Projekt

Allgemein

Profil

« Zurück | Weiter » 

Revision c1716dbd

Von Moritz Bunkus vor fast 14 Jahren hinzugefügt

  • ID c1716dbdeb0ba6d2cd9c708a2c54b9845e9532b4
  • Vorgänger 56a7606e
  • Nachfolger 39d61f60

Unterstützung für die XML-Ausgabe von Lastschriften

Unterschiede anzeigen:

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