<?php
/* Copyright (C) 2004-2005 Rodolphe Quiedeville <rodolphe@quiedeville.org>
 * Copyright (C) 2005-2012 Regis Houssin        <regis.houssin@inodbox.com>
 * Copyright (C) 2010-2015 Juanjo Menent        <jmenent@2byte.es>
 * Copyright (C) 2010-2014 Laurent Destailleur  <eldy@users.sourceforge.net>
 * Copyright (C) 2014-2016 Ferran Marcet       <fmarcet@2byte.es>
 * Copyright (C) 2018      Nicolas ZABOURI     <info@inovea-conseil.com>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program. If not, see <https://www.gnu.org/licenses/>.
 */

/**
 *      \file       htdocs/compta/prelevement/class/bonprelevementPF.class.php
 *      \ingroup    prelevement
 *      \brief      File of withdrawal receipts class
 */

require_once DOL_DOCUMENT_ROOT.'/core/class/commonobject.class.php';
require_once DOL_DOCUMENT_ROOT.'/compta/facture/class/facture.class.php';
require_once DOL_DOCUMENT_ROOT.'/fourn/class/fournisseur.facture.class.php';
require_once DOL_DOCUMENT_ROOT.'/compta/bank/class/account.class.php';
require_once DOL_DOCUMENT_ROOT.'/societe/class/societe.class.php';
require_once DOL_DOCUMENT_ROOT.'/compta/paiement/class/paiement.class.php';
require_once DOL_DOCUMENT_ROOT.'/fourn/class/paiementfourn.class.php';
dol_include_once('/prelevementpf/lib/prelevementpf.lib.php');
dol_include_once('/prelevementpf/lib/helper.lib.php');



/**
 *	Class to manage withdrawal receipts
 */
class BonPrelevementPF extends CommonObject
{
	/**
	 * @var string ID to identify managed object
	 */
	public $element = 'widthdrawpf';

	/**
	 * @var string Name of table without prefix where object is stored
	 */
	public $table_element = 'prelevementpf_bons';

	/**
	 * @var string String with name of icon for myobject. Must be the part after the 'object_' into object_myobject.png
	 */
	public $picto = 'payment';

	public $date_echeance;
	public $raison_sociale;
	public $reference_remise;
	public $emetteur_code_guichet;
	public $emetteur_numero_compte;
	public $emetteur_code_banque;
	public $emetteur_cle_rib;
	public $emetteur_nom;
	
	public $emetteur_nne;

	public $emetteur_iban;
	public $emetteur_bic;
	public $emetteur_ics;

	public $date_trans;
	public $user_trans;

	public $total;
	public $fetched;
	public $statut; // 0-Wait, 1-Trans, 2-Done
	public $labelStatus = array();

	public $file_prelevement;
	public $file_rejet;

	public $invoice_in_error = array();
	public $thirdparty_in_error = array();

	const STATUS_DRAFT = 0;
	const STATUS_TRANSFERED = 1;
	const STATUS_CREDITED = 2;

	
	const CODE_ENREGISTREMENT_EMETTEUR     = '03';
	const CODE_ENREGISTREMENT_DESTINATAIRE = '06';
	const CODE_ENREGISTREMENT_TOTAL        = '08';
	const CODE_OPERATION = '08';


	/**
	 *	Constructor
	 *
	 *  @param		DoliDB		$db      	Database handler
	 */
	public function __construct($db)
	{
		global $conf, $langs;

		$this->db = $db;

		$this->filename = '';

		$this->date_echeance = dol_now();
		$this->raison_sociale = "";
		$this->reference_remise = "";

		$this->file_prelevement = "";
		$this->file_rejet       = "";

		$this->emetteur_code_guichet = "";
		$this->emetteur_numero_compte = "";
		$this->emetteur_code_banque = "";
		$this->emetteur_cle_rib = "";
		$this->emetteur_nom = "";

		$this->emetteur_nne = "";

		$this->emetteur_iban = "";
		$this->emetteur_bic = "";
		$this->emetteur_ics = "";

		$this->factures = array();

		$this->methodes_trans = array();

		$this->methodes_trans[0] = "Internet";

		$this->fetched = 0;
	}

	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
	/**
	 * Add invoice to withdrawal
	 *
	 * @param	int		$invoice_id 	id invoice to add
	 * @param	int		$client_id  	id invoice customer
	 * @param	string	$client_nom 	customer name
	 * @param	int		$amount 		amount of invoice
	 * @param	string	$code_banque 	code of bank withdrawal
	 * @param	string	$code_guichet 	code of bank's office
	 * @param	string	$number bank 	account number
	 * @param	string	$number_key 	number key of account number
	 * @param	string	$type			'debit-order' or 'bank-transfer'
	 * @return	int						>0 if OK, <0 if KO
	 */
	public function AddFacture($invoice_id, $client_id, $client_nom, $amount, $code_banque, $code_guichet, $number, $number_key, $type = 'debit-order')
	{
		// phpcs:enable
		$result = 0;
		$line_id = 0;

		// Add lines
		$result = $this->addline($line_id, $client_id, $client_nom, $amount, $code_banque, $code_guichet, $number, $number_key);

		if ($result == 0)
		{
			if ($line_id > 0)
			{
				$sql = "INSERT INTO ".MAIN_DB_PREFIX."prelevementpf_facture (";
				if ($type != 'bank-transfer') {
					$sql .= "fk_facture";
				} else {
					$sql .= "fk_facture_fourn";
				}
				$sql .= ",fk_prelevementpf_lignes";
				$sql .= ") VALUES (";
				$sql .= $invoice_id;
				$sql .= ", ".$line_id;
				$sql .= ")";

				if ($this->db->query($sql))
				{
					$result = 0;
				} else {
					$result = -1;
					$this->errors[] = get_class($this)."::AddFacture ".$this->db->lasterror;
					dol_syslog(get_class($this)."::AddFacture Error $result");
				}
			} else {
				$result = -2;
				$this->errors[] = get_class($this)."::AddFacture linedid Empty";
				dol_syslog(get_class($this)."::AddFacture Error $result");
			}
		} else {
			$result = -3;
			dol_syslog(get_class($this)."::AddFacture Error $result");
		}

		return $result;
	}

	/**
	 *	Add line to withdrawal
	 *
	 *	@param	int		$line_id 		id line to add
	 *	@param	int		$client_id  	id invoice customer
	 *	@param	string	$client_nom 	customer name
	 *	@param	int		$amount 		amount of invoice
	 *	@param	string	$code_banque 	code of bank withdrawal
	 *	@param	string	$code_guichet 	code of bank's office
	 *	@param	string	$number 		bank account number
	 *	@param  string	$number_key 	number key of account number
	 *	@return	int						>0 if OK, <0 if KO
	 */
	public function addline(&$line_id, $client_id, $client_nom, $amount, $code_banque, $code_guichet, $number, $number_key)
	{
		$result = -1;
		$concat = 0;

		if ($concat == 1)
		{
			/*
			 * We aggregate the lines
			 */
			$sql = "SELECT rowid";
			$sql .= " FROM  ".MAIN_DB_PREFIX."prelevementpf_lignes";
			$sql .= " WHERE fk_prelevementpf_bons = ".$this->id;
			$sql .= " AND fk_soc =".$client_id;
			$sql .= " AND code_banque = '".$this->db->escape($code_banque)."'";
			$sql .= " AND code_guichet = '".$this->db->escape($code_guichet)."'";
			$sql .= " AND number = '".$this->db->escape($number)."'";

			$resql = $this->db->query($sql);
			if ($resql)
			{
				$num = $this->db->num_rows($resql);
			} else {
				$result = -1;
			}
		} else {
			/*
			 * No aggregate
			 */
			$sql = "INSERT INTO ".MAIN_DB_PREFIX."prelevementpf_lignes (";
			$sql .= "fk_prelevementpf_bons";
			$sql .= ", fk_soc";
			$sql .= ", client_nom";
			$sql .= ", amount";
			$sql .= ", code_banque";
			$sql .= ", code_guichet";
			$sql .= ", number";
			$sql .= ", cle_rib";
			$sql .= ") VALUES (";
			$sql .= $this->id;
			$sql .= ", ".$client_id;
			$sql .= ", '".$this->db->escape($client_nom)."'";
			$sql .= ", '".price2num($amount)."'";
			$sql .= ", '".$this->db->escape($code_banque)."'";
			$sql .= ", '".$this->db->escape($code_guichet)."'";
			$sql .= ", '".$this->db->escape($number)."'";
			$sql .= ", '".$this->db->escape($number_key)."'";
			$sql .= ")";

			if ($this->db->query($sql))
			{
				$line_id = $this->db->last_insert_id(MAIN_DB_PREFIX."prelevementpf_lignes");
				$result = 0;
			} else {
				$this->errors[] = get_class($this)."::addline Error -2 ".$this->db->lasterror;
				dol_syslog(get_class($this)."::addline Error -2");
				$result = -2;
			}
		}

		return $result;
	}

