Test Failed
Branch develop (71ce82)
by
unknown
46:10
created

FactureLigneRec::update()   F

Complexity

Conditions 11
Paths 320

Size

Total Lines 76
Code Lines 51

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 11
eloc 51
nc 320
nop 0
dl 0
loc 76
rs 3.9622
c 0
b 0
f 0

How to fix   Long Method    Complexity   

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:

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
 *
10
 * This program is free software; you can redistribute it and/or modify
11
 * it under the terms of the GNU General Public License as published by
12
 * the Free Software Foundation; either version 3 of the License, or
13
 * (at your option) any later version.
14
 *
15
 * This program is distributed in the hope that it will be useful,
16
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18
 * GNU General Public License for more details.
19
 *
20
 * You should have received a copy of the GNU General Public License
21
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
22
 */
23
24
/**
25
 *	\file       htdocs/compta/facture/class/facture-rec.class.php
26
 *	\ingroup    facture
27
 *	\brief      Fichier de la classe des factures recurentes
28
 */
29
30
require_once DOL_DOCUMENT_ROOT.'/core/class/notify.class.php';
31
require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php';
32
require_once DOL_DOCUMENT_ROOT.'/compta/facture/class/facture.class.php';
33
require_once DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php';
34
35
36
/**
37
 *	Class to manage invoice templates
38
 */
