dolibarr 21.0.4
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-2024 Frédéric France <frederic.france@free.fr>
10 * Copyright (C) 2024 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{
45 const TRIGGER_PREFIX = 'SUPPLIERBILLREC';
49 public $element = 'invoice_supplier_rec';
50
54 public $table_element = 'facture_fourn_rec';
55
59 public $table_element_line = 'facture_fourn_det_rec';
60
64 public $fk_element = 'fk_facture_fourn';
65
69 public $picto = 'bill';
70
74 protected $table_ref_field = 'titre';
75
80 public $titre;
84 public $title;
85
90 public $ref_supplier;
94 public $socid;
95
100 public $fk_soc;
101
105 public $suspended; // status
106
111 public $libelle;
115 public $label;
116
121 public $amount;
126 public $remise;
127
131 public $vat_src_code;
135 public $localtax1;
139 public $localtax2;
140
144 public $user_author;
148 public $user_modif;
152 public $fk_project;
153
157 public $mode_reglement_id;
161 public $mode_reglement_code;
165 public $cond_reglement_code;
169 public $cond_reglement_doc;
173 public $cond_reglement_id;
174
178 public $date_lim_reglement;
179
183 public $usenewprice = 0;
187 public $frequency;
191 public $unit_frequency;
195 public $date_when;
199 public $date_last_gen;
200
204 public $nb_gen_done;
205
209 public $nb_gen_max;
210
214 public $auto_validate; //
218 public $generate_pdf; // 1 to generate PDF on invoice generation (default)
219
224 public $lines = array();
225
226
227 /* Override fields in CommonObject
228 public $entity;
229 public $total_ht;
230 public $total_tva;
231 public $total_ttc;
232 public $fk_account;
233 public $mode_reglement;
234 public $cond_reglement;
235 public $note_public;
236 public $note_private;
237 */
238
263 // BEGIN MODULEBUILDER PROPERTIES
267 public $fields = array(
268 'rowid' => array('type' => 'integer', 'label' => 'TechnicalID', 'enabled' => 1, 'visible' => -1, 'notnull' => 1, 'position' => 10),
269 'titre' => array('type' => 'varchar(100)', 'label' => 'Titre', 'enabled' => 1, 'showoncombobox' => 1, 'visible' => -1, 'position' => 15),
270 'ref_supplier' => array('type' => 'varchar(180)', 'label' => 'RefSupplier', 'enabled' => 1, 'showoncombobox' => 1, 'visible' => -1, 'position' => 20),
271 'entity' => array('type' => 'integer', 'label' => 'Entity', 'default' => '1', 'enabled' => 1, 'visible' => -2, 'notnull' => 1, 'position' => 25, 'index' => 1),
272 'fk_soc' => array('type' => 'integer:Societe:societe/class/societe.class.php', 'label' => 'ThirdParty', 'enabled' => 'isModEnabled("societe")', 'visible' => -1, 'notnull' => 1, 'position' => 30),
273 'datec' => array('type' => 'datetime', 'label' => 'DateCreation', 'enabled' => 1, 'visible' => -1, 'position' => 35),
274 'tms' => array('type' => 'timestamp', 'label' => 'DateModification', 'enabled' => 1, 'visible' => -1, 'notnull' => 1, 'position' => 40),
275 'suspended' => array('type' => 'integer', 'label' => 'Suspended', 'enabled' => 1, 'visible' => -1, 'position' => 225),
276 'libelle' => array('type' => 'varchar(100)', 'label' => 'Libelle', 'enabled' => 1, 'showoncombobox' => 0, 'visible' => -1, 'position' => 15),
277
278 'localtax1' => array('type' => 'double(24,8)', 'label' => 'Localtax1', 'enabled' => 1, 'visible' => -1, 'position' => 60, 'isameasure' => 1),
279 'localtax2' => array('type' => 'double(24,8)', 'label' => 'Localtax2', 'enabled' => 1, 'visible' => -1, 'position' => 65, 'isameasure' => 1),
280 'total_ht' => array('type' => 'double(24,8)', 'label' => 'Total', 'enabled' => 1, 'visible' => -1, 'position' => 70, 'isameasure' => 1),
281 'total_tva' => array('type' => 'double(24,8)', 'label' => 'Tva', 'enabled' => 1, 'visible' => -1, 'position' => 55, 'isameasure' => 1),
282 'total_ttc' => array('type' => 'double(24,8)', 'label' => 'Total ttc', 'enabled' => 1, 'visible' => -1, 'position' => 75, 'isameasure' => 1),
283
284 'fk_user_author' => array('type' => 'integer:User:user/class/user.class.php', 'label' => 'Fk user author', 'enabled' => 1, 'visible' => -1, 'position' => 80),
285 'fk_user_modif' => array('type' => 'integer:User:user/class/user.class.php', 'label' => 'UserModif', 'enabled' => 1, 'visible' => -2, 'notnull' => -1, 'position' => 210),
286 '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),
287 'fk_account' => array('type' => 'integer', 'label' => 'Fk account', 'enabled' => 'isModEnabled("bank")', 'visible' => -1, 'position' => 175),
288 'fk_cond_reglement' => array('type' => 'integer', 'label' => 'Fk cond reglement', 'enabled' => 1, 'visible' => -1, 'position' => 90),
289 'fk_mode_reglement' => array('type' => 'integer', 'label' => 'Fk mode reglement', 'enabled' => 1, 'visible' => -1, 'position' => 95),
290 'date_lim_reglement' => array('type' => 'date', 'label' => 'Date lim reglement', 'enabled' => 1, 'visible' => -1, 'position' => 100),
291
292 'note_private' => array('type' => 'html', 'label' => 'NotePublic', 'enabled' => 1, 'visible' => 0, 'position' => 105),
293 'note_public' => array('type' => 'html', 'label' => 'NotePrivate', 'enabled' => 1, 'visible' => 0, 'position' => 110),
294 'modelpdf' => array('type' => 'varchar(255)', 'label' => 'Modelpdf', 'enabled' => 1, 'visible' => -1, 'position' => 115),
295
296 'fk_multicurrency' => array('type' => 'integer', 'label' => 'Fk multicurrency', 'enabled' => 1, 'visible' => -1, 'position' => 180),
297 'multicurrency_code' => array('type' => 'varchar(255)', 'label' => 'Multicurrency code', 'enabled' => 1, 'visible' => -1, 'position' => 185),
298 'multicurrency_tx' => array('type' => 'double(24,8)', 'label' => 'Multicurrency tx', 'enabled' => 1, 'visible' => -1, 'position' => 190, 'isameasure' => 1),
299 'multicurrency_total_ht' => array('type' => 'double(24,8)', 'label' => 'Multicurrency total ht', 'enabled' => 1, 'visible' => -1, 'position' => 195, 'isameasure' => 1),
300 'multicurrency_total_tva' => array('type' => 'double(24,8)', 'label' => 'Multicurrency total tva', 'enabled' => 1, 'visible' => -1, 'position' => 200, 'isameasure' => 1),
301 'multicurrency_total_ttc' => array('type' => 'double(24,8)', 'label' => 'Multicurrency total ttc', 'enabled' => 1, 'visible' => -1, 'position' => 205, 'isameasure' => 1),
302
303 'usenewprice' => array('type' => 'integer', 'label' => 'UseNewPrice', 'enabled' => 1, 'visible' => 0, 'position' => 155),
304 'frequency' => array('type' => 'integer', 'label' => 'Frequency', 'enabled' => 1, 'visible' => -1, 'position' => 150),
305 'unit_frequency' => array('type' => 'varchar(2)', 'label' => 'Unit frequency', 'enabled' => 1, 'visible' => -1, 'position' => 125),
306
307 'date_when' => array('type' => 'datetime', 'label' => 'Date when', 'enabled' => 1, 'visible' => -1, 'position' => 130),
308 'date_last_gen' => array('type' => 'datetime', 'label' => 'Date last gen', 'enabled' => 1, 'visible' => -1, 'position' => 135),
309 'nb_gen_done' => array('type' => 'integer', 'label' => 'Nb gen done', 'enabled' => 1, 'visible' => -1, 'position' => 140),
310 'nb_gen_max' => array('type' => 'integer', 'label' => 'Nb gen max', 'enabled' => 1, 'visible' => -1, 'position' => 145),
311 'revenuestamp' => array('type' => 'double(24,8)', 'label' => 'RevenueStamp', 'enabled' => 1, 'visible' => -1, 'position' => 160, 'isameasure' => 1),
312 'auto_validate' => array('type' => 'integer', 'label' => 'Auto validate', 'enabled' => 1, 'visible' => -1, 'position' => 165),
313 'generate_pdf' => array('type' => 'integer', 'label' => 'Generate pdf', 'enabled' => 1, 'visible' => -1, 'position' => 170),
314 );
315 // END MODULEBUILDER PROPERTIES
316
317 const STATUS_NOTSUSPENDED = 0;
318 const STATUS_SUSPENDED = 1;
319
320
321
327 public function __construct($db)
328 {
329 $this->db = $db;
330 }
331
340 public function create($user, $facFournId, $notrigger = 0)
341 {
342 global $conf;
343
344 $error = 0;
345 $now = dol_now();
346
347 // Clean parameters
348 $this->titre = empty($this->titre) ? '' : $this->titre; // deprecated
349 $this->title = empty($this->title) ? '' : $this->title;
350 $keyforref = $this->table_ref_field;
351 $this->ref = $this->$keyforref;
352 $this->ref_supplier = empty($this->ref_supplier) ? '' : $this->ref_supplier;
353 $this->usenewprice = empty($this->usenewprice) ? 0 : $this->usenewprice;
354 $this->suspended = empty($this->suspended) ? 0 : $this->suspended;
355 // No frequency defined then no next date to execution
356 if (empty($this->frequency)) {
357 $this->frequency = 0;
358 $this->date_when = null;
359 }
360 $this->frequency = abs($this->frequency);
361 $this->nb_gen_done = 0;
362 $this->nb_gen_max = empty($this->nb_gen_max) ? 0 : $this->nb_gen_max;
363 $this->auto_validate = empty($this->auto_validate) ? 0 : $this->auto_validate;
364 $this->generate_pdf = empty($this->generate_pdf) ? 0 : $this->generate_pdf;
365
366 $this->db->begin();
367
368 // On charge la facture fournisseur depuis laquelle on crée la facture fournisseur modèle
369 $facfourn_src = new FactureFournisseur($this->db);
370 $result = $facfourn_src->fetch($facFournId);
371 if ($result > 0) {
372 $sql = 'INSERT INTO '.MAIN_DB_PREFIX.'facture_fourn_rec (';
373 $sql .= 'titre';
374 $sql .= ", subtype";
375 $sql .= ', ref_supplier';
376 $sql .= ', entity';
377 $sql .= ', fk_soc';
378 $sql .= ', datec';
379 $sql .= ', suspended';
380 $sql .= ', libelle';
381 $sql .= ', total_ttc';
382 $sql .= ', fk_user_author';
383 $sql .= ', fk_projet';
384 $sql .= ', fk_account';
385 $sql .= ', fk_cond_reglement';
386 $sql .= ', fk_mode_reglement';
387 $sql .= ', date_lim_reglement';
388 $sql .= ', note_private';
389 $sql .= ', note_public';
390 $sql .= ', modelpdf';
391 $sql .= ', fk_multicurrency';
392 $sql .= ', multicurrency_code';
393 $sql .= ', multicurrency_tx';
394 $sql .= ', usenewprice';
395 $sql .= ', frequency';
396 $sql .= ', unit_frequency';
397 $sql .= ', date_when';
398 $sql .= ', date_last_gen';
399 $sql .= ', nb_gen_done';
400 $sql .= ', nb_gen_max';
401 $sql .= ', auto_validate';
402 $sql .= ', generate_pdf';
403 $sql .= ') VALUES (';
404 $sql .= "'".$this->db->escape($this->title)."'";
405 $sql .= ", ".($this->subtype ? "'".$this->db->escape($this->subtype)."'" : "null");
406 $sql .= ", '".$this->db->escape($this->ref_supplier)."'";
407 $sql .= ", ".((int) $conf->entity);
408 $sql .= ", ".((int) $facfourn_src->socid);
409 $sql .= ", '".$this->db->idate($now)."'";
410 $sql .= ", ".((int) $this->suspended);
411 $sql .= ", '".$this->db->escape($this->libelle)."'";
412 $sql .= ", " .(!empty($facfourn_src->total_ttc) ? (float) $facfourn_src->total_ttc : '0'); // amount
413 $sql .= ", " .((int) $user->id);
414 $sql .= ", " .(!empty($this->fk_project) ? ((int) $this->fk_project) : 'NULL');
415 $sql .= ", " .(!empty($facfourn_src->fk_account) ? ((int) $facfourn_src->fk_account) : 'NULL');
416 $sql .= ", " .($this->cond_reglement_id > 0 ? (int) $this->cond_reglement_id : 'NULL');
417 $sql .= ", " .($this->mode_reglement_id > 0 ? (int) $this->mode_reglement_id : 'NULL');
418 $sql .= ", ".($facfourn_src->date_echeance > 0 ? "'".$this->db->idate($facfourn_src->date_echeance)."'" : 'NULL'); // date_lim_reglement
419 $sql .= ", " .(!empty($this->note_private) ? "'".$this->db->escape($this->note_private)."'" : 'NULL');
420 $sql .= ", " .(!empty($this->note_public) ? "'".$this->db->escape($this->note_public)."'" : 'NULL');
421 $sql .= ", " .(!empty($this->model_pdf) ? "'".$this->db->escape($this->model_pdf)."'" : 'NULL');
422 $sql .= ", " . (int) $facfourn_src->fk_multicurrency;
423 $sql .= ", '".$this->db->escape($facfourn_src->multicurrency_code)."'";
424 $sql .= ", " . (float) $facfourn_src->multicurrency_tx;
425 $sql .= ", " . (int) $this->usenewprice;
426 $sql .= ", " . (int) $this->frequency;
427 $sql .= ", '".$this->db->escape($this->unit_frequency)."'";
428 $sql .= ", " .(!empty($this->date_when) ? "'".$this->db->idate($this->date_when)."'" : 'NULL');
429 $sql .= ", " .(!empty($this->date_last_gen) ? "'".$this->db->idate($this->date_last_gen)."'" : 'NULL');
430 $sql .= ", " . (int) $this->nb_gen_done;
431 $sql .= ", " . (int) $this->nb_gen_max;
432 $sql .= ", " . (int) $this->auto_validate;
433 $sql .= ", " . (int) $this->generate_pdf;
434 $sql .= ')';
435
436 if ($this->db->query($sql)) {
437 $this->id = $this->db->last_insert_id(MAIN_DB_PREFIX. 'facture_fourn_rec');
438
439 // Fields used into addline later
440 $this->fk_multicurrency = $facfourn_src->fk_multicurrency;
441
442 $this->multicurrency_code = $facfourn_src->multicurrency_code;
443 $this->multicurrency_tx = $facfourn_src->multicurrency_tx;
444
445 // Add lines
446 $num = count($facfourn_src->lines);
447 for ($i = 0; $i < $num; $i++) {
448 $facfourn_line = $facfourn_src->lines[$i];
449 '@phan-var-force SupplierInvoiceLine $facfourn_line';
450
451 $tva_tx = $facfourn_line->tva_tx;
452 if (!empty($facfourn_line->vat_src_code) && !preg_match('/\‍(/', (string) $tva_tx)) {
453 $tva_tx .= ' ('.$facfourn_line->vat_src_code.')';
454 }
455
456 $result_insert = $this->addline(
457 $facfourn_line->fk_product,
458 $facfourn_line->ref_supplier,
459 $facfourn_line->product_label,
460 $facfourn_line->desc ? $facfourn_line->desc : $facfourn_line->description,
461 $facfourn_line->pu_ht,
462 $facfourn_line->pu_ttc,
463 $facfourn_line->qty,
464 $facfourn_line->remise_percent,
465 $tva_tx,
466 $facfourn_line->localtax1_tx,
467 $facfourn_line->localtax2_tx,
468 'HT',
469 $facfourn_line->product_type,
470 $facfourn_line->date_start,
471 $facfourn_line->date_end,
472 $facfourn_line->info_bits,
473 $facfourn_line->special_code,
474 $facfourn_line->rang,
475 $facfourn_line->fk_unit
476 );
477
478 if ($result_insert < 0) {
479 $error++;
480 } else {
481 $objectline = new FactureFournisseurLigneRec($this->db);
482
483 $result2 = $objectline->fetch($result_insert);
484 if ($result2 > 0) {
485 // Extrafields
486 if (method_exists($facfourn_line, 'fetch_optionals')) {
487 $facfourn_line->fetch_optionals($facfourn_line->id);
488 $objectline->array_options = $facfourn_line->array_options;
489 }
490
491 $result = $objectline->insertExtraFields();
492 if ($result < 0) {
493 $error++;
494 }
495 } elseif ($result2 < 0) {
496 $this->errors[] = $objectline->error;
497 $error++;
498 }
499 }
500 }
501
502 if (!empty($this->linkedObjectsIds) && empty($this->linked_objects)) { // To use new linkedObjectsIds instead of old linked_objects
503 $this->linked_objects = $this->linkedObjectsIds; // TODO Replace linked_objects with linkedObjectsIds
504 }
505
506 // Add object linked
507 if (!$error && $this->id && !empty($this->linked_objects) && is_array($this->linked_objects)) {
508 foreach ($this->linked_objects as $origin => $tmp_origin_id) {
509 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, ...))
510 foreach ($tmp_origin_id as $origin_id) {
511 $ret = $this->add_object_linked($origin, $origin_id);
512 if (!$ret) {
513 $this->error = $this->db->lasterror();
514 $error++;
515 }
516 }
517 } else { // Old behaviour, if linked_object has only one link per type, so is something like array('contract'=>id1))
518 $origin_id = $tmp_origin_id;
519 $ret = $this->add_object_linked($origin, $origin_id);
520 if (!$ret) {
521 $this->error = $this->db->lasterror();
522 $error++;
523 }
524 }
525 }
526 }
527
528 if (!$error) {
529 $result = $this->insertExtraFields();
530 if ($result < 0) {
531 $error++;
532 }
533 }
534
535 if (!$error && !$notrigger) {
536 // Call trigger
537 $result = $this->call_trigger('SUPPLIERBILLREC_CREATE', $user);
538 if ($result < 0) {
539 $this->db->rollback();
540 return -2;
541 }
542 // End call triggers
543 }
544
545 if ($error) {
546 $this->db->rollback();
547 return -3;
548 } else {
549 $this->db->commit();
550 return $this->id;
551 }
552 } else {
553 $this->error = $this->db->lasterror();
554 $this->db->rollback();
555 return -2;
556 }
557 } else {
558 $this->db->rollback();
559 return -1;
560 }
561 }
562
563
571 public function update(User $user, $notrigger = 0)
572 {
573 $error = 0;
574
575 $sql = "UPDATE ".MAIN_DB_PREFIX."facture_fourn_rec SET";
576 $sql .= " titre = '" . (!empty($this->title) ? $this->db->escape($this->title) : "")."'," ;
577 $sql .= " subtype=".(isset($this->subtype) ? $this->db->escape($this->subtype) : "null").",";
578 $sql .= " ref_supplier = '". (!empty($this->ref_supplier) ? $this->db->escape($this->ref_supplier) : "")."',";
579 $sql .= " entity = ". (!empty($this->entity) ? ((int) $this->entity) : 1) . ',';
580 if (!empty($this->socid) && $this->socid > 0) {
581 $sql .= " fk_soc = ". ((int) $this->socid). ',';
582 } elseif (!empty($this->fk_soc) && $this->fk_soc > 0) { // For backward compatibility
583 $sql .= " fk_soc = ". ((int) $this->fk_soc). ',';
584 }
585 $sql .= " suspended = ". (!empty($this->suspended) ? ((int) $this->suspended) : 0) . ',';
586 $sql .= " libelle = ". (!empty($this->libelle) ? "'".$this->db->escape($this->libelle)."'" : 'NULL') . ",";
587 $sql .= " vat_src_code = ". (!empty($this->vat_src_code) ? "'".$this->db->escape($this->vat_src_code)."'" : 'NULL') . ',';
588 $sql .= " localtax1 = ". (!empty($this->localtax1) ? ((float) $this->localtax1) : 0.00) . ',';
589 $sql .= " localtax2 = ". (!empty($this->localtax2) ? ((float) $this->localtax2) : 0.00) . ',';
590 $sql .= " total_ht = ". (!empty($this->total_ht) ? ((float) $this->total_ht) : 0.00) . ',';
591 $sql .= " total_tva = ". (!empty($this->total_tva) ? ((float) $this->total_tva) : 0.00) . ',';
592 $sql .= " total_ttc = ". (!empty($this->total_ttc) ? ((float) $this->total_ttc) : 0.00) . ',';
593 $sql .= " fk_user_modif = ". ((int) $user->id) . ',';
594 $sql .= " fk_projet = ". (!empty($this->fk_project) ? ((int) $this->fk_project) : 'NULL') . ',';
595 $sql .= " fk_account = ". (!empty($this->fk_account) ? ((int) $this->fk_account) : 'NULL') . ',';
596 $sql .= " fk_mode_reglement = ". (!empty($this->mode_reglement_id) ? ((int) $this->mode_reglement_id) : 'NULL') . ',';
597 $sql .= " fk_cond_reglement = ". (!empty($this->cond_reglement_id) ? ((int) $this->cond_reglement_id) : 'NULL') . ',';
598 $sql .= " date_lim_reglement = ". (!empty($this->date_lim_reglement) ? "'".$this->db->idate($this->date_lim_reglement)."'" : 'NULL') . ',';
599 $sql .= " note_private = '". (!empty($this->note_private) ? $this->db->escape($this->note_private) : '') . "',";
600 $sql .= " note_public = '". (!empty($this->note_public) ? $this->db->escape($this->note_public) : '') . "',";
601 $sql .= " modelpdf = ". (!empty($this->model_pdf) ? "'".$this->db->escape($this->model_pdf)."'" : 'NULL') . ",";
602 $sql .= " fk_multicurrency = ". (!empty($this->fk_multicurrency) ? ((int) $this->fk_multicurrency) : 'NULL') . ',';
603 $sql .= " multicurrency_code = ". (!empty($this->multicurrency_code) ? "'".$this->db->escape($this->multicurrency_code)."'" : 'NULL') . ",";
604 $sql .= " multicurrency_tx = ". (!empty($this->multicurrency_tx) ? ((float) $this->multicurrency_tx) : 1) . ',';
605 $sql .= " multicurrency_total_ht = ". (!empty($this->multicurrency_total_ht) ? ((float) $this->multicurrency_total_ht) : 0.00) . ',';
606 $sql .= " multicurrency_total_tva = ". (!empty($this->multicurrency_total_tva) ? ((float) $this->multicurrency_total_tva) : 0.00) . ',';
607 $sql .= " multicurrency_total_ttc = ". (!empty($this->multicurrency_total_ttc) ? ((float) $this->multicurrency_total_ttc) : 0.00) . ',';
608 $sql .= " usenewprice = ". (!empty($this->usenewprice) ? ((int) $this->usenewprice) : 0) . ',';
609 $sql .= " frequency = ". (!empty($this->frequency) ? ((int) $this->frequency) : 0). ',';
610 $sql .= " unit_frequency = '". (!empty($this->unit_frequency) ? $this->db->escape($this->unit_frequency) : ''). "',";
611 $sql .= " date_when = ". (!empty($this->date_when) ? "'".$this->db->idate($this->date_when)."'" : 'NULL') . ',';
612 $sql .= " date_last_gen = ". (!empty($this->date_last_gen) ? "'".$this->db->idate($this->date_last_gen)."'" : 'NULL') . ',';
613 $sql .= " nb_gen_done = ". (!empty($this->nb_gen_done) ? ((int) $this->nb_gen_done) : 0) . ',';
614 $sql .= " nb_gen_max = ". (!empty($this->nb_gen_max) ? ((int) $this->nb_gen_max) : 0) . ',';
615 $sql .= " auto_validate = ". (!empty($this->auto_validate) ? ((int) $this->auto_validate) : 0);
616 $sql .= " WHERE rowid = ". (int) $this->id;
617
618 $this->db->begin();
619
620 dol_syslog(get_class($this)."::update", LOG_DEBUG);
621 $resql = $this->db->query($sql);
622 if ($resql) {
623 if (!$error) {
624 $result = $this->insertExtraFields();
625 if ($result < 0) {
626 $error++;
627 }
628 }
629
630 if (!$error && !$notrigger) {
631 // Call trigger
632 $result = $this->call_trigger('SUPPLIERBILLREC_MODIFY', $user);
633 if ($result < 0) {
634 $this->db->rollback();
635 return -2;
636 }
637 // End call triggers
638 }
639 $this->db->commit();
640 return 1;
641 } else {
642 $this->error = $this->db->lasterror();
643 $this->db->rollback();
644 return -2;
645 }
646 }
647
656 public function fetch($rowid, $ref = '', $ref_ext = '')
657 {
658 $sql = 'SELECT f.rowid, f.titre as title, f.subtype, f.ref_supplier, f.entity, f.fk_soc';
659 $sql .= ', f.datec, f.tms, f.suspended';
660 $sql .= ', f.libelle as label';
661 $sql .= ', f.vat_src_code, f.localtax1, f.localtax2';
662 $sql .= ', f.total_tva, f.total_ht, f.total_ttc';
663 $sql .= ', f.fk_user_author, f.fk_user_modif';
664 $sql .= ', f.fk_projet as fk_project, f.fk_account';
665 $sql .= ', f.fk_mode_reglement, p.code as mode_reglement_code, p.libelle as mode_reglement_libelle';
666 $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';
667 $sql .= ', f.date_lim_reglement';
668 $sql .= ', f.note_private, f.note_public, f.modelpdf as model_pdf';
669 $sql .= ', f.fk_multicurrency, f.multicurrency_code, f.multicurrency_tx, f.multicurrency_total_ht, f.multicurrency_total_tva, f.multicurrency_total_ttc';
670 $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';
671 $sql .= ', f.generate_pdf';
672 $sql .= ' FROM '.MAIN_DB_PREFIX.'facture_fourn_rec as f';
673 $sql .= ' LEFT JOIN '.MAIN_DB_PREFIX.'c_payment_term as c ON f.fk_cond_reglement = c.rowid';
674 $sql .= ' LEFT JOIN '.MAIN_DB_PREFIX.'c_paiement as p ON f.fk_mode_reglement = p.id';
675 $sql .= ' WHERE f.entity IN ('.getEntity('invoice').')';
676 if ($rowid) {
677 $sql .= ' AND f.rowid='. (int) $rowid;
678 } elseif ($ref) {
679 $sql .= " AND f.titre='".$this->db->escape($ref)."'";
680 } else {
681 $sql .= ' AND f.rowid = 0';
682 }
683
684 $result = $this->db->query($sql);
685 if ($result) {
686 if ($this->db->num_rows($result)) {
687 $obj = $this->db->fetch_object($result);
688
689 $keyforref = $this->table_ref_field;
690
691 $this->id = $obj->rowid;
692 $this->titre = $obj->title;
693 $this->title = $obj->title;
694 $this->subtype = $obj->subtype;
695 $this->ref = $obj->title;
696 $this->ref_supplier = $obj->ref_supplier;
697 $this->entity = $obj->entity;
698 $this->socid = $obj->fk_soc;
699 $this->date_creation = $obj->datec;
700 $this->date_modification = $obj->tms;
701 $this->suspended = $obj->suspended;
702 $this->libelle = $obj->label;
703 $this->label = $obj->label;
704 $this->vat_src_code = $obj->vat_src_code;
705 $this->total_localtax1 = $obj->localtax1;
706 $this->total_localtax2 = $obj->localtax2;
707 $this->total_ht = $obj->total_ht;
708 $this->total_tva = $obj->total_tva;
709 $this->total_ttc = $obj->total_ttc;
710 $this->user_author = $obj->fk_user_author;
711 $this->user_modif = $obj->fk_user_modif;
712 $this->fk_project = $obj->fk_project;
713 $this->fk_account = $obj->fk_account;
714 $this->mode_reglement_id = $obj->fk_mode_reglement;
715 $this->mode_reglement_code = $obj->mode_reglement_code;
716 $this->mode_reglement = $obj->mode_reglement_libelle;
717 $this->cond_reglement_id = $obj->fk_cond_reglement;
718 $this->cond_reglement_code = $obj->cond_reglement_code;
719 $this->cond_reglement = $obj->cond_reglement_libelle;
720 $this->cond_reglement_doc = $obj->cond_reglement_libelle_doc;
721 $this->date_lim_reglement = $this->db->jdate($obj->date_lim_reglement);
722 $this->note_private = $obj->note_private;
723 $this->note_public = $obj->note_public;
724 $this->model_pdf = $obj->model_pdf;
725
726 // Multicurrency
727 $this->fk_multicurrency = $obj->fk_multicurrency;
728 $this->multicurrency_code = $obj->multicurrency_code;
729 $this->multicurrency_tx = $obj->multicurrency_tx;
730 $this->multicurrency_total_ht = $obj->multicurrency_total_ht;
731 $this->multicurrency_total_tva = $obj->multicurrency_total_tva;
732 $this->multicurrency_total_ttc = $obj->multicurrency_total_ttc;
733
734 $this->usenewprice = $obj->usenewprice;
735 $this->frequency = $obj->frequency;
736 $this->unit_frequency = $obj->unit_frequency;
737 $this->date_when = $this->db->jdate($obj->date_when);
738 $this->date_last_gen = $this->db->jdate($obj->date_last_gen);
739 $this->nb_gen_done = $obj->nb_gen_done;
740 $this->nb_gen_max = $obj->nb_gen_max;
741 $this->auto_validate = $obj->auto_validate;
742 $this->generate_pdf = $obj->generate_pdf;
743
744 // Retrieve all extrafield
745 // fetch optionals attributes and labels
746 $this->fetch_optionals();
747
748 /*
749 * Lines
750 */
751 $result = $this->fetch_lines();
752 if ($result < 0) {
753 $this->error = $this->db->lasterror();
754 return -3;
755 }
756 return 1;
757 } else {
758 $this->error = 'Bill with id '.$rowid.' or ref '.$ref.' not found';
759 dol_syslog('Facture::Fetch Error '.$this->error, LOG_ERR);
760 return -2;
761 }
762 } else {
763 $this->error = $this->db->error();
764 return -1;
765 }
766 }
767
768
774 public function getLinesArray()
775 {
776 return $this->fetch_lines();
777 }
778
779 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
785 public function fetch_lines()
786 {
787 // phpcs:enable
788 $this->lines = array();
789
790 // Retrieve all extrafield for line
791 // fetch optionals attributes and labels
792 /*if (!is_object($extrafields)) {
793 require_once DOL_DOCUMENT_ROOT.'/core/class/extrafields.class.php';
794 $extrafields = new ExtraFields($this->db);
795 }
796 $extrafields->fetch_name_optionals_label($this->table_element_line, true);
797 */
798
799 $sql = 'SELECT l.rowid,';
800 $sql .= ' l.fk_facture_fourn, l.fk_parent_line, l.fk_product, l.ref, l.label, l.description as line_desc,';
801 $sql .= ' l.pu_ht, l.pu_ttc, l.qty, l.remise_percent, l.fk_remise_except, l.vat_src_code, l.tva_tx,';
802 $sql .= ' l.localtax1_tx, l.localtax2_tx, l.localtax1_type, l.localtax2_type,';
803 $sql .= ' l.total_ht, l.total_tva, l.total_ttc, total_localtax1, total_localtax2,';
804 $sql .= ' l.product_type, l.date_start, l.date_end,';
805 $sql .= ' l.info_bits, l.special_code, l.rang,';
806 $sql .= ' l.fk_unit, l.import_key, l.fk_user_author, l.fk_user_modif,';
807 $sql .= ' l.fk_multicurrency, l.multicurrency_code, l.multicurrency_subprice, l.multicurrency_total_ht, l.multicurrency_total_tva, l.multicurrency_total_ttc,';
808 $sql .= ' p.ref as product_ref, p.fk_product_type as fk_product_type, p.label as product_label, p.description as product_desc';
809 $sql .= ' FROM '.MAIN_DB_PREFIX.'facture_fourn_det_rec as l';
810 $sql .= ' LEFT JOIN '.MAIN_DB_PREFIX.'product as p ON l.fk_product = p.rowid';
811 $sql .= ' WHERE l.fk_facture_fourn = '. (int) $this->id;
812 $sql .= ' ORDER BY l.rang';
813
814 dol_syslog('FactureFournisseurRec::fetch_lines', LOG_DEBUG);
815
816 $result = $this->db->query($sql);
817 if ($result) {
818 $num = $this->db->num_rows($result);
819 $i = 0;
820 while ($i < $num) {
821 $objp = $this->db->fetch_object($result);
822
823 $line = new FactureFournisseurLigneRec($this->db);
824
825 $line->id = $objp->rowid;
826 $line->fk_facture_fourn = $objp->fk_facture_fourn;
827 $line->fk_parent = $objp->fk_parent_line;
828 $line->fk_product = $objp->fk_product;
829 $line->ref_supplier = $objp->ref;
830 $line->label = $objp->label;
831 $line->description = $objp->line_desc;
832 $line->desc = $objp->line_desc;
833 $line->pu_ht = $objp->pu_ht;
834 $line->pu_ttc = $objp->pu_ttc;
835 $line->qty = $objp->qty;
836 $line->remise_percent = $objp->remise_percent;
837 $line->fk_remise_except = $objp->fk_remise_except;
838 $line->vat_src_code = $objp->vat_src_code;
839 $line->tva_tx = $objp->tva_tx;
840 $line->localtax1_tx = $objp->localtax1_tx;
841 $line->localtax1_type = $objp->localtax1_type;
842 $line->localtax2_tx = $objp->localtax2_tx;
843 $line->localtax2_type = $objp->localtax2_type;
844 $line->total_ht = $objp->total_ht;
845 $line->total_tva = $objp->total_tva;
846 $line->total_localtax1 = $objp->total_localtax1;
847 $line->total_localtax2 = $objp->total_localtax2;
848 $line->total_ttc = $objp->total_ttc;
849 $line->product_type = $objp->product_type;
850 $line->date_start = $this->db->jdate($objp->date_start);
851 $line->date_end = $this->db->jdate($objp->date_end);
852 $line->info_bits = $objp->info_bits ;
853 $line->special_code = $objp->special_code;
854 $line->rang = $objp->rang;
855 $line->fk_unit = $objp->fk_unit;
856 $line->import_key = $objp->import_key;
857 $line->fk_user_author = $objp->fk_user_author;
858 $line->fk_user_modif = $objp->fk_user_modif;
859 $line->fk_multicurrency = $objp->fk_multicurrency;
860 $line->multicurrency_code = $objp->multicurrency_code;
861 $line->multicurrency_subprice = $objp->multicurrency_subprice;
862 $line->multicurrency_total_ht = $objp->multicurrency_total_ht;
863 $line->multicurrency_total_tva = $objp->multicurrency_total_tva;
864 $line->multicurrency_total_ttc = $objp->multicurrency_total_ttc;
865
866 $line->fetch_optionals();
867
868 $this->lines[$i] = $line;
869
870 $i++;
871 }
872
873 $this->db->free($result);
874 return 1;
875 } else {
876 $this->error = $this->db->lasterror();
877 return -3;
878 }
879 }
880
881
890 public function delete(User $user, $notrigger = 0, $idwarehouse = -1)
891 {
892 $rowid = $this->id;
893
894 dol_syslog(get_class($this)."::delete rowid=".((int) $rowid), LOG_DEBUG);
895
896 $error = 0;
897 $this->db->begin();
898
899 $main = MAIN_DB_PREFIX.'facture_fourn_det_rec';
900 $ef = $main."_extrafields";
901
902 $sqlef = "DELETE FROM ".$ef." WHERE fk_object IN (SELECT rowid FROM ".$main." WHERE fk_facture_fourn = ". (int) $rowid .")";
903 $sql = "DELETE FROM ".MAIN_DB_PREFIX."facture_fourn_det_rec WHERE fk_facture_fourn = ". (int) $rowid;
904
905 if ($this->db->query($sqlef) && $this->db->query($sql)) {
906 $sql = "DELETE FROM ".MAIN_DB_PREFIX."facture_fourn_rec WHERE rowid = ". (int) $rowid;
907 dol_syslog($sql);
908 if ($this->db->query($sql)) {
909 // Delete linked object
910 $res = $this->deleteObjectLinked();
911 if ($res < 0) {
912 $error = -3;
913 }
914 // Delete extrafields
915 $res = $this->deleteExtraFields();
916 if ($res < 0) {
917 $error = -4;
918 }
919 } else {
920 $this->error = $this->db->lasterror();
921 $error = -1;
922 }
923 } else {
924 $this->error = $this->db->lasterror();
925 $error = -2;
926 }
927 if (!$error && !$notrigger) {
928 // Call trigger
929 $result = $this->call_trigger('SUPPLIERBILLREC_DELETE', $user);
930 if ($result < 0) {
931 $error++;
932 }
933 // End call triggers
934 }
935 if (! $error) {
936 $this->db->commit();
937 return 1;
938 } else {
939 $this->db->rollback();
940 return $error;
941 }
942 }
943
970 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)
971 {
972 global $mysoc, $user;
973
974 include_once DOL_DOCUMENT_ROOT.'/core/lib/price.lib.php';
975
976 $facid = $this->id; //Supplier invoice template ID linked to
977
978 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);
979
980 // Check if object of the line is product or service
981 if ($type < 0) {
982 return -1;
983 }
984
985 $localtaxes_type = getLocalTaxesFromRate($txtva, 0, $this->thirdparty, $mysoc);
986
987 // Clean vat code
988 $reg = array();
989 $vat_src_code = '';
990 if (preg_match('/\‍((.*)\‍)/', (string) $txtva, $reg)) {
991 $vat_src_code = $reg[1];
992 $txtva = preg_replace('/\s*\‍(.*\‍)/', '', (string) $txtva); // Remove code into vatrate.
993 }
994
995 // Clean parameters
996 $fk_product = empty($fk_product) ? 0 : $fk_product;
997 $label = empty($label) ? '' : $label;
998 $remise_percent = empty($remise_percent) ? 0 : price2num($remise_percent);
999 $qty = price2num($qty);
1000 $pu_ht = price2num($pu_ht);
1001 $pu_ttc = price2num($pu_ttc);
1002 if (!preg_match('/\‍((.*)\‍)/', $txtva)) {
1003 $txtva = price2num($txtva); // $txtva can have format '5.0(XXX)' or '5'
1004 }
1005 $txlocaltax1 = price2num($txlocaltax1);
1006 $txlocaltax2 = price2num($txlocaltax2);
1007 $txtva = !empty($txtva) ? $txtva : 0;
1008 $txlocaltax1 = !empty($txlocaltax1) ? $txlocaltax1 : 0;
1009 $txlocaltax2 = !empty($txlocaltax2) ? $txlocaltax2 : 0;
1010 $info_bits = !empty($info_bits) ? $info_bits : 0;
1011 $info_bits = !empty($info_bits) ? $info_bits : 0;
1012 $pu = $price_base_type == 'HT' ? $pu_ht : $pu_ttc;
1013
1014 // Calcul du total TTC et de la TVA pour la ligne a partir de qty, pu, remise_percent et txtva
1015 // TRES IMPORTANT: C'est au moment de l'insertion ligne qu'on doit stocker
1016 // la part ht, tva et ttc, et ce au niveau de la ligne qui a son propre taux tva.
1017
1018 $tabprice = calcul_price_total($qty, $pu, $remise_percent, $txtva, $txlocaltax1, $txlocaltax2, 0, $price_base_type, $info_bits, $type, $mysoc, $localtaxes_type, 100, $this->multicurrency_tx, $pu_ht_devise);
1019 $total_ht = $tabprice[0];
1020 $total_tva = $tabprice[1];
1021 $total_ttc = $tabprice[2];
1022 $total_localtax1 = $tabprice[9];
1023 $total_localtax2 = $tabprice[10];
1024 $pu_ht = $tabprice[3];
1025
1026 // MultiCurrency
1027 $multicurrency_total_ht = $tabprice[16];
1028 $multicurrency_total_tva = $tabprice[17];
1029 $multicurrency_total_ttc = $tabprice[18];
1030 $pu_ht_devise = $tabprice[19];
1031
1032 $this->db->begin();
1033 $product_type = $type;
1034 if ($fk_product) {
1035 $product = new Product($this->db);
1036 $result = $product->fetch($fk_product);
1037 if ($result < 0) {
1038 return -1;
1039 }
1040 $product_type = $product->type;
1041 if (empty($label)) {
1042 $label = $product->label;
1043 }
1044 }
1045
1046 $sql = 'INSERT INTO ' . MAIN_DB_PREFIX . 'facture_fourn_det_rec (';
1047 $sql .= 'fk_facture_fourn';
1048 $sql .= ', fk_product';
1049 $sql .= ', ref';
1050 $sql .= ', label';
1051 $sql .= ', description';
1052 $sql .= ', pu_ht';
1053 $sql .= ', pu_ttc';
1054 $sql .= ', qty';
1055 $sql .= ', remise_percent';
1056 $sql .= ', fk_remise_except';
1057 $sql .= ', vat_src_code';
1058 $sql .= ', tva_tx';
1059 $sql .= ', localtax1_tx';
1060 $sql .= ', localtax1_type';
1061 $sql .= ', localtax2_tx';
1062 $sql .= ', localtax2_type';
1063 $sql .= ', total_ht';
1064 $sql .= ', total_tva';
1065 $sql .= ', total_localtax1';
1066 $sql .= ', total_localtax2';
1067 $sql .= ', total_ttc';
1068 $sql .= ', product_type';
1069 $sql .= ', date_start';
1070 $sql .= ', date_end';
1071 $sql .= ', info_bits';
1072 $sql .= ', special_code';
1073 $sql .= ', rang';
1074 $sql .= ', fk_unit';
1075 $sql .= ', fk_user_author';
1076 $sql .= ', fk_multicurrency, multicurrency_code, multicurrency_subprice, multicurrency_total_ht, multicurrency_total_tva, multicurrency_total_ttc';
1077 $sql .= ') VALUES (';
1078 $sql .= ' ' . (int) $facid; // source supplier invoice id
1079 $sql .= ', ' . (!empty($fk_product) ? "'" . $this->db->escape($fk_product) . "'" : 'null');
1080 $sql .= ', ' . (!empty($ref) ? "'" . $this->db->escape($ref) . "'" : 'null');
1081 $sql .= ', ' . (!empty($label) ? "'" . $this->db->escape($label) . "'" : 'null');
1082 $sql .= ", '" . $this->db->escape($desc) . "'";
1083 $sql .= ', ' . price2num($pu_ht);
1084 $sql .= ', ' . price2num($pu_ttc);
1085 $sql .= ', ' . price2num($qty);
1086 $sql .= ', ' . price2num($remise_percent);
1087 $sql .= ', null';
1088 $sql .= ", '" . $this->db->escape($vat_src_code) . "'";
1089 $sql .= ', ' . price2num($txtva);
1090 $sql .= ', ' . price2num($txlocaltax1);
1091 $sql .= ", '" . $this->db->escape(isset($localtaxes_type[0]) ? $localtaxes_type[0] : '') . "'";
1092 $sql .= ', ' . price2num($txlocaltax2);
1093 $sql .= ", '" . $this->db->escape(isset($localtaxes_type[2]) ? $localtaxes_type[2] : '') . "'";
1094 $sql .= ', ' . price2num($total_ht);
1095 $sql .= ', ' . price2num($total_tva);
1096 $sql .= ', ' . price2num($total_localtax1);
1097 $sql .= ', ' . price2num($total_localtax2);
1098 $sql .= ', ' . price2num($total_ttc);
1099 $sql .= ', ' . (int) $product_type;
1100 $sql .= ', ' . ($date_start > 0 ? (int) $date_start : 'NULL');
1101 $sql .= ', ' . ($date_end > 0 ? (int) $date_end : 'NULL');
1102 $sql .= ', ' . (int) $info_bits;
1103 $sql .= ', ' . (int) $special_code;
1104 $sql .= ', ' . (int) $rang;
1105 $sql .= ', ' . ($fk_unit ? (int) $fk_unit : 'NULL');
1106 $sql .= ', ' . (int) $user->id;
1107 $sql .= ', ' . (int) $this->fk_multicurrency;
1108 $sql .= ", '" . $this->db->escape($this->multicurrency_code) . "'";
1109 $sql .= ', ' . price2num($pu_ht_devise, 'CU');
1110 $sql .= ', ' . price2num($multicurrency_total_ht, 'CT');
1111 $sql .= ', ' . price2num($multicurrency_total_tva, 'CT');
1112 $sql .= ', ' . price2num($multicurrency_total_ttc, 'CT');
1113 $sql .= ')';
1114
1115 dol_syslog(get_class($this). '::addline', LOG_DEBUG);
1116 if ($this->db->query($sql)) {
1117 $lineId = $this->db->last_insert_id(MAIN_DB_PREFIX. 'facture_fourn_det_rec');
1118 $this->update_price();
1119 $this->id = $facid;
1120 $this->db->commit();
1121 return $lineId;
1122 } else {
1123 $this->db->rollback();
1124 $this->error = $this->db->lasterror();
1125
1126 return -1;
1127 }
1128 }
1129
1157 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)
1158 {
1159 global $mysoc, $user;
1160
1161 $facid = $this->id;
1162
1163 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);
1164 include_once DOL_DOCUMENT_ROOT.'/core/lib/price.lib.php';
1165
1166 // Check parameters
1167 if ($type < 0) {
1168 return -1;
1169 }
1170
1171 // Clean parameters
1172 $fk_product = empty($fk_product) ? 0 : $fk_product;
1173 $label = empty($label) ? '' : $label;
1174 $remise_percent = empty($remise_percent) ? 0 : price2num($remise_percent);
1175 $qty = price2num($qty);
1176 $info_bits = empty($info_bits) ? 0 : $info_bits;
1177 $pu_ht = price2num($pu_ht);
1178 $pu_ttc = price2num($pu_ttc);
1179 $pu_ht_devise = price2num($pu_ht_devise);
1180
1181 if (!preg_match('/\‍((.*)\‍)/', (string) $txtva)) {
1182 $txtva = price2num($txtva); // $txtva can have format '5.0(XXX)' or '5'
1183 }
1184
1185 $txlocaltax1 = empty($txlocaltax1) ? 0 : price2num($txlocaltax1);
1186 $txlocaltax2 = empty($txlocaltax2) ? 0 : price2num($txlocaltax2);
1187 $this->multicurrency_total_ht = empty($this->multicurrency_total_ht) ? 0 : $this->multicurrency_total_ht;
1188 $this->multicurrency_total_tva = empty($this->multicurrency_total_tva) ? 0 : $this->multicurrency_total_tva;
1189 $this->multicurrency_total_ttc = empty($this->multicurrency_total_ttc) ? 0 : $this->multicurrency_total_ttc;
1190
1191 $pu = $price_base_type == 'HT' ? $pu_ht : $pu_ttc;
1192
1193
1194 // Calculate total with, without tax and tax from qty, pu, remise_percent and txtva
1195 // TRES IMPORTANT: C'est au moment de l'insertion ligne qu'on doit stocker
1196 // la part ht, tva et ttc, et ce au niveau de la ligne qui a son propre taux tva.
1197
1198 $localtaxes_type = getLocalTaxesFromRate($txtva, 0, $this->thirdparty, $mysoc);
1199
1200 // Clean vat code
1201 $vat_src_code = '';
1202 $reg = array();
1203 if (preg_match('/\‍((.*)\‍)/', $txtva, $reg)) {
1204 $vat_src_code = $reg[1];
1205 $txtva = preg_replace('/\s*\‍(.*\‍)/', '', $txtva); // Remove code into vatrate.
1206 }
1207
1208 $tabprice = calcul_price_total($qty, $pu, $remise_percent, $txtva, $txlocaltax1, $txlocaltax2, 0, $price_base_type, $info_bits, $type, $mysoc, $localtaxes_type, 100, $this->multicurrency_tx, $pu_ht_devise);
1209
1210 $total_ht = $tabprice[0];
1211 $total_tva = $tabprice[1];
1212 $total_ttc = $tabprice[2];
1213 $total_localtax1 = $tabprice[9];
1214 $total_localtax2 = $tabprice[10];
1215 $pu_ht = $tabprice[3];
1216 $pu_tva = $tabprice[4];
1217 $pu_ttc = $tabprice[5];
1218
1219 // MultiCurrency
1220 $multicurrency_total_ht = $tabprice[16];
1221 $multicurrency_total_tva = $tabprice[17];
1222 $multicurrency_total_ttc = $tabprice[18];
1223 $pu_ht_devise = $tabprice[19];
1224
1225 $product_type = $type;
1226 if ($fk_product) {
1227 $product = new Product($this->db);
1228 $result = $product->fetch($fk_product);
1229 $product_type = $product->type;
1230 }
1231
1232 $sql = 'UPDATE ' . MAIN_DB_PREFIX . 'facture_fourn_det_rec SET';
1233 $sql .= ' fk_facture_fourn = ' . ((int) $facid);
1234 $sql .= ', fk_product = ' . ($fk_product > 0 ? ((int) $fk_product) : 'null');
1235 $sql .= ", ref = '" . $this->db->escape($ref) . "'";
1236 $sql .= ", label = '" . $this->db->escape($label) . "'";
1237 $sql .= ", description = '" . $this->db->escape($desc) . "'";
1238 $sql .= ', pu_ht = ' . price2num($pu_ht);
1239 $sql .= ', qty = ' . price2num($qty);
1240 $sql .= ", remise_percent = '" . price2num($remise_percent) . "'";
1241 $sql .= ", vat_src_code = '" . $this->db->escape($vat_src_code) . "'";
1242 $sql .= ', tva_tx = ' . price2num($txtva);
1243 $sql .= ', localtax1_tx = ' . (float) $txlocaltax1;
1244 $sql .= ", localtax1_type = '" . $this->db->escape($localtaxes_type[0]) . "'";
1245 $sql .= ', localtax2_tx = ' . (float) $txlocaltax2;
1246 $sql .= ", localtax2_type = '" . $this->db->escape($localtaxes_type[2]) . "'";
1247 $sql .= ", total_ht = '" . price2num($total_ht) . "'";
1248 $sql .= ", total_tva = '" . price2num($total_tva) . "'";
1249 $sql .= ", total_localtax1 = '" . price2num($total_localtax1) . "'";
1250 $sql .= ", total_localtax2 = '" . price2num($total_localtax2) . "'";
1251 $sql .= ", total_ttc = '" . price2num($total_ttc) . "'";
1252 $sql .= ', product_type = ' . (int) $product_type;
1253 $sql .= ', date_start = ' . (empty($date_start) ? 'NULL' : (int) $date_start);
1254 $sql .= ', date_end = ' . (empty($date_end) ? 'NULL' : (int) $date_end);
1255 $sql .= ', info_bits = ' . (int) $info_bits;
1256 $sql .= ', special_code = ' . (int) $special_code;
1257 $sql .= ', rang = ' . (int) $rang;
1258 $sql .= ', fk_unit = ' . ($fk_unit ? "'" . $this->db->escape($fk_unit) . "'" : 'null');
1259 $sql .= ', fk_user_modif = ' . (int) $user;
1260 $sql .= ', multicurrency_subprice = '.price2num($pu_ht_devise);
1261 $sql .= ', multicurrency_total_ht = '.price2num($multicurrency_total_ht);
1262 $sql .= ', multicurrency_total_tva = '.price2num($multicurrency_total_tva);
1263 $sql .= ', multicurrency_total_ttc = '.price2num($multicurrency_total_ttc);
1264 $sql .= ' WHERE rowid = ' . (int) $rowid;
1265
1266 dol_syslog(get_class($this). '::updateline', LOG_DEBUG);
1267 if ($this->db->query($sql)) {
1268 $this->id = $facid;
1269 $this->update_price();
1270 return 1;
1271 } else {
1272 $this->error = $this->db->lasterror();
1273 return -1;
1274 }
1275 }
1276
1277
1285 public function getNextNumRef($soc, $mode = 'next')
1286 {
1287 // Not used for recurring invoices
1288 return '';
1289 }
1290
1296 public function getNextDate()
1297 {
1298 if (empty($this->date_when)) {
1299 return false;
1300 }
1301 return dol_time_plus_duree((int) $this->date_when, $this->frequency, $this->unit_frequency, 1);
1302 }
1303
1309 public function isMaxNbGenReached()
1310 {
1311 $ret = false;
1312 if ($this->nb_gen_max > 0 && ($this->nb_gen_done >= $this->nb_gen_max)) {
1313 $ret = true;
1314 }
1315 return $ret;
1316 }
1317
1324 public function strikeIfMaxNbGenReached($ret)
1325 {
1326 // Special case to strike the date
1327 return ($this->isMaxNbGenReached() ? '<strike>' : '').$ret.($this->isMaxNbGenReached() ? '</strike>' : '');
1328 }
1329
1340 public function createRecurringInvoices($restrictioninvoiceid = 0, $forcevalidation = 0)
1341 {
1342 global $conf, $langs, $db, $user, $hookmanager;
1343
1344 $error = 0;
1345 $nb_create = 0;
1346
1347 // Load translation files required by the page
1348 $langs->loadLangs(array('main', 'bills'));
1349
1350 $now = dol_now();
1351 $tmparray = dol_getdate($now);
1352 $today = dol_mktime(23, 59, 59, $tmparray['mon'], $tmparray['mday'], $tmparray['year']); // Today is last second of current day
1353
1354 dol_syslog('createRecurringInvoices restrictioninvoiceid=' .$restrictioninvoiceid. ' forcevalidation=' .$forcevalidation);
1355
1356 $sql = 'SELECT rowid FROM '.MAIN_DB_PREFIX.'facture_fourn_rec';
1357 $sql .= ' WHERE frequency > 0'; // A recurring supplier invoice is an invoice with a frequency
1358 $sql .= " AND (date_when IS NULL OR date_when <= '".$this->db->idate($today)."')";
1359 $sql .= ' AND (nb_gen_done < nb_gen_max OR nb_gen_max = 0)';
1360 $sql .= ' AND suspended = 0';
1361 $sql .= ' AND entity = '. (int) $conf->entity; // MUST STAY = $conf->entity here
1362 if ($restrictioninvoiceid > 0) {
1363 $sql .= ' AND rowid = '. (int) $restrictioninvoiceid;
1364 }
1365 $sql .= $this->db->order('entity', 'ASC');
1366 //print $sql;exit;
1367 $parameters = array(
1368 'restrictioninvoiceid' => $restrictioninvoiceid,
1369 'forcevalidation' => $forcevalidation,
1370 );
1371 $reshook = $hookmanager->executeHooks('beforeCreationOfRecurringInvoices', $parameters, $sql); // note that $sql might be modified by hooks
1372
1373 $resql = $this->db->query($sql);
1374 if ($resql) {
1375 $i = 0;
1376 $num = $this->db->num_rows($resql);
1377
1378 if ($num) {
1379 $this->output .= $langs->trans('FoundXQualifiedRecurringInvoiceTemplate', $num)."\n";
1380 } else {
1381 $this->output .= $langs->trans('NoQualifiedRecurringInvoiceTemplateFound');
1382 }
1383
1384 $saventity = $conf->entity;
1385 $laststep = "None";
1386
1387 while ($i < $num) { // Loop on each template invoice. If $num = 0, test is false at first pass.
1388 $line = $this->db->fetch_object($resql);
1389
1390 $this->db->begin();
1391
1392 $invoiceidgenerated = 0;
1393
1394 $new_fac_fourn = null;
1395 $facturerec = new FactureFournisseurRec($this->db);
1396 $laststep = "Fetch {$line->rowid}";
1397 $facturerec->fetch($line->rowid);
1398
1399 if ($facturerec->id > 0) {
1400 // Set entity context
1401 $conf->entity = $facturerec->entity;
1402
1403 dol_syslog('createRecurringInvoices Process invoice template id=' .$facturerec->id. ', ref=' .$facturerec->ref. ', entity=' .$facturerec->entity);
1404
1405 $new_fac_fourn = new FactureFournisseur($this->db);
1406 $new_fac_fourn->fac_rec = $facturerec->id; // We will create $facture from this recurring invoice
1407 $new_fac_fourn->fk_fac_rec_source = $facturerec->id; // We will create $facture from this recurring invoice
1408
1409 $new_fac_fourn->type = self::TYPE_STANDARD;
1410 $new_fac_fourn->subtype = $facturerec->subtype;
1411 $new_fac_fourn->statut = self::STATUS_DRAFT; // deprecated
1412 $new_fac_fourn->status = self::STATUS_DRAFT;
1413 $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.
1414 $new_fac_fourn->socid = $facturerec->socid;
1415 $new_fac_fourn->lines = $facturerec->lines;
1416 $new_fac_fourn->ref_supplier = $facturerec->ref_supplier;
1417 $new_fac_fourn->model_pdf = $facturerec->model_pdf;
1418 $new_fac_fourn->fk_project = $facturerec->fk_project;
1419 $new_fac_fourn->label = $facturerec->label;
1420 $new_fac_fourn->libelle = $facturerec->label; // deprecated
1421
1422 $invoiceidgenerated = $new_fac_fourn->create($user);
1423 $laststep = "Create invoiceidgenerated $invoiceidgenerated";
1424 if ($invoiceidgenerated <= 0) {
1425 $this->errors = $new_fac_fourn->errors;
1426 $this->error = $new_fac_fourn->error;
1427 $error++;
1428 }
1429 if (!$error && ($facturerec->auto_validate || $forcevalidation)) {
1430 $result = $new_fac_fourn->validate($user);
1431 $laststep = "Validate by user {$user->login}";
1432 if ($result <= 0) {
1433 $this->errors = $new_fac_fourn->errors;
1434 $this->error = $new_fac_fourn->error;
1435 $error++;
1436 }
1437 }
1438
1439 if (!$error && $facturerec->generate_pdf) {
1440 // We refresh the object in order to have all necessary data (like date_lim_reglement)
1441 $laststep = "Refresh ".$new_fac_fourn->id;
1442 $new_fac_fourn->fetch($new_fac_fourn->id);
1443 $laststep = "GenerateDocument ".$new_fac_fourn->id;
1444 $result = $new_fac_fourn->generateDocument($facturerec->model_pdf, $langs);
1445 if ($result < 0) {
1446 $this->errors = $new_fac_fourn->errors;
1447 $this->error = $new_fac_fourn->error;
1448 $error++;
1449 }
1450 }
1451 } else {
1452 $error++;
1453 $this->error = 'Failed to load invoice template with id=' .$line->rowid. ', entity=' .$conf->entity."\n";
1454 $this->errors[] = 'Failed to load invoice template with id=' .$line->rowid. ', entity=' .$conf->entity;
1455 dol_syslog('createRecurringInvoices Failed to load invoice template with id=' .$line->rowid. ', entity=' .$conf->entity);
1456 }
1457
1458 if (!$error && $invoiceidgenerated >= 0) {
1459 $facturerec->nb_gen_done++;
1460 $facturerec->date_last_gen = dol_now();
1461 $nextDate = $facturerec->getNextDate();
1462 $facturerec->date_when = (($nextDate === false) ? null : $nextDate);
1463 $facturerec->update($user);
1464 $this->db->commit('createRecurringInvoices Process invoice template id=' .$facturerec->id. ', title=' .$facturerec->title);
1465 dol_syslog('createRecurringInvoices Process invoice template ' .$facturerec->title. ' is finished with a success generation');
1466 $nb_create++;
1467 $this->output .= $langs->trans('InvoiceGeneratedFromTemplate', $new_fac_fourn->ref, $facturerec->title)."\n";
1468 } else {
1469 $this->db->rollback('createRecurringInvoices Process invoice template error='.$error.' invoiceidgenerated='.$invoiceidgenerated.' LastStep='.$laststep.' id=' .$facturerec->id. ', title=' .$facturerec->title);
1470 }
1471
1472 $parameters = array(
1473 'cpt' => $i,
1474 'total' => $num,
1475 'errorCount' => $error,
1476 'invoiceidgenerated' => $invoiceidgenerated,
1477 'facturerec' => $facturerec, // it's an object which PHP passes by "reference", so modifiable by hooks.
1478 'this' => $this, // it's an object which PHP passes by "reference", so modifiable by hooks.
1479 );
1480 $reshook = $hookmanager->executeHooks('afterCreationOfRecurringInvoice', $parameters, $new_fac_fourn); // note: $facture can be modified by hooks (warning: $facture can be null)
1481
1482 $i++;
1483 }
1484
1485 $conf->entity = $saventity; // Restore entity context
1486 } else {
1487 dol_print_error($this->db);
1488 }
1489
1490 $this->output = trim($this->output);
1491
1492 return $error ? $error : 0;
1493 }
1494
1507 public function getNomUrl($withpicto = 0, $option = '', $max = 0, $short = 0, $moretitle = '', $notooltip = 0, $save_lastsearch_value = -1)
1508 {
1509 global $langs, $hookmanager;
1510
1511 $result = '';
1512
1513 $label = '<u>'.$langs->trans('RepeatableInvoice').'</u>';
1514 if (!empty($this->ref)) {
1515 $label .= '<br><b>'.$langs->trans('Ref').':</b> '.$this->ref;
1516 }
1517 if ($this->frequency > 0) {
1518 $label .= '<br><b>'.$langs->trans('Frequency').':</b> '.$langs->trans('FrequencyPer_'.$this->unit_frequency, $this->frequency);
1519 }
1520 if (!empty($this->date_last_gen)) {
1521 $label .= '<br><b>'.$langs->trans('DateLastGeneration').':</b> '.dol_print_date($this->date_last_gen, 'dayhour');
1522 }
1523 if ($this->frequency > 0) {
1524 if (!empty($this->date_when)) {
1525 $label .= '<br><b>'.$langs->trans('NextDateToExecution').':</b> ';
1526 $label .= (empty($this->suspended) ? '' : '<strike>').dol_print_date($this->date_when, 'day').(empty($this->suspended) ? '' : '</strike>'); // No hour for this property
1527 if (!empty($this->suspended)) {
1528 $label .= ' ('.$langs->trans('Disabled').')';
1529 }
1530 }
1531 }
1532
1533 $url = DOL_URL_ROOT.'/fourn/facture/card-rec.php?facid='.$this->id;
1534
1535 if ($short) {
1536 return $url;
1537 }
1538
1539 if ($option != 'nolink') {
1540 // Add param to save lastsearch_values or not
1541 $add_save_lastsearch_values = ($save_lastsearch_value == 1 ? 1 : 0);
1542 if ($save_lastsearch_value == -1 && preg_match('/list\.php/', $_SERVER['PHP_SELF'])) {
1543 $add_save_lastsearch_values = 1;
1544 }
1545 if ($add_save_lastsearch_values) {
1546 $url .= '&save_lastsearch_values=1';
1547 }
1548 }
1549
1550 $linkstart = '<a href="'.$url.'" title="'.dol_escape_htmltag($label, 1).'" class="classfortooltip">';
1551 $linkend = '</a>';
1552
1553 $result .= $linkstart;
1554 if ($withpicto) {
1555 $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);
1556 }
1557 if ($withpicto != 2) {
1558 $result .= $this->ref;
1559 }
1560 $result .= $linkend;
1561 global $action;
1562 $hookmanager->initHooks(array($this->element . 'dao'));
1563 $parameters = array('id' => $this->id, 'getnomurl' => &$result);
1564 $reshook = $hookmanager->executeHooks('getNomUrl', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks
1565 if ($reshook > 0) {
1566 $result = $hookmanager->resPrint;
1567 } else {
1568 $result .= $hookmanager->resPrint;
1569 }
1570 return $result;
1571 }
1572
1580 public function getLibStatut($mode = 0, $alreadypaid = -1)
1581 {
1582 return $this->LibStatut($this->frequency ? 1 : 0, $this->suspended, $mode, $alreadypaid, empty($this->type) ? 0 : $this->type);
1583 }
1584
1585 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1597 public function LibStatut($recur, $status, $mode = 0, $alreadypaid = -1, $type = 0, $nbofopendirectdebitorcredittransfer = 0)
1598 {
1599 // phpcs:enable
1600 global $langs;
1601 $langs->load('bills');
1602
1603 $labelStatus = $langs->transnoentitiesnoconv('Active');
1604 $statusType = 'status0';
1605
1606 //print "$recur,$status,$mode,$alreadypaid,$type";
1607 if ($mode == 0) {
1608 if ($recur) {
1609 if ($status == self::STATUS_SUSPENDED) {
1610 $labelStatus = $langs->transnoentitiesnoconv('Disabled');
1611 } else {
1612 $labelStatus = $langs->transnoentitiesnoconv('Active');
1613 }
1614 } else {
1615 if ($status == self::STATUS_SUSPENDED) {
1616 $labelStatus = $langs->transnoentitiesnoconv('Disabled');
1617 } else {
1618 $labelStatus = $langs->transnoentitiesnoconv('Draft');
1619 }
1620 }
1621 } elseif ($mode == 1) {
1622 $prefix = 'Short';
1623 if ($recur) {
1624 if ($status == self::STATUS_SUSPENDED) {
1625 $labelStatus = $langs->transnoentitiesnoconv('Disabled');
1626 } else {
1627 $labelStatus = $langs->transnoentitiesnoconv('Active');
1628 }
1629 } else {
1630 if ($status == self::STATUS_SUSPENDED) {
1631 $labelStatus = $langs->transnoentitiesnoconv('Disabled');
1632 } else {
1633 $labelStatus = $langs->transnoentitiesnoconv('Draft');
1634 }
1635 }
1636 } elseif ($mode == 2) {
1637 if ($recur) {
1638 if ($status == self::STATUS_SUSPENDED) {
1639 $statusType = 'status6';
1640 $labelStatus = $langs->transnoentitiesnoconv('Disabled');
1641 } else {
1642 $statusType = 'status4';
1643 $labelStatus = $langs->transnoentitiesnoconv('Active');
1644 }
1645 } else {
1646 if ($status == self::STATUS_SUSPENDED) {
1647 $statusType = 'status6';
1648 $labelStatus = $langs->transnoentitiesnoconv('Disabled');
1649 } else {
1650 $statusType = 'status0';
1651 $labelStatus = $langs->transnoentitiesnoconv('Draft');
1652 }
1653 }
1654 } elseif ($mode == 3) {
1655 if ($recur) {
1656 $prefix = 'Short';
1657 if ($status == self::STATUS_SUSPENDED) {
1658 $statusType = 'status6';
1659 $labelStatus = $langs->transnoentitiesnoconv('Disabled');
1660 } else {
1661 $statusType = 'status4';
1662 $labelStatus = $langs->transnoentitiesnoconv('Active');
1663 }
1664 } else {
1665 if ($status == self::STATUS_SUSPENDED) {
1666 $statusType = 'status6';
1667 $labelStatus = $langs->transnoentitiesnoconv('Disabled');
1668 } else {
1669 $statusType = 'status0';
1670 $labelStatus = $langs->transnoentitiesnoconv('Draft');
1671 }
1672 }
1673 } elseif ($mode == 4) {
1674 $prefix = '';
1675 if ($recur) {
1676 if ($status == self::STATUS_SUSPENDED) {
1677 $statusType = 'status6';
1678 $labelStatus = $langs->transnoentitiesnoconv('Disabled');
1679 } else {
1680 $statusType = 'status4';
1681 $labelStatus = $langs->transnoentitiesnoconv('Active');
1682 }
1683 } else {
1684 if ($status == self::STATUS_SUSPENDED) {
1685 $statusType = 'status6';
1686 $labelStatus = $langs->transnoentitiesnoconv('Disabled');
1687 } else {
1688 $statusType = 'status0';
1689 $labelStatus = $langs->transnoentitiesnoconv('Draft');
1690 }
1691 }
1692 } elseif ($mode == 5 || $mode == 6) {
1693 $prefix = '';
1694 if ($mode == 5) {
1695 $prefix = 'Short';
1696 }
1697 if ($recur) {
1698 if ($status == self::STATUS_SUSPENDED) {
1699 $statusType = 'status6';
1700 $labelStatus = $langs->transnoentitiesnoconv('Disabled');
1701 } else {
1702 $statusType = 'status4';
1703 $labelStatus = $langs->transnoentitiesnoconv('Active');
1704 }
1705 } else {
1706 if ($status == self::STATUS_SUSPENDED) {
1707 $statusType = 'status6';
1708 $labelStatus = $langs->transnoentitiesnoconv('Disabled');
1709 } else {
1710 $statusType = 'status0';
1711 $labelStatus = $langs->transnoentitiesnoconv('Draft');
1712 }
1713 }
1714 }
1715
1716 $labelStatusShort = $labelStatus;
1717
1718 return dolGetStatus($labelStatus, $labelStatusShort, '', $statusType, $mode);
1719 }
1720
1729 public function initAsSpecimen($option = '')
1730 {
1731 global $user, $langs, $conf;
1732
1733 $now = dol_now();
1734 $arraynow = dol_getdate($now);
1735 $nownotime = dol_mktime(0, 0, 0, $arraynow['mon'], $arraynow['mday'], $arraynow['year']);
1736
1737 // Load array of products prodids
1738 $num_prods = 0;
1739 $prodids = array();
1740
1741 $sql = 'SELECT rowid';
1742 $sql .= ' FROM ' .MAIN_DB_PREFIX. 'product';
1743 $sql .= ' WHERE entity IN (' .getEntity('product'). ')';
1744 $sql .= $this->db->plimit(100);
1745
1746 $resql = $this->db->query($sql);
1747 if ($resql) {
1748 $num_prods = $this->db->num_rows($resql);
1749 $i = 0;
1750 while ($i < $num_prods) {
1751 $i++;
1752 $row = $this->db->fetch_row($resql);
1753 $prodids[$i] = $row[0];
1754 }
1755 }
1756
1757 // Initialize parameters
1758 $this->id = 0;
1759 $this->ref = 'SPECIMEN';
1760 $this->title = 'SPECIMEN';
1761 $this->specimen = 1;
1762 $this->socid = 1;
1763 $this->date = $nownotime;
1764 $this->date_lim_reglement = $nownotime + 3600 * 24 * 30;
1765 $this->cond_reglement_id = 1;
1766 $this->cond_reglement_code = 'RECEP';
1767 $this->date_lim_reglement = $this->calculate_date_lim_reglement();
1768 $this->mode_reglement_id = 0; // Not forced to show payment mode CHQ + VIR
1769 $this->mode_reglement_code = ''; // Not forced to show payment mode CHQ + VIR
1770 $this->note_public = 'This is a comment (public)';
1771 $this->note_private = 'This is a comment (private)';
1772 $this->note = 'This is a comment (private)';
1773 $this->fk_incoterms = 0;
1774 $this->location_incoterms = '';
1775
1776 if (empty($option) || $option != 'nolines') {
1777 // Lines
1778 $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)
1779 $xnbp = 0;
1780 while ($xnbp < $nbp) {
1781 $line = new FactureLigne($this->db);
1782 $line->desc = $langs->trans('Description'). ' ' .$xnbp;
1783 $line->qty = 1;
1784 $line->subprice = 100;
1785 $line->tva_tx = 19.6;
1786 $line->localtax1_tx = 0;
1787 $line->localtax2_tx = 0;
1788 $line->remise_percent = 0;
1789 if ($xnbp == 1) { // Qty is negative (product line)
1790 $prodid = mt_rand(1, $num_prods);
1791 $line->fk_product = $prodids[$prodid];
1792 $line->qty = -1;
1793 $line->total_ht = -100;
1794 $line->total_ttc = -119.6;
1795 $line->total_tva = -19.6;
1796 } elseif ($xnbp == 2) { // UP is negative (free line)
1797 $line->subprice = -100;
1798 $line->total_ht = -100;
1799 $line->total_ttc = -119.6;
1800 $line->total_tva = -19.6;
1801 $line->remise_percent = 0;
1802 } elseif ($xnbp == 3) { // Discount is 50% (product line)
1803 $prodid = mt_rand(1, $num_prods);
1804 $line->fk_product = $prodids[$prodid];
1805 $line->total_ht = 50;
1806 $line->total_ttc = 59.8;
1807 $line->total_tva = 9.8;
1808 $line->remise_percent = 50;
1809 } else { // (product line)
1810 $prodid = mt_rand(1, $num_prods);
1811 $line->fk_product = $prodids[$prodid];
1812 $line->total_ht = 100;
1813 $line->total_ttc = 119.6;
1814 $line->total_tva = 19.6;
1815 $line->remise_percent = 00;
1816 }
1817
1818 $this->lines[$xnbp] = $line;
1819 $xnbp++;
1820
1821 $this->total_ht += $line->total_ht;
1822 $this->total_tva += $line->total_tva;
1823 $this->total_ttc += $line->total_ttc;
1824 }
1825 $this->revenuestamp = 0;
1826
1827 // Add a line "offered"
1828 $line = new FactureLigne($this->db);
1829 $line->desc = $langs->trans('Description'). ' (offered line)';
1830 $line->qty = 1;
1831 $line->subprice = 100;
1832 $line->tva_tx = 19.6;
1833 $line->localtax1_tx = 0;
1834 $line->localtax2_tx = 0;
1835 $line->remise_percent = 100;
1836 $line->total_ht = 0;
1837 $line->total_ttc = 0; // 90 * 1.196
1838 $line->total_tva = 0;
1839 $prodid = mt_rand(1, $num_prods);
1840 $line->fk_product = $prodids[$prodid];
1841
1842 $this->lines[$xnbp] = $line;
1843 $xnbp++;
1844 }
1845
1846 $this->usenewprice = 0;
1847
1848 return 1;
1849 }
1850
1859 public static function replaceThirdparty(DoliDB $dbs, $origin_id, $dest_id)
1860 {
1861 $tables = array(
1862 'facture_fourn_rec'
1863 );
1864
1865 return CommonObject::commonReplaceThirdparty($dbs, $origin_id, $dest_id, $tables);
1866 }
1867
1875 public function setFrequencyAndUnit($frequency, $unit)
1876 {
1877 if (!$this->table_element) {
1878 dol_syslog(get_class($this). '::setFrequencyAndUnit was called on object with property table_element not defined', LOG_ERR);
1879 return -1;
1880 }
1881
1882 if (!empty($frequency) && empty($unit)) {
1883 dol_syslog(get_class($this). '::setFrequencyAndUnit was called on object with params frequency defined but unit not defined', LOG_ERR);
1884 return -2;
1885 }
1886
1887 $sql = "UPDATE ".MAIN_DB_PREFIX.$this->table_element;
1888 $sql .= " SET frequency = ".($frequency ? ((int) $frequency) : "NULL");
1889 if (!empty($unit)) {
1890 $sql .= ", unit_frequency = '".$this->db->escape($unit)."'";
1891 }
1892 $sql .= " WHERE rowid = ".((int) $this->id);
1893
1894 dol_syslog(get_class($this).'::setFrequencyAndUnit', LOG_DEBUG);
1895
1896 if ($this->db->query($sql)) {
1897 $this->frequency = $frequency;
1898 if (!empty($unit)) {
1899 $this->unit_frequency = $unit;
1900 }
1901 return 1;
1902 } else {
1903 $this->error = $this->db->lasterror();
1904 return -1;
1905 }
1906 }
1907
1915 public function setNextDate($date, $increment_nb_gen_done = 0)
1916 {
1917 if (!$this->table_element) {
1918 dol_syslog(get_class($this).'::setNextDate was called on object with property table_element not defined', LOG_ERR);
1919 return -1;
1920 }
1921 $sql = "UPDATE ".MAIN_DB_PREFIX.$this->table_element;
1922 $sql .= " SET date_when = " .($date ? "'".$this->db->idate($date)."'" : "NULL");
1923 if ($increment_nb_gen_done > 0) {
1924 $sql .= ", nb_gen_done = nb_gen_done + 1";
1925 }
1926 $sql .= " WHERE rowid = " . (int) $this->id;
1927
1928 dol_syslog(get_class($this).'::setNextDate', LOG_DEBUG);
1929
1930 if ($this->db->query($sql)) {
1931 $this->date_when = $date;
1932 if ($increment_nb_gen_done > 0) {
1933 $this->nb_gen_done++;
1934 }
1935 return 1;
1936 } else {
1937 $this->error = $this->db->lasterror();
1938 return -1;
1939 }
1940 }
1941
1948 public function setMaxPeriod($nb)
1949 {
1950 if (!$this->table_element) {
1951 dol_syslog(get_class($this).'::setMaxPeriod was called on object with property table_element not defined', LOG_ERR);
1952 return -1;
1953 }
1954
1955 if (empty($nb)) {
1956 $nb = 0;
1957 }
1958
1959 $sql = "UPDATE ".MAIN_DB_PREFIX.$this->table_element;
1960 $sql .= " SET nb_gen_max = ". (int) $nb;
1961 $sql .= " WHERE rowid = " . (int) $this->id;
1962
1963 dol_syslog(get_class($this).'::setMaxPeriod', LOG_DEBUG);
1964
1965 if ($this->db->query($sql)) {
1966 $this->nb_gen_max = $nb;
1967 return 1;
1968 } else {
1969 dol_print_error($this->db);
1970 return -1;
1971 }
1972 }
1973
1980 public function setAutoValidate($validate)
1981 {
1982 if (!$this->table_element) {
1983 dol_syslog(get_class($this).'::setAutoValidate was called on object with property table_element not defined', LOG_ERR);
1984 return -1;
1985 }
1986
1987 $sql = "UPDATE ".MAIN_DB_PREFIX.$this->table_element;
1988 $sql .= " SET auto_validate = ".((int) $validate);
1989 $sql .= " WHERE rowid = " . (int) $this->id;
1990
1991 dol_syslog(get_class($this).'::setAutoValidate', LOG_DEBUG);
1992
1993 if ($this->db->query($sql)) {
1994 $this->auto_validate = $validate;
1995 return 1;
1996 } else {
1997 dol_print_error($this->db);
1998 return -1;
1999 }
2000 }
2001
2008 public function setGeneratePdf($validate)
2009 {
2010 if (!$this->table_element) {
2011 dol_syslog(get_class($this).'::setGeneratePdf was called on object with property table_element not defined', LOG_ERR);
2012 return -1;
2013 }
2014
2015 $sql = "UPDATE ".MAIN_DB_PREFIX.$this->table_element;
2016 $sql .= " SET generate_pdf = ". (int) $validate;
2017 $sql .= " WHERE rowid = " . (int) $this->id;
2018
2019 dol_syslog(get_class($this).'::setGeneratePdf', LOG_DEBUG);
2020
2021 if ($this->db->query($sql)) {
2022 $this->generate_pdf = $validate;
2023 return 1;
2024 } else {
2025 dol_print_error($this->db);
2026 return -1;
2027 }
2028 }
2029
2036 public function setModelPdf($model)
2037 {
2038 if (!$this->table_element) {
2039 dol_syslog(get_class($this).'::setModelPdf was called on object with property table_element not defined', LOG_ERR);
2040 return -1;
2041 }
2042
2043 $sql = "UPDATE ".MAIN_DB_PREFIX.$this->table_element;
2044 $sql .= " SET modelpdf = '".$this->db->escape($model)."'";
2045 $sql .= " WHERE rowid = " . (int) $this->id;
2046
2047 dol_syslog(get_class($this).'::setModelPdf', LOG_DEBUG);
2048
2049 if ($this->db->query($sql)) {
2050 $this->model_pdf = $model;
2051 return 1;
2052 } else {
2053 dol_print_error($this->db);
2054 return -1;
2055 }
2056 }
2057}
$object ref
Definition info.php:89
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.
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.
call_trigger($triggerName, $user)
Call trigger based on this instance.
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)
create($user, $facFournId, $notrigger=0)
Create a predefined supplier invoice.
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)
Class to manage invoice lines.
Class to manage products or services.
Class to manage Dolibarr users.
dol_time_plus_duree($time, $duration_value, $duration_unit, $ruleforendofmonth=0)
Add a delay to a date.
Definition date.lib.php:125
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...
GETPOSTINT($paramname, $method=0)
Return the value of a $_GET or $_POST supervariable, converted into integer.
price2num($amount, $rounding='', $option=0)
Function that return a number with universal decimal format (decimal separator is '.
img_object($titlealt, $picto, $moreatt='', $pictoisfullpath=0, $srconly=0, $notitle=0, $allowothertags=array())
Show a picto called object_picto (generic function)
dol_now($mode='auto')
Return date for now.
getLocalTaxesFromRate($vatrate, $local, $buyer, $seller, $firstparamisid=0)
Get type and rate of localtaxes for a particular vat rate/country of a thirdparty.
dol_print_date($time, $format='', $tzoutput='auto', $outputlangs=null, $encodetooutput=false)
Output date in a string format according to outputlangs (or langs if not defined).
dolGetStatus($statusLabel='', $statusLabelShort='', $html='', $statusType='status0', $displayMode=0, $url='', $params=array())
Output the badge of a status.
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...
global $conf
The following vars must be defined: $type2label $form $conf, $lang, The following vars may also be de...
Definition member.php:79
calcul_price_total($qty, $pu, $remise_percent_ligne, $txtva, $uselocaltax1_rate, $uselocaltax2_rate, $remise_percent_global, $price_base_type, $info_bits, $type, $seller='', $localtaxes_array=[], $progress=100, $multicurrency_tx=1, $pu_devise=0, $multicurrency_code='')
Calculate totals (net, vat, ...) of a line.
Definition price.lib.php:90
if(preg_match('/crypted:/i', $dolibarr_main_db_pass)||!empty($dolibarr_main_db_encrypted_pass)) $conf db type
Definition repair.php:150