	/**
	 *	Return error string
	 *
	 *  @param	int		$error 		 Id of error
	 *	@return	string               Error string
	 */
	public function getErrorString($error)
	{
		global $langs;

		$errors = array();

		$errors[1027] = $langs->trans("DateInvalid");

		return $errors[abs($error)];
	}

	/**
	 *	Get object and lines from database
	 *
	 *	@param	int		$rowid		Id of object to load
	 *  @param	string	$ref		Ref of direct debit
	 *	@return	int					>0 if OK, <0 if KO
	 */
	public function fetch($rowid, $ref = '')
	{
		global $conf;

		$sql = "SELECT p.rowid, p.ref, p.amount, p.note";
		$sql .= ", p.datec";
		$sql .= ", p.date_trans as date_trans";
		$sql .= ", p.method_trans, p.fk_user_trans";
		$sql .= ", p.date_credit as date_credit";
		$sql .= ", p.fk_user_credit";
		$sql .= ", p.type";
		$sql .= ", p.statut as status";
		$sql .= ", p.code_banque, p.code_guichet, p.numero_compte, p.cle_rib";
		$sql .= ", p.file_prelevement, p.file_rejet";
		$sql .= ", pb.name AS bank_name";
		$sql .= " FROM ".MAIN_DB_PREFIX."prelevementpf_bons as p";
		$sql .= " LEFT JOIN ".MAIN_DB_PREFIX."prelevementpf_bank as pb ON pb.rowid=p.fk_prelevementbank";
		$sql .= " WHERE p.entity IN (".getEntity('invoice').")";
		if ($rowid > 0) $sql .= " AND p.rowid = ".$rowid;
		else $sql .= " AND p.ref = '".$this->db->escape($ref)."'";

		dol_syslog(get_class($this)."::fetch", LOG_DEBUG);
		$result = $this->db->query($sql);
		if ($result)
		{
			if ($this->db->num_rows($result))
			{
				$obj = $this->db->fetch_object($result);

				$this->id             = $obj->rowid;
				$this->ref            = $obj->ref;
				$this->amount         = $obj->amount;
				$this->note           = $obj->note;
				$this->datec          = $this->db->jdate($obj->datec);

				$this->date_trans     = $this->db->jdate($obj->date_trans);
				$this->method_trans   = $obj->method_trans;
				$this->user_trans     = $obj->fk_user_trans;

				$this->date_credit    = $this->db->jdate($obj->date_credit);
				$this->user_credit    = $obj->fk_user_credit;

				$this->type           = $obj->type;

				$this->date_echeance  = $this->db->jdate( date("Y-m-d H:i:s", strtotime("+1 MONTH", strtotime($obj->datec))) );

				$this->status         = $obj->status;
				$this->statut         = $obj->status; // For backward compatibility
				
				$this->file_prelevement = $obj->file_prelevement;
				$this->file_rejet       = $obj->file_rejet;

				$this->emetteur_code_banque 	= $obj->code_banque;
				$this->emetteur_code_guichet	= $obj->code_guichet;
				$this->emetteur_numero_compte   = $obj->numero_compte;
				$this->emetteur_cle_rib 		= $obj->cle_rib;
				$this->emetteur_nom 			= $obj->bank_name;

				$this->emetteur_nne             = $conf->global->PRELEVEMENTPF_NNE; // Ex: prelevementpf_ICS = "FR78ZZZ123456";

				$this->fetched = 1;

				return 1;
			} else {
				dol_syslog(get_class($this)."::Fetch Erreur aucune ligne retournee");
				return -1;
			}
		} else {
			return -2;
		}
	}

	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
	/**
	 * Set credite and set status of linked invoices. Still used ??
	 *
	 * @return		int		<0 if KO, >=0 if OK
	 */
	public function set_credite()
	{
		// phpcs:enable
		global $user, $conf;

		$error = 0;

		if ($this->db->begin())
		{
			$sql = " UPDATE ".MAIN_DB_PREFIX."prelevementpf_bons";
			$sql .= " SET statut = ".self::STATUS_TRANSFERED;
			$sql .= " WHERE rowid = ".$this->id;
			$sql .= " AND entity = ".$conf->entity;

			$result = $this->db->query($sql);
			if (!$result)
			{
				dol_syslog(get_class($this)."::set_credite Erreur 1");
				$error++;
			}

			if (!$error)
			{
				$facs = array();
				$facs = $this->getListInvoices();

				$num = count($facs);
				for ($i = 0; $i < $num; $i++)
				{
					/* Tag invoice as paid */
					dol_syslog(get_class($this)."::set_credite set_paid fac ".$facs[$i]);
					$fac = new Facture($this->db);
					$fac->fetch($facs[$i]);
					$result = $fac->set_paid($user);
				}
			}

			if (!$error)
			{
				$sql = " UPDATE ".MAIN_DB_PREFIX."prelevementpf_lignes";
				$sql .= " SET statut = 2";
				$sql .= " WHERE fk_prelevementpf_bons = ".$this->id;

				if (!$this->db->query($sql))
				{
					dol_syslog(get_class($this)."::set_credite Erreur 1");
					$error++;
				}
			}

			/*
			 * End of procedure
			 */
			if (!$error)
			{
				$this->db->commit();
				return 0;
			} else {
				$this->db->rollback();
				dol_syslog(get_class($this)."::set_credite ROLLBACK ");

				return -1;
			}
		} else {
			dol_syslog(get_class($this)."::set_credite Ouverture transaction SQL impossible ");
			return -2;
		}
	}

	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
	/**
	 *	Set direct debit or credit transfer order to "paid" status.
	 *
	 *	@param	User	$user			Id of user
	 *	@param 	int		$date			date of action
	 *	@return	int						>0 if OK, <0 if KO
	 */
	public function set_infocredit($user, $date)
	{
		// phpcs:enable
		global $conf, $langs;

		$error = 0;

		if ($this->fetched == 1)
		{
			if ($date < $this->date_trans)
			{
				$this->error = 'DateOfMovementLowerThanDateOfFileTransmission';
				dol_syslog("bon-prelevment::set_infocredit 1027 ".$this->error);
				return -1027;
			}

			$this->db->begin();

			$sql = " UPDATE ".MAIN_DB_PREFIX."prelevementpf_bons ";
			$sql .= " SET fk_user_credit = ".$user->id;
			$sql .= ", statut = ".self::STATUS_CREDITED;
			$sql .= ", date_credit = '".$this->db->idate($date)."'";
			$sql .= " WHERE rowid=".$this->id;
			$sql .= " AND entity = ".$conf->entity;
			$sql .= " AND statut = ".self::STATUS_TRANSFERED;

			$resql = $this->db->query($sql);
			if ($resql)
			{
				$langs->load('withdrawals');
				$subject = $langs->trans("InfoCreditSubject", $this->ref);
				$message = $langs->trans("InfoCreditMessage", $this->ref, dol_print_date($date, 'dayhour'));

				//Add payment of withdrawal into bank
				$bankaccount = ($this->type == 'bank-transfer' ? $conf->global->PAYMENTBYBANKTRANSFER_ID_BANKACCOUNT : $conf->global->prelevementpf_ID_BANKACCOUNT);
				$facs = array();
				$amounts = array();
				$amountsperthirdparty = array();

				$facs = $this->getListInvoices(1);

				// Loop on each invoice. $facs=array(0=>id, 1=>amount requested)
				$num = count($facs);
				for ($i = 0; $i < $num; $i++)
				{
					if ($this->type == 'bank-transfer') {
						$fac = new FactureFournisseur($this->db);
					} else {
						$fac = new Facture($this->db);
					}

					$result = $fac->fetch($facs[$i][0]);

					$amounts[$fac->id] = $facs[$i][1];
					$amountsperthirdparty[$fac->socid][$fac->id] = $facs[$i][1];

					$totalpaye = $fac->getSommePaiement();
					$totalcreditnotes = $fac->getSumCreditNotesUsed();
					$totaldeposits = $fac->getSumDepositsUsed();
					$alreadypayed = $totalpaye + $totalcreditnotes + $totaldeposits;

					// @TODO Move this after creation of payment
					if (price2num($alreadypayed + $facs[$i][1], 'MT') == $fac->total_ttc) {
						$result = $fac->set_paid($user);
						if ($result < 0) {
							$this->error = $fac->error;
							$this->errors = $fac->errors;
						}
					}
				}
				//var_dump($amountsperthirdparty);exit;

				// Make one payment per customer
				foreach ($amountsperthirdparty as $thirdpartyid => $cursoramounts)
				{
					if ($this->type == 'bank-transfer') {
						$paiement = new PaiementFourn($this->db);
					} else {
						$paiement = new Paiement($this->db);
					}
					$paiement->datepaye     = $date;
					$paiement->amounts      = $cursoramounts; // Array with detail of dispatching of payments for each invoice

					if ($this->type == 'bank-transfer') {
						$paiement->paiementid = 2;
						$paiement->paiementcode = 'VIR';
					} else {
						$paiement->paiementid = 3;
						$paiement->paiementcode = 'PRE';
					}

					$paiement->num_payment = $this->ref; // Set ref of direct debit note
					$paiement->id_prelevement = $this->id;

					$paiement_id = $paiement->create($user); // This use ->paiementid, that is ID of payment mode
					if ($paiement_id < 0)
					{
						$error++;
						$this->error = $paiement->error;
						$this->errors = $paiement->errors;
						dol_syslog(get_class($this)."::set_infocredit AddPayment Error ".$this->error);
					} else {
						if ($this->type == 'bank-transfer') {
							$modeforaddpayment = 'payment_supplier';
						} else {
							$modeforaddpayment = 'payment';
						}

						$result = $paiement->addPaymentToBank($user, $modeforaddpayment, '(WithdrawalPayment)', $bankaccount, '', '');
						if ($result < 0)
						{
							$error++;
							$this->error = $paiement->error;
							$this->errors = $paiement->errors;
							dol_syslog(get_class($this)."::set_infocredit AddPaymentToBank Error ".$this->error);
						}
					}
					//var_dump($paiement->amounts);
					//var_dump($thirdpartyid);
					//var_dump($cursoramounts);
				}

				// Update withdrawal line
				// TODO: Translate to ligneprelevement.class.php
				if (!$error) {
					$sql = " UPDATE ".MAIN_DB_PREFIX."prelevementpf_lignes";
					$sql .= " SET statut = 2";
					$sql .= " WHERE fk_prelevementpf_bons = ".$this->id;

					if (!$this->db->query($sql)) {
						dol_syslog(get_class($this)."::set_infocredit Update lines Error");
						$error++;
					}
				}
			} else {
				$this->error = $this->db->lasterror();
				dol_syslog(get_class($this)."::set_infocredit Update Bons Error");
				$error++;
			}

			/*
			 * End of procedure
			 */
			if ($error == 0)
			{
				$this->date_credit = $date;
				$this->statut = self::STATUS_CREDITED;

				$this->db->commit();
				return 0;
			} else {
				$this->db->rollback();
				return -1;
			}
		} else {
			return -1026;
		}
	}

	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
	/**
	 *	Set withdrawal to transmited status
	 *
	 *	@param	User		$user		id of user
	 *	@param 	int	$date		date of action
	 *	@param	string		$method		method of transmision to bank
	 *	@return	int						>0 if OK, <0 if KO
	 */
	public function set_infotrans($user, $date, $method)
	{
		// phpcs:enable
		global $conf, $langs;

		$error = 0;

		dol_syslog(get_class($this)."::set_infotrans Start", LOG_INFO);
		if ($this->db->begin())
		{
			$sql = "UPDATE ".MAIN_DB_PREFIX."prelevementpf_bons ";
			$sql .= " SET fk_user_trans = ".$user->id;
			$sql .= " , date_trans = '".$this->db->idate($date)."'";
			$sql .= " , method_trans = ".$method;
			$sql .= " , statut = ".self::STATUS_TRANSFERED;
			$sql .= " WHERE rowid = ".$this->id;
			$sql .= " AND entity = ".$conf->entity;
			$sql .= " AND statut = 0";

			if ($this->db->query($sql))
			{
				$this->method_trans = $method;
				$langs->load('withdrawals');
				$subject = $langs->trans("InfoTransSubject", $this->ref);
				$message = $langs->trans("InfoTransMessage", $this->ref, dolGetFirstLastname($user->firstname, $user->lastname));
				$message .= $langs->trans("InfoTransData", price($this->amount), $this->methodes_trans[$this->method_trans], dol_print_date($date, 'day'));

				// TODO Call trigger to create a notification using notification module
			} else {
				$error++;
			}

			if ($error == 0)
			{
				$this->date_trans = $date;
				$this->statut = 1;
				$this->user_trans = $user->id;
				$this->db->commit();

				return 0;
			} else {
				$this->db->rollback();
				dol_syslog(get_class($this)."::set_infotrans ROLLBACK", LOG_ERR);

				return -1;
			}
		} else {
			dol_syslog(get_class($this)."::set_infotrans Ouverture transaction SQL impossible", LOG_CRIT);
			return -2;
		}
	}

