diff --git a/htdocs/core/ajax/row.php b/htdocs/core/ajax/row.php index 0b1106ca20a..9853faa8585 100644 --- a/htdocs/core/ajax/row.php +++ b/htdocs/core/ajax/row.php @@ -95,6 +95,8 @@ if (GETPOST('roworder', 'alpha', 3) && GETPOST('table_element_line', 'aZ09', 3) $perm = 1; } elseif ($table_element_line == 'facture_fourn_det' && $user->rights->fournisseur->facture->creer) { $perm = 1; + } elseif ($table_element_line == 'facture_fourn_det_rec' && $user->rights->fournisseur->facture->creer) { + $perm = 1; } elseif ($table_element_line == 'ecm_files' && $fk_element == 'fk_product' && (!empty($user->rights->produit->creer) || !empty($user->rights->service->creer))) { $perm = 1; } elseif ($table_element_line == 'ecm_files' && $fk_element == 'fk_ticket' && !empty($user->rights->ticket->write)) { diff --git a/htdocs/core/class/commonobject.class.php b/htdocs/core/class/commonobject.class.php index 2f8adb0225f..87f6ba693fc 100644 --- a/htdocs/core/class/commonobject.class.php +++ b/htdocs/core/class/commonobject.class.php @@ -3385,7 +3385,7 @@ abstract class CommonObject $MODULE = "MODULE_DISALLOW_UPDATE_PRICE_ORDER"; } elseif ($this->element == 'facture' || $this->element == 'invoice') { $MODULE = "MODULE_DISALLOW_UPDATE_PRICE_INVOICE"; - } elseif ($this->element == 'facture_fourn' || $this->element == 'supplier_invoice' || $this->element == 'invoice_supplier') { + } elseif ($this->element == 'facture_fourn' || $this->element == 'supplier_invoice' || $this->element == 'invoice_supplier' || $this->element == 'invoice_supplier_rec') { $MODULE = "MODULE_DISALLOW_UPDATE_PRICE_SUPPLIER_INVOICE"; } elseif ($this->element == 'order_supplier' || $this->element == 'supplier_order') { $MODULE = "MODULE_DISALLOW_UPDATE_PRICE_SUPPLIER_ORDER"; @@ -3430,6 +3430,9 @@ abstract class CommonObject $fieldtva = 'tva'; $fieldup = 'pu_ht'; } + if ($this->element == 'invoice_supplier_rec') { + $fieldup = 'pu_ht'; + } if ($this->element == 'expensereport') { $fieldup = 'value_unit'; } @@ -3580,7 +3583,7 @@ abstract class CommonObject if ($this->element == 'facture' || $this->element == 'facturerec') { $fieldtva = 'total_tva'; } - if ($this->element == 'facture_fourn' || $this->element == 'invoice_supplier') { + if ($this->element == 'facture_fourn' || $this->element == 'invoice_supplier' || $this->element == 'invoice_supplier_rec') { $fieldtva = 'total_tva'; } if ($this->element == 'propal') { @@ -8043,6 +8046,8 @@ abstract class CommonObject $element = $this->element; if ($element == 'facturerec') { $element = 'facture'; + } elseif ($element == 'invoice_supplier_rec') { + return $user->rights->fournisseur->facture; } return $user->rights->{$element}; diff --git a/htdocs/core/lib/invoice.lib.php b/htdocs/core/lib/invoice.lib.php index 1e4cdf16791..c6f972f46c8 100644 --- a/htdocs/core/lib/invoice.lib.php +++ b/htdocs/core/lib/invoice.lib.php @@ -200,7 +200,7 @@ function invoice_rec_prepare_head($object) $h = 0; $head = array(); - $head[$h][0] = DOL_URL_ROOT.'/compta/facture/card-rec.php?id='.$object->id; + $head[$h][0] = DOL_URL_ROOT . '/compta/facture/card-rec.php?id=' . $object->id; $head[$h][1] = $langs->trans("RepeatableInvoice"); $head[$h][2] = 'card'; $h++; @@ -216,6 +216,35 @@ function invoice_rec_prepare_head($object) return $head; } +/** + * Return array head with list of tabs to view object informations. + * + * @param Facture $object Invoice object + * @return array head array with tabs + */ +function supplier_invoice_rec_prepare_head($object) +{ + global $db, $langs, $conf; + + $h = 0; + $head = array(); + + $head[$h][0] = DOL_URL_ROOT . '/fourn/facture/card-rec.php?id=' . $object->id; + $head[$h][1] = $langs->trans("RepeatableSupplierInvoice"); + $head[$h][2] = 'card'; + $h++; + + // Show more tabs from modules + // Entries must be declared in modules descriptor with line + // $this->tabs = array('entity:+tabname:Title:@mymodule:/mymodule/mypage.php?id=__ID__'); to add new tab + // $this->tabs = array('entity:-tabname); to remove a tab + complete_head_from_modules($conf, $langs, $object, $head, $h, 'invoice_supplier_rec'); + + complete_head_from_modules($conf, $langs, $object, $head, $h, 'invoice_supplier_rec', 'remove'); + + return $head; +} + /** * Return a HTML table that contains a pie chart of customer invoices * diff --git a/htdocs/core/menus/standard/eldy.lib.php b/htdocs/core/menus/standard/eldy.lib.php index 58ddeb0fbf3..e69644bd123 100644 --- a/htdocs/core/menus/standard/eldy.lib.php +++ b/htdocs/core/menus/standard/eldy.lib.php @@ -1087,6 +1087,8 @@ function print_left_eldy_menu($db, $menu_array_before, $menu_array_after, &$tabM $newmenu->add("/fourn/facture/list.php?leftmenu=suppliers_bills_paid&search_status=2", $langs->trans("BillShortStatusPaid"), 2, $user->rights->fournisseur->facture->lire, '', $mainmenu, 'suppliers_bills_paid'); } + $newmenu->add("/fourn/facture/list-rec.php?leftmenu=supplierinvoicestemplate_list", $langs->trans("ListOfTemplates"), 1, $user->rights->fournisseur->facture->lire, '', $mainmenu, 'supplierinvoicestemplate_list'); + $newmenu->add("/fourn/paiement/list.php?leftmenu=suppliers_bills_payment", $langs->trans("Payments"), 1, $user->rights->fournisseur->facture->lire, '', $mainmenu, 'suppliers_bills_payment'); if ($usemenuhider || empty($leftmenu) || preg_match('/suppliers_bills/', $leftmenu)) { diff --git a/htdocs/core/modules/modFournisseur.class.php b/htdocs/core/modules/modFournisseur.class.php index 0f730f773bb..8bd801e0daa 100644 --- a/htdocs/core/modules/modFournisseur.class.php +++ b/htdocs/core/modules/modFournisseur.class.php @@ -129,6 +129,25 @@ class modFournisseur extends DolibarrModules 6=>array('file'=>'box_supplier_orders_awaiting_reception.php', 'enabledbydefaulton'=>'Home'), ); + $arraydate = dol_getdate(dol_now()); + $datestart = dol_mktime(23, 0, 0, $arraydate['mon'], $arraydate['mday'], $arraydate['year']); + $this->cronjobs = array( + 0 => array( + 'label'=>'RecurringSupplierInvoices', + 'jobtype'=>'method', + 'class'=>'fourn/class/fournisseur.facture-rec.class.php', + 'objectname'=>'FactureFournisseurRec', + 'method'=>'createRecurringInvoices', + 'parameters'=>'', + 'comment'=>'Generate recurring supplier invoices', + 'frequency'=>1, + 'unitfrequency'=>3600 * 24, + 'priority'=>50, + 'status'=>1, + 'datestart'=>$datestart + )); + + // Permissions $this->rights = array(); $this->rights_class = 'fournisseur'; diff --git a/htdocs/core/tpl/objectline_create.tpl.php b/htdocs/core/tpl/objectline_create.tpl.php index 8d21a789648..335754a8168 100644 --- a/htdocs/core/tpl/objectline_create.tpl.php +++ b/htdocs/core/tpl/objectline_create.tpl.php @@ -65,7 +65,7 @@ $colspan = 3; // Columns: total ht + col edit + col delete if (!empty($conf->multicurrency->enabled) && $this->multicurrency_code != $conf->currency) { $colspan++; //Add column for Total (currency) if required } -if (in_array($object->element, array('propal', 'commande', 'order', 'facture', 'facturerec', 'invoice', 'supplier_proposal', 'order_supplier', 'invoice_supplier'))) { +if (in_array($object->element, array('propal', 'commande', 'order', 'facture', 'facturerec', 'invoice', 'supplier_proposal', 'order_supplier', 'invoice_supplier', 'invoice_supplier_rec'))) { $colspan++; // With this, there is a column move button } @@ -89,6 +89,8 @@ if (!empty($extrafields)) { $objectline = new SupplierInvoiceLine($this->db); } elseif ($this->table_element_line == 'facturedet_rec') { $objectline = new FactureLigneRec($this->db); + } elseif ($this->table_element_line == 'facture_fourn_det_rec') { + $objectline = new FactureFournisseurLigneRec($this->db); } } print "\n"; @@ -103,7 +105,7 @@ if ($nolinesbefore) {
trans('AddNewLine'); ?> element == 'supplier_proposal' || $object->element == 'order_supplier' || $object->element == 'invoice_supplier') { // We must have same test in printObjectLines + if ($object->element == 'supplier_proposal' || $object->element == 'order_supplier' || $object->element == 'invoice_supplier' || $object->element == 'invoice_supplier_rec') { // We must have same test in printObjectLines ?> trans('SupplierRef'); ?> global->MAIN_DOLEDITOR_HEIGHT) ? 100 : $conf->global->MAIN_DOLEDITOR_HEIGHT), $toolbarname, '', false, true, $enabled, $nbrows, '98%'); $doleditor->Create(); // Show autofill date for recurring invoices - if (!empty($conf->service->enabled) && $object->element == 'facturerec') { + if (!empty($conf->service->enabled) && ($object->element == 'facturerec' || $object->element == 'invoice_supplier_rec')) { echo '

'; echo $langs->trans('AutoFillDateFrom').' '; echo $form->selectyesno('date_start_fill', $line->date_start_fill, 1); @@ -362,7 +364,7 @@ if ($nolinesbefore) { } } echo ''; - if ($object->element == 'supplier_proposal' || $object->element == 'order_supplier' || $object->element == 'invoice_supplier') { // We must have same test in printObjectLines + if ($object->element == 'supplier_proposal' || $object->element == 'order_supplier' || $object->element == 'invoice_supplier' || $object->element == 'invoice_supplier_rec') { // We must have same test in printObjectLines $coldisplay++; ?> "> diff --git a/htdocs/core/tpl/objectline_edit.tpl.php b/htdocs/core/tpl/objectline_edit.tpl.php index ea7b039b550..0f0043eadd6 100644 --- a/htdocs/core/tpl/objectline_edit.tpl.php +++ b/htdocs/core/tpl/objectline_edit.tpl.php @@ -66,7 +66,7 @@ $colspan = 3; // Col total ht + col edit + col delete if (!empty($inputalsopricewithtax)) { $colspan++; // We add 1 if col total ttc } -if (in_array($object->element, array('propal', 'supplier_proposal', 'facture', 'facturerec', 'invoice', 'commande', 'order', 'order_supplier', 'invoice_supplier'))) { +if (in_array($object->element, array('propal', 'supplier_proposal', 'facture', 'facturerec', 'invoice', 'commande', 'order', 'order_supplier', 'invoice_supplier', 'invoice_supplier_rec'))) { $colspan++; // With this, there is a column move button } if (!empty($conf->multicurrency->enabled) && $this->multicurrency_code != $conf->currency) { @@ -170,7 +170,11 @@ $coldisplay++; } // Show autofill date for recuring invoices - if (!empty($conf->service->enabled) && $line->product_type == 1 && $line->element == 'facturedetrec') { + if (!empty($conf->service->enabled) && $line->product_type == 1 && ($line->element == 'facturedetrec' || $line->element == 'invoice_supplier_det_rec')) { + if ($line->element == 'invoice_supplier_det_rec') { + $line->date_start_fill = $line->date_start; + $line->date_end_fill = $line->date_end; + } echo '
'; echo $langs->trans('AutoFillDateFrom').' '; echo $form->selectyesno('date_start_fill', GETPOSTISSET('date_start_fill') ? GETPOST('date_start_fill', 'int') : $line->date_start_fill, 1); @@ -183,7 +187,7 @@ $coldisplay++; element == 'supplier_proposal' || $object->element == 'order_supplier' || $object->element == 'invoice_supplier') { // We must have same test in printObjectLines + if ($object->element == 'supplier_proposal' || $object->element == 'order_supplier' || $object->element == 'invoice_supplier' || $object->element == 'invoice_supplier_rec') { // We must have same test in printObjectLines $coldisplay++; ?> diff --git a/htdocs/core/tpl/objectline_title.tpl.php b/htdocs/core/tpl/objectline_title.tpl.php index e1f89b18937..0f86289dfe1 100644 --- a/htdocs/core/tpl/objectline_title.tpl.php +++ b/htdocs/core/tpl/objectline_title.tpl.php @@ -55,7 +55,7 @@ if (!empty($conf->global->MAIN_VIEW_LINE_NUMBER)) { print ''.$langs->trans('Description').''; // Supplier ref -if ($this->element == 'supplier_proposal' || $this->element == 'order_supplier' || $this->element == 'invoice_supplier') { +if ($this->element == 'supplier_proposal' || $this->element == 'order_supplier' || $this->element == 'invoice_supplier' || $this->element == 'invoice_supplier_rec') { print ''.$langs->trans("SupplierRef").''; } diff --git a/htdocs/core/tpl/objectline_view.tpl.php b/htdocs/core/tpl/objectline_view.tpl.php index c4ddc7d0c4c..36eceb87341 100644 --- a/htdocs/core/tpl/objectline_view.tpl.php +++ b/htdocs/core/tpl/objectline_view.tpl.php @@ -162,7 +162,11 @@ if (($line->info_bits & 2) == 2) { } // Show date range - if ($line->element == 'facturedetrec') { + if ($line->element == 'facturedetrec' || $line->element == 'invoice_supplier_det_rec') { + if ($line->element == 'invoice_supplier_det_rec' && $line->product_type != Product::TYPE_PRODUCT) { + $line->date_start_fill = $line->date_start; + $line->date_end_fill = $line->date_end; + } if ($line->date_start_fill || $line->date_end_fill) { print '
'; } @@ -202,6 +206,8 @@ if (($line->info_bits & 2) == 2) { if ($line->fk_product > 0 && !empty($conf->global->PRODUIT_DESC_IN_FORM)) { if ($line->element == 'facturedetrec') { print (!empty($line->description) && $line->description != $line->product_label) ? (($line->date_start_fill || $line->date_end_fill) ? '' : '
').'
'.dol_htmlentitiesbr($line->description) : ''; + } elseif ($line->element == 'invoice_supplier_det_rec') { + print (!empty($line->description) && $line->description != $line->label) ? (($line->date_start || $line->date_end) ? '' : '
').'
'.dol_htmlentitiesbr($line->description) : ''; } else { print (!empty($line->description) && $line->description != $line->product_label) ? (($line->date_start || $line->date_end) ? '' : '
').'
'.dol_htmlentitiesbr($line->description) : ''; } @@ -239,7 +245,7 @@ if (!empty($conf->accounting->enabled) && $line->fk_accounting_account > 0) { } print ''; -if ($object->element == 'supplier_proposal' || $object->element == 'order_supplier' || $object->element == 'invoice_supplier') { // We must have same test in printObjectLines +if ($object->element == 'supplier_proposal' || $object->element == 'order_supplier' || $object->element == 'invoice_supplier' || $object->element == 'invoice_supplier_rec') { // We must have same test in printObjectLines print ''; print ($line->ref_fourn ? $line->ref_fourn : $line->ref_supplier); print ''; diff --git a/htdocs/fourn/class/fournisseur.facture-rec.class.php b/htdocs/fourn/class/fournisseur.facture-rec.class.php new file mode 100644 index 00000000000..f77db53e116 --- /dev/null +++ b/htdocs/fourn/class/fournisseur.facture-rec.class.php @@ -0,0 +1,2193 @@ + + * Copyright (C) 2004-2019 Laurent Destailleur + * Copyright (C) 2009-2012 Regis Houssin + * Copyright (C) 2010-2011 Juanjo Menent + * Copyright (C) 2012 Cedric Salvador + * Copyright (C) 2013 Florian Henry + * Copyright (C) 2015 Marcos García + * Copyright (C) 2017-2020 Frédéric France + * + * 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/fourn/facture/class/fournisseur.facture-rec.class.php + * \ingroup facture + * \brief Fichier de la classe des factures fournisseursrecurentes + */ + +require_once DOL_DOCUMENT_ROOT.'/core/class/notify.class.php'; +require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php'; +require_once DOL_DOCUMENT_ROOT.'/fourn/class/fournisseur.facture.class.php'; +require_once DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php'; + + +/** + * Class to manage invoice templates + */ +class FactureFournisseurRec extends CommonInvoice +{ + /** + * @var string ID to identify managed object + */ + public $element = 'invoice_supplier_rec'; + + /** + * @var string Name of table without prefix where object is stored + */ + public $table_element = 'facture_fourn_rec'; + + /** + * @var string Name of subtable line + */ + public $table_element_line = 'facture_fourn_det_rec'; + + /** + * @var string Field with ID of parent key if this field has a parent + */ + public $fk_element = 'fk_facture_fourn'; + + /** + * @var string String with name of icon for myobject. Must be the part after the 'object_' into object_myobject.png + */ + public $picto = 'bill'; + + /** + * {@inheritdoc} + */ + protected $table_ref_field = 'titre'; + + /** + * @var string The label of recurring invoice + */ + public $titre; + public $ref_supplier; + public $socid; + + public $suspended; + public $libelle; + public $amount; + public $remise; + public $vat_src_code; + public $localtax1; + public $localtax2; + + public $user_author; + public $user_modif; + public $fk_project; + + public $mode_reglement_id; + public $mode_reglement_code; + public $cond_reglement_code; + public $cond_reglement_doc; + public $cond_reglement_id; + + public $date_lim_reglement; + + public $fk_multicurrency; + public $multicurrency_code; + public $multicurrency_tx; + public $multicurrency_total_ht; + public $multicurrency_total_tva; + public $multicurrency_total_ttc; + + public $usenewprice = 0; + public $frequency; + public $unit_frequency; + public $date_when; + public $date_last_gen; + public $nb_gen_done; + public $nb_gen_max; + public $auto_validate; // 0 to create in draft, 1 to create and validate the new invoice + public $generate_pdf; // 1 to generate PDF on invoice generation (default) + + public $model_pdf; + + /* Override fields in CommonObject + public $entity; + public $date_creation; + public $date_modification; + public $total_ht; + public $total_tva; + public $total_ttc; + public $fk_account; + public $mode_reglement; + public $cond_reglement; + public $note_public; + public $note_private; + */ + + /** + * 'type' if the field format ('integer', 'integer:ObjectClass:PathToClass[:AddCreateButtonOrNot[:Filter]]', 'varchar(x)', 'double(24,8)', 'real', 'price', 'text', 'html', 'date', 'datetime', 'timestamp', 'duration', 'mail', 'phone', 'url', 'password') + * Note: Filter can be a string like "(t.ref:like:'SO-%') or (t.date_creation:<:'20160101') or (t.nature:is:NULL)" + * 'label' the translation key. + * 'enabled' is a condition when the field must be managed. + * 'position' is the sort order of field. + * 'notnull' is set to 1 if not null in database. Set to -1 if we must set data to null if empty ('' or 0). + * 'visible' says if field is visible in list (Examples: 0=Not visible, 1=Visible on list and create/update/view forms, 2=Visible on list only, 3=Visible on create/update/view form only (not list), 4=Visible on list and update/view form only (not create). 5=Visible on list and view only (not create/not update). Using a negative value means field is not shown by default on list but can be selected for viewing) + * 'noteditable' says if field is not editable (1 or 0) + * 'default' is a default value for creation (can still be overwrote by the Setup of Default Values if field is editable in creation form). Note: If default is set to '(PROV)' and field is 'ref', the default value will be set to '(PROVid)' where id is rowid when a new record is created. + * 'index' if we want an index in database. + * 'foreignkey'=>'tablename.field' if the field is a foreign key (it is recommanded to name the field fk_...). + * 'searchall' is 1 if we want to search in this field when making a search from the quick search button. + * 'isameasure' must be set to 1 if you want to have a total on list for this field. Field type must be summable like integer or double(24,8). + * 'css' is the CSS style to use on field. For example: 'maxwidth200' + * 'help' is a string visible as a tooltip on field + * 'showoncombobox' if value of the field must be visible into the label of the combobox that list record + * 'disabled' is 1 if we want to have the field locked by a 'disabled' attribute. In most cases, this is never set into the definition of $fields into class, but is set dynamically by some part of code. + * 'arrayofkeyval' to set list of value if type is a list of predefined values. For example: array("0"=>"Draft","1"=>"Active","-1"=>"Cancel") + * 'comment' is not used. You can store here any text of your choice. It is not used by application. + * + * Note: To have value dynamic, you can set value to 0 in definition and edit the value on the fly into the constructor. + */ + + // BEGIN MODULEBUILDER PROPERTIES + /** + * @var array Array with all fields and their property. Do not use it as a static var. It may be modified by constructor. + */ + public $fields = array( + 'rowid' =>array('type'=>'integer', 'label'=>'TechnicalID', 'enabled'=>1, 'visible'=>-1, 'notnull'=>1, 'position'=>10), + 'titre' =>array('type'=>'varchar(100)', 'label'=>'Titre', 'enabled'=>1, 'showoncombobox' => 1, 'visible'=>-1, 'position'=>15), + 'ref_supplier' =>array('type'=>'varchar(180)', 'label'=>'RefSupplier', 'enabled'=>1, 'showoncombobox' => 1, 'visible'=>-1, 'position'=>20), + 'entity' =>array('type'=>'integer', 'label'=>'Entity', 'default'=>1, 'enabled'=>1, 'visible'=>-2, 'notnull'=>1, 'position'=>25, 'index'=>1), + 'fk_soc' =>array('type'=>'integer:Societe:societe/class/societe.class.php', 'label'=>'ThirdParty', 'enabled'=>1, 'visible'=>-1, 'notnull'=>1, 'position'=>30), + 'datec' =>array('type'=>'datetime', 'label'=>'DateCreation', 'enabled'=>1, 'visible'=>-1, 'position'=>35), + 'tms' =>array('type'=>'timestamp', 'label'=>'DateModification', 'enabled'=>1, 'visible'=>-1, 'notnull'=>1, 'position'=>40), + 'suspended' =>array('type'=>'integer', 'label'=>'Suspended', 'enabled'=>1, 'visible'=>-1, 'position'=>225), + 'libelle' =>array('type'=>'varchar(100)', 'label'=>'Libelle', 'enabled'=>1, 'showoncombobox' => 0, 'visible'=>-1, 'position'=>15), + 'amount' =>array('type'=>'double(24,8)', 'label'=>'Amount', 'enabled'=>1, 'visible'=>-1, 'notnull'=>1, 'position'=>35), + 'remise' =>array('type'=>'double', 'label'=>'Remise', 'enabled'=>1, 'visible'=>-1, 'position'=>40), + + 'localtax1' =>array('type'=>'double(24,8)', 'label'=>'Localtax1', 'enabled'=>1, 'visible'=>-1, 'position'=>60, 'isameasure'=>1), + 'localtax2' =>array('type'=>'double(24,8)', 'label'=>'Localtax2', 'enabled'=>1, 'visible'=>-1, 'position'=>65, 'isameasure'=>1), + 'total_ht' =>array('type'=>'double(24,8)', 'label'=>'Total', 'enabled'=>1, 'visible'=>-1, 'position'=>70, 'isameasure'=>1), + 'total_tva' =>array('type'=>'double(24,8)', 'label'=>'Tva', 'enabled'=>1, 'visible'=>-1, 'position'=>55, 'isameasure'=>1), + 'total_ttc' =>array('type'=>'double(24,8)', 'label'=>'Total ttc', 'enabled'=>1, 'visible'=>-1, 'position'=>75, 'isameasure'=>1), + + 'fk_user_author' =>array('type'=>'integer:User:user/class/user.class.php', 'label'=>'Fk user author', 'enabled'=>1, 'visible'=>-1, 'position'=>80), + 'fk_user_modif' =>array('type'=>'integer:User:user/class/user.class.php', 'label'=>'UserModif', 'enabled'=>1, 'visible'=>-2, 'notnull'=>-1, 'position'=>210), + 'fk_projet' =>array('type'=>'integer:Project:projet/class/project.class.php:1:fk_statut=1', 'label'=>'Fk projet', 'enabled'=>1, 'visible'=>-1, 'position'=>85), + 'fk_account' =>array('type'=>'integer', 'label'=>'Fk account', 'enabled'=>1, 'visible'=>-1, 'position'=>175), + 'fk_cond_reglement' =>array('type'=>'integer', 'label'=>'Fk cond reglement', 'enabled'=>1, 'visible'=>-1, 'position'=>90), + 'fk_mode_reglement' =>array('type'=>'integer', 'label'=>'Fk mode reglement', 'enabled'=>1, 'visible'=>-1, 'position'=>95), + 'date_lim_reglement' =>array('type'=>'date', 'label'=>'Date lim reglement', 'enabled'=>1, 'visible'=>-1, 'position'=>100), + + 'note_private' =>array('type'=>'text', 'label'=>'NotePublic', 'enabled'=>1, 'visible'=>0, 'position'=>105), + 'note_public' =>array('type'=>'text', 'label'=>'NotePrivate', 'enabled'=>1, 'visible'=>0, 'position'=>110), + 'modelpdf' =>array('type'=>'varchar(255)', 'label'=>'Modelpdf', 'enabled'=>1, 'visible'=>-1, 'position'=>115), + + 'fk_multicurrency' =>array('type'=>'integer', 'label'=>'Fk multicurrency', 'enabled'=>1, 'visible'=>-1, 'position'=>180), + 'multicurrency_code' =>array('type'=>'varchar(255)', 'label'=>'Multicurrency code', 'enabled'=>1, 'visible'=>-1, 'position'=>185), + 'multicurrency_tx' =>array('type'=>'double(24,8)', 'label'=>'Multicurrency tx', 'enabled'=>1, 'visible'=>-1, 'position'=>190, 'isameasure'=>1), + 'multicurrency_total_ht' =>array('type'=>'double(24,8)', 'label'=>'Multicurrency total ht', 'enabled'=>1, 'visible'=>-1, 'position'=>195, 'isameasure'=>1), + 'multicurrency_total_tva' =>array('type'=>'double(24,8)', 'label'=>'Multicurrency total tva', 'enabled'=>1, 'visible'=>-1, 'position'=>200, 'isameasure'=>1), + 'multicurrency_total_ttc' =>array('type'=>'double(24,8)', 'label'=>'Multicurrency total ttc', 'enabled'=>1, 'visible'=>-1, 'position'=>205, 'isameasure'=>1), + + 'usenewprice' =>array('type'=>'integer', 'label'=>'UseNewPrice', 'enabled'=>1, 'visible'=>0, 'position'=>155), + 'frequency' =>array('type'=>'integer', 'label'=>'Frequency', 'enabled'=>1, 'visible'=>-1, 'position'=>150), + 'unit_frequency' =>array('type'=>'varchar(2)', 'label'=>'Unit frequency', 'enabled'=>1, 'visible'=>-1, 'position'=>125), + + 'date_when' =>array('type'=>'datetime', 'label'=>'Date when', 'enabled'=>1, 'visible'=>-1, 'position'=>130), + 'date_last_gen' =>array('type'=>'datetime', 'label'=>'Date last gen', 'enabled'=>1, 'visible'=>-1, 'position'=>135), + 'nb_gen_done' =>array('type'=>'integer', 'label'=>'Nb gen done', 'enabled'=>1, 'visible'=>-1, 'position'=>140), + 'nb_gen_max' =>array('type'=>'integer', 'label'=>'Nb gen max', 'enabled'=>1, 'visible'=>-1, 'position'=>145), + 'revenuestamp' =>array('type'=>'double(24,8)', 'label'=>'RevenueStamp', 'enabled'=>1, 'visible'=>-1, 'position'=>160, 'isameasure'=>1), + 'auto_validate' =>array('type'=>'integer', 'label'=>'Auto validate', 'enabled'=>1, 'visible'=>-1, 'position'=>165), + 'generate_pdf' =>array('type'=>'integer', 'label'=>'Generate pdf', 'enabled'=>1, 'visible'=>-1, 'position'=>170), + + ); + // END MODULEBUILDER PROPERTIES + + const STATUS_NOTSUSPENDED = 0; + const STATUS_SUSPENDED = 1; + + + + /** + * Constructor + * + * @param DoliDB $db Database handler + */ + public function __construct($db) + { + $this->db = $db; + } + + /** + * Create a predefined supplier invoice + * + * @param User $user User object + * @param int $facFournId + * @param int $notrigger No trigger + * @return int <0 if KO, id of invoice created if OK + */ + public function create($user, $facFournId, $notrigger = 0) + { + global $conf; + + $error = 0; + $now = dol_now(); + + // Clean parameters + $this->titre = empty($this->titre) ? '' : $this->titre; + $this->ref_supplier = empty($this->ref_supplier) ? '' : $this->ref_supplier; + $this->usenewprice = empty($this->usenewprice) ? 0 : $this->usenewprice; + $this->suspended = empty($this->suspended) ? 0 : $this->suspended; + // No frequency defined then no next date to execution + if (empty($this->frequency)) { + $this->frequency = 0; + $this->date_when = null; + } + $this->frequency = abs($this->frequency); + $this->nb_gen_done = 0; + $this->nb_gen_max = empty($this->nb_gen_max) ? 0 : $this->nb_gen_max; + $this->auto_validate = empty($this->auto_validate) ? 0 : $this->auto_validate; + $this->generate_pdf = empty($this->generate_pdf) ? 0 : $this->generate_pdf; + + $this->db->begin(); + + // On charge la facture fournisseur depuis laquelle on crée la facture fournisseur modèle + $facfourn_src = new FactureFournisseur($this->db); + $result = $facfourn_src->fetch($facFournId); + if ($result > 0) { + + $sql = 'INSERT INTO '.MAIN_DB_PREFIX.'facture_fourn_rec ('; + $sql .= 'titre'; + $sql .= ', ref_supplier'; + $sql .= ', entity'; + $sql .= ', fk_soc'; + $sql .= ', datec'; + $sql .= ', suspended'; + $sql .= ', libelle'; + $sql .= ', amount'; + $sql .= ', remise'; + $sql .= ', fk_user_author'; + $sql .= ', fk_projet'; + $sql .= ', fk_account'; + $sql .= ', fk_cond_reglement'; + $sql .= ', fk_mode_reglement'; + $sql .= ', date_lim_reglement'; + $sql .= ', note_private'; + $sql .= ', note_public'; + $sql .= ', modelpdf'; + $sql .= ', fk_multicurrency'; + $sql .= ', multicurrency_code'; + $sql .= ', multicurrency_tx'; + $sql .= ', usenewprice'; + $sql .= ', frequency'; + $sql .= ', unit_frequency'; + $sql .= ', date_when'; + $sql .= ', date_last_gen'; + $sql .= ', nb_gen_done'; + $sql .= ', nb_gen_max'; + $sql .= ', auto_validate'; + $sql .= ', generate_pdf'; + $sql .= ') VALUES ('; + $sql .= "'".$this->db->escape($this->titre)."'"; + $sql .= ", '".$this->db->escape($this->ref_supplier)."'"; + $sql .= ', ' . (int) $conf->entity; + $sql .= ', ' . (int) $facfourn_src->socid; + $sql .= ", '".$this->db->idate($now)."'"; + $sql .= ', ' . (int) $this->suspended; + if (!empty(GETPOST('libelle'))){ + $sql .= ", '" . $this->db->escape(GETPOST('libelle')) . "'"; + } elseif (! empty($this->libelle)) { + $sql .= ", '" . $this->db->escape($this->libelle) . "'"; + } else { + $sql .= ", ''"; + } + $sql .= ', ' .(!empty($facfourn_src->total_ttc) ? (float) $facfourn_src->total_ttc : '0'); // amount + $sql .= ', ' .(!empty($facfourn_src->remise) ? (float) $facfourn_src->remise : '0'); + $sql .= ', ' . (int) $user->id; + $sql .= ', ' .(!empty($this->fk_project) ? $this->fk_project : 'NULL'); // Fields declarded on creation + $sql .= ', ' .(!empty($facfourn_src->fk_account) ? $facfourn_src->fk_account : 'NULL'); + $sql .= ', ' .($this->cond_reglement_id > 0 ? (int) $this->cond_reglement_id : 'NULL'); + $sql .= ', ' .($this->mode_reglement_id > 0 ? (int) $this->mode_reglement_id : 'NULL'); + $sql .= ", '".($facfourn_src->date_echeance > 0 ? $this->db->idate($facfourn_src->date_echeance) : 'NULL')."'"; // date_lim_reglement + $sql .= ', ' .(!empty($this->note_private) ? "'".$this->db->escape($this->note_private)."'" : 'NULL'); // Fields declarded on creation + $sql .= ', ' .(!empty($this->note_public) ? "'".$this->db->escape($this->note_public)."'" : 'NULL'); // Fields declarded on creation + $sql .= ', ' .(!empty($this->model_pdf) ? "'".$this->db->escape($this->model_pdf)."'" : 'NULL'); // Fields declarded on creation + $sql .= ', ' . (int) $facfourn_src->fk_multicurrency; + $sql .= ", '".$this->db->escape($facfourn_src->multicurrency_code)."'"; + $sql .= ', ' . (float) $facfourn_src->multicurrency_tx; + $sql .= ', ' . (int) $this->usenewprice; // Fields declarded on creation + $sql .= ', ' . (int) $this->frequency; // Fields declarded on creation + $sql .= ", '".$this->db->escape($this->unit_frequency)."'"; // Fields declarded on creation + $sql .= ', ' .(!empty($this->date_when) ? "'".$this->db->idate($this->date_when)."'" : 'NULL'); // Fields declarded on creation + $sql .= ', ' .(!empty($this->date_last_gen) ? "'".$this->db->idate($this->date_last_gen)."'" : 'NULL'); // Fields declarded on creation + $sql .= ', ' . (int) $this->nb_gen_done; // Fields declarded on creation + $sql .= ', ' . (int) $this->nb_gen_max; // Fields declarded on creation + $sql .= ', ' . (int) $this->auto_validate; // Fields declarded on creation + $sql .= ', ' . (int) $this->generate_pdf; // Fields declarded on creation + $sql .= ')'; + + if ($this->db->query($sql)) { + $this->id = $this->db->last_insert_id(MAIN_DB_PREFIX. 'facture_fourn_rec'); + + // Fields used into addline later + $this->fk_multicurrency = $facfourn_src->fk_multicurrency; + + $this->multicurrency_code = $facfourn_src->multicurrency_code; + $this->multicurrency_tx = $facfourn_src->multicurrency_tx; + + // Add lines + $num = count($facfourn_src->lines); + for ($i = 0; $i < $num; $i++) { + $tva_tx = $facfourn_src->lines[$i]->tva_tx; + if (!empty($facfourn_src->lines[$i]->vat_src_code) && !preg_match('/\(/', $tva_tx)) { + $tva_tx .= ' ('.$facfourn_src->lines[$i]->vat_src_code.')'; + } + + $result_insert = $this->addline( + $facfourn_src->lines[$i]->fk_product, + $facfourn_src->lines[$i]->ref_supplier, + $facfourn_src->lines[$i]->label, + $facfourn_src->lines[$i]->description, + $facfourn_src->lines[$i]->pu_ht, + $facfourn_src->lines[$i]->pu_ttc, + $facfourn_src->lines[$i]->qty, + $facfourn_src->lines[$i]->remise_percent, + $tva_tx, + $facfourn_src->lines[$i]->localtax1_tx, + $facfourn_src->lines[$i]->localtax2_tx, + 'HT', + $facfourn_src->lines[$i]->product_type, + $facfourn_src->lines[$i]->date_start, + $facfourn_src->lines[$i]->date_end, + $facfourn_src->lines[$i]->info_bits, + $facfourn_src->lines[$i]->special_code, + $facfourn_src->lines[$i]->rang, + $facfourn_src->lines[$i]->fk_unit + ); + + if ($result_insert < 0) { + $error++; + } else { + $objectline = new FactureFournisseurLigneRec($this->db); + + $result2 = $objectline->fetch($result_insert); + if ($result2 > 0) { + // Extrafields + if (method_exists($facfourn_src->lines[$i], 'fetch_optionals')) { + $facfourn_src->lines[$i]->fetch_optionals($facfourn_src->lines[$i]->id); + $objectline->array_options = $facfourn_src->lines[$i]->array_options; + } + + $result = $objectline->insertExtraFields(); + if ($result < 0) { + $error++; + } + } elseif ($result2 < 0) { + $this->errors[] = $objectline->error; + $error++; + } + } + } + + if (!empty($this->linkedObjectsIds) && empty($this->linked_objects)) { // To use new linkedObjectsIds instead of old linked_objects + $this->linked_objects = $this->linkedObjectsIds; // TODO Replace linked_objects with linkedObjectsIds + } + + // Add object linked + if (!$error && $this->id && !empty($this->linked_objects) && is_array($this->linked_objects)) { + foreach ($this->linked_objects as $origin => $tmp_origin_id) { + if (is_array($tmp_origin_id)) { // New behaviour, if linked_object can have several links per type, so is something like array('contract'=>array(id1, id2, ...)) + foreach ($tmp_origin_id as $origin_id) { + $ret = $this->add_object_linked($origin, $origin_id); + if (!$ret) { + $this->error = $this->db->lasterror(); + $error++; + } + } + } else // Old behaviour, if linked_object has only one link per type, so is something like array('contract'=>id1)) + { + $origin_id = $tmp_origin_id; + $ret = $this->add_object_linked($origin, $origin_id); + if (!$ret) { + $this->error = $this->db->lasterror(); + $error++; + } + } + } + } + + if (!$error) { + $result = $this->insertExtraFields(); + if ($result < 0) { + $error++; + } + } + + if (!$error && !$notrigger) { + // Call trigger + $result = $this->call_trigger('SUPPLIERBILLREC_CREATE', $user); + if ($result < 0) { + $this->db->rollback(); + return -2; + } + // End call triggers + } + + if ($error) { + $this->db->rollback(); + return -3; + } else { + $this->db->commit(); + return $this->id; + } + } else { + $this->error = $this->db->lasterror(); + $this->db->rollback(); + return -2; + } + } else { + $this->db->rollback(); + return -1; + } + } + + + /** + * Update fourn_invoice_rec. + * + * @param User $user User + * @param int $notrigger No trigger + * @return int <0 if KO, Id of line if OK + */ + public function update(User $user, $notrigger = 0) + { + global $conf; + + $error = 0; + + $sql = "UPDATE ".MAIN_DB_PREFIX."facture_fourn_rec SET"; + $sql .= ' titre = "' . (!empty($this->titre) ? $this->titre .'",' : '"",') ; + $sql .= ' ref_supplier = "'. (!empty($this->ref_supplier) ? $this->ref_supplier .'",' : '" ",'); + $sql .= " entity = ". (!empty($this->entity) ? $this->entity : 1) . ','; + if ($this->fk_soc > 0) $sql .= " fk_soc = ". (int) $this->fk_soc. ','; + $sql .= ' tms = "'. date('Y-m-d H:i:s', dol_now()) . '",'; + $sql .= " suspended = ". (!empty($this->suspended) ? $this->suspended : 0) . ','; + $sql .= ' libelle = "'. (!empty($this->libelle) ? $this->libelle : 'NULL') . '",'; + $sql .= " amount = ". (!empty($this->amount) ? $this->amount : 0.00) . ','; + $sql .= " remise = ". (!empty($this->remise) ? $this->remise : 'NULL') . ','; + $sql .= " vat_src_code = ". (!empty($this->vat_src_code) ? $this->vat_src_code : 'NULL') . ','; + $sql .= " localtax1 = ". (!empty($this->localtax1) ? $this->localtax1 : 0.00) . ','; + $sql .= " localtax2 = ". (!empty($this->localtax2) ? $this->localtax2 : 0.00) . ','; + $sql .= " total_ht = ". (!empty($this->total_ht) ? $this->total_ht : 0.00) . ','; + $sql .= " total_tva = ". (!empty($this->total_tva) ? $this->total_tva : 0.00) . ','; + $sql .= " total_ttc = ". (!empty($this->total_ttc) ? $this->total_ttc : 0.00) . ','; + $sql .= " fk_user_modif = ". $user->id . ','; + $sql .= " fk_projet = ". (!empty($this->fk_project) ? $this->fk_project : 'NULL') . ','; + $sql .= " fk_account = ". (!empty($this->fk_account) ? $this->fk_account : 'NULL') . ','; + $sql .= " fk_mode_reglement = ". (!empty($this->mode_reglement_id) ? $this->mode_reglement_id : 'NULL') . ','; + $sql .= " fk_cond_reglement = ". (!empty($this->cond_reglement_id) ? $this->cond_reglement_id : 'NULL') . ','; + $sql .= " date_lim_reglement = ". (!empty($this->date_lim_reglement) ? '"'.date("Y-m-d H:i:s", $this->date_lim_reglement).'"' : 'NULL') . ','; + $sql .= ' note_private = "'. (!empty($this->note_private) ? $this->note_private : '') . '",'; + $sql .= ' note_public = "'. (!empty($this->note_public) ? $this->note_public : '') . '",'; + $sql .= ' modelpdf = "'. (!empty($this->model_pdf) ? $this->model_pdf : 'NULL') . '",'; + $sql .= " fk_multicurrency = ". (!empty($this->fk_multicurrency) ? $this->fk_multicurrency : 'NULL') . ','; + $sql .= ' multicurrency_code = "'. (!empty($this->multicurrency_code) ? $this->multicurrency_code : 'NULL') . '",'; + $sql .= " multicurrency_tx = ". (!empty($this->multicurrency_tx) ? $this->multicurrency_tx : 1) . ','; + $sql .= " multicurrency_total_ht = ". (!empty($this->multicurrency_total_ht) ? $this->multicurrency_total_ht : 0.00) . ','; + $sql .= " multicurrency_total_tva = ". (!empty($this->multicurrency_total_tva) ? $this->multicurrency_total_tva : 0.00) . ','; + $sql .= " multicurrency_total_ttc = ". (!empty($this->multicurrency_total_ttc) ? $this->multicurrency_total_ttc : 0.00) . ','; + $sql .= " usenewprice = ". (!empty($this->usenewprice) ? $this->usenewprice : 0) . ','; + $sql .= " frequency = ". (!empty($this->frequency) ? $this->frequency : 0). ','; + $sql .= ' unit_frequency = "'. (!empty($this->unit_frequency) ? $this->unit_frequency : 0). '",'; + $sql .= " date_when = ". (!empty($this->date_when) ? '"'.date("Y-m-d H:i:s", $this->date_when).'"' : 0) . ','; + $sql .= " date_last_gen = ". (!empty($this->date_last_gen) ? '"'.date("Y-m-d H:i:s", $this->date_last_gen).'"' : 0) . ','; + $sql .= " nb_gen_done = ". (!empty($this->nb_gen_done) ? $this->nb_gen_done : 0) . ','; + $sql .= " nb_gen_max = ". (!empty($this->nb_gen_max) ? $this->nb_gen_max : 0) . ','; + $sql .= " auto_validate = ". (!empty($this->auto_validate) ? $this->auto_validate : 0); + $sql .= " WHERE rowid = ". (int) $this->id; + + dol_syslog(get_class($this)."::update", LOG_DEBUG); + $resql = $this->db->query($sql); + if ($resql) { + if (!$error) { + $result = $this->insertExtraFields(); + if ($result < 0) { + $error++; + } + } + + if (!$error && !$notrigger) { + // Call trigger + $result = $this->call_trigger('BILLREC_UPDATE', $user); + if ($result < 0) { + $this->db->rollback(); + return -2; + } + // End call triggers + } + $this->db->commit(); + return 1; + } else { + $this->error = $this->db->lasterror(); + $this->db->rollback(); + return -2; + } + } + + /** + * Load object and lines + * + * @param int $rowid Id of object to load + * @param string $ref Reference of recurring invoice + * @param string $ref_ext External reference of invoice + * @return int >0 if OK, <0 if KO, 0 if not found + */ + public function fetch($rowid, $ref = '', $ref_ext = '') + { + $sql = 'SELECT f.rowid, f.titre, f.ref_supplier, f.entity, f.fk_soc'; + $sql .= ', f.datec, f.tms, f.suspended'; + $sql .= ', f.libelle, f.amount, f.remise'; + $sql .= ', f.vat_src_code, f.localtax1, f.localtax2'; + $sql .= ', f.total_tva, f.total_ht, f.total_ttc'; + $sql .= ', f.fk_user_author, f.fk_user_modif'; + $sql .= ', f.fk_projet, f.fk_account'; + $sql .= ', f.fk_mode_reglement, p.code as mode_reglement_code, p.libelle as mode_reglement_libelle'; + $sql .= ', f.fk_cond_reglement, c.code as cond_reglement_code, c.libelle as cond_reglement_libelle, c.libelle_facture as cond_reglement_libelle_doc'; + $sql .= ', f.date_lim_reglement'; + $sql .= ', f.note_private, f.note_public, f.modelpdf'; + $sql .= ', f.fk_multicurrency, f.multicurrency_code, f.multicurrency_tx, f.multicurrency_total_ht, f.multicurrency_total_tva, f.multicurrency_total_ttc'; + $sql .= ', f.usenewprice, f.frequency, f.unit_frequency, f.date_when, f.date_last_gen, f.nb_gen_done, f.nb_gen_max, f.auto_validate'; + $sql .= ', f.generate_pdf'; + $sql .= ' FROM '.MAIN_DB_PREFIX.'facture_fourn_rec 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 IN ('.getEntity('invoice').')'; + if ($rowid) { + $sql .= ' AND f.rowid='. (int) $rowid; + } elseif ($ref) { + $sql .= " AND f.titre='".$this->db->escape($ref)."'"; + } else { + $sql .= ' AND f.rowid = 0'; + } + + $result = $this->db->query($sql); + if ($result) { + if ($this->db->num_rows($result)) { + $obj = $this->db->fetch_object($result); + + $this->id = $obj->rowid; + $this->titre = $obj->titre; + $this->ref_supplier = $obj->ref_supplier; + $this->entity = $obj->entity; + $this->socid = $obj->fk_soc; + $this->date_creation = $obj->datec; + $this->date_modification = $obj->tms; + $this->suspended = $obj->suspended; + $this->libelle = $obj->libelle; + $this->amount = $obj->amount; + $this->remise = $obj->remise; + $this->vat_src_code = $obj->vat_src_code; + $this->total_localtax1 = $obj->localtax1; + $this->total_localtax2 = $obj->localtax2; + $this->total_ht = $obj->total_ht; + $this->total_tva = $obj->total_tva; + $this->total_ttc = $obj->total_ttc; + $this->user_author = $obj->fk_user_author; + $this->user_modif = $obj->fk_user_modif; + $this->fk_project = $obj->fk_projet; + $this->fk_account = $obj->fk_account; + $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->date_lim_reglement = $this->db->jdate($obj->date_lim_reglement); + $this->note_private = $obj->note_private; + $this->note_public = $obj->note_public; + $this->model_pdf = $obj->modelpdf; + + // Multicurrency + $this->fk_multicurrency = $obj->fk_multicurrency; + $this->multicurrency_code = $obj->multicurrency_code; + $this->multicurrency_tx = $obj->multicurrency_tx; + $this->multicurrency_total_ht = $obj->multicurrency_total_ht; + $this->multicurrency_total_tva = $obj->multicurrency_total_tva; + $this->multicurrency_total_ttc = $obj->multicurrency_total_ttc; + + $this->usenewprice = $obj->usenewprice; + $this->frequency = $obj->frequency; + $this->unit_frequency = $obj->unit_frequency; + $this->date_when = $this->db->jdate($obj->date_when); + $this->date_last_gen = $this->db->jdate($obj->date_last_gen); + $this->nb_gen_done = $obj->nb_gen_done; + $this->nb_gen_max = $obj->nb_gen_max; + $this->auto_validate = $obj->auto_validate; + $this->generate_pdf = $obj->generate_pdf; + + + if ($this->statut == self::STATUS_DRAFT) { + $this->brouillon = 1; + } + + // Retrieve all extrafield + // fetch optionals attributes and labels + $this->fetch_optionals(); + + /* + * Lines + */ + $result = $this->fetch_lines(); + if ($result < 0) { + $this->error = $this->db->lasterror(); + return -3; + } + return 1; + } else { + $this->error = 'Bill with id '.$rowid.' or ref '.$ref.' not found'; + dol_syslog('Facture::Fetch Error '.$this->error, LOG_ERR); + return -2; + } + } else { + $this->error = $this->db->error(); + return -1; + } + } + + + /** + * Create an array of invoice lines + * + * @return int >0 if OK, <0 if KO + */ + public function getLinesArray() + { + return $this->fetch_lines(); + } + + + // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps + /** + * Get lines of template invoices into this->lines + * + * @return int 1 if OK, < 0 if KO + */ + public function fetch_lines() + { + global $extrafields; + + // phpcs:enable + $this->lines = array(); + + // Retrieve all extrafield for line + // fetch optionals attributes and labels + if (!is_object($extrafields)) { + require_once DOL_DOCUMENT_ROOT.'/core/class/extrafields.class.php'; + $extrafields = new ExtraFields($this->db); + } + $extrafields->fetch_name_optionals_label($this->table_element_line, true); + + $sql = 'SELECT l.rowid,'; + $sql .= ' l.fk_facture_fourn, l.fk_parent_line, l.fk_product, l.ref, l.label, l.description,'; + $sql .= ' l.pu_ht, l.pu_ttc, l.qty, l.remise_percent, l.fk_remise_except, l.vat_src_code, l.tva_tx,'; + $sql .= ' l.localtax1_tx, l.localtax2_tx, l.localtax1_type, l.localtax2_type,'; + $sql .= ' l.total_ht, l.total_tva, l.total_ttc, total_localtax1, total_localtax2,'; + $sql .= ' l.product_type, l.date_start, l.date_end,'; + $sql .= ' l.info_bits, l.special_code, l.rang,'; + $sql .= ' l.fk_unit, l.import_key, l.fk_user_author, l.fk_user_modif,'; + $sql .= ' l.fk_multicurrency, l.multicurrency_code, l.multicurrency_subprice, l.multicurrency_total_ht, l.multicurrency_total_tva, l.multicurrency_total_ttc,'; + $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.'facture_fourn_det_rec as l'; + $sql .= ' LEFT JOIN '.MAIN_DB_PREFIX.'product as p ON l.fk_product = p.rowid'; + $sql .= ' WHERE l.fk_facture_fourn = '. (int) $this->id; + $sql .= ' ORDER BY l.rang'; + + dol_syslog('FactureFournisseurRec::fetch_lines', 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 FactureFournisseurLigneRec($this->db); + + $line->id = $objp->rowid; + $line->fk_facture_fourn = $objp->fk_facture_fourn; + $line->fk_parent = $objp->fk_parent_line; + $line->fk_product = $objp->fk_product; + $line->ref_supplier = $objp->ref; + $line->label = $objp->label; + $line->description = $objp->description; + $line->pu_ht = $objp->pu_ht; + $line->pu_ttc = $objp->pu_ttc; + $line->qty = $objp->qty; + $line->remise_percent = $objp->remise_percent; + $line->fk_remise_except = $objp->fk_remise_except; + $line->vat_src_code = $objp->vat_src_code; + $line->tva_tx = $objp->tva_tx; + $line->localtax1_tx = $objp->localtax1_tx; + $line->localtax1_type = $objp->localtax1_type; + $line->localtax2_tx = $objp->localtax2_tx; + $line->localtax2_type = $objp->localtax2_type; + $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->product_type = $objp->product_type; + $line->date_start = $objp->date_start; + $line->date_end = $objp->date_end; + $line->info_bits = $objp->info_bits ; + $line->special_code = $objp->special_code; + $line->rang = $objp->rang; + $line->fk_unit = $objp->fk_unit; + $line->import_key = $objp->import_key; + $line->fk_user_author = $objp->fk_user_author; + $line->fk_user_modif = $objp->fk_user_modif; + $line->fk_multicurrency = $objp->fk_multicurrency; + $line->multicurrency_code = $objp->multicurrency_code; + $line->multicurrency_subprice = $objp->multicurrency_subprice; + $line->multicurrency_total_ht = $objp->multicurrency_total_ht; + $line->multicurrency_total_tva = $objp->multicurrency_total_tva; + $line->multicurrency_total_ttc = $objp->multicurrency_total_ttc; + + $line->fetch_optionals(); + + $this->lines[$i] = $line; + + $i++; + } + + $this->db->free($result); + return 1; + } else { + $this->error = $this->db->lasterror(); + return -3; + } + } + + + /** + * Delete template invoice + * + * @param User $user User that delete. + * @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 + */ + public function delete(User $user, $notrigger = 0, $idwarehouse = -1) + { + $rowid = $this->id; + + dol_syslog(get_class($this)."::delete rowid=".((int) $rowid), LOG_DEBUG); + + $error = 0; + $this->db->begin(); + + $main = MAIN_DB_PREFIX.'facture_fourn_det_rec'; + $ef = $main."_extrafields"; + + $sqlef = "DELETE FROM ".$ef." WHERE fk_object IN (SELECT rowid FROM ".$main." WHERE fk_facture_fourn = ". (int) $rowid .")"; + $sql = "DELETE FROM ".MAIN_DB_PREFIX."facture_fourn_det_rec WHERE fk_facture_fourn = ". (int) $rowid; + + if ($this->db->query($sqlef) && $this->db->query($sql)) { + $sql = "DELETE FROM ".MAIN_DB_PREFIX."facture_fourn_rec WHERE rowid = ". (int) $rowid; + dol_syslog($sql); + if ($this->db->query($sql)) { + // Delete linked object + $res = $this->deleteObjectLinked(); + if ($res < 0) { + $error = -3; + } + // Delete extrafields + $res = $this->deleteExtraFields(); + if ($res < 0) { + $error = -4; + } + } else { + $this->error = $this->db->lasterror(); + $error = -1; + } + } else { + $this->error = $this->db->lasterror(); + $error = -2; + } + + if (!$error) { + $this->db->commit(); + return 1; + } else { + $this->db->rollback(); + return $error; + } + } + + /** + * Add a line to recursive supplier invoice + * + * @param int $fk_product Product/Service ID predefined + * @param string $ref + * @param string $label + * @param string $desc Description de la ligne + * @param double $pu_ht + * @param int $pu_ttc + * @param double $qty Quantite + * @param int $remise_percent Percentage discount of the line + * @param double $txtva Taux de tva force, sinon -1 + * @param int $txlocaltax1 Local tax 1 rate (deprecated) + * @param int $txlocaltax2 Local tax 2 rate (deprecated) + * @param string $price_base_type HT or TTC + * @param int $type Type of line (0=product, 1=service) + * @param int $date_start + * @param int $date_end + * @param int $info_bits VAT npr or not ? + * @param int $special_code Special code + * @param int $rang Position of line + * @param string $fk_unit Unit + * @param int $pu_ht_devise Unit price in currency + * @return int <0 if KO, Id of line if OK + * @throws Exception + */ + public function addline($fk_product, $ref, $label, $desc, $pu_ht, $pu_ttc, $qty, $remise_percent, $txtva, $txlocaltax1 = 0, $txlocaltax2 = 0, $price_base_type = 'HT', $type = 0, $date_start = 0, $date_end = 0, $info_bits = 0, $special_code = 0, $rang = -1, $fk_unit = null, $pu_ht_devise = 0) + { + global $mysoc, $user; + + include_once DOL_DOCUMENT_ROOT.'/core/lib/price.lib.php'; + + $facid = $this->id; //Supplier invoice template ID linked to + + dol_syslog(get_class($this)."::addline facid=$facid,desc=$desc,pu_ht=$pu_ht,qty=$qty,txtva=$txtva,txlocaltax1=$txlocaltax1,txlocaltax2=$txlocaltax2,fk_product=$fk_product,remise_percent=$remise_percent,info_bits=$info_bits,price_base_type=$price_base_type,pu_ttc=$pu_ttc,type=$type,fk_unit=$fk_unit,pu_ht_devise=$pu_ht_devise,date_start_fill=$date_start,date_end_fill=$date_end", LOG_DEBUG); + + // Check if object of the line is product or service + if ($type < 0) { + return -1; + } + + if ($this->suspended == self::STATUS_NOTSUSPENDED) { + + $localtaxes_type = getLocalTaxesFromRate($txtva, 0, $this->thirdparty, $mysoc); + + // Clean vat code + $reg = array(); + $vat_src_code = ''; + if (preg_match('/\((.*)\)/', $txtva, $reg)) { + $vat_src_code = $reg[1]; + $txtva = preg_replace('/\s*\(.*\)/', '', $txtva); // Remove code into vatrate. + } + + // Clean parameters + $fk_product = empty($fk_product) ? 0 : $fk_product; + $label = empty($label) ? '' : $label; + $remise_percent = empty($remise_percent) ? 0 : price2num($remise_percent); + $qty = price2num($qty); + $pu_ht = price2num($pu_ht); + $pu_ttc = price2num($pu_ttc); + if (!preg_match('/\((.*)\)/', $txtva)) { + $txtva = price2num($txtva); // $txtva can have format '5.0(XXX)' or '5' + } + $txlocaltax1 = price2num($txlocaltax1); + $txlocaltax2 = price2num($txlocaltax2); + $txtva = !empty($txtva) ? $txtva : 0; + $txlocaltax1 = !empty($txlocaltax1) ? $txlocaltax1 : 0; + $txlocaltax2 = !empty($txlocaltax2) ? $txlocaltax2 : 0; + $info_bits = !empty($info_bits) ? $info_bits : 0; + $info_bits = !empty($info_bits) ? $info_bits : 0; + $pu = $price_base_type == 'HT' ? $pu_ht : $pu_ttc; + + // 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, $mysoc, $localtaxes_type, 100, $this->multicurrency_tx, $pu_ht_devise); + $total_ht = $tabprice[0]; + $total_tva = $tabprice[1]; + $total_ttc = $tabprice[2]; + $total_localtax1 = $tabprice[9]; + $total_localtax2 = $tabprice[10]; + $pu_ht = $tabprice[3]; + + // MultiCurrency + $multicurrency_total_ht = $tabprice[16]; + $multicurrency_total_tva = $tabprice[17]; + $multicurrency_total_ttc = $tabprice[18]; + $pu_ht_devise = $tabprice[19]; + + $this->db->begin(); + $product_type = $type; + if ($fk_product) { + $product = new Product($this->db); + $result = $product->fetch($fk_product); + if ($result < 0) { + return -1; + } + $product_type = $product->type; + if (empty($label)){ + $label = $product->label; + } + } + + $sql = 'INSERT INTO ' . MAIN_DB_PREFIX . 'facture_fourn_det_rec ('; + $sql .= 'fk_facture_fourn'; + $sql .= ', fk_product'; + $sql .= ', ref'; + $sql .= ', label'; + $sql .= ', description'; + $sql .= ', pu_ht'; + $sql .= ', pu_ttc'; + $sql .= ', qty'; + $sql .= ', remise_percent'; + $sql .= ', fk_remise_except'; + $sql .= ', vat_src_code'; + $sql .= ', tva_tx'; + $sql .= ', localtax1_tx'; + $sql .= ', localtax1_type'; + $sql .= ', localtax2_tx'; + $sql .= ', localtax2_type'; + $sql .= ', total_ht'; + $sql .= ', total_tva'; + $sql .= ', total_localtax1'; + $sql .= ', total_localtax2'; + $sql .= ', total_ttc'; + $sql .= ', product_type'; + $sql .= ', date_start'; + $sql .= ', date_end'; + $sql .= ', info_bits'; + $sql .= ', special_code'; + $sql .= ', rang'; + $sql .= ', fk_unit'; + $sql .= ', fk_user_author'; + $sql .= ', fk_multicurrency, multicurrency_code, multicurrency_subprice, multicurrency_total_ht, multicurrency_total_tva, multicurrency_total_ttc'; + $sql .= ') VALUES ('; + $sql .= ' ' . (int) $facid; // source supplier invoie id + $sql .= ', ' . (! empty($fk_product) ? "'" . $this->db->escape($fk_product) . "'" : 'null'); + $sql .= ', ' . (! empty($ref) ? "'" . $this->db->escape($ref) . "'" : 'null'); + $sql .= ', ' . (! empty($label) ? "'" . $this->db->escape($label) . "'" : 'null'); + $sql .= ", '" . $this->db->escape($desc) . "'"; + $sql .= ', ' . price2num($pu_ht); + $sql .= ', ' . price2num($pu_ttc); + $sql .= ', ' . price2num($qty); + $sql .= ', ' . price2num($remise_percent); + $sql .= ', null'; + $sql .= ", '" . $this->db->escape($vat_src_code) . "'"; + $sql .= ', ' . price2num($txtva); + $sql .= ', ' . price2num($txlocaltax1); + $sql .= ", '" . $this->db->escape(isset($localtaxes_type[0]) ? $localtaxes_type[0] : '') . "'"; + $sql .= ', ' . price2num($txlocaltax2); + $sql .= ", '" . $this->db->escape(isset($localtaxes_type[2]) ? $localtaxes_type[2] : '') . "'"; + $sql .= ', ' . price2num($total_ht); + $sql .= ', ' . price2num($total_tva); + $sql .= ', ' . price2num($total_localtax1); + $sql .= ', ' . price2num($total_localtax2); + $sql .= ', ' . price2num($total_ttc); + $sql .= ', ' . (int) $product_type; + $sql .= ', ' . ($date_start > 0 ? (int) $date_start : 'NULL'); + $sql .= ', ' . ($date_end > 0 ? (int) $date_end : 'NULL'); + $sql .= ', ' . (int) $info_bits; + $sql .= ', ' . (int) $special_code; + $sql .= ', ' . (int) $rang; + $sql .= ', ' . ($fk_unit ? (int) $fk_unit : 'NULL'); + $sql .= ', ' . (int) $user; + $sql .= ', ' . (int) $this->fk_multicurrency; + $sql .= ", '" . $this->db->escape($this->multicurrency_code) . "'"; + $sql .= ', ' . price2num($pu_ht_devise, 'CU'); + $sql .= ', ' . price2num($multicurrency_total_ht, 'CT'); + $sql .= ', ' . price2num($multicurrency_total_tva, 'CT'); + $sql .= ', ' . price2num($multicurrency_total_ttc, 'CT'); + $sql .= ')'; + + dol_syslog(get_class($this). '::addline', LOG_DEBUG); + if ($this->db->query($sql)) { + $lineId = $this->db->last_insert_id(MAIN_DB_PREFIX. 'facture_fourn_det_rec'); + $this->update_price(); + $this->id = $facid; + $this->db->commit(); + return $lineId; + } else { + $this->db->rollback(); + $this->error = $this->db->lasterror(); + + return -1; + } + } + } + + /** + * Update a line to supplier invoice template + * + * @param $rowid + * @param int $fk_product Product/Service ID predefined + * @param $ref + * @param string $label Label of the line + * @param string $desc Description de la ligne + * @param double $pu_ht Prix unitaire HT (> 0 even for credit note) + * @param double $qty Quantite + * @param int $remise_percent Percentage discount of the line + * @param double $txtva Taux de tva force, sinon -1 + * @param int $txlocaltax1 Local tax 1 rate (deprecated) + * @param int $txlocaltax2 Local tax 2 rate (deprecated) + * @param string $price_base_type HT or TTC + * @param int $type Type of line (0=product, 1=service) + * @param int $date_start + * @param int $date_end + * @param int $info_bits Bits of type of lines + * @param int $special_code Special code + * @param int $rang Position of line + * @param string $fk_unit Unit + * @param int $pu_ht_devise Unit price in currency + * @return int <0 if KO, Id of line if OK + * @throws Exception + */ + public function updateline($rowid, $fk_product, $ref, $label, $desc, $pu_ht, $qty, $remise_percent, $txtva, $txlocaltax1 = 0, $txlocaltax2 = 0, $price_base_type = 'HT', $type = 0, $date_start = 0, $date_end = 0, $info_bits = 0, $special_code = 0, $rang = -1, $fk_unit = null, $pu_ht_devise = 0) + { + global $mysoc, $user; + + $facid = $this->id; + + dol_syslog(get_class($this). '::updateline facid=' .$facid." rowid=$rowid, desc=$desc, pu_ht=$pu_ht, qty=$qty, txtva=$txtva, txlocaltax1=$txlocaltax1, txlocaltax2=$txlocaltax2, fk_product=$fk_product, remise_percent=$remise_percent, info_bits=$info_bits, fk_remise_except=$fk_remise_except, price_base_type=$price_base_type, pu_ttc=$pu_ttc, type=$type, fk_unit=$fk_unit, pu_ht_devise=$pu_ht_devise", LOG_DEBUG); + include_once DOL_DOCUMENT_ROOT.'/core/lib/price.lib.php'; + + // Check parameters + if ($type < 0) { + return -1; + } + + if ($this->brouillon) { + // Clean parameters + $fk_product = empty($fk_product) ? 0 : $fk_product; + $label = empty($label) ? '' : $label; + $remise_percent = empty($remise_percent) ? 0 : price2num($remise_percent); + $qty = price2num($qty); + $info_bits = empty($info_bits) ? 0 : $info_bits; + $pu_ht = price2num($pu_ht); + $pu_ttc = price2num($pu_ttc); + $pu_ht_devise = price2num($pu_ht_devise); + + if (!preg_match('/\((.*)\)/', $txtva)) { + $txtva = price2num($txtva); // $txtva can have format '5.0(XXX)' or '5' + } + + $txlocaltax1 = empty($txlocaltax1) ? 0 : price2num($txlocaltax1); + $txlocaltax2 = empty($txlocaltax2) ? 0 : price2num($txlocaltax2); + $this->multicurrency_subprice = empty($this->multicurrency_subprice) ? 0 : $this->multicurrency_subprice; + $this->multicurrency_total_ht = empty($this->multicurrency_total_ht) ? 0 : $this->multicurrency_total_ht; + $this->multicurrency_total_tva = empty($this->multicurrency_total_tva) ? 0 : $this->multicurrency_total_tva; + $this->multicurrency_total_ttc = empty($this->multicurrency_total_ttc) ? 0 : $this->multicurrency_total_ttc; + + $pu = $price_base_type == 'HT' ? $pu_ht : $pu_ttc; + + + // 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. + + $localtaxes_type = getLocalTaxesFromRate($txtva, 0, $this->thirdparty, $mysoc); + + // Clean vat code + $vat_src_code = ''; + $reg = array(); + if (preg_match('/\((.*)\)/', $txtva, $reg)) { + $vat_src_code = $reg[1]; + $txtva = preg_replace('/\s*\(.*\)/', '', $txtva); // Remove code into vatrate. + } + + $tabprice = calcul_price_total($qty, $pu, $remise_percent, $txtva, $txlocaltax1, $txlocaltax2, 0, $price_base_type, $info_bits, $type, $mysoc, $localtaxes_type, 100, $this->multicurrency_tx, $pu_ht_devise); + + $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]; + + // MultiCurrency + $multicurrency_total_ht = $tabprice[16]; + $multicurrency_total_tva = $tabprice[17]; + $multicurrency_total_ttc = $tabprice[18]; + $pu_ht_devise = $tabprice[19]; + + $product_type = $type; + if ($fk_product) { + $product = new Product($this->db); + $result = $product->fetch($fk_product); + $product_type = $product->type; + } + + $sql = 'UPDATE ' . MAIN_DB_PREFIX . 'facture_fourn_det_rec SET '; + $sql .= 'fk_facture_fourn= ' . $facid;; + $sql .= ', fk_product=' . (! empty($fk_product) ? "'" . $this->db->escape($fk_product) . "'" : 'null'); + $sql .= ", ref='" . $this->db->escape($ref) . "'"; + $sql .= ", label='" . $this->db->escape($label) . "'"; + $sql .= ", description='" . $this->db->escape($desc) . "'"; + $sql .= ', pu_ht=' . price2num($pu_ht); + $sql .= ', qty=' . price2num($qty); + $sql .= ", remise_percent='" . price2num($remise_percent) . "'"; + $sql .= ", vat_src_code='" . $this->db->escape($vat_src_code) . "'"; + $sql .= ', tva_tx=' . price2num($txtva); + $sql .= ', localtax1_tx=' . (float) $txlocaltax1; + $sql .= ", localtax1_type='" . $this->db->escape($localtaxes_type[0]) . "'"; + $sql .= ', localtax2_tx=' . (float) $txlocaltax2; + $sql .= ", localtax2_type='" . $this->db->escape($localtaxes_type[2]) . "'"; + $sql .= ", total_ht='" . price2num($total_ht) . "'"; + $sql .= ", total_tva='" . price2num($total_tva) . "'"; + $sql .= ", total_localtax1='" . price2num($total_localtax1) . "'"; + $sql .= ", total_localtax2='" . price2num($total_localtax2) . "'"; + $sql .= ", total_ttc='" . price2num($total_ttc) . "'"; + $sql .= ', product_type=' . (int) $product_type; + $sql .= ', date_start=' . (empty($date_start) ? 'NULL' : (int) $date_start); + $sql .= ', date_end=' . (empty($date_end) ? 'NULL' : (int) $date_end); + $sql .= ', info_bits=' . (int) $info_bits; + $sql .= ', special_code=' . (int) $special_code; + $sql .= ', rang=' . (int) $rang; + $sql .= ', fk_unit=' . ($fk_unit ? "'" . $this->db->escape($fk_unit) . "'" : 'null'); + $sql .= ', fk_user_modif=' . (int) $user; + $sql .= ', multicurrency_subprice = '.price2num($pu_ht_devise); + $sql .= ', multicurrency_total_ht = '.price2num($multicurrency_total_ht); + $sql .= ', multicurrency_total_tva = '.price2num($multicurrency_total_tva); + $sql .= ', multicurrency_total_ttc = '.price2num($multicurrency_total_ttc); + $sql .= ' WHERE rowid = ' . (int) $rowid; + + dol_syslog(get_class($this). '::updateline', LOG_DEBUG); + if ($this->db->query($sql)) { + $this->id = $facid; + $this->update_price(); + return 1; + } else { + $this->error = $this->db->lasterror(); + return -1; + } + } + } + + + /** + * Return the next date of + * + * @return int|false false if KO, timestamp if OK + */ + public function getNextDate() + { + if (empty($this->date_when)) { + return false; + } + return dol_time_plus_duree($this->date_when, $this->frequency, $this->unit_frequency); + } + + /** + * Return if maximum number of generation is reached + * + * @return boolean False by default, True if maximum number of generation is reached + */ + public function isMaxNbGenReached() + { + $ret = false; + if ($this->nb_gen_max > 0 && ($this->nb_gen_done >= $this->nb_gen_max)) { + $ret = true; + } + return $ret; + } + + /** + * Format string to output with by striking the string if max number of generation was reached + * + * @param string $ret Default value to output + * @return boolean False by default, True if maximum number of generation is reached + */ + public function strikeIfMaxNbGenReached($ret) + { + // Special case to strike the date + return ($this->isMaxNbGenReached() ? '' : '').$ret.($this->isMaxNbGenReached() ? '' : ''); + } + + /** + * Create all recurrents supplier invoices (for all entities if multicompany is used). + * A result may also be provided into this->output. + * + * WARNING: This method change temporarly context $conf->entity to be in correct context for each recurring invoice found. + * + * @param int $restrictioninvoiceid 0=All qualified template invoices found. > 0 = restrict action on invoice ID + * @param int $forcevalidation 1=Force validation of invoice whatever is template auto_validate flag. + * @return int 0 if OK, < 0 if KO (this function is used also by cron so only 0 is OK) + */ + public function createRecurringInvoices($restrictioninvoiceid = 0, $forcevalidation = 0) + { + global $conf, $langs, $db, $user, $hookmanager; + + $error = 0; + $nb_create = 0; + + // Load translation files required by the page + $langs->loadLangs(array('main', 'bills')); + + $now = dol_now(); + $tmparray = dol_getdate($now); + $today = dol_mktime(23, 59, 59, $tmparray['mon'], $tmparray['mday'], $tmparray['year']); // Today is last second of current day + + dol_syslog('createRecurringInvoices restrictioninvoiceid=' .$restrictioninvoiceid. ' forcevalidation=' .$forcevalidation); + + $sql = 'SELECT rowid FROM '.MAIN_DB_PREFIX.'facture_fourn_rec'; + $sql .= ' WHERE frequency > 0'; // A recurring supplier invoice is an invoice with a frequency + $sql .= " AND (date_when IS NULL OR date_when <= '".$this->db->idate($today)."')"; + $sql .= ' AND (nb_gen_done < nb_gen_max OR nb_gen_max = 0)'; + $sql .= ' AND suspended = 0'; + $sql .= ' AND entity = '. (int) $conf->entity; // MUST STAY = $conf->entity here + if ($restrictioninvoiceid > 0) { + $sql .= ' AND rowid = '. (int) $restrictioninvoiceid; + } + $sql .= $this->db->order('entity', 'ASC'); + //print $sql;exit; + $parameters = array( + 'restrictioninvoiceid' => $restrictioninvoiceid, + 'forcevalidation' => $forcevalidation, + ); + $reshook = $hookmanager->executeHooks('beforeCreationOfRecurringInvoices', $parameters, $sql); // note that $sql might be modified by hooks + + $resql = $this->db->query($sql); + if ($resql) { + $i = 0; + $num = $this->db->num_rows($resql); + + if ($num) { + $this->output .= $langs->trans('FoundXQualifiedRecurringInvoiceTemplate', $num)."\n"; + } else { + $this->output .= $langs->trans('NoQualifiedRecurringInvoiceTemplateFound'); + } + + $saventity = $conf->entity; + + while ($i < $num) { // Loop on each template invoice. If $num = 0, test is false at first pass. + $line = $this->db->fetch_object($resql); + + $this->db->begin(); + + $invoiceidgenerated = 0; + + $new_fac_fourn = null; + $facturerec = new FactureFournisseurRec($this->db); + $facturerec->fetch($line->rowid); + + if ($facturerec->id > 0) { + // Set entity context + $conf->entity = $facturerec->entity; + + dol_syslog('createRecurringInvoices Process invoice template id=' .$facturerec->id. ', ref=' .$facturerec->ref. ', entity=' .$facturerec->entity); + + $new_fac_fourn = new FactureFournisseur($this->db); + $new_fac_fourn->fac_rec = $facturerec->id; // We will create $facture from this recurring invoice + $new_fac_fourn->fk_fac_rec_source = $facturerec->id; // We will create $facture from this recurring invoice + + $new_fac_fourn->type = self::TYPE_STANDARD; + $new_fac_fourn->brouillon = 1; + $new_fac_fourn->statut = self::STATUS_DRAFT; + $new_fac_fourn->status = self::STATUS_DRAFT; + $new_fac_fourn->date = empty($facturerec->date_when) ? $now : $facturerec->date_when; // We could also use dol_now here but we prefer date_when so invoice has real date when we would like even if we generate later. + $new_fac_fourn->socid = $facturerec->socid; + $new_fac_fourn->lines = $facturerec->lines; + $new_fac_fourn->ref_supplier = $facturerec->ref_supplier; + $new_fac_fourn->model_pdf = $facturerec->model_pdf; + $new_fac_fourn->fk_project = $facturerec->fk_project; + $new_fac_fourn->libelle = $facturerec->libelle; + + $invoiceidgenerated = $new_fac_fourn->create($user); + if ($invoiceidgenerated <= 0) { + $this->errors = $new_fac_fourn->errors; + $this->error = $new_fac_fourn->error; + $error++; + } + if (!$error && ($facturerec->auto_validate || $forcevalidation)) { + $result = $new_fac_fourn->validate($user); + if ($result <= 0) { + $this->errors = $new_fac_fourn->errors; + $this->error = $new_fac_fourn->error; + $error++; + } + } + + if (!$error && $facturerec->generate_pdf) { + // We refresh the object in order to have all necessary data (like date_lim_reglement) + $new_fac_fourn->fetch($new_fac_fourn->id); + $result = $new_fac_fourn->generateDocument($facturerec->model_pdf, $langs); + if ($result <= 0) { + $this->errors = $new_fac_fourn->errors; + $this->error = $new_fac_fourn->error; + $error++; + } + } + } else { + $error++; + $this->error = 'Failed to load invoice template with id=' .$line->rowid. ', entity=' .$conf->entity."\n"; + $this->errors[] = 'Failed to load invoice template with id=' .$line->rowid. ', entity=' .$conf->entity; + dol_syslog('createRecurringInvoices Failed to load invoice template with id=' .$line->rowid. ', entity=' .$conf->entity); + } + + if (!$error && $invoiceidgenerated >= 0) { + $facturerec->nb_gen_done++; + $facturerec->date_last_gen = dol_now(); + $facturerec->date_when= $facturerec->getNextDate(); + $facturerec->update($user); + $this->db->commit('createRecurringInvoices Process invoice template id=' .$facturerec->id. ', title=' .$facturerec->titre); + dol_syslog('createRecurringInvoices Process invoice template ' .$facturerec->titre. ' is finished with a success generation'); + $nb_create++; + $this->output .= $langs->trans('InvoiceGeneratedFromTemplate', $new_fac_fourn->ref, $facturerec->titre)."\n"; + } else { + $this->db->rollback('createRecurringInvoices Process invoice template id=' .$facturerec->id. ', title=' .$facturerec->titre); + } + + $parameters = array( + 'cpt' => $i, + 'total' => $num, + 'errorCount' => $error, + 'invoiceidgenerated' => $invoiceidgenerated, + 'facturerec' => $facturerec, // it's an object which PHP passes by "reference", so modifiable by hooks. + 'this' => $this, // it's an object which PHP passes by "reference", so modifiable by hooks. + ); + $reshook = $hookmanager->executeHooks('afterCreationOfRecurringInvoice', $parameters, $new_fac_fourn); // note: $facture can be modified by hooks (warning: $facture can be null) + + $i++; + } + + $conf->entity = $saventity; // Restore entity context + } else { + dol_print_error($this->db); + } + + $this->output = trim($this->output); + + return $error ? $error : 0; + } + + /** + * Return clicable name (with picto eventually) + * + * @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 + * @param int $notooltip 1=Disable tooltip + * @param int $save_lastsearch_value -1=Auto, 0=No save of lastsearch_values when clicking, 1=Save lastsearch_values whenclicking + * @return string String with URL + */ + public function getNomUrl($withpicto = 0, $option = '', $max = 0, $short = 0, $moretitle = '', $notooltip = '', $save_lastsearch_value = -1) + { + global $langs; + + $result = ''; + + $label = ''.$langs->trans('RepeatableInvoice').''; + if (!empty($this->ref)) { + $label .= '
'.$langs->trans('Ref').': '.$this->ref; + } + if ($this->frequency > 0) { + $label .= '
'.$langs->trans('Frequency').': '.$langs->trans('FrequencyPer_'.$this->unit_frequency, $this->frequency); + } + if (!empty($this->date_last_gen)) { + $label .= '
'.$langs->trans('DateLastGeneration').': '.dol_print_date($this->date_last_gen, 'dayhour'); + } + if ($this->frequency > 0) { + if (!empty($this->date_when)) { + $label .= '
'.$langs->trans('NextDateToExecution').': '; + $label .= (empty($this->suspended) ? '' : '').dol_print_date($this->date_when, 'day').(empty($this->suspended) ? '' : ''); // No hour for this property + if (!empty($this->suspended)) { + $label .= ' ('.$langs->trans('Disabled').')'; + } + } + } + + $url = DOL_URL_ROOT.'/fourn/facture/card-rec.php?facid='.$this->id; + + if ($short) { + return $url; + } + + if ($option != 'nolink') { + // Add param to save lastsearch_values or not + $add_save_lastsearch_values = ($save_lastsearch_value == 1 ? 1 : 0); + if ($save_lastsearch_value == -1 && preg_match('/list\.php/', $_SERVER['PHP_SELF'])) { + $add_save_lastsearch_values = 1; + } + if ($add_save_lastsearch_values) { + $url .= '&save_lastsearch_values=1'; + } + } + + $linkstart = ''; + $linkend = ''; + + $result .= $linkstart; + if ($withpicto) { + $result .= img_object(($notooltip ? '' : $label), ($this->picto ? $this->picto : 'generic'), ($notooltip ? (($withpicto != 2) ? 'class="paddingright"' : '') : 'class="'.(($withpicto != 2) ? 'paddingright ' : '').'classfortooltip"'), 0, 0, $notooltip ? 0 : 1); + } + if ($withpicto != 2) { + $result .= $this->ref; + } + $result .= $linkend; + + return $result; + } + + /** + * Return label of object status + * + * @param int $mode 0=long label, 1=short label, 2=Picto + short label, 3=Picto, 4=Picto + long label, 5=short label + picto, 6=Long label + picto + * @param integer $alreadypaid Not used on recurring invoices + * @return string Label of status + */ + public function getLibStatut($mode = 0, $alreadypaid = -1) + { + return $this->LibStatut($this->frequency ? 1 : 0, $this->suspended, $mode, $alreadypaid, empty($this->type) ? 0 : $this->type); + } + + // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps + /** + * Return label of a status + * + * @param int $recur Is it a recurring invoice ? + * @param int $status Id status (suspended or not) + * @param int $mode 0=long label, 1=short label, 2=Picto + short label, 3=Picto, 4=Picto + long label, 5=short label + picto, 6=long label + picto + * @param integer $alreadypaid Not used for recurring invoices + * @param int $type Type invoice + * @return string Label of status + */ + public function LibStatut($recur, $status, $mode = 0, $alreadypaid = -1, $type = 0) + { + // phpcs:enable + global $langs; + $langs->load('bills'); + + $labelStatus = $langs->transnoentitiesnoconv('Active'); + $statusType = 'status0'; + + //print "$recur,$status,$mode,$alreadypaid,$type"; + if ($mode == 0) { + if ($recur) { + if ($status == self::STATUS_SUSPENDED) { + $labelStatus = $langs->transnoentitiesnoconv('Disabled'); + } else { + $labelStatus = $langs->transnoentitiesnoconv('Active'); + } + } else { + if ($status == self::STATUS_SUSPENDED) { + $labelStatus = $langs->transnoentitiesnoconv('Disabled'); + } else { + $labelStatus = $langs->transnoentitiesnoconv('Draft'); + } + } + } elseif ($mode == 1) { + $prefix = 'Short'; + if ($recur) { + if ($status == self::STATUS_SUSPENDED) { + $labelStatus = $langs->transnoentitiesnoconv('Disabled'); + } else { + $labelStatus = $langs->transnoentitiesnoconv('Active'); + } + } else { + if ($status == self::STATUS_SUSPENDED) { + $labelStatus = $langs->transnoentitiesnoconv('Disabled'); + } else { + $labelStatus = $langs->transnoentitiesnoconv('Draft'); + } + } + } elseif ($mode == 2) { + if ($recur) { + if ($status == self::STATUS_SUSPENDED) { + $statusType = 'status6'; + $labelStatus = $langs->transnoentitiesnoconv('Disabled'); + } else { + $statusType = 'status4'; + $labelStatus = $langs->transnoentitiesnoconv('Active'); + } + } else { + if ($status == self::STATUS_SUSPENDED) { + $statusType = 'status6'; + $labelStatus = $langs->transnoentitiesnoconv('Disabled'); + } else { + $statusType = 'status0'; + $labelStatus = $langs->transnoentitiesnoconv('Draft'); + } + } + } elseif ($mode == 3) { + if ($recur) { + $prefix = 'Short'; + if ($status == self::STATUS_SUSPENDED) { + $statusType = 'status6'; + $labelStatus = $langs->transnoentitiesnoconv('Disabled'); + } else { + $statusType = 'status4'; + $labelStatus = $langs->transnoentitiesnoconv('Active'); + } + } else { + if ($status == self::STATUS_SUSPENDED) { + $statusType = 'status6'; + $labelStatus = $langs->transnoentitiesnoconv('Disabled'); + } else { + $statusType = 'status0'; + $labelStatus = $langs->transnoentitiesnoconv('Draft'); + } + } + } elseif ($mode == 4) { + $prefix = ''; + if ($recur) { + if ($status == self::STATUS_SUSPENDED) { + $statusType = 'status6'; + $labelStatus = $langs->transnoentitiesnoconv('Disabled'); + } else { + $statusType = 'status4'; + $labelStatus = $langs->transnoentitiesnoconv('Active'); + } + } else { + if ($status == self::STATUS_SUSPENDED) { + $statusType = 'status6'; + $labelStatus = $langs->transnoentitiesnoconv('Disabled'); + } else { + $statusType = 'status0'; + $labelStatus = $langs->transnoentitiesnoconv('Draft'); + } + } + } elseif ($mode == 5 || $mode == 6) { + $prefix = ''; + if ($mode == 5) { + $prefix = 'Short'; + } + if ($recur) { + if ($status == self::STATUS_SUSPENDED) { + $statusType = 'status6'; + $labelStatus = $langs->transnoentitiesnoconv('Disabled'); + } else { + $statusType = 'status4'; + $labelStatus = $langs->transnoentitiesnoconv('Active'); + } + } else { + if ($status == self::STATUS_SUSPENDED) { + $statusType = 'status6'; + $labelStatus = $langs->transnoentitiesnoconv('Disabled'); + } else { + $statusType = 'status0'; + $labelStatus = $langs->transnoentitiesnoconv('Draft'); + } + } + } + + $labelStatusShort = $labelStatus; + + return dolGetStatus($labelStatus, $labelStatusShort, '', $statusType, $mode); + } + + /** + * 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 + */ + public 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']); + + // Load array of products prodids + $num_prods = 0; + $prodids = array(); + + $sql = 'SELECT rowid'; + $sql .= ' FROM ' .MAIN_DB_PREFIX. 'product'; + $sql .= ' WHERE entity IN (' .getEntity('product'). ')'; + $sql .= $this->db->plimit(100); + + $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->title = '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)'; + $this->fk_incoterms = 0; + $this->location_incoterms = ''; + + 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 = mt_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; + } elseif ($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; + } elseif ($xnbp == 3) { // Discount is 50% (product line) + $prodid = mt_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 = mt_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->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 = mt_rand(1, $num_prods); + $line->fk_product = $prodids[$prodid]; + + $this->lines[$xnbp] = $line; + $xnbp++; + } + + $this->usenewprice = 0; + } + + /** + * Function used to replace a thirdparty id with another one. + * + * @param DoliDB $db Database handler + * @param int $origin_id Old thirdparty id + * @param int $dest_id New thirdparty id + * @return bool + */ + public static function replaceThirdparty(DoliDB $db, $origin_id, $dest_id) + { + $tables = array( + 'facture_rec' + ); + + return CommonObject::commonReplaceThirdparty($db, $origin_id, $dest_id, $tables); + } + + /** + * Update frequency and unit + * + * @param int $frequency value of frequency + * @param string $unit unit of frequency (d, m, y) + * @return int <0 if KO, >0 if OK + */ + public function setFrequencyAndUnit($frequency, $unit) + { + if (!$this->table_element) { + dol_syslog(get_class($this). '::setFrequencyAndUnit was called on objet with property table_element not defined', LOG_ERR); + return -1; + } + + if (!empty($frequency) && empty($unit)) { + dol_syslog(get_class($this). '::setFrequencyAndUnit was called on objet with params frequency defined but unit not defined', LOG_ERR); + return -2; + } + + $sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element; + $sql .= ' SET frequency = '.($frequency ? $this->db->escape($frequency) : 'null'); + if (!empty($unit)) { + $sql .= ', unit_frequency = '.$this->db->escape($unit); + } + $sql .= ' WHERE rowid = ' . (int) $this->id; + + dol_syslog(get_class($this). '::setFrequencyAndUnit', LOG_DEBUG); + if ($this->db->query($sql)) { + $this->frequency = $frequency; + if (!empty($unit)) { + $this->unit_frequency = $unit; + } + return 1; + } else { + dol_print_error($this->db); + return -1; + } + } + + /** + * Update the next date of execution + * + * @param datetime $date date of execution + * @param int $increment_nb_gen_done 0 do nothing more, >0 increment nb_gen_done + * @return int <0 if KO, >0 if OK + */ + public function setNextDate($date, $increment_nb_gen_done = 0) + { + if (!$this->table_element) { + dol_syslog(get_class($this). '::setNextDate was called on objet with property table_element not defined', LOG_ERR); + return -1; + } + $sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element; + $sql .= ' SET date_when = ' .($date ? "'".$this->db->idate($date)."'" : 'null'); + if ($increment_nb_gen_done > 0) { + $sql .= ', nb_gen_done = nb_gen_done + 1'; + } + $sql .= ' WHERE rowid = ' . (int) $this->id; + + dol_syslog(get_class($this). '::setNextDate', LOG_DEBUG); + if ($this->db->query($sql)) { + $this->date_when = $date; + if ($increment_nb_gen_done > 0) { + $this->nb_gen_done++; + } + return 1; + } else { + dol_print_error($this->db); + return -1; + } + } + + /** + * Update the maximum period + * + * @param int $nb number of maximum period + * @return int <0 if KO, >0 if OK + */ + public function setMaxPeriod($nb) + { + if (!$this->table_element) { + dol_syslog(get_class($this). '::setMaxPeriod was called on objet with property table_element not defined', LOG_ERR); + return -1; + } + + if (empty($nb)) { + $nb = 0; + } + + $sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element; + $sql .= ' SET nb_gen_max = '. (int) $nb; + $sql .= ' WHERE rowid = ' . (int) $this->id; + + dol_syslog(get_class($this). '::setMaxPeriod', LOG_DEBUG); + if ($this->db->query($sql)) { + $this->nb_gen_max = $nb; + return 1; + } else { + dol_print_error($this->db); + return -1; + } + } + + /** + * Update the auto validate flag of invoice + * + * @param int $validate 0 to create in draft, 1 to create and validate invoice + * @return int <0 if KO, >0 if OK + */ + public function setAutoValidate($validate) + { + if (!$this->table_element) { + dol_syslog(get_class($this). '::setAutoValidate was called on objet with property table_element not defined', LOG_ERR); + return -1; + } + + $sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element; + $sql .= ' SET auto_validate = '.((int) $validate); + $sql .= ' WHERE rowid = ' . (int) $this->id; + + dol_syslog(get_class($this). '::setAutoValidate', LOG_DEBUG); + if ($this->db->query($sql)) { + $this->auto_validate = $validate; + return 1; + } else { + dol_print_error($this->db); + return -1; + } + } + + /** + * Update the auto generate documents + * + * @param int $validate 0 no document, 1 to generate document + * @return int <0 if KO, >0 if OK + */ + public function setGeneratePdf($validate) + { + if (!$this->table_element) { + dol_syslog(get_class($this). '::setGeneratePdf was called on objet with property table_element not defined', LOG_ERR); + return -1; + } + + $sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element; + $sql .= ' SET generate_pdf = '. (int) $validate; + $sql .= ' WHERE rowid = ' . (int) $this->id; + + dol_syslog(get_class($this). '::setGeneratePdf', LOG_DEBUG); + if ($this->db->query($sql)) { + $this->generate_pdf = $validate; + return 1; + } else { + dol_print_error($this->db); + return -1; + } + } + + /** + * Update the model for documents + * + * @param string $model model of document generator + * @return int <0 if KO, >0 if OK + */ + public function setModelPdf($model) + { + if (!$this->table_element) { + dol_syslog(get_class($this). '::setModelPdf was called on objet with property table_element not defined', LOG_ERR); + return -1; + } + + $sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element; + $sql .= " SET modelpdf = '".$this->db->escape($model)."'"; + $sql .= ' WHERE rowid = ' . (int) $this->id; + + dol_syslog(get_class($this). '::setModelPdf', LOG_DEBUG); + if ($this->db->query($sql)) { + $this->model_pdf = $model; + return 1; + } else { + dol_print_error($this->db); + return -1; + } + } +} + + + +/** + * Class to manage supplier invoice lines of templates. + * Saved into database table llx_facture_fourn_det_rec + */ +class FactureFournisseurLigneRec extends CommonObjectLine +{ + /** + * @var string ID to identify managed object + */ + public $element = 'invoice_supplier_det_rec'; + + /** + * @var string Name of table without prefix where object is stored + */ + public $table_element = 'facture_fourn_det_rec'; + + public $fk_facture_fourn; + public $fk_parent; + public $fk_product; + public $ref_supplier; + public $label; + public $description; + public $pu_ht; + public $pu_ttc; + public $qty; + public $remise_percent; + public $fk_remise_except; + public $vat_src_code; + public $tva_tx; + public $localtax1_tx; + public $localtax1_type; + public $localtax2_tx; + public $localtax2_type; + + public $product_type; + public $date_start; + public $date_end; + public $info_bits; + public $special_code; + public $rang; + + public $fk_user_author; + public $fk_user_modif; + public $fk_multicurrency; + public $multicurrency_subprice; + + + /* Overrides fields in CommonObject + public $total_ht; + public $total_tva; + public $total_localtax1; + public $total_localtax2; + public $total_ttc; + + public $fk_unit; + public $import_key; + public $multicurrency_code; + public $multicurrency_total_ht; + public $multicurrency_total_tva; + public $multicurrency_total_ttc; + */ + + + /** + * Delete supplier order template line in database + * + * @param User $user Object user + * @param int $notrigger Disable triggers + * @return int <0 if KO, >0 if OK + */ + public function delete(User $user, $notrigger = false) { + $error = 0; + $this->db->begin(); + + if (! $error) { + if (! $notrigger) { + // Call triggers + $result = $this->call_trigger('LINEBILLREC_DELETE', $user); + if ($result < 0) { + $error++; + } // Do also here what you must do to rollback action if trigger fail + // End call triggers + } + } + + if (! $error) { + $result = $this->deleteExtraFields(); + if ($result < 0) { + $error++; + } + } + + if (! $error) { + $sql = 'DELETE FROM ' . MAIN_DB_PREFIX . $this->table_element . ' WHERE rowid=' . (int) $this->id; + + $res = $this->db->query($sql); + if ($res === false) { + $error++; + $this->errors[] = $this->db->lasterror(); + } + } + + // Commit or rollback + if ($error) { + $this->db->rollback(); + return -1; + } else { + $this->db->commit(); + return 1; + } + } + + + /** + * Get line of template invoice + * + * @param int $rowid Id of invoice + * @return int 1 if OK, < 0 if KO + */ + public function fetch($rowid) + { + $sql = 'SELECT l.rowid,'; + $sql .= ' l.fk_facture_fourn, l.fk_parent_line, l.fk_product,'; + $sql .= ' l.ref as ref_supplier, l.label, l.description, l.pu_ht, l.pu_ttc, l.qty, l.remise_percent, l.fk_remise_except,'; + $sql .= ' l.vat_src_code, l.tva_tx, l.localtax1_tx, l.localtax1_type, l.localtax2_tx, l.localtax2_type,'; + $sql .= ' l.total_ht, l.total_tva, l.total_localtax1, l.total_localtax2, l.total_ttc,'; + $sql .= ' l.product_type, l.date_start, l.date_end,'; + $sql .= ' l.info_bits, l.special_code, l.rang, l.fk_unit, l.import_key,'; + $sql .= ' l.fk_user_author, l.fk_user_modif, l.fk_multicurrency,'; + $sql .= ' l.multicurrency_code, l.multicurrency_subprice, l.multicurrency_total_ht, l.multicurrency_total_tva, l.multicurrency_total_ttc,'; + $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.'facture_fourn_det_rec as l'; + $sql .= ' LEFT JOIN '.MAIN_DB_PREFIX.'product as p ON l.fk_product = p.rowid'; + $sql .= ' WHERE l.rowid = '. (int) $rowid; + $sql .= ' ORDER BY l.rang'; + + dol_syslog('FactureRec::fetch', LOG_DEBUG); + $result = $this->db->query($sql); + if ($result) { + $objp = $this->db->fetch_object($result); + + $this->id = $objp->rowid; + $this->fk_facture_fourn = $objp->fk_facture_fourn; + $this->fk_parent = $objp->fk_parent_line; + $this->fk_product = $objp->fk_product; + $this->ref_supplier = $objp->ref_supplier; + $this->label = $objp->label; + $this->description = $objp->description; + $this->pu_ht = $objp->pu_ht; + $this->pu_ttc = $objp->pu_ttc; + $this->qty = $objp->qty; + $this->remise_percent = $objp->remise_percent; + $this->fk_remise_except = $objp->fk_remise_except; + $this->vat_src_code = $objp->vat_src_code; + $this->tva_tx = $objp->tva_tx; + $this->localtax1_tx = $objp->localtax1_tx; + $this->localtax1_type = $objp->localtax1_type; + $this->localtax2_tx = $objp->localtax2_tx; + $this->localtax2_type = $objp->localtax2_type; + $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->product_type = $objp->product_type; + $this->date_start = $objp->date_start; + $this->date_end = $objp->date_end; + $this->info_bits = $objp->info_bits ; + $this->special_code = $objp->special_code; + $this->rang = $objp->rang; + $this->fk_unit = $objp->fk_unit; + $this->import_key = $objp->import_key; + $this->fk_user_author = $objp->fk_user_author; + $this->fk_user_modif = $objp->fk_user_modif; + $this->fk_multicurrency = $objp->fk_multicurrency; + $this->multicurrency_code = $objp->multicurrency_code; + $this->multicurrency_subprice = $objp->multicurrency_subprice; + $this->multicurrency_total_ht = $objp->multicurrency_total_ht; + $this->multicurrency_total_tva = $objp->multicurrency_total_tva; + $this->multicurrency_total_ttc = $objp->multicurrency_total_ttc; + + $this->db->free($result); + return 1; + } else { + $this->error = $this->db->lasterror(); + return -3; + } + } + + + /** + * Update a line to supplier invoice template . + * + * @param User $user User + * @param int $notrigger No trigger + * @return int <0 if KO, Id of line if OK + */ + public function update(User $user, $notrigger = 0) + { + global $conf; + + $error = 0; + + include_once DOL_DOCUMENT_ROOT.'/core/lib/price.lib.php'; + + $sql = 'UPDATE ' . MAIN_DB_PREFIX . 'facture_fourn_det_rec SET'; + $sql .= ' fk_facture_fourn = ' . (int) $this->fk_facture_fourn; + $sql .= ', fk_parent_line = ' . (int) $this->fk_parent; + $sql .= ', fk_product = ' . (int) $this->fk_product; + $sql .= ', ref = ' . (! empty($this->ref) ? "'" . $this->db->escape($this->ref) . "'" : 'null') . "'"; + $sql .= ", label ='" . (! empty($this->label) ? "'" . $this->db->escape($this->label) . "'" : 'null') . "'"; + $sql .= ", description ='" . $this->db->escape($this->description) . "'"; + $sql .= ', pu_ht =' . price2num($this->pu_ht); + $sql .= ', pu_ttc =' . price2num($this->pu_ttc); + $sql .= ', qty =' . price2num($this->qty); + $sql .= ", remise_percent ='" . price2num($this->remise_percent) . "'"; + $sql .= ', fk_remise_except =' . (int) $this->fk_remise_except; + $sql .= ", vat_src_code ='" . $this->db->escape($this->vat_src_code) . "'"; + $sql .= ', tva_tx =' . price2num($this->tva_tx); + $sql .= ', localtax1_tx =' . price2num($this->localtax1_tx); + $sql .= ", localtax1_type ='" . $this->db->escape($this->localtax1_type) . "'"; + $sql .= ', localtax2_tx =' . price2num($this->localtax2_tx); + $sql .= ", localtax2_type ='" . $this->db->escape($this->localtax2_type) . "'"; + if (empty($this->skip_update_total)) { + $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 .= ', product_type =' . (int) $this->product_type; + $sql .= ', date_start =' . (int) $this->date_start; + $sql .= ', date_end =' . (int) $this->date_end; + $sql .= ", info_bits ='" . price2num($this->info_bits) . "'"; + $sql .= ', special_code =' . (int) $this->special_code; + $sql .= ', rang =' . (int) $this->rang; + $sql .= ', fk_unit =' .($this->fk_unit ? "'".$this->db->escape($this->fk_unit)."'" : 'null'); + $sql .= ', fk_user_modif =' . (int) $user; + + $sql .= ' WHERE rowid = ' . (int) $this->id; + + $this->db->begin(); + + dol_syslog(get_class($this). '::updateline', LOG_DEBUG); + $resql = $this->db->query($sql); + if ($resql) { + if (!$error) { + $result = $this->insertExtraFields(); + if ($result < 0) { + $error++; + } + } + + if (!$error && !$notrigger) { + // Call trigger + $result = $this->call_trigger('LINESUPPLIERBILLREC_UPDATE', $user); + if ($result < 0) { + $error++; + } + // End call triggers + } + + if ($error) { + $this->db->rollback(); + return -2; + } else { + $this->db->commit(); + return 1; + } + } else { + $this->error = $this->db->lasterror(); + $this->db->rollback(); + return -2; + } + } +} diff --git a/htdocs/fourn/class/fournisseur.facture.class.php b/htdocs/fourn/class/fournisseur.facture.class.php index e9db81e298f..37d4ee2b11e 100644 --- a/htdocs/fourn/class/fournisseur.facture.class.php +++ b/htdocs/fourn/class/fournisseur.facture.class.php @@ -251,6 +251,8 @@ class FactureFournisseur extends CommonInvoice */ public $fk_facture_source; + public $fac_rec; + public $fields = array( 'rowid' =>array('type'=>'integer', 'label'=>'TechnicalID', 'enabled'=>1, 'visible'=>-1, 'notnull'=>1, 'position'=>10), @@ -410,6 +412,128 @@ class FactureFournisseur extends CommonInvoice $this->db->begin(); + // Create invoice from a template recurring invoice + if ($this->fac_rec > 0) { + $this->fk_fac_rec_source = $this->fac_rec; + + require_once DOL_DOCUMENT_ROOT . '/fourn/class/fournisseur.facture-rec.class.php'; + $_facrec = new FactureFournisseurRec($this->db); + $result = $_facrec->fetch($this->fac_rec); + $result = $_facrec->fetchObjectLinked(null, '', null, '', 'OR', 1, 'sourcetype', 0); // This load $_facrec->linkedObjectsIds + + // Define some dates + if (! empty($_facrec->frequency)) { + $originaldatewhen = $_facrec->date_when; + $nextdatewhen = dol_time_plus_duree($originaldatewhen, $_facrec->frequency, $_facrec->unit_frequency); + $previousdaynextdatewhen = dol_time_plus_duree($nextdatewhen, -1, 'd'); + $this->socid = $_facrec->socid; + } + + $this->entity = $_facrec->entity; // Invoice created in same entity than template + + // Fields coming from GUI (priority on template). TODO Value of template should be used as default value on GUI so we can use here always value from GUI + $this->fk_projet = GETPOST('projectid', 'int') > 0 ? ((int) GETPOST('projectid', 'int')) : $_facrec->fk_projet; + $this->note_public = GETPOST('note_public', 'restricthtml') ? GETPOST('note_public', 'restricthtml') : $_facrec->note_public; + $this->note_private = GETPOST('note_private', 'restricthtml') ? GETPOST('note_private', 'restricthtml') : $_facrec->note_private; + $this->model_pdf = GETPOST('model', 'alpha') ? GETPOST('model', 'alpha') : $_facrec->model_pdf; + $this->cond_reglement_id = GETPOST('cond_reglement_id', 'int') > 0 ? ((int) GETPOST('cond_reglement_id', 'int')) : $_facrec->cond_reglement_id; + $this->mode_reglement_id = GETPOST('mode_reglement_id', 'int') > 0 ? ((int) GETPOST('mode_reglement_id', 'int')) : $_facrec->mode_reglement_id; + $this->fk_account = GETPOST('fk_account') > 0 ? ((int) GETPOST('fk_account')) : $_facrec->fk_account; + + // Set here to have this defined for substitution into notes, should be recalculated after adding lines to get same result + $this->total_ht = $_facrec->total_ht; + $this->total_ttc = $_facrec->total_ttc; + + // Fields always coming from template + $this->remise = $_facrec->remise; + $this->fk_incoterms = $_facrec->fk_incoterms; + $this->location_incoterms = $_facrec->location_incoterms; + + // Clean parameters + if (! $this->type) { + $this->type = self::TYPE_STANDARD; + } + if (! empty(GETPOST('ref_supplier'))) { + $this->ref_supplier = trim($this->ref_supplier); + } else { + $this->ref_supplier = trim($this->ref_supplier . '_' . ($_facrec->nb_gen_done + 1)); + } + $this->note_public = trim($this->note_public); + $this->note_private = trim($this->note_private); + $this->note_private = dol_concatdesc($this->note_private, $langs->trans("GeneratedFromRecurringInvoice", $_facrec->titre)); + + $this->array_options = $_facrec->array_options; + + //if (! $this->remise) $this->remise = 0; + if (! $this->mode_reglement_id) { + $this->mode_reglement_id = 0; + } + $this->brouillon = 1; + $this->status = self::STATUS_DRAFT; + $this->statut = self::STATUS_DRAFT; + + $this->linked_objects = $_facrec->linkedObjectsIds; + // We do not add link to template invoice or next invoice will be linked to all generated invoices + //$this->linked_objects['facturerec'][0] = $this->fac_rec; + + $forceduedate = $this->calculate_date_lim_reglement(); + + // For recurring invoices, update date and number of last generation of recurring template invoice, before inserting new invoice + if ($_facrec->frequency > 0) { + dol_syslog("This is a recurring invoice so we set date_last_gen and next date_when"); + if (empty($_facrec->date_when)) { + $_facrec->date_when = $now; + } + $next_date = $_facrec->getNextDate(); // Calculate next date + $result = $_facrec->setValueFrom('date_last_gen', $now, '', null, 'date', '', $user, ''); + //$_facrec->setValueFrom('nb_gen_done', $_facrec->nb_gen_done + 1); // Not required, +1 already included into setNextDate when second param is 1. + $result = $_facrec->setNextDate($next_date, 1); + } + + // Define lang of customer + $outputlangs = $langs; + $newlang = ''; + + if ($conf->global->MAIN_MULTILANGS && empty($newlang) && isset($this->thirdparty->default_lang)) { + $newlang = $this->thirdparty->default_lang; // for proposal, order, invoice, ... + } + if ($conf->global->MAIN_MULTILANGS && empty($newlang) && isset($this->default_lang)) { + $newlang = $this->default_lang; // for thirdparty + } + if (! empty($newlang)) { + $outputlangs = new Translate("", $conf); + $outputlangs->setDefaultLang($newlang); + } + + // Array of possible substitutions (See also file mailing-send.php that should manage same substitutions) + $substitutionarray = getCommonSubstitutionArray($outputlangs, 0, null, $this); + $substitutionarray['__INVOICE_PREVIOUS_MONTH__'] = dol_print_date(dol_time_plus_duree($this->date, -1, 'm'), '%m'); + $substitutionarray['__INVOICE_MONTH__'] = dol_print_date($this->date, '%m'); + $substitutionarray['__INVOICE_NEXT_MONTH__'] = dol_print_date(dol_time_plus_duree($this->date, 1, 'm'), '%m'); + $substitutionarray['__INVOICE_PREVIOUS_MONTH_TEXT__'] = dol_print_date(dol_time_plus_duree($this->date, -1, 'm'), '%B'); + $substitutionarray['__INVOICE_MONTH_TEXT__'] = dol_print_date($this->date, '%B'); + $substitutionarray['__INVOICE_NEXT_MONTH_TEXT__'] = dol_print_date(dol_time_plus_duree($this->date, 1, 'm'), '%B'); + $substitutionarray['__INVOICE_PREVIOUS_YEAR__'] = dol_print_date(dol_time_plus_duree($this->date, -1, 'y'), '%Y'); + $substitutionarray['__INVOICE_YEAR__'] = dol_print_date($this->date, '%Y'); + $substitutionarray['__INVOICE_NEXT_YEAR__'] = dol_print_date(dol_time_plus_duree($this->date, 1, 'y'), '%Y'); + // Only for template invoice + $substitutionarray['__INVOICE_DATE_NEXT_INVOICE_BEFORE_GEN__'] = dol_print_date($originaldatewhen, 'dayhour'); + $substitutionarray['__INVOICE_DATE_NEXT_INVOICE_AFTER_GEN__'] = dol_print_date($nextdatewhen, 'dayhour'); + $substitutionarray['__INVOICE_PREVIOUS_DATE_NEXT_INVOICE_AFTER_GEN__'] = dol_print_date($previousdaynextdatewhen, 'dayhour'); + $substitutionarray['__INVOICE_COUNTER_CURRENT__'] = $_facrec->nb_gen_done; + $substitutionarray['__INVOICE_COUNTER_MAX__'] = $_facrec->nb_gen_max; + + complete_substitutions_array($substitutionarray, $outputlangs); + + $this->note_public = make_substitutions($this->note_public, $substitutionarray); + $this->note_private = make_substitutions($this->note_private, $substitutionarray); + } + + // Define due date if not already defined + if (! empty($forceduedate)) { + $this->date_echeance = $forceduedate; + } + if (!$remise) { $remise = 0; } @@ -437,6 +561,7 @@ class FactureFournisseur extends CommonInvoice $sql .= ", multicurrency_code"; $sql .= ", multicurrency_tx"; $sql .= ", fk_facture_source"; + $sql .= ", fk_fac_rec_source"; $sql .= ")"; $sql .= " VALUES ("; $sql .= "'(PROV)'"; @@ -462,6 +587,7 @@ class FactureFournisseur extends CommonInvoice $sql .= ", '".$this->db->escape($this->multicurrency_code)."'"; $sql .= ", ".(double) $this->multicurrency_tx; $sql .= ", ".(isset($this->fk_facture_source) ? $this->fk_facture_source : "NULL"); + $sql .= ", ".(isset($this->fk_fac_rec_source) ? $this->fk_fac_rec_source : "NULL"); $sql .= ")"; dol_syslog(get_class($this)."::create", LOG_DEBUG); @@ -506,7 +632,7 @@ class FactureFournisseur extends CommonInvoice } } - if (count($this->lines) && is_object($this->lines[0])) { // If this->lines is array of InvoiceLines (preferred mode) + if (!$error && empty($this->fac_rec) && count($this->lines) && is_object($this->lines[0])) { // If this->lines is array of InvoiceLines (preferred mode) dol_syslog("There is ".count($this->lines)." lines that are invoice lines objects"); foreach ($this->lines as $i => $val) { $sql = 'INSERT INTO '.MAIN_DB_PREFIX.'facture_fourn_det (fk_facture_fourn, special_code, fk_remise_except)'; @@ -516,7 +642,7 @@ class FactureFournisseur extends CommonInvoice if ($resql_insert) { $idligne = $this->db->last_insert_id(MAIN_DB_PREFIX.'facture_fourn_det'); - $this->updateline( + $res = $this->updateline( $idligne, $this->lines[$i]->description, $this->lines[$i]->pu_ht, @@ -543,8 +669,7 @@ class FactureFournisseur extends CommonInvoice return -5; } } - } else // If this->lines is an array of invoice line arrays - { + } elseif (!$error && empty($this->fac_rec)) { // If this->lines is an array of invoice line arrays dol_syslog("There is ".count($this->lines)." lines that are array lines"); foreach ($this->lines as $i => $val) { $line = $this->lines[$i]; @@ -591,6 +716,92 @@ class FactureFournisseur extends CommonInvoice } } + /* + * Insert lines of template 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); + } + + // For line from template invoice, we use data from template invoice + /* + $tva_tx = get_default_tva($mysoc,$soc,$prod->id); + $tva_npr = get_default_npr($mysoc,$soc,$prod->id); + if (empty($tva_tx)) $tva_npr=0; + $localtax1_tx=get_localtax($tva_tx,1,$soc,$mysoc,$tva_npr); + $localtax2_tx=get_localtax($tva_tx,2,$soc,$mysoc,$tva_npr); + */ + $tva_tx = $_facrec->lines[$i]->tva_tx . ($_facrec->lines[$i]->vat_src_code ? '(' . $_facrec->lines[$i]->vat_src_code . ')' : ''); + $tva_npr = $_facrec->lines[$i]->info_bits; + if (empty($tva_tx)) { + $tva_npr = 0; + } + $localtax1_tx = $_facrec->lines[$i]->localtax1_tx; + $localtax2_tx = $_facrec->lines[$i]->localtax2_tx; + + $fk_product_fournisseur_price = empty($_facrec->lines[$i]->fk_product_fournisseur_price) ? null : $_facrec->lines[$i]->fk_product_fournisseur_price; + $buyprice = empty($_facrec->lines[$i]->buyprice) ? 0 : $_facrec->lines[$i]->buyprice; + + // If buyprice not defined from template invoice, we try to guess the best value + if (! $buyprice && $_facrec->lines[$i]->fk_product > 0) { + require_once DOL_DOCUMENT_ROOT . '/fourn/class/fournisseur.product.class.php'; + $producttmp = new ProductFournisseur($this->db); + $producttmp->fetch($_facrec->lines[$i]->fk_product); + + // If margin module defined on costprice, we try the costprice + // If not defined or if module margin defined and pmp and stock module enabled, we try pmp price + // else we get the best supplier price + if ($conf->global->MARGIN_TYPE == 'costprice' && ! empty($producttmp->cost_price)) { + $buyprice = $producttmp->cost_price; + } elseif (! empty($conf->stock->enabled) && ($conf->global->MARGIN_TYPE == 'costprice' || $conf->global->MARGIN_TYPE == 'pmp') && ! empty($producttmp->pmp)) { + $buyprice = $producttmp->pmp; + } else { + if ($producttmp->find_min_price_product_fournisseur($_facrec->lines[$i]->fk_product) > 0) { + if ($producttmp->product_fourn_price_id > 0) { + $buyprice = price2num($producttmp->fourn_unitprice * (1 - $producttmp->fourn_remise_percent / 100) + $producttmp->fourn_remise, 'MU'); + } + } + } + } + + $result_insert = $this->addline( + $_facrec->lines[$i]->description, + $_facrec->lines[$i]->pu_ht, + $tva_tx, + $localtax1_tx, + $localtax2_tx, + $_facrec->lines[$i]->qty, + $_facrec->lines[$i]->fk_product, + $_facrec->lines[$i]->remise_percent, + ($_facrec->lines[$i]->date_start == 1 && $this->date) ? $this->date : '', + ($_facrec->lines[$i]->date_end == 1 && $previousdaynextdatewhen) ? $previousdaynextdatewhen : '', + 0, + $_facrec->lines[$i]->info_bits, + 'HT', + 0, + $_facrec->lines[$i]->rang, + false, + $_facrec->lines[$i]->array_options, + $_facrec->lines[$i]->fk_unit, + 0, + 0, + $_facrec->lines[$i]->ref_supplier, + $_facrec->lines[$i]->special_code, + 0, + 0, + ); + if ($result_insert < 0) { + $error++; + $this->error = $this->db->error(); + break; + } + } + } + + // Update total price $result = $this->update_price(); if ($result > 0) { @@ -674,6 +885,7 @@ class FactureFournisseur extends CommonInvoice $sql .= " t.fk_user_author,"; $sql .= " t.fk_user_valid,"; $sql .= " t.fk_facture_source,"; + $sql .= " t.fk_fac_rec_source,"; $sql .= " t.fk_projet as fk_project,"; $sql .= " t.fk_cond_reglement,"; $sql .= " t.fk_account,"; @@ -741,6 +953,7 @@ class FactureFournisseur extends CommonInvoice $this->author = $obj->fk_user_author; $this->fk_user_valid = $obj->fk_user_valid; $this->fk_facture_source = $obj->fk_facture_source; + $this->fk_fac_rec_source = $obj->fk_fac_rec_source; $this->fk_project = $obj->fk_project; $this->cond_reglement_id = $obj->fk_cond_reglement; $this->cond_reglement_code = $obj->cond_reglement_code; @@ -3412,7 +3625,7 @@ class SupplierInvoiceLine extends CommonObjectLine $this->db->begin(); $sql = "UPDATE ".MAIN_DB_PREFIX."facture_fourn_det SET"; - $sql .= " description ='".$this->db->escape($this->description)."'"; + $sql .= ' description ="'.$this->db->escape($this->description).'"'; $sql .= ", ref ='".$this->db->escape($this->ref_supplier ? $this->ref_supplier : $this->ref)."'"; $sql .= ", date_start = ".($this->date_start != '' ? "'".$this->db->idate($this->date_start)."'" : "null"); $sql .= ", date_end = ".($this->date_end != '' ? "'".$this->db->idate($this->date_end)."'" : "null"); diff --git a/htdocs/fourn/facture/card-rec.php b/htdocs/fourn/facture/card-rec.php new file mode 100644 index 00000000000..502d0d124ce --- /dev/null +++ b/htdocs/fourn/facture/card-rec.php @@ -0,0 +1,1644 @@ + + * Copyright (C) 2004-2016 Laurent Destailleur + * Copyright (C) 2005-2012 Regis Houssin + * Copyright (C) 2013 Florian Henry + * Copyright (C) 2013 Juanjo Menent + * Copyright (C) 2015 Jean-François Ferry + * Copyright (C) 2012 Cedric Salvador + * Copyright (C) 2015 Alexandre Spangaro + * Copyright (C) 2016 Meziane Sof + * Copyright (C) 2017-2018 Frédéric France + * + * 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/fourn/facture/card-rec.php + * \ingroup facture fournisseurs + * \brief Page to show predefined invoice + */ + +require '../../main.inc.php'; +require_once DOL_DOCUMENT_ROOT . '/fourn/class/fournisseur.facture-rec.class.php'; +require_once DOL_DOCUMENT_ROOT . '/fourn/class/fournisseur.product.class.php'; +require_once DOL_DOCUMENT_ROOT . '/product/class/product.class.php'; +require_once DOL_DOCUMENT_ROOT . '/core/class/html.formother.class.php'; +if (! empty($conf->projet->enabled)) { + include_once DOL_DOCUMENT_ROOT . '/projet/class/project.class.php'; +} +require_once DOL_DOCUMENT_ROOT . '/core/class/html.formprojet.class.php'; +require_once DOL_DOCUMENT_ROOT . '/core/class/doleditor.class.php'; +require_once DOL_DOCUMENT_ROOT . '/core/lib/invoice.lib.php'; +require_once DOL_DOCUMENT_ROOT . '/core/class/extrafields.class.php'; + +// Load translation files required by the page +$langs->loadLangs(array('bills', 'companies', 'compta', 'admin', 'other', 'products', 'banks', 'suppliers')); + +$action = GETPOST('action', 'alpha'); +$massaction = GETPOST('massaction', 'alpha'); +$show_files = GETPOST('show_files', 'int'); +$confirm = GETPOST('confirm', 'alpha'); +$cancel = GETPOST('cancel', 'alpha'); +$toselect = GETPOST('toselect', 'array'); +$contextpage = GETPOST('contextpage', 'aZ') ? GETPOST('contextpage', 'aZ') : 'supplierinvoicetemplatelist'; // To manage different context of search + +$limit = GETPOST('limit', 'int') ? GETPOST('limit', 'int') : $conf->liste_limit; +$sortfield = GETPOST("sortfield", 'alpha'); +$sortorder = GETPOST("sortorder", 'alpha'); +$page = GETPOSTISSET('pageplusone') ? (GETPOST('pageplusone') - 1) : GETPOST("page", 'int'); + +// Security check +$id = (GETPOST('facid', 'int') ? GETPOST('facid', 'int') : GETPOST('id', 'int')); +$lineid = GETPOST('lineid', 'int'); +$title = GETPOST('title', 'alpha'); +$ref_supplier = GETPOST('ref_supplier', 'alpha'); +$projectid = GETPOST('projectid', 'int'); +$year_date_when = GETPOST('year_date_when'); +$month_date_when = GETPOST('month_date_when'); +if ($user->socid) { + $socid = $user->socid; +} +$objecttype = 'facturefournisseur_rec'; +if ($action == "create" || $action == "add") { + $objecttype = ''; +} + +if (empty($page) || $page == -1) { + $page = 0; +} // If $page is not defined, or '' or -1 +$offset = $limit * $page; +if (! $sortorder) { + $sortorder = 'DESC'; +} +if (! $sortfield) { + $sortfield = 'f.titre'; +} +$pageprev = $page - 1; +$pagenext = $page + 1; + +$object = new FactureFournisseurRec($db); +if (($id > 0 || $title) && $action != 'create' && $action != 'add') { + $ret = $object->fetch($id, $title); + if (! $ret) { + setEventMessages($langs->trans("ErrorRecordNotFound"), null, 'errors'); + } +} + +// Initialize technical object to manage hooks of page. Note that conf->hooks_modules contains array of hook context +$hookmanager->initHooks(array('supplierinvoicereccard', 'globalcard')); +$extrafields = new ExtraFields($db); + +// fetch optionals attributes and labels +$extrafields->fetch_name_optionals_label($object->table_element); + +$search_array_options = $extrafields->getOptionalsFromPost($object->table_element, '', 'search_'); + +$permissionnote = $user->rights->fournisseur->facture->creer || $user->rights->supplier_invoice->creer; // Used by the include of actions_setnotes.inc.php +$permissiondellink = $user->rights->fournisseur->facture->creer || $user->rights->supplier_invoice->creer;; // Used by the include of actions_dellink.inc.php +$permissiontoedit = $user->rights->fournisseur->facture->creer || $user->rights->supplier_invoice->creer;; // Used by the include of actions_lineupdonw.inc.php + +$usercanread = $user->rights->fournisseur->facture->lire || $user->rights->supplier_invoice->lire; +$usercancreate = $user->rights->fournisseur->facture->creer || $user->rights->supplier_invoice->creer; +$usercandelete = $user->rights->fournisseur->facture->supprimer || $user->rights->supplier_invoice->supprimer; +$usercanvalidate = ((empty($conf->global->MAIN_USE_ADVANCED_PERMS) && ! empty($usercancreate)) || (! empty($conf->global->MAIN_USE_ADVANCED_PERMS) && ! empty($user->rights->fournisseur->supplier_invoice_advance->validate))); +$usercansend = (empty($conf->global->MAIN_USE_ADVANCED_PERMS) || $user->rights->fournisseur->supplier_invoice_advance->send); + +$usercanproductignorepricemin = ((! empty($conf->global->MAIN_USE_ADVANCED_PERMS) && empty($user->rights->produit->ignore_price_min_advance)) || empty($conf->global->MAIN_USE_ADVANCED_PERMS)); +$usercancreatemargin = $user->rights->margins->creer; +$usercanreadallmargin = $user->rights->margins->liretous; +$usercancreatewithdrarequest = $user->rights->prelevement->bons->creer; + +$now = dol_now(); + +$error = 0; + +$result = restrictedArea($user, 'facture', $object->id, $objecttype); + +/* + * Actions + */ + +if (GETPOST('cancel', 'alpha')) { + $action = 'list'; + $massaction = ''; +} +if (! GETPOST('confirmmassaction', 'alpha') && $massaction != 'presend' && $massaction != 'confirm_presend') { + $massaction = ''; +} + +$parameters = array('socid' => $socid); +$reshook = $hookmanager->executeHooks('doActions', $parameters, $object, $action); // Note that $action and $object may have been modified by some hooks +if ($reshook < 0) { + setEventMessages($hookmanager->error, $hookmanager->errors, 'errors'); +} + +if (empty($reshook)) { + if (GETPOST('cancel', 'alpha')) { + $action = ''; + } + + // Selection of new fields + include DOL_DOCUMENT_ROOT . '/core/actions_changeselectedfields.inc.php'; + + // Set note + include DOL_DOCUMENT_ROOT . '/core/actions_setnotes.inc.php'; // Must be include, not include_once + + include DOL_DOCUMENT_ROOT . '/core/actions_dellink.inc.php'; // Must be include, not include_once + + include DOL_DOCUMENT_ROOT . '/core/actions_lineupdown.inc.php'; // Must be include, not include_once + + // Create predefined invoice + if ($action == 'add') { + if (! GETPOST('title', 'alphanohtml')) { + setEventMessages($langs->transnoentities("ErrorFieldRequired", $langs->trans("Title")), null, 'errors'); + $action = "create"; + $error++; + } + + $frequency = GETPOST('frequency', 'int'); + $reyear = GETPOST('reyear', 'int'); + $remonth = GETPOST('remonth', 'int'); + $reday = GETPOST('reday', 'int'); + $rehour = GETPOST('rehour', 'int'); + $remin = GETPOST('remin', 'int'); + $nb_gen_max = GETPOST('nb_gen_max', 'int'); + //if (empty($nb_gen_max)) $nb_gen_max =0; + + if (GETPOST('frequency', 'int')) { + if (empty($reyear) || empty($remonth) || empty($reday)) { + setEventMessages($langs->transnoentities("ErrorFieldRequired", $langs->trans("Date")), null, 'errors'); + $action = "create"; + $error++; + } + } + + if (! $error) { + $object->titre = GETPOST('title', 'nohtml'); // deprecated + $object->title = GETPOST('title', 'nohtml'); + $object->fk_project = GETPOST('projectid', 'int'); + $object->ref_supplier = GETPOST('ref_supplier', 'nohtml'); + + $object->note_private = GETPOST('note_private', 'restricthtml'); + $object->note_public = GETPOST('note_public', 'restricthtml'); + $object->model_pdf = GETPOST('modelpdf', 'alpha'); + $object->usenewprice = GETPOST('usenewprice', 'alpha'); + + $object->frequency = $frequency; + $object->unit_frequency = GETPOST('unit_frequency', 'alpha'); + $object->nb_gen_max = $nb_gen_max; + $object->auto_validate = GETPOST('auto_validate', 'int'); + $object->generate_pdf = GETPOST('generate_pdf', 'int'); + + $date_next_execution = dol_mktime($rehour, $remin, 0, $remonth, $reday, $reyear); + $object->date_when = $date_next_execution; + + $db->begin(); + + $oldinvoice = new FactureFournisseur($db); + $oldinvoice->fetch(GETPOST('facid', 'int')); + + $object->cond_reglement_id = $oldinvoice->cond_reglement_id; + $object->cond_reglement_code = $oldinvoice->cond_reglement_code; + $object->cond_reglement_label = $oldinvoice->cond_reglement_label; + $object->cond_reglement_doc = $oldinvoice->cond_reglement_doc; + $object->mode_reglement_id = $oldinvoice->mode_reglement_id; + $object->mode_reglement_code = $oldinvoice->mode_reglement_code; + + $result = $object->create($user, $oldinvoice->id); + if ($result > 0) { + $result = $oldinvoice->delete($user, 1); + if ($result < 0) { + $error++; + setEventMessages($oldinvoice->error, $oldinvoice->errors, 'errors'); + $action = "create"; + } + } else { + $error++; + setEventMessages($object->error, $object->errors, 'errors'); + $action = "create"; + } + + if (! $error) { + $db->commit(); + + header("Location: " . $_SERVER['PHP_SELF'] . '?facid=' . $object->id); + exit; + } else { + $db->rollback(); + + $error++; + setEventMessages($object->error, $object->errors, 'errors'); + $action = "create"; + } + } + } + + // Delete + //TODO : Droits + if ($action == 'confirm_deleteinvoice' && $confirm == 'yes' && ($user->rights->fournisseur->facture->supprimer || $user->rights->supplier_invoice->supprimer)) { + $object->delete($user); + + header('Location: ' . DOL_URL_ROOT . '/fourn/facture/list-rec.php'); + exit; + } + + // Update field + // Set condition + if ($action == 'setconditions' && $usercancreate) { + $result = $object->setPaymentTerms(GETPOST('cond_reglement_id', 'int')); + } elseif ($action == 'setmode' && $usercancreate) { + // Set mode + $result = $object->setPaymentMethods(GETPOST('mode_reglement_id', 'int')); + } elseif ($action == 'classin' && $usercancreate) { + // Set project + $object->setProject(GETPOST('projectid', 'int')); + } elseif ($action == 'setref_supplier' && $usercancreate) { + $result = $object->setValueFrom('ref_supplier', $ref_supplier, '', null, 'text', '', $user); + + if ($result <= 0) { + $error++; + if ($object->error == 'DB_ERROR_RECORD_ALREADY_EXISTS') { + $langs->load("errors"); + setEventMessages($langs->trans('ErrorRefAlreadyExists', $ref_supplier), null, 'errors'); + } else { + setEventMessages($object->error, $object->errors, 'errors'); + } + } + } elseif ($action == 'settitle' && $usercancreate) { + $result = $object->setValueFrom('titre', $title, '', null, 'text', '', $user); + + if ($result > 0) { + $object->titre = $title; + $object->title = $title; + $object->ref = $object->title; + } else { + $error++; + if ($object->error == 'DB_ERROR_RECORD_ALREADY_EXISTS') { + $langs->load("errors"); + setEventMessages($langs->trans('ErrorTitreAlreadyExists', $title), null, 'errors'); + } else { + setEventMessages($object->error, $object->errors, 'errors'); + } + } + } elseif ($action == 'setbankaccount' && $usercancreate) { + // Set bank account + $result = $object->setBankAccount(GETPOST('fk_account', 'int')); + } elseif ($action == 'setfrequency' && $usercancreate) { + // Set frequency and unit frequency + $object->setFrequencyAndUnit(GETPOST('frequency', 'int'), GETPOST('unit_frequency', 'alpha')); + } elseif ($action == 'setdate_when' && $usercancreate) { + // Set next date of execution + $date = dol_mktime(GETPOST('date_whenhour'), GETPOST('date_whenmin'), 0, GETPOST('date_whenmonth'), GETPOST('date_whenday'), GETPOST('date_whenyear')); + if (! empty($date)) { + $object->setNextDate($date); + } + } elseif ($action == 'setnb_gen_max' && $usercancreate) { + // Set max period + $object->setMaxPeriod(GETPOST('nb_gen_max', 'int')); + } elseif ($action == 'setauto_validate' && $usercancreate) { + // Set auto validate + $object->setAutoValidate(GETPOST('auto_validate', 'int')); + } elseif ($action == 'setgenerate_pdf' && $usercancreate) { + // Set generate pdf + $object->setGeneratepdf(GETPOST('generate_pdf', 'int')); + } elseif ($action == 'setmodelpdf' && $usercancreate) { + // Set model pdf + $object->setModelpdf(GETPOST('modelpdf', 'alpha')); + } elseif ($action == 'disable' && $usercancreate) { + // Set status disabled + $db->begin(); + + $object->fetch($id); + + $res = $object->setValueFrom('suspended', 1); + if ($res <= 0) { + $error++; + } + + if (! $error) { + $db->commit(); + } else { + $db->rollback(); + setEventMessages($object->error, $object->errors, 'errors'); + } + } elseif ($action == 'enable' && $usercancreate) { + // Set status enabled + $db->begin(); + + $object->fetch($id); + + $res = $object->setValueFrom('suspended', 0); + if ($res <= 0) { + $error++; + } + + if (! $error) { + $db->commit(); + } else { + $db->rollback(); + setEventMessages($object->error, $object->errors, 'errors'); + } + } elseif ($action == 'setmulticurrencycode' && $usercancreate) { + // Multicurrency Code + $result = $object->setMulticurrencyCode(GETPOST('multicurrency_code', 'alpha')); + } elseif ($action == 'setmulticurrencyrate' && $usercancreate) { + // Multicurrency rate + $result = $object->setMulticurrencyRate(price2num(GETPOST('multicurrency_tx')), GETPOST('calculation_mode', 'int')); + } elseif ($action == 'setlibelle' && $usercancreate) { + // Set label + $object->fetch($id); + $object->libelle = GETPOST('libelle'); + $result = $object->update($user); + + if ($result < 0) { + dol_print_error($db); + } + } + + // Delete line + if ($action == 'confirm_deleteline' && $confirm == 'yes' && $usercancreate) { + $object->fetch($id); + $object->fetch_thirdparty(); + + $db->begin(); + + $line = new FactureFournisseurLigneRec($db); + + // For triggers + $line->id = $lineid; + + if ($line->delete($user) > 0) { + $result = $object->update_price(1); + + if ($result > 0) { + $db->commit(); + $object->fetch($object->id); // Reload lines + } else { + $db->rollback(); + setEventMessages($db->lasterror(), null, 'errors'); + } + } else { + $db->rollback(); + setEventMessages($line->error, $line->errors, 'errors'); + } + } elseif ($action == 'update_extras') { + $object->oldcopy = dol_clone($object); + + // Fill array 'array_options' with data from update form + $ret = $extrafields->setOptionalsFromPost(null, $object, GETPOST('attribute', 'restricthtml')); + if ($ret < 0) { + $error++; + } + + if (! $error) { + $result = $object->insertExtraFields('BILLREC_MODIFY'); + if ($result < 0) { + setEventMessages($object->error, $object->errors, 'errors'); + $error++; + } + } + } + + // Add a new line + if ($action == 'addline' && $usercancreate) { + $langs->load('errors'); + $error = 0; + + // Set if we used free entry or predefined product + + $product_desc = (GETPOSTISSET('dp_desc') ? GETPOST('dp_desc', 'restricthtml') : ''); + $price_ht = price2num(GETPOST('price_ht'), 'MU', 2); + $price_ht_devise = price2num(GETPOST('multicurrency_price_ht'), 'CU', 2); + $prod_entry_mode = GETPOST('prod_entry_mode', 'alpha'); + if ($prod_entry_mode == 'free') { + $idprod = 0; + $tva_tx = (GETPOST('tva_tx', 'alpha') ? GETPOST('tva_tx', 'alpha') : 0); + $ref_fournisseur = (GETPOSTISSET('fourn_ref') ? GETPOST('fourn_ref', 'restricthtml') : ''); + } else { + $idprod = GETPOST('idprod', 'int'); + $tva_tx = ''; + } + + $qty = price2num(GETPOST('qty' . $predef, 'alpha'), 'MS', 2); + $remise_percent = price2num(GETPOST('remise_percent' . $predef), '', 2); + + // Extrafields + $extralabelsline = $extrafields->fetch_name_optionals_label($object->table_element_line); + $array_options = $extrafields->getOptionalsFromPost($object->table_element_line, $predef); + // Unset extrafield + if (is_array($extralabelsline)) { + // Get extra fields + foreach ($extralabelsline as $key => $value) { + unset($_POST["options_" . $key . $predef]); + } + } + + if ((empty($idprod) || $idprod < 0) && ($price_ht < 0) && ($qty < 0)) { + setEventMessages($langs->trans('ErrorBothFieldCantBeNegative', $langs->transnoentitiesnoconv('UnitPriceHT'), $langs->transnoentitiesnoconv('Qty')), null, 'errors'); + $error++; + } + if ($prod_entry_mode == 'free' && (empty($idprod) || $idprod < 0) && GETPOST('type') < 0) { + setEventMessages($langs->trans('ErrorFieldRequired', $langs->transnoentitiesnoconv('Type')), null, 'errors'); + $error++; + } + if ($prod_entry_mode == 'free' && (empty($idprod) || $idprod < 0) && (! ($price_ht >= 0) || $price_ht == '')) { // Unit price can be 0 but not '' + setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("UnitPriceHT")), null, 'errors'); + $error++; + } + if ($qty == '') { + setEventMessages($langs->trans('ErrorFieldRequired', $langs->transnoentitiesnoconv('Qty')), null, 'errors'); + $error++; + } + if ($prod_entry_mode == 'free' && (empty($idprod) || $idprod < 0) && empty($product_desc)) { + setEventMessages($langs->trans('ErrorFieldRequired', $langs->transnoentitiesnoconv('Description')), null, 'errors'); + $error++; + } + if ($qty < 0) { + $langs->load("errors"); + setEventMessages($langs->trans('ErrorQtyForCustomerInvoiceCantBeNegative'), null, 'errors'); + $error++; + } + + if ($prod_entry_mode != 'free' && empty($error)) { // With combolist mode idprodfournprice is > 0 or -1. With autocomplete, idprodfournprice is > 0 or '' + $productsupplier = new ProductFournisseur($db); + + $idprod = 0; + if (GETPOST('idprodfournprice', 'alpha') == -1 || GETPOST('idprodfournprice', 'alpha') == '') { + $idprod = -99; // Same behaviour than with combolist. When not select idprodfournprice is now -99 (to avoid conflict with next action that may return -1, -2, ...) + } + $reg = array(); + if (preg_match('/^idprod_([0-9]+)$/', GETPOST('idprodfournprice', 'alpha'), $reg)) { + $idprod = (int) $reg[1]; + $res = $productsupplier->fetch($idprod); // Load product from its id + // Call to init some price properties of $productsupplier + // So if a supplier price already exists for another thirdparty (first one found), we use it as reference price + if (! empty($conf->global->SUPPLIER_TAKE_FIRST_PRICE_IF_NO_PRICE_FOR_CURRENT_SUPPLIER)) { + $fksoctosearch = 0; + $productsupplier->get_buyprice(0, -1, $idprod, 'none', $fksoctosearch); // We force qty to -1 to be sure to find if a supplier price exist + if ($productsupplier->fourn_socid != $socid) { // The price we found is for another supplier, so we clear supplier price + $productsupplier->ref_supplier = ''; + } + } else { + $fksoctosearch = $object->thirdparty->id; + $productsupplier->get_buyprice(0, -1, $idprod, 'none', $fksoctosearch); // We force qty to -1 to be sure to find if a supplier price exist + } + } elseif (GETPOST('idprodfournprice', 'alpha') > 0) { + $qtytosearch = $qty; // Just to see if a price exists for the quantity. Not used to found vat. + $idprod = $productsupplier->get_buyprice(GETPOST('idprodfournprice', 'alpha'), $qtytosearch); + $res = $productsupplier->fetch($idprod); + $ref_fournisseur = $productsupplier->ref_supplier; + } + } + + if (! $error && ($qty >= 0) && (! empty($product_desc) || (! empty($idprod) && $idprod > 0))) { + $ret = $object->fetch($id); + if ($ret < 0) { + dol_print_error($db, $object->error); + exit(); + } + $ret = $object->fetch_thirdparty(); + + // Clean parameters + $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 + + // Ecrase $pu par celui du produit + // Ecrase $desc par celui du produit + // Ecrase $tva_tx par celui du produit + // Ecrase $base_price_type par celui du produit + // Replaces $fk_unit with the product's + if (! empty($idprod) && $idprod > 0) { + $prod = new Product($db); + $prod->fetch($idprod); + + $label = ((GETPOST('product_label') && GETPOST('product_label') != $prod->label) ? GETPOST('product_label') : ''); + + // Update if prices fields are defined + $tva_tx = get_default_tva($mysoc, $object->thirdparty, $prod->id); + $tva_npr = get_default_npr($mysoc, $object->thirdparty, $prod->id); + if (empty($tva_tx)) { + $tva_npr = 0; + } + + // Search the correct price into loaded array product_price_by_qty using id of array retrieved into POST['pqp']. + $pqp = (GETPOST('pbq', 'int') ? GETPOST('pbq', 'int') : 0); + + $datapriceofproduct = $prod->getSellPrice($mysoc, $object->thirdparty, $pqp); + + $pu_ht = $datapriceofproduct['pu_ht']; + $pu_ttc = $datapriceofproduct['pu_ttc']; + $price_min = $datapriceofproduct['price_min']; + $price_base_type = $datapriceofproduct['price_base_type']; + $tva_tx = $datapriceofproduct['tva_tx']; + $tva_npr = $datapriceofproduct['tva_npr']; + + $tmpvat = price2num(preg_replace('/\s*\(.*\)/', '', $tva_tx)); + $tmpprodvat = price2num(preg_replace('/\s*\(.*\)/', '', $prod->tva_tx)); + + // if price ht was forced (ie: from gui when calculated by margin rate and cost price). TODO Why this ? + if (! empty($price_ht)) { + $pu_ht = price2num($price_ht, 'MU'); + $pu_ttc = price2num($pu_ht * (1 + ($tmpvat / 100)), 'MU'); + } elseif ($tmpvat != $tmpprodvat) { + // 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 ($price_base_type != 'HT') { + $pu_ht = price2num($pu_ttc / (1 + ($tmpvat / 100)), 'MU'); + } else { + $pu_ttc = price2num($pu_ht * (1 + ($tmpvat / 100)), 'MU'); + } + } + + $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', 'aZ09')) { + $newlang = GETPOST('lang_id', 'aZ09'); + } + if (empty($newlang)) { + $newlang = $object->thirdparty->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 = 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 = '('; + // 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', 'alpha')) { + $newlang = GETPOST('lang_id', 'alpha'); + } + if (empty($newlang)) { + $newlang = $object->thirdparty->default_lang; + } + if (! empty($newlang)) { + $outputlangs = new Translate("", $conf); + $outputlangs->setDefaultLang($newlang); + $outputlangs->load('products'); + } + if (! empty($prod->customcode)) { + $tmptxt .= $outputlangs->transnoentitiesnoconv("CustomCode") . ': ' . $prod->customcode; + } + if (! empty($prod->customcode) && ! empty($prod->country_code)) { + $tmptxt .= ' - '; + } + if (! empty($prod->country_code)) { + $tmptxt .= $outputlangs->transnoentitiesnoconv("CountryOrigin") . ': ' . getCountry($prod->country_code, 0, $db, $outputlangs, 0); + } + } else { + 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; + $fk_unit = $prod->fk_unit; + } 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); + if (empty($tva_tx)) { + $tva_npr = 0; + } + $desc = $product_desc; + $type = GETPOST('type'); + $fk_unit = GETPOST('units', 'alpha'); + } + + $date_start_fill = ! empty(GETPOST('date_start_fill', 'int')) ? GETPOST('date_start_fill', 'int') : null; + $date_end_fill = ! empty(GETPOST('date_end_fill', 'int')) ? GETPOST('date_end_fill', 'int') : null; + + // Margin + $fournprice = price2num(GETPOST('fournprice' . $predef) ? GETPOST('fournprice' . $predef) : ''); + $buyingprice = price2num(GETPOST('buying_price' . $predef) != '' ? GETPOST('buying_price' . $predef) : ''); // If buying_price is '0', we must keep this value + + // Local Taxes + $localtax1_tx = get_localtax($tva_tx, 1, $object->thirdparty, $mysoc, $tva_npr); + $localtax2_tx = get_localtax($tva_tx, 2, $object->thirdparty, $mysoc, $tva_npr); + $info_bits = 0; + if ($tva_npr) { + $info_bits |= 0x01; + } + + //To set vars in float type to avoid non-numeric warnings + $pu_ht = (float) price2num($pu_ht); + $remise_percent = (float) price2num($remise_percent); + + $price_min = (float) price2num($price_min); + if ($usercanproductignorepricemin && (! empty($price_min) && ($pu_ht * (1 - $remise_percent / 100) < $price_min))) { + $mesg = $langs->trans("CantBeLessThanMinPrice", price(price2num($price_min, 'MU'), 0, $langs, 0, 0, -1, $conf->currency)); + setEventMessages($mesg, null, 'errors'); + } else { + // Insert line + $result = $object->addline($idprod, $ref_fournisseur, $label, $desc, $pu_ht, $pu_ttc, $qty, $remise_percent, $tva_tx, $localtax1_tx, $localtax2_tx, $price_base_type, $type, $date_start_fill, $date_end_fill, $info_bits, $special_code, -1, $fk_unit); + + if ($result > 0) { + $object->fetch($object->id); // Reload lines + + unset($_POST['prod_entry_mode']); + unset($_POST['qty']); + unset($_POST['type']); + unset($_POST['remise_percent']); + unset($_POST['price_ht']); + unset($_POST['multicurrency_price_ht']); + unset($_POST['price_ttc']); + unset($_POST['tva_tx']); + unset($_POST['product_ref']); + unset($_POST['product_label']); + unset($_POST['product_desc']); + unset($_POST['fournprice']); + unset($_POST['buying_price']); + unset($_POST['np_marginRate']); + unset($_POST['np_markRate']); + unset($_POST['dp_desc']); + unset($_POST['idprod']); + unset($_POST['units']); + unset($_POST['date_starthour']); + unset($_POST['date_startmin']); + unset($_POST['date_startsec']); + unset($_POST['date_startday']); + unset($_POST['date_startmonth']); + unset($_POST['date_startyear']); + unset($_POST['date_endhour']); + unset($_POST['date_endmin']); + unset($_POST['date_endsec']); + unset($_POST['date_endday']); + unset($_POST['date_endmonth']); + unset($_POST['date_endyear']); + unset($_POST['date_start_fill']); + unset($_POST['date_end_fill']); + unset($_POST['situations']); + unset($_POST['progress']); + } else { + setEventMessages($object->error, $object->errors, 'errors'); + } + + $action = ''; + } + } + } elseif ($action == 'updateline' && $usercancreate && ! GETPOST('cancel', 'alpha')) { + if (! $object->fetch($id) > 0) { + dol_print_error($db); + } + $object->fetch_thirdparty(); + + // Clean parameters + $date_start = ''; + $date_end = ''; + $description = dol_htmlcleanlastbr(GETPOST('product_desc', 'restricthtml') ? GETPOST('product_desc', 'restricthtml') : GETPOST('desc', 'restricthtml')); + $ref_fourn = GETPOST('fourn_ref', 'alpha'); + $pu_ht = price2num(GETPOST('price_ht'), '', 2); + $vat_rate = (GETPOST('tva_tx') ? GETPOST('tva_tx') : 0); + $qty = GETPOST('qty'); + $pu_ht_devise = price2num(GETPOST('multicurrency_subprice'), '', 2); + + // 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->thirdparty); + $localtax2_rate = get_localtax($vat_rate, 2, $object->thirdparty); + + // Extrafields + $extralabelsline = $extrafields->fetch_name_optionals_label($object->table_element_line); + $array_options = $extrafields->getOptionalsFromPost($object->table_element_line); + + $objectline = new FactureFournisseurLigneRec($db); + if ($objectline->fetch(GETPOST('lineid', 'int'))) { + $objectline->array_options = $array_options; + $result = $objectline->insertExtraFields(); + if ($result < 0) { + setEventMessages($langs->trans('Error') . $result, null, 'errors'); + } + } + + $position = ($objectline->rang >= 0 ? $objectline->rang : 0); + + // Unset extrafield + if (is_array($extralabelsline)) { + // Get extra fields + foreach ($extralabelsline as $key => $value) { + unset($_POST["options_" . $key]); + } + } + + // Define special_code for special lines + $special_code = GETPOST('special_code', 'int'); + if (! GETPOST('qty', 'alpha')) { + $special_code = 3; + } + + $remise_percent = price2num(GETPOST('remise_percent'), '', 2); + + // Check minimum price + $productid = GETPOST('productid', 'int'); + if (! empty($productid)) { + $product = new Product($db); + $product->fetch($productid); + + $type = $product->type; + + $price_min = $product->price_min; + if (! empty($conf->global->PRODUIT_MULTIPRICES) && ! empty($object->thirdparty->price_level)) { + $price_min = $product->multiprices_min[$object->thirdparty->price_level]; + } + + $label = $product->label; + + // Check price is not lower than minimum (check is done only for standard or replacement invoices) + if (((! empty($conf->global->MAIN_USE_ADVANCED_PERMS) && empty($user->rights->produit->ignore_price_min_advance)) || empty($conf->global->MAIN_USE_ADVANCED_PERMS)) && $price_min && (price2num($pu_ht) * (1 - $remise_percent / 100) < price2num($price_min))) { + setEventMessages($langs->trans("CantBeLessThanMinPrice", price(price2num($price_min, 'MU'), 0, $langs, 0, 0, -1, $conf->currency)), null, 'errors'); + $error++; + } + } else { + $type = GETPOST('type', 'int'); + $label = (GETPOST('product_label') ? GETPOST('product_label') : ''); + + // Check parameters + if (GETPOST('type', 'int') < 0) { + setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("Type")), null, 'errors'); + $error++; + } + } + if ($qty < 0) { + $langs->load("errors"); + setEventMessages($langs->trans('ErrorQtyForCustomerInvoiceCantBeNegative'), null, 'errors'); + $error++; + } + + $date_start_fill = ! empty(GETPOST('date_start_fill', 'int')) ? GETPOST('date_start_fill', 'int') : 'NULL'; + $date_end_fill = ! empty(GETPOST('date_end_fill', 'int')) ? GETPOST('date_end_fill', 'int') : 'NULL'; + + // Update line + if (! $error) { + $result = $object->updateline(GETPOST('lineid', 'int'), GETPOST('productid', 'int'), $ref_fourn, $label, $description, $pu_ht, $qty, $remise_percent, $vat_rate, $localtax1_rate, $localtax1_rate, 'HT', $type, $date_start_fill, $date_end_fill, $info_bits, $special_code, -1); + if ($result >= 0) { + $object->fetch($object->id); // Reload lines + + unset($_POST['qty']); + unset($_POST['type']); + unset($_POST['productid']); + unset($_POST['remise_percent']); + unset($_POST['price_ht']); + unset($_POST['multicurrency_price_ht']); + unset($_POST['price_ttc']); + unset($_POST['tva_tx']); + unset($_POST['product_ref']); + unset($_POST['product_label']); + unset($_POST['product_desc']); + unset($_POST['fournprice']); + unset($_POST['buying_price']); + unset($_POST['np_marginRate']); + unset($_POST['np_markRate']); + unset($_POST['dp_desc']); + unset($_POST['idprod']); + unset($_POST['units']); + unset($_POST['date_starthour']); + unset($_POST['date_startmin']); + unset($_POST['date_startsec']); + unset($_POST['date_startday']); + unset($_POST['date_startmonth']); + unset($_POST['date_startyear']); + unset($_POST['date_endhour']); + unset($_POST['date_endmin']); + unset($_POST['date_endsec']); + unset($_POST['date_endday']); + unset($_POST['date_endmonth']); + unset($_POST['date_endyear']); + unset($_POST['situations']); + unset($_POST['progress']); + } else { + setEventMessages($object->error, $object->errors, 'errors'); + } + } + } +} + +/* + * View + */ + +$help_url = ''; +llxHeader('', $langs->trans("RepeatableSupplierInvoice"), $help_url); + +$form = new Form($db); +$formother = new FormOther($db); +if (! empty($conf->projet->enabled)) { + $formproject = new FormProjets($db); +} +$companystatic = new Societe($db); +$invoicerectmp = new FactureFournisseurRec($db); + +$now = dol_now(); +$nowlasthour = dol_get_last_hour($now); + +/* + * Create mode + */ +if ($action == 'create') { + print load_fiche_titre($langs->trans("CreateRepeatableInvoice"), '', 'bill'); + + $object = new FactureFournisseur($db); // Source invoice + $product_static = new Product($db); + + if ($object->fetch($id) > 0) { + $result = $object->fetch_lines(); + + print '
'; + print ''; + print ''; + print ''; + + print dol_get_fiche_head(null, '', '', 0); + + $rowspan = 4; + if (! empty($conf->projet->enabled)) $rowspan++; + if ($object->fk_account > 0) $rowspan++; + + print ''; + + $object->fetch_thirdparty(); + + // Title + print ''; + + // Ref supplier + print ''; + + // Third party + print ''; + print ''; + + $note_public = GETPOSTISSET('note_public') ? GETPOST('note_public', 'restricthtml') : $object->note_public; + $note_private = GETPOSTISSET('note_private') ? GETPOST('note_private', 'restricthtml') : $object->note_private; + + // Help of substitution key + $substitutionarray = getCommonSubstitutionArray($langs, 2, null, $object); + + $substitutionarray['__INVOICE_PREVIOUS_MONTH__'] = $langs->trans("PreviousMonthOfInvoice") . ' (' . $langs->trans("Example") . ': ' . dol_print_date(dol_time_plus_duree($object->date, -1, 'm'), '%m') . ')'; + $substitutionarray['__INVOICE_MONTH__'] = $langs->trans("MonthOfInvoice") . ' (' . $langs->trans("Example") . ': ' . dol_print_date($object->date, '%m') . ')'; + $substitutionarray['__INVOICE_NEXT_MONTH__'] = $langs->trans("NextMonthOfInvoice") . ' (' . $langs->trans("Example") . ': ' . dol_print_date(dol_time_plus_duree($object->date, 1, 'm'), '%m') . ')'; + $substitutionarray['__INVOICE_PREVIOUS_MONTH_TEXT__'] = $langs->trans("TextPreviousMonthOfInvoice") . ' (' . $langs->trans("Example") . ': ' . dol_print_date(dol_time_plus_duree($object->date, -1, 'm'), '%B') . ')'; + $substitutionarray['__INVOICE_MONTH_TEXT__'] = $langs->trans("TextMonthOfInvoice") . ' (' . $langs->trans("Example") . ': ' . dol_print_date($object->date, '%B') . ')'; + $substitutionarray['__INVOICE_NEXT_MONTH_TEXT__'] = $langs->trans("TextNextMonthOfInvoice") . ' (' . $langs->trans("Example") . ': ' . dol_print_date(dol_time_plus_duree($object->date, 1, 'm'), '%B') . ')'; + $substitutionarray['__INVOICE_PREVIOUS_YEAR__'] = $langs->trans("PreviousYearOfInvoice") . ' (' . $langs->trans("Example") . ': ' . dol_print_date(dol_time_plus_duree($object->date, -1, 'y'), '%Y') . ')'; + $substitutionarray['__INVOICE_YEAR__'] = $langs->trans("YearOfInvoice") . ' (' . $langs->trans("Example") . ': ' . dol_print_date($object->date, '%Y') . ')'; + $substitutionarray['__INVOICE_NEXT_YEAR__'] = $langs->trans("NextYearOfInvoice") . ' (' . $langs->trans("Example") . ': ' . dol_print_date(dol_time_plus_duree($object->date, 1, 'y'), '%Y') . ')'; + // Only on template invoices + $substitutionarray['__INVOICE_DATE_NEXT_INVOICE_BEFORE_GEN__'] = $langs->trans("DateNextInvoiceBeforeGen") . ' (' . $langs->trans("Example") . ': ' . dol_print_date($object->date_when, 'dayhour') . ')'; + $substitutionarray['__INVOICE_DATE_NEXT_INVOICE_AFTER_GEN__'] = $langs->trans("DateNextInvoiceAfterGen") . ' (' . $langs->trans("Example") . ': ' . dol_print_date(dol_time_plus_duree($object->date_when, $object->frequency, $object->unit_frequency), 'dayhour') . ')'; + $substitutionarray['__INVOICE_COUNTER_CURRENT__'] = $langs->trans("Count"); + $substitutionarray['__INVOICE_COUNTER_MAX__'] = $langs->trans("MaxPeriodNumber"); + + $htmltext = '' . $langs->trans("FollowingConstantsWillBeSubstituted") . ':
'; + foreach ($substitutionarray as $key => $val) { + $htmltext .= $key . ' = ' . $langs->trans($val) . '
'; + } + $htmltext .= '
'; + + // Libelle + print ''; + + // Public note + print ''; + print ''; + print ''; + print ''; + print ''; + } + + // Author + print ""; + + // Payment term + print ""; + + // Payment mode + print ""; + + // Project + if (! empty($conf->projet->enabled) && is_object($object->thirdparty) && $object->thirdparty->id > 0) { + $projectid = GETPOST('projectid') ? GETPOST('projectid') : $object->fk_project; + $langs->load('projects'); + print ''; + } + + // Bank account + if ($object->fk_account > 0) { + print ""; + } + + // Model pdf + print ""; + + print "
' . $langs->trans("Title") . ''; + print ''; + print '
' . $langs->trans("SupplierRef") . ''; + print ''; + print '
' . $langs->trans("Customer") . '' . $object->thirdparty->getNomUrl(1, 'customer') . '
' . $langs->trans("Label") . ''; + print ''; + print '
'; + print $form->textwithpicto($langs->trans('NotePublic'), $htmltext, 1, 'help', '', 0, 2, 'notepublic'); + print ''; + $doleditor = new DolEditor('note_public', $note_public, '', 80, 'dolibarr_notes', 'In', 0, false, empty($conf->global->FCKEDITOR_ENABLE_NOTE_PUBLIC) ? 0 : 1, ROWS_3, '90%'); + print $doleditor->Create(1); + + // Private note + if (empty($user->socid)) { + print '
'; + print $form->textwithpicto($langs->trans('NotePrivate'), $htmltext, 1, 'help', '', 0, 2, 'noteprivate'); + print ''; + $doleditor = new DolEditor('note_private', $note_private, '', 80, 'dolibarr_notes', 'In', 0, false, empty($conf->global->FCKEDITOR_ENABLE_NOTE_PRIVATE) ? 0 : 1, ROWS_3, '90%'); + print $doleditor->Create(1); + print '
" . $langs->trans("Author") . "" . $user->getFullName($langs) . "
" . $langs->trans("PaymentConditions") . ""; + $form->form_conditions_reglement($_SERVER['PHP_SELF'] . '?id=' . $object->id, $object->cond_reglement_id, 'none'); + print "
" . $langs->trans("PaymentMode") . ""; + $form->form_modes_reglement($_SERVER['PHP_SELF'] . '?id=' . $object->id, $object->mode_reglement_id, 'none', '', 1); + print "
' . $langs->trans('Project') . ''; + $numprojet = $formproject->select_projects($object->thirdparty->id, $projectid, 'projectid', 0, 0, 1, 0, 0, 0, 0, '', 0, 0, ''); + print '   thirdparty->id . (! empty($id) ? '&id=' . $id : '')) . '">' . $langs->trans("AddProject") . ''; + print '
" . $langs->trans('BankAccount') . ""; + $form->formSelectAccount($_SERVER['PHP_SELF'] . '?id=' . $object->id, $object->fk_account, 'none'); + print "
" . $langs->trans('Model') . ""; + include_once DOL_DOCUMENT_ROOT . '/core/modules/supplier_invoice/modules_facturefournisseur.php'; + $list = ModelePDFSuppliersInvoices::liste_modeles($db); + print $form->selectarray('modelpdf', $list, $conf->global->INVOICE_SUPPLIER_ADDON_PDF); + print "
"; + + print dol_get_fiche_end(); + + // Autogeneration + $title = $langs->trans("Recurrence"); + print load_fiche_titre(img_picto('', 'recurring', 'class="pictofixedwidth"') . $title, '', ''); + + print dol_get_fiche_head(null, '', '', 0); + + print ''; + + // Frequency + unit + print '"; + + // Date next run + print ""; + + // Number max of generation + print ""; + + // Auto validate the invoice + print ""; + + // Auto generate document + if (! empty($conf->global->INVOICE_REC_CAN_DISABLE_DOCUMENT_FILE_GENERATION)) { + print ""; + } else { + print ''; + } + + print "
' . $form->textwithpicto($langs->trans("Frequency"), $langs->transnoentitiesnoconv('toolTipFrequency')) . ""; + print " " . $form->selectarray('unit_frequency', array('d' => $langs->trans('Day'), 'm' => $langs->trans('Month'), 'y' => $langs->trans('Year')), (GETPOST('unit_frequency') ? GETPOST('unit_frequency') : 'm')); + print "
" . $langs->trans('NextDateToExecution') . ""; + $date_next_execution = isset($date_next_execution) ? $date_next_execution : (GETPOST('remonth') ? dol_mktime(12, 0, 0, GETPOST('remonth'), GETPOST('reday'), GETPOST('reyear')) : -1); + print $form->selectDate($date_next_execution, '', 1, 1, '', "add", 1, 1); + print "
" . $langs->trans("MaxPeriodNumber") . ""; + print ''; + print "
" . $langs->trans("StatusOfGeneratedInvoices") . ""; + $select = array('0' => $langs->trans('BillStatusDraft'), '1' => $langs->trans('BillStatusValidated')); + print $form->selectarray('auto_validate', $select, GETPOST('auto_validate')); + print "
" . $langs->trans("StatusOfGeneratedDocuments") . ""; + $select = array('0' => $langs->trans('DoNotGenerateDoc'), '1' => $langs->trans('AutoGenerateDoc')); + print $form->selectarray('generate_pdf', $select, GETPOST('generate_pdf')); + print "
"; + + print dol_get_fiche_end(); + + $title = $langs->trans("ProductsAndServices"); + if (empty($conf->service->enabled)) { + $title = $langs->trans("Products"); + } elseif (empty($conf->product->enabled)) { + $title = $langs->trans("Services"); + } + + print load_fiche_titre($title, '', ''); + + /* + * Invoice lines + */ + print '
'; + print ''; + // Show object lines + if (! empty($object->lines)) { + $disableedit = 1; + $disablemove = 1; + $disableremove = 1; + $object->printObjectLines('', $mysoc, $object->thirdparty, $lineid, 0); // No date selector for template invoice + } + + print "
\n"; + print '
'; + print ''; + print "\n"; + + print $form->buttonsSaveCancel("Create"); + + print "\n"; + } else { + dol_print_error('', "Error, no invoice " . $object->id); + } +} else { + /* + * View mode + */ + if ($object->id > 0) { + $object->fetch($object->id); + $object->fetch_thirdparty(); + + // Confirmation de la suppression d'une ligne produit + if ($action == 'ask_deleteline') { + $formconfirm = $form->formconfirm($_SERVER["PHP_SELF"] . '?id=' . $object->id . '&lineid=' . $lineid, $langs->trans('DeleteProductLine'), $langs->trans('ConfirmDeleteProductLine'), 'confirm_deleteline', '', 'no', 1); + } + + // Confirm delete of repeatable invoice + if ($action == 'ask_deleteinvoice') { + $formconfirm = $form->formconfirm($_SERVER["PHP_SELF"] . '?id=' . $object->id, $langs->trans('DeleteRepeatableInvoice'), $langs->trans('ConfirmDeleteRepeatableInvoice'), 'confirm_deleteinvoice', '', 'no', 1); + } + + print $formconfirm; + + $author = new User($db); + $author->fetch($object->user_author); + + $head = supplier_invoice_rec_prepare_head($object); + + print dol_get_fiche_head($head, 'card', $langs->trans('RepeatableInvoice'), -1, 'bill'); // Add a div + + // Recurring invoice content + + $linkback = '' . $langs->trans('BackToList') . ''; + + $morehtmlref = ''; + if ($action != 'edittitle') { + $morehtmlref .= $form->editfieldkey($object->titre, 'title', $object->titre, $object, $usercancreate, '', '', 0, 2); + } else { + $morehtmlref .= $form->editfieldval('', 'title', $object->titre, $object, $usercancreate, 'string'); + } + $morehtmlref .= '
'; + //Ref supplier + $morehtmlref .= $form->editfieldkey("RefSupplier", 'ref_supplier', $object->ref_supplier, $object, $usercancreate, 'string', '', 0, 1); + $morehtmlref .= $form->editfieldval("RefSupplier", 'ref_supplier', $object->ref_supplier, $object, $usercancreate, 'string', '', null, null, '', 1); + // Thirdparty + $morehtmlref .= '
' . $langs->trans('ThirdParty') . ' : ' . $object->thirdparty->getNomUrl(1); + + // Project + if (! empty($conf->projet->enabled)) { + $langs->load('projects'); + $morehtmlref .= '
' . $langs->trans('Project') . ' '; + if ($usercancreate) { + if ($action != 'classify') { + $morehtmlref .= '' . img_edit($langs->transnoentitiesnoconv('SetProject')) . ' : '; + } + if ($action == 'classify') { + $morehtmlref .= '
'; + $morehtmlref .= ''; + $morehtmlref .= ''; + $morehtmlref .= $formproject->select_projects($object->socid, $object->fk_project, 'projectid', $maxlength, 0, 1, 0, 1, 0, 0, '', 1); + $morehtmlref .= ''; + $morehtmlref .= '
'; + } else { + $morehtmlref .= $form->form_project($_SERVER['PHP_SELF'] . '?id=' . $object->id, $object->socid, $object->fk_project, 'none', 0, 0, 0, 1); + } + } else { + if (! empty($object->fk_project)) { + $project = new Project($db); + $project->fetch($object->fk_project); + $morehtmlref .= ' : ' . $project->getNomUrl(1); + if ($project->title) { + $morehtmlref .= ' - ' . $project->title; + } + } else { + $morehtmlref .= ''; + } + } + } + $morehtmlref .= '
'; + + $morehtmlright = ''; + + dol_banner_tab($object, 'ref', $linkback, 1, 'title', 'none', $morehtmlref, '', 0, '', $morehtmlright); + + print '
'; + print '
'; + print '
'; + + print ''; + + print '"; + + // Label + print ''; + print ''; + print ''; + print ''; + + print ''; + print ''; + print ''; + + print ''; + print ''; + + // Amount Local Taxes + if (($mysoc->localtax1_assuj == "1" && $mysoc->useLocalTax(1)) || $object->total_localtax1 != 0) { // Localtax1 + print ''; + print ''; + } + if (($mysoc->localtax2_assuj == "1" && $mysoc->useLocalTax(2)) || $object->total_localtax2 != 0) { // Localtax2 + print ''; + print ''; + } + + print ''; + print ''; + + // Payment term + print ''; + + // Payment mode + print ''; + + // Multicurrency + if (! empty($conf->multicurrency->enabled)) { + // Multicurrency code + print ''; + print ''; + + // Multicurrency rate + if ($object->multicurrency_code != $conf->currency || $object->multicurrency_tx != 1) { + print ''; + print ''; + } + } + + // Help of substitution key + $dateexample = dol_now(); + if (! empty($object->frequency) && ! empty($object->date_when)) { + $dateexample = $object->date_when; + } + + $substitutionarray = getCommonSubstitutionArray($langs, 2, null, $object); + + $substitutionarray['__INVOICE_PREVIOUS_MONTH__'] = $langs->trans("PreviousMonthOfInvoice") . ' (' . $langs->trans("Example") . ': ' . dol_print_date(dol_time_plus_duree($dateexample, -1, 'm'), '%m') . ')'; + $substitutionarray['__INVOICE_MONTH__'] = $langs->trans("MonthOfInvoice") . ' (' . $langs->trans("Example") . ': ' . dol_print_date($dateexample, '%m') . ')'; + $substitutionarray['__INVOICE_NEXT_MONTH__'] = $langs->trans("NextMonthOfInvoice") . ' (' . $langs->trans("Example") . ': ' . dol_print_date(dol_time_plus_duree($dateexample, 1, 'm'), '%m') . ')'; + $substitutionarray['__INVOICE_PREVIOUS_MONTH_TEXT__'] = $langs->trans("TextPreviousMonthOfInvoice") . ' (' . $langs->trans("Example") . ': ' . dol_print_date(dol_time_plus_duree($dateexample, -1, 'm'), '%B') . ')'; + $substitutionarray['__INVOICE_MONTH_TEXT__'] = $langs->trans("TextMonthOfInvoice") . ' (' . $langs->trans("Example") . ': ' . dol_print_date($dateexample, '%B') . ')'; + $substitutionarray['__INVOICE_NEXT_MONTH_TEXT__'] = $langs->trans("TextNextMonthOfInvoice") . ' (' . $langs->trans("Example") . ': ' . dol_print_date(dol_time_plus_duree($dateexample, 1, 'm'), '%B') . ')'; + $substitutionarray['__INVOICE_PREVIOUS_YEAR__'] = $langs->trans("PreviousYearOfInvoice") . ' (' . $langs->trans("Example") . ': ' . dol_print_date(dol_time_plus_duree($dateexample, -1, 'y'), '%Y') . ')'; + $substitutionarray['__INVOICE_YEAR__'] = $langs->trans("YearOfInvoice") . ' (' . $langs->trans("Example") . ': ' . dol_print_date($dateexample, '%Y') . ')'; + $substitutionarray['__INVOICE_NEXT_YEAR__'] = $langs->trans("NextYearOfInvoice") . ' (' . $langs->trans("Example") . ': ' . dol_print_date(dol_time_plus_duree($dateexample, 1, 'y'), '%Y') . ')'; + // Only on template invoices + $substitutionarray['__INVOICE_DATE_NEXT_INVOICE_BEFORE_GEN__'] = $langs->trans("DateNextInvoiceBeforeGen") . ' (' . $langs->trans("Example") . ': ' . dol_print_date(($object->date_when ? $object->date_when : dol_now()), 'dayhour') . ')'; + $substitutionarray['__INVOICE_DATE_NEXT_INVOICE_AFTER_GEN__'] = $langs->trans("DateNextInvoiceAfterGen") . ' (' . $langs->trans("Example") . ': ' . dol_print_date(dol_time_plus_duree(($object->date_when ? $object->date_when : dol_now()), $object->frequency, $object->unit_frequency), 'dayhour') . ')'; + $substitutionarray['__INVOICE_COUNTER_CURRENT__'] = $object->nb_gen_done; + $substitutionarray['__INVOICE_COUNTER_MAX__'] = $object->nb_gen_max; + + $htmltext = '' . $langs->trans("FollowingConstantsWillBeSubstituted") . ':
'; + foreach ($substitutionarray as $key => $val) { + $htmltext .= $key . ' = ' . $langs->trans($val) . '
'; + } + $htmltext .= '
'; + + // Note public + print ''; + print ''; + + // Note private + print ''; + print ''; + + // Bank Account + print '"; + print ''; + + // Model pdf + print '"; + print ''; + + // Other attributes + $cols = 2; + include DOL_DOCUMENT_ROOT . '/core/tpl/extrafields_view.tpl.php'; + + print '
' . $langs->trans('Author') . ''; + print $author->getNomUrl(-1); + print "
' . $form->editfieldkey("Label", 'libelle', $object->libelle, $object, $usercancreate) . '' . $form->editfieldval("Label", 'libelle', $object->libelle, $object, $usercancreate) . '
' . $langs->trans('AmountHT') . '' . price($object->total_ht, '', $langs, 1, -1, -1, $conf->currency) . '
' . $langs->trans("AmountVAT") . '' . price($object->total_tva, '', $langs, 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("AmountTTC") . '' . price($object->total_ttc, '', $langs, 1, -1, -1, $conf->currency) . '
'; + print ''; + if ($action != 'editconditions' && $usercancreate) { + print ''; + } + print '
'; + print $langs->trans('PaymentConditionsShort'); + print '' . img_edit($langs->trans('SetConditions'), 1) . '
'; + print '
'; + 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'); + } + + print '
'; + print ''; + if ($action != 'editmode' && $usercancreate) { + print ''; + } + print '
'; + print $langs->trans('PaymentMode'); + print '' . 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', 'CRDT', 1, 1); + } else { + $form->form_modes_reglement($_SERVER['PHP_SELF'] . '?facid=' . $object->id, $object->mode_reglement_id, 'none'); + } + print '
'; + print ''; + if ($usercancreate && $action != 'editmulticurrencycode' && ! empty($object->brouillon)) { + print ''; + } + print '
'; + print $form->editfieldkey('Currency', 'multicurrency_code', '', $object, 0); + print '' . img_edit($langs->transnoentitiesnoconv('SetMultiCurrencyCode'), 1) . '
'; + print '
'; + $htmlname = (($usercancreate && $action == 'editmulticurrencycode') ? 'multicurrency_code' : 'none'); + $form->form_multicurrency_code($_SERVER['PHP_SELF'] . '?id=' . $object->id, $object->multicurrency_code, $htmlname); + print '
'; + print ''; + if ($usercancreate && $action != 'editmulticurrencyrate' && ! empty($object->brouillon) && $object->multicurrency_code && $object->multicurrency_code != $conf->currency) { + print ''; + } + print '
'; + print $form->editfieldkey('CurrencyRate', 'multicurrency_tx', '', $object, 0); + print '' . img_edit($langs->transnoentitiesnoconv('SetMultiCurrencyCode'), 1) . '
'; + print '
'; + if ($action == 'editmulticurrencyrate' || $action == 'actualizemulticurrencyrate') { + if ($action == 'actualizemulticurrencyrate') { + list($object->fk_multicurrency, $object->multicurrency_tx) = MultiCurrency::getIdAndTxFromCode($object->db, $object->multicurrency_code); + } + $form->form_multicurrency_rate($_SERVER['PHP_SELF'] . '?id=' . $object->id, $object->multicurrency_tx, ($usercancreate ? 'multicurrency_tx' : 'none'), $object->multicurrency_code); + } else { + $form->form_multicurrency_rate($_SERVER['PHP_SELF'] . '?id=' . $object->id, $object->multicurrency_tx, 'none', $object->multicurrency_code); + if ($object->statut == $object::STATUS_DRAFT && $object->multicurrency_code && $object->multicurrency_code != $conf->currency) { + print '
        '; + print '' . $langs->trans("ActualizeCurrency") . ''; + print '
