TSubtotal::isSubtotal()   A
last analyzed

Complexity

Conditions 5
Paths 6

Size

Total Lines 6
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 1 Features 0
Metric Value
cc 5
eloc 4
c 1
b 1
f 0
nc 6
nop 2
dl 0
loc 6
rs 9.6111
1
<?php
2
3
4
class TSubtotal {
5
6
	static $module_number = 104777;
7
8
	/**
9
	 * @param CommonObject $object
10
	 * @param string       $label
11
	 * @param int          $qty
12
	 * @param int          $rang
13
	 * @return int
14
	 */
15
	static function addSubTotalLine(&$object, $label, $qty, $rang=-1) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
16
17
		$res = 0;
18
19
		if( (float)DOL_VERSION <= 3.4 ) {
20
			/**
21
			 * @var $object Facture
22
			 */
23
			if($object->element=='facture') $res =  $object->addline($object->id, $label, 0,$qty,0,0,0,0,0,'','',0,0,'','HT',0,9,-1, TSubtotal::$module_number);
24
			/**
25
			 * @var $object Propal
26
			 */
27
			else if($object->element=='propal') $res =  $object->addline($object->id,$label, 0,$qty,0,0,0,0,0,'HT',0,0,9,-1, TSubtotal::$module_number);
28
			/**
29
			 * @var $object Commande
30
			 */
31
			else if($object->element=='commande') $res =  $object->addline($object->id,$label, 0,$qty,0,0,0,0,0,0,0,'HT',0,'','',9,-1, TSubtotal::$module_number);
32
33
		}
34
		else {
35
			$desc = '';
36
37
			$TNotElements = array ('invoice_supplier', 'order_supplier');
38
			if ((float) DOL_VERSION < 6  || $qty==50 && !in_array($object->element, $TNotElements) ) {
39
				$desc = $label;
40
				$label = '';
41
			}
42
43
			if($object->element=='facture')
44
            {
45
                /** @var Facture $object */
46
                $res =  $object->addline($desc, 0,$qty,0,0,0,0,0,'','',0,0,'','HT',0,9,$rang, TSubtotal::$module_number, '', 0, 0, null, 0, $label);
47
            }
48
			elseif($object->element=='invoice_supplier') {
49
                /** @var FactureFournisseur $object */
50
			    $object->special_code = TSubtotal::$module_number;
51
                if( (float)DOL_VERSION < 6 ) $rang = $object->line_max() + 1;
52
			    $res = $object->addline($label,0,0,0,0,$qty,0,0,'','',0,0,'HT',9,$rang);
53
			}
54
			/**
55
			 * @var $object Propal
56
			 */
57
			else if($object->element=='propal') $res = $object->addline($desc, 0,$qty,0,0,0,0,0,'HT',0,0,9,$rang, TSubtotal::$module_number, 0, 0, 0, $label);
58
			/**
59
			 * @var $object Propal Fournisseur
60
			 */
61
			else if($object->element=='supplier_proposal') $res = $object->addline($desc, 0,$qty,0,0,0,0,0,'HT',0,0,9,$rang, TSubtotal::$module_number, 0, 0, 0, $label);
62
63
			/**
64
			 * @var $object Commande
65
			 */
66
			else if($object->element=='commande') $res =  $object->addline($desc, 0,$qty,0,0,0,0,0,0,0,'HT',0,'','',9,$rang, TSubtotal::$module_number, 0, null, 0, $label);
67
			/**
68
			 * @var $object Commande fournisseur
69
			 */
70
			else if($object->element=='order_supplier') {
71
			    $object->special_code = TSubtotal::$module_number;
72
			    $res = $object->addline($label, 0,$qty,0,0,0,0,0,'',0,'HT', 0, 9);
73
			}
74
			/**
75
			 * @var $object Facturerec
76
			 */
77
			else if($object->element=='facturerec') $res =  $object->addline($desc, 0,$qty, 0, 0, 0, 0, 0, 'HT', 0, '', 0, 9, $rang, TSubtotal::$module_number,$label);
78
79
		}
80
81
		self::generateDoc($object);
82
83
		return $res;
84
	}
85
86
	/**
87
	 * @param CommonObject $object
88
	 */
89
	public static function generateDoc(&$object)
90
	{
91
		global $conf,$langs,$db;
92
93
		if (empty($conf->global->MAIN_DISABLE_PDF_AUTOUPDATE))
94
		{
95
			$hidedetails = (GETPOST('hidedetails', 'int') ? GETPOST('hidedetails', 'int') : (! empty($conf->global->MAIN_GENERATE_DOCUMENTS_HIDE_DETAILS) ? 1 : 0));
96
			$hidedesc = (GETPOST('hidedesc', 'int') ? GETPOST('hidedesc', 'int') : (! empty($conf->global->MAIN_GENERATE_DOCUMENTS_HIDE_DESC) ? 1 : 0));
97
			$hideref = (GETPOST('hideref', 'int') ? GETPOST('hideref', 'int') : (! empty($conf->global->MAIN_GENERATE_DOCUMENTS_HIDE_REF) ? 1 : 0));
98
99
			// Define output language
100
			$outputlangs = $langs;
101
			$newlang = GETPOST('lang_id', 'alpha');
102
			if (! empty($conf->global->MAIN_MULTILANGS) && empty($newlang))
103
				$newlang = !empty($object->client) ? $object->client->default_lang : $object->thirdparty->default_lang;
104
			if (! empty($newlang)) {
105
				$outputlangs = new Translate("", $conf);
106
				$outputlangs->setDefaultLang($newlang);
107
			}
108
109
			$ret = $object->fetch($object->id); // Reload to get new records
110
			if ((float) DOL_VERSION <= 3.6)
111
			{
112
				if ($object->element == 'propal') propale_pdf_create($db, $object, $object->modelpdf, $outputlangs, $hidedetails, $hidedesc, $hideref);
113
				elseif ($object->element == 'commande') commande_pdf_create($db, $object, $object->modelpdf, $outputlangs, $hidedetails, $hidedesc, $hideref);
114
				elseif ($object->element == 'facture') facture_pdf_create($db, $object, $object->modelpdf, $outputlangs, $hidedetails, $hidedesc, $hideref);
115
			}
116
			else
117
			{
118
				if ($object->element!= 'facturerec') $object->generateDocument($object->modelpdf, $outputlangs, $hidedetails, $hidedesc, $hideref);
119
			}
120
		}
121
	}
122
123
	/**
124
	 * Permet de mettre à jour les rangs afin de décaler des lignes pour une insertion en milieu de document
125
	 *
126
	 * @param type $object
127
	 * @param type $rang_start
128
	 * @param type $move_to
129
	 */
130
	public static function updateRang(&$object, $rang_start, $move_to=1)
131
	{
132
		if (!class_exists('GenericObject')) require_once DOL_DOCUMENT_ROOT.'/core/class/genericobject.class.php';
133
134
		$row=new GenericObject($object->db);
135
		$row->table_element_line = $object->table_element_line;
136
		$row->fk_element = $object->fk_element;
137
		$row->id = $object->id;
138
139
		foreach ($object->lines as &$line)
140
		{
141
			if ($line->rang < $rang_start) continue;
142
143
			$row->updateRangOfLine($line->id, $line->rang+$move_to);
144
		}
145
	}
146
147
	/**
148
	 * Méthode qui se charge de faire les ajouts de sous-totaux manquant afin de fermer les titres ouvert lors de l'ajout d'un nouveau titre
149
	 *
150
	 * @global Translate   $langs
151
	 * @param CommonObject $object
152
	 * @param int          $level_new_title
153
	 */
154
	public static function addSubtotalMissing(&$object, $level_new_title)
155
	{
156
		global $langs;
157
		$TTitle = self::getAllTitleWithoutTotalFromDocument($object);
158
		// Reverse - Pour partir de la fin et remonter dans les titres pour me permettre de m'arrêter quand je trouve un titre avec un niveau inférieur à celui qui a était ajouté
159
		$TTitle_reverse = array_reverse($TTitle);
160
161
		foreach ($TTitle_reverse as $k => $title_line)
162
		{
163
			$title_niveau = self::getNiveau($title_line);
164
			if ($title_niveau < $level_new_title) break;
165
166
			$rang_to_add = self::titleHasTotalLine($object, $title_line, true, true);
167
168
			if (is_numeric($rang_to_add))
169
			{
170
				if ($rang_to_add != -1) self::updateRang($object, $rang_to_add);
171
172
				self::addSubTotalLine($object, $langs->trans('SubTotal'), 100-$title_niveau, $rang_to_add);
173
174
				$object->lines[] = $object->line; // ajout de la ligne dans le tableau de ligne (Dolibarr ne le fait pas)
175
				if ($rang_to_add != -1)
176
				{
177
					if (method_exists($object, 'fetch_lines')) $object->fetch_lines();
178
					else $object->fetch($object->id);
179
				}
180
			}
181
		}
182
	}
183
184
	public static function addTitle(&$object, $label, $level, $rang=-1)
