dolibarr 23.0.3
schedule.php
Go to the documentation of this file.
1<?php
2/* Copyright (C) 2017 Franck Moreau <franck.moreau@theobald.com>
3 * Copyright (C) 2018-2024 Alexandre Spangaro <alexandre@inovea-conseil.com>
4 * Copyright (C) 2020 Maxime DEMAREST <maxime@indelog.fr>
5 * Copyright (C) 2024-2025 MDW <mdeweerd@users.noreply.github.com>
6 * Copyright (C) 2024-2025 Frédéric France <frederic.france@free.fr>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 3 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program. If not, see <https://www.gnu.org/licenses/>.
20 */
21
28// Load Dolibarr environment
29require '../main.inc.php';
30require_once DOL_DOCUMENT_ROOT.'/loan/class/loan.class.php';
31require_once DOL_DOCUMENT_ROOT.'/core/lib/loan.lib.php';
32require_once DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php';
33require_once DOL_DOCUMENT_ROOT.'/loan/class/loanschedule.class.php';
34require_once DOL_DOCUMENT_ROOT.'/loan/class/paymentloan.class.php';
35require_once DOL_DOCUMENT_ROOT.'/core/class/html.formprojet.class.php';
36if (isModEnabled('project')) {
37 require_once DOL_DOCUMENT_ROOT.'/projet/class/project.class.php';
38}
39
48$loanid = GETPOSTINT('loanid');
49$action = GETPOST('action', 'aZ09');
50
51// Security check
52$socid = 0;
53if (GETPOSTISSET('socid')) {
54 $socid = GETPOSTINT('socid');
55}
56if ($user->socid) {
57 $socid = $user->socid;
58}
59if (!$user->hasRight('loan', 'calc')) {
61}
62
63// Load translation files required by the page
64$langs->loadLangs(array("compta", "bills", "loan"));
65
66$object = new Loan($db);
67$object->fetch($loanid);
68
69$echeances = new LoanSchedule($db);
70$echeances->fetchAll($object->id);
71
72if ($object->paid > 0 && count($echeances->lines) == 0) {
73 $pay_without_schedule = 1;
74} else {
75 $pay_without_schedule = 0;
76}
77
78$permissiontoadd = $user->hasRight('loan', 'write');
79
80
81/*
82 * Actions
83 */
84
85if ($action == 'createecheancier' && empty($pay_without_schedule) && $permissiontoadd) {
86 $db->begin();
87 $i = 1;
88 while ($i < $object->nbterm + 1) {
89 $date = GETPOSTINT('hi_date'.$i);
90 $mens = price2num(GETPOST('mens'.$i));
91 $int = price2num(GETPOST('hi_interets'.$i));
92 $insurance = price2num(GETPOST('hi_insurance'.$i));
93
94 $new_echeance = new LoanSchedule($db);
95
96 $new_echeance->fk_loan = $object->id;
97 $new_echeance->datec = dol_now();
98 $new_echeance->tms = dol_now();
99 $new_echeance->datep = $date;
100 $new_echeance->amount_capital = (float) $mens - (float) $int;
101 $new_echeance->amount_insurance = $insurance;
102 $new_echeance->amount_interest = $int;
103 $new_echeance->fk_typepayment = 3;
104 $new_echeance->fk_bank = 0;
105 $new_echeance->fk_user_creat = $user->id;
106 $new_echeance->fk_user_modif = $user->id;
107 $result = $new_echeance->create($user);
108 if ($result < 0) {
109 setEventMessages($new_echeance->error, $new_echeance->errors, 'errors');
110 $db->rollback();
111 $echeances->lines = [];
112 break;
113 }
114 $echeances->lines[] = $new_echeance;
115 $i++;
116 }
117 if ($result > 0) {
118 $db->commit();
119 }
120}
121
122if ($action == 'updateecheancier' && empty($pay_without_schedule) && $permissiontoadd) {
123 $db->begin();
124 $i = 1;
125 while ($i < $object->nbterm + 1) {
126 $mens = price2num(GETPOST('mens'.$i));
127 $int = price2num(GETPOST('hi_interets'.$i));
128 $id = GETPOSTINT('hi_rowid'.$i);
129 $insurance = price2num(GETPOST('hi_insurance'.$i));
130
131 $new_echeance = new LoanSchedule($db);
132 $new_echeance->fetch($id);
133 $new_echeance->tms = dol_now();
134 $new_echeance->amount_capital = (float) $mens - (float) $int;
135 $new_echeance->amount_insurance = $insurance;
136 $new_echeance->amount_interest = $int;
137 $new_echeance->fk_user_modif = $user->id;
138 $result = $new_echeance->update($user, 0);
139 if ($result < 0) {
140 setEventMessages(null, $new_echeance->errors, 'errors');
141 $db->rollback();
142 $echeances->fetchAll($object->id);
143 break;
144 }
145
146 $echeances->lines[$i - 1] = $new_echeance;
147 $i++;
148 }
149 if ($result > 0) {
150 $db->commit();
151 }
152}
153
154
155/*
156 * View
157 */
158
159$form = new Form($db);
160$formproject = new FormProjets($db);
161
162$title = $langs->trans("Loan").' - '.$langs->trans("FinancialCommitment");
163$help_url = 'EN:Module_Loan|FR:Module_Emprunt';
164
165llxHeader("", $title, $help_url, '', 0, 0, '', '', '', 'mod-loan page-card_schedule');
166
167$head = loan_prepare_head($object);
168print dol_get_fiche_head($head, 'FinancialCommitment', $langs->trans("Loan"), -1, 'money-bill-alt');
169
170$linkback = '<a href="'.DOL_URL_ROOT.'/loan/list.php?restore_lastsearch_values=1">'.$langs->trans("BackToList").'</a>';
171
172$morehtmlref = '<div class="refidno">';
173// Ref loan
174$morehtmlref .= $form->editfieldkey("Label", 'label', $object->label, $object, 0, 'string', '', 0, 1);
175$morehtmlref .= $form->editfieldval("Label", 'label', $object->label, $object, 0, 'string', '', null, null, '', 1);
176// Project
177if (isModEnabled('project')) {
178 $langs->loadLangs(array("projects"));
179 $morehtmlref .= '<br>'.$langs->trans('Project').' : ';
180 if ($user->hasRight('loan', 'write')) {
181 if ($action != 'classify') {
182 //$morehtmlref .= '<a class="editfielda" href="'.dolBuildUrl($_SERVER['PHP_SELF'], ['action' => 'classify', 'id' => $object->id], true).'">'.img_edit($langs->transnoentitiesnoconv('SetProject')).'</a> : ';
183 if ($action == 'classify') {
184 //$morehtmlref.=$form->form_project($_SERVER['PHP_SELF'] . '?id=' . $object->id, $object->socid, $object->fk_project, 'projectid', 0, 0, 1, 1);
185 $morehtmlref .= '<form method="post" action="'.$_SERVER['PHP_SELF'].'?id='.$object->id.'">';
186 $morehtmlref .= '<input type="hidden" name="action" value="classin">';
187 $morehtmlref .= '<input type="hidden" name="token" value="'.newToken().'">';
188 $morehtmlref .= $formproject->select_projects(-1, (string) $object->fk_project, 'projectid', 16, 0, 1, 0, 1, 0, 0, '', 1);
189 $morehtmlref .= '<input type="submit" class="button valignmiddle" value="'.$langs->trans("Modify").'">';
190 $morehtmlref .= '</form>';
191 } else {
192 $morehtmlref .= $form->form_project($_SERVER['PHP_SELF'].'?id='.$object->id, -1, (string) $object->fk_project, 'none', 0, 0, 0, 1, '', 'maxwidth300');
193 }
194 }
195 } else {
196 if (!empty($object->fk_project)) {
197 $proj = new Project($db);
198 $proj->fetch($object->fk_project);
199 $morehtmlref .= ' : '.$proj->getNomUrl(1);
200 if ($proj->title) {
201 $morehtmlref .= ' - '.$proj->title;
202 }
203 } else {
204 $morehtmlref .= '';
205 }
206 }
207}
208$morehtmlref .= '</div>';
209
210$morehtmlstatus = '';
211
212dol_banner_tab($object, 'loanid', $linkback, 1, 'rowid', 'ref', $morehtmlref, '', 0, '', $morehtmlstatus);
213
214?>
215<script type="text/javascript">
216$(document).ready(function() {
217 var timeout = null;
218 var delay = 750; // 0.75 seconds
219 $('[name^="mens"]').keyup(function() {
220 clearTimeout(timeout);
221 timeout = setTimeout(() => {
222 var echeance = $(this).attr('ech');
223 var mens = $(this).val();
224 calculateMens(echeance, mens);
225 }, delay);
226 });
227 function calculateMens(echeance, mens) {
228 var table = $('[name^="mens"]');
229 var idcap = echeance-1;
230 idcap = '#hi_capital'+idcap;
231 var capital = price2numjs($(idcap).val());
232 console.log("Change monthly amount echeance="+echeance+" idcap="+idcap+" capital="+capital);
233 $.ajax({
234 method: "GET",
235 dataType: 'json',
236 url: 'calcmens.php',
237 data: {
238 echeance: echeance,
239 mens: price2numjs(mens),
240 capital: capital,
241 rate: <?php echo $object->rate / 100; ?>,
242 nbterm: <?php echo $object->nbterm; ?>,
243 token: '<?php echo currentToken(); ?>'
244 },
245 success: function(data) {
246 $.each(data, function(index, element) {
247 $('#hi_capital'+index).val(element.cap_rest);
248 $('#capital'+index).text(element.cap_rest_str);
249 $('#hi_interets'+index).val(element.interet);
250 $('#interets'+index).text(element.interet_str);
251 $('#mens'+index).val(element.mens);
252 });
253 }
254 });
255 }
256});
257</script>
258<?php
259
260if ($pay_without_schedule == 1) {
261 print '<div class="warning">'.$langs->trans('CantUseScheduleWithLoanStartedToPaid').'</div>'."\n";
262}
263
264print '<form name="createecheancier" action="'.$_SERVER["PHP_SELF"].'" method="POST">';
265print '<input type="hidden" name="token" value="'.newToken().'">';
266print '<input type="hidden" name="loanid" value="'.$loanid.'">';
267if (count($echeances->lines) > 0) {
268 print '<input type="hidden" name="action" value="updateecheancier">';
269} else {
270 print '<input type="hidden" name="action" value="createecheancier">';
271}
272
273print '<br>';
274
275print '<div class="div-table-responsive-no-min">';
276print '<table class="border centpercent">';
277
278$colspan = 6;
279if (count($echeances->lines) > 0) {
280 $colspan++;
281}
282
283print '<tr class="liste_titre">';
284print '<th class="center">'.$langs->trans("Term").'</th>';
285print '<th class="center">'.$langs->trans("Date").'</th>';
286print '<th class="center">'.$langs->trans("Insurance");
287print '<th class="center">'.$langs->trans("InterestAmount").'</th>';
288print '<th class="center">'.$langs->trans("Amount").'</th>';
289print '<th class="center">'.$langs->trans("CapitalRemain");
290print '<br>('.price($object->capital, 0, '', 1, -1, -1, $conf->currency).')';
291print '<input type="hidden" name="hi_capital0" id ="hi_capital0" value="'.$object->capital.'">';
292print '</th>';
293if (count($echeances->lines) > 0) {
294 print '<th class="center">'.$langs->trans('DoPayment').'</th>';
295}
296print '</tr>'."\n";
297
298if ($object->nbterm > 0 && count($echeances->lines) == 0) {
299 $i = 1;
300 $capital = $object->capital;
301 $insurance = (float) $object->insurance_amount / $object->nbterm;
302 $insurance = price2num($insurance, 'MT');
303 $regulInsurance = price2num((float) $object->insurance_amount - ((float) $insurance * $object->nbterm));
304 while ($i < $object->nbterm + 1) {
305 $mens = price2num($echeances->calcMonthlyPayments($capital, $object->rate / 100, $object->nbterm - $i + 1), 'MT');
306 $int = ($capital * ($object->rate / 12)) / 100;
307 $int = price2num($int, 'MT');
308 $insu = ((float) $insurance + (($i == 1) ? (float) $regulInsurance : 0));
309 $cap_rest = price2num((float) $capital - ((float) $mens - (float) $int), 'MT');
310 print '<tr>';
311 print '<td class="center" id="n'.$i.'">'.$i.'</td>';
312 print '<td class="center" id ="date'.$i.'"><input type="hidden" name="hi_date'.$i.'" id ="hi_date'.$i.'" value="'.dol_time_plus_duree($object->datestart, $i - 1, 'm').'">'.dol_print_date(dol_time_plus_duree($object->datestart, $i - 1, 'm'), 'day').'</td>';
313 print '<td class="center amount" id="insurance'.$i.'">'.price($insu, 0, '', 1, -1, -1, $conf->currency).'</td><input type="hidden" name="hi_insurance'.$i.'" id ="hi_insurance'.$i.'" value="'.$insu.'">';
314 print '<td class="center amount" id="interets'.$i.'">'.price($int, 0, '', 1, -1, -1, $conf->currency).'</td><input type="hidden" name="hi_interets'.$i.'" id ="hi_interets'.$i.'" value="'.$int.'">';
315 print '<td class="center"><input class="width75 right" name="mens'.$i.'" id="mens'.$i.'" value="'.price($mens).'" ech="'.$i.'"></td>';
316 print '<td class="center amount" id="capital'.$i.'">'.price($cap_rest).'</td><input type="hidden" name="hi_capital'.$i.'" id ="hi_capital'.$i.'" value="'.$cap_rest.'">';
317 print '</tr>'."\n";
318 $i++;
319 $capital = $cap_rest;
320 }
321} elseif (count($echeances->lines) > 0) {
322 $i = 1;
323 $capital = $object->capital;
324 $insurance = (float) $object->insurance_amount / $object->nbterm;
325 $insurance = price2num($insurance, 'MT');
326 $regulInsurance = price2num((float) $object->insurance_amount - ((float) $insurance * $object->nbterm));
327 $printed = false;
328 foreach ($echeances->lines as $line) {
329 $mens = $line->amount_capital + $line->amount_interest;
330 $int = $line->amount_interest;
331 $insu = ((float) $insurance + (($i == 1) ? (float) $regulInsurance : 0));
332 $cap_rest = price2num($capital - ($mens - $int), 'MT');
333
334 print '<tr>';
335 print '<td class="center" id="n'.$i.'"><input type="hidden" name="hi_rowid'.$i.'" id ="hi_rowid'.$i.'" value="'.$line->id.'">'.$i.'</td>';
336 print '<td class="center" id ="date'.$i.'"><input type="hidden" name="hi_date'.$i.'" id ="hi_date'.$i.'" value="'.$line->datep.'">'.dol_print_date($line->datep, 'day').'</td>';
337 print '<td class="center amount" id="insurance'.$i.'">'.price($insu, 0, '', 1, -1, -1, $conf->currency).'</td><input type="hidden" name="hi_insurance'.$i.'" id ="hi_insurance'.$i.'" value="'.$insu.'">';
338 print '<td class="center amount" id="interets'.$i.'">'.price($int, 0, '', 1, -1, -1, $conf->currency).'</td><input type="hidden" name="hi_interets'.$i.'" id ="hi_interets'.$i.'" value="'.$int.'">';
339 if (empty($line->fk_bank)) {
340 print '<td class="center"><input class="right width75" name="mens'.$i.'" id="mens'.$i.'" value="'.price($mens).'" ech="'.$i.'"></td>';
341 } else {
342 print '<td class="center amount">'.price($mens, 0, '', 1, -1, -1, $conf->currency).'</td><input type="hidden" name="mens'.$i.'" id ="mens'.$i.'" value="'.$mens.'">';
343 }
344
345 print '<td class="center amount" id="capital'.$i.'">'.price($cap_rest, 0, '', 1, -1, -1, $conf->currency).'</td><input type="hidden" name="hi_capital'.$i.'" id ="hi_capital'.$i.'" value="'.$cap_rest.'">';
346 print '<td class="center">';
347 if (!empty($line->fk_bank)) {
348 print $langs->trans('Paid');
349 if (!empty($line->fk_payment_loan)) {
350 print '&nbsp;<a href="'.DOL_URL_ROOT.'/loan/payment/card.php?id='.$line->fk_payment_loan.'">('.img_object($langs->trans("Payment"), "payment").' '.$line->fk_payment_loan.')</a>';
351 }
352 } elseif (!$printed) {
353 print '<a class="butAction smallpaddingimp" href="'.DOL_URL_ROOT.'/loan/payment/payment.php?id='.$object->id.'&action=create">'.$langs->trans('DoPayment').'</a>';
354 $printed = true;
355 }
356 print '</td>';
357 print '</tr>'."\n";
358 $i++;
359 $capital = $cap_rest;
360 }
361}
362
363print '</table>';
364print '</div>';
365
366print '</br>';
367
368if (count($echeances->lines) == 0) {
369 $label = $langs->trans("Create");
370} else {
371 $label = $langs->trans("Save");
372}
373print '<div class="center"><input type="submit" class="button button-add" value="'.$label.'" '.(($pay_without_schedule == 1) ? 'disabled title="'.$langs->trans('CantUseScheduleWithLoanStartedToPaid').'"' : '').'title=""></div>';
374print '</form>';
375
376// End of page
377llxFooter();
378$db->close();
$id
Support class for third parties, contacts, members, users or resources.
Definition account.php:47
if(! $sortfield) if(! $sortorder) $object
Definition account.php:100
llxFooter($comment='', $zone='private', $disabledoutputofmessages=0)
Empty footer.
Definition wrapper.php:91
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:73
Class to manage generation of HTML components Only common components must be here.
Class to manage building of HTML components.
Loan.
Class to manage Schedule of loans.
Class to manage projects.
price2numjs(amount)
Function similar to PHP price2num()
dol_time_plus_duree($time, $duration_value, $duration_unit, $ruleforendofmonth=0)
Add a delay to a date.
Definition date.lib.php:125
dol_now($mode='gmt')
Return date for now.
setEventMessages($mesg, $mesgs, $style='mesgs', $messagekey='', $noduplicate=0, $attop=0)
Set event messages in dol_events session object.
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, $morecssdiv='')
Show tabs of a record.
price2num($amount, $rounding='', $option=0)
Function that return a number with universal decimal format (decimal separator is '.
img_object($titlealt, $picto, $moreatt='', $pictoisfullpath=0, $srconly=0, $notitle=0, $allowothertags=array())
Show a picto called object_picto (generic function)
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.
GETPOST($paramname, $check='alphanohtml', $method=0, $filter=null, $options=null, $noreplace=0)
Return value of a param into GET or POST supervariable.
dol_print_date($time, $format='', $tzoutput='auto', $outputlangs=null, $encodetooutput=false, $decorate=0)
Output date in a string format according to outputlangs (or langs if not defined).
isModEnabled($module)
Is Dolibarr module enabled.
treeview li table
No Email.
loan_prepare_head($object)
Prepare array with list of tabs.
Definition loan.lib.php:34
if(preg_match('/(crypted|dolcrypt):/i', $dolibarr_main_db_pass)||!empty($dolibarr_main_db_encrypted_pass)) $conf db type
'integer', 'integer:ObjectClass:PathToClass[:AddCreateButtonOrNot[:Filter[:Sortfield]]]',...
Definition repair.php:125
accessforbidden($message='', $printheader=1, $printfooter=1, $showonlymessage=0, $params=null)
Show a message to say access is forbidden and stop program.