39
class FactureRec extends CommonInvoice
40
{
41
	public $element='facturerec';
42
	public $table_element='facture_rec';
43
	public $table_element_line='facturedet_rec';
44
	public $fk_element='fk_facture';
45
	public $picto='bill';
46
47
	var $entity;
48
	var $number;
49
	var $date;
50
	var $amount;
51
	var $remise;
52
	var $tva;
53
	var $total;
54
	var $db_table;
55
	var $propalid;
56
57
	var $date_last_gen;
58
	var $date_when;
59
	var $nb_gen_done;
60
	var $nb_gen_max;
61
62
	var $frequency;
63
	var $unit_frequency;
64
65
	var $rang;
66
	var $special_code;
67
68
	var $usenewprice=0;
69
70
	/**
71
	 *	Constructor
72
	 *
73
	 * 	@param		DoliDB		$db		Database handler
74
	 */
75
	function __construct($db)
76
	{
77
		$this->db = $db;
78
	}
79
80
	/**
81
	 * 	Create a predefined invoice
82
	 *
83
	 * 	@param		User	$user		User object
84
	 * 	@param		int		$facid		Id of source invoice
85
	 *	@return		int					<0 if KO, id of invoice created if OK
86
	 */
87
	function create($user, $facid)
88
	{
89
		global $conf;
90
91
		$error=0;
92
		$now=dol_now();
93
94
		// Clean parameters
95
		$this->titre=trim($this->titre);
96
		$this->usenewprice=empty($this->usenewprice)?0:$this->usenewprice;
97
98
		// No frequency defined then no next date to execution
99
		if (empty($this->frequency))
100
		{
101
			$this->frequency=0;
102
			$this->date_when=NULL;
103
		}
104
105
106
		$this->frequency=abs($this->frequency);
107
		$this->nb_gen_done=0;
108
		$this->nb_gen_max=empty($this->nb_gen_max)?0:$this->nb_gen_max;
109
		$this->auto_validate=empty($this->auto_validate)?0:$this->auto_validate;
110
111
		$this->db->begin();
112
113
		// Charge facture modele
114
		$facsrc=new Facture($this->db);
115
		$result=$facsrc->fetch($facid);
116
		if ($result > 0)
117
		{
118
			// On positionne en mode brouillon la facture
119
			$this->brouillon = 1;
120
121
			$sql = "INSERT INTO ".MAIN_DB_PREFIX."facture_rec (";
122
			$sql.= "titre";
123
			$sql.= ", fk_soc";
124
			$sql.= ", entity";
125
			$sql.= ", datec";
126
			$sql.= ", amount";
127
			$sql.= ", remise";
128
			$sql.= ", note_private";
129
			$sql.= ", note_public";
130
			$sql.= ", fk_user_author";
131
			$sql.= ", fk_projet";
132
			$sql.= ", fk_account";
133
			$sql.= ", fk_cond_reglement";
134
			$sql.= ", fk_mode_reglement";
135
			$sql.= ", usenewprice";
136
			$sql.= ", frequency";
137
			$sql.= ", unit_frequency";
138
			$sql.= ", date_when";
139
			$sql.= ", date_last_gen";
140
			$sql.= ", nb_gen_done";
141
			$sql.= ", nb_gen_max";
142
			$sql.= ", auto_validate";
143
			$sql.= ") VALUES (";
144
			$sql.= "'".$this->titre."'";
145
			$sql.= ", ".$facsrc->socid;
146
			$sql.= ", ".$conf->entity;
147
			$sql.= ", '".$this->db->idate($now)."'";
148
			$sql.= ", ".(!empty($facsrc->amount)?$facsrc->amount:'0');
149
			$sql.= ", ".(!empty($facsrc->remise)?$this->remise:'0');
150
			$sql.= ", ".(!empty($this->note_private)?("'".$this->db->escape($this->note_private)."'"):"NULL");
151
			$sql.= ", ".(!empty($this->note_public)?("'".$this->db->escape($this->note_public)."'"):"NULL");
152
			$sql.= ", '".$user->id."'";
153
			$sql.= ", ".(! empty($facsrc->fk_project)?"'".$facsrc->fk_project."'":"null");
154
			$sql.= ", ".(! empty($facsrc->fk_account)?"'".$facsrc->fk_account."'":"null");
155
			$sql.= ", '".$facsrc->cond_reglement_id."'";
156
			$sql.= ", '".$facsrc->mode_reglement_id."'";
157
			$sql.= ", ".$this->usenewprice;
158
			$sql.= ", ".$this->frequency;
159
			$sql.= ", '".$this->db->escape($this->unit_frequency)."'";
160
			$sql.= ", ".(!empty($this->date_when)?"'".$this->db->idate($this->date_when)."'":'NULL');
161
			$sql.= ", ".(!empty($this->date_last_gen)?"'".$this->db->idate($this->date_last_gen)."'":'NULL');
162
			$sql.= ", ".$this->nb_gen_done;
163
			$sql.= ", ".$this->nb_gen_max;
164
			$sql.= ", ".$this->auto_validate;
165
			$sql.= ")";
166
167
			if ($this->db->query($sql))
168
			{
169
				$this->id = $this->db->last_insert_id(MAIN_DB_PREFIX."facture_rec");
170
171
				// Add lines
172
				$num=count($facsrc->lines);
173
				for ($i = 0; $i < $num; $i++)
174
				{
175
					$tva_tx = $facsrc->lines[$i]->tva_tx;
176
					if (! empty($facsrc->lines[$i]->vat_src_code) && ! preg_match('/\(/', $tva_tx)) $tva_tx .= ' ('.$facsrc->lines[$i]->vat_src_code.')';
177
178
					$result_insert = $this->addline(
179
                        $facsrc->lines[$i]->desc,
180
                        $facsrc->lines[$i]->subprice,
181
                        $facsrc->lines[$i]->qty,
182
						$tva_tx,
183
                        $facsrc->lines[$i]->localtax1_tx,
184
                        $facsrc->lines[$i]->localtax2_tx,
185
                        $facsrc->lines[$i]->fk_product,
186
                        $facsrc->lines[$i]->remise_percent,
187
                        'HT',
188
                        0,
189
                        '',
190
                        0,
191
                        $facsrc->lines[$i]->product_type,
192
                        $facsrc->lines[$i]->rang,
193
                        $facsrc->lines[$i]->special_code,
194
                    	$facsrc->lines[$i]->label,
195
	                    $facsrc->lines[$i]->fk_unit
196
                    );
197
198
					if ($result_insert < 0)
199
					{
200
						$error++;
201
					}
202
				}
203
204
			    // Add object linked
205
			    if (! $error && $this->id && is_array($this->linked_objects) && ! empty($this->linked_objects))
206
			    {
207
			        foreach($this->linked_objects as $origin => $origin_id)
208
			        {
209
			            $ret = $this->add_object_linked($origin, $origin_id);
210
			            if (! $ret)
211
			            {
212
			                $this->error=$this->db->lasterror();
213
			                $error++;
214
			            }
215
			        }
216
			    }
217
218
				if ($error)
219
				{
220
					$this->db->rollback();
221
				}
222
				else
223
				{
224
					$this->db->commit();
225
					return $this->id;
226
				}
227
			}
228
			else
229
			{
230
			    $this->error=$this->db->lasterror();
231
				$this->db->rollback();
232
				return -2;
233
			}
234
		}
235
		else
236
		{
237
			$this->db->rollback();
238
			return -1;
239
		}
240
	}
241
242
243
	/**
244
	 *	Load object and lines
245
	 *
246
	 *	@param      int		$rowid       	Id of object to load
247
	 * 	@param		string	$ref			Reference of recurring invoice
248
	 * 	@param		string	$ref_ext		External reference of invoice
249
	 * 	@param		int		$ref_int		Internal reference of other object
250
	 *	@return     int         			>0 if OK, <0 if KO, 0 if not found
251
	 */
252
	function fetch($rowid, $ref='', $ref_ext='', $ref_int='')
253
	{
254
		$sql = 'SELECT f.rowid, f.entity, f.titre, f.suspended, f.fk_soc, f.amount, f.tva, f.localtax1, f.localtax2, f.total, f.total_ttc';
255
		$sql.= ', f.remise_percent, f.remise_absolue, f.remise';
256
		$sql.= ', f.date_lim_reglement as dlr';
257
		$sql.= ', f.note_private, f.note_public, f.fk_user_author';
258
		$sql.= ', f.fk_mode_reglement, f.fk_cond_reglement, f.fk_projet';
259
		$sql.= ', f.fk_account';
260
		$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';
261
		$sql.= ', p.code as mode_reglement_code, p.libelle as mode_reglement_libelle';
262
		$sql.= ', c.code as cond_reglement_code, c.libelle as cond_reglement_libelle, c.libelle_facture as cond_reglement_libelle_doc';
263
		//$sql.= ', el.fk_source';
264
		$sql.= ' FROM '.MAIN_DB_PREFIX.'facture_rec as f';
265
		$sql.= ' LEFT JOIN '.MAIN_DB_PREFIX.'c_payment_term as c ON f.fk_cond_reglement = c.rowid';
266
		$sql.= ' LEFT JOIN '.MAIN_DB_PREFIX.'c_paiement as p ON f.fk_mode_reglement = p.id';
267
		//$sql.= " LEFT JOIN ".MAIN_DB_PREFIX."element_element as el ON el.fk_target = f.rowid AND el.targettype = 'facture'";
268
		if ($rowid) $sql.= ' WHERE f.rowid='.$rowid;
269
		elseif ($ref) $sql.= " WHERE f.titre='".$this->db->escape($ref)."'";
270
		/* This field are not used for template invoice
271
		if ($ref_ext) $sql.= " AND f.ref_ext='".$this->db->escape($ref_ext)."'";
272
		if ($ref_int) $sql.= " AND f.ref_int='".$this->db->escape($ref_int)."'";
273
		*/
274
275
		$result = $this->db->query($sql);
276
		if ($result)
277
		{
278
			if ($this->db->num_rows($result))
279
			{
280
				$obj = $this->db->fetch_object($result);
281
282
				$this->id                     = $obj->rowid;
283
				$this->entity                 = $obj->entity;
284
				$this->titre                  = $obj->titre;
285
				$this->ref                    = $obj->titre;
286
				$this->ref_client             = $obj->ref_client;
287
				$this->suspended              = $obj->suspended;
288
				$this->type                   = $obj->type;
289
				$this->datep                  = $obj->dp;
290
				$this->date                   = $obj->df;
291
				$this->amount                 = $obj->amount;
292
				$this->remise_percent         = $obj->remise_percent;
293
				$this->remise_absolue         = $obj->remise_absolue;
294
				$this->remise                 = $obj->remise;
295
				$this->total_ht               = $obj->total;
296
				$this->total_tva              = $obj->tva;
297
				$this->total_localtax1        = $obj->localtax1;
298
				$this->total_localtax2        = $obj->localtax2;
299
				$this->total_ttc              = $obj->total_ttc;
300
				$this->paye                   = $obj->paye;
301
				$this->close_code             = $obj->close_code;
302
				$this->close_note             = $obj->close_note;
303
				$this->socid                  = $obj->fk_soc;
304
				$this->date_lim_reglement     = $this->db->jdate($obj->dlr);
305
				$this->mode_reglement_id      = $obj->fk_mode_reglement;
306
				$this->mode_reglement_code    = $obj->mode_reglement_code;
307
				$this->mode_reglement         = $obj->mode_reglement_libelle;
308
				$this->cond_reglement_id      = $obj->fk_cond_reglement;
309
				$this->cond_reglement_code    = $obj->cond_reglement_code;
310
				$this->cond_reglement         = $obj->cond_reglement_libelle;
311
				$this->cond_reglement_doc     = $obj->cond_reglement_libelle_doc;
312
				$this->fk_project             = $obj->fk_projet;
313
				$this->fk_account             = $obj->fk_account;
314
				$this->fk_facture_source      = $obj->fk_facture_source;
315
				$this->note_private           = $obj->note_private;
316
				$this->note_public            = $obj->note_public;
317
				$this->user_author            = $obj->fk_user_author;
318
				$this->modelpdf               = $obj->model_pdf;
319
				$this->rang					  = $obj->rang;
320
				$this->special_code			  = $obj->special_code;
321
				$this->frequency			  = $obj->frequency;
322
				$this->unit_frequency		  = $obj->unit_frequency;
323
				$this->date_when			  = $this->db->jdate($obj->date_when);
324
				$this->date_last_gen		  = $this->db->jdate($obj->date_last_gen);
325
				$this->nb_gen_done			  = $obj->nb_gen_done;
326
				$this->nb_gen_max			  = $obj->nb_gen_max;
327
				$this->usenewprice			  = $obj->usenewprice;
328
				$this->auto_validate		  = $obj->auto_validate;
329
330
				if ($this->statut == self::STATUS_DRAFT)	$this->brouillon = 1;
331
332
333
				// Retreive all extrafield for thirdparty
334
				// fetch optionals attributes and labels
335
				require_once(DOL_DOCUMENT_ROOT.'/core/class/extrafields.class.php');
336
				$extrafields=new ExtraFields($this->db);
337
				$extralabels=$extrafields->fetch_name_optionals_label($this->table_element,true);
338
				$this->fetch_optionals($this->id,$extralabels);
339
340
				/*
341
				 * Lines
342
				 */
343
				$result=$this->fetch_lines();
344
				if ($result < 0)
345
				{
346
					$this->error=$this->db->lasterror();
347
					return -3;
348
				}
349
				return 1;
350
			}
351
			else
352
			{
353
				$this->error='Bill with id '.$rowid.' or ref '.$ref.' not found sql='.$sql;
354
				dol_syslog('Facture::Fetch Error '.$this->error, LOG_ERR);
355
				return -2;
356
			}
357
		}
358
		else
359
		{
360
			$this->error=$this->db->error();
361
			return -1;
362
		}
363
	}
364
365
366
	/**
367
	 * 	Create an array of invoice lines
368
	 *
369
	 * 	@return int		>0 if OK, <0 if KO
370
	 */
371
	function getLinesArray()
372
	{
373
	    return $this->fetch_lines();
374
	}
375
376
377
	/**
378
	 *	Recupere les lignes de factures predefinies dans this->lines
379
	 *
380
	 *	@return     int         1 if OK, < 0 if KO
381
 	 */
382
	function fetch_lines()
383
	{
384
		$this->lines=array();
385
386
		$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, ';
387
		$sql.= ' l.localtax1_tx, l.localtax2_tx, l.localtax1_type, l.localtax2_type, l.remise, l.remise_percent, l.subprice,';
388
		$sql.= ' l.info_bits, l.total_ht, l.total_tva, l.total_ttc,';
389
		//$sql.= ' l.situation_percent, l.fk_prev_id,';
390
		//$sql.= ' l.localtax1_tx, l.localtax2_tx, l.localtax1_type, l.localtax2_type, l.remise_percent, l.fk_remise_except, l.subprice,';
391
		$sql.= ' l.rang, l.special_code,';
392
		//$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,';
393
		$sql.= ' l.fk_unit, l.fk_contract_line,';
394
		//$sql.= ' l.fk_multicurrency, l.multicurrency_code, l.multicurrency_subprice, l.multicurrency_total_ht, l.multicurrency_total_tva, l.multicurrency_total_ttc,';
395
		$sql.= ' p.ref as product_ref, p.fk_product_type as fk_product_type, p.label as product_label, p.description as product_desc';
396
		$sql.= ' FROM '.MAIN_DB_PREFIX.'facturedet_rec as l';
397
		$sql.= ' LEFT JOIN '.MAIN_DB_PREFIX.'product as p ON l.fk_product = p.rowid';
398
		$sql.= ' WHERE l.fk_facture = '.$this->id;
399
		$sql.= ' ORDER BY l.rang';
400
401
		dol_syslog('FactureRec::fetch_lines', LOG_DEBUG);
402
		$result = $this->db->query($sql);
403
		if ($result)
404
		{
405
			$num = $this->db->num_rows($result);
406
			$i = 0;
407
			while ($i < $num)
408
			{
409
				$objp = $this->db->fetch_object($result);
410
				$line = new FactureLigneRec($this->db);
411
412
				$line->id	            = $objp->rowid;
413
				$line->rowid	        = $objp->rowid;
414
				$line->label            = $objp->custom_label;		// Label line
415
				$line->desc             = $objp->description;		// Description line
416
				$line->description      = $objp->description;		// Description line
417
				$line->product_type     = $objp->product_type;		// Type of line
418
				$line->ref              = $objp->product_ref;		// Ref product
419
				$line->product_ref      = $objp->product_ref;		// Ref product
420
				$line->libelle          = $objp->product_label;		// deprecated
421
				$line->product_label	= $objp->product_label;		// Label product
422
				$line->product_desc     = $objp->product_desc;		// Description product
423
				$line->fk_product_type  = $objp->fk_product_type;	// Type of product
424
				$line->qty              = $objp->qty;
425
				$line->subprice         = $objp->subprice;
426
427
				$line->vat_src_code     = $objp->vat_src_code;
428
				$line->tva_tx           = $objp->tva_tx;
429
				$line->localtax1_tx     = $objp->localtax1_tx;
430
				$line->localtax2_tx     = $objp->localtax2_tx;
431
				$line->localtax1_type   = $objp->localtax1_type;
432
				$line->localtax2_type   = $objp->localtax2_type;
433
				$line->remise_percent   = $objp->remise_percent;
434
				$line->fk_remise_except = $objp->fk_remise_except;
435
				$line->fk_product       = $objp->fk_product;
436
				$line->info_bits        = $objp->info_bits;
437
				$line->total_ht         = $objp->total_ht;
438
				$line->total_tva        = $objp->total_tva;
439
				$line->total_ttc        = $objp->total_ttc;
440
				$line->code_ventilation = $objp->fk_code_ventilation;
441
				$line->rang 			= $objp->rang;
442
				$line->special_code 	= $objp->special_code;
443
				$line->fk_unit          = $objp->fk_unit;
444
                $line->fk_contract_line = $objp->fk_contract_line;
445
446
				// Ne plus utiliser
447
				$line->price            = $objp->price;
448
				$line->remise           = $objp->remise;
449
450
451
				// Retreive all extrafield for thirdparty
452
				// fetch optionals attributes and labels
453
				require_once(DOL_DOCUMENT_ROOT.'/core/class/extrafields.class.php');
454
				$extrafieldsline=new ExtraFields($line->db);
455
				$extrafieldsline=$extrafieldsline->fetch_name_optionals_label($line->table_element,true);
456
				$extralabelsline = $line->fetch_optionals($line->id,$extrafieldsline);
457
458
459
				$this->lines[$i] = $line;
460
461
				$i++;
462
			}
463
464
			$this->db->free($result);
465
			return 1;
466
		}
467
		else
468
		{
469
			$this->error=$this->db->lasterror();
470
			return -3;
471
		}
472
	}
473
474
475
	/**
476
	 * 	Delete template invoice
477
	 *
478
	 *	@param     	User	$user          	User that delete.
479
	 *	@param		int		$notrigger		1=Does not execute triggers, 0= execute triggers
480
	 *	@param		int		$idwarehouse	Id warehouse to use for stock change.
481
	 *	@return		int						<0 if KO, >0 if OK
482
	 */
483
	function delete(User $user, $notrigger=0, $idwarehouse=-1)
484
	{
485
	    $rowid=$this->id;
486
487
	    dol_syslog(get_class($this)."::delete rowid=".$rowid, LOG_DEBUG);
488
489
        $error=0;
490
		$this->db->begin();
491
492
		$sql = "DELETE FROM ".MAIN_DB_PREFIX."facturedet_rec WHERE fk_facture = ".$rowid;
493
		dol_syslog($sql);
494
		if ($this->db->query($sql))
495
		{
496
			$sql = "DELETE FROM ".MAIN_DB_PREFIX."facture_rec WHERE rowid = ".$rowid;
497
			dol_syslog($sql);
498
			if ($this->db->query($sql))
499
			{
500
				// Delete linked object
501
				$res = $this->deleteObjectLinked();
502
				if ($res < 0) $error=-3;
503
			}
504
			else
505
			{
506
				$this->error=$this->db->lasterror();
507
				$error=-1;
508
			}
509
		}
510
		else
511
		{
512
			$this->error=$this->db->lasterror();
513
			$error=-2;
514
		}
515
516
		if (! $error)
517
		{
518
		    $this->db->commit();
519
		    return 1;
520
		}
521
		else
522
		{
523
	        $this->db->rollback();
524
	        return $error;
525
		}
526
	}
527
528
529
	/**
530
	 * 	Add a line to invoice
531
	 *
532
     *	@param    	string		$desc            	Description de la ligne
533
     *	@param    	double		$pu_ht              Prix unitaire HT (> 0 even for credit note)
534
     *	@param    	double		$qty             	Quantite
535
     *	@param    	double		$txtva           	Taux de tva force, sinon -1
536
	 * 	@param		double		$txlocaltax1		Local tax 1 rate (deprecated)
537
	 *  @param		double		$txlocaltax2		Local tax 2 rate (deprecated)
538
     *	@param    	int			$fk_product      	Id du produit/service predefini
539
     *	@param    	double		$remise_percent  	Pourcentage de remise de la ligne
540
     *	@param		string		$price_base_type	HT or TTC
541
     *	@param    	int			$info_bits			Bits de type de lignes
542
     *	@param    	int			$fk_remise_except	Id remise
543
     *	@param    	double		$pu_ttc             Prix unitaire TTC (> 0 even for credit note)
544
     *	@param		int			$type				Type of line (0=product, 1=service)
545
     *	@param      int			$rang               Position of line
546
     *	@param		int			$special_code		Special code
547
     *	@param		string		$label				Label of the line
548
     *	@param		string		$fk_unit			Unit
549
     *	@return    	int             				<0 if KO, Id of line if OK
550
	 */
551
	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)
