diff --git a/ChangeLog b/ChangeLog index c0eb78120b0..bbfeb367955 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..0390efcdda4 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 @@ -67,6 +68,7 @@ if ($action == 'STOCK_CALCULATE_ON_SUPPLIER_BILL' $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); @@ -239,6 +241,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..590901a937a 100644 --- a/htdocs/compta/facture.php +++ b/htdocs/compta/facture.php @@ -1,34 +1,34 @@ * Copyright (C) 2004 Eric Seigne - * Copyright (C) 2004-2013 Laurent Destailleur - * Copyright (C) 2005 Marc Barilley / Ocebo - * Copyright (C) 2005-2012 Regis Houssin - * Copyright (C) 2006 Andre Cianfarani - * Copyright (C) 2010-2013 Juanjo Menent - * Copyright (C) 2012 Christophe Battarel - * Copyright (C) 2013 Jean-Francois FERRY - * 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-2013 Laurent Destailleur +* Copyright (C) 2005 Marc Barilley / Ocebo +* Copyright (C) 2005-2012 Regis Houssin +* Copyright (C) 2006 Andre Cianfarani +* Copyright (C) 2010-2013 Juanjo Menent +* Copyright (C) 2012 Christophe Battarel +* Copyright (C) 2013 Jean-Francois FERRY +* 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.php - * \ingroup facture - * \brief Page to create/see an invoice - */ +* \ingroup facture +* \brief Page to create/see an invoice +*/ require '../main.inc.php'; require_once DOL_DOCUMENT_ROOT . '/compta/facture/class/facture.class.php'; @@ -99,7 +99,7 @@ $hookmanager->initHooks(array('invoicecard')); /* * Actions - */ +*/ $parameters=array('socid'=>$socid); $reshook=$hookmanager->executeHooks('doActions',$parameters,$object,$action); // Note that $action and $object may have been modified by some hooks @@ -108,47 +108,47 @@ $reshook=$hookmanager->executeHooks('doActions',$parameters,$object,$action); // Action clone object if ($action == 'confirm_clone' && $confirm == 'yes' && $user->rights->facture->creer) { - if (1==0 && empty($_REQUEST["clone_content"]) && empty($_REQUEST["clone_receivers"])) - { - $mesgs[]='
'.$langs->trans("NoCloneOptionsSpecified").'
'; - } - else - { - if ($object->fetch($id) > 0) - { - $result=$object->createFromClone($socid); - if ($result > 0) - { - header("Location: ".$_SERVER['PHP_SELF'].'?facid='.$result); - exit; - } - else - { - $mesgs[]=$object->error; - $action=''; - } - } - } + if (1==0 && empty($_REQUEST["clone_content"]) && empty($_REQUEST["clone_receivers"])) + { + $mesgs[]='
'.$langs->trans("NoCloneOptionsSpecified").'
'; + } + else + { + if ($object->fetch($id) > 0) + { + $result=$object->createFromClone($socid); + if ($result > 0) + { + header("Location: ".$_SERVER['PHP_SELF'].'?facid='.$result); + exit; + } + else + { + $mesgs[]=$object->error; + $action=''; + } + } + } } // Change status of invoice else if ($action == 'reopen' && $user->rights->facture->creer) { - $result = $object->fetch($id); - if ($object->statut == 2 - || ($object->statut == 3 && $object->close_code != 'replaced')) - { - $result = $object->set_unpaid($user); - if ($result > 0) - { - header('Location: '.$_SERVER["PHP_SELF"].'?facid='.$id); - exit; - } - else - { - $mesgs[]='
'.$object->error.'
'; - } - } + $result = $object->fetch($id); + if ($object->statut == 2 + || ($object->statut == 3 && $object->close_code != 'replaced')) + { + $result = $object->set_unpaid($user); + if ($result > 0) + { + header('Location: '.$_SERVER["PHP_SELF"].'?facid='.$id); + exit; + } + else + { + $mesgs[]='
'.$object->error.'
'; + } + } } // Delete invoice @@ -156,7 +156,20 @@ else if ($action == 'confirm_delete' && $confirm == 'yes' && $user->rights->fact { $result = $object->fetch($id); $object->fetch_thirdparty(); - $result = $object->delete(); + + $idwarehouse=GETPOST('idwarehouse'); + + $qualified_for_stock_change=0; + if (empty($conf->global->STOCK_SUPPORTS_SERVICES)) + { + $qualified_for_stock_change=$object->hasProductsOrServices(2); + } + else + { + $qualified_for_stock_change=$object->hasProductsOrServices(1); + } + + $result = $object->delete(0,0,$idwarehouse); if ($result > 0) { header('Location: '.DOL_URL_ROOT.'/compta/facture/list.php'); @@ -208,146 +221,146 @@ else if ($action == 'confirm_deleteline' && $confirm == 'yes' && $user->rights-> // Delete link of credit note to invoice else if ($action == 'unlinkdiscount' && $user->rights->facture->creer) { - $discount=new DiscountAbsolute($db); - $result=$discount->fetch($_GET["discountid"]); - $discount->unlink_invoice(); + $discount=new DiscountAbsolute($db); + $result=$discount->fetch($_GET["discountid"]); + $discount->unlink_invoice(); } // Validation else if ($action == 'valid' && $user->rights->facture->creer) { - $object->fetch($id); + $object->fetch($id); - // On verifie signe facture - if ($object->type == 2) - { - // Si avoir, le signe doit etre negatif - if ($object->total_ht >= 0) - { - $mesgs[]='
'.$langs->trans("ErrorInvoiceAvoirMustBeNegative").'
'; - $action=''; - } - } - else - { - // Si non avoir, le signe doit etre positif - if (empty($conf->global->FACTURE_ENABLE_NEGATIVE) && $object->total_ht < 0) - { - $mesgs[]='
'.$langs->trans("ErrorInvoiceOfThisTypeMustBePositive").'
'; - $action=''; - } - } + // On verifie signe facture + if ($object->type == 2) + { + // Si avoir, le signe doit etre negatif + if ($object->total_ht >= 0) + { + $mesgs[]='
'.$langs->trans("ErrorInvoiceAvoirMustBeNegative").'
'; + $action=''; + } + } + else + { + // Si non avoir, le signe doit etre positif + if (empty($conf->global->FACTURE_ENABLE_NEGATIVE) && $object->total_ht < 0) + { + $mesgs[]='
'.$langs->trans("ErrorInvoiceOfThisTypeMustBePositive").'
'; + $action=''; + } + } } else if ($action == 'set_thirdparty' && $user->rights->facture->creer) { - $object->fetch($id); - $object->setValueFrom('fk_soc',$socid); + $object->fetch($id); + $object->setValueFrom('fk_soc',$socid); - header('Location: '.$_SERVER["PHP_SELF"].'?facid='.$id); - exit; + header('Location: '.$_SERVER["PHP_SELF"].'?facid='.$id); + exit; } else if ($action == 'classin' && $user->rights->facture->creer) { - $object->fetch($id); - $object->setProject($_POST['projectid']); + $object->fetch($id); + $object->setProject($_POST['projectid']); } else if ($action == 'setmode' && $user->rights->facture->creer) { - $object->fetch($id); - $result = $object->setPaymentMethods(GETPOST('mode_reglement_id','int')); - if ($result < 0) dol_print_error($db,$object->error); + $object->fetch($id); + $result = $object->setPaymentMethods(GETPOST('mode_reglement_id','int')); + if ($result < 0) dol_print_error($db,$object->error); } else if ($action == 'setinvoicedate' && $user->rights->facture->creer) { - $object->fetch($id); - $old_date_lim_reglement=$object->date_lim_reglement; - $object->date=dol_mktime(12,0,0,$_POST['invoicedatemonth'],$_POST['invoicedateday'],$_POST['invoicedateyear']); - $new_date_lim_reglement=$object->calculate_date_lim_reglement(); - if ($new_date_lim_reglement > $old_date_lim_reglement) $object->date_lim_reglement=$new_date_lim_reglement; - if ($object->date_lim_reglement < $object->date) $object->date_lim_reglement=$object->date; - $result=$object->update($user); - if ($result < 0) dol_print_error($db,$object->error); + $object->fetch($id); + $old_date_lim_reglement=$object->date_lim_reglement; + $object->date=dol_mktime(12,0,0,$_POST['invoicedatemonth'],$_POST['invoicedateday'],$_POST['invoicedateyear']); + $new_date_lim_reglement=$object->calculate_date_lim_reglement(); + if ($new_date_lim_reglement > $old_date_lim_reglement) $object->date_lim_reglement=$new_date_lim_reglement; + if ($object->date_lim_reglement < $object->date) $object->date_lim_reglement=$object->date; + $result=$object->update($user); + if ($result < 0) dol_print_error($db,$object->error); } else if ($action == 'setconditions' && $user->rights->facture->creer) { - $object->fetch($id); - $object->cond_reglement_code=0; // To clean property - $object->cond_reglement_id=0; // To clean property - $result=$object->setPaymentTerms(GETPOST('cond_reglement_id','int')); - if ($result < 0) dol_print_error($db,$object->error); + $object->fetch($id); + $object->cond_reglement_code=0; // To clean property + $object->cond_reglement_id=0; // To clean property + $result=$object->setPaymentTerms(GETPOST('cond_reglement_id','int')); + if ($result < 0) dol_print_error($db,$object->error); - $old_date_lim_reglement=$object->date_lim_reglement; - $new_date_lim_reglement=$object->calculate_date_lim_reglement(); - if ($new_date_lim_reglement > $old_date_lim_reglement) $object->date_lim_reglement=$new_date_lim_reglement; - if ($object->date_lim_reglement < $object->date) $object->date_lim_reglement=$object->date; - $result=$object->update($user); - if ($result < 0) dol_print_error($db,$object->error); + $old_date_lim_reglement=$object->date_lim_reglement; + $new_date_lim_reglement=$object->calculate_date_lim_reglement(); + if ($new_date_lim_reglement > $old_date_lim_reglement) $object->date_lim_reglement=$new_date_lim_reglement; + if ($object->date_lim_reglement < $object->date) $object->date_lim_reglement=$object->date; + $result=$object->update($user); + if ($result < 0) dol_print_error($db,$object->error); } else if ($action == 'setpaymentterm' && $user->rights->facture->creer) { - $object->fetch($id); - $object->date_lim_reglement=dol_mktime(12,0,0,$_POST['paymenttermmonth'],$_POST['paymenttermday'],$_POST['paymenttermyear']); - if ($object->date_lim_reglement < $object->date) - { - $object->date_lim_reglement=$object->calculate_date_lim_reglement(); - setEventMessage($langs->trans("DatePaymentTermCantBeLowerThanObjectDate"),'warnings'); - } - $result=$object->update($user); - if ($result < 0) dol_print_error($db,$object->error); + $object->fetch($id); + $object->date_lim_reglement=dol_mktime(12,0,0,$_POST['paymenttermmonth'],$_POST['paymenttermday'],$_POST['paymenttermyear']); + if ($object->date_lim_reglement < $object->date) + { + $object->date_lim_reglement=$object->calculate_date_lim_reglement(); + setEventMessage($langs->trans("DatePaymentTermCantBeLowerThanObjectDate"),'warnings'); + } + $result=$object->update($user); + if ($result < 0) dol_print_error($db,$object->error); } else if ($action == 'setrevenuestamp' && $user->rights->facture->creer) { - $object->fetch($id); - $object->revenuestamp=GETPOST('revenuestamp'); - $result=$object->update($user); - $object->update_price(1); - if ($result < 0) dol_print_error($db,$object->error); + $object->fetch($id); + $object->revenuestamp=GETPOST('revenuestamp'); + $result=$object->update($user); + $object->update_price(1); + if ($result < 0) dol_print_error($db,$object->error); } else if ($action == 'setremisepercent' && $user->rights->facture->creer) { - $object->fetch($id); - $result = $object->set_remise($user, $_POST['remise_percent']); + $object->fetch($id); + $result = $object->set_remise($user, $_POST['remise_percent']); } else if ($action == "setabsolutediscount" && $user->rights->facture->creer) { - // POST[remise_id] ou POST[remise_id_for_payment] - if (! empty($_POST["remise_id"])) - { - $ret=$object->fetch($id); - if ($ret > 0) - { - $result=$object->insert_discount($_POST["remise_id"]); - if ($result < 0) - { - $mesgs[]='
'.$object->error.'
'; - } - } - else - { - dol_print_error($db,$object->error); - } - } - if (! empty($_POST["remise_id_for_payment"])) - { - require_once DOL_DOCUMENT_ROOT.'/core/class/discount.class.php'; - $discount = new DiscountAbsolute($db); - $discount->fetch($_POST["remise_id_for_payment"]); + // POST[remise_id] ou POST[remise_id_for_payment] + if (! empty($_POST["remise_id"])) + { + $ret=$object->fetch($id); + if ($ret > 0) + { + $result=$object->insert_discount($_POST["remise_id"]); + if ($result < 0) + { + $mesgs[]='
'.$object->error.'
'; + } + } + else + { + dol_print_error($db,$object->error); + } + } + if (! empty($_POST["remise_id_for_payment"])) + { + require_once DOL_DOCUMENT_ROOT.'/core/class/discount.class.php'; + $discount = new DiscountAbsolute($db); + $discount->fetch($_POST["remise_id_for_payment"]); - $result=$discount->link_to_invoice(0,$id); - if ($result < 0) - { - $mesgs[]='
'.$discount->error.'
'; - } - } + $result=$discount->link_to_invoice(0,$id); + if ($result < 0) + { + $mesgs[]='
'.$discount->error.'
'; + } + } } else if ($action == 'set_ref_client' && $user->rights->facture->creer) { - $object->fetch($id); - $object->set_ref_client($_POST['ref_client']); + $object->fetch($id); + $object->set_ref_client($_POST['ref_client']); } else if ($action == 'setnote_public' && $user->rights->facture->creer) @@ -367,864 +380,894 @@ else if ($action == 'setnote_private' && $user->rights->facture->creer) // Classify to validated else if ($action == 'confirm_valid' && $confirm == 'yes' && $user->rights->facture->valider) { - $idwarehouse=GETPOST('idwarehouse'); + $idwarehouse=GETPOST('idwarehouse'); - $object->fetch($id); - $object->fetch_thirdparty(); + $object->fetch($id); + $object->fetch_thirdparty(); - // Check parameters + // Check parameters - // Check for mandatory prof id - for ($i = 1; $i < 5; $i++) - { + // Check for mandatory prof id + for ($i = 1; $i < 5; $i++) + { - $idprof_mandatory ='SOCIETE_IDPROF'.($i).'_INVOICE_MANDATORY'; - $idprof='idprof'.$i; - if (! $object->thirdparty->$idprof && ! empty($conf->global->$idprof_mandatory)) - { - if (! $error) $langs->load("errors"); - $error++; + $idprof_mandatory ='SOCIETE_IDPROF'.($i).'_INVOICE_MANDATORY'; + $idprof='idprof'.$i; + if (! $object->thirdparty->$idprof && ! empty($conf->global->$idprof_mandatory)) + { + if (! $error) $langs->load("errors"); + $error++; - setEventMessage($langs->trans('ErrorProdIdIsMandatory',$langs->transcountry('ProfId'.$i, $object->thirdparty->country_code)),'errors'); - } - } + setEventMessage($langs->trans('ErrorProdIdIsMandatory',$langs->transcountry('ProfId'.$i, $object->thirdparty->country_code)),'errors'); + } + } - //Check for warehouse - if ($object->type != 3 && ! empty($conf->global->STOCK_CALCULATE_ON_BILL) && $object->hasProductsOrServices(1)) - { - if (! $idwarehouse || $idwarehouse == -1) - { - $error++; - setEventMessage($langs->trans('ErrorFieldRequired',$langs->transnoentitiesnoconv("Warehouse")),'errors'); - $action=''; - } - } + $qualified_for_stock_change=0; + if (empty($conf->global->STOCK_SUPPORTS_SERVICES)) + { + $qualified_for_stock_change=$object->hasProductsOrServices(2); + } + else + { + $qualified_for_stock_change=$object->hasProductsOrServices(1); + } - if (! $error) - { - $result = $object->validate($user,'',$idwarehouse); - if ($result >= 0) - { - // Define output language - $outputlangs = $langs; - $newlang=''; - if ($conf->global->MAIN_MULTILANGS && empty($newlang) && ! empty($_REQUEST['lang_id'])) $newlang=$_REQUEST['lang_id']; - if ($conf->global->MAIN_MULTILANGS && empty($newlang)) $newlang=$object->client->default_lang; - if (! empty($newlang)) - { - $outputlangs = new Translate("",$conf); - $outputlangs->setDefaultLang($newlang); - } - if (empty($conf->global->MAIN_DISABLE_PDF_AUTOUPDATE)) - { - $ret=$object->fetch($id); // Reload to get new records - facture_pdf_create($db, $object, $object->modelpdf, $outputlangs, $hidedetails, $hidedesc, $hideref); - } - } - else - { - setEventMessage($object->error,'errors'); - } - } + //Check for warehouse + if ($object->type != 3 && ! empty($conf->global->STOCK_CALCULATE_ON_BILL) && $qualified_for_stock_change) + { + if (! $idwarehouse || $idwarehouse == -1) + { + $error++; + setEventMessage($langs->trans('ErrorFieldRequired',$langs->transnoentitiesnoconv("Warehouse")),'errors'); + $action=''; + } + } + + if (! $error) + { + $result = $object->validate($user,'',$idwarehouse); + if ($result >= 0) + { + // Define output language + $outputlangs = $langs; + $newlang=''; + if ($conf->global->MAIN_MULTILANGS && empty($newlang) && ! empty($_REQUEST['lang_id'])) $newlang=$_REQUEST['lang_id']; + if ($conf->global->MAIN_MULTILANGS && empty($newlang)) $newlang=$object->client->default_lang; + if (! empty($newlang)) + { + $outputlangs = new Translate("",$conf); + $outputlangs->setDefaultLang($newlang); + } + if (empty($conf->global->MAIN_DISABLE_PDF_AUTOUPDATE)) + { + $ret=$object->fetch($id); // Reload to get new records + facture_pdf_create($db, $object, $object->modelpdf, $outputlangs, $hidedetails, $hidedesc, $hideref); + } + } + else + { + setEventMessage($object->error,'errors'); + } + } } // Go back to draft status (unvalidate) else if ($action == 'confirm_modif' && ((empty($conf->global->MAIN_USE_ADVANCED_PERMS) && $user->rights->facture->valider) || $user->rights->facture->invoice_advance->unvalidate)) { - $idwarehouse=GETPOST('idwarehouse'); + $idwarehouse=GETPOST('idwarehouse'); - $object->fetch($id); - $object->fetch_thirdparty(); + $object->fetch($id); + $object->fetch_thirdparty(); - // Check parameters - if ($object->type != 3 && ! empty($conf->global->STOCK_CALCULATE_ON_BILL) && $object->hasProductsOrServices(1)) - { - if (! $idwarehouse || $idwarehouse == -1) - { - $error++; - setEventMessage($langs->trans('ErrorFieldRequired',$langs->transnoentitiesnoconv("Warehouse")),'errors'); - $action=''; - } - } + $qualified_for_stock_change=0; + if (empty($conf->global->STOCK_SUPPORTS_SERVICES)) + { + $qualified_for_stock_change=$object->hasProductsOrServices(2); + } + else + { + $qualified_for_stock_change=$object->hasProductsOrServices(1); + } - if (! $error) - { - // On verifie si la facture a des paiements - $sql = 'SELECT pf.amount'; - $sql.= ' FROM '.MAIN_DB_PREFIX.'paiement_facture as pf'; - $sql.= ' WHERE pf.fk_facture = '.$object->id; + // Check parameters + if ($object->type != 3 && ! empty($conf->global->STOCK_CALCULATE_ON_BILL) && $qualified_for_stock_change) + { + if (! $idwarehouse || $idwarehouse == -1) + { + $error++; + setEventMessage($langs->trans('ErrorFieldRequired',$langs->transnoentitiesnoconv("Warehouse")),'errors'); + $action=''; + } + } - $result = $db->query($sql); - if ($result) - { - $i = 0; - $num = $db->num_rows($result); + if (! $error) + { + // On verifie si la facture a des paiements + $sql = 'SELECT pf.amount'; + $sql.= ' FROM '.MAIN_DB_PREFIX.'paiement_facture as pf'; + $sql.= ' WHERE pf.fk_facture = '.$object->id; - while ($i < $num) - { - $objp = $db->fetch_object($result); - $totalpaye += $objp->amount; - $i++; - } - } - else - { - dol_print_error($db,''); - } + $result = $db->query($sql); + if ($result) + { + $i = 0; + $num = $db->num_rows($result); - $resteapayer = $object->total_ttc - $totalpaye; + while ($i < $num) + { + $objp = $db->fetch_object($result); + $totalpaye += $objp->amount; + $i++; + } + } + else + { + dol_print_error($db,''); + } - // On verifie si les lignes de factures ont ete exportees en compta et/ou ventilees - $ventilExportCompta = $object->getVentilExportCompta(); + $resteapayer = $object->total_ttc - $totalpaye; - // On verifie si aucun paiement n'a ete effectue - if ($resteapayer == $object->total_ttc && $object->paye == 0 && $ventilExportCompta == 0) - { - $object->set_draft($user, $idwarehouse); + // On verifie si les lignes de factures ont ete exportees en compta et/ou ventilees + $ventilExportCompta = $object->getVentilExportCompta(); - // Define output language - $outputlangs = $langs; - $newlang=''; - if ($conf->global->MAIN_MULTILANGS && empty($newlang) && ! empty($_REQUEST['lang_id'])) $newlang=$_REQUEST['lang_id']; - if ($conf->global->MAIN_MULTILANGS && empty($newlang)) $newlang=$object->client->default_lang; - if (! empty($newlang)) - { - $outputlangs = new Translate("",$conf); - $outputlangs->setDefaultLang($newlang); - } - if (empty($conf->global->MAIN_DISABLE_PDF_AUTOUPDATE)) - { - $ret=$object->fetch($id); // Reload to get new records - facture_pdf_create($db, $object, $object->modelpdf, $outputlangs, $hidedetails, $hidedesc, $hideref); - } - } - } + // On verifie si aucun paiement n'a ete effectue + if ($resteapayer == $object->total_ttc && $object->paye == 0 && $ventilExportCompta == 0) + { + $object->set_draft($user, $idwarehouse); + + // Define output language + $outputlangs = $langs; + $newlang=''; + if ($conf->global->MAIN_MULTILANGS && empty($newlang) && ! empty($_REQUEST['lang_id'])) $newlang=$_REQUEST['lang_id']; + if ($conf->global->MAIN_MULTILANGS && empty($newlang)) $newlang=$object->client->default_lang; + if (! empty($newlang)) + { + $outputlangs = new Translate("",$conf); + $outputlangs->setDefaultLang($newlang); + } + if (empty($conf->global->MAIN_DISABLE_PDF_AUTOUPDATE)) + { + $ret=$object->fetch($id); // Reload to get new records + facture_pdf_create($db, $object, $object->modelpdf, $outputlangs, $hidedetails, $hidedesc, $hideref); + } + } + } } // Classify "paid" else if ($action == 'confirm_paid' && $confirm == 'yes' && $user->rights->facture->paiement) { - $object->fetch($id); - $result = $object->set_paid($user); + $object->fetch($id); + $result = $object->set_paid($user); } // Classif "paid partialy" else if ($action == 'confirm_paid_partially' && $confirm == 'yes' && $user->rights->facture->paiement) { - $object->fetch($id); - $close_code=$_POST["close_code"]; - $close_note=$_POST["close_note"]; - if ($close_code) - { - $result = $object->set_paid($user,$close_code,$close_note); - } - else - { - setEventMessage($langs->trans("ErrorFieldRequired",$langs->transnoentitiesnoconv("Reason")),'errors'); - } + $object->fetch($id); + $close_code=$_POST["close_code"]; + $close_note=$_POST["close_note"]; + if ($close_code) + { + $result = $object->set_paid($user,$close_code,$close_note); + } + else + { + setEventMessage($langs->trans("ErrorFieldRequired",$langs->transnoentitiesnoconv("Reason")),'errors'); + } } // Classify "abandoned" else if ($action == 'confirm_canceled' && $confirm == 'yes') { - $object->fetch($id); - $close_code=$_POST["close_code"]; - $close_note=$_POST["close_note"]; - if ($close_code) - { - $result = $object->set_canceled($user,$close_code,$close_note); - } - else - { - setEventMessage($langs->trans("ErrorFieldRequired",$langs->transnoentitiesnoconv("Reason")),'errors'); - } + $object->fetch($id); + $close_code=$_POST["close_code"]; + $close_note=$_POST["close_note"]; + if ($close_code) + { + $result = $object->set_canceled($user,$close_code,$close_note); + } + else + { + setEventMessage($langs->trans("ErrorFieldRequired",$langs->transnoentitiesnoconv("Reason")),'errors'); + } } // Convertir en reduc else if ($action == 'confirm_converttoreduc' && $confirm == 'yes' && $user->rights->facture->creer) { - $db->begin(); + $db->begin(); - $object->fetch($id); - $object->fetch_thirdparty(); - $object->fetch_lines(); + $object->fetch($id); + $object->fetch_thirdparty(); + $object->fetch_lines(); - if (! $object->paye) // protection against multiple submit - { - // Boucle sur chaque taux de tva - $i=0; - foreach($object->lines as $line) - { - $amount_ht[$line->tva_tx]+=$line->total_ht; - $amount_tva[$line->tva_tx]+=$line->total_tva; - $amount_ttc[$line->tva_tx]+=$line->total_ttc; - $i++; - } + if (! $object->paye) // protection against multiple submit + { + // Boucle sur chaque taux de tva + $i=0; + foreach($object->lines as $line) + { + $amount_ht[$line->tva_tx]+=$line->total_ht; + $amount_tva[$line->tva_tx]+=$line->total_tva; + $amount_ttc[$line->tva_tx]+=$line->total_ttc; + $i++; + } - // Insert one discount by VAT rate category - $discount = new DiscountAbsolute($db); - if ($object->type == 2) $discount->description='(CREDIT_NOTE)'; - elseif ($object->type == 3) $discount->description='(DEPOSIT)'; - else { - $this->error="CantConvertToReducAnInvoiceOfThisType"; - return -1; - } - $discount->tva_tx=abs($object->total_ttc); - $discount->fk_soc=$object->socid; - $discount->fk_facture_source=$object->id; + // Insert one discount by VAT rate category + $discount = new DiscountAbsolute($db); + if ($object->type == 2) $discount->description='(CREDIT_NOTE)'; + elseif ($object->type == 3) $discount->description='(DEPOSIT)'; + else { + $this->error="CantConvertToReducAnInvoiceOfThisType"; + return -1; + } + $discount->tva_tx=abs($object->total_ttc); + $discount->fk_soc=$object->socid; + $discount->fk_facture_source=$object->id; - $error=0; - foreach($amount_ht as $tva_tx => $xxx) - { - $discount->amount_ht=abs($amount_ht[$tva_tx]); - $discount->amount_tva=abs($amount_tva[$tva_tx]); - $discount->amount_ttc=abs($amount_ttc[$tva_tx]); - $discount->tva_tx=abs($tva_tx); + $error=0; + foreach($amount_ht as $tva_tx => $xxx) + { + $discount->amount_ht=abs($amount_ht[$tva_tx]); + $discount->amount_tva=abs($amount_tva[$tva_tx]); + $discount->amount_ttc=abs($amount_ttc[$tva_tx]); + $discount->tva_tx=abs($tva_tx); - $result=$discount->create($user); - if ($result < 0) - { - $error++; - break; - } - } + $result=$discount->create($user); + if ($result < 0) + { + $error++; + break; + } + } - if (! $error) - { - // Classe facture - $result=$object->set_paid($user); - if ($result > 0) - { - //$mesgs[]='OK'.$discount->id; - $db->commit(); - } - else - { - $mesgs[]='
'.$object->error.'
'; - $db->rollback(); - } - } - else - { - $mesgs[]='
'.$discount->error.'
'; - $db->rollback(); - } - } + if (! $error) + { + // Classe facture + $result=$object->set_paid($user); + if ($result > 0) + { + //$mesgs[]='OK'.$discount->id; + $db->commit(); + } + else + { + $mesgs[]='
'.$object->error.'
'; + $db->rollback(); + } + } + else + { + $mesgs[]='
'.$discount->error.'
'; + $db->rollback(); + } + } } /* * Insert new invoice in database - */ +*/ else if ($action == 'add' && $user->rights->facture->creer) { if ($socid>0) - $object->socid=GETPOST('socid','int'); + $object->socid=GETPOST('socid','int'); - $db->begin(); + $db->begin(); - $error=0; + $error=0; - // Get extra fields - foreach($_POST as $key => $value) - { - if (preg_match("/^options_/",$key)) - { - $object->array_options[$key]=GETPOST($key); - } - } + // Get extra fields + foreach($_POST as $key => $value) + { + if (preg_match("/^options_/",$key)) + { + $object->array_options[$key]=GETPOST($key); + } + } - // Replacement invoice - if ($_POST['type'] == 1) - { - $datefacture = dol_mktime(12, 0, 0, $_POST['remonth'], $_POST['reday'], $_POST['reyear']); - if (empty($datefacture)) - { - $error++; - setEventMessage($langs->trans("ErrorFieldRequired",$langs->transnoentitiesnoconv("Date")),'errors'); - } + // Replacement invoice + if ($_POST['type'] == 1) + { + $datefacture = dol_mktime(12, 0, 0, $_POST['remonth'], $_POST['reday'], $_POST['reyear']); + if (empty($datefacture)) + { + $error++; + setEventMessage($langs->trans("ErrorFieldRequired",$langs->transnoentitiesnoconv("Date")),'errors'); + } - if (! ($_POST['fac_replacement'] > 0)) - { - $error++; - setEventMessage($langs->trans("ErrorFieldRequired",$langs->transnoentitiesnoconv("ReplaceInvoice")),'errors'); - } + if (! ($_POST['fac_replacement'] > 0)) + { + $error++; + setEventMessage($langs->trans("ErrorFieldRequired",$langs->transnoentitiesnoconv("ReplaceInvoice")),'errors'); + } - if (! $error) - { - // This is a replacement invoice - $result=$object->fetch($_POST['fac_replacement']); - $object->fetch_thirdparty(); + if (! $error) + { + // This is a replacement invoice + $result=$object->fetch($_POST['fac_replacement']); + $object->fetch_thirdparty(); - $object->date = $datefacture; - $object->note_public = trim($_POST['note_public']); - $object->note = trim($_POST['note']); - $object->ref_client = $_POST['ref_client']; - $object->ref_int = $_POST['ref_int']; - $object->modelpdf = $_POST['model']; - $object->fk_project = $_POST['projectid']; - $object->cond_reglement_id = $_POST['cond_reglement_id']; - $object->mode_reglement_id = $_POST['mode_reglement_id']; - $object->remise_absolue = $_POST['remise_absolue']; - $object->remise_percent = $_POST['remise_percent']; + $object->date = $datefacture; + $object->note_public = trim($_POST['note_public']); + $object->note = trim($_POST['note']); + $object->ref_client = $_POST['ref_client']; + $object->ref_int = $_POST['ref_int']; + $object->modelpdf = $_POST['model']; + $object->fk_project = $_POST['projectid']; + $object->cond_reglement_id = $_POST['cond_reglement_id']; + $object->mode_reglement_id = $_POST['mode_reglement_id']; + $object->remise_absolue = $_POST['remise_absolue']; + $object->remise_percent = $_POST['remise_percent']; - // Proprietes particulieres a facture de remplacement - $object->fk_facture_source = $_POST['fac_replacement']; - $object->type = 1; + // Proprietes particulieres a facture de remplacement + $object->fk_facture_source = $_POST['fac_replacement']; + $object->type = 1; - $id=$object->createFromCurrent($user); - if ($id <= 0) $mesgs[]=$object->error; - } - } + $id=$object->createFromCurrent($user); + if ($id <= 0) $mesgs[]=$object->error; + } + } - // Credit note invoice - if ($_POST['type'] == 2) - { - if (! $_POST['fac_avoir'] > 0) - { - $error++; - setEventMessage($langs->trans("ErrorFieldRequired",$langs->transnoentitiesnoconv("CorrectInvoice")),'errors'); - } + // Credit note invoice + if ($_POST['type'] == 2) + { + if (! $_POST['fac_avoir'] > 0) + { + $error++; + setEventMessage($langs->trans("ErrorFieldRequired",$langs->transnoentitiesnoconv("CorrectInvoice")),'errors'); + } - $datefacture = dol_mktime(12, 0, 0, $_POST['remonth'], $_POST['reday'], $_POST['reyear']); - if (empty($datefacture)) - { - $error++; - setEventMessage($langs->trans("ErrorFieldRequired",$langs->trans("Date")),'errors'); - } + $datefacture = dol_mktime(12, 0, 0, $_POST['remonth'], $_POST['reday'], $_POST['reyear']); + if (empty($datefacture)) + { + $error++; + setEventMessage($langs->trans("ErrorFieldRequired",$langs->trans("Date")),'errors'); + } - if (! $error) - { - // Si facture avoir - $datefacture = dol_mktime(12, 0, 0, $_POST['remonth'], $_POST['reday'], $_POST['reyear']); + if (! $error) + { + // Si facture avoir + $datefacture = dol_mktime(12, 0, 0, $_POST['remonth'], $_POST['reday'], $_POST['reyear']); - //$result=$object->fetch($_POST['fac_avoir']); + //$result=$object->fetch($_POST['fac_avoir']); - $object->socid = GETPOST('socid','int'); - $object->number = $_POST['facnumber']; - $object->date = $datefacture; - $object->note_public = trim($_POST['note_public']); - $object->note = trim($_POST['note']); - $object->ref_client = $_POST['ref_client']; - $object->ref_int = $_POST['ref_int']; - $object->modelpdf = $_POST['model']; - $object->fk_project = $_POST['projectid']; - $object->cond_reglement_id = 0; - $object->mode_reglement_id = $_POST['mode_reglement_id']; - $object->remise_absolue = $_POST['remise_absolue']; - $object->remise_percent = $_POST['remise_percent']; + $object->socid = GETPOST('socid','int'); + $object->number = $_POST['facnumber']; + $object->date = $datefacture; + $object->note_public = trim($_POST['note_public']); + $object->note = trim($_POST['note']); + $object->ref_client = $_POST['ref_client']; + $object->ref_int = $_POST['ref_int']; + $object->modelpdf = $_POST['model']; + $object->fk_project = $_POST['projectid']; + $object->cond_reglement_id = 0; + $object->mode_reglement_id = $_POST['mode_reglement_id']; + $object->remise_absolue = $_POST['remise_absolue']; + $object->remise_percent = $_POST['remise_percent']; - // Proprietes particulieres a facture avoir - $object->fk_facture_source = $_POST['fac_avoir']; - $object->type = 2; + // Proprietes particulieres a facture avoir + $object->fk_facture_source = $_POST['fac_avoir']; + $object->type = 2; - $id = $object->create($user); + $id = $object->create($user); - // Add predefined lines - for ($i = 1; $i <= $NBLINES; $i++) - { - if ($_POST['idprod'.$i]) - { - $product=new Product($db); - $product->fetch($_POST['idprod'.$i]); - $startday=dol_mktime(12, 0, 0, $_POST['date_start'.$i.'month'], $_POST['date_start'.$i.'day'], $_POST['date_start'.$i.'year']); - $endday=dol_mktime(12, 0, 0, $_POST['date_end'.$i.'month'], $_POST['date_end'.$i.'day'], $_POST['date_end'.$i.'year']); - $result=$object->addline($id,$product->description,$product->price, $_POST['qty'.$i], $product->tva_tx, $product->localtax1_tx, $product->localtax2_tx, $_POST['idprod'.$i], $_POST['remise_percent'.$i], $startday, $endday, 0, 0, '', $product->price_base_type, $product->price_ttc, $product->type); - } - } - } - } + // Add predefined lines + for ($i = 1; $i <= $NBLINES; $i++) + { + if ($_POST['idprod'.$i]) + { + $product=new Product($db); + $product->fetch($_POST['idprod'.$i]); + $startday=dol_mktime(12, 0, 0, $_POST['date_start'.$i.'month'], $_POST['date_start'.$i.'day'], $_POST['date_start'.$i.'year']); + $endday=dol_mktime(12, 0, 0, $_POST['date_end'.$i.'month'], $_POST['date_end'.$i.'day'], $_POST['date_end'.$i.'year']); + $result=$object->addline($id,$product->description,$product->price, $_POST['qty'.$i], $product->tva_tx, $product->localtax1_tx, $product->localtax2_tx, $_POST['idprod'.$i], $_POST['remise_percent'.$i], $startday, $endday, 0, 0, '', $product->price_base_type, $product->price_ttc, $product->type); + } + } + } + } - // Standard invoice or Deposit invoice created from a Predefined invoice - if (($_POST['type'] == 0 || $_POST['type'] == 3) && $_POST['fac_rec'] > 0) - { - $datefacture = dol_mktime(12, 0, 0, $_POST['remonth'], $_POST['reday'], $_POST['reyear']); - if (empty($datefacture)) - { - $error++; - setEventMessage($langs->trans("ErrorFieldRequired",$langs->transnoentitiesnoconv("Date")),'errors'); - } + // Standard invoice or Deposit invoice created from a Predefined invoice + if (($_POST['type'] == 0 || $_POST['type'] == 3) && $_POST['fac_rec'] > 0) + { + $datefacture = dol_mktime(12, 0, 0, $_POST['remonth'], $_POST['reday'], $_POST['reyear']); + if (empty($datefacture)) + { + $error++; + setEventMessage($langs->trans("ErrorFieldRequired",$langs->transnoentitiesnoconv("Date")),'errors'); + } - if (! $error) - { - $object->socid = GETPOST('socid','int'); - $object->type = $_POST['type']; - $object->number = $_POST['facnumber']; - $object->date = $datefacture; - $object->note_public = trim($_POST['note_public']); - $object->note_private = trim($_POST['note_private']); - $object->ref_client = $_POST['ref_client']; - $object->ref_int = $_POST['ref_int']; - $object->modelpdf = $_POST['model']; + if (! $error) + { + $object->socid = GETPOST('socid','int'); + $object->type = $_POST['type']; + $object->number = $_POST['facnumber']; + $object->date = $datefacture; + $object->note_public = trim($_POST['note_public']); + $object->note_private = trim($_POST['note_private']); + $object->ref_client = $_POST['ref_client']; + $object->ref_int = $_POST['ref_int']; + $object->modelpdf = $_POST['model']; - // Source facture - $object->fac_rec = $_POST['fac_rec']; + // Source facture + $object->fac_rec = $_POST['fac_rec']; - $id = $object->create($user); - } - } + $id = $object->create($user); + } + } - // Standard or deposit or proforma invoice - if (($_POST['type'] == 0 || $_POST['type'] == 3 || $_POST['type'] == 4) && $_POST['fac_rec'] <= 0) - { - if (GETPOST('socid','int')<1) - { - $error++; - setEventMessage($langs->trans("ErrorFieldRequired",$langs->transnoentitiesnoconv("Customer")),'errors'); - } + // Standard or deposit or proforma invoice + if (($_POST['type'] == 0 || $_POST['type'] == 3 || $_POST['type'] == 4) && $_POST['fac_rec'] <= 0) + { + if (GETPOST('socid','int')<1) + { + $error++; + setEventMessage($langs->trans("ErrorFieldRequired",$langs->transnoentitiesnoconv("Customer")),'errors'); + } - $datefacture = dol_mktime(12, 0, 0, $_POST['remonth'], $_POST['reday'], $_POST['reyear']); - if (empty($datefacture)) - { - $error++; - setEventMessage($langs->trans("ErrorFieldRequired",$langs->transnoentitiesnoconv("Date")),'errors'); - } + $datefacture = dol_mktime(12, 0, 0, $_POST['remonth'], $_POST['reday'], $_POST['reyear']); + if (empty($datefacture)) + { + $error++; + setEventMessage($langs->trans("ErrorFieldRequired",$langs->transnoentitiesnoconv("Date")),'errors'); + } - if (! $error) - { - // Si facture standard - $object->socid = GETPOST('socid','int'); - $object->type = GETPOST('type'); - $object->number = $_POST['facnumber']; - $object->date = $datefacture; - $object->note_public = trim($_POST['note_public']); - $object->note_private = trim($_POST['note_private']); - $object->ref_client = $_POST['ref_client']; - $object->ref_int = $_POST['ref_int']; - $object->modelpdf = $_POST['model']; - $object->fk_project = $_POST['projectid']; - $object->cond_reglement_id = ($_POST['type'] == 3?1:$_POST['cond_reglement_id']); - $object->mode_reglement_id = $_POST['mode_reglement_id']; - $object->amount = $_POST['amount']; - $object->remise_absolue = $_POST['remise_absolue']; - $object->remise_percent = $_POST['remise_percent']; - $object->fetch_thirdparty(); + if (! $error) + { + // Si facture standard + $object->socid = GETPOST('socid','int'); + $object->type = GETPOST('type'); + $object->number = $_POST['facnumber']; + $object->date = $datefacture; + $object->note_public = trim($_POST['note_public']); + $object->note_private = trim($_POST['note_private']); + $object->ref_client = $_POST['ref_client']; + $object->ref_int = $_POST['ref_int']; + $object->modelpdf = $_POST['model']; + $object->fk_project = $_POST['projectid']; + $object->cond_reglement_id = ($_POST['type'] == 3?1:$_POST['cond_reglement_id']); + $object->mode_reglement_id = $_POST['mode_reglement_id']; + $object->amount = $_POST['amount']; + $object->remise_absolue = $_POST['remise_absolue']; + $object->remise_percent = $_POST['remise_percent']; + $object->fetch_thirdparty(); - // If creation from another object of another module (Example: origin=propal, originid=1) - if ($_POST['origin'] && $_POST['originid']) - { - // Parse element/subelement (ex: project_task) - $element = $subelement = $_POST['origin']; - if (preg_match('/^([^_]+)_([^_]+)/i',$_POST['origin'],$regs)) - { - $element = $regs[1]; - $subelement = $regs[2]; - } + // If creation from another object of another module (Example: origin=propal, originid=1) + if ($_POST['origin'] && $_POST['originid']) + { + // Parse element/subelement (ex: project_task) + $element = $subelement = $_POST['origin']; + if (preg_match('/^([^_]+)_([^_]+)/i',$_POST['origin'],$regs)) + { + $element = $regs[1]; + $subelement = $regs[2]; + } - // For compatibility - if ($element == 'order') { $element = $subelement = 'commande'; } - if ($element == 'propal') { $element = 'comm/propal'; $subelement = 'propal'; } - if ($element == 'contract') { $element = $subelement = 'contrat'; } - if ($element == 'inter') { $element = $subelement = 'ficheinter'; } - if ($element == 'shipping') { $element = $subelement = 'expedition'; } + // For compatibility + if ($element == 'order') { + $element = $subelement = 'commande'; + } + if ($element == 'propal') { + $element = 'comm/propal'; $subelement = 'propal'; + } + if ($element == 'contract') { + $element = $subelement = 'contrat'; + } + if ($element == 'inter') { + $element = $subelement = 'ficheinter'; + } + if ($element == 'shipping') { + $element = $subelement = 'expedition'; + } - $object->origin = $_POST['origin']; - $object->origin_id = $_POST['originid']; + $object->origin = $_POST['origin']; + $object->origin_id = $_POST['originid']; - // Possibility to add external linked objects with hooks - $object->linked_objects[$object->origin] = $object->origin_id; - if (is_array($_POST['other_linked_objects']) && ! empty($_POST['other_linked_objects'])) - { - $object->linked_objects = array_merge($object->linked_objects, $_POST['other_linked_objects']); - } + // Possibility to add external linked objects with hooks + $object->linked_objects[$object->origin] = $object->origin_id; + if (is_array($_POST['other_linked_objects']) && ! empty($_POST['other_linked_objects'])) + { + $object->linked_objects = array_merge($object->linked_objects, $_POST['other_linked_objects']); + } - $id = $object->create($user); + $id = $object->create($user); - if ($id > 0) - { - dol_include_once('/'.$element.'/class/'.$subelement.'.class.php'); + if ($id > 0) + { + dol_include_once('/'.$element.'/class/'.$subelement.'.class.php'); - $classname = ucfirst($subelement); - $srcobject = new $classname($db); + $classname = ucfirst($subelement); + $srcobject = new $classname($db); - dol_syslog("Try to find source object origin=".$object->origin." originid=".$object->origin_id." to add lines"); - $result=$srcobject->fetch($object->origin_id); - if ($result > 0) - { - $lines = $srcobject->lines; - if (empty($lines) && method_exists($srcobject,'fetch_lines')) $lines = $srcobject->fetch_lines(); + dol_syslog("Try to find source object origin=".$object->origin." originid=".$object->origin_id." to add lines"); + $result=$srcobject->fetch($object->origin_id); + if ($result > 0) + { + $lines = $srcobject->lines; + if (empty($lines) && method_exists($srcobject,'fetch_lines')) $lines = $srcobject->fetch_lines(); - $fk_parent_line=0; - $num=count($lines); + $fk_parent_line=0; + $num=count($lines); - for ($i=0;$i<$num;$i++) - { - $label=(! empty($lines[$i]->label)?$lines[$i]->label:''); - $desc=(! empty($lines[$i]->desc)?$lines[$i]->desc:$lines[$i]->libelle); + for ($i=0;$i<$num;$i++) + { + $label=(! empty($lines[$i]->label)?$lines[$i]->label:''); + $desc=(! empty($lines[$i]->desc)?$lines[$i]->desc:$lines[$i]->libelle); - if ($lines[$i]->subprice < 0) - { - // Negative line, we create a discount line - $discount = new DiscountAbsolute($db); - $discount->fk_soc=$object->socid; - $discount->amount_ht=abs($lines[$i]->total_ht); - $discount->amount_tva=abs($lines[$i]->total_tva); - $discount->amount_ttc=abs($lines[$i]->total_ttc); - $discount->tva_tx=$lines[$i]->tva_tx; - $discount->fk_user=$user->id; - $discount->description=$desc; - $discountid=$discount->create($user); - if ($discountid > 0) - { - $result=$object->insert_discount($discountid); // This include link_to_invoice - } - else - { - $mesgs[]=$discount->error; - $error++; - break; - } - } - else - { - // Positive line - $product_type=($lines[$i]->product_type?$lines[$i]->product_type:0); + if ($lines[$i]->subprice < 0) + { + // Negative line, we create a discount line + $discount = new DiscountAbsolute($db); + $discount->fk_soc=$object->socid; + $discount->amount_ht=abs($lines[$i]->total_ht); + $discount->amount_tva=abs($lines[$i]->total_tva); + $discount->amount_ttc=abs($lines[$i]->total_ttc); + $discount->tva_tx=$lines[$i]->tva_tx; + $discount->fk_user=$user->id; + $discount->description=$desc; + $discountid=$discount->create($user); + if ($discountid > 0) + { + $result=$object->insert_discount($discountid); // This include link_to_invoice + } + else + { + $mesgs[]=$discount->error; + $error++; + break; + } + } + else + { + // Positive line + $product_type=($lines[$i]->product_type?$lines[$i]->product_type:0); - // Date start - $date_start=false; - if ($lines[$i]->date_debut_prevue) $date_start=$lines[$i]->date_debut_prevue; - if ($lines[$i]->date_debut_reel) $date_start=$lines[$i]->date_debut_reel; - if ($lines[$i]->date_start) $date_start=$lines[$i]->date_start; + // Date start + $date_start=false; + if ($lines[$i]->date_debut_prevue) $date_start=$lines[$i]->date_debut_prevue; + if ($lines[$i]->date_debut_reel) $date_start=$lines[$i]->date_debut_reel; + if ($lines[$i]->date_start) $date_start=$lines[$i]->date_start; - //Date end - $date_end=false; - if ($lines[$i]->date_fin_prevue) $date_end=$lines[$i]->date_fin_prevue; - if ($lines[$i]->date_fin_reel) $date_end=$lines[$i]->date_fin_reel; - if ($lines[$i]->date_end) $date_end=$lines[$i]->date_end; + //Date end + $date_end=false; + if ($lines[$i]->date_fin_prevue) $date_end=$lines[$i]->date_fin_prevue; + if ($lines[$i]->date_fin_reel) $date_end=$lines[$i]->date_fin_reel; + if ($lines[$i]->date_end) $date_end=$lines[$i]->date_end; - // Reset fk_parent_line for no child products and special product - if (($lines[$i]->product_type != 9 && empty($lines[$i]->fk_parent_line)) || $lines[$i]->product_type == 9) { - $fk_parent_line = 0; - } + // Reset fk_parent_line for no child products and special product + if (($lines[$i]->product_type != 9 && empty($lines[$i]->fk_parent_line)) || $lines[$i]->product_type == 9) { + $fk_parent_line = 0; + } - $result = $object->addline( - $id, - $desc, - $lines[$i]->subprice, - $lines[$i]->qty, - $lines[$i]->tva_tx, - $lines[$i]->localtax1_tx, - $lines[$i]->localtax2_tx, - $lines[$i]->fk_product, - $lines[$i]->remise_percent, - $date_start, - $date_end, - 0, - $lines[$i]->info_bits, - $lines[$i]->fk_remise_except, - 'HT', - 0, - $product_type, - $lines[$i]->rang, - $lines[$i]->special_code, - $object->origin, - $lines[$i]->rowid, - $fk_parent_line, - $lines[$i]->fk_fournprice, - $lines[$i]->pa_ht, - $label - ); + $result = $object->addline( + $id, + $desc, + $lines[$i]->subprice, + $lines[$i]->qty, + $lines[$i]->tva_tx, + $lines[$i]->localtax1_tx, + $lines[$i]->localtax2_tx, + $lines[$i]->fk_product, + $lines[$i]->remise_percent, + $date_start, + $date_end, + 0, + $lines[$i]->info_bits, + $lines[$i]->fk_remise_except, + 'HT', + 0, + $product_type, + $lines[$i]->rang, + $lines[$i]->special_code, + $object->origin, + $lines[$i]->rowid, + $fk_parent_line, + $lines[$i]->fk_fournprice, + $lines[$i]->pa_ht, + $label + ); - if ($result > 0) - { - $lineid=$result; - } - else - { - $lineid=0; - $error++; - break; - } + if ($result > 0) + { + $lineid=$result; + } + else + { + $lineid=0; + $error++; + break; + } - // Defined the new fk_parent_line - if ($result > 0 && $lines[$i]->product_type == 9) { - $fk_parent_line = $result; - } - } - } + // Defined the new fk_parent_line + if ($result > 0 && $lines[$i]->product_type == 9) { + $fk_parent_line = $result; + } + } + } - // Hooks - $parameters=array('objFrom'=>$srcobject); - $reshook=$hookmanager->executeHooks('createFrom',$parameters,$object,$action); // Note that $action and $object may have been modified by hook - if ($reshook < 0) $error++; - } - else - { - $mesgs[]=$srcobject->error; - $error++; - } - } - else - { - $mesgs[]=$object->error; - $error++; - } - } - // If some invoice's lines already known - else - { - $id = $object->create($user); + // Hooks + $parameters=array('objFrom'=>$srcobject); + $reshook=$hookmanager->executeHooks('createFrom',$parameters,$object,$action); // Note that $action and $object may have been modified by hook + if ($reshook < 0) $error++; + } + else + { + $mesgs[]=$srcobject->error; + $error++; + } + } + else + { + $mesgs[]=$object->error; + $error++; + } + } + // If some invoice's lines already known + else + { + $id = $object->create($user); - for ($i = 1; $i <= $NBLINES; $i++) - { - if ($_POST['idprod'.$i]) - { - $product=new Product($db); - $product->fetch($_POST['idprod'.$i]); - $startday=dol_mktime(12, 0, 0, $_POST['date_start'.$i.'month'], $_POST['date_start'.$i.'day'], $_POST['date_start'.$i.'year']); - $endday=dol_mktime(12, 0, 0, $_POST['date_end'.$i.'month'], $_POST['date_end'.$i.'day'], $_POST['date_end'.$i.'year']); - $result=$object->addline($id,$product->description,$product->price, $_POST['qty'.$i], $product->tva_tx, $product->localtax1_tx, $product->localtax2_tx, $_POST['idprod'.$i], $_POST['remise_percent'.$i], $startday, $endday, 0, 0, '', $product->price_base_type, $product->price_ttc, $product->type); - } - } - } - } - } + for ($i = 1; $i <= $NBLINES; $i++) + { + if ($_POST['idprod'.$i]) + { + $product=new Product($db); + $product->fetch($_POST['idprod'.$i]); + $startday=dol_mktime(12, 0, 0, $_POST['date_start'.$i.'month'], $_POST['date_start'.$i.'day'], $_POST['date_start'.$i.'year']); + $endday=dol_mktime(12, 0, 0, $_POST['date_end'.$i.'month'], $_POST['date_end'.$i.'day'], $_POST['date_end'.$i.'year']); + $result=$object->addline($id,$product->description,$product->price, $_POST['qty'.$i], $product->tva_tx, $product->localtax1_tx, $product->localtax2_tx, $_POST['idprod'.$i], $_POST['remise_percent'.$i], $startday, $endday, 0, 0, '', $product->price_base_type, $product->price_ttc, $product->type); + } + } + } + } + } - // End of object creation, we show it - if ($id > 0 && ! $error) - { - $db->commit(); - header('Location: '.$_SERVER["PHP_SELF"].'?facid='.$id); - exit; - } - else - { - $db->rollback(); - $action='create'; - $_GET["origin"]=$_POST["origin"]; - $_GET["originid"]=$_POST["originid"]; - $mesgs[]='
'.$object->error.'
'; - } + // End of object creation, we show it + if ($id > 0 && ! $error) + { + $db->commit(); + header('Location: '.$_SERVER["PHP_SELF"].'?facid='.$id); + exit; + } + else + { + $db->rollback(); + $action='create'; + $_GET["origin"]=$_POST["origin"]; + $_GET["originid"]=$_POST["originid"]; + $mesgs[]='
'.$object->error.'
'; + } } // Add a new line else if (($action == 'addline' || $action == 'addline_predef') && $user->rights->facture->creer) { $langs->load('errors'); - $error = 0; + $error = 0; - $idprod=GETPOST('idprod', 'int'); + $idprod=GETPOST('idprod', 'int'); $product_desc = (GETPOST('product_desc')?GETPOST('product_desc'):(GETPOST('np_desc')?GETPOST('np_desc'):(GETPOST('dp_desc')?GETPOST('dp_desc'):''))); $price_ht = GETPOST('price_ht'); $tva_tx=(GETPOST('tva_tx')?GETPOST('tva_tx'):0); if ((empty($idprod) || GETPOST('usenewaddlineform')) && ($price_ht < 0) && (GETPOST('qty') < 0)) - { - setEventMessage($langs->trans('ErrorBothFieldCantBeNegative', $langs->transnoentitiesnoconv('UnitPriceHT'), $langs->transnoentitiesnoconv('Qty')), 'errors'); - $error++; - } - if (empty($idprod) && GETPOST('type') < 0) - { - setEventMessage($langs->trans('ErrorFieldRequired', $langs->transnoentitiesnoconv('Type')), 'errors'); - $error++; - } + { + setEventMessage($langs->trans('ErrorBothFieldCantBeNegative', $langs->transnoentitiesnoconv('UnitPriceHT'), $langs->transnoentitiesnoconv('Qty')), 'errors'); + $error++; + } + if (empty($idprod) && GETPOST('type') < 0) + { + setEventMessage($langs->trans('ErrorFieldRequired', $langs->transnoentitiesnoconv('Type')), 'errors'); + $error++; + } if ((empty($idprod) || GETPOST('usenewaddlineform')) && (!($price_ht >= 0) || $price_ht == '')) // Unit price can be 0 but not '' { setEventMessage($langs->trans("ErrorFieldRequired",$langs->transnoentitiesnoconv("UnitPriceHT")), 'errors'); $error++; } - if (! GETPOST('qty') && GETPOST('qty') == '') - { - setEventMessage($langs->trans('ErrorFieldRequired', $langs->transnoentitiesnoconv('Qty')), 'errors'); - $error++; - } - if (empty($idprod) && empty($product_desc)) - { - setEventMessage($langs->trans('ErrorFieldRequired', $langs->transnoentitiesnoconv('Description')), 'errors'); - $error++; - } + if (! GETPOST('qty') && GETPOST('qty') == '') + { + setEventMessage($langs->trans('ErrorFieldRequired', $langs->transnoentitiesnoconv('Qty')), 'errors'); + $error++; + } + if (empty($idprod) && empty($product_desc)) + { + setEventMessage($langs->trans('ErrorFieldRequired', $langs->transnoentitiesnoconv('Description')), 'errors'); + $error++; + } - if (! $error && (GETPOST('qty') >= 0) && (! empty($product_desc) || ! empty($idprod))) - { - $ret=$object->fetch($id); - if ($ret < 0) - { - dol_print_error($db,$object->error); - exit; - } - $ret=$object->fetch_thirdparty(); + if (! $error && (GETPOST('qty') >= 0) && (! empty($product_desc) || ! empty($idprod))) + { + $ret=$object->fetch($id); + if ($ret < 0) + { + dol_print_error($db,$object->error); + exit; + } + $ret=$object->fetch_thirdparty(); - // Clean parameters - $predef=((! empty($idprod) && $conf->global->MAIN_FEATURES_LEVEL < 2) ? '_predef' : ''); - $date_start=dol_mktime(GETPOST('date_start'.$predef.'hour'), GETPOST('date_start'.$predef.'min'), GETPOST('date_start'.$predef.'sec'), GETPOST('date_start'.$predef.'month'), GETPOST('date_start'.$predef.'day'), GETPOST('date_start'.$predef.'year')); - $date_end=dol_mktime(GETPOST('date_end'.$predef.'hour'), GETPOST('date_end'.$predef.'min'), GETPOST('date_end'.$predef.'sec'), GETPOST('date_end'.$predef.'month'), GETPOST('date_end'.$predef.'day'), GETPOST('date_end'.$predef.'year')); - $price_base_type = (GETPOST('price_base_type', 'alpha')?GETPOST('price_base_type', 'alpha'):'HT'); + // Clean parameters + $predef=((! empty($idprod) && $conf->global->MAIN_FEATURES_LEVEL < 2) ? '_predef' : ''); + $date_start=dol_mktime(GETPOST('date_start'.$predef.'hour'), GETPOST('date_start'.$predef.'min'), GETPOST('date_start'.$predef.'sec'), GETPOST('date_start'.$predef.'month'), GETPOST('date_start'.$predef.'day'), GETPOST('date_start'.$predef.'year')); + $date_end=dol_mktime(GETPOST('date_end'.$predef.'hour'), GETPOST('date_end'.$predef.'min'), GETPOST('date_end'.$predef.'sec'), GETPOST('date_end'.$predef.'month'), GETPOST('date_end'.$predef.'day'), GETPOST('date_end'.$predef.'year')); + $price_base_type = (GETPOST('price_base_type', 'alpha')?GETPOST('price_base_type', 'alpha'):'HT'); - // Define special_code for special lines - $special_code=0; - //if (empty($_POST['qty'])) $special_code=3; // Options should not exists on invoices + // Define special_code for special lines + $special_code=0; + //if (empty($_POST['qty'])) $special_code=3; // Options should not exists on invoices - // Ecrase $pu par celui du produit - // Ecrase $desc par celui du produit - // Ecrase $txtva par celui du produit - // Ecrase $base_price_type par celui du produit - if (! empty($idprod)) - { - $prod = new Product($db); - $prod->fetch($idprod); + // Ecrase $pu par celui du produit + // Ecrase $desc par celui du produit + // Ecrase $txtva par celui du produit + // Ecrase $base_price_type par celui du produit + if (! empty($idprod)) + { + $prod = new Product($db); + $prod->fetch($idprod); - $label = ((GETPOST('product_label') && GETPOST('product_label')!=$prod->label)?GETPOST('product_label'):''); + $label = ((GETPOST('product_label') && GETPOST('product_label')!=$prod->label)?GETPOST('product_label'):''); - // Update if prices fields are defined - if (GETPOST('usenewaddlineform')) - { - $pu_ht=price2num($price_ht, 'MU'); + // Update if prices fields are defined + if (GETPOST('usenewaddlineform')) + { + $pu_ht=price2num($price_ht, 'MU'); $pu_ttc=price2num(GETPOST('price_ttc'), 'MU'); $tva_npr=(preg_match('/\*/', $tva_tx)?1:0); $tva_tx=str_replace('*','', $tva_tx); $desc = $product_desc; - } - else + } + else { - $tva_tx = get_default_tva($mysoc,$object->client,$prod->id); - $tva_npr = get_default_npr($mysoc,$object->client,$prod->id); + $tva_tx = get_default_tva($mysoc,$object->client,$prod->id); + $tva_npr = get_default_npr($mysoc,$object->client,$prod->id); - // We define price for product - if (! empty($conf->global->PRODUIT_MULTIPRICES) && ! empty($object->client->price_level)) - { - $pu_ht = $prod->multiprices[$object->client->price_level]; - $pu_ttc = $prod->multiprices_ttc[$object->client->price_level]; - $price_min = $prod->multiprices_min[$object->client->price_level]; - $price_base_type = $prod->multiprices_base_type[$object->client->price_level]; - } - else - { - $pu_ht = $prod->price; - $pu_ttc = $prod->price_ttc; - $price_min = $prod->price_min; - $price_base_type = $prod->price_base_type; - } + // We define price for product + if (! empty($conf->global->PRODUIT_MULTIPRICES) && ! empty($object->client->price_level)) + { + $pu_ht = $prod->multiprices[$object->client->price_level]; + $pu_ttc = $prod->multiprices_ttc[$object->client->price_level]; + $price_min = $prod->multiprices_min[$object->client->price_level]; + $price_base_type = $prod->multiprices_base_type[$object->client->price_level]; + } + else + { + $pu_ht = $prod->price; + $pu_ttc = $prod->price_ttc; + $price_min = $prod->price_min; + $price_base_type = $prod->price_base_type; + } - // On reevalue prix selon taux tva car taux tva transaction peut etre different - // de ceux du produit par defaut (par exemple si pays different entre vendeur et acheteur). - if ($tva_tx != $prod->tva_tx) - { - if ($price_base_type != 'HT') - { - $pu_ht = price2num($pu_ttc / (1 + ($tva_tx/100)), 'MU'); - } - else - { - $pu_ttc = price2num($pu_ht * (1 + ($tva_tx/100)), 'MU'); - } - } + // On reevalue prix selon taux tva car taux tva transaction peut etre different + // de ceux du produit par defaut (par exemple si pays different entre vendeur et acheteur). + if ($tva_tx != $prod->tva_tx) + { + if ($price_base_type != 'HT') + { + $pu_ht = price2num($pu_ttc / (1 + ($tva_tx/100)), 'MU'); + } + else + { + $pu_ttc = price2num($pu_ht * (1 + ($tva_tx/100)), 'MU'); + } + } - $desc=''; + $desc=''; - // Define output language - if (! empty($conf->global->MAIN_MULTILANGS) && ! empty($conf->global->PRODUIT_TEXTS_IN_THIRDPARTY_LANGUAGE)) - { - $outputlangs = $langs; - $newlang=''; - if (empty($newlang) && GETPOST('lang_id')) $newlang=GETPOST('lang_id'); - if (empty($newlang)) $newlang=$object->client->default_lang; - if (! empty($newlang)) - { - $outputlangs = new Translate("",$conf); - $outputlangs->setDefaultLang($newlang); - } + // Define output language + if (! empty($conf->global->MAIN_MULTILANGS) && ! empty($conf->global->PRODUIT_TEXTS_IN_THIRDPARTY_LANGUAGE)) + { + $outputlangs = $langs; + $newlang=''; + if (empty($newlang) && GETPOST('lang_id')) $newlang=GETPOST('lang_id'); + if (empty($newlang)) $newlang=$object->client->default_lang; + if (! empty($newlang)) + { + $outputlangs = new Translate("",$conf); + $outputlangs->setDefaultLang($newlang); + } - $desc = (! empty($prod->multilangs[$outputlangs->defaultlang]["description"])) ? $prod->multilangs[$outputlangs->defaultlang]["description"] : $prod->description; - } - else - { - $desc = $prod->description; - } + $desc = (! empty($prod->multilangs[$outputlangs->defaultlang]["description"])) ? $prod->multilangs[$outputlangs->defaultlang]["description"] : $prod->description; + } + else + { + $desc = $prod->description; + } - $desc=dol_concatdesc($desc,$product_desc); + $desc=dol_concatdesc($desc,$product_desc); - // Add custom code and origin country into description - if (empty($conf->global->MAIN_PRODUCT_DISABLE_CUSTOMCOUNTRYCODE) && (! empty($prod->customcode) || ! empty($prod->country_code))) - { - $tmptxt='('; - if (! empty($prod->customcode)) $tmptxt.=$langs->transnoentitiesnoconv("CustomCode").': '.$prod->customcode; - if (! empty($prod->customcode) && ! empty($prod->country_code)) $tmptxt.=' - '; - if (! empty($prod->country_code)) $tmptxt.=$langs->transnoentitiesnoconv("CountryOrigin").': '.getCountry($prod->country_code,0,$db,$langs,0); - $tmptxt.=')'; - $desc= dol_concatdesc($desc, $tmptxt); - } - } + // Add custom code and origin country into description + if (empty($conf->global->MAIN_PRODUCT_DISABLE_CUSTOMCOUNTRYCODE) && (! empty($prod->customcode) || ! empty($prod->country_code))) + { + $tmptxt='('; + if (! empty($prod->customcode)) $tmptxt.=$langs->transnoentitiesnoconv("CustomCode").': '.$prod->customcode; + if (! empty($prod->customcode) && ! empty($prod->country_code)) $tmptxt.=' - '; + if (! empty($prod->country_code)) $tmptxt.=$langs->transnoentitiesnoconv("CountryOrigin").': '.getCountry($prod->country_code,0,$db,$langs,0); + $tmptxt.=')'; + $desc= dol_concatdesc($desc, $tmptxt); + } + } - $type = $prod->type; - } - else - { - $pu_ht = price2num($price_ht, 'MU'); + $type = $prod->type; + } + else + { + $pu_ht = price2num($price_ht, 'MU'); $pu_ttc = price2num(GETPOST('price_ttc'), 'MU'); $tva_npr = (preg_match('/\*/', $tva_tx)?1:0); $tva_tx = str_replace('*', '', $tva_tx); $label = (GETPOST('product_label')?GETPOST('product_label'):''); $desc = $product_desc; $type = GETPOST('type'); - } + } - // Margin - $fournprice=(GETPOST('fournprice')?GETPOST('fournprice'):''); + // Margin + $fournprice=(GETPOST('fournprice')?GETPOST('fournprice'):''); $buyingprice=(GETPOST('buying_price')?GETPOST('buying_price'):''); - // Local Taxes - $localtax1_tx= get_localtax($tva_tx, 1, $object->client); - $localtax2_tx= get_localtax($tva_tx, 2, $object->client); + // Local Taxes + $localtax1_tx= get_localtax($tva_tx, 1, $object->client); + $localtax2_tx= get_localtax($tva_tx, 2, $object->client); - $info_bits=0; - if ($tva_npr) $info_bits |= 0x01; + $info_bits=0; + if ($tva_npr) $info_bits |= 0x01; - if (! empty($price_min) && (price2num($pu_ht)*(1-price2num(GETPOST('remise_percent'))/100) < price2num($price_min))) - { - $mesg = $langs->trans("CantBeLessThanMinPrice",price2num($price_min,'MU').$langs->getCurrencySymbol($conf->currency)); + if (! empty($price_min) && (price2num($pu_ht)*(1-price2num(GETPOST('remise_percent'))/100) < price2num($price_min))) + { + $mesg = $langs->trans("CantBeLessThanMinPrice",price2num($price_min,'MU').$langs->getCurrencySymbol($conf->currency)); setEventMessage($mesg, 'errors'); - } - else - { - // Insert line - $result = $object->addline( - $id, - $desc, - $pu_ht, - GETPOST('qty'), - $tva_tx, - $localtax1_tx, - $localtax2_tx, - $idprod, - GETPOST('remise_percent'), - $date_start, - $date_end, - 0, - $info_bits, - '', - $price_base_type, - $pu_ttc, - $type, - -1, - $special_code, - '', - 0, - GETPOST('fk_parent_line'), - $fournprice, - $buyingprice, - $label - ); + } + else + { + // Insert line + $result = $object->addline( + $id, + $desc, + $pu_ht, + GETPOST('qty'), + $tva_tx, + $localtax1_tx, + $localtax2_tx, + $idprod, + GETPOST('remise_percent'), + $date_start, + $date_end, + 0, + $info_bits, + '', + $price_base_type, + $pu_ttc, + $type, + -1, + $special_code, + '', + 0, + GETPOST('fk_parent_line'), + $fournprice, + $buyingprice, + $label + ); - if ($result > 0) - { - if (empty($conf->global->MAIN_DISABLE_PDF_AUTOUPDATE)) - { - // Define output language - $outputlangs = $langs; - $newlang=GETPOST('lang_id','alpha'); - if (! empty($conf->global->MAIN_MULTILANGS) && empty($newlang)) $newlang=$object->client->default_lang; - if (! empty($newlang)) - { - $outputlangs = new Translate("",$conf); - $outputlangs->setDefaultLang($newlang); - } + if ($result > 0) + { + if (empty($conf->global->MAIN_DISABLE_PDF_AUTOUPDATE)) + { + // Define output language + $outputlangs = $langs; + $newlang=GETPOST('lang_id','alpha'); + if (! empty($conf->global->MAIN_MULTILANGS) && empty($newlang)) $newlang=$object->client->default_lang; + if (! empty($newlang)) + { + $outputlangs = new Translate("",$conf); + $outputlangs->setDefaultLang($newlang); + } - $ret=$object->fetch($id); // Reload to get new records - facture_pdf_create($db, $object, $object->modelpdf, $outputlangs, $hidedetails, $hidedesc, $hideref); - } + $ret=$object->fetch($id); // Reload to get new records + facture_pdf_create($db, $object, $object->modelpdf, $outputlangs, $hidedetails, $hidedesc, $hideref); + } - unset($_POST['qty']); - unset($_POST['type']); - unset($_POST['idprod']); - unset($_POST['remise_percent']); - unset($_POST['price_ht']); + unset($_POST['qty']); + unset($_POST['type']); + unset($_POST['idprod']); + unset($_POST['remise_percent']); + unset($_POST['price_ht']); unset($_POST['price_ttc']); unset($_POST['tva_tx']); unset($_POST['product_ref']); @@ -1236,99 +1279,99 @@ else if (($action == 'addline' || $action == 'addline_predef') && $user->rights- // old method unset($_POST['np_desc']); unset($_POST['dp_desc']); - } - else - { - setEventMessage($object->error, 'errors'); - } + } + else + { + setEventMessage($object->error, 'errors'); + } - $action=''; - } - } + $action=''; + } + } } else if ($action == 'updateligne' && $user->rights->facture->creer && $_POST['save'] == $langs->trans('Save')) { - if (! $object->fetch($id) > 0) dol_print_error($db); - $object->fetch_thirdparty(); + if (! $object->fetch($id) > 0) dol_print_error($db); + $object->fetch_thirdparty(); - // Clean parameters - $date_start=''; - $date_end=''; - $date_start=dol_mktime(GETPOST('date_starthour'), GETPOST('date_startmin'), GETPOST('date_startsec'), GETPOST('date_startmonth'), GETPOST('date_startday'), GETPOST('date_startyear')); - $date_end=dol_mktime(GETPOST('date_endhour'), GETPOST('date_endmin'), GETPOST('date_endsec'), GETPOST('date_endmonth'), GETPOST('date_endday'), GETPOST('date_endyear')); - $description=dol_htmlcleanlastbr(GETPOST('product_desc')); - $pu_ht=GETPOST('price_ht'); - $vat_rate=(GETPOST('tva_tx')?GETPOST('tva_tx'):0); + // Clean parameters + $date_start=''; + $date_end=''; + $date_start=dol_mktime(GETPOST('date_starthour'), GETPOST('date_startmin'), GETPOST('date_startsec'), GETPOST('date_startmonth'), GETPOST('date_startday'), GETPOST('date_startyear')); + $date_end=dol_mktime(GETPOST('date_endhour'), GETPOST('date_endmin'), GETPOST('date_endsec'), GETPOST('date_endmonth'), GETPOST('date_endday'), GETPOST('date_endyear')); + $description=dol_htmlcleanlastbr(GETPOST('product_desc')); + $pu_ht=GETPOST('price_ht'); + $vat_rate=(GETPOST('tva_tx')?GETPOST('tva_tx'):0); - // Define info_bits - $info_bits=0; - if (preg_match('/\*/', $vat_rate)) $info_bits |= 0x01; + // Define info_bits + $info_bits=0; + if (preg_match('/\*/', $vat_rate)) $info_bits |= 0x01; - // Define vat_rate - $vat_rate=str_replace('*','',$vat_rate); - $localtax1_rate=get_localtax($vat_rate,1,$object->client); - $localtax2_rate=get_localtax($vat_rate,2,$object->client); + // Define vat_rate + $vat_rate=str_replace('*','',$vat_rate); + $localtax1_rate=get_localtax($vat_rate,1,$object->client); + $localtax2_rate=get_localtax($vat_rate,2,$object->client); - // Add buying price + // Add buying price $fournprice=(GETPOST('fournprice')?GETPOST('fournprice'):''); $buyingprice=(GETPOST('buying_price')?GETPOST('buying_price'):''); - // Check minimum price + // Check minimum price $productid = GETPOST('productid', 'int'); - if (! empty($productid)) - { - $product = new Product($db); - $product->fetch($productid); + if (! empty($productid)) + { + $product = new Product($db); + $product->fetch($productid); - $type=$product->type; + $type=$product->type; - $price_min = $product->price_min; - if (! empty($conf->global->PRODUIT_MULTIPRICES) && ! empty($object->client->price_level)) - $price_min = $product->multiprices_min[$object->client->price_level]; + $price_min = $product->price_min; + if (! empty($conf->global->PRODUIT_MULTIPRICES) && ! empty($object->client->price_level)) + $price_min = $product->multiprices_min[$object->client->price_level]; - $label = ((GETPOST('update_label') && GETPOST('product_label')) ? GETPOST('product_label'):''); + $label = ((GETPOST('update_label') && GETPOST('product_label')) ? GETPOST('product_label'):''); - if ($price_min && (price2num($pu_ht)*(1-price2num(GETPOST('remise_percent'))/100) < price2num($price_min))) - { - setEventMessage($langs->trans("CantBeLessThanMinPrice", price2num($price_min,'MU')).$langs->getCurrencySymbol($conf->currency), 'errors'); - $error++; - } - } - else - { - $type = GETPOST('type'); - $label = (GETPOST('product_label') ? GETPOST('product_label'):''); + if ($price_min && (price2num($pu_ht)*(1-price2num(GETPOST('remise_percent'))/100) < price2num($price_min))) + { + setEventMessage($langs->trans("CantBeLessThanMinPrice", price2num($price_min,'MU')).$langs->getCurrencySymbol($conf->currency), 'errors'); + $error++; + } + } + else + { + $type = GETPOST('type'); + $label = (GETPOST('product_label') ? GETPOST('product_label'):''); - // Check parameters - if (GETPOST('type') < 0) { - setEventMessage($langs->trans("ErrorFieldRequired",$langs->transnoentitiesnoconv("Type")), 'errors'); - $error++; - } - } + // Check parameters + if (GETPOST('type') < 0) { + setEventMessage($langs->trans("ErrorFieldRequired",$langs->transnoentitiesnoconv("Type")), 'errors'); + $error++; + } + } // Update line if (! $error) { $result = $object->updateline( - GETPOST('lineid'), - $description, - $pu_ht, - GETPOST('qty'), - GETPOST('remise_percent'), - $date_start, - $date_end, - $vat_rate, - $localtax1_rate, - $localtax2_rate, - 'HT', - $info_bits, - $type, - GETPOST('fk_parent_line'), - 0, - $fournprice, - $buyingprice, - $label + GETPOST('lineid'), + $description, + $pu_ht, + GETPOST('qty'), + GETPOST('remise_percent'), + $date_start, + $date_end, + $vat_rate, + $localtax1_rate, + $localtax2_rate, + 'HT', + $info_bits, + $type, + GETPOST('fk_parent_line'), + 0, + $fournprice, + $buyingprice, + $label ); if ($result >= 0) @@ -1367,2247 +1410,2303 @@ else if ($action == 'updateligne' && $user->rights->facture->creer && $_POST['sa { setEventMessage($object->error, 'errors'); } - } + } } else if ($action == 'updateligne' && $user->rights->facture->creer && $_POST['cancel'] == $langs->trans('Cancel')) { - header('Location: '.$_SERVER["PHP_SELF"].'?facid='.$id); // Pour reaffichage de la fiche en cours d'edition - exit; + header('Location: '.$_SERVER["PHP_SELF"].'?facid='.$id); // Pour reaffichage de la fiche en cours d'edition + exit; } // Modify line position (up) else if ($action == 'up' && $user->rights->facture->creer) { - $object->fetch($id); - $object->fetch_thirdparty(); - $object->line_up($_GET['rowid']); + $object->fetch($id); + $object->fetch_thirdparty(); + $object->line_up($_GET['rowid']); - // Define output language - $outputlangs = $langs; - $newlang=''; - if ($conf->global->MAIN_MULTILANGS && empty($newlang) && ! empty($_REQUEST['lang_id'])) $newlang=$_REQUEST['lang_id']; - if ($conf->global->MAIN_MULTILANGS && empty($newlang)) $newlang=$object->client->default_lang; - if (! empty($newlang)) - { - $outputlangs = new Translate("",$conf); - $outputlangs->setDefaultLang($newlang); - } - if (empty($conf->global->MAIN_DISABLE_PDF_AUTOUPDATE)) facture_pdf_create($db, $object, $object->modelpdf, $outputlangs, $hidedetails, $hidedesc, $hideref); + // Define output language + $outputlangs = $langs; + $newlang=''; + if ($conf->global->MAIN_MULTILANGS && empty($newlang) && ! empty($_REQUEST['lang_id'])) $newlang=$_REQUEST['lang_id']; + if ($conf->global->MAIN_MULTILANGS && empty($newlang)) $newlang=$object->client->default_lang; + if (! empty($newlang)) + { + $outputlangs = new Translate("",$conf); + $outputlangs->setDefaultLang($newlang); + } + if (empty($conf->global->MAIN_DISABLE_PDF_AUTOUPDATE)) facture_pdf_create($db, $object, $object->modelpdf, $outputlangs, $hidedetails, $hidedesc, $hideref); - header('Location: '.$_SERVER["PHP_SELF"].'?facid='.$object->id.'#'.$_GET['rowid']); - exit; + header('Location: '.$_SERVER["PHP_SELF"].'?facid='.$object->id.'#'.$_GET['rowid']); + exit; } // Modify line position (down) else if ($action == 'down' && $user->rights->facture->creer) { - $object->fetch($id); - $object->fetch_thirdparty(); - $object->line_down($_GET['rowid']); + $object->fetch($id); + $object->fetch_thirdparty(); + $object->line_down($_GET['rowid']); - // Define output language - $outputlangs = $langs; - $newlang=''; - if ($conf->global->MAIN_MULTILANGS && empty($newlang) && ! empty($_REQUEST['lang_id'])) $newlang=$_REQUEST['lang_id']; - if ($conf->global->MAIN_MULTILANGS && empty($newlang)) $newlang=$object->client->default_lang; - if (! empty($newlang)) - { - $outputlangs = new Translate("",$conf); - $outputlangs->setDefaultLang($newlang); - } - if (empty($conf->global->MAIN_DISABLE_PDF_AUTOUPDATE)) facture_pdf_create($db, $object, $object->modelpdf, $outputlangs, $hidedetails, $hidedesc, $hideref); + // Define output language + $outputlangs = $langs; + $newlang=''; + if ($conf->global->MAIN_MULTILANGS && empty($newlang) && ! empty($_REQUEST['lang_id'])) $newlang=$_REQUEST['lang_id']; + if ($conf->global->MAIN_MULTILANGS && empty($newlang)) $newlang=$object->client->default_lang; + if (! empty($newlang)) + { + $outputlangs = new Translate("",$conf); + $outputlangs->setDefaultLang($newlang); + } + if (empty($conf->global->MAIN_DISABLE_PDF_AUTOUPDATE)) facture_pdf_create($db, $object, $object->modelpdf, $outputlangs, $hidedetails, $hidedesc, $hideref); - header('Location: '.$_SERVER["PHP_SELF"].'?facid='.$object->id.'#'.$_GET['rowid']); - exit; + header('Location: '.$_SERVER["PHP_SELF"].'?facid='.$object->id.'#'.$_GET['rowid']); + exit; } /* * Add file in email form - */ +*/ if (GETPOST('addfile')) { - require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php'; + require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php'; - // Set tmp user directory - $vardir=$conf->user->dir_output."/".$user->id; - $upload_dir_tmp = $vardir.'/temp'; + // Set tmp user directory + $vardir=$conf->user->dir_output."/".$user->id; + $upload_dir_tmp = $vardir.'/temp'; - dol_add_file_process($upload_dir_tmp,0,0); - $action='presend'; + dol_add_file_process($upload_dir_tmp,0,0); + $action='presend'; } /* * Remove file in email form - */ +*/ if (! empty($_POST['removedfile'])) { - require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php'; + require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php'; - // Set tmp user directory - $vardir=$conf->user->dir_output."/".$user->id; - $upload_dir_tmp = $vardir.'/temp'; + // Set tmp user directory + $vardir=$conf->user->dir_output."/".$user->id; + $upload_dir_tmp = $vardir.'/temp'; // TODO Delete only files that was uploaded from email form - dol_remove_file_process($_POST['removedfile'],0); - $action='presend'; + dol_remove_file_process($_POST['removedfile'],0); + $action='presend'; } /* * Send mail - */ +*/ if (($action == 'send' || $action == 'relance') && ! $_POST['addfile'] && ! $_POST['removedfile'] && ! $_POST['cancel']) { - $langs->load('mails'); + $langs->load('mails'); - $actiontypecode='';$subject='';$actionmsg='';$actionmsg2=''; + $actiontypecode='';$subject='';$actionmsg='';$actionmsg2=''; - $result=$object->fetch($id); - $result=$object->fetch_thirdparty(); + $result=$object->fetch($id); + $result=$object->fetch_thirdparty(); - if ($result > 0) - { -// $ref = dol_sanitizeFileName($object->ref); -// $file = $conf->facture->dir_output . '/' . $ref . '/' . $ref . '.pdf'; - -// if (is_readable($file)) -// { - if ($_POST['sendto']) - { - // Le destinataire a ete fourni via le champ libre - $sendto = $_POST['sendto']; - $sendtoid = 0; - } - elseif ($_POST['receiver'] != '-1') - { - // Recipient was provided from combo list - if ($_POST['receiver'] == 'thirdparty') // Id of third party - { - $sendto = $object->client->email; - $sendtoid = 0; - } - else // Id du contact - { - $sendto = $object->client->contact_get_property($_POST['receiver'],'email'); - $sendtoid = $_POST['receiver']; - } - } - - if (dol_strlen($sendto)) - { - $langs->load("commercial"); - - $from = $_POST['fromname'] . ' <' . $_POST['frommail'] .'>'; - $replyto = $_POST['replytoname']. ' <' . $_POST['replytomail'].'>'; - $message = $_POST['message']; - $sendtocc = $_POST['sendtocc']; - $deliveryreceipt = $_POST['deliveryreceipt']; - - if ($action == 'send') - { - if (dol_strlen($_POST['subject'])) $subject = $_POST['subject']; - else $subject = $langs->transnoentities('Bill').' '.$object->ref; - $actiontypecode='AC_FAC'; - $actionmsg=$langs->transnoentities('MailSentBy').' '.$from.' '.$langs->transnoentities('To').' '.$sendto.".\n"; - if ($message) - { - $actionmsg.=$langs->transnoentities('MailTopic').": ".$subject."\n"; - $actionmsg.=$langs->transnoentities('TextUsedInTheMessageBody').":\n"; - $actionmsg.=$message; - } - //$actionmsg2=$langs->transnoentities('Action'.$actiontypecode); - } - if ($action == 'relance') - { - if (dol_strlen($_POST['subject'])) $subject = $_POST['subject']; - else $subject = $langs->transnoentities('Relance facture '.$object->ref); - $actiontypecode='AC_FAC'; - $actionmsg=$langs->transnoentities('MailSentBy').' '.$from.' '.$langs->transnoentities('To').' '.$sendto.".\n"; - if ($message) { - $actionmsg.=$langs->transnoentities('MailTopic').": ".$subject."\n"; - $actionmsg.=$langs->transnoentities('TextUsedInTheMessageBody').":\n"; - $actionmsg.=$message; - } - //$actionmsg2=$langs->transnoentities('Action'.$actiontypecode); - } - - // Create form object - include_once DOL_DOCUMENT_ROOT.'/core/class/html.formmail.class.php'; - $formmail = new FormMail($db); - - $attachedfiles=$formmail->get_attached_files(); - $filepath = $attachedfiles['paths']; - $filename = $attachedfiles['names']; - $mimetype = $attachedfiles['mimes']; - - // Send mail - require_once DOL_DOCUMENT_ROOT.'/core/class/CMailFile.class.php'; - $mailfile = new CMailFile($subject,$sendto,$from,$message,$filepath,$mimetype,$filename,$sendtocc,'',$deliveryreceipt,-1); - if ($mailfile->error) - { - $mesgs[]='
'.$mailfile->error.'
'; - } - else - { - $result=$mailfile->sendfile(); - if ($result) - { - $error=0; - - // Initialisation donnees - $object->sendtoid = $sendtoid; - $object->actiontypecode = $actiontypecode; - $object->actionmsg = $actionmsg; // Long text - $object->actionmsg2 = $actionmsg2; // Short text - $object->fk_element = $object->id; - $object->elementtype = $object->element; - - // Appel des triggers - include_once DOL_DOCUMENT_ROOT . '/core/class/interfaces.class.php'; - $interface=new Interfaces($db); - $result=$interface->run_triggers('BILL_SENTBYMAIL',$object,$user,$langs,$conf); - if ($result < 0) { $error++; $this->errors=$interface->errors; } - // Fin appel triggers - - if ($error) - { - dol_print_error($db); - } - else - { - // Redirect here - // This avoid sending mail twice if going out and then back to page - $mesg=$langs->trans('MailSuccessfulySent',$mailfile->getValidAddress($from,2),$mailfile->getValidAddress($sendto,2)); - setEventMessage($mesg); - header('Location: '.$_SERVER["PHP_SELF"].'?facid='.$object->id); - exit; - } - } - else - { - $langs->load("other"); - $mesg='
'; - if ($mailfile->error) - { - $mesg.=$langs->trans('ErrorFailedToSendMail',$from,$sendto); - $mesg.='
'.$mailfile->error; - } - else - { - $mesg.='No mail sent. Feature is disabled by option MAIN_DISABLE_ALL_MAILS'; - } - $mesg.='
'; - $mesgs[]=$mesg; - } - } -/* } - else - { - $langs->load("other"); - $mesgs[]='
'.$langs->trans('ErrorMailRecipientIsEmpty').'
'; - dol_syslog('Recipient email is empty'); - }*/ - } - else - { - $langs->load("errors"); - $mesgs[]='
'.$langs->trans('ErrorCantReadFile',$file).'
'; - dol_syslog('Failed to read file: '.$file); - } - } - else - { - $langs->load("other"); - $mesgs[]='
'.$langs->trans('ErrorFailedToReadEntity',$langs->trans("Invoice")).'
'; - dol_syslog('Impossible de lire les donnees de la facture. Le fichier facture n\'a peut-etre pas ete genere.'); - } - - $action = 'presend'; -} - -/* - * Generate document - */ -else if ($action == 'builddoc') // En get ou en post -{ - $object->fetch($id); - $object->fetch_thirdparty(); - - if (GETPOST('model')) $object->setDocModel($user, GETPOST('model')); - if (GETPOST('fk_bank')) $object->fk_bank=GETPOST('fk_bank'); - - // Define output language - $outputlangs = $langs; - $newlang=''; - if ($conf->global->MAIN_MULTILANGS && empty($newlang) && GETPOST('lang_id')) $newlang=GETPOST('lang_id'); - if ($conf->global->MAIN_MULTILANGS && empty($newlang)) $newlang=$object->client->default_lang; - if (! empty($newlang)) - { - $outputlangs = new Translate("",$conf); - $outputlangs->setDefaultLang($newlang); - } - $result=facture_pdf_create($db, $object, $object->modelpdf, $outputlangs, $hidedetails, $hidedesc, $hideref); - if ($result <= 0) - { - dol_print_error($db,$result); - exit; - } - else - { - header('Location: '.$_SERVER["PHP_SELF"].'?facid='.$object->id.(empty($conf->global->MAIN_JUMP_TAG)?'':'#builddoc')); - exit; - } -} - -// Remove file in doc form -else if ($action == 'remove_file') -{ - if ($object->fetch($id)) + if ($result > 0) { - require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php'; + // $ref = dol_sanitizeFileName($object->ref); + // $file = $conf->facture->dir_output . '/' . $ref . '/' . $ref . '.pdf'; - $object->fetch_thirdparty(); - - $langs->load("other"); - $upload_dir = $conf->facture->dir_output; - $file = $upload_dir . '/' . GETPOST('file'); - $ret=dol_delete_file($file,0,0,0,$object); - if ($ret) setEventMessage($langs->trans("FileWasRemoved", GETPOST('urlfile'))); - else setEventMessage($langs->trans("ErrorFailToDeleteFile", GETPOST('urlfile')), 'errors'); - $action=''; - } -} - -if (! empty($conf->global->MAIN_DISABLE_CONTACTS_TAB) && $user->rights->facture->creer) -{ - if ($action == 'addcontact') - { - $result = $object->fetch($id); - - if ($result > 0 && $id > 0) + // if (is_readable($file)) + // { + if ($_POST['sendto']) { - $contactid = (GETPOST('userid') ? GETPOST('userid') : GETPOST('contactid')); - $result = $object->add_contact($contactid, $_POST["type"], $_POST["source"]); + // Le destinataire a ete fourni via le champ libre + $sendto = $_POST['sendto']; + $sendtoid = 0; } - - if ($result >= 0) + elseif ($_POST['receiver'] != '-1') { - header("Location: ".$_SERVER['PHP_SELF']."?id=".$object->id); - exit; - } - else - { - if ($object->error == 'DB_ERROR_RECORD_ALREADY_EXISTS') + // Recipient was provided from combo list + if ($_POST['receiver'] == 'thirdparty') // Id of third party { - $langs->load("errors"); - $mesgs[] = '
'.$langs->trans("ErrorThisContactIsAlreadyDefinedAsThisType").'
'; + $sendto = $object->client->email; + $sendtoid = 0; + } + else // Id du contact + { + $sendto = $object->client->contact_get_property($_POST['receiver'],'email'); + $sendtoid = $_POST['receiver']; + } + } + + if (dol_strlen($sendto)) + { + $langs->load("commercial"); + + $from = $_POST['fromname'] . ' <' . $_POST['frommail'] .'>'; + $replyto = $_POST['replytoname']. ' <' . $_POST['replytomail'].'>'; + $message = $_POST['message']; + $sendtocc = $_POST['sendtocc']; + $deliveryreceipt = $_POST['deliveryreceipt']; + + if ($action == 'send') + { + if (dol_strlen($_POST['subject'])) $subject = $_POST['subject']; + else $subject = $langs->transnoentities('Bill').' '.$object->ref; + $actiontypecode='AC_FAC'; + $actionmsg=$langs->transnoentities('MailSentBy').' '.$from.' '.$langs->transnoentities('To').' '.$sendto.".\n"; + if ($message) + { + $actionmsg.=$langs->transnoentities('MailTopic').": ".$subject."\n"; + $actionmsg.=$langs->transnoentities('TextUsedInTheMessageBody').":\n"; + $actionmsg.=$message; + } + //$actionmsg2=$langs->transnoentities('Action'.$actiontypecode); + } + if ($action == 'relance') + { + if (dol_strlen($_POST['subject'])) $subject = $_POST['subject']; + else $subject = $langs->transnoentities('Relance facture '.$object->ref); + $actiontypecode='AC_FAC'; + $actionmsg=$langs->transnoentities('MailSentBy').' '.$from.' '.$langs->transnoentities('To').' '.$sendto.".\n"; + if ($message) { + $actionmsg.=$langs->transnoentities('MailTopic').": ".$subject."\n"; + $actionmsg.=$langs->transnoentities('TextUsedInTheMessageBody').":\n"; + $actionmsg.=$message; + } + //$actionmsg2=$langs->transnoentities('Action'.$actiontypecode); + } + + // Create form object + include_once DOL_DOCUMENT_ROOT.'/core/class/html.formmail.class.php'; + $formmail = new FormMail($db); + + $attachedfiles=$formmail->get_attached_files(); + $filepath = $attachedfiles['paths']; + $filename = $attachedfiles['names']; + $mimetype = $attachedfiles['mimes']; + + // Send mail + require_once DOL_DOCUMENT_ROOT.'/core/class/CMailFile.class.php'; + $mailfile = new CMailFile($subject,$sendto,$from,$message,$filepath,$mimetype,$filename,$sendtocc,'',$deliveryreceipt,-1); + if ($mailfile->error) + { + $mesgs[]='
'.$mailfile->error.'
'; } else { - $mesgs[] = '
'.$object->error.'
'; + $result=$mailfile->sendfile(); + if ($result) + { + $error=0; + + // Initialisation donnees + $object->sendtoid = $sendtoid; + $object->actiontypecode = $actiontypecode; + $object->actionmsg = $actionmsg; // Long text + $object->actionmsg2 = $actionmsg2; // Short text + $object->fk_element = $object->id; + $object->elementtype = $object->element; + + // Appel des triggers + include_once DOL_DOCUMENT_ROOT . '/core/class/interfaces.class.php'; + $interface=new Interfaces($db); + $result=$interface->run_triggers('BILL_SENTBYMAIL',$object,$user,$langs,$conf); + if ($result < 0) { + $error++; $this->errors=$interface->errors; + } + // Fin appel triggers + + if ($error) + { + dol_print_error($db); + } + else + { + // Redirect here + // This avoid sending mail twice if going out and then back to page + $mesg=$langs->trans('MailSuccessfulySent',$mailfile->getValidAddress($from,2),$mailfile->getValidAddress($sendto,2)); + setEventMessage($mesg); + header('Location: '.$_SERVER["PHP_SELF"].'?facid='.$object->id); + exit; + } + } + else + { + $langs->load("other"); + $mesg='
'; + if ($mailfile->error) + { + $mesg.=$langs->trans('ErrorFailedToSendMail',$from,$sendto); + $mesg.='
'.$mailfile->error; + } + else + { + $mesg.='No mail sent. Feature is disabled by option MAIN_DISABLE_ALL_MAILS'; + } + $mesg.='
'; + $mesgs[]=$mesg; + } } + /* } + else + { + $langs->load("other"); + $mesgs[]='
'.$langs->trans('ErrorMailRecipientIsEmpty').'
'; + dol_syslog('Recipient email is empty'); + }*/ + } + else + { + $langs->load("errors"); + $mesgs[]='
'.$langs->trans('ErrorCantReadFile',$file).'
'; + dol_syslog('Failed to read file: '.$file); + } + } + else + { + $langs->load("other"); + $mesgs[]='
'.$langs->trans('ErrorFailedToReadEntity',$langs->trans("Invoice")).'
'; + dol_syslog('Impossible de lire les donnees de la facture. Le fichier facture n\'a peut-etre pas ete genere.'); + } + + $action = 'presend'; + } + + /* + * Generate document + */ + else if ($action == 'builddoc') // En get ou en post + { + $object->fetch($id); + $object->fetch_thirdparty(); + + if (GETPOST('model')) $object->setDocModel($user, GETPOST('model')); + if (GETPOST('fk_bank')) $object->fk_bank=GETPOST('fk_bank'); + + // Define output language + $outputlangs = $langs; + $newlang=''; + if ($conf->global->MAIN_MULTILANGS && empty($newlang) && GETPOST('lang_id')) $newlang=GETPOST('lang_id'); + if ($conf->global->MAIN_MULTILANGS && empty($newlang)) $newlang=$object->client->default_lang; + if (! empty($newlang)) + { + $outputlangs = new Translate("",$conf); + $outputlangs->setDefaultLang($newlang); + } + $result=facture_pdf_create($db, $object, $object->modelpdf, $outputlangs, $hidedetails, $hidedesc, $hideref); + if ($result <= 0) + { + dol_print_error($db,$result); + exit; + } + else + { + header('Location: '.$_SERVER["PHP_SELF"].'?facid='.$object->id.(empty($conf->global->MAIN_JUMP_TAG)?'':'#builddoc')); + exit; } } - // bascule du statut d'un contact - else if ($action == 'swapstatut') + // Remove file in doc form + else if ($action == 'remove_file') { if ($object->fetch($id)) { - $result=$object->swapContactStatus(GETPOST('ligne')); - } - else - { - dol_print_error($db); + require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php'; + + $object->fetch_thirdparty(); + + $langs->load("other"); + $upload_dir = $conf->facture->dir_output; + $file = $upload_dir . '/' . GETPOST('file'); + $ret=dol_delete_file($file,0,0,0,$object); + if ($ret) setEventMessage($langs->trans("FileWasRemoved", GETPOST('urlfile'))); + else setEventMessage($langs->trans("ErrorFailToDeleteFile", GETPOST('urlfile')), 'errors'); + $action=''; } } - // Efface un contact - else if ($action == 'deletecontact') + if (! empty($conf->global->MAIN_DISABLE_CONTACTS_TAB) && $user->rights->facture->creer) { - $object->fetch($id); - $result = $object->delete_contact($lineid); - - if ($result >= 0) + if ($action == 'addcontact') { - header("Location: ".$_SERVER['PHP_SELF']."?id=".$object->id); - exit; - } - else { - dol_print_error($db); - } - } -} + $result = $object->fetch($id); -if ($action == 'update_extras') -{ - // Fill array 'array_options' with data from add form - $extralabels=$extrafields->fetch_name_optionals_label('facture'); - $ret = $extrafields->setOptionalsFromPost($extralabels,$object); - - // 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('id'=>$object->id); - $reshook=$hookmanager->executeHooks('insertExtraFields',$parameters,$object,$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=$object->insertExtraFields(); - if ($result < 0) + if ($result > 0 && $id > 0) { - $error++; + $contactid = (GETPOST('userid') ? GETPOST('userid') : GETPOST('contactid')); + $result = $object->add_contact($contactid, $_POST["type"], $_POST["source"]); + } + + if ($result >= 0) + { + header("Location: ".$_SERVER['PHP_SELF']."?id=".$object->id); + exit; + } + else + { + if ($object->error == 'DB_ERROR_RECORD_ALREADY_EXISTS') + { + $langs->load("errors"); + $mesgs[] = '
'.$langs->trans("ErrorThisContactIsAlreadyDefinedAsThisType").'
'; + } + else + { + $mesgs[] = '
'.$object->error.'
'; + } + } + } + + // bascule du statut d'un contact + else if ($action == 'swapstatut') + { + if ($object->fetch($id)) + { + $result=$object->swapContactStatus(GETPOST('ligne')); + } + else + { + dol_print_error($db); + } + } + + // Efface un contact + else if ($action == 'deletecontact') + { + $object->fetch($id); + $result = $object->delete_contact($lineid); + + if ($result >= 0) + { + header("Location: ".$_SERVER['PHP_SELF']."?id=".$object->id); + exit; + } + else { + dol_print_error($db); } } } - else if ($reshook < 0) $error++; -} - - -/* - * View - */ - -$form = new Form($db); -$formother=new FormOther($db); -$formfile = new FormFile($db); -$bankaccountstatic=new Account($db); -$now=dol_now(); - -llxHeader('',$langs->trans('Bill'),'EN:Customers_Invoices|FR:Factures_Clients|ES:Facturas_a_clientes'); - - - -/********************************************************************* - * - * Mode creation - * - **********************************************************************/ -if ($action == 'create') -{ - $facturestatic=new Facture($db); - $extralabels=$extrafields->fetch_name_optionals_label('facture'); - - print_fiche_titre($langs->trans('NewBill')); - - $soc = new Societe($db); - if ($socid>0) $res=$soc->fetch($socid); - - if (! empty($origin) && ! empty($originid)) - { - // Parse element/subelement (ex: project_task) - $element = $subelement = $origin; - if (preg_match('/^([^_]+)_([^_]+)/i', $origin, $regs)) - { - $element = $regs[1]; - $subelement = $regs[2]; - } - - if ($element == 'project') - { - $projectid=$originid; - } - else - { - // For compatibility - if ($element == 'order' || $element == 'commande') { $element = $subelement = 'commande'; } - if ($element == 'propal') { $element = 'comm/propal'; $subelement = 'propal'; } - if ($element == 'contract') { $element = $subelement = 'contrat'; } - if ($element == 'shipping') { $element = $subelement = 'expedition'; } - - dol_include_once('/'.$element.'/class/'.$subelement.'.class.php'); - - $classname = ucfirst($subelement); - $objectsrc = new $classname($db); - $objectsrc->fetch($originid); - if (empty($objectsrc->lines) && method_exists($objectsrc,'fetch_lines')) $objectsrc->fetch_lines(); - $objectsrc->fetch_thirdparty(); - - $projectid = (! empty($objectsrc->fk_project)?$objectsrc->fk_project:''); - $ref_client = (! empty($objectsrc->ref_client)?$objectsrc->ref_client:''); - $ref_int = (! empty($objectsrc->ref_int)?$objectsrc->ref_int:''); - - $soc = $objectsrc->thirdparty; - $cond_reglement_id = (! empty($objectsrc->cond_reglement_id)?$objectsrc->cond_reglement_id:(! empty($soc->cond_reglement_id)?$soc->cond_reglement_id:1)); - $mode_reglement_id = (! empty($objectsrc->mode_reglement_id)?$objectsrc->mode_reglement_id:(! empty($soc->mode_reglement_id)?$soc->mode_reglement_id:0)); - $remise_percent = (! empty($objectsrc->remise_percent)?$objectsrc->remise_percent:(! empty($soc->remise_percent)?$soc->remise_percent:0)); - $remise_absolue = (! empty($objectsrc->remise_absolue)?$objectsrc->remise_absolue:(! empty($soc->remise_absolue)?$soc->remise_absolue:0)); - $dateinvoice = empty($conf->global->MAIN_AUTOFILL_DATE)?-1:0; - } - } - else - { - $cond_reglement_id = $soc->cond_reglement_id; - $mode_reglement_id = $soc->mode_reglement_id; - $remise_percent = $soc->remise_percent; - $remise_absolue = 0; - $dateinvoice = empty($conf->global->MAIN_AUTOFILL_DATE)?-1:0; - } - $absolute_discount=$soc->getAvailableDiscounts(); - - - if (! empty($conf->use_javascript_ajax)) - { - print ajax_combobox('fac_replacement'); - print ajax_combobox('fac_avoir'); - } - - print '
'; - print ''; - print ''; - if ($soc->id > 0) - print '' ."\n"; - print ''; - print ''; - print ''; - print ''; - print ''; - - print ''; - - // Ref - print ''; - - // Factures predefinies - if (empty($origin) && empty($originid) && $socid>0) - { - $sql = 'SELECT r.rowid, r.titre, r.total_ttc'; - $sql.= ' FROM '.MAIN_DB_PREFIX.'facture_rec as r'; - $sql.= ' WHERE r.fk_soc = '.$soc->id; - - $resql=$db->query($sql); - if ($resql) - { - $num = $db->num_rows($resql); - $i = 0; - - if ($num > 0) - { - print ''; - } - $db->free($resql); - } - else - { - dol_print_error($db); - } - } - - // Tiers - print ''; - print ''; - if($soc->id > 0) - { - print ''; - } - else - { - print ''; - } - print ''."\n"; - - // Type de facture - $facids=$facturestatic->list_replacable_invoices($soc->id); - if ($facids < 0) - { - dol_print_error($db,$facturestatic); - exit; - } - $options=""; - foreach ($facids as $facparam) - { - $options.=''; - } - - $facids=$facturestatic->list_qualified_avoir_invoices($soc->id); - if ($facids < 0) - { - dol_print_error($db,$facturestatic); - exit; - } - $optionsav=""; - $newinvoice_static=new Facture($db); - foreach ($facids as $key => $valarray) - { - $newinvoice_static->id=$key; - $newinvoice_static->ref=$valarray['ref']; - $newinvoice_static->statut=$valarray['status']; - $newinvoice_static->type=$valarray['type']; - $newinvoice_static->paye=$valarray['paye']; - - $optionsav.=''; - } - - print ''; - - if ($socid > 0) - { - // Discounts for third party - print ''; - } - - // Date invoice - print ''; - - // Payment term - print ''; - - // Payment mode - print ''; - - // Project - if (! empty($conf->projet->enabled) && $socid>0) - { - $langs->load('projects'); - print ''; - } - - // Other attributes - $parameters=array('objectsrc' => $objectsrc, 'colspan' => ' colspan="3"'); - $reshook=$hookmanager->executeHooks('formObjectOptions',$parameters,$object,$action); // Note that $action and $object may have been modified by hook - if (empty($reshook) && ! empty($extrafields->attribute_label)) - { - print $object->showOptionals($extrafields,'edit'); - } - - // Modele PDF - print ''; - print '"; - - // Public note - print ''; - print ''; - print ''; - - // Private note - if (empty($user->societe_id)) - { - print ''; - print ''; - print ''; - } - - if (! empty($origin) && ! empty($originid) && is_object($objectsrc)) - { - // TODO for compatibility - if ($origin == 'contrat') - { - // Calcul contrat->price (HT), contrat->total (TTC), contrat->tva - $objectsrc->remise_absolue=$remise_absolue; - $objectsrc->remise_percent=$remise_percent; - $objectsrc->update_price(1,-1,1); - } - - print "\n"; - print "\n"; - print ''."\n"; - print ''."\n"; - print ''."\n"; - print ''; - print ''; - - $newclassname=$classname; - if ($newclassname == 'Propal') $newclassname = 'CommercialProposal'; - elseif ($newclassname == 'Commande') $newclassname = 'Order'; - - print ''; - print ''; - print '"; - if ($mysoc->localtax1_assuj=="1") //Localtax1 RE - { - print '"; - } - - if ($mysoc->localtax2_assuj=="1") //Localtax2 IRPF - { - print '"; - } - print '"; - } - else - { - // Show deprecated optional form to add product line here - if (! empty($conf->global->PRODUCT_SHOW_WHEN_CREATE)) - { - print ''; - } - } - - print "
'.$langs->trans('Ref').''.$langs->trans('Draft').'
'.$langs->trans('CreateFromRepeatableInvoice').''; - print '
'.$langs->trans('Customer').''; - print $soc->getNomUrl(1); - print ''; - print ''; - print $form->select_company('','socid','s.client = 1 OR s.client = 3',1); - print '
'.$langs->trans('Type').''; - print ''."\n"; - - // Standard invoice - print ''."\n"; - - // Proforma - if (! empty($conf->global->FACTURE_USE_PROFORMAT)) - { - print ''."\n"; - } - - if (empty($origin)) - { - // Deposit - print ''."\n"; - } - - if ($socid > 0) + if ($action == 'update_extras') { - // Replacement - print ''."\n"; - } - - if (empty($origin) && $socid > 0) - { - // Credit note - print ''."\n"; - } - - print '
'; - print ''; - print ''; - $desc=$form->textwithpicto($langs->trans("InvoiceStandardAsk"),$langs->transnoentities("InvoiceStandardDesc"),1); - print $desc; - print '
'; - print ''; - print ''; - $desc=$form->textwithpicto($langs->trans("InvoiceProForma"),$langs->transnoentities("InvoiceProFormaDesc"),1); - print $desc; - print '
'; - print ''; - print ''; - $desc=$form->textwithpicto($langs->trans("InvoiceDeposit"),$langs->transnoentities("InvoiceDepositDesc"),1); - print $desc; - print '
'; - print ''; - print ''; - $text=$langs->trans("InvoiceReplacementAsk").' '; - $text.=''; - $desc=$form->textwithpicto($text,$langs->transnoentities("InvoiceReplacementDesc"),1); - print $desc; - print '
'; - print ''; - print ''; - $text=$langs->transnoentities("InvoiceAvoirAsk").' '; - // $text.=''; - $text.=''; - $desc=$form->textwithpicto($text,$langs->transnoentities("InvoiceAvoirDesc"),1); - print $desc; - print '
'; - print '
'.$langs->trans('Discounts').''; - if ($soc->remise_client) print $langs->trans("CompanyHasRelativeDiscount",''.$soc->remise_client.''); - else print $langs->trans("CompanyHasNoRelativeDiscount"); - print ' ('.$langs->trans("EditRelativeDiscount").')'; - print '. '; - print '
'; - if ($absolute_discount) print $langs->trans("CompanyHasAbsoluteDiscount",''.price($absolute_discount).'',$langs->trans("Currency".$conf->currency)); - else print $langs->trans("CompanyHasNoAbsoluteDiscount"); - print ' ('.$langs->trans("EditGlobalDiscounts").')'; - print '.'; - print '
'.$langs->trans('Date').''; - $form->select_date($dateinvoice,'','','','',"add",1,1); - print '
'.$langs->trans('PaymentConditionsShort').''; - $form->select_conditions_paiements(isset($_POST['cond_reglement_id'])?$_POST['cond_reglement_id']:$cond_reglement_id,'cond_reglement_id'); - print '
'.$langs->trans('PaymentMode').''; - $form->select_types_paiements(isset($_POST['mode_reglement_id'])?$_POST['mode_reglement_id']:$mode_reglement_id,'mode_reglement_id'); - print '
'.$langs->trans('Project').''; - select_projects($soc->id, $projectid, 'projectid'); - print '
'.$langs->trans('Model').''; - include_once DOL_DOCUMENT_ROOT.'/core/modules/facture/modules_facture.php'; - $liste=ModelePDFFactures::liste_modeles($db); - print $form->selectarray('model',$liste,$conf->global->FACTURE_ADDON_PDF); - print "
'.$langs->trans('NotePublic').''; - $note_public=''; - if (is_object($objectsrc)) // Take value from source object - { - $note_public=$objectsrc->note_public; - } - $doleditor = new DolEditor('note_public', $note_public, '', 80, 'dolibarr_notes', 'In', 0, false, true, ROWS_3, 70); - print $doleditor->Create(1); - - //print '
'.$langs->trans('NotePrivate').''; - $note_private=''; - if (! empty($origin) && ! empty($originid) && is_object($objectsrc)) // Take value from source object - { - $note_private=$objectsrc->note_private; - } - $doleditor = new DolEditor('note_private', $note_private, '', 80, 'dolibarr_notes', 'In', 0, false, true, ROWS_3, 70); - print $doleditor->Create(1); - //print '
'.$langs->trans($newclassname).''.$objectsrc->getNomUrl(1).'
'.$langs->trans('TotalHT').''.price($objectsrc->total_ht).'
'.$langs->trans('TotalVAT').''.price($objectsrc->total_tva)."
'.$langs->transcountry("AmountLT1",$mysoc->country_code).''.price($objectsrc->total_localtax1)."
'.$langs->transcountry("AmountLT2",$mysoc->country_code).''.price($objectsrc->total_localtax2)."
'.$langs->trans('TotalTTC').''.price($objectsrc->total_ttc)."
'; - - // Zone de choix des produits predefinis a la creation - print ''; - print ''; - print ''; - print ''; - print ''; - print ''; - if (! empty($conf->service->enabled)) - { - print ''; - } - print ''; - for ($i = 1 ; $i <= $NBLINES ; $i++) - { - print ''; - print ''; - print ''; - print ''; - print ''; - // Si le module service est actif, on propose des dates de debut et fin a la ligne - if (! empty($conf->service->enabled)) - { - print ''; - } - print "\n"; - } - - print '
'.$langs->trans('ProductsAndServices').''.$langs->trans('Qty').''.$langs->trans('ReductionShort').'     '.$langs->trans('ServiceLimitedDuration').'
'; - // multiprix - if (! empty($conf->global->PRODUIT_MULTIPRICES)) - $form->select_produits('','idprod'.$i,'',$conf->product->limit_size,$soc->price_level); - else - $form->select_produits('','idprod'.$i,'',$conf->product->limit_size); - print '% '; - print ''; - print ''; - print '
'; - print $langs->trans('From').' '; - print ''; - print $form->select_date('','date_start'.$i,$usehm,$usehm,1,"add"); - print '
'; - print $langs->trans('to').' '; - print ''; - print $form->select_date('','date_end'.$i,$usehm,$usehm,1,"add"); - print '
'; - print '
'; - print '
\n"; - - // Button "Create Draft" - print '
'; - - print "
\n"; - - // Show origin lines - if (! empty($origin) && ! empty($originid) && is_object($objectsrc)) - { - print '
'; - - $title=$langs->trans('ProductsAndServices'); - print_titre($title); - - print ''; - - $objectsrc->printOriginLinesList(); - - print '
'; - } - -} -else if ($id > 0 || ! empty($ref)) -{ - /* - * Show object in view mode - */ - - $result=$object->fetch($id,$ref); - - // fetch optionals attributes and labels - $extralabels=$extrafields->fetch_name_optionals_label('facture'); - - if ($result > 0) - { - if ($user->societe_id>0 && $user->societe_id!=$object->socid) accessforbidden('',0); - - $result=$object->fetch_thirdparty(); - - $soc = new Societe($db); - $soc->fetch($object->socid); - $selleruserevenustamp=$mysoc->useRevenueStamp(); - - $totalpaye = $object->getSommePaiement(); - $totalcreditnotes = $object->getSumCreditNotesUsed(); - $totaldeposits = $object->getSumDepositsUsed(); - //print "totalpaye=".$totalpaye." totalcreditnotes=".$totalcreditnotes." totaldeposts=".$totaldeposits." selleruserrevenuestamp=".$selleruserevenustamp; - - // We can also use bcadd to avoid pb with floating points - // For example print 239.2 - 229.3 - 9.9; does not return 0. - //$resteapayer=bcadd($object->total_ttc,$totalpaye,$conf->global->MAIN_MAX_DECIMALS_TOT); - //$resteapayer=bcadd($resteapayer,$totalavoir,$conf->global->MAIN_MAX_DECIMALS_TOT); - $resteapayer = price2num($object->total_ttc - $totalpaye - $totalcreditnotes - $totaldeposits,'MT'); - - if ($object->paye) $resteapayer=0; - $resteapayeraffiche=$resteapayer; - - if (! empty($conf->global->FACTURE_DEPOSITS_ARE_JUST_PAYMENTS)) - { - $filterabsolutediscount="fk_facture_source IS NULL"; // If we want deposit to be substracted to payments only and not to total of final invoice - $filtercreditnote="fk_facture_source IS NOT NULL"; // If we want deposit to be substracted to payments only and not to total of final invoice - } - else - { - $filterabsolutediscount="fk_facture_source IS NULL OR (fk_facture_source IS NOT NULL AND description='(DEPOSIT)')"; - $filtercreditnote="fk_facture_source IS NOT NULL AND description <> '(DEPOSIT)'"; - } - - $absolute_discount=$soc->getAvailableDiscounts('',$filterabsolutediscount); - $absolute_creditnote=$soc->getAvailableDiscounts('',$filtercreditnote); - $absolute_discount=price2num($absolute_discount,'MT'); - $absolute_creditnote=price2num($absolute_creditnote,'MT'); - - $author = new User($db); - if ($object->user_author) - { - $author->fetch($object->user_author); - } - - $objectidnext=$object->getIdReplacingInvoice(); - - - $head = facture_prepare_head($object); - - dol_fiche_head($head, 'compta', $langs->trans('InvoiceCustomer'), 0, 'bill'); - - $formconfirm=''; - - // Confirmation de la conversion de l'avoir en reduc - if ($action == 'converttoreduc') - { - $text=$langs->trans('ConfirmConvertToReduc'); - $formconfirm=$form->formconfirm($_SERVER['PHP_SELF'].'?facid='.$object->id,$langs->trans('ConvertToReduc'),$text,'confirm_converttoreduc','',"yes",2); - } - - // 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); - } - - // Confirmation de la validation - if ($action == 'valid') - { - // on verifie si l'objet est en numerotation provisoire - $objectref = substr($object->ref, 1, 4); - if ($objectref == 'PROV') - { - $savdate=$object->date; - if (! empty($conf->global->FAC_FORCE_DATE_VALIDATION)) - { - $object->date=dol_now(); - $object->date_lim_reglement=$object->calculate_date_lim_reglement(); - } - $numref = $object->getNextNumRef($soc); - //$object->date=$savdate; - } - else - { - $numref = $object->ref; - } - - $text=$langs->trans('ConfirmValidateBill',$numref); - if (! empty($conf->notification->enabled)) - { - require_once DOL_DOCUMENT_ROOT .'/core/class/notify.class.php'; - $notify=new Notify($db); - $text.='
'; - $text.=$notify->confirmMessage('NOTIFY_VAL_FAC',$object->socid); - } - $formquestion=array(); - - if ($object->type != 3 && ! empty($conf->global->STOCK_CALCULATE_ON_BILL) && $object->hasProductsOrServices(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("SelectWarehouseForStockIncrease"):$langs->trans("SelectWarehouseForStockDecrease"); - $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))); - } - if ($object->type != 2 && $object->total_ttc < 0) // Can happen only if $conf->global->FACTURE_ENABLE_NEGATIVE is on - { - $text.='
'.img_warning().' '.$langs->trans("ErrorInvoiceOfThisTypeMustBePositive"); - } - $formconfirm=$form->formconfirm($_SERVER["PHP_SELF"].'?facid='.$object->id,$langs->trans('ValidateBill'),$text,'confirm_valid',$formquestion,(($object->type != 2 && $object->total_ttc < 0)?"no":"yes"),($conf->notification->enabled?0:2)); - } - - // Confirm back to draft status - if ($action == 'modif') - { - $text=$langs->trans('ConfirmUnvalidateBill',$object->ref); - $formquestion=array(); - if ($object->type != 3 && ! empty($conf->global->STOCK_CALCULATE_ON_BILL) && $object->hasProductsOrServices(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('UnvalidateBill'),$text,'confirm_modif',$formquestion,"yes",1); - } - - // Confirmation du classement paye - if ($action == 'paid' && $resteapayer <= 0) - { - $formconfirm=$form->formconfirm($_SERVER["PHP_SELF"].'?facid='.$object->id,$langs->trans('ClassifyPaid'),$langs->trans('ConfirmClassifyPaidBill',$object->ref),'confirm_paid','',"yes",1); - } - if ($action == 'paid' && $resteapayer > 0) - { - // Code - $i=0; - $close[$i]['code']='discount_vat';$i++; - $close[$i]['code']='badcustomer';$i++; - // Help - $i=0; - $close[$i]['label']=$langs->trans("HelpEscompte").'