	/**
	 *	Get invoice list
	 *
	 *  @param 	int		$amounts 	If you want to get the amount of the order for each invoice
	 *	@return	array 				Id of invoices
	 */
	private function getListInvoices($amounts = 0)
	{
		global $conf;

		$arr = array();

		/*
		 * Returns all invoices presented within same order
		 */
		$sql = "SELECT ";
		if ($this->type == 'bank-transfer') {
			$sql .= " pf.fk_facture_fourn";
		} else {
			$sql .= " pf.fk_facture";
		}
		if ($amounts) $sql .= ", SUM(pl.amount)";
		$sql .= " FROM ".MAIN_DB_PREFIX."prelevementpf_bons as p";
		$sql .= " , ".MAIN_DB_PREFIX."prelevementpf_lignes as pl";
		$sql .= " , ".MAIN_DB_PREFIX."prelevementpf_facture as pf";
		$sql .= " WHERE pf.fk_prelevementpf_lignes = pl.rowid";
		$sql .= " AND pl.fk_prelevementpf_bons = p.rowid";
		$sql .= " AND p.rowid = ".$this->id;
		$sql .= " AND p.entity = ".$conf->entity;
		if ($amounts) {
			if ($this->type == 'bank-transfer') {
				$sql .= " GROUP BY fk_facture_fourn";
			} else {
				$sql .= " GROUP BY fk_facture";
			}
		}

		$resql = $this->db->query($sql);
		if ($resql)
		{
			$num = $this->db->num_rows($resql);

			if ($num)
			{
				$i = 0;
				while ($i < $num)
				{
					$row = $this->db->fetch_row($resql);
					if (!$amounts) $arr[$i] = $row[0];
					else {
						$arr[$i] = array(
							$row[0],
							$row[1]
						);
					}
					$i++;
				}
			}
			$this->db->free($resql);
		} else {
			dol_syslog(get_class($this)."::getListInvoices Erreur");
		}

		return $arr;
	}

	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
	/**
	 *	Returns amount waiting for direct debit payment or credit transfer payment
	 *
	 *	@param	string	$mode		'direct-debit' or 'bank-transfer'
	 *	@return	double	 			<O if KO, Total amount
	 */
	public function SommeAPrelever($mode = 'direct-debit')
	{
		// phpcs:enable
		global $conf;

		$sql = "SELECT sum(pfd.amount) as nb";
		if ($mode != 'bank-transfer') {
			$sql .= " FROM ".MAIN_DB_PREFIX."facture as f,";
		} else {
			$sql .= " FROM ".MAIN_DB_PREFIX."facture_fourn as f,";
		}
		$sql .= " ".MAIN_DB_PREFIX."prelevementpf_facture_demande as pfd";
		$sql .= " WHERE f.entity IN (".getEntity('invoice').")";
		if (empty($conf->global->WITHDRAWAL_ALLOW_ANY_INVOICE_STATUS))
		{
			$sql .= " AND f.fk_statut = ".Facture::STATUS_VALIDATED;
		}
		if ($mode != 'bank-transfer') {
			$sql .= " AND f.rowid = pfd.fk_facture";
		} else {
			$sql .= " AND f.rowid = pfd.fk_facture_fourn";
		}
		$sql .= " AND f.paye = 0";
		$sql .= " AND pfd.traite = 0";
		$sql .= " AND pfd.ext_payment_id IS NULL";
		$sql .= " AND f.total_ttc > 0";

		$resql = $this->db->query($sql);
		if ($resql)
		{
			$obj = $this->db->fetch_object($resql);

			$this->db->free($resql);

			return $obj->nb;
		} else {
			$error = 1;
			dol_syslog(get_class($this)."::SommeAPrelever Erreur -1");
			dol_syslog($this->db->error());

			return -1;
		}
	}

