1<?php
2/* Copyright (C) 2014-2018  Alexandre Spangaro   <aspangaro@open-dsi.fr>
3 * Copyright (C) 2015-2018  Frederic 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
20/**
21 *  \file       htdocs/loan/class/paymentloan.class.php
22 *  \ingroup    loan
23 *  \brief      File of class to manage payment of loans
24 */
25
26require_once DOL_DOCUMENT_ROOT.'/core/class/commonobject.class.php';
27
28
29/**
30 * Class to manage payments of loans
31 */
32class PaymentLoan extends CommonObject
33{
34	/**
35	 * @var string ID to identify managed object
36	 */
37	public $element = 'payment_loan';
38
39	/**
40	 * @var string Name of table without prefix where object is stored
41	 */
42	public $table_element = 'payment_loan';
43
44	/**
45	 * @var string String with name of icon for PaymentLoan
46	 */
47	public $picto = 'money-bill-alt';
48
49	/**
50	 * @var int Loan ID
51	 */
52	public $fk_loan;
53
54	/**
55	 * @var string Create date
56	 */
57	public $datec = '';
58
59	public $tms = '';
60
61	/**
62	 * @var string Payment date
63	 */
64	public $datep = '';
65
66	public $amounts = array(); // Array of amounts
67
68	public $amount_capital; // Total amount of payment
69
70	public $amount_insurance;
71
72	public $amount_interest;
73
74	/**
75	 * @var int Payment mode ID
76	 */
77	public $fk_typepayment;
78
79	/**
80	 * @var int Payment ID
81	 */
82	public $num_payment;
83
84	/**
85	 * @var int Bank ID
86	 */
87	public $fk_bank;
88
89	/**
90	 * @var int User ID
91	 */
92	public $fk_user_creat;
93
94	/**
95	 * @var int user ID
96	 */
97	public $fk_user_modif;
98
99	public $type_code;
100	public $type_label;
101
102
103	/**
104	 *	Constructor
105	 *
106	 *  @param		DoliDB		$db      Database handler
107	 */
108	public function __construct($db)
109	{
110		$this->db = $db;
111	}
112
113	/**
114	 *  Create payment of loan into database.
115	 *  Use this->amounts to have list of lines for the payment
116	 *
117	 *  @param      User		$user   User making payment
118	 *  @return     int     			<0 if KO, id of payment if OK
119	 */
120	public function create($user)
121	{
122		global $conf, $langs;
123
124		$error = 0;
125
126		$now = dol_now();
127
128		// Validate parameters
129		if (!$this->datep) {
130			$this->error = 'ErrorBadValueForParameter';
131			return -1;
132		}
133
134		// Clean parameters
135		if (isset($this->fk_loan)) {
136			$this->fk_loan = (int) $this->fk_loan;
137		}
138		if (isset($this->amount_capital)) {
139			$this->amount_capital = price2num($this->amount_capital ? $this->amount_capital : 0);
140		}
141		if (isset($this->amount_insurance)) {
142			$this->amount_insurance = price2num($this->amount_insurance ? $this->amount_insurance : 0);
143		}
144		if (isset($this->amount_interest)) {
145			$this->amount_interest = price2num($this->amount_interest ? $this->amount_interest : 0);
146		}
147		if (isset($this->fk_typepayment)) {
148			$this->fk_typepayment = (int) $this->fk_typepayment;
149		}
150		if (isset($this->num_payment)) {
151			$this->num_payment = (int) $this->num_payment;
152		}
153		if (isset($this->note_private)) {
154			$this->note_private = trim($this->note_private);
155		}
156		if (isset($this->note_public)) {
157			$this->note_public = trim($this->note_public);
158		}
159		if (isset($this->fk_bank)) {
160			$this->fk_bank = (int) $this->fk_bank;
161		}
162		if (isset($this->fk_user_creat)) {
163			$this->fk_user_creat = (int) $this->fk_user_creat;
164		}
165		if (isset($this->fk_user_modif)) {
166			$this->fk_user_modif = (int) $this->fk_user_modif;
167		}
168
169		$totalamount = $this->amount_capital + $this->amount_insurance + $this->amount_interest;
170		$totalamount = price2num($totalamount);
171
172		// Check parameters
173		if ($totalamount == 0) {
174			return -1; // Negative amounts are accepted for reject prelevement but not null
175		}
176
177
178		$this->db->begin();
179
180		if ($totalamount != 0) {
181			$sql = "INSERT INTO ".MAIN_DB_PREFIX."payment_loan (fk_loan, datec, datep, amount_capital, amount_insurance, amount_interest,";
182			$sql .= " fk_typepayment, num_payment, note_private, note_public, fk_user_creat, fk_bank)";
183			$sql .= " VALUES (".$this->chid.", '".$this->db->idate($now)."',";
184			$sql .= " '".$this->db->idate($this->datep)."',";
185			$sql .= " ".price2num($this->amount_capital).",";
186			$sql .= " ".price2num($this->amount_insurance).",";
187			$sql .= " ".price2num($this->amount_interest).",";
188			$sql .= " ".((int) $this->paymenttype).", '".$this->db->escape($this->num_payment)."', '".$this->db->escape($this->note_private)."', '".$this->db->escape($this->note_public)."', ".$user->id.",";
189			$sql .= " 0)";
190
191			dol_syslog(get_class($this)."::create", LOG_DEBUG);
192			$resql = $this->db->query($sql);
193			if ($resql) {
194				$this->id = $this->db->last_insert_id(MAIN_DB_PREFIX."payment_loan");
195			} else {
196				$this->error = $this->db->lasterror();
197				$error++;
198			}
199		}
200
201		if ($totalamount != 0 && !$error) {
202			$this->amount_capital = $totalamount;
203			$this->db->commit();
204			return $this->id;
205		} else {
206			$this->error = $this->db->lasterror();
207			$this->db->rollback();
208			return -1;
209		}
210	}
211
212	/**
213	 *  Load object in memory from database
214	 *
215	 *  @param	int		$id         Id object
216	 *  @return int         		<0 if KO, >0 if OK
217	 */
218	public function fetch($id)
219	{
220		global $langs;
221		$sql = "SELECT";
222		$sql .= " t.rowid,";
223		$sql .= " t.fk_loan,";
224		$sql .= " t.datec,";
225		$sql .= " t.tms,";
226		$sql .= " t.datep,";
227		$sql .= " t.amount_capital,";
228		$sql .= " t.amount_insurance,";
229		$sql .= " t.amount_interest,";
230		$sql .= " t.fk_typepayment,";
231		$sql .= " t.num_payment,";
232		$sql .= " t.note_private,";
233		$sql .= " t.note_public,";
234		$sql .= " t.fk_bank,";
235		$sql .= " t.fk_user_creat,";
236		$sql .= " t.fk_user_modif,";
237		$sql .= " pt.code as type_code, pt.libelle as type_label,";
238		$sql .= ' b.fk_account';
239		$sql .= " FROM ".MAIN_DB_PREFIX."payment_loan as t";
240		$sql .= " LEFT JOIN ".MAIN_DB_PREFIX."c_paiement as pt ON t.fk_typepayment = pt.id";
241		$sql .= ' LEFT JOIN '.MAIN_DB_PREFIX.'bank as b ON t.fk_bank = b.rowid';
242		$sql .= " WHERE t.rowid = ".((int) $id);
243
244		dol_syslog(get_class($this)."::fetch", LOG_DEBUG);
245		$resql = $this->db->query($sql);
246		if ($resql) {
247			if ($this->db->num_rows($resql)) {
248				$obj = $this->db->fetch_object($resql);
249
250				$this->id = $obj->rowid;
251				$this->ref = $obj->rowid;
252
253				$this->fk_loan = $obj->fk_loan;
254				$this->datec = $this->db->jdate($obj->datec);
255				$this->tms = $this->db->jdate($obj->tms);
256				$this->datep = $this->db->jdate($obj->datep);
257				$this->amount_capital = $obj->amount_capital;
258				$this->amount_insurance = $obj->amount_insurance;
259				$this->amount_interest = $obj->amount_interest;
260				$this->fk_typepayment = $obj->fk_typepayment;
261				$this->num_payment = $obj->num_payment;
262				$this->note_private = $obj->note_private;
263				$this->note_public = $obj->note_public;
264				$this->fk_bank = $obj->fk_bank;
265				$this->fk_user_creat = $obj->fk_user_creat;
266				$this->fk_user_modif = $obj->fk_user_modif;
267
268				$this->type_code = $obj->type_code;
269				$this->type_label = $obj->type_label;
270
271				$this->bank_account = $obj->fk_account;
272				$this->bank_line = $obj->fk_bank;
273			}
274			$this->db->free($resql);
275
276			return 1;
277		} else {
278			$this->error = "Error ".$this->db->lasterror();
279			return -1;
280		}
281	}
282
283
284	/**
285	 *  Update database
286	 *
287	 *  @param	User	$user        	User that modify
288	 *  @param  int		$notrigger	    0=launch triggers after, 1=disable triggers
289	 *  @return int         			<0 if KO, >0 if OK
290	 */
291	public function update($user = 0, $notrigger = 0)
292	{
293		global $conf, $langs;
294		$error = 0;
295
296		// Clean parameters
297		if (isset($this->fk_loan)) {
298			$this->fk_loan = (int) $this->fk_loan;
299		}
300		if (isset($this->amount_capital)) {
301			$this->amount_capital = trim($this->amount_capital);
302		}
303		if (isset($this->amount_insurance)) {
304			$this->amount_insurance = trim($this->amount_insurance);
305		}
306		if (isset($this->amount_interest)) {
307			$this->amount_interest = trim($this->amount_interest);
308		}
309		if (isset($this->fk_typepayment)) {
310			$this->fk_typepayment = (int) $this->fk_typepayment;
311		}
312		if (isset($this->num_payment)) {
313			$this->num_payment = (int) $this->num_payment;
314		}
315		if (isset($this->note_private)) {
316			$this->note = trim($this->note_private);
317		}
318		if (isset($this->note_public)) {
319			$this->note = trim($this->note_public);
320		}
321		if (isset($this->fk_bank)) {
322			$this->fk_bank = (int) $this->fk_bank;
323		}
324		if (isset($this->fk_user_creat)) {
325			$this->fk_user_creat = (int) $this->fk_user_creat;
326		}
327		if (isset($this->fk_user_modif)) {
328			$this->fk_user_modif = (int) $this->fk_user_modif;
329		}
330
331		// Check parameters
332
333		// Update request
334		$sql = "UPDATE ".MAIN_DB_PREFIX."payment_loan SET";
335		$sql .= " fk_loan=".(isset($this->fk_loan) ? $this->fk_loan : "null").",";
336		$sql .= " datec=".(dol_strlen($this->datec) != 0 ? "'".$this->db->idate($this->datec)."'" : 'null').",";
337		$sql .= " tms=".(dol_strlen($this->tms) != 0 ? "'".$this->db->idate($this->tms)."'" : 'null').",";
338		$sql .= " datep=".(dol_strlen($this->datep) != 0 ? "'".$this->db->idate($this->datep)."'" : 'null').",";
339		$sql .= " amount_capital=".(isset($this->amount_capital) ? $this->amount_capital : "null").",";
340		$sql .= " amount_insurance=".(isset($this->amount_insurance) ? $this->amount_insurance : "null").",";
341		$sql .= " amount_interest=".(isset($this->amount_interest) ? $this->amount_interest : "null").",";
342		$sql .= " fk_typepayment=".(isset($this->fk_typepayment) ? $this->fk_typepayment : "null").",";
343		$sql .= " num_payment=".(isset($this->num_payment) ? "'".$this->db->escape($this->num_payment)."'" : "null").",";
344		$sql .= " note_private=".(isset($this->note_private) ? "'".$this->db->escape($this->note_private)."'" : "null").",";
345		$sql .= " note_public=".(isset($this->note_public) ? "'".$this->db->escape($this->note_public)."'" : "null").",";
346		$sql .= " fk_bank=".(isset($this->fk_bank) ? $this->fk_bank : "null").",";
347		$sql .= " fk_user_creat=".(isset($this->fk_user_creat) ? $this->fk_user_creat : "null").",";
348		$sql .= " fk_user_modif=".(isset($this->fk_user_modif) ? $this->fk_user_modif : "null")."";
349		$sql .= " WHERE rowid=".((int) $this->id);
350
351		$this->db->begin();
352
353		dol_syslog(get_class($this)."::update", LOG_DEBUG);
354		$resql = $this->db->query($sql);
355		if (!$resql) {
356			$error++; $this->errors[] = "Error ".$this->db->lasterror();
357		}
358
359		// Commit or rollback
360		if ($error) {
361			foreach ($this->errors as $errmsg) {
362				dol_syslog(get_class($this)."::update ".$errmsg, LOG_ERR);
363				$this->error .= ($this->error ? ', '.$errmsg : $errmsg);
364			}
365			$this->db->rollback();
366			return -1 * $error;
367		} else {
368			$this->db->commit();
369			return 1;
370		}
371	}
372
373
374	/**
375	 *  Delete object in database
376	 *
377	 *  @param	User	$user        	User that delete
378	 *  @param  int		$notrigger		0=launch triggers after, 1=disable triggers
379	 *  @return int						<0 if KO, >0 if OK
380	 */
381	public function delete($user, $notrigger = 0)
382	{
383		global $conf, $langs;
384		$error = 0;
385
386		$this->db->begin();
387
388		if (!$error) {
389			$sql = "DELETE FROM ".MAIN_DB_PREFIX."bank_url";
390			$sql .= " WHERE type='payment_loan' AND url_id=".((int) $this->id);
391
392			dol_syslog(get_class($this)."::delete", LOG_DEBUG);
393			$resql = $this->db->query($sql);
394			if (!$resql) {
395				$error++; $this->errors[] = "Error ".$this->db->lasterror();
396			}
397		}
398
399		if (!$error) {
400			$sql = "DELETE FROM ".MAIN_DB_PREFIX."payment_loan";
401			$sql .= " WHERE rowid=".((int) $this->id);
402
403			dol_syslog(get_class($this)."::delete", LOG_DEBUG);
404			$resql = $this->db->query($sql);
405			if (!$resql) {
406				$error++; $this->errors[] = "Error ".$this->db->lasterror();
407			}
408		}
409
410		// Set loan unpaid if loan has no other payment
411		if (!$error) {
412			require_once DOL_DOCUMENT_ROOT.'/loan/class/loan.class.php';
413			$loan = new Loan($this->db);
414			$loan->fetch($this->fk_loan);
415			$sum_payment = $loan->getSumPayment();
416			if ($sum_payment == 0) {
417				dol_syslog(get_class($this)."::delete : set loan to unpaid", LOG_DEBUG);
418				if ($loan->setUnpaid($user) < 1) {
419					$error++;
420					dol_print_error($this->db);
421				}
422			}
423		}
424
425		//if (! $error)
426		//{
427		//	if (! $notrigger)
428		//	{
429				// Uncomment this and change MYOBJECT to your own tag if you
430				// want this action call a trigger.
431
432				//// Call triggers
433				//include_once DOL_DOCUMENT_ROOT . '/core/class/interfaces.class.php';
434				//$interface=new Interfaces($this->db);
435				//$result=$interface->run_triggers('MYOBJECT_DELETE',$this,$user,$langs,$conf);
436				//if ($result < 0) { $error++; $this->errors=$interface->errors; }
437				//// End call triggers
438		//	}
439		//}
440
441		// Commit or rollback
442		if ($error) {
443			foreach ($this->errors as $errmsg) {
444				dol_syslog(get_class($this)."::delete ".$errmsg, LOG_ERR);
445				$this->error .= ($this->error ? ', '.$errmsg : $errmsg);
446			}
447			$this->db->rollback();
448			return -1 * $error;
449		} else {
450			$this->db->commit();
451			return 1;
452		}
453	}
454
455	/**
456	 * Retourne le libelle du statut d'une facture (brouillon, validee, abandonnee, payee)
457	 *
458	 * @param	int		$mode       0=libelle long, 1=libelle court, 2=Picto + Libelle court, 3=Picto, 4=Picto + Libelle long, 5=Libelle court + Picto
459	 * @return  string				Libelle
460	 */
461	public function getLibStatut($mode = 0)
462	{
463		return $this->LibStatut($this->statut, $mode);
464	}
465
466	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
467	/**
468	 * Renvoi le libelle d'un statut donne
469	 *
470	 * @param   int		$status     Statut
471	 * @param   int		$mode       0=libelle long, 1=libelle court, 2=Picto + Libelle court, 3=Picto, 4=Picto + Libelle long, 5=Libelle court + Picto
472	 * @return	string  		    Libelle du statut
473	 */
474	public function LibStatut($status, $mode = 0)
475	{
476		// phpcs:enable
477		return '';
478	}
479
480	/**
481	 *      Add record into bank for payment with links between this bank record and invoices of payment.
482	 *      All payment properties must have been set first like after a call to create().
483	 *
484	 *      @param	User	$user               Object of user making payment
485	 *      @param  int		$fk_loan            Id of fk_loan to do link with this payment
486	 *      @param  string	$mode               'payment_loan'
487	 *      @param  string	$label              Label to use in bank record
488	 *      @param  int		$accountid          Id of bank account to do link with
489	 *      @param  string	$emetteur_nom       Name of transmitter
490	 *      @param  string	$emetteur_banque    Name of bank
491	 *      @return int                 		<0 if KO, >0 if OK
492	 */
493	public function addPaymentToBank($user, $fk_loan, $mode, $label, $accountid, $emetteur_nom, $emetteur_banque)
494	{
495		global $conf;
496
497		$error = 0;
498		$this->db->begin();
499
500		if (!empty($conf->banque->enabled)) {
501			require_once DOL_DOCUMENT_ROOT.'/compta/bank/class/account.class.php';
502
503			$acc = new Account($this->db);
504			$acc->fetch($accountid);
505
506			$total = $this->amount_capital;
507			if ($mode == 'payment_loan') {
508				$total = -$total;
509			}
510
511			// Insert payment into llx_bank
512			$bank_line_id = $acc->addline(
513				$this->datep,
514				$this->paymenttype, // Payment mode ID or code ("CHQ or VIR for example")
515				$label,
516				$total,
517				$this->num_payment,
518				'',
519				$user,
520				$emetteur_nom,
521				$emetteur_banque
522			);
523
524			// Update fk_bank into llx_paiement.
525			// We know the payment who generated the account write
526			if ($bank_line_id > 0) {
527				$result = $this->update_fk_bank($bank_line_id);
528				if ($result <= 0) {
529					$error++;
530					dol_print_error($this->db);
531				}
532
533				// Add link 'payment_loan' in bank_url between payment and bank transaction
534				$url = '';
535				if ($mode == 'payment_loan') {
536					$url = DOL_URL_ROOT.'/loan/payment/card.php?id=';
537				}
538				if ($url) {
539					$result = $acc->add_url_line($bank_line_id, $this->id, $url, '(payment)', $mode);
540					if ($result <= 0) {
541						$error++;
542						dol_print_error($this->db);
543					}
544				}
545
546
547				// Add link 'loan' in bank_url between invoice and bank transaction (for each invoice concerned by payment)
548				if ($mode == 'payment_loan') {
549					$result = $acc->add_url_line($bank_line_id, $fk_loan, DOL_URL_ROOT.'/loan/card.php?id=', ($this->label ? $this->label : ''), 'loan');
550					if ($result <= 0) {
551						dol_print_error($this->db);
552					}
553				}
554			} else {
555				$this->error = $acc->error;
556				$error++;
557			}
558		}
559
560
561		// Set loan payment started if no set
562		if (!$error) {
563			require_once DOL_DOCUMENT_ROOT.'/loan/class/loan.class.php';
564			$loan = new Loan($this->db);
565			$loan->fetch($fk_loan);
566			if ($loan->paid == $loan::STATUS_UNPAID) {
567				dol_syslog(get_class($this)."::addPaymentToBank : set loan payment to started", LOG_DEBUG);
568				if ($loan->setStarted($user) < 1) {
569					$error++;
570					dol_print_error($this->db);
571				}
572			}
573		}
574
575		if (!$error) {
576			$this->db->commit();
577			return 1;
578		} else {
579			$this->db->rollback();
580			return -1;
581		}
582	}
583
584
585	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
586	/**
587	 *  Update link between loan's payment and the line generate in llx_bank
588	 *
589	 *  @param	int		$id_bank         Id if bank
590	 *  @return	int			             >0 if OK, <=0 if KO
591	 */
592	public function update_fk_bank($id_bank)
593	{
594		// phpcs:enable
595		$sql = "UPDATE ".MAIN_DB_PREFIX."payment_loan SET fk_bank = ".((int) $id_bank)." WHERE rowid = ".((int) $this->id);
596
597		dol_syslog(get_class($this)."::update_fk_bank", LOG_DEBUG);
598		$result = $this->db->query($sql);
599		if ($result) {
600			$this->fk_bank = ((int) $id_bank);
601			return 1;
602		} else {
603			$this->error = $this->db->error();
604			return 0;
605		}
606	}
607
608	/**
609	 *  Return clicable name (with eventually a picto)
610	 *
611	 *	@param	int		$withpicto					0=No picto, 1=Include picto into link, 2=No picto
612	 * 	@param	int		$maxlen						Max length label
613	 *	@param	int  	$notooltip					1=Disable tooltip
614	 *	@param	string	$moretitle					Add more text to title tooltip
615	 *  @param  int     $save_lastsearch_value    	-1=Auto, 0=No save of lastsearch_values when clicking, 1=Save lastsearch_values whenclicking
616	 *	@return	string								String with URL
617	 */
618	public function getNomUrl($withpicto = 0, $maxlen = 0, $notooltip = 0, $moretitle = '', $save_lastsearch_value = -1)
619	{
620		global $langs, $conf;
621
622		if (!empty($conf->dol_no_mouse_hover)) {
623			$notooltip = 1; // Force disable tooltips
624		}
625
626		$result = '';
627		$label = '<u>'.$langs->trans("Loan").'</u>';
628		if (!empty($this->id)) {
629			$label .= '<br><b>'.$langs->trans('Ref').':</b> '.$this->id;
630		}
631		if ($moretitle) {
632			$label .= ' - '.$moretitle;
633		}
634
635		$url = DOL_URL_ROOT.'/loan/payment/card.php?id='.$this->id;
636
637		$add_save_lastsearch_values = ($save_lastsearch_value == 1 ? 1 : 0);
638		if ($save_lastsearch_value == -1 && preg_match('/list\.php/', $_SERVER["PHP_SELF"])) {
639			$add_save_lastsearch_values = 1;
640		}
641		if ($add_save_lastsearch_values) {
642			$url .= '&save_lastsearch_values=1';
643		}
644
645		$linkstart = '<a href="'.$url.'" title="'.dol_escape_htmltag($label, 1).'" class="classfortooltip">';
646		$linkend = '</a>';
647
648		$result .= $linkstart;
649		if ($withpicto) {
650			$result .= img_object(($notooltip ? '' : $label), $this->picto, ($notooltip ? (($withpicto != 2) ? 'class="paddingright"' : '') : 'class="'.(($withpicto != 2) ? 'paddingright ' : '').'classfortooltip"'), 0, 0, $notooltip ? 0 : 1);
651		}
652		if ($withpicto != 2) {
653			$result .= $this->ref;
654		}
655		$result .= $linkend;
656
657		return $result;
658	}
659}
660