185
	/**
186
	 * @param CommonObject $object
187
	 * @param string       $label
188
	 * @param int          $level
189
	 * @param int          $rang
190
	 * @return int
191
	 */
192
	{
193
		return self::addSubTotalLine($object, $label, $level, $rang);
194
	}
195
196
	public static function addTotal(&$object, $label, $level, $rang=-1)
197
	/**
198
	 * @param CommonObject $object
199
	 * @param string       $label
200
	 * @param int          $level
201
	 * @param int          $rang
202
	 * @return int
203
	 */
204
	{
205
		return self::addSubTotalLine($object, $label, (100-$level), $rang);
206
	}
207
208
	/**
209
	 * Récupère la liste des lignes de titre qui n'ont pas de sous-total
210
	 *
211
	 * @param Propal|Commande|Facture				$object
212
	 * @param boolean								$get_block_total
213
	 *
214
	 * @return array
215
	 */
216
	public static function getAllTitleWithoutTotalFromDocument(&$object, $get_block_total=false)
217
	{
218
		$TTitle = self::getAllTitleFromDocument($object, $get_block_total);
219
220
		foreach ($TTitle as $k => $title_line)
221
		{
222
			if (self::titleHasTotalLine($object, $title_line)) unset($TTitle[$k]);
223
		}
224
225
		return $TTitle;
226
	}
227
228
	/**
229
	 * Est-ce que mon titre ($title_line) a un sous-total ?
230
	 *
231
	 * @param Propal|Commande|Facture				$object
232
	 * @param PropaleLigne|OrderLine|FactureLigne	$title_line
233
	 * @param boolean								$strict_mode			si true alors un titre doit avoir un sous-total de même niveau; si false un titre possède un sous-total à partir du moment où l'on trouve un titre de niveau égale ou inférieur
234
	 * @param boolean								$return_rang_on_false	si true alors renvoi le rang où devrait ce trouver le sous-total
235
	 * @return boolean
236
	 */
237
	public static function titleHasTotalLine(&$object, &$title_line, $strict_mode=false, $return_rang_on_false=false)
238
	{
239
		if (empty($object->lines) || !is_array($object->lines)) return false;
240
241
		$title_niveau = self::getNiveau($title_line);
242
		foreach ($object->lines as &$line)
243
		{
244
			if ($line->rang <= $title_line->rang) continue;
245
			if (self::isTitle($line) && self::getNiveau($line) <= $title_niveau) return false; // Oups on croise un titre d'un niveau inférieur ou égale (exemple : je croise un titre niveau 2 alors que je suis sur un titre de niveau 3) pas lieu de continuer car un nouveau bloc commence
246
			if (!self::isSubtotal($line)) continue;
247
248
			$subtotal_niveau = self::getNiveau($line);
249
250
			// Comparaison du niveau de la ligne de sous-total avec celui du titre
251
			if ($subtotal_niveau == $title_niveau) return true; // niveau égale => Ok mon titre a un sous-total
252
			elseif ($subtotal_niveau < $title_niveau) // niveau inférieur trouvé (exemple : sous-total de niveau 1 contre mon titre de niveau 3)
253
			{
254
				if ($strict_mode) return ($return_rang_on_false) ? $line->rang : false; // mode strict niveau pas égale donc faux
255
				else return true; // mode libre => OK je considère que mon titre à un sous-total
256
			}
257
		}
258
259
		// Sniff, j'ai parcouru toutes les lignes et pas de sous-total pour ce titre
260
		return ($return_rang_on_false) ? -1 : false;
261
	}
262
263
	/**
264
	 * @param CommonObject $object
265
	 * @param boolean      $get_block_total
266
	 * @return array
267
	 */
268
	public static function getAllTitleFromDocument(&$object, $get_block_total=false)
269
	{
270
		$TRes = array();
271
		if (!empty($object->lines))
272
		{
273
			foreach ($object->lines as $k => &$line)
274
			{
275
				if (self::isTitle($line))
276
				{
277
					if ($get_block_total)
278
					{
279
						$TTot = self::getTotalBlockFromTitle($object, $line);
280
281
						$line->total_pa_ht = $TTot['total_pa_ht'];
282
						$line->total_options = $TTot['total_options'];
283
						$line->total_ht = $TTot['total_ht'];
284
						$line->total_tva = $TTot['total_tva'];
285
						$line->total_ttc = $TTot['total_ttc'];
286
						$line->TTotal_tva = $TTot['TTotal_tva'];
287
						$line->multicurrency_total_ht = $TTot['multicurrency_total_ht'];
288
						$line->multicurrency_total_tva = $TTot['multicurrency_total_tva'];
289
						$line->multicurrency_total_ttc = $TTot['multicurrency_total_ttc'];
290
						$line->TTotal_tva_multicurrency = $TTot['TTotal_tva_multicurrency'];
291
					}
292
293
					$TRes[] = $line;
294
				}
295
			}
296
		}
297
298
		return $TRes;
299
	}
300
301
	/**
302
	 * @param CommonObject     $object
303
	 * @param CommonObjectLine $line
304
	 * @param boolean          $breakOnTitle
305
	 * @return array
306
	 */
307
	public static function getTotalBlockFromTitle(&$object, &$line, $breakOnTitle = false)
308
	{
309
		dol_include_once('/core/lib/price.lib.php');
310
		$TTot = array('total_pa_ht' => 0, 'total_options' => 0, 'total_ht' => 0, 'total_tva' => 0, 'total_ttc' => 0, 'TTotal_tva' => array(), 'multicurrency_total_ht' => 0, 'multicurrency_total_tva' => 0, 'multicurrency_total_ttc' => 0, 'TTotal_tva_multicurrency' => array());
311
312
		foreach ($object->lines as &$l)
313
		{
314
			if ($l->rang <= $line->rang) continue;
315
			elseif (self::isSubtotal($l) && self::getNiveau($l) <= self::getNiveau($line)) break;
316
			elseif ($breakOnTitle && self::isTitle($l) && self::getNiveau($l) <= self::getNiveau($line)) break;
317
318
			if (!empty($l->array_options['options_subtotal_nc']))
319
			{
320
				$tabprice = calcul_price_total($l->qty, $l->subprice, $l->remise_percent, $l->tva_tx, $l->localtax1_tx, $l->localtax2_tx, 0, 'HT', $l->info_bits, $l->product_type);
321
				$TTot['total_options'] += $tabprice[0]; // total ht
322
			}
323
			else
324
			{
325
				// Fix DA020000 : exlure les sous-totaux du calcul (calcul pété)
326
				// sinon ça compte les ligne de produit puis les sous-totaux qui leurs correspondent...
327
				if (! self::isSubtotal($l))
328
				{
329
					$TTot['total_pa_ht'] += $l->pa_ht * $l->qty;
330
					$TTot['total_subprice'] += $l->subprice * $l->qty;
331
					$TTot['total_unit_subprice'] += $l->subprice; // Somme des prix unitaires non remisés
332
					$TTot['total_ht'] += $l->total_ht;
333
					$TTot['total_tva'] += $l->total_tva;
334
					$TTot['total_ttc'] += $l->total_ttc;
335
					$TTot['TTotal_tva'][$l->tva_tx] += $l->total_tva;
336
					$TTot['multicurrency_total_ht'] += $l->multicurrency_total_ht;
337
					$TTot['multicurrency_total_tva'] += $l->multicurrency_total_tva;
338
					$TTot['multicurrency_total_ttc'] += $l->multicurrency_total_ttc;
339
					$TTot['TTotal_tva_multicurrency'][$l->tva_tx] += $l->multicurrency_total_tva;
340
				}
341
342
			}
343
		}
344
345
		return $TTot;
346
	}
347
348
	/**
349
	 * @param DoliDB  $db
350
	 * @param int     $fk_commandedet
351
	 * @param boolean $supplier
352
	 * @return int|false
353
	 */
354
	public static function getOrderIdFromLineId(&$db, $fk_commandedet, $supplier = false)
355
	{
356
		if (empty($fk_commandedet)) return false;
357
358
		$table = 'commandedet';
359
		if ($supplier) $table = 'commande_fournisseurdet';
360
361
		$sql = 'SELECT fk_commande FROM '.MAIN_DB_PREFIX.$table.' WHERE rowid = '.$fk_commandedet;
362
		$resql = $db->query($sql);
363
364
		if ($resql && ($row = $db->fetch_object($resql))) return $row->fk_commande;
365
		else return false;
366
	}
367
368
	/**
369
	 * @param DoliDB  $db
370
	 * @param int     $fk_commande
371
	 * @param boolean $supplier
372
	 * @return false|int
373
	 */
374
	public static function getLastLineOrderId(&$db, $fk_commande, $supplier = false)
375
	{
376
		if (empty($fk_commande)) return false;
377
378
        $table = 'commandedet';
379
        if ($supplier) $table = 'commande_fournisseurdet';
380
381
		$sql = 'SELECT rowid FROM '.MAIN_DB_PREFIX.$table.' WHERE fk_commande = '.$fk_commande.' ORDER BY rang DESC LIMIT 1';
382
		$resql = $db->query($sql);
383
384
		if ($resql && ($row = $db->fetch_object($resql))) return (int) $row->rowid;
385
		else return false;
386
	}