552
	{
553
	    global $mysoc;
554
555
		$facid=$this->id;
556
557
		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", LOG_DEBUG);
558
		include_once DOL_DOCUMENT_ROOT.'/core/lib/price.lib.php';
559
560
		// Check parameters
561
		if ($type < 0) return -1;
562
563
		$localtaxes_type=getLocalTaxesFromRate($txtva, 0, $this->thirdparty, $mysoc);
564
565
		// Clean vat code
566
		$vat_src_code='';
567
		if (preg_match('/\((.*)\)/', $txtva, $reg))
568
		{
569
			$vat_src_code = $reg[1];
570
			$txtva = preg_replace('/\s*\(.*\)/', '', $txtva);    // Remove code into vatrate.
571
		}
572
573
		if ($this->brouillon)
574
		{
575
			// Clean parameters
576
			$remise_percent=price2num($remise_percent);
577
			if (empty($remise_percent)) $remise_percent=0;
578
			$qty=price2num($qty);
579
			if (! $info_bits) $info_bits=0;
580
			$pu_ht = price2num($pu_ht);
581
			$pu_ttc = price2num($pu_ttc);
582
			$txtva = price2num($txtva);
583
			$txlocaltax1 = price2num($txlocaltax1);
584
			$txlocaltax2 = price2num($txlocaltax2);
585
			if (empty($txtva)) $txtva=0;
586
			if (empty($txlocaltax1)) $txlocaltax1=0;
587
			if (empty($txlocaltax2)) $txlocaltax2=0;
588
589
			if ($price_base_type=='HT')
590
			{
591
				$pu=$pu_ht;
592
			}
593
			else
594
			{
595
				$pu=$pu_ttc;
596
			}
597
598
			// Calcul du total TTC et de la TVA pour la ligne a partir de
599
			// qty, pu, remise_percent et txtva
600
			// TRES IMPORTANT: C'est au moment de l'insertion ligne qu'on doit stocker
601
			// la part ht, tva et ttc, et ce au niveau de la ligne qui a son propre taux tva.
602
603
604
			$tabprice=calcul_price_total($qty, $pu, $remise_percent, $txtva, $txlocaltax1, $txlocaltax2, 0, $price_base_type, $info_bits, $type, $mysoc, $localtaxes_type);
605
			$total_ht  = $tabprice[0];
606
			$total_tva = $tabprice[1];
607
			$total_ttc = $tabprice[2];
608
			$total_localtax1=$tabprice[9];
609
			$total_localtax2=$tabprice[10];
610
611
			$product_type=$type;
612
			if ($fk_product)
613
			{
614
				$product=new Product($this->db);
615
				$result=$product->fetch($fk_product);
616
				$product_type=$product->type;
617
			}
618
619
			$sql = "INSERT INTO ".MAIN_DB_PREFIX."facturedet_rec (";
620
			$sql.= "fk_facture";
621
			$sql.= ", label";
622
			$sql.= ", description";
623
			$sql.= ", price";
624
			$sql.= ", qty";
625
			$sql.= ", tva_tx";
626
			$sql.= ", vat_src_code";
627
			$sql.= ", localtax1_tx";
628
			$sql.= ", localtax1_type";
629
			$sql.= ", localtax2_tx";
630
			$sql.= ", localtax2_type";
631
			$sql.= ", fk_product";
632
			$sql.= ", product_type";
633
			$sql.= ", remise_percent";
634
			$sql.= ", subprice";
635
			$sql.= ", remise";
636
			$sql.= ", total_ht";
637
			$sql.= ", total_tva";
638
			$sql.= ", total_localtax1";
639
			$sql.= ", total_localtax2";
640
			$sql.= ", total_ttc";
641
			$sql.= ", rang";
642
			$sql.= ", special_code";
643
			$sql.= ", fk_unit";
644
			$sql.= ") VALUES (";
645
			$sql.= "'".$facid."'";
646
			$sql.= ", ".(! empty($label)?"'".$this->db->escape($label)."'":"null");
647
			$sql.= ", '".$this->db->escape($desc)."'";
648
			$sql.= ", ".price2num($pu_ht);
649
			$sql.= ", ".price2num($qty);
650
			$sql.= ", ".price2num($txtva);
651
			$sql.= ", '".$this->db->escape($vat_src_code)."'";
652
			$sql.= ", ".price2num($txlocaltax1);
653
			$sql.= ", '".$this->db->escape($localtaxes_type[0])."'";
654
			$sql.= ", ".price2num($txlocaltax2);
655
			$sql.= ", '".$this->db->escape($localtaxes_type[2])."'";
656
			$sql.= ", ".(! empty($fk_product)?"'".$fk_product."'":"null");
657
			$sql.= ", ".$product_type;
658
			$sql.= ", ".price2num($remise_percent);
659
			$sql.= ", ".price2num($pu_ht);
660
			$sql.= ", null";
661
			$sql.= ", ".price2num($total_ht);
662
			$sql.= ", ".price2num($total_tva);
663
			$sql.= ", ".price2num($total_localtax1);
664
			$sql.= ", ".price2num($total_localtax2);
665
			$sql.= ", ".price2num($total_ttc);
666
			$sql.= ", ".$rang;
667
			$sql.= ", ".$special_code;
668
			$sql.= ", ".($fk_unit?"'".$this->db->escape($fk_unit)."'":"null").")";
669
670
			dol_syslog(get_class($this)."::addline", LOG_DEBUG);
671
			if ($this->db->query($sql))
672
			{
673
				$lineId = $this->db->last_insert_id(MAIN_DB_PREFIX."facturedet_rec");
674
				$this->id=$facid;
675
				$this->update_price();
676
				return $lineId;
677
			}
678
			else
679
			{
680
				$this->error=$this->db->lasterror();
681
				return -1;
682
			}
683
		}
684
	}
