Merge branch 'master' of vc.linet-services.de:public/lx-office-erp
authorSven Schöling <s.schoeling@linet-services.de>
Wed, 14 Dec 2011 15:30:29 +0000 (16:30 +0100)
committerSven Schöling <s.schoeling@linet-services.de>
Wed, 14 Dec 2011 15:30:29 +0000 (16:30 +0100)
13 files changed:
SL/Controller/Helper/ParseFilter.pm
SL/Controller/Helper/ReportGenerator.pm [new file with mode: 0644]
SL/DB/Helper/Paginated.pm [new file with mode: 0644]
SL/DB/OrderItem.pm
SL/ReportGenerator.pm
bin/mozilla/gl.pl
locale/de/all
t/controllers/helpers/parse_filter.t
templates/webpages/common/paginate.html [new file with mode: 0644]
templates/webpages/gl/search.html [new file with mode: 0644]
templates/webpages/report_generator/csv_export_options.html
templates/webpages/report_generator/html_report.html
templates/webpages/report_generator/pdf_export_options.html

index 3753d16..ac086f5 100644 (file)
@@ -36,7 +36,7 @@ sub parse_filter {
 
   my $query = _parse_filter($flattened, %params);
 
-  _launder_keys($filter) unless $params{no_launder};
+  _launder_keys($filter, $params{launder_to}) unless $params{no_launder};
 
   return
     ($query   && @$query   ? (query => $query) : ()),
@@ -44,23 +44,27 @@ sub parse_filter {
 }
 
 sub _launder_keys {
-  my ($filter) = @_;
+  my ($filter, $launder_to) = @_;
+  $launder_to ||= $filter;
   return unless ref $filter eq 'HASH';
-  my @keys = keys %$filter;
-  for my $key (@keys) {
+  for my $key (keys %$filter) {
     my $orig = $key;
     $key =~ s/:/_/g;
-    $filter->{$key} = $filter->{$orig};
-    _launder_keys($filter->{$key});
+    if ('' eq ref $filter->{$orig}) {
+      $launder_to->{$key} = $filter->{$orig};
+    } elsif ('ARRAY' eq ref $filter->{$orig}) {
+      $launder_to->{$key} = [ @{ $filter->{$orig} } ];
+    } else {
+      $launder_to->{$key} ||= { };
+      _launder_keys($filter->{$key}, $launder_to->{$key});
+    }
   };
-
-  return $filter;
 }
 
 sub _pre_parse {
   my ($filter, $with_objects, $prefix, %params) = @_;
 
-  return () unless 'HASH'  eq ref $filter;
+  return (undef, $with_objects) unless 'HASH'  eq ref $filter;
   $with_objects ||= [];
 
   my @result;
@@ -207,18 +211,38 @@ and later
 The special empty method will be used to set the method for the previous
 method-less input.
 
-=item Laundering filter
+=back
+
+=head1 LAUNDERING
 
 Unfortunately Template cannot parse the postfixes if you want to
 rerender the filter. For this reason all colons filter keys are by
-default laundered into underscores. If you don't want this to happen
-pass C<< no_launder => 1 >> as a parameter. A full select_tag then
-loks like this:
+default laundered into underscores, so you can use them like this:
 
   [% L.input_tag('filter.price:number::lt', filter.price_number__lt) %]
 
+All of your original entries will stay intactg. If you don't want this to
+happen pass C<< no_launder => 1 >> as a parameter.  Additionally you can pass a
+different target for the laundered values with the C<launder_to>  parameter. It
+takes an hashref and will deep copy all values in your filter to the target. So
+if you have a filter that looks liek this:
 
-=back
+  $filter = {
+    'price:number::lt' => '2,30',
+    'closed            => '1',
+  }
+
+and parse it with
+
+  parse_filter($filter, launder_to => $laundered_filter = { })
+
+the original filter will be unchanged, and C<$laundered_filter> will end up
+like this:
+
+  $filter = {
+    'price_number__lt' => '2,30',
+    'closed            => '1',
+  }
 
 =head1 FILTERS (leading with :)
 
diff --git a/SL/Controller/Helper/ReportGenerator.pm b/SL/Controller/Helper/ReportGenerator.pm
new file mode 100644 (file)
index 0000000..3455375
--- /dev/null
@@ -0,0 +1,101 @@
+#=====================================================================
+# LX-Office ERP
+# Copyright (C) 2004
+# Based on SQL-Ledger Version 2.1.9
+# Web http://www.lx-office.org
+######################################################################
+#
+# Mixin for controllers to use ReportGenerator things
+#
+######################################################################
+
+use strict;
+
+use List::Util qw(max);
+
+use SL::Form;
+use SL::Common;
+use SL::MoreCommon;
+use SL::ReportGenerator;
+
+use Exporter 'import';
+our @EXPORT = qw(
+  action_report_generator_export_as_pdf action_report_generator_export_as_csv
+  action_report_generator_back report_generator_do
+);
+
+sub action_report_generator_export_as_pdf {
+  my ($self) = @_;
+  if ($::form->{report_generator_pdf_options_set}) {
+    my $saved_form = save_form();
+
+    $self->report_generator_do('PDF');
+
+    if ($::form->{report_generator_printed}) {
+      restore_form($saved_form);
+      $::form->{MESSAGE} = $::locale->text('The list has been printed.');
+      $self->report_generator_do('HTML');
+    }
+
+    return;
+  }
+
+  my @form_values = $::form->flatten_variables(grep { ($_ ne 'login') && ($_ ne 'password') } keys %{ $::form });
+
+  $::form->get_lists('printers' => 'ALL_PRINTERS');
+  map { $_->{selected} = $::myconfig{default_printer_id} == $_->{id} } @{ $::form->{ALL_PRINTERS} };
+
+  $::form->{copies} = max $::myconfig{copies} * 1, 1;
+  $::form->{title} = $::locale->text('PDF export -- options');
+  $::form->header;
+  print $::form->parse_html_template('report_generator/pdf_export_options', {
+    'HIDDEN'               => \@form_values,
+    'ALLOW_FONT_SELECTION' => SL::ReportGenerator->check_for_pdf_api, });
+}
+
+sub action_report_generator_export_as_csv {
+  my ($self) = @_;
+  if ($::form->{report_generator_csv_options_set}) {
+    $self->report_generator_do('CSV');
+    return;
+  }
+
+  my @form_values = $::form->flatten_variables(grep { ($_ ne 'login') && ($_ ne 'password') } keys %{ $::form });
+
+  $::form->{title} = $::locale->text('CSV export -- options');
+  $::form->header;
+  print $::form->parse_html_template('report_generator/csv_export_options', { 'HIDDEN' => \@form_values });
+}
+
+sub action_report_generator_back {
+  $_[0]->report_generator_do('HTML');
+}
+
+sub report_generator_set_default_sort {
+  my ($default_sortorder, $default_sortdir) = @_;
+
+  $::form->{sort}         ||= $default_sortorder;
+  $::form->{sortdir}        = $default_sortdir unless (defined $::form->{sortdir});
+  $::form->{sortdir}        = $::form->{sortdir} ? 1 : 0;
+}
+
+sub report_generator_do {
+  my ($self, $format)  = @_;
+
+  my $nextsub = $::form->{report_generator_nextsub};
+  if (!$nextsub) {
+    $::form->error($::locale->text('report_generator_nextsub is not defined.'));
+  }
+
+  foreach my $key (split m/ +/, $::form->{report_generator_variable_list}) {
+    $::form->{$key} = $::form->{"report_generator_hidden_${key}"};
+  }
+
+  $::form->{report_generator_output_format} = $format;
+
+  delete @{$::form}{map { "report_generator_$_" } qw(nextsub variable_list)};
+
+  $self->_run_action($nextsub);
+}
+
+1;
diff --git a/SL/DB/Helper/Paginated.pm b/SL/DB/Helper/Paginated.pm
new file mode 100644 (file)
index 0000000..a24d4d7
--- /dev/null
@@ -0,0 +1,151 @@
+package SL::DB::Helper::Paginated;
+
+use strict;
+
+require Exporter;
+our @ISA    = qw(Exporter);
+our @EXPORT = qw(paginate disable_paginating);
+
+use List::MoreUtils qw(any);
+
+sub paginate {
+  my ($self, %params) = @_;
+  my $page = $params{page} || 1;
+  my %args = %{ $params{args} || {} };
+
+  my $ret = { };
+
+  $ret->{per_page} = per_page($self, %params);
+  $ret->{max}    = ceil($self->get_all_count(%args), $ret->{per_page}) || 1;
+  $ret->{cur}    = $page < 1 ? 1
+                 : $page > $ret->{max} ? $ret->{max}
+                 : $page;
+  $ret->{common} = make_common_pages($ret->{cur}, $ret->{max});
+
+  $params{args}{page}     = $ret->{cur};
+  $params{args}{per_page} = $ret->{per_page};
+  delete $params{args}{limit};
+  delete $params{args}{offset};
+
+  return $ret;
+}
+
+sub per_page {
+  my ($self, %params) = @_;
+
+  return $params{per_page} if exists $params{per_page};
+  return $self->default_objects_per_page;
+}
+
+sub ceil {
+  my ($a, $b) = @_;
+  use integer;
+
+  return 1 unless $b;
+  return $a / $b + ($a % $b ? 1 : 0);
+}
+
+sub make_common_pages {
+  my ($cur, $max) = @_;
+  return [
+    map {
+      active  => $_ != $cur,
+      page    => $_,
+      visible => calc_visibility($cur, $max, $_),
+    }, 1 .. $max
+  ];
+}
+
+sub calc_visibility {
+  my ($cur, $max, $this) = @_;
+  any { $_ } abs($cur - $this) < 5,
+             $this <= 3,
+             $this == $max,
+             any { abs ($cur - $this) == $_ } 10, 50, 100, 500, 1000, 5000;
+}
+
+sub disable_paginating {
+  my ($self, %params) = @_;
+
+  delete $params{args}{page};
+  delete $params{args}{per_page};
+}
+
+1;
+
+__END__
+
+=encoding utf-8
+
+=head1 NAME
+
+SL::Helper::Paginated - Manager mixin for paginating results.
+
+=head1 SYNOPSIS
+
+In the manager:
+
+  use SL::Helper::Paginated;
+
+  __PACKAGE__->default_objects_per_page(10); # optional, defaults to 20
+
+In the controller:
+
+  my %args = (
+    query => [ id         => $params{list_of_selected_ids},
+               other_attr => $::form->{other_attr}, ],
+  );
+
+  $self->{pages}   = SL::DB::Manager::MyObject->paginate(args => \%args, page => $::form->{page});
+  $self->{objects} = SL::DB::Manager::MyObject->get_all(%args);
+
+In the template:
+
+  [% PROCESS 'common/paginate.html'
+    pages=SELF.pages
+    base_url=L.url_for(action='list', ...)
+  %]
+
+=head1 FUNCTIONS
+
+=over 4
+
+=item C<paginate> args => HREF, page => $page, [ per_page => $per_page ]
+
+Paginate will prepare information to be used for paginating, change the given
+args to use them, and return a data structure containing information for later
+display.
+
+C<args> needs to contain a reference to a hash, which will be used as an
+argument for C<get_all>. After C<paginate> the keys C<page> and C<per_page>
+will be set. The keys C<limit> and C<offset> will be unset, should they exist,
+since they don't make sense with paginating.
+
+C<page> should contain a value between 1 and the maximum pages. Will be
+sanitized.
+
+The parameter C<per_page> is optional. If not given the default value of the
+Manager will be used.
+
+=back
+
+=head1 TEMPLATE HELPERS
+
+=over 4
+
+=item C<common/paginate.html> pages=SELF.pages, base_url=URL
+
+The template will render a simple list of links to the
+various other pages. A C<base_url> must be given for the links to work.
+
+=back
+
+=head1 BUGS
+
+None yet.
+
+=head1 AUTHOR
+
+Sven Schöling E<lt>s.schoeling@linet-services.deE<gt>
+
+=cut
index 9e045f7..6efee00 100644 (file)
@@ -27,6 +27,11 @@ __PACKAGE__->meta->add_relationship(
     class        => 'SL::DB::Unit',
     column_map   => { unit => 'name' },
   },
+  order => {
+    type         => 'one to one',
+    class        => 'SL::DB::Order',
+    column_map   => { trans_id => 'id' },
+  },
 );
 
 # Creates get_all, get_all_count, get_all_iterator, delete_all and update_all.
@@ -39,4 +44,26 @@ sub is_price_update_available {
   return $self->origprice > $self->part->sellprice;
 }
 
+package SL::DB::Manager::OrderItem;
+
+use SL::DB::Helper::Paginated;
+use SL::DB::Helper::Sorted;
+
+sub _sort_spec {
+  return ( columns => { delivery_date => [ 'deliverydate',        ],
+                        description   => [ 'lower(orderitems.description)',  ],
+                        partnumber    => [ 'part.partnumber',     ],
+                        qty           => [ 'qty'                  ],
+                        ordnumber     => [ 'order.ordnumber'      ],
+                        customer      => [ 'lower(customer.name)', ],
+                        position      => [ 'trans_id', 'runningnumber' ],
+                        transdate     => [ 'transdate', 'lower(order.reqdate::text)' ],
+                      },
+           default => [ 'position', 1 ],
+           nulls   => { }
+         );
+}
+
+sub default_objects_per_page { 40 }
+
 1;
index 6b99901..f81435e 100644 (file)
@@ -23,6 +23,7 @@ sub new {
   $self->{options}  = {
     'std_column_visibility' => 0,
     'output_format'         => 'HTML',
+    'controller_class   '   => '',
     'allow_pdf_export'      => 1,
     'allow_csv_export'      => 1,
     'html_template'         => 'report_generator/html_report',
@@ -389,6 +390,7 @@ sub prepare_html_content {
     'EXPORT_VARIABLE_LIST' => join(' ', @{ $self->{export}->{variable_list} }),
     'EXPORT_NEXTSUB'       => $self->{export}->{nextsub},
     'DATA_PRESENT'         => $self->{data_present},
+    'CONTROLLER_DISPATCH'  => $opts->{controller_class},
   };
 
   return $variables;
@@ -768,6 +770,10 @@ sub _generate_csv_content {
   }
 }
 
+sub check_for_pdf_api {
+  return eval { require PDF::API2; 1; } ? 1 : 0;
+}
+
 1;
 
 __END__
@@ -921,6 +927,12 @@ Used to determine if a button for CSV export should be displayed. Default is yes
 
 The template to be used for HTML reports. Default is 'report_generator/html_report'.
 
+=item controller_class
+
+If this is used from a C<SL::Controller::Base> based controller class, pass the
+class name here and make sure C<SL::Controller::Helper::ReportGenerator> is
+used in the controller. That way the exports stay functional.
+
 =back
 
 =head2 PDF Options
index 625490d..6ed1e4c 100644 (file)
@@ -211,232 +211,27 @@ sub edit {
 
 
 sub search {
-  $main::lxdebug->enter_sub();
-
-  $main::auth->assert('general_ledger');
-
-  my $form     = $main::form;
-  my %myconfig = %main::myconfig;
-  my $locale   = $main::locale;
-  my $cgi      = $::request->{cgi};
-
-  $form->{title} = $locale->text('Journal');
-
-  $form->all_departments(\%myconfig);
-
-  # departments
-  if (@{ $form->{all_departments} || [] }) {
-    $form->{selectdepartment} = "<option>\n";
-
-    map {
-      $form->{selectdepartment} .=
-        "<option>$_->{description}--$_->{id}\n"
-    } (@{ $form->{all_departments} || [] });
-  }
-
-  my $department;
-  $department = qq|
-        <tr>
-          <th align=right nowrap>| . $locale->text('Department') . qq|</th>
-          <td colspan=3><select name=department>$form->{selectdepartment}</select></td>
-        </tr>
-| if $form->{selectdepartment};
-
-  $form->get_lists("projects" => { "key" => "ALL_PROJECTS",
-                                   "all" => 1},
-                                   "employees"    => "ALL_EMPLOYEES" );
-
-  my %project_labels = ();
-  my @project_values = ("");
-  foreach my $item (@{ $form->{"ALL_PROJECTS"} }) {
-    push(@project_values, $item->{"id"});
-    $project_labels{$item->{"id"}} = $item->{"projectnumber"};
-  }
-
-  my $projectnumber =
-    NTI($cgi->popup_menu('-name' => "project_id",
-                         '-values' => \@project_values,
-                         '-labels' => \%project_labels));
-
-  my %employee_labels = ();
-  my @employee_values = ("");
-  foreach my $item (@{ $form->{"ALL_EMPLOYEES"} }) {
-    # value in Form "1234--Name" übergeben
-    my $id = "$item->{'id'}--$item->{'name'}";
-    push(@employee_values, "$id");
-    $employee_labels{$id} = $item->{"name"};
-  }
-
-  my $employeenumber =
-    NTI($cgi->popup_menu('-name' => "employee",
-                         '-values' => \@employee_values,
-                         '-labels' => \%employee_labels));
+  $::lxdebug->enter_sub;
+  $::auth->assert('general_ledger');
 
-  # use JavaScript Calendar or not
-  $form->{jsscript} = 1;
-  my $jsscript = "";
-  my ($button1, $button2, $onload);
-  if ($form->{jsscript}) {
-
-    # with JavaScript Calendar
-    $button1 = qq|
-       <td><input name=datefrom id=datefrom size=11 title="$myconfig{dateformat}" onBlur=\"check_right_date_format(this)\">
-       <input type=button name=datefrom id="trigger1" value=|
-      . $locale->text('button') . qq|></td>
-       |;
-    $button2 = qq|
-       <td><input name=dateto id=dateto size=11 title="$myconfig{dateformat}" onBlur=\"check_right_date_format(this)\">
-       <input type=button name=dateto id="trigger2" value=|
-      . $locale->text('button') . qq|></td>
-     |;
-
-    #write Trigger
-    $jsscript =
-      Form->write_trigger(\%myconfig, "2", "datefrom", "BR", "trigger1",
-                          "dateto", "BL", "trigger2");
-  } else {
-
-    # without JavaScript Calendar
-    $button1 =
-      qq|<td><input name=datefrom id=datefrom size=11 title="$myconfig{dateformat}" onBlur=\"check_right_date_format(this)\"></td>|;
-    $button2 =
-      qq|<td><input name=dateto id=dateto size=11 title="$myconfig{dateformat}" onBlur=\"check_right_date_format(this)\"></td>|;
-  }
-  $form->{javascript} .= qq|<script type="text/javascript" src="js/common.js"></script>|;
-  $form->header;
-  $onload = qq|focus()|;
-  $onload .= qq|;setupDateFormat('|. $myconfig{dateformat} .qq|', '|. $locale->text("Falsches Datumsformat!") .qq|')|;
-  $onload .= qq|;setupPoints('|. $myconfig{numberformat} .qq|', '|. $locale->text("wrongformat") .qq|')|;
-  print qq|
-<body onLoad="$onload">
-
-<form method=post action=gl.pl>
-
-<input type=hidden name=sort value=datesort>
-
-<table width=100%>
-  <tr>
-    <th class=listtop>$form->{title}</th>
-  </tr>
-  <tr height="5"></tr>
-  <tr>
-    <td>
-      <table>
-        <tr>
-          <th align=right>| . $locale->text('Reference') . qq|</th>
-          <td><input name=reference size=20></td>
-          <th align=right>| . $locale->text('Source') . qq|</th>
-          <td><input name=source size=20></td>
-        </tr>
-        $department
-        <tr>
-          <th align=right>| . $locale->text('Description') . qq|</th>
-          <td><input name=description size=40></td>
-          <th align=right>| . $locale->text('Account Number') . qq|</th>
-          <td><input name=accno size=20></td>
-        </tr>
-        <tr>
-          <th align=right>| . $locale->text('Notes') . qq|</th>
-          <td colspan=3><input name=notes size=40></td>
-        </tr>
-        <tr>
-          <th align=right>| . $locale->text('Project Number') . qq|</th>
-          <td colspan=3>$projectnumber</td>
-        </tr>
- <tr>
-    <th align=right>| . $locale->text('Employee') . qq|</th>
-    <td colspan=3>$employeenumber</td>
-  </tr>
-  <tr>
-    <th align=right>| . $locale->text('Filter date by') . qq|</th>
-    <td colspan=3>
-    <input name=datesort class=radio type=radio value=gldate checked>&nbsp;| . $locale->text('Booking Date') . qq|
-    <input name=datesort class=radio type=radio value=transdate>&nbsp;| . $locale->text('Invoice Date') . qq|
-    </td>
-  </tr>
-  <tr>
-    <th align=right>| . $locale->text('From') . qq|</th>
-          $button1
-          <th align=right>| . $locale->text('To (time)') . qq|</th>
-          $button2
-        </tr>
-        <tr>
-          <th align=right>| . $locale->text('Include in Report') . qq|</th>
-          <td colspan=3>
-            <table>
-              <tr>
-                <td>
-                  <input name="category" class=radio type=radio value=X checked>&nbsp;|
-    . $locale->text('All') . qq|
-                  <input name="category" class=radio type=radio value=A>&nbsp;|
-    . $locale->text('Asset') . qq|
-                  <input name="category" class=radio type=radio value=L>&nbsp;|
-    . $locale->text('Liability') . qq|
-                  <input name="category" class=radio type=radio value=I>&nbsp;|
-    . $locale->text('Revenue') . qq|
-                  <input name="category" class=radio type=radio value=E>&nbsp;|
-    . $locale->text('Expense') . qq|
-                </td>
-              </tr>
-              <tr>
-                <table>
-                  <tr>
-                    <td align=right><input name="l_id" class=checkbox type=checkbox value=Y></td>
-                    <td>| . $locale->text('ID') . qq|</td>
-                    <td align=right><input name="l_transdate" class=checkbox type=checkbox value=Y checked></td>
-                    <td>| . $locale->text('Invoice Date') . qq|</td>
-                    <td align=right><input name="l_gldate" class=checkbox type=checkbox value=Y checked></td>
-                    <td>| . $locale->text('Booking Date') . qq|</td>
-                    <td align=right><input name="l_reference" class=checkbox type=checkbox value=Y checked></td>
-                    <td>| . $locale->text('Reference') . qq|</td>
-                    <td align=right><input name="l_description" class=checkbox type=checkbox value=Y checked></td>
-                    <td>| . $locale->text('Description') . qq|</td>
-                    <td align=right><input name="l_notes" class=checkbox type=checkbox value=Y></td>
-                    <td>| . $locale->text('Notes') . qq|</td>
-                  </tr>
-                  <tr>
-                    <td align=right><input name="l_debit" class=checkbox type=checkbox value=Y checked></td>
-                    <td>| . $locale->text('Debit') . qq|</td>
-                    <td align=right><input name="l_credit" class=checkbox type=checkbox value=Y checked></td>
-                    <td>| . $locale->text('Credit') . qq|</td>
-                    <td align=right><input name="l_source" class=checkbox type=checkbox value=Y checked></td>
-                    <td>| . $locale->text('Source') . qq|</td>
-                    <td align=right><input name="l_accno" class=checkbox type=checkbox value=Y checked></td>
-                    <td>| . $locale->text('Account') . qq|</td>
-                  </tr>
-                  <tr>
-                    <td align=right><input name="l_subtotal" class=checkbox type=checkbox value=Y></td>
-                    <td>| . $locale->text('Subtotal') . qq|</td>
-                    <td align=right><input name="l_projectnumbers" class=checkbox type=checkbox value=Y></td>
-                    <td>| . $locale->text('Project Number') . qq|</td>
-                    <td align=right><input name="l_employee" class=checkbox type=checkbox value=Y></td>
-                    <td>| . $locale->text('Employee') . qq|</td>
-                  </tr>
-                </table>
-              </tr>
-            </table>
-        </tr>
-      </table>
-    </td>
-  </tr>
-  <tr>
-    <td><hr size=3 noshade></td>
-  </tr>
-</table>
+  $::form->all_departments(\%::myconfig);
+  $::form->get_lists(
+    projects  => { key => "ALL_PROJECTS", all => 1 },
+    employees => "ALL_EMPLOYEES",
+  );
 
-$jsscript
+  my $onload = "focus()"
+             . qq|;setupDateFormat('|. $::myconfig{dateformat} . qq|', '| . $::locale->text("Falsches Datumsformat!") . qq|')|
+             . qq|;setupPoints('|. $::myconfig{numberformat} .   qq|', '| . $::locale->text("wrongformat") . qq|')|;
 
-<input type=hidden name=nextsub value=generate_report>
+  $::form->header;
+  print $::form->parse_html_template('gl/search', {
+    onload => $onload,
+    department_label => sub { ("$_[0]{description}--$_[0]{id}")x2 },
+    employee_label => sub { "$_[0]{id}--$_[0]{name}" },
+  });
 
-<br>
-<input class=submit type=submit name=action value="|
-    . $locale->text('Continue') . qq|">
-</form>
-
-</body>
-</html>
-|;
-  $main::lxdebug->leave_sub();
+  $::lxdebug->leave_sub;
 }
 
 sub create_subtotal_row {
index 2b911de..b8c8999 100644 (file)
@@ -2197,6 +2197,7 @@ $self->{texts} = {
   'month'                       => 'Monatliche Abgabe',
   'monthly'                     => 'monatlich',
   'new Window'                  => 'neues Fenster',
+  'next'                        => 'Nächste',
   'no'                          => 'nein',
   'no bestbefore'               => 'keine Mindesthaltbarkeit',
   'no chargenumber'             => 'keine Chargennummer',
@@ -2220,6 +2221,7 @@ $self->{texts} = {
   'pos_eur'                     => 'E/ÜR',
   'pos_ustva'                   => 'UStVA',
   'posted!'                     => 'gebucht',
+  'prev'                        => 'Vorherige',
   'print'                       => 'drucken',
   'proforma'                    => 'Proforma',
   'project_list'                => 'projektliste',
index 84547e0..179c236 100644 (file)
@@ -1,6 +1,6 @@
 use lib 't';
 
-use Test::More tests => 13;
+use Test::More tests => 17;
 use Test::Deep;
 use Data::Dumper;
 
@@ -12,14 +12,19 @@ undef *::any; # Test::Deep exports any (for junctions) and MoreCommon exports an
 Support::TestSetup::login();
 my ($filter, $expected);
 
-sub test ($$$) {
-  my $got = { parse_filter($_[0]) };
+sub test ($$$;%) {
+  my ($filter, $expect, $msg, %params) = @_;
+  my $target = delete $params{target};
+  my $args = { parse_filter($filter, %params) };
+  my $got  = $args;
+     $got = $filter             if $target =~ /filter/;
+     $got = $params{launder_to} if $target =~ /launder/;
   cmp_deeply(
     $got,
-    $_[1],
-    $_[2]
+    $expect,
+    $msg,
   ) or do {
-    print STDERR "expected => ", Dumper($_[1]), "\ngot: => ", Dumper($got), $/;
+    print STDERR "expected => ", Dumper($expect), "\ngot: => ", Dumper($got), $/;
   }
 }
 
@@ -126,3 +131,49 @@ test {
   ],
 }, 'arrays with filter';
 
+
+########### laundering
+
+test {
+  'sellprice:number' => [
+    '123,4', '2,34', '0,4',
+  ]
+}, {
+  'sellprice:number' => [ '123,4', '2,34', '0,4' ],
+  'sellprice_number' => [ '123,4', '2,34', '0,4' ],
+}, 'laundering with array', target => 'filter';
+
+my %args = (
+  'sellprice:number' => [
+    '123,4', '2,34', '0,4',
+  ],
+);
+test {
+  %args,
+}, {
+  %args
+}, 'laundering into launder does not alter filter', target => 'filter', launder_to => {};
+
+
+test {
+  part => {
+   'sellprice:number' => '123,4',
+  }
+}, {
+  part => {
+    'sellprice:number' => '123,4',
+    'sellprice_number' => '123,4'
+  }
+}, 'deep laundering', target => 'filter';
+
+
+test {
+  part => {
+   'sellprice:number' => '123,4',
+  }
+}, {
+  part => {
+    'sellprice_number' => '123,4'
+  }
+}, 'deep laundering, check for laundered hash', target => 'launder', launder_to => { };
+
diff --git a/templates/webpages/common/paginate.html b/templates/webpages/common/paginate.html
new file mode 100644 (file)
index 0000000..a476fa0
--- /dev/null
@@ -0,0 +1,9 @@
+[%- USE T8 %]
+[%- IF pages.max > 1 %]
+[%- IF pages.cur > 1 %]<a href='[% base_url _ "&page=" _ (pages.cur - 1) %]'>&laquo; [% 'prev' | $T8 %]</a> [% ELSE %]<b>&laquo;</b> [% END %]
+[%- FOR p = pages.common %]
+  [%- NEXT UNLESS p.visible %]
+  [%- IF p.active %]<a href="[% base_url _ "&page=" _ p.page %]">[% p.page %]</a> [% ELSE %]<b>[% p.page %]</b> [%- END %]
+[%- END %]
+[%- IF pages.cur < pages.max %]<a href='[% base_url _ "&page=" _ (pages.cur + 1) %]'>[% 'next' | $T8 %] &raquo;</a>[% ELSE %]<b>&raquo;</b>[%- END %]
+[%- END %]
diff --git a/templates/webpages/gl/search.html b/templates/webpages/gl/search.html
new file mode 100644 (file)
index 0000000..0d3a155
--- /dev/null
@@ -0,0 +1,128 @@
+[%- USE T8 %]
+[%- USE HTML %]
+[%- USE LxERP %]
+[%- USE L %]
+<body onLoad="[% onload %]">
+
+<form method=post action=gl.pl>
+
+<input type=hidden name=sort value=datesort>
+
+<table width=100%>
+  <tr>
+    <th class=listtop>[% 'Journal' | $T8 %]</th>
+  </tr>
+  <tr height="5"></tr>
+  <tr>
+    <td>
+      <table>
+        <tr>
+          <th align=right>[% 'Reference' | $T8 %]</th>
+          <td><input name=reference size=20></td>
+          <th align=right>[% 'Source' | $T8 %]</th>
+          <td><input name=source size=20></td>
+        </tr>
+        [%- IF all_departments %]
+        <tr>
+          <th align=right nowrap>[% 'Department' | $T8 %]</th>
+          <td colspan=3>[% L.select_tag('department', L.options_for_select(all_departments, value_title_sub=\department_label, with_empty=1)) %]</td>
+        </tr>
+        [%- END %]
+        <tr>
+          <th align=right>[% 'Description' | $T8 %]</th>
+          <td><input name=description size=40></td>
+          <th align=right>[% 'Account Number' | $T8 %]</th>
+          <td><input name=accno size=20></td>
+        </tr>
+        <tr>
+          <th align=right>[% 'Notes' | $T8 %]</th>
+          <td colspan=3><input name=notes size=40></td>
+        </tr>
+        <tr>
+          <th align=right>[% 'Project Number' | $T8 %]</th>
+          <td colspan=3>[% L.select_tag('project_id', L.options_for_select(ALL_PROJECTS, title='projectnumber', with_empty=1)) %]</td>
+        </tr>
+ <tr>
+    <th align=right>[% 'Employee' | $T8 %]</th>
+    <td colspan=3>[% L.select_tag('employee', L.options_for_select(ALL_EMPLOYEES, value_sub=\employee_label, title='name', with_empty=1)) %]</td>
+  </tr>
+  <tr>
+    <th align=right>[% 'Filter date by' | $T8 %]</th>
+    <td colspan=3>
+    <input name=datesort class=radio type=radio value=gldate checked> [% 'Booking Date' | $T8 %]
+    <input name=datesort class=radio type=radio value=transdate> [% 'Invoice Date' | $T8 %]
+  </td>
+  </tr>
+  <tr>
+    <th align=right>[% 'From' | $T8 %]</th>
+          <td>[% L.date_tag('datefrom') %]</td>
+          <th align=right>[% 'To (time)' | $T8 %]</th>
+          <td>[% L.date_tag('dateto') %]</td>
+        </tr>
+        <tr>
+          <th align=right>[% 'Include in Report' | $T8 %]</th>
+          <td colspan=3>
+            <table>
+              <tr>
+                <td>
+                  <input name="category" class=radio type=radio value=X checked> [% 'All' | $T8 %]
+                  <input name="category" class=radio type=radio value=A> [% 'Asset' | $T8 %]
+                  <input name="category" class=radio type=radio value=L> [% 'Liability' | $T8 %]
+                  <input name="category" class=radio type=radio value=I> [% 'Revenue' | $T8 %]
+                  <input name="category" class=radio type=radio value=E> [% 'Expense' | $T8 %]
+                </td>
+              </tr>
+              <tr>
+                <table>
+                  <tr>
+                    <td align=right><input name="l_id" class=checkbox type=checkbox value=Y></td>
+                    <td>[% 'ID' | $T8 %]</td>
+                    <td align=right><input name="l_transdate" class=checkbox type=checkbox value=Y checked></td>
+                    <td>[% 'Invoice Date' | $T8 %]</td>
+                    <td align=right><input name="l_gldate" class=checkbox type=checkbox value=Y checked></td>
+                    <td>[% 'Booking Date' | $T8 %]</td>
+                    <td align=right><input name="l_reference" class=checkbox type=checkbox value=Y checked></td>
+                    <td>[% 'Reference' | $T8 %]</td>
+                    <td align=right><input name="l_description" class=checkbox type=checkbox value=Y checked></td>
+                    <td>[% 'Description' | $T8 %]</td>
+                    <td align=right><input name="l_notes" class=checkbox type=checkbox value=Y></td>
+                    <td>[% 'Notes' | $T8 %]</td>
+                  </tr>
+                  <tr>
+                    <td align=right><input name="l_debit" class=checkbox type=checkbox value=Y checked></td>
+                    <td>[% 'Debit' | $T8 %]</td>
+                    <td align=right><input name="l_credit" class=checkbox type=checkbox value=Y checked></td>
+                    <td>[% 'Credit' | $T8 %]</td>
+                    <td align=right><input name="l_source" class=checkbox type=checkbox value=Y checked></td>
+                    <td>[% 'Source' | $T8 %]</td>
+                    <td align=right><input name="l_accno" class=checkbox type=checkbox value=Y checked></td>
+                    <td>[% 'Account' | $T8 %]</td>
+                  </tr>
+                  <tr>
+                    <td align=right><input name="l_subtotal" class=checkbox type=checkbox value=Y></td>
+                    <td>[% 'Subtotal' | $T8 %]</td>
+                    <td align=right><input name="l_projectnumbers" class=checkbox type=checkbox value=Y></td>
+                    <td>[% 'Project Number' | $T8 %]</td>
+                    <td align=right><input name="l_employee" class=checkbox type=checkbox value=Y></td>
+                    <td>[% 'Employee' | $T8 %]</td>
+                  </tr>
+                </table>
+              </tr>
+            </table>
+        </tr>
+      </table>
+    </td>
+  </tr>
+  <tr>
+    <td><hr size=3 noshade></td>
+  </tr>
+</table>
+
+<input type=hidden name=nextsub value=generate_report>
+
+<br>
+<input class=submit type=submit name=action value="[% 'Continue' | $T8 %]">
+</form>
+
+</body>
+</html>
index 0af5560..996adfc 100644 (file)
@@ -1,16 +1,6 @@
 [%- USE T8 %]
 [% USE HTML %]<body>
 
- <script type="text/javascript">
-  <!--
-      function submit_report_generator_form(nextsub) {
-        document.report_generator_form.report_generator_dispatch_to.value = nextsub;
-        document.report_generator_form.submit();
-      }
-
-    -->
- </script>
-
  <div class="listheading" width="100%">[% HTML.escape(title) %]</div>
 
  <form action="[% HTML.escape(script) %]" method="post" name="report_generator_form">
@@ -21,7 +11,6 @@
 
   <input type="hidden" name="report_generator_csv_options_set" value="1">
   <input type="hidden" name="report_generator_dispatch_to" value="">
-  <input type="hidden" name="action" value="report_generator_dispatcher">
 
   <table>
    <tr>
 
   </table>
 
+[%- IF CONTROLLER_DISPATCH %]
+   <p>
+    <input type="hidden" name="action" value="[% CONTROLLER_DISPATCH | html %]/dispatch">
+    <input type="submit" name="action_report_generator_export_as_csv" value="[% 'Export as CSV' | $T8 %]">
+    <input type="submit" name="action_report_generator_back" value="[% 'Back' | $T8 %]">
+    <input type="hidden" name="CONTROLLER_DISPATCH" value="[% CONTROLLER_DISPATCH | html %]">
+   </p>
+[%- ELSE %]
   <p>
+   <input type="hidden" name="action" value="report_generator_dispatcher">
    <input type="submit" class="submit" onclick="submit_report_generator_form('report_generator_export_as_csv')" value="[% 'Export as CSV' | $T8 %]">
    <input type="submit" class="submit" onclick="submit_report_generator_form('report_generator_back')" value="[% 'Back' | $T8 %]">
   </p>
+ <script type="text/javascript"><!--
+      function submit_report_generator_form(nextsub) {
+        document.report_generator_form.report_generator_dispatch_to.value = nextsub;
+        document.report_generator_form.submit();
+      } // -->
+ </script>
+[%- END %]
+
 
  </form>
 </body>
index 32c2bd5..8b2d253 100644 (file)
@@ -1,16 +1,6 @@
 [%- USE T8 %]
 [% USE HTML %]<body>
 
- <script type="text/javascript">
-  <!--
-      function submit_report_generator_form(nextsub) {
-        document.report_generator_form.report_generator_dispatch_to.value = nextsub;
-        document.report_generator_form.submit();
-      }
-
-    -->
- </script>
-
  <style type="text/css">
   <!--
 .top_border {
    [% FOREACH var = EXPORT_VARIABLES %]<input type="hidden" name="report_generator_hidden_[% var.key %]" value="[% HTML.escape(var.value) %]">
    [% END %]
 
+[%- IF CONTROLLER_DISPATCH %]
+   <input type="hidden" name="action" value="[% CONTROLLER_DISPATCH %]/dispatch">
+   <input type="hidden" name="report_generator_nextsub" value="[% HTML.escape(EXPORT_NEXTSUB) %]">
+   <input type="hidden" name="report_generator_variable_list" value="[% HTML.escape(EXPORT_VARIABLE_LIST) %]">
+   <input type="hidden" name="CONTROLLER_DISPATCH" value="[% CONTROLLER_DISPATCH | html %]">
+
+   <p>
+    [% 'List export' | $T8 %]<br>
+    [% IF ALLOW_PDF_EXPORT %]<input type="submit" name="action_report_generator_export_as_pdf" value="[% 'Export as PDF' | $T8 %]">[% END %]
+    [% IF ALLOW_CSV_EXPORT %]<input type="submit" name="action_report_generator_export_as_csv" value="[% 'Export as CSV' | $T8 %]">[% END %]
+   </p>
+[%- ELSE %]
    <input type="hidden" name="report_generator_nextsub" value="[% HTML.escape(EXPORT_NEXTSUB) %]">
    <input type="hidden" name="report_generator_variable_list" value="[% HTML.escape(EXPORT_VARIABLE_LIST) %]">
    <input type="hidden" name="report_generator_dispatch_to" value="">
     [% IF ALLOW_PDF_EXPORT %]<input type="submit" class="submit" onclick="submit_report_generator_form('report_generator_export_as_pdf')" value="[% 'Export as PDF' | $T8 %]">[% END %]
     [% IF ALLOW_CSV_EXPORT %]<input type="submit" class="submit" onclick="submit_report_generator_form('report_generator_export_as_csv')" value="[% 'Export as CSV' | $T8 %]">[% END %]
    </p>
+ <script type="text/javascript"> <!--
+      function submit_report_generator_form(nextsub) {
+        document.report_generator_form.report_generator_dispatch_to.value = nextsub;
+        document.report_generator_form.submit();
+      } // -->
+ </script>
+[%- END %]
+
   </form>
  [% END %]
 
index 41eb6c0..5af4de8 100644 (file)
@@ -3,16 +3,6 @@
 
  [%- SET default_margin = LxERP.format_amount(1.5) %]
 
- <script type="text/javascript">
-  <!--
-      function submit_report_generator_form(nextsub) {
-        document.report_generator_form.report_generator_dispatch_to.value = nextsub;
-        document.report_generator_form.submit();
-      }
-
-    -->
- </script>
-
  <div class="listheading" width="100%">[% HTML.escape(title) %]</div>
 
  <form action="[% HTML.escape(script) %]" method="post" name="report_generator_form">
@@ -23,7 +13,6 @@
 
   <input type="hidden" name="report_generator_pdf_options_set" value="1">
   <input type="hidden" name="report_generator_dispatch_to" value="">
-  <input type="hidden" name="action" value="report_generator_dispatcher">
 
   <table>
    <tr>
    [% END %]
   </table>
 
+[%- IF CONTROLLER_DISPATCH %]
+   <p>
+    <input type="hidden" name="action" value="[% CONTROLLER_DISPATCH | html %]/dispatch">
+    <input type="submit" name="action_report_generator_export_as_pdf" value="[% 'Export as PDF' | $T8 %]">
+    <input type="submit" name="action_report_generator_back" value="[% 'Back' | $T8 %]">
+    <input type="hidden" name="CONTROLLER_DISPATCH" value="[% CONTROLLER_DISPATCH | html %]">
+   </p>
+[%- ELSE %]
   <p>
+   <input type="hidden" name="action" value="report_generator_dispatcher">
    <input type="submit" class="submit" onclick="submit_report_generator_form('report_generator_export_as_pdf')" value="[% 'Export as PDF' | $T8 %]">
    <input type="submit" class="submit" onclick="submit_report_generator_form('report_generator_back')" value="[% 'Back' | $T8 %]">
   </p>
+ <script type="text/javascript"><!--
+      function submit_report_generator_form(nextsub) {
+        document.report_generator_form.report_generator_dispatch_to.value = nextsub;
+        document.report_generator_form.submit();
+      } // -->
+ </script>
+[%- END %]
 
  </form>
 </body>