387
388
	/**
389
	 * @param FactureLigne|PropaleLigne|OrderLine $object
390
	 * @param int $rang  rank of the line in the object; The first line has rank = 1, not 0.
391
	 * @param int $lvl
392
	 * @return bool|FactureLigne|PropaleLigne|OrderLine
393
	 */
394
	public static function getParentTitleOfLine(&$object, $rang, $lvl = 0)
395
	{
396
		if ($rang <= 0) return false;
397
398
		$skip_title = 0;
399
		$TLineReverse = array_reverse($object->lines);
400
401
		foreach($TLineReverse as $line)
402
		{
403
			if ($line->rang >= $rang || ($lvl > 0 && self::getNiveau($line) > $lvl)) continue; // Tout ce qui ce trouve en dessous j'ignore, nous voulons uniquement ce qui ce trouve au dessus
404
405
            if (self::isTitle($line))
406
			{
407
				if ($skip_title)
408
				{
409
					$skip_title--;
410
					continue;
411
				}
412
413
				//@INFO J'ai ma ligne titre qui contient ma ligne, par contre je check pas s'il y a un sous-total
414
				return $line;
415
				break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
416
			}
417
			elseif (self::isSubtotal($line))
418
			{
419
				// Il s'agit d'un sous-total, ça veut dire que le prochain titre théoriquement doit être ignorer (je travail avec un incrément au cas ou je croise plusieurs sous-totaux)
420
				$skip_title++;
421
			}
422
		}
423
424
		return false;
425
	}
426
427
	/**
428
	 * @param CommonObjectLine $line
429
	 * @param int              $level
430
	 * @return bool
431
	 */
432
	public static function isTitle(&$line, $level=-1)
433
	{
434
		$res = $line->special_code == self::$module_number && $line->product_type == 9 && $line->qty <= 9;
435
		if($res && $level > -1) {
436
			return $line->qty == $level;
437
		} else return $res;
438
439
	}
440
441
	/**
442
	 * @param CommonObjectLine $line
443
	 * @param int              $level
444
	 * @return bool
445
	 */
446
	public static function isSubtotal(&$line, $level=-1)
447
	{
448
	    $res = $line->special_code == self::$module_number && $line->product_type == 9 && $line->qty >= 90;
449
	    if($res && $level > -1) {
450
	        return self::getNiveau($line) == $level;
451
	    } else return $res;
452
	}
453
454
	/**
455
	 * @param CommonObjectLine $line
456
	 * @return bool
457
	 */
458
	public static function isFreeText(&$line)
459
	{
460
		return $line->special_code == self::$module_number && $line->product_type == 9 && $line->qty == 50;
461
	}
462
463
	/**
464
	 * @param CommonObjectLine $line
465
	 * @return bool
466
	 */
467
	public static function isModSubtotalLine(&$line)
468
	{
469
		return self::isTitle($line) || self::isSubtotal($line) || self::isFreeText($line);
470
	}
471
472
	/**
473
	 * @param CommonObjectLine $line
474
	 * @param int $readonly
475
	 * @return string|void
476
	 */
477
	public static function getFreeTextHtml(&$line, $readonly=0)
478
	{
479
		global $conf;
480
481
		// Copie du fichier "objectline_edit.tpl.php"
482
		// editeur wysiwyg
483
		require_once DOL_DOCUMENT_ROOT.'/core/class/doleditor.class.php';
484
		$nbrows=ROWS_2;
485
		if (! empty($conf->global->MAIN_INPUT_DESC_HEIGHT)) $nbrows=$conf->global->MAIN_INPUT_DESC_HEIGHT;
486
		$enable=(isset($conf->global->FCKEDITOR_ENABLE_DETAILS)?$conf->global->FCKEDITOR_ENABLE_DETAILS:0);
487
		$toolbarname='dolibarr_details';
488
		if (! empty($conf->global->FCKEDITOR_ENABLE_DETAILS_FULL)) $toolbarname='dolibarr_notes';
489
		$text = !empty($line->description)?$line->description:$line->label;
490
		$doleditor=new DolEditor('line-description',$text,'',164,$toolbarname,'',false,true,$enable,$nbrows,'98%', $readonly);
491
		return $doleditor->Create(1);
492
	}
493
494
	/**
495
	 * @param CommonObject $object
496
	 * @param int          $lineid
497
	 * @param bool         $withBlockLine
498
	 * @return int
499
	 */
500
	public static function duplicateLines(&$object, $lineid, $withBlockLine=false)
501
	{
502
		global $db,$user,$conf;
503
504
		$createRight = $user->rights->{$object->element}->creer;
505
		if($object->element == 'facturerec' )
506
		{
507
		    $object->statut = 0; // hack for facture rec
508
		    $createRight = $user->rights->facture->creer;
509
		}
510
		elseif($object->element == 'order_supplier' )
511
		{
512
		    $createRight = $user->rights->fournisseur->commande->creer;
513
		}
514
		elseif($object->element == 'invoice_supplier' )
515
		{
516
		    $createRight = $user->rights->fournisseur->facture->creer;
517
		}
518
519
		if ($object->statut == 0  && $createRight && (!empty($conf->global->SUBTOTAL_ALLOW_DUPLICATE_BLOCK) || !empty($conf->global->SUBTOTAL_ALLOW_DUPLICATE_LINE)))
520
		{
521
			dol_include_once('/subtotal/lib/subtotal.lib.php');
522
523
            if(!empty($object->lines)) {
524
                foreach($object->lines as $line) {
525
                    if($line->id == $lineid) $duplicateLine = $line;
526
                }
527
            }
528
            if(!empty($duplicateLine) && !self::isModSubtotalLine($duplicateLine)) $TLine = array($duplicateLine);
529
            else $TLine = self::getLinesFromTitleId($object, $lineid, $withBlockLine);
530
531
			if (!empty($TLine))
532
			{
533
				$object->db->begin();
534
				$res = 1;
535
                $object->context['subtotalDuplicateLines'] = true;
536
537
				$TLineAdded = array();
538
				foreach ($TLine as $line)
539
				{
540
					// TODO refactore avec un doAddLine sur le même schéma que le doUpdateLine
541
					switch ($object->element) {
542
						case 'propal':
543
							//$desc, $pu_ht, $qty, $txtva, $txlocaltax1=0.0, $txlocaltax2=0.0, $fk_product=0, $remise_percent=0.0, $price_base_type='HT', $pu_ttc=0.0, $info_bits=0, $type=0, $rang=-1, $special_code=0, $fk_parent_line=0, $fk_fournprice=0, $pa_ht=0, $label='',$date_start='', $date_end='',$array_options=0, $fk_unit=null, $origin='', $origin_id=0)
544
							$res = $object->addline($line->desc, $line->subprice, $line->qty, $line->tva_tx, $line->localtax1_tx, $line->localtax2_tx, $line->fk_product, $line->remise_percent, 'HT', 0, $line->info_bits, $line->product_type, -1, $line->special_code, 0, 0, $line->pa_ht, $line->label, $line->date_start, $line->date_end, $line->array_options, $line->fk_unit, $object->element, $line->id);
545
							break;
546
547
						case 'supplier_proposal':
548
						    $res = $object->addline($line->desc, $line->subprice, $line->qty, $line->tva_tx, $line->localtax1_tx, $line->localtax2_tx, $line->fk_product, $line->remise_percent, 'HT', 0, $line->info_bits, $line->product_type, -1, $line->special_code, 0, 0, $line->pa_ht, $line->label, $line->date_start, $line->date_end, $line->array_options, $line->fk_unit, $object->element, $line->id);
549
						    break;
550
551
						case 'commande':
552
							//$desc, $pu_ht, $qty, $txtva, $txlocaltax1=0, $txlocaltax2=0, $fk_product=0, $remise_percent=0, $info_bits=0, $fk_remise_except=0, $price_base_type='HT', $pu_ttc=0, $date_start='', $date_end='', $type=0, $rang=-1, $special_code=0, $fk_parent_line=0, $fk_fournprice=null, $pa_ht=0, $label='',$array_options=0, $fk_unit=null, $origin='', $origin_id=0)
553
							$res = $object->addline($line->desc, $line->subprice, $line->qty, $line->tva_tx, $line->localtax1_tx, $line->localtax2_tx, $line->fk_product, $line->remise_percent, $line->info_bits, $line->fk_remise_except, 'HT', 0, $line->date_start, $line->date_end, $line->product_type, -1, $line->special_code, 0, 0, $line->pa_ht, $line->label, $line->array_options, $line->fk_unit, $object->element, $line->id);
554
							break;
555
556
						case 'order_supplier':
557
						    $object->line = $line;
558
						    $object->line->origin = $object->element;
559
						    $object->line->origin_id = $line->id;
560
						    $object->line->fk_commande = $object->id;
561
						    $object->line->rang = $object->line_max() +1;
562
						    $res = $object->line->insert(1);
563
							break;
564
565
						case 'facture':
566
							//$desc, $pu_ht, $qty, $txtva, $txlocaltax1=0, $txlocaltax2=0, $fk_product=0, $remise_percent=0, $date_start='', $date_end='', $ventil=0, $info_bits=0, $fk_remise_except='', $price_base_type='HT', $pu_ttc=0, $type=self::TYPE_STANDARD, $rang=-1, $special_code=0, $origin='', $origin_id=0, $fk_parent_line=0, $fk_fournprice=null, $pa_ht=0, $label='', $array_options=0, $situation_percent=100, $fk_prev_id='', $fk_unit = null
567
							$res = $object->addline($line->desc, $line->subprice, $line->qty, $line->tva_tx, $line->localtax1_tx, $line->localtax2_tx, $line->fk_product, $line->remise_percent, $line->date_start, $line->date_end, 0, $line->info_bits, $line->fk_remise_except, 'HT', 0, $line->product_type, -1, $line->special_code, $object->element, $line->id, $line->fk_parent_line, $line->fk_fournprice, $line->pa_ht, $line->label, $line->array_options, $line->situation_percent, $line->fk_prev_id, $line->fk_unit);
568
							break;
569
						/*	Totally useless on invoice supplier
570
						case 'invoice_supplier':
571
						    //var_dump($line); exit;
572
						    $rang = $object->line_max() +1;
573
						    $object->special_code = $line->special_code;
574
						    if (TSubtotal::isModSubtotalLine($line)) {
575
						        $object->line = $line;
576
						        $object->line->desc = $line->description;
577
						        $object->line->description = $line->description;
578
						        $object->line->fk_facture_fourn = $object->id;
579
						        $object->line->rang = $rang;
580
						        //var_dump($object->line); exit;
581
    						    $res = $object->line->insert(1);
582
						        break;
583
						        //var_dump($line->desc, $line->label, $line->description); exit;
584
						    }
585
						    $res = $object->addline($line->desc, $line->subprice, $line->tva_tx, $line->localtax1_tx, $line->localtax2_tx, $line->qty, $line->fk_product, $line->remise_percent, $line->date_start, $line->date_end, 0, $line->info_bits, 'HT', $line->product_type, $rang);
586
						    break;
587
							*/
588
						case 'facturerec':
589
							//$desc, $pu_ht, $qty, $txtva, $txlocaltax1=0, $txlocaltax2=0, $fk_product=0, $remise_percent=0, $date_start='', $date_end='', $ventil=0, $info_bits=0, $fk_remise_except='', $price_base_type='HT', $pu_ttc=0, $type=self::TYPE_STANDARD, $rang=-1, $special_code=0, $origin='', $origin_id=0, $fk_parent_line=0, $fk_fournprice=null, $pa_ht=0, $label='', $array_options=0, $situation_percent=100, $fk_prev_id='', $fk_unit = null
590
							$res = $object->addline($line->desc, $line->subprice, $line->qty, $line->tva_tx, $line->localtax1_tx, $line->localtax2_tx, $line->fk_product, $line->remise_percent, $line->date_start, $line->date_end, 0, $line->info_bits, $line->fk_remise_except, 'HT', 0, $line->product_type, -1, $line->special_code, $line->origin, $line->origin_id, $line->fk_parent_line, $line->fk_fournprice, $line->pa_ht, $line->label, $line->array_options, $line->situation_percent, $line->fk_prev_id, $line->fk_unit);
591
							break;
592
					}
593
594
					$TLineAdded[] = $object->line;
595
					// Error from addline
596
					if ($res <= 0) break;
597
				}
598
599
				if ($res > 0)
600
				{
601
					$object->db->commit();
602
					foreach ($TLineAdded as &$line)
603
					{
604
					    // ça peut paraitre non optimisé de déclancher la fonction sur toutes les lignes mais ceci est nécessaire pour réappliquer l'état exact de chaque ligne
605
                        //En gros ça met à jour le sous total
606
					   if(!empty($line->array_options['options_subtotal_nc'])) _updateLineNC($object->element, $object->id, $line->id, $line->array_options['options_subtotal_nc']);
607
					}
608
					return count($TLineAdded);
609
				}
610
				else
611
				{
612
					$object->db->rollback();
613
					return -1;
614
				}
615
			}
616
617
			return 0;
618
		}
619
	}
