dolibarr 25.0.0-alpha
fournisseur.orderline.class.php
Go to the documentation of this file.
1<?php
2/* Copyright (C) 2003-2006 Rodolphe Quiedeville <rodolphe@quiedeville.org>
3 * Copyright (C) 2004-2017 Laurent Destailleur <eldy@users.sourceforge.net>
4 * Copyright (C) 2005-2012 Regis Houssin <regis.houssin@inodbox.com>
5 * Copyright (C) 2007 Franky Van Liedekerke <franky.van.liedekerke@telenet.be>
6 * Copyright (C) 2010-2020 Juanjo Menent <jmenent@2byte.es>
7 * Copyright (C) 2010-2018 Philippe Grand <philippe.grand@atoo-net.com>
8 * Copyright (C) 2012-2015 Marcos García <marcosgdf@gmail.com>
9 * Copyright (C) 2013 Florian Henry <florian.henry@open-concept.pro>
10 * Copyright (C) 2013 Cédric Salvador <csalvador@gpcsolutions.fr>
11 * Copyright (C) 2018 Nicolas ZABOURI <info@inovea-conseil.com>
12 * Copyright (C) 2018-2025 Frédéric France <frederic.france@free.fr>
13 * Copyright (C) 2018-2022 Ferran Marcet <fmarcet@2byte.es>
14 * Copyright (C) 2021 Josep Lluís Amador <joseplluis@lliuretic.cat>
15 * Copyright (C) 2022 Gauthier VERDOL <gauthier.verdol@atm-consulting.fr>
16 * Copyright (C) 2024 Solution Libre SAS <contact@solution-libre.fr>
17 * Copyright (C) 2024-2026 MDW <mdeweerd@users.noreply.github.com>
18 * Copyright (C) 2024 William Mead <william.mead@manchenumerique.fr>
19 * Copyright (C) 2026 Pierre Ardoin <developpeur@lesmetiersdubatiment.fr>
20 *
21 * This program is free software; you can redistribute it and/or modify
22 * it under the terms of the GNU General Public License as published by
23 * the Free Software Foundation; either version 3 of the License, or
24 * (at your option) any later version.
25 *
26 * This program is distributed in the hope that it will be useful,
27 * but WITHOUT ANY WARRANTY; without even the implied warranty of
28 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
29 * GNU General Public License for more details.
30 *
31 * You should have received a copy of the GNU General Public License
32 * along with this program. If not, see <https://www.gnu.org/licenses/>.
33 */
34
41require_once DOL_DOCUMENT_ROOT.'/core/class/commonobjectline.class.php';
42require_once DOL_DOCUMENT_ROOT.'/multicurrency/class/multicurrency.class.php';
43
48{
52 public $element = 'commande_fournisseurdet';
53
57 public $table_element = 'commande_fournisseurdet';
58
62 public $parent_element = 'commande_fournisseur';
63
67 public $fk_parent_attribute = 'fk_commande_fournisseur';
68
72 public $oldline;
73
78 public $fk_commande;
79
80 // From llx_commande_fournisseurdet
84 public $fk_parent_line;
85
89 public $fk_facture;
90
94 public $rang = 0;
95
99 public $special_code = 0;
100
106 public $pu_ht;
107
111 public $date_start;
112
116 public $date_end;
117
121 public $fk_fournprice;
122
126 public $packaging;
127
131 public $pa_ht;
132
133 // From llx_product_fournisseur_price
134
139 public $ref_supplier;
140
146 public $ref_fourn;
147
151 public $remise;
152
153
159 public function __construct($db)
160 {
161 $this->db = $db;
162 }
163
170 public function fetch($rowid)
171 {
172 $sql = 'SELECT cd.rowid, cd.fk_commande, cd.fk_product, cd.product_type, cd.description, cd.qty, cd.tva_tx, cd.special_code,';
173 $sql .= ' cd.localtax1_tx, cd.localtax2_tx, cd.localtax1_type, cd.localtax2_type, cd.ref as ref_supplier,';
174 $sql .= ' cd.remise, cd.remise_percent, cd.subprice, cd.subprice_ttc,';
175 $sql .= ' cd.info_bits, cd.total_ht, cd.total_tva, cd.total_ttc,';
176 $sql .= ' cd.total_localtax1, cd.total_localtax2,';
177 $sql .= ' p.ref as product_ref, p.label as product_label, p.description as product_desc,';
178 $sql .= ' cd.date_start, cd.date_end, cd.fk_unit, cd.extraparams,';
179 $sql .= ' cd.multicurrency_subprice, cd.multicurrency_subprice_ttc, cd.multicurrency_total_ht, cd.multicurrency_total_tva, cd.multicurrency_total_ttc,';
180 $sql .= ' c.fk_soc as socid';
181 $sql .= ' FROM '.$this->db->prefix().'commande_fournisseur as c, '.$this->db->prefix().'commande_fournisseurdet as cd';
182 $sql .= ' LEFT JOIN '.$this->db->prefix().'product as p ON cd.fk_product = p.rowid';
183 $sql .= ' WHERE cd.fk_commande = c.rowid AND cd.rowid = '.((int) $rowid);
184
185 $result = $this->db->query($sql);
186 if ($result) {
187 $objp = $this->db->fetch_object($result);
188
189 if (!empty($objp)) {
190 $this->rowid = $objp->rowid;
191 $this->id = $objp->rowid;
192 $this->fk_commande = $objp->fk_commande;
193 $this->desc = $objp->description;
194 $this->qty = $objp->qty;
195 $this->ref_fourn = $objp->ref_supplier;
196 $this->ref_supplier = $objp->ref_supplier;
197 $this->subprice = $objp->subprice;
198 $this->subprice_ttc = $objp->subprice_ttc;
199 $this->tva_tx = $objp->tva_tx;
200 $this->localtax1_tx = $objp->localtax1_tx;
201 $this->localtax2_tx = $objp->localtax2_tx;
202 $this->localtax1_type = $objp->localtax1_type;
203 $this->localtax2_type = $objp->localtax2_type;
204 $this->remise = $objp->remise;
205 $this->remise_percent = $objp->remise_percent;
206 $this->fk_product = $objp->fk_product;
207 $this->info_bits = $objp->info_bits;
208 $this->total_ht = $objp->total_ht;
209 $this->total_tva = $objp->total_tva;
210 $this->total_localtax1 = $objp->total_localtax1;
211 $this->total_localtax2 = $objp->total_localtax2;
212 $this->total_ttc = $objp->total_ttc;
213 $this->product_type = $objp->product_type;
214 $this->special_code = $objp->special_code;
215
216 $this->ref = $objp->product_ref;
217
218 $this->product_ref = $objp->product_ref;
219 $this->product_label = $objp->product_label;
220 $this->product_desc = $objp->product_desc;
221
222 if (getDolGlobalInt('PRODUCT_USE_SUPPLIER_PACKAGING')) {
223 // TODO We should not fetch this properties into the fetch_lines. This is NOT properties of a line.
224 // Move this into another method and call it when required.
225
226 // Take better packaging for $objp->qty (first supplier ref quantity <= $objp->qty)
227 $sqlsearchpackage = 'SELECT rowid, packaging FROM '.$this->db->prefix()."product_fournisseur_price";
228 $sqlsearchpackage .= ' WHERE entity IN ('.getEntity('productsupplierprice').")";
229 $sqlsearchpackage .= " AND fk_product = ".((int) $objp->fk_product);
230 $sqlsearchpackage .= " AND ref_fourn = '".$this->db->escape($objp->ref_supplier)."'";
231 $sqlsearchpackage .= " AND quantity <= ".((float) $objp->qty); // required to be qualified
232 $sqlsearchpackage .= " AND (packaging IS NULL OR packaging = 0 OR packaging <= ".((float) $objp->qty).")"; // required to be qualified
233 $sqlsearchpackage .= " AND fk_soc = ".((int) $objp->socid);
234 $sqlsearchpackage .= " ORDER BY packaging ASC"; // Take the smaller package first
235 $sqlsearchpackage .= " LIMIT 1";
236
237 $resqlsearchpackage = $this->db->query($sqlsearchpackage);
238 if ($resqlsearchpackage) {
239 $objsearchpackage = $this->db->fetch_object($resqlsearchpackage);
240 if ($objsearchpackage) {
241 $this->fk_fournprice = $objsearchpackage->rowid;
242 $this->packaging = (float) $objsearchpackage->packaging;
243 }
244 } else {
245 $this->error = $this->db->lasterror();
246 return -1;
247 }
248 }
249
250 $this->date_start = $this->db->jdate($objp->date_start);
251 $this->date_end = $this->db->jdate($objp->date_end);
252 $this->fk_unit = $objp->fk_unit;
253
254 $this->extraparams = !empty($objp->extraparams) ? (array) json_decode($objp->extraparams, true) : array();
255
256 $this->multicurrency_subprice = $objp->multicurrency_subprice;
257 $this->multicurrency_subprice_ttc = $objp->multicurrency_subprice_ttc;
258 $this->multicurrency_total_ht = $objp->multicurrency_total_ht;
259 $this->multicurrency_total_tva = $objp->multicurrency_total_tva;
260 $this->multicurrency_total_ttc = $objp->multicurrency_total_ttc;
261
262 $this->fetch_optionals();
263
264 $this->db->free($result);
265 return 1;
266 } else {
267 $this->error = 'Supplier order line with id='.$rowid.' not found';
268 dol_syslog(get_class($this)."::fetch Error ".$this->error, LOG_ERR);
269 return 0;
270 }
271 } else {
272 dol_print_error($this->db);
273 return -1;
274 }
275 }
276
283 public function insert($notrigger = 0)
284 {
285 global $conf, $user;
286
287 $error = 0;
288
289 dol_syslog(get_class($this)."::insert rang=".$this->rang);
290
291 // Clean parameters
292 if (empty($this->tva_tx)) {
293 $this->tva_tx = 0;
294 }
295 if (empty($this->localtax1_tx)) {
296 $this->localtax1_tx = 0;
297 }
298 if (empty($this->localtax2_tx)) {
299 $this->localtax2_tx = 0;
300 }
301 if (empty($this->localtax1_type)) {
302 $this->localtax1_type = '0';
303 }
304 if (empty($this->localtax2_type)) {
305 $this->localtax2_type = '0';
306 }
307 if (empty($this->total_localtax1)) {
308 $this->total_localtax1 = 0;
309 }
310 if (empty($this->total_localtax2)) {
311 $this->total_localtax2 = 0;
312 }
313 if (empty($this->rang)) {
314 $this->rang = 0;
315 }
316 if (empty($this->remise_percent)) {
317 $this->remise_percent = 0;
318 }
319 if (empty($this->subprice_ttc)) {
320 $this->subprice_ttc = 0;
321 }
322 if (empty($this->info_bits)) {
323 $this->info_bits = 0;
324 }
325 if (empty($this->special_code)) {
326 $this->special_code = 0;
327 }
328 if (empty($this->fk_parent_line)) {
329 $this->fk_parent_line = 0;
330 }
331 if (empty($this->pa_ht)) {
332 $this->pa_ht = 0;
333 }
334
335 // Multicurrency
336 if (!empty($this->multicurrency_code)) {
337 list($this->fk_multicurrency, $this->multicurrency_tx) = MultiCurrency::getIdAndTxFromCode($this->db, $this->multicurrency_code);
338 }
339 if (empty($this->fk_multicurrency)) {
340 $this->multicurrency_code = $conf->currency;
341 $this->fk_multicurrency = 0;
342 $this->multicurrency_tx = 1;
343 }
344
345 // Check parameters
346 if ($this->product_type < 0) {
347 return -1;
348 }
349
350 $this->db->begin();
351
352 // Insert line into database
353 $sql = 'INSERT INTO '.$this->db->prefix().$this->table_element;
354 $sql .= " (fk_commande, label, description, date_start, date_end,";
355 $sql .= " fk_product, product_type, special_code, rang,";
356 $sql .= " qty, vat_src_code, tva_tx, localtax1_tx, localtax2_tx, localtax1_type, localtax2_type, remise_percent, subprice, subprice_ttc, ref,";
357 $sql .= " total_ht, total_tva, total_localtax1, total_localtax2, total_ttc, fk_unit,";
358 $sql .= " fk_multicurrency, multicurrency_code, multicurrency_subprice, multicurrency_total_ht, multicurrency_total_tva, multicurrency_total_ttc,";
359 $sql .= " fk_parent_line)";
360 $sql .= " VALUES (".((int) $this->fk_commande).", '".$this->db->escape($this->label)."','".$this->db->escape($this->desc)."',";
361 $sql .= " ".($this->date_start ? "'".$this->db->idate($this->date_start)."'" : "null").",";
362 $sql .= " ".($this->date_end ? "'".$this->db->idate($this->date_end)."'" : "null").",";
363 if ($this->fk_product) {
364 $sql .= ((int) $this->fk_product).",";
365 } else {
366 $sql .= "null,";
367 }
368 $sql .= ((int) $this->product_type).",";
369 $sql .= ((int) $this->special_code).",";
370 $sql .= "'".$this->db->escape((string) $this->rang)."',";
371 $sql .= "'".$this->db->escape((string) $this->qty)."', ";
372 $sql .= " ".(empty($this->vat_src_code) ? "''" : "'".$this->db->escape((string) $this->vat_src_code)."'").",";
373 $sql .= " ".price2num($this->tva_tx).", ";
374 $sql .= " ".price2num($this->localtax1_tx).",";
375 $sql .= " ".price2num($this->localtax2_tx).",";
376 $sql .= " '".$this->db->escape($this->localtax1_type)."',";
377 $sql .= " '".$this->db->escape($this->localtax2_type)."',";
378 $sql .= " ".((float) $this->remise_percent).", ".price2num($this->subprice, 'MU').", ".price2num($this->subprice_ttc, 'MU').", '".$this->db->escape($this->ref_supplier)."',";
379 $sql .= " ".price2num($this->total_ht).",";
380 $sql .= " ".price2num($this->total_tva).",";
381 $sql .= " ".price2num($this->total_localtax1).",";
382 $sql .= " ".price2num($this->total_localtax2).",";
383 $sql .= " ".price2num($this->total_ttc).",";
384 $sql .= ($this->fk_unit ? "'".$this->db->escape((string) $this->fk_unit)."'" : "null");
385 $sql .= ", ".($this->fk_multicurrency ? ((int) $this->fk_multicurrency) : "null");
386 $sql .= ", '".$this->db->escape($this->multicurrency_code)."'";
387 $sql .= ", ".($this->multicurrency_subprice ? price2num($this->multicurrency_subprice) : '0');
388 $sql .= ", ".($this->multicurrency_total_ht ? price2num($this->multicurrency_total_ht) : '0');
389 $sql .= ", ".($this->multicurrency_total_tva ? price2num($this->multicurrency_total_tva) : '0');
390 $sql .= ", ".($this->multicurrency_total_ttc ? price2num($this->multicurrency_total_ttc) : '0');
391 $sql .= ", ".((!empty($this->fk_parent_line) && $this->fk_parent_line > 0) ? ((int) $this->fk_parent_line) : 'null');
392 $sql .= ")";
393
394 dol_syslog(get_class($this)."::insert", LOG_DEBUG);
395 $resql = $this->db->query($sql);
396 if ($resql) {
397 $this->id = $this->db->last_insert_id($this->db->prefix().$this->table_element);
398 $this->rowid = $this->id;
399
400 if (!$error) {
401 $result = $this->insertExtraFields();
402 if ($result < 0) {
403 $error++;
404 }
405 }
406
407 if (!$error && !$notrigger) {
408 // Call trigger
409 $result = $this->call_trigger('LINEORDER_SUPPLIER_CREATE', $user);
410 if ($result < 0) {
411 $error++;
412 }
413 // End call triggers
414 }
415
416 if (!$error) {
417 $this->db->commit();
418 return 1;
419 }
420
421 foreach ($this->errors as $errmsg) {
422 dol_syslog(get_class($this)."::delete ".$errmsg, LOG_ERR);
423 $this->errors[] = ($this->errors ? ', '.$errmsg : $errmsg);
424 }
425 $this->db->rollback();
426 return -1 * $error;
427 } else {
428 $this->errors[] = $this->db->error();
429 $this->db->rollback();
430 return -2;
431 }
432 }
439 public function update($notrigger = 0)
440 {
441 global $user;
442
443 $error = 0;
444
445 $this->db->begin();
446
447 $sql = "UPDATE ".$this->db->prefix().$this->table_element." SET";
448 $sql .= " description='".$this->db->escape($this->desc)."'";
449 $sql .= ", ref='".$this->db->escape($this->ref_supplier)."'";
450 $sql .= ", subprice = ".((float) price2num($this->subprice));
451 $sql .= ", subprice_ttc = ".((float) price2num($this->subprice_ttc));
452 $sql .= ", remise_percent = ".((float) price2num($this->remise_percent));
453 $sql .= ", vat_src_code = '".$this->db->escape((string) $this->vat_src_code)."'";
454 $sql .= ", tva_tx = ".((float) price2num($this->tva_tx));
455 $sql .= ", localtax1_tx = ".((float) price2num($this->localtax1_tx));
456 $sql .= ", localtax2_tx = ".((float) price2num($this->localtax2_tx));
457 $sql .= ", localtax1_type = '".$this->db->escape($this->localtax1_type)."'";
458 $sql .= ", localtax2_type = '".$this->db->escape($this->localtax2_type)."'";
459 $sql .= ", qty = ".((float) price2num($this->qty));
460 $sql .= ", date_start = ".(!empty($this->date_start) ? "'".$this->db->idate($this->date_start)."'" : "null");
461 $sql .= ", date_end = ".(!empty($this->date_end) ? "'".$this->db->idate($this->date_end)."'" : "null");
462 $sql .= ", info_bits = ".((int) $this->info_bits);
463 $sql .= ", total_ht = ".((float) price2num($this->total_ht));
464 $sql .= ", total_tva = ".((float) price2num($this->total_tva));
465 $sql .= ", total_localtax1 = ".((float) price2num($this->total_localtax1));
466 $sql .= ", total_localtax2 = ".((float) price2num($this->total_localtax2));
467 $sql .= ", total_ttc = ".((float) price2num($this->total_ttc));
468 $sql .= ", product_type = ".((int) $this->product_type);
469 $sql .= ", special_code = ".((int) $this->special_code);
470 $sql .= ", fk_unit = ".($this->fk_unit ? ((int) $this->fk_unit) : "null");
471 if (!empty($this->rang)) {
472 $sql .= ", rang=".((int) $this->rang);
473 }
474 // Multicurrency
475 $sql .= ", multicurrency_subprice = ".((float) price2num($this->multicurrency_subprice));
476 $sql .= ", multicurrency_subprice_ttc = ".((float) price2num($this->multicurrency_subprice_ttc));
477 $sql .= ", multicurrency_total_ht = ".((float) price2num($this->multicurrency_total_ht));
478 $sql .= ", multicurrency_total_tva = ".((float) price2num($this->multicurrency_total_tva));
479 $sql .= ", multicurrency_total_ttc = ".((float) price2num($this->multicurrency_total_ttc));
480
481 $sql .= " WHERE rowid = ".((int) $this->id);
482
483 dol_syslog(get_class($this)."::updateline", LOG_DEBUG);
484 $resql = $this->db->query($sql);
485 if ($resql) {
486 if (!$error) {
487 $result = $this->insertExtraFields();
488 if ($result < 0) {
489 $error++;
490 }
491 }
492
493 if (!$error && !$notrigger) {
494 // Call trigger
495 $result = $this->call_trigger('LINEORDER_SUPPLIER_MODIFY', $user);
496 if ($result < 0) {
497 $this->db->rollback();
498 return -1;
499 }
500 // End call triggers
501 }
502
503 if (!$error) {
504 $this->db->commit();
505 return 1;
506 } else {
507 $this->db->rollback();
508 return -1;
509 }
510 } else {
511 $this->error = $this->db->lasterror();
512 $this->db->rollback();
513 return -1;
514 }
515 }
516
524 public function delete($user, $notrigger = 0)
525 {
526 if (empty($user)) {
527 global $user;
528 }
529
530 $error = 0;
531
532 $this->db->begin();
533
534 // extrafields
535 $result = $this->deleteExtraFields();
536 if ($result < 0) {
537 $this->db->rollback();
538 return -1;
539 }
540
541 $sql1 = 'UPDATE '.$this->db->prefix()."commandedet SET fk_commandefourndet = NULL WHERE fk_commandefourndet = ".((int) $this->id);
542 $resql = $this->db->query($sql1);
543 if (!$resql) {
544 $this->db->rollback();
545 return -1;
546 }
547
548 $sql2 = 'DELETE FROM '.$this->db->prefix()."commande_fournisseurdet WHERE rowid = ".((int) $this->id);
549
550 dol_syslog(__METHOD__, LOG_DEBUG);
551 $resql = $this->db->query($sql2);
552 if ($resql) {
553 if (!$notrigger) {
554 // Call trigger
555 $result = $this->call_trigger('LINEORDER_SUPPLIER_DELETE', $user);
556 if ($result < 0) {
557 $error++;
558 }
559 // End call triggers
560 }
561
562 if (!$error) {
563 $this->db->commit();
564 return 1;
565 }
566
567 foreach ($this->errors as $errmsg) {
568 dol_syslog(get_class($this)."::delete ".$errmsg, LOG_ERR);
569 $this->error .= ($this->error ? ', '.$errmsg : $errmsg);
570 }
571 $this->db->rollback();
572 return -1 * $error;
573 } else {
574 $this->error = $this->db->lasterror();
575 return -1;
576 }
577 }
578}
$object ref
Definition info.php:90
Class to manage line orders.
update($notrigger=0)
Update the line object into db.
insert($notrigger=0)
Insert line into database.
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...
deleteExtraFields()
Delete all extra fields values for the current object.
insertExtraFields($trigger='', $userused=null)
Add/Update all extra fields values for the current object.
Superclass for orders classes.
static getIdAndTxFromCode($dbs, $code, $date_document=0)
Get id and rate of currency from code.
if(!isModEnabled('ai')||!getDolGlobalString('AI_ASSISTANT_ENABLED')) global $conf
The main.inc.php has been included so the following variable are now defined:
price2num($amount, $rounding='', $option=0)
Function that return a number with universal decimal format (decimal separator is '.
getDolGlobalInt($key, $default=0)
Return a Dolibarr global constant int value.
dol_syslog($message, $level=LOG_INFO, $ident=0, $suffixinfilename='', $restricttologhandler='', $logcontext=null)
Write log message into outputs.
dol_print_error($db=null, $error='', $errors=null)
Displays error message system with all the information to facilitate the diagnosis and the escalation...