	/**
	 *	Get number of invoices waiting for payment
	 *
	 *	@param	string	$mode		'direct-debit' or 'bank-transfer'
	 *	@return	int					<O if KO, number of invoices if OK
	 */
	public function nbOfInvoiceToPay($mode = 'direct-debit')
	{
		return $this->NbFactureAPrelever($mode);
	}

	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
	/**
	 *	Get number of invoices to pay
	 *
	 *	@param	string	$type		'direct-debit' or 'bank-transfer'
	 *	@return	int					<O if KO, number of invoices if OK
	 */
	public function NbFactureAPrelever($type = 'direct-debit')
	{
		// phpcs:enable
		global $conf;

		$sql = "SELECT count(f.rowid) as nb";
		if ($type == 'bank-transfer') {
			$sql .= " FROM ".MAIN_DB_PREFIX."facture_fourn as f";
		} else {
			$sql .= " FROM ".MAIN_DB_PREFIX."facture as f";
		}
		$sql .= ", ".MAIN_DB_PREFIX."prelevementpf_facture_demande as pfd";
		$sql .= " WHERE f.entity IN (".getEntity('invoice').")";
		if (empty($conf->global->WITHDRAWAL_ALLOW_ANY_INVOICE_STATUS))
		{
			$sql .= " AND f.fk_statut = ".Facture::STATUS_VALIDATED;
		}
		if ($type == 'bank-transfer') {
			$sql .= " AND f.rowid = pfd.fk_facture_fourn";
		} else {
			$sql .= " AND f.rowid = pfd.fk_facture";
		}
		$sql .= " AND pfd.traite = 0";
		$sql .= " AND pfd.ext_payment_id IS NULL";
		$sql .= " AND f.total_ttc > 0";

		dol_syslog(get_class($this)."::NbFactureAPrelever");
		$resql = $this->db->query($sql);

		if ($resql)
		{
			$obj = $this->db->fetch_object($resql);

			$this->db->free($resql);

			return $obj->nb;
		} else {
			$this->error = get_class($this)."::NbFactureAPrelever Erreur -1 sql=".$this->db->error();
			return -1;
		}
	}


	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
	/**
	 *	Create a direct debit order or a credit transfer order
	 *  TODO delete params banque and agence when not necessary
	 *
	 *	@param 	int		$banque			dolibarr mysoc bank
	 *	@param	int		$agence			dolibarr mysoc bank office (guichet)
	 *	@param	string	$mode			real=do action, simu=test only
	 *  @param	string	$format			FRST, RCUR or ALL
	 *  @param  string  $executiondate	Date to execute the transfer
	 *  @param	int	    $notrigger		Disable triggers
	 *  @param	string	$type			'direct-debit' or 'bank-transfer'
	 *	@return	int						<0 if KO, No of invoice included into file if OK
	 */
	public function create($banque = 0, $agence = 0, $mode = 'real', $format = 'ALL', $executiondate = '', $notrigger = 0, $type = 'direct-debit')
	{
		// phpcs:enable
		global $conf, $langs, $user;

		dol_syslog(__METHOD__."::Bank=".$banque." Office=".$agence." mode=".$mode." format=".$format, LOG_DEBUG);

		require_once DOL_DOCUMENT_ROOT."/compta/facture/class/facture.class.php";
		require_once DOL_DOCUMENT_ROOT."/societe/class/societe.class.php";

		if ($type != 'bank-transfer') {
			if (empty($format)) {
				$this->error = 'ErrorBadParametersForDirectDebitFileCreate';
				return -1;
			}
		}

		$error = 0;

		$datetimeprev = time();
		//Choice the date of the execution direct debit
		if (!empty($executiondate)) $datetimeprev = $executiondate;

		$month = strftime("%m", $datetimeprev);
		$year = strftime("%Y", $datetimeprev);

		$this->invoice_in_error = array();
		$this->thirdparty_in_error = array();

		// Read invoices
		$factures = array();
		$factures_prev = array();
		$factures_result = array();
		$factures_prev_id = array();
		$factures_prev_amount = array();
		$factures_errors = array();
		
		$t_bankbons = array();

		$t_prelevementbank = prelevementpf_getprelevementbank();
		$t_companybank = []; // company account
		$t_customerbank = [];    // customer account
		foreach( $t_prelevementbank as $pb ){
			if($pb->fk_bank_account){
				$t_companybank[ $b->banque_prelevement ] = $pb->rowid;
				foreach( $pb->prelevementbank as $b ){
					$t_customerbank[ $b->code ] = $pb->rowid;
				}
			}
		}

		// Get all invoices in demand 
		if (!$error)
		{
			$sql = "SELECT f.rowid, pfd.rowid as pfdrowid, f.fk_soc";
			$sql .= ", pfd.code_banque, pfd.code_guichet, pfd.number, pfd.cle_rib";
			$sql .= ", pfd.amount";
			$sql .= ", s.nom as name";
			if ($type != 'bank-transfer') {
				$sql .= " FROM ".MAIN_DB_PREFIX."facture as f";
			} else {
				$sql .= " FROM ".MAIN_DB_PREFIX."facture_fourn as f";
			}
			$sql .= ", ".MAIN_DB_PREFIX."societe as s";
			$sql .= ", ".MAIN_DB_PREFIX."prelevementpf_facture_demande as pfd";
			$sql .= " WHERE f.entity IN (".getEntity('invoice').')';
			if ($type != 'bank-transfer') {
				$sql .= " AND f.rowid = pfd.fk_facture";
			} else {
				$sql .= " AND f.rowid = pfd.fk_facture_fourn";
			}
			$sql .= " AND s.rowid = f.fk_soc";
			$sql .= " AND f.fk_statut = 1"; // Invoice validated
			$sql .= " AND f.paye = 0";
			$sql .= " AND pfd.traite = 0";
			$sql .= " AND f.total_ttc > 0";
			$sql .= " AND pfd.ext_payment_id IS NULL";

			dol_syslog(__METHOD__."::Read invoices, sql=".$sql, LOG_DEBUG);

			$resql = $this->db->query($sql);
			if ($resql)
			{
				$num = $this->db->num_rows($resql);
				$i = 0;

				while ($i < $num)
				{
					$row = $this->db->fetch_row($resql);
					$factures[$i] = $row; // All fields
					if ($row[7] == 0) {
						$error++;
						dol_syslog(__METHOD__."::Read invoices error Found a null invoice", LOG_ERR);
						$this->invoice_in_error[$row[0]] = "Error for invoice id ".$row[0].", found a null amount";
						break;
					}
					$i++;
				}
				$this->db->free($resql);
				dol_syslog(__METHOD__."::Read invoices, ".$i." invoices to withdraw", LOG_DEBUG);
			} else {
				$error++;
				dol_syslog(__METHOD__."::Read invoices error ".$this->db->error(), LOG_ERR);
			}
		}

		// Check invoices informations : RIB, IBAN
		if (!$error)
		{
			require_once DOL_DOCUMENT_ROOT.'/societe/class/companybankaccount.class.php';
			$soc = new Societe($this->db);

			// Check BAN
			$i = 0;
			dol_syslog(__METHOD__."::Check BAN", LOG_DEBUG);

			if (count($factures) > 0)
			{
				foreach ($factures as $key => $fac)
				{
					if ($type != 'bank-transfer') {
						$tmpinvoice = new Facture($this->db);
					} else {
						$tmpinvoice = new FactureFournisseur($this->db);
					}
					$resfetch = $tmpinvoice->fetch($fac[0]);
					if ($resfetch >= 0)		// Field 0 of $fac is rowid of invoice
					{
						if ($soc->fetch($tmpinvoice->socid) >= 0)
						{
							$bac = new CompanyBankAccount($this->db);
							$bac->fetch(0, $soc->id);

							if ($type != 'bank-transfer') {
								if ($format == 'FRST' && $bac->frstrecur != 'FRST')
								{
									continue;
								}
								if ($format == 'RCUR' && ($bac->frstrecur != 'RCUR' && $bac->frstrecur != 'RECUR'))
								{
									continue;
								}
							}

							if ( prelevementpf_checkBanForAccount($bac) )
							{
								$t_rib = prelevementpf_parseRIB( trim($bac->code_banque).trim($bac->code_guichet).trim($bac->number).trim($bac->cle) );
								
								if( isset($t_customerbank[ $t_rib['code_banque'] ]) ){
									$code_banque = $t_prelevementbank[ $t_customerbank[ $t_rib['code_banque'] ] ]->banque_prelevement;
									if( !isset($factures_prev[ $code_banque ]) ) $factures_prev[ $code_banque ] = [];
									if( !isset($factures_prev_id[ $code_banque ]) ) $factures_prev_id[ $code_banque ] = [];
									if( !isset($factures_prev_amount[ $code_banque ]) ) $factures_prev_amount[ $code_banque ] = 0;
									$factures_prev[ $code_banque ][] = $fac;
									/* second array necessary for BonPrelevement */
									$factures_prev_id[ $code_banque ][] = $fac[0];
									$factures_prev_amount[ $code_banque ] += $fac[7];
									$i++;
									//dol_syslog(__METHOD__."::RIB is ok", LOG_DEBUG);
								} else {
									dol_syslog(__METHOD__."::Check Bank Code Error on bank is not taken into account ".$tmpinvoice->socid." ".$soc->name, LOG_WARNING);
								}
							} else {
								dol_syslog(__METHOD__."::Check BAN Error on default bank number BAN for thirdparty reported by prelevementpf_checkBanForAccount() ".$tmpinvoice->socid." ".$soc->name, LOG_WARNING);
								$this->invoice_in_error[$fac[0]] = "Error on default bank number BAN for invoice ".$tmpinvoice->getNomUrl(0)." for thirdparty ".$soc->getNomUrl(0);
								$this->thirdparty_in_error[$soc->id] = "Error on default bank number BAN for invoice ".$tmpinvoice->getNomUrl(0)." for thirdparty ".$soc->getNomUrl(0);
							}
						} else {
							dol_syslog(__METHOD__."::Check BAN Failed to read company", LOG_WARNING);
						}
					} else {
						dol_syslog(__METHOD__."::Check BAN Failed to read invoice", LOG_WARNING);
					}
				}
			} else {
				dol_syslog(__METHOD__."::Check BAN No invoice to process", LOG_WARNING);
			}
		}

		$ok = 0;

		// Withdraw invoices in factures_prev array
		$out = $i." invoices will be included.";
		//print $out."\n";
		dol_syslog($out);

		// Return warning
		/*$i=0;
		 foreach ($this->thirdparty_in_error as $key => $val)
		 {
		 if ($i < 10) setEventMessages($val, null, 'warnings');
		 else setEventMessages('More error were discarded...', null, 'warnings');
		 $i++;
		 }*/

		if (count($factures_prev) > 0)
		{
			if ($mode == 'real') {
				$ok = 1;
			} else {
				print $langs->trans("ModeWarning"); // "Option for real mode was not set, we stop after this simulation\n";
			}
		}

		if ($ok)
		{
			/*
			 * We are in real mode.
			 * We create order and build file into disk
			 */
			$this->db->begin();

			$now = dol_now();

			/*
			 * Process order generation
			 */
			if (!$error)
			{
				foreach($factures_prev as $code_banque=>$prev){

					$ref = substr($year, -2).$month;

					$sql = "SELECT substring(ref from char_length(ref) - 1)";
					$sql .= " FROM ".MAIN_DB_PREFIX."prelevementpf_bons";
					$sql .= " WHERE ref LIKE '%".$this->db->escape($ref)."%'";
					$sql .= " AND entity = ".$conf->entity;
					$sql .= " ORDER BY ref DESC LIMIT 1";

					dol_syslog(get_class($this)."::create sql=".$sql, LOG_DEBUG);
					$resql = $this->db->query($sql);

					if ($resql)
					{
						$row = $this->db->fetch_row($resql);
						$ref = "T".$ref.str_pad(dol_substr("00".intval($row[0]) + 1, 0, 2), 2, "0", STR_PAD_LEFT);

						if ($type != 'bank-transfer') {
							$dir = $conf->prelevementpf->dir_output.'/receipts';
						} else {
							$dir = $conf->paymentbybanktransfer->dir_output.'/receipts';
						}
						if (!is_dir($dir)) dol_mkdir($dir);

						$this->filename = $dir.'/'.$ref.'.xml';
						$r_prelevementbank = $t_prelevementbank[$t_customerbank[ $code_banque ]];

						// Create withdraw receipt in database
						$sql = "INSERT INTO ".MAIN_DB_PREFIX."prelevementpf_bons (";
						$sql .= "ref, entity, datec, type, amount";
						$sql .= ", code_banque, code_guichet, numero_compte, cle_rib";
						$sql .= ", fk_prelevementbank";
						$sql .= ") VALUES (";
						$sql .= "'".$this->db->escape($ref)."'";
						$sql .= ", ".$conf->entity;
						$sql .= ", '".$this->db->idate($now)."'";
						$sql .= ", '".($type == 'bank-transfer' ? 'bank-transfer' : 'debit-order')."'";
						$sql .= ", '".price2num($factures_prev_amount[ $code_banque ])."'";
						$sql .= ", '".$code_banque."', '".$r_prelevementbank->code_guichet."', '".$r_prelevementbank->account_number."', '".$r_prelevementbank->cle_rib."'";
						$sql .= ", ".$t_customerbank[ $code_banque ];
						$sql .= ")";


						$resql = $this->db->query($sql);
						if ($resql)
						{
							$prev_id = $this->db->last_insert_id(MAIN_DB_PREFIX."prelevementpf_bons");
							$t_bankbons[$code_banque] = ['id' => $prev_id, 'ref' => $ref];
						} else {
							$error++;
							dol_syslog(__METHOD__."::Create withdraw receipt ".$this->db->lasterror(), LOG_ERR);
						}
					} else {
						$error++;
						dol_syslog(__METHOD__."::Get last withdraw receipt ".$this->db->lasterror(), LOG_ERR);
					}
				}
			}

			if (!$error)
			{
				if ($type != 'bank-transfer') {
					$fact = new Facture($this->db);
				} else {
					$fact = new FactureFournisseur($this->db);
				}

				/*
				 * Create withdrawal receipt in database
				 */
				if (count($factures_prev) > 0)
				{
					foreach($factures_prev as $code_banque=>$prev){

						$this->id = $t_bankbons[$code_banque]['id'];
						$this->ref = $t_bankbons[$code_banque]['ref'];

						foreach ($prev as $fac)	// Add a link in database for each invoice
						{
							// Fetch invoice
							$result = $fact->fetch($fac[0]);
							if ($result < 0) {
								$this->error = 'ERRORBONPRELEVEMENT Failed to load invoice with id '.$fac[0];
								break;
							}

							/*
							* Add standing order. This add record into llx_prelevementpf_lignes
							*
							* $fac[0] : invoice_id
							* $fac[1] : ???
							* $fac[2] : third party id
							* $fac[3] : banque
							* $fac[4] : guichet
							* $fac[5] : number
							* $fac[6] : cle rib
							* $fac[7] : amount
							* $fac[8] : client nom
							*/
							$ri = $this->AddFacture($fac[0], $fac[2], $fac[8], $fac[7], $fac[3], $fac[4], $fac[5], $fac[6], $type);
							if ($ri <> 0)
							{
								$error++;
							}

							// Update invoice requests as done
							$sql = "UPDATE ".MAIN_DB_PREFIX."prelevementpf_facture_demande";
							$sql .= " SET traite = 1";
							$sql .= ", date_traite = '".$this->db->idate($now)."'";
							$sql .= ", fk_prelevementpf_bons = ".$this->id;
							$sql .= " WHERE rowid = ".$fac[1];

							$resql = $this->db->query($sql);
							if (!$resql)
							{
								$error++;
								$this->errors[] = $this->db->lasterror();
								dol_syslog(__METHOD__."::Update Error=".$this->db->lasterror(), LOG_ERR);
							}
						}
					}
				}
			}

			if (!$error)
			{
				/*
				 * Create file of type='direct-debit' for direct debit order or type='bank-transfer' for credit transfer into a XML file
				 */

				foreach( $factures_prev as $code_banque=>$prev){
					dol_syslog(__METHOD__."::Init direct debit or credit transfer file for ".count($prev)." invoices", LOG_DEBUG);
	
					if (count($prev) > 0)
					{
						$this->fetch( $t_bankbons[$code_banque]['id'] );

						$this->date_echeance = $datetimeprev;
						$this->reference_remise = $this->ref;

						$id = $t_prelevementbank[ $t_companybank[$code_banque] ]->rowid;
						if ($type == 'bank-transfer') {
//							$id = $conf->global->PAYMENTBYBANKTRANSFER_ID_BANKACCOUNT;
						}

						$this->factures = $factures_prev_id[$code_banque];
						$this->context['factures_prev'] = $prev;

						// Generation of direct debit or credti transfer file $this->filename (May be a SEPA file for european countries)
						// This also set the property $this->total with amount that is included into file
						$result = $this->generate($format, $executiondate, $type);
						if ($result < 0) {
							/*var_dump($this->error);
							var_dump($this->invoice_in_error); */
							$error++;
						}
					}
					dol_syslog(__METHOD__."::End withdraw receipt, file ".$this->filename, LOG_DEBUG);
					
				}
			}
			//var_dump($this->total);exit;


			if (!$error && !$notrigger)
			{
				$triggername = 'DIRECT_DEBIT_ORDER_CREATE';
				if ($type != 'bank-transfer') {
					$triggername = 'CREDIT_TRANSFER_ORDER_CREATE';
				}

				// Call trigger
				$result = $this->call_trigger($triggername, $user);
				if ($result < 0) $error++;
				// End call triggers
			}

			if (!$error)
			{
				$this->db->commit();
				return count($factures_prev);
			} else {
				$this->db->rollback();
				return -1;
			}
		} else {
			return 0;
		}
	}


