dolibarr 20.0.0
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 = GETPOSTINT('id');
37$action = GETPOST('action', 'aZ09');
38$cancel = GETPOST('cancel', 'alpha');
39$datepaid = dol_mktime(12, 0, 0, GETPOSTINT('remonth'), GETPOSTINT('reday'), GETPOSTINT('reyear'));
40
41// Security check
42$socid = 0;
43if ($user->socid > 0) {
44 $socid = $user->socid;
45} elseif (GETPOSTISSET('socid')) {
46 $socid = GETPOSTINT('socid');
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 schedule 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 (!GETPOSTINT('paymenttype') > 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("bank") && !GETPOSTINT('accountid') > 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 already 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 = GETPOSTINT('accountid');
156 $payment->paymenttype = GETPOSTINT('paymenttype');
157 $payment->num_payment = GETPOST('num_payment', 'alphanohtml');
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 // @phan-suppress-next-line PhanPluginSuspiciousParamOrder
171 $result = $payment->addPaymentToBank($user, $chid, 'payment_loan', '(LoanPayment)', $payment->fk_bank, '', '');
172 if (!($result > 0)) {
173 setEventMessages($payment->error, $payment->errors, 'errors');
174 $error++;
175 }
176 }
177
178 // Update loan schedule with payment value
179 if (!$error && !empty($line)) {
180 // If payment values are modified, recalculate schedule
181 if (($line->amount_capital != $pay_amount_capital) || ($line->amount_insurance != $pay_amount_insurance) || ($line->amount_interest != $pay_amount_interest)) {
182 $arr_term = loanCalcMonthlyPayment(($pay_amount_capital + $pay_amount_interest), $remaindertopay, ($loan->rate / 100), $echance, $loan->nbterm);
183 foreach ($arr_term as $k => $v) {
184 // Update fk_bank for current line
185 if ($k == $echance) {
186 $ls->lines[$k - 1]->fk_bank = $payment->fk_bank;
187 $ls->lines[$k - 1]->fk_payment_loan = $payment->id;
188 }
189 $ls->lines[$k - 1]->amount_capital = $v['mens'] - $v['interet'];
190 $ls->lines[$k - 1]->amount_interest = $v['interet'];
191 $ls->lines[$k - 1]->tms = dol_now();
192 $ls->lines[$k - 1]->fk_user_modif = $user->id;
193 $result = $ls->lines[$k - 1]->update($user, 0);
194 if ($result < 1) {
195 setEventMessages(null, $ls->errors, 'errors');
196 $error++;
197 break;
198 }
199 }
200 } else { // Only add fk_bank bank to schedule line (mark as paid)
201 $line->fk_bank = $payment->fk_bank;
202 $line->fk_payment_loan = $payment->id;
203 $result = $line->update($user, 0);
204 if ($result < 1) {
205 setEventMessages(null, $line->errors, 'errors');
206 $error++;
207 }
208 }
209 }
210
211 if (!$error) {
212 $db->commit();
213 $loc = DOL_URL_ROOT.'/loan/card.php?id='.$chid;
214 header('Location: '.$loc);
215 exit;
216 } else {
217 $db->rollback();
218 }
219 }
220 }
221
222 $action = 'create';
223}
224
225
226/*
227 * View
228 */
229
230llxHeader();
231
232$form = new Form($db);
233
234
235// Form to create loan's payment
236if ($action == 'create') {
237 $total = $loan->capital;
238
239 print load_fiche_titre($langs->trans("DoPayment"));
240
241 $sql = "SELECT SUM(amount_capital) as total";
242 $sql .= " FROM ".MAIN_DB_PREFIX."payment_loan";
243 $sql .= " WHERE fk_loan = ".((int) $chid);
244 $resql = $db->query($sql);
245 if ($resql) {
246 $obj = $db->fetch_object($resql);
247 $sumpaid = $obj->total;
248 $db->free($resql);
249 }
250
251 print '<form name="add_payment" action="'.$_SERVER['PHP_SELF'].'" method="post">';
252 print '<input type="hidden" name="token" value="'.newToken().'">';
253 print '<input type="hidden" name="id" value="'.$chid.'">';
254 print '<input type="hidden" name="chid" value="'.$chid.'">';
255 print '<input type="hidden" name="line_id" value="'.$line_id.'">';
256 print '<input type="hidden" name="remaindertopay" value="'.($total - $sumpaid).'">';
257 print '<input type="hidden" name="action" value="add_payment">';
258
259 print dol_get_fiche_head();
260
261 /*
262 print '<table class="border centpercent">';
263
264 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>';
265 if ($echance > 0)
266 {
267 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";
268 }
269 print '<tr><td>'.$langs->trans("DateStart").'</td><td colspan="2">'.dol_print_date($loan->datestart, 'day')."</td></tr>\n";
270 print '<tr><td>'.$langs->trans("Label").'</td><td colspan="2">'.$loan->label."</td></tr>\n";
271 print '<tr><td>'.$langs->trans("Amount").'</td><td colspan="2">'.price($loan->capital, 0, $outputlangs, 1, -1, -1, $conf->currency).'</td></tr>';
272
273 print '<tr><td>'.$langs->trans("AlreadyPaid").'</td><td colspan="2">'.price($sumpaid, 0, $outputlangs, 1, -1, -1, $conf->currency).'</td></tr>';
274 print '<tr><td class="tdtop">'.$langs->trans("RemainderToPay").'</td><td colspan="2">'.price($total - $sumpaid, 0, $outputlangs, 1, -1, -1, $conf->currency).'</td></tr>';
275 print '</tr>';
276
277 print '</table>';
278 */
279
280 print '<table class="border centpercent">';
281
282 print '<tr><td class="titlefield fieldrequired">'.$langs->trans("Date").'</td><td colspan="2">';
283 if (empty($datepaid)) {
284 if (empty($ts_temppaid)) {
285 $datepayment = !getDolGlobalString('MAIN_AUTOFILL_DATE') ? -1 : dol_now();
286 } else {
287 $datepayment = $ts_temppaid;
288 }
289 } else {
290 $datepayment = $datepaid;
291 }
292 print $form->selectDate($datepayment, '', 0, 0, 0, "add_payment", 1, 1);
293 print "</td>";
294 print '</tr>';
295
296 print '<tr><td class="fieldrequired">'.$langs->trans("PaymentMode").'</td><td colspan="2">';
297 print img_picto('', 'money-bill-alt', 'class="pictofixedwidth"');
298 $form->select_types_paiements(GETPOSTISSET("paymenttype") ? GETPOST("paymenttype", 'alphanohtml') : $loan->fk_typepayment, "paymenttype");
299 print "</td>\n";
300 print '</tr>';
301
302 print '<tr>';
303 print '<td class="fieldrequired">'.$langs->trans('AccountToDebit').'</td>';
304 print '<td colspan="2">';
305 print img_picto('', 'bank_account', 'class="pictofixedwidth"');
306 $form->select_comptes(GETPOSTISSET("accountid") ? GETPOSTINT("accountid") : $loan->accountid, "accountid", 0, 'courant = '.Account::TYPE_CURRENT, 1); // Show opend bank account list
307 print '</td></tr>';
308
309 // Number
310 print '<tr><td>'.$langs->trans('Numero');
311 print ' <em>('.$langs->trans("ChequeOrTransferNumber").')</em>';
312 print '</td>';
313 print '<td colspan="2"><input name="num_payment" type="text" value="'.GETPOST('num_payment', 'alphanohtml').'"></td>'."\n";
314 print "</tr>";
315
316 print '<tr>';
317 print '<td class="tdtop">'.$langs->trans("NotePrivate").'</td>';
318 print '<td valign="top" colspan="2"><textarea name="note_private" wrap="soft" cols="60" rows="'.ROWS_3.'"></textarea></td>';
319 print '</tr>';
320
321 print '<tr>';
322 print '<td class="tdtop">'.$langs->trans("NotePublic").'</td>';
323 print '<td valign="top" colspan="2"><textarea name="note_public" wrap="soft" cols="60" rows="'.ROWS_3.'"></textarea></td>';
324 print '</tr>';
325
326 print '</table>';
327
328 print dol_get_fiche_end();
329
330
331 print '<table class="noborder centpercent">';
332 print '<tr class="liste_titre">';
333 print '<td class="left">'.$langs->trans("DateDue").'</td>';
334 print '<td class="right">'.$langs->trans("LoanCapital").'</td>';
335 print '<td class="right">'.$langs->trans("AlreadyPaid").'</td>';
336 print '<td class="right">'.$langs->trans("RemainderToPay").'</td>';
337 print '<td class="right">'.$langs->trans("Amount").'</td>';
338 print "</tr>\n";
339
340 print '<tr class="oddeven">';
341
342 if ($loan->datestart > 0) {
343 print '<td class="left" valign="center">'.dol_print_date($loan->datestart, 'day').'</td>';
344 } else {
345 print '<td class="center" valign="center"><b>!!!</b></td>';
346 }
347
348 print '<td class="right" valign="center">'.price($loan->capital)."</td>";
349
350 print '<td class="right" valign="center">'.price($sumpaid)."</td>";
351
352 print '<td class="right" valign="center">'.price($loan->capital - $sumpaid)."</td>";
353
354 print '<td class="right">';
355 if ($sumpaid < $loan->capital) {
356 print $langs->trans("LoanCapital").': <input type="text" size="8" name="amount_capital" value="'.(GETPOSTISSET('amount_capital') ? GETPOST('amount_capital') : $amount_capital).'">';
357 } else {
358 print '-';
359 }
360 print '<br>';
361 if ($sumpaid < $loan->capital) {
362 print $langs->trans("Insurance").': <input type="text" size="8" name="amount_insurance" value="'.(GETPOSTISSET('amount_insurance') ? GETPOST('amount_insurance') : $amount_insurance).'">';
363 } else {
364 print '-';
365 }
366 print '<br>';
367 if ($sumpaid < $loan->capital) {
368 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').'"' : '').'>';
369 } else {
370 print '-';
371 }
372 print "</td>";
373
374 print "</tr>\n";
375
376 print '</table>';
377
378 print $form->buttonsSaveCancel();
379
380 print "</form>\n";
381}
382
383llxFooter();
384$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 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.
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.
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.