dolibarr 18.0.6
paiement.php
Go to the documentation of this file.
1<?php
2/* Copyright (C) 2001-2006 Rodolphe Quiedeville <rodolphe@quiedeville.org>
3 * Copyright (C) 2004-2017 Laurent Destailleur <eldy@users.sourceforge.net>
4 * Copyright (C) 2005 Marc Barilley / Ocebo <marc@ocebo.com>
5 * Copyright (C) 2005-2012 Regis Houssin <regis.houssin@inodbox.com>
6 * Copyright (C) 2007 Franky Van Liedekerke <franky.van.liedekerke@telenet.be>
7 * Copyright (C) 2012 Cédric Salvador <csalvador@gpcsolutions.fr>
8 * Copyright (C) 2014 Raphaël Doursenaud <rdoursenaud@gpcsolutions.fr>
9 * Copyright (C) 2014 Teddy Andreotti <125155@supinfo.com>
10 * Copyright (C) 2015 Juanjo Menent <jmenent@2byte.es>
11 * Copyright (C) 2018-2021 Frédéric France <frederic.france@netlogic.fr>
12 * Copyright (C) 2023 Lenin Rivas <lenin.rivas777@gmail.com>
13 * Copyright (C) 2023 Sylvain Legrand <technique@infras.fr>
14 *
15 * This program is free software; you can redistribute it and/or modify
16 * it under the terms of the GNU General Public License as published by
17 * the Free Software Foundation; either version 3 of the License, or
18 * (at your option) any later version.
19 *
20 * This program is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 * GNU General Public License for more details.
24 *
25 * You should have received a copy of the GNU General Public License
26 * along with this program. If not, see <https://www.gnu.org/licenses/>.
27 */
28
35// Load Dolibarr environment
36require '../main.inc.php';
37require_once DOL_DOCUMENT_ROOT.'/compta/paiement/class/paiement.class.php';
38require_once DOL_DOCUMENT_ROOT.'/compta/facture/class/facture.class.php';
39require_once DOL_DOCUMENT_ROOT.'/compta/bank/class/account.class.php';
40require_once DOL_DOCUMENT_ROOT.'/societe/class/societe.class.php';
41
42// Load translation files required by the page
43$langs->loadLangs(array('companies', 'bills', 'banks', 'multicurrency'));
44
45$action = GETPOST('action', 'alpha');
46$confirm = GETPOST('confirm', 'alpha');
47
48$facid = GETPOST('facid', 'int');
49$accountid = GETPOST('accountid', 'int');
50$paymentnum = GETPOST('num_paiement', 'alpha');
51$socid = GETPOST('socid', 'int');
52
53$sortfield = GETPOST('sortfield', 'aZ09comma');
54$sortorder = GETPOST('sortorder', 'aZ09comma');
55$page = GETPOSTISSET('pageplusone') ? (GETPOST('pageplusone') - 1) : GETPOST("page", 'int');
56
57$amounts = array();
58$amountsresttopay = array();
59$addwarning = 0;
60
61$multicurrency_amounts = array();
62$multicurrency_amountsresttopay = array();
63
64// Security check
65if ($user->socid > 0) {
66 $socid = $user->socid;
67}
68
69$object = new Facture($db);
70
71// Load object
72if ($facid > 0) {
73 $ret = $object->fetch($facid);
74}
75
76// Initialize technical object to manage hooks of paiements. Note that conf->hooks_modules contains array array
77$hookmanager->initHooks(array('paiementcard', 'globalcard'));
78
79$formquestion = array();
80
81$usercanissuepayment = $user->hasRight('facture', 'paiement');
82
83$fieldid = 'rowid';
84$isdraft = (($object->statut == Facture::STATUS_DRAFT) ? 1 : 0);
85$result = restrictedArea($user, 'facture', $object->id, '', '', 'fk_soc', $fieldid, $isdraft);
86
87
88/*
89 * Actions
90 */
91
92$parameters = array('socid'=>$socid);
93$reshook = $hookmanager->executeHooks('doActions', $parameters, $object, $action); // Note that $action and $object may have been modified by some hooks
94if ($reshook < 0) {
95 setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
96}
97
98if (empty($reshook)) {
99 if (($action == 'add_paiement' || ($action == 'confirm_paiement' && $confirm == 'yes')) && $usercanissuepayment) {
100 $error = 0;
101
102 $datepaye = dol_mktime(12, 0, 0, GETPOST('remonth', 'int'), GETPOST('reday', 'int'), GETPOST('reyear', 'int'));
103 $paiement_id = 0;
104 $totalpayment = 0;
105 $multicurrency_totalpayment = 0;
106 $atleastonepaymentnotnull = 0;
107 $formquestion = array();
108 $i = 0;
109
110 // Generate payment array and check if there is payment higher than invoice and payment date before invoice date
111 $tmpinvoice = new Facture($db);
112 foreach ($_POST as $key => $value) {
113 if (substr($key, 0, 7) == 'amount_' && GETPOST($key) != '') {
114 $cursorfacid = substr($key, 7);
115 $amounts[$cursorfacid] = price2num(GETPOST($key));
116 $totalpayment = $totalpayment + $amounts[$cursorfacid];
117 if (!empty($amounts[$cursorfacid])) {
118 $atleastonepaymentnotnull++;
119 }
120 $result = $tmpinvoice->fetch($cursorfacid);
121 if ($result <= 0) {
122 dol_print_error($db);
123 }
124 $amountsresttopay[$cursorfacid] = price2num($tmpinvoice->total_ttc - $tmpinvoice->getSommePaiement());
125 if ($amounts[$cursorfacid]) {
126 // Check amount
127 if ($amounts[$cursorfacid] && (abs($amounts[$cursorfacid]) > abs($amountsresttopay[$cursorfacid]))) {
128 $addwarning = 1;
129 $formquestion['text'] = img_warning($langs->trans("PaymentHigherThanReminderToPay")).' '.$langs->trans("HelpPaymentHigherThanReminderToPay");
130 }
131 // Check date
132 if ($datepaye && ($datepaye < $tmpinvoice->date)) {
133 $langs->load("errors");
134 //$error++;
135 setEventMessages($langs->transnoentities("WarningPaymentDateLowerThanInvoiceDate", dol_print_date($datepaye, 'day'), dol_print_date($tmpinvoice->date, 'day'), $tmpinvoice->ref), null, 'warnings');
136 }
137 }
138
139 $formquestion[$i++] = array('type' => 'hidden', 'name' => $key, 'value' => GETPOST($key));
140 } elseif (substr($key, 0, 21) == 'multicurrency_amount_') {
141 $cursorfacid = substr($key, 21);
142 $multicurrency_amounts[$cursorfacid] = price2num(GETPOST($key));
143 $multicurrency_totalpayment += floatval($multicurrency_amounts[$cursorfacid]);
144 if (!empty($multicurrency_amounts[$cursorfacid])) {
145 $atleastonepaymentnotnull++;
146 }
147 $result = $tmpinvoice->fetch($cursorfacid);
148 if ($result <= 0) {
149 dol_print_error($db);
150 }
151 $multicurrency_amountsresttopay[$cursorfacid] = price2num($tmpinvoice->multicurrency_total_ttc - $tmpinvoice->getSommePaiement(1));
152 if ($multicurrency_amounts[$cursorfacid]) {
153 // Check amount
154 if ($multicurrency_amounts[$cursorfacid] && (abs($multicurrency_amounts[$cursorfacid]) > abs($multicurrency_amountsresttopay[$cursorfacid]))) {
155 $addwarning = 1;
156 $formquestion['text'] = img_warning($langs->trans("PaymentHigherThanReminderToPay")).' '.$langs->trans("HelpPaymentHigherThanReminderToPay");
157 }
158 // Check date
159 if ($datepaye && ($datepaye < $tmpinvoice->date)) {
160 $langs->load("errors");
161 //$error++;
162 setEventMessages($langs->transnoentities("WarningPaymentDateLowerThanInvoiceDate", dol_print_date($datepaye, 'day'), dol_print_date($tmpinvoice->date, 'day'), $tmpinvoice->ref), null, 'warnings');
163 }
164 }
165
166 $formquestion[$i++] = array('type' => 'hidden', 'name' => $key, 'value' => GETPOST($key, 'int'));
167 }
168 }
169
170 // Check parameters
171 if (!GETPOST('paiementcode')) {
172 setEventMessages($langs->transnoentities('ErrorFieldRequired', $langs->transnoentities('PaymentMode')), null, 'errors');
173 $error++;
174 }
175
176 if (isModEnabled("banque")) {
177 // If bank module is on, account is required to enter a payment
178 if (GETPOST('accountid') <= 0) {
179 setEventMessages($langs->transnoentities('ErrorFieldRequired', $langs->transnoentities('AccountToCredit')), null, 'errors');
180 $error++;
181 }
182 }
183
184 if (empty($totalpayment) && empty($multicurrency_totalpayment) && empty($atleastonepaymentnotnull)) {
185 setEventMessages($langs->transnoentities('ErrorFieldRequired', $langs->trans('PaymentAmount')), null, 'errors');
186 $error++;
187 }
188
189 if (empty($datepaye)) {
190 setEventMessages($langs->transnoentities('ErrorFieldRequired', $langs->transnoentities('Date')), null, 'errors');
191 $error++;
192 }
193
194 // Check if payments in both currency
195 if ($totalpayment > 0 && $multicurrency_totalpayment > 0) {
196 $langs->load("errors");
197 setEventMessages($langs->transnoentities('ErrorPaymentInBothCurrency'), null, 'errors');
198 $error++;
199 }
200 }
201
202 /*
203 * Action add_paiement
204 */
205 if ($action == 'add_paiement') {
206 if ($error) {
207 $action = 'create';
208 }
209 // The next of this action is displayed at the page's bottom.
210 }
211
212 /*
213 * Action confirm_paiement
214 */
215 if ($action == 'confirm_paiement' && $confirm == 'yes' && $usercanissuepayment) {
216 $error = 0;
217
218 $datepaye = dol_mktime(12, 0, 0, GETPOST('remonth', 'int'), GETPOST('reday', 'int'), GETPOST('reyear', 'int'), 'tzuser');
219
220 $db->begin();
221
222 $thirdparty = new Societe($db);
223 if ($socid > 0) {
224 $thirdparty->fetch($socid);
225 }
226
227 $multicurrency_code = array();
228 $multicurrency_tx = array();
229
230 // Clean parameters amount if payment is for a credit note
231 foreach ($amounts as $key => $value) { // How payment is dispatched
232 $tmpinvoice = new Facture($db);
233 $tmpinvoice->fetch($key);
234 if ($tmpinvoice->type == Facture::TYPE_CREDIT_NOTE) {
235 $newvalue = price2num($value, 'MT');
236 $amounts[$key] = - abs($newvalue);
237 }
238 $multicurrency_code[$key] = $tmpinvoice->multicurrency_code;
239 $multicurrency_tx[$key] = $tmpinvoice->multicurrency_tx;
240 }
241
242 foreach ($multicurrency_amounts as $key => $value) { // How payment is dispatched
243 $tmpinvoice = new Facture($db);
244 $tmpinvoice->fetch($key);
245 if ($tmpinvoice->type == Facture::TYPE_CREDIT_NOTE) {
246 $newvalue = price2num($value, 'MT');
247 $multicurrency_amounts[$key] = - abs($newvalue);
248 }
249 $multicurrency_code[$key] = $tmpinvoice->multicurrency_code;
250 $multicurrency_tx[$key] = $tmpinvoice->multicurrency_tx;
251 }
252
253 if (isModEnabled("banque")) {
254 // If the bank module is active, an account is required to input a payment
255 if (GETPOST('accountid', 'int') <= 0) {
256 setEventMessages($langs->trans('ErrorFieldRequired', $langs->transnoentities('AccountToCredit')), null, 'errors');
257 $error++;
258 }
259 }
260
261 // Creation of payment line
262 $paiement = new Paiement($db);
263 $paiement->datepaye = $datepaye;
264 $paiement->amounts = $amounts; // Array with all payments dispatching with invoice id
265 $paiement->multicurrency_amounts = $multicurrency_amounts; // Array with all payments dispatching
266 $paiement->multicurrency_code = $multicurrency_code; // Array with all currency of payments dispatching
267 $paiement->multicurrency_tx = $multicurrency_tx; // Array with all currency tx of payments dispatching
268 $paiement->paiementid = dol_getIdFromCode($db, GETPOST('paiementcode'), 'c_paiement', 'code', 'id', 1);
269 $paiement->num_payment = GETPOST('num_paiement', 'alpha');
270 $paiement->note_private = GETPOST('comment', 'alpha');
271 $paiement->fk_account = GETPOST('accountid', 'int');
272
273 if (!$error) {
274 // Create payment and update this->multicurrency_amounts if this->amounts filled or
275 // this->amounts if this->multicurrency_amounts filled.
276 // This also set ->amount and ->multicurrency_amount
277 $paiement_id = $paiement->create($user, (GETPOST('closepaidinvoices') == 'on' ? 1 : 0), $thirdparty); // This include closing invoices and regenerating documents
278 if ($paiement_id < 0) {
279 setEventMessages($paiement->error, $paiement->errors, 'errors');
280 $error++;
281 }
282 }
283
284 if (!$error) {
285 $label = '(CustomerInvoicePayment)';
286 if (GETPOST('type') == Facture::TYPE_CREDIT_NOTE) {
287 $label = '(CustomerInvoicePaymentBack)'; // Refund of a credit note
288 }
289 $result = $paiement->addPaymentToBank($user, 'payment', $label, GETPOST('accountid', 'int'), GETPOST('chqemetteur'), GETPOST('chqbank'));
290 if ($result < 0) {
291 setEventMessages($paiement->error, $paiement->errors, 'errors');
292 $error++;
293 }
294 }
295
296 if (!$error) {
297 $db->commit();
298
299 // If payment dispatching on more than one invoice, we stay on summary page, otherwise jump on invoice card
300 $invoiceid = 0;
301 foreach ($paiement->amounts as $key => $amount) {
302 $facid = $key;
303 if (is_numeric($amount) && $amount <> 0) {
304 if ($invoiceid != 0) {
305 $invoiceid = -1; // There is more than one invoice payed by this payment
306 } else {
307 $invoiceid = $facid;
308 }
309 }
310 }
311 if ($invoiceid > 0) {
312 $loc = DOL_URL_ROOT.'/compta/facture/card.php?facid='.$invoiceid;
313 } else {
314 $loc = DOL_URL_ROOT.'/compta/paiement/card.php?id='.$paiement_id;
315 }
316 header('Location: '.$loc);
317 exit;
318 } else {
319 $db->rollback();
320 }
321 }
322}
323
324
325/*
326 * View
327 */
328
329$form = new Form($db);
330
331
332llxHeader('', $langs->trans("Payment"));
333
334
335
336if ($action == 'create' || $action == 'confirm_paiement' || $action == 'add_paiement') {
337 $facture = new Facture($db);
338 $result = $facture->fetch($facid);
339
340 if ($result >= 0) {
341 $facture->fetch_thirdparty();
342
343 $title = '';
344 if ($facture->type != Facture::TYPE_CREDIT_NOTE) {
345 $title .= $langs->trans("EnterPaymentReceivedFromCustomer");
346 }
347 if ($facture->type == Facture::TYPE_CREDIT_NOTE) {
348 $title .= $langs->trans("EnterPaymentDueToCustomer");
349 }
350 print load_fiche_titre($title);
351
352 // Initialize data for confirmation (this is used because data can be change during confirmation)
353 if ($action == 'add_paiement') {
354 $i = 0;
355
356 $formquestion[$i++] = array('type' => 'hidden', 'name' => 'facid', 'value' => $facture->id);
357 $formquestion[$i++] = array('type' => 'hidden', 'name' => 'socid', 'value' => $facture->socid);
358 $formquestion[$i++] = array('type' => 'hidden', 'name' => 'type', 'value' => $facture->type);
359 }
360
361 // Invoice with Paypal transaction
362 // TODO add hook here
363 if (isModEnabled('paypalplus') && $conf->global->PAYPAL_ENABLE_TRANSACTION_MANAGEMENT && !empty($facture->ref_ext)) {
364 if (!empty($conf->global->PAYPAL_BANK_ACCOUNT)) {
365 $accountid = $conf->global->PAYPAL_BANK_ACCOUNT;
366 }
367 $paymentnum = $facture->ref_ext;
368 }
369
370 // Add realtime total information
371 if (!empty($conf->use_javascript_ajax)) {
372 print "\n".'<script type="text/javascript">';
373 print '$(document).ready(function () {
374 setPaiementCode();
375
376 $("#selectpaiementcode").change(function() {
377 setPaiementCode();
378 });
379
380 function setPaiementCode()
381 {
382 var code = $("#selectpaiementcode option:selected").val();
383 console.log("setPaiementCode code="+code);
384
385 if (code == \'CHQ\' || code == \'VIR\')
386 {
387 if (code == \'CHQ\')
388 {
389 $(\'.fieldrequireddyn\').addClass(\'fieldrequired\');
390 }
391 if ($(\'#fieldchqemetteur\').val() == \'\')
392 {
393 var emetteur = ('.$facture->type.' == '.Facture::TYPE_CREDIT_NOTE.') ? \''.dol_escape_js(dol_escape_htmltag($conf->global->MAIN_INFO_SOCIETE_NOM)).'\' : jQuery(\'#thirdpartylabel\').val();
394 $(\'#fieldchqemetteur\').val(emetteur);
395 }
396 }
397 else
398 {
399 $(\'.fieldrequireddyn\').removeClass(\'fieldrequired\');
400 $(\'#fieldchqemetteur\').val(\'\');
401 }
402 }
403
404 function _elemToJson(selector)
405 {
406 var subJson = {};
407 $.map(selector.serializeArray(), function(n,i)
408 {
409 subJson[n["name"]] = n["value"];
410 });
411
412 return subJson;
413 }
414 function callForResult(imgId)
415 {
416 var json = {};
417 var form = $("#payment_form");
418
419 json["invoice_type"] = $("#invoice_type").val();
420 json["amountPayment"] = $("#amountpayment").attr("value");
421 json["amounts"] = _elemToJson(form.find("input.amount"));
422 json["remains"] = _elemToJson(form.find("input.remain"));
423 json["token"] = "'.currentToken().'";
424 if (imgId != null) {
425 json["imgClicked"] = imgId;
426 }
427
428 $.post("'.DOL_URL_ROOT.'/compta/ajaxpayment.php", json, function(data)
429 {
430 json = $.parseJSON(data);
431
432 form.data(json);
433
434 for (var key in json)
435 {
436 if (key == "result") {
437 if (json["makeRed"]) {
438 $("#"+key).addClass("error");
439 } else {
440 $("#"+key).removeClass("error");
441 }
442 json[key]=json["label"]+" "+json[key];
443 $("#"+key).text(json[key]);
444 } else {console.log(key);
445 form.find("input[name*=\""+key+"\"]").each(function() {
446 $(this).attr("value", json[key]);
447 });
448 }
449 }
450 });
451 }
452 $("#payment_form").find("input.amount").change(function() {
453 callForResult();
454 });
455 $("#payment_form").find("input.amount").keyup(function() {
456 callForResult();
457 });
458 ';
459
460 print ' });'."\n";
461
462 //Add js for AutoFill
463 print ' $(document).ready(function () {';
464 print ' $(".AutoFillAmout").on(\'click touchstart\', function(){
465 $("input[name="+$(this).data(\'rowname\')+"]").val($(this).data("value")).trigger("change");
466 });';
467 print ' });'."\n";
468
469 print ' </script>'."\n";
470 }
471
472 print '<form id="payment_form" name="add_paiement" action="'.$_SERVER["PHP_SELF"].'" method="POST">';
473 print '<input type="hidden" name="token" value="'.newToken().'">';
474 print '<input type="hidden" name="action" value="add_paiement">';
475 print '<input type="hidden" name="facid" value="'.$facture->id.'">';
476 print '<input type="hidden" name="socid" value="'.$facture->socid.'">';
477 print '<input type="hidden" name="type" id="invoice_type" value="'.$facture->type.'">';
478 print '<input type="hidden" name="thirdpartylabel" id="thirdpartylabel" value="'.dol_escape_htmltag($facture->thirdparty->name).'">';
479 print '<input type="hidden" name="page_y" value="">';
480
481 print dol_get_fiche_head();
482
483 print '<table class="border centpercent">';
484
485 // Third party
486 print '<tr><td class="titlefieldcreate"><span class="fieldrequired">'.$langs->trans('Company').'</span></td><td>'.$facture->thirdparty->getNomUrl(4)."</td></tr>\n";
487
488 // Date payment
489 print '<tr><td><span class="fieldrequired">'.$langs->trans('Date').'</span></td><td>';
490 $datepayment = dol_mktime(12, 0, 0, GETPOST('remonth', 'int'), GETPOST('reday', 'int'), GETPOST('reyear', 'int'));
491 $datepayment = ($datepayment == '' ? (empty($conf->global->MAIN_AUTOFILL_DATE) ?-1 : '') : $datepayment);
492 print $form->selectDate($datepayment, '', '', '', 0, "add_paiement", 1, 1, 0, '', '', $facture->date);
493 print '</td></tr>';
494
495 // Payment mode
496 print '<tr><td><span class="fieldrequired">'.$langs->trans('PaymentMode').'</span></td><td>';
497 $form->select_types_paiements((GETPOST('paiementcode') ?GETPOST('paiementcode') : $facture->mode_reglement_code), 'paiementcode', '', 2);
498 print "</td>\n";
499 print '</tr>';
500
501 // Bank account
502 print '<tr>';
503 if (isModEnabled("banque")) {
504 if ($facture->type != 2) {
505 print '<td><span class="fieldrequired">'.$langs->trans('AccountToCredit').'</span></td>';
506 }
507 if ($facture->type == 2) {
508 print '<td><span class="fieldrequired">'.$langs->trans('AccountToDebit').'</span></td>';
509 }
510
511 print '<td>';
512 print img_picto('', 'bank_account');
513 print $form->select_comptes($accountid, 'accountid', 0, '', 2, '', 0, 'widthcentpercentminusx maxwidth500', 1);
514 print '</td>';
515 } else {
516 print '<td>&nbsp;</td>';
517 }
518 print "</tr>\n";
519
520 // Bank check number
521 print '<tr><td>'.$langs->trans('Numero');
522 print ' <em class="opacitymedium">('.$langs->trans("ChequeOrTransferNumber").')</em>';
523 print '</td>';
524 print '<td><input name="num_paiement" type="text" class="maxwidth200" value="'.$paymentnum.'"></td></tr>';
525
526 // Check transmitter
527 print '<tr><td class="'.(GETPOST('paiementcode') == 'CHQ' ? 'fieldrequired ' : '').'fieldrequireddyn">'.$langs->trans('CheckTransmitter');
528 print ' <em class="opacitymedium">('.$langs->trans("ChequeMaker").')</em>';
529 print '</td>';
530 print '<td><input id="fieldchqemetteur" class="maxwidth300" name="chqemetteur" type="text" value="'.GETPOST('chqemetteur', 'alphanohtml').'"></td></tr>';
531
532 // Bank name
533 print '<tr><td>'.$langs->trans('Bank');
534 print ' <em class="opacitymedium">('.$langs->trans("ChequeBank").')</em>';
535 print '</td>';
536 print '<td><input name="chqbank" class="maxwidth300" type="text" value="'.GETPOST('chqbank', 'alphanohtml').'"></td></tr>';
537
538 // Comments
539 print '<tr><td>'.$langs->trans('Comments').'</td>';
540 print '<td class="tdtop">';
541 print '<textarea name="comment" wrap="soft" class="quatrevingtpercent" rows="'.ROWS_3.'">'.GETPOST('comment', 'restricthtml').'</textarea>';
542 print '</td></tr>';
543
544 // Go Source Invoice (useful when there are many invoices)
545 if ($action != 'add_paiement' && !empty($conf->global->FACTURE_PAYMENTS_SHOW_LINK_TO_INPUT_ORIGIN_IS_MORE_THAN)) {
546 print '<tr><td></td>';
547 print '<td class="tdtop right">';
548 print '<a class="right" href="#amount_'.$facid.'">'.$langs->trans("GoSourceInvoice").'</a>';
549 print '</td></tr>';
550 }
551
552 print '</table>';
553
554 print dol_get_fiche_end();
555
556
557 /*
558 * List of unpaid invoices
559 */
560
561 $sql = 'SELECT f.rowid as facid, f.ref, f.total_ttc, f.multicurrency_code, f.multicurrency_total_ttc, f.type,';
562 $sql .= ' f.datef as df, f.fk_soc as socid, f.date_lim_reglement as dlr';
563 $sql .= ' FROM '.MAIN_DB_PREFIX.'facture as f';
564 $sql .= ' WHERE f.entity IN ('.getEntity('facture').')';
565 $sql .= ' AND (f.fk_soc = '.((int) $facture->socid);
566 // Can pay invoices of all child of parent company
567 if (!empty($conf->global->FACTURE_PAYMENTS_ON_DIFFERENT_THIRDPARTIES_BILLS) && !empty($facture->thirdparty->parent)) {
568 $sql .= ' OR f.fk_soc IN (SELECT rowid FROM '.MAIN_DB_PREFIX.'societe WHERE parent = '.((int) $facture->thirdparty->parent).')';
569 }
570 // Can pay invoices of all child of myself
571 if (!empty($conf->global->FACTURE_PAYMENTS_ON_SUBSIDIARY_COMPANIES)) {
572 $sql .= ' OR f.fk_soc IN (SELECT rowid FROM '.MAIN_DB_PREFIX.'societe WHERE parent = '.((int) $facture->thirdparty->id).')';
573 }
574 $sql .= ') AND f.paye = 0';
575 $sql .= ' AND f.fk_statut = 1'; // Statut=0 => not validated, Statut=2 => canceled
576 if ($facture->type != Facture::TYPE_CREDIT_NOTE) {
577 $sql .= ' AND type IN (0,1,3,5)'; // Standard invoice, replacement, deposit, situation
578 } else {
579 $sql .= ' AND type = 2'; // If paying back a credit note, we show all credit notes
580 }
581 // Sort invoices by date and serial number: the older one comes first
582 $sql .= ' ORDER BY f.datef ASC, f.ref ASC';
583
584 $resql = $db->query($sql);
585 if ($resql) {
586 $num = $db->num_rows($resql);
587 if ($num > 0) {
588 $arraytitle = $langs->trans('Invoice');
589 if ($facture->type == 2) {
590 $arraytitle = $langs->trans("CreditNotes");
591 }
592 $alreadypayedlabel = $langs->trans('Received');
593 $multicurrencyalreadypayedlabel = $langs->trans('MulticurrencyReceived');
594 if ($facture->type == 2) {
595 $alreadypayedlabel = $langs->trans("PaidBack");
596 $multicurrencyalreadypayedlabel = $langs->trans("MulticurrencyPaidBack");
597 }
598 $remaindertopay = $langs->trans('RemainderToTake');
599 $multicurrencyremaindertopay = $langs->trans('MulticurrencyRemainderToTake');
600 if ($facture->type == 2) {
601 $remaindertopay = $langs->trans("RemainderToPayBack");
602 $multicurrencyremaindertopay = $langs->trans("MulticurrencyRemainderToPayBack");
603 }
604
605 $i = 0;
606 //print '<tr><td colspan="3">';
607 print '<br>';
608
609 print '<div class="div-table-responsive-no-min">'; // You can use div-table-responsive-no-min if you dont need reserved height for your table
610 print '<table class="noborder centpercent">';
611
612 print '<tr class="liste_titre">';
613 print '<td>'.$arraytitle.'</td>';
614 print '<td class="center">'.$langs->trans('Date').'</td>';
615 print '<td class="center">'.$langs->trans('DateMaxPayment').'</td>';
616 if (isModEnabled('multicurrency')) {
617 print '<td>'.$langs->trans('Currency').'</td>';
618 print '<td class="right">'.$langs->trans('MulticurrencyAmountTTC').'</td>';
619 print '<td class="right">'.$multicurrencyalreadypayedlabel.'</td>';
620 print '<td class="right">'.$multicurrencyremaindertopay.'</td>';
621 print '<td class="right">'.$langs->trans('MulticurrencyPaymentAmount').'</td>';
622 }
623 print '<td class="right">'.$langs->trans('AmountTTC').'</td>';
624 print '<td class="right">'.$alreadypayedlabel.'</td>';
625 print '<td class="right">'.$remaindertopay.'</td>';
626 print '<td class="right">'.$langs->trans('PaymentAmount').'</td>';
627
628 $parameters = array();
629 $reshook = $hookmanager->executeHooks('printFieldListTitle', $parameters, $facture, $action); // Note that $action and $object may have been modified by hook
630
631 print '<td align="right">&nbsp;</td>';
632 print "</tr>\n";
633
634 $total_ttc = 0;
635 $totalrecu = 0;
636 $totalrecucreditnote = 0;
637 $totalrecudeposits = 0;
638
639 while ($i < $num) {
640 $objp = $db->fetch_object($resql);
641
642 $sign = 1;
643 if ($facture->type == Facture::TYPE_CREDIT_NOTE) {
644 $sign = -1;
645 }
646
647 $soc = new Societe($db);
648 $soc->fetch($objp->socid);
649
650 $invoice = new Facture($db);
651 $invoice->fetch($objp->facid);
652 $paiement = $invoice->getSommePaiement();
653 $creditnotes = $invoice->getSumCreditNotesUsed();
654 $deposits = $invoice->getSumDepositsUsed();
655 $alreadypayed = price2num($paiement + $creditnotes + $deposits, 'MT');
656 $remaintopay = price2num($invoice->total_ttc - $paiement - $creditnotes - $deposits, 'MT');
657
658 // Multicurrency Price
659 if (isModEnabled('multicurrency')) {
660 $multicurrency_payment = $invoice->getSommePaiement(1);
661 $multicurrency_creditnotes = $invoice->getSumCreditNotesUsed(1);
662 $multicurrency_deposits = $invoice->getSumDepositsUsed(1);
663 $multicurrency_alreadypayed = price2num($multicurrency_payment + $multicurrency_creditnotes + $multicurrency_deposits, 'MT');
664 $multicurrency_remaintopay = price2num($invoice->multicurrency_total_ttc - $multicurrency_payment - $multicurrency_creditnotes - $multicurrency_deposits, 'MT');
665 }
666
667
668 print '<tr class="oddeven'.(($invoice->id == $facid) ? ' highlight' : '').'">';
669
670 print '<td class="nowraponall">';
671 print $invoice->getNomUrl(1, '');
672 if ($objp->socid != $facture->thirdparty->id) {
673 print ' - '.$soc->getNomUrl(1).' ';
674 }
675 print "</td>\n";
676
677 // Date
678 print '<td class="center">'.dol_print_date($db->jdate($objp->df), 'day')."</td>\n";
679
680 // Due date
681 if ($objp->dlr > 0) {
682 print '<td class="nowraponall center">';
683 print dol_print_date($db->jdate($objp->dlr), 'day');
684
685 if ($invoice->hasDelay()) {
686 print img_warning($langs->trans('Late'));
687 }
688
689 print '</td>';
690 } else {
691 print '<td align="center"></td>';
692 }
693
694 // Currency
695 if (isModEnabled('multicurrency')) {
696 print '<td class="center">'.$objp->multicurrency_code."</td>\n";
697 }
698
699 // Multicurrency Price
700 if (isModEnabled('multicurrency')) {
701 print '<td class="right">';
702 if ($objp->multicurrency_code && $objp->multicurrency_code != $conf->currency) {
703 print price($sign * $objp->multicurrency_total_ttc);
704 }
705 print '</td>';
706
707 // Multicurrency Price
708 print '<td class="right">';
709 if ($objp->multicurrency_code && $objp->multicurrency_code != $conf->currency) {
710 print price($sign * $multicurrency_payment);
711 if ($multicurrency_creditnotes) {
712 print '+'.price($multicurrency_creditnotes);
713 }
714 if ($multicurrency_deposits) {
715 print '+'.price($multicurrency_deposits);
716 }
717 }
718 print '</td>';
719
720 // Multicurrency remain to pay
721 print '<td class="right">';
722 if ($objp->multicurrency_code && $objp->multicurrency_code != $conf->currency) {
723 print price($sign * $multicurrency_remaintopay);
724 }
725 print '</td>';
726
727 print '<td class="right nowraponall">';
728
729 // Add remind multicurrency amount
730 $namef = 'multicurrency_amount_'.$objp->facid;
731 $nameRemain = 'multicurrency_remain_'.$objp->facid;
732
733 if ($objp->multicurrency_code && $objp->multicurrency_code != $conf->currency) {
734 if ($action != 'add_paiement') {
735 if (!empty($conf->use_javascript_ajax)) {
736 print img_picto("Auto fill", 'rightarrow', "class='AutoFillAmout' data-rowname='".$namef."' data-value='".($sign * $multicurrency_remaintopay)."'");
737 }
738 print '<input type="text" class="maxwidth75 multicurrency_amount" name="'.$namef.'" value="'.GETPOST($namef).'">';
739 print '<input type="hidden" class="multicurrency_remain" name="'.$nameRemain.'" value="'.$multicurrency_remaintopay.'">';
740 } else {
741 print '<input type="text" class="maxwidth75" name="'.$namef.'_disabled" value="'.GETPOST($namef).'" disabled>';
742 print '<input type="hidden" name="'.$namef.'" value="'.GETPOST($namef).'">';
743 }
744 }
745 print "</td>";
746 }
747
748 // Price
749 print '<td class="right"><span class="amount">'.price($sign * $objp->total_ttc).'</span></td>';
750
751 // Received + already paid
752 print '<td class="right"><span class="amount">'.price($sign * $paiement);
753 if ($creditnotes) {
754 print '<span class="opacitymedium">+'.price($creditnotes).'</span>';
755 }
756 if ($deposits) {
757 print '<span class="opacitymedium">+'.price($deposits).'</span>';
758 }
759 print '</span></td>';
760
761 // Remain to take or to pay back
762 print '<td class="right">';
763 print price($sign * $remaintopay);
764 if (isModEnabled('prelevement')) {
765 $numdirectdebitopen = 0;
766 $totaldirectdebit = 0;
767 $sql = "SELECT COUNT(pfd.rowid) as nb, SUM(pfd.amount) as amount";
768 $sql .= " FROM ".MAIN_DB_PREFIX."prelevement_demande as pfd";
769 $sql .= " WHERE fk_facture = ".((int) $objp->facid);
770 $sql .= " AND pfd.traite = 0";
771 $sql .= " AND pfd.ext_payment_id IS NULL";
772
773 $result_sql = $db->query($sql);
774 if ($result_sql) {
775 $obj = $db->fetch_object($result_sql);
776 $numdirectdebitopen = $obj->nb;
777 $totaldirectdebit = $obj->amount;
778 } else {
779 dol_print_error($db);
780 }
781 if ($numdirectdebitopen) {
782 $langs->load("withdrawals");
783 print img_warning($langs->trans("WarningSomeDirectDebitOrdersAlreadyExists", $numdirectdebitopen, price(price2num($totaldirectdebit, 'MT'), 0, $langs, 1, -1, -1, $conf->currency)), '', 'classfortooltip');
784 }
785 }
786 print '</td>';
787 //$test= price(price2num($objp->total_ttc - $paiement - $creditnotes - $deposits));
788
789 // Amount
790 print '<td class="right nowraponall">';
791
792 // Add remind amount
793 $namef = 'amount_'.$objp->facid;
794 $nameRemain = 'remain_'.$objp->facid;
795
796 if ($action != 'add_paiement') {
797 if (!empty($conf->use_javascript_ajax)) {
798 print img_picto("Auto fill", 'rightarrow', "class='AutoFillAmout' data-rowname='".$namef."' data-value='".($sign * $remaintopay)."'");
799 }
800 print '<input type="text" class="maxwidth75 amount" id="'.$namef.'" name="'.$namef.'" value="'.dol_escape_htmltag(GETPOST($namef)).'">';
801 print '<input type="hidden" class="remain" name="'.$nameRemain.'" value="'.$remaintopay.'">';
802 } else {
803 print '<input type="text" class="maxwidth75" name="'.$namef.'_disabled" value="'.dol_escape_htmltag(GETPOST($namef)).'" disabled>';
804 print '<input type="hidden" name="'.$namef.'" value="'.dol_escape_htmltag(GETPOST($namef)).'">';
805 }
806 print "</td>";
807
808 $parameters = array();
809 $reshook = $hookmanager->executeHooks('printFieldListValue', $parameters, $objp, $action); // Note that $action and $object may have been modified by hook
810
811 // Warning
812 print '<td align="center" width="16">';
813 //print "xx".$amounts[$invoice->id]."-".$amountsresttopay[$invoice->id]."<br>";
814 if (!empty($amounts[$invoice->id]) && (abs($amounts[$invoice->id]) > abs($amountsresttopay[$invoice->id]))
815 || !empty($multicurrency_amounts[$invoice->id]) && (abs($multicurrency_amounts[$invoice->id]) > abs($multicurrency_amountsresttopay[$invoice->id]))) {
816 print ' '.img_warning($langs->trans("PaymentHigherThanReminderToPay"));
817 }
818 print '</td>';
819
820 print "</tr>\n";
821
822 $total_ttc += $objp->total_ttc;
823 $totalrecu += $paiement;
824 $totalrecucreditnote += $creditnotes;
825 $totalrecudeposits += $deposits;
826 $i++;
827 }
828
829 if ($i > 1) {
830 // Print total
831 print '<tr class="liste_total">';
832 print '<td colspan="3" class="left">'.$langs->trans('TotalTTC').'</td>';
833 if (isModEnabled('multicurrency')) {
834 print '<td></td>';
835 print '<td></td>';
836 print '<td></td>';
837 print '<td></td>';
838 print '<td class="right" id="multicurrency_result" style="font-weight: bold;"></td>';
839 }
840 print '<td class="right"><b>'.price($sign * $total_ttc).'</b></td>';
841 print '<td class="right"><b>'.price($sign * $totalrecu);
842 if ($totalrecucreditnote) {
843 print '+'.price($totalrecucreditnote);
844 }
845 if ($totalrecudeposits) {
846 print '+'.price($totalrecudeposits);
847 }
848 print '</b></td>';
849 print '<td class="right"><b>'.price($sign * price2num($total_ttc - $totalrecu - $totalrecucreditnote - $totalrecudeposits, 'MT')).'</b></td>';
850 print '<td class="right" id="result" style="font-weight: bold;"></td>'; // Autofilled
851 print '<td align="center">&nbsp;</td>';
852 print "</tr>\n";
853 }
854 print "</table>";
855 print "</div>\n";
856 }
857 $db->free($resql);
858 } else {
859 dol_print_error($db);
860 }
861
862 $formconfirm = '';
863
864 // Save button
865 if ($action != 'add_paiement') {
866 $checkboxlabel = $langs->trans("ClosePaidInvoicesAutomatically");
867 if ($facture->type == Facture::TYPE_CREDIT_NOTE) {
868 $checkboxlabel = $langs->trans("ClosePaidCreditNotesAutomatically");
869 }
870 $buttontitle = $langs->trans('ToMakePayment');
871 if ($facture->type == Facture::TYPE_CREDIT_NOTE) {
872 $buttontitle = $langs->trans('ToMakePaymentBack');
873 }
874
875 print '<br><div class="center">';
876 print '<input type="checkbox" checked name="closepaidinvoices"> '.$checkboxlabel;
877 /*if (isModEnabled('prelevement')) {
878 $langs->load("withdrawals");
879 if (!empty($conf->global->WITHDRAW_DISABLE_AUTOCREATE_ONPAYMENTS)) print '<br>'.$langs->trans("IfInvoiceNeedOnWithdrawPaymentWontBeClosed");
880 }*/
881 print '<br><input type="submit" class="button reposition" value="'.dol_escape_htmltag($buttontitle).'"><br><br>';
882 print '</div>';
883 }
884
885 // Form to confirm payment
886 if ($action == 'add_paiement') {
887 $preselectedchoice = $addwarning ? 'no' : 'yes';
888
889 print '<br>';
890 if (!empty($totalpayment)) {
891 $text = $langs->trans('ConfirmCustomerPayment', $totalpayment, $langs->transnoentitiesnoconv("Currency".$conf->currency));
892 }
893 if (!empty($multicurrency_totalpayment)) {
894 $text .= '<br>'.$langs->trans('ConfirmCustomerPayment', $multicurrency_totalpayment, $langs->transnoentitiesnoconv("paymentInInvoiceCurrency"));
895 }
896 if (GETPOST('closepaidinvoices')) {
897 $text .= '<br>'.$langs->trans("AllCompletelyPayedInvoiceWillBeClosed");
898 print '<input type="hidden" name="closepaidinvoices" value="'.GETPOST('closepaidinvoices').'">';
899 }
900 $formconfirm = $form->formconfirm($_SERVER['PHP_SELF'].'?facid='.$facture->id.'&socid='.$facture->socid.'&type='.$facture->type, $langs->trans('ReceivedCustomersPayments'), $text, 'confirm_paiement', $formquestion, $preselectedchoice);
901 }
902
903 // Call Hook formConfirm
904 $parameters = array('formConfirm' => $formconfirm);
905 $reshook = $hookmanager->executeHooks('formConfirm', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
906 if (empty($reshook)) {
907 $formconfirm .= $hookmanager->resPrint;
908 } elseif ($reshook > 0) {
909 $formconfirm = $hookmanager->resPrint;
910 }
911
912 // Print form confirm
913 print $formconfirm;
914
915 print "</form>\n";
916 }
917}
918
919
923if (!GETPOST('action', 'aZ09')) {
924 if (empty($page) || $page == -1) {
925 $page = 0;
926 }
927 $limit = GETPOST('limit', 'int') ?GETPOST('limit', 'int') : $conf->liste_limit;
928 $offset = $limit * $page;
929
930 if (!$sortorder) {
931 $sortorder = 'DESC';
932 }
933 if (!$sortfield) {
934 $sortfield = 'p.datep';
935 }
936
937 $sql = 'SELECT p.datep as dp, p.amount, f.total_ttc as fa_amount, f.ref';
938 $sql .= ', f.rowid as facid, c.libelle as paiement_type, p.num_paiement as num_payment';
939 $sql .= ' FROM '.MAIN_DB_PREFIX.'paiement as p LEFT JOIN '.MAIN_DB_PREFIX.'c_paiement as c ON p.fk_paiement = c.id';
940 $sql .= ', '.MAIN_DB_PREFIX.'facture as f';
941 $sql .= ' WHERE p.fk_facture = f.rowid';
942 $sql .= ' AND f.entity IN ('.getEntity('invoice').')';
943 if ($socid) {
944 $sql .= ' AND f.fk_soc = '.((int) $socid);
945 }
946
947 $sql .= $db->order($sortfield, $sortorder);
948 $sql .= $db->plimit($limit + 1, $offset);
949 $resql = $db->query($sql);
950
951 if ($resql) {
952 $num = $db->num_rows($resql);
953 $i = 0;
954
955 print_barre_liste($langs->trans('Payments'), $page, $_SERVER["PHP_SELF"], '', $sortfield, $sortorder, '', $num);
956 print '<table class="noborder centpercent">';
957 print '<tr class="liste_titre">';
958 print_liste_field_titre('Invoice', $_SERVER["PHP_SELF"], 'f.ref', '', '', '', $sortfield, $sortorder);
959 print_liste_field_titre('Date', $_SERVER["PHP_SELF"], 'p.datep', '', '', '', $sortfield, $sortorder);
960 print_liste_field_titre('Type', $_SERVER["PHP_SELF"], 'c.libelle', '', '', '', $sortfield, $sortorder);
961 print_liste_field_titre('Amount', $_SERVER["PHP_SELF"], 'p.amount', '', '', '', $sortfield, $sortorder, 'right ');
962 print_liste_field_titre('', $_SERVER["PHP_SELF"], "", '', '', '', $sortfield, $sortorder, 'maxwidthsearch ');
963 print "</tr>\n";
964
965 while ($i < min($num, $limit)) {
966 $objp = $db->fetch_object($resql);
967
968 print '<tr class="oddeven">';
969 print '<td><a href="'.DOL_URL_ROOT.'/compta/facture/card.php?facid='.$objp->facid.'">'.$objp->ref."</a></td>\n";
970 print '<td>'.dol_print_date($db->jdate($objp->dp))."</td>\n";
971 print '<td>'.$objp->paiement_type.' '.$objp->num_payment."</td>\n";
972 print '<td class="right"><span class="amount">'.price($objp->amount).'</span></td>';
973 print '<td>&nbsp;</td>';
974 print '</tr>';
975
976 $parameters = array();
977 $reshook = $hookmanager->executeHooks('printObjectLine', $parameters, $objp, $action); // Note that $action and $object may have been modified by hook
978
979 $i++;
980 }
981 print '</table>';
982 }
983}
984
985llxFooter();
986
987$db->close();
if(!defined('NOREQUIRESOC')) if(!defined( 'NOREQUIRETRAN')) if(!defined('NOTOKENRENEWAL')) if(!defined( 'NOREQUIREMENU')) if(!defined('NOREQUIREHTML')) if(!defined( 'NOREQUIREAJAX')) llxHeader()
Empty header.
Definition wrapper.php:56
llxFooter()
Empty footer.
Definition wrapper.php:70
Class to manage invoices.
const STATUS_DRAFT
Draft status.
const TYPE_CREDIT_NOTE
Credit note invoice.
Class to manage generation of HTML components Only common components must be here.
Class to manage payments of customer invoices.
Class to manage third parties objects (customers, suppliers, prospects...)
dol_mktime($hour, $minute, $second, $month, $day, $year, $gm='auto', $check=1)
Return a timestamp date built from detailed informations (by default a local PHP server timestamp) Re...
load_fiche_titre($titre, $morehtmlright='', $picto='generic', $pictoisfullpath=0, $id='', $morecssontable='', $morehtmlcenter='')
Load a title with picto.
img_warning($titlealt='default', $moreatt='', $morecss='pictowarning')
Show warning logo.
dol_get_fiche_head($links=array(), $active='', $title='', $notab=0, $picto='', $pictoisfullpath=0, $morehtmlright='', $morecss='', $limittoshow=0, $moretabssuffix='', $dragdropfile=0)
Show tabs of a record.
price2num($amount, $rounding='', $option=0)
Function that return a number with universal decimal format (decimal separator is '.
dol_print_error($db='', $error='', $errors=null)
Displays error message system with all the information to facilitate the diagnosis and the escalation...
currentToken()
Return the value of token currently saved into session with name 'token'.
dol_get_fiche_end($notab=0)
Return tab footer of a card.
price($amount, $form=0, $outlangs='', $trunc=1, $rounding=-1, $forcerounding=-1, $currency_code='')
Function to format a value into an amount for visual output Function used into PDF and HTML pages.
dol_print_date($time, $format='', $tzoutput='auto', $outputlangs='', $encodetooutput=false)
Output date in a string format according to outputlangs (or langs if not defined).
img_picto($titlealt, $picto, $moreatt='', $pictoisfullpath=false, $srconly=0, $notitle=0, $alt='', $morecss='', $marginleftonlyshort=2)
Show picto whatever it's its name (generic function)
dol_escape_js($stringtoescape, $mode=0, $noescapebackslashn=0)
Returns text escaped for inclusion into javascript code.
dol_getIdFromCode($db, $key, $tablename, $fieldkey='code', $fieldid='id', $entityfilter=0, $filters='')
Return an id or code from a code or id.
print_liste_field_titre($name, $file="", $field="", $begin="", $moreparam="", $moreattrib="", $sortfield="", $sortorder="", $prefix="", $tooltip="", $forcenowrapcolumntitle=0)
Show title line of an array.
GETPOST($paramname, $check='alphanohtml', $method=0, $filter=null, $options=null, $noreplace=0)
Return value of a param into GET or POST supervariable.
setEventMessages($mesg, $mesgs, $style='mesgs', $messagekey='', $noduplicate=0)
Set event messages in dol_events session object.
print_barre_liste($titre, $page, $file, $options='', $sortfield='', $sortorder='', $morehtmlcenter='', $num=-1, $totalnboflines='', $picto='generic', $pictoisfullpath=0, $morehtmlright='', $morecss='', $limit=-1, $hideselectlimit=0, $hidenavigation=0, $pagenavastextinput=0, $morehtmlrightbeforearrow='')
Print a title with navigation controls for pagination.
dol_escape_htmltag($stringtoescape, $keepb=0, $keepn=0, $noescapetags='', $escapeonlyhtmltags=0, $cleanalsojavascript=0)
Returns text escaped for inclusion in HTML alt or title or value tags, or into values of HTML input f...
restrictedArea(User $user, $features, $object=0, $tableandshare='', $feature2='', $dbt_keyfield='fk_soc', $dbt_select='rowid', $isdraft=0, $mode=0)
Check permissions of a user to show a page and an object.