	/**
	 *  Get object and lines from database
	 *
	 *  @param	User	$user		Object user that delete
	 *  @param	int		$notrigger	1=Does not execute triggers, 0= execute triggers
	 *  @return	int					>0 if OK, <0 if KO
	 */
	public function delete($user = null, $notrigger = 0)
	{
		$this->db->begin();

		$error = 0;
		$resql1 = $resql2 = $resql3 = $resql4 = 0;

		if (!$notrigger)
		{
			$triggername = 'DIRECT_DEBIT_ORDER_DELETE';
			if ($this->type == 'bank-transfer') {
				$triggername = 'PAYMENTBYBANKTRANFER_DELETE';
			}
			// Call trigger
			$result = $this->call_trigger($triggername, $user);
			if ($result < 0) $error++;
			// End call triggers
		}

		if (!$error)
		{
			$sql = "DELETE FROM ".MAIN_DB_PREFIX."prelevementpf_facture WHERE fk_prelevementpf_lignes IN (SELECT rowid FROM ".MAIN_DB_PREFIX."prelevementpf_lignes WHERE fk_prelevementpf_bons = ".$this->id.")";
			$resql1 = $this->db->query($sql);
			if (!$resql1) dol_print_error($this->db);
		}

		if (!$error)
		{
			$sql = "DELETE FROM ".MAIN_DB_PREFIX."prelevementpf_lignes WHERE fk_prelevementpf_bons = ".$this->id;
			$resql2 = $this->db->query($sql);
			if (!$resql2) dol_print_error($this->db);
		}

		if (!$error)
		{
			$sql = "DELETE FROM ".MAIN_DB_PREFIX."prelevementpf_bons WHERE rowid = ".$this->id;
			$resql3 = $this->db->query($sql);
			if (!$resql3) dol_print_error($this->db);
		}

		if (!$error)
		{
			$sql = "UPDATE ".MAIN_DB_PREFIX."prelevementpf_facture_demande SET fk_prelevementpf_bons = NULL, traite = 0 WHERE fk_prelevementpf_bons = ".$this->id;
			$resql4 = $this->db->query($sql);
			if (!$resql4) dol_print_error($this->db);
		}

		if ($resql1 && $resql2 && $resql3 && $resql4 && !$error)
		{
			$this->db->commit();
			return 1;
		} else {
			$this->db->rollback();
			return -1;
		}
	}


