dolibarr 23.0.4
facture-rec.class.php
Go to the documentation of this file.
1<?php
2/* Copyright (C) 2003-2005 Rodolphe Quiedeville <rodolphe@quiedeville.org>
3 * Copyright (C) 2004-2019 Laurent Destailleur <eldy@users.sourceforge.net>
4 * Copyright (C) 2009-2012 Regis Houssin <regis.houssin@inodbox.com>
5 * Copyright (C) 2010-2011 Juanjo Menent <jmenent@2byte.es>
6 * Copyright (C) 2012 Cedric Salvador <csalvador@gpcsolutions.fr>
7 * Copyright (C) 2013 Florian Henry <florian.henry@open-concept.pro>
8 * Copyright (C) 2015 Marcos García <marcosgdf@gmail.com>
9 * Copyright (C) 2017-2025 Frédéric France <frederic.france@free.fr>
10 * Copyright (C) 2023 Nick Fragoulis
11 * Copyright (C) 2024-2025 MDW <mdeweerd@users.noreply.github.com>
12 *
13 * This program is free software; you can redistribute it and/or modify
14 * it under the terms of the GNU General Public License as published by
15 * the Free Software Foundation; either version 3 of the License, or
16 * (at your option) any later version.
17 *
18 * This program is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
22 *
23 * You should have received a copy of the GNU General Public License
24 * along with this program. If not, see <https://www.gnu.org/licenses/>.
25 */
26
33require_once DOL_DOCUMENT_ROOT.'/core/class/commoninvoice.class.php';
34require_once DOL_DOCUMENT_ROOT.'/core/class/notify.class.php';
35require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php';
36require_once DOL_DOCUMENT_ROOT.'/compta/facture/class/facture.class.php';
37require_once DOL_DOCUMENT_ROOT.'/compta/facture/class/factureligne.class.php';
38require_once DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php';
39require_once DOL_DOCUMENT_ROOT.'/subtotals/class/commonsubtotal.class.php';
40
41
46{
47 use CommonSubtotal;
48
53 public $TRIGGER_PREFIX = 'BILLREC';
54
58 public $element = 'facturerec';
59
63 public $table_element = 'facture_rec';
64
68 public $table_element_line = 'facturedet_rec';
69
73 public $fk_element = 'fk_facture';
74
78 public $picto = 'bill';
79
83 protected $table_ref_field = 'titre';
84
88 public $title;
89
94 public $titre;
95
99 public $multicurrency_subprice;
103 public $socid;
107 public $number;
111 public $date;
112 //public $remise;
113 //public $remise_absolue;
114 //public $remise_percent;
115
121 public $total;
122
128 public $tva;
129
133 public $date_last_gen;
137 public $date_when;
141 public $nb_gen_done;
145 public $nb_gen_max;
146
150 public $user_author;
151
155 public $frequency;
156
160 public $unit_frequency;
161
165 public $rule_for_lines_dates;
166
170 public $rang;
171
175 public $special_code;
176
180 public $usenewprice = 0;
181
185 public $date_lim_reglement;
189 public $cond_reglement_code; // Code in llx_c_paiement
193 public $mode_reglement_code; // Code in llx_c_paiement
194
198 public $fk_societe_rib;
199
203 public $suspended; // status
204
208 public $auto_validate; // 0 to create in draft, 1 to create and validate the new invoice
209
213 public $generate_pdf; // 1 to generate PDF on invoice generation (default)
214
218 public $usenewcurrencyrate;
219
220
221
222 const PAYMENTCODETOEDITSOCIETERIB = "PRE";
223
224
249 // BEGIN MODULEBUILDER PROPERTIES
253 public $fields = array(
254 'rowid' => array('type' => 'integer', 'label' => 'TechnicalID', 'enabled' => 1, 'visible' => -1, 'notnull' => 1, 'position' => 10),
255 'titre' => array('type' => 'varchar(100)', 'label' => 'Titre', 'enabled' => 1, 'showoncombobox' => 1, 'visible' => -1, 'position' => 15),
256 'entity' => array('type' => 'integer', 'label' => 'Entity', 'default' => '1', 'enabled' => 1, 'visible' => -2, 'notnull' => 1, 'position' => 20, 'index' => 1),
257 'fk_soc' => array('type' => 'integer:Societe:societe/class/societe.class.php', 'label' => 'ThirdParty', 'enabled' => 'isModEnabled("societe")', 'visible' => -1, 'notnull' => 1, 'position' => 25),
258 'subtype' => array('type' => 'smallint(6)', 'label' => 'InvoiceSubtype', 'enabled' => 1, 'visible' => -1, 'notnull' => 1, 'position' => 30),
259 'datec' => array('type' => 'datetime', 'label' => 'DateCreation', 'enabled' => 1, 'visible' => -1, 'position' => 35),
260 'total_tva' => array('type' => 'double(24,8)', 'label' => 'Tva', 'enabled' => 1, 'visible' => -1, 'position' => 55, 'isameasure' => 1),
261 'localtax1' => array('type' => 'double(24,8)', 'label' => 'Localtax1', 'enabled' => 1, 'visible' => -1, 'position' => 60, 'isameasure' => 1),
262 'localtax2' => array('type' => 'double(24,8)', 'label' => 'Localtax2', 'enabled' => 1, 'visible' => -1, 'position' => 65, 'isameasure' => 1),
263 'total_ht' => array('type' => 'double(24,8)', 'label' => 'Total', 'enabled' => 1, 'visible' => -1, 'position' => 70, 'isameasure' => 1),
264 'total_ttc' => array('type' => 'double(24,8)', 'label' => 'Total ttc', 'enabled' => 1, 'visible' => -1, 'position' => 75, 'isameasure' => 1),
265 'fk_user_author' => array('type' => 'integer:User:user/class/user.class.php', 'label' => 'UserAuthor', 'enabled' => 1, 'visible' => -1, 'position' => 80),
266 'fk_projet' => array('type' => 'integer:Project:projet/class/project.class.php:1:(fk_statut:=:1)', 'label' => 'Fk projet', 'enabled' => "isModEnabled('project')", 'visible' => -1, 'position' => 85),
267 'fk_cond_reglement' => array('type' => 'integer', 'label' => 'Fk cond reglement', 'enabled' => 1, 'visible' => -1, 'position' => 90),
268 'fk_mode_reglement' => array('type' => 'integer', 'label' => 'Fk mode reglement', 'enabled' => 1, 'visible' => -1, 'position' => 95),
269 'date_lim_reglement' => array('type' => 'date', 'label' => 'Date lim reglement', 'enabled' => 1, 'visible' => -1, 'position' => 100),
270 'note_private' => array('type' => 'html', 'label' => 'NotePrivate', 'enabled' => 1, 'visible' => 0, 'position' => 105),
271 'note_public' => array('type' => 'html', 'label' => 'NotePublic', 'enabled' => 1, 'visible' => 0, 'position' => 110),
272 'modelpdf' => array('type' => 'varchar(255)', 'label' => 'Modelpdf', 'enabled' => 1, 'visible' => -1, 'position' => 115),
273 'date_when' => array('type' => 'datetime', 'label' => 'Date when', 'enabled' => 1, 'visible' => -1, 'position' => 130),
274 'date_last_gen' => array('type' => 'datetime', 'label' => 'Date last gen', 'enabled' => 1, 'visible' => -1, 'position' => 135),
275 'nb_gen_done' => array('type' => 'integer', 'label' => 'Nb gen done', 'enabled' => 1, 'visible' => -1, 'position' => 140),
276 'nb_gen_max' => array('type' => 'integer', 'label' => 'Nb gen max', 'enabled' => 1, 'visible' => -1, 'position' => 145),
277 'frequency' => array('type' => 'integer', 'label' => 'Frequency', 'enabled' => 1, 'visible' => -1, 'position' => 150),
278 'unit_frequency' => array('type' => 'varchar(2)', 'label' => 'UnitFrequency', 'enabled' => 1, 'visible' => -1, 'position' => 152),
279 'rule_for_lines_dates' => array('type' => 'varchar(255)', 'label' => 'RuleForLinesDates', 'enabled' => 'getDolGlobalInt("FACTUREREC_SUPPORT_RULE_FOR_LINES")', 'visible' => 1, 'position' => 153, 'arrayofkeyval' => array('prepaid' => "Prepaid", 'postpaid' => "Postpaid"), 'default' => 'prepaid'),
280 'usenewprice' => array('type' => 'integer', 'label' => 'UseNewPrice', 'enabled' => 1, 'visible' => 0, 'position' => 155),
281 'revenuestamp' => array('type' => 'double(24,8)', 'label' => 'RevenueStamp', 'enabled' => 1, 'visible' => -1, 'position' => 160, 'isameasure' => 1),
282 'auto_validate' => array('type' => 'integer', 'label' => 'Auto validate', 'enabled' => 1, 'visible' => -1, 'position' => 165),
283 'generate_pdf' => array('type' => 'integer', 'label' => 'Generate pdf', 'enabled' => 1, 'visible' => -1, 'position' => 170),
284 'fk_account' => array('type' => 'integer', 'label' => 'Fk account', 'enabled' => 'isModEnabled("bank")', 'visible' => -1, 'position' => 175),
285 'fk_multicurrency' => array('type' => 'integer', 'label' => 'Fk multicurrency', 'enabled' => 1, 'visible' => -1, 'position' => 180),
286 'multicurrency_code' => array('type' => 'varchar(255)', 'label' => 'Multicurrency code', 'enabled' => 1, 'visible' => -1, 'position' => 185),
287 'multicurrency_tx' => array('type' => 'double(24,8)', 'label' => 'Multicurrency tx', 'enabled' => 1, 'visible' => -1, 'position' => 190, 'isameasure' => 1),
288 'multicurrency_total_ht' => array('type' => 'double(24,8)', 'label' => 'Multicurrency total ht', 'enabled' => 1, 'visible' => -1, 'position' => 195, 'isameasure' => 1),
289 'multicurrency_total_tva' => array('type' => 'double(24,8)', 'label' => 'Multicurrency total tva', 'enabled' => 1, 'visible' => -1, 'position' => 200, 'isameasure' => 1),
290 'multicurrency_total_ttc' => array('type' => 'double(24,8)', 'label' => 'Multicurrency total ttc', 'enabled' => 1, 'visible' => -1, 'position' => 205, 'isameasure' => 1),
291 'fk_user_modif' => array('type' => 'integer:User:user/class/user.class.php', 'label' => 'UserModif', 'enabled' => 1, 'visible' => -2, 'notnull' => -1, 'position' => 210),
292 'tms' => array('type' => 'timestamp', 'label' => 'DateModification', 'enabled' => 1, 'visible' => -1, 'notnull' => 1, 'position' => 215),
293 'suspended' => array('type' => 'integer', 'label' => 'Suspended', 'enabled' => 1, 'visible' => -1, 'position' => 225),
294 'fk_societe_rib' => array('type' => 'integer', 'label' => 'Fk Societe RIB', 'enabled' => 'isModEnabled("bank")', 'visible' => -1, 'position' => 175),
295 );
296 // END MODULEBUILDER PROPERTIES
297
298 const STATUS_NOTSUSPENDED = 0;
299 const STATUS_SUSPENDED = 1;
300
301
302
308 public function __construct(DoliDB $db)
309 {
310 $this->db = $db;
311 }
312
322 public function create($user, $facid, $notrigger = 0, $onlylines = array())
323 {
324 global $conf;
325
326 $error = 0;
327 $now = dol_now();
328
329 // Clean parameters
330 $this->titre = trim(isset($this->titre) ? $this->titre : $this->title); // deprecated
331 $this->title = trim($this->title);
332 $this->usenewprice = empty($this->usenewprice) ? 0 : $this->usenewprice;
333 if (empty($this->suspended)) {
334 $this->suspended = 0;
335 }
336 if (empty($this->rule_for_lines_dates)) {
337 $this->rule_for_lines_dates = 'prepaid';
338 }
339
340 // No frequency defined then no next date to execution
341 if (empty($this->frequency)) {
342 $this->frequency = 0;
343 $this->date_when = null;
344 }
345
346 $this->frequency = abs($this->frequency);
347 $this->nb_gen_done = 0;
348 $this->nb_gen_max = empty($this->nb_gen_max) ? 0 : $this->nb_gen_max;
349 $this->auto_validate = empty($this->auto_validate) ? 0 : $this->auto_validate;
350 $this->generate_pdf = empty($this->generate_pdf) ? 0 : $this->generate_pdf;
351
352 $this->db->begin();
353
354 // Load invoice template
355 $facsrc = new Facture($this->db);
356 $result = $facsrc->fetch($facid);
357 if ($result > 0) {
358 $this->socid = $facsrc->socid;
359
360 $sql = "INSERT INTO ".MAIN_DB_PREFIX."facture_rec (";
361 $sql .= "titre";
362 $sql .= ", fk_soc";
363 $sql .= ", subtype";
364 $sql .= ", entity";
365 $sql .= ", datec";
366 $sql .= ", amount";
367 //$sql .= ", remise";
368 $sql .= ", note_private";
369 $sql .= ", note_public";
370 $sql .= ", modelpdf";
371 $sql .= ", fk_user_author";
372 $sql .= ", fk_projet";
373 $sql .= ", fk_account";
374 $sql .= ", fk_cond_reglement";
375 $sql .= ", fk_mode_reglement";
376 $sql .= ", usenewprice";
377 $sql .= ", frequency";
378 $sql .= ", unit_frequency";
379 $sql .= ", date_when";
380 $sql .= ", date_last_gen";
381 $sql .= ", nb_gen_done";
382 $sql .= ", nb_gen_max";
383 $sql .= ", auto_validate";
384 $sql .= ", generate_pdf";
385 $sql .= ", fk_multicurrency";
386 $sql .= ", multicurrency_code";
387 $sql .= ", multicurrency_tx";
388 $sql .= ", suspended";
389 $sql .= ", fk_societe_rib";
390 $sql .= ", rule_for_lines_dates";
391 $sql .= ") VALUES (";
392 $sql .= "'".$this->db->escape($this->titre ? $this->titre : $this->title)."'";
393 $sql .= ", ".((int) $this->socid);
394 $sql .= ", ".(isset($this->subtype) ? (int) $this->subtype : "null");
395 $sql .= ", ".((int) $conf->entity);
396 $sql .= ", '".$this->db->idate($now)."'";
397 $sql .= ", ".(!empty($facsrc->total_ttc) ? ((float) $facsrc->total_ttc) : '0');
398 //$sql .= ", ".(!empty($facsrc->remise_absolue) ? ((float) $this->remise_absolue) : '0');
399 $sql .= ", ".(!empty($this->note_private) ? ("'".$this->db->escape($this->note_private)."'") : "NULL");
400 $sql .= ", ".(!empty($this->note_public) ? ("'".$this->db->escape($this->note_public)."'") : "NULL");
401 $sql .= ", ".(!empty($this->model_pdf) ? ("'".$this->db->escape($this->model_pdf)."'") : "NULL");
402 $sql .= ", ".((int) $user->id);
403 $sql .= ", ".(!empty($this->fk_project) ? ((int) $this->fk_project) : "null");
404 $sql .= ", ".(!empty($facsrc->fk_account) ? ((int) $facsrc->fk_account) : "null");
405 $sql .= ", ".($this->cond_reglement_id > 0 ? ((int) $this->cond_reglement_id) : "null");
406 $sql .= ", ".($this->mode_reglement_id > 0 ? ((int) $this->mode_reglement_id) : "null");
407 $sql .= ", ".((int) $this->usenewprice);
408 $sql .= ", ".((int) $this->frequency);
409 $sql .= ", '".$this->db->escape($this->unit_frequency)."'";
410 $sql .= ", ".(!empty($this->date_when) ? "'".$this->db->idate($this->date_when)."'" : 'NULL');
411 $sql .= ", ".(!empty($this->date_last_gen) ? "'".$this->db->idate($this->date_last_gen)."'" : 'NULL');
412 $sql .= ", ".((int) $this->nb_gen_done);
413 $sql .= ", ".((int) $this->nb_gen_max);
414 $sql .= ", ".((int) $this->auto_validate);
415 $sql .= ", ".((int) $this->generate_pdf);
416 $sql .= ", ".((int) $facsrc->fk_multicurrency);
417 $sql .= ", '".$this->db->escape($facsrc->multicurrency_code)."'";
418 $sql .= ", ".((float) $facsrc->multicurrency_tx);
419 $sql .= ", ".((int) $this->suspended);
420 $sql .= ", ".(!empty($this->fk_societe_rib) ? ((int) $this->fk_societe_rib) : 'NULL');
421 $sql .= ", '".$this->db->escape($this->rule_for_lines_dates)."'";
422 $sql .= ")";
423
424 if ($this->db->query($sql)) {
425 $this->id = $this->db->last_insert_id(MAIN_DB_PREFIX."facture_rec");
426
427 // Fields used into addline later
428 $this->fk_multicurrency = $facsrc->fk_multicurrency;
429 $this->multicurrency_code = $facsrc->multicurrency_code;
430 $this->multicurrency_tx = $facsrc->multicurrency_tx;
431
432 // Add lines
433 $fk_parent_line = 0;
434
435 $num = count($facsrc->lines);
436 for ($i = 0; $i < $num; $i++) {
437 $facline = $facsrc->lines[$i];
438 '@phan-var-force FactureLigneRec $facline';
439 if (!empty($onlylines) && !in_array($facline->id, $onlylines)) {
440 continue; // Skip unselected lines
441 }
442
443 // Reset fk_parent_line for no child products and special product
444 if (($facline->product_type != 9 && empty($facline->fk_parent_line)) || $facline->product_type == 9) {
445 $fk_parent_line = 0;
446 }
447
448 $tva_tx = $facline->tva_tx;
449 if (!empty($facline->vat_src_code) && !preg_match('/\‍(/', (string) $tva_tx)) {
450 $tva_tx .= ' ('.$facline->vat_src_code.')';
451 }
452
453 $default_start_fill = getDolGlobalInt('INVOICEREC_SET_AUTOFILL_DATE_START');
454 $default_end_fill = getDolGlobalInt('INVOICEREC_SET_AUTOFILL_DATE_END');
455
456 $result_insert = $this->addline(
457 $facline->desc,
458 $facline->subprice,
459 $facline->qty,
460 $tva_tx,
461 $facline->localtax1_tx,
462 $facline->localtax2_tx,
463 $facline->fk_product,
464 $facline->remise_percent,
465 'HT',
466 $facline->info_bits,
467 0,
468 0,
469 $facline->product_type,
470 $facline->rang,
471 $facline->special_code,
472 $facline->label,
473 $facline->fk_unit,
474 $facline->multicurrency_subprice,
475 $default_start_fill,
476 $default_end_fill,
477 0,
478 $facline->pa_ht,
479 $fk_parent_line
480 );
481
482 // Defined the new fk_parent_line
483 if ($result_insert > 0 && $facline->product_type == 9) {
484 $fk_parent_line = $result_insert;
485 }
486
487 if ($result_insert < 0) {
488 $error++;
489 } else {
490 $objectline = new FactureLigneRec($this->db);
491
492 $result2 = $objectline->fetch($result_insert);
493 if ($result2 > 0) {
494 // Extrafields
495 if (method_exists($facline, 'fetch_optionals')) {
496 $facline->fetch_optionals($facline->id);
497 $objectline->array_options = $facline->array_options;
498 }
499
500 $result = $objectline->insertExtraFields();
501 if ($result < 0) {
502 $error++;
503 }
504
505 $objectline->extraparams = $facline->extraparams;
506 $result = $objectline->setExtraParameters();
507 if ($result < 0) {
508 $error++;
509 }
510 } elseif ($result2 < 0) {
511 $this->errors[] = $objectline->error;
512 $error++;
513 }
514 }
515 }
516
517 if (!empty($this->linkedObjectsIds) && empty($this->linked_objects)) { // To use new linkedObjectsIds instead of old linked_objects
518 $this->linked_objects = $this->linkedObjectsIds; // TODO Replace linked_objects with linkedObjectsIds
519 }
520
521 // Add object linked
522 if (!$error && $this->id && !empty($this->linked_objects) && is_array($this->linked_objects)) {
523 foreach ($this->linked_objects as $origin => $tmp_origin_id) {
524 if (is_array($tmp_origin_id)) { // New behaviour, if linked_object can have several links per type, so is something like array('contract'=>array(id1, id2, ...))
525 foreach ($tmp_origin_id as $origin_id) {
526 $ret = $this->add_object_linked($origin, $origin_id);
527 if (!$ret) {
528 $this->error = $this->db->lasterror();
529 $error++;
530 }
531 }
532 } else { // Old behaviour, if linked_object has only one link per type, so is something like array('contract'=>id1))
533 $origin_id = $tmp_origin_id;
534 $ret = $this->add_object_linked($origin, $origin_id);
535 if (!$ret) {
536 $this->error = $this->db->lasterror();
537 $error++;
538 }
539 }
540 }
541 }
542
543 if (!$error) {
544 $result = $this->insertExtraFields();
545 if ($result < 0) {
546 $error++;
547 }
548 }
549
550 if (!$error && !$notrigger) {
551 // Call trigger
552 $result = $this->call_trigger('BILLREC_CREATE', $user);
553 if ($result < 0) {
554 $this->db->rollback();
555 return -2;
556 }
557 // End call triggers
558 }
559
560 if ($error) {
561 $this->db->rollback();
562 return -3;
563 } else {
564 $this->db->commit();
565 return $this->id;
566 }
567 } else {
568 $this->error = $this->db->lasterror();
569 $this->db->rollback();
570 return -2;
571 }
572 } else {
573 $this->db->rollback();
574 return -1;
575 }
576 }
577
578
586 public function update(User $user, $notrigger = 0)
587 {
588 $error = 0;
589
590 $sql = "UPDATE ".MAIN_DB_PREFIX."facture_rec SET";
591 $sql .= " entity = ".((int) $this->entity).",";
592 $sql .= " titre = '".$this->db->escape($this->title)."',";
593 $sql .= " suspended = ".((int) $this->suspended).",";
594 $sql .= " fk_soc = ".((int) $this->socid).",";
595 $sql .= " total_tva = ".((float) $this->total_tva).",";
596 $sql .= " localtax1 = ".((float) $this->total_localtax1).",";
597 $sql .= " localtax2 = ".((float) $this->total_localtax2).",";
598 $sql .= " total_ht = ".((float) $this->total_ht).",";
599 $sql .= " total_ttc = ".((float) $this->total_ttc).",";
600 $sql .= " fk_societe_rib = ".(!empty($this->fk_societe_rib) ? ((int) $this->fk_societe_rib) : 'NULL');
601
602 // TODO Add missing fields
603 $sql .= " WHERE rowid = ".((int) $this->id);
604
605 $this->db->begin();
606
607 dol_syslog(get_class($this)."::update", LOG_DEBUG);
608
609 $resql = $this->db->query($sql);
610 if ($resql) {
611 if (!$error) {
612 $result = $this->insertExtraFields();
613 if ($result < 0) {
614 $error++;
615 }
616 }
617
618 if (!$error && !$notrigger) {
619 // Call trigger
620 $result = $this->call_trigger('BILLREC_MODIFY', $user);
621 if ($result < 0) {
622 $this->db->rollback();
623 return -2;
624 }
625 // End call triggers
626 }
627 $this->db->commit();
628 return 1;
629 } else {
630 $this->error = $this->db->lasterror();
631 $this->db->rollback();
632 return -1;
633 }
634 }
635
646 public function fetch($rowid, $ref = '', $ref_ext = '', $noextrafields = 0, $nolines = 0)
647 {
648 dol_syslog('FactureRec::fetch', LOG_DEBUG);
649
650 $sql = 'SELECT f.rowid, f.entity, f.titre as title, f.suspended, f.fk_soc, f.subtype, f.total_tva, f.localtax1, f.localtax2, f.total_ht, f.total_ttc';
651 $sql .= ', f.date_lim_reglement as dlr';
652 $sql .= ', f.note_private, f.note_public, f.fk_user_author';
653 $sql .= ', f.modelpdf as model_pdf';
654 $sql .= ', f.fk_mode_reglement, f.fk_cond_reglement, f.fk_projet as fk_project';
655 $sql .= ', f.fk_account, f.fk_societe_rib';
656 $sql .= ', f.frequency, f.unit_frequency, f.rule_for_lines_dates, f.date_when, f.date_last_gen, f.nb_gen_done, f.nb_gen_max, f.usenewprice, f.auto_validate';
657 $sql .= ', f.generate_pdf';
658 $sql .= ", f.fk_multicurrency, f.multicurrency_code, f.multicurrency_tx, f.multicurrency_total_ht, f.multicurrency_total_tva, f.multicurrency_total_ttc";
659 $sql .= ', p.code as mode_reglement_code, p.libelle as mode_reglement_libelle';
660 $sql .= ', c.code as cond_reglement_code, c.libelle as cond_reglement_libelle, c.libelle_facture as cond_reglement_libelle_doc';
661 //$sql.= ', el.fk_source';
662 $sql .= ' FROM '.MAIN_DB_PREFIX.'facture_rec as f';
663 $sql .= ' LEFT JOIN '.MAIN_DB_PREFIX.'c_payment_term as c ON f.fk_cond_reglement = c.rowid';
664 $sql .= ' LEFT JOIN '.MAIN_DB_PREFIX.'c_paiement as p ON f.fk_mode_reglement = p.id';
665 //$sql.= " LEFT JOIN ".MAIN_DB_PREFIX."element_element as el ON el.fk_target = f.rowid AND el.targettype = 'facture'";
666 $sql .= ' WHERE f.entity IN ('.getEntity('invoice').')';
667 if ($rowid) {
668 $sql .= ' AND f.rowid = '.((int) $rowid);
669 } elseif ($ref) {
670 $sql .= " AND f.titre = '".$this->db->escape($ref)."'";
671 } else {
672 $sql .= ' AND f.rowid = 0';
673 }
674 /* This field are not used for template invoice
675 if ($ref_ext) $sql.= " AND f.ref_ext='".$this->db->escape($ref_ext)."'";
676 */
677
678 $result = $this->db->query($sql);
679 if ($result) {
680 if ($this->db->num_rows($result)) {
681 $obj = $this->db->fetch_object($result);
682
683 $this->id = $obj->rowid;
684 $this->entity = $obj->entity;
685 $this->titre = $obj->title; // deprecated
686 $this->title = $obj->title;
687 $this->ref = $obj->title;
688 $this->subtype = $obj->subtype;
689 $this->suspended = $obj->suspended;
690 $this->total_ht = $obj->total_ht;
691 $this->total_tva = $obj->total_tva;
692 $this->total_localtax1 = $obj->localtax1;
693 $this->total_localtax2 = $obj->localtax2;
694 $this->total_ttc = $obj->total_ttc;
695 $this->socid = $obj->fk_soc;
696 $this->date_lim_reglement = $this->db->jdate($obj->dlr);
697 $this->mode_reglement_id = $obj->fk_mode_reglement;
698 $this->mode_reglement_code = $obj->mode_reglement_code;
699 $this->mode_reglement = $obj->mode_reglement_libelle;
700 $this->cond_reglement_id = $obj->fk_cond_reglement;
701 $this->cond_reglement_code = $obj->cond_reglement_code;
702 $this->cond_reglement = $obj->cond_reglement_libelle;
703 $this->cond_reglement_doc = $obj->cond_reglement_libelle_doc;
704 $this->fk_project = $obj->fk_project;
705 $this->fk_account = $obj->fk_account;
706 $this->fk_societe_rib = $obj->fk_societe_rib;
707 $this->note_private = $obj->note_private;
708 $this->note_public = $obj->note_public;
709 $this->user_creation_id = $obj->fk_user_author;
710 $this->model_pdf = $obj->model_pdf;
711 //$this->special_code = $obj->special_code;
712 $this->frequency = $obj->frequency;
713 $this->unit_frequency = $obj->unit_frequency;
714 $this->rule_for_lines_dates = $obj->rule_for_lines_dates;
715 $this->date_when = $this->db->jdate($obj->date_when);
716 $this->date_last_gen = $this->db->jdate($obj->date_last_gen);
717 $this->nb_gen_done = $obj->nb_gen_done;
718 $this->nb_gen_max = $obj->nb_gen_max;
719 $this->usenewprice = $obj->usenewprice;
720 $this->auto_validate = $obj->auto_validate;
721 $this->generate_pdf = $obj->generate_pdf;
722
723 // Multicurrency
724 $this->fk_multicurrency = $obj->fk_multicurrency;
725 $this->multicurrency_code = $obj->multicurrency_code;
726 $this->multicurrency_tx = $obj->multicurrency_tx;
727 $this->multicurrency_total_ht = $obj->multicurrency_total_ht;
728 $this->multicurrency_total_tva = $obj->multicurrency_total_tva;
729 $this->multicurrency_total_ttc = $obj->multicurrency_total_ttc;
730
731 // Retrieve all extrafield
732 // fetch optionals attributes and labels
733 if (empty($noextrafields)) {
734 $result = $this->fetch_optionals();
735 if ($result < 0) {
736 $this->error = $this->db->lasterror();
737 return -4;
738 }
739 }
740
741 // Retrieve lines
742 if (empty($nolines)) {
743 $result = $this->fetch_lines();
744 if ($result < 0) {
745 $this->error = $this->db->lasterror();
746 return -3;
747 }
748 }
749
750 return 1;
751 } else {
752 $this->error = 'Bill with id '.$rowid.' or ref '.$ref.' not found';
753 dol_syslog('Facture::Fetch Error '.$this->error, LOG_ERR);
754 return -2;
755 }
756 } else {
757 $this->error = $this->db->error();
758 return -1;
759 }
760 }
761
762
768 public function getLinesArray()
769 {
770 return $this->fetch_lines();
771 }
772
773
774 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
780 public function fetch_lines()
781 {
782 // phpcs:enable
783
784 $this->lines = array();
785
786 dol_syslog('FactureRec::fetch_lines', LOG_DEBUG);
787
788 $sql = 'SELECT l.rowid, l.fk_facture, l.fk_product, l.fk_parent_line, l.product_type, l.label as custom_label, l.description, l.product_type, l.price, l.qty, l.vat_src_code, l.tva_tx, ';
789 $sql .= ' l.localtax1_tx, l.localtax2_tx, l.localtax1_type, l.localtax2_type, l.remise, l.remise_percent, l.subprice,';
790 $sql .= ' l.info_bits, l.date_start_fill, l.date_end_fill, l.total_ht, l.total_tva, l.total_ttc, l.fk_product_fournisseur_price, l.buy_price_ht as pa_ht,';
791 $sql .= ' l.rang, l.special_code,';
792 $sql .= ' l.fk_unit, l.fk_contract_line, l.extraparams,';
793 $sql .= ' l.fk_multicurrency, l.multicurrency_code, l.multicurrency_subprice, l.multicurrency_total_ht, l.multicurrency_total_tva, l.multicurrency_total_ttc,';
794 $sql .= ' p.ref as product_ref, p.fk_product_type as fk_product_type, p.label as product_label, p.description as product_desc';
795 $sql .= ' FROM '.MAIN_DB_PREFIX.'facturedet_rec as l';
796 $sql .= ' LEFT JOIN '.MAIN_DB_PREFIX.'product as p ON l.fk_product = p.rowid';
797 $sql .= ' WHERE l.fk_facture = '.((int) $this->id);
798 $sql .= ' ORDER BY l.rang';
799
800 $result = $this->db->query($sql);
801 if ($result) {
802 $num = $this->db->num_rows($result);
803 $i = 0;
804 while ($i < $num) {
805 $objp = $this->db->fetch_object($result);
806 $line = new FactureLigneRec($this->db);
807
808 $line->id = $objp->rowid;
809 $line->rowid = $objp->rowid;
810 $line->fk_facture = $objp->fk_facture;
811 $line->fk_parent_line = $objp->fk_parent_line;
812 $line->desc = $objp->description; // Description line
813 $line->description = $objp->description; // Description line
814 $line->ref = $objp->product_ref; // Ref product
815 $line->product_ref = $objp->product_ref; // Ref product
816 $line->libelle = $objp->product_label; // deprecated
817 $line->product_label = $objp->product_label; // Label product
818 $line->product_desc = $objp->product_desc; // Description product
819 $line->product_type = $objp->product_type; // Type of line
820 $line->fk_product_type = $objp->fk_product_type; // Type of product
821 $line->qty = $objp->qty;
822 $line->subprice = $objp->subprice;
823
824 $line->label = $objp->custom_label; // @deprecated
825
826 $line->vat_src_code = $objp->vat_src_code;
827 $line->tva_tx = $objp->tva_tx;
828 $line->localtax1_tx = $objp->localtax1_tx;
829 $line->localtax2_tx = $objp->localtax2_tx;
830 $line->localtax1_type = $objp->localtax1_type;
831 $line->localtax2_type = $objp->localtax2_type;
832 $line->remise_percent = $objp->remise_percent;
833 //$line->fk_remise_except = $objp->fk_remise_except;
834 $line->fk_product = $objp->fk_product;
835 $line->date_start_fill = $objp->date_start_fill;
836 $line->date_end_fill = $objp->date_end_fill;
837 $line->info_bits = $objp->info_bits;
838 $line->total_ht = $objp->total_ht;
839 $line->total_tva = $objp->total_tva;
840 $line->total_ttc = $objp->total_ttc;
841
842 $line->fk_product_fournisseur_price = $objp->fk_product_fournisseur_price;
843 $line->fk_fournprice = $objp->fk_product_fournisseur_price; // For backward compatibility
844
845 $marginInfos = getMarginInfos($objp->subprice, $objp->remise_percent, $objp->tva_tx, $objp->localtax1_tx, $objp->localtax2_tx, $objp->fk_product_fournisseur_price, $objp->pa_ht);
846
847 $line->buyprice = $marginInfos[0];
848 $line->pa_ht = $marginInfos[0]; // For backward compatibility
849 $line->marge_tx = (string) $marginInfos[1];
850 $line->marque_tx = (string) $marginInfos[2];
851 $line->rang = $objp->rang;
852 $line->special_code = $objp->special_code;
853 $line->fk_unit = $objp->fk_unit;
854 $line->fk_contract_line = $objp->fk_contract_line;
855
856 $line->extraparams = !empty($objp->extraparams) ? (array) json_decode($objp->extraparams, true) : array();
857
858 // Ne plus utiliser
859 $line->price = $objp->price;
860 $line->remise = $objp->remise;
861
862 $line->fetch_optionals();
863
864 // Multicurrency
865 $line->fk_multicurrency = $objp->fk_multicurrency;
866 $line->multicurrency_code = $objp->multicurrency_code;
867 $line->multicurrency_subprice = $objp->multicurrency_subprice;
868 $line->multicurrency_total_ht = $objp->multicurrency_total_ht;
869 $line->multicurrency_total_tva = $objp->multicurrency_total_tva;
870 $line->multicurrency_total_ttc = $objp->multicurrency_total_ttc;
871
872 $this->lines[$i] = $line;
873
874 $i++;
875 }
876
877 $this->db->free($result);
878 return 1;
879 } else {
880 $this->error = $this->db->lasterror();
881 return -3;
882 }
883 }
884
885
894 public function delete(User $user, $notrigger = 0, $idwarehouse = -1)
895 {
896 $rowid = $this->id;
897
898 dol_syslog(get_class($this)."::delete rowid=".((int) $rowid), LOG_DEBUG);
899
900 $error = 0;
901 $this->db->begin();
902
903 $main = MAIN_DB_PREFIX.'facturedet_rec';
904 $ef = $main."_extrafields";
905
906 $sqlef = "DELETE FROM $ef WHERE fk_object IN (SELECT rowid FROM ".$main." WHERE fk_facture = ".((int) $rowid).")";
907 $sql = "DELETE FROM ".MAIN_DB_PREFIX."facturedet_rec WHERE fk_facture = ".((int) $rowid);
908
909 if ($this->db->query($sqlef) && $this->db->query($sql)) {
910 $sql = "DELETE FROM ".MAIN_DB_PREFIX."facture_rec WHERE rowid = ".((int) $rowid);
911 dol_syslog($sql);
912 if ($this->db->query($sql)) {
913 // Delete linked object
914 $res = $this->deleteObjectLinked();
915 if ($res < 0) {
916 $error = -3;
917 }
918 // Delete extrafields
919 $res = $this->deleteExtraFields();
920 if ($res < 0) {
921 $error = -4;
922 }
923 } else {
924 $this->error = $this->db->lasterror();
925 $error = -1;
926 }
927 } else {
928 $this->error = $this->db->lasterror();
929 $error = -2;
930 }
931 if (!$error && !$notrigger) {
932 // Call trigger
933 $result = $this->call_trigger('BILLREC_DELETE', $user);
934 if ($result < 0) {
935 $error++;
936 }
937 // End call triggers
938 }
939 if (!$error) {
940 $this->db->commit();
941 return 1;
942 } else {
943 $this->db->rollback();
944 return $error;
945 }
946 }
947
948
977 public function addline($desc, $pu_ht, $qty, $txtva, $txlocaltax1 = 0, $txlocaltax2 = 0, $fk_product = 0, $remise_percent = 0, $price_base_type = 'HT', $info_bits = 0, $fk_remise_except = 0, $pu_ttc = 0, $type = 0, $rang = -1, $special_code = 0, $label = '', $fk_unit = null, $pu_ht_devise = 0, $date_start_fill = 0, $date_end_fill = 0, $fk_fournprice = null, $pa_ht = 0, $fk_parent_line = 0)
978 {
979 global $mysoc;
980
981 $facid = $this->id;
982
983 dol_syslog(get_class($this)."::addline facid=$facid,desc=$desc,pu_ht=$pu_ht,qty=$qty,txtva=$txtva,txlocaltax1=$txlocaltax1,txlocaltax2=$txlocaltax2,fk_product=$fk_product,remise_percent=$remise_percent,info_bits=$info_bits,fk_remise_except=$fk_remise_except,price_base_type=$price_base_type,pu_ttc=$pu_ttc,type=$type,fk_unit=$fk_unit,pu_ht_devise=$pu_ht_devise,date_start_fill=$date_start_fill,date_end_fill=$date_end_fill,pa_ht=$pa_ht", LOG_DEBUG);
984 include_once DOL_DOCUMENT_ROOT.'/core/lib/price.lib.php';
985
986 // Check parameters
987 if ($type < 0) {
988 return -1;
989 }
990
991 $localtaxes_type = getLocalTaxesFromRate((float) $txtva, 0, $this->thirdparty, $mysoc);
992
993 // Clean vat code
994 $reg = array();
995 $vat_src_code = '';
996 if (preg_match('/\‍((.*)\‍)/', (string) $txtva, $reg)) {
997 $vat_src_code = $reg[1];
998 $txtva = preg_replace('/\s*\‍(.*\‍)/', '', (string) $txtva); // Remove code from vatrate.
999 }
1000
1001
1002 // Clean parameters
1003 $remise_percent = price2num($remise_percent);
1004 if (empty($remise_percent)) {
1005 $remise_percent = 0;
1006 }
1007 $qty = (float) price2num($qty);
1008 $pu_ht = (float) price2num($pu_ht);
1009 $pu_ttc = (float) price2num($pu_ttc);
1010 if (!preg_match('/\‍((.*)\‍)/', $txtva)) {
1011 $txtva = price2num($txtva); // $txtva can have format '5.0(XXX)' or '5'
1012 }
1013 $txlocaltax1 = (float) price2num($txlocaltax1);
1014 $txlocaltax2 = (float) price2num($txlocaltax2);
1015 if (empty($txtva)) {
1016 $txtva = 0;
1017 }
1018 if (empty($txlocaltax1)) {
1019 $txlocaltax1 = 0;
1020 }
1021 if (empty($txlocaltax2)) {
1022 $txlocaltax2 = 0;
1023 }
1024 if (empty($info_bits)) {
1025 $info_bits = 0;
1026 }
1027
1028 if ($price_base_type == 'HT') {
1029 $pu = $pu_ht;
1030 } else {
1031 $pu = $pu_ttc;
1032 }
1033
1034 // Calcul du total TTC et de la TVA pour la ligne a partir de
1035 // qty, pu, remise_percent et txtva
1036 // TRES IMPORTANT: C'est au moment de l'insertion ligne qu'on doit stocker
1037 // la part ht, tva et ttc, et ce au niveau de la ligne qui a son propre taux tva.
1038
1039 $tabprice = calcul_price_total($qty, $pu, $remise_percent, $txtva, $txlocaltax1, $txlocaltax2, 0, $price_base_type, $info_bits, $type, $mysoc, $localtaxes_type, 100, $this->multicurrency_tx, $pu_ht_devise);
1040 $total_ht = $tabprice[0];
1041 $total_tva = $tabprice[1];
1042 $total_ttc = $tabprice[2];
1043 $total_localtax1 = $tabprice[9];
1044 $total_localtax2 = $tabprice[10];
1045 $pu_ht = $tabprice[3];
1046
1047 // MultiCurrency
1048 $multicurrency_total_ht = $tabprice[16];
1049 $multicurrency_total_tva = $tabprice[17];
1050 $multicurrency_total_ttc = $tabprice[18];
1051 $pu_ht_devise = $tabprice[19];
1052
1053 $product_type = $type;
1054 if ($fk_product) {
1055 $product = new Product($this->db);
1056 $result = $product->fetch($fk_product);
1057 $product_type = $product->type;
1058 }
1059
1060 if (empty($fk_parent_line) || $fk_parent_line < 0) {
1061 $fk_parent_line = 0;
1062 }
1063
1064 // Rank to use
1065 $ranktouse = $rang;
1066 if ($ranktouse == -1) {
1067 $rangmax = $this->line_max(0);
1068 $ranktouse = $rangmax + 1;
1069 }
1070
1071 $sql = "INSERT INTO ".MAIN_DB_PREFIX."facturedet_rec (";
1072 $sql .= "fk_facture";
1073 $sql .= ", fk_parent_line";
1074 $sql .= ", label";
1075 $sql .= ", description";
1076 $sql .= ", price";
1077 $sql .= ", qty";
1078 $sql .= ", tva_tx";
1079 $sql .= ", vat_src_code";
1080 $sql .= ", localtax1_tx";
1081 $sql .= ", localtax1_type";
1082 $sql .= ", localtax2_tx";
1083 $sql .= ", localtax2_type";
1084 $sql .= ", fk_product";
1085 $sql .= ", product_type";
1086 $sql .= ", remise_percent";
1087 $sql .= ", subprice";
1088 $sql .= ", remise";
1089 $sql .= ", total_ht";
1090 $sql .= ", total_tva";
1091 $sql .= ", total_localtax1";
1092 $sql .= ", total_localtax2";
1093 $sql .= ", total_ttc";
1094 $sql .= ", date_start_fill";
1095 $sql .= ", date_end_fill";
1096 $sql .= ", fk_product_fournisseur_price";
1097 $sql .= ", buy_price_ht";
1098 $sql .= ", info_bits";
1099 $sql .= ", rang";
1100 $sql .= ", special_code";
1101 $sql .= ", fk_unit";
1102 $sql .= ', fk_multicurrency, multicurrency_code, multicurrency_subprice, multicurrency_total_ht, multicurrency_total_tva, multicurrency_total_ttc';
1103 $sql .= ") VALUES (";
1104 $sql .= " ".((int) $facid);
1105 $sql .= ", ".($fk_parent_line > 0 ? ((int) $fk_parent_line) : "null");
1106 $sql .= ", ".(!empty($label) ? "'".$this->db->escape($label)."'" : "null");
1107 $sql .= ", '".$this->db->escape($desc)."'";
1108 $sql .= ", ".price2num($pu_ht);
1109 $sql .= ", ".price2num($qty);
1110 $sql .= ", ".price2num($txtva);
1111 $sql .= ", '".$this->db->escape($vat_src_code)."'";
1112 $sql .= ", ".price2num($txlocaltax1);
1113 $sql .= ", '".$this->db->escape(isset($localtaxes_type[0]) ? $localtaxes_type[0] : '')."'";
1114 $sql .= ", ".price2num($txlocaltax2);
1115 $sql .= ", '".$this->db->escape(isset($localtaxes_type[2]) ? $localtaxes_type[2] : '')."'";
1116 $sql .= ", ".(!empty($fk_product) ? "'".$this->db->escape((string) $fk_product)."'" : "null");
1117 $sql .= ", ".((int) $product_type);
1118 $sql .= ", ".price2num($remise_percent);
1119 $sql .= ", ".price2num($pu_ht);
1120 $sql .= ", null";
1121 $sql .= ", ".price2num($total_ht);
1122 $sql .= ", ".price2num($total_tva);
1123 $sql .= ", ".price2num($total_localtax1);
1124 $sql .= ", ".price2num($total_localtax2);
1125 $sql .= ", ".price2num($total_ttc);
1126 $sql .= ", ".(int) $date_start_fill;
1127 $sql .= ", ".(int) $date_end_fill;
1128 $sql .= ", ".($fk_fournprice > 0 ? $fk_fournprice : 'null');
1129 $sql .= ", ".($pa_ht ? price2num($pa_ht) : 0);
1130 $sql .= ", ".((int) $info_bits);
1131 $sql .= ", ".((int) $ranktouse);
1132 $sql .= ", ".((int) $special_code);
1133 $sql .= ", ".($fk_unit ? ((int) $fk_unit) : "null");
1134 $sql .= ", ".(int) $this->fk_multicurrency;
1135 $sql .= ", '".$this->db->escape($this->multicurrency_code)."'";
1136 $sql .= ", ".price2num($pu_ht_devise, 'CU');
1137 $sql .= ", ".price2num($multicurrency_total_ht, 'CT');
1138 $sql .= ", ".price2num($multicurrency_total_tva, 'CT');
1139 $sql .= ", ".price2num($multicurrency_total_ttc, 'CT');
1140 $sql .= ")";
1141
1142 dol_syslog(get_class($this)."::addline", LOG_DEBUG);
1143 if ($this->db->query($sql)) {
1144 $lineId = $this->db->last_insert_id(MAIN_DB_PREFIX."facturedet_rec");
1145 $this->id = $facid;
1146 $this->update_price(1);
1147 return $lineId;
1148 } else {
1149 $this->error = $this->db->lasterror();
1150 return -1;
1151 }
1152 }
1153
1184 public function updateline($rowid, $desc, $pu_ht, $qty, $txtva, $txlocaltax1 = 0, $txlocaltax2 = 0, $fk_product = 0, $remise_percent = 0, $price_base_type = 'HT', $info_bits = 0, $fk_remise_except = 0, $pu_ttc = 0, $type = 0, $rang = -1, $special_code = 0, $label = '', $fk_unit = null, $pu_ht_devise = 0, $notrigger = 0, $date_start_fill = 0, $date_end_fill = 0, $fk_fournprice = null, $pa_ht = 0, $fk_parent_line = 0)
1185 {
1186 global $mysoc;
1187
1188 if (!$this->isLineOfObject($rowid)) {
1189 $this->error = 'ErrorLineIDDoesNotMatchWithObjectID';
1190 return -1;
1191 }
1192
1193 $facid = $this->id;
1194
1195 dol_syslog(get_class($this)."::updateline facid=".$facid." rowid=$rowid, desc=$desc, pu_ht=$pu_ht, qty=$qty, txtva=$txtva, txlocaltax1=$txlocaltax1, txlocaltax2=$txlocaltax2, fk_product=$fk_product, remise_percent=$remise_percent, info_bits=$info_bits, fk_remise_except=$fk_remise_except, price_base_type=$price_base_type, pu_ttc=$pu_ttc, type=$type, fk_unit=$fk_unit, pu_ht_devise=$pu_ht_devise", LOG_DEBUG);
1196 include_once DOL_DOCUMENT_ROOT.'/core/lib/price.lib.php';
1197
1198 // Clean parameters
1199 if (empty($remise_percent)) {
1200 $remise_percent = 0;
1201 }
1202
1203 // Check parameters
1204 if ($type < 0) {
1205 return -1;
1206 }
1207
1208 // Clean parameters
1209 $remise_percent = (float) price2num($remise_percent);
1210 $qty = (float) price2num($qty);
1211 if (empty($info_bits)) {
1212 $info_bits = 0;
1213 }
1214 $pu_ht = (float) price2num($pu_ht);
1215 $pu_ttc = (float) price2num($pu_ttc);
1216 $pu_ht_devise = (float) price2num($pu_ht_devise);
1217 if (!preg_match('/\‍((.*)\‍)/', (string) $txtva)) {
1218 $txtva = price2num($txtva); // $txtva can have format '5.0(XXX)' or '5'
1219 }
1220 $txlocaltax1 = (float) price2num($txlocaltax1);
1221 $txlocaltax2 = (float) price2num($txlocaltax2);
1222 if (empty($txlocaltax1)) {
1223 $txlocaltax1 = 0;
1224 }
1225 if (empty($txlocaltax2)) {
1226 $txlocaltax2 = 0;
1227 }
1228
1229 if (empty($this->multicurrency_subprice)) {
1230 $this->multicurrency_subprice = 0;
1231 }
1232 if (empty($this->multicurrency_total_ht)) {
1233 $this->multicurrency_total_ht = 0;
1234 }
1235 if (empty($this->multicurrency_total_tva)) {
1236 $this->multicurrency_total_tva = 0;
1237 }
1238 if (empty($this->multicurrency_total_ttc)) {
1239 $this->multicurrency_total_ttc = 0;
1240 }
1241
1242 if ($price_base_type == 'HT') {
1243 $pu = $pu_ht;
1244 } else {
1245 $pu = $pu_ttc;
1246 }
1247
1248 // Calculate total with, without tax and tax from qty, pu, remise_percent and txtva
1249 // TRES IMPORTANT: C'est au moment de l'insertion ligne qu'on doit stocker
1250 // la part ht, tva et ttc, et ce au niveau de la ligne qui a son propre taux tva.
1251
1252 $localtaxes_type = getLocalTaxesFromRate($txtva, 0, $this->thirdparty, $mysoc);
1253
1254 // Clean vat code
1255 $vat_src_code = '';
1256 $reg = array();
1257 if (preg_match('/\‍((.*)\‍)/', $txtva, $reg)) {
1258 $vat_src_code = $reg[1];
1259 $txtva = preg_replace('/\s*\‍(.*\‍)/', '', $txtva); // Remove code into vatrate.
1260 }
1261
1262 $tabprice = calcul_price_total($qty, $pu, $remise_percent, $txtva, $txlocaltax1, $txlocaltax2, 0, $price_base_type, $info_bits, $type, $mysoc, $localtaxes_type, 100, $this->multicurrency_tx, $pu_ht_devise);
1263
1264 $total_ht = $tabprice[0];
1265 $total_tva = $tabprice[1];
1266 $total_ttc = $tabprice[2];
1267 $total_localtax1 = $tabprice[9];
1268 $total_localtax2 = $tabprice[10];
1269 $pu_ht = $tabprice[3];
1270 $pu_tva = $tabprice[4];
1271 $pu_ttc = $tabprice[5];
1272
1273 // MultiCurrency
1274 $multicurrency_total_ht = $tabprice[16];
1275 $multicurrency_total_tva = $tabprice[17];
1276 $multicurrency_total_ttc = $tabprice[18];
1277 $pu_ht_devise = $tabprice[19];
1278
1279 $product_type = $type;
1280 if ($fk_product) {
1281 $product = new Product($this->db);
1282 $result = $product->fetch($fk_product);
1283 $product_type = $product->type;
1284 }
1285
1286 if (empty($fk_parent_line) || $fk_parent_line < 0) {
1287 $fk_parent_line = 0;
1288 }
1289
1290 $sql = "UPDATE ".MAIN_DB_PREFIX."facturedet_rec SET ";
1291 $sql .= "fk_facture = ".((int) $facid);
1292 $sql .= ", fk_parent_line = ".($fk_parent_line > 0 ? ((int) $fk_parent_line) : "null");
1293 $sql .= ", label=".(!empty($label) ? "'".$this->db->escape($label)."'" : "null");
1294 $sql .= ", description='".$this->db->escape($desc)."'";
1295 $sql .= ", price=".price2num($pu_ht);
1296 $sql .= ", qty=".price2num($qty);
1297 $sql .= ", tva_tx=".price2num($txtva);
1298 $sql .= ", vat_src_code='".$this->db->escape($vat_src_code)."'";
1299 $sql .= ", localtax1_tx=".((float) $txlocaltax1);
1300 $sql .= ", localtax1_type='".$this->db->escape($localtaxes_type[0])."'";
1301 $sql .= ", localtax2_tx=".((float) $txlocaltax2);
1302 $sql .= ", localtax2_type='".$this->db->escape($localtaxes_type[2])."'";
1303 $sql .= ", fk_product=".(!empty($fk_product) ? "'".$this->db->escape((string) $fk_product)."'" : "null");
1304 $sql .= ", product_type=".((int) $product_type);
1305 $sql .= ", remise_percent='".price2num($remise_percent)."'";
1306 $sql .= ", subprice='".price2num($pu_ht)."'";
1307 $sql .= ", total_ht='".price2num($total_ht)."'";
1308 $sql .= ", total_tva='".price2num($total_tva)."'";
1309 $sql .= ", total_localtax1='".price2num($total_localtax1)."'";
1310 $sql .= ", total_localtax2='".price2num($total_localtax2)."'";
1311 $sql .= ", total_ttc='".price2num($total_ttc)."'";
1312 $sql .= ", date_start_fill=".((int) $date_start_fill);
1313 $sql .= ", date_end_fill=".((int) $date_end_fill);
1314 $sql .= ", fk_product_fournisseur_price=".($fk_fournprice > 0 ? (int) $fk_fournprice : 'null');
1315 $sql .= ", buy_price_ht=".($pa_ht ? price2num($pa_ht) : 0);
1316 $sql .= ", info_bits=".((int) $info_bits);
1317 $sql .= ", rang=".((int) $rang);
1318 $sql .= ", special_code=".((int) $special_code);
1319 $sql .= ", fk_unit=".($fk_unit ? "'".$this->db->escape((string) $fk_unit)."'" : "null");
1320 $sql .= ', multicurrency_subprice = '.price2num($pu_ht_devise);
1321 $sql .= ', multicurrency_total_ht = '.price2num($multicurrency_total_ht);
1322 $sql .= ', multicurrency_total_tva = '.price2num($multicurrency_total_tva);
1323 $sql .= ', multicurrency_total_ttc = '.price2num($multicurrency_total_ttc);
1324 $sql .= " WHERE rowid = ".((int) $rowid);
1325
1326 dol_syslog(get_class($this)."::updateline", LOG_DEBUG);
1327 if ($this->db->query($sql)) {
1328 $this->id = $facid;
1329 $this->update_price(1);
1330 return 1;
1331 } else {
1332 $this->error = $this->db->lasterror();
1333 return -1;
1334 }
1335 }
1336
1337
1343 public function getNextDate()
1344 {
1345 if (empty($this->date_when)) {
1346 return false;
1347 }
1348 // date_when is read from database in the timezone of the server (jdate), so the delay must be added in this timezone
1349 return dol_time_plus_duree($this->date_when, $this->frequency, $this->unit_frequency, 1, 'tzserver');
1350 }
1351
1357 public function isMaxNbGenReached()
1358 {
1359 $ret = false;
1360 if ($this->nb_gen_max > 0 && ($this->nb_gen_done >= $this->nb_gen_max)) {
1361 $ret = true;
1362 }
1363 return $ret;
1364 }
1365
1372 public function strikeIfMaxNbGenReached($ret)
1373 {
1374 return $this->isMaxNbGenReached() ? '<strike>'.$ret.'</strike>' : $ret;
1375 }
1376
1388 public function createRecurringInvoices($restrictioninvoiceid = 0, $forcevalidation = 0, $notrigger = 0)
1389 {
1390 global $conf, $langs, $user, $hookmanager, $action;
1391
1392 $error = 0;
1393 $nb_create = 0;
1394
1395 // Load translation files required by the page
1396 $langs->loadLangs(array("main", "bills"));
1397
1398 $now = dol_now();
1399 $tmparray = dol_getdate($now);
1400 $today = dol_mktime(23, 59, 59, $tmparray['mon'], $tmparray['mday'], $tmparray['year']); // Today is last second of current day
1401
1402 $this->output = '';
1403
1404 dol_syslog("createRecurringInvoices restrictioninvoiceid=".$restrictioninvoiceid." forcevalidation=".$forcevalidation);
1405
1406 $sql = 'SELECT rowid FROM '.MAIN_DB_PREFIX.'facture_rec';
1407 $sql .= ' WHERE frequency > 0'; // A recurring invoice is an invoice with a frequency
1408 $sql .= " AND (date_when IS NULL OR date_when <= '".$this->db->idate($today)."')";
1409 $sql .= ' AND (nb_gen_done < nb_gen_max OR nb_gen_max = 0)';
1410 $sql .= ' AND suspended = 0';
1411 $sql .= ' AND entity = '.$conf->entity; // MUST STAY = $conf->entity here
1412 if ($restrictioninvoiceid > 0) {
1413 $sql .= ' AND rowid = '.((int) $restrictioninvoiceid);
1414 }
1415 $sql .= $this->db->order('entity', 'ASC');
1416 //print $sql;exit;
1417 $parameters = array(
1418 'restrictioninvoiceid' => $restrictioninvoiceid,
1419 'forcevalidation' => $forcevalidation,
1420 );
1421 $reshook = $hookmanager->executeHooks('beforeCreationOfRecurringInvoices', $parameters, $sql); // note that $sql might be modified by hooks
1422
1423 $resql = $this->db->query($sql);
1424 if ($resql) {
1425 $i = 0;
1426 $num = $this->db->num_rows($resql);
1427
1428 if ($num) {
1429 $this->output .= $langs->trans("FoundXQualifiedRecurringInvoiceTemplate", $num)."\n";
1430 } else {
1431 $this->output .= $langs->trans("NoQualifiedRecurringInvoiceTemplateFound");
1432 }
1433
1434 $saventity = $conf->entity;
1435
1436 while ($i < $num) { // Loop on each template invoice. If $num = 0, test is false at first pass.
1437 $line = $this->db->fetch_object($resql);
1438
1439 $this->db->begin();
1440
1441 $errorforinvoice = 0;
1442 $invoiceidgenerated = 0;
1443
1444 $facture = null;
1445 $facturerec = new FactureRec($this->db);
1446 $facturerec->fetch($line->rowid);
1447
1448 if ($facturerec->id > 0) {
1449 // Set entity context
1450 $conf->entity = $facturerec->entity;
1451
1452 dol_syslog("createRecurringInvoices Process invoice template id=".$facturerec->id.", ref=".$facturerec->ref.", entity=".$facturerec->entity);
1453
1454 $facture = new Facture($this->db);
1455 $facture->fac_rec = $facturerec->id; // We will create $facture from this recurring invoice
1456 $facture->fk_fac_rec_source = $facturerec->id; // We will create $facture from this recurring invoice
1457
1458 $facture->type = self::TYPE_STANDARD;
1459 $facture->subtype = $facturerec->subtype;
1460 $facture->statut = self::STATUS_DRAFT; // deprecated
1461 $facture->status = self::STATUS_DRAFT;
1462 $facture->date = (empty($facturerec->date_when) ? $now : $facturerec->date_when); // We could also use dol_now here but we prefer date_when so invoice has real date when we would like even if we generate later.
1463 $facture->socid = $facturerec->socid;
1464
1465 if (!empty($facturerec->fk_multicurrency)) {
1466 $facture->fk_multicurrency = $facturerec->fk_multicurrency;
1467 $facture->multicurrency_code = $facturerec->multicurrency_code;
1468 $facture->multicurrency_tx = $facturerec->multicurrency_tx;
1469 }
1470
1471 if (isset($facture->array_options) && isset($facturerec->array_options)) {
1472 foreach ($facturerec->array_options as $key => $value) {
1473 if (isset($facture->array_options[$key])) {
1474 $facture->array_options[$key] = $value;
1475 }
1476 }
1477 }
1478
1479 $parameters['facture'] = &$facture;
1480 $reshook = $hookmanager->executeHooks('beforeCreationOfEachRecurringInvoice', $parameters, $facturerec, $action); // note that $facturerec or $facture might be modified by hooks
1481
1482 // Create invoice. This may update prices according to multiplrice rules
1483 $invoiceidgenerated = $facture->create($user, 0, 0, (isModEnabled('multicurrency') ? $facturerec->usenewcurrencyrate : 0));
1484 if ($invoiceidgenerated <= 0) {
1485 $this->setErrorsFromObject($facture);
1486 $error++;
1487 $errorforinvoice++;
1488 }
1489
1490
1491 if (!$errorforinvoice && ($facturerec->auto_validate || $forcevalidation)) {
1492 $result = $facture->validate($user);
1493 if ($result <= 0) {
1494 $this->setErrorsFromObject($facture);
1495 $error++;
1496 $errorforinvoice++;
1497 }
1498 }
1499 if (!$errorforinvoice && $facturerec->generate_pdf) {
1500 // We refresh the object in order to have all necessary data (like date_lim_reglement)
1501 $facture->fetch($facture->id);
1502 $result = $facture->generateDocument($facturerec->model_pdf, $langs);
1503 if ($result <= 0) {
1504 $this->setErrorsFromObject($facture);
1505 $error++;
1506 $errorforinvoice++;
1507 }
1508 }
1509 } else {
1510 $error++;
1511 $this->error = "Failed to load invoice template with id=".$line->rowid.", entity=".$conf->entity."\n";
1512 $this->errors[] = "Failed to load invoice template with id=".$line->rowid.", entity=".$conf->entity;
1513 dol_syslog("createRecurringInvoices Failed to load invoice template with id=".$line->rowid.", entity=".$conf->entity);
1514 }
1515
1516 // Commit or rollback
1517 if (!$error && $invoiceidgenerated >= 0) {
1518 $this->db->commit("createRecurringInvoices Process invoice template id=".$facturerec->id.", ref=".$facturerec->ref);
1519 dol_syslog("createRecurringInvoices Process invoice template ".$facturerec->ref." is finished with a success generation");
1520 $nb_create++;
1521 $this->output .= $langs->trans("InvoiceGeneratedFromTemplate", $facture->ref, $facturerec->ref)."\n";
1522 } else {
1523 $this->output .= $langs->trans("InvoiceGeneratedFromTemplateError", $facture->ref, $facturerec->ref, $this->error)."\n";
1524 $this->db->rollback("createRecurringInvoices Process invoice template id=".$facturerec->id.", ref=".$facturerec->ref);
1525 }
1526
1527 $parameters = array(
1528 'cpt' => $i,
1529 'total' => $num,
1530 'errorCount' => $error,
1531 'errorForInvoice' => $errorforinvoice,
1532 'invoiceidgenerated' => $invoiceidgenerated,
1533 'facturerec' => $facturerec, // it's an object which PHP passes by "reference", so modifiable by hooks.
1534 'this' => $this, // it's an object which PHP passes by "reference", so modifiable by hooks.
1535 );
1536 // @phan-suppress-next-line PhanTypeMismatchArgumentNullable
1537 $reshook = $hookmanager->executeHooks('afterCreationOfRecurringInvoice', $parameters, $facture); // note: $facture can be modified by hooks (warning: $facture can be null)
1538
1539 $i++;
1540 }
1541
1542 $conf->entity = $saventity; // Restore entity context
1543 } else {
1544 dol_print_error($this->db);
1545 }
1546
1547 $this->output = trim($this->output);
1548
1549 return $error ? $error : 0;
1550 }
1551
1564 public function getNomUrl($withpicto = 0, $option = '', $max = 0, $short = 0, $moretitle = '', $notooltip = 0, $save_lastsearch_value = -1)
1565 {
1566 global $langs, $hookmanager;
1567
1568 $result = '';
1569
1570 $label = img_picto('', $this->picto).' <u class="paddingrightonly">'.$langs->trans("RepeatableInvoice").'</u>';
1571 if (!empty($this->ref)) {
1572 $label .= '<br><b>'.$langs->trans('Ref').':</b> '.$this->ref;
1573 }
1574 if ($this->frequency > 0) {
1575 $label .= '<br><b>'.$langs->trans('Frequency').':</b> '.$langs->trans('FrequencyPer_'.$this->unit_frequency, $this->frequency);
1576 }
1577 if (!empty($this->date_last_gen)) {
1578 $label .= '<br><b>'.$langs->trans('DateLastGeneration').':</b> '.dol_print_date($this->date_last_gen, 'dayhour');
1579 }
1580 if ($this->frequency > 0) {
1581 if (!empty($this->date_when)) {
1582 $label .= '<br><b>'.$langs->trans('NextDateToExecution').':</b> ';
1583 $label .= (empty($this->suspended) ? '' : '<strike>').dol_print_date($this->date_when, 'day').(empty($this->suspended) ? '' : '</strike>'); // No hour for this property
1584 if (!empty($this->suspended)) {
1585 $label .= ' ('.$langs->trans("Disabled").')';
1586 }
1587 }
1588 }
1589
1590 $url = DOL_URL_ROOT.'/compta/facture/card-rec.php?id='.$this->id;
1591
1592 if ($short) {
1593 return $url;
1594 }
1595
1596 if ($option != 'nolink') {
1597 // Add param to save lastsearch_values or not
1598 $add_save_lastsearch_values = ($save_lastsearch_value == 1 ? 1 : 0);
1599 if ($save_lastsearch_value == -1 && isset($_SERVER["PHP_SELF"]) && preg_match('/list\.php/', $_SERVER["PHP_SELF"])) {
1600 $add_save_lastsearch_values = 1;
1601 }
1602 if ($add_save_lastsearch_values) {
1603 $url .= '&save_lastsearch_values=1';
1604 }
1605 }
1606
1607 $linkstart = '<a href="'.$url.'" title="'.dol_escape_htmltag($label, 1).'" class="classfortooltip">';
1608 $linkend = '</a>';
1609
1610 $result .= $linkstart;
1611 if ($withpicto) {
1612 $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);
1613 }
1614 if ($withpicto != 2) {
1615 $result .= dol_trunc($this->ref, $max);
1616 }
1617 $result .= $linkend;
1618 global $action;
1619 $hookmanager->initHooks(array($this->element . 'dao'));
1620 $parameters = array('id' => $this->id, 'getnomurl' => &$result);
1621 $reshook = $hookmanager->executeHooks('getNomUrl', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks
1622 if ($reshook > 0) {
1623 $result = $hookmanager->resPrint;
1624 } else {
1625 $result .= $hookmanager->resPrint;
1626 }
1627 return $result;
1628 }
1629
1637 public function getLibStatut($mode = 0, $alreadypaid = -1)
1638 {
1639 return $this->LibStatut($this->frequency ? 1 : 0, $this->suspended, $mode, $alreadypaid, empty($this->type) ? 0 : $this->type);
1640 }
1641
1642 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1654 public function LibStatut($recur, $status, $mode = 0, $alreadypaid = -1, $type = 0, $nbofopendirectdebitorcredittransfer = 0)
1655 {
1656 // phpcs:enable
1657 global $langs;
1658 $langs->load('bills');
1659
1660 $labelStatus = $langs->transnoentitiesnoconv('Active');
1661 $statusType = 'status0';
1662
1663 //print "$recur,$status,$mode,$alreadypaid,$type";
1664 if ($mode == 0) {
1665 if ($recur) {
1666 if ($status == self::STATUS_SUSPENDED) {
1667 $labelStatus = $langs->transnoentitiesnoconv('Disabled');
1668 } else {
1669 $labelStatus = $langs->transnoentitiesnoconv('Active');
1670 }
1671 } else {
1672 if ($status == self::STATUS_SUSPENDED) {
1673 $labelStatus = $langs->transnoentitiesnoconv('Disabled');
1674 } else {
1675 $labelStatus = $langs->transnoentitiesnoconv("Draft");
1676 }
1677 }
1678 } elseif ($mode == 1) {
1679 $prefix = 'Short';
1680 if ($recur) {
1681 if ($status == self::STATUS_SUSPENDED) {
1682 $labelStatus = $langs->transnoentitiesnoconv('Disabled');
1683 } else {
1684 $labelStatus = $langs->transnoentitiesnoconv('Active');
1685 }
1686 } else {
1687 if ($status == self::STATUS_SUSPENDED) {
1688 $labelStatus = $langs->transnoentitiesnoconv('Disabled');
1689 } else {
1690 $labelStatus = $langs->transnoentitiesnoconv("Draft");
1691 }
1692 }
1693 } elseif ($mode == 2) {
1694 if ($recur) {
1695 if ($status == self::STATUS_SUSPENDED) {
1696 $statusType = 'status6';
1697 $labelStatus = $langs->transnoentitiesnoconv('Disabled');
1698 } else {
1699 $statusType = 'status4';
1700 $labelStatus = $langs->transnoentitiesnoconv('Active');
1701 }
1702 } else {
1703 if ($status == self::STATUS_SUSPENDED) {
1704 $statusType = 'status6';
1705 $labelStatus = $langs->transnoentitiesnoconv('Disabled');
1706 } else {
1707 $statusType = 'status0';
1708 $labelStatus = $langs->transnoentitiesnoconv('Draft');
1709 }
1710 }
1711 } elseif ($mode == 3) {
1712 if ($recur) {
1713 $prefix = 'Short';
1714 if ($status == self::STATUS_SUSPENDED) {
1715 $statusType = 'status6';
1716 $labelStatus = $langs->transnoentitiesnoconv('Disabled');
1717 } else {
1718 $statusType = 'status4';
1719 $labelStatus = $langs->transnoentitiesnoconv('Active');
1720 }
1721 } else {
1722 if ($status == self::STATUS_SUSPENDED) {
1723 $statusType = 'status6';
1724 $labelStatus = $langs->transnoentitiesnoconv('Disabled');
1725 } else {
1726 $statusType = 'status0';
1727 $labelStatus = $langs->transnoentitiesnoconv('Draft');
1728 }
1729 }
1730 } elseif ($mode == 4) {
1731 $prefix = '';
1732 if ($recur) {
1733 if ($status == self::STATUS_SUSPENDED) {
1734 $statusType = 'status6';
1735 $labelStatus = $langs->transnoentitiesnoconv('Disabled');
1736 } else {
1737 $statusType = 'status4';
1738 $labelStatus = $langs->transnoentitiesnoconv('Active');
1739 }
1740 } else {
1741 if ($status == self::STATUS_SUSPENDED) {
1742 $statusType = 'status6';
1743 $labelStatus = $langs->transnoentitiesnoconv('Disabled');
1744 } else {
1745 $statusType = 'status0';
1746 $labelStatus = $langs->transnoentitiesnoconv('Draft');
1747 }
1748 }
1749 } elseif ($mode == 5 || $mode == 6) {
1750 $prefix = '';
1751 if ($mode == 5) {
1752 $prefix = 'Short';
1753 }
1754 if ($recur) {
1755 if ($status == self::STATUS_SUSPENDED) {
1756 $statusType = 'status6';
1757 $labelStatus = $langs->transnoentitiesnoconv('Disabled');
1758 } else {
1759 $statusType = 'status4';
1760 $labelStatus = $langs->transnoentitiesnoconv('Active');
1761 }
1762 } else {
1763 if ($status == self::STATUS_SUSPENDED) {
1764 $statusType = 'status6';
1765 $labelStatus = $langs->transnoentitiesnoconv('Disabled');
1766 } else {
1767 $statusType = 'status0';
1768 $labelStatus = $langs->transnoentitiesnoconv('Draft');
1769 }
1770 }
1771 }
1772
1773 $labelStatusShort = $labelStatus;
1774
1775 return dolGetStatus($labelStatus, $labelStatusShort, '', $statusType, $mode);
1776 }
1777
1785 public function getNextNumRef($soc, $mode = 'next')
1786 {
1787 // Not used for recurring invoices
1788 return '';
1789 }
1790
1797 public function info($id)
1798 {
1799 $sql = 'SELECT c.rowid, datec, tms as datem,';
1800 $sql .= ' fk_user_author, fk_user_modif';
1801 $sql .= ' FROM '.MAIN_DB_PREFIX.'facture_rec as c';
1802 $sql .= ' WHERE c.rowid = '.((int) $id);
1803
1804 $result = $this->db->query($sql);
1805 if ($result) {
1806 if ($this->db->num_rows($result)) {
1807 $obj = $this->db->fetch_object($result);
1808
1809 $this->id = $obj->rowid;
1810
1811 $this->user_creation_id = $obj->fk_user_author;
1812 $this->user_modification_id = $obj->fk_user_modif;
1813 $this->date_creation = $this->db->jdate($obj->datec);
1814 $this->date_modification = $this->db->jdate($obj->datem);
1815 }
1816 $this->db->free($result);
1817 } else {
1818 dol_print_error($this->db);
1819 }
1820 }
1821
1830 public function initAsSpecimen($option = '')
1831 {
1832 global $langs;
1833
1834 $now = dol_now();
1835 $arraynow = dol_getdate($now);
1836 $nownotime = dol_mktime(0, 0, 0, $arraynow['mon'], $arraynow['mday'], $arraynow['year']);
1837
1838 // Load array of products prodids
1839 $num_prods = 0;
1840 $prodids = array();
1841
1842 $sql = "SELECT rowid";
1843 $sql .= " FROM ".MAIN_DB_PREFIX."product";
1844 $sql .= " WHERE entity IN (".getEntity('product').")";
1845 $sql .= $this->db->plimit(100);
1846
1847 $resql = $this->db->query($sql);
1848 if ($resql) {
1849 $num_prods = $this->db->num_rows($resql);
1850 $i = 0;
1851 while ($i < $num_prods) {
1852 $i++;
1853 $row = $this->db->fetch_row($resql);
1854 $prodids[$i] = $row[0];
1855 }
1856 }
1857
1858 // Initialize parameters
1859 $this->id = 0;
1860 $this->ref = 'SPECIMEN';
1861 $this->title = 'SPECIMEN';
1862 $this->specimen = 1;
1863 $this->socid = 1;
1864 $this->date = $nownotime;
1865 $this->date_lim_reglement = $nownotime + 3600 * 24 * 30;
1866 $this->cond_reglement_id = 1;
1867 $this->cond_reglement_code = 'RECEP';
1868 $this->date_lim_reglement = $this->calculate_date_lim_reglement();
1869 $this->mode_reglement_id = 0; // Not forced to show payment mode CHQ + VIR
1870 $this->mode_reglement_code = ''; // Not forced to show payment mode CHQ + VIR
1871 $this->note_public = 'This is a comment (public)';
1872 $this->note_private = 'This is a comment (private)';
1873 $this->fk_incoterms = 0;
1874 $this->location_incoterms = '';
1875
1876 if (empty($option) || $option != 'nolines') {
1877 // Lines
1878 $nbp = min(1000, GETPOSTINT('nblines') ? GETPOSTINT('nblines') : 5); // We can force the nb of lines to test from command line (but not more than 1000)
1879 $xnbp = 0;
1880 while ($xnbp < $nbp) {
1881 $line = new FactureLigne($this->db);
1882 $line->desc = $langs->trans("Description")." ".$xnbp;
1883 $line->qty = 1;
1884 $line->subprice = 100;
1885 $line->tva_tx = 19.6;
1886 $line->localtax1_tx = 0;
1887 $line->localtax2_tx = 0;
1888 $line->remise_percent = 0;
1889 if ($xnbp == 1) { // Qty is negative (product line)
1890 $prodid = mt_rand(1, $num_prods);
1891 $line->fk_product = $prodids[$prodid];
1892 $line->qty = -1;
1893 $line->total_ht = -100;
1894 $line->total_ttc = -119.6;
1895 $line->total_tva = -19.6;
1896 } elseif ($xnbp == 2) { // UP is negative (free line)
1897 $line->subprice = -100;
1898 $line->total_ht = -100;
1899 $line->total_ttc = -119.6;
1900 $line->total_tva = -19.6;
1901 $line->remise_percent = 0;
1902 } elseif ($xnbp == 3) { // Discount is 50% (product line)
1903 $prodid = mt_rand(1, $num_prods);
1904 $line->fk_product = $prodids[$prodid];
1905 $line->total_ht = 50;
1906 $line->total_ttc = 59.8;
1907 $line->total_tva = 9.8;
1908 $line->remise_percent = 50;
1909 } else { // (product line)
1910 $prodid = mt_rand(1, $num_prods);
1911 $line->fk_product = $prodids[$prodid];
1912 $line->total_ht = 100;
1913 $line->total_ttc = 119.6;
1914 $line->total_tva = 19.6;
1915 $line->remise_percent = 00;
1916 }
1917
1918 $this->lines[$xnbp] = $line;
1919 $xnbp++;
1920
1921 $this->total_ht += $line->total_ht;
1922 $this->total_tva += $line->total_tva;
1923 $this->total_ttc += $line->total_ttc;
1924 }
1925 $this->revenuestamp = 0;
1926
1927 // Add a line "offered"
1928 $line = new FactureLigne($this->db);
1929 $line->desc = $langs->trans("Description")." (offered line)";
1930 $line->qty = 1;
1931 $line->subprice = 100;
1932 $line->tva_tx = 19.6;
1933 $line->localtax1_tx = 0;
1934 $line->localtax2_tx = 0;
1935 $line->remise_percent = 100;
1936 $line->total_ht = 0;
1937 $line->total_ttc = 0; // 90 * 1.196
1938 $line->total_tva = 0;
1939 $prodid = mt_rand(1, $num_prods);
1940 $line->fk_product = $prodids[$prodid];
1941
1942 $this->lines[$xnbp] = $line;
1943 $xnbp++;
1944 }
1945
1946 $this->usenewprice = 0;
1947
1948 return 1;
1949 }
1950
1959 public static function replaceThirdparty(DoliDB $dbs, $origin_id, $dest_id)
1960 {
1961 $tables = array(
1962 'facture_rec'
1963 );
1964
1965 return CommonObject::commonReplaceThirdparty($dbs, $origin_id, $dest_id, $tables);
1966 }
1967
1976 public static function replaceProduct(DoliDB $dbs, $origin_id, $dest_id)
1977 {
1978 $tables = array(
1979 'facturedet_rec'
1980 );
1981
1982 return CommonObject::commonReplaceProduct($dbs, $origin_id, $dest_id, $tables);
1983 }
1984
1993 public function setFrequencyAndUnit($frequency, $unit, $notrigger = 0)
1994 {
1995 global $user;
1996
1997 if (!$this->table_element) {
1998 dol_syslog(get_class($this)."::setFrequencyAndUnit was called on object with property table_element not defined", LOG_ERR);
1999 return -1;
2000 }
2001
2002 if (!empty($frequency) && empty($unit)) {
2003 dol_syslog(get_class($this)."::setFrequencyAndUnit was called on object with params frequency defined but unit not defined", LOG_ERR);
2004 return -2;
2005 }
2006
2007 $sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element;
2008 $sql .= ' SET frequency = '.($frequency ? $this->db->escape((string) $frequency) : 'null');
2009 if (!empty($unit)) {
2010 $sql .= ', unit_frequency = \''.$this->db->escape($unit).'\'';
2011 }
2012 $sql .= " WHERE rowid = ".((int) $this->id);
2013
2014 dol_syslog(get_class($this)."::setFrequencyAndUnit", LOG_DEBUG);
2015 if ($this->db->query($sql)) {
2016 $this->frequency = $frequency;
2017 if (!empty($unit)) {
2018 $this->unit_frequency = $unit;
2019 }
2020
2021 if (!$notrigger) {
2022 // Call trigger
2023 $result = $this->call_trigger('BILLREC_MODIFY', $user);
2024 if ($result < 0) {
2025 return $result;
2026 }
2027 // End call triggers
2028 }
2029
2030 return 1;
2031 } else {
2032 dol_print_error($this->db);
2033 return -1;
2034 }
2035 }
2036
2045 public function setNextDate($date, $increment_nb_gen_done = 0, $notrigger = 0)
2046 {
2047 global $user;
2048
2049 if (!$this->table_element) {
2050 dol_syslog(get_class($this)."::setNextDate was called on object with property table_element not defined", LOG_ERR);
2051 return -1;
2052 }
2053 $sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element;
2054 $sql .= " SET date_when = ".($date ? "'".$this->db->idate($date)."'" : "null");
2055 if ($increment_nb_gen_done > 0) {
2056 $sql .= ', nb_gen_done = nb_gen_done + 1';
2057 }
2058 $sql .= " WHERE rowid = ".((int) $this->id);
2059
2060 dol_syslog(get_class($this)."::setNextDate", LOG_DEBUG);
2061 if ($this->db->query($sql)) {
2062 $this->date_when = $date;
2063 if ($increment_nb_gen_done > 0) {
2064 $this->nb_gen_done++;
2065
2066 if (getDolGlobalInt('MAIN_SUSPEND_FACTURE_REC_ON_MAX_GEN_REACHED') && $this->isMaxNbGenReached()) {
2067 $resSuspend = $this->setValueFrom('suspended', 1);
2068
2069 if ($resSuspend <= 0) {
2070 dol_syslog(__METHOD__ . '::setValueFrom Error : ' . $this->error, LOG_ERR);
2071 return -1;
2072 }
2073 }
2074 }
2075
2076 if (!$notrigger) {
2077 if (empty($this->context['actionmsgmore'])) {
2078 $this->context['actionmsgmore'] = 'Trigger called by setNextDate';
2079 }
2080
2081 // Call trigger
2082 $result = $this->call_trigger('BILLREC_MODIFY', $user);
2083 if ($result < 0) {
2084 return $result;
2085 }
2086 // End call triggers
2087 }
2088 return 1;
2089 } else {
2090 dol_print_error($this->db);
2091 return -1;
2092 }
2093 }
2094
2102 public function setMaxPeriod($nb, $notrigger = 0)
2103 {
2104 global $user;
2105
2106 if (!$this->table_element) {
2107 dol_syslog(get_class($this)."::setMaxPeriod was called on object with property table_element not defined", LOG_ERR);
2108 return -1;
2109 }
2110
2111 if (empty($nb)) {
2112 $nb = 0;
2113 }
2114
2115 $sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element;
2116 $sql .= ' SET nb_gen_max = '.((int) $nb);
2117 $sql .= " WHERE rowid = ".((int) $this->id);
2118
2119 dol_syslog(get_class($this)."::setMaxPeriod", LOG_DEBUG);
2120 if ($this->db->query($sql)) {
2121 $this->nb_gen_max = $nb;
2122
2123 if (!$notrigger) {
2124 // Call trigger
2125 $result = $this->call_trigger('BILLREC_MODIFY', $user);
2126 if ($result < 0) {
2127 return $result;
2128 }
2129 // End call triggers
2130 }
2131
2132 return 1;
2133 } else {
2134 dol_print_error($this->db);
2135 return -1;
2136 }
2137 }
2138
2146 public function setAutoValidate($validate, $notrigger = 0)
2147 {
2148 global $user;
2149
2150 if (!$this->table_element) {
2151 dol_syslog(get_class($this)."::setAutoValidate was called on object with property table_element not defined", LOG_ERR);
2152 return -1;
2153 }
2154
2155 $sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element;
2156 $sql .= ' SET auto_validate = '.((int) $validate);
2157 $sql .= " WHERE rowid = ".((int) $this->id);
2158
2159 dol_syslog(get_class($this)."::setAutoValidate", LOG_DEBUG);
2160 if ($this->db->query($sql)) {
2161 $this->auto_validate = $validate;
2162
2163 if (!$notrigger) {
2164 // Call trigger
2165 $result = $this->call_trigger('BILLREC_MODIFY', $user);
2166 if ($result < 0) {
2167 return $result;
2168 }
2169 // End call triggers
2170 }
2171
2172 return 1;
2173 } else {
2174 dol_print_error($this->db);
2175 return -1;
2176 }
2177 }
2178
2186 public function setGeneratePdf($validate, $notrigger = 0)
2187 {
2188 global $user;
2189
2190 if (!$this->table_element) {
2191 dol_syslog(get_class($this)."::setGeneratePdf was called on object with property table_element not defined", LOG_ERR);
2192 return -1;
2193 }
2194
2195 $sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element;
2196 $sql .= ' SET generate_pdf = '.((int) $validate);
2197 $sql .= " WHERE rowid = ".((int) $this->id);
2198
2199 dol_syslog(get_class($this)."::setGeneratePdf", LOG_DEBUG);
2200 if ($this->db->query($sql)) {
2201 $this->generate_pdf = $validate;
2202
2203 if (!$notrigger) {
2204 // Call trigger
2205 $result = $this->call_trigger('BILLREC_MODIFY', $user);
2206 if ($result < 0) {
2207 return $result;
2208 }
2209 // End call triggers
2210 }
2211
2212 return 1;
2213 } else {
2214 dol_print_error($this->db);
2215 return -1;
2216 }
2217 }
2218
2226 public function setModelPdf($model, $notrigger = 0)
2227 {
2228 global $user;
2229 if (!$this->table_element) {
2230 dol_syslog(get_class($this)."::setModelPdf was called on object with property table_element not defined", LOG_ERR);
2231 return -1;
2232 }
2233
2234 $sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element;
2235 $sql .= " SET modelpdf = '".$this->db->escape($model)."'";
2236 $sql .= " WHERE rowid = ".((int) $this->id);
2237
2238 dol_syslog(get_class($this)."::setModelPdf", LOG_DEBUG);
2239 if ($this->db->query($sql)) {
2240 $this->model_pdf = $model;
2241
2242 if (!$notrigger) {
2243 // Call trigger
2244 $result = $this->call_trigger('BILLREC_MODIFY', $user);
2245 if ($result < 0) {
2246 return $result;
2247 }
2248 // End call triggers
2249 }
2250
2251 return 1;
2252 } else {
2253 dol_print_error($this->db);
2254 return -1;
2255 }
2256 }
2257}
2258
2259
2260
2266{
2270 public $element = 'facturedetrec';
2271
2275 public $table_element = 'facturedet_rec';
2276
2280 public $parent_element = 'facturerec';
2281
2285 public $fk_parent_attribute = 'fk_facture';
2286
2288
2291 public $fk_facture;
2295 public $fk_parent_line;
2296
2300 public $fk_product_fournisseur_price;
2305 public $fk_fournprice;
2306
2310 public $rang;
2311 //public $situation_percent; // Not supported on recurring invoice line
2312
2316 public $desc;
2320 public $description;
2321
2326 public $fk_product_type;
2327
2331 public $fk_contract_line;
2332
2333
2341 public function delete(User $user, $notrigger = 0)
2342 {
2343 $error = 0;
2344
2345 $this->db->begin();
2346
2347 if (!$error) {
2348 if (!$notrigger) {
2349 // Call triggers
2350 $result = $this->call_trigger('LINEBILLREC_DELETE', $user);
2351 if ($result < 0) {
2352 $error++;
2353 } // Do also here what you must do to rollback action if trigger fail
2354 // End call triggers
2355 }
2356 }
2357
2358 if (!$error) {
2359 $result = $this->deleteExtraFields();
2360 if ($result < 0) {
2361 $error++;
2362 }
2363 }
2364
2365 if (!$error) {
2366 $sql = 'DELETE FROM '.MAIN_DB_PREFIX.$this->table_element.' WHERE rowid='.((int) $this->id);
2367
2368 $res = $this->db->query($sql);
2369 if (!$res) {
2370 $error++;
2371 $this->errors[] = $this->db->lasterror();
2372 }
2373 }
2374
2375 // Commit or rollback
2376 if ($error) {
2377 $this->db->rollback();
2378 return -1;
2379 } else {
2380 $this->db->commit();
2381 return 1;
2382 }
2383 }
2384
2385
2392 public function fetch($rowid)
2393 {
2394 $sql = 'SELECT l.rowid, l.fk_facture, l.fk_parent_line, l.fk_product, l.product_type, l.label as custom_label, l.description, l.product_type, l.price, l.qty, l.vat_src_code, l.tva_tx,';
2395 $sql .= ' l.localtax1_tx, l.localtax2_tx, l.localtax1_type, l.localtax2_type, l.remise, l.remise_percent, l.subprice,';
2396 $sql .= ' l.date_start_fill, l.date_end_fill, l.info_bits, l.total_ht, l.total_tva, l.total_ttc,';
2397 $sql .= ' l.rang, l.special_code,';
2398 $sql .= ' l.fk_unit, l.fk_contract_line,';
2399 $sql .= ' l.import_key, l.fk_multicurrency,';
2400 $sql .= ' l.multicurrency_code, l.multicurrency_subprice, l.multicurrency_total_ht, l.multicurrency_total_tva, l.multicurrency_total_ttc,';
2401 $sql .= ' l.buy_price_ht, l.fk_product_fournisseur_price,';
2402 $sql .= ' l.fk_user_author, l.fk_user_modif, l.extraparams,';
2403 $sql .= ' p.ref as product_ref, p.fk_product_type as fk_product_type, p.label as product_label, p.description as product_desc';
2404 $sql .= ' FROM '.MAIN_DB_PREFIX.'facturedet_rec as l';
2405 $sql .= ' LEFT JOIN '.MAIN_DB_PREFIX.'product as p ON l.fk_product = p.rowid';
2406 $sql .= ' WHERE l.rowid = '.((int) $rowid);
2407 $sql .= ' ORDER BY l.rang';
2408
2409 dol_syslog('FactureRec::fetch', LOG_DEBUG);
2410 $result = $this->db->query($sql);
2411 if ($result) {
2412 $objp = $this->db->fetch_object($result);
2413
2414 $this->id = $objp->rowid;
2415 $this->fk_facture = $objp->fk_facture;
2416 $this->fk_parent_line = $objp->fk_parent_line;
2417 $this->label = $objp->custom_label; // Label line
2418 $this->desc = $objp->description; // Description line
2419 $this->description = $objp->description; // Description line
2420 $this->product_type = $objp->product_type; // Type of line
2421 $this->ref = $objp->product_ref; // Ref product
2422 $this->product_ref = $objp->product_ref; // Ref product
2423 $this->libelle = $objp->product_label; // deprecated
2424 $this->product_label = $objp->product_label; // Label product
2425 $this->product_desc = $objp->product_desc; // Description product
2426 $this->fk_product_type = $objp->fk_product_type; // Type of product
2427 $this->qty = $objp->qty;
2428 $this->price = $objp->price;
2429 $this->subprice = $objp->subprice;
2430 $this->vat_src_code = $objp->vat_src_code;
2431 $this->tva_tx = $objp->tva_tx;
2432 $this->localtax1_tx = $objp->localtax1_tx;
2433 $this->localtax2_tx = $objp->localtax2_tx;
2434 $this->localtax1_type = $objp->localtax1_type;
2435 $this->localtax2_type = $objp->localtax2_type;
2436 $this->remise_percent = $objp->remise_percent;
2437 //$this->fk_remise_except = $objp->fk_remise_except;
2438 $this->fk_product = $objp->fk_product;
2439 $this->date_start_fill = $objp->date_start_fill;
2440 $this->date_end_fill = $objp->date_end_fill;
2441 $this->info_bits = $objp->info_bits;
2442 $this->total_ht = $objp->total_ht;
2443 $this->total_tva = $objp->total_tva;
2444 $this->total_ttc = $objp->total_ttc;
2445
2446 $this->rang = $objp->rang;
2447 $this->special_code = $objp->special_code;
2448 $this->fk_unit = $objp->fk_unit;
2449 $this->fk_contract_line = $objp->fk_contract_line;
2450 $this->import_key = $objp->import_key;
2451 $this->fk_multicurrency = $objp->fk_multicurrency;
2452 $this->multicurrency_code = $objp->multicurrency_code;
2453 $this->multicurrency_subprice = $objp->multicurrency_subprice;
2454 $this->multicurrency_total_ht = $objp->multicurrency_total_ht;
2455 $this->multicurrency_total_tva = $objp->multicurrency_total_tva;
2456 $this->multicurrency_total_ttc = $objp->multicurrency_total_ttc;
2457
2458 $this->buy_price_ht = $objp->buy_price_ht;
2459
2460 $this->fk_product_fournisseur_price = $objp->fk_product_fournisseur_price;
2461 $this->fk_user_author = $objp->fk_user_author;
2462 $this->fk_user_modif = $objp->fk_user_modif;
2463
2464 $this->db->free($result);
2465 return 1;
2466 } else {
2467 $this->error = $this->db->lasterror();
2468 return -3;
2469 }
2470 }
2471
2472
2480 public function update(User $user, $notrigger = 0)
2481 {
2482 global $conf;
2483
2484 $error = 0;
2485
2486 // Clean parameters
2487 if (empty($this->fk_parent_line)) {
2488 $this->fk_parent_line = 0;
2489 }
2490
2491 include_once DOL_DOCUMENT_ROOT.'/core/lib/price.lib.php';
2492
2493 $sql = "UPDATE ".MAIN_DB_PREFIX."facturedet_rec SET";
2494 $sql .= " fk_facture = ".((int) $this->fk_facture);
2495 $sql .= ", fk_parent_line=".($this->fk_parent_line > 0 ? $this->fk_parent_line : "null");
2496 $sql .= ", label=".(!empty($this->label) ? "'".$this->db->escape($this->label)."'" : "null");
2497 $sql .= ", description='".$this->db->escape($this->desc)."'";
2498 $sql .= ", price=".price2num($this->price);
2499 $sql .= ", qty=".price2num($this->qty);
2500 $sql .= ", tva_tx=".price2num($this->tva_tx);
2501 $sql .= ", vat_src_code='".$this->db->escape($this->vat_src_code)."'";
2502 $sql .= ", localtax1_tx=".price2num($this->localtax1_tx);
2503 $sql .= ", localtax1_type='".$this->db->escape((string) $this->localtax1_type)."'";
2504 $sql .= ", localtax2_tx=".price2num($this->localtax2_tx);
2505 $sql .= ", localtax2_type='".$this->db->escape((string) $this->localtax2_type)."'";
2506 $sql .= ", fk_product=".($this->fk_product > 0 ? $this->fk_product : "null");
2507 $sql .= ", product_type=".((int) $this->product_type);
2508 $sql .= ", remise_percent=".price2num($this->remise_percent);
2509 $sql .= ", subprice=".price2num($this->subprice);
2510 $sql .= ", info_bits=".price2num($this->info_bits);
2511 $sql .= ", date_start_fill=".(int) $this->date_start_fill;
2512 $sql .= ", date_end_fill=".(int) $this->date_end_fill;
2513 if (empty($this->skip_update_total)) {
2514 $sql .= ", total_ht=".price2num($this->total_ht);
2515 $sql .= ", total_tva=".price2num($this->total_tva);
2516 $sql .= ", total_localtax1=".price2num($this->total_localtax1);
2517 $sql .= ", total_localtax2=".price2num($this->total_localtax2);
2518 $sql .= ", total_ttc=".price2num($this->total_ttc);
2519 }
2520 $sql .= ", rang=".((int) $this->rang);
2521 $sql .= ", special_code=".((int) $this->special_code);
2522 $sql .= ", fk_unit=".($this->fk_unit ? "'".$this->db->escape((string) $this->fk_unit)."'" : "null");
2523 $sql .= ", fk_contract_line=".($this->fk_contract_line ? $this->fk_contract_line : "null");
2524 $sql .= " WHERE rowid = ".((int) $this->id);
2525
2526 $this->db->begin();
2527
2528 dol_syslog(get_class($this)."::updateline", LOG_DEBUG);
2529
2530 $resql = $this->db->query($sql);
2531 if ($resql) {
2532 if (!$error) {
2533 $result = $this->insertExtraFields();
2534 if ($result < 0) {
2535 $error++;
2536 }
2537 }
2538
2539 if (!$error && !$notrigger) {
2540 // Call trigger
2541 $result = $this->call_trigger('LINEBILLREC_MODIFY', $user);
2542 if ($result < 0) {
2543 $error++;
2544 }
2545 // End call triggers
2546 }
2547
2548 if ($error) {
2549 $this->db->rollback();
2550 return -2;
2551 } else {
2552 $this->db->commit();
2553 return 1;
2554 }
2555 } else {
2556 $this->error = $this->db->lasterror();
2557 $this->db->rollback();
2558 return -2;
2559 }
2560 }
2561}
$object ref
Definition info.php:90
Superclass for invoice classes.
const TYPE_STANDARD
Standard invoice.
calculate_date_lim_reglement($cond_reglement=0)
Returns an invoice payment deadline based on the invoice settlement conditions and billing date.
const STATUS_DRAFT
Draft status.
Parent class of all other business classes for details of elements (invoices, contracts,...
fetch_optionals($rowid=null, $optionsArray=null)
Function to get extra fields of an object into $this->array_options This method is in most cases call...
update_price($exclspec=0, $roundingadjust='auto', $nodatabaseupdate=0, $seller=null)
Update total_ht, total_ttc, total_vat, total_localtax1, total_localtax2 for an object (sum of lines).
add_object_linked($origin=null, $origin_id=null, $f_user=null, $notrigger=0)
Add an object link into llx_element_element.
deleteObjectLinked($sourceid=null, $sourcetype='', $targetid=null, $targettype='', $rowid=0, $f_user=null, $notrigger=0)
Delete all links between an object $this.
setErrorsFromObject($object)
setErrorsFromObject
isLineOfObject($lineid)
Check that a line belongs to this object, using $this->table_element_line and $this->fk_element.
deleteExtraFields()
Delete all extra fields values for the current object.
static commonReplaceThirdparty(DoliDB $dbs, $origin_id, $dest_id, array $tables, $ignoreerrors=0)
Function used to replace a thirdparty id with another one.
setValueFrom($field, $value, $table='', $id=null, $format='', $id_field='', $fuser=null, $trigkey='', $fk_user_field='fk_user_modif')
Setter generic.
static commonReplaceProduct(DoliDB $dbs, $origin_id, $dest_id, array $tables, $ignoreerrors=0)
Function used to replace a product id with another one.
line_max($fk_parent_line=0)
Get max value used for position of line (rang)
insertExtraFields($trigger='', $userused=null)
Add/Update all extra fields values for the current object.
Class to manage Dolibarr database access.
Class to manage invoices.
Class to manage invoice lines.
Class to manage invoice lines of templates.
fetch($rowid)
Get line of template invoice.
update(User $user, $notrigger=0)
Update a line to invoice_rec.
Class to manage invoice templates.
setFrequencyAndUnit($frequency, $unit, $notrigger=0)
Update frequency and unit.
getLibStatut($mode=0, $alreadypaid=-1)
Return label of object status.
addline($desc, $pu_ht, $qty, $txtva, $txlocaltax1=0, $txlocaltax2=0, $fk_product=0, $remise_percent=0, $price_base_type='HT', $info_bits=0, $fk_remise_except=0, $pu_ttc=0, $type=0, $rang=-1, $special_code=0, $label='', $fk_unit=null, $pu_ht_devise=0, $date_start_fill=0, $date_end_fill=0, $fk_fournprice=null, $pa_ht=0, $fk_parent_line=0)
Add a line to invoice.
updateline($rowid, $desc, $pu_ht, $qty, $txtva, $txlocaltax1=0, $txlocaltax2=0, $fk_product=0, $remise_percent=0, $price_base_type='HT', $info_bits=0, $fk_remise_except=0, $pu_ttc=0, $type=0, $rang=-1, $special_code=0, $label='', $fk_unit=null, $pu_ht_devise=0, $notrigger=0, $date_start_fill=0, $date_end_fill=0, $fk_fournprice=null, $pa_ht=0, $fk_parent_line=0)
Update a line to invoice.
LibStatut($recur, $status, $mode=0, $alreadypaid=-1, $type=0, $nbofopendirectdebitorcredittransfer=0)
Return label of a status.
fetch_lines()
Get lines of template invoices into this->lines.
info($id)
Load miscellaneous information for tab "Info".
getLinesArray()
Create an array of invoice lines.
static replaceThirdparty(DoliDB $dbs, $origin_id, $dest_id)
Function used to replace a thirdparty id with another one.
getNomUrl($withpicto=0, $option='', $max=0, $short=0, $moretitle='', $notooltip=0, $save_lastsearch_value=-1)
Return clickable name (with picto eventually)
isMaxNbGenReached()
Return if maximum number of generation is reached.
setModelPdf($model, $notrigger=0)
Update the model for documents.
getNextNumRef($soc, $mode='next')
Return next reference of invoice not already used (or last reference)
__construct(DoliDB $db)
Constructor.
setNextDate($date, $increment_nb_gen_done=0, $notrigger=0)
Update the next date of execution.
setAutoValidate($validate, $notrigger=0)
Update the auto validate flag of invoice.
initAsSpecimen($option='')
Initialise an instance with random values.
setMaxPeriod($nb, $notrigger=0)
Update the maximum period.
update(User $user, $notrigger=0)
Update a line invoice_rec.
create($user, $facid, $notrigger=0, $onlylines=array())
Create a predefined invoice.
strikeIfMaxNbGenReached($ret)
Format string to output with by striking the string if max number of generations was reached.
fetch($rowid, $ref='', $ref_ext='', $noextrafields=0, $nolines=0)
Load object and lines.
setGeneratePdf($validate, $notrigger=0)
Update the auto generate documents.
static replaceProduct(DoliDB $dbs, $origin_id, $dest_id)
Function used to replace a product id with another one.
getNextDate()
Return the next date of.
createRecurringInvoices($restrictioninvoiceid=0, $forcevalidation=0, $notrigger=0)
Create all recurrents invoices (for all entities if multicompany is used).
Class to manage products or services.
Class to manage Dolibarr users.
global $mysoc
dol_time_plus_duree($time, $duration_value, $duration_unit, $ruleforendofmonth=0, $tz='')
Add a delay to a date.
Definition date.lib.php:128
print $script_file $mode $langs defaultlang(is_numeric($duration_value) ? " delay=". $duration_value :"").(is_numeric($duration_value2) ? " after cd cd cd description as description
Only used if Module[ID]Desc translation string is not found.
dol_now($mode='gmt')
Return date for now.
dol_mktime($hour, $minute, $second, $month, $day, $year, $gm='auto', $check=1)
Return a timestamp date built from detailed information (by default a local PHP server timestamp) Rep...
img_picto($titlealt, $picto, $moreatt='', $pictoisfullpath=0, $srconly=0, $notitle=0, $alt='', $morecss='', $marginleftonlyshort=2, $allowothertags=array())
Show picto whatever it's its name (generic function)
GETPOSTINT($paramname, $method=0)
Return the value of a $_GET or $_POST supervariable, converted into integer.
price2num($amount, $rounding='', $option=0)
Function that return a number with universal decimal format (decimal separator is '.
img_object($titlealt, $picto, $moreatt='', $pictoisfullpath=0, $srconly=0, $notitle=0, $allowothertags=array())
Show a picto called object_picto (generic function)
price($amount, $form=0, $outlangs='', $trunc=1, $rounding=-1, $forcerounding=-1, $currency_code='')
Function to format a value into an amount for visual output Function used into PDF and HTML pages.
getDolGlobalInt($key, $default=0)
Return a Dolibarr global constant int value.
getLocalTaxesFromRate($vatrate, $local, $buyer, $seller, $firstparamisid=0)
Get type and rate of localtaxes for a particular vat rate/country of a thirdparty.
dolGetStatus($statusLabel='', $statusLabelShort='', $html='', $statusType='status0', $displayMode=0, $url='', $params=array())
Output the badge of a status.
dol_print_date($time, $format='', $tzoutput='auto', $outputlangs=null, $encodetooutput=false, $decorate=0)
Output date in a string format according to outputlangs (or langs if not defined).
dol_print_error($db=null, $error='', $errors=null)
Displays error message system with all the information to facilitate the diagnosis and the escalation...
dol_trunc($string, $size=40, $trunc='right', $stringencoding='UTF-8', $nodot=0, $display=0)
Truncate a string to a particular length adding '…' if string larger than length.
isModEnabled($module)
Is Dolibarr module enabled.
dol_syslog($message, $level=LOG_INFO, $ident=0, $suffixinfilename='', $restricttologhandler='', $logcontext=null)
Write log message into outputs.
dol_getdate($timestamp, $fast=false, $forcetimezone='')
Return an array with locale date info.
dol_escape_htmltag($stringtoescape, $keepb=0, $keepn=0, $noescapetags='', $escapeonlyhtmltags=0, $cleanalsojavascript=0)
Returns text escaped for inclusion in HTML alt or title or value tags, or into values of HTML input f...
getMarginInfos($pv_ht, $remise_percent, $tva_tx, $localtax1_tx, $localtax2_tx, $fk_pa, $pa_ht)
Return an array with margins information of a line.
calcul_price_total($qty, $pu, $remise_percent_ligne, $txtva, $uselocaltax1_rate, $uselocaltax2_rate, $remise_percent_global, $price_base_type, $info_bits, $type, $seller=null, $localtaxes_array=[], $progress=100, $multicurrency_tx=1, $pu_devise=0, $multicurrency_code='')
Calculate totals (net, vat, ...) of a line.
Definition price.lib.php:90
if(getDolGlobalString( 'TAKEPOS_SHOW_CUSTOMER')) print $langs trans('Date')." left Label right Qty right Price right TotalHT right TotalTTC right right right right right right right right right centpercent right TotalHT right n right VAT right n right TotalVAT right n No sujeto a RE IRPF right TotalLT1 right n right TotalLT2 right n right TotalTTC right n takeposcustomercurrency takeposcustomercurrency takeposcustomercurrency takeposcustomercurrency right TotalTTC takeposcustomercurrency right takeposcustomercurrency n right PaymentTypeShortLIQ right SELECT p pos_change as p datep as date
Definition receipt.php:469
if(preg_match('/(crypted|dolcrypt):/i', $dolibarr_main_db_pass)||!empty($dolibarr_main_db_encrypted_pass)) $conf db type
'integer', 'integer:ObjectClass:PathToClass[:AddCreateButtonOrNot[:Filter[:Sortfield]]]',...
Definition repair.php:132