'.$langs->trans("ConfirmClassifyPaidPartiallyReasonDiscountVatDesc");$i++; - $close[$i]['label']=$langs->trans("ConfirmClassifyPaidPartiallyReasonBadCustomerDesc");$i++; - // Texte - $i=0; - $close[$i]['reason']=$form->textwithpicto($langs->transnoentities("ConfirmClassifyPaidPartiallyReasonDiscountVat",$resteapayer,$langs->trans("Currency".$conf->currency)),$close[$i]['label'],1);$i++; - $close[$i]['reason']=$form->textwithpicto($langs->transnoentities("ConfirmClassifyPaidPartiallyReasonBadCustomer",$resteapayer,$langs->trans("Currency".$conf->currency)),$close[$i]['label'],1);$i++; - // arrayreasons[code]=reason - foreach($close as $key => $val) - { - $arrayreasons[$close[$key]['code']]=$close[$key]['reason']; - } - - // Cree un tableau formulaire - $formquestion=array( - 'text' => $langs->trans("ConfirmClassifyPaidPartiallyQuestion"), - array('type' => 'radio', 'name' => 'close_code', 'label' => $langs->trans("Reason"), 'values' => $arrayreasons), - array('type' => 'text', 'name' => 'close_note', 'label' => $langs->trans("Comment"), 'value' => '', 'size' => '100') - ); - // Paiement incomplet. On demande si motif = escompte ou autre - $formconfirm=$form->formconfirm($_SERVER["PHP_SELF"].'?facid='.$object->id,$langs->trans('ClassifyPaid'),$langs->trans('ConfirmClassifyPaidPartially',$object->ref),'confirm_paid_partially',$formquestion,"yes"); - } - - // Confirmation du classement abandonne - if ($action == 'canceled') - { - // S'il y a une facture de remplacement pas encore validee (etat brouillon), - // on ne permet pas de classer abandonner la facture. - if ($objectidnext) - { - $facturereplacement=new Facture($db); - $facturereplacement->fetch($objectidnext); - $statusreplacement=$facturereplacement->statut; - } - if ($objectidnext && $statusreplacement == 0) - { - print '
'.$langs->trans("ErrorCantCancelIfReplacementInvoiceNotValidated").'
'; - } - else - { - // Code - $close[1]['code']='badcustomer'; - $close[2]['code']='abandon'; - // Help - $close[1]['label']=$langs->trans("ConfirmClassifyPaidPartiallyReasonBadCustomerDesc"); - $close[2]['label']=$langs->trans("ConfirmClassifyAbandonReasonOtherDesc"); - // Texte - $close[1]['reason']=$form->textwithpicto($langs->transnoentities("ConfirmClassifyPaidPartiallyReasonBadCustomer",$object->ref),$close[1]['label'],1); - $close[2]['reason']=$form->textwithpicto($langs->transnoentities("ConfirmClassifyAbandonReasonOther"),$close[2]['label'],1); - // arrayreasons - $arrayreasons[$close[1]['code']]=$close[1]['reason']; - $arrayreasons[$close[2]['code']]=$close[2]['reason']; - - // Cree un tableau formulaire - $formquestion=array( - 'text' => $langs->trans("ConfirmCancelBillQuestion"), - array('type' => 'radio', 'name' => 'close_code', 'label' => $langs->trans("Reason"), 'values' => $arrayreasons), - array('type' => 'text', 'name' => 'close_note', 'label' => $langs->trans("Comment"), 'value' => '', 'size' => '100') - ); - - $formconfirm=$form->formconfirm($_SERVER['PHP_SELF'].'?facid='.$object->id,$langs->trans('CancelBill'),$langs->trans('ConfirmCancelBill',$object->ref),'confirm_canceled',$formquestion,"yes"); - } - } - - // Confirmation de la suppression d'une ligne produit - if ($action == 'ask_deleteline') - { - $formconfirm=$form->formconfirm($_SERVER["PHP_SELF"].'?facid='.$object->id.'&lineid='.$lineid, $langs->trans('DeleteProductLine'), $langs->trans('ConfirmDeleteProductLine'), 'confirm_deleteline', '', 'no', 1); - } - - // Clone confirmation - if ($action == 'clone') - { - // Create an array for form - $formquestion=array( - //'text' => $langs->trans("ConfirmClone"), - //array('type' => 'checkbox', 'name' => 'clone_content', 'label' => $langs->trans("CloneMainAttributes"), 'value' => 1) - ); - // Paiement incomplet. On demande si motif = escompte ou autre - $formconfirm=$form->formconfirm($_SERVER["PHP_SELF"].'?facid='.$object->id,$langs->trans('CloneInvoice'),$langs->trans('ConfirmCloneInvoice',$object->ref),'confirm_clone',$formquestion,'yes',1); - } - - if (! $formconfirm) - { - $parameters=array('lineid'=>$lineid); - $formconfirm=$hookmanager->executeHooks('formConfirm',$parameters,$object,$action); // Note that $action and $object may have been modified by hook - } - - // Print form confirm - print $formconfirm; - - - // Invoice content - - print ''; - - $linkback = ''.$langs->trans("BackToList").''; - - // Ref - print ''; - print ''; - - // Ref customer - print ''; - print ''; + + // Third party + print ''; + + // Type + print ''; + + // Relative and absolute discounts + $addrelativediscount=''.$langs->trans("EditRelativeDiscounts").''; + $addabsolutediscount=''.$langs->trans("EditGlobalDiscounts").''; + $addcreditnote=''.$langs->trans("AddCreditNote").''; + + print ''; + + // Date invoice + print ''; + + + /* + * List of payments + */ + + $sign=1; + if ($object->type == 2) $sign=-1; + + $nbrows=8; $nbcols=2; + if (! empty($conf->projet->enabled)) $nbrows++; + if (! empty($conf->banque->enabled)) $nbcols++; + if($mysoc->localtax1_assuj=="1") $nbrows++; + if($mysoc->localtax2_assuj=="1") $nbrows++; + if ($selleruserevenustamp) $nbrows++; + + print ''; + + // Conditions de reglement + print ''; + + // Date payment term + print ''; + + // Payment mode + print ''; + + // Amount + print ''; + print ''; + print ''; + print ''; + + // Amount Local Taxes + if ($mysoc->localtax1_assuj=="1" && $mysoc->useLocalTax(1)) //Localtax1 (example RE) + { + print ''; + print ''; + } + if ($mysoc->localtax2_assuj=="1" && $mysoc->useLocalTax(2)) //Localtax2 (example IRPF) + { + print ''; + print ''; + } + + // Revenue stamp + if ($selleruserevenustamp) // Test company use revenue stamp + { + print ''; + } + + // Total with tax + print ''; + + // Statut + print ''; + print ''; + + // Project + if (! empty($conf->projet->enabled)) + { + $langs->load('projects'); + print ''; + print ''; + print ''; + } + + // Other attributes + $res=$object->fetch_optionals($object->id,$extralabels); + $parameters=array('colspan' => ' colspan="2"'); + $reshook=$hookmanager->executeHooks('formObjectOptions',$parameters,$object,$action); // Note that $action and $object may have been modified by hook + if (empty($reshook) && ! empty($extrafields->attribute_label)) + { + + if ($action == 'edit_extras') + { + print ''; + print ''; + print ''; + print ''; + } + + foreach($extrafields->attribute_label as $key=>$label) + { + $value=(isset($_POST["options_".$key])?$_POST["options_".$key]:$object->array_options["options_".$key]); + if ($extrafields->attribute_type[$key] == 'separate') + { + print $extrafields->showSeparator($key); + } + else + { + print 'attribute_required[$key])) print ' class="fieldrequired"'; + print '>'.$label.''."\n"; + } + } + + if(count($extrafields->attribute_label) > 0) { + + if ($action == 'edit_extras' && $user->rights->facture->creer) + { + print ''; + + } + else { + if ($object->statut == 0 && $user->rights->facture->creer) + { + print ''; + } + } + } + } + + print '
'.$langs->trans('Ref').''; - $morehtmlref=''; - $discount=new DiscountAbsolute($db); - $result=$discount->fetch(0,$object->id); - if ($result > 0) - { - $morehtmlref=' ('.$langs->trans("CreditNoteConvertedIntoDiscount",$discount->getNomUrl(1,'discount')).')'; - } - if ($result < 0) - { - dol_print_error('',$discount->error); - } - print $form->showrefnav($object, 'ref', $linkback, 1, 'facnumber', 'ref', $morehtmlref); - print '
'; - print ''; - if ($action != 'refclient' && ! empty($object->brouillon)) print ''; - print '
'; - print $langs->trans('RefCustomer'); - print ''.img_edit($langs->trans('Modify')).'
'; - print '
'; - if ($user->rights->facture->creer && $action == 'refclient') + // Fill array 'array_options' with data from add form + $extralabels=$extrafields->fetch_name_optionals_label('facture'); + $ret = $extrafields->setOptionalsFromPost($extralabels,$object); + + // 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('id'=>$object->id); + $reshook=$hookmanager->executeHooks('insertExtraFields',$parameters,$object,$action); // Note that $action and $object may have been modified by some hooks + if (empty($reshook)) { - print '
'; - print ''; - print ''; - print ''; - print ' '; - print '
'; + if (empty($conf->global->MAIN_EXTRAFIELDS_DISABLED)) // For avoid conflicts if trigger used + { + $result=$object->insertExtraFields(); + if ($result < 0) + { + $error++; + } + } + } + else if ($reshook < 0) $error++; + + } + + + /* + * View + */ + + $form = new Form($db); + $formother=new FormOther($db); + $formfile = new FormFile($db); + $bankaccountstatic=new Account($db); + $now=dol_now(); + + llxHeader('',$langs->trans('Bill'),'EN:Customers_Invoices|FR:Factures_Clients|ES:Facturas_a_clientes'); + + + + /********************************************************************* + * + * Mode creation + * + **********************************************************************/ + if ($action == 'create') + { + $facturestatic=new Facture($db); + $extralabels=$extrafields->fetch_name_optionals_label('facture'); + + print_fiche_titre($langs->trans('NewBill')); + + $soc = new Societe($db); + if ($socid>0) $res=$soc->fetch($socid); + + if (! empty($origin) && ! empty($originid)) + { + // Parse element/subelement (ex: project_task) + $element = $subelement = $origin; + if (preg_match('/^([^_]+)_([^_]+)/i', $origin, $regs)) + { + $element = $regs[1]; + $subelement = $regs[2]; + } + + if ($element == 'project') + { + $projectid=$originid; + } + else + { + // For compatibility + if ($element == 'order' || $element == 'commande') { + $element = $subelement = 'commande'; + } + if ($element == 'propal') { + $element = 'comm/propal'; $subelement = 'propal'; + } + if ($element == 'contract') { + $element = $subelement = 'contrat'; + } + if ($element == 'shipping') { + $element = $subelement = 'expedition'; + } + + dol_include_once('/'.$element.'/class/'.$subelement.'.class.php'); + + $classname = ucfirst($subelement); + $objectsrc = new $classname($db); + $objectsrc->fetch($originid); + if (empty($objectsrc->lines) && method_exists($objectsrc,'fetch_lines')) $objectsrc->fetch_lines(); + $objectsrc->fetch_thirdparty(); + + $projectid = (! empty($objectsrc->fk_project)?$objectsrc->fk_project:''); + $ref_client = (! empty($objectsrc->ref_client)?$objectsrc->ref_client:''); + $ref_int = (! empty($objectsrc->ref_int)?$objectsrc->ref_int:''); + + $soc = $objectsrc->thirdparty; + $cond_reglement_id = (! empty($objectsrc->cond_reglement_id)?$objectsrc->cond_reglement_id:(! empty($soc->cond_reglement_id)?$soc->cond_reglement_id:1)); + $mode_reglement_id = (! empty($objectsrc->mode_reglement_id)?$objectsrc->mode_reglement_id:(! empty($soc->mode_reglement_id)?$soc->mode_reglement_id:0)); + $remise_percent = (! empty($objectsrc->remise_percent)?$objectsrc->remise_percent:(! empty($soc->remise_percent)?$soc->remise_percent:0)); + $remise_absolue = (! empty($objectsrc->remise_absolue)?$objectsrc->remise_absolue:(! empty($soc->remise_absolue)?$soc->remise_absolue:0)); + $dateinvoice = empty($conf->global->MAIN_AUTOFILL_DATE)?-1:0; + } } else { - print $object->ref_client; + $cond_reglement_id = $soc->cond_reglement_id; + $mode_reglement_id = $soc->mode_reglement_id; + $remise_percent = $soc->remise_percent; + $remise_absolue = 0; + $dateinvoice = empty($conf->global->MAIN_AUTOFILL_DATE)?-1:0; } + $absolute_discount=$soc->getAvailableDiscounts(); + + + if (! empty($conf->use_javascript_ajax)) + { + print ajax_combobox('fac_replacement'); + print ajax_combobox('fac_avoir'); + } + + print '
'; + print ''; + print ''; + if ($soc->id > 0) + print '' ."\n"; + print ''; + print ''; + print ''; + print ''; + print ''; + + print ''; + + // Ref + print ''; + + // Factures predefinies + if (empty($origin) && empty($originid) && $socid>0) + { + $sql = 'SELECT r.rowid, r.titre, r.total_ttc'; + $sql.= ' FROM '.MAIN_DB_PREFIX.'facture_rec as r'; + $sql.= ' WHERE r.fk_soc = '.$soc->id; + + $resql=$db->query($sql); + if ($resql) + { + $num = $db->num_rows($resql); + $i = 0; + + if ($num > 0) + { + print ''; + } + $db->free($resql); + } + else + { + dol_print_error($db); + } + } + + // Tiers + print ''; + print ''; + if($soc->id > 0) + { + print ''; + } + else + { + print ''; + } + print ''."\n"; + + // Type de facture + $facids=$facturestatic->list_replacable_invoices($soc->id); + if ($facids < 0) + { + dol_print_error($db,$facturestatic); + exit; + } + $options=""; + foreach ($facids as $facparam) + { + $options.=''; + } + + $facids=$facturestatic->list_qualified_avoir_invoices($soc->id); + if ($facids < 0) + { + dol_print_error($db,$facturestatic); + exit; + } + $optionsav=""; + $newinvoice_static=new Facture($db); + foreach ($facids as $key => $valarray) + { + $newinvoice_static->id=$key; + $newinvoice_static->ref=$valarray['ref']; + $newinvoice_static->statut=$valarray['status']; + $newinvoice_static->type=$valarray['type']; + $newinvoice_static->paye=$valarray['paye']; + + $optionsav.=''; + } + + print ''; - // Third party - print ''; - - // Type - print ''; - - // Relative and absolute discounts - $addrelativediscount=''.$langs->trans("EditRelativeDiscounts").''; - $addabsolutediscount=''.$langs->trans("EditGlobalDiscounts").''; - $addcreditnote=''.$langs->trans("AddCreditNote").''; - - print ''; - - // Date invoice - print ''; - - - /* - * List of payments - */ - - $sign=1; - if ($object->type == 2) $sign=-1; - - $nbrows=8; $nbcols=2; - if (! empty($conf->projet->enabled)) $nbrows++; - if (! empty($conf->banque->enabled)) $nbcols++; - if($mysoc->localtax1_assuj=="1") $nbrows++; - if($mysoc->localtax2_assuj=="1") $nbrows++; - if ($selleruserevenustamp) $nbrows++; - - print ''; } - print ''; + // Date invoice + print ''; - // Conditions de reglement - print ''; + // Payment term + print ''; - // Date payment term - print ''; + // Payment mode + print ''; - // Payment mode - print ''; + // Project + if (! empty($conf->projet->enabled) && $socid>0) + { + $langs->load('projects'); + print ''; + } - // Amount - print ''; - print ''; - print ''; - print ''; + // Other attributes + $parameters=array('objectsrc' => $objectsrc, 'colspan' => ' colspan="3"'); + $reshook=$hookmanager->executeHooks('formObjectOptions',$parameters,$object,$action); // Note that $action and $object may have been modified by hook + if (empty($reshook) && ! empty($extrafields->attribute_label)) + { + print $object->showOptionals($extrafields,'edit'); + } - // Amount Local Taxes - if ($mysoc->localtax1_assuj=="1" && $mysoc->useLocalTax(1)) //Localtax1 (example RE) - { - print ''; - print ''; - } - if ($mysoc->localtax2_assuj=="1" && $mysoc->useLocalTax(2)) //Localtax2 (example IRPF) - { - print ''; - print ''; - } + // Modele PDF + print ''; + print '"; - // Revenue stamp - if ($selleruserevenustamp) // Test company use revenue stamp - { - print ''; + print ''; + print ''; + + // Private note + if (empty($user->societe_id)) + { + print ''; + print ''; + print ''; + } + + if (! empty($origin) && ! empty($originid) && is_object($objectsrc)) + { + // TODO for compatibility + if ($origin == 'contrat') + { + // Calcul contrat->price (HT), contrat->total (TTC), contrat->tva + $objectsrc->remise_absolue=$remise_absolue; + $objectsrc->remise_percent=$remise_percent; + $objectsrc->update_price(1,-1,1); + } + + print "\n"; + print "\n"; + print ''."\n"; + print ''."\n"; + print ''."\n"; + print ''; + print ''; + + $newclassname=$classname; + if ($newclassname == 'Propal') $newclassname = 'CommercialProposal'; + elseif ($newclassname == 'Commande') $newclassname = 'Order'; + + print ''; + print ''; + print '"; + if ($mysoc->localtax1_assuj=="1") //Localtax1 RE + { + print '"; + } + + if ($mysoc->localtax2_assuj=="1") //Localtax2 IRPF + { + print '"; + } + print '"; + } + else + { + // Show deprecated optional form to add product line here + if (! empty($conf->global->PRODUCT_SHOW_WHEN_CREATE)) + { + print ''; + } + } + + print "
'.$langs->trans('Ref').''.$langs->trans('Draft').'
'.$langs->trans('CreateFromRepeatableInvoice').''; + print '
'.$langs->trans('Customer').''; + print $soc->getNomUrl(1); + print ''; + print ''; + print $form->select_company('','socid','s.client = 1 OR s.client = 3',1); + print '
'.$langs->trans('Type').''; + print ''."\n"; + + // Standard invoice + print ''."\n"; + + // Proforma + if (! empty($conf->global->FACTURE_USE_PROFORMAT)) + { + print ''."\n"; + } + + if (empty($origin)) + { + // Deposit + print ''."\n"; + } + + if ($socid > 0) + { + // Replacement + print ''."\n"; + } + + if (empty($origin) && $socid > 0) + { + // Credit note + print ''."\n"; + } + + print '
'; + print ''; + print ''; + $desc=$form->textwithpicto($langs->trans("InvoiceStandardAsk"),$langs->transnoentities("InvoiceStandardDesc"),1); + print $desc; + print '
'; + print ''; + print ''; + $desc=$form->textwithpicto($langs->trans("InvoiceProForma"),$langs->transnoentities("InvoiceProFormaDesc"),1); + print $desc; + print '
'; + print ''; + print ''; + $desc=$form->textwithpicto($langs->trans("InvoiceDeposit"),$langs->transnoentities("InvoiceDepositDesc"),1); + print $desc; + print '
'; + print ''; + print ''; + $text=$langs->trans("InvoiceReplacementAsk").' '; + $text.=''; + $desc=$form->textwithpicto($text,$langs->transnoentities("InvoiceReplacementDesc"),1); + print $desc; + print '
'; + print ''; + print ''; + $text=$langs->transnoentities("InvoiceAvoirAsk").' '; + // $text.=''; + $text.=''; + $desc=$form->textwithpicto($text,$langs->transnoentities("InvoiceAvoirDesc"),1); + print $desc; + print '
'; print '
'; - print ''; - print ''; - print ''; - print '
'.$langs->trans('Company').''; - if (! empty($conf->global->FACTURE_CHANGE_THIRDPARTY) && $action != 'editthirdparty' && $object->brouillon && $user->rights->facture->creer) - print 'id.'">'.img_edit($langs->trans('SetLinkToThirdParty'),1).'
'; - print '
'; - if ($action == 'editthirdparty') - { - $form->form_thirdparty($_SERVER['PHP_SELF'].'?facid='.$object->id,$object->socid,'socid'); - } - else - { - print '  '.$soc->getNomUrl(1,'compta'); - print '   ('.$langs->trans('OtherBills').')'; - } - print '
'.$langs->trans('Type').''; - print $object->getLibType(); - if ($object->type == 1) - { - $facreplaced=new Facture($db); - $facreplaced->fetch($object->fk_facture_source); - print ' ('.$langs->transnoentities("ReplaceInvoice",$facreplaced->getNomUrl(1)).')'; - } - if ($object->type == 2) - { - $facusing=new Facture($db); - $facusing->fetch($object->fk_facture_source); - print ' ('.$langs->transnoentities("CorrectInvoice",$facusing->getNomUrl(1)).')'; - } - - $facidavoir=$object->getListIdAvoirFromInvoice(); - if (count($facidavoir) > 0) - { - print ' ('.$langs->transnoentities("InvoiceHasAvoir"); - $i=0; - foreach($facidavoir as $id) - { - if ($i==0) print ' '; - else print ','; - $facavoir=new Facture($db); - $facavoir->fetch($id); - print $facavoir->getNomUrl(1); - } - print ')'; - } - if ($objectidnext > 0) - { - $facthatreplace=new Facture($db); - $facthatreplace->fetch($objectidnext); - print ' ('.$langs->transnoentities("ReplacedByInvoice",$facthatreplace->getNomUrl(1)).')'; - } - print '
'.$langs->trans('Discounts'); - print ''; - if ($soc->remise_client) print $langs->trans("CompanyHasRelativeDiscount",$soc->remise_client); - else print $langs->trans("CompanyHasNoRelativeDiscount"); - //print ' ('.$addrelativediscount.')'; - - if ($absolute_discount > 0) - { - print '. '; - if ($object->statut > 0 || $object->type == 2 || $object->type == 3) - { - if ($object->statut == 0) - { - print $langs->trans("CompanyHasAbsoluteDiscount",price($absolute_discount),$langs->transnoentities("Currency".$conf->currency)); - print '. '; - } - else - { - if ($object->statut < 1 || $object->type == 2 || $object->type == 3) - { - $text=$langs->trans("CompanyHasAbsoluteDiscount",price($absolute_discount),$langs->transnoentities("Currency".$conf->currency)); - print '
'.$text.'.
'; - } - else - { - $text=$langs->trans("CompanyHasAbsoluteDiscount",price($absolute_discount),$langs->transnoentities("Currency".$conf->currency)); - $text2=$langs->trans("AbsoluteDiscountUse"); - print $form->textwithpicto($text,$text2); - } - } - } - else - { - // Remise dispo de type remise fixe (not credit note) - print '
'; - $form->form_remise_dispo($_SERVER["PHP_SELF"].'?facid='.$object->id, GETPOST('discountid'), 'remise_id', $soc->id, $absolute_discount, $filterabsolutediscount, $resteapayer, ' ('.$addabsolutediscount.')'); - } - } - else - { - if ($absolute_creditnote > 0) // If not, link will be added later - { - if ($object->statut == 0 && $object->type != 2 && $object->type != 3) print ' ('.$addabsolutediscount.')
'; - else print '. '; - } - else print '. '; - } - if ($absolute_creditnote > 0) - { - // If validated, we show link "add credit note to payment" - if ($object->statut != 1 || $object->type == 2 || $object->type == 3) - { - if ($object->statut == 0 && $object->type != 3) - { - $text=$langs->trans("CompanyHasCreditNote",price($absolute_creditnote),$langs->transnoentities("Currency".$conf->currency)); - print $form->textwithpicto($text,$langs->trans("CreditNoteDepositUse")); - } - else - { - print $langs->trans("CompanyHasCreditNote",price($absolute_creditnote),$langs->transnoentities("Currency".$conf->currency)).'.'; - } - } - else - { - // Remise dispo de type avoir - if (! $absolute_discount) print '
'; - //$form->form_remise_dispo($_SERVER["PHP_SELF"].'?facid='.$object->id, 0, 'remise_id_for_payment', $soc->id, $absolute_creditnote, $filtercreditnote, $resteapayer); - $form->form_remise_dispo($_SERVER["PHP_SELF"].'?facid='.$object->id, 0, 'remise_id_for_payment', $soc->id, $absolute_creditnote, $filtercreditnote, 0); // We must allow credit not even if amount is higher - } - } - if (! $absolute_discount && ! $absolute_creditnote) - { - print $langs->trans("CompanyHasNoAbsoluteDiscount"); - if ($object->statut == 0 && $object->type != 2 && $object->type != 3) print ' ('.$addabsolutediscount.')
'; - else print '. '; - } - /*if ($object->statut == 0 && $object->type != 2 && $object->type != 3) - { - if (! $absolute_discount && ! $absolute_creditnote) print '
'; - //print '   -   '; - print $addabsolutediscount; - //print '   -   '.$addcreditnote; // We disbale link to credit note - }*/ - print '
'; - print ''; - if ($object->type != 2 && $action != 'editinvoicedate' && ! empty($object->brouillon) && $user->rights->facture->creer) print ''; - print '
'; - print $langs->trans('Date'); - print 'id.'">'.img_edit($langs->trans('SetDate'),1).'
'; - print '
'; - - if ($object->type != 2) - { - if ($action == 'editinvoicedate') - { - $form->form_date($_SERVER['PHP_SELF'].'?facid='.$object->id,$object->date,'invoicedate'); - } - else - { - print dol_print_date($object->date,'daytext'); - } - } - else - { - print dol_print_date($object->date,'daytext'); - } - print ''; - - print ''; - - // List of payments already done - print ''; - print ''; - print ''; - if (! empty($conf->banque->enabled)) print ''; - print ''; - print ''; - print ''; - - $var=true; - - // Payments already done (from payment on this invoice) - $sql = 'SELECT p.datep as dp, p.num_paiement, p.rowid, p.fk_bank,'; - $sql.= ' c.code as payment_code, c.libelle as payment_label,'; - $sql.= ' pf.amount,'; - $sql.= ' ba.rowid as baid, ba.ref, ba.label'; - $sql.= ' FROM '.MAIN_DB_PREFIX.'c_paiement as c, '.MAIN_DB_PREFIX.'paiement_facture as pf, '.MAIN_DB_PREFIX.'paiement as p'; - $sql.= ' LEFT JOIN '.MAIN_DB_PREFIX.'bank as b ON p.fk_bank = b.rowid'; - $sql.= ' LEFT JOIN '.MAIN_DB_PREFIX.'bank_account as ba ON b.fk_account = ba.rowid'; - $sql.= ' WHERE pf.fk_facture = '.$object->id.' AND p.fk_paiement = c.id AND pf.fk_paiement = p.rowid'; - $sql.= ' ORDER BY p.datep, p.tms'; - - $result = $db->query($sql); - if ($result) - { - $num = $db->num_rows($result); - $i = 0; - - //if ($object->type != 2) - //{ - if ($num > 0) - { - while ($i < $num) - { - $objp = $db->fetch_object($result); - $var=!$var; - print ''; - $label=($langs->trans("PaymentType".$objp->payment_code)!=("PaymentType".$objp->payment_code))?$langs->trans("PaymentType".$objp->payment_code):$objp->payment_label; - print ''; - if (! empty($conf->banque->enabled)) - { - $bankaccountstatic->id=$objp->baid; - $bankaccountstatic->ref=$objp->ref; - $bankaccountstatic->label=$objp->ref; - print ''; - } - print ''; - print ''; - print ''; - $i++; - } - } - else - { - print ''; - } - //} - $db->free($result); - } - else - { - dol_print_error($db); - } - - if ($object->type != 2) - { - // Total already paid - print ''; - - $resteapayeraffiche=$resteapayer; - - // Loop on each credit note or deposit amount applied - $creditnoteamount=0; - $depositamount=0; - $sql = "SELECT re.rowid, re.amount_ht, re.amount_tva, re.amount_ttc,"; - $sql.= " re.description, re.fk_facture_source"; - $sql.= " FROM ".MAIN_DB_PREFIX ."societe_remise_except as re"; - $sql.= " WHERE fk_facture = ".$object->id; - $resql=$db->query($sql); - if ($resql) - { - $num = $db->num_rows($resql); - $i = 0; - $invoice=new Facture($db); - while ($i < $num) - { - $obj = $db->fetch_object($resql); - $invoice->fetch($obj->fk_facture_source); - print ''; - print ''; - print ''; - $i++; - if ($invoice->type == 2) $creditnoteamount += $obj->amount_ttc; - if ($invoice->type == 3) $depositamount += $obj->amount_ttc; - } - } - else - { - dol_print_error($db); - } - - // Paye partiellement 'escompte' - if (($object->statut == 2 || $object->statut == 3) && $object->close_code == 'discount_vat') - { - print ''; - $resteapayeraffiche=0; - } - // Paye partiellement ou Abandon 'badcustomer' - if (($object->statut == 2 || $object->statut == 3) && $object->close_code == 'badcustomer') - { - print ''; - //$resteapayeraffiche=0; - } - // Paye partiellement ou Abandon 'product_returned' - if (($object->statut == 2 || $object->statut == 3) && $object->close_code == 'product_returned') - { - print ''; - $resteapayeraffiche=0; - } - // Paye partiellement ou Abandon 'abandon' - if (($object->statut == 2 || $object->statut == 3) && $object->close_code == 'abandon') - { - print ''; - $resteapayeraffiche=0; - } - - // Billed - print ''; - - // Remainder to pay - print ''; - print ''; - print ''; - } - else // Credit note - { - // Total already paid back - print ''; - - // Billed - print ''; - - // Remainder to pay back - print ''; - print ''; - print ''; - - // Sold credit note - //print ''; - //print ''; - } - - print '
'.($object->type == 2 ? $langs->trans("PaymentsBack") : $langs->trans('Payments')).''.$langs->trans('Type').''.$langs->trans('BankAccount').''.$langs->trans('Amount').' 
'; - print ''.img_object($langs->trans('ShowPayment'),'payment').' '; - print dol_print_date($db->jdate($objp->dp),'day').''.$label.' '.$objp->num_paiement.''; - if ($bankaccountstatic->id) print $bankaccountstatic->getNomUrl(1,'transactions'); - print ''.price($sign * $objp->amount).' 
'.$langs->trans("None").'
'; - if ($object->type != 3) print $langs->trans('AlreadyPaidNoCreditNotesNoDeposits'); - else print $langs->trans('AlreadyPaid'); - print ' :'.price($totalpaye).' 
'; - if ($invoice->type == 2) print $langs->trans("CreditNote").' '; - if ($invoice->type == 3) print $langs->trans("Deposit").' '; - print $invoice->getNomUrl(0); - print ' :'.price($obj->amount_ttc).''; - print 'rowid.'">'.img_delete().''; - print '
'; - print $form->textwithpicto($langs->trans("Discount").':',$langs->trans("HelpEscompte"),-1); - print ''.price($object->total_ttc - $creditnoteamount - $depositamount - $totalpaye).' 
'; - print $form->textwithpicto($langs->trans("Abandoned").':',$langs->trans("HelpAbandonBadCustomer"),-1); - print ''.price($object->total_ttc - $creditnoteamount - $depositamount - $totalpaye).' 
'; - print $form->textwithpicto($langs->trans("ProductReturned").':',$langs->trans("HelpAbandonProductReturned"),-1); - print ''.price($object->total_ttc - $creditnoteamount - $depositamount - $totalpaye).' 
'; - $text=$langs->trans("HelpAbandonOther"); - if ($object->close_note) $text.='

