dolibarr 21.0.0-alpha
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
34$langs->loadLangs(array("bills", "loan"));
35
36$action = GETPOST('action', 'aZ09');
37$confirm = GETPOST('confirm', 'alpha');
38$cancel = GETPOST('cancel', 'alpha');
39
40$chid = GETPOSTINT('id');
41$datepaid = dol_mktime(12, 0, 0, GETPOSTINT('remonth'), GETPOSTINT('reday'), GETPOSTINT('reyear'));
42
43// Security check
44$socid = 0;
45if ($user->socid > 0) {
46 $socid = $user->socid;
47} elseif (GETPOSTISSET('socid')) {
48 $socid = GETPOSTINT('socid');
49}
50if (!$user->hasRight('loan', 'write')) {
52}
53
54$loan = new Loan($db);
55$loan->fetch($chid);
56
57$echance = 0;
58$ls = new LoanSchedule($db);
59// grab all loanschedule
60$res = $ls->fetchAll($chid);
61if ($res > 0) {
62 foreach ($ls->lines as $l) {
63 $echance++; // Count term pos
64 // last unpaid term
65 if (empty($l->fk_bank)) {
66 $line_id = $l->id;
67 break;
68 } elseif ($line_id == $l->id) {
69 // If line_id provided, only count temp pos
70 break;
71 }
72 }
73}
74
75// Set current line with last unpaid line (only if schedule is used)
76if (!empty($line_id)) {
77 $line = new LoanSchedule($db);
78 $res = $line->fetch($line_id);
79 if ($res > 0) {
80 $amount_capital = price($line->amount_capital);
81 $amount_insurance = price($line->amount_insurance);
82 $amount_interest = price($line->amount_interest);
83 if (empty($datepaid)) {
84 $ts_temppaid = $line->datep;
85 }
86 }
87}
88
89$permissiontoadd = $user->hasRight('loan', 'write');
90
91
92/*
93 * Actions
94 */
95
96if ($action == 'add_payment' && $permissiontoadd) {
97 $error = 0;
98
99 if ($cancel) {
100 $loc = DOL_URL_ROOT.'/loan/card.php?id='.$chid;
101 header("Location: ".$loc);
102 exit;
103 }
104
105 if (!GETPOSTINT('paymenttype') > 0) {
106 setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentities("PaymentMode")), null, 'errors');
107 $error++;
108 }
109 if ($datepaid == '') {
110 setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentities("Date")), null, 'errors');
111 $error++;
112 }
113 if (isModEnabled("bank") && !GETPOSTINT('accountid') > 0) {
114 setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentities("AccountToCredit")), null, 'errors');
115 $error++;
116 }
117
118 if (!$error) {
119 $paymentid = 0;
120
121 $pay_amount_capital = (float) price2num(GETPOST('amount_capital'));
122 $pay_amount_insurance = (float) price2num(GETPOST('amount_insurance'));
123 // User can't set interest him self if schedule is set (else value in schedule can be incoherent)
124 if (!empty($line)) {
125 $pay_amount_interest = $line->amount_interest;
126 } else {
127 $pay_amount_interest = (float) price2num(GETPOST('amount_interest'));
128 }
129 $remaindertopay = (float) price2num(GETPOST('remaindertopay'));
130 $amount = (float) price2num($pay_amount_capital + $pay_amount_insurance + $pay_amount_interest, 'MT');
131
132 // This term is already paid
133 if (!empty($line) && !empty($line->fk_bank)) {
134 setEventMessages($langs->trans('TermPaidAllreadyPaid'), null, 'errors');
135 $error++;
136 }
137
138 if (empty($remaindertopay)) {
139 setEventMessages('Empty sumpaid', null, 'errors');
140 $error++;
141 }
142
143 if ($amount == 0) {
144 setEventMessages($langs->trans('ErrorNoPaymentDefined'), null, 'errors');
145 $error++;
146 }
147
148 if (!$error) {
149 $db->begin();
150
151 // Create a line of payments
152 $payment = new PaymentLoan($db);
153 $payment->chid = $chid;
154 $payment->datep = $datepaid;
155 $payment->label = $loan->label;
156 $payment->amount_capital = $pay_amount_capital;
157 $payment->amount_insurance = $pay_amount_insurance;
158 $payment->amount_interest = $pay_amount_interest;
159 $payment->fk_bank = GETPOSTINT('accountid');
160 $payment->paymenttype = GETPOSTINT('paymenttype');
161 $payment->num_payment = GETPOST('num_payment', 'alphanohtml');
162 $payment->note_private = GETPOST('note_private', 'restricthtml');
163 $payment->note_public = GETPOST('note_public', 'restricthtml');
164
165 if (!$error) {
166 $paymentid = $payment->create($user);
167 if ($paymentid < 0) {
168 setEventMessages($payment->error, $payment->errors, 'errors');
169 $error++;
170 }
171 }
172
173 if (!$error) {
174 // @phan-suppress-next-line PhanPluginSuspiciousParamOrder
175 $result = $payment->addPaymentToBank($user, $chid, 'payment_loan', '(LoanPayment)', $payment->fk_bank, '', '');
176 if (!($result > 0)) {
177 setEventMessages($payment->error, $payment->errors, 'errors');
178 $error++;
179 }
180 }
181
182 // Update loan schedule with payment value
183 if (!$error && !empty($line)) {
184 // If payment values are modified, recalculate schedule
185 if (($line->amount_capital != $pay_amount_capital) || ($line->amount_insurance != $pay_amount_insurance) || ($line->amount_interest != $pay_amount_interest)) {
186 $arr_term = loanCalcMonthlyPayment(($pay_amount_capital + $pay_amount_interest), $remaindertopay, ($loan->rate / 100), $echance, (int) $loan->nbterm);
187 foreach ($arr_term as $k => $v) {
188 // Update fk_bank for current line
189 if ($k == $echance) {
190 $ls->lines[$k - 1]->fk_bank = $payment->fk_bank;
191 $ls->lines[$k - 1]->fk_payment_loan = $payment->id;
192 }
193 $ls->lines[$k - 1]->amount_capital = $v['mens'] - $v['interet'];
194 $ls->lines[$k - 1]->amount_interest = $v['interet'];
195 $ls->lines[$k - 1]->tms = dol_now();
196 $ls->lines[$k - 1]->fk_user_modif = $user->id;
197 $result = $ls->lines[$k - 1]->update($user, 0);
198 if ($result < 1) {
199 setEventMessages(null, $ls->errors, 'errors');
200 $error++;
201 break;
202 }
203 }
204 } else { // Only add fk_bank bank to schedule line (mark as paid)
205 $line->fk_bank = $payment->fk_bank;
206 $line->fk_payment_loan = $payment->id;
207 $result = $line->update($user, 0);
208 if ($result < 1) {
209 setEventMessages(null, $line->errors, 'errors');
210 $error++;
211 }
212 }
213 }
214
215 if (!$error) {
216 $db->commit();
217 $loc = DOL_URL_ROOT.'/loan/card.php?id='.$chid;
218 header('Location: '.$loc);
219 exit;
220 } else {
221 $db->rollback();
222 }
223 }
224 }
225
226 $action = 'create';
227}
228
229
230/*
231 * View
232 */
233$form = new Form($db);
234
235$title = $langs->trans('Loans');
236$help_url = "EN:Module_Loan|FR:Module_Emprunt";
237
238llxHeader('', $title, $help_url, '', 0, 0, '', '', '', 'bodyforlist mod-loan page-payment-list');
239
240
241// Form to create loan's payment
242if ($action == 'create') {
243 $total = $loan->capital;
244
245 print load_fiche_titre($langs->trans("DoPayment"));
246
247 $sql = "SELECT SUM(amount_capital) as total";
248 $sql .= " FROM ".MAIN_DB_PREFIX."payment_loan";
249 $sql .= " WHERE fk_loan = ".((int) $chid);
250 $resql = $db->query($sql);
251 if ($resql) {
252 $obj = $db->fetch_object($resql);
253 $sumpaid = $obj->total;
254 $db->free($resql);
255 }
256
257 print '<form name="add_payment" action="'.$_SERVER['PHP_SELF'].'" method="post">';
258 print '<input type="hidden" name="token" value="'.newToken().'">';
259 print '<input type="hidden" name="id" value="'.$chid.'">';
260 print '<input type="hidden" name="chid" value="'.$chid.'">';
261 print '<input type="hidden" name="line_id" value="'.$line_id.'">';
262 print '<input type="hidden" name="remaindertopay" value="'.($total - $sumpaid).'">';
263 print '<input type="hidden" name="action" value="add_payment">';
264
265 print dol_get_fiche_head();
266
267 /*
268 print '<table class="border centpercent">';
269
270 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>';
271 if ($echance > 0)
272 {
273 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";
274 }
275 print '<tr><td>'.$langs->trans("DateStart").'</td><td colspan="2">'.dol_print_date($loan->datestart, 'day')."</td></tr>\n";
276 print '<tr><td>'.$langs->trans("Label").'</td><td colspan="2">'.$loan->label."</td></tr>\n";
277 print '<tr><td>'.$langs->trans("Amount").'</td><td colspan="2">'.price($loan->capital, 0, $outputlangs, 1, -1, -1, $conf->currency).'</td></tr>';
278
279 print '<tr><td>'.$langs->trans("AlreadyPaid").'</td><td colspan="2">'.price($sumpaid, 0, $outputlangs, 1, -1, -1, $conf->currency).'</td></tr>';
280 print '<tr><td class="tdtop">'.$langs->trans("RemainderToPay").'</td><td colspan="2">'.price($total - $sumpaid, 0, $outputlangs, 1, -1, -1, $conf->currency).'</td></tr>';
281 print '</tr>';
282
283 print '</table>';
284 */
285
286 print '<table class="border centpercent">';
287
288 print '<tr><td class="titlefield fieldrequired">'.$langs->trans("Date").'</td><td colspan="2">';
289 if (empty($datepaid)) {
290 if (empty($ts_temppaid)) {
291 $datepayment = !getDolGlobalString('MAIN_AUTOFILL_DATE') ? -1 : dol_now();
292 } else {
293 $datepayment = $ts_temppaid;
294 }
295 } else {
296 $datepayment = $datepaid;
297 }
298 print $form->selectDate($datepayment, '', 0, 0, 0, "add_payment", 1, 1);
299 print "</td>";
300 print '</tr>';
301
302 print '<tr><td class="fieldrequired">'.$langs->trans("PaymentMode").'</td><td colspan="2">';
303 print img_picto('', 'money-bill-alt', 'class="pictofixedwidth"');
304 $form->select_types_paiements(GETPOSTISSET("paymenttype") ? GETPOST("paymenttype", 'alphanohtml') : $loan->fk_typepayment, "paymenttype");
305 print "</td>\n";
306 print '</tr>';
307
308 print '<tr>';
309 print '<td class="fieldrequired">'.$langs->trans('AccountToDebit').'</td>';
310 print '<td colspan="2">';
311 print img_picto('', 'bank_account', 'class="pictofixedwidth"');
312 $form->select_comptes(GETPOSTISSET("accountid") ? GETPOSTINT("accountid") : $loan->accountid, "accountid", 0, 'courant = '.Account::TYPE_CURRENT, 1); // Show opend bank account list
313 print '</td></tr>';
314
315 // Number
316 print '<tr><td>'.$langs->trans('Numero');
317 print ' <em>('.$langs->trans("ChequeOrTransferNumber").')</em>';
318 print '</td>';
319 print '<td colspan="2"><input name="num_payment" type="text" value="'.GETPOST('num_payment', 'alphanohtml').'"></td>'."\n";
320 print "</tr>";
321
322 print '<tr>';
323 print '<td class="tdtop">'.$langs->trans("NotePrivate").'</td>';
324 print '<td valign="top" colspan="2"><textarea name="note_private" wrap="soft" cols="60" rows="'.ROWS_3.'"></textarea></td>';
325 print '</tr>';
326
327 print '<tr>';
328 print '<td class="tdtop">'.$langs->trans("NotePublic").'</td>';
329 print '<td valign="top" colspan="2"><textarea name="note_public" wrap="soft" cols="60" rows="'.ROWS_3.'"></textarea></td>';
330 print '</tr>';
331
332 print '</table>';
333
334 print dol_get_fiche_end();
335
336
337 print '<table class="noborder centpercent">';
338 print '<tr class="liste_titre">';
339 print '<td class="left">'.$langs->trans("DateDue").'</td>';
340 print '<td class="right">'.$langs->trans("LoanCapital").'</td>';
341 print '<td class="right">'.$langs->trans("AlreadyPaid").'</td>';
342 print '<td class="right">'.$langs->trans("RemainderToPay").'</td>';
343 print '<td class="right">'.$langs->trans("Amount").'</td>';
344 print "</tr>\n";
345
346 print '<tr class="oddeven">';
347
348 if ($loan->datestart > 0) {
349 print '<td class="left" valign="center">'.dol_print_date($loan->datestart, 'day').'</td>';
350 } else {
351 print '<td class="center" valign="center"><b>!!!</b></td>';
352 }
353
354 print '<td class="right" valign="center">'.price($loan->capital)."</td>";
355
356 print '<td class="right" valign="center">'.price($sumpaid)."</td>";
357
358 print '<td class="right" valign="center">'.price($loan->capital - $sumpaid)."</td>";
359
360 print '<td class="right">';
361 if ($sumpaid < $loan->capital) {
362 print $langs->trans("LoanCapital").': <input type="text" size="8" name="amount_capital" value="'.(GETPOSTISSET('amount_capital') ? GETPOST('amount_capital') : $amount_capital).'">';
363 } else {
364 print '-';
365 }
366 print '<br>';
367 if ($sumpaid < $loan->capital) {
368 print $langs->trans("Insurance").': <input type="text" size="8" name="amount_insurance" value="'.(GETPOSTISSET('amount_insurance') ? GETPOST('amount_insurance') : $amount_insurance).'">';
369 } else {
370 print '-';
371 }
372 print '<br>';
373 if ($sumpaid < $loan->capital) {
374 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').'"' : '').'>';
375 } else {
376 print '-';
377 }
378 print "</td>";
379
380 print "</tr>\n";
381
382 print '</table>';
383
384 print $form->buttonsSaveCancel();
385
386 print "</form>\n";
387}
388
389llxFooter();
390$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:70
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.