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