Formatting
[memberdb.git] / include / directdebit.php
1 <?php
2
3
4 function action_directdebit()
5 {
6
7     $debittype = array(
8         1 => 'DTAUS',
9         2 => 'FRST',
10         3 => 'RCUR'
11     );
12
13     $members = db_get_members();
14     if (empty($members)) {
15         return;
16     }
17
18     $debits = array();
19     $cash_payments = array();
20     foreach ($members as $member) {
21         if (empty($member['directdebit'])) {
22             // Barzahler
23             $open = bcsub(fees_sum_for_member($member['id'], time()),
24                 bcadd(finance_get_paid_fees_for_member($member['id']),
25                     finance_get_paid_fees_for_member($member['id'], true)));
26             if (bccomp($open, 0) != 1) {
27                 continue;
28             }
29             $cash_payments[] = array(
30                 'member_id'     => $member['id'],
31                 'member_number' => $member['number'],
32                 'nickname'      => $member['nickname'],
33                 'amount'        => $open
34             );
35             continue;
36         }
37         $info = fee_next_directdebit_for_member($member['id'], time());
38         if (empty($info)) {
39             continue;
40         }
41         $debits[] = array(
42             'member_id'        => $member['id'],
43             'member_number'    => $member['number'],
44             'nickname'         => $member['nickname'],
45             'accountholder'    => $member['accountholder'],
46             'accountnumber'    => $member['accountnumber'],
47             'bankcode'         => $member['bankcode'],
48             //          'bankname'         => $member['bankname'],
49             'amount'           => $info['value'],
50             'amountcent'       => '' . (int)round(bcmul($info['value'], 100)),
51             'purpose'          => $info['info'],
52             'ddmandatesigdate' => $member['ddmandatesigdate'],
53             'debittype'        => $debittype[$member['directdebit']],
54         );
55     }
56
57     js_modal_windows();
58     js_get_master_key();
59
60     ?>
61     <noscript>
62         <p class="error">
63             <strong>Achtung:</strong> Ohne JavaScript geht hier gar nichts. Bitte aktivieren!
64         </p>
65     </noscript>
66     <?php if (!empty($cash_payments)) : ?>
67     <h2>Barzahler</h2>
68     <table>
69         <tr>
70             <th>Mitgliedsnummer</th>
71             <th>Nickname</th>
72             <th style="text-align: right;">Betrag</th>
73             <th></th>
74         </tr>
75         <?php foreach ($cash_payments as $payment) : ?>
76             <tr>
77                 <td><a href="<?= html_escape(link_to('fees',
78                         array('member_id' => $payment['member_id']))) ?>"><?= html_escape($payment['member_number']) ?></a>
79                 </td>
80                 <td><?= html_escape($payment['nickname']) ?></td>
81                 <td style="text-align: right;"><?= html_escape(format_money($payment['amount'])) ?></td>
82                 <td>
83                     <form action="<?= link_to('create_earning') ?>" method="post" class="clearfix">
84                         <?= html_hidden_field('date', format_date(time())) ?>
85                         <?= html_hidden_field('type', 'fee') ?>
86                         <?= html_hidden_field('status', 'paid') ?>
87                         <?= html_hidden_field('value', format_money($payment['amount'])) ?>
88                         <?= html_hidden_field('member_id', $payment['member_id']) ?>
89                         <?= html_hidden_field('description', '') ?>
90                         <?= html_hidden_field('account', 'cash') ?>
91                         <input class="submit" type="submit" name="submit" value="Einnahme verbuchen"/>
92                     </form>
93                 </td>
94             </tr>
95         <?php endforeach ?>
96     </table>
97 <?php endif ?>
98
99     <h2>Bankeinzug</h2>
100     <table>
101         <tr>
102             <th>Mitgliedsnummer</th>
103             <th>Nickname</th>
104             <th>Verwendungszweck</th>
105             <th>Einzugstyp</th>
106             <th style="text-align: right;">Betrag</th>
107         </tr>
108         <?php $total = 0; ?>
109         <?php foreach ($debits as $debit) : ?>
110             <tr>
111                 <td><a href="<?= html_escape(link_to('fees',
112                         array('member_id' => $debit['member_id']))) ?>"><?= html_escape($debit['member_number']) ?></a>
113                 </td>
114                 <td><?= html_escape($debit['nickname']) ?></td>
115                 <td><?= html_escape($debit['purpose']) ?></td>
116                 <td><?= html_escape($debit['debittype']) ?></td>
117                 <td style="text-align: right;"><?= html_escape(format_money($debit['amount'])) ?></td>
118             </tr>
119             <?php $total = bcadd($total, $debit['amount']); ?>
120         <?php endforeach ?>
121         <tr class="total">
122             <td>Gesamt</td>
123             <td></td>
124             <td></td>
125             <td></td>
126             <td style="text-align: right;"><?= html_escape(format_money($total)) ?></td>
127         </tr>
128     </table>
129
130     <!-- ?=html_hidden_field('directdebittype', 'pain')? -->
131     <?= html_list_box('Dateiformat', 'directdebittype', array('dtaus' => 'DTAUS', 'pain' => 'PAIN'), 'pain'); ?>
132     <input class="submit" type="button" name="btn_directdebit" value="Datei erzeugen" onclick="ask_for_password()"
133            id="btn_directdebit"/>
134     <br/>
135     <br/>
136     <form action="<?= link_to('create_earnings') ?>" method="post" class="clearfix">
137         <?php $count = 0; ?>
138         <?php foreach ($debits as $debit) : ?>
139             <?= html_hidden_field(sprintf('earnings[%d][date]', $count), format_date(time())) ?>
140             <?= html_hidden_field(sprintf('earnings[%d][type]', $count), 'fee') ?>
141             <?= html_hidden_field(sprintf('earnings[%d][status]', $count), 'paid') ?>
142             <?= html_hidden_field(sprintf('earnings[%d][value]', $count), $debit['amount']) ?>
143             <?= html_hidden_field(sprintf('earnings[%d][member_id]', $count), $debit['member_id']) ?>
144             <?= html_hidden_field(sprintf('earnings[%d][description]', $count), $debit['purpose']) ?>
145             <?php $count++; ?>
146         <?php endforeach ?>
147         <input class="submit" type="submit" name="btn_create_earnings" value="Einnahmen verbuchen"/>
148     </form>
149     <hr/>
150     <form action="<?= link_to('export_ibanhin') ?>" method="POST" class="clearfix">
151         <input class="submit" type="submit" name="btn_export_ibanhin" value="IBAN-hin Export"/>
152     </form>
153
154     <div id="password_popup" class="modal_window">
155         <fieldset>
156             <legend>Passwortabfrage</legend>
157             <?= html_password_field('Passwort', 'password') ?>
158             <input class="submit" type="button" name="btn_generate_directdebit" value="Datei erzeugen"
159                    onclick="generate_directdebit()"/>
160             <input class="submit" type="button" name="btn_cancel" value="Abbrechen"
161                    onclick="cancel_ask_for_password()"/>
162         </fieldset>
163     </div>
164     <div id="directdebit_popup" class="modal_window">
165         <fieldset>
166             <legend>DTAUS / SEPA PAIN FRST</legend>
167             <textarea id="directdebit_content" style="width: 100%" rows="15" readonly="readonly"></textarea>
168             <legend>SEPA PAIN RCUR</legend>
169             <textarea id="directdebit_content2" style="width: 100%" rows="15" readonly="readonly"></textarea>
170             <input class="submit" type="button" name="btn_directdebit_close" value="Schließen"
171                    onclick="directdebit_close()"/>
172         </fieldset>
173     </div>
174
175     <script type="text/javascript">
176
177         var debits = new Array(
178             <?=join(",\n", array_map('json_encode', $debits)) ?>
179         );
180
181
182         $(document).ready(function () {
183             $('#password').keypress(function (event) {
184                 if (event.keyCode == '13') {
185                     generate_directdebit();
186                 }
187             });
188             $('#btn_directdebit').focus();
189         });
190
191
192         function ask_for_password() {/*{{{*/
193             modal_window_show($("#password_popup"));
194             $("#password").focus();
195             return;
196         }
197
198         /*}}}*/
199
200         function cancel_ask_for_password() {/*{{{*/
201             modal_window_hide();
202             $("#btn_directdebit").focus();
203             return;
204         }
205
206         /*}}}*/
207
208
209         function generate_directdebit() {/*{{{*/
210
211             var password = $('#password').val();
212             var directdebitcontent = "";
213             var directdebitcontent2 = "Wird nur bei SEPA verwendet.";
214             $("#password").val('');
215
216             // We pass a closure so that get_master_key may defer execution
217             get_master_key(password, function (masterkey) {
218
219                 modal_window_replace($("#directdebit_popup"));
220
221                 switch ($('#directdebittype').val()) {
222                     case "dtaus":
223                         if (!DTAUS.setAccountFileSender('<?=dtaus_string(ACCOUNT_HOLDER)?>', '<?=BANK_CODE?>', '<?=ACCOUNT_NUMBER?>')) {
224                             $('#directdebit_content').val(DTAUS.errormsg);
225                             return;
226                         }
227
228                         for (var i = 0; i < debits.length; i++) {
229
230                             if (debits[i]['debittype'] != 'DTAUS') {
231                                 continue;
232                             }
233
234                             var accountholder = debits[i]['accountholder'];
235                             var accountnumber = debits[i]['accountnumber'];
236                             var bankcode = debits[i]['bankcode'];
237
238                             // Encrypt/Decrypt data using AES with masterkey
239                             if (accountholder != "") accountholder = Crypto.charenc.UTF8.bytesToString(Crypto.AES.decrypt(accountholder, masterkey));
240                             if (accountnumber != "") accountnumber = Crypto.charenc.UTF8.bytesToString(Crypto.AES.decrypt(accountnumber, masterkey));
241                             if (bankcode != "") bankcode = Crypto.charenc.UTF8.bytesToString(Crypto.AES.decrypt(bankcode, masterkey));
242
243                             accountholder = DTAUS.prepareString(accountholder);
244
245                             if (!DTAUS.addExchange(accountholder, bankcode, accountnumber, '', debits[i]['amountcent'], debits[i]['purpose'])) {
246                                 $('#directdebit_content').val('Mitglied ' + debits[i]['member_number'] + ' ' + accountholder + '\n' + DTAUS.errormsg);
247                                 return;
248                             }
249                         }
250                         directdebitcontent = DTAUS.getFileContent();
251                         break;
252
253                     case "pain":
254
255                     <?php $bic = (USE_BIC == 1) ? '\'' . BIC . '\'' : 'null'; ?>
256
257                         // datejs.com MAGIC
258                         var jetzt = new Date.today();
259                         var collectiondate = new Date.parse('<?=DIRECTDEBIT_DAY_OF_MONTH?>');
260                         if (jetzt.getDate() > <?=DIRECTDEBIT_DAY_OF_MONTH?>) {
261                             collectiondate = collectiondate.add(1).month();
262                         }
263
264                         if (!SEPACORE.init(collectiondate, '<?=CREDITOR_IDENTIFIER?>', '<?=ACCOUNT_HOLDER?>', '<?=IBAN?>', <?=$bic?>)) {
265                             $('#directdebit_content').val(DTAUS.errormsg);
266                             return;
267                         }
268
269                         for (var i = 0; i < debits.length; i++) {
270
271                             if (debits[i]['debittype'] != 'FRST' && debits[i]['debittype'] != 'RCUR') {
272                                 continue;
273                             }
274
275                             var accountholder = debits[i]['accountholder'];
276                             var accountnumber = debits[i]['accountnumber'];
277                             var bankcode = debits[i]['bankcode'];
278
279                             // Encrypt/Decrypt data using AES with masterkey
280                             if (accountholder != "") accountholder = Crypto.charenc.UTF8.bytesToString(Crypto.AES.decrypt(accountholder, masterkey));
281                             if (accountnumber != "") accountnumber = Crypto.charenc.UTF8.bytesToString(Crypto.AES.decrypt(accountnumber, masterkey));
282                             if (bankcode != "") bankcode = Crypto.charenc.UTF8.bytesToString(Crypto.AES.decrypt(bankcode, masterkey));
283
284                             // Mandatsreferenz '/V1/M:n/'; z.B. /V:1/M:2/
285                             var mandateref = '/V:1/M:' + debits[i]['member_number'] + '/';
286                             var e2eid = '/V:1/E2E:' + parseInt(SEPACORE.creationdate.getTime() / 1000) + '/S:' + debits[i]['debittype'][0] + '/I:' + i + '/';
287                             if (!SEPACORE.addDDTx(debits[i]['debittype'], accountholder, accountnumber, bankcode, mandateref, debits[i]['ddmandatesigdate'].substring(0, 10), debits[i]['amountcent'], debits[i]['purpose'], e2eid)) {
288                                 $('#directdebit_content').val('Mitglied ' + debits[i]['member_number'] + ' ' + accountholder + '\n' + SEPACORE.errormsg);
289                                 return;
290                             }
291                         }
292
293                         directdebitcontent = SEPACORE.getXMLContent('FRST');
294                         directdebitcontent2 = SEPACORE.getXMLContent('RCUR');
295
296                         if (SEPACORE.errormsg.lenght > 0) {
297                             $('#directdebit_content').val(SEPACORE.errormsg);
298                             return;
299                         }
300                         break;
301                 }
302                 $('#directdebit_content').val(directdebitcontent);
303                 $('#directdebit_content2').val(directdebitcontent2);
304                 $('#directdebit_content').focus();
305                 $('#directdebit_content').select();
306             });
307
308         }
309
310         /*}}}*/
311
312         function directdebit_close() {/*{{{*/
313             modal_window_hide();
314             $("#directdebit_content").val('');
315             $("#directdebit_content2").val('');
316         }
317
318         /*}}}*/
319
320
321     </script>
322     <?
323 }
324
325 // borrowed from PEARs Payment_DTA
326 function dtaus_string($string)
327 {
328     if (strlen($string) == 0) {
329         return '';
330     }
331     $special_chars = array(
332         'á' => 'a',
333         'à' => 'a',
334         'ä' => 'ae',
335         'â' => 'a',
336         'ã' => 'a',
337         'å' => 'a',
338         'æ' => 'ae',
339         'ā' => 'a',
340         'ă' => 'a',
341         'ą' => 'a',
342         'ȁ' => 'a',
343         'ȃ' => 'a',
344         'Á' => 'A',
345         'À' => 'A',
346         'Ä' => 'Ae',
347         'Â' => 'A',
348         'Ã' => 'A',
349         'Å' => 'A',
350         'Æ' => 'AE',
351         'Ā' => 'A',
352         'Ă' => 'A',
353         'Ą' => 'A',
354         'Ȁ' => 'A',
355         'Ȃ' => 'A',
356         'ç' => 'c',
357         'ć' => 'c',
358         'ĉ' => 'c',
359         'ċ' => 'c',
360         'č' => 'c',
361         'Ç' => 'C',
362         'Ć' => 'C',
363         'Ĉ' => 'C',
364         'Ċ' => 'C',
365         'Č' => 'C',
366         'ď' => 'd',
367         'đ' => 'd',
368         'Ď' => 'D',
369         'Đ' => 'D',
370         'é' => 'e',
371         'è' => 'e',
372         'ê' => 'e',
373         'ë' => 'e',
374         'ē' => 'e',
375         'ĕ' => 'e',
376         'ė' => 'e',
377         'ę' => 'e',
378         'ě' => 'e',
379         'ȅ' => 'e',
380         'ȇ' => 'e',
381         'É' => 'E',
382         'È' => 'E',
383         'Ê' => 'E',
384         'Ë' => 'E',
385         'Ē' => 'E',
386         'Ĕ' => 'E',
387         'Ė' => 'E',
388         'Ę' => 'E',
389         'Ě' => 'E',
390         'Ȅ' => 'E',
391         'Ȇ' => 'E',
392         'ĝ' => 'g',
393         'ğ' => 'g',
394         'ġ' => 'g',
395         'ģ' => 'g',
396         'Ĝ' => 'G',
397         'Ğ' => 'G',
398         'Ġ' => 'G',
399         'Ģ' => 'G',
400         'ĥ' => 'h',
401         'ħ' => 'h',
402         'Ĥ' => 'H',
403         'Ħ' => 'H',
404         'ì' => 'i',
405         'ì' => 'i',
406         'î' => 'i',
407         'ï' => 'i',
408         'ĩ' => 'i',
409         'ī' => 'i',
410         'ĭ' => 'i',
411         'į' => 'i',
412         'ı' => 'i',
413         'ij' => 'ij',
414         'ȉ' => 'i',
415         'ȋ' => 'i',
416         'Í' => 'I',
417         'Ì' => 'I',
418         'Î' => 'I',
419         'Ï' => 'I',
420         'Ĩ' => 'I',
421         'Ī' => 'I',
422         'Ĭ' => 'I',
423         'Į' => 'I',
424         'İ' => 'I',
425         'IJ' => 'IJ',
426         'Ȉ' => 'I',
427         'Ȋ' => 'I',
428         'ĵ' => 'j',
429         'Ĵ' => 'J',
430         'ķ' => 'k',
431         'Ķ' => 'K',
432         'ĺ' => 'l',
433         'ļ' => 'l',
434         'ľ' => 'l',
435         'ŀ' => 'l',
436         'ł' => 'l',
437         'Ĺ' => 'L',
438         'Ļ' => 'L',
439         'Ľ' => 'L',
440         'Ŀ' => 'L',
441         'Ł' => 'L',
442         'ñ' => 'n',
443         'ń' => 'n',
444         'ņ' => 'n',
445         'ň' => 'n',
446         'ʼn' => 'n',
447         'Ñ' => 'N',
448         'Ń' => 'N',
449         'Ņ' => 'N',
450         'Ň' => 'N',
451         'ó' => 'o',
452         'ò' => 'o',
453         'ö' => 'oe',
454         'ô' => 'o',
455         'õ' => 'o',
456         'ø' => 'o',
457         'ō' => 'o',
458         'ŏ' => 'o',
459         'ő' => 'o',
460         'œ' => 'oe',
461         'ȍ' => 'o',
462         'ȏ' => 'o',
463         'Ó' => 'O',
464         'Ò' => 'O',
465         'Ö' => 'Oe',
466         'Ô' => 'O',
467         'Õ' => 'O',
468         'Ø' => 'O',
469         'Ō' => 'O',
470         'Ŏ' => 'O',
471         'Ő' => 'O',
472         'Œ' => 'OE',
473         'Ȍ' => 'O',
474         'Ȏ' => 'O',
475         'ŕ' => 'r',
476         'ř' => 'r',
477         'ȑ' => 'r',
478         'ȓ' => 'r',
479         'Ŕ' => 'R',
480         'Ř' => 'R',
481         'Ȑ' => 'R',
482         'Ȓ' => 'R',
483         'ß' => 'ss',
484         'ś' => 's',
485         'ŝ' => 's',
486         'ş' => 's',
487         'š' => 's',
488         'ș' => 's',
489         'Ś' => 'S',
490         'Ŝ' => 'S',
491         'Ş' => 'S',
492         'Š' => 'S',
493         'Ș' => 'S',
494         'ţ' => 't',
495         'ť' => 't',
496         'ŧ' => 't',
497         'ț' => 't',
498         'Ţ' => 'T',
499         'Ť' => 'T',
500         'Ŧ' => 'T',
501         'Ț' => 'T',
502         'ú' => 'u',
503         'ù' => 'u',
504         'ü' => 'ue',
505         'û' => 'u',
506         'ũ' => 'u',
507         'ū' => 'u',
508         'ŭ' => 'u',
509         'ů' => 'u',
510         'ű' => 'u',
511         'ų' => 'u',
512         'ȕ' => 'u',
513         'ȗ' => 'u',
514         'Ú' => 'U',
515         'Ù' => 'U',
516         'Ü' => 'Ue',
517         'Û' => 'U',
518         'Ũ' => 'U',
519         'Ū' => 'U',
520         'Ŭ' => 'U',
521         'Ů' => 'U',
522         'Ű' => 'U',
523         'Ų' => 'U',
524         'Ȕ' => 'U',
525         'Ȗ' => 'U',
526         'ŵ' => 'w',
527         'Ŵ' => 'W',
528         'ý' => 'y',
529         'ÿ' => 'y',
530         'ŷ' => 'y',
531         'Ý' => 'Y',
532         'Ÿ' => 'Y',
533         'Ŷ' => 'Y',
534         'ź' => 'z',
535         'ż' => 'z',
536         'ž' => 'z',
537         'Ź' => 'Z',
538         'Ż' => 'Z',
539         'Ž' => 'Z',
540     );
541
542
543     $result = strtr($string, $special_chars);   // replace known special chars
544     $result = strtoupper($result);                  // upper case
545     // make sure every special char is replaced by one space, not two or three
546     $result = mb_convert_encoding($result, 'ASCII', 'UTF-8');
547     $result = preg_replace('/[^A-Z0-9 \.,&\-\/\+\*\$%]/', ' ', $result);
548
549     return $result;
550 }