Revision c1716dbd
Von Moritz Bunkus vor fast 14 Jahren hinzugefügt
SL/SEPA.pm | ||
---|---|---|
178 | 178 |
my ($columns, $joins); |
179 | 179 |
|
180 | 180 |
if ($params{details}) { |
181 |
$columns = qq|, arap.invnumber, arap.invoice, vc.name AS vc_name, c.accno AS chart_accno, c.description AS chart_description|; |
|
181 |
$columns = qq|, arap.invnumber, arap.invoice, arap.transdate AS reference_date, vc.name AS vc_name, c.accno AS chart_accno, c.description AS chart_description|;
|
|
182 | 182 |
$joins = qq|LEFT JOIN ${arap} arap ON (sei.${arap}_id = arap.id) |
183 | 183 |
LEFT JOIN ${vc} vc ON (arap.${vc}_id = vc.id) |
184 | 184 |
LEFT JOIN chart c ON (sei.chart_id = c.id)|; |
SL/SEPA/XML.pm | ||
---|---|---|
32 | 32 |
$self->{src_charset} = 'UTF-8'; |
33 | 33 |
$self->{grouped} = 0; |
34 | 34 |
|
35 |
map { $self->{$_} = $params{$_} if (exists $params{$_}) } qw(src_charset company message_id grouped);
|
|
35 |
map { $self->{$_} = $params{$_} if (exists $params{$_}) } qw(src_charset company creditor_id message_id grouped collection);
|
|
36 | 36 |
|
37 | 37 |
$self->{iconv} = SL::Iconv->new($self->{src_charset}, "UTF-8") || croak "Unsupported source charset $self->{src_charset}."; |
38 | 38 |
|
39 | 39 |
my $missing_parameter = first { !$self->{$_} } qw(company message_id); |
40 | 40 |
croak "Missing parameter: $missing_parameter" if ($missing_parameter); |
41 |
croak "Missing parameter: creditor_id" if !$self->{creditor_id} && $self->{collection}; |
|
41 | 42 |
|
42 |
map { $self->{$_} = $self->_replace_special_chars($self->{iconv}->convert($self->{$_})) } qw(company message_id); |
|
43 |
map { $self->{$_} = $self->_replace_special_chars($self->{iconv}->convert($self->{$_})) } qw(company message_id creditor_id);
|
|
43 | 44 |
} |
44 | 45 |
|
45 | 46 |
sub add_transaction { |
... | ... | |
77 | 78 |
my $self = shift; |
78 | 79 |
my $amount = shift; |
79 | 80 |
|
80 |
return sprintf '%d.%02d', int($amount), int($amount * 100) % 100;
|
|
81 |
return sprintf '%.02f', $amount;
|
|
81 | 82 |
} |
82 | 83 |
|
83 | 84 |
sub _group_transactions { |
... | ... | |
116 | 117 |
DATA_INDENT => 2, |
117 | 118 |
ENCODING => 'utf-8'); |
118 | 119 |
|
119 |
my @now = localtime; |
|
120 |
my $time_zone = strftime "%z", @now; |
|
121 |
my $now_str = strftime('%Y-%m-%dT%H:%M:%S', @now) . substr($time_zone, 0, 3) . ':' . substr($time_zone, 3, 2); |
|
120 |
my @now = localtime; |
|
121 |
my $time_zone = strftime "%z", @now; |
|
122 |
my $now_str = strftime('%Y-%m-%dT%H:%M:%S', @now) . substr($time_zone, 0, 3) . ':' . substr($time_zone, 3, 2); |
|
123 |
|
|
124 |
my $is_coll = $self->{collection}; |
|
125 |
my $cd_src = $is_coll ? 'Cdtr' : 'Dbtr'; |
|
126 |
my $cd_dst = $is_coll ? 'Dbtr' : 'Cdtr'; |
|
127 |
my $pain_id = $is_coll ? 'pain.008.002.01' : 'pain.001.001.02'; |
|
128 |
my $pain_elmt = $is_coll ? 'pain.008.001.01' : 'pain.001.001.02'; |
|
129 |
my @pii_base = (strftime('PII%Y%m%d%H%M%S', @now), rand(1000000000)); |
|
122 | 130 |
|
123 | 131 |
my $grouped_transactions = $self->_group_transactions(); |
124 | 132 |
|
125 | 133 |
$xml->xmlDecl(); |
134 |
|
|
126 | 135 |
$xml->startTag('Document', |
127 |
'xmlns' => 'urn:sepade:xsd:pain.001.001.02.grp',
|
|
136 |
'xmlns' => "urn:swift:xsd:\$${pain_id}",
|
|
128 | 137 |
'xmlns:xsi' => 'http://www.w3.org/2001/XMLSchema-instance', |
129 |
'xsi:schemaLocation' => 'urn:sepade:xsd:pain.001.001.02.grp pain.001.001.02.grp.xsd');
|
|
138 |
'xsi:schemaLocation' => "urn:swift:xsd:\$${pain_id} ${pain_id}.xsd");
|
|
130 | 139 |
|
131 |
$xml->startTag('pain.001.001.02');
|
|
140 |
$xml->startTag($pain_elmt);
|
|
132 | 141 |
|
133 | 142 |
$xml->startTag('GrpHdr'); |
134 | 143 |
$xml->dataElement('MsgId', encode('UTF-8', substr($self->{message_id}, 0, 35))); |
... | ... | |
148 | 157 |
my $master_transaction = $transaction_group->{transactions}->[0]; |
149 | 158 |
|
150 | 159 |
$xml->startTag('PmtInf'); |
151 |
$xml->dataElement('PmtMtd', 'TRF'); |
|
160 |
if ($is_coll) { |
|
161 |
$xml->dataElement('PmtInfId', sprintf('%s%010d', @pii_base)); |
|
162 |
$pii_base[1]++; |
|
163 |
} |
|
164 |
$xml->dataElement('PmtMtd', $is_coll ? 'DD' : 'TRF'); |
|
152 | 165 |
|
153 | 166 |
$xml->startTag('PmtTpInf'); |
154 | 167 |
$xml->startTag('SvcLvl'); |
155 | 168 |
$xml->dataElement('Cd', 'SEPA'); |
156 | 169 |
$xml->endTag('SvcLvl'); |
170 |
|
|
171 |
if ($is_coll) { |
|
172 |
$xml->startTag('LclInstrm'); |
|
173 |
$xml->dataElement('Cd', 'CORE'); |
|
174 |
$xml->endTag('LclInstrm'); |
|
175 |
$xml->dataElement('SeqTp', 'OOFF'); |
|
176 |
} |
|
157 | 177 |
$xml->endTag('PmtTpInf'); |
158 | 178 |
|
159 |
$xml->dataElement('ReqdExctnDt', $master_transaction->get('execution_date')); |
|
160 |
$xml->startTag('Dbtr');
|
|
179 |
$xml->dataElement($is_coll ? 'ReqdColltnDt' : 'ReqdExctnDt', $master_transaction->get('execution_date'));
|
|
180 |
$xml->startTag($cd_src);
|
|
161 | 181 |
$xml->dataElement('Nm', encode('UTF-8', substr($self->{company}, 0, 70))); |
162 |
$xml->endTag('Dbtr');
|
|
182 |
$xml->endTag($cd_src);
|
|
163 | 183 |
|
164 |
$xml->startTag('DbtrAcct');
|
|
184 |
$xml->startTag($cd_src . 'Acct');
|
|
165 | 185 |
$xml->startTag('Id'); |
166 | 186 |
$xml->dataElement('IBAN', $master_transaction->get('src_iban', 34)); |
167 | 187 |
$xml->endTag('Id'); |
168 |
$xml->endTag('DbtrAcct');
|
|
188 |
$xml->endTag($cd_src . 'Acct');
|
|
169 | 189 |
|
170 |
$xml->startTag('DbtrAgt');
|
|
190 |
$xml->startTag($cd_src . 'Agt');
|
|
171 | 191 |
$xml->startTag('FinInstnId'); |
172 | 192 |
$xml->dataElement('BIC', $master_transaction->get('src_bic', 20)); |
173 | 193 |
$xml->endTag('FinInstnId'); |
174 |
$xml->endTag('DbtrAgt');
|
|
194 |
$xml->endTag($cd_src . 'Agt');
|
|
175 | 195 |
|
176 | 196 |
$xml->dataElement('ChrgBr', 'SLEV'); |
177 | 197 |
|
178 | 198 |
foreach my $transaction (@{ $transaction_group->{transactions} }) { |
179 |
$xml->startTag('CdtTrfTxInf'); |
|
199 |
$xml->startTag($is_coll ? 'DrctDbtTxInf' : 'CdtTrfTxInf');
|
|
180 | 200 |
|
181 | 201 |
$xml->startTag('PmtId'); |
182 | 202 |
$xml->dataElement('EndToEndId', $transaction->get('end_to_end_id', 35)); |
183 | 203 |
$xml->endTag('PmtId'); |
184 | 204 |
|
185 |
$xml->startTag('Amt'); |
|
186 |
$xml->startTag('InstdAmt', 'Ccy' => 'EUR'); |
|
187 |
$xml->characters($self->_format_amount($transaction->{amount})); |
|
188 |
$xml->endTag('InstdAmt'); |
|
189 |
$xml->endTag('Amt'); |
|
190 |
|
|
191 |
$xml->startTag('CdtrAgt'); |
|
205 |
if ($is_coll) { |
|
206 |
$xml->startTag('InstdAmt', 'Ccy' => 'EUR'); |
|
207 |
$xml->characters($self->_format_amount($transaction->{amount})); |
|
208 |
$xml->endTag('InstdAmt'); |
|
209 |
|
|
210 |
$xml->startTag('DrctDbtTx'); |
|
211 |
|
|
212 |
$xml->startTag('MndtRltdInf'); |
|
213 |
$xml->dataElement('MndtId', $transaction->get('reference', 35)); |
|
214 |
$xml->dataElement('DtOfSgntr', $transaction->get('reference_date', 2010-12-02)); |
|
215 |
$xml->endTag('MndtRltdInf'); |
|
216 |
|
|
217 |
$xml->startTag('CdtrSchmeId'); |
|
218 |
$xml->startTag('Id'); |
|
219 |
$xml->startTag('PrvtId'); |
|
220 |
$xml->startTag('OthrId'); |
|
221 |
$xml->dataElement('Id', encode('UTF-8', substr($self->{creditor_id}, 0, 35))); |
|
222 |
$xml->dataElement('IdTp', 'SEPA'); |
|
223 |
$xml->endTag('OthrId'); |
|
224 |
$xml->endTag('PrvtId'); |
|
225 |
$xml->endTag('Id'); |
|
226 |
$xml->endTag('CdtrSchmeId'); |
|
227 |
|
|
228 |
$xml->endTag('DrctDbtTx'); |
|
229 |
|
|
230 |
} else { |
|
231 |
$xml->startTag('Amt'); |
|
232 |
$xml->startTag('InstdAmt', 'Ccy' => 'EUR'); |
|
233 |
$xml->characters($self->_format_amount($transaction->{amount})); |
|
234 |
$xml->endTag('InstdAmt'); |
|
235 |
$xml->endTag('Amt'); |
|
236 |
} |
|
237 |
|
|
238 |
$xml->startTag("${cd_dst}Agt"); |
|
192 | 239 |
$xml->startTag('FinInstnId'); |
193 | 240 |
$xml->dataElement('BIC', $transaction->get('dst_bic', 20)); |
194 | 241 |
$xml->endTag('FinInstnId'); |
195 |
$xml->endTag('CdtrAgt');
|
|
242 |
$xml->endTag("${cd_dst}Agt");
|
|
196 | 243 |
|
197 |
$xml->startTag('Cdtr');
|
|
198 |
$xml->dataElement('Nm', $transaction->get('recipient', 70));
|
|
199 |
$xml->endTag('Cdtr');
|
|
244 |
$xml->startTag("${cd_dst}");
|
|
245 |
$xml->dataElement('Nm', $transaction->get('company', 70));
|
|
246 |
$xml->endTag("${cd_dst}");
|
|
200 | 247 |
|
201 |
$xml->startTag('CdtrAcct');
|
|
248 |
$xml->startTag("${cd_dst}Acct");
|
|
202 | 249 |
$xml->startTag('Id'); |
203 | 250 |
$xml->dataElement('IBAN', $transaction->get('dst_iban', 34)); |
204 | 251 |
$xml->endTag('Id'); |
205 |
$xml->endTag('CdtrAcct');
|
|
252 |
$xml->endTag("${cd_dst}Acct");
|
|
206 | 253 |
|
207 | 254 |
$xml->startTag('RmtInf'); |
208 | 255 |
$xml->dataElement('Ustrd', $transaction->get('reference', 140)); |
209 | 256 |
$xml->endTag('RmtInf'); |
210 | 257 |
|
211 |
$xml->endTag('CdtTrfTxInf'); |
|
258 |
$xml->endTag($is_coll ? 'DrctDbtTxInf' : 'CdtTrfTxInf');
|
|
212 | 259 |
} |
213 | 260 |
|
214 | 261 |
$xml->endTag('PmtInf'); |
215 | 262 |
} |
216 | 263 |
|
217 |
$xml->endTag('pain.001.001.02');
|
|
264 |
$xml->endTag($pain_elmt);
|
|
218 | 265 |
$xml->endTag('Document'); |
219 | 266 |
|
220 | 267 |
return $output; |
SL/SEPA/XML/Transaction.pm | ||
---|---|---|
25 | 25 |
$self->{sepa} = $params{sepa}; |
26 | 26 |
delete $params{sepa}; |
27 | 27 |
|
28 |
my $missing_parameter = first { !$params{$_} } qw(src_iban src_bic dst_iban dst_bic recipient reference amount end_to_end_id);
|
|
28 |
my $missing_parameter = first { !$params{$_} } qw(src_iban src_bic dst_iban dst_bic company reference amount end_to_end_id);
|
|
29 | 29 |
croak "Missing parameter: $missing_parameter" if ($missing_parameter); |
30 | 30 |
|
31 | 31 |
$params{end_to_end_id} ||= 'NOTPROVIDED'; |
... | ... | |
35 | 35 |
|
36 | 36 |
map { $self->{$_} = $self->{sepa}->{iconv}->convert($params{$_}) } keys %params; |
37 | 37 |
map { $self->{$_} =~ s/\s+//g } qw(src_iban src_bic dst_iban dst_bic); |
38 |
map { $self->{$_} = $self->{sepa}->_replace_special_chars($self->{$_}) } qw(recipient reference end_to_end_id);
|
|
38 |
map { $self->{$_} = $self->{sepa}->_replace_special_chars($self->{$_}) } qw(company reference end_to_end_id);
|
|
39 | 39 |
} |
40 | 40 |
|
41 | 41 |
sub get { |
bin/mozilla/sepa.pl | ||
---|---|---|
425 | 425 |
$main::lxdebug->leave_sub(); |
426 | 426 |
} |
427 | 427 |
|
428 |
# TODO |
|
428 | 429 |
sub bank_transfer_download_sepa_xml { |
429 | 430 |
$main::lxdebug->enter_sub(); |
430 | 431 |
|
... | ... | |
432 | 433 |
my $myconfig = \%main::myconfig; |
433 | 434 |
my $locale = $main::locale; |
434 | 435 |
my $cgi = $main::cgi; |
436 |
my $vc = $form->{vc} eq 'customer' ? 'customer' : 'vendor'; |
|
435 | 437 |
|
436 | 438 |
if (!$myconfig->{company}) { |
437 | 439 |
$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); |
438 | 440 |
} |
439 | 441 |
|
442 |
if (($vc eq 'customer') && !$myconfig->{sepa_creditor_id}) { |
|
443 |
$form->show_generic_error($locale->text('You have to enter the SEPA creditor ID in your user preferences (see the "Program" menu, "Preferences").'), 'back_button' => 1); |
|
444 |
} |
|
445 |
|
|
440 | 446 |
my @ids; |
441 | 447 |
if ($form->{mode} && ($form->{mode} eq 'multi')) { |
442 | 448 |
@ids = map $_->{id}, grep { $_->{selected} } @{ $form->{exports} || [] }; |
... | ... | |
452 | 458 |
my @items = (); |
453 | 459 |
|
454 | 460 |
foreach my $id (@ids) { |
455 |
my $export = SL::SEPA->retrieve_export('id' => $id, 'details' => 1); |
|
461 |
my $export = SL::SEPA->retrieve_export('id' => $id, 'details' => 1, vc => $vc);
|
|
456 | 462 |
push @items, grep { !$_->{executed} } @{ $export->{items} } if ($export && !$export->{closed}); |
457 | 463 |
} |
458 | 464 |
|
... | ... | |
463 | 469 |
my $message_id = strftime('MSG%Y%m%d%H%M%S', localtime) . sprintf('%06d', $$); |
464 | 470 |
|
465 | 471 |
my $sepa_xml = SL::SEPA::XML->new('company' => $myconfig->{company}, |
472 |
'creditor_id' => $myconfig->{sepa_creditor_id}, |
|
466 | 473 |
'src_charset' => $main::dbcharset || 'ISO-8859-15', |
467 | 474 |
'message_id' => $message_id, |
468 | 475 |
'grouped' => 1, |
476 |
'collection' => $vc eq 'customer', |
|
469 | 477 |
); |
470 | 478 |
|
471 | 479 |
foreach my $item (@items) { |
... | ... | |
475 | 483 |
$requested_execution_date = sprintf '%04d-%02d-%02d', $yy, $mm, $dd; |
476 | 484 |
} |
477 | 485 |
|
486 |
if ($vc eq 'customer') { |
|
487 |
my ($yy, $mm, $dd) = $locale->parse_date($myconfig, $item->{reference_date}); |
|
488 |
$item->{reference_date} = sprintf '%04d-%02d-%02d', $yy, $mm, $dd; |
|
489 |
} |
|
490 |
|
|
478 | 491 |
$sepa_xml->add_transaction({ 'src_iban' => $item->{our_iban}, |
479 | 492 |
'src_bic' => $item->{our_bic}, |
480 |
'dst_iban' => $item->{vendor_iban},
|
|
481 |
'dst_bic' => $item->{vendor_bic},
|
|
482 |
'recipient' => $item->{vendor_name},
|
|
493 |
'dst_iban' => $item->{vc_iban},
|
|
494 |
'dst_bic' => $item->{vc_bic},
|
|
495 |
'company' => $item->{vc_name},
|
|
483 | 496 |
'amount' => $item->{amount}, |
484 | 497 |
'reference' => $item->{reference}, |
498 |
'reference_date' => $item->{reference_date}, |
|
485 | 499 |
'execution_date' => $requested_execution_date, |
486 | 500 |
'end_to_end_id' => $item->{end_to_end_id} }); |
487 | 501 |
} |
... | ... | |
489 | 503 |
my $xml = $sepa_xml->to_xml(); |
490 | 504 |
|
491 | 505 |
print $cgi->header('-type' => 'application/octet-stream', |
492 |
'-content-disposition' => 'attachment; filename="SEPA_' . $message_id . '.cct"',
|
|
506 |
'-content-disposition' => 'attachment; filename="SEPA_' . $message_id . ($vc eq 'customer' ? '.cdd' : '.cct') . '"',
|
|
493 | 507 |
'-content-length' => length $xml); |
494 | 508 |
print $xml; |
495 | 509 |
|
locale/de/all | ||
---|---|---|
1923 | 1923 |
'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.', |
1924 | 1924 |
'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.', |
1925 | 1925 |
'You have to enter a company name in your user preferences (see the "Program" menu, "Preferences").' => 'Sie m?ssen einen Firmennamen in Ihren Einstellungen angeben (siehe Men? "Programm", "Einstellungen").', |
1926 |
'You have to enter the SEPA creditor ID in your user preferences (see the "Program" menu, "Preferences").' => 'Sie m?ssen die SEPA-Kreditoren-Identifikation in Ihren Einstellungen angeben (siehe Men? "Programm", "Einstellungen").', |
|
1926 | 1927 |
'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.', |
1927 | 1928 |
'You have to specify a department.' => 'Sie m?ssen eine Abteilung w?hlen.', |
1928 | 1929 |
'You have to specify an execution date for each antry.' => 'Sie m?ssen f?r jeden zu buchenden Eintrag ein Ausf?hrungsdatum angeben.', |
Auch abrufbar als: Unified diff
Unterstützung für die XML-Ausgabe von Lastschriften