685
686
	/**
687
	 * 	Update a line to invoice
688
	 *
689
	 *  @param     	int			$rowid           	Id of line to update
690
	 *	@param    	string		$desc            	Description de la ligne
691
	 *	@param    	double		$pu_ht              Prix unitaire HT (> 0 even for credit note)
692
	 *	@param    	double		$qty             	Quantite
693
	 *	@param    	double		$txtva           	Taux de tva force, sinon -1
694
	 * 	@param		double		$txlocaltax1		Local tax 1 rate (deprecated)
695
	 *  @param		double		$txlocaltax2		Local tax 2 rate (deprecated)
696
	 *	@param    	int			$fk_product      	Id du produit/service predefini
697
	 *	@param    	double		$remise_percent  	Pourcentage de remise de la ligne
698
	 *	@param		string		$price_base_type	HT or TTC
699
	 *	@param    	int			$info_bits			Bits de type de lignes
700
	 *	@param    	int			$fk_remise_except	Id remise
701
	 *	@param    	double		$pu_ttc             Prix unitaire TTC (> 0 even for credit note)
702
	 *	@param		int			$type				Type of line (0=product, 1=service)
703
	 *	@param      int			$rang               Position of line
704
	 *	@param		int			$special_code		Special code
705
	 *	@param		string		$label				Label of the line
706
	 *	@param		string		$fk_unit			Unit
707
	 *	@return    	int             				<0 if KO, Id of line if OK
708
	 */
709
	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)
710
	{
711
	    global $mysoc;
712
713
	    $facid=$this->id;
714
715
	    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", 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
	        $qty=price2num($qty);
736
	        if (! $info_bits) $info_bits=0;
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
743
	        if ($price_base_type=='HT')
744
	        {
745
	            $pu=$pu_ht;
746
	        }
747
	        else
748
	        {
749
	            $pu=$pu_ttc;
750
	        }
751
752
	        // Calcul du total TTC et de la TVA pour la ligne a partir de
753
	        // qty, pu, remise_percent et txtva
754
	        // TRES IMPORTANT: C'est au moment de l'insertion ligne qu'on doit stocker
755
	        // la part ht, tva et ttc, et ce au niveau de la ligne qui a son propre taux tva.
756
	        $tabprice=calcul_price_total($qty, $pu, $remise_percent, $txtva, $txlocaltax1, $txlocaltax2, 0, $price_base_type, $info_bits, $type, $mysoc, $localtaxes_type);
757
758
	        $total_ht  = $tabprice[0];
759
	        $total_tva = $tabprice[1];
760
	        $total_ttc = $tabprice[2];
761
		    $total_localtax1=$tabprice[9];
762
		    $total_localtax2=$tabprice[10];
763
764
	        $product_type=$type;
765
	        if ($fk_product)
766
	        {
767
	            $product=new Product($this->db);
768
	            $result=$product->fetch($fk_product);
769
	            $product_type=$product->type;
770
	        }
771
772
	        $sql = "UPDATE ".MAIN_DB_PREFIX."facturedet_rec SET ";
773
	        $sql.= "fk_facture = '".$facid."'";
774
	        $sql.= ", label=".(! empty($label)?"'".$this->db->escape($label)."'":"null");
775
	        $sql.= ", description='".$this->db->escape($desc)."'";
776
	        $sql.= ", price=".price2num($pu_ht);
777
	        $sql.= ", qty=".price2num($qty);
778
	        $sql.= ", tva_tx=".price2num($txtva);
779
	        $sql.= ", vat_src_code='".$this->db->escape($vat_src_code)."'";
780
		    $sql.= ", localtax1_tx=".price2num($txlocaltax1);
781
		    $sql.= ", localtax1_type='".$this->db->escape($localtaxes_type[0])."'";
782
		    $sql.= ", localtax2_tx=".price2num($txlocaltax2);
783
		    $sql.= ", localtax2_type='".$this->db->escape($localtaxes_type[2])."'";
784
	        $sql.= ", fk_product=".(! empty($fk_product)?"'".$fk_product."'":"null");
785
	        $sql.= ", product_type=".$product_type;
786
	        $sql.= ", remise_percent='".price2num($remise_percent)."'";
787
	        $sql.= ", subprice='".price2num($pu_ht)."'";
788
	        $sql.= ", total_ht='".price2num($total_ht)."'";
789
	        $sql.= ", total_tva='".price2num($total_tva)."'";
790
	        $sql.= ", total_localtax1='".price2num($total_localtax1)."'";
791
	        $sql.= ", total_localtax2='".price2num($total_localtax2)."'";
792
	        $sql.= ", total_ttc='".price2num($total_ttc)."'";
793
	        $sql.= ", rang=".$rang;
794
	        $sql.= ", special_code=".$special_code;
795
	        $sql.= ", fk_unit=".($fk_unit?"'".$this->db->escape($fk_unit)."'":"null");
796
	        $sql.= " WHERE rowid = ".$rowid;
797
798
	        dol_syslog(get_class($this)."::updateline", LOG_DEBUG);
799
	        if ($this->db->query($sql))
800
	        {
801
	            $this->id=$facid;
802
	            $this->update_price();
803
	            return 1;
804
	        }
805
	        else
806
	        {
807
	            $this->error=$this->db->lasterror();
808
	            return -1;
809
	        }
810
	    }
