dolibarr  13.0.2
facture-rec.class.php
Go to the documentation of this file.
1 <?php
2 /* Copyright (C) 2003-2005 Rodolphe Quiedeville <rodolphe@quiedeville.org>
3  * Copyright (C) 2004-2019 Laurent Destailleur <eldy@users.sourceforge.net>
4  * Copyright (C) 2009-2012 Regis Houssin <regis.houssin@inodbox.com>
5  * Copyright (C) 2010-2011 Juanjo Menent <jmenent@2byte.es>
6  * Copyright (C) 2012 Cedric Salvador <csalvador@gpcsolutions.fr>
7  * Copyright (C) 2013 Florian Henry <florian.henry@open-concept.pro>
8  * Copyright (C) 2015 Marcos García <marcosgdf@gmail.com>
9  * Copyright (C) 2017-2020 Frédéric France <frederic.france@netlogic.fr>
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 <https://www.gnu.org/licenses/>.
23  */
24 
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 
41 {
45  public $element = 'facturerec';
46 
50  public $table_element = 'facture_rec';
51 
55  public $table_element_line = 'facturedet_rec';
56 
60  public $fk_element = 'fk_facture';
61 
65  public $picto = 'bill';
66 
70  public $entity;
71 
75  protected $table_ref_field = 'titre';
76 
80  public $title;
81 
82  public $number;
83  public $date;
84  public $remise;
85  public $tva;
86  public $total;
87  public $db_table;
88  public $propalid;
89 
90  public $date_last_gen;
91  public $date_when;
92  public $nb_gen_done;
93  public $nb_gen_max;
94 
98  public $frequency;
99 
103  public $unit_frequency;
104 
105  public $rang;
106  public $special_code;
107 
108  public $usenewprice = 0;
109 
110  public $suspended; // status
111 
136  // BEGIN MODULEBUILDER PROPERTIES
140  public $fields = array(
141  'rowid' =>array('type'=>'integer', 'label'=>'TechnicalID', 'enabled'=>1, 'visible'=>-1, 'notnull'=>1, 'position'=>10),
142  'titre' =>array('type'=>'varchar(100)', 'label'=>'Titre', 'enabled'=>1, 'showoncombobox' => 1, 'visible'=>-1, 'position'=>15),
143  'entity' =>array('type'=>'integer', 'label'=>'Entity', 'default'=>1, 'enabled'=>1, 'visible'=>-2, 'notnull'=>1, 'position'=>20, 'index'=>1),
144  'fk_soc' =>array('type'=>'integer:Societe:societe/class/societe.class.php', 'label'=>'ThirdParty', 'enabled'=>1, 'visible'=>-1, 'notnull'=>1, 'position'=>25),
145  'datec' =>array('type'=>'datetime', 'label'=>'DateCreation', 'enabled'=>1, 'visible'=>-1, 'position'=>30),
146  //'amount' =>array('type'=>'double(24,8)', 'label'=>'Amount', 'enabled'=>1, 'visible'=>-1, 'notnull'=>1, 'position'=>35),
147  'remise' =>array('type'=>'double', 'label'=>'Remise', 'enabled'=>1, 'visible'=>-1, 'position'=>40),
148  //'remise_percent' =>array('type'=>'double', 'label'=>'Remise percent', 'enabled'=>1, 'visible'=>-1, 'position'=>45),
149  //'remise_absolue' =>array('type'=>'double', 'label'=>'Remise absolue', 'enabled'=>1, 'visible'=>-1, 'position'=>50),
150  'tva' =>array('type'=>'double(24,8)', 'label'=>'Tva', 'enabled'=>1, 'visible'=>-1, 'position'=>55, 'isameasure'=>1),
151  'localtax1' =>array('type'=>'double(24,8)', 'label'=>'Localtax1', 'enabled'=>1, 'visible'=>-1, 'position'=>60, 'isameasure'=>1),
152  'localtax2' =>array('type'=>'double(24,8)', 'label'=>'Localtax2', 'enabled'=>1, 'visible'=>-1, 'position'=>65, 'isameasure'=>1),
153  'total' =>array('type'=>'double(24,8)', 'label'=>'Total', 'enabled'=>1, 'visible'=>-1, 'position'=>70, 'isameasure'=>1),
154  'total_ttc' =>array('type'=>'double(24,8)', 'label'=>'Total ttc', 'enabled'=>1, 'visible'=>-1, 'position'=>75, 'isameasure'=>1),
155  'fk_user_author' =>array('type'=>'integer:User:user/class/user.class.php', 'label'=>'Fk user author', 'enabled'=>1, 'visible'=>-1, 'position'=>80),
156  'fk_projet' =>array('type'=>'integer:Project:projet/class/project.class.php:1:fk_statut=1', 'label'=>'Fk projet', 'enabled'=>1, 'visible'=>-1, 'position'=>85),
157  'fk_cond_reglement' =>array('type'=>'integer', 'label'=>'Fk cond reglement', 'enabled'=>1, 'visible'=>-1, 'position'=>90),
158  'fk_mode_reglement' =>array('type'=>'integer', 'label'=>'Fk mode reglement', 'enabled'=>1, 'visible'=>-1, 'position'=>95),
159  'date_lim_reglement' =>array('type'=>'date', 'label'=>'Date lim reglement', 'enabled'=>1, 'visible'=>-1, 'position'=>100),
160  'note_private' =>array('type'=>'text', 'label'=>'NotePublic', 'enabled'=>1, 'visible'=>0, 'position'=>105),
161  'note_public' =>array('type'=>'text', 'label'=>'NotePrivate', 'enabled'=>1, 'visible'=>0, 'position'=>110),
162  'modelpdf' =>array('type'=>'varchar(255)', 'label'=>'Modelpdf', 'enabled'=>1, 'visible'=>-1, 'position'=>115),
163  'date_last_gen' =>array('type'=>'varchar(7)', 'label'=>'Last gen', 'enabled'=>1, 'visible'=>-1, 'position'=>120),
164  'unit_frequency' =>array('type'=>'varchar(2)', 'label'=>'Unit frequency', 'enabled'=>1, 'visible'=>-1, 'position'=>125),
165  'date_when' =>array('type'=>'datetime', 'label'=>'Date when', 'enabled'=>1, 'visible'=>-1, 'position'=>130),
166  'date_last_gen' =>array('type'=>'datetime', 'label'=>'Date last gen', 'enabled'=>1, 'visible'=>-1, 'position'=>135),
167  'nb_gen_done' =>array('type'=>'integer', 'label'=>'Nb gen done', 'enabled'=>1, 'visible'=>-1, 'position'=>140),
168  'nb_gen_max' =>array('type'=>'integer', 'label'=>'Nb gen max', 'enabled'=>1, 'visible'=>-1, 'position'=>145),
169  'frequency' =>array('type'=>'integer', 'label'=>'Frequency', 'enabled'=>1, 'visible'=>-1, 'position'=>150),
170  'usenewprice' =>array('type'=>'integer', 'label'=>'UseNewPrice', 'enabled'=>1, 'visible'=>0, 'position'=>155),
171  'revenuestamp' =>array('type'=>'double(24,8)', 'label'=>'RevenueStamp', 'enabled'=>1, 'visible'=>-1, 'position'=>160, 'isameasure'=>1),
172  'auto_validate' =>array('type'=>'integer', 'label'=>'Auto validate', 'enabled'=>1, 'visible'=>-1, 'position'=>165),
173  'generate_pdf' =>array('type'=>'integer', 'label'=>'Generate pdf', 'enabled'=>1, 'visible'=>-1, 'position'=>170),
174  'fk_account' =>array('type'=>'integer', 'label'=>'Fk account', 'enabled'=>1, 'visible'=>-1, 'position'=>175),
175  'fk_multicurrency' =>array('type'=>'integer', 'label'=>'Fk multicurrency', 'enabled'=>1, 'visible'=>-1, 'position'=>180),
176  'multicurrency_code' =>array('type'=>'varchar(255)', 'label'=>'Multicurrency code', 'enabled'=>1, 'visible'=>-1, 'position'=>185),
177  'multicurrency_tx' =>array('type'=>'double(24,8)', 'label'=>'Multicurrency tx', 'enabled'=>1, 'visible'=>-1, 'position'=>190, 'isameasure'=>1),
178  'multicurrency_total_ht' =>array('type'=>'double(24,8)', 'label'=>'Multicurrency total ht', 'enabled'=>1, 'visible'=>-1, 'position'=>195, 'isameasure'=>1),
179  'multicurrency_total_tva' =>array('type'=>'double(24,8)', 'label'=>'Multicurrency total tva', 'enabled'=>1, 'visible'=>-1, 'position'=>200, 'isameasure'=>1),
180  'multicurrency_total_ttc' =>array('type'=>'double(24,8)', 'label'=>'Multicurrency total ttc', 'enabled'=>1, 'visible'=>-1, 'position'=>205, 'isameasure'=>1),
181  'fk_user_modif' =>array('type'=>'integer:User:user/class/user.class.php', 'label'=>'UserModif', 'enabled'=>1, 'visible'=>-2, 'notnull'=>-1, 'position'=>210),
182  'tms' =>array('type'=>'timestamp', 'label'=>'DateModification', 'enabled'=>1, 'visible'=>-1, 'notnull'=>1, 'position'=>215),
183  'suspended' =>array('type'=>'integer', 'label'=>'Suspended', 'enabled'=>1, 'visible'=>-1, 'position'=>225),
184  );
185  // END MODULEBUILDER PROPERTIES
186 
187  const STATUS_NOTSUSPENDED = 0;
188  const STATUS_SUSPENDED = 1;
189 
190 
191 
197  public function __construct($db)
198  {
199  $this->db = $db;
200  }
201 
210  public function create($user, $facid, $notrigger = 0)
211  {
212  global $conf;
213 
214  $error = 0;
215  $now = dol_now();
216 
217  // Clean parameters
218  $this->titre = trim(isset($this->titre) ? $this->titre : $this->title); // deprecated
219  $this->title = trim($this->title);
220  $this->usenewprice = empty($this->usenewprice) ? 0 : $this->usenewprice;
221  if (empty($this->suspended)) $this->suspended = 0;
222 
223  // No frequency defined then no next date to execution
224  if (empty($this->frequency))
225  {
226  $this->frequency = 0;
227  $this->date_when = null;
228  }
229 
230  $this->frequency = abs($this->frequency);
231  $this->nb_gen_done = 0;
232  $this->nb_gen_max = empty($this->nb_gen_max) ? 0 : $this->nb_gen_max;
233  $this->auto_validate = empty($this->auto_validate) ? 0 : $this->auto_validate;
234  $this->generate_pdf = empty($this->generate_pdf) ? 0 : $this->generate_pdf;
235 
236  $this->db->begin();
237 
238  // Charge facture modele
239  $facsrc = new Facture($this->db);
240  $result = $facsrc->fetch($facid);
241  if ($result > 0)
242  {
243  // On positionne en mode brouillon la facture
244  $this->brouillon = 1;
245 
246  $sql = "INSERT INTO ".MAIN_DB_PREFIX."facture_rec (";
247  $sql .= "titre";
248  $sql .= ", fk_soc";
249  $sql .= ", entity";
250  $sql .= ", datec";
251  $sql .= ", amount";
252  $sql .= ", remise";
253  $sql .= ", note_private";
254  $sql .= ", note_public";
255  $sql .= ", modelpdf";
256  $sql .= ", fk_user_author";
257  $sql .= ", fk_projet";
258  $sql .= ", fk_account";
259  $sql .= ", fk_cond_reglement";
260  $sql .= ", fk_mode_reglement";
261  $sql .= ", usenewprice";
262  $sql .= ", frequency";
263  $sql .= ", unit_frequency";
264  $sql .= ", date_when";
265  $sql .= ", date_last_gen";
266  $sql .= ", nb_gen_done";
267  $sql .= ", nb_gen_max";
268  $sql .= ", auto_validate";
269  $sql .= ", generate_pdf";
270  $sql .= ", fk_multicurrency";
271  $sql .= ", multicurrency_code";
272  $sql .= ", multicurrency_tx";
273  $sql .= ", suspended";
274  $sql .= ") VALUES (";
275  $sql .= "'".$this->db->escape($this->titre ? $this->titre : $this->title)."'";
276  $sql .= ", ".$facsrc->socid;
277  $sql .= ", ".$conf->entity;
278  $sql .= ", '".$this->db->idate($now)."'";
279  $sql .= ", ".(!empty($facsrc->amount) ? $facsrc->amount : '0');
280  $sql .= ", ".(!empty($facsrc->remise) ? $this->remise : '0');
281  $sql .= ", ".(!empty($this->note_private) ? ("'".$this->db->escape($this->note_private)."'") : "NULL");
282  $sql .= ", ".(!empty($this->note_public) ? ("'".$this->db->escape($this->note_public)."'") : "NULL");
283  $sql .= ", ".(!empty($this->modelpdf) ? ("'".$this->db->escape($this->modelpdf)."'") : "NULL");
284  $sql .= ", '".$this->db->escape($user->id)."'";
285  $sql .= ", ".(!empty($facsrc->fk_project) ? "'".$this->db->escape($facsrc->fk_project)."'" : "null");
286  $sql .= ", ".(!empty($facsrc->fk_account) ? "'".$this->db->escape($facsrc->fk_account)."'" : "null");
287  $sql .= ", ".($facsrc->cond_reglement_id > 0 ? $this->db->escape($facsrc->cond_reglement_id) : "null");
288  $sql .= ", ".($facsrc->mode_reglement_id > 0 ? $this->db->escape($facsrc->mode_reglement_id) : "null");
289  $sql .= ", ".$this->usenewprice;
290  $sql .= ", ".$this->frequency;
291  $sql .= ", '".$this->db->escape($this->unit_frequency)."'";
292  $sql .= ", ".(!empty($this->date_when) ? "'".$this->db->idate($this->date_when)."'" : 'NULL');
293  $sql .= ", ".(!empty($this->date_last_gen) ? "'".$this->db->idate($this->date_last_gen)."'" : 'NULL');
294  $sql .= ", ".$this->db->escape($this->nb_gen_done);
295  $sql .= ", ".$this->db->escape($this->nb_gen_max);
296  $sql .= ", ".$this->db->escape($this->auto_validate);
297  $sql .= ", ".$this->db->escape($this->generate_pdf);
298  $sql .= ", ".$this->db->escape($facsrc->fk_multicurrency);
299  $sql .= ", '".$this->db->escape($facsrc->multicurrency_code)."'";
300  $sql .= ", ".$this->db->escape($facsrc->multicurrency_tx);
301  $sql .= ", ".$this->db->escape($this->suspended);
302  $sql .= ")";
303 
304  if ($this->db->query($sql))
305  {
306  $this->id = $this->db->last_insert_id(MAIN_DB_PREFIX."facture_rec");
307 
308  // Fields used into addline later
309  $this->fk_multicurrency = $facsrc->fk_multicurrency;
310  $this->multicurrency_code = $facsrc->multicurrency_code;
311  $this->multicurrency_tx = $facsrc->multicurrency_tx;
312 
313  // Add lines
314  $num = count($facsrc->lines);
315  for ($i = 0; $i < $num; $i++)
316  {
317  $tva_tx = $facsrc->lines[$i]->tva_tx;
318  if (!empty($facsrc->lines[$i]->vat_src_code) && !preg_match('/\(/', $tva_tx)) $tva_tx .= ' ('.$facsrc->lines[$i]->vat_src_code.')';
319 
320  $result_insert = $this->addline(
321  $facsrc->lines[$i]->desc,
322  $facsrc->lines[$i]->subprice,
323  $facsrc->lines[$i]->qty,
324  $tva_tx,
325  $facsrc->lines[$i]->localtax1_tx,
326  $facsrc->lines[$i]->localtax2_tx,
327  $facsrc->lines[$i]->fk_product,
328  $facsrc->lines[$i]->remise_percent,
329  'HT',
330  $facsrc->lines[$i]->info_bits,
331  '',
332  0,
333  $facsrc->lines[$i]->product_type,
334  $facsrc->lines[$i]->rang,
335  $facsrc->lines[$i]->special_code,
336  $facsrc->lines[$i]->label,
337  $facsrc->lines[$i]->fk_unit,
338  $facsrc->lines[$i]->multicurrency_subprice,
339  0,
340  0,
341  null,
342  $facsrc->lines[$i]->pa_ht
343  );
344 
345  if ($result_insert < 0)
346  {
347  $error++;
348  } else {
349  $objectline = new FactureLigneRec($this->db);
350  $result2 = $objectline->fetch($result_insert);
351  if ($result2 > 0) {
352  // Extrafields
353  if (method_exists($facsrc->lines[$i], 'fetch_optionals')) {
354  $facsrc->lines[$i]->fetch_optionals($facsrc->lines[$i]->rowid);
355  $objectline->array_options = $facsrc->lines[$i]->array_options;
356  }
357 
358  $result = $objectline->insertExtraFields();
359  if ($result < 0)
360  {
361  $error++;
362  }
363  } elseif ($result2 < 0) {
364  $this->errors[] = $objectline->error;
365  $error++;
366  }
367  }
368  }
369 
370  if (!empty($this->linkedObjectsIds) && empty($this->linked_objects)) // To use new linkedObjectsIds instead of old linked_objects
371  {
372  $this->linked_objects = $this->linkedObjectsIds; // TODO Replace linked_objects with linkedObjectsIds
373  }
374 
375  // Add object linked
376  if (!$error && $this->id && !empty($this->linked_objects) && is_array($this->linked_objects))
377  {
378  foreach ($this->linked_objects as $origin => $tmp_origin_id)
379  {
380  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, ...))
381  {
382  foreach ($tmp_origin_id as $origin_id)
383  {
384  $ret = $this->add_object_linked($origin, $origin_id);
385  if (!$ret)
386  {
387  $this->error = $this->db->lasterror();
388  $error++;
389  }
390  }
391  } else // Old behaviour, if linked_object has only one link per type, so is something like array('contract'=>id1))
392  {
393  $origin_id = $tmp_origin_id;
394  $ret = $this->add_object_linked($origin, $origin_id);
395  if (!$ret)
396  {
397  $this->error = $this->db->lasterror();
398  $error++;
399  }
400  }
401  }
402  }
403 
404  if (!$error) {
405  $result = $this->insertExtraFields();
406  if ($result < 0)
407  {
408  $error++;
409  }
410  }
411 
412  if (!$error && !$notrigger)
413  {
414  // Call trigger
415  $result = $this->call_trigger('BILLREC_CREATE', $user);
416  if ($result < 0)
417  {
418  $this->db->rollback();
419  return -2;
420  }
421  // End call triggers
422  }
423 
424  if ($error)
425  {
426  $this->db->rollback();
427  return -3;
428  } else {
429  $this->db->commit();
430  return $this->id;
431  }
432  } else {
433  $this->error = $this->db->lasterror();
434  $this->db->rollback();
435  return -2;
436  }
437  } else {
438  $this->db->rollback();
439  return -1;
440  }
441  }
442 
443 
451  public function update(User $user, $notrigger = 0)
452  {
453  global $conf;
454 
455  $error = 0;
456 
457  $sql = "UPDATE ".MAIN_DB_PREFIX."facture_rec SET";
458  $sql .= " fk_soc = ".$this->fk_soc;
459  // TODO Add missing fields
460  $sql .= " WHERE rowid = ".$this->id;
461 
462  dol_syslog(get_class($this)."::update", LOG_DEBUG);
463  $resql = $this->db->query($sql);
464  if ($resql)
465  {
466  if (!$error)
467  {
468  $result = $this->insertExtraFields();
469  if ($result < 0)
470  {
471  $error++;
472  }
473  }
474 
475  if (!$error && !$notrigger)
476  {
477  // Call trigger
478  $result = $this->call_trigger('BILLREC_UPDATE', $user);
479  if ($result < 0)
480  {
481  $this->db->rollback();
482  return -2;
483  }
484  // End call triggers
485  }
486  $this->db->commit();
487  return 1;
488  } else {
489  $this->error = $this->db->lasterror();
490  $this->db->rollback();
491  return -2;
492  }
493  }
494 
503  public function fetch($rowid, $ref = '', $ref_ext = '')
504  {
505  $sql = 'SELECT f.rowid, f.entity, f.titre as title, f.suspended, f.fk_soc, f.tva, f.localtax1, f.localtax2, f.total, f.total_ttc';
506  $sql .= ', f.remise_percent, f.remise_absolue, f.remise';
507  $sql .= ', f.date_lim_reglement as dlr';
508  $sql .= ', f.note_private, f.note_public, f.fk_user_author';
509  $sql .= ', f.modelpdf as model_pdf';
510  $sql .= ', f.fk_mode_reglement, f.fk_cond_reglement, f.fk_projet as fk_project';
511  $sql .= ', f.fk_account';
512  $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';
513  $sql .= ', f.generate_pdf';
514  $sql .= ", f.fk_multicurrency, f.multicurrency_code, f.multicurrency_tx, f.multicurrency_total_ht, f.multicurrency_total_tva, f.multicurrency_total_ttc";
515  $sql .= ', p.code as mode_reglement_code, p.libelle as mode_reglement_libelle';
516  $sql .= ', c.code as cond_reglement_code, c.libelle as cond_reglement_libelle, c.libelle_facture as cond_reglement_libelle_doc';
517  //$sql.= ', el.fk_source';
518  $sql .= ' FROM '.MAIN_DB_PREFIX.'facture_rec as f';
519  $sql .= ' LEFT JOIN '.MAIN_DB_PREFIX.'c_payment_term as c ON f.fk_cond_reglement = c.rowid';
520  $sql .= ' LEFT JOIN '.MAIN_DB_PREFIX.'c_paiement as p ON f.fk_mode_reglement = p.id';
521  //$sql.= " LEFT JOIN ".MAIN_DB_PREFIX."element_element as el ON el.fk_target = f.rowid AND el.targettype = 'facture'";
522  $sql .= ' WHERE f.entity IN ('.getEntity('invoice').')';
523  if ($rowid) {
524  $sql .= ' AND f.rowid='.((int) $rowid);
525  } elseif ($ref) {
526  $sql .= " AND f.titre='".$this->db->escape($ref)."'";
527  // This field are not used for template invoice
528  //} elseif ($ref_ext) { $sql.= " AND f.ref_ext='".$this->db->escape($ref_ext)."'"; }
529  } else {
530  $sql .= ' AND f.rowid = 0';
531  }
532 
533  $result = $this->db->query($sql);
534  if ($result)
535  {
536  if ($this->db->num_rows($result))
537  {
538  $obj = $this->db->fetch_object($result);
539 
540  $this->id = $obj->rowid;
541  $this->entity = $obj->entity;
542  $this->titre = $obj->title; // deprecated
543  $this->title = $obj->title;
544  $this->ref = $obj->title;
545  $this->ref_client = $obj->ref_client;
546  $this->suspended = $obj->suspended;
547  $this->type = $obj->type;
548  $this->datep = $obj->dp;
549  $this->date = $obj->df;
550  $this->remise_percent = $obj->remise_percent;
551  $this->remise_absolue = $obj->remise_absolue;
552  $this->remise = $obj->remise;
553  $this->total_ht = $obj->total;
554  $this->total_tva = $obj->tva;
555  $this->total_localtax1 = $obj->localtax1;
556  $this->total_localtax2 = $obj->localtax2;
557  $this->total_ttc = $obj->total_ttc;
558  $this->paye = $obj->paye;
559  $this->close_code = $obj->close_code;
560  $this->close_note = $obj->close_note;
561  $this->socid = $obj->fk_soc;
562  $this->date_lim_reglement = $this->db->jdate($obj->dlr);
563  $this->mode_reglement_id = $obj->fk_mode_reglement;
564  $this->mode_reglement_code = $obj->mode_reglement_code;
565  $this->mode_reglement = $obj->mode_reglement_libelle;
566  $this->cond_reglement_id = $obj->fk_cond_reglement;
567  $this->cond_reglement_code = $obj->cond_reglement_code;
568  $this->cond_reglement = $obj->cond_reglement_libelle;
569  $this->cond_reglement_doc = $obj->cond_reglement_libelle_doc;
570  $this->fk_project = $obj->fk_project;
571  $this->fk_account = $obj->fk_account;
572  $this->fk_facture_source = $obj->fk_facture_source;
573  $this->note_private = $obj->note_private;
574  $this->note_public = $obj->note_public;
575  $this->user_author = $obj->fk_user_author;
576  $this->modelpdf = $obj->model_pdf; // deprecatd
577  $this->model_pdf = $obj->model_pdf;
578  $this->rang = $obj->rang;
579  $this->special_code = $obj->special_code;
580  $this->frequency = $obj->frequency;
581  $this->unit_frequency = $obj->unit_frequency;
582  $this->date_when = $this->db->jdate($obj->date_when);
583  $this->date_last_gen = $this->db->jdate($obj->date_last_gen);
584  $this->nb_gen_done = $obj->nb_gen_done;
585  $this->nb_gen_max = $obj->nb_gen_max;
586  $this->usenewprice = $obj->usenewprice;
587  $this->auto_validate = $obj->auto_validate;
588  $this->generate_pdf = $obj->generate_pdf;
589 
590  // Multicurrency
591  $this->fk_multicurrency = $obj->fk_multicurrency;
592  $this->multicurrency_code = $obj->multicurrency_code;
593  $this->multicurrency_tx = $obj->multicurrency_tx;
594  $this->multicurrency_total_ht = $obj->multicurrency_total_ht;
595  $this->multicurrency_total_tva = $obj->multicurrency_total_tva;
596  $this->multicurrency_total_ttc = $obj->multicurrency_total_ttc;
597 
598  if ($this->statut == self::STATUS_DRAFT) $this->brouillon = 1;
599 
600  // Retrieve all extrafield
601  // fetch optionals attributes and labels
602  $this->fetch_optionals();
603 
604  /*
605  * Lines
606  */
607  $result = $this->fetch_lines();
608  if ($result < 0)
609  {
610  $this->error = $this->db->lasterror();
611  return -3;
612  }
613  return 1;
614  } else {
615  $this->error = 'Bill with id '.$rowid.' or ref '.$ref.' not found sql='.$sql;
616  dol_syslog('Facture::Fetch Error '.$this->error, LOG_ERR);
617  return -2;
618  }
619  } else {
620  $this->error = $this->db->error();
621  return -1;
622  }
623  }
624 
625 
631  public function getLinesArray()
632  {
633  return $this->fetch_lines();
634  }
635 
636 
637  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
643  public function fetch_lines()
644  {
645  global $extrafields;
646 
647  // phpcs:enable
648  $this->lines = array();
649 
650  // Retrieve all extrafield for line
651  // fetch optionals attributes and labels
652  if (!is_object($extrafields))
653  {
654  require_once DOL_DOCUMENT_ROOT.'/core/class/extrafields.class.php';
655  $extrafields = new ExtraFields($this->db);
656  }
657  $extrafields->fetch_name_optionals_label($this->table_element_line, true);
658 
659  $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, ';
660  $sql .= ' l.localtax1_tx, l.localtax2_tx, l.localtax1_type, l.localtax2_type, l.remise, l.remise_percent, l.subprice,';
661  $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, l.buy_price_ht as pa_ht,';
662  //$sql.= ' l.situation_percent, l.fk_prev_id,';
663  //$sql.= ' l.localtax1_tx, l.localtax2_tx, l.localtax1_type, l.localtax2_type, l.remise_percent, l.fk_remise_except, l.subprice,';
664  $sql .= ' l.rang, l.special_code,';
665  //$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, l.buy_price_ht as pa_ht,';
666  $sql .= ' l.fk_unit, l.fk_contract_line,';
667  $sql .= ' l.fk_multicurrency, l.multicurrency_code, l.multicurrency_subprice, l.multicurrency_total_ht, l.multicurrency_total_tva, l.multicurrency_total_ttc,';
668  $sql .= ' p.ref as product_ref, p.fk_product_type as fk_product_type, p.label as product_label, p.description as product_desc';
669  $sql .= ' FROM '.MAIN_DB_PREFIX.'facturedet_rec as l';
670  $sql .= ' LEFT JOIN '.MAIN_DB_PREFIX.'product as p ON l.fk_product = p.rowid';
671  $sql .= ' WHERE l.fk_facture = '.$this->id;
672  $sql .= ' ORDER BY l.rang';
673 
674  dol_syslog('FactureRec::fetch_lines', LOG_DEBUG);
675  $result = $this->db->query($sql);
676  if ($result)
677  {
678  $num = $this->db->num_rows($result);
679  $i = 0;
680  while ($i < $num)
681  {
682  $objp = $this->db->fetch_object($result);
683  $line = new FactureLigneRec($this->db);
684 
685  $line->id = $objp->rowid;
686  $line->rowid = $objp->rowid;
687  $line->desc = $objp->description; // Description line
688  $line->description = $objp->description; // Description line
689  $line->product_type = $objp->product_type; // Type of line
690  $line->ref = $objp->product_ref; // Ref product
691  $line->product_ref = $objp->product_ref; // Ref product
692  $line->libelle = $objp->product_label; // deprecated
693  $line->product_label = $objp->product_label; // Label product
694  $line->product_desc = $objp->product_desc; // Description product
695  $line->fk_product_type = $objp->fk_product_type; // Type of product
696  $line->qty = $objp->qty;
697  $line->subprice = $objp->subprice;
698 
699  $line->label = $objp->custom_label; // @deprecated
700 
701  $line->vat_src_code = $objp->vat_src_code;
702  $line->tva_tx = $objp->tva_tx;
703  $line->localtax1_tx = $objp->localtax1_tx;
704  $line->localtax2_tx = $objp->localtax2_tx;
705  $line->localtax1_type = $objp->localtax1_type;
706  $line->localtax2_type = $objp->localtax2_type;
707  $line->remise_percent = $objp->remise_percent;
708  $line->fk_remise_except = $objp->fk_remise_except;
709  $line->fk_product = $objp->fk_product;
710  $line->date_start_fill = $objp->date_start_fill;
711  $line->date_end_fill = $objp->date_end_fill;
712  $line->info_bits = $objp->info_bits;
713  $line->total_ht = $objp->total_ht;
714  $line->total_tva = $objp->total_tva;
715  $line->total_ttc = $objp->total_ttc;
716 
717  //$line->code_ventilation = $objp->fk_code_ventilation;
718 
719  $line->fk_product_fournisseur_price = $objp->fk_product_fournisseur_price;
720  $line->fk_fournprice = $objp->fk_product_fournisseur_price; // For backward compatibility
721 
722  $marginInfos = getMarginInfos($objp->subprice, $objp->remise_percent, $objp->tva_tx, $objp->localtax1_tx, $objp->localtax2_tx, $objp->fk_product_fournisseur_price, $objp->pa_ht);
723 
724  $line->buyprice = $marginInfos[0];
725  $line->pa_ht = $marginInfos[0]; // For backward compatibility
726  $line->marge_tx = $marginInfos[1];
727  $line->marque_tx = $marginInfos[2];
728  $line->rang = $objp->rang;
729  $line->special_code = $objp->special_code;
730  $line->fk_unit = $objp->fk_unit;
731  $line->fk_contract_line = $objp->fk_contract_line;
732 
733  // Ne plus utiliser
734  $line->price = $objp->price;
735  $line->remise = $objp->remise;
736 
737  $line->fetch_optionals();
738 
739  // Multicurrency
740  $line->fk_multicurrency = $objp->fk_multicurrency;
741  $line->multicurrency_code = $objp->multicurrency_code;
742  $line->multicurrency_subprice = $objp->multicurrency_subprice;
743  $line->multicurrency_total_ht = $objp->multicurrency_total_ht;
744  $line->multicurrency_total_tva = $objp->multicurrency_total_tva;
745  $line->multicurrency_total_ttc = $objp->multicurrency_total_ttc;
746 
747  $this->lines[$i] = $line;
748 
749  $i++;
750  }
751 
752  $this->db->free($result);
753  return 1;
754  } else {
755  $this->error = $this->db->lasterror();
756  return -3;
757  }
758  }
759 
760 
769  public function delete(User $user, $notrigger = 0, $idwarehouse = -1)
770  {
771  $rowid = $this->id;
772 
773  dol_syslog(get_class($this)."::delete rowid=".$rowid, LOG_DEBUG);
774 
775  $error = 0;
776  $this->db->begin();
777 
778  $main = MAIN_DB_PREFIX.'facturedet_rec';
779  $ef = $main."_extrafields";
780  $sqlef = "DELETE FROM $ef WHERE fk_object IN (SELECT rowid FROM $main WHERE fk_facture = $rowid)";
781  dol_syslog($sqlef);
782  $sql = "DELETE FROM ".MAIN_DB_PREFIX."facturedet_rec WHERE fk_facture = ".$rowid;
783  dol_syslog($sql);
784  if ($this->db->query($sqlef) && $this->db->query($sql))
785  {
786  $sql = "DELETE FROM ".MAIN_DB_PREFIX."facture_rec WHERE rowid = ".$rowid;
787  dol_syslog($sql);
788  if ($this->db->query($sql))
789  {
790  // Delete linked object
791  $res = $this->deleteObjectLinked();
792  if ($res < 0) $error = -3;
793  // Delete extrafields
794  $res = $this->deleteExtraFields();
795  if ($res < 0) $error = -4;
796  } else {
797  $this->error = $this->db->lasterror();
798  $error = -1;
799  }
800  } else {
801  $this->error = $this->db->lasterror();
802  $error = -2;
803  }
804 
805  if (!$error)
806  {
807  $this->db->commit();
808  return 1;
809  } else {
810  $this->db->rollback();
811  return $error;
812  }
813  }
814 
815 
843  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)
844  {
845  global $mysoc;
846 
847  $facid = $this->id;
848 
849  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);
850  include_once DOL_DOCUMENT_ROOT.'/core/lib/price.lib.php';
851 
852  // Check parameters
853  if ($type < 0) return -1;
854 
855  $localtaxes_type = getLocalTaxesFromRate($txtva, 0, $this->thirdparty, $mysoc);
856 
857  // Clean vat code
858  $vat_src_code = '';
859  if (preg_match('/\((.*)\)/', $txtva, $reg))
860  {
861  $vat_src_code = $reg[1];
862  $txtva = preg_replace('/\s*\(.*\)/', '', $txtva); // Remove code into vatrate.
863  }
864 
865  if ($this->brouillon)
866  {
867  // Clean parameters
868  $remise_percent = price2num($remise_percent);
869  if (empty($remise_percent)) $remise_percent = 0;
870  $qty = price2num($qty);
871  $pu_ht = price2num($pu_ht);
872  $pu_ttc = price2num($pu_ttc);
873  if (!preg_match('/\((.*)\)/', $txtva)) {
874  $txtva = price2num($txtva); // $txtva can have format '5.0(XXX)' or '5'
875  }
876  $txlocaltax1 = price2num($txlocaltax1);
877  $txlocaltax2 = price2num($txlocaltax2);
878  if (empty($txtva)) $txtva = 0;
879  if (empty($txlocaltax1)) $txlocaltax1 = 0;
880  if (empty($txlocaltax2)) $txlocaltax2 = 0;
881  if (empty($info_bits)) $info_bits = 0;
882 
883  if ($price_base_type == 'HT')
884  {
885  $pu = $pu_ht;
886  } else {
887  $pu = $pu_ttc;
888  }
889 
890  // Calcul du total TTC et de la TVA pour la ligne a partir de
891  // qty, pu, remise_percent et txtva
892  // TRES IMPORTANT: C'est au moment de l'insertion ligne qu'on doit stocker
893  // la part ht, tva et ttc, et ce au niveau de la ligne qui a son propre taux tva.
894 
895  $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);
896  $total_ht = $tabprice[0];
897  $total_tva = $tabprice[1];
898  $total_ttc = $tabprice[2];
899  $total_localtax1 = $tabprice[9];
900  $total_localtax2 = $tabprice[10];
901  $pu_ht = $tabprice[3];
902 
903  // MultiCurrency
904  $multicurrency_total_ht = $tabprice[16];
905  $multicurrency_total_tva = $tabprice[17];
906  $multicurrency_total_ttc = $tabprice[18];
907  $pu_ht_devise = $tabprice[19];
908 
909  $product_type = $type;
910  if ($fk_product)
911  {
912  $product = new Product($this->db);
913  $result = $product->fetch($fk_product);
914  $product_type = $product->type;
915  }
916 
917  $sql = "INSERT INTO ".MAIN_DB_PREFIX."facturedet_rec (";
918  $sql .= "fk_facture";
919  $sql .= ", label";
920  $sql .= ", description";
921  $sql .= ", price";
922  $sql .= ", qty";
923  $sql .= ", tva_tx";
924  $sql .= ", vat_src_code";
925  $sql .= ", localtax1_tx";
926  $sql .= ", localtax1_type";
927  $sql .= ", localtax2_tx";
928  $sql .= ", localtax2_type";
929  $sql .= ", fk_product";
930  $sql .= ", product_type";
931  $sql .= ", remise_percent";
932  $sql .= ", subprice";
933  $sql .= ", remise";
934  $sql .= ", total_ht";
935  $sql .= ", total_tva";
936  $sql .= ", total_localtax1";
937  $sql .= ", total_localtax2";
938  $sql .= ", total_ttc";
939  $sql .= ", date_start_fill";
940  $sql .= ", date_end_fill";
941  $sql .= ", fk_product_fournisseur_price";
942  $sql .= ", buy_price_ht";
943  $sql .= ", info_bits";
944  $sql .= ", rang";
945  $sql .= ", special_code";
946  $sql .= ", fk_unit";
947  $sql .= ', fk_multicurrency, multicurrency_code, multicurrency_subprice, multicurrency_total_ht, multicurrency_total_tva, multicurrency_total_ttc';
948  $sql .= ") VALUES (";
949  $sql .= " ".((int) $facid);
950  $sql .= ", ".(!empty($label) ? "'".$this->db->escape($label)."'" : "null");
951  $sql .= ", '".$this->db->escape($desc)."'";
952  $sql .= ", ".price2num($pu_ht);
953  $sql .= ", ".price2num($qty);
954  $sql .= ", ".price2num($txtva);
955  $sql .= ", '".$this->db->escape($vat_src_code)."'";
956  $sql .= ", ".price2num($txlocaltax1);
957  $sql .= ", '".$this->db->escape(isset($localtaxes_type[0]) ? $localtaxes_type[0] : '')."'";
958  $sql .= ", ".price2num($txlocaltax2);
959  $sql .= ", '".$this->db->escape(isset($localtaxes_type[2]) ? $localtaxes_type[2] : '')."'";
960  $sql .= ", ".(!empty($fk_product) ? "'".$this->db->escape($fk_product)."'" : "null");
961  $sql .= ", ".$product_type;
962  $sql .= ", ".price2num($remise_percent);
963  $sql .= ", ".price2num($pu_ht);
964  $sql .= ", null";
965  $sql .= ", ".price2num($total_ht);
966  $sql .= ", ".price2num($total_tva);
967  $sql .= ", ".price2num($total_localtax1);
968  $sql .= ", ".price2num($total_localtax2);
969  $sql .= ", ".price2num($total_ttc);
970  $sql .= ", ".(int) $date_start_fill;
971  $sql .= ", ".(int) $date_end_fill;
972  $sql .= ", ".($fk_fournprice > 0 ? $fk_fournprice : 'null');
973  $sql .= ", ".($pa_ht ? price2num($pa_ht) : 0);
974  $sql .= ", ".$info_bits;
975  $sql .= ", ".$rang;
976  $sql .= ", ".$special_code;
977  $sql .= ", ".($fk_unit ? "'".$this->db->escape($fk_unit)."'" : "null");
978  $sql .= ", ".(int) $this->fk_multicurrency;
979  $sql .= ", '".$this->db->escape($this->multicurrency_code)."'";
980  $sql .= ", ".price2num($pu_ht_devise);
981  $sql .= ", ".price2num($multicurrency_total_ht);
982  $sql .= ", ".price2num($multicurrency_total_tva);
983  $sql .= ", ".price2num($multicurrency_total_ttc);
984  $sql .= ")";
985 
986  dol_syslog(get_class($this)."::addline", LOG_DEBUG);
987  if ($this->db->query($sql))
988  {
989  $lineId = $this->db->last_insert_id(MAIN_DB_PREFIX."facturedet_rec");
990  $this->id = $facid;
991  $this->update_price();
992  return $lineId;
993  } else {
994  $this->error = $this->db->lasterror();
995  return -1;
996  }
997  }
998  }
999 
1029  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)
1030  {
1031  global $mysoc;
1032 
1033  $facid = $this->id;
1034 
1035  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);
1036  include_once DOL_DOCUMENT_ROOT.'/core/lib/price.lib.php';
1037 
1038  // Clean parameters
1039  if (empty($remise_percent)) $remise_percent = 0;
1040 
1041  // Check parameters
1042  if ($type < 0) return -1;
1043 
1044  if ($this->brouillon)
1045  {
1046  // Clean parameters
1047  $remise_percent = price2num($remise_percent);
1048  $qty = price2num($qty);
1049  if (empty($info_bits)) $info_bits = 0;
1050  $pu_ht = price2num($pu_ht);
1051  $pu_ttc = price2num($pu_ttc);
1052  $pu_ht_devise = price2num($pu_ht_devise);
1053  if (!preg_match('/\((.*)\)/', $txtva)) {
1054  $txtva = price2num($txtva); // $txtva can have format '5.0(XXX)' or '5'
1055  }
1056  $txlocaltax1 = price2num($txlocaltax1);
1057  $txlocaltax2 = price2num($txlocaltax2);
1058  if (empty($txlocaltax1)) $txlocaltax1 = 0;
1059  if (empty($txlocaltax2)) $txlocaltax2 = 0;
1060 
1061  if (empty($this->multicurrency_subprice)) $this->multicurrency_subprice = 0;
1062  if (empty($this->multicurrency_total_ht)) $this->multicurrency_total_ht = 0;
1063  if (empty($this->multicurrency_total_tva)) $this->multicurrency_total_tva = 0;
1064  if (empty($this->multicurrency_total_ttc)) $this->multicurrency_total_ttc = 0;
1065 
1066  if ($price_base_type == 'HT')
1067  {
1068  $pu = $pu_ht;
1069  } else {
1070  $pu = $pu_ttc;
1071  }
1072 
1073  // Calculate total with, without tax and tax from qty, pu, remise_percent and txtva
1074  // TRES IMPORTANT: C'est au moment de l'insertion ligne qu'on doit stocker
1075  // la part ht, tva et ttc, et ce au niveau de la ligne qui a son propre taux tva.
1076 
1077  $localtaxes_type = getLocalTaxesFromRate($txtva, 0, $this->thirdparty, $mysoc);
1078 
1079  // Clean vat code
1080  $vat_src_code = '';
1081  $reg = array();
1082  if (preg_match('/\((.*)\)/', $txtva, $reg))
1083  {
1084  $vat_src_code = $reg[1];
1085  $txtva = preg_replace('/\s*\(.*\)/', '', $txtva); // Remove code into vatrate.
1086  }
1087 
1088  $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);
1089 
1090  $total_ht = $tabprice[0];
1091  $total_tva = $tabprice[1];
1092  $total_ttc = $tabprice[2];
1093  $total_localtax1 = $tabprice[9];
1094  $total_localtax2 = $tabprice[10];
1095  $pu_ht = $tabprice[3];
1096  $pu_tva = $tabprice[4];
1097  $pu_ttc = $tabprice[5];
1098 
1099  // MultiCurrency
1100  $multicurrency_total_ht = $tabprice[16];
1101  $multicurrency_total_tva = $tabprice[17];
1102  $multicurrency_total_ttc = $tabprice[18];
1103  $pu_ht_devise = $tabprice[19];
1104 
1105  $product_type = $type;
1106  if ($fk_product)
1107  {
1108  $product = new Product($this->db);
1109  $result = $product->fetch($fk_product);
1110  $product_type = $product->type;
1111  }
1112 
1113  $sql = "UPDATE ".MAIN_DB_PREFIX."facturedet_rec SET ";
1114  $sql .= "fk_facture = ".((int) $facid);
1115  $sql .= ", label=".(!empty($label) ? "'".$this->db->escape($label)."'" : "null");
1116  $sql .= ", description='".$this->db->escape($desc)."'";
1117  $sql .= ", price=".price2num($pu_ht);
1118  $sql .= ", qty=".price2num($qty);
1119  $sql .= ", tva_tx=".price2num($txtva);
1120  $sql .= ", vat_src_code='".$this->db->escape($vat_src_code)."'";
1121  $sql .= ", localtax1_tx=".$txlocaltax1;
1122  $sql .= ", localtax1_type='".$this->db->escape($localtaxes_type[0])."'";
1123  $sql .= ", localtax2_tx=".$txlocaltax2;
1124  $sql .= ", localtax2_type='".$this->db->escape($localtaxes_type[2])."'";
1125  $sql .= ", fk_product=".(!empty($fk_product) ? "'".$this->db->escape($fk_product)."'" : "null");
1126  $sql .= ", product_type=".$product_type;
1127  $sql .= ", remise_percent='".price2num($remise_percent)."'";
1128  $sql .= ", subprice='".price2num($pu_ht)."'";
1129  $sql .= ", total_ht='".price2num($total_ht)."'";
1130  $sql .= ", total_tva='".price2num($total_tva)."'";
1131  $sql .= ", total_localtax1='".price2num($total_localtax1)."'";
1132  $sql .= ", total_localtax2='".price2num($total_localtax2)."'";
1133  $sql .= ", total_ttc='".price2num($total_ttc)."'";
1134  $sql .= ", date_start_fill=".((int) $date_start_fill);
1135  $sql .= ", date_end_fill=".((int) $date_end_fill);
1136  $sql .= ", fk_product_fournisseur_price=".($fk_fournprice > 0 ? $fk_fournprice : 'null');
1137  $sql .= ", buy_price_ht=".($pa_ht ? price2num($pa_ht) : 0);
1138  $sql .= ", info_bits=".$info_bits;
1139  $sql .= ", rang=".$rang;
1140  $sql .= ", special_code=".$special_code;
1141  $sql .= ", fk_unit=".($fk_unit ? "'".$this->db->escape($fk_unit)."'" : "null");
1142  $sql .= ', multicurrency_subprice = '.$pu_ht_devise;
1143  $sql .= ', multicurrency_total_ht = '.$multicurrency_total_ht;
1144  $sql .= ', multicurrency_total_tva = '.$multicurrency_total_tva;
1145  $sql .= ', multicurrency_total_ttc = '.$multicurrency_total_ttc;
1146  $sql .= " WHERE rowid = ".$rowid;
1147 
1148  dol_syslog(get_class($this)."::updateline", LOG_DEBUG);
1149  if ($this->db->query($sql))
1150  {
1151  $this->id = $facid;
1152  $this->update_price();
1153  return 1;
1154  } else {
1155  $this->error = $this->db->lasterror();
1156  return -1;
1157  }
1158  }
1159  }
1160 
1161 
1167  public function getNextDate()
1168  {
1169  if (empty($this->date_when)) return false;
1170  return dol_time_plus_duree($this->date_when, $this->frequency, $this->unit_frequency);
1171  }
1172 
1178  public function isMaxNbGenReached()
1179  {
1180  $ret = false;
1181  if ($this->nb_gen_max > 0 && ($this->nb_gen_done >= $this->nb_gen_max)) $ret = true;
1182  return $ret;
1183  }
1184 
1191  public function strikeIfMaxNbGenReached($ret)
1192  {
1193  // Special case to strike the date
1194  return ($this->isMaxNbGenReached() ? '<strike>' : '').$ret.($this->isMaxNbGenReached() ? '</strike>' : '');
1195  }
1196 
1207  public function createRecurringInvoices($restrictioninvoiceid = 0, $forcevalidation = 0)
1208  {
1209  global $conf, $langs, $db, $user, $hookmanager;
1210 
1211  $error = 0;
1212  $nb_create = 0;
1213 
1214  // Load translation files required by the page
1215  $langs->loadLangs(array("main", "bills"));
1216 
1217  $now = dol_now();
1218  $tmparray = dol_getdate($now);
1219  $today = dol_mktime(23, 59, 59, $tmparray['mon'], $tmparray['mday'], $tmparray['year']); // Today is last second of current day
1220 
1221  dol_syslog("createRecurringInvoices restrictioninvoiceid=".$restrictioninvoiceid." forcevalidation=".$forcevalidation);
1222 
1223  $sql = 'SELECT rowid FROM '.MAIN_DB_PREFIX.'facture_rec';
1224  $sql .= ' WHERE frequency > 0'; // A recurring invoice is an invoice with a frequency
1225  $sql .= " AND (date_when IS NULL OR date_when <= '".$this->db->idate($today)."')";
1226  $sql .= ' AND (nb_gen_done < nb_gen_max OR nb_gen_max = 0)';
1227  $sql .= ' AND suspended = 0';
1228  $sql .= ' AND entity = '.$conf->entity; // MUST STAY = $conf->entity here
1229  if ($restrictioninvoiceid > 0)
1230  $sql .= ' AND rowid = '.$restrictioninvoiceid;
1231  $sql .= $this->db->order('entity', 'ASC');
1232  //print $sql;exit;
1233  $parameters = array(
1234  'restrictioninvoiceid' => $restrictioninvoiceid,
1235  'forcevalidation' => $forcevalidation,
1236  );
1237  $reshook = $hookmanager->executeHooks('beforeCreationOfRecurringInvoices', $parameters, $sql); // note that $sql might be modified by hooks
1238 
1239  $resql = $this->db->query($sql);
1240  if ($resql)
1241  {
1242  $i = 0;
1243  $num = $this->db->num_rows($resql);
1244 
1245  if ($num)
1246  $this->output .= $langs->trans("FoundXQualifiedRecurringInvoiceTemplate", $num)."\n";
1247  else $this->output .= $langs->trans("NoQualifiedRecurringInvoiceTemplateFound");
1248 
1249  $saventity = $conf->entity;
1250 
1251  while ($i < $num) // Loop on each template invoice. If $num = 0, test is false at first pass.
1252  {
1253  $line = $this->db->fetch_object($resql);
1254 
1255  $this->db->begin();
1256 
1257  $invoiceidgenerated = 0;
1258 
1259  $facture = null;
1260  $facturerec = new FactureRec($this->db);
1261  $facturerec->fetch($line->rowid);
1262 
1263  if ($facturerec->id > 0)
1264  {
1265  // Set entity context
1266  $conf->entity = $facturerec->entity;
1267 
1268  dol_syslog("createRecurringInvoices Process invoice template id=".$facturerec->id.", ref=".$facturerec->ref.", entity=".$facturerec->entity);
1269 
1270  $facture = new Facture($this->db);
1271  $facture->fac_rec = $facturerec->id; // We will create $facture from this recurring invoice
1272  $facture->fk_fac_rec_source = $facturerec->id; // We will create $facture from this recurring invoice
1273 
1274  $facture->type = self::TYPE_STANDARD;
1275  $facture->brouillon = 1;
1276  $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.
1277  $facture->socid = $facturerec->socid;
1278 
1279  $invoiceidgenerated = $facture->create($user);
1280  if ($invoiceidgenerated <= 0)
1281  {
1282  $this->errors = $facture->errors;
1283  $this->error = $facture->error;
1284  $error++;
1285  }
1286  if (!$error && ($facturerec->auto_validate || $forcevalidation))
1287  {
1288  $result = $facture->validate($user);
1289  if ($result <= 0)
1290  {
1291  $this->errors = $facture->errors;
1292  $this->error = $facture->error;
1293  $error++;
1294  }
1295  }
1296  if (!$error && $facturerec->generate_pdf)
1297  {
1298  // We refresh the object in order to have all necessary data (like date_lim_reglement)
1299  $facture->fetch($facture->id);
1300  $result = $facture->generateDocument($facturerec->modelpdf, $langs);
1301  if ($result <= 0)
1302  {
1303  $this->errors = $facture->errors;
1304  $this->error = $facture->error;
1305  $error++;
1306  }
1307  }
1308  } else {
1309  $error++;
1310  $this->error = "Failed to load invoice template with id=".$line->rowid.", entity=".$conf->entity."\n";
1311  $this->errors[] = "Failed to load invoice template with id=".$line->rowid.", entity=".$conf->entity;
1312  dol_syslog("createRecurringInvoices Failed to load invoice template with id=".$line->rowid.", entity=".$conf->entity);
1313  }
1314 
1315  if (!$error && $invoiceidgenerated >= 0)
1316  {
1317  $this->db->commit("createRecurringInvoices Process invoice template id=".$facturerec->id.", ref=".$facturerec->ref);
1318  dol_syslog("createRecurringInvoices Process invoice template ".$facturerec->ref." is finished with a success generation");
1319  $nb_create++;
1320  $this->output .= $langs->trans("InvoiceGeneratedFromTemplate", $facture->ref, $facturerec->ref)."\n";
1321  } else {
1322  $this->db->rollback("createRecurringInvoices Process invoice template id=".$facturerec->id.", ref=".$facturerec->ref);
1323  }
1324 
1325  $parameters = array(
1326  'cpt' => $i,
1327  'total' => $num,
1328  'errorCount' => $error,
1329  'invoiceidgenerated' => $invoiceidgenerated,
1330  'facturerec' => $facturerec, // it's an object which PHP passes by "reference", so modifiable by hooks.
1331  'this' => $this, // it's an object which PHP passes by "reference", so modifiable by hooks.
1332  );
1333  $reshook = $hookmanager->executeHooks('afterCreationOfRecurringInvoice', $parameters, $facture); // note: $facture can be modified by hooks (warning: $facture can be null)
1334 
1335  $i++;
1336  }
1337 
1338  $conf->entity = $saventity; // Restore entity context
1339  } else dol_print_error($this->db);
1340 
1341  $this->output = trim($this->output);
1342 
1343  return $error ? $error : 0;
1344  }
1345 
1358  public function getNomUrl($withpicto = 0, $option = '', $max = 0, $short = 0, $moretitle = '', $notooltip = '', $save_lastsearch_value = -1)
1359  {
1360  global $langs;
1361 
1362  $result = '';
1363 
1364  $label = '<u>'.$langs->trans("RepeatableInvoice").'</u>';
1365  if (!empty($this->ref)) {
1366  $label .= '<br><b>'.$langs->trans('Ref').':</b> '.$this->ref;
1367  }
1368  if ($this->frequency > 0) {
1369  $label .= '<br><b>'.$langs->trans('Frequency').':</b> '.$langs->trans('FrequencyPer_'.$this->unit_frequency, $this->frequency);
1370  }
1371  if (!empty($this->date_last_gen)) {
1372  $label .= '<br><b>'.$langs->trans('DateLastGeneration').':</b> '.dol_print_date($this->date_last_gen, 'dayhour');
1373  }
1374  if ($this->frequency > 0) {
1375  if (!empty($this->date_when)) {
1376  $label .= '<br><b>'.$langs->trans('NextDateToExecution').':</b> ';
1377  $label .= (empty($this->suspended) ? '' : '<strike>').dol_print_date($this->date_when, 'day').(empty($this->suspended) ? '' : '</strike>'); // No hour for this property
1378  if (!empty($this->suspended)) $label .= ' ('.$langs->trans("Disabled").')';
1379  }
1380  }
1381 
1382  $url = DOL_URL_ROOT.'/compta/facture/card-rec.php?facid='.$this->id;
1383 
1384  if ($short) return $url;
1385 
1386  if ($option != 'nolink')
1387  {
1388  // Add param to save lastsearch_values or not
1389  $add_save_lastsearch_values = ($save_lastsearch_value == 1 ? 1 : 0);
1390  if ($save_lastsearch_value == -1 && preg_match('/list\.php/', $_SERVER["PHP_SELF"])) $add_save_lastsearch_values = 1;
1391  if ($add_save_lastsearch_values) $url .= '&save_lastsearch_values=1';
1392  }
1393 
1394  $linkstart = '<a href="'.$url.'" title="'.dol_escape_htmltag($label, 1).'" class="classfortooltip">';
1395  $linkend = '</a>';
1396 
1397  $result .= $linkstart;
1398  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);
1399  if ($withpicto != 2) $result .= $this->ref;
1400  $result .= $linkend;
1401 
1402  return $result;
1403  }
1404 
1412  public function getLibStatut($mode = 0, $alreadypaid = -1)
1413  {
1414  return $this->LibStatut($this->frequency ? 1 : 0, $this->suspended, $mode, $alreadypaid, empty($this->type) ? 0 : $this->type);
1415  }
1416 
1417  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1428  public function LibStatut($recur, $status, $mode = 0, $alreadypaid = -1, $type = 0)
1429  {
1430  // phpcs:enable
1431  global $langs;
1432  $langs->load('bills');
1433 
1434  $labelStatus = $langs->trans('Active');
1435  $statusType = 'status0';
1436 
1437  //print "$recur,$status,$mode,$alreadypaid,$type";
1438  if ($mode == 0)
1439  {
1440  $prefix = '';
1441  if ($recur)
1442  {
1443  if ($status == self::STATUS_SUSPENDED) {
1444  $labelStatus = $langs->trans('Disabled');
1445  } else {
1446  $labelStatus = $langs->trans('Active');
1447  }
1448  } else {
1449  if ($status == self::STATUS_SUSPENDED) {
1450  $labelStatus = $langs->trans('Disabled');
1451  } else {
1452  $labelStatus = $langs->trans("Draft");
1453  }
1454  }
1455  } elseif ($mode == 1)
1456  {
1457  $prefix = 'Short';
1458  if ($recur)
1459  {
1460  if ($status == self::STATUS_SUSPENDED) {
1461  $labelStatus = $langs->trans('Disabled');
1462  } else {
1463  $labelStatus = $langs->trans('Active');
1464  }
1465  } else {
1466  if ($status == self::STATUS_SUSPENDED) {
1467  $labelStatus = $langs->trans('Disabled');
1468  } else {
1469  $labelStatus = $langs->trans("Draft");
1470  }
1471  }
1472  } elseif ($mode == 2)
1473  {
1474  if ($recur)
1475  {
1476  if ($status == self::STATUS_SUSPENDED) {
1477  $statusType = 'status6';
1478  $labelStatus = $langs->trans('Disabled');
1479  } else {
1480  $statusType = 'status4';
1481  $labelStatus = $langs->trans('Active');
1482  }
1483  } else {
1484  if ($status == self::STATUS_SUSPENDED) {
1485  $statusType = 'status6';
1486  $labelStatus = $langs->trans('Disabled');
1487  } else {
1488  $statusType = 'status0';
1489  $labelStatus = $langs->trans('Draft');
1490  }
1491  }
1492  } elseif ($mode == 3)
1493  {
1494  if ($recur)
1495  {
1496  $prefix = 'Short';
1497  if ($status == self::STATUS_SUSPENDED) {
1498  $statusType = 'status6';
1499  $labelStatus = $langs->trans('Disabled');
1500  } else {
1501  $statusType = 'status4';
1502  $labelStatus = $langs->trans('Active');
1503  }
1504  } else {
1505  if ($status == self::STATUS_SUSPENDED) {
1506  $statusType = 'status6';
1507  $labelStatus = $langs->trans('Disabled');
1508  } else {
1509  $statusType = 'status0';
1510  $labelStatus = $langs->trans('Draft');
1511  }
1512  }
1513  } elseif ($mode == 4)
1514  {
1515  $prefix = '';
1516  if ($recur)
1517  {
1518  if ($status == self::STATUS_SUSPENDED) {
1519  $statusType = 'status6';
1520  $labelStatus = $langs->trans('Disabled');
1521  } else {
1522  $statusType = 'status4';
1523  $labelStatus = $langs->trans('Active');
1524  }
1525  } else {
1526  if ($status == self::STATUS_SUSPENDED) {
1527  $statusType = 'status6';
1528  $labelStatus = $langs->trans('Disabled');
1529  } else {
1530  $statusType = 'status0';
1531  $labelStatus = $langs->trans('Draft');
1532  }
1533  }
1534  } elseif ($mode == 5 || $mode == 6)
1535  {
1536  $prefix = '';
1537  if ($mode == 5) $prefix = 'Short';
1538  if ($recur)
1539  {
1540  if ($status == self::STATUS_SUSPENDED) {
1541  $statusType = 'status6';
1542  $labelStatus = $langs->trans('Disabled');
1543  } else {
1544  $statusType = 'status4';
1545  $labelStatus = $langs->trans('Active');
1546  }
1547  } else {
1548  if ($status == self::STATUS_SUSPENDED) {
1549  $statusType = 'status6';
1550  $labelStatus = $langs->trans('Disabled');
1551  } else {
1552  $statusType = 'status0';
1553  $labelStatus = $langs->trans('Draft');
1554  }
1555  }
1556  }
1557 
1558  if (empty($labelStatusShort)) $labelStatusShort = $labelStatus;
1559 
1560  return dolGetStatus($labelStatus, $labelStatusShort, '', $statusType, $mode);
1561  }
1562 
1571  public function initAsSpecimen($option = '')
1572  {
1573  global $user, $langs, $conf;
1574 
1575  $now = dol_now();
1576  $arraynow = dol_getdate($now);
1577  $nownotime = dol_mktime(0, 0, 0, $arraynow['mon'], $arraynow['mday'], $arraynow['year']);
1578 
1579  // Load array of products prodids
1580  $num_prods = 0;
1581  $prodids = array();
1582 
1583  $sql = "SELECT rowid";
1584  $sql .= " FROM ".MAIN_DB_PREFIX."product";
1585  $sql .= " WHERE entity IN (".getEntity('product').")";
1586  $sql .= $this->db->plimit(100);
1587 
1588  $resql = $this->db->query($sql);
1589  if ($resql)
1590  {
1591  $num_prods = $this->db->num_rows($resql);
1592  $i = 0;
1593  while ($i < $num_prods)
1594  {
1595  $i++;
1596  $row = $this->db->fetch_row($resql);
1597  $prodids[$i] = $row[0];
1598  }
1599  }
1600 
1601  // Initialize parameters
1602  $this->id = 0;
1603  $this->ref = 'SPECIMEN';
1604  $this->specimen = 1;
1605  $this->socid = 1;
1606  $this->date = $nownotime;
1607  $this->date_lim_reglement = $nownotime + 3600 * 24 * 30;
1608  $this->cond_reglement_id = 1;
1609  $this->cond_reglement_code = 'RECEP';
1610  $this->date_lim_reglement = $this->calculate_date_lim_reglement();
1611  $this->mode_reglement_id = 0; // Not forced to show payment mode CHQ + VIR
1612  $this->mode_reglement_code = ''; // Not forced to show payment mode CHQ + VIR
1613  $this->note_public = 'This is a comment (public)';
1614  $this->note_private = 'This is a comment (private)';
1615  $this->note = 'This is a comment (private)';
1616  $this->fk_incoterms = 0;
1617  $this->location_incoterms = '';
1618 
1619  if (empty($option) || $option != 'nolines')
1620  {
1621  // Lines
1622  $nbp = 5;
1623  $xnbp = 0;
1624  while ($xnbp < $nbp)
1625  {
1626  $line = new FactureLigne($this->db);
1627  $line->desc = $langs->trans("Description")." ".$xnbp;
1628  $line->qty = 1;
1629  $line->subprice = 100;
1630  $line->tva_tx = 19.6;
1631  $line->localtax1_tx = 0;
1632  $line->localtax2_tx = 0;
1633  $line->remise_percent = 0;
1634  if ($xnbp == 1) // Qty is negative (product line)
1635  {
1636  $prodid = mt_rand(1, $num_prods);
1637  $line->fk_product = $prodids[$prodid];
1638  $line->qty = -1;
1639  $line->total_ht = -100;
1640  $line->total_ttc = -119.6;
1641  $line->total_tva = -19.6;
1642  } elseif ($xnbp == 2) // UP is negative (free line)
1643  {
1644  $line->subprice = -100;
1645  $line->total_ht = -100;
1646  $line->total_ttc = -119.6;
1647  $line->total_tva = -19.6;
1648  $line->remise_percent = 0;
1649  } elseif ($xnbp == 3) // Discount is 50% (product line)
1650  {
1651  $prodid = mt_rand(1, $num_prods);
1652  $line->fk_product = $prodids[$prodid];
1653  $line->total_ht = 50;
1654  $line->total_ttc = 59.8;
1655  $line->total_tva = 9.8;
1656  $line->remise_percent = 50;
1657  } else // (product line)
1658  {
1659  $prodid = mt_rand(1, $num_prods);
1660  $line->fk_product = $prodids[$prodid];
1661  $line->total_ht = 100;
1662  $line->total_ttc = 119.6;
1663  $line->total_tva = 19.6;
1664  $line->remise_percent = 00;
1665  }
1666 
1667  $this->lines[$xnbp] = $line;
1668  $xnbp++;
1669 
1670  $this->total_ht += $line->total_ht;
1671  $this->total_tva += $line->total_tva;
1672  $this->total_ttc += $line->total_ttc;
1673  }
1674  $this->revenuestamp = 0;
1675 
1676  // Add a line "offered"
1677  $line = new FactureLigne($this->db);
1678  $line->desc = $langs->trans("Description")." (offered line)";
1679  $line->qty = 1;
1680  $line->subprice = 100;
1681  $line->tva_tx = 19.6;
1682  $line->localtax1_tx = 0;
1683  $line->localtax2_tx = 0;
1684  $line->remise_percent = 100;
1685  $line->total_ht = 0;
1686  $line->total_ttc = 0; // 90 * 1.196
1687  $line->total_tva = 0;
1688  $prodid = mt_rand(1, $num_prods);
1689  $line->fk_product = $prodids[$prodid];
1690 
1691  $this->lines[$xnbp] = $line;
1692  $xnbp++;
1693  }
1694 
1695  $this->usenewprice = 0;
1696  }
1697 
1706  public static function replaceThirdparty(DoliDB $db, $origin_id, $dest_id)
1707  {
1708  $tables = array(
1709  'facture_rec'
1710  );
1711 
1712  return CommonObject::commonReplaceThirdparty($db, $origin_id, $dest_id, $tables);
1713  }
1714 
1722  public function setFrequencyAndUnit($frequency, $unit)
1723  {
1724  if (!$this->table_element) {
1725  dol_syslog(get_class($this)."::setFrequencyAndUnit was called on objet with property table_element not defined", LOG_ERR);
1726  return -1;
1727  }
1728 
1729  if (!empty($frequency) && empty($unit)) {
1730  dol_syslog(get_class($this)."::setFrequencyAndUnit was called on objet with params frequency defined but unit not defined", LOG_ERR);
1731  return -2;
1732  }
1733 
1734  $sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element;
1735  $sql .= ' SET frequency = '.($frequency ? $this->db->escape($frequency) : 'null');
1736  if (!empty($unit)) {
1737  $sql .= ', unit_frequency = \''.$this->db->escape($unit).'\'';
1738  }
1739  $sql .= ' WHERE rowid = '.$this->id;
1740 
1741  dol_syslog(get_class($this)."::setFrequencyAndUnit", LOG_DEBUG);
1742  if ($this->db->query($sql)) {
1743  $this->frequency = $frequency;
1744  if (!empty($unit)) $this->unit_frequency = $unit;
1745  return 1;
1746  } else {
1747  dol_print_error($this->db);
1748  return -1;
1749  }
1750  }
1751 
1759  public function setNextDate($date, $increment_nb_gen_done = 0)
1760  {
1761  if (!$this->table_element)
1762  {
1763  dol_syslog(get_class($this)."::setNextDate was called on objet with property table_element not defined", LOG_ERR);
1764  return -1;
1765  }
1766  $sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element;
1767  $sql .= " SET date_when = ".($date ? "'".$this->db->idate($date)."'" : "null");
1768  if ($increment_nb_gen_done > 0) $sql .= ', nb_gen_done = nb_gen_done + 1';
1769  $sql .= ' WHERE rowid = '.$this->id;
1770 
1771  dol_syslog(get_class($this)."::setNextDate", LOG_DEBUG);
1772  if ($this->db->query($sql))
1773  {
1774  $this->date_when = $date;
1775  if ($increment_nb_gen_done > 0) $this->nb_gen_done++;
1776  return 1;
1777  } else {
1778  dol_print_error($this->db);
1779  return -1;
1780  }
1781  }
1782 
1789  public function setMaxPeriod($nb)
1790  {
1791  if (!$this->table_element)
1792  {
1793  dol_syslog(get_class($this)."::setMaxPeriod was called on objet with property table_element not defined", LOG_ERR);
1794  return -1;
1795  }
1796 
1797  if (empty($nb)) $nb = 0;
1798 
1799  $sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element;
1800  $sql .= ' SET nb_gen_max = '.$nb;
1801  $sql .= ' WHERE rowid = '.$this->id;
1802 
1803  dol_syslog(get_class($this)."::setMaxPeriod", LOG_DEBUG);
1804  if ($this->db->query($sql))
1805  {
1806  $this->nb_gen_max = $nb;
1807  return 1;
1808  } else {
1809  dol_print_error($this->db);
1810  return -1;
1811  }
1812  }
1813 
1820  public function setAutoValidate($validate)
1821  {
1822  if (!$this->table_element)
1823  {
1824  dol_syslog(get_class($this)."::setAutoValidate was called on objet with property table_element not defined", LOG_ERR);
1825  return -1;
1826  }
1827 
1828  $sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element;
1829  $sql .= ' SET auto_validate = '.$validate;
1830  $sql .= ' WHERE rowid = '.$this->id;
1831 
1832  dol_syslog(get_class($this)."::setAutoValidate", LOG_DEBUG);
1833  if ($this->db->query($sql))
1834  {
1835  $this->auto_validate = $validate;
1836  return 1;
1837  } else {
1838  dol_print_error($this->db);
1839  return -1;
1840  }
1841  }
1842 
1849  public function setGeneratePdf($validate)
1850  {
1851  if (!$this->table_element)
1852  {
1853  dol_syslog(get_class($this)."::setGeneratePdf was called on objet with property table_element not defined", LOG_ERR);
1854  return -1;
1855  }
1856 
1857  $sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element;
1858  $sql .= ' SET generate_pdf = '.$validate;
1859  $sql .= ' WHERE rowid = '.$this->id;
1860 
1861  dol_syslog(get_class($this)."::setGeneratePdf", LOG_DEBUG);
1862  if ($this->db->query($sql))
1863  {
1864  $this->generate_pdf = $validate;
1865  return 1;
1866  } else {
1867  dol_print_error($this->db);
1868  return -1;
1869  }
1870  }
1871 
1878  public function setModelPdf($model)
1879  {
1880  if (!$this->table_element)
1881  {
1882  dol_syslog(get_class($this)."::setModelPdf was called on objet with property table_element not defined", LOG_ERR);
1883  return -1;
1884  }
1885 
1886  $sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element;
1887  $sql .= ' SET modelpdf = "'.$model.'"';
1888  $sql .= ' WHERE rowid = '.$this->id;
1889 
1890  dol_syslog(get_class($this)."::setModelPdf", LOG_DEBUG);
1891  if ($this->db->query($sql))
1892  {
1893  $this->modelpdf = $model;
1894  return 1;
1895  } else {
1896  dol_print_error($this->db);
1897  return -1;
1898  }
1899  }
1900 }
1901 
1902 
1903 
1909 {
1913  public $element = 'facturedetrec';
1914 
1918  public $table_element = 'facturedet_rec';
1919 
1920 
1921 
1929  public function delete(User $user, $notrigger = false)
1930  {
1931  $error = 0;
1932 
1933  $this->db->begin();
1934 
1935  if (!$error) {
1936  if (!$notrigger) {
1937  // Call triggers
1938  $result = $this->call_trigger('LINEBILLREC_DELETE', $user);
1939  if ($result < 0) { $error++; } // Do also here what you must do to rollback action if trigger fail
1940  // End call triggers
1941  }
1942  }
1943 
1944  if (!$error)
1945  {
1946  $result = $this->deleteExtraFields();
1947  if ($result < 0) {
1948  $error++;
1949  }
1950  }
1951 
1952  if (!$error)
1953  {
1954  $sql = 'DELETE FROM '.MAIN_DB_PREFIX.$this->table_element.' WHERE rowid='.$this->id;
1955 
1956  $res = $this->db->query($sql);
1957  if ($res === false) {
1958  $error++;
1959  $this->errors[] = $this->db->lasterror();
1960  }
1961  }
1962 
1963  // Commit or rollback
1964  if ($error) {
1965  $this->db->rollback();
1966  return -1;
1967  } else {
1968  $this->db->commit();
1969  return 1;
1970  }
1971  }
1972 
1973 
1980  public function fetch($rowid)
1981  {
1982  $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,';
1983  $sql .= ' l.localtax1_tx, l.localtax2_tx, l.localtax1_type, l.localtax2_type, l.remise, l.remise_percent, l.subprice,';
1984  $sql .= ' l.date_start_fill, l.date_end_fill, l.info_bits, l.total_ht, l.total_tva, l.total_ttc,';
1985  $sql .= ' l.rang, l.special_code,';
1986  $sql .= ' l.fk_unit, l.fk_contract_line,';
1987  $sql .= ' l.import_key, l.fk_multicurrency,';
1988  $sql .= ' l.multicurrency_code, l.multicurrency_subprice, l.multicurrency_total_ht, l.multicurrency_total_tva, l.multicurrency_total_ttc,';
1989  $sql .= ' l.buy_price_ht, l.fk_product_fournisseur_price,';
1990  $sql .= ' l.fk_user_author, l.fk_user_modif,';
1991  $sql .= ' p.ref as product_ref, p.fk_product_type as fk_product_type, p.label as product_label, p.description as product_desc';
1992  $sql .= ' FROM '.MAIN_DB_PREFIX.'facturedet_rec as l';
1993  $sql .= ' LEFT JOIN '.MAIN_DB_PREFIX.'product as p ON l.fk_product = p.rowid';
1994  $sql .= ' WHERE l.rowid = '.$rowid;
1995  $sql .= ' ORDER BY l.rang';
1996 
1997  dol_syslog('FactureRec::fetch', LOG_DEBUG);
1998  $result = $this->db->query($sql);
1999  if ($result)
2000  {
2001  $objp = $this->db->fetch_object($result);
2002 
2003  $this->id = $objp->rowid;
2004  $this->label = $objp->custom_label; // Label line
2005  $this->desc = $objp->description; // Description line
2006  $this->description = $objp->description; // Description line
2007  $this->product_type = $objp->product_type; // Type of line
2008  $this->ref = $objp->product_ref; // Ref product
2009  $this->product_ref = $objp->product_ref; // Ref product
2010  $this->libelle = $objp->product_label; // deprecated
2011  $this->product_label = $objp->product_label; // Label product
2012  $this->product_desc = $objp->product_desc; // Description product
2013  $this->fk_product_type = $objp->fk_product_type; // Type of product
2014  $this->qty = $objp->qty;
2015  $this->price = $objp->price;
2016  $this->subprice = $objp->subprice;
2017  $this->fk_facture = $objp->fk_facture;
2018  $this->vat_src_code = $objp->vat_src_code;
2019  $this->tva_tx = $objp->tva_tx;
2020  $this->localtax1_tx = $objp->localtax1_tx;
2021  $this->localtax2_tx = $objp->localtax2_tx;
2022  $this->localtax1_type = $objp->localtax1_type;
2023  $this->localtax2_type = $objp->localtax2_type;
2024  $this->remise_percent = $objp->remise_percent;
2025  //$this->fk_remise_except = $objp->fk_remise_except;
2026  $this->fk_product = $objp->fk_product;
2027  $this->date_start_fill = $objp->date_start_fill;
2028  $this->date_end_fill = $objp->date_end_fill;
2029  $this->info_bits = $objp->info_bits;
2030  $this->total_ht = $objp->total_ht;
2031  $this->total_tva = $objp->total_tva;
2032  $this->total_ttc = $objp->total_ttc;
2033  //$this->code_ventilation = $objp->fk_code_ventilation;
2034  $this->rang = $objp->rang;
2035  $this->special_code = $objp->special_code;
2036  $this->fk_unit = $objp->fk_unit;
2037  $this->fk_contract_line = $objp->fk_contract_line;
2038  $this->import_key = $objp->import_key;
2039  $this->fk_multicurrency = $objp->fk_multicurrency;
2040  $this->multicurrency_code = $objp->multicurrency_code;
2041  $this->multicurrency_subprice = $objp->multicurrency_subprice;
2042  $this->multicurrency_total_ht = $objp->multicurrency_total_ht;
2043  $this->multicurrency_total_tva = $objp->multicurrency_total_tva;
2044  $this->multicurrency_total_ttc = $objp->multicurrency_total_ttc;
2045  $this->buy_price_ht = $objp->buy_price_ht;
2046  $this->fk_product_fournisseur_price = $objp->fk_product_fournisseur_price;
2047  $this->fk_user_author = $objp->fk_user_author;
2048  $this->fk_user_modif = $objp->fk_user_modif;
2049 
2050  $this->db->free($result);
2051  return 1;
2052  } else {
2053  $this->error = $this->db->lasterror();
2054  return -3;
2055  }
2056  }
2057 
2058 
2066  public function update(User $user, $notrigger = 0)
2067  {
2068  global $conf;
2069 
2070  $error = 0;
2071 
2072  include_once DOL_DOCUMENT_ROOT.'/core/lib/price.lib.php';
2073 
2074  $sql = "UPDATE ".MAIN_DB_PREFIX."facturedet_rec SET";
2075  $sql .= " fk_facture = ".$this->fk_facture;
2076  $sql .= ", label=".(!empty($this->label) ? "'".$this->db->escape($this->label)."'" : "null");
2077  $sql .= ", description='".$this->db->escape($this->desc)."'";
2078  $sql .= ", price=".price2num($this->price);
2079  $sql .= ", qty=".price2num($this->qty);
2080  $sql .= ", tva_tx=".price2num($this->tva_tx);
2081  $sql .= ", vat_src_code='".$this->db->escape($this->vat_src_code)."'";
2082  $sql .= ", localtax1_tx=".price2num($this->localtax1_tx);
2083  $sql .= ", localtax1_type='".$this->db->escape($this->localtax1_type)."'";
2084  $sql .= ", localtax2_tx=".price2num($this->localtax2_tx);
2085  $sql .= ", localtax2_type='".$this->db->escape($this->localtax2_type)."'";
2086  $sql .= ", fk_product=".($this->fk_product > 0 ? $this->fk_product : "null");
2087  $sql .= ", product_type=".$this->product_type;
2088  $sql .= ", remise_percent='".price2num($this->remise_percent)."'";
2089  $sql .= ", subprice='".price2num($this->subprice)."'";
2090  $sql .= ", info_bits='".price2num($this->info_bits)."'";
2091  $sql .= ", date_start_fill=".(int) $this->date_start_fill;
2092  $sql .= ", date_end_fill=".(int) $this->date_end_fill;
2093  if (empty($this->skip_update_total)) {
2094  $sql .= ", total_ht=".price2num($this->total_ht);
2095  $sql .= ", total_tva=".price2num($this->total_tva);
2096  $sql .= ", total_localtax1=".price2num($this->total_localtax1);
2097  $sql .= ", total_localtax2=".price2num($this->total_localtax2);
2098  $sql .= ", total_ttc=".price2num($this->total_ttc);
2099  }
2100  $sql .= ", rang=".$this->rang;
2101  $sql .= ", special_code=".$this->special_code;
2102  $sql .= ", fk_unit=".($this->fk_unit ? "'".$this->db->escape($this->fk_unit)."'" : "null");
2103  $sql .= ", fk_contract_line=".($this->fk_contract_line ? $this->fk_contract_line : "null");
2104  $sql .= " WHERE rowid = ".$this->id;
2105 
2106  $this->db->begin();
2107 
2108  dol_syslog(get_class($this)."::updateline", LOG_DEBUG);
2109  $resql = $this->db->query($sql);
2110  if ($resql)
2111  {
2112  if (!$error)
2113  {
2114  $result = $this->insertExtraFields();
2115  if ($result < 0)
2116  {
2117  $error++;
2118  }
2119  }
2120 
2121  if (!$error && !$notrigger)
2122  {
2123  // Call trigger
2124  $result = $this->call_trigger('LINEBILLREC_UPDATE', $user);
2125  if ($result < 0)
2126  {
2127  $error++;
2128  }
2129  // End call triggers
2130  }
2131 
2132  if ($error) {
2133  $this->db->rollback();
2134  return -2;
2135  } else {
2136  $this->db->commit();
2137  return 1;
2138  }
2139  } else {
2140  $this->error = $this->db->lasterror();
2141  $this->db->rollback();
2142  return -2;
2143  }
2144  }
2145 }
create($user, $facid, $notrigger=0)
Create a predefined invoice.
setNextDate($date, $increment_nb_gen_done=0)
Update the next date of execution.
calculate_date_lim_reglement($cond_reglement=0)
Returns an invoice payment deadline based on the invoice settlement conditions and billing date...
Class to manage invoice lines of templates.
dol_mktime($hour, $minute, $second, $month, $day, $year, $gm= 'auto', $check=1)
Return a timestamp date built from detailed informations (by default a local PHP server timestamp) Re...
if(!empty($arrayfields['u.datec']['checked'])) print_liste_field_titre("DateCreationShort"u if(!empty($arrayfields['u.tms']['checked'])) print_liste_field_titre("DateModificationShort"u if(!empty($arrayfields['u.statut']['checked'])) print_liste_field_titre("Status"u statut
Definition: list.php:632
getMarginInfos($pvht, $remise_percent, $tva_tx, $localtax1_tx, $localtax2_tx, $fk_pa, $paht)
Return an array with margins information of a line.
</td > param sortfield sortorder printFieldListOption< tdclass="liste_titremaxwidthsearchright"></td ></tr >< trclass="liste_titre">< inputtype="checkbox"onClick="toggle(this)"/> Ref p ref Label p label Duration p duration center DesiredStock p desiredstock right StockLimitShort p seuil_stock_alerte right stock_physique right stock_real_warehouse right Ordered right StockToBuy right SupplierRef right param sortfield sortorder printFieldListTitle warehouseinternal SELECT description FROM product_lang WHERE qty< br > qty qty qty StockTooLow StockTooLow help help help< trclass="oddeven">< td >< inputtype="checkbox"class="check"name="choose'.$i.'"></td >< tdclass="nowrap"> stock</td >< td >< inputtype="hidden"name="desc'.$i.'"value="'.dol_escape_htmltag($objp-> description
Only used if Module[ID]Desc translation string is not found.
Definition: replenish.php:750
getNomUrl($withpicto=0, $option= '', $max=0, $short=0, $moretitle= '', $notooltip= '', $save_lastsearch_value=-1)
Return clicable name (with picto eventually)
initAsSpecimen($option= '')
Initialise an instance with random values.
Class to manage products or services.
dol_now($mode= 'auto')
Return date for now.
createRecurringInvoices($restrictioninvoiceid=0, $forcevalidation=0)
Create all recurrents invoices (for all entities if multicompany is used).
Class to manage invoice templates.
calcul_price_total($qty, $pu, $remise_percent_ligne, $txtva, $uselocaltax1_rate, $uselocaltax2_rate, $remise_percent_global, $price_base_type, $info_bits, $type, $seller= '', $localtaxes_array= '', $progress=100, $multicurrency_tx=1, $pu_devise=0, $multicurrency_code= '')
Calculate totals (net, vat, ...) of a line.
Definition: price.lib.php:86
Class to manage Dolibarr users.
Definition: user.class.php:44
Class to manage Dolibarr database access.
setAutoValidate($validate)
Update the auto validate flag of invoice.
setGeneratePdf($validate)
Update the auto generate documents.
getLinesArray()
Create an array of invoice lines.
getNextDate()
Return the next date of.
fetch($rowid, $ref= '', $ref_ext= '')
Load object and lines.
Parent class of all other business classes for details of elements (invoices, contracts, proposals, orders, ...)
$conf db
API class for accounts.
Definition: inc.php:54
price($amount, $form=0, $outlangs= '', $trunc=1, $rounding=-1, $forcerounding=-1, $currency_code= '')
Function to format a value into an amount for visual output Function used into PDF and HTML pages...
insertExtraFields($trigger= '', $userused=null)
Add/Update all extra fields values for the current object.
Class to manage standard extra fields.
__construct($db)
Constructor.
fetch_lines()
Get lines of template invoices into this-&gt;lines.
setMaxPeriod($nb)
Update the maximum period.
price2num($amount, $rounding= '', $option=0)
Function that return a number with universal decimal format (decimal separator is &#39;...
static commonReplaceThirdparty(DoliDB $db, $origin_id, $dest_id, array $tables, $ignoreerrors=0)
Function used to replace a thirdparty id with another one.
dol_syslog($message, $level=LOG_INFO, $ident=0, $suffixinfilename= '', $restricttologhandler= '', $logcontext=null)
Write log message into outputs.
dol_getdate($timestamp, $fast=false, $forcetimezone= '')
Return an array with locale date info.
update(User $user, $notrigger=0)
Update a line to invoice_rec.
img_object($titlealt, $picto, $moreatt= '', $pictoisfullpath=false, $srconly=0, $notitle=0)
Show a picto called object_picto (generic function)
deleteExtraFields()
Delete all extra fields values for the current object.
fetch_optionals($rowid=null, $optionsArray=null)
Function to get extra fields of an object into $this-&gt;array_options This method is in most cases call...
deleteObjectLinked($sourceid=null, $sourcetype= '', $targetid=null, $targettype= '', $rowid= '')
Delete all links between an object $this.
Superclass for invoices classes.
print $_SERVER["PHP_SELF"]
Edit parameters.
strikeIfMaxNbGenReached($ret)
Format string to output with by striking the string if max number of generation was reached...
fetch($rowid)
Get line of template invoice.
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)
Update a line to invoice.
dol_print_date($time, $format= '', $tzoutput= 'auto', $outputlangs= '', $encodetooutput=false)
Output date in a string format according to outputlangs (or langs if not defined).
call_trigger($triggerName, $user)
Call trigger based on this instance.
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)
Add a line to invoice.
setFrequencyAndUnit($frequency, $unit)
Update frequency and unit.
if(!empty($conf->facture->enabled)&&$user->rights->facture->lire) if((!empty($conf->fournisseur->enabled)&&empty($conf->global->MAIN_USE_NEW_SUPPLIERMOD)||!empty($conf->supplier_invoice->enabled))&&$user->rights->fournisseur->facture->lire) if(!empty($conf->don->enabled)&&$user->rights->don->lire) if(!empty($conf->tax->enabled)&&$user->rights->tax->charges->lire) if(!empty($conf->facture->enabled)&&!empty($conf->commande->enabled)&&$user->rights->commande->lire &&empty($conf->global->WORKFLOW_DISABLE_CREATE_INVOICE_FROM_ORDER)) if(!empty($conf->facture->enabled)&&$user->rights->facture->lire) if((!empty($conf->fournisseur->enabled)&&empty($conf->global->MAIN_USE_NEW_SUPPLIERMOD)||!empty($conf->supplier_invoice->enabled))&&$user->rights->fournisseur->facture->lire) $resql
Social contributions to pay.
Definition: index.php:1232
dol_print_error($db= '', $error= '', $errors=null)
Displays error message system with all the information to facilitate the diagnosis and the escalation...
static replaceThirdparty(DoliDB $db, $origin_id, $dest_id)
Function used to replace a thirdparty id with another one.
LibStatut($recur, $status, $mode=0, $alreadypaid=-1, $type=0)
Return label of a status.
setModelPdf($model)
Update the model for documents.
dolGetStatus($statusLabel= '', $statusLabelShort= '', $html= '', $statusType= 'status0', $displayMode=0, $url= '', $params=array())
Output the badge of a status.
isMaxNbGenReached()
Return if maximum number of generation is reached.
Class to manage invoices.
getLocalTaxesFromRate($vatrate, $local, $buyer, $seller, $firstparamisid=0)
Get type and rate of localtaxes for a particular vat rate/country of a thirdparty.
update(User $user, $notrigger=0)
Update a line to invoice_rec.
add_object_linked($origin=null, $origin_id=null)
Add objects linked in llx_element_element.
update_price($exclspec=0, $roundingadjust= 'none', $nodatabaseupdate=0, $seller=null)
Update total_ht, total_ttc, total_vat, total_localtax1, total_localtax2 for an object (sum of lines)...
dol_time_plus_duree($time, $duration_value, $duration_unit)
Add a delay to a date.
Definition: date.lib.php:114
if(preg_match('/crypted:/i', $dolibarr_main_db_pass)||!empty($dolibarr_main_db_encrypted_pass)) $conf db type
Definition: repair.php:105
if(!empty($search_group)) natural_search(array("g.nom"g note
Definition: list.php:122
getLibStatut($mode=0, $alreadypaid=-1)
Return label of object status.
Class to manage invoice lines.
dol_escape_htmltag($stringtoescape, $keepb=0, $keepn=0, $keepmoretags= '', $escapeonlyhtmltags=0)
Returns text escaped for inclusion in HTML alt or title tags, or into values of HTML input fields...