620
621
	/**
622
	 * @param CommonObject $object
623
	 * @param string       $key_trad
624
	 * @param int          $level
625
	 * @param string       $under_title
626
	 * @param bool         $withBlockLine
627
	 * @param bool         $key_is_id
628
	 * @return array
629
	 */
630
	public static function getLinesFromTitle(&$object, $key_trad, $level=1, $under_title='', $withBlockLine=false, $key_is_id=false)
631
	{
632
		global $langs;
633
634
		// Besoin de comparer sur les 2 formes d'écriture
635
		if (!$key_is_id) $TTitle_search = array($langs->trans($key_trad), $langs->transnoentitiesnoconv($key_trad));
636
637
		$TTitle_under_search = array();
638
		if (!empty($under_title)) $TTitle_under_search = array($langs->trans($under_title), $langs->transnoentitiesnoconv($under_title));
639
640
		$TLine = array();
641
		$add_line = false;
642
		$under_title_found=false;
643
644
		foreach ($object->lines as $key => &$line)
645
		{
646
			if (!$under_title_found && !empty($TTitle_under_search))
647
			{
648
				if ($line->product_type == 9 && (in_array($line->desc, $TTitle_under_search) || in_array($line->label, $TTitle_under_search)) ) $under_title_found = true;
649
			}
650
			else
651
			{
652
				if ( ($key_is_id && $line->id == $key_trad) || (!$key_is_id && $line->product_type == 9 && $line->qty == $level && (in_array($line->desc, $TTitle_search) || in_array($line->label, $TTitle_search) )))
653
				{
654
					if ($key_is_id) $level = $line->qty;
655
656
					$add_line = true;
657
					if ($withBlockLine) $TLine[] = $line;
658
					continue;
659
				}
660
				elseif ($add_line && TSubtotal::isModSubtotalLine($line) && TSubtotal::getNiveau($line) == $level) // Si on tombe sur un sous-total, il faut que ce soit un du même niveau que le titre
661
				{
662
					if ($withBlockLine) $TLine[] = $line;
663
					break;
664
				}
665
666
				if ($add_line)
667
				{
668
					if (!$withBlockLine && (self::isTitle($line) || self::isSubtotal($line)) ) continue;
669
					else $TLine[] = $line;
670
				}
671
			}
672
		}
673
674
		return $TLine;
675
	}
676
677
	/**
678
	 * @param CommonObject $object
679
	 * @param int          $lineid
680
	 * @param bool         $withBlockLine
681
	 * @return array
682
	 */
683
	public static function getLinesFromTitleId(&$object, $lineid, $withBlockLine=false)
684
	{
685
		return self::getLinesFromTitle($object, $lineid, '', '', $withBlockLine, true);
686
	}
687
688
	/**
689
	 * Wrapper around $object->updateline() to ensure it is called with the right parameters depending on the object's
690
	 * type.
691
	 *
692
	 * @param CommonObject $object
693
	 * @param int $rowid
694
	 * @param string $desc
695
	 * @param double $pu
696
	 * @param double $qty
697
	 * @param double $remise_percent
698
	 * @param $date_start
699
	 * @param $date_end
700
	 * @param double $txtva
701
	 * @param $type
702
	 * @param int $txlocaltax1
703
	 * @param int $txlocaltax2
704
	 * @param string $price_base_type
705
	 * @param int $info_bits
706
	 * @param int $fk_parent_line
707
	 * @param int $skip_update_total
708
	 * @param null $fk_fournprice
0 ignored issues
show
Documentation Bug introduced by
Are you sure the doc-type for parameter $fk_fournprice is correct as it would always require null to be passed?
Loading history...
709
	 * @param int $pa_ht
710
	 * @param string $label
711
	 * @param int $special_code
712
	 * @param int $array_options
713
	 * @param int $situation_percent
714
	 * @param null $fk_unit
0 ignored issues
show
Documentation Bug introduced by
Are you sure the doc-type for parameter $fk_unit is correct as it would always require null to be passed?
Loading history...
715
	 * @param int $notrigger
716
	 * @return int
717
	 */
718
	public static function doUpdateLine(&$object, $rowid, $desc, $pu, $qty, $remise_percent, $date_start, $date_end, $txtva, $type, $txlocaltax1=0, $txlocaltax2=0, $price_base_type='HT', $info_bits=0, $fk_parent_line=0, $skip_update_total=0, $fk_fournprice=null, $pa_ht=0, $label='', $special_code=0, $array_options=0, $situation_percent=0, $fk_unit = null, $notrigger = 0)
