/users/session_files/
/users/pid/
/users/.cache/
+/users/kivitendo-print*
/config/lx_office.conf
/config/kivitendo.conf
/doc/online/*/*.html
qw(AR_amount AR_tax AR_paid AP_amount AP_tax AP_paid IC_sale IC_cogs IC_taxpart IC_income IC_expense IC_taxservice);
}
- if ($form->{AR_include_in_dropdown}) {
- $form->{$form->{AR_include_in_dropdown}} = $form->{AR_include_in_dropdown};
- }
- if ($form->{AP_include_in_dropdown}) {
- $form->{$form->{AP_include_in_dropdown}} = $form->{AP_include_in_dropdown};
+ for (qw(AR_include_in_dropdown AP_include_in_dropdown)) {
+ $form->{$form->{$_}} = $form->{$_} if $form->{$_};
}
$form->{link} = "";
if (!$form->{id} || $form->{id} eq "") {
$query = qq|SELECT nextval('id')|;
($form->{"id"}) = selectrow_query($form, $dbh, $query);
- $query = qq|INSERT INTO chart (id, accno) VALUES (?, ?)|;
- do_query($form, $dbh, $query, $form->{"id"}, $form->{"accno"});
+ $query = qq|INSERT INTO chart (id, accno, link) VALUES (?, ?, ?)|;
+ do_query($form, $dbh, $query, $form->{"id"}, $form->{"accno"}, '');
}
@values = ();
vendornumber = ?,
articlenumber = ?,
servicenumber = ?,
+ assemblynumber = ?,
sdonumber = ?,
pdonumber = ?,
businessnumber = ?,
$form->{sqnumber}, $form->{rfqnumber},
$form->{customernumber}, $form->{vendornumber},
$form->{articlenumber}, $form->{servicenumber},
+ $form->{assemblynumber},
$form->{sdonumber}, $form->{pdonumber},
$form->{businessnumber}, $form->{weightunit},
conv_i($form->{language_id}));
(SELECT accno FROM chart WHERE id = chart_id) AS taxnumber,
(SELECT description FROM chart WHERE id = chart_id) AS account_description
FROM tax t
- ORDER BY taxkey|;
+ ORDER BY taxkey, rate|;
my $sth = $dbh->prepare($query);
$sth->execute || $form->dberror($query);
taxdescription,
round(rate * 100, 2) AS rate,
chart_id,
+ chart_categories,
(id IN (SELECT tax_id
FROM acc_trans)) AS tax_already_used
FROM tax
$form->{rate} = $form->{rate} / 100;
- my @values = ($form->{taxkey}, $form->{taxdescription}, $form->{rate}, $form->{chart_id}, $form->{chart_id} );
+ my $chart_categories = '';
+ $chart_categories .= 'A' if $form->{asset};
+ $chart_categories .= 'L' if $form->{liability};
+ $chart_categories .= 'Q' if $form->{equity};
+ $chart_categories .= 'I' if $form->{revenue};
+ $chart_categories .= 'E' if $form->{expense};
+ $chart_categories .= 'C' if $form->{costs};
+
+ my @values = ($form->{taxkey}, $form->{taxdescription}, $form->{rate}, $form->{chart_id}, $form->{chart_id}, $chart_categories);
if ($form->{id} ne "") {
$query = qq|UPDATE tax SET
taxkey = ?,
taxdescription = ?,
rate = ?,
chart_id = ?,
- taxnumber = (SELECT accno FROM chart WHERE id= ? )
+ taxnumber = (SELECT accno FROM chart WHERE id= ? ),
+ chart_categories = ?
WHERE id = ?|;
push(@values, $form->{id});
taxdescription,
rate,
chart_id,
- taxnumber
+ taxnumber,
+ chart_categories
)
- VALUES (?, ?, ?, ?, (SELECT accno FROM chart WHERE id = ?) )|;
+ VALUES (?, ?, ?, ?, (SELECT accno FROM chart WHERE id = ?), ? )|;
}
do_query($form, $dbh, $query, @values);
}
sub _log_msg {
- # my $message = join('', @_);
- # $message .= "\n" unless $message =~ m/\n$/;
- # $::lxdebug->message(0, $message);
+ my $message = join('', @_);
+ $message .= "\n" unless $message =~ m/\n$/;
+ $::lxdebug->message(LXDebug::DEBUG1(), $message);
}
sub _generate_time_period_variables {
$form->{formname} = $form->{type};
$form->{format} = 'pdf';
$form->{media} = 'printer';
- $form->{OUT} = "| " . $config->printer->printer_command;
+ $form->{OUT} = $config->printer->printer_command;
+ $form->{OUT_MODE} = '|-';
$form->prepare_for_printing;
removeProp => 2,
val => 2,
+ # Class attribute
+ addClass => 2,
+ removeClass => 2,
+ toggleClass => 2,
+
# Data storage
data => 3,
removeData => 2,
# Form Events
focus => 1,
+ # ## jqModal plugin ##
+
+ # Closing and removing the popup
+ jqmClose => 1,
+
# ## jstree plugin ## pattern: $.jstree._reference($(<TARGET>)).<FUNCTION>(<ARGS>)
# Operations on the whole tree
'jstree:select_node' => 2, # $.jstree._reference($(<TARGET>)).<FUNCTION>(<ARGS>, true)
'jstree:deselect_node' => 2,
'jstree:deselect_all' => 1,
+
+ # ## other stuff ##
+ redirect_to => 1, # window.location.href = <TARGET>
);
sub AUTOLOAD {
return $self;
}
+sub action_if {
+ my ($self, $condition, @args) = @_;
+
+ return $condition ? $self->action(@args) : $self;
+}
+
sub init__actions {
return [];
}
The first variation is obviously better suited for chaining.
-Additional functions:
+=over 4
+
+=item C<action $method, @args>
+
+Call the function with the name C<$method> on C<$self> with arguments
+C<@args>. Returns the return value of the actual function
+called. Useful for chaining (see above).
+
+=item C<action_if $condition, $method, @args>
+
+Call the function with the name C<$method> on C<$self> with arguments
+C<@args> if C<$condition> is trueish. Does nothing otherwise.
+
+Returns the return value of the actual function called if
+C<$condition> is trueish and C<$self> otherwise. Useful for chaining
+(see above).
+
+This function is equivalent to the following:
+
+ if ($condition) {
+ $obj->$method(@args);
+ }
+
+But it is easier to integrate into a method call chain, e.g.:
+
+ $js->html('#content', $html)
+ ->action_if($item->is_flagged, 'toggleClass', '#marker', 'flagged')
+ ->render($self);
+
+=back
+
+=head2 ADDITIONAL FUNCTIONS
=over 4
Display a C<$message> in the flash of type C<$type>. Multiple calls of
C<flash> on the same C<$self> will be merged by type.
-On the client side the flash of this type will be cleared before the
-message is shown.
+On the client side the flashes of all types will be cleared after each
+successful ClientJS call that did not end with C<$js-E<gt>error(...)>.
=item C<error $message>
The messages of multiple calls of C<error> on the same C<$self> will
be merged.
+=item C<redirect_to $url>
+
+Redirects the browser window to the new URL by setting the JavaScript
+property C<window.location.href>. Note that
+L<SL::Controller::Base/redirect_to> is AJAX aware and uses this
+function if the current request is an AJAX request as determined by
+L<SL::Request/is_ajax>.
+
=back
=head2 JQUERY FUNCTIONS
return "/tmp/kivitendo-tmp-" . unique_id();
}
+sub truncate {
+ my ($text, %params) = @_;
+
+ $params{at} //= 50;
+ $params{at} = 3 if 3 > $params{at};
+
+ $params{strip} //= '';
+
+ $text =~ s/[\r\n]+$//g if $params{strip} =~ m/^(?: 1 | newlines? | full )$/x;
+ $text =~ s/[\r\n]+/ /g if $params{strip} =~ m/^(?: newlines? | full )$/x;
+
+ return $text if length($text) <= $params{at};
+ return substr($text, 0, $params{at} - 3) . '...';
+}
+
sub retrieve_parts {
$main::lxdebug->enter_sub();
}
1;
+__END__
+
+=pod
+
+=encoding utf8
+
+=head1 NAME
+
+Common - Common routines used in a lot of places.
+
+=head1 SYNOPSIS
+
+ my $short_text = Common::truncate($long_text, at => 10);
+
+=head1 FUNCTIONS
+
+=over 4
+
+=item C<truncate $text, %params>
+
+Truncates C<$text> at a position and insert an ellipsis if the text is
+longer. The maximum number of characters to return is given with the
+paramter C<at> which defaults to 50.
+
+The optional parameter C<strip> can be used to remove unwanted line
+feed/carriage return characters from the text before truncation. It
+can be set to C<1> (only strip those at the end of C<$text>) or
+C<full> (replace consecutive line feed/carriage return characters in
+the middle by a single space and remove tailing line feed/carriage
+return characters).
+
+=back
+
+=head1 BUGS
+
+Nothing here yet.
+
+=head1 AUTHOR
+
+Moritz Bunkus E<lt>m.bunkus@linet-services.deE<gt>,
+Sven Schöling E<lt>s.schoeling@linet-services.deE<gt>
+
+=cut
SL::Helper::Flash::delay_flash();
}
+ return $self->render(SL::ClientJS->new->redirect_to($self->url_for(@_))) if $::request->is_ajax;
+
print $::request->{cgi}->redirect($url);
}
}
# Only certain types are supported.
- croak "Unsupported type: " . $options->{type} unless $options->{type} =~ m/^(?:html|js|json)$/;
+ croak "Unsupported type: " . $options->{type} unless $options->{type} =~ m/^(?:html|js|json|text)$/;
# The "template" argument must be a string or a reference to one.
$template = ${ $template } if ((ref($template) || '') eq 'REF') && (ref(${ $template }) eq 'SL::Presenter::EscapedText');
$::form->{header} = 1;
my $content_type = $options->{type} eq 'html' ? 'text/html'
: $options->{type} eq 'js' ? 'text/javascript'
+ : $options->{type} eq 'text' ? 'text/plain'
: 'application/json';
print $::form->create_http_response(content_type => $content_type,
=item C<type>
-The template type. Can be C<html> (the default), C<js> for JavaScript
-or C<json> for JSON content. Affects the extension that's added to the
-file name given with a non-reference C<$template> argument, the
-content type HTTP header that is output and whether or not the layout
-will be output as well (see description of C<layout> below).
+The template type. Can be C<html> (the default), C<js> for JavaScript,
+C<json> for JSON and C<text> for plain text content. Affects the
+extension that's added to the file name given with a non-reference
+C<$template> argument, the content type HTTP header that is output and
+whether or not the layout will be output as well (see description of
+C<layout> below).
=item C<process>
=item C<redirect_to %url_params>
-Redirects the browser to a new URL by outputting a HTTP redirect
-header. The URL is generated by calling L</url_for> with
-C<%url_params>.
+Redirects the browser to a new URL. The URL is generated by calling
+L</url_for> with C<%url_params>.
+
+This function implements the redirection depending on whether or not
+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.
=item C<run_before $sub, %params>
vendors => SL::DB::Manager::Vendor->get_all };
}
+sub force_allow_columns {
+ return ();
+}
+
sub init_vc_by {
my ($self) = @_;
eval "require " . $self->class;
my %unwanted = map { ( $_ => 1 ) } (qw(itime mtime), map { $_->name } @{ $self->class->meta->primary_key_columns });
+ delete $unwanted{$_} for ($self->force_allow_columns);
+
my %profile;
for my $col ($self->class->meta->columns) {
next if $unwanted{$col};
}
}
-1;
+sub clean_fields {
+ my ($self, $illegal_chars, $object, @fields) = @_;
+
+ my @cleaned_fields;
+ foreach my $field (grep { $object->can($_) } @fields) {
+ my $value = $object->$field;
+ next unless defined($value) && ($value =~ s/$illegal_chars/ /g);
+
+ $object->$field($value);
+ push @cleaned_fields, $field;
+ }
+
+ return @cleaned_fields;
+}
+
+1;
return SL::DB::Manager::CustomVariableConfig->get_all(where => [ module => 'Contacts' ]);
}
+sub force_allow_columns {
+ return qw(cp_id);
+}
+
sub check_objects {
my ($self) = @_;
$self->controller->track_progress(phase => 'building data', progress => 0);
- my $i;
- my $num_data = scalar @{ $self->controller->data };
+ my $i = 0;
+ my $num_data = scalar @{ $self->controller->data };
+ my $update_policy = $self->controller->profile->get('update_policy') || 'update_existing';
+ my %contacts_by_id = map { ( $_->cp_id => $_ ) } @{ $self->existing_objects };
+ my $methods = $self->controller->headers->{methods};
+ my %used_methods = map { ( $_ => 1 ) } @{ $methods };
+
foreach my $entry (@{ $self->controller->data }) {
$self->controller->track_progress(progress => $i/$num_data * 100) if $i % 100 == 0;
+ my $object = $entry->{object};
+ if ($object->cp_id) {
+ my $existing_contact = $contacts_by_id{ $object->cp_id };
+ if (!$existing_contact) {
+ $contacts_by_id{ $object->cp_id } = $object if $object->cp_id;
+
+ } elsif ($update_policy eq 'skip') {
+ push(@{ $entry->{errors} }, $::locale->text('Skipping due to existing entry in database'));
+ next;
+
+ } elsif ($update_policy eq 'update_existing') {
+ # Update existing customer/vendor records.
+ $entry->{object_to_save} = $existing_contact;
+
+ $object->cp_cv_id($existing_contact->cp_cv_id);
+
+ foreach (qw(cp_name cp_gender)) {
+ $object->$_($existing_contact->$_) if !$object->$_;
+ }
+
+ $existing_contact->$_( $entry->{object}->$_ ) for @{ $methods };
+
+ push @{ $entry->{information} }, $::locale->text('Updating existing entry in database');
+
+ } else {
+ $object->cp_id(undef);
+ }
+ }
+
$self->check_name($entry);
$self->check_vc($entry, 'cp_cv_id');
$self->check_gender($entry);
$self->handle_cvars($entry);
+
+ my @cleaned_fields = $self->clean_fields(qr{[\r\n]}, $object, qw(cp_title cp_givenname cp_name cp_email cp_phone1 cp_phone2 cp_fax cp_mobile1 cp_mobile2 cp_satphone cp_satfax
+ cp_privatphone cp_privatemail cp_abteilung cp_street cp_zipcode cp_city cp_position));
+
+ push @{ $entry->{information} }, $::locale->text('Illegal characters have been removed from the following fields: #1', join(', ', @cleaned_fields))
+ if @cleaned_fields;
} continue {
$i++;
}
{ name => 'cp_fax', description => $::locale->text('Fax') },
{ name => 'cp_gender', description => $::locale->text('Gender') },
{ name => 'cp_givenname', description => $::locale->text('Given Name') },
+ { name => 'cp_id', description => $::locale->text('Database ID') },
{ name => 'cp_mobile1', description => $::locale->text('Mobile1') },
{ name => 'cp_mobile2', description => $::locale->text('Mobile2') },
{ name => 'cp_name', description => $::locale->text('Name') },
$self->controller->track_progress(phase => 'building data', progress => 0);
- my $numbercolumn = $self->controller->profile->get('table') . "number";
- my %vcs_by_number = map { ( $_->$numbercolumn => 1 ) } @{ $self->existing_objects };
+ my $vc = $self->controller->profile->get('table');
+ my $update_policy = $self->controller->profile->get('update_policy') || 'update_existing';
+ my $numbercolumn = "${vc}number";
+ my %vcs_by_number = map { ( $_->$numbercolumn => $_ ) } @{ $self->existing_objects };
+ my $methods = $self->controller->headers->{methods};
my $i;
my $num_data = scalar @{ $self->controller->data };
next if @{ $entry->{errors} };
- if ($vcs_by_number{ $object->$numbercolumn }) {
- $entry->{object}->$numbercolumn('####');
+ my @cleaned_fields = $self->clean_fields(qr{[\r\n]}, $object, qw(name department_1 department_2 street zipcode city country contact phone fax homepage email cc bcc
+ taxnumber account_number bank_code bank username greeting));
+
+ push @{ $entry->{information} }, $::locale->text('Illegal characters have been removed from the following fields: #1', join(', ', @cleaned_fields))
+ if @cleaned_fields;
+
+ my $existing_vc = $vcs_by_number{ $object->$numbercolumn };
+ if (!$existing_vc) {
+ $vcs_by_number{ $object->$numbercolumn } = $object if $object->$numbercolumn;
+
+ } elsif ($update_policy eq 'skip') {
+ push(@{$entry->{errors}}, $::locale->text('Skipping due to existing entry in database'));
+
+ } elsif ($update_policy eq 'update_existing') {
+ # Update existing customer/vendor records.
+ $entry->{object_to_save} = $existing_vc;
+
+ $existing_vc->$_( $entry->{object}->$_ ) for @{ $methods };
+
+ push @{ $entry->{information} }, $::locale->text('Updating existing entry in database');
+
} else {
- $vcs_by_number{ $object->$numbercolumn } = $object;
+ $object->$numbercolumn('####');
}
} continue {
$i++;
my $object = $entry->{object};
# Check whether or not business ID is valid.
- if ($object->business_id && !$self->businesss_by->{id}->{ $object->business_id }) {
+ if ($object->business_id && !$self->businesses_by->{id}->{ $object->business_id }) {
push @{ $entry->{errors} }, $::locale->text('Error: Invalid business');
return 0;
}
eval {
my $linked_records = $self->object->linked_records(direction => 'both');
+ push @{ $linked_records }, $self->object->sepa_export_items if $self->object->can('sepa_export_items');
my $output = SL::Presenter->get->grouped_record_list(
$linked_records,
with_columns => [ qw(record_link_direction) ],
my $query =
qq|SELECT ac.acc_trans_id, ac.transdate, ac.trans_id,ar.id, ac.amount, ac.taxkey,
- ar.invnumber, ar.duedate, ar.amount as umsatz,
+ ar.invnumber, ar.duedate, ar.amount as umsatz, ar.deliverydate,
ct.name,
c.accno, c.taxkey_id as charttax, c.datevautomatik, c.id, ac.chart_link AS link,
ar.invoice
UNION ALL
SELECT ac.acc_trans_id, ac.transdate, ac.trans_id,ap.id, ac.amount, ac.taxkey,
- ap.invnumber, ap.duedate, ap.amount as umsatz,
+ ap.invnumber, ap.duedate, ap.amount as umsatz, ap.deliverydate,
ct.name,
c.accno, c.taxkey_id as charttax, c.datevautomatik, c.id, ac.chart_link AS link,
ap.invoice
UNION ALL
SELECT ac.acc_trans_id, ac.transdate, ac.trans_id,gl.id, ac.amount, ac.taxkey,
- gl.reference AS invnumber, gl.transdate AS duedate, ac.amount as umsatz,
+ gl.reference AS invnumber, gl.transdate AS duedate, ac.amount as umsatz, NULL as deliverydate,
gl.description AS name,
c.accno, c.taxkey_id as charttax, c.datevautomatik, c.id, ac.chart_link AS link,
FALSE AS invoice
push @{ $self->{DATEV} }, [ \%new_trans, $trans->[$j] ];
} elsif (($j != $notsplitindex) && !$trans->[$j]->{is_tax}) {
- my %tax_info = $taxkeys->get_full_tax_info('transdate' => $trans->[$j]->{transdate});
+ my %tax_info = $taxkeys->get_full_tax_info('transdate' => $trans->[$j]->{transdate},
+ 'deliverydate' => $trans->[$j]->{deliverydate});
my %new_trans = ();
map { $new_trans{$_} = $trans->[$notsplitindex]->{$_}; } keys %{ $trans->[$notsplitindex] };
($self->delivered ? $::locale->text('delivered') : $::locale->text('not delivered'));
}
+sub date {
+ goto &transdate;
+}
+
1;
employee_id salesman_id closed department_id language_id payment_id delivery_customer_id delivery_vendor_id shipto_id proforma
globalproject_id delivered transaction_description container_type accepted_by_customer invoice terms storno storno_id dunning_config_id
orddate quodate reqdate gldate duedate deliverydate datepaid transdate));
+ $form->{currency} = $form->{curr}; # curr is called currency in almost all forms
if (_has($self, 'transdate')) {
my $transdate_idx = ref($self) eq 'SL::DB::Order' ? ($self->quotation ? 'quodate' : 'orddate')
_copy($self->contact, $form, '', '', 0, grep { /^cp_/ } map { $_->name } SL::DB::Contact->meta->columns) if _has($self, 'cp_id');
_copy($self->shipto, $form, '', '', 0, grep { /^shipto/ } map { $_->name } SL::DB::Shipto->meta->columns) if _has($self, 'shipto_id');
_copy($self->globalproject, $form, 'globalproject', '', 0, qw(number description)) if _has($self, 'globalproject_id');
- _copy($self->employee, $form, 'employee', '', 0, map { $_->name } SL::DB::Employee->meta->columns) if _has($self, 'employee_id');
- _copy($self->salesman, $form, 'salesman', '', 0, map { $_->name } SL::DB::Employee->meta->columns) if _has($self, 'salesman_id');
+ _copy($self->employee, $form, 'employee_', '', 0, map { $_->name } SL::DB::Employee->meta->columns) if _has($self, 'employee_id');
+ _copy($self->salesman, $form, 'salesman_', '', 0, map { $_->name } SL::DB::Employee->meta->columns) if _has($self, 'salesman_id');
_copy($self->acceptance_confirmed_by, $form, 'acceptance_confirmed_by_', '', 0, map { $_->name } SL::DB::Employee->meta->columns) if _has($self, 'acceptance_confirmed_by_id');
$form->{employee} = $self->employee->name if _has($self, 'employee_id');
use utf8;
use strict;
+use SL::Util qw(camelify);
+
require Exporter;
our @ISA = qw(Exporter);
our @EXPORT_OK = qw(get_table_for_package get_package_for_table get_package_names);
die "Can't resolve '$string' as a database model, sorry. Did you perhaps forgot to load it?";
}
-sub camelify {
- my ($str) = @_;
- $str =~ s/_+(.)/uc($1)/ge;
- ucfirst $str;
-}
-
-sub snakify {
- my ($str) = @_;
- $str =~ s/(?<!^)\u(.)/'_' . lc($1)/ge;
- lcfirst $str;
-}
-
sub plurify {
my ($str) = @_;
$str . 's';
use List::Util qw(max);
use SL::DB::Default;
+use SL::PrefixedNumber;
sub oe_scoping {
SL::DB::Manager::Order->type_filter($_[0]);
vendor => { number_column => 'vendornumber', number_range_column => 'vendornumber', },
part => { number_column => 'partnumber', number_range_column => 'articlenumber', scoping => \&parts_scoping },
service => { number_column => 'partnumber', number_range_column => 'servicenumber', scoping => \&parts_scoping },
- assembly => { number_column => 'partnumber', number_range_column => 'articlenumber', scoping => \&parts_scoping },
+ assembly => { number_column => 'partnumber', number_range_column => 'assemblynumber', scoping => \&parts_scoping },
);
sub get_next_trans_number {
return $number if $self->id && $number;
- my $re = '^(.*?)(\d+)$';
- my %conditions = $scoping_conditions ? ( query => [ $scoping_conditions->($spec_type) ] ) : ();
- my @numbers = map { $_->$number_column } @{ $self->_get_manager_class->get_all(%conditions) };
- my %numbers_in_use = map { ( $_ => 1 ) } @numbers;
- @numbers = grep { $_ } map { my @matches = m/$re/; @matches ? $matches[-1] * 1 : undef } @numbers;
-
- my $defaults = SL::DB::Default->get;
- my $number_range = $defaults->$number_range_column;
- my @matches = $number_range =~ m/$re/;
- my $prefix = (2 != scalar(@matches)) ? '' : $matches[ 0];
- my $ref_number = !@matches ? '1' : $matches[-1];
- my $min_places = length($ref_number);
-
- my $new_number = $fill_holes_in_range ? $ref_number : max($ref_number, @numbers);
- my $new_number_full = undef;
-
- while (1) {
- $new_number = $new_number + 1;
- my $new_number_s = $new_number;
- $new_number_s =~ s/\.\d+//g;
- $new_number_full = $prefix . ('0' x max($min_places - length($new_number_s), 0)) . $new_number_s;
- last if !$numbers_in_use{$new_number_full};
- }
-
- $defaults->update_attributes($number_range_column => $new_number_full) if $params{update_defaults};
- $self->$number_column($new_number_full) if $params{update_record};
-
- return $new_number_full;
+ my %conditions = $scoping_conditions ? ( query => [ $scoping_conditions->($spec_type) ] ) : ();
+ my @numbers = map { $_->$number_column } @{ $self->_get_manager_class->get_all(%conditions) };
+ my %numbers_in_use = map { ( $_ => 1 ) } @numbers;
+
+ my $defaults = SL::DB::Default->get;
+ $number_range_column = 'articlenumber' if $number_range_column eq 'assemblynumber' and length($defaults->$number_range_column) < 1;
+ my $sequence = SL::PrefixedNumber->new(number => $defaults->$number_range_column);
+
+ $sequence->set_to_max(@numbers) if !$fill_holes_in_range;
+
+ my $new_number = $sequence->get_next;
+ $new_number = $sequence->get_next while $numbers_in_use{$new_number};
+
+ $defaults->update_attributes($number_range_column => $new_number) if $params{update_defaults};
+ $self->$number_column($new_number) if $params{update_record};
+
+ return $new_number;
}
sub create_trans_number {
class => 'SL::DB::Invoice',
column_map => { id => 'storno_id' },
},
+ sepa_export_items => {
+ type => 'one to many',
+ class => 'SL::DB::SepaExportItem',
+ column_map => { id => 'ar_id' },
+ manager_args => { with_objects => [ 'sepa_export' ] }
+ },
);
__PACKAGE__->meta->initialize;
croak("Unsupported source object type '" . ref($source) . "'") unless ref($source) =~ m/^ SL::DB:: (?: Order | DeliveryOrder ) $/x;
croak("Cannot create invoices for purchase records") unless $source->customer_id;
- my $terms = $source->can('payment_id') && $source->payment_id ? $source->payment_term->terms_netto : 0;
+ my $terms = $source->can('payment_id') && $source->payment_id ? $source->payment_terms->terms_netto : 0;
my %args = ( map({ ( $_ => $source->$_ ) } qw(customer_id taxincluded shippingpoint shipvia notes intnotes curr salesman_id cusordnumber ordnumber quonumber
department_id cp_id language_id payment_id delivery_customer_id delivery_vendor_id taxzone_id shipto_id
return $self->closed ? $::locale->text('closed') : $::locale->text('open');
}
+sub date {
+ goto &transdate;
+}
+
1;
__END__
mtime => { type => 'timestamp' },
rmanumber => { type => 'text' },
cnnumber => { type => 'text' },
- accounting_method => { type => 'text' },
- inventory_system => { type => 'text' },
- profit_determination => { type => 'text' },
dunning_ar_amount_fee => { type => 'integer' },
dunning_ar_amount_interest => { type => 'integer' },
dunning_ar => { type => 'integer' },
ar_paid_accno_id => { type => 'integer' },
id => { type => 'serial', not_null => 1 },
language_id => { type => 'integer' },
- payments_changeable => { type => 'integer', default => '0', not_null => 1 },
- show_bestbefore => { type => 'boolean', default => 'false' },
+ accounting_method => { type => 'text' },
+ inventory_system => { type => 'text' },
+ profit_determination => { type => 'text' },
datev_check_on_sales_invoice => { type => 'boolean', default => 'true' },
datev_check_on_purchase_invoice => { type => 'boolean', default => 'true' },
datev_check_on_ar_transaction => { type => 'boolean', default => 'true' },
datev_check_on_ap_transaction => { type => 'boolean', default => 'true' },
datev_check_on_gl_transaction => { type => 'boolean', default => 'true' },
+ payments_changeable => { type => 'integer', default => '0', not_null => 1 },
is_changeable => { type => 'integer', default => 2, not_null => 1 },
ir_changeable => { type => 'integer', default => 2, not_null => 1 },
ar_changeable => { type => 'integer', default => 2, not_null => 1 },
ap_changeable => { type => 'integer', default => 2, not_null => 1 },
gl_changeable => { type => 'integer', default => 2, not_null => 1 },
- is_show_mark_as_paid => { type => 'boolean', default => 'true' },
- ir_show_mark_as_paid => { type => 'boolean', default => 'true' },
- ar_show_mark_as_paid => { type => 'boolean', default => 'true' },
- ap_show_mark_as_paid => { type => 'boolean', default => 'true' },
+ show_bestbefore => { type => 'boolean', default => 'false' },
sales_order_show_delete => { type => 'boolean', default => 'true' },
purchase_order_show_delete => { type => 'boolean', default => 'true' },
sales_delivery_order_show_delete => { type => 'boolean', default => 'true' },
purchase_delivery_order_show_delete => { type => 'boolean', default => 'true' },
+ is_show_mark_as_paid => { type => 'boolean', default => 'true' },
+ ir_show_mark_as_paid => { type => 'boolean', default => 'true' },
+ ar_show_mark_as_paid => { type => 'boolean', default => 'true' },
+ ap_show_mark_as_paid => { type => 'boolean', default => 'true' },
+ assemblynumber => { type => 'text' },
],
primary_key_columns => [ 'id' ],
-
- allow_inline_column_values => 1,
);
1;
my ($result, $exception);
my $worker = sub {
- SL::DB::Object::Hooks::run_hooks($self, 'before_save');
$exception = $EVAL_ERROR unless eval {
+ SL::DB::Object::Hooks::run_hooks($self, 'before_save');
$result = $self->SUPER::save(@args);
+ SL::DB::Object::Hooks::run_hooks($self, 'after_save', $result);
1;
};
- SL::DB::Object::Hooks::run_hooks($self, 'after_save', $result);
return $result;
};
my ($result, $exception);
my $worker = sub {
- SL::DB::Object::Hooks::run_hooks($self, 'before_delete');
$exception = $EVAL_ERROR unless eval {
+ SL::DB::Object::Hooks::run_hooks($self, 'before_delete');
$result = $self->SUPER::delete(@args);
+ SL::DB::Object::Hooks::run_hooks($self, 'after_delete', $result);
1;
};
- SL::DB::Object::Hooks::run_hooks($self, 'after_delete', $result);
return $result;
};
foreach my $sub (@{ ( $hooks{$when} || { })->{ ref($object) } || [ ] }) {
my $result = ref($sub) eq 'CODE' ? $sub->($object, @args) : $object->call_sub($sub, @args);
- die SL::X::DBHookError->new(when => $when,
- hook => (ref($sub) eq 'CODE' ? '<anonymous sub>' : $sub),
- object => $object)
+ die SL::X::DBHookError->new(when => $when,
+ hook => (ref($sub) eq 'CODE' ? '<anonymous sub>' : $sub),
+ object => $object,
+ object_type => ref($object))
if !$result;
}
}
return $self->${ \ $number_method{$self->type} }(@_);
}
+sub date {
+ goto &transdate;
+}
+
1;
__END__
# The calculator hasn't been adjusted for purchase invoices yet.
# use SL::DB::Helper::PriceTaxCalculator;
-__PACKAGE__->meta->add_relationship(invoiceitems => { type => 'one to many',
- class => 'SL::DB::InvoiceItem',
- column_map => { id => 'trans_id' },
- manager_args => { with_objects => [ 'part' ] }
- },
- );
+__PACKAGE__->meta->add_relationship(
+ invoiceitems => {
+ type => 'one to many',
+ class => 'SL::DB::InvoiceItem',
+ column_map => { id => 'trans_id' },
+ manager_args => { with_objects => [ 'part' ] }
+ },
+ sepa_export_items => {
+ type => 'one to many',
+ class => 'SL::DB::SepaExportItem',
+ column_map => { id => 'ap_id' },
+ manager_args => { with_objects => [ 'sepa_export' ] }
+ },
+);
__PACKAGE__->meta->initialize;
return 0;
}
+sub date {
+ goto &transdate;
+}
+
1;
-# This file has been auto-generated only because it didn't exist.
-# Feel free to modify it at will; it will not be overwritten automatically.
-
package SL::DB::SepaExportItem;
use strict;
# Creates get_all, get_all_count, get_all_iterator, delete_all and update_all.
__PACKAGE__->meta->make_manager_class;
+sub compare_to {
+ my ($self, $other) = @_;
+
+ return 1 if $self->execution_date && !$other->execution_date;
+ return -1 if !$self->execution_date && $other->execution_date;
+
+ my $result = 0;
+ $result = $self->execution_date <=> $other->execution_date if $self->execution_date;
+ return $result || ($self->sepa_export_id <=> $other->sepa_export_id) || ($self->id <=> $other->id);
+}
+
1;
use List::MoreUtils qw(any);
use SL::Common;
+use SL::DBUpgrade2::Base;
use SL::DBUtils;
use SL::Iconv;
next if ($control->{ignore});
+ $control->{charset} = 'UTF-8' if $file =~ m/\.pl$/;
$control->{charset} = $control->{charset} || $control->{encoding} || Common::DEFAULT_CHARSET;
if (!$control->{"tag"}) {
my ($self, $dbh, $filename, $version_or_control, $db_charset) = @_;
- my $form = $self->{form};
- my $fh = IO::File->new($filename, "r") or $form->error("$filename : $!\n");
- my $file_charset = Common::DEFAULT_CHARSET;
-
- if (ref($version_or_control) eq "HASH") {
- $file_charset = $version_or_control->{charset};
-
- } else {
- while (<$fh>) {
- last if !/^--/;
- next if !/^--\s*\@(?:charset|encoding):\s*(.+)/;
- $file_charset = $1;
- last;
- }
- $fh->seek(0, SEEK_SET);
- }
-
- my $contents = join "", <$fh>;
- $fh->close();
+ $dbh->begin_work;
- $db_charset ||= Common::DEFAULT_CHARSET;
-
- my $iconv = SL::Iconv->new($file_charset, $db_charset);
-
- $dbh->begin_work();
-
- # setup dbup_ export vars
- my %dbup_myconfig = ();
- map({ $dbup_myconfig{$_} = $form->{$_}; } qw(dbname dbuser dbpasswd dbhost dbport dbconnect));
-
- my $dbup_locale = $::locale;
-
- my $result = eval($contents);
+ # setup dbup_ export vars & run script
+ my %dbup_myconfig = map { ($_ => $::form->{$_}) } qw(dbname dbuser dbpasswd dbhost dbport dbconnect);
+ my $result = SL::DBUpgrade2::Base::execute_script(
+ file_name => $filename,
+ tag => $version_or_control->{tag},
+ dbh => $dbh,
+ myconfig => \%dbup_myconfig,
+ );
- if (1 != $result) {
+ if (1 != ($result // 1)) {
$dbh->rollback();
- $dbh->disconnect();
}
if (!defined($result)) {
- print $form->parse_html_template("dbupgrade/error",
- { "file" => $filename,
- "error" => $@ });
+ print $::form->parse_html_template("dbupgrade/error", { file => $filename, error => $@ });
::end_of_request();
} elsif (1 != $result) {
unlink("users/nologin") if (2 == $result);
}
if (ref($version_or_control) eq "HASH") {
- $dbh->do("INSERT INTO " . $self->{schema} . "schema_info (tag, login) VALUES (" . $dbh->quote($version_or_control->{"tag"}) . ", " . $dbh->quote($form->{"login"}) . ")");
+ $dbh->do("INSERT INTO " . $self->{schema} . "schema_info (tag, login) VALUES (" . $dbh->quote($version_or_control->{tag}) . ", " . $dbh->quote($::form->{login}) . ")");
} elsif ($version_or_control) {
$dbh->do("UPDATE defaults SET version = " . $dbh->quote($version_or_control));
}
--- /dev/null
+package SL::DBUpgrade2::Base;
+
+use strict;
+
+use parent qw(Rose::Object);
+
+use Carp;
+use English qw(-no_match_vars);
+use File::Basename ();
+use File::Copy ();
+use File::Path ();
+use List::MoreUtils qw(uniq);
+
+use Rose::Object::MakeMethods::Generic (
+ scalar => [ qw(dbh myconfig) ],
+);
+
+use SL::DBUtils;
+
+sub execute_script {
+ my (%params) = @_;
+
+ my $file_name = delete $params{file_name};
+
+ if (!eval { require $file_name }) {
+ delete $INC{$file_name};
+ die $EVAL_ERROR;
+ }
+
+ my $package = delete $params{tag};
+ $package =~ s/[^a-zA-Z0-9_]+/_/g;
+ $package = "SL::DBUpgrade2::${package}";
+
+ $package->new(%params)->run;
+}
+
+sub db_error {
+ my ($self, $msg) = @_;
+
+ die $::locale->text("Database update error:") . "<br>$msg<br>" . $DBI::errstr;
+}
+
+sub db_query {
+ my ($self, $query, $may_fail) = @_;
+
+ return if $self->dbh->do($query);
+
+ $self->db_error($query) unless $may_fail;
+
+ $self->dbh->rollback;
+ $self->dbh->begin_work;
+}
+
+sub check_coa {
+ my ($self, $wanted_coa) = @_;
+
+ my ($have_coa) = selectrow_query($::form, $self->dbh, q{ SELECT count(*) FROM defaults WHERE coa = ? }, $wanted_coa);
+
+ return $have_coa;
+}
+
+sub is_coa_empty {
+ my ($self) = @_;
+
+ my $query = q{ SELECT count(*)
+ FROM ar, ap, gl, invoice, acc_trans, customer, vendor, parts
+ };
+ my ($empty) = selectrow_query($::form, $self->dbh, $query);
+
+ return !$empty;
+}
+
+sub add_print_templates {
+ my ($self, $src_dir, @files) = @_;
+
+ $::lxdebug->message(LXDebug::DEBUG1(), "add_print_templates: src_dir $src_dir files " . join(' ', @files));
+
+ foreach (@files) {
+ croak "File '${src_dir}/$_' does not exist" unless -f "${src_dir}/$_";
+ }
+
+ my %users = $::auth->read_all_users;
+ my @template_dirs = uniq map { $_ = $_->{templates}; s:/+$::; $_ } values %users;
+
+ $::lxdebug->message(LXDebug::DEBUG1(), "add_print_templates: template_dirs " . join(' ', @template_dirs));
+
+ foreach my $src_file (@files) {
+ foreach my $template_dir (@template_dirs) {
+ my $dest_file = $template_dir . '/' . $src_file;
+
+ if (-f $dest_file) {
+ $::lxdebug->message(LXDebug::DEBUG1(), "add_print_templates: dest_file exists, skipping: ${dest_file}");
+ next;
+ }
+
+ my $dest_dir = File::Basename::dirname($dest_file);
+
+ if ($dest_dir && !-d $dest_dir) {
+ File::Path::make_path($dest_dir) or die "Cannot create directory '${dest_dir}': $!";
+ }
+
+ File::Copy::copy($src_dir . '/' . $src_file, $dest_file) or die "Cannot copy '${src_dir}/${src_file}' to '${dest_file}': $!";
+
+ $::lxdebug->message(LXDebug::DEBUG1(), "add_print_templates: copied '${src_dir}/${src_file}' to '${dest_file}'");
+ }
+ }
+
+ return 1;
+}
+
+1;
+__END__
+
+=pod
+
+=encoding utf8
+
+=head1 NAME
+
+SL::DBUpgrade2::Base - Base class for Perl-based database upgrade files
+
+=head1 OVERVIEW
+
+Database scripts written in Perl must be derived from this class and
+provide a method called C<run>.
+
+The functions in this base class offer functionality for the upgrade
+scripts.
+
+=head1 PROPERTIES
+
+The following properties (which can be accessed with
+C<$self-E<gt>property_name>) are available to the database upgrade
+script:
+
+=over 4
+
+=item C<dbh>
+
+The database handle; an Instance of L<DBI>. It is connected, and a
+transaction has been started right before the script (the method
+L</run>)) was executed.
+
+=item C<myconfig>
+
+The stripped-down version of the C<%::myconfig> hash: this hash
+reference only contains the database connection parameters applying to
+the current database.
+
+=back
+
+=head1 FUNCTIONS
+
+=over 4
+
+=item C<add_print_templates $source_dir, @files>
+
+Adds (copies) new print templates to existing users. All existing
+users in the authentication database are read. The listed C<@files>
+are copied to each user's configured templates directory preserving
+sub-directory structure (non-existing sub-directories will be
+created). If a template with the same name exists it will be skipped.
+
+The source file names must all be relative to the source directory
+C<$source_dir>. This way only the desired sub-directories are created
+in the users' template directories. Example:
+
+ $self->add_print_templates(
+ 'templates/print/Standard',
+ qw(receipt.tex common.sty images/background.png)
+ );
+
+Let's assume a user's template directory is
+C<templates/big-money-inc>. The call above would trigger five actions:
+
+=over 2
+
+=item 1. Create the directory C<templates/big-money-inc> if it doesn't
+exist.
+
+=item 2. Copy C<templates/print/Standard/receipt.tex> to
+C<templates/big-money-inc/receipt.tex> if there's no such file in that
+directory.
+
+=item 3. Copy C<templates/print/Standard/common.sty> to
+C<templates/big-money-inc/common.sty> if there's no such file in that
+directory.
+
+=item 4. Create the directory C<templates/big-money-inc/images> if it
+doesn't exist.
+
+=item 5. Copy C<templates/print/Standard/images/background.png> to
+C<templates/big-money-inc/images/background.png> if there's no such
+file in that directory.
+
+=back
+
+=item C<check_coa $coa_name>
+
+Returns trueish if the database uses the chart of accounts named
+C<$coa_name>.
+
+=item C<db_error $message>
+
+Outputs an error message C<$message> to the user and aborts execution.
+
+=item C<db_query $query, $may_fail>
+
+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
+
+=item C<execute_script>
+
+Executes a named database upgrade script. This function is not
+supposed to be called from an upgrade script. Instead, the upgrade
+manager L<SL::DBUpgrade2> uses it in order to execute the actual
+database upgrade scripts.
+
+=item C<is_coa_empty>
+
+Returns trueish if no transactions have been recorded in the table
+C<acc_trans> yet.
+
+=item C<run>
+
+This method is the entry point for the actual upgrade. Each upgrade
+script must provide this method.
+
+=back
+
+=head1 BUGS
+
+Nothing here yet.
+
+=head1 AUTHOR
+
+Moritz Bunkus E<lt>m.bunkus@linet-services.deE<gt>
+
+=cut
sub order_details {
$main::lxdebug->enter_sub();
- my ($self) = @_;
-
- my $myconfig = \%main::myconfig;
- my $form = $main::form;
+ my ($self, $myconfig, $form) = @_;
# connect to database
my $dbh = $form->get_standard_dbh($myconfig);
my $ic_cvar_configs = CVar->get_configs(module => 'IC');
$form->{TEMPLATE_ARRAYS} = { };
- IC->prepare_parts_for_printing();
+ IC->prepare_parts_for_printing(myconfig => $myconfig, form => $form);
my @arrays =
qw(runningnumber number description longdescription qty unit
use SL::Menu;
use SL::MoreCommon qw(uri_encode uri_decode);
use SL::OE;
+use SL::PrefixedNumber;
use SL::Request;
use SL::Template;
use SL::User;
main menu list_accounts jquery.autocomplete
jquery.multiselect2side frame_header/header
ui-lightness/jquery-ui
- jquery-ui.custom
+ jquery-ui.custom jqModal
);
$layout->use_javascript("$_.js") for (qw(
- jquery jquery-ui jquery.cookie jqModal jquery.checkall
+ jquery jquery-ui jquery.cookie jqModal jquery.checkall jquery.download
common part_selection switchmenuframe
), "jquery/ui/i18n/jquery.ui.datepicker-$::myconfig{countrycode}");
$ext_for_format = $self->{"format"} =~ m/pdf/ ? 'pdf' : 'odt';
} elsif ($self->{"format"} =~ /(postscript|pdf)/i) {
- $ENV{"TEXINPUTS"} = ".:" . getcwd() . "/" . $myconfig->{"templates"} . ":" . $ENV{"TEXINPUTS"};
$template_type = 'LaTeX';
$ext_for_format = 'pdf';
my $where = @where ? ' WHERE ' . join(' AND ', map { "($_)" } @where) : '';
- my $query = qq|SELECT * FROM tax $where ORDER BY taxkey|;
+ my $query = qq|SELECT * FROM tax $where ORDER BY taxkey, rate|;
$self->{$key} = selectall_hashref_query($self, $dbh, $query);
my ($var) = $sth->fetchrow_array;
$sth->finish;
- if ($var =~ m/\d+$/) {
- my $new_var = (substr $var, $-[0]) * 1 + 1;
- my $len_diff = length($var) - $-[0] - length($new_var);
- $var = substr($var, 0, $-[0]) . ($len_diff > 0 ? '0' x $len_diff : '') . $new_var;
-
- } else {
- $var = $var . '1';
- }
-
+ $var = 0 if !defined($var) || ($var eq '');
+ $var = SL::PrefixedNumber->new(number => $var)->get_next;
$query = qq|UPDATE defaults SET $fld = ?|;
do_query($self, $dbh, $query, $var);
IC->retrieve_accounts(\%::myconfig, $self, map { $_ => $self->{"id_$_"} } 1 .. $self->{rowcount});
if ($self->{type} =~ /_delivery_order$/) {
- DO->order_details();
+ DO->order_details(\%::myconfig, $self);
} elsif ($self->{type} =~ /sales_order|sales_quotation|request_quotation|purchase_order/) {
OE->order_details(\%::myconfig, $self);
} else {
push(@apvalues, '%' . $form->{description} . '%');
}
- if ($form->{employee} =~ /--/) {
- ($form->{employee_id},$form->{employee_name}) = split(/--/,$form->{employee});
- #if ($form->{employee_id}) {
+ if ($form->{employee_id}) {
$glwhere .= " AND g.employee_id = ? ";
$arwhere .= " AND a.employee_id = ? ";
$apwhere .= " AND a.employee_id = ? ";
$main::lxdebug->leave_sub();
}
+sub get_tax_dropdown {
+ my $myconfig = \%main::myconfig;
+ my $form = $main::form;
+
+ my $dbh = $form->get_standard_dbh($myconfig);
+
+ my $query = qq|SELECT category FROM chart WHERE accno = ?|;
+ my ($category) = selectrow_query($form, $dbh, $query, $form->{accno});
+
+ $query = qq|SELECT * FROM tax WHERE chart_categories like '%$category%' order by taxkey, rate|;
+
+ my $sth = prepare_execute_query($form, $dbh, $query);
+
+ $form->{TAX_ACCOUNTS} = [];
+ while (my $ref = $sth->fetchrow_hashref("NAME_lc")) {
+ push(@{ $form->{TAX_ACCOUNTS} }, $ref);
+ }
+
+}
1;
my $in = IO::File->new($self->git_exe . qq! log --format='tformat:\%H|\%an|\%ae|\%ai|\%s' ${since_until} |!);
if (!$in) {
+ no warnings 'once';
$::lxdebug->message(LXDebug::WARN(), "Error spawning git: $!");
return ();
}
use strict;
+use SL::Util qw(_hashify);
+
sub now_local {
return shift->now(time_zone => $::locale->get_local_time_zone);
}
}
sub to_kivitendo {
- my $self = shift;
- my %params = (scalar(@_) == 1) && (ref($_[0]) eq 'HASH') ? %{ $_[0] } : @_;
+ my ($self, %params) = _hashify(1, @_);
return $::locale->format_date_object($self, %params);
}
# transdate madness.
my $transdate = "";
- if ($form->{type} eq "invoice") {
- if (($form->{vc} eq "vendor") || !$form->{deliverydate}) {
+ if ($form->{type} eq "invoice" or $form->{type} eq "credit_note") {
+ # use deliverydate for sales and purchase invoice, if it exists
+ # also use deliverydate for credit notes
+ if (!$form->{deliverydate}) {
+ $transdate = $form->{invdate};
+ } else {
+ $transdate = $form->{deliverydate};
+ }
+ } elsif ($form->{script} eq 'ir.pl') {
+ # when a purchase invoice is opened from the report of purchase invoices
+ # $form->{type} isn't set, but $form->{script} is, not sure why this is or
+ # whether this distinction matters in some other scenario. Otherwise one
+ # could probably take out this elsif and add a
+ # " or $form->{script} eq 'ir.pl' "
+ # to the above if-statement
+ if (!$form->{deliverydate}) {
$transdate = $form->{invdate};
} else {
$transdate = $form->{deliverydate};
# if credit_note has a deliverydate, use this instead of invdate
# useful for credit_notes of invoices from an old period with different tax
# if there is no deliverydate then invdate is used, old default (see next elsif)
+ # Falls hier der Stichtag für Steuern anders bestimmt wird,
+ # entsprechend auch bei Taxkeys.pm anpassen
$transdate = $form->{deliverydate};
} elsif (($form->{type} eq "credit_note") || ($form->{script} eq 'ir.pl')) {
$transdate = $form->{invdate};
my $self = shift;
my %params = @_;
- my $myconfig = \%main::myconfig;
- my $form = $main::form;
+ my $myconfig = $params{myconfig} || \%main::myconfig;
+ my $form = $params{form} || $main::form;
my $dbh = $params{dbh} || $form->get_standard_dbh($myconfig);
# check if we sold the item already and
# make an entry for the expense and inventory
+ my $taxzone = $form->{taxzone_id} * 1;
$query =
qq|SELECT i.id, i.qty, i.allocated, i.trans_id, i.base_qty,
- p.inventory_accno_id, p.expense_accno_id, a.transdate
- FROM invoice i, ar a, parts p
+ bg.inventory_accno_id, bg.expense_accno_id_${taxzone} AS expense_accno_id, a.transdate
+ FROM invoice i, ar a, parts p, buchungsgruppen bg
WHERE (i.parts_id = p.id)
AND (i.parts_id = ?)
AND ((i.base_qty + i.allocated) > 0)
AND (i.trans_id = a.id)
+ AND (p.buchungsgruppen_id = bg.id)
ORDER BY transdate|;
# ORDER BY transdate guarantees FIFO
# allocated >= 0
# add entry for inventory, this one is for the sold item
- $query = qq|INSERT INTO acc_trans (trans_id, chart_id, amount, transdate, taxkey, tax_id) VALUES (?, ?, ?, ?,
+ $query = qq|INSERT INTO acc_trans (trans_id, chart_id, amount, transdate, taxkey, tax_id, chart_link) VALUES (?, ?, ?, ?,
(SELECT taxkey_id
FROM taxkeys
WHERE chart_id= ?
WHERE chart_id= ?
AND startdate <= ?
ORDER BY startdate DESC LIMIT 1),
- (SELECT chart_link FROM chart WHERE id = ?))|;
+ (SELECT link FROM chart WHERE id = ?))|;
@values = ($ref->{trans_id}, $ref->{inventory_accno_id}, $linetotal, $ref->{transdate}, $ref->{inventory_accno_id}, $ref->{transdate}, $ref->{inventory_accno_id}, $ref->{transdate},
$ref->{inventory_accno_id});
do_query($form, $dbh, $query, @values);
# add expense
- $query = qq|INSERT INTO acc_trans (trans_id, chart_id, amount, transdate, taxkey, tax_id) VALUES (?, ?, ?, ?,
+ $query = qq|INSERT INTO acc_trans (trans_id, chart_id, amount, transdate, taxkey, tax_id, chart_link) VALUES (?, ?, ?, ?,
(SELECT taxkey_id
FROM taxkeys
WHERE chart_id= ?
WHERE chart_id= ?
AND startdate <= ?
ORDER BY startdate DESC LIMIT 1),
- (SELECT chart_link FROM chart WHERE id = ?))|;
+ (SELECT link FROM chart WHERE id = ?))|;
@values = ($ref->{trans_id}, $ref->{expense_accno_id}, ($linetotal * -1), $ref->{transdate}, $ref->{expense_accno_id}, $ref->{transdate}, $ref->{expense_accno_id}, $ref->{transdate},
$ref->{expense_accno_id});
do_query($form, $dbh, $query, @values);
my $transdate = "";
if ($form->{type} eq "invoice") {
- $transdate = $form->{invdate} ? $dbh->quote($form->{invdate}) : "current_date";
+ $transdate = $form->{deliverydate} ? $dbh->quote($form->{deliverydate})
+ : $form->{invdate} ? $dbh->quote($form->{invdate})
+ : "current_date";
} else {
$transdate = $form->{transdate} ? $dbh->quote($form->{transdate}) : "current_date";
}
$form->{discount} = [];
- IC->prepare_parts_for_printing();
+ IC->prepare_parts_for_printing(myconfig => $myconfig, form => $form);
my $ic_cvar_configs = CVar->get_configs(module => 'IC');
}
$project_id = conv_i($form->{"globalproject_id"});
-
+ # entsprechend auch beim Bestimmen des Steuerschlüssels in Taxkey.pm berücksichtigen
my $taxdate = $form->{deliverydate} ? $form->{deliverydate} : $form->{invdate};
foreach my $trans_id (keys %{ $form->{amount_cogs} }) {
package SL::Layout::Base;
use strict;
-use parent qw(SL::Controller::Base);
+use parent qw(Rose::Object);
use List::MoreUtils qw(uniq);
use Time::HiRes qw();
);
use SL::Menu;
+use SL::Presenter;
my %menu_cache;
$_[0]{_header_done};
}
+sub presenter {
+ SL::Presenter->get;
+}
+
1;
+
+__END__
+
+=encoding utf-8
+
+=head1 NAME
+
+SL::Layout::Base - Base class for layouts
+
+=head1 SYNOPSIS
+
+ package SL::Layout::MyLayout;
+
+ use parent qw(SL::Layout::Base);
+
+=head1 DESCRIPTION
+
+For a description about the external interface of layouts in general see
+L<SL::Layout::Dispatcher>.
+
+This is a base class for layouts in general. It provides the basic interface
+and some capabilities to extend and cascade layouts.
+
+
+=head1 IMPLEMENTING LAYOUT CALLBACKS
+
+There are eight callbacks (C<pre_content>, C<post_content>, C<start_content>,
+C<end_content>, C<stylesheets>, C<stylesheets_inline>, C<javscripts>,
+C<javascripts_inline>) which are documented in L<SL::Layout::Dispatcher>. If
+you are writing a new simple layout, you can just override some of them like
+this:
+
+ package SL::Layout::MyEvilLayout;
+
+ sub pre_content {
+ '<h1>This is MY page now</h1>'
+ }
+
+ sub post_content {
+ '<p align="right"><small><em>Brought to you by my own layout class</em></small></p>'
+ }
+
+
+To preserve the sanitizing effects of C<stylesheets> and C<javascripts> you should instead do the following:
+
+ sub stylesheets {
+ $_[0]->add_stylesheets(qw(mystyle1.css mystyle2.css);
+ $_[0]->SUPER::stylesheets;
+ }
+
+If you want to add something to a different layout, you should write a sub
+layout and add it to the other layouts.
+
+
+=head1 SUB LAYOUTS
+
+Layouts can be aggregated, so that common elements can be used in different
+layouts. Currently this is used for the L<None|SL::Layout::None> sub layout,
+which contains a lot of the stylesheets and javascripts necessary. Another
+example is the L<Top|SL::Layout::Top> layout, which is used to generate a
+common top bar for all menu types.
+
+To add a sub layout to your layout just overwrite the sub_layout method:
+
+ package SL::Layout::MyFinalLayout;
+
+ sub init_sub_layout {
+ [
+ SL::Layout::None->new,
+ SL::Layout::MyEvilLayout->new,
+ ]
+ }
+
+You can also add a sublayout at runtime:
+
+ $layout->add_sub_layout(SL::Layout::SideBar->new);
+
+The standard implementation for the callbacks will see to it that the contents
+of all sub layouts will get rendered.
+
+
+=head1 COMBINING SUB LAYOUTS AND OWN BEHAVIOUR
+
+This is still somewhat rough, and improvements are welcome.
+
+For the C<*_content> callbacks this works if you just remember to dispatch to the base method:
+
+ sub post_content {
+ return $_[0]->render_status_bar .
+ $_[0]->SUPER::post_content
+ }
+
+For the stylesheet and javascript callbacks things are hard, because of the
+backwards compatibility, and the built-in sanity checks. The best way currently
+is to just add your content and dispatch to the base method.
+
+ sub stylesheets {
+ $_[0]->add_stylesheets(qw(mystyle1.css mystyle2.css);
+ $_[0]->SUPER::stylesheets;
+ }
+
+=head1 GORY DETAILS ABOUT JAVASCRIPT AND STYLESHEET OVERLOADING
+
+The original code used to store one stylehsheet in C<< $form->{stylesheet} >> and
+allowed/expected authors of potential C<bin/mozilla/> controllers to change
+that into their own modified stylesheet.
+
+This was at some point cleaned up into a method C<use stylesheet> which took a
+string of space separated stylesheets and processed them into the response.
+
+A lot of controllers are still using this methods so the layout interface
+supports it to change as few controller code as possible, while providing the
+more intuitive C<add_stylesheets> method.
+
+At the same time the following things need to be possible:
+
+=over 4
+
+=item 1.
+
+Runtime additions.
+
+ $layout->add_stylesheets(...)
+
+Since add_stylesheets adds to C<< $self->{stylesheets} >> there must be a way to read
+from it. Currently this is the deprecated C<use_stylesheet>.
+
+=item 2.
+
+Overriding Callbacks
+
+A leaf layout should be able to override a callback to return a list.
+
+=item 3.
+
+Sanitizing
+
+C<stylesheets> needs to retain it's sanitizing behaviour.
+
+=item 4.
+
+Aggregation
+
+The standard implementation should be able to collect from sub layouts.
+
+=item 5.
+
+Preserving of Inclusion Order
+
+Since there is currently no standard way of mixing own content and including
+sub layouts, this has to be done manually. Certain things like jquery get added
+in L<SL::Layout::None> so that they get rendered first.
+
+=back
+
+The current implementation provides no good candidate for overriding in sub
+classes, which should be changed. The other points work pretty well.
+
+=head1 BUGS
+
+None yet, if you don't count the horrible stylesheet/javascript interface.
+
+=head1 AUTHOR
+
+Sven Schöling E<lt>s.schoeling@linet-services.deE<gt>
+
+=cut
+
}
1;
+
+__END__
+
+=encoding utf-8
+
+=head1 NAME
+
+SL::Layout::Dispatcher - provides layouts by name.
+
+=head1 SYNOPSIS
+
+ use SL::Layout::Dispatcher;
+ $::request->layout(SL::Layout::Dispatcher->new(style => 'login'));
+
+ # same as
+
+ use SL::Layout::Login;
+ $::request->layout(SL::Layout::Login->new);
+
+=head1 INTRODUCTION
+
+A layout in kivitendo is anything that should be included into a text/html
+response without having each controller do it manually. This includes:
+
+=over 4
+
+=item *
+
+menus
+
+=item *
+
+status bars
+
+=item
+
+div containers for error handling and ajax responses
+
+=item *
+
+javascript and css includes
+
+=item *
+
+html header and body
+
+=back
+
+It does not include:
+
+=over 4
+
+=item *
+
+http headers
+
+=item *
+
+anthing that is not a text/html response
+
+=back
+
+All of these tasks are handled by a layout object, which is stored in the
+global L<$::request|SL::Request> object. An appropriate layout object will be
+chosen during the login/session_restore process.
+
+
+=head1 INTERFACE
+
+Every layout must be instantiated from L<SL::Layout::Base> and must implement
+the following eight callbacks:
+
+=over 4
+
+=item C<pre_content>
+
+Content that must, for whatever reason, appear before the main content.
+
+=item C<start_content>
+
+An introcutory clause for the main content. Usually something like C<< <div
+class='content'> >>.
+
+=item C<end_content>
+
+The corresponding end of L</start_content> like C<< </div> >>
+
+=item C<post_content>
+
+Any extra content that should appear after the main content in the response
+source. Note that it is preferred to put extra content after the main content,
+so that it gets rendered faster.
+
+=item C<stylesheets>
+
+A list of stylesheets that should be included as a full relative web path. Will
+be rendered into the html header.
+
+=item C<stylesheets_inline>
+
+A list of stylesheet snippets that need to be included in the response. Will be
+added to the html header.
+
+=item C<javascripts>
+
+A list of javascripts that should be included as a full relative web path.
+
+Note:
+There is no guarantee where these will end up in the content. Currently they
+will be rendered into the header, but are likely to be moved into the footer in
+the future.
+
+=item C<javascripts_inline>
+
+A list of javascript snippets that need to be included in the response.
+
+Note:
+These will end up in the footer, so make sure they don't contain
+initializations to static javascript includes that may be included earlier.
+
+=back
+
+=head1 RUNTIME INTERFACE
+
+Each layout object can add stylesheets and javascripts at runtime, as long as
+its before the actual rendering has begun. This can be used to add special
+javascripts only your controller needs.
+
+=over 4
+
+=item C<add_stylesheets>
+
+Adds the list of arguments to the list of used stylesheets.
+
+These will first be searched in the theme folder for the current user, and only
+after that be searched from the common C<css/> folder.
+
+Duplicated files will be only included once.
+
+Non-existing files will be pruned from the list.
+
+=item C<use_stylesheet>
+
+Backwards compatible alias for C<add_stylesheets>. Deprecated.
+
+=item C<add_javascripts>
+
+Adds the list of arguments to the list of used javascripts.
+
+Duplicated files will be only included once.
+
+Non-existing files will be pruned from the list.
+
+=item C<use_javascript>
+
+Backwards compatible alias for C<add_javascripts>. Deprecated.
+
+=item C<add_javascripts_inline>
+
+Add a snippet of javascript.
+
+=item C<add_stylesheets_inline>
+
+Add a snippet of css.
+
+=item C<focus>
+
+If set with a selector, the layout will generate javascript to set the page
+focus to that selector on document.ready.
+
+=back
+
+=head1 BUGS
+
+None yet :)
+
+=head1 TODO
+
+non existing css or js includes should generate a log entry.
+
+=head1 AUTHOR
+
+Sven Schöling E<lt>s.schoeling@linet-services.deE<gt>
+
+=cut
$callback = URI->new($callback)->rel($callback) if $callback;
$callback = "login.pl?action=company_logo" if $callback =~ /^(\.\/)?$/;
- $self->render("menu/menunew", { output => 0 },
+ $self->presenter->render("menu/menunew",
force_ul_width => 1,
date => $self->clock_line,
menu_items => $self->acc_menu,
my $self = shift;
$self->SUPER::javascripts_inline;
my $sections = [ section_menu($self->menu) ];
- $self->render('menu/menu', { output => 0 },
+ $self->presenter->render('menu/menu',
sections => $sections,
)
}
s/y+/yy/gi;
} $::myconfig{dateformat};
- return $self->render(
+ return $self->presenter->render(
'layout/javascript_setup',
- { type => 'js', output => 0, },
+ { type => 'js' },
datefmt => $datefmt,
focus => $::request->layout->focus,
ajax_spinner => 1,
sub pre_content {
my ($self) = @_;
- $self->SUPER::render('menu/header', { output => 0 },
+ $self->presenter->render('menu/header',
now => DateTime->now_local,
is_fastcgi => scalar($::dispatcher->interface_type =~ /fastcgi/i),
is_links => scalar($ENV{HTTP_USER_AGENT} =~ /links/i));
$callback = URI->new($callback)->rel($callback) if $callback;
$callback = "login.pl?action=company_logo" if $callback =~ /^(\.\/)?$/;
- $self->SUPER::render('menu/menuv3', { output => 0 },
+ $self->presenter->render('menu/menuv3',
force_ul_width => 1,
date => $self->clock_line,
menu => $self->print_menu,
$form->{discount} = [];
$form->{TEMPLATE_ARRAYS} = { };
- IC->prepare_parts_for_printing();
+ IC->prepare_parts_for_printing(myconfig => $myconfig, form => $form);
my $ic_cvar_configs = CVar->get_configs(module => 'IC');
--- /dev/null
+package SL::PrefixedNumber;
+
+use strict;
+
+use parent qw(Rose::Object);
+
+use Carp;
+use List::Util qw(max);
+
+use Rose::Object::MakeMethods::Generic
+(
+ scalar => [ qw(number) ],
+ 'scalar --get_set_init' => [ qw(_state) ],
+);
+
+sub init__state {
+ my ($self) = @_;
+
+ croak "No 'number' set" if !defined($self->number);
+
+ my @matches = $self->number =~ m/^(.*?)(\d+)$/;
+ my @matches2 = $self->number =~ m/^(.*[^\d])$/;
+ my $prefix = @matches2 ? $matches2[0] : (2 != scalar(@matches)) ? '' : $matches[ 0],;
+ my $ref_number = !@matches ? '0' : $matches[-1];
+ my $min_places = length $ref_number;
+
+ return {
+ prefix => $prefix,
+ ref_number => $ref_number,
+ min_places => $min_places,
+ };
+}
+
+sub get_current {
+ my ($self) = @_;
+
+ return $self->format($self->_state->{ref_number});
+}
+
+sub get_next {
+ my ($self) = @_;
+
+ return $self->set_to($self->_state->{ref_number} + 1);
+}
+
+sub format {
+ my ($self, $number) = @_;
+
+ my $state = $self->_state;
+ $number =~ s/\.\d+//g;
+
+ return $state->{prefix} . ('0' x max($state->{min_places} - length($number), 0)) . $number;
+}
+
+sub set_to {
+ my ($self, $new_number) = @_;
+
+ my $state = $self->_state;
+ $state->{ref_number} = $new_number;
+
+ return $self->number($self->format($new_number));
+}
+
+sub set_to_max {
+ my ($self, @numbers) = @_;
+
+ return $self->set_to(max map { SL::PrefixedNumber->new(number => $_)->_state->{ref_number} } @numbers);
+}
+
+1;
+__END__
+
+=pod
+
+=encoding utf8
+
+=head1 NAME
+
+SL::PrefixedNumber - Increment a number prefixed with some text
+
+=head1 SYNOPSIS
+
+ my $number = SL::PrefixedNumber->new(number => 'FB000042')->get_next;
+ print $number; # FB000043
+
+=head1 FUNCTIONS
+
+=over 4
+
+=item C<format $number>
+
+Returns C<$number> formatted according to the rules in C<$self>. Does
+not modify C<$self>. E.g.
+
+ my $sequence = SL::PrefixedNumber->new('FB12345');
+ print $sequence->format(42); # FB00042
+ print $sequence->get_next; # FB12346
+
+=item C<get_current>
+
+Returns the current number in the sequence (formatted). Does not
+modify C<$self>.
+
+=item C<get_next>
+
+Returns the next number in the sequence (formatted). Modifies C<$self>
+accordingly so that calling C<get_next> multiple times will actually
+iterate over the sequence.
+
+=item C<set_to $number>
+
+Sets the current postfix to C<$number> but does not change the
+prefix. Returns the formatted new number. E.g.:
+
+ my $sequence = SL::PrefixedNumber->new(number => 'FB000042');
+ print $sequence->set_to(123); # FB000123
+ print $sequence->get_next; # FB000124
+
+=item C<set_to_max @numbers>
+
+Sets the current postfix to the maximum of all the numbers listed in
+C<@numbers>. All those numbers can be prefixed numbers. Returns the
+formatted maximum number. E.g.
+
+ my $sequence = SL::PrefixedNumber->new(number => 'FB000042');
+ print $sequence->set_to_max('FB000123', 'FB999', 'FB00001'); # FB000999
+ print $sequence->get_next; # FB001000
+
+=back
+
+=head1 BUGS
+
+Nothing here yet.
+
+=head1 AUTHOR
+
+Moritz Bunkus E<lt>m.bunkus@linet-services.deE<gt>
+
+=cut
use SL::Presenter::Order;
use SL::Presenter::Project;
use SL::Presenter::Record;
+use SL::Presenter::SepaExport;
use SL::Presenter::Text;
use SL::Presenter::Tag;
}
# Only certain types are supported.
- croak "Unsupported type: " . $options->{type} unless $options->{type} =~ m/^(?:html|js|json)$/;
+ croak "Unsupported type: " . $options->{type} unless $options->{type} =~ m/^(?:html|js|json|text)$/;
# The "template" argument must be a string or a reference to one.
$template = ${ $template } if ((ref($template) || '') eq 'REF') && (ref(${ $template }) eq 'SL::Presenter::EscapedText');
# Look for the file given by $template if $template is not a reference.
my $source;
if (!ref $template) {
- $source = "templates/webpages/${template}." . $options->{type};
+ my $ext = $options->{type} eq 'text' ? 'txt' : $options->{type};
+ $source = "templates/webpages/${template}.${ext}";
croak "Template file ${source} not found" unless -f $source;
} elsif (ref($template) eq 'SCALAR') {
=item C<type>
-The template type. Can be C<html> (the default), C<js> for JavaScript
-or C<json> for JSON content. Affects only the extension that's added
-to the file name given with a non-reference C<$template> argument.
+The template type. Can be C<html> (the default), C<js> for JavaScript,
+C<json> for JSON and C<text> for plain text content. Affects only the
+extension that's added to the file name given with a non-reference
+C<$template> argument.
=item C<process>
use Exporter qw(import);
our @EXPORT = qw(grouped_record_list empty_record_list record_list);
+use SL::Util;
+
use Carp;
use List::Util qw(first);
%params = map { exists $params{$_} ? ($_ => $params{$_}) : () } qw(edit_record_links with_columns object_id object_model);
- my %groups = _group_records($list);
+ my %groups = _sort_grouped_lists(_group_records($list));
my $output = '';
$output .= _sales_quotation_list( $self, $groups{sales_quotations}, %params) if $groups{sales_quotations};
$output .= _purchase_invoice_list( $self, $groups{purchase_invoices}, %params) if $groups{purchase_invoices};
$output .= _ar_transaction_list( $self, $groups{ar_transactions}, %params) if $groups{ar_transactions};
+ $output .= _sepa_collection_list( $self, $groups{sepa_collections}, %params) if $groups{sepa_collections};
+ $output .= _sepa_transfer_list( $self, $groups{sepa_transfers}, %params) if $groups{sepa_transfers};
+
$output = $self->render('presenter/record/grouped_record_list', %params, output => $output);
return $output;
my $meta = $column_meta{ $spec->{data} };
my $type = ref $meta;
my $relationship = $relationships{ $spec->{data} };
- my $rel_type = !$relationship ? '' : lc $relationship->class;
- $rel_type =~ s/^sl::db:://;
+ my $rel_type = !$relationship ? '' : $relationship->class;
+ $rel_type =~ s/^SL::DB:://;
+ $rel_type = SL::Util::snakify($rel_type);
if (ref($spec->{data}) eq 'CODE') {
$cell{value} = $spec->{data}->($obj);
purchase_delivery_orders => sub { (ref($_[0]) eq 'SL::DB::DeliveryOrder') && !$_[0]->is_sales },
purchase_invoices => sub { (ref($_[0]) eq 'SL::DB::PurchaseInvoice') && $_[0]->invoice },
ap_transactions => sub { (ref($_[0]) eq 'SL::DB::PurchaseInvoice') && !$_[0]->invoice },
+ sepa_collections => sub { (ref($_[0]) eq 'SL::DB::SepaExportItem') && $_[0]->ar_id },
+ sepa_transfers => sub { (ref($_[0]) eq 'SL::DB::SepaExportItem') && $_[0]->ap_id },
);
my %groups;
return %groups;
}
+sub _sort_grouped_lists {
+ my (%groups) = @_;
+
+ foreach my $group (keys %groups) {
+ next unless @{ $groups{$group} };
+ if ($groups{$group}->[0]->can('compare_to')) {
+ $groups{$group} = [ sort { $a->compare_to($b) } @{ $groups{$group} } ];
+ } else {
+ $groups{$group} = [ sort { $a->date <=> $b->date } @{ $groups{$group} } ];
+ }
+ }
+
+ return %groups;
+}
+
sub _sales_quotation_list {
my ($self, $list, %params) = @_;
);
}
+sub _sepa_export_list {
+ my ($self, $list, %params) = @_;
+
+ my ($source, $destination) = $params{type} eq 'sepa_transfer' ? qw(our vc) : qw(vc our);
+ $params{title} = $params{type} eq 'sepa_transfer' ? $::locale->text('Bank transfers via SEPA') : $::locale->text('Bank collections via SEPA');
+ $params{with_columns} = [ grep { $_ ne 'record_link_direction' } @{ $params{with_columns} || [] } ];
+
+ delete $params{edit_record_links};
+
+ return $self->record_list(
+ $list,
+ columns => [
+ [ $::locale->text('Export Number'), 'sepa_export', ],
+ [ $::locale->text('Execution date'), 'execution_date' ],
+ [ $::locale->text('Export date'), sub { $_[0]->sepa_export->itime->to_kivitendo } ],
+ [ $::locale->text('Source BIC'), "${source}_bic" ],
+ [ $::locale->text('Source IBAN'), "${source}_iban" ],
+ [ $::locale->text('Destination BIC'), "${destination}_bic" ],
+ [ $::locale->text('Destination IBAN'), "${destination}_iban" ],
+ [ $::locale->text('Amount'), 'amount' ],
+ ],
+ %params,
+ );
+}
+
+sub _sepa_transfer_list {
+ my ($self, $list, %params) = @_;
+ _sepa_export_list($self, $list, %params, type => 'sepa_transfer');
+}
+
+sub _sepa_collection_list {
+ my ($self, $list, %params) = @_;
+ _sepa_export_list($self, $list, %params, type => 'sepa_collection');
+}
+
1;
__END__
=item * AP transactions
+=item * SEPA collections
+
+=item * SEPA transfers
+
=back
Objects of unknown types are skipped.
--- /dev/null
+package SL::Presenter::SepaExport;
+
+use strict;
+
+use parent qw(Exporter);
+
+use Exporter qw(import);
+our @EXPORT = qw(sepa_export);
+
+use Carp;
+
+sub sepa_export {
+ my ($self, $sepa_export, %params) = @_;
+
+ $params{display} ||= 'inline';
+
+ croak "Unknown display type '$params{display}'" unless $params{display} =~ m/^(?:inline|table-cell)$/;
+
+ my $text = join '', (
+ $params{no_link} ? '' : '<a href="sepa.pl?action=bank_transfer_edit&vc=' . $self->escape($sepa_export->vc) . '&id=' . $self->escape($sepa_export->id) . '">',
+ $self->escape($sepa_export->id),
+ $params{no_link} ? '' : '</a>',
+ );
+ return $self->escaped_text($text);
+}
+
+1;
+
+__END__
+
+=pod
+
+=encoding utf8
+
+=head1 NAME
+
+SL::Presenter::SepaExport - Presenter module for Rose::DB objects
+for SEPA transfers and collections
+
+=head1 SYNOPSIS
+
+ # Collections from an invoice:
+ my $invoice = SL::DB::Invoice->new(id => 123)->load;
+ my $object = $invoice->sepa_export_items->[0]->sepa_export;
+ my $html = SL::Presenter->get->sepa_export($object, display => 'inline');
+
+ # Transfers from a purchase invoice:
+ my $invoice = SL::DB::PurchaseInvoice->new(id => 123)->load;
+ my $object = $invoice->sepa_export_items->[0]->sepa_export;
+ my $html = SL::Presenter->get->sepa_export($object, display => 'inline');
+
+=head1 FUNCTIONS
+
+=over 4
+
+=item C<sepa_export $object, %params>
+
+Returns a rendered version (actually an instance of
+L<SL::Presenter::EscapedText>) of the SEPA collection/transfer object
+C<$object>.
+
+C<%params> can include:
+
+=over 2
+
+=item * display
+
+Either C<inline> (the default) or C<table-cell>. At the moment both
+representations are identical and produce the objects's delivery
+order number linked to the corresponding 'edit' action.
+
+=item * no_link
+
+If falsish (the default) then the delivery order number will be linked
+to the "edit SEPA transfer" dialog from the 'cash' menu.
+
+=back
+
+=back
+
+=head1 BUGS
+
+Nothing here yet.
+
+=head1 AUTHOR
+
+Moritz Bunkus E<lt>m.bunkus@linet-services.deE<gt>
+
+=cut
sub input_tag {
my ($self, $name, $value, %attributes) = @_;
- $attributes{id} ||= $self->name_to_id($name);
+ _set_id_attribute(\%attributes, $name);
$attributes{type} ||= 'text';
return $self->html_tag('input', undef, %attributes, name => $name, value => $value);
sub select_tag {
my ($self, $name, $collection, %attributes) = @_;
- $attributes{id} ||= $self->name_to_id($name);
+ _set_id_attribute(\%attributes, $name);
my $value_key = delete($attributes{value_key}) || 'id';
my $title_key = delete($attributes{title_key}) || $value_key;
return $self->html_tag('select', $code, %attributes, name => $name);
}
+sub _set_id_attribute {
+ my ($attributes, $name) = @_;
+
+ $attributes->{id} = name_to_id(undef, $name) if !delete($attributes->{no_id}) && !$attributes->{id};
+
+ return %{ $attributes };
+}
+
1;
__END__
A module modeled a bit after Rails' ActionView helpers. Several small
functions that create HTML tags from various kinds of data sources.
+The C<id> attribute is usually calculated automatically. This can be
+overridden by either specifying an C<id> attribute or by setting
+C<no_id> to trueish.
+
=head1 FUNCTIONS
=head2 LOW-LEVEL FUNCTIONS
sub truncate {
my ($self, $text, %params) = @_;
- $params{at} ||= 50;
- $params{at} = 3 if 3 > $params{at};
- $params{at} -= 3;
-
- return $text if length($text) < $params{at};
- return substr($text, 0, $params{at}) . '...';
+ return Common::truncate($text, %params);
}
sub simple_format {
If the parameter C<skip_zero> is trueish then C<---> is returned
instead of the normal formatting if C<$value> equals 0.
-=item C<truncate $text, [%params]>
+=item C<truncate $text, %params>
Returns the C<$text> truncated after a certain number of
-characters.
-
-The number of characters to truncate at is determined by the parameter
-C<at> which defaults to 50. If the text is longer than C<$params{at}>
-then it will be truncated and postfixed with '...'. Otherwise it will
-be returned unmodified.
+characters. See L<Common/truncate> for the actual implementation and
+supported parameters.
=item C<simple_format $text>
$sth->finish;
+ # filter for opening and closing bookings
# if l_ob is selected l_cb is always ignored
- if ( $form->{l_ob} ) {
- $where .= ' AND ac.ob_transaction is true '
- } elsif ( not $form->{l_cb} ) {
- $where .= ' AND ac.cb_transaction is false ';
+ if ( $last_period ) {
+ # ob/cb-settings for "compared to" balance
+ if ( $form->{l_ob_compared} ) {
+ $where .= ' AND ac.ob_transaction is true '
+ } elsif ( not $form->{l_cb_compared} ) {
+ $where .= ' AND ac.cb_transaction is false ';
+ };
+ } else {
+ # ob/cb-settings for "as of" balance
+ if ( $form->{l_ob} ) {
+ $where .= ' AND ac.ob_transaction is true '
+ } elsif ( not $form->{l_cb} ) {
+ $where .= ' AND ac.cb_transaction is false ';
+ };
};
+
if ($fromdate) {
$fromdate = conv_dateq($fromdate);
if ($form->{method} eq 'cash') {
$col->{CELL_ROWS} = [ ];
foreach my $i (0 .. scalar(@{ $col->{data} }) - 1) {
push @{ $col->{CELL_ROWS} }, {
- 'data' => $self->html_format($col->{data}->[$i]),
+ 'data' => '' . $self->html_format($col->{data}->[$i]),
'link' => $col->{link}->[$i],
};
}
Returns the requested content type (either C<html>, C<js> or C<json>).
+=item C<layout>
+
+Set and retrieve the layout object for the current request. Must be an instance
+of L<SL::Layout::Base>. Defaults to an isntance of L<SL::Layout::None>.
+
+For more information about layouts, see L<SL::Layout::Dispatcher>.
+
=back
=head1 SPECIAL FUNCTIONS
}
my $sth = $self->{handles}->{get_tax_info};
- do_statement($form, $sth, $self->{queries}->{get_tax_info}, $params{taxkey}, $params{transdate});
+ # Lieferdatum (deliverydate) ist entscheidend für den Steuersatz
+ do_statement($form, $sth, $self->{queries}->{get_tax_info}, $params{taxkey}, $params{deliverydate} || $params{transdate});
my $ref = $sth->fetchrow_hashref() || { };
my @all_taxkeys = map { $_->{taxkey} } (selectall_hashref_query($form, $form->get_standard_dbh(), qq|SELECT DISTINCT taxkey FROM tax WHERE taxkey IS NOT NULL|));
foreach my $taxkey (@all_taxkeys) {
- my $ref = $self->get_tax_info('transdate' => $params{transdate}, 'taxkey' => $taxkey);
+ my $ref = $self->get_tax_info('transdate' => $params{transdate}, 'taxkey' => $taxkey, 'deliverydate' => $params{deliverydate});
$tax_info{taxkeys}->{$taxkey} = $ref;
$tax_info{accnos}->{$ref->{taxchart_id}} = $ref if ($ref->{taxchart_id});
use strict;
+use Carp;
use Cwd;
+use English qw(-no_match_vars);
+use File::Basename;
+use File::Temp;
+use List::MoreUtils qw(any);
use Unicode::Normalize qw();
sub new {
sub format_string {
my ($self, $variable) = @_;
- my $form = $self->{"form"};
$variable = $main::locale->quote_special_chars('Template/LaTeX', $variable);
if ($key eq 'tag-style') {
$self->set_tag_style(split(m/\s+/, $value, 2));
}
+ if ($key eq 'use-template-toolkit') {
+ $self->set_use_template_toolkit($value);
+ }
}
sub _parse_config_lines {
$used_packages{$1} = 1;
$last_usepackage_line = $i;
- } elsif ($lines->[$i] =~ m/\\begin{document}/) {
+ } elsif ($lines->[$i] =~ m/\\begin\{document\}/) {
$document_start_line = $i;
last;
my $form = $self->{"form"};
if (!open(IN, "$form->{templates}/$form->{IN}")) {
- $self->{"error"} = "$!";
+ $self->{"error"} = "$form->{templates}/$form->{IN}: $!";
return 0;
}
binmode IN, ":utf8" if $::locale->is_utf8;
$self->{"forced_pagebreaks"} = [];
- my $new_contents = $self->parse_block($contents);
+ my $new_contents;
+ if ($self->{use_template_toolkit}) {
+ if ($self->{custom_tag_style}) {
+ $contents = "[% TAGS $self->{tag_start} $self->{tag_end} %]\n" . $contents;
+ }
+
+ $::form->init_template->process(\$contents, $form, \$new_contents) || die $::form->template->error;
+ } else {
+ $new_contents = $self->parse_block($contents);
+ }
if (!defined($new_contents)) {
$main::lxdebug->leave_sub();
return 0;
my ($form, $userspath) = ($self->{"form"}, $self->{"userspath"});
# Convert the tex file to postscript
+ local $ENV{TEXINPUTS} = ".:" . $form->{cwd} . "/" . $form->{templates} . ":" . $ENV{TEXINPUTS};
if (!chdir("$userspath")) {
$self->{"error"} = "chdir : $!";
my ($form, $userspath) = ($self->{"form"}, $self->{"userspath"});
# Convert the tex file to PDF
+ local $ENV{TEXINPUTS} = ".:" . $form->{cwd} . "/" . $form->{templates} . ":" . $ENV{TEXINPUTS};
if (!chdir("$userspath")) {
$self->{"error"} = "chdir : $!";
$form->{tmpfile} =~ s/tex$/pdf/;
$self->cleanup();
+
+ return 1;
}
sub _get_latex_path {
return 1;
}
+sub parse_and_create_pdf {
+ my ($class, $template_file_name, %params) = @_;
+
+ my $keep_temp = $::lx_office_conf{debug} && $::lx_office_conf{debug}->{keep_temp_files};
+ my ($tex_fh, $tex_file_name) = File::Temp::tempfile(
+ 'kivitendo-printXXXXXX',
+ SUFFIX => '.tex',
+ DIR => $::lx_office_conf{paths}->{userspath},
+ UNLINK => $keep_temp ? 0 : 1,,
+ );
+
+ my $old_wd = getcwd();
+
+ my $local_form = Form->new('');
+ $local_form->{cwd} = $old_wd;
+ $local_form->{IN} = $template_file_name;
+ $local_form->{tmpdir} = $::lx_office_conf{paths}->{userspath};
+ $local_form->{tmpfile} = $tex_file_name;
+ $local_form->{templates} = $::myconfig{templates};
+
+ foreach (keys %params) {
+ croak "The parameter '$_' must not be used." if exists $local_form->{$_};
+ $local_form->{$_} = $params{$_};
+ }
+
+ my $error;
+ eval {
+ my $template = SL::Template::LaTeX->new($template_file_name, $local_form, \%::myconfig, $::lx_office_conf{paths}->{userspath});
+ my $result = $template->parse($tex_fh) && $template->convert_to_pdf;
+
+ die $template->{error} unless $result;
+
+ 1;
+ } or do { $error = $EVAL_ERROR; };
+
+ chdir $old_wd;
+ close $tex_fh;
+
+ if ($keep_temp) {
+ chmod(((stat $tex_file_name)[2] & 07777) | 0660, $tex_file_name);
+ } else {
+ my $tmpfile = $tex_file_name;
+ $tmpfile =~ s/\.\w+$//;
+ unlink(grep { !m/\.pdf$/ } <$tmpfile.*>);
+ }
+
+ return (error => $error) if $error;
+ return (file_name => do { $tex_file_name =~ s/tex$/pdf/; $tex_file_name });
+}
+
1;
$contents =~ s|</office:automatic-styles>|${new_styles}</office:automatic-styles>|;
$contents =~ s|[\n\r]||gm;
- my $new_contents = $self->parse_block($contents);
+ my $new_contents;
+ if ($self->{use_template_toolkit}) {
+ my $additional_params = $::form;
+
+ $::form->init_template->process(\$contents, $additional_params, \$new_contents) || die $::form->template->error;
+ } else {
+ $new_contents = $self->parse_block($contents);
+ }
if (!defined($new_contents)) {
$main::lxdebug->leave_sub();
return 0;
use Scalar::Util qw(blessed);
use SL::Presenter;
+use SL::Util qw(_hashify);
use strict;
return $string;
}
-sub _hashify {
- return (@_ && (ref($_[0]) eq 'HASH')) ? %{ $_[0] } : @_;
-}
-
sub new {
my ($class, $context, @args) = @_;
sub truncate { return _call_presenter('truncate', @_); }
sub simple_format { return _call_presenter('simple_format', @_); }
+sub _set_id_attribute {
+ my ($attributes, $name) = @_;
+ SL::Presenter::Tag::_set_id_attribute($attributes, $name);
+}
+
sub img_tag {
- my ($self, @slurp) = @_;
- my %options = _hashify(@slurp);
+ my ($self, %options) = _hashify(1, @_);
$options{alt} ||= '';
}
sub textarea_tag {
- my ($self, $name, $content, @slurp) = @_;
- my %attributes = _hashify(@slurp);
+ my ($self, $name, $content, %attributes) = _hashify(3, @_);
- $attributes{id} ||= $self->name_to_id($name);
+ _set_id_attribute(\%attributes, $name);
$attributes{rows} *= 1; # required by standard
$attributes{cols} *= 1; # required by standard
$content = $content ? _H($content) : '';
}
sub checkbox_tag {
- my ($self, $name, @slurp) = @_;
- my %attributes = _hashify(@slurp);
+ my ($self, $name, %attributes) = _hashify(2, @_);
- $attributes{id} ||= $self->name_to_id($name);
+ _set_id_attribute(\%attributes, $name);
$attributes{value} = 1 unless defined $attributes{value};
my $label = delete $attributes{label};
my $checkall = delete $attributes{checkall};
}
sub radio_button_tag {
- my $self = shift;
- my $name = shift;
- my %attributes = _hashify(@_);
+ my ($self, $name, %attributes) = _hashify(2, @_);
+ _set_id_attribute(\%attributes, $name);
$attributes{value} = 1 unless defined $attributes{value};
- $attributes{id} ||= $self->name_to_id($name . "_" . $attributes{value});
my $label = delete $attributes{label};
if ($attributes{checked}) {
}
sub hidden_tag {
- my ($self, $name, $value, @slurp) = @_;
- return $self->input_tag($name, $value, _hashify(@slurp), type => 'hidden');
+ my ($self, $name, $value, %attributes) = _hashify(3, @_);
+ return $self->input_tag($name, $value, %attributes, type => 'hidden');
}
sub div_tag {
}
sub link {
- my ($self, $href, $content, @slurp) = @_;
- my %params = _hashify(@slurp);
+ my ($self, $href, $content, %params) = _hashify(3, @_);
$href ||= '#';
}
sub submit_tag {
- my ($self, $name, $value, @slurp) = @_;
- my %attributes = _hashify(@slurp);
+ my ($self, $name, $value, %attributes) = _hashify(3, @_);
if ( $attributes{confirm} ) {
$attributes{onclick} = 'return confirm("'. _J(delete($attributes{confirm})) .'");';
}
sub button_tag {
- my ($self, $onclick, $value, @slurp) = @_;
- my %attributes = _hashify(@slurp);
+ my ($self, $onclick, $value, %attributes) = _hashify(3, @_);
- $attributes{id} ||= $self->name_to_id($attributes{name}) if $attributes{name};
+ _set_id_attribute(\%attributes, $attributes{name}) if $attributes{name};
$attributes{type} ||= 'button';
+ $onclick = 'if (!confirm("'. _J(delete($attributes{confirm})) .'")) return false; ' . $onclick if $attributes{confirm};
+
return $self->html_tag('input', undef, %attributes, value => $value, onclick => $onclick);
}
+sub ajax_submit_tag {
+ my ($self, $url, $form_selector, $text, @slurp) = @_;
+
+ $url = _J($url);
+ $form_selector = _J($form_selector);
+ my $onclick = qq|submit_ajax_form('${url}', '${form_selector}')|;
+
+ return $self->button_tag($onclick, $text, @slurp);
+}
+
sub yes_no_tag {
- my ($self, $name, $value) = splice @_, 0, 3;
- my %attributes = _hashify(@_);
+ my ($self, $name, $value, %attributes) = _hashify(3, @_);
return $self->select_tag($name, [ [ 1 => $::locale->text('Yes') ], [ 0 => $::locale->text('No') ] ], default => $value ? 1 : 0, %attributes);
}
my $date_tag_id_idx = 0;
sub date_tag {
- my ($self, $name, $value, @slurp) = @_;
+ my ($self, $name, $value, %params) = _hashify(3, @_);
- my %params = _hashify(@slurp);
- my $id = $self->name_to_id($name) . _tag_id();
+ _set_id_attribute(\%params, $name);
my @onchange = $params{onchange} ? (onChange => delete $params{onchange}) : ();
my @class = $params{no_cal} || $params{readonly} ? () : (class => 'datepicker');
return $self->input_tag(
$name, blessed($value) ? $value->to_lxoffice : $value,
- id => $id,
size => 11,
onblur => "check_right_date_format(this);",
%params,
}
sub tabbed {
- my ($self, $tabs, @slurp) = @_;
- my %params = _hashify(@slurp);
+ my ($self, $tabs, %params) = _hashify(2, @_);
my $id = $params{id} || 'tab_' . _tag_id();
$params{selected} *= 1;
}
sub tab {
- my ($self, $name, $src, @slurp) = @_;
- my %params = _hashify(@slurp);
+ my ($self, $name, $src, %params) = _hashify(3, @_);
$params{method} ||= 'process';
}
sub areainput_tag {
- my ($self, $name, $value, @slurp) = @_;
- my %attributes = _hashify(@slurp);
+ my ($self, $name, $value, %attributes) = _hashify(3, @_);
my ($rows, $cols);
my $min = delete $attributes{min_rows} || 1;
}
sub multiselect2side {
- my ($self, $id, @slurp) = @_;
- my %params = _hashify(@slurp);
+ my ($self, $id, %params) = _hashify(2, @_);
$params{labelsx} = "\"" . _J($params{labelsx} || $::locale->text('Available')) . "\"";
$params{labeldx} = "\"" . _J($params{labeldx} || $::locale->text('Selected')) . "\"";
}
sub sortable_element {
- my ($self, $selector, @slurp) = @_;
- my %params = _hashify(@slurp);
+ my ($self, $selector, %params) = _hashify(2, @_);
my %attributes = ( distance => 5,
helper => <<'JAVASCRIPT' );
}
sub online_help_tag {
- my ($self, $tag, @slurp) = @_;
- my %params = _hashify(@slurp);
+ my ($self, $tag, %params) = _hashify(2, @_);
my $cc = $::myconfig{countrycode};
my $file = "doc/online/$cc/$tag.html";
my $text = $params{text} || $::locale->text('Help');
}
sub sortable_table_header {
- my ($self, $by, @slurp) = @_;
- my %params = _hashify(@slurp);
+ my ($self, $by, %params) = _hashify(2, @_);
my $controller = $self->{CONTEXT}->stash->get('SELF');
my $sort_spec = $controller->get_sort_spec;
my %template_params = (
pages => \%paginate_params,
url_maker => sub {
- my %url_params = _hashify(@_);
+ my %url_params = _hashify(0, @_);
$url_params{ $paginate_spec->{FORM_PARAMS}->[0] } = delete $url_params{page};
$url_params{ $paginate_spec->{FORM_PARAMS}->[1] } = delete $url_params{per_page} if exists $url_params{per_page};
A module modeled a bit after Rails' ActionView helpers. Several small
functions that create HTML tags from various kinds of data sources.
+The C<id> attribute is usually calculated automatically. This can be
+overridden by either specifying an C<id> attribute or by setting
+C<no_id> to trueish.
+
=head1 FUNCTIONS
=head2 LOW-LEVEL FUNCTIONS
If C<$attributes{confirm}> is set then a JavaScript popup dialog will
be added via the C<onclick> handler asking the question given with
-C<$attributes{confirm}>. If request is only submitted if the user
+C<$attributes{confirm}>. The request is only submitted if the user
clicks the dialog's ok/yes button.
+=item C<ajax_submit_tag $url, $form_selector, $text, %attributes>
+
+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>.
+
+=item C<button_tag $onclick, $text, %attributes>
+
+Creates a HTML 'input type="button"' tag with an onclick handler
+C<$onclick> and a value of C<$text>. The button does not have a name
+nor an ID by default.
+
+If C<$attributes{confirm}> is set then a JavaScript popup dialog will
+be prepended to the C<$onclick> handler asking the question given with
+C<$attributes{confirm}>. The request is only submitted if the user
+clicks the dialog's "ok/yes" button.
+
=item C<textarea_tag $name, $value, %attributes>
Creates a HTML 'textarea' tag named C<$name> with the content
--- /dev/null
+package SL::Template::Plugin::LxLatex;
+
+use strict;
+use parent qw( Template::Plugin::Filter );
+
+my $cached_instance;
+
+sub new {
+ my $class = shift;
+
+ return $cached_instance ||= $class->SUPER::new(@_);
+}
+
+sub init {
+ my $self = shift;
+
+ $self->install_filter($self->{ _ARGS }->[0] || 'LxLatex');
+
+ return $self;
+}
+
+sub filter {
+ my ($self, $text, $args) = @_;
+ return $::locale->quote_special_chars('Template/LaTeX', $text);
+}
+
+return 'SL::Template::Plugin::LxLatex';
my $tag_start = shift;
my $tag_end = shift;
+ $self->{custom_tag_style} = 1;
$self->{tag_start} = $tag_start;
$self->{tag_end} = $tag_end;
$self->{tag_start_qm} = quotemeta $tag_start;
$self->{substitute_vars_re} = "$self->{tag_start_qm}(.+?)$self->{tag_end_qm}";
}
+sub set_use_template_toolkit {
+ my $self = shift;
+ my $value = shift;
+
+ $self->{use_template_toolkit} = $value;
+}
+
sub cleanup {
my ($self) = @_;
}
use Carp;
use List::MoreUtils qw(any none);
use SL::DBUtils;
+use SL::PrefixedNumber;
use Rose::Object::MakeMethods::Generic
(
} elsif ($type =~ /part|service|assembly/) {
$filters{trans_number} = "partnumber";
$filters{numberfield} = $type eq 'service' ? 'servicenumber' : 'articlenumber';
+ $filters{numberfield} = $type eq 'assembly' ? 'assemblynumber' : $filters{numberfield};
$filters{table} = "parts";
- $filters{where} = 'COALESCE(inventory_accno_id, 0) ' . ($type eq 'service' ? '=' : '<>') . ' 0';
}
return %filters;
($business_number) = selectfirst_array_query($form, $self->dbh, qq|SELECT customernumberinit FROM business WHERE id = ?|, $self->business_id) if $self->business_id;
my $number = $business_number;
($number) = selectfirst_array_query($form, $self->dbh, qq|SELECT $filters{numberfield} FROM defaults|) if !$number;
+ if ($filters{numberfield} eq 'assemblynumber' and length($number) < 1) {
+ $filters{numberfield} = 'articlenumber';
+ ($number) = selectfirst_array_query($form, $self->dbh, qq|SELECT $filters{numberfield} FROM defaults|) if !$number;
+ }
$number ||= '';
+ my $sequence = SL::PrefixedNumber->new(number => $number);
do {
- if ($number =~ m/\d+$/) {
- my $new_number = substr($number, $-[0]) * 1 + 1;
- my $len_diff = length($number) - $-[0] - length($new_number);
- $number = substr($number, 0, $-[0]) . ($len_diff > 0 ? '0' x $len_diff : '') . $new_number;
-
- } else {
- $number = $number . '1';
- }
+ $number = $sequence->get_next;
} while ($numbers_in_use{$number});
if ($self->save) {
--- /dev/null
+package SL::Util;
+
+use strict;
+
+use parent qw(Exporter);
+
+use Carp;
+
+our @EXPORT_OK = qw(_hashify camelify snakify);
+
+sub _hashify {
+ my $keep = shift;
+
+ croak "Invalid number of entries to keep" if 0 > $keep;
+
+ return @_[0..scalar(@_) - 1] if $keep >= scalar(@_);
+ return ($keep ? @_[0..$keep - 1] : (),
+ ((1 + $keep) == scalar(@_)) && ((ref($_[$keep]) || '') eq 'HASH') ? %{ $_[$keep] } : @_[$keep..scalar(@_) - 1]);
+}
+
+sub camelify {
+ my ($str) = @_;
+ $str =~ s/_+([[:lower:]])/uc($1)/ge;
+ ucfirst $str;
+}
+
+sub snakify {
+ my ($str) = @_;
+ $str =~ s/_([[:upper:]])/'_' . lc($1)/ge;
+ $str =~ s/(?<!^)([[:upper:]])/'_' . lc($1)/ge;
+ lc $str;
+}
+
+1;
+__END__
+
+=pod
+
+=encoding utf8
+
+=head1 NAME
+
+SL::Util - Assorted utility functions
+
+=head1 OVERVIEW
+
+Most important things first:
+
+DO NOT USE C<@EXPORT> HERE! Only C<@EXPORT_OK> is allowed!
+
+=head1 FUNCTIONS
+
+=over 4
+
+=item C<_hashify $num, @args>
+
+Hashifies the very last argument. Returns a list consisting of two
+parts:
+
+The first part are the first C<$num> elements of C<@args>.
+
+The second part depends on the remaining arguments. If exactly one
+argument remains and is a hash reference then its dereferenced
+elements will be used. Otherwise the remaining elements of C<@args>
+will be returned as-is.
+
+Useful if you want to write code that can be called from Perl code and
+Template code both. Example:
+
+ use SL::Util qw(_hashify);
+
+ sub do_stuff {
+ my ($self, %params) = _hashify(1, @_);
+ # Now do stuff, obviously!
+ }
+
+=item C<camilify $string>
+
+Returns C<$string> converted from underscore-style to
+camel-case-style, e.g. for the string C<stupid_example_dude> it will
+return C<StupidExampleDude>.
+
+L</snakify> does the reverse.
+
+=item C<snakify $string>
+
+Returns C<$string> converted from camel-case-style to
+underscore-style, e.g. for the string C<EvenWorseExample> it will
+return C<even_worse_example>.
+
+L</camilify> does the reverse.
+
+=back
+
+=head1 BUGS
+
+Nothing here yet.
+
+=head1 AUTHOR
+
+Moritz Bunkus E<lt>m.bunkus@linet-services.deE<gt>
+
+=cut
use Exception::Lite qw(declareExceptionClass);
declareExceptionClass('SL::X::FormError');
-declareExceptionClass('SL::X::DBHookError', [ '%s hook \'%s\' failed', qw(when hook object) ]);
+declareExceptionClass('SL::X::DBHookError', [ '%s hook \'%s\' for object type \'%s\' failed', qw(when hook object_type object) ]);
1;
_get_taxaccount_selection();
+ $form->{asset} = 1;
+ $form->{liability} = 1;
+ $form->{equity} = 1;
+ $form->{revenue} = 1;
+ $form->{expense} = 1;
+ $form->{costs} = 1;
+
$form->header();
my $parameters_ref = {
$form->{title} = $locale->text('Edit');
AM->get_tax(\%myconfig, \%$form);
+
_get_taxaccount_selection();
+ $form->{asset} = $form->{chart_categories} =~ 'A' ? 1 : 0;
+ $form->{liability} = $form->{chart_categories} =~ 'L' ? 1 : 0;
+ $form->{equity} = $form->{chart_categories} =~ 'Q' ? 1 : 0;
+ $form->{revenue} = $form->{chart_categories} =~ 'I' ? 1 : 0;
+ $form->{expense} = $form->{chart_categories} =~ 'E' ? 1 : 0;
+ $form->{costs} = $form->{chart_categories} =~ 'C' ? 1 : 0;
+
$form->{rate} = $form->format_amount(\%myconfig, $form->{rate}, 2);
$form->header();
- #set readonly if the there are entries in acc_trans with the tax
- my $readonly = $form->{tax_already_used} ? 'readonly' : '';
-
my $parameters_ref = {
- readonly => $readonly,
};
# Ausgabe des Templates
my $cvar_configs = CVar->get_configs('module' => 'Contacts');
my @columns = qw(
- cp_id vcname vcnumber cp_name cp_givenname cp_street cp_zipcode cp_city cp_phone1 cp_phone2
- cp_mobile1 cp_mobile2 cp_email cp_abteilung cp_position cp_birthday cp_gender
+ cp_id vcname vcnumber cp_name cp_givenname cp_street cp_zipcode cp_city cp_phone1 cp_phone2 cp_privatphone
+ cp_mobile1 cp_mobile2 cp_fax cp_email cp_privatemail cp_abteilung cp_position cp_birthday cp_gender
);
my @includeable_custom_variables = grep { $_->{includeable} } @{ $cvar_configs };
'cp_position' => { 'text' => $::locale->text('Function/position'), },
'cp_birthday' => { 'text' => $::locale->text('Birthday'), },
'cp_gender' => { 'text' => $::locale->text('Gender'), },
+ 'cp_fax' => { 'text' => $::locale->text('Fax'), },
+ 'cp_privatphone' => { 'text' => $::locale->text('Private Phone') },
+ 'cp_privatemail' => { 'text' => $::locale->text('Private E-mail') },
%column_defs_cvars,
);
$row->{vcname}->{link} = build_std_url('action=edit', 'id=' . E($ref->{vcid}), 'db=' . E($ref->{db}), 'callback', @hidden_nondefault);
$row->{vcnumber}->{link} = $row->{vcname}->{link};
- $row->{cp_email}->{link} = 'mailto:' . E($ref->{cp_email});
+
+ for (qw(cp_email cp_privatemail)) {
+ $row->{$_}->{link} = 'mailto:' . E($ref->{$_}) if $ref->{$_};
+ }
$report->add_data($row);
}
$form->{follow_up_trans_info} = $form->{donumber} .'('. $follow_up_vc .')';
- $::request->layout->use_stylesheet('presenter/record/record_list.css');
-
$form->header();
# Fix für Bug 1082 Erwartet wird: 'abteilungsNAME--abteilungsID'
# und Erweiterung für Bug 1760:
);
# add employee here, so that variable is still known and passed in url when choosing a different sort order in resulting table
- my @hidden_variables = qw(accno source reference department description notes project_id datefrom dateto employee datesort category l_subtotal);
+ my @hidden_variables = qw(accno source reference department description notes project_id datefrom dateto employee_id datesort category l_subtotal);
push @hidden_variables, map { "l_${_}" } @columns;
foreach ( @hidden_variables ) {
print URL "$_\n";
};
+ my $employee = $form->{employee_id} ? SL::DB::Employee->new(id => $form->{employee_id})->load->name : '';
+
my (@options, @date_options);
push @options, $locale->text('Account') . " : $form->{accno} $form->{account_description}" if ($form->{accno});
push @options, $locale->text('Source') . " : $form->{source}" if ($form->{source});
push @options, $locale->text('Reference') . " : $form->{reference}" if ($form->{reference});
push @options, $locale->text('Description') . " : $form->{description}" if ($form->{description});
push @options, $locale->text('Notes') . " : $form->{notes}" if ($form->{notes});
- push @options, $locale->text('Employee') . " : $form->{employee_name}" if ($form->{employee_name});
+ push @options, $locale->text('Employee') . " : $employee" if $employee;
my $datesorttext = $form->{datesort} eq 'transdate' ? $locale->text('Invoice Date') : $locale->text('Booking Date');
push @date_options, "$datesorttext" if ($form->{datesort} and ($form->{datefrom} or $form->{dateto}));
push @date_options, $locale->text('From'), $locale->date(\%myconfig, $form->{datefrom}, 1) if ($form->{datefrom});
my %taxchart_labels = ();
my @taxchart_values = ();
my %taxcharts = ();
- foreach my $item (@{ $form->{ALL_TAXCHARTS} }) {
+ foreach my $item (@{ $form->{TAX_ACCOUNTS} }) {
my $key = $item->{id} . "--" . $item->{rate};
$taxchart_init = $key if ($taxchart_init == $item->{id});
push(@taxchart_values, $key);
my $accno = qq|<td>| .
NTI($cgi->popup_menu('-name' => "accno_$i",
'-id' => "accno_$i",
- '-onChange' => "setTaxkey($i)",
+ '-onChange' => "updateTaxes($i);",
'-style' => 'width:200px',
'-values' => \@chart_values,
'-labels' => \%chart_labels,
"all" => 0,
"old_id" => \@old_project_ids },
"charts" => { "key" => "ALL_CHARTS",
- "transdate" => $::form->{transdate} },
- "taxcharts" => "ALL_TAXCHARTS");
+ "transdate" => $::form->{transdate} });
+
+ $::form->{accno} = $::form->{ALL_CHARTS}[0]->{accno};
+ GL->get_tax_dropdown();
GL->get_chart_balances('charts' => $::form->{ALL_CHARTS});
call_sub($main::form->{nextsub});
}
+sub get_tax_dropdown {
+
+ my $form = $main::form;
+ $main::lxdebug->enter_sub();
+ GL->get_tax_dropdown();
+
+ foreach my $item (@{ $form->{TAX_ACCOUNTS} }) {
+ $item->{taxdescription} = $::locale->{iconv_utf8}->convert($item->{taxdescription});
+ $item->{taxdescription} .= ' ' . $form->round_amount($item->{rate} * 100);
+ }
+
+ print $form->ajax_response_header, $form->parse_html_template("gl/update_tax_accounts");
+
+ $main::lxdebug->leave_sub();
+
+}
+
1;
}
my %header = (
- runningnumber => { text => $locale->text('No.'), nowrap => 1, width => '5%' },
- qty => { text => $locale->text('Qty'), nowrap => 1, width => '10%' },
- unit => { text => $locale->text('Unit'), nowrap => 1, width => '5%' },
- partnumber => { text => $locale->text('Part Number'), nowrap => 1, width => '20%' },
- description => { text => $locale->text('Part Description'), nowrap => 1, width => '50%' },
- lastcost => { text => $locale->text('Purchase Prices'), nowrap => 1, width => '50%' },
- total => { text => $locale->text('Sale Prices'), nowrap => 1, },
- bom => { text => $locale->text('BOM'), },
- partsgroup => { text => $locale->text('Group'), },
+ runningnumber => { text => $locale->text('No.'), nowrap => 1, width => '5%', align => 'left',},
+ qty => { text => $locale->text('Qty'), nowrap => 1, width => '10%', align => 'left',},
+ unit => { text => $locale->text('Unit'), nowrap => 1, width => '5%', align => 'left',},
+ partnumber => { text => $locale->text('Part Number'), nowrap => 1, width => '20%', align => 'left',},
+ description => { text => $locale->text('Part Description'), nowrap => 1, width => '50%', align => 'left',},
+ lastcost => { text => $locale->text('Purchase Prices'), nowrap => 1, width => '50%', align => 'right',},
+ total => { text => $locale->text('Sale Prices'), nowrap => 1, align => 'right',},
+ bom => { text => $locale->text('BOM'), align => 'center',},
+ partsgroup => { text => $locale->text('Group'), align => 'left',},
);
my @ROWS;
# parse pricegroups. and no, don't rely on check_form for this...
map { $form->{"price_$_"} = $form->parse_amount(\%myconfig, $form->{"price_$_"}) } 1 .. $form->{price_rows};
+ $form->{sellprice} = $form->parse_amount(\%myconfig, $form->{sellprice});
# same for makemodel lastcosts
# but parse_amount not necessary for assembly component lastcosts
unless ($form->{item} eq "assembly") {
map { $form->{"lastcost_$_"} = $form->parse_amount(\%myconfig, $form->{"lastcost_$_"}) } 1 .. $form->{"makemodel_rows"};
};
+ $form->{listprice} = $form->parse_amount(\%myconfig, $form->{listprice});
if ($form->{item} eq "assembly") {
my $i = $form->{assembly_rows};
map { $form->{$_} = $form->parse_amount(\%myconfig, $form->{$_}) }
qw(sellprice listprice weight);
- $form->{sellprice} += ($form->{"sellprice_$i"} * $form->{"qty_$i"});
$form->{weight} += ($form->{"weight_$i"} * $form->{"qty_$i"});
if ($form->{"not_discountable_$i"}) {
call_sub($display_form);
# saving the history
if(!exists $form->{addition}) {
- $form->{snumbers} = qq|ordnumber_| . $form->{ordnumber};
+ $form->{snumbers} = "${inv}number" . "_" . $form->{"${inv}number"};
$form->{addition} = "PRINTED";
$form->save_history;
}
# create the form variables
if ($form->{type} =~ /_delivery_order$/) {
- DO->order_details();
+ DO->order_details(\%myconfig, \%$form);
} elsif ($order) {
OE->order_details(\%myconfig, \%$form);
} else {
# saving the history
if(!exists $form->{addition}) {
- $form->{snumbers} = qq|ordnumber_| . $form->{ordnumber};
+ $form->{snumbers} = "${inv}number" . "_" . $form->{"${inv}number"};
if($form->{media} =~ /printer/) {
$form->{addition} = "PRINTED";
}
# prepare meta information for template introspection
$form->{template_meta} = {
formname => $form->{formname},
- language => SL::DB::Manager::Language->find_by_or_create(id => $form->{language_id}),
+ language => SL::DB::Manager::Language->find_by_or_create(id => $form->{language_id} || undef),
format => $form->{format},
media => $form->{media},
extension => $extension,
- printer => SL::DB::Manager::Printer->find_by_or_create(id => $form->{printer_id}),
+ printer => SL::DB::Manager::Printer->find_by_or_create(id => $form->{printer_id} || undef),
today => DateTime->today,
};
my $invdate = $form->{invdate} eq 'undefined' ? undef : $form->{invdate};
my $duedate = $form->get_duedate(\%myconfig, $invdate);
- print $form->ajax_response_header() . $duedate;
+ print $form->ajax_response_header() . ($duedate || $invdate);
$main::lxdebug->leave_sub();
}
map { $_.'_rate', $_.'_description', $_.'_taxnumber' } split / /, $form->{taxaccounts}];
$form->{jsscript} = 1;
- $::request->layout->use_stylesheet('presenter/record/record_list.css');
$form->header();
print $form->parse_html_template("ir/form_header", \%TMPL_VAR);
map { $_.'_rate', $_.'_description', $_.'_taxnumber' } split / /, $form->{taxaccounts}];
$form->{jsscript} = 1;
- $::request->layout->use_stylesheet('presenter/record/record_list.css');
$form->header();
print $form->parse_html_template("is/form_header", \%TMPL_VAR);
my ($tax, $subtotal);
$form->{taxaccounts_array} = [ split(/ /, $form->{taxaccounts}) ];
- if ($form->{customer_id}) {
+ if( $form->{customer_id} && !$form->{taxincluded_changed_by_user} ) {
my $customer = SL::DB::Customer->new(id => $form->{customer_id})->load();
$form->{taxincluded} = defined($customer->taxincluded_checked) ? $customer->taxincluded_checked : $myconfig{taxincluded_checked};
}
$form->{javascript} .= qq|<script type="text/javascript" src="js/show_history.js"></script>|;
$form->{javascript} .= qq|<script type="text/javascript" src="js/show_vc_details.js"></script>|;
- $::request->layout->use_stylesheet('presenter/record/record_list.css');
-
$form->header;
$TMPL_VAR{HIDDENS} = [ map { name => $_, value => $form->{$_} },
$TMPL_VAR{notes} = qq|<textarea name=notes rows="$rows" cols="25">| . H($form->{notes}) . qq|</textarea>|;
$TMPL_VAR{intnotes} = qq|<textarea name=intnotes rows="$introws" cols="35">| . H($form->{intnotes}) . qq|</textarea>|;
- if ($form->{customer_id}) {
+ if( $form->{customer_id} && !$form->{taxincluded_changed_by_user} ) {
my $customer = SL::DB::Customer->new(id => $form->{customer_id})->load();
$form->{taxincluded} = defined($customer->taxincluded_checked) ? $customer->taxincluded_checked : $myconfig{taxincluded_checked};
}
$::lxdebug->enter_sub;
$::auth->assert('cash');
+ # reset difference as it doesn't always arrive here empty
+ $::form->{difference} = 0;
+
RC->payment_transactions(\%::myconfig, $::form);
my $i;
--- /dev/null
+/* the overlayed element */
+.jqModal_overlay {
+ position: fixed;
+ top: 50%;
+ margin-top: -250px;
+ height: 500px;
+
+ left: 50%;
+ margin-left: -400px;
+ width: 800px;
+
+ background-color: #fff;
+ border: 1px solid #333;
+
+ /* CSS3 styling for latest browsers */
+ box-shadow: 0 0 90px 5px #000;
+ -moz-box-shadow: 0 0 90px 5px #000;
+ -webkit-box-shadow: 0 0 90px #000;
+
+ padding: 10px;
+}
+
+.jqModal_overlay .overlay_content {
+ width: 790px;
+ height: 490px;
+ overflow: auto;
+}
+
+.jqModal_overlay .close {
+ background-image: url(../../image/dialog-close.png);
+ position: absolute;
+ right: -16px;
+ top: -16px;
+ cursor: pointer;
+ height: 32px;
+ width: 32px;
+}
border-width: 1px;
background: #FFFFE0;
}
-.listrow1 {
+.listrow1, .listrow:nth-child(odd) {
background-color: #FFFFFF;
color: black;
vertical-align: top;
}
-.listrow0 {
+.listrow0, .listrow:nth-child(even) {
background-color: #FFFF99;
color: black;
vertical-align: top;
--- /dev/null
+/* the overlayed element */
+.jqModal_overlay {
+ position: fixed;
+ top: 50%;
+ margin-top: -250px;
+ height: 500px;
+
+ left: 50%;
+ margin-left: -400px;
+ width: 800px;
+
+ background-image: url("../../image/fade.png");
+ background-repeat: repeat-x;
+ background-color: #fff;
+ border: 1px solid #333;
+
+ /* CSS3 styling for latest browsers */
+ box-shadow: 0 0 90px 5px #000;
+ -moz-box-shadow: 0 0 90px 5px #000;
+ -webkit-box-shadow: 0 0 90px #000;
+
+ padding: 10px;
+}
+
+.jqModal_overlay .overlay_content {
+ width: 790px;
+ height: 490px;
+ overflow: auto;
+}
+
+.jqModal_overlay .close {
+ background-image: url(../../image/dialog-close.png);
+ position: absolute;
+ right: -16px;
+ top: -16px;
+ cursor: pointer;
+ height: 32px;
+ width: 32px;
+}
}
-.listrow1 { background-color: rgb(208,207,201); color: black; vertical-align: top; }
-.listrow0 { background-color: rgb(236,233,216); color: black; vertical-align: top; }
+.listrow1, .listrow:nth-child(odd) { background-color: rgb(208,207,201); color: black; vertical-align: top; }
+.listrow0, .listrow:nth-child(even) { background-color: rgb(236,233,216); color: black; vertical-align: top; }
.listrowempty { background-color: rgb(255,255,255); color: black; vertical-align: top; }
.redrow1 { background-color: rgb(250,167, 161); color: black; vertical-align: top; }
font-weight: bold;
}
-.jqmWindow {
- display: none;
-
- position: fixed;
- top: 17%;
- left: 40%;
-
- margin-left: -200px;
- width: 700px;
-
- background-color: lemonchiffon;
- color: #333;
- border: 1px solid black;
- padding: 4px;
-}
-
-.jqmContent {
- padding: 8px;
-}
-
-.jqmWindow h1 {
- border: 0;
- padding: 0;
- background-color: lemonchiffon;
-}
-
-.jqmOverlay {
- background-color: #000;
-}
-
/* Kontenliste Styles */
.coa_listrow1 {
+++ /dev/null
-/* the overlayed element */
-.record_list_overlay {
- position: fixed;
- top: 50%;
- margin-top: -250px;
- height: 500px;
-
- left: 50%;
- margin-left: -400px;
- width: 800px;
-
- background-color: #fff;
- border: 1px solid #333;
-
- /* CSS3 styling for latest browsers */
- box-shadow: 0 0 90px 5px #000;
- -moz-box-shadow: 0 0 90px 5px #000;
- -webkit-box-shadow: 0 0 90px #000;
-
- padding: 10px;
-}
-
-.record_list_overlay .overlay_content {
- width: 790px;
- height: 490px;
- overflow: auto;
-}
-
-.record_list_overlay .close {
- background-image: url(../../../image/dialog-close.png);
- position: absolute;
- right: -16px;
- top: -16px;
- cursor: pointer;
- height: 32px;
- width: 32px;
-}
<term><varname>charset</varname></term>
<listitem>
- <para>Empfohlen. Gibt den Zeichensatz an, in dem das Script
- geschrieben wurde, z.B. "<literal>UTF-8</literal>". Aus
- Kompatibilitätsgründen mit alten Upgrade-Scripten wird bei
- Abwesenheit des Tags der Zeichensatz
- "<literal>ISO-8859-15</literal>" angenommen.</para>
+ <para>Empfohlen. Gibt den Zeichensatz an, in dem das Script geschrieben wurde, z.B. "<literal>UTF-8</literal>". Aus
+ Kompatibilitätsgründen mit alten Upgrade-Scripten wird bei Abwesenheit des Tags für SQL-Upgradedateien der Zeichensatz
+ "<literal>ISO-8859-15</literal>" angenommen. Perl-Upgradescripte hingegen müssen immer in UTF-8 encodiert sein und sollten
+ demnach auch ein "<literal>use utf8;</literal>" enthalten.</para>
</listitem>
</varlistentry>
</variablelist>
</sect2>
+ <sect2 id="db-upgrade-files.format-perl-files" xreflabel="Format von Perl-Upgradedateien">
+ <title>Format von in Perl geschriebenen Datenbankupgradescripten</title>
+
+ <para>In Perl geschriebene Datenbankscripte werden nicht einfach so ausgeführt sondern müssen sich an gewisse Konventionen
+ halten. Dafür bekommen sie aber auch einige Komfortfunktionen bereitgestellt.</para>
+
+ <para>Ein Upgradescript stellt dabei eine vollständige Objektklasse dar, die vom Elternobjekt
+ "<literal>SL::DBUpgrade2::Base</literal>" erben und eine Funktion namens "<literal>run</literal>" zur Verfügung stellen muss. Das
+ Script wird ausgeführt, indem eine Instanz dieser Klasse erzeugt und darauf die erwähnte "<literal>run</literal>" aufgerufen
+ wird.</para>
+
+ <para>Zu beachten ist, dass sich der Paketname der Datei aus dem Wert für "<literal>@tag</literal>" ableitet. Dabei werden alle
+ Zeichen, die in Paketnamen ungültig wären (gerade Bindestriche), durch Unterstriche ersetzt. Insgesamt sieht der Paketname wie folgt
+ aus: "<literal>SL::DBUpgrade2::tag</literal>".</para>
+
+ <para>Welche Komfortfunktionen zur Verfügung stehen, erfahren Sie in der Perl-Dokumentation zum oben genannten Modul; aufzurufen mit
+ "<command>perldoc SL/DBUpgrade2/Base.pm</command>".</para>
+
+ <para>Ein Mindestgerüst eines gültigen Perl-Upgradescriptes sieht wie folgt aus:</para>
+
+ <programlisting># @tag: beispiel-upgrade-file42
+# @description: Ein schönes Beispielscript
+# @depends: release_3_0_0
+package SL::DBUpgrade2::beispiel_upgrade_file42;
+
+use strict;
+use utf8;
+
+use parent qw(SL::DBUpgrade2::Base);
+
+sub run {
+ my ($self) = @_;
+
+ # hier Aktionen ausführen
+
+ return 1;
+}
+
+1;
+</programlisting>
+ </sect2>
+
<sect2 id="db-upgrade-files.dbupgrade-tool"
xreflabel="Hilfsscript dbupgrade2_tool.pl">
<title>Hilfsscript dbupgrade2_tool.pl</title>
erlaubt und sollten stattdessen mit Unterstrichen ersetzt
werden.</p></dd><dt><span class="term">
<code class="varname">charset</code>
- </span></dt><dd><p>Empfohlen. Gibt den Zeichensatz an, in dem das Script
- geschrieben wurde, z.B. "<code class="literal">UTF-8</code>". Aus
- Kompatibilitätsgründen mit alten Upgrade-Scripten wird bei
- Abwesenheit des Tags der Zeichensatz
- "<code class="literal">ISO-8859-15</code>" angenommen.</p></dd><dt><span class="term">
+ </span></dt><dd><p>Empfohlen. Gibt den Zeichensatz an, in dem das Script geschrieben wurde, z.B. "<code class="literal">UTF-8</code>". Aus
+ Kompatibilitätsgründen mit alten Upgrade-Scripten wird bei Abwesenheit des Tags für SQL-Upgradedateien der Zeichensatz
+ "<code class="literal">ISO-8859-15</code>" angenommen. Perl-Upgradescripte hingegen müssen immer in UTF-8 encodiert sein und sollten
+ demnach auch ein "<code class="literal">use utf8;</code>" enthalten.</p></dd><dt><span class="term">
<code class="varname">description</code>
</span></dt><dd><p>Benötigt. Eine Beschreibung, was in diesem Update
passiert. Diese wird dem Benutzer beim eigentlichen
<code class="varname">ignore</code>
</span></dt><dd><p>Optional. Falls der Wert auf 1 (true) steht, wird das
Skript bei der Anmeldung ignoriert und entsprechend nicht
- ausgeführt.</p></dd></dl></div></div><div class="sect2" title="4.3.3. Hilfsscript dbupgrade2_tool.pl"><div class="titlepage"><div><div><h3 class="title"><a name="db-upgrade-files.dbupgrade-tool"></a>4.3.3. Hilfsscript dbupgrade2_tool.pl</h3></div></div></div><p>Um die Arbeit mit den Abhängigkeiten etwas zu erleichtern,
+ ausgeführt.</p></dd></dl></div></div><div class="sect2" title="4.3.3. Format von in Perl geschriebenen Datenbankupgradescripten"><div class="titlepage"><div><div><h3 class="title"><a name="db-upgrade-files.format-perl-files"></a>4.3.3. Format von in Perl geschriebenen Datenbankupgradescripten</h3></div></div></div><p>In Perl geschriebene Datenbankscripte werden nicht einfach so ausgeführt sondern müssen sich an gewisse Konventionen
+ halten. Dafür bekommen sie aber auch einige Komfortfunktionen bereitgestellt.</p><p>Ein Upgradescript stellt dabei eine vollständige Objektklasse dar, die vom Elternobjekt
+ "<code class="literal">SL::DBUpgrade2::Base</code>" erben und eine Funktion namens "<code class="literal">run</code>" zur Verfügung stellen muss. Das
+ Script wird ausgeführt, indem eine Instanz dieser Klasse erzeugt und darauf die erwähnte "<code class="literal">run</code>" aufgerufen
+ wird.</p><p>Zu beachten ist, dass sich der Paketname der Datei aus dem Wert für "<code class="literal">@tag</code>" ableitet. Dabei werden alle
+ Zeichen, die in Paketnamen ungültig wären (gerade Bindestriche), durch Unterstriche ersetzt. Insgesamt sieht der Paketname wie folgt
+ aus: "<code class="literal">SL::DBUpgrade2::tag</code>".</p><p>Welche Komfortfunktionen zur Verfügung stehen, erfahren Sie in der Perl-Dokumentation zum oben genannten Modul; aufzurufen mit
+ "<span class="command"><strong>perldoc SL/DBUpgrade2/Base.pm</strong></span>".</p><p>Ein Mindestgerüst eines gültigen Perl-Upgradescriptes sieht wie folgt aus:</p><pre class="programlisting"># @tag: beispiel-upgrade-file42
+# @description: Ein schönes Beispielscript
+# @depends: release_3_0_0
+package SL::DBUpgrade2::beispiel_upgrade_file42;
+
+use strict;
+use utf8;
+
+use parent qw(SL::DBUpgrade2::Base);
+
+sub run {
+ my ($self) = @_;
+
+ # hier Aktionen ausführen
+
+ return 1;
+}
+
+1;
+</pre></div><div class="sect2" title="4.3.4. Hilfsscript dbupgrade2_tool.pl"><div class="titlepage"><div><div><h3 class="title"><a name="db-upgrade-files.dbupgrade-tool"></a>4.3.4. Hilfsscript dbupgrade2_tool.pl</h3></div></div></div><p>Um die Arbeit mit den Abhängigkeiten etwas zu erleichtern,
existiert ein Hilfsscript namens
"<code class="filename">scripts/dbupgrade2_tool.pl</code>". Es muss aus dem
kivitendo-ERP-Basisverzeichnis heraus aufgerufen werden. Dieses Tool
<title>kivitendo 3.0.0: Installation, Konfiguration, Entwicklung</title><link rel="stylesheet" type="text/css" href="style.css"><meta name="generator" content="DocBook XSL Stylesheets V1.76.1-RC2"><link rel="home" href="index.html" title="kivitendo 3.0.0: Installation, Konfiguration, Entwicklung"><link rel="next" href="ch01.html" title="Kapitel 1. Aktuelle Hinweise"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">kivitendo 3.0.0: Installation, Konfiguration, Entwicklung</th></tr><tr><td width="20%" align="left"> </td><th width="60%" align="center"> </th><td width="20%" align="right"> <a accesskey="n" href="ch01.html">Weiter</a></td></tr></table><hr></div><div lang="de" class="book" title="kivitendo 3.0.0: Installation, Konfiguration, Entwicklung"><div class="titlepage"><div><div><h1 class="title"><a name="kivitendo-documentation"></a>kivitendo 3.0.0: Installation, Konfiguration, Entwicklung</h1></div></div><hr></div><div class="toc"><p><b>Inhaltsverzeichnis</b></p><dl><dt><span class="chapter"><a href="ch01.html">1. Aktuelle Hinweise</a></span></dt><dt><span class="chapter"><a href="ch02.html">2. Installation und Grundkonfiguration</a></span></dt><dd><dl><dt><span class="sect1"><a href="ch02.html#Installation-%C3%9Cbersicht">2.1. Übersicht</a></span></dt><dt><span class="sect1"><a href="ch02s02.html">2.2. Benötigte Software und Pakete</a></span></dt><dd><dl><dt><span class="sect2"><a href="ch02s02.html#Betriebssystem">2.2.1. Betriebssystem</a></span></dt><dt><span class="sect2"><a href="ch02s02.html#Pakete">2.2.2. Benötigte Perl-Pakete installieren</a></span></dt></dl></dd><dt><span class="sect1"><a href="ch02s03.html">2.3. Manuelle Installation des Programmpaketes</a></span></dt><dt><span class="sect1"><a href="ch02s04.html">2.4. kivitendo-Konfigurationsdatei</a></span></dt><dd><dl><dt><span class="sect2"><a href="ch02s04.html#config.config-file.introduction">2.4.1. Einführung</a></span></dt><dt><span class="sect2"><a href="ch02s04.html#config.config-file.sections-parameters">2.4.2. Abschnitte und Parameter</a></span></dt><dt><span class="sect2"><a href="ch02s04.html#config.config-file.prior-versions">2.4.3. Versionen vor 2.6.3</a></span></dt></dl></dd><dt><span class="sect1"><a href="ch02s05.html">2.5. Anpassung der PostgreSQL-Konfiguration</a></span></dt><dd><dl><dt><span class="sect2"><a href="ch02s05.html#Zeichens%C3%A4tze-die-Verwendung-von-UTF-8">2.5.1. Zeichensätze/die Verwendung von UTF-8</a></span></dt><dt><span class="sect2"><a href="ch02s05.html#%C3%84nderungen-an-Konfigurationsdateien">2.5.2. Änderungen an Konfigurationsdateien</a></span></dt><dt><span class="sect2"><a href="ch02s05.html#Erweiterung-f%C3%BCr-servergespeicherte-Prozeduren">2.5.3. Erweiterung für servergespeicherte Prozeduren</a></span></dt><dt><span class="sect2"><a href="ch02s05.html#Datenbankbenutzer-anlegen">2.5.4. Datenbankbenutzer anlegen</a></span></dt></dl></dd><dt><span class="sect1"><a href="ch02s06.html">2.6. Webserver-Konfiguration</a></span></dt><dd><dl><dt><span class="sect2"><a href="ch02s06.html#d0e678">2.6.1. Grundkonfiguration mittels CGI</a></span></dt><dt><span class="sect2"><a href="ch02s06.html#Apache-Konfiguration.FCGI">2.6.2. Konfiguration für FastCGI/FCGI</a></span></dt></dl></dd><dt><span class="sect1"><a href="ch02s07.html">2.7. Der Task-Server</a></span></dt><dd><dl><dt><span class="sect2"><a href="ch02s07.html#Konfiguration-des-Task-Servers">2.7.1. Verfügbare und notwendige Konfigurationsoptionen</a></span></dt><dt><span class="sect2"><a href="ch02s07.html#Einbinden-in-den-Boot-Prozess">2.7.2. Automatisches Starten des Task-Servers beim Booten</a></span></dt><dt><span class="sect2"><a href="ch02s07.html#Prozesskontrolle">2.7.3. Wie der Task-Server gestartet und beendet wird</a></span></dt><dt><span class="sect2"><a href="ch02s07.html#Prozesskontrolle2">2.7.4. Task-Server mit mehreren Mandanten</a></span></dt></dl></dd><dt><span class="sect1"><a href="ch02s08.html">2.8. Benutzerauthentifizierung und Administratorpasswort</a></span></dt><dd><dl><dt><span class="sect2"><a href="ch02s08.html#Grundlagen-zur-Benutzerauthentifizierung">2.8.1. Grundlagen zur Benutzerauthentifizierung</a></span></dt><dt><span class="sect2"><a href="ch02s08.html#Administratorpasswort">2.8.2. Administratorpasswort</a></span></dt><dt><span class="sect2"><a href="ch02s08.html#Authentifizierungsdatenbank">2.8.3. Authentifizierungsdatenbank</a></span></dt><dt><span class="sect2"><a href="ch02s08.html#Passwort%C3%BCberpr%C3%BCfung">2.8.4. Passwortüberprüfung</a></span></dt><dt><span class="sect2"><a href="ch02s08.html#Name-des-Session-Cookies">2.8.5. Name des Session-Cookies</a></span></dt><dt><span class="sect2"><a href="ch02s08.html#Anlegen-der-Authentifizierungsdatenbank">2.8.6. Anlegen der Authentifizierungsdatenbank</a></span></dt></dl></dd><dt><span class="sect1"><a href="ch02s09.html">2.9. Benutzer- und Gruppenverwaltung</a></span></dt><dd><dl><dt><span class="sect2"><a href="ch02s09.html#Zusammenh%C3%A4nge">2.9.1. Zusammenhänge</a></span></dt><dt><span class="sect2"><a href="ch02s09.html#Datenbanken-anlegen">2.9.2. Datenbanken anlegen</a></span></dt><dt><span class="sect2"><a href="ch02s09.html#Gruppen-anlegen">2.9.3. Gruppen anlegen</a></span></dt><dt><span class="sect2"><a href="ch02s09.html#Benutzer-anlegen">2.9.4. Benutzer anlegen</a></span></dt><dt><span class="sect2"><a href="ch02s09.html#Gruppenmitgliedschaften-verwalten">2.9.5. Gruppenmitgliedschaften verwalten</a></span></dt><dt><span class="sect2"><a href="ch02s09.html#Migration-alter-Installationen">2.9.6. Migration alter Installationen</a></span></dt></dl></dd><dt><span class="sect1"><a href="ch02s10.html">2.10. E-Mail-Versand aus kivitendo heraus</a></span></dt><dd><dl><dt><span class="sect2"><a href="ch02s10.html#config.sending-email.sendmail">2.10.1. Versand über lokalen E-Mail-Server</a></span></dt><dt><span class="sect2"><a href="ch02s10.html#config.sending-email.smtp">2.10.2. Versand über einen SMTP-Server</a></span></dt></dl></dd><dt><span class="sect1"><a href="ch02s11.html">2.11. Drucken mit kivitendo</a></span></dt><dd><dl><dt><span class="sect2"><a href="ch02s11.html#Vorlagenverzeichnis-anlegen">2.11.1. Vorlagenverzeichnis anlegen</a></span></dt><dt><span class="sect2"><a href="ch02s11.html#Vorlagen-Standard">2.11.2. Standard</a></span></dt><dt><span class="sect2"><a href="ch02s11.html#f-tex">2.11.3. f-tex</a></span></dt><dt><span class="sect2"><a href="ch02s11.html#Vorlagen-RB">2.11.4. RB</a></span></dt><dt><span class="sect2"><a href="ch02s11.html#allgemeine-hinweise-zu-latex">2.11.5. Allgemeine Hinweise zu LaTeX Vorlagen</a></span></dt></dl></dd><dt><span class="sect1"><a href="ch02s12.html">2.12. OpenDocument-Vorlagen</a></span></dt><dt><span class="sect1"><a href="ch02s13.html">2.13. Konfiguration zur Einnahmenüberschussrechnung/Bilanzierung:
EUR</a></span></dt><dd><dl><dt><span class="sect2"><a href="ch02s13.html#config.eur.introduction">2.13.1. Einführung</a></span></dt><dt><span class="sect2"><a href="ch02s13.html#config.eur.parameters">2.13.2. Konfigurationsparameter</a></span></dt><dt><span class="sect2"><a href="ch02s13.html#config.eur.setting-parameters">2.13.3. Festlegen der Parameter</a></span></dt><dt><span class="sect2"><a href="ch02s13.html#config.eur.inventory-system-perpetual">2.13.4. Bemerkungen zu Bestandsmethode</a></span></dt><dt><span class="sect2"><a href="ch02s13.html#config.eur.knonw-issues">2.13.5. Bekannte Probleme</a></span></dt></dl></dd><dt><span class="sect1"><a href="ch02s14.html">2.14. SKR04 19% Umstellung für innergemeinschaftlichen Erwerb</a></span></dt><dd><dl><dt><span class="sect2"><a href="ch02s14.html#config.skr04-update-3804.introduction">2.14.1. Einführung</a></span></dt><dt><span class="sect2"><a href="ch02s14.html#config.skr04-update-3804.create-chart">2.14.2. Konto 3804 manuell anlegen</a></span></dt></dl></dd><dt><span class="sect1"><a href="ch02s15.html">2.15. Einstellungen pro Mandant</a></span></dt><dt><span class="sect1"><a href="ch02s16.html">2.16. kivitendo ERP verwenden</a></span></dt></dl></dd><dt><span class="chapter"><a href="ch03.html">3. Features und Funktionen</a></span></dt><dd><dl><dt><span class="sect1"><a href="ch03.html#features.periodic-invoices">3.1. Wiederkehrende Rechnungen</a></span></dt><dd><dl><dt><span class="sect2"><a href="ch03.html#features.periodic-invoices.introduction">3.1.1. Einführung</a></span></dt><dt><span class="sect2"><a href="ch03.html#features.periodic-invoices.configuration">3.1.2. Konfiguration</a></span></dt><dt><span class="sect2"><a href="ch03.html#features.periodic-invoices.variables">3.1.3. Spezielle Variablen</a></span></dt><dt><span class="sect2"><a href="ch03.html#features.periodic-invoices.reports">3.1.4. Auflisten</a></span></dt><dt><span class="sect2"><a href="ch03.html#features.periodic-invoices.task-server">3.1.5. Erzeugung der eigentlichen Rechnungen</a></span></dt><dt><span class="sect2"><a href="ch03.html#features.periodic-invoices.create-for-current-month">3.1.6. Erste Rechnung für aktuellen Monat erstellen</a></span></dt></dl></dd><dt><span class="sect1"><a href="ch03s02.html">3.2. Dokumentenvorlagen und verfügbare Variablen</a></span></dt><dd><dl><dt><span class="sect2"><a href="ch03s02.html#dokumentenvorlagen-und-variablen.einf%C3%BChrung">3.2.1. Einführung</a></span></dt><dt><span class="sect2"><a href="ch03s02.html#dokumentenvorlagen-und-variablen.variablen-ausgeben">3.2.2. Variablen ausgeben</a></span></dt><dt><span class="sect2"><a href="ch03s02.html#dokumentenvorlagen-und-variablen.verwendung-in-druckbefehlen">3.2.3. Verwendung in Druckbefehlen</a></span></dt><dt><span class="sect2"><a href="ch03s02.html#dokumentenvorlagen-und-variablen.tag-style">3.2.4. Anfang und Ende der Tags verändern</a></span></dt><dt><span class="sect2"><a href="ch03s02.html#dokumentenvorlagen-und-variablen.zuordnung-dateinamen">3.2.5. Zuordnung von den Dateinamen zu den Funktionen</a></span></dt><dt><span class="sect2"><a href="ch03s02.html#dokumentenvorlagen-und-variablen.dateinamen-erweitert">3.2.6. Sprache, Drucker und E-Mail</a></span></dt><dt><span class="sect2"><a href="ch03s02.html#dokumentenvorlagen-und-variablen.allgemeine-variablen">3.2.7. Allgemeine Variablen, die in allen Vorlagen vorhanden
sind</a></span></dt><dt><span class="sect2"><a href="ch03s02.html#dokumentenvorlagen-und-variablen.invoice">3.2.8. Variablen in Rechnungen</a></span></dt><dt><span class="sect2"><a href="ch03s02.html#dokumentenvorlagen-und-variablen.dunning">3.2.9. Variablen in Mahnungen und Rechnungen über Mahngebühren</a></span></dt><dt><span class="sect2"><a href="ch03s02.html#dokumentenvorlagen-und-variablen.andere-vorlagen">3.2.10. Variablen in anderen Vorlagen</a></span></dt><dt><span class="sect2"><a href="ch03s02.html#dokumentenvorlagen-und-variablen.bloecke">3.2.11. Blöcke, bedingte Anweisungen und Schleifen</a></span></dt><dt><span class="sect2"><a href="ch03s02.html#dokumentenvorlagen-und-variablen.markup">3.2.12. Markup-Code zur Textformatierung innerhalb von
- Formularen</a></span></dt></dl></dd><dt><span class="sect1"><a href="ch03s03.html">3.3. Excel-Vorlagen</a></span></dt><dd><dl><dt><span class="sect2"><a href="ch03s03.html#excel-templates.summary">3.3.1. Zusammenfassung</a></span></dt><dt><span class="sect2"><a href="ch03s03.html#excel-templates.usage">3.3.2. Bedienung</a></span></dt><dt><span class="sect2"><a href="ch03s03.html#excel-templates.syntax">3.3.3. Variablensyntax</a></span></dt><dt><span class="sect2"><a href="ch03s03.html#excel-templates.limitations">3.3.4. Einschränkungen</a></span></dt></dl></dd></dl></dd><dt><span class="chapter"><a href="ch04.html">4. Entwicklerdokumentation</a></span></dt><dd><dl><dt><span class="sect1"><a href="ch04.html#devel.globals">4.1. Globale Variablen</a></span></dt><dd><dl><dt><span class="sect2"><a href="ch04.html#d0e5252">4.1.1. Wie sehen globale Variablen in Perl aus?</a></span></dt><dt><span class="sect2"><a href="ch04.html#d0e5353">4.1.2. Warum sind globale Variablen ein Problem?</a></span></dt><dt><span class="sect2"><a href="ch04.html#d0e5386">4.1.3. Kanonische globale Variablen</a></span></dt><dt><span class="sect2"><a href="ch04.html#d0e5766">4.1.4. Ehemalige globale Variablen</a></span></dt></dl></dd><dt><span class="sect1"><a href="ch04s02.html">4.2. Entwicklung unter FastCGI</a></span></dt><dd><dl><dt><span class="sect2"><a href="ch04s02.html#devel.fcgi.general">4.2.1. Allgemeines</a></span></dt><dt><span class="sect2"><a href="ch04s02.html#devel.fcgi.exiting">4.2.2. Programmende und Ausnahmen</a></span></dt><dt><span class="sect2"><a href="ch04s02.html#devel.fcgi.globals">4.2.3. Globale Variablen</a></span></dt><dt><span class="sect2"><a href="ch04s02.html#devel.fcgi.performance">4.2.4. Performance und Statistiken</a></span></dt><dt><span class="sect2"><a href="ch04s02.html#devel.fcgi.known-issues">4.2.5. Bekannte Probleme</a></span></dt></dl></dd><dt><span class="sect1"><a href="ch04s03.html">4.3. SQL-Upgradedateien</a></span></dt><dd><dl><dt><span class="sect2"><a href="ch04s03.html#db-upgrade-files.introduction">4.3.1. Einführung</a></span></dt><dt><span class="sect2"><a href="ch04s03.html#db-upgrade-files.format">4.3.2. Format der Kontrollinformationen</a></span></dt><dt><span class="sect2"><a href="ch04s03.html#db-upgrade-files.dbupgrade-tool">4.3.3. Hilfsscript dbupgrade2_tool.pl</a></span></dt></dl></dd><dt><span class="sect1"><a href="ch04s04.html">4.4. Translations and languages</a></span></dt><dd><dl><dt><span class="sect2"><a href="ch04s04.html#translations-languages.introduction">4.4.1. Introduction</a></span></dt><dt><span class="sect2"><a href="ch04s04.html#translations-languages.file-structure">4.4.2. File structure</a></span></dt></dl></dd><dt><span class="sect1"><a href="ch04s05.html">4.5. Die kivitendo-Test-Suite</a></span></dt><dd><dl><dt><span class="sect2"><a href="ch04s05.html#devel.testsuite.intro">4.5.1. Einführung</a></span></dt><dt><span class="sect2"><a href="ch04s05.html#devel.testsuite.prerequisites">4.5.2. Voraussetzungen</a></span></dt><dt><span class="sect2"><a href="ch04s05.html#devel.testsuite.execution">4.5.3.
+ Formularen</a></span></dt></dl></dd><dt><span class="sect1"><a href="ch03s03.html">3.3. Excel-Vorlagen</a></span></dt><dd><dl><dt><span class="sect2"><a href="ch03s03.html#excel-templates.summary">3.3.1. Zusammenfassung</a></span></dt><dt><span class="sect2"><a href="ch03s03.html#excel-templates.usage">3.3.2. Bedienung</a></span></dt><dt><span class="sect2"><a href="ch03s03.html#excel-templates.syntax">3.3.3. Variablensyntax</a></span></dt><dt><span class="sect2"><a href="ch03s03.html#excel-templates.limitations">3.3.4. Einschränkungen</a></span></dt></dl></dd></dl></dd><dt><span class="chapter"><a href="ch04.html">4. Entwicklerdokumentation</a></span></dt><dd><dl><dt><span class="sect1"><a href="ch04.html#devel.globals">4.1. Globale Variablen</a></span></dt><dd><dl><dt><span class="sect2"><a href="ch04.html#d0e5252">4.1.1. Wie sehen globale Variablen in Perl aus?</a></span></dt><dt><span class="sect2"><a href="ch04.html#d0e5353">4.1.2. Warum sind globale Variablen ein Problem?</a></span></dt><dt><span class="sect2"><a href="ch04.html#d0e5386">4.1.3. Kanonische globale Variablen</a></span></dt><dt><span class="sect2"><a href="ch04.html#d0e5766">4.1.4. Ehemalige globale Variablen</a></span></dt></dl></dd><dt><span class="sect1"><a href="ch04s02.html">4.2. Entwicklung unter FastCGI</a></span></dt><dd><dl><dt><span class="sect2"><a href="ch04s02.html#devel.fcgi.general">4.2.1. Allgemeines</a></span></dt><dt><span class="sect2"><a href="ch04s02.html#devel.fcgi.exiting">4.2.2. Programmende und Ausnahmen</a></span></dt><dt><span class="sect2"><a href="ch04s02.html#devel.fcgi.globals">4.2.3. Globale Variablen</a></span></dt><dt><span class="sect2"><a href="ch04s02.html#devel.fcgi.performance">4.2.4. Performance und Statistiken</a></span></dt><dt><span class="sect2"><a href="ch04s02.html#devel.fcgi.known-issues">4.2.5. Bekannte Probleme</a></span></dt></dl></dd><dt><span class="sect1"><a href="ch04s03.html">4.3. SQL-Upgradedateien</a></span></dt><dd><dl><dt><span class="sect2"><a href="ch04s03.html#db-upgrade-files.introduction">4.3.1. Einführung</a></span></dt><dt><span class="sect2"><a href="ch04s03.html#db-upgrade-files.format">4.3.2. Format der Kontrollinformationen</a></span></dt><dt><span class="sect2"><a href="ch04s03.html#db-upgrade-files.format-perl-files">4.3.3. Format von in Perl geschriebenen Datenbankupgradescripten</a></span></dt><dt><span class="sect2"><a href="ch04s03.html#db-upgrade-files.dbupgrade-tool">4.3.4. Hilfsscript dbupgrade2_tool.pl</a></span></dt></dl></dd><dt><span class="sect1"><a href="ch04s04.html">4.4. Translations and languages</a></span></dt><dd><dl><dt><span class="sect2"><a href="ch04s04.html#translations-languages.introduction">4.4.1. Introduction</a></span></dt><dt><span class="sect2"><a href="ch04s04.html#translations-languages.file-structure">4.4.2. File structure</a></span></dt></dl></dd><dt><span class="sect1"><a href="ch04s05.html">4.5. Die kivitendo-Test-Suite</a></span></dt><dd><dl><dt><span class="sect2"><a href="ch04s05.html#devel.testsuite.intro">4.5.1. Einführung</a></span></dt><dt><span class="sect2"><a href="ch04s05.html#devel.testsuite.prerequisites">4.5.2. Voraussetzungen</a></span></dt><dt><span class="sect2"><a href="ch04s05.html#devel.testsuite.execution">4.5.3.
Existierende Tests ausführen
</a></span></dt><dt><span class="sect2"><a href="ch04s05.html#devel.testsuite.meaning_of_scripts">4.5.4.
Bedeutung der verschiedenen Test-Scripte
if (data.error)
return display_flash('error', data.error);
- $('#flash_error').hide();
- $('#flash_error_content').empty();
+ $(['info', 'warning', 'error']).each(function(idx, category) {
+ $('#flash_' + category).hide();
+ $('#flash_' + category + '_content').empty();
+ });
if ((data.js || '') != '')
eval(data.js);
else if (action[0] == 'removeProp') $(action[1]).removeProp(action[2]);
else if (action[0] == 'val') $(action[1]).val(action[2]);
+ // Class attribute
+ else if (action[0] == 'addClass') $(action[1]).addClass(action[2]);
+ else if (action[0] == 'removeClass') $(action[1]).removeClass(action[2]);
+ else if (action[0] == 'toggleClass') $(action[1]).toggleClass(action[2]);
+
// Data storage
else if (action[0] == 'data') $(action[1]).data(action[2], action[3]);
else if (action[0] == 'removeData') $(action[1]).removeData(action[2]);
// Form Events
else if (action[0] == 'focus') $(action[1]).focus();
+ // ## jqModal plugin ##
+
+ // Closing and removing the popup
+ else if (action[0] == 'jqmClose') $(action[1]).jqmClose();
+
// ## jstree plugin ##
// Operations on the whole tree
else if (action[0] == 'jstree:deselect_node') $.jstree._reference($(action[1])).deselect_node(action[2]);
else if (action[0] == 'jstree:deselect_all') $.jstree._reference($(action[1])).deselect_all();
+ // ## other stuff ##
+ else if (action[0] == 'redirect_to') window.location.href = action[1];
+
else console.log('Unknown action: ' + action[0]);
});
// console.log("current_content_type " + $('#current_content_type').val() + ' ID ' + $('#current_content_id').val());
}
+function submit_ajax_form(url, form_selector, additional_data) {
+ var separator = /\?/.test(url) ? '&' : '?';
+ $.post(url + separator + $(form_selector).serialize(), additional_data, eval_json_result);
+ return true;
+}
+
// Local Variables:
// mode: js
// End:
return false;
}
+function open_jqm_window(params) {
+ params = params || { };
+ var url = params.url;
+ var id = params.id ? params.id : 'jqm_popup_dialog';
+
+ if (params.data) {
+ var data = typeof params.data === "string" ? params.data : $.param(params.data);
+ url += (/\?/.exec(url) ? "&" : "?") + data;
+ }
+
+ $('#' + id).remove();
+ var div = $('<div id="' + id + '" class="jqmWindow jqModal_overlay ' + (params.class || '') + '"></div>').hide().appendTo('body');
+ var close = $('<div class="close"></div>').appendTo(div);
+ var content = $('<div class="overlay_content"></div>').appendTo(div);
+ div.jqm({ modal: true });
+ div.jqmShow();
+ $.ajax({ url: url, success: function(new_html) { $(content).html(new_html); } });
+ $(close).click(function() {
+ div.jqmClose();
+ });
+
+ return true;
+}
+
$(document).ready(function () {
// initialize all jQuery UI tab elements:
$(".tabwidget").each(function(idx, element) { $(element).tabs(); });
$.fn.jqmAddTrigger=function(e){return hs(this,e,'jqmShow');};
$.fn.jqmShow=function(t){return this.each(function(){t=t||window.event;$.jqm.open(this._jqm,t);});};
$.fn.jqmHide=function(t){return this.each(function(){t=t||window.event;$.jqm.close(this._jqm,t)});};
+$.fn.jqmClose=function(t){return this.each(function(){t=t||window.event;$.jqm.close(this._jqm,t);this.remove();});};
$.jqm = {
hash:{},
--- /dev/null
+jQuery.download = function(url, data, method) {
+ //url and data options required
+ if (!url || !data)
+ return;
+
+ //data can be string of parameters or array/object
+ data = typeof data == 'string' ? data : jQuery.param(data);
+ //split params into form inputs
+ var form = jQuery('<form action="'+ url +'" method="'+ (method||'post') +'"></form>');
+ jQuery.each(data.split('&'), function(){
+ var pair = this.split('=');
+ var input = jQuery('<input type="hidden"/>');
+ input.attr('name', decodeURIComponent(pair[0]));
+ input.val(decodeURIComponent(pair[1]));
+ input.appendTo(form);
+ });
+ //send request
+ form.appendTo('body').submit().remove();
+};
'Account Nummer' => 'Kontonummer',
'Account Type' => 'Kontoart',
'Account Type missing!' => 'Kontoart fehlt!',
+ 'Account categories' => 'Kontoarten',
'Account deleted!' => 'Konto gelöscht!',
'Account for fees' => 'Konto für Gebühren',
'Account for interest' => 'Konto für Zinsen',
'Basic Data' => 'Basisdaten',
'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.',
'Belegnummer' => 'Buchungsnummer',
'Beratername' => 'Beratername',
'Beraternummer' => 'Beraternummer',
'Carry over shipping address' => 'Lieferadresse übernehmen',
'Cash' => 'Zahlungsverkehr',
'Cc' => 'Cc',
+ 'Cc E-mail' => 'CC (E-Mail)',
'Change kivitendo installation settings (all menu entries beneath \'System\')' => 'Verändern der kivitendo-Installationseinstellungen (Menüpunkte unterhalb von \'System\')',
'Change representative to' => 'Vertreter ändern in',
'Changes in this block are only sensible if the account is NOT a summary account AND there exists one valid taxkey. To select both Receivables and Payables only make sense for Payment / Receipt (i.e. account cash).' => 'Es ist nur sinnvoll Änderungen vorzunehmen, wenn das Konto KEIN Sammelkonto ist und wenn ein gültiger Steuerschlüssel für das Konto existiert. Gleichzeitig Haken bei Forderungen und Verbindlichkeiten zu setzen, macht auch NUR für den Zahlungsein- und Ausgang (bspw. Bank oder Kasse) Sinn.',
'Documentation (in German)' => 'Dokumentation',
'Documents in the WebDAV repository' => 'Dokumente im WebDAV-Repository',
'Done' => 'Fertig',
+ 'Double partnumbers' => 'Doppelte Artikelnummern',
'Download SEPA XML export file' => 'SEPA-XML-Exportdatei herunterladen',
'Download sample file' => 'Beispieldatei herunterladen',
'Download the backup' => 'Die Sicherungsdatei herunterladen',
'Execution type' => 'Ausführungsart',
'Existing Buchungsgruppen' => 'Existierende Buchungsgruppen',
'Existing Datasets' => 'Existierende Datenbanken',
+ 'Existing contacts (with column \'cp_id\')' => 'Existierende Ansprechpersonen (mit Spalte \'cp_id\')',
+ 'Existing customers/vendors with same customer/vendor number' => 'Existierende Kunden/Lieferanten mit derselben Kunden-/Lieferantennummer',
'Existing file on server' => 'Auf dem Server existierende Datei',
'Existing pending follow-ups for this item' => 'Noch nicht erledigte Wiedervorlagen für dieses Dokument',
'Existing profiles' => 'Existierende Profile',
'Expenses EU with UStId' => 'Aufwand EU m. UStId',
'Expenses EU without UStId' => 'Aufwand EU o. UStId',
'Export Buchungsdaten' => 'Export Buchungsdaten',
+ 'Export Number' => 'Exportnummer',
'Export Stammdaten' => 'Export Stammdaten',
'Export as CSV' => 'Als CSV exportieren',
'Export as PDF' => 'Als PDF exportieren',
'From' => 'Von',
'From Date' => 'Von',
'From this version on it is necessary to name a default value.' => 'Ab dieser Version benötigt kivitendo eine Standardwährung.',
+ 'From this version on a new feature is available.' => 'Ab dieser Version ist ein neues Feature verfügbar.',
+ 'From this version on the partnumber of services, articles and assemblies have to be unique.' => 'Ab dieser Version müssen Artikelnummern eindeutig vergeben werden.',
'From this version on the taxkey 0 must have a tax rate of 0 (for DATEV compatibility).' => 'Ab dieser Version muss der Steuerschlüssel 0 einen Steuersatz von 0% haben (auf Grund der DATEV-Kompatibilität).',
'Full Access' => 'Vollzugriff',
'Full Preview' => 'Alles',
'If the database user listed above does not have the right to create a database then enter the name and password of the superuser below:' => 'Falls der oben genannte Datenbankbenutzer nicht die Berechtigung zum Anlegen neuer Datenbanken hat, so können Sie hier den Namen und das Passwort des Datenbankadministratoraccounts angeben:',
'If you chose to let kivitendo do the migration then kivitendo will also remove the old member file after creating a backup copy of it in the directory "#1".' => 'Falls Sie sich entscheiden, kivitendo die Migration durchführen zu lassen, so wird kivitendo ein Backup der alten Dateien im Verzeichnis "#1" erstellen und die Dateien anschließend löschen.',
'If you enter values for the part number and / or part description then only those bins containing parts whose part number or part description match your input will be shown.' => 'Wenn Sie für die Artikelnummer und / oder die Beschreibung etwas eingeben, so werden nur die Lagerplätze angezeigt, in denen Waren eingelagert sind, die Ihre Suchbegriffe enthalten.',
+ 'If you have not chosen for example the category revenue for a tax and you choose an revenue account to create a transfer in the general ledger, this tax will not be displayed in the tax dropdown.' => 'Wenn Sie z.B. die Kategory Erlös für eine Steuer nicht gewählt haben und ein Erlöskonto beim Erstellen einer Dialogbuchung wählen, wird diese Steuer auch nicht im Dropdown-Menü für die Steuern angezeigt.',
'If you see this message, you most likely just setup your LX-Office and haven\'t added any entry types. If this is the case, the option is accessible for administrators in the System menu.' => 'Wenn Sie diese Meldung sehen haben Sie wahrscheinlich ein frisches LX-Office Setup und noch keine Buchungsgruppen eingerichtet. Ein Administrator kann dies im Systemmenü erledigen.',
'If you select a base unit then you also have to enter a factor.' => 'Wenn Sie eine Basiseinheit auswählen, dann müssen Sie auch einen Faktor eingeben.',
'If you want to change any of these parameters then press the "Back" button, edit the file "config/kivitendo.conf" and login into the admin module again.' => 'Wenn Sie einen der Parameter ändern wollen, so drücken Sie auf den "Zurück"-Button, bearbeiten Sie die Datei "config/kivitendo.conf", und melden Sie sich erneut im Administrationsbereich an.',
'If you want to delete such a dataset you have to edit the user(s) that are using the dataset in question and have them use another dataset.' => 'Wenn Sie eine solche Datenbank löschen wollen, so müssen Sie zuerst die Benutzer bearbeiten, die die fragliche Datenbank benutzen, und sie so ändern, dass sie eine andere Datenbank benutzen.',
'If you want to set up the authentication database yourself then log in to the administration panel. kivitendo will then create the database and tables for you.' => 'Wenn Sie die Authentifizierungs-Datenbank selber einrichten wollen, so melden Sie sich im Administrationsbereich an. kivitendo wird dann die Datenbank und die erforderlichen Tabellen für Sie anlegen.',
+ 'Illegal characters have been removed from the following fields: #1' => 'Ungültige Zeichen wurden aus den folgenden Feldern entfernt: #1',
'Image' => 'Grafik',
'Import' => 'Import',
'Import CSV' => 'CSV-Import',
'Increase' => 'Erhöhen',
'Individual Items' => 'Einzelteile',
'Information' => 'Information',
+ 'Insert with new customer/vendor number' => 'Mit neuer Kunden-/Lieferantennummer anlegen',
+ 'Insert with new database ID' => 'Neu anlegen mit neuer Datenbank-ID',
'Insert with new part number' => 'Mit neuer Artikelnummer einfügen',
'Interest' => 'Zinsen',
'Interest Rate' => 'Zinssatz',
'Languages and translations' => 'Sprachen und Übersetzungen',
'Last Action' => 'Letzte Aktivität',
'Last Article Number' => 'Letzte Artikelnummer',
+ 'Last Assembly Number' => 'Letzte Erzeugnisnummer',
'Last Cost' => 'Einkaufspreis',
'Last Credit Note Number' => 'Letzte Gutschriftnummer',
'Last Customer Number' => 'Letzte Kundennummer',
'Missing Method!' => 'Fehlender Voranmeldungszeitraum',
'Missing Tax Authoritys Preferences' => 'Fehlende Angaben zum Finanzamt!',
'Missing amount' => 'Fehlbetrag',
- 'Missing parameter #1 in call to sub #2.' => 'Fehlernder Parameter \'#1\' in Funktionsaufruf \'#2\'.',
+ 'Missing parameter #1 in call to sub #2.' => 'Fehlender Parameter \'#1\' in Funktionsaufruf \'#2\'.',
'Missing parameter (at least one of #1) in call to sub #2.' => 'Fehlernder Parameter (mindestens einer aus \'#1\') in Funktionsaufruf \'#2\'.',
'Missing taxkeys in invoices with taxes.' => 'Fehlende Steuerschlüssel in Rechnungen mit Steuern',
'Missing user id!' => 'Benutzer ID fehlt!',
'New bank account' => 'Neues Bankkonto',
'New contact' => 'Neue Ansprechperson',
'New customer' => 'Neuer Kunde',
+ 'New filter for tax accounts' => 'Neue Filter für Steuerkonten',
'New invoice' => 'Neue Rechnung',
'New part' => 'Neue Ware',
'New sales order' => 'Neuer Auftrag',
'Part Notes' => 'Bemerkungen',
'Part Number' => 'Artikelnummer',
'Part Number missing!' => 'Artikelnummer fehlt!',
+ 'Partnumber' => 'Artikelnummer',
'Partnumber must not be set to empty!' => 'Die Artikelnummer darf nicht auf leer geändert werden.',
'Partnumber not unique!' => 'Artikelnummer bereits vorhanden!',
'Parts' => 'Waren',
'Please Check the bank information for each customer:' => 'Bitte überprüfen Sie die Bankinformationen der Kunden:',
'Please Check the bank information for each vendor:' => 'Bitte überprüfen Sie die Kontoinformationen der Lieferanten:',
'Please ask your administrator to create warehouses and bins.' => 'Bitten Sie Ihren Administrator, dass er Lager und Lagerplätze anlegt.',
+ 'Please change the partnumber of the following parts and run the update again:' => 'Bitte ändern Sie daher die Artikelnumer folgender Artikel:',
+ 'Please choose for which categories the taxes should be displayed:' => 'Bitte wählen Sie für welche Kontoarten die Steuer angezeigt werden soll:',
'Please contact your administrator or a service provider.' => 'Bitte kontaktieren Sie Ihren Administrator oder einen Dienstleister.',
'Please contact your administrator.' => 'Bitte wenden Sie sich an Ihren Administrator.',
'Please define a taxkey for the following taxes and run the update again:' => 'Bitte definieren Sie einen Steuerschlüssel für die folgenden Steuern und starten Sie dann das Update erneut:',
'Service Items' => 'Dienstleistungen',
'Service Number missing!' => 'Dienstleistungsnummer fehlt!',
'Service unit' => 'Dienstleistungseinheit',
+ 'Service, assembly or part' => 'Dienstleistung, Erzeugnis oder Ware',
'Services' => 'Dienstleistungen',
'Set Language Values' => 'Spracheinstellungen',
'Set eMail text' => 'eMail Text eingeben',
'Single values in item mode, cumulated values in invoice mode' => 'Einzelwerte im Artikelmodus, kumulierte Werte im Rechnungsmodus',
'Skip' => 'Überspringen',
'Skip entry' => 'Eintrag überspringen',
- 'Skipping due to existing entry in database' => 'Übersprungen, wegen existierender Artikelnummer',
+ 'Skipping due to existing entry in database' => 'Wegen existierendem Eintrag mit selber Nummer übersprungen',
'Skonto' => 'Skonto',
'Skonto Terms' => 'Zahlungsziel Skonto',
+ 'So far you could use one partnumber for severel parts, for example a service and an article.' => 'Bisher war es möglich eine Artikelnummer für mehrere Artikel zu verwenden, zum Beispiel eine Artikelnummer für eine Dienstleistung, eine Ware und ein Erzeugnis.',
'Sold' => 'Verkauft',
'Solution' => 'Lösung',
'Sort By' => 'Sortiert nach',
'Tax deleted!' => 'Steuer gelöscht!',
'Tax number' => 'Steuernummer',
'Tax paid' => 'Vorsteuer',
+ 'Tax rate' => 'Steuersatz',
'Tax saved!' => 'Steuer gespeichert!',
'Tax-O-Matic' => 'Steuer',
'Tax-o-matic Account' => 'Automatikbuchung auf Konto',
'There are #1 more open invoices from this vendor with other currencies.' => 'Es gibt #1 weitere offene Rechnungen von diesem Lieferanten, die in anderen Währungen ausgestellt wurden.',
'There are #1 unfinished follow-ups of which #2 are due.' => 'Es gibt #1 Wiedervorlage(n), von denen #2 fällig ist/sind.',
'There are bookings to the account 3803 after 01.01.2007. If you didn\'t change this account manually to 19% the bookings are probably incorrect.' => 'Das Konto 3803 wurde nach dem 01.01.2007 bebucht. Falls Sie dieses Konto nicht manuell auf 19% gestellt haben sind die Buchungen wahrscheinlich mit falscher Umsatzsteuer gebucht worden.',
+ 'There are double partnumbers in your database.' => 'In ihrer Datenbank befinden sich mehrfach vergebene Artikelnummern.',
'There are entries in tax where taxkey is NULL.' => 'In der Datenbank sind Steuern ohne Steuerschlüssel vorhanden (in der Tabelle tax Spalte taxkey).',
'There are four tax zones.' => 'Es gibt vier Steuerzonen.',
'There are invalid taxnumbers in use.' => 'Es werden ungültige Steuerautomatik-Konten benutzt.',
'This corresponds to kivitendo\'s behavior prior to version 2.4.4.' => 'Dies entspricht kivitendos Verhalten vor Version 2.4.4.',
'This could have happened for two reasons:' => 'Dies kann aus zwei Gründen geschehen sein:',
'This customer number is already in use.' => 'Diese Kundennummer wird bereits verwendet.',
+ 'This feature especially prevents mistakes by mixing up prior tax and sales tax.' => 'Dieses Feature vermeidet insbesondere Verwechslungen von Umsatz- und Vorsteuer.',
'This group will be called "Full Access".' => 'Diese Gruppe wird "Vollzugriff" genannt.',
'This installation uses an unknown chart of accounts ("#1"). This database upgrade cannot create standard buchungsgruppen automatically.' => 'Diese Installation benutzt einen unbekannten Kontenrahmen ("#1"). Dieses Datenbankupgrade kann die Standardbuchungsgruppen nicht automatisch anlegen.',
'This is a preliminary check for existing sources. Nothing will be created or deleted at this stage!' => 'In diesem Schritt werden bestehende Datenbanken gesucht. Es werden noch keine Änderungen vorgenommen!',
'Update complete' => 'Update beendet.',
'Update prices' => 'Preise aktualisieren',
'Update prices of existing entries' => 'Preise von vorhandenen Artikeln aktualisieren',
+ 'Update properties of existing entries' => 'Eigenschaften von existierenden Einträgen aktualisieren',
'Update?' => 'Aktualisieren?',
'Updated' => 'Erneuert am',
+ 'Updating existing entry in database' => 'Existierenden Eintrag in Datenbank aktualisieren',
'Updating prices of existing entry in database' => 'Preis des Eintrags in der Datenbank wird aktualisiert',
'Uploaded on #1, size #2 kB' => 'Am #1 hochgeladen, Größe #2 kB',
'Use As New' => 'Als neu verwenden',
'You are logged out!' => 'Auf Wiedersehen!',
'You can also create new units now.' => 'Sie können jetzt auch neue Einheiten anlegen.',
'You can also delete this transaction and re-enter it manually.' => 'Alternativ können Sie die Buchung auch mit löschen lassen und sie anschließend neu eingeben.',
+ 'You can choose account categories for taxes. Depending on these categories taxes will be displayed for transfers in the general ledger or not.' => 'Sie können Kontoarten für Steuern auswählen. Abhängig von diesen Kontoarten werden dann Steuern bei Dialogbuchungen angezeigt oder nicht.',
'You can correct this transaction by chosing the correct taxkeys from the drop down boxes and hitting the button "Fix transaction" afterwards.' => 'Sie haben die Möglichkeit, die Buchung zu korrigieren, indem Sie in den Drop-Down-Boxen die richtigen Steuerschlüssel auswählen und anschließend auf den Button "Buchung korrigieren" drücken.',
'You can create a missing dataset by going back and chosing "Create Dataset".' => 'Sie können eine fehlende Datenbank erstellen, indem Sie jetzt zuück gehen und den Punkt "Neue Datenbank anlegen" wählen.',
'You can create warehouses and bins via the menu "System -> Warehouses".' => 'Sie können Lager und Lagerplätze über das Menü "System -> Lager" anlegen.',
'You can either create a new database or chose an existing database.' => 'Sie können entweder eine neue Datenbank erstellen oder eine existierende auswählen.',
'You can find information on the migration in the upgrade chapter of the documentation.' => 'Informationen über die Migration sind in der Upgrade Kapitel in der Dokumentation zu finden.',
'You can only delete datasets that are not in use.' => 'Sie können nur Datenbanken löschen, die momentan nicht in Benutzung sind.',
+ 'You can update existing contacts by providing the \'cp_id\' column with their database IDs. Otherwise: ' => 'Sie können existierende Einträge aktualisieren, indem Sie eine Spalte \'cp_id\' mit der Datenbank-ID des Eintrags mitgeben. Andernfalls: ',
'You can use the following strings in the long description and all translations. They will be replaced by their actual values by kivitendo before they\'re output.' => 'Sie können die folgenden Begriffe in den Langtexten und allen Übersetzungen benutzen. Sie werden von kivitendo vor der Ausgabe durch ihren tatsächlichen Wert ersetzt.',
'You cannot adjust the price for pricegroup "#1" by a negative percentage.' => 'Sie können den Preis für Preisgruppe "#1" um einen negativen Prozentwert anpassen.',
'You cannot continue before all required modules are installed.' => 'Sie können nicht fortfahren, bevor alle benötigten Pakete installiert sind.',
'ap_aging_list' => 'liste_offene_verbindlichkeiten',
'ar_aging_list' => 'liste_offene_forderungen',
'as at' => 'zum Stand',
+ 'assembly' => 'Erzeugnis',
'assembly_list' => 'erzeugnisliste',
'averaged values, in invoice mode only useful when filtered by a part' => 'gemittelte Werte, im Rechnungsmodus nur sinnvoll wenn nach Artikel gefiltert wird',
'back' => 'zurück',
'ea' => 'St.',
'emailed to' => 'gemailt an',
'empty' => 'leer',
+ 'every third month' => 'vierteljährlich',
'every time' => 'immer',
'executed' => 'ausgeführt',
'failed' => 'fehlgeschlagen',
'order' => 'Reihenfolge',
'our vendor number at customer' => 'Unsere Lieferanten-Nr. beim Kunden',
'parsing csv' => 'Parse CSV Daten',
+ 'part' => 'Ware',
'part_list' => 'Warenliste',
'percental' => 'prozentual',
'periodic' => 'Aufwandsmethode',
'purchase_order' => 'Auftrag',
'purchase_order_list' => 'lieferantenauftragsliste',
'quarter' => 'Vierteljährliche (quartalsweise) Abgabe',
- 'quarterly' => 'quartalsweise',
'quotation_list' => 'angebotsliste',
'release_material' => 'Materialausgabebe',
'reorder item' => 'Eintrag umsortieren',
'saving data' => 'Speichere Daten',
'sent' => 'gesendet',
'sent to printer' => 'an Drucker geschickt',
+ 'service' => 'Dienstleistung',
'service_list' => 'dienstleistungsliste',
'shipped' => 'verschickt',
'singular first char' => 'S',
--- /dev/null
+#!/usr/bin/perl
+
+BEGIN {
+ use SL::System::Process;
+ my $exe_dir = SL::System::Process::exe_dir;
+
+ unshift @INC, "${exe_dir}/modules/override"; # Use our own versions of various modules (e.g. YAML).
+ push @INC, "${exe_dir}/modules/fallback"; # Only use our own versions of modules if there's no system version.
+ unshift @INC, $exe_dir;
+}
+
+use strict;
+use warnings;
+
+use Data::Dumper;
+use DBI;
+use List::MoreUtils qw(any);
+use SL::LxOfficeConf;
+
+our %lx_office_conf;
+SL::LxOfficeConf->read;
+
+sub psql {
+ my ($title, %params) = @_;
+ print "Connecting to ${title} database '" . $params{db} . "' on " . $params{host} . ':' . $params{port} . " with PostgreSQL username " . $params{user} . "\n\n";
+ print "If asked for the password use this: " . $params{password} . "\n\n";
+ exec "psql", "-U", $params{user}, "-h", $params{host}, "-p", $params{port}, $params{db};
+}
+
+my $settings = $lx_office_conf{'authentication/database'};
+die "Missing configuration section 'authentication/database'" unless $settings;
+die "Incomplete database settings" if any { !$settings->{$_} } qw (host db user);
+$settings->{port} ||= 5432;
+
+psql("authentication", %{ $settings }) if !@ARGV;
+
+my $dbh = DBI->connect('dbi:Pg:dbname=' . $settings->{db} . ';host=' . $settings->{host} . ($settings->{port} ? ';port=' . $settings->{port} : ''), $settings->{user}, $settings->{password})
+ or die "Database connection to authentication database failed: " . $DBI::errstr;
+
+my $user_id = $dbh->selectrow_array(qq|SELECT id FROM auth.user WHERE login = ?|, undef, $ARGV[0])
+ or do {
+ $dbh->disconnect;
+ die "No such user in authentication database: " . $ARGV[0];
+ };
+
+my $href = $dbh->selectall_hashref(qq|SELECT cfg_key, cfg_value FROM auth.user_config WHERE user_id = ?|, 'cfg_key', undef, $user_id);
+$dbh->disconnect;
+
+my %params = (
+ host => $href->{dbhost}->{cfg_value},
+ db => $href->{dbname}->{cfg_value},
+ port => $href->{dbport}->{cfg_value} || 5432,
+ user => $href->{dbuser}->{cfg_value},
+ password => $href->{dbpasswd}->{cfg_value},
+);
+
+die "Incomplete database settings for user " . $ARGV[0] if any { !$settings->{$_} } qw (host db user);
+
+psql($ARGV[0] . "'s", %params);
if (data.error)
return display_flash('error', data.error);
- $('#flash_error').hide();
- $('#flash_error_content').empty();
+ $(['info', 'warning', 'error']).each(function(idx, category) {
+ $('#flash_' + category).hide();
+ $('#flash_' + category + '_content').empty();
+ });
if ((data.js || '') != '')
eval(data.js);
// console.log("current_content_type " + $('#current_content_type').val() + ' ID ' + $('#current_content_id').val());
}
+function submit_ajax_form(url, form_selector, additional_data) {
+ var separator = /\?/.test(url) ? '&' : '?';
+ $.post(url + separator + $(form_selector).serialize(), additional_data, eval_json_result);
+ return true;
+}
+
// Local Variables:
// mode: js
// End:
my $file = shift;
- if (!defined $cached{$file}) {
- my %plugins = ( 'loaded' => { }, 'needed' => { } );
-
- open(IN, $file) || die $file;
+ return if defined $cached{$file};
- my $copying = 0;
- my $issubmit = 0;
- my $text = "";
- while (my $line = <IN>) {
- chomp($line);
+ my %plugins = ( 'loaded' => { }, 'needed' => { } );
- while ($line =~ m/\[\%[^\w]*use[^\w]+(\w+)[^\w]*?\%\]/gi) {
- $plugins{loaded}->{$1} = 1;
- }
+ if (!open(IN, $file)) {
+ print "E: template file '$file' not found\n";
+ return;
+ }
- while ($line =~ m/\[\%[^\w]*(\w+)\.\w+\(/g) {
- my $plugin = $1;
- $plugins{needed}->{$plugin} = 1 if (first { $_ eq $plugin } qw(HTML LxERP JavaScript JSON L P));
- }
+ my $copying = 0;
+ my $issubmit = 0;
+ my $text = "";
+ while (my $line = <IN>) {
+ chomp($line);
- $plugins{needed}->{T8} = 1 if $line =~ m/\[\%.*\|.*\$T8/;
-
- while ($line =~ m/(?: # Start von Variante 1: LxERP.t8('...'); ohne darumliegende [% ... %]-Tags
- (LxERP\.t8)\( # LxERP.t8( ::Parameter $1::
- ([\'\"]) # Anfang des zu übersetzenden Strings ::Parameter $2::
- (.*?) # Der zu übersetzende String ::Parameter $3::
- (?<!\\)\2 # Ende des zu übersetzenden Strings
- | # Start von Variante 2: [% '...' | $T8 %]
- \[\% # Template-Start-Tag
- [\-~#]? # Whitespace-Unterdrückung
- \s* # Optional beliebig viele Whitespace
- ([\'\"]) # Anfang des zu übersetzenden Strings ::Parameter $4::
- (.*?) # Der zu übersetzende String ::Parameter $5::
- (?<!\\)\4 # Ende des zu übersetzenden Strings
- \s*\|\s* # Pipe-Zeichen mit optionalen Whitespace davor und danach
- (\$T8) # Filteraufruf ::Parameter $6::
- .*? # Optionale Argumente für den Filter
- \s* # Whitespaces
- [\-~#]? # Whitespace-Unterdrückung
- \%\] # Template-Ende-Tag
- )
- /ix) {
- my $module = $1 || $6;
- my $string = $3 || $5;
- print "Found filter >>>$string<<<\n" if $debug;
- substr $line, $LAST_MATCH_START[1], $LAST_MATCH_END[0] - $LAST_MATCH_START[0], '';
-
- $string = unescape_template_string($string);
- $cached{$file}{all}{$string} = 1;
- $cached{$file}{html}{$string} = 1;
- $cached{$file}{submit}{$string} = 1 if $PREMATCH =~ /$submitsearch/;
- $plugins{needed}->{T8} = 1 if $module eq '$T8';
- $plugins{needed}->{LxERP} = 1 if $module eq 'LxERP.t8';
- }
+ while ($line =~ m/\[\%[^\w]*use[^\w]+(\w+)[^\w]*?\%\]/gi) {
+ $plugins{loaded}->{$1} = 1;
+ }
- while ($line =~ m/\[\% # Template-Start-Tag
- [\-~#]? # Whitespace-Unterdrückung
- \s* # Optional beliebig viele Whitespace
- (?: # Die erkannten Template-Direktiven
- PROCESS
- |
- INCLUDE
- )
- \s+ # Mindestens ein Whitespace
- [\'\"]? # Anfang des Dateinamens
- ([^\s]+) # Beliebig viele Nicht-Whitespaces -- Dateiname
- \.html # Endung ".html", ansonsten kann es der Name eines Blocks sein
- /ix) {
- my $new_file_name = "$basedir/templates/webpages/$1.html";
- $cached{$file}{scanh}{$new_file_name} = 1;
- substr $line, $LAST_MATCH_START[1], $LAST_MATCH_END[0] - $LAST_MATCH_START[0], '';
- }
+ while ($line =~ m/\[\%[^\w]*(\w+)\.\w+\(/g) {
+ my $plugin = $1;
+ $plugins{needed}->{$plugin} = 1 if (first { $_ eq $plugin } qw(HTML LxERP JavaScript JSON L P));
}
- close(IN);
+ $plugins{needed}->{T8} = 1 if $line =~ m/\[\%.*\|.*\$T8/;
+
+ while ($line =~ m/(?: # Start von Variante 1: LxERP.t8('...'); ohne darumliegende [% ... %]-Tags
+ (LxERP\.t8)\( # LxERP.t8( ::Parameter $1::
+ ([\'\"]) # Anfang des zu übersetzenden Strings ::Parameter $2::
+ (.*?) # Der zu übersetzende String ::Parameter $3::
+ (?<!\\)\2 # Ende des zu übersetzenden Strings
+ | # Start von Variante 2: [% '...' | $T8 %]
+ \[\% # Template-Start-Tag
+ [\-~#]? # Whitespace-Unterdrückung
+ \s* # Optional beliebig viele Whitespace
+ ([\'\"]) # Anfang des zu übersetzenden Strings ::Parameter $4::
+ (.*?) # Der zu übersetzende String ::Parameter $5::
+ (?<!\\)\4 # Ende des zu übersetzenden Strings
+ \s*\|\s* # Pipe-Zeichen mit optionalen Whitespace davor und danach
+ (\$T8) # Filteraufruf ::Parameter $6::
+ .*? # Optionale Argumente für den Filter
+ \s* # Whitespaces
+ [\-~#]? # Whitespace-Unterdrückung
+ \%\] # Template-Ende-Tag
+ )
+ /ix) {
+ my $module = $1 || $6;
+ my $string = $3 || $5;
+ print "Found filter >>>$string<<<\n" if $debug;
+ substr $line, $LAST_MATCH_START[1], $LAST_MATCH_END[0] - $LAST_MATCH_START[0], '';
+
+ $string = unescape_template_string($string);
+ $cached{$file}{all}{$string} = 1;
+ $cached{$file}{html}{$string} = 1;
+ $cached{$file}{submit}{$string} = 1 if $PREMATCH =~ /$submitsearch/;
+ $plugins{needed}->{T8} = 1 if $module eq '$T8';
+ $plugins{needed}->{LxERP} = 1 if $module eq 'LxERP.t8';
+ }
- foreach my $plugin (keys %{ $plugins{needed} }) {
- next if ($plugins{loaded}->{$plugin});
- print "E: " . strip_base($file) . " requires the Template plugin '$plugin', but is not loaded with '[\% USE $plugin \%]'.\n";
+ while ($line =~ m/\[\% # Template-Start-Tag
+ [\-~#]? # Whitespace-Unterdrückung
+ \s* # Optional beliebig viele Whitespace
+ (?: # Die erkannten Template-Direktiven
+ PROCESS
+ |
+ INCLUDE
+ )
+ \s+ # Mindestens ein Whitespace
+ [\'\"]? # Anfang des Dateinamens
+ ([^\s]+) # Beliebig viele Nicht-Whitespaces -- Dateiname
+ \.html # Endung ".html", ansonsten kann es der Name eines Blocks sein
+ /ix) {
+ my $new_file_name = "$basedir/templates/webpages/$1.html";
+ $cached{$file}{scanh}{$new_file_name} = 1;
+ substr $line, $LAST_MATCH_START[1], $LAST_MATCH_END[0] - $LAST_MATCH_START[0], '';
}
}
+ close(IN);
+
+ foreach my $plugin (keys %{ $plugins{needed} }) {
+ next if ($plugins{loaded}->{$plugin});
+ print "E: " . strip_base($file) . " requires the Template plugin '$plugin', but is not loaded with '[\% USE $plugin \%]'.\n";
+ }
+
# copy back into global arrays
$alllocales{$_} = 1 for keys %{$cached{$file}{all}};
$locale{$_} = 1 for keys %{$cached{$file}{html}};
-#!/usr/bin/perl
# @tag: auth_schema_normalization_1
# @description: Auth-Datenbankschema Normalisierungen Teil 1
# @depends:
+package SL::DBUpgrade2::auth_schema_normalization_1;
use strict;
+use utf8;
-sub do_one {
- my ($dbh, $query) = @_;
+use parent qw(SL::DBUpgrade2::Base);
- if ($dbh->do($query)) {
- $dbh->commit();
- } else {
- $dbh->rollback();
- }
-}
-
-sub do_all {
- my $dbh = $::auth->dbconnect();
+sub run {
+ my ($self) = @_;
my @queries = ( qq|ALTER TABLE auth.group_rights ADD PRIMARY KEY (group_id, "right");|,
qq|ALTER TABLE auth.user_config ADD PRIMARY KEY (user_id, cfg_key);|,
qq|ALTER TABLE auth.user_group ADD PRIMARY KEY (user_id, group_id);|);
- do_one($dbh, $_) for @queries;
-}
+ $self->db_query($_, 1) for @queries;
-do_all();
+ return 1;
+}
1;
# @tag: SKR04-3804-addition
# @description: Konto 3804 zu SKR04 hinzufügen: Umsatzsteuer 19% für Steuerschlüssel 13 (Umsatzsteuer aus EG-Erwerb)
# @depends:
-# @charset: UTF-8
+package SL::DBUpgrade2::SKR04_3804_addition;
use utf8;
use strict;
-die("This script cannot be run from the command line.") unless ($main::form);
-
-sub mydberror {
- my ($msg) = @_;
- die($dbup_locale->text("Database update error:") . "<br>$msg<br>" . $DBI::errstr);
-}
-
-sub do_query {
- my ($query, $may_fail) = @_;
-
- if (!$dbh->do($query)) {
- mydberror($query) unless ($may_fail);
- $dbh->rollback();
- $dbh->begin_work();
- }
-}
+use parent qw(SL::DBUpgrade2::Base);
-
-sub do_update {
+sub run {
+ my ($self) = @_;
# 1. Überprüfen ob Kontenrahmen SKR04 ist, wenn nicht alles überspringen
- my ($kontenrahmen) = $dbh->selectrow_array("select coa from defaults");
+ my ($kontenrahmen) = $self->dbh->selectrow_array("select coa from defaults");
unless ( $kontenrahmen eq 'Germany-DATEV-SKR04EU' ) {
print "Kontenrahmen ist nicht SKR04, überspringen<br>";
# mit der falschen MwSt (16%) gebucht worden, wenn dies nicht manuell
# geändert worden ist
- my ($anzahl_buchungen) = $dbh->selectrow_array("select count (*) from acc_trans where taxkey=13 and transdate >= '2007-01-01';");
+ my ($anzahl_buchungen) = $self->dbh->selectrow_array("select count (*) from acc_trans where taxkey=13 and transdate >= '2007-01-01';");
if ( $anzahl_buchungen > 0 ) {
- if ($main::form->{bookings_exist} ) {
+ if ($::form->{bookings_exist} ) {
# Benutzer hat Meldung bestätigt
print "Buchungen nach dem 01.01.2007 existierten, Upgrade überspringen";
- return 1;
- } else {
- # Meldung anzeigen und auf Rückgabe warten
- print_past_booking_warning();
- return 2;
- };
- } else { # es gibt keine Buchungen mit taxkey 13 nach 01.01.2007
-
- # prüfen ob Konto 3804 schon existiert
- my ($konto_existiert) = $dbh->selectrow_array("select count (*) from chart where accno = '3804'");
- if ( $konto_existiert ) {
- # 3804 existiert, wir gehen davon aus, daß der Benutzer das Konto schon selber angelegt hat und
- # ordnungsgemäß benutzt
-
- if ($main::form->{account_exists} ) {
+ return 1;
+ }
+
+ # Meldung anzeigen und auf Rückgabe warten
+ print_past_booking_warning();
+ return 2;
+ }
+
+ # es gibt keine Buchungen mit taxkey 13 nach 01.01.2007
+
+ # prüfen ob Konto 3804 schon existiert
+ my ($konto_existiert) = $self->dbh->selectrow_array("select count (*) from chart where accno = '3804'");
+ if ( $konto_existiert ) {
+ # 3804 existiert, wir gehen davon aus, daß der Benutzer das Konto schon selber angelegt hat und
+ # ordnungsgemäß benutzt
+
+ if ($::form->{account_exists} ) {
# Benutzer hat Meldung bestätigt
- print "Konto existiert, Upgrade überspringen\n";
- return 1;
- } else {
- # Meldung anzeigen und auf Rückgabe warten
- print_3804_already_exists();
- return 2;
- };
- } else {
+ print "Konto existiert, Upgrade überspringen\n";
+ return 1;
+ }
+
+ # Meldung anzeigen und auf Rückgabe warten
+ print_3804_already_exists();
+ return 2;
+ }
# noch keine Buchungen mit taxkey 13 und Konto 3804 existiert noch nicht,
# also legen wir es an und machen noch die nötigen Einstellungen in tax und
# taxkeys
- my $insert_chart = <<SQL;
+ my $insert_chart = <<SQL;
INSERT INTO chart (
accno, description,
charttype, category, link,
);
SQL
- do_query($insert_chart);
-
- my $konto_anlegen = $dbh->prepare($insert_chart) || mydberror($insert_chart);
-
+ $self->db_query($insert_chart);
- # 13-1 (16%) korrigieren:
- my $edit_taxkey_13 = qq|UPDATE tax SET taxdescription = 'Steuerpflichtige EG-Lieferung zum vollen Steuersatz', rate = '0.16', chart_id = (select id FROM chart where accno = '3803'), taxnumber = 3803 WHERE taxkey = '13'|;
- do_query($edit_taxkey_13);
+ my $konto_anlegen = $self->dbh->prepare($insert_chart) || $self->db_error($insert_chart);
- # Sicherstellen, daß 3803 die richtige Bezeichnung hat
- my $update_3803 = qq|update chart set description = 'Umsatzsteuer aus EG-Erwerb 16%' where accno = '3803'|;
- do_query($update_3803);
+ # 13-1 (16%) korrigieren:
+ my $edit_taxkey_13 = qq|UPDATE tax SET taxdescription = 'Steuerpflichtige EG-Lieferung zum vollen Steuersatz', rate = '0.16', chart_id = (select id FROM chart where accno = '3803'), taxnumber = 3803 WHERE taxkey = '13'|;
+ $self->db_query($edit_taxkey_13);
- # Zweiter Eintrag für taxkey 13 in key: 19%
- my $insert_taxkey_13_2 = qq|INSERT INTO tax ( taxkey, taxdescription, rate, chart_id, taxnumber ) VALUES ('13', 'Steuerpflichtige EG-Lieferung zum vollen Steuersatz', '0.19', (select id from chart where accno = '3804'), '3804')|;
+ # Sicherstellen, daß 3803 die richtige Bezeichnung hat
+ my $update_3803 = qq|update chart set description = 'Umsatzsteuer aus EG-Erwerb 16%' where accno = '3803'|;
+ $self->db_query($update_3803);
- do_query($insert_taxkey_13_2);
+ # Zweiter Eintrag für taxkey 13 in key: 19%
+ my $insert_taxkey_13_2 = qq|INSERT INTO tax ( taxkey, taxdescription, rate, chart_id, taxnumber ) VALUES ('13', 'Steuerpflichtige EG-Lieferung zum vollen Steuersatz', '0.19', (select id from chart where accno = '3804'), '3804')|;
- # alle Konten finden, bei denen 3803 das Steuerautomatikkonto ist,
- # und dort den zweiten Eintrag ab 1.1.2007 für 19% einstellen
- my $sth_query = $dbh->prepare(qq|select c.id from chart c join taxkeys t on (c.id = t.chart_id) where tax_id = (select id from tax where taxnumber = '3803')|);
- my $sth_insert = $dbh->prepare(qq|INSERT INTO taxkeys ( taxkey_id, chart_id, tax_id, pos_ustva, startdate )
- VALUES (13, ?, (select id from tax where taxkey = 13 and rate = '0.19'),
- (select pos_ustva from taxkeys where tax_id = (select id from tax where taxnumber = '3803') and pos_ustva > 0 limit 1),
- '01.01.2007')|);
- $sth_query->execute();
+ $self->db_query($insert_taxkey_13_2);
- while (my $ref = $sth_query->fetchrow_hashref()) {
- $sth_insert->execute($ref->{id});
- }
- $sth_query->finish();
- $sth_insert->finish();
+ # alle Konten finden, bei denen 3803 das Steuerautomatikkonto ist,
+ # und dort den zweiten Eintrag ab 1.1.2007 für 19% einstellen
+ my $sth_query = $self->dbh->prepare(qq|select c.id from chart c join taxkeys t on (c.id = t.chart_id) where tax_id = (select id from tax where taxnumber = '3803')|);
+ my $sth_insert = $self->dbh->prepare(<<SQL);
+ INSERT INTO taxkeys ( taxkey_id, chart_id, tax_id, pos_ustva, startdate )
+ VALUES ( 13, ?, (select id from tax where taxkey = 13 and rate = '0.19'),
+ (SELECT pos_ustva FROM taxkeys WHERE tax_id = (SELECT id FROM tax WHERE taxnumber = '3803') AND pos_ustva > 0 LIMIT 1),
+ '01.01.2007' )
+SQL
+ $sth_query->execute;
- }; # end code update
- }; # end check if 3804 exists
+ while (my $ref = $sth_query->fetchrow_hashref) {
+ $sth_insert->execute($ref->{id});
+ }
+ $sth_query->finish;
+ $sth_insert->finish;
-}; # end do_update
+} # end run
sub print_past_booking_warning {
- print $main::form->parse_html_template("dbupgrade/SKR04_3804_update");
-};
+ print $::form->parse_html_template("dbupgrade/SKR04_3804_update");
+}
+
sub print_3804_already_exists {
- print $main::form->parse_html_template("dbupgrade/SKR04_3804_already_exists");
-};
+ print $::form->parse_html_template("dbupgrade/SKR04_3804_already_exists");
+}
-return do_update();
+1;
# @tag: USTVA_abstraction
# @description: Abstraktion der USTVA Report Daten. Dies vereinfacht die Integration von Steuerberichten anderer Nationen in kivitendo.
# @depends: release_2_4_2
+package SL::DBUpgrade2::USTVA_abstraction;
+
+use strict;
+use utf8;
+
+use parent qw(SL::DBUpgrade2::Base);
# Abstraktionlayer between general Taxreports and USTVA
# Most of the data and structures are not used yet, but maybe in future,
###################
-use strict;
-
-die("This script cannot be run from the command line.") unless ($main::form);
-
-sub mydberror {
- my ($msg) = @_;
- die($dbup_locale->text("Database update error:") .
- "<br>$msg<br>" . $DBI::errstr);
-}
-
-sub do_query {
- my ($query, $may_fail) = @_;
-
- if (!$dbh->do($query)) {
- mydberror($query) unless ($may_fail);
- $dbh->rollback();
- $dbh->begin_work();
- }
-}
-
-
sub create_tables {
+ my ($self) = @_;
# Watch out, SCHEMAs are new in Lx!
my @queries = ( # Watch out, it's a normal array!
},
);
- do_query("DROP SCHEMA tax CASCADE;", 1);
- map({ do_query($_, 0); } @queries);
+ $self->db_query("DROP SCHEMA tax CASCADE;", 1);
+ map({ $self->db_query($_, 0); } @queries);
return 1;
}
sub do_copy {
+ my ($self) = @_;
my @copy_statements = (
"INSERT INTO tax.report_categorys (id, description, subdescription) VALUES (?, ?, ?)",
my @copy_data = (
[ "0;;",
- "1;Lieferungen und sonstige Leistungen;(einschließlich unentgeltlicher Wertabgaben)",
+ "1;Lieferungen und sonstige Leistungen;(einschließlich unentgeltlicher Wertabgaben)",
"2;Innergemeinschaftliche Erwerbe;",
- "3;Ergänzende Angaben zu Umsätzen;",
+ "3;Ergänzende Angaben zu Umsätzen;",
"99;Summe;",
],
["0;0;;;",
- "1;1;received;Steuerfreie Umsätze mit Vorsteuerabzug;",
- "2;1;recieved;Steuerfreie Umsätze ohne Vorsteuerabzug;",
- "3;1;recieved;Steuerpflichtige Umsätze;(Lieferungen und sonstige Leistungen einschl. unentgeltlicher Wertabgaben)",
+ "1;1;received;Steuerfreie Umsätze mit Vorsteuerabzug;",
+ "2;1;recieved;Steuerfreie Umsätze ohne Vorsteuerabzug;",
+ "3;1;recieved;Steuerpflichtige Umsätze;(Lieferungen und sonstige Leistungen einschl. unentgeltlicher Wertabgaben)",
"4;2;recieved;Steuerfreie innergemeinschaftliche Erwerbe;",
"5;2;recieved;Steuerpflichtige innergemeinschaftliche Erwerbe;",
- "6;3;recieved;Umsätze, für die als Leistungsempfänger die Steuer nach § 13b Abs. 2 UStG geschuldet wird;",
+ "6;3;recieved;Umsätze, für die als Leistungsempfänger die Steuer nach § 13b Abs. 2 UStG geschuldet wird;",
"66;3;recieved;;",
- "7;3;paied;Abziehbare Vorsteuerbeträge;",
- "8;3;paied;Andere Steuerbeträge;",
+ "7;3;paied;Abziehbare Vorsteuerbeträge;",
+ "8;3;paied;Andere Steuerbeträge;",
"99;99;;Summe;",
],
["0;keine;0;< < < keine UStVa Position > > >;;;19700101",
- "1;41;1;Innergemeinschaftliche Lieferungen (§ 4 Nr. 1 Buchst. b UStG) an Abnehmer mit USt-IdNr.;0;0;19700101",
+ "1;41;1;Innergemeinschaftliche Lieferungen (§ 4 Nr. 1 Buchst. b UStG) an Abnehmer mit USt-IdNr.;0;0;19700101",
"2;44;1;neuer Fahrzeuge an Abnehmer ohne USt-IdNr.;0;0;19700101",
- "3;49;1;neuer Fahrzeuge außerhalb eines Unternehmens (§ 2a UStG);0;0;19700101",
- "4;43;1;Weitere steuerfreie Umsätze mit Vorsteuerabzug;0;0;19700101",
- "5;48;2;Umsätze nach § 4 Nr. 8 bis 28 UStG;0;0;19700101",
+ "3;49;1;neuer Fahrzeuge auÃ\9ferhalb eines Unternehmens (§ 2a UStG);0;0;19700101",
+ "4;43;1;Weitere steuerfreie Umsätze mit Vorsteuerabzug;0;0;19700101",
+ "5;48;2;Umsätze nach § 4 Nr. 8 bis 28 UStG;0;0;19700101",
"6;51;3;zum Steuersatz von 16 %;0;0;19700101",
"7;511;3;;6;2;19700101",
"8;81;3;zum Steuersatz von 19 %;0;0;19700101",
"9;811;3;;8;2;19700101",
"10;86;3;zum Steuersatz von 7 %;0;0;19700101",
"11;861;3;;10;2;19700101",
- "12;35;3;Umsätze, die anderen Steuersätzen unterliegen;0;0;19700101",
+ "12;35;3;Umsätze, die anderen Steuersätzen unterliegen;0;0;19700101",
"13;36;3;;12;2;19700101",
- "14;77;3;Lieferungen in das übrige Gemeinschaftsgebiet an Abnehmer mit USt-IdNr.;0;0;19700101",
- "15;76;3;Umsätze, für die eine Steuer nach § 24 UStG zu entrichten ist;0;0;19700101",
+ "14;77;3;Lieferungen in das übrige Gemeinschaftsgebiet an Abnehmer mit USt-IdNr.;0;0;19700101",
+ "15;76;3;Umsätze, für die eine Steuer nach § 24 UStG zu entrichten ist;0;0;19700101",
"16;80;3;;15;2;19700101",
- "17;91;4;Erwerbe nach § 4b UStG;0;0;19700101",
+ "17;91;4;Erwerbe nach § 4b UStG;0;0;19700101",
"18;97;5;zum Steuersatz von 16 %;0;0;19700101",
"19;971;5;;18;2;19700101",
"20;89;5;zum Steuersatz von 19 %;0;0;19700101",
"21;891;5;;20;2;19700101",
"22;93;5;zum Steuersatz von 7 %;0;0;19700101",
"23;931;5;;22;2;19700101",
- "24;95;5;zu anderen Steuersätzen;0;0;19700101",
+ "24;95;5;zu anderen Steuersätzen;0;0;19700101",
"25;98;5;;24;2;19700101",
"26;94;5;neuer Fahrzeuge von Lieferern ohne USt-IdNr. zum allgemeinen Steuersatz;0;0;19700101",
"27;96;5;;26;2;19700101",
- "28;42;66;Lieferungen des ersten Abnehmers bei innergemeinschaftlichen Dreiecksgeschäften (§ 25b Abs. 2 UStG);0;0;19700101",
- "29;60;66;Steuerpflichtige Umsätze im Sinne des § 13b Abs. 1 Satz 1 Nr. 1 bis 5 UStG, für die der Leistungsempfänger die Steuer schuldet;0;0;19700101",
- "30;45;66;Nicht steuerbare Umsätze (Leistungsort nicht im Inland);0;0;19700101",
- "31;52;6;Leistungen eines im Ausland ansässigen Unternehmers (§ 13b Abs. 1 Satz 1 Nr. 1 und 5 UStG);0;0;19700101",
+ "28;42;66;Lieferungen des ersten Abnehmers bei innergemeinschaftlichen Dreiecksgeschäften (§ 25b Abs. 2 UStG);0;0;19700101",
+ "29;60;66;Steuerpflichtige Umsätze im Sinne des § 13b Abs. 1 Satz 1 Nr. 1 bis 5 UStG, für die der Leistungsempfänger die Steuer schuldet;0;0;19700101",
+ "30;45;66;Nicht steuerbare Umsätze (Leistungsort nicht im Inland);0;0;19700101",
+ "31;52;6;Leistungen eines im Ausland ansässigen Unternehmers (§ 13b Abs. 1 Satz 1 Nr. 1 und 5 UStG);0;0;19700101",
"32;53;6;;31;2;19700101",
- "33;73;6;Lieferungen sicherungsübereigneter Gegenstände und Umsätze, die unter das GrEStG fallen (§ 13b Abs. 1 Satz 1 Nr. 2 und 3 UStG);0;0;19700101",
+ "33;73;6;Lieferungen sicherungsübereigneter Gegenstände und Umsätze, die unter das GrEStG fallen (§ 13b Abs. 1 Satz 1 Nr. 2 und 3 UStG);0;0;19700101",
"34;74;6;;33;2;19700101",
- "35;84;6;Bauleistungen eines im Inland ansässigen Unternehmers (§ 13b Abs. 1 Satz 1 Nr. 4 UStG);0;0;19700101",
+ "35;84;6;Bauleistungen eines im Inland ansässigen Unternehmers (§ 13b Abs. 1 Satz 1 Nr. 4 UStG);0;0;19700101",
"36;85;6;;35;2;19700101",
- "37;65;6;Steuer infolge Wechsels der Besteuerungsform sowie Nachsteuer auf versteuerte Anzahlungen u. ä. wegen Steuersatzänderung;;2;19700101",
- "38;66;7;Vorsteuerbeträge aus Rechnungen von anderen Unternehmern (§ 15 Abs. 1 Satz 1 Nr. 1 UStG), aus Leistungen im Sinne des § 13a Abs. 1 Nr. 6 UStG (§ 15 Abs. 1 Satz 1 Nr. 5 UStG) und aus innergemeinschaftlichen Dreiecksgeschäften (§ 25b Abs. 5 UStG);;2;19700101",
- "39;61;7;Vorsteuerbeträge aus dem innergemeinschaftlichen Erwerb von Gegenständen (§ 15 Abs. 1 Satz 1 Nr. 3 UStG);;2;19700101",
- "40;62;7;Entrichtete Einfuhrumsatzsteuer (§ 15 Abs. 1 Satz 1 Nr. 2 UStG);;2;19700101",
- "41;67;7;Vorsteuerbeträge aus Leistungen im Sinne des § 13b Abs. 1 UStG (§ 15 Abs. 1 Satz 1 Nr. 4 UStG);;2;19700101",
- "42;63;7;Vorsteuerbeträge, die nach allgemeinen Durchschnittssätzen berechnet sind (§§ 23 und 23a UStG);;2;19700101",
- "43;64;7;Berichtigung des Vorsteuerabzugs (§ 15a UStG);;2;19700101",
- "44;59;7;Vorsteuerabzug für innergemeinschaftliche Lieferungen neuer Fahrzeuge außerhalb eines Unternehmens (§ 2a UStG) sowie von Kleinunternehmern im Sinne des § 19 Abs. 1 UStG (§ 15 Abs. 4a UStG);;2;19700101",
- "45;69;8;in Rechnungen unrichtig oder unberechtigt ausgewiesene Steuerbeträge (§ 14c UStG) sowie Steuerbeträge, die nach § 4 Nr. 4a Satz 1 Buchst. a Satz 2, § 6a Abs. 4 Satz 2, § 17 Abs. 1 Satz 6 oder § 25b Abs. 2 UStG geschuldet werden;;2;19700101",
- "46;39;8;Anrechnung (Abzug) der festgesetzten Sondervorauszahlung für Dauerfristverlängerung (nur auszufüllen in der letzten Voranmeldung des Besteuerungszeitraums, in der Regel Dezember);;2;19700101",
+ "37;65;6;Steuer infolge Wechsels der Besteuerungsform sowie Nachsteuer auf versteuerte Anzahlungen u. ä. wegen Steuersatzänderung;;2;19700101",
+ "38;66;7;Vorsteuerbeträge aus Rechnungen von anderen Unternehmern (§ 15 Abs. 1 Satz 1 Nr. 1 UStG), aus Leistungen im Sinne des § 13a Abs. 1 Nr. 6 UStG (§ 15 Abs. 1 Satz 1 Nr. 5 UStG) und aus innergemeinschaftlichen Dreiecksgeschäften (§ 25b Abs. 5 UStG);;2;19700101",
+ "39;61;7;Vorsteuerbeträge aus dem innergemeinschaftlichen Erwerb von Gegenständen (§ 15 Abs. 1 Satz 1 Nr. 3 UStG);;2;19700101",
+ "40;62;7;Entrichtete Einfuhrumsatzsteuer (§ 15 Abs. 1 Satz 1 Nr. 2 UStG);;2;19700101",
+ "41;67;7;Vorsteuerbeträge aus Leistungen im Sinne des § 13b Abs. 1 UStG (§ 15 Abs. 1 Satz 1 Nr. 4 UStG);;2;19700101",
+ "42;63;7;Vorsteuerbeträge, die nach allgemeinen Durchschnittssätzen berechnet sind (§§ 23 und 23a UStG);;2;19700101",
+ "43;64;7;Berichtigung des Vorsteuerabzugs (§ 15a UStG);;2;19700101",
+ "44;59;7;Vorsteuerabzug für innergemeinschaftliche Lieferungen neuer Fahrzeuge auÃ\9ferhalb eines Unternehmens (§ 2a UStG) sowie von Kleinunternehmern im Sinne des § 19 Abs. 1 UStG (§ 15 Abs. 4a UStG);;2;19700101",
+ "45;69;8;in Rechnungen unrichtig oder unberechtigt ausgewiesene Steuerbeträge (§ 14c UStG) sowie Steuerbeträge, die nach § 4 Nr. 4a Satz 1 Buchst. a Satz 2, § 6a Abs. 4 Satz 2, § 17 Abs. 1 Satz 6 oder § 25b Abs. 2 UStG geschuldet werden;;2;19700101",
+ "46;39;8;Anrechnung (Abzug) der festgesetzten Sondervorauszahlung für Dauerfristverlängerung (nur auszufüllen in der letzten Voranmeldung des Besteuerungszeitraums, in der Regel Dezember);;2;19700101",
],
);
for my $statement ( 0 .. $#copy_statements ) {
- my $query = $iconv->convert($copy_statements[$statement]);
- my $sth = $dbh->prepare($query) || mydberror($query);
+ my $query = $copy_statements[$statement];
+ my $sth = $self->dbh->prepare($query) || $self->db_error($query);
for my $copy_line ( 0 .. $#{$copy_data[$statement]} ) {
#print $copy_data[$statement][$copy_line] . "<br />"
- $sth->execute(split m/;/, $iconv->convert($copy_data[$statement][$copy_line]), -1) || mydberror($query);
+ $sth->execute(split m/;/, $copy_data[$statement][$copy_line], -1) || $self->db_error($query);
}
$sth->finish();
}
return 1;
}
+sub run {
+ my ($self) = @_;
+ return $self->create_tables && $self->do_copy;
+}
-return create_tables() && do_copy();
+1;
# @tag: USTVA_at
# @description: USTVA Report Daten fuer Oesterreich. Vielen Dank an Gerhard Winkler..
# @depends: USTVA_abstraction
+package SL::DBUpgrade2::USTVA_at;
use strict;
+use utf8;
-use SL::DBUtils;
+use parent qw(SL::DBUpgrade2::Base);
-unless ( $main::form ) {
- die("This script cannot be run from the command line.");
-}
+sub run {
+ my ($self) = @_;
-if ( check_coa('Austria') ){
-
- if ( coa_is_empty() ) {
- print qq|Eine leere Datenbank mit Kontenrahmen Österreich vorgefunden. <br />
- Die Aktualisierungen werden eingespielt...<br />
- <b>Achtung: Dieses Update ist ungetestet und bedarf weiterer Konfiguration</b>|;
-
- return 1
- && clear_tables(( 'tax.report_variables', 'tax.report_headings',
- 'tax.report_categorys', 'taxkeys',
- 'tax', 'chart',
- 'buchungsgruppen',
- ))
- && do_copy_tax_report_structure()
- && do_insert_chart()
- && do_insert_tax()
- && do_insert_taxkeys()
- && do_insert_buchungsgruppen()
- ;
+ if (!$self->check_coa('Austria')) {
+ print qq|Nichts zu tun in diesem Kontenrahmen.|;
+ return 1;
}
- else {
- print qq|Eine österreichische Datenbank in der bereits Buchungssätze enthalten sind, kann nicht aktualisiert werden.<br />
+
+ if (!$self->is_coa_empty) {
+ print qq|Eine österreichische Datenbank in der bereits Buchungssätze enthalten sind, kann nicht aktualisiert werden.<br />
Bitte eine neue Datenbank mit Kontenrahmen 'Austria' anlegen.|;
return 1;
}
+ print qq|Eine leere Datenbank mit Kontenrahmen Österreich vorgefunden. <br />
+ Die Aktualisierungen werden eingespielt...<br />
+ <b>Achtung: Dieses Update ist ungetestet und bedarf weiterer Konfiguration</b>|;
+
+ return
+ $self->clear_tables('tax.report_variables', 'tax.report_headings',
+ 'tax.report_categorys', 'taxkeys',
+ 'tax', 'chart',
+ 'buchungsgruppen')
+ && $self->do_copy_tax_report_structure()
+ && $self->do_insert_chart()
+ && $self->do_insert_tax()
+ && $self->do_insert_taxkeys()
+ && $self->do_insert_buchungsgruppen()
+ ;
}
-else {
- print qq|Nichts zu tun in diesem Kontenrahmen.|;
- return 1;
-}
-
-return 0;
-
-######################################################
-
-sub mydberror {
- my ($msg) = @_;
- die($dbup_locale->text("Database update error:") .
- "<br>$msg<br>" . $DBI::errstr);
-}
-
-sub do_query {
- my ($query, $may_fail) = @_;
-
- if (!$dbh->do($query)) {
- mydberror($query) unless ($may_fail);
- $dbh->rollback();
- $dbh->begin_work();
- }
-}
-
sub clear_tables {
-
- my @clear = @_;
+ my ($self, @clear) = @_;
my @queries = (
q{ DELETE FROM tax.report_categorys; },
q{ DELETE FROM tax.report_variables; },
);
- map({ do_query("DELETE FROM $_ ;", 0); } @clear);
+ map({ $self->db_query("DELETE FROM $_ ;", 0); } @clear);
return 1;
}
-sub check_coa {
-
- my ( $want_coa ) = @_;
-
- my $query = q{ SELECT count(*) FROM defaults WHERE coa = ? };
- my ($have_coa) = selectrow_query($main::form, $dbh, $query, $want_coa);
-
- return $have_coa;
-
-}
-
-sub coa_is_empty {
-
- my $query = q{ SELECT count(*)
- FROM ar, ap, gl, invoice, acc_trans, customer, vendor, parts
- };
- my ($empty) = selectrow_query($main::form, $dbh, $query);
-
- $empty = !$empty;
-
- return $empty;
-}
-
-
sub do_copy_tax_report_structure {
+ my ($self) = @_;
my @queries = (
"INSERT INTO tax.report_categorys (id, description, subdescription) VALUES (0, NULL, NULL)",
"INSERT INTO tax.report_headings (id, category_id, type, description, subdescription) VALUES (0, 0, NULL, NULL, NULL)",
);
- map({ do_query($_); } @queries);
+ map({ $self->db_query($_); } @queries);
my @copy_statements = (
my @copy_data = (
[
- "1;000;0;a) Gesamtbetrag der Bemessungsgrundlage für Lieferungen und sonstige Leistungen (ohne den nachstehend angeführten Eigenverbrauch) einschließlich Anzahlungen (jeweils ohne Umsatzsteuer);2;1970-01-01",
- "2;001;0;zuzüglich Eigenverbrauch (§1 Abs. 1 Z 2, § 3 Abs. 2 und § 3a Abs. 1a);2;1970-01-01",
- "3;021;0;abzüglich Umsätze für die die Steuerschuld gemäß § 19 Abs. 1 zweiter Satz sowie gemäß § 19 Abs. 1a, Abs. 1b, Abs. 1c auf den Leistungsempfänger übergegangen ist.;2;1970-01-01",
- "4;011;0;a) §6 Abs. 1 Z 1 iVm § 7 (Ausfuhrlieferungen);2;1970-01-01",
- "5;012;0;b) §6 Abs. 1 Z 1 iVm § 8 (Lohnveredelungen);2;1970-01-01",
- "6;015;0;c) §6 Abs. 1 Z 2 bis 6 sowie § 23 Abs. 5 (Seeschifffahrt, Luftfahrt, grenzüberschreitende Personenbeförderung, Diplomaten, Reisevorleistungen im Drittlandsgebiet usw.);2;1970-01-01",
- "7;017;0;d) Art. 6 Abs. 1 (innergemeinschaftliche Lieferungen ohne die nachstehend gesondert anzuführenden Fahrzeuglieferungen);2;1970-01-01",
- "8;018;0;e) Art. 6 Abs. 1, sofern Lieferungen neuer Fahrzeuge an Abnehmer ohne UID-Nummer bzw. durch Fahrzeuglieferer gemäß Art. 2 erfolgen.;2;1970-01-01",
- "9;019;0;a) § 6 Abs. 1 Z 9 lit. a (Grundstücksumsätze);2;1970-01-01",
- "10;016;0;b) §6 Abs. 1 Z 27 (Kleinunternehmer);2;1970-01-01",
- "11;020;0;c) § 6 Abs. 1 Z ___ (übrige steuerfreie Umsätze ohne Vorsteuerabzug);2;1970-01-01",
+ "1;000;0;a) Gesamtbetrag der Bemessungsgrundlage für Lieferungen und sonstige Leistungen (ohne den nachstehend angeführten Eigenverbrauch) einschließlich Anzahlungen (jeweils ohne Umsatzsteuer);2;1970-01-01",
+ "2;001;0;zuzüglich Eigenverbrauch (§1 Abs. 1 Z 2, § 3 Abs. 2 und § 3a Abs. 1a);2;1970-01-01",
+ "3;021;0;abzüglich Umsätze für die die Steuerschuld gemäß § 19 Abs. 1 zweiter Satz sowie gemäß § 19 Abs. 1a, Abs. 1b, Abs. 1c auf den Leistungsempfänger übergegangen ist.;2;1970-01-01",
+ "4;011;0;a) §6 Abs. 1 Z 1 iVm § 7 (Ausfuhrlieferungen);2;1970-01-01",
+ "5;012;0;b) §6 Abs. 1 Z 1 iVm § 8 (Lohnveredelungen);2;1970-01-01",
+ "6;015;0;c) §6 Abs. 1 Z 2 bis 6 sowie § 23 Abs. 5 (Seeschifffahrt, Luftfahrt, grenzüberschreitende Personenbeförderung, Diplomaten, Reisevorleistungen im Drittlandsgebiet usw.);2;1970-01-01",
+ "7;017;0;d) Art. 6 Abs. 1 (innergemeinschaftliche Lieferungen ohne die nachstehend gesondert anzuführenden Fahrzeuglieferungen);2;1970-01-01",
+ "8;018;0;e) Art. 6 Abs. 1, sofern Lieferungen neuer Fahrzeuge an Abnehmer ohne UID-Nummer bzw. durch Fahrzeuglieferer gemäß Art. 2 erfolgen.;2;1970-01-01",
+ "9;019;0;a) § 6 Abs. 1 Z 9 lit. a (Grundstücksumsätze);2;1970-01-01",
+ "10;016;0;b) §6 Abs. 1 Z 27 (Kleinunternehmer);2;1970-01-01",
+ "11;020;0;c) § 6 Abs. 1 Z ___ (übrige steuerfreie Umsätze ohne Vorsteuerabzug);2;1970-01-01",
"12;022_links;0;20% Nominalsteuersatz;2;1970-01-01",
"13;022_rechts;0;20% Nominalsteuersatz;2;1970-01-01",
- "14;029_links;0;10% ermäßigter Steuersatz;2;1970-01-01",
- "15;029_rechts;0;10% ermäßigter Steuersatz;2;1970-01-01",
- "16;025_links;0;12% für Weinumsätze durch landwirtschaftliche Betriebe;2;1970-01-01",
- "17;025_rechts;0;12% für Weinumsätze durch landwirtschaftliche Betriebe;2;1970-01-01",
- "18;035_links;0;16% für Jungholz und Mittelberg;2;1970-01-01",
- "19;035_rechts;0;16% für Jungholz und Mittelberg;2;1970-01-01",
- "20;052_links;0;10% Zusatzsteuer für pauschalierte land- und forstwirtschaftliche Betriebe;2;1970-01-01",
- "21;052_rechts;0;10% Zusatzsteuer für pauschalierte land- und forstwirtschaftliche Betriebe;2;1970-01-01",
- "22;038_links;0;8% Zusatzsteuer für pauschalierte land- und forstwirtschaftliche Betriebe;2;1970-01-01",
- "23;038_rechts;0;8% Zusatzsteuer für pauschalierte land- und forstwirtschaftliche Betriebe;2;1970-01-01",
- "24;056;0;Steuerschuld gemäß § 11 Abs. 12 und 14, § 16 Abs. 2 sowie gemäß Art. 7 Abs. 4;2;1970-01-01",
- "25;057;0;Steuerschuld gemäß § 19 Abs. 1 zweiter Satz, § 19 Abs. 1c sowie gemäß Art. 25 Abs. 5;2;1970-01-01",
- "26;048;0;Steuerschuld gemäß § 19 Abs. 1a (Bauleistungen);2;1970-01-01",
- "27;044;0;Steuerschuld gemäß § 19 Abs. 1b (Sicherungseigentum, Vorbehaltseigentum und Grundstücke im Zwangsversteigerungsverfahren);2;1970-01-01",
- "28;070;0;Gesamtbetrag der Bemessungsgrundlagen für innergemeinschaftliche Erwerbe;2;1970-01-01",
- "29;071;0;Davon Steuerfrei gemäß Art. 6 Abs 2;2;1970-01-01",
+ "14;029_links;0;10% ermäßigter Steuersatz;2;1970-01-01",
+ "15;029_rechts;0;10% ermäßigter Steuersatz;2;1970-01-01",
+ "16;025_links;0;12% für Weinumsätze durch landwirtschaftliche Betriebe;2;1970-01-01",
+ "17;025_rechts;0;12% für Weinumsätze durch landwirtschaftliche Betriebe;2;1970-01-01",
+ "18;035_links;0;16% für Jungholz und Mittelberg;2;1970-01-01",
+ "19;035_rechts;0;16% für Jungholz und Mittelberg;2;1970-01-01",
+ "20;052_links;0;10% Zusatzsteuer für pauschalierte land- und forstwirtschaftliche Betriebe;2;1970-01-01",
+ "21;052_rechts;0;10% Zusatzsteuer für pauschalierte land- und forstwirtschaftliche Betriebe;2;1970-01-01",
+ "22;038_links;0;8% Zusatzsteuer für pauschalierte land- und forstwirtschaftliche Betriebe;2;1970-01-01",
+ "23;038_rechts;0;8% Zusatzsteuer für pauschalierte land- und forstwirtschaftliche Betriebe;2;1970-01-01",
+ "24;056;0;Steuerschuld gemäß § 11 Abs. 12 und 14, § 16 Abs. 2 sowie gemäß Art. 7 Abs. 4;2;1970-01-01",
+ "25;057;0;Steuerschuld gemäß § 19 Abs. 1 zweiter Satz, § 19 Abs. 1c sowie gemäß Art. 25 Abs. 5;2;1970-01-01",
+ "26;048;0;Steuerschuld gemäÃ\9f § 19 Abs. 1a (Bauleistungen);2;1970-01-01",
+ "27;044;0;Steuerschuld gemäß § 19 Abs. 1b (Sicherungseigentum, Vorbehaltseigentum und Grundstücke im Zwangsversteigerungsverfahren);2;1970-01-01",
+ "28;070;0;Gesamtbetrag der Bemessungsgrundlagen für innergemeinschaftliche Erwerbe;2;1970-01-01",
+ "29;071;0;Davon Steuerfrei gemäß Art. 6 Abs 2;2;1970-01-01",
"30;072_links;0;20% Nominalsteuersatz;2;1970-01-01",
"31;072_rechts;0;20% Nominalsteuersatz;2;1970-01-01",
- "32;073_links;0;10% ermäßigter Steuersatz;2;1970-01-01",
- "33;073_rechts;0;10% ermäßigter Steuersatz;2;1970-01-01",
- "34;075_links;0;16% für Jungholz und Mittelberg;2;1970-01-01",
- "35;075_rechts;0;16% für Jungholz und Mittelberg;2;1970-01-01",
- "36;076;0;Erwerbe gemäß Art. 3 Abs. 8 zweiter Satz, die im Mitgliedstaat des Bestimmungslandes besteuert worden sind;2;1970-01-01",
- "37;077;0;Erwerbe gemäß Art. 3 Abs. 8 zweiter Satz, die gemäß Art. 25 Abs. 2 im Inland als besteuert gelten;2;1970-01-01",
- "38;060;0;Gesamtbetrag der Vorsteuern (ohne die nachstehend gesondert anzuführenden Beträge);2;1970-01-01",
- "39;061;0;Vorsteuern betreffend die entrichtete Einfuhrumsatzsteuer (§12 Abs. 1 Z 2 lit.a);2;1970-01-01",
- "40;083;0;Vorsteuern betreffend die am Abgabenkonto verbuchte Einfuhrumsatzsteuer (§12 Abs. 1 Z 2 lit.b);2;1970-01-01",
+ "32;073_links;0;10% ermäßigter Steuersatz;2;1970-01-01",
+ "33;073_rechts;0;10% ermäßigter Steuersatz;2;1970-01-01",
+ "34;075_links;0;16% für Jungholz und Mittelberg;2;1970-01-01",
+ "35;075_rechts;0;16% für Jungholz und Mittelberg;2;1970-01-01",
+ "36;076;0;Erwerbe gemäß Art. 3 Abs. 8 zweiter Satz, die im Mitgliedstaat des Bestimmungslandes besteuert worden sind;2;1970-01-01",
+ "37;077;0;Erwerbe gemäß Art. 3 Abs. 8 zweiter Satz, die gemäß Art. 25 Abs. 2 im Inland als besteuert gelten;2;1970-01-01",
+ "38;060;0;Gesamtbetrag der Vorsteuern (ohne die nachstehend gesondert anzuführenden Beträge);2;1970-01-01",
+ "39;061;0;Vorsteuern betreffend die entrichtete Einfuhrumsatzsteuer (§12 Abs. 1 Z 2 lit.a);2;1970-01-01",
+ "40;083;0;Vorsteuern betreffend die am Abgabenkonto verbuchte Einfuhrumsatzsteuer (§12 Abs. 1 Z 2 lit.b);2;1970-01-01",
"41;065;0;Vorsteuern aus dem innergemeinschaftlichen Erwerb;2;1970-01-01",
- "42;066;0;Vorsteuern betreffend der Steuerschuld gemäß § 19 Abs. 1c sowie gemäß Art. 25 Abs. 5;2;1970-01-01",
- "43;082;0;Vorsteuern betreffend der Steuerschuld gemäß § 19 Abs. 1a (Bauleistungen);2;1970-01-01",
- "44;087;0;Vorsteuern betreffend die Steuerschuld gemäß § 19 Abs. 1b (Sicherungseigentum, Vorbehaltseigentum und Grundstücke im Zwangsversteigerungsverfahren);2;1970-01-01",
- "45;064;0;Vorsteuern gemäß §12 Abs. 16 und Vorsteuern für innergemeinschaftliche Lieferungen neuer Fahrzeuge von Fahrzeuglieferanten gemäß Art. 2;2;1970-01-01",
- "46;062;0;Davon gemäß § 12 Abs. 3 iVm Abs. 4 und 5;2;1970-01-01",
- "47;063;0;Berichtigung gemäß § 12 Abs. 10 und 11;2;1970-01-01",
- "48;067;0;Berichtigung gemäß § 16;2;1970-01-01",
+ "42;066;0;Vorsteuern betreffend der Steuerschuld gemäß § 19 Abs. 1c sowie gemäß Art. 25 Abs. 5;2;1970-01-01",
+ "43;082;0;Vorsteuern betreffend der Steuerschuld gemäÃ\9f § 19 Abs. 1a (Bauleistungen);2;1970-01-01",
+ "44;087;0;Vorsteuern betreffend die Steuerschuld gemäß § 19 Abs. 1b (Sicherungseigentum, Vorbehaltseigentum und Grundstücke im Zwangsversteigerungsverfahren);2;1970-01-01",
+ "45;064;0;Vorsteuern gemäß §12 Abs. 16 und Vorsteuern für innergemeinschaftliche Lieferungen neuer Fahrzeuge von Fahrzeuglieferanten gemäß Art. 2;2;1970-01-01",
+ "46;062;0;Davon gemäÃ\9f § 12 Abs. 3 iVm Abs. 4 und 5;2;1970-01-01",
+ "47;063;0;Berichtigung gemäÃ\9f § 12 Abs. 10 und 11;2;1970-01-01",
+ "48;067;0;Berichtigung gemäÃ\9f § 16;2;1970-01-01",
"49;090;0;Sonstige Berichtigungen;2;1970-01-01",
"50;095;0;Zahllast/Gutschrift;2;1970-01-01",
],
);
for my $statement ( 0 .. $#copy_statements ) {
- my $query = $iconv->convert($copy_statements[$statement]);
- my $sth = $dbh->prepare($query) || mydberror($query);
+ my $query = $copy_statements[$statement];
+ my $sth = $self->dbh->prepare($query) || $self->db_error($query);
for my $copy_line ( 0 .. $#{$copy_data[$statement]} ) {
#print $copy_data[$statement][$copy_line] . "<br />"
- $sth->execute(split m/;/, $iconv->convert($copy_data[$statement][$copy_line]), -1) || mydberror($query);
+ $sth->execute(split m/;/, $copy_data[$statement][$copy_line], -1) || $self->db_error($query);
} #/
$sth->finish();
}
}
sub do_insert_chart {
+ my ($self) = @_;
my @copy_statements = (
- "INSERT INTO chart VALUES (1, '0000', 'AUFWENDUNGEN FÜR INGANGSETZEN UND ERWEITERN DES BETRIEBES', 'H', 'A', '', '00', NULL, NULL, NULL, NULL, NULL, false, '2006-01-28 18:22:52.276724', NULL, NULL, NULL);",
+ "INSERT INTO chart VALUES (1, '0000', 'AUFWENDUNGEN FÜR INGANGSETZEN UND ERWEITERN DES BETRIEBES', 'H', 'A', '', '00', NULL, NULL, NULL, NULL, NULL, false, '2006-01-28 18:22:52.276724', NULL, NULL, NULL);",
"INSERT INTO chart VALUES (2, '0010', 'Firmenwert', 'A', 'A', 'AP_amount', '015', NULL, NULL, NULL, NULL, NULL, false, '2006-01-28 18:22:52.28365', NULL, NULL, NULL);",
- "INSERT INTO chart VALUES (3, '0100', 'IMMATERIELLE VERMÖGENSGEGENSTÄNDE', 'H', 'A', '', '01', NULL, NULL, NULL, NULL, NULL, false, '2006-01-28 18:22:52.288542', NULL, NULL, NULL);",
+ "INSERT INTO chart VALUES (3, '0100', 'IMMATERIELLE VERMÖGENSGEGENSTÄNDE', 'H', 'A', '', '01', NULL, NULL, NULL, NULL, NULL, false, '2006-01-28 18:22:52.288542', NULL, NULL, NULL);",
"INSERT INTO chart VALUES (4, '0110', 'Rechte', 'A', 'A', 'AP_amount', '011', NULL, NULL, NULL, NULL, NULL, false, '2006-01-28 18:22:52.291937', NULL, NULL, NULL);",
- "INSERT INTO chart VALUES (5, '0200', 'GRUNDSTÜCKE', 'H', 'A', '', '02-03', NULL, NULL, NULL, NULL, NULL, false, '2006-01-28 18:22:52.294929', NULL, NULL, NULL);",
- "INSERT INTO chart VALUES (6, '0210', 'unbebaute Grundstücke', 'A', 'A', 'AP_amount', '020', NULL, NULL, NULL, NULL, NULL, false, '2006-01-28 18:22:52.297958', NULL, NULL, NULL);",
- "INSERT INTO chart VALUES (7, '0220', 'bebaute Grundstücke', 'A', 'A', 'AP_amount', '021', NULL, NULL, NULL, NULL, NULL, false, '2006-01-28 18:22:52.300987', NULL, NULL, NULL);",
- "INSERT INTO chart VALUES (8, '0229', 'kum. Abschreibung bebaute Grundstücke', 'A', 'A', '', '039', NULL, NULL, NULL, NULL, NULL, false, '2006-01-28 18:22:52.304114', NULL, NULL, NULL);",
+ "INSERT INTO chart VALUES (5, '0200', 'GRUNDSTÜCKE', 'H', 'A', '', '02-03', NULL, NULL, NULL, NULL, NULL, false, '2006-01-28 18:22:52.294929', NULL, NULL, NULL);",
+ "INSERT INTO chart VALUES (6, '0210', 'unbebaute Grundstücke', 'A', 'A', 'AP_amount', '020', NULL, NULL, NULL, NULL, NULL, false, '2006-01-28 18:22:52.297958', NULL, NULL, NULL);",
+ "INSERT INTO chart VALUES (7, '0220', 'bebaute Grundstücke', 'A', 'A', 'AP_amount', '021', NULL, NULL, NULL, NULL, NULL, false, '2006-01-28 18:22:52.300987', NULL, NULL, NULL);",
+ "INSERT INTO chart VALUES (8, '0229', 'kum. Abschreibung bebaute Grundstücke', 'A', 'A', '', '039', NULL, NULL, NULL, NULL, NULL, false, '2006-01-28 18:22:52.304114', NULL, NULL, NULL);",
"INSERT INTO chart VALUES (10, '0410', 'Maschinen', 'A', 'A', 'AP_amount', '041', NULL, NULL, NULL, NULL, NULL, false, '2006-01-28 18:22:52.312216', NULL, NULL, NULL);",
"INSERT INTO chart VALUES (11, '0419', 'kum. Abschreibung Maschinen', 'A', 'A', '', '069', NULL, NULL, NULL, NULL, NULL, false, '2006-01-28 18:22:52.316198', NULL, NULL, NULL);",
"INSERT INTO chart VALUES (12, '0500', 'FAHRZEUGE', 'H', 'A', '', '06', NULL, NULL, NULL, NULL, NULL, false, '2006-01-28 18:22:52.319978', NULL, NULL, NULL);",
"INSERT INTO chart VALUES (13, '0510', 'Fahrzeuge', 'A', 'A', 'AP_amount', '063', NULL, NULL, NULL, NULL, NULL, false, '2006-01-28 18:22:52.323002', NULL, NULL, NULL);",
"INSERT INTO chart VALUES (14, '0519', 'kum. Abschreibung Fahrzeuge', 'A', 'A', '', '069', NULL, NULL, NULL, NULL, NULL, false, '2006-01-28 18:22:52.326041', NULL, NULL, NULL);",
- "INSERT INTO chart VALUES (15, '0600', 'BETRIEBS- UND GESCHÄFTSAUSSTATTUNG', 'H', 'A', '', '06', NULL, NULL, NULL, NULL, NULL, false, '2006-01-28 18:22:52.330691', NULL, NULL, NULL);",
- "INSERT INTO chart VALUES (16, '0620', 'Büroeinrichtungen', 'A', 'A', 'AP_amount', '066', NULL, NULL, NULL, NULL, NULL, false, '2006-01-28 18:22:52.33373', NULL, NULL, NULL);",
- "INSERT INTO chart VALUES (17, '0625', 'kum. Abschreibung Betriebs- und Geschäftsausstattung', 'A', 'A', '', '069', NULL, NULL, NULL, NULL, NULL, false, '2006-01-28 18:22:52.336939', NULL, NULL, NULL);",
+ "INSERT INTO chart VALUES (15, '0600', 'BETRIEBS- UND GESCHÄFTSAUSSTATTUNG', 'H', 'A', '', '06', NULL, NULL, NULL, NULL, NULL, false, '2006-01-28 18:22:52.330691', NULL, NULL, NULL);",
+ "INSERT INTO chart VALUES (16, '0620', 'Büroeinrichtungen', 'A', 'A', 'AP_amount', '066', NULL, NULL, NULL, NULL, NULL, false, '2006-01-28 18:22:52.33373', NULL, NULL, NULL);",
+ "INSERT INTO chart VALUES (17, '0625', 'kum. Abschreibung Betriebs- und Geschäftsausstattung', 'A', 'A', '', '069', NULL, NULL, NULL, NULL, NULL, false, '2006-01-28 18:22:52.336939', NULL, NULL, NULL);",
"INSERT INTO chart VALUES (18, '0700', 'GELEISTETE ANZAHLUNGEN', 'H', 'A', '', '07', NULL, NULL, NULL, NULL, NULL, false, '2006-01-28 18:22:52.340614', NULL, NULL, NULL);",
"INSERT INTO chart VALUES (19, '0800', 'FINANZANLAGEN', 'H', 'A', '', '08-09', NULL, NULL, NULL, NULL, NULL, false, '2006-01-28 18:22:52.3436', NULL, NULL, NULL);",
"INSERT INTO chart VALUES (20, '0810', 'Beteiligungen', 'A', 'A', 'AP_amount', '081', NULL, NULL, NULL, NULL, NULL, false, '2006-01-28 18:22:52.346638', NULL, NULL, NULL);",
"INSERT INTO chart VALUES (21, '0820', 'Wertpapiere', 'A', 'A', 'AP_amount', '080', NULL, NULL, NULL, NULL, NULL, false, '2006-01-28 18:22:52.351452', NULL, NULL, NULL);",
"INSERT INTO chart VALUES (22, '1100', 'ROHSTOFFE', 'H', 'A', '', '1', NULL, NULL, NULL, NULL, NULL, false, '2006-01-28 18:22:52.354419', NULL, NULL, NULL);",
- "INSERT INTO chart VALUES (23, '1120', 'Vorräte - Rohstoffe', 'A', 'A', 'IC', '110-119', NULL, NULL, NULL, NULL, NULL, false, '2006-01-28 18:22:52.357447', NULL, NULL, NULL);",
+ "INSERT INTO chart VALUES (23, '1120', 'Vorräte - Rohstoffe', 'A', 'A', 'IC', '110-119', NULL, NULL, NULL, NULL, NULL, false, '2006-01-28 18:22:52.357447', NULL, NULL, NULL);",
"INSERT INTO chart VALUES (24, '1200', 'BEZOGENE TEILE', 'H', 'A', '', '1', NULL, NULL, NULL, NULL, NULL, false, '2006-01-28 18:22:52.360423', NULL, NULL, NULL);",
- "INSERT INTO chart VALUES (25, '1220', 'Vorräte - bezogene Teile', 'A', 'A', 'IC', '120-129', NULL, NULL, NULL, NULL, NULL, false, '2006-01-28 18:22:52.363627', NULL, NULL, NULL);",
+ "INSERT INTO chart VALUES (25, '1220', 'Vorräte - bezogene Teile', 'A', 'A', 'IC', '120-129', NULL, NULL, NULL, NULL, NULL, false, '2006-01-28 18:22:52.363627', NULL, NULL, NULL);",
"INSERT INTO chart VALUES (26, '1300', 'HILFS- UND BETRIEBSSTOFFE', 'H', 'A', '', '1', NULL, NULL, NULL, NULL, NULL, false, '2006-01-28 18:22:52.368083', NULL, NULL, NULL);",
"INSERT INTO chart VALUES (27, '1320', 'Hilfsstoffe', 'A', 'A', 'IC', '130-134', NULL, NULL, NULL, NULL, NULL, false, '2006-01-28 18:22:52.372229', NULL, NULL, NULL);",
"INSERT INTO chart VALUES (28, '1350', 'Betriebssstoffe', 'A', 'A', 'IC', '135-139', NULL, NULL, NULL, NULL, NULL, false, '2006-01-28 18:22:52.375303', NULL, NULL, NULL);",
"INSERT INTO chart VALUES (29, '1400', 'UNFERTIGE ERZEUGNISSE', 'H', 'A', '', '1', NULL, NULL, NULL, NULL, NULL, false, '2006-01-28 18:22:52.378277', NULL, NULL, NULL);",
- "INSERT INTO chart VALUES (30, '1420', 'Vorräte - unfertige Erzeugnisse', 'A', 'A', 'IC', '140-149', NULL, NULL, NULL, NULL, NULL, false, '2006-01-28 18:22:52.381463', NULL, NULL, NULL);",
+ "INSERT INTO chart VALUES (30, '1420', 'Vorräte - unfertige Erzeugnisse', 'A', 'A', 'IC', '140-149', NULL, NULL, NULL, NULL, NULL, false, '2006-01-28 18:22:52.381463', NULL, NULL, NULL);",
"INSERT INTO chart VALUES (31, '1500', 'FERTIGE ERZEUGNISSE', 'H', 'A', '', '1', NULL, NULL, NULL, NULL, NULL, false, '2006-01-28 18:22:52.384434', NULL, NULL, NULL);",
- "INSERT INTO chart VALUES (34, '1540', 'Vorräte - Gruppe C', 'A', 'A', 'IC', '150-159', NULL, NULL, NULL, NULL, NULL, false, '2006-01-28 18:22:52.395426', NULL, NULL, NULL);",
+ "INSERT INTO chart VALUES (34, '1540', 'Vorräte - Gruppe C', 'A', 'A', 'IC', '150-159', NULL, NULL, NULL, NULL, NULL, false, '2006-01-28 18:22:52.395426', NULL, NULL, NULL);",
"INSERT INTO chart VALUES (35, '1600', 'WAREN', 'H', 'A', '', '1', NULL, NULL, NULL, NULL, NULL, false, '2006-01-28 18:22:52.39872', NULL, NULL, NULL);",
"INSERT INTO chart VALUES (36, '1700', 'NOCH NICHT ABGERECHNETE LEISTUNGEN', 'H', 'A', '', '1', NULL, NULL, NULL, NULL, NULL, false, '2006-01-28 18:22:52.401807', NULL, NULL, NULL);",
"INSERT INTO chart VALUES (37, '1800', 'GELEISTETE ANZAHLUNGEN', 'H', 'A', '', '1', NULL, NULL, NULL, NULL, NULL, false, '2006-01-28 18:22:52.404851', NULL, NULL, NULL);",
"INSERT INTO chart VALUES (43, '2320', 'sonstige Forderungen', 'A', 'A', 'AP_amount', '23-24', NULL, NULL, NULL, NULL, NULL, false, '2006-01-28 18:22:52.428868', NULL, NULL, NULL);",
"INSERT INTO chart VALUES (44, '2500', 'FORDERUNGEN AUS ABGABENVERRECHNUNG', 'H', 'A', '', '2', NULL, NULL, NULL, NULL, NULL, false, '2006-01-28 18:22:52.432042', NULL, NULL, NULL);",
"INSERT INTO chart VALUES (46, '2600', 'WERTPAPIERE UND ANTEILE', 'H', 'A', '', '2', NULL, NULL, NULL, NULL, NULL, false, '2006-01-28 18:22:52.438205', NULL, NULL, NULL);",
- "INSERT INTO chart VALUES (47, '2620', 'Wertpapiere Umlaufvermögen', 'A', 'A', 'AP_amount', '26', NULL, NULL, NULL, NULL, NULL, false, '2006-01-28 18:22:52.441382', NULL, NULL, NULL);",
+ "INSERT INTO chart VALUES (47, '2620', 'Wertpapiere Umlaufvermögen', 'A', 'A', 'AP_amount', '26', NULL, NULL, NULL, NULL, NULL, false, '2006-01-28 18:22:52.441382', NULL, NULL, NULL);",
"INSERT INTO chart VALUES (48, '2700', 'KASSABESTAND', 'H', 'A', '', '2', NULL, NULL, NULL, NULL, NULL, false, '2006-01-28 18:22:52.444391', NULL, NULL, NULL);",
"INSERT INTO chart VALUES (50, '2800', 'SCHECKS, GUTHABEN BEI KREDITINSTITUTEN', 'H', 'A', '', '2', NULL, NULL, NULL, NULL, NULL, false, '2006-01-28 18:22:52.45237', NULL, NULL, NULL);",
"INSERT INTO chart VALUES (53, '3100', 'LANGFRISTIGE VERBINDLICHKEITEN', 'H', 'L', '', '3', NULL, NULL, NULL, NULL, NULL, false, '2006-01-28 18:22:52.461985', NULL, NULL, NULL);",
"INSERT INTO chart VALUES (58, '3500', 'VERBINDLICHKEITEN FINANZAMT', 'H', 'L', '', '35', NULL, NULL, NULL, NULL, NULL, false, '2006-01-28 18:22:52.480487', NULL, NULL, NULL);",
"INSERT INTO chart VALUES (105, '7611', 'Reinigungsmaterial', 'A', 'E', 'AP_amount', '', 9, NULL, 11, 3, NULL, false, '2006-01-28 18:22:52.649072', '2006-02-03 15:26:38.591173', NULL, NULL);",
"INSERT INTO chart VALUES (163, '7340', 'Reisekosten', 'A', 'E', 'AP_amount', '', 9, NULL, NULL, 3, NULL, false, '2006-02-03 15:38:11.636188', NULL, NULL, NULL);",
- "INSERT INTO chart VALUES (74, '4600', 'SONSTIGE ERLÖSE', 'H', 'I', '', '4', NULL, NULL, NULL, NULL, NULL, false, '2006-01-28 18:22:52.539718', NULL, NULL, NULL);",
+ "INSERT INTO chart VALUES (74, '4600', 'SONSTIGE ERLÖSE', 'H', 'I', '', '4', NULL, NULL, NULL, NULL, NULL, false, '2006-01-28 18:22:52.539718', NULL, NULL, NULL);",
"INSERT INTO chart VALUES (95, '7120', 'Grundsteuer', 'A', 'E', '', '', 0, NULL, 12, 3, NULL, false, '2006-01-28 18:22:52.612982', '2006-02-03 15:07:18.076256', NULL, NULL);",
"INSERT INTO chart VALUES (94, '7110', 'Ertragssteuern', 'A', 'E', '', '', 0, NULL, 12, 3, NULL, false, '2006-01-28 18:22:52.60961', '2006-02-03 15:07:57.018877', NULL, NULL);",
"INSERT INTO chart VALUES (159, '7130', 'Gewerbl. Sozialversicherung', 'A', 'E', 'AP_amount', '', 0, NULL, 12, 3, NULL, false, '2006-02-03 15:16:10.635938', NULL, NULL, NULL);",
"INSERT INTO chart VALUES (89, '6710', 'freiwilliger Sozialaufwand', 'A', 'E', '', '660-665', NULL, NULL, NULL, NULL, NULL, false, '2006-01-28 18:22:52.592541', NULL, NULL, NULL);",
"INSERT INTO chart VALUES (90, '7000', 'ABSCHREIBUNGEN', 'H', 'E', '', '7', NULL, NULL, NULL, NULL, NULL, false, '2006-01-28 18:22:52.595566', NULL, NULL, NULL);",
"INSERT INTO chart VALUES (91, '7010', 'Abschreibungen', 'A', 'E', '', '700', NULL, NULL, NULL, NULL, NULL, false, '2006-01-28 18:22:52.598657', NULL, NULL, NULL);",
- "INSERT INTO chart VALUES (92, '7020', 'geringwertige Wirtschaftsgüter', 'A', 'E', 'AP_amount', '701-708', NULL, NULL, NULL, NULL, NULL, false, '2006-01-28 18:22:52.601829', NULL, NULL, NULL);",
+ "INSERT INTO chart VALUES (92, '7020', 'geringwertige Wirtschaftsgüter', 'A', 'E', 'AP_amount', '701-708', NULL, NULL, NULL, NULL, NULL, false, '2006-01-28 18:22:52.601829', NULL, NULL, NULL);",
"INSERT INTO chart VALUES (93, '7100', 'SONSTIGE STEUERN', 'H', 'E', '', '71', NULL, NULL, NULL, NULL, NULL, false, '2006-01-28 18:22:52.604871', NULL, NULL, NULL);",
"INSERT INTO chart VALUES (96, '7200', 'INSTANDHALTUNGSAUFWAND', 'H', 'E', '', '7', NULL, NULL, NULL, NULL, NULL, false, '2006-01-28 18:22:52.6171', NULL, NULL, NULL);",
"INSERT INTO chart VALUES (98, '7300', 'TRANSPORTKOSTEN', 'H', 'L', '', '73', NULL, NULL, NULL, NULL, NULL, false, '2006-01-28 18:22:52.623721', NULL, NULL, NULL);",
"INSERT INTO chart VALUES (100, '7400', 'MIET-,PACHT-,LEASING-, LIZENZAUFWAND', 'H', 'E', '', '74', NULL, NULL, NULL, NULL, NULL, false, '2006-01-28 18:22:52.631869', NULL, NULL, NULL);",
"INSERT INTO chart VALUES (113, '7710', 'Sachversicherung', 'A', 'E', 'AP_amount', '', 0, NULL, 13, NULL, NULL, false, '2006-01-28 18:22:52.677258', '2006-02-03 15:19:30.793109', NULL, NULL);",
"INSERT INTO chart VALUES (103, '7600', 'VERWALTUNGSKOSTEN', 'H', 'E', '', '76', NULL, NULL, NULL, NULL, NULL, false, '2006-01-28 18:22:52.641023', NULL, NULL, NULL);",
- "INSERT INTO chart VALUES (161, '7780', 'Beiträge zur Berufsvertretung', 'A', 'E', 'AP_amount', '', 0, NULL, NULL, 3, NULL, false, '2006-02-03 15:33:11.055578', NULL, NULL, NULL);",
+ "INSERT INTO chart VALUES (161, '7780', 'Beiträge zur Berufsvertretung', 'A', 'E', 'AP_amount', '', 0, NULL, NULL, 3, NULL, false, '2006-02-03 15:33:11.055578', NULL, NULL, NULL);",
"INSERT INTO chart VALUES (102, '7420', 'Betriebsk. und ant. AfA Garage + Werkst.', 'A', 'E', 'AP_amount', '', 0, NULL, NULL, 3, NULL, false, '2006-01-28 18:22:52.637918', '2006-02-03 15:41:13.126408', NULL, NULL);",
- "INSERT INTO chart VALUES (112, '7700', 'VERSICHERUNGEN UND ÜBRIGE AUFWÄNDUNGEN', 'H', 'E', '', '', 0, NULL, NULL, NULL, NULL, false, '2006-01-28 18:22:52.674186', '2006-02-03 15:44:43.301845', NULL, NULL);",
- "INSERT INTO chart VALUES (114, '8000', 'FINANZERTRÄGE UND FINANZAUFWÄNDUNGEN', 'H', 'L', '', '', 0, NULL, NULL, NULL, NULL, false, '2006-01-28 18:22:52.680743', '2006-02-03 15:45:08.299546', NULL, NULL);",
- "INSERT INTO chart VALUES (33, '1530', 'Vorräte Gruppe B', 'A', 'A', 'IC', '', 0, NULL, NULL, NULL, NULL, false, '2006-01-28 18:22:52.392343', '2006-02-03 16:25:53.167131', NULL, NULL);",
+ "INSERT INTO chart VALUES (112, '7700', 'VERSICHERUNGEN UND ÜBRIGE AUFWÄNDUNGEN', 'H', 'E', '', '', 0, NULL, NULL, NULL, NULL, false, '2006-01-28 18:22:52.674186', '2006-02-03 15:44:43.301845', NULL, NULL);",
+ "INSERT INTO chart VALUES (114, '8000', 'FINANZERTRÄGE UND FINANZAUFWÄNDUNGEN', 'H', 'L', '', '', 0, NULL, NULL, NULL, NULL, false, '2006-01-28 18:22:52.680743', '2006-02-03 15:45:08.299546', NULL, NULL);",
+ "INSERT INTO chart VALUES (33, '1530', 'Vorräte Gruppe B', 'A', 'A', 'IC', '', 0, NULL, NULL, NULL, NULL, false, '2006-01-28 18:22:52.392343', '2006-02-03 16:25:53.167131', NULL, NULL);",
"INSERT INTO chart VALUES (120, '9020', 'nicht einbezahltes Kapital', 'A', 'Q', '', '919', NULL, NULL, NULL, NULL, NULL, false, '2006-01-28 18:22:52.700926', NULL, NULL, NULL);",
- "INSERT INTO chart VALUES (121, '9200', 'KAPITALRÜCKLAGEN', 'H', 'Q', '', '9', NULL, NULL, NULL, NULL, NULL, false, '2006-01-28 18:22:52.703925', NULL, NULL, NULL);",
- "INSERT INTO chart VALUES (122, '9210', 'freie Rücklage', 'A', 'Q', '', '920-929', NULL, NULL, NULL, NULL, NULL, false, '2006-01-28 18:22:52.708819', NULL, NULL, NULL);",
+ "INSERT INTO chart VALUES (121, '9200', 'KAPITALRÜCKLAGEN', 'H', 'Q', '', '9', NULL, NULL, NULL, NULL, NULL, false, '2006-01-28 18:22:52.703925', NULL, NULL, NULL);",
+ "INSERT INTO chart VALUES (122, '9210', 'freie Rücklage', 'A', 'Q', '', '920-929', NULL, NULL, NULL, NULL, NULL, false, '2006-01-28 18:22:52.708819', NULL, NULL, NULL);",
"INSERT INTO chart VALUES (123, '9300', 'GEWINN', 'H', 'Q', '', '939', NULL, NULL, NULL, NULL, NULL, false, '2006-01-28 18:22:52.712247', NULL, NULL, NULL);",
"INSERT INTO chart VALUES (124, '9310', 'Gewinnvortrag Vorjahr', 'A', 'Q', '', '980', NULL, NULL, NULL, NULL, NULL, false, '2006-01-28 18:22:52.716177', NULL, NULL, NULL);",
"INSERT INTO chart VALUES (125, '9320', 'Jahresgewinn', 'A', 'Q', '', '985', NULL, NULL, NULL, NULL, NULL, false, '2006-01-28 18:22:52.719991', NULL, NULL, NULL);",
- "INSERT INTO chart VALUES (126, '9400', 'RÜCKSTELLUNGEN', 'H', 'L', '', '3', NULL, NULL, NULL, NULL, NULL, false, '2006-01-28 18:22:52.723021', NULL, NULL, NULL);",
- "INSERT INTO chart VALUES (127, '9420', 'Abfertigungsrückstellung', 'A', 'L', '', '300', NULL, NULL, NULL, NULL, NULL, false, '2006-01-28 18:22:52.726006', NULL, NULL, NULL);",
- "INSERT INTO chart VALUES (128, '9430', 'Urlaubsrückstellung', 'A', 'L', '', '304-309', NULL, NULL, NULL, NULL, NULL, false, '2006-01-28 18:22:52.730698', NULL, NULL, NULL);",
+ "INSERT INTO chart VALUES (126, '9400', 'RÜCKSTELLUNGEN', 'H', 'L', '', '3', NULL, NULL, NULL, NULL, NULL, false, '2006-01-28 18:22:52.723021', NULL, NULL, NULL);",
+ "INSERT INTO chart VALUES (127, '9420', 'Abfertigungsrückstellung', 'A', 'L', '', '300', NULL, NULL, NULL, NULL, NULL, false, '2006-01-28 18:22:52.726006', NULL, NULL, NULL);",
+ "INSERT INTO chart VALUES (128, '9430', 'Urlaubsrückstellung', 'A', 'L', '', '304-309', NULL, NULL, NULL, NULL, NULL, false, '2006-01-28 18:22:52.730698', NULL, NULL, NULL);",
"INSERT INTO chart VALUES (129, '9700', 'EINLAGEN STILLER GESELLSCHAFTER', 'H', 'Q', '', '9', NULL, NULL, NULL, NULL, NULL, false, '2006-01-28 18:22:52.73381', NULL, NULL, NULL);",
"INSERT INTO chart VALUES (71, '4300', 'UMSATZ DIENSTLEISTUNGEN', 'H', 'I', '', '', 0, NULL, NULL, NULL, NULL, false, '2006-01-28 18:22:52.529746', '2006-01-28 18:34:28.843136', NULL, NULL);",
- "INSERT INTO chart VALUES (9, '0300', 'BETRIEBS- UND GESCHÄFTSGEBÄUDE', 'H', 'A', '', '', 0, NULL, NULL, NULL, NULL, false, '2006-01-28 18:22:52.308885', '2006-02-02 09:31:17.849895', NULL, NULL);",
+ "INSERT INTO chart VALUES (9, '0300', 'BETRIEBS- UND GESCHÄFTSGEBÄUDE', 'H', 'A', '', '', 0, NULL, NULL, NULL, NULL, false, '2006-01-28 18:22:52.308885', '2006-02-02 09:31:17.849895', NULL, NULL);",
"INSERT INTO chart VALUES (45, '2530', 'sonstige Forderungen aus Abgebenverrechnung', 'A', 'A', 'AP_amount', '', 0, NULL, NULL, NULL, NULL, false, '2006-01-28 18:22:52.435243', '2006-02-02 09:59:42.729713', NULL, NULL);",
- "INSERT INTO chart VALUES (67, '4000', 'BETRIEBLICHE ERTRÄGE', 'H', 'I', '', '', 0, NULL, NULL, NULL, NULL, false, '2006-01-28 18:22:52.513926', '2006-02-02 10:05:21.278993', NULL, NULL);",
- "INSERT INTO chart VALUES (75, '4630', 'Erlöse aus Abgang vom Anlagevermögen', 'A', 'I', 'AR_amount:IC_income', '', 0, NULL, NULL, NULL, NULL, false, '2006-01-28 18:22:52.542817', '2006-02-02 10:09:41.959462', NULL, NULL);",
- "INSERT INTO chart VALUES (131, '4450', 'Erlösschmälerung durch Skontoaufwand', 'A', 'I', 'AR_amount', '', 0, NULL, NULL, NULL, NULL, false, '2006-01-28 18:22:52.740526', '2006-02-02 10:20:51.822294', NULL, NULL);",
- "INSERT INTO chart VALUES (144, '4640', 'Erträge aus Abgang vom Anlagevermögen', 'A', 'I', 'AR_amount:IC_income', '', 0, NULL, NULL, NULL, NULL, false, '2006-02-02 10:24:49.118289', '2006-02-02 10:25:34.716838', NULL, NULL);",
- "INSERT INTO chart VALUES (118, '9000', 'KAPITAL, UNVERSTEUERTE RÜCKLAGEN, ABSCHLUSS- UND EVIDENZKONTEN', 'H', 'Q', '', '', 0, NULL, NULL, NULL, NULL, false, '2006-01-28 18:22:52.694841', '2006-02-02 10:28:27.424046', NULL, NULL);",
+ "INSERT INTO chart VALUES (67, '4000', 'BETRIEBLICHE ERTRÄGE', 'H', 'I', '', '', 0, NULL, NULL, NULL, NULL, false, '2006-01-28 18:22:52.513926', '2006-02-02 10:05:21.278993', NULL, NULL);",
+ "INSERT INTO chart VALUES (75, '4630', 'Erlöse aus Abgang vom Anlagevermögen', 'A', 'I', 'AR_amount:IC_income', '', 0, NULL, NULL, NULL, NULL, false, '2006-01-28 18:22:52.542817', '2006-02-02 10:09:41.959462', NULL, NULL);",
+ "INSERT INTO chart VALUES (131, '4450', 'Erlösschmälerung durch Skontoaufwand', 'A', 'I', 'AR_amount', '', 0, NULL, NULL, NULL, NULL, false, '2006-01-28 18:22:52.740526', '2006-02-02 10:20:51.822294', NULL, NULL);",
+ "INSERT INTO chart VALUES (144, '4640', 'Erträge aus Abgang vom Anlagevermögen', 'A', 'I', 'AR_amount:IC_income', '', 0, NULL, NULL, NULL, NULL, false, '2006-02-02 10:24:49.118289', '2006-02-02 10:25:34.716838', NULL, NULL);",
+ "INSERT INTO chart VALUES (118, '9000', 'KAPITAL, UNVERSTEUERTE RÜCKLAGEN, ABSCHLUSS- UND EVIDENZKONTEN', 'H', 'Q', '', '', 0, NULL, NULL, NULL, NULL, false, '2006-01-28 18:22:52.694841', '2006-02-02 10:28:27.424046', NULL, NULL);",
"INSERT INTO chart VALUES (147, '9410', 'Privatentnahme', 'A', 'Q', '', '', 0, NULL, NULL, NULL, NULL, false, '2006-02-02 11:52:04.383364', NULL, NULL, NULL);",
"INSERT INTO chart VALUES (76, '5000', 'MATERIALAUFWAND', 'H', 'E', '', '', 0, NULL, NULL, NULL, NULL, false, '2006-01-28 18:22:52.545768', '2006-02-02 12:02:53.065559', NULL, NULL);",
"INSERT INTO chart VALUES (160, '7140', 'Fremdenverkehrsabgabe', 'A', 'E', 'AP_amount', '', 0, NULL, 12, 3, NULL, false, '2006-02-03 15:16:52.380825', NULL, NULL, NULL);",
"INSERT INTO chart VALUES (99, '7310', 'Frachtaufwand durch Dritte', 'A', 'E', 'AP_amount:IC_expense', '', 9, NULL, NULL, 3, NULL, false, '2006-01-28 18:22:52.628717', '2006-02-03 15:22:49.082217', NULL, NULL);",
"INSERT INTO chart VALUES (152, '7320', 'KFZ-Aufwand', 'A', 'E', 'AP_amount:IC_expense', '', 9, NULL, NULL, 3, NULL, false, '2006-02-02 12:22:18.511562', '2006-02-03 15:23:31.584235', NULL, NULL);",
"INSERT INTO chart VALUES (80, '5600', 'VERBRAUCH BRENN- UND TREIBSTOFFE, ENERGIE UND WASSER', 'H', 'I', '', '', 0, NULL, NULL, NULL, NULL, false, '2006-01-28 18:22:52.56006', '2006-02-02 12:17:24.198896', NULL, NULL);",
- "INSERT INTO chart VALUES (109, '7390', 'Porto und Postgebühren', 'A', 'E', 'AP_amount:IC_expense', '', 0, NULL, NULL, NULL, NULL, false, '2006-01-28 18:22:52.661848', '2006-02-02 12:28:47.456197', NULL, NULL);",
+ "INSERT INTO chart VALUES (109, '7390', 'Porto und Postgebühren', 'A', 'E', 'AP_amount:IC_expense', '', 0, NULL, NULL, NULL, NULL, false, '2006-01-28 18:22:52.661848', '2006-02-02 12:28:47.456197', NULL, NULL);",
"INSERT INTO chart VALUES (101, '7410', 'Miete und Pachtaufwand', 'A', 'E', 'AP_amount', '', 0, NULL, NULL, NULL, NULL, false, '2006-01-28 18:22:52.634888', '2006-02-02 12:29:27.184902', NULL, NULL);",
"INSERT INTO chart VALUES (107, '7620', 'Zeitungen und Zeitschriften', 'A', 'E', '', '', 0, NULL, NULL, NULL, NULL, false, '2006-01-28 18:22:52.655683', '2006-02-02 12:32:43.287819', NULL, NULL);",
"INSERT INTO chart VALUES (106, '7670', 'Werbung und Marketing', 'A', 'E', 'AP_amount', '', 0, NULL, NULL, NULL, NULL, false, '2006-01-28 18:22:52.652584', '2006-02-02 12:33:37.934111', NULL, NULL);",
- "INSERT INTO chart VALUES (110, '7680', 'Repräsentationsaufwand', 'A', 'E', '', '', 0, NULL, NULL, NULL, NULL, false, '2006-01-28 18:22:52.665034', '2006-02-02 12:35:16.950252', NULL, NULL);",
+ "INSERT INTO chart VALUES (110, '7680', 'Repräsentationsaufwand', 'A', 'E', '', '', 0, NULL, NULL, NULL, NULL, false, '2006-01-28 18:22:52.665034', '2006-02-02 12:35:16.950252', NULL, NULL);",
"INSERT INTO chart VALUES (111, '7750', 'Rechtsberatung', 'A', 'E', 'AP_amount', '', 0, NULL, NULL, NULL, NULL, false, '2006-01-28 18:22:52.671109', '2006-02-02 12:36:56.116865', NULL, NULL);",
"INSERT INTO chart VALUES (153, '7755', 'Steuerberatung', 'A', 'E', 'AP_amount', '', 0, NULL, NULL, NULL, NULL, false, '2006-02-02 12:37:35.558667', NULL, NULL, NULL);",
- "INSERT INTO chart VALUES (115, '8280', 'Bankzinsen und Gebühren', 'A', 'E', '', '', 0, NULL, NULL, NULL, NULL, false, '2006-01-28 18:22:52.683783', '2006-02-02 12:41:44.274229', NULL, NULL);",
- "INSERT INTO chart VALUES (117, '8110', 'Erträge aus Zinsen', 'A', 'I', '', '', 0, NULL, NULL, NULL, NULL, false, '2006-01-28 18:22:52.691802', '2006-02-02 12:42:41.520779', NULL, NULL);",
- "INSERT INTO chart VALUES (132, '8050', 'Erträge aus Wertpapieren', 'A', 'E', '', '', 0, NULL, NULL, NULL, NULL, false, '2006-01-28 18:22:52.743602', '2006-02-02 12:44:29.033245', NULL, NULL);",
- "INSERT INTO chart VALUES (104, '7610', 'Büromaterial', 'A', 'E', 'AP_amount', '', 9, NULL, 11, 3, NULL, false, '2006-01-28 18:22:52.644151', '2006-02-03 15:25:38.53287', NULL, NULL);",
- "INSERT INTO chart VALUES (116, '8010', 'Erträge aus Beteiligungen', 'A', 'I', '', '', 0, NULL, NULL, NULL, NULL, false, '2006-01-28 18:22:52.688643', '2006-02-02 12:47:19.930787', NULL, NULL);",
- "INSERT INTO chart VALUES (119, '9010', 'Kapital, Geschäftsanteile', 'A', 'Q', '', '', 0, NULL, NULL, NULL, NULL, false, '2006-01-28 18:22:52.69788', '2006-02-02 12:48:41.514201', NULL, NULL);",
+ "INSERT INTO chart VALUES (115, '8280', 'Bankzinsen und Gebühren', 'A', 'E', '', '', 0, NULL, NULL, NULL, NULL, false, '2006-01-28 18:22:52.683783', '2006-02-02 12:41:44.274229', NULL, NULL);",
+ "INSERT INTO chart VALUES (117, '8110', 'Erträge aus Zinsen', 'A', 'I', '', '', 0, NULL, NULL, NULL, NULL, false, '2006-01-28 18:22:52.691802', '2006-02-02 12:42:41.520779', NULL, NULL);",
+ "INSERT INTO chart VALUES (132, '8050', 'Erträge aus Wertpapieren', 'A', 'E', '', '', 0, NULL, NULL, NULL, NULL, false, '2006-01-28 18:22:52.743602', '2006-02-02 12:44:29.033245', NULL, NULL);",
+ "INSERT INTO chart VALUES (104, '7610', 'Büromaterial', 'A', 'E', 'AP_amount', '', 9, NULL, 11, 3, NULL, false, '2006-01-28 18:22:52.644151', '2006-02-03 15:25:38.53287', NULL, NULL);",
+ "INSERT INTO chart VALUES (116, '8010', 'Erträge aus Beteiligungen', 'A', 'I', '', '', 0, NULL, NULL, NULL, NULL, false, '2006-01-28 18:22:52.688643', '2006-02-02 12:47:19.930787', NULL, NULL);",
+ "INSERT INTO chart VALUES (119, '9010', 'Kapital, Geschäftsanteile', 'A', 'Q', '', '', 0, NULL, NULL, NULL, NULL, false, '2006-01-28 18:22:52.69788', '2006-02-02 12:48:41.514201', NULL, NULL);",
"INSERT INTO chart VALUES (108, '7380', 'Telefonkosten, Internetkosten', 'A', 'E', 'AP_amount', '', 9, NULL, 11, 3, NULL, false, '2006-01-28 18:22:52.658721', '2006-02-03 15:24:27.553821', NULL, NULL);",
- "INSERT INTO chart VALUES (32, '1520', 'Vorräte Gruppe A', 'A', 'A', 'IC', '', 0, NULL, NULL, NULL, NULL, false, '2006-01-28 18:22:52.389168', '2006-02-03 16:26:08.72507', NULL, NULL);",
+ "INSERT INTO chart VALUES (32, '1520', 'Vorräte Gruppe A', 'A', 'A', 'IC', '', 0, NULL, NULL, NULL, NULL, false, '2006-01-28 18:22:52.389168', '2006-02-03 16:26:08.72507', NULL, NULL);",
"INSERT INTO chart VALUES (52, '2820', 'Bankguthaben', 'A', 'A', 'AR_paid:AP_paid', '', 0, NULL, NULL, 1, NULL, false, '2006-01-28 18:22:52.458922', '2006-02-04 15:00:18.424069', NULL, NULL);",
- "INSERT INTO chart VALUES (59, '3550', 'Finanzamt Verrechnung Körperschaftssteuer', 'A', 'L', '', '', 0, NULL, NULL, NULL, NULL, false, '2006-01-28 18:22:52.483655', '2006-02-08 20:09:47.697565', NULL, NULL);",
+ "INSERT INTO chart VALUES (59, '3550', 'Finanzamt Verrechnung Körperschaftssteuer', 'A', 'L', '', '', 0, NULL, NULL, NULL, NULL, false, '2006-01-28 18:22:52.483655', '2006-02-08 20:09:47.697565', NULL, NULL);",
"INSERT INTO chart VALUES (60, '3540', 'Finanzamt Verrechnung Umsatzsteuer', 'A', 'L', '', '', 0, NULL, NULL, NULL, NULL, false, '2006-01-28 18:22:52.48865', '2006-02-08 20:15:23.622013', NULL, NULL);",
"INSERT INTO chart VALUES (78, '5030', 'Warengruppe 1 10 %', 'A', 'E', 'AP_amount:IC_cogs', '', 7, NULL, 4, 2, NULL, false, '2006-01-28 18:22:52.553586', '2006-02-08 20:31:31.539794', NULL, NULL);",
"INSERT INTO chart VALUES (79, '5040', 'Warengruppe 2 20%', 'A', 'E', 'AP_amount:IC_cogs', '', 9, NULL, 4, 2, NULL, false, '2006-01-28 18:22:52.55679', '2006-02-03 14:44:38.100283', NULL, NULL);",
"INSERT INTO chart VALUES (155, '5210', 'Sonst. Verbrauchsmaterial', 'A', 'E', 'AP_amount', '', 9, NULL, 4, 3, NULL, false, '2006-02-03 14:49:06.01478', '2006-02-03 14:54:51.813269', NULL, NULL);",
"INSERT INTO chart VALUES (146, '9850', 'Schlussbilanz', 'A', 'L', '', '', 0, NULL, NULL, NULL, NULL, false, '2006-02-02 10:36:45.059659', '2006-02-02 10:38:05.014595', NULL, NULL);",
- "INSERT INTO chart VALUES (150, '5640', 'Verbrauch von sonstigen Ölen und Schmierstoffen', 'A', 'E', 'AP_amount', '', 9, NULL, 4, 1, 19, false, '2006-02-02 12:07:52.512006', '2006-02-03 15:01:09.867763', NULL, NULL);",
- "INSERT INTO chart VALUES (130, '9810', 'Eröffnungsbilanz', 'A', 'L', '', '', 0, NULL, NULL, NULL, NULL, false, '2006-01-28 18:22:52.736825', '2006-02-02 10:37:49.001565', NULL, NULL);",
+ "INSERT INTO chart VALUES (150, '5640', 'Verbrauch von sonstigen Ölen und Schmierstoffen', 'A', 'E', 'AP_amount', '', 9, NULL, 4, 1, 19, false, '2006-02-02 12:07:52.512006', '2006-02-03 15:01:09.867763', NULL, NULL);",
+ "INSERT INTO chart VALUES (130, '9810', 'Eröffnungsbilanz', 'A', 'L', '', '', 0, NULL, NULL, NULL, NULL, false, '2006-01-28 18:22:52.736825', '2006-02-02 10:37:49.001565', NULL, NULL);",
"INSERT INTO chart VALUES (164, '9800', 'BILANZKONTEN', 'H', 'L', '', '', 0, NULL, NULL, NULL, NULL, false, '2006-03-06 22:23:47.795675', NULL, NULL, NULL);",
"INSERT INTO chart VALUES (148, '5620', 'Verbrauch von Treibstoffen (Diesel)', 'A', 'E', 'AP_amount', '', 9, NULL, 4, 2, 17, false, '2006-02-02 11:59:26.297394', '2006-02-03 15:00:02.362976', NULL, NULL);",
- "INSERT INTO chart VALUES (149, '5630', 'Verbrauch von Treib- und Schmierstoffen für Motorsägen', 'A', 'E', 'AP_amount', '', 9, NULL, 4, 1, 19, false, '2006-02-02 12:01:05.969406', '2006-02-03 15:00:30.512596', NULL, NULL);",
- "INSERT INTO chart VALUES (158, '5650', 'gasförmige Brennstoffe', 'A', 'E', 'AP_amount', '', 9, NULL, 4, 2, 12, false, '2006-02-03 15:02:36.649746', NULL, NULL, NULL);",
+ "INSERT INTO chart VALUES (149, '5630', 'Verbrauch von Treib- und Schmierstoffen für Motorsägen', 'A', 'E', 'AP_amount', '', 9, NULL, 4, 1, 19, false, '2006-02-02 12:01:05.969406', '2006-02-03 15:00:30.512596', NULL, NULL);",
+ "INSERT INTO chart VALUES (158, '5650', 'gasförmige Brennstoffe', 'A', 'E', 'AP_amount', '', 9, NULL, 4, 2, 12, false, '2006-02-03 15:02:36.649746', NULL, NULL, NULL);",
"INSERT INTO chart VALUES (156, '5710', 'Warenbezugskosten', 'A', 'E', 'AP_amount', '', 9, NULL, 4, 2, 8, false, '2006-02-03 14:56:21.395879', NULL, NULL, NULL);",
"INSERT INTO chart VALUES (157, '5750', 'Fremdarbeit', 'A', 'E', 'AP_amount', '', 9, NULL, 4, 2, NULL, false, '2006-02-03 14:58:23.887944', NULL, NULL, NULL);",
"INSERT INTO chart VALUES (154, '5310', 'Arbeitskleidung', 'A', 'E', 'AP_amount', '', 9, NULL, 4, 1, NULL, false, '2006-02-03 14:48:10.349391', '2006-02-03 16:23:46.154559', NULL, NULL);",
"INSERT INTO chart VALUES (151, '5510', 'Verbrauchswerkzeug', 'A', 'E', 'AP_amount', '', 9, NULL, 4, 2, NULL, false, '2006-02-02 12:19:18.193535', '2006-02-03 14:51:29.573924', NULL, NULL);",
"INSERT INTO chart VALUES (81, '5610', 'Energie (Strom und Wasser)', 'A', 'E', 'AP_amount', '', 9, NULL, 4, 2, NULL, false, '2006-01-28 18:22:52.563249', '2006-02-03 14:59:32.292173', NULL, NULL);",
"INSERT INTO chart VALUES (97, '7210', 'Reparatur und Instandhaltung', 'A', 'E', 'AP_amount', '', 9, NULL, NULL, NULL, NULL, false, '2006-01-28 18:22:52.620315', '2006-02-03 15:14:08.186799', NULL, NULL);",
- "INSERT INTO chart VALUES (72, '4320', 'Erlöse Beratung', 'A', 'I', 'AR_amount:IC_sale:IC_income', '', 3, 51, 1, 1, 2, false, '2006-01-28 18:22:52.533226', '2006-02-04 23:05:45.241847', NULL, NULL);",
- "INSERT INTO chart VALUES (73, '4330', 'Erlöse Programmierung', 'A', 'I', 'AR_amount:IC_sale:IC_income', '', 3, 51, 1, 1, 1, false, '2006-01-28 18:22:52.536409', '2006-02-04 23:06:03.959353', NULL, NULL);",
- "INSERT INTO chart VALUES (69, '4030', 'Erlöse - Softwareverkauf', 'A', 'I', 'AR_amount:IC_sale', '', 2, 86, 1, 1, 1, false, '2006-01-28 18:22:52.521819', '2006-02-02 10:06:58.91888', NULL, NULL);",
- "INSERT INTO chart VALUES (70, '4040', 'Erlöse - Ersatzteilverkauf', 'A', 'I', 'AR_amount:IC_sale', '', 3, 51, 1, 1, 1, false, '2006-01-28 18:22:52.524987', '2006-02-02 10:07:34.327738', NULL, NULL);",
+ "INSERT INTO chart VALUES (72, '4320', 'Erlöse Beratung', 'A', 'I', 'AR_amount:IC_sale:IC_income', '', 3, 51, 1, 1, 2, false, '2006-01-28 18:22:52.533226', '2006-02-04 23:05:45.241847', NULL, NULL);",
+ "INSERT INTO chart VALUES (73, '4330', 'Erlöse Programmierung', 'A', 'I', 'AR_amount:IC_sale:IC_income', '', 3, 51, 1, 1, 1, false, '2006-01-28 18:22:52.536409', '2006-02-04 23:06:03.959353', NULL, NULL);",
+ "INSERT INTO chart VALUES (69, '4030', 'Erlöse - Softwareverkauf', 'A', 'I', 'AR_amount:IC_sale', '', 2, 86, 1, 1, 1, false, '2006-01-28 18:22:52.521819', '2006-02-02 10:06:58.91888', NULL, NULL);",
+ "INSERT INTO chart VALUES (70, '4040', 'Erlöse - Ersatzteilverkauf', 'A', 'I', 'AR_amount:IC_sale', '', 3, 51, 1, 1, 1, false, '2006-01-28 18:22:52.524987', '2006-02-02 10:07:34.327738', NULL, NULL);",
"INSERT INTO chart VALUES (57, '3310', 'Verbindlichkeiten aus Lieferungen & Leistungen', 'A', 'L', 'AP', '', 0, NULL, NULL, 1, NULL, false, '2006-01-28 18:22:52.477485', '2006-02-02 18:12:21.634302', NULL, NULL);",
"INSERT INTO chart VALUES (51, '2810', 'Schecks', 'A', 'A', '', '', 0, NULL, NULL, NULL, NULL, false, '2006-01-28 18:22:52.455807', NULL, NULL, NULL);",
- "INSERT INTO chart VALUES (55, '3120', 'Kredite von Eigentümern', 'A', 'L', '', '', 0, NULL, NULL, NULL, NULL, false, '2006-01-28 18:22:52.471098', NULL, NULL, NULL);",
+ "INSERT INTO chart VALUES (55, '3120', 'Kredite von Eigentümern', 'A', 'L', '', '', 0, NULL, NULL, NULL, NULL, false, '2006-01-28 18:22:52.471098', NULL, NULL, NULL);",
"INSERT INTO chart VALUES (49, '2710', 'Kassa', 'A', 'A', 'AR_paid', '', 0, NULL, NULL, 1, NULL, false, '2006-01-28 18:22:52.449148', '2006-02-04 14:59:14.410329', NULL, NULL);",
"INSERT INTO chart VALUES (77, '5020', 'Warengruppe 0', 'A', 'E', 'IC:IC_cogs:AP_amount', '', 7, NULL, NULL, NULL, 8, false, '2006-01-28 18:22:52.550381', '2006-02-08 20:30:42.871241', NULL, NULL);",
- "INSERT INTO chart VALUES (68, '4020', 'Erlöse - Hardwareverkauf', 'A', 'I', 'AR_amount:IC_sale', '', 2, 86, 1, 1, 1, false, '2006-01-28 18:22:52.51796', '2006-02-04 23:05:12.810823', NULL, NULL);",
+ "INSERT INTO chart VALUES (68, '4020', 'Erlöse - Hardwareverkauf', 'A', 'I', 'AR_amount:IC_sale', '', 2, 86, 1, 1, 1, false, '2006-01-28 18:22:52.51796', '2006-02-04 23:05:12.810823', NULL, NULL);",
"INSERT INTO chart VALUES (40, '2010', 'Forderungen Lieferung & Leistung', 'A', 'A', 'AR', '200-207', NULL, NULL, NULL, NULL, NULL, false, '2006-01-28 18:22:52.41697', NULL, NULL, NULL);",
"INSERT INTO chart VALUES (65, '2510', 'Vorsteuer 10%', 'A', 'E', 'AR_tax:AP_tax:IC_taxpart:IC_taxservice', NULL, 0, 66, NULL, NULL, NULL, false, '2006-01-28 18:22:52.505337', '2006-02-02 17:38:40.373624', NULL, NULL);",
"INSERT INTO chart VALUES (64, '2512', 'Vorsteuer 12%', 'A', 'E', 'AR_tax:AP_tax:IC_taxpart:IC_taxservice', NULL, 0, 66, NULL, NULL, NULL, false, '2006-01-28 18:22:52.502023', '2006-02-08 20:14:19.543049', NULL, NULL);",
"insert into chart (accno,description,charttype,gifi_accno,category,link) values ('0400','MASCHINEN','H','04-05','A','');",
"insert into chart (accno,description,charttype,gifi_accno,category,link) values ('7411','Lizenzen','A','748-749','E','AP_amount');",
"insert into chart (accno,description,charttype,gifi_accno,category,link) values ('7631','Internetkosten','A','738-739','E','AP_amount:IC_expense');",
- "insert into chart (accno,description,charttype,gifi_accno,category,link) values ('7632','Reise- und Repräsentationsaufwand','A','734-735','E','');",
- "insert into chart (accno,description,charttype,gifi_accno,category,link) values ('7634','Registrierungsgebühren','A','748-749','E','AP_amount');",
- "insert into chart (accno,description,charttype,gifi_accno,category,link) values ('8020','Bankzinsen und Gebühren','A','80-83','E','');",
+ "insert into chart (accno,description,charttype,gifi_accno,category,link) values ('7632','Reise- und Repräsentationsaufwand','A','734-735','E','');",
+ "insert into chart (accno,description,charttype,gifi_accno,category,link) values ('7634','Registrierungsgebühren','A','748-749','E','AP_amount');",
+ "insert into chart (accno,description,charttype,gifi_accno,category,link) values ('8020','Bankzinsen und Gebühren','A','80-83','E','');",
);
for my $statement ( 0 .. $#copy_statements ) {
- my $query = $iconv->convert($copy_statements[$statement]);
+ my $query = $copy_statements[$statement];
#print $query . "<br />"; # Diagnose only!
- do_query($query, 0);
+ $self->db_query($query, 0);
}
return 1;
}
sub do_insert_tax {
+ my ($self) = @_;
my @copy_statements = (
"INSERT INTO tax (chart_id, taxnumber, taxkey, taxdescription, itime, mtime, rate, id) VALUES (65, '2510', 7, 'Vorsteuer 10%', '2006-01-30 11:08:23.332857', '2006-02-08 20:28:09.63567', 0.10000, 173);",
);
for my $statement ( 0 .. $#copy_statements ) {
- my $query = $iconv->convert($copy_statements[$statement]);
+ my $query = $copy_statements[$statement];
#print $query . "<br />"; # Diagnose only!
- do_query($query, 0);
+ $self->db_query($query, 0);
}
return 1;
}
sub do_insert_taxkeys {
+ my ($self) = @_;
my @copy_statements = (
"INSERT INTO taxkeys VALUES (230, 69, 177, 2, NULL, '1970-01-01');",
);
for my $statement ( 0 .. $#copy_statements ) {
- my $query = $iconv->convert($copy_statements[$statement]);
+ my $query = $copy_statements[$statement];
#print $query . "<br />"; # Diagnose only!
- do_query($query, 0);
+ $self->db_query($query, 0);
}
return 1;
}
sub do_insert_buchungsgruppen {
+ my ($self) = @_;
my @copy_statements = (
- "INSERT INTO buchungsgruppen VALUES (256, 'Erlöse aus Dienstleistungen', 23, 72, 99, 72, 77, 72, 77, 72, 77, 3);",
- "INSERT INTO buchungsgruppen VALUES (254, 'Erlöse aus Warenlieferungen', 23, 68, 77, 72, 77, 72, 77, 72, 77, 2);",
- "INSERT INTO buchungsgruppen VALUES (255, 'Erlöse aus Dienstleistungen', 23, 72, 77, 72, 77, 72, 77, 72, 77, 1);",
+ "INSERT INTO buchungsgruppen VALUES (256, 'Erlöse aus Dienstleistungen', 23, 72, 99, 72, 77, 72, 77, 72, 77, 3);",
+ "INSERT INTO buchungsgruppen VALUES (254, 'Erlöse aus Warenlieferungen', 23, 68, 77, 72, 77, 72, 77, 72, 77, 2);",
+ "INSERT INTO buchungsgruppen VALUES (255, 'Erlöse aus Dienstleistungen', 23, 72, 77, 72, 77, 72, 77, 72, 77, 1);",
);
for my $statement ( 0 .. $#copy_statements ) {
- my $query = $iconv->convert($copy_statements[$statement]);
+ my $query = $copy_statements[$statement];
#print $query . "<br />"; # Diagnose only!
- do_query($query, 0);
+ $self->db_query($query, 0);
}
-return 1;
+ return 1;
}
-
-
+1;
--- /dev/null
+-- @tag: acc_trans_booleans_not_null
+-- @description: Alte acc_trans boolean-Einträge mit NULL-Werten auf false setzen
+-- @depends: release_3_0_0
+-- @charset: utf-8
+
+UPDATE acc_trans SET cleared = 'f' where cleared IS NULL;
+UPDATE acc_trans SET ob_transaction = 'f' where ob_transaction IS NULL;
+UPDATE acc_trans SET cb_transaction = 'f' where cb_transaction IS NULL;
+UPDATE acc_trans SET fx_transaction = 'f' where fx_transaction IS NULL;
+
+ALTER TABLE acc_trans ALTER cleared SET NOT NULL;
+ALTER TABLE acc_trans ALTER ob_transaction SET NOT NULL;
+ALTER TABLE acc_trans ALTER cb_transaction SET NOT NULL;
+ALTER TABLE acc_trans ALTER fx_transaction SET NOT NULL;
# @tag: acc_trans_constraints
# @description: Fügt NOT-NULL-Constraints ein für die Spalten
# @depends:
-# @charset: UTF-8
+package SL::DBUpgrade2::acc_trans_constraints;
use utf8;
use strict;
-die("This script cannot be run from the command line.") unless ($main::form);
+use parent qw(SL::DBUpgrade2::Base);
-sub mydberror {
- my ($msg) = @_;
- die($dbup_locale->text("Database update error:") . "<br>$msg<br>" . $DBI::errstr);
-}
-
-sub do_query {
- my ($query, $may_fail) = @_;
-
- if (!$dbh->do($query)) {
- mydberror($query) unless ($may_fail);
- $dbh->rollback();
- $dbh->begin_work();
- }
-}
+sub run {
+ my ($self) = @_;
-sub do_update {
my $query = qq|SELECT count(*) FROM acc_trans WHERE chart_id IS NULL|;
- my ($no_chart_id) = $dbh->selectrow_array($query);
+ my ($no_chart_id) = $self->dbh->selectrow_array($query);
$query = qq|SELECT count(*) FROM acc_trans WHERE trans_id IS NULL|;
- my ($no_trans_id) = $dbh->selectrow_array($query);
+ my ($no_trans_id) = $self->dbh->selectrow_array($query);
- $form->{no_chart_id}=$no_chart_id;
- $form->{no_trans_id}=$no_trans_id;
+ $::form->{no_chart_id}=$no_chart_id;
+ $::form->{no_trans_id}=$no_trans_id;
if ($no_chart_id > 0 or $no_trans_id > 0){
#list all invalid transactions where only chart_id is null:
LEFT JOIN project p ON (p.id=acc.project_id)
WHERE acc.chart_id IS NULL;|;
- my $sth = $dbh->prepare($query);
- $sth->execute || $main::form->dberror($query);
+ my $sth = $self->dbh->prepare($query);
+ $sth->execute || $::form->dberror($query);
- $main::form->{NO_CHART_ID} = [];
+ $::form->{NO_CHART_ID} = [];
while (my $ref = $sth->fetchrow_hashref("NAME_lc")) {
- map {$ref->{$_} = $::locale->{iconv_utf8}->convert($ref->{$_})} keys %$ref;
- push @{ $main::form->{NO_CHART_ID} }, $ref;
+ push @{ $::form->{NO_CHART_ID} }, $ref;
}
$sth->finish;
LEFT JOIN project p ON (p.id=acc.project_id)
WHERE acc.trans_id IS NULL;|;
- $sth = $dbh->prepare($query);
- $sth->execute || $main::form->dberror($query);
+ $sth = $self->dbh->prepare($query);
+ $sth->execute || $::form->dberror($query);
- $main::form->{NO_TRANS_ID} = [];
+ $::form->{NO_TRANS_ID} = [];
while (my $ref = $sth->fetchrow_hashref("NAME_lc")) {
- map {$ref->{$_} = $::locale->{iconv_utf8}->convert($ref->{$_})} keys %$ref;
$ref->{category} = ($ref->{category} eq 'A') ? $::locale->text('Account Category A')
: ($ref->{category} eq 'E') ? $::locale->text('Account Category E')
: ($ref->{category} eq 'L') ? $::locale->text('Account Category L')
: ($ref->{category} eq 'C') ? $::locale->text('Account Category C')
: ($ref->{category} eq 'G') ? $::locale->text('Account Category G')
: $::locale->text('Unknown Category') . ': ' . $ref->{category};
- push @{ $main::form->{NO_TRANS_ID} }, $ref;
+ push @{ $::form->{NO_TRANS_ID} }, $ref;
}
$sth->finish;
$query = qq|ALTER TABLE acc_trans ALTER COLUMN chart_id SET NOT NULL;|;
$query .= qq|ALTER TABLE acc_trans ALTER COLUMN trans_id SET NOT NULL;|;
- do_query($query);
+ $self->db_query($query);
return 1;
}
sub print_error_message {
- print $main::form->parse_html_template("dbupgrade/acc_trans_constraints");
+ print $::form->parse_html_template("dbupgrade/acc_trans_constraints");
}
-return do_update();
+1;
# @tag: acc_trans_id_uniqueness
# @description: Sorgt dafür, dass acc_trans.acc_trans_id eindeutig ist
# @depends: release_2_6_1
-# @charset: utf-8
+package SL::DBUpgrade2::acc_trans_id_uniqueness;
use utf8;
use strict;
-use Data::Dumper;
-die "This script cannot be run from the command line." unless $::form;
+use parent qw(SL::DBUpgrade2::Base);
-sub mydberror {
- my ($msg) = @_;
- die $dbup_locale->text("Database update error:") . "<br>$msg<br>" . $DBI::errstr;
-}
-
-sub do_query {
- my ($query, $may_fail) = @_;
+use SL::DBUtils;
- return if $dbh->do($query);
-
- mydberror($query) unless ($may_fail);
- $dbh->rollback();
- $dbh->begin_work();
-}
+sub run {
+ my ($self) = @_;
-sub do_update {
my $query = <<SQL;
SELECT acc_trans_id, trans_id, itime, mtime
FROM acc_trans
ORDER BY trans_id, itime, mtime NULLS FIRST
SQL
- my @entries = selectall_hashref_query($form, $dbh, $query);
+ my @entries = selectall_hashref_query($::form, $self->dbh, $query);
return 1 unless @entries;
))
SQL
- do_query($query, 0);
+ $self->db_query($query, 0);
my %skipped_acc_trans_ids;
foreach my $entry (@entries) {
AND (mtime $mtime)
SQL
- do_query($query, 0);
+ $self->db_query($query, 0);
}
}
return 1;
}
-return do_update();
+1;
# @tag: add_more_constraints_fibu_projekt_xplace3
# @description: Falls der Datenbestand es unproblematisch hergibt, ein paar 'schärfere' Constraints für die acc_trans gesetzt. Keine acc_trans-Eintrag ohne trans_id oder chart_id. Ferner project_id in acc_trans als Fremdschlüssel für project definiert.
# @depends: release_2_6_0 fix_acc_trans_ap_taxkey_bug
-# @charset: utf-8
+package SL::DBUpgrade2::add_more_constraints_fibu_projekt_xplace3;
-use utf8;
use strict;
-use Data::Dumper;
-die("This script cannot be run from the command line.") unless ($main::form);
+use utf8;
-sub mydberror {
- my ($msg) = @_;
- die($dbup_locale->text("Database update error:") .
- "<br>$msg<br>" . $DBI::errstr);
-}
+use parent qw(SL::DBUpgrade2::Base);
-sub do_query {
- my ($query, $may_fail) = @_;
+use SL::DBUtils;
- if (!$dbh->do($query)) {
- mydberror($query) unless ($may_fail);
- $dbh->rollback();
- $dbh->begin_work();
- }
-}
+sub run {
+ my ($self) = @_;
-sub do_update {
my @queries;
- # die project_id in der acc_trans ist auch zwingend fremdschlüssel in project
+ # die project_id in der acc_trans ist auch zwingend fremdschlüssel in project
push @queries, "ALTER TABLE acc_trans ADD FOREIGN KEY (project_id) REFERENCES project(id)";
my $query = qq|select count(*) from acc_trans where chart_id is NULL|;
- my $sth_all_groups = prepare_execute_query($form, $dbh, $query);
+ my $sth_all_groups = prepare_execute_query($::form, $self->dbh, $query);
while (my $hash_ref = $sth_all_groups->fetchrow_hashref()) { # Schleife
if ($hash_ref->{count} eq 0){
- # Falls wir keine alte buggy Installation haben, ist es super die
+ # Falls wir keine alte buggy Installation haben, ist es super die
# Gewissheit zu haben, dass kein acc_trans-Eintrag ohne chart_id vorhanden ist
push @queries, "ALTER TABLE acc_trans ALTER COLUMN chart_id SET NOT NULL";
}
}
$sth_all_groups->finish();
my $query = qq|select count(*) from acc_trans where trans_id is NULL|;
- my $sth_all_groups = prepare_execute_query($form, $dbh, $query);
+ my $sth_all_groups = prepare_execute_query($::form, $self->dbh, $query);
while (my $hash_ref = $sth_all_groups->fetchrow_hashref()) { # Schleife
if ($hash_ref->{count} eq 0){
- # Falls wir keine alte buggy Installation haben, ist es super die
+ # Falls wir keine alte buggy Installation haben, ist es super die
# Gewissheit zu haben, dass kein acc_trans-Eintrag ohne trans_id vorhanden ist
push @queries, "ALTER TABLE acc_trans ALTER COLUMN trans_id SET NOT NULL";
}
# if in doubt use brute force ;-) jb
foreach my $query (@queries){
- my $sth = prepare_query($form, $dbh, $query);
- do_statement($form,$sth,$query);
+ my $sth = prepare_query($::form, $self->dbh, $query);
+ do_statement($::form,$sth,$query);
$sth->finish();
}
- $dbh ->commit();
+ $self->dbh ->commit();
return 1;
}
-return do_update();
-
+1;
--- /dev/null
+-- @tag: ap_deliverydate
+-- @description: deliverydate zu Einkaufsrechnung hinzufügen
+-- @depends: release_3_0_0
+-- @charset: utf-8
+ALTER TABLE ap ADD COLUMN deliverydate date;
# @description: Zusätzliches Recht alle Kunden / Lieferanten editieren, war bisher standardmäßig IMMER so und kann jetzt deaktiviert werden
# falls es deaktiviert wird, kann ich den Kunden / Lieferanten nur editieren wenn ich selber als Verkäufer eingetragen bin
# @depends: release_2_6_3
-# @charset: utf-8
+package SL::DBUpgrade2::auth_enable_ct_all_edit;
-use utf8;
use strict;
-use Data::Dumper;
-die("This script cannot be run from the command line.") unless ($main::form);
+use utf8;
-sub mydberror {
- my ($msg) = @_;
- die($dbup_locale->text("Database update error:") .
- "<br>$msg<br>" . $DBI::errstr);
-}
+use parent qw(SL::DBUpgrade2::Base);
-sub do_update {
- my $dbh = $main::auth->dbconnect();
+use SL::DBUtils;
+
+sub run {
+ my ($self) = @_;
+
+ $self->dbh($::auth->dbconnect);
my $query = <<SQL;
SELECT id
FROM auth."group"
)
SQL
- my @group_ids = selectall_array_query($form, $dbh, $query);
+ my @group_ids = selectall_array_query($::form, $self->dbh, $query);
if (@group_ids) {
$query = <<SQL;
INSERT INTO auth.group_rights (group_id, "right", granted)
VALUES (?, 'customer_vendor_all_edit', TRUE)
SQL
- my $sth = prepare_query($form, $dbh, $query);
+ my $sth = prepare_query($::form, $self->dbh, $query);
foreach my $id (@group_ids) {
- do_statement($form, $sth, $query, $id);
+ do_statement($::form, $sth, $query, $id);
}
$sth->finish();
- $dbh->commit();
+ $self->dbh->commit();
}
return 1;
}
-return do_update();
-
+1;
# @tag: auth_enable_edit_prices
# @description: Zusätzliches Recht readonly für das Attribut readonly bei Preisen und Rabatten im Textfeld. Das Skript hakt standardmässig dieses Recht an, sodass es keinen Unterschied zu vorhergehenden Version gibt.
# @depends: release_2_6_3
-# @charset: utf-8
+package SL::DBUpgrade2::auth_enable_edit_prices;
-use utf8;
use strict;
-use Data::Dumper;
-die("This script cannot be run from the command line.") unless ($main::form);
+use utf8;
-sub mydberror {
- my ($msg) = @_;
- die($dbup_locale->text("Database update error:") .
- "<br>$msg<br>" . $DBI::errstr);
-}
+use parent qw(SL::DBUpgrade2::Base);
-sub do_update {
- my $dbh = $main::auth->dbconnect();
+use SL::DBUtils;
+
+sub run {
+ my ($self) = @_;
+
+ $self->dbh($::auth->dbconnect);
my $query = <<SQL;
SELECT id
FROM auth."group"
)
SQL
- my @group_ids = selectall_array_query($form, $dbh, $query);
+ my @group_ids = selectall_array_query($::form, $self->dbh, $query);
if (@group_ids) {
$query = <<SQL;
INSERT INTO auth.group_rights (group_id, "right", granted)
VALUES (?, 'edit_prices', TRUE)
SQL
- my $sth = prepare_query($form, $dbh, $query);
+ my $sth = prepare_query($::form, $self->dbh, $query);
foreach my $id (@group_ids) {
- do_statement($form, $sth, $query, $id);
+ do_statement($::form, $sth, $query, $id);
}
$sth->finish();
- $dbh->commit();
+ $self->dbh->commit();
}
return 1;
}
-return do_update();
-
+1;
# @tag: auth_enable_sales_all_edit
# @description: Neues gruppenbezogenes Recht für den Bereich Verkauf hinzugefügt (sales_all_edit := Nur wenn angehakt, können Verkaufsdokumente von anderen Bearbeitern eingesehen werden) Das Skript hakt standardmässig dieses Recht an, sodass es keinen Unterschied zu vorhergehenden Version gibt.
# @depends: release_2_6_0
-# @charset: utf-8
+package SL::DBUpgrade2::auth_enable_sales_all_edit;
-use utf8;
use strict;
-use Data::Dumper;
-die("This script cannot be run from the command line.") unless ($main::form);
+use utf8;
-sub mydberror {
- my ($msg) = @_;
- die($dbup_locale->text("Database update error:") .
- "<br>$msg<br>" . $DBI::errstr);
-}
+use parent qw(SL::DBUpgrade2::Base);
-sub do_update {
- my $dbh = $main::auth->dbconnect();
+use SL::DBUtils;
+
+sub run {
+ my ($self) = @_;
+
+ $self->dbh($::auth->dbconnect);
my $query = <<SQL;
SELECT id
FROM auth."group"
)
SQL
- my @group_ids = selectall_array_query($form, $dbh, $query);
+ my @group_ids = selectall_array_query($::form, $self->dbh, $query);
if (@group_ids) {
$query = <<SQL;
INSERT INTO auth.group_rights (group_id, "right", granted)
VALUES (?, 'sales_all_edit', TRUE)
SQL
- my $sth = prepare_query($form, $dbh, $query);
+ my $sth = prepare_query($::form, $self->dbh, $query);
foreach my $id (@group_ids) {
- do_statement($form, $sth, $query, $id);
+ do_statement($::form, $sth, $query, $id);
}
$sth->finish();
- $dbh->commit();
+ $self->dbh->commit();
}
return 1;
}
-return do_update();
-
+1;
--- /dev/null
+# @tag: background_job_change_create_periodic_invoices_to_daily
+# @description: Hintergrundjob zum Erzeugen periodischer Rechnungen täglich ausführen
+# @depends: release_3_0_0
+package SL::DBUpgrade2::background_job_change_create_periodic_invoices_to_daily;
+
+use strict;
+use utf8;
+
+use parent qw(SL::DBUpgrade2::Base);
+
+use SL::DB::BackgroundJob;
+
+sub run {
+ my ($self) = @_;
+
+ foreach my $job (@{ SL::DB::Manager::BackgroundJob->get_all(where => [ package_name => 'CreatePeriodicInvoices' ]) }) {
+ $job->update_attributes(cron_spec => '0 3 * * *', next_run_at => undef);
+ }
+
+ return 1;
+}
+
+1;
-#!/usr/bin/perl
# @tag: background_jobs_3
# @description: Backgroundjob Cleanup einrichten
# @depends: emmvee_background_jobs_2
-# @charset: utf-8
+package SL::DBUpgrade2::background_jobs_3;
use strict;
+use utf8;
+
+use parent qw(SL::DBUpgrade2::Base);
use SL::BackgroundJob::BackgroundJobCleanup;
-SL::BackgroundJob::BackgroundJobCleanup->create_job;
+sub run {
+ SL::BackgroundJob::BackgroundJobCleanup->create_job;
+ return 1;
+}
1;
# @tag: charts_without_taxkey
# @description: Fügt für jedes Konto, was keinen Steuerschlüssel hat, den Steuerschlüssel 0 hinzu
# @depends:
-# @charset: UTF-8
+package SL::DBUpgrade2::charts_without_taxkey;
-use utf8;
use strict;
-use SL::Locale;
-
-die("This script cannot be run from the command line.") unless ($main::form);
-
-sub mydberror {
- my ($msg) = @_;
- die($dbup_locale->text("Database update error:") . "<br>$msg<br>" . $DBI::errstr);
-}
-
-sub do_query {
- my ($query, $may_fail) = @_;
+use utf8;
- if (!$dbh->do($query)) {
- mydberror($query) unless ($may_fail);
- $dbh->rollback();
- $dbh->begin_work();
- }
-}
+use parent qw(SL::DBUpgrade2::Base);
+sub run {
+ my ($self) = @_;
-sub do_update {
- my ($taxkey0_with_taxes_exists) = $dbh->selectrow_array("SELECT COUNT(*) FROM tax WHERE taxkey=0 AND NOT rate=0;");
+ my ($taxkey0_with_taxes_exists) = $self->dbh->selectrow_array("SELECT COUNT(*) FROM tax WHERE taxkey=0 AND NOT rate=0;");
if ($taxkey0_with_taxes_exists > 0){
print_error_message();
return 0;
}
- my ($taxkey0_exists) = $dbh->selectrow_array("SELECT COUNT(*) FROM tax WHERE taxkey=0");
+ my ($taxkey0_exists) = $self->dbh->selectrow_array("SELECT COUNT(*) FROM tax WHERE taxkey=0");
if ($taxkey0_exists == 0){
my $insert_taxkey0 = <<SQL;
-INSERT INTO tax
+INSERT INTO tax
(rate, taxkey, taxdescription)
VALUES
(0, 0, 'Keine Steuer');
SQL
- do_query($insert_taxkey0);
+ $self->db_query($insert_taxkey0);
print $::locale->text("taxkey 0 with taxrate 0 was created.");
};
-
+
my $insert_taxkeys = <<SQL;
-INSERT INTO taxkeys
- (chart_id, tax_id, taxkey_id, startdate)
- SELECT
- c.id, (SELECT id FROM tax WHERE taxkey=0), 0, '1970-01-01'
+INSERT INTO taxkeys
+ (chart_id, tax_id, taxkey_id, startdate)
+ SELECT
+ c.id, (SELECT id FROM tax WHERE taxkey=0), 0, '1970-01-01'
FROM chart c WHERE c.id NOT IN (SELECT chart_id FROM taxkeys);
SQL
- do_query($insert_taxkeys);
+ $self->db_query($insert_taxkeys);
return 1;
-}; # end do_update
+} # end run
sub print_error_message {
- print $main::form->parse_html_template("dbupgrade/taxkey_update");
-};
+ print $::form->parse_html_template("dbupgrade/taxkey_update");
+}
-return do_update();
+1;
# @tag: contacts_add_cp_position
# @description: Feld 'Funktion/Position' zu Kontakten
# @depends: release_3_0_0
-# @charset: utf-8
+package SL::DBUpgrade2::contacts_add_cp_position;
-package contacts_add_cp_position;
use strict;
+use utf8;
-die 'This script cannot be run from the command line.' if !$::form;
+use parent qw(SL::DBUpgrade2::Base);
-my $query = 'ALTER TABLE contacts ADD COLUMN cp_position VARCHAR(75)';
+sub run {
+ my ($self) = @_;
-if (!$dbh->do($query)) {
- $dbh->rollback;
- $dbh->begin_work;
+ $self->db_query('ALTER TABLE contacts ADD COLUMN cp_position VARCHAR(75)', 1);
+
+ return 1;
}
1;
# @tag: contacts_add_street_and_zipcode_and_city
# @description: Spalten hinzufügen.
# @depends: release_2_7_0
-# @charset: utf-8
+package SL::DBUpgrade2::contacts_add_street_and_zipcode_and_city;
-use utf8;
use strict;
+use utf8;
+
+use parent qw(SL::DBUpgrade2::Base);
+
+sub run {
+ my ($self) = @_;
-my @queries = (
- 'ALTER TABLE contacts ADD COLUMN cp_street text;',
- 'ALTER TABLE contacts ADD COLUMN cp_zipcode text;',
- 'ALTER TABLE contacts ADD COLUMN cp_city text;',
-);
+ my @queries = (
+ 'ALTER TABLE contacts ADD COLUMN cp_street text;',
+ 'ALTER TABLE contacts ADD COLUMN cp_zipcode text;',
+ 'ALTER TABLE contacts ADD COLUMN cp_city text;',
+ );
-foreach my $query (@queries) {
- if ( $dbh->do($query) ) {
- next;
- }
+ $self->db_query($_, 1) for @queries;
- $dbh->rollback();
- $dbh->begin_work();
+ return 1;
}
-return 1;
+1;
# @tag: contacts_convert_cp_birthday_to_date
# @description: Umstellung cp_birthday von Freitext auf Datumsfeld
# @depends: release_2_7_0
-package contacts_convert_cp_birthday_to_date;
+package SL::DBUpgrade2::contacts_convert_cp_birthday_to_date;
+
use strict;
+use utf8;
-die 'This script cannot be run from the command line.' if !$::form;
+use parent qw(SL::DBUpgrade2::Base);
sub convert_to_date {
- my ($str) = @_;
+ my ($self, $str) = @_;
return '' if !$str;
- my $sth = $dbh->prepare('SELECT ?::date AS date') or return undef;
+ my $sth = $self->dbh->prepare('SELECT ?::date AS date') or return undef;
$sth->execute($str) or return undef;
return $sth->fetchrow_hashref->{date};
}
-sub update {
+sub run {
+ my ($self) = @_;
+
my @data = ();
my @auto_data = ();
my $sql = <<SQL;
ORDER BY cp_id;
SQL
- my $sth = $dbh->prepare($sql) or die $dbh->errstr;
- $sth->execute or die $dbh->errstr;
+ my $sth = $self->dbh->prepare($sql) or die $self->dbh->errstr;
+ $sth->execute or die $self->dbh->errstr;
my $i = -1;
while (my $row = $sth->fetchrow_hashref) {
$i++;
- $row->{cp_birthday} = convert_to_date($::form->{form_submitted} ? $::form->{'cp_birthday_'. $i} : $row->{cp_birthday_old});
+ $row->{cp_birthday} = $self->convert_to_date($::form->{form_submitted} ? $::form->{'cp_birthday_'. $i} : $row->{cp_birthday_old});
$row->{row_index} = $i;
if ( defined($row->{cp_birthday}) ) {
ALTER TABLE contacts ADD COLUMN cp_birthday date;
SQL
- $dbh->do($sql);
+ $self->dbh->do($sql);
$sql = <<SQL;
UPDATE contacts
WHERE cp_id = ?
SQL
- $sth = $dbh->prepare($sql) or die $dbh->errstr;
+ $sth = $self->dbh->prepare($sql) or die $self->dbh->errstr;
foreach (grep { $_->{cp_birthday} ne '' } @auto_data) {
- $sth->execute($_->{cp_birthday}, $_->{cp_id}) or die $dbh->errstr;
+ $sth->execute($_->{cp_birthday}, $_->{cp_id}) or die $self->dbh->errstr;
}
return 1;
}
}
-return update();
+1;
# @tag: cp_greeting_migration
# @description: Migration of cp_greeting to cp_gender
# @depends: generic_translations
+package SL::DBUpgrade2::cp_greeting_migration;
use strict;
+use utf8;
-die("This script cannot be run from the command line.") unless ($main::form);
-
-sub mydberror {
- my ($msg) = @_;
- die($dbup_locale->text("Database update error:") . "<br>$msg<br>" . $DBI::errstr);
-}
-
-sub do_query {
- my ($query, $may_fail) = @_;
-
- if (!$dbh->do($query)) {
- mydberror($query) unless ($may_fail);
- $dbh->rollback();
- $dbh->begin_work();
- }
-}
-
+use parent qw(SL::DBUpgrade2::Base);
sub query_result {
+ my ($self) = @_;
# list of all entries where cp_greeting is empty, meaning can't determine gender from parsing Herr/Frau/...
# this assumes cp_greeting still exists, i.e. gender.sql was not run yet
my ($gender_table, $mchecked, $fchecked);
my $sql2 = "select cp_id,cp_givenname,cp_name,cp_title,cp_greeting from contacts where not (cp_greeting ILIKE '%frau%' OR cp_greeting ILIKE '%herr%' or cp_greeting ILIKE '%mrs.%' or cp_greeting ILIKE '%miss%') ";
- my $sth2 = $dbh->prepare($sql2) or die $dbh->errstr();
- $sth2->execute() or die $dbh->errstr();
+ my $sth2 = $self->dbh->prepare($sql2) or die $self->dbh->errstr();
+ $sth2->execute() or die $self->dbh->errstr();
my $i = 1;
$gender_table .= '<table border="1"><tr><th>cp_givenname</th><th>cp_name</th><th>cp_title</th><th>cp_greeting</th><th><translate>male/female</th></tr>';
$gender_table .= "\n";
while (my $row = $sth2->fetchrow_hashref()) {
- if ($main::form->{"gender_$i"} eq "f" ) {
+ if ($::form->{"gender_$i"} eq "f" ) {
$mchecked = "";
$fchecked = "checked";
} else {
$gender_table .= "<input type=hidden name=\"number_of_gender_entries\" value=\"$i\">";
$gender_table .= "</table>";
- $main::form->{gender_table} = $gender_table;
+ $::form->{gender_table} = $gender_table;
my $title_table;
my $sql3 = "select cp_id,cp_givenname,cp_name,cp_title,cp_greeting from contacts where not ( (cp_greeting ILIKE '%frau%' OR cp_greeting ILIKE '%herr%' or cp_greeting ILIKE '%mrs.%' or cp_greeting ILIKE '%miss%')) and not (cp_greeting like ''); ";
- my $sth3 = $dbh->prepare($sql3) or die $dbh->errstr();
- $sth3->execute() or die $dbh->errstr();
+ my $sth3 = $self->dbh->prepare($sql3) or die $self->dbh->errstr();
+ $sth3->execute() or die $self->dbh->errstr();
$title_table = '<table border="1"><tr><th>cp_givenname</th><th>cp_name</th><th>cp_title</th><th>cp_greeting</th><th>cp_title new</th></tr>';
$title_table .= "<input type=hidden name=\"number_of_title_entries\" value=\"$j\">";
$title_table .= "</table>";
- $main::form->{title_table} = $title_table;
+ $::form->{title_table} = $title_table;
}
sub print_question {
- query_result();
+ my ($self) = @_;
+
+ $self->query_result;
# parse html form in /templates/webpages/dbupgrade/cp_greeting_update_form
- print $main::form->parse_html_template("dbupgrade/cp_greeting_update_form");
+ print $::form->parse_html_template("dbupgrade/cp_greeting_update_form");
}
sub alter_schema_only {
+ my ($self) = @_;
+
my $sqlcode = <<SQL;
ALTER TABLE contacts ADD COLUMN cp_gender char(1);
ALTER TABLE contacts DROP COLUMN cp_greeting;
SQL
- $dbh->do($sqlcode);
+ $self->dbh->do($sqlcode);
}
-sub do_update {
+sub run {
+ my ($self) = @_;
+
# main function
# Do not ask the user anything if there are no entries in the
# contacts table.
- my ($data_exists) = $dbh->selectrow_array("SELECT * FROM contacts LIMIT 1");
+ my ($data_exists) = $self->dbh->selectrow_array("SELECT * FROM contacts LIMIT 1");
if (!$data_exists) {
- alter_schema_only();
+ $self->alter_schema_only;
return 1;
}
# without doing anything
my $column_exists = 1;
- if (!$dbh->do("SELECT cp_gender FROM contacts LIMIT 1")) {
- $dbh->rollback();
- $dbh->begin_work();
+ if (!$self->dbh->do("SELECT cp_gender FROM contacts LIMIT 1")) {
+ $self->dbh->rollback();
+ $self->dbh->begin_work();
$column_exists = 0;
}
return 1 if $column_exists;
- if (!$main::form->{do_migrate}) {
+ if (!$::form->{do_migrate}) {
# case 1: first call of page
- set_default_greetings();
- print_question();
+ $self->set_default_greetings;
+ $self->print_question;
return 2;
- } else {
- # case 2: submit button was pressed, hidden field do_migrate was set
- migrate_data();
}
+ # case 2: submit button was pressed, hidden field do_migrate was set
+ $self->migrate_data;
+
return 1;
}
sub migrate_data {
+ my ($self) = @_;
my $sqlcode = <<EOF
ALTER TABLE contacts ADD COLUMN cp_gender char(1);
EOF
;
- for (my $i = 1; $i <= $main::form->{number_of_gender_entries}; $i++ ) {
- next unless $main::form->{"cp_id_$i"};
- if ( $main::form->{"gender_$i"} eq "f" ) {
- $sqlcode .= "UPDATE contacts SET cp_gender = \'f\' WHERE cp_id = $main::form->{\"cp_id_$i\"};\n";
+ for (my $i = 1; $i <= $::form->{number_of_gender_entries}; $i++ ) {
+ next unless $::form->{"cp_id_$i"};
+ if ( $::form->{"gender_$i"} eq "f" ) {
+ $sqlcode .= "UPDATE contacts SET cp_gender = \'f\' WHERE cp_id = $::form->{\"cp_id_$i\"};\n";
}
}
- for (my $i = 1; $i <= $main::form->{number_of_title_entries}; $i++ ) {
- next unless $main::form->{"cp_id_title_$i"} and $main::form->{"cp_id_$i"};
- $sqlcode .= "UPDATE contacts SET cp_title = \'$main::form->{\"cp_name_$i\"}\' WHERE cp_id = $main::form->{\"cp_id_$i\"};\n";
+ for (my $i = 1; $i <= $::form->{number_of_title_entries}; $i++ ) {
+ next unless $::form->{"cp_id_title_$i"} and $::form->{"cp_id_$i"};
+ $sqlcode .= "UPDATE contacts SET cp_title = \'$::form->{\"cp_name_$i\"}\' WHERE cp_id = $::form->{\"cp_id_$i\"};\n";
}
$sqlcode .= "ALTER TABLE contacts DROP COLUMN cp_greeting;";
# insert chosen default values
- $sqlcode .= "INSERT INTO generic_translations (translation_type, translation) VALUES ('greetings::male','$main::form->{default_male}');";
- $sqlcode .= "INSERT INTO generic_translations (translation_type, translation) VALUES ('greetings::female','$main::form->{default_female}');";
+ $sqlcode .= "INSERT INTO generic_translations (translation_type, translation) VALUES ('greetings::male','$::form->{default_male}');";
+ $sqlcode .= "INSERT INTO generic_translations (translation_type, translation) VALUES ('greetings::female','$::form->{default_female}');";
my $query = $sqlcode;
- do_query($query);
+ $self->db_query($query);
}
sub set_default_greetings {
+ my ($self) = @_;
+
# add html input boxes to template so user can specify default greetings
my $default_male = "Herr";
my $default_female = "Frau";
my $default_greeting_text_male = "<input type=\"text\" id=\"default_male\" name=\"default_male\" value=\"$default_male\"><br>";
my $default_greeting_text_female = "<input type=\"text\" id=\"default_female\" name=\"default_female\" value=\"$default_female\"><br>";
- $main::form->{default_greeting_text_male} = $default_greeting_text_male;
- $main::form->{default_greeting_text_female} = $default_greeting_text_female;
+ $::form->{default_greeting_text_male} = $default_greeting_text_male;
+ $::form->{default_greeting_text_female} = $default_greeting_text_female;
}
-return do_update();
-
+1;
# @tag: defaults_datev_check
# @description: Einstellung für DATEV-Überprüfungen (datev_check) vom Config-File in die DB verlagern.
# @depends: release_2_7_0
-# @charset: utf-8
+package SL::DBUpgrade2::defaults_datev_check;
use utf8;
-use strict;
-
-die("This script cannot be run from the command line.") unless ($main::form);
-
-sub mydberror {
- my ($msg) = @_;
- die($dbup_locale->text("Database update error:") .
- "<br>$msg<br>" . $DBI::errstr);
-}
-
-sub do_query {
- my ($query, $may_fail) = @_;
- if (!$dbh->do($query)) {
- mydberror($query) unless ($may_fail);
- $dbh->rollback();
- $dbh->begin_work();
- }
-}
+use parent qw(SL::DBUpgrade2::Base);
+use strict;
-sub do_update {
+sub run {
+ my ($self) = @_;
# this query will fail if column already exist (new database)
- do_query(qq|ALTER TABLE defaults ADD COLUMN datev_check_on_sales_invoice boolean DEFAULT true|, 1);
- do_query(qq|ALTER TABLE defaults ADD COLUMN datev_check_on_purchase_invoice boolean DEFAULT true|, 1);
- do_query(qq|ALTER TABLE defaults ADD COLUMN datev_check_on_ar_transaction boolean DEFAULT true|, 1);
- do_query(qq|ALTER TABLE defaults ADD COLUMN datev_check_on_ap_transaction boolean DEFAULT true|, 1);
- do_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|, 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);
# check current configuration and set default variables accordingly, so that
# kivitendo's behaviour isn't changed by this update
}
my $update_column = "UPDATE defaults SET datev_$check = '$check_set';";
- do_query($update_column);
+ $self->db_query($update_column);
}
-
return 1;
}
-return do_update();
-
+1;
# @tag: defaults_posting_config
# @description: Einstellung, ob und wann Zahlungen änderbar sind, vom Config-File in die DB verlagern.
# @depends: release_2_7_0
-# @charset: utf-8
+package SL::DBUpgrade2::defaults_posting_config;
-use utf8;
use strict;
+use utf8;
-die("This script cannot be run from the command line.") unless ($main::form);
-
-sub mydberror {
- my ($msg) = @_;
- die($dbup_locale->text("Database update error:") .
- "<br>$msg<br>" . $DBI::errstr);
-}
-
-sub do_query {
- my ($query, $may_fail) = @_;
-
- if (!$dbh->do($query)) {
- mydberror($query) unless ($may_fail);
- $dbh->rollback();
- $dbh->begin_work();
- }
-}
+use parent qw(SL::DBUpgrade2::Base);
-sub do_update {
+sub run {
+ my ($self) = @_;
# this query will fail if column already exist (new database)
- do_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|, 1);
# check current configuration and set default variables accordingly, so that
# kivitendo behaviour isn't changed by this update
}
my $update_column = "UPDATE defaults SET payments_changeable = '$payments_changeable';";
- do_query($update_column);
+ $self->db_query($update_column);
return 1;
}
-return do_update();
-
+1;
# @tag: defaults_show_bestbefore
# @description: Einstellung, ob Mindesthaltbarkeitsdatum angezeigt wird, vom Config-File in die DB verlagern.
# @depends: release_2_7_0
-# @charset: utf-8
+package SL::DBUpgrade2::defaults_show_bestbefore;
-use utf8;
use strict;
+use utf8;
-die("This script cannot be run from the command line.") unless ($main::form);
-
-sub mydberror {
- my ($msg) = @_;
- die($dbup_locale->text("Database update error:") .
- "<br>$msg<br>" . $DBI::errstr);
-}
-
-sub do_query {
- my ($query, $may_fail) = @_;
-
- if (!$dbh->do($query)) {
- mydberror($query) unless ($may_fail);
- $dbh->rollback();
- $dbh->begin_work();
- }
-}
+use parent qw(SL::DBUpgrade2::Base);
-sub do_update {
+sub run {
+ my ($self) = @_;
# this query will fail if column already exist (new database)
- do_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|, 1);
# check current configuration and set default variables accordingly, so that
# kivitendo behaviour isn't changed by this update
}
my $update_column = "UPDATE defaults SET show_bestbefore = '$show_bestbefore';";
- do_query($update_column);
+ $self->db_query($update_column);
return 1;
}
-return do_update();
-
+1;
-#!/usr/bin/perl
# @tag: emmvee_background_jobs_2
# @description: Hintergrundjobs einrichten
# @depends: emmvee_background_jobs
-# @charset: utf-8
+package SL::DBUpgrade2::emmvee_background_jobs_2;
use strict;
+use utf8;
+
+use parent qw(SL::DBUpgrade2::Base);
use SL::BackgroundJob::CleanBackgroundJobHistory;
-SL::BackgroundJob::CleanBackgroundJobHistory->create_job;
+sub run {
+ SL::BackgroundJob::CleanBackgroundJobHistory->create_job;
+ return 1;
+}
1;
--- /dev/null
+# @tag: erzeugnisnummern
+# @description: Erzeugnisnummern und Artikelnummern sollen eindeutig sein.
+# @depends: release_3_0_0
+package SL::DBUpgrade2::erzeugnisnummern;
+
+use strict;
+use utf8;
+
+use parent qw(SL::DBUpgrade2::Base);
+
+sub run {
+ my ($self) = @_;
+
+ if ( $::form->{'continued'} ) {
+ my $update_query;
+ foreach my $i (1 .. $::form->{rowcount}) {
+ $update_query = qq|UPDATE parts SET partnumber = '| . $::form->{"partnumber_$i"} . qq|' WHERE id = | . $::form->{"partid_$i"};
+ $self->db_query($update_query);
+ print FH $i;
+ }
+ $self->dbh->commit();
+ }
+
+ my $query = qq|SELECT id, partnumber, description, unit, notes, assembly, ean, inventory_accno_id
+ FROM parts pa
+ WHERE (SELECT COUNT(*)
+ FROM parts p
+ WHERE p.partnumber=pa.partnumber)
+ > 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;
+ }
+
+ if ( scalar @{ $::form->{PARTS} } > 0 ) {
+ &print_error_message;
+ return 2;
+ }
+
+ $query = qq|ALTER TABLE parts ADD UNIQUE (partnumber)|;
+ $self->db_query($query);
+
+ $query = qq|ALTER TABLE defaults ADD assemblynumber TEXT|;
+ $self->db_query($query);
+ return 1;
+} # end run
+
+sub print_error_message {
+ print $::form->parse_html_template("dbupgrade/erzeugnisnummern");
+}
+
+1;
# @tag: finanzamt_update_fa_bufa_nr_hamburg
-# @description: Aktualisiert die fa_bufa_nr für Hamburg
+# @description: Aktualisiert die fa_bufa_nr für Hamburg
# @depends: release_2_7_0
-# @charset: utf-8
-package finanzamt_update_fa_bufa_nr_hamburg;
-use utf8;
+package SL::DBUpgrade2::finanzamt_update_fa_bufa_nr_hamburg;
+
use strict;
+use utf8;
-if ( !$::form ) {
- die('This script cannot be run from the command line.');
-}
+use parent qw(SL::DBUpgrade2::Base);
-sub query {
- my ($query) = @_;
+sub run {
+ my ($self) = @_;
- if ( !$dbh->do($query) ) {
- die($dbup_locale->text('Database update error:') .'<br>'. $query .'<br>'. $DBI::errstr);
- }
-}
-
-my @data = (
+ my @data = (
['02', '41'],
['57', '42'],
['71', '43'],
['08', '51'],
);
-foreach my $entry (@data) {
- query('
+ foreach my $entry (@data) {
+ $self->db_query('
UPDATE finanzamt
SET
fa_bufa_nr = \'22'. $entry->[1] .'\'
WHERE
fa_land_nr = \'2\'
- AND fa_bufa_nr = \'22'. $entry->[0] .'\';');
+ AND fa_bufa_nr = \'22'. $entry->[0] .'\'');
+ }
+
+ return 1;
}
-return 1;
+1;
# @tag: fix_acc_trans_ap_taxkey_bug
-# @description: Korrektur falscher Steuerschlüssel in acc_trans bei Eingangsrechnungen
+# @description: Korrektur falscher Steuerschlüssel in acc_trans bei Eingangsrechnungen
# @depends: release_2_6_0
+package SL::DBUpgrade2::fix_acc_trans_ap_taxkey_bug;
use strict;
+use utf8;
-die "This script cannot be run from the command line." unless $::form;
+use parent qw(SL::DBUpgrade2::Base);
-sub mydberror {
- my $msg = shift;
- die $dbup_locale->text("Database update error:") . "<br>$msg<br>" . $DBI::errstr;
-}
-
-sub do_query {
- my $query = shift;
- my $may_fail = shift;
-
- if (!$dbh->do($query)) {
- mydberror($query) unless $may_fail;
- $dbh->rollback();
- $dbh->begin_work();
- }
-}
+sub run {
+ my ($self) = @_;
-sub do_update {
my $q_find = <<SQL;
SELECT * FROM (
SELECT
WHERE acc_trans_id = ?
SQL
- my $h_find = $dbh->prepare($q_find) || mydberror($q_find);
- my $h_change = $dbh->prepare($q_change) || mydberror($q_change);
+ my $h_find = $self->dbh->prepare($q_find) || $self->db_error($q_find);
+ my $h_change = $self->dbh->prepare($q_change) || $self->db_error($q_change);
- $h_find->execute() || mydberror($q_find);
+ $h_find->execute() || $self->db_error($q_find);
my $num_changed = 0;
while (my $ref = $h_find->fetchrow_hashref()) {
# $::lxdebug->dump(0, "ref", $ref);
- $h_change->execute($ref->{wanted_taxkey}, $ref->{acc_trans_id}) || mydberror($q_change);
+ $h_change->execute($ref->{wanted_taxkey}, $ref->{acc_trans_id}) || $self->db_error($q_change);
$num_changed++;
}
$h_find->finish();
$h_change->finish();
- print $dbup_locale->text('Number of entries changed: #1', $num_changed) . "<br/>\n";
+ print $::locale->text('Number of entries changed: #1', $num_changed) . "<br/>\n";
}
-do_update();
-return 1;
-
+1;
# @tag: globalprojectnumber_ap_ar_oe
# @description: Neue Spalte für eine globale Projektnummer in Einkaufs- und Verkaufsbelegen
# @depends: release_2_4_1
+package SL::DBUpgrade2::globalprojectnumber_ap_ar_oe;
use strict;
+use utf8;
-die("This script cannot be run from the command line.") unless ($main::form);
+use parent qw(SL::DBUpgrade2::Base);
-sub mydberror {
- my ($msg) = @_;
- die($dbup_locale->text("Database update error:") .
- "<br>$msg<br>" . $DBI::errstr);
-}
-
-sub do_query {
- my ($query, $may_fail) = @_;
+sub run {
+ my ($self) = @_;
- if (!$dbh->do($query)) {
- mydberror($query) unless ($may_fail);
- $dbh->rollback();
- $dbh->begin_work();
- }
-}
-
-sub do_update {
my @queries =
("ALTER TABLE ap ADD COLUMN globalproject_id integer;",
"ALTER TABLE ap ADD FOREIGN KEY (globalproject_id) REFERENCES project (id);",
"ALTER TABLE oe ADD COLUMN globalproject_id integer;",
"ALTER TABLE oe ADD FOREIGN KEY (globalproject_id) REFERENCES project (id);");
- do_query("ALTER TABLE project ADD PRIMARY KEY (id);", 1);
- map({ do_query($_, 0); } @queries);
+ $self->db_query("ALTER TABLE project ADD PRIMARY KEY (id);", 1);
+ map({ $self->db_query($_, 0); } @queries);
return 1;
}
-return do_update();
-
+1;
# @tag: periodic_invoices_background_job
# @description: Hintergrundjob zum Erzeugen wiederkehrender Rechnungen
# @depends: periodic_invoices
-# @charset: utf-8
+package SL::DBUpgrade2::periodic_invoices_background_job;
use strict;
+use utf8;
+
+use parent qw(SL::DBUpgrade2::Base);
use SL::BackgroundJob::CreatePeriodicInvoices;
-SL::BackgroundJob::CreatePeriodicInvoices->create_job;
+sub run {
+ SL::BackgroundJob::CreatePeriodicInvoices->create_job;
+ return 1;
+}
1;
# @tag: rundungsfehler_korrigieren_BUG1328-2
# @description: Die entsprechende Cent-Abweichung die durch den Rundungsfehler in Bug 1328 behoben wurde, entsprechende für alte Buchungen korrigieren.
# @depends: release_2_6_0
-# @charset: utf-8
+package SL::DBUpgrade2::rundungsfehler_korrigieren_BUG1328_2;
-use utf8;
use strict;
-use Data::Dumper;
-die("This script cannot be run from the command line.") unless ($main::form);
+use utf8;
-sub mydberror {
- my ($msg) = @_;
- die($dbup_locale->text("Database update error:") .
- "<br>$msg<br>" . $DBI::errstr);
-}
+use parent qw(SL::DBUpgrade2::Base);
-sub do_query {
- my ($query, $may_fail) = @_;
+use SL::DBUtils;
- if (!$dbh->do($query)) {
- mydberror($query) unless ($may_fail);
- $dbh->rollback();
- $dbh->begin_work();
- }
-}
+sub run {
+ my ($self) = @_;
-sub do_update {
my @queries;
my $query = qq|select distinct id,acamount from (select ap.id,ap.amount as apamount, ac.amount*-1 as acamount from ap left join acc_trans ac on (ac.trans_id =
ap.id) where ac.chart_id IN (select id from chart where link ='AP' OR link like '%:AP' OR link like 'AP:%')) as foo where apamount + 0.01 = abs(acamount)|;
- my $sth_all_groups = prepare_execute_query($form, $dbh, $query);
+ my $sth_all_groups = prepare_execute_query($::form, $self->dbh, $query);
while (my $hash_ref = $sth_all_groups->fetchrow_hashref()) { # Schleife
push @queries, "UPDATE ap set amount =" . $hash_ref->{acamount} . " WHERE id = " . $hash_ref->{id};
}
my $query = qq|select distinct id,acamount from (select ar.id, ar.amount as aramount, ac.amount*-1 as acamount from ar left join acc_trans ac on (ac.trans_id =
ar.id) where ac.chart_id IN (select id from chart where link ='AR' OR link like '%:AR' OR link like 'AR:%')) as foo where aramount + 0.01 = abs(acamount)|;
- my $sth_all_groups = prepare_execute_query($form, $dbh, $query);
+ my $sth_all_groups = prepare_execute_query($::form, $self->dbh, $query);
while (my $hash_ref = $sth_all_groups->fetchrow_hashref()) { # Schleife
- # Falls wir keine alte buggy Installation haben, ist es super die
+ # Falls wir keine alte buggy Installation haben, ist es super die
# Gewissheit zu haben, dass kein acc_trans-Eintrag ohne trans_id vorhanden ist
push @queries, "UPDATE ar set amount =" . $hash_ref->{acamount} . " WHERE id = " . $hash_ref->{id};
}
# if in doubt use brute force ;-) jb
foreach my $query (@queries){
- my $sth = prepare_query($form, $dbh, $query);
- do_statement($form,$sth,$query);
+ my $sth = prepare_query($::form, $self->dbh, $query);
+ do_statement($::form,$sth,$query);
$sth->finish();
}
- $dbh ->commit();
+ $self->dbh ->commit();
return 1;
}
-return do_update();
-
+1;
# @tag: self_test_background_job
# @description: Hintergrundjob für tägliche Selbsttests
# @depends: release_2_7_0
-# @charset: utf-8
+package SL::DBUpgrade2::self_test_background_job;
use strict;
+use utf8;
+
+use parent qw(SL::DBUpgrade2::Base);
use SL::BackgroundJob::SelfTest;
-SL::BackgroundJob::SelfTest->create_job;
+sub run {
+ SL::BackgroundJob::SelfTest->create_job;
+ return 1;
+}
1;
--- /dev/null
+# @tag: steuerfilterung
+# @description: Steuern in Dialogbuchungen filtern.
+# @depends: release_3_0_0
+package SL::DBUpgrade2::steuerfilterung;
+
+use strict;
+use utf8;
+
+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;
+ foreach my $i (1 .. $::form->{rowcount}) {
+ $tax_id = $::form->{"tax_id_$i"};
+ $categories = '';
+ $categories .= 'A' if $::form->{"asset_$i"};
+ $categories .= 'L' if $::form->{"liability_$i"};
+ $categories .= 'Q' if $::form->{"equity_$i"};
+ $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|;
+ $self->db_query($update_query);
+ }
+ $update_query = qq|ALTER TABLE tax ALTER COLUMN chart_categories SET NOT NULL|;
+ $self->db_query($update_query);
+ $self->dbh->commit();
+ return 1;
+ }
+
+ my $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);
+
+ $::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;
+ }
+
+ &print_message;
+ return 2;
+} # end run
+
+sub print_message {
+ print $::form->parse_html_template("dbupgrade/steuerfilterung");
+}
+
+1;
# @tag: tax_constraints
# @description: Setzt Fremdschlüssel und andere constraints auf die Tabellen tax und taxkeys
# @depends: release_3_0_0 charts_without_taxkey
-# @charset: utf-8
+package SL::DBUpgrade2::tax_constraints;
-use utf8;
use strict;
-use SL::Locale;
-
-die("This script cannot be run from the command line.") unless ($main::form);
-
-sub mydberror {
- my ($msg) = @_;
- die($dbup_locale->text("Database update error:") . "<br>$msg<br>" . $DBI::errstr);
-}
+use utf8;
-sub do_query {
- my ($query, $may_fail) = @_;
+use parent qw(SL::DBUpgrade2::Base);
- if (!$dbh->do($query)) {
- mydberror($query) unless ($may_fail);
- $dbh->rollback();
- $dbh->begin_work();
- }
-}
+sub run {
+ my ($self) = @_;
-sub do_update {
#CHECK CONSISTANCY OF tax
#update tax.rate and tax.taxdescription in order to set later NOT NULL constraints
my $query= <<SQL;
UPDATE tax SET taxdescription='-' WHERE COALESCE(taxdescription, '') = '';
SQL
- do_query($query);
+ $self->db_query($query);
#check automatic tax accounts
$query= <<SQL;
SELECT count(*) FROM tax WHERE chart_id NOT IN (SELECT id FROM chart);
SQL
- my ($invalid_tax_account) = $dbh->selectrow_array($query);
+ my ($invalid_tax_account) = $self->dbh->selectrow_array($query);
if ($invalid_tax_account > 0){
#list all invalid tax accounts
FROM tax WHERE chart_id NOT IN (SELECT id FROM chart);
SQL
- my $sth = $dbh->prepare($query);
- $sth->execute || $main::form->dberror($query);
+ my $sth = $self->dbh->prepare($query);
+ $sth->execute || $::form->dberror($query);
- $main::form->{TAX} = [];
+ $::form->{TAX} = [];
while (my $ref = $sth->fetchrow_hashref("NAME_lc")) {
- push @{ $main::form->{TAX} }, $ref;
+ push @{ $::form->{TAX} }, $ref;
}
$sth->finish;
- $main::form->{invalid_tax_account} = 1;
+ $::form->{invalid_tax_account} = 1;
print_error_message();
return 0;
}
SELECT count(*) FROM tax WHERE taxkey IS NULL;
SQL
- my ($taxkey_is_null) = $dbh->selectrow_array($query);
+ my ($taxkey_is_null) = $self->dbh->selectrow_array($query);
if ($taxkey_is_null > 0){
#list all invalid tax accounts
WHERE taxkey IS NULL;
SQL
- my $sth = $dbh->prepare($query);
- $sth->execute || $main::form->dberror($query);
+ my $sth = $self->dbh->prepare($query);
+ $sth->execute || $::form->dberror($query);
- $main::form->{TAX} = [];
+ $::form->{TAX} = [];
while (my $ref = $sth->fetchrow_hashref("NAME_lc")) {
- push @{ $main::form->{TAX} }, $ref;
+ push @{ $::form->{TAX} }, $ref;
}
$sth->finish;
- $main::form->{taxkey_is_null} = 1;
+ $::form->{taxkey_is_null} = 1;
print_error_message();
return 0;
}
OR startdate IS NULL;
SQL
- do_query($query);
+ $self->db_query($query);
#There are 3 cases for taxkeys.tax_id and taxkeys.taxkey_id
#taxkeys.taxkey_id is NULL and taxkeys.tax_id is not NULL:
AND tax_id IS NOT NULL;
SQL
- do_query($query);
+ $self->db_query($query);
#taxkeys.taxkey_id and taxkeys.tax_id are NULL:
AND tax_id IS NULL;
SQL
- do_query($query);
+ $self->db_query($query);
#Last case where taxkeys.taxkey_id is not null and taxkeys.tax_id is null
AND tax_id IS NULL;
SQL
- my $sth = $dbh->prepare($query);
- $sth->execute || $main::form->dberror($query);
+ my $sth = $self->dbh->prepare($query);
+ $sth->execute || $::form->dberror($query);
- $main::form->{TAXID} = [];
+ $::form->{TAXID} = [];
my $rowcount = 0;
while (my $ref = $sth->fetchrow_hashref("NAME_lc")) {
- push @{ $main::form->{TAXID} }, $ref;
+ push @{ $::form->{TAXID} }, $ref;
$rowcount++;
}
$sth->finish;
my $tax_id;
for my $i (0 .. $rowcount-1){
$query= qq|
- SELECT id FROM tax WHERE rate = 0 and taxkey=| . $main::form->{TAXID}[$i]->{taxkey_id} . qq| LIMIT 1
+ SELECT id FROM tax WHERE rate = 0 and taxkey=| . $::form->{TAXID}[$i]->{taxkey_id} . qq| LIMIT 1
|;
- ($tax_id) = $dbh->selectrow_array($query);
+ ($tax_id) = $self->dbh->selectrow_array($query);
if ( not $tax_id ){
$insertquery=qq|
- INSERT INTO tax (rate, taxdescription, taxkey) VALUES (0, '| . $::locale->text('0% tax with taxkey') . $main::form->{TAXID}[$i]->{taxkey_id} . $::locale->text('. Automatically generated.') .
- qq|', | . $main::form->{TAXID}[$i]->{taxkey_id} . qq|);
+ INSERT INTO tax (rate, taxdescription, taxkey) VALUES (0, '| . $::locale->text('0% tax with taxkey') . $::form->{TAXID}[$i]->{taxkey_id} . $::locale->text('. Automatically generated.') .
+ qq|', | . $::form->{TAXID}[$i]->{taxkey_id} . qq|);
|;
- do_query($insertquery);
- ($tax_id) = $dbh->selectrow_array($query);
- $tax_id || $main::form->dberror($query);
+ $self->db_query($insertquery);
+ ($tax_id) = $self->dbh->selectrow_array($query);
+ $tax_id || $::form->dberror($query);
}
$updatequery = qq|
- UPDATE taxkeys SET tax_id= | . $tax_id . qq| WHERE taxkey_id = | . $main::form->{TAXID}[$i]->{taxkey_id} . qq| AND tax_id IS NULL
+ UPDATE taxkeys SET tax_id= | . $tax_id . qq| WHERE taxkey_id = | . $::form->{TAXID}[$i]->{taxkey_id} . qq| AND tax_id IS NULL
|;
- do_query($updatequery);
+ $self->db_query($updatequery);
}
#The triple taxkey_id, chart_id, startdate in taxkeys has to be unique
AND tk2.startdate = tk1.startdate) > 1;
SQL
- $sth = $dbh->prepare($query);
- $sth->execute || $main::form->dberror($query);
+ $sth = $self->dbh->prepare($query);
+ $sth->execute || $::form->dberror($query);
- $main::form->{TAXKEYS} = [];
+ $::form->{TAXKEYS} = [];
$rowcount = 0;
while (my $ref = $sth->fetchrow_hashref("NAME_lc")) {
- push @{ $main::form->{TAXKEYS} }, $ref;
+ push @{ $::form->{TAXKEYS} }, $ref;
$rowcount++;
}
$sth->finish;
AND tk2.startdate = tk1.startdate) > 1
AND NOT tk1.id = (SELECT id
FROM taxkeys
- WHERE chart_id = | . $main::form->{TAXKEYS}[$i]->{chart_id} . qq|
- AND startdate = '| . $main::form->{TAXKEYS}[$i]->{startdate} . qq|'
+ WHERE chart_id = | . $::form->{TAXKEYS}[$i]->{chart_id} . qq|
+ AND startdate = '| . $::form->{TAXKEYS}[$i]->{startdate} . qq|'
LIMIT 1)
|;
- do_query($query);
+ $self->db_query($query);
}
#END CHECK OF taxkeys
ALTER TABLE tax ALTER COLUMN rate SET DEFAULT 0;
SQL
- do_query($query);
+ $self->db_query($query);
#Create NOT NULL constraint for tax.description
$query= <<SQL;
ALTER TABLE tax ALTER COLUMN taxdescription SET NOT NULL;
SQL
- do_query($query);
+ $self->db_query($query);
#Create foreign key for tax.chart_id to chart.id
$query= <<SQL;
ALTER TABLE tax ADD FOREIGN KEY (chart_id) REFERENCES chart(id);
SQL
- do_query($query);
+ $self->db_query($query);
#Create NOT NULL constraint for tax.taxkey
$query= <<SQL;
ALTER TABLE tax ALTER COLUMN taxkey SET NOT NULL;
SQL
- do_query($query);
+ $self->db_query($query);
#Create NOT NULL constraint for taxkey.chart_id and foreign key for taxkey.chart_id
$query= <<SQL;
ALTER TABLE taxkeys ADD FOREIGN KEY (chart_id) REFERENCES chart(id);
SQL
- do_query($query);
+ $self->db_query($query);
#Create NOT NULL constraint for taxkey.startdate
$query= <<SQL;
ALTER TABLE taxkeys ALTER COLUMN startdate SET NOT NULL;
SQL
- do_query($query);
+ $self->db_query($query);
#Create NOT NULL constraint for taxkey.taxkey_id
$query= <<SQL;
ALTER TABLE taxkeys ALTER COLUMN taxkey_id SET NOT NULL;
SQL
- do_query($query);
+ $self->db_query($query);
#Create NOT NULL constraint for taxkey.tax_id
$query= <<SQL;
ALTER TABLE taxkeys ALTER COLUMN tax_id SET NOT NULL;
SQL
- do_query($query);
+ $self->db_query($query);
#The triple chart_id, taxkey_id, startdate should be unique:
$query= <<SQL;
CREATE UNIQUE INDEX taxkeys_chartid_startdate ON taxkeys(chart_id, startdate);
SQL
- do_query($query);
+ $self->db_query($query);
#ALL CONSTRAINTS WERE ADDED
return 1;
-}; # end do_update
+} # end run
sub print_error_message {
- print $main::form->parse_html_template("dbupgrade/tax_constraints");
+ print $::form->parse_html_template("dbupgrade/tax_constraints");
}
-return do_update();
+1;
# @tag: umstellung_eur
# @description: Variable eur umstellen: bitte in doc/dokumentation.pdf das entsprechende Kapitel zur Konfiguration von EUR lesen
# @depends: release_2_6_3
-# @charset: utf-8
-
-# this script relies on $eur still being set in kivitendo.conf, and the
-# variable available in $::lx_office_conf{system}->{eur}
+package SL::DBUpgrade2::umstellung_eur;
+use strict;
use utf8;
-#use strict;
-use Data::Dumper;
-die("This script cannot be run from the command line.") unless ($main::form);
-
-sub mydberror {
- my ($msg) = @_;
- die($dbup_locale->text("Database update error:") .
- "<br>$msg<br>" . $DBI::errstr);
-}
-sub do_query {
- my ($query, $may_fail) = @_;
+use parent qw(SL::DBUpgrade2::Base);
- if (!$dbh->do($query)) {
- mydberror($query) unless ($may_fail);
- $dbh->rollback();
- $dbh->begin_work();
- }
-}
+# this script relies on $eur still being set in kivitendo.conf, and the
+# variable available in $::lx_office_conf{system}->{eur}
-sub do_update {
+sub run {
+ my ($self) = @_;
# check if accounting_method has already been set (new database), if so return
# only set variables according to eur for update of existing database
foreach my $column (qw(accounting_method inventory_system profit_determination)) {
# this query will fail if columns already exist (new database)
- do_query(qq|ALTER TABLE defaults ADD COLUMN ${column} TEXT|, 1);
+ $self->db_query(qq|ALTER TABLE defaults ADD COLUMN ${column} TEXT|, 1);
}
my $accounting_method;
my $update_eur = "UPDATE defaults set accounting_method = '$accounting_method' where accounting_method is null;" .
"UPDATE defaults set inventory_system = '$inventory_system' where inventory_system is null; " .
"UPDATE defaults set profit_determination = '$profit_determination' where profit_determination is null;";
- do_query($update_eur);
+ $self->db_query($update_eur);
return 1;
}
-return do_update();
-
+1;
# @tag: warehouse
# @description: Diverse neue Tabellen und Spalten zur Mehrlagerfähigkeit inkl. Migration
# @depends: release_2_4_3
+package SL::DBUpgrade2::warehouse;
use strict;
+use utf8;
-die("This script cannot be run from the command line.") unless ($main::form);
-
-my $do_sql_migration = 0;
-my ($check_sql, $sqlcode);
-
-sub mydberror {
- my ($msg) = @_;
- die($dbup_locale->text("Database update error:") .
- "<br>$msg<br>" . $DBI::errstr);
-}
-
-sub do_query {
- my ($query, $may_fail) = @_;
-
- if (!$dbh->do($query)) {
- mydberror($query) unless ($may_fail);
- $dbh->rollback();
- $dbh->begin_work();
- }
-}
+use parent qw(SL::DBUpgrade2::Base);
+use SL::DBUtils;
sub print_question {
- print $main::form->parse_html_template("dbupgrade/warehouse_form");
-}
-
-sub do_update {
- if (!$main::form->{do_migrate}
- && (selectfirst_array_query($main::form, $dbh, $check_sql))[0]) { # check if update is needed
- print_question();
- return 2;
- } else {
- if ($main::form->{do_migrate} eq 'Y') {
- # if yes, both warehouse and bin must be given
- if (!$main::form->{import_warehouse} || !$main::form->{bin_default}) {
- print_question();
- return 2;
- }
- # flag for extra code
- $do_sql_migration = 1;
- }
- }
- my $warehouse = $main::form->{import_warehouse} ne '' ? $main::form->{import_warehouse} : "Transfer";
- my $bin = $main::form->{bin_default} ne '' ? $main::form->{bin_default} : "1";
-
- $warehouse = $dbh->quote($warehouse);
- $bin = $dbh->quote($bin);
-
- my $migration_code = <<EOF
-
--- Adjust warehouse
-INSERT INTO warehouse (description, sortkey, invalid) VALUES ($warehouse, 1, FALSE);
-
-UPDATE tmp_parts SET bin = NULL WHERE bin = '';
-
--- Restore old onhand
-INSERT INTO bin
- (warehouse_id, description)
- (SELECT DISTINCT warehouse.id, COALESCE(bin, $bin)
- FROM warehouse, tmp_parts
- WHERE warehouse.description=$warehouse);
-INSERT INTO inventory
- (warehouse_id, parts_id, bin_id, qty, employee_id, trans_id, trans_type_id, chargenumber)
- (SELECT warehouse.id, tmp_parts.id, bin.id, onhand, (SELECT id FROM employee LIMIT 1), nextval('id'), transfer_type.id, ''
- FROM transfer_type, warehouse, tmp_parts, bin
- WHERE warehouse.description = $warehouse
- AND COALESCE(bin, $bin) = bin.description
- AND transfer_type.description = 'stock');
-EOF
-;
-
- # do standard code
- my $query = $sqlcode;
- $query .= $migration_code if $do_sql_migration;
-
- do_query($query);
-
- return 1;
+ print $::form->parse_html_template("dbupgrade/warehouse_form");
}
+sub run {
+ my ($self) = @_;
-
-$sqlcode = <<EOF
+ my $do_sql_migration = 0;
+ my $check_sql = qq|SELECT COUNT(id) FROM parts WHERE onhand > 0;|;
+ my $sqlcode = <<SQL;
-- Table "bin" for bins.
CREATE TABLE bin (
id integer NOT NULL DEFAULT nextval('id'),
CREATE TRIGGER trig_update_onhand
AFTER INSERT OR UPDATE OR DELETE ON inventory
FOR EACH ROW EXECUTE PROCEDURE update_onhand();
-EOF
-;
+SQL
+
+ if (!$::form->{do_migrate}
+ && (selectfirst_array_query($::form, $self->dbh, $check_sql))[0]) { # check if update is needed
+ print_question();
+ return 2;
+ } else {
+ if ($::form->{do_migrate} eq 'Y') {
+ # if yes, both warehouse and bin must be given
+ if (!$::form->{import_warehouse} || !$::form->{bin_default}) {
+ print_question();
+ return 2;
+ }
+ # flag for extra code
+ $do_sql_migration = 1;
+ }
+ }
+ my $warehouse = $::form->{import_warehouse} ne '' ? $::form->{import_warehouse} : "Transfer";
+ my $bin = $::form->{bin_default} ne '' ? $::form->{bin_default} : "1";
+
+ $warehouse = $self->dbh->quote($warehouse);
+ $bin = $self->dbh->quote($bin);
+
+ my $migration_code = <<EOF
+-- Adjust warehouse
+INSERT INTO warehouse (description, sortkey, invalid) VALUES ($warehouse, 1, FALSE);
-$check_sql = <<EOF
-SELECT COUNT(id) FROM parts WHERE onhand > 0;
+UPDATE tmp_parts SET bin = NULL WHERE bin = '';
+
+-- Restore old onhand
+INSERT INTO bin
+ (warehouse_id, description)
+ (SELECT DISTINCT warehouse.id, COALESCE(bin, $bin)
+ FROM warehouse, tmp_parts
+ WHERE warehouse.description=$warehouse);
+INSERT INTO inventory
+ (warehouse_id, parts_id, bin_id, qty, employee_id, trans_id, trans_type_id, chargenumber)
+ (SELECT warehouse.id, tmp_parts.id, bin.id, onhand, (SELECT id FROM employee LIMIT 1), nextval('id'), transfer_type.id, ''
+ FROM transfer_type, warehouse, tmp_parts, bin
+ WHERE warehouse.description = $warehouse
+ AND COALESCE(bin, $bin) = bin.description
+ AND transfer_type.description = 'stock');
EOF
;
-return do_update();
+ # do standard code
+ my $query = $sqlcode;
+ $query .= $migration_code if $do_sql_migration;
+
+ $self->db_query($query);
+
+ return 1;
+}
+
+1;
$finder->find(\$text);
- }, "."
-);
+ }, "./templates", "./doc",
+ );
if (@fails) {
ok(0, join "\n", @fails);
--- /dev/null
+use strict;
+
+use Test::More;
+
+use lib 't';
+use Support::TestSetup;
+
+Support::TestSetup::login();
+
+use SL::Common;
+
+sub test_truncate {
+ is(Common::truncate('nothing to do', at => -1), '...', 'truncation length < 0: at least 3');
+ is(Common::truncate('nothing to do', at => 0), '...', 'truncation length = 0: at least 3');
+ is(Common::truncate('nothing to do', at => 1), '...', 'truncation length = 1: at least 3');
+ is(Common::truncate('nothing to do', at => 2), '...', 'truncation length = 2: at least 3');
+ is(Common::truncate('nothing to do', at => 3), '...', 'truncation length = 3: at least 3');
+ is(Common::truncate('nothing to do', at => 4), 'n...', 'truncation length = 4');
+ is(Common::truncate('nothing to do', at => 9), 'nothin...', 'text length equal to truncation + 4');
+ is(Common::truncate('nothing to do', at => 10), 'nothing...', 'text length equal to truncation + 3');
+ is(Common::truncate('nothing to do', at => 11), 'nothing ...', 'text length equal to truncation + 2');
+ is(Common::truncate('nothing to do', at => 12), 'nothing t...', 'text length equal to truncation + 1');
+ is(Common::truncate('nothing to do', at => 13), 'nothing to do', 'text length equal to truncation');
+ is(Common::truncate('nothing to do', at => 14), 'nothing to do', 'text length equal to truncation - 1');
+ is(Common::truncate('nothing to do', at => 15), 'nothing to do', 'text length equal to truncation - 2');
+ is(Common::truncate('nothing to do', at => 16), 'nothing to do', 'text length equal to truncation - 3');
+ is(Common::truncate('nothing to do', at => 200), 'nothing to do', 'text length smaller than truncation');
+
+ is(Common::truncate('012345678901234567890123456789012345678901234567890123456789'), '01234567890123456789012345678901234567890123456...', 'default truncation length of 50');
+
+ # Test stripping
+ is(Common::truncate("nothing\n\rat\rall\n\n", at => 50, strip => 1), "nothing\n\rat\rall", 'strip = 1, at = 50');
+ is(Common::truncate("nothing\n\rat\rall\n\n", at => 13, strip => 1), "nothing\n\ra...", 'strip = 1, at = 13');
+
+ is(Common::truncate("nothing\n\rat\rall\n\n", at => 50, strip => 'full'), "nothing at all", 'strip = full, at = 50');
+ is(Common::truncate("nothing\n\rat\rall\n\n", at => 13, strip => 'full'), "nothing at...", 'strip = full, at = 13');
+
+ is(Common::truncate("nothing\n\rat\rall\n\n", at => 50, strip => 'newlines'), "nothing at all", 'strip = newlines, at = 50');
+ is(Common::truncate("nothing\n\rat\rall\n\n", at => 13, strip => 'newlines'), "nothing at...", 'strip = newlines, at = 13');
+
+ is(Common::truncate("nothing\n\rat\rall\n\n", at => 50, strip => 'newline'), "nothing at all", 'strip = newline, at = 50');
+ is(Common::truncate("nothing\n\rat\rall\n\n", at => 13, strip => 'newline'), "nothing at...", 'strip = newline, at = 13');
+}
+
+test_truncate();
+
+done_testing;
+
+1;
use Support::TestSetup;
use SL::Presenter;
+use SL::Controller::Base;
+use SL::Layout::Javascript;
no warnings 'uninitialized';
-use Test::More tests => 51;
+use Test::More;
use Test::Exception;
use strict;
use Data::Dumper;
use Support::TestSetup;
-use_ok 'SL::DB::RequirementSpec';
-use_ok 'SL::DB::RequirementSpecItem';
-use_ok 'SL::DB::RequirementSpecTextBlock';
+eval {
+ require 'SL::DB::RequirementSpec';
+ require 'SL::DB::RequirementSpecItem';
+ require 'SL::DB::RequirementSpecTextBlock';
+ 1;
+} or my $skip = 'RequirementSpec is not available for this test';
+
+if ($skip) {
+ plan skip_all => $skip;
+} else {
+ plan tests => 48;
+}
sub reset_state {
"SL::DB::Manager::${_}"->delete_all(all => 1) for qw(RequirementSpecTextBlock RequirementSpecItem RequirementSpec);
--- /dev/null
+use Test::More tests => 8;
+
+use strict;
+
+use lib 't';
+
+use SL::Util qw(camelify);
+
+is(camelify('hello'), 'Hello', 'hello');
+is(camelify('hello_world'), 'HelloWorld', 'hello_world');
+is(camelify('hello_world_'), 'HelloWorld_', 'hello_world_');
+is(camelify('charlie_the_unicorn'), 'CharlieTheUnicorn', 'charlie_the_unicorn');
+is(camelify('_charlie_the_unicorn'), 'CharlieTheUnicorn', '_charlie_the_unicorn');
+is(camelify('hello__world'), 'HelloWorld', 'hello__world');
+is(camelify('hELLO'), 'HELLO', 'hELLO');
+is(camelify('hellO_worlD'), 'HellOWorlD', 'hellO_worlD');
--- /dev/null
+use Test::More tests => 52;
+
+use strict;
+
+use lib 't';
+
+use_ok 'SL::Util';
+
+sub numtest {
+ my @result = SL::Util::_hashify(@_);
+ return scalar(@result);
+}
+
+sub memtest {
+ my $key = shift;
+ my $keep = $_[0];
+ my @result = SL::Util::_hashify(@_);
+ splice @result, 0, $keep;
+
+ return '<empty>' if !@result;
+ return '<odd-sized>' if scalar(@result) % 2;
+
+ my %hash = @result;
+ return $hash{$key};
+}
+
+my $href = { 42 => 54, unicorn => 'charlie' };
+my %hash = ( 23 => 13, chunky => 'bacon' );
+
+is(numtest(0, $href), 4, 'case A1');
+is(numtest(0, %hash), 4, 'case A2');
+is(numtest(1, $href), 1, 'case A3');
+is(numtest(1, %hash), 4, 'case A4');
+is(numtest(2, $href), 1, 'case A5');
+is(numtest(2, %hash), 4, 'case A6');
+is(numtest(3, $href), 1, 'case A7');
+is(numtest(3, %hash), 4, 'case A8');
+is(numtest(4, $href), 1, 'case A9');
+is(numtest(4, %hash), 4, 'case A10');
+is(numtest(5, $href), 1, 'case A11');
+is(numtest(5, %hash), 4, 'case A12');
+
+is(numtest(0, 'dummy1', $href), 2, 'case B1');
+is(numtest(0, 'dummy1', %hash), 5, 'case B2');
+is(numtest(1, 'dummy1', $href), 5, 'case B3');
+is(numtest(1, 'dummy1', %hash), 5, 'case B4');
+is(numtest(2, 'dummy1', $href), 2, 'case B5');
+is(numtest(2, 'dummy1', %hash), 5, 'case B6');
+is(numtest(3, 'dummy1', $href), 2, 'case B7');
+is(numtest(3, 'dummy1', %hash), 5, 'case B8');
+is(numtest(4, 'dummy1', $href), 2, 'case B9');
+is(numtest(4, 'dummy1', %hash), 5, 'case B10');
+is(numtest(5, 'dummy1', $href), 2, 'case B11');
+is(numtest(5, 'dummy1', %hash), 5, 'case B12');
+
+is(numtest(0, 'dummy1', 'dummy2', $href), 3, 'case C1');
+is(numtest(0, 'dummy1', 'dummy2', %hash), 6, 'case C2');
+is(numtest(1, 'dummy1', 'dummy2', $href), 3, 'case C3');
+is(numtest(1, 'dummy1', 'dummy2', %hash), 6, 'case C4');
+is(numtest(2, 'dummy1', 'dummy2', $href), 6, 'case C5');
+is(numtest(2, 'dummy1', 'dummy2', %hash), 6, 'case C6');
+is(numtest(3, 'dummy1', 'dummy2', $href), 3, 'case C7');
+is(numtest(3, 'dummy1', 'dummy2', %hash), 6, 'case C8');
+is(numtest(4, 'dummy1', 'dummy2', $href), 3, 'case C9');
+is(numtest(4, 'dummy1', 'dummy2', %hash), 6, 'case C10');
+is(numtest(5, 'dummy1', 'dummy2', $href), 3, 'case C11');
+is(numtest(5, 'dummy1', 'dummy2', %hash), 6, 'case C12');
+
+is(memtest(42, 0, $href), '54', 'case D1');
+is(memtest(23, 0, %hash), '13', 'case D2');
+is(memtest('unicorn', 0, $href), 'charlie', 'case D3');
+is(memtest('chunky', 0, %hash), 'bacon', 'case D4');
+is(memtest(42, 1, $href), '<empty>', 'case D5');
+is(memtest(23, 1, %hash), '<odd-sized>', 'case D6');
+
+is(memtest(42, 0, 'dummy1', $href), undef, 'case E1');
+is(memtest(23, 0, 'dummy1', %hash), '<odd-sized>', 'case E2');
+is(memtest('unicorn', 0, 'dummy1', $href), undef, 'case E3');
+is(memtest(42, 1, 'dummy1', $href), '54', 'case E4');
+is(memtest(23, 1, 'dummy1', %hash), '13', 'case E5');
+is(memtest('unicorn', 1, 'dymmy1', $href), 'charlie', 'case E6');
+is(memtest('chunky', 1, 'dummy1', %hash), 'bacon', 'case E7');
+is(memtest(42, 2, 'dummy1', $href), '<empty>', 'case E8');
+is(memtest(23, 2, 'dummy1', %hash), '<odd-sized>', 'case E9');
--- /dev/null
+use Test::More tests => 7;
+
+use strict;
+
+use lib 't';
+
+use SL::Util qw(snakify);
+
+is(snakify('Hello'), 'hello', 'Hello');
+is(snakify('HelloWorld'), 'hello_world', 'helloWorld');
+is(snakify('HelloWorld_'), 'hello_world_', 'helloWorld_');
+is(snakify('charlieTheUnicorn'), 'charlie_the_unicorn', 'charlieTheUnicorn');
+is(snakify('_CharlieTheUnicorn'), '_charlie_the_unicorn', '_CharlieTheUnicorn');
+is(snakify('HEllo'), 'h_ello', 'HEllo');
+is(snakify('HELlo'), 'h_e_llo', 'HELlo');
--- /dev/null
+use Test::More tests => 14;
+use Test::Exception;
+
+use strict;
+
+use lib 't';
+use utf8;
+
+use Data::Dumper;
+use Support::TestSetup;
+
+use_ok 'SL::PrefixedNumber';
+
+sub n {
+ return SL::PrefixedNumber->new(number => $_[0]);
+}
+
+is(n('FB4711' )->get_next, 'FB4712', 'increment FB4711');
+is(n('4711' )->get_next, '4712', 'increment 4711');
+is(n('FB54UFB4711')->get_next, 'FB54UFB4712', 'increment FB54UFB4711');
+is(n('FB' )->get_next, 'FB1', 'increment FB');
+is(n('' )->get_next, '1', 'increment ""');
+is(n('0042-FB' )->get_next, '0042-FB1', 'increment 0042-FB');
+my $o = n('0042-FB');
+$o->get_next;
+is($o->get_next, '0042-FB2', 'increment 0042-FB twice');
+
+is(n('FB4711')->set_to(54), 'FB0054', 'set FB4711 to 54');
+$o = n('FB4711');
+$o->set_to(54);
+is($o->get_next, 'FB0055', 'set FB4711 to 54 then increment');
+
+is(n('FB121231')->get_current, 'FB121231', 'set FB121231 get current');
+is(n('FB121231')->format(42), 'FB000042', 'set FB121231 format 42');
+is(n('FB123123')->set_to_max('FB0711', 'FB911', 'FB8'), 'FB000911', 'set FB123123 max FB000911');
+
+throws_ok { n()->get_next } qr/no.*number/i, 'get_next without number set';
<tr>
<th align="right" nowrap>[% 'Last RFQ Number' | $T8 %]</th>
<td><input name="rfqnumber" size="10" value="[% HTML.escape(defaults_rfqnumber) %]"></td>
+ <th align="right" nowrap>[% 'Last Assembly Number' | $T8 %]</th>
+ <td><input name="assemblynumber" size="10" value="[% HTML.escape(defaults_assemblynumber) %]"></td>
</tr>
<tr>
<th align="right" nowrap>[% 'Last Sales Delivery Order Number' | $T8 %]</th>
<td><input name="sdonumber" size="10" value="[% HTML.escape(defaults_sdonumber) %]"></td>
+ </tr>
+
+ <tr>
<th align="right" nowrap>[% 'Last Purchase Delivery Order Number' | $T8 %]</th>
<td><input name="pdonumber" size="10" value="[% HTML.escape(defaults_pdonumber) %]"></td>
</tr>
[%- USE T8 %]
[%- USE HTML %]
+[%- USE L %]
<form method="post" action="am.pl">
<input type="hidden" name="id" value="[% HTML.escape(id) %]">
<input type="hidden" name="type" value="tax">
<table width="100%">
<tr>
<td>[% 'tax_taxkey' | $T8 %]</td>
- <td><input name="taxkey" size="2" value="[% HTML.escape(taxkey) %]" [% readonly %]></td>
+ <td>[% IF tax_already_used %]<p>[% HTML.escape(taxkey) %]</p>
+ <input type="hidden" name="taxkey" size="2" value="[% HTML.escape(taxkey) %]">
+ [% ELSE %]<input name="taxkey" size="2" value="[% HTML.escape(taxkey) %]">
+ [% END %]</td>
</tr>
<tr>
<tr>
<td>[% 'tax_percent' | $T8 %]</td>
- <td><input name="rate" size="10" value="[% HTML.escape(rate) %]" [% readonly %]> %</td>
+ <td>[% IF tax_already_used %]<p>[% HTML.escape(rate) %] %</p>
+ <input type="hidden" name="rate" size="10" value="[% HTML.escape(rate) %]">
+ [% ELSE %]<input name="rate" size="10" value="[% HTML.escape(rate) %]"> %
+ [% END %]</td>
</tr>
<tr>
<td><select name="chart_id"><option value="0">[% 'None' | $T8 %]</option>[% FOREACH row = ACCOUNTS %]<option value="[% HTML.escape(row.id) %]" [% IF row.selected %]selected[% END %]>[% HTML.escape(row.taxaccount) %]</option>[% END %]</select></td>
</tr>
+ <td>[% 'Account categories' | $T8 %]</td>
+ <td><table>
+ <colgroup>
+ <col width="10">
+ <col width="130">
+ <col width="10">
+ <col width="130">
+ <col width="10">
+ <col width="130">
+ <col width="10">
+ <col width="130">
+ <col width="10">
+ <col width="130">
+ <col width="10">
+ <col width="130">
+ </colgroup>
+ <tr>
+ <td align="right">[% IF asset %]
+ [% L.checkbox_tag('asset', value => 1, checked => 1, class => 'checkbox') %]
+ [% ELSE %]
+ [% L.checkbox_tag('asset', value => 1, checked => 0, class => 'checkbox') %]
+ [% END %]
+ </td>
+ <td align="left">[% 'Asset' | $T8 %] (A)</td>
+ <td align="right">[% IF liability %]
+ [% L.checkbox_tag('liability', value => 1, checked => 1, class => 'checkbox') %]
+ [% ELSE %]
+ [% L.checkbox_tag('liability', value => 1, checked => 0, class => 'checkbox') %]
+ [% END %]
+ </td>
+ <td align="left">[% 'Liability' | $T8 %] (L)</td>
+ <td align="right">[% IF equity %]
+ [% L.checkbox_tag('equity', value => 1, checked => 1, class => 'checkbox') %]
+ [% ELSE %]
+ [% L.checkbox_tag('equity', value => 1, checked => 0, class => 'checkbox') %]
+ [% END %]
+ </td>
+ <td align="left">[% 'Equity' | $T8 %] (Q)</td>
+ <td align="right">[% IF revenue %]
+ [% L.checkbox_tag('revenue', value => 1, checked => 1, class => 'checkbox') %]
+ [% ELSE %]
+ [% L.checkbox_tag('revenue', value => 1, checked => 0, class => 'checkbox') %]
+ [% END %]
+ </td>
+ <td align="left">[% 'Revenue' | $T8 %] (I)</td>
+ <td align="right">[% IF expense %]
+ [% L.checkbox_tag('expense', value => 1, checked => 1, class => 'checkbox') %]
+ [% ELSE %]
+ [% L.checkbox_tag('expense', value => 1, checked => 0, class => 'checkbox') %]
+ [% END %]
+ </td>
+ <td align="left">[% 'Expense' | $T8 %] (E)</td>
+ <td align="right">[% IF costs %]
+ [% L.checkbox_tag('costs', value => 1, checked => 1, class => 'checkbox') %]
+ [% ELSE %]
+ [% L.checkbox_tag('costs', value => 1, checked => 0, class => 'checkbox') %]
+ [% END %]
+ </td>
+ <td align="left">[% 'Costs' | $T8 %] (C)</td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+
+ </table>
</table>
[% UNLESS orphaned %]
<p>[% saved_message | html %]</p>
[% END %]
+<div class="tabwidget">
+ <ul>
+ <li><a href="#ui-tabs-basic-data">[% 'Basic Data' | $T8 %]</a></li>
+[%- IF id %]
+ <li><a href="controller.pl?action=RecordLinks/ajax_list&object_model=PurchaseInvoice&object_id=[% HTML.url(id) %]">[% 'Linked Records' | $T8 %]</a></li>
+[%- END %]
+ </ul>
+
+<div id="ui-tabs-basic-data">
<table width="100%">
<tr valign="top">
<td>
</table>
</td>
</tr>
- <tr>
- <td><hr size="3" noshade></td>
- </tr>
</table>
+</div>
+</div>
[% L.hidden_tag('follow_up_trans_info_1', follow_up_trans_info) %]
[% L.hidden_tag('follow_up_rowcount', 1) %]
+<h1>[% title | html %]</h1>
+
[%- IF saved_message %]<p>[% saved_message | html %]</p>[% END %]
+<div class="tabwidget">
+ <ul>
+ <li><a href="#ui-tabs-basic-data">[% 'Basic Data' | $T8 %]</a></li>
+[%- IF id %]
+ <li><a href="controller.pl?action=RecordLinks/ajax_list&object_model=Invoice&object_id=[% HTML.url(id) %]">[% 'Linked Records' | $T8 %]</a></li>
+[%- END %]
+ </ul>
+
+<div id="ui-tabs-basic-data">
<table width=100%>
- <tr class=listtop>
- <th class=listtop>[% title | html %]</th>
- </tr>
- <tr height="5"></tr>
<tr valign=top>
<td>
<table width=100%>
</table>
</td>
</tr>
- <tr>
- <td><hr size=3 noshade></td>
- </tr>
</table>
+</div>
+</div>
+[% PROCESS 'common/flash.html' %]
<div id='csv_import_report'></div>
<script type='text/javascript'>
--- /dev/null
+[%- USE LxERP -%][%- USE L -%]
+<tr>
+ <th align="right">[%- LxERP.t8("Existing contacts (with column 'cp_id')") %]:</th>
+ <td colspan="10">
+ [% opts = [ [ 'update_existing', LxERP.t8('Update properties of existing entries') ], [ 'insert_new', LxERP.t8('Insert with new database ID') ], [ 'skip', LxERP.t8('Skip entry') ] ] %]
+ [% L.select_tag('settings.update_policy', opts, default = SELF.profile.get('update_policy'), style = 'width: 300px') %]
+ </td>
+</tr>
[% L.select_tag('settings.table', opts, default = SELF.profile.get('table'), style = 'width: 300px') %]
</td>
</tr>
+
+<tr>
+ <th align="right">[%- LxERP.t8('Existing customers/vendors with same customer/vendor number') %]:</th>
+ <td colspan="10">
+ [% opts = [ [ 'update_existing', LxERP.t8('Update properties of existing entries') ], [ 'insert_new', LxERP.t8('Insert with new customer/vendor number') ], [ 'skip', LxERP.t8('Skip entry') ] ] %]
+ [% L.select_tag('settings.update_policy', opts, default = SELF.profile.get('update_policy'), style = 'width: 300px') %]
+ </td>
+</tr>
[%- IF SELF.type == 'contacts' %]
<p>
+ [%- LxERP.t8("You can update existing contacts by providing the 'cp_id' column with their database IDs. Otherwise: ") %]
[%- LxERP.t8('At least one of the columns #1, customer, customernumber, vendor, vendornumber (depending on the target table) is required for matching the entry to an existing customer or vendor.', 'cp_cv_id') %]
</p>
[%- INCLUDE 'csv_import/_form_parts.html' %]
[%- ELSIF SELF.type == 'customers_vendors' %]
[%- INCLUDE 'csv_import/_form_customers_vendors.html' %]
+[%- ELSIF SELF.type == 'contacts' %]
+ [%- INCLUDE 'csv_import/_form_contacts.html' %]
[%- END %]
<tr>
</td>
</tr>
- <tr>
- <td colspan="2"><hr></td>
- </tr>
-
- <tr>
- <th align="left" nowrap>[% 'Bcc' | $T8 %]</th>
- <td><input name="bcc" size="40" value="[% HTML.escape(bcc) %]"></td>
- </tr>
[% IF CUSTOM_VARIABLES.Contacts.size %]
<tr>
<td colspan="2"><hr></td>
<td><input name="email" size="45" value="[% HTML.escape(email) %]"></td>
</tr>
+ <tr>
+ <th align="right" nowrap>[% 'Cc E-mail' | $T8 %]</th>
+ <td><input name="cc" size="45" value="[% HTML.escape(cc) %]"></td>
+ </tr>
+
+ <tr>
+ <th align="right" nowrap>[% 'Bcc E-mail' | $T8 %]</th>
+ <td><input name="bcc" size="45" value="[% HTML.escape(bcc) %]"></td>
+ </tr>
+
+
<tr>
<th align="right" nowrap>
[% IF homepage %]<a href="[% HTML.escape(homepage) %]" title="[% 'Open this Website' | $T8 %]" target="_blank">[% 'Homepage' | $T8 %]</a>
<td><input name="taxnumber" size="20" value="[% HTML.escape(taxnumber) %]"></td>
<!-- Anm.: R&B 15.11.2008 VAT Reg No ist Ust-ID in GB, aber generell sollte es laut Richardson die sales tax id sein -->
<th align="right">[% 'sales tax identification number' | $T8 %]</th>
- <td><input name="ustid" id="ustid" maxlength="14" size="20" value="[% HTML.escape(ustid) %]"></td>
+ <td>[% L.input_tag('ustid', ustid, maxlength=14, size=30) %]</td>
[%- IF is_customer %]
<th align="right">[% 'our vendor number at customer' | $T8 %]</th>
- <td><input name="c_vendor_id" size="10" value="[% HTML.escape(c_vendor_id) %]"></td>
+ <td>[% L.input_tag('c_vendor_id', c_vendor_id, size=30) %]</td>
[%- ELSE %]
<th align="right">[% 'Customer Number' | $T8 %]</th>
- <td><input name="v_customer_id" size="10" value="[% HTML.escape(v_customer_id) %]"></td>
+ <td>[% L.input_tag('v_customer_id', v_customer_id, size=30) %]</td>
[%- END %]
</tr>
<tr>
<th align="right">[% 'Account Number' | $T8 %]</th>
- <td><input name="account_number" size="10" maxlength="100" value="[% HTML.escape(account_number) %]"></td>
+ <td>[% L.input_tag('account_number', account_number, size=30) %]</td>
<th align="right">[% 'Bank Code Number' | $T8 %]</th>
- <td><input name="bank_code" size="10" maxlength="100" value="[% HTML.escape(bank_code) %]"></td>
+ <td>[% L.input_tag('bank_code', bank_code, size=30) %]</td>
<th align="right">[% 'Bank' | $T8 %]</th>
- <td><input name="bank" size="20" value="[% HTML.escape(bank) %]"></td>
+ <td>[% L.input_tag('bank', bank, size=30) %]</td>
</tr>
<tr>
<th align="right">[% 'IBAN' | $T8 %]</th>
- <td><input name="iban" size="10" maxlength="100" value="[% HTML.escape(iban) %]"></td>
+ <td>[% L.input_tag('iban', iban, maxlength=100, size=30) %]</td>
<th align="right">[% 'BIC' | $T8 %]</th>
- <td><input name="bic" size="10" maxlength="100" value="[% HTML.escape(bic) %]"></td>
+ <td>[% L.input_tag('bic', bic, maxlength=100, size=30) %]</td>
[%- IF ALL_CURRENCIES.size %]
<th align="right">[% 'Currency' | $T8 %]</th>
<td>[% L.select_tag('currency', ALL_CURRENCIES, default = currency, with_empty = 1) %]</td>
<input name="l.cp_mobile" id="l_cp_mobile" type="checkbox" class="checkbox" value="Y" checked>
<label for="l_cp_mobile">[% 'Mobile' | $T8 %]</label>
</td>
- <td>
- <input name="l.cp_email" id="l_cp_email" type="checkbox" class="checkbox" value="Y" checked>
- <label for="l_cp_email">[% 'E-mail' | $T8 %]</label>
- </td>
+
+ <td>[%- L.checkbox_tag('l.cp_privatphone', value='Y', label=LxERP.t8('Private Phone'), class='checkbox', checked=1) %]</td>
+ </tr>
+
+ <tr>
+ <td>[%- L.checkbox_tag('l.cp_fax', value='Y', label=LxERP.t8('Fax'), class='checkbox') %]</td>
+ <td>[%- L.checkbox_tag('l.cp_email', value='Y', label=LxERP.t8('E-mail'), class='checkbox', checked=1) %]</td>
+ <td>[%- L.checkbox_tag('l.cp_privatemail', value='Y', label=LxERP.t8('Private E-mail'), class='checkbox') %]</td>
</tr>
<tr>
- <td>
- <input name="l.cp_birthday" id="l_cp_birthday" type="checkbox" class="checkbox" value="Y">
- <label for="l_cp_birthday">[% 'Birthday' | $T8 %]</label>
- </td>
<td>
<input name="l.cp_abteilung" id="l_cp_abteilung" type="checkbox" class="checkbox" value="Y">
<label for="l_cp_abteilung">[% 'Department' | $T8 %]</label>
<input name="l.cp_gender" id="l_cp_gender" type="checkbox" class="checkbox" value="Y">
<label for="l_cp_gender">[% 'Gender' | $T8 %]</label>
</td>
+
+ <td>
+ <input name="l.cp_birthday" id="l_cp_birthday" type="checkbox" class="checkbox" value="Y">
+ <label for="l_cp_birthday">[% 'Birthday' | $T8 %]</label>
+ </td>
</tr>
[% CUSTOM_VARIABLES_INCLUSION_CODE %]
--- /dev/null
+[%- USE T8 %]
+[% USE HTML %]<div class="listtop">[% 'Double partnumbers' | $T8 %]</div>
+
+<form name="Form" method="post" action="login.pl">
+<input type="hidden" name="action" value="login">
+<input type="hidden" name="continued" value="1">
+
+<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>[% 'Please change the partnumber of the following parts and run the update again:' | $T8 %]</p>
+<table>
+ <tr>
+ <th class="listheading">[% 'Partnumber' | $T8 %]</th>
+ <th class="listheading">[% 'Description' | $T8 %]</th>
+ <th class="listheading">[% 'Unit' | $T8 %]</th>
+ <th class="listheading">[% 'Notes' | $T8 %]</th>
+ <th class="listheading">[% 'EAN' | $T8 %]</th>
+ <th class="listheading">[% 'Service, assembly or part' | $T8 %]</th>
+ </tr>
+
+ [% SET row_odd = '1' %][% FOREACH row = PARTS %]
+ <tr class="listrow[% IF row_odd %]1[% SET row_odd = '0' %][% ELSE %]0[% SET row_odd = '1' %][% END %]">
+ <td align="right"><input name='partnumber_[% loop.count %]' value='[% HTML.escape(row.partnumber) %]'></td>
+ <input type="hidden" name='partid_[% loop.count %]' value='[% HTML.escape(row.id) %]'>
+ <td align="left"> [% HTML.escape(row.description) %]</a></td>
+ <td align="right">[% HTML.escape(row.unit) %]</td>
+ <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>
+ </tr>
+ [% SET rowcount = loop.count %]
+ [% END %]
+ <input type="hidden" name="rowcount" value="[% rowcount %]">
+</table>
+
+<input type="submit" value="[% 'Continue' | $T8 %]">
+
+</form>
--- /dev/null
+
+[% USE T8 %]
+[% USE HTML %]
+[% USE L %]
+<div class="listtop">[% 'New filter for tax accounts' | $T8 %]</div>
+
+<form name="Form" method="post" action="login.pl">
+<input type="hidden" name="action" value="login">
+<input type="hidden" name="continued" 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>
+<p>[% 'If you have not chosen for example the category revenue for a tax and you choose an revenue account to create a transfer in the general ledger, this tax will not be displayed in the tax dropdown.' | $T8 %]</p>
+<p>[% 'This feature especially prevents mistakes by mixing up prior tax and sales tax.' | $T8 %]</p>
+<p>[% 'Please choose for which categories the taxes should be displayed:' | $T8 %]</p>
+<table>
+ <tr>
+ <th class="listheading">[% 'Taxkey' | $T8 %]</th>
+ <th class="listheading">[% 'Description' | $T8 %]</th>
+ <th class="listheading">[% 'Tax rate' | $T8 %]</th>
+ <th class="listheading">[% 'Asset' | $T8 %] (A)</th>
+ <th class="listheading">[% 'Liability' | $T8 %] (L)</th>
+ <th class="listheading">[% 'Equity' | $T8 %] (Q)</th>
+ <th class="listheading">[% 'Costs' | $T8 %] (C)</th>
+ <th class="listheading">[% 'Revenue' | $T8 %] (I)</th>
+ <th class="listheading">[% 'Expense' | $T8 %] (E)</th>
+ </tr>
+
+ [% SET row_odd = '1' %][% FOREACH row = PARTS %]
+ <tr class="listrow[% IF row_odd %]1[% SET row_odd = '0' %][% ELSE %]0[% SET row_odd = '1' %][% END %]">
+ <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>
+ </tr>
+ <input type="hidden" name="tax_id_[% loop.count %]" value="[% row.tax_id %]">
+ [% SET rowcount = loop.count %]
+ [% END %]
+ <input type="hidden" name="rowcount" value="[% rowcount %]">
+</table>
+
+<input type="submit" value="[% 'Continue' | $T8 %]">
+
+</form>
[%- USE L %]
<script type="text/javascript">
<!--
- function setTaxkey(row) {
- var accno = document.getElementById('accno_' + row);
- var taxkey = accno.options[accno.selectedIndex].value;
- var reg = /--([0-9]*)/;
- var found = reg.exec(taxkey);
- var index = found[1];
- index = parseInt(index);
- var tax = 'taxchart_' + row;
- for (var i = 0; i < document.getElementById(tax).options.length; ++i) {
- var reg2 = new RegExp("^"+ index, "");
- if (reg2.exec(document.getElementById(tax).options[i].value)) {
- document.getElementById(tax).options[i].selected = true;
- break;
- }
+function updateTaxes(row)
+{
+ var accno = document.getElementById('accno_' + row);
+ var taxkey = accno.options[accno.selectedIndex].value;
+ var reg = /--([0-9]*)/;
+ var found = reg.exec(taxkey);
+ var index = found[1];
+ index = parseInt(index);
+ var tax = 'taxchart_' + row;
+ var taxkeyposition = taxkey.lastIndexOf(found[0]);
+ var account = taxkey.substr(0, taxkeyposition);
+
+ var xmlhttp;
+ if (window.XMLHttpRequest)
+ {// code for IE7+, Firefox, Chrome, Opera, Safari
+ xmlhttp=new XMLHttpRequest();
+ }
+ else
+ {// code for IE6, IE5
+ xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");
+ }
+ xmlhttp.onreadystatechange=function()
+ {
+ if (xmlhttp.readyState==4 && xmlhttp.status==200)
+ {
+ var element = document.getElementById("taxchart_" + row);
+ element.innerHTML = xmlhttp.responseText;
}
- };
+ }
+ xmlhttp.open("GET","gl.pl?action=get_tax_dropdown&accno=" + account + "&select_index=" + index,true);
+ xmlhttp.send();
+};
function copy_debit_to_credit() {
var txt = document.getElementsByName('debit_1')[0].value;
</tr>
<tr>
<th align=right>[% 'Employee' | $T8 %]</th>
- <td colspan=3>[% L.select_tag('employee', ALL_EMPLOYEES, title_key = 'safe_name', with_empty = 1) %]</td>
+ <td colspan=3>[% L.select_tag('employee_id', ALL_EMPLOYEES, title_key = 'safe_name', with_empty = 1) %]</td>
</tr>
<tr>
<th align=right>[% 'Filter date by' | $T8 %]</th>
--- /dev/null
+[% FOR row = TAX_ACCOUNTS %]
+<option value='[% row.id %]--[% row.rate %]' [% IF row.id == select_index %]selected[% END %]>[% row.taxdescription %] %</option>
+[% END %]
<td valign="top">
[% L.radio_button_tag("periodicity", value => "m", label => LxERP.t8("monthly"), checked => periodicity == 'm') %]
<br>
- [% L.radio_button_tag("periodicity", value => "q", label => LxERP.t8("quarterly"), checked => periodicity == 'q') %]
+ [% L.radio_button_tag("periodicity", value => "q", label => LxERP.t8("every third month"), checked => periodicity == 'q') %]
<br>
[% L.radio_button_tag("periodicity", value => "y", label => LxERP.t8("yearly"), checked => periodicity == 'y') %]
</td>
<script type="text/javascript">
<!--
-$(function() {
-
-});
-
function record_links_add() {
- var url = "controller.pl?action=RecordLinks/ajax_add_filter&object_model=[% JavaScript.escape(object_model) %]&object_id=[% JavaScript.escape(object_id) %]&";
- var id = 'record_links_add';
-
- $('#' + id).remove();
- var div = $('<div id="' + id + '" class="jqmWindow record_list_overlay"></div>').hide().appendTo('body');
- var close = $('<div class="close"></div>').appendTo(div);
- var content = $('<div class="overlay_content"></div>').appendTo(div);
- div.jqm({ modal: true });
- div.jqmShow();
- $.ajax({ url: url, success: function(new_html) { $(content).html(new_html); } });
- $(close).click(function() {
- div.jqmHide();
- div.remove();
- });
+ open_jqm_window({ url: 'controller.pl',
+ data: { action: 'RecordLinks/ajax_add_filter',
+ object_model: '[% JavaScript.escape(object_model) %]',
+ object_id: '[% JavaScript.escape(object_id) %]'
+ },
+ id: 'record_links_add' });
+ return true;
}
function record_links_delete() {
<tr>
<th align=right nowrap>[% 'Difference' | $T8 %]</th>
<td width=10%></td>
- <td align=right><input name=null size=11 value="[% LxERP.format_amount(difference, 2, 0) %]"></td>
+ <td align=right><input name=null size=11 value="[% LxERP.format_amount(difference, 2, 0) %]" readonly></td>
<input type=hidden name=difference value="[% LxERP.format_amount(difference, 2, 0) %]">
</tr>
</table>
[% L.button_tag('filter_record_links()', LxERP.t8("Search")) %]
[% L.button_tag('add_selected_record_links()', LxERP.t8("Add links"), id='add_selected_record_links_button', disabled=1) %]
<a href="#" onclick="record_links_reset_form();">[%- LxERP.t8("Reset") %]</a>
- <a href="#" onclick="record_links_cancel();">[% LxERP.t8("Cancel") %]</a>
+ <a href="#" onclick="$('#record_links_add').jqmClose();">[% LxERP.t8("Cancel") %]</a>
</p>
<hr>
$('.jqmWindow form select').prop('selectedIndex', 0);
}
-function record_links_cancel() {
- $('.jqmWindow').jqmHide();
- $('.jqmWindow').remove();
-}
-
function filter_record_links() {
var url="controller.pl?action=RecordLinks/ajax_add_list&" + $(".jqmWindow form").serialize();
$.ajax({
url: url,
success: function(new_html) {
$('#record_links_list').replaceWith(new_html);
- record_links_cancel();
+ $('#record_links_add').jqmClose();
}
});
}
[% FOREACH row = Q %]
<tr>
<td></td>
- <td>[% row.description %]</td>
+ <td>[% row.accno _ ' - ' IF l_accno and row.accno %][% row.description %]</td>
<td align="right">[% LxERP.format_amount(row.this, decimalplaces) %]</td>
[%- IF last_period %]
<td align="right">[% LxERP.format_amount(row.last, decimalplaces) %]</td>
<tr>
<th align=right>[% 'as at' | $T8 %]</th>
<td> [% L.date_tag('asofdate', asofdate) %]</td>
+ <td><input name=l_cb class=checkbox type=checkbox value=Y> [% 'CB Transactions' | $T8 %]</td>
+ <td><input name=l_ob class=checkbox type=checkbox value=Y> [% 'only OB Transactions' | $T8 %]</td>
+ </tr>
+ </tr>
<th align=right nowrap>[% 'Compare to' | $T8 %]</th>
<td>[% L.date_tag('compareasofdate', compareasofdate) %]</td>
+ <td><input name=l_cb_compared class=checkbox type=checkbox value=Y> [% 'CB Transactions' | $T8 %]</td>
+ <td><input name=l_ob_compared class=checkbox type=checkbox value=Y> [% 'only OB Transactions' | $T8 %]</td>
</tr>
<tr>
<th align=right>[% 'Decimalplaces' | $T8 %]</th>
<input name=l_subtotal class=checkbox type=checkbox value=Y> [% 'Subtotal' | $T8 %]
<input name=l_accno class=checkbox type=checkbox value=Y> [% 'Account Number' | $T8 %]</td>
</tr>
- <tr>
- <th></th>
- <td><input name=l_cb class=checkbox type=checkbox value=Y> [% 'CB Transactions' | $T8 %]
- <input name=l_ob class=checkbox type=checkbox value=Y> [% 'only OB Transactions' | $T8 %]</td>
- </tr>
[%- END %]
[%- IF is_trial_balance %]
<td align="right">[% LxERP.format_amount(invoice.invoice_amount, -2) %]</td>
<td align="right">[% LxERP.format_amount(invoice.open_amount, -2) %]</td>
<td align="right">[% invoice.duedate %]</td>
- <td><input name="bank_transfers[].reference" value="[% HTML.escape(invoice.reference_prefix _ invoice.invnumber) %]"></td>
+ <td>
+ [%- SET reference = invoice.reference_prefix _ invoice.invnumber %]
+ <input name="bank_transfers[].reference" value="[% HTML.escape(reference.substr(0, 140)) %]" maxlength="140" size="60">
+ </td>
<td align="right">
- <input name="bank_transfers[].amount" value="[% LxERP.format_amount(invoice.invoice_amount, -2) %]" style="text-align: right">
+ <input name="bank_transfers[].amount" value="[% LxERP.format_amount(invoice.invoice_amount, -2) %]" style="text-align: right" size="12">
</td>
</tr>
[%- END %]
<input type="hidden" name="vc_bank_info[].name" value="[% HTML.escape(vbi.name) %]">
[% HTML.escape(vbi.name) %]
</td>
- <td><input name="vc_bank_info[].iban" size="20" value="[% HTML.escape(vbi.iban) %]"></td>
- <td><input name="vc_bank_info[].bic" size="20" value="[% HTML.escape(vbi.bic) %]"></td>
+ <td><input name="vc_bank_info[].iban" size="34" value="[% HTML.escape(vbi.iban.substr(0, 34)) %]" maxlength="34"></td>
+ <td><input name="vc_bank_info[].bic" size="20" value="[% HTML.escape(vbi.bic.substr(0, 20)) %]" maxlength="20"></td>
<td><input name="vc_bank_info[].bank" size="30" value="[% HTML.escape(vbi.bank) %]"></td>
</tr>
[%- END %]
<td align="right">[% LxERP.format_amount(bank_transfer.invoice_amount, -2) %]</td>
<td align="right">[% LxERP.format_amount(bank_transfer.open_amount, -2) %]</td>
- <td><input name="bank_transfers[].reference" value="[% HTML.escape(bank_transfer.reference) %]"></td>
- <td align="right"><input name="bank_transfers[].amount" value="[% LxERP.format_amount(bank_transfer.amount, -2) %]" style="text-align: right"></td>
+ <td>
+ <input name="bank_transfers[].reference" value="[% HTML.escape(bank_transfer.reference.substr(0, 140)) %]" size="60" maxlength="140">
+ </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) %]
</td>
<input type="hidden" name="vc" value="[%- HTML.escape(vc) %]">
<input type="hidden" name="confirmation" value="1">
</form>
-
<table>
+
+ <tr>
+ <td align="right">[% 'Main sorting' | $T8 %]</td>
+ <td>
+ <select name="mainsort" id="mainsort">
+ <option value="description">[% 'Part' | $T8 %]</option>
+ <option value="customername">[% 'Customer' | $T8 %]</option>
+ <option value="country">[% 'Country' | $T8 %]</option>
+ <option value="partsgroup">[% 'Group' | $T8 %]</option>
+ <option value="business">[% 'Customer type' | $T8 %]</option>
+ <option value="salesman" selected="selected">[% 'Salesman' | $T8 %]</option>
+ <option value="month">[% 'Month' | $T8 %]</option>
+ </select>
+ </td>
+ <td align=left><input name="l_headers_mainsort" class=checkbox type=checkbox value=Y checked> [% 'Heading' | $T8 %]</td>
+ <td align=left><input name="l_subtotal_mainsort" class=checkbox type=checkbox value=Y checked> [% 'Subtotal' | $T8 %]</td>
+ </tr>
+
+ <tr>
+ <td align="right">[% 'Secondary sorting' | $T8 %]</td>
+ <td>
+ <select name="subsort" id="subsort">
+ <option value="description">[% 'Part' | $T8 %]</option>
+ <option value="customername">[% 'Customer' | $T8 %]</option>
+ <option value="country">[% 'Country' | $T8 %]</option>
+ <option value="partsgroup">[% 'Group' | $T8 %]</option>
+ <option value="business">[% 'Customer type' | $T8 %]</option>
+ <option value="salesman">[% 'Salesman' | $T8 %]</option>
+ <option value="month" selected="selected">[% 'Month' | $T8 %]</option>
+ </select>
+ </td>
+ <td align=left><input name="l_headers_subsort" class=checkbox type=checkbox value=Y checked> [% 'Heading' | $T8 %]</td>
+ <td align=left><input name="l_subtotal_subsort" class=checkbox type=checkbox value=Y checked> [% 'Subtotal' | $T8 %]</td>
+ </tr>
+
+ <tr>
+ <th align="right">[% 'Item mode' | $T8 %]</th>
+ <td colspan="3" align=left><input name="l_parts" class=checkbox type=checkbox value=Y> ([%'Show items from invoices individually' | $T8 %]) </td>
+ </tr>
+
+ <tr>
+ <th align="right">[% 'Total sum' | $T8 %]</th>
+ <td colspan="1" align=left><input name="l_total" class=checkbox type=checkbox value=Y checked></td>
+ <td align="right" nowrap>[% 'Decimalplaces' | $T8 %]: </td>
+ <td colspan="2"><input name="decimalplaces" size="2" value="2"></td>
+ </tr>
+
+ <tr>
+ <td></td>
+ <td colspan="7">
+ <hr size="1" noshade="">
+ </td>
+ <tr>
+
<tr>
<th align=right>[% 'Customer' | $T8 %]</th>
<td>
</td>
</tr>
-
-
- <tr>
- <td></td>
- <td colspan="7">
- <hr size="1" noshade="">
- </td>
- <tr>
-
-
-
- <tr>
- <td align="right">[% 'Main sorting' | $T8 %]</td>
- <td>
- <select name="mainsort" id="mainsort">
- <option value="description">[% 'Part' | $T8 %]</option>
- <option value="customername">[% 'Customer' | $T8 %]</option>
- <option value="country">[% 'Country' | $T8 %]</option>
- <option value="partsgroup">[% 'Group' | $T8 %]</option>
- <option value="business">[% 'Customer type' | $T8 %]</option>
- <option value="salesman" selected="selected">[% 'Salesman' | $T8 %]</option>
- <option value="month">[% 'Month' | $T8 %]</option>
- </select>
- </td>
- <td align=left><input name="l_headers_mainsort" class=checkbox type=checkbox value=Y checked> [% 'Heading' | $T8 %]</td>
- <td align=left><input name="l_subtotal_mainsort" class=checkbox type=checkbox value=Y checked> [% 'Subtotal' | $T8 %]</td>
- </tr>
-
- <tr>
- <td align="right">[% 'Secondary sorting' | $T8 %]</td>
- <td>
- <select name="subsort" id="subsort">
- <option value="description">[% 'Part' | $T8 %]</option>
- <option value="customername">[% 'Customer' | $T8 %]</option>
- <option value="country">[% 'Country' | $T8 %]</option>
- <option value="partsgroup">[% 'Group' | $T8 %]</option>
- <option value="business">[% 'Customer type' | $T8 %]</option>
- <option value="salesman">[% 'Salesman' | $T8 %]</option>
- <option value="month" selected="selected">[% 'Month' | $T8 %]</option>
- </select>
- </td>
- <td align=left><input name="l_headers_subsort" class=checkbox type=checkbox value=Y checked> [% 'Heading' | $T8 %]</td>
- <td align=left><input name="l_subtotal_subsort" class=checkbox type=checkbox value=Y checked> [% 'Subtotal' | $T8 %]</td>
- </tr>
-
- <tr>
- <th align="right">[% 'Item mode' | $T8 %]</th>
- <td colspan="3" align=left><input name="l_parts" class=checkbox type=checkbox value=Y> ([%'Show items from invoices individually' | $T8 %]) </td>
- </tr>
-
- <tr>
- <th align="right">[% 'Total sum' | $T8 %]</th>
- <td colspan="1" align=left><input name="l_total" class=checkbox type=checkbox value=Y checked></td>
- <td align="right" nowrap>[% 'Decimalplaces' | $T8 %]: </td>
- <td colspan="2"><input name="decimalplaces" size="2" value="2"></td>
- </tr>
</table>
<hr size="3" noshade="">