'; + } + } + print '
'; + print $form->editfieldkey($form->textwithpicto($langs->trans('NotePublic'), $htmltext, 1, 'help', '', 0, 2, 'notepublic'), 'note_public', $object->note_public, $object, $usercancreate); + print ''; + print $form->editfieldval($langs->trans("NotePublic"), 'note_public', $object->note_public, $object, $usercancreate, 'textarea:' . ROWS_4 . ':90%', '', null, null, '', 1); + print '
'; + print $form->editfieldkey($form->textwithpicto($langs->trans("NotePrivate"), $htmltext, 1, 'help', '', 0, 2, 'noteprivate'), 'note_private', $object->note_private, $object, $usercancreate); + print ''; + print $form->editfieldval($langs->trans("NotePrivate"), 'note_private', $object->note_private, $object, $usercancreate, 'textarea:' . ROWS_4 . ':90%', '', null, null, '', 1); + print '
'; + print ''; + } + print '
'; + print $langs->trans('BankAccount'); + print ''; + if ($action != 'editbankaccount' && $usercancreate && $object->statut == FactureFournisseurRec::STATUS_NOTSUSPENDED) { + print '' . img_edit($langs->trans('SetBankAccount'), 1) . '
'; + print '
'; + if ($action == 'editbankaccount') { + $form->formSelectAccount($_SERVER['PHP_SELF'] . '?id=' . $object->id, $object->fk_account, 'fk_account', 1); + } else { + $form->formSelectAccount($_SERVER['PHP_SELF'] . '?id=' . $object->id, $object->fk_account, 'none'); + } + print "
'; + print ''; + } + print '
'; + print $langs->trans('Model'); + print ''; + if ($action != 'editmodelpdf' && $usercancreate && $object->statut == FactureFournisseurRec::STATUS_NOTSUSPENDED) { + print '' . img_edit($langs->trans('SetModel'), 1) . '
'; + print '
'; + if ($action == 'editmodelpdf') { + include_once DOL_DOCUMENT_ROOT . '/core/modules/supplier_invoice/modules_facturefournisseur.php'; + $list = array(); + $models = ModelePDFSuppliersInvoices::liste_modeles($db); + foreach ($models as $k => $model) { + $list[] = str_replace(':', '|', $k) . ':' . $model; + } + $select = 'select;' . implode(',', $list); + //TODO : Droits + print $form->editfieldval($langs->trans('Model'), 'modelpdf', $object->model_pdf, $object, $usercancreate, $select); + } else { + print $object->model_pdf; + } + print "
'; + + print '
'; + print '
'; + print '
'; + + /* + * Recurrence + */ + $title = $langs->trans("Recurrence"); + //print load_fiche_titre($title, '', 'calendar'); + + print ''; + + print ''; + + // if "frequency" is empty or = 0, the reccurence is disabled + print ''; + + // Date when (next invoice generation) + print ''; + print ''; + + // Max period / Rest period + print ''; + print ''; + + // Status of generated invoices + print ''; + // Auto generate documents + if (! empty($conf->global->INVOICE_REC_CAN_DISABLE_DOCUMENT_FILE_GENERATION)) { + print ''; + print ''; + print ''; + print ''; + } else { + print ''; + } + + print '
' . img_picto('', 'recurring', 'class="pictofixedwidth"') . $title . '
'; + print ''; + if ($action != 'editfrequency' && $usercancreate) { + print ''; + } + print '
'; + print $langs->trans('Frequency'); + print '' . img_edit($langs->trans('Edit'), 1) . '
'; + print '
'; + if ($action == 'editfrequency') { + print '
'; + print ''; + print ''; + print ''; + print ''; + print ''; + print '
'; + print " " . $form->selectarray('unit_frequency', array('d' => $langs->trans('Day'), 'm' => $langs->trans('Month'), 'y' => $langs->trans('Year')), ($object->unit_frequency ? $object->unit_frequency : 'm')); + print '
'; + } else { + if ($object->frequency > 0) { + print $langs->trans('FrequencyPer_' . $object->unit_frequency, $object->frequency); + } else { + print $langs->trans("NotARecurringInvoiceTemplate"); + } + } + print '
'; + if ($action == 'date_when' || $object->frequency > 0) { + print $form->editfieldkey($langs->trans("NextDateToExecution"), 'date_when', $object->date_when, $object, $usercancreate, 'day'); + } else { + print $langs->trans("NextDateToExecution"); + } + print ''; + if ($action == 'date_when' || $object->frequency > 0) { + print $form->editfieldval($langs->trans("NextDateToExecution"), 'date_when', $object->date_when, $object, $usercancreate, 'day', $object->date_when, null, '', '', 0, 'strikeIfMaxNbGenReached'); + } + //var_dump(dol_print_date($object->date_when+60, 'dayhour').' - '.dol_print_date($now, 'dayhour')); + if (! $object->isMaxNbGenReached()) { + if (! $object->suspended && $action != 'editdate_when' && $object->frequency > 0 && $object->date_when && $object->date_when < $now) { + print img_warning($langs->trans("Late")); + } + } else { + print img_info($langs->trans("MaxNumberOfGenerationReached")); + } + print '
'; + if ($action == 'nb_gen_max' || $object->frequency > 0) { + print $form->editfieldkey($langs->trans("MaxPeriodNumber"), 'nb_gen_max', $object->nb_gen_max, $object, $usercancreate); + } else { + print $langs->trans("MaxPeriodNumber"); + } + print ''; + if ($action == 'nb_gen_max' || $object->frequency > 0) { + print $form->editfieldval($langs->trans("MaxPeriodNumber"), 'nb_gen_max', $object->nb_gen_max ? $object->nb_gen_max : '', $object, $usercancreate); + } else { + print ''; + } + print '
'; + if ($action == 'auto_validate' || $object->frequency > 0) { + print $form->editfieldkey($langs->trans("StatusOfGeneratedInvoices"), 'auto_validate', $object->auto_validate, $object, $usercancreate); + } else { + print $langs->trans("StatusOfGeneratedInvoices"); + } + print ''; + $select = 'select;0:' . $langs->trans('BillStatusDraft') . ',1:' . $langs->trans('BillStatusValidated'); + if ($action == 'auto_validate' || $object->frequency > 0) { + print $form->editfieldval($langs->trans("StatusOfGeneratedInvoices"), 'auto_validate', $object->auto_validate, $object, $usercancreate, $select); + } + print '
'; + if ($action == 'generate_pdf' || $object->frequency > 0) { + print $form->editfieldkey($langs->trans("StatusOfGeneratedDocuments"), 'generate_pdf', $object->generate_pdf, $object, $usercancreate); + } else { + print $langs->trans("StatusOfGeneratedDocuments"); + } + print ''; + $select = 'select;0:' . $langs->trans('DoNotGenerateDoc') . ',1:' . $langs->trans('AutogenerateDoc'); + if ($action == 'generate_pdf' || $object->frequency > 0) { + print $form->editfieldval($langs->trans("StatusOfGeneratedDocuments"), 'generate_pdf', $object->generate_pdf, $object, $usercancreate, $select); + } + print '
'; + + // Frequencry/Recurring section + if ($object->frequency > 0) { + print '
'; + + if (empty($conf->cron->enabled)) { + print info_admin($langs->trans("EnableAndSetupModuleCron", $langs->transnoentitiesnoconv("Module2300Name"))); + } + + print '
'; + print ''; + + // Nb of generation already done + print ''; + print ''; + print ''; + + // Date last + print ''; + print ''; + + print '
' . $langs->trans("NbOfGenerationDone") . ''; + print $object->nb_gen_done ? $object->nb_gen_done : '0'; + print '
'; + print $langs->trans("DateLastGeneration"); + print ''; + print dol_print_date($object->date_last_gen, 'dayhour'); + print '
'; + + print '
'; + } + + print '
'; + print '
'; + + print '