719
	{
720
		$res = 0;
721
		$object->db->begin();
722
723
		switch ($object->element)
724
		{
725
		    case 'propal':
726
		        $res = $object->updateline($rowid, $pu, $qty, $remise_percent, $txtva, $txlocaltax1, $txlocaltax2, $desc, $price_base_type, $info_bits, $special_code, $fk_parent_line, $skip_update_total, $fk_fournprice, $pa_ht, $label, $type, $date_start, $date_end, $array_options, $fk_unit, 0, $notrigger);
727
		        break;
728
729
		    case 'supplier_proposal':
730
		        $res = $object->updateline($rowid, $pu, $qty, $remise_percent, $txtva, $txlocaltax1, $txlocaltax2, $desc, $price_base_type, $info_bits, $special_code, $fk_parent_line, $skip_update_total, $fk_fournprice, $pa_ht, $label, $type, $array_options,'', $fk_unit);
731
		        break;
732
733
			case 'commande':
734
				$res = $object->updateline($rowid, $desc, $pu, $qty, $remise_percent, $txtva, $txlocaltax1, $txlocaltax2, $price_base_type, $info_bits, $date_start, $date_end, $type, $fk_parent_line, $skip_update_total, $fk_fournprice, $pa_ht, $label, $special_code, $array_options, $fk_unit, 0, $notrigger);
735
				break;
736
737
			case 'order_supplier':
738
			    $object->special_code = SELF::$module_number;
739
			    if (empty($desc)) $desc = $label;
740
			    $res = $object->updateline($rowid, $desc, $pu, $qty, $remise_percent, $txtva, $txlocaltax1, $txlocaltax2, $price_base_type, $info_bits, $type, 0, $date_start, $date_end, $array_options, $fk_unit);
741
			    break;
742
743
			case 'facture':
744
				$res = $object->updateline($rowid, $desc, $pu, $qty, $remise_percent, $date_start, $date_end, $txtva, $txlocaltax1, $txlocaltax2, $price_base_type, $info_bits, $type, $fk_parent_line, $skip_update_total, $fk_fournprice, $pa_ht, $label, $special_code, $array_options, $situation_percent, $fk_unit, 0, $notrigger);
745
				break;
746
747
			case 'invoice_supplier':
748
			    $object->special_code = SELF::$module_number;
749
			    if (empty($desc)) $desc = $label;
750
			    $res = $object->updateline($rowid, $desc, $pu, $txtva, $txlocaltax1, $txlocaltax2, $qty, 0, $price_base_type, $info_bits, $type, $remise_percent, 0, $date_start, $date_end, $array_options, $fk_unit);
751
			    break;
752
753
			case 'facturerec':
754
				// Add extrafields and get rang
755
				$factureRecLine = new FactureLigneRec($object->db);
756
				$factureRecLine->fetch($rowid);
757
				$factureRecLine->array_options = $array_options;
758
				$factureRecLine->insertExtraFields();
759
				$rang=$factureRecLine->rang;
760
761
				$fk_product=0; $fk_remise_except=''; $pu_ttc=0;
762
				$res = $object->updateline($rowid, $desc, $pu, $qty, $txtva, $txlocaltax1, $txlocaltax2, $fk_product, $remise_percent, $price_base_type, $info_bits, $fk_remise_except, $pu_ttc, $type, $rang, $special_code, $label, $fk_unit);
763
				break;
764
		}
765
766
		if ($res <= 0) $object->db->rollback();
767
		else $object->db->commit();
768
769
		return $res;
770
	}
771
772
	/**
773
	 * @param CommonObjectLine $origin_line
774
	 * @param bool             $reverse
775
	 * @return array
776
	 */
777
	public static function getAllTitleFromLine(&$origin_line, $reverse = false)
778
	{
779
		global $db, $object;
780
781
		$TTitle = array();
782
		if(! empty($object->id) && in_array($object->element, array('propal', 'commande', 'facture'))) {}
783
		else {
784
			if ($origin_line->element == 'propaldet')
785
			{
786
				$object = new Propal($db);
787
				$object->fetch($origin_line->fk_propal);
788
			}
789
			else if ($origin_line->element == 'commandedet')
790
			{
791
				$object = new Commande($db);
792
				$object->fetch($origin_line->fk_commande);
793
			}
794
			else if ($origin_line->element == 'facturedet')
795
			{
796
				$object = new Facture($db);
797
				$object->fetch($origin_line->fk_facture);
798
			}
799
			else
800
			{
801
				return $TTitle;
802
			}
803
		}
804
805
		// Récupération de la position de la ligne
806
		$i = 0;
807
		foreach ($object->lines as &$line)
808
		{
809
			if ($origin_line->id == $line->id) break;
810
			else $i++;
811
		}
812
813
		$i--; // Skip la ligne d'origine
814
815
		// Si elle n'est pas en 1ère position, alors on cherche des titres au dessus
816
		if ($i >= 0)
817
		{
818
			$next_title_lvl_to_skip = 0;
819
			for ($y = $i; $y >= 0; $y--)
820
			{
821
				// Si je tombe sur un sous-total, je récupère son niveau pour savoir quel est le prochain niveau de titre que doit ignorer
822
				if (self::isSubtotal($object->lines[$y]))
823
				{
824
					$next_title_lvl_to_skip = self::getNiveau($object->lines[$y]);
825
				}
826
				elseif (self::isTitle($object->lines[$y]))
827
				{
828
					if ($object->lines[$y]->qty == $next_title_lvl_to_skip)
829
					{
830
						$next_title_lvl_to_skip = 0;
831
						continue;
832
					}
833
					else
834
					{
835
						if (empty($object->lines[$y]->array_options) && !empty($object->lines[$y]->id)) $object->lines[$y]->fetch_optionals();
836
						$TTitle[$object->lines[$y]->id] = $object->lines[$y];
837
838
						if ($object->lines[$y]->qty == 1) break;
839
					}
840
				}
841
			}
842
		}
843
844
		if ($reverse) $TTitle = array_reverse($TTitle, true);
845
846
		return $TTitle;
847
	}
848
849
	/**
850
	 * @param CommonObjectLine $line
851
	 * @return int
852
	 */
853
	public static function getNiveau(&$line)
854
	{
855
		if (self::isTitle($line)) return $line->qty;
856
		elseif (self::isSubtotal($line)) return 100 - $line->qty;
857
		else return 0;
858
	}
859
860
	/**
861
	 * Ajoute une page de récap à la génération du PDF
862
	 * Le tableau total en bas du document se base sur les totaux des titres niveau 1 pour le moment
863
	 *
864
	 * @param array $parameters assoc array; keys: 'object' (CommonObject), 'file' (string), 'outputlangs' (Translate)
865
	 * @param null  $origin_pdf unused [lines that used it are commented out]
0 ignored issues
show
Documentation Bug introduced by
Are you sure the doc-type for parameter $origin_pdf is correct as it would always require null to be passed?
Loading history...
866
	 */
867
	public static function addRecapPage(&$parameters, &$origin_pdf)
