Merge branch 'currency'
authorNiclas Zimmermann <niclas@kivitendo-premium.de>
Fri, 24 May 2013 09:49:46 +0000 (11:49 +0200)
committerNiclas Zimmermann <niclas@kivitendo-premium.de>
Fri, 24 May 2013 09:49:46 +0000 (11:49 +0200)
60 files changed:
SL/AP.pm
SL/AR.pm
SL/BackgroundJob/SelfTest/Transactions.pm
SL/CT.pm
SL/ClientJS.pm
SL/Common.pm
SL/Controller/Base.pm
SL/DATEV.pm
SL/DB.pm
SL/DBConnect.pm
SL/DBUpgrade2.pm
SL/DBUpgrade2/Base.pm
SL/DO.pm
SL/Dispatcher.pm
SL/Form.pm
SL/GL.pm
SL/IR.pm
SL/IS.pm
SL/LXDebug.pm
SL/Request.pm
SL/SEPA.pm
SL/SEPA/XML.pm
SL/Template/Plugin/L.pm
SL/User.pm
SL/VK.pm
bin/mozilla/do.pl
bin/mozilla/rp.pl
bin/mozilla/sepa.pl
bin/mozilla/vk.pl
config/kivitendo.conf.default
js/client_js.js
js/part_selection.js
locale/de/all
menu.ini
scripts/generate_client_js_actions.tpl
scripts/locales.pl
sql/Pg-upgrade2/USTVA_abstraction.pl
sql/Pg-upgrade2/USTVA_at.pl
sql/Pg-upgrade2/acc_trans_id_uniqueness.pl
sql/Pg-upgrade2/charts_without_taxkey.pl
sql/Pg-upgrade2/contacts_add_cp_position.pl
sql/Pg-upgrade2/contacts_add_street_and_zipcode_and_city.pl
sql/Pg-upgrade2/contacts_convert_cp_birthday_to_date.pl
sql/Pg-upgrade2/defaults_datev_check.pl
sql/Pg-upgrade2/defaults_posting_config.pl
sql/Pg-upgrade2/defaults_show_bestbefore.pl
sql/Pg-upgrade2/erzeugnisnummern.pl
sql/Pg-upgrade2/globalprojectnumber_ap_ar_oe.pl
sql/Pg-upgrade2/steuerfilterung.pl
sql/Pg-upgrade2/umstellung_eur.pl
t/controllers/helpers/parse_filter.t
t/helper/csv.t
t/request/flatten.t
templates/webpages/ct/search_contact.html
templates/webpages/dbupgrade/erzeugnisnummern.html
templates/webpages/dbupgrade/steuerfilterung.html
templates/webpages/do/search.html
templates/webpages/gl/form_header_chart_balances_js.html
templates/webpages/ic/search.html
templates/webpages/sepa/bank_transfer_create.html

index 04e1ade..bc5a362 100644 (file)
--- a/SL/AP.pm
+++ b/SL/AP.pm
@@ -415,6 +415,7 @@ sub post_transaction {
       dbh        => $dbh,
       from       => $transdate,
       to         => $transdate,
+      trans_id   => $form->{id},
     );
 
     $datev->export;
index 212b2b8..b6a7376 100644 (file)
--- a/SL/AR.pm
+++ b/SL/AR.pm
@@ -330,6 +330,7 @@ sub post_transaction {
       dbh        => $dbh,
       from       => $transdate,
       to         => $transdate,
+      trans_id   => $form->{id},
     );
 
     $datev->export;
