dolibarr 23.0.3
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 $facid = $this->id;
1189
1190 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);
1191 include_once DOL_DOCUMENT_ROOT.'/core/lib/price.lib.php';
1192
1193 // Clean parameters
1194 if (empty($remise_percent)) {
1195 $remise_percent = 0;
1196 }
1197
1198 // Check parameters
1199 if ($type < 0) {
1200 return -1;
1201 }
1202
1203 // Clean parameters
1204 $remise_percent = (float) price2num($remise_percent);
1205 $qty = (float) price2num($qty);
1206 if (empty($info_bits)) {
1207 $info_bits = 0;
1208 }
1209 $pu_ht = (float) price2num($pu_ht);
1210 $pu_ttc = (float) price2num($pu_ttc);
1211 $pu_ht_devise = (float) price2num($pu_ht_devise);
1212 if (!preg_match('/\‍((.*)\‍)/', (string) $txtva)) {
1213 $txtva = price2num($txtva); // $txtva can have format '5.0(XXX)' or '5'
1214 }
1215 $txlocaltax1 = (float) price2num($txlocaltax1);
1216 $txlocaltax2 = (float) price2num($txlocaltax2);
1217 if (empty($txlocaltax1)) {
1218 $txlocaltax1 = 0;
1219 }
1220 if (empty($txlocaltax2)) {
1221 $txlocaltax2 = 0;
1222 }
1223
1224 if (empty($this->multicurrency_subprice)) {
1225 $this->multicurrency_subprice = 0;
1226 }
1227 if (empty($this->multicurrency_total_ht)) {
1228 $this->multicurrency_total_ht = 0;
1229 }
1230 if (empty($this->multicurrency_total_tva)) {
1231 $this->multicurrency_total_tva = 0;
1232 }
1233 if (empty($this->multicurrency_total_ttc)) {
1234 $this->multicurrency_total_ttc = 0;
1235 }
1236
1237 if ($price_base_type == 'HT') {
1238 $pu = $pu_ht;
1239 } else {
1240 $pu = $pu_ttc;
1241 }
1242
1243 // Calculate total with, without tax and tax from qty, pu, remise_percent and txtva
1244 // TRES IMPORTANT: C'est au moment de l'insertion ligne qu'on doit stocker
1245 // la part ht, tva et ttc, et ce au niveau de la ligne qui a son propre taux tva.
1246
1247 $localtaxes_type = getLocalTaxesFromRate($txtva, 0, $this->thirdparty, $mysoc);
1248
1249 // Clean vat code
1250 $vat_src_code = '';
1251 $reg = array();
1252 if (preg_match('/\‍((.*)\‍)/', $txtva, $reg)) {
1253 $vat_src_code = $reg[1];
1254 $txtva = preg_replace('/\s*\‍(.*\‍)/', '', $txtva); // Remove code into vatrate.
1255 }
1256
1257 $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);
1258
1259 $total_ht = $tabprice[0];
1260 $total_tva = $tabprice[1];
1261 $total_ttc = $tabprice[2];
1262 $total_localtax1 = $tabprice[9];
1263 $total_localtax2 = $tabprice[10];
1264 $pu_ht = $tabprice[3];
1265 $pu_tva = $tabprice[4];
1266 $pu_ttc = $tabprice[5];
1267
1268 // MultiCurrency
1269 $multicurrency_total_ht = $tabprice[16];
1270 $multicurrency_total_tva = $tabprice[17];
1271 $multicurrency_total_ttc = $tabprice[18];
1272 $pu_ht_devise = $tabprice[19];
1273
1274 $product_type = $type;
1275 if ($fk_product) {
1276 $product = new Product($this->db);
1277 $result = $product->fetch($fk_product);
1278 $product_type = $product->type;
1279 }
1280
1281 if (empty($fk_parent_line) || $fk_parent_line < 0) {
1282 $fk_parent_line = 0;
1283 }
1284
1285 $sql = "UPDATE ".MAIN_DB_PREFIX."facturedet_rec SET ";
1286 $sql .= "fk_facture = ".((int) $facid);
1287 $sql .= ", fk_parent_line = ".($fk_parent_line > 0 ? ((int) $fk_parent_line) : "null");
1288 $sql .= ", label=".(!empty($label) ? "'".$this->db->escape($label)."'" : "null");
1289 $sql .= ", description='".$this->db->escape($desc)."'";
1290 $sql .= ", price=".price2num($pu_ht);
1291 $sql .= ", qty=".price2num($qty);
1292 $sql .= ", tva_tx=".price2num($txtva);
1293 $sql .= ", vat_src_code='".$this->db->escape($vat_src_code)."'";
1294 $sql .= ", localtax1_tx=".((float) $txlocaltax1);
1295 $sql .= ", localtax1_type='".$this->db->escape($localtaxes_type[0])."'";
1296 $sql .= ", localtax2_tx=".((float) $txlocaltax2);
1297 $sql .= ", localtax2_type='".$this->db->escape($localtaxes_type[2])."'";
1298 $sql .= ", fk_product=".(!empty($fk_product) ? "'".$this->db->escape((string) $fk_product)."'" : "null");
1299 $sql .= ", product_type=".((int) $product_type);
1300 $sql .= ", remise_percent='".price2num($remise_percent)."'";
1301 $sql .= ", subprice='".price2num($pu_ht)."'";
1302 $sql .= ", total_ht='".price2num($total_ht)."'";
1303 $sql .= ", total_tva='".price2num($total_tva)."'";
1304 $sql .= ", total_localtax1='".price2num($total_localtax1)."'";
1305 $sql .= ", total_localtax2='".price2num($total_localtax2)."'";
1306 $sql .= ", total_ttc='".price2num($total_ttc)."'";
1307 $sql .= ", date_start_fill=".((int) $date_start_fill);
1308 $sql .= ", date_end_fill=".((int) $date_end_fill);
1309 $sql .= ", fk_product_fournisseur_price=".($fk_fournprice > 0 ? (int) $fk_fournprice : 'null');
1310 $sql .= ", buy_price_ht=".($pa_ht ? price2num($pa_ht) : 0);
1311 $sql .= ", info_bits=".((int) $info_bits);
1312 $sql .= ", rang=".((int) $rang);
1313 $sql .= ", special_code=".((int) $special_code);
1314 $sql .= ", fk_unit=".($fk_unit ? "'".$this->db->escape((string) $fk_unit)."'" : "null");
1315 $sql .= ', multicurrency_subprice = '.price2num($pu_ht_devise);
1316 $sql .= ', multicurrency_total_ht = '.price2num($multicurrency_total_ht);
1317 $sql .= ', multicurrency_total_tva = '.price2num($multicurrency_total_tva);
1318 $sql .= ', multicurrency_total_ttc = '.price2num($multicurrency_total_ttc);
1319 $sql .= " WHERE rowid = ".((int) $rowid);
1320
1321 dol_syslog(get_class($this)."::updateline", LOG_DEBUG);
1322 if ($this->db->query($sql)) {
1323 $this->id = $facid;
1324 $this->update_price(1);
1325 return 1;
1326 } else {
1327 $this->error = $this->db->lasterror();
1328 return -1;
1329 }
1330 }
1331
1332
1338 public function getNextDate()
1339 {
1340 if (empty($this->date_when)) {
1341 return false;
1342 }
1343 return dol_time_plus_duree($this->date_when, $this->frequency, $this->unit_frequency, 1);
1344 }
1345
1351 public function isMaxNbGenReached()
1352 {
1353 $ret = false;
1354 if ($this->nb_gen_max > 0 && ($this->nb_gen_done >= $this->nb_gen_max)) {
1355 $ret = true;
1356 }
1357 return $ret;
1358 }
1359
1366 public function strikeIfMaxNbGenReached($ret)
1367 {
1368 return $this->isMaxNbGenReached() ? '<strike>'.$ret.'</strike>' : $ret;
1369 }
1370
1382 public function createRecurringInvoices($restrictioninvoiceid = 0, $forcevalidation = 0, $notrigger = 0)
1383 {
1384 global $conf, $langs, $user, $hookmanager, $action;
1385
1386 $error = 0;
1387 $nb_create = 0;
1388
1389 // Load translation files required by the page
1390 $langs->loadLangs(array("main", "bills"));
1391
1392 $now = dol_now();
1393 $tmparray = dol_getdate($now);
1394 $today = dol_mktime(23, 59, 59, $tmparray['mon'], $tmparray['mday'], $tmparray['year']); // Today is last second of current day
1395
1396 $this->output = '';
1397
1398 dol_syslog("createRecurringInvoices restrictioninvoiceid=".$restrictioninvoiceid." forcevalidation=".$forcevalidation);
1399
1400 $sql = 'SELECT rowid FROM '.MAIN_DB_PREFIX.'facture_rec';
1401 $sql .= ' WHERE frequency > 0'; // A recurring invoice is an invoice with a frequency
1402 $sql .= " AND (date_when IS NULL OR date_when <= '".$this->db->idate($today)."')";
1403 $sql .= ' AND (nb_gen_done < nb_gen_max OR nb_gen_max = 0)';
1404 $sql .= ' AND suspended = 0';
1405 $sql .= ' AND entity = '.$conf->entity; // MUST STAY = $conf->entity here
1406 if ($restrictioninvoiceid > 0) {
1407 $sql .= ' AND rowid = '.((int) $restrictioninvoiceid);
1408 }
1409 $sql .= $this->db->order('entity', 'ASC');
1410 //print $sql;exit;
1411 $parameters = array(
1412 'restrictioninvoiceid' => $restrictioninvoiceid,
1413 'forcevalidation' => $forcevalidation,
1414 );
1415 $reshook = $hookmanager->executeHooks('beforeCreationOfRecurringInvoices', $parameters, $sql); // note that $sql might be modified by hooks
1416
1417 $resql = $this->db->query($sql);
1418 if ($resql) {
1419 $i = 0;
1420 $num = $this->db->num_rows($resql);
1421
1422 if ($num) {
1423 $this->output .= $langs->trans("FoundXQualifiedRecurringInvoiceTemplate", $num)."\n";
1424 } else {
1425 $this->output .= $langs->trans("NoQualifiedRecurringInvoiceTemplateFound");
1426 }
1427
1428 $saventity = $conf->entity;
1429
1430 while ($i < $num) { // Loop on each template invoice. If $num = 0, test is false at first pass.
1431 $line = $this->db->fetch_object($resql);
1432
1433 $this->db->begin();
1434
1435 $errorforinvoice = 0;
1436 $invoiceidgenerated = 0;
1437
1438 $facture = null;
1439 $facturerec = new FactureRec($this->db);
1440 $facturerec->fetch($line->rowid);
1441
1442 if ($facturerec->id > 0) {
1443 // Set entity context
1444 $conf->entity = $facturerec->entity;
1445
1446 dol_syslog("createRecurringInvoices Process invoice template id=".$facturerec->id.", ref=".$facturerec->ref.", entity=".$facturerec->entity);
1447
1448 $facture = new Facture($this->db);
1449 $facture->fac_rec = $facturerec->id; // We will create $facture from this recurring invoice
1450 $facture->fk_fac_rec_source = $facturerec->id; // We will create $facture from this recurring invoice
1451
1452 $facture->type = self::TYPE_STANDARD;
1453 $facture->subtype = $facturerec->subtype;
1454 $facture->statut = self::STATUS_DRAFT; // deprecated
1455 $facture->status = self::STATUS_DRAFT;
1456 $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.
1457 $facture->socid = $facturerec->socid;
1458
1459 if (!empty($facturerec->fk_multicurrency)) {
1460 $facture->fk_multicurrency = $facturerec->fk_multicurrency;
1461 $facture->multicurrency_code = $facturerec->multicurrency_code;
1462 $facture->multicurrency_tx = $facturerec->multicurrency_tx;
1463 }
1464
1465 if (isset($facture->array_options) && isset($facturerec->array_options)) {
1466 foreach ($facturerec->array_options as $key => $value) {
1467 if (isset($facture->array_options[$key])) {
1468 $facture->array_options[$key] = $value;
1469 }
1470 }
1471 }
1472
1473 $parameters['facture'] = &$facture;
1474 $reshook = $hookmanager->executeHooks('beforeCreationOfEachRecurringInvoice', $parameters, $facturerec, $action); // note that $facturerec or $facture might be modified by hooks
1475
1476 // Create invoice. This may update prices according to multiplrice rules
1477 $invoiceidgenerated = $facture->create($user, 0, 0, (isModEnabled('multicurrency') ? $facturerec->usenewcurrencyrate : 0));
1478 if ($invoiceidgenerated <= 0) {
1479 $this->setErrorsFromObject($facture);
1480 $error++;
1481 $errorforinvoice++;
1482 }
1483
1484
1485 if (!$errorforinvoice && ($facturerec->auto_validate || $forcevalidation)) {
1486 $result = $facture->validate($user);
1487 if ($result <= 0) {
1488 $this->setErrorsFromObject($facture);
1489 $error++;
1490 $errorforinvoice++;
1491 }
1492 }
1493 if (!$errorforinvoice && $facturerec->generate_pdf) {
1494 // We refresh the object in order to have all necessary data (like date_lim_reglement)
1495 $facture->fetch($facture->id);
1496 $result = $facture->generateDocument($facturerec->model_pdf, $langs);
1497 if ($result <= 0) {
1498 $this->setErrorsFromObject($facture);
1499 $error++;
1500 $errorforinvoice++;
1501 }
1502 }
1503 } else {
1504 $error++;
1505 $this->error = "Failed to load invoice template with id=".$line->rowid.", entity=".$conf->entity."\n";
1506 $this->errors[] = "Failed to load invoice template with id=".$line->rowid.", entity=".$conf->entity;
1507 dol_syslog("createRecurringInvoices Failed to load invoice template with id=".$line->rowid.", entity=".$conf->entity);
1508 }
1509
1510 // Commit or rollback
1511 if (!$error && $invoiceidgenerated >= 0) {
1512 $this->db->commit("createRecurringInvoices Process invoice template id=".$facturerec->id.", ref=".$facturerec->ref);
1513 dol_syslog("createRecurringInvoices Process invoice template ".$facturerec->ref." is finished with a success generation");
1514 $nb_create++;
1515 $this->output .= $langs->trans("InvoiceGeneratedFromTemplate", $facture->ref, $facturerec->ref)."\n";
1516 } else {
1517 $this->output .= $langs->trans("InvoiceGeneratedFromTemplateError", $facture->ref, $facturerec->ref, $this->error)."\n";
1518 $this->db->rollback("createRecurringInvoices Process invoice template id=".$facturerec->id.", ref=".$facturerec->ref);
1519 }
1520
1521 $parameters = array(
1522 'cpt' => $i,
1523 'total' => $num,
1524 'errorCount' => $error,
1525 'errorForInvoice' => $errorforinvoice,
1526 'invoiceidgenerated' => $invoiceidgenerated,
1527 'facturerec' => $facturerec, // it's an object which PHP passes by "reference", so modifiable by hooks.
1528 'this' => $this, // it's an object which PHP passes by "reference", so modifiable by hooks.
1529 );
1530 // @phan-suppress-next-line PhanTypeMismatchArgumentNullable
1531 $reshook = $hookmanager->executeHooks('afterCreationOfRecurringInvoice', $parameters, $facture); // note: $facture can be modified by hooks (warning: $facture can be null)
1532
1533 $i++;
1534 }
1535
1536 $conf->entity = $saventity; // Restore entity context
1537 } else {
1538 dol_print_error($this->db);
1539 }
1540
1541 $this->output = trim($this->output);
1542
1543 return $error ? $error : 0;
1544 }
1545
1558 public function getNomUrl($withpicto = 0, $option = '', $max = 0, $short = 0, $moretitle = '', $notooltip = 0, $save_lastsearch_value = -1)
1559 {
1560 global $langs, $hookmanager;
1561
1562 $result = '';
1563
1564 $label = img_picto('', $this->picto).' <u class="paddingrightonly">'.$langs->trans("RepeatableInvoice").'</u>';
1565 if (!empty($this->ref)) {
1566 $label .= '<br><b>'.$langs->trans('Ref').':</b> '.$this->ref;
1567 }
1568 if ($this->frequency > 0) {
1569 $label .= '<br><b>'.$langs->trans('Frequency').':</b> '.$langs->trans('FrequencyPer_'.$this->unit_frequency, $this->frequency);
1570 }
1571 if (!empty($this->date_last_gen)) {
1572 $label .= '<br><b>'.$langs->trans('DateLastGeneration').':</b> '.dol_print_date($this->date_last_gen, 'dayhour');
1573 }
1574 if ($this->frequency > 0) {
1575 if (!empty($this->date_when)) {
1576 $label .= '<br><b>'.$langs->trans('NextDateToExecution').':</b> ';
1577 $label .= (empty($this->suspended) ? '' : '<strike>').dol_print_date($this->date_when, 'day').(empty($this->suspended) ? '' : '</strike>'); // No hour for this property
1578 if (!empty($this->suspended)) {
1579 $label .= ' ('.$langs->trans("Disabled").')';
1580 }
1581 }
1582 }
1583
1584 $url = DOL_URL_ROOT.'/compta/facture/card-rec.php?id='.$this->id;
1585
1586 if ($short) {
1587 return $url;
1588 }
1589
1590 if ($option != 'nolink') {
1591 // Add param to save lastsearch_values or not
1592 $add_save_lastsearch_values = ($save_lastsearch_value == 1 ? 1 : 0);
1593 if ($save_lastsearch_value == -1 && isset($_SERVER["PHP_SELF"]) && preg_match('/list\.php/', $_SERVER["PHP_SELF"])) {
1594 $add_save_lastsearch_values = 1;
1595 }
1596 if ($add_save_lastsearch_values) {
1597 $url .= '&save_lastsearch_values=1';
1598 }
1599 }
1600
1601 $linkstart = '<a href="'.$url.'" title="'.dol_escape_htmltag($label, 1).'" class="classfortooltip">';
1602 $linkend = '</a>';
1603
1604 $result .= $linkstart;
1605 if ($withpicto) {
1606 $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);
1607 }
1608 if ($withpicto != 2) {
1609 $result .= dol_trunc($this->ref, $max);
1610 }
1611 $result .= $linkend;
1612 global $action;
1613 $hookmanager->initHooks(array($this->element . 'dao'));
1614 $parameters = array('id' => $this->id, 'getnomurl' => &$result);
1615 $reshook = $hookmanager->executeHooks('getNomUrl', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks
1616 if ($reshook > 0) {
1617 $result = $hookmanager->resPrint;
1618 } else {
1619 $result .= $hookmanager->resPrint;
1620 }
1621 return $result;
1622 }
1623
1631 public function getLibStatut($mode = 0, $alreadypaid = -1)
1632 {
1633 return $this->LibStatut($this->frequency ? 1 : 0, $this->suspended, $mode, $alreadypaid, empty($this->type) ? 0 : $this->type);
1634 }
1635
1636 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1648 public function LibStatut($recur, $status, $mode = 0, $alreadypaid = -1, $type = 0, $nbofopendirectdebitorcredittransfer = 0)
1649 {
1650 // phpcs:enable
1651 global $langs;
1652 $langs->load('bills');
1653
1654 $labelStatus = $langs->transnoentitiesnoconv('Active');
1655 $statusType = 'status0';
1656
1657 //print "$recur,$status,$mode,$alreadypaid,$type";
1658 if ($mode == 0) {
1659 if ($recur) {
1660 if ($status == self::STATUS_SUSPENDED) {
1661 $labelStatus = $langs->transnoentitiesnoconv('Disabled');
1662 } else {
1663 $labelStatus = $langs->transnoentitiesnoconv('Active');
1664 }
1665 } else {
1666 if ($status == self::STATUS_SUSPENDED) {
1667 $labelStatus = $langs->transnoentitiesnoconv('Disabled');
1668 } else {
1669 $labelStatus = $langs->transnoentitiesnoconv("Draft");
1670 }
1671 }
1672 } elseif ($mode == 1) {
1673 $prefix = 'Short';
1674 if ($recur) {
1675 if ($status == self::STATUS_SUSPENDED) {
1676 $labelStatus = $langs->transnoentitiesnoconv('Disabled');
1677 } else {
1678 $labelStatus = $langs->transnoentitiesnoconv('Active');
1679 }
1680 } else {
1681 if ($status == self::STATUS_SUSPENDED) {
1682 $labelStatus = $langs->transnoentitiesnoconv('Disabled');
1683 } else {
1684 $labelStatus = $langs->transnoentitiesnoconv("Draft");
1685 }
1686 }
1687 } elseif ($mode == 2) {
1688 if ($recur) {
1689 if ($status == self::STATUS_SUSPENDED) {
1690 $statusType = 'status6';
1691 $labelStatus = $langs->transnoentitiesnoconv('Disabled');
1692 } else {
1693 $statusType = 'status4';
1694 $labelStatus = $langs->transnoentitiesnoconv('Active');
1695 }
1696 } else {
1697 if ($status == self::STATUS_SUSPENDED) {
1698 $statusType = 'status6';
1699 $labelStatus = $langs->transnoentitiesnoconv('Disabled');
1700 } else {
1701 $statusType = 'status0';
1702 $labelStatus = $langs->transnoentitiesnoconv('Draft');
1703 }
1704 }
1705 } elseif ($mode == 3) {
1706 if ($recur) {
1707 $prefix = 'Short';
1708 if ($status == self::STATUS_SUSPENDED) {
1709 $statusType = 'status6';
1710 $labelStatus = $langs->transnoentitiesnoconv('Disabled');
1711 } else {
1712 $statusType = 'status4';
1713 $labelStatus = $langs->transnoentitiesnoconv('Active');
1714 }
1715 } else {
1716 if ($status == self::STATUS_SUSPENDED) {
1717 $statusType = 'status6';
1718 $labelStatus = $langs->transnoentitiesnoconv('Disabled');
1719 } else {
1720 $statusType = 'status0';
1721 $labelStatus = $langs->transnoentitiesnoconv('Draft');
1722 }
1723 }
1724 } elseif ($mode == 4) {
1725 $prefix = '';
1726 if ($recur) {
1727 if ($status == self::STATUS_SUSPENDED) {
1728 $statusType = 'status6';
1729 $labelStatus = $langs->transnoentitiesnoconv('Disabled');
1730 } else {
1731 $statusType = 'status4';
1732 $labelStatus = $langs->transnoentitiesnoconv('Active');
1733 }
1734 } else {
1735 if ($status == self::STATUS_SUSPENDED) {
1736 $statusType = 'status6';
1737 $labelStatus = $langs->transnoentitiesnoconv('Disabled');
1738 } else {
1739 $statusType = 'status0';
1740 $labelStatus = $langs->transnoentitiesnoconv('Draft');
1741 }
1742 }
1743 } elseif ($mode == 5 || $mode == 6) {
1744 $prefix = '';
1745 if ($mode == 5) {
1746 $prefix = 'Short';
1747 }
1748 if ($recur) {
1749 if ($status == self::STATUS_SUSPENDED) {
1750 $statusType = 'status6';
1751 $labelStatus = $langs->transnoentitiesnoconv('Disabled');
1752 } else {
1753 $statusType = 'status4';
1754 $labelStatus = $langs->transnoentitiesnoconv('Active');
1755 }
1756 } else {
1757 if ($status == self::STATUS_SUSPENDED) {
1758 $statusType = 'status6';
1759 $labelStatus = $langs->transnoentitiesnoconv('Disabled');
1760 } else {
1761 $statusType = 'status0';
1762 $labelStatus = $langs->transnoentitiesnoconv('Draft');
1763 }
1764 }
1765 }
1766
1767 $labelStatusShort = $labelStatus;
1768
1769 return dolGetStatus($labelStatus, $labelStatusShort, '', $statusType, $mode);
1770 }
1771
1779 public function getNextNumRef($soc, $mode = 'next')
1780 {
1781 // Not used for recurring invoices
1782 return '';
1783 }
1784
1791 public function info($id)
1792 {
1793 $sql = 'SELECT c.rowid, datec, tms as datem,';
1794 $sql .= ' fk_user_author, fk_user_modif';
1795 $sql .= ' FROM '.MAIN_DB_PREFIX.'facture_rec as c';
1796 $sql .= ' WHERE c.rowid = '.((int) $id);
1797
1798 $result = $this->db->query($sql);
1799 if ($result) {
1800 if ($this->db->num_rows($result)) {
1801 $obj = $this->db->fetch_object($result);
1802
1803 $this->id = $obj->rowid;
1804
1805 $this->user_creation_id = $obj->fk_user_author;
1806 $this->user_modification_id = $obj->fk_user_modif;
1807 $this->date_creation = $this->db->jdate($obj->datec);
1808 $this->date_modification = $this->db->jdate($obj->datem);
1809 }
1810 $this->db->free($result);
1811 } else {
1812 dol_print_error($this->db);
1813 }
1814 }
1815
1824 public function initAsSpecimen($option = '')
1825 {
1826 global $langs;
1827
1828 $now = dol_now();
1829 $arraynow = dol_getdate($now);
1830 $nownotime = dol_mktime(0, 0, 0, $arraynow['mon'], $arraynow['mday'], $arraynow['year']);
1831
1832 // Load array of products prodids
1833 $num_prods = 0;
1834 $prodids = array();
1835
1836 $sql = "SELECT rowid";
1837 $sql .= " FROM ".MAIN_DB_PREFIX."product";
1838 $sql .= " WHERE entity IN (".getEntity('product').")";
1839 $sql .= $this->db->plimit(100);
1840
1841 $resql = $this->db->query($sql);
1842 if ($resql) {
1843 $num_prods = $this->db->num_rows($resql);
1844 $i = 0;
1845 while ($i < $num_prods) {
1846 $i++;
1847 $row = $this->db->fetch_row($resql);
1848 $prodids[$i] = $row[0];
1849 }
1850 }
1851
1852 // Initialize parameters
1853 $this->id = 0;
1854 $this->ref = 'SPECIMEN';
1855 $this->title = 'SPECIMEN';
1856 $this->specimen = 1;
1857 $this->socid = 1;
1858 $this->date = $nownotime;
1859 $this->date_lim_reglement = $nownotime + 3600 * 24 * 30;
1860 $this->cond_reglement_id = 1;
1861 $this->cond_reglement_code = 'RECEP';
1862 $this->date_lim_reglement = $this->calculate_date_lim_reglement();
1863 $this->mode_reglement_id = 0; // Not forced to show payment mode CHQ + VIR
1864 $this->mode_reglement_code = ''; // Not forced to show payment mode CHQ + VIR
1865 $this->note_public = 'This is a comment (public)';
1866 $this->note_private = 'This is a comment (private)';
1867 $this->fk_incoterms = 0;
1868 $this->location_incoterms = '';
1869
1870 if (empty($option) || $option != 'nolines') {
1871 // Lines
1872 $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)
1873 $xnbp = 0;
1874 while ($xnbp < $nbp) {
1875 $line = new FactureLigne($this->db);
1876 $line->desc = $langs->trans("Description")." ".$xnbp;
1877 $line->qty = 1;
1878 $line->subprice = 100;
1879 $line->tva_tx = 19.6;
1880 $line->localtax1_tx = 0;
1881 $line->localtax2_tx = 0;
1882 $line->remise_percent = 0;
1883 if ($xnbp == 1) { // Qty is negative (product line)
1884 $prodid = mt_rand(1, $num_prods);
1885 $line->fk_product = $prodids[$prodid];
1886 $line->qty = -1;
1887 $line->total_ht = -100;
1888 $line->total_ttc = -119.6;
1889 $line->total_tva = -19.6;
1890 } elseif ($xnbp == 2) { // UP is negative (free line)
1891 $line->subprice = -100;
1892 $line->total_ht = -100;
1893 $line->total_ttc = -119.6;
1894 $line->total_tva = -19.6;
1895 $line->remise_percent = 0;
1896 } elseif ($xnbp == 3) { // Discount is 50% (product line)
1897 $prodid = mt_rand(1, $num_prods);
1898 $line->fk_product = $prodids[$prodid];
1899 $line->total_ht = 50;
1900 $line->total_ttc = 59.8;
1901 $line->total_tva = 9.8;
1902 $line->remise_percent = 50;
1903 } else { // (product line)
1904 $prodid = mt_rand(1, $num_prods);
1905 $line->fk_product = $prodids[$prodid];
1906 $line->total_ht = 100;
1907 $line->total_ttc = 119.6;
1908 $line->total_tva = 19.6;
1909 $line->remise_percent = 00;
1910 }
1911
1912 $this->lines[$xnbp] = $line;
1913 $xnbp++;
1914
1915 $this->total_ht += $line->total_ht;
1916 $this->total_tva += $line->total_tva;
1917 $this->total_ttc += $line->total_ttc;
1918 }
1919 $this->revenuestamp = 0;
1920
1921 // Add a line "offered"
1922 $line = new FactureLigne($this->db);
1923 $line->desc = $langs->trans("Description")." (offered line)";
1924 $line->qty = 1;
1925 $line->subprice = 100;
1926 $line->tva_tx = 19.6;
1927 $line->localtax1_tx = 0;
1928 $line->localtax2_tx = 0;
1929 $line->remise_percent = 100;
1930 $line->total_ht = 0;
1931 $line->total_ttc = 0; // 90 * 1.196
1932 $line->total_tva = 0;
1933 $prodid = mt_rand(1, $num_prods);
1934 $line->fk_product = $prodids[$prodid];
1935
1936 $this->lines[$xnbp] = $line;
1937 $xnbp++;
1938 }
1939
1940 $this->usenewprice = 0;
1941
1942 return 1;
1943 }
1944
1953 public static function replaceThirdparty(DoliDB $dbs, $origin_id, $dest_id)
1954 {
1955 $tables = array(
1956 'facture_rec'
1957 );
1958
1959 return CommonObject::commonReplaceThirdparty($dbs, $origin_id, $dest_id, $tables);
1960 }
1961
1970 public static function replaceProduct(DoliDB $dbs, $origin_id, $dest_id)
1971 {
1972 $tables = array(
1973 'facturedet_rec'
1974 );
1975
1976 return CommonObject::commonReplaceProduct($dbs, $origin_id, $dest_id, $tables);
1977 }
1978
1987 public function setFrequencyAndUnit($frequency, $unit, $notrigger = 0)
1988 {
1989 global $user;
1990
1991 if (!$this->table_element) {
1992 dol_syslog(get_class($this)."::setFrequencyAndUnit was called on object with property table_element not defined", LOG_ERR);
1993 return -1;
1994 }
1995
1996 if (!empty($frequency) && empty($unit)) {
1997 dol_syslog(get_class($this)."::setFrequencyAndUnit was called on object with params frequency defined but unit not defined", LOG_ERR);
1998 return -2;
1999 }
2000
2001 $sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element;
2002 $sql .= ' SET frequency = '.($frequency ? $this->db->escape((string) $frequency) : 'null');
2003 if (!empty($unit)) {
2004 $sql .= ', unit_frequency = \''.$this->db->escape($unit).'\'';
2005 }
2006 $sql .= " WHERE rowid = ".((int) $this->id);
2007
2008 dol_syslog(get_class($this)."::setFrequencyAndUnit", LOG_DEBUG);
2009 if ($this->db->query($sql)) {
2010 $this->frequency = $frequency;
2011 if (!empty($unit)) {
2012 $this->unit_frequency = $unit;
2013 }
2014
2015 if (!$notrigger) {
2016 // Call trigger
2017 $result = $this->call_trigger('BILLREC_MODIFY', $user);
2018 if ($result < 0) {
2019 return $result;
2020 }
2021 // End call triggers
2022 }
2023
2024 return 1;
2025 } else {
2026 dol_print_error($this->db);
2027 return -1;
2028 }
2029 }
2030
2039 public function setNextDate($date, $increment_nb_gen_done = 0, $notrigger = 0)
2040 {
2041 global $user;
2042
2043 if (!$this->table_element) {
2044 dol_syslog(get_class($this)."::setNextDate was called on object with property table_element not defined", LOG_ERR);
2045 return -1;
2046 }
2047 $sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element;
2048 $sql .= " SET date_when = ".($date ? "'".$this->db->idate($date)."'" : "null");
2049 if ($increment_nb_gen_done > 0) {
2050 $sql .= ', nb_gen_done = nb_gen_done + 1';
2051 }
2052 $sql .= " WHERE rowid = ".((int) $this->id);
2053
2054 dol_syslog(get_class($this)."::setNextDate", LOG_DEBUG);
2055 if ($this->db->query($sql)) {
2056 $this->date_when = $date;
2057 if ($increment_nb_gen_done > 0) {
2058 $this->nb_gen_done++;
2059
2060 if (getDolGlobalInt('MAIN_SUSPEND_FACTURE_REC_ON_MAX_GEN_REACHED') && $this->isMaxNbGenReached()) {
2061 $resSuspend = $this->setValueFrom('suspended', 1);
2062
2063 if ($resSuspend <= 0) {
2064 dol_syslog(__METHOD__ . '::setValueFrom Error : ' . $this->error, LOG_ERR);
2065 return -1;
2066 }
2067 }
2068 }
2069
2070 if (!$notrigger) {
2071 if (empty($this->context['actionmsgmore'])) {
2072 $this->context['actionmsgmore'] = 'Trigger called by setNextDate';
2073 }
2074
2075 // Call trigger
2076 $result = $this->call_trigger('BILLREC_MODIFY', $user);
2077 if ($result < 0) {
2078 return $result;
2079 }
2080 // End call triggers
2081 }
2082 return 1;
2083 } else {
2084 dol_print_error($this->db);
2085 return -1;
2086 }
2087 }
2088
2096 public function setMaxPeriod($nb, $notrigger = 0)
2097 {
2098 global $user;
2099
2100 if (!$this->table_element) {
2101 dol_syslog(get_class($this)."::setMaxPeriod was called on object with property table_element not defined", LOG_ERR);
2102 return -1;
2103 }
2104
2105 if (empty($nb)) {
2106 $nb = 0;
2107 }
2108
2109 $sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element;
2110 $sql .= ' SET nb_gen_max = '.((int) $nb);
2111 $sql .= " WHERE rowid = ".((int) $this->id);
2112
2113 dol_syslog(get_class($this)."::setMaxPeriod", LOG_DEBUG);
2114 if ($this->db->query($sql)) {
2115 $this->nb_gen_max = $nb;
2116
2117 if (!$notrigger) {
2118 // Call trigger
2119 $result = $this->call_trigger('BILLREC_MODIFY', $user);
2120 if ($result < 0) {
2121 return $result;
2122 }
2123 // End call triggers
2124 }
2125
2126 return 1;
2127 } else {
2128 dol_print_error($this->db);
2129 return -1;
2130 }
2131 }
2132
2140 public function setAutoValidate($validate, $notrigger = 0)
2141 {
2142 global $user;
2143
2144 if (!$this->table_element) {
2145 dol_syslog(get_class($this)."::setAutoValidate was called on object with property table_element not defined", LOG_ERR);
2146 return -1;
2147 }
2148
2149 $sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element;
2150 $sql .= ' SET auto_validate = '.((int) $validate);
2151 $sql .= " WHERE rowid = ".((int) $this->id);
2152
2153 dol_syslog(get_class($this)."::setAutoValidate", LOG_DEBUG);
2154 if ($this->db->query($sql)) {
2155 $this->auto_validate = $validate;
2156
2157 if (!$notrigger) {
2158 // Call trigger
2159 $result = $this->call_trigger('BILLREC_MODIFY', $user);
2160 if ($result < 0) {
2161 return $result;
2162 }
2163 // End call triggers
2164 }
2165
2166 return 1;
2167 } else {
2168 dol_print_error($this->db);
2169 return -1;
2170 }
2171 }
2172
2180 public function setGeneratePdf($validate, $notrigger = 0)
2181 {
2182 global $user;
2183
2184 if (!$this->table_element) {
2185 dol_syslog(get_class($this)."::setGeneratePdf was called on object with property table_element not defined", LOG_ERR);
2186 return -1;
2187 }
2188
2189 $sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element;
2190 $sql .= ' SET generate_pdf = '.((int) $validate);
2191 $sql .= " WHERE rowid = ".((int) $this->id);
2192
2193 dol_syslog(get_class($this)."::setGeneratePdf", LOG_DEBUG);
2194 if ($this->db->query($sql)) {
2195 $this->generate_pdf = $validate;
2196
2197 if (!$notrigger) {
2198 // Call trigger
2199 $result = $this->call_trigger('BILLREC_MODIFY', $user);
2200 if ($result < 0) {
2201 return $result;
2202 }
2203 // End call triggers
2204 }
2205
2206 return 1;
2207 } else {
2208 dol_print_error($this->db);
2209 return -1;
2210 }
2211 }
2212
2220 public function setModelPdf($model, $notrigger = 0)
2221 {
2222 global $user;
2223 if (!$this->table_element) {
2224 dol_syslog(get_class($this)."::setModelPdf was called on object with property table_element not defined", LOG_ERR);
2225 return -1;
2226 }
2227
2228 $sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element;
2229 $sql .= " SET modelpdf = '".$this->db->escape($model)."'";
2230 $sql .= " WHERE rowid = ".((int) $this->id);
2231
2232 dol_syslog(get_class($this)."::setModelPdf", LOG_DEBUG);
2233 if ($this->db->query($sql)) {
2234 $this->model_pdf = $model;
2235
2236 if (!$notrigger) {
2237 // Call trigger
2238 $result = $this->call_trigger('BILLREC_MODIFY', $user);
2239 if ($result < 0) {
2240 return $result;
2241 }
2242 // End call triggers
2243 }
2244
2245 return 1;
2246 } else {
2247 dol_print_error($this->db);
2248 return -1;
2249 }
2250 }
2251}
2252
2253
2254
2260{
2264 public $element = 'facturedetrec';
2265
2269 public $table_element = 'facturedet_rec';
2270
2274 public $parent_element = 'facturerec';
2275
2279 public $fk_parent_attribute = 'fk_facture';
2280
2282
2285 public $fk_facture;
2289 public $fk_parent_line;
2290
2294 public $fk_product_fournisseur_price;
2299 public $fk_fournprice;
2300
2304 public $rang;
2305 //public $situation_percent; // Not supported on recurring invoice line
2306
2310 public $desc;
2314 public $description;
2315
2320 public $fk_product_type;
2321
2325 public $fk_contract_line;
2326
2327
2335 public function delete(User $user, $notrigger = 0)
2336 {
2337 $error = 0;
2338
2339 $this->db->begin();
2340
2341 if (!$error) {
2342 if (!$notrigger) {
2343 // Call triggers
2344 $result = $this->call_trigger('LINEBILLREC_DELETE', $user);
2345 if ($result < 0) {
2346 $error++;
2347 } // Do also here what you must do to rollback action if trigger fail
2348 // End call triggers
2349 }
2350 }
2351
2352 if (!$error) {
2353 $result = $this->deleteExtraFields();
2354 if ($result < 0) {
2355 $error++;
2356 }
2357 }
2358
2359 if (!$error) {
2360 $sql = 'DELETE FROM '.MAIN_DB_PREFIX.$this->table_element.' WHERE rowid='.((int) $this->id);
2361
2362 $res = $this->db->query($sql);
2363 if (!$res) {
2364 $error++;
2365 $this->errors[] = $this->db->lasterror();
2366 }
2367 }
2368
2369 // Commit or rollback
2370 if ($error) {
2371 $this->db->rollback();
2372 return -1;
2373 } else {
2374 $this->db->commit();
2375 return 1;
2376 }
2377 }
2378
2379
2386 public function fetch($rowid)
2387 {
2388 $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,';
2389 $sql .= ' l.localtax1_tx, l.localtax2_tx, l.localtax1_type, l.localtax2_type, l.remise, l.remise_percent, l.subprice,';
2390 $sql .= ' l.date_start_fill, l.date_end_fill, l.info_bits, l.total_ht, l.total_tva, l.total_ttc,';
2391 $sql .= ' l.rang, l.special_code,';
2392 $sql .= ' l.fk_unit, l.fk_contract_line,';
2393 $sql .= ' l.import_key, l.fk_multicurrency,';
2394 $sql .= ' l.multicurrency_code, l.multicurrency_subprice, l.multicurrency_total_ht, l.multicurrency_total_tva, l.multicurrency_total_ttc,';
2395 $sql .= ' l.buy_price_ht, l.fk_product_fournisseur_price,';
2396 $sql .= ' l.fk_user_author, l.fk_user_modif, l.extraparams,';
2397 $sql .= ' p.ref as product_ref, p.fk_product_type as fk_product_type, p.label as product_label, p.description as product_desc';
2398 $sql .= ' FROM '.MAIN_DB_PREFIX.'facturedet_rec as l';
2399 $sql .= ' LEFT JOIN '.MAIN_DB_PREFIX.'product as p ON l.fk_product = p.rowid';
2400 $sql .= ' WHERE l.rowid = '.((int) $rowid);
2401 $sql .= ' ORDER BY l.rang';
2402
2403 dol_syslog('FactureRec::fetch', LOG_DEBUG);
2404 $result = $this->db->query($sql);
2405 if ($result) {
2406 $objp = $this->db->fetch_object($result);
2407
2408 $this->id = $objp->rowid;
2409 $this->fk_facture = $objp->fk_facture;
2410 $this->fk_parent_line = $objp->fk_parent_line;
2411 $this->label = $objp->custom_label; // Label line
2412 $this->desc = $objp->description; // Description line
2413 $this->description = $objp->description; // Description line
2414 $this->product_type = $objp->product_type; // Type of line
2415 $this->ref = $objp->product_ref; // Ref product
2416 $this->product_ref = $objp->product_ref; // Ref product
2417 $this->libelle = $objp->product_label; // deprecated
2418 $this->product_label = $objp->product_label; // Label product
2419 $this->product_desc = $objp->product_desc; // Description product
2420 $this->fk_product_type = $objp->fk_product_type; // Type of product
2421 $this->qty = $objp->qty;
2422 $this->price = $objp->price;
2423 $this->subprice = $objp->subprice;
2424 $this->vat_src_code = $objp->vat_src_code;
2425 $this->tva_tx = $objp->tva_tx;
2426 $this->localtax1_tx = $objp->localtax1_tx;
2427 $this->localtax2_tx = $objp->localtax2_tx;
2428 $this->localtax1_type = $objp->localtax1_type;
2429 $this->localtax2_type = $objp->localtax2_type;
2430 $this->remise_percent = $objp->remise_percent;
2431 //$this->fk_remise_except = $objp->fk_remise_except;
2432 $this->fk_product = $objp->fk_product;
2433 $this->date_start_fill = $objp->date_start_fill;
2434 $this->date_end_fill = $objp->date_end_fill;
2435 $this->info_bits = $objp->info_bits;
2436 $this->total_ht = $objp->total_ht;
2437 $this->total_tva = $objp->total_tva;
2438 $this->total_ttc = $objp->total_ttc;
2439
2440 $this->rang = $objp->rang;
2441 $this->special_code = $objp->special_code;
2442 $this->fk_unit = $objp->fk_unit;
2443 $this->fk_contract_line = $objp->fk_contract_line;
2444 $this->import_key = $objp->import_key;
2445 $this->fk_multicurrency = $objp->fk_multicurrency;
2446 $this->multicurrency_code = $objp->multicurrency_code;
2447 $this->multicurrency_subprice = $objp->multicurrency_subprice;
2448 $this->multicurrency_total_ht = $objp->multicurrency_total_ht;
2449 $this->multicurrency_total_tva = $objp->multicurrency_total_tva;
2450 $this->multicurrency_total_ttc = $objp->multicurrency_total_ttc;
2451
2452 $this->buy_price_ht = $objp->buy_price_ht;
2453
2454 $this->fk_product_fournisseur_price = $objp->fk_product_fournisseur_price;
2455 $this->fk_user_author = $objp->fk_user_author;
2456 $this->fk_user_modif = $objp->fk_user_modif;
2457
2458 $this->db->free($result);
2459 return 1;
2460 } else {
2461 $this->error = $this->db->lasterror();
2462 return -3;
2463 }
2464 }
2465
2466
2474 public function update(User $user, $notrigger = 0)
2475 {
2476 global $conf;
2477
2478 $error = 0;
2479
2480 // Clean parameters
2481 if (empty($this->fk_parent_line)) {
2482 $this->fk_parent_line = 0;
2483 }
2484
2485 include_once DOL_DOCUMENT_ROOT.'/core/lib/price.lib.php';
2486
2487 $sql = "UPDATE ".MAIN_DB_PREFIX."facturedet_rec SET";
2488 $sql .= " fk_facture = ".((int) $this->fk_facture);
2489 $sql .= ", fk_parent_line=".($this->fk_parent_line > 0 ? $this->fk_parent_line : "null");
2490 $sql .= ", label=".(!empty($this->label) ? "'".$this->db->escape($this->label)."'" : "null");
2491 $sql .= ", description='".$this->db->escape($this->desc)."'";
2492 $sql .= ", price=".price2num($this->price);
2493 $sql .= ", qty=".price2num($this->qty);
2494 $sql .= ", tva_tx=".price2num($this->tva_tx);
2495 $sql .= ", vat_src_code='".$this->db->escape($this->vat_src_code)."'";
2496 $sql .= ", localtax1_tx=".price2num($this->localtax1_tx);
2497 $sql .= ", localtax1_type='".$this->db->escape((string) $this->localtax1_type)."'";
2498 $sql .= ", localtax2_tx=".price2num($this->localtax2_tx);
2499 $sql .= ", localtax2_type='".$this->db->escape((string) $this->localtax2_type)."'";
2500 $sql .= ", fk_product=".($this->fk_product > 0 ? $this->fk_product : "null");
2501 $sql .= ", product_type=".((int) $this->product_type);
2502 $sql .= ", remise_percent=".price2num($this->remise_percent);
2503 $sql .= ", subprice=".price2num($this->subprice);
2504 $sql .= ", info_bits=".price2num($this->info_bits);
2505 $sql .= ", date_start_fill=".(int) $this->date_start_fill;
2506 $sql .= ", date_end_fill=".(int) $this->date_end_fill;
2507 if (empty($this->skip_update_total)) {
2508 $sql .= ", total_ht=".price2num($this->total_ht);
2509 $sql .= ", total_tva=".price2num($this->total_tva);
2510 $sql .= ", total_localtax1=".price2num($this->total_localtax1);
2511 $sql .= ", total_localtax2=".price2num($this->total_localtax2);
2512 $sql .= ", total_ttc=".price2num($this->total_ttc);
2513 }
2514 $sql .= ", rang=".((int) $this->rang);
2515 $sql .= ", special_code=".((int) $this->special_code);
2516 $sql .= ", fk_unit=".($this->fk_unit ? "'".$this->db->escape((string) $this->fk_unit)."'" : "null");
2517 $sql .= ", fk_contract_line=".($this->fk_contract_line ? $this->fk_contract_line : "null");
2518 $sql .= " WHERE rowid = ".((int) $this->id);
2519
2520 $this->db->begin();
2521
2522 dol_syslog(get_class($this)."::updateline", LOG_DEBUG);
2523
2524 $resql = $this->db->query($sql);
2525 if ($resql) {
2526 if (!$error) {
2527 $result = $this->insertExtraFields();
2528 if ($result < 0) {
2529 $error++;
2530 }
2531 }
2532
2533 if (!$error && !$notrigger) {
2534 // Call trigger
2535 $result = $this->call_trigger('LINEBILLREC_MODIFY', $user);
2536 if ($result < 0) {
2537 $error++;
2538 }
2539 // End call triggers
2540 }
2541
2542 if ($error) {
2543 $this->db->rollback();
2544 return -2;
2545 } else {
2546 $this->db->commit();
2547 return 1;
2548 }
2549 } else {
2550 $this->error = $this->db->lasterror();
2551 $this->db->rollback();
2552 return -2;
2553 }
2554 }
2555}
$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
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)
Add a delay to a date.
Definition date.lib.php:125
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:464
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:125