'.$langs->trans("Reason").':'.$object->close_note; - print $form->textwithpicto($langs->trans("Abandoned").':',$text,-1); - print '
'.price($object->total_ttc - $creditnoteamount - $depositamount - $totalpaye).' 
'.$langs->trans("Billed").' :'.price($object->total_ttc).' 
'; - if ($resteapayeraffiche >= 0) print $langs->trans('RemainderToPay'); - else print $langs->trans('ExcessReceived'); - print ' :'.price($resteapayeraffiche).' 
'; - print $langs->trans('AlreadyPaidBack'); - print ' :'.price($sign * $totalpaye).' 
'.$langs->trans("Billed").' :'.price($sign * $object->total_ttc).' 
'; - if ($resteapayeraffiche <= 0) print $langs->trans('RemainderToPayBack'); - else print $langs->trans('ExcessPaydBack'); - print ' :'.price($sign * $resteapayeraffiche).' 
'.$langs->trans('TotalTTC').' :'.price($sign * $object->total_ttc).' 
'; - - // Margin Infos - if (! empty($conf->margin->enabled)) + if ($socid > 0) { - print '
'; - $object->displayMarginInfos($object->statut > 0); + // Discounts for third party + print '
'.$langs->trans('Discounts').''; + if ($soc->remise_client) print $langs->trans("CompanyHasRelativeDiscount",''.$soc->remise_client.''); + else print $langs->trans("CompanyHasNoRelativeDiscount"); + print ' ('.$langs->trans("EditRelativeDiscount").')'; + print '. '; + print '
'; + if ($absolute_discount) print $langs->trans("CompanyHasAbsoluteDiscount",''.price($absolute_discount).'',$langs->trans("Currency".$conf->currency)); + else print $langs->trans("CompanyHasNoAbsoluteDiscount"); + print ' ('.$langs->trans("EditGlobalDiscounts").')'; + print '.'; + print '
'.$langs->trans('Date').''; + $form->select_date($dateinvoice,'','','','',"add",1,1); + print '
'; - print ''; - if ($object->type != 2 && $action != 'editconditions' && ! empty($object->brouillon) && $user->rights->facture->creer) print ''; - print '
'; - print $langs->trans('PaymentConditionsShort'); - print 'id.'">'.img_edit($langs->trans('SetConditions'),1).'
'; - print '
'; - if ($object->type != 2) - { - if ($action == 'editconditions') - { - $form->form_conditions_reglement($_SERVER['PHP_SELF'].'?facid='.$object->id,$object->cond_reglement_id,'cond_reglement_id'); - } - else - { - $form->form_conditions_reglement($_SERVER['PHP_SELF'].'?facid='.$object->id,$object->cond_reglement_id,'none'); - } - } - else - { - print ' '; - } - print '
'.$langs->trans('PaymentConditionsShort').''; + $form->select_conditions_paiements(isset($_POST['cond_reglement_id'])?$_POST['cond_reglement_id']:$cond_reglement_id,'cond_reglement_id'); + print '
'; - print ''; - if ($object->type != 2 && $action != 'editpaymentterm' && ! empty($object->brouillon) && $user->rights->facture->creer) print ''; - print '
'; - print $langs->trans('DateMaxPayment'); - print 'id.'">'.img_edit($langs->trans('SetDate'),1).'
'; - print '
'; - if ($object->type != 2) - { - if ($action == 'editpaymentterm') - { - $form->form_date($_SERVER['PHP_SELF'].'?facid='.$object->id,$object->date_lim_reglement,'paymentterm'); - } - else - { - print dol_print_date($object->date_lim_reglement,'daytext'); - if ($object->date_lim_reglement < ($now - $conf->facture->client->warning_delay) && ! $object->paye && $object->statut == 1 && ! isset($object->am)) print img_warning($langs->trans('Late')); - } - } - else - { - print ' '; - } - print '
'.$langs->trans('PaymentMode').''; + $form->select_types_paiements(isset($_POST['mode_reglement_id'])?$_POST['mode_reglement_id']:$mode_reglement_id,'mode_reglement_id'); + print '
'; - print ''; - if ($action != 'editmode' && ! empty($object->brouillon) && $user->rights->facture->creer) print ''; - print '
'; - print $langs->trans('PaymentMode'); - print 'id.'">'.img_edit($langs->trans('SetMode'),1).'
'; - print '
'; - if ($action == 'editmode') - { - $form->form_modes_reglement($_SERVER['PHP_SELF'].'?facid='.$object->id,$object->mode_reglement_id,'mode_reglement_id'); - } - else - { - $form->form_modes_reglement($_SERVER['PHP_SELF'].'?facid='.$object->id,$object->mode_reglement_id,'none'); - } - print '
'.$langs->trans('Project').''; + select_projects($soc->id, $projectid, 'projectid'); + print '
'.$langs->trans('AmountHT').''.price($object->total_ht,1,'',1,-1,-1,$conf->currency).'
'.$langs->trans('AmountVAT').''.price($object->total_tva,1,'',1,-1,-1,$conf->currency).'
'.$langs->transcountry("AmountLT1",$mysoc->country_code).''.price($object->total_localtax1,1,'',1,-1,-1,$conf->currency).'
'.$langs->transcountry("AmountLT2",$mysoc->country_code).''.price($object->total_localtax2,1,'',1,-1,-1,$conf->currency).'
'.$langs->trans('Model').''; + include_once DOL_DOCUMENT_ROOT.'/core/modules/facture/modules_facture.php'; + $liste=ModelePDFFactures::liste_modeles($db); + print $form->selectarray('model',$liste,$conf->global->FACTURE_ADDON_PDF); + print "
'; - print ''; - if ($action != 'editrevenuestamp' && ! empty($object->brouillon) && $user->rights->facture->creer) print ''; - print '
'; - print $langs->trans('RevenueStamp'); - print 'id.'">'.img_edit($langs->trans('SetRevenuStamp'),1).'
'; - print '
'; - if ($action == 'editrevenuestamp') - { + // Public note + print '
'.$langs->trans('NotePublic').''; + $note_public=''; + if (is_object($objectsrc)) // Take value from source object + { + $note_public=$objectsrc->note_public; + } + $doleditor = new DolEditor('note_public', $note_public, '', 80, 'dolibarr_notes', 'In', 0, false, true, ROWS_3, 70); + print $doleditor->Create(1); + + //print '
'.$langs->trans('NotePrivate').''; + $note_private=''; + if (! empty($origin) && ! empty($originid) && is_object($objectsrc)) // Take value from source object + { + $note_private=$objectsrc->note_private; + } + $doleditor = new DolEditor('note_private', $note_private, '', 80, 'dolibarr_notes', 'In', 0, false, true, ROWS_3, 70); + print $doleditor->Create(1); + //print '
'.$langs->trans($newclassname).''.$objectsrc->getNomUrl(1).'
'.$langs->trans('TotalHT').''.price($objectsrc->total_ht).'
'.$langs->trans('TotalVAT').''.price($objectsrc->total_tva)."
'.$langs->transcountry("AmountLT1",$mysoc->country_code).''.price($objectsrc->total_localtax1)."
'.$langs->transcountry("AmountLT2",$mysoc->country_code).''.price($objectsrc->total_localtax2)."
'.$langs->trans('TotalTTC').''.price($objectsrc->total_ttc)."
'; + + // Zone de choix des produits predefinis a la creation + print ''; + print ''; + print ''; + print ''; + print ''; + print ''; + if (! empty($conf->service->enabled)) + { + print ''; + } + print ''; + for ($i = 1 ; $i <= $NBLINES ; $i++) + { + print ''; + print ''; + print ''; + print ''; + print ''; + // Si le module service est actif, on propose des dates de debut et fin a la ligne + if (! empty($conf->service->enabled)) + { + print ''; + } + print "\n"; + } + + print '
'.$langs->trans('ProductsAndServices').''.$langs->trans('Qty').''.$langs->trans('ReductionShort').'     '.$langs->trans('ServiceLimitedDuration').'
'; + // multiprix + if (! empty($conf->global->PRODUIT_MULTIPRICES)) + $form->select_produits('','idprod'.$i,'',$conf->product->limit_size,$soc->price_level); + else + $form->select_produits('','idprod'.$i,'',$conf->product->limit_size); + print '% '; + print ''; + print ''; + print '
'; + print $langs->trans('From').' '; + print ''; + print $form->select_date('','date_start'.$i,$usehm,$usehm,1,"add"); + print '
'; + print $langs->trans('to').' '; + print ''; + print $form->select_date('','date_end'.$i,$usehm,$usehm,1,"add"); + print '
'; + print '
'; + print '
\n"; + + // Button "Create Draft" + print '
'; + + print "
\n"; + + // Show origin lines + if (! empty($origin) && ! empty($originid) && is_object($objectsrc)) + { + print '
'; + + $title=$langs->trans('ProductsAndServices'); + print_titre($title); + + print ''; + + $objectsrc->printOriginLinesList(); + + print '
'; + } + + } + else if ($id > 0 || ! empty($ref)) + { + /* + * Show object in view mode + */ + + $result=$object->fetch($id,$ref); + + // fetch optionals attributes and labels + $extralabels=$extrafields->fetch_name_optionals_label('facture'); + + if ($result > 0) + { + if ($user->societe_id>0 && $user->societe_id!=$object->socid) accessforbidden('',0); + + $result=$object->fetch_thirdparty(); + + $soc = new Societe($db); + $soc->fetch($object->socid); + $selleruserevenustamp=$mysoc->useRevenueStamp(); + + $totalpaye = $object->getSommePaiement(); + $totalcreditnotes = $object->getSumCreditNotesUsed(); + $totaldeposits = $object->getSumDepositsUsed(); + //print "totalpaye=".$totalpaye." totalcreditnotes=".$totalcreditnotes." totaldeposts=".$totaldeposits." selleruserrevenuestamp=".$selleruserevenustamp; + + // We can also use bcadd to avoid pb with floating points + // For example print 239.2 - 229.3 - 9.9; does not return 0. + //$resteapayer=bcadd($object->total_ttc,$totalpaye,$conf->global->MAIN_MAX_DECIMALS_TOT); + //$resteapayer=bcadd($resteapayer,$totalavoir,$conf->global->MAIN_MAX_DECIMALS_TOT); + $resteapayer = price2num($object->total_ttc - $totalpaye - $totalcreditnotes - $totaldeposits,'MT'); + + if ($object->paye) $resteapayer=0; + $resteapayeraffiche=$resteapayer; + + if (! empty($conf->global->FACTURE_DEPOSITS_ARE_JUST_PAYMENTS)) + { + $filterabsolutediscount="fk_facture_source IS NULL"; // If we want deposit to be substracted to payments only and not to total of final invoice + $filtercreditnote="fk_facture_source IS NOT NULL"; // If we want deposit to be substracted to payments only and not to total of final invoice + } + else + { + $filterabsolutediscount="fk_facture_source IS NULL OR (fk_facture_source IS NOT NULL AND description='(DEPOSIT)')"; + $filtercreditnote="fk_facture_source IS NOT NULL AND description <> '(DEPOSIT)'"; + } + + $absolute_discount=$soc->getAvailableDiscounts('',$filterabsolutediscount); + $absolute_creditnote=$soc->getAvailableDiscounts('',$filtercreditnote); + $absolute_discount=price2num($absolute_discount,'MT'); + $absolute_creditnote=price2num($absolute_creditnote,'MT'); + + $author = new User($db); + if ($object->user_author) + { + $author->fetch($object->user_author); + } + + $objectidnext=$object->getIdReplacingInvoice(); + + + $head = facture_prepare_head($object); + + dol_fiche_head($head, 'compta', $langs->trans('InvoiceCustomer'), 0, 'bill'); + + $formconfirm=''; + + // Confirmation de la conversion de l'avoir en reduc + if ($action == 'converttoreduc') + { + $text=$langs->trans('ConfirmConvertToReduc'); + $formconfirm=$form->formconfirm($_SERVER['PHP_SELF'].'?facid='.$object->id,$langs->trans('ConvertToReduc'),$text,'confirm_converttoreduc','',"yes",2); + } + + // Confirmation to delete invoice + if ($action == 'delete') + { + $text=$langs->trans('ConfirmDeleteBill',$object->ref); + $formquestion=array(); + + $qualified_for_stock_change=0; + if (empty($conf->global->STOCK_SUPPORTS_SERVICES)) + { + $qualified_for_stock_change=$object->hasProductsOrServices(2); + } + else + { + $qualified_for_stock_change=$object->hasProductsOrServices(1); + } + + if ($object->type != 3 && ! empty($conf->global->STOCK_CALCULATE_ON_BILL) && $qualified_for_stock_change && $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,0,0,$langs->trans("NoStockAction")))); + $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 + if ($action == 'valid') + { + // on verifie si l'objet est en numerotation provisoire + $objectref = substr($object->ref, 1, 4); + if ($objectref == 'PROV') + { + $savdate=$object->date; + if (! empty($conf->global->FAC_FORCE_DATE_VALIDATION)) + { + $object->date=dol_now(); + $object->date_lim_reglement=$object->calculate_date_lim_reglement(); + } + $numref = $object->getNextNumRef($soc); + //$object->date=$savdate; + } + else + { + $numref = $object->ref; + } + + $text=$langs->trans('ConfirmValidateBill',$numref); + if (! empty($conf->notification->enabled)) + { + require_once DOL_DOCUMENT_ROOT .'/core/class/notify.class.php'; + $notify=new Notify($db); + $text.='
'; + $text.=$notify->confirmMessage('NOTIFY_VAL_FAC',$object->socid); + } + $formquestion=array(); + + $qualified_for_stock_change=0; + if (empty($conf->global->STOCK_SUPPORTS_SERVICES)) + { + $qualified_for_stock_change=$object->hasProductsOrServices(2); + } + else + { + $qualified_for_stock_change=$object->hasProductsOrServices(1); + } + + if ($object->type != 3 && ! empty($conf->global->STOCK_CALCULATE_ON_BILL) && $qualified_for_stock_change) + { + $langs->load("stocks"); + require_once DOL_DOCUMENT_ROOT.'/product/class/html.formproduct.class.php'; + $formproduct=new FormProduct($db); + $label=$object->type==2?$langs->trans("SelectWarehouseForStockIncrease"):$langs->trans("SelectWarehouseForStockDecrease"); + $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))); + } + if ($object->type != 2 && $object->total_ttc < 0) // Can happen only if $conf->global->FACTURE_ENABLE_NEGATIVE is on + { + $text.='
'.img_warning().' '.$langs->trans("ErrorInvoiceOfThisTypeMustBePositive"); + } + $formconfirm=$form->formconfirm($_SERVER["PHP_SELF"].'?facid='.$object->id,$langs->trans('ValidateBill'),$text,'confirm_valid',$formquestion,(($object->type != 2 && $object->total_ttc < 0)?"no":"yes"),($conf->notification->enabled?0:2)); + } + + // Confirm back to draft status + if ($action == 'modif') + { + $text=$langs->trans('ConfirmUnvalidateBill',$object->ref); + $formquestion=array(); + + $qualified_for_stock_change=0; + if (empty($conf->global->STOCK_SUPPORTS_SERVICES)) + { + $qualified_for_stock_change=$object->hasProductsOrServices(2); + } + else + { + $qualified_for_stock_change=$object->hasProductsOrServices(1); + } + if ($object->type != 3 && ! empty($conf->global->STOCK_CALCULATE_ON_BILL) && $qualified_for_stock_change) + { + $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('UnvalidateBill'),$text,'confirm_modif',$formquestion,"yes",1); + } + + // Confirmation du classement paye + if ($action == 'paid' && $resteapayer <= 0) + { + $formconfirm=$form->formconfirm($_SERVER["PHP_SELF"].'?facid='.$object->id,$langs->trans('ClassifyPaid'),$langs->trans('ConfirmClassifyPaidBill',$object->ref),'confirm_paid','',"yes",1); + } + if ($action == 'paid' && $resteapayer > 0) + { + // Code + $i=0; + $close[$i]['code']='discount_vat';$i++; + $close[$i]['code']='badcustomer';$i++; + // Help + $i=0; + $close[$i]['label']=$langs->trans("HelpEscompte").'

