Passed
Branch develop (5cbde9)
by
unknown
26:38
created

FactureRec::addline()   F

Complexity

Conditions 17
Paths 16387

Size

Total Lines 155
Code Lines 120

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 17
eloc 120
c 0
b 0
f 0
nc 16387
nop 22
dl 0
loc 155
rs 0.8399

How to fix   Long Method    Complexity    Many Parameters   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

Many Parameters

Methods with many parameters are not only hard to understand, but their parameters also often become inconsistent when you need more, or different data.

There are several approaches to avoid long parameter lists:

1
<?php
2
/* Copyright (C) 2003-2005	Rodolphe Quiedeville	<[email protected]>
3
 * Copyright (C) 2004-2015	Laurent Destailleur		<[email protected]>
4
 * Copyright (C) 2009-2012	Regis Houssin			<[email protected]>
5
 * Copyright (C) 2010-2011	Juanjo Menent			<[email protected]>
6
 * Copyright (C) 2012       Cedric Salvador         <[email protected]>
7
 * Copyright (C) 2013       Florian Henry		  	<[email protected]>
8
 * Copyright (C) 2015       Marcos García           <[email protected]>
9
 * Copyright (C) 2017       Frédéric France         <[email protected]>
10
 *
11
 * This program is free software; you can redistribute it and/or modify
12
 * it under the terms of the GNU General Public License as published by
13
 * the Free Software Foundation; either version 3 of the License, or
14
 * (at your option) any later version.
15
 *
16
 * This program is distributed in the hope that it will be useful,
17
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19
 * GNU General Public License for more details.
20
 *
21
 * You should have received a copy of the GNU General Public License
22
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
23
 */
24
25
/**
26
 *	\file       htdocs/compta/facture/class/facture-rec.class.php
27
 *	\ingroup    facture
28
 *	\brief      Fichier de la classe des factures recurentes
29
 */
30
31
require_once DOL_DOCUMENT_ROOT.'/core/class/notify.class.php';
32
require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php';
33
require_once DOL_DOCUMENT_ROOT.'/compta/facture/class/facture.class.php';
34
require_once DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php';
35
36
37
/**
38
 *	Class to manage invoice templates
39
 */
