paiementfourn.class.php 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914
  1. <?php
  2. /* Copyright (C) 2002-2004 Rodolphe Quiedeville <rodolphe@quiedeville.org>
  3. * Copyright (C) 2004-2007 Laurent Destailleur <eldy@users.sourceforge.net>
  4. * Copyright (C) 2005 Marc Barilley / Ocebo <marc@ocebo.com>
  5. * Copyright (C) 2005-2009 Regis Houssin <regis.houssin@inodbox.com>
  6. * Copyright (C) 2010-2011 Juanjo Menent <jmenent@2byte.es>
  7. * Copyright (C) 2014 Marcos García <marcosgdf@gmail.com>
  8. * Copyright (C) 2018 Nicolas ZABOURI <info@inovea-conseil.com>
  9. * Copyright (C) 2018 Frédéric France <frederic.francenetlogic.fr>
  10. * Copyright (C) 2023 Joachim Kueter <git-jk@bloxera.com>
  11. *
  12. * This program is free software; you can redistribute it and/or modify
  13. * it under the terms of the GNU General Public License as published by
  14. * the Free Software Foundation; either version 3 of the License, or
  15. * (at your option) any later version.
  16. *
  17. * This program is distributed in the hope that it will be useful,
  18. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  19. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  20. * GNU General Public License for more details.
  21. *
  22. * You should have received a copy of the GNU General Public License
  23. * along with this program. If not, see <https://www.gnu.org/licenses/>.
  24. */
  25. /**
  26. * \file htdocs/fourn/class/paiementfourn.class.php
  27. * \ingroup fournisseur, facture
  28. * \brief File of class to manage payments of suppliers invoices
  29. */
  30. require_once DOL_DOCUMENT_ROOT.'/compta/bank/class/account.class.php';
  31. require_once DOL_DOCUMENT_ROOT.'/compta/paiement/class/paiement.class.php';
  32. require_once DOL_DOCUMENT_ROOT.'/multicurrency/class/multicurrency.class.php';
  33. /**
  34. * Class to manage payments for supplier invoices
  35. */
  36. class PaiementFourn extends Paiement
  37. {
  38. /**
  39. * @var string ID to identify managed object
  40. */
  41. public $element = 'payment_supplier';
  42. /**
  43. * @var string Name of table without prefix where object is stored
  44. */
  45. public $table_element = 'paiementfourn';
  46. /**
  47. * @var string String with name of icon for myobject. Must be the part after the 'object_' into object_myobject.png
  48. */
  49. public $picto = 'payment';
  50. public $statut; //Status of payment. 0 = unvalidated; 1 = validated
  51. // fk_paiement dans llx_paiement est l'id du type de paiement (7 pour CHQ, ...)
  52. // fk_paiement dans llx_paiement_facture est le rowid du paiement
  53. /**
  54. * Label of payment type
  55. * @var string
  56. */
  57. public $type_label;
  58. /**
  59. * Code of Payment type
  60. * @var string
  61. */
  62. public $type_code;
  63. /**
  64. * @var string Id of prelevement
  65. */
  66. public $id_prelevement;
  67. /**
  68. * @var string num_prelevement
  69. */
  70. public $num_prelevement;
  71. /**
  72. * Constructor
  73. *
  74. * @param DoliDB $db Database handler
  75. */
  76. public function __construct($db)
  77. {
  78. $this->db = $db;
  79. }
  80. /**
  81. * Load payment object
  82. *
  83. * @param int $id Id if payment to get
  84. * @param string $ref Ref of payment to get
  85. * @param int $fk_bank Id of bank line associated to payment
  86. * @return int <0 if KO, -2 if not found, >0 if OK
  87. */
  88. public function fetch($id, $ref = '', $fk_bank = '')
  89. {
  90. $error = 0;
  91. $sql = 'SELECT p.rowid, p.ref, p.entity, p.datep as dp, p.amount, p.statut, p.fk_bank, p.multicurrency_amount,';
  92. $sql .= ' c.code as payment_code, c.libelle as payment_type,';
  93. $sql .= ' p.num_paiement as num_payment, p.note, b.fk_account, p.fk_paiement';
  94. $sql .= ' FROM '.MAIN_DB_PREFIX.'paiementfourn as p';
  95. $sql .= ' LEFT JOIN '.MAIN_DB_PREFIX.'c_paiement as c ON p.fk_paiement = c.id';
  96. $sql .= ' LEFT JOIN '.MAIN_DB_PREFIX.'bank as b ON p.fk_bank = b.rowid';
  97. $sql .= ' WHERE p.entity IN ('.getEntity('facture_fourn').')';
  98. if ($id > 0) {
  99. $sql .= ' AND p.rowid = '.((int) $id);
  100. } elseif ($ref) {
  101. $sql .= " AND p.ref = '".$this->db->escape($ref)."'";
  102. } elseif ($fk_bank > 0) {
  103. $sql .= ' AND p.fk_bank = '.((int) $fk_bank);
  104. }
  105. //print $sql;
  106. $resql = $this->db->query($sql);
  107. if ($resql) {
  108. $num = $this->db->num_rows($resql);
  109. if ($num > 0) {
  110. $obj = $this->db->fetch_object($resql);
  111. $this->id = $obj->rowid;
  112. $this->ref = $obj->ref;
  113. $this->entity = $obj->entity;
  114. $this->date = $this->db->jdate($obj->dp);
  115. $this->datepaye = $this->db->jdate($obj->dp);
  116. $this->num_payment = $obj->num_payment;
  117. $this->numero = $obj->num_payment;
  118. $this->bank_account = $obj->fk_account;
  119. $this->fk_account = $obj->fk_account;
  120. $this->bank_line = $obj->fk_bank;
  121. $this->montant = $obj->amount; // deprecated
  122. $this->amount = $obj->amount;
  123. $this->multicurrency_amount = $obj->multicurrency_amount;
  124. $this->note = $obj->note;
  125. $this->note_private = $obj->note;
  126. $this->type_code = $obj->payment_code;
  127. $this->type_label = $obj->payment_type;
  128. $this->fk_paiement = $obj->fk_paiement;
  129. $this->statut = $obj->statut;
  130. $error = 1;
  131. } else {
  132. $error = -2; // TODO Use 0 instead
  133. }
  134. $this->db->free($resql);
  135. } else {
  136. dol_print_error($this->db);
  137. $error = -1;
  138. }
  139. return $error;
  140. }
  141. /**
  142. * Create payment in database
  143. *
  144. * @param User $user Object of creating user
  145. * @param int $closepaidinvoices 1=Also close payed invoices to paid, 0=Do nothing more
  146. * @param Societe $thirdparty Thirdparty
  147. * @return int id of created payment, < 0 if error
  148. */
  149. public function create($user, $closepaidinvoices = 0, $thirdparty = null)
  150. {
  151. global $langs, $conf;
  152. $error = 0;
  153. $way = $this->getWay();
  154. $now = dol_now();
  155. // Clean parameters
  156. $totalamount = 0;
  157. $totalamount_converted = 0;
  158. $atleastonepaymentnotnull = 0;
  159. if ($way == 'dolibarr') {
  160. $amounts = &$this->amounts;
  161. $amounts_to_update = &$this->multicurrency_amounts;
  162. } else {
  163. $amounts = &$this->multicurrency_amounts;
  164. $amounts_to_update = &$this->amounts;
  165. }
  166. $currencyofpayment = '';
  167. foreach ($amounts as $key => $value) {
  168. if (empty($value)) {
  169. continue;
  170. }
  171. // $key is id of invoice, $value is amount, $way is a 'dolibarr' if amount is in main currency, 'customer' if in foreign currency
  172. $value_converted = Multicurrency::getAmountConversionFromInvoiceRate($key, $value ? $value : 0, $way, 'facture_fourn');
  173. // Add controls of input validity
  174. if ($value_converted === false) {
  175. // We failed to find the conversion for one invoice
  176. $this->error = 'FailedToFoundTheConversionRateForInvoice';
  177. return -1;
  178. }
  179. if (empty($currencyofpayment)) {
  180. $currencyofpayment = $this->multicurrency_code[$key];
  181. }
  182. if ($currencyofpayment != $this->multicurrency_code[$key]) {
  183. // If we have invoices with different currencies in the payment, we stop here
  184. $this->error = 'ErrorYouTryToPayInvoicesWithDifferentCurrenciesInSamePayment';
  185. return -1;
  186. }
  187. $totalamount_converted += $value_converted;
  188. $amounts_to_update[$key] = price2num($value_converted, 'MT');
  189. $newvalue = price2num($value, 'MT');
  190. $amounts[$key] = $newvalue;
  191. $totalamount += $newvalue;
  192. if (!empty($newvalue)) {
  193. $atleastonepaymentnotnull++;
  194. }
  195. }
  196. if (!empty($currencyofpayment)) {
  197. // We must check that the currency of invoices is the same than the currency of the bank
  198. $bankaccount = new Account($this->db);
  199. $bankaccount->fetch($this->fk_account);
  200. $bankcurrencycode = empty($bankaccount->currency_code) ? $conf->currency : $bankaccount->currency_code;
  201. if ($currencyofpayment != $bankcurrencycode && $currencyofpayment != $conf->currency && $bankcurrencycode != $conf->currency) {
  202. $langs->load("errors");
  203. $this->error = $langs->trans('ErrorYouTryToPayInvoicesInACurrencyFromBankWithAnotherCurrency', $currencyofpayment, $bankcurrencycode);
  204. return -1;
  205. }
  206. }
  207. $totalamount = price2num($totalamount);
  208. $totalamount_converted = price2num($totalamount_converted);
  209. dol_syslog(get_class($this)."::create", LOG_DEBUG);
  210. $this->db->begin();
  211. if ($totalamount <> 0) { // On accepte les montants negatifs
  212. $ref = $this->getNextNumRef(is_object($thirdparty) ? $thirdparty : '');
  213. if ($way == 'dolibarr') {
  214. $total = $totalamount;
  215. $mtotal = $totalamount_converted; // Maybe use price2num with MT for the converted value
  216. } else {
  217. $total = $totalamount_converted; // Maybe use price2num with MT for the converted value
  218. $mtotal = $totalamount;
  219. }
  220. $sql = 'INSERT INTO '.MAIN_DB_PREFIX.'paiementfourn (';
  221. $sql .= 'ref, entity, datec, datep, amount, multicurrency_amount, fk_paiement, num_paiement, note, fk_user_author, fk_bank)';
  222. $sql .= " VALUES ('".$this->db->escape($ref)."', ".((int) $conf->entity).", '".$this->db->idate($now)."',";
  223. $sql .= " '".$this->db->idate($this->datepaye)."', ".((float) $total).", ".((float) $mtotal).", ".((int) $this->paiementid).", '".$this->db->escape($this->num_payment)."', '".$this->db->escape($this->note_private)."', ".((int) $user->id).", 0)";
  224. $resql = $this->db->query($sql);
  225. if ($resql) {
  226. $this->id = $this->db->last_insert_id(MAIN_DB_PREFIX.'paiementfourn');
  227. // Insere tableau des montants / factures
  228. foreach ($this->amounts as $key => $amount) {
  229. $facid = $key;
  230. if (is_numeric($amount) && $amount <> 0) {
  231. $amount = price2num($amount);
  232. $sql = 'INSERT INTO '.MAIN_DB_PREFIX.'paiementfourn_facturefourn (fk_facturefourn, fk_paiementfourn, amount, multicurrency_amount)';
  233. $sql .= " VALUES (".((int) $facid).", ".((int) $this->id).", ".((float) $amount).', '.((float) $this->multicurrency_amounts[$key]).')';
  234. $resql = $this->db->query($sql);
  235. if ($resql) {
  236. $invoice = new FactureFournisseur($this->db);
  237. $invoice->fetch($facid);
  238. // If we want to closed paid invoices
  239. if ($closepaidinvoices) {
  240. $paiement = $invoice->getSommePaiement();
  241. $creditnotes=$invoice->getSumCreditNotesUsed();
  242. //$creditnotes = 0;
  243. $deposits=$invoice->getSumDepositsUsed();
  244. //$deposits = 0;
  245. $alreadypayed = price2num($paiement + $creditnotes + $deposits, 'MT');
  246. $remaintopay = price2num($invoice->total_ttc - $paiement - $creditnotes - $deposits, 'MT');
  247. if ($remaintopay == 0) {
  248. // If invoice is a down payment, we also convert down payment to discount
  249. if ($invoice->type == FactureFournisseur::TYPE_DEPOSIT) {
  250. $amount_ht = $amount_tva = $amount_ttc = array();
  251. $multicurrency_amount_ht = $multicurrency_amount_tva = $multicurrency_amount_ttc = array();
  252. // Insert one discount by VAT rate category
  253. require_once DOL_DOCUMENT_ROOT . '/core/class/discount.class.php';
  254. $discount = new DiscountAbsolute($this->db);
  255. $discount->fetch('', 0, $invoice->id);
  256. if (empty($discount->id)) { // If the invoice was not yet converted into a discount (this may have been done manually before we come here)
  257. $discount->discount_type = 1; // Supplier discount
  258. $discount->description = '(DEPOSIT)';
  259. $discount->fk_soc = $invoice->socid;
  260. $discount->fk_invoice_supplier_source = $invoice->id;
  261. // Loop on each vat rate
  262. $i = 0;
  263. foreach ($invoice->lines as $line) {
  264. if ($line->total_ht != 0) { // no need to create discount if amount is null
  265. $amount_ht[$line->tva_tx] += $line->total_ht;
  266. $amount_tva[$line->tva_tx] += $line->total_tva;
  267. $amount_ttc[$line->tva_tx] += $line->total_ttc;
  268. $multicurrency_amount_ht[$line->tva_tx] += $line->multicurrency_total_ht;
  269. $multicurrency_amount_tva[$line->tva_tx] += $line->multicurrency_total_tva;
  270. $multicurrency_amount_ttc[$line->tva_tx] += $line->multicurrency_total_ttc;
  271. $i++;
  272. }
  273. }
  274. foreach ($amount_ht as $tva_tx => $xxx) {
  275. $discount->amount_ht = abs($amount_ht[$tva_tx]);
  276. $discount->amount_tva = abs($amount_tva[$tva_tx]);
  277. $discount->amount_ttc = abs($amount_ttc[$tva_tx]);
  278. $discount->multicurrency_amount_ht = abs($multicurrency_amount_ht[$tva_tx]);
  279. $discount->multicurrency_amount_tva = abs($multicurrency_amount_tva[$tva_tx]);
  280. $discount->multicurrency_amount_ttc = abs($multicurrency_amount_ttc[$tva_tx]);
  281. $discount->tva_tx = abs($tva_tx);
  282. $result = $discount->create($user);
  283. if ($result < 0) {
  284. $error++;
  285. break;
  286. }
  287. }
  288. }
  289. if ($error) {
  290. setEventMessages($discount->error, $discount->errors, 'errors');
  291. $error++;
  292. }
  293. }
  294. // Set invoice to paid
  295. if (!$error) {
  296. $result = $invoice->setPaid($user, '', '');
  297. if ($result < 0) {
  298. $this->error = $invoice->error;
  299. $error++;
  300. }
  301. }
  302. } else {
  303. // hook to have an option to automatically close a closable invoice with less payment than the total amount (e.g. agreed cash discount terms)
  304. global $hookmanager;
  305. $hookmanager->initHooks(array('payment_supplierdao'));
  306. $parameters = array('facid' => $facid, 'invoice' => $invoice, 'remaintopay' => $remaintopay);
  307. $action = 'CLOSEPAIDSUPPLIERINVOICE';
  308. $reshook = $hookmanager->executeHooks('createPayment', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks
  309. if ($reshook < 0) {
  310. $this->error = $hookmanager->error;
  311. $error++;
  312. } elseif ($reshook == 0) {
  313. dol_syslog("Remain to pay for invoice " . $facid . " not null. We do nothing more.");
  314. }
  315. }
  316. }
  317. // Regenerate documents of invoices
  318. if (empty($conf->global->MAIN_DISABLE_PDF_AUTOUPDATE)) {
  319. $newlang = '';
  320. $outputlangs = $langs;
  321. if (getDolGlobalInt('MAIN_MULTILANGS') && empty($newlang)) {
  322. $newlang = $invoice->thirdparty->default_lang;
  323. }
  324. if (!empty($newlang)) {
  325. $outputlangs = new Translate("", $conf);
  326. $outputlangs->setDefaultLang($newlang);
  327. }
  328. $ret = $invoice->fetch($facid); // Reload to get new records
  329. $result = $invoice->generateDocument($invoice->model_pdf, $outputlangs);
  330. if ($result < 0) {
  331. setEventMessages($invoice->error, $invoice->errors, 'errors');
  332. $error++;
  333. }
  334. }
  335. } else {
  336. $this->error = $this->db->lasterror();
  337. $error++;
  338. }
  339. } else {
  340. dol_syslog(get_class($this).'::Create Amount line '.$key.' not a number. We discard it.');
  341. }
  342. }
  343. if (!$error) {
  344. // Call trigger
  345. $result = $this->call_trigger('PAYMENT_SUPPLIER_CREATE', $user);
  346. if ($result < 0) {
  347. $error++;
  348. }
  349. // End call triggers
  350. }
  351. } else {
  352. $this->error = $this->db->lasterror();
  353. $error++;
  354. }
  355. } else {
  356. $this->error = "ErrorTotalIsNull";
  357. dol_syslog('PaiementFourn::Create Error '.$this->error, LOG_ERR);
  358. $error++;
  359. }
  360. if ($totalamount <> 0 && $error == 0) { // On accepte les montants negatifs
  361. $this->amount = $total;
  362. $this->total = $total;
  363. $this->multicurrency_amount = $mtotal;
  364. $this->db->commit();
  365. dol_syslog('PaiementFourn::Create Ok Total = '.$this->amount.', Total currency = '.$this->multicurrency_amount);
  366. return $this->id;
  367. } else {
  368. $this->db->rollback();
  369. return -1;
  370. }
  371. }
  372. /**
  373. * Delete a payment and lines generated into accounts
  374. * Si le paiement porte sur un ecriture compte qui est rapprochee, on refuse
  375. * Si le paiement porte sur au moins une facture a "payee", on refuse
  376. *
  377. * @param int $notrigger No trigger
  378. * @return int <0 si ko, >0 si ok
  379. */
  380. public function delete($notrigger = 0)
  381. {
  382. global $conf, $user, $langs;
  383. $bank_line_id = $this->bank_line;
  384. $this->db->begin();
  385. // Verifier si paiement porte pas sur une facture a l'etat payee
  386. // Si c'est le cas, on refuse la suppression
  387. $billsarray = $this->getBillsArray('paye=1');
  388. if (is_array($billsarray)) {
  389. if (count($billsarray)) {
  390. $this->error = "ErrorCantDeletePaymentSharedWithPayedInvoice";
  391. $this->db->rollback();
  392. return -1;
  393. }
  394. } else {
  395. $this->db->rollback();
  396. return -2;
  397. }
  398. // Verifier si paiement ne porte pas sur ecriture bancaire rapprochee
  399. // Si c'est le cas, on refuse le delete
  400. if ($bank_line_id) {
  401. $accline = new AccountLine($this->db);
  402. $accline->fetch($bank_line_id);
  403. if ($accline->rappro) {
  404. $this->error = "ErrorCantDeletePaymentReconciliated";
  405. $this->db->rollback();
  406. return -3;
  407. }
  408. }
  409. // Efface la ligne de paiement (dans paiement_facture et paiement)
  410. $sql = 'DELETE FROM '.MAIN_DB_PREFIX.'paiementfourn_facturefourn';
  411. $sql .= ' WHERE fk_paiementfourn = '.((int) $this->id);
  412. $resql = $this->db->query($sql);
  413. if ($resql) {
  414. $sql = 'DELETE FROM '.MAIN_DB_PREFIX.'paiementfourn';
  415. $sql .= " WHERE rowid = ".((int) $this->id);
  416. $result = $this->db->query($sql);
  417. if (!$result) {
  418. $this->error = $this->db->error();
  419. $this->db->rollback();
  420. return -3;
  421. }
  422. // Supprimer l'ecriture bancaire si paiement lie a ecriture
  423. if ($bank_line_id) {
  424. $accline = new AccountLine($this->db);
  425. $result = $accline->fetch($bank_line_id);
  426. if ($result > 0) { // If result = 0, record not found, we don't try to delete
  427. $result = $accline->delete($user);
  428. }
  429. if ($result < 0) {
  430. $this->error = $accline->error;
  431. $this->db->rollback();
  432. return -4;
  433. }
  434. }
  435. if (!$notrigger) {
  436. // Appel des triggers
  437. $result = $this->call_trigger('PAYMENT_SUPPLIER_DELETE', $user);
  438. if ($result < 0) {
  439. $this->db->rollback();
  440. return -1;
  441. }
  442. // Fin appel triggers
  443. }
  444. $this->db->commit();
  445. return 1;
  446. } else {
  447. $this->error = $this->db->error;
  448. $this->db->rollback();
  449. return -5;
  450. }
  451. }
  452. /**
  453. * Information on object
  454. *
  455. * @param int $id Id du paiement dont il faut afficher les infos
  456. * @return void
  457. */
  458. public function info($id)
  459. {
  460. $sql = 'SELECT c.rowid, datec, fk_user_author as fk_user_creat, tms';
  461. $sql .= ' FROM '.MAIN_DB_PREFIX.'paiementfourn as c';
  462. $sql .= ' WHERE c.rowid = '.((int) $id);
  463. $resql = $this->db->query($sql);
  464. if ($resql) {
  465. $num = $this->db->num_rows($resql);
  466. if ($num) {
  467. $obj = $this->db->fetch_object($resql);
  468. $this->id = $obj->rowid;
  469. if ($obj->fk_user_creat) {
  470. $cuser = new User($this->db);
  471. $cuser->fetch($obj->fk_user_creat);
  472. $this->user_creation = $cuser;
  473. }
  474. if ($obj->fk_user_modif) {
  475. $muser = new User($this->db);
  476. $muser->fetch($obj->fk_user_modif);
  477. $this->user_modification = $muser;
  478. }
  479. $this->date_creation = $this->db->jdate($obj->datec);
  480. $this->date_modification = $this->db->jdate($obj->tms);
  481. }
  482. $this->db->free($resql);
  483. } else {
  484. dol_print_error($this->db);
  485. }
  486. }
  487. /**
  488. * Return list of supplier invoices the payment point to
  489. *
  490. * @param string $filter SQL filter. Warning: This value must not come from a user input.
  491. * @return array Array of supplier invoice id
  492. */
  493. public function getBillsArray($filter = '')
  494. {
  495. $sql = 'SELECT fk_facturefourn';
  496. $sql .= ' FROM '.MAIN_DB_PREFIX.'paiementfourn_facturefourn as pf, '.MAIN_DB_PREFIX.'facture_fourn as f';
  497. $sql .= ' WHERE pf.fk_facturefourn = f.rowid AND fk_paiementfourn = '.((int) $this->id);
  498. if ($filter) {
  499. $sql .= " AND ".$filter;
  500. }
  501. dol_syslog(get_class($this).'::getBillsArray', LOG_DEBUG);
  502. $resql = $this->db->query($sql);
  503. if ($resql) {
  504. $i = 0;
  505. $num = $this->db->num_rows($resql);
  506. $billsarray = array();
  507. while ($i < $num) {
  508. $obj = $this->db->fetch_object($resql);
  509. $billsarray[$i] = $obj->fk_facturefourn;
  510. $i++;
  511. }
  512. return $billsarray;
  513. } else {
  514. $this->error = $this->db->error();
  515. dol_syslog(get_class($this).'::getBillsArray Error '.$this->error);
  516. return -1;
  517. }
  518. }
  519. /**
  520. * Retourne le libelle du statut d'une facture (brouillon, validee, abandonnee, payee)
  521. *
  522. * @param int $mode 0=libelle long, 1=libelle court, 2=Picto + Libelle court, 3=Picto, 4=Picto + Libelle long, 5=Libelle court + Picto
  523. * @return string Libelle
  524. */
  525. public function getLibStatut($mode = 0)
  526. {
  527. return $this->LibStatut($this->statut, $mode);
  528. }
  529. // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
  530. /**
  531. * Renvoi le libelle d'un statut donne
  532. *
  533. * @param int $status Statut
  534. * @param int $mode 0=libelle long, 1=libelle court, 2=Picto + Libelle court, 3=Picto, 4=Picto + Libelle long, 5=Libelle court + Picto
  535. * @return string Libelle du statut
  536. */
  537. public function LibStatut($status, $mode = 0)
  538. {
  539. // phpcs:enable
  540. global $langs;
  541. $langs->load('compta');
  542. /*if ($mode == 0)
  543. {
  544. if ($status == 0) return $langs->trans('ToValidate');
  545. if ($status == 1) return $langs->trans('Validated');
  546. }
  547. if ($mode == 1)
  548. {
  549. if ($status == 0) return $langs->trans('ToValidate');
  550. if ($status == 1) return $langs->trans('Validated');
  551. }
  552. if ($mode == 2)
  553. {
  554. if ($status == 0) return img_picto($langs->trans('ToValidate'),'statut1').' '.$langs->trans('ToValidate');
  555. if ($status == 1) return img_picto($langs->trans('Validated'),'statut4').' '.$langs->trans('Validated');
  556. }
  557. if ($mode == 3)
  558. {
  559. if ($status == 0) return img_picto($langs->trans('ToValidate'),'statut1');
  560. if ($status == 1) return img_picto($langs->trans('Validated'),'statut4');
  561. }
  562. if ($mode == 4)
  563. {
  564. if ($status == 0) return img_picto($langs->trans('ToValidate'),'statut1').' '.$langs->trans('ToValidate');
  565. if ($status == 1) return img_picto($langs->trans('Validated'),'statut4').' '.$langs->trans('Validated');
  566. }
  567. if ($mode == 5)
  568. {
  569. if ($status == 0) return $langs->trans('ToValidate').' '.img_picto($langs->trans('ToValidate'),'statut1');
  570. if ($status == 1) return $langs->trans('Validated').' '.img_picto($langs->trans('Validated'),'statut4');
  571. }
  572. if ($mode == 6)
  573. {
  574. if ($status == 0) return $langs->trans('ToValidate').' '.img_picto($langs->trans('ToValidate'),'statut1');
  575. if ($status == 1) return $langs->trans('Validated').' '.img_picto($langs->trans('Validated'),'statut4');
  576. }*/
  577. return '';
  578. }
  579. /**
  580. * Return clicable name (with picto eventually)
  581. *
  582. * @param int $withpicto 0=No picto, 1=Include picto into link, 2=Only picto
  583. * @param string $option Sur quoi pointe le lien
  584. * @param string $mode 'withlistofinvoices'=Include list of invoices into tooltip
  585. * @param int $notooltip 1=Disable tooltip
  586. * @param string $morecss Add more CSS
  587. * @return string Chaine avec URL
  588. */
  589. public function getNomUrl($withpicto = 0, $option = '', $mode = 'withlistofinvoices', $notooltip = 0, $morecss = '')
  590. {
  591. global $langs, $conf, $hookmanager;
  592. if (!empty($conf->dol_no_mouse_hover)) {
  593. $notooltip = 1; // Force disable tooltips
  594. }
  595. $result = '';
  596. $text = $this->ref; // Sometimes ref contains label
  597. $reg = array();
  598. if (preg_match('/^\((.*)\)$/i', $text, $reg)) {
  599. // Label generique car entre parentheses. On l'affiche en le traduisant
  600. if ($reg[1] == 'paiement') {
  601. $reg[1] = 'Payment';
  602. }
  603. $text = $langs->trans($reg[1]);
  604. }
  605. $label = img_picto('', $this->picto).' <u>'.$langs->trans("Payment").'</u><br>';
  606. $label .= '<strong>'.$langs->trans("Ref").':</strong> '.$text;
  607. $dateofpayment = ($this->datepaye ? $this->datepaye : $this->date);
  608. if ($dateofpayment) {
  609. $label .= '<br><strong>'.$langs->trans("Date").':</strong> '.dol_print_date($dateofpayment, 'dayhour', 'tzuser');
  610. }
  611. if ($this->amount) {
  612. $label .= '<br><strong>'.$langs->trans("Amount").':</strong> '.price($this->amount, 0, $langs, 1, -1, -1, $conf->currency);
  613. }
  614. $linkclose = '';
  615. if (empty($notooltip)) {
  616. if (!empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER)) {
  617. $label = $langs->trans("Payment");
  618. $linkclose .= ' alt="'.dol_escape_htmltag($label, 1).'"';
  619. }
  620. $linkclose .= ' title="'.dol_escape_htmltag($label, 1).'"';
  621. $linkclose .= ' class="classfortooltip'.($morecss ? ' '.$morecss : '').'"';
  622. } else {
  623. $linkclose = ($morecss ? ' class="'.$morecss.'"' : '');
  624. }
  625. $linkstart = '<a href="'.DOL_URL_ROOT.'/fourn/paiement/card.php?id='.$this->id.'"';
  626. $linkstart .= $linkclose.'>';
  627. $linkend = '</a>';
  628. $result .= $linkstart;
  629. if ($withpicto) {
  630. $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);
  631. }
  632. if ($withpicto != 2) {
  633. $result .= $this->ref;
  634. }
  635. $result .= $linkend;
  636. global $action;
  637. $hookmanager->initHooks(array($this->element . 'dao'));
  638. $parameters = array('id'=>$this->id, 'getnomurl' => &$result);
  639. $reshook = $hookmanager->executeHooks('getNomUrl', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks
  640. if ($reshook > 0) {
  641. $result = $hookmanager->resPrint;
  642. } else {
  643. $result .= $hookmanager->resPrint;
  644. }
  645. return $result;
  646. }
  647. /**
  648. * Initialise an instance with random values.
  649. * Used to build previews or test instances.
  650. * id must be 0 if object instance is a specimen.
  651. *
  652. * @param string $option ''=Create a specimen invoice with lines, 'nolines'=No lines
  653. * @return void
  654. */
  655. public function initAsSpecimen($option = '')
  656. {
  657. global $user, $langs, $conf;
  658. $now = dol_now();
  659. $arraynow = dol_getdate($now);
  660. $nownotime = dol_mktime(0, 0, 0, $arraynow['mon'], $arraynow['mday'], $arraynow['year']);
  661. // Initialize parameters
  662. $this->id = 0;
  663. $this->ref = 'SPECIMEN';
  664. $this->specimen = 1;
  665. $this->facid = 1;
  666. $this->socid = 1;
  667. $this->datepaye = $nownotime;
  668. }
  669. /**
  670. * Return next reference of supplier invoice not already used (or last reference)
  671. * according to numbering module defined into constant SUPPLIER_PAYMENT_ADDON
  672. *
  673. * @param Societe $soc object company
  674. * @param string $mode 'next' for next value or 'last' for last value
  675. * @return string free ref or last ref
  676. */
  677. public function getNextNumRef($soc, $mode = 'next')
  678. {
  679. global $conf, $db, $langs;
  680. $langs->load("bills");
  681. // Clean parameters (if not defined or using deprecated value)
  682. if (empty($conf->global->SUPPLIER_PAYMENT_ADDON)) {
  683. $conf->global->SUPPLIER_PAYMENT_ADDON = 'mod_supplier_payment_bronan';
  684. } elseif ($conf->global->SUPPLIER_PAYMENT_ADDON == 'brodator') {
  685. $conf->global->SUPPLIER_PAYMENT_ADDON = 'mod_supplier_payment_brodator';
  686. } elseif ($conf->global->SUPPLIER_PAYMENT_ADDON == 'bronan') {
  687. $conf->global->SUPPLIER_PAYMENT_ADDON = 'mod_supplier_payment_bronan';
  688. }
  689. if (!empty($conf->global->SUPPLIER_PAYMENT_ADDON)) {
  690. $mybool = false;
  691. $file = $conf->global->SUPPLIER_PAYMENT_ADDON.".php";
  692. $classname = $conf->global->SUPPLIER_PAYMENT_ADDON;
  693. // Include file with class
  694. $dirmodels = array_merge(array('/'), (array) $conf->modules_parts['models']);
  695. foreach ($dirmodels as $reldir) {
  696. $dir = dol_buildpath($reldir."core/modules/supplier_payment/");
  697. // Load file with numbering class (if found)
  698. if (is_file($dir.$file) && is_readable($dir.$file)) {
  699. $mybool |= include_once $dir.$file;
  700. }
  701. }
  702. // For compatibility
  703. if ($mybool === false) {
  704. $file = $conf->global->SUPPLIER_PAYMENT_ADDON.".php";
  705. $classname = "mod_supplier_payment_".$conf->global->SUPPLIER_PAYMENT_ADDON;
  706. $classname = preg_replace('/\-.*$/', '', $classname);
  707. // Include file with class
  708. foreach ($conf->file->dol_document_root as $dirroot) {
  709. $dir = $dirroot."/core/modules/supplier_payment/";
  710. // Load file with numbering class (if found)
  711. if (is_file($dir.$file) && is_readable($dir.$file)) {
  712. $mybool |= include_once $dir.$file;
  713. }
  714. }
  715. }
  716. if ($mybool === false) {
  717. dol_print_error('', "Failed to include file ".$file);
  718. return '';
  719. }
  720. $obj = new $classname();
  721. $numref = "";
  722. $numref = $obj->getNextValue($soc, $this);
  723. /**
  724. * $numref can be empty in case we ask for the last value because if there is no invoice created with the
  725. * set up mask.
  726. */
  727. if ($mode != 'last' && !$numref) {
  728. dol_print_error($db, "SupplierPayment::getNextNumRef ".$obj->error);
  729. return "";
  730. }
  731. return $numref;
  732. } else {
  733. $langs->load("errors");
  734. print $langs->trans("Error")." ".$langs->trans("ErrorModuleSetupNotComplete", $langs->transnoentitiesnoconv("Supplier"));
  735. return "";
  736. }
  737. }
  738. /**
  739. * Create a document onto disk according to template model.
  740. *
  741. * @param string $modele Force template to use ('' to not force)
  742. * @param Translate $outputlangs Object lang a utiliser pour traduction
  743. * @param int $hidedetails Hide details of lines
  744. * @param int $hidedesc Hide description
  745. * @param int $hideref Hide ref
  746. * @param null|array $moreparams Array to provide more information
  747. * @return int <0 if KO, 0 if nothing done, >0 if OK
  748. */
  749. public function generateDocument($modele, $outputlangs, $hidedetails = 0, $hidedesc = 0, $hideref = 0, $moreparams = null)
  750. {
  751. global $conf, $user, $langs;
  752. $langs->load("suppliers");
  753. // Set the model on the model name to use
  754. if (empty($modele)) {
  755. if (!empty($conf->global->SUPPLIER_PAYMENT_ADDON_PDF)) {
  756. $modele = $conf->global->SUPPLIER_PAYMENT_ADDON_PDF;
  757. } else {
  758. $modele = ''; // No default value. For supplier invoice, we allow to disable all PDF generation
  759. }
  760. }
  761. if (empty($modele)) {
  762. return 0;
  763. } else {
  764. $modelpath = "core/modules/supplier_payment/doc/";
  765. return $this->commonGenerateDocument($modelpath, $modele, $outputlangs, $hidedetails, $hidedesc, $hideref, $moreparams);
  766. }
  767. }
  768. /**
  769. * get the right way of payment
  770. *
  771. * @return string 'dolibarr' if standard comportment or paid in dolibarr currency, 'customer' if payment received from multicurrency inputs
  772. */
  773. public function getWay()
  774. {
  775. global $conf;
  776. $way = 'dolibarr';
  777. if (isModEnabled("multicurrency")) {
  778. foreach ($this->multicurrency_amounts as $value) {
  779. if (!empty($value)) { // one value found then payment is in invoice currency
  780. $way = 'customer';
  781. break;
  782. }
  783. }
  784. }
  785. return $way;
  786. }
  787. // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
  788. /**
  789. * Load the third party of object, from id into this->thirdparty
  790. *
  791. * @param int $force_thirdparty_id Force thirdparty id
  792. * @return int <0 if KO, >0 if OK
  793. */
  794. public function fetch_thirdparty($force_thirdparty_id = 0)
  795. {
  796. // phpcs:enable
  797. require_once DOL_DOCUMENT_ROOT.'/fourn/class/fournisseur.facture.class.php';
  798. if (empty($force_thirdparty_id)) {
  799. $billsarray = $this->getBillsArray(); // From payment, the fk_soc isn't available, we should load the first supplier invoice to get him
  800. if (!empty($billsarray)) {
  801. $supplier_invoice = new FactureFournisseur($this->db);
  802. if ($supplier_invoice->fetch($billsarray[0]) > 0) {
  803. $force_thirdparty_id = $supplier_invoice->fk_soc;
  804. }
  805. }
  806. }
  807. return parent::fetch_thirdparty($force_thirdparty_id);
  808. }
  809. }