dbh => $dbh,
from => $transdate,
to => $transdate,
+ trans_id => $form->{id},
);
$datev->export;
dbh => $dbh,
from => $transdate,
to => $transdate,
+ trans_id => $form->{id},
);
$datev->export;
$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;
$self->check_paid_stornos;
$self->check_stornos_ohne_partner;
$self->check_overpayments;
+ $self->check_every_account_with_taxkey;
$self->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__
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";
$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;
$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;
}
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});
}
}
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} . '%';
}
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',
my %supported_methods = (
# ## Non-jQuery methods ##
- flash => 2, # display_flash(<TARGET>, <ARGS>)
+ flash => 2, # kivi.display_flash(<TARGET>, <ARGS>)
# ## jQuery basics ##
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:
=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.
} 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});
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>
return $self->{to};
}
+sub trans_id {
+ my $self = shift;
+
+ if (@_) {
+ $self->{trans_id} = $_[0];
+ }
+
+ return $self->{trans_id};
+}
+
sub accnofrom {
my $self = shift;
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;
LEFT JOIN chart c ON (ac.chart_id = c.id)
WHERE (ar.id IS NOT NULL)
AND $fromto
+ $trans_id_filter
$filter
UNION ALL
LEFT JOIN chart c ON (ac.chart_id = c.id)
WHERE (ap.id IS NOT NULL)
AND $fromto
+ $trans_id_filter
$filter
UNION ALL
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|;
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
return DBIx::Log4perl->connect(@_);
}
+sub get_options {
+ my $self = shift;
+ my $options = {
+ pg_enable_utf8 => $::locale->is_utf8,
+ @_
+ };
+
+ return $options;
+}
+
1;
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
}
$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();
}
before the current one is applied.
=item charset
+
=item encoding
The charset this file uses. Defaults to C<ISO-8859-15> if
}
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;
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>
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,
my %allowed_sort_columns = (
"transdate" => "dord.transdate",
+ "reqdate" => "dord.reqdate",
"id" => "dord.id",
"donumber" => "dord.donumber",
"ordnumber" => "dord.ordnumber",
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'));
# 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
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
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"},
dbh => $dbh,
from => $transdate,
to => $transdate,
+ trans_id => $form->{id},
);
$datev->export;
dbh => $dbh,
from => $transdate,
to => $transdate,
+ trans_id => $form->{id},
);
$datev->export;
dbh => $dbh,
from => $transdate,
to => $transdate,
+ trans_id => $form->{id},
);
$datev->export;
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 = {};
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 {
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;
}
}
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__
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;
} else {
${ $previous } = $data;
}
+ $::lxdebug->add_request_params($name, $$previous) if $log;
undef $previous;
undef $filename;
# 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;
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);
}
}
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;
};
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)|;
# 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.
$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');
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);
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}) {
$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);
}
sub dump {
my $self = shift;
- require Data::Dumper;
return '<pre>' . Data::Dumper::Dumper(@_) . '</pre>';
}
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>
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
$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') {
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 =
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();
$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 = (
&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}};
$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);
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;
$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});
$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});
$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();
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) | .
$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}) {
$form->{rowcount} = scalar @{ $form->{DO} };
my @columns = qw(
- ids transdate
+ ids transdate reqdate
id donumber
ordnumber customernumber
name employee salesman
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'), },
'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";
}
$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;
'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},
# 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
&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');
$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;
$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);
}
# 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
#
// "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();
// 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 ##
});
// 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
input_partnotes = input_partnumber;
input_partnotes = input_partnotes.replace(/partnumber/, "partnotes");
if (input_partnotes == input_partnumber)
- input_partnoes = "";
+ input_partnotes = "";
}
if (filter)
'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',
'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',
'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!',
'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',
ACCESS=customer_vendor_edit
module=ct.pl
action=search_contact
-db=customer
[Master Data--Reports--Parts]
ACCESS=part_service_assembly_edit
// "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();
});
// 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
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,
},
);
- $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;
q{ DELETE FROM tax.report_variables; },
);
- map({ $self->db_query("DELETE FROM $_ ;", 0); } @clear);
+ $self->db_query("DELETE FROM $_") for @clear;
return 1;
);
- 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;
}
))
SQL
- $self->db_query($query, 0);
+ $self->db_query($query);
my %skipped_acc_trans_ids;
foreach my $entry (@entries) {
AND (mtime $mtime)
SQL
- $self->db_query($query, 0);
+ $self->db_query($query);
}
}
# @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;
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;
}
'ALTER TABLE contacts ADD COLUMN cp_city text;',
);
- $self->db_query($_, 1) for @queries;
+ $self->db_query($_, may_fail => 1) for @queries;
return 1;
}
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};
}
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
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
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
use parent qw(SL::DBUpgrade2::Base);
+use SL::DBUtils;
+
sub run {
my ($self) = @_;
$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
> 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;
"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;
}
# @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 = '';
$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|;
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 {
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;
name => 'Test',
whut => 'moof',
}, {
- query => [ %{{
+ query => bag(
name => 'Test',
whut => 'moof'
- }} ],
+ ),
}, 'basic test';
test {
},
},
}, {
- 'query' => [ %{{
+ 'query' => bag(
'invoice.customer.name' => 'test',
'customer.name' => 'test',
- }} ],
+ ),
'with_objects' => bag( 'invoice.customer', 'customer', 'invoice' )
}, 'object in more than one relationship';
#####
$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',
);
use Test::More;
-use Test::Deep;
+use Test::Deep qw(cmp_deeply);
use Data::Dumper;
use_ok 'SL::Request', qw(flatten unflatten);
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 {
'q' => 4
},
}
-}, bag(
+}, [
[ 'x' => 1, ],
[ 'y.a' => 2, ],
[ 'y.b.p' => 3, ],
[ 'y.b.q' => 4 ],
-), 'Hash::Flatten 1';
+], 'Hash::Flatten 1';
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 {
},
]
},
-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,
'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,
},
]
},
-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();
[%- 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>
[%- 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">
<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>
<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 %]
<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 %]
<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 %]
<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>
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]);
}
<tr>
<td></td>
<td colspan="3">
- <input name="null" id="null_1" class="radio" type="radio" value="1" checked> <label for="null_1">[% 'Top Level' | $T8 %]</label>
- <input name="bom" id="bom" class="checkbox" type="checkbox" value="1"> <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 %]
</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 %]