'; + + // Lines + print '
+ + + + + '; + + if (! empty($conf->use_javascript_ajax) && $object->statut == 0) { + include DOL_DOCUMENT_ROOT . '/core/tpl/ajaxrow.tpl.php'; + } + + print '
'; + print ''; + $object->fetch_lines(); + // Show object lines + if (! empty($object->lines)) { + $canchangeproduct = 1; + // To set ref for getNomURL function + foreach ($object->lines as $line) { + $line->ref = $line->label; + $line->product_label = $line->label; + $line->subprice = $line->pu_ht; + } + + global $canchangeproduct; + $canchangeproduct = 0; + + $object->statut = $object->suspended; + $object->printObjectLines($action, $mysoc, $object->thirdparty, $lineid, 0); // No date selector for template invoice + } + + // Form to add new line + //TODO : Droits + if ($object->statut == $object::STATUS_DRAFT && $usercancreate && $action != 'valid' && $action != 'editline') { + if ($action != 'editline') { + // Add free products/services + + $parameters = array(); + $reshook = $hookmanager->executeHooks('formAddObjectLine', $parameters, $object, $action); // Note that $action and $object may have been modified by hook + if ($reshook < 0) setEventMessages($hookmanager->error, $hookmanager->errors, 'errors'); + if (empty($reshook)) + global $senderissupplier; + $senderissupplier = 2; + $object->formAddObjectLine(0, $object->thirdparty, $mysoc); // No date selector for template invoice + } + } + + print "
\n"; + print '
'; + + print "
\n"; + + print dol_get_fiche_end(); + + /* + * Action bar + */ + print '
'; + + if (empty($object->suspended)) { + if ($usercancreate) { + if (! empty($object->frequency) && $object->nb_gen_max > 0 && ($object->nb_gen_done >= $object->nb_gen_max)) { + print ''; + } else { + if (empty($object->frequency) || $object->date_when <= $nowlasthour) { + print ''; + } else { + print ''; + } + } + } else { + print ''; + } + } + + if ($usercancreate) { + if (empty($object->suspended)) { + print ''; + } else { + print ''; + } + } + + //if ($object->statut == Facture::STATUS_DRAFT && ($user->rights->fournisseur->facture->supprimer || $user->rights->supplier_invoice->supprimer)) + if (($user->rights->fournisseur->facture->supprimer || $user->rights->supplier_invoice->supprimer)) { + print ''; + } + + print '
'; + + print '
'; + print ''; // ancre + + // Show links to link elements + $linktoelem = $form->showLinkToObjectBlock($object, null, array('invoice')); + + $somethingshown = $form->showLinkedObjectBlock($object, $linktoelem); + + print '
'; + } +} + +// End of page +llxFooter(); +$db->close(); diff --git a/htdocs/fourn/facture/card.php b/htdocs/fourn/facture/card.php index 76159d177c5..b98ef2f8cc6 100644 --- a/htdocs/fourn/facture/card.php +++ b/htdocs/fourn/facture/card.php @@ -37,6 +37,7 @@ require_once DOL_DOCUMENT_ROOT.'/core/class/html.formfile.class.php'; require_once DOL_DOCUMENT_ROOT.'/fourn/class/fournisseur.class.php'; require_once DOL_DOCUMENT_ROOT.'/core/modules/supplier_invoice/modules_facturefournisseur.php'; require_once DOL_DOCUMENT_ROOT.'/fourn/class/fournisseur.facture.class.php'; +require_once DOL_DOCUMENT_ROOT.'/fourn/class/fournisseur.facture-rec.class.php'; require_once DOL_DOCUMENT_ROOT.'/fourn/class/paiementfourn.class.php'; require_once DOL_DOCUMENT_ROOT.'/core/class/discount.class.php'; require_once DOL_DOCUMENT_ROOT.'/core/lib/fourn.lib.php'; @@ -883,8 +884,52 @@ if (empty($reshook)) { } } + // Standard invoice or Deposit invoice, created from a Predefined template invoice + if ((GETPOST('type') == FactureFournisseur::TYPE_STANDARD || GETPOST('type') == FactureFournisseur::TYPE_DEPOSIT) && GETPOST('fac_rec', 'int') > 0) { + if (empty($dateinvoice)) { + $error++; + setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("Date")), null, 'errors'); + $action = 'create'; + } elseif ($dateinvoice > (dol_get_last_hour(dol_now('tzuserrel')) + (empty($conf->global->INVOICE_MAX_FUTURE_DELAY) ? 0 : $conf->global->INVOICE_MAX_FUTURE_DELAY))) { + $error++; + setEventMessages($langs->trans("ErrorDateIsInFuture"), null, 'errors'); + $action = 'create'; + } + + if (!$error) { + $object->socid = GETPOST('socid', 'int'); + $object->type = GETPOST('type'); + $object->ref = GETPOST('ref'); + $object->date = $dateinvoice; + $object->note_public = trim(GETPOST('note_public', 'restricthtml')); + $object->note_private = trim(GETPOST('note_private', 'restricthtml')); + $object->ref_client = GETPOST('ref_client'); + $object->model_pdf = GETPOST('model'); + $object->fk_project = GETPOST('projectid', 'int'); + $object->cond_reglement_id = (GETPOST('type') == 3 ? 1 : GETPOST('cond_reglement_id')); + $object->mode_reglement_id = GETPOST('mode_reglement_id', 'int'); + $object->fk_account = GETPOST('fk_account', 'int'); + $object->amount = price2num(GETPOST('amount')); + $object->remise_absolue = price2num(GETPOST('remise_absolue'), 'MU'); + $object->remise_percent = price2num(GETPOST('remise_percent'), '', 2); + $object->fk_incoterms = GETPOST('incoterm_id', 'int'); + $object->location_incoterms = GETPOST('location_incoterms', 'alpha'); + $object->multicurrency_code = GETPOST('multicurrency_code', 'alpha'); + $object->multicurrency_tx = GETPOST('originmulticurrency_tx', 'int'); + + // Source facture + $object->fac_rec = GETPOST('fac_rec', 'int'); + $fac_rec = new FactureFournisseurRec($db); + $fac_rec->fetch($object->fac_rec); + $fac_rec->fetch_lines(); + $object->lines = $fac_rec->lines; + + $id = $object->create($user); // This include recopy of links from recurring invoice and recurring invoice lines + } + } + // Standard invoice or Deposit invoice, not from a Predefined template invoice - if (GETPOST('type') == FactureFournisseur::TYPE_STANDARD || GETPOST('type') == FactureFournisseur::TYPE_DEPOSIT) { + if (GETPOST('type') == FactureFournisseur::TYPE_STANDARD || GETPOST('type') == FactureFournisseur::TYPE_DEPOSIT && GETPOST('fac_rec') <= 0) { if (GETPOST('socid', 'int') < 1) { setEventMessages($langs->trans('ErrorFieldRequired', $langs->transnoentities('Supplier')), null, 'errors'); $action = 'create'; @@ -1957,11 +2002,17 @@ if ($action == 'create') { // Ref print ''.$langs->trans('Ref').''.$langs->trans('Draft').''; + $exampletemplateinvoice = new FactureFournisseurRec($db); + $invoice_predefined = new FactureFournisseurRec($db); + if (empty($origin) && empty($originid) && GETPOST('fac_rec', 'int') > 0) { + $invoice_predefined->fetch(GETPOST('fac_rec', 'int')); + } + // Third party print ''.$langs->trans('Supplier').''; print ''; - if ($societe->id > 0) { + if ($societe->id > 0 && (!GETPOST('fac_rec', 'int') || !empty($invoice_predefined->frequency))) { $absolute_discount = $societe->getAvailableDiscounts('', '', 0, 1); print $societe->getNomUrl(1, 'supplier'); print ''; @@ -1973,16 +2024,86 @@ if ($action == 'create') { $(document).ready(function() { $("#socid").change(function() { var socid = $(this).val(); - // reload page - window.location.href = "'.$_SERVER["PHP_SELF"].'?action=create&socid="+socid; + var fac_rec = $(\'#fac_rec\').val(); + window.location.href = "'.$_SERVER["PHP_SELF"].'?action=create&socid="+socid+"&fac_rec="+fac_rec; }); }); '; } - print ' '; + if (!GETPOST('fac_rec', 'int')) { + print ' '; + } } print ''; + // Overwrite some values if creation of invoice is from a predefined invoice + if (empty($origin) && empty($originid) && GETPOST('fac_rec', 'int') > 0) { + $invoice_predefined->fetch(GETPOST('fac_rec', 'int')); + + $dateinvoice = $invoice_predefined->date_when; // To use next gen date by default later + if (empty($projectid)) { + $projectid = $invoice_predefined->fk_project; + } + $cond_reglement_id = $invoice_predefined->cond_reglement_id; + $mode_reglement_id = $invoice_predefined->mode_reglement_id; + $fk_account = $invoice_predefined->fk_account; + $note_public = $invoice_predefined->note_public; + $note_private = $invoice_predefined->note_private; + + if (!empty($invoice_predefined->multicurrency_code)) { + $currency_code = $invoice_predefined->multicurrency_code; + } + if (!empty($invoice_predefined->multicurrency_tx)) { + $currency_tx = $invoice_predefined->multicurrency_tx; + } + + $sql = 'SELECT r.rowid, r.titre as title, r.total_ttc'; + $sql .= ' FROM '.MAIN_DB_PREFIX.'facture_fourn_rec as r'; + $sql .= ' WHERE r.fk_soc = '. (int) $invoice_predefined->socid; + + $resql = $db->query($sql); + if ($resql) { + $num = $db->num_rows($resql); + $i = 0; + + if ($num > 0) { + print ''.$langs->trans('CreateFromRepeatableInvoice').''; + //print ''; + print ''; + // Option to reload page to retrieve customer informations. Note, this clear other input + if (empty($conf->global->RELOAD_PAGE_ON_TEMPLATE_CHANGE_DISABLED)) { + print ''; + } + print ''; + } + $db->free($resql); + } else { + dol_print_error($db); + } + } + // Ref supplier print ''.$langs->trans('RefSupplier').'id > 0) { @@ -2288,6 +2409,34 @@ if ($action == 'create') { print ''; } + // Help of substitution key + $htmltext = ''; + if (GETPOST('fac_rec', 'int') > 0) { + $dateexample = $newdateinvoice ? $newdateinvoice : $dateinvoice; + if (empty($dateexample)) { + $dateexample = dol_now(); + } + $substitutionarray = array( + '__TOTAL_HT__' => $langs->trans("AmountHT").' ('.$langs->trans("Example").': '.price($exampletemplateinvoice->total_ht).')', + '__TOTAL_TTC__' => $langs->trans("AmountTTC").' ('.$langs->trans("Example").': '.price($exampletemplateinvoice->total_ttc).')', + '__INVOICE_PREVIOUS_MONTH__' => $langs->trans("PreviousMonthOfInvoice").' ('.$langs->trans("Example").': '.dol_print_date(dol_time_plus_duree($dateexample, -1, 'm'), '%m').')', + '__INVOICE_MONTH__' => $langs->trans("MonthOfInvoice").' ('.$langs->trans("Example").': '.dol_print_date($dateexample, '%m').')', + '__INVOICE_NEXT_MONTH__' => $langs->trans("NextMonthOfInvoice").' ('.$langs->trans("Example").': '.dol_print_date(dol_time_plus_duree($dateexample, 1, 'm'), '%m').')', + '__INVOICE_PREVIOUS_MONTH_TEXT__' => $langs->trans("TextPreviousMonthOfInvoice").' ('.$langs->trans("Example").': '.dol_print_date(dol_time_plus_duree($dateexample, -1, 'm'), '%B').')', + '__INVOICE_MONTH_TEXT__' => $langs->trans("TextMonthOfInvoice").' ('.$langs->trans("Example").': '.dol_print_date($dateexample, '%B').')', + '__INVOICE_NEXT_MONTH_TEXT__' => $langs->trans("TextNextMonthOfInvoice").' ('.$langs->trans("Example").': '.dol_print_date(dol_time_plus_duree($dateexample, 1, 'm'), '%B').')', + '__INVOICE_PREVIOUS_YEAR__' => $langs->trans("PreviousYearOfInvoice").' ('.$langs->trans("Example").': '.dol_print_date(dol_time_plus_duree($dateexample, -1, 'y'), '%Y').')', + '__INVOICE_YEAR__' => $langs->trans("YearOfInvoice").' ('.$langs->trans("Example").': '.dol_print_date($dateexample, '%Y').')', + '__INVOICE_NEXT_YEAR__' => $langs->trans("NextYearOfInvoice").' ('.$langs->trans("Example").': '.dol_print_date(dol_time_plus_duree($dateexample, 1, 'y'), '%Y').')' + ); + + $htmltext = ''.$langs->trans("FollowingConstantsWillBeSubstituted").':
'; + foreach ($substitutionarray as $key => $val) { + $htmltext .= $key.' = '.$langs->trans($val).'
'; + } + $htmltext .= '
'; + } + // Intracomm report if (!empty($conf->intracommreport->enabled)) { $langs->loadLangs(array("intracommreport")); @@ -2776,6 +2925,19 @@ if ($action == 'create') { print '
'; } } + + if ($object->fk_fac_rec_source > 0) { + $tmptemplate = new FactureFournisseurRec($db); + $result = $tmptemplate->fetch($object->fk_fac_rec_source); + if ($result > 0) { + print ' '; + $link = ''.dol_escape_htmltag($tmptemplate->titre).''; + $s = $langs->transnoentities("GeneratedFromSupplierTemplate", $link); + + print $s; + print ''; + } + } print ''; @@ -3559,6 +3721,13 @@ if ($action == 'create') { print 'socid.'">'.$langs->trans('ToClone').''; } + // Clone as predefined / Create template + if (($object->type == FactureFournisseur::TYPE_STANDARD || $object->type == FactureFournisseur::TYPE_DEPOSIT) && $object->statut == 0 && $usercancreate) { + if (!$objectidnext && count($object->lines) > 0) { + print ''.$langs->trans("ChangeIntoRepeatableInvoice").''; + } + } + // Delete $isErasable = $object->is_erasable(); if ($action != 'confirm_edit' && ($user->rights->fournisseur->facture->supprimer || ($usercancreate && $isErasable == 1))) { // isErasable = 1 means draft with temporary ref (draft can always be deleted with no need of permissions) diff --git a/htdocs/fourn/facture/list-rec.php b/htdocs/fourn/facture/list-rec.php new file mode 100644 index 00000000000..7da3a224d4f --- /dev/null +++ b/htdocs/fourn/facture/list-rec.php @@ -0,0 +1,922 @@ + + * Copyright (C) 2004-2016 Laurent Destailleur + * Copyright (C) 2005-2012 Regis Houssin + * Copyright (C) 2013 Florian Henry + * Copyright (C) 2013 Juanjo Menent + * Copyright (C) 2015 Jean-François Ferry + * Copyright (C) 2012 Cedric Salvador + * Copyright (C) 2015-2021 Alexandre Spangaro + * Copyright (C) 2016 Meziane Sof + * + * 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/invoicetemplate_list.php + * \ingroup facture + * \brief Page to show list of template/recurring invoices + */ + +require '../../main.inc.php'; +require_once DOL_DOCUMENT_ROOT.'/fourn/class/fournisseur.facture-rec.class.php'; +require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php'; +require_once DOL_DOCUMENT_ROOT.'/core/class/html.formother.class.php'; +require_once DOL_DOCUMENT_ROOT.'/projet/class/project.class.php'; +require_once DOL_DOCUMENT_ROOT.'/core/class/html.formprojet.class.php'; +require_once DOL_DOCUMENT_ROOT.'/core/class/doleditor.class.php'; +require_once DOL_DOCUMENT_ROOT.'/core/lib/invoice.lib.php'; +require_once DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php'; +require_once DOL_DOCUMENT_ROOT.'/core/class/extrafields.class.php'; + +// Load translation files required by the page +$langs->loadLangs(array('bills', 'compta', 'admin', 'other', 'suppliers')); + +$action = GETPOST('action', 'alpha'); +$massaction = GETPOST('massaction', 'alpha'); +$show_files = GETPOST('show_files', 'int'); +$confirm = GETPOST('confirm', 'alpha'); +$cancel = GETPOST('cancel', 'alpha'); +$toselect = GETPOST('toselect', 'array'); +$contextpage = GETPOST('contextpage', 'aZ') ?GETPOST('contextpage', 'aZ') : 'invoicetemplatelist'; // To manage different context of search +$optioncss = GETPOST('optioncss', 'alpha'); + +$socid = GETPOST('socid', 'int'); + +// Security check +$id = (GETPOST('facid', 'int') ?GETPOST('facid', 'int') : GETPOST('id', 'int')); +$lineid = GETPOST('lineid', 'int'); +$ref = GETPOST('ref', 'alpha'); +if ($user->socid) { + $socid = $user->socid; +} +$objecttype = 'facture_fourn_rec'; +if ($action == "create" || $action == "add") { + $objecttype = ''; +} +$result = restrictedArea($user, 'facture', $id, $objecttype); + +$search_ref = GETPOST('search_ref'); +$search_societe = GETPOST('search_societe'); +$search_montant_ht = GETPOST('search_montant_ht'); +$search_montant_vat = GETPOST('search_montant_vat'); +$search_montant_ttc = GETPOST('search_montant_ttc'); +$search_payment_mode = GETPOST('search_payment_mode'); +$search_payment_term = GETPOST('search_payment_term'); +$search_date_startday = GETPOST('search_date_startday', 'int'); +$search_date_startmonth = GETPOST('search_date_startmonth', 'int'); +$search_date_startyear = GETPOST('search_date_startyear', 'int'); +$search_date_endday = GETPOST('search_date_endday', 'int'); +$search_date_endmonth = GETPOST('search_date_endmonth', 'int'); +$search_date_endyear = GETPOST('search_date_endyear', 'int'); +$search_date_start = dol_mktime(0, 0, 0, $search_date_startmonth, $search_date_startday, $search_date_startyear); // Use tzserver +$search_date_end = dol_mktime(23, 59, 59, $search_date_endmonth, $search_date_endday, $search_date_endyear); +$search_date_when_startday = GETPOST('search_date_when_startday', 'int'); +$search_date_when_startmonth = GETPOST('search_date_when_startmonth', 'int'); +$search_date_when_startyear = GETPOST('search_date_when_startyear', 'int'); +$search_date_when_endday = GETPOST('search_date_when_endday', 'int'); +$search_date_when_endmonth = GETPOST('search_date_when_endmonth', 'int'); +$search_date_when_endyear = GETPOST('search_date_when_endyear', 'int'); +$search_date_when_start = dol_mktime(0, 0, 0, $search_date_when_startmonth, $search_date_when_startday, $search_date_when_startyear); // Use tzserver +$search_date_when_end = dol_mktime(23, 59, 59, $search_date_when_endmonth, $search_date_when_endday, $search_date_when_endyear); +$search_recurring = GETPOST('search_recurring', 'int'); +$search_frequency = GETPOST('search_frequency', 'alpha'); +$search_unit_frequency = GETPOST('search_unit_frequency', 'alpha'); +$search_status = GETPOST('search_status', 'int'); + +$limit = GETPOST('limit', 'int') ?GETPOST('limit', 'int') : $conf->liste_limit; +$sortfield = GETPOST('sortfield', 'alpha'); +$sortorder = GETPOST('sortorder', 'alpha'); +$page = GETPOSTISSET('pageplusone') ? (GETPOST('pageplusone') - 1) : GETPOST('page', 'int'); +if (empty($page) || $page == -1) { + $page = 0; +} // If $page is not defined, or '' or -1 +$offset = $limit * $page; +if (!$sortorder) { + $sortorder = 'DESC'; +} +if (!$sortfield) { + $sortfield = 'f.titre'; +} +$pageprev = $page - 1; +$pagenext = $page + 1; + +$object = new FactureFournisseurRec($db); +if (($id > 0 || $ref) && $action != 'create' && $action != 'add') { + $ret = $object->fetch($id, $ref); + if (!$ret) { + setEventMessages($langs->trans("ErrorRecordNotFound"), null, 'errors'); + } +} + +// Initialize technical object to manage hooks of page. Note that conf->hooks_modules contains array of hook context +$hookmanager->initHooks(array('supplierinvoicereclist')); +$extrafields = new ExtraFields($db); + +// fetch optionals attributes and labels +$extrafields->fetch_name_optionals_label($object->table_element); + +$search_array_options = $extrafields->getOptionalsFromPost($object->table_element, '', 'search_'); + +$permissionnote = $user->rights->facture->creer; // Used by the include of actions_setnotes.inc.php +$permissiondellink = $user->rights->facture->creer; // Used by the include of actions_dellink.inc.php +$permissiontoedit = $user->rights->facture->creer; // Used by the include of actions_lineupdonw.inc.php + +$arrayfields = array( + 'f.titre'=>array('label'=>'Ref', 'checked'=>1), + 's.nom'=>array('label'=>'ThirdParty', 'checked'=>1), + 'f.total_ht'=>array('label'=>'AmountHT', 'checked'=>1), + 'f.total_tva'=>array('label'=>'AmountVAT', 'checked'=>1), + 'f.total_ttc'=>array('label'=>'AmountTTC', 'checked'=>1), + 'f.fk_mode_reglement'=>array('label'=>'PaymentMode', 'checked'=>0), + 'f.fk_cond_reglement'=>array('label'=>'PaymentTerm', 'checked'=>0), + 'recurring'=>array('label'=>'RecurringInvoice', 'checked'=>1), + 'f.frequency'=>array('label'=>'Frequency', 'checked'=>1), + 'f.unit_frequency'=>array('label'=>'FrequencyUnit', 'checked'=>1), + 'f.nb_gen_done'=>array('label'=>'NbOfGenerationDoneShort', 'checked'=>1), + 'f.date_last_gen'=>array('label'=>'DateLastGenerationShort', 'checked'=>1), + 'f.date_when'=>array('label'=>'NextDateToExecutionShort', 'checked'=>1), + 'f.fk_user_author'=>array('label'=>'UserCreation', 'checked'=>0, 'position'=>500), + 'f.fk_user_modif'=>array('label'=>'UserModification', 'checked'=>0, 'position'=>505), + 'f.datec'=>array('label'=>'DateCreation', 'checked'=>0, 'position'=>520), + 'f.tms'=>array('label'=>'DateModificationShort', 'checked'=>0, 'position'=>525), + 'suspended '=>array('label'=>'Status', 'checked'=>1, 'position'=>1000), +); +// Extra fields +include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_array_fields.tpl.php'; + +$object->fields = dol_sort_array($object->fields, 'position'); +$arrayfields = dol_sort_array($arrayfields, 'position'); + +if ($socid > 0) { + $tmpthirdparty = new Societe($db); + $res = $tmpthirdparty->fetch($socid); + if ($res > 0) { + $search_societe = $tmpthirdparty->name; + } +} +$objecttype = 'facture_fourn_rec'; + +$result = restrictedArea($user, 'facture', $object->id, $objecttype); + + +/* + * Actions + */ + +if (GETPOST('cancel', 'alpha')) { + $action = 'list'; + $massaction = ''; +} +if (!GETPOST('confirmmassaction', 'alpha') && $massaction != 'presend' && $massaction != 'confirm_presend') { + $massaction = ''; +} + +$parameters = array('socid' => $socid); +$reshook = $hookmanager->executeHooks('doActions', $parameters, $object, $action); // Note that $action and $object may have been modified by some hooks +if ($reshook < 0) { + setEventMessages($hookmanager->error, $hookmanager->errors, 'errors'); +} + +if (empty($reshook)) { + if (GETPOST('cancel', 'alpha')) { + $action = ''; + } + + // Selection of new fields + include DOL_DOCUMENT_ROOT.'/core/actions_changeselectedfields.inc.php'; + + // Do we click on purge search criteria ? + if (GETPOST('button_removefilter_x', 'alpha') || GETPOST('button_removefilter.x', 'alpha') || GETPOST('button_removefilter', 'alpha')) { // All test are required to be compatible with all browsers + $search_ref = ''; + $search_societe = ''; + $search_montant_ht = ''; + $search_montant_vat = ''; + $search_montant_ttc = ''; + $search_payment_mode = ''; + $search_payment_term = ''; + $search_date_startday = ''; + $search_date_startmonth = ''; + $search_date_startyear = ''; + $search_date_endday = ''; + $search_date_endmonth = ''; + $search_date_endyear = ''; + $search_date_start = ''; + $search_date_end = ''; + $search_date_when_startday = ''; + $search_date_when_startmonth = ''; + $search_date_when_startyear = ''; + $search_date_when_endday = ''; + $search_date_when_endmonth = ''; + $search_date_when_endyear = ''; + $search_date_when_start = ''; + $search_date_when_end = ''; + $search_recurring = ''; + $search_frequency = ''; + $search_unit_frequency = ''; + $search_status = ''; + $search_array_options = array(); + } + + // Mass actions + /*$objectclass='MyObject'; + $objectlabel='MyObject'; + $permissiontoread = $user->rights->mymodule->read; + $permissiontodelete = $user->rights->mymodule->delete; + $uploaddir = $conf->mymodule->dir_output; + include DOL_DOCUMENT_ROOT.'/core/actions_massactions.inc.php';*/ +} + + +/* + * View + */ + +$help_url = ''; +llxHeader('', $langs->trans("RepeatableSupplierInvoices"), $help_url); + +$form = new Form($db); +$formother = new FormOther($db); +if (!empty($conf->projet->enabled)) { + $formproject = new FormProjets($db); +} +$companystatic = new Societe($db); +$supplierinvoicerectmp = new FactureFournisseurRec($db); +$tmpuser = new User($db); + +$now = dol_now(); +$tmparray = dol_getdate($now); +$today = dol_mktime(23, 59, 59, $tmparray['mon'], $tmparray['mday'], $tmparray['year']); // Today is last second of current day + + +/* + * List mode + */ + +$sql = "SELECT s.nom as name, s.rowid as socid, f.rowid as facid, f.titre as title, f.total_ht, f.total_tva, f.total_ttc, f.frequency, f.unit_frequency,"; +$sql .= " f.nb_gen_done, f.nb_gen_max, f.date_last_gen, f.date_when, f.suspended,"; +$sql .= " f.datec, f.fk_user_author, f.tms, f.fk_user_modif,"; +$sql .= " f.fk_cond_reglement, f.fk_mode_reglement"; +// Add fields from extrafields +if (!empty($extrafields->attributes[$object->table_element]['label'])) { + foreach ($extrafields->attributes[$object->table_element]['label'] as $key => $val) { + $sql .= ($extrafields->attributes[$object->table_element]['type'][$key] != 'separate' ? ", ef.".$key." as options_".$key : ''); + } +} +// Add fields from hooks +$parameters = array(); +$reshook = $hookmanager->executeHooks('printFieldListSelect', $parameters, $object); // Note that $action and $object may have been modified by hook +$sql .= preg_replace('/^,/', '', $hookmanager->resPrint); +$sql = preg_replace('/,\s*$/', '', $sql); + +$sql .= ' FROM '.MAIN_DB_PREFIX.'societe as s, '.MAIN_DB_PREFIX.'facture_fourn_rec as f'; +$sql .= ' LEFT JOIN '.MAIN_DB_PREFIX.'facture_fourn_rec_extrafields as ef ON ef.fk_object = f.rowid'; +if (empty($user->rights->societe->client->voir) && !$socid) { + $sql .= ', '.MAIN_DB_PREFIX.'societe_commerciaux as sc'; +} +$sql .= ' WHERE f.fk_soc = s.rowid'; +$sql .= ' AND f.entity IN ('.getEntity('invoice').')'; +if (empty($user->rights->societe->client->voir) && !$socid) { + $sql .= ' AND s.rowid = sc.fk_soc AND sc.fk_user = '. (int) $user->id; +} +if ($search_ref) { + $sql .= natural_search('f.titre', $search_ref); +} +if ($socid) { + $sql .= ' AND s.rowid = '.(int) $socid; +} +if ($search_societe) { + $sql .= natural_search('s.nom', $search_societe); +} +if ($search_montant_ht != '') { + $sql .= natural_search('f.total_ht', $search_montant_ht, 1); +} +if ($search_montant_vat != '') { + $sql .= natural_search('f.total_tva', $search_montant_vat, 1); +} +if ($search_montant_ttc != '') { + $sql .= natural_search('f.total_ttc', $search_montant_ttc, 1); +} +if (!empty($search_payment_mode) && $search_payment_mode != '-1') { + $sql .= natural_search('f.fk_mode_reglement', $search_payment_mode, 1); +} +if (!empty($search_payment_term) && $search_payment_term != '-1') { + $sql .= natural_search('f.fk_cond_reglement', $search_payment_term, 1); +} +if ($search_recurring == '1') { + $sql .= ' AND f.frequency > 0'; +} +if ($search_recurring == '0') { + $sql .= ' AND (f.frequency IS NULL or f.frequency = 0)'; +} +if ($search_frequency != '') { + $sql .= natural_search('f.frequency', $search_frequency, 1); +} +if ($search_unit_frequency != '') { + $sql .= ' AND f.frequency > 0'.natural_search('f.unit_frequency', $search_unit_frequency); +} +if ($search_status != '' && $search_status >= -1) { + if ($search_status == 0) { + $sql .= ' AND frequency = 0 AND suspended = 0'; + } + if ($search_status == 1) { + $sql .= ' AND frequency != 0 AND suspended = 0'; + } + if ($search_status == -1) { + $sql .= ' AND suspended = 1'; + } +} +if ($search_date_start) { + $sql .= " AND f.date_last_gen >= '".$db->idate($search_date_start)."'"; +} +if ($search_date_end) { + $sql .= " AND f.date_last_gen <= '".$db->idate($search_date_end)."'"; +} +if ($search_date_when_start) { + $sql .= " AND f.date_when >= '".$db->idate($search_date_when_start)."'"; +} +if ($search_date_when_end) { + $sql .= " AND f.date_when <= '".$db->idate($search_date_when_end)."'"; +} + +$tmpsortfield = $sortfield; +if ($tmpsortfield == 'recurring') { + $tmpsortfield = 'f.frequency'; +} +$sql .= $db->order($tmpsortfield, $sortorder); + +$nbtotalofrecords = ''; +if (empty($conf->global->MAIN_DISABLE_FULL_SCANLIST)) { + $result = $db->query($sql); + $nbtotalofrecords = $db->num_rows($result); + if (($page * $limit) > $nbtotalofrecords) { // if total resultset is smaller then paging size (filtering), goto and load page 0 + $page = 0; + $offset = 0; + } +} + +$sql .= $db->plimit($limit + 1, $offset); + +$resql = $db->query($sql); +if ($resql) { + $num = $db->num_rows($resql); + + $param = ''; + if (!empty($contextpage) && $contextpage != $_SERVER["PHP_SELF"]) { + $param .= '&contextpage='.urlencode($contextpage); + } + if ($limit > 0 && $limit != $conf->liste_limit) { + $param .= '&limit='.urlencode($limit); + } + if ($socid > 0) { + $param .= '&socid='.urlencode($socid); + } + if ($search_date_startday) { + $param .= '&search_date_startday='.urlencode($search_date_startday); + } + if ($search_date_startmonth) { + $param .= '&search_date_startmonth='.urlencode($search_date_startmonth); + } + if ($search_date_startyear) { + $param .= '&search_date_startyear='.urlencode($search_date_startyear); + } + if ($search_date_endday) { + $param .= '&search_date_endday='.urlencode($search_date_endday); + } + if ($search_date_endmonth) { + $param .= '&search_date_endmonth='.urlencode($search_date_endmonth); + } + if ($search_date_endyear) { + $param .= '&search_date_endyear='.urlencode($search_date_endyear); + } + if ($search_date_when_startday) { + $param .= '&search_date_when_startday='.urlencode($search_date_when_startday); + } + if ($search_date_when_startmonth) { + $param .= '&search_date_when_startmonth='.urlencode($search_date_when_startmonth); + } + if ($search_date_when_startyear) { + $param .= '&search_date_when_startyear='.urlencode($search_date_when_startyear); + } + if ($search_date_when_endday) { + $param .= '&search_date_when_endday='.urlencode($search_date_when_endday); + } + if ($search_date_when_endmonth) { + $param .= '&search_date_when_endmonth='.urlencode($search_date_when_endmonth); + } + if ($search_date_when_endyear) { + $param .= '&search_date_when_endyear='.urlencode($search_date_when_endyear); + } + if ($search_ref) { + $param .= '&search_ref='.urlencode($search_ref); + } + if ($search_societe) { + $param .= '&search_societe='.urlencode($search_societe); + } + if ($search_montant_ht != '') { + $param .= '&search_montant_ht='.urlencode($search_montant_ht); + } + if ($search_montant_vat != '') { + $param .= '&search_montant_vat='.urlencode($search_montant_vat); + } + if ($search_montant_ttc != '') { + $param .= '&search_montant_ttc='.urlencode($search_montant_ttc); + } + if ($search_payment_mode != '') { + $param .= '&search_payment_mode='.urlencode($search_payment_mode); + } + if ($search_payment_term != '') { + $param .= '&search_payment_term='.urlencode($search_payment_term); + } + if ($search_recurring != '' && $search_recurring != '-1') { + $param .= '&search_recurring='.urlencode($search_recurring); + } + if ($search_frequency > 0) { + $param .= '&search_frequency='.urlencode($search_frequency); + } + if ($search_unit_frequency != '') { + $param .= '&search_unit_frequency='.urlencode($search_unit_frequency); + } + if ($search_status != '') { + $param .= '&search_status='.urlencode($search_status); + } + if ($optioncss != '') { + $param .= '&optioncss='.urlencode($optioncss); + } + // Add $param from extra fields + include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_search_param.tpl.php'; + + $massactionbutton = $form->selectMassAction('', $massaction == 'presend' ? array() : array('presend'=>$langs->trans("SendByMail"), 'builddoc'=>$langs->trans("PDFMerge"))); + + $varpage = empty($contextpage) ? $_SERVER["PHP_SELF"] : $contextpage; + $selectedfields = $form->multiSelectArrayWithCheckbox('selectedfields', $arrayfields, $varpage); // This also change content of $arrayfields + //$selectedfields.=$form->showCheckAddButtons('checkforselect', 1); + + print '
'; + if ($optioncss != '') { + print ''; + } + print ''; + print ''; + print ''; + print ''; + print ''; + print ''; + print ''; + + $title = $langs->trans("RepeatableSupplierInvoices"); + + print_barre_liste($title, $page, $_SERVER['PHP_SELF'], $param, $sortfield, $sortorder, '', $num, $nbtotalofrecords, 'bill', 0, '', '', $limit, 0, 0, 1); + + print ''.$langs->trans("ToCreateAPredefinedSupplierInvoice", $langs->transnoentitiesnoconv("ChangeIntoRepeatableInvoice")).'

