From c0c1de79920764293452f4198bf6ddc6b0575be1 Mon Sep 17 00:00:00 2001 From: fhenry Date: Thu, 18 Apr 2013 08:40:29 +0200 Subject: [PATCH] [ task #826 ] Increasing stock when deleting an invoice --- ChangeLog | 1 + htdocs/admin/stock.php | 19 +- htdocs/compta/facture.php | 35 +- htdocs/compta/facture/class/facture.class.php | 6433 +++++++++-------- htdocs/langs/en_US/agenda.lang | 1 + htdocs/langs/en_US/stocks.lang | 1 + htdocs/langs/es_ES/agenda.lang | 1 + htdocs/langs/es_ES/stocks.lang | 1 + htdocs/langs/fr_FR/agenda.lang | 1 + htdocs/langs/fr_FR/stocks.lang | 1 + 10 files changed, 3296 insertions(+), 3198 deletions(-) diff --git a/ChangeLog b/ChangeLog index da6bd6b1bfd..1de66c954a4 100644 --- a/ChangeLog +++ b/ChangeLog @@ -49,6 +49,7 @@ For users: - New: [ task #814 ] Add extrafield feature into Project/project tasks module - New: [ task #770 ] Add ODT document generation for Projects module - New: [ task #741 ] Add intervention box +- New: [ task #826 ] Optionnal increase stock when deleting an invoice already validated For translators: - Update language files. diff --git a/htdocs/admin/stock.php b/htdocs/admin/stock.php index bbdbf3276db..96502bbdb10 100644 --- a/htdocs/admin/stock.php +++ b/htdocs/admin/stock.php @@ -4,6 +4,7 @@ * Copyright (C) 2005-2009 Regis Houssin * Copyright (C) 2012 Juanjo Menent * Copyright (C) 2013 Philippe Grand + * Copyright (C) 2013 Florian Henry * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -61,15 +62,18 @@ if ($action == 'STOCK_CALCULATE_ON_BILL' // Mode of stock increase if ($action == 'STOCK_CALCULATE_ON_SUPPLIER_BILL' || $action == 'STOCK_CALCULATE_ON_SUPPLIER_VALIDATE_ORDER' -|| $action == 'STOCK_CALCULATE_ON_SUPPLIER_DISPATCH_ORDER') +|| $action == 'STOCK_CALCULATE_ON_SUPPLIER_DISPATCH_ORDER' +|| $action == 'STOCK_CALCULATE_ON_DELETE_INVOICE') { $db->begin(); $res=dolibarr_set_const($db, "STOCK_CALCULATE_ON_SUPPLIER_BILL", '','chaine',0,'',$conf->entity); $res=dolibarr_set_const($db, "STOCK_CALCULATE_ON_SUPPLIER_VALIDATE_ORDER", '','chaine',0,'',$conf->entity); $res=dolibarr_set_const($db, "STOCK_CALCULATE_ON_SUPPLIER_DISPATCH_ORDER", '','chaine',0,'',$conf->entity); + $res=dolibarr_set_const($db, "STOCK_CALCULATE_ON_DELETE_INVOICE", '','chaine',0,'',$conf->entity); if ($action == 'STOCK_CALCULATE_ON_SUPPLIER_BILL') $res=dolibarr_set_const($db, "STOCK_CALCULATE_ON_SUPPLIER_BILL", GETPOST('STOCK_CALCULATE_ON_SUPPLIER_BILL','alpha'),'chaine',0,'',$conf->entity); if ($action == 'STOCK_CALCULATE_ON_SUPPLIER_VALIDATE_ORDER') $res=dolibarr_set_const($db, "STOCK_CALCULATE_ON_SUPPLIER_VALIDATE_ORDER", GETPOST('STOCK_CALCULATE_ON_SUPPLIER_VALIDATE_ORDER','alpha'),'chaine',0,'',$conf->entity); if ($action == 'STOCK_CALCULATE_ON_SUPPLIER_DISPATCH_ORDER') $res=dolibarr_set_const($db, "STOCK_CALCULATE_ON_SUPPLIER_DISPATCH_ORDER", GETPOST('STOCK_CALCULATE_ON_SUPPLIER_DISPATCH_ORDER','alpha'),'chaine',0,'',$conf->entity); + if ($action == 'STOCK_CALCULATE_ON_DELETE_INVOICE') $res=dolibarr_set_const($db, "STOCK_CALCULATE_ON_DELETE_INVOICE", GETPOST('STOCK_CALCULATE_ON_DELETE_INVOICE','alpha'),'chaine',0,'',$conf->entity); } if($action) @@ -239,6 +243,19 @@ if (! empty($conf->fournisseur->enabled)) print ''; print "\n\n\n"; } +if (! empty($conf->facture->enabled)) +{ + $var=!$var; + print ""; + print ''.$langs->trans("ReStockOnDeleteInvoice").''; + print ''; + print "
"; + print ''; + print ""; + print $form->selectyesno("STOCK_CALCULATE_ON_DELETE_INVOICE",$conf->global->STOCK_CALCULATE_ON_DELETE_INVOICE,1); + print ''; + print "
\n\n\n"; +} print ''; diff --git a/htdocs/compta/facture.php b/htdocs/compta/facture.php index 53e839e0241..6ba029d63b4 100644 --- a/htdocs/compta/facture.php +++ b/htdocs/compta/facture.php @@ -156,7 +156,21 @@ else if ($action == 'confirm_delete' && $confirm == 'yes' && $user->rights->fact { $result = $object->fetch($id); $object->fetch_thirdparty(); - $result = $object->delete(); + + $idwarehouse=GETPOST('idwarehouse'); + + //Check for warehouse + if ($object->type != 3 && ! empty($conf->global->STOCK_CALCULATE_ON_DELETE_INVOICE) && $object->hasProductsOrServices(1) && $object->statut>=1) + { + if (! $idwarehouse || $idwarehouse == -1) + { + $error++; + setEventMessage($langs->trans('ErrorFieldRequired',$langs->transnoentitiesnoconv("Warehouse")),'errors'); + $action=''; + } + } + + $result = $object->delete(0,0,$idwarehouse); if ($result > 0) { header('Location: '.DOL_URL_ROOT.'/compta/facture/list.php'); @@ -2334,8 +2348,23 @@ else if ($id > 0 || ! empty($ref)) // Confirmation to delete invoice if ($action == 'delete') { - $text=$langs->trans('ConfirmDeleteBill'); - $formconfirm=$form->formconfirm($_SERVER['PHP_SELF'].'?facid='.$object->id,$langs->trans('DeleteBill'),$text,'confirm_delete','',0,1); + $text=$langs->trans('ConfirmDeleteBill',$object->ref); + $formquestion=array(); + if ($object->type != 3 && ! empty($conf->global->STOCK_CALCULATE_ON_DELETE_INVOICE) && $object->hasProductsOrServices(1) && $object->statut>=1) + { + $langs->load("stocks"); + require_once DOL_DOCUMENT_ROOT.'/product/class/html.formproduct.class.php'; + $formproduct=new FormProduct($db); + $label=$object->type==2?$langs->trans("SelectWarehouseForStockDecrease"):$langs->trans("SelectWarehouseForStockIncrease"); + $formquestion=array( + //'text' => $langs->trans("ConfirmClone"), + //array('type' => 'checkbox', 'name' => 'clone_content', 'label' => $langs->trans("CloneMainAttributes"), 'value' => 1), + //array('type' => 'checkbox', 'name' => 'update_prices', 'label' => $langs->trans("PuttingPricesUpToDate"), 'value' => 1), + array('type' => 'other', 'name' => 'idwarehouse', 'label' => $label, 'value' => $formproduct->selectWarehouses(GETPOST('idwarehouse'),'idwarehouse','',1))); + $formconfirm=$form->formconfirm($_SERVER['PHP_SELF'].'?facid='.$object->id,$langs->trans('DeleteBill'),$text,'confirm_delete',$formquestion,"yes",1); + }else { + $formconfirm=$form->formconfirm($_SERVER['PHP_SELF'].'?facid='.$object->id,$langs->trans('DeleteBill'),$text,'confirm_delete','','',1); + } } // Confirmation de la validation diff --git a/htdocs/compta/facture/class/facture.class.php b/htdocs/compta/facture/class/facture.class.php index f36ddc88a1d..fa03d8527b0 100644 --- a/htdocs/compta/facture/class/facture.class.php +++ b/htdocs/compta/facture/class/facture.class.php @@ -1,37 +1,37 @@ * Copyright (C) 2004-2012 Laurent Destailleur - * Copyright (C) 2004 Sebastien Di Cintio - * Copyright (C) 2004 Benoit Mortier - * Copyright (C) 2005 Marc Barilley / Ocebo - * Copyright (C) 2005-2013 Regis Houssin - * Copyright (C) 2006 Andre Cianfarani - * Copyright (C) 2007 Franky Van Liedekerke - * Copyright (C) 2010-2012 Juanjo Menent - * Copyright (C) 2012 Christophe Battarel - * Copyright (C) 2012 Marcos García - * Copyright (C) 2013 Cedric Gross - * Copyright (C) 2013 Florian Henry - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ +* Copyright (C) 2004 Sebastien Di Cintio +* Copyright (C) 2004 Benoit Mortier +* Copyright (C) 2005 Marc Barilley / Ocebo +* Copyright (C) 2005-2013 Regis Houssin +* Copyright (C) 2006 Andre Cianfarani +* Copyright (C) 2007 Franky Van Liedekerke +* Copyright (C) 2010-2012 Juanjo Menent +* Copyright (C) 2012 Christophe Battarel +* Copyright (C) 2012 Marcos García +* Copyright (C) 2013 Cedric Gross +* Copyright (C) 2013 Florian Henry +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 3 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see . +*/ /** * \file htdocs/compta/facture/class/facture.class.php - * \ingroup facture - * \brief File of class to manage invoices - */ +* \ingroup facture +* \brief File of class to manage invoices +*/ include_once DOL_DOCUMENT_ROOT.'/core/class/commoninvoice.class.php'; require_once DOL_DOCUMENT_ROOT .'/product/class/product.class.php'; @@ -44,1831 +44,1870 @@ require_once DOL_DOCUMENT_ROOT .'/margin/lib/margins.lib.php'; */ class Facture extends CommonInvoice { - public $element='facture'; - public $table_element='facture'; - public $table_element_line = 'facturedet'; - public $fk_element = 'fk_facture'; - protected $ismultientitymanaged = 1; // 0=No test on entity, 1=Test with field entity, 2=Test with link by societe + public $element='facture'; + public $table_element='facture'; + public $table_element_line = 'facturedet'; + public $fk_element = 'fk_facture'; + protected $ismultientitymanaged = 1; // 0=No test on entity, 1=Test with field entity, 2=Test with link by societe - var $id; - //! Id client - var $socid; - //! Objet societe client (to load with fetch_client method) - var $client; - var $author; - var $fk_user_author; - var $fk_user_valid; - //! Invoice date - var $date; // Invoice date - var $date_creation; // Creation date - var $date_validation; // Validation date - var $datem; - var $ref; - var $ref_client; - var $ref_ext; - var $ref_int; - //! 0=Standard invoice, 1=Replacement invoice, 2=Credit note invoice, 3=Deposit invoice, 4=Proforma invoice - var $type=0; + var $id; + //! Id client + var $socid; + //! Objet societe client (to load with fetch_client method) + var $client; + var $author; + var $fk_user_author; + var $fk_user_valid; + //! Invoice date + var $date; // Invoice date + var $date_creation; // Creation date + var $date_validation; // Validation date + var $datem; + var $ref; + var $ref_client; + var $ref_ext; + var $ref_int; + //! 0=Standard invoice, 1=Replacement invoice, 2=Credit note invoice, 3=Deposit invoice, 4=Proforma invoice + var $type=0; - //var $amount; - var $remise_absolue; - var $remise_percent; - var $total_ht=0; - var $total_tva=0; - var $total_ttc=0; - var $revenuestamp; - var $note; // deprecated - var $note_private; - var $note_public; - //! 0=draft, - //! 1=validated (need to be paid), - //! 2=classified paid partially (close_code='discount_vat','badcustomer') or completely (close_code=null), - //! 3=classified abandoned and no payment done (close_code='badcustomer','abandon' or 'replaced') - var $statut; - //! Fermeture apres paiement partiel: discount_vat, badcustomer, abandon - //! Fermeture alors que aucun paiement: replaced (si remplace), abandon - var $close_code; - //! Commentaire si mis a paye sans paiement complet - var $close_note; - //! 1 if invoice paid COMPLETELY, 0 otherwise (do not use it anymore, use statut and close_code - var $paye; - //! id of source invoice if replacement invoice or credit note - var $fk_facture_source; - var $origin; - var $origin_id; - var $linked_objects=array(); - var $fk_project; - var $date_lim_reglement; - var $cond_reglement_id; // Id in llx_c_paiement - var $cond_reglement_code; // Code in llx_c_paiement - var $mode_reglement_id; // Id in llx_c_paiement - var $mode_reglement_code; // Code in llx_c_paiement - var $fk_bank; // Field to store bank id to use when payment mode is withdraw - var $modelpdf; - var $products=array(); // deprecated - var $lines=array(); - var $line; - var $extraparams=array(); - //! Pour board - var $nbtodo; - var $nbtodolate; - var $specimen; + //var $amount; + var $remise_absolue; + var $remise_percent; + var $total_ht=0; + var $total_tva=0; + var $total_ttc=0; + var $revenuestamp; + var $note; // deprecated + var $note_private; + var $note_public; + //! 0=draft, + //! 1=validated (need to be paid), + //! 2=classified paid partially (close_code='discount_vat','badcustomer') or completely (close_code=null), + //! 3=classified abandoned and no payment done (close_code='badcustomer','abandon' or 'replaced') + var $statut; + //! Fermeture apres paiement partiel: discount_vat, badcustomer, abandon + //! Fermeture alors que aucun paiement: replaced (si remplace), abandon + var $close_code; + //! Commentaire si mis a paye sans paiement complet + var $close_note; + //! 1 if invoice paid COMPLETELY, 0 otherwise (do not use it anymore, use statut and close_code + var $paye; + //! id of source invoice if replacement invoice or credit note + var $fk_facture_source; + var $origin; + var $origin_id; + var $linked_objects=array(); + var $fk_project; + var $date_lim_reglement; + var $cond_reglement_id; // Id in llx_c_paiement + var $cond_reglement_code; // Code in llx_c_paiement + var $mode_reglement_id; // Id in llx_c_paiement + var $mode_reglement_code; // Code in llx_c_paiement + var $fk_bank; // Field to store bank id to use when payment mode is withdraw + var $modelpdf; + var $products=array(); // deprecated + var $lines=array(); + var $line; + var $extraparams=array(); + //! Pour board + var $nbtodo; + var $nbtodolate; + var $specimen; - var $fac_rec; + var $fac_rec; - /** - * Constructor - * + /** + * Constructor + * * @param DoliDB $db Database handler - */ - function __construct($db) - { - $this->db = $db; - } + */ + function __construct($db) + { + $this->db = $db; + } - /** - * Create invoice in database - * Note: this->ref can be set or empty. If empty, we will use "(PROV)" - * - * @param User $user Object user that create - * @param int $notrigger 1=Does not execute triggers, 0 otherwise - * @param int $forceduedate 1=Do not recalculate due date from payment condition but force it with value - * @return int <0 if KO, >0 if OK - */ - function create($user,$notrigger=0,$forceduedate=0) - { - global $langs,$conf,$mysoc,$hookmanager; - $error=0; + /** + * Create invoice in database + * Note: this->ref can be set or empty. If empty, we will use "(PROV)" + * + * @param User $user Object user that create + * @param int $notrigger 1=Does not execute triggers, 0 otherwise + * @param int $forceduedate 1=Do not recalculate due date from payment condition but force it with value + * @return int <0 if KO, >0 if OK + */ + function create($user,$notrigger=0,$forceduedate=0) + { + global $langs,$conf,$mysoc,$hookmanager; + $error=0; - // Clean parameters - if (empty($this->type)) $this->type = 0; - $this->ref_client=trim($this->ref_client); - $this->note=(isset($this->note) ? trim($this->note) : trim($this->note_private)); // deprecated - $this->note_private=(isset($this->note_private) ? trim($this->note_private) : trim($this->note_private)); - $this->note_public=trim($this->note_public); - if (! $this->cond_reglement_id) $this->cond_reglement_id = 0; - if (! $this->mode_reglement_id) $this->mode_reglement_id = 0; - $this->brouillon = 1; + // Clean parameters + if (empty($this->type)) $this->type = 0; + $this->ref_client=trim($this->ref_client); + $this->note=(isset($this->note) ? trim($this->note) : trim($this->note_private)); // deprecated + $this->note_private=(isset($this->note_private) ? trim($this->note_private) : trim($this->note_private)); + $this->note_public=trim($this->note_public); + if (! $this->cond_reglement_id) $this->cond_reglement_id = 0; + if (! $this->mode_reglement_id) $this->mode_reglement_id = 0; + $this->brouillon = 1; - dol_syslog(get_class($this)."::create user=".$user->id); + dol_syslog(get_class($this)."::create user=".$user->id); - // Check parameters - if (empty($this->date) || empty($user->id)) - { - $this->error="ErrorBadParameter"; - dol_syslog(get_class($this)."::create Try to create an invoice with an empty parameter (user, date, ...)", LOG_ERR); - return -3; - } - $soc = new Societe($this->db); - $result=$soc->fetch($this->socid); - if ($result < 0) - { - $this->error="Failed to fetch company"; - dol_syslog(get_class($this)."::create ".$this->error, LOG_ERR); - return -2; - } + // Check parameters + if (empty($this->date) || empty($user->id)) + { + $this->error="ErrorBadParameter"; + dol_syslog(get_class($this)."::create Try to create an invoice with an empty parameter (user, date, ...)", LOG_ERR); + return -3; + } + $soc = new Societe($this->db); + $result=$soc->fetch($this->socid); + if ($result < 0) + { + $this->error="Failed to fetch company"; + dol_syslog(get_class($this)."::create ".$this->error, LOG_ERR); + return -2; + } - $now=dol_now(); + $now=dol_now(); - $this->db->begin(); + $this->db->begin(); - // Create invoice from a predefined invoice - if ($this->fac_rec > 0) - { - require_once DOL_DOCUMENT_ROOT.'/compta/facture/class/facture-rec.class.php'; - $_facrec = new FactureRec($this->db); - $result=$_facrec->fetch($this->fac_rec); + // Create invoice from a predefined invoice + if ($this->fac_rec > 0) + { + require_once DOL_DOCUMENT_ROOT.'/compta/facture/class/facture-rec.class.php'; + $_facrec = new FactureRec($this->db); + $result=$_facrec->fetch($this->fac_rec); - $this->fk_project = $_facrec->fk_project; - $this->cond_reglement = $_facrec->cond_reglement_id; - $this->cond_reglement_id = $_facrec->cond_reglement_id; - $this->mode_reglement = $_facrec->mode_reglement_id; - $this->mode_reglement_id = $_facrec->mode_reglement_id; - $this->remise_absolue = $_facrec->remise_absolue; - $this->remise_percent = $_facrec->remise_percent; + $this->fk_project = $_facrec->fk_project; + $this->cond_reglement = $_facrec->cond_reglement_id; + $this->cond_reglement_id = $_facrec->cond_reglement_id; + $this->mode_reglement = $_facrec->mode_reglement_id; + $this->mode_reglement_id = $_facrec->mode_reglement_id; + $this->remise_absolue = $_facrec->remise_absolue; + $this->remise_percent = $_facrec->remise_percent; - // Clean parametres - if (! $this->type) $this->type = 0; - $this->ref_client=trim($this->ref_client); - $this->note_private=trim($this->note_private); - $this->note_public=trim($this->note_public); - //if (! $this->remise) $this->remise = 0; - if (! $this->mode_reglement_id) $this->mode_reglement_id = 0; - $this->brouillon = 1; - } + // Clean parametres + if (! $this->type) $this->type = 0; + $this->ref_client=trim($this->ref_client); + $this->note_private=trim($this->note_private); + $this->note_public=trim($this->note_public); + //if (! $this->remise) $this->remise = 0; + if (! $this->mode_reglement_id) $this->mode_reglement_id = 0; + $this->brouillon = 1; + } - // Define due date if not already defined - $datelim=(empty($forceduedate)?$this->calculate_date_lim_reglement():$forceduedate); + // Define due date if not already defined + $datelim=(empty($forceduedate)?$this->calculate_date_lim_reglement():$forceduedate); - // Insert into database - $socid = $this->socid; + // Insert into database + $socid = $this->socid; - $sql = "INSERT INTO ".MAIN_DB_PREFIX."facture ("; - $sql.= " facnumber"; - $sql.= ", entity"; - $sql.= ", ref_ext"; - $sql.= ", type"; - $sql.= ", fk_soc"; - $sql.= ", datec"; - $sql.= ", remise_absolue"; - $sql.= ", remise_percent"; - $sql.= ", datef"; - $sql.= ", note_private"; - $sql.= ", note_public"; - $sql.= ", ref_client, ref_int"; - $sql.= ", fk_facture_source, fk_user_author, fk_projet"; - $sql.= ", fk_cond_reglement, fk_mode_reglement, date_lim_reglement, model_pdf"; - $sql.= ")"; - $sql.= " VALUES ("; - $sql.= "'(PROV)'"; - $sql.= ", ".$conf->entity; - $sql.= ", ".($this->ref_ext?"'".$this->db->escape($this->ref_ext)."'":"null"); - $sql.= ", '".$this->type."'"; - $sql.= ", '".$socid."'"; - $sql.= ", '".$this->db->idate($now)."'"; - $sql.= ",".($this->remise_absolue>0?$this->remise_absolue:'NULL'); - $sql.= ",".($this->remise_percent>0?$this->remise_percent:'NULL'); - $sql.= ", '".$this->db->idate($this->date)."'"; - $sql.= ",".($this->note_private?"'".$this->db->escape($this->note_private)."'":"null"); - $sql.= ",".($this->note_public?"'".$this->db->escape($this->note_public)."'":"null"); - $sql.= ",".($this->ref_client?"'".$this->db->escape($this->ref_client)."'":"null"); - $sql.= ",".($this->ref_int?"'".$this->db->escape($this->ref_int)."'":"null"); - $sql.= ",".($this->fk_facture_source?"'".$this->db->escape($this->fk_facture_source)."'":"null"); - $sql.= ",".($user->id > 0 ? "'".$user->id."'":"null"); - $sql.= ",".($this->fk_project?$this->fk_project:"null"); - $sql.= ','.$this->cond_reglement_id; - $sql.= ",".$this->mode_reglement_id; - $sql.= ", '".$this->db->idate($datelim)."', '".$this->modelpdf."')"; + $sql = "INSERT INTO ".MAIN_DB_PREFIX."facture ("; + $sql.= " facnumber"; + $sql.= ", entity"; + $sql.= ", ref_ext"; + $sql.= ", type"; + $sql.= ", fk_soc"; + $sql.= ", datec"; + $sql.= ", remise_absolue"; + $sql.= ", remise_percent"; + $sql.= ", datef"; + $sql.= ", note_private"; + $sql.= ", note_public"; + $sql.= ", ref_client, ref_int"; + $sql.= ", fk_facture_source, fk_user_author, fk_projet"; + $sql.= ", fk_cond_reglement, fk_mode_reglement, date_lim_reglement, model_pdf"; + $sql.= ")"; + $sql.= " VALUES ("; + $sql.= "'(PROV)'"; + $sql.= ", ".$conf->entity; + $sql.= ", ".($this->ref_ext?"'".$this->db->escape($this->ref_ext)."'":"null"); + $sql.= ", '".$this->type."'"; + $sql.= ", '".$socid."'"; + $sql.= ", '".$this->db->idate($now)."'"; + $sql.= ",".($this->remise_absolue>0?$this->remise_absolue:'NULL'); + $sql.= ",".($this->remise_percent>0?$this->remise_percent:'NULL'); + $sql.= ", '".$this->db->idate($this->date)."'"; + $sql.= ",".($this->note_private?"'".$this->db->escape($this->note_private)."'":"null"); + $sql.= ",".($this->note_public?"'".$this->db->escape($this->note_public)."'":"null"); + $sql.= ",".($this->ref_client?"'".$this->db->escape($this->ref_client)."'":"null"); + $sql.= ",".($this->ref_int?"'".$this->db->escape($this->ref_int)."'":"null"); + $sql.= ",".($this->fk_facture_source?"'".$this->db->escape($this->fk_facture_source)."'":"null"); + $sql.= ",".($user->id > 0 ? "'".$user->id."'":"null"); + $sql.= ",".($this->fk_project?$this->fk_project:"null"); + $sql.= ','.$this->cond_reglement_id; + $sql.= ",".$this->mode_reglement_id; + $sql.= ", '".$this->db->idate($datelim)."', '".$this->modelpdf."')"; - dol_syslog(get_class($this)."::create sql=".$sql); - $resql=$this->db->query($sql); - if ($resql) - { - $this->id = $this->db->last_insert_id(MAIN_DB_PREFIX.'facture'); + dol_syslog(get_class($this)."::create sql=".$sql); + $resql=$this->db->query($sql); + if ($resql) + { + $this->id = $this->db->last_insert_id(MAIN_DB_PREFIX.'facture'); - // Update ref with new one - $this->ref='(PROV'.$this->id.')'; - $sql = 'UPDATE '.MAIN_DB_PREFIX."facture SET facnumber='".$this->ref."' WHERE rowid=".$this->id; + // Update ref with new one + $this->ref='(PROV'.$this->id.')'; + $sql = 'UPDATE '.MAIN_DB_PREFIX."facture SET facnumber='".$this->ref."' WHERE rowid=".$this->id; - dol_syslog(get_class($this)."::create sql=".$sql); - $resql=$this->db->query($sql); - if (! $resql) $error++; + dol_syslog(get_class($this)."::create sql=".$sql); + $resql=$this->db->query($sql); + if (! $resql) $error++; - // Add object linked - if (! $error && $this->id && is_array($this->linked_objects) && ! empty($this->linked_objects)) - { - foreach($this->linked_objects as $origin => $origin_id) - { - $ret = $this->add_object_linked($origin, $origin_id); - if (! $ret) - { - dol_print_error($this->db); - $error++; - } + // Add object linked + if (! $error && $this->id && is_array($this->linked_objects) && ! empty($this->linked_objects)) + { + foreach($this->linked_objects as $origin => $origin_id) + { + $ret = $this->add_object_linked($origin, $origin_id); + if (! $ret) + { + dol_print_error($this->db); + $error++; + } - // TODO mutualiser - if ($origin == 'commande') - { - // On recupere les differents contact interne et externe - $order = new Commande($this->db); - $order->id = $origin_id; + // TODO mutualiser + if ($origin == 'commande') + { + // On recupere les differents contact interne et externe + $order = new Commande($this->db); + $order->id = $origin_id; - // On recupere le commercial suivi propale - $this->userid = $order->getIdcontact('internal', 'SALESREPFOLL'); + // On recupere le commercial suivi propale + $this->userid = $order->getIdcontact('internal', 'SALESREPFOLL'); - if ($this->userid) - { - //On passe le commercial suivi commande en commercial suivi paiement - $this->add_contact($this->userid[0], 'SALESREPFOLL', 'internal'); - } + if ($this->userid) + { + //On passe le commercial suivi commande en commercial suivi paiement + $this->add_contact($this->userid[0], 'SALESREPFOLL', 'internal'); + } - // On recupere le contact client facturation commande - $this->contactid = $order->getIdcontact('external', 'BILLING'); + // On recupere le contact client facturation commande + $this->contactid = $order->getIdcontact('external', 'BILLING'); - if ($this->contactid) - { - //On passe le contact client facturation commande en contact client facturation - $this->add_contact($this->contactid[0], 'BILLING', 'external'); - } - } - } - } + if ($this->contactid) + { + //On passe le contact client facturation commande en contact client facturation + $this->add_contact($this->contactid[0], 'BILLING', 'external'); + } + } + } + } - /* - * Insert lines of invoices into database - */ - if (count($this->lines) && is_object($this->lines[0])) - { - $fk_parent_line = 0; + /* + * Insert lines of invoices into database + */ + if (count($this->lines) && is_object($this->lines[0])) + { + $fk_parent_line = 0; - dol_syslog("There is ".count($this->lines)." lines that are invoice lines objects"); - foreach ($this->lines as $i => $val) - { - $newinvoiceline=new FactureLigne($this->db); - $newinvoiceline=$this->lines[$i]; - $newinvoiceline->fk_facture=$this->id; - if ($result >= 0 && ($newinvoiceline->info_bits & 0x01) == 0) // We keep only lines with first bit = 0 - { - // Reset fk_parent_line for no child products and special product + dol_syslog("There is ".count($this->lines)." lines that are invoice lines objects"); + foreach ($this->lines as $i => $val) + { + $newinvoiceline=new FactureLigne($this->db); + $newinvoiceline=$this->lines[$i]; + $newinvoiceline->fk_facture=$this->id; + if ($result >= 0 && ($newinvoiceline->info_bits & 0x01) == 0) // We keep only lines with first bit = 0 + { + // Reset fk_parent_line for no child products and special product if (($newinvoiceline->product_type != 9 && empty($newinvoiceline->fk_parent_line)) || $newinvoiceline->product_type == 9) { $fk_parent_line = 0; } - $newinvoiceline->fk_parent_line=$fk_parent_line; + $newinvoiceline->fk_parent_line=$fk_parent_line; $result=$newinvoiceline->insert(); - // Defined the new fk_parent_line + // Defined the new fk_parent_line if ($result > 0 && $newinvoiceline->product_type == 9) { $fk_parent_line = $result; } - } - if ($result < 0) - { - $this->error=$newinvoiceline->error; - $error++; - break; - } - } - } - else - { - $fk_parent_line = 0; + } + if ($result < 0) + { + $this->error=$newinvoiceline->error; + $error++; + break; + } + } + } + else + { + $fk_parent_line = 0; - dol_syslog("There is ".count($this->lines)." lines that are array lines"); - foreach ($this->lines as $i => $val) - { - if (($this->lines[$i]->info_bits & 0x01) == 0) // We keep only lines with first bit = 0 - { - // Reset fk_parent_line for no child products and special product + dol_syslog("There is ".count($this->lines)." lines that are array lines"); + foreach ($this->lines as $i => $val) + { + if (($this->lines[$i]->info_bits & 0x01) == 0) // We keep only lines with first bit = 0 + { + // Reset fk_parent_line for no child products and special product if (($this->lines[$i]->product_type != 9 && empty($this->lines[$i]->fk_parent_line)) || $this->lines[$i]->product_type == 9) { $fk_parent_line = 0; } - $result = $this->addline( - $this->id, - $this->lines[$i]->desc, - $this->lines[$i]->subprice, - $this->lines[$i]->qty, - $this->lines[$i]->tva_tx, - $this->lines[$i]->localtax1_tx, - $this->lines[$i]->localtax2_tx, - $this->lines[$i]->fk_product, - $this->lines[$i]->remise_percent, - $this->lines[$i]->date_start, - $this->lines[$i]->date_end, - $this->lines[$i]->fk_code_ventilation, - $this->lines[$i]->info_bits, - $this->lines[$i]->fk_remise_except, - 'HT', - 0, - $this->lines[$i]->product_type, - $this->lines[$i]->rang, - $this->lines[$i]->special_code, - '', - 0, - $fk_parent_line, - $this->lines[$i]->fk_fournprice, - $this->lines[$i]->pa_ht, - $this->lines[$i]->label - ); - if ($result < 0) - { - $this->error=$this->db->lasterror(); - dol_print_error($this->db); - $this->db->rollback(); - return -1; - } + $result = $this->addline( + $this->id, + $this->lines[$i]->desc, + $this->lines[$i]->subprice, + $this->lines[$i]->qty, + $this->lines[$i]->tva_tx, + $this->lines[$i]->localtax1_tx, + $this->lines[$i]->localtax2_tx, + $this->lines[$i]->fk_product, + $this->lines[$i]->remise_percent, + $this->lines[$i]->date_start, + $this->lines[$i]->date_end, + $this->lines[$i]->fk_code_ventilation, + $this->lines[$i]->info_bits, + $this->lines[$i]->fk_remise_except, + 'HT', + 0, + $this->lines[$i]->product_type, + $this->lines[$i]->rang, + $this->lines[$i]->special_code, + '', + 0, + $fk_parent_line, + $this->lines[$i]->fk_fournprice, + $this->lines[$i]->pa_ht, + $this->lines[$i]->label + ); + if ($result < 0) + { + $this->error=$this->db->lasterror(); + dol_print_error($this->db); + $this->db->rollback(); + return -1; + } - // Defined the new fk_parent_line + // Defined the new fk_parent_line if ($result > 0 && $this->lines[$i]->product_type == 9) { $fk_parent_line = $result; } - } - } - } + } + } + } - /* - * Insert lines of predefined invoices - */ - if (! $error && $this->fac_rec > 0) - { - foreach ($_facrec->lines as $i => $val) - { - if ($_facrec->lines[$i]->fk_product) - { - $prod = new Product($this->db); - $res=$prod->fetch($_facrec->lines[$i]->fk_product); - } - $tva_tx = get_default_tva($mysoc,$soc,$prod->id); - $localtax1_tx=get_localtax($tva_tx,1,$soc); - $localtax2_tx=get_localtax($tva_tx,2,$soc); + /* + * Insert lines of predefined invoices + */ + if (! $error && $this->fac_rec > 0) + { + foreach ($_facrec->lines as $i => $val) + { + if ($_facrec->lines[$i]->fk_product) + { + $prod = new Product($this->db); + $res=$prod->fetch($_facrec->lines[$i]->fk_product); + } + $tva_tx = get_default_tva($mysoc,$soc,$prod->id); + $localtax1_tx=get_localtax($tva_tx,1,$soc); + $localtax2_tx=get_localtax($tva_tx,2,$soc); - $result_insert = $this->addline( - $this->id, - $_facrec->lines[$i]->desc, - $_facrec->lines[$i]->subprice, - $_facrec->lines[$i]->qty, - $tva_tx, - $localtax1_tx, - $localtax2_tx, - $_facrec->lines[$i]->fk_product, - $_facrec->lines[$i]->remise_percent, - '','',0,0,'','HT',0, - $_facrec->lines[$i]->product_type, - $_facrec->lines[$i]->rang, - $_facrec->lines[$i]->special_code, - '', - 0, - 0, - null, - 0, - $_facrec->lines[$i]->label - ); + $result_insert = $this->addline( + $this->id, + $_facrec->lines[$i]->desc, + $_facrec->lines[$i]->subprice, + $_facrec->lines[$i]->qty, + $tva_tx, + $localtax1_tx, + $localtax2_tx, + $_facrec->lines[$i]->fk_product, + $_facrec->lines[$i]->remise_percent, + '','',0,0,'','HT',0, + $_facrec->lines[$i]->product_type, + $_facrec->lines[$i]->rang, + $_facrec->lines[$i]->special_code, + '', + 0, + 0, + null, + 0, + $_facrec->lines[$i]->label + ); - if ( $result_insert < 0) - { - $error++; - $this->error=$this->db->error(); - break; - } - } - } + if ( $result_insert < 0) + { + $error++; + $this->error=$this->db->error(); + break; + } + } + } - if (! $error) - { - $result=$this->update_price(1); - if ($result > 0) - { - // Actions on extra fields (by external module or standard code) - // FIXME le hook fait double emploi avec le trigger !! - $hookmanager->initHooks(array('invoicedao')); - $parameters=array('invoiceid'=>$this->id); - $reshook=$hookmanager->executeHooks('insertExtraFields',$parameters,$this,$action); // Note that $action and $object may have been modified by some hooks - if (empty($reshook)) - { - if (empty($conf->global->MAIN_EXTRAFIELDS_DISABLED)) // For avoid conflicts if trigger used - { - $result=$this->insertExtraFields(); - if ($result < 0) - { - $error++; - } - } - } - else if ($reshook < 0) $error++; + if (! $error) + { + $result=$this->update_price(1); + if ($result > 0) + { + // Actions on extra fields (by external module or standard code) + // FIXME le hook fait double emploi avec le trigger !! + $hookmanager->initHooks(array('invoicedao')); + $parameters=array('invoiceid'=>$this->id); + $reshook=$hookmanager->executeHooks('insertExtraFields',$parameters,$this,$action); // Note that $action and $object may have been modified by some hooks + if (empty($reshook)) + { + if (empty($conf->global->MAIN_EXTRAFIELDS_DISABLED)) // For avoid conflicts if trigger used + { + $result=$this->insertExtraFields(); + if ($result < 0) + { + $error++; + } + } + } + else if ($reshook < 0) $error++; - // Appel des triggers - include_once DOL_DOCUMENT_ROOT . '/core/class/interfaces.class.php'; - $interface=new Interfaces($this->db); - $result=$interface->run_triggers('BILL_CREATE',$this,$user,$langs,$conf); - if ($result < 0) { $error++; $this->errors=$interface->errors; } - // Fin appel triggers + // Appel des triggers + include_once DOL_DOCUMENT_ROOT . '/core/class/interfaces.class.php'; + $interface=new Interfaces($this->db); + $result=$interface->run_triggers('BILL_CREATE',$this,$user,$langs,$conf); + if ($result < 0) { + $error++; $this->errors=$interface->errors; + } + // Fin appel triggers - if (! $error) - { - $this->db->commit(); - return $this->id; - } - else - { - $this->db->rollback(); - return -4; - } - } - else - { - $this->error=$langs->trans('FailedToUpdatePrice'); - $this->db->rollback(); - return -3; - } - } - else - { - dol_syslog(get_class($this)."::create error ".$this->error, LOG_ERR); - $this->db->rollback(); - return -2; - } - } - else - { - $this->error=$this->db->error(); - dol_syslog(get_class($this)."::create error ".$this->error." sql=".$sql, LOG_ERR); - $this->db->rollback(); - return -1; - } - } + if (! $error) + { + $this->db->commit(); + return $this->id; + } + else + { + $this->db->rollback(); + return -4; + } + } + else + { + $this->error=$langs->trans('FailedToUpdatePrice'); + $this->db->rollback(); + return -3; + } + } + else + { + dol_syslog(get_class($this)."::create error ".$this->error, LOG_ERR); + $this->db->rollback(); + return -2; + } + } + else + { + $this->error=$this->db->error(); + dol_syslog(get_class($this)."::create error ".$this->error." sql=".$sql, LOG_ERR); + $this->db->rollback(); + return -1; + } + } - /** - * Create a new invoice in database from current invoice - * - * @param User $user Object user that ask creation - * @param int $invertdetail Reverse sign of amounts for lines - * @return int <0 if KO, >0 if OK - */ - function createFromCurrent($user,$invertdetail=0) - { - // Charge facture source - $facture=new Facture($this->db); + /** + * Create a new invoice in database from current invoice + * + * @param User $user Object user that ask creation + * @param int $invertdetail Reverse sign of amounts for lines + * @return int <0 if KO, >0 if OK + */ + function createFromCurrent($user,$invertdetail=0) + { + // Charge facture source + $facture=new Facture($this->db); - $facture->fk_facture_source = $this->fk_facture_source; - $facture->type = $this->type; - $facture->socid = $this->socid; - $facture->date = $this->date; - $facture->note_public = $this->note_public; - $facture->note_private = $this->note_private; - $facture->ref_client = $this->ref_client; - $facture->modelpdf = $this->modelpdf; - $facture->fk_project = $this->fk_project; - $facture->cond_reglement_id = $this->cond_reglement_id; - $facture->mode_reglement_id = $this->mode_reglement_id; - $facture->remise_absolue = $this->remise_absolue; - $facture->remise_percent = $this->remise_percent; + $facture->fk_facture_source = $this->fk_facture_source; + $facture->type = $this->type; + $facture->socid = $this->socid; + $facture->date = $this->date; + $facture->note_public = $this->note_public; + $facture->note_private = $this->note_private; + $facture->ref_client = $this->ref_client; + $facture->modelpdf = $this->modelpdf; + $facture->fk_project = $this->fk_project; + $facture->cond_reglement_id = $this->cond_reglement_id; + $facture->mode_reglement_id = $this->mode_reglement_id; + $facture->remise_absolue = $this->remise_absolue; + $facture->remise_percent = $this->remise_percent; - $facture->lines = $this->lines; // Tableau des lignes de factures - $facture->products = $this->lines; // Tant que products encore utilise + $facture->lines = $this->lines; // Tableau des lignes de factures + $facture->products = $this->lines; // Tant que products encore utilise - // Loop on each line of new invoice - foreach($facture->lines as $i => $line) - { - if ($invertdetail) - { - $facture->lines[$i]->subprice = -$facture->lines[$i]->subprice; - $facture->lines[$i]->total_ht = -$facture->lines[$i]->total_ht; - $facture->lines[$i]->total_tva = -$facture->lines[$i]->total_tva; - $facture->lines[$i]->total_localtax1 = -$facture->lines[$i]->total_localtax1; - $facture->lines[$i]->total_localtax2 = -$facture->lines[$i]->total_localtax2; - $facture->lines[$i]->total_ttc = -$facture->lines[$i]->total_ttc; - } - } + // Loop on each line of new invoice + foreach($facture->lines as $i => $line) + { + if ($invertdetail) + { + $facture->lines[$i]->subprice = -$facture->lines[$i]->subprice; + $facture->lines[$i]->total_ht = -$facture->lines[$i]->total_ht; + $facture->lines[$i]->total_tva = -$facture->lines[$i]->total_tva; + $facture->lines[$i]->total_localtax1 = -$facture->lines[$i]->total_localtax1; + $facture->lines[$i]->total_localtax2 = -$facture->lines[$i]->total_localtax2; + $facture->lines[$i]->total_ttc = -$facture->lines[$i]->total_ttc; + } + } - dol_syslog(get_class($this)."::createFromCurrent invertdetail=".$invertdetail." socid=".$this->socid." nboflines=".count($facture->lines)); + dol_syslog(get_class($this)."::createFromCurrent invertdetail=".$invertdetail." socid=".$this->socid." nboflines=".count($facture->lines)); - $facid = $facture->create($user); - if ($facid <= 0) - { - $this->error=$facture->error; - $this->errors=$facture->errors; - } + $facid = $facture->create($user); + if ($facid <= 0) + { + $this->error=$facture->error; + $this->errors=$facture->errors; + } - return $facid; - } + return $facid; + } - /** - * Load an object from its id and create a new one in database - * - * @param int $socid Id of thirdparty - * @return int New id of clone - */ - function createFromClone($socid=0) - { - global $conf,$user,$langs; + /** + * Load an object from its id and create a new one in database + * + * @param int $socid Id of thirdparty + * @return int New id of clone + */ + function createFromClone($socid=0) + { + global $conf,$user,$langs; - $error=0; + $error=0; - $this->db->begin(); + $this->db->begin(); - // Load source object - $objFrom = dol_clone($this); + // Load source object + $objFrom = dol_clone($this); - // Change socid if needed - if (! empty($socid) && $socid != $this->socid) - { - $objsoc = new Societe($this->db); + // Change socid if needed + if (! empty($socid) && $socid != $this->socid) + { + $objsoc = new Societe($this->db); - if ($objsoc->fetch($socid)>0) - { - $this->socid = $objsoc->id; - $this->cond_reglement_id = (! empty($objsoc->cond_reglement_id) ? $objsoc->cond_reglement_id : 0); - $this->mode_reglement_id = (! empty($objsoc->mode_reglement_id) ? $objsoc->mode_reglement_id : 0); - $this->fk_project = ''; - $this->fk_delivery_address = ''; - } + if ($objsoc->fetch($socid)>0) + { + $this->socid = $objsoc->id; + $this->cond_reglement_id = (! empty($objsoc->cond_reglement_id) ? $objsoc->cond_reglement_id : 0); + $this->mode_reglement_id = (! empty($objsoc->mode_reglement_id) ? $objsoc->mode_reglement_id : 0); + $this->fk_project = ''; + $this->fk_delivery_address = ''; + } - // TODO Change product price if multi-prices - } + // TODO Change product price if multi-prices + } - $this->id=0; - $this->statut=0; + $this->id=0; + $this->statut=0; - // Clear fields - $this->user_author = $user->id; - $this->user_valid = ''; - $this->fk_facture_source = 0; - $this->date_creation = ''; - $this->date_validation = ''; - $this->ref_client = ''; - $this->close_code = ''; - $this->close_note = ''; - $this->products = $this->lines; // Tant que products encore utilise + // Clear fields + $this->user_author = $user->id; + $this->user_valid = ''; + $this->fk_facture_source = 0; + $this->date_creation = ''; + $this->date_validation = ''; + $this->ref_client = ''; + $this->close_code = ''; + $this->close_note = ''; + $this->products = $this->lines; // Tant que products encore utilise - // Loop on each line of new invoice - foreach($this->lines as $i => $line) - { - if (($this->lines[$i]->info_bits & 0x02) == 0x02) // We do not clone line of discounts - { - unset($this->lines[$i]); - unset($this->products[$i]); // Tant que products encore utilise - } - } + // Loop on each line of new invoice + foreach($this->lines as $i => $line) + { + if (($this->lines[$i]->info_bits & 0x02) == 0x02) // We do not clone line of discounts + { + unset($this->lines[$i]); + unset($this->products[$i]); // Tant que products encore utilise + } + } - // Create clone - $result=$this->create($user); - if ($result < 0) $error++; + // Create clone + $result=$this->create($user); + if ($result < 0) $error++; - if (! $error) - { - // Hook of thirdparty module + if (! $error) + { + // Hook of thirdparty module if (is_object($hookmanager)) { - $parameters=array('objFrom'=>$objFrom); - $action=''; + $parameters=array('objFrom'=>$objFrom); + $action=''; $reshook=$hookmanager->executeHooks('createFrom',$parameters,$this,$action); // Note that $action and $object may have been modified by some hooks if ($reshook < 0) $error++; } - // Appel des triggers - include_once DOL_DOCUMENT_ROOT . '/core/class/interfaces.class.php'; - $interface=new Interfaces($this->db); - $result=$interface->run_triggers('BILL_CLONE',$this,$user,$langs,$conf); - if ($result < 0) { $error++; $this->errors=$interface->errors; } - // Fin appel triggers - } - - // End - if (! $error) - { - $this->db->commit(); - return $this->id; - } - else - { - $this->db->rollback(); - return -1; - } - } - - /** - * Load an object from an order and create a new invoice into database - * - * @param Object $object Object source - * @return int <0 if KO, 0 if nothing done, 1 if OK - */ - function createFromOrder($object) - { - global $conf,$user,$langs,$hookmanager; - - $error=0; - - // Closed order - $this->date = dol_now(); - $this->source = 0; - - $num=count($object->lines); - for ($i = 0; $i < $num; $i++) - { - $line = new FactureLigne($this->db); - - $line->libelle = $object->lines[$i]->libelle; - $line->label = $object->lines[$i]->label; - $line->desc = $object->lines[$i]->desc; - $line->subprice = $object->lines[$i]->subprice; - $line->total_ht = $object->lines[$i]->total_ht; - $line->total_tva = $object->lines[$i]->total_tva; - $line->total_ttc = $object->lines[$i]->total_ttc; - $line->tva_tx = $object->lines[$i]->tva_tx; - $line->localtax1_tx = $object->lines[$i]->localtax1_tx; - $line->localtax2_tx = $object->lines[$i]->localtax2_tx; - $line->qty = $object->lines[$i]->qty; - $line->fk_remise_except = $object->lines[$i]->fk_remise_except; - $line->remise_percent = $object->lines[$i]->remise_percent; - $line->fk_product = $object->lines[$i]->fk_product; - $line->info_bits = $object->lines[$i]->info_bits; - $line->product_type = $object->lines[$i]->product_type; - $line->rang = $object->lines[$i]->rang; - $line->special_code = $object->lines[$i]->special_code; - $line->fk_parent_line = $object->lines[$i]->fk_parent_line; - - $this->lines[$i] = $line; - } - - $this->socid = $object->socid; - $this->fk_project = $object->fk_project; - $this->cond_reglement_id = $object->cond_reglement_id; - $this->mode_reglement_id = $object->mode_reglement_id; - $this->availability_id = $object->availability_id; - $this->demand_reason_id = $object->demand_reason_id; - $this->date_livraison = $object->date_livraison; - $this->fk_delivery_address = $object->fk_delivery_address; - $this->contact_id = $object->contactid; - $this->ref_client = $object->ref_client; - $this->note_private = $object->note_private; - $this->note_public = $object->note_public; - - $this->origin = $object->element; - $this->origin_id = $object->id; - - // Possibility to add external linked objects with hooks - $this->linked_objects[$this->origin] = $this->origin_id; - if (! empty($object->other_linked_objects) && is_array($object->other_linked_objects)) - { - $this->linked_objects = array_merge($this->linked_objects, $object->other_linked_objects); - } - - $ret = $this->create($user); - - if ($ret > 0) - { - // Actions hooked (by external module) - $hookmanager->initHooks(array('invoicedao')); - - $parameters=array('objFrom'=>$object); - $action=''; - $reshook=$hookmanager->executeHooks('createFrom',$parameters,$this,$action); // Note that $action and $object may have been modified by some hooks - if ($reshook < 0) $error++; - - if (! $error) - { - return 1; - } - else return -1; - } - else return -1; - } - - /** - * Return clicable link of object (with eventually picto) - * - * @param int $withpicto Add picto into link - * @param string $option Where point the link - * @param int $max Maxlength of ref - * @param int $short 1=Return just URL - * @param string $moretitle Add more text to title tooltip - * @return string String with URL - */ - function getNomUrl($withpicto=0,$option='',$max=0,$short=0,$moretitle='') - { - global $langs; - - $result=''; - - if ($option == 'withdraw') $url = DOL_URL_ROOT.'/compta/facture/prelevement.php?facid='.$this->id; - else $url = DOL_URL_ROOT.'/compta/facture.php?facid='.$this->id; - - if ($short) return $url; - - $picto='bill'; - if ($this->type == 1) $picto.='r'; // Replacement invoice - if ($this->type == 2) $picto.='a'; // Credit note - if ($this->type == 3) $picto.='d'; // Deposit invoice - - $label=$langs->trans("ShowInvoice").': '.$this->ref; - if ($this->type == 1) $label=$langs->transnoentitiesnoconv("ShowInvoiceReplace").': '.$this->ref; - if ($this->type == 2) $label=$langs->transnoentitiesnoconv("ShowInvoiceAvoir").': '.$this->ref; - if ($this->type == 3) $label=$langs->transnoentitiesnoconv("ShowInvoiceDeposit").': '.$this->ref; - if ($moretitle) $label.=' - '.$moretitle; - - //$linkstart=''; - $linkstart=''; - $linkend=''; - - if ($withpicto) $result.=($linkstart.img_object(($max?dol_trunc($label,$max):$label),$picto).$linkend); - if ($withpicto && $withpicto != 2) $result.=' '; - if ($withpicto != 2) $result.=$linkstart.($max?dol_trunc($this->ref,$max):$this->ref).$linkend; - return $result; - } - - - /** - * Get object and lines from database - * - * @param int $rowid Id of object to load - * @param string $ref Reference of invoice - * @param string $ref_ext External reference of invoice - * @param int $ref_int Internal reference of other object - * @return int >0 if OK, <0 if KO, 0 if not found - */ - function fetch($rowid, $ref='', $ref_ext='', $ref_int='') - { - global $conf; - - if (empty($rowid) && empty($ref) && empty($ref_ext) && empty($ref_int)) return -1; - - $sql = 'SELECT f.rowid,f.facnumber,f.ref_client,f.ref_ext,f.ref_int,f.type,f.fk_soc,f.amount,f.tva, f.localtax1, f.localtax2, f.total, f.total_ttc, f.revenuestamp'; - $sql.= ', f.remise_percent, f.remise_absolue, f.remise'; - $sql.= ', f.datef as df'; - $sql.= ', f.date_lim_reglement as dlr'; - $sql.= ', f.datec as datec'; - $sql.= ', f.date_valid as datev'; - $sql.= ', f.tms as datem'; - $sql.= ', f.note_private, f.note_public, f.fk_statut, f.paye, f.close_code, f.close_note, f.fk_user_author, f.fk_user_valid, f.model_pdf'; - $sql.= ', f.fk_facture_source'; - $sql.= ', f.fk_mode_reglement, f.fk_cond_reglement, f.fk_projet, f.extraparams'; - $sql.= ', p.code as mode_reglement_code, p.libelle as mode_reglement_libelle'; - $sql.= ', c.code as cond_reglement_code, c.libelle as cond_reglement_libelle, c.libelle_facture as cond_reglement_libelle_doc'; - $sql.= ' FROM '.MAIN_DB_PREFIX.'facture as f'; - $sql.= ' LEFT JOIN '.MAIN_DB_PREFIX.'c_payment_term as c ON f.fk_cond_reglement = c.rowid'; - $sql.= ' LEFT JOIN '.MAIN_DB_PREFIX.'c_paiement as p ON f.fk_mode_reglement = p.id'; - $sql.= ' WHERE f.entity = '.$conf->entity; - if ($rowid) $sql.= " AND f.rowid=".$rowid; - if ($ref) $sql.= " AND f.facnumber='".$this->db->escape($ref)."'"; - if ($ref_ext) $sql.= " AND f.ref_ext='".$this->db->escape($ref_ext)."'"; - if ($ref_int) $sql.= " AND f.ref_int='".$this->db->escape($ref_int)."'"; - - dol_syslog(get_class($this)."::fetch sql=".$sql, LOG_DEBUG); - $result = $this->db->query($sql); - if ($result) - { - if ($this->db->num_rows($result)) - { - $obj = $this->db->fetch_object($result); - - $this->id = $obj->rowid; - $this->ref = $obj->facnumber; - $this->ref_client = $obj->ref_client; - $this->ref_ext = $obj->ref_ext; - $this->ref_int = $obj->ref_int; - $this->type = $obj->type; - $this->date = $this->db->jdate($obj->df); - $this->date_creation = $this->db->jdate($obj->datec); - $this->date_validation = $this->db->jdate($obj->datev); - $this->datem = $this->db->jdate($obj->datem); - $this->remise_percent = $obj->remise_percent; - $this->remise_absolue = $obj->remise_absolue; - //$this->remise = $obj->remise; - $this->total_ht = $obj->total; - $this->total_tva = $obj->tva; - $this->total_localtax1 = $obj->localtax1; - $this->total_localtax2 = $obj->localtax2; - $this->total_ttc = $obj->total_ttc; - $this->revenuestamp = $obj->revenuestamp; - $this->paye = $obj->paye; - $this->close_code = $obj->close_code; - $this->close_note = $obj->close_note; - $this->socid = $obj->fk_soc; - $this->statut = $obj->fk_statut; - $this->date_lim_reglement = $this->db->jdate($obj->dlr); - $this->mode_reglement_id = $obj->fk_mode_reglement; - $this->mode_reglement_code = $obj->mode_reglement_code; - $this->mode_reglement = $obj->mode_reglement_libelle; - $this->cond_reglement_id = $obj->fk_cond_reglement; - $this->cond_reglement_code = $obj->cond_reglement_code; - $this->cond_reglement = $obj->cond_reglement_libelle; - $this->cond_reglement_doc = $obj->cond_reglement_libelle_doc; - $this->fk_project = $obj->fk_projet; - $this->fk_facture_source = $obj->fk_facture_source; - $this->note = $obj->note_private; // deprecated - $this->note_private = $obj->note_private; - $this->note_public = $obj->note_public; - $this->user_author = $obj->fk_user_author; - $this->user_valid = $obj->fk_user_valid; - $this->modelpdf = $obj->model_pdf; - - $this->extraparams = (array) json_decode($obj->extraparams, true); - - if ($this->statut == 0) $this->brouillon = 1; - - // Retreive all extrafield for invoice - // fetch optionals attributes and labels - if(!class_exists('Extrafields')) - require_once(DOL_DOCUMENT_ROOT.'/core/class/extrafields.class.php'); - $extrafields=new ExtraFields($this->db); - $extralabels=$extrafields->fetch_name_optionals_label('facture',true); - if (count($extralabels)>0) { - $this->array_options = array(); - } - foreach($extrafields->attribute_label as $key=>$label) - { - $this->array_options['options_'.$key]=$label; - } - - /* - * Lines - */ - - $this->lines = array(); - - $result=$this->fetch_lines(); - if ($result < 0) - { - $this->error=$this->db->error(); - dol_syslog(get_class($this)."::fetch Error ".$this->error, LOG_ERR); - return -3; - } - return 1; - } - else - { - $this->error='Bill with id '.$rowid.' or ref '.$ref.' not found sql='.$sql; - dol_syslog(get_class($this)."::fetch Error ".$this->error, LOG_ERR); - return 0; - } - } - else - { - $this->error=$this->db->error(); - dol_syslog(get_class($this)."::fetch Error ".$this->error, LOG_ERR); - return -1; - } - } - - - /** - * Load all detailed lines into this->lines - * - * @return int 1 if OK, < 0 if KO - */ - function fetch_lines() - { - $this->lines=array(); - - $sql = 'SELECT l.rowid, l.fk_product, l.fk_parent_line, l.label as custom_label, l.description, l.product_type, l.price, l.qty, l.tva_tx, '; - $sql.= ' l.localtax1_tx, l.localtax2_tx, l.remise, l.remise_percent, l.fk_remise_except, l.subprice,'; - $sql.= ' l.rang, l.special_code,'; - $sql.= ' l.date_start as date_start, l.date_end as date_end,'; - $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,'; - $sql.= ' p.ref as product_ref, p.fk_product_type as fk_product_type, p.label as product_label, p.description as product_desc'; - $sql.= ' FROM '.MAIN_DB_PREFIX.'facturedet as l'; - $sql.= ' LEFT JOIN '.MAIN_DB_PREFIX.'product as p ON l.fk_product = p.rowid'; - $sql.= ' WHERE l.fk_facture = '.$this->id; - $sql.= ' ORDER BY l.rang'; - - dol_syslog(get_class($this).'::fetch_lines sql='.$sql, LOG_DEBUG); - $result = $this->db->query($sql); - if ($result) - { - $num = $this->db->num_rows($result); - $i = 0; - while ($i < $num) - { - $objp = $this->db->fetch_object($result); - $line = new FactureLigne($this->db); - - $line->rowid = $objp->rowid; - $line->label = $objp->custom_label; - $line->desc = $objp->description; // Description line - $line->product_type = $objp->product_type; // Type of line - $line->product_ref = $objp->product_ref; // Ref product - $line->libelle = $objp->product_label; // TODO deprecated - $line->product_label = $objp->product_label; // Label product - $line->product_desc = $objp->product_desc; // Description product - $line->fk_product_type = $objp->fk_product_type; // Type of product - $line->qty = $objp->qty; - $line->subprice = $objp->subprice; - $line->tva_tx = $objp->tva_tx; - $line->localtax1_tx = $objp->localtax1_tx; - $line->localtax2_tx = $objp->localtax2_tx; - $line->remise_percent = $objp->remise_percent; - $line->fk_remise_except = $objp->fk_remise_except; - $line->fk_product = $objp->fk_product; - $line->date_start = $this->db->jdate($objp->date_start); - $line->date_end = $this->db->jdate($objp->date_end); - $line->date_start = $this->db->jdate($objp->date_start); - $line->date_end = $this->db->jdate($objp->date_end); - $line->info_bits = $objp->info_bits; - $line->total_ht = $objp->total_ht; - $line->total_tva = $objp->total_tva; - $line->total_localtax1 = $objp->total_localtax1; - $line->total_localtax2 = $objp->total_localtax2; - $line->total_ttc = $objp->total_ttc; - $line->code_ventilation = $objp->fk_code_ventilation; - $line->fk_fournprice = $objp->fk_fournprice; - $marginInfos = getMarginInfos($objp->subprice, $objp->remise_percent, $objp->tva_tx, $objp->localtax1_tx, $objp->localtax2_tx, $line->fk_fournprice, $objp->pa_ht); - $line->pa_ht = $marginInfos[0]; - $line->marge_tx = $marginInfos[1]; - $line->marque_tx = $marginInfos[2]; - $line->rang = $objp->rang; - $line->special_code = $objp->special_code; - $line->fk_parent_line = $objp->fk_parent_line; - - // Ne plus utiliser - //$line->price = $objp->price; - //$line->remise = $objp->remise; - - $this->lines[$i] = $line; - - $i++; - } - $this->db->free($result); - return 1; - } - else - { - $this->error=$this->db->error(); - dol_syslog(get_class($this).'::fetch_lines '.$this->error,LOG_ERR); - return -3; - } - } - - - /** - * Update database - * - * @param User $user User that modify - * @param int $notrigger 0=launch triggers after, 1=disable triggers - * @return int <0 if KO, >0 if OK - */ - function update($user=0, $notrigger=0) - { - global $conf, $langs; - $error=0; - - // Clean parameters - if (empty($this->type)) $this->type=0; - if (isset($this->facnumber)) $this->facnumber=trim($this->ref); - if (isset($this->ref_client)) $this->ref_client=trim($this->ref_client); - if (isset($this->increment)) $this->increment=trim($this->increment); - if (isset($this->close_code)) $this->close_code=trim($this->close_code); - if (isset($this->close_note)) $this->close_note=trim($this->close_note); - if (isset($this->note) || isset($this->note_private)) $this->note=(isset($this->note) ? trim($this->note) : trim($this->note_private)); // deprecated - if (isset($this->note) || isset($this->note_private)) $this->note_private=(isset($this->note_private) ? trim($this->note_private) : trim($this->note)); - if (isset($this->note_public)) $this->note_public=trim($this->note_public); - if (isset($this->modelpdf)) $this->modelpdf=trim($this->modelpdf); - if (isset($this->import_key)) $this->import_key=trim($this->import_key); - - // Check parameters - // Put here code to add control on parameters values - - // Update request - $sql = "UPDATE ".MAIN_DB_PREFIX."facture SET"; - - $sql.= " facnumber=".(isset($this->ref)?"'".$this->db->escape($this->ref)."'":"null").","; - $sql.= " type=".(isset($this->type)?$this->type:"null").","; - $sql.= " ref_client=".(isset($this->ref_client)?"'".$this->db->escape($this->ref_client)."'":"null").","; - $sql.= " increment=".(isset($this->increment)?"'".$this->db->escape($this->increment)."'":"null").","; - $sql.= " fk_soc=".(isset($this->socid)?$this->socid:"null").","; - $sql.= " datec=".(strval($this->date_creation)!='' ? "'".$this->db->idate($this->date_creation)."'" : 'null').","; - $sql.= " datef=".(strval($this->date)!='' ? "'".$this->db->idate($this->date)."'" : 'null').","; - $sql.= " date_valid=".(strval($this->date_validation)!='' ? "'".$this->db->idate($this->date_validation)."'" : 'null').","; - $sql.= " paye=".(isset($this->paye)?$this->paye:"null").","; - $sql.= " remise_percent=".(isset($this->remise_percent)?$this->remise_percent:"null").","; - $sql.= " remise_absolue=".(isset($this->remise_absolue)?$this->remise_absolue:"null").","; - //$sql.= " remise=".(isset($this->remise)?$this->remise:"null").","; - $sql.= " close_code=".(isset($this->close_code)?"'".$this->db->escape($this->close_code)."'":"null").","; - $sql.= " close_note=".(isset($this->close_note)?"'".$this->db->escape($this->close_note)."'":"null").","; - $sql.= " tva=".(isset($this->total_tva)?$this->total_tva:"null").","; - $sql.= " localtax1=".(isset($this->total_localtax1)?$this->total_localtax1:"null").","; - $sql.= " localtax2=".(isset($this->total_localtax2)?$this->total_localtax2:"null").","; - $sql.= " total=".(isset($this->total_ht)?$this->total_ht:"null").","; - $sql.= " total_ttc=".(isset($this->total_ttc)?$this->total_ttc:"null").","; - $sql.= " revenuestamp=".((isset($this->revenuestamp) && $this->revenuestamp != '')?$this->revenuestamp:"null").","; - $sql.= " fk_statut=".(isset($this->statut)?$this->statut:"null").","; - $sql.= " fk_user_author=".(isset($this->user_author)?$this->user_author:"null").","; - $sql.= " fk_user_valid=".(isset($this->fk_user_valid)?$this->fk_user_valid:"null").","; - $sql.= " fk_facture_source=".(isset($this->fk_facture_source)?$this->fk_facture_source:"null").","; - $sql.= " fk_projet=".(isset($this->fk_project)?$this->fk_project:"null").","; - $sql.= " fk_cond_reglement=".(isset($this->cond_reglement_id)?$this->cond_reglement_id:"null").","; - $sql.= " fk_mode_reglement=".(isset($this->mode_reglement_id)?$this->mode_reglement_id:"null").","; - $sql.= " date_lim_reglement=".(strval($this->date_lim_reglement)!='' ? "'".$this->db->idate($this->date_lim_reglement)."'" : 'null').","; - $sql.= " note_private=".(isset($this->note_private)?"'".$this->db->escape($this->note_private)."'":"null").","; - $sql.= " note_public=".(isset($this->note_public)?"'".$this->db->escape($this->note_public)."'":"null").","; - $sql.= " model_pdf=".(isset($this->modelpdf)?"'".$this->db->escape($this->modelpdf)."'":"null").","; - $sql.= " import_key=".(isset($this->import_key)?"'".$this->db->escape($this->import_key)."'":"null").""; - - $sql.= " WHERE rowid=".$this->id; - - $this->db->begin(); - - dol_syslog(get_class($this)."::update sql=".$sql, LOG_DEBUG); - $resql = $this->db->query($sql); - if (! $resql) { $error++; $this->errors[]="Error ".$this->db->lasterror(); } - - if (! $error) - { - if (! $notrigger) - { - // Call triggers - include_once DOL_DOCUMENT_ROOT . '/core/class/interfaces.class.php'; - $interface=new Interfaces($this->db); - $result=$interface->run_triggers('BILL_MODIFY',$this,$user,$langs,$conf); - if ($result < 0) { $error++; $this->errors=$interface->errors; } - // End call triggers - } - } - - // Commit or rollback - if ($error) - { - foreach($this->errors as $errmsg) - { - dol_syslog(get_class($this)."::update ".$errmsg, LOG_ERR); - $this->error.=($this->error?', '.$errmsg:$errmsg); - } - $this->db->rollback(); - return -1*$error; - } - else - { - $this->db->commit(); - return 1; - } - } - - - /** - * Add a discount line into invoice using an existing absolute discount - * - * @param int $idremise Id of absolute discount - * @return int >0 if OK, <0 if KO - */ - function insert_discount($idremise) - { - global $langs; - - include_once DOL_DOCUMENT_ROOT.'/core/lib/price.lib.php'; - include_once DOL_DOCUMENT_ROOT.'/core/class/discount.class.php'; - - $this->db->begin(); - - $remise=new DiscountAbsolute($this->db); - $result=$remise->fetch($idremise); - - if ($result > 0) - { - if ($remise->fk_facture) // Protection against multiple submission - { - $this->error=$langs->trans("ErrorDiscountAlreadyUsed"); - $this->db->rollback(); - return -5; - } - - $facligne=new FactureLigne($this->db); - $facligne->fk_facture=$this->id; - $facligne->fk_remise_except=$remise->id; - $facligne->desc=$remise->description; // Description ligne - $facligne->tva_tx=$remise->tva_tx; - $facligne->subprice=-$remise->amount_ht; - $facligne->fk_product=0; // Id produit predefini - $facligne->qty=1; - $facligne->remise_percent=0; - $facligne->rang=-1; - $facligne->info_bits=2; - - $facligne->total_ht = -$remise->amount_ht; - $facligne->total_tva = -$remise->amount_tva; - $facligne->total_ttc = -$remise->amount_ttc; - - $lineid=$facligne->insert(); - if ($lineid > 0) - { - $result=$this->update_price(1); - if ($result > 0) - { - // Create linke between discount and invoice line - $result=$remise->link_to_invoice($lineid,0); - if ($result < 0) - { - $this->error=$remise->error; - $this->db->rollback(); - return -4; - } - - $this->db->commit(); - return 1; - } - else - { - $this->error=$facligne->error; - $this->db->rollback(); - return -1; - } - } - else - { - $this->error=$facligne->error; - $this->db->rollback(); - return -2; - } - } - else - { - $this->db->rollback(); - return -3; - } - } - - /** - * Set customer ref - * - * @param string $ref_client Customer ref - * @return int <0 if KO, >0 if OK - */ - function set_ref_client($ref_client) - { - $sql = 'UPDATE '.MAIN_DB_PREFIX.'facture'; - if (empty($ref_client)) - $sql .= ' SET ref_client = NULL'; - else - $sql .= ' SET ref_client = \''.$this->db->escape($ref_client).'\''; - $sql .= ' WHERE rowid = '.$this->id; - if ($this->db->query($sql)) - { - $this->ref_client = $ref_client; - return 1; - } - else - { - dol_print_error($this->db); - return -1; - } - } - - /** - * Delete invoice - * - * @param int $rowid Id of invoice to delete. If empty, we delete current instance of invoice - * @param int $notrigger 1=Does not execute triggers, 0= execute triggers - * @return int <0 if KO, >0 if OK - */ - function delete($rowid=0, $notrigger=0) - { - global $user,$langs,$conf; - require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php'; - - if (! $rowid) $rowid=$this->id; - - dol_syslog(get_class($this)."::delete rowid=".$rowid, LOG_DEBUG); - - // TODO Test if there is at least on payment. If yes, refuse to delete. - - $error=0; - $this->db->begin(); - - if (! $error && ! $notrigger) - { - // Appel des triggers - include_once DOL_DOCUMENT_ROOT . '/core/class/interfaces.class.php'; - $interface=new Interfaces($this->db); - $result=$interface->run_triggers('BILL_DELETE',$this,$user,$langs,$conf); - if ($result < 0) { - $error++; $this->errors=$interface->errors; - } - // Fin appel triggers - } - - if (! $error) - { - // Delete linked object - $res = $this->deleteObjectLinked(); - if ($res < 0) $error++; - } - - if (! $error) - { - // If invoice was converted into a discount not yet consumed, we remove discount - $sql = 'DELETE FROM '.MAIN_DB_PREFIX.'societe_remise_except'; - $sql.= ' WHERE fk_facture_source = '.$rowid; - $sql.= ' AND fk_facture_line IS NULL'; - $resql=$this->db->query($sql); - - // If invoice has consumned discounts - $this->fetch_lines(); - $list_rowid_det=array(); - foreach($this->lines as $key => $invoiceline) - { - $list_rowid_det[]=$invoiceline->rowid; - } - - // Consumned discounts are freed - if (count($list_rowid_det)) - { - $sql = 'UPDATE '.MAIN_DB_PREFIX.'societe_remise_except'; - $sql.= ' SET fk_facture = NULL, fk_facture_line = NULL'; - $sql.= ' WHERE fk_facture_line IN ('.join(',',$list_rowid_det).')'; - - dol_syslog(get_class($this)."::delete sql=".$sql); - if (! $this->db->query($sql)) - { - $this->error=$this->db->error()." sql=".$sql; - dol_syslog(get_class($this)."::delete ".$this->error, LOG_ERR); - $this->db->rollback(); - return -5; - } - } - - // Delete invoice line - $sql = 'DELETE FROM '.MAIN_DB_PREFIX.'facturedet WHERE fk_facture = '.$rowid; - if ($this->db->query($sql) && $this->delete_linked_contact()) - { - $sql = 'DELETE FROM '.MAIN_DB_PREFIX.'facture WHERE rowid = '.$rowid; - $resql=$this->db->query($sql); - if ($resql) - { - // On efface le repertoire de pdf provisoire - $ref = dol_sanitizeFileName($this->ref); - if ($conf->facture->dir_output) - { - $dir = $conf->facture->dir_output . "/" . $ref; - $file = $conf->facture->dir_output . "/" . $ref . "/" . $ref . ".pdf"; - if (file_exists($file)) // We must delete all files before deleting directory - { - $ret=dol_delete_preview($this); - - if (! dol_delete_file($file,0,0,0,$this)) // For triggers - { - $this->error=$langs->trans("ErrorCanNotDeleteFile",$file); - $this->db->rollback(); - return 0; - } - } - if (file_exists($dir)) - { - if (! dol_delete_dir_recursive($dir)) // For remove dir and meta - { - $this->error=$langs->trans("ErrorCanNotDeleteDir",$dir); - $this->db->rollback(); - return 0; - } - } - } - - $this->db->commit(); - return 1; - } - else - { - $this->error=$this->db->lasterror()." sql=".$sql; - dol_syslog(get_class($this)."::delete ".$this->error, LOG_ERR); - $this->db->rollback(); - return -6; - } - } - else - { - $this->error=$this->db->lasterror()." sql=".$sql; - dol_syslog(get_class($this)."::delete ".$this->error, LOG_ERR); - $this->db->rollback(); - return -4; - } - } - else - { - $this->error=$this->db->lasterror(); - dol_syslog(get_class($this)."::delete ".$this->error, LOG_ERR); - $this->db->rollback(); - return -2; - } - } - - - /** - * Renvoi une date limite de reglement de facture en fonction des - * conditions de reglements de la facture et date de facturation - * - * @param string $cond_reglement Condition of payment (code or id) to use. If 0, we use current condition. - * @return date Date limite de reglement si ok, <0 si ko - */ - function calculate_date_lim_reglement($cond_reglement=0) - { - if (! $cond_reglement) $cond_reglement=$this->cond_reglement_code; - if (! $cond_reglement) $cond_reglement=$this->cond_reglement_id; - - $cdr_nbjour=0; $cdr_fdm=0; $cdr_decalage=0; - - $sqltemp = 'SELECT c.fdm,c.nbjour,c.decalage'; - $sqltemp.= ' FROM '.MAIN_DB_PREFIX.'c_payment_term as c'; - if (is_numeric($cond_reglement)) $sqltemp.= " WHERE c.rowid=".$cond_reglement; - else $sqltemp.= " WHERE c.code='".$this->db->escape($cond_reglement)."'"; - - dol_syslog(get_class($this).'::calculate_date_lim_reglement sql='.$sqltemp); - $resqltemp=$this->db->query($sqltemp); - if ($resqltemp) - { - if ($this->db->num_rows($resqltemp)) - { - $obj = $this->db->fetch_object($resqltemp); - $cdr_nbjour = $obj->nbjour; - $cdr_fdm = $obj->fdm; - $cdr_decalage = $obj->decalage; - } - } - else - { - $this->error=$this->db->error(); - return -1; - } - $this->db->free($resqltemp); - - /* Definition de la date limite */ - - // 1 : ajout du nombre de jours - $datelim = $this->date + ($cdr_nbjour * 3600 * 24); - - // 2 : application de la regle "fin de mois" - if ($cdr_fdm) - { - $mois=date('m', $datelim); - $annee=date('Y', $datelim); - if ($mois == 12) - { - $mois = 1; - $annee += 1; - } - else - { - $mois += 1; - } - // On se deplace au debut du mois suivant, et on retire un jour - $datelim=dol_mktime(12,0,0,$mois,1,$annee); - $datelim -= (3600 * 24); - } - - // 3 : application du decalage - $datelim += ($cdr_decalage * 3600 * 24); - - return $datelim; - } - - /** - * Tag la facture comme paye completement (close_code non renseigne) ou partiellement (close_code renseigne) + appel trigger BILL_PAYED - * - * @param User $user Objet utilisateur qui modifie - * @param string $close_code Code renseigne si on classe a payee completement alors que paiement incomplet (cas escompte par exemple) - * @param string $close_note Commentaire renseigne si on classe a payee alors que paiement incomplet (cas escompte par exemple) - * @return int <0 if KO, >0 if OK - */ - function set_paid($user,$close_code='',$close_note='') - { - global $conf,$langs; - $error=0; - - if ($this->paye != 1) - { - $this->db->begin(); - - dol_syslog(get_class($this)."::set_paid rowid=".$this->id, LOG_DEBUG); - $sql = 'UPDATE '.MAIN_DB_PREFIX.'facture SET'; - $sql.= ' fk_statut=2'; - if (! $close_code) $sql.= ', paye=1'; - if ($close_code) $sql.= ", close_code='".$this->db->escape($close_code)."'"; - if ($close_note) $sql.= ", close_note='".$this->db->escape($close_note)."'"; - $sql.= ' WHERE rowid = '.$this->id; - - $resql = $this->db->query($sql); - if ($resql) - { - // Appel des triggers - include_once DOL_DOCUMENT_ROOT . '/core/class/interfaces.class.php'; - $interface=new Interfaces($this->db); - $result=$interface->run_triggers('BILL_PAYED',$this,$user,$langs,$conf); - if ($result < 0) { $error++; $this->errors=$interface->errors; } - // Fin appel triggers - } - else - { - $error++; - $this->error=$this->db->error(); - dol_print_error($this->db); - } - - if (! $error) - { - $this->db->commit(); - return 1; - } - else - { - $this->db->rollback(); - return -1; - } - } - else - { - return 0; - } - } - - - /** - * Tag la facture comme non payee completement + appel trigger BILL_UNPAYED - * Fonction utilisee quand un paiement prelevement est refuse, - * ou quand une facture annulee et reouverte. - * - * @param User $user Object user that change status - * @return int <0 if KO, >0 if OK - */ - function set_unpaid($user) - { - global $conf,$langs; - $error=0; - - $this->db->begin(); - - $sql = 'UPDATE '.MAIN_DB_PREFIX.'facture'; - $sql.= ' SET paye=0, fk_statut=1, close_code=null, close_note=null'; - $sql.= ' WHERE rowid = '.$this->id; - - dol_syslog(get_class($this)."::set_unpaid sql=".$sql); - $resql = $this->db->query($sql); - if ($resql) - { - // Appel des triggers - include_once DOL_DOCUMENT_ROOT . '/core/class/interfaces.class.php'; - $interface=new Interfaces($this->db); - $result=$interface->run_triggers('BILL_UNPAYED',$this,$user,$langs,$conf); - if ($result < 0) { $error++; $this->errors=$interface->errors; } - // Fin appel triggers - } - else - { - $error++; - $this->error=$this->db->error(); - dol_print_error($this->db); - } - - if (! $error) - { - $this->db->commit(); - return 1; - } - else - { - $this->db->rollback(); - return -1; - } - } - - - /** - * Tag invoice as canceled, with no payment on it (example for replacement invoice or payment never received) + call trigger BILL_CANCEL - * Warning, if option to decrease stock on invoice was set, this function does not change stock (it might be a cancel because - * of no payment even if merchandises were sent). - * - * @param User $user Object user making change - * @param string $close_code Code de fermeture - * @param string $close_note Comment - * @return int <0 if KO, >0 if OK - */ - function set_canceled($user,$close_code='',$close_note='') - { - global $conf,$langs; + // Appel des triggers + include_once DOL_DOCUMENT_ROOT . '/core/class/interfaces.class.php'; + $interface=new Interfaces($this->db); + $result=$interface->run_triggers('BILL_CLONE',$this,$user,$langs,$conf); + if ($result < 0) { + $error++; $this->errors=$interface->errors; + } + // Fin appel triggers + } + + // End + if (! $error) + { + $this->db->commit(); + return $this->id; + } + else + { + $this->db->rollback(); + return -1; + } + } + + /** + * Load an object from an order and create a new invoice into database + * + * @param Object $object Object source + * @return int <0 if KO, 0 if nothing done, 1 if OK + */ + function createFromOrder($object) + { + global $conf,$user,$langs,$hookmanager; $error=0; - dol_syslog(get_class($this)."::set_canceled rowid=".$this->id, LOG_DEBUG); + // Closed order + $this->date = dol_now(); + $this->source = 0; - $this->db->begin(); + $num=count($object->lines); + for ($i = 0; $i < $num; $i++) + { + $line = new FactureLigne($this->db); - $sql = 'UPDATE '.MAIN_DB_PREFIX.'facture SET'; - $sql.= ' fk_statut=3'; - if ($close_code) $sql.= ", close_code='".$this->db->escape($close_code)."'"; - if ($close_note) $sql.= ", close_note='".$this->db->escape($close_note)."'"; - $sql.= ' WHERE rowid = '.$this->id; + $line->libelle = $object->lines[$i]->libelle; + $line->label = $object->lines[$i]->label; + $line->desc = $object->lines[$i]->desc; + $line->subprice = $object->lines[$i]->subprice; + $line->total_ht = $object->lines[$i]->total_ht; + $line->total_tva = $object->lines[$i]->total_tva; + $line->total_ttc = $object->lines[$i]->total_ttc; + $line->tva_tx = $object->lines[$i]->tva_tx; + $line->localtax1_tx = $object->lines[$i]->localtax1_tx; + $line->localtax2_tx = $object->lines[$i]->localtax2_tx; + $line->qty = $object->lines[$i]->qty; + $line->fk_remise_except = $object->lines[$i]->fk_remise_except; + $line->remise_percent = $object->lines[$i]->remise_percent; + $line->fk_product = $object->lines[$i]->fk_product; + $line->info_bits = $object->lines[$i]->info_bits; + $line->product_type = $object->lines[$i]->product_type; + $line->rang = $object->lines[$i]->rang; + $line->special_code = $object->lines[$i]->special_code; + $line->fk_parent_line = $object->lines[$i]->fk_parent_line; - $resql = $this->db->query($sql); - if ($resql) - { - // On desaffecte de la facture les remises liees - // car elles n'ont pas ete utilisees vu que la facture est abandonnee. - $sql = 'UPDATE '.MAIN_DB_PREFIX.'societe_remise_except'; - $sql.= ' SET fk_facture = NULL'; - $sql.= ' WHERE fk_facture = '.$this->id; + $this->lines[$i] = $line; + } - $resql=$this->db->query($sql); - if ($resql) - { - // Appel des triggers - include_once DOL_DOCUMENT_ROOT . '/core/class/interfaces.class.php'; - $interface=new Interfaces($this->db); - $result=$interface->run_triggers('BILL_CANCEL',$this,$user,$langs,$conf); - if ($result < 0) { $error++; $this->errors=$interface->errors; } - // Fin appel triggers + $this->socid = $object->socid; + $this->fk_project = $object->fk_project; + $this->cond_reglement_id = $object->cond_reglement_id; + $this->mode_reglement_id = $object->mode_reglement_id; + $this->availability_id = $object->availability_id; + $this->demand_reason_id = $object->demand_reason_id; + $this->date_livraison = $object->date_livraison; + $this->fk_delivery_address = $object->fk_delivery_address; + $this->contact_id = $object->contactid; + $this->ref_client = $object->ref_client; + $this->note_private = $object->note_private; + $this->note_public = $object->note_public; - $this->db->commit(); - return 1; - } - else - { - $this->error=$this->db->error()." sql=".$sql; - $this->db->rollback(); - return -1; - } - } - else - { - $this->error=$this->db->error()." sql=".$sql; - $this->db->rollback(); - return -2; - } - } + $this->origin = $object->element; + $this->origin_id = $object->id; - /** - * Tag invoice as validated + call trigger BILL_VALIDATE - * Object must have lines loaded with fetch_lines - * - * @param User $user Object user that validate - * @param string $force_number Reference to force on invoice - * @param int $idwarehouse Id of warehouse to use for stock decrease - * @return int <0 if KO, >0 if OK - */ - function validate($user, $force_number='', $idwarehouse=0) - { - global $conf,$langs; - require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php'; + // Possibility to add external linked objects with hooks + $this->linked_objects[$this->origin] = $this->origin_id; + if (! empty($object->other_linked_objects) && is_array($object->other_linked_objects)) + { + $this->linked_objects = array_merge($this->linked_objects, $object->other_linked_objects); + } - $now=dol_now(); + $ret = $this->create($user); - $error=0; - dol_syslog(get_class($this).'::validate user='.$user->id.', force_number='.$force_number.', idwarehouse='.$idwarehouse); + if ($ret > 0) + { + // Actions hooked (by external module) + $hookmanager->initHooks(array('invoicedao')); - // Check parameters - if (! $this->brouillon) - { - dol_syslog(get_class($this)."::validate no draft status", LOG_WARNING); - return 0; - } + $parameters=array('objFrom'=>$object); + $action=''; + $reshook=$hookmanager->executeHooks('createFrom',$parameters,$this,$action); // Note that $action and $object may have been modified by some hooks + if ($reshook < 0) $error++; - if (! $user->rights->facture->valider) - { - $this->error='Permission denied'; - dol_syslog(get_class($this)."::validate ".$this->error, LOG_ERR); - return -1; - } + if (! $error) + { + return 1; + } + else return -1; + } + else return -1; + } - $this->db->begin(); + /** + * Return clicable link of object (with eventually picto) + * + * @param int $withpicto Add picto into link + * @param string $option Where point the link + * @param int $max Maxlength of ref + * @param int $short 1=Return just URL + * @param string $moretitle Add more text to title tooltip + * @return string String with URL + */ + function getNomUrl($withpicto=0,$option='',$max=0,$short=0,$moretitle='') + { + global $langs; - $this->fetch_thirdparty(); - $this->fetch_lines(); + $result=''; - // Check parameters - if ($this->type == 1) // si facture de remplacement - { - // Controle que facture source connue - if ($this->fk_facture_source <= 0) - { - $this->error=$langs->trans("ErrorFieldRequired",$langs->trans("InvoiceReplacement")); - $this->db->rollback(); - return -10; - } + if ($option == 'withdraw') $url = DOL_URL_ROOT.'/compta/facture/prelevement.php?facid='.$this->id; + else $url = DOL_URL_ROOT.'/compta/facture.php?facid='.$this->id; - // Charge la facture source a remplacer - $facreplaced=new Facture($this->db); - $result=$facreplaced->fetch($this->fk_facture_source); - if ($result <= 0) - { - $this->error=$langs->trans("ErrorBadInvoice"); - $this->db->rollback(); - return -11; - } + if ($short) return $url; - // Controle que facture source non deja remplacee par une autre - $idreplacement=$facreplaced->getIdReplacingInvoice('validated'); - if ($idreplacement && $idreplacement != $this->id) - { - $facreplacement=new Facture($this->db); - $facreplacement->fetch($idreplacement); - $this->error=$langs->trans("ErrorInvoiceAlreadyReplaced",$facreplaced->ref,$facreplacement->ref); - $this->db->rollback(); - return -12; - } + $picto='bill'; + if ($this->type == 1) $picto.='r'; // Replacement invoice + if ($this->type == 2) $picto.='a'; // Credit note + if ($this->type == 3) $picto.='d'; // Deposit invoice - $result=$facreplaced->set_canceled($user,'replaced',''); - if ($result < 0) - { - $this->error=$facreplaced->error; - $this->db->rollback(); - return -13; - } - } + $label=$langs->trans("ShowInvoice").': '.$this->ref; + if ($this->type == 1) $label=$langs->transnoentitiesnoconv("ShowInvoiceReplace").': '.$this->ref; + if ($this->type == 2) $label=$langs->transnoentitiesnoconv("ShowInvoiceAvoir").': '.$this->ref; + if ($this->type == 3) $label=$langs->transnoentitiesnoconv("ShowInvoiceDeposit").': '.$this->ref; + if ($moretitle) $label.=' - '.$moretitle; - // Define new ref - if ($force_number) - { - $num = $force_number; - } - else if (preg_match('/^[\(]?PROV/i', $this->ref)) - { - if (! empty($conf->global->FAC_FORCE_DATE_VALIDATION)) // If option enabled, we force invoice date - { - $this->date=dol_now(); - $this->date_lim_reglement=$this->calculate_date_lim_reglement(); - } - $num = $this->getNextNumRef($this->client); - } - else - { - $num = $this->ref; - } + //$linkstart=''; + $linkstart=''; + $linkend=''; - if ($num) - { - $this->update_price(1); + if ($withpicto) $result.=($linkstart.img_object(($max?dol_trunc($label,$max):$label),$picto).$linkend); + if ($withpicto && $withpicto != 2) $result.=' '; + if ($withpicto != 2) $result.=$linkstart.($max?dol_trunc($this->ref,$max):$this->ref).$linkend; + return $result; + } - // Validate - $sql = 'UPDATE '.MAIN_DB_PREFIX.'facture'; - $sql.= " SET facnumber='".$num."', fk_statut = 1, fk_user_valid = ".$user->id.", date_valid = '".$this->db->idate($now)."'"; - if (! empty($conf->global->FAC_FORCE_DATE_VALIDATION)) // If option enabled, we force invoice date - { - $sql.= ', datef='.$this->db->idate($this->date); - $sql.= ', date_lim_reglement='.$this->db->idate($this->date_lim_reglement); - } - $sql.= ' WHERE rowid = '.$this->id; - dol_syslog(get_class($this)."::validate sql=".$sql); - $resql=$this->db->query($sql); - if (! $resql) - { - dol_syslog(get_class($this)."::validate Echec update - 10 - sql=".$sql, LOG_ERR); - dol_print_error($this->db); - $error++; - } + /** + * Get object and lines from database + * + * @param int $rowid Id of object to load + * @param string $ref Reference of invoice + * @param string $ref_ext External reference of invoice + * @param int $ref_int Internal reference of other object + * @return int >0 if OK, <0 if KO, 0 if not found + */ + function fetch($rowid, $ref='', $ref_ext='', $ref_int='') + { + global $conf; - // On verifie si la facture etait une provisoire - if (! $error && (preg_match('/^[\(]?PROV/i', $this->ref))) - { - // La verif qu'une remise n'est pas utilisee 2 fois est faite au moment de l'insertion de ligne - } + if (empty($rowid) && empty($ref) && empty($ref_ext) && empty($ref_int)) return -1; - if (! $error) - { - // Define third party as a customer - $result=$this->client->set_as_client(); + $sql = 'SELECT f.rowid,f.facnumber,f.ref_client,f.ref_ext,f.ref_int,f.type,f.fk_soc,f.amount,f.tva, f.localtax1, f.localtax2, f.total, f.total_ttc, f.revenuestamp'; + $sql.= ', f.remise_percent, f.remise_absolue, f.remise'; + $sql.= ', f.datef as df'; + $sql.= ', f.date_lim_reglement as dlr'; + $sql.= ', f.datec as datec'; + $sql.= ', f.date_valid as datev'; + $sql.= ', f.tms as datem'; + $sql.= ', f.note_private, f.note_public, f.fk_statut, f.paye, f.close_code, f.close_note, f.fk_user_author, f.fk_user_valid, f.model_pdf'; + $sql.= ', f.fk_facture_source'; + $sql.= ', f.fk_mode_reglement, f.fk_cond_reglement, f.fk_projet, f.extraparams'; + $sql.= ', p.code as mode_reglement_code, p.libelle as mode_reglement_libelle'; + $sql.= ', c.code as cond_reglement_code, c.libelle as cond_reglement_libelle, c.libelle_facture as cond_reglement_libelle_doc'; + $sql.= ' FROM '.MAIN_DB_PREFIX.'facture as f'; + $sql.= ' LEFT JOIN '.MAIN_DB_PREFIX.'c_payment_term as c ON f.fk_cond_reglement = c.rowid'; + $sql.= ' LEFT JOIN '.MAIN_DB_PREFIX.'c_paiement as p ON f.fk_mode_reglement = p.id'; + $sql.= ' WHERE f.entity = '.$conf->entity; + if ($rowid) $sql.= " AND f.rowid=".$rowid; + if ($ref) $sql.= " AND f.facnumber='".$this->db->escape($ref)."'"; + if ($ref_ext) $sql.= " AND f.ref_ext='".$this->db->escape($ref_ext)."'"; + if ($ref_int) $sql.= " AND f.ref_int='".$this->db->escape($ref_int)."'"; - // Si active on decremente le produit principal et ses composants a la validation de facture - if ($this->type != 3 && $result >= 0 && ! empty($conf->stock->enabled) && ! empty($conf->global->STOCK_CALCULATE_ON_BILL)) - { - require_once DOL_DOCUMENT_ROOT.'/product/stock/class/mouvementstock.class.php'; - $langs->load("agenda"); + dol_syslog(get_class($this)."::fetch sql=".$sql, LOG_DEBUG); + $result = $this->db->query($sql); + if ($result) + { + if ($this->db->num_rows($result)) + { + $obj = $this->db->fetch_object($result); - // Loop on each line - $cpt=count($this->lines); - for ($i = 0; $i < $cpt; $i++) - { - if ($this->lines[$i]->fk_product > 0) - { - $mouvP = new MouvementStock($this->db); - // We decrease stock for product - if ($this->type == 2) $result=$mouvP->reception($user, $this->lines[$i]->fk_product, $idwarehouse, $this->lines[$i]->qty, $this->lines[$i]->subprice, $langs->trans("InvoiceValidatedInDolibarr",$num)); - else $result=$mouvP->livraison($user, $this->lines[$i]->fk_product, $idwarehouse, $this->lines[$i]->qty, $this->lines[$i]->subprice, $langs->trans("InvoiceValidatedInDolibarr",$num)); - if ($result < 0) { $error++; } - } - } - } - } + $this->id = $obj->rowid; + $this->ref = $obj->facnumber; + $this->ref_client = $obj->ref_client; + $this->ref_ext = $obj->ref_ext; + $this->ref_int = $obj->ref_int; + $this->type = $obj->type; + $this->date = $this->db->jdate($obj->df); + $this->date_creation = $this->db->jdate($obj->datec); + $this->date_validation = $this->db->jdate($obj->datev); + $this->datem = $this->db->jdate($obj->datem); + $this->remise_percent = $obj->remise_percent; + $this->remise_absolue = $obj->remise_absolue; + //$this->remise = $obj->remise; + $this->total_ht = $obj->total; + $this->total_tva = $obj->tva; + $this->total_localtax1 = $obj->localtax1; + $this->total_localtax2 = $obj->localtax2; + $this->total_ttc = $obj->total_ttc; + $this->revenuestamp = $obj->revenuestamp; + $this->paye = $obj->paye; + $this->close_code = $obj->close_code; + $this->close_note = $obj->close_note; + $this->socid = $obj->fk_soc; + $this->statut = $obj->fk_statut; + $this->date_lim_reglement = $this->db->jdate($obj->dlr); + $this->mode_reglement_id = $obj->fk_mode_reglement; + $this->mode_reglement_code = $obj->mode_reglement_code; + $this->mode_reglement = $obj->mode_reglement_libelle; + $this->cond_reglement_id = $obj->fk_cond_reglement; + $this->cond_reglement_code = $obj->cond_reglement_code; + $this->cond_reglement = $obj->cond_reglement_libelle; + $this->cond_reglement_doc = $obj->cond_reglement_libelle_doc; + $this->fk_project = $obj->fk_projet; + $this->fk_facture_source = $obj->fk_facture_source; + $this->note = $obj->note_private; // deprecated + $this->note_private = $obj->note_private; + $this->note_public = $obj->note_public; + $this->user_author = $obj->fk_user_author; + $this->user_valid = $obj->fk_user_valid; + $this->modelpdf = $obj->model_pdf; - if (! $error) - { - $this->oldref = ''; + $this->extraparams = (array) json_decode($obj->extraparams, true); - // Rename directory if dir was a temporary ref - if (preg_match('/^[\(]?PROV/i', $this->ref)) - { - // On renomme repertoire facture ($this->ref = ancienne ref, $num = nouvelle ref) - // afin de ne pas perdre les fichiers attaches - $facref = dol_sanitizeFileName($this->ref); - $snumfa = dol_sanitizeFileName($num); - $dirsource = $conf->facture->dir_output.'/'.$facref; - $dirdest = $conf->facture->dir_output.'/'.$snumfa; - if (file_exists($dirsource)) - { - dol_syslog(get_class($this)."::validate rename dir ".$dirsource." into ".$dirdest); + if ($this->statut == 0) $this->brouillon = 1; - if (@rename($dirsource, $dirdest)) - { - $this->oldref = $facref; + // Retreive all extrafield for invoice + // fetch optionals attributes and labels + if(!class_exists('Extrafields')) + require_once(DOL_DOCUMENT_ROOT.'/core/class/extrafields.class.php'); + $extrafields=new ExtraFields($this->db); + $extralabels=$extrafields->fetch_name_optionals_label('facture',true); + if (count($extralabels)>0) { + $this->array_options = array(); + } + foreach($extrafields->attribute_label as $key=>$label) + { + $this->array_options['options_'.$key]=$label; + } - dol_syslog("Rename ok"); - // Suppression ancien fichier PDF dans nouveau rep - dol_delete_file($conf->facture->dir_output.'/'.$snumfa.'/'.$facref.'*.*'); - } - } - } - } + /* + * Lines + */ - // Set new ref and define current statut - if (! $error) - { - $this->ref = $num; - $this->facnumber=$num; - $this->statut=1; - $this->brouillon=0; - $this->date_validation=$now; - } + $this->lines = array(); - // Trigger calls - if (! $error) - { - // Appel des triggers - include_once DOL_DOCUMENT_ROOT . '/core/class/interfaces.class.php'; - $interface=new Interfaces($this->db); - $result=$interface->run_triggers('BILL_VALIDATE',$this,$user,$langs,$conf); - if ($result < 0) { $error++; $this->errors=$interface->errors; } - // Fin appel triggers - } - } - else - { - $error++; - } + $result=$this->fetch_lines(); + if ($result < 0) + { + $this->error=$this->db->error(); + dol_syslog(get_class($this)."::fetch Error ".$this->error, LOG_ERR); + return -3; + } + return 1; + } + else + { + $this->error='Bill with id '.$rowid.' or ref '.$ref.' not found sql='.$sql; + dol_syslog(get_class($this)."::fetch Error ".$this->error, LOG_ERR); + return 0; + } + } + else + { + $this->error=$this->db->error(); + dol_syslog(get_class($this)."::fetch Error ".$this->error, LOG_ERR); + return -1; + } + } - if (! $error) - { - $this->db->commit(); - return 1; - } - else - { - $this->db->rollback(); - $this->error=$this->db->lasterror(); - return -1; - } - } - /** - * Set draft status - * - * @param User $user Object user that modify - * @param int $idwarehouse Id warehouse to use for stock change. - * @return int <0 if KO, >0 if OK - */ - function set_draft($user,$idwarehouse=-1) - { - global $conf,$langs; + /** + * Load all detailed lines into this->lines + * + * @return int 1 if OK, < 0 if KO + */ + function fetch_lines() + { + $this->lines=array(); - $error=0; + $sql = 'SELECT l.rowid, l.fk_product, l.fk_parent_line, l.label as custom_label, l.description, l.product_type, l.price, l.qty, l.tva_tx, '; + $sql.= ' l.localtax1_tx, l.localtax2_tx, l.remise, l.remise_percent, l.fk_remise_except, l.subprice,'; + $sql.= ' l.rang, l.special_code,'; + $sql.= ' l.date_start as date_start, l.date_end as date_end,'; + $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,'; + $sql.= ' p.ref as product_ref, p.fk_product_type as fk_product_type, p.label as product_label, p.description as product_desc'; + $sql.= ' FROM '.MAIN_DB_PREFIX.'facturedet as l'; + $sql.= ' LEFT JOIN '.MAIN_DB_PREFIX.'product as p ON l.fk_product = p.rowid'; + $sql.= ' WHERE l.fk_facture = '.$this->id; + $sql.= ' ORDER BY l.rang'; - if ($this->statut == 0) - { - dol_syslog(get_class($this)."::set_draft already draft status", LOG_WARNING); - return 0; - } + dol_syslog(get_class($this).'::fetch_lines sql='.$sql, LOG_DEBUG); + $result = $this->db->query($sql); + if ($result) + { + $num = $this->db->num_rows($result); + $i = 0; + while ($i < $num) + { + $objp = $this->db->fetch_object($result); + $line = new FactureLigne($this->db); - $this->db->begin(); + $line->rowid = $objp->rowid; + $line->label = $objp->custom_label; + $line->desc = $objp->description; // Description line + $line->product_type = $objp->product_type; // Type of line + $line->product_ref = $objp->product_ref; // Ref product + $line->libelle = $objp->product_label; // TODO deprecated + $line->product_label = $objp->product_label; // Label product + $line->product_desc = $objp->product_desc; // Description product + $line->fk_product_type = $objp->fk_product_type; // Type of product + $line->qty = $objp->qty; + $line->subprice = $objp->subprice; + $line->tva_tx = $objp->tva_tx; + $line->localtax1_tx = $objp->localtax1_tx; + $line->localtax2_tx = $objp->localtax2_tx; + $line->remise_percent = $objp->remise_percent; + $line->fk_remise_except = $objp->fk_remise_except; + $line->fk_product = $objp->fk_product; + $line->date_start = $this->db->jdate($objp->date_start); + $line->date_end = $this->db->jdate($objp->date_end); + $line->date_start = $this->db->jdate($objp->date_start); + $line->date_end = $this->db->jdate($objp->date_end); + $line->info_bits = $objp->info_bits; + $line->total_ht = $objp->total_ht; + $line->total_tva = $objp->total_tva; + $line->total_localtax1 = $objp->total_localtax1; + $line->total_localtax2 = $objp->total_localtax2; + $line->total_ttc = $objp->total_ttc; + $line->code_ventilation = $objp->fk_code_ventilation; + $line->fk_fournprice = $objp->fk_fournprice; + $marginInfos = getMarginInfos($objp->subprice, $objp->remise_percent, $objp->tva_tx, $objp->localtax1_tx, $objp->localtax2_tx, $line->fk_fournprice, $objp->pa_ht); + $line->pa_ht = $marginInfos[0]; + $line->marge_tx = $marginInfos[1]; + $line->marque_tx = $marginInfos[2]; + $line->rang = $objp->rang; + $line->special_code = $objp->special_code; + $line->fk_parent_line = $objp->fk_parent_line; - $sql = "UPDATE ".MAIN_DB_PREFIX."facture"; - $sql.= " SET fk_statut = 0"; - $sql.= " WHERE rowid = ".$this->id; + // Ne plus utiliser + //$line->price = $objp->price; + //$line->remise = $objp->remise; - dol_syslog(get_class($this)."::set_draft sql=".$sql, LOG_DEBUG); - $result=$this->db->query($sql); - if ($result) - { - // Si on decremente le produit principal et ses composants a la validation de facture, on réincrement - if ($this->type != 3 && $result >= 0 && ! empty($conf->stock->enabled) && ! empty($conf->global->STOCK_CALCULATE_ON_BILL)) - { - require_once DOL_DOCUMENT_ROOT.'/product/stock/class/mouvementstock.class.php'; - $langs->load("agenda"); + $this->lines[$i] = $line; - $num=count($this->lines); - for ($i = 0; $i < $num; $i++) - { - if ($this->lines[$i]->fk_product > 0) - { - $mouvP = new MouvementStock($this->db); - // We decrease stock for product - if ($this->type == 2) $result=$mouvP->livraison($user, $this->lines[$i]->fk_product, $idwarehouse, $this->lines[$i]->qty, $this->lines[$i]->subprice, $langs->trans("InvoiceBackToDraftInDolibarr",$this->ref)); - else $result=$mouvP->reception($user, $this->lines[$i]->fk_product, $idwarehouse, $this->lines[$i]->qty, 0, $langs->trans("InvoiceBackToDraftInDolibarr",$this->ref)); // we use 0 for price, to not change the weighted average value - } - } - } + $i++; + } + $this->db->free($result); + return 1; + } + else + { + $this->error=$this->db->error(); + dol_syslog(get_class($this).'::fetch_lines '.$this->error,LOG_ERR); + return -3; + } + } + + + /** + * Update database + * + * @param User $user User that modify + * @param int $notrigger 0=launch triggers after, 1=disable triggers + * @return int <0 if KO, >0 if OK + */ + function update($user=0, $notrigger=0) + { + global $conf, $langs; + $error=0; + + // Clean parameters + if (empty($this->type)) $this->type=0; + if (isset($this->facnumber)) $this->facnumber=trim($this->ref); + if (isset($this->ref_client)) $this->ref_client=trim($this->ref_client); + if (isset($this->increment)) $this->increment=trim($this->increment); + if (isset($this->close_code)) $this->close_code=trim($this->close_code); + if (isset($this->close_note)) $this->close_note=trim($this->close_note); + if (isset($this->note) || isset($this->note_private)) $this->note=(isset($this->note) ? trim($this->note) : trim($this->note_private)); // deprecated + if (isset($this->note) || isset($this->note_private)) $this->note_private=(isset($this->note_private) ? trim($this->note_private) : trim($this->note)); + if (isset($this->note_public)) $this->note_public=trim($this->note_public); + if (isset($this->modelpdf)) $this->modelpdf=trim($this->modelpdf); + if (isset($this->import_key)) $this->import_key=trim($this->import_key); + + // Check parameters + // Put here code to add control on parameters values + + // Update request + $sql = "UPDATE ".MAIN_DB_PREFIX."facture SET"; + + $sql.= " facnumber=".(isset($this->ref)?"'".$this->db->escape($this->ref)."'":"null").","; + $sql.= " type=".(isset($this->type)?$this->type:"null").","; + $sql.= " ref_client=".(isset($this->ref_client)?"'".$this->db->escape($this->ref_client)."'":"null").","; + $sql.= " increment=".(isset($this->increment)?"'".$this->db->escape($this->increment)."'":"null").","; + $sql.= " fk_soc=".(isset($this->socid)?$this->socid:"null").","; + $sql.= " datec=".(strval($this->date_creation)!='' ? "'".$this->db->idate($this->date_creation)."'" : 'null').","; + $sql.= " datef=".(strval($this->date)!='' ? "'".$this->db->idate($this->date)."'" : 'null').","; + $sql.= " date_valid=".(strval($this->date_validation)!='' ? "'".$this->db->idate($this->date_validation)."'" : 'null').","; + $sql.= " paye=".(isset($this->paye)?$this->paye:"null").","; + $sql.= " remise_percent=".(isset($this->remise_percent)?$this->remise_percent:"null").","; + $sql.= " remise_absolue=".(isset($this->remise_absolue)?$this->remise_absolue:"null").","; + //$sql.= " remise=".(isset($this->remise)?$this->remise:"null").","; + $sql.= " close_code=".(isset($this->close_code)?"'".$this->db->escape($this->close_code)."'":"null").","; + $sql.= " close_note=".(isset($this->close_note)?"'".$this->db->escape($this->close_note)."'":"null").","; + $sql.= " tva=".(isset($this->total_tva)?$this->total_tva:"null").","; + $sql.= " localtax1=".(isset($this->total_localtax1)?$this->total_localtax1:"null").","; + $sql.= " localtax2=".(isset($this->total_localtax2)?$this->total_localtax2:"null").","; + $sql.= " total=".(isset($this->total_ht)?$this->total_ht:"null").","; + $sql.= " total_ttc=".(isset($this->total_ttc)?$this->total_ttc:"null").","; + $sql.= " revenuestamp=".((isset($this->revenuestamp) && $this->revenuestamp != '')?$this->revenuestamp:"null").","; + $sql.= " fk_statut=".(isset($this->statut)?$this->statut:"null").","; + $sql.= " fk_user_author=".(isset($this->user_author)?$this->user_author:"null").","; + $sql.= " fk_user_valid=".(isset($this->fk_user_valid)?$this->fk_user_valid:"null").","; + $sql.= " fk_facture_source=".(isset($this->fk_facture_source)?$this->fk_facture_source:"null").","; + $sql.= " fk_projet=".(isset($this->fk_project)?$this->fk_project:"null").","; + $sql.= " fk_cond_reglement=".(isset($this->cond_reglement_id)?$this->cond_reglement_id:"null").","; + $sql.= " fk_mode_reglement=".(isset($this->mode_reglement_id)?$this->mode_reglement_id:"null").","; + $sql.= " date_lim_reglement=".(strval($this->date_lim_reglement)!='' ? "'".$this->db->idate($this->date_lim_reglement)."'" : 'null').","; + $sql.= " note_private=".(isset($this->note_private)?"'".$this->db->escape($this->note_private)."'":"null").","; + $sql.= " note_public=".(isset($this->note_public)?"'".$this->db->escape($this->note_public)."'":"null").","; + $sql.= " model_pdf=".(isset($this->modelpdf)?"'".$this->db->escape($this->modelpdf)."'":"null").","; + $sql.= " import_key=".(isset($this->import_key)?"'".$this->db->escape($this->import_key)."'":"null").""; + + $sql.= " WHERE rowid=".$this->id; + + $this->db->begin(); + + dol_syslog(get_class($this)."::update sql=".$sql, LOG_DEBUG); + $resql = $this->db->query($sql); + if (! $resql) { + $error++; $this->errors[]="Error ".$this->db->lasterror(); + } + + if (! $error) + { + if (! $notrigger) + { + // Call triggers + include_once DOL_DOCUMENT_ROOT . '/core/class/interfaces.class.php'; + $interface=new Interfaces($this->db); + $result=$interface->run_triggers('BILL_MODIFY',$this,$user,$langs,$conf); + if ($result < 0) { + $error++; $this->errors=$interface->errors; + } + // End call triggers + } + } + + // Commit or rollback + if ($error) + { + foreach($this->errors as $errmsg) + { + dol_syslog(get_class($this)."::update ".$errmsg, LOG_ERR); + $this->error.=($this->error?', '.$errmsg:$errmsg); + } + $this->db->rollback(); + return -1*$error; + } + else + { + $this->db->commit(); + return 1; + } + } + + + /** + * Add a discount line into invoice using an existing absolute discount + * + * @param int $idremise Id of absolute discount + * @return int >0 if OK, <0 if KO + */ + function insert_discount($idremise) + { + global $langs; + + include_once DOL_DOCUMENT_ROOT.'/core/lib/price.lib.php'; + include_once DOL_DOCUMENT_ROOT.'/core/class/discount.class.php'; + + $this->db->begin(); + + $remise=new DiscountAbsolute($this->db); + $result=$remise->fetch($idremise); + + if ($result > 0) + { + if ($remise->fk_facture) // Protection against multiple submission + { + $this->error=$langs->trans("ErrorDiscountAlreadyUsed"); + $this->db->rollback(); + return -5; + } + + $facligne=new FactureLigne($this->db); + $facligne->fk_facture=$this->id; + $facligne->fk_remise_except=$remise->id; + $facligne->desc=$remise->description; // Description ligne + $facligne->tva_tx=$remise->tva_tx; + $facligne->subprice=-$remise->amount_ht; + $facligne->fk_product=0; // Id produit predefini + $facligne->qty=1; + $facligne->remise_percent=0; + $facligne->rang=-1; + $facligne->info_bits=2; + + $facligne->total_ht = -$remise->amount_ht; + $facligne->total_tva = -$remise->amount_tva; + $facligne->total_ttc = -$remise->amount_ttc; + + $lineid=$facligne->insert(); + if ($lineid > 0) + { + $result=$this->update_price(1); + if ($result > 0) + { + // Create linke between discount and invoice line + $result=$remise->link_to_invoice($lineid,0); + if ($result < 0) + { + $this->error=$remise->error; + $this->db->rollback(); + return -4; + } + + $this->db->commit(); + return 1; + } + else + { + $this->error=$facligne->error; + $this->db->rollback(); + return -1; + } + } + else + { + $this->error=$facligne->error; + $this->db->rollback(); + return -2; + } + } + else + { + $this->db->rollback(); + return -3; + } + } + + /** + * Set customer ref + * + * @param string $ref_client Customer ref + * @return int <0 if KO, >0 if OK + */ + function set_ref_client($ref_client) + { + $sql = 'UPDATE '.MAIN_DB_PREFIX.'facture'; + if (empty($ref_client)) + $sql .= ' SET ref_client = NULL'; + else + $sql .= ' SET ref_client = \''.$this->db->escape($ref_client).'\''; + $sql .= ' WHERE rowid = '.$this->id; + if ($this->db->query($sql)) + { + $this->ref_client = $ref_client; + return 1; + } + else + { + dol_print_error($this->db); + return -1; + } + } + + /** + * Delete invoice + * + * @param int $rowid Id of invoice to delete. If empty, we delete current instance of invoice + * @param int $notrigger 1=Does not execute triggers, 0= execute triggers + * @param int $idwarehouse Id warehouse to use for stock change. + * @return int <0 if KO, >0 if OK + */ + function delete($rowid=0, $notrigger=0, $idwarehouse=-1) + { + global $user,$langs,$conf; + require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php'; + + if (empty($rowid)) $rowid=$this->id; + + dol_syslog(get_class($this)."::delete rowid=".$rowid, LOG_DEBUG); + + // TODO Test if there is at least on payment. If yes, refuse to delete. + + $error=0; + $this->db->begin(); + + if (! $error && ! $notrigger) + { + // Appel des triggers + include_once DOL_DOCUMENT_ROOT . '/core/class/interfaces.class.php'; + $interface=new Interfaces($this->db); + $result=$interface->run_triggers('BILL_DELETE',$this,$user,$langs,$conf); + if ($result < 0) { + $error++; $this->errors=$interface->errors; + } + // Fin appel triggers + } + + if (! $error) + { + // Delete linked object + $res = $this->deleteObjectLinked(); + if ($res < 0) $error++; + } + + if (! $error) + { + // If invoice was converted into a discount not yet consumed, we remove discount + $sql = 'DELETE FROM '.MAIN_DB_PREFIX.'societe_remise_except'; + $sql.= ' WHERE fk_facture_source = '.$rowid; + $sql.= ' AND fk_facture_line IS NULL'; + $resql=$this->db->query($sql); + + // If invoice has consumned discounts + $this->fetch_lines(); + $list_rowid_det=array(); + foreach($this->lines as $key => $invoiceline) + { + $list_rowid_det[]=$invoiceline->rowid; + } + + // Consumned discounts are freed + if (count($list_rowid_det)) + { + $sql = 'UPDATE '.MAIN_DB_PREFIX.'societe_remise_except'; + $sql.= ' SET fk_facture = NULL, fk_facture_line = NULL'; + $sql.= ' WHERE fk_facture_line IN ('.join(',',$list_rowid_det).')'; + + dol_syslog(get_class($this)."::delete sql=".$sql); + if (! $this->db->query($sql)) + { + $this->error=$this->db->error()." sql=".$sql; + dol_syslog(get_class($this)."::delete ".$this->error, LOG_ERR); + $this->db->rollback(); + return -5; + } + } + + // If we decrament stock on invoice validation, we increment + if ($this->type != 3 && $result >= 0 && ! empty($conf->stock->enabled) && ! empty($conf->global->STOCK_CALCULATE_ON_DELETE_INVOICE)) + { + require_once DOL_DOCUMENT_ROOT.'/product/stock/class/mouvementstock.class.php'; + $langs->load("agenda"); + + $num=count($this->lines); + for ($i = 0; $i < $num; $i++) + { + if ($this->lines[$i]->fk_product > 0) + { + $mouvP = new MouvementStock($this->db); + // We decrease stock for product + if ($this->type == 2) $result=$mouvP->livraison($user, $this->lines[$i]->fk_product, $idwarehouse, $this->lines[$i]->qty, $this->lines[$i]->subprice, $langs->trans("InvoiceDeleteDolibarr",$this->ref)); + else $result=$mouvP->reception($user, $this->lines[$i]->fk_product, $idwarehouse, $this->lines[$i]->qty, 0, $langs->trans("InvoiceDeleteDolibarr",$this->ref)); // we use 0 for price, to not change the weighted average value + } + } + } + + + // Delete invoice line + $sql = 'DELETE FROM '.MAIN_DB_PREFIX.'facturedet WHERE fk_facture = '.$rowid; + if ($this->db->query($sql) && $this->delete_linked_contact()) + { + $sql = 'DELETE FROM '.MAIN_DB_PREFIX.'facture WHERE rowid = '.$rowid; + $resql=$this->db->query($sql); + if ($resql) + { + // On efface le repertoire de pdf provisoire + $ref = dol_sanitizeFileName($this->ref); + if ($conf->facture->dir_output) + { + $dir = $conf->facture->dir_output . "/" . $ref; + $file = $conf->facture->dir_output . "/" . $ref . "/" . $ref . ".pdf"; + if (file_exists($file)) // We must delete all files before deleting directory + { + $ret=dol_delete_preview($this); + + if (! dol_delete_file($file,0,0,0,$this)) // For triggers + { + $this->error=$langs->trans("ErrorCanNotDeleteFile",$file); + $this->db->rollback(); + return 0; + } + } + if (file_exists($dir)) + { + if (! dol_delete_dir_recursive($dir)) // For remove dir and meta + { + $this->error=$langs->trans("ErrorCanNotDeleteDir",$dir); + $this->db->rollback(); + return 0; + } + } + } + + $this->db->commit(); + return 1; + } + else + { + $this->error=$this->db->lasterror()." sql=".$sql; + dol_syslog(get_class($this)."::delete ".$this->error, LOG_ERR); + $this->db->rollback(); + return -6; + } + } + else + { + $this->error=$this->db->lasterror()." sql=".$sql; + dol_syslog(get_class($this)."::delete ".$this->error, LOG_ERR); + $this->db->rollback(); + return -4; + } + } + else + { + $this->error=$this->db->lasterror(); + dol_syslog(get_class($this)."::delete ".$this->error, LOG_ERR); + $this->db->rollback(); + return -2; + } + } + + + /** + * Renvoi une date limite de reglement de facture en fonction des + * conditions de reglements de la facture et date de facturation + * + * @param string $cond_reglement Condition of payment (code or id) to use. If 0, we use current condition. + * @return date Date limite de reglement si ok, <0 si ko + */ + function calculate_date_lim_reglement($cond_reglement=0) + { + if (! $cond_reglement) $cond_reglement=$this->cond_reglement_code; + if (! $cond_reglement) $cond_reglement=$this->cond_reglement_id; + + $cdr_nbjour=0; $cdr_fdm=0; $cdr_decalage=0; + + $sqltemp = 'SELECT c.fdm,c.nbjour,c.decalage'; + $sqltemp.= ' FROM '.MAIN_DB_PREFIX.'c_payment_term as c'; + if (is_numeric($cond_reglement)) $sqltemp.= " WHERE c.rowid=".$cond_reglement; + else $sqltemp.= " WHERE c.code='".$this->db->escape($cond_reglement)."'"; + + dol_syslog(get_class($this).'::calculate_date_lim_reglement sql='.$sqltemp); + $resqltemp=$this->db->query($sqltemp); + if ($resqltemp) + { + if ($this->db->num_rows($resqltemp)) + { + $obj = $this->db->fetch_object($resqltemp); + $cdr_nbjour = $obj->nbjour; + $cdr_fdm = $obj->fdm; + $cdr_decalage = $obj->decalage; + } + } + else + { + $this->error=$this->db->error(); + return -1; + } + $this->db->free($resqltemp); + + /* Definition de la date limite */ + + // 1 : ajout du nombre de jours + $datelim = $this->date + ($cdr_nbjour * 3600 * 24); + + // 2 : application de la regle "fin de mois" + if ($cdr_fdm) + { + $mois=date('m', $datelim); + $annee=date('Y', $datelim); + if ($mois == 12) + { + $mois = 1; + $annee += 1; + } + else + { + $mois += 1; + } + // On se deplace au debut du mois suivant, et on retire un jour + $datelim=dol_mktime(12,0,0,$mois,1,$annee); + $datelim -= (3600 * 24); + } + + // 3 : application du decalage + $datelim += ($cdr_decalage * 3600 * 24); + + return $datelim; + } + + /** + * Tag la facture comme paye completement (close_code non renseigne) ou partiellement (close_code renseigne) + appel trigger BILL_PAYED + * + * @param User $user Objet utilisateur qui modifie + * @param string $close_code Code renseigne si on classe a payee completement alors que paiement incomplet (cas escompte par exemple) + * @param string $close_note Commentaire renseigne si on classe a payee alors que paiement incomplet (cas escompte par exemple) + * @return int <0 if KO, >0 if OK + */ + function set_paid($user,$close_code='',$close_note='') + { + global $conf,$langs; + $error=0; + + if ($this->paye != 1) + { + $this->db->begin(); + + dol_syslog(get_class($this)."::set_paid rowid=".$this->id, LOG_DEBUG); + $sql = 'UPDATE '.MAIN_DB_PREFIX.'facture SET'; + $sql.= ' fk_statut=2'; + if (! $close_code) $sql.= ', paye=1'; + if ($close_code) $sql.= ", close_code='".$this->db->escape($close_code)."'"; + if ($close_note) $sql.= ", close_note='".$this->db->escape($close_note)."'"; + $sql.= ' WHERE rowid = '.$this->id; + + $resql = $this->db->query($sql); + if ($resql) + { + // Appel des triggers + include_once DOL_DOCUMENT_ROOT . '/core/class/interfaces.class.php'; + $interface=new Interfaces($this->db); + $result=$interface->run_triggers('BILL_PAYED',$this,$user,$langs,$conf); + if ($result < 0) { + $error++; $this->errors=$interface->errors; + } + // Fin appel triggers + } + else + { + $error++; + $this->error=$this->db->error(); + dol_print_error($this->db); + } + + if (! $error) + { + $this->db->commit(); + return 1; + } + else + { + $this->db->rollback(); + return -1; + } + } + else + { + return 0; + } + } + + + /** + * Tag la facture comme non payee completement + appel trigger BILL_UNPAYED + * Fonction utilisee quand un paiement prelevement est refuse, + * ou quand une facture annulee et reouverte. + * + * @param User $user Object user that change status + * @return int <0 if KO, >0 if OK + */ + function set_unpaid($user) + { + global $conf,$langs; + $error=0; + + $this->db->begin(); + + $sql = 'UPDATE '.MAIN_DB_PREFIX.'facture'; + $sql.= ' SET paye=0, fk_statut=1, close_code=null, close_note=null'; + $sql.= ' WHERE rowid = '.$this->id; + + dol_syslog(get_class($this)."::set_unpaid sql=".$sql); + $resql = $this->db->query($sql); + if ($resql) + { + // Appel des triggers + include_once DOL_DOCUMENT_ROOT . '/core/class/interfaces.class.php'; + $interface=new Interfaces($this->db); + $result=$interface->run_triggers('BILL_UNPAYED',$this,$user,$langs,$conf); + if ($result < 0) { + $error++; $this->errors=$interface->errors; + } + // Fin appel triggers + } + else + { + $error++; + $this->error=$this->db->error(); + dol_print_error($this->db); + } + + if (! $error) + { + $this->db->commit(); + return 1; + } + else + { + $this->db->rollback(); + return -1; + } + } + + + /** + * Tag invoice as canceled, with no payment on it (example for replacement invoice or payment never received) + call trigger BILL_CANCEL + * Warning, if option to decrease stock on invoice was set, this function does not change stock (it might be a cancel because + * of no payment even if merchandises were sent). + * + * @param User $user Object user making change + * @param string $close_code Code de fermeture + * @param string $close_note Comment + * @return int <0 if KO, >0 if OK + */ + function set_canceled($user,$close_code='',$close_note='') + { + global $conf,$langs; + + $error=0; + + dol_syslog(get_class($this)."::set_canceled rowid=".$this->id, LOG_DEBUG); + + $this->db->begin(); + + $sql = 'UPDATE '.MAIN_DB_PREFIX.'facture SET'; + $sql.= ' fk_statut=3'; + if ($close_code) $sql.= ", close_code='".$this->db->escape($close_code)."'"; + if ($close_note) $sql.= ", close_note='".$this->db->escape($close_note)."'"; + $sql.= ' WHERE rowid = '.$this->id; + + $resql = $this->db->query($sql); + if ($resql) + { + // On desaffecte de la facture les remises liees + // car elles n'ont pas ete utilisees vu que la facture est abandonnee. + $sql = 'UPDATE '.MAIN_DB_PREFIX.'societe_remise_except'; + $sql.= ' SET fk_facture = NULL'; + $sql.= ' WHERE fk_facture = '.$this->id; + + $resql=$this->db->query($sql); + if ($resql) + { + // Appel des triggers + include_once DOL_DOCUMENT_ROOT . '/core/class/interfaces.class.php'; + $interface=new Interfaces($this->db); + $result=$interface->run_triggers('BILL_CANCEL',$this,$user,$langs,$conf); + if ($result < 0) { + $error++; $this->errors=$interface->errors; + } + // Fin appel triggers + + $this->db->commit(); + return 1; + } + else + { + $this->error=$this->db->error()." sql=".$sql; + $this->db->rollback(); + return -1; + } + } + else + { + $this->error=$this->db->error()." sql=".$sql; + $this->db->rollback(); + return -2; + } + } + + /** + * Tag invoice as validated + call trigger BILL_VALIDATE + * Object must have lines loaded with fetch_lines + * + * @param User $user Object user that validate + * @param string $force_number Reference to force on invoice + * @param int $idwarehouse Id of warehouse to use for stock decrease + * @return int <0 if KO, >0 if OK + */ + function validate($user, $force_number='', $idwarehouse=0) + { + global $conf,$langs; + require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php'; + + $now=dol_now(); + + $error=0; + dol_syslog(get_class($this).'::validate user='.$user->id.', force_number='.$force_number.', idwarehouse='.$idwarehouse); + + // Check parameters + if (! $this->brouillon) + { + dol_syslog(get_class($this)."::validate no draft status", LOG_WARNING); + return 0; + } + + if (! $user->rights->facture->valider) + { + $this->error='Permission denied'; + dol_syslog(get_class($this)."::validate ".$this->error, LOG_ERR); + return -1; + } + + $this->db->begin(); + + $this->fetch_thirdparty(); + $this->fetch_lines(); + + // Check parameters + if ($this->type == 1) // si facture de remplacement + { + // Controle que facture source connue + if ($this->fk_facture_source <= 0) + { + $this->error=$langs->trans("ErrorFieldRequired",$langs->trans("InvoiceReplacement")); + $this->db->rollback(); + return -10; + } + + // Charge la facture source a remplacer + $facreplaced=new Facture($this->db); + $result=$facreplaced->fetch($this->fk_facture_source); + if ($result <= 0) + { + $this->error=$langs->trans("ErrorBadInvoice"); + $this->db->rollback(); + return -11; + } + + // Controle que facture source non deja remplacee par une autre + $idreplacement=$facreplaced->getIdReplacingInvoice('validated'); + if ($idreplacement && $idreplacement != $this->id) + { + $facreplacement=new Facture($this->db); + $facreplacement->fetch($idreplacement); + $this->error=$langs->trans("ErrorInvoiceAlreadyReplaced",$facreplaced->ref,$facreplacement->ref); + $this->db->rollback(); + return -12; + } + + $result=$facreplaced->set_canceled($user,'replaced',''); + if ($result < 0) + { + $this->error=$facreplaced->error; + $this->db->rollback(); + return -13; + } + } + + // Define new ref + if ($force_number) + { + $num = $force_number; + } + else if (preg_match('/^[\(]?PROV/i', $this->ref)) + { + if (! empty($conf->global->FAC_FORCE_DATE_VALIDATION)) // If option enabled, we force invoice date + { + $this->date=dol_now(); + $this->date_lim_reglement=$this->calculate_date_lim_reglement(); + } + $num = $this->getNextNumRef($this->client); + } + else + { + $num = $this->ref; + } + + if ($num) + { + $this->update_price(1); + + // Validate + $sql = 'UPDATE '.MAIN_DB_PREFIX.'facture'; + $sql.= " SET facnumber='".$num."', fk_statut = 1, fk_user_valid = ".$user->id.", date_valid = '".$this->db->idate($now)."'"; + if (! empty($conf->global->FAC_FORCE_DATE_VALIDATION)) // If option enabled, we force invoice date + { + $sql.= ', datef='.$this->db->idate($this->date); + $sql.= ', date_lim_reglement='.$this->db->idate($this->date_lim_reglement); + } + $sql.= ' WHERE rowid = '.$this->id; + + dol_syslog(get_class($this)."::validate sql=".$sql); + $resql=$this->db->query($sql); + if (! $resql) + { + dol_syslog(get_class($this)."::validate Echec update - 10 - sql=".$sql, LOG_ERR); + dol_print_error($this->db); + $error++; + } + + // On verifie si la facture etait une provisoire + if (! $error && (preg_match('/^[\(]?PROV/i', $this->ref))) + { + // La verif qu'une remise n'est pas utilisee 2 fois est faite au moment de l'insertion de ligne + } + + if (! $error) + { + // Define third party as a customer + $result=$this->client->set_as_client(); + + // Si active on decremente le produit principal et ses composants a la validation de facture + if ($this->type != 3 && $result >= 0 && ! empty($conf->stock->enabled) && ! empty($conf->global->STOCK_CALCULATE_ON_BILL)) + { + require_once DOL_DOCUMENT_ROOT.'/product/stock/class/mouvementstock.class.php'; + $langs->load("agenda"); + + // Loop on each line + $cpt=count($this->lines); + for ($i = 0; $i < $cpt; $i++) + { + if ($this->lines[$i]->fk_product > 0) + { + $mouvP = new MouvementStock($this->db); + // We decrease stock for product + if ($this->type == 2) $result=$mouvP->reception($user, $this->lines[$i]->fk_product, $idwarehouse, $this->lines[$i]->qty, $this->lines[$i]->subprice, $langs->trans("InvoiceValidatedInDolibarr",$num)); + else $result=$mouvP->livraison($user, $this->lines[$i]->fk_product, $idwarehouse, $this->lines[$i]->qty, $this->lines[$i]->subprice, $langs->trans("InvoiceValidatedInDolibarr",$num)); + if ($result < 0) { + $error++; + } + } + } + } + } + + if (! $error) + { + $this->oldref = ''; + + // Rename directory if dir was a temporary ref + if (preg_match('/^[\(]?PROV/i', $this->ref)) + { + // On renomme repertoire facture ($this->ref = ancienne ref, $num = nouvelle ref) + // afin de ne pas perdre les fichiers attaches + $facref = dol_sanitizeFileName($this->ref); + $snumfa = dol_sanitizeFileName($num); + $dirsource = $conf->facture->dir_output.'/'.$facref; + $dirdest = $conf->facture->dir_output.'/'.$snumfa; + if (file_exists($dirsource)) + { + dol_syslog(get_class($this)."::validate rename dir ".$dirsource." into ".$dirdest); + + if (@rename($dirsource, $dirdest)) + { + $this->oldref = $facref; + + dol_syslog("Rename ok"); + // Suppression ancien fichier PDF dans nouveau rep + dol_delete_file($conf->facture->dir_output.'/'.$snumfa.'/'.$facref.'*.*'); + } + } + } + } + + // Set new ref and define current statut + if (! $error) + { + $this->ref = $num; + $this->facnumber=$num; + $this->statut=1; + $this->brouillon=0; + $this->date_validation=$now; + } + + // Trigger calls + if (! $error) + { + // Appel des triggers + include_once DOL_DOCUMENT_ROOT . '/core/class/interfaces.class.php'; + $interface=new Interfaces($this->db); + $result=$interface->run_triggers('BILL_VALIDATE',$this,$user,$langs,$conf); + if ($result < 0) { + $error++; $this->errors=$interface->errors; + } + // Fin appel triggers + } + } + else + { + $error++; + } + + if (! $error) + { + $this->db->commit(); + return 1; + } + else + { + $this->db->rollback(); + $this->error=$this->db->lasterror(); + return -1; + } + } + + /** + * Set draft status + * + * @param User $user Object user that modify + * @param int $idwarehouse Id warehouse to use for stock change. + * @return int <0 if KO, >0 if OK + */ + function set_draft($user,$idwarehouse=-1) + { + global $conf,$langs; + + $error=0; + + if ($this->statut == 0) + { + dol_syslog(get_class($this)."::set_draft already draft status", LOG_WARNING); + return 0; + } + + $this->db->begin(); + + $sql = "UPDATE ".MAIN_DB_PREFIX."facture"; + $sql.= " SET fk_statut = 0"; + $sql.= " WHERE rowid = ".$this->id; + + dol_syslog(get_class($this)."::set_draft sql=".$sql, LOG_DEBUG); + $result=$this->db->query($sql); + if ($result) + { + // Si on decremente le produit principal et ses composants a la validation de facture, on réincrement + if ($this->type != 3 && $result >= 0 && ! empty($conf->stock->enabled) && ! empty($conf->global->STOCK_CALCULATE_ON_BILL)) + { + require_once DOL_DOCUMENT_ROOT.'/product/stock/class/mouvementstock.class.php'; + $langs->load("agenda"); + + $num=count($this->lines); + for ($i = 0; $i < $num; $i++) + { + if ($this->lines[$i]->fk_product > 0) + { + $mouvP = new MouvementStock($this->db); + // We decrease stock for product + if ($this->type == 2) $result=$mouvP->livraison($user, $this->lines[$i]->fk_product, $idwarehouse, $this->lines[$i]->qty, $this->lines[$i]->subprice, $langs->trans("InvoiceBackToDraftInDolibarr",$this->ref)); + else $result=$mouvP->reception($user, $this->lines[$i]->fk_product, $idwarehouse, $this->lines[$i]->qty, 0, $langs->trans("InvoiceBackToDraftInDolibarr",$this->ref)); // we use 0 for price, to not change the weighted average value + } + } + } if ($error == 0) - { + { $old_statut=$this->statut; - $this->brouillon = 1; - $this->statut = 0; + $this->brouillon = 1; + $this->statut = 0; // Appel des triggers include_once DOL_DOCUMENT_ROOT . '/core/class/interfaces.class.php'; $interface=new Interfaces($this->db); @@ -1885,270 +1924,270 @@ class Facture extends CommonInvoice return -1; } - if ($error == 0) - { - $this->db->commit(); - return 1; - } - else - { - $this->db->rollback(); - return -1; - } - } - else - { - $this->error=$this->db->error(); - $this->db->rollback(); - return -1; - } - } + if ($error == 0) + { + $this->db->commit(); + return 1; + } + else + { + $this->db->rollback(); + return -1; + } + } + else + { + $this->error=$this->db->error(); + $this->db->rollback(); + return -1; + } + } - /** - * Add an invoice line into database (linked to product/service or not). - * Les parametres sont deja cense etre juste et avec valeurs finales a l'appel - * de cette methode. Aussi, pour le taux tva, il doit deja avoir ete defini - * par l'appelant par la methode get_default_tva(societe_vendeuse,societe_acheteuse,produit) - * et le desc doit deja avoir la bonne valeur (a l'appelant de gerer le multilangue) - * - * @param int $facid Id de la facture - * @param string $desc Description de la ligne - * @param double $pu_ht Prix unitaire HT (> 0 even for credit note) - * @param double $qty Quantite - * @param double $txtva Taux de tva force, sinon -1 - * @param double $txlocaltax1 Local tax 1 rate - * @param double $txlocaltax2 Local tax 2 rate - * @param int $fk_product Id du produit/service predefini - * @param double $remise_percent Pourcentage de remise de la ligne - * @param timestamp $date_start Date de debut de validite du service - * @param timestamp $date_end Date de fin de validite du service - * @param int $ventil Code de ventilation comptable - * @param int $info_bits Bits de type de lignes - * @param int $fk_remise_except Id remise - * @param string $price_base_type HT or TTC - * @param double $pu_ttc Prix unitaire TTC (> 0 even for credit note) - * @param int $type Type of line (0=product, 1=service) - * @param int $rang Position of line - * @param int $special_code Special code (also used by externals modules!) - * @param string $origin 'order', ... - * @param int $origin_id Id of origin object - * @param int $fk_parent_line Id of parent line - * @param int $fk_fournprice To calculate margin - * @param int $pa_ht Buying price of line - * @param string $label Label of the line - * @return int <0 if KO, Id of line if OK - */ - function addline($facid, $desc, $pu_ht, $qty, $txtva, $txlocaltax1=0, $txlocaltax2=0, $fk_product=0, $remise_percent=0, $date_start='', $date_end='', $ventil=0, $info_bits=0, $fk_remise_except='', $price_base_type='HT', $pu_ttc=0, $type=0, $rang=-1, $special_code=0, $origin='', $origin_id=0, $fk_parent_line=0, $fk_fournprice=null, $pa_ht=0, $label='') - { - 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,date_start=$date_start,date_end=$date_end,ventil=$ventil,info_bits=$info_bits,fk_remise_except=$fk_remise_except,price_base_type=$price_base_type,pu_ttc=$pu_ttc,type=$type", LOG_DEBUG); - include_once DOL_DOCUMENT_ROOT.'/core/lib/price.lib.php'; + /** + * Add an invoice line into database (linked to product/service or not). + * Les parametres sont deja cense etre juste et avec valeurs finales a l'appel + * de cette methode. Aussi, pour le taux tva, il doit deja avoir ete defini + * par l'appelant par la methode get_default_tva(societe_vendeuse,societe_acheteuse,produit) + * et le desc doit deja avoir la bonne valeur (a l'appelant de gerer le multilangue) + * + * @param int $facid Id de la facture + * @param string $desc Description de la ligne + * @param double $pu_ht Prix unitaire HT (> 0 even for credit note) + * @param double $qty Quantite + * @param double $txtva Taux de tva force, sinon -1 + * @param double $txlocaltax1 Local tax 1 rate + * @param double $txlocaltax2 Local tax 2 rate + * @param int $fk_product Id du produit/service predefini + * @param double $remise_percent Pourcentage de remise de la ligne + * @param timestamp $date_start Date de debut de validite du service + * @param timestamp $date_end Date de fin de validite du service + * @param int $ventil Code de ventilation comptable + * @param int $info_bits Bits de type de lignes + * @param int $fk_remise_except Id remise + * @param string $price_base_type HT or TTC + * @param double $pu_ttc Prix unitaire TTC (> 0 even for credit note) + * @param int $type Type of line (0=product, 1=service) + * @param int $rang Position of line + * @param int $special_code Special code (also used by externals modules!) + * @param string $origin 'order', ... + * @param int $origin_id Id of origin object + * @param int $fk_parent_line Id of parent line + * @param int $fk_fournprice To calculate margin + * @param int $pa_ht Buying price of line + * @param string $label Label of the line + * @return int <0 if KO, Id of line if OK + */ + function addline($facid, $desc, $pu_ht, $qty, $txtva, $txlocaltax1=0, $txlocaltax2=0, $fk_product=0, $remise_percent=0, $date_start='', $date_end='', $ventil=0, $info_bits=0, $fk_remise_except='', $price_base_type='HT', $pu_ttc=0, $type=0, $rang=-1, $special_code=0, $origin='', $origin_id=0, $fk_parent_line=0, $fk_fournprice=null, $pa_ht=0, $label='') + { + 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,date_start=$date_start,date_end=$date_end,ventil=$ventil,info_bits=$info_bits,fk_remise_except=$fk_remise_except,price_base_type=$price_base_type,pu_ttc=$pu_ttc,type=$type", LOG_DEBUG); + include_once DOL_DOCUMENT_ROOT.'/core/lib/price.lib.php'; - // Clean parameters - if (empty($remise_percent)) $remise_percent=0; - if (empty($qty)) $qty=0; - if (empty($info_bits)) $info_bits=0; - if (empty($rang)) $rang=0; - if (empty($ventil)) $ventil=0; - if (empty($txtva)) $txtva=0; - if (empty($txlocaltax1)) $txlocaltax1=0; - if (empty($txlocaltax2)) $txlocaltax2=0; - if (empty($fk_parent_line) || $fk_parent_line < 0) $fk_parent_line=0; + // Clean parameters + if (empty($remise_percent)) $remise_percent=0; + if (empty($qty)) $qty=0; + if (empty($info_bits)) $info_bits=0; + if (empty($rang)) $rang=0; + if (empty($ventil)) $ventil=0; + if (empty($txtva)) $txtva=0; + if (empty($txlocaltax1)) $txlocaltax1=0; + if (empty($txlocaltax2)) $txlocaltax2=0; + if (empty($fk_parent_line) || $fk_parent_line < 0) $fk_parent_line=0; - $remise_percent=price2num($remise_percent); - $qty=price2num($qty); - $pu_ht=price2num($pu_ht); - $pu_ttc=price2num($pu_ttc); - $pa_ht=price2num($pa_ht); - $txtva=price2num($txtva); - $txlocaltax1=price2num($txlocaltax1); - $txlocaltax2=price2num($txlocaltax2); + $remise_percent=price2num($remise_percent); + $qty=price2num($qty); + $pu_ht=price2num($pu_ht); + $pu_ttc=price2num($pu_ttc); + $pa_ht=price2num($pa_ht); + $txtva=price2num($txtva); + $txlocaltax1=price2num($txlocaltax1); + $txlocaltax2=price2num($txlocaltax2); - if ($price_base_type=='HT') - { - $pu=$pu_ht; - } - else - { - $pu=$pu_ttc; - } + if ($price_base_type=='HT') + { + $pu=$pu_ht; + } + else + { + $pu=$pu_ttc; + } - // Check parameters - if ($type < 0) return -1; + // Check parameters + if ($type < 0) return -1; - if (! empty($this->brouillon)) - { - $this->db->begin(); + if (! empty($this->brouillon)) + { + $this->db->begin(); - // Calcul du total TTC et de la TVA pour la ligne a partir de - // qty, pu, remise_percent et txtva - // TRES IMPORTANT: C'est au moment de l'insertion ligne qu'on doit stocker - // la part ht, tva et ttc, et ce au niveau de la ligne qui a son propre taux tva. - $tabprice = calcul_price_total($qty, $pu, $remise_percent, $txtva, $txlocaltax1, $txlocaltax2, 0, $price_base_type, $info_bits, $type); - $total_ht = $tabprice[0]; - $total_tva = $tabprice[1]; - $total_ttc = $tabprice[2]; - $total_localtax1 = $tabprice[9]; - $total_localtax2 = $tabprice[10]; - $pu_ht = $tabprice[3]; + // Calcul du total TTC et de la TVA pour la ligne a partir de + // qty, pu, remise_percent et txtva + // TRES IMPORTANT: C'est au moment de l'insertion ligne qu'on doit stocker + // la part ht, tva et ttc, et ce au niveau de la ligne qui a son propre taux tva. + $tabprice = calcul_price_total($qty, $pu, $remise_percent, $txtva, $txlocaltax1, $txlocaltax2, 0, $price_base_type, $info_bits, $type); + $total_ht = $tabprice[0]; + $total_tva = $tabprice[1]; + $total_ttc = $tabprice[2]; + $total_localtax1 = $tabprice[9]; + $total_localtax2 = $tabprice[10]; + $pu_ht = $tabprice[3]; - // Rang to use - $rangtouse = $rang; - if ($rangtouse == -1) - { - $rangmax = $this->line_max($fk_parent_line); - $rangtouse = $rangmax + 1; - } + // Rang to use + $rangtouse = $rang; + if ($rangtouse == -1) + { + $rangmax = $this->line_max($fk_parent_line); + $rangtouse = $rangmax + 1; + } - $product_type=$type; - if ($fk_product) - { - $product=new Product($this->db); - $result=$product->fetch($fk_product); - $product_type=$product->type; - } + $product_type=$type; + if ($fk_product) + { + $product=new Product($this->db); + $result=$product->fetch($fk_product); + $product_type=$product->type; + } - // Insert line - $this->line=new FactureLigne($this->db); - $this->line->fk_facture=$facid; - $this->line->label=$label; - $this->line->desc=$desc; - $this->line->qty= ($this->type==2?abs($qty):$qty); // For credit note, quantity is always positive and unit price negative - $this->line->tva_tx=$txtva; - $this->line->localtax1_tx=$txlocaltax1; - $this->line->localtax2_tx=$txlocaltax2; - $this->line->fk_product=$fk_product; - $this->line->product_type=$product_type; - $this->line->remise_percent=$remise_percent; - $this->line->subprice= ($this->type==2?-abs($pu_ht):$pu_ht); // For credit note, unit price always negative, always positive otherwise - $this->line->date_start=$date_start; - $this->line->date_end=$date_end; - $this->line->ventil=$ventil; - $this->line->rang=$rangtouse; - $this->line->info_bits=$info_bits; - $this->line->fk_remise_except=$fk_remise_except; - $this->line->total_ht= (($this->type==2||$qty<0)?-abs($total_ht):$total_ht); // For credit note and if qty is negative, total is negative - $this->line->total_tva= (($this->type==2||$qty<0)?-abs($total_tva):$total_tva); - $this->line->total_localtax1=(($this->type==2||$qty<0)?-abs($total_localtax1):$total_localtax1); - $this->line->total_localtax2=(($this->type==2||$qty<0)?-abs($total_localtax2):$total_localtax2); - $this->line->total_ttc= (($this->type==2||$qty<0)?-abs($total_ttc):$total_ttc); - $this->line->special_code=$special_code; - $this->line->fk_parent_line=$fk_parent_line; - $this->line->origin=$origin; - $this->line->origin_id=$origin_id; + // Insert line + $this->line=new FactureLigne($this->db); + $this->line->fk_facture=$facid; + $this->line->label=$label; + $this->line->desc=$desc; + $this->line->qty= ($this->type==2?abs($qty):$qty); // For credit note, quantity is always positive and unit price negative + $this->line->tva_tx=$txtva; + $this->line->localtax1_tx=$txlocaltax1; + $this->line->localtax2_tx=$txlocaltax2; + $this->line->fk_product=$fk_product; + $this->line->product_type=$product_type; + $this->line->remise_percent=$remise_percent; + $this->line->subprice= ($this->type==2?-abs($pu_ht):$pu_ht); // For credit note, unit price always negative, always positive otherwise + $this->line->date_start=$date_start; + $this->line->date_end=$date_end; + $this->line->ventil=$ventil; + $this->line->rang=$rangtouse; + $this->line->info_bits=$info_bits; + $this->line->fk_remise_except=$fk_remise_except; + $this->line->total_ht= (($this->type==2||$qty<0)?-abs($total_ht):$total_ht); // For credit note and if qty is negative, total is negative + $this->line->total_tva= (($this->type==2||$qty<0)?-abs($total_tva):$total_tva); + $this->line->total_localtax1=(($this->type==2||$qty<0)?-abs($total_localtax1):$total_localtax1); + $this->line->total_localtax2=(($this->type==2||$qty<0)?-abs($total_localtax2):$total_localtax2); + $this->line->total_ttc= (($this->type==2||$qty<0)?-abs($total_ttc):$total_ttc); + $this->line->special_code=$special_code; + $this->line->fk_parent_line=$fk_parent_line; + $this->line->origin=$origin; + $this->line->origin_id=$origin_id; // infos marge $this->line->fk_fournprice = $fk_fournprice; $this->line->pa_ht = $pa_ht; - $result=$this->line->insert(); - if ($result > 0) - { - // Reorder if child line + $result=$this->line->insert(); + if ($result > 0) + { + // Reorder if child line if (! empty($fk_parent_line)) $this->line_order(true,'DESC'); - // Mise a jour informations denormalisees au niveau de la facture meme - $this->id=$facid; // TODO To move this we must remove parameter facid into this function declaration - $result=$this->update_price(1); - if ($result > 0) - { - $this->db->commit(); - return $this->line->rowid; - } - else - { - $this->error=$this->db->error(); - dol_syslog("Error sql=$sql, error=".$this->error,LOG_ERR); - $this->db->rollback(); - return -1; - } - } - else - { - $this->error=$this->line->error; - $this->db->rollback(); - return -2; - } - } - } + // Mise a jour informations denormalisees au niveau de la facture meme + $this->id=$facid; // TODO To move this we must remove parameter facid into this function declaration + $result=$this->update_price(1); + if ($result > 0) + { + $this->db->commit(); + return $this->line->rowid; + } + else + { + $this->error=$this->db->error(); + dol_syslog("Error sql=$sql, error=".$this->error,LOG_ERR); + $this->db->rollback(); + return -1; + } + } + else + { + $this->error=$this->line->error; + $this->db->rollback(); + return -2; + } + } + } - /** - * Update a detail line - * - * @param int $rowid Id of line to update - * @param string $desc Description of line - * @param double $pu Prix unitaire (HT ou TTC selon price_base_type) (> 0 even for credit note lines) - * @param double $qty Quantity - * @param double $remise_percent Pourcentage de remise de la ligne - * @param date $date_start Date de debut de validite du service - * @param date $date_end Date de fin de validite du service - * @param double $txtva VAT Rate - * @param double $txlocaltax1 Local tax 1 rate - * @param double $txlocaltax2 Local tax 2 rate - * @param string $price_base_type HT or TTC - * @param int $info_bits Miscellaneous informations - * @param int $type Type of line (0=product, 1=service) - * @param int $fk_parent_line Id of parent line (0 in most cases, used by modules adding sublevels into lines). - * @param int $skip_update_total Keep fields total_xxx to 0 (used for special lines by some modules) - * @param int $fk_fournprice Id of origin supplier price - * @param int $pa_ht Price (without tax) of product when it was bought - * @param string $label Label of the line - * @param int $special_code Special code (also used by externals modules!) - * @return int < 0 if KO, > 0 if OK - */ - function updateline($rowid, $desc, $pu, $qty, $remise_percent, $date_start, $date_end, $txtva, $txlocaltax1=0, $txlocaltax2=0, $price_base_type='HT', $info_bits=0, $type=0, $fk_parent_line=0, $skip_update_total=0, $fk_fournprice=null, $pa_ht=0, $label='', $special_code=0) - { - include_once DOL_DOCUMENT_ROOT.'/core/lib/price.lib.php'; + /** + * Update a detail line + * + * @param int $rowid Id of line to update + * @param string $desc Description of line + * @param double $pu Prix unitaire (HT ou TTC selon price_base_type) (> 0 even for credit note lines) + * @param double $qty Quantity + * @param double $remise_percent Pourcentage de remise de la ligne + * @param date $date_start Date de debut de validite du service + * @param date $date_end Date de fin de validite du service + * @param double $txtva VAT Rate + * @param double $txlocaltax1 Local tax 1 rate + * @param double $txlocaltax2 Local tax 2 rate + * @param string $price_base_type HT or TTC + * @param int $info_bits Miscellaneous informations + * @param int $type Type of line (0=product, 1=service) + * @param int $fk_parent_line Id of parent line (0 in most cases, used by modules adding sublevels into lines). + * @param int $skip_update_total Keep fields total_xxx to 0 (used for special lines by some modules) + * @param int $fk_fournprice Id of origin supplier price + * @param int $pa_ht Price (without tax) of product when it was bought + * @param string $label Label of the line + * @param int $special_code Special code (also used by externals modules!) + * @return int < 0 if KO, > 0 if OK + */ + function updateline($rowid, $desc, $pu, $qty, $remise_percent, $date_start, $date_end, $txtva, $txlocaltax1=0, $txlocaltax2=0, $price_base_type='HT', $info_bits=0, $type=0, $fk_parent_line=0, $skip_update_total=0, $fk_fournprice=null, $pa_ht=0, $label='', $special_code=0) + { + include_once DOL_DOCUMENT_ROOT.'/core/lib/price.lib.php'; - dol_syslog(get_class($this)."::updateline $rowid, $desc, $pu, $qty, $remise_percent, $date_start, $date_end, $txtva, $txlocaltax1, $txlocaltax2, $price_base_type, $info_bits, $type, $fk_parent_line", LOG_DEBUG); + dol_syslog(get_class($this)."::updateline $rowid, $desc, $pu, $qty, $remise_percent, $date_start, $date_end, $txtva, $txlocaltax1, $txlocaltax2, $price_base_type, $info_bits, $type, $fk_parent_line", LOG_DEBUG); - if ($this->brouillon) - { - $this->db->begin(); + if ($this->brouillon) + { + $this->db->begin(); - // Clean parameters - if (empty($qty)) $qty=0; - if (empty($fk_parent_line) || $fk_parent_line < 0) $fk_parent_line=0; - if (empty($special_code) || $special_code == 3) $special_code=0; + // Clean parameters + if (empty($qty)) $qty=0; + if (empty($fk_parent_line) || $fk_parent_line < 0) $fk_parent_line=0; + if (empty($special_code) || $special_code == 3) $special_code=0; - $remise_percent = price2num($remise_percent); - $qty = price2num($qty); - $pu = price2num($pu); - $pa_ht = price2num($pa_ht); - $txtva = price2num($txtva); - $txlocaltax1 = price2num($txlocaltax1); - $txlocaltax2 = price2num($txlocaltax2); + $remise_percent = price2num($remise_percent); + $qty = price2num($qty); + $pu = price2num($pu); + $pa_ht = price2num($pa_ht); + $txtva = price2num($txtva); + $txlocaltax1 = price2num($txlocaltax1); + $txlocaltax2 = price2num($txlocaltax2); - // Check parameters - if ($type < 0) return -1; + // Check parameters + if ($type < 0) return -1; - // Calculate total with, without tax and tax from qty, pu, remise_percent and txtva - // TRES IMPORTANT: C'est au moment de l'insertion ligne qu'on doit stocker - // la part ht, tva et ttc, et ce au niveau de la ligne qui a son propre taux tva. - $tabprice=calcul_price_total($qty, $pu, $remise_percent, $txtva, $txlocaltax1, $txlocaltax2, 0, $price_base_type, $info_bits, $type); - $total_ht = $tabprice[0]; - $total_tva = $tabprice[1]; - $total_ttc = $tabprice[2]; - $total_localtax1=$tabprice[9]; - $total_localtax2=$tabprice[10]; - $pu_ht = $tabprice[3]; - $pu_tva = $tabprice[4]; - $pu_ttc = $tabprice[5]; + // Calculate total with, without tax and tax from qty, pu, remise_percent and txtva + // TRES IMPORTANT: C'est au moment de l'insertion ligne qu'on doit stocker + // la part ht, tva et ttc, et ce au niveau de la ligne qui a son propre taux tva. + $tabprice=calcul_price_total($qty, $pu, $remise_percent, $txtva, $txlocaltax1, $txlocaltax2, 0, $price_base_type, $info_bits, $type); + $total_ht = $tabprice[0]; + $total_tva = $tabprice[1]; + $total_ttc = $tabprice[2]; + $total_localtax1=$tabprice[9]; + $total_localtax2=$tabprice[10]; + $pu_ht = $tabprice[3]; + $pu_tva = $tabprice[4]; + $pu_ttc = $tabprice[5]; - // Old properties: $price, $remise (deprecated) - $price = $pu; - $remise = 0; - if ($remise_percent > 0) - { - $remise = round(($pu * $remise_percent / 100),2); - $price = ($pu - $remise); - } - $price = price2num($price); + // Old properties: $price, $remise (deprecated) + $price = $pu; + $remise = 0; + if ($remise_percent > 0) + { + $remise = round(($pu * $remise_percent / 100),2); + $price = ($pu - $remise); + } + $price = price2num($price); - // Update line into database - $this->line=new FactureLigne($this->db); + // Update line into database + $this->line=new FactureLigne($this->db); - // Stock previous line records + // Stock previous line records $staticline=new FactureLigne($this->db); $staticline->fetch($rowid); $this->line->oldline = $staticline; @@ -2160,981 +2199,981 @@ class Facture extends CommonInvoice $this->line->rang = $rangmax + 1; } - $this->line->rowid = $rowid; - $this->line->label = $label; - $this->line->desc = $desc; - $this->line->qty = ($this->type==2?abs($qty):$qty); // For credit note, quantity is always positive and unit price negative - $this->line->tva_tx = $txtva; - $this->line->localtax1_tx = $txlocaltax1; - $this->line->localtax2_tx = $txlocaltax2; - $this->line->remise_percent = $remise_percent; - $this->line->subprice = ($this->type==2?-abs($pu_ht):$pu_ht); // For credit note, unit price always negative, always positive otherwise - $this->line->date_start = $date_start; - $this->line->date_end = $date_end; - $this->line->total_ht = (($this->type==2||$qty<0)?-abs($total_ht):$total_ht); // For credit note and if qty is negative, total is negative - $this->line->total_tva = (($this->type==2||$qty<0)?-abs($total_tva):$total_tva); - $this->line->total_localtax1 = (($this->type==2||$qty<0)?-abs($total_localtax1):$total_localtax1); - $this->line->total_localtax2 = (($this->type==2||$qty<0)?-abs($total_localtax2):$total_localtax2); - $this->line->total_ttc = (($this->type==2||$qty<0)?-abs($total_ttc):$total_ttc); - $this->line->info_bits = $info_bits; - $this->line->special_code = $special_code; - $this->line->product_type = $type; - $this->line->fk_parent_line = $fk_parent_line; - $this->line->skip_update_total = $skip_update_total; + $this->line->rowid = $rowid; + $this->line->label = $label; + $this->line->desc = $desc; + $this->line->qty = ($this->type==2?abs($qty):$qty); // For credit note, quantity is always positive and unit price negative + $this->line->tva_tx = $txtva; + $this->line->localtax1_tx = $txlocaltax1; + $this->line->localtax2_tx = $txlocaltax2; + $this->line->remise_percent = $remise_percent; + $this->line->subprice = ($this->type==2?-abs($pu_ht):$pu_ht); // For credit note, unit price always negative, always positive otherwise + $this->line->date_start = $date_start; + $this->line->date_end = $date_end; + $this->line->total_ht = (($this->type==2||$qty<0)?-abs($total_ht):$total_ht); // For credit note and if qty is negative, total is negative + $this->line->total_tva = (($this->type==2||$qty<0)?-abs($total_tva):$total_tva); + $this->line->total_localtax1 = (($this->type==2||$qty<0)?-abs($total_localtax1):$total_localtax1); + $this->line->total_localtax2 = (($this->type==2||$qty<0)?-abs($total_localtax2):$total_localtax2); + $this->line->total_ttc = (($this->type==2||$qty<0)?-abs($total_ttc):$total_ttc); + $this->line->info_bits = $info_bits; + $this->line->special_code = $special_code; + $this->line->product_type = $type; + $this->line->fk_parent_line = $fk_parent_line; + $this->line->skip_update_total = $skip_update_total; // infos marge $this->line->fk_fournprice = $fk_fournprice; $this->line->pa_ht = $pa_ht; - // A ne plus utiliser - //$this->line->price=$price; - //$this->line->remise=$remise; + // A ne plus utiliser + //$this->line->price=$price; + //$this->line->remise=$remise; - $result=$this->line->update(); - if ($result > 0) - { - // Reorder if child line - if (! empty($fk_parent_line)) $this->line_order(true,'DESC'); + $result=$this->line->update(); + if ($result > 0) + { + // Reorder if child line + if (! empty($fk_parent_line)) $this->line_order(true,'DESC'); - // Mise a jour info denormalisees au niveau facture - $this->update_price(1); - $this->db->commit(); - return $result; - } - else - { - $this->db->rollback(); - return -1; - } - } - else - { - $this->error="Invoice statut makes operation forbidden"; - return -2; - } - } + // Mise a jour info denormalisees au niveau facture + $this->update_price(1); + $this->db->commit(); + return $result; + } + else + { + $this->db->rollback(); + return -1; + } + } + else + { + $this->error="Invoice statut makes operation forbidden"; + return -2; + } + } - /** - * Delete line in database - * - * @param int $rowid Id of line to delete - * @return int <0 if KO, >0 if OK - */ - function deleteline($rowid) - { - global $langs, $conf; + /** + * Delete line in database + * + * @param int $rowid Id of line to delete + * @return int <0 if KO, >0 if OK + */ + function deleteline($rowid) + { + global $langs, $conf; - dol_syslog(get_class($this)."::deleteline rowid=".$rowid, LOG_DEBUG); + dol_syslog(get_class($this)."::deleteline rowid=".$rowid, LOG_DEBUG); - if (! $this->brouillon) - { - $this->error='ErrorBadStatus'; - return -1; - } + if (! $this->brouillon) + { + $this->error='ErrorBadStatus'; + return -1; + } - $this->db->begin(); + $this->db->begin(); - // Libere remise liee a ligne de facture - $sql = 'UPDATE '.MAIN_DB_PREFIX.'societe_remise_except'; - $sql.= ' SET fk_facture_line = NULL'; - $sql.= ' WHERE fk_facture_line = '.$rowid; + // Libere remise liee a ligne de facture + $sql = 'UPDATE '.MAIN_DB_PREFIX.'societe_remise_except'; + $sql.= ' SET fk_facture_line = NULL'; + $sql.= ' WHERE fk_facture_line = '.$rowid; - dol_syslog(get_class($this)."::deleteline sql=".$sql); - $result = $this->db->query($sql); - if (! $result) - { - $this->error=$this->db->error(); - dol_syslog(get_class($this)."::deleteline Error ".$this->error, LOG_ERR); - $this->db->rollback(); - return -1; - } + dol_syslog(get_class($this)."::deleteline sql=".$sql); + $result = $this->db->query($sql); + if (! $result) + { + $this->error=$this->db->error(); + dol_syslog(get_class($this)."::deleteline Error ".$this->error, LOG_ERR); + $this->db->rollback(); + return -1; + } - $line=new FactureLigne($this->db); + $line=new FactureLigne($this->db); - // For triggers - $line->fetch($rowid); + // For triggers + $line->fetch($rowid); - if ($line->delete() > 0) - { - $result=$this->update_price(1); + if ($line->delete() > 0) + { + $result=$this->update_price(1); - if ($result > 0) - { - $this->db->commit(); - return 1; - } - else - { - $this->db->rollback(); - $this->error=$this->db->lasterror(); - return -1; - } - } - else - { - $this->db->rollback(); - $this->error=$this->db->lasterror(); - return -1; - } - } + if ($result > 0) + { + $this->db->commit(); + return 1; + } + else + { + $this->db->rollback(); + $this->error=$this->db->lasterror(); + return -1; + } + } + else + { + $this->db->rollback(); + $this->error=$this->db->lasterror(); + return -1; + } + } - /** - * Set percent discount - * - * @param User $user User that set discount - * @param double $remise Discount - * @return int <0 if ko, >0 if ok - */ - function set_remise($user, $remise) - { - // Clean parameters - if (empty($remise)) $remise=0; + /** + * Set percent discount + * + * @param User $user User that set discount + * @param double $remise Discount + * @return int <0 if ko, >0 if ok + */ + function set_remise($user, $remise) + { + // Clean parameters + if (empty($remise)) $remise=0; - if ($user->rights->facture->creer) - { - $remise=price2num($remise); + if ($user->rights->facture->creer) + { + $remise=price2num($remise); - $sql = 'UPDATE '.MAIN_DB_PREFIX.'facture'; - $sql.= ' SET remise_percent = '.$remise; - $sql.= ' WHERE rowid = '.$this->id; - $sql.= ' AND fk_statut = 0 ;'; + $sql = 'UPDATE '.MAIN_DB_PREFIX.'facture'; + $sql.= ' SET remise_percent = '.$remise; + $sql.= ' WHERE rowid = '.$this->id; + $sql.= ' AND fk_statut = 0 ;'; - if ($this->db->query($sql)) - { - $this->remise_percent = $remise; - $this->update_price(1); - return 1; - } - else - { - $this->error=$this->db->error(); - return -1; - } - } - } + if ($this->db->query($sql)) + { + $this->remise_percent = $remise; + $this->update_price(1); + return 1; + } + else + { + $this->error=$this->db->error(); + return -1; + } + } + } - /** - * Set absolute discount - * - * @param User $user User that set discount - * @param double $remise Discount - * @return int <0 if KO, >0 if OK - */ - function set_remise_absolue($user, $remise) - { - if (empty($remise)) $remise=0; + /** + * Set absolute discount + * + * @param User $user User that set discount + * @param double $remise Discount + * @return int <0 if KO, >0 if OK + */ + function set_remise_absolue($user, $remise) + { + if (empty($remise)) $remise=0; - if ($user->rights->facture->creer) - { - $remise=price2num($remise); + if ($user->rights->facture->creer) + { + $remise=price2num($remise); - $sql = 'UPDATE '.MAIN_DB_PREFIX.'facture'; - $sql.= ' SET remise_absolue = '.$remise; - $sql.= ' WHERE rowid = '.$this->id; - $sql.= ' AND fk_statut = 0 ;'; + $sql = 'UPDATE '.MAIN_DB_PREFIX.'facture'; + $sql.= ' SET remise_absolue = '.$remise; + $sql.= ' WHERE rowid = '.$this->id; + $sql.= ' AND fk_statut = 0 ;'; - dol_syslog(get_class($this)."::set_remise_absolue sql=$sql"); + dol_syslog(get_class($this)."::set_remise_absolue sql=$sql"); - if ($this->db->query($sql)) - { - $this->remise_absolue = $remise; - $this->update_price(1); - return 1; - } - else - { - $this->error=$this->db->error(); - return -1; - } - } - } + if ($this->db->query($sql)) + { + $this->remise_absolue = $remise; + $this->update_price(1); + return 1; + } + else + { + $this->error=$this->db->error(); + return -1; + } + } + } - /** - * Return list of payments - * - * @param string $filtertype 1 to filter on type of payment == 'PRE' - * @return array Array with list of payments - */ - function getListOfPayments($filtertype='') - { - $retarray=array(); + /** + * Return list of payments + * + * @param string $filtertype 1 to filter on type of payment == 'PRE' + * @return array Array with list of payments + */ + function getListOfPayments($filtertype='') + { + $retarray=array(); - $table='paiement_facture'; - $table2='paiement'; - $field='fk_facture'; - $field2='fk_paiement'; - if ($this->element == 'facture_fourn' || $this->element == 'invoice_supplier') - { - $table='paiementfourn_facturefourn'; - $table2='paiementfourn'; - $field='fk_facturefourn'; - $field2='fk_paiementfourn'; - } + $table='paiement_facture'; + $table2='paiement'; + $field='fk_facture'; + $field2='fk_paiement'; + if ($this->element == 'facture_fourn' || $this->element == 'invoice_supplier') + { + $table='paiementfourn_facturefourn'; + $table2='paiementfourn'; + $field='fk_facturefourn'; + $field2='fk_paiementfourn'; + } - $sql = 'SELECT pf.amount, p.fk_paiement, p.datep, t.code'; - $sql.= ' FROM '.MAIN_DB_PREFIX.$table.' as pf, '.MAIN_DB_PREFIX.$table2.' as p, '.MAIN_DB_PREFIX.'c_paiement as t'; - $sql.= ' WHERE pf.'.$field.' = '.$this->id; - $sql.= ' AND pf.'.$field2.' = p.rowid'; - $sql.= ' AND p.fk_paiement = t.id'; - if ($filtertype) $sql.=" AND t.code='PRE'"; + $sql = 'SELECT pf.amount, p.fk_paiement, p.datep, t.code'; + $sql.= ' FROM '.MAIN_DB_PREFIX.$table.' as pf, '.MAIN_DB_PREFIX.$table2.' as p, '.MAIN_DB_PREFIX.'c_paiement as t'; + $sql.= ' WHERE pf.'.$field.' = '.$this->id; + $sql.= ' AND pf.'.$field2.' = p.rowid'; + $sql.= ' AND p.fk_paiement = t.id'; + if ($filtertype) $sql.=" AND t.code='PRE'"; - dol_syslog(get_class($this)."::getListOfPayments sql=".$sql, LOG_DEBUG); - $resql=$this->db->query($sql); - if ($resql) - { - $num = $this->db->num_rows($resql); - $i=0; - while ($i < $num) - { - $obj = $this->db->fetch_object($resql); - $retarray[]=array('amount'=>$obj->amount,'type'=>$obj->code, 'date'=>$obj->datep); - $i++; - } - $this->db->free($resql); - return $retarray; - } - else - { - $this->error=$this->db->lasterror(); - dol_print_error($this->db); - return array(); - } - } + dol_syslog(get_class($this)."::getListOfPayments sql=".$sql, LOG_DEBUG); + $resql=$this->db->query($sql); + if ($resql) + { + $num = $this->db->num_rows($resql); + $i=0; + while ($i < $num) + { + $obj = $this->db->fetch_object($resql); + $retarray[]=array('amount'=>$obj->amount,'type'=>$obj->code, 'date'=>$obj->datep); + $i++; + } + $this->db->free($resql); + return $retarray; + } + else + { + $this->error=$this->db->lasterror(); + dol_print_error($this->db); + return array(); + } + } - /** - * Return amount (with tax) of all credit notes and deposits invoices used by invoice - * - * @return int <0 if KO, Sum of credit notes and deposits amount otherwise - */ - function getSumCreditNotesUsed() - { - require_once DOL_DOCUMENT_ROOT.'/core/class/discount.class.php'; + /** + * Return amount (with tax) of all credit notes and deposits invoices used by invoice + * + * @return int <0 if KO, Sum of credit notes and deposits amount otherwise + */ + function getSumCreditNotesUsed() + { + require_once DOL_DOCUMENT_ROOT.'/core/class/discount.class.php'; - $discountstatic=new DiscountAbsolute($this->db); - $result=$discountstatic->getSumCreditNotesUsed($this); - if ($result >= 0) - { - return $result; - } - else - { - $this->error=$discountstatic->error; - return -1; - } - } + $discountstatic=new DiscountAbsolute($this->db); + $result=$discountstatic->getSumCreditNotesUsed($this); + if ($result >= 0) + { + return $result; + } + else + { + $this->error=$discountstatic->error; + return -1; + } + } - /** - * Return amount (with tax) of all deposits invoices used by invoice - * - * @return int <0 if KO, Sum of deposits amount otherwise - */ - function getSumDepositsUsed() - { - require_once DOL_DOCUMENT_ROOT.'/core/class/discount.class.php'; + /** + * Return amount (with tax) of all deposits invoices used by invoice + * + * @return int <0 if KO, Sum of deposits amount otherwise + */ + function getSumDepositsUsed() + { + require_once DOL_DOCUMENT_ROOT.'/core/class/discount.class.php'; - $discountstatic=new DiscountAbsolute($this->db); - $result=$discountstatic->getSumDepositsUsed($this); - if ($result >= 0) - { - return $result; - } - else - { - $this->error=$discountstatic->error; - return -1; - } - } + $discountstatic=new DiscountAbsolute($this->db); + $result=$discountstatic->getSumDepositsUsed($this); + if ($result >= 0) + { + return $result; + } + else + { + $this->error=$discountstatic->error; + return -1; + } + } - /** - * Return next reference of customer invoice not already used (or last reference) - * according to numbering module defined into constant FACTURE_ADDON - * - * @param Society $soc object company - * @param string $mode 'next' for next value or 'last' for last value - * @return string free ref or last ref - */ - function getNextNumRef($soc,$mode='next') - { - global $conf, $db, $langs; - $langs->load("bills"); + /** + * Return next reference of customer invoice not already used (or last reference) + * according to numbering module defined into constant FACTURE_ADDON + * + * @param Society $soc object company + * @param string $mode 'next' for next value or 'last' for last value + * @return string free ref or last ref + */ + function getNextNumRef($soc,$mode='next') + { + global $conf, $db, $langs; + $langs->load("bills"); - // Clean parameters (if not defined or using deprecated value) - if (empty($conf->global->FACTURE_ADDON)) $conf->global->FACTURE_ADDON='mod_facture_terre'; - else if ($conf->global->FACTURE_ADDON=='terre') $conf->global->FACTURE_ADDON='mod_facture_terre'; - else if ($conf->global->FACTURE_ADDON=='mercure') $conf->global->FACTURE_ADDON='mod_facture_mercure'; + // Clean parameters (if not defined or using deprecated value) + if (empty($conf->global->FACTURE_ADDON)) $conf->global->FACTURE_ADDON='mod_facture_terre'; + else if ($conf->global->FACTURE_ADDON=='terre') $conf->global->FACTURE_ADDON='mod_facture_terre'; + else if ($conf->global->FACTURE_ADDON=='mercure') $conf->global->FACTURE_ADDON='mod_facture_mercure'; - $mybool=false; + $mybool=false; - $file = $conf->global->FACTURE_ADDON.".php"; - $classname = $conf->global->FACTURE_ADDON; - // Include file with class - foreach ($conf->file->dol_document_root as $dirroot) - { - $dir = $dirroot."/core/modules/facture/"; - // Load file with numbering class (if found) - $mybool|=@include_once $dir.$file; - } + $file = $conf->global->FACTURE_ADDON.".php"; + $classname = $conf->global->FACTURE_ADDON; + // Include file with class + foreach ($conf->file->dol_document_root as $dirroot) + { + $dir = $dirroot."/core/modules/facture/"; + // Load file with numbering class (if found) + $mybool|=@include_once $dir.$file; + } - // For compatibility - if (! $mybool) - { - $file = $conf->global->FACTURE_ADDON."/".$conf->global->FACTURE_ADDON.".modules.php"; - $classname = "mod_facture_".$conf->global->FACTURE_ADDON; - // Include file with class - foreach ($conf->file->dol_document_root as $dirroot) - { - $dir = $dirroot."/core/modules/facture/"; - // Load file with numbering class (if found) - $mybool|=@include_once $dir.$file; - } - } - //print "xx".$mybool.$dir.$file."-".$classname; + // For compatibility + if (! $mybool) + { + $file = $conf->global->FACTURE_ADDON."/".$conf->global->FACTURE_ADDON.".modules.php"; + $classname = "mod_facture_".$conf->global->FACTURE_ADDON; + // Include file with class + foreach ($conf->file->dol_document_root as $dirroot) + { + $dir = $dirroot."/core/modules/facture/"; + // Load file with numbering class (if found) + $mybool|=@include_once $dir.$file; + } + } + //print "xx".$mybool.$dir.$file."-".$classname; - if (! $mybool) - { - dol_print_error('',"Failed to include file ".$file); - return ''; - } + if (! $mybool) + { + dol_print_error('',"Failed to include file ".$file); + return ''; + } - $obj = new $classname(); + $obj = new $classname(); - $numref = ""; - $numref = $obj->getNumRef($soc,$this,$mode); + $numref = ""; + $numref = $obj->getNumRef($soc,$this,$mode); - if ( $numref != "") - { - return $numref; - } - else - { - //dol_print_error($db,get_class($this)."::getNextNumRef ".$obj->error); - return false; - } - } + if ( $numref != "") + { + return $numref; + } + else + { + //dol_print_error($db,get_class($this)."::getNextNumRef ".$obj->error); + return false; + } + } - /** - * Load miscellaneous information for tab "Info" - * - * @param int $id Id of object to load - * @return void - */ - function info($id) - { - $sql = 'SELECT c.rowid, datec, date_valid as datev, tms as datem,'; - $sql.= ' fk_user_author, fk_user_valid'; - $sql.= ' FROM '.MAIN_DB_PREFIX.'facture as c'; - $sql.= ' WHERE c.rowid = '.$id; + /** + * Load miscellaneous information for tab "Info" + * + * @param int $id Id of object to load + * @return void + */ + function info($id) + { + $sql = 'SELECT c.rowid, datec, date_valid as datev, tms as datem,'; + $sql.= ' fk_user_author, fk_user_valid'; + $sql.= ' FROM '.MAIN_DB_PREFIX.'facture as c'; + $sql.= ' WHERE c.rowid = '.$id; - $result=$this->db->query($sql); - if ($result) - { - if ($this->db->num_rows($result)) - { - $obj = $this->db->fetch_object($result); - $this->id = $obj->rowid; - if ($obj->fk_user_author) - { - $cuser = new User($this->db); - $cuser->fetch($obj->fk_user_author); - $this->user_creation = $cuser; - } - if ($obj->fk_user_valid) - { - $vuser = new User($this->db); - $vuser->fetch($obj->fk_user_valid); - $this->user_validation = $vuser; - } - $this->date_creation = $this->db->jdate($obj->datec); - $this->date_modification = $this->db->jdate($obj->datem); - $this->date_validation = $this->db->jdate($obj->datev); // Should be in log table - } - $this->db->free($result); - } - else - { - dol_print_error($this->db); - } - } + $result=$this->db->query($sql); + if ($result) + { + if ($this->db->num_rows($result)) + { + $obj = $this->db->fetch_object($result); + $this->id = $obj->rowid; + if ($obj->fk_user_author) + { + $cuser = new User($this->db); + $cuser->fetch($obj->fk_user_author); + $this->user_creation = $cuser; + } + if ($obj->fk_user_valid) + { + $vuser = new User($this->db); + $vuser->fetch($obj->fk_user_valid); + $this->user_validation = $vuser; + } + $this->date_creation = $this->db->jdate($obj->datec); + $this->date_modification = $this->db->jdate($obj->datem); + $this->date_validation = $this->db->jdate($obj->datev); // Should be in log table + } + $this->db->free($result); + } + else + { + dol_print_error($this->db); + } + } - /** - * Renvoi si les lignes de facture sont ventilees et/ou exportees en compta - * - * @return int <0 if KO, 0=no, 1=yes - */ - function getVentilExportCompta() - { - // On verifie si les lignes de factures ont ete exportees en compta et/ou ventilees - $ventilExportCompta = 0 ; - $num=count($this->lines); - for ($i = 0; $i < $num; $i++) - { - if ($this->lines[$i]->export_compta <> 0 && $this->lines[$i]->code_ventilation <> 0) - { - $ventilExportCompta++; - } - } + /** + * Renvoi si les lignes de facture sont ventilees et/ou exportees en compta + * + * @return int <0 if KO, 0=no, 1=yes + */ + function getVentilExportCompta() + { + // On verifie si les lignes de factures ont ete exportees en compta et/ou ventilees + $ventilExportCompta = 0 ; + $num=count($this->lines); + for ($i = 0; $i < $num; $i++) + { + if ($this->lines[$i]->export_compta <> 0 && $this->lines[$i]->code_ventilation <> 0) + { + $ventilExportCompta++; + } + } - if ($ventilExportCompta <> 0) - { - return 1; - } - else - { - return 0; - } - } + if ($ventilExportCompta <> 0) + { + return 1; + } + else + { + return 0; + } + } - /** - * Return if an invoice can be deleted - * Rule is: - * If hidden option INVOICE_CAN_ALWAYS_BE_REMOVED is on, we can - * If invoice has a definitive ref, is last, without payment and not dipatched into accountancy -> yes end of rule - * If invoice is draft and ha a temporary ref -> yes - * - * @return int <0 if KO, 0=no, 1=yes - */ - function is_erasable() - { - global $conf; + /** + * Return if an invoice can be deleted + * Rule is: + * If hidden option INVOICE_CAN_ALWAYS_BE_REMOVED is on, we can + * If invoice has a definitive ref, is last, without payment and not dipatched into accountancy -> yes end of rule + * If invoice is draft and ha a temporary ref -> yes + * + * @return int <0 if KO, 0=no, 1=yes + */ + function is_erasable() + { + global $conf; - if (! empty($conf->global->INVOICE_CAN_ALWAYS_BE_REMOVED)) return 1; - if (! empty($conf->global->INVOICE_CAN_NEVER_BE_REMOVED)) return 0; + if (! empty($conf->global->INVOICE_CAN_ALWAYS_BE_REMOVED)) return 1; + if (! empty($conf->global->INVOICE_CAN_NEVER_BE_REMOVED)) return 0; - // on verifie si la facture est en numerotation provisoire - $facref = substr($this->ref, 1, 4); + // on verifie si la facture est en numerotation provisoire + $facref = substr($this->ref, 1, 4); - // If not a draft invoice and not temporary invoice - if ($facref != 'PROV') - { - $maxfacnumber = $this->getNextNumRef($this->client,'last'); - $ventilExportCompta = $this->getVentilExportCompta(); - // If there is no invoice into the reset range and not already dispatched, we can delete - if ($maxfacnumber == '' && $ventilExportCompta == 0) return 1; - // If invoice to delete is last one and not already dispatched, we can delete - if ($maxfacnumber == $this->ref && $ventilExportCompta == 0) return 1; - } - else if ($this->statut == 0 && $facref == 'PROV') // Si facture brouillon et provisoire - { - return 1; - } + // If not a draft invoice and not temporary invoice + if ($facref != 'PROV') + { + $maxfacnumber = $this->getNextNumRef($this->client,'last'); + $ventilExportCompta = $this->getVentilExportCompta(); + // If there is no invoice into the reset range and not already dispatched, we can delete + if ($maxfacnumber == '' && $ventilExportCompta == 0) return 1; + // If invoice to delete is last one and not already dispatched, we can delete + if ($maxfacnumber == $this->ref && $ventilExportCompta == 0) return 1; + } + else if ($this->statut == 0 && $facref == 'PROV') // Si facture brouillon et provisoire + { + return 1; + } - return 0; - } + return 0; + } - /** - * Renvoi liste des factures remplacables - * Statut validee ou abandonnee pour raison autre + non payee + aucun paiement + pas deja remplacee - * - * @param int $socid Id societe - * @return array Tableau des factures ('id'=>id, 'ref'=>ref, 'status'=>status, 'paymentornot'=>0/1) - */ - function list_replacable_invoices($socid=0) - { - global $conf; + /** + * Renvoi liste des factures remplacables + * Statut validee ou abandonnee pour raison autre + non payee + aucun paiement + pas deja remplacee + * + * @param int $socid Id societe + * @return array Tableau des factures ('id'=>id, 'ref'=>ref, 'status'=>status, 'paymentornot'=>0/1) + */ + function list_replacable_invoices($socid=0) + { + global $conf; - $return = array(); + $return = array(); - $sql = "SELECT f.rowid as rowid, f.facnumber, f.fk_statut,"; - $sql.= " ff.rowid as rowidnext"; - $sql.= " FROM ".MAIN_DB_PREFIX."facture as f"; - $sql.= " LEFT JOIN ".MAIN_DB_PREFIX."paiement_facture as pf ON f.rowid = pf.fk_facture"; - $sql.= " LEFT JOIN ".MAIN_DB_PREFIX."facture as ff ON f.rowid = ff.fk_facture_source"; - $sql.= " WHERE (f.fk_statut = 1 OR (f.fk_statut = 3 AND f.close_code = 'abandon'))"; - $sql.= " AND f.entity = ".$conf->entity; - $sql.= " AND f.paye = 0"; // Pas classee payee completement - $sql.= " AND pf.fk_paiement IS NULL"; // Aucun paiement deja fait - $sql.= " AND ff.fk_statut IS NULL"; // Renvoi vrai si pas facture de remplacement - if ($socid > 0) $sql.=" AND f.fk_soc = ".$socid; - $sql.= " ORDER BY f.facnumber"; + $sql = "SELECT f.rowid as rowid, f.facnumber, f.fk_statut,"; + $sql.= " ff.rowid as rowidnext"; + $sql.= " FROM ".MAIN_DB_PREFIX."facture as f"; + $sql.= " LEFT JOIN ".MAIN_DB_PREFIX."paiement_facture as pf ON f.rowid = pf.fk_facture"; + $sql.= " LEFT JOIN ".MAIN_DB_PREFIX."facture as ff ON f.rowid = ff.fk_facture_source"; + $sql.= " WHERE (f.fk_statut = 1 OR (f.fk_statut = 3 AND f.close_code = 'abandon'))"; + $sql.= " AND f.entity = ".$conf->entity; + $sql.= " AND f.paye = 0"; // Pas classee payee completement + $sql.= " AND pf.fk_paiement IS NULL"; // Aucun paiement deja fait + $sql.= " AND ff.fk_statut IS NULL"; // Renvoi vrai si pas facture de remplacement + if ($socid > 0) $sql.=" AND f.fk_soc = ".$socid; + $sql.= " ORDER BY f.facnumber"; - dol_syslog(get_class($this)."::list_replacable_invoices sql=$sql"); - $resql=$this->db->query($sql); - if ($resql) - { - while ($obj=$this->db->fetch_object($resql)) - { - $return[$obj->rowid]=array( 'id' => $obj->rowid, + dol_syslog(get_class($this)."::list_replacable_invoices sql=$sql"); + $resql=$this->db->query($sql); + if ($resql) + { + while ($obj=$this->db->fetch_object($resql)) + { + $return[$obj->rowid]=array( 'id' => $obj->rowid, 'ref' => $obj->facnumber, 'status' => $obj->fk_statut); - } - //print_r($return); - return $return; - } - else - { - $this->error=$this->db->error(); - dol_syslog(get_class($this)."::list_replacable_invoices ".$this->error, LOG_ERR); - return -1; - } - } + } + //print_r($return); + return $return; + } + else + { + $this->error=$this->db->error(); + dol_syslog(get_class($this)."::list_replacable_invoices ".$this->error, LOG_ERR); + return -1; + } + } - /** - * Renvoi liste des factures qualifiables pour correction par avoir - * Les factures qui respectent les regles suivantes sont retournees: - * (validee + paiement en cours) ou classee (payee completement ou payee partiellement) + pas deja remplacee + pas deja avoir - * - * @param int $socid Id societe - * @return array Tableau des factures ($id => array('ref'=>,'paymentornot'=>,'status'=>,'paye'=>) - */ - function list_qualified_avoir_invoices($socid=0) - { - global $conf; + /** + * Renvoi liste des factures qualifiables pour correction par avoir + * Les factures qui respectent les regles suivantes sont retournees: + * (validee + paiement en cours) ou classee (payee completement ou payee partiellement) + pas deja remplacee + pas deja avoir + * + * @param int $socid Id societe + * @return array Tableau des factures ($id => array('ref'=>,'paymentornot'=>,'status'=>,'paye'=>) + */ + function list_qualified_avoir_invoices($socid=0) + { + global $conf; - $return = array(); + $return = array(); - $sql = "SELECT f.rowid as rowid, f.facnumber, f.fk_statut, f.type, f.paye, pf.fk_paiement"; - $sql.= " FROM ".MAIN_DB_PREFIX."facture as f"; - $sql.= " LEFT JOIN ".MAIN_DB_PREFIX."paiement_facture as pf ON f.rowid = pf.fk_facture"; - $sql.= " LEFT JOIN ".MAIN_DB_PREFIX."facture as ff ON (f.rowid = ff.fk_facture_source AND ff.type=1)"; - $sql.= " WHERE f.entity = ".$conf->entity; - $sql.= " AND f.fk_statut in (1,2)"; - // $sql.= " WHERE f.fk_statut >= 1"; - // $sql.= " AND (f.paye = 1"; // Classee payee completement - // $sql.= " OR f.close_code IS NOT NULL)"; // Classee payee partiellement - $sql.= " AND ff.type IS NULL"; // Renvoi vrai si pas facture de remplacement - $sql.= " AND f.type != 2"; // Type non 2 si facture non avoir - if ($socid > 0) $sql.=" AND f.fk_soc = ".$socid; - $sql.= " ORDER BY f.facnumber"; + $sql = "SELECT f.rowid as rowid, f.facnumber, f.fk_statut, f.type, f.paye, pf.fk_paiement"; + $sql.= " FROM ".MAIN_DB_PREFIX."facture as f"; + $sql.= " LEFT JOIN ".MAIN_DB_PREFIX."paiement_facture as pf ON f.rowid = pf.fk_facture"; + $sql.= " LEFT JOIN ".MAIN_DB_PREFIX."facture as ff ON (f.rowid = ff.fk_facture_source AND ff.type=1)"; + $sql.= " WHERE f.entity = ".$conf->entity; + $sql.= " AND f.fk_statut in (1,2)"; + // $sql.= " WHERE f.fk_statut >= 1"; + // $sql.= " AND (f.paye = 1"; // Classee payee completement + // $sql.= " OR f.close_code IS NOT NULL)"; // Classee payee partiellement + $sql.= " AND ff.type IS NULL"; // Renvoi vrai si pas facture de remplacement + $sql.= " AND f.type != 2"; // Type non 2 si facture non avoir + if ($socid > 0) $sql.=" AND f.fk_soc = ".$socid; + $sql.= " ORDER BY f.facnumber"; - dol_syslog(get_class($this)."::list_qualified_avoir_invoices sql=".$sql); - $resql=$this->db->query($sql); - if ($resql) - { - while ($obj=$this->db->fetch_object($resql)) - { - $qualified=0; - if ($obj->fk_statut == 1) $qualified=1; - if ($obj->fk_statut == 2) $qualified=1; - if ($qualified) - { - //$ref=$obj->facnumber; - $paymentornot=($obj->fk_paiement?1:0); - $return[$obj->rowid]=array('ref'=>$obj->facnumber,'status'=>$obj->fk_statut,'type'=>$obj->type,'paye'=>$obj->paye,'paymentornot'=>$paymentornot); - } - } + dol_syslog(get_class($this)."::list_qualified_avoir_invoices sql=".$sql); + $resql=$this->db->query($sql); + if ($resql) + { + while ($obj=$this->db->fetch_object($resql)) + { + $qualified=0; + if ($obj->fk_statut == 1) $qualified=1; + if ($obj->fk_statut == 2) $qualified=1; + if ($qualified) + { + //$ref=$obj->facnumber; + $paymentornot=($obj->fk_paiement?1:0); + $return[$obj->rowid]=array('ref'=>$obj->facnumber,'status'=>$obj->fk_statut,'type'=>$obj->type,'paye'=>$obj->paye,'paymentornot'=>$paymentornot); + } + } - return $return; - } - else - { - $this->error=$this->db->error(); - dol_syslog(get_class($this)."::list_avoir_invoices ".$this->error, LOG_ERR); - return -1; - } - } + return $return; + } + else + { + $this->error=$this->db->error(); + dol_syslog(get_class($this)."::list_avoir_invoices ".$this->error, LOG_ERR); + return -1; + } + } - /** - * Create a withdrawal request for a standing order - * - * @param User $user User asking standing order - * @return int <0 if KO, >0 if OK - */ - function demande_prelevement($user) - { - dol_syslog(get_class($this)."::demande_prelevement", LOG_DEBUG); + /** + * Create a withdrawal request for a standing order + * + * @param User $user User asking standing order + * @return int <0 if KO, >0 if OK + */ + function demande_prelevement($user) + { + dol_syslog(get_class($this)."::demande_prelevement", LOG_DEBUG); - $soc = new Societe($this->db); - $soc->id = $this->socid; - $soc->load_ban(); + $soc = new Societe($this->db); + $soc->id = $this->socid; + $soc->load_ban(); - if ($this->statut > 0 && $this->paye == 0) - { - $sql = 'SELECT count(*)'; - $sql.= ' FROM '.MAIN_DB_PREFIX.'prelevement_facture_demande'; - $sql.= ' WHERE fk_facture = '.$this->id; - $sql.= ' AND traite = 0'; + if ($this->statut > 0 && $this->paye == 0) + { + $sql = 'SELECT count(*)'; + $sql.= ' FROM '.MAIN_DB_PREFIX.'prelevement_facture_demande'; + $sql.= ' WHERE fk_facture = '.$this->id; + $sql.= ' AND traite = 0'; - $resql=$this->db->query($sql); - if ($resql) - { - $row = $this->db->fetch_row($resql); - if ($row[0] == 0) - { - $now=dol_now(); + $resql=$this->db->query($sql); + if ($resql) + { + $row = $this->db->fetch_row($resql); + if ($row[0] == 0) + { + $now=dol_now(); - $sql = 'INSERT INTO '.MAIN_DB_PREFIX.'prelevement_facture_demande'; - $sql .= ' (fk_facture, amount, date_demande, fk_user_demande, code_banque, code_guichet, number, cle_rib)'; - $sql .= ' VALUES ('.$this->id; - $sql .= ",'".price2num($this->total_ttc)."'"; - $sql .= ",".$this->db->idate($now).",".$user->id; - $sql .= ",'".$soc->bank_account->code_banque."'"; - $sql .= ",'".$soc->bank_account->code_guichet."'"; - $sql .= ",'".$soc->bank_account->number."'"; - $sql .= ",'".$soc->bank_account->cle_rib."')"; - if ( $this->db->query($sql)) - { - return 1; - } - else - { - $this->error=$this->db->error(); - dol_syslog(get_class($this).'::demandeprelevement Erreur'); - return -1; - } - } - else - { - $this->error="A request already exists"; - dol_syslog(get_class($this).'::demandeprelevement Impossible de creer une demande, demande deja en cours'); - } - } - else - { - $this->error=$this->db->error(); - dol_syslog(get_class($this).'::demandeprelevement Erreur -2'); - return -2; - } - } - else - { - $this->error="Status of invoice does not allow this"; - dol_syslog(get_class($this)."::demandeprelevement ".$this->error." $this->statut, $this->paye, $this->mode_reglement_id"); - return -3; - } - } + $sql = 'INSERT INTO '.MAIN_DB_PREFIX.'prelevement_facture_demande'; + $sql .= ' (fk_facture, amount, date_demande, fk_user_demande, code_banque, code_guichet, number, cle_rib)'; + $sql .= ' VALUES ('.$this->id; + $sql .= ",'".price2num($this->total_ttc)."'"; + $sql .= ",".$this->db->idate($now).",".$user->id; + $sql .= ",'".$soc->bank_account->code_banque."'"; + $sql .= ",'".$soc->bank_account->code_guichet."'"; + $sql .= ",'".$soc->bank_account->number."'"; + $sql .= ",'".$soc->bank_account->cle_rib."')"; + if ( $this->db->query($sql)) + { + return 1; + } + else + { + $this->error=$this->db->error(); + dol_syslog(get_class($this).'::demandeprelevement Erreur'); + return -1; + } + } + else + { + $this->error="A request already exists"; + dol_syslog(get_class($this).'::demandeprelevement Impossible de creer une demande, demande deja en cours'); + } + } + else + { + $this->error=$this->db->error(); + dol_syslog(get_class($this).'::demandeprelevement Erreur -2'); + return -2; + } + } + else + { + $this->error="Status of invoice does not allow this"; + dol_syslog(get_class($this)."::demandeprelevement ".$this->error." $this->statut, $this->paye, $this->mode_reglement_id"); + return -3; + } + } - /** - * Supprime une demande de prelevement - * - * @param Use $user utilisateur creant la demande - * @param int $did id de la demande a supprimer - * @return int <0 if OK, >0 if KO - */ - function demande_prelevement_delete($user, $did) - { - $sql = 'DELETE FROM '.MAIN_DB_PREFIX.'prelevement_facture_demande'; - $sql .= ' WHERE rowid = '.$did; - $sql .= ' AND traite = 0'; - if ( $this->db->query($sql) ) - { - return 0; - } - else - { - $this->error=$this->db->lasterror(); - dol_syslog(get_class($this).'::demande_prelevement_delete Error '.$this->error); - return -1; - } - } + /** + * Supprime une demande de prelevement + * + * @param Use $user utilisateur creant la demande + * @param int $did id de la demande a supprimer + * @return int <0 if OK, >0 if KO + */ + function demande_prelevement_delete($user, $did) + { + $sql = 'DELETE FROM '.MAIN_DB_PREFIX.'prelevement_facture_demande'; + $sql .= ' WHERE rowid = '.$did; + $sql .= ' AND traite = 0'; + if ( $this->db->query($sql) ) + { + return 0; + } + else + { + $this->error=$this->db->lasterror(); + dol_syslog(get_class($this).'::demande_prelevement_delete Error '.$this->error); + return -1; + } + } - /** - * Load indicators for dashboard (this->nbtodo and this->nbtodolate) - * - * @param User $user Object user - * @return int <0 if KO, >0 if OK - */ - function load_board($user) - { - global $conf, $user; + /** + * Load indicators for dashboard (this->nbtodo and this->nbtodolate) + * + * @param User $user Object user + * @return int <0 if KO, >0 if OK + */ + function load_board($user) + { + global $conf, $user; - $now=dol_now(); + $now=dol_now(); - $this->nbtodo=$this->nbtodolate=0; - $clause = " WHERE"; + $this->nbtodo=$this->nbtodolate=0; + $clause = " WHERE"; - $sql = "SELECT f.rowid, f.date_lim_reglement as datefin"; - $sql.= " FROM ".MAIN_DB_PREFIX."facture as f"; - if (!$user->rights->societe->client->voir && !$user->societe_id) - { - $sql.= " LEFT JOIN ".MAIN_DB_PREFIX."societe_commerciaux as sc ON f.fk_soc = sc.fk_soc"; - $sql.= " WHERE sc.fk_user = " .$user->id; - $clause = " AND"; - } - $sql.= $clause." f.paye=0"; - $sql.= " AND f.entity = ".$conf->entity; - $sql.= " AND f.fk_statut = 1"; - if ($user->societe_id) $sql.= " AND f.fk_soc = ".$user->societe_id; + $sql = "SELECT f.rowid, f.date_lim_reglement as datefin"; + $sql.= " FROM ".MAIN_DB_PREFIX."facture as f"; + if (!$user->rights->societe->client->voir && !$user->societe_id) + { + $sql.= " LEFT JOIN ".MAIN_DB_PREFIX."societe_commerciaux as sc ON f.fk_soc = sc.fk_soc"; + $sql.= " WHERE sc.fk_user = " .$user->id; + $clause = " AND"; + } + $sql.= $clause." f.paye=0"; + $sql.= " AND f.entity = ".$conf->entity; + $sql.= " AND f.fk_statut = 1"; + if ($user->societe_id) $sql.= " AND f.fk_soc = ".$user->societe_id; - $resql=$this->db->query($sql); - if ($resql) - { - while ($obj=$this->db->fetch_object($resql)) - { - $this->nbtodo++; - if ($this->db->jdate($obj->datefin) < ($now - $conf->facture->client->warning_delay)) $this->nbtodolate++; - } - return 1; - } - else - { - dol_print_error($this->db); - $this->error=$this->db->error(); - return -1; - } - } + $resql=$this->db->query($sql); + if ($resql) + { + while ($obj=$this->db->fetch_object($resql)) + { + $this->nbtodo++; + if ($this->db->jdate($obj->datefin) < ($now - $conf->facture->client->warning_delay)) $this->nbtodolate++; + } + return 1; + } + else + { + dol_print_error($this->db); + $this->error=$this->db->error(); + return -1; + } + } - /* gestion des contacts d'une facture */ + /* gestion des contacts d'une facture */ - /** - * Retourne id des contacts clients de facturation - * - * @return array Liste des id contacts facturation - */ - function getIdBillingContact() - { - return $this->getIdContact('external','BILLING'); - } + /** + * Retourne id des contacts clients de facturation + * + * @return array Liste des id contacts facturation + */ + function getIdBillingContact() + { + return $this->getIdContact('external','BILLING'); + } - /** - * Retourne id des contacts clients de livraison - * - * @return array Liste des id contacts livraison - */ - function getIdShippingContact() - { - return $this->getIdContact('external','SHIPPING'); - } + /** + * Retourne id des contacts clients de livraison + * + * @return array Liste des id contacts livraison + */ + function getIdShippingContact() + { + return $this->getIdContact('external','SHIPPING'); + } - /** - * Initialise an instance with random values. - * Used to build previews or test instances. - * id must be 0 if object instance is a specimen. - * - * @param string $option ''=Create a specimen invoice with lines, 'nolines'=No lines - * @return void - */ - function initAsSpecimen($option='') - { - global $user,$langs,$conf; + /** + * Initialise an instance with random values. + * Used to build previews or test instances. + * id must be 0 if object instance is a specimen. + * + * @param string $option ''=Create a specimen invoice with lines, 'nolines'=No lines + * @return void + */ + function initAsSpecimen($option='') + { + global $user,$langs,$conf; - $now=dol_now(); - $arraynow=dol_getdate($now); - $nownotime=dol_mktime(0, 0, 0, $arraynow['mon'], $arraynow['mday'], $arraynow['year']); + $now=dol_now(); + $arraynow=dol_getdate($now); + $nownotime=dol_mktime(0, 0, 0, $arraynow['mon'], $arraynow['mday'], $arraynow['year']); - $prodids = array(); - $sql = "SELECT rowid"; - $sql.= " FROM ".MAIN_DB_PREFIX."product"; - $sql.= " WHERE entity IN (".getEntity('product', 1).")"; - $resql = $this->db->query($sql); - if ($resql) - { - $num_prods = $this->db->num_rows($resql); - $i = 0; - while ($i < $num_prods) - { - $i++; - $row = $this->db->fetch_row($resql); - $prodids[$i] = $row[0]; - } - } + $prodids = array(); + $sql = "SELECT rowid"; + $sql.= " FROM ".MAIN_DB_PREFIX."product"; + $sql.= " WHERE entity IN (".getEntity('product', 1).")"; + $resql = $this->db->query($sql); + if ($resql) + { + $num_prods = $this->db->num_rows($resql); + $i = 0; + while ($i < $num_prods) + { + $i++; + $row = $this->db->fetch_row($resql); + $prodids[$i] = $row[0]; + } + } - // Initialize parameters - $this->id=0; - $this->ref = 'SPECIMEN'; - $this->specimen=1; - $this->socid = 1; - $this->date = $nownotime; - $this->date_lim_reglement = $nownotime + 3600 * 24 *30; - $this->cond_reglement_id = 1; - $this->cond_reglement_code = 'RECEP'; - $this->date_lim_reglement=$this->calculate_date_lim_reglement(); - $this->mode_reglement_id = 0; // Not forced to show payment mode CHQ + VIR - $this->mode_reglement_code = ''; // Not forced to show payment mode CHQ + VIR - $this->note_public='This is a comment (public)'; - $this->note_private='This is a comment (private)'; - $this->note='This is a comment (private)'; + // Initialize parameters + $this->id=0; + $this->ref = 'SPECIMEN'; + $this->specimen=1; + $this->socid = 1; + $this->date = $nownotime; + $this->date_lim_reglement = $nownotime + 3600 * 24 *30; + $this->cond_reglement_id = 1; + $this->cond_reglement_code = 'RECEP'; + $this->date_lim_reglement=$this->calculate_date_lim_reglement(); + $this->mode_reglement_id = 0; // Not forced to show payment mode CHQ + VIR + $this->mode_reglement_code = ''; // Not forced to show payment mode CHQ + VIR + $this->note_public='This is a comment (public)'; + $this->note_private='This is a comment (private)'; + $this->note='This is a comment (private)'; - if (empty($option) || $option != 'nolines') - { - // Lines - $nbp = 5; - $xnbp = 0; - while ($xnbp < $nbp) - { - $line=new FactureLigne($this->db); - $line->desc=$langs->trans("Description")." ".$xnbp; - $line->qty=1; - $line->subprice=100; - $line->tva_tx=19.6; - $line->localtax1_tx=0; - $line->localtax2_tx=0; - $line->remise_percent=0; - if ($xnbp == 1) // Qty is negative (product line) - { - $prodid = rand(1, $num_prods); - $line->fk_product=$prodids[$prodid]; - $line->qty=-1; - $line->total_ht=-100; - $line->total_ttc=-119.6; - $line->total_tva=-19.6; - } - else if ($xnbp == 2) // UP is negative (free line) - { - $line->subprice=-100; - $line->total_ht=-100; - $line->total_ttc=-119.6; - $line->total_tva=-19.6; - $line->remise_percent=0; - } - else if ($xnbp == 3) // Discount is 50% (product line) - { - $prodid = rand(1, $num_prods); - $line->fk_product=$prodids[$prodid]; - $line->total_ht=50; - $line->total_ttc=59.8; - $line->total_tva=9.8; - $line->remise_percent=50; - } - else // (product line) - { - $prodid = rand(1, $num_prods); - $line->fk_product=$prodids[$prodid]; - $line->total_ht=100; - $line->total_ttc=119.6; - $line->total_tva=19.6; - $line->remise_percent=00; - } + if (empty($option) || $option != 'nolines') + { + // Lines + $nbp = 5; + $xnbp = 0; + while ($xnbp < $nbp) + { + $line=new FactureLigne($this->db); + $line->desc=$langs->trans("Description")." ".$xnbp; + $line->qty=1; + $line->subprice=100; + $line->tva_tx=19.6; + $line->localtax1_tx=0; + $line->localtax2_tx=0; + $line->remise_percent=0; + if ($xnbp == 1) // Qty is negative (product line) + { + $prodid = rand(1, $num_prods); + $line->fk_product=$prodids[$prodid]; + $line->qty=-1; + $line->total_ht=-100; + $line->total_ttc=-119.6; + $line->total_tva=-19.6; + } + else if ($xnbp == 2) // UP is negative (free line) + { + $line->subprice=-100; + $line->total_ht=-100; + $line->total_ttc=-119.6; + $line->total_tva=-19.6; + $line->remise_percent=0; + } + else if ($xnbp == 3) // Discount is 50% (product line) + { + $prodid = rand(1, $num_prods); + $line->fk_product=$prodids[$prodid]; + $line->total_ht=50; + $line->total_ttc=59.8; + $line->total_tva=9.8; + $line->remise_percent=50; + } + else // (product line) + { + $prodid = rand(1, $num_prods); + $line->fk_product=$prodids[$prodid]; + $line->total_ht=100; + $line->total_ttc=119.6; + $line->total_tva=19.6; + $line->remise_percent=00; + } - $this->lines[$xnbp]=$line; - $xnbp++; + $this->lines[$xnbp]=$line; + $xnbp++; - $this->total_ht += $line->total_ht; - $this->total_tva += $line->total_tva; - $this->total_ttc += $line->total_ttc; - } - $this->revenuestamp = 0; - - // Add a line "offered" - $line=new FactureLigne($this->db); - $line->desc=$langs->trans("Description")." (offered line)"; - $line->qty=1; - $line->subprice=100; - $line->tva_tx=19.6; - $line->localtax1_tx=0; - $line->localtax2_tx=0; - $line->remise_percent=100; - $line->total_ht=0; - $line->total_ttc=0; // 90 * 1.196 - $line->total_tva=0; - $prodid = rand(1, $num_prods); - $line->fk_product=$prodids[$prodid]; + $this->total_ht += $line->total_ht; + $this->total_tva += $line->total_tva; + $this->total_ttc += $line->total_ttc; + } + $this->revenuestamp = 0; - $this->lines[$xnbp]=$line; - $xnbp++; - } - } + // Add a line "offered" + $line=new FactureLigne($this->db); + $line->desc=$langs->trans("Description")." (offered line)"; + $line->qty=1; + $line->subprice=100; + $line->tva_tx=19.6; + $line->localtax1_tx=0; + $line->localtax2_tx=0; + $line->remise_percent=100; + $line->total_ht=0; + $line->total_ttc=0; // 90 * 1.196 + $line->total_tva=0; + $prodid = rand(1, $num_prods); + $line->fk_product=$prodids[$prodid]; - /** - * Load indicators for dashboard (this->nbtodo and this->nbtodolate) - * + $this->lines[$xnbp]=$line; + $xnbp++; + } + } + + /** + * Load indicators for dashboard (this->nbtodo and this->nbtodolate) + * * @return int <0 if KO, >0 if OK - */ - function load_state_board() - { - global $conf, $user; + */ + function load_state_board() + { + global $conf, $user; - $this->nb=array(); + $this->nb=array(); - $clause = "WHERE"; + $clause = "WHERE"; - $sql = "SELECT count(f.rowid) as nb"; - $sql.= " FROM ".MAIN_DB_PREFIX."facture as f"; - $sql.= " LEFT JOIN ".MAIN_DB_PREFIX."societe as s ON f.fk_soc = s.rowid"; - if (!$user->rights->societe->client->voir && !$user->societe_id) - { - $sql.= " LEFT JOIN ".MAIN_DB_PREFIX."societe_commerciaux as sc ON s.rowid = sc.fk_soc"; - $sql.= " WHERE sc.fk_user = " .$user->id; - $clause = "AND"; - } - $sql.= " ".$clause." f.entity = ".$conf->entity; + $sql = "SELECT count(f.rowid) as nb"; + $sql.= " FROM ".MAIN_DB_PREFIX."facture as f"; + $sql.= " LEFT JOIN ".MAIN_DB_PREFIX."societe as s ON f.fk_soc = s.rowid"; + if (!$user->rights->societe->client->voir && !$user->societe_id) + { + $sql.= " LEFT JOIN ".MAIN_DB_PREFIX."societe_commerciaux as sc ON s.rowid = sc.fk_soc"; + $sql.= " WHERE sc.fk_user = " .$user->id; + $clause = "AND"; + } + $sql.= " ".$clause." f.entity = ".$conf->entity; - $resql=$this->db->query($sql); - if ($resql) - { - while ($obj=$this->db->fetch_object($resql)) - { - $this->nb["invoices"]=$obj->nb; - } - return 1; - } - else - { - dol_print_error($this->db); - $this->error=$this->db->error(); - return -1; - } - } + $resql=$this->db->query($sql); + if ($resql) + { + while ($obj=$this->db->fetch_object($resql)) + { + $this->nb["invoices"]=$obj->nb; + } + return 1; + } + else + { + dol_print_error($this->db); + $this->error=$this->db->error(); + return -1; + } + } - /** - * Create an array of invoice lines - * - * @return int >0 if OK, <0 if KO - */ - function getLinesArray() - { - $sql = 'SELECT l.rowid, l.label as custom_label, l.description, l.fk_product, l.product_type, l.qty, l.tva_tx,'; - $sql.= ' l.fk_remise_except, l.localtax1_tx, l.localtax2_tx,'; - $sql.= ' l.remise_percent, l.subprice, l.info_bits, l.rang, l.special_code, l.fk_parent_line,'; - $sql.= ' l.total_ht, l.total_tva, l.total_ttc, l.fk_product_fournisseur_price as fk_fournprice, l.buy_price_ht as pa_ht,'; - $sql.= ' l.date_start, l.date_end,'; - $sql.= ' p.ref as product_ref, p.fk_product_type, p.label as product_label,'; - $sql.= ' p.description as product_desc'; - $sql.= ' FROM '.MAIN_DB_PREFIX.'facturedet as l'; - $sql.= ' LEFT JOIN '.MAIN_DB_PREFIX.'product p ON l.fk_product=p.rowid'; - $sql.= ' WHERE l.fk_facture = '.$this->id; - $sql.= ' ORDER BY l.rang ASC, l.rowid'; + /** + * Create an array of invoice lines + * + * @return int >0 if OK, <0 if KO + */ + function getLinesArray() + { + $sql = 'SELECT l.rowid, l.label as custom_label, l.description, l.fk_product, l.product_type, l.qty, l.tva_tx,'; + $sql.= ' l.fk_remise_except, l.localtax1_tx, l.localtax2_tx,'; + $sql.= ' l.remise_percent, l.subprice, l.info_bits, l.rang, l.special_code, l.fk_parent_line,'; + $sql.= ' l.total_ht, l.total_tva, l.total_ttc, l.fk_product_fournisseur_price as fk_fournprice, l.buy_price_ht as pa_ht,'; + $sql.= ' l.date_start, l.date_end,'; + $sql.= ' p.ref as product_ref, p.fk_product_type, p.label as product_label,'; + $sql.= ' p.description as product_desc'; + $sql.= ' FROM '.MAIN_DB_PREFIX.'facturedet as l'; + $sql.= ' LEFT JOIN '.MAIN_DB_PREFIX.'product p ON l.fk_product=p.rowid'; + $sql.= ' WHERE l.fk_facture = '.$this->id; + $sql.= ' ORDER BY l.rang ASC, l.rowid'; - $resql = $this->db->query($sql); - if ($resql) - { - $num = $this->db->num_rows($resql); - $i = 0; + $resql = $this->db->query($sql); + if ($resql) + { + $num = $this->db->num_rows($resql); + $i = 0; - while ($i < $num) - { - $obj = $this->db->fetch_object($resql); + while ($i < $num) + { + $obj = $this->db->fetch_object($resql); - $this->lines[$i]->id = $obj->rowid; - $this->lines[$i]->label = $obj->custom_label; - $this->lines[$i]->description = $obj->description; - $this->lines[$i]->fk_product = $obj->fk_product; - $this->lines[$i]->ref = $obj->product_ref; - $this->lines[$i]->product_label = $obj->product_label; - $this->lines[$i]->product_desc = $obj->product_desc; - $this->lines[$i]->fk_product_type = $obj->fk_product_type; - $this->lines[$i]->product_type = $obj->product_type; - $this->lines[$i]->qty = $obj->qty; - $this->lines[$i]->subprice = $obj->subprice; - $this->lines[$i]->fk_remise_except = $obj->fk_remise_except; - $this->lines[$i]->remise_percent = $obj->remise_percent; - $this->lines[$i]->tva_tx = $obj->tva_tx; - $this->lines[$i]->info_bits = $obj->info_bits; - $this->lines[$i]->total_ht = $obj->total_ht; - $this->lines[$i]->total_tva = $obj->total_tva; - $this->lines[$i]->total_ttc = $obj->total_ttc; - $this->lines[$i]->fk_parent_line = $obj->fk_parent_line; - $this->lines[$i]->special_code = $obj->special_code; - $this->lines[$i]->rang = $obj->rang; - $this->lines[$i]->date_start = $this->db->jdate($obj->date_start); - $this->lines[$i]->date_end = $this->db->jdate($obj->date_end); + $this->lines[$i]->id = $obj->rowid; + $this->lines[$i]->label = $obj->custom_label; + $this->lines[$i]->description = $obj->description; + $this->lines[$i]->fk_product = $obj->fk_product; + $this->lines[$i]->ref = $obj->product_ref; + $this->lines[$i]->product_label = $obj->product_label; + $this->lines[$i]->product_desc = $obj->product_desc; + $this->lines[$i]->fk_product_type = $obj->fk_product_type; + $this->lines[$i]->product_type = $obj->product_type; + $this->lines[$i]->qty = $obj->qty; + $this->lines[$i]->subprice = $obj->subprice; + $this->lines[$i]->fk_remise_except = $obj->fk_remise_except; + $this->lines[$i]->remise_percent = $obj->remise_percent; + $this->lines[$i]->tva_tx = $obj->tva_tx; + $this->lines[$i]->info_bits = $obj->info_bits; + $this->lines[$i]->total_ht = $obj->total_ht; + $this->lines[$i]->total_tva = $obj->total_tva; + $this->lines[$i]->total_ttc = $obj->total_ttc; + $this->lines[$i]->fk_parent_line = $obj->fk_parent_line; + $this->lines[$i]->special_code = $obj->special_code; + $this->lines[$i]->rang = $obj->rang; + $this->lines[$i]->date_start = $this->db->jdate($obj->date_start); + $this->lines[$i]->date_end = $this->db->jdate($obj->date_end); $this->lines[$i]->fk_fournprice = $obj->fk_fournprice; $marginInfos = getMarginInfos($obj->subprice, $obj->remise_percent, $obj->tva_tx, $obj->localtax1_tx, $obj->localtax2_tx, $this->lines[$i]->fk_fournprice, $obj->pa_ht); $this->lines[$i]->pa_ht = $marginInfos[0]; $this->lines[$i]->marge_tx = $marginInfos[1]; $this->lines[$i]->marque_tx = $marginInfos[2]; - $i++; - } - $this->db->free($resql); + $i++; + } + $this->db->free($resql); - return 1; - } - else - { - $this->error=$this->db->error(); - dol_syslog("Error sql=".$sql.", error=".$this->error,LOG_ERR); - return -1; - } - } + return 1; + } + else + { + $this->error=$this->db->error(); + dol_syslog("Error sql=".$sql.", error=".$this->error,LOG_ERR); + return -1; + } + } } @@ -3147,322 +3186,324 @@ class Facture extends CommonInvoice */ class FactureLigne { - var $db; - var $error; + var $db; + var $error; - var $oldline; + var $oldline; - //! From llx_facturedet - var $rowid; - //! Id facture - var $fk_facture; - //! Id parent line - var $fk_parent_line; - var $label; - //! Description ligne - var $desc; - var $fk_product; // Id of predefined product - var $product_type = 0; // Type 0 = product, 1 = Service + //! From llx_facturedet + var $rowid; + //! Id facture + var $fk_facture; + //! Id parent line + var $fk_parent_line; + var $label; + //! Description ligne + var $desc; + var $fk_product; // Id of predefined product + var $product_type = 0; // Type 0 = product, 1 = Service - var $qty; // Quantity (example 2) - var $tva_tx; // Taux tva produit/service (example 19.6) - var $localtax1_tx; // Local tax 1 - var $localtax2_tx; // Local tax 2 - var $subprice; // P.U. HT (example 100) - var $remise_percent; // % de la remise ligne (example 20%) - var $fk_remise_except; // Link to line into llx_remise_except - var $rang = 0; + var $qty; // Quantity (example 2) + var $tva_tx; // Taux tva produit/service (example 19.6) + var $localtax1_tx; // Local tax 1 + var $localtax2_tx; // Local tax 2 + var $subprice; // P.U. HT (example 100) + var $remise_percent; // % de la remise ligne (example 20%) + var $fk_remise_except; // Link to line into llx_remise_except + var $rang = 0; - var $fk_fournprice; - var $pa_ht; - var $marge_tx; - var $marque_tx; + var $fk_fournprice; + var $pa_ht; + var $marge_tx; + var $marque_tx; - var $info_bits = 0; // Liste d'options cumulables: - // Bit 0: 0 si TVA normal - 1 si TVA NPR - // Bit 1: 0 si ligne normal - 1 si bit discount (link to line into llx_remise_except) + var $info_bits = 0; // Liste d'options cumulables: + // Bit 0: 0 si TVA normal - 1 si TVA NPR + // Bit 1: 0 si ligne normal - 1 si bit discount (link to line into llx_remise_except) - var $special_code; // Liste d'options non cumulabels: - // 1: frais de port - // 2: ecotaxe - // 3: ?? + var $special_code; // Liste d'options non cumulabels: + // 1: frais de port + // 2: ecotaxe + // 3: ?? - var $origin; - var $origin_id; + var $origin; + var $origin_id; - //! Total HT de la ligne toute quantite et incluant la remise ligne - var $total_ht; - //! Total TVA de la ligne toute quantite et incluant la remise ligne - var $total_tva; - var $total_localtax1; //Total Local tax 1 de la ligne - var $total_localtax2; //Total Local tax 2 de la ligne - //! Total TTC de la ligne toute quantite et incluant la remise ligne - var $total_ttc; + //! Total HT de la ligne toute quantite et incluant la remise ligne + var $total_ht; + //! Total TVA de la ligne toute quantite et incluant la remise ligne + var $total_tva; + var $total_localtax1; //Total Local tax 1 de la ligne + var $total_localtax2; //Total Local tax 2 de la ligne + //! Total TTC de la ligne toute quantite et incluant la remise ligne + var $total_ttc; - var $fk_code_ventilation = 0; + var $fk_code_ventilation = 0; - var $date_start; - var $date_end; + var $date_start; + var $date_end; - // Ne plus utiliser - //var $price; // P.U. HT apres remise % de ligne (exemple 80) - //var $remise; // Montant calcule de la remise % sur PU HT (exemple 20) + // Ne plus utiliser + //var $price; // P.U. HT apres remise % de ligne (exemple 80) + //var $remise; // Montant calcule de la remise % sur PU HT (exemple 20) - // From llx_product - var $ref; // Product ref (deprecated) - var $product_ref; // Product ref - var $libelle; // Product label (deprecated) - var $product_label; // Product label - var $product_desc; // Description produit + // From llx_product + var $ref; // Product ref (deprecated) + var $product_ref; // Product ref + var $libelle; // Product label (deprecated) + var $product_label; // Product label + var $product_desc; // Description produit - var $skip_update_total; // Skip update price total for special lines + var $skip_update_total; // Skip update price total for special lines - /** - * Constructor - * - * @param DoliDB $db Database handler - */ - function __construct($db) - { - $this->db = $db; - } + /** + * Constructor + * + * @param DoliDB $db Database handler + */ + function __construct($db) + { + $this->db = $db; + } - /** - * Load invoice line from database - * - * @param int $rowid id of invoice line to get - * @return int <0 if KO, >0 if OK - */ - function fetch($rowid) - { - $sql = 'SELECT fd.rowid, fd.fk_facture, fd.fk_parent_line, fd.fk_product, fd.product_type, fd.label as custom_label, fd.description, fd.price, fd.qty, fd.tva_tx,'; - $sql.= ' fd.localtax1_tx, fd. localtax2_tx, fd.remise, fd.remise_percent, fd.fk_remise_except, fd.subprice,'; - $sql.= ' fd.date_start as date_start, fd.date_end as date_end, fd.fk_product_fournisseur_price as fk_fournprice, fd.buy_price_ht as pa_ht,'; - $sql.= ' fd.info_bits, fd.total_ht, fd.total_tva, fd.total_ttc, fd.total_localtax1, fd.total_localtax2, fd.rang,'; - $sql.= ' fd.fk_code_ventilation,'; - $sql.= ' p.ref as product_ref, p.label as product_libelle, p.description as product_desc'; - $sql.= ' FROM '.MAIN_DB_PREFIX.'facturedet as fd'; - $sql.= ' LEFT JOIN '.MAIN_DB_PREFIX.'product as p ON fd.fk_product = p.rowid'; - $sql.= ' WHERE fd.rowid = '.$rowid; + /** + * Load invoice line from database + * + * @param int $rowid id of invoice line to get + * @return int <0 if KO, >0 if OK + */ + function fetch($rowid) + { + $sql = 'SELECT fd.rowid, fd.fk_facture, fd.fk_parent_line, fd.fk_product, fd.product_type, fd.label as custom_label, fd.description, fd.price, fd.qty, fd.tva_tx,'; + $sql.= ' fd.localtax1_tx, fd. localtax2_tx, fd.remise, fd.remise_percent, fd.fk_remise_except, fd.subprice,'; + $sql.= ' fd.date_start as date_start, fd.date_end as date_end, fd.fk_product_fournisseur_price as fk_fournprice, fd.buy_price_ht as pa_ht,'; + $sql.= ' fd.info_bits, fd.total_ht, fd.total_tva, fd.total_ttc, fd.total_localtax1, fd.total_localtax2, fd.rang,'; + $sql.= ' fd.fk_code_ventilation,'; + $sql.= ' p.ref as product_ref, p.label as product_libelle, p.description as product_desc'; + $sql.= ' FROM '.MAIN_DB_PREFIX.'facturedet as fd'; + $sql.= ' LEFT JOIN '.MAIN_DB_PREFIX.'product as p ON fd.fk_product = p.rowid'; + $sql.= ' WHERE fd.rowid = '.$rowid; - $result = $this->db->query($sql); - if ($result) - { - $objp = $this->db->fetch_object($result); + $result = $this->db->query($sql); + if ($result) + { + $objp = $this->db->fetch_object($result); - $this->rowid = $objp->rowid; - $this->fk_facture = $objp->fk_facture; - $this->fk_parent_line = $objp->fk_parent_line; - $this->label = $objp->custom_label; - $this->desc = $objp->description; - $this->qty = $objp->qty; - $this->subprice = $objp->subprice; - $this->tva_tx = $objp->tva_tx; - $this->localtax1_tx = $objp->localtax1_tx; - $this->localtax2_tx = $objp->localtax2_tx; - $this->remise_percent = $objp->remise_percent; - $this->fk_remise_except = $objp->fk_remise_except; - $this->fk_product = $objp->fk_product; - $this->product_type = $objp->product_type; - $this->date_start = $this->db->jdate($objp->date_start); - $this->date_end = $this->db->jdate($objp->date_end); - $this->info_bits = $objp->info_bits; - $this->total_ht = $objp->total_ht; - $this->total_tva = $objp->total_tva; - $this->total_localtax1 = $objp->total_localtax1; - $this->total_localtax2 = $objp->total_localtax2; - $this->total_ttc = $objp->total_ttc; - $this->fk_code_ventilation = $objp->fk_code_ventilation; - $this->rang = $objp->rang; + $this->rowid = $objp->rowid; + $this->fk_facture = $objp->fk_facture; + $this->fk_parent_line = $objp->fk_parent_line; + $this->label = $objp->custom_label; + $this->desc = $objp->description; + $this->qty = $objp->qty; + $this->subprice = $objp->subprice; + $this->tva_tx = $objp->tva_tx; + $this->localtax1_tx = $objp->localtax1_tx; + $this->localtax2_tx = $objp->localtax2_tx; + $this->remise_percent = $objp->remise_percent; + $this->fk_remise_except = $objp->fk_remise_except; + $this->fk_product = $objp->fk_product; + $this->product_type = $objp->product_type; + $this->date_start = $this->db->jdate($objp->date_start); + $this->date_end = $this->db->jdate($objp->date_end); + $this->info_bits = $objp->info_bits; + $this->total_ht = $objp->total_ht; + $this->total_tva = $objp->total_tva; + $this->total_localtax1 = $objp->total_localtax1; + $this->total_localtax2 = $objp->total_localtax2; + $this->total_ttc = $objp->total_ttc; + $this->fk_code_ventilation = $objp->fk_code_ventilation; + $this->rang = $objp->rang; $this->fk_fournprice = $objp->fk_fournprice; $marginInfos = getMarginInfos($objp->subprice, $objp->remise_percent, $objp->tva_tx, $objp->localtax1_tx, $objp->localtax2_tx, $this->fk_fournprice, $objp->pa_ht); $this->pa_ht = $marginInfos[0]; $this->marge_tx = $marginInfos[1]; $this->marque_tx = $marginInfos[2]; - $this->ref = $objp->product_ref; // deprecated - $this->product_ref = $objp->product_ref; - $this->libelle = $objp->product_libelle; // deprecated - $this->product_label = $objp->product_libelle; - $this->product_desc = $objp->product_desc; + $this->ref = $objp->product_ref; // deprecated + $this->product_ref = $objp->product_ref; + $this->libelle = $objp->product_libelle; // deprecated + $this->product_label = $objp->product_libelle; + $this->product_desc = $objp->product_desc; - $this->db->free($result); - } - else - { - dol_print_error($this->db); - } - } + $this->db->free($result); + } + else + { + dol_print_error($this->db); + } + } - /** - * Insert line in database - * - * @param int $notrigger 1 no triggers - * @return int <0 if KO, >0 if OK - */ - function insert($notrigger=0) - { - global $langs,$user,$conf; + /** + * Insert line in database + * + * @param int $notrigger 1 no triggers + * @return int <0 if KO, >0 if OK + */ + function insert($notrigger=0) + { + global $langs,$user,$conf; $error=0; - dol_syslog(get_class($this)."::insert rang=".$this->rang, LOG_DEBUG); + dol_syslog(get_class($this)."::insert rang=".$this->rang, LOG_DEBUG); - // Clean parameters - $this->desc=trim($this->desc); - if (empty($this->tva_tx)) $this->tva_tx=0; - if (empty($this->localtax1_tx)) $this->localtax1_tx=0; - if (empty($this->localtax2_tx)) $this->localtax2_tx=0; - if (empty($this->total_localtax1)) $this->total_localtax1=0; - if (empty($this->total_localtax2)) $this->total_localtax2=0; - if (empty($this->rang)) $this->rang=0; - if (empty($this->remise_percent)) $this->remise_percent=0; - if (empty($this->info_bits)) $this->info_bits=0; - if (empty($this->subprice)) $this->subprice=0; - if (empty($this->special_code)) $this->special_code=0; - if (empty($this->fk_parent_line)) $this->fk_parent_line=0; + // Clean parameters + $this->desc=trim($this->desc); + if (empty($this->tva_tx)) $this->tva_tx=0; + if (empty($this->localtax1_tx)) $this->localtax1_tx=0; + if (empty($this->localtax2_tx)) $this->localtax2_tx=0; + if (empty($this->total_localtax1)) $this->total_localtax1=0; + if (empty($this->total_localtax2)) $this->total_localtax2=0; + if (empty($this->rang)) $this->rang=0; + if (empty($this->remise_percent)) $this->remise_percent=0; + if (empty($this->info_bits)) $this->info_bits=0; + if (empty($this->subprice)) $this->subprice=0; + if (empty($this->special_code)) $this->special_code=0; + if (empty($this->fk_parent_line)) $this->fk_parent_line=0; - if (empty($this->pa_ht)) $this->pa_ht=0; + if (empty($this->pa_ht)) $this->pa_ht=0; - // si prix d'achat non renseigne et utilise pour calcul des marges alors prix achat = prix vente - if ($this->pa_ht == 0) { - if ($this->subprice > 0 && (isset($conf->global->ForceBuyingPriceIfNull) && $conf->global->ForceBuyingPriceIfNull == 1)) - $this->pa_ht = $this->subprice * (1 - $this->remise_percent / 100); - } + // si prix d'achat non renseigne et utilise pour calcul des marges alors prix achat = prix vente + if ($this->pa_ht == 0) { + if ($this->subprice > 0 && (isset($conf->global->ForceBuyingPriceIfNull) && $conf->global->ForceBuyingPriceIfNull == 1)) + $this->pa_ht = $this->subprice * (1 - $this->remise_percent / 100); + } - // Check parameters - if ($this->product_type < 0) return -1; + // Check parameters + if ($this->product_type < 0) return -1; - $this->db->begin(); + $this->db->begin(); - // Insertion dans base de la ligne - $sql = 'INSERT INTO '.MAIN_DB_PREFIX.'facturedet'; - $sql.= ' (fk_facture, fk_parent_line, label, description, qty, tva_tx, localtax1_tx, localtax2_tx,'; - $sql.= ' fk_product, product_type, remise_percent, subprice, fk_remise_except,'; - $sql.= ' date_start, date_end, fk_code_ventilation, '; - $sql.= ' rang, special_code, fk_product_fournisseur_price, buy_price_ht,'; - $sql.= ' info_bits, total_ht, total_tva, total_ttc, total_localtax1, total_localtax2)'; - $sql.= " VALUES (".$this->fk_facture.","; - $sql.= " ".($this->fk_parent_line>0?"'".$this->fk_parent_line."'":"null").","; - $sql.= " ".(! empty($this->label)?"'".$this->db->escape($this->label)."'":"null").","; - $sql.= " '".$this->db->escape($this->desc)."',"; - $sql.= " ".price2num($this->qty).","; - $sql.= " ".price2num($this->tva_tx).","; - $sql.= " ".price2num($this->localtax1_tx).","; - $sql.= " ".price2num($this->localtax2_tx).","; - $sql.= ' '.(! empty($this->fk_product)?$this->fk_product:"null").','; - $sql.= " ".$this->product_type.","; - $sql.= " ".price2num($this->remise_percent).","; - $sql.= " ".price2num($this->subprice).","; - $sql.= ' '.(! empty($this->fk_remise_except)?$this->fk_remise_except:"null").','; - $sql.= " ".(! empty($this->date_start)?"'".$this->db->idate($this->date_start)."'":"null").","; - $sql.= " ".(! empty($this->date_end)?"'".$this->db->idate($this->date_end)."'":"null").","; - $sql.= ' '.$this->fk_code_ventilation.','; - $sql.= ' '.$this->rang.','; - $sql.= ' '.$this->special_code.','; - $sql.= ' '.(! empty($this->fk_fournprice)?$this->fk_fournprice:"null").','; - $sql.= ' '.price2num($this->pa_ht).','; - $sql.= " '".$this->info_bits."',"; - $sql.= " ".price2num($this->total_ht).","; + // Insertion dans base de la ligne + $sql = 'INSERT INTO '.MAIN_DB_PREFIX.'facturedet'; + $sql.= ' (fk_facture, fk_parent_line, label, description, qty, tva_tx, localtax1_tx, localtax2_tx,'; + $sql.= ' fk_product, product_type, remise_percent, subprice, fk_remise_except,'; + $sql.= ' date_start, date_end, fk_code_ventilation, '; + $sql.= ' rang, special_code, fk_product_fournisseur_price, buy_price_ht,'; + $sql.= ' info_bits, total_ht, total_tva, total_ttc, total_localtax1, total_localtax2)'; + $sql.= " VALUES (".$this->fk_facture.","; + $sql.= " ".($this->fk_parent_line>0?"'".$this->fk_parent_line."'":"null").","; + $sql.= " ".(! empty($this->label)?"'".$this->db->escape($this->label)."'":"null").","; + $sql.= " '".$this->db->escape($this->desc)."',"; + $sql.= " ".price2num($this->qty).","; + $sql.= " ".price2num($this->tva_tx).","; + $sql.= " ".price2num($this->localtax1_tx).","; + $sql.= " ".price2num($this->localtax2_tx).","; + $sql.= ' '.(! empty($this->fk_product)?$this->fk_product:"null").','; + $sql.= " ".$this->product_type.","; + $sql.= " ".price2num($this->remise_percent).","; + $sql.= " ".price2num($this->subprice).","; + $sql.= ' '.(! empty($this->fk_remise_except)?$this->fk_remise_except:"null").','; + $sql.= " ".(! empty($this->date_start)?"'".$this->db->idate($this->date_start)."'":"null").","; + $sql.= " ".(! empty($this->date_end)?"'".$this->db->idate($this->date_end)."'":"null").","; + $sql.= ' '.$this->fk_code_ventilation.','; + $sql.= ' '.$this->rang.','; + $sql.= ' '.$this->special_code.','; + $sql.= ' '.(! empty($this->fk_fournprice)?$this->fk_fournprice:"null").','; + $sql.= ' '.price2num($this->pa_ht).','; + $sql.= " '".$this->info_bits."',"; + $sql.= " ".price2num($this->total_ht).","; $sql.= " ".price2num($this->total_tva).","; $sql.= " ".price2num($this->total_ttc).","; - $sql.= " ".price2num($this->total_localtax1).","; - $sql.= " ".price2num($this->total_localtax2); - $sql.= ')'; + $sql.= " ".price2num($this->total_localtax1).","; + $sql.= " ".price2num($this->total_localtax2); + $sql.= ')'; - dol_syslog(get_class($this)."::insert sql=".$sql); - $resql=$this->db->query($sql); - if ($resql) - { - $this->rowid=$this->db->last_insert_id(MAIN_DB_PREFIX.'facturedet'); + dol_syslog(get_class($this)."::insert sql=".$sql); + $resql=$this->db->query($sql); + if ($resql) + { + $this->rowid=$this->db->last_insert_id(MAIN_DB_PREFIX.'facturedet'); - // Si fk_remise_except defini, on lie la remise a la facture - // ce qui la flague comme "consommee". - if ($this->fk_remise_except) - { - $discount=new DiscountAbsolute($this->db); - $result=$discount->fetch($this->fk_remise_except); - if ($result >= 0) - { - // Check if discount was found - if ($result > 0) - { - // Check if discount not already affected to another invoice - if ($discount->fk_facture) - { - $this->error=$langs->trans("ErrorDiscountAlreadyUsed",$discount->id); - dol_syslog(get_class($this)."::insert Error ".$this->error, LOG_ERR); - $this->db->rollback(); - return -3; - } - else - { - $result=$discount->link_to_invoice($this->rowid,0); - if ($result < 0) - { - $this->error=$discount->error; - dol_syslog(get_class($this)."::insert Error ".$this->error, LOG_ERR); - $this->db->rollback(); - return -3; - } - } - } - else - { - $this->error=$langs->trans("ErrorADiscountThatHasBeenRemovedIsIncluded"); - dol_syslog(get_class($this)."::insert Error ".$this->error, LOG_ERR); - $this->db->rollback(); - return -3; - } - } - else - { - $this->error=$discount->error; - dol_syslog(get_class($this)."::insert Error ".$this->error, LOG_ERR); - $this->db->rollback(); - return -3; - } - } + // Si fk_remise_except defini, on lie la remise a la facture + // ce qui la flague comme "consommee". + if ($this->fk_remise_except) + { + $discount=new DiscountAbsolute($this->db); + $result=$discount->fetch($this->fk_remise_except); + if ($result >= 0) + { + // Check if discount was found + if ($result > 0) + { + // Check if discount not already affected to another invoice + if ($discount->fk_facture) + { + $this->error=$langs->trans("ErrorDiscountAlreadyUsed",$discount->id); + dol_syslog(get_class($this)."::insert Error ".$this->error, LOG_ERR); + $this->db->rollback(); + return -3; + } + else + { + $result=$discount->link_to_invoice($this->rowid,0); + if ($result < 0) + { + $this->error=$discount->error; + dol_syslog(get_class($this)."::insert Error ".$this->error, LOG_ERR); + $this->db->rollback(); + return -3; + } + } + } + else + { + $this->error=$langs->trans("ErrorADiscountThatHasBeenRemovedIsIncluded"); + dol_syslog(get_class($this)."::insert Error ".$this->error, LOG_ERR); + $this->db->rollback(); + return -3; + } + } + else + { + $this->error=$discount->error; + dol_syslog(get_class($this)."::insert Error ".$this->error, LOG_ERR); + $this->db->rollback(); + return -3; + } + } - if (! $notrigger) - { - // Appel des triggers - include_once DOL_DOCUMENT_ROOT . '/core/class/interfaces.class.php'; - $interface=new Interfaces($this->db); - $result = $interface->run_triggers('LINEBILL_INSERT',$this,$user,$langs,$conf); - if ($result < 0) { $error++; $this->errors=$interface->errors; } - // Fin appel triggers - } + if (! $notrigger) + { + // Appel des triggers + include_once DOL_DOCUMENT_ROOT . '/core/class/interfaces.class.php'; + $interface=new Interfaces($this->db); + $result = $interface->run_triggers('LINEBILL_INSERT',$this,$user,$langs,$conf); + if ($result < 0) { + $error++; $this->errors=$interface->errors; + } + // Fin appel triggers + } - $this->db->commit(); - return $this->rowid; + $this->db->commit(); + return $this->rowid; - } - else - { - $this->error=$this->db->error(); - dol_syslog(get_class($this)."::insert Error ".$this->error, LOG_ERR); - $this->db->rollback(); - return -2; - } - } + } + else + { + $this->error=$this->db->error(); + dol_syslog(get_class($this)."::insert Error ".$this->error, LOG_ERR); + $this->db->rollback(); + return -2; + } + } - /** - * Update line into database - * - * @param User $user User object - * @param int $notrigger Disable triggers - * @return int <0 if KO, >0 if OK - */ - function update($user='',$notrigger=0) - { - global $user,$langs,$conf; + /** + * Update line into database + * + * @param User $user User object + * @param int $notrigger Disable triggers + * @return int <0 if KO, >0 if OK + */ + function update($user='',$notrigger=0) + { + global $user,$langs,$conf; $error=0; - // Clean parameters - $this->desc=trim($this->desc); + // Clean parameters + $this->desc=trim($this->desc); if (empty($this->tva_tx)) $this->tva_tx=0; if (empty($this->localtax1_tx)) $this->localtax1_tx=0; if (empty($this->localtax2_tx)) $this->localtax2_tx=0; @@ -3474,74 +3515,76 @@ class FactureLigne if (empty($this->product_type)) $this->product_type=0; if (empty($this->fk_parent_line)) $this->fk_parent_line=0; - // Check parameters - if ($this->product_type < 0) return -1; + // Check parameters + if ($this->product_type < 0) return -1; - if (empty($this->pa_ht)) $this->pa_ht=0; + if (empty($this->pa_ht)) $this->pa_ht=0; - // si prix d'achat non renseigne et utilise pour calcul des marges alors prix achat = prix vente - if ($this->pa_ht == 0) { - if ($this->subprice > 0 && (isset($conf->global->ForceBuyingPriceIfNull) && $conf->global->ForceBuyingPriceIfNull == 1)) - $this->pa_ht = $this->subprice * (1 - $this->remise_percent / 100); - } + // si prix d'achat non renseigne et utilise pour calcul des marges alors prix achat = prix vente + if ($this->pa_ht == 0) { + if ($this->subprice > 0 && (isset($conf->global->ForceBuyingPriceIfNull) && $conf->global->ForceBuyingPriceIfNull == 1)) + $this->pa_ht = $this->subprice * (1 - $this->remise_percent / 100); + } - $this->db->begin(); + $this->db->begin(); - // Mise a jour ligne en base - $sql = "UPDATE ".MAIN_DB_PREFIX."facturedet SET"; - $sql.= " description='".$this->db->escape($this->desc)."'"; - $sql.= ",label=".(! empty($this->label)?"'".$this->db->escape($this->label)."'":"null"); - $sql.= ",subprice=".price2num($this->subprice).""; - $sql.= ",remise_percent=".price2num($this->remise_percent).""; - if ($this->fk_remise_except) $sql.= ",fk_remise_except=".$this->fk_remise_except; - else $sql.= ",fk_remise_except=null"; - $sql.= ",tva_tx=".price2num($this->tva_tx).""; - $sql.= ",localtax1_tx=".price2num($this->localtax1_tx).""; - $sql.= ",localtax2_tx=".price2num($this->localtax2_tx).""; - $sql.= ",qty=".price2num($this->qty).""; - $sql.= ",date_start=".(! empty($this->date_start)?"'".$this->db->idate($this->date_start)."'":"null"); - $sql.= ",date_end=".(! empty($this->date_end)?"'".$this->db->idate($this->date_end)."'":"null"); - $sql.= ",product_type=".$this->product_type; - $sql.= ",info_bits='".$this->info_bits."'"; - $sql.= ",special_code='".$this->special_code."'"; - if (empty($this->skip_update_total)) - { - $sql.= ",total_ht=".price2num($this->total_ht).""; - $sql.= ",total_tva=".price2num($this->total_tva).""; - $sql.= ",total_ttc=".price2num($this->total_ttc).""; - $sql.= ",total_localtax1=".price2num($this->total_localtax1).""; - $sql.= ",total_localtax2=".price2num($this->total_localtax2).""; - } + // Mise a jour ligne en base + $sql = "UPDATE ".MAIN_DB_PREFIX."facturedet SET"; + $sql.= " description='".$this->db->escape($this->desc)."'"; + $sql.= ",label=".(! empty($this->label)?"'".$this->db->escape($this->label)."'":"null"); + $sql.= ",subprice=".price2num($this->subprice).""; + $sql.= ",remise_percent=".price2num($this->remise_percent).""; + if ($this->fk_remise_except) $sql.= ",fk_remise_except=".$this->fk_remise_except; + else $sql.= ",fk_remise_except=null"; + $sql.= ",tva_tx=".price2num($this->tva_tx).""; + $sql.= ",localtax1_tx=".price2num($this->localtax1_tx).""; + $sql.= ",localtax2_tx=".price2num($this->localtax2_tx).""; + $sql.= ",qty=".price2num($this->qty).""; + $sql.= ",date_start=".(! empty($this->date_start)?"'".$this->db->idate($this->date_start)."'":"null"); + $sql.= ",date_end=".(! empty($this->date_end)?"'".$this->db->idate($this->date_end)."'":"null"); + $sql.= ",product_type=".$this->product_type; + $sql.= ",info_bits='".$this->info_bits."'"; + $sql.= ",special_code='".$this->special_code."'"; + if (empty($this->skip_update_total)) + { + $sql.= ",total_ht=".price2num($this->total_ht).""; + $sql.= ",total_tva=".price2num($this->total_tva).""; + $sql.= ",total_ttc=".price2num($this->total_ttc).""; + $sql.= ",total_localtax1=".price2num($this->total_localtax1).""; + $sql.= ",total_localtax2=".price2num($this->total_localtax2).""; + } $sql.= " , fk_product_fournisseur_price='".$this->fk_fournprice."'"; $sql.= " , buy_price_ht='".price2num($this->pa_ht)."'"; - $sql.= ",fk_parent_line=".($this->fk_parent_line>0?$this->fk_parent_line:"null"); - if (! empty($this->rang)) $sql.= ", rang=".$this->rang; - $sql.= " WHERE rowid = ".$this->rowid; + $sql.= ",fk_parent_line=".($this->fk_parent_line>0?$this->fk_parent_line:"null"); + if (! empty($this->rang)) $sql.= ", rang=".$this->rang; + $sql.= " WHERE rowid = ".$this->rowid; - dol_syslog(get_class($this)."::update sql=".$sql, LOG_DEBUG); - $resql=$this->db->query($sql); - if ($resql) - { - if (! $notrigger) - { - // Appel des triggers - include_once DOL_DOCUMENT_ROOT . '/core/class/interfaces.class.php'; - $interface=new Interfaces($this->db); - $result = $interface->run_triggers('LINEBILL_UPDATE',$this,$user,$langs,$conf); - if ($result < 0) { $error++; $this->errors=$interface->errors; } - // Fin appel triggers - } - $this->db->commit(); - return 1; - } - else - { - $this->error=$this->db->error(); - dol_syslog(get_class($this)."::update Error ".$this->error, LOG_ERR); - $this->db->rollback(); - return -2; - } - } + dol_syslog(get_class($this)."::update sql=".$sql, LOG_DEBUG); + $resql=$this->db->query($sql); + if ($resql) + { + if (! $notrigger) + { + // Appel des triggers + include_once DOL_DOCUMENT_ROOT . '/core/class/interfaces.class.php'; + $interface=new Interfaces($this->db); + $result = $interface->run_triggers('LINEBILL_UPDATE',$this,$user,$langs,$conf); + if ($result < 0) { + $error++; $this->errors=$interface->errors; + } + // Fin appel triggers + } + $this->db->commit(); + return 1; + } + else + { + $this->error=$this->db->error(); + dol_syslog(get_class($this)."::update Error ".$this->error, LOG_ERR); + $this->db->rollback(); + return -2; + } + } /** * Delete line in database @@ -3564,7 +3607,9 @@ class FactureLigne include_once DOL_DOCUMENT_ROOT . '/core/class/interfaces.class.php'; $interface=new Interfaces($this->db); $result = $interface->run_triggers('LINEBILL_DELETE',$this,$user,$langs,$conf); - if ($result < 0) { $error++; $this->errors=$interface->errors; } + if ($result < 0) { + $error++; $this->errors=$interface->errors; + } // Fin appel triggers $this->db->commit(); @@ -3580,45 +3625,45 @@ class FactureLigne } } - /** - * Mise a jour en base des champs total_xxx de ligne de facture - * - * @return int <0 if KO, >0 if OK - */ - function update_total() - { - $this->db->begin(); - dol_syslog(get_class($this)."::update_total", LOG_DEBUG); + /** + * Mise a jour en base des champs total_xxx de ligne de facture + * + * @return int <0 if KO, >0 if OK + */ + function update_total() + { + $this->db->begin(); + dol_syslog(get_class($this)."::update_total", LOG_DEBUG); - // Clean parameters + // Clean parameters if (empty($this->total_localtax1)) $this->total_localtax1=0; if (empty($this->total_localtax2)) $this->total_localtax2=0; - // Mise a jour ligne en base - $sql = "UPDATE ".MAIN_DB_PREFIX."facturedet SET"; - $sql.= " total_ht=".price2num($this->total_ht).""; - $sql.= ",total_tva=".price2num($this->total_tva).""; - $sql.= ",total_localtax1=".price2num($this->total_localtax1).""; - $sql.= ",total_localtax2=".price2num($this->total_localtax2).""; - $sql.= ",total_ttc=".price2num($this->total_ttc).""; - $sql.= " WHERE rowid = ".$this->rowid; + // Mise a jour ligne en base + $sql = "UPDATE ".MAIN_DB_PREFIX."facturedet SET"; + $sql.= " total_ht=".price2num($this->total_ht).""; + $sql.= ",total_tva=".price2num($this->total_tva).""; + $sql.= ",total_localtax1=".price2num($this->total_localtax1).""; + $sql.= ",total_localtax2=".price2num($this->total_localtax2).""; + $sql.= ",total_ttc=".price2num($this->total_ttc).""; + $sql.= " WHERE rowid = ".$this->rowid; - dol_syslog(get_class($this)."::update_total sql=".$sql, LOG_DEBUG); + dol_syslog(get_class($this)."::update_total sql=".$sql, LOG_DEBUG); - $resql=$this->db->query($sql); - if ($resql) - { - $this->db->commit(); - return 1; - } - else - { - $this->error=$this->db->error(); - dol_syslog(get_class($this)."::update_total Error ".$this->error, LOG_ERR); - $this->db->rollback(); - return -2; - } - } + $resql=$this->db->query($sql); + if ($resql) + { + $this->db->commit(); + return 1; + } + else + { + $this->error=$this->db->error(); + dol_syslog(get_class($this)."::update_total Error ".$this->error, LOG_ERR); + $this->db->rollback(); + return -2; + } + } } ?> diff --git a/htdocs/langs/en_US/agenda.lang b/htdocs/langs/en_US/agenda.lang index 2355c112194..7bd84be4cd1 100644 --- a/htdocs/langs/en_US/agenda.lang +++ b/htdocs/langs/en_US/agenda.lang @@ -40,6 +40,7 @@ ActionsEvents= Events for which Dolibarr will create an action in agenda automat PropalValidatedInDolibarr= Proposal %s validated InvoiceValidatedInDolibarr= Invoice %s validated InvoiceBackToDraftInDolibarr=Invoice %s go back to draft status +InvoiceDeleteDolibarr=Invoice %s deleted OrderValidatedInDolibarr= Order %s validated OrderApprovedInDolibarr=Order %s approved OrderBackToDraftInDolibarr=Order %s go back to draft status diff --git a/htdocs/langs/en_US/stocks.lang b/htdocs/langs/en_US/stocks.lang index 35aa3ca537a..918665fcc4b 100644 --- a/htdocs/langs/en_US/stocks.lang +++ b/htdocs/langs/en_US/stocks.lang @@ -55,6 +55,7 @@ DeStockOnShipment=Decrease real stocks on shipment validation ReStockOnBill=Increase real stocks on suppliers invoices/credit notes validation ReStockOnValidateOrder=Increase real stocks on suppliers orders approbation ReStockOnDispatchOrder=Increase real stocks on manual dispatching into warehouses, after supplier order receiving +ReStockOnDispatchOrder=Increase real stocks on invocie deletion OrderStatusNotReadyToDispatch=Order has not yet or no more a status that allows dispatching of products in stock warehouses. StockDiffPhysicTeoric=Reason for difference stock physical and theoretical NoPredefinedProductToDispatch=No predefined products for this object. So no dispatching in stock is required. diff --git a/htdocs/langs/es_ES/agenda.lang b/htdocs/langs/es_ES/agenda.lang index e0131db59fe..f254bf1b453 100644 --- a/htdocs/langs/es_ES/agenda.lang +++ b/htdocs/langs/es_ES/agenda.lang @@ -41,6 +41,7 @@ ActionsEvents=Eventos para que Dolibarr cree una acción de forma automática PropalValidatedInDolibarr=Presupuesto %s validado InvoiceValidatedInDolibarr=Factura %s validada InvoiceBackToDraftInDolibarr=Factura %s devuelta a borrador +InvoiceDeleteDolibarr=Factura %s elimina OrderValidatedInDolibarr=Pedido %s validado OrderApprovedInDolibarr=Pedido %s aprobado OrderBackToDraftInDolibarr=Pedido %s devuelto a borrador diff --git a/htdocs/langs/es_ES/stocks.lang b/htdocs/langs/es_ES/stocks.lang index fe51937ac65..8bbc06c59c1 100644 --- a/htdocs/langs/es_ES/stocks.lang +++ b/htdocs/langs/es_ES/stocks.lang @@ -54,6 +54,7 @@ DeStockOnShipment=Decrementar los stocks físicos sobre los envíos ReStockOnBill=Incrementar los stocks físicos sobre las facturas/abonos de proveedores ReStockOnValidateOrder=Incrementar los stocks físicos sobre los pedidos a proveedores ReStockOnDispatchOrder=Incrementa los stocks físicos en el desglose manual de la recepción de los pedidos a proveedores en los almacenes +ReStockOnDeleteInvoice=Incrementa los stocks físicos a la suppresion de las facturas OrderStatusNotReadyToDispatch=El pedido aún no está o no tiene un estado que permita un desglose de stock. StockDiffPhysicTeoric=Motivo de la diferencia entre valores físicos y teóricos NoPredefinedProductToDispatch=No hay productos predefinidos en este objeto. Por lo tanto no se puede realizar un desglose de stock. diff --git a/htdocs/langs/fr_FR/agenda.lang b/htdocs/langs/fr_FR/agenda.lang index 33555be6951..cf8216b617b 100644 --- a/htdocs/langs/fr_FR/agenda.lang +++ b/htdocs/langs/fr_FR/agenda.lang @@ -40,6 +40,7 @@ ActionsEvents=Événements pour lesquels Dolibarr doit créer une action dans l' PropalValidatedInDolibarr=Proposition %s validée InvoiceValidatedInDolibarr=Facture %s validée InvoiceBackToDraftInDolibarr=Facture %s repassée en brouillon +InvoiceDeleteDolibarr=Facture %s supprimée OrderValidatedInDolibarr=Commande %s validée OrderApprovedInDolibarr=Commande %s approuvée OrderBackToDraftInDolibarr=Commande %s repassée en brouillon diff --git a/htdocs/langs/fr_FR/stocks.lang b/htdocs/langs/fr_FR/stocks.lang index fb016e23ef3..e8219f5faf8 100644 --- a/htdocs/langs/fr_FR/stocks.lang +++ b/htdocs/langs/fr_FR/stocks.lang @@ -55,6 +55,7 @@ DeStockOnShipment=Décrémente les stocks physiques sur validation des expéditi ReStockOnBill=Incrémente les stocks physiques sur validation des factures/avoirs fournisseurs ReStockOnValidateOrder=Incrémente les stocks physiques sur approbation des commandes fournisseurs ReStockOnDispatchOrder=Incrémente les stocks physiques sur ventilation manuelle de la réception des commandes fournisseurs dans les entrepôts +ReStockOnDeleteInvoice=Incrémente les stocks physiques sur la suppression des factures OrderStatusNotReadyToDispatch=La commande n'a pas encore ou n'a plus un statut permettant une ventilation en stock. StockDiffPhysicTeoric=Raison écart stock physique-théorique NoPredefinedProductToDispatch=Pas de produits prédéfinis dans cet objet. Aucune ventilation en stock n'est donc à faire.