40
class FactureRec extends CommonInvoice
41
{
42
	/**
43
	 * @var string ID to identify managed object
44
	 */
45
	public $element='facturerec';
46
47
	/**
48
	 * @var string Name of table without prefix where object is stored
49
	 */
50
	public $table_element='facture_rec';
51
52
	/**
53
	 * @var int    Name of subtable line
54
	 */
55
	public $table_element_line='facturedet_rec';
56
57
	/**
58
	 * @var int Field with ID of parent key if this field has a parent
59
	 */
60
	public $fk_element='fk_facture';
61
62
	/**
63
	 * @var string String with name of icon for myobject. Must be the part after the 'object_' into object_myobject.png
64
	 */
65
	public $picto='bill';
66
67
	/**
68
	 * @var int Entity
69
	 */
70
	public $entity;
71
72
	public $number;
73
	public $date;
74
	public $amount;
75
	public $remise;
76
	public $tva;
77
	public $total;
78
	public $db_table;
79
	public $propalid;
80
81
	public $date_last_gen;
82
	public $date_when;
83
	public $nb_gen_done;
84
	public $nb_gen_max;
85
86
	public $frequency;
87
	public $unit_frequency;
88
89
	public $rang;
90
	public $special_code;
91
92
	public $usenewprice=0;
93
94
	public $suspended;			// status
95
96
	const STATUS_NOTSUSPENDED = 0;
97
	const STATUS_SUSPENDED = 1;
98
99
100
101
	/**
102
	 *	Constructor
103
	 *
104
	 * 	@param		DoliDB		$db		Database handler
105
	 */
106
	public function __construct($db)
107
	{
108
		$this->db = $db;
109
	}
110
111
	/**
112
	 * 	Create a predefined invoice
113
	 *
114
	 * 	@param		User	$user		User object
115
	 * 	@param		int		$facid		Id of source invoice
116
	 *	@return		int					<0 if KO, id of invoice created if OK
117
	 */
118
	public function create($user, $facid)
119
	{
120
		global $conf;
121
122
		$error=0;
123
		$now=dol_now();
124
125
		// Clean parameters
126
		$this->titre=trim($this->titre);	// deprecated
127
		$this->title=trim($this->title);
128
		$this->usenewprice=empty($this->usenewprice)?0:$this->usenewprice;
129
		if (empty($this->suspended)) $this->suspended=0;
130
131
		// No frequency defined then no next date to execution
132
		if (empty($this->frequency))
133
		{
134
			$this->frequency=0;
135
			$this->date_when=null;
136
		}
137
138
139
		$this->frequency=abs($this->frequency);
140
		$this->nb_gen_done=0;
141
		$this->nb_gen_max=empty($this->nb_gen_max)?0:$this->nb_gen_max;
142
		$this->auto_validate=empty($this->auto_validate)?0:$this->auto_validate;
143
		$this->generate_pdf = empty($this->generate_pdf)?0:$this->generate_pdf;
144
145
		$this->db->begin();
146
147
		// Charge facture modele
148
		$facsrc=new Facture($this->db);
149
		$result=$facsrc->fetch($facid);
150
		if ($result > 0)
151
		{
152
			// On positionne en mode brouillon la facture
153
			$this->brouillon = 1;
154
155
			$sql = "INSERT INTO ".MAIN_DB_PREFIX."facture_rec (";
156
			$sql.= "titre";
157
			$sql.= ", fk_soc";
158
			$sql.= ", entity";
159
			$sql.= ", datec";
160
			$sql.= ", amount";
161
			$sql.= ", remise";
162
			$sql.= ", note_private";
163
			$sql.= ", note_public";
164
			$sql.= ", modelpdf";
165
			$sql.= ", fk_user_author";
166
			$sql.= ", fk_projet";
167
			$sql.= ", fk_account";
168
			$sql.= ", fk_cond_reglement";
169
			$sql.= ", fk_mode_reglement";
170
			$sql.= ", usenewprice";
171
			$sql.= ", frequency";
172
			$sql.= ", unit_frequency";
173
			$sql.= ", date_when";
174
			$sql.= ", date_last_gen";
175
			$sql.= ", nb_gen_done";
176
			$sql.= ", nb_gen_max";
177
			$sql.= ", auto_validate";
178
			$sql.= ", generate_pdf";
179
			$sql.= ", fk_multicurrency";
180
			$sql.= ", multicurrency_code";
181
			$sql.= ", multicurrency_tx";
182
			$sql.= ", suspended";
183
			$sql.= ") VALUES (";
184
			$sql.= "'".$this->db->escape($this->titre ? $this->titre : $this->title)."'";
185
			$sql.= ", ".$facsrc->socid;
186
			$sql.= ", ".$conf->entity;
187
			$sql.= ", '".$this->db->idate($now)."'";
188
			$sql.= ", ".(!empty($facsrc->amount)?$facsrc->amount:'0');
0 ignored issues
show
Bug introduced by
The property amount does not seem to exist on Facture.
Loading history...
189
			$sql.= ", ".(!empty($facsrc->remise)?$this->remise:'0');
0 ignored issues
show
Bug introduced by
The property remise does not exist on Facture. Did you mean remise_percent?
Loading history...
190
			$sql.= ", ".(!empty($this->note_private)?("'".$this->db->escape($this->note_private)."'"):"NULL");
191
			$sql.= ", ".(!empty($this->note_public)?("'".$this->db->escape($this->note_public)."'"):"NULL");
192
			$sql.= ", ".(!empty($this->modelpdf)?("'".$this->db->escape($this->modelpdf)."'"):"NULL");
193
			$sql.= ", '".$this->db->escape($user->id)."'";
194
			$sql.= ", ".(! empty($facsrc->fk_project)?"'".$facsrc->fk_project."'":"null");
195
			$sql.= ", ".(! empty($facsrc->fk_account)?"'".$facsrc->fk_account."'":"null");
196
			$sql.= ", ".($facsrc->cond_reglement_id > 0 ? $this->db->escape($facsrc->cond_reglement_id) : "null");
197
			$sql.= ", ".($facsrc->mode_reglement_id > 0 ? $this->db->escape($facsrc->mode_reglement_id) : "null");
198
			$sql.= ", ".$this->usenewprice;
199
			$sql.= ", ".$this->frequency;
200
			$sql.= ", '".$this->db->escape($this->unit_frequency)."'";
201
			$sql.= ", ".(!empty($this->date_when)?"'".$this->db->idate($this->date_when)."'":'NULL');
202
			$sql.= ", ".(!empty($this->date_last_gen)?"'".$this->db->idate($this->date_last_gen)."'":'NULL');
203
			$sql.= ", ".$this->db->escape($this->nb_gen_done);
204
			$sql.= ", ".$this->db->escape($this->nb_gen_max);
205
			$sql.= ", ".$this->db->escape($this->auto_validate);
206
			$sql.= ", ".$this->db->escape($this->generate_pdf);
207
			$sql.= ", ".$this->db->escape($facsrc->fk_multicurrency);
208
			$sql.= ", '".$this->db->escape($facsrc->multicurrency_code)."'";
209
			$sql.= ", ".$this->db->escape($facsrc->multicurrency_tx);
210
			$sql.= ", ".$this->db->escape($this->suspended);
211
			$sql.= ")";
212
213
			if ($this->db->query($sql))
214
			{
215
				$this->id = $this->db->last_insert_id(MAIN_DB_PREFIX."facture_rec");
216
217
				// Fields used into addline later
218
				$this->fk_multicurrency = $facsrc->fk_multicurrency;
219
				$this->multicurrency_code = $facsrc->multicurrency_code;
220
				$this->multicurrency_tx = $facsrc->multicurrency_tx;
221
222
				// Add lines
223
				$num=count($facsrc->lines);
224
				for ($i = 0; $i < $num; $i++)
225
				{
226
					$tva_tx = $facsrc->lines[$i]->tva_tx;
227
					if (! empty($facsrc->lines[$i]->vat_src_code) && ! preg_match('/\(/', $tva_tx)) $tva_tx .= ' ('.$facsrc->lines[$i]->vat_src_code.')';
228
229
                    $result_insert = $this->addline(
230
                        $facsrc->lines[$i]->desc,
231
                        $facsrc->lines[$i]->subprice,
232
                        $facsrc->lines[$i]->qty,
233
						$tva_tx,
234
                        $facsrc->lines[$i]->localtax1_tx,
235
                        $facsrc->lines[$i]->localtax2_tx,
236
                        $facsrc->lines[$i]->fk_product,
237
                        $facsrc->lines[$i]->remise_percent,
238
                        'HT',
239
						$facsrc->lines[$i]->info_bits,
240
                        '',
241
                        0,
242
                        $facsrc->lines[$i]->product_type,
243
                        $facsrc->lines[$i]->rang,
244
                        $facsrc->lines[$i]->special_code,
245
                    	$facsrc->lines[$i]->label,
1 ignored issue
show
Deprecated Code introduced by
The property FactureLigne::$label has been deprecated. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

245
                    	/** @scrutinizer ignore-deprecated */ $facsrc->lines[$i]->label,
Loading history...
246
						$facsrc->lines[$i]->fk_unit,
247
						$facsrc->lines[$i]->multicurrency_subprice
248
                    );
249
250
					if ($result_insert < 0)
251
					{
252
						$error++;
253
					}
254
				}
255
256
				if (! empty($this->linkedObjectsIds) && empty($this->linked_objects))	// To use new linkedObjectsIds instead of old linked_objects
257
				{
258
					$this->linked_objects = $this->linkedObjectsIds;	// TODO Replace linked_objects with linkedObjectsIds
259
				}
260
261
				// Add object linked
262
				if (! $error && $this->id && is_array($this->linked_objects) && ! empty($this->linked_objects))
263
				{
264
					foreach($this->linked_objects as $origin => $tmp_origin_id)
265
					{
266
					    if (is_array($tmp_origin_id))       // New behaviour, if linked_object can have several links per type, so is something like array('contract'=>array(id1, id2, ...))
267
					    {
268
					        foreach($tmp_origin_id as $origin_id)
269
					        {
270
					            $ret = $this->add_object_linked($origin, $origin_id);
271
					            if (! $ret)
272
					            {
273
					                $this->error=$this->db->lasterror();
274
					                $error++;
275
					            }
276
					        }
277
					    }
278
					    else                                // Old behaviour, if linked_object has only one link per type, so is something like array('contract'=>id1))
279
					    {
280
					        $origin_id = $tmp_origin_id;
281
	    					$ret = $this->add_object_linked($origin, $origin_id);
282
	    					if (! $ret)
283
	    					{
284
	    						$this->error=$this->db->lasterror();
285
	    						$error++;
286
	    					}
287
					    }
288
					}
289
				}
290
291
				if ($error)
292
				{
293
					$this->db->rollback();
294
				}
295
				else
296
				{
297
					$this->db->commit();
298
					return $this->id;
299
				}
300
			}
301
			else
302
			{
303
			    $this->error=$this->db->lasterror();
304
				$this->db->rollback();
305
				return -2;
306
			}
307
		}
308
		else
309
		{
310
			$this->db->rollback();
311
			return -1;
312
		}
313
	}
314
315
316
	/**
317
	 * 	Update a line to invoice_rec.
318
	 *
319
	 *  @param		User	$user					User
320
	 *  @param		int		$notrigger				No trigger
321
	 *	@return    	int             				<0 if KO, Id of line if OK
322
	 */
323
	public function update(User $user, $notrigger = 0)
324
	{
325
	    global $conf;
326
327
        $error = 0;
328
329
	    $sql = "UPDATE ".MAIN_DB_PREFIX."facture_rec SET";
330
	    $sql.= " fk_soc = ".$this->fk_soc;
331
        // TODO Add missing fields
332
	    $sql.= " WHERE rowid = ".$this->id;
333
334
	    dol_syslog(get_class($this)."::update", LOG_DEBUG);
335
	    $resql=$this->db->query($sql);
336
	    if ($resql)
337
	    {
338
	        if (empty($conf->global->MAIN_EXTRAFIELDS_DISABLED)) // For avoid conflicts if trigger used
339
	        {
340
	            $result=$this->insertExtraFields();
341
	            if ($result < 0)
342
	            {
343
	                $error++;
344
	            }
345
	        }
346
347
	        if (! $error && ! $notrigger)
348
	        {
349
	            // Call trigger
350
	            $result=$this->call_trigger('BILLREC_UPDATE', $user);
351
	            if ($result < 0)
352
	            {
353
	                $this->db->rollback();
354
	                return -2;
355
	            }
356
	            // End call triggers
357
	        }
358
	        $this->db->commit();
359
	        return 1;
360
	    }
361
	    else
362
	    {
363
	        $this->error=$this->db->lasterror();
364
	        $this->db->rollback();
365
	        return -2;
366
	    }
367
	}
368
369
	/**
370
	 *	Load object and lines
371
	 *
372
	 *	@param      int		$rowid       	Id of object to load
373
	 * 	@param		string	$ref			Reference of recurring invoice
374
	 * 	@param		string	$ref_ext		External reference of invoice
375
	 * 	@param		int		$ref_int		Internal reference of other object
376
	 *	@return     int         			>0 if OK, <0 if KO, 0 if not found
377
	 */
378
	public function fetch($rowid, $ref = '', $ref_ext = '', $ref_int = '')
379
	{
380
		$sql = 'SELECT f.rowid, f.entity, f.titre as title, f.suspended, f.fk_soc, f.amount, f.tva, f.localtax1, f.localtax2, f.total, f.total_ttc';
381
		$sql.= ', f.remise_percent, f.remise_absolue, f.remise';
382
		$sql.= ', f.date_lim_reglement as dlr';
383
		$sql.= ', f.note_private, f.note_public, f.fk_user_author';
384
        $sql.= ', f.modelpdf';
385
		$sql.= ', f.fk_mode_reglement, f.fk_cond_reglement, f.fk_projet as fk_project';
386
		$sql.= ', f.fk_account';
387
		$sql.= ', f.frequency, f.unit_frequency, f.date_when, f.date_last_gen, f.nb_gen_done, f.nb_gen_max, f.usenewprice, f.auto_validate';
388
        $sql.= ', f.generate_pdf';
389
        $sql.= ", f.fk_multicurrency, f.multicurrency_code, f.multicurrency_tx, f.multicurrency_total_ht, f.multicurrency_total_tva, f.multicurrency_total_ttc";
390
        $sql.= ', p.code as mode_reglement_code, p.libelle as mode_reglement_libelle';
391
		$sql.= ', c.code as cond_reglement_code, c.libelle as cond_reglement_libelle, c.libelle_facture as cond_reglement_libelle_doc';
392
		//$sql.= ', el.fk_source';
393
		$sql.= ' FROM '.MAIN_DB_PREFIX.'facture_rec as f';
394
		$sql.= ' LEFT JOIN '.MAIN_DB_PREFIX.'c_payment_term as c ON f.fk_cond_reglement = c.rowid';
395
		$sql.= ' LEFT JOIN '.MAIN_DB_PREFIX.'c_paiement as p ON f.fk_mode_reglement = p.id';
396
		//$sql.= " LEFT JOIN ".MAIN_DB_PREFIX."element_element as el ON el.fk_target = f.rowid AND el.targettype = 'facture'";
397
		$sql.= ' WHERE f.entity IN ('.getEntity('invoice').')';
398
		if ($rowid) $sql.= ' AND f.rowid='.$rowid;
399
		elseif ($ref) $sql.= " AND f.titre='".$this->db->escape($ref)."'";
400
		/* This field are not used for template invoice
401
		if ($ref_ext) $sql.= " AND f.ref_ext='".$this->db->escape($ref_ext)."'";
402
		if ($ref_int) $sql.= " AND f.ref_int='".$this->db->escape($ref_int)."'";
403
		*/
404
405
		$result = $this->db->query($sql);
406
		if ($result)
407
		{
408
			if ($this->db->num_rows($result))
409
			{
410
				$obj = $this->db->fetch_object($result);
411
412
				$this->id                     = $obj->rowid;
413
				$this->entity                 = $obj->entity;
414
				$this->titre                  = $obj->title;	// deprecated
415
				$this->title                  = $obj->title;
416
				$this->ref                    = $obj->title;
417
				$this->ref_client             = $obj->ref_client;
418
				$this->suspended              = $obj->suspended;
419
				$this->type                   = $obj->type;
420
				$this->datep                  = $obj->dp;
421
				$this->date                   = $obj->df;
422
				$this->amount                 = $obj->amount;
423
				$this->remise_percent         = $obj->remise_percent;
424
				$this->remise_absolue         = $obj->remise_absolue;
425
				$this->remise                 = $obj->remise;
426
				$this->total_ht               = $obj->total;
427
				$this->total_tva              = $obj->tva;
428
				$this->total_localtax1        = $obj->localtax1;
429
				$this->total_localtax2        = $obj->localtax2;
430
				$this->total_ttc              = $obj->total_ttc;
431
				$this->paye                   = $obj->paye;
432
				$this->close_code             = $obj->close_code;
433
				$this->close_note             = $obj->close_note;
434
				$this->socid                  = $obj->fk_soc;
435
				$this->date_lim_reglement     = $this->db->jdate($obj->dlr);
436
				$this->mode_reglement_id      = $obj->fk_mode_reglement;
437
				$this->mode_reglement_code    = $obj->mode_reglement_code;
438
				$this->mode_reglement         = $obj->mode_reglement_libelle;
439
				$this->cond_reglement_id      = $obj->fk_cond_reglement;
440
				$this->cond_reglement_code    = $obj->cond_reglement_code;
441
				$this->cond_reglement         = $obj->cond_reglement_libelle;
442
				$this->cond_reglement_doc     = $obj->cond_reglement_libelle_doc;
443
				$this->fk_project             = $obj->fk_project;
444
				$this->fk_account             = $obj->fk_account;
445
				$this->fk_facture_source      = $obj->fk_facture_source;
446
				$this->note_private           = $obj->note_private;
447
				$this->note_public            = $obj->note_public;
448
				$this->user_author            = $obj->fk_user_author;
449
				$this->modelpdf               = $obj->modelpdf;
450
				$this->rang					  = $obj->rang;
451
				$this->special_code			  = $obj->special_code;
452
				$this->frequency			  = $obj->frequency;
453
				$this->unit_frequency		  = $obj->unit_frequency;
454
				$this->date_when			  = $this->db->jdate($obj->date_when);
455
				$this->date_last_gen		  = $this->db->jdate($obj->date_last_gen);
456
				$this->nb_gen_done			  = $obj->nb_gen_done;
457
				$this->nb_gen_max			  = $obj->nb_gen_max;
458
				$this->usenewprice			  = $obj->usenewprice;
459
				$this->auto_validate		  = $obj->auto_validate;
460
				$this->generate_pdf           = $obj->generate_pdf;
461
462
				// Multicurrency
463
				$this->fk_multicurrency 		= $obj->fk_multicurrency;
464
				$this->multicurrency_code 		= $obj->multicurrency_code;
465
				$this->multicurrency_tx 		= $obj->multicurrency_tx;
466
				$this->multicurrency_total_ht 	= $obj->multicurrency_total_ht;
467
				$this->multicurrency_total_tva 	= $obj->multicurrency_total_tva;
468
				$this->multicurrency_total_ttc 	= $obj->multicurrency_total_ttc;
469
470
				if ($this->statut == self::STATUS_DRAFT)	$this->brouillon = 1;
471
472
				// Retreive all extrafield
473
				// fetch optionals attributes and labels
474
				$this->fetch_optionals();
475
476
				/*
477
				 * Lines
478
				 */
479
				$result=$this->fetch_lines();
480
				if ($result < 0)
481
				{
482
					$this->error=$this->db->lasterror();
483
					return -3;
484
				}
485
				return 1;
486
			}
487
			else
488
			{
489
				$this->error='Bill with id '.$rowid.' or ref '.$ref.' not found sql='.$sql;
490
				dol_syslog('Facture::Fetch Error '.$this->error, LOG_ERR);
491
				return -2;
492
			}
493
		}
494
		else
495
		{
496
			$this->error=$this->db->error();
497
			return -1;
498
		}
499
	}
500
501
502
	/**
503
	 * 	Create an array of invoice lines
504
	 *
505
	 * 	@return int		>0 if OK, <0 if KO
506
	 */
507
	public function getLinesArray()
508
	{
509
	    return $this->fetch_lines();
510
	}
511
512
513
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
514
	/**
515
	 *	Get lines of template invoices into this->lines
516
	 *
517
	 *  @return     int         1 if OK, < 0 if KO
518
     */
519
	public function fetch_lines()
520
	{
521
        // phpcs:enable
522
		$this->lines=array();
523
524
		// Retreive all extrafield for line
525
		// fetch optionals attributes and labels
526
		require_once DOL_DOCUMENT_ROOT.'/core/class/extrafields.class.php';
527
		$extrafieldsline=new ExtraFields($this->db);
528
		$extrafieldsline=$extrafieldsline->fetch_name_optionals_label('facturedet_rec', true);
529
530
		$sql = 'SELECT l.rowid, l.fk_product, l.product_type, l.label as custom_label, l.description, l.product_type, l.price, l.qty, l.vat_src_code, l.tva_tx, ';
531
		$sql.= ' l.localtax1_tx, l.localtax2_tx, l.localtax1_type, l.localtax2_type, l.remise, l.remise_percent, l.subprice,';
532
		$sql.= ' l.info_bits, l.date_start_fill, l.date_end_fill, l.total_ht, l.total_tva, l.total_ttc, l.fk_product_fournisseur_price as fk_fournprice, l.buy_price_ht as pa_ht,';
533
		//$sql.= ' l.situation_percent, l.fk_prev_id,';
534
		//$sql.= ' l.localtax1_tx, l.localtax2_tx, l.localtax1_type, l.localtax2_type, l.remise_percent, l.fk_remise_except, l.subprice,';
535
		$sql.= ' l.rang, l.special_code,';
536
		//$sql.= ' l.info_bits, l.total_ht, l.total_tva, l.total_localtax1, l.total_localtax2, l.total_ttc, l.fk_code_ventilation, l.fk_product_fournisseur_price as fk_fournprice, l.buy_price_ht as pa_ht,';
537
		$sql.= ' l.fk_unit, l.fk_contract_line,';
538
		$sql.= ' l.fk_multicurrency, l.multicurrency_code, l.multicurrency_subprice, l.multicurrency_total_ht, l.multicurrency_total_tva, l.multicurrency_total_ttc,';
539
		$sql.= ' p.ref as product_ref, p.fk_product_type as fk_product_type, p.label as product_label, p.description as product_desc';
540
		$sql.= ' FROM '.MAIN_DB_PREFIX.'facturedet_rec as l';
541
		$sql.= ' LEFT JOIN '.MAIN_DB_PREFIX.'product as p ON l.fk_product = p.rowid';
542
		$sql.= ' WHERE l.fk_facture = '.$this->id;
543
		$sql.= ' ORDER BY l.rang';
544
545
		dol_syslog('FactureRec::fetch_lines', LOG_DEBUG);
546
		$result = $this->db->query($sql);
547
		if ($result)
548
		{
549
			$num = $this->db->num_rows($result);
550
			$i = 0;
551
			while ($i < $num)
552
			{
553
				$objp = $this->db->fetch_object($result);
554
				$line = new FactureLigneRec($this->db);
555
556
				$line->id	            = $objp->rowid;
557
				$line->rowid	        = $objp->rowid;
558
				$line->desc             = $objp->description;		// Description line
559
				$line->description      = $objp->description;		// Description line
560
				$line->product_type     = $objp->product_type;		// Type of line
561
				$line->ref              = $objp->product_ref;		// Ref product
562
				$line->product_ref      = $objp->product_ref;		// Ref product
563
				$line->libelle          = $objp->product_label;		// deprecated
564
				$line->product_label	= $objp->product_label;		// Label product
565
				$line->product_desc     = $objp->product_desc;		// Description product
566
				$line->fk_product_type  = $objp->fk_product_type;	// Type of product
567
				$line->qty              = $objp->qty;
568
				$line->subprice         = $objp->subprice;
569
570
				$line->label            = $objp->custom_label;		// @deprecated
571
572
				$line->vat_src_code     = $objp->vat_src_code;
573
				$line->tva_tx           = $objp->tva_tx;
574
				$line->localtax1_tx     = $objp->localtax1_tx;
575
				$line->localtax2_tx     = $objp->localtax2_tx;
576
				$line->localtax1_type   = $objp->localtax1_type;
577
				$line->localtax2_type   = $objp->localtax2_type;
578
				$line->remise_percent   = $objp->remise_percent;
579
				$line->fk_remise_except = $objp->fk_remise_except;
580
				$line->fk_product       = $objp->fk_product;
581
				$line->date_start_fill  = $objp->date_start_fill;
582
				$line->date_end_fill    = $objp->date_end_fill;
583
				$line->info_bits        = $objp->info_bits;
584
				$line->total_ht         = $objp->total_ht;
585
				$line->total_tva        = $objp->total_tva;
586
				$line->total_ttc        = $objp->total_ttc;
587
				$line->code_ventilation = $objp->fk_code_ventilation;
588
				$line->fk_fournprice 	= $objp->fk_fournprice;
589
				$marginInfos			= getMarginInfos($objp->subprice, $objp->remise_percent, $objp->tva_tx, $objp->localtax1_tx, $objp->localtax2_tx, $line->fk_fournprice, $objp->pa_ht);
590
				$line->pa_ht 			= $marginInfos[0];
591
				$line->marge_tx			= $marginInfos[1];
592
				$line->marque_tx		= $marginInfos[2];
593
				$line->rang 			= $objp->rang;
594
				$line->special_code 	= $objp->special_code;
595
				$line->fk_unit          = $objp->fk_unit;
596
                $line->fk_contract_line = $objp->fk_contract_line;
597
598
				// Ne plus utiliser
599
				$line->price            = $objp->price;
600
				$line->remise           = $objp->remise;
601
602
				$extralabelsline = $line->fetch_optionals($line->id);
603
604
				// Multicurrency
605
				$line->fk_multicurrency 		= $objp->fk_multicurrency;
606
				$line->multicurrency_code 		= $objp->multicurrency_code;
607
				$line->multicurrency_subprice 	= $objp->multicurrency_subprice;
608
				$line->multicurrency_total_ht 	= $objp->multicurrency_total_ht;
609
				$line->multicurrency_total_tva 	= $objp->multicurrency_total_tva;
610
				$line->multicurrency_total_ttc 	= $objp->multicurrency_total_ttc;
611
612
				$this->lines[$i] = $line;
613
614
				$i++;
615
			}
616
617
			$this->db->free($result);
618
			return 1;
619
		}
620
		else
621
		{
622
			$this->error=$this->db->lasterror();
623
			return -3;
624
		}
625
	}
626
627
628
	/**
629
	 * 	Delete template invoice
630
	 *
631
	 *	@param     	User	$user          	User that delete.
632
	 *	@param		int		$notrigger		1=Does not execute triggers, 0= execute triggers
633
	 *	@param		int		$idwarehouse	Id warehouse to use for stock change.
634
	 *	@return		int						<0 if KO, >0 if OK
635
	 */
636
	public function delete(User $user, $notrigger = 0, $idwarehouse = -1)
637
	{
638
	    $rowid=$this->id;
639
640
	    dol_syslog(get_class($this)."::delete rowid=".$rowid, LOG_DEBUG);
641
642
        $error=0;
643
		$this->db->begin();
644
645
		$sql = "DELETE FROM ".MAIN_DB_PREFIX."facturedet_rec WHERE fk_facture = ".$rowid;
646
		dol_syslog($sql);
647
		if ($this->db->query($sql))
648
		{
649
			$sql = "DELETE FROM ".MAIN_DB_PREFIX."facture_rec WHERE rowid = ".$rowid;
650
			dol_syslog($sql);
651
			if ($this->db->query($sql))
652
			{
653
				// Delete linked object
654
				$res = $this->deleteObjectLinked();
655
				if ($res < 0) $error=-3;
656
			}
657
			else
658
			{
659
				$this->error=$this->db->lasterror();
660
				$error=-1;
661
			}
662
		}
663
		else
664
		{
665
			$this->error=$this->db->lasterror();
666
			$error=-2;
667
		}
668
669
		if (! $error)
670
		{
671
		    $this->db->commit();
672
		    return 1;
673
		}
674
		else
675
		{
676
	        $this->db->rollback();
677
	        return $error;
678
		}
679
	}
680
681
682
	/**
683
	 * 	Add a line to invoice
684
	 *
685
     *	@param    	string		$desc            	Description de la ligne
686
     *	@param    	double		$pu_ht              Prix unitaire HT (> 0 even for credit note)
687
     *	@param    	double		$qty             	Quantite
688
     *	@param    	double		$txtva           	Taux de tva force, sinon -1
689
	 * 	@param		double		$txlocaltax1		Local tax 1 rate (deprecated)
690
	 *  @param		double		$txlocaltax2		Local tax 2 rate (deprecated)
691
     *	@param    	int			$fk_product      	Product/Service ID predefined
692
     *	@param    	double		$remise_percent  	Percentage discount of the line
693
     *	@param		string		$price_base_type	HT or TTC
694
     *	@param    	int			$info_bits			VAT npr or not ?
695
     *	@param    	int			$fk_remise_except	Id remise
696
     *	@param    	double		$pu_ttc             Prix unitaire TTC (> 0 even for credit note)
697
     *	@param		int			$type				Type of line (0=product, 1=service)
698
     *	@param      int			$rang               Position of line
699
     *	@param		int			$special_code		Special code
700
     *	@param		string		$label				Label of the line
701
     *	@param		string		$fk_unit			Unit
702
	 * 	@param		double		$pu_ht_devise		Unit price in currency
703
	 *  @param		int			$date_start_fill	1=Flag to fill start date when generating invoice
704
	 *  @param		int			$date_end_fill		1=Flag to fill end date when generating invoice
705
	 * 	@param		int			$fk_fournprice		Supplier price id (to calculate margin) or ''
706
	 * 	@param		int			$pa_ht				Buying price of line (to calculate margin) or ''
707
     *	@return    	int             				<0 if KO, Id of line if OK
708
	 */
709
	public function addline($desc, $pu_ht, $qty, $txtva, $txlocaltax1 = 0, $txlocaltax2 = 0, $fk_product = 0, $remise_percent = 0, $price_base_type = 'HT', $info_bits = 0, $fk_remise_except = '', $pu_ttc = 0, $type = 0, $rang = -1, $special_code = 0, $label = '', $fk_unit = null, $pu_ht_devise = 0, $date_start_fill = 0, $date_end_fill = 0, $fk_fournprice = null, $pa_ht = 0)
710
	{
711
	    global $mysoc;
712
713
		$facid=$this->id;
714
715
		dol_syslog(get_class($this)."::addline facid=$facid,desc=$desc,pu_ht=$pu_ht,qty=$qty,txtva=$txtva,txlocaltax1=$txlocaltax1,txlocaltax2=$txlocaltax2,fk_product=$fk_product,remise_percent=$remise_percent,info_bits=$info_bits,fk_remise_except=$fk_remise_except,price_base_type=$price_base_type,pu_ttc=$pu_ttc,type=$type,fk_unit=$fk_unit,pu_ht_devise=$pu_ht_devise,date_start_fill=$date_start_fill,date_end_fill=$date_end_fill,pa_ht=$pa_ht", LOG_DEBUG);
716
		include_once DOL_DOCUMENT_ROOT.'/core/lib/price.lib.php';
717
718
		// Check parameters
719
		if ($type < 0) return -1;
720
721
		$localtaxes_type=getLocalTaxesFromRate($txtva, 0, $this->thirdparty, $mysoc);
722
723
		// Clean vat code
724
		$vat_src_code='';
725
		if (preg_match('/\((.*)\)/', $txtva, $reg))
726
		{
727
			$vat_src_code = $reg[1];
728
			$txtva = preg_replace('/\s*\(.*\)/', '', $txtva);    // Remove code into vatrate.
729
		}
730
731
		if ($this->brouillon)
732
		{
733
			// Clean parameters
734
			$remise_percent=price2num($remise_percent);
735
			if (empty($remise_percent)) $remise_percent=0;
736
			$qty=price2num($qty);
737
			$pu_ht = price2num($pu_ht);
738
			$pu_ttc = price2num($pu_ttc);
739
			$txtva = price2num($txtva);
740
			$txlocaltax1 = price2num($txlocaltax1);
741
			$txlocaltax2 = price2num($txlocaltax2);
742
			if (empty($txtva)) $txtva=0;
743
			if (empty($txlocaltax1)) $txlocaltax1=0;
744
			if (empty($txlocaltax2)) $txlocaltax2=0;
745
			if (empty($info_bits)) $info_bits=0;
746
747
			if ($price_base_type=='HT')
748
			{
749
				$pu=$pu_ht;
750
			}
751
			else
752
			{
753
				$pu=$pu_ttc;
754
			}
755
756
			// Calcul du total TTC et de la TVA pour la ligne a partir de
757
			// qty, pu, remise_percent et txtva
758
			// TRES IMPORTANT: C'est au moment de l'insertion ligne qu'on doit stocker
759
			// la part ht, tva et ttc, et ce au niveau de la ligne qui a son propre taux tva.
760
761
			$tabprice=calcul_price_total($qty, $pu, $remise_percent, $txtva, $txlocaltax1, $txlocaltax2, 0, $price_base_type, $info_bits, $type, $mysoc, $localtaxes_type, 100, $this->multicurrency_tx, $pu_ht_devise);
762
			$total_ht  = $tabprice[0];
763
			$total_tva = $tabprice[1];
764
			$total_ttc = $tabprice[2];
765
			$total_localtax1=$tabprice[9];
766
			$total_localtax2=$tabprice[10];
767
			$pu_ht = $tabprice[3];
768
769
			// MultiCurrency
770
			$multicurrency_total_ht  = $tabprice[16];
771
			$multicurrency_total_tva = $tabprice[17];
772
			$multicurrency_total_ttc = $tabprice[18];
773
			$pu_ht_devise = $tabprice[19];
774
775
			$product_type=$type;
776
			if ($fk_product)
777
			{
778
				$product=new Product($this->db);
779
				$result=$product->fetch($fk_product);
780
				$product_type=$product->type;
781
			}
782
783
			$sql = "INSERT INTO ".MAIN_DB_PREFIX."facturedet_rec (";
784
			$sql.= "fk_facture";
785
			$sql.= ", label";
786
			$sql.= ", description";
787
			$sql.= ", price";
788
			$sql.= ", qty";
789
			$sql.= ", tva_tx";
790
			$sql.= ", vat_src_code";
791
			$sql.= ", localtax1_tx";
792
			$sql.= ", localtax1_type";
793
			$sql.= ", localtax2_tx";
794
			$sql.= ", localtax2_type";
795
			$sql.= ", fk_product";
796
			$sql.= ", product_type";
797
			$sql.= ", remise_percent";
798
			$sql.= ", subprice";
799
			$sql.= ", remise";
800
			$sql.= ", total_ht";
801
			$sql.= ", total_tva";
802
			$sql.= ", total_localtax1";
803
			$sql.= ", total_localtax2";
804
			$sql.= ", total_ttc";
805
			$sql.= ", date_start_fill";
806
			$sql.= ", date_end_fill";
807
			$sql.= ", fk_product_fournisseur_price";
808
			$sql.= ", buy_price_ht";
809
			$sql.= ", info_bits";
810
			$sql.= ", rang";
811
			$sql.= ", special_code";
812
			$sql.= ", fk_unit";
813
			$sql.= ', fk_multicurrency, multicurrency_code, multicurrency_subprice, multicurrency_total_ht, multicurrency_total_tva, multicurrency_total_ttc';
814
			$sql.= ") VALUES (";
815
			$sql.= "'".$facid."'";
816
			$sql.= ", ".(! empty($label)?"'".$this->db->escape($label)."'":"null");
817
			$sql.= ", '".$this->db->escape($desc)."'";
818
			$sql.= ", ".price2num($pu_ht);
819
			$sql.= ", ".price2num($qty);
820
			$sql.= ", ".price2num($txtva);
821
			$sql.= ", '".$this->db->escape($vat_src_code)."'";
822
			$sql.= ", ".price2num($txlocaltax1);
823
			$sql.= ", '".$this->db->escape($localtaxes_type[0])."'";
824
			$sql.= ", ".price2num($txlocaltax2);
825
			$sql.= ", '".$this->db->escape($localtaxes_type[2])."'";
826
			$sql.= ", ".(! empty($fk_product)?"'".$fk_product."'":"null");
827
			$sql.= ", ".$product_type;
828
			$sql.= ", ".price2num($remise_percent);
829
			$sql.= ", ".price2num($pu_ht);
830
			$sql.= ", null";
831
			$sql.= ", ".price2num($total_ht);
832
			$sql.= ", ".price2num($total_tva);
833
			$sql.= ", ".price2num($total_localtax1);
834
			$sql.= ", ".price2num($total_localtax2);
835
			$sql.= ", ".price2num($total_ttc);
836
			$sql.= ", ".(int) $date_start_fill;
837
			$sql.= ", ".(int) $date_end_fill;
838
			$sql.= ", ".($fk_fournprice > 0 ? $fk_fournprice : 'null');
839
			$sql.= ", ".($pa_ht ? price2num($pa_ht) : 0);
840
			$sql.= ", ".$info_bits;
841
			$sql.= ", ".$rang;
842
			$sql.= ", ".$special_code;
843
			$sql.= ", ".($fk_unit?"'".$this->db->escape($fk_unit)."'":"null");
844
			$sql.= ", ".(int) $this->fk_multicurrency;
845
			$sql.= ", '".$this->db->escape($this->multicurrency_code)."'";
846
			$sql.= ", ".price2num($pu_ht_devise);
847
			$sql.= ", ".price2num($multicurrency_total_ht);
848
			$sql.= ", ".price2num($multicurrency_total_tva);
849
			$sql.= ", ".price2num($multicurrency_total_ttc);
850
			$sql.= ")";
851
852
			dol_syslog(get_class($this)."::addline", LOG_DEBUG);
853
			if ($this->db->query($sql))
854
			{
855
				$lineId = $this->db->last_insert_id(MAIN_DB_PREFIX."facturedet_rec");
856
				$this->id=$facid;
857
				$this->update_price();
858
				return $lineId;
859
			}
860
			else
861
			{
862
				$this->error=$this->db->lasterror();
863
				return -1;
864
			}
865
		}
866
	}
867
868
	/**
869
	 * 	Update a line to invoice
870
	 *
871
	 *  @param     	int			$rowid           	Id of line to update
872
	 *	@param    	string		$desc            	Description de la ligne
873
	 *	@param    	double		$pu_ht              Prix unitaire HT (> 0 even for credit note)
874
	 *	@param    	double		$qty             	Quantite
875
	 *	@param    	double		$txtva           	Taux de tva force, sinon -1
876
	 * 	@param		double		$txlocaltax1		Local tax 1 rate (deprecated)
877
	 *  @param		double		$txlocaltax2		Local tax 2 rate (deprecated)
878
	 *	@param    	int			$fk_product      	Product/Service ID predefined
879
	 *	@param    	double		$remise_percent  	Percentage discount of the line
880
	 *	@param		string		$price_base_type	HT or TTC
881
	 *	@param    	int			$info_bits			Bits of type of lines
882
	 *	@param    	int			$fk_remise_except	Id remise
883
	 *	@param    	double		$pu_ttc             Prix unitaire TTC (> 0 even for credit note)
884
	 *	@param		int			$type				Type of line (0=product, 1=service)
885
	 *	@param      int			$rang               Position of line
886
	 *	@param		int			$special_code		Special code
887
	 *	@param		string		$label				Label of the line
888
	 *	@param		string		$fk_unit			Unit
889
	 * 	@param		double		$pu_ht_devise		Unit price in currency
890
	 * 	@param		int			$notrigger			disable line update trigger
891
	 *  @param		int			$date_start_fill	1=Flag to fill start date when generating invoice
892
	 *  @param		int			$date_end_fill		1=Flag to fill end date when generating invoice
893
	 * 	@param		int			$fk_fournprice		Id of origin supplier price
894
	 * 	@param		int			$pa_ht				Price (without tax) of product when it was bought
895
	 *	@return    	int             				<0 if KO, Id of line if OK
896
	 */
897
	public function updateline($rowid, $desc, $pu_ht, $qty, $txtva, $txlocaltax1 = 0, $txlocaltax2 = 0, $fk_product = 0, $remise_percent = 0, $price_base_type = 'HT', $info_bits = 0, $fk_remise_except = '', $pu_ttc = 0, $type = 0, $rang = -1, $special_code = 0, $label = '', $fk_unit = null, $pu_ht_devise = 0, $notrigger = 0, $date_start_fill = 0, $date_end_fill = 0, $fk_fournprice = null, $pa_ht = 0)
898
	{
899
	    global $mysoc;
900
901
	    $facid=$this->id;
902
903
	    dol_syslog(get_class($this)."::updateline facid=".$facid." rowid=$rowid, desc=$desc, pu_ht=$pu_ht, qty=$qty, txtva=$txtva, txlocaltax1=$txlocaltax1, txlocaltax2=$txlocaltax2, fk_product=$fk_product, remise_percent=$remise_percent, info_bits=$info_bits, fk_remise_except=$fk_remise_except, price_base_type=$price_base_type, pu_ttc=$pu_ttc, type=$type, fk_unit=$fk_unit, pu_ht_devise=$pu_ht_devise", LOG_DEBUG);
904
	    include_once DOL_DOCUMENT_ROOT.'/core/lib/price.lib.php';
905
906
	    // Clean parameters
907
	    if (empty($remise_percent)) $remise_percent = 0;
908
909
	    // Check parameters
910
	    if ($type < 0) return -1;
911
912
	    if ($this->brouillon)
913
	    {
914
	        // Clean parameters
915
	        $remise_percent=price2num($remise_percent);
916
	        $qty=price2num($qty);
917
	        if (empty($info_bits)) $info_bits=0;
918
	        $pu_ht=price2num($pu_ht);
919
	        $pu_ttc=price2num($pu_ttc);
920
	        $txtva=price2num($txtva);
921
		    $txlocaltax1	= price2num($txlocaltax1);
922
		    $txlocaltax2	= price2num($txlocaltax2);
923
		    if (empty($txlocaltax1)) $txlocaltax1=0;
924
		    if (empty($txlocaltax2)) $txlocaltax2=0;
925
926
		    if (empty($this->multicurrency_subprice)) $this->multicurrency_subprice=0;
927
		    if (empty($this->multicurrency_total_ht)) $this->multicurrency_total_ht=0;
928
		    if (empty($this->multicurrency_total_tva)) $this->multicurrency_total_tva=0;
929
		    if (empty($this->multicurrency_total_ttc)) $this->multicurrency_total_ttc=0;
930
931
	        if ($price_base_type=='HT')
932
	        {
933
	            $pu=$pu_ht;
934
	        }
935
	        else
936
	        {
937
	            $pu=$pu_ttc;
938
	        }
939
940
	        // Calculate total with, without tax and tax from qty, pu, remise_percent and txtva
941
	        // TRES IMPORTANT: C'est au moment de l'insertion ligne qu'on doit stocker
942
	        // la part ht, tva et ttc, et ce au niveau de la ligne qui a son propre taux tva.
943
944
	        $localtaxes_type=getLocalTaxesFromRate($txtva, 0, $this->thirdparty, $mysoc);
945
946
	        // Clean vat code
947
	        $vat_src_code='';
948
	        if (preg_match('/\((.*)\)/', $txtva, $reg))
949
	        {
950
	        	$vat_src_code = $reg[1];
951
	        	$txtva = preg_replace('/\s*\(.*\)/', '', $txtva);    // Remove code into vatrate.
952
	        }
953
954
	        $tabprice=calcul_price_total($qty, $pu, $remise_percent, $txtva, $txlocaltax1, $txlocaltax2, 0, $price_base_type, $info_bits, $type, $mysoc, $localtaxes_type, 100, $this->multicurrency_tx, $pu_ht_devise);
955
956
	        $total_ht  = $tabprice[0];
957
	        $total_tva = $tabprice[1];
958
	        $total_ttc = $tabprice[2];
959
		    $total_localtax1=$tabprice[9];
960
		    $total_localtax2=$tabprice[10];
961
		    $pu_ht  = $tabprice[3];
962
		    $pu_tva = $tabprice[4];
963
		    $pu_ttc = $tabprice[5];
964
965
		    // MultiCurrency
966
		    $multicurrency_total_ht  = $tabprice[16];
967
		    $multicurrency_total_tva = $tabprice[17];
968
		    $multicurrency_total_ttc = $tabprice[18];
969
		    $pu_ht_devise = $tabprice[19];
970
971
	        $product_type=$type;
972
	        if ($fk_product)
973
	        {
974
	            $product=new Product($this->db);
975
	            $result=$product->fetch($fk_product);
976
	            $product_type=$product->type;
977
	        }
978
979
	        $sql = "UPDATE ".MAIN_DB_PREFIX."facturedet_rec SET ";
980
	        $sql.= "fk_facture = '".$facid."'";
981
	        $sql.= ", label=".(! empty($label)?"'".$this->db->escape($label)."'":"null");
982
	        $sql.= ", description='".$this->db->escape($desc)."'";
983
	        $sql.= ", price=".price2num($pu_ht);
984
	        $sql.= ", qty=".price2num($qty);
985
	        $sql.= ", tva_tx=".price2num($txtva);
986
	        $sql.= ", vat_src_code='".$this->db->escape($vat_src_code)."'";
987
		    $sql.= ", localtax1_tx=".$txlocaltax1;
988
		    $sql.= ", localtax1_type='".$this->db->escape($localtaxes_type[0])."'";
989
		    $sql.= ", localtax2_tx=".$txlocaltax2;
990
		    $sql.= ", localtax2_type='".$this->db->escape($localtaxes_type[2])."'";
991
	        $sql.= ", fk_product=".(! empty($fk_product)?"'".$fk_product."'":"null");
992
	        $sql.= ", product_type=".$product_type;
993
	        $sql.= ", remise_percent='".price2num($remise_percent)."'";
994
	        $sql.= ", subprice='".price2num($pu_ht)."'";
995
	        $sql.= ", total_ht='".price2num($total_ht)."'";
996
	        $sql.= ", total_tva='".price2num($total_tva)."'";
997
	        $sql.= ", total_localtax1='".price2num($total_localtax1)."'";
998
	        $sql.= ", total_localtax2='".price2num($total_localtax2)."'";
999
	        $sql.= ", total_ttc='".price2num($total_ttc)."'";
1000
	        $sql.= ", date_start_fill=".((int) $date_start_fill);
1001
	        $sql.= ", date_end_fill=".((int) $date_end_fill);
1002
	        $sql.= ", fk_product_fournisseur_price=".($fk_fournprice > 0 ? $fk_fournprice : 'null');
1003
	        $sql.= ", buy_price_ht=".($pa_ht ? price2num($pa_ht) : 0);
1004
	        $sql.= ", info_bits=".$info_bits;
1005
	        $sql.= ", rang=".$rang;
1006
	        $sql.= ", special_code=".$special_code;
1007
	        $sql.= ", fk_unit=".($fk_unit?"'".$this->db->escape($fk_unit)."'":"null");
1008
	        $sql.= ', multicurrency_subprice = '.$pu_ht_devise;
1009
	        $sql.= ', multicurrency_total_ht = '.$multicurrency_total_ht;
1010
	        $sql.= ', multicurrency_total_tva = '.$multicurrency_total_tva;
1011
	        $sql.= ', multicurrency_total_ttc = '.$multicurrency_total_ttc;
1012
	        $sql.= " WHERE rowid = ".$rowid;
1013
1014
	        dol_syslog(get_class($this)."::updateline", LOG_DEBUG);
1015
	        if ($this->db->query($sql))
1016
	        {
1017
	            $this->id=$facid;
1018
	            $this->update_price();
1019
	            return 1;
1020
	        }
1021
	        else
1022
	        {
1023
	            $this->error=$this->db->lasterror();
1024
	            return -1;
1025
	        }
1026
	    }
1027
	}
1028
1029
1030
	/**
1031
	 * Return the next date of
1032
	 *
1033
	 * @return  int|false   false if KO, timestamp if OK
1034
	 */
1035
	public function getNextDate()
1036
	{
1037
		if (empty($this->date_when)) return false;
1038
		return dol_time_plus_duree($this->date_when, $this->frequency, $this->unit_frequency);
1039
	}
1040
1041
	/**
1042
	 * Return if maximum number of generation is reached
1043
	 *
1044
	 * @return	boolean			False by default, True if maximum number of generation is reached
1045
	 */
1046
	public function isMaxNbGenReached()
1047
	{
1048
		$ret = false;
1049
		if ($this->nb_gen_max > 0 && ($this->nb_gen_done >= $this->nb_gen_max)) $ret = true;
1050
		return $ret;
1051
	}
1052
1053
	/**
1054
	 * Format string to output with by striking the string if max number of generation was reached
1055
	 *
1056
	 * @param	string		$ret	Default value to output
1057
	 * @return	boolean				False by default, True if maximum number of generation is reached
1058
	 */
1059
	public function strikeIfMaxNbGenReached($ret)
1060
	{
1061
		// Special case to strike the date
1062
		return ($this->isMaxNbGenReached()?'<strike>':'').$ret.($this->isMaxNbGenReached()?'</strike>':'');
1063
	}
1064
1065
	/**
1066
	 *  Create all recurrents invoices (for all entities if multicompany is used).
1067
	 *  A result may also be provided into this->output.
1068
	 *
1069
	 *  WARNING: This method change temporarly context $conf->entity to be in correct context for each recurring invoice found.
1070
	 *
1071
	 *  @param	int		$restrictioninvoiceid		0=All qualified template invoices found. > 0 = restrict action on invoice ID
1072
	 *  @param	int		$forcevalidation		1=Force validation of invoice whatever is template auto_validate flag.
1073
	 *  @return	int								0 if OK, < 0 if KO (this function is used also by cron so only 0 is OK)
1074
	 */
1075
	public function createRecurringInvoices($restrictioninvoiceid = 0, $forcevalidation = 0)
1076
	{
1077
		global $conf, $langs, $db, $user, $hookmanager;
1078
1079
		$error=0;
1080
		$nb_create=0;
1081
1082
		// Load translation files required by the page
1083
		$langs->loadLangs(array("main","bills"));
1084
1085
		$now = dol_now();
1086
		$tmparray=dol_getdate($now);
1087
		$today = dol_mktime(23, 59, 59, $tmparray['mon'], $tmparray['mday'], $tmparray['year']);   // Today is last second of current day
1088
1089
		dol_syslog("createRecurringInvoices restrictioninvoiceid=".$restrictioninvoiceid." forcevalidation=".$forcevalidation);
1090
1091
		$sql = 'SELECT rowid FROM '.MAIN_DB_PREFIX.'facture_rec';
1092
		$sql.= ' WHERE frequency > 0';      // A recurring invoice is an invoice with a frequency
1093
		$sql.= " AND (date_when IS NULL OR date_when <= '".$db->idate($today)."')";
1094
		$sql.= ' AND (nb_gen_done < nb_gen_max OR nb_gen_max = 0)';
1095
		$sql.= ' AND suspended = 0';
1096
		$sql.= ' AND entity = '.$conf->entity;	// MUST STAY = $conf->entity here
1097
		if ($restrictioninvoiceid > 0)
1098
			$sql.=' AND rowid = '.$restrictioninvoiceid;
1099
		$sql.= $db->order('entity', 'ASC');
1100
		//print $sql;exit;
1101
		$parameters = array(
1102
			'restrictioninvoiceid' => $restrictioninvoiceid,
1103
			'forcevalidation' => $forcevalidation,
1104
		);
1105
		$reshook = $hookmanager->executeHooks('beforeCreationOfRecurringInvoices', $parameters, $sql); // note that $sql might be modified by hooks
1106
1107
		$resql = $db->query($sql);
1108
		if ($resql)
1109
		{
1110
			$i=0;
1111
			$num = $db->num_rows($resql);
1112
1113
			if ($num)
1114
				$this->output.=$langs->trans("FoundXQualifiedRecurringInvoiceTemplate", $num)."\n";
1115
			else
1116
				$this->output.=$langs->trans("NoQualifiedRecurringInvoiceTemplateFound");
1117
1118
			$saventity = $conf->entity;
1119
1120
			while ($i < $num)     // Loop on each template invoice. If $num = 0, test is false at first pass.
1121
			{
1122
				$line = $db->fetch_object($resql);
1123
1124
				$db->begin();
1125
1126
				$invoiceidgenerated = 0;
1127
1128
				$facture = null;
1129
				$facturerec = new FactureRec($db);
1130
				$facturerec->fetch($line->rowid);
1131
1132
				if ($facturerec->id > 0)
1133
				{
1134
					// Set entity context
1135
					$conf->entity = $facturerec->entity;
1136
1137
					dol_syslog("createRecurringInvoices Process invoice template id=".$facturerec->id.", ref=".$facturerec->ref.", entity=".$facturerec->entity);
1138
1139
					$facture = new Facture($db);
1140
					$facture->fac_rec = $facturerec->id;    // We will create $facture from this recurring invoice
1141
					$facture->fk_fac_rec_source = $facturerec->id;    // We will create $facture from this recurring invoice
1142
1143
					$facture->type = self::TYPE_STANDARD;
1144
					$facture->brouillon = 1;
1145
					$facture->date = (empty($facturerec->date_when)?$now:$facturerec->date_when);	// We could also use dol_now here but we prefer date_when so invoice has real date when we would like even if we generate later.
1146
					$facture->socid = $facturerec->socid;
1147
1148
					$invoiceidgenerated = $facture->create($user);
1149
					if ($invoiceidgenerated <= 0)
1150
					{
1151
						$this->errors = $facture->errors;
1152
						$this->error = $facture->error;
1153
						$error++;
1154
					}
1155
					if (! $error && ($facturerec->auto_validate || $forcevalidation))
1156
					{
1157
						$result = $facture->validate($user);
1158
						if ($result <= 0)
1159
						{
1160
							$this->errors = $facture->errors;
1161
							$this->error = $facture->error;
1162
							$error++;
1163
						}
1164
					}
1165
					if (! $error && $facturerec->generate_pdf)
1166
					{
1167
						// We refresh the object in order to have all necessary data (like date_lim_reglement)
1168
						$facture->fetch($facture->id);
1169
						$result = $facture->generateDocument($facturerec->modelpdf, $langs);
1170
						if ($result <= 0)
1171
						{
1172
							$this->errors = $facture->errors;
1173
							$this->error = $facture->error;
1174
							$error++;
1175
						}
1176
					}
1177
				}
1178
				else
1179
				{
1180
					$error++;
1181
					$this->error="Failed to load invoice template with id=".$line->rowid.", entity=".$conf->entity."\n";
1182
					$this->errors[]="Failed to load invoice template with id=".$line->rowid.", entity=".$conf->entity;
1183
					dol_syslog("createRecurringInvoices Failed to load invoice template with id=".$line->rowid.", entity=".$conf->entity);
1184
				}
1185
1186
				if (! $error && $invoiceidgenerated >= 0)
1187
				{
1188
					$db->commit("createRecurringInvoices Process invoice template id=".$facturerec->id.", ref=".$facturerec->ref);
1189
					dol_syslog("createRecurringInvoices Process invoice template ".$facturerec->ref." is finished with a success generation");
1190
					$nb_create++;
1191
					$this->output.=$langs->trans("InvoiceGeneratedFromTemplate", $facture->ref, $facturerec->ref)."\n";
1192
				}
1193
				else
1194
				{
1195
					$db->rollback("createRecurringInvoices Process invoice template id=".$facturerec->id.", ref=".$facturerec->ref);
1196
				}
1197
1198
				$parameters = array(
1199
					'cpt'        => $i,
1200
					'total'      => $num,
1201
					'errorCount' => $error,
1202
					'invoiceidgenerated' => $invoiceidgenerated,
1203
					'facturerec' => $facturerec,	// it's an object which PHP passes by "reference", so modifiable by hooks.
1204
					'this'       => $this,		// it's an object which PHP passes by "reference", so modifiable by hooks.
1205
				);
1206
				$reshook = $hookmanager->executeHooks('afterCreationOfRecurringInvoice', $parameters, $facture);  // note: $facture can be modified by hooks (warning: $facture can be null)
1207
1208
				$i++;
1209
			}
1210
1211
			$conf->entity = $saventity;      // Restore entity context
1212
		}
1213
		else dol_print_error($db);
1214
1215
		$this->output=trim($this->output);
1216
1217
		return $error?$error:0;
1218
	}
1219
1220
	/**
1221
	 *	Return clicable name (with picto eventually)
1222
	 *
1223
	 * @param	int		$withpicto       			Add picto into link
1224
	 * @param  string	$option          			Where point the link
1225
	 * @param  int		$max             			Maxlength of ref
1226
	 * @param  int		$short           			1=Return just URL
1227
	 * @param  string   $moretitle       			Add more text to title tooltip
1228
     * @param	int  	$notooltip		 			1=Disable tooltip
1229
     * @param  int		$save_lastsearch_value    	-1=Auto, 0=No save of lastsearch_values when clicking, 1=Save lastsearch_values whenclicking
1230
	 * @return string 			         			String with URL
1231
	 */
1232
	public function getNomUrl($withpicto = 0, $option = '', $max = 0, $short = 0, $moretitle = '', $notooltip = '', $save_lastsearch_value = -1)
1233
	{
1234
		global $langs;
1235
1236
		$result='';
1237
1238
		$label = '<u>' . $langs->trans("ShowInvoice") . '</u>';
1239
		if (! empty($this->ref))
1240
			$label .= '<br><b>'.$langs->trans('Ref') . ':</b> ' . $this->ref;
1241
		if (! empty($this->date_last_gen))
1242
			$label .= '<br><b>'.$langs->trans('DateLastGeneration') . ':</b> ' . dol_print_date($this->date_last_gen, 'dayhour');
1243
		if ($this->frequency > 0)
1244
		{
1245
			if (! empty($this->date_when))
1246
			{
1247
				$label .= '<br><b>'.$langs->trans('NextDateToExecution') . ':</b> ';
1248
				$label .= (empty($this->suspended)?'':'<strike>'). dol_print_date($this->date_when, 'day').(empty($this->suspended)?'':'</strike>');	// No hour for this property
1249
				if (! empty($this->suspended)) $label .= ' ('.$langs->trans("Disabled").')';
1250
			}
1251
		}
1252
1253
        $url = DOL_URL_ROOT.'/compta/facture/fiche-rec.php?facid='.$this->id;
1254
1255
        if ($short) return $url;
1256
1257
        if ($option != 'nolink')
1258
        {
1259
        	// Add param to save lastsearch_values or not
1260
        	$add_save_lastsearch_values=($save_lastsearch_value == 1 ? 1 : 0);
1261
        	if ($save_lastsearch_value == -1 && preg_match('/list\.php/', $_SERVER["PHP_SELF"])) $add_save_lastsearch_values=1;
1262
        	if ($add_save_lastsearch_values) $url.='&save_lastsearch_values=1';
1263
        }
1264
1265
		$linkstart = '<a href="'.$url.'" title="'.dol_escape_htmltag($label, 1).'" class="classfortooltip">';
1266
		$linkend='</a>';
1267
1268
		$result .= $linkstart;
1269
		if ($withpicto) $result.=img_object(($notooltip?'':$label), ($this->picto?$this->picto:'generic'), ($notooltip?(($withpicto != 2) ? 'class="paddingright"' : ''):'class="'.(($withpicto != 2) ? 'paddingright ' : '').'classfortooltip"'), 0, 0, $notooltip?0:1);
1270
		if ($withpicto != 2) $result.= $this->ref;
1271
		$result .= $linkend;
1272
1273
		return $result;
1274
	}
1275
1276
	/**
1277
	 *  Return label of object status
1278
	 *
1279
	 *  @param      int		$mode			0=long label, 1=short label, 2=Picto + short label, 3=Picto, 4=Picto + long label, 5=short label + picto, 6=Long label + picto
1280
	 *  @param      integer	$alreadypaid    Not used on recurring invoices
1281
	 *  @return     string			        Label of status
1282
	 */
1283
	public function getLibStatut($mode = 0, $alreadypaid = -1)
1284
	{
1285
1286
		return $this->LibStatut($this->frequency?1:0, $this->suspended, $mode, $alreadypaid, empty($this->type)?0:$this->type);
1287
	}
1288
1289
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1290
	/**
1291
	 *	Return label of a status
1292
	 *
1293
	 *	@param    	int  	$recur         	Is it a recurring invoice ?
1294
	 *	@param      int		$status        	Id status (suspended or not)
1295
	 *	@param      int		$mode          	0=long label, 1=short label, 2=Picto + short label, 3=Picto, 4=Picto + long label, 5=short label + picto, 6=long label + picto
1296
	 *	@param		integer	$alreadypaid	Not used for recurring invoices
1297
	 *	@param		int		$type			Type invoice
1298
	 *	@return     string        			Label of status
1299
	 */
1300
	public function LibStatut($recur, $status, $mode = 0, $alreadypaid = -1, $type = 0)
1301
	{
1302
        // phpcs:enable
1303
		global $langs;
1304
		$langs->load('bills');
1305
1306
		//print "$recur,$status,$mode,$alreadypaid,$type";
1307
		if ($mode == 0)
1308
		{
1309
			$prefix='';
1310
			if ($recur)
1311
			{
1312
				if ($status == self::STATUS_SUSPENDED) return $langs->trans('Disabled');
1313
				else return $langs->trans('Active');
1314
			}
1315
			else
1316
			{
1317
				if ($status == self::STATUS_SUSPENDED) return $langs->trans('Disabled');
1318
				else return $langs->trans("Draft");
1319
			}
1320
		}
1321
		elseif ($mode == 1)
1322
		{
1323
			$prefix='Short';
1324
			if ($recur)
1325
			{
1326
				if ($status == self::STATUS_SUSPENDED) return $langs->trans('Disabled');
1327
				else return $langs->trans('Active');
1328
			}
1329
			else
1330
			{
1331
				if ($status == self::STATUS_SUSPENDED) return $langs->trans('Disabled');
1332
				else return $langs->trans("Draft");
1333
			}
1334
		}
1335
		elseif ($mode == 2)
1336
		{
1337
			if ($recur)
1338
			{
1339
				if ($status == self::STATUS_SUSPENDED) return img_picto($langs->trans('Disabled'), 'statut6').' '.$langs->trans('Disabled');
1340
				else return img_picto($langs->trans('Active'), 'statut4').' '.$langs->trans('Active');
1341
			}
1342
			else
1343
			{
1344
				if ($status == self::STATUS_SUSPENDED) return img_picto($langs->trans('Disabled'), 'statut6').' '.$langs->trans('Disabled');
1345
				else return img_picto($langs->trans('Draft'), 'statut0').' '.$langs->trans('Draft');
1346
			}
1347
		}
1348
		elseif ($mode == 3)
1349
		{
1350
			if ($recur)
1351
			{
1352
				$prefix='Short';
1353
				if ($status == self::STATUS_SUSPENDED) return img_picto($langs->trans('Disabled'), 'statut6');
1354
				else return img_picto($langs->trans('Active'), 'statut4');
1355
			}
1356
			else
1357
			{
1358
				if ($status == self::STATUS_SUSPENDED) return img_picto($langs->trans('Disabled'), 'statut6');
1359
				else return img_picto($langs->trans('Draft'), 'statut0');
1360
			}
1361
		}
1362
		elseif ($mode == 4)
1363
		{
1364
			$prefix='';
1365
			if ($recur)
1366
			{
1367
				if ($status == self::STATUS_SUSPENDED) return img_picto($langs->trans('Disabled'), 'statut6').' '.$langs->trans('Disabled');
1368
				else return img_picto($langs->trans('Active'), 'statut4').' '.$langs->trans('Active');
1369
			}
1370
			else
1371
			{
1372
				if ($status == self::STATUS_SUSPENDED) return img_picto($langs->trans('Disabled'), 'statut6').' '.$langs->trans('Disabled');
1373
				else return img_picto($langs->trans('Draft'), 'statut0').' '.$langs->trans('Draft');
1374
			}
1375
		}
1376
		elseif ($mode == 5 || $mode == 6)
1377
		{
1378
			$prefix='';
1379
			if ($mode == 5) $prefix='Short';
1380
			if ($recur)
1381
			{
1382
				if ($status == self::STATUS_SUSPENDED) return '<span class="xhideonsmartphone">'.$langs->trans('Disabled').' </span>'.img_picto($langs->trans('Disabled'), 'statut6');
1383
				else return '<span class="xhideonsmartphone">'.$langs->trans('Active').' </span>'.img_picto($langs->trans('Active'), 'statut4');
1384
			}
1385
			else
1386
			{
1387
				if ($status == self::STATUS_SUSPENDED) return '<span class="xhideonsmartphone">'.$langs->trans('Disabled').' </span>'.img_picto($langs->trans('Disabled'), 'statut6');
1388
				else return $langs->trans('Draft').' '.img_picto($langs->trans('Active'), 'statut0');
1389
			}
1390
		}
1391
	}
1392
1393
	/**
1394
	 *  Initialise an instance with random values.
1395
	 *  Used to build previews or test instances.
1396
	 *	id must be 0 if object instance is a specimen.
1397
	 *
1398
	 *	@param	string		$option		''=Create a specimen invoice with lines, 'nolines'=No lines
1399
	 *  @return	void
1400
	 */
1401
	public function initAsSpecimen($option = '')
1402
	{
1403
		global $user,$langs,$conf;
1404
1405
		$now=dol_now();
1406
		$arraynow=dol_getdate($now);
1407
		$nownotime=dol_mktime(0, 0, 0, $arraynow['mon'], $arraynow['mday'], $arraynow['year']);
1408
1409
        // Load array of products prodids
1410
		$num_prods = 0;
1411
		$prodids = array();
1412
1413
		$sql = "SELECT rowid";
1414
		$sql.= " FROM ".MAIN_DB_PREFIX."product";
1415
		$sql.= " WHERE entity IN (".getEntity('product').")";
1416
		$resql = $this->db->query($sql);
1417
		if ($resql)
1418
		{
1419
			$num_prods = $this->db->num_rows($resql);
1420
			$i = 0;
1421
			while ($i < $num_prods)
1422
			{
1423
				$i++;
1424
				$row = $this->db->fetch_row($resql);
1425
				$prodids[$i] = $row[0];
1426
			}
1427
		}
1428
1429
		// Initialize parameters
1430
		$this->id=0;
1431
		$this->ref = 'SPECIMEN';
1432
		$this->specimen=1;
1433
		$this->socid = 1;
1434
		$this->date = $nownotime;
1435
		$this->date_lim_reglement = $nownotime + 3600 * 24 *30;
1436
		$this->cond_reglement_id   = 1;
1437
		$this->cond_reglement_code = 'RECEP';
1438
		$this->date_lim_reglement=$this->calculate_date_lim_reglement();
1439
		$this->mode_reglement_id   = 0;		// Not forced to show payment mode CHQ + VIR
1440
		$this->mode_reglement_code = '';	// Not forced to show payment mode CHQ + VIR
1441
		$this->note_public='This is a comment (public)';
1442
		$this->note_private='This is a comment (private)';
1443
		$this->note='This is a comment (private)';
1 ignored issue
show
Deprecated Code introduced by
The property CommonObject::$note has been deprecated. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

1443
		/** @scrutinizer ignore-deprecated */ $this->note='This is a comment (private)';
Loading history...
1444
		$this->fk_incoterms=0;
1445
		$this->location_incoterms='';
1446
1447
		if (empty($option) || $option != 'nolines')
1448
		{
1449
			// Lines
1450
			$nbp = 5;
1451
			$xnbp = 0;
1452
			while ($xnbp < $nbp)
1453
			{
1454
				$line=new FactureLigne($this->db);
1455
				$line->desc=$langs->trans("Description")." ".$xnbp;
1456
				$line->qty=1;
1457
				$line->subprice=100;
1458
				$line->tva_tx=19.6;
1459
				$line->localtax1_tx=0;
1460
				$line->localtax2_tx=0;
1461
				$line->remise_percent=0;
1462
				if ($xnbp == 1)        // Qty is negative (product line)
1463
				{
1464
					$prodid = mt_rand(1, $num_prods);
1465
					$line->fk_product=$prodids[$prodid];
1466
					$line->qty=-1;
1467
					$line->total_ht=-100;
1468
					$line->total_ttc=-119.6;
1469
					$line->total_tva=-19.6;
1470
				}
1471
				elseif ($xnbp == 2)    // UP is negative (free line)
1472
				{
1473
					$line->subprice=-100;
1474
					$line->total_ht=-100;
1475
					$line->total_ttc=-119.6;
1476
					$line->total_tva=-19.6;
1477
					$line->remise_percent=0;
1478
				}
1479
				elseif ($xnbp == 3)    // Discount is 50% (product line)
1480
				{
1481
					$prodid = mt_rand(1, $num_prods);
1482
					$line->fk_product=$prodids[$prodid];
1483
					$line->total_ht=50;
1484
					$line->total_ttc=59.8;
1485
					$line->total_tva=9.8;
1486
					$line->remise_percent=50;
1487
				}
1488
				else    // (product line)
1489
				{
1490
					$prodid = mt_rand(1, $num_prods);
1491
					$line->fk_product=$prodids[$prodid];
1492
					$line->total_ht=100;
1493
					$line->total_ttc=119.6;
1494
					$line->total_tva=19.6;
1495
					$line->remise_percent=00;
1496
				}
1497
1498
				$this->lines[$xnbp]=$line;
1499
				$xnbp++;
1500
1501
				$this->total_ht       += $line->total_ht;
1502
				$this->total_tva      += $line->total_tva;
1503
				$this->total_ttc      += $line->total_ttc;
1504
			}
1505
			$this->revenuestamp = 0;
1506
1507
			// Add a line "offered"
1508
			$line=new FactureLigne($this->db);
1509
			$line->desc=$langs->trans("Description")." (offered line)";
1510
			$line->qty=1;
1511
			$line->subprice=100;
1512
			$line->tva_tx=19.6;
1513
			$line->localtax1_tx=0;
1514
			$line->localtax2_tx=0;
1515
			$line->remise_percent=100;
1516
			$line->total_ht=0;
1517
			$line->total_ttc=0;    // 90 * 1.196
1518
			$line->total_tva=0;
1519
			$prodid = mt_rand(1, $num_prods);
1520
			$line->fk_product=$prodids[$prodid];
1521
1522
			$this->lines[$xnbp]=$line;
1523
			$xnbp++;
1524
		}
1525
1526
		$this->usenewprice = 1;
1527
	}
1528
1529
	/**
1530
	 * Function used to replace a thirdparty id with another one.
1531
	 *
1532
	 * @param DoliDB $db Database handler
1533
	 * @param int $origin_id Old thirdparty id
1534
	 * @param int $dest_id New thirdparty id
1535
	 * @return bool
1536
	 */
1537
	public static function replaceThirdparty(DoliDB $db, $origin_id, $dest_id)
1538
	{
1539
		$tables = array(
1540
			'facture_rec'
1541
		);
1542
1543
		return CommonObject::commonReplaceThirdparty($db, $origin_id, $dest_id, $tables);
1544
	}
1545
1546
	/**
1547
     *	Update frequency and unit
1548
     *
1549
     *	@param     	int		$frequency		value of frequency
1550
     *	@param     	string	$unit 			unit of frequency  (d, m, y)
1551
     *	@return		int						<0 if KO, >0 if OK
1552
     */
1553
    public function setFrequencyAndUnit($frequency, $unit)
1554
    {
1555
        if (! $this->table_element) {
1556
            dol_syslog(get_class($this)."::setFrequencyAndUnit was called on objet with property table_element not defined", LOG_ERR);
1557
            return -1;
1558
        }
1559
1560
        if (!empty($frequency) && empty($unit)) {
1561
            dol_syslog(get_class($this)."::setFrequencyAndUnit was called on objet with params frequency defined but unit not defined", LOG_ERR);
1562
            return -2;
1563
        }
1564
1565
        $sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element;
1566
        $sql.= ' SET frequency = '.($frequency?$this->db->escape($frequency):'null');
1567
        if (!empty($unit)) {
1568
        	$sql.= ', unit_frequency = \''.$this->db->escape($unit).'\'';
1569
		}
1570
        $sql.= ' WHERE rowid = '.$this->id;
1571
1572
        dol_syslog(get_class($this)."::setFrequencyAndUnit", LOG_DEBUG);
1573
        if ($this->db->query($sql)) {
1574
            $this->frequency = $frequency;
1575
            if (!empty($unit)) $this->unit_frequency = $unit;
1576
            return 1;
1577
        }
1578
        else
1579
        {
1580
            dol_print_error($this->db);
1581
            return -1;
1582
        }
1583
    }
1584
1585
	/**
1586
     *	Update the next date of execution
1587
     *
1588
     *	@param     	datetime	$date					date of execution
1589
     *	@param     	int			$increment_nb_gen_done	0 do nothing more, >0 increment nb_gen_done
1590
     *	@return		int									<0 if KO, >0 if OK
1591
     */
1592
    public function setNextDate($date, $increment_nb_gen_done = 0)
1593
    {
1594
        if (! $this->table_element)
1595
        {
1596
            dol_syslog(get_class($this)."::setNextDate was called on objet with property table_element not defined", LOG_ERR);
1597
            return -1;
1598
        }
1599
        $sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element;
1600
        $sql.= " SET date_when = ".($date ? "'".$this->db->idate($date)."'" : "null");
1601
        if ($increment_nb_gen_done>0) $sql.= ', nb_gen_done = nb_gen_done + 1';
1602
        $sql.= ' WHERE rowid = '.$this->id;
1603
1604
        dol_syslog(get_class($this)."::setNextDate", LOG_DEBUG);
1605
        if ($this->db->query($sql))
1606
        {
1607
            $this->date_when = $date;
1608
            if ($increment_nb_gen_done>0) $this->nb_gen_done++;
1609
            return 1;
1610
        }
1611
        else
1612
        {
1613
            dol_print_error($this->db);
1614
            return -1;
1615
        }
1616
    }
1617
1618
	/**
1619
     *	Update the maximum period
1620
     *
1621
     *	@param     	int		$nb		number of maximum period
1622
     *	@return		int				<0 if KO, >0 if OK
1623
     */
1624
    public function setMaxPeriod($nb)
1625
    {
1626
        if (! $this->table_element)
1627
        {
1628
            dol_syslog(get_class($this)."::setMaxPeriod was called on objet with property table_element not defined", LOG_ERR);
1629
            return -1;
1630
        }
1631
1632
        if (empty($nb)) $nb=0;
1633
1634
        $sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element;
1635
        $sql.= ' SET nb_gen_max = '.$nb;
1636
        $sql.= ' WHERE rowid = '.$this->id;
1637
1638
        dol_syslog(get_class($this)."::setMaxPeriod", LOG_DEBUG);
1639
        if ($this->db->query($sql))
1640
        {
1641
            $this->nb_gen_max = $nb;
1642
            return 1;
1643
        }
1644
        else
1645
        {
1646
            dol_print_error($this->db);
1647
            return -1;
1648
        }
1649
    }
1650
1651
	/**
1652
     *	Update the auto validate flag of invoice
1653
     *
1654
     *	@param     	int		$validate		0 to create in draft, 1 to create and validate invoice
1655
     *	@return		int						<0 if KO, >0 if OK
1656
     */
1657
    public function setAutoValidate($validate)
1658
    {
1659
        if (! $this->table_element)
1660
        {
1661
            dol_syslog(get_class($this)."::setAutoValidate was called on objet with property table_element not defined", LOG_ERR);
1662
            return -1;
1663
        }
1664
1665
        $sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element;
1666
        $sql.= ' SET auto_validate = '.$validate;
1667
        $sql.= ' WHERE rowid = '.$this->id;
1668
1669
        dol_syslog(get_class($this)."::setAutoValidate", LOG_DEBUG);
1670
        if ($this->db->query($sql))
1671
        {
1672
            $this->auto_validate = $validate;
1673
            return 1;
1674
        }
1675
        else
1676
        {
1677
            dol_print_error($this->db);
1678
            return -1;
1679
        }
1680
    }
1681
1682
    /**
1683
     *	Update the auto generate documents
1684
     *
1685
     *	@param     	int		$validate		0 no document, 1 to generate document
1686
     *	@return		int						<0 if KO, >0 if OK
1687
     */
1688
    public function setGeneratePdf($validate)
1689
    {
1690
        if (! $this->table_element)
1691
        {
1692
            dol_syslog(get_class($this)."::setGeneratePdf was called on objet with property table_element not defined", LOG_ERR);
1693
            return -1;
1694
        }
1695
1696
        $sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element;
1697
        $sql.= ' SET generate_pdf = '.$validate;
1698
        $sql.= ' WHERE rowid = '.$this->id;
1699
1700
        dol_syslog(get_class($this)."::setGeneratePdf", LOG_DEBUG);
1701
        if ($this->db->query($sql))
1702
        {
1703
            $this->generate_pdf = $validate;
1704
            return 1;
1705
        }
1706
        else
1707
        {
1708
            dol_print_error($this->db);
1709
            return -1;
1710
        }
1711
    }
1712
1713
    /**
1714
     *  Update the model for documents
1715
     *
1716
     *  @param     	string		$model		model of document generator
1717
     *  @return		int						<0 if KO, >0 if OK
1718
     */
1719
    public function setModelPdf($model)
1720
    {
1721
        if (! $this->table_element)
1722
        {
1723
            dol_syslog(get_class($this)."::setModelPdf was called on objet with property table_element not defined", LOG_ERR);
1724
            return -1;
1725
        }
1726
1727
        $sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element;
1728
        $sql.= ' SET modelpdf = "' . $model . '"';
1729
        $sql.= ' WHERE rowid = '.$this->id;
1730
1731
        dol_syslog(get_class($this)."::setModelPdf", LOG_DEBUG);
1732
        if ($this->db->query($sql))
1733
        {
1734
            $this->modelpdf = $model;
1735
            return 1;
1736
        }
1737
        else
1738
        {
1739
            dol_print_error($this->db);
1740
            return -1;
1741
        }
1742
    }
1743
}
1744
1745
1746
1747
/**
1748
 *	Class to manage invoice lines of templates.
1749
 *  Saved into database table llx_facturedet_rec
1750
 */