'.$langs->trans("ConfirmClassifyPaidPartiallyReasonDiscountVatDesc");$i++; + $close[$i]['label']=$langs->trans("ConfirmClassifyPaidPartiallyReasonBadCustomerDesc");$i++; + // Texte + $i=0; + $close[$i]['reason']=$form->textwithpicto($langs->transnoentities("ConfirmClassifyPaidPartiallyReasonDiscountVat",$resteapayer,$langs->trans("Currency".$conf->currency)),$close[$i]['label'],1);$i++; + $close[$i]['reason']=$form->textwithpicto($langs->transnoentities("ConfirmClassifyPaidPartiallyReasonBadCustomer",$resteapayer,$langs->trans("Currency".$conf->currency)),$close[$i]['label'],1);$i++; + // arrayreasons[code]=reason + foreach($close as $key => $val) + { + $arrayreasons[$close[$key]['code']]=$close[$key]['reason']; + } + + // Cree un tableau formulaire + $formquestion=array( + 'text' => $langs->trans("ConfirmClassifyPaidPartiallyQuestion"), + array('type' => 'radio', 'name' => 'close_code', 'label' => $langs->trans("Reason"), 'values' => $arrayreasons), + array('type' => 'text', 'name' => 'close_note', 'label' => $langs->trans("Comment"), 'value' => '', 'size' => '100') + ); + // Paiement incomplet. On demande si motif = escompte ou autre + $formconfirm=$form->formconfirm($_SERVER["PHP_SELF"].'?facid='.$object->id,$langs->trans('ClassifyPaid'),$langs->trans('ConfirmClassifyPaidPartially',$object->ref),'confirm_paid_partially',$formquestion,"yes"); + } + + // Confirmation du classement abandonne + if ($action == 'canceled') + { + // S'il y a une facture de remplacement pas encore validee (etat brouillon), + // on ne permet pas de classer abandonner la facture. + if ($objectidnext) + { + $facturereplacement=new Facture($db); + $facturereplacement->fetch($objectidnext); + $statusreplacement=$facturereplacement->statut; + } + if ($objectidnext && $statusreplacement == 0) + { + print '
'.$langs->trans("ErrorCantCancelIfReplacementInvoiceNotValidated").'
'; + } + else + { + // Code + $close[1]['code']='badcustomer'; + $close[2]['code']='abandon'; + // Help + $close[1]['label']=$langs->trans("ConfirmClassifyPaidPartiallyReasonBadCustomerDesc"); + $close[2]['label']=$langs->trans("ConfirmClassifyAbandonReasonOtherDesc"); + // Texte + $close[1]['reason']=$form->textwithpicto($langs->transnoentities("ConfirmClassifyPaidPartiallyReasonBadCustomer",$object->ref),$close[1]['label'],1); + $close[2]['reason']=$form->textwithpicto($langs->transnoentities("ConfirmClassifyAbandonReasonOther"),$close[2]['label'],1); + // arrayreasons + $arrayreasons[$close[1]['code']]=$close[1]['reason']; + $arrayreasons[$close[2]['code']]=$close[2]['reason']; + + // Cree un tableau formulaire + $formquestion=array( + 'text' => $langs->trans("ConfirmCancelBillQuestion"), + array('type' => 'radio', 'name' => 'close_code', 'label' => $langs->trans("Reason"), 'values' => $arrayreasons), + array('type' => 'text', 'name' => 'close_note', 'label' => $langs->trans("Comment"), 'value' => '', 'size' => '100') + ); + + $formconfirm=$form->formconfirm($_SERVER['PHP_SELF'].'?facid='.$object->id,$langs->trans('CancelBill'),$langs->trans('ConfirmCancelBill',$object->ref),'confirm_canceled',$formquestion,"yes"); + } + } + + // Confirmation de la suppression d'une ligne produit + if ($action == 'ask_deleteline') + { + $formconfirm=$form->formconfirm($_SERVER["PHP_SELF"].'?facid='.$object->id.'&lineid='.$lineid, $langs->trans('DeleteProductLine'), $langs->trans('ConfirmDeleteProductLine'), 'confirm_deleteline', '', 'no', 1); + } + + // Clone confirmation + if ($action == 'clone') + { + // Create an array for form + $formquestion=array( + //'text' => $langs->trans("ConfirmClone"), + //array('type' => 'checkbox', 'name' => 'clone_content', 'label' => $langs->trans("CloneMainAttributes"), 'value' => 1) + ); + // Paiement incomplet. On demande si motif = escompte ou autre + $formconfirm=$form->formconfirm($_SERVER["PHP_SELF"].'?facid='.$object->id,$langs->trans('CloneInvoice'),$langs->trans('ConfirmCloneInvoice',$object->ref),'confirm_clone',$formquestion,'yes',1); + } + + if (! $formconfirm) + { + $parameters=array('lineid'=>$lineid); + $formconfirm=$hookmanager->executeHooks('formConfirm',$parameters,$object,$action); // Note that $action and $object may have been modified by hook + } + + // Print form confirm + print $formconfirm; + + + // Invoice content + + print ''; + + $linkback = ''.$langs->trans("BackToList").''; + + // Ref + print ''; + print ''; + + // Ref customer + print ''; + print ''; - } - - // Total with tax - print ''; - - // Statut - print ''; - print ''; - - // Project - if (! empty($conf->projet->enabled)) - { - $langs->load('projects'); - print ''; - print ''; - print ''; - } - - // Other attributes - $res=$object->fetch_optionals($object->id,$extralabels); - $parameters=array('colspan' => ' colspan="2"'); - $reshook=$hookmanager->executeHooks('formObjectOptions',$parameters,$object,$action); // Note that $action and $object may have been modified by hook - if (empty($reshook) && ! empty($extrafields->attribute_label)) - { - - if ($action == 'edit_extras') - { - print ''; - print ''; - print ''; - print ''; - } - - foreach($extrafields->attribute_label as $key=>$label) - { - $value=(isset($_POST["options_".$key])?$_POST["options_".$key]:$object->array_options["options_".$key]); - if ($extrafields->attribute_type[$key] == 'separate') - { - print $extrafields->showSeparator($key); - } - else - { - print 'attribute_required[$key])) print ' class="fieldrequired"'; - print '>'.$label.''."\n"; - } - } - - if(count($extrafields->attribute_label) > 0) { - - if ($action == 'edit_extras' && $user->rights->facture->creer) - { - print ''; - - } - else { - if ($object->statut == 0 && $user->rights->facture->creer) - { - print ''; - } - } - } - } - - print '
'.$langs->trans('Ref').''; + $morehtmlref=''; + $discount=new DiscountAbsolute($db); + $result=$discount->fetch(0,$object->id); + if ($result > 0) + { + $morehtmlref=' ('.$langs->trans("CreditNoteConvertedIntoDiscount",$discount->getNomUrl(1,'discount')).')'; + } + if ($result < 0) + { + dol_print_error('',$discount->error); + } + print $form->showrefnav($object, 'ref', $linkback, 1, 'facnumber', 'ref', $morehtmlref); + print '
'; + print ''; + if ($action != 'refclient' && ! empty($object->brouillon)) print ''; + print '
'; + print $langs->trans('RefCustomer'); + print ''.img_edit($langs->trans('Modify')).'
'; + print '
'; + if ($user->rights->facture->creer && $action == 'refclient') + { print '
'; print ''; - print ''; - print $formother->select_revenue_stamp(GETPOST('revenuestamp'), 'revenuestamp', $mysoc->country_code); - //print ''; + print ''; + print ''; print ' '; print '
'; - } - else - { - print price($object->revenuestamp,1,'',1,-1,-1,$conf->currency); - } - print '
'.$langs->trans('AmountTTC').''.price($object->total_ttc,1,'',1,-1,-1,$conf->currency).'
'.$langs->trans('Status').''.($object->getLibStatut(4,$totalpaye)).'
'; - - print ''; - if ($action != 'classify') - { - print ''; - } - print '
'; - print $langs->trans('Project'); - print 'id.'">'; - print img_edit($langs->trans('SetProject'),1); - print '
'; - - print '
'; - if ($action == 'classify') - { - $form->form_project($_SERVER['PHP_SELF'].'?facid='.$object->id,$object->socid,$object->fk_project,'projectid'); - } - else - { - $form->form_project($_SERVER['PHP_SELF'].'?facid='.$object->id,$object->socid,$object->fk_project,'none'); - } - print '
'; - // Convert date into timestamp format - if (in_array($extrafields->attribute_type[$key],array('date','datetime'))) - { - $value = isset($_POST["options_".$key])?dol_mktime($_POST["options_".$key."hour"], $_POST["options_".$key."min"], 0, $_POST["options_".$key."month"], $_POST["options_".$key."day"], $_POST["options_".$key."year"]):$object->array_options['options_'.$key]; - } - - if ($action == 'edit_extras' && $user->rights->facture->creer) - { - print $extrafields->showInputField($key,$value); - } - else - { - print $extrafields->showOutputField($key,$value); - } - print '
'; - print ''; - print ''; - print '
'.img_picto('','edit').' '.$langs->trans('Modify').'

