dolibarr 24.0.2
fournisseur.facture-rec.class.php
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) 2024-2026 MDW <mdeweerd@users.noreply.github.com>
11 * Copyright (C) 2023-2024 Nick Fragoulis
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/notify.class.php';
34require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php';
35require_once DOL_DOCUMENT_ROOT.'/fourn/class/fournisseur.facture.class.php';
36require_once DOL_DOCUMENT_ROOT.'/fourn/class/fournisseur.facture-rec.ligne.class.php';
37require_once DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php';
38
39
44{
49 public $TRIGGER_PREFIX = 'SUPPLIERBILLREC';
50
54 public $element = 'invoice_supplier_rec';
55
59 public $table_element = 'facture_fourn_rec';
60
64 public $table_element_line = 'facture_fourn_det_rec';
65
69 public $fk_element = 'fk_facture_fourn';
70
74 public $picto = 'supplier_invoice';
75
79 protected $table_ref_field = 'titre';
80
85 public $titre;
89 public $title;
90
94 public $ref_supplier;
98 public $socid;
99
104 public $fk_soc;
105
109 public $suspended; // status
110
115 public $libelle;
119 public $label;
120
125 public $amount;
130 public $remise;
131
135 public $vat_src_code;
139 public $localtax1;
143 public $localtax2;
144
148 public $user_author;
152 public $user_modif;
156 public $fk_project;
157
161 public $mode_reglement_id;
165 public $mode_reglement_code;
169 public $cond_reglement_code;
173 public $cond_reglement_doc;
177 public $cond_reglement_id;
178
182 public $date_lim_reglement;
183
187 public $usenewprice = 0;
191 public $frequency;
195 public $unit_frequency;
199 public $date_when;
203 public $date_last_gen;
204
208 public $nb_gen_done;
209
213 public $nb_gen_max;
214
218 public $auto_validate; //
222 public $generate_pdf; // 1 to generate PDF on invoice generation (default)
223
228 public $lines = array();
229
230
231 /* Override fields in CommonObject
232 public $total_ht;
233 public $total_tva;
234 public $total_ttc;
235 public $fk_account;
236 public $mode_reglement;
237 public $cond_reglement;
238 public $note_public;
239 public $note_private;
240 */
241
266 // BEGIN MODULEBUILDER PROPERTIES
270 public $fields = array(
271 'rowid' => array('type' => 'integer', 'label' => 'TechnicalID', 'enabled' => 1, 'visible' => -1, 'notnull' => 1, 'position' => 10),
272 'titre' => array('type' => 'varchar(100)', 'label' => 'Titre', 'enabled' => 1, 'showoncombobox' => 1, 'visible' => -1, 'position' => 15),
273 'ref_supplier' => array('type' => 'varchar(180)', 'label' => 'RefSupplier', 'enabled' => 1, 'showoncombobox' => 1, 'visible' => -1, 'position' => 20),
274 'entity' => array('type' => 'integer', 'label' => 'Entity', 'default' => '1', 'enabled' => 1, 'visible' => -2, 'notnull' => 1, 'position' => 25, 'index' => 1),
275 'fk_soc' => array('type' => 'integer:Societe:societe/class/societe.class.php', 'label' => 'ThirdParty', 'enabled' => 'isModEnabled("societe")', 'visible' => -1, 'notnull' => 1, 'position' => 30),
276 'datec' => array('type' => 'datetime', 'label' => 'DateCreation', 'enabled' => 1, 'visible' => -1, 'position' => 35),
277 'tms' => array('type' => 'timestamp', 'label' => 'DateModification', 'enabled' => 1, 'visible' => -1, 'notnull' => 1, 'position' => 40),
278 'suspended' => array('type' => 'integer', 'label' => 'Suspended', 'enabled' => 1, 'visible' => -1, 'position' => 225),
279 'libelle' => array('type' => 'varchar(100)', 'label' => 'Libelle', 'enabled' => 1, 'showoncombobox' => 0, 'visible' => -1, 'position' => 15),
280
281 'localtax1' => array('type' => 'double(24,8)', 'label' => 'Localtax1', 'enabled' => 1, 'visible' => -1, 'position' => 60, 'isameasure' => 1),
282 'localtax2' => array('type' => 'double(24,8)', 'label' => 'Localtax2', 'enabled' => 1, 'visible' => -1, 'position' => 65, 'isameasure' => 1),
283 'total_ht' => array('type' => 'double(24,8)', 'label' => 'Total', 'enabled' => 1, 'visible' => -1, 'position' => 70, 'isameasure' => 1),
284 'total_tva' => array('type' => 'double(24,8)', 'label' => 'Tva', 'enabled' => 1, 'visible' => -1, 'position' => 55, 'isameasure' => 1),
285 'total_ttc' => array('type' => 'double(24,8)', 'label' => 'Total ttc', 'enabled' => 1, 'visible' => -1, 'position' => 75, 'isameasure' => 1),
286
287 'fk_user_author' => array('type' => 'integer:User:user/class/user.class.php', 'label' => 'UserAuthor', 'enabled' => 1, 'visible' => -1, 'position' => 80),
288 'fk_user_modif' => array('type' => 'integer:User:user/class/user.class.php', 'label' => 'UserModif', 'enabled' => 1, 'visible' => -2, 'notnull' => -1, 'position' => 210),
289 '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),
290 'fk_account' => array('type' => 'integer', 'label' => 'Fk account', 'enabled' => 'isModEnabled("bank")', 'visible' => -1, 'position' => 175),
291 'fk_cond_reglement' => array('type' => 'integer', 'label' => 'Fk cond reglement', 'enabled' => 1, 'visible' => -1, 'position' => 90),
292 'fk_mode_reglement' => array('type' => 'integer', 'label' => 'Fk mode reglement', 'enabled' => 1, 'visible' => -1, 'position' => 95),
293 'date_lim_reglement' => array('type' => 'date', 'label' => 'Date lim reglement', 'enabled' => 1, 'visible' => -1, 'position' => 100),
294
295 'note_private' => array('type' => 'html', 'label' => 'NotePublic', 'enabled' => 1, 'visible' => 0, 'position' => 105),
296 'note_public' => array('type' => 'html', 'label' => 'NotePrivate', 'enabled' => 1, 'visible' => 0, 'position' => 110),
297 'modelpdf' => array('type' => 'varchar(255)', 'label' => 'Modelpdf', 'enabled' => 1, 'visible' => -1, 'position' => 115),
298
299 'fk_multicurrency' => array('type' => 'integer', 'label' => 'Fk multicurrency', 'enabled' => 1, 'visible' => -1, 'position' => 180),
300 'multicurrency_code' => array('type' => 'varchar(255)', 'label' => 'Multicurrency code', 'enabled' => 1, 'visible' => -1, 'position' => 185),
301 'multicurrency_tx' => array('type' => 'double(24,8)', 'label' => 'Multicurrency tx', 'enabled' => 1, 'visible' => -1, 'position' => 190, 'isameasure' => 1),
302 'multicurrency_total_ht' => array('type' => 'double(24,8)', 'label' => 'Multicurrency total ht', 'enabled' => 1, 'visible' => -1, 'position' => 195, 'isameasure' => 1),
303 'multicurrency_total_tva' => array('type' => 'double(24,8)', 'label' => 'Multicurrency total tva', 'enabled' => 1, 'visible' => -1, 'position' => 200, 'isameasure' => 1),
304 'multicurrency_total_ttc' => array('type' => 'double(24,8)', 'label' => 'Multicurrency total ttc', 'enabled' => 1, 'visible' => -1, 'position' => 205, 'isameasure' => 1),
305
306 'usenewprice' => array('type' => 'integer', 'label' => 'UseNewPrice', 'enabled' => 1, 'visible' => 0, 'position' => 155),
307 'frequency' => array('type' => 'integer', 'label' => 'Frequency', 'enabled' => 1, 'visible' => -1, 'position' => 150),
308 'unit_frequency' => array('type' => 'varchar(2)', 'label' => 'Unit frequency', 'enabled' => 1, 'visible' => -1, 'position' => 125),
309
310 'date_when' => array('type' => 'datetime', 'label' => 'Date when', 'enabled' => 1, 'visible' => -1, 'position' => 130),
311 'date_last_gen' => array('type' => 'datetime', 'label' => 'Date last gen', 'enabled' => 1, 'visible' => -1, 'position' => 135),
312 'nb_gen_done' => array('type' => 'integer', 'label' => 'Nb gen done', 'enabled' => 1, 'visible' => -1, 'position' => 140),
313 'nb_gen_max' => array('type' => 'integer', 'label' => 'Nb gen max', 'enabled' => 1, 'visible' => -1, 'position' => 145),
314 'revenuestamp' => array('type' => 'double(24,8)', 'label' => 'RevenueStamp', 'enabled' => 1, 'visible' => -1, 'position' => 160, 'isameasure' => 1),
315 'auto_validate' => array('type' => 'integer', 'label' => 'Auto validate', 'enabled' => 1, 'visible' => -1, 'position' => 165),
316 'generate_pdf' => array('type' => 'integer', 'label' => 'Generate pdf', 'enabled' => 1, 'visible' => -1, 'position' => 170),
317 );
318 // END MODULEBUILDER PROPERTIES
319
320 const STATUS_NOTSUSPENDED = 0;
321 const STATUS_SUSPENDED = 1;
322
323
324
330 public function __construct($db)
331 {
332 $this->db = $db;
333 }
334
344 public function create($user, $facFournId, $notrigger = 0, $onlylines = array())
345 {
346 global $conf;
347
348 $error = 0;
349 $now = dol_now();
350
351 // Clean parameters
352 $this->titre = empty($this->titre) ? '' : $this->titre; // deprecated
353 $this->title = empty($this->title) ? '' : $this->title;
354 $keyforref = $this->table_ref_field;
355 $this->ref = $this->$keyforref;
356
357 $this->ref_supplier = empty($this->ref_supplier) ? '' : $this->ref_supplier;
358
359 $this->usenewprice = empty($this->usenewprice) ? 0 : $this->usenewprice;
360 $this->suspended = empty($this->suspended) ? 0 : $this->suspended;
361 // No frequency defined then no next date to execution
362 if (empty($this->frequency)) {
363 $this->frequency = 0;
364 $this->date_when = null;
365 }
366 $this->frequency = abs($this->frequency);
367 $this->nb_gen_done = 0;
368 $this->nb_gen_max = empty($this->nb_gen_max) ? 0 : $this->nb_gen_max;
369 $this->auto_validate = empty($this->auto_validate) ? 0 : $this->auto_validate;
370 $this->generate_pdf = empty($this->generate_pdf) ? 0 : $this->generate_pdf;
371
372 $this->db->begin();
373
374 // We load the supplier invoice from which we create the model/template supplier invoice
375 $facfourn_src = new FactureFournisseur($this->db);
376 $result = $facfourn_src->fetch($facFournId);
377 if ($result > 0) {
378 $sql = 'INSERT INTO '.MAIN_DB_PREFIX.'facture_fourn_rec (';
379 $sql .= 'titre';
380 $sql .= ", subtype";
381 $sql .= ', ref_supplier';
382 $sql .= ', entity';
383 $sql .= ', fk_soc';
384 $sql .= ', datec';
385 $sql .= ', suspended';
386 $sql .= ', libelle';
387 $sql .= ', total_ttc';
388 $sql .= ', fk_user_author';
389 $sql .= ', fk_projet';
390 $sql .= ', fk_account';
391 $sql .= ', fk_cond_reglement';
392 $sql .= ', fk_mode_reglement';
393 $sql .= ', date_lim_reglement';
394 $sql .= ', note_private';
395 $sql .= ', note_public';
396 $sql .= ', modelpdf';
397 $sql .= ', fk_multicurrency';
398 $sql .= ', multicurrency_code';
399 $sql .= ', multicurrency_tx';
400 $sql .= ', usenewprice';
401 $sql .= ', frequency';
402 $sql .= ', unit_frequency';
403 $sql .= ', date_when';
404 $sql .= ', date_last_gen';
405 $sql .= ', nb_gen_done';
406 $sql .= ', nb_gen_max';
407 $sql .= ', auto_validate';
408 $sql .= ', generate_pdf';
409 $sql .= ') VALUES (';
410 $sql .= "'".$this->db->escape($this->title)."'";
411 $sql .= ", ".(isset($this->subtype) ? (int) $this->subtype : "NULL");
412 $sql .= ", '".$this->db->escape($this->ref_supplier)."'";
413 $sql .= ", ".((int) $conf->entity);
414 $sql .= ", ".((int) $facfourn_src->socid);
415 $sql .= ", '".$this->db->idate($now)."'";
416 $sql .= ", ".((int) $this->suspended);
417 $sql .= ", '".$this->db->escape($this->libelle)."'";
418 $sql .= ", " .(!empty($facfourn_src->total_ttc) ? (float) $facfourn_src->total_ttc : '0'); // amount
419 $sql .= ", " .((int) $user->id);
420 $sql .= ", " .(!empty($this->fk_project) ? ((int) $this->fk_project) : 'NULL');
421 $sql .= ", " .(!empty($facfourn_src->fk_account) ? ((int) $facfourn_src->fk_account) : 'NULL');
422 $sql .= ", " .($this->cond_reglement_id > 0 ? (int) $this->cond_reglement_id : 'NULL');
423 $sql .= ", " .($this->mode_reglement_id > 0 ? (int) $this->mode_reglement_id : 'NULL');
424 $sql .= ", ".($facfourn_src->date_echeance > 0 ? "'".$this->db->idate($facfourn_src->date_echeance)."'" : 'NULL'); // date_lim_reglement
425 $sql .= ", " .(!empty($this->note_private) ? "'".$this->db->escape($this->note_private)."'" : 'NULL');
426 $sql .= ", " .(!empty($this->note_public) ? "'".$this->db->escape($this->note_public)."'" : 'NULL');
427 $sql .= ", " .(!empty($this->model_pdf) ? "'".$this->db->escape($this->model_pdf)."'" : 'NULL');
428 $sql .= ", " . (int) $facfourn_src->fk_multicurrency;
429 $sql .= ", '".$this->db->escape($facfourn_src->multicurrency_code)."'";
430 $sql .= ", " . (float) $facfourn_src->multicurrency_tx;
431 $sql .= ", " . (int) $this->usenewprice;
432 $sql .= ", " . (int) $this->frequency;
433 $sql .= ", '".$this->db->escape($this->unit_frequency)."'";
434 $sql .= ", " .(!empty($this->date_when) ? "'".$this->db->idate($this->date_when)."'" : 'NULL');
435 $sql .= ", " .(!empty($this->date_last_gen) ? "'".$this->db->idate($this->date_last_gen)."'" : 'NULL');
436 $sql .= ", " . (int) $this->nb_gen_done;
437 $sql .= ", " . (int) $this->nb_gen_max;
438 $sql .= ", " . (int) $this->auto_validate;
439 $sql .= ", " . (int) $this->generate_pdf;
440 $sql .= ')';
441
442 if ($this->db->query($sql)) {
443 $this->id = $this->db->last_insert_id(MAIN_DB_PREFIX. 'facture_fourn_rec');
444
445 // Fields used into addline later
446 $this->fk_multicurrency = $facfourn_src->fk_multicurrency;
447
448 $this->multicurrency_code = $facfourn_src->multicurrency_code;
449 $this->multicurrency_tx = $facfourn_src->multicurrency_tx;
450
451 // Add lines
452 $num = count($facfourn_src->lines);
453 for ($i = 0; $i < $num; $i++) {
454 $facfourn_line = $facfourn_src->lines[$i];
455 '@phan-var-force SupplierInvoiceLine $facfourn_line';
456 if (!empty($onlylines) && !in_array($facfourn_line->id, $onlylines)) {
457 continue; // Skip unselected lines
458 }
459
460 $tva_tx = $facfourn_line->tva_tx;
461 if (!empty($facfourn_line->vat_src_code) && !preg_match('/\‍(/', (string) $tva_tx)) {
462 $tva_tx .= ' ('.$facfourn_line->vat_src_code.')';
463 }
464
465 $result_insert = $this->addline(
466 $facfourn_line->fk_product,
467 $facfourn_line->ref_supplier,
468 $facfourn_line->product_label,
469 $facfourn_line->desc ? $facfourn_line->desc : $facfourn_line->description,
470 $facfourn_line->pu_ht,
471 $facfourn_line->pu_ttc,
472 $facfourn_line->qty,
473 $facfourn_line->remise_percent,
474 $tva_tx,
475 $facfourn_line->localtax1_tx,
476 $facfourn_line->localtax2_tx,
477 'HT',
478 $facfourn_line->product_type,
479 $facfourn_line->date_start,
480 $facfourn_line->date_end,
481 $facfourn_line->info_bits,
482 $facfourn_line->special_code,
483 $facfourn_line->rang,
484 $facfourn_line->fk_unit
485 );
486
487 if ($result_insert < 0) {
488 $error++;
489 } else {
490 $objectline = new FactureFournisseurLigneRec($this->db);
491
492 $result2 = $objectline->fetch($result_insert);
493 if ($result2 > 0) {
494 // Extrafields
495 if (method_exists($facfourn_line, 'fetch_optionals')) {
496 $facfourn_line->fetch_optionals($facfourn_line->id);
497 $objectline->array_options = $facfourn_line->array_options;
498 }
499
500 $result = $objectline->insertExtraFields();
501 if ($result < 0) {
502 $error++;
503 }
504 } elseif ($result2 < 0) {
505 $this->errors[] = $objectline->error;
506 $error++;
507 }
508 }
509 }
510
511 if (!empty($this->linkedObjectsIds) && empty($this->linked_objects)) { // To use new linkedObjectsIds instead of old linked_objects
512 $this->linked_objects = $this->linkedObjectsIds; // TODO Replace linked_objects with linkedObjectsIds
513 }
514
515 // Add object linked
516 if (!$error && $this->id && !empty($this->linked_objects) && is_array($this->linked_objects)) {
517 foreach ($this->linked_objects as $origin => $tmp_origin_id) {
518 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, ...))
519 foreach ($tmp_origin_id as $origin_id) {
520 $ret = $this->add_object_linked($origin, $origin_id);
521 if (!$ret) {
522 $this->error = $this->db->lasterror();
523 $error++;
524 }
525 }
526 } else { // Old behaviour, if linked_object has only one link per type, so is something like array('contract'=>id1))
527 $origin_id = $tmp_origin_id;
528 $ret = $this->add_object_linked($origin, $origin_id);
529 if (!$ret) {
530 $this->error = $this->db->lasterror();
531 $error++;
532 }
533 }
534 }
535 }
536
537 if (!$error) {
538 $result = $this->insertExtraFields();
539 if ($result < 0) {
540 $error++;
541 }
542 }
543
544 if (!$error && !$notrigger) {
545 // Call trigger
546 $result = $this->call_trigger('SUPPLIERBILLREC_CREATE', $user);
547 if ($result < 0) {
548 $this->db->rollback();
549 return -2;
550 }
551 // End call triggers
552 }
553
554 if ($error) {
555 $this->db->rollback();
556 return -3;
557 } else {
558 $this->db->commit();
559 return $this->id;
560 }
561 } else {
562 $this->error = $this->db->lasterror();
563 $this->db->rollback();
564 return -2;
565 }
566 } else {
567 $this->db->rollback();
568 return -1;
569 }
570 }
571
572
580 public function update(User $user, $notrigger = 0)
581 {
582 $error = 0;
583
584 $sql = "UPDATE ".MAIN_DB_PREFIX."facture_fourn_rec SET";
585 $sql .= " titre = '" . (!empty($this->title) ? $this->db->escape($this->title) : "")."'," ;
586 $sql .= " subtype=".(isset($this->subtype) ? (int) $this->subtype : "NULL").",";
587 $sql .= " ref_supplier = '". (!empty($this->ref_supplier) ? $this->db->escape($this->ref_supplier) : "")."',";
588 $sql .= " entity = ". (!empty($this->entity) ? ((int) $this->entity) : 1) . ',';
589 if (!empty($this->socid) && $this->socid > 0) {
590 $sql .= " fk_soc = ". ((int) $this->socid). ',';
591 } elseif (!empty($this->fk_soc) && $this->fk_soc > 0) { // For backward compatibility
592 $sql .= " fk_soc = ". ((int) $this->fk_soc). ',';
593 }
594 $sql .= " suspended = ". (!empty($this->suspended) ? ((int) $this->suspended) : 0) . ',';
595 $sql .= " libelle = ". (!empty($this->libelle) ? "'".$this->db->escape($this->libelle)."'" : 'NULL') . ",";
596 $sql .= " vat_src_code = ". (!empty($this->vat_src_code) ? "'".$this->db->escape($this->vat_src_code)."'" : 'NULL') . ',';
597 $sql .= " localtax1 = ". (!empty($this->localtax1) ? ((float) $this->localtax1) : 0.00) . ',';
598 $sql .= " localtax2 = ". (!empty($this->localtax2) ? ((float) $this->localtax2) : 0.00) . ',';
599 $sql .= " total_ht = ". (!empty($this->total_ht) ? ((float) $this->total_ht) : 0.00) . ',';
600 $sql .= " total_tva = ". (!empty($this->total_tva) ? ((float) $this->total_tva) : 0.00) . ',';
601 $sql .= " total_ttc = ". (!empty($this->total_ttc) ? ((float) $this->total_ttc) : 0.00) . ',';
602 $sql .= " fk_user_modif = ". ((int) $user->id) . ',';
603 $sql .= " fk_projet = ". (!empty($this->fk_project) ? ((int) $this->fk_project) : 'NULL') . ',';
604 $sql .= " fk_account = ". (!empty($this->fk_account) ? ((int) $this->fk_account) : 'NULL') . ',';
605 $sql .= " fk_mode_reglement = ". (!empty($this->mode_reglement_id) ? ((int) $this->mode_reglement_id) : 'NULL') . ',';
606 $sql .= " fk_cond_reglement = ". (!empty($this->cond_reglement_id) ? ((int) $this->cond_reglement_id) : 'NULL') . ',';
607 $sql .= " date_lim_reglement = ". (!empty($this->date_lim_reglement) ? "'".$this->db->idate($this->date_lim_reglement)."'" : 'NULL') . ',';
608 $sql .= " note_private = '". (!empty($this->note_private) ? $this->db->escape($this->note_private) : '') . "',";
609 $sql .= " note_public = '". (!empty($this->note_public) ? $this->db->escape($this->note_public) : '') . "',";
610 $sql .= " modelpdf = ". (!empty($this->model_pdf) ? "'".$this->db->escape($this->model_pdf)."'" : 'NULL') . ",";
611 $sql .= " fk_multicurrency = ". (!empty($this->fk_multicurrency) ? ((int) $this->fk_multicurrency) : 'NULL') . ',';
612 $sql .= " multicurrency_code = ". (!empty($this->multicurrency_code) ? "'".$this->db->escape($this->multicurrency_code)."'" : 'NULL') . ",";
613 $sql .= " multicurrency_tx = ". (!empty($this->multicurrency_tx) ? ((float) $this->multicurrency_tx) : 1) . ',';
614 $sql .= " multicurrency_total_ht = ". (!empty($this->multicurrency_total_ht) ? ((float) $this->multicurrency_total_ht) : 0.00) . ',';
615 $sql .= " multicurrency_total_tva = ". (!empty($this->multicurrency_total_tva) ? ((float) $this->multicurrency_total_tva) : 0.00) . ',';
616 $sql .= " multicurrency_total_ttc = ". (!empty($this->multicurrency_total_ttc) ? ((float) $this->multicurrency_total_ttc) : 0.00) . ',';
617 $sql .= " usenewprice = ". (!empty($this->usenewprice) ? ((int) $this->usenewprice) : 0) . ',';
618 $sql .= " frequency = ". (!empty($this->frequency) ? ((int) $this->frequency) : 0). ',';
619 $sql .= " unit_frequency = '". (!empty($this->unit_frequency) ? $this->db->escape($this->unit_frequency) : ''). "',";
620 $sql .= " date_when = ". (!empty($this->date_when) ? "'".$this->db->idate($this->date_when)."'" : 'NULL') . ',';
621 $sql .= " date_last_gen = ". (!empty($this->date_last_gen) ? "'".$this->db->idate($this->date_last_gen)."'" : 'NULL') . ',';
622 $sql .= " nb_gen_done = ". (!empty($this->nb_gen_done) ? ((int) $this->nb_gen_done) : 0) . ',';
623 $sql .= " nb_gen_max = ". (!empty($this->nb_gen_max) ? ((int) $this->nb_gen_max) : 0) . ',';
624 $sql .= " auto_validate = ". (!empty($this->auto_validate) ? ((int) $this->auto_validate) : 0);
625 $sql .= " WHERE rowid = ". (int) $this->id;
626
627 $this->db->begin();
628
629 dol_syslog(get_class($this)."::update", LOG_DEBUG);
630 $resql = $this->db->query($sql);
631 if ($resql) {
632 if (!$error) {
633 $result = $this->insertExtraFields();
634 if ($result < 0) {
635 $error++;
636 }
637 }
638
639 if (!$error && !$notrigger) {
640 // Call trigger
641 $result = $this->call_trigger('SUPPLIERBILLREC_MODIFY', $user);
642 if ($result < 0) {
643 $this->db->rollback();
644 return -2;
645 }
646 // End call triggers
647 }
648 $this->db->commit();
649 return 1;
650 } else {
651 $this->error = $this->db->lasterror();
652 $this->db->rollback();
653 return -2;
654 }
655 }
656
665 public function fetch($rowid, $ref = '', $ref_ext = '')
666 {
667 $sql = 'SELECT f.rowid, f.titre as title, f.subtype, f.ref_supplier, f.entity, f.fk_soc';
668 $sql .= ', f.datec, f.tms, f.suspended';
669 $sql .= ', f.libelle as label';
670 $sql .= ', f.vat_src_code, f.localtax1, f.localtax2';
671 $sql .= ', f.total_tva, f.total_ht, f.total_ttc';
672 $sql .= ', f.fk_user_author, f.fk_user_modif';
673 $sql .= ', f.fk_projet as fk_project, f.fk_account';
674 $sql .= ', f.fk_mode_reglement, p.code as mode_reglement_code, p.libelle as mode_reglement_libelle';
675 $sql .= ', f.fk_cond_reglement, c.code as cond_reglement_code, c.libelle as cond_reglement_libelle, c.libelle_facture as cond_reglement_libelle_doc';
676 $sql .= ', f.date_lim_reglement';
677 $sql .= ', f.note_private, f.note_public, f.modelpdf as model_pdf';
678 $sql .= ', f.fk_multicurrency, f.multicurrency_code, f.multicurrency_tx, f.multicurrency_total_ht, f.multicurrency_total_tva, f.multicurrency_total_ttc';
679 $sql .= ', f.usenewprice, f.frequency, f.unit_frequency, f.date_when, f.date_last_gen, f.nb_gen_done, f.nb_gen_max, f.auto_validate';
680 $sql .= ', f.generate_pdf';
681 $sql .= ' FROM '.MAIN_DB_PREFIX.'facture_fourn_rec as f';
682 $sql .= ' LEFT JOIN '.MAIN_DB_PREFIX.'c_payment_term as c ON f.fk_cond_reglement = c.rowid';
683 $sql .= ' LEFT JOIN '.MAIN_DB_PREFIX.'c_paiement as p ON f.fk_mode_reglement = p.id';
684 $sql .= ' WHERE f.entity IN ('.getEntity('invoice').')';
685 if ($rowid) {
686 $sql .= ' AND f.rowid='. (int) $rowid;
687 } elseif ($ref) {
688 $sql .= " AND f.titre='".$this->db->escape($ref)."'";
689 } else {
690 $sql .= ' AND f.rowid = 0';
691 }
692
693 $result = $this->db->query($sql);
694 if ($result) {
695 if ($this->db->num_rows($result)) {
696 $obj = $this->db->fetch_object($result);
697
698 $keyforref = $this->table_ref_field;
699
700 $this->id = $obj->rowid;
701 $this->titre = $obj->title;
702 $this->title = $obj->title;
703 $this->subtype = $obj->subtype;
704 $this->ref = $obj->title;
705 $this->ref_supplier = $obj->ref_supplier;
706 $this->entity = $obj->entity;
707 $this->socid = $obj->fk_soc;
708 $this->date_creation = $obj->datec;
709 $this->date_modification = $obj->tms;
710 $this->status = $obj->suspended;
711 $this->suspended = $obj->suspended;
712 $this->libelle = $obj->label;
713 $this->label = $obj->label;
714 $this->vat_src_code = $obj->vat_src_code;
715 $this->total_localtax1 = $obj->localtax1;
716 $this->total_localtax2 = $obj->localtax2;
717 $this->total_ht = $obj->total_ht;
718 $this->total_tva = $obj->total_tva;
719 $this->total_ttc = $obj->total_ttc;
720 $this->user_creation_id = $obj->fk_user_author;
721 $this->user_modif = $obj->fk_user_modif;
722 $this->fk_project = $obj->fk_project;
723 $this->fk_account = $obj->fk_account;
724 $this->mode_reglement_id = $obj->fk_mode_reglement;
725 $this->mode_reglement_code = $obj->mode_reglement_code;
726 $this->mode_reglement = $obj->mode_reglement_libelle;
727 $this->cond_reglement_id = $obj->fk_cond_reglement;
728 $this->cond_reglement_code = $obj->cond_reglement_code;
729 $this->cond_reglement = $obj->cond_reglement_libelle;
730 $this->cond_reglement_doc = $obj->cond_reglement_libelle_doc;
731 $this->date_lim_reglement = $this->db->jdate($obj->date_lim_reglement);
732 $this->note_private = $obj->note_private;
733 $this->note_public = $obj->note_public;
734 $this->model_pdf = $obj->model_pdf;
735
736 // Multicurrency
737 $this->fk_multicurrency = $obj->fk_multicurrency;
738 $this->multicurrency_code = $obj->multicurrency_code;
739 $this->multicurrency_tx = $obj->multicurrency_tx;
740 $this->multicurrency_total_ht = $obj->multicurrency_total_ht;
741 $this->multicurrency_total_tva = $obj->multicurrency_total_tva;
742 $this->multicurrency_total_ttc = $obj->multicurrency_total_ttc;
743
744 $this->usenewprice = $obj->usenewprice;
745 $this->frequency = $obj->frequency;
746 $this->unit_frequency = $obj->unit_frequency;
747 $this->date_when = $this->db->jdate($obj->date_when);
748 $this->date_last_gen = $this->db->jdate($obj->date_last_gen);
749 $this->nb_gen_done = $obj->nb_gen_done;
750 $this->nb_gen_max = $obj->nb_gen_max;
751 $this->auto_validate = $obj->auto_validate;
752 $this->generate_pdf = $obj->generate_pdf;
753
754 // Retrieve all extrafield
755 // fetch optionals attributes and labels
756 $this->fetch_optionals();
757
758 /*
759 * Lines
760 */
761 $result = $this->fetch_lines();
762 if ($result < 0) {
763 $this->error = $this->db->lasterror();
764 return -3;
765 }
766 return 1;
767 } else {
768 $this->error = 'Bill with id '.$rowid.' or ref '.$ref.' not found';
769 dol_syslog('Facture::Fetch Error '.$this->error, LOG_ERR);
770 return -2;
771 }
772 } else {
773 $this->error = $this->db->error();
774 return -1;
775 }
776 }
777
778
784 public function getLinesArray()
785 {
786 return $this->fetch_lines();
787 }
788
789 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
795 public function fetch_lines()
796 {
797 // phpcs:enable
798 $this->lines = array();
799
800 // Retrieve all extrafield for line
801 // fetch optionals attributes and labels
802 /*if (!is_object($extrafields)) {
803 require_once DOL_DOCUMENT_ROOT.'/core/class/extrafields.class.php';
804 $extrafields = new ExtraFields($this->db);
805 }
806 $extrafields->fetch_name_optionals_label($this->table_element_line, true);
807 */
808
809 $sql = 'SELECT l.rowid,';
810 $sql .= ' l.fk_facture_fourn, l.fk_parent_line, l.fk_product, l.ref as ref_supplier, l.label, l.description as line_desc,';
811 $sql .= ' l.pu_ht, l.pu_ttc, l.qty, l.remise_percent, l.fk_remise_except, l.vat_src_code, l.tva_tx,';
812 $sql .= ' l.localtax1_tx, l.localtax2_tx, l.localtax1_type, l.localtax2_type,';
813 $sql .= ' l.total_ht, l.total_tva, l.total_ttc, total_localtax1, total_localtax2,';
814 $sql .= ' l.product_type, l.date_start, l.date_end,';
815 $sql .= ' l.info_bits, l.special_code, l.rang,';
816 $sql .= ' l.fk_unit, l.import_key, l.fk_user_author, l.fk_user_modif, l.extraparams,';
817 $sql .= ' l.fk_multicurrency, l.multicurrency_code, l.multicurrency_subprice, l.multicurrency_total_ht, l.multicurrency_total_tva, l.multicurrency_total_ttc,';
818 $sql .= ' p.ref as product_ref, p.fk_product_type as fk_product_type, p.label as product_label, p.description as product_desc';
819 $sql .= ' FROM '.MAIN_DB_PREFIX.'facture_fourn_det_rec as l';
820 $sql .= ' LEFT JOIN '.MAIN_DB_PREFIX.'product as p ON l.fk_product = p.rowid';
821 $sql .= ' WHERE l.fk_facture_fourn = '. (int) $this->id;
822 $sql .= ' ORDER BY l.rang';
823
824 dol_syslog('FactureFournisseurRec::fetch_lines', LOG_DEBUG);
825
826 $result = $this->db->query($sql);
827 if ($result) {
828 $num = $this->db->num_rows($result);
829 $i = 0;
830 while ($i < $num) {
831 $objp = $this->db->fetch_object($result);
832
833 $line = new FactureFournisseurLigneRec($this->db);
834
835 $line->id = $objp->rowid;
836 $line->fk_facture_fourn = $objp->fk_facture_fourn;
837 $line->fk_parent = $objp->fk_parent_line;
838 $line->fk_product = $objp->fk_product;
839 $line->ref = $objp->product_ref; // Ref of product
840 $line->product_ref = $objp->product_ref; // Ref of product
841 $line->product_label = $objp->product_label;
842 $line->product_desc = $objp->product_desc;
843 $line->ref_supplier = $objp->ref_supplier;
844 $line->label = $objp->label;
845 $line->description = $objp->line_desc;
846 $line->desc = $objp->line_desc;
847 $line->pu_ht = $objp->pu_ht; // deprecated
848 $line->subprice = $objp->pu_ht;
849 $line->pu_ttc = $objp->pu_ttc; // deprecated
850 $line->subprice_ttc = $objp->pu_ttc;
851 $line->qty = $objp->qty;
852 $line->remise_percent = $objp->remise_percent;
853 $line->fk_remise_except = $objp->fk_remise_except;
854 $line->vat_src_code = $objp->vat_src_code;
855 $line->tva_tx = $objp->tva_tx;
856 $line->localtax1_tx = $objp->localtax1_tx;
857 $line->localtax1_type = $objp->localtax1_type;
858 $line->localtax2_tx = $objp->localtax2_tx;
859 $line->localtax2_type = $objp->localtax2_type;
860 $line->total_ht = $objp->total_ht;
861 $line->total_tva = $objp->total_tva;
862 $line->total_localtax1 = $objp->total_localtax1;
863 $line->total_localtax2 = $objp->total_localtax2;
864 $line->total_ttc = $objp->total_ttc;
865 $line->product_type = $objp->product_type;
866 $line->date_start = $objp->date_start; // Not a SQL datetime string, but a boolean 0 or 1, jdate() would corrupt it
867 $line->date_end = $objp->date_end; // Not a SQL datetime string, but a boolean 0 or 1, jdate() would corrupt it
868 $line->info_bits = $objp->info_bits ;
869 $line->special_code = $objp->special_code;
870 $line->rang = $objp->rang;
871 $line->fk_unit = $objp->fk_unit;
872 $line->import_key = $objp->import_key;
873 $line->fk_user_author = $objp->fk_user_author;
874 $line->fk_user_modif = $objp->fk_user_modif;
875 $this->extraparams = !empty($objp->extraparams) ? (array) json_decode($objp->extraparams, true) : array();
876 $line->fk_multicurrency = $objp->fk_multicurrency;
877 $line->multicurrency_code = $objp->multicurrency_code;
878 $line->multicurrency_subprice = $objp->multicurrency_subprice;
879 $line->multicurrency_total_ht = $objp->multicurrency_total_ht;
880 $line->multicurrency_total_tva = $objp->multicurrency_total_tva;
881 $line->multicurrency_total_ttc = $objp->multicurrency_total_ttc;
882
883 $line->fetch_optionals();
884
885 $this->lines[$i] = $line;
886
887 $i++;
888 }
889
890 $this->db->free($result);
891 return 1;
892 } else {
893 $this->error = $this->db->lasterror();
894 return -3;
895 }
896 }
897
898
907 public function delete(User $user, $notrigger = 0, $idwarehouse = -1)
908 {
909 $rowid = $this->id;
910
911 dol_syslog(get_class($this)."::delete rowid=".((int) $rowid), LOG_DEBUG);
912
913 $error = 0;
914 $this->db->begin();
915
916 $sql_main_table = MAIN_DB_PREFIX.'facture_fourn_det_rec';
917 $sql_ef_table = $sql_main_table."_extrafields";
918
919 $sqlef = "DELETE FROM ".$sql_ef_table." WHERE fk_object IN (SELECT rowid FROM ".$sql_main_table." WHERE fk_facture_fourn = ". (int) $rowid .")";
920 $sql = "DELETE FROM ".MAIN_DB_PREFIX."facture_fourn_det_rec WHERE fk_facture_fourn = ". (int) $rowid;
921
922 if ($this->db->query($sqlef) && $this->db->query($sql)) {
923 $sql = "DELETE FROM ".MAIN_DB_PREFIX."facture_fourn_rec WHERE rowid = ". (int) $rowid;
924 dol_syslog($sql);
925 if ($this->db->query($sql)) {
926 // Delete linked object
927 $res = $this->deleteObjectLinked();
928 if ($res < 0) {
929 $error = -3;
930 }
931 // Delete extrafields
932 $res = $this->deleteExtraFields();
933 if ($res < 0) {
934 $error = -4;
935 }
936 } else {
937 $this->error = $this->db->lasterror();
938 $error = -1;
939 }
940 } else {
941 $this->error = $this->db->lasterror();
942 $error = -2;
943 }
944 if (!$error && !$notrigger) {
945 // Call trigger
946 $result = $this->call_trigger('SUPPLIERBILLREC_DELETE', $user);
947 if ($result < 0) {
948 $error++;
949 }
950 // End call triggers
951 }
952 if (! $error) {
953 $this->db->commit();
954 return 1;
955 } else {
956 $this->db->rollback();
957 return $error;
958 }
959 }
960
987 public function addline($fk_product, $ref, $label, $desc, $pu_ht, $pu_ttc, $qty, $remise_percent, $txtva, $txlocaltax1 = 0, $txlocaltax2 = 0, $price_base_type = 'HT', $type = 0, $date_start = 0, $date_end = 0, $info_bits = 0, $special_code = 0, $rang = -1, $fk_unit = null, $pu_ht_devise = 0)
988 {
989 global $mysoc, $user;
990
991 include_once DOL_DOCUMENT_ROOT.'/core/lib/price.lib.php';
992
993 $facid = $this->id; //Supplier invoice template ID linked to
994
995 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,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,date_end_fill=$date_end", LOG_DEBUG);
996
997 // Check if object of the line is product or service
998 if ($type < 0) {
999 return -1;
1000 }
1001
1002 $localtaxes_type = getLocalTaxesFromRate($txtva, 0, $this->thirdparty, $mysoc);
1003
1004 // Clean vat code
1005 $reg = array();
1006 $vat_src_code = '';
1007 if (preg_match('/\‍((.*)\‍)/', (string) $txtva, $reg)) {
1008 $vat_src_code = $reg[1];
1009 $txtva = preg_replace('/\s*\‍(.*\‍)/', '', (string) $txtva); // Remove code into vatrate.
1010 }
1011
1012 // Clean parameters
1013 $fk_product = empty($fk_product) ? 0 : $fk_product;
1014 $label = empty($label) ? '' : $label;
1015 $remise_percent = empty($remise_percent) ? 0 : price2num($remise_percent);
1016 $qty = price2num($qty);
1017 $pu_ht = price2num($pu_ht);
1018 $pu_ttc = price2num($pu_ttc);
1019 if (!preg_match('/\‍((.*)\‍)/', $txtva)) {
1020 $txtva = price2num($txtva); // $txtva can have format '5.0(XXX)' or '5'
1021 }
1022 $txlocaltax1 = price2num($txlocaltax1);
1023 $txlocaltax2 = price2num($txlocaltax2);
1024 $txtva = !empty($txtva) ? $txtva : 0;
1025 $txlocaltax1 = !empty($txlocaltax1) ? $txlocaltax1 : 0;
1026 $txlocaltax2 = !empty($txlocaltax2) ? $txlocaltax2 : 0;
1027 $info_bits = !empty($info_bits) ? $info_bits : 0;
1028 $info_bits = !empty($info_bits) ? $info_bits : 0;
1029
1030 $pu = ($price_base_type == 'HT' ? $pu_ht : $pu_ttc);
1031
1032 // Calculation of the gross total (TTC) and VAT for the line from qty, pu, remise_percent and txtva
1033 // VERY IMPORTANT: It's at the time of line insertion that we must store the net, VAT, and gross amounts,
1034 // and this is done at the line level, which has its own VAT rate
1035
1036 $tabprice = calcul_price_total((float) $qty, (float) $pu, $remise_percent, $txtva, $txlocaltax1, $txlocaltax2, 0, $price_base_type, $info_bits, $type, $mysoc, $localtaxes_type, 100, $this->multicurrency_tx, $pu_ht_devise);
1037 $total_ht = $tabprice[0];
1038 $total_tva = $tabprice[1];
1039 $total_ttc = $tabprice[2];
1040 $total_localtax1 = $tabprice[9];
1041 $total_localtax2 = $tabprice[10];
1042 $pu_ht = $tabprice[3];
1043
1044 // MultiCurrency
1045 $multicurrency_total_ht = $tabprice[16];
1046 $multicurrency_total_tva = $tabprice[17];
1047 $multicurrency_total_ttc = $tabprice[18];
1048 $pu_ht_devise = $tabprice[19];
1049
1050 $this->db->begin();
1051 $product_type = $type;
1052 if ($fk_product) {
1053 $product = new Product($this->db);
1054 $result = $product->fetch($fk_product);
1055 if ($result < 0) {
1056 return -1;
1057 }
1058 $product_type = $product->type;
1059 if (empty($label)) {
1060 $label = $product->label;
1061 }
1062 }
1063
1064 $sql = 'INSERT INTO ' . MAIN_DB_PREFIX . 'facture_fourn_det_rec (';
1065 $sql .= 'fk_facture_fourn';
1066 $sql .= ', fk_product';
1067 $sql .= ', ref';
1068 $sql .= ', label';
1069 $sql .= ', description';
1070 $sql .= ', pu_ht';
1071 $sql .= ', pu_ttc';
1072 $sql .= ', qty';
1073 $sql .= ', remise_percent';
1074 $sql .= ', fk_remise_except';
1075 $sql .= ', vat_src_code';
1076 $sql .= ', tva_tx';
1077 $sql .= ', localtax1_tx';
1078 $sql .= ', localtax1_type';
1079 $sql .= ', localtax2_tx';
1080 $sql .= ', localtax2_type';
1081 $sql .= ', total_ht';
1082 $sql .= ', total_tva';
1083 $sql .= ', total_localtax1';
1084 $sql .= ', total_localtax2';
1085 $sql .= ', total_ttc';
1086 $sql .= ', product_type';
1087 $sql .= ', date_start';
1088 $sql .= ', date_end';
1089 $sql .= ', info_bits';
1090 $sql .= ', special_code';
1091 $sql .= ', rang';
1092 $sql .= ', fk_unit';
1093 $sql .= ', fk_user_author';
1094 $sql .= ', fk_multicurrency, multicurrency_code, multicurrency_subprice, multicurrency_total_ht, multicurrency_total_tva, multicurrency_total_ttc';
1095 $sql .= ') VALUES (';
1096 $sql .= ' ' . (int) $facid; // source supplier invoice id
1097 $sql .= ', ' . (!empty($fk_product) ? ((int) $fk_product) : 'null');
1098 $sql .= ', ' . (!empty($ref) ? "'" . $this->db->escape($ref) . "'" : 'null');
1099 $sql .= ', ' . (!empty($label) ? "'" . $this->db->escape($label) . "'" : 'null');
1100 $sql .= ", '" . $this->db->escape($desc) . "'";
1101 $sql .= ', ' . price2num($pu_ht);
1102 $sql .= ', ' . price2num($pu_ttc);
1103 $sql .= ', ' . price2num($qty);
1104 $sql .= ', ' . price2num($remise_percent);
1105 $sql .= ', null';
1106 $sql .= ", '" . $this->db->escape($vat_src_code) . "'";
1107 $sql .= ', ' . price2num($txtva);
1108 $sql .= ', ' . price2num($txlocaltax1);
1109 $sql .= ", '" . $this->db->escape(isset($localtaxes_type[0]) ? $localtaxes_type[0] : '') . "'";
1110 $sql .= ', ' . price2num($txlocaltax2);
1111 $sql .= ", '" . $this->db->escape(isset($localtaxes_type[2]) ? $localtaxes_type[2] : '') . "'";
1112 $sql .= ', ' . price2num($total_ht);
1113 $sql .= ', ' . price2num($total_tva);
1114 $sql .= ', ' . price2num($total_localtax1);
1115 $sql .= ', ' . price2num($total_localtax2);
1116 $sql .= ', ' . price2num($total_ttc);
1117 $sql .= ', ' . (int) $product_type;
1118 $sql .= ', ' . ($date_start > 0 ? (int) $date_start : 'NULL');
1119 $sql .= ', ' . ($date_end > 0 ? (int) $date_end : 'NULL');
1120 $sql .= ', ' . (int) $info_bits;
1121 $sql .= ', ' . (int) $special_code;
1122 $sql .= ', ' . (int) $rang;
1123 $sql .= ', ' . ($fk_unit ? (int) $fk_unit : 'NULL');
1124 $sql .= ', ' . (int) $user->id;
1125 $sql .= ', ' . (int) $this->fk_multicurrency;
1126 $sql .= ", '" . $this->db->escape($this->multicurrency_code) . "'";
1127 $sql .= ', ' . price2num($pu_ht_devise, 'CU');
1128 $sql .= ', ' . price2num($multicurrency_total_ht, 'CT');
1129 $sql .= ', ' . price2num($multicurrency_total_tva, 'CT');
1130 $sql .= ', ' . price2num($multicurrency_total_ttc, 'CT');
1131 $sql .= ')';
1132
1133 dol_syslog(get_class($this). '::addline', LOG_DEBUG);
1134 if ($this->db->query($sql)) {
1135 $lineId = $this->db->last_insert_id(MAIN_DB_PREFIX. 'facture_fourn_det_rec');
1136 $this->update_price();
1137 $this->id = $facid;
1138 $this->db->commit();
1139 return $lineId;
1140 } else {
1141 $this->db->rollback();
1142 $this->error = $this->db->lasterror();
1143
1144 return -1;
1145 }
1146 }
1147
1175 public function updateline($rowid, $fk_product, $ref, $label, $desc, $pu_ht, $qty, $remise_percent, $txtva, $txlocaltax1 = 0, $txlocaltax2 = 0, $price_base_type = 'HT', $type = 0, $date_start = 0, $date_end = 0, $info_bits = 0, $special_code = 0, $rang = -1, $fk_unit = null, $pu_ht_devise = 0, $pu_ttc = 0)
1176 {
1177 global $mysoc, $user;
1178
1179 if (!$this->isLineOfObject($rowid)) {
1180 $this->error = 'ErrorLineIDDoesNotMatchWithObjectID';
1181 return -1;
1182 }
1183
1184 $facid = $this->id;
1185
1186 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, price_base_type=$price_base_type, pu_ttc=$pu_ttc, type=$type, fk_unit=$fk_unit, pu_ht_devise=$pu_ht_devise", LOG_DEBUG);
1187 include_once DOL_DOCUMENT_ROOT.'/core/lib/price.lib.php';
1188
1189 // Check parameters
1190 if ($type < 0) {
1191 return -1;
1192 }
1193
1194 // Clean parameters
1195 $fk_product = empty($fk_product) ? 0 : $fk_product;
1196 $label = empty($label) ? '' : $label;
1197 $remise_percent = empty($remise_percent) ? 0 : price2num($remise_percent);
1198 $qty = price2num($qty);
1199 $info_bits = empty($info_bits) ? 0 : $info_bits;
1200 $pu_ht = price2num($pu_ht);
1201 $pu_ttc = price2num($pu_ttc);
1202 $pu_ht_devise = price2num($pu_ht_devise);
1203
1204 if (!preg_match('/\‍((.*)\‍)/', (string) $txtva)) {
1205 $txtva = price2num($txtva); // $txtva can have format '5.0(XXX)' or '5'
1206 }
1207
1208 $txlocaltax1 = empty($txlocaltax1) ? 0 : price2num($txlocaltax1);
1209 $txlocaltax2 = empty($txlocaltax2) ? 0 : price2num($txlocaltax2);
1210 $this->multicurrency_total_ht = empty($this->multicurrency_total_ht) ? 0 : $this->multicurrency_total_ht;
1211 $this->multicurrency_total_tva = empty($this->multicurrency_total_tva) ? 0 : $this->multicurrency_total_tva;
1212 $this->multicurrency_total_ttc = empty($this->multicurrency_total_ttc) ? 0 : $this->multicurrency_total_ttc;
1213
1214 $pu = ($price_base_type == 'HT' ? $pu_ht : $pu_ttc);
1215
1216
1217 // Calculation of the gross total (TTC) and VAT for the line from qty, pu, remise_percent and txtva
1218 // VERY IMPORTANT: It's at the time of line insertion that we must store the net, VAT, and gross amounts,
1219 // and this is done at the line level, which has its own VAT rate
1220
1221 $localtaxes_type = getLocalTaxesFromRate($txtva, 0, $this->thirdparty, $mysoc);
1222
1223 // Clean vat code
1224 $vat_src_code = '';
1225 $reg = array();
1226 if (preg_match('/\‍((.*)\‍)/', $txtva, $reg)) {
1227 $vat_src_code = $reg[1];
1228 $txtva = preg_replace('/\s*\‍(.*\‍)/', '', $txtva); // Remove code into vatrate.
1229 }
1230
1231 $tabprice = calcul_price_total((float) $qty, (float) $pu, $remise_percent, $txtva, $txlocaltax1, $txlocaltax2, 0, $price_base_type, $info_bits, $type, $mysoc, $localtaxes_type, 100, $this->multicurrency_tx, (float) $pu_ht_devise);
1232
1233 $total_ht = $tabprice[0];
1234 $total_tva = $tabprice[1];
1235 $total_ttc = $tabprice[2];
1236 $total_localtax1 = $tabprice[9];
1237 $total_localtax2 = $tabprice[10];
1238 $pu_ht = $tabprice[3];
1239 $pu_tva = $tabprice[4];
1240 $pu_ttc = $tabprice[5];
1241
1242 // MultiCurrency
1243 $multicurrency_total_ht = $tabprice[16];
1244 $multicurrency_total_tva = $tabprice[17];
1245 $multicurrency_total_ttc = $tabprice[18];
1246 $pu_ht_devise = $tabprice[19];
1247
1248 $product_type = $type;
1249 if ($fk_product) {
1250 $product = new Product($this->db);
1251 $result = $product->fetch($fk_product);
1252 $product_type = $product->type;
1253 }
1254
1255 $sql = 'UPDATE ' . MAIN_DB_PREFIX . 'facture_fourn_det_rec SET';
1256 $sql .= ' fk_facture_fourn = ' . ((int) $facid);
1257 $sql .= ', fk_product = ' . ($fk_product > 0 ? ((int) $fk_product) : 'null');
1258 $sql .= ", ref = '" . $this->db->escape($ref) . "'";
1259 $sql .= ", label = '" . $this->db->escape($label) . "'";
1260 $sql .= ", description = '" . $this->db->escape($desc) . "'";
1261 $sql .= ', pu_ht = ' . price2num($pu_ht);
1262 $sql .= ', qty = ' . price2num($qty);
1263 $sql .= ", remise_percent = '" . price2num($remise_percent) . "'";
1264 $sql .= ", vat_src_code = '" . $this->db->escape($vat_src_code) . "'";
1265 $sql .= ', tva_tx = ' . price2num($txtva);
1266 $sql .= ', localtax1_tx = ' . (float) $txlocaltax1;
1267 $sql .= ", localtax1_type = '" . $this->db->escape($localtaxes_type[0]) . "'";
1268 $sql .= ', localtax2_tx = ' . (float) $txlocaltax2;
1269 $sql .= ", localtax2_type = '" . $this->db->escape($localtaxes_type[2]) . "'";
1270 $sql .= ", total_ht = '" . price2num($total_ht) . "'";
1271 $sql .= ", total_tva = '" . price2num($total_tva) . "'";
1272 $sql .= ", total_localtax1 = '" . price2num($total_localtax1) . "'";
1273 $sql .= ", total_localtax2 = '" . price2num($total_localtax2) . "'";
1274 $sql .= ", total_ttc = '" . price2num($total_ttc) . "'";
1275 $sql .= ', product_type = ' . (int) $product_type;
1276 $sql .= ', date_start = ' . (empty($date_start) ? 'NULL' : (int) $date_start);
1277 $sql .= ', date_end = ' . (empty($date_end) ? 'NULL' : (int) $date_end);
1278 $sql .= ', info_bits = ' . (int) $info_bits;
1279 $sql .= ', special_code = ' . (int) $special_code;
1280 $sql .= ', rang = ' . (int) $rang;
1281 $sql .= ', fk_unit = ' . ($fk_unit ? "'" . $this->db->escape($fk_unit) . "'" : 'null');
1282 $sql .= ', fk_user_modif = ' . (int) $user;
1283 $sql .= ', multicurrency_subprice = '.price2num($pu_ht_devise);
1284 $sql .= ', multicurrency_total_ht = '.price2num($multicurrency_total_ht);
1285 $sql .= ', multicurrency_total_tva = '.price2num($multicurrency_total_tva);
1286 $sql .= ', multicurrency_total_ttc = '.price2num($multicurrency_total_ttc);
1287 $sql .= ' WHERE rowid = ' . (int) $rowid;
1288
1289 dol_syslog(get_class($this). '::updateline', LOG_DEBUG);
1290 if ($this->db->query($sql)) {
1291 $this->id = $facid;
1292 $this->update_price();
1293 return 1;
1294 } else {
1295 $this->error = $this->db->lasterror();
1296 return -1;
1297 }
1298 }
1299
1300
1308 public function getNextNumRef($soc, $mode = 'next')
1309 {
1310 // Not used for recurring invoices
1311 return '';
1312 }
1313
1319 public function getNextDate()
1320 {
1321 if (empty($this->date_when)) {
1322 return false;
1323 }
1324 // date_when is read from database in the timezone of the server (jdate), so the delay must be added in this timezone
1325 return dol_time_plus_duree((int) $this->date_when, $this->frequency, $this->unit_frequency, 1, 'tzserver');
1326 }
1327
1333 public function isMaxNbGenReached()
1334 {
1335 $ret = false;
1336 if ($this->nb_gen_max > 0 && ($this->nb_gen_done >= $this->nb_gen_max)) {
1337 $ret = true;
1338 }
1339 return $ret;
1340 }
1341
1348 public function strikeIfMaxNbGenReached($ret)
1349 {
1350 // Special case to strike the date
1351 return ($this->isMaxNbGenReached() ? '<strike>' : '').$ret.($this->isMaxNbGenReached() ? '</strike>' : '');
1352 }
1353
1364 public function createRecurringInvoices($restrictioninvoiceid = 0, $forcevalidation = 0)
1365 {
1366 global $conf, $langs, $db, $user, $hookmanager;
1367
1368 $error = 0;
1369 $nb_create = 0;
1370
1371 // Load translation files required by the page
1372 $langs->loadLangs(array('main', 'bills'));
1373
1374 $now = dol_now();
1375 $tmparray = dol_getdate($now);
1376 $today = dol_mktime(23, 59, 59, $tmparray['mon'], $tmparray['mday'], $tmparray['year']); // Today is last second of current day
1377
1378 dol_syslog('createRecurringInvoices restrictioninvoiceid=' .$restrictioninvoiceid. ' forcevalidation=' .$forcevalidation);
1379
1380 $sql = 'SELECT rowid FROM '.MAIN_DB_PREFIX.'facture_fourn_rec';
1381 $sql .= ' WHERE frequency > 0'; // A recurring supplier invoice is an invoice with a frequency
1382 $sql .= " AND (date_when IS NULL OR date_when <= '".$this->db->idate($today)."')";
1383 $sql .= ' AND (nb_gen_done < nb_gen_max OR nb_gen_max = 0)';
1384 $sql .= ' AND suspended = 0';
1385 $sql .= ' AND entity = '. (int) $conf->entity; // MUST STAY = $conf->entity here
1386 if ($restrictioninvoiceid > 0) {
1387 $sql .= ' AND rowid = '. (int) $restrictioninvoiceid;
1388 }
1389 $sql .= $this->db->order('entity', 'ASC');
1390 if (getDolGlobalInt('NB_REC_FACT_GEN_BY_CALL')) {
1391 $sql .= $this->db->plimit(getDolGlobalInt('NB_REC_FACT_GEN_BY_CALL'));
1392 }
1393 //print $sql;exit;
1394 $parameters = array(
1395 'restrictioninvoiceid' => $restrictioninvoiceid,
1396 'forcevalidation' => $forcevalidation,
1397 );
1398 $reshook = $hookmanager->executeHooks('beforeCreationOfRecurringInvoices', $parameters, $sql); // note that $sql might be modified by hooks
1399
1400 $resql = $this->db->query($sql);
1401 if ($resql) {
1402 $i = 0;
1403 $num = $this->db->num_rows($resql);
1404
1405 if ($num) {
1406 $this->output .= $langs->trans('FoundXQualifiedRecurringInvoiceTemplate', $num)."\n";
1407 } else {
1408 $this->output .= $langs->trans('NoQualifiedRecurringInvoiceTemplateFound');
1409 }
1410
1411 $saventity = $conf->entity;
1412 $laststep = "None";
1413
1414 while ($i < $num) { // Loop on each template invoice. If $num = 0, test is false at first pass.
1415 $line = $this->db->fetch_object($resql);
1416
1417 $this->db->begin();
1418
1419 $invoiceidgenerated = 0;
1420
1421 $new_fac_fourn = null;
1422 $facturerec = new FactureFournisseurRec($this->db);
1423 $laststep = "Fetch {$line->rowid}";
1424 $facturerec->fetch($line->rowid);
1425
1426 if ($facturerec->id > 0) {
1427 // Set entity context
1428 $conf->entity = $facturerec->entity;
1429
1430 dol_syslog('createRecurringInvoices Process invoice template id=' .$facturerec->id. ', ref=' .$facturerec->ref. ', entity=' .$facturerec->entity);
1431
1432 $new_fac_fourn = new FactureFournisseur($this->db);
1433 $new_fac_fourn->fac_rec = $facturerec->id; // We will create $facture from this recurring invoice
1434 $new_fac_fourn->fk_fac_rec_source = $facturerec->id; // We will create $facture from this recurring invoice
1435
1436 $new_fac_fourn->type = self::TYPE_STANDARD;
1437 $new_fac_fourn->subtype = $facturerec->subtype;
1438 $new_fac_fourn->statut = self::STATUS_DRAFT; // deprecated
1439 $new_fac_fourn->status = self::STATUS_DRAFT;
1440 $new_fac_fourn->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.
1441 $new_fac_fourn->socid = $facturerec->socid;
1442 $new_fac_fourn->lines = $facturerec->lines;
1443 $new_fac_fourn->ref_supplier = $facturerec->ref_supplier;
1444 $new_fac_fourn->model_pdf = $facturerec->model_pdf;
1445 $new_fac_fourn->fk_project = $facturerec->fk_project;
1446 $new_fac_fourn->label = $facturerec->label;
1447 $new_fac_fourn->libelle = $facturerec->label; // deprecated
1448
1449 $invoiceidgenerated = $new_fac_fourn->create($user);
1450 $laststep = "Create invoiceidgenerated $invoiceidgenerated";
1451 if ($invoiceidgenerated <= 0) {
1452 $this->setErrorsFromObject($new_fac_fourn);
1453 $error++;
1454 }
1455 if (!$error && ($facturerec->auto_validate || $forcevalidation)) {
1456 $result = $new_fac_fourn->validate($user);
1457 $laststep = "Validate by user {$user->login}";
1458 if ($result <= 0) {
1459 $this->setErrorsFromObject($new_fac_fourn);
1460 $error++;
1461 }
1462 }
1463
1464 if (!$error && $facturerec->generate_pdf) {
1465 // We refresh the object in order to have all necessary data (like date_lim_reglement)
1466 $laststep = "Refresh ".$new_fac_fourn->id;
1467 $new_fac_fourn->fetch($new_fac_fourn->id);
1468 $laststep = "GenerateDocument ".$new_fac_fourn->id;
1469 $result = $new_fac_fourn->generateDocument($facturerec->model_pdf, $langs);
1470 if ($result < 0) {
1471 $this->setErrorsFromObject($new_fac_fourn);
1472 $error++;
1473 }
1474 }
1475 } else {
1476 $error++;
1477 $this->error = 'Failed to load invoice template with id=' .$line->rowid. ', entity=' .$conf->entity."\n";
1478 $this->errors[] = 'Failed to load invoice template with id=' .$line->rowid. ', entity=' .$conf->entity;
1479 dol_syslog('createRecurringInvoices Failed to load invoice template with id=' .$line->rowid. ', entity=' .$conf->entity);
1480 }
1481
1482 if (!$error && $invoiceidgenerated >= 0) {
1483 $facturerec->nb_gen_done++;
1484 $facturerec->date_last_gen = dol_now();
1485 $nextDate = $facturerec->getNextDate();
1486 $facturerec->date_when = (($nextDate === false) ? null : $nextDate);
1487 $facturerec->update($user);
1488 $this->db->commit('createRecurringInvoices Process invoice template id=' .$facturerec->id. ', title=' .$facturerec->title);
1489 dol_syslog('createRecurringInvoices Process invoice template ' .$facturerec->title. ' is finished with a success generation');
1490 $nb_create++;
1491 $this->output .= $langs->trans('InvoiceGeneratedFromTemplate', $new_fac_fourn->ref, $facturerec->title)."\n";
1492 } else {
1493 $this->db->rollback('createRecurringInvoices Process invoice template error='.$error.' invoiceidgenerated='.$invoiceidgenerated.' LastStep='.$laststep.' id=' .$facturerec->id. ', title=' .$facturerec->title);
1494 }
1495
1496 $parameters = array(
1497 'cpt' => $i,
1498 'total' => $num,
1499 'errorCount' => $error,
1500 'invoiceidgenerated' => $invoiceidgenerated,
1501 'facturerec' => $facturerec, // it's an object which PHP passes by "reference", so modifiable by hooks.
1502 'this' => $this, // it's an object which PHP passes by "reference", so modifiable by hooks.
1503 );
1504 // @phan-suppress-next-line PhanTypeMismatchArgumentNullable
1505 $reshook = $hookmanager->executeHooks('afterCreationOfRecurringInvoice', $parameters, $new_fac_fourn); // note: $facture can be modified by hooks (warning: $facture can be null)
1506
1507 $i++;
1508 }
1509
1510 $conf->entity = $saventity; // Restore entity context
1511 } else {
1512 dol_print_error($this->db);
1513 }
1514
1515 $this->output = trim($this->output);
1516
1517 return $error ? $error : 0;
1518 }
1519
1532 public function getNomUrl($withpicto = 0, $option = '', $max = 0, $short = 0, $moretitle = '', $notooltip = 0, $save_lastsearch_value = -1)
1533 {
1534 global $langs, $hookmanager;
1535
1536 $result = '';
1537
1538 $label = '<u>'.$langs->trans('RepeatableInvoice').'</u>';
1539 if (!empty($this->ref)) {
1540 $label .= '<br><b>'.$langs->trans('Ref').':</b> '.$this->ref;
1541 }
1542 if ($this->frequency > 0) {
1543 $label .= '<br><b>'.$langs->trans('Frequency').':</b> '.$langs->trans('FrequencyPer_'.$this->unit_frequency, $this->frequency);
1544 }
1545 if (!empty($this->date_last_gen)) {
1546 $label .= '<br><b>'.$langs->trans('DateLastGeneration').':</b> '.dol_print_date($this->date_last_gen, 'dayhour');
1547 }
1548 if ($this->frequency > 0) {
1549 if (!empty($this->date_when)) {
1550 $label .= '<br><b>'.$langs->trans('NextDateToExecution').':</b> ';
1551 $label .= (empty($this->suspended) ? '' : '<strike>').dol_print_date($this->date_when, 'day').(empty($this->suspended) ? '' : '</strike>'); // No hour for this property
1552 if (!empty($this->suspended)) {
1553 $label .= ' ('.$langs->trans('Disabled').')';
1554 }
1555 }
1556 }
1557
1558 $url = DOL_URL_ROOT.'/fourn/facture/card-rec.php?facid='.$this->id;
1559
1560 if ($short) {
1561 return $url;
1562 }
1563
1564 if ($option != 'nolink') {
1565 // Add param to save lastsearch_values or not
1566 $add_save_lastsearch_values = ($save_lastsearch_value == 1 ? 1 : 0);
1567 if ($save_lastsearch_value == -1 && preg_match('/list\.php/', $_SERVER['PHP_SELF'])) {
1568 $add_save_lastsearch_values = 1;
1569 }
1570 if ($add_save_lastsearch_values) {
1571 $url .= '&save_lastsearch_values=1';
1572 }
1573 }
1574
1575 $linkstart = '<a href="'.$url.'" title="'.dol_escape_htmltag($label, 1).'" class="classfortooltip">';
1576 $linkend = '</a>';
1577
1578 $result .= $linkstart;
1579 if ($withpicto) {
1580 $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);
1581 }
1582 if ($withpicto != 2) {
1583 $result .= $this->ref;
1584 }
1585 $result .= $linkend;
1586 global $action;
1587 $hookmanager->initHooks(array($this->element . 'dao'));
1588 $parameters = array('id' => $this->id, 'getnomurl' => &$result);
1589 $reshook = $hookmanager->executeHooks('getNomUrl', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks
1590 if ($reshook > 0) {
1591 $result = $hookmanager->resPrint;
1592 } else {
1593 $result .= $hookmanager->resPrint;
1594 }
1595 return $result;
1596 }
1597
1605 public function getLibStatut($mode = 0, $alreadypaid = -1)
1606 {
1607 return $this->LibStatut($this->frequency ? 1 : 0, $this->suspended, $mode, $alreadypaid, empty($this->type) ? 0 : $this->type);
1608 }
1609
1610 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1622 public function LibStatut($recur, $status, $mode = 0, $alreadypaid = -1, $type = 0, $nbofopendirectdebitorcredittransfer = 0)
1623 {
1624 // phpcs:enable
1625 global $langs;
1626 $langs->load('bills');
1627
1628 $labelStatus = $langs->transnoentitiesnoconv('Active');
1629 $statusType = 'status0';
1630
1631 //print "$recur,$status,$mode,$alreadypaid,$type";
1632 if ($mode == 0) {
1633 if ($recur) {
1634 if ($status == self::STATUS_SUSPENDED) {
1635 $labelStatus = $langs->transnoentitiesnoconv('Disabled');
1636 } else {
1637 $labelStatus = $langs->transnoentitiesnoconv('Active');
1638 }
1639 } else {
1640 if ($status == self::STATUS_SUSPENDED) {
1641 $labelStatus = $langs->transnoentitiesnoconv('Disabled');
1642 } else {
1643 $labelStatus = $langs->transnoentitiesnoconv('Draft');
1644 }
1645 }
1646 } elseif ($mode == 1) {
1647 $prefix = 'Short';
1648 if ($recur) {
1649 if ($status == self::STATUS_SUSPENDED) {
1650 $labelStatus = $langs->transnoentitiesnoconv('Disabled');
1651 } else {
1652 $labelStatus = $langs->transnoentitiesnoconv('Active');
1653 }
1654 } else {
1655 if ($status == self::STATUS_SUSPENDED) {
1656 $labelStatus = $langs->transnoentitiesnoconv('Disabled');
1657 } else {
1658 $labelStatus = $langs->transnoentitiesnoconv('Draft');
1659 }
1660 }
1661 } elseif ($mode == 2) {
1662 if ($recur) {
1663 if ($status == self::STATUS_SUSPENDED) {
1664 $statusType = 'status6';
1665 $labelStatus = $langs->transnoentitiesnoconv('Disabled');
1666 } else {
1667 $statusType = 'status4';
1668 $labelStatus = $langs->transnoentitiesnoconv('Active');
1669 }
1670 } else {
1671 if ($status == self::STATUS_SUSPENDED) {
1672 $statusType = 'status6';
1673 $labelStatus = $langs->transnoentitiesnoconv('Disabled');
1674 } else {
1675 $statusType = 'status0';
1676 $labelStatus = $langs->transnoentitiesnoconv('Draft');
1677 }
1678 }
1679 } elseif ($mode == 3) {
1680 if ($recur) {
1681 $prefix = 'Short';
1682 if ($status == self::STATUS_SUSPENDED) {
1683 $statusType = 'status6';
1684 $labelStatus = $langs->transnoentitiesnoconv('Disabled');
1685 } else {
1686 $statusType = 'status4';
1687 $labelStatus = $langs->transnoentitiesnoconv('Active');
1688 }
1689 } else {
1690 if ($status == self::STATUS_SUSPENDED) {
1691 $statusType = 'status6';
1692 $labelStatus = $langs->transnoentitiesnoconv('Disabled');
1693 } else {
1694 $statusType = 'status0';
1695 $labelStatus = $langs->transnoentitiesnoconv('Draft');
1696 }
1697 }
1698 } elseif ($mode == 4) {
1699 $prefix = '';
1700 if ($recur) {
1701 if ($status == self::STATUS_SUSPENDED) {
1702 $statusType = 'status6';
1703 $labelStatus = $langs->transnoentitiesnoconv('Disabled');
1704 } else {
1705 $statusType = 'status4';
1706 $labelStatus = $langs->transnoentitiesnoconv('Active');
1707 }
1708 } else {
1709 if ($status == self::STATUS_SUSPENDED) {
1710 $statusType = 'status6';
1711 $labelStatus = $langs->transnoentitiesnoconv('Disabled');
1712 } else {
1713 $statusType = 'status0';
1714 $labelStatus = $langs->transnoentitiesnoconv('Draft');
1715 }
1716 }
1717 } elseif ($mode == 5 || $mode == 6) {
1718 $prefix = '';
1719 if ($mode == 5) {
1720 $prefix = 'Short';
1721 }
1722 if ($recur) {
1723 if ($status == self::STATUS_SUSPENDED) {
1724 $statusType = 'status6';
1725 $labelStatus = $langs->transnoentitiesnoconv('Disabled');
1726 } else {
1727 $statusType = 'status4';
1728 $labelStatus = $langs->transnoentitiesnoconv('Active');
1729 }
1730 } else {
1731 if ($status == self::STATUS_SUSPENDED) {
1732 $statusType = 'status6';
1733 $labelStatus = $langs->transnoentitiesnoconv('Disabled');
1734 } else {
1735 $statusType = 'status0';
1736 $labelStatus = $langs->transnoentitiesnoconv('Draft');
1737 }
1738 }
1739 }
1740
1741 $labelStatusShort = $labelStatus;
1742
1743 return dolGetStatus($labelStatus, $labelStatusShort, '', $statusType, $mode);
1744 }
1745
1754 public function initAsSpecimen($option = '')
1755 {
1756 global $user, $langs, $conf;
1757
1758 $now = dol_now();
1759 $arraynow = dol_getdate($now);
1760 $nownotime = dol_mktime(0, 0, 0, $arraynow['mon'], $arraynow['mday'], $arraynow['year']);
1761
1762 // Load array of products prodids
1763 $num_prods = 0;
1764 $prodids = array();
1765
1766 $sql = 'SELECT rowid';
1767 $sql .= ' FROM ' .MAIN_DB_PREFIX. 'product';
1768 $sql .= ' WHERE entity IN (' .getEntity('product'). ')';
1769 $sql .= $this->db->plimit(100);
1770
1771 $resql = $this->db->query($sql);
1772 if ($resql) {
1773 $num_prods = $this->db->num_rows($resql);
1774 $i = 0;
1775 while ($i < $num_prods) {
1776 $i++;
1777 $row = $this->db->fetch_row($resql);
1778 $prodids[$i] = $row[0];
1779 }
1780 }
1781
1782 // Initialize parameters
1783 $this->id = 0;
1784 $this->ref = 'SPECIMEN';
1785 $this->title = 'SPECIMEN';
1786 $this->specimen = 1;
1787 $this->socid = 1;
1788 $this->date = $nownotime;
1789 $this->date_lim_reglement = $nownotime + 3600 * 24 * 30;
1790 $this->cond_reglement_id = 1;
1791 $this->cond_reglement_code = 'RECEP';
1792 $this->date_lim_reglement = $this->calculate_date_lim_reglement();
1793 $this->mode_reglement_id = 0; // Not forced to show payment mode CHQ + VIR
1794 $this->mode_reglement_code = ''; // Not forced to show payment mode CHQ + VIR
1795 $this->note_public = 'This is a comment (public)';
1796 $this->note_private = 'This is a comment (private)';
1797 $this->note = 'This is a comment (private)';
1798 $this->fk_incoterms = 0;
1799 $this->location_incoterms = '';
1800
1801 if (empty($option) || $option != 'nolines') {
1802 // Lines
1803 $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)
1804 $xnbp = 0;
1805 while ($xnbp < $nbp) {
1806 $line = new FactureLigne($this->db);
1807 $line->desc = $langs->trans('Description'). ' ' .$xnbp;
1808 $line->qty = 1;
1809 $line->subprice = 100;
1810 $line->tva_tx = 19.6;
1811 $line->localtax1_tx = 0;
1812 $line->localtax2_tx = 0;
1813 $line->remise_percent = 0;
1814 if ($xnbp == 1) { // Qty is negative (product line)
1815 $prodid = mt_rand(1, $num_prods);
1816 $line->fk_product = $prodids[$prodid];
1817 $line->qty = -1;
1818 $line->total_ht = -100;
1819 $line->total_ttc = -119.6;
1820 $line->total_tva = -19.6;
1821 } elseif ($xnbp == 2) { // UP is negative (free line)
1822 $line->subprice = -100;
1823 $line->total_ht = -100;
1824 $line->total_ttc = -119.6;
1825 $line->total_tva = -19.6;
1826 $line->remise_percent = 0;
1827 } elseif ($xnbp == 3) { // Discount is 50% (product line)
1828 $prodid = mt_rand(1, $num_prods);
1829 $line->fk_product = $prodids[$prodid];
1830 $line->total_ht = 50;
1831 $line->total_ttc = 59.8;
1832 $line->total_tva = 9.8;
1833 $line->remise_percent = 50;
1834 } else { // (product line)
1835 $prodid = mt_rand(1, $num_prods);
1836 $line->fk_product = $prodids[$prodid];
1837 $line->total_ht = 100;
1838 $line->total_ttc = 119.6;
1839 $line->total_tva = 19.6;
1840 $line->remise_percent = 00;
1841 }
1842
1843 $this->lines[$xnbp] = $line;
1844 $xnbp++;
1845
1846 $this->total_ht += $line->total_ht;
1847 $this->total_tva += $line->total_tva;
1848 $this->total_ttc += $line->total_ttc;
1849 }
1850 $this->revenuestamp = 0;
1851
1852 // Add a line "offered"
1853 $line = new FactureLigne($this->db);
1854 $line->desc = $langs->trans('Description'). ' (offered line)';
1855 $line->qty = 1;
1856 $line->subprice = 100;
1857 $line->tva_tx = 19.6;
1858 $line->localtax1_tx = 0;
1859 $line->localtax2_tx = 0;
1860 $line->remise_percent = 100;
1861 $line->total_ht = 0;
1862 $line->total_ttc = 0; // 90 * 1.196
1863 $line->total_tva = 0;
1864 $prodid = mt_rand(1, $num_prods);
1865 $line->fk_product = $prodids[$prodid];
1866
1867 $this->lines[$xnbp] = $line;
1868 $xnbp++;
1869 }
1870
1871 $this->usenewprice = 0;
1872
1873 return 1;
1874 }
1875
1884 public static function replaceThirdparty(DoliDB $dbs, $origin_id, $dest_id)
1885 {
1886 $tables = array(
1887 'facture_fourn_rec'
1888 );
1889
1890 return CommonObject::commonReplaceThirdparty($dbs, $origin_id, $dest_id, $tables);
1891 }
1892
1900 public function setFrequencyAndUnit($frequency, $unit)
1901 {
1902 if (!$this->table_element) {
1903 dol_syslog(get_class($this). '::setFrequencyAndUnit was called on object with property table_element not defined', LOG_ERR);
1904 return -1;
1905 }
1906
1907 if (!empty($frequency) && empty($unit)) {
1908 dol_syslog(get_class($this). '::setFrequencyAndUnit was called on object with params frequency defined but unit not defined', LOG_ERR);
1909 return -2;
1910 }
1911
1912 $sql = "UPDATE ".MAIN_DB_PREFIX.$this->table_element;
1913 $sql .= " SET frequency = ".($frequency ? ((int) $frequency) : "NULL");
1914 if (!empty($unit)) {
1915 $sql .= ", unit_frequency = '".$this->db->escape($unit)."'";
1916 }
1917 $sql .= " WHERE rowid = ".((int) $this->id);
1918
1919 dol_syslog(get_class($this).'::setFrequencyAndUnit', LOG_DEBUG);
1920
1921 if ($this->db->query($sql)) {
1922 $this->frequency = $frequency;
1923 if (!empty($unit)) {
1924 $this->unit_frequency = $unit;
1925 }
1926 return 1;
1927 } else {
1928 $this->error = $this->db->lasterror();
1929 return -1;
1930 }
1931 }
1932
1940 public function setNextDate($date, $increment_nb_gen_done = 0)
1941 {
1942 if (!$this->table_element) {
1943 dol_syslog(get_class($this).'::setNextDate was called on object with property table_element not defined', LOG_ERR);
1944 return -1;
1945 }
1946 $sql = "UPDATE ".MAIN_DB_PREFIX.$this->table_element;
1947 $sql .= " SET date_when = " .($date ? "'".$this->db->idate($date)."'" : "NULL");
1948 if ($increment_nb_gen_done > 0) {
1949 $sql .= ", nb_gen_done = nb_gen_done + 1";
1950 }
1951 $sql .= " WHERE rowid = " . (int) $this->id;
1952
1953 dol_syslog(get_class($this).'::setNextDate', LOG_DEBUG);
1954
1955 if ($this->db->query($sql)) {
1956 $this->date_when = $date;
1957 if ($increment_nb_gen_done > 0) {
1958 $this->nb_gen_done++;
1959 }
1960 return 1;
1961 } else {
1962 $this->error = $this->db->lasterror();
1963 return -1;
1964 }
1965 }
1966
1973 public function setMaxPeriod($nb)
1974 {
1975 if (!$this->table_element) {
1976 dol_syslog(get_class($this).'::setMaxPeriod was called on object with property table_element not defined', LOG_ERR);
1977 return -1;
1978 }
1979
1980 if (empty($nb)) {
1981 $nb = 0;
1982 }
1983
1984 $sql = "UPDATE ".MAIN_DB_PREFIX.$this->table_element;
1985 $sql .= " SET nb_gen_max = ". (int) $nb;
1986 $sql .= " WHERE rowid = " . (int) $this->id;
1987
1988 dol_syslog(get_class($this).'::setMaxPeriod', LOG_DEBUG);
1989
1990 if ($this->db->query($sql)) {
1991 $this->nb_gen_max = $nb;
1992 return 1;
1993 } else {
1994 dol_print_error($this->db);
1995 return -1;
1996 }
1997 }
1998
2005 public function setAutoValidate($validate)
2006 {
2007 if (!$this->table_element) {
2008 dol_syslog(get_class($this).'::setAutoValidate was called on object with property table_element not defined', LOG_ERR);
2009 return -1;
2010 }
2011
2012 $sql = "UPDATE ".MAIN_DB_PREFIX.$this->table_element;
2013 $sql .= " SET auto_validate = ".((int) $validate);
2014 $sql .= " WHERE rowid = " . (int) $this->id;
2015
2016 dol_syslog(get_class($this).'::setAutoValidate', LOG_DEBUG);
2017
2018 if ($this->db->query($sql)) {
2019 $this->auto_validate = $validate;
2020 return 1;
2021 } else {
2022 dol_print_error($this->db);
2023 return -1;
2024 }
2025 }
2026
2033 public function setGeneratePdf($validate)
2034 {
2035 if (!$this->table_element) {
2036 dol_syslog(get_class($this).'::setGeneratePdf was called on object with property table_element not defined', LOG_ERR);
2037 return -1;
2038 }
2039
2040 $sql = "UPDATE ".MAIN_DB_PREFIX.$this->table_element;
2041 $sql .= " SET generate_pdf = ". (int) $validate;
2042 $sql .= " WHERE rowid = " . (int) $this->id;
2043
2044 dol_syslog(get_class($this).'::setGeneratePdf', LOG_DEBUG);
2045
2046 if ($this->db->query($sql)) {
2047 $this->generate_pdf = $validate;
2048 return 1;
2049 } else {
2050 dol_print_error($this->db);
2051 return -1;
2052 }
2053 }
2054
2061 public function setModelPdf($model)
2062 {
2063 if (!$this->table_element) {
2064 dol_syslog(get_class($this).'::setModelPdf was called on object with property table_element not defined', LOG_ERR);
2065 return -1;
2066 }
2067
2068 $sql = "UPDATE ".MAIN_DB_PREFIX.$this->table_element;
2069 $sql .= " SET modelpdf = '".$this->db->escape($model)."'";
2070 $sql .= " WHERE rowid = " . (int) $this->id;
2071
2072 dol_syslog(get_class($this).'::setModelPdf', LOG_DEBUG);
2073
2074 if ($this->db->query($sql)) {
2075 $this->model_pdf = $model;
2076 return 1;
2077 } else {
2078 dol_print_error($this->db);
2079 return -1;
2080 }
2081 }
2082}
$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.
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.
insertExtraFields($trigger='', $userused=null)
Add/Update all extra fields values for the current object.
Class to manage Dolibarr database access.
Class to manage suppliers invoices.
Class to manage supplier invoice lines of templates.
Class to manage invoice templates.
setModelPdf($model)
Update the model for documents.
fetch($rowid, $ref='', $ref_ext='')
Load object and lines.
strikeIfMaxNbGenReached($ret)
Format string to output with by striking the string if max number of generation was reached.
setFrequencyAndUnit($frequency, $unit)
Update frequency and unit.
getNextNumRef($soc, $mode='next')
Return next reference of invoice not already used (or last reference)
setGeneratePdf($validate)
Update the auto generate documents.
getLinesArray()
Create an array of invoice lines.
initAsSpecimen($option='')
Initialise an instance with random values.
updateline($rowid, $fk_product, $ref, $label, $desc, $pu_ht, $qty, $remise_percent, $txtva, $txlocaltax1=0, $txlocaltax2=0, $price_base_type='HT', $type=0, $date_start=0, $date_end=0, $info_bits=0, $special_code=0, $rang=-1, $fk_unit=null, $pu_ht_devise=0, $pu_ttc=0)
Update a line to supplier invoice template.
isMaxNbGenReached()
Return if maximum number of generation is reached.
LibStatut($recur, $status, $mode=0, $alreadypaid=-1, $type=0, $nbofopendirectdebitorcredittransfer=0)
Return label of a status.
setAutoValidate($validate)
Update the auto validate flag of invoice.
static replaceThirdparty(DoliDB $dbs, $origin_id, $dest_id)
Function used to replace a thirdparty id with another one.
getNextDate()
Return the next date of.
fetch_lines()
Get lines of template invoices into this->lines.
getLibStatut($mode=0, $alreadypaid=-1)
Return label of object status.
setNextDate($date, $increment_nb_gen_done=0)
Update the next date of execution.
setMaxPeriod($nb)
Update the maximum period.
createRecurringInvoices($restrictioninvoiceid=0, $forcevalidation=0)
Create all recurrents supplier invoices (for all entities if multicompany is used).
update(User $user, $notrigger=0)
Update fourn_invoice_rec.
addline($fk_product, $ref, $label, $desc, $pu_ht, $pu_ttc, $qty, $remise_percent, $txtva, $txlocaltax1=0, $txlocaltax2=0, $price_base_type='HT', $type=0, $date_start=0, $date_end=0, $info_bits=0, $special_code=0, $rang=-1, $fk_unit=null, $pu_ht_devise=0)
Add a line to recursive supplier invoice.
getNomUrl($withpicto=0, $option='', $max=0, $short=0, $moretitle='', $notooltip=0, $save_lastsearch_value=-1)
Return clickable name (with picto eventually)
create($user, $facFournId, $notrigger=0, $onlylines=array())
Create a predefined supplier invoice.
Class to manage invoice lines.
Class to manage products or services.
Class to manage Dolibarr users.
print $langs trans("Ref").' m titre as m m statut as status
Or an array listing all the potential status of the object: array: int of the status => translated la...
Definition index.php:169
global $mysoc
dol_time_plus_duree($time, $duration_value, $duration_unit, $ruleforendofmonth=0, $tz='')
Add a delay to a date.
Definition date.lib.php:129
if(!isModEnabled('ai')||!getDolGlobalString('AI_ASSISTANT_ENABLED')) global $conf
The main.inc.php has been included so the following variable are now defined:
$date_start
Variables from include:
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...
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)
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.
GETPOSTINT($paramname, $method=0, $nodefault=0)
Return the value of a $_GET or $_POST supervariable, converted into integer.
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_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...
calcul_price_total($qty, $pu, $remise_percent_ligne, $txtva, $uselocaltax1_rate, $uselocaltax2_rate, $notused, $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
print $langs trans('Date')." left Ref 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 Paid right PaymentTypeShortLIQ right SELECT p pos_change as p datep as date
Definition receipt.php:492
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:137