1751
class FactureLigneRec extends CommonInvoiceLine
1752
{
1753
	/**
1754
	 * @var string ID to identify managed object
1755
	 */
1756
	public $element='facturedetrec';
1757
1758
	/**
1759
	 * @var string Name of table without prefix where object is stored
1760
	 */
1761
	public $table_element='facturedet_rec';
1762
1763
	public $date_start_fill;
1764
	public $date_end_fill;
1765
1766
1767
    /**
1768
     * 	Delete line in database
1769
     *
1770
     *  @param		User	$user		Object user
1771
     *  @param		int		$notrigger	Disable triggers
1772
     *	@return		int					<0 if KO, >0 if OK
1773
     */
1774
    public function delete(User $user, $notrigger = false)
1775
    {
1776
    	$error=0;
1777
1778
	    $this->db->begin();
1779
1780
	    if (! $error) {
1781
	        if (! $notrigger) {
1 ignored issue
show
Bug Best Practice introduced by
The expression $notrigger of type false|integer is loosely compared to false; this is ambiguous if the integer can be 0. You might want to explicitly use === false instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
1782
	            // Call triggers
1783
	            $result=$this->call_trigger('LINEBILLREC_DELETE', $user);
1784
	            if ($result < 0) { $error++; } // Do also here what you must do to rollback action if trigger fail
1785
	            // End call triggers
1786
	        }
1787
	    }
1788
1789
	    if (! $error)
1790
	    {
1791
    		$sql = 'DELETE FROM '.MAIN_DB_PREFIX.$this->table_element.' WHERE rowid='.$this->id;
1792
1793
    		$res = $this->db->query($sql);
1794
    		if($res===false) {
0 ignored issues
show
introduced by
The condition $res === false is always false.
Loading history...
1795
    		    $error++;
1796
    		    $this->errors[] = $this->db->lasterror();
1797
    		}
1798
	    }
1799
1800
    	// Commit or rollback
1801
		if ($error) {
1802
		    $this->db->rollback();
1803
		    return -1;
1804
		} else {
1805
		    $this->db->commit();
1806
		    return 1;
1807
		}
1808
    }
1809
1810
1811
    /**
1812
     *	Get line of template invoice
1813
     *
1814
     *	@param		int 	$rowid		Id of invoice
1815
     *	@return     int         		1 if OK, < 0 if KO
1816
     */
1817
    public function fetch($rowid)
1818
    {
1819
    	$sql = 'SELECT l.rowid, l.fk_facture ,l.fk_product, l.product_type, l.label as custom_label, l.description, l.product_type, l.price, l.qty, l.vat_src_code, l.tva_tx,';
1820
    	$sql.= ' l.localtax1_tx, l.localtax2_tx, l.localtax1_type, l.localtax2_type, l.remise, l.remise_percent, l.subprice,';
1821
    	$sql.= ' l.date_start_fill, l.date_end_fill, l.info_bits, l.total_ht, l.total_tva, l.total_ttc,';
1822
    	$sql.= ' l.rang, l.special_code,';
1823
    	$sql.= ' l.fk_unit, l.fk_contract_line,';
1824
    	$sql.= ' p.ref as product_ref, p.fk_product_type as fk_product_type, p.label as product_label, p.description as product_desc';
1825
    	$sql.= ' FROM '.MAIN_DB_PREFIX.'facturedet_rec as l';
1826
    	$sql.= ' LEFT JOIN '.MAIN_DB_PREFIX.'product as p ON l.fk_product = p.rowid';
1827
    	$sql.= ' WHERE l.rowid = '.$rowid;
1828
    	$sql.= ' ORDER BY l.rang';
1829
1830
    	dol_syslog('FactureRec::fetch', LOG_DEBUG);
1831
    	$result = $this->db->query($sql);
1832
    	if ($result)
1833
    	{
1834
1835
    		$objp = $this->db->fetch_object($result);
1836
1837
    		$this->id	            = $objp->rowid;
1838
    		$this->label            = $objp->custom_label;		// Label line
1839
    		$this->desc             = $objp->description;		// Description line
1840
    		$this->description      = $objp->description;		// Description line
1841
    		$this->product_type     = $objp->product_type;		// Type of line
1842
    		$this->ref              = $objp->product_ref;		// Ref product
1843
    		$this->product_ref      = $objp->product_ref;		// Ref product
1844
    		$this->libelle          = $objp->product_label;		// deprecated
1845
    		$this->product_label	= $objp->product_label;		// Label product
1846
    		$this->product_desc     = $objp->product_desc;		// Description product
1847
    		$this->fk_product_type  = $objp->fk_product_type;	// Type of product
1848
    		$this->qty              = $objp->qty;
1849
    		$this->price			= $objp->price;
1850
    		$this->subprice         = $objp->subprice;
1851
    		$this->fk_facture		= $objp->fk_facture;
1852
    		$this->vat_src_code     = $objp->vat_src_code;
1853
    		$this->tva_tx           = $objp->tva_tx;
1854
    		$this->localtax1_tx     = $objp->localtax1_tx;
1855
    		$this->localtax2_tx     = $objp->localtax2_tx;
1856
    		$this->localtax1_type   = $objp->localtax1_type;
1857
    		$this->localtax2_type   = $objp->localtax2_type;
1858
    		$this->remise_percent   = $objp->remise_percent;
1859
    		$this->fk_remise_except = $objp->fk_remise_except;
1860
    		$this->fk_product       = $objp->fk_product;
1861
    		$this->date_start_fill  = $objp->date_start_fill;
1862
    		$this->date_end_fill    = $objp->date_end_fill;
1863
    		$this->info_bits        = $objp->info_bits;
1864
    		$this->total_ht         = $objp->total_ht;
1865
    		$this->total_tva        = $objp->total_tva;
1866
    		$this->total_ttc        = $objp->total_ttc;
1867
    		$this->code_ventilation = $objp->fk_code_ventilation;
1868
    		$this->rang 			= $objp->rang;
1869
    		$this->special_code 	= $objp->special_code;
1870
    		$this->fk_unit          = $objp->fk_unit;
1871
    		$this->fk_contract_line = $objp->fk_contract_line;
1872
1873
1874
    		$this->db->free($result);
1875
    		return 1;
1876
    	}
1877
    	else
1878
    	{
1879
    		$this->error=$this->db->lasterror();
1880
    		return -3;
1881
    	}
1882
    }
1883
1884
1885
    /**
1886
     * 	Update a line to invoice_rec.
1887
     *
1888
     *  @param		User	$user					User
1889
     *  @param		int		$notrigger				No trigger
1890
     *	@return    	int             				<0 if KO, Id of line if OK
1891
     */
1892
    public function update(User $user, $notrigger = 0)
1893
    {
1894
    	global $conf;
1895
1896
    	$error = 0;
1897
1898
    	include_once DOL_DOCUMENT_ROOT.'/core/lib/price.lib.php';
1899
1900
    	$sql = "UPDATE ".MAIN_DB_PREFIX."facturedet_rec SET";
1901
    	$sql.= " fk_facture = ".$this->fk_facture;
1902
    	$sql.= ", label=".(! empty($this->label)?"'".$this->db->escape($this->label)."'":"null");
1903
    	$sql.= ", description='".$this->db->escape($this->desc)."'";
1904
    	$sql.= ", price=".price2num($this->price);
1905
    	$sql.= ", qty=".price2num($this->qty);
1906
    	$sql.= ", tva_tx=".price2num($this->tva_tx);
1907
    	$sql.= ", vat_src_code='".$this->db->escape($this->vat_src_code)."'";
1908
    	$sql.= ", localtax1_tx=".price2num($this->localtax1_tx);
1909
    	$sql.= ", localtax1_type='".$this->db->escape($this->localtax1_type)."'";
1910
    	$sql.= ", localtax2_tx=".price2num($this->localtax2_tx);
1911
    	$sql.= ", localtax2_type='".$this->db->escape($this->localtax2_type)."'";
1912
    	$sql.= ", fk_product=".($this->fk_product > 0 ? $this->fk_product :"null");
1913
    	$sql.= ", product_type=".$this->product_type;
1914
    	$sql.= ", remise_percent='".price2num($this->remise_percent)."'";
1915
    	$sql.= ", subprice='".price2num($this->subprice)."'";
1916
    	$sql.= ", info_bits='".price2num($this->info_bits)."'";
1917
    	$sql.= ", date_start_fill=".(int) $this->date_start_fill;
1918
    	$sql.= ", date_end_fill=".(int) $this->date_end_fill;
1919
    	if (empty($this->skip_update_total)) {
1920
    		$sql.= ", total_ht=".price2num($this->total_ht);
1921
	    	$sql.= ", total_tva=".price2num($this->total_tva);
1922
	    	$sql.= ", total_localtax1=".price2num($this->total_localtax1);
1923
	    	$sql.= ", total_localtax2=".price2num($this->total_localtax2);
1924
	    	$sql.= ", total_ttc=".price2num($this->total_ttc);
1925
    	}
1926
    	$sql.= ", rang=".$this->rang;
1927
    	$sql.= ", special_code=".$this->special_code;
1928
    	$sql.= ", fk_unit=".($this->fk_unit ?"'".$this->db->escape($this->fk_unit)."'":"null");
1929
    	$sql.= ", fk_contract_line=".($this->fk_contract_line?$this->fk_contract_line:"null");
1930
    	$sql.= " WHERE rowid = ".$this->id;
1931
1932
    	dol_syslog(get_class($this)."::updateline", LOG_DEBUG);
1933
    	$resql=$this->db->query($sql);
1934
        if ($resql)
1935
        {
1936
    		if (empty($conf->global->MAIN_EXTRAFIELDS_DISABLED)) // For avoid conflicts if trigger used
1937
    		{
1938
    			$result=$this->insertExtraFields();
1939
    			if ($result < 0)
1940
    			{
1941
    				$error++;
1942
    			}
1943
    		}
1944
1945
    		if (! $error && ! $notrigger)
1946
    		{
1947
    			// Call trigger
1948
    			$result=$this->call_trigger('LINEBILLREC_UPDATE', $user);
1949
    			if ($result < 0)
1950
    			{
1951
    				$this->db->rollback();
1952
    				return -2;
1953
    			}
1954
    			// End call triggers
1955
    		}
1956
            $this->db->commit();
1957
            return 1;
1958
        }
1959
        else
1960
        {
1961
            $this->error=$this->db->lasterror();
1962
            $this->db->rollback();
1963
            return -2;
1964
        }
1965
    }
1966
}
1967