	/**
	 *	Returns clickable name (with picto)
	 *
	 *  @param  int     $withpicto                  Include picto in link (0=No picto, 1=Include picto into link, 2=Only picto)
	 *  @param  string  $option                     On what the link point to ('nolink', ...)
	 *  @param  int     $notooltip                  1=Disable tooltip
	 *  @param  string  $morecss                    Add more css on link
	 *  @param  int     $save_lastsearch_value      -1=Auto, 0=No save of lastsearch_values when clicking, 1=Save lastsearch_values whenclicking
	 *	@return	string								URL of target
	 */
	public function getNomUrl($withpicto = 0, $option = '', $notooltip = 0, $morecss = '', $save_lastsearch_value = -1)
	{
		global $conf, $langs, $hookmanager;

		if (!empty($conf->dol_no_mouse_hover)) $notooltip = 1; // Force disable tooltips

		$result = '';

		$labeltoshow = 'PaymentByDirectDebit';
		if ($this->type == 'bank-transfer') {
			$labeltoshow = 'PaymentByBankTransfer';
		}

		$label = '<u>'.$langs->trans($labeltoshow).'</u>';
		$label .= '<br>';
		$label .= '<b>'.$langs->trans('Ref').':</b> '.$this->ref;
		if (isset($this->statut)) {
			$label .= '<br><b>'.$langs->trans("Status").":</b> ".$this->getLibStatut(5);
		}

		$url = dol_buildpath('/prelevementpf/card.php',1).'?id='.$this->id;
		if ($this->type == 'bank-transfer') {
			$url = dol_buildpath('/prelevementpf/card.php',1).'?id='.$this->id;
		}

		if ($option != 'nolink')
		{
			// Add param to save lastsearch_values or not
			$add_save_lastsearch_values = ($save_lastsearch_value == 1 ? 1 : 0);
			if ($save_lastsearch_value == -1 && preg_match('/list\.php/', $_SERVER["PHP_SELF"])) $add_save_lastsearch_values = 1;
			if ($add_save_lastsearch_values) $url .= '&save_lastsearch_values=1';
		}

		$linkclose = '';
		if (empty($notooltip))
		{
			if (!empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER))
			{
				$label = $langs->trans("ShowMyObject");
				$linkclose .= ' alt="'.dol_escape_htmltag($label, 1).'"';
			}
			$linkclose .= ' title="'.dol_escape_htmltag($label, 1).'"';
			$linkclose .= ' class="classfortooltip'.($morecss ? ' '.$morecss : '').'"';

			/*
			 $hookmanager->initHooks(array('myobjectdao'));
			 $parameters=array('id'=>$this->id);
			 $reshook=$hookmanager->executeHooks('getnomurltooltip',$parameters,$this,$action);    // Note that $action and $object may have been modified by some hooks
			 if ($reshook > 0) $linkclose = $hookmanager->resPrint;
			 */
		} else $linkclose = ($morecss ? ' class="'.$morecss.'"' : '');

