dolibarr 25.0.0-alpha
commonsubtotal.class.php
1<?php
2/* Copyright (C) 2014-2017 Laurent Destailleur <eldy@users.sourceforge.net>
3 * Copyright (C) 2024 MDW <mdeweerd@users.noreply.github.com>
4 * Copyright (C) 2024-2026 Frédéric France <frederic.france@free.fr>
5 * Copyright (C) 2025 Charlene Benke <charlene@patas-monkey.com>
6 * Copyright (C) 2026 Lionel Vessiller <lvessiller@open-dsi.fr>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 3 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program. If not, see <https://www.gnu.org/licenses/>.
20 * or see https://www.gnu.org/
21 */
22
23
30trait CommonSubtotal
31{
36 public static $PRODUCT_TYPE = 9;
37
42 public static $TITLE_OPTIONS = ['titleshowuponpdf', 'titleshowtotalexludingvatonpdf', 'titleforcepagebreak'];
43
48 public static $SUBTOTAL_OPTIONS = ['subtotalshowtotalexludingvatonpdf'];
49
53 public static $ALLOWED_TYPES = [
54 'propal',
55 'commande',
56 'facture',
57 'facturerec',
58 'shipping',
59 'supplier_proposal',
60 'order_supplier',
61 'invoice_supplier',
62 'fichinter',
63 ];
64
65
80 public function addSubtotalLine($langs, $desc, $depth, $options = array(), $parent_line = 0)
81 {
82 if (!isset($desc) || trim((string) $desc) === '') {
83 $this->errors[] = $langs->trans("TitleNeedDesc");
84 return -1;
85 }
86 $current_module = $this->element;
87 // Ensure the object is one of the supported types
88 if (!in_array($current_module, self::$ALLOWED_TYPES)) {
89 $this->errors[] = $langs->trans("UnsupportedModuleError");
90 return -1; // Unsupported type
91 }
92 $error = 0;
93 $desc = dol_html_entity_decode($desc, ENT_QUOTES);
94 $rang = -1;
95 $next_line = false;
96 $result = 0;
97
98 if ($depth < 0 && $current_module != 'shipping') {
99 foreach ($this->lines as $line) {
100 if (!$next_line && $line->desc == $desc && $line->qty == -$depth) {
101 $next_line = true;
102 continue;
103 }
104 if ($next_line && $line->desc == $desc && $line->qty == $depth) {
105 $next_line = false;
106 continue;
107 }
108 if ($next_line && $line->special_code == SUBTOTALS_SPECIAL_CODE && abs($line->qty) <= abs($depth)) {
109 $rang = $line->rang;
110 break;
111 }
112 }
113 }
114
115 if ($depth > 0 && $current_module != 'shipping') {
116 $max_existing_level = 0;
117
118 foreach ($this->lines as $line) {
119 if ($line->special_code == SUBTOTALS_SPECIAL_CODE && $line->qty > $max_existing_level) {
120 $max_existing_level = $line->qty;
121 }
122 }
123
124 if ($max_existing_level+1 < $depth) {
125 $depth = $max_existing_level+1;
126 $this->errors[] = $langs->trans("TitleAddedLevelTooHigh", $depth);
127
128 $error ++;
129 }
130 }
131
132 // Add the line calling the right module
133 if ($current_module == 'facture' && $this instanceof Facture) {
134 $result = $this->addline(
135 $desc, // Description
136 0, // Unit price
137 $depth, // Quantity
138 0, // VAT rate
139 0, // Local tax 1
140 0, // Local tax 2
141 0, // FK product
142 0, // Discount percentage
143 '', // Date start
144 '', // Date end
145 0, // FK code ventilation
146 0, // Info bits
147 0, // FK remise except
148 '', // Price base type
149 0, // PU ttc
150 self::$PRODUCT_TYPE, // Type
151 $rang, // Rang
152 SUBTOTALS_SPECIAL_CODE // Special code
153 );
154 } elseif ($current_module == 'propal' && $this instanceof Propal) {
155 $result = $this->addline(
156 $desc, // Description
157 0, // Unit price
158 $depth, // Quantity
159 0, // VAT rate
160 0, // Local tax 1
161 0, // Local tax 2
162 0, // FK product
163 0, // Discount percentage
164 '', // Price base type
165 0, // PU ttc
166 0, // Info bits
167 self::$PRODUCT_TYPE, // Type
168 $rang, // Rang
169 SUBTOTALS_SPECIAL_CODE // Special code
170 );
171 } elseif ($current_module == 'commande' && $this instanceof Commande) {
172 $result = $this->addline(
173 $desc, // Description
174 0, // Unit price
175 $depth, // Quantity
176 0, // VAT rate
177 0, // Local tax 1
178 0, // Local tax 2
179 0, // FK product
180 0, // Discount percentage
181 0, // Info bits
182 0, // FK remise except
183 '', // Price base type
184 0, // PU ttc
185 '', // Date start
186 '', // Date end
187 self::$PRODUCT_TYPE, // Type
188 $rang, // Rang
189 SUBTOTALS_SPECIAL_CODE // Special code
190 );
191 } elseif ($current_module == 'shipping' && $this instanceof Expedition) {
192 $result = $this->addline(
193 0, // Warehouse ID
194 (int) $parent_line, // Source line
195 $depth // Quantity
196 );
197 } elseif ($current_module == 'facturerec' && $this instanceof FactureRec) {
198 $rang = $rang == -1 ? $rang : $rang-1;
199 $result = $this->addline(
200 $desc, // Description
201 0, // Unit price
202 $depth, // Quantity
203 0, // VAT rate
204 0, // Local tax 1
205 0, // Local tax 2
206 0, // FK product
207 0, // Discount percentage
208 '', // Price base type
209 0, // Info bits
210 0, // FK remise except
211 0, // PU ttc
212 self::$PRODUCT_TYPE, // Type
213 $rang, // Rang
214 SUBTOTALS_SPECIAL_CODE // Special code
215 );
216 $this->fetch_lines();
217 } elseif ($current_module == 'supplier_proposal' && $this instanceof SupplierProposal) {
218 $rang = $rang == -1 ? $rang : $rang-1;
219 $result = $this->addline(
220 $desc, // Description
221 0, // Unit price
222 $depth, // Quantity
223 0, // VAT rate
224 0, // Local tax 1
225 0, // Local tax 2
226 0, // FK product
227 0, // Discount percentage
228 '', // Price base type
229 0, // PU ttc
230 0, // Info bits
231 self::$PRODUCT_TYPE, // Type
232 $rang, // Rang
233 SUBTOTALS_SPECIAL_CODE // Special code
234 );
235 } elseif ($current_module == 'order_supplier' && $this instanceof CommandeFournisseur) {
236 $rang = $rang == -1 ? $rang : $rang-1;
237 $result = $this->addline(
238 $desc, // Description
239 0, // Unit price
240 $depth, // Quantity
241 0, // VAT rate
242 0, // Local tax 1
243 0, // Local tax 2
244 0, // FK product
245 0, // fk fourn price
246 '', // ref supplier
247 0, // Remise percent
248 '', // Price base type
249 0, // PU ttc
250 self::$PRODUCT_TYPE, // Type
251 0, // info bits
252 0, // no trigger
253 null, // Date start
254 null, // Date end
255 [], // array_options
256 null, // fk_unit
257 0, // pu ht devise
258 '', // origin type
259 0, // origin id
260 $rang, // Rang
261 SUBTOTALS_SPECIAL_CODE // Special code
262 );
263 } elseif ($current_module == 'invoice_supplier' && $this instanceof FactureFournisseur) {
264 $rang = $rang == -1 ? $rang : $rang-1;
265 $result = $this->addline(
266 $desc, // Description
267 0, // Unit price
268 0, // VAT rate
269 0, // Local tax 1
270 0, // Local tax 2
271 $depth, // Quantity
272 0, // FK product
273 0, // Remise percent
274 '', // Date start
275 '', // Date end
276 0, // Code ventilation
277 0, // info bits
278 '', // Price base type
279 self::$PRODUCT_TYPE, // Type
280 $rang, // Rang
281 0, // no trigger
282 [], // array_options
283 null, // fk_unit
284 0, // origin id
285 0, // pu ht devise
286 '', // ref supplier
287 SUBTOTALS_SPECIAL_CODE // Special code
288 );
289 } elseif ($current_module == 'fichinter' && $this instanceof Fichinter) {
290 global $user;
291 $result = $this->addline(
292 $user, // user
293 $this->id, // fk_fichinter
294 $desc, // Description
295 0, // dateintervention
296 $depth, // duration
297 [], // arrayoption
298 self::$PRODUCT_TYPE, // Type
299 $rang, // Rang
300 SUBTOTALS_SPECIAL_CODE // Special code
301 );
302 }
303
304
305 if ($current_module != 'shipping' && $result > 0) {
306 // SupplierProposal::addline() and Fichinter::addline() do not append the new line
307 // to $this->lines, so reload the lines before looking the new one up by id.
308 if ($current_module == 'supplier_proposal') {
309 $this->fetch($this->id);
310 } elseif ($current_module == 'fichinter') {
311 $this->fetch_lines();
312 }
313 foreach ($this->lines as $line) {
314 '@phan-var-force CommonObjectLine $line';
316 if ($line->id == $result) {
317 $line->extraparams["subtotal"] = $options;
318 $line->setExtraParameters();
319 }
320 }
321 }
322
323 if ($result < 0) {
324 return $result;
325 }
326
327 return $error > 0 ? 0 : $result;
328 }
329
343 public function deleteSubtotalLine($langs, $id, $correspondingstline = false, $user = null)
344 {
345 $current_module = $this->element;
346 // Ensure the object is one of the supported types
347 if (!in_array($current_module, self::$ALLOWED_TYPES)) {
348 $this->errors[] = $langs->trans("UnsupportedModuleError");
349 return -1; // Unsupported type
350 }
351
352 $result = 0;
353
354 if ($correspondingstline) {
355 $oldDesc = "";
356 $oldDepth = 0;
357 foreach ($this->lines as $line) {
358 if ($line->id == $id) {
359 $oldDesc = $line->desc;
360 $oldDepth = $line->qty;
361 }
362 if ($line->special_code == SUBTOTALS_SPECIAL_CODE && $line->qty == -$oldDepth && $line->desc == $oldDesc) {
363 $this->deleteSubtotalLine($langs, $line->id, false, $user);
364 break;
365 }
366 }
367 }
368
369 // Add the line calling the right module
370 if ($current_module == 'facture' && $this instanceof Facture) {
371 $rowid = $id; // for phan suspicious parameter order...
372 $result = $this->deleteLine($rowid);
373 } elseif ($current_module == 'propal' && $this instanceof Propal) {
374 $rowid = $id; // for phan suspicious parameter order...
375 $result = $this->deleteLine($rowid);
376 } elseif ($current_module == 'commande' && $this instanceof Commande) {
377 $lineid = $id; // for phan suspicious parameter order...
378 $result = $this->deleteLine($user, $lineid);
379 } elseif ($current_module == 'facturerec') {
380 $line = new FactureLigneRec($this->db);
381 $line->id = $id;
382 $result = $line->delete($user);
383 } elseif ($current_module == 'shipping') {
384 $line = new ExpeditionLigne($this->db);
385 $line->id = $id;
386 $result = $line->delete($user);
387 } elseif ($current_module == 'supplier_proposal') {
388 $line = new SupplierProposalLine($this->db);
389 $line->id = $id;
390 $result = $line->delete($user);
391 } elseif ($current_module == 'order_supplier') {
392 $line = new CommandeFournisseurLigne($this->db);
393 $line->id = $id;
394 $result = $line->delete($user);
395 } elseif ($current_module == 'invoice_supplier') {
396 $line = new SupplierInvoiceLine($this->db);
397 $line->id = $id;
398 $result = $line->delete();
399 } elseif ($current_module == 'fichinter') {
400 $line = new FichinterLigne($this->db);
401 $line->id = $id;
402 $result = $line->deleteLine($user);
403 }
404
405 return $result >= 0 ? $result : -1; // Return line ID or false
406 }
407
423 public function updateSubtotalLine($langs, $lineid, $desc, $depth, $options) // @phpstan-ignore-line
424 {
425 $current_module = $this->element;
426 // Ensure the object is one of the supported types
427 if (!in_array($current_module, self::$ALLOWED_TYPES)) {
428 $this->errors[] = $langs->trans("UnsupportedModuleError");
429 return -1; // Unsupported type
430 }
431
432 $result = 0;
433 $error = 0;
434
435 $max_existing_level = 0;
436
437 if ($depth>0) {
438 foreach ($this->lines as $line) {
439 if ($line->special_code == SUBTOTALS_SPECIAL_CODE && $line->qty > $max_existing_level && $line->id != $lineid) {
440 $max_existing_level = $line->qty;
441 }
442 }
443 }
444
445 if ($max_existing_level+1 < $depth) {
446 $depth = $max_existing_level+1;
447 $this->errors[] = $langs->trans("TitleEditedLevelTooHigh");
448 $error ++;
449 }
450
451 if ($depth>0) {
452 $oldDesc = "";
453 $oldDepth = 0;
454 foreach ($this->lines as $line) {
455 if ($line->id == $lineid) {
456 $oldDesc = $line->desc;
457 $oldDepth = $line->qty;
458 }
459 if ($line->special_code == SUBTOTALS_SPECIAL_CODE && $line->qty == -$oldDepth && $line->desc == $oldDesc) {
460 $this->updateSubtotalLine($langs, $line->id, $desc, -$depth, !empty($line->extraparams["subtotal"]) ? $line->extraparams["subtotal"] : array());
461 break;
462 }
463 }
464 }
465
466 // Update the line calling the right module
467 if ($current_module == 'facture' && $this instanceof Facture) {
468 $result = $this->updateline(
469 $lineid, // ID of line to change
470 $desc, // Description
471 0, // Unit price
472 $depth, // Quantity
473 0, // Discount percentage
474 '', // Date start
475 '', // Date end
476 0, // VAT rate
477 0, // Local tax 1
478 0, // Local tax 2
479 '', // Price base type
480 0, // Info bits
481 self::$PRODUCT_TYPE, // Type
482 0, // FK parent line
483 0, // Skip update total
484 0, // FK fournprice
485 0, // PA ht
486 '', // Label
487 SUBTOTALS_SPECIAL_CODE // Special code
488 );
489 } elseif ($current_module == 'propal' && $this instanceof Propal) {
490 $result = $this->updateline(
491 $lineid, // ID of line to change
492 0, // Unit price
493 $depth, // Quantity
494 0, // Discount percentage
495 0, // VAT rate
496 0, // Local tax 1
497 0, // Local tax 2
498 $desc, // Description
499 '', // Price base type
500 0, // Info bits
501 SUBTOTALS_SPECIAL_CODE, // Special code
502 0, // FK parent line
503 0, // Skip update total
504 0, // FK fournprice
505 0, // PA ht
506 '', // Label
507 self::$PRODUCT_TYPE // Type
508 );
509 } elseif ($current_module == 'commande' && $this instanceof Commande) {
510 $result = $this->updateline(
511 $lineid, // ID of line to change
512 $desc, // Description
513 0, // Unit price
514 $depth, // Quantity
515 0, // Discount percentage
516 0, // VAT rate
517 0, // Local tax 1
518 0, // Local tax 2
519 '', // Price base type
520 0, // Info bits
521 '', // Date start
522 '', // Date end
523 self::$PRODUCT_TYPE, // Type
524 0, // FK parent line
525 0, // Skip update total
526 0, // FK fournprice
527 0, // PA ht
528 '', // Label
529 SUBTOTALS_SPECIAL_CODE // Special code
530 );
531 } elseif ($current_module == 'facturerec' && $this instanceof FactureRec) {
532 $objectline = new FactureLigneRec($this->db);
533 $objectline->fetch($lineid);
534 $line_rang = $objectline->rang;
535 $result = $this->updateline(
536 $lineid, // ID of line to change
537 $desc, // Description
538 0, // Unit price
539 $depth, // Quantity
540 0, // VAT rate
541 0, // Local tax 1
542 0, // Local tax 2
543 0, // FK parent line
544 0, // Discount percentage
545 '', // Price base type
546 0, // Info bits
547 0, // FK parent line
548 0, // PU ttc
549 self::$PRODUCT_TYPE, // Type
550 $line_rang, // Rang
551 SUBTOTALS_SPECIAL_CODE // Special code
552 );
553 } elseif ($current_module == 'supplier_proposal' && $this instanceof SupplierProposal) {
554 $objectline = new SupplierProposalLine($this->db);
555 $objectline->fetch($lineid);
556 $line_rang = $objectline->rang;
557 $result = $this->updateline(
558 $lineid, // ID of line to change
559 0, // Unit price
560 $depth, // Quantity
561 0, // Discount percentage
562 0, // VAT rate
563 0, // Local tax 1
564 0, // Local tax 2
565 $desc, // Description
566 '', // Price base type
567 0, // Info bits
568 SUBTOTALS_SPECIAL_CODE, // Special code
569 0, // FK parent line
570 0, //
571 0, //
572 0, //
573 '', //
574 self::$PRODUCT_TYPE // Type
575 );
576 } elseif ($current_module == 'order_supplier' && $this instanceof CommandeFournisseur) {
577 $objectline = new CommandeFournisseurLigne($this->db);
578 $objectline->fetch($lineid);
579 $line_rang = $objectline->rang;
580 // special code comes from old line
581 $result = $this->updateline(
582 $lineid, // ID of line to change
583 $desc, // Description
584 0, // Unit price
585 $depth, // Quantity
586 0, // Discount percentage
587 0, // VAT rate
588 0, // Local tax 1
589 0, // Local tax 2
590 '', // Price base type
591 0, // Info bits
592 self::$PRODUCT_TYPE, // Type
593 0, // no trigger
594 0, //
595 0, //
596 [], //
597 null //
598 );
599 } elseif ($current_module == 'invoice_supplier' && $this instanceof FactureFournisseur) {
600 $objectline = new SupplierInvoiceLine($this->db);
601 $objectline->fetch($lineid);
602 $line_rang = $objectline->rang;
603 $result = $this->updateline(
604 $lineid, // ID of line to change
605 $desc, // Description
606 0, // Unit price
607 0, // VAT rate
608 0, // Local tax 1
609 0, // Local tax 2
610 $depth, // Quantity
611 0, // product id
612 '', // Price base type
613 0, // Info bits
614 self::$PRODUCT_TYPE, // Type
615 0 // Discount percentage
616 );
617 }
618
619 foreach ($this->lines as $line) {
620 '@phan-var-force CommonObjectLine $line';
622 if ($line->id == $lineid) {
623 $line->extraparams["subtotal"] = $options;
624 $line->setExtraParameters();
625 }
626 }
627
628 if ($result < 0) {
629 return $result;
630 }
631
632 return $error > 0 ? 0 : $result;
633 }
634
647 public function updateSubtotalLineBlockLines($langs, $linerang, $mode, $value) // @phpstan-ignore-line
648 {
649 $current_module = $this->element;
650 // Ensure the object is one of the supported types
651 if (!in_array($current_module, self::$ALLOWED_TYPES)) {
652 $this->errors[] = $langs->trans("UnsupportedModuleError");
653 return -1; // Unsupported type
654 }
655
656 $result = 0;
657 $linerang -= 1;
658
659 $nb_lines = count($this->lines);
660
661 for ($i = $linerang+1; $i < $nb_lines; $i++) {
662 if ($this->lines[$i]->special_code == SUBTOTALS_SPECIAL_CODE) {
663 if (abs($this->lines[$i]->qty) <= (int) $this->lines[$linerang]->qty) {
664 return 1;
665 }
666 } else {
667 if ($current_module == 'facture' && $this instanceof Facture) {
668 // Preserve the original entry mode of the line so the total is not drifted by rounding.
669 $line_price_base_type = $this->lines[$i]->getPriceBaseType();
670 $line_pu = ($line_price_base_type === 'TTC') ? $this->lines[$i]->subprice_ttc : $this->lines[$i]->subprice;
671 $result = $this->updateline(
672 $this->lines[$i]->id,
673 $this->lines[$i]->desc,
674 $line_pu,
675 $this->lines[$i]->qty,
676 $mode == 'discount' ? $value : $this->lines[$i]->remise_percent,
677 $this->lines[$i]->date_start,
678 $this->lines[$i]->date_end,
679 $mode == 'tva' ? $value : $this->lines[$i]->tva_tx,
680 $this->lines[$i]->localtax1_tx,
681 $this->lines[$i]->localtax2_tx,
682 $line_price_base_type,
683 $this->lines[$i]->info_bits,
684 $this->lines[$i]->product_type,
685 $this->lines[$i]->fk_parent_line,
686 0,
687 $this->lines[$i]->fk_fournprice,
688 $this->lines[$i]->pa_ht,
689 $this->lines[$i]->label,
690 $this->lines[$i]->special_code,
691 $this->lines[$i]->array_options,
692 $this->lines[$i]->situation_percent,
693 $this->lines[$i]->fk_unit,
694 $this->lines[$i]->multicurrency_subprice
695 );
696 } elseif ($current_module == 'commande' && $this instanceof Commande) {
697 // Preserve the original entry mode of the line so the total is not drifted by rounding.
698 $line_price_base_type = $this->lines[$i]->getPriceBaseType();
699 $line_pu = ($line_price_base_type === 'TTC') ? $this->lines[$i]->subprice_ttc : $this->lines[$i]->subprice;
700 $result = $this->updateline(
701 $this->lines[$i]->id,
702 $this->lines[$i]->desc,
703 $line_pu,
704 $this->lines[$i]->qty,
705 $mode == 'discount' ? $value : $this->lines[$i]->remise_percent,
706 $mode == 'tva' ? $value : $this->lines[$i]->tva_tx,
707 $this->lines[$i]->localtax1_tx,
708 $this->lines[$i]->localtax2_tx,
709 $line_price_base_type,
710 $this->lines[$i]->info_bits,
711 $this->lines[$i]->date_start,
712 $this->lines[$i]->date_end,
713 $this->lines[$i]->product_type,
714 $this->lines[$i]->fk_parent_line,
715 0,
716 $this->lines[$i]->fk_fournprice,
717 $this->lines[$i]->pa_ht,
718 $this->lines[$i]->label,
719 $this->lines[$i]->special_code,
720 $this->lines[$i]->array_options,
721 $this->lines[$i]->fk_unit,
722 $this->lines[$i]->multicurrency_subprice
723 );
724 } elseif ($current_module == 'propal' && $this instanceof Propal) {
725 // Preserve the original entry mode of the line so the total is not drifted by rounding.
726 $line_price_base_type = $this->lines[$i]->getPriceBaseType();
727 $line_pu = ($line_price_base_type === 'TTC') ? $this->lines[$i]->subprice_ttc : $this->lines[$i]->subprice;
728 $result = $this->updateline(
729 $this->lines[$i]->id,
730 $line_pu,
731 $this->lines[$i]->qty,
732 $mode == 'discount' ? $value : $this->lines[$i]->remise_percent,
733 $mode == 'tva' ? $value : $this->lines[$i]->tva_tx,
734 $this->lines[$i]->localtax1_tx,
735 $this->lines[$i]->localtax2_tx,
736 $this->lines[$i]->desc,
737 $line_price_base_type,
738 $this->lines[$i]->info_bits,
739 $this->lines[$i]->special_code,
740 $this->lines[$i]->fk_parent_line,
741 0,
742 $this->lines[$i]->fk_fournprice,
743 $this->lines[$i]->pa_ht,
744 $this->lines[$i]->label,
745 $this->lines[$i]->product_type,
746 $this->lines[$i]->date_start,
747 $this->lines[$i]->date_end,
748 $this->lines[$i]->array_options,
749 $this->lines[$i]->fk_unit,
750 $this->lines[$i]->multicurrency_subprice
751 );
752 } elseif ($current_module == 'supplier_proposal' && $this instanceof SupplierProposal) {
753 // Preserve the original entry mode of the line so the total is not drifted by rounding.
754 $line_price_base_type = $this->lines[$i]->getPriceBaseType();
755 $line_pu = ($line_price_base_type === 'TTC') ? $this->lines[$i]->subprice_ttc : $this->lines[$i]->subprice;
756 $result = $this->updateline(
757 $this->lines[$i]->id,
758 $line_pu,
759 $this->lines[$i]->qty,
760 $mode == 'discount' ? $value : $this->lines[$i]->remise_percent,
761 $mode == 'tva' ? $value : $this->lines[$i]->tva_tx,
762 $this->lines[$i]->localtax1_tx,
763 $this->lines[$i]->localtax2_tx,
764 $this->lines[$i]->desc,
765 $line_price_base_type,
766 $this->lines[$i]->info_bits,
767 $this->lines[$i]->special_code,
768 $this->lines[$i]->fk_parent_line,
769 0,
770 $this->lines[$i]->fk_fournprice,
771 $this->lines[$i]->pa_ht,
772 $this->lines[$i]->label,
773 $this->lines[$i]->product_type,
774 $this->lines[$i]->array_options,
775 $this->lines[$i]->ref_supplier,
776 (int) $this->lines[$i]->fk_unit,
777 $this->lines[$i]->multicurrency_subprice
778 );
779 } elseif ($current_module == 'order_supplier' && $this instanceof CommandeFournisseur) {
780 // Preserve the original entry mode of the line so the total is not drifted by rounding.
781 $line_price_base_type = $this->lines[$i]->getPriceBaseType();
782 $line_pu = ($line_price_base_type === 'TTC') ? $this->lines[$i]->subprice_ttc : $this->lines[$i]->subprice;
783 $result = $this->updateline(
784 $this->lines[$i]->id,
785 $this->lines[$i]->desc,
786 $line_pu,
787 $this->lines[$i]->qty,
788 $mode == 'discount' ? $value : $this->lines[$i]->remise_percent,
789 $mode == 'tva' ? $value : $this->lines[$i]->tva_tx,
790 $this->lines[$i]->localtax1_tx,
791 $this->lines[$i]->localtax2_tx,
792 $line_price_base_type,
793 $this->lines[$i]->info_bits,
794 $this->lines[$i]->product_type,
795 0,
796 $this->lines[$i]->date_start,
797 $this->lines[$i]->date_end,
798 $this->lines[$i]->array_options,
799 $this->lines[$i]->fk_unit,
800 $this->lines[$i]->multicurrency_subprice,
801 $this->lines[$i]->ref_supplier
802 );
803 }
804 if ($result < 0) {
805 return $result;
806 }
807 }
808 }
809 return 1;
810 }
811
825 public function getSubtotalLineAmountValue($line, $multicurrency = false)
826 {
827 $field = $multicurrency ? 'multicurrency_total_ht' : 'total_ht';
828
829 $abovelines = array();
830 $aboverangs = array();
831 foreach ($this->lines as $l) {
832 if (!is_object($l) || $l->rang >= $line->rang) {
833 continue;
834 }
835 $aboverangs[] = (int) $l->rang;
836 $abovelines[] = $l;
837 }
838 // Scan the lines above the current one from the nearest to the farthest.
839 array_multisort($aboverangs, SORT_DESC, SORT_NUMERIC, $abovelines);
840
841 $final_amount = 0;
842 foreach ($abovelines as $l) {
843 if ($l->special_code == SUBTOTALS_SPECIAL_CODE && $l->qty > 0) {
844 if ($l->qty <= abs($line->qty)) {
845 break;
846 }
847 continue;
848 }
849 $final_amount += (float) $l->$field;
850 }
851
852 return $final_amount;
853 }
854
864 public function getSubtotalLineAmount($line)
865 {
866 return price($this->getSubtotalLineAmountValue($line, false));
867 }
868
878 public function getSubtotalLineMulticurrencyAmount($line)
879 {
880 return price($this->getSubtotalLineAmountValue($line, true));
881 }
882
889 public function getSubtotalColors($level)
890 {
891 return getDolGlobalString('SUBTOTAL_BACK_COLOR_LEVEL_'.abs($level));
892 }
893
901 public function getPossibleTitles()
902 {
903 $titles = array();
904 foreach ($this->lines as $line) {
905 if ($line->special_code == SUBTOTALS_SPECIAL_CODE && $line->qty > 0) {
906 $titles[$line->desc] = $line->desc;
907 }
908 if ($line->special_code == SUBTOTALS_SPECIAL_CODE && $line->qty < 0) {
909 unset($titles[$line->desc]);
910 }
911 }
912 return $titles;
913 }
914
923 public function getPossibleLevels($langs)
924 {
925 $depth_array = array();
926 $max_depth = getDolGlobalInt('SUBTOTAL_'.strtoupper($this->element).'_MAX_DEPTH', 2);
927 for ($i = 0; $i < $max_depth; $i++) {
928 $depth_array[$i + 1] = $langs->trans("SubtotalLevel", $i + 1);
929 }
930 return $depth_array;
931 }
932
941 public function getPredefinedTitles()
942 {
943 $titles = array();
944
945 $sql = "SELECT rowid, label FROM ".MAIN_DB_PREFIX."c_subtotals_titles";
946 $sql .= " WHERE active = 1 AND entity IN (".getEntity('c_subtotals_titles').")";
947 $sql .= " ORDER BY label ASC";
948
949 $resql = $this->db->query($sql);
950 if ($resql) {
951 while ($obj = $this->db->fetch_object($resql)) {
952 $titles[(int) $obj->rowid] = $obj->label;
953 }
954 }
955
956 return $titles;
957 }
958
967 public function getPredefinedTexts()
968 {
969 $texts = array();
970
971 $sql = "SELECT rowid, label, content FROM ".MAIN_DB_PREFIX."c_subtotals_texts";
972 $sql .= " WHERE active = 1 AND entity IN (".getEntity('c_subtotals_texts').")";
973 $sql .= " ORDER BY label ASC";
974
975 $resql = $this->db->query($sql);
976 if ($resql) {
977 while ($obj = $this->db->fetch_object($resql)) {
978 $texts[(int) $obj->rowid] = array('label' => $obj->label, 'content' => $obj->content);
979 }
980 }
981
982 return $texts;
983 }
984
992 public function getDisabledShippmentSubtotalLines()
993 {
994 $toDisableLines = array();
995 $toDisable = true;
996 $oldDesc = "";
997 $oldDepth = 0;
998
999 foreach ($this->lines as $titleLine) {
1000 if ($titleLine->special_code != SUBTOTALS_SPECIAL_CODE || $titleLine->qty <= 0) {
1001 continue;
1002 }
1003 foreach ($this->lines as $line) {
1004 if ($line->id == $titleLine->id) {
1005 $oldDesc = $line->desc;
1006 $oldDepth = $line->qty;
1007 }
1008 if ($line->special_code != SUBTOTALS_SPECIAL_CODE && $line->fk_product_type == 0 && !empty($oldDesc) && !empty($oldDepth)) {
1009 $toDisable = false;
1010 }
1011 if ($line->special_code == SUBTOTALS_SPECIAL_CODE && $line->qty == -$oldDepth && $line->desc == $oldDesc) {
1012 if ($toDisable) {
1013 $toDisableLines = array_merge($toDisableLines, array($titleLine->id, $line->id));
1014 }
1015 $oldDesc = "";
1016 $oldDepth = 0;
1017 $toDisable = true;
1018 break;
1019 }
1020 }
1021 }
1022 return $toDisableLines;
1023 }
1024}
$id
Support class for third parties, contacts, members, users or resources.
Definition account.php:47
Class to manage predefined suppliers products.
Class to manage line orders.
Class to manage customers orders.
Class to manage lines of shipment.
Class to manage suppliers invoices.
Class to manage invoices.
Class to manage invoice lines of templates.
Class to manage invoice templates.
Class to manage intervention lines.
Class to manage proposals.
Class to manage line invoices.
Class to manage price ask supplier.
Class to manage supplier_proposal lines.
dol_html_entity_decode($a, $b, $c='UTF-8', $keepsomeentities=0)
Replace html_entity_decode functions to manage errors.
price($amount, $form=0, $outlangs='', $trunc=1, $rounding=-1, $forcerounding=-1, $currency_code='')
Function to format a value into an amount for visual output Function used into PDF and HTML pages.
getDolGlobalInt($key, $default=0)
Return a Dolibarr global constant int value.
getDolGlobalString($key, $default='')
Return a Dolibarr global constant string value.