dolibarr 23.0.3
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-2024 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-2025 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,';
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_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->info_bits)) {
320 $this->info_bits = 0;
321 }
322 if (empty($this->special_code)) {
323 $this->special_code = 0;
324 }
325 if (empty($this->fk_parent_line)) {
326 $this->fk_parent_line = 0;
327 }
328 if (empty($this->pa_ht)) {
329 $this->pa_ht = 0;
330 }
331
332 // Multicurrency
333 if (!empty($this->multicurrency_code)) {
334 list($this->fk_multicurrency, $this->multicurrency_tx) = MultiCurrency::getIdAndTxFromCode($this->db, $this->multicurrency_code);
335 }
336 if (empty($this->fk_multicurrency)) {
337 $this->multicurrency_code = $conf->currency;
338 $this->fk_multicurrency = 0;
339 $this->multicurrency_tx = 1;
340 }
341
342 // Check parameters
343 if ($this->product_type < 0) {
344 return -1;
345 }
346
347 $this->db->begin();
348
349 // Insertion dans base de la ligne
350 $sql = 'INSERT INTO '.$this->db->prefix().$this->table_element;
351 $sql .= " (fk_commande, label, description, date_start, date_end,";
352 $sql .= " fk_product, product_type, special_code, rang,";
353 $sql .= " qty, vat_src_code, tva_tx, localtax1_tx, localtax2_tx, localtax1_type, localtax2_type, remise_percent, subprice, subprice_ttc, ref,";
354 $sql .= " total_ht, total_tva, total_localtax1, total_localtax2, total_ttc, fk_unit,";
355 $sql .= " fk_multicurrency, multicurrency_code, multicurrency_subprice, multicurrency_total_ht, multicurrency_total_tva, multicurrency_total_ttc,";
356 $sql .= " fk_parent_line)";
357 $sql .= " VALUES (".$this->fk_commande.", '".$this->db->escape($this->label)."','".$this->db->escape($this->desc)."',";
358 $sql .= " ".($this->date_start ? "'".$this->db->idate($this->date_start)."'" : "null").",";
359 $sql .= " ".($this->date_end ? "'".$this->db->idate($this->date_end)."'" : "null").",";
360 if ($this->fk_product) {
361 $sql .= $this->fk_product.",";
362 } else {
363 $sql .= "null,";
364 }
365 $sql .= ((int) $this->product_type).",";
366 $sql .= ((int) $this->special_code).",";
367 $sql .= "'".$this->db->escape((string) $this->rang)."',";
368 $sql .= "'".$this->db->escape((string) $this->qty)."', ";
369 $sql .= " ".(empty($this->vat_src_code) ? "''" : "'".$this->db->escape((string) $this->vat_src_code)."'").",";
370 $sql .= " ".price2num($this->tva_tx).", ";
371 $sql .= " ".price2num($this->localtax1_tx).",";
372 $sql .= " ".price2num($this->localtax2_tx).",";
373 $sql .= " '".$this->db->escape($this->localtax1_type)."',";
374 $sql .= " '".$this->db->escape($this->localtax2_type)."',";
375 $sql .= " ".((float) $this->remise_percent).", ".price2num($this->subprice, 'MU').", ".price2num($this->subprice_ttc, 'MU').", '".$this->db->escape($this->ref_supplier)."',";
376 $sql .= " ".price2num($this->total_ht).",";
377 $sql .= " ".price2num($this->total_tva).",";
378 $sql .= " ".price2num($this->total_localtax1).",";
379 $sql .= " ".price2num($this->total_localtax2).",";
380 $sql .= " ".price2num($this->total_ttc).",";
381 $sql .= ($this->fk_unit ? "'".$this->db->escape((string) $this->fk_unit)."'" : "null");
382 $sql .= ", ".($this->fk_multicurrency ? ((int) $this->fk_multicurrency) : "null");
383 $sql .= ", '".$this->db->escape($this->multicurrency_code)."'";
384 $sql .= ", ".($this->multicurrency_subprice ? price2num($this->multicurrency_subprice) : '0');
385 $sql .= ", ".($this->multicurrency_total_ht ? price2num($this->multicurrency_total_ht) : '0');
386 $sql .= ", ".($this->multicurrency_total_tva ? price2num($this->multicurrency_total_tva) : '0');
387 $sql .= ", ".($this->multicurrency_total_ttc ? price2num($this->multicurrency_total_ttc) : '0');
388 $sql .= ", ".((!empty($this->fk_parent_line) && $this->fk_parent_line > 0) ? $this->fk_parent_line : 'null');
389 $sql .= ")";
390
391 dol_syslog(get_class($this)."::insert", LOG_DEBUG);
392 $resql = $this->db->query($sql);
393 if ($resql) {
394 $this->id = $this->db->last_insert_id($this->db->prefix().$this->table_element);
395 $this->rowid = $this->id;
396
397 if (!$error) {
398 $result = $this->insertExtraFields();
399 if ($result < 0) {
400 $error++;
401 }
402 }
403
404 if (!$error && !$notrigger) {
405 // Call trigger
406 $result = $this->call_trigger('LINEORDER_SUPPLIER_CREATE', $user);
407 if ($result < 0) {
408 $error++;
409 }
410 // End call triggers
411 }
412
413 if (!$error) {
414 $this->db->commit();
415 return 1;
416 }
417
418 foreach ($this->errors as $errmsg) {
419 dol_syslog(get_class($this)."::delete ".$errmsg, LOG_ERR);
420 $this->errors[] = ($this->errors ? ', '.$errmsg : $errmsg);
421 }
422 $this->db->rollback();
423 return -1 * $error;
424 } else {
425 $this->errors[] = $this->db->error();
426 $this->db->rollback();
427 return -2;
428 }
429 }
436 public function update($notrigger = 0)
437 {
438 global $user;
439
440 $error = 0;
441
442 $this->db->begin();
443
444 $sql = "UPDATE ".$this->db->prefix().$this->table_element." SET";
445 $sql .= " description='".$this->db->escape($this->desc)."'";
446 $sql .= ", ref='".$this->db->escape($this->ref_supplier)."'";
447 $sql .= ", subprice = ".((float) price2num($this->subprice));
448 $sql .= ", subprice_ttc = ".((float) price2num($this->subprice_ttc));
449 $sql .= ", remise_percent = ".((float) price2num($this->remise_percent));
450 $sql .= ", vat_src_code = '".$this->db->escape((string) $this->vat_src_code)."'";
451 $sql .= ", tva_tx = ".((float) price2num($this->tva_tx));
452 $sql .= ", localtax1_tx = ".((float) price2num($this->localtax1_tx));
453 $sql .= ", localtax2_tx = ".((float) price2num($this->localtax2_tx));
454 $sql .= ", localtax1_type = '".$this->db->escape($this->localtax1_type)."'";
455 $sql .= ", localtax2_type = '".$this->db->escape($this->localtax2_type)."'";
456 $sql .= ", qty = ".((float) price2num($this->qty));
457 $sql .= ", date_start = ".(!empty($this->date_start) ? "'".$this->db->idate($this->date_start)."'" : "null");
458 $sql .= ", date_end = ".(!empty($this->date_end) ? "'".$this->db->idate($this->date_end)."'" : "null");
459 $sql .= ", info_bits = ".((int) $this->info_bits);
460 $sql .= ", total_ht = ".((float) price2num($this->total_ht));
461 $sql .= ", total_tva = ".((float) price2num($this->total_tva));
462 $sql .= ", total_localtax1 = ".((float) price2num($this->total_localtax1));
463 $sql .= ", total_localtax2 = ".((float) price2num($this->total_localtax2));
464 $sql .= ", total_ttc = ".((float) price2num($this->total_ttc));
465 $sql .= ", product_type = ".((int) $this->product_type);
466 $sql .= ", special_code = ".((int) $this->special_code);
467 $sql .= ", fk_unit = ".($this->fk_unit ? ((int) $this->fk_unit) : "null");
468 if (!empty($this->rang)) {
469 $sql .= ", rang=".((int) $this->rang);
470 }
471 // Multicurrency
472 $sql .= ", multicurrency_subprice = ".((float) price2num($this->multicurrency_subprice));
473 $sql .= ", multicurrency_subprice_ttc = ".((float) price2num($this->multicurrency_subprice_ttc));
474 $sql .= ", multicurrency_total_ht = ".((float) price2num($this->multicurrency_total_ht));
475 $sql .= ", multicurrency_total_tva = ".((float) price2num($this->multicurrency_total_tva));
476 $sql .= ", multicurrency_total_ttc = ".((float) price2num($this->multicurrency_total_ttc));
477
478 $sql .= " WHERE rowid = ".((int) $this->id);
479
480 dol_syslog(get_class($this)."::updateline", LOG_DEBUG);
481 $resql = $this->db->query($sql);
482 if ($resql) {
483 if (!$error) {
484 $result = $this->insertExtraFields();
485 if ($result < 0) {
486 $error++;
487 }
488 }
489
490 if (!$error && !$notrigger) {
491 // Call trigger
492 $result = $this->call_trigger('LINEORDER_SUPPLIER_MODIFY', $user);
493 if ($result < 0) {
494 $this->db->rollback();
495 return -1;
496 }
497 // End call triggers
498 }
499
500 if (!$error) {
501 $this->db->commit();
502 return 1;
503 } else {
504 $this->db->rollback();
505 return -1;
506 }
507 } else {
508 $this->error = $this->db->lasterror();
509 $this->db->rollback();
510 return -1;
511 }
512 }
513
521 public function delete($user, $notrigger = 0)
522 {
523 if (empty($user)) {
524 global $user;
525 }
526
527 $error = 0;
528
529 $this->db->begin();
530
531 // extrafields
532 $result = $this->deleteExtraFields();
533 if ($result < 0) {
534 $this->db->rollback();
535 return -1;
536 }
537
538 $sql1 = 'UPDATE '.$this->db->prefix()."commandedet SET fk_commandefourndet = NULL WHERE fk_commandefourndet = ".((int) $this->id);
539 $resql = $this->db->query($sql1);
540 if (!$resql) {
541 $this->db->rollback();
542 return -1;
543 }
544
545 $sql2 = 'DELETE FROM '.$this->db->prefix()."commande_fournisseurdet WHERE rowid = ".((int) $this->id);
546
547 dol_syslog(__METHOD__, LOG_DEBUG);
548 $resql = $this->db->query($sql2);
549 if ($resql) {
550 if (!$notrigger) {
551 // Call trigger
552 $result = $this->call_trigger('LINEORDER_SUPPLIER_DELETE', $user);
553 if ($result < 0) {
554 $error++;
555 }
556 // End call triggers
557 }
558
559 if (!$error) {
560 $this->db->commit();
561 return 1;
562 }
563
564 foreach ($this->errors as $errmsg) {
565 dol_syslog(get_class($this)."::delete ".$errmsg, LOG_ERR);
566 $this->error .= ($this->error ? ', '.$errmsg : $errmsg);
567 }
568 $this->db->rollback();
569 return -1 * $error;
570 } else {
571 $this->error = $this->db->lasterror();
572 return -1;
573 }
574 }
575}
$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.
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_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.