811
	}
812
813
814
	/**
815
	 * Return the next date of
816
	 *
817
	 * @return	timestamp	false if KO, timestamp if OK
818
	 */
819
	function getNextDate()
820
	{
821
		if (empty($this->date_when)) return false;
822
		return dol_time_plus_duree($this->date_when, $this->frequency, $this->unit_frequency);
823
	}
824
825
	/**
826
	 *  Create all recurrents invoices (for all entities if multicompany is used).
827
	 *  A result may also be provided into this->output.
828
	 *
829
	 *  WARNING: This method change context $conf->entity to be in correct context for each recurring invoice found.
830
	 *
831
	 *  @return	int						0 if OK, < 0 if KO (this function is used also by cron so only 0 is OK)
832
	 */
833
	function createRecurringInvoices()
834
	{
835
		global $conf, $langs, $db, $user;
836
837
		$langs->load("bills");
838
839
		$nb_create=0;
840
841
		$now = dol_now();
842
		$tmparray=dol_getdate($now);
843
		$today = dol_mktime(23,59,59,$tmparray['mon'],$tmparray['mday'],$tmparray['year']);   // Today is last second of current day
844
845
		dol_syslog("createRecurringInvoices");
846
		$sql = 'SELECT rowid FROM '.MAIN_DB_PREFIX.'facture_rec';
847
		$sql.= ' WHERE frequency > 0';      // A recurring invoice is an invoice with a frequency
848
		$sql.= " AND (date_when IS NULL OR date_when <= '".$db->idate($today)."')";
849
		$sql.= ' AND (nb_gen_done < nb_gen_max OR nb_gen_max = 0)';
850
		$sql.= $db->order('entity', 'ASC');
851
		//print $sql;exit;
852
853
		$resql = $db->query($sql);
854
		if ($resql)
855
		{
856
		    $i=0;
857
		    $num = $db->num_rows($resql);
858
859
		    if ($num) $this->output.=$langs->trans("FoundXQualifiedRecurringInvoiceTemplate", $num)."\n";
860
		    else $this->output.=$langs->trans("NoQualifiedRecurringInvoiceTemplateFound");
861
862
		    $saventity = $conf->entity;
863
864
		    while ($i < $num)     // Loop on each template invoice
865
			{
866
			    $line = $db->fetch_object($resql);
867
868
			    $db->begin();
869
870
				$facturerec = new FactureRec($db);
871
				$facturerec->fetch($line->rowid);
872
873
				// Set entity context
874
				$conf->entity = $facturerec->entity;
875
876
				dol_syslog("createRecurringInvoices Process invoice template id=".$facturerec->id.", ref=".$facturerec->ref.", entity=".$facturerec->entity);
877
878
			    $error=0;
879
880
			    $facture = new Facture($db);
881
				$facture->fac_rec = $facturerec->id;    // We will create $facture from this recurring invoice
882
				$facture->fk_fac_rec_source = $facturerec->id;    // We will create $facture from this recurring invoice
883
884
			    $facture->type = self::TYPE_STANDARD;
885
			    $facture->brouillon = 1;
886
			    $facture->date = $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.
887
			    $facture->socid = $facturerec->socid;
888
			    $facture->suspended = 0;
889
890
			    $invoiceidgenerated = $facture->create($user);
891
			    if ($invoiceidgenerated <= 0)
892
			    {
893
			        $this->errors = $facture->errors;
894
			        $this->error = $facture->error;
895
			        $error++;
896
			    }
897
			    if (! $error && $facturerec->auto_validate)
898
			    {
899
			        $result = $facture->validate($user);
900
			        if ($result <= 0)
901
			        {
902
    			        $this->errors = $facture->errors;
903
    			        $this->error = $facture->error;
904
			            $error++;
905
			        }
906
			    }
907
908
				if (! $error && $invoiceidgenerated >= 0)
909
				{
910
					$db->commit("createRecurringInvoices Process invoice template id=".$facturerec->id.", ref=".$facturerec->ref);
911
					dol_syslog("createRecurringInvoices Process invoice template ".$facturerec->ref." is finished with a success generation");
912
					$nb_create++;
913
					$this->output.=$langs->trans("InvoiceGeneratedFromTemplate", $facture->ref, $facturerec->ref)."\n";
914
				}
915
				else
916
				{
917
				    $db->rollback("createRecurringInvoices Process invoice template id=".$facturerec->id.", ref=".$facturerec->ref);
918
				}
919
920
				$i++;
921
			}
922
923
			$conf->entity = $saventity;      // Restore entity context
924
		}
925
		else dol_print_error($db);
926
927
		$this->output=trim($this->output);
928
929
		return $error?$error:0;
0 ignored issues
show
Bug introduced by
The variable $error does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
930
	}
931
932
	/**
933
	 *	Return clicable name (with picto eventually)
934
	 *
935
	 * @param	int		$withpicto       Add picto into link
936
	 * @param  string	$option          Where point the link
937
	 * @param  int		$max             Maxlength of ref
938
	 * @param  int		$short           1=Return just URL
939
	 * @param  string   $moretitle       Add more text to title tooltip
940
	 * @return string 			         String with URL
941
	 */
942
	function getNomUrl($withpicto=0,$option='',$max=0,$short=0,$moretitle='')
943
	{
944
		global $langs;
945
946
		$result='';
947
        $label=$langs->trans("ShowInvoice").': '.$this->ref;
948
949
        $url = DOL_URL_ROOT.'/compta/facture/fiche-rec.php?facid='.$this->id;
950
951
        if ($short) return $url;
952
953
		$picto='bill';
954
955
		$link = '<a href="'.$url.'" title="'.dol_escape_htmltag($label, 1).'" class="classfortooltip">';
956
		$linkend='</a>';
957
958
959
960
        if ($withpicto) $result.=($link.img_object($label, $picto, 'class="classfortooltip"').$linkend);
961
		if ($withpicto && $withpicto != 2) $result.=' ';
962
		if ($withpicto != 2) $result.=$link.$this->ref.$linkend;
963
		return $result;
964
	}
965
966
	/**
967
	 *  Return label of object status
968
	 *
969
	 *  @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
970
	 *  @param      integer	$alreadypaid    Not used
971
	 *  @return     string			        Label
972
	 */
973
	function getLibStatut($mode=0,$alreadypaid=-1)
974
	{
975
		return $this->LibStatut($this->frequency?1:0, $this->suspended, $mode, $alreadypaid, $this->type);
976
	}