'; - - if (! empty($conf->global->MAIN_DISABLE_CONTACTS_TAB)) - { - $blocname = 'contacts'; - $title = $langs->trans('ContactsAddresses'); - include DOL_DOCUMENT_ROOT.'/core/tpl/bloc_showhide.tpl.php'; - } - - if (! empty($conf->global->MAIN_DISABLE_NOTES_TAB)) - { - $blocname = 'notes'; - $title = $langs->trans('Notes'); - include DOL_DOCUMENT_ROOT.'/core/tpl/bloc_showhide.tpl.php'; - } - - /* - * Lines - */ - $result = $object->getLinesArray(); - - if (! empty($conf->use_javascript_ajax) && $object->statut == 0) - { - include DOL_DOCUMENT_ROOT.'/core/tpl/ajaxrow.tpl.php'; - } - - print ''; - - // Show object lines - if (! empty($object->lines)) - $ret=$object->printObjectLines($action,$mysoc,$soc,$lineid,1); - - /* - * Form to add new line - */ - if ($object->statut == 0 && $user->rights->facture->creer && $action <> 'valid' && $action <> 'editline') - { - $var=true; - - if ($conf->global->MAIN_FEATURES_LEVEL > 1) - { - // Add free or predefined products/services - $object->formAddObjectLine(1,$mysoc,$soc); - } - else - { - // Add free products/services - $object->formAddFreeProduct(1,$mysoc,$soc); - - // Add predefined products/services - if (! empty($conf->product->enabled) || ! empty($conf->service->enabled)) - { - $var=!$var; - $object->formAddPredefinedProduct(1,$mysoc,$soc); - } - } - - $parameters=array(); - $reshook=$hookmanager->executeHooks('formAddObjectLine',$parameters,$object,$action); // Note that $action and $object may have been modified by hook - } - - print "
\n"; - - print "\n"; - - - /* - * Boutons actions - */ - - if ($action != 'prerelance' && $action != 'presend') - { - if ($user->societe_id == 0 && $action <> 'valid' && $action <> 'editline') - { - print '
'; - - // Editer une facture deja validee, sans paiement effectue et pas exporte en compta - if ($object->statut == 1) - { - // On verifie si les lignes de factures ont ete exportees en compta et/ou ventilees - $ventilExportCompta = $object->getVentilExportCompta(); - - if ($resteapayer == $object->total_ttc && $object->paye == 0 && $ventilExportCompta == 0) - { - if (! $objectidnext) - { - if ((empty($conf->global->MAIN_USE_ADVANCED_PERMS) && $user->rights->facture->valider) || $user->rights->facture->invoice_advance->unvalidate) - { - print ''; - } - else - { - print '
'.$langs->trans('Modify').'
'; - } - } - else - { - print '
'.$langs->trans('Modify').'
'; - } - } - } - - // Reopen a standard paid invoice - if (($object->type == 0 || $object->type == 1) && ($object->statut == 2 || $object->statut == 3)) // A paid invoice (partially or completely) - { - if (! $objectidnext && $object->close_code != 'replaced') // Not replaced by another invoice - { - print ''; - } - else - { - print '
'.$langs->trans('ReOpen').'
'; - } - } - - // Validate - if ($object->statut == 0 && count($object->lines) > 0 && - ( - (($object->type == 0 || $object->type == 1 || $object->type == 3 || $object->type == 4) && (! empty($conf->global->FACTURE_ENABLE_NEGATIVE) || $object->total_ttc >= 0)) - || ($object->type == 2 && $object->total_ttc <= 0)) - ) - { - if ($user->rights->facture->valider) - { - print ''; - } - } - - // Send by mail - if (($object->statut == 1 || $object->statut == 2)) - { - if ($objectidnext) - { - print '
'.$langs->trans('SendByMail').'
'; - } - else - { - if (empty($conf->global->MAIN_USE_ADVANCED_PERMS) || $user->rights->facture->invoice_advance->send) - { - print ''; - } - else print ''; - } - } - - if (! empty($conf->global->FACTURE_SHOW_SEND_REMINDER)) // For backward compatibility - { - if (($object->statut == 1 || $object->statut == 2) && $resteapayer > 0) - { - if ($objectidnext) - { - print '
'.$langs->trans('SendRemindByMail').'
'; - } - else - { - if (empty($conf->global->MAIN_USE_ADVANCED_PERMS) || $user->rights->facture->invoice_advance->send) - { - print ''; - } - else print ''; - } - } - } - - // Create payment - if ($object->type != 2 && $object->statut == 1 && $object->paye == 0 && $user->rights->facture->paiement) - { - if ($objectidnext) - { - print '
'.$langs->trans('DoPayment').'
'; - } - else - { - if ($resteapayer == 0) - { - print '
'.$langs->trans('DoPayment').'
'; - } - else - { - print ''; - } - } - } - - // Reverse back money or convert to reduction - if ($object->type == 2 || $object->type == 3) - { - // For credit note only - if ($object->type == 2 && $object->statut == 1 && $object->paye == 0 && $user->rights->facture->paiement) - { - print ''; - } - // For credit note - if ($object->type == 2 && $object->statut == 1 && $object->paye == 0 && $user->rights->facture->creer && $object->getSommePaiement() == 0) - { - print ''; - } - // For deposit invoice - if ($object->type == 3 && $object->statut == 1 && $resteapayer == 0 && $user->rights->facture->creer) - { - print ''; - } - } - - // Classify paid (if not deposit and not credit note. Such invoice are "converted") - if ($object->statut == 1 && $object->paye == 0 && $user->rights->facture->paiement && - (($object->type != 2 && $object->type != 3 && $resteapayer <= 0) || ($object->type == 2 && $resteapayer >= 0)) ) - { - print ''; - } - - // Classify 'closed not completely paid' (possible si validee et pas encore classee payee) - if ($object->statut == 1 && $object->paye == 0 && $resteapayer > 0 - && $user->rights->facture->paiement) - { - if ($totalpaye > 0 || $totalcreditnotes > 0) - { - // If one payment or one credit note was linked to this invoice - print ''; - } - else - { - if ($objectidnext) - { - print '
'.$langs->trans('ClassifyCanceled').'
'; - } - else - { - print ''; - } - } - } - - // Clone - if (($object->type == 0 || $object->type == 3 || $object->type == 4) && $user->rights->facture->creer) - { - print ''; - } - - // Clone as predefined - if (($object->type == 0 || $object->type == 3 || $object->type == 4) && $object->statut == 0 && $user->rights->facture->creer) - { - if (! $objectidnext) - { - print ''; - } - } - - // Delete - if ($user->rights->facture->supprimer) - { - if (! $object->is_erasable()) - { - print ''; - } - else if ($objectidnext) - { - print ''; - } - elseif ($object->getSommePaiement()) - { - print ''; - } - else - { - print ''; - } - } - else - { - print ''; - } - - print '
'; - } - } - print '
'; - - if ($action != 'prerelance' && $action != 'presend') - { - print '
'; - //print '
'; - //print ''; // ancre - - /* - * Documents generes - */ - $filename=dol_sanitizeFileName($object->ref); - $filedir=$conf->facture->dir_output . '/' . dol_sanitizeFileName($object->ref); - $urlsource=$_SERVER['PHP_SELF'].'?facid='.$object->id; - $genallowed=$user->rights->facture->creer; - $delallowed=$user->rights->facture->supprimer; - - print $formfile->showdocuments('facture',$filename,$filedir,$urlsource,$genallowed,$delallowed,$object->modelpdf,1,0,0,28,0,'','','',$soc->default_lang); - $somethingshown=$formfile->numoffiles; - - /* - * Linked object block - */ - $somethingshown=$object->showLinkedObjectBlock(); - - // Link for paypal payment - if (! empty($conf->paypal->enabled) && $object->statut != 0) - { - include_once DOL_DOCUMENT_ROOT.'/paypal/lib/paypal.lib.php'; - print showPaypalPaymentUrl('invoice',$object->ref); - } - - print '
'; - //print '
'; - - // List of actions on element - include_once DOL_DOCUMENT_ROOT.'/core/class/html.formactions.class.php'; - $formactions=new FormActions($db); - $somethingshown=$formactions->showactions($object,'invoice',$socid); - - //print '
'; - print '
'; - } - else - { - /* - * Affiche formulaire mail - */ - - // By default if $action=='presend' - $titreform='SendBillByMail'; - $topicmail='SendBillRef'; - $action='send'; - $modelmail='facture_send'; - - if ($action == 'prerelance') // For backward compatibility - { - $titrefrom='SendReminderBillByMail'; - $topicmail='SendReminderBillRef'; - $action='relance'; - $modelmail='facture_relance'; - } - - $ref = dol_sanitizeFileName($object->ref); - include_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php'; - $fileparams = dol_most_recent_file($conf->facture->dir_output . '/' . $ref, preg_quote($ref,'/')); - $file=$fileparams['fullname']; - - // Build document if it not exists - if (! $file || ! is_readable($file)) - { - // Define output language - $outputlangs = $langs; - $newlang=''; - if ($conf->global->MAIN_MULTILANGS && empty($newlang) && ! empty($_REQUEST['lang_id'])) $newlang=$_REQUEST['lang_id']; - if ($conf->global->MAIN_MULTILANGS && empty($newlang)) $newlang=$object->client->default_lang; - if (! empty($newlang)) - { - $outputlangs = new Translate("",$conf); - $outputlangs->setDefaultLang($newlang); - } - - $result=facture_pdf_create($db, $object, GETPOST('model')?GETPOST('model'):$object->modelpdf, $outputlangs, $hidedetails, $hidedesc, $hideref); - if ($result <= 0) - { - dol_print_error($db,$result); - exit; - } - $fileparams = dol_most_recent_file($conf->facture->dir_output . '/' . $ref, preg_quote($ref,'/')); - $file=$fileparams['fullname']; - } - - print '
'; - print_titre($langs->trans($titreform)); - - // Cree l'objet formulaire mail - include_once DOL_DOCUMENT_ROOT.'/core/class/html.formmail.class.php'; - $formmail = new FormMail($db); - $formmail->fromtype = 'user'; - $formmail->fromid = $user->id; - $formmail->fromname = $user->getFullName($langs); - $formmail->frommail = $user->email; - $formmail->withfrom=1; - $liste=array(); - foreach ($object->thirdparty->thirdparty_and_contact_email_array(1) as $key=>$value) $liste[$key]=$value; - $formmail->withto=GETPOST('sendto')?GETPOST('sendto'):$liste; - $formmail->withtocc=$liste; - $formmail->withtoccc=$conf->global->MAIN_EMAIL_USECCC; - $formmail->withtopic=$langs->transnoentities($topicmail,'__FACREF__'); - $formmail->withfile=2; - $formmail->withbody=1; - $formmail->withdeliveryreceipt=1; - $formmail->withcancel=1; - // Tableau des substitutions - $formmail->substit['__FACREF__']=$object->ref; - $formmail->substit['__SIGNATURE__']=$user->signature; - $formmail->substit['__PERSONALIZED__']=''; - $formmail->substit['__CONTACTCIVNAME__']=''; - - //Find the good contact adress - $custcontact=''; - $contactarr=array(); - $contactarr=$object->liste_contact(-1,'external'); - - if (is_array($contactarr) && count($contactarr)>0) { - foreach($contactarr as $contact) { - if ($contact['libelle']==$langs->trans('TypeContact_facture_external_BILLING')) { - - require_once DOL_DOCUMENT_ROOT . '/contact/class/contact.class.php'; - - $contactstatic=new Contact($db); - $contactstatic->fetch($contact['id']); - $custcontact=$contactstatic->getFullName($langs,1); - } - } - - if (!empty($custcontact)) { - $formmail->substit['__CONTACTCIVNAME__']=$custcontact; - } - } - - - // Tableau des parametres complementaires du post - $formmail->param['action']=$action; - $formmail->param['models']=$modelmail; - $formmail->param['facid']=$object->id; - $formmail->param['returnurl']=$_SERVER["PHP_SELF"].'?id='.$object->id; - - // Init list of files - if (GETPOST("mode")=='init') - { - $formmail->clear_attached_files(); - $formmail->add_attached_files($file,basename($file),dol_mimetype($file)); - } - - $formmail->show_form(); - - print '
'; - } - } - else - { - dol_print_error($db,$object->error); - } -} - -dol_htmloutput_mesg('',$mesgs); - -llxFooter(); -$db->close(); -?> + } + else + { + print $object->ref_client; + } + print '
'; + print ''; + print ''; + print ''; + print '
'.$langs->trans('Company').''; + if (! empty($conf->global->FACTURE_CHANGE_THIRDPARTY) && $action != 'editthirdparty' && $object->brouillon && $user->rights->facture->creer) + print 'id.'">'.img_edit($langs->trans('SetLinkToThirdParty'),1).'
'; + print '
'; + if ($action == 'editthirdparty') + { + $form->form_thirdparty($_SERVER['PHP_SELF'].'?facid='.$object->id,$object->socid,'socid'); + } + else + { + print '  '.$soc->getNomUrl(1,'compta'); + print '   ('.$langs->trans('OtherBills').')'; + } + print '
'.$langs->trans('Type').''; + print $object->getLibType(); + if ($object->type == 1) + { + $facreplaced=new Facture($db); + $facreplaced->fetch($object->fk_facture_source); + print ' ('.$langs->transnoentities("ReplaceInvoice",$facreplaced->getNomUrl(1)).')'; + } + if ($object->type == 2) + { + $facusing=new Facture($db); + $facusing->fetch($object->fk_facture_source); + print ' ('.$langs->transnoentities("CorrectInvoice",$facusing->getNomUrl(1)).')'; + } + + $facidavoir=$object->getListIdAvoirFromInvoice(); + if (count($facidavoir) > 0) + { + print ' ('.$langs->transnoentities("InvoiceHasAvoir"); + $i=0; + foreach($facidavoir as $id) + { + if ($i==0) print ' '; + else print ','; + $facavoir=new Facture($db); + $facavoir->fetch($id); + print $facavoir->getNomUrl(1); + } + print ')'; + } + if ($objectidnext > 0) + { + $facthatreplace=new Facture($db); + $facthatreplace->fetch($objectidnext); + print ' ('.$langs->transnoentities("ReplacedByInvoice",$facthatreplace->getNomUrl(1)).')'; + } + print '
'.$langs->trans('Discounts'); + print ''; + if ($soc->remise_client) print $langs->trans("CompanyHasRelativeDiscount",$soc->remise_client); + else print $langs->trans("CompanyHasNoRelativeDiscount"); + //print ' ('.$addrelativediscount.')'; + + if ($absolute_discount > 0) + { + print '. '; + if ($object->statut > 0 || $object->type == 2 || $object->type == 3) + { + if ($object->statut == 0) + { + print $langs->trans("CompanyHasAbsoluteDiscount",price($absolute_discount),$langs->transnoentities("Currency".$conf->currency)); + print '. '; + } + else + { + if ($object->statut < 1 || $object->type == 2 || $object->type == 3) + { + $text=$langs->trans("CompanyHasAbsoluteDiscount",price($absolute_discount),$langs->transnoentities("Currency".$conf->currency)); + print '
'.$text.'.
'; + } + else + { + $text=$langs->trans("CompanyHasAbsoluteDiscount",price($absolute_discount),$langs->transnoentities("Currency".$conf->currency)); + $text2=$langs->trans("AbsoluteDiscountUse"); + print $form->textwithpicto($text,$text2); + } + } + } + else + { + // Remise dispo de type remise fixe (not credit note) + print '
'; + $form->form_remise_dispo($_SERVER["PHP_SELF"].'?facid='.$object->id, GETPOST('discountid'), 'remise_id', $soc->id, $absolute_discount, $filterabsolutediscount, $resteapayer, ' ('.$addabsolutediscount.')'); + } + } + else + { + if ($absolute_creditnote > 0) // If not, link will be added later + { + if ($object->statut == 0 && $object->type != 2 && $object->type != 3) print ' ('.$addabsolutediscount.')
'; + else print '. '; + } + else print '. '; + } + if ($absolute_creditnote > 0) + { + // If validated, we show link "add credit note to payment" + if ($object->statut != 1 || $object->type == 2 || $object->type == 3) + { + if ($object->statut == 0 && $object->type != 3) + { + $text=$langs->trans("CompanyHasCreditNote",price($absolute_creditnote),$langs->transnoentities("Currency".$conf->currency)); + print $form->textwithpicto($text,$langs->trans("CreditNoteDepositUse")); + } + else + { + print $langs->trans("CompanyHasCreditNote",price($absolute_creditnote),$langs->transnoentities("Currency".$conf->currency)).'.'; + } + } + else + { + // Remise dispo de type avoir + if (! $absolute_discount) print '
'; + //$form->form_remise_dispo($_SERVER["PHP_SELF"].'?facid='.$object->id, 0, 'remise_id_for_payment', $soc->id, $absolute_creditnote, $filtercreditnote, $resteapayer); + $form->form_remise_dispo($_SERVER["PHP_SELF"].'?facid='.$object->id, 0, 'remise_id_for_payment', $soc->id, $absolute_creditnote, $filtercreditnote, 0); // We must allow credit not even if amount is higher + } + } + if (! $absolute_discount && ! $absolute_creditnote) + { + print $langs->trans("CompanyHasNoAbsoluteDiscount"); + if ($object->statut == 0 && $object->type != 2 && $object->type != 3) print ' ('.$addabsolutediscount.')
'; + else print '. '; + } + /*if ($object->statut == 0 && $object->type != 2 && $object->type != 3) + { + if (! $absolute_discount && ! $absolute_creditnote) print '
'; + //print '   -   '; + print $addabsolutediscount; + //print '   -   '.$addcreditnote; // We disbale link to credit note + }*/ + print '
'; + print ''; + if ($object->type != 2 && $action != 'editinvoicedate' && ! empty($object->brouillon) && $user->rights->facture->creer) print ''; + print '
'; + print $langs->trans('Date'); + print 'id.'">'.img_edit($langs->trans('SetDate'),1).'
'; + print '
'; + + if ($object->type != 2) + { + if ($action == 'editinvoicedate') + { + $form->form_date($_SERVER['PHP_SELF'].'?facid='.$object->id,$object->date,'invoicedate'); + } + else + { + print dol_print_date($object->date,'daytext'); + } + } + else + { + print dol_print_date($object->date,'daytext'); + } + print ''; + + print ''; + + // List of payments already done + print ''; + print ''; + print ''; + if (! empty($conf->banque->enabled)) print ''; + print ''; + print ''; + print ''; + + $var=true; + + // Payments already done (from payment on this invoice) + $sql = 'SELECT p.datep as dp, p.num_paiement, p.rowid, p.fk_bank,'; + $sql.= ' c.code as payment_code, c.libelle as payment_label,'; + $sql.= ' pf.amount,'; + $sql.= ' ba.rowid as baid, ba.ref, ba.label'; + $sql.= ' FROM '.MAIN_DB_PREFIX.'c_paiement as c, '.MAIN_DB_PREFIX.'paiement_facture as pf, '.MAIN_DB_PREFIX.'paiement as p'; + $sql.= ' LEFT JOIN '.MAIN_DB_PREFIX.'bank as b ON p.fk_bank = b.rowid'; + $sql.= ' LEFT JOIN '.MAIN_DB_PREFIX.'bank_account as ba ON b.fk_account = ba.rowid'; + $sql.= ' WHERE pf.fk_facture = '.$object->id.' AND p.fk_paiement = c.id AND pf.fk_paiement = p.rowid'; + $sql.= ' ORDER BY p.datep, p.tms'; + + $result = $db->query($sql); + if ($result) + { + $num = $db->num_rows($result); + $i = 0; + + //if ($object->type != 2) + //{ + if ($num > 0) + { + while ($i < $num) + { + $objp = $db->fetch_object($result); + $var=!$var; + print ''; + $label=($langs->trans("PaymentType".$objp->payment_code)!=("PaymentType".$objp->payment_code))?$langs->trans("PaymentType".$objp->payment_code):$objp->payment_label; + print ''; + if (! empty($conf->banque->enabled)) + { + $bankaccountstatic->id=$objp->baid; + $bankaccountstatic->ref=$objp->ref; + $bankaccountstatic->label=$objp->ref; + print ''; + } + print ''; + print ''; + print ''; + $i++; + } + } + else + { + print ''; + } + //} + $db->free($result); + } + else + { + dol_print_error($db); + } + + if ($object->type != 2) + { + // Total already paid + print ''; + + $resteapayeraffiche=$resteapayer; + + // Loop on each credit note or deposit amount applied + $creditnoteamount=0; + $depositamount=0; + $sql = "SELECT re.rowid, re.amount_ht, re.amount_tva, re.amount_ttc,"; + $sql.= " re.description, re.fk_facture_source"; + $sql.= " FROM ".MAIN_DB_PREFIX ."societe_remise_except as re"; + $sql.= " WHERE fk_facture = ".$object->id; + $resql=$db->query($sql); + if ($resql) + { + $num = $db->num_rows($resql); + $i = 0; + $invoice=new Facture($db); + while ($i < $num) + { + $obj = $db->fetch_object($resql); + $invoice->fetch($obj->fk_facture_source); + print ''; + print ''; + print ''; + $i++; + if ($invoice->type == 2) $creditnoteamount += $obj->amount_ttc; + if ($invoice->type == 3) $depositamount += $obj->amount_ttc; + } + } + else + { + dol_print_error($db); + } + + // Paye partiellement 'escompte' + if (($object->statut == 2 || $object->statut == 3) && $object->close_code == 'discount_vat') + { + print ''; + $resteapayeraffiche=0; + } + // Paye partiellement ou Abandon 'badcustomer' + if (($object->statut == 2 || $object->statut == 3) && $object->close_code == 'badcustomer') + { + print ''; + //$resteapayeraffiche=0; + } + // Paye partiellement ou Abandon 'product_returned' + if (($object->statut == 2 || $object->statut == 3) && $object->close_code == 'product_returned') + { + print ''; + $resteapayeraffiche=0; + } + // Paye partiellement ou Abandon 'abandon' + if (($object->statut == 2 || $object->statut == 3) && $object->close_code == 'abandon') + { + print ''; + $resteapayeraffiche=0; + } + + // Billed + print ''; + + // Remainder to pay + print ''; + print ''; + print ''; + } + else // Credit note + { + // Total already paid back + print ''; + + // Billed + print ''; + + // Remainder to pay back + print ''; + print ''; + print ''; + + // Sold credit note + //print ''; + //print ''; + } + + print '
'.($object->type == 2 ? $langs->trans("PaymentsBack") : $langs->trans('Payments')).''.$langs->trans('Type').''.$langs->trans('BankAccount').''.$langs->trans('Amount').' 
'; + print ''.img_object($langs->trans('ShowPayment'),'payment').' '; + print dol_print_date($db->jdate($objp->dp),'day').''.$label.' '.$objp->num_paiement.''; + if ($bankaccountstatic->id) print $bankaccountstatic->getNomUrl(1,'transactions'); + print ''.price($sign * $objp->amount).' 
'.$langs->trans("None").'
'; + if ($object->type != 3) print $langs->trans('AlreadyPaidNoCreditNotesNoDeposits'); + else print $langs->trans('AlreadyPaid'); + print ' :'.price($totalpaye).' 
'; + if ($invoice->type == 2) print $langs->trans("CreditNote").' '; + if ($invoice->type == 3) print $langs->trans("Deposit").' '; + print $invoice->getNomUrl(0); + print ' :'.price($obj->amount_ttc).''; + print 'rowid.'">'.img_delete().''; + print '
'; + print $form->textwithpicto($langs->trans("Discount").':',$langs->trans("HelpEscompte"),-1); + print ''.price($object->total_ttc - $creditnoteamount - $depositamount - $totalpaye).' 
'; + print $form->textwithpicto($langs->trans("Abandoned").':',$langs->trans("HelpAbandonBadCustomer"),-1); + print ''.price($object->total_ttc - $creditnoteamount - $depositamount - $totalpaye).' 
'; + print $form->textwithpicto($langs->trans("ProductReturned").':',$langs->trans("HelpAbandonProductReturned"),-1); + print ''.price($object->total_ttc - $creditnoteamount - $depositamount - $totalpaye).' 
'; + $text=$langs->trans("HelpAbandonOther"); + if ($object->close_note) $text.='