index a7fe763..9b5daed 100644 (file)
@@ -15,7 +15,7 @@ sub run {
 
   $self->_setup;
 
-  $self->tester->plan(tests => 15);
+  $self->tester->plan(tests => 16);
 
   $self->check_konten_mit_saldo_nicht_in_guv;
   $self->check_bilanzkonten_mit_pos_eur;
@@ -31,6 +31,7 @@ sub run {
   $self->check_paid_stornos;
   $self->check_stornos_ohne_partner;
   $self->check_overpayments;
+  $self->check_every_account_with_taxkey;
   $self->calc_saldenvortraege;
 }
 
@@ -392,6 +393,23 @@ sub calc_saldenvortraege {
   $self->tester->diag("Saldo $saldenvortragskonto am 31.12.@{[DateTime->today->year]}: @{[ $saldo_9000_jahresende * 1 ]}    (sollte 0 sein)");
 }
 
+sub check_every_account_with_taxkey {
+  my ($self) = @_;
+
+  my $query = qq|SELECT accno, description FROM chart WHERE id NOT IN (select chart_id from taxkeys)|;
+  my $accounts_without_tk = selectall_hashref_query($::form, $self->dbh, $query);
+
+  if ( scalar @{ $accounts_without_tk } > 0 ){
+    $self->tester->ok(0, "Folgende Konten haben keinen gültigen Steuerschlüssel:");
+
+    for my $account_without_tk (@{ $accounts_without_tk } ) {
+      $self->tester->diag("Kontonummer: $account_without_tk->{accno} Beschreibung: $account_without_tk->{description}");
+    }
+  } else {
+    $self->tester->ok(1, "Jedes Konto hat einen gültigen Steuerschlüssel!");
+  }
+}
+
 1;
 
 __END__
index 39c29b0..66b3e25 100644 (file)
--- a/SL/CT.pm
+++ b/SL/CT.pm
@@ -616,24 +616,24 @@ sub search {
   my @values;
 
   my %allowed_sort_columns = (
-      "id" => "id",
-      "customernumber" => "customernumber",
-      "vendornumber" => "vendornumber",
-      "name" => "ct.name",
-      "contact" => "contact",
-      "phone" => "phone",
-      "fax" => "fax",
-      "email" => "email",
-      "street" => "street",
-      "taxnumber" => "taxnumber",
-      "business" => "business",
-      "invnumber" => "invnumber",
-      "ordnumber" => "ordnumber",
-      "quonumber" => "quonumber",
-      "zipcode" => "zipcode",
-      "city" => "city",
-      "country" => "country",
-      "salesman" => "e.name"
+      "id"                 => "ct.id",
+      "customernumber"     => "ct.customernumber",
+      "vendornumber"       => "ct.vendornumber",
+      "name"               => "ct.name",
+      "contact"            => "ct.contact",
+      "phone"              => "ct.phone",
+      "fax"                => "ct.fax",
+      "email"              => "ct.email",
+      "street"             => "ct.street",
+      "taxnumber"          => "ct.taxnumber",
+      "business"           => "ct.business",
+      "invnumber"          => "ct.invnumber",
+      "ordnumber"          => "ct.ordnumber",
+      "quonumber"          => "ct.quonumber",
+      "zipcode"            => "ct.zipcode",
+      "city"               => "ct.city",
+      "country"            => "ct.country",
+      "salesman"           => "e.name"
     );
 
   $form->{sort} ||= "name";
@@ -675,10 +675,10 @@ sub search {
     $where .= " AND ((lower(ct.city) LIKE lower(?))
                      OR
                      (ct.id IN (
-                        SELECT trans_id
-                        FROM shipto
-                        WHERE (module = 'CT')
-                          AND (lower(shiptocity) LIKE lower(?))
+                        SELECT sc.trans_id
+                        FROM shipto sc
+                        WHERE (sc.module = 'CT')
+                          AND (lower(sc.shiptocity) LIKE lower(?))
                       ))
                      )";
     push @values, ('%' . $form->{addr_city} . '%') x 2;
@@ -688,10 +688,10 @@ sub search {
     $where .= " AND ((lower(ct.country) LIKE lower(?))
                      OR
                      (ct.id IN (
-                        SELECT trans_id
-                        FROM shipto
-                        WHERE (module = 'CT')
-                          AND (lower(shiptocountry) LIKE lower(?))
+                        SELECT so.trans_id
+                        FROM shipto so
+                        WHERE (so.module = 'CT')
+                          AND (lower(so.shiptocountry) LIKE lower(?))
                       ))
                      )";
     push @values, ('%' . $form->{addr_country} . '%') x 2;
@@ -717,20 +717,20 @@ sub search {
   }
 
   if ($form->{obsolete} eq "Y") {
-    $where .= qq| AND obsolete|;
+    $where .= qq| AND ct.obsolete|;
   } elsif ($form->{obsolete} eq "N") {
-    $where .= qq| AND NOT obsolete|;
+    $where .= qq| AND NOT ct.obsolete|;
   }
 
   if ($form->{business_id}) {
-    $where .= qq| AND (business_id = ?)|;
+    $where .= qq| AND (ct.business_id = ?)|;
     push(@values, conv_i($form->{business_id}));
   }
 
   # Nur Kunden finden, bei denen ich selber der Verkäufer bin
   # Gilt nicht für Lieferanten
   if ($cv eq 'customer' &&   !$main::auth->assert('customer_vendor_all_edit', 1)) {
-    $where .= qq| AND ct.salesman_id = (select id from employee where login= ?)|;
+    $where .= qq| AND ct.salesman_id = (select em.id from employee em where em.login = ?)|;
     push(@values, $form->{login});
   }
 
@@ -744,12 +744,12 @@ sub search {
   }
 
   if ($form->{addr_street}) {
-    $where .= qq| AND (street ILIKE ?)|;
+    $where .= qq| AND (ct.street ILIKE ?)|;
     push @values, '%' . $form->{addr_street} . '%';
   }
 
   if ($form->{addr_zipcode}) {
-    $where .= qq| AND (zipcode ILIKE ?)|;
+    $where .= qq| AND (ct.zipcode ILIKE ?)|;
     push @values, $form->{addr_zipcode} . '%';
   }
 
@@ -1157,7 +1157,6 @@ sub search_contacts {
   my %params    = @_;
 
   my $dbh       = $params{dbh} || $::form->get_standard_dbh;
-  my $vc        = $params{db} eq 'customer' ? 'customer' : 'vendor';
 
   my %sortspecs = (
     'cp_name'   => 'cp_name, cp_givenname',
index a04702e..96132cf 100644 (file)
@@ -14,7 +14,7 @@ use Rose::Object::MakeMethods::Generic
 
 my %supported_methods = (
   # ## Non-jQuery methods ##
-  flash        => 2,            # display_flash(<TARGET>, <ARGS>)
+  flash        => 2,            # kivi.display_flash(<TARGET>, <ARGS>)
 
   # ## jQuery basics ##
 
@@ -217,12 +217,12 @@ with jQuery
 First some JavaScript code:
 
   // In the client generate an AJAX request whose 'success' handler
-  // calls "eval_json_response(data)":
+  // calls "eval_json_result(data)":
   var data = {
     action: "SomeController/the_action",
     id:     $('#some_input_field').val()
   };
-  $.post("controller.pl", data, eval_json_response);
+  $.post("controller.pl", data, eval_json_result);
 
 Now some Perl code:
 
@@ -278,7 +278,7 @@ There are three things that need to be done for this to work:
 
 =item 1. The "client_js.js" has to be loaded before the AJAX request is started.
 
-=item 2. The client code needs to call C<eval_json_response()> with the result returned from the server.
+=item 2. The client code needs to call C<kivi.eval_json_result()> with the result returned from the server.
 
 =item 3. The server must use this module.
 
index ff6c721..e86e6c4 100644 (file)
@@ -501,6 +501,8 @@ sub save_email_status {
   } elsif ($form->{script} eq 'ir.pl') {
     $table = 'ap';
 
+  } elsif ($form->{script} eq 'do.pl') {
+    $table = 'delivery_orders';
   }
 
   return $main::lxdebug->leave_sub() if (!$form->{id} || !$table || !$form->{formname});
index 17a1d61..c6977d0 100644 (file)
@@ -512,7 +512,7 @@ the current request is an AJAX request as determined by
 L<SL::Request/is_ajax>. If it is a normal request then it outputs a
 standard HTTP redirect header (HTTP code 302). If it is an AJAX
 request then it outputs an AJAX response suitable for the
-C<eval_json_result> function from the L<SL::ClientJS> module.
+C<kivi.eval_json_result> function from the L<SL::ClientJS> module.
 
 =item C<run_before $sub, %params>
 
index 406f09d..dfd1542 100644 (file)
@@ -193,6 +193,16 @@ sub to {
  return $self->{to};
 }
 
+sub trans_id {
+  my $self = shift;
+
+  if (@_) {
+    $self->{trans_id} = $_[0];
+  }
+
+  return $self->{trans_id};
+}
+
 sub accnofrom {
  my $self = shift;
 
@@ -342,6 +352,10 @@ sub _get_transactions {
 
   my $form     =  $main::form;
 
+  my $trans_id_filter = '';
+
+  $trans_id_filter = 'AND ac.trans_id = ' . $self->trans_id if $self->trans_id;
+
   my ($notsplitindex);
 
   $fromto      =~ s/transdate/ac\.transdate/g;
@@ -363,6 +377,7 @@ sub _get_transactions {
        LEFT JOIN chart c     ON (ac.chart_id    = c.id)
        WHERE (ar.id IS NOT NULL)
          AND $fromto
+         $trans_id_filter
          $filter
 
        UNION ALL
@@ -378,6 +393,7 @@ sub _get_transactions {
        LEFT JOIN chart c   ON (ac.chart_id  = c.id)
        WHERE (ap.id IS NOT NULL)
          AND $fromto
+         $trans_id_filter
          $filter
 
        UNION ALL
@@ -392,6 +408,7 @@ sub _get_transactions {
        LEFT JOIN chart c ON (ac.chart_id  = c.id)
        WHERE (gl.id IS NOT NULL)
          AND $fromto
+         $trans_id_filter
          $filter
 
        ORDER BY trans_id, acc_trans_id|;
index dd55163..5a22c5d 100644 (file)
--- a/SL/DB.pm
+++ b/SL/DB.pm
@@ -126,4 +126,79 @@ sub _flatten_settings {
   return %flattened;
 }
 
+sub with_transaction {
+  my ($self, $code, @args) = @_;
+
+  return $code->(@args) if $self->in_transaction;
+  if (wantarray) {
+    my @result;
+    return $self->do_transaction(sub { @result = $code->(@args) }) ? @result : ();
+
+  } else {
+    my $result;
+    return $self->do_transaction(sub { $result = $code->(@args) }) ? $result : undef;
+  }
+}
+
 1;
+__END__
+
+=pod
+
+=encoding utf8
+
+=head1 NAME
+
+SL::DB - Database access class for all RDB objects
+
+=head1 FUNCTIONS
+
+=over 4
+
+=item C<create $domain, $type>
+
+Registers the database information with Rose, creates a cached
+connection and executes initial SQL statements. Those can include
+setting the time & date format to the user's preferences.
+
+=item C<dbi_connect $dsn, $login, $password, $options>
+
+Forwards the call to L<SL::DBConnect/connect> which connects to the
+database. This indirection allows L<SL::DBConnect/connect> to route
+the calls through L<DBIx::Log4Perl> if this is enabled in the
+configuration.
+
+=item C<with_transaction $code_ref, @args>
+
+Executes C<$code_ref> with parameters C<@args> within a transaction,
+starting one if none is currently active. Example:
+
+  return $self->db->with_transaction(sub {
+    # do stuff with $self
+  });
+
+One big difference to L<Rose::DB/do_transaction> is the return code
+handling. If a transaction is already active then C<with_transcation>
+simply returns the result of calling C<$code_ref> as-is.
+
+Otherwise the return value depends on the result of the underlying
+transaction. If the transaction fails then C<undef> is returned in
+scalar context and an empty list in list context. If the transaction
+succeeds then the return value of C<$code_ref> is returned preserving
+context.
+
+So if you want to differentiate between "transaction failed" and
+"succeeded" then your C<$code_ref> should never return C<undef>
+itself.
+
+=back
+
+=head1 BUGS
+
+Nothing here yet.
+
+=head1 AUTHOR
+
+Moritz Bunkus E<lt>m.bunkus@linet-services.deE<gt>
+
+=cut
index 4e08450..8dc9787 100644 (file)
@@ -20,4 +20,14 @@ sub connect {
   return DBIx::Log4perl->connect(@_);
 }
 
+sub get_options {
+  my $self    = shift;
+  my $options = {
+    pg_enable_utf8 => $::locale->is_utf8,
+    @_
+  };
+
+  return $options;
+}
+
 1;
index d98627c..6de1fd2 100644 (file)
@@ -242,6 +242,8 @@ sub process_perl_script {
 
   my ($self, $dbh, $filename, $version_or_control, $db_charset) = @_;
 
+  my %form_values = map { $_ => $::form->{$_} } qw(dbconnect dbdefault dbdriver dbhost dbmbkiviunstable dbname dboptions dbpasswd dbport dbupdate dbuser login template_object version);
+
   $dbh->begin_work;
 
   # setup dbup_ export vars & run script
@@ -272,6 +274,13 @@ sub process_perl_script {
   }
   $dbh->commit();
 
+  # Clear $::form of values that may have been set so that following
+  # Perl upgrade scripts won't have to work with old data (think of
+  # the usual 'continued' mechanism that's used for determining
+  # whether or not the upgrade form must be displayed).
+  delete @{ $::form }{ keys %{ $::form } };
+  $::form->{$_} = $form_values{$_} for keys %form_values;
+
   $::lxdebug->leave_sub();
 }
 
@@ -540,6 +549,7 @@ depends on. All other upgrades listed in C<depends> will be applied
 before the current one is applied.
 
 =item charset
+
 =item encoding
 
 The charset this file uses. Defaults to C<ISO-8859-15> if
index 09e4e5f..2c1e111 100644 (file)
@@ -41,11 +41,11 @@ sub db_error {
 }
 
 sub db_query {
-  my ($self, $query, $may_fail) = @_;
+  my ($self, $query, %params) = @_;
 
-  return if $self->dbh->do($query);
+  return if $self->dbh->do($query, undef, @{ $params{bind} || [] });
 
-  $self->db_error($query) unless $may_fail;
+  $self->db_error($query) unless $params{may_fail};
 
   $self->dbh->rollback;
   $self->dbh->begin_work;
@@ -204,13 +204,24 @@ C<$coa_name>.
 
 Outputs an error message C<$message> to the user and aborts execution.
 
-=item C<db_query $query, $may_fail>
+=item C<db_query $query, %params>
 
-Executes an SQL query. What the method does if the query fails depends
-on C<$may_fail>. If it is falsish then the method will simply die
-outputting the error message via L</db_error>. If C<$may_fail> is
-trueish then the current transaction will be rolled back, a new one
-will be started
+Executes an SQL query. The following parameters are supported:
+
+=over 2
+
+=item C<may_fail>
+
+What the method does if the query fails depends on this parameter. If
+it is falsish (the default) then the method will simply die outputting
+the error message via L</db_error>. If C<may_fail> is trueish then the
+current transaction will be rolled back, a new one will be started.
+
+=item C<bind>
+
+An optional array reference containing bind parameter for the query.
+
+=back
 
 =item C<execute_script>
 
index 5d406dc..f3623c9 100644 (file)
--- a/SL/DO.pm
+++ b/SL/DO.pm
@@ -61,7 +61,8 @@ sub transactions {
   my $vc = $form->{vc} eq "customer" ? "customer" : "vendor";
 
   my $query =
-    qq|SELECT dord.id, dord.donumber, dord.ordnumber, dord.transdate,
+    qq|SELECT dord.id, dord.donumber, dord.ordnumber,
+         dord.transdate, dord.reqdate,
          ct.${vc}number, ct.name, dord.${vc}_id, dord.globalproject_id,
          dord.closed, dord.delivered, dord.shippingpoint, dord.shipvia,
          dord.transaction_description,
@@ -143,6 +144,7 @@ sub transactions {
 
   my %allowed_sort_columns = (
     "transdate"               => "dord.transdate",
+    "reqdate"                 => "dord.reqdate",
     "id"                      => "dord.id",
     "donumber"                => "dord.donumber",
     "ordnumber"               => "dord.ordnumber",
index 828dc1f..93d3a18 100644 (file)
@@ -209,6 +209,7 @@ sub handle_request {
   my %routing;
   eval { %routing = _route_request($ENV{SCRIPT_NAME}); 1; } or return;
   ($routing_type, $script_name, $action) = @routing{qw(type controller action)};
+  $::lxdebug->log_request($routing_type, $script_name, $action);
 
   $::request->type(lc($routing{request_type} || 'html'));
 
index f7097bd..30c8bd4 100644 (file)
@@ -1361,21 +1361,13 @@ sub datetonum {
 
 # Database routines used throughout
 
-sub _dbconnect_options {
-  my $self    = shift;
-  my $options = { pg_enable_utf8 => $::locale->is_utf8,
-                  @_ };
-
-  return $options;
-}
-
 sub dbconnect {
   $main::lxdebug->enter_sub(2);
 
   my ($self, $myconfig) = @_;
 
   # connect to database
-  my $dbh = SL::DBConnect->connect($myconfig->{dbconnect}, $myconfig->{dbuser}, $myconfig->{dbpasswd}, $self->_dbconnect_options)
+  my $dbh = SL::DBConnect->connect($myconfig->{dbconnect}, $myconfig->{dbuser}, $myconfig->{dbpasswd}, SL::DBConnect->get_options)
     or $self->dberror;
 
   # set db options
@@ -1394,7 +1386,7 @@ sub dbconnect_noauto {
   my ($self, $myconfig) = @_;
 
   # connect to database
-  my $dbh = SL::DBConnect->connect($myconfig->{dbconnect}, $myconfig->{dbuser}, $myconfig->{dbpasswd}, $self->_dbconnect_options(AutoCommit => 0))
+  my $dbh = SL::DBConnect->connect($myconfig->{dbconnect}, $myconfig->{dbuser}, $myconfig->{dbpasswd}, SL::DBConnect->get_options(AutoCommit => 0))
     or $self->dberror;
 
   # set db options
index a422877..ada29ac 100644 (file)
--- a/SL/GL.pm
+++ b/SL/GL.pm
@@ -171,10 +171,10 @@ sub post_transaction {
         qq|INSERT INTO acc_trans (trans_id, chart_id, amount, transdate,
                                   source, memo, project_id, taxkey, tax_id, chart_link)
            VALUES (?, (SELECT chart_id FROM tax WHERE id = ?),
-                   ?, ?, ?, ?, ?, ?, ?, (SELECT link 
-                                         FROM chart 
-                                         WHERE id = (SELECT chart_id 
-                                                     FROM tax 
+                   ?, ?, ?, ?, ?, ?, ?, (SELECT link
+                                         FROM chart
+                                         WHERE id = (SELECT chart_id
+                                                     FROM tax
                                                      WHERE id = ?)))|;
       @values = (conv_i($form->{id}), conv_i($form->{"tax_id_$i"}),
                  $tax, conv_date($form->{transdate}), $form->{"source_$i"},
@@ -198,6 +198,7 @@ sub post_transaction {
       dbh        => $dbh,
       from       => $transdate,
       to         => $transdate,
+      trans_id   => $form->{id},
     );
 
     $datev->export;
index 70a747e..5c335ec 100644 (file)
--- a/SL/IR.pm
+++ b/SL/IR.pm
@@ -767,6 +767,7 @@ sub post_invoice {
       dbh        => $dbh,
       from       => $transdate,
       to         => $transdate,
+      trans_id   => $form->{id},
     );
 
     $datev->export;
index 35c2c40..a844b73 100644 (file)
--- a/SL/IS.pm
+++ b/SL/IS.pm
@@ -1172,6 +1172,7 @@ sub post_invoice {
       dbh        => $dbh,
       from       => $transdate,
       to         => $transdate,
+      trans_id   => $form->{id},
     );
 
     $datev->export;
index 17009dd..6517d9c 100644 (file)
@@ -8,34 +8,29 @@ use constant QUERY              =>  1 << 3;
 use constant TRACE              =>  1 << 4;
 use constant BACKTRACE_ON_ERROR =>  1 << 5;
 use constant REQUEST_TIMER      =>  1 << 6;
-use constant WARN               =>  1 << 7;
-use constant TRACE2             =>  1 << 8;
-use constant ALL                => (1 << 9) - 1;
+use constant REQUEST            =>  1 << 7;
+use constant WARN               =>  1 << 8;
+use constant TRACE2             =>  1 << 9;
+use constant ALL                => (1 << 10) - 1;
 use constant DEVEL              => INFO | DEBUG1 | QUERY | TRACE | BACKTRACE_ON_ERROR | REQUEST_TIMER;
 
 use constant FILE_TARGET   => 0;
 use constant STDERR_TARGET => 1;
 
+use Data::Dumper;
 use POSIX qw(strftime getppid);
 use Time::HiRes qw(gettimeofday tv_interval);
 use YAML;
+use SL::Request ();
 
 use strict;
 
-my ($data_dumper_available, $text_diff_available);
+my ($text_diff_available);
 
-our $global_level;
-our $watch_form;
+our $global_level = NONE();
+our $watch_form   = 0;
 our $file_name;
 
-BEGIN {
-  eval("use Data::Dumper");
-  $data_dumper_available = $@ ? 0 : 1;
-
-  $global_level      = NONE;
-  $watch_form        = 0;
-}
-
 sub new {
   my $type = shift;
   my $self = {};
@@ -159,38 +154,29 @@ sub warn {
 sub dump {
   my ($self, $level, $name, $variable, %options) = @_;
 
-  if ($data_dumper_available) {
-    my $password;
-    if ($variable && ('Form' eq ref $variable) && defined $variable->{password}) {
-      $password             = $variable->{password};
-      $variable->{password} = 'X' x 8;
-    }
-
-    my $dumper = Data::Dumper->new([$variable]);
-    $dumper->Sortkeys(1);
-    $dumper->Indent(2);
-    $dumper->$_($options{$_}) for keys %options;
-    my $output = $dumper->Dump();
-    $self->message($level, "dumping ${name}:\n" . $output);
-
-    $variable->{password} = $password if (defined $password);
+  my $password;
+  if ($variable && ('Form' eq ref $variable) && defined $variable->{password}) {
+    $password             = $variable->{password};
+    $variable->{password} = 'X' x 8;
+  }
 
-    # Data::Dumper does not reset the iterator belonging to this hash
-    # if 'Sortkeys' is true. Therefore clear the iterator manually.
-    # See "perldoc -f each".
-    if ($variable && (('HASH' eq ref $variable) || ('Form' eq ref $variable))) {
-      keys %{ $variable };
-    }
+  my $dumper = Data::Dumper->new([$variable]);
+  $dumper->Sortkeys(1);
+  $dumper->Indent(2);
+  $dumper->$_($options{$_}) for keys %options;
+  my $output = $dumper->Dump();
+  $self->message($level, "dumping ${name}:\n" . $output);
 
-    return $output;
+  $variable->{password} = $password if (defined $password);
 
-  } else {
-    $self->message($level,
-                   "dumping ${name}: Data::Dumper not available; "
-                     . "variable cannot be dumped");
-
-    return undef;
+  # Data::Dumper does not reset the iterator belonging to this hash
+  # if 'Sortkeys' is true. Therefore clear the iterator manually.
+  # See "perldoc -f each".
+  if ($variable && (('HASH' eq ref $variable) || ('Form' eq ref $variable))) {
+    keys %{ $variable };
   }
+
+  return $output;
 }
 
 sub dump_yaml {
@@ -267,14 +253,19 @@ sub _write {
   local *FILE;
 
   chomp($message);
+  $self->_write_raw("${date}${message}\n");
+}
 
+sub _write_raw {
+  my ($self, $message) = @_;
+  local *FILE;
   if ((FILE_TARGET == $self->{"target"})
       && open(FILE, ">>", $self->{"file"})) {
-    print(FILE "${date}${message}\n");
-    close(FILE);
+    print FILE $message;
+    close FILE;
 
   } elsif (STDERR_TARGET == $self->{"target"}) {
-    print(STDERR "${date}${message}\n");
+    print STDERR $message;
   }
 }
 
@@ -338,6 +329,44 @@ sub level_by_name {
   return $global_level & $self->_by_name($level);
 }
 
+sub is_request_logging_enabled {
+  my ($self) = @_;
+  return $global_level & REQUEST;
+}
+
+sub add_request_params {
+  my ($self, $key, $value) = @_;
+  return unless $self->is_request_logging_enabled;
+  return if $key =~ /password/;
+
+  push @{ $::request->{debug}{PARAMS} ||= [] }, [ $key => $value ];
+}
+
+sub log_request {
+  my ($self, $type, $controller, $action) = @_;
+  return unless $self->is_request_logging_enabled;
+
+  my $session_id = $::auth->create_or_refresh_session;
+
+  my $template = <<EOL;
+*************************************
+ $ENV{REQUEST_METHOD} $ENV{SCRIPT_NAME}    $session_id ($::myconfig{login})
+   routing: $type, controller: $controller, action: $action
+EOL
+
+  $self->_write('Request', $template);
+
+  my $params = join "\n   ", map {
+    "$_->[0] = $_->[1]"
+  } @{ $::request->{debug}{PARAMS} || [] };
+
+  $self->_write_raw(<<EOL);
+
+ Params
+   $params
+EOL
+}
+
 1;
 __END__
 
index 4479bd7..860a0f0 100644 (file)
@@ -70,19 +70,23 @@ sub _store_value {
 sub _input_to_hash {
   $::lxdebug->enter_sub(2);
 
-  my ($target, $input) = @_;
+  my ($target, $input, $log) = @_;
   my @pairs = split(/&/, $input);
 
   foreach (@pairs) {
     my ($key, $value) = split(/=/, $_, 2);
-    _store_value($target, uri_decode($key), uri_decode($value)) if ($key);
+    next unless $key;
+    _store_value($target, uri_decode($key), uri_decode($value));
+
+    # for debugging
+    $::lxdebug->add_request_params(uri_decode($key) => uri_decode($value)) if $log;
   }
 
   $::lxdebug->leave_sub(2);
 }
 
 sub _parse_multipart_formdata {
-  my ($target, $temp_target, $input) = @_;
+  my ($target, $temp_target, $input, $log) = @_;
   my ($name, $filename, $headers_done, $content_type, $boundary_found, $need_cr, $previous, $p_attachment, $encoding, $transfer_encoding);
   my $data_start = 0;
 
@@ -113,6 +117,7 @@ sub _parse_multipart_formdata {
       } else {
         ${ $previous } = $data;
       }
+      $::lxdebug->add_request_params($name, $$previous) if $log;
 
       undef $previous;
       undef $filename;
@@ -263,8 +268,8 @@ sub read_cgi_input {
 
   # since both of these can potentially bring their encoding in INPUT_ENCODING
   # they get dumped into temp_target
-  _input_to_hash($temp_target, $ENV{QUERY_STRING}) if $ENV{QUERY_STRING};
-  _input_to_hash($temp_target, $ARGV[0])           if @ARGV && $ARGV[0];
+  _input_to_hash($temp_target, $ENV{QUERY_STRING}, 1) if $ENV{QUERY_STRING};
+  _input_to_hash($temp_target, $ARGV[0],           1) if @ARGV && $ARGV[0];
 
   if ($ENV{CONTENT_LENGTH}) {
     my $content;
@@ -272,10 +277,10 @@ sub read_cgi_input {
     if ($ENV{'CONTENT_TYPE'} && $ENV{'CONTENT_TYPE'} =~ /multipart\/form-data/) {
       # multipart formdata can bring it's own encoding, so give it both
       # and let ti decide on it's own
-      _parse_multipart_formdata($target, $temp_target, $content);
+      _parse_multipart_formdata($target, $temp_target, $content, 1);
     } else {
       # normal encoding must be recoded
-      _input_to_hash($temp_target, $content);
+      _input_to_hash($temp_target, $content, 1);
     }
   }
 
@@ -312,7 +317,7 @@ sub flatten {
   for (ref $source) {
     /^HASH$/ && do {
       my $first = 1;
-      for my $key (keys %$source) {
+      for my $key (sort keys %$source) {
         flatten($source->{$key} => $target, (defined $prefix ? $prefix . $arr_prefix->($first) . '.' : '') . $key);
         $first = 0;
       };
index 73a3330..d31204e 100644 (file)
@@ -178,7 +178,7 @@ sub retrieve_export {
     my ($columns, $joins);
 
     if ($params{details}) {
-      $columns = qq|, arap.invnumber, arap.invoice, arap.transdate AS reference_date, vc.name AS vc_name, c.accno AS chart_accno, c.description AS chart_description|;
+      $columns = qq|, arap.invnumber, arap.invoice, arap.transdate AS reference_date, vc.name AS vc_name, vc.${vc}number AS vc_number, c.accno AS chart_accno, c.description AS chart_description|;
       $joins   = qq|LEFT JOIN ${arap} arap ON (sei.${arap}_id = arap.id)
                     LEFT JOIN ${vc} vc     ON (arap.${vc}_id  = vc.id)
                     LEFT JOIN chart c      ON (sei.chart_id   = c.id)|;
@@ -398,7 +398,7 @@ sub post_payment {
 
     # Record the payment in acc_trans offsetting AR/AP.
     do_statement($form, @{ $handles{add_acc_trans} }, $orig_item->{"${arap}_id"}, $arap_chart_id,         -1 * $mult * $orig_item->{amount}, $item->{execution_date}, '', $arap_chart_id);
-    do_statement($form, @{ $handles{add_acc_trans} }, $orig_item->{"${arap}_id"}, $orig_item->{chart_id},      $mult * $orig_item->{amount}, $item->{execution_date}, $orig_item->{reference}, 
+    do_statement($form, @{ $handles{add_acc_trans} }, $orig_item->{"${arap}_id"}, $orig_item->{chart_id},      $mult * $orig_item->{amount}, $item->{execution_date}, $orig_item->{reference},
                                                       $orig_item->{chart_id});
 
     # Update the invoice to reflect the new paid amount.
index 35f116a..90c77ec 100644 (file)
@@ -223,7 +223,7 @@ sub to_xml {
         $xml->startTag('DrctDbtTx');
 
         $xml->startTag('MndtRltdInf');
-        $xml->dataElement('MndtId', $self->_restricted_identification_sepa2($transaction->get('reference')));
+        $xml->dataElement('MndtId', $self->_restricted_identification_sepa2($transaction->get('company_number')));
         $xml->dataElement('DtOfSgntr', $transaction->get('reference_date', 2010-12-02));
         $xml->endTag('MndtRltdInf');
 
index fa18692..5ef07b7 100644 (file)
@@ -2,6 +2,7 @@ package SL::Template::Plugin::L;
 
 use base qw( Template::Plugin );
 use Template::Plugin;
+use Data::Dumper;
 use List::MoreUtils qw(apply);
 use List::Util qw(max);
 use Scalar::Util qw(blessed);
@@ -115,7 +116,7 @@ sub radio_button_tag {
   my ($self, $name, %attributes) = _hashify(2, @_);
 
   _set_id_attribute(\%attributes, $name);
-  $attributes{value}   = 1 unless defined $attributes{value};
+  $attributes{value}   = 1 unless exists $attributes{value};
   my $label            = delete $attributes{label};
 
   if ($attributes{checked}) {
@@ -184,7 +185,7 @@ sub ajax_submit_tag {
 
   $url           = _J($url);
   $form_selector = _J($form_selector);
-  my $onclick    = qq|submit_ajax_form('${url}', '${form_selector}')|;
+  my $onclick    = qq|kivi.submit_ajax_form('${url}', '${form_selector}')|;
 
   return $self->button_tag($onclick, $text, @slurp);
 }
@@ -439,7 +440,6 @@ sub online_help_tag {
 
 sub dump {
   my $self = shift;
-  require Data::Dumper;
   return '<pre>' . Data::Dumper::Dumper(@_) . '</pre>';
 }
 
@@ -580,8 +580,8 @@ clicks the dialog's ok/yes button.
 Creates a HTML 'input type="button"' tag with a very specific onclick
 handler that submits the form given by the jQuery selector
 C<$form_selector> to the URL C<$url> (the actual JavaScript function
-called for that is C<submit_ajax_form()> in C<js/client_js.js>). The
-button's label will be C<$text>.
+called for that is C<kivi.submit_ajax_form()> in
+C<js/client_js.js>). The button's label will be C<$text>.
 
 =item C<button_tag $onclick, $text, %attributes>
 
index 21c3689..e11fda4 100644 (file)
@@ -105,7 +105,7 @@ sub login {
     my %myconfig = $main::auth->read_user(login => $self->{login});
 
     # check if database is down
-    my $dbh = SL::DBConnect->connect($myconfig{dbconnect}, $myconfig{dbuser}, $myconfig{dbpasswd})
+    my $dbh = SL::DBConnect->connect($myconfig{dbconnect}, $myconfig{dbuser}, $myconfig{dbpasswd}, SL::DBConnect->get_options)
       or $self->error($DBI::errstr);
 
     # we got a connection, check the version
@@ -245,7 +245,7 @@ sub dbsources {
   $form->{sid} = $form->{dbdefault};
   &dbconnect_vars($form, $form->{dbdefault});
 
-  my $dbh = SL::DBConnect->connect($form->{dbconnect}, $form->{dbuser}, $form->{dbpasswd})
+  my $dbh = SL::DBConnect->connect($form->{dbconnect}, $form->{dbuser}, $form->{dbpasswd}, SL::DBConnect->get_options)
     or $form->dberror;
 
   if ($form->{dbdriver} eq 'Pg') {
@@ -262,7 +262,7 @@ sub dbsources {
         next if ($db =~ /^template/);
 
         &dbconnect_vars($form, $db);
-        my $dbh = SL::DBConnect->connect($form->{dbconnect}, $form->{dbuser}, $form->{dbpasswd})
+        my $dbh = SL::DBConnect->connect($form->{dbconnect}, $form->{dbuser}, $form->{dbpasswd}, SL::DBConnect->get_options)
           or $form->dberror;
 
         $query =
@@ -317,7 +317,7 @@ sub dbclusterencoding {
 
   dbconnect_vars($form, $form->{dbdefault});
 
-  my $dbh                = SL::DBConnect->connect($form->{dbconnect}, $form->{dbuser}, $form->{dbpasswd}) || $form->dberror();
+  my $dbh                = SL::DBConnect->connect($form->{dbconnect}, $form->{dbuser}, $form->{dbpasswd}, SL::DBConnect->get_options) || $form->dberror();
   my $query              = qq|SELECT pg_encoding_to_char(encoding) FROM pg_database WHERE datname = 'template0'|;
   my ($cluster_encoding) = $dbh->selectrow_array($query);
   $dbh->disconnect();
@@ -335,7 +335,7 @@ sub dbcreate {
   $form->{sid} = $form->{dbdefault};
   &dbconnect_vars($form, $form->{dbdefault});
   my $dbh =
-    SL::DBConnect->connect($form->{dbconnect}, $form->{dbuser}, $form->{dbpasswd})
+    SL::DBConnect->connect($form->{dbconnect}, $form->{dbuser}, $form->{dbpasswd}, SL::DBConnect->get_options)
     or $form->dberror;
   $form->{db} =~ s/\"//g;
   my %dbcreate = (
@@ -377,7 +377,7 @@ sub dbcreate {
 
   &dbconnect_vars($form, $form->{db});
 
-  $dbh = SL::DBConnect->connect($form->{dbconnect}, $form->{dbuser}, $form->{dbpasswd})
+  $dbh = SL::DBConnect->connect($form->{dbconnect}, $form->{dbuser}, $form->{dbpasswd}, SL::DBConnect->get_options)
     or $form->dberror;
 
   my $db_charset = $Common::db_encoding_to_charset{$form->{encoding}};
@@ -416,7 +416,7 @@ sub dbdelete {
 
   $form->{sid} = $form->{dbdefault};
   &dbconnect_vars($form, $form->{dbdefault});
-  my $dbh = SL::DBConnect->connect($form->{dbconnect}, $form->{dbuser}, $form->{dbpasswd})
+  my $dbh = SL::DBConnect->connect($form->{dbconnect}, $form->{dbuser}, $form->{dbpasswd}, SL::DBConnect->get_options)
     or $form->dberror;
   my $query = $dbdelete{$form->{dbdriver}};
   do_query($form, $dbh, $query);
@@ -462,7 +462,7 @@ sub dbneedsupdate {
     map { $form->{$_} = $member->{$_} } qw(dbname dbuser dbpasswd dbhost dbport);
     dbconnect_vars($form, $form->{dbname});
 
-    my $dbh = SL::DBConnect->connect($form->{dbconnect}, $form->{dbuser}, $form->{dbpasswd});
+    my $dbh = SL::DBConnect->connect($form->{dbconnect}, $form->{dbuser}, $form->{dbpasswd}, SL::DBConnect->get_options);
 
     next unless $dbh;
 
@@ -592,7 +592,7 @@ sub dbupdate {
     $db =~ s/^db//;
     &dbconnect_vars($form, $db);
 
-    my $dbh = SL::DBConnect->connect($form->{dbconnect}, $form->{dbuser}, $form->{dbpasswd})
+    my $dbh = SL::DBConnect->connect($form->{dbconnect}, $form->{dbuser}, $form->{dbpasswd}, SL::DBConnect->get_options)
       or $form->dberror;
 
     $dbh->do($form->{dboptions}) if ($form->{dboptions});
@@ -656,7 +656,7 @@ sub dbupdate2 {
     $db =~ s/^db//;
     &dbconnect_vars($form, $db);
 
-    my $dbh = SL::DBConnect->connect($form->{dbconnect}, $form->{dbuser}, $form->{dbpasswd}) or $form->dberror;
+    my $dbh = SL::DBConnect->connect($form->{dbconnect}, $form->{dbuser}, $form->{dbpasswd}, SL::DBConnect->get_options) or $form->dberror;
 
     $dbh->do($form->{dboptions}) if ($form->{dboptions});
 
@@ -696,7 +696,7 @@ sub save_member {
 
   $main::auth->save_user($self->{login}, map { $_, $self->{$_} } config_vars());
 
-  my $dbh = SL::DBConnect->connect($self->{dbconnect}, $self->{dbuser}, $self->{dbpasswd});
+  my $dbh = SL::DBConnect->connect($self->{dbconnect}, $self->{dbuser}, $self->{dbpasswd}, SL::DBConnect->get_options);
   if ($dbh) {
     $self->create_employee_entry($::form, $dbh, $self, 1);
     $dbh->disconnect();
index c373a19..2c0ce67 100644 (file)
--- a/SL/VK.pm
+++ b/SL/VK.pm
@@ -50,8 +50,12 @@ sub invoice_transactions {
 
   my @values;
 
+  # default usage: always use parts.description for (sub-)totalling and in header and subheader lines
+  # but use invoice.description in article mode
+  # so we extract both versions in our query and later overwrite the description in article mode
+
   my $query =
-    qq|SELECT ct.id as customerid, ct.name as customername,ct.customernumber,ct.country,ar.invnumber,ar.id,ar.transdate,p.partnumber,pg.partsgroup,i.parts_id,i.qty,i.price_factor,i.discount,i.description as description,i.lastcost,i.sellprice,i.fxsellprice,i.marge_total,i.marge_percent,i.unit,b.description as business,e.name as employee,e2.name as salesman, to_char(ar.transdate,'Month') as month, to_char(ar.transdate, 'YYYYMM') as nummonth, p.unit as parts_unit, p.weight | .
+    qq|SELECT ct.id as customerid, ct.name as customername,ct.customernumber,ct.country,ar.invnumber,ar.id,ar.transdate,p.partnumber,p.description as description, pg.partsgroup,i.parts_id,i.qty,i.price_factor,i.discount,i.description as invoice_description,i.lastcost,i.sellprice,i.fxsellprice,i.marge_total,i.marge_percent,i.unit,b.description as business,e.name as employee,e2.name as salesman, to_char(ar.transdate,'Month') as month, to_char(ar.transdate, 'YYYYMM') as nummonth, p.unit as parts_unit, p.weight | .
     qq|FROM invoice i | .
     qq|JOIN ar on (i.trans_id = ar.id) | .
     qq|JOIN parts p on (i.parts_id = p.id) | .
@@ -122,9 +126,12 @@ sub invoice_transactions {
     $where .= qq| AND (ct.country ILIKE ?)|;
     push(@values, '%' . $form->{country} . '%');
   }
-  # nimmt man description am Besten aus invoice oder parts?
+
+  # when filtering for parts by description we probably want to filter by the description of the part as per the master data
+  # invoice.description may differ due to manually changing the description in the invoice or because of translations of the description
+  # at least in the translation case we probably want the report to also include translated articles, so we have to filter via parts.description
   if ($form->{description}) {
-    $where .= qq| AND (i.description ILIKE ?)|;
+    $where .= qq| AND (p.description ILIKE ?)|;
     push(@values, '%' . $form->{description} . '%');
   }
   if ($form->{transdatefrom}) {
index 576564f..a155e8a 100644 (file)
@@ -489,7 +489,7 @@ sub orders {
   $form->{rowcount} = scalar @{ $form->{DO} };
 
   my @columns = qw(
-    ids                     transdate
+    ids                     transdate               reqdate
     id                      donumber
     ordnumber               customernumber
     name                    employee  salesman
@@ -516,6 +516,7 @@ sub orders {
   my %column_defs = (
     'ids'                     => { 'text' => '', },
     'transdate'               => { 'text' => $locale->text('Date'), },
+    'reqdate'                 => { 'text' => $locale->text('Reqdate'), },
     'id'                      => { 'text' => $locale->text('ID'), },
     'donumber'                => { 'text' => $locale->text('Delivery Order'), },
     'ordnumber'               => { 'text' => $locale->text('Order'), },
@@ -531,7 +532,7 @@ sub orders {
     'department'              => { 'text' => $locale->text('Department'), },
   );
 
-  foreach my $name (qw(id transdate donumber ordnumber name employee salesman shipvia transaction_description department)) {
+  foreach my $name (qw(id transdate reqdate donumber ordnumber name employee salesman shipvia transaction_description department)) {
     my $sortdir                 = $form->{sort} eq $name ? 1 - $form->{sortdir} : $form->{sortdir};
     $column_defs{$name}->{link} = $href . "&sort=$name&sortdir=$sortdir";
   }
index c3a13da..d455d5a 100644 (file)
@@ -969,7 +969,7 @@ sub aging {
   $report->set_columns(%column_defs);
   $report->set_column_order(@columns);
 
-  my @hidden_variables = qw(todate customer vendor arap title ct);
+  my @hidden_variables = qw(todate customer vendor arap title ct fordate reporttype);
   $report->set_export_options('generate_' . ($form->{arap} eq 'ar' ? 'ar' : 'ap') . '_aging', @hidden_variables);
 
   my @options;
index 518b9a8..18f48b2 100755 (executable)
@@ -511,6 +511,7 @@ sub bank_transfer_download_sepa_xml {
                                  'dst_iban'       => $item->{vc_iban},
                                  'dst_bic'        => $item->{vc_bic},
                                  'company'        => $item->{vc_name},
+                                 'company_number' => $item->{vc_number},
                                  'amount'         => $item->{amount},
                                  'reference'      => $item->{reference},
                                  'reference_date' => $item->{reference_date},
index c6296e9..a60d430 100644 (file)
@@ -104,6 +104,11 @@ sub invoice_transactions {
 
   # can't currently be configured from report, empty line between main sortings
   my $addemptylines = 1;
+  
+  # don't add empty lines between mainsort subtotals when only subtotal_mainsort is selected
+  if ($form->{l_subtotal_mainsort} eq "Y" and not defined $form->{l_headers_mainsort} and not defined $form->{l_headers_subsort} and not defined $form->{l_subtotal_subsort} ) {
+    $addemptylines = 0 
+  };
 
   if ( $form->{customer} =~ /--/ ) {
     # Felddaten kommen aus Dropdownbox
@@ -119,12 +124,12 @@ sub invoice_transactions {
 
     &check_name('customer', no_select => 1);
 
-    # $form->{customer_id} wurde schon von check_name gesetzt
+    # $form->{customer_id} was already set by check_name
     $form->{customername} = $form->{customer};
   };
-  # ist $form->{customer} leer passiert hier nichts weiter
+  # if $form->{customer} is empty nothing further happens here
 
-  # decimalplaces überprüfen oder auf Default 2 setzen
+  # test for decimalplaces or set to default of 2
   $form->{decimalplaces} = 2 unless $form->{decimalplaces} > 0 && $form->{decimalplaces} < 6;
 
   my $cvar_configs_ct = CVar->get_configs('module' => 'CT');
@@ -281,9 +286,9 @@ sub invoice_transactions {
   $callback = $form->escape($href);
 
   my @subtotal_columns = qw(qty weight sellprice sellprice_total lastcost lastcost_total marge_total marge_percent discount);
-  # Gesamtsumme:
-  # Summe von sellprice_total, lastcost_total und marge_total
-  # Durchschnitt von marge_percent
+  # Total sum:
+  # sum of sellprice_total, lastcost_total and marge_total
+  # average of marge_percent
   my @total_columns = qw(sellprice_total lastcost_total marge_total marge_percent );
 
   my %totals     = map { $_ => 0 } @total_columns;
@@ -402,6 +407,9 @@ sub invoice_transactions {
 
       $row{invnumber}->{link} = build_std_url("script=is.pl", 'action=edit') . "&id=" . E($ar->{id}) . "&callback=${callback}";
 
+      # use partdescription according to invoice in article mode
+      $row{description}->{data} = $ar->{invoice_description};
+
       $report->add_data(\%row);
     }
 
index 9debb7b..4e4919d 100644 (file)
@@ -260,6 +260,8 @@ dbix_log4perl_config = log4perl.logger = FATAL, LOGFILE
 #   TRACE              - Track function calls and returns
 #   BACKTRACE_ON_ERROR - Print a function call backtrace when $form->error() is called
 #   REQUEST_TIMER      - Log timing of HTTP requests
+#   REQUEST            - Log each request. Careful! Passwords get filtered, but
+#                        there may be confidential information being logged here
 #   WARN               - warnings
 #   ALL                - all possible debug messages
 #
index abeac1b..0477715 100644 (file)
@@ -4,17 +4,18 @@
 // "scripts/generate_client_js_actions.pl". See the documentation for
 // SL/ClientJS.pm for instructions.
 
-function display_flash(type, message) {
+namespace("kivi", function(ns) {
+ns.display_flash = function(type, message) {
   $('#flash_' + type + '_content').text(message);
   $('#flash_' + type).show();
-}
+};
 
-function eval_json_result(data) {
+ns.eval_json_result = function(data) {
   if (!data)
     return;
 
   if (data.error)
-    return display_flash('error', data.error);
+    return ns.display_flash('error', data.error);
 
   $(['info', 'warning', 'error']).each(function(idx, category) {
     $('#flash_' + category).hide();
@@ -29,7 +30,7 @@ function eval_json_result(data) {
       // console.log("ACTION " + action[0] + " ON " + action[1]);
 
       // ## Non-jQuery methods ##
-           if (action[0] == 'flash')                display_flash(action[1], action[2]);
+           if (action[0] == 'flash')                kivi.display_flash(action[1], action[2]);
 
       // ## jQuery basics ##
 
@@ -124,13 +125,15 @@ function eval_json_result(data) {
     });
 
   // console.log("current_content_type " + $('#current_content_type').val() + ' ID ' + $('#current_content_id').val());
-}
+};
 
-function submit_ajax_form(url, form_selector, additional_data) {
+ns.submit_ajax_form = function(url, form_selector, additional_data) {
   var separator = /\?/.test(url) ? '&' : '?';
-  $.post(url + separator + $(form_selector).serialize(), additional_data, eval_json_result);
+  $.post(url + separator + $(form_selector).serialize(), additional_data, ns.eval_json_result);
   return true;
-}
+};
+
+});
 
 // Local Variables:
 // mode: js
index 9ce022c..9fd5657 100644 (file)
@@ -12,7 +12,7 @@ function part_selection_window(input_partnumber, input_description, input_partsi
     input_partnotes = input_partnumber;
     input_partnotes = input_partnotes.replace(/partnumber/, "partnotes");
     if (input_partnotes == input_partnumber)
-      input_partnoes = "";
+      input_partnotes = "";
   }
 
   if (filter)
index 2e84032..e681137 100755 (executable)
@@ -285,7 +285,7 @@ $self->{texts} = {
   'Batch Printing'              => 'Druck',
   'Bcc'                         => 'Bcc',
   'Bcc E-mail'                  => 'BCC (E-Mail)',
-  'Because the useability gets worth if one partnumber is used for several parts (for example if you are searching a position for an invoice), partnumbers should be unique.' => 'Da die Benutzerfreundlichkeit durch doppelte Artikelnummern erheblich verschlechtert wird (zum Beispiel, wenn man einen Artikel für eine Rechnung sucht), sollten Artikelnummern eindeutig vergeben sein.',
+  'Because the useability gets worse if one partnumber is used for several parts (for example if you are searching a position for an invoice), partnumbers should be unique.' => 'Da die Benutzerfreundlichkeit durch doppelte Artikelnummern erheblich verschlechtert wird (zum Beispiel, wenn man einen Artikel für eine Rechnung sucht), sollten Artikelnummern eindeutig vergeben sein.',
   'Belegnummer'                 => 'Buchungsnummer',
   'Beratername'                 => 'Beratername',
   'Beraternummer'               => 'Beraternummer',
@@ -298,6 +298,7 @@ $self->{texts} = {
   'Billing/shipping address (street)' => 'Rechnungsadresse (Straße)',
   'Billing/shipping address (zipcode)' => 'Rechnungsadresse (PLZ)',
   'Bin'                         => 'Lagerplatz',
+  'Bin 2'                       => '',
   'Bin From'                    => 'Quelllagerplatz',
   'Bin List'                    => 'Lagerliste',
   'Bin To'                      => 'Ziellagerplatz',
@@ -607,7 +608,9 @@ $self->{texts} = {
   'Decrease'                    => 'Verringern',
   'Default (no language selected)' => 'Standard (keine Sprache ausgewählt)',
   'Default Accounts'            => 'Standardkonten',
+  'Default Bin'                 => '',
   'Default Customer/Vendor Language' => 'Standard-Kunden-/Lieferantensprache',
+  'Default Warehouse'           => '',
   'Default buchungsgruppe'      => 'Standardbuchungsgruppe',
   'Default currency'            => 'Standardwährung',
   'Default currency missing!'   => 'Standardwährung fehlt!',
@@ -2171,7 +2174,7 @@ $self->{texts} = {
   'Top (Javascript)'            => 'Oben (mit Javascript)',
   'Top 100'                     => 'Top 100',
   'Top 100 hinzufuegen'         => 'Top 100 hinzufügen',
-  'Top Level'                   => 'Hauptartikelbezeichnung',
+  'Top Level Designation only'  => 'Nur Hauptartikelbezeichnung',
   'Total'                       => 'Summe',
   'Total Fees'                  => 'Kumulierte Gebühren',
   'Total stock value'           => 'Gesamter Bestandswert',
index 5f85eed..a974868 100644 (file)
--- a/menu.ini
+++ b/menu.ini
@@ -62,7 +62,6 @@ db=vendor
 ACCESS=customer_vendor_edit
 module=ct.pl
 action=search_contact
-db=customer
 
 [Master Data--Reports--Parts]
 ACCESS=part_service_assembly_edit
index 4603266..6772cd1 100644 (file)
@@ -4,17 +4,18 @@
 // "scripts/generate_client_js_actions.pl". See the documentation for
 // SL/ClientJS.pm for instructions.
 
-function display_flash(type, message) {
+namespace("kivi", function(ns) {
+ns.display_flash = function(type, message) {
   $('#flash_' + type + '_content').text(message);
   $('#flash_' + type).show();
-}
+};
 
-function eval_json_result(data) {
+ns.eval_json_result = function(data) {
   if (!data)
     return;
 
   if (data.error)
-    return display_flash('error', data.error);
+    return ns.display_flash('error', data.error);
 
   $(['info', 'warning', 'error']).each(function(idx, category) {
     $('#flash_' + category).hide();
@@ -32,13 +33,15 @@ function eval_json_result(data) {
     });
 
   // console.log("current_content_type " + $('#current_content_type').val() + ' ID ' + $('#current_content_id').val());
-}
+};
 
-function submit_ajax_form(url, form_selector, additional_data) {
+ns.submit_ajax_form = function(url, form_selector, additional_data) {
   var separator = /\?/.test(url) ? '&' : '?';
-  $.post(url + separator + $(form_selector).serialize(), additional_data, eval_json_result);
+  $.post(url + separator + $(form_selector).serialize(), additional_data, ns.eval_json_result);
   return true;
-}
+};
+
+});
 
 // Local Variables:
 // mode: js
index 8105abd..93b34fd 100755 (executable)
@@ -166,6 +166,14 @@ close($js_file);
 my @new_missing = grep { !$self->{texts}{$_} } sort keys %alllocales;
 
 if (@new_missing) {
+  if ($opt_c) {
+    my %existing_lc = map { (lc $_ => $_) } grep { $self->{texts}->{$_} } keys %{ $self->{texts} };
+    foreach my $entry (@new_missing) {
+      my $other = $existing_lc{lc $entry};
+      print "W: No entry for '${entry}' exists, but there is one with different case: '${other}'\n" if $other;
+    }
+  }
+
   generate_file(
     file      => "$locales_dir/missing",
     header    => $MISSING_HEADER,
index a1b4a9c..fc1638c 100644 (file)
@@ -47,8 +47,8 @@ sub create_tables {
       },
   );
 
-  $self->db_query("DROP SCHEMA tax CASCADE;", 1);
-  map({ $self->db_query($_, 0); } @queries);
+  $self->db_query("DROP SCHEMA tax CASCADE;", may_fail => 1);
+  $self->db_query($_) for @queries;
 
   return 1;
 
index 2cffc3d..02143ae 100644 (file)
@@ -48,7 +48,7 @@ sub clear_tables {
       q{ DELETE FROM tax.report_variables; },
   );
 
-  map({ $self->db_query("DELETE FROM $_ ;", 0); } @clear);
+  $self->db_query("DELETE FROM $_") for @clear;
 
   return 1;
 
@@ -303,11 +303,7 @@ sub do_insert_chart {
 
   );
 
-  for my $statement ( 0 .. $#copy_statements ) {
-    my $query = $copy_statements[$statement];
-      #print $query . "<br />";  # Diagnose only!
-      $self->db_query($query, 0);
-  }
+  $self->db_query($_) for @copy_statements;
 
   return 1;
 }
index f90d731..f83e99e 100644 (file)
@@ -33,7 +33,7 @@ SQL
     ))
 SQL
 
-  $self->db_query($query, 0);
+  $self->db_query($query);
 
   my %skipped_acc_trans_ids;
   foreach my $entry (@entries) {
@@ -50,7 +50,7 @@ SQL
           AND (mtime $mtime)
 SQL
 
-      $self->db_query($query, 0);
+      $self->db_query($query);
     }
   }
 
index ff95ff0..7ca9cb8 100644 (file)
@@ -1,6 +1,6 @@
 # @tag: charts_without_taxkey
 # @description: Fügt für jedes Konto, was keinen Steuerschlüssel hat, den Steuerschlüssel 0 hinzu
-# @depends:
+# @depends: release_3_0_0
 package SL::DBUpgrade2::charts_without_taxkey;
 
 use strict;
index 8922847..6bcbbb6 100644 (file)
@@ -11,7 +11,7 @@ use parent qw(SL::DBUpgrade2::Base);
 sub run {
   my ($self) = @_;
 
-  $self->db_query('ALTER TABLE contacts ADD COLUMN cp_position VARCHAR(75)', 1);
+  $self->db_query('ALTER TABLE contacts ADD COLUMN cp_position VARCHAR(75)', may_fail => 1);
 
   return 1;
 }
index f830e7c..9d684c1 100644 (file)
@@ -17,7 +17,7 @@ sub run {
     'ALTER TABLE contacts ADD COLUMN cp_city text;',
   );
 
-  $self->db_query($_, 1) for @queries;
+  $self->db_query($_, may_fail => 1) for @queries;
 
   return 1;
 }
index bb45209..ab4a017 100644 (file)
@@ -11,10 +11,10 @@ use parent qw(SL::DBUpgrade2::Base);
 sub convert_to_date {
   my ($self, $str) = @_;
 
-  return '' if !$str;
+  return '' if !$str || ($str =~ m/00.*00.*00.*00/); # 0000-00-00 may be present in old databases.
 
   my $sth = $self->dbh->prepare('SELECT ?::date AS date') or return undef;
-  $sth->execute($str)                               or return undef;
+  $sth->execute($str)                                     or return undef;
 
   return $sth->fetchrow_hashref->{date};
 }
index e213e62..175da42 100644 (file)
@@ -12,11 +12,11 @@ sub run {
   my ($self) = @_;
 
   # this query will fail if column already exist (new database)
-  $self->db_query(qq|ALTER TABLE defaults ADD COLUMN datev_check_on_sales_invoice boolean    DEFAULT true|, 1);
-  $self->db_query(qq|ALTER TABLE defaults ADD COLUMN datev_check_on_purchase_invoice boolean DEFAULT true|, 1);
-  $self->db_query(qq|ALTER TABLE defaults ADD COLUMN datev_check_on_ar_transaction boolean   DEFAULT true|, 1);
-  $self->db_query(qq|ALTER TABLE defaults ADD COLUMN datev_check_on_ap_transaction boolean   DEFAULT true|, 1);
-  $self->db_query(qq|ALTER TABLE defaults ADD COLUMN datev_check_on_gl_transaction boolean   DEFAULT true|, 1);
+  $self->db_query(qq|ALTER TABLE defaults ADD COLUMN datev_check_on_sales_invoice boolean    DEFAULT true|, may_fail => 1);
+  $self->db_query(qq|ALTER TABLE defaults ADD COLUMN datev_check_on_purchase_invoice boolean DEFAULT true|, may_fail => 1);
+  $self->db_query(qq|ALTER TABLE defaults ADD COLUMN datev_check_on_ar_transaction boolean   DEFAULT true|, may_fail => 1);
+  $self->db_query(qq|ALTER TABLE defaults ADD COLUMN datev_check_on_ap_transaction boolean   DEFAULT true|, may_fail => 1);
+  $self->db_query(qq|ALTER TABLE defaults ADD COLUMN datev_check_on_gl_transaction boolean   DEFAULT true|, may_fail => 1);
 
   # check current configuration and set default variables accordingly, so that
   # kivitendo's behaviour isn't changed by this update
index c638494..a94f2f5 100644 (file)
@@ -12,7 +12,7 @@ sub run {
   my ($self) = @_;
 
   # this query will fail if column already exist (new database)
-  $self->db_query(qq|ALTER TABLE defaults ADD COLUMN payments_changeable integer NOT NULL DEFAULT 0|, 1);
+  $self->db_query(qq|ALTER TABLE defaults ADD COLUMN payments_changeable integer NOT NULL DEFAULT 0|, may_fail => 1);
 
   # check current configuration and set default variables accordingly, so that
   # kivitendo behaviour isn't changed by this update
index 44f3cf9..a7c144c 100644 (file)
@@ -12,7 +12,7 @@ sub run {
   my ($self) = @_;
 
   # this query will fail if column already exist (new database)
-  $self->db_query(qq|ALTER TABLE defaults ADD COLUMN show_bestbefore boolean DEFAULT false|, 1);
+  $self->db_query(qq|ALTER TABLE defaults ADD COLUMN show_bestbefore boolean DEFAULT false|, may_fail => 1);
 
   # check current configuration and set default variables accordingly, so that
   # kivitendo behaviour isn't changed by this update
index 81c0241..4146894 100644 (file)
@@ -8,6 +8,8 @@ use utf8;
 
 use parent qw(SL::DBUpgrade2::Base);
 
+use SL::DBUtils;
+
 sub run {
   my ($self) = @_;
 
@@ -21,7 +23,7 @@ sub run {
     $self->dbh->commit();
   }
 
-  my $query = qq|SELECT id, partnumber, description, unit, notes, assembly, ean, inventory_accno_id
+  my $query = qq|SELECT id, partnumber, description, unit, notes, assembly, ean, inventory_accno_id, obsolete
                    FROM parts pa
                    WHERE (SELECT COUNT(*)
                           FROM parts p
@@ -29,14 +31,7 @@ sub run {
                           > 1
                    ORDER BY partnumber;|;
 
-  my $sth = $self->dbh->prepare($query);
-  $sth->execute || $::form->dberror($query);
-
-  $::form->{PARTS} = [];
-  while (my $ref = $sth->fetchrow_hashref("NAME_lc")) {
-    map {$ref->{$_} = $::locale->{iconv_utf8}->convert($ref->{$_})} keys %$ref;
-    push @{ $::form->{PARTS} }, $ref;
-  }
+  $::form->{PARTS} = [ selectall_hashref_query($::form, $self->dbh, $query) ];
 
   if ( scalar @{ $::form->{PARTS} } > 0 ) {
     &print_error_message;
index df31c04..f12c92a 100644 (file)
@@ -19,8 +19,8 @@ sub run {
      "ALTER TABLE oe ADD COLUMN globalproject_id integer;",
      "ALTER TABLE oe ADD FOREIGN KEY (globalproject_id) REFERENCES project (id);");
 
-  $self->db_query("ALTER TABLE project ADD PRIMARY KEY (id);", 1);
-  map({ $self->db_query($_, 0); } @queries);
+  $self->db_query("ALTER TABLE project ADD PRIMARY KEY (id)", may_fail => 1);
+  $self->db_query($_) for @queries;
 
   return 1;
 }
index 165a779..5fc8f32 100644 (file)
@@ -1,21 +1,22 @@
 # @tag: steuerfilterung
 # @description: Steuern in Dialogbuchungen filtern.
-# @depends: release_3_0_0
+# @depends: release_3_0_0 tax_constraints
 package SL::DBUpgrade2::steuerfilterung;
 
 use strict;
 use utf8;
+use List::Util qw(first);
 
 use parent qw(SL::DBUpgrade2::Base);
 
 sub run {
   my ($self) = @_;
 
-  if ( $::form->{'continued'} ) {
-    my $update_query = qq|ALTER TABLE tax ADD chart_categories TEXT|;
-    $self->db_query($update_query);
-    my $categories;
-    my $tax_id;
+  my $categories;
+  my $tax_id;
+
+  if ( $::form->{continued_tax} ) {
+    my $update_query;
     foreach my $i (1 .. $::form->{rowcount}) {
       $tax_id = $::form->{"tax_id_$i"};
       $categories = '';
@@ -25,7 +26,7 @@ sub run {
       $categories .= 'C' if $::form->{"costs_$i"};
       $categories .= 'I' if $::form->{"revenue_$i"};
       $categories .= 'E' if $::form->{"expense_$i"};
-      $update_query = qq|UPDATE tax SET chart_categories = '$categories' WHERE id=$tax_id|;
+      $update_query = qq|UPDATE tax SET chart_categories = '$categories' WHERE id=$tax_id;|;
       $self->db_query($update_query);
     }
     $update_query = qq|ALTER TABLE tax ALTER COLUMN chart_categories SET NOT NULL|;
@@ -34,19 +35,62 @@ sub run {
     return 1;
   }
 
-  my $query = qq|SELECT taxkey, taxdescription, rate, id AS tax_id FROM tax order by taxkey, rate|;
+  my $query = qq|ALTER TABLE tax ADD chart_categories TEXT|;
+  $self->db_query($query);
+  $self->dbh->commit();
+
+  my @well_known_taxes = (
+      { taxkey => 0,  rate => 0,    taxdescription => qr{keine.*steuer}i,                       categories => 'ALQCIE' },
+      { taxkey => 1,  rate => 0,    taxdescription => qr{frei}i,                                categories => 'ALQCIE' },
+      { taxkey => 2,  rate => 0.07, taxdescription => qr{umsatzsteuer}i,                        categories => 'I' },
+      { taxkey => 3,  rate => 0.16, taxdescription => qr{umsatzsteuer}i,                        categories => 'I' },
+      { taxkey => 3,  rate => 0.19, taxdescription => qr{umsatzsteuer}i,                        categories => 'I' },
+      { taxkey => 8,  rate => 0.07, taxdescription => qr{vorsteuer}i,                           categories => 'E' },
+      { taxkey => 9,  rate => 0.16, taxdescription => qr{vorsteuer}i,                           categories => 'E' },
+      { taxkey => 9,  rate => 0.19, taxdescription => qr{vorsteuer}i,                           categories => 'E' },
+      { taxkey => 10, rate => 0,    taxdescription => qr{andere.*steuerpflichtige.*lieferung}i, categories => 'I' },
+      { taxkey => 11, rate => 0,    taxdescription => qr{frei.*innergem.*mit}i,                 categories => 'I' },
+      { taxkey => 12, rate => 0.07, taxdescription => qr{steuerpflichtig.*lieferung.*erm}i,     categories => 'I' },
+      { taxkey => 13, rate => 0.16, taxdescription => qr{steuerpflichtig.*lieferung.*voll}i,    categories => 'I' },
+      { taxkey => 13, rate => 0.19, taxdescription => qr{steuerpflichtig.*lieferung.*voll}i,    categories => 'I' },
+      { taxkey => 18, rate => 0.07,  taxdescription => qr{innergem.*erwerb.*erm}i,              categories => 'E' },
+      { taxkey => 19, rate => 0.16, taxdescription => qr{innergem.*erwerb.*voll}i,              categories => 'E' },
+      { taxkey => 19, rate => 0.19, taxdescription => qr{innergem.*erwerb.*voll}i,              categories => 'E' },
+      );
+
+  $query = qq|SELECT taxkey, taxdescription, rate, id AS tax_id FROM tax order by taxkey, rate;|;
 
   my $sth = $self->dbh->prepare($query);
   $sth->execute || $::form->dberror($query);
 
+  my $well_known_tax;
+
   $::form->{PARTS} = [];
   while (my $ref = $sth->fetchrow_hashref("NAME_lc")) {
-    $ref->{rate} = $::form->format_amount(\%::myconfig, $::form->round_amount($ref->{rate} * 100));
-    push @{ $::form->{PARTS} }, $ref;
+    $well_known_tax = first {
+      ($ref->{taxkey} == $_->{taxkey})
+      && ($ref->{rate} == $_->{rate})
+      && ($ref->{taxdescription} =~ $_->{taxdescription})
+    } @well_known_taxes;
+    if ($well_known_tax) {
+      $categories = $well_known_tax->{categories};
+      $tax_id = $ref->{tax_id};
+      $query = qq|UPDATE tax SET chart_categories = '$categories' WHERE id=$tax_id;|;
+      $self->db_query($query);
+    } else {
+      $ref->{rate} = $::form->format_amount(\%::myconfig, $::form->round_amount($ref->{rate} * 100));
+      push @{ $::form->{PARTS} }, $ref;
+    }
   }
 
-  &print_message;
-  return 2;
+  if (scalar @{ $::form->{PARTS} } > 0){
+    &print_message;
+    return 2;
+  } else {
+    $query = qq|ALTER TABLE tax ALTER COLUMN chart_categories SET NOT NULL|;
+    $self->db_query($query);
+    return 1;
+  }
 } # end run
 
 sub print_message {
index 0f76060..cf93d76 100644 (file)
@@ -20,7 +20,7 @@ sub run {
 
   foreach my $column (qw(accounting_method inventory_system profit_determination)) {
     # this query will fail if columns already exist (new database)
-    $self->db_query(qq|ALTER TABLE defaults ADD COLUMN ${column} TEXT|, 1);
+    $self->db_query(qq|ALTER TABLE defaults ADD COLUMN ${column} TEXT|, may_fail => 1);
   }
 
   my $accounting_method;
index 9d003c0..1bc3a00 100644 (file)
@@ -35,10 +35,10 @@ test {
   name => 'Test',
   whut => 'moof',
 }, {
-  query => [ %{{
+  query => bag(
     name => 'Test',
     whut => 'moof'
-  }} ],
+  ),
 }, 'basic test';
 
 test {
@@ -96,10 +96,10 @@ test {
     },
   },
 }, {
-  'query' => [ %{{
+  'query' => bag(
                'invoice.customer.name'  => 'test',
                'customer.name'          => 'test',
-             }} ],
+            ),
   'with_objects' => bag( 'invoice.customer', 'customer', 'invoice' )
 }, 'object in more than one relationship';
 
index 3023833..088ed68 100644 (file)
@@ -299,7 +299,7 @@ is_deeply $csv->get_data, [ { description => 'Kaffee' } ], 'case insensitive hea
 #####
 
 $csv = SL::Helper::Csv->new(
-  file   => \"\x{FEFF}description\nKaffee",
+  file   => \"\x{EF}\x{BB}\x{BF}description\nKaffee",
   class  => 'SL::DB::Part',
   encoding => 'utf8',
 );
index 0cfd65f..590f5cf 100644 (file)
@@ -1,5 +1,5 @@
 use Test::More;
-use Test::Deep;
+use Test::Deep qw(cmp_deeply);
 use Data::Dumper;
 
 use_ok 'SL::Request', qw(flatten unflatten);
@@ -13,8 +13,8 @@ sub f ($$$) {
   my $unflat = unflatten($flat);
   print Dumper($unflat) if DEBUG;
 
-  cmp_deeply($flat, $_[1], $_[2]);
-  cmp_deeply($unflat, $_[0], $_[2]);
+  cmp_deeply($flat, $_[1], $_[2] . " flatten");
+  cmp_deeply($unflat, $_[0], $_[2] . " unflatten");
 }
 
 f {
@@ -55,12 +55,12 @@ f {
       'q' => 4
     },
   }
-}, bag(
+}, [
  [ 'x'     => 1, ],
  [ 'y.a'   => 2, ],
  [ 'y.b.p' => 3, ],
  [ 'y.b.q' => 4  ],
-), 'Hash::Flatten 1';
+], 'Hash::Flatten 1';
 
 
 f {
@@ -70,13 +70,13 @@ f {
   },
   'a' => [1,2,3],
 },
-bag (
- ['x'    => 1, ],
+[
  ['0.1'  => 2, ],
  ['a[]'  => 1, ],
  ['a[]'  => 2, ],
  ['a[]'  => 3, ],
-), 'Hash::Flatten 2 - weird keys and values';
+ ['x'    => 1, ],
+], 'Hash::Flatten 2 - weird keys and values';
 
 
 f {
@@ -95,15 +95,15 @@ f {
     },
   ]
 },
-bag(
+[
+  [ 'ay.a'    => 2,       ],
   [ 'ay.b.p'  => 3,       ],
   [ 'ay.b.q'  => 4,       ],
-  [ 'ay.a'    => 2,       ],
   [ 'x'       => 1,       ],
   [ 'y[]'     => 'a',    ],
   [ 'y[]'     => 2        ],
   [ 'y[+].baz' => 'bum',  ],
-), 'Hash::Flatten 3 - mixed';
+], 'Hash::Flatten 3 - mixed';
 
 f {
   'x' => 1,
@@ -117,17 +117,17 @@ f {
     'money',
   ]
 },
-bag(
+[
  [ 'x'        => 1,        ],
- [ 'y[][]'    => 'his',    ],
- [ 'y[][+][]' => 'parted', ],
- [ 'y[][][]'  => 'from',   ],
  [ 'y[+][]'   => 'a',      ],
- [ 'y[+][]'   => 'easily', ],
  [ 'y[][]'    => 'fool',   ],
  [ 'y[][]'    => 'is'      ],
+ [ 'y[+][]'   => 'easily', ],
+ [ 'y[][+][]' => 'parted', ],
+ [ 'y[][][]'  => 'from',   ],
+ [ 'y[][]'    => 'his',    ],
  [ 'y[]'      => 'money',  ],
-), 'Hash::Flatten 4 - array nesting';
+], 'Hash::Flatten 4 - array nesting';
 
 f {
   'x' => 1,
@@ -145,15 +145,15 @@ f {
     },
   ]
 },
-bag(
-  [ 'x'        => 1,     ],
-  [ 's'        => 'hey', ],
+[
   [ 'ay.a'     => 2,     ],
-  [ 'y[+].baz' => 'bum', ],
   [ 'ay.b.p'   => 3,     ],
-  [ 'y[]'      => 'a',   ],
   [ 'ay.b.q'   => 4,     ],
+  [ 's'        => 'hey', ],
+  [ 'x'        => 1,     ],
+  [ 'y[]'      => 'a',   ],
   [ 'y[]'      => 2      ],
-), 'Hash::Flatten 5 - deep mix';
+  [ 'y[+].baz' => 'bum', ],
+], 'Hash::Flatten 5 - deep mix';
 
 done_testing();
index 389328a..f5277bf 100644 (file)
@@ -4,8 +4,6 @@
 [%- USE LxERP %]
  <form method="post" action="ct.pl" name="Form">
 
-  <input type="hidden" name="db" value="[% db | html %]">
-
   <div class="listtop">[% 'Contacts' | $T8 %]</div>
 
   <table>
index e5a7ec6..6466854 100644 (file)
@@ -1,5 +1,5 @@
 [%- USE T8 %]
-[% USE HTML %]<div class="listtop">[% 'Double partnumbers' | $T8 %]</div>
+[% USE HTML %][%- USE LxERP -%]<div class="listtop">[% 'Double partnumbers' | $T8 %]</div>
 
 <form name="Form" method="post" action="login.pl">
 <input type="hidden" name="action" value="login">
@@ -8,7 +8,7 @@
 <p>[% 'There are double partnumbers in your database.' | $T8 %]</p>
 <p>[% 'From this version on the partnumber of services, articles and assemblies have to be unique.' | $T8 %]</p>
 <p>[% 'So far you could use one partnumber for severel parts, for example a service and an article.' | $T8 %]</p>
-<p>[% 'Because the useability gets worth if one partnumber is used for several parts (for example if you are searching a position for an invoice), partnumbers should be unique.' | $T8 %]</p>
+<p>[% 'Because the useability gets worse if one partnumber is used for several parts (for example if you are searching a position for an invoice), partnumbers should be unique.' | $T8 %]</p>
 
 <p>[% 'Please change the partnumber of the following parts and run the update again:' | $T8 %]</p>
 <table>
@@ -19,6 +19,7 @@
     <th class="listheading">[% 'Notes' | $T8 %]</th>
     <th class="listheading">[% 'EAN' | $T8 %]</th>
     <th class="listheading">[% 'Service, assembly or part' | $T8 %]</th>
+    <th class="listheading">[% 'Obsolete' | $T8 %]</th>
   </tr>
 
   [% SET row_odd = '1' %][% FOREACH row = PARTS %]
@@ -30,6 +31,7 @@
     <td align="right">[% HTML.escape(row.notes) %]</td>
     <td align="right">[% HTML.escape(row.ean) %]</td>
     <td align="right">[% IF row.assembly %] [% 'assembly' | $T8 %] [% ELSE %] [% IF row.inventory_accno_id %] [% 'part' | $T8 %] [% ELSE %] [% 'service' | $T8 %] [% END %] [% END %]</td>
+    <td>[% IF row.obsolete %][%- LxERP.t8("Obsolete") %][%- ELSE %][%- LxERP.t8("Not obsolete") %][%- END %]</td>
   </tr>
   [% SET rowcount = loop.count %]
   [% END %]
index da4ebf0..dc3e788 100644 (file)
@@ -6,7 +6,7 @@
 
 <form name="Form" method="post" action="login.pl">
 <input type="hidden" name="action" value="login">
-<input type="hidden" name="continued" value="1">
+<input type="hidden" name="continued_tax" value="1">
 
 <p>[% 'From this version on a new feature is available.' | $T8 %]</p>
 <p>[% 'You can choose account categories for taxes. Depending on these categories taxes will be displayed for transfers in the general ledger or not.' | $T8 %]</p>
     <td align="right">[% HTML.escape(row.taxkey) %]</td>
     <td align="left"> [% HTML.escape(row.taxdescription) %]</a></td>
     <td align="right">[% HTML.escape(row.rate) %] %</td>
-    <td align="center">[% IF row.taxkey == 0 or row.taxkey == 1 %]
-                     [% L.checkbox_tag('asset_' _ loop.count, value => 1, checked => 1, class => 'checkbox') %]
-                     [% ELSE %]
-                     [% L.checkbox_tag('asset_' _ loop.count, value => 1, checked => 0, class => 'checkbox') %]
-                     [% END %]</td>
-
-    <td align="center">[% IF row.taxkey == 0 or row.taxkey == 1 %]
-                     [% L.checkbox_tag('liability_' _ loop.count, value => 1, checked => 1, class => 'checkbox') %]
-                     [% ELSE %]
-                     [% L.checkbox_tag('liability_' _ loop.count, value => 1, checked => 0, class => 'checkbox') %]
-                     [% END %]</td>
-
-    <td align="center">[% IF row.taxkey == 0 or row.taxkey == 1 %]
-                     [% L.checkbox_tag('equity_' _ loop.count, value => 1, checked => 1, class => 'checkbox') %]
-                     [% ELSE %]
-                     [% L.checkbox_tag('equity_' _ loop.count, value => 1, checked => 0, class => 'checkbox') %]
-                     [% END %]</td>
-
-    <td align="center">[% IF row.taxkey == 0 or row.taxkey == 1 %]
-                     [% L.checkbox_tag('costs_' _ loop.count, value => 1, checked => 1, class => 'checkbox') %]
-                     [% ELSE %]
-                     [% L.checkbox_tag('costs_' _ loop.count, value => 1, checked => 0, class => 'checkbox') %]
-                     [% END %]</td>
-
-    <td align="center">[% IF row.taxkey == 8 or row.taxkey == 9 or row.taxkey == 18 or row.taxkey == 19%]
-                     [% L.checkbox_tag('revenue_' _ loop.count, value => 1, checked => 0, class => 'checkbox') %]
-                     [% ELSE %]
-                     [% L.checkbox_tag('revenue_' _ loop.count, value => 1, checked => 1, class => 'checkbox') %]
-                     [% END %]</td>
-
-    <td align="center">[% IF row.taxkey == 2 or row.taxkey == 3 or row.taxkey == 10 or row.taxkey == 11 or row.taxkey == 12 or row.taxkey == 13 %]
-                     [% L.checkbox_tag('expense_' _ loop.count, value => 1, checked => 0, class => 'checkbox') %]
-                     [% ELSE %]
-                     [% L.checkbox_tag('expense_' _ loop.count, value => 1, checked => 1, class => 'checkbox') %]
-                     [% END %]</td>
+    <td align="center">[% L.checkbox_tag('asset_' _ loop.count, value => 1, checked => 1, class => 'checkbox') %]</td>
+    <td align="center">[% L.checkbox_tag('liability_' _ loop.count, value => 1, checked => 1, class => 'checkbox') %]</td>
+    <td align="center">[% L.checkbox_tag('equity_' _ loop.count, value => 1, checked => 1, class => 'checkbox') %]</td>
+    <td align="center">[% L.checkbox_tag('costs_' _ loop.count, value => 1, checked => 1, class => 'checkbox') %]</td>
+    <td align="center">[% L.checkbox_tag('revenue_' _ loop.count, value => 1, checked => 1, class => 'checkbox') %]</td>
+    <td align="center">[% L.checkbox_tag('expense_' _ loop.count, value => 1, checked => 1, class => 'checkbox') %]</td>
   </tr>
   <input type="hidden" name="tax_id_[% loop.count %]" value="[% row.tax_id %]">
   [% SET rowcount = loop.count %]
index 6e1bedc..5bc2a19 100644 (file)
          <input name="l_transdate" id="l_transdate" class="checkbox" type="checkbox" value="Y" checked>
          <label for="l_transdate">[% 'Date' | $T8 %]</label>
         </td>
+        <td>
+         <input name="l_reqdate" id="l_reqdate" class="checkbox" type="checkbox" value="Y" checked>
+         <label for="l_reqdate">[% 'Reqdate' | $T8 %]</label>
+        </td>
+       </tr>
 
+       <tr>
         <td>
          <input name="l_name" id="l_name" class="checkbox" type="checkbox" value="Y" checked>
          <label for="l_name">[% IF is_customer %][% 'Customer' | $T8 %][% ELSE %][% 'Vendor' | $T8 %][% END %]</label>
index 3263ee7..705d8f6 100644 (file)
@@ -12,7 +12,7 @@ chart_balances[[% loop.count - 1 %]] = '[% JavaScript.escape(LxERP.format_amount
 
 function show_chart_balance(obj) {
   var row = $(obj).attr('name').replace(/.*_/, '');
-  var idx = $('#accno_' + row).attr('selectedIndex');
+  var idx = $('#accno_' + row).prop('selectedIndex');
   $('#chart_balance_' + row).html(chart_balances[idx]);
 }
 
index 8379e15..b8276e6 100644 (file)
@@ -73,8 +73,8 @@
       <tr>
        <td></td>
        <td colspan="3">
-        <input name="null" id="null_1" class="radio" type="radio" value="1" checked>&nbsp;<label for="null_1">[% 'Top Level' | $T8 %]</label>
-        <input name="bom" id="bom" class="checkbox" type="checkbox" value="1">&nbsp;<label for="bom">[% 'Individual Items' | $T8 %]</label>
+        [% L.radio_button_tag('bom', id='bom_0', value=0, checked=1, label=LxERP.t8('Top Level Designation only')) %]
+        [% L.radio_button_tag('bom', id='bom_1', value=1,            label=LxERP.t8('Individual Items')) %]
        </td>
       </tr>
       [%- END %]
       <tr>
        <td></td>
        <td colspan="3">
-        <input name="itemstatus" id="itemstatus_active" class="radio" type="radio" value="active" checked>
-        <label for="itemstatus_active">[% 'Active' | $T8 %]</label>
-        <input name="itemstatus" id="itemstatus_onhand" class="radio" type="radio" value="onhand">
+        [%- L.radio_button_tag('itemstatus', value='active', id='itemstatus_active', label=LxERP.t8('Active'), checked=1) %]
       [%- UNLESS is_service %]
-        <label for="itemstatus_onhand">[% 'On Hand' | $T8 %]</label>
-        <input name="itemstatus" id="itemstatus_short" class="radio" type="radio" value="short">
-        <label for="itemstatus_short">[% 'Short' | $T8 %]</label>
-        <input name="itemstatus" id="itemstatus_obsolete" class="radio" type="radio" value="obsolete">
+        [%- L.radio_button_tag('itemstatus', value='onhand', id='itemstatus_onhand', label=LxERP.t8('On Hand')) %]
+        [%- L.radio_button_tag('itemstatus', value='short', id='itemstatus_short', label=LxERP.t8('Short')) %]
+        [%- L.radio_button_tag('itemstatus', value='obsolete', id='itemstatus_obsolete', label=LxERP.t8('Obsolete')) %]
       [%- END %]
-        <label for="itemstatus_obsolete">[% 'Obsolete' | $T8 %]</label>
-        <input name="itemstatus" id="itemstatus_orphaned" class="radio" type="radio" value="orphaned">
-        <label for="itemstatus_orphaned">[% 'Orphaned' | $T8 %]</label>
-        <input name="itemstatus" id="itemstatus_all" class="radio" type="radio" value="">
-        <label for="itemstatus_all">[% 'All' | $T8 %]</label>
+        [%- L.radio_button_tag('itemstatus', value='orphaned', id='itemstatus_orphaned', label=LxERP.t8('Orphaned')) %]
+        [%- L.radio_button_tag('itemstatus', value='', id='itemstatus_all', label=LxERP.t8('All')) %]
        </td>
       </tr>
 
            <table>
             <tr>
              [%- UNLESS is_assembly %]
-             <td><input name="bought" id="bought" class="checkbox" type="checkbox" value="1"></td>
-             <td nowrap><label for="bought">[% 'Bought' | $T8 %]</label></td>
+             <td>[%- L.checkbox_tag('bought', label=LxERP.t8('Bought')) %]</td>
              [%- END %]
-             <td><input name="sold" id="sold" class="checkbox" type="checkbox" value="1"></td>
-             <td nowrap><label for="sold">[% 'Sold' | $T8 %]</label></td>
+             <td>[%- L.checkbox_tag('sold', label=LxERP.t8('Sold')) %]</td>
             </tr>
 
             <tr>
-             <td colspan="4"><hr size="1" noshade></td>
+             <td colspan="2"><hr size="1" noshade></td>
             </tr>
 
             <tr>
              [%- UNLESS is_assembly %]
-             <td><input name="onorder" id="onorder" class="checkbox" type="checkbox" value="1"></td>
-             <td nowrap><label for="onorder">[% 'On Order' | $T8 %]</label></td>
+             <td>[%- L.checkbox_tag('onorder', label=LxERP.t8('On Order')) %]</td>
              [%- END %]
-             <td><input name="ordered" id="ordered" class="checkbox" type="checkbox" value="1"></td>
-             <td nowrap><label for="ordered">[% 'Ordered' | $T8 %]</label></td>
+             <td>[%- L.checkbox_tag('ordered', label=LxERP.t8('Ordered')) %]</td>
             </tr>
 
             <tr>
-             <td colspan="4"><hr size="1" noshade></td>
+             <td colspan="2"><hr size="1" noshade></td>
             </tr>
 
             <tr>
              [%- UNLESS is_assembly %]
-             <td><input name="rfq" id="rfq" class="checkbox" type="checkbox" value="1"></td>
-             <td nowrap><label for="rfq">[% 'RFQ' | $T8 %]</label></td>
+             <td>[%- L.checkbox_tag('rfq', label=LxERP.t8('RFQ')) %]</td>
              [%- END %]
-             <td><input name="quoted" id="quoted" class="checkbox" type="checkbox" value="1"></td>
-             <td nowrap><label for="quoted">[% 'Quoted' | $T8 %]</label></td>
+             <td>[%- L.checkbox_tag('quoted', label=LxERP.t8('Quoted')) %]</td>
             </tr>
            </table>
           </td>
            <table>
             <tr>
              <th>[% 'From' | $T8 %]</th>
-             <td>[% L.date_tag('transdatefrom') %]</td>
+             <td nowrap>[% L.date_tag('transdatefrom') %]</td>
              <th>[% 'To (time)' | $T8 %]</th>
-             <td>[% L.date_tag('transdateto') %]</td>
+             <td nowrap>[% L.date_tag('transdateto') %]</td>
             </tr>
            </table>
           </td>
        <th align="right" nowrap>[% 'Include in Report' | $T8 %]</th> <td colspan="3">
         <table>
          <tr>
-          <td>
-           <input name="l_partnumber" id="l_partnumber" class="checkbox" type="checkbox" value="Y" checked>
-           <label for="l_partnumber">[% 'Part Number' | $T8 %]</label>
-          </td>
-          <td>
-           <input name="l_description" id="l_description" class="checkbox" type="checkbox" value="Y" checked>
-           <label for="l_description">[% 'Part Description' | $T8 %]</label>
-          </td>
+          <td>[%- L.checkbox_tag('l_partnumber', label=LxERP.t8('Part Number'), checked=1, value='Y') %]</td>
+          <td>[%- L.checkbox_tag('l_description', label=LxERP.t8('Part Description'), checked=1, value='Y') %]</td>
       [%- UNLESS is_service %]
-          <td>
-           <input name="l_serialnumber" id="l_serialnumber" class="checkbox" type="checkbox" value="Y">
-           <label for="l_serialnumber">[% 'Serial Number' | $T8 %]</label>
-          </td>
+          <td>[%- L.checkbox_tag('l_serialnumber', label=LxERP.t8('Serial Number'), value='Y') %]</td>
       [%- END %]
-          <td>
-           <input name="l_unit" id="l_unit" class="checkbox" type="checkbox" value="Y" checked>
-           <label for="l_unit">[% 'Unit of measure' | $T8 %]</label>
-          </td>
+          <td>[%- L.checkbox_tag('l_unit', label=LxERP.t8('Unit of measure'), value='Y', checked=1) %]</td>
          </tr>
 
          <tr>
-          <td>
-           <input name="l_listprice" id="l_listprice" class="checkbox" type="checkbox" value="Y">
-           <label for="l_listprice">[% 'List Price' | $T8 %]</label>
-          </td>
-          <td>
-           <input name="l_sellprice" id="l_sellprice" class="checkbox" type="checkbox" value="Y" checked>
-           <label for="l_sellprice">[% 'Sell Price' | $T8 %]</label>
-          </td>
-          <td>
-           <input name="l_lastcost" id="l_lastcost" class="checkbox" type="checkbox" value="Y" checked>
-           <label for="l_lastcost">[% 'Last Cost' | $T8 %]</label>
-          </td>
-          <td>
-           <input name="l_linetotal" id="l_linetotal" class="checkbox" type="checkbox" value="Y" checked>
-           <label for="l_linetotal">[% 'Line Total' | $T8 %]</label>
-          </td>
+          <td>[%- L.checkbox_tag('l_listprice', label=LxERP.t8('List Price'), value='Y') %]</td>
+          <td>[%- L.checkbox_tag('l_sellprice', label=LxERP.t8('Sell Price'), value='Y', checked=1) %]</td>
+          <td>[%- L.checkbox_tag('l_lastcost', label=LxERP.t8('Last Cost'), value='Y', checked=1) %]</td>
+          <td>[%- L.checkbox_tag('l_linetotal', label=LxERP.t8('Line Total'), value='Y', checked=1) %]</td>
          </tr>
 
          <tr>
-          <td>
-           <input name="l_priceupdate" id="l_priceupdate" class="checkbox" type="checkbox" value="Y">
-           <label for="l_priceupdate">[% 'Updated' | $T8 %]</label>
-          </td>
-          <td>
+          <td>[%- L.checkbox_tag('l_priceupdate', label=LxERP.t8('Updated'), value='Y') %]</td>
           <!-- auskommentiert fuer bug nummer 852 - ggf. fuer einen standardlagerplatz verwertet jb 18.5.09-->
-           <!--input name="l_bin" id="l_bin" class="checkbox" type="checkbox" value="Y">
-           <label for="l_bin">[% 'Bin' | $T8 %]</label -->
-           <input name="l_deliverydate" id="l_deliverydate" class="checkbox" type="checkbox" value="Y">
-           <label for="l_deliverydate">[% 'deliverydate' | $T8 %]</label>
-          </td>
+          <!-- <td>[%#- L.checkbox_tag('l_bin', label=LxERP.t8('Bin'), value='Y') %]</td> -->
+          <td>[%- L.checkbox_tag('l_deliverydate', label=LxERP.t8('Delivery Date'), value='Y') %]</td>
       [%- UNLESS is_service %]
-          <td>
-           <input name="l_rop" id="l_rop" class="checkbox" type="checkbox" value="Y">
-           <label for="l_rop">[% 'ROP' | $T8 %]</label>
-          </td>
-          <td>
-           <input name="l_weight" id="l_weight" class="checkbox" type="checkbox" value="Y">
-           <label for="l_weight">[% 'Weight' | $T8 %]</label>
-          </td>
+          <td>[%- L.checkbox_tag('l_rop', label=LxERP.t8('ROP'), value='Y') %]</td>
+          <td>[%- L.checkbox_tag('l_weight', label=LxERP.t8('Weight'), value='Y') %]</td>
       [%- END %]
          </tr>
 
          <tr>
-          <td>
-           <input name="l_image" id="l_image" class="checkbox"[%- IF conf_parts_listing_images %] checked="checked"[% END %] type="checkbox" value="Y">
-           <label for="l_image">[% 'Image' | $T8 %]</label>
-          </td>
-          <td>
-           <input name="l_drawing" id="l_drawing" class="checkbox" type="checkbox" value="Y">
-           <label for="l_drawing">[% 'Drawing' | $T8 %]</label>
-          </td>
-          <td>
-           <input name="l_microfiche" id="l_microfiche" class="checkbox" type="checkbox" value="Y">
-           <label for="l_microfiche">[% 'Microfiche' | $T8 %]</label>
-          </td>
-          <td>
-           <input name="l_partsgroup" id="l_partsgroup" class="checkbox" type="checkbox" value="Y">
-           <label for="l_partsgroup">[% 'Group' | $T8 %]</label>
+          <td>[%- L.checkbox_tag('l_image', label=LxERP.t8('Image'), value='Y', checked=(conf_parts_listing_images ? 1 : 0)) %]</td>
+          <td>[%- L.checkbox_tag('l_drawing', label=LxERP.t8('Drawing'), value='Y') %]</td>
+          <td>[%- L.checkbox_tag('l_microfiche', label=LxERP.t8('Microfiche'), value='Y') %]</td>
+          <td>[%- L.checkbox_tag('l_partsgroup', label=LxERP.t8('Group'), value='Y') %]</td>
           </td>
          </tr>
 
          <tr>
-          <td>
-           <input name="l_transdate" id="l_transdate" class="checkbox" type="checkbox" value="Y">
-           <label for="l_transdate">[% 'Transdate' | $T8 %]</label>
-          </td>
-          <td>
-           <input name="l_subtotal" id="l_subtotal" class="checkbox" type="checkbox" value="Y">
-           <label for="l_subtotal">[% 'Subtotal' | $T8 %]</label>
-          </td>
-          <td>
-           <input name="l_soldtotal" id="l_soldtotal" class="checkbox" type="checkbox" value="Y">
-           <label for="l_soldtotal">[% 'Qty in Selected Records' | $T8 %]</label>
-          </td>
-          <td>
-           <input name="l_ean" id="l_ean" class="checkbox" type="checkbox" value="Y">
-           <label for="l_ean">[% 'EAN' | $T8 %]</label>
-          </td>
+          <td>[%- L.checkbox_tag('l_transdate', label=LxERP.t8('Transdate'), value='Y') %]</td>
+          <td>[%- L.checkbox_tag('l_subtotal', label=LxERP.t8('Subtotal'), value='Y') %]</td>
+          <td>[%- L.checkbox_tag('l_soldtotal', label=LxERP.t8('Qty in Selected Records'), value='Y') %]</td>
+          <td>[%- L.checkbox_tag('l_ean', label=LxERP.t8('EAN'), value='Y') %]</td>
          </tr>
 
          <tr>
       [%- UNLESS is_service %]
-          <td>
-           <input name="l_onhand" id="l_onhand" class="checkbox" type="checkbox" value="Y">
-           <label for="l_onhand">[% 'Stocked Qty' | $T8 %]</label>
-          </td>
+          <td>[%- L.checkbox_tag('l_onhand', label=LxERP.t8('Stocked Qty'), value='Y') %]</td>
       [%- END %]
-          <td>
-           <input name="l_projectnumber" id="l_projectnumber" class="checkbox" type="checkbox" value="Y">
-           <label for="l_projectnumber">[% 'Project Number' | $T8 %]</label>
-          </td>
-          <td>
-           <input name="l_projectdescription" id="l_projectdescription" class="checkbox" type="checkbox" value="Y">
-           <label for="l_projectdescription">[% 'Project Description' | $T8 %]</label>
-          </td>
-          <td>
-           <input name="l_pricegroups" id="l_pricegroups" class="checkbox" type="checkbox" value="Y" checked>
-           <label for="l_pricegroups">[% 'Pricegroups' | $T8 %]</label>
-          </td>
+          <td>[%- L.checkbox_tag('l_projectnumber', label=LxERP.t8('Project Number'), value='Y') %]</td>
+          <td>[%- L.checkbox_tag('l_projectdescription', label=LxERP.t8('Project Description'), value='Y') %]</td>
+          <td>[%- L.checkbox_tag('l_pricegroups', label=LxERP.t8('Pricegroups'), value='Y', checked=1) %]</td>
          </tr>
 
          <tr>
-          <td>
-           <input name="l_notes" id="l_notes" class="checkbox" type="checkbox" value="Y">
-           <label for="l_notes">[% 'Notes' | $T8 %]</label>
-          </td>
+          <td>[%- L.checkbox_tag('l_notes', label=LxERP.t8('Notes'), value='Y') %]</td>
          </tr>
 
          [% CUSTOM_VARIABLES_INCLUSION_CODE %]
index 3100dad..89421a6 100644 (file)
       </td>
       <td align="right"><input name="bank_transfers[].amount" value="[% LxERP.format_amount(bank_transfer.amount, -2) %]" style="text-align: right" size="12"></td>
       <td nowrap>
-        [% L.date_tag('requested_execution_date_'_ loop.count, bank_transfer.requested_execution_date) %]
+        [% L.date_tag('bank_transfers[].requested_execution_date', bank_transfer.requested_execution_date) %]
       </td>
      </tr>
     [%- END %]