dolibarr 21.0.0-alpha
factureligne.class.php
Go to the documentation of this file.
1<?php
2/* Copyright (C) 2002-2007 Rodolphe Quiedeville <rodolphe@quiedeville.org>
3 * Copyright (C) 2004-2013 Laurent Destailleur <eldy@users.sourceforge.net>
4 * Copyright (C) 2004 Sebastien Di Cintio <sdicintio@ressource-toi.org>
5 * Copyright (C) 2004 Benoit Mortier <benoit.mortier@opensides.be>
6 * Copyright (C) 2005 Marc Barilley / Ocebo <marc@ocebo.com>
7 * Copyright (C) 2005-2014 Regis Houssin <regis.houssin@inodbox.com>
8 * Copyright (C) 2006 Andre Cianfarani <acianfa@free.fr>
9 * Copyright (C) 2007 Franky Van Liedekerke <franky.van.liedekerke@telenet.be>
10 * Copyright (C) 2010-2020 Juanjo Menent <jmenent@2byte.es>
11 * Copyright (C) 2012-2014 Christophe Battarel <christophe.battarel@altairis.fr>
12 * Copyright (C) 2012-2015 Marcos García <marcosgdf@gmail.com>
13 * Copyright (C) 2012 Cédric Salvador <csalvador@gpcsolutions.fr>
14 * Copyright (C) 2012-2014 Raphaël Doursenaud <rdoursenaud@gpcsolutions.fr>
15 * Copyright (C) 2013 Cedric Gross <c.gross@kreiz-it.fr>
16 * Copyright (C) 2013 Florian Henry <florian.henry@open-concept.pro>
17 * Copyright (C) 2016-2022 Ferran Marcet <fmarcet@2byte.es>
18 * Copyright (C) 2018-2024 Alexandre Spangaro <alexandre@inovea-conseil.com>
19 * Copyright (C) 2018 Nicolas ZABOURI <info@inovea-conseil.com>
20 * Copyright (C) 2022 Sylvain Legrand <contact@infras.fr>
21 * Copyright (C) 2023 Gauthier VERDOL <gauthier.verdol@atm-consulting.fr>
22 * Copyright (C) 2023 Nick Fragoulis
23 * Copyright (C) 2024 MDW <mdeweerd@users.noreply.github.com>
24 * Copyright (C) 2024 Frédéric France <frederic.france@free.fr>
25 *
26 * This program is free software; you can redistribute it and/or modify
27 * it under the terms of the GNU General Public License as published by
28 * the Free Software Foundation; either version 3 of the License, or
29 * (at your option) any later version.
30 *
31 * This program is distributed in the hope that it will be useful,
32 * but WITHOUT ANY WARRANTY; without even the implied warranty of
33 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
34 * GNU General Public License for more details.
35 *
36 * You should have received a copy of the GNU General Public License
37 * along with this program. If not, see <https://www.gnu.org/licenses/>.
38 */
39
46require_once DOL_DOCUMENT_ROOT.'/core/class/commoninvoice.class.php';
47require_once DOL_DOCUMENT_ROOT.'/core/class/commonobjectline.class.php';
48require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php';
49require_once DOL_DOCUMENT_ROOT.'/margin/lib/margins.lib.php';
50
56{
60 public $element = 'facturedet';
61
65 public $table_element = 'facturedet';
66
70 public $oldline;
71
73
76 public $fk_facture;
80 public $fk_parent_line;
81
85 public $desc;
89 public $ref_ext;
90
94 public $localtax1_type; // Local tax 1 type
98 public $localtax2_type; // Local tax 2 type
102 public $fk_remise_except; // Link to line into llx_remise_except
106 public $rang = 0;
110 public $fk_fournprice;
114 public $pa_ht;
118 public $marge_tx;
122 public $marque_tx;
123
127 public $tva_npr;
128
132 public $remise_percent;
133
137 public $batch;
141 public $fk_warehouse;
142
143
147 public $origin;
151 public $origin_id;
152
156 public $fk_code_ventilation = 0;
157
158
162 public $date_start;
166 public $date_end;
167
171 public $skip_update_total; // Skip update price total for special lines
172
176 public $situation_percent;
177
181 public $fk_prev_id;
182
183
189 public function __construct($db)
190 {
191 $this->db = $db;
192 }
193
200 public function fetch($rowid)
201 {
202 $sql = 'SELECT fd.rowid, fd.fk_facture, fd.fk_parent_line, fd.fk_product, fd.product_type, fd.label as custom_label, fd.description, fd.price, fd.qty, fd.vat_src_code, fd.tva_tx,';
203 $sql .= ' fd.localtax1_tx, fd. localtax2_tx, fd.remise, fd.remise_percent, fd.fk_remise_except, fd.subprice, fd.ref_ext,';
204 $sql .= ' fd.date_start as date_start, fd.date_end as date_end, fd.fk_product_fournisseur_price as fk_fournprice, fd.buy_price_ht as pa_ht,';
205 $sql .= ' fd.info_bits, fd.special_code, fd.total_ht, fd.total_tva, fd.total_ttc, fd.total_localtax1, fd.total_localtax2, fd.rang,';
206 $sql .= ' fd.fk_code_ventilation,';
207 $sql .= ' fd.fk_unit, fd.fk_user_author, fd.fk_user_modif,';
208 $sql .= ' fd.situation_percent, fd.fk_prev_id,';
209 $sql .= ' fd.multicurrency_subprice,';
210 $sql .= ' fd.multicurrency_total_ht,';
211 $sql .= ' fd.multicurrency_total_tva,';
212 $sql .= ' fd.multicurrency_total_ttc,';
213 $sql .= ' p.ref as product_ref, p.label as product_label, p.description as product_desc';
214 $sql .= ' FROM '.MAIN_DB_PREFIX.'facturedet as fd';
215 $sql .= ' LEFT JOIN '.MAIN_DB_PREFIX.'product as p ON fd.fk_product = p.rowid';
216 $sql .= ' WHERE fd.rowid = '.((int) $rowid);
217
218 $result = $this->db->query($sql);
219 if ($result) {
220 $objp = $this->db->fetch_object($result);
221
222 if (!$objp) {
223 $this->error = 'InvoiceLine with id '. $rowid .' not found sql='.$sql;
224 return 0;
225 }
226
227 $this->rowid = $objp->rowid;
228 $this->id = $objp->rowid;
229 $this->fk_facture = $objp->fk_facture;
230 $this->fk_parent_line = $objp->fk_parent_line;
231 $this->label = $objp->custom_label;
232 $this->desc = $objp->description;
233 $this->qty = $objp->qty;
234 $this->subprice = $objp->subprice;
235 $this->ref_ext = $objp->ref_ext;
236 $this->vat_src_code = $objp->vat_src_code;
237 $this->tva_tx = $objp->tva_tx;
238 $this->localtax1_tx = $objp->localtax1_tx;
239 $this->localtax2_tx = $objp->localtax2_tx;
240 $this->remise_percent = $objp->remise_percent;
241 $this->fk_remise_except = $objp->fk_remise_except;
242 $this->fk_product = $objp->fk_product;
243 $this->product_type = $objp->product_type;
244 $this->date_start = $this->db->jdate($objp->date_start);
245 $this->date_end = $this->db->jdate($objp->date_end);
246 $this->info_bits = $objp->info_bits;
247 $this->tva_npr = (($objp->info_bits & 1) == 1) ? 1 : 0;
248 $this->special_code = $objp->special_code;
249 $this->total_ht = $objp->total_ht;
250 $this->total_tva = $objp->total_tva;
251 $this->total_localtax1 = $objp->total_localtax1;
252 $this->total_localtax2 = $objp->total_localtax2;
253 $this->total_ttc = $objp->total_ttc;
254 $this->fk_code_ventilation = $objp->fk_code_ventilation;
255 $this->rang = $objp->rang;
256 $this->fk_fournprice = $objp->fk_fournprice;
257 $marginInfos = getMarginInfos($objp->subprice, $objp->remise_percent, $objp->tva_tx, $objp->localtax1_tx, $objp->localtax2_tx, $this->fk_fournprice, $objp->pa_ht);
258 $this->pa_ht = $marginInfos[0];
259 $this->marge_tx = $marginInfos[1];
260 $this->marque_tx = $marginInfos[2];
261
262 $this->ref = $objp->product_ref; // deprecated
263
264 $this->product_ref = $objp->product_ref;
265 $this->product_label = $objp->product_label;
266 $this->product_desc = $objp->product_desc;
267
268 $this->fk_unit = $objp->fk_unit;
269 $this->fk_user_modif = $objp->fk_user_modif;
270 $this->fk_user_author = $objp->fk_user_author;
271
272 $this->situation_percent = $objp->situation_percent;
273 $this->fk_prev_id = $objp->fk_prev_id;
274
275 $this->multicurrency_subprice = $objp->multicurrency_subprice;
276 $this->multicurrency_total_ht = $objp->multicurrency_total_ht;
277 $this->multicurrency_total_tva = $objp->multicurrency_total_tva;
278 $this->multicurrency_total_ttc = $objp->multicurrency_total_ttc;
279
280 $this->fetch_optionals();
281
282 $this->db->free($result);
283
284 return 1;
285 } else {
286 $this->error = $this->db->lasterror();
287 return -1;
288 }
289 }
290
298 public function insert($notrigger = 0, $noerrorifdiscountalreadylinked = 0)
299 {
300 global $langs, $user;
301
302 $error = 0;
303
304 $pa_ht_isemptystring = (empty($this->pa_ht) && $this->pa_ht == ''); // If true, we can use a default value. If this->pa_ht = '0', we must use '0'.
305
306 dol_syslog(get_class($this)."::insert rang=".$this->rang, LOG_DEBUG);
307
308 // Clean parameters
309 $this->desc = trim($this->desc);
310 if (empty($this->tva_tx)) {
311 $this->tva_tx = 0;
312 }
313 if (empty($this->localtax1_tx)) {
314 $this->localtax1_tx = 0;
315 }
316 if (empty($this->localtax2_tx)) {
317 $this->localtax2_tx = 0;
318 }
319 if (empty($this->localtax1_type)) {
320 $this->localtax1_type = 0;
321 }
322 if (empty($this->localtax2_type)) {
323 $this->localtax2_type = 0;
324 }
325 if (empty($this->total_localtax1)) {
326 $this->total_localtax1 = 0;
327 }
328 if (empty($this->total_localtax2)) {
329 $this->total_localtax2 = 0;
330 }
331 if (empty($this->rang)) {
332 $this->rang = 0;
333 }
334 if (empty($this->remise_percent)) {
335 $this->remise_percent = 0;
336 }
337 if (empty($this->info_bits)) {
338 $this->info_bits = 0;
339 }
340 if (empty($this->subprice)) {
341 $this->subprice = 0;
342 }
343 if (empty($this->ref_ext)) {
344 $this->ref_ext = '';
345 }
346 if (empty($this->special_code)) {
347 $this->special_code = 0;
348 }
349 if (empty($this->fk_parent_line)) {
350 $this->fk_parent_line = 0;
351 }
352 if (empty($this->fk_prev_id)) {
353 $this->fk_prev_id = 0;
354 }
355 if (!isset($this->situation_percent) || $this->situation_percent > 100 || (string) $this->situation_percent == '') {
356 $this->situation_percent = 100;
357 }
358
359 if (empty($this->pa_ht)) {
360 $this->pa_ht = 0;
361 }
362 if (empty($this->multicurrency_subprice)) {
363 $this->multicurrency_subprice = 0;
364 }
365 if (empty($this->multicurrency_total_ht)) {
366 $this->multicurrency_total_ht = 0;
367 }
368 if (empty($this->multicurrency_total_tva)) {
369 $this->multicurrency_total_tva = 0;
370 }
371 if (empty($this->multicurrency_total_ttc)) {
372 $this->multicurrency_total_ttc = 0;
373 }
374
375 // if buy price not defined, define buyprice as configured in margin admin
376 if ($this->pa_ht == 0 && $pa_ht_isemptystring) {
377 $result = $this->defineBuyPrice($this->subprice, $this->remise_percent, $this->fk_product);
378 if ($result < 0) {
379 return $result;
380 } else {
381 $this->pa_ht = $result;
382 }
383 }
384
385 // Check parameters
386 if ($this->product_type < 0) {
387 $this->error = 'ErrorProductTypeMustBe0orMore';
388 return -1;
389 }
390 if (!empty($this->fk_product) && $this->fk_product > 0) {
391 // Check product exists
392 $result = Product::isExistingObject('product', $this->fk_product);
393 if ($result <= 0) {
394 $this->error = 'ErrorProductIdDoesNotExists';
395 dol_syslog(get_class($this)."::insert Error ".$this->error, LOG_ERR);
396 return -1;
397 }
398 }
399
400 $this->db->begin();
401
402 // Update line in database
403 $sql = 'INSERT INTO '.MAIN_DB_PREFIX.'facturedet';
404 $sql .= ' (fk_facture, fk_parent_line, label, description, qty,';
405 $sql .= ' vat_src_code, tva_tx, localtax1_tx, localtax2_tx, localtax1_type, localtax2_type,';
406 $sql .= ' fk_product, product_type, remise_percent, subprice, ref_ext, fk_remise_except,';
407 $sql .= ' date_start, date_end, fk_code_ventilation,';
408 $sql .= ' rang, special_code, fk_product_fournisseur_price, buy_price_ht,';
409 $sql .= ' info_bits, total_ht, total_tva, total_ttc, total_localtax1, total_localtax2,';
410 $sql .= ' situation_percent, fk_prev_id,';
411 $sql .= ' fk_unit, fk_user_author, fk_user_modif,';
412 $sql .= ' fk_multicurrency, multicurrency_code, multicurrency_subprice, multicurrency_total_ht, multicurrency_total_tva, multicurrency_total_ttc,';
413 $sql .= ' batch, fk_warehouse';
414 $sql .= ')';
415 $sql .= " VALUES (".$this->fk_facture.",";
416 $sql .= " ".($this->fk_parent_line > 0 ? $this->fk_parent_line : "null").",";
417 $sql .= " ".(!empty($this->label) ? "'".$this->db->escape($this->label)."'" : "null").",";
418 $sql .= " '".$this->db->escape($this->desc)."',";
419 $sql .= " ".price2num($this->qty).",";
420 $sql .= " ".(empty($this->vat_src_code) ? "''" : "'".$this->db->escape($this->vat_src_code)."'").",";
421 $sql .= " ".price2num($this->tva_tx).",";
422 $sql .= " ".price2num($this->localtax1_tx).",";
423 $sql .= " ".price2num($this->localtax2_tx).",";
424 $sql .= " '".$this->db->escape($this->localtax1_type)."',";
425 $sql .= " '".$this->db->escape($this->localtax2_type)."',";
426 $sql .= ' '.((!empty($this->fk_product) && $this->fk_product > 0) ? $this->fk_product : "null").',';
427 $sql .= " ".((int) $this->product_type).",";
428 $sql .= " ".price2num($this->remise_percent).",";
429 $sql .= " ".price2num($this->subprice).",";
430 $sql .= " '".$this->db->escape($this->ref_ext)."',";
431 $sql .= ' '.(!empty($this->fk_remise_except) ? $this->fk_remise_except : "null").',';
432 $sql .= " ".(!empty($this->date_start) ? "'".$this->db->idate($this->date_start)."'" : "null").",";
433 $sql .= " ".(!empty($this->date_end) ? "'".$this->db->idate($this->date_end)."'" : "null").",";
434 $sql .= ' '.((int) $this->fk_code_ventilation).',';
435 $sql .= ' '.((int) $this->rang).',';
436 $sql .= ' '.((int) $this->special_code).',';
437 $sql .= ' '.(!empty($this->fk_fournprice) ? $this->fk_fournprice : "null").',';
438 $sql .= ' '.price2num($this->pa_ht).',';
439 $sql .= " '".$this->db->escape($this->info_bits)."',";
440 $sql .= " ".price2num($this->total_ht).",";
441 $sql .= " ".price2num($this->total_tva).",";
442 $sql .= " ".price2num($this->total_ttc).",";
443 $sql .= " ".price2num($this->total_localtax1).",";
444 $sql .= " ".price2num($this->total_localtax2);
445 $sql .= ", ".((float) $this->situation_percent);
446 $sql .= ", ".(!empty($this->fk_prev_id) ? $this->fk_prev_id : "null");
447 $sql .= ", ".(!$this->fk_unit ? 'NULL' : $this->fk_unit);
448 $sql .= ", ".((int) $user->id);
449 $sql .= ", ".((int) $user->id);
450 $sql .= ", ".(int) $this->fk_multicurrency;
451 $sql .= ", '".$this->db->escape($this->multicurrency_code)."'";
452 $sql .= ", ".price2num($this->multicurrency_subprice);
453 $sql .= ", ".price2num($this->multicurrency_total_ht);
454 $sql .= ", ".price2num($this->multicurrency_total_tva);
455 $sql .= ", ".price2num($this->multicurrency_total_ttc);
456 $sql .= ", '".$this->db->escape($this->batch)."'";
457 $sql .= ", ".((int) $this->fk_warehouse);
458 $sql .= ')';
459
460 dol_syslog(get_class($this)."::insert", LOG_DEBUG);
461 $resql = $this->db->query($sql);
462 if ($resql) {
463 $this->id = $this->db->last_insert_id(MAIN_DB_PREFIX.'facturedet');
464 $this->rowid = $this->id; // For backward compatibility
465
466 if (!$error) {
467 $result = $this->insertExtraFields();
468 if ($result < 0) {
469 $error++;
470 }
471 }
472
473 // If fk_remise_except is defined, the discount is linked to the invoice
474 // which flags it as "consumed".
475 if ($this->fk_remise_except) {
476 $discount = new DiscountAbsolute($this->db);
477 $result = $discount->fetch($this->fk_remise_except);
478 if ($result >= 0) {
479 // Check if discount was found
480 if ($result > 0) {
481 // Check if discount not already affected to another invoice
482 if ($discount->fk_facture_line > 0) {
483 if (empty($noerrorifdiscountalreadylinked)) {
484 $this->error = $langs->trans("ErrorDiscountAlreadyUsed", $discount->id);
485 dol_syslog(get_class($this)."::insert Error ".$this->error, LOG_ERR);
486 $this->db->rollback();
487 return -3;
488 }
489 } else {
490 $result = $discount->link_to_invoice($this->rowid, 0);
491 if ($result < 0) {
492 $this->error = $discount->error;
493 dol_syslog(get_class($this)."::insert Error ".$this->error, LOG_ERR);
494 $this->db->rollback();
495 return -3;
496 }
497 }
498 } else {
499 $this->error = $langs->trans("ErrorADiscountThatHasBeenRemovedIsIncluded");
500 dol_syslog(get_class($this)."::insert Error ".$this->error, LOG_ERR);
501 $this->db->rollback();
502 return -3;
503 }
504 } else {
505 $this->error = $discount->error;
506 dol_syslog(get_class($this)."::insert Error ".$this->error, LOG_ERR);
507 $this->db->rollback();
508 return -3;
509 }
510 }
511
512 if (!$notrigger) {
513 // Call trigger
514 $result = $this->call_trigger('LINEBILL_INSERT', $user);
515 if ($result < 0) {
516 $this->db->rollback();
517 return -2;
518 }
519 // End call triggers
520 }
521
522 $this->db->commit();
523 return $this->id;
524 } else {
525 $this->error = $this->db->lasterror();
526 $this->db->rollback();
527 return -2;
528 }
529 }
530
538 public function update($user = null, $notrigger = 0)
539 {
540 global $user, $conf;
541
542 $error = 0;
543
544 $pa_ht_isemptystring = (empty($this->pa_ht) && $this->pa_ht == ''); // If true, we can use a default value. If this->pa_ht = '0', we must use '0'.
545
546 // Clean parameters
547 $this->desc = trim($this->desc);
548 if (empty($this->ref_ext)) {
549 $this->ref_ext = '';
550 }
551 if (empty($this->tva_tx)) {
552 $this->tva_tx = 0;
553 }
554 if (empty($this->localtax1_tx)) {
555 $this->localtax1_tx = 0;
556 }
557 if (empty($this->localtax2_tx)) {
558 $this->localtax2_tx = 0;
559 }
560 if (empty($this->localtax1_type)) {
561 $this->localtax1_type = 0;
562 }
563 if (empty($this->localtax2_type)) {
564 $this->localtax2_type = 0;
565 }
566 if (empty($this->total_localtax1)) {
567 $this->total_localtax1 = 0;
568 }
569 if (empty($this->total_localtax2)) {
570 $this->total_localtax2 = 0;
571 }
572 if (empty($this->remise_percent)) {
573 $this->remise_percent = 0;
574 }
575 if (empty($this->info_bits)) {
576 $this->info_bits = 0;
577 }
578 if (empty($this->special_code)) {
579 $this->special_code = 0;
580 }
581 if (empty($this->product_type)) {
582 $this->product_type = 0;
583 }
584 if (empty($this->fk_parent_line)) {
585 $this->fk_parent_line = 0;
586 }
587 if (!isset($this->situation_percent) || $this->situation_percent > 100 || (string) $this->situation_percent == '') {
588 $this->situation_percent = 100;
589 }
590 if (empty($this->pa_ht)) {
591 $this->pa_ht = 0;
592 }
593
594 if (empty($this->multicurrency_subprice)) {
595 $this->multicurrency_subprice = 0;
596 }
597 if (empty($this->multicurrency_total_ht)) {
598 $this->multicurrency_total_ht = 0;
599 }
600 if (empty($this->multicurrency_total_tva)) {
601 $this->multicurrency_total_tva = 0;
602 }
603 if (empty($this->multicurrency_total_ttc)) {
604 $this->multicurrency_total_ttc = 0;
605 }
606
607 // Check parameters
608 if ($this->product_type < 0) {
609 return -1;
610 }
611
612 // if buy price not provided, define buyprice as configured in margin admin
613 if ($this->pa_ht == 0 && $pa_ht_isemptystring) {
614 // We call defineBuyPrice only if data was not provided (if input was '0', we will not go here and value will remaine '0')
615 $result = $this->defineBuyPrice($this->subprice, $this->remise_percent, $this->fk_product);
616 if ($result < 0) {
617 return $result;
618 } else {
619 $this->pa_ht = $result;
620 }
621 }
622
623 $this->db->begin();
624
625 // Update line in database
626 $sql = "UPDATE ".MAIN_DB_PREFIX."facturedet SET";
627 $sql .= " description='".$this->db->escape($this->desc)."'";
628 $sql .= ", ref_ext='".$this->db->escape($this->ref_ext)."'";
629 $sql .= ", label=".(!empty($this->label) ? "'".$this->db->escape($this->label)."'" : "null");
630 $sql .= ", subprice=".price2num($this->subprice);
631 $sql .= ", remise_percent=".price2num($this->remise_percent);
632 if ($this->fk_remise_except) {
633 $sql .= ", fk_remise_except=".$this->fk_remise_except;
634 } else {
635 $sql .= ", fk_remise_except=null";
636 }
637 $sql .= ", vat_src_code = '".(empty($this->vat_src_code) ? '' : $this->db->escape($this->vat_src_code))."'";
638 $sql .= ", tva_tx=".price2num($this->tva_tx);
639 $sql .= ", localtax1_tx=".price2num($this->localtax1_tx);
640 $sql .= ", localtax2_tx=".price2num($this->localtax2_tx);
641 $sql .= ", localtax1_type='".$this->db->escape($this->localtax1_type)."'";
642 $sql .= ", localtax2_type='".$this->db->escape($this->localtax2_type)."'";
643 $sql .= ", qty=".price2num($this->qty);
644 $sql .= ", date_start=".(!empty($this->date_start) ? "'".$this->db->idate($this->date_start)."'" : "null");
645 $sql .= ", date_end=".(!empty($this->date_end) ? "'".$this->db->idate($this->date_end)."'" : "null");
646 $sql .= ", product_type=".$this->product_type;
647 $sql .= ", info_bits='".$this->db->escape($this->info_bits)."'";
648 $sql .= ", special_code=" . (int) $this->special_code;
649 if (empty($this->skip_update_total)) {
650 $sql .= ", total_ht=".price2num($this->total_ht);
651 $sql .= ", total_tva=".price2num($this->total_tva);
652 $sql .= ", total_ttc=".price2num($this->total_ttc);
653 $sql .= ", total_localtax1=".price2num($this->total_localtax1);
654 $sql .= ", total_localtax2=".price2num($this->total_localtax2);
655 }
656 $sql .= ", fk_product_fournisseur_price=".(!empty($this->fk_fournprice) ? "'".$this->db->escape($this->fk_fournprice)."'" : "null");
657 $sql .= ", buy_price_ht=".(($this->pa_ht || (string) $this->pa_ht === '0') ? price2num($this->pa_ht) : "null"); // $this->pa_ht should always be defined (set to 0 or to sell price depending on option)
658 $sql .= ", fk_parent_line=".($this->fk_parent_line > 0 ? $this->fk_parent_line : "null");
659 if (!empty($this->rang)) {
660 $sql .= ", rang=".((int) $this->rang);
661 }
662 $sql .= ", situation_percent = ".((float) $this->situation_percent);
663 $sql .= ", fk_unit = ".(!$this->fk_unit ? 'NULL' : $this->fk_unit);
664 $sql .= ", fk_user_modif = ".((int) $user->id);
665
666 // Multicurrency
667 $sql .= ", multicurrency_subprice=".price2num($this->multicurrency_subprice);
668 $sql .= ", multicurrency_total_ht=".price2num($this->multicurrency_total_ht);
669 $sql .= ", multicurrency_total_tva=".price2num($this->multicurrency_total_tva);
670 $sql .= ", multicurrency_total_ttc=".price2num($this->multicurrency_total_ttc);
671
672 $sql .= ", batch = '".$this->db->escape($this->batch)."'";
673 $sql .= ", fk_warehouse = ".((int) $this->fk_warehouse);
674
675 $sql .= " WHERE rowid = ".((int) $this->rowid);
676
677 dol_syslog(get_class($this)."::update", LOG_DEBUG);
678 $resql = $this->db->query($sql);
679 if ($resql) {
680 if (!$error) {
681 $this->id = $this->rowid;
682 $result = $this->insertExtraFields();
683 if ($result < 0) {
684 $error++;
685 }
686 }
687
688 if (!$error && !$notrigger) {
689 // Call trigger
690 $result = $this->call_trigger('LINEBILL_MODIFY', $user);
691 if ($result < 0) {
692 $this->db->rollback();
693 return -2;
694 }
695 // End call triggers
696 }
697 $this->db->commit();
698 return 1;
699 } else {
700 $this->error = $this->db->error();
701 $this->db->rollback();
702 return -2;
703 }
704 }
705
713 public function delete($tmpuser = null, $notrigger = 0)
714 {
715 global $user;
716
717 $this->db->begin();
718
719 // Call trigger
720 if (empty($notrigger)) {
721 $result = $this->call_trigger('LINEBILL_DELETE', $user);
722 if ($result < 0) {
723 $this->db->rollback();
724 return -1;
725 }
726 }
727 // End call triggers
728
729 // extrafields
730 $result = $this->deleteExtraFields();
731 if ($result < 0) {
732 $this->db->rollback();
733 return -1;
734 }
735
736 // Free discount linked to invoice line
737 $sql = 'UPDATE '.MAIN_DB_PREFIX.'societe_remise_except';
738 $sql .= ' SET fk_facture_line = NULL';
739 $sql .= ' WHERE fk_facture_line = '.((int) $this->id);
740
741 dol_syslog(get_class($this)."::deleteline", LOG_DEBUG);
742 $result = $this->db->query($sql);
743 if (!$result) {
744 $this->error = $this->db->error();
745 $this->errors[] = $this->error;
746 $this->db->rollback();
747 return -1;
748 }
749
750 $sql = 'UPDATE '.MAIN_DB_PREFIX.'element_time';
751 $sql .= ' SET invoice_id = NULL, invoice_line_id = NULL';
752 $sql .= ' WHERE invoice_line_id = '.((int) $this->id);
753 if (!$this->db->query($sql)) {
754 $this->error = $this->db->error()." sql=".$sql;
755 $this->errors[] = $this->error;
756 $this->db->rollback();
757 return -1;
758 }
759
760 $sql = "DELETE FROM ".MAIN_DB_PREFIX."facturedet WHERE rowid = ".((int) $this->id);
761
762 if ($this->db->query($sql)) {
763 $this->db->commit();
764 return 1;
765 } else {
766 $this->error = $this->db->error()." sql=".$sql;
767 $this->errors[] = $this->error;
768 $this->db->rollback();
769 return -1;
770 }
771 }
772
773 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
780 public function update_total()
781 {
782 // phpcs:enable
783 $this->db->begin();
784 dol_syslog(get_class($this)."::update_total", LOG_DEBUG);
785
786 // Clean parameters
787 if (empty($this->total_localtax1)) {
788 $this->total_localtax1 = 0;
789 }
790 if (empty($this->total_localtax2)) {
791 $this->total_localtax2 = 0;
792 }
793
794 // Update line in database
795 $sql = "UPDATE ".MAIN_DB_PREFIX."facturedet SET";
796 $sql .= " total_ht=".price2num($this->total_ht);
797 $sql .= ",total_tva=".price2num($this->total_tva);
798 $sql .= ",total_localtax1=".price2num($this->total_localtax1);
799 $sql .= ",total_localtax2=".price2num($this->total_localtax2);
800 $sql .= ",total_ttc=".price2num($this->total_ttc);
801 $sql .= " WHERE rowid = ".((int) $this->rowid);
802
803 dol_syslog(get_class($this)."::update_total", LOG_DEBUG);
804
805 $resql = $this->db->query($sql);
806 if ($resql) {
807 $this->db->commit();
808 return 1;
809 } else {
810 $this->error = $this->db->error();
811 $this->db->rollback();
812 return -2;
813 }
814 }
815
816 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
826 public function get_prev_progress($invoiceid, $include_credit_note = true)
827 {
828 // phpcs:enable
829 global $invoicecache;
830
831 if (is_null($this->fk_prev_id) || empty($this->fk_prev_id) || $this->fk_prev_id == "") {
832 return 0;
833 } else {
834 // If invoice is not a situation invoice, this->fk_prev_id is used for something else
835 if (!isset($invoicecache[$invoiceid])) {
836 $invoicecache[$invoiceid] = new Facture($this->db);
837 $invoicecache[$invoiceid]->fetch($invoiceid);
838 }
839 if ($invoicecache[$invoiceid]->type != Facture::TYPE_SITUATION) {
840 return 0;
841 }
842
843 $sql = "SELECT situation_percent FROM ".MAIN_DB_PREFIX."facturedet";
844 $sql .= " WHERE rowid = ".((int) $this->fk_prev_id);
845
846 $resql = $this->db->query($sql);
847
848 if ($resql && $this->db->num_rows($resql) > 0) {
849 $returnPercent = 0;
850
851 $obj = $this->db->fetch_object($resql);
852 if ($obj) {
853 $returnPercent = (float) $obj->situation_percent;
854 }
855
856 if ($include_credit_note) {
857 $sql = 'SELECT fd.situation_percent FROM '.MAIN_DB_PREFIX.'facturedet fd';
858 $sql .= ' JOIN '.MAIN_DB_PREFIX.'facture f ON (f.rowid = fd.fk_facture) ';
859 $sql .= " WHERE fd.fk_prev_id = ".((int) $this->fk_prev_id);
860 $sql .= " AND f.situation_cycle_ref = ".((int) $invoicecache[$invoiceid]->situation_cycle_ref); // Prevent cycle outed
861 $sql .= " AND f.type = ".Facture::TYPE_CREDIT_NOTE;
862
863 $res = $this->db->query($sql);
864 if ($res) {
865 while ($obj = $this->db->fetch_object($res)) {
866 $returnPercent += (float) $obj->situation_percent;
867 }
868 } else {
869 dol_print_error($this->db);
870 }
871 }
872
873 return $returnPercent;
874 } else {
875 $this->error = $this->db->error();
876 dol_syslog(get_class($this)."::select Error ".$this->error, LOG_ERR);
877 $this->db->rollback();
878 return -1;
879 }
880 }
881 }
882
883 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
893 public function getAllPrevProgress($invoiceid, $include_credit_note = true)
894 {
895 // phpcs:enable
896 global $invoicecache;
897
898 if (is_null($this->fk_prev_id) || empty($this->fk_prev_id) || $this->fk_prev_id == "") {
899 return 0;
900 } else {
901 // If invoice is not a situation invoice, this->fk_prev_id is used for something else
902 if (!isset($invoicecache[$invoiceid])) {
903 $invoicecache[$invoiceid] = new Facture($this->db);
904 $invoicecache[$invoiceid]->fetch($invoiceid);
905 }
906 if ($invoicecache[$invoiceid]->type != Facture::TYPE_SITUATION) {
907 return 0;
908 }
909
910 $all_found = false;
911 $lastprevid = $this->fk_prev_id;
912 $cumulated_percent = 0.0;
913
914 while (!$all_found) {
915 $sql = "SELECT situation_percent, fk_prev_id FROM ".MAIN_DB_PREFIX."facturedet WHERE rowid = ".((int) $lastprevid);
916 $resql = $this->db->query($sql);
917
918 if ($resql && $this->db->num_rows($resql) > 0) {
919 $obj = $this->db->fetch_object($resql);
920 $cumulated_percent += floatval($obj->situation_percent);
921
922 if ($include_credit_note) {
923 $sql_credit_note = 'SELECT fd.situation_percent FROM '.MAIN_DB_PREFIX.'facturedet fd';
924 $sql_credit_note .= ' JOIN '.MAIN_DB_PREFIX.'facture f ON (f.rowid = fd.fk_facture) ';
925 $sql_credit_note .= " WHERE fd.fk_prev_id = ".((int) $lastprevid);
926 $sql_credit_note .= " AND f.situation_cycle_ref = ".((int) $invoicecache[$invoiceid]->situation_cycle_ref); // Prevent cycle outed
927 $sql_credit_note .= " AND f.type = ".Facture::TYPE_CREDIT_NOTE;
928
929 $res_credit_note = $this->db->query($sql_credit_note);
930 if ($res_credit_note) {
931 while ($cn = $this->db->fetch_object($res_credit_note)) {
932 $cumulated_percent += floatval($cn->situation_percent);
933 }
934 } else {
935 dol_print_error($this->db);
936 }
937 }
938
939 // Si fk_prev_id, on continue
940 if ($obj->fk_prev_id) {
941 $lastprevid = $obj->fk_prev_id;
942 } else { // Sinon on stoppe la boucle
943 $all_found = true;
944 }
945 } else {
946 $this->error = $this->db->error();
947 dol_syslog(get_class($this)."::select Error ".$this->error, LOG_ERR);
948 $this->db->rollback();
949 return -1;
950 }
951 }
952 return $cumulated_percent;
953 }
954 }
955}
$object ref
Definition info.php:79
Parent class of all other business classes for details of elements (invoices, contracts,...
fetch_optionals($rowid=null, $optionsArray=null)
Function to get extra fields of an object into $this->array_options This method is in most cases call...
defineBuyPrice($unitPrice=0.0, $discountPercent=0.0, $fk_product=0)
Get buy price to use for margin calculation.
static isExistingObject($element, $id, $ref='', $ref_ext='')
Check if an object id or ref exists If you don't need or want to instantiate the object and just need...
deleteExtraFields()
Delete all extra fields values for the current object.
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 absolute discounts.
Class to manage invoices.
const TYPE_SITUATION
Situation invoice.
Class to manage invoice lines.
insert($notrigger=0, $noerrorifdiscountalreadylinked=0)
Insert line into database.
get_prev_progress($invoiceid, $include_credit_note=true)
Returns situation_percent of the previous line.
fetch($rowid)
Load invoice line from database.
update($user=null, $notrigger=0)
Update line into database.
__construct($db)
Constructor.
getAllPrevProgress($invoiceid, $include_credit_note=true)
Returns situation_percent of all the previous line.
update_total()
Update DB line fields total_xxx Used by migration.
price2num($amount, $rounding='', $option=0)
Function that return a number with universal decimal format (decimal separator is '.
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.
getMarginInfos($pv_ht, $remise_percent, $tva_tx, $localtax1_tx, $localtax2_tx, $fk_pa, $pa_ht)
Return an array with margins information of a line.
if(preg_match('/crypted:/i', $dolibarr_main_db_pass)||!empty($dolibarr_main_db_encrypted_pass)) $conf db type
Definition repair.php:137