'; + + $i = 0; + + $moreforfilter = ''; + + print '
'; + print ''."\n"; + + // Filters lines + print ''; + // Ref + if (!empty($arrayfields['f.titre']['checked'])) { + print ''; + } + // Thirdparty + if (!empty($arrayfields['s.nom']['checked'])) { + print ''; + } + if (!empty($arrayfields['f.total_ht']['checked'])) { + // Amount net + print ''; + } + if (!empty($arrayfields['f.total_tva']['checked'])) { + // Amount Vat + print ''; + } + if (!empty($arrayfields['f.total_ttc']['checked'])) { + // Amount + print ''; + } + if (!empty($arrayfields['f.fk_cond_reglement']['checked'])) { + // Payment term + print '"; + } + if (!empty($arrayfields['f.fk_mode_reglement']['checked'])) { + // Payment mode + print ''; + } + if (!empty($arrayfields['recurring']['checked'])) { + // Recurring or not + print ''; + } + if (!empty($arrayfields['f.frequency']['checked'])) { + // Recurring or not + print ''; + } + if (!empty($arrayfields['f.unit_frequency']['checked'])) { + // Frequency unit + print ''; + } + if (!empty($arrayfields['f.nb_gen_done']['checked'])) { + // Nb generation + print ''; + } + // Date invoice + if (!empty($arrayfields['f.date_last_gen']['checked'])) { + print ''; + } + // Date next generation + if (!empty($arrayfields['f.date_when']['checked'])) { + print ''; + } + // Extra fields + include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_search_input.tpl.php'; + + // Fields from hook + $parameters = array('arrayfields'=>$arrayfields); + $reshook = $hookmanager->executeHooks('printFieldListOption', $parameters); // Note that $action and $object may have been modified by hook + print $hookmanager->resPrint; + // User creation + if (!empty($arrayfields['f.fk_user_author']['checked'])) { + print ''; + } + // User modification + if (!empty($arrayfields['f.fk_user_modif']['checked'])) { + print ''; + } + // Date creation + if (!empty($arrayfields['f.datec']['checked'])) { + print ''; + } + // Date modification + if (!empty($arrayfields['f.tms']['checked'])) { + print ''; + } + // Action column + print ''; + print "\n"; + + print ''; + if (!empty($arrayfields['f.titre']['checked'])) { + print_liste_field_titre($arrayfields['f.titre']['label'], $_SERVER['PHP_SELF'], "f.titre", "", $param, "", $sortfield, $sortorder); + } + if (!empty($arrayfields['s.nom']['checked'])) { + print_liste_field_titre($arrayfields['s.nom']['label'], $_SERVER['PHP_SELF'], "s.nom", "", $param, "", $sortfield, $sortorder); + } + if (!empty($arrayfields['f.total_ht']['checked'])) { + print_liste_field_titre($arrayfields['f.total_ht']['label'], $_SERVER['PHP_SELF'], "f.total_ht", "", $param, 'class="right"', $sortfield, $sortorder); + } + if (!empty($arrayfields['f.total_tva']['checked'])) { + print_liste_field_titre($arrayfields['f.total_tva']['label'], $_SERVER['PHP_SELF'], "f.total_tva", "", $param, 'class="right"', $sortfield, $sortorder); + } + if (!empty($arrayfields['f.total_ttc']['checked'])) { + print_liste_field_titre($arrayfields['f.total_ttc']['label'], $_SERVER['PHP_SELF'], "f.total_ttc", "", $param, 'class="right"', $sortfield, $sortorder); + } + if (!empty($arrayfields['f.fk_cond_reglement']['checked'])) { + print_liste_field_titre($arrayfields['f.fk_cond_reglement']['label'], $_SERVER['PHP_SELF'], "f.fk_cond_reglement", "", $param, '', $sortfield, $sortorder); + } + if (!empty($arrayfields['f.fk_mode_reglement']['checked'])) { + print_liste_field_titre($arrayfields['f.fk_mode_reglement']['label'], $_SERVER['PHP_SELF'], "f.fk_mode_reglement", "", $param, '', $sortfield, $sortorder); + } + if (!empty($arrayfields['recurring']['checked'])) { + print_liste_field_titre($arrayfields['recurring']['label'], $_SERVER['PHP_SELF'], "recurring", "", $param, 'class="center"', $sortfield, $sortorder); + } + if (!empty($arrayfields['f.frequency']['checked'])) { + print_liste_field_titre($arrayfields['f.frequency']['label'], $_SERVER['PHP_SELF'], "f.frequency", "", $param, 'align="center"', $sortfield, $sortorder); + } + if (!empty($arrayfields['f.unit_frequency']['checked'])) { + print_liste_field_titre($arrayfields['f.unit_frequency']['label'], $_SERVER['PHP_SELF'], "f.unit_frequency", "", $param, 'align="center"', $sortfield, $sortorder); + } + if (!empty($arrayfields['f.nb_gen_done']['checked'])) { + print_liste_field_titre($arrayfields['f.nb_gen_done']['label'], $_SERVER['PHP_SELF'], "f.nb_gen_done", "", $param, 'align="center"', $sortfield, $sortorder); + } + if (!empty($arrayfields['f.date_last_gen']['checked'])) { + print_liste_field_titre($arrayfields['f.date_last_gen']['label'], $_SERVER['PHP_SELF'], "f.date_last_gen", "", $param, 'align="center"', $sortfield, $sortorder); + } + if (!empty($arrayfields['f.date_when']['checked'])) { + print_liste_field_titre($arrayfields['f.date_when']['label'], $_SERVER['PHP_SELF'], "f.date_when", "", $param, 'align="center"', $sortfield, $sortorder); + } + if (!empty($arrayfields['f.fk_user_author']['checked'])) { + print_liste_field_titre($arrayfields['f.fk_user_author']['label'], $_SERVER['PHP_SELF'], "f.fk_user_author", "", $param, 'align="center"', $sortfield, $sortorder); + } + if (!empty($arrayfields['f.fk_user_modif']['checked'])) { + print_liste_field_titre($arrayfields['f.fk_user_modif']['label'], $_SERVER['PHP_SELF'], "f.fk_user_modif", "", $param, 'align="center"', $sortfield, $sortorder); + } + if (!empty($arrayfields['f.datec']['checked'])) { + print_liste_field_titre($arrayfields['f.datec']['label'], $_SERVER['PHP_SELF'], "f.datec", "", $param, 'align="center"', $sortfield, $sortorder); + } + if (!empty($arrayfields['f.tms']['checked'])) { + print_liste_field_titre($arrayfields['f.tms']['label'], $_SERVER['PHP_SELF'], "f.tms", "", $param, 'align="center"', $sortfield, $sortorder); + } + // Extra fields + include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_search_title.tpl.php'; + if (!empty($arrayfields['status']['checked'])) { + print_liste_field_titre($arrayfields['status']['label'], $_SERVER['PHP_SELF'], "f.suspended,f.frequency", "", $param, 'align="center"', $sortfield, $sortorder); + } + print_liste_field_titre($selectedfields, $_SERVER["PHP_SELF"], "", '', '', 'align="center"', $sortfield, $sortorder, 'center maxwidthsearch '); + print "\n"; + + if ($num > 0) { + $i = 0; + $totalarray = array(); + $totalarray['nbfield'] = 0; + $totalarray['val']['f.total_ht'] = 0; + $totalarray['val']['f.total_tva'] = 0; + $totalarray['val']['f.total_ttc'] = 0; + while ($i < min($num, $limit)) { + $objp = $db->fetch_object($resql); + if (empty($objp)) { + break; + } + + $companystatic->id = $objp->socid; + $companystatic->name = $objp->name; + + $supplierinvoicerectmp->id = !empty($objp->id) ? $objp->id : $objp->facid; + $supplierinvoicerectmp->frequency = $objp->frequency; + $supplierinvoicerectmp->suspended = $objp->suspended; + $supplierinvoicerectmp->unit_frequency = $objp->unit_frequency; + $supplierinvoicerectmp->nb_gen_max = $objp->nb_gen_max; + $supplierinvoicerectmp->nb_gen_done = $objp->nb_gen_done; + $supplierinvoicerectmp->ref = $objp->title; + $supplierinvoicerectmp->total_ht = $objp->total_ht; + $supplierinvoicerectmp->total_tva = $objp->total_tva; + $supplierinvoicerectmp->total_ttc = $objp->total_ttc; + + print ''; + + if (!empty($arrayfields['f.titre']['checked'])) { + print '\n"; + if (!$i) { + $totalarray['nbfield']++; + } + } + if (!empty($arrayfields['s.nom']['checked'])) { + print ''; + if (!$i) { + $totalarray['nbfield']++; + } + } + if (!empty($arrayfields['f.total_ht']['checked'])) { + print ''."\n"; + if (!$i) { + $totalarray['nbfield']++; + } + if (!$i) { + $totalarray['pos'][$totalarray['nbfield']] = 'f.total_ht'; + } + $totalarray['val']['f.total_ht'] += $objp->total_ht; + } + if (!empty($arrayfields['f.total_tva']['checked'])) { + print ''."\n"; + if (!$i) { + $totalarray['nbfield']++; + } + if (!$i) { + $totalarray['pos'][$totalarray['nbfield']] = 'f.total_tva'; + } + $totalarray['val']['f.total_tva'] += $objp->total_tva; + } + if (!empty($arrayfields['f.total_ttc']['checked'])) { + print ''."\n"; + if (!$i) { + $totalarray['nbfield']++; + } + if (!$i) { + $totalarray['pos'][$totalarray['nbfield']] = 'f.total_ttc'; + } + $totalarray['val']['f.total_ttc'] += $objp->total_ttc; + } + // Payment term + if (!empty($arrayfields['f.fk_cond_reglement']['checked'])) { + print ''."\n"; + if (!$i) { + $totalarray['nbfield']++; + } + } + // Payment mode + if (!empty($arrayfields['f.fk_mode_reglement']['checked'])) { + print ''."\n"; + if (!$i) { + $totalarray['nbfield']++; + } + } + // Is it a recurring invoice + if (!empty($arrayfields['recurring']['checked'])) { + print ''; + if (!$i) { + $totalarray['nbfield']++; + } + } + if (!empty($arrayfields['f.frequency']['checked'])) { + print ''; + if (!$i) { + $totalarray['nbfield']++; + } + } + if (!empty($arrayfields['f.unit_frequency']['checked'])) { + print ''; + if (!$i) { + $totalarray['nbfield']++; + } + } + if (!empty($arrayfields['f.nb_gen_done']['checked'])) { + print ''; + if (!$i) { + $totalarray['nbfield']++; + } + } + // Date last generation + if (!empty($arrayfields['f.date_last_gen']['checked'])) { + print ''; + if (!$i) { + $totalarray['nbfield']++; + } + } + // Date next generation + if (!empty($arrayfields['f.date_when']['checked'])) { + print ''; + if (!$i) { + $totalarray['nbfield']++; + } + } + if (!empty($arrayfields['f.fk_user_author']['checked'])) { + print ''; + if (!$i) { + $totalarray['nbfield']++; + } + } + if (!empty($arrayfields['f.fk_user_modif']['checked'])) { + print ''; + if (!$i) { + $totalarray['nbfield']++; + } + } + if (!empty($arrayfields['f.datec']['checked'])) { + print ''; + if (!$i) { + $totalarray['nbfield']++; + } + } + if (!empty($arrayfields['f.tms']['checked'])) { + print ''; + if (!$i) { + $totalarray['nbfield']++; + } + } + + $obj = $objp; + // Extra fields + include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_print_fields.tpl.php'; + // Fields from hook + $parameters = array('arrayfields'=>$arrayfields, 'obj'=>$objp, 'i'=>$i, 'totalarray'=>&$totalarray); + $reshook = $hookmanager->executeHooks('printFieldListValue', $parameters, $object); // Note that $action and $object may have been modified by hook + print $hookmanager->resPrint; + // Status + if (!empty($arrayfields['status']['checked'])) { + print ''; + if (!$i) { + $totalarray['nbfield']++; + } + } + // Action column + print '"; + + print "\n"; + + $i++; + } + } else { + $colspan = 1; + foreach ($arrayfields as $key => $val) { + if (!empty($val['checked'])) { + $colspan++; + } + } + print ''; + } + + // Show total line + include DOL_DOCUMENT_ROOT.'/core/tpl/list_print_total.tpl.php'; + + + print "
'; + print ''; + print ''; + print ''; + print ''; + print ''; + print ''; + print ''; + print ''; + $form->select_conditions_paiements($search_payment_term, 'search_payment_term', -1, 1, 1, 'maxwidth100'); + print "'; + $form->select_types_paiements($search_payment_mode, 'search_payment_mode', '', 0, 1, 1, 0, 1, 'maxwidth100'); + print ''; + print $form->selectyesno('search_recurring', $search_recurring, 1, false, 1); + print ''; + print ''; + print ''; + print ''; + print ''; + print ''; + print '
'; + print $form->selectDate($search_date_start ? $search_date_start : -1, 'search_date_start', 0, 0, 1, '', 1, 0, 0, '', '', '', '', 1, '', $langs->trans('From')); + print '
'; + print '
'; + print $form->selectDate($search_date_end ? $search_date_end : -1, 'search_date_end', 0, 0, 1, '', 1, 0, 0, '', '', '', '', 1, '', $langs->trans('to')); + print '
'; + print '
'; + print '
'; + print $form->selectDate($search_date_when_start ? $search_date_when_start : -1, 'search_date_when_start', 0, 0, 1, '', 1, 0, 0, '', '', '', '', 1, '', $langs->trans('From')); + print '
'; + print '
'; + print $form->selectDate($search_date_when_end ? $search_date_when_end : -1, 'search_date_when_end', 0, 0, 1, '', 1, 0, 0, '', '', '', '', 1, '', $langs->trans('to')); + print '
'; + print '
'; + print ''; + print ''; + print ''; + print ''; + $searchpicto = $form->showFilterButtons(); + print $searchpicto; + print '
'; + print $supplierinvoicerectmp->getNomUrl(1); + print ""; + print "'.$companystatic->getNomUrl(1, 'customer').''.price($objp->total_ht).''.price($objp->total_tva).''.price($objp->total_ttc).''; + $form->form_conditions_reglement('', $objp->fk_cond_reglement, 'none'); + print ''; + $form->form_modes_reglement('', $objp->fk_mode_reglement, 'none'); + print ''.($objp->frequency ? img_picto($langs->trans("Frequency").': '.$objp->frequency.' '.$objp->unit_frequency, 'recurring', 'class="opacitymedium"').' ' : '').yn($objp->frequency ? 1 : 0).''.($objp->frequency > 0 ? $objp->frequency : '').''.($objp->frequency > 0 ? $objp->unit_frequency : '').''; + print ($objp->frequency > 0 ? $objp->nb_gen_done.($objp->nb_gen_max > 0 ? ' / '.$objp->nb_gen_max : '') : ''.$langs->trans('NA').''); + print ''; + print ($objp->frequency > 0 ? dol_print_date($db->jdate($objp->date_last_gen), 'day') : ''.$langs->trans('NA').''); + print ''; + print '
'; + print ($objp->frequency ? ($supplierinvoicerectmp->isMaxNbGenReached() ? '' : '').dol_print_date($db->jdate($objp->date_when), 'day').($supplierinvoicerectmp->isMaxNbGenReached() ? '' : '') : ''.$langs->trans('NA').''); + if (!$supplierinvoicerectmp->isMaxNbGenReached()) { + if (!$objp->suspended && $objp->frequency > 0 && $db->jdate($objp->date_when) && $db->jdate($objp->date_when) < $now) { + print img_warning($langs->trans("Late")); + } + } else { + print img_info($langs->trans("MaxNumberOfGenerationReached")); + } + print '
'; + print '
'; + if ($objp->fk_user_author > 0) { + $tmpuser->fetch($objp->fk_user_author); + print $tmpuser->getNomUrl(1); + } + print ''; + if ($objp->fk_user_author > 0) { + $tmpuser->fetch($objp->fk_user_author); + print $tmpuser->getNomUrl(1); + } + print ''; + print dol_print_date($db->jdate($objp->datec), 'dayhour'); + print ''; + print dol_print_date($db->jdate($objp->tms), 'dayhour'); + print ''; + print $supplierinvoicerectmp->getLibStatut(3, 0); + print ''; + if ($user->rights->facture->creer && empty($supplierinvoicerectmp->suspended)) { + if ($supplierinvoicerectmp->isMaxNbGenReached()) { + print $langs->trans("MaxNumberOfGenerationReached"); + } elseif (empty($objp->frequency) || $db->jdate($objp->date_when) <= $today) { + print ''; + print img_picto($langs->trans("CreateBill"), 'add', 'class="paddingrightonly"'); + print $langs->trans("CreateBill").''; + } else { + print $form->textwithpicto('', $langs->trans("DateIsNotEnough")); + } + } else { + print " "; + } + if (!$i) { + $totalarray['nbfield']++; + } + print "
'.$langs->trans("NoRecordFound").'
"; + print "
"; + print "
"; + + $db->free($resql); +} else { + dol_print_error($db); +} + +// End of page +llxFooter(); +$db->close(); diff --git a/htdocs/install/mysql/migration/15.0.0-16.0.0.sql b/htdocs/install/mysql/migration/15.0.0-16.0.0.sql index 55218730381..c76abb14eb1 100644 --- a/htdocs/install/mysql/migration/15.0.0-16.0.0.sql +++ b/htdocs/install/mysql/migration/15.0.0-16.0.0.sql @@ -96,4 +96,130 @@ CREATE TABLE llx_stock_mouvement_extrafields ( import_key varchar(14) )ENGINE=innodb; + +-- Facture fourn rec +CREATE TABLE llx_facture_fourn_rec +( + rowid integer AUTO_INCREMENT PRIMARY KEY, + titre varchar(200) NOT NULL, + ref_supplier varchar(180) NOT NULL, + entity integer DEFAULT 1 NOT NULL, + fk_soc integer NOT NULL, + datec datetime, + tms timestamp DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + suspended integer DEFAULT 0, + libelle varchar(255), + amount double(24, 8) DEFAULT 0 NOT NULL, + remise real DEFAULT 0, + vat_src_code varchar(10) DEFAULT '', + localtax1 double(24,8) DEFAULT 0, + localtax2 double(24,8) DEFAULT 0, + total_ht double(24,8) DEFAULT 0, + total_tva double(24,8) DEFAULT 0, + total_ttc double(24,8) DEFAULT 0, + fk_user_author integer, + fk_user_modif integer, + fk_projet integer, + fk_account integer, + fk_cond_reglement integer, + fk_mode_reglement integer, + date_lim_reglement date, + note_private text, + note_public text, + modelpdf varchar(255), + fk_multicurrency integer, + multicurrency_code varchar(3), + multicurrency_tx double(24,8) DEFAULT 1, + multicurrency_total_ht double(24,8) DEFAULT 0, + multicurrency_total_tva double(24,8) DEFAULT 0, + multicurrency_total_ttc double(24,8) DEFAULT 0, + usenewprice integer DEFAULT 0, + frequency integer, + unit_frequency varchar(2) DEFAULT 'm', + date_when datetime DEFAULT NULL, + date_last_gen datetime DEFAULT NULL, + nb_gen_done integer DEFAULT NULL, + nb_gen_max integer DEFAULT NULL, + auto_validate integer DEFAULT 0, + generate_pdf integer DEFAULT 1 + +)ENGINE=innodb; + +ALTER TABLE llx_facture_fourn_rec ADD UNIQUE INDEX uk_facture_fourn_rec_ref (titre, entity); +ALTER TABLE llx_facture_fourn_rec ADD UNIQUE INDEX uk_facture_fourn_rec_ref_supplier (ref_supplier, fk_soc, entity); +ALTER TABLE llx_facture_fourn_rec ADD INDEX idx_facture_fourn_rec_date_lim_reglement (date_lim_reglement); +ALTER TABLE llx_facture_fourn_rec ADD INDEX idx_facture_fourn_rec_fk_soc (fk_soc); +ALTER TABLE llx_facture_fourn_rec ADD INDEX idx_facture_fourn_rec_fk_user_author (fk_user_author); +ALTER TABLE llx_facture_fourn_rec ADD INDEX idx_facture_fourn_rec_fk_projet (fk_projet); +ALTER TABLE llx_facture_fourn_rec ADD CONSTRAINT fk_facture_fourn_rec_fk_soc FOREIGN KEY (fk_soc) REFERENCES llx_societe (rowid); +ALTER TABLE llx_facture_fourn_rec ADD CONSTRAINT fk_facture_fourn_rec_fk_user_author FOREIGN KEY (fk_user_author) REFERENCES llx_user (rowid); +ALTER TABLE llx_facture_fourn_rec ADD CONSTRAINT fk_facture_fourn_rec_fk_projet FOREIGN KEY (fk_projet) REFERENCES llx_projet (rowid); + +CREATE TABLE llx_facture_fourn_rec_extrafields +( + rowid integer AUTO_INCREMENT PRIMARY KEY, + tms timestamp DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + fk_object integer NOT NULL, + import_key varchar(14) -- import key +) ENGINE=innodb; + +ALTER TABLE llx_facture_fourn_rec_extrafields ADD INDEX idx_facture_fourn_rec_extrafields (fk_object); + +CREATE TABLE llx_facture_fourn_det_rec +( + rowid integer AUTO_INCREMENT PRIMARY KEY, + fk_facture_fourn integer NOT NULL, + fk_parent_line integer NULL, + fk_product integer NULL, + ref varchar(50), + label varchar(255) DEFAULT NULL, + description text, + pu_ht double(24,8), + pu_ttc double(24,8), + qty real, + remise_percent real DEFAULT 0, + fk_remise_except integer NULL, + vat_src_code varchar(10) DEFAULT '', + tva_tx double(7,4), + localtax1_tx double(7,4) DEFAULT 0, + localtax1_type varchar(10) NULL, + localtax2_tx double(7,4) DEFAULT 0, + localtax2_type varchar(10) NULL, + total_ht double(24,8), + total_tva double(24,8), + total_localtax1 double(24,8) DEFAULT 0, + total_localtax2 double(24,8) DEFAULT 0, + total_ttc double(24,8), + product_type integer DEFAULT 0, + date_start integer DEFAULT NULL, + date_end integer DEFAULT NULL, + info_bits integer DEFAULT 0, + special_code integer UNSIGNED DEFAULT 0, + rang integer DEFAULT 0, + fk_unit integer DEFAULT NULL, + import_key varchar(14), + fk_user_author integer, + fk_user_modif integer, + fk_multicurrency integer, + multicurrency_code varchar(3), + multicurrency_subprice double(24,8) DEFAULT 0, + multicurrency_total_ht double(24,8) DEFAULT 0, + multicurrency_total_tva double(24,8) DEFAULT 0, + multicurrency_total_ttc double(24,8) DEFAULT 0 +)ENGINE=innodb; + +ALTER TABLE llx_facture_fourn_det_rec ADD CONSTRAINT fk_facture_fourn_det_rec_fk_unit FOREIGN KEY (fk_unit) REFERENCES llx_c_units (rowid); + +CREATE TABLE llx_facture_fourn_det_rec_extrafields +( + rowid integer AUTO_INCREMENT PRIMARY KEY, + tms timestamp DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + fk_object integer NOT NULL, -- object id + import_key varchar(14) -- import key +)ENGINE=innodb; + +ALTER TABLE llx_facture_fourn_det_rec_extrafields ADD INDEX idx_facture_fourn_det_rec_extrafields (fk_object); + +ALTER TABLE llx_facture_fourn ADD COLUMN fk_fac_rec_source integer; + ALTER TABLE llx_mrp_mo ADD COLUMN fk_parent_line integer; diff --git a/htdocs/install/mysql/tables/llx_facture_fourn.sql b/htdocs/install/mysql/tables/llx_facture_fourn.sql index 683f15623a6..9ceff4e4fa9 100644 --- a/htdocs/install/mysql/tables/llx_facture_fourn.sql +++ b/htdocs/install/mysql/tables/llx_facture_fourn.sql @@ -61,6 +61,7 @@ create table llx_facture_fourn fk_user_valid integer, -- user validating fk_user_closing integer, -- user closing + fk_fac_rec_source integer, -- facture rec source fk_facture_source integer, -- facture origine si facture avoir fk_projet integer, -- projet auquel est associee la facture diff --git a/htdocs/install/mysql/tables/llx_facture_fourn_det_rec.extrafields.key.sql b/htdocs/install/mysql/tables/llx_facture_fourn_det_rec.extrafields.key.sql new file mode 100644 index 00000000000..221f7fa6398 --- /dev/null +++ b/htdocs/install/mysql/tables/llx_facture_fourn_det_rec.extrafields.key.sql @@ -0,0 +1,20 @@ +-- ======================================================================== +-- Copyright (C) 2017 ATM-CONSULTING +-- +-- 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 . +-- +-- =================================================================== + + +ALTER TABLE llx_facture_fourn_det_rec_extrafields ADD INDEX llx_facture_fourn_det_rec_extrafields (fk_object); \ No newline at end of file diff --git a/htdocs/install/mysql/tables/llx_facture_fourn_det_rec.extrafields.sql b/htdocs/install/mysql/tables/llx_facture_fourn_det_rec.extrafields.sql new file mode 100644 index 00000000000..096cab080fd --- /dev/null +++ b/htdocs/install/mysql/tables/llx_facture_fourn_det_rec.extrafields.sql @@ -0,0 +1,24 @@ +-- =================================================================== +-- +-- 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 . +-- +-- =================================================================== + +create table llx_facture_fourn_det_rec_extrafields +( + rowid integer AUTO_INCREMENT PRIMARY KEY, + tms timestamp DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + fk_object integer NOT NULL, -- object id + import_key varchar(14) -- import key +)ENGINE=innodb; diff --git a/htdocs/install/mysql/tables/llx_facture_fourn_det_rec.key.sql b/htdocs/install/mysql/tables/llx_facture_fourn_det_rec.key.sql new file mode 100644 index 00000000000..6d0618c912a --- /dev/null +++ b/htdocs/install/mysql/tables/llx_facture_fourn_det_rec.key.sql @@ -0,0 +1,18 @@ +-- =================================================================== +-- +-- 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 . +-- +-- =================================================================== + +ALTER TABLE llx_facture_fourn_det_rec ADD CONSTRAINT fk_facture_fourn_det_rec_fk_unit FOREIGN KEY (fk_unit) REFERENCES llx_c_units (rowid); diff --git a/htdocs/install/mysql/tables/llx_facture_fourn_det_rec.sql b/htdocs/install/mysql/tables/llx_facture_fourn_det_rec.sql new file mode 100644 index 00000000000..8f29f85230a --- /dev/null +++ b/htdocs/install/mysql/tables/llx_facture_fourn_det_rec.sql @@ -0,0 +1,61 @@ +-- =================================================================== +-- +-- 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 . +-- +-- =================================================================== + +create table llx_facture_fourn_det_rec +( + rowid integer AUTO_INCREMENT PRIMARY KEY, + fk_facture_fourn integer NOT NULL, + fk_parent_line integer NULL, + fk_product integer NULL, + ref varchar(50), -- supplier product ref + label varchar(255) DEFAULT NULL, + description text, + pu_ht double(24,8), -- unit price excluding tax + pu_ttc double(24,8), -- unit price with tax + qty real, -- quantity of product/service + remise_percent real DEFAULT 0, -- % de la remise ligne (exemple 20%) + fk_remise_except integer NULL, -- Lien vers table des remises fixes + vat_src_code varchar(10) DEFAULT '', -- Vat code used as source of vat fields. Not strict foreign key here. + tva_tx double(7,4), -- taux tva + localtax1_tx double(7,4) DEFAULT 0, -- localtax1 rate + localtax1_type varchar(10) NULL, -- localtax1 type + localtax2_tx double(7,4) DEFAULT 0, -- localtax2 rate + localtax2_type varchar(10) NULL, -- localtax2 type + total_ht double(24,8), -- Total HT de la ligne toute quantity et incluant remise ligne et globale + total_tva double(24,8), -- Total TVA de la ligne toute quantity et incluant remise ligne et globale + total_localtax1 double(24,8) DEFAULT 0, -- Total LocalTax1 for total quantity of line + total_localtax2 double(24,8) DEFAULT 0, -- total LocalTax2 for total quantity of line + total_ttc double(24,8), -- Total TTC de la ligne toute quantity et incluant remise ligne et globale + product_type integer DEFAULT 0, + date_start integer DEFAULT NULL, -- date debut si service + date_end integer DEFAULT NULL, -- date fin si service + info_bits integer DEFAULT 0, -- TVA NPR ou non + special_code integer UNSIGNED DEFAULT 0, -- code for special lines + rang integer DEFAULT 0, -- ordre d'affichage + fk_unit integer DEFAULT NULL, + import_key varchar(14), + + fk_user_author integer, -- user making creation + fk_user_modif integer, -- user making last change + + fk_multicurrency integer, + multicurrency_code varchar(3), + multicurrency_subprice double(24,8) DEFAULT 0, + multicurrency_total_ht double(24,8) DEFAULT 0, + multicurrency_total_tva double(24,8) DEFAULT 0, + multicurrency_total_ttc double(24,8) DEFAULT 0 +)ENGINE=innodb; diff --git a/htdocs/install/mysql/tables/llx_facture_fourn_rec.extrafields.key.sql b/htdocs/install/mysql/tables/llx_facture_fourn_rec.extrafields.key.sql new file mode 100644 index 00000000000..86dddf51624 --- /dev/null +++ b/htdocs/install/mysql/tables/llx_facture_fourn_rec.extrafields.key.sql @@ -0,0 +1,19 @@ +-- =================================================================== +-- +-- 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 . +-- +-- =================================================================== + + +ALTER TABLE llx_facture_fourn_rec_extrafields ADD INDEX idx_facture_fourn_rec_extrafields (fk_object); diff --git a/htdocs/install/mysql/tables/llx_facture_fourn_rec.extrafields.sql b/htdocs/install/mysql/tables/llx_facture_fourn_rec.extrafields.sql new file mode 100644 index 00000000000..d1f5bd80e41 --- /dev/null +++ b/htdocs/install/mysql/tables/llx_facture_fourn_rec.extrafields.sql @@ -0,0 +1,7 @@ +create table llx_facture_fourn_rec_extrafields +( + rowid integer AUTO_INCREMENT PRIMARY KEY, + tms timestamp DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + fk_object integer NOT NULL, + import_key varchar(14) -- import key +) ENGINE=innodb; \ No newline at end of file diff --git a/htdocs/install/mysql/tables/llx_facture_fourn_rec.key.sql b/htdocs/install/mysql/tables/llx_facture_fourn_rec.key.sql new file mode 100644 index 00000000000..b3065fdb5d6 --- /dev/null +++ b/htdocs/install/mysql/tables/llx_facture_fourn_rec.key.sql @@ -0,0 +1,29 @@ +-- ============================================================================ +-- +-- 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 . +-- +-- ============================================================================ + + +ALTER TABLE llx_facture_fourn_rec ADD UNIQUE INDEX uk_facture_fourn_rec_ref (ref, entity); +ALTER TABLE llx_facture_fourn_rec ADD UNIQUE INDEX uk_facture_fourn_rec_ref_supplier (ref_supplier, fk_soc, entity); + +ALTER TABLE llx_facture_fourn_rec ADD INDEX idx_facture_fourn_rec_date_lim_reglement (date_lim_reglement); +ALTER TABLE llx_facture_fourn_rec ADD INDEX idx_facture_fourn_rec_fk_soc (fk_soc); +ALTER TABLE llx_facture_fourn_rec ADD INDEX idx_facture_fourn_rec_fk_user_author (fk_user_author); +ALTER TABLE llx_facture_fourn_rec ADD INDEX idx_facture_fourn_rec_fk_projet (fk_projet); + +ALTER TABLE llx_facture_fourn_rec ADD CONSTRAINT fk_facture_fourn_rec_fk_soc FOREIGN KEY (fk_soc) REFERENCES llx_societe (rowid); +ALTER TABLE llx_facture_fourn_rec ADD CONSTRAINT fk_facture_fourn_rec_fk_user_author FOREIGN KEY (fk_user_author) REFERENCES llx_user (rowid); +ALTER TABLE llx_facture_fourn_rec ADD CONSTRAINT fk_facture_fourn_rec_fk_projet FOREIGN KEY (fk_projet) REFERENCES llx_projet (rowid); diff --git a/htdocs/install/mysql/tables/llx_facture_fourn_rec.sql b/htdocs/install/mysql/tables/llx_facture_fourn_rec.sql new file mode 100644 index 00000000000..edaa49e0ea1 --- /dev/null +++ b/htdocs/install/mysql/tables/llx_facture_fourn_rec.sql @@ -0,0 +1,77 @@ +-- =========================================================================== +-- +-- 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 . +-- +-- =========================================================================== + +create table llx_facture_fourn_rec +( + rowid integer AUTO_INCREMENT PRIMARY KEY, + titre varchar(200) NOT NULL, + ref_supplier varchar(180) NOT NULL, + entity integer DEFAULT 1 NOT NULL, -- multi company id + fk_soc integer NOT NULL, + + datec datetime, -- date de creation + tms timestamp DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, -- last modification date + + suspended integer DEFAULT 0, -- 1=suspended + + libelle varchar(255), + amount double(24, 8) DEFAULT 0 NOT NULL, + remise real DEFAULT 0, + + vat_src_code varchar(10) DEFAULT '', -- Vat code used as source of vat fields. Not strict foreign key here. + localtax1 double(24,8) DEFAULT 0, + localtax2 double(24,8) DEFAULT 0, + total_ht double(24,8) DEFAULT 0, + total_tva double(24,8) DEFAULT 0, + total_ttc double(24,8) DEFAULT 0, + + fk_user_author integer, -- user creating + fk_user_modif integer, -- user making last change + + fk_projet integer, -- projet auquel est associe la facture + + fk_account integer, -- bank account + fk_cond_reglement integer, -- condition de reglement (30 jours, fin de mois ...) + fk_mode_reglement integer, -- mode de reglement (CHQ, VIR, ...) + date_lim_reglement date, -- date limite de reglement + + note_private text, + note_public text, + modelpdf varchar(255), + + fk_multicurrency integer, + multicurrency_code varchar(3), + multicurrency_tx double(24,8) DEFAULT 1, + multicurrency_total_ht double(24,8) DEFAULT 0, + multicurrency_total_tva double(24,8) DEFAULT 0, + multicurrency_total_ttc double(24,8) DEFAULT 0, + + + -- Fields linked to the recurring behavior + + usenewprice integer DEFAULT 0, -- update invoice with current price of product instead of recorded price + frequency integer, -- frequency (for example: 3 for every 3 month) + unit_frequency varchar(2) DEFAULT 'm', -- 'm' for month (date_when must be a day <= 28), 'y' for year, ... + + date_when datetime DEFAULT NULL, -- date for next gen (when an invoice is generated, this field must be updated with next date) + date_last_gen datetime DEFAULT NULL, -- date for last gen (date with last successfull generation of invoice) + nb_gen_done integer DEFAULT NULL, -- nb of generation done (when an invoice is generated, this field must incremented) + nb_gen_max integer DEFAULT NULL, -- maximum number of generation + auto_validate integer DEFAULT 0, -- 0 to create in draft, 1 to create and validate the new invoice + generate_pdf integer DEFAULT 1 -- 0 disable pdf, 1 to generate pdf + +)ENGINE=innodb; diff --git a/htdocs/langs/en_US/errors.lang b/htdocs/langs/en_US/errors.lang index cbce9a6a264..98d83aa9453 100644 --- a/htdocs/langs/en_US/errors.lang +++ b/htdocs/langs/en_US/errors.lang @@ -9,6 +9,7 @@ ErrorBadMXDomain=Email %s seems incorrect (domain has no valid MX record) ErrorBadUrl=Url %s is incorrect ErrorBadValueForParamNotAString=Bad value for your parameter. It appends generally when translation is missing. ErrorRefAlreadyExists=Reference %s already exists. +ErrorTitleAlreadyExists=Title %s already exists. ErrorLoginAlreadyExists=Login %s already exists. ErrorGroupAlreadyExists=Group %s already exists. ErrorEmailAlreadyExists=Email %s already exists. diff --git a/htdocs/langs/en_US/suppliers.lang b/htdocs/langs/en_US/suppliers.lang index ca9ee174d29..15da3f0638a 100644 --- a/htdocs/langs/en_US/suppliers.lang +++ b/htdocs/langs/en_US/suppliers.lang @@ -47,3 +47,10 @@ BuyerName=Buyer name AllProductServicePrices=All product / service prices AllProductReferencesOfSupplier=All references of vendor BuyingPriceNumShort=Vendor prices +RepeatableSupplierInvoice=Template supplier invoice +RepeatableSupplierInvoices=Template supplier invoices +RepeatableSupplierInvoicesList=Template supplier invoices +RecurringSupplierInvoices=Recurring supplier invoices +ToCreateAPredefinedSupplierInvoice=In order to create template supplier invoice, you must create a standard invoice, then, without validating it, click on the "%s" button. +GeneratedFromSupplierTemplate=Generated from supplier invoice template %s +SupplierInvoiceGeneratedFromTemplate=Supplier invoice %s Generated from supplier invoice template %s \ No newline at end of file diff --git a/htdocs/langs/fr_FR/errors.lang b/htdocs/langs/fr_FR/errors.lang index 80814e27ed2..80d4034a1ba 100644 --- a/htdocs/langs/fr_FR/errors.lang +++ b/htdocs/langs/fr_FR/errors.lang @@ -8,7 +8,7 @@ ErrorBadEMail=L'email '%s' est invalide ErrorBadMXDomain=L'email %s semble incorrect (domaine n'a pas d'enregistrement MX valide) ErrorBadUrl=L'URL '%s' est invalide ErrorBadValueForParamNotAString=Mauvaise valeur de paramètre. Ceci arrive lors d'une tentative de traduction d'une clé non renseignée. -ErrorRefAlreadyExists=Le référence %s existe déjà. +ErrorRefAlreadyExists=La référence %s existe déjà. ErrorLoginAlreadyExists=L'identifiant %s existe déjà. ErrorGroupAlreadyExists=Le groupe %s existe déjà. ErrorEmailAlreadyExists=L'e-mail %s existe déjà. diff --git a/htdocs/langs/fr_FR/suppliers.lang b/htdocs/langs/fr_FR/suppliers.lang index 0d0bf4528a5..dd5402d66ae 100644 --- a/htdocs/langs/fr_FR/suppliers.lang +++ b/htdocs/langs/fr_FR/suppliers.lang @@ -46,4 +46,4 @@ ReputationForThisProduct=Réputation BuyerName=Nom de l'acheteur AllProductServicePrices=Tous les prix du produits / service AllProductReferencesOfSupplier=Toutes les références du fournisseur -BuyingPriceNumShort=Prix fournisseurs +BuyingPriceNumShort=Prix fournisseurs \ No newline at end of file