From: Jan Büren
Date: Sat, 10 Oct 2009 09:05:08 +0000 (+0200)
Subject: Änderungen für den SEPA-Export
X-Git-Tag: release-2.6.1beta1~237^2~3
X-Git-Url: http://wagnertech.de/git?a=commitdiff_plain;h=1c603341fc02e3a5a7b5126cd7df6478d2e34700;p=kivitendo-erp.git
Änderungen für den SEPA-Export
---
diff --git a/SL/Chart.pm b/SL/Chart.pm
new file mode 100644
index 000000000..5d3c7d334
--- /dev/null
+++ b/SL/Chart.pm
@@ -0,0 +1,49 @@
+package SL::Chart;
+
+use strict;
+
+use SL::Form;
+use SL::DBUtils;
+
+sub list {
+ $main::lxdebug->enter_sub();
+
+ my $self = shift;
+ my %params = @_;
+
+ my $myconfig = \%main::myconfig;
+ my $form = $main::form;
+
+ my $dbh = $params{dbh} || $form->get_standard_dbh($myconfig);
+
+ my @values = ();
+ my @where = ();
+
+ if ($params{link}) {
+ if ($params{link} =~ '%') {
+ push @where, "c.link LIKE ?";
+ push @values, $params{link};
+
+ } else {
+ push @where, "(c.link = ?) OR (c.link LIKE ?) OR (c.link LIKE ?) OR (c.link LIKE ?)";
+ push @values, $params{link}, '%:' . $params{link} . ':%', '%:' . $params{link}, $params{link} . ':%';
+ }
+ }
+
+ my $where = scalar @where ? 'WHERE ' . join(' AND ', map { "($_)" } @where) : '';
+
+ my $query =
+ qq|SELECT c.id, c.accno, c.description, c.link
+ FROM chart c
+ $where
+ ORDER BY c.accno|;
+
+ my $charts = selectall_hashref_query($form, $dbh, $query, @values);
+
+ $main::lxdebug->leave_sub();
+
+ return $charts;
+}
+
+1;
+
diff --git a/SL/SEPA.pm b/SL/SEPA.pm
new file mode 100644
index 000000000..05e1ec610
--- /dev/null
+++ b/SL/SEPA.pm
@@ -0,0 +1,407 @@
+package SL::SEPA;
+
+use strict;
+
+use POSIX qw(strftime);
+
+use SL::DBUtils;
+
+sub retrieve_open_invoices {
+ $main::lxdebug->enter_sub();
+
+ my $self = shift;
+ my %params = @_;
+
+ my $myconfig = \%main::myconfig;
+ my $form = $main::form;
+
+ my $dbh = $params{dbh} || $form->get_standard_dbh($myconfig);
+
+ my $query =
+ qq|
+ SELECT ap.id, ap.invnumber, ap.vendor_id, ap.amount AS invoice_amount, ap.invoice,
+ v.name AS vendorname,
+
+ COALESCE(v.iban, '') <> '' AND COALESCE(v.bic, '') <> '' AS vendor_bank_info_ok,
+
+ ap.amount - ap.paid - COALESCE(open_transfers.amount, 0) AS open_amount
+
+ FROM ap
+ LEFT JOIN vendor v ON (ap.vendor_id = v.id)
+ LEFT JOIN (SELECT sei.ap_id, SUM(sei.amount) AS amount
+ FROM sepa_export_items sei
+ LEFT JOIN sepa_export se ON (sei.sepa_export_id = se.id)
+ WHERE NOT se.closed
+ GROUP BY sei.ap_id)
+ AS open_transfers ON (ap.id = open_transfers.ap_id)
+
+ WHERE ap.amount > (COALESCE(open_transfers.amount, 0) + ap.paid)
+
+ ORDER BY lower(v.name) ASC, lower(ap.invnumber) ASC
+|;
+
+ my $results = selectall_hashref_query($form, $dbh, $query);
+
+ $main::lxdebug->leave_sub();
+
+ return $results;
+}
+
+sub create_export {
+ $main::lxdebug->enter_sub();
+
+ my $self = shift;
+ my %params = @_;
+
+ Common::check_params(\%params, qw(employee bank_transfers));
+
+ my $myconfig = \%main::myconfig;
+ my $form = $main::form;
+
+ my $dbh = $params{dbh} || $form->get_standard_dbh($myconfig);
+
+ my ($export_id) = selectfirst_array_query($form, $dbh, qq|SELECT nextval('sepa_export_id_seq')|);
+ my $query =
+ qq|INSERT INTO sepa_export (id, employee_id)
+ VALUES (?, (SELECT id
+ FROM employee
+ WHERE login = ?))|;
+ do_query($form, $dbh, $query, $export_id, $params{employee});
+
+ my $q_item_id = qq|SELECT nextval('id')|;
+ my $h_item_id = prepare_query($form, $dbh, $q_item_id);
+
+ my $q_insert =
+ qq|INSERT INTO sepa_export_items (id, sepa_export_id, ap_id, chart_id,
+ amount, requested_execution_date, reference, end_to_end_id,
+ our_iban, our_bic, vendor_iban, vendor_bic)
+ VALUES (?, ?, ?, ?,
+ ?, ?, ?, ?,
+ ?, ?, ?, ?)|;
+ my $h_insert = prepare_query($form, $dbh, $q_insert);
+
+ my $q_reference =
+ qq|SELECT ap.invnumber,
+ (SELECT COUNT(at.*)
+ FROM acc_trans at
+ LEFT JOIN chart c ON (at.chart_id = c.id)
+ WHERE (at.trans_id = ?)
+ AND (c.link LIKE '%AP_paid%'))
+ +
+ (SELECT COUNT(sei.*)
+ FROM sepa_export_items sei
+ WHERE (sei.ap_id = ?))
+ AS num_payments
+ FROM ap
+ WHERE id = ?|;
+ my $h_reference = prepare_query($form, $dbh, $q_reference);
+
+ my @now = localtime;
+
+ foreach my $transfer (@{ $params{bank_transfers} }) {
+ if (!$transfer->{reference}) {
+ do_statement($form, $h_reference, $q_reference, (conv_i($transfer->{ap_id})) x 3);
+
+ my ($invnumber, $num_payments) = $h_reference->fetchrow_array();
+ $num_payments++;
+
+ $transfer->{reference} = "${invnumber}-${num_payments}";
+ }
+
+ $h_item_id->execute();
+ my ($item_id) = $h_item_id->fetchrow_array();
+
+ my $end_to_end_id = strftime "LXO%Y%m%d%H%M%S", localtime;
+ my $item_id_len = length "$item_id";
+ my $num_zeroes = 35 - $item_id_len - length $end_to_end_id;
+ $end_to_end_id .= '0' x $num_zeroes if (0 < $num_zeroes);
+ $end_to_end_id .= $item_id;
+ $end_to_end_id = substr $end_to_end_id, 0, 35;
+
+ my @values = ($item_id, $export_id,
+ conv_i($transfer->{ap_id}), conv_i($transfer->{chart_id}),
+ $transfer->{amount}, conv_date($transfer->{requested_execution_date}),
+ $transfer->{reference}, $end_to_end_id,
+ map { my $pfx = $_; map { $transfer->{"${pfx}_${_}"} } qw(iban bic) } qw(our vendor));
+
+ do_statement($form, $h_insert, $q_insert, @values);
+ }
+
+ $h_insert->finish();
+ $h_item_id->finish();
+
+ $dbh->commit() unless ($params{dbh});
+
+ $main::lxdebug->leave_sub();
+
+ return $export_id;
+}
+
+sub retrieve_export {
+ $main::lxdebug->enter_sub();
+
+ my $self = shift;
+ my %params = @_;
+
+ Common::check_params(\%params, qw(id));
+
+ my $myconfig = \%main::myconfig;
+ my $form = $main::form;
+
+ my $dbh = $params{dbh} || $form->get_standard_dbh($myconfig);
+
+ my ($joins, $columns);
+
+ if ($params{details}) {
+ $columns = ', ap.invoice';
+ $joins = 'LEFT JOIN ap ON (se.ap_id = ap.id)';
+ }
+
+ my $query =
+ qq|SELECT se.*,
+ CASE WHEN COALESCE(e.name, '') <> '' THEN e.name ELSE e.login END AS employee
+ FROM sepa_export se
+ LEFT JOIN employee e ON (se.employee_id = e.id)
+ WHERE se.id = ?|;
+
+ my $export = selectfirst_hashref_query($form, $dbh, $query, conv_i($params{id}));
+
+ if ($export->{id}) {
+ my ($columns, $joins);
+
+ if ($params{details}) {
+ $columns = qq|, ap.invnumber, ap.invoice, v.name AS vendor_name, c.accno AS chart_accno, c.description AS chart_description|;
+ $joins = qq|LEFT JOIN ap ON (sei.ap_id = ap.id)
+ LEFT JOIN vendor v ON (ap.vendor_id = v.id)
+ LEFT JOIN chart c ON (sei.chart_id = c.id)|;
+ }
+
+ $query = qq|SELECT sei.*
+ $columns
+ FROM sepa_export_items sei
+ $joins
+ WHERE sei.sepa_export_id = ?|;
+ $export->{items} = selectall_hashref_query($form, $dbh, $query, conv_i($params{id}));
+
+ } else {
+ $export->{items} = [];
+ }
+
+ $main::lxdebug->leave_sub();
+
+ return $export;
+}
+
+sub close_export {
+ $main::lxdebug->enter_sub();
+
+ my $self = shift;
+ my %params = @_;
+
+ Common::check_params(\%params, qw(id));
+
+ my $myconfig = \%main::myconfig;
+ my $form = $main::form;
+
+ my $dbh = $params{dbh} || $form->get_standard_dbh($myconfig);
+
+ my @ids = ref $params{id} eq 'ARRAY' ? @{ $params{id} } : ($params{id});
+ my $placeholders = join ', ', ('?') x scalar @ids;
+ my $query = qq|UPDATE sepa_export SET closed = TRUE WHERE id IN ($placeholders)|;
+
+ do_query($form, $dbh, $query, map { conv_i($_) } @ids);
+
+ $dbh->commit() unless ($params{dbh});
+
+ $main::lxdebug->leave_sub();
+}
+
+sub list_exports {
+ $main::lxdebug->enter_sub();
+
+ my $self = shift;
+ my %params = @_;
+
+ my $myconfig = \%main::myconfig;
+ my $form = $main::form;
+
+ my $dbh = $params{dbh} || $form->get_standard_dbh($myconfig);
+
+ my %sort_columns = (
+ 'id' => [ 'se.id', ],
+ 'export_date' => [ 'se.itime', ],
+ 'employee' => [ 'e.name', 'se.id', ],
+ 'executed' => [ 'se.executed', 'se.id', ],
+ 'closed' => [ 'se.closed', 'se.id', ],
+ );
+
+ my %sort_spec = create_sort_spec('defs' => \%sort_columns, 'default' => 'id', 'column' => $params{sortorder}, 'dir' => $params{sortdir});
+
+ my (@where, @values, @where_sub, @values_sub, %joins_sub);
+
+ my $filter = $params{filter} || { };
+
+ foreach (qw(executed closed)) {
+ push @where, $filter->{$_} ? "se.$_" : "NOT se.$_" if (exists $filter->{$_});
+ }
+
+ my %operators = ('from' => '>=',
+ 'to' => '<=');
+
+ foreach my $dir (qw(from to)) {
+ next unless ($filter->{"export_date_${dir}"});
+ push @where, "se.itime $operators{$dir} ?::date";
+ push @values, $filter->{"export_date_${dir}"};
+ }
+
+ if ($filter->{invnumber}) {
+ push @where_sub, "ap.invnumber ILIKE ?";
+ push @values_sub, '%' . $filter->{invnumber} . '%';
+ $joins_sub{ap} = 1;
+ }
+
+ if ($filter->{vendor}) {
+ push @where_sub, "v.name ILIKE ?";
+ push @values_sub, '%' . $filter->{vendor} . '%';
+ $joins_sub{ap} = 1;
+ $joins_sub{vendor} = 1;
+ }
+
+ foreach my $type (qw(requested_execution execution)) {
+ foreach my $dir (qw(from to)) {
+ next unless ($filter->{"${type}_date_${dir}"});
+ push @where_sub, "(items.${type}_date IS NOT NULL) AND (items.${type}_date $operators{$dir} ?)";
+ push @values_sub, $filter->{"${type}_date_${_}"};
+ }
+ }
+
+ if (@where_sub) {
+ my $joins_sub = '';
+ $joins_sub .= ' LEFT JOIN ap ON (items.ap_id = ap.id)' if ($joins_sub{ap});
+ $joins_sub .= ' LEFT JOIN vendor v ON (ap.vendor_id = v.id)' if ($joins_sub{vendor});
+
+ my $where_sub = join(' AND ', map { "(${_})" } @where_sub);
+
+ my $query_sub = qq|se.id IN (SELECT items.sepa_export_id
+ FROM sepa_export_items items
+ $joins_sub
+ WHERE $where_sub)|;
+
+ push @where, $query_sub;
+ push @values, @values_sub;
+ }
+
+ my $where = ' WHERE ' . join(' AND ', map { "(${_})" } @where) if (@where);
+
+ my $query =
+ qq|SELECT se.id, se.employee_id, se.executed, se.closed, itime::date AS export_date,
+ e.name AS employee
+ FROM sepa_export se
+ LEFT JOIN (
+ SELECT emp.id,
+ CASE WHEN COALESCE(emp.name, '') <> '' THEN emp.name ELSE emp.login END AS name
+ FROM employee emp
+ ) AS e ON (se.employee_id = e.id)
+ $where
+ ORDER BY $sort_spec{sql}|;
+
+ my $results = selectall_hashref_query($form, $dbh, $query, @values);
+
+ $main::lxdebug->leave_sub();
+
+ return $results;
+}
+
+sub post_payment {
+ $main::lxdebug->enter_sub();
+
+ my $self = shift;
+ my %params = @_;
+
+ Common::check_params(\%params, qw(items));
+
+ my $myconfig = \%main::myconfig;
+ my $form = $main::form;
+
+ my $dbh = $params{dbh} || $form->get_standard_dbh($myconfig);
+
+ my @items = ref $params{items} eq 'ARRAY' ? @{ $params{items} } : ($params{items});
+
+ my %handles = (
+ 'get_item' => [ qq|SELECT sei.*
+ FROM sepa_export_items sei
+ WHERE sei.id = ?| ],
+
+ 'get_ap' => [ qq|SELECT at.chart_id
+ FROM acc_trans at
+ LEFT JOIN chart c ON (at.chart_id = c.id)
+ WHERE (trans_id = ?)
+ AND ((c.link LIKE '%:AP') OR (c.link LIKE 'AP:%') OR (c.link = 'AP'))
+ LIMIT 1| ],
+
+ 'add_acc_trans' => [ qq|INSERT INTO acc_trans (trans_id, chart_id, amount, transdate, gldate, source, memo)
+ VALUES (?, ?, ?, ?, current_date, ?, '')| ],
+
+ 'update_ap' => [ qq|UPDATE ap
+ SET paid = paid + ?
+ WHERE id = ?| ],
+
+ 'finish_item' => [ qq|UPDATE sepa_export_items
+ SET execution_date = ?, executed = TRUE
+ WHERE id = ?| ],
+
+ 'has_unexecuted' => [ qq|SELECT sei1.id
+ FROM sepa_export_items sei1
+ WHERE (sei1.sepa_export_id = (SELECT sei2.sepa_export_id
+ FROM sepa_export_items sei2
+ WHERE sei2.id = ?))
+ AND NOT COALESCE(sei1.executed, FALSE)
+ LIMIT 1| ],
+
+ 'do_close' => [ qq|UPDATE sepa_export
+ SET executed = TRUE, closed = TRUE
+ WHERE (id = ?)| ],
+ );
+
+ map { unshift @{ $_ }, prepare_query($form, $dbh, $_->[0]) } values %handles;
+
+ foreach my $item (@items) {
+ my $item_id = conv_i($item->{id});
+
+ # Retrieve the item data belonging to the ID.
+ do_statement($form, @{ $handles{get_item} }, $item_id);
+ my $orig_item = $handles{get_item}->[0]->fetchrow_hashref();
+
+ next if (!$orig_item);
+
+ # Retrieve the invoice's AP chart ID.
+ do_statement($form, @{ $handles{get_ap} }, $orig_item->{ap_id});
+ my ($ap_chart_id) = $handles{get_ap}->[0]->fetchrow_array();
+
+ # Record the payment in acc_trans offsetting AP.
+ do_statement($form, @{ $handles{add_acc_trans} }, $orig_item->{ap_id}, $ap_chart_id, -1 * $orig_item->{amount}, $item->{execution_date}, '');
+ do_statement($form, @{ $handles{add_acc_trans} }, $orig_item->{ap_id}, $orig_item->{chart_id}, $orig_item->{amount}, $item->{execution_date}, $orig_item->{reference});
+
+ # Update the invoice to reflect the new paid amount.
+ do_statement($form, @{ $handles{update_ap} }, $orig_item->{amount}, $orig_item->{ap_id});
+
+ # Update the item to reflect that it has been posted.
+ do_statement($form, @{ $handles{finish_item} }, $item->{execution_date}, $item_id);
+
+ # Check whether or not we can close the export itself if there are no unexecuted items left.
+ do_statement($form, @{ $handles{has_unexecuted} }, $item_id);
+ my ($has_unexecuted) = $handles{has_unexecuted}->[0]->fetchrow_array();
+
+ if (!$has_unexecuted) {
+ do_statement($form, @{ $handles{do_close} }, $orig_item->{sepa_export_id});
+ }
+ }
+
+ map { $_->[0]->finish() } values %handles;
+
+ $dbh->commit() unless ($params{dbh});
+
+ $main::lxdebug->leave_sub();
+}
+
+1;
diff --git a/SL/SEPA/XML.pm b/SL/SEPA/XML.pm
new file mode 100644
index 000000000..ee455360f
--- /dev/null
+++ b/SL/SEPA/XML.pm
@@ -0,0 +1,227 @@
+package SL::SEPA::XML;
+
+use strict;
+use utf8;
+
+use Carp;
+use Encode;
+use List::Util qw(first sum);
+use List::MoreUtils qw(any);
+use POSIX qw(strftime);
+use Text::Iconv;
+use XML::Writer;
+
+use SL::SEPA::XML::Transaction;
+
+sub new {
+ my $class = shift;
+ my $self = {};
+
+ bless $self, $class;
+
+ $self->_init(@_);
+
+ return $self;
+}
+
+sub _init {
+ my $self = shift;
+ my %params = @_;
+
+ $self->{transactions} = [];
+ $self->{src_charset} = 'UTF-8';
+ $self->{grouped} = 0;
+
+ map { $self->{$_} = $params{$_} if (exists $params{$_}) } qw(src_charset company message_id grouped);
+
+ $self->{iconv} = Text::Iconv->new($self->{src_charset}, "UTF-8") || croak "Unsupported source charset $self->{src_charset}.";
+
+ my $missing_parameter = first { !$self->{$_} } qw(company message_id);
+ croak "Missing parameter: $missing_parameter" if ($missing_parameter);
+
+ map { $self->{$_} = $self->_replace_special_chars(decode('UTF-8', $self->{iconv}->convert($self->{$_}))) } qw(company message_id);
+}
+
+sub add_transaction {
+ my $self = shift;
+
+ foreach my $transaction (@_) {
+ croak "Expecting hash reference." if (ref $transaction ne 'HASH');
+ push @{ $self->{transactions} }, SL::SEPA::XML::Transaction->new(%{ $transaction }, 'sepa' => $self);
+ }
+
+ return 1;
+}
+
+sub _replace_special_chars {
+ my $self = shift;
+ my $text = shift;
+
+ my %special_chars = (
+ 'ä' => 'ae',
+ 'ö' => 'oe',
+ 'ü' => 'ue',
+ 'Ã' => 'Ae',
+ 'Ã' => 'Oe',
+ 'Ã' => 'Ue',
+ 'Ã' => 'ss',
+ '&' => '+',
+ );
+
+ map { $text =~ s/$_/$special_chars{$_}/g; } keys %special_chars;
+
+ return $text;
+}
+
+sub _format_amount {
+ my $self = shift;
+ my $amount = shift;
+
+ return sprintf '%d.%02d', int($amount), int($amount * 100) % 100;
+}
+
+sub _group_transactions {
+ my $self = shift;
+
+ my $grouped = {
+ 'sum_amount' => 0,
+ 'groups' => { },
+ };
+
+ foreach my $transaction (@{ $self->{transactions} }) {
+ my $key = $self->{grouped} ? join("\t", map { $transaction->get($_) } qw(src_bic src_iban execution_date)) : 'all';
+ $grouped->{groups}->{$key} ||= {
+ 'sum_amount' => 0,
+ 'transactions' => [ ],
+ };
+
+ push @{ $grouped->{groups}->{$key}->{transactions} }, $transaction;
+
+ $grouped->{groups}->{$key}->{sum_amount} += $transaction->{amount};
+ $grouped->{sum_amount} += $transaction->{amount};
+ }
+
+ return $grouped;
+}
+
+sub to_xml {
+ my $self = shift;
+
+ croak "No transactions added yet." if (!@{ $self->{transactions} });
+
+ my $output = '';
+
+ my $xml = XML::Writer->new(OUTPUT => \$output,
+ DATA_MODE => 1,
+ DATA_INDENT => 2,
+ ENCODING => 'utf-8');
+
+ my @now = localtime;
+ my $time_zone = strftime "%z", @now;
+ my $now_str = strftime('%Y-%m-%dT%H:%M:%S', @now) . substr($time_zone, 0, 3) . ':' . substr($time_zone, 3, 2);
+
+ my $grouped_transactions = $self->_group_transactions();
+
+ $xml->xmlDecl();
+ $xml->startTag('Document',
+ 'xmlns' => 'urn:sepade:xsd:pain.001.001.02.grp',
+ 'xmlns:xsi' => 'http://www.w3.org/2001/XMLSchema-instance',
+ 'xsi:schemaLocation' => 'urn:sepade:xsd:pain.001.001.02.grp pain.001.001.02.grp.xsd');
+
+ $xml->startTag('pain.001.001.02');
+
+ $xml->startTag('GrpHdr');
+ $xml->dataElement('MsgId', encode('UTF-8', substr($self->{message_id}, 0, 35)));
+ $xml->dataElement('CreDtTm', $now_str);
+ $xml->dataElement('NbOfTxs', scalar @{ $self->{transactions} });
+ $xml->dataElement('CtrlSum', $self->_format_amount($grouped_transactions->{sum_amount}));
+ $xml->dataElement('Grpg', 'MIXD');
+
+ $xml->startTag('InitgPty');
+ $xml->dataElement('Nm', encode('UTF-8', substr($self->{company}, 0, 70)));
+ $xml->endTag('InitgPty');
+
+ $xml->endTag('GrpHdr');
+
+ foreach my $key (keys %{ $grouped_transactions->{groups} }) {
+ my $transaction_group = $grouped_transactions->{groups}->{$key};
+ my $master_transaction = $transaction_group->{transactions}->[0];
+
+ $xml->startTag('PmtInf');
+ $xml->dataElement('PmtMtd', 'TRF');
+
+ $xml->startTag('PmtTpInf');
+ $xml->startTag('SvcLvl');
+ $xml->dataElement('Cd', 'SEPA');
+ $xml->endTag('SvcLvl');
+ $xml->endTag('PmtTpInf');
+
+ $xml->dataElement('ReqdExctnDt', $master_transaction->get('execution_date'));
+ $xml->startTag('Dbtr');
+ $xml->dataElement('Nm', encode('UTF-8', substr($self->{company}, 0, 70)));
+ $xml->endTag('Dbtr');
+
+ $xml->startTag('DbtrAcct');
+ $xml->startTag('Id');
+ $xml->dataElement('IBAN', $master_transaction->get('src_iban', 34));
+ $xml->endTag('Id');
+ $xml->endTag('DbtrAcct');
+
+ $xml->startTag('DbtrAgt');
+ $xml->startTag('FinInstnId');
+ $xml->dataElement('BIC', $master_transaction->get('src_bic', 20));
+ $xml->endTag('FinInstnId');
+ $xml->endTag('DbtrAgt');
+
+ $xml->dataElement('ChrgBr', 'SLEV');
+
+ foreach my $transaction (@{ $transaction_group->{transactions} }) {
+ $xml->startTag('CdtTrfTxInf');
+
+ $xml->startTag('PmtId');
+ $xml->dataElement('EndToEndId', $transaction->get('end_to_end_id', 35));
+ $xml->endTag('PmtId');
+
+ $xml->startTag('Amt');
+ $xml->startTag('InstdAmt', 'Ccy' => 'EUR');
+ $xml->characters($self->_format_amount($transaction->{amount}));
+ $xml->endTag('InstdAmt');
+ $xml->endTag('Amt');
+
+ $xml->startTag('CdtrAgt');
+ $xml->startTag('FinInstnId');
+ $xml->dataElement('BIC', $transaction->get('dst_bic', 20));
+ $xml->endTag('FinInstnId');
+ $xml->endTag('CdtrAgt');
+
+ $xml->startTag('Cdtr');
+ $xml->dataElement('Nm', $transaction->get('recipient', 70));
+ $xml->endTag('Cdtr');
+
+ $xml->startTag('CdtrAcct');
+ $xml->startTag('Id');
+ $xml->dataElement('IBAN', $transaction->get('dst_iban', 34));
+ $xml->endTag('Id');
+ $xml->endTag('CdtrAcct');
+
+ $xml->startTag('RmtInf');
+ $xml->dataElement('Ustrd', $transaction->get('reference', 140));
+ $xml->endTag('RmtInf');
+
+ $xml->endTag('CdtTrfTxInf');
+ }
+
+ $xml->endTag('PmtInf');
+ }
+
+ $xml->endTag('pain.001.001.02');
+ $xml->endTag('Document');
+
+ return $output;
+}
+
+1;
+
+# Local Variables:
+# coding: utf-8
+# End:
diff --git a/SL/SEPA/XML/Transaction.pm b/SL/SEPA/XML/Transaction.pm
new file mode 100644
index 000000000..8849b4192
--- /dev/null
+++ b/SL/SEPA/XML/Transaction.pm
@@ -0,0 +1,54 @@
+package SL::SEPA::XML::Transaction;
+
+use strict;
+
+use Carp;
+use Encode;
+use List::Util qw(first);
+use POSIX qw(strftime);
+use Text::Iconv;
+
+sub new {
+ my $class = shift;
+ my $self = {};
+
+ bless $self, $class;
+
+ $self->_init(@_);
+
+ return $self;
+}
+
+sub _init {
+ my $self = shift;
+ my %params = @_;
+
+ $self->{sepa} = $params{sepa};
+ delete $params{sepa};
+
+ my $missing_parameter = first { !$params{$_} } qw(src_iban src_bic dst_iban dst_bic recipient reference amount end_to_end_id);
+ croak "Missing parameter: $missing_parameter" if ($missing_parameter);
+
+ $params{end_to_end_id} ||= 'NOTPROVIDED';
+ $params{execution_date} ||= strftime "%Y-%m-%d", localtime;
+
+ croak "Execution date format wrong for '$params{execution_date}': not YYYY-MM-DD." if ($params{execution_date} !~ /^\d{4}-\d{2}-\d{2}$/);
+
+ map { $self->{$_} = decode('UTF-8', $self->{sepa}->{iconv}->convert($params{$_})) } keys %params;
+ map { $self->{$_} =~ s/\s+//g } qw(src_iban src_bic dst_iban dst_bic);
+ map { $self->{$_} = $self->{sepa}->_replace_special_chars($self->{$_}) } qw(recipient reference end_to_end_id);
+}
+
+sub get {
+ my $self = shift;
+ my $key = shift;
+ my $max_len = shift;
+
+ return undef if (!defined $self->{$key});
+
+ my $str = $max_len ? substr($self->{$key}, 0, $max_len) : $self->{$key};
+
+ return encode('UTF-8', $str);
+}
+
+1;
diff --git a/bankaccounts.pl b/bankaccounts.pl
new file mode 120000
index 000000000..385000d1b
--- /dev/null
+++ b/bankaccounts.pl
@@ -0,0 +1 @@
+am.pl
\ No newline at end of file
diff --git a/bin/mozilla/bankaccounts.pl b/bin/mozilla/bankaccounts.pl
new file mode 100644
index 000000000..0815954dc
--- /dev/null
+++ b/bin/mozilla/bankaccounts.pl
@@ -0,0 +1,162 @@
+use strict;
+
+use POSIX qw(strftime);
+
+use SL::BankAccount;
+use SL::Chart;
+use SL::Form;
+use SL::ReportGenerator;
+
+require "bin/mozilla/common.pl";
+require "bin/mozilla/reportgenerator.pl";
+
+sub bank_account_add {
+ $main::lxdebug->enter_sub();
+
+ bank_account_display_form('account' => {});
+
+ $main::lxdebug->leave_sub();
+}
+
+sub bank_account_edit {
+ $main::lxdebug->enter_sub();
+
+ my %params = @_;
+ my $form = $main::form;
+
+ my $account = SL::BankAccount->retrieve('id' => $params{id} || $form->{id});
+
+ bank_account_display_form('account' => $account);
+
+ $main::lxdebug->leave_sub();
+}
+
+sub bank_account_display_form {
+ $main::lxdebug->enter_sub();
+
+ my %params = @_;
+ my $account = $params{account} || {};
+ my $form = $main::form;
+ my $locale = $main::locale;
+
+ my $charts = SL::Chart->list('link' => 'AP_paid');
+ my $label_sub = sub { join '--', map { $_[0]->{$_} } qw(accno description) };
+
+ $form->{title} = $account->{id} ? $locale->text('Edit bank account') : $locale->text('Add bank account');
+
+ $form->header();
+ print $form->parse_html_template('bankaccounts/bank_account_display_form',
+ { 'CHARTS' => $charts,
+ 'account' => $account,
+ 'chart_label' => $label_sub,
+ 'params' => \%params });
+
+ $main::lxdebug->leave_sub();
+}
+
+sub bank_account_save {
+ $main::lxdebug->enter_sub();
+
+ my $form = $main::form;
+ my $locale = $main::locale;
+
+ my $account = $form->{account} && (ref $form->{account} eq 'HASH') ? $form->{account} : { };
+
+ if (any { !$account->{$_} } qw(account_number bank_code iban bic)) {
+ bank_account_display_form('account' => $account,
+ 'error' => $locale->text('You have to fill in at least an account number, the bank code, the IBAN and the BIC.'));
+
+ $main::lxdebug->leave_sub();
+ return;
+ }
+
+ my $id = SL::BankAccount->save(%{ $account });
+
+ if ($form->{callback}) {
+ $form->redirect();
+
+ } else {
+ bank_account_edit('id' => $id);
+ }
+
+ $main::lxdebug->leave_sub();
+}
+
+
+sub bank_account_list {
+ $main::lxdebug->enter_sub();
+
+ my $form = $main::form;
+ my $locale = $main::locale;
+
+ $form->{title} = $locale->text('List of bank accounts');
+
+ $form->{sort} ||= 'account_number';
+ $form->{sortdir} = '1' if (!defined $form->{sortdir});
+
+ $form->{callback} = build_std_url('action=bank_account_list', 'sort', 'sortdir');
+
+ my $accounts = SL::BankAccount->list('sortorder' => $form->{sort},
+ 'sortdir' => $form->{sortdir});
+
+ my $report = SL::ReportGenerator->new(\%main::myconfig, $form);
+
+ my $href = build_std_url('action=bank_account_list');
+
+ my %column_defs = (
+ 'account_number' => { 'text' => $locale->text('Account number'), },
+ 'bank_code' => { 'text' => $locale->text('Bank code'), },
+ 'bank' => { 'text' => $locale->text('Bank'), },
+ 'bic' => { 'text' => $locale->text('BIC'), },
+ 'iban' => { 'text' => $locale->text('IBAN'), },
+ );
+
+ my @columns = qw(account_number bank bank_code bic iban);
+
+ foreach my $name (@columns) {
+ my $sortdir = $form->{sort} eq $name ? 1 - $form->{sortdir} : $form->{sortdir};
+ $column_defs{$name}->{link} = $href . "&sort=$name&sortdir=$sortdir";
+ }
+
+ $report->set_options('raw_bottom_info_text' => $form->parse_html_template('bankaccounts/bank_account_list_bottom'),
+ 'std_column_visibility' => 1,
+ 'output_format' => 'HTML',
+ 'title' => $form->{title},
+ 'attachment_basename' => $locale->text('bankaccounts') . strftime('_%Y%m%d', localtime time),
+ );
+ $report->set_options_from_form();
+
+ $report->set_columns(%column_defs);
+ $report->set_column_order(@columns);
+ $report->set_export_options('bank_account_list');
+ $report->set_sort_indicator($form->{sort}, $form->{sortdir});
+
+ my $edit_url = build_std_url('action=bank_account_edit', 'callback');
+
+ foreach my $account (@{ $accounts }) {
+ my $row = { map { $_ => { 'data' => $account->{$_} } } keys %{ $account } };
+
+ $row->{account_number}->{link} = $edit_url . '&id=' . E($account->{id});
+
+ $report->add_data($row);
+ }
+
+ $report->generate_with_headers();
+
+ $main::lxdebug->leave_sub();
+}
+
+sub dispatcher {
+ my $form = $main::form;
+
+ foreach my $action (qw(bank_account_save bank_account_delete)) {
+ if ($form->{"action_${action}"}) {
+ call_sub($action);
+ return;
+ }
+ }
+
+ $form->error($main::locale->text('No action defined.'));
+}
+
+1;
diff --git a/bin/mozilla/sepa.pl b/bin/mozilla/sepa.pl
new file mode 100755
index 000000000..bf220e380
--- /dev/null
+++ b/bin/mozilla/sepa.pl
@@ -0,0 +1,545 @@
+use strict;
+
+use List::MoreUtils qw(any none uniq);
+use List::Util qw(first);
+use POSIX qw(strftime);
+
+use SL::BankAccount;
+use SL::Chart;
+use SL::CT;
+use SL::Form;
+use SL::ReportGenerator;
+use SL::SEPA;
+use SL::SEPA::XML;
+
+require "bin/mozilla/common.pl";
+require "bin/mozilla/reportgenerator.pl";
+
+sub bank_transfer_add {
+ $main::lxdebug->enter_sub();
+
+ my $form = $main::form;
+ my $locale = $main::locale;
+
+ $form->{title} = $locale->text('Prepare bank transfer via SEPA XML');
+
+ my $bank_accounts = SL::BankAccount->list();
+
+ if (!scalar @{ $bank_accounts }) {
+ $form->error($locale->text('You have not added bank accounts yet.'));
+ }
+
+ my $invoices = SL::SEPA->retrieve_open_invoices();
+
+ if (!scalar @{ $invoices }) {
+ $form->show_generic_information($locale->text('Either there are no open invoices, or you have already initiated bank transfers ' .
+ 'with the open amounts for those that are still open.'));
+ $main::lxdebug->leave_sub();
+ return;
+ }
+
+ my $bank_account_label_sub = sub { $locale->text('Account number #1, bank code #2, #3', $_[0]->{account_number}, $_[0]->{bank_code}, $_[0]->{bank}) };
+
+ $form->header();
+ print $form->parse_html_template('sepa/bank_transfer_add',
+ { 'INVOICES' => $invoices,
+ 'BANK_ACCOUNTS' => $bank_accounts,
+ 'bank_account_label' => $bank_account_label_sub, });
+
+ $main::lxdebug->leave_sub();
+}
+
+sub bank_transfer_create {
+ $main::lxdebug->enter_sub();
+
+ my $form = $main::form;
+ my $locale = $main::locale;
+ my $myconfig = \%main::myconfig;
+
+ $form->{title} = $locale->text('Create bank transfer via SEPA XML');
+
+ my $bank_accounts = SL::BankAccount->list();
+
+ if (!scalar @{ $bank_accounts }) {
+ $form->error($locale->text('You have not added bank accounts yet.'));
+ }
+
+ my $bank_account = first { $form->{bank_account}->{id} == $_->{id} } @{ $bank_accounts };
+
+ if (!$bank_account) {
+ $form->error($locale->text('The selected bank account does not exist anymore.'));
+ }
+
+ my $invoices = SL::SEPA->retrieve_open_invoices();
+ my %invoices_map = map { $_->{id} => $_ } @{ $invoices };
+ my @bank_transfers =
+ map +{ %{ $invoices_map{ $_->{ap_id} } }, %{ $_ } },
+ grep { $_->{selected} && (0 < $_->{amount}) && $invoices_map{ $_->{ap_id} } }
+ map { $_->{amount} = $form->parse_amount($myconfig, $_->{amount}); $_ }
+ @{ $form->{bank_transfers} || [] };
+
+ if (!scalar @bank_transfers) {
+ $form->error($locale->text('You have selected none of the invoices.'));
+ }
+
+ my ($vendor_bank_info);
+ my $error_message;
+
+ if ($form->{confirmation}) {
+ $vendor_bank_info = { map { $_->{id} => $_ } @{ $form->{vendor_bank_info} || [] } };
+
+ foreach my $info (values %{ $vendor_bank_info }) {
+ if (any { !$info->{$_} } qw(iban bic)) {
+ $error_message = $locale->text('The bank information must not be empty.');
+ last;
+ }
+ }
+ }
+
+ if ($error_message || !$form->{confirmation}) {
+ my @vendor_ids = uniq map { $_->{vendor_id} } @bank_transfers;
+ $vendor_bank_info ||= CT->get_bank_info('vc' => 'vendor',
+ 'id' => \@vendor_ids);
+ my @vendor_bank_info = sort { lc $a->{name} cmp lc $b->{name} } values %{ $vendor_bank_info };
+
+ my $bank_account_label_sub = sub { $locale->text('Account number #1, bank code #2, #3', $_[0]->{account_number}, $_[0]->{bank_code}, $_[0]->{bank}) };
+
+ $form->{jsscript} = 1;
+
+ $form->header();
+ print $form->parse_html_template('sepa/bank_transfer_create',
+ { 'BANK_TRANSFERS' => \@bank_transfers,
+ 'BANK_ACCOUNTS' => $bank_accounts,
+ 'VENDOR_BANK_INFO' => \@vendor_bank_info,
+ 'bank_account' => $bank_account,
+ 'bank_account_label' => $bank_account_label_sub,
+ 'error_message' => $error_message,
+ });
+
+ } else {
+ foreach my $bank_transfer (@bank_transfers) {
+ foreach (qw(iban bic)) {
+ $bank_transfer->{"vendor_${_}"} = $vendor_bank_info->{ $bank_transfer->{vendor_id} }->{$_};
+ $bank_transfer->{"our_${_}"} = $bank_account->{$_};
+ }
+
+ $bank_transfer->{chart_id} = $bank_account->{chart_id};
+ }
+
+ my $id = SL::SEPA->create_export('employee' => $form->{login},
+ 'bank_transfers' => \@bank_transfers);
+
+ $form->header();
+ print $form->parse_html_template('sepa/bank_transfer_created', { 'id' => $id });
+ }
+
+ $main::lxdebug->leave_sub();
+}
+
+sub bank_transfer_search {
+ $main::lxdebug->enter_sub();
+
+ my $form = $main::form;
+ my $locale = $main::locale;
+
+ $form->{title} = $locale->text('List of bank transfers');
+ $form->{jsscript} = 1;
+
+ $form->header();
+ print $form->parse_html_template('sepa/bank_transfer_search');
+
+ $main::lxdebug->leave_sub();
+}
+
+
+sub bank_transfer_list {
+ $main::lxdebug->enter_sub();
+
+ my $form = $main::form;
+ my $locale = $main::locale;
+ my $cgi = $main::cgi;
+
+ $form->{title} = $locale->text('List of bank transfers');
+
+ $form->{sort} ||= 'id';
+ $form->{sortdir} = '1' if (!defined $form->{sortdir});
+
+ $form->{callback} = build_std_url('action=bank_transfer_list', 'sort', 'sortdir');
+
+ my %filter = map +( $_ => $form->{"f_${_}"} ),
+ grep { $form->{"f_${_}"} }
+ (qw(vendor invnumber),
+ map { ("${_}_date_from", "${_}_date_to") }
+ qw(export requested_execution execution));
+ $filter{executed} = $form->{l_executed} ? 1 : 0 if ($form->{l_executed} != $form->{l_not_executed});
+ $filter{closed} = $form->{l_closed} ? 1 : 0 if ($form->{l_open} != $form->{l_closed});
+
+ my $exports = SL::SEPA->list_exports('filter' => \%filter,
+ 'sortorder' => $form->{sort},
+ 'sortdir' => $form->{sortdir});
+
+ my $open_available = any { !$_->{closed} } @{ $exports };
+
+ my $report = SL::ReportGenerator->new(\%main::myconfig, $form);
+
+ my @hidden_vars = grep { m/^[fl]_/ && $form->{$_} } keys %{ $form };
+
+ my $href = build_std_url('action=bank_transfer_list', @hidden_vars);
+
+ my %column_defs = (
+ 'selected' => { 'text' => $cgi->checkbox(-name => 'select_all', -id => 'select_all', -label => ''), },
+ 'id' => { 'text' => $locale->text('Number'), },
+ 'export_date' => { 'text' => $locale->text('Export date'), },
+ 'employee' => { 'text' => $locale->text('Employee'), },
+ 'executed' => { 'text' => $locale->text('Executed'), },
+ 'closed' => { 'text' => $locale->text('Closed'), },
+ );
+
+ my @columns = qw(selected id export_date employee executed closed);
+
+ foreach my $name (qw(id export_date employee executed closed)) {
+ my $sortdir = $form->{sort} eq $name ? 1 - $form->{sortdir} : $form->{sortdir};
+ $column_defs{$name}->{link} = $href . "&sort=$name&sortdir=$sortdir";
+ }
+
+ $column_defs{selected}->{visible} = $open_available ? 1 : 0;
+ $column_defs{executed}->{visible} = $form->{l_executed} && $form->{l_not_executed} ? 1 : 0;
+ $column_defs{closed}->{visible} = $form->{l_closed} && $form->{l_open} ? 1 : 0;
+
+ my @options = ();
+ push @options, $locale->text('Vendor') . ' : ' . $form->{f_vendor} if ($form->{f_vendor});
+ push @options, $locale->text('Invoice number') . ' : ' . $form->{f_invnumber} if ($form->{f_invnumber});
+ push @options, $locale->text('Export date from') . ' : ' . $form->{f_export_date_from} if ($form->{f_export_date_from});
+ push @options, $locale->text('Export date to') . ' : ' . $form->{f_export_date_to} if ($form->{f_export_date_to});
+ push @options, $locale->text('Requested execution date from') . ' : ' . $form->{f_requested_execution_date_from} if ($form->{f_requested_execution_date_from});
+ push @options, $locale->text('Requested execution date to') . ' : ' . $form->{f_requested_execution_date_to} if ($form->{f_requested_execution_date_to});
+ push @options, $locale->text('Execution date from') . ' : ' . $form->{f_execution_date_from} if ($form->{f_execution_date_from});
+ push @options, $locale->text('Execution date to') . ' : ' . $form->{f_execution_date_to} if ($form->{f_execution_date_to});
+ push @options, $form->{l_executed} ? $locale->text('executed') : $locale->text('not yet executed') if ($form->{l_executed} != $form->{l_not_executed});
+ push @options, $form->{l_closed} ? $locale->text('closed') : $locale->text('open') if ($form->{l_open} != $form->{l_closed});
+
+ $report->set_options('top_info_text' => join("\n", @options),
+ 'raw_top_info_text' => $form->parse_html_template('sepa/bank_transfer_list_top'),
+ 'raw_bottom_info_text' => $form->parse_html_template('sepa/bank_transfer_list_bottom', { 'show_buttons' => $open_available }),
+ 'std_column_visibility' => 1,
+ 'output_format' => 'HTML',
+ 'title' => $form->{title},
+ 'attachment_basename' => $locale->text('banktransfers') . strftime('_%Y%m%d', localtime time),
+ );
+ $report->set_options_from_form();
+
+ $report->set_columns(%column_defs);
+ $report->set_column_order(@columns);
+ $report->set_export_options('bank_transfer_list', @hidden_vars);
+ $report->set_sort_indicator($form->{sort}, $form->{sortdir});
+
+ my $edit_url = build_std_url('action=bank_transfer_edit', 'callback');
+
+ foreach my $export (@{ $exports }) {
+ my $row = { map { $_ => { 'data' => $export->{$_} } } keys %{ $export } };
+
+ map { $row->{$_}->{data} = $export->{$_} ? $locale->text('yes') : $locale->text('no') } qw(executed closed);
+
+ $row->{id}->{link} = $edit_url . '&id=' . E($export->{id});
+
+ if (!$export->{closed}) {
+ $row->{selected}->{raw_data} =
+ $cgi->hidden(-name => "exports[+].id", -value => $export->{id})
+ . $cgi->checkbox(-name => "exports[].selected", -value => 1, -label => '');
+ }
+
+ $report->add_data($row);
+ }
+
+ $report->generate_with_headers();
+
+ $main::lxdebug->leave_sub();
+}
+
+sub bank_transfer_edit {
+ $main::lxdebug->enter_sub();
+
+ my $form = $main::form;
+ my $locale = $main::locale;
+
+ my @ids = ();
+ if (!$form->{mode} || ($form->{mode} eq 'single')) {
+ push @ids, $form->{id};
+ } else {
+ @ids = map $_->{id}, grep { $_->{selected} } @{ $form->{exports} || [] };
+
+ if (!@ids) {
+ $form->show_generic_error($locale->text('You have not selected any export.'), 'back_button' => 1);
+ }
+ }
+
+ my $export;
+
+ foreach my $id (@ids) {
+ my $curr_export = SL::SEPA->retrieve_export('id' => $id, 'details' => 1);
+
+ foreach my $item (@{ $curr_export->{items} }) {
+ map { $item->{"export_${_}"} = $curr_export->{$_} } grep { !ref $curr_export->{$_} } keys %{ $curr_export };
+ }
+
+ if (!$export) {
+ $export = $curr_export;
+ } else {
+ push @{ $export->{items} }, @{ $curr_export->{items} };
+ }
+ }
+
+ if ($form->{mode} && ($form->{mode} eq 'multi')) {
+ $export->{items} = [ grep { !$_->{export_closed} && !$_->{executed} } @{ $export->{items} } ];
+
+ if (!@{ $export->{items} }) {
+ $form->show_generic_error($locale->text('All the selected exports have already been closed, or all of their items have already been executed.'), 'back_button' => 1);
+ }
+
+ } elsif (!$export) {
+ $form->error($locale->text('That export does not exist.'));
+ }
+
+ $form->{jsscript} = 1;
+ $form->{title} = $locale->text('View SEPA export');
+ $form->header();
+ print $form->parse_html_template('sepa/bank_transfer_edit',
+ { 'ids' => \@ids,
+ 'export' => $export,
+ 'current_date' => $form->current_date(\%main::myconfig),
+ 'show_post_payments_button' => any { !$_->{export_closed} && !$_->{executed} } @{ $export->{items} },
+ });
+
+ $main::lxdebug->leave_sub();
+}
+
+sub bank_transfer_post_payments {
+ $main::lxdebug->enter_sub();
+
+ my $form = $main::form;
+ my $locale = $main::locale;
+
+ my @items = grep { $_->{selected} } @{ $form->{items} || [] };
+
+ if (!@items) {
+ $form->show_generic_error($locale->text('You have not selected any item.'), 'back_button' => 1);
+ }
+ my @export_ids = uniq map { $_->{sepa_export_id} } @items;
+ my %exports = map { $_ => SL::SEPA->retrieve_export('id' => $_, 'details' => 1) } @export_ids;
+ my @items_to_post = ();
+
+ foreach my $item (@items) {
+ my $export = $exports{ $item->{sepa_export_id} };
+ next if (!$export || $export->{closed} || $export->{executed});
+
+ push @items_to_post, $item if (none { ($_->{id} == $item->{id}) && $_->{executed} } @{ $export->{items} });
+ }
+
+ if (!@items_to_post) {
+ $form->show_generic_error($locale->text('All the selected exports have already been closed, or all of their items have already been executed.'), 'back_button' => 1);
+ }
+
+ if (any { !$_->{execution_date} } @items_to_post) {
+ $form->show_generic_error($locale->text('You have to specify an execution date for each antry.'), 'back_button' => 1);
+ }
+
+ SL::SEPA->post_payment('items' => \@items_to_post);
+
+ $form->show_generic_information($locale->text('The payments have been posted.'));
+
+ $main::lxdebug->leave_sub();
+}
+
+sub bank_transfer_payment_list_as_pdf {
+ $main::lxdebug->enter_sub();
+
+ my $form = $main::form;
+ my %myconfig = %main::myconfig;
+ my $locale = $main::locale;
+
+ my @ids = @{ $form->{items} || [] };
+ my @export_ids = uniq map { $_->{export_id} } @ids;
+
+ $form->show_generic_error($locale->text('Multi mode not supported.'), 'back_button' => 1) if 1 != scalar @export_ids;
+
+ my $export = SL::SEPA->retrieve_export('id' => $export_ids[0], 'details' => 1);
+ my @items = ();
+
+ foreach my $id (@ids) {
+ my $item = first { $_->{id} == $id->{id} } @{ $export->{items} };
+ push @items, $item if $item;
+ }
+
+ $form->show_generic_error($locale->text('No transfers were executed in this export.'), 'back_button' => 1) if 1 > scalar @items;
+
+ my $report = SL::ReportGenerator->new(\%main::myconfig, $form);
+
+ my %column_defs = (
+ 'invnumber' => { 'text' => $locale->text('Invoice'), },
+ 'vendor_name' => { 'text' => $locale->text('Vendor'), },
+ 'our_iban' => { 'text' => $locale->text('Source IBAN'), },
+ 'our_bic' => { 'text' => $locale->text('Source BIC'), },
+ 'vendor_iban' => { 'text' => $locale->text('Destination IBAN'), },
+ 'vendor_bic' => { 'text' => $locale->text('Destination BIC'), },
+ 'amount' => { 'text' => $locale->text('Amount'), },
+ 'reference' => { 'text' => $locale->text('Reference'), },
+ 'execution_date' => { 'text' => $locale->text('Execution date'), },
+ );
+
+ map { $column_defs{$_}->{align} = 'right' } qw(amount execution_date);
+
+ my @columns = qw(invnumber vendor_name our_iban our_bic vendor_iban vendor_bic amount reference execution_date);
+
+ $report->set_options('std_column_visibility' => 1,
+ 'output_format' => 'PDF',
+ 'title' => $locale->text('Bank transfer payment list for export #1', $export->{id}),
+ 'attachment_basename' => $locale->text('bank_transfer_payment_list_#1', $export->{id}) . strftime('_%Y%m%d', localtime time),
+ );
+
+ $report->set_columns(%column_defs);
+ $report->set_column_order(@columns);
+
+ foreach my $item (@items) {
+ my $row = { map { $_ => { 'data' => $item->{$_} } } @columns };
+ $row->{amount}->{data} = $form->format_amount(\%myconfig, $item->{amount}, 2);
+
+ $report->add_data($row);
+ }
+
+ $report->generate_with_headers();
+
+ $main::lxdebug->leave_sub();
+}
+
+sub bank_transfer_download_sepa_xml {
+ $main::lxdebug->enter_sub();
+
+ my $form = $main::form;
+ my $myconfig = \%main::myconfig;
+ my $locale = $main::locale;
+ my $cgi = $main::cgi;
+
+ if (!$myconfig->{company}) {
+ $form->show_generic_error($locale->text('You have to enter a company name in your user preferences (see the "Program" menu, "Preferences").'), 'back_button' => 1);
+ }
+
+ my @ids;
+ if ($form->{mode} && ($form->{mode} eq 'multi')) {
+ @ids = map $_->{id}, grep { $_->{selected} } @{ $form->{exports} || [] };
+
+ } else {
+ @ids = ($form->{id});
+ }
+
+ if (!@ids) {
+ $form->show_generic_error($locale->text('You have not selected any export.'), 'back_button' => 1);
+ }
+
+ my @items = ();
+
+ foreach my $id (@ids) {
+ my $export = SL::SEPA->retrieve_export('id' => $id, 'details' => 1);
+ push @items, grep { !$_->{executed} } @{ $export->{items} } if ($export && !$export->{closed});
+ }
+
+ if (!@items) {
+ $form->show_generic_error($locale->text('All the selected exports have already been closed, or all of their items have already been executed.'), 'back_button' => 1);
+ }
+
+ my $message_id = strftime('MSG%Y%m%d%H%M%S', localtime) . sprintf('%06d', $$);
+
+ my $sepa_xml = SL::SEPA::XML->new('company' => $myconfig->{company},
+ 'src_charset' => $main::dbcharset || 'ISO-8859-15',
+ 'message_id' => $message_id,
+ 'grouped' => 1,
+ );
+
+ foreach my $item (@items) {
+ my $requested_execution_date;
+ if ($item->{requested_execution_date}) {
+ my ($yy, $mm, $dd) = $locale->parse_date($myconfig, $item->{requested_execution_date});
+ $requested_execution_date = sprintf '%04d-%02d-%02d', $yy, $mm, $dd;
+ }
+
+ $sepa_xml->add_transaction({ 'src_iban' => $item->{our_iban},
+ 'src_bic' => $item->{our_bic},
+ 'dst_iban' => $item->{vendor_iban},
+ 'dst_bic' => $item->{vendor_bic},
+ 'recipient' => $item->{vendor_name},
+ 'amount' => $item->{amount},
+ 'reference' => $item->{reference},
+ 'execution_date' => $requested_execution_date,
+ 'end_to_end_id' => $item->{end_to_end_id} });
+ }
+
+ my $xml = $sepa_xml->to_xml();
+
+ print $cgi->header('-type' => 'application/octet-stream',
+ '-content-disposition' => 'attachment; filename="SEPA_' . $message_id . '.cct"',
+ '-content-length' => length $xml);
+ print $xml;
+
+ $main::lxdebug->leave_sub();
+}
+
+sub bank_transfer_mark_as_closed_step1 {
+ $main::lxdebug->enter_sub();
+
+ my $form = $main::form;
+ my $locale = $main::locale;
+
+ my @export_ids = map { $_->{id} } grep { $_->{selected} } @{ $form->{exports} || [] };
+
+ if (!@export_ids) {
+ $form->show_generic_error($locale->text('You have not selected any export.'), 'back_button' => 1);
+ }
+
+ my @open_export_ids = ();
+ foreach my $id (@export_ids) {
+ my $export = SL::SEPA->retrieve_export('id' => $id);
+ push @open_export_ids, $id if (!$export->{closed});
+ }
+
+ if (!@open_export_ids) {
+ $form->show_generic_error($locale->text('All of the exports you have selected were already closed.'), 'back_button' => 1);
+ }
+
+ $form->{title} = $locale->text('Close SEPA exports');
+ $form->header();
+ print $form->parse_html_template('sepa/bank_transfer_mark_as_closed_step1', { 'OPEN_EXPORT_IDS' => \@open_export_ids });
+
+ $main::lxdebug->leave_sub();
+}
+
+sub bank_transfer_mark_as_closed_step2 {
+ $main::lxdebug->enter_sub();
+
+ my $form = $main::form;
+ my $locale = $main::locale;
+
+ map { SL::SEPA->close_export('id' => $_); } @{ $form->{open_export_ids} || [] };
+
+ $form->{title} = $locale->text('Close SEPA exports');
+ $form->header();
+ $form->show_generic_information($locale->text('The selected exports have been closed.'));
+
+ $main::lxdebug->leave_sub();
+}
+
+sub dispatcher {
+ my $form = $main::form;
+
+ foreach my $action (qw(bank_transfer_create bank_transfer_edit bank_transfer_list
+ bank_transfer_post_payments bank_transfer_download_sepa_xml
+ bank_transfer_mark_as_closed_step1 bank_transfer_mark_as_closed_step2
+ bank_transfer_payment_list_as_pdf)) {
+ if ($form->{"action_${action}"}) {
+ call_sub($action);
+ return;
+ }
+ }
+
+ $form->error($main::locale->text('No action defined.'));
+}
+
+1;
diff --git a/locale/de/all b/locale/de/all
index c9490043c..9291db415 100644
--- a/locale/de/all
+++ b/locale/de/all
@@ -93,6 +93,8 @@ $self->{texts} = {
'Account deleted!' => 'Konto gelöscht!',
'Account for fees' => 'Konto für Gebühren',
'Account for interest' => 'Konto für Zinsen',
+ 'Account number' => 'Kontonummer',
+ 'Account number #1, bank code #2, #3' => 'Kontonummer #1, BLZ #2, #3',
'Account saved!' => 'Konto gespeichert!',
'Accounting Group deleted!' => 'Buchungsgruppe gelöscht!',
'Accounting Group saved!' => 'Buchungsgruppe gespeichert!',
@@ -147,6 +149,7 @@ $self->{texts} = {
'Add Warehouse' => 'Lager erfassen',
'Add a new group' => 'Neue Gruppe erfassen',
'Add and edit units' => 'Einheiten erfassen und bearbeiten',
+ 'Add bank account' => 'Bankkonto erfassen',
'Add custom variable' => 'Benutzerdefinierte Variable erfassen',
'Add note' => 'Notiz erfassen',
'Add to group' => 'Zu Gruppe hinzufügen',
@@ -162,7 +165,9 @@ $self->{texts} = {
'All changes in that file have been reverted.' => 'Alle Änderungen in dieser Datei wurden rückgängig gemacht.',
'All database upgrades have been applied.' => 'Alle Datenbankupdates wurden eingespielt.',
'All general ledger entries' => 'Alle Hauptbucheinträge',
+ 'All of the exports you have selected were already closed.' => 'Alle von Ihnen ausgewählten Exporte sind bereits abgeschlossen.',
'All reports' => 'Alle Berichte (Kontenübersicht, Summen- u. Saldenliste, GuV, BWA, Bilanz, Projektbuchungen)',
+ 'All the selected exports have already been closed, or all of their items have already been executed.' => 'Alle ausgewählten Exporte sind als abgeschlossen markiert, oder für alle Einträge wurden bereits Zahlungen verbucht.',
'Allow access' => 'Zugriff erlauben',
'Allow the following users access to my follow-ups:' => 'Erlaube den folgenden Benutzern Zugriff auf meine Wiedervorlagen:',
'Alternatively you can create a new part which will then be selected.' => 'Sie können auch einen neuen Artikel anlegen, der dann automatisch ausgewählt wird.',
@@ -188,7 +193,7 @@ $self->{texts} = {
'Are you sure you want to delete Quotation Number' => 'Sind Sie sicher, dass Angebotnummer gelöscht werden soll?',
'Are you sure you want to delete Transaction' => 'Buchung wirklich löschen?',
'Are you sure you want to remove the marked entries from the queue?' => 'Sind Sie sicher, dass die markierten Einträge von der Warteschlange gelöscht werden sollen?',
- 'Are you sure you want to update the prices' => 'Sind Sie sicher, dass Sie die Preise aktualisieren wollen',
+ 'Are you sure you want to update the prices' => 'Sind Sie sicher, dass Sie die Preise aktualisieren wollen?',
'Article Code' => 'Artikelkürzel',
'Article Code missing!' => 'Artikelkürzel fehlt',
'As a result, the saved onhand values of the present goods can be stored into a warehouse designated by you, or will be reset for a proper warehouse tracking' => 'Als Konsequenz können die gespeicherten Mengen entweder in ein Lager überführt werden, oder für eine frische Lagerverwaltung resettet werden.',
@@ -234,6 +239,12 @@ $self->{texts} = {
'Bank Code Number' => 'Bankleitzahl',
'Bank Connection Tax Office' => 'Bankverbindung des Finanzamts',
'Bank Connections' => 'Bankverbindungen',
+ 'Bank accounts' => 'Bankkonten',
+ 'Bank code' => 'Bankleitzahl',
+ 'Bank transfer amount' => 'Überweisungssumme',
+ 'Bank transfer payment list for export #1' => 'Überweisungszahlungsliste für SEPA-Export #1',
+ 'Bank transfer via SEPA' => 'Überweisung via SEPA',
+ 'Bank transfers via SEPA' => 'Überweisungen via SEPA',
'Base unit' => 'Basiseinheit',
'Basic data' => 'Basisdaten',
'Batch Printing' => 'Druck',
@@ -332,6 +343,7 @@ $self->{texts} = {
'Change Lx-Office installation settings (all menu entries beneath \'System\')' => 'Verändern der Lx-Office-Installationseinstellungen (Menüpunkte unterhalb von \'System\')',
'Charge Number' => 'Chargennummer',
'Charge number' => 'Chargennummer',
+ 'Chart' => 'Buchungskonto',
'Chart Type' => 'Kontentyp',
'Chart balance' => 'Kontensaldo',
'Chart of Accounts' => 'Kontenübersicht',
@@ -350,6 +362,7 @@ $self->{texts} = {
'Click on login name to edit!' => 'Zum Bearbeiten den Zugriffsnamen anklicken!',
'Close' => 'Übernehmen',
'Close Books up to' => 'Die Bücher abschließen bis zum',
+ 'Close SEPA exports' => 'SEPA-Export abschließen',
'Close Window' => 'Fenster Schließen',
'Closed' => 'Geschlossen',
'Collective Orders only work for orders from one customer!' => 'Sammelaufträge funktionieren nur für Aufträge von einem Kunden!',
@@ -399,6 +412,8 @@ $self->{texts} = {
'Create and edit sales orders' => 'Auftragsbestätigungen erfassen und bearbeiten',
'Create and edit sales quotations' => 'Angebote erfassen und bearbeiten',
'Create and edit vendor invoices' => 'Eingangsrechnungen erfassen und bearbeiten',
+ 'Create bank transfer' => 'Überweisung erstellen',
+ 'Create bank transfer via SEPA XML' => 'Überweisung via SEPA XML erzeugen',
'Create invoice?' => 'Rechnung erstellen?',
'Create new' => 'Neu erfassen',
'Create tables' => 'Tabellen anlegen',
@@ -516,6 +531,8 @@ $self->{texts} = {
öffnet einzelne Kontendetails)',
'Description missing!' => 'Beschreibung fehlt.',
'Description must not be empty!' => 'Beschreibung darf nicht leer sein',
+ 'Destination BIC' => 'Ziel-BIC',
+ 'Destination IBAN' => 'Ziel-IBAN',
'Destination bin' => 'Ziellagerplatz',
'Destination warehouse' => 'Ziellager',
'Destination warehouse and bin' => 'Ziellager und -lagerplatz',
@@ -527,6 +544,7 @@ $self->{texts} = {
'Display' => 'Anzeigen',
'Display file' => 'Datei anzeigen',
'Display options' => 'Anzeigeoptionen',
+ 'Do you really want to close the following SEPA exports? No payment will be recorded for bank transfers that haven\'t been marked as executed yet.' => 'Wollen Sie wirklich die folgenden SEPA-Exporte abschließen? Für Überweisungen, die noch nicht gebucht wurden, werden dann keine Zahlungen verbucht.',
'Do you really want to delete AP transaction #1?' => 'Wollen Sie wirklich die Kreditorenbuchung #1 löschen?',
'Do you really want to delete AR transaction #1?' => 'Wollen Sie wirklich die Debitorenbuchung #1 löschen?',
'Do you really want to delete GL transaction #1?' => 'Wollen Sie wirklich die Dialogbuchung #1 löschen?',
@@ -539,6 +557,7 @@ $self->{texts} = {
'Document' => 'Dokument',
'Documents in the WebDAV repository' => 'Dokumente im WebDAV-Repository',
'Done' => 'Fertig',
+ 'Download SEPA XML export file' => 'SEPA-XML-Exportdatei herunterladen',
'Download the backup' => 'Die Sicherungsdatei herunterladen',
'Draft saved.' => 'Entwurf gespeichert.',
'Drawing' => 'Zeichnung',
@@ -626,6 +645,7 @@ $self->{texts} = {
'Edit Vendor Invoice' => 'Einkaufsrechnung bearbeiten',
'Edit Warehouse' => 'Lager bearbeiten',
'Edit and delete a group' => 'Gruppen bearbeiten und löschen',
+ 'Edit bank account' => 'Bankkonto bearbeiten',
'Edit custom variable' => 'Benutzerdefinierte Variable bearbeiten',
'Edit file' => 'Datei bearbeiten',
'Edit greetings' => 'Anreden bearbeiten',
@@ -644,11 +664,13 @@ $self->{texts} = {
'Edit the stylesheet' => 'Stilvorlage bearbeiten',
'Edit units' => 'Einheiten bearbeiten',
'Editable' => 'Bearbeitbar',
+ 'Either there are no open invoices, or you have already initiated bank transfers with the open amounts for those that are still open.' => 'Entweder gibt es keine offenen Rechnungen, oder es wurden bereits Überweisungen über die offenen Beträge aller offenen Rechnungen erstellt.',
'Element disabled' => 'Element deaktiviert',
'Employee' => 'Bearbeiter',
'Empty transaction!' => 'Buchung ist leer!',
'Enter a description for this new draft.' => 'Geben Sie eine Beschreibung für diesen Entwurf ein.',
'Enter longdescription' => 'Langtext eingeben',
+ 'Enter the requested execution date or leave empty for the quickest possible execution:' => 'Geben Sie das jeweils gewünschte Ausführungsdatum an, oder lassen Sie das Feld leer für die schnellstmögliche Ausführung:',
'Enter up to 3 letters separated by a colon (i.e CAD:USD:EUR) for your native and foreign currencies' => 'Geben Sie Ihre und weitere Währungen mit bis zu drei Buchstaben pro Währung und Währungen durch Doppelpunkte getrennt ein (z.B. EUR:USD:CAD)',
'Equity' => 'Passiva',
'Error' => 'Fehler',
@@ -667,6 +689,10 @@ $self->{texts} = {
'Exchangerate Difference' => 'Wechselkursunterschied',
'Exchangerate for payment missing!' => 'Es fehlt der Wechselkurs für die Bezahlung!',
'Exchangerate missing!' => 'Es fehlt der Wechselkurs!',
+ 'Executed' => 'Ausgeführt',
+ 'Execution date' => 'Ausführungsdatum',
+ 'Execution date from' => 'Ausführungsdatum von',
+ 'Execution date to' => 'Ausführungsdatum bis',
'Existing Buchungsgruppen' => 'Existierende Buchungsgruppen',
'Existing Datasets' => 'existierende Datenbanken',
'Existing pending follow-ups for this item' => 'Noch nicht erledigte Wiedervorlagen für dieses Dokument',
@@ -683,6 +709,9 @@ $self->{texts} = {
'Export Stammdaten' => 'Export Stammdaten',
'Export as CSV' => 'Als CSV exportieren',
'Export as PDF' => 'Als PDF exportieren',
+ 'Export date' => 'Exportdatum',
+ 'Export date from' => 'Exportdatum von',
+ 'Export date to' => 'Exportdatum bis',
'Extended' => 'Gesamt',
'Extension Of Time' => 'Dauerfristverlängerung',
'Factor' => 'Faktor',
@@ -830,6 +859,7 @@ $self->{texts} = {
'Invoice deleted!' => 'Rechnung gelöscht!',
'Invoice for fees' => 'Rechnung über Gebühren',
'Invoice has already been storno\'d!' => 'Diese Rechnung wurde bereits storniert.',
+ 'Invoice number' => 'Rechnungsnummer',
'Invoice with Storno (abbreviation)' => 'R(S)',
'Invoices' => 'Rechnungen',
'Is this a summary account to record' => 'Buchungskonto in',
@@ -907,8 +937,12 @@ $self->{texts} = {
'List Tax' => 'Bearbeiten',
'List Transactions' => 'Buchungsliste',
'List Warehouses' => 'Lager anzeigen',
- 'List export' => 'Listenexport',
+ 'List bank accounts' => 'Bankkonten anzeigen',
+ 'List export' => 'Export anzeigen',
+ 'List of bank accounts' => 'Liste der Bankkonten',
+ 'List of bank transfers' => 'Überweisungsliste',
'List of custom variables' => 'Liste der benutzerdefinierten Variablen',
+ 'List open SEPA exports' => 'Noch nicht ausgeführte SEPA-Exporte anzeigen',
'Load draft' => 'Entwurf laden',
'Local Tax Office Preferences' => 'Angaben zum Finanzamt',
'Lock System' => 'System sperren',
@@ -936,6 +970,7 @@ $self->{texts} = {
'Mar' => 'März',
'March' => 'März',
'Margins' => 'Seitenränder',
+ 'Mark as closed' => 'Abschließen',
'Mark as paid?' => 'Als bezahlt markieren?',
'Mark closed' => 'Schließen',
'Marked as paid' => 'Als bezahlt markiert',
@@ -969,6 +1004,7 @@ $self->{texts} = {
'Monat' => 'Monat',
'Monthly' => 'monatlich',
'More than one control file with the tag \'%s\' exist.' => 'Es gibt mehr als eine Kontrolldatei mit dem Tag \'%s\'.',
+ 'Multi mode not supported.' => 'Multimodus wird nicht unterstützt.',
'Multibyte Encoding' => 'Schriftsatz',
'MwSt. inkl.' => 'MwSt. inkl.',
'Name' => 'Name',
@@ -980,6 +1016,7 @@ $self->{texts} = {
'New Buchungsgruppe [% loop.count %]' => 'Neue Buchungsgruppe [% loop.count %]',
'New Templates' => 'neue Vorlagen',
'New assembly' => 'Neues Erzeugnis',
+ 'New bank account' => 'Neues Bankkonto',
'New contact' => 'Neuer Ansprechpartner',
'New customer' => 'Neuer Kunde',
'New invoice' => 'Neue Rechnung',
@@ -999,6 +1036,7 @@ $self->{texts} = {
'No Vendor was found matching the search parameters.' => 'Zu dem Suchbegriff wurde kein Händler gefunden',
'No action defined.' => 'Keine Aktion definiert.',
'No backup file has been uploaded.' => 'Es wurde keine Sicherungsdatei hochgeladen.',
+ 'No bank information has been entered in this vendor\'s master data entry. You cannot create bank transfers unless you enter bank information.' => 'Für diesen Lieferanten wurden in seinen Stammdaten keine Kontodaten hinterlegt. Solange dies nicht geschehen ist, können Sie keine Überweisungen für den Lieferanten anlegen.',
'No bins have been added to this warehouse yet.' => 'Es wurden zu diesem Lager noch keine Lagerplätze angelegt.',
'No customer has been selected yet.' => 'Es wurde noch kein Kunde ausgewählt.',
'No data was found.' => 'Es wurden keine Daten gefunden.',
@@ -1013,6 +1051,7 @@ $self->{texts} = {
'No part was found matching the search parameters.' => 'Es wurde kein Artikel gefunden, auf den die Suchparameter zutreffen.',
'No prices will be updated because no prices have been entered.' => 'Es werden keine Preise aktualisiert, weil keine gültigen Preisänderungen eingegeben wurden.',
'No problems were recognized.' => 'Es wurden keine Probleme gefunden.',
+ 'No transfers were executed in this export.' => 'In diesem SEPA-Export wurden keine Überweisungen ausgeführt.',
'No unknown units where found.' => 'Es wurden keine unbekannten Einheiten gefunden.',
'No user has been selected.' => 'Es wurde kein Benutzer ausgewählt.',
'No valid number entered for pricegroup "#1".' => 'Für Preisgruppe "#1" wurde keine gültige Nummer eingegeben.',
@@ -1057,6 +1096,7 @@ $self->{texts} = {
'One or more Perl modules missing' => 'Ein oder mehr Perl-Module fehlen',
'Only due follow-ups' => 'Nur fällige Wiedervorlagen',
'Open' => 'Offen',
+ 'Open amount' => 'offener Betrag',
'OpenDocument/OASIS' => 'OpenDocument/OASIS',
'Openings' => 'Öffnungszeiten',
'Optional comment' => 'Optionaler Kommentar',
@@ -1114,6 +1154,7 @@ $self->{texts} = {
'Payment Terms missing in row ' => 'Zahlungsfrist fehlt in Zeile ',
'Payment Terms saved!' => 'Zahlungskonditionen gespeichert!',
'Payment date missing!' => 'Tag der Zahlung fehlt!',
+ 'Payment list as PDF' => 'Zahlungsliste als PDF',
'Payment posted!' => 'Zahlung gebucht!',
'Payment terms deleted!' => 'Zahlungskonditionen gelöscht!',
'Payments' => 'Zahlungsausgänge',
@@ -1125,6 +1166,7 @@ $self->{texts} = {
'Phone1' => 'Telefon 1 ',
'Phone2' => 'Telefon 2',
'Pick List' => 'Sammelliste',
+ '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 enter a license key.' => 'Bitte geben Sie einen Lizenzschlüssel an.',
'Please enter a number of licenses.' => 'Bitte geben Sie die Anzahl Lizenzschlüssel an.',
@@ -1144,6 +1186,7 @@ $self->{texts} = {
'Please select a vendor from the list below.' => 'Bitte einen Händler aus der Liste auswählen',
'Please select the chart of accounts this installation is using from the list below.' => 'Bitte wählen Sie den Kontenrahmen aus, der bei dieser Installation verwendet wird.',
'Please select the database you want to backup' => 'Bitte wählen Sie die zu sichernde Datenbank gefunden',
+ 'Please select the source bank account for the transfers:' => 'Bitte wählen Sie das Bankkonto als Quelle für die Überweisungen aus:',
'Please seletct the dataset you want to delete:' => 'Bitte wählen Sie die zu löschende Datenbank aus:',
'Please specify a description for the warehouse designated for these goods.' => 'Bitte geben Sie den Namen des Ziellagers für die übernommenen Daten ein.',
'Plural' => 'Plural',
@@ -1151,6 +1194,7 @@ $self->{texts} = {
'Portrait' => 'Hochformat',
'Post' => 'Buchen',
'Post Payment' => 'Zahlung buchen',
+ 'Post payments' => 'Zahlungen buchen',
'Postscript' => 'Postscript',
'Posustva_coa' => 'USTVA Kennz.',
'Preferences' => 'Benutzereinstellungen',
@@ -1159,6 +1203,7 @@ $self->{texts} = {
'Preis' => 'Preis',
'Preisgruppe' => 'Preisgruppe',
'Preisklasse' => 'Preisgruppe',
+ 'Prepare bank transfer via SEPA XML' => 'Überweisung via SEPA XML vorbereiten',
'Prepayment' => 'Vorauszahlung',
'Preview' => 'Druckvorschau',
'Previous transdate text' => 'wurde gespeichert am',
@@ -1213,6 +1258,7 @@ $self->{texts} = {
'Purchase Prices' => 'Einkaufspreise',
'Purchase delivery order' => 'Lieferschein (Einkauf)',
'Purchase invoices' => 'Einkaufsrechnungen',
+ 'Purpose' => 'Verwendungszweck',
'Qty' => 'Menge',
'Qty according to delivery order' => 'Menge laut Lieferschein',
'Qty in stock' => 'Lagerbestand',
@@ -1273,6 +1319,9 @@ $self->{texts} = {
'Request for Quotation' => 'Anfrage',
'Request for Quotations' => 'Anfragen',
'Request quotation' => 'Preisanfrage',
+ 'Requested execution date' => 'Gewünschtes Ausführungsdatum',
+ 'Requested execution date from' => 'Gewünschtes Ausführungsdatum von',
+ 'Requested execution date to' => 'Gewünschtes Ausführungsdatum bis',
'Required by' => 'Lieferdatum',
'Restore Dataset' => 'Datenbank wiederherstellen',
'Revenue' => 'Erlöskonto',
@@ -1283,6 +1332,8 @@ $self->{texts} = {
'SAVED' => 'Gespeichert',
'SAVED FOR DUNNING' => 'Gespeichert',
'SCREENED' => 'Angezeigt',
+ 'SEPA XML download' => 'SEPA-XML-Download',
+ 'SEPA exports:' => 'SEPA-Exporte:',
'Saldo Credit' => 'Saldo Haben',
'Saldo Debit' => 'Saldo Soll',
'Saldo neu' => 'Saldo neu',
@@ -1380,6 +1431,9 @@ $self->{texts} = {
'Sold' => 'Verkauft',
'Solution' => 'Lösung',
'Source' => 'Beleg',
+ 'Source BIC' => 'Quell-BIC',
+ 'Source IBAN' => 'Quell-IBAN',
+ 'Source bank account' => 'Quellkonto',
'Source bin' => 'Quelllagerplatz',
'Spoolfile' => 'Druckdatei',
'Start Dunning Process' => 'Mahnprozess starten',
@@ -1392,6 +1446,7 @@ $self->{texts} = {
'Statement sent to' => 'Sammelrechnung verschickt an',
'Statements sent to printer!' => 'Sammelrechnungen an Drucker geschickt!',
'Step 1 of 3: Parts' => 'Schritt 1 von 3: Waren',
+ 'Step 2' => 'Schritt 2',
'Step 2 of 3: Services' => 'Schritt 2 von 3: Dienstleistungen',
'Step 3 of 3: Assemblies' => 'Schritt 3 von 3: Erzeugnisse',
'Step 3 of 3: Default units' => 'Schritt 3 von 3: Standardeinheiten',
@@ -1419,6 +1474,7 @@ $self->{texts} = {
'TODO list options' => 'Aufgabenlistenoptionen',
'TOP100' => 'Top 100',
'TOTAL' => 'TOTAL',
+ 'Target bank account' => 'Zielkonto',
'Tax' => 'Steuer',
'Tax Consultant' => 'Steuerberater/-in',
'Tax Included' => 'Steuer im Preis inbegriffen',
@@ -1463,11 +1519,13 @@ $self->{texts} = {
'Text field variables: \'WIDTH=w HEIGHT=h\' sets the width and height of the text field. They default to 30 and 5 respectively.' => 'Textfelder: \'WIDTH=w HEIGHT=h\' setzen die Breite und die Höhe des Textfeldes. Wenn nicht anders angegeben, so werden sie 30 Zeichen breit und fünf Zeichen hoch dargestellt.',
'Text variables: \'MAXLENGTH=n\' sets the maximum entry length to \'n\'.' => 'Textzeilen: \'MAXLENGTH=n\' setzt eine Maximallänge von n Zeichen.',
'Text, text field and number variables: The default value will be used as-is.' => 'Textzeilen, Textfelder und Zahlenvariablen: Der Standardwert wird so wie er ist übernommen.',
+ 'That export does not exist.' => 'Dieser Export existiert nicht.',
'The \'tag\' field must only consist of alphanumeric characters or the carachters - _ ( )' => 'Das Feld \'tag\' darf nur aus alphanumerischen Zeichen und den Zeichen - _ ( ) bestehen.',
'The AP transaction #1 has been deleted.' => 'Die Kreditorenbuchung #1 wurde gelöscht.',
'The AR transaction #1 has been deleted.' => 'Die Debitorenbuchung #1 wurde gelöscht.',
'The GL transaction #1 has been deleted.' => 'Die Dialogbuchung #1 wurde gelöscht.',
'The LDAP server "#1:#2" is unreachable. Please check config/authentication.pl.' => 'Der LDAP-Server "#1:#2" ist nicht erreichbar. Bitte überprüfen Sie die Angaben in config/authentication.pl.',
+ 'The SEPA export has been created.' => 'Der SEPA-Export wurde erstellt',
'The access rights have been saved.' => 'Die Zugriffsrechte wurden gespeichert.',
'The assembly has been created.' => 'Das Erzeugnis wurde hergestellt.',
'The assistant could not find anything wrong with #1. Maybe the problem has been solved in the meantime.' => 'Der Korrekturassistent konnte kein Problem bei #1 feststellen. Eventuell wurde das Problem in der Zwischenzeit bereits behoben.',
@@ -1475,6 +1533,7 @@ $self->{texts} = {
'The authentication database is not reachable at the moment. Either it hasn\'t been set up yet or the database server might be down. Please contact your administrator.' => 'Die Authentifizierungsdatenbank kann momentan nicht erreicht werden. Entweder wurde sie noch nicht eingerichtet, oder der Datenbankserver antwortet nicht. Bitte wenden Sie sich an Ihren Administrator.',
'The available options depend on the varibale type:' => 'Die verfügbaren Optionen hängen vom Variablentypen ab:',
'The backup you upload here has to be a file created with "pg_dump -o -Ft".' => 'Die von Ihnen hochzuladende Sicherungsdatei muss mit dem Programm und den Parametern "pg_dump -o -Ft" erstellt worden sein.',
+ 'The bank information must not be empty.' => 'Die Bankinformationen müssen vollständig ausgefüllt werden.',
'The base unit does not exist or it is about to be deleted in row %d.' => 'Die Basiseinheit in Zeile %d existiert nicht oder soll gelöscht werden.',
'The base unit does not exist.' => 'Die Basiseinheit existiert nicht.',
'The base unit relations must not contain loops (e.g. by saying that unit A\'s base unit is B, B\'s base unit is C and C\'s base unit is A) in row %d.' => 'Die Beziehungen der Einheiten dürfen keine Schleifen beinhalten (z.B. wenn gesagt wird, dass Einheit As Basiseinheit B, Bs Basiseinheit C und Cs Basiseinheit A ist) in Zeile %d.',
@@ -1541,6 +1600,7 @@ $self->{texts} = {
'The parts have been removed.' => 'Die Waren wurden aus dem Lager entnommen.',
'The parts have been stocked.' => 'Die Artikel wurden eingelagert.',
'The parts have been transferred.' => 'Die Waren wurden umgelagert.',
+ 'The payments have been posted.' => 'Die Zahlungen wurden gebucht.',
'The pg_dump process could not be started.' => 'Der pg_dump-Prozess konnte nicht gestartet werden.',
'The pg_restore process could not be started.' => 'Der pg_restore-Prozess konnte nicht gestartet werden.',
'The preferred one is to install packages provided by your operating system distribution (e.g. Debian or RPM packages).' => 'Die bevorzugte Art, ein Perl-Modul zu installieren, ist durch Installation eines von Ihrem Betriebssystem zur Verfügung gestellten Paketes (z.B. Debian-Pakete oder RPM).',
@@ -1552,7 +1612,9 @@ $self->{texts} = {
'The second reason is that Lx-Office allowed the user to enter the tax amount manually regardless of the taxkey used.' => 'Zum Anderen war es möglich, die Steuern unabhängig vom ausgewählten Steuerschlüssel selber einzugeben.',
'The second way is to use Perl\'s CPAN module and let it download and install the module for you.' => 'Die zweite Variante besteht darin, Perls CPAN-Modul zu benutzen und es das Modul für Sie installieren zu lassen.',
'The selected PostgreSQL installation uses UTF-8 as its encoding. Therefore you have to configure Lx-Office to use UTF-8 as well.' => 'Die ausgewählte PostgreSQL-Installation benutzt UTF-8 als Zeichensatz. Deshalb müssen Sie Lx-Office so konfigurieren, dass es ebenfalls UTF-8 als Zeichensatz benutzt.',
+ 'The selected bank account does not exist anymore.' => 'Das ausgewählte Bankkonto existiert nicht mehr.',
'The selected bin does not exist.' => 'Der ausgewählte Lagerplatz existiert nicht.',
+ 'The selected exports have been closed.' => 'Die ausgewählten Exporte wurden abgeschlossen.',
'The selected warehouse does not exist.' => 'Das ausgewählte Lager existiert nicht.',
'The selected warehouse is empty.' => 'Das ausgewählte Lager ist leer.',
'The session is invalid or has expired.' => 'Die Session ist ungültig oder abgelaufen.',
@@ -1718,6 +1780,7 @@ $self->{texts} = {
'Verrechnungseinheit' => 'Verrechnungseinheit',
'Version' => 'Version',
'View License' => 'Lizenz ansehen',
+ 'View SEPA export' => 'SEPA-Export-Details ansehen',
'View warehouse content' => 'Lagerbestand ansehen',
'Von Konto: ' => 'von Konto: ',
'WEBDAV access' => 'WEBDAV-Zugriff',
@@ -1773,11 +1836,18 @@ $self->{texts} = {
'You did not enter a name!' => 'Sie haben keinen Namen eingegeben!',
'You do not have the permissions to access this function.' => 'Sie verfügen nicht über die notwendigen Rechte, um auf diese Funktion zuzugreifen.',
'You have entered or selected the following shipping address for this customer:' => 'Sie haben die folgende Lieferadresse eingegeben oder ausgewählt:',
+ 'You have not added bank accounts yet.' => 'Sie haben noch keine Bankkoten angelegt.',
'You have not selected any delivery order.' => 'Sie haben keinen Lieferschein ausgewählt.',
+ 'You have not selected any export.' => 'Sie haben keinen Export ausgewählt.',
+ 'You have not selected any item.' => 'Sie haben keine noch nicht gebuchten Einträge ausgewählt.',
+ 'You have selected none of the invoices.' => 'Sie haben keine der Rechnungen ausgewählt.',
'You have to chose a dimension unit and a service unit which will then be assigned to those entries.' => 'Sie müssen eine Maß- und eine Dienstleistungseinheit auswählen, die diesen Waren und Dienstleistungen, denen noch keine Einheit zugeordnet ist, zugeordnet wird.',
'You have to chose which unit to save for each of them.' => 'Sie müssen für jeden Artikel die neue Einheit auswählen.',
'You have to create at least one group, grant it access to Lx-Office\'s functions and assign users to it.' => 'Sie müssen mindestens eine Benutzergruppe anlegen, ihr Zugriff auf die verschiedenen Funktionsbereiche von Lx-Office gewähren und Benutzer dieser Gruppe zuordnen.',
'You have to create new Buchungsgruppen for all the combinations of inventory, income and expense accounts that have been used already.' => 'Sie müssen neue Buchungsgruppen für alle Kombinationen aus Inventar-, Erlös- und Aufwandskonto, die bereits benutzt wurden.',
+ 'You have to enter a company name in your user preferences (see the "Program" menu, "Preferences").' => 'Sie müssen einen Firmennamen in Ihren Benutzereinstellungen angeben (siehe "Programm"-Menü, "Benuztereinstellungen).',
+ 'You have to fill in at least an account number, the bank code, the IBAN and the BIC.' => 'Sie müssen zumindest die Kontonummer, die Bankleitzahl, die IBAN und den BIC angeben.',
+ 'You have to specify an execution date for each antry.' => 'Sie müssen für jeden zu buchenden Eintrag ein Ausführungsdatum angeben.',
'You must chose a user.' => 'Sie müssen einen Benutzer auswählen.',
'You will now be forwarded to the administration panel.' => 'Sie werden nun zum Administrationsbereich weitergeleitet.',
'You\'re not editing a file.' => 'Sie bearbeiten momentan keine Datei.',
@@ -1801,6 +1871,9 @@ $self->{texts} = {
'as at' => 'zum Stand',
'assembly_list' => 'erzeugnisliste',
'back' => 'zurück',
+ 'bank_transfer_payment_list_#1' => 'ueberweisungs_zahlungsliste_#1',
+ 'bankaccounts' => 'Bankkonten',
+ 'banktransfers' => 'ueberweisungen',
'bin_list' => 'Lagerliste',
'bis' => 'bis',
'button' => '?',
@@ -1810,6 +1883,7 @@ $self->{texts} = {
'choice' => 'auswählen',
'choice part' => 'Artikel auswählen',
'close' => 'schließen',
+ 'closed' => 'geschlossen',
'config/authentication.pl: Key "DB_config" is missing.' => 'config/authentication.pl: Das Schlüsselwort "DB_config" fehlt.',
'config/authentication.pl: Key "LDAP_config" is missing.' => 'config/authentication.pl: Der Schlüssel "LDAP_config" fehlt.',
'config/authentication.pl: Missing parameters in "DB_config". Required parameters are "host", "db" and "user".' => 'config/authentication.pl: Fehlende Parameter in "DB_config". Benötigte Parameter sind "host", "db" und "user".',
@@ -1832,6 +1906,7 @@ $self->{texts} = {
'eMail?' => 'eMail?',
'ea' => 'St.',
'emailed to' => 'gemailt an',
+ 'executed' => 'ausgeführt',
'female' => 'weiblich',
'follow_up_list' => 'wiedervorlageliste',
'for' => 'für',
@@ -1850,7 +1925,7 @@ $self->{texts} = {
'list_of_receipts' => 'zahlungseingaenge',
'list_of_transactions' => 'buchungsliste',
'logout' => 'abmelden',
- 'male' => 'männlich',
+ 'male' => 'männlich',
'mark as paid' => 'als bezahlt markieren',
'master' => 'de',
'missing' => 'Fehlbestand',
@@ -1859,10 +1934,13 @@ $self->{texts} = {
'no' => 'nein',
'no chargenumber' => 'keine Chargennummer',
'none (pricegroup)' => 'keine',
+ 'not executed' => 'nicht ausgeführt',
'not transferred in yet' => 'noch nicht eingelagert',
'not transferred out yet' => 'noch nicht ausgelagert',
+ 'not yet executed' => 'Noch nicht ausgeführt',
'number' => 'Nummer',
'oe.pl::search called with unknown type' => 'oe.pl::search mit unbekanntem Typ aufgerufen',
+ 'open' => 'Offen',
'order' => 'Reihenfolge',
'our vendor number at customer' => 'unsere Lieferanten-Nr. beim Kunden',
'packing_list' => 'Versandliste',
diff --git a/locale/de/bankaccounts b/locale/de/bankaccounts
new file mode 100644
index 000000000..3a642df96
--- /dev/null
+++ b/locale/de/bankaccounts
@@ -0,0 +1,221 @@
+#!/usr/bin/perl
+
+$self->{texts} = {
+ 'A temporary file could not be created. Please verify that the directory "#1" is writeable by the webserver.' => 'Eine temporäre Datei konnte nicht angelegt werden. Bitte stellen Sie sicher, dass das Verzeichnis "#1" vom Webserver beschrieben werden darf.',
+ 'ADDED' => 'Hinzugefügt',
+ 'AP' => 'Einkauf',
+ 'AR' => 'Verkauf',
+ 'Account number' => 'Kontonummer',
+ 'Add bank account' => 'Bankkonto erfassen',
+ 'Address' => 'Adresse',
+ 'Advance turnover tax return' => 'Umsatzsteuervoranmeldung',
+ 'All reports' => 'Alle Berichte (Kontenübersicht, Summen- u. Saldenliste, GuV, BWA, Bilanz, Projektbuchungen)',
+ 'Attempt to call an undefined sub named \'%s\'' => 'Es wurde versucht, eine nicht definierte Unterfunktion namens \'%s\' aufzurufen.',
+ 'BIC' => 'BIC',
+ 'Bank' => 'Bank',
+ 'Bank code' => 'Bankleitzahl',
+ 'Bcc' => 'Bcc',
+ 'Bin List' => 'Lagerliste',
+ 'Binding to the LDAP server as "#1" failed. Please check config/authentication.pl.' => 'Die Anmeldung am LDAP-Server als "#1" schlug fehl. Bitte überprüfen Sie die Angaben in config/authentication.pl.',
+ 'CANCELED' => 'Storniert',
+ 'CR' => 'H',
+ 'CRM admin' => 'Administration',
+ 'CRM create customers, vendors and contacts' => 'Erfassen (Kunden, Lieferanten, Personen)',
+ 'CRM follow up' => 'Wiedervorlage',
+ 'CRM know how' => 'Wissens DB',
+ 'CRM notices' => 'Notizen',
+ 'CRM opportunity' => 'Auftragschance',
+ 'CRM optional software' => 'CRM optionale Software',
+ 'CRM other' => 'alles Andere',
+ 'CRM search' => 'Adresssuche',
+ 'CRM send email' => 'eMail',
+ 'CRM services' => 'Dienstleistung',
+ 'CRM status' => 'Admin Stautus',
+ 'CRM termin' => 'Termine',
+ 'CRM user' => 'Admin Benutzer',
+ 'CSV export -- options' => 'CSV-Export -- Optionen',
+ 'Cc' => 'Cc',
+ 'Change Lx-Office installation settings (all menu entries beneath \'System\')' => 'Verändern der Lx-Office-Installationseinstellungen (Menüpunkte unterhalb von \'System\')',
+ 'Confirmation' => 'Auftragsbestätigung',
+ 'Contact' => 'Kontakt',
+ 'Could not spawn the printer command.' => 'Die Druckanwendung konnte nicht gestartet werden.',
+ 'Create and edit RFQs' => 'Lieferantenanfragen erfassen und bearbeiten',
+ 'Create and edit customers and vendors' => 'Kunden und Lieferanten erfassen und bearbeiten',
+ 'Create and edit dunnings' => 'Mahnungen erfassen und bearbeiten',
+ 'Create and edit invoices and credit notes' => 'Rechnungen und Gutschriften erfassen und bearbeiten',
+ 'Create and edit parts, services, assemblies' => 'Artikel, Dienstleistungen, Erzeugnisse erfassen und bearbeiten',
+ 'Create and edit projects' => 'Projekte erfassen und bearbeiten',
+ 'Create and edit purchase delivery orders' => 'Lieferscheine von Lieferanten erfassen und bearbeiten',
+ 'Create and edit purchase orders' => 'Lieferantenaufträge erfassen und bearbeiten',
+ 'Create and edit sales delivery orders' => 'Lieferscheine für Kunden erfassen und bearbeiten',
+ 'Create and edit sales orders' => 'Auftragsbestätigungen erfassen und bearbeiten',
+ 'Create and edit sales quotations' => 'Angebote erfassen und bearbeiten',
+ 'Create and edit vendor invoices' => 'Eingangsrechnungen erfassen und bearbeiten',
+ 'Credit Note' => 'Gutschrift',
+ 'Customer Number' => 'Kundennummer',
+ 'Customer details' => 'Kundendetails',
+ 'DATEV Export' => 'DATEV-Export',
+ 'DELETED' => 'Gelöscht',
+ 'DR' => 'S',
+ 'DUNNING STARTED' => 'Mahnprozess gestartet',
+ 'Dataset upgrade' => 'Datenbankaktualisierung',
+ 'Date' => 'Datum',
+ 'Delivery Order' => 'Lieferschein',
+ 'Dependency loop detected:' => 'Schleife in den Abhängigkeiten entdeckt:',
+ 'Directory' => 'Verzeichnis',
+ 'Dunning' => 'Mahnung',
+ 'ELSE' => 'Zusatz',
+ 'Edit bank account' => 'Bankkonto bearbeiten',
+ 'Enter longdescription' => 'Langtext eingeben',
+ 'Error in database control file \'%s\': %s' => 'Fehler in Datenbankupgradekontrolldatei \'%s\': %s',
+ 'File' => 'Datei',
+ 'General ledger and cash' => 'Finanzbuchhaltung und Zahlungsverkehr',
+ 'History' => 'Historie',
+ 'IBAN' => 'IBAN',
+ 'Invoice' => 'Rechnung',
+ 'List of bank accounts' => 'Liste der Bankkonten',
+ 'MAILED' => 'Gesendet',
+ 'Manage license keys' => 'Lizenzschlüssel verwalten',
+ 'Mark as paid?' => 'Als bezahlt markieren?',
+ 'Marked as paid' => 'Als bezahlt markiert',
+ 'Master Data' => 'Stammdaten',
+ 'May set the BCC field when sending emails' => 'Beim Verschicken von Emails das Feld \'BCC\' setzen',
+ 'Message' => 'Nachricht',
+ 'Missing \'description\' field.' => 'Fehlendes Feld \'description\'.',
+ 'Missing \'tag\' field.' => 'Fehlendes Feld \'tag\'.',
+ 'Missing parameter #1 in call to sub #2.' => 'Fehlernder 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\'.',
+ 'More than one control file with the tag \'%s\' exist.' => 'Es gibt mehr als eine Kontrolldatei mit dem Tag \'%s\'.',
+ 'Name' => 'Name',
+ 'No %s was found matching the search parameters.' => 'Es wurde kein %s gefunden, auf den die Suchparameter zutreffen.',
+ 'No Customer was found matching the search parameters.' => 'Zu dem Suchbegriff wurde kein Endkunde gefunden',
+ 'No Vendor was found matching the search parameters.' => 'Zu dem Suchbegriff wurde kein Händler gefunden',
+ 'No action defined.' => 'Keine Aktion definiert.',
+ 'No customer has been selected yet.' => 'Es wurde noch kein Kunde ausgewählt.',
+ 'No or an unknown authenticantion module specified in "config/authentication.pl".' => 'Es wurde kein oder ein unbekanntes Authentifizierungsmodul in "config/authentication.pl" angegeben.',
+ 'No part was found matching the search parameters.' => 'Es wurde kein Artikel gefunden, auf den die Suchparameter zutreffen.',
+ 'No vendor has been selected yet.' => 'Es wurde noch kein Lieferant ausgewählt.',
+ 'Others' => 'Andere',
+ 'PAYMENT POSTED' => 'Rechung gebucht',
+ 'PDF export -- options' => 'PDF-Export -- Optionen',
+ 'POSTED' => 'Gebucht',
+ 'POSTED AS NEW' => 'Als neu gebucht',
+ 'PRINTED' => 'Gedruckt',
+ 'Packing List' => 'Lieferschein',
+ 'Page #1/#2' => 'Seite #1/#2',
+ 'Part Number' => 'Artikelnummer',
+ 'Part description' => 'Artikelbeschreibung',
+ 'Pick List' => 'Sammelliste',
+ 'Please enter values' => 'Bitte Werte eingeben',
+ 'Preview' => 'Druckvorschau',
+ 'Proforma Invoice' => 'Proformarechnung',
+ 'Purchase Order' => 'Lieferantenauftrag',
+ 'Quotation' => 'Angebot',
+ 'RFQ' => 'Anfrage',
+ 'Receipt, payment, reconciliation' => 'Zahlungseingang, Zahlungsausgang, Kontenabgleich',
+ 'Reports' => 'Berichte',
+ 'SAVED' => 'Gespeichert',
+ 'SAVED FOR DUNNING' => 'Gespeichert',
+ 'SCREENED' => 'Angezeigt',
+ 'Select a Customer' => 'Endkunde auswählen',
+ 'Select a customer' => 'Einen Kunden auswählen',
+ 'Select a part' => 'Artikel auswählen',
+ 'Select a vendor' => 'Einen Lieferanten auswählen',
+ 'Storno Invoice' => 'Stornorechnung',
+ 'Storno Packing List' => 'Stornolieferschein',
+ 'Subject' => 'Betreff',
+ 'The \'tag\' field must only consist of alphanumeric characters or the carachters - _ ( )' => 'Das Feld \'tag\' darf nur aus alphanumerischen Zeichen und den Zeichen - _ ( ) bestehen.',
+ 'The LDAP server "#1:#2" is unreachable. Please check config/authentication.pl.' => 'Der LDAP-Server "#1:#2" ist nicht erreichbar. Bitte überprüfen Sie die Angaben in config/authentication.pl.',
+ 'The config file "config/authentication.pl" contained invalid Perl code:' => 'Die Konfigurationsdatei "config/authentication.pl" enthielt ungütigen Perl-Code:',
+ 'The config file "config/authentication.pl" was not found.' => 'Die Konfigurationsdatei "config/authentication.pl" wurde nicht gefunden.',
+ 'The connection to the LDAP server cannot be encrypted (SSL/TLS startup failure). Please check config/authentication.pl.' => 'Die Verbindung zum LDAP-Server kann nicht verschlüsselt werden (Fehler bei SSL/TLS-Initialisierung). Bitte überprüfen Sie die Angaben in config/authentication.pl.',
+ 'The connection to the authentication database failed:' => 'Die Verbindung zur Authentifizierungsdatenbank schlug fehl:',
+ 'The connection to the template database failed:' => 'Die Verbindung zur Vorlagendatenbank schlug fehl:',
+ 'The creation of the authentication database failed:' => 'Das Anlegen der Authentifizierungsdatenbank schlug fehl:',
+ 'The list has been printed.' => 'Die Liste wurde ausgedruckt.',
+ 'To (email)' => 'An',
+ 'Transactions, AR transactions, AP transactions' => 'Dialogbuchen, Debitorenrechnungen, Kreditorenrechnungen',
+ 'Trying to call a sub without a name' => 'Es wurde versucht, eine Unterfunktion ohne Namen aufzurufen.',
+ 'Unit' => 'Einheit',
+ 'Unknown dependency \'%s\'.' => 'Unbekannte Abhängigkeit \'%s\'.',
+ 'Value' => 'Wert',
+ 'Variable' => 'Variable',
+ 'Vendor details' => 'Lieferantendetails',
+ 'View warehouse content' => 'Lagerbestand ansehen',
+ 'Warehouse management' => 'Lagerverwaltung/Bestandsveränderung',
+ 'You do not have the permissions to access this function.' => 'Sie verfügen nicht über die notwendigen Rechte, um auf diese Funktion zuzugreifen.',
+ 'You have to fill in at least an account number, the bank code, the IBAN and the BIC.' => 'Sie müssen zumindest die Kontonummer, die Bankleitzahl, die IBAN und den BIC angeben.',
+ 'Your PostgreSQL installationen uses UTF-8 as its encoding. Therefore you have to configure Lx-Office to use UTF-8 as well.' => 'Ihre PostgreSQL-Installation benutzt UTF-8 als Zeichensatz. Sie müssen deshalb Lx-Office so konfigurieren, dass es ebenfalls UTF-8 als Zeichensatz benutzt.',
+ '[email]' => '[email]',
+ 'bankaccounts' => 'Bankkonten',
+ 'bin_list' => 'Lagerliste',
+ 'config/authentication.pl: Key "DB_config" is missing.' => 'config/authentication.pl: Das Schlüsselwort "DB_config" fehlt.',
+ 'config/authentication.pl: Key "LDAP_config" is missing.' => 'config/authentication.pl: Der Schlüssel "LDAP_config" fehlt.',
+ 'config/authentication.pl: Missing parameters in "DB_config". Required parameters are "host", "db" and "user".' => 'config/authentication.pl: Fehlende Parameter in "DB_config". Benötigte Parameter sind "host", "db" und "user".',
+ 'config/authentication.pl: Missing parameters in "LDAP_config". Required parameters are "host", "attribute" and "base_dn".' => 'config/authentication.pl: Fehlende Parameter in "LDAP_config". Benötigt werden "host", "attribute" und "base_dn".',
+ 'customer' => 'Kunde',
+ 'invoice' => 'Rechnung',
+ 'no' => 'nein',
+ 'packing_list' => 'Versandliste',
+ 'pick_list' => 'Entnahmeliste',
+ 'proforma' => 'Proforma',
+ 'purchase_order' => 'Auftrag',
+ 'report_generator_dispatch_to is not defined.' => 'report_generator_dispatch_to ist nicht definiert.',
+ 'report_generator_nextsub is not defined.' => 'report_generator_nextsub ist nicht definiert.',
+ 'request_quotation' => 'Angebotsanforderung',
+ 'sales_order' => 'Kundenauftrag',
+ 'sales_quotation' => 'Verkaufsangebot',
+ 'vendor' => 'Lieferant',
+ 'yes' => 'ja',
+};
+
+$self->{subs} = {
+ 'E' => 'E',
+ 'H' => 'H',
+ 'NTI' => 'NTI',
+ 'Q' => 'Q',
+ 'ap_transaction' => 'ap_transaction',
+ 'ar_transaction' => 'ar_transaction',
+ 'bank_account_add' => 'bank_account_add',
+ 'bank_account_display_form' => 'bank_account_display_form',
+ 'bank_account_edit' => 'bank_account_edit',
+ 'bank_account_list' => 'bank_account_list',
+ 'bank_account_save' => 'bank_account_save',
+ 'build_std_url' => 'build_std_url',
+ 'calculate_qty' => 'calculate_qty',
+ 'call_sub' => 'call_sub',
+ 'cov_selection_internal' => 'cov_selection_internal',
+ 'delivery_customer_selection' => 'delivery_customer_selection',
+ 'dispatcher' => 'dispatcher',
+ 'format_dates' => 'format_dates',
+ 'gl_transaction' => 'gl_transaction',
+ 'mark_as_paid_common' => 'mark_as_paid_common',
+ 'part_selection_internal' => 'part_selection_internal',
+ 'reformat_numbers' => 'reformat_numbers',
+ 'report_generator_back' => 'report_generator_back',
+ 'report_generator_dispatcher' => 'report_generator_dispatcher',
+ 'report_generator_do' => 'report_generator_do',
+ 'report_generator_export_as_csv' => 'report_generator_export_as_csv',
+ 'report_generator_export_as_pdf' => 'report_generator_export_as_pdf',
+ 'report_generator_set_default_sort' => 'report_generator_set_default_sort',
+ 'retrieve_partunits' => 'retrieve_partunits',
+ 'sales_invoice' => 'sales_invoice',
+ 'select_part' => 'select_part',
+ 'select_part_internal' => 'select_part_internal',
+ 'set_longdescription' => 'set_longdescription',
+ 'show_history' => 'show_history',
+ 'show_vc_details' => 'show_vc_details',
+ 'vendor_invoice' => 'vendor_invoice',
+ 'vendor_selection' => 'vendor_selection',
+ 'erfassen' => 'add',
+ 'zurück' => 'back',
+ 'Übernehmen' => 'close',
+ 'weiter' => 'continue',
+ 'löschen' => 'delete',
+ 'als_csv_exportieren' => 'export_as_csv',
+ 'als_pdf_exportieren' => 'export_as_pdf',
+ 'neue_ware' => 'new_part',
+ 'speichern' => 'save',
+};
+
+1;
diff --git a/locale/de/menu b/locale/de/menu
index 28ed3678a..61e064883 100644
--- a/locale/de/menu
+++ b/locale/de/menu
@@ -40,6 +40,7 @@ $self->{texts} = {
'Add Vendor' => 'Lieferant erfassen',
'Add Vendor Invoice' => 'Einkaufsrechnung erfassen',
'Add Warehouse' => 'Lager erfassen',
+ 'Add bank account' => 'Bankkonto erfassen',
'Administration area' => 'Administrationsbereich',
'Advance turnover tax return' => 'Umsatzsteuervoranmeldung',
'All reports' => 'Alle Berichte (Kontenübersicht, Summen- u. Saldenliste, GuV, BWA, Bilanz, Projektbuchungen)',
@@ -47,6 +48,9 @@ $self->{texts} = {
'Audit Control' => 'Bücherkontrolle',
'BWA' => 'BWA',
'Balance Sheet' => 'Bilanz',
+ 'Bank accounts' => 'Bankkonten',
+ 'Bank transfer via SEPA' => 'Überweisung via SEPA',
+ 'Bank transfers via SEPA' => 'Überweisungen via SEPA',
'Batch Printing' => 'Druck',
'Bcc' => 'Bcc',
'Binding to the LDAP server as "#1" failed. Please check config/authentication.pl.' => 'Die Anmeldung am LDAP-Server als "#1" schlug fehl. Bitte überprüfen Sie die Angaben in config/authentication.pl.',
@@ -131,6 +135,7 @@ $self->{texts} = {
'List Printer' => 'Drucker anzeigen',
'List Tax' => 'Bearbeiten',
'List Warehouses' => 'Lager anzeigen',
+ 'List bank accounts' => 'Bankkonten anzeigen',
'Logout' => 'Abmeldung',
'Manage license keys' => 'Lizenzschlüssel verwalten',
'Master Data' => 'Stammdaten',
diff --git a/locale/de/menunew b/locale/de/menunew
index 8b285c133..f9cb66da2 100644
--- a/locale/de/menunew
+++ b/locale/de/menunew
@@ -39,6 +39,7 @@ $self->{texts} = {
'Add Vendor' => 'Lieferant erfassen',
'Add Vendor Invoice' => 'Einkaufsrechnung erfassen',
'Add Warehouse' => 'Lager erfassen',
+ 'Add bank account' => 'Bankkonto erfassen',
'Administration area' => 'Administrationsbereich',
'Advance turnover tax return' => 'Umsatzsteuervoranmeldung',
'All reports' => 'Alle Berichte (Kontenübersicht, Summen- u. Saldenliste, GuV, BWA, Bilanz, Projektbuchungen)',
@@ -46,6 +47,9 @@ $self->{texts} = {
'Audit Control' => 'Bücherkontrolle',
'BWA' => 'BWA',
'Balance Sheet' => 'Bilanz',
+ 'Bank accounts' => 'Bankkonten',
+ 'Bank transfer via SEPA' => 'Überweisung via SEPA',
+ 'Bank transfers via SEPA' => 'Überweisungen via SEPA',
'Batch Printing' => 'Druck',
'Bcc' => 'Bcc',
'Binding to the LDAP server as "#1" failed. Please check config/authentication.pl.' => 'Die Anmeldung am LDAP-Server als "#1" schlug fehl. Bitte überprüfen Sie die Angaben in config/authentication.pl.',
@@ -130,6 +134,7 @@ $self->{texts} = {
'List Printer' => 'Drucker anzeigen',
'List Tax' => 'Bearbeiten',
'List Warehouses' => 'Lager anzeigen',
+ 'List bank accounts' => 'Bankkonten anzeigen',
'Logout' => 'Abmeldung',
'Manage license keys' => 'Lizenzschlüssel verwalten',
'Master Data' => 'Stammdaten',
diff --git a/locale/de/sepa b/locale/de/sepa
new file mode 100644
index 000000000..8b44c16c9
--- /dev/null
+++ b/locale/de/sepa
@@ -0,0 +1,279 @@
+#!/usr/bin/perl
+
+$self->{texts} = {
+ 'A temporary file could not be created. Please verify that the directory "#1" is writeable by the webserver.' => 'Eine temporäre Datei konnte nicht angelegt werden. Bitte stellen Sie sicher, dass das Verzeichnis "#1" vom Webserver beschrieben werden darf.',
+ 'ADDED' => 'Hinzugefügt',
+ 'AP' => 'Einkauf',
+ 'AP Transaction' => 'Kreditorenbuchung',
+ 'AR' => 'Verkauf',
+ 'AR Transaction' => 'Debitorenbuchung',
+ 'Account number #1, bank code #2, #3' => 'Kontonummer #1, BLZ #2, #3',
+ 'Address' => 'Adresse',
+ 'Advance turnover tax return' => 'Umsatzsteuervoranmeldung',
+ 'All of the exports you have selected were already closed.' => 'Alle von Ihnen ausgewählten Exporte sind bereits abgeschlossen.',
+ 'All reports' => 'Alle Berichte (Kontenübersicht, Summen- u. Saldenliste, GuV, BWA, Bilanz, Projektbuchungen)',
+ 'All the selected exports have already been closed, or all of their items have already been executed.' => 'Alle ausgewählten Exporte sind als abgeschlossen markiert, oder für alle Einträge wurden bereits Zahlungen verbucht.',
+ 'Amount' => 'Betrag',
+ 'Attempt to call an undefined sub named \'%s\'' => 'Es wurde versucht, eine nicht definierte Unterfunktion namens \'%s\' aufzurufen.',
+ 'Bank transfer payment list for export #1' => 'Überweisungszahlungsliste für SEPA-Export #1',
+ 'Bcc' => 'Bcc',
+ 'Bin List' => 'Lagerliste',
+ 'Binding to the LDAP server as "#1" failed. Please check config/authentication.pl.' => 'Die Anmeldung am LDAP-Server als "#1" schlug fehl. Bitte überprüfen Sie die Angaben in config/authentication.pl.',
+ 'CANCELED' => 'Storniert',
+ 'CR' => 'H',
+ 'CRM admin' => 'Administration',
+ 'CRM create customers, vendors and contacts' => 'Erfassen (Kunden, Lieferanten, Personen)',
+ 'CRM follow up' => 'Wiedervorlage',
+ 'CRM know how' => 'Wissens DB',
+ 'CRM notices' => 'Notizen',
+ 'CRM opportunity' => 'Auftragschance',
+ 'CRM optional software' => 'CRM optionale Software',
+ 'CRM other' => 'alles Andere',
+ 'CRM search' => 'Adresssuche',
+ 'CRM send email' => 'eMail',
+ 'CRM services' => 'Dienstleistung',
+ 'CRM status' => 'Admin Stautus',
+ 'CRM termin' => 'Termine',
+ 'CRM user' => 'Admin Benutzer',
+ 'CSV export -- options' => 'CSV-Export -- Optionen',
+ 'Cc' => 'Cc',
+ 'Change Lx-Office installation settings (all menu entries beneath \'System\')' => 'Verändern der Lx-Office-Installationseinstellungen (Menüpunkte unterhalb von \'System\')',
+ 'Close SEPA exports' => 'SEPA-Export abschließen',
+ 'Closed' => 'Geschlossen',
+ 'Confirmation' => 'Auftragsbestätigung',
+ 'Contact' => 'Kontakt',
+ 'Could not spawn the printer command.' => 'Die Druckanwendung konnte nicht gestartet werden.',
+ 'Create and edit RFQs' => 'Lieferantenanfragen erfassen und bearbeiten',
+ 'Create and edit customers and vendors' => 'Kunden und Lieferanten erfassen und bearbeiten',
+ 'Create and edit dunnings' => 'Mahnungen erfassen und bearbeiten',
+ 'Create and edit invoices and credit notes' => 'Rechnungen und Gutschriften erfassen und bearbeiten',
+ 'Create and edit parts, services, assemblies' => 'Artikel, Dienstleistungen, Erzeugnisse erfassen und bearbeiten',
+ 'Create and edit projects' => 'Projekte erfassen und bearbeiten',
+ 'Create and edit purchase delivery orders' => 'Lieferscheine von Lieferanten erfassen und bearbeiten',
+ 'Create and edit purchase orders' => 'Lieferantenaufträge erfassen und bearbeiten',
+ 'Create and edit sales delivery orders' => 'Lieferscheine für Kunden erfassen und bearbeiten',
+ 'Create and edit sales orders' => 'Auftragsbestätigungen erfassen und bearbeiten',
+ 'Create and edit sales quotations' => 'Angebote erfassen und bearbeiten',
+ 'Create and edit vendor invoices' => 'Eingangsrechnungen erfassen und bearbeiten',
+ 'Create bank transfer via SEPA XML' => 'Überweisung via SEPA XML erzeugen',
+ 'Credit Note' => 'Gutschrift',
+ 'Customer' => 'Kunde',
+ 'Customer Number' => 'Kundennummer',
+ 'Customer details' => 'Kundendetails',
+ 'DATEV Export' => 'DATEV-Export',
+ 'DELETED' => 'Gelöscht',
+ 'DR' => 'S',
+ 'DUNNING STARTED' => 'Mahnprozess gestartet',
+ 'Dataset upgrade' => 'Datenbankaktualisierung',
+ 'Date' => 'Datum',
+ 'Delivery Order' => 'Lieferschein',
+ 'Dependency loop detected:' => 'Schleife in den Abhängigkeiten entdeckt:',
+ 'Destination BIC' => 'Ziel-BIC',
+ 'Destination IBAN' => 'Ziel-IBAN',
+ 'Directory' => 'Verzeichnis',
+ 'Dunning' => 'Mahnung',
+ 'ELSE' => 'Zusatz',
+ 'Either there are no open invoices, or you have already initiated bank transfers with the open amounts for those that are still open.' => 'Entweder gibt es keine offenen Rechnungen, oder es wurden bereits Überweisungen über die offenen Beträge aller offenen Rechnungen erstellt.',
+ 'Employee' => 'Bearbeiter',
+ 'Enter longdescription' => 'Langtext eingeben',
+ 'Error in database control file \'%s\': %s' => 'Fehler in Datenbankupgradekontrolldatei \'%s\': %s',
+ 'Executed' => 'Ausgeführt',
+ 'Execution date' => 'Ausführungsdatum',
+ 'Execution date from' => 'Ausführungsdatum von',
+ 'Execution date to' => 'Ausführungsdatum bis',
+ 'Export date' => 'Exportdatum',
+ 'Export date from' => 'Exportdatum von',
+ 'Export date to' => 'Exportdatum bis',
+ 'File' => 'Datei',
+ 'GL Transaction' => 'Dialogbuchung',
+ 'General ledger and cash' => 'Finanzbuchhaltung und Zahlungsverkehr',
+ 'History' => 'Historie',
+ 'Invoice' => 'Rechnung',
+ 'Invoice number' => 'Rechnungsnummer',
+ 'List of bank transfers' => 'Überweisungsliste',
+ 'MAILED' => 'Gesendet',
+ 'Manage license keys' => 'Lizenzschlüssel verwalten',
+ 'Mark as paid?' => 'Als bezahlt markieren?',
+ 'Marked as paid' => 'Als bezahlt markiert',
+ 'Master Data' => 'Stammdaten',
+ 'May set the BCC field when sending emails' => 'Beim Verschicken von Emails das Feld \'BCC\' setzen',
+ 'Message' => 'Nachricht',
+ 'Missing \'description\' field.' => 'Fehlendes Feld \'description\'.',
+ 'Missing \'tag\' field.' => 'Fehlendes Feld \'tag\'.',
+ 'Missing parameter #1 in call to sub #2.' => 'Fehlernder 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\'.',
+ 'More than one control file with the tag \'%s\' exist.' => 'Es gibt mehr als eine Kontrolldatei mit dem Tag \'%s\'.',
+ 'Multi mode not supported.' => 'Multimodus wird nicht unterstützt.',
+ 'Name' => 'Name',
+ 'No' => 'Nein',
+ 'No %s was found matching the search parameters.' => 'Es wurde kein %s gefunden, auf den die Suchparameter zutreffen.',
+ 'No Customer was found matching the search parameters.' => 'Zu dem Suchbegriff wurde kein Endkunde gefunden',
+ 'No Vendor was found matching the search parameters.' => 'Zu dem Suchbegriff wurde kein Händler gefunden',
+ 'No action defined.' => 'Keine Aktion definiert.',
+ 'No customer has been selected yet.' => 'Es wurde noch kein Kunde ausgewählt.',
+ 'No or an unknown authenticantion module specified in "config/authentication.pl".' => 'Es wurde kein oder ein unbekanntes Authentifizierungsmodul in "config/authentication.pl" angegeben.',
+ 'No part was found matching the search parameters.' => 'Es wurde kein Artikel gefunden, auf den die Suchparameter zutreffen.',
+ 'No transfers were executed in this export.' => 'In diesem SEPA-Export wurden keine Überweisungen ausgeführt.',
+ 'No vendor has been selected yet.' => 'Es wurde noch kein Lieferant ausgewählt.',
+ 'Number' => 'Nummer',
+ 'Others' => 'Andere',
+ 'PAYMENT POSTED' => 'Rechung gebucht',
+ 'PDF export -- options' => 'PDF-Export -- Optionen',
+ 'POSTED' => 'Gebucht',
+ 'POSTED AS NEW' => 'Als neu gebucht',
+ 'PRINTED' => 'Gedruckt',
+ 'Packing List' => 'Lieferschein',
+ 'Page #1/#2' => 'Seite #1/#2',
+ 'Part Number' => 'Artikelnummer',
+ 'Part description' => 'Artikelbeschreibung',
+ 'Pick List' => 'Sammelliste',
+ 'Please enter values' => 'Bitte Werte eingeben',
+ 'Prepare bank transfer via SEPA XML' => 'Überweisung via SEPA XML vorbereiten',
+ 'Preview' => 'Druckvorschau',
+ 'Proforma Invoice' => 'Proformarechnung',
+ 'Purchase Order' => 'Lieferantenauftrag',
+ 'Quotation' => 'Angebot',
+ 'RFQ' => 'Anfrage',
+ 'Receipt, payment, reconciliation' => 'Zahlungseingang, Zahlungsausgang, Kontenabgleich',
+ 'Reference' => 'Referenz',
+ 'Reports' => 'Berichte',
+ 'Request quotation' => 'Preisanfrage',
+ 'Requested execution date from' => 'Gewünschtes Ausführungsdatum von',
+ 'Requested execution date to' => 'Gewünschtes Ausführungsdatum bis',
+ 'SAVED' => 'Gespeichert',
+ 'SAVED FOR DUNNING' => 'Gespeichert',
+ 'SCREENED' => 'Angezeigt',
+ 'Sales Invoice' => 'Rechnung',
+ 'Sales Order' => 'Kundenauftrag',
+ 'Sales quotation' => 'Angebot',
+ 'Select a Customer' => 'Endkunde auswählen',
+ 'Select a customer' => 'Einen Kunden auswählen',
+ 'Select a part' => 'Artikel auswählen',
+ 'Select a vendor' => 'Einen Lieferanten auswählen',
+ 'Source BIC' => 'Quell-BIC',
+ 'Source IBAN' => 'Quell-IBAN',
+ 'Storno Invoice' => 'Stornorechnung',
+ 'Storno Packing List' => 'Stornolieferschein',
+ 'Subject' => 'Betreff',
+ 'That export does not exist.' => 'Dieser Export existiert nicht.',
+ 'The \'tag\' field must only consist of alphanumeric characters or the carachters - _ ( )' => 'Das Feld \'tag\' darf nur aus alphanumerischen Zeichen und den Zeichen - _ ( ) bestehen.',
+ 'The LDAP server "#1:#2" is unreachable. Please check config/authentication.pl.' => 'Der LDAP-Server "#1:#2" ist nicht erreichbar. Bitte überprüfen Sie die Angaben in config/authentication.pl.',
+ 'The bank information must not be empty.' => 'Die Bankinformationen müssen vollständig ausgefüllt werden.',
+ 'The config file "config/authentication.pl" contained invalid Perl code:' => 'Die Konfigurationsdatei "config/authentication.pl" enthielt ungütigen Perl-Code:',
+ 'The config file "config/authentication.pl" was not found.' => 'Die Konfigurationsdatei "config/authentication.pl" wurde nicht gefunden.',
+ 'The connection to the LDAP server cannot be encrypted (SSL/TLS startup failure). Please check config/authentication.pl.' => 'Die Verbindung zum LDAP-Server kann nicht verschlüsselt werden (Fehler bei SSL/TLS-Initialisierung). Bitte überprüfen Sie die Angaben in config/authentication.pl.',
+ 'The connection to the authentication database failed:' => 'Die Verbindung zur Authentifizierungsdatenbank schlug fehl:',
+ 'The connection to the template database failed:' => 'Die Verbindung zur Vorlagendatenbank schlug fehl:',
+ 'The creation of the authentication database failed:' => 'Das Anlegen der Authentifizierungsdatenbank schlug fehl:',
+ 'The list has been printed.' => 'Die Liste wurde ausgedruckt.',
+ 'The payments have been posted.' => 'Die Zahlungen wurden gebucht.',
+ 'The selected bank account does not exist anymore.' => 'Das ausgewählte Bankkonto existiert nicht mehr.',
+ 'The selected exports have been closed.' => 'Die ausgewählten Exporte wurden abgeschlossen.',
+ 'To (email)' => 'An',
+ 'Transactions, AR transactions, AP transactions' => 'Dialogbuchen, Debitorenrechnungen, Kreditorenrechnungen',
+ 'Trying to call a sub without a name' => 'Es wurde versucht, eine Unterfunktion ohne Namen aufzurufen.',
+ 'Unit' => 'Einheit',
+ 'Unknown dependency \'%s\'.' => 'Unbekannte Abhängigkeit \'%s\'.',
+ 'Value' => 'Wert',
+ 'Variable' => 'Variable',
+ 'Vendor' => 'Lieferant',
+ 'Vendor Invoice' => 'Einkaufsrechnung',
+ 'Vendor details' => 'Lieferantendetails',
+ 'View SEPA export' => 'SEPA-Export-Details ansehen',
+ 'View warehouse content' => 'Lagerbestand ansehen',
+ 'Warehouse management' => 'Lagerverwaltung/Bestandsveränderung',
+ 'Yes' => 'Ja',
+ 'You do not have the permissions to access this function.' => 'Sie verfügen nicht über die notwendigen Rechte, um auf diese Funktion zuzugreifen.',
+ 'You have not added bank accounts yet.' => 'Sie haben noch keine Bankkoten angelegt.',
+ 'You have not selected any export.' => 'Sie haben keinen Export ausgewählt.',
+ 'You have not selected any item.' => 'Sie haben keine noch nicht gebuchten Einträge ausgewählt.',
+ 'You have selected none of the invoices.' => 'Sie haben keine der Rechnungen ausgewählt.',
+ 'You have to enter a company name in your user preferences (see the "Program" menu, "Preferences").' => 'Sie müssen einen Firmennamen in Ihren Benutzereinstellungen angeben (siehe "Programm"-Menü, "Benuztereinstellungen).',
+ 'You have to specify an execution date for each antry.' => 'Sie müssen für jeden zu buchenden Eintrag ein Ausführungsdatum angeben.',
+ 'Your PostgreSQL installationen uses UTF-8 as its encoding. Therefore you have to configure Lx-Office to use UTF-8 as well.' => 'Ihre PostgreSQL-Installation benutzt UTF-8 als Zeichensatz. Sie müssen deshalb Lx-Office so konfigurieren, dass es ebenfalls UTF-8 als Zeichensatz benutzt.',
+ '[email]' => '[email]',
+ 'bank_transfer_payment_list_#1' => 'ueberweisungs_zahlungsliste_#1',
+ 'banktransfers' => 'ueberweisungen',
+ 'bin_list' => 'Lagerliste',
+ 'closed' => 'geschlossen',
+ 'config/authentication.pl: Key "DB_config" is missing.' => 'config/authentication.pl: Das Schlüsselwort "DB_config" fehlt.',
+ 'config/authentication.pl: Key "LDAP_config" is missing.' => 'config/authentication.pl: Der Schlüssel "LDAP_config" fehlt.',
+ 'config/authentication.pl: Missing parameters in "DB_config". Required parameters are "host", "db" and "user".' => 'config/authentication.pl: Fehlende Parameter in "DB_config". Benötigte Parameter sind "host", "db" und "user".',
+ 'config/authentication.pl: Missing parameters in "LDAP_config". Required parameters are "host", "attribute" and "base_dn".' => 'config/authentication.pl: Fehlende Parameter in "LDAP_config". Benötigt werden "host", "attribute" und "base_dn".',
+ 'customer' => 'Kunde',
+ 'executed' => 'ausgeführt',
+ 'invoice' => 'Rechnung',
+ 'no' => 'nein',
+ 'not yet executed' => 'Noch nicht ausgeführt',
+ 'open' => 'Offen',
+ 'packing_list' => 'Versandliste',
+ 'pick_list' => 'Entnahmeliste',
+ 'proforma' => 'Proforma',
+ 'purchase_order' => 'Auftrag',
+ 'report_generator_dispatch_to is not defined.' => 'report_generator_dispatch_to ist nicht definiert.',
+ 'report_generator_nextsub is not defined.' => 'report_generator_nextsub ist nicht definiert.',
+ 'request_quotation' => 'Angebotsanforderung',
+ 'sales_order' => 'Kundenauftrag',
+ 'sales_quotation' => 'Verkaufsangebot',
+ 'vendor' => 'Lieferant',
+ 'yes' => 'ja',
+};
+
+$self->{subs} = {
+ 'E' => 'E',
+ 'H' => 'H',
+ 'NTI' => 'NTI',
+ 'Q' => 'Q',
+ 'ap_transaction' => 'ap_transaction',
+ 'ar_transaction' => 'ar_transaction',
+ 'bank_transfer_add' => 'bank_transfer_add',
+ 'bank_transfer_create' => 'bank_transfer_create',
+ 'bank_transfer_download_sepa_xml' => 'bank_transfer_download_sepa_xml',
+ 'bank_transfer_edit' => 'bank_transfer_edit',
+ 'bank_transfer_list' => 'bank_transfer_list',
+ 'bank_transfer_mark_as_closed_step1' => 'bank_transfer_mark_as_closed_step1',
+ 'bank_transfer_mark_as_closed_step2' => 'bank_transfer_mark_as_closed_step2',
+ 'bank_transfer_payment_list_as_pdf' => 'bank_transfer_payment_list_as_pdf',
+ 'bank_transfer_post_payments' => 'bank_transfer_post_payments',
+ 'bank_transfer_search' => 'bank_transfer_search',
+ 'build_std_url' => 'build_std_url',
+ 'calculate_qty' => 'calculate_qty',
+ 'call_sub' => 'call_sub',
+ 'cov_selection_internal' => 'cov_selection_internal',
+ 'delivery_customer_selection' => 'delivery_customer_selection',
+ 'dispatcher' => 'dispatcher',
+ 'format_dates' => 'format_dates',
+ 'gl_transaction' => 'gl_transaction',
+ 'mark_as_paid_common' => 'mark_as_paid_common',
+ 'part_selection_internal' => 'part_selection_internal',
+ 'reformat_numbers' => 'reformat_numbers',
+ 'report_generator_back' => 'report_generator_back',
+ 'report_generator_dispatcher' => 'report_generator_dispatcher',
+ 'report_generator_do' => 'report_generator_do',
+ 'report_generator_export_as_csv' => 'report_generator_export_as_csv',
+ 'report_generator_export_as_pdf' => 'report_generator_export_as_pdf',
+ 'report_generator_set_default_sort' => 'report_generator_set_default_sort',
+ 'retrieve_partunits' => 'retrieve_partunits',
+ 'sales_invoice' => 'sales_invoice',
+ 'select_part' => 'select_part',
+ 'select_part_internal' => 'select_part_internal',
+ 'set_longdescription' => 'set_longdescription',
+ 'show_history' => 'show_history',
+ 'show_vc_details' => 'show_vc_details',
+ 'vendor_invoice' => 'vendor_invoice',
+ 'vendor_selection' => 'vendor_selection',
+ 'zurück' => 'back',
+ 'Übernehmen' => 'close',
+ 'weiter' => 'continue',
+ 'Überweisung_erstellen' => 'create_bank_transfer',
+ 'als_csv_exportieren' => 'export_as_csv',
+ 'als_pdf_exportieren' => 'export_as_pdf',
+ 'abschließen' => 'mark_as_closed',
+ 'neue_ware' => 'new_part',
+ 'zahlungsliste_als_pdf' => 'payment_list_as_pdf',
+ 'zahlungen_buchen' => 'post_payments',
+ 'sepa_xml_download' => 'sepa_xml_download',
+ 'schritt_2' => 'step_2',
+};
+
+1;
diff --git a/menu.ini b/menu.ini
index 7835f30b0..da0270236 100644
--- a/menu.ini
+++ b/menu.ini
@@ -339,6 +339,10 @@ ACCESS=cash
module=rc.pl
action=reconciliation
+[Cash--Bank transfer via SEPA]
+module=sepa.pl
+action=bank_transfer_add
+
[Cash--Reports]
module=menu.pl
action=acc_menu
@@ -355,6 +359,9 @@ module=rp.pl
action=report
report=payments
+[Cash--Reports--Bank transfers via SEPA]
+module=sepa.pl
+action=bank_transfer_search
[Reports]
@@ -536,6 +543,20 @@ submenu=1
module=am.pl
action=list_tax
+[System--Bank accounts]
+module=menu.pl
+action=acc_menu
+target=acc_menu
+submenu=1
+
+[System--Bank accounts--Add bank account]
+module=bankaccounts.pl
+action=bank_account_add
+
+[System--Bank accounts--List bank accounts]
+module=bankaccounts.pl
+action=bank_account_list
+
[System--Groups]
module=menu.pl
action=acc_menu
diff --git a/sepa.pl b/sepa.pl
new file mode 120000
index 000000000..385000d1b
--- /dev/null
+++ b/sepa.pl
@@ -0,0 +1 @@
+am.pl
\ No newline at end of file
diff --git a/sql/Pg-upgrade2/sepa.sql b/sql/Pg-upgrade2/sepa.sql
new file mode 100644
index 000000000..f2dd7026d
--- /dev/null
+++ b/sql/Pg-upgrade2/sepa.sql
@@ -0,0 +1,44 @@
+-- @tag: sepa
+-- @description: Tabellen für den SEPA-XML-Exportassistenten
+-- @depends: release_2_6_0
+-- @ignore: 0
+--DROP TABLE sepa_export_items;
+--DROP TABLE sepa_export;
+--DROP SEQUENCE sepa_export_id_seq;
+
+CREATE SEQUENCE sepa_export_id_seq;
+
+CREATE TABLE sepa_export (
+ id integer NOT NULL DEFAULT nextval('sepa_export_id_seq'),
+ employee_id integer NOT NULL,
+ executed boolean DEFAULT FALSE,
+ closed boolean DEFAULT FALSE,
+ itime timestamp DEFAULT now(),
+
+ PRIMARY KEY (id),
+ FOREIGN KEY (employee_id) REFERENCES employee (id)
+);
+
+CREATE TABLE sepa_export_items (
+ id integer NOT NULL DEFAULT nextval('id'),
+ sepa_export_id integer NOT NULL,
+ ap_id integer NOT NULL,
+ chart_id integer NOT NULL,
+ amount NUMERIC(25,5),
+ reference varchar(35),
+ requested_execution_date date,
+ executed boolean DEFAULT FALSE,
+ execution_date date,
+
+ our_iban varchar(100),
+ our_bic varchar(100),
+ vendor_iban varchar(100),
+ vendor_bic varchar(100),
+
+ end_to_end_id varchar(35),
+
+ PRIMARY KEY (id),
+ FOREIGN KEY (sepa_export_id) REFERENCES sepa_export (id),
+ FOREIGN KEY (ap_id) REFERENCES ap (id),
+ FOREIGN KEY (chart_id) REFERENCES chart (id)
+);
diff --git a/templates/webpages/bankaccounts/bank_account_display_form_de.html b/templates/webpages/bankaccounts/bank_account_display_form_de.html
new file mode 100644
index 000000000..89faee13c
--- /dev/null
+++ b/templates/webpages/bankaccounts/bank_account_display_form_de.html
@@ -0,0 +1,70 @@
+[% USE HTML %]
+
+
+[%- IF params.error %]
+ [% params.error %]
+[%- END %]
+
+ [% title %]
+
+
+
+
+