868
	{
869
		global $user,$conf,$langs;
870
871
		$origin_file = $parameters['file'];
872
		$outputlangs = $parameters['outputlangs'];
873
		$object = $parameters['object'];
874
875
		$outputlangs->load('subtotal@subtotal');
876
877
		$objmarge = new stdClass();
878
		$objmarge->page_hauteur = 297;
879
		$objmarge->page_largeur = 210;
880
		$objmarge->marge_gauche = 10;
881
		$objmarge->marge_haute = 10;
882
		$objmarge->marge_droite = 10;
883
884
		$objectref = dol_sanitizeFileName($object->ref);
885
		if ($object->element == 'propal') $dir = $conf->propal->dir_output . '/' . $objectref;
886
		elseif ($object->element == 'commande') $dir = $conf->commande->dir_output . '/' . $objectref;
887
		elseif ($object->element == 'facture') $dir = $conf->facture->dir_output . '/' . $objectref;
888
		elseif ($object->element == 'facturerec') return; // no PDF for facturerec
889
		else
890
		{
891
			setEventMessage($langs->trans('warning_subtotal_recap_object_element_unknown', $object->element), 'warnings');
892
			return -1;
893
		}
894
		$file = $dir . '/' . $objectref . '_recap.pdf';
895
896
//		$pdf=pdf_getInstance($origin_pdf->format);
897
		$pdf=pdf_getInstance(array(210, 297)); // Format A4 Portrait
898
		$default_font_size = pdf_getPDFFontSize($outputlangs);	// Must be after pdf_getInstance
899
		$pdf->SetAutoPageBreak(1,0);
900
901
		if (class_exists('TCPDF'))
902
		{
903
			$pdf->setPrintHeader(false);
904
			$pdf->setPrintFooter(false);
905
		}
906
		$pdf->SetFont(pdf_getPDFFont($outputlangs));
907
		// Set path to the background PDF File
908
		if (empty($conf->global->MAIN_DISABLE_FPDI) && ! empty($conf->global->MAIN_ADD_PDF_BACKGROUND))
909
		{
910
			$pagecount = $pdf->setSourceFile($conf->mycompany->dir_output.'/'.$conf->global->MAIN_ADD_PDF_BACKGROUND);
911
			$tplidx = $pdf->importPage(1);
912
		}
913
914
		$pdf->Open();
915
		$pagenb=0;
916
		$pdf->SetDrawColor(128,128,128);
917
918
		$pdf->SetTitle($outputlangs->convToOutputCharset($object->ref));
919
		$pdf->SetSubject($outputlangs->transnoentities("subtotalRecap"));
920
		$pdf->SetCreator("Dolibarr ".DOL_VERSION);
921
		$pdf->SetAuthor($outputlangs->convToOutputCharset($user->getFullName($outputlangs)));
922
		$pdf->SetKeyWords($outputlangs->convToOutputCharset($object->ref)." ".$outputlangs->transnoentities("subtotalRecap")." ".$outputlangs->convToOutputCharset($object->thirdparty->name));
923
		if (! empty($conf->global->MAIN_DISABLE_PDF_COMPRESSION)) $pdf->SetCompression(false);
924
925
		$pdf->SetMargins($objmarge->marge_gauche, $objmarge->marge_haute, $objmarge->marge_droite);   // Left, Top, Right
926
927
		$pagenb=0;
928
		$pdf->SetDrawColor(128,128,128);
929
930
931
		// New page
932
		$pdf->AddPage();
933
		if (! empty($tplidx)) $pdf->useTemplate($tplidx);
934
		$pagenb++;
935
936
937
		self::pagehead($objmarge, $pdf, $object, 1, $outputlangs);
938
		$pdf->SetFont('','', $default_font_size - 1);
939
		$pdf->MultiCell(0, 3, '');		// Set interline to 3
940
		$pdf->SetTextColor(0,0,0);
941
942
		$heightforinfotot = 25;	// Height reserved to output the info and total part
943
		$heightforfooter = $objmarge->marge_basse + 8;	// Height reserved to output the footer (value include bottom margin)
944
945
		$posx_designation = 25;
946
		$posx_options = 150;
947
		$posx_montant = 170;
948
949
		$tab_top = 72;
950
		$tab_top_newpage = (empty($conf->global->MAIN_PDF_DONOTREPEAT_HEAD)?72:20); // TODO à vérifier
951
952
		$TTot = array('total_ht' => 0, 'total_ttc' => 0, 'TTotal_tva' => array());
953
954
		$TLine = self::getAllTitleFromDocument($object, true);
955
		if (!empty($TLine))
956
		{
957
			$hidetop = 0;
958
959
			$iniY = $tab_top + 10;
960
			$curY = $tab_top + 10;
961
			$nexY = $tab_top + 10;
962
963
			$nblignes = count($TLine);
964
			foreach($TLine as $i => &$line)
965
			{
966
				$curY = $nexY;
967
968
				if (self::getNiveau($line) == 1)
969
				{
970
					$pdf->SetFont('','B', $default_font_size - 1);   // Into loop to work with multipage
971
					$curY+=2;
972
973
					$TTot['total_ht'] += $line->total_ht;
974
					$TTot['total_tva'] += $line->total_tva;
975
					$TTot['total_ttc'] += $line->total_ttc;
976
					$TTot['multicurrency_total_ht'] += $line->multicurrency_total_ht;
977
					$TTot['multicurrency_total_tva'] += $line->multicurrency_total_tva;
978
					$TTot['multicurrency_total_ttc'] += $line->multicurrency_total_ttc;
979
980
					foreach ($line->TTotal_tva as $tx => $amount)
981
					{
982
						$TTot['TTotal_tva'][$tx] += $amount;
983
					}
984
985
					foreach ($line->TTotal_tva_multicurrency as $tx => $amount)
986
					{
987
						$TTot['TTotal_tva_multicurrency'][$tx] += $amount;
988
					}
989
				}
990
				else $pdf->SetFont('','', $default_font_size - 1);   // Into loop to work with multipage
991
992
				$pdf->SetTextColor(0,0,0);
993
994
				$pdf->setTopMargin($tab_top_newpage + 10);
995
				$pdf->setPageOrientation('', 1, $heightforfooter+$heightforinfotot);	// The only function to edit the bottom margin of current page to set it.
996
				$pageposbefore=$pdf->getPage();
997
998
				$showpricebeforepagebreak=1;
999
1000
				$decalage = (self::getNiveau($line) - 1) * 2;
1001
1002
				// Print: Designation
1003
				$label = $line->label;
1004
				if( (float)DOL_VERSION < 6 ) {
1005
					$label = !empty($line->label) ? $line->label : $line->desc;
1006
				}
1007
1008
1009
				$pdf->startTransaction();
1010
				$pdf->writeHTMLCell($posx_options-$posx_designation-$decalage, 3, $posx_designation+$decalage, $curY, $outputlangs->convToOutputCharset($label), 0, 1, false, true, 'J',true);
1011
				$pageposafter=$pdf->getPage();
1012
				if ($pageposafter > $pageposbefore)	// There is a pagebreak
1013
				{
1014
					$pdf->rollbackTransaction(true);
1015
					$pageposafter=$pageposbefore;
1016
					//print $pageposafter.'-'.$pageposbefore;exit;
1017
					$pdf->setPageOrientation('', 1, $heightforfooter);	// The only function to edit the bottom margin of current page to set it.
1018
					$pdf->writeHTMLCell($posx_options-$posx_designation-$decalage, 3, $posx_designation+$decalage, $curY, $outputlangs->convToOutputCharset($label), 0, 1, false, true, 'J',true);
1019
1020
					$pageposafter=$pdf->getPage();
1021
					$posyafter=$pdf->GetY();
1022
					//var_dump($posyafter); var_dump(($this->page_hauteur - ($heightforfooter+$heightforfreetext+$heightforinfotot))); exit;
1023
					if ($posyafter > ($objmarge->page_hauteur - ($heightforfooter+$heightforinfotot)))	// There is no space left for total+free text
1024
					{
1025
						if ($i == ($nblignes-1))	// No more lines, and no space left to show total, so we create a new page
1026
						{
1027
							$pdf->AddPage('','',true);
1028
							if (! empty($tplidx)) $pdf->useTemplate($tplidx);
1029
							if (empty($conf->global->MAIN_PDF_DONOTREPEAT_HEAD)) self::pagehead($objmarge, $pdf, $object, 0, $outputlangs);
1030
							$pdf->setPage($pageposafter+1);
1031
						}
1032
					}
1033
					else
1034
					{
1035
						// We found a page break
1036
						$showpricebeforepagebreak=0;
1037
					}
1038
				}
1039
				else	// No pagebreak
1040
				{
1041
					$pdf->commitTransaction();
1042
				}
1043
				$posYAfterDescription=$pdf->GetY();
1044
1045
				$nexY = $pdf->GetY();
1046
				$pageposafter=$pdf->getPage();
1047
1048
				$pdf->setPage($pageposbefore);
1049
				$pdf->setTopMargin($objmarge->marge_haute);
1050
				$pdf->setPageOrientation('', 1, 0);	// The only function to edit the bottom margin of current page to set it.
1051
1052
				// We suppose that a too long description or photo were moved completely on next page
1053
				if ($pageposafter > $pageposbefore && empty($showpricebeforepagebreak)) {
1054
					$pdf->setPage($pageposafter); $curY = $tab_top_newpage + 10;
1055
				}
1056
1057
				self::printLevel($objmarge, $pdf, $line, $curY, $posx_designation);
1058
1059
				// Print: Options
1060
				if (!empty($line->total_options))
1061
				{
1062
					$pdf->SetXY($posx_options, $curY);
1063
					$pdf->MultiCell($posx_montant-$posx_options-0.8, 3, price($line->total_options, 0, $outputlangs), 0, 'R', 0);
1064
				}
1065
1066
				// Print: Montant
1067
				$pdf->SetXY($posx_montant, $curY);
1068
				$pdf->MultiCell($objmarge->page_largeur-$objmarge->marge_droite-$posx_montant-0.8, 3, price($line->total_ht, 0, $outputlangs), 0, 'R', 0);
1069
1070
				$nexY+=2;    // Passe espace entre les lignes
1071
1072
				// Detect if some page were added automatically and output _tableau for past pages
1073
				while ($pagenb < $pageposafter)
1074
				{
1075
					$pdf->setPage($pagenb);
1076
					if ($pagenb == 1)
1077
					{
1078
						self::tableau($objmarge, $pdf, $posx_designation, $posx_options, $posx_montant, $tab_top, $objmarge->page_hauteur - $tab_top - $heightforfooter, 0, $outputlangs, 0, 1, $object->multicurrency_code);
1079
					}
1080
					else
1081
					{
1082
						self::tableau($objmarge, $pdf, $posx_designation, $posx_options, $posx_montant, $tab_top_newpage, $objmarge->page_hauteur - $tab_top_newpage - $heightforfooter, 0, $outputlangs, $hidetop, 1, $object->multicurrency_code);
1083
					}
1084
1085
					$pagenb++;
1086
					$pdf->setPage($pagenb);
1087
					$pdf->setPageOrientation('', 1, 0);	// The only function to edit the bottom margin of current page to set it.
1088
					if (empty($conf->global->MAIN_PDF_DONOTREPEAT_HEAD)) self::pagehead($objmarge, $pdf, $object, 0, $outputlangs);
1089
				}
1090
			}
1091
		}
1092
1093
		// Show square
1094
		if ($pagenb == 1)
1095
		{
1096
			self::tableau($objmarge, $pdf, $posx_designation, $posx_options, $posx_montant, $tab_top, $objmarge->page_hauteur - $tab_top - $heightforinfotot - $heightforfooter, 0, $outputlangs, 0, 0, $object->multicurrency_code);
1097
			$bottomlasttab=$objmarge->page_hauteur - $heightforinfotot - $heightforfooter + 1;
1098
		}
1099
		else
1100
		{
1101
			self::tableau($objmarge, $pdf, $posx_designation, $posx_options, $posx_montant, $tab_top_newpage, $objmarge->page_hauteur - $tab_top_newpage - $heightforinfotot - $heightforfooter, 0, $outputlangs, $hidetop, 0, $object->multicurrency_code);
1102
			$bottomlasttab=$objmarge->page_hauteur - $heightforinfotot - $heightforfooter + 1;
1103
		}
1104
1105
		// Affiche zone totaux
1106
		$posy=self::tableau_tot($objmarge, $pdf, $object, $bottomlasttab, $outputlangs, $TTot);
1107
1108
		$pdf->Close();
1109
		$pdf->Output($file,'F');
1110
1111
		$pagecount = self::concat($outputlangs, array($origin_file, $file), $origin_file);
1112
1113
		if (empty($conf->global->SUBTOTAL_KEEP_RECAP_FILE)) unlink($file);
1114
	}
