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