		$linkstart = '<a href="'.$url.'"';
		$linkstart .= $linkclose.'>';
		$linkend = '</a>';

		$result .= $linkstart;
		if ($withpicto) $result .= img_object(($notooltip ? '' : $label), ($this->picto ? $this->picto : 'generic'), ($notooltip ? (($withpicto != 2) ? 'class="paddingright"' : '') : 'class="'.(($withpicto != 2) ? 'paddingright ' : '').'classfortooltip"'), 0, 0, $notooltip ? 0 : 1);
		if ($withpicto != 2) $result .= $this->ref;
		$result .= $linkend;
		//if ($withpicto != 2) $result.=(($addlabel && $this->label) ? $sep . dol_trunc($this->label, ($addlabel > 1 ? $addlabel : 0)) : '');

		global $action, $hookmanager;
		$hookmanager->initHooks(array('banktransferdao'));
		$parameters = array('id'=>$this->id, 'getnomurl'=>$result);
		$reshook = $hookmanager->executeHooks('getNomUrl', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks
		if ($reshook > 0) $result = $hookmanager->resPrint;
		else $result .= $hookmanager->resPrint;

		return $result;
	}


	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
	/**
	 *	Delete a notification def by id
	 *
	 *	@param	int		$rowid		id of notification
	 *	@return	int					0 if OK, <0 if KO
	 */
	public function DeleteNotificationById($rowid)
	{
		// phpcs:enable
		$result = 0;

		$sql = "DELETE FROM ".MAIN_DB_PREFIX."notify_def";
		$sql .= " WHERE rowid = ".((int) $rowid);

		if ($this->db->query($sql))
		{
			return 0;
		} else {
			return -1;
		}
	}

	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
	/**
	 *	Delete a notification
	 *
	 *	@param	int	$user		notification user
	 *	@param	string	$action		notification action
	 *	@return	int					>0 if OK, <0 if KO
	 */
	public function DeleteNotification($user, $action)
	{
		// phpcs:enable
		$result = 0;

		$sql = "DELETE FROM ".MAIN_DB_PREFIX."notify_def";
		$sql .= " WHERE fk_user=".$user." AND fk_action='".$this->db->escape($action)."'";

		if ($this->db->query($sql))
		{
			return 0;
		} else {
			return -1;
		}
	}

	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
	/**
	 *	Add a notification
	 *
	 *	@param	DoliDB	$db			database handler
	 *	@param	int	$user		notification user
	 *	@param	string	$action		notification action
	 *	@return	int					0 if OK, <0 if KO
	 */
	public function AddNotification($db, $user, $action)
	{
		// phpcs:enable
		$result = 0;

		if ($this->DeleteNotification($user, $action) == 0)
		{
			$now = dol_now();

			$sql = "INSERT INTO ".MAIN_DB_PREFIX."notify_def (datec,fk_user, fk_soc, fk_contact, fk_action)";
			$sql .= " VALUES ('".$this->db->idate($now)."', ".$user.", 'NULL', 'NULL', '".$this->db->escape($action)."')";

			dol_syslog("adnotiff: ".$sql);
			if ($this->db->query($sql))
			{
				$result = 0;
			} else {
				$result = -1;
				dol_syslog(get_class($this)."::AddNotification Error $result");
			}
		}

		return $result;
	}

	/**
	 *    Return status label of object
	 *
	 *    @param    int		$mode   0=Label, 1=Picto + label, 2=Picto, 3=Label + Picto
	 * 	  @return	string     		Label
	 */
	public function getLibStatut($mode = 0)
	{
		return $this->LibStatut($this->statut, $mode);
	}

	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
	/**
	 *  Return status label for a status
	 *
	 *  @param	int		$status     Id status
	 *  @param  int		$mode       0=long label, 1=short label, 2=Picto + short label, 3=Picto, 4=Picto + long label, 5=Short label + Picto, 6=Long label + Picto
	 * 	@return	string  		    Label
	 */
	public function LibStatut($status, $mode = 0)
	{
		// phpcs:enable
		if (empty($this->labelStatus) || empty($this->labelStatusShort))
		{
			global $langs;
			//$langs->load("mymodule");
			$this->labelStatus[self::STATUS_DRAFT] = $langs->trans('StatusWaiting');
			$this->labelStatus[self::STATUS_TRANSFERED] = $langs->trans('StatusTrans');
			$this->labelStatus[self::STATUS_CREDITED] = $langs->trans('StatusCredited');
			$this->labelStatusShort[self::STATUS_DRAFT] = $langs->trans('StatusWaiting');
			$this->labelStatusShort[self::STATUS_TRANSFERED] = $langs->trans('StatusTrans');
			$this->labelStatusShort[self::STATUS_CREDITED] = $langs->trans('StatusCredited');
		}

		$statusType = 'status1';
		if ($status == self::STATUS_TRANSFERED) $statusType = 'status3';
		if ($status == self::STATUS_CREDITED) $statusType = 'status6';

		return dolGetStatus($this->labelStatus[$status], $this->labelStatusShort[$status], '', $statusType, $mode);
	}