977
978
	/**
979
	 *	Renvoi le libelle d'un statut donne
980
	 *
981
	 *	@param    	int  	$recur         	Is it a recurring invoice ?
982
	 *	@param      int		$status        	Id status (suspended or not)
983
	 *	@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
984
	 *	@param		int		$alreadypaid	Not used
985
	 *	@param		int		$type			Type invoice
986
	 *	@return     string        			Libelle du statut
987
	 */
988
	function LibStatut($recur,$status,$mode=0,$alreadypaid=-1,$type=0)
989
	{
990
		global $langs;
991
		$langs->load('bills');
992
993
		//print "$recur,$status,$mode,$alreadypaid,$type";
994
		if ($mode == 0)
995
		{
996
			$prefix='';
997
			if ($recur)
998
			{
999
				if ($status == 1) return $langs->trans('Suspended');       // credit note
1000
				else return $langs->trans('Active');
1001
			}
1002
			else return $langs->trans("Draft");
1003
		}
1004
		if ($mode == 1)
1005
		{
1006
			$prefix='Short';
1007
			if ($recur)
1008
			{
1009
				if ($status == 1) return $langs->trans('Suspended');
1010
				else return $langs->trans('Active');
1011
			}
1012
			else return $langs->trans("Draft");
1013
		}
1014
		if ($mode == 2)
1015
		{
1016
			if ($recur)
1017
			{
1018
				if ($status == 1) return img_picto($langs->trans('Suspended'),'statut6').' '.$langs->trans('Suspended');
1019
				else return img_picto($langs->trans('Active'),'statut4').' '.$langs->trans('Active');
1020
			}
1021
			else return img_picto($langs->trans('Draft'),'statut0').' '.$langs->trans('Draft');
1022
		}
1023
		if ($mode == 3)
1024
		{
1025
			if ($recur)
1026
			{
1027
				$prefix='Short';
1028
				if ($status == 1) return img_picto($langs->trans('Suspended'),'statut6');
1029
				else return img_picto($langs->trans('Active'),'statut4');
1030
			}
1031
			else return img_picto($langs->trans('Draft'),'statut0');
1032
		}
1033
		if ($mode == 4)
1034
		{
1035
			$prefix='';
1036
			if ($recur)
1037
			{
1038
				if ($type == 1) return img_picto($langs->trans('Suspended'),'statut6').' '.$langs->trans('Suspended');
1039
				else return img_picto($langs->trans('Active'),'statut4').' '.$langs->trans('Active');
1040
			}
1041
			else return img_picto($langs->trans('Draft'),'statut0').' '.$langs->trans('Draft');
1042
		}
1043
		if ($mode == 5 || $mode == 6)
1044
		{
1045
			$prefix='';
1046
			if ($mode == 5) $prefix='Short';
1047
			if ($recur)
1048
			{
1049
				if ($status == 1) return '<span class="xhideonsmartphone">'.$langs->trans('Suspended').' </span>'.img_picto($langs->trans('Suspended'),'statut6');
1050
				else return '<span class="xhideonsmartphone">'.$langs->trans('Active').' </span>'.img_picto($langs->trans('Active'),'statut4');
1051
			}
1052
			else return $langs->trans('Draft').' '.img_picto($langs->trans('Active'),'statut0');
1053
		}
1054
	}
1055
1056
	/**
1057
	 *  Initialise an instance with random values.
1058
	 *  Used to build previews or test instances.
1059
	 *	id must be 0 if object instance is a specimen.
1060
	 *
1061
	 *	@param	string		$option		''=Create a specimen invoice with lines, 'nolines'=No lines
1062
	 *  @return	void
1063
	 */
1064
	function initAsSpecimen($option='')
1065
	{
1066
		global $user,$langs,$conf;
1067
1068
		$now=dol_now();
1069
		$arraynow=dol_getdate($now);
1070
		$nownotime=dol_mktime(0, 0, 0, $arraynow['mon'], $arraynow['mday'], $arraynow['year']);
1071
1072
        // Load array of products prodids
1073
		$num_prods = 0;
1074
		$prodids = array();
1075
1076
		$sql = "SELECT rowid";
1077
		$sql.= " FROM ".MAIN_DB_PREFIX."product";
1078
		$sql.= " WHERE entity IN (".getEntity('product').")";
1079
		$resql = $this->db->query($sql);
1080
		if ($resql)
1081
		{
1082
			$num_prods = $this->db->num_rows($resql);
1083
			$i = 0;
1084
			while ($i < $num_prods)
1085
			{
1086
				$i++;
1087
				$row = $this->db->fetch_row($resql);
1088
				$prodids[$i] = $row[0];
1089
			}
1090
		}
1091
1092
		// Initialize parameters
1093
		$this->id=0;
1094
		$this->ref = 'SPECIMEN';
1095
		$this->specimen=1;
1096
		$this->socid = 1;
1097
		$this->date = $nownotime;
1098
		$this->date_lim_reglement = $nownotime + 3600 * 24 *30;
1099
		$this->cond_reglement_id   = 1;
1100
		$this->cond_reglement_code = 'RECEP';
1101
		$this->date_lim_reglement=$this->calculate_date_lim_reglement();
1102
		$this->mode_reglement_id   = 0;		// Not forced to show payment mode CHQ + VIR
1103
		$this->mode_reglement_code = '';	// Not forced to show payment mode CHQ + VIR
1104
		$this->note_public='This is a comment (public)';
1105
		$this->note_private='This is a comment (private)';
1106
		$this->note='This is a comment (private)';
1107
		$this->fk_incoterms=0;
1108
		$this->location_incoterms='';
1109
1110
		if (empty($option) || $option != 'nolines')
1111
		{
1112
			// Lines
1113
			$nbp = 5;
1114
			$xnbp = 0;
1115
			while ($xnbp < $nbp)
1116
			{
1117
				$line=new FactureLigne($this->db);
1118
				$line->desc=$langs->trans("Description")." ".$xnbp;
1119
				$line->qty=1;
1120
				$line->subprice=100;
1121
				$line->tva_tx=19.6;
1122
				$line->localtax1_tx=0;
1123
				$line->localtax2_tx=0;
1124
				$line->remise_percent=0;
1125
				if ($xnbp == 1)        // Qty is negative (product line)
1126
				{
1127
					$prodid = mt_rand(1, $num_prods);
1128
					$line->fk_product=$prodids[$prodid];
1129
					$line->qty=-1;
1130
					$line->total_ht=-100;
1131
					$line->total_ttc=-119.6;
1132
					$line->total_tva=-19.6;
1133
				}
1134
				else if ($xnbp == 2)    // UP is negative (free line)
1135
				{
1136
					$line->subprice=-100;
1137
					$line->total_ht=-100;
1138
					$line->total_ttc=-119.6;
1139
					$line->total_tva=-19.6;
1140
					$line->remise_percent=0;
1141
				}
1142
				else if ($xnbp == 3)    // Discount is 50% (product line)
1143
				{
1144
					$prodid = mt_rand(1, $num_prods);
1145
					$line->fk_product=$prodids[$prodid];
1146
					$line->total_ht=50;
1147
					$line->total_ttc=59.8;
1148
					$line->total_tva=9.8;
1149
					$line->remise_percent=50;
1150
				}
1151
				else    // (product line)
1152
				{
1153
					$prodid = mt_rand(1, $num_prods);
1154
					$line->fk_product=$prodids[$prodid];
1155
					$line->total_ht=100;
1156
					$line->total_ttc=119.6;
1157
					$line->total_tva=19.6;
1158
					$line->remise_percent=00;
1159
				}
1160
1161
				$this->lines[$xnbp]=$line;
1162
				$xnbp++;
1163
1164
				$this->total_ht       += $line->total_ht;
1165
				$this->total_tva      += $line->total_tva;
1166
				$this->total_ttc      += $line->total_ttc;
1167
			}
1168
			$this->revenuestamp = 0;
1169
1170
			// Add a line "offered"
1171
			$line=new FactureLigne($this->db);
1172
			$line->desc=$langs->trans("Description")." (offered line)";
1173
			$line->qty=1;
1174
			$line->subprice=100;
1175
			$line->tva_tx=19.6;
1176
			$line->localtax1_tx=0;
1177
			$line->localtax2_tx=0;
1178
			$line->remise_percent=100;
1179
			$line->total_ht=0;
1180
			$line->total_ttc=0;    // 90 * 1.196
1181
			$line->total_tva=0;
1182
			$prodid = mt_rand(1, $num_prods);
1183
			$line->fk_product=$prodids[$prodid];
1184
1185
			$this->lines[$xnbp]=$line;
1186
			$xnbp++;
1187
		}
1188
1189
		$this->usenewprice = 1;
1190
	}