1115
1116
	/**
1117
	 * @param stdClass         $objmarge Fields: 'marge_gauche', …
1118
	 * @param TCPDF            $pdf
1119
	 * @param CommonObjectLine $line
1120
	 * @param int              $curY
1121
	 * @param int              $posx_designation
1122
	 */
1123
	private static function printLevel($objmarge, $pdf, $line, $curY, $posx_designation)
1124
	{
1125
		$level = $line->qty; // TODO à améliorer
1126
1127
		$pdf->SetXY($objmarge->marge_gauche, $curY);
1128
		$pdf->MultiCell($posx_designation-$objmarge->marge_gauche-0.8, 5, $level, 0, 'L', 0);
1129
	}
1130
1131
	/**
1132
	 *  Show top header of page.
1133
	 *
1134
	 *  @param	TCPDF     $pdf          Object PDF
1135
	 *  @param  Object    $object       Object to show
1136
	 *  @param  int       $showdetail   0=no, 1=yes
1137
	 *  @param  Translate $outputlangs  Object lang for output
1138
	 *  @return	void
1139
	 */
1140
	private static function pagehead(&$objmarge, &$pdf, &$object, $showdetail, $outputlangs)
1141
	{
1142
		global $conf,$mysoc;
1143
1144
		$default_font_size = pdf_getPDFFontSize($outputlangs);
1145
1146
		pdf_pagehead($pdf,$outputlangs,$objmarge->page_hauteur);
1147
1148
		$pdf->SetTextColor(0,0,60);
1149
		$pdf->SetFont('','B', $default_font_size + 3);
1150
1151
		$posy=$objmarge->marge_haute;
1152
		$posx=$objmarge->page_largeur-$objmarge->marge_droite-100;
1153
1154
		$pdf->SetXY($objmarge->marge_gauche,$posy);
1155
1156
		$logo=$conf->mycompany->dir_output.'/logos/'.$mysoc->logo;
1157
		if ($mysoc->logo)
1158
		{
1159
			if (is_readable($logo))
1160
			{
1161
			    $height=pdf_getHeightForLogo($logo);
1162
			    $pdf->Image($logo, $objmarge->marge_gauche, $posy, 0, $height);	// width=0 (auto)
1163
			}
1164
			else
1165
			{
1166
				$pdf->SetTextColor(200,0,0);
1167
				$pdf->SetFont('','B',$default_font_size - 2);
1168
				$pdf->MultiCell(100, 3, $outputlangs->transnoentities("ErrorLogoFileNotFound",$logo), 0, 'L');
1169
				$pdf->MultiCell(100, 3, $outputlangs->transnoentities("ErrorGoToGlobalSetup"), 0, 'L');
1170
			}
1171
1172
			$posy+=35;
1173
		}
1174
		else
1175
		{
1176
			$text=$mysoc->name;
1177
			$pdf->MultiCell(100, 4, $outputlangs->convToOutputCharset($text), 0, 'L');
1178
1179
			$posy+=15;
1180
		}
1181
1182
1183
		$pdf->SetTextColor(0,0,0);
1184
		$pdf->SetFont('','B', $default_font_size + 2);
1185
		$pdf->SetXY($objmarge->marge_gauche,$posy);
1186
1187
		$key = 'subtotalPropalTitle';
1188
		if ($object->element == 'commande') $key = 'subtotalCommandeTitle';
1189
		elseif ($object->element == 'facture') $key = 'subtotalInvoiceTitle';
1190
		elseif ($object->element == 'facturerec') $key = 'subtotalInvoiceTitle';
1191
1192
		$pdf->MultiCell(150, 4, $outputlangs->transnoentities($key, $object->ref, $object->thirdparty->name), '', 'L');
1193
1194
		$pdf->SetFont('','', $default_font_size);
1195
		$pdf->SetXY($objmarge->page_largeur-$objmarge->marge_droite-40,$posy);
1196
		$pdf->MultiCell(40, 4, dol_print_date($object->date, 'daytext'), '', 'R');
1197
1198
		$posy += 8;
1199
1200
		$pdf->SetFont('','B', $default_font_size + 2);
1201
		$pdf->SetXY($objmarge->marge_gauche,$posy);
1202
		$pdf->MultiCell(70, 4, $outputlangs->transnoentities('subtotalRecapLot'), '', 'L');
1203
1204
	}
1205
1206
	/**
1207
	 *   Show table for lines
1208
	 *
1209
	 *   @param		PDF			$pdf     		Object PDF
1210
	 *   @param		string		$tab_top		Top position of table
1211
	 *   @param		string		$tab_height		Height of table (rectangle)
1212
	 *   @param		int			$nexY			Y (not used)
1213
	 *   @param		Translate	$outputlangs	Langs object
1214
	 *   @param		int			$hidetop		1=Hide top bar of array and title, 0=Hide nothing, -1=Hide only title
1215
	 *   @param		int			$hidebottom		Hide bottom bar of array
1216
	 *   @param		string		$currency		Currency code
1217
	 *   @return	void
1218
	 */
1219
	private static function tableau(&$objmarge, &$pdf, $posx_designation, $posx_options, $posx_montant, $tab_top, $tab_height, $nexY, $outputlangs, $hidetop=0, $hidebottom=0, $currency='')
1220
	{
1221
		global $conf;
1222
1223
		// Force to disable hidetop and hidebottom
1224
		$hidebottom=0;
1225
		if ($hidetop) $hidetop=-1;
1226
1227
		$currency = !empty($currency) ? $currency : $conf->currency;
1228
		$default_font_size = pdf_getPDFFontSize($outputlangs);
1229
1230
		// Amount in (at tab_top - 1)
1231
		$pdf->SetTextColor(0,0,0);
1232
		$pdf->SetFont('','',$default_font_size);
1233
1234
		if (empty($hidetop))
1235
		{
1236
			$titre = $outputlangs->transnoentities("AmountInCurrency",$outputlangs->transnoentitiesnoconv("Currency".$currency));
1237
			$pdf->SetXY($objmarge->page_largeur - $objmarge->marge_droite - ($pdf->GetStringWidth($titre) + 3), $tab_top-4.5);
1238
			$pdf->MultiCell(($pdf->GetStringWidth($titre) + 3), 2, $titre);
1239
1240
			if (! empty($conf->global->MAIN_PDF_TITLE_BACKGROUND_COLOR)) $pdf->Rect($objmarge->marge_gauche, $tab_top, $objmarge->page_largeur-$objmarge->marge_droite-$objmarge->marge_gauche, 8, 'F', null, explode(',',$conf->global->MAIN_PDF_TITLE_BACKGROUND_COLOR));
1241
1242
1243
			$pdf->line($objmarge->marge_gauche, $tab_top, $objmarge->page_largeur-$objmarge->marge_droite, $tab_top);	// line prend une position y en 2eme param et 4eme param
1244
1245
			$pdf->SetXY($posx_designation, $tab_top+2);
1246
			$pdf->MultiCell($posx_options - $posx_designation,2, $outputlangs->transnoentities("Designation"),'','L');
1247
			$pdf->SetXY($posx_options, $tab_top+2);
1248
			$pdf->MultiCell($posx_montant - $posx_options,2, $outputlangs->transnoentities("Options"),'','R');
1249
			$pdf->SetXY($posx_montant, $tab_top+2);
1250
			$pdf->MultiCell($objmarge->page_largeur - $objmarge->marge_droite - $posx_montant,2, $outputlangs->transnoentities("Amount"),'','R');
1251
1252
			$pdf->line($objmarge->marge_gauche, $tab_top+8, $objmarge->page_largeur-$objmarge->marge_droite, $tab_top+8);	// line prend une position y en 2eme param et 4eme param
1253
		}
1254
		else
1255
		{
1256
			$pdf->line($objmarge->marge_gauche, $tab_top-2, $objmarge->page_largeur-$objmarge->marge_droite, $tab_top-2);	// line prend une position y en 2eme param et 4eme param
1257
		}
1258
1259
	}