'.$langs->trans("Reason").':'.$object->close_note; + print $form->textwithpicto($langs->trans("Abandoned").':',$text,-1); + print '
'.price($object->total_ttc - $creditnoteamount - $depositamount - $totalpaye).' 
'.$langs->trans("Billed").' :'.price($object->total_ttc).' 
'; + if ($resteapayeraffiche >= 0) print $langs->trans('RemainderToPay'); + else print $langs->trans('ExcessReceived'); + print ' :'.price($resteapayeraffiche).' 
'; + print $langs->trans('AlreadyPaidBack'); + print ' :'.price($sign * $totalpaye).' 
'.$langs->trans("Billed").' :'.price($sign * $object->total_ttc).' 
'; + if ($resteapayeraffiche <= 0) print $langs->trans('RemainderToPayBack'); + else print $langs->trans('ExcessPaydBack'); + print ' :'.price($sign * $resteapayeraffiche).' 
'.$langs->trans('TotalTTC').' :'.price($sign * $object->total_ttc).' 
'; + + // Margin Infos + if (! empty($conf->margin->enabled)) + { + print '
'; + $object->displayMarginInfos($object->statut > 0); + } + + print '
'; + print ''; + if ($object->type != 2 && $action != 'editconditions' && ! empty($object->brouillon) && $user->rights->facture->creer) print ''; + print '
'; + print $langs->trans('PaymentConditionsShort'); + print 'id.'">'.img_edit($langs->trans('SetConditions'),1).'
'; + print '
'; + if ($object->type != 2) + { + if ($action == 'editconditions') + { + $form->form_conditions_reglement($_SERVER['PHP_SELF'].'?facid='.$object->id,$object->cond_reglement_id,'cond_reglement_id'); + } + else + { + $form->form_conditions_reglement($_SERVER['PHP_SELF'].'?facid='.$object->id,$object->cond_reglement_id,'none'); + } + } + else + { + print ' '; + } + print '
'; + print ''; + if ($object->type != 2 && $action != 'editpaymentterm' && ! empty($object->brouillon) && $user->rights->facture->creer) print ''; + print '
'; + print $langs->trans('DateMaxPayment'); + print 'id.'">'.img_edit($langs->trans('SetDate'),1).'
'; + print '
'; + if ($object->type != 2) + { + if ($action == 'editpaymentterm') + { + $form->form_date($_SERVER['PHP_SELF'].'?facid='.$object->id,$object->date_lim_reglement,'paymentterm'); + } + else + { + print dol_print_date($object->date_lim_reglement,'daytext'); + if ($object->date_lim_reglement < ($now - $conf->facture->client->warning_delay) && ! $object->paye && $object->statut == 1 && ! isset($object->am)) print img_warning($langs->trans('Late')); + } + } + else + { + print ' '; + } + print '
'; + print ''; + if ($action != 'editmode' && ! empty($object->brouillon) && $user->rights->facture->creer) print ''; + print '
'; + print $langs->trans('PaymentMode'); + print 'id.'">'.img_edit($langs->trans('SetMode'),1).'
'; + print '
'; + if ($action == 'editmode') + { + $form->form_modes_reglement($_SERVER['PHP_SELF'].'?facid='.$object->id,$object->mode_reglement_id,'mode_reglement_id'); + } + else + { + $form->form_modes_reglement($_SERVER['PHP_SELF'].'?facid='.$object->id,$object->mode_reglement_id,'none'); + } + print '
'.$langs->trans('AmountHT').''.price($object->total_ht,1,'',1,-1,-1,$conf->currency).'
'.$langs->trans('AmountVAT').''.price($object->total_tva,1,'',1,-1,-1,$conf->currency).'
'.$langs->transcountry("AmountLT1",$mysoc->country_code).''.price($object->total_localtax1,1,'',1,-1,-1,$conf->currency).'
'.$langs->transcountry("AmountLT2",$mysoc->country_code).''.price($object->total_localtax2,1,'',1,-1,-1,$conf->currency).'
'; + print ''; + if ($action != 'editrevenuestamp' && ! empty($object->brouillon) && $user->rights->facture->creer) print ''; + print '
'; + print $langs->trans('RevenueStamp'); + print 'id.'">'.img_edit($langs->trans('SetRevenuStamp'),1).'
'; + print '
'; + if ($action == 'editrevenuestamp') + { + print '
'; + print ''; + print ''; + print $formother->select_revenue_stamp(GETPOST('revenuestamp'), 'revenuestamp', $mysoc->country_code); + //print ''; + print ' '; + print '
'; + } + else + { + print price($object->revenuestamp,1,'',1,-1,-1,$conf->currency); + } + print '
'.$langs->trans('AmountTTC').''.price($object->total_ttc,1,'',1,-1,-1,$conf->currency).'
'.$langs->trans('Status').''.($object->getLibStatut(4,$totalpaye)).'
'; + + print ''; + if ($action != 'classify') + { + print ''; + } + print '
'; + print $langs->trans('Project'); + print 'id.'">'; + print img_edit($langs->trans('SetProject'),1); + print '
'; + + print '
'; + if ($action == 'classify') + { + $form->form_project($_SERVER['PHP_SELF'].'?facid='.$object->id,$object->socid,$object->fk_project,'projectid'); + } + else + { + $form->form_project($_SERVER['PHP_SELF'].'?facid='.$object->id,$object->socid,$object->fk_project,'none'); + } + print '
'; + // Convert date into timestamp format + if (in_array($extrafields->attribute_type[$key],array('date','datetime'))) + { + $value = isset($_POST["options_".$key])?dol_mktime($_POST["options_".$key."hour"], $_POST["options_".$key."min"], 0, $_POST["options_".$key."month"], $_POST["options_".$key."day"], $_POST["options_".$key."year"]):$object->array_options['options_'.$key]; + } + + if ($action == 'edit_extras' && $user->rights->facture->creer) + { + print $extrafields->showInputField($key,$value); + } + else + { + print $extrafields->showOutputField($key,$value); + } + print '
'; + print ''; + print ''; + print '
'.img_picto('','edit').' '.$langs->trans('Modify').'

