dolibarr 21.0.0-beta
loanschedule.class.php
Go to the documentation of this file.
1<?php
2/* Copyright (C) 2017 Florian HENRY <florian.henry@atm-consulting.fr>
3 * Copyright (C) 2018-2024 Frédéric France <frederic.france@free.fr>
4 * Copyright (C) 2024 MDW <mdeweerd@users.noreply.github.com>
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
26require_once DOL_DOCUMENT_ROOT.'/core/class/commonobject.class.php';
27
28
33{
37 public $element = 'loan_schedule';
38
42 public $table_element = 'loan_schedule';
43
47 public $fk_loan;
48
52 public $bank_account;
56 public $bank_line;
57
61 public $datec;
62
66 public $datep;
67
71 public $amounts = array(); // Array of amounts
75 public $amount_capital;
79 public $amount_insurance;
83 public $amount_interest;
84
88 public $fk_typepayment;
89
94 public $num_payment;
95
99 public $fk_bank;
100
104 public $fk_payment_loan;
105
109 public $fk_user_creat;
110
114 public $fk_user_modif;
115
120 public $lines = array();
121
127 public $total;
128
132 public $type_code;
136 public $type_label;
137
138
144 public function __construct($db)
145 {
146 $this->db = $db;
147 }
148
156 public function create($user)
157 {
158 global $conf, $langs;
159
160 $error = 0;
161
162 $now = dol_now();
163
164 // Validate parameters
165 if (!$this->datep) {
166 $this->error = 'ErrorBadValueForParameter';
167 return -1;
168 }
169
170 // Clean parameters
171 if (isset($this->fk_loan)) {
172 $this->fk_loan = (int) $this->fk_loan;
173 }
174 if (isset($this->amount_capital)) {
175 $this->amount_capital = trim($this->amount_capital ? $this->amount_capital : 0);
176 }
177 if (isset($this->amount_insurance)) {
178 $this->amount_insurance = trim($this->amount_insurance ? $this->amount_insurance : 0);
179 }
180 if (isset($this->amount_interest)) {
181 $this->amount_interest = trim($this->amount_interest ? $this->amount_interest : 0);
182 }
183 if (isset($this->fk_typepayment)) {
184 $this->fk_typepayment = (int) $this->fk_typepayment;
185 }
186 if (isset($this->fk_bank)) {
187 $this->fk_bank = (int) $this->fk_bank;
188 }
189 if (isset($this->fk_user_creat)) {
190 $this->fk_user_creat = (int) $this->fk_user_creat;
191 }
192 if (isset($this->fk_user_modif)) {
193 $this->fk_user_modif = (int) $this->fk_user_modif;
194 }
195
196 $totalamount = (float) $this->amount_capital + (float) $this->amount_insurance + (float) $this->amount_interest;
197 $totalamount = price2num($totalamount);
198
199 // Check parameters
200 if ($totalamount == 0) {
201 $this->errors[] = 'Amount must not be "0".';
202 return -1; // Negative amounts are accepted for reject prelevement but not null
203 }
204
205
206 $this->db->begin();
207
208 if ($totalamount != 0) {
209 $sql = "INSERT INTO ".MAIN_DB_PREFIX.$this->table_element." (fk_loan, datec, datep, amount_capital, amount_insurance, amount_interest,";
210 $sql .= " fk_typepayment, fk_user_creat, fk_bank)";
211 $sql .= " VALUES (".$this->fk_loan.", '".$this->db->idate($now)."',";
212 $sql .= " '".$this->db->idate($this->datep)."',";
213 $sql .= " ".price2num($this->amount_capital).",";
214 $sql .= " ".price2num($this->amount_insurance).",";
215 $sql .= " ".price2num($this->amount_interest).",";
216 $sql .= " ".price2num($this->fk_typepayment).", ";
217 $sql .= " ".((int) $user->id).",";
218 $sql .= " ".((int) $this->fk_bank).")";
219
220 dol_syslog(get_class($this)."::create", LOG_DEBUG);
221 $resql = $this->db->query($sql);
222 if ($resql) {
223 $this->id = $this->db->last_insert_id(MAIN_DB_PREFIX."payment_loan");
224 } else {
225 $this->error = $this->db->lasterror();
226 $error++;
227 }
228 }
229
230 if ($totalamount != 0 && !$error) {
231 $this->amount_capital = $totalamount;
232 $this->db->commit();
233 return $this->id;
234 } else {
235 $this->errors[] = $this->db->lasterror();
236 $this->db->rollback();
237 return -1;
238 }
239 }
240
247 public function fetch($id)
248 {
249 global $langs;
250 $sql = "SELECT";
251 $sql .= " t.rowid,";
252 $sql .= " t.fk_loan,";
253 $sql .= " t.datec,";
254 $sql .= " t.tms,";
255 $sql .= " t.datep,";
256 $sql .= " t.amount_capital,";
257 $sql .= " t.amount_insurance,";
258 $sql .= " t.amount_interest,";
259 $sql .= " t.fk_typepayment,";
260 $sql .= " t.num_payment,";
261 $sql .= " t.note_private,";
262 $sql .= " t.note_public,";
263 $sql .= " t.fk_bank,";
264 $sql .= " t.fk_payment_loan,";
265 $sql .= " t.fk_user_creat,";
266 $sql .= " t.fk_user_modif,";
267 $sql .= " pt.code as type_code, pt.libelle as type_label,";
268 $sql .= ' b.fk_account';
269 $sql .= " FROM ".MAIN_DB_PREFIX.$this->table_element." as t";
270 $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."c_paiement as pt ON t.fk_typepayment = pt.id";
271 $sql .= ' LEFT JOIN '.MAIN_DB_PREFIX.'bank as b ON t.fk_bank = b.rowid';
272 $sql .= " WHERE t.rowid = ".((int) $id);
273
274 dol_syslog(get_class($this)."::fetch", LOG_DEBUG);
275 $resql = $this->db->query($sql);
276 if ($resql) {
277 if ($this->db->num_rows($resql)) {
278 $obj = $this->db->fetch_object($resql);
279
280 $this->id = $obj->rowid;
281 $this->ref = $obj->rowid;
282
283 $this->fk_loan = $obj->fk_loan;
284 $this->datec = $this->db->jdate($obj->datec);
285 $this->tms = $this->db->jdate($obj->tms);
286 $this->datep = $this->db->jdate($obj->datep);
287 $this->amount_capital = $obj->amount_capital;
288 $this->amount_insurance = $obj->amount_insurance;
289 $this->amount_interest = $obj->amount_interest;
290 $this->fk_typepayment = $obj->fk_typepayment;
291 $this->num_payment = $obj->num_payment;
292 $this->note_private = $obj->note_private;
293 $this->note_public = $obj->note_public;
294 $this->fk_bank = $obj->fk_bank;
295 $this->fk_payment_loan = $obj->fk_payment_loan;
296 $this->fk_user_creat = $obj->fk_user_creat;
297 $this->fk_user_modif = $obj->fk_user_modif;
298
299 $this->type_code = $obj->type_code;
300 $this->type_label = $obj->type_label;
301
302 $this->bank_account = $obj->fk_account;
303 $this->bank_line = $obj->fk_bank;
304 }
305 $this->db->free($resql);
306
307 return 1;
308 } else {
309 $this->error = "Error ".$this->db->lasterror();
310 return -1;
311 }
312 }
313
314
322 public function update($user = null, $notrigger = 0)
323 {
324 global $conf, $langs;
325 $error = 0;
326
327 // Clean parameters
328 if (isset($this->amount_capital)) {
329 $this->amount_capital = trim($this->amount_capital);
330 }
331 if (isset($this->amount_insurance)) {
332 $this->amount_insurance = trim($this->amount_insurance);
333 }
334 if (isset($this->amount_interest)) {
335 $this->amount_interest = trim($this->amount_interest);
336 }
337 if (isset($this->num_payment)) {
338 $this->num_payment = trim($this->num_payment);
339 }
340 if (isset($this->note_private)) {
341 $this->note_private = trim($this->note_private);
342 }
343 if (isset($this->note_public)) {
344 $this->note_public = trim($this->note_public);
345 }
346 if (isset($this->fk_bank)) {
347 $this->fk_bank = (int) $this->fk_bank;
348 }
349 if (isset($this->fk_payment_loan)) {
350 $this->fk_payment_loan = (int) $this->fk_payment_loan;
351 }
352
353 // Check parameters
354 // Put here code to add control on parameters values
355
356 // Update request
357 $sql = "UPDATE ".MAIN_DB_PREFIX.$this->table_element." SET";
358
359 $sql .= " fk_loan=".(isset($this->fk_loan) ? $this->fk_loan : "null").",";
360 $sql .= " datec=".(dol_strlen($this->datec) != 0 ? "'".$this->db->idate($this->datec)."'" : 'null').",";
361 $sql .= " tms=".(dol_strlen((string) $this->tms) != 0 ? "'".$this->db->idate($this->tms)."'" : 'null').",";
362 $sql .= " datep=".(dol_strlen($this->datep) != 0 ? "'".$this->db->idate($this->datep)."'" : 'null').",";
363 $sql .= " amount_capital=".(isset($this->amount_capital) ? $this->amount_capital : "null").",";
364 $sql .= " amount_insurance=".(isset($this->amount_insurance) ? $this->amount_insurance : "null").",";
365 $sql .= " amount_interest=".(isset($this->amount_interest) ? $this->amount_interest : "null").",";
366 $sql .= " fk_typepayment=".(isset($this->fk_typepayment) ? $this->fk_typepayment : "null").",";
367 $sql .= " num_payment=".(isset($this->num_payment) ? "'".$this->db->escape($this->num_payment)."'" : "null").",";
368 $sql .= " note_private=".(isset($this->note_private) ? "'".$this->db->escape($this->note_private)."'" : "null").",";
369 $sql .= " note_public=".(isset($this->note_public) ? "'".$this->db->escape($this->note_public)."'" : "null").",";
370 $sql .= " fk_bank=".(isset($this->fk_bank) ? ((int) $this->fk_bank) : "null").",";
371 $sql .= " fk_payment_loan=".(isset($this->fk_payment_loan) ? ((int) $this->fk_payment_loan) : "null").",";
372 $sql .= " fk_user_creat=".(isset($this->fk_user_creat) ? ((int) $this->fk_user_creat) : "null").",";
373 $sql .= " fk_user_modif=".(isset($this->fk_user_modif) ? ((int) $this->fk_user_modif) : "null");
374
375 $sql .= " WHERE rowid=".((int) $this->id);
376
377 $this->db->begin();
378
379 dol_syslog(get_class($this)."::update", LOG_DEBUG);
380 $resql = $this->db->query($sql);
381 if (!$resql) {
382 $error++;
383 $this->errors[] = "Error ".$this->db->lasterror();
384 }
385
386 // Commit or rollback
387 if ($error) {
388 $this->db->rollback();
389 return -1 * $error;
390 } else {
391 $this->db->commit();
392 return 1;
393 }
394 }
395
396
404 public function delete($user, $notrigger = 0)
405 {
406 global $conf, $langs;
407 $error = 0;
408
409 $this->db->begin();
410
411 if (!$error) {
412 $sql = "DELETE FROM ".MAIN_DB_PREFIX.$this->table_element;
413 $sql .= " WHERE rowid=".((int) $this->id);
414
415 dol_syslog(get_class($this)."::delete", LOG_DEBUG);
416 $resql = $this->db->query($sql);
417 if (!$resql) {
418 $error++;
419 $this->errors[] = "Error ".$this->db->lasterror();
420 }
421 }
422
423 // Commit or rollback
424 if ($error) {
425 foreach ($this->errors as $errmsg) {
426 dol_syslog(get_class($this)."::delete ".$errmsg, LOG_ERR);
427 $this->error .= ($this->error ? ', '.$errmsg : $errmsg);
428 }
429 $this->db->rollback();
430 return -1 * $error;
431 } else {
432 $this->db->commit();
433 return 1;
434 }
435 }
436
445 public function calcMonthlyPayments($capital, $rate, $nbterm)
446 {
447 $result = '';
448
449 if (!empty($capital) && !empty($nbterm)) {
450 if (!empty($rate)) {
451 $result = ($capital * ($rate / 12)) / (1 - pow((1 + ($rate / 12)), ($nbterm * -1)));
452 } else {
453 $result = $capital / $nbterm;
454 }
455 }
456
457 return $result;
458 }
459
460
467 public function fetchAll($loanid)
468 {
469 $sql = "SELECT";
470 $sql .= " t.rowid,";
471 $sql .= " t.fk_loan,";
472 $sql .= " t.datec,";
473 $sql .= " t.tms,";
474 $sql .= " t.datep,";
475 $sql .= " t.amount_capital,";
476 $sql .= " t.amount_insurance,";
477 $sql .= " t.amount_interest,";
478 $sql .= " t.fk_typepayment,";
479 $sql .= " t.num_payment,";
480 $sql .= " t.note_private,";
481 $sql .= " t.note_public,";
482 $sql .= " t.fk_bank,";
483 $sql .= " t.fk_payment_loan,";
484 $sql .= " t.fk_user_creat,";
485 $sql .= " t.fk_user_modif";
486 $sql .= " FROM ".MAIN_DB_PREFIX.$this->table_element." as t";
487 $sql .= " WHERE t.fk_loan = ".((int) $loanid);
488
489 dol_syslog(get_class($this)."::fetchAll", LOG_DEBUG);
490 $resql = $this->db->query($sql);
491
492 if ($resql) {
493 while ($obj = $this->db->fetch_object($resql)) {
494 $line = new LoanSchedule($this->db);
495 $line->id = $obj->rowid;
496 $line->ref = $obj->rowid;
497
498 $line->fk_loan = $obj->fk_loan;
499 $line->datec = $this->db->jdate($obj->datec);
500 $line->tms = $this->db->jdate($obj->tms);
501 $line->datep = $this->db->jdate($obj->datep);
502 $line->amount_capital = $obj->amount_capital;
503 $line->amount_insurance = $obj->amount_insurance;
504 $line->amount_interest = $obj->amount_interest;
505 $line->fk_typepayment = $obj->fk_typepayment;
506 $line->num_payment = $obj->num_payment;
507 $line->note_private = $obj->note_private;
508 $line->note_public = $obj->note_public;
509 $line->fk_bank = $obj->fk_bank;
510 $line->fk_payment_loan = $obj->fk_payment_loan;
511 $line->fk_user_creat = $obj->fk_user_creat;
512 $line->fk_user_modif = $obj->fk_user_modif;
513
514 $this->lines[] = $line;
515 }
516 $this->db->free($resql);
517 return 1;
518 } else {
519 $this->error = "Error ".$this->db->lasterror();
520 return -1;
521 }
522 }
523
529 private function transPayment() // @phpstan-ignore-line
530 {
531 require_once DOL_DOCUMENT_ROOT.'/loan/class/loan.class.php';
532 require_once DOL_DOCUMENT_ROOT.'/core/lib/loan.lib.php';
533 require_once DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php';
534
535 $toinsert = array();
536
537 $sql = "SELECT l.rowid";
538 $sql .= " FROM ".MAIN_DB_PREFIX."loan as l";
539 $sql .= " WHERE l.paid = 0";
540 $resql = $this->db->query($sql);
541
542 if ($resql) {
543 while ($obj = $this->db->fetch_object($resql)) {
544 $lastrecorded = $this->lastPayment($obj->rowid);
545 $toinsert = $this->paimenttorecord($obj->rowid, $lastrecorded);
546 if (count($toinsert) > 0) {
547 foreach ($toinsert as $echid) {
548 $this->db->begin();
549 $sql = "INSERT INTO ".MAIN_DB_PREFIX."payment_loan ";
550 $sql .= "(fk_loan,datec,tms,datep,amount_capital,amount_insurance,amount_interest,fk_typepayment,num_payment,note_private,note_public,fk_bank,fk_user_creat,fk_user_modif) ";
551 $sql .= "SELECT fk_loan,datec,tms,datep,amount_capital,amount_insurance,amount_interest,fk_typepayment,num_payment,note_private,note_public,fk_bank,fk_user_creat,fk_user_modif";
552 $sql .= " FROM ".MAIN_DB_PREFIX."loan_schedule WHERE rowid =".((int) $echid);
553 $res = $this->db->query($sql);
554 if ($res) {
555 $this->db->commit();
556 } else {
557 $this->db->rollback();
558 }
559 }
560 }
561 }
562 }
563 }
564
565
572 private function lastPayment($loanid)
573 {
574 $sql = "SELECT p.datep";
575 $sql .= " FROM ".MAIN_DB_PREFIX."payment_loan as p ";
576 $sql .= " WHERE p.fk_loan = ".((int) $loanid);
577 $sql .= " ORDER BY p.datep DESC ";
578 $sql .= " LIMIT 1 ";
579
580 $resql = $this->db->query($sql);
581
582 if ($resql) {
583 $obj = $this->db->fetch_object($resql);
584 return $this->db->jdate($obj->datep);
585 } else {
586 return -1;
587 }
588 }
589
597 public function paimenttorecord($loanid, $datemax)
598 {
599 $result = array();
600
601 $sql = "SELECT p.rowid";
602 $sql .= " FROM ".MAIN_DB_PREFIX.$this->table_element." as p ";
603 $sql .= " WHERE p.fk_loan = ".((int) $loanid);
604 if (!empty($datemax)) {
605 $sql .= " AND p.datep > '".$this->db->idate($datemax)."'";
606 }
607 $sql .= " AND p.datep <= '".$this->db->idate(dol_now())."'";
608
609 $resql = $this->db->query($sql);
610
611 if ($resql) {
612 while ($obj = $this->db->fetch_object($resql)) {
613 $result[] = $obj->rowid;
614 }
615 }
616
617 return $result;
618 }
619}
$object ref
Definition info.php:89
Parent class of all other business classes (invoices, contracts, proposals, orders,...
Class to manage Schedule of loans.
__construct($db)
Constructor.
fetchAll($loanid)
Load all object in memory from database.
calcMonthlyPayments($capital, $rate, $nbterm)
Calculate Monthly Payments.
create($user)
Create payment of loan into database.
fetch($id)
Load object in memory from database.
paimenttorecord($loanid, $datemax)
paimenttorecord
update($user=null, $notrigger=0)
Update database.
lastPayment($loanid)
lastpayment
transPayment()
transPayment
price2num($amount, $rounding='', $option=0)
Function that return a number with universal decimal format (decimal separator is '.
dol_now($mode='auto')
Return date for now.
dol_syslog($message, $level=LOG_INFO, $ident=0, $suffixinfilename='', $restricttologhandler='', $logcontext=null)
Write log message into outputs.
global $conf
The following vars must be defined: $type2label $form $conf, $lang, The following vars may also be de...
Definition member.php:79