1260
1261
	/**
1262
	 * @param stdClass     $objmarge
1263
	 * @param TCPDF        $pdf
1264
	 * @param CommonObject $object
1265
	 * @param int          $posy
1266
	 * @param Translate    $outputlangs
1267
	 * @param array        $TTot
1268
	 * @return float|int
1269
	 */
1270
	private static function tableau_tot(&$objmarge, &$pdf, $object, $posy, $outputlangs, $TTot)
1271
	{
1272
		global $conf;
1273
1274
		$pdf->line($objmarge->marge_gauche, $posy, $objmarge->page_largeur-$objmarge->marge_droite, $posy);	// line prend une position y en 2eme param et 4eme param
1275
1276
		$default_font_size = pdf_getPDFFontSize($outputlangs);
1277
1278
		$tab2_top = $posy+2;
1279
		$tab2_hl = 4;
1280
		$pdf->SetFont('','', $default_font_size - 1);
1281
1282
		// Tableau total
1283
		$col1x = 120; $col2x = 170;
1284
		if ($objmarge->page_largeur < 210) // To work with US executive format
1285
		{
1286
			$col2x-=20;
1287
		}
1288
		$largcol2 = ($objmarge->page_largeur - $objmarge->marge_droite - $col2x);
1289
1290
		$useborder=0;
1291
		$index = 0;
1292
1293
		// Total HT
1294
		$pdf->SetFillColor(255,255,255);
1295
		$pdf->SetXY($col1x, $tab2_top + 0);
1296
		$pdf->MultiCell($col2x-$col1x, $tab2_hl, $outputlangs->transnoentities("TotalHT"), 0, 'L', 1);
1297
1298
		// $total_ht = ($conf->multicurrency->enabled && $object->mylticurrency_tx != 1) ? $TTot['multicurrency_total_ht'] : $TTot['total_ht'];
1299
		$total_ht = $TTot['total_ht'];
1300
		$pdf->SetXY($col2x, $tab2_top + 0);
1301
		$pdf->MultiCell($largcol2, $tab2_hl, price($total_ht, 0, $outputlangs), 0, 'R', 1);
1302
1303
		// Show VAT by rates and total
1304
		$pdf->SetFillColor(248,248,248);
1305
1306
		$atleastoneratenotnull=0;
1307
		foreach($TTot['TTotal_tva'] as $tvakey => $tvaval)
1308
		{
1309
			if ($tvakey != 0)    // On affiche pas taux 0
1310
			{
1311
				$atleastoneratenotnull++;
1312
1313
				$index++;
1314
				$pdf->SetXY($col1x, $tab2_top + $tab2_hl * $index);
1315
1316
				$tvacompl='';
1317
				if (preg_match('/\*/',$tvakey))
1318
				{
1319
					$tvakey=str_replace('*','',$tvakey);
1320
					$tvacompl = " (".$outputlangs->transnoentities("NonPercuRecuperable").")";
1321
				}
1322
				$totalvat =$outputlangs->transnoentities("TotalVAT").' ';
1323
				$totalvat.=vatrate($tvakey,1).$tvacompl;
1324
				$pdf->MultiCell($col2x-$col1x, $tab2_hl, $totalvat, 0, 'L', 1);
1325
1326
				$pdf->SetXY($col2x, $tab2_top + $tab2_hl * $index);
1327
				$pdf->MultiCell($largcol2, $tab2_hl, price($tvaval, 0, $outputlangs), 0, 'R', 1);
1328
			}
1329
		}
1330
1331
		// Total TTC
1332
		$index++;
1333
		$pdf->SetXY($col1x, $tab2_top + $tab2_hl * $index);
1334
		$pdf->SetTextColor(0,0,60);
1335
		$pdf->SetFillColor(224,224,224);
1336
		$pdf->MultiCell($col2x-$col1x, $tab2_hl, $outputlangs->transnoentities("TotalTTC"), $useborder, 'L', 1);
1337
1338
		// $total_ttc = ($conf->multicurrency->enabled && $object->multiccurency_tx != 1) ? $TTot['multicurrency_total_ttc'] : $TTot['total_ttc'];
1339
		$total_ttc = $TTot['total_ttc'];
1340
		$pdf->SetXY($col2x, $tab2_top + $tab2_hl * $index);
1341
		$pdf->MultiCell($largcol2, $tab2_hl, price($total_ttc, 0, $outputlangs), $useborder, 'R', 1);
1342
1343
		$pdf->SetTextColor(0,0,0);
1344
1345
		$index++;
1346
		return ($tab2_top + ($tab2_hl * $index));
1347
1348
	}
1349
1350
	/**
1351
	 * Rect pdf
1352
	 *
1353
	 * @param	PDF		$pdf			Object PDF
1354
	 * @param	float	$x				Abscissa of first point
1355
	 * @param	float	$y		        Ordinate of first point
1356
	 * @param	float	$l				??
1357
	 * @param	float	$h				??
1358
	 * @param	int		$hidetop		1=Hide top bar of array and title, 0=Hide nothing, -1=Hide only title
1359
	 * @param	int		$hidebottom		Hide bottom
1360
	 * @return	void
1361
	 */
1362
	private static function printRect($pdf, $x, $y, $l, $h, $hidetop=0, $hidebottom=0)
1363
	{
1364
	    if (empty($hidetop) || $hidetop==-1) $pdf->line($x, $y, $x+$l, $y);
1365
	    $pdf->line($x+$l, $y, $x+$l, $y+$h);
1366
	    if (empty($hidebottom)) $pdf->line($x+$l, $y+$h, $x, $y+$h);
1367
	    $pdf->line($x, $y+$h, $x, $y);
1368
	}
1369
1370
	/**
1371
	 * @param Translate $outputlangs
1372
	 * @param array     $files
1373
	 * @param string    $fileoutput
1374
	 * @return int
1375
	 */
1376
	public static function concat(&$outputlangs, $files, $fileoutput='')
1377
	{
1378
		global $conf;
1379
1380
		if (empty($fileoutput)) $fileoutput = $file[0];
1381
1382
		$pdf=pdf_getInstance();
1383
        if (class_exists('TCPDF'))
1384
        {
1385
            $pdf->setPrintHeader(false);
1386
            $pdf->setPrintFooter(false);
1387
        }
1388
        $pdf->SetFont(pdf_getPDFFont($outputlangs));
1389
1390
        if (! empty($conf->global->MAIN_DISABLE_PDF_COMPRESSION)) $pdf->SetCompression(false);
1391
1392
1393
		foreach($files as $file)
1394
		{
1395
			$pagecount = $pdf->setSourceFile($file);
1396
			for ($i = 1; $i <= $pagecount; $i++)
1397
			{
1398
				$tplidx = $pdf->ImportPage($i);
1399
				$s = $pdf->getTemplatesize($tplidx);
1400
				$pdf->AddPage($s['h'] > $s['w'] ? 'P' : 'L');
1401
				$pdf->useTemplate($tplidx);
1402
			}
1403
		}
1404
1405
		$pdf->Output($fileoutput,'F');
1406
		if (! empty($conf->global->MAIN_UMASK)) @chmod($file, octdec($conf->global->MAIN_UMASK));
1407
1408
		return $pagecount;
1409
	}
1410
1411
	/**
1412
	 * Méthode pour savoir si une ligne fait partie d'un bloc Compris/Non Compris
1413
	 *
1414
	 * @param PropaleLigne|OrderLine|FactureLigne	$line
1415
	 * @return	true or false
1416
	 */
1417
	public static function hasNcTitle(&$line)
1418
	{
1419
		if(isset($line->has_nc_title)) return $line->has_nc_title;
1420
1421
		$TTitle = self::getAllTitleFromLine($line);
1422
		foreach ($TTitle as &$line_title)
1423
		{
1424
			if (!empty($line_title->array_options['options_subtotal_nc']))
1425
			{
1426
				$line->has_nc_title = true;
1427
				return true;
1428
			}
1429
		}
1430
1431
		$line->has_nc_title = false;
1432
		return false;
1433
	}
1434
1435
	/**
1436
	 * Méthode pour récupérer le titre de la ligne
1437
	 *
1438
	 * @param PropaleLigne|OrderLine|FactureLigne	$line
1439
	 * @return	string
1440
	 */
1441
	public static function getTitleLabel($line)
1442
	{
1443
		$title = $line->label;
1444
		if (empty($title)) $title = !empty($line->description) ? $line->description : $line->desc;
1445
		return $title;
1446
	}
1447
}
1448