1191
1192
	/**
1193
	 * Function used to replace a thirdparty id with another one.
1194
	 *
1195
	 * @param DoliDB $db Database handler
1196
	 * @param int $origin_id Old thirdparty id
1197
	 * @param int $dest_id New thirdparty id
1198
	 * @return bool
1199
	 */
1200
	public static function replaceThirdparty(DoliDB $db, $origin_id, $dest_id)
1201
	{
1202
		$tables = array(
1203
			'facture_rec'
1204
		);
1205
1206
		return CommonObject::commonReplaceThirdparty($db, $origin_id, $dest_id, $tables);
1207
	}
1208
1209
	/**
1210
     *	Update frequency and unit
1211
     *
1212
     *	@param     	int		$frequency		value of frequency
1213
	 *	@param     	string	$unit 			unit of frequency  (d, m, y)
1214
     *	@return		int						<0 if KO, >0 if OK
1215
     */
1216
    function setFrequencyAndUnit($frequency,$unit)
1217
    {
1218
        if (! $this->table_element)
1219
        {
1220
            dol_syslog(get_class($this)."::setFrequencyAndUnit was called on objet with property table_element not defined",LOG_ERR);
1221
            return -1;
1222
        }
1223
1224
		if (!empty($frequency) && empty($unit))
1225
        {
1226
            dol_syslog(get_class($this)."::setFrequencyAndUnit was called on objet with params frequency defined but unit not defined",LOG_ERR);
1227
            return -2;
1228
        }
1229
1230
        $sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element;
1231
        $sql.= ' SET frequency = '.($frequency?$this->db->escape($frequency):'null');
1232
        if (!empty($unit))
1233
        {
1234
        	$sql.= ', unit_frequency = \''.$this->db->escape($unit).'\'';
1235
		}
1236
        $sql.= ' WHERE rowid = '.$this->id;
1237
1238
        dol_syslog(get_class($this)."::setFrequencyAndUnit", LOG_DEBUG);
1239
        if ($this->db->query($sql))
1240
        {
1241
            $this->frequency = $frequency;
1242
			if (!empty($unit)) $this->unit_frequency = $unit;
1243
            return 1;
1244
        }
1245
        else
1246
        {
1247
            dol_print_error($this->db);
1248
            return -1;
1249
        }
1250
    }
1251
1252
	/**
1253
     *	Update the next date of execution
1254
     *
1255
     *	@param     	datetime	$date					date of execution
1256
     *	@param     	int			$increment_nb_gen_done	0 do nothing more, >0 increment nb_gen_done
1257
     *	@return		int									<0 if KO, >0 if OK
1258
     */
1259
    function setNextDate($date, $increment_nb_gen_done=0)
1260
    {
1261
        if (! $this->table_element)
1262
        {
1263
            dol_syslog(get_class($this)."::setNextDate was called on objet with property table_element not defined",LOG_ERR);
1264
            return -1;
1265
        }
1266
        $sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element;
1267
        $sql.= " SET date_when = ".($date ? "'".$this->db->idate($date)."'" : "null");
1268
        if ($increment_nb_gen_done>0) $sql.= ', nb_gen_done = nb_gen_done + 1';
1269
        $sql.= ' WHERE rowid = '.$this->id;
1270
1271
        dol_syslog(get_class($this)."::setNextDate", LOG_DEBUG);
1272
        if ($this->db->query($sql))
1273
        {
1274
            $this->date_when = $date;
1275
            if ($increment_nb_gen_done>0) $this->nb_gen_done++;
1276
            return 1;
1277
        }
1278
        else
1279
        {
1280
            dol_print_error($this->db);
1281
            return -1;
1282
        }
1283
    }
1284
1285
	/**
1286
     *	Update the maximum period
1287
     *
1288
     *	@param     	int		$nb		number of maximum period
1289
     *	@return		int				<0 if KO, >0 if OK
1290
     */
1291
    function setMaxPeriod($nb)
1292
    {
1293
        if (! $this->table_element)
1294
        {
1295
            dol_syslog(get_class($this)."::setMaxPeriod was called on objet with property table_element not defined",LOG_ERR);
1296
            return -1;
1297
        }
1298
1299
        if (empty($nb)) $nb=0;
1300
1301
        $sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element;
1302
        $sql.= ' SET nb_gen_max = '.$nb;
1303
        $sql.= ' WHERE rowid = '.$this->id;
1304
1305
        dol_syslog(get_class($this)."::setMaxPeriod", LOG_DEBUG);
1306
        if ($this->db->query($sql))
1307
        {
1308
            $this->nb_gen_max = $nb;
1309
            return 1;
1310
        }
1311
        else
1312
        {
1313
            dol_print_error($this->db);
1314
            return -1;
1315
        }
1316
    }
1317
1318
	/**
1319
     *	Update the auto validate invoice
1320
     *
1321
     *	@param     	int		$validate		0 to create in draft, 1 to create and validate invoice
1322
     *	@return		int						<0 if KO, >0 if OK
1323
     */
1324
    function setAutoValidate($validate)
1325
    {
1326
        if (! $this->table_element)
1327
        {
1328
            dol_syslog(get_class($this)."::setAutoValidate was called on objet with property table_element not defined",LOG_ERR);
1329
            return -1;
1330
        }
1331
1332
        $sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element;
1333
        $sql.= ' SET auto_validate = '.$validate;
1334
        $sql.= ' WHERE rowid = '.$this->id;
1335
1336
        dol_syslog(get_class($this)."::setAutoValidate", LOG_DEBUG);
1337
        if ($this->db->query($sql))
1338
        {
1339
            $this->auto_validate = $validate;
1340
            return 1;
1341
        }
1342
        else
1343
        {
1344
            dol_print_error($this->db);
1345
            return -1;
1346
        }
1347
    }
1348
}
1349
1350
1351
1352
/**
1353
 *	Class to manage invoice lines of templates.
1354
 *  Saved into database table llx_facturedet_rec
1355
 */
1356
class FactureLigneRec extends CommonInvoiceLine
1357
{
1358
	public $element='facturedetrec';
1359
	public $table_element='facturedet_rec';
1360
1361
    /**
1362
     * 	Delete line in database
1363
     *
1364
     *  @param		User	$user		Object user
1365
     *  @param		int		$notrigger	Disable triggers
1366
     *	@return		int					<0 if KO, >0 if OK
1367
     */
1368
    function delete(User $user, $notrigger = false)
1369
    {
1370
    	$error=0;
1371
1372
	    $this->db->begin();
1373
1374
	    if (! $error) {
1375
	        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 zero. You might want to explicitly use === null 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...
1376
	            // Call triggers
1377
	            $result=$this->call_trigger('LINEBILLREC_DELETE', $user);
1378
	            if ($result < 0) { $error++; } // Do also here what you must do to rollback action if trigger fail
1379
	            // End call triggers
1380
	        }
1381
	    }
1382
1383
	    if (! $error)
1384
	    {
1385
    		$sql = 'DELETE FROM '.MAIN_DB_PREFIX.$this->table_element.' WHERE rowid='.$this->id;
1386
1387
    		$res = $this->db->query($sql);
1388
    		if($res===false) {
1389
    		    $error++;
1390
    		    $this->errors[] = $this->db->lasterror();
1391
    		}
1392
	    }
1393
1394
    	// Commit or rollback
1395
		if ($error) {
1396
		    $this->db->rollback();
1397
		    return -1;
1398
		} else {
1399
		    $this->db->commit();
1400
		    return 1;
1401
		}
1402
    }
1403
1404
1405
    /**
1406
     *	Recupere les lignes de factures predefinies dans this->lines
1407
     *
1408
     *	@param		int 	$rowid		Id of invoice
1409
     *	@return     int         		1 if OK, < 0 if KO
1410
     */
