dolibarr 21.0.0-beta
payment.php
Go to the documentation of this file.
1<?php
2/* Copyright (C) 2014-2024 Alexandre Spangaro <alexandre@inovea-conseil.com>
3 * Copyright (C) 2015-2024 Frédéric France <frederic.france@free.fr>
4 * Copyright (C) 2020 Maxime DEMAREST <maxime@indelog.fr>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <https://www.gnu.org/licenses/>.
18 */
19
26// Load Dolibarr environment
27require '../../main.inc.php';
28require_once DOL_DOCUMENT_ROOT.'/loan/class/loan.class.php';
29require_once DOL_DOCUMENT_ROOT.'/loan/class/loanschedule.class.php';
30require_once DOL_DOCUMENT_ROOT.'/loan/class/paymentloan.class.php';
31require_once DOL_DOCUMENT_ROOT.'/compta/bank/class/account.class.php';
32require_once DOL_DOCUMENT_ROOT.'/core/lib/loan.lib.php';
33
42$langs->loadLangs(array("bills", "loan"));
43
44$action = GETPOST('action', 'aZ09');
45$confirm = GETPOST('confirm', 'alpha');
46$cancel = GETPOST('cancel', 'alpha');
47
48$chid = GETPOSTINT('id');
49$datepaid = dol_mktime(12, 0, 0, GETPOSTINT('remonth'), GETPOSTINT('reday'), GETPOSTINT('reyear'));
50
51// Security check
52$socid = 0;
53if ($user->socid > 0) {
54 $socid = $user->socid;
55} elseif (GETPOSTISSET('socid')) {
56 $socid = GETPOSTINT('socid');
57}
58if (!$user->hasRight('loan', 'write')) {
60}
61
62$loan = new Loan($db);
63$loan->fetch($chid);
64
65$echance = 0;
66$ls = new LoanSchedule($db);
67// grab all loanschedule
68$res = $ls->fetchAll($chid);
69if ($res > 0) {
70 foreach ($ls->lines as $l) {
71 $echance++; // Count term pos
72 // last unpaid term
73 if (empty($l->fk_bank)) {
74 $line_id = $l->id;
75 break;
76 } elseif ($line_id == $l->id) {
77 // If line_id provided, only count temp pos
78 break;
79 }
80 }
81}
82
83// Set current line with last unpaid line (only if schedule is used)
84if (!empty($line_id)) {
85 $line = new LoanSchedule($db);
86 $res = $line->fetch($line_id);
87 if ($res > 0) {
88 $amount_capital = price($line->amount_capital);
89 $amount_insurance = price($line->amount_insurance);
90 $amount_interest = price($line->amount_interest);
91 if (empty($datepaid)) {
92 $ts_temppaid = $line->datep;
93 }
94 }
95}
96
97$permissiontoadd = $user->hasRight('loan', 'write');
98
99
100/*
101 * Actions
102 */
103
104if ($action == 'add_payment' && $permissiontoadd) {
105 $error = 0;
106
107 if ($cancel) {
108 $loc = DOL_URL_ROOT.'/loan/card.php?id='.$chid;
109 header("Location: ".$loc);
110 exit;
111 }
112
113 if (!GETPOSTINT('paymenttype') > 0) {
114 setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentities("PaymentMode")), null, 'errors');
115 $error++;
116 }
117 if ($datepaid == '') {
118 setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentities("Date")), null, 'errors');
119 $error++;
120 }
121 if (isModEnabled("bank") && !GETPOSTINT('accountid') > 0) {
122 setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentities("AccountToCredit")), null, 'errors');
123 $error++;
124 }
125
126 if (!$error) {
127 $paymentid = 0;
128
129 $pay_amount_capital = (float) price2num(GETPOST('amount_capital'));
130 $pay_amount_insurance = (float) price2num(GETPOST('amount_insurance'));
131 // User can't set interest him self if schedule is set (else value in schedule can be incoherent)
132 if (!empty($line)) {
133 $pay_amount_interest = $line->amount_interest;
134 } else {
135 $pay_amount_interest = (float) price2num(GETPOST('amount_interest'));
136 }
137 $remaindertopay = (float) price2num(GETPOST('remaindertopay'));
138 $amount = (float) price2num($pay_amount_capital + $pay_amount_insurance + $pay_amount_interest, 'MT');
139
140 // This term is already paid
141 if (!empty($line) && !empty($line->fk_bank)) {
142 setEventMessages($langs->trans('TermPaidAllreadyPaid'), null, 'errors');
143 $error++;
144 }
145
146 if (empty($remaindertopay)) {
147 setEventMessages('Empty sumpaid', null, 'errors');
148 $error++;
149 }
150
151 if ($amount == 0) {
152 setEventMessages($langs->trans('ErrorNoPaymentDefined'), null, 'errors');
153 $error++;
154 }
155
156 if (!$error) {
157 $db->begin();
158
159 // Create a line of payments
160 $payment = new PaymentLoan($db);
161 $payment->chid = $chid;
162 $payment->datep = $datepaid;
163 $payment->label = $loan->label;
164 $payment->amount_capital = $pay_amount_capital;
165 $payment->amount_insurance = $pay_amount_insurance;
166 $payment->amount_interest = $pay_amount_interest;
167 $payment->fk_bank = GETPOSTINT('accountid');
168 $payment->paymenttype = GETPOSTINT('paymenttype');
169 $payment->num_payment = GETPOST('num_payment', 'alphanohtml');
170 $payment->note_private = GETPOST('note_private', 'restricthtml');
171 $payment->note_public = GETPOST('note_public', 'restricthtml');
172
173 if (!$error) {
174 $paymentid = $payment->create($user);
175 if ($paymentid < 0) {
176 setEventMessages($payment->error, $payment->errors, 'errors');
177 $error++;
178 }
179 }
180
181 if (!$error) {
182 // @phan-suppress-next-line PhanPluginSuspiciousParamOrder
183 $result = $payment->addPaymentToBank($user, $chid, 'payment_loan', '(LoanPayment)', $payment->fk_bank, '', '');
184 if (!($result > 0)) {
185 setEventMessages($payment->error, $payment->errors, 'errors');
186 $error++;
187 }
188 }
189
190 // Update loan schedule with payment value
191 if (!$error && !empty($line)) {
192 // If payment values are modified, recalculate schedule
193 if (($line->amount_capital != $pay_amount_capital) || ($line->amount_insurance != $pay_amount_insurance) || ($line->amount_interest != $pay_amount_interest)) {
194 $arr_term = loanCalcMonthlyPayment(($pay_amount_capital + $pay_amount_interest), $remaindertopay, ($loan->rate / 100), $echance, (int) $loan->nbterm);
195 foreach ($arr_term as $k => $v) {
196 // Update fk_bank for current line
197 if ($k == $echance) {
198 $ls->lines[$k - 1]->fk_bank = $payment->fk_bank;
199 $ls->lines[$k - 1]->fk_payment_loan = $payment->id;
200 }
201 $ls->lines[$k - 1]->amount_capital = $v['mens'] - $v['interet'];
202 $ls->lines[$k - 1]->amount_interest = $v['interet'];
203 $ls->lines[$k - 1]->tms = dol_now();
204 $ls->lines[$k - 1]->fk_user_modif = $user->id;
205 $result = $ls->lines[$k - 1]->update($user, 0);
206 if ($result < 1) {
207 setEventMessages(null, $ls->errors, 'errors');
208 $error++;
209 break;
210 }
211 }
212 } else { // Only add fk_bank bank to schedule line (mark as paid)
213 $line->fk_bank = $payment->fk_bank;
214 $line->fk_payment_loan = $payment->id;
215 $result = $line->update($user, 0);
216 if ($result < 1) {
217 setEventMessages(null, $line->errors, 'errors');
218 $error++;
219 }
220 }
221 }
222
223 if (!$error) {
224 $db->commit();
225 $loc = DOL_URL_ROOT.'/loan/card.php?id='.$chid;
226 header('Location: '.$loc);
227 exit;
228 } else {
229 $db->rollback();
230 }
231 }
232 }
233
234 $action = 'create';
235}
236
237
238/*
239 * View
240 */
241$form = new Form($db);
242
243$title = $langs->trans('Loans');
244$help_url = "EN:Module_Loan|FR:Module_Emprunt";
245
246llxHeader('', $title, $help_url, '', 0, 0, '', '', '', 'bodyforlist mod-loan page-payment-list');
247
248
249// Form to create loan's payment
250if ($action == 'create') {
251 $total = $loan->capital;
252
253 print load_fiche_titre($langs->trans("DoPayment"));
254
255 $sql = "SELECT SUM(amount_capital) as total";
256 $sql .= " FROM ".MAIN_DB_PREFIX."payment_loan";
257 $sql .= " WHERE fk_loan = ".((int) $chid);
258 $resql = $db->query($sql);
259 if ($resql) {
260 $obj = $db->fetch_object($resql);
261 $sumpaid = $obj->total;
262 $db->free($resql);
263 }
264
265 print '<form name="add_payment" action="'.$_SERVER['PHP_SELF'].'" method="post">';
266 print '<input type="hidden" name="token" value="'.newToken().'">';
267 print '<input type="hidden" name="id" value="'.$chid.'">';
268 print '<input type="hidden" name="chid" value="'.$chid.'">';
269 print '<input type="hidden" name="line_id" value="'.$line_id.'">';
270 print '<input type="hidden" name="remaindertopay" value="'.($total - $sumpaid).'">';
271 print '<input type="hidden" name="action" value="add_payment">';
272
273 print dol_get_fiche_head();
274
275 /*
276 print '<table class="border centpercent">';
277
278 print '<tr><td class="titlefield">'.$langs->trans("Ref").'</td><td colspan="2"><a href="'.DOL_URL_ROOT.'/loan/card.php?id='.$chid.'">'.$chid.'</a></td></tr>';
279 if ($echance > 0)
280 {
281 print '<tr><td>'.$langs->trans("Term").'</td><td colspan="2"><a href="'.DOL_URL_ROOT.'/loan/schedule.php?loanid='.$chid.'#n'.$echance.'">'.$echance.'</a></td></tr>'."\n";
282 }
283 print '<tr><td>'.$langs->trans("DateStart").'</td><td colspan="2">'.dol_print_date($loan->datestart, 'day')."</td></tr>\n";
284 print '<tr><td>'.$langs->trans("Label").'</td><td colspan="2">'.$loan->label."</td></tr>\n";
285 print '<tr><td>'.$langs->trans("Amount").'</td><td colspan="2">'.price($loan->capital, 0, $outputlangs, 1, -1, -1, $conf->currency).'</td></tr>';
286
287 print '<tr><td>'.$langs->trans("AlreadyPaid").'</td><td colspan="2">'.price($sumpaid, 0, $outputlangs, 1, -1, -1, $conf->currency).'</td></tr>';
288 print '<tr><td class="tdtop">'.$langs->trans("RemainderToPay").'</td><td colspan="2">'.price($total - $sumpaid, 0, $outputlangs, 1, -1, -1, $conf->currency).'</td></tr>';
289 print '</tr>';
290
291 print '</table>';
292 */
293
294 print '<table class="border centpercent">';
295
296 print '<tr><td class="titlefield fieldrequired">'.$langs->trans("Date").'</td><td colspan="2">';
297 if (empty($datepaid)) {
298 if (empty($ts_temppaid)) {
299 $datepayment = !getDolGlobalString('MAIN_AUTOFILL_DATE') ? -1 : dol_now();
300 } else {
301 $datepayment = $ts_temppaid;
302 }
303 } else {
304 $datepayment = $datepaid;
305 }
306 print $form->selectDate($datepayment, '', 0, 0, 0, "add_payment", 1, 1);
307 print "</td>";
308 print '</tr>';
309
310 print '<tr><td class="fieldrequired">'.$langs->trans("PaymentMode").'</td><td colspan="2">';
311 print img_picto('', 'money-bill-alt', 'class="pictofixedwidth"');
312 $form->select_types_paiements(GETPOSTISSET("paymenttype") ? GETPOST("paymenttype", 'alphanohtml') : $loan->fk_typepayment, "paymenttype");
313 print "</td>\n";
314 print '</tr>';
315
316 print '<tr>';
317 print '<td class="fieldrequired">'.$langs->trans('AccountToDebit').'</td>';
318 print '<td colspan="2">';
319 print img_picto('', 'bank_account', 'class="pictofixedwidth"');
320 $form->select_comptes(GETPOSTISSET("accountid") ? GETPOSTINT("accountid") : $loan->accountid, "accountid", 0, 'courant = '.Account::TYPE_CURRENT, 1); // Show opend bank account list
321 print '</td></tr>';
322
323 // Number
324 print '<tr><td>'.$langs->trans('Numero');
325 print ' <em>('.$langs->trans("ChequeOrTransferNumber").')</em>';
326 print '</td>';
327 print '<td colspan="2"><input name="num_payment" type="text" value="'.GETPOST('num_payment', 'alphanohtml').'"></td>'."\n";
328 print "</tr>";
329
330 print '<tr>';
331 print '<td class="tdtop">'.$langs->trans("NotePrivate").'</td>';
332 print '<td valign="top" colspan="2"><textarea name="note_private" wrap="soft" cols="60" rows="'.ROWS_3.'"></textarea></td>';
333 print '</tr>';
334
335 print '<tr>';
336 print '<td class="tdtop">'.$langs->trans("NotePublic").'</td>';
337 print '<td valign="top" colspan="2"><textarea name="note_public" wrap="soft" cols="60" rows="'.ROWS_3.'"></textarea></td>';
338 print '</tr>';
339
340 print '</table>';
341
342 print dol_get_fiche_end();
343
344
345 print '<table class="noborder centpercent">';
346 print '<tr class="liste_titre">';
347 print '<td class="left">'.$langs->trans("DateDue").'</td>';
348 print '<td class="right">'.$langs->trans("LoanCapital").'</td>';
349 print '<td class="right">'.$langs->trans("AlreadyPaid").'</td>';
350 print '<td class="right">'.$langs->trans("RemainderToPay").'</td>';
351 print '<td class="right">'.$langs->trans("Amount").'</td>';
352 print "</tr>\n";
353
354 print '<tr class="oddeven">';
355
356 if ($loan->datestart > 0) {
357 print '<td class="left" valign="center">'.dol_print_date($loan->datestart, 'day').'</td>';
358 } else {
359 print '<td class="center" valign="center"><b>!!!</b></td>';
360 }
361
362 print '<td class="right" valign="center">'.price($loan->capital)."</td>";
363
364 print '<td class="right" valign="center">'.price($sumpaid)."</td>";
365
366 print '<td class="right" valign="center">'.price($loan->capital - $sumpaid)."</td>";
367
368 print '<td class="right">';
369 if ($sumpaid < $loan->capital) {
370 print $langs->trans("LoanCapital").': <input type="text" size="8" name="amount_capital" value="'.(GETPOSTISSET('amount_capital') ? GETPOST('amount_capital') : $amount_capital).'">';
371 } else {
372 print '-';
373 }
374 print '<br>';
375 if ($sumpaid < $loan->capital) {
376 print $langs->trans("Insurance").': <input type="text" size="8" name="amount_insurance" value="'.(GETPOSTISSET('amount_insurance') ? GETPOST('amount_insurance') : $amount_insurance).'">';
377 } else {
378 print '-';
379 }
380 print '<br>';
381 if ($sumpaid < $loan->capital) {
382 print $langs->trans("Interest").': <input type="text" size="8" name="amount_interest" value="'.(GETPOSTISSET('amount_interest') ? GETPOST('amount_interest') : $amount_interest).'" '.(!empty($line) ? 'disabled title="'.$langs->trans('CantModifyInterestIfScheduleIsUsed').'"' : '').'>';
383 } else {
384 print '-';
385 }
386 print "</td>";
387
388 print "</tr>\n";
389
390 print '</table>';
391
392 print $form->buttonsSaveCancel();
393
394 print "</form>\n";
395}
396
397llxFooter();
398$db->close();
if(!defined('NOREQUIRESOC')) if(!defined( 'NOREQUIRETRAN')) if(!defined('NOTOKENRENEWAL')) if(!defined( 'NOREQUIREMENU')) if(!defined('NOREQUIREHTML')) if(!defined( 'NOREQUIREAJAX')) llxHeader($head='', $title='', $help_url='', $target='', $disablejs=0, $disablehead=0, $arrayofjs='', $arrayofcss='', $morequerystring='', $morecssonbody='', $replacemainareaby='', $disablenofollow=0, $disablenoindex=0)
Empty header.
Definition wrapper.php:71
Class to manage bank accounts.
Class to manage generation of HTML components Only common components must be here.
Loan.
Class to manage Schedule of loans.
Class to manage payments of loans.
llxFooter()
Footer empty.
Definition document.php:107
dol_mktime($hour, $minute, $second, $month, $day, $year, $gm='auto', $check=1)
Return a timestamp date built from detailed information (by default a local PHP server timestamp) Rep...
load_fiche_titre($title, $morehtmlright='', $picto='generic', $pictoisfullpath=0, $id='', $morecssontable='', $morehtmlcenter='')
Load a title with picto.
setEventMessages($mesg, $mesgs, $style='mesgs', $messagekey='', $noduplicate=0, $attop=0)
Set event messages in dol_events session object.
img_picto($titlealt, $picto, $moreatt='', $pictoisfullpath=0, $srconly=0, $notitle=0, $alt='', $morecss='', $marginleftonlyshort=2)
Show picto whatever it's its name (generic function)
GETPOSTINT($paramname, $method=0)
Return the value of a $_GET or $_POST supervariable, converted into integer.
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_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_now($mode='auto')
Return date for now.
GETPOST($paramname, $check='alphanohtml', $method=0, $filter=null, $options=null, $noreplace=0)
Return value of a param into GET or POST supervariable.
getDolGlobalString($key, $default='')
Return a Dolibarr global constant string value.
loanCalcMonthlyPayment($mens, $capital, $rate, $numactualloadterm, $nbterm)
Calculate remaining loan mensuality and interests.
Definition loan.lib.php:103
accessforbidden($message='', $printheader=1, $printfooter=1, $showonlymessage=0, $params=null)
Show a message to say access is forbidden and stop program.