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