  /******************************************************************************* */
  /**
   * Creer le fichier de prelevement
   */
  public function generate($format = 'ALL', $executiondate = '', $type = 'direct-debit'){
   
	$r_prelevement = dbFetchOnce(
	  'SELECT p.* '
	  .', pb.libelle_compte, pb.file_prelevement, pb.file_rejet '	
	  .'FROM (SELECT p0.* FROM '.MAIN_DB_PREFIX.'prelevementpf_bons AS p0 WHERE p0.rowid='.$this->id.') AS p '
	  .'JOIN '.MAIN_DB_PREFIX.'prelevementpf_prelevementbank AS pb ON pb.rowid=p.fk_prelevementbank'
    );

    $tr_prelevementdet = dbFetch(
	  'SELECT pl.rowid AS fk_prelevementpf_lignes '
	  .', pl.fk_soc, pl.client_nom, pl.amount '
	  .', pl.code_banque, pl.code_guichet, pl.number AS numero_compte, pl.cle_rib '
	  .', GROUP_CONCAT(f.ref) AS refs_facture '
	  .'FROM (SELECT pl0.* FROM '.MAIN_DB_PREFIX.'prelevementpf_lignes AS pl0 WHERE pl0.fk_prelevementpf_bons='.$this->id.') AS pl '
	  .'JOIN '.MAIN_DB_PREFIX.'prelevementpf_facture AS pf ON pf.fk_prelevementpf_lignes=pl.rowid '
	  .'JOIN '.MAIN_DB_PREFIX.'facture AS f ON pf.fk_facture=f.rowid '
	  .'GROUP BY pl.rowid'
	);


	foreach($tr_prelevementdet as $kdet=>$pdet){
		$tr_prelevementdet[$kdet]->client_ref = $this->gen_ref_client($pdet);
		$t_rib = prelevementpf_parseRIB( trim($pdet->code_banque).trim($pdet->code_guichet).trim($pdet->numero_compte).trim($pdet->cle_rib) );
		dol_syslog(trim($pdet->code_banque).trim($pdet->code_guichet).trim($pdet->numero_compte).trim($pdet->cle_rib)." - ".$t_rib, LOG_ERR);///
		$tr_prelevementdet[$kdet]->code_banque = $t_rib['code_banque'];
		$tr_prelevementdet[$kdet]->code_guichet = $t_rib['code_guichet'];
		$tr_prelevementdet[$kdet]->numero_compte = $t_rib['account_number'];
		$tr_prelevementdet[$kdet]->cle_rib = $t_rib['cle_rib'];
		$tr_prelevementdet[$kdet]->libelle = $this->gen_libelle($pdet);
	}

    // generation du contenu du fichier
    $gen = '';
    if($r_prelevement && $tr_prelevementdet){
      $gen.= $this->_genPrelevementLineEmetteur($r_prelevement);
      $gen.= $this->_genPrelevementLineDestinataire($tr_prelevementdet);
      $gen.= $this->_genPrelevementLineTotal($r_prelevement, $tr_prelevementdet);
    }

    // generation du fichier de prelevement
    $filepath = $this->gen_filepath_prelevement($r_prelevement);
	$relativepath = $this->gen_filepath_prelevement($r_prelevement,0);
	
	$updateBon = doQuery('UPDATE '.MAIN_DB_PREFIX.'prelevementpf_bons SET file_prelevement="'.$relativepath.'" WHERE rowid='.$this->id);
    create_file_text($filepath,$gen);
	
    return $relativepath;
  }

  /**
   * Genere la premiere ligne de prelevement : Emetteur
   */
  private function _genPrelevementLineEmetteur($t_data){
    global $mysoc;

    $line = '';

    $line .= self::CODE_ENREGISTREMENT_EMETTEUR;  // code enregistrement
    $line .= self::CODE_OPERATION;  // code operation
    $line .= sprintf("%8s",'');  // inutilise
    $line .= sprintf("%6.6d",$this->emetteur_nne);  // numero emetteur
    $line .= sprintf("%6.6s",date('ymd',$this->datec));  // date execution
    $line .= sprintf("%1s",'');  // inutilise
    $line .= sprintf("%5.5s",date('dm',$this->date_echeance).(date('y',$this->date_echeance)%10));  // date echeance : ddmmy
    $line .= sprintf("%-24.24s",$mysoc->name);  // raison sociale du donneur d ordre
    $line .= sprintf("%24s",'');  // inutilise
    $line .= sprintf("%8s",'');  // inutilise
    $line .= sprintf("%5.5s",$this->emetteur_code_guichet);  // code guichet
    $line .= sprintf("%11.11s",$this->emetteur_numero_compte);  // numero de compte
    $line .= sprintf("%16s",'');  // inutilise
    $line .= sprintf("%31s",'');  // inutilise
    $line .= sprintf("%5.5s",$this->emetteur_code_banque);  // code etablissement
    $line .= sprintf("%6s",'');  // inutilise
    $line .= "\r\n";

    return $line;
  }

  /**
   * Genere la premiere ligne de prelevement : Emetteur
   */
  private function _genPrelevementLineDestinataire($t_data_destinataire){
    $line = '';

    foreach ($t_data_destinataire as $data){
      $line .= self::CODE_ENREGISTREMENT_DESTINATAIRE;  // code enregistrement
      $line .= self::CODE_OPERATION;  // code operation
      $line .= sprintf("%8s",'');  // inutilise
      $line .= sprintf("%6.6d",$this->emetteur_nne);  // numero emetteur
      $line .= sprintf("%'012.12s",$data->client_ref);  // ref destinataire
      $line .= sprintf("%-24.24s",utf8_decode($data->client_nom));  // nom destinataire
      $line .= sprintf("%-24.24s",'');  // domiciliation
      $line .= sprintf("%8s",'');  // inutilise
      $line .= sprintf("%5.5s",$data->code_guichet);  // code guichet
      $line .= sprintf("%11.11s",$data->numero_compte);  // numero de compte
      $line .= sprintf("%'014.14d00",$data->amount);  // montant
      $line .= sprintf("%-31.31s",$data->libelle);  // libelle
      $line .= sprintf("%5.5s",$data->code_banque);  // code etablissement
      $line .= sprintf("%6s",'');  // inutilise
      $line .= "\r\n";
    }

    return $line;
  }

  /**
   * Genere la premiere ligne de prelevement : Emetteur
   */
  private function _genPrelevementLineTotal($t_data, $t_data_destinataire){
    $line = '';

    $line .= self::CODE_ENREGISTREMENT_TOTAL;  // code enregistrement
    $line .= self::CODE_OPERATION;  // code operation
    $line .= sprintf("%8s",'');  // inutilise
    $line .= sprintf("%6.6d",$this->emetteur_nne);  // numero emetteur
    $line .= sprintf("%12s",'');  // inutilise
    $line .= sprintf("%24s",'');  // inutilise
    $line .= sprintf("%24s",'');  // inutilise
    $line .= sprintf("%8s",'');  // inutilise
    $line .= sprintf("%5s",count($t_data_destinataire));  // nombre d enregistrement
    $line .= sprintf("%11s",'');  // raison sociale du donneur d ordre
    $line .= sprintf("%'014.14d00",$this->amount);  // montant
    $line .= sprintf("%31s",'');  // inutilise
    $line .= sprintf("%5s",'');  // code etablissement
    $line .= sprintf("%6s",'');  // inutilise
    $line .= "\r\n";

    return $line;
  }

// --------------------------------------------------------------------------------

  /**
   * Genere la reference du destinataire
   */
  public function gen_ref_client($data){
    $ref = '';
    $ref.= 'C'.sprintf("%'011.11s", $data->fk_soc) ;

    return $ref;
  }

  /**
   * Genere la reference du destinataire
   */
  public function gen_libelle($data){
    $ref = 'L';

    $ref.= sprintf("%'011.11d", $data->fk_prelevementpf_lignes);

    return $ref;
  }

  /**
   * Genere le nom du fichier de prelevement
   * mode=0 : relative path
   * mode=1 : url path
   * none : file path
   */
  public function gen_filepath_prelevement($data, $mode=-1){
    $filepath = '';

    $t_replace = array(
      '%d' => date('d',strtotime($data->datec)),
      '%m' => date('m',strtotime($data->datec)),
      '%y' => date('y',strtotime($data->datec)),
      '%Y' => date('Y',strtotime($data->datec)),
    );

    $filename = str_replace(array_keys($t_replace), array_values($t_replace), $data->file_prelevement);

    // mode
    switch( $mode ){
		case 0 : // simple path
			$filepath = 'bon/'.$data->ref.'/'.$filename;
			break;
		case 1 : // url
			$filepath = DOL_MAIN_URL_ROOT.'/documents/prelevementpf/bon/'.$data->ref.'/'.$filename;
			break;
      default : // path
        $filepath = DOL_DATA_ROOT
			.DIRECTORY_SEPARATOR.'prelevementpf'
			.DIRECTORY_SEPARATOR.'bon'
			.DIRECTORY_SEPARATOR.$data->ref
            .DIRECTORY_SEPARATOR.$filename
        ;
        break;
	}
	

    return $filepath;
  }

// --------------------------------------------------------------------------------
  /**
   * Recupere les comptes emetteur
   */
  public function get_prelevement_bank(){
    $sql = 'SELECT *';
    $sql.= ' FROM '.MAIN_DB_PREFIX.'c_prelevement_bank';
    $sql.= ' WHERE active=1';
    $t_res = dbFetch($sql, 'code_banque');

    return $t_res;
  }

}