'; + + if (! empty($conf->global->MAIN_DISABLE_CONTACTS_TAB)) + { + $blocname = 'contacts'; + $title = $langs->trans('ContactsAddresses'); + include DOL_DOCUMENT_ROOT.'/core/tpl/bloc_showhide.tpl.php'; + } + + if (! empty($conf->global->MAIN_DISABLE_NOTES_TAB)) + { + $blocname = 'notes'; + $title = $langs->trans('Notes'); + include DOL_DOCUMENT_ROOT.'/core/tpl/bloc_showhide.tpl.php'; + } + + /* + * Lines + */ + $result = $object->getLinesArray(); + + if (! empty($conf->use_javascript_ajax) && $object->statut == 0) + { + include DOL_DOCUMENT_ROOT.'/core/tpl/ajaxrow.tpl.php'; + } + + print ''; + + // Show object lines + if (! empty($object->lines)) + $ret=$object->printObjectLines($action,$mysoc,$soc,$lineid,1); + + /* + * Form to add new line + */ + if ($object->statut == 0 && $user->rights->facture->creer && $action <> 'valid' && $action <> 'editline') + { + $var=true; + + if ($conf->global->MAIN_FEATURES_LEVEL > 1) + { + // Add free or predefined products/services + $object->formAddObjectLine(1,$mysoc,$soc); + } + else + { + // Add free products/services + $object->formAddFreeProduct(1,$mysoc,$soc); + + // Add predefined products/services + if (! empty($conf->product->enabled) || ! empty($conf->service->enabled)) + { + $var=!$var; + $object->formAddPredefinedProduct(1,$mysoc,$soc); + } + } + + $parameters=array(); + $reshook=$hookmanager->executeHooks('formAddObjectLine',$parameters,$object,$action); // Note that $action and $object may have been modified by hook + } + + print "
\n"; + + print "\n"; + + + /* + * Boutons actions + */ + + if ($action != 'prerelance' && $action != 'presend') + { + if ($user->societe_id == 0 && $action <> 'valid' && $action <> 'editline') + { + print '
'; + + // Editer une facture deja validee, sans paiement effectue et pas exporte en compta + if ($object->statut == 1) + { + // On verifie si les lignes de factures ont ete exportees en compta et/ou ventilees + $ventilExportCompta = $object->getVentilExportCompta(); + + if ($resteapayer == $object->total_ttc && $object->paye == 0 && $ventilExportCompta == 0) + { + if (! $objectidnext) + { + if ((empty($conf->global->MAIN_USE_ADVANCED_PERMS) && $user->rights->facture->valider) || $user->rights->facture->invoice_advance->unvalidate) + { + print ''; + } + else + { + print '
'.$langs->trans('Modify').'
'; + } + } + else + { + print '
'.$langs->trans('Modify').'
'; + } + } + } + + // Reopen a standard paid invoice + if (($object->type == 0 || $object->type == 1) && ($object->statut == 2 || $object->statut == 3)) // A paid invoice (partially or completely) + { + if (! $objectidnext && $object->close_code != 'replaced') // Not replaced by another invoice + { + print ''; + } + else + { + print '
'.$langs->trans('ReOpen').'
'; + } + } + + // Validate + if ($object->statut == 0 && count($object->lines) > 0 && + ( + (($object->type == 0 || $object->type == 1 || $object->type == 3 || $object->type == 4) && (! empty($conf->global->FACTURE_ENABLE_NEGATIVE) || $object->total_ttc >= 0)) + || ($object->type == 2 && $object->total_ttc <= 0)) + ) + { + if ($user->rights->facture->valider) + { + print ''; + } + } + + // Send by mail + if (($object->statut == 1 || $object->statut == 2)) + { + if ($objectidnext) + { + print '
'.$langs->trans('SendByMail').'
'; + } + else + { + if (empty($conf->global->MAIN_USE_ADVANCED_PERMS) || $user->rights->facture->invoice_advance->send) + { + print ''; + } + else print ''; + } + } + + if (! empty($conf->global->FACTURE_SHOW_SEND_REMINDER)) // For backward compatibility + { + if (($object->statut == 1 || $object->statut == 2) && $resteapayer > 0) + { + if ($objectidnext) + { + print '
'.$langs->trans('SendRemindByMail').'
'; + } + else + { + if (empty($conf->global->MAIN_USE_ADVANCED_PERMS) || $user->rights->facture->invoice_advance->send) + { + print ''; + } + else print ''; + } + } + } + + // Create payment + if ($object->type != 2 && $object->statut == 1 && $object->paye == 0 && $user->rights->facture->paiement) + { + if ($objectidnext) + { + print '
'.$langs->trans('DoPayment').'
'; + } + else + { + if ($resteapayer == 0) + { + print '
'.$langs->trans('DoPayment').'
'; + } + else + { + print ''; + } + } + } + + // Reverse back money or convert to reduction + if ($object->type == 2 || $object->type == 3) + { + // For credit note only + if ($object->type == 2 && $object->statut == 1 && $object->paye == 0 && $user->rights->facture->paiement) + { + print ''; + } + // For credit note + if ($object->type == 2 && $object->statut == 1 && $object->paye == 0 && $user->rights->facture->creer && $object->getSommePaiement() == 0) + { + print ''; + } + // For deposit invoice + if ($object->type == 3 && $object->statut == 1 && $resteapayer == 0 && $user->rights->facture->creer) + { + print ''; + } + } + + // Classify paid (if not deposit and not credit note. Such invoice are "converted") + if ($object->statut == 1 && $object->paye == 0 && $user->rights->facture->paiement && + (($object->type != 2 && $object->type != 3 && $resteapayer <= 0) || ($object->type == 2 && $resteapayer >= 0)) ) + { + print ''; + } + + // Classify 'closed not completely paid' (possible si validee et pas encore classee payee) + if ($object->statut == 1 && $object->paye == 0 && $resteapayer > 0 + && $user->rights->facture->paiement) + { + if ($totalpaye > 0 || $totalcreditnotes > 0) + { + // If one payment or one credit note was linked to this invoice + print ''; + } + else + { + if ($objectidnext) + { + print '
'.$langs->trans('ClassifyCanceled').'
'; + } + else + { + print ''; + } + } + } + + // Clone + if (($object->type == 0 || $object->type == 3 || $object->type == 4) && $user->rights->facture->creer) + { + print ''; + } + + // Clone as predefined + if (($object->type == 0 || $object->type == 3 || $object->type == 4) && $object->statut == 0 && $user->rights->facture->creer) + { + if (! $objectidnext) + { + print ''; + } + } + + // Delete + if ($user->rights->facture->supprimer) + { + if (! $object->is_erasable()) + { + print ''; + } + else if ($objectidnext) + { + print ''; + } + elseif ($object->getSommePaiement()) + { + print ''; + } + else + { + print ''; + } + } + else + { + print ''; + } + + print '
'; + } + } + print '
'; + + if ($action != 'prerelance' && $action != 'presend') + { + print '
'; + //print '
'; + //print ''; // ancre + + /* + * Documents generes + */ + $filename=dol_sanitizeFileName($object->ref); + $filedir=$conf->facture->dir_output . '/' . dol_sanitizeFileName($object->ref); + $urlsource=$_SERVER['PHP_SELF'].'?facid='.$object->id; + $genallowed=$user->rights->facture->creer; + $delallowed=$user->rights->facture->supprimer; + + print $formfile->showdocuments('facture',$filename,$filedir,$urlsource,$genallowed,$delallowed,$object->modelpdf,1,0,0,28,0,'','','',$soc->default_lang); + $somethingshown=$formfile->numoffiles; + + /* + * Linked object block + */ + $somethingshown=$object->showLinkedObjectBlock(); + + // Link for paypal payment + if (! empty($conf->paypal->enabled) && $object->statut != 0) + { + include_once DOL_DOCUMENT_ROOT.'/paypal/lib/paypal.lib.php'; + print showPaypalPaymentUrl('invoice',$object->ref); + } + + print '
'; + //print '
'; + + // List of actions on element + include_once DOL_DOCUMENT_ROOT.'/core/class/html.formactions.class.php'; + $formactions=new FormActions($db); + $somethingshown=$formactions->showactions($object,'invoice',$socid); + + //print '
'; + print '
'; + } + else + { + /* + * Affiche formulaire mail + */ + + // By default if $action=='presend' + $titreform='SendBillByMail'; + $topicmail='SendBillRef'; + $action='send'; + $modelmail='facture_send'; + + if ($action == 'prerelance') // For backward compatibility + { + $titrefrom='SendReminderBillByMail'; + $topicmail='SendReminderBillRef'; + $action='relance'; + $modelmail='facture_relance'; + } + + $ref = dol_sanitizeFileName($object->ref); + include_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php'; + $fileparams = dol_most_recent_file($conf->facture->dir_output . '/' . $ref, preg_quote($ref,'/')); + $file=$fileparams['fullname']; + + // Build document if it not exists + if (! $file || ! is_readable($file)) + { + // Define output language + $outputlangs = $langs; + $newlang=''; + if ($conf->global->MAIN_MULTILANGS && empty($newlang) && ! empty($_REQUEST['lang_id'])) $newlang=$_REQUEST['lang_id']; + if ($conf->global->MAIN_MULTILANGS && empty($newlang)) $newlang=$object->client->default_lang; + if (! empty($newlang)) + { + $outputlangs = new Translate("",$conf); + $outputlangs->setDefaultLang($newlang); + } + + $result=facture_pdf_create($db, $object, GETPOST('model')?GETPOST('model'):$object->modelpdf, $outputlangs, $hidedetails, $hidedesc, $hideref); + if ($result <= 0) + { + dol_print_error($db,$result); + exit; + } + $fileparams = dol_most_recent_file($conf->facture->dir_output . '/' . $ref, preg_quote($ref,'/')); + $file=$fileparams['fullname']; + } + + print '
'; + print_titre($langs->trans($titreform)); + + // Cree l'objet formulaire mail + include_once DOL_DOCUMENT_ROOT.'/core/class/html.formmail.class.php'; + $formmail = new FormMail($db); + $formmail->fromtype = 'user'; + $formmail->fromid = $user->id; + $formmail->fromname = $user->getFullName($langs); + $formmail->frommail = $user->email; + $formmail->withfrom=1; + $liste=array(); + foreach ($object->thirdparty->thirdparty_and_contact_email_array(1) as $key=>$value) $liste[$key]=$value; + $formmail->withto=GETPOST('sendto')?GETPOST('sendto'):$liste; + $formmail->withtocc=$liste; + $formmail->withtoccc=$conf->global->MAIN_EMAIL_USECCC; + $formmail->withtopic=$langs->transnoentities($topicmail,'__FACREF__'); + $formmail->withfile=2; + $formmail->withbody=1; + $formmail->withdeliveryreceipt=1; + $formmail->withcancel=1; + // Tableau des substitutions + $formmail->substit['__FACREF__']=$object->ref; + $formmail->substit['__SIGNATURE__']=$user->signature; + $formmail->substit['__PERSONALIZED__']=''; + $formmail->substit['__CONTACTCIVNAME__']=''; + + //Find the good contact adress + $custcontact=''; + $contactarr=array(); + $contactarr=$object->liste_contact(-1,'external'); + + if (is_array($contactarr) && count($contactarr)>0) { + foreach($contactarr as $contact) { + if ($contact['libelle']==$langs->trans('TypeContact_facture_external_BILLING')) { + + require_once DOL_DOCUMENT_ROOT . '/contact/class/contact.class.php'; + + $contactstatic=new Contact($db); + $contactstatic->fetch($contact['id']); + $custcontact=$contactstatic->getFullName($langs,1); + } + } + + if (!empty($custcontact)) { + $formmail->substit['__CONTACTCIVNAME__']=$custcontact; + } + } + + + // Tableau des parametres complementaires du post + $formmail->param['action']=$action; + $formmail->param['models']=$modelmail; + $formmail->param['facid']=$object->id; + $formmail->param['returnurl']=$_SERVER["PHP_SELF"].'?id='.$object->id; + + // Init list of files + if (GETPOST("mode")=='init') + { + $formmail->clear_attached_files(); + $formmail->add_attached_files($file,basename($file),dol_mimetype($file)); + } + + $formmail->show_form(); + + print '
'; + } + } + else + { + dol_print_error($db,$object->error); + } + } + + dol_htmloutput_mesg('',$mesgs); + + llxFooter(); + $db->close(); + ?> diff --git a/htdocs/compta/facture/class/facture.class.php b/htdocs/compta/facture/class/facture.class.php index f36ddc88a1d..58e57d7f88c 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_BILL) && $idwarehouse!=-1) + { + 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).""; - } - $sql.= " , fk_product_fournisseur_price='".$this->fk_fournprice."'"; + // 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=".(! empty($this->fk_fournprice)?"'".$this->db->escape($this->fk_fournprice)."'":"null"); $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/core/class/commonobject.class.php b/htdocs/core/class/commonobject.class.php index 6d8dfff5934..73d7e7b0e5d 100644 --- a/htdocs/core/class/commonobject.class.php +++ b/htdocs/core/class/commonobject.class.php @@ -2310,7 +2310,7 @@ abstract class CommonObject /** * Function to say how many lines object contains * - * @param int $predefined -1=All, 0=Count free product/service only, 1=Count predefined product/service only + * @param int $predefined -1=All, 0=Count free product/service only, 1=Count predefined product/service only, 2=Count predefined product, 3=Count predefined service * @return int <0 if KO, 0 if no predefined products, nb of lines with predefined products if found */ function hasProductsOrServices($predefined=-1) @@ -2323,6 +2323,8 @@ abstract class CommonObject if ($predefined == -1) $qualified=1; if ($predefined == 1 && $val->fk_product > 0) $qualified=1; if ($predefined == 0 && $val->fk_product <= 0) $qualified=1; + if ($predefined == 2 && $val->fk_product > 0 && $val->product_type==0) $qualified=1; + if ($predefined == 3 && $val->fk_product > 0 && $val->product_type==1) $qualified=1; if ($qualified) $nb++; } dol_syslog(get_class($this).'::hasProductsOrServices we found '.$nb.' qualified lines of products/servcies'); 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..8a836c7b3dc 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 +ReStockOnDeleteInvoice=Increase real stocks on invoice 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. @@ -86,4 +87,5 @@ PersonalStock=Personal stock %s ThisWarehouseIsPersonalStock=This warehouse represents personal stock of %s %s SelectWarehouseForStockDecrease=Choose warehouse to use for stock decrease SelectWarehouseForStockIncrease=Choose warehouse to use for stock increase +NoStockAction=No stock action LastWaitingSupplierOrders=Orders waiting for receptions \ No newline at end of file diff --git a/htdocs/langs/es_ES/agenda.lang b/htdocs/langs/es_ES/agenda.lang index e0131db59fe..70a768bec15 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 eliminada 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..be0bf800bb8 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 en la eliminación de 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. @@ -85,4 +86,5 @@ PersonalStock=Stock personal %s ThisWarehouseIsPersonalStock=Este almacén representa el stock personal de %s %s SelectWarehouseForStockDecrease=Seleccione el almacén a usar en el decremento de stock SelectWarehouseForStockIncrease=Seleccione el almacén a usar en el incremento de stock +NoStockAction=Sin acciones sobre el stock LastWaitingSupplierOrders=Pedidos en espera de recepción \ No newline at end of file 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..1b2daaf9521 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. @@ -86,4 +87,5 @@ PersonalStock=Stock personnel %s ThisWarehouseIsPersonalStock=Cet entrepôt représente le stock personnel de %s %s SelectWarehouseForStockDecrease=Sélectionner l'entrepôt à utiliser pour la décrémentation du stock SelectWarehouseForStockIncrease=Sélectionner l'entrepôt à utiliser pour l'incrémentation du stock +NoStockAction=Pas d'action sur l'entrepot LastWaitingSupplierOrders=Commandes en attente de réception \ No newline at end of file diff --git a/htdocs/product/class/html.formproduct.class.php b/htdocs/product/class/html.formproduct.class.php index 422f93eff16..45b0a129808 100644 --- a/htdocs/product/class/html.formproduct.class.php +++ b/htdocs/product/class/html.formproduct.class.php @@ -109,9 +109,10 @@ class FormProduct * @param int $empty 1=Can be empty, 0 if not * @param int $disabled 1=Select is disabled * @param int $fk_product Add quantity of stock in label for product with id fk_product. Nothing if 0. + * @param string $empty_label Empty label if needed (only if $empty=1) * @return string HTML select */ - function selectWarehouses($selected='',$htmlname='idwarehouse',$filtertype='',$empty=0,$disabled=0,$fk_product=0) + function selectWarehouses($selected='',$htmlname='idwarehouse',$filtertype='',$empty=0,$disabled=0,$fk_product=0,$empty_label='') { global $langs,$user; @@ -120,7 +121,7 @@ class FormProduct $this->loadWarehouses($fk_product); $out='