1411
    function fetch($rowid)
1412
    {
1413
    	$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,';
1414
    	$sql.= ' l.localtax1_tx, l.localtax2_tx, l.localtax1_type, l.localtax2_type, l.remise, l.remise_percent, l.subprice,';
1415
    	$sql.= ' l.info_bits, l.total_ht, l.total_tva, l.total_ttc,';
1416
    	$sql.= ' l.rang, l.special_code,';
1417
    	$sql.= ' l.fk_unit, l.fk_contract_line,';
1418
    	$sql.= ' p.ref as product_ref, p.fk_product_type as fk_product_type, p.label as product_label, p.description as product_desc';
1419
    	$sql.= ' FROM '.MAIN_DB_PREFIX.'facturedet_rec as l';
1420
    	$sql.= ' LEFT JOIN '.MAIN_DB_PREFIX.'product as p ON l.fk_product = p.rowid';
1421
    	$sql.= ' WHERE l.rowid = '.$rowid;
1422
    	$sql.= ' ORDER BY l.rang';
1423
1424
    	dol_syslog('FactureRec::fetch', LOG_DEBUG);
1425
    	$result = $this->db->query($sql);
1426
    	if ($result)
1427
    	{
1428
1429
    		$objp = $this->db->fetch_object($result);
1430
1431
    		$this->id	            = $objp->rowid;
1432
    		$this->label            = $objp->custom_label;		// Label line
1433
    		$this->desc             = $objp->description;		// Description line
1434
    		$this->description      = $objp->description;		// Description line
1435
    		$this->product_type     = $objp->product_type;		// Type of line
1436
    		$this->ref              = $objp->product_ref;		// Ref product
1437
    		$this->product_ref      = $objp->product_ref;		// Ref product
1438
    		$this->libelle          = $objp->product_label;		// deprecated
1439
    		$this->product_label	= $objp->product_label;		// Label product
1440
    		$this->product_desc     = $objp->product_desc;		// Description product
1441
    		$this->fk_product_type  = $objp->fk_product_type;	// Type of product
1442
    		$this->qty              = $objp->qty;
1443
    		$this->price			= $objp->price;
1444
    		$this->subprice         = $objp->subprice;
1445
    		$this->fk_facture		= $objp->fk_facture;
1446
    		$this->vat_src_code     = $objp->vat_src_code;
1447
    		$this->tva_tx           = $objp->tva_tx;
1448
    		$this->localtax1_tx     = $objp->localtax1_tx;
1449
    		$this->localtax2_tx     = $objp->localtax2_tx;
1450
    		$this->localtax1_type   = $objp->localtax1_type;
1451
    		$this->localtax2_type   = $objp->localtax2_type;
1452
    		$this->remise_percent   = $objp->remise_percent;
1453
    		$this->fk_remise_except = $objp->fk_remise_except;
1454
    		$this->fk_product       = $objp->fk_product;
1455
    		$this->info_bits        = $objp->info_bits;
1456
    		$this->total_ht         = $objp->total_ht;
1457
    		$this->total_tva        = $objp->total_tva;
1458
    		$this->total_ttc        = $objp->total_ttc;
1459
    		$this->code_ventilation = $objp->fk_code_ventilation;
1460
    		$this->rang 			= $objp->rang;
1461
    		$this->special_code 	= $objp->special_code;
1462
    		$this->fk_unit          = $objp->fk_unit;
1463
    		$this->fk_contract_line = $objp->fk_contract_line;
1464
1465
1466
    		$this->db->free($result);
1467
    		return 1;
1468
    	}
1469
    	else
1470
    	{
1471
    		$this->error=$this->db->lasterror();
1472
    		return -3;
1473
    	}
1474
    }
1475
1476
1477
    /**
1478
     * 	Update a line to invoice_rec.
1479
     *
1480
     *	@return    	int             				<0 if KO, Id of line if OK
1481
     */
1482
    function update()
1483
    {
1484
    	global $user;
1485
1486
    	include_once DOL_DOCUMENT_ROOT.'/core/lib/price.lib.php';
1487
1488
    	if ($fk_product)
0 ignored issues
show
Bug introduced by
The variable $fk_product does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
1489
    	{
1490
    		$product=new Product($this->db);
1491
    		$result=$product->fetch($fk_product);
0 ignored issues
show
Bug introduced by
The variable $fk_product does not exist. Did you mean $product?

This check looks for variables that are accessed but have not been defined. It raises an issue if it finds another variable that has a similar name.

The variable may have been renamed without also renaming all references.

Loading history...
1492
    		$product_type=$product->type;
1493
    	}
1494
1495
    	$sql = "UPDATE ".MAIN_DB_PREFIX."facturedet_rec SET ";
1496
    	$sql.= " fk_facture = ".$this->fk_facture;
1497
    	$sql.= ", label=".(! empty($this->label)?"'".$this->db->escape($this->label)."'":"null");
1498
    	$sql.= ", description='".$this->db->escape($this->desc)."'";
1499
    	$sql.= ", price=".price2num($this->price);
1500
    	$sql.= ", qty=".price2num($this->qty);
1501
    	$sql.= ", tva_tx=".price2num($this->tva_tx);
1502
    	$sql.= ", vat_src_code='".$this->db->escape($this->vat_src_code)."'";
1503
    	$sql.= ", localtax1_tx=".price2num($this->localtax1_tx);
1504
    	$sql.= ", localtax1_type='".$this->db->escape($this->localtax1_type)."'";
1505
    	$sql.= ", localtax2_tx=".price2num($this->localtax2_tx);
1506
    	$sql.= ", localtax2_type='".$this->db->escape($this->localtax2_type)."'";
1507
    	$sql.= ", fk_product=".(! empty($this->fk_product)?"'".$this->fk_product."'":"null");
1508
    	$sql.= ", product_type=".$this->product_type;
1509
    	$sql.= ", remise_percent='".price2num($this->remise_percent)."'";
1510
    	$sql.= ", subprice='".price2num($this->subprice)."'";
1511
    	$sql.= ", total_ht='".price2num($this->total_ht)."'";
1512
    	$sql.= ", total_tva='".price2num($this->total_tva)."'";
1513
    	$sql.= ", total_localtax1='".price2num($this->total_localtax1)."'";
1514
    	$sql.= ", total_localtax2='".price2num($this->total_localtax2)."'";
1515
    	$sql.= ", total_ttc='".price2num($this->total_ttc)."'";
1516
    	$sql.= ", rang=".$this->rang;
1517
    	$sql.= ", special_code=".$this->special_code;
1518
    	$sql.= ", fk_unit=".($this->fk_unit ?"'".$this->db->escape($this->fk_unit )."'":"null");
1519
    	$sql.= ", fk_contract_line=".($this->fk_contract_line?$this->fk_contract_line:"null");
1520
1521
    	$sql.= " WHERE rowid = ".$this->id;
1522
1523
    	dol_syslog(get_class($this)."::updateline", LOG_DEBUG);
1524
    	$resql=$this->db->query($sql);
1525
    	if ($resql)
1526
    	{
1527
    		if (empty($conf->global->MAIN_EXTRAFIELDS_DISABLED)) // For avoid conflicts if trigger used
0 ignored issues
show
Bug introduced by
The variable $conf does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
1528
    		{
1529
    			$result=$this->insertExtraFields();
1530
    			if ($result < 0)
1531
    			{
1532
    				$error++;
0 ignored issues
show
Bug introduced by
The variable $error does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
1533
    			}
1534
    		}
1535
1536
    		if (! $notrigger)
0 ignored issues
show
Bug introduced by
The variable $notrigger does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
1537
    		{
1538
    			// Call trigger
1539
    			$result=$this->call_trigger('LINEBILL_REC_UPDATE',$user);
1540
    			if ($result < 0)
1541
    			{
1542
    				$this->db->rollback();
1543
    				return -2;
1544
    			}
1545
    			// End call triggers
1546
    		}
1547
    		$this->db->commit();
1548
    		return 1;
1549
    	}
1550
    	else
1551
    	{
1552
    		$this->error=$this->db->error();
1553
    		$this->db->rollback();
1554
    		return -2;
1555
    	}
1556
1557
    }
1558
1559
}
1560