commoninvoice.class.php 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794
  1. <?php
  2. /* Copyright (C) 2012 Regis Houssin <regis.houssin@inodbox.com>
  3. * Copyright (C) 2012 Cédric Salvador <csalvador@gpcsolutions.fr>
  4. * Copyright (C) 2012-2014 Raphaël Doursenaud <rdoursenaud@gpcsolutions.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 <http://www.gnu.org/licenses/>.
  18. */
  19. /**
  20. * \file htdocs/core/class/commoninvoice.class.php
  21. * \ingroup core
  22. * \brief File of the superclass of invoices classes (customer and supplier)
  23. */
  24. require_once DOL_DOCUMENT_ROOT .'/core/class/commonobject.class.php';
  25. /**
  26. * Superclass for invoices classes
  27. */
  28. abstract class CommonInvoice extends CommonObject
  29. {
  30. /**
  31. * Standard invoice
  32. */
  33. const TYPE_STANDARD = 0;
  34. /**
  35. * Replacement invoice
  36. */
  37. const TYPE_REPLACEMENT = 1;
  38. /**
  39. * Credit note invoice
  40. */
  41. const TYPE_CREDIT_NOTE = 2;
  42. /**
  43. * Deposit invoice
  44. */
  45. const TYPE_DEPOSIT = 3;
  46. /**
  47. * Proforma invoice.
  48. * @deprectad Remove this. A "proforma invoice" is an order with a look of invoice, not an invoice !
  49. */
  50. const TYPE_PROFORMA = 4;
  51. /**
  52. * Situation invoice
  53. */
  54. const TYPE_SITUATION = 5;
  55. /**
  56. * Draft status
  57. */
  58. const STATUS_DRAFT = 0;
  59. /**
  60. * Validated (need to be paid)
  61. */
  62. const STATUS_VALIDATED = 1;
  63. /**
  64. * Classified paid.
  65. * If paid partially, $this->close_code can be:
  66. * - CLOSECODE_DISCOUNTVAT
  67. * - CLOSECODE_BADDEBT
  68. * If paid completelly, this->close_code will be null
  69. */
  70. const STATUS_CLOSED = 2;
  71. /**
  72. * Classified abandoned and no payment done.
  73. * $this->close_code can be:
  74. * - CLOSECODE_BADDEBT
  75. * - CLOSECODE_ABANDONED
  76. * - CLOSECODE_REPLACED
  77. */
  78. const STATUS_ABANDONED = 3;
  79. /**
  80. * Return remain amount to pay. Property ->id and ->total_ttc must be set.
  81. * This does not include open direct debit requests.
  82. *
  83. * @param int $multicurrency Return multicurrency_amount instead of amount
  84. * @return double Remain of amount to pay
  85. */
  86. function getRemainToPay($multicurrency=0)
  87. {
  88. $alreadypaid=0;
  89. $alreadypaid+=$this->getSommePaiement($multicurrency);
  90. $alreadypaid+=$this->getSumDepositsUsed($multicurrency);
  91. $alreadypaid+=$this->getSumCreditNotesUsed($multicurrency);
  92. return $this->total_ttc - $alreadypaid;
  93. }
  94. /**
  95. * Return amount of payments already done
  96. *
  97. * @param int $multicurrency Return multicurrency_amount instead of amount
  98. * @return int Amount of payment already done, <0 if KO
  99. */
  100. function getSommePaiement($multicurrency=0)
  101. {
  102. $table='paiement_facture';
  103. $field='fk_facture';
  104. if ($this->element == 'facture_fourn' || $this->element == 'invoice_supplier')
  105. {
  106. $table='paiementfourn_facturefourn';
  107. $field='fk_facturefourn';
  108. }
  109. $sql = 'SELECT sum(amount) as amount, sum(multicurrency_amount) as multicurrency_amount';
  110. $sql.= ' FROM '.MAIN_DB_PREFIX.$table;
  111. $sql.= ' WHERE '.$field.' = '.$this->id;
  112. dol_syslog(get_class($this)."::getSommePaiement", LOG_DEBUG);
  113. $resql=$this->db->query($sql);
  114. if ($resql)
  115. {
  116. $obj = $this->db->fetch_object($resql);
  117. $this->db->free($resql);
  118. if ($multicurrency) return $obj->multicurrency_amount;
  119. else return $obj->amount;
  120. }
  121. else
  122. {
  123. $this->error=$this->db->lasterror();
  124. return -1;
  125. }
  126. }
  127. /**
  128. * Return amount (with tax) of all deposits invoices used by invoice.
  129. * Should always be empty, except if option FACTURE_DEPOSITS_ARE_JUST_PAYMENTS is on (not recommended).
  130. *
  131. * @param int $multicurrency Return multicurrency_amount instead of amount
  132. * @return int <0 if KO, Sum of deposits amount otherwise
  133. */
  134. function getSumDepositsUsed($multicurrency=0)
  135. {
  136. if ($this->element == 'facture_fourn' || $this->element == 'invoice_supplier')
  137. {
  138. // TODO
  139. return 0;
  140. }
  141. require_once DOL_DOCUMENT_ROOT.'/core/class/discount.class.php';
  142. $discountstatic=new DiscountAbsolute($this->db);
  143. $result=$discountstatic->getSumDepositsUsed($this, $multicurrency);
  144. if ($result >= 0)
  145. {
  146. return $result;
  147. }
  148. else
  149. {
  150. $this->error=$discountstatic->error;
  151. return -1;
  152. }
  153. }
  154. /**
  155. * Return amount (with tax) of all credit notes invoices + excess received used by invoice
  156. *
  157. * @param int $multicurrency Return multicurrency_amount instead of amount
  158. * @return int <0 if KO, Sum of credit notes and deposits amount otherwise
  159. */
  160. function getSumCreditNotesUsed($multicurrency=0)
  161. {
  162. require_once DOL_DOCUMENT_ROOT.'/core/class/discount.class.php';
  163. $discountstatic=new DiscountAbsolute($this->db);
  164. $result=$discountstatic->getSumCreditNotesUsed($this, $multicurrency);
  165. if ($result >= 0)
  166. {
  167. return $result;
  168. }
  169. else
  170. {
  171. $this->error=$discountstatic->error;
  172. return -1;
  173. }
  174. }
  175. /**
  176. * Renvoie tableau des ids de facture avoir issus de la facture
  177. *
  178. * @return array Tableau d'id de factures avoirs
  179. */
  180. function getListIdAvoirFromInvoice()
  181. {
  182. $idarray=array();
  183. $sql = 'SELECT rowid';
  184. $sql.= ' FROM '.MAIN_DB_PREFIX.$this->table_element;
  185. $sql.= ' WHERE fk_facture_source = '.$this->id;
  186. $sql.= ' AND type = 2';
  187. $resql=$this->db->query($sql);
  188. if ($resql)
  189. {
  190. $num = $this->db->num_rows($resql);
  191. $i = 0;
  192. while ($i < $num)
  193. {
  194. $row = $this->db->fetch_row($resql);
  195. $idarray[]=$row[0];
  196. $i++;
  197. }
  198. }
  199. else
  200. {
  201. dol_print_error($this->db);
  202. }
  203. return $idarray;
  204. }
  205. /**
  206. * Renvoie l'id de la facture qui la remplace
  207. *
  208. * @param string $option filtre sur statut ('', 'validated', ...)
  209. * @return int <0 si KO, 0 si aucune facture ne remplace, id facture sinon
  210. */
  211. function getIdReplacingInvoice($option='')
  212. {
  213. $sql = 'SELECT rowid';
  214. $sql.= ' FROM '.MAIN_DB_PREFIX.$this->table_element;
  215. $sql.= ' WHERE fk_facture_source = '.$this->id;
  216. $sql.= ' AND type < 2';
  217. if ($option == 'validated') $sql.= ' AND fk_statut = 1';
  218. // PROTECTION BAD DATA
  219. // Au cas ou base corrompue et qu'il y a une facture de remplacement validee
  220. // et une autre non, on donne priorite a la validee.
  221. // Ne devrait pas arriver (sauf si acces concurrentiel et que 2 personnes
  222. // ont cree en meme temps une facture de remplacement pour la meme facture)
  223. $sql.= ' ORDER BY fk_statut DESC';
  224. $resql=$this->db->query($sql);
  225. if ($resql)
  226. {
  227. $obj = $this->db->fetch_object($resql);
  228. if ($obj)
  229. {
  230. // Si il y en a
  231. return $obj->rowid;
  232. }
  233. else
  234. {
  235. // Si aucune facture ne remplace
  236. return 0;
  237. }
  238. }
  239. else
  240. {
  241. return -1;
  242. }
  243. }
  244. /**
  245. * Return list of payments
  246. *
  247. * @param string $filtertype 1 to filter on type of payment == 'PRE'
  248. * @return array Array with list of payments
  249. */
  250. function getListOfPayments($filtertype='')
  251. {
  252. $retarray=array();
  253. $table='paiement_facture';
  254. $table2='paiement';
  255. $field='fk_facture';
  256. $field2='fk_paiement';
  257. $sharedentity='facture';
  258. if ($this->element == 'facture_fourn' || $this->element == 'invoice_supplier')
  259. {
  260. $table='paiementfourn_facturefourn';
  261. $table2='paiementfourn';
  262. $field='fk_facturefourn';
  263. $field2='fk_paiementfourn';
  264. $sharedentity='facture_fourn';
  265. }
  266. $sql = 'SELECT p.ref, pf.amount, pf.multicurrency_amount, p.fk_paiement, p.datep, p.num_paiement as num, t.code';
  267. $sql.= ' FROM '.MAIN_DB_PREFIX.$table.' as pf, '.MAIN_DB_PREFIX.$table2.' as p, '.MAIN_DB_PREFIX.'c_paiement as t';
  268. $sql.= ' WHERE pf.'.$field.' = '.$this->id;
  269. //$sql.= ' WHERE pf.'.$field.' = 1';
  270. $sql.= ' AND pf.'.$field2.' = p.rowid';
  271. $sql.= ' AND p.fk_paiement = t.id';
  272. $sql.= ' AND p.entity IN (' . getEntity($sharedentity).')';
  273. if ($filtertype) $sql.=" AND t.code='PRE'";
  274. dol_syslog(get_class($this)."::getListOfPayments", LOG_DEBUG);
  275. $resql=$this->db->query($sql);
  276. if ($resql)
  277. {
  278. $num = $this->db->num_rows($resql);
  279. $i=0;
  280. while ($i < $num)
  281. {
  282. $obj = $this->db->fetch_object($resql);
  283. $retarray[]=array('amount'=>$obj->amount,'type'=>$obj->code, 'date'=>$obj->datep, 'num'=>$obj->num, 'ref'=>$obj->ref);
  284. $i++;
  285. }
  286. $this->db->free($resql);
  287. return $retarray;
  288. }
  289. else
  290. {
  291. $this->error=$this->db->lasterror();
  292. dol_print_error($this->db);
  293. return array();
  294. }
  295. }
  296. // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
  297. /**
  298. * Return if an invoice can be deleted
  299. * Rule is:
  300. * If invoice is draft and has a temporary ref -> yes (1)
  301. * If hidden option INVOICE_CAN_NEVER_BE_REMOVED is on -> no (0)
  302. * If invoice is dispatched in bookkeeping -> no (-1)
  303. * If invoice has a definitive ref, is not last and INVOICE_CAN_ALWAYS_BE_REMOVED off -> no (-2)
  304. * If invoice not last in a cycle -> no (-3)
  305. * If there is payment -> no (-4)
  306. * Otherwise -> yes (2)
  307. *
  308. * @return int <=0 if no, >0 if yes
  309. */
  310. function is_erasable()
  311. {
  312. // phpcs:enable
  313. global $conf;
  314. // We check if invoice is a temporary number (PROVxxxx)
  315. $tmppart = substr($this->ref, 1, 4);
  316. if ($this->statut == self::STATUS_DRAFT && $tmppart === 'PROV') // If draft invoice and ref not yet defined
  317. {
  318. return 1;
  319. }
  320. if (! empty($conf->global->INVOICE_CAN_NEVER_BE_REMOVED)) return 0;
  321. // If not a draft invoice and not temporary invoice
  322. if ($tmppart !== 'PROV')
  323. {
  324. $ventilExportCompta = $this->getVentilExportCompta();
  325. if ($ventilExportCompta != 0) return -1;
  326. // Get last number of validated invoice
  327. if ($this->element != 'invoice_supplier')
  328. {
  329. if (empty($this->thirdparty)) $this->fetch_thirdparty(); // We need to have this->thirdparty defined, in case of numbering rule use tags that depend on thirdparty (like {t} tag).
  330. $maxfacnumber = $this->getNextNumRef($this->thirdparty,'last');
  331. // If there is no invoice into the reset range and not already dispatched, we can delete
  332. // If invoice to delete is last one and not already dispatched, we can delete
  333. if (empty($conf->global->INVOICE_CAN_ALWAYS_BE_REMOVED) && $maxfacnumber != '' && $maxfacnumber != $this->ref) return -2;
  334. // TODO If there is payment in bookkeeping, check payment is not dispatched in accounting
  335. // ...
  336. if ($this->situation_cycle_ref && method_exists($this, 'is_last_in_cycle'))
  337. {
  338. $last = $this->is_last_in_cycle();
  339. if (! $last) return -3;
  340. }
  341. }
  342. }
  343. // Test if there is at least one payment. If yes, refuse to delete.
  344. if (empty($conf->global->INVOICE_CAN_ALWAYS_BE_REMOVED) && $this->getSommePaiement() > 0) return -4;
  345. return 2;
  346. }
  347. /**
  348. * Return if an invoice was dispatched into bookkeeping
  349. *
  350. * @return int <0 if KO, 0=no, 1=yes
  351. */
  352. public function getVentilExportCompta()
  353. {
  354. $alreadydispatched = 0;
  355. $type = 'customer_invoice';
  356. if ($this->element == 'invoice_supplier') $type = 'supplier_invoice';
  357. $sql = " SELECT COUNT(ab.rowid) as nb FROM ".MAIN_DB_PREFIX."accounting_bookkeeping as ab WHERE ab.doc_type='".$type."' AND ab.fk_doc = ".$this->id;
  358. $resql = $this->db->query($sql);
  359. if ($resql)
  360. {
  361. $obj = $this->db->fetch_object($resql);
  362. if ($obj)
  363. {
  364. $alreadydispatched = $obj->nb;
  365. }
  366. }
  367. else
  368. {
  369. $this->error = $this->db->lasterror();
  370. return -1;
  371. }
  372. if ($alreadydispatched)
  373. {
  374. return 1;
  375. }
  376. return 0;
  377. }
  378. /**
  379. * Return label of type of invoice
  380. *
  381. * @return string Label of type of invoice
  382. */
  383. function getLibType()
  384. {
  385. global $langs;
  386. if ($this->type == CommonInvoice::TYPE_STANDARD) return $langs->trans("InvoiceStandard");
  387. elseif ($this->type == CommonInvoice::TYPE_REPLACEMENT) return $langs->trans("InvoiceReplacement");
  388. elseif ($this->type == CommonInvoice::TYPE_CREDIT_NOTE) return $langs->trans("InvoiceAvoir");
  389. elseif ($this->type == CommonInvoice::TYPE_DEPOSIT) return $langs->trans("InvoiceDeposit");
  390. elseif ($this->type == CommonInvoice::TYPE_PROFORMA) return $langs->trans("InvoiceProForma"); // Not used.
  391. elseif ($this->type == CommonInvoice::TYPE_SITUATION) return $langs->trans("InvoiceSituation");
  392. return $langs->trans("Unknown");
  393. }
  394. /**
  395. * Return label of object status
  396. *
  397. * @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
  398. * @param integer $alreadypaid 0=No payment already done, >0=Some payments were already done (we recommand to put here amount payed if you have it, 1 otherwise)
  399. * @return string Label of status
  400. */
  401. function getLibStatut($mode=0, $alreadypaid=-1)
  402. {
  403. return $this->LibStatut($this->paye, $this->statut, $mode, $alreadypaid, $this->type);
  404. }
  405. // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
  406. /**
  407. * Return label of a status
  408. *
  409. * @param int $paye Status field paye
  410. * @param int $status Id status
  411. * @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
  412. * @param integer $alreadypaid 0=No payment already done, >0=Some payments were already done (we recommand to put here amount payed if you have it, -1 otherwise)
  413. * @param int $type Type invoice
  414. * @return string Label of status
  415. */
  416. function LibStatut($paye, $status, $mode=0, $alreadypaid=-1, $type=0)
  417. {
  418. // phpcs:enable
  419. global $langs;
  420. $langs->load('bills');
  421. //print "$paye,$status,$mode,$alreadypaid,$type";
  422. if ($mode == 0)
  423. {
  424. $prefix='';
  425. if (! $paye)
  426. {
  427. if ($status == 0) return $langs->trans('Bill'.$prefix.'StatusDraft');
  428. elseif (($status == 3 || $status == 2) && $alreadypaid <= 0) return $langs->trans('Bill'.$prefix.'StatusClosedUnpaid');
  429. elseif (($status == 3 || $status == 2) && $alreadypaid > 0) return $langs->trans('Bill'.$prefix.'StatusClosedPaidPartially');
  430. elseif ($alreadypaid <= 0) return $langs->trans('Bill'.$prefix.'StatusNotPaid');
  431. else return $langs->trans('Bill'.$prefix.'StatusStarted');
  432. }
  433. else
  434. {
  435. if ($type == self::TYPE_CREDIT_NOTE) return $langs->trans('Bill'.$prefix.'StatusPaidBackOrConverted'); // credit note
  436. elseif ($type == self::TYPE_DEPOSIT) return $langs->trans('Bill'.$prefix.'StatusConverted'); // deposit invoice
  437. else return $langs->trans('Bill'.$prefix.'StatusPaid');
  438. }
  439. }
  440. elseif ($mode == 1)
  441. {
  442. $prefix='Short';
  443. if (! $paye)
  444. {
  445. if ($status == 0) return $langs->trans('Bill'.$prefix.'StatusDraft');
  446. elseif (($status == 3 || $status == 2) && $alreadypaid <= 0) return $langs->trans('Bill'.$prefix.'StatusCanceled');
  447. elseif (($status == 3 || $status == 2) && $alreadypaid > 0) return $langs->trans('Bill'.$prefix.'StatusClosedPaidPartially');
  448. elseif ($alreadypaid <= 0) return $langs->trans('Bill'.$prefix.'StatusNotPaid');
  449. else return $langs->trans('Bill'.$prefix.'StatusStarted');
  450. }
  451. else
  452. {
  453. if ($type == self::TYPE_CREDIT_NOTE) return $langs->trans('Bill'.$prefix.'StatusPaidBackOrConverted');
  454. elseif ($type == self::TYPE_DEPOSIT) return $langs->trans('Bill'.$prefix.'StatusConverted');
  455. else return $langs->trans('Bill'.$prefix.'StatusPaid');
  456. }
  457. }
  458. elseif ($mode == 2)
  459. {
  460. $prefix='Short';
  461. if (! $paye)
  462. {
  463. if ($status == 0) return img_picto($langs->trans('BillStatusDraft'),'statut0').' '.$langs->trans('Bill'.$prefix.'StatusDraft');
  464. elseif (($status == 3 || $status == 2) && $alreadypaid <= 0) return img_picto($langs->trans('StatusCanceled'),'statut5').' '.$langs->trans('Bill'.$prefix.'StatusCanceled');
  465. elseif (($status == 3 || $status == 2) && $alreadypaid > 0) return img_picto($langs->trans('BillStatusClosedPaidPartially'),'statut9').' '.$langs->trans('Bill'.$prefix.'StatusClosedPaidPartially');
  466. elseif ($alreadypaid <= 0) return img_picto($langs->trans('BillStatusNotPaid'),'statut1').' '.$langs->trans('Bill'.$prefix.'StatusNotPaid');
  467. else return img_picto($langs->trans('BillStatusStarted'),'statut3').' '.$langs->trans('Bill'.$prefix.'StatusStarted');
  468. }
  469. else
  470. {
  471. if ($type == self::TYPE_CREDIT_NOTE) return img_picto($langs->trans('BillStatusPaidBackOrConverted'),'statut6').' '.$langs->trans('Bill'.$prefix.'StatusPaidBackOrConverted');
  472. elseif ($type == self::TYPE_DEPOSIT) return img_picto($langs->trans('BillStatusConverted'),'statut6').' '.$langs->trans('Bill'.$prefix.'StatusConverted');
  473. else return img_picto($langs->trans('BillStatusPaid'),'statut6').' '.$langs->trans('Bill'.$prefix.'StatusPaid');
  474. }
  475. }
  476. elseif ($mode == 3)
  477. {
  478. $prefix='Short';
  479. if (! $paye)
  480. {
  481. if ($status == 0) return img_picto($langs->trans('BillStatusDraft'),'statut0');
  482. elseif (($status == 3 || $status == 2) && $alreadypaid <= 0) return img_picto($langs->trans('BillStatusCanceled'),'statut5');
  483. elseif (($status == 3 || $status == 2) && $alreadypaid > 0) return img_picto($langs->trans('BillStatusClosedPaidPartially'),'statut9');
  484. elseif ($alreadypaid <= 0) return img_picto($langs->trans('BillStatusNotPaid'),'statut1');
  485. else return img_picto($langs->trans('BillStatusStarted'),'statut3');
  486. }
  487. else
  488. {
  489. if ($type == self::TYPE_CREDIT_NOTE) return img_picto($langs->trans('BillStatusPaidBackOrConverted'),'statut6');
  490. elseif ($type == self::TYPE_DEPOSIT) return img_picto($langs->trans('BillStatusConverted'),'statut6');
  491. else return img_picto($langs->trans('BillStatusPaid'),'statut6');
  492. }
  493. }
  494. elseif ($mode == 4)
  495. {
  496. $prefix='';
  497. if (! $paye)
  498. {
  499. if ($status == 0) return img_picto($langs->trans('BillStatusDraft'),'statut0').' '.$langs->trans('BillStatusDraft');
  500. elseif (($status == 3 || $status == 2) && $alreadypaid <= 0) return img_picto($langs->trans('BillStatusCanceled'),'statut5').' '.$langs->trans('Bill'.$prefix.'StatusCanceled');
  501. elseif (($status == 3 || $status == 2) && $alreadypaid > 0) return img_picto($langs->trans('BillStatusClosedPaidPartially'),'statut9').' '.$langs->trans('Bill'.$prefix.'StatusClosedPaidPartially');
  502. elseif ($alreadypaid <= 0) return img_picto($langs->trans('BillStatusNotPaid'),'statut1').' '.$langs->trans('BillStatusNotPaid');
  503. else return img_picto($langs->trans('BillStatusStarted'),'statut3').' '.$langs->trans('BillStatusStarted');
  504. }
  505. else
  506. {
  507. if ($type == self::TYPE_CREDIT_NOTE) return img_picto($langs->trans('BillStatusPaidBackOrConverted'),'statut6').' '.$langs->trans('BillStatusPaidBackOrConverted');
  508. elseif ($type == self::TYPE_DEPOSIT) return img_picto($langs->trans('BillStatusConverted'),'statut6').' '.$langs->trans('BillStatusConverted');
  509. else return img_picto($langs->trans('BillStatusPaid'),'statut6').' '.$langs->trans('BillStatusPaid');
  510. }
  511. }
  512. elseif ($mode == 5 || $mode == 6)
  513. {
  514. $prefix='';
  515. if ($mode == 5) $prefix='Short';
  516. if (! $paye)
  517. {
  518. if ($status == 0) return '<span class="xhideonsmartphone">'.$langs->trans('Bill'.$prefix.'StatusDraft').' </span>'.img_picto($langs->trans('BillStatusDraft'),'statut0');
  519. elseif (($status == 3 || $status == 2) && $alreadypaid <= 0) return '<span class="xhideonsmartphone">'.$langs->trans('Bill'.$prefix.'StatusCanceled').' </span>'.img_picto($langs->trans('BillStatusCanceled'),'statut5');
  520. elseif (($status == 3 || $status == 2) && $alreadypaid > 0) return '<span class="xhideonsmartphone">'.$langs->trans('Bill'.$prefix.'StatusClosedPaidPartially').' </span>'.img_picto($langs->trans('BillStatusClosedPaidPartially'),'statut9');
  521. elseif ($alreadypaid <= 0)
  522. {
  523. if ($type == self::TYPE_CREDIT_NOTE) return '<span class="xhideonsmartphone">'.$langs->trans('Bill'.$prefix.'StatusNotRefunded').' </span>'.img_picto($langs->trans('StatusNotRefunded'),'statut1');
  524. return '<span class="xhideonsmartphone">'.$langs->trans('Bill'.$prefix.'StatusNotPaid').' </span>'.img_picto($langs->trans('BillStatusNotPaid'),'statut1');
  525. }
  526. else return '<span class="xhideonsmartphone">'.$langs->trans('Bill'.$prefix.'StatusStarted').' </span>'.img_picto($langs->trans('BillStatusStarted'),'statut3');
  527. }
  528. else
  529. {
  530. if ($type == self::TYPE_CREDIT_NOTE) return '<span class="xhideonsmartphone">'.$langs->trans('Bill'.$prefix.'StatusPaidBackOrConverted').' </span>'.img_picto($langs->trans('BillStatusPaidBackOrConverted'),'statut6');
  531. elseif ($type == self::TYPE_DEPOSIT) return '<span class="xhideonsmartphone">'.$langs->trans('Bill'.$prefix.'StatusConverted').' </span>'.img_picto($langs->trans('BillStatusConverted'),'statut6');
  532. else return '<span class="xhideonsmartphone">'.$langs->trans('Bill'.$prefix.'StatusPaid').' </span>'.img_picto($langs->trans('BillStatusPaid'),'statut6');
  533. }
  534. }
  535. }
  536. // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
  537. /**
  538. * Renvoi une date limite de reglement de facture en fonction des
  539. * conditions de reglements de la facture et date de facturation.
  540. *
  541. * @param integer $cond_reglement Condition of payment (code or id) to use. If 0, we use current condition.
  542. * @return date Date limite de reglement si ok, <0 si ko
  543. */
  544. function calculate_date_lim_reglement($cond_reglement=0)
  545. {
  546. // phpcs:enable
  547. if (! $cond_reglement) $cond_reglement=$this->cond_reglement_code;
  548. if (! $cond_reglement) $cond_reglement=$this->cond_reglement_id;
  549. $cdr_nbjour=0;
  550. $cdr_type=0;
  551. $cdr_decalage=0;
  552. $sqltemp = 'SELECT c.type_cdr, c.nbjour, c.decalage';
  553. $sqltemp.= ' FROM '.MAIN_DB_PREFIX.'c_payment_term as c';
  554. if (is_numeric($cond_reglement)) $sqltemp.= " WHERE c.rowid=".$cond_reglement;
  555. else {
  556. $sqltemp.= " WHERE c.entity IN (".getEntity('c_payment_term').")";
  557. $sqltemp.= " AND c.code='".$this->db->escape($cond_reglement)."'";
  558. }
  559. dol_syslog(get_class($this).'::calculate_date_lim_reglement', LOG_DEBUG);
  560. $resqltemp=$this->db->query($sqltemp);
  561. if ($resqltemp)
  562. {
  563. if ($this->db->num_rows($resqltemp))
  564. {
  565. $obj = $this->db->fetch_object($resqltemp);
  566. $cdr_nbjour = $obj->nbjour;
  567. $cdr_type = $obj->type_cdr;
  568. $cdr_decalage = $obj->decalage;
  569. }
  570. }
  571. else
  572. {
  573. $this->error=$this->db->error();
  574. return -1;
  575. }
  576. $this->db->free($resqltemp);
  577. /* Definition de la date limite */
  578. // 0 : ajout du nombre de jours
  579. if ($cdr_type == 0)
  580. {
  581. $datelim = $this->date + ($cdr_nbjour * 3600 * 24);
  582. $datelim += ($cdr_decalage * 3600 * 24);
  583. }
  584. // 1 : application de la regle "fin de mois"
  585. elseif ($cdr_type == 1)
  586. {
  587. $datelim = $this->date + ($cdr_nbjour * 3600 * 24);
  588. $mois=date('m', $datelim);
  589. $annee=date('Y', $datelim);
  590. if ($mois == 12)
  591. {
  592. $mois = 1;
  593. $annee += 1;
  594. }
  595. else
  596. {
  597. $mois += 1;
  598. }
  599. // On se deplace au debut du mois suivant, et on retire un jour
  600. $datelim=dol_mktime(12,0,0,$mois,1,$annee);
  601. $datelim -= (3600 * 24);
  602. $datelim += ($cdr_decalage * 3600 * 24);
  603. }
  604. // 2 : application de la règle, le N du mois courant ou suivant
  605. elseif ($cdr_type == 2 && !empty($cdr_decalage))
  606. {
  607. $datelim = $this->date + ($cdr_nbjour * 3600 * 24);
  608. $date_piece = dol_mktime(0, 0, 0, date('m', $datelim),date('d', $datelim),date('Y', $datelim)); // Sans les heures minutes et secondes
  609. $date_lim_current = dol_mktime(0, 0, 0, date('m', $datelim), $cdr_decalage, date('Y', $datelim)); // Sans les heures minutes et secondes
  610. $date_lim_next = dol_time_plus_duree($date_lim_current, 1, 'm'); // Add 1 month
  611. $diff = $date_piece - $date_lim_current;
  612. if ($diff < 0) $datelim = $date_lim_current;
  613. else $datelim = $date_lim_next;
  614. }
  615. else return 'Bad value for type_cdr in database for record cond_reglement = '.$cond_reglement;
  616. return $datelim;
  617. }
  618. }
  619. require_once DOL_DOCUMENT_ROOT .'/core/class/commonobjectline.class.php';
  620. /**
  621. * Parent class of all other business classes for details of elements (invoices, contracts, proposals, orders, ...)
  622. */
  623. abstract class CommonInvoiceLine extends CommonObjectLine
  624. {
  625. /**
  626. * Quantity
  627. * @var double
  628. */
  629. public $qty;
  630. /**
  631. * Unit price before taxes
  632. * @var float
  633. */
  634. public $subprice;
  635. /**
  636. * Type of the product. 0 for product 1 for service
  637. * @var int
  638. */
  639. public $product_type = 0;
  640. /**
  641. * Id of corresponding product
  642. * @var int
  643. */
  644. public $fk_product;
  645. /**
  646. * VAT code
  647. * @var string
  648. */
  649. public $vat_src_code;
  650. /**
  651. * VAT %
  652. * @var float
  653. */
  654. public $tva_tx;
  655. /**
  656. * Local tax 1 %
  657. * @var float
  658. */
  659. public $localtax1_tx;
  660. /**
  661. * Local tax 2 %
  662. * @var float
  663. */
  664. public $localtax2_tx;
  665. /**
  666. * Percent of discount
  667. * @var float
  668. */
  669. public $remise_percent;
  670. /**
  671. * Total amount before taxes
  672. * @var float
  673. */
  674. public $total_ht;
  675. /**
  676. * Total VAT amount
  677. * @var float
  678. */
  679. public $total_tva;
  680. /**
  681. * Total local tax 1 amount
  682. * @var float
  683. */
  684. public $total_localtax1;
  685. /**
  686. * Total local tax 2 amount
  687. * @var float
  688. */
  689. public $total_localtax2;
  690. /**
  691. * Total amount with taxes
  692. * @var float
  693. */
  694. public $total_ttc;
  695. /**
  696. * Liste d'options cumulables:
  697. * Bit 0: 0 si TVA normal - 1 si TVA NPR
  698. * Bit 1: 0 si ligne normal - 1 si bit discount (link to line into llx_remise_except)
  699. * @var int
  700. */
  701. public $info_bits = 0;
  702. /**
  703. * Constructor
  704. *
  705. * @param DoliDB $db Database handler
  706. */
  707. public function __construct(DoliDB $db)
  708. {
  709. $this->db = $db;
  710. }
  711. }