dolibarr  19.0.0-dev
card.php
Go to the documentation of this file.
1 <?php
2 /* Copyright (C) 2002-2006 Rodolphe Quiedeville <rodolphe@quiedeville.org>
3  * Copyright (C) 2004 Eric Seigne <eric.seigne@ryxeo.com>
4  * Copyright (C) 2004-2020 Laurent Destailleur <eldy@users.sourceforge.net>
5  * Copyright (C) 2005 Marc Barilley / Ocebo <marc@ocebo.com>
6  * Copyright (C) 2005-2015 Regis Houssin <regis.houssin@inodbox.com>
7  * Copyright (C) 2006 Andre Cianfarani <acianfa@free.fr>
8  * Copyright (C) 2010-2015 Juanjo Menent <jmenent@2byte.es>
9  * Copyright (C) 2012-2013 Christophe Battarel <christophe.battarel@altairis.fr>
10  * Copyright (C) 2012-2013 Cédric Salvador <csalvador@gpcsolutions.fr>
11  * Copyright (C) 2012-2014 Raphaël Doursenaud <rdoursenaud@gpcsolutions.fr>
12  * Copyright (C) 2013 Jean-Francois FERRY <jfefe@aternatik.fr>
13  * Copyright (C) 2013-2014 Florian Henry <florian.henry@open-concept.pro>
14  * Copyright (C) 2013 Cédric Salvador <csalvador@gpcsolutions.fr>
15  * Copyright (C) 2014-2019 Ferran Marcet <fmarcet@2byte.es>
16  * Copyright (C) 2015-2016 Marcos García <marcosgdf@gmail.com>
17  * Copyright (C) 2018-2023 Frédéric France <frederic.france@netlogic.fr>
18  * Copyright (C) 2022 Gauthier VERDOL <gauthier.verdol@atm-consulting.fr>
19  *
20  * This program is free software; you can redistribute it and/or modify
21  * it under the terms of the GNU General Public License as published by
22  * the Free Software Foundation; either version 3 of the License, or
23  * (at your option) any later version.
24  *
25  * This program is distributed in the hope that it will be useful,
26  * but WITHOUT ANY WARRANTY; without even the implied warranty of
27  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
28  * GNU General Public License for more details.
29  *
30  * You should have received a copy of the GNU General Public License
31  * along with this program. If not, see <https://www.gnu.org/licenses/>.
32  */
33 
40 // Libraries
41 require '../../main.inc.php';
42 require_once DOL_DOCUMENT_ROOT.'/compta/facture/class/facture.class.php';
43 require_once DOL_DOCUMENT_ROOT.'/compta/facture/class/facture-rec.class.php';
44 require_once DOL_DOCUMENT_ROOT.'/compta/bank/class/account.class.php';
45 require_once DOL_DOCUMENT_ROOT.'/compta/paiement/class/paiement.class.php';
46 
47 require_once DOL_DOCUMENT_ROOT.'/core/modules/facture/modules_facture.php';
48 require_once DOL_DOCUMENT_ROOT.'/core/class/discount.class.php';
49 require_once DOL_DOCUMENT_ROOT.'/core/class/html.formfile.class.php';
50 require_once DOL_DOCUMENT_ROOT.'/core/class/html.formother.class.php';
51 require_once DOL_DOCUMENT_ROOT.'/core/class/html.formmargin.class.php';
52 require_once DOL_DOCUMENT_ROOT.'/core/lib/invoice.lib.php';
53 require_once DOL_DOCUMENT_ROOT.'/core/lib/functions2.lib.php';
54 require_once DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php';
55 require_once DOL_DOCUMENT_ROOT.'/core/class/extrafields.class.php';
56 
57 if (isModEnabled('commande')) {
58  require_once DOL_DOCUMENT_ROOT.'/commande/class/commande.class.php';
59 }
60 if (isModEnabled('project')) {
61  require_once DOL_DOCUMENT_ROOT.'/projet/class/project.class.php';
62  require_once DOL_DOCUMENT_ROOT.'/core/class/html.formprojet.class.php';
63 }
64 require_once DOL_DOCUMENT_ROOT.'/core/class/doleditor.class.php';
65 
66 if (isModEnabled('variants')) {
67  require_once DOL_DOCUMENT_ROOT.'/variants/class/ProductCombination.class.php';
68 }
69 if (isModEnabled('accounting')) {
70  require_once DOL_DOCUMENT_ROOT.'/accountancy/class/accountingjournal.class.php';
71 }
72 
73 // Load translation files required by the page
74 $langs->loadLangs(array('bills', 'companies', 'compta', 'products', 'banks', 'main', 'withdrawals'));
75 if (isModEnabled('incoterm')) {
76  $langs->load('incoterm');
77 }
78 if (isModEnabled('margin')) {
79  $langs->load('margins');
80 }
81 
82 // General $Variables
83 $id = (GETPOST('id', 'int') ? GETPOST('id', 'int') : GETPOST('facid', 'int')); // For backward compatibility
84 $ref = GETPOST('ref', 'alpha');
85 $socid = GETPOST('socid', 'int');
86 $action = GETPOST('action', 'aZ09');
87 $confirm = GETPOST('confirm', 'alpha');
88 $cancel = GETPOST('cancel', 'alpha');
89 $backtopage = GETPOST('backtopage', 'alpha');
90 
91 $lineid = GETPOST('lineid', 'int');
92 $userid = GETPOST('userid', 'int');
93 $search_ref = GETPOST('sf_ref', 'alpha') ? GETPOST('sf_ref', 'alpha') : GETPOST('search_ref', 'alpha');
94 $search_societe = GETPOST('search_societe', 'alpha');
95 $search_montant_ht = GETPOST('search_montant_ht', 'alpha');
96 $search_montant_ttc = GETPOST('search_montant_ttc', 'alpha');
97 $origin = GETPOST('origin', 'alpha');
98 $originid = (GETPOST('originid', 'int') ? GETPOST('originid', 'int') : GETPOST('origin_id', 'int')); // For backward compatibility
99 $fac_rec = GETPOST('fac_rec', 'int');
100 $facid = GETPOST('facid', 'int');
101 $ref_client = GETPOST('ref_client', 'int');
102 $rank = (GETPOST('rank', 'int') > 0) ? GETPOST('rank', 'int') : -1;
103 $projectid = (GETPOST('projectid', 'int') ? GETPOST('projectid', 'int') : 0);
104 
105 // PDF
106 $hidedetails = (GETPOST('hidedetails', 'int') ? GETPOST('hidedetails', 'int') : (!empty($conf->global->MAIN_GENERATE_DOCUMENTS_HIDE_DETAILS) ? 1 : 0));
107 $hidedesc = (GETPOST('hidedesc', 'int') ? GETPOST('hidedesc', 'int') : (!empty($conf->global->MAIN_GENERATE_DOCUMENTS_HIDE_DESC) ? 1 : 0));
108 $hideref = (GETPOST('hideref', 'int') ? GETPOST('hideref', 'int') : (!empty($conf->global->MAIN_GENERATE_DOCUMENTS_HIDE_REF) ? 1 : 0));
109 
110 // Number of lines for predefined product/service choices
111 $NBLINES = 4;
112 
113 $usehm = (!empty($conf->global->MAIN_USE_HOURMIN_IN_DATE_RANGE) ? $conf->global->MAIN_USE_HOURMIN_IN_DATE_RANGE : 0);
114 
115 $object = new Facture($db);
116 $extrafields = new ExtraFields($db);
117 
118 // Fetch optionals attributes and labels
119 $extrafields->fetch_name_optionals_label($object->table_element);
120 
121 // Load object
122 if ($id > 0 || !empty($ref)) {
123  if ($action != 'add') {
124  if (empty($conf->global->INVOICE_USE_SITUATION)) {
125  $fetch_situation = false;
126  } else {
127  $fetch_situation = true;
128  }
129  $ret = $object->fetch($id, $ref, '', '', $fetch_situation);
130  }
131 }
132 
133 // Initialize technical object to manage hooks of page. Note that conf->hooks_modules contains array of hook context
134 $hookmanager->initHooks(array('invoicecard', 'globalcard'));
135 
136 // Permissions
137 $usercanread = $user->hasRight("facture", "lire");
138 $usercancreate = $user->hasRight("facture", "creer");
139 $usercanissuepayment = $user->hasRight("facture", "paiement");
140 $usercandelete = $user->hasRight("facture", "supprimer");
141 $usercancreatecontract = $user->hasRight("contrat", "creer");
142 
143 // Advanced Permissions
144 $usercanvalidate = ((empty($conf->global->MAIN_USE_ADVANCED_PERMS) && $usercancreate) || (!empty($conf->global->MAIN_USE_ADVANCED_PERMS) && !empty($user->rights->facture->invoice_advance->validate)));
145 $usercansend = (empty($conf->global->MAIN_USE_ADVANCED_PERMS) || (!empty($conf->global->MAIN_USE_ADVANCED_PERMS) && !empty($user->rights->facture->invoice_advance->send)));
146 $usercanreopen = ((empty($conf->global->MAIN_USE_ADVANCED_PERMS) && $usercancreate) || (!empty($conf->global->MAIN_USE_ADVANCED_PERMS) && !empty($user->rights->facture->invoice_advance->reopen)));
147 if (!empty($conf->global->INVOICE_DISALLOW_REOPEN)) {
148  $usercanreopen = false;
149 }
150 $usercanunvalidate = ((empty($conf->global->MAIN_USE_ADVANCED_PERMS) && !empty($usercancreate)) || (!empty($conf->global->MAIN_USE_ADVANCED_PERMS) && !empty($user->rights->facture->invoice_advance->unvalidate)));
151 
152 $usermustrespectpricemin = ((!empty($conf->global->MAIN_USE_ADVANCED_PERMS) && empty($user->rights->produit->ignore_price_min_advance)) || empty($conf->global->MAIN_USE_ADVANCED_PERMS));
153 $usercancreatemargin = (!empty($user->rights->margins->creer) ? $user->rights->margins->creer : 0);
154 $usercanreadallmargin = (!empty($user->rights->margins->liretous) ? $user->rights->margins->liretous : 0);
155 $usercancreatewithdrarequest = (!empty($user->rights->prelevement->bons->creer) ? $user->rights->prelevement->bons->creer : 0);
156 
157 $permissionnote = $usercancreate; // Used by the include of actions_setnotes.inc.php
158 $permissiondellink = $usercancreate; // Used by the include of actions_dellink.inc.php
159 $permissiontoedit = $usercancreate; // Used by the include of actions_lineupdonw.inc.php
160 $permissiontoadd = $usercancreate; // Used by the include of actions_addupdatedelete.inc.php
161 
162 // retained warranty invoice available type
163 $retainedWarrantyInvoiceAvailableType = array();
164 if (!empty($conf->global->INVOICE_USE_RETAINED_WARRANTY)) {
165  $retainedWarrantyInvoiceAvailableType = explode('+', $conf->global->INVOICE_USE_RETAINED_WARRANTY);
166 }
167 
168 // Security check
169 if ($user->socid) {
170  $socid = $user->socid;
171 }
172 $isdraft = (($object->statut == Facture::STATUS_DRAFT) ? 1 : 0);
173 
174 $result = restrictedArea($user, 'facture', $object->id, '', '', 'fk_soc', 'rowid', $isdraft);
175 
176 
177 /*
178  * Actions
179  */
180 
181 $parameters = array('socid' => $socid);
182 $reshook = $hookmanager->executeHooks('doActions', $parameters, $object, $action); // Note that $action and $object may have been modified by some hooks
183 if ($reshook < 0) {
184  setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
185 }
186 
187 if (empty($reshook)) {
188  $backurlforlist = DOL_URL_ROOT.'/compta/facture/list.php';
189 
190  if (empty($backtopage) || ($cancel && empty($id))) {
191  if (empty($backtopage) || ($cancel && strpos($backtopage, '__ID__'))) {
192  if (empty($id) && (($action != 'add' && $action != 'create') || $cancel)) {
193  $backtopage = $backurlforlist;
194  } else {
195  $backtopage = DOL_URL_ROOT.'/compta/facture/card.php?id='.((!empty($id) && $id > 0) ? $id : '__ID__');
196  }
197  }
198  }
199 
200  if ($cancel) {
201  if (!empty($backtopageforcancel)) {
202  header("Location: ".$backtopageforcancel);
203  exit;
204  } elseif (!empty($backtopage)) {
205  header("Location: ".$backtopage);
206  exit;
207  }
208  $action = '';
209  }
210 
211  include DOL_DOCUMENT_ROOT.'/core/actions_setnotes.inc.php'; // Must be include, not include_once
212 
213  include DOL_DOCUMENT_ROOT.'/core/actions_dellink.inc.php'; // Must be include, not include_once
214 
215  include DOL_DOCUMENT_ROOT.'/core/actions_lineupdown.inc.php'; // Must be include, not include_once
216 
217  // Action clone object
218  if ($action == 'confirm_clone' && $confirm == 'yes' && $permissiontoadd) {
219  $objectutil = dol_clone($object, 1); // To avoid to denaturate loaded object when setting some properties for clone. We use native clone to keep this->db valid.
220 
221  $objectutil->date = dol_mktime(12, 0, 0, GETPOST('newdatemonth', 'int'), GETPOST('newdateday', 'int'), GETPOST('newdateyear', 'int'));
222  $objectutil->socid = $socid;
223  $result = $objectutil->createFromClone($user, $id);
224  if ($result > 0) {
225  header("Location: ".$_SERVER['PHP_SELF'].'?facid='.$result);
226  exit();
227  } else {
228  $langs->load("errors");
229  setEventMessages($objectutil->error, $objectutil->errors, 'errors');
230  $action = '';
231  }
232  } elseif ($action == 'reopen' && $usercanreopen) {
233  $result = $object->fetch($id);
234 
235  if ($object->statut == Facture::STATUS_CLOSED || ($object->statut == Facture::STATUS_ABANDONED && ($object->close_code != 'replaced' || $object->getIdReplacingInvoice() == 0)) || ($object->statut == Facture::STATUS_VALIDATED && $object->paye == 1)) { // ($object->statut == 1 && $object->paye == 1) should not happened but can be found when data are corrupted
236  $result = $object->setUnpaid($user);
237  if ($result > 0) {
238  header('Location: '.$_SERVER["PHP_SELF"].'?facid='.$id);
239  exit();
240  } else {
241  setEventMessages($object->error, $object->errors, 'errors');
242  }
243  }
244  } elseif ($action == 'confirm_delete' && $confirm == 'yes') {
245  // Delete invoice
246  $result = $object->fetch($id);
247  $object->fetch_thirdparty();
248 
249  $idwarehouse = GETPOST('idwarehouse');
250 
251  $qualified_for_stock_change = 0;
252  if (empty($conf->global->STOCK_SUPPORTS_SERVICES)) {
253  $qualified_for_stock_change = $object->hasProductsOrServices(2);
254  } else {
255  $qualified_for_stock_change = $object->hasProductsOrServices(1);
256  }
257 
258  $isErasable = $object->is_erasable();
259 
260  if (($usercandelete && $isErasable > 0)
261  || ($usercancreate && $isErasable == 1)) {
262  $result = $object->delete($user, 0, $idwarehouse);
263  if ($result > 0) {
264  header('Location: '.DOL_URL_ROOT.'/compta/facture/list.php?restore_lastsearch_values=1');
265  exit();
266  } else {
267  setEventMessages($object->error, $object->errors, 'errors');
268  $action = '';
269  }
270  }
271  } elseif ($action == 'confirm_deleteline' && $confirm == 'yes' && $usercancreate) {
272  // Delete line
273  $object->fetch($id);
274  $object->fetch_thirdparty();
275 
276  $result = $object->deleteline(GETPOST('lineid', 'int'));
277  if ($result > 0) {
278  // reorder lines
279  $object->line_order(true);
280  // Define output language
281  $outputlangs = $langs;
282  $newlang = '';
283  if (getDolGlobalInt('MAIN_MULTILANGS') && empty($newlang) && GETPOST('lang_id')) {
284  $newlang = GETPOST('lang_id');
285  }
286  if (getDolGlobalInt('MAIN_MULTILANGS') && empty($newlang)) {
287  $newlang = $object->thirdparty->default_lang;
288  }
289  if (!empty($newlang)) {
290  $outputlangs = new Translate("", $conf);
291  $outputlangs->setDefaultLang($newlang);
292  $outputlangs->load('products');
293  }
294  if (empty($conf->global->MAIN_DISABLE_PDF_AUTOUPDATE)) {
295  $ret = $object->fetch($id); // Reload to get new records
296  $result = $object->generateDocument($object->model_pdf, $outputlangs, $hidedetails, $hidedesc, $hideref);
297  }
298  if ($result >= 0) {
299  header('Location: '.$_SERVER["PHP_SELF"].'?facid='.$id);
300  exit();
301  }
302  } else {
303  setEventMessages($object->error, $object->errors, 'errors');
304  $action = '';
305  }
306  } elseif ($action == 'unlinkdiscount' && $usercancreate) {
307  // Delete link of credit note to invoice
308  $discount = new DiscountAbsolute($db);
309  $result = $discount->fetch(GETPOSTINT("discountid"));
310  $discount->unlink_invoice();
311  } elseif ($action == 'valid' && $usercancreate) {
312  // Validation
313  $object->fetch($id);
314 
315  if (!empty($conf->global-> INVOICE_CHECK_POSTERIOR_DATE)) {
316  $last_of_type = $object->willBeLastOfSameType(true);
317  if (empty($object->date_validation) && !$last_of_type[0]) {
318  setEventMessages($langs->transnoentities("ErrorInvoiceIsNotLastOfSameType", $object->ref, dol_print_date($object->date, 'day'), dol_print_date($last_of_type[1], 'day')), null, 'errors');
319  $action = '';
320  }
321  }
322 
323  // On verifie signe facture
324  if ($object->type == Facture::TYPE_CREDIT_NOTE) {
325  // Si avoir, le signe doit etre negatif
326  if ($object->total_ht >= 0) {
327  setEventMessages($langs->trans("ErrorInvoiceAvoirMustBeNegative"), null, 'errors');
328  $action = '';
329  }
330  } else {
331  // If not a credit note, amount with tax must be positive or nul.
332  // Note that amount excluding tax can be negative because you can have a invoice of 100 with vat of 20 that
333  // consumes a credit note of 100 with vat 0 (total with tax is 0 but without tax is -20).
334  // For some cases, credit notes can have a vat of 0 (for example when selling goods in France).
335  if (empty($conf->global->FACTURE_ENABLE_NEGATIVE) && $object->total_ttc < 0) {
336  setEventMessages($langs->trans("ErrorInvoiceOfThisTypeMustBePositive"), null, 'errors');
337  $action = '';
338  }
339 
340  // Also negative lines should not be allowed on 'non Credit notes' invoices. A test is done when adding or updating lines but we must
341  // do it again in validation to avoid cases where invoice is created from another object that allow negative lines.
342  // Note that we can accept the negative line if sum with other lines with same vat makes total positive: Because all the lines will be merged together
343  // when converted into 'available credit' and we will get a positive available credit line.
344  // Note: Other solution if you want to add a negative line on invoice, is to create a discount for customer and consumme it (but this is possible on standard invoice only).
345  $array_of_total_ht_per_vat_rate = array();
346  $array_of_total_ht_devise_per_vat_rate = array();
347  foreach ($object->lines as $line) {
348  //$vat_src_code_for_line = $line->vat_src_code; // TODO We chek sign of total per vat without taking into account the vat code because for the moment the vat code is lost/unknown when we add a down payment.
349  $vat_src_code_for_line = '';
350  if (empty($array_of_total_ht_per_vat_rate[$line->tva_tx.'_'.$vat_src_code_for_line])) {
351  $array_of_total_ht_per_vat_rate[$line->tva_tx.'_'.$vat_src_code_for_line] = 0;
352  }
353  if (empty($array_of_total_ht_devise_per_vat_rate[$line->tva_tx.'_'.$vat_src_code_for_line])) {
354  $array_of_total_ht_devise_per_vat_rate[$line->tva_tx.'_'.$vat_src_code_for_line] = 0;
355  }
356  $array_of_total_ht_per_vat_rate[$line->tva_tx.'_'.$vat_src_code_for_line] += $line->total_ht;
357  $array_of_total_ht_devise_per_vat_rate[$line->tva_tx.'_'.$vat_src_code_for_line] += $line->multicurrency_total_ht;
358  }
359 
360  //var_dump($array_of_total_ht_per_vat_rate);exit;
361  foreach ($array_of_total_ht_per_vat_rate as $vatrate => $tmpvalue) {
362  $tmp_total_ht = price2num($array_of_total_ht_per_vat_rate[$vatrate]);
363  $tmp_total_ht_devise = price2num($array_of_total_ht_devise_per_vat_rate[$vatrate]);
364 
365  if (($tmp_total_ht < 0 || $tmp_total_ht_devise < 0) && empty($conf->global->FACTURE_ENABLE_NEGATIVE_LINES)) {
366  if ($object->type == $object::TYPE_DEPOSIT) {
367  $langs->load("errors");
368  // Using negative lines on deposit lead to headach and blocking problems when you want to consume them.
369  setEventMessages($langs->trans("ErrorLinesCantBeNegativeOnDeposits"), null, 'errors');
370  $error++;
371  $action = '';
372  } else {
373  $tmpvatratetoshow = explode('_', $vatrate);
374  $tmpvatratetoshow[0] = round($tmpvatratetoshow[0], 2);
375 
376  if ($tmpvatratetoshow[0] != 0) {
377  $langs->load("errors");
378  setEventMessages($langs->trans("ErrorLinesCantBeNegativeForOneVATRate", $tmpvatratetoshow[0]), null, 'errors');
379  $error++;
380  $action = '';
381  }
382  }
383  }
384  }
385  }
386  } elseif ($action == 'classin' && $usercancreate) {
387  $object->fetch($id);
388  $object->setProject(GETPOST('projectid', 'int'));
389  } elseif ($action == 'setmode' && $usercancreate) {
390  $object->fetch($id);
391  $result = $object->setPaymentMethods(GETPOST('mode_reglement_id', 'int'));
392  if ($result < 0) {
393  dol_print_error($db, $object->error);
394  }
395  } elseif ($action == 'setretainedwarrantyconditions' && $user->hasRight('facture', 'creer')) {
396  $object->fetch($id);
397  $object->retained_warranty_fk_cond_reglement = 0; // To clean property
398  $result = $object->setRetainedWarrantyPaymentTerms(GETPOST('retained_warranty_fk_cond_reglement', 'int'));
399  if ($result < 0) {
400  dol_print_error($db, $object->error);
401  }
402 
403  $old_rw_date_lim_reglement = $object->retained_warranty_date_limit;
404  $new_rw_date_lim_reglement = $object->calculate_date_lim_reglement($object->retained_warranty_fk_cond_reglement);
405  if ($new_rw_date_lim_reglement > $old_rw_date_lim_reglement) {
406  $object->retained_warranty_date_limit = $new_rw_date_lim_reglement;
407  }
408  if ($object->retained_warranty_date_limit < $object->date) {
409  $object->retained_warranty_date_limit = $object->date;
410  }
411  $result = $object->update($user);
412  if ($result < 0) {
413  dol_print_error($db, $object->error);
414  }
415  } elseif ($action == 'setretainedwarranty' && $user->hasRight('facture', 'creer')) {
416  $object->fetch($id);
417  $result = $object->setRetainedWarranty(GETPOST('retained_warranty', 'float'));
418  if ($result < 0) {
419  dol_print_error($db, $object->error);
420  }
421  } elseif ($action == 'setretainedwarrantydatelimit' && $user->hasRight('facture', 'creer')) {
422  $object->fetch($id);
423  $result = $object->setRetainedWarrantyDateLimit(GETPOST('retained_warranty_date_limit', 'float'));
424  if ($result < 0) {
425  dol_print_error($db, $object->error);
426  }
427  } elseif ($action == 'setmulticurrencycode' && $usercancreate) { // Multicurrency Code
428  $result = $object->setMulticurrencyCode(GETPOST('multicurrency_code', 'alpha'));
429  } elseif ($action == 'setmulticurrencyrate' && $usercancreate) { // Multicurrency rate
430  $result = $object->setMulticurrencyRate(price2num(GETPOST('multicurrency_tx')), GETPOST('calculation_mode', 'int'));
431  } elseif ($action == 'setinvoicedate' && $usercancreate) {
432  $object->fetch($id);
433  $old_date_lim_reglement = $object->date_lim_reglement;
434  $newdate = dol_mktime(0, 0, 0, GETPOST('invoicedatemonth', 'int'), GETPOST('invoicedateday', 'int'), GETPOST('invoicedateyear', 'int'), 'tzserver');
435  if (empty($newdate)) {
436  setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("Date")), null, 'errors');
437  header('Location: '.$_SERVER["PHP_SELF"].'?facid='.$id.'&action=editinvoicedate&token='.newToken());
438  exit;
439  }
440  if ($newdate > (dol_now('tzuserrel') + (empty($conf->global->INVOICE_MAX_FUTURE_DELAY) ? 0 : $conf->global->INVOICE_MAX_FUTURE_DELAY))) {
441  if (empty($conf->global->INVOICE_MAX_FUTURE_DELAY)) {
442  setEventMessages($langs->trans("WarningInvoiceDateInFuture"), null, 'warnings');
443  } else {
444  setEventMessages($langs->trans("WarningInvoiceDateTooFarInFuture"), null, 'warnings');
445  }
446  }
447 
448  $object->date = $newdate;
449  $new_date_lim_reglement = $object->calculate_date_lim_reglement();
450  if ($new_date_lim_reglement > $old_date_lim_reglement) {
451  $object->date_lim_reglement = $new_date_lim_reglement;
452  }
453  if ($object->date_lim_reglement < $object->date) {
454  $object->date_lim_reglement = $object->date;
455  }
456  $result = $object->update($user);
457  if ($result < 0) {
458  dol_print_error($db, $object->error);
459  }
460  } elseif ($action == 'setdate_pointoftax' && $usercancreate) {
461  $object->fetch($id);
462 
463  $date_pointoftax = dol_mktime(0, 0, 0, GETPOST('date_pointoftaxmonth', 'int'), GETPOST('date_pointoftaxday', 'int'), GETPOST('date_pointoftaxyear', 'int'), 'tzserver');
464 
465  $object->date_pointoftax = $date_pointoftax;
466  $result = $object->update($user);
467  if ($result < 0) {
468  dol_print_error($db, $object->error);
469  }
470  } elseif ($action == 'setconditions' && $usercancreate) {
471  $object->fetch($id);
472  $object->cond_reglement_code = 0; // To clean property
473  $object->cond_reglement_id = 0; // To clean property
474 
475  $error = 0;
476 
477  $db->begin();
478 
479  if (!$error) {
480  $result = $object->setPaymentTerms(GETPOST('cond_reglement_id', 'int'));
481  if ($result < 0) {
482  $error++;
483  setEventMessages($object->error, $object->errors, 'errors');
484  }
485  }
486 
487  if (!$error) {
488  $old_date_lim_reglement = $object->date_lim_reglement;
489  $new_date_lim_reglement = $object->calculate_date_lim_reglement();
490  if ($new_date_lim_reglement > $old_date_lim_reglement) {
491  $object->date_lim_reglement = $new_date_lim_reglement;
492  }
493  if ($object->date_lim_reglement < $object->date) {
494  $object->date_lim_reglement = $object->date;
495  }
496  $result = $object->update($user);
497  if ($result < 0) {
498  $error++;
499  setEventMessages($object->error, $object->errors, 'errors');
500  }
501  }
502 
503  if ($error) {
504  $db->rollback();
505  } else {
506  $db->commit();
507  }
508  } elseif ($action == 'setpaymentterm' && $usercancreate) {
509  $object->fetch($id);
510  $object->date_lim_reglement = dol_mktime(12, 0, 0, GETPOST('paymenttermmonth', 'int'), GETPOST('paymenttermday', 'int'), GETPOST('paymenttermyear', 'int'));
511  if ($object->date_lim_reglement < $object->date) {
512  $object->date_lim_reglement = $object->calculate_date_lim_reglement();
513  setEventMessages($langs->trans("DatePaymentTermCantBeLowerThanObjectDate"), null, 'warnings');
514  }
515  $result = $object->update($user);
516  if ($result < 0) {
517  dol_print_error($db, $object->error);
518  }
519  } elseif ($action == 'setrevenuestamp' && $usercancreate) {
520  $object->fetch($id);
521  $object->revenuestamp = GETPOST('revenuestamp');
522  $result = $object->update($user);
523  $object->update_price(1);
524  if ($result < 0) {
525  dol_print_error($db, $object->error);
526  } else {
527  // Define output language
528  if (empty($conf->global->MAIN_DISABLE_PDF_AUTOUPDATE)) {
529  $outputlangs = $langs;
530  $newlang = '';
531  if (getDolGlobalInt('MAIN_MULTILANGS') && empty($newlang) && GETPOST('lang_id', 'aZ09')) {
532  $newlang = GETPOST('lang_id', 'aZ09');
533  }
534  if (getDolGlobalInt('MAIN_MULTILANGS') && empty($newlang)) {
535  $newlang = $object->thirdparty->default_lang;
536  }
537  if (!empty($newlang)) {
538  $outputlangs = new Translate("", $conf);
539  $outputlangs->setDefaultLang($newlang);
540  $outputlangs->load('products');
541  }
542  $model = $object->model_pdf;
543  $ret = $object->fetch($id); // Reload to get new records
544 
545  $result = $object->generateDocument($model, $outputlangs, $hidedetails, $hidedesc, $hideref);
546  if ($result < 0) {
547  setEventMessages($object->error, $object->errors, 'errors');
548  }
549  }
550  }
551  } elseif ($action == 'set_incoterms' && isModEnabled('incoterm')) { // Set incoterm
552  $result = $object->setIncoterms(GETPOST('incoterm_id', 'int'), GETPOST('location_incoterms', 'alpha'));
553  } elseif ($action == 'setbankaccount' && $usercancreate) { // bank account
554  $result = $object->setBankAccount(GETPOST('fk_account', 'int'));
555  } elseif ($action == 'setremisepercent' && $usercancreate) {
556  $object->fetch($id);
557  $result = $object->setDiscount($user, price2num(GETPOST('remise_percent'), '', 2));
558  } elseif ($action == "setabsolutediscount" && $usercancreate) {
559  // We have POST[remise_id] or POST[remise_id_for_payment]
560  $db->begin();
561 
562  // We use the credit to reduce amount of invoice
563  if (GETPOST("remise_id", 'int') > 0) {
564  $ret = $object->fetch($id);
565  if ($ret > 0) {
566  $result = $object->insert_discount(GETPOST("remise_id", 'int'));
567  if ($result < 0) {
568  setEventMessages($object->error, $object->errors, 'errors');
569  }
570  } else {
571  $error++;
572  setEventMessages($object->error, $object->errors, 'errors');
573  }
574  }
575  // We use the credit to reduce remain to pay
576  if (GETPOST("remise_id_for_payment", 'int') > 0) {
577  require_once DOL_DOCUMENT_ROOT.'/core/class/discount.class.php';
578  $discount = new DiscountAbsolute($db);
579  $discount->fetch(GETPOST("remise_id_for_payment", 'int'));
580 
581  //var_dump($object->getRemainToPay(0));
582  //var_dump($discount->amount_ttc);exit;
583  $remaintopay = $object->getRemainToPay(0);
584  if (price2num($discount->amount_ttc) > price2num($remaintopay)) {
585  // TODO Split the discount in 2 automatically
586  $error++;
587  setEventMessages($langs->trans("ErrorDiscountLargerThanRemainToPaySplitItBefore"), null, 'errors');
588  }
589 
590  if (!$error) {
591  $result = $discount->link_to_invoice(0, $id);
592  if ($result < 0) {
593  $error++;
594  setEventMessages($discount->error, $discount->errors, 'errors');
595  }
596  }
597 
598  if (!$error) {
599  $newremaintopay = $object->getRemainToPay(0);
600  if ($newremaintopay == 0) {
601  $object->setPaid($user);
602  }
603  }
604  }
605 
606  if (!$error) {
607  $db->commit();
608  } else {
609  $db->rollback();
610  }
611 
612  if (empty($error) && empty($conf->global->MAIN_DISABLE_PDF_AUTOUPDATE)) {
613  $outputlangs = $langs;
614  $newlang = '';
615  if (getDolGlobalInt('MAIN_MULTILANGS') && empty($newlang) && GETPOST('lang_id', 'aZ09')) {
616  $newlang = GETPOST('lang_id', 'aZ09');
617  }
618  if (getDolGlobalInt('MAIN_MULTILANGS') && empty($newlang)) {
619  $newlang = $object->thirdparty->default_lang;
620  }
621  if (!empty($newlang)) {
622  $outputlangs = new Translate("", $conf);
623  $outputlangs->setDefaultLang($newlang);
624  }
625  $ret = $object->fetch($id); // Reload to get new records
626 
627  $result = $object->generateDocument($object->model_pdf, $outputlangs, $hidedetails, $hidedesc, $hideref);
628  if ($result < 0) {
629  setEventMessages($object->error, $object->errors, 'errors');
630  }
631  }
632  } elseif ($action == 'setref' && $usercancreate) {
633  $object->fetch($id);
634  $object->setValueFrom('ref', GETPOST('ref'), '', null, '', '', $user, 'BILL_MODIFY');
635  } elseif ($action == 'setref_client' && $usercancreate) {
636  $object->fetch($id);
637  $object->set_ref_client(GETPOST('ref_client'));
638  } elseif ($action == 'confirm_valid' && $confirm == 'yes' && $usercanvalidate) {
639  // Classify to validated
640  $idwarehouse = GETPOST('idwarehouse', 'int');
641 
642  $object->fetch($id);
643  $object->fetch_thirdparty();
644 
645  // Check for warehouse
646  if ($object->type != Facture::TYPE_DEPOSIT && !empty($conf->global->STOCK_CALCULATE_ON_BILL)) {
647  $qualified_for_stock_change = 0;
648  if (empty($conf->global->STOCK_SUPPORTS_SERVICES)) {
649  $qualified_for_stock_change = $object->hasProductsOrServices(2);
650  } else {
651  $qualified_for_stock_change = $object->hasProductsOrServices(1);
652  }
653 
654  if ($qualified_for_stock_change) {
655  if (!$idwarehouse || $idwarehouse == - 1) {
656  $error++;
657  setEventMessages($langs->trans('ErrorFieldRequired', $langs->transnoentitiesnoconv("Warehouse")), null, 'errors');
658  $action = '';
659  }
660  }
661  }
662 
663  if (!$error) {
664  $result = $object->validate($user, '', $idwarehouse);
665  if ($result >= 0) {
666  // Define output language
667  if (empty($conf->global->MAIN_DISABLE_PDF_AUTOUPDATE)) {
668  $outputlangs = $langs;
669  $newlang = '';
670  if (getDolGlobalInt('MAIN_MULTILANGS') && empty($newlang) && GETPOST('lang_id', 'aZ09')) {
671  $newlang = GETPOST('lang_id', 'aZ09');
672  }
673  if (getDolGlobalInt('MAIN_MULTILANGS') && empty($newlang)) {
674  $newlang = $object->thirdparty->default_lang;
675  }
676  if (!empty($newlang)) {
677  $outputlangs = new Translate("", $conf);
678  $outputlangs->setDefaultLang($newlang);
679  $outputlangs->load('products');
680  }
681  $model = $object->model_pdf;
682 
683  $ret = $object->fetch($id); // Reload to get new records
684 
685  $result = $object->generateDocument($model, $outputlangs, $hidedetails, $hidedesc, $hideref);
686  if ($result < 0) {
687  setEventMessages($object->error, $object->errors, 'errors');
688  }
689  }
690  } else {
691  if (count($object->errors)) {
692  setEventMessages(null, $object->errors, 'errors');
693  } else {
694  setEventMessages($object->error, $object->errors, 'errors');
695  }
696  }
697  }
698  } elseif ($action == 'confirm_modif' && $usercanunvalidate) {
699  // Go back to draft status (unvalidate)
700  $idwarehouse = GETPOST('idwarehouse', 'int');
701 
702  $object->fetch($id);
703  $object->fetch_thirdparty();
704 
705  // Check parameters
706  if ($object->type != Facture::TYPE_DEPOSIT && !empty($conf->global->STOCK_CALCULATE_ON_BILL)) {
707  $qualified_for_stock_change = 0;
708  if (empty($conf->global->STOCK_SUPPORTS_SERVICES)) {
709  $qualified_for_stock_change = $object->hasProductsOrServices(2);
710  } else {
711  $qualified_for_stock_change = $object->hasProductsOrServices(1);
712  }
713 
714  if ($qualified_for_stock_change) {
715  if (!$idwarehouse || $idwarehouse == - 1) {
716  $error++;
717  setEventMessages($langs->trans('ErrorFieldRequired', $langs->transnoentitiesnoconv("Warehouse")), null, 'errors');
718  $action = '';
719  }
720  }
721  }
722 
723  if (!$error) {
724  // We check if invoice has payments
725  $sql = 'SELECT pf.amount';
726  $sql .= ' FROM '.MAIN_DB_PREFIX.'paiement_facture as pf';
727  $sql .= ' WHERE pf.fk_facture = '.((int) $object->id);
728 
729  $result = $db->query($sql);
730  if ($result) {
731  $i = 0;
732  $num = $db->num_rows($result);
733 
734  while ($i < $num) {
735  $objp = $db->fetch_object($result);
736  $totalpaid += $objp->amount;
737  $i++;
738  }
739  } else {
740  dol_print_error($db, '');
741  }
742 
743  $resteapayer = $object->total_ttc - $totalpaid;
744 
745  // We check that invlice lines are transferred into accountancy
746  $ventilExportCompta = $object->getVentilExportCompta();
747 
748  // On verifie si aucun paiement n'a ete effectue
749  if ($ventilExportCompta == 0) {
750  if (!empty($conf->global->INVOICE_CAN_BE_EDITED_EVEN_IF_PAYMENT_DONE) || ($resteapayer == $object->total_ttc && empty($object->paye))) {
751  $result = $object->setDraft($user, $idwarehouse);
752  if ($result < 0) {
753  setEventMessages($object->error, $object->errors, 'errors');
754  }
755 
756  // Define output language
757  if (empty($conf->global->MAIN_DISABLE_PDF_AUTOUPDATE)) {
758  $outputlangs = $langs;
759  $newlang = '';
760  if (getDolGlobalInt('MAIN_MULTILANGS') && empty($newlang) && GETPOST('lang_id', 'aZ09')) {
761  $newlang = GETPOST('lang_id', 'aZ09');
762  }
763  if (getDolGlobalInt('MAIN_MULTILANGS') && empty($newlang)) {
764  $newlang = $object->thirdparty->default_lang;
765  }
766  if (!empty($newlang)) {
767  $outputlangs = new Translate("", $conf);
768  $outputlangs->setDefaultLang($newlang);
769  $outputlangs->load('products');
770  }
771  $model = $object->model_pdf;
772  $ret = $object->fetch($id); // Reload to get new records
773 
774  $object->generateDocument($model, $outputlangs, $hidedetails, $hidedesc, $hideref);
775  }
776  }
777  }
778  }
779  } elseif ($action == 'confirm_paid' && $confirm == 'yes' && $usercanissuepayment) {
780  // Classify "paid"
781  $object->fetch($id);
782  $result = $object->setPaid($user);
783  if ($result < 0) {
784  setEventMessages($object->error, $object->errors, 'errors');
785  }
786  } elseif ($action == 'confirm_paid_partially' && $confirm == 'yes' && $usercanissuepayment) {
787  // Classif "paid partialy"
788  $object->fetch($id);
789  $close_code = GETPOST("close_code", 'restricthtml');
790  $close_note = GETPOST("close_note", 'restricthtml');
791  if ($close_code) {
792  $result = $object->setPaid($user, $close_code, $close_note);
793  if ($result < 0) {
794  setEventMessages($object->error, $object->errors, 'errors');
795  }
796  } else {
797  setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("Reason")), null, 'errors');
798  }
799  } elseif ($action == 'confirm_canceled' && $confirm == 'yes') {
800  // Classify "abandoned"
801  $object->fetch($id);
802  $close_code = GETPOST("close_code", 'restricthtml');
803  $close_note = GETPOST("close_note", 'restricthtml');
804  if ($close_code) {
805  $result = $object->setCanceled($user, $close_code, $close_note);
806  if ($result < 0) {
807  setEventMessages($object->error, $object->errors, 'errors');
808  }
809  } else {
810  setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("Reason")), null, 'errors');
811  }
812  } elseif ($action == 'confirm_converttoreduc' && $confirm == 'yes' && $usercancreate) {
813  // Convertir en reduc
814  $object->fetch($id);
815  $object->fetch_thirdparty();
816  //$object->fetch_lines(); // Already done into fetch
817 
818  // Check if there is already a discount (protection to avoid duplicate creation when resubmit post)
819  $discountcheck = new DiscountAbsolute($db);
820  $result = $discountcheck->fetch(0, $object->id);
821 
822  $canconvert = 0;
823  if ($object->type == Facture::TYPE_DEPOSIT && empty($discountcheck->id)) {
824  $canconvert = 1; // we can convert deposit into discount if deposit is payed (completely, partially or not at all) and not already converted (see real condition into condition used to show button converttoreduc)
825  }
826  if (($object->type == Facture::TYPE_CREDIT_NOTE || $object->type == Facture::TYPE_STANDARD || $object->type == Facture::TYPE_SITUATION) && $object->paye == 0 && empty($discountcheck->id)) {
827  $canconvert = 1; // we can convert credit note into discount if credit note is not payed back and not already converted and amount of payment is 0 (see real condition into condition used to show button converttoreduc)
828  }
829 
830  if ($canconvert) {
831  $db->begin();
832 
833  $amount_ht = $amount_tva = $amount_ttc = array();
834  $multicurrency_amount_ht = $multicurrency_amount_tva = $multicurrency_amount_ttc = array();
835 
836  // Loop on each vat rate
837  $i = 0;
838  foreach ($object->lines as $line) {
839  if ($line->product_type < 9 && $line->total_ht != 0) { // Remove lines with product_type greater than or equal to 9 and no need to create discount if amount is null
840  $keyforvatrate = $line->tva_tx.($line->vat_src_code ? ' ('.$line->vat_src_code.')' : '');
841 
842  $amount_ht[$keyforvatrate] += $line->total_ht;
843  $amount_tva[$keyforvatrate] += $line->total_tva;
844  $amount_ttc[$keyforvatrate] += $line->total_ttc;
845  $multicurrency_amount_ht[$keyforvatrate] += $line->multicurrency_total_ht;
846  $multicurrency_amount_tva[$keyforvatrate] += $line->multicurrency_total_tva;
847  $multicurrency_amount_ttc[$keyforvatrate] += $line->multicurrency_total_ttc;
848  $i++;
849  }
850  }
851 
852  // If some payments were already done, we change the amount to pay using same prorate
853  if (!empty($conf->global->INVOICE_ALLOW_REUSE_OF_CREDIT_WHEN_PARTIALLY_REFUNDED) && $object->type == Facture::TYPE_CREDIT_NOTE) {
854  $alreadypaid = $object->getSommePaiement(); // This can be not 0 if we allow to create credit to reuse from credit notes partially refunded.
855  if ($alreadypaid && abs($alreadypaid) < abs($object->total_ttc)) {
856  $ratio = abs(($object->total_ttc - $alreadypaid) / $object->total_ttc);
857  foreach ($amount_ht as $vatrate => $val) {
858  $amount_ht[$vatrate] = price2num($amount_ht[$vatrate] * $ratio, 'MU');
859  $amount_tva[$vatrate] = price2num($amount_tva[$vatrate] * $ratio, 'MU');
860  $amount_ttc[$vatrate] = price2num($amount_ttc[$vatrate] * $ratio, 'MU');
861  $multicurrency_amount_ht[$vatrate] = price2num($multicurrency_amount_ht[$vatrate] * $ratio, 'MU');
862  $multicurrency_amount_tva[$vatrate] = price2num($multicurrency_amount_tva[$vatrate] * $ratio, 'MU');
863  $multicurrency_amount_ttc[$vatrate] = price2num($multicurrency_amount_ttc[$vatrate] * $ratio, 'MU');
864  }
865  }
866  }
867  //var_dump($amount_ht);var_dump($amount_tva);var_dump($amount_ttc);exit;
868 
869  // Insert one discount by VAT rate category
870  $discount = new DiscountAbsolute($db);
871  if ($object->type == Facture::TYPE_CREDIT_NOTE) {
872  $discount->description = '(CREDIT_NOTE)';
873  } elseif ($object->type == Facture::TYPE_DEPOSIT) {
874  $discount->description = '(DEPOSIT)';
875  } elseif ($object->type == Facture::TYPE_STANDARD || $object->type == Facture::TYPE_REPLACEMENT || $object->type == Facture::TYPE_SITUATION) {
876  $discount->description = '(EXCESS RECEIVED)';
877  } else {
878  setEventMessages($langs->trans('CantConvertToReducAnInvoiceOfThisType'), null, 'errors');
879  }
880  $discount->fk_soc = $object->socid;
881  $discount->fk_facture_source = $object->id;
882 
883  $error = 0;
884 
885  if ($object->type == Facture::TYPE_STANDARD || $object->type == Facture::TYPE_REPLACEMENT || $object->type == Facture::TYPE_SITUATION) {
886  // If we're on a standard invoice, we have to get excess received to create a discount in TTC without VAT
887 
888  // Total payments
889  $sql = 'SELECT SUM(pf.amount) as total_paiements';
890  $sql .= ' FROM '.MAIN_DB_PREFIX.'paiement_facture as pf, '.MAIN_DB_PREFIX.'paiement as p';
891  $sql .= ' LEFT JOIN '.MAIN_DB_PREFIX.'c_paiement as c ON p.fk_paiement = c.id';
892  $sql .= ' WHERE pf.fk_facture = '.((int) $object->id);
893  $sql .= ' AND pf.fk_paiement = p.rowid';
894  $sql .= ' AND p.entity IN ('.getEntity('invoice').')';
895  $resql = $db->query($sql);
896  if (!$resql) {
897  dol_print_error($db);
898  }
899 
900  $res = $db->fetch_object($resql);
901  $total_paiements = $res->total_paiements;
902 
903  // Total credit note and deposit
904  $total_creditnote_and_deposit = 0;
905  $sql = "SELECT re.rowid, re.amount_ht, re.amount_tva, re.amount_ttc,";
906  $sql .= " re.description, re.fk_facture_source";
907  $sql .= " FROM ".MAIN_DB_PREFIX."societe_remise_except as re";
908  $sql .= " WHERE fk_facture = ".((int) $object->id);
909  $resql = $db->query($sql);
910  if (!empty($resql)) {
911  while ($obj = $db->fetch_object($resql)) {
912  $total_creditnote_and_deposit += $obj->amount_ttc;
913  }
914  } else {
915  dol_print_error($db);
916  }
917 
918  $discount->amount_ht = $discount->amount_ttc = $total_paiements + $total_creditnote_and_deposit - $object->total_ttc;
919  $discount->amount_tva = 0;
920  $discount->tva_tx = 0;
921  $discount->vat_src_code = '';
922 
923  $result = $discount->create($user);
924  if ($result < 0) {
925  $error++;
926  }
927  }
928  if ($object->type == Facture::TYPE_CREDIT_NOTE || $object->type == Facture::TYPE_DEPOSIT) {
929  foreach ($amount_ht as $tva_tx => $xxx) {
930  $discount->amount_ht = abs($amount_ht[$tva_tx]);
931  $discount->amount_tva = abs($amount_tva[$tva_tx]);
932  $discount->amount_ttc = abs($amount_ttc[$tva_tx]);
933  $discount->multicurrency_amount_ht = abs($multicurrency_amount_ht[$tva_tx]);
934  $discount->multicurrency_amount_tva = abs($multicurrency_amount_tva[$tva_tx]);
935  $discount->multicurrency_amount_ttc = abs($multicurrency_amount_ttc[$tva_tx]);
936 
937  // Clean vat code
938  $reg = array();
939  $vat_src_code = '';
940  if (preg_match('/\‍((.*)\‍)/', $tva_tx, $reg)) {
941  $vat_src_code = $reg[1];
942  $tva_tx = preg_replace('/\s*\‍(.*\‍)/', '', $tva_tx); // Remove code into vatrate.
943  }
944 
945  $discount->tva_tx = abs($tva_tx);
946  $discount->vat_src_code = $vat_src_code;
947 
948  $result = $discount->create($user);
949  if ($result < 0) {
950  $error++;
951  break;
952  }
953  }
954  }
955 
956  if (empty($error)) {
957  if ($object->type != Facture::TYPE_DEPOSIT) {
958  // Classe facture
959  $result = $object->setPaid($user);
960  if ($result >= 0) {
961  $db->commit();
962  } else {
963  setEventMessages($object->error, $object->errors, 'errors');
964  $db->rollback();
965  }
966  } else {
967  $db->commit();
968  }
969  } else {
970  setEventMessages($discount->error, $discount->errors, 'errors');
971  $db->rollback();
972  }
973  }
974  } elseif ($action == 'confirm_delete_paiement' && $confirm == 'yes' && $usercanissuepayment) {
975  // Delete payment
976  $object->fetch($id);
977  if ($object->statut == Facture::STATUS_VALIDATED && $object->paye == 0) {
978  $paiement = new Paiement($db);
979  $result = $paiement->fetch(GETPOST('paiement_id', 'int'));
980  if ($result > 0) {
981  $result = $paiement->delete(); // If fetch ok and found
982  if ($result >= 0) {
983  header("Location: ".$_SERVER['PHP_SELF']."?id=".$id);
984  exit;
985  }
986  }
987  if ($result < 0) {
988  setEventMessages($paiement->error, $paiement->errors, 'errors');
989  }
990  }
991  } elseif ($action == 'add' && $usercancreate) {
992  // Insert new invoice in database
993  if ($socid > 0) {
994  $object->socid = GETPOST('socid', 'int');
995  }
996  $selectedLines = GETPOST('toselect', 'array');
997 
998  if (GETPOST('type', 'int') === '') {
999  setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("Type")), null, 'errors');
1000  }
1001 
1002  $db->begin();
1003 
1004  $error = 0;
1005  $originentity = GETPOST('originentity');
1006  // Fill array 'array_options' with data from add form
1007  $ret = $extrafields->setOptionalsFromPost(null, $object);
1008  if ($ret < 0) {
1009  $error++;
1010  }
1011 
1012  $dateinvoice = dol_mktime(0, 0, 0, GETPOST('remonth', 'int'), GETPOST('reday', 'int'), GETPOST('reyear', 'int'), 'tzserver'); // If we enter the 02 january, we need to save the 02 january for server
1013  $date_pointoftax = dol_mktime(0, 0, 0, GETPOST('date_pointoftaxmonth', 'int'), GETPOST('date_pointoftaxday', 'int'), GETPOST('date_pointoftaxyear', 'int'), 'tzserver');
1014 
1015  // Replacement invoice
1016  if (GETPOST('type') == Facture::TYPE_REPLACEMENT) {
1017  if (empty($dateinvoice)) {
1018  $error++;
1019  setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("Date")), null, 'errors');
1020  $action = 'create';
1021  } elseif ($dateinvoice > (dol_get_last_hour(dol_now('tzuserrel')) + (empty($conf->global->INVOICE_MAX_FUTURE_DELAY) ? 0 : $conf->global->INVOICE_MAX_FUTURE_DELAY))) {
1022  $error++;
1023  setEventMessages($langs->trans("ErrorDateIsInFuture"), null, 'errors');
1024  $action = 'create';
1025  }
1026 
1027  if (!(GETPOST('fac_replacement', 'int') > 0)) {
1028  $error++;
1029  setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("ReplaceInvoice")), null, 'errors');
1030  $action = 'create';
1031  }
1032 
1033  if (!$error) {
1034  // This is a replacement invoice
1035  $result = $object->fetch(GETPOST('fac_replacement', 'int'));
1036  $object->fetch_thirdparty();
1037 
1038  $object->date = $dateinvoice;
1039  $object->date_pointoftax = $date_pointoftax;
1040  $object->note_public = trim(GETPOST('note_public', 'restricthtml'));
1041  $object->note_private = trim(GETPOST('note_private', 'restricthtml'));
1042  $object->ref_client = GETPOST('ref_client', 'alphanohtml');
1043  $object->model_pdf = GETPOST('model', 'alphanohtml');
1044  $object->fk_project = GETPOST('projectid', 'int');
1045  $object->cond_reglement_id = GETPOST('cond_reglement_id', 'int');
1046  $object->mode_reglement_id = GETPOST('mode_reglement_id', 'int');
1047  $object->fk_account = GETPOST('fk_account', 'int');
1048  $object->remise_absolue = price2num(GETPOST('remise_absolue'), 'MU', 2);
1049  $object->remise_percent = price2num(GETPOST('remise_percent'), '', 2);
1050  $object->fk_incoterms = GETPOST('incoterm_id', 'int');
1051  $object->location_incoterms = GETPOST('location_incoterms', 'alpha');
1052  $object->multicurrency_code = GETPOST('multicurrency_code', 'alpha');
1053  $object->multicurrency_tx = GETPOST('originmulticurrency_tx', 'int');
1054 
1055  // Proprietes particulieres a facture de remplacement
1056  $object->fk_facture_source = GETPOST('fac_replacement', 'int');
1057  $object->type = Facture::TYPE_REPLACEMENT;
1058 
1059  $id = $object->createFromCurrent($user);
1060  if ($id <= 0) {
1061  setEventMessages($object->error, $object->errors, 'errors');
1062  }
1063  }
1064  }
1065 
1066  // Credit note invoice
1067  if (GETPOST('type') == Facture::TYPE_CREDIT_NOTE) {
1068  $sourceinvoice = GETPOST('fac_avoir', 'int');
1069  if (!($sourceinvoice > 0) && empty($conf->global->INVOICE_CREDIT_NOTE_STANDALONE)) {
1070  $error++;
1071  setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("CorrectInvoice")), null, 'errors');
1072  $action = 'create';
1073  }
1074 
1075  if (empty($dateinvoice)) {
1076  $error++;
1077  setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("Date")), null, 'errors');
1078  $action = 'create';
1079  } elseif ($dateinvoice > (dol_get_last_hour(dol_now('tzuserrel')) + (empty($conf->global->INVOICE_MAX_FUTURE_DELAY) ? 0 : $conf->global->INVOICE_MAX_FUTURE_DELAY))) {
1080  $error++;
1081  setEventMessages($langs->trans("ErrorDateIsInFuture"), null, 'errors');
1082  $action = 'create';
1083  }
1084 
1085  if (!$error) {
1086  if (!empty($originentity)) {
1087  $object->entity = $originentity;
1088  }
1089  $object->socid = GETPOST('socid', 'int');
1090  $object->ref = GETPOST('ref');
1091  $object->date = $dateinvoice;
1092  $object->date_pointoftax = $date_pointoftax;
1093  $object->note_public = trim(GETPOST('note_public', 'restricthtml'));
1094  $object->note_private = trim(GETPOST('note_private', 'restricthtml'));
1095  $object->ref_client = GETPOST('ref_client');
1096  $object->model_pdf = GETPOST('model');
1097  $object->fk_project = GETPOST('projectid', 'int');
1098  $object->cond_reglement_id = 0; // No payment term for a credit note
1099  $object->mode_reglement_id = GETPOST('mode_reglement_id', 'int');
1100  $object->fk_account = GETPOST('fk_account', 'int');
1101  $object->remise_absolue = price2num(GETPOST('remise_absolue'), 'MU');
1102  $object->remise_percent = price2num(GETPOST('remise_percent'), '', 2);
1103  $object->fk_incoterms = GETPOST('incoterm_id', 'int');
1104  $object->location_incoterms = GETPOST('location_incoterms', 'alpha');
1105  $object->multicurrency_code = GETPOST('multicurrency_code', 'alpha');
1106  $object->multicurrency_tx = GETPOST('originmulticurrency_tx', 'int');
1107 
1108  // Proprietes particulieres a facture avoir
1109  $object->fk_facture_source = $sourceinvoice > 0 ? $sourceinvoice : '';
1110  $object->type = Facture::TYPE_CREDIT_NOTE;
1111 
1112  $facture_source = new Facture($db); // fetch origin object
1113  if ($facture_source->fetch($object->fk_facture_source) > 0) {
1114  if ($facture_source->type == Facture::TYPE_SITUATION) {
1115  $object->situation_counter = $facture_source->situation_counter;
1116  $object->situation_cycle_ref = $facture_source->situation_cycle_ref;
1117  $facture_source->fetchPreviousNextSituationInvoice();
1118  }
1119  }
1120 
1121 
1122  $id = $object->create($user);
1123  if ($id < 0) {
1124  $error++;
1125  } else {
1126  // copy internal contacts
1127  if ($object->copy_linked_contact($facture_source, 'internal') < 0) {
1128  $error++;
1129  } elseif ($facture_source->socid == $object->socid) {
1130  // copy external contacts if same company
1131  if ($object->copy_linked_contact($facture_source, 'external') < 0) {
1132  $error++;
1133  }
1134  }
1135  }
1136 
1137  // NOTE: Pb with situation invoice
1138  // NOTE: fields total on situation invoice are stored as cumulative values on total of lines (bad) but delta on invoice total
1139  // NOTE: fields total on credit note are stored as delta both on total of lines and on invoice total (good)
1140  // NOTE: fields situation_percent on situation invoice are stored as cumulative values on lines (bad)
1141  // NOTE: fields situation_percent on credit note are stored as delta on lines (good)
1142  if (GETPOST('invoiceAvoirWithLines', 'int') == 1 && $id > 0) {
1143  if (!empty($facture_source->lines)) {
1144  $fk_parent_line = 0;
1145 
1146  foreach ($facture_source->lines as $line) {
1147  // Extrafields
1148  if (method_exists($line, 'fetch_optionals')) {
1149  // load extrafields
1150  $line->fetch_optionals();
1151  }
1152 
1153  // Reset fk_parent_line for no child products and special product
1154  if (($line->product_type != 9 && empty($line->fk_parent_line)) || $line->product_type == 9) {
1155  $fk_parent_line = 0;
1156  }
1157 
1158 
1159  if ($facture_source->type == Facture::TYPE_SITUATION) {
1160  $source_fk_prev_id = $line->fk_prev_id; // temporary storing situation invoice fk_prev_id
1161  $line->fk_prev_id = $line->id; // The new line of the new credit note we are creating must be linked to the situation invoice line it is created from
1162 
1163  if (!empty($facture_source->tab_previous_situation_invoice)) {
1164  // search the last standard invoice in cycle and the possible credit note between this last and facture_source
1165  // TODO Move this out of loop of $facture_source->lines
1166  $tab_jumped_credit_notes = array();
1167  $lineIndex = count($facture_source->tab_previous_situation_invoice) - 1;
1168  $searchPreviousInvoice = true;
1169  while ($searchPreviousInvoice) {
1170  if ($facture_source->tab_previous_situation_invoice[$lineIndex]->type == Facture::TYPE_SITUATION || $lineIndex < 1) {
1171  $searchPreviousInvoice = false; // find, exit;
1172  break;
1173  } else {
1174  if ($facture_source->tab_previous_situation_invoice[$lineIndex]->type == Facture::TYPE_CREDIT_NOTE) {
1175  $tab_jumped_credit_notes[$lineIndex] = $facture_source->tab_previous_situation_invoice[$lineIndex]->id;
1176  }
1177  $lineIndex--; // go to previous invoice in cycle
1178  }
1179  }
1180 
1181  $maxPrevSituationPercent = 0;
1182  foreach ($facture_source->tab_previous_situation_invoice[$lineIndex]->lines as $prevLine) {
1183  if ($prevLine->id == $source_fk_prev_id) {
1184  $maxPrevSituationPercent = max($maxPrevSituationPercent, $prevLine->situation_percent);
1185 
1186  //$line->subprice = $line->subprice - $prevLine->subprice;
1187  $line->total_ht = $line->total_ht - $prevLine->total_ht;
1188  $line->total_tva = $line->total_tva - $prevLine->total_tva;
1189  $line->total_ttc = $line->total_ttc - $prevLine->total_ttc;
1190  $line->total_localtax1 = $line->total_localtax1 - $prevLine->total_localtax1;
1191  $line->total_localtax2 = $line->total_localtax2 - $prevLine->total_localtax2;
1192 
1193  $line->multicurrency_subprice = $line->multicurrency_subprice - $prevLine->multicurrency_subprice;
1194  $line->multicurrency_total_ht = $line->multicurrency_total_ht - $prevLine->multicurrency_total_ht;
1195  $line->multicurrency_total_tva = $line->multicurrency_total_tva - $prevLine->multicurrency_total_tva;
1196  $line->multicurrency_total_ttc = $line->multicurrency_total_ttc - $prevLine->multicurrency_total_ttc;
1197  }
1198  }
1199 
1200  // prorata
1201  $line->situation_percent = $maxPrevSituationPercent - $line->situation_percent;
1202 
1203  //print 'New line based on invoice id '.$facture_source->tab_previous_situation_invoice[$lineIndex]->id.' fk_prev_id='.$source_fk_prev_id.' will be fk_prev_id='.$line->fk_prev_id.' '.$line->total_ht.' '.$line->situation_percent.'<br>';
1204 
1205  // If there is some credit note between last situation invoice and invoice used for credit note generation (note: credit notes are stored as delta)
1206  $maxPrevSituationPercent = 0;
1207  foreach ($tab_jumped_credit_notes as $index => $creditnoteid) {
1208  foreach ($facture_source->tab_previous_situation_invoice[$index]->lines as $prevLine) {
1209  if ($prevLine->fk_prev_id == $source_fk_prev_id) {
1210  $maxPrevSituationPercent = $prevLine->situation_percent;
1211 
1212  $line->total_ht -= $prevLine->total_ht;
1213  $line->total_tva -= $prevLine->total_tva;
1214  $line->total_ttc -= $prevLine->total_ttc;
1215  $line->total_localtax1 -= $prevLine->total_localtax1;
1216  $line->total_localtax2 -= $prevLine->total_localtax2;
1217 
1218  $line->multicurrency_subprice -= $prevLine->multicurrency_subprice;
1219  $line->multicurrency_total_ht -= $prevLine->multicurrency_total_ht;
1220  $line->multicurrency_total_tva -= $prevLine->multicurrency_total_tva;
1221  $line->multicurrency_total_ttc -= $prevLine->multicurrency_total_ttc;
1222  }
1223  }
1224  }
1225 
1226  // prorata
1227  $line->situation_percent += $maxPrevSituationPercent;
1228 
1229  //print 'New line based on invoice id '.$facture_source->tab_previous_situation_invoice[$lineIndex]->id.' fk_prev_id='.$source_fk_prev_id.' will be fk_prev_id='.$line->fk_prev_id.' '.$line->total_ht.' '.$line->situation_percent.'<br>';
1230  }
1231  }
1232 
1233  $line->fk_facture = $object->id;
1234  $line->fk_parent_line = $fk_parent_line;
1235 
1236  $line->subprice = -$line->subprice; // invert price for object
1237  $line->pa_ht = $line->pa_ht; // we choosed to have buy/cost price always positive, so no revert of sign here
1238  $line->total_ht = -$line->total_ht;
1239  $line->total_tva = -$line->total_tva;
1240  $line->total_ttc = -$line->total_ttc;
1241  $line->total_localtax1 = -$line->total_localtax1;
1242  $line->total_localtax2 = -$line->total_localtax2;
1243 
1244  $line->multicurrency_subprice = -$line->multicurrency_subprice;
1245  $line->multicurrency_total_ht = -$line->multicurrency_total_ht;
1246  $line->multicurrency_total_tva = -$line->multicurrency_total_tva;
1247  $line->multicurrency_total_ttc = -$line->multicurrency_total_ttc;
1248 
1249  $line->context['createcreditnotefrominvoice'] = 1;
1250  $result = $line->insert(0, 1); // When creating credit note with same lines than source, we must ignore error if discount alreayd linked
1251 
1252  $object->lines[] = $line; // insert new line in current object
1253 
1254  // Defined the new fk_parent_line
1255  if ($result > 0 && $line->product_type == 9) {
1256  $fk_parent_line = $result;
1257  }
1258  }
1259 
1260  $object->update_price(1);
1261  }
1262  }
1263 
1264  if (GETPOST('invoiceAvoirWithPaymentRestAmount', 'int') == 1 && $id > 0) {
1265  if ($facture_source->fetch($object->fk_facture_source) > 0) {
1266  $totalpaid = $facture_source->getSommePaiement();
1267  $totalcreditnotes = $facture_source->getSumCreditNotesUsed();
1268  $totaldeposits = $facture_source->getSumDepositsUsed();
1269  $remain_to_pay = abs($facture_source->total_ttc - $totalpaid - $totalcreditnotes - $totaldeposits);
1270 
1271  $object->addline($langs->trans('invoiceAvoirLineWithPaymentRestAmount'), $remain_to_pay, 1, 0, 0, 0, 0, 0, '', '', 'TTC');
1272  }
1273  }
1274 
1275  // Add link between credit note and origin
1276  if (!empty($object->fk_facture_source) && $id > 0) {
1277  $facture_source->fetch($object->fk_facture_source);
1278  $facture_source->fetchObjectLinked();
1279 
1280  if (!empty($facture_source->linkedObjectsIds)) {
1281  foreach ($facture_source->linkedObjectsIds as $sourcetype => $TIds) {
1282  $object->add_object_linked($sourcetype, current($TIds));
1283  }
1284  }
1285  }
1286  }
1287  }
1288 
1289  // Standard invoice or Deposit invoice, created from a Predefined template invoice
1290  if ((GETPOST('type') == Facture::TYPE_STANDARD || GETPOST('type') == Facture::TYPE_DEPOSIT) && GETPOST('fac_rec', 'int') > 0) {
1291  if (empty($dateinvoice)) {
1292  $error++;
1293  setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("Date")), null, 'errors');
1294  $action = 'create';
1295  } elseif ($dateinvoice > (dol_get_last_hour(dol_now('tzuserrel')) + (empty($conf->global->INVOICE_MAX_FUTURE_DELAY) ? 0 : $conf->global->INVOICE_MAX_FUTURE_DELAY))) {
1296  $error++;
1297  setEventMessages($langs->trans("ErrorDateIsInFuture"), null, 'errors');
1298  $action = 'create';
1299  }
1300 
1301  if (!$error) {
1302  $object->socid = GETPOST('socid', 'int');
1303  $object->type = GETPOST('type');
1304  $object->ref = GETPOST('ref');
1305  $object->date = $dateinvoice;
1306  $object->date_pointoftax = $date_pointoftax;
1307  $object->note_public = trim(GETPOST('note_public', 'restricthtml'));
1308  $object->note_private = trim(GETPOST('note_private', 'restricthtml'));
1309  $object->ref_customer = GETPOST('ref_client');
1310  $object->ref_client = $object->ref_customer;
1311  $object->model_pdf = GETPOST('model');
1312  $object->fk_project = GETPOST('projectid', 'int');
1313  $object->cond_reglement_id = (GETPOST('type') == 3 ? 1 : GETPOST('cond_reglement_id'));
1314  $object->mode_reglement_id = GETPOST('mode_reglement_id', 'int');
1315  $object->fk_account = GETPOST('fk_account', 'int');
1316  $object->amount = price2num(GETPOST('amount'));
1317  $object->remise_absolue = price2num(GETPOST('remise_absolue'), 'MU');
1318  $object->remise_percent = price2num(GETPOST('remise_percent'), '', 2);
1319  $object->fk_incoterms = GETPOST('incoterm_id', 'int');
1320  $object->location_incoterms = GETPOST('location_incoterms', 'alpha');
1321  $object->multicurrency_code = GETPOST('multicurrency_code', 'alpha');
1322  $object->multicurrency_tx = GETPOST('originmulticurrency_tx', 'int');
1323 
1324  // Source facture
1325  $object->fac_rec = GETPOST('fac_rec', 'int');
1326 
1327  $id = $object->create($user); // This include recopy of links from recurring invoice and recurring invoice lines
1328  }
1329  }
1330 
1331  // Standard or deposit invoice, not from a Predefined template invoice
1332  if ((GETPOST('type') == Facture::TYPE_STANDARD || GETPOST('type') == Facture::TYPE_DEPOSIT || GETPOST('type') == Facture::TYPE_PROFORMA || (GETPOST('type') == Facture::TYPE_SITUATION && !GETPOST('situations'))) && GETPOST('fac_rec') <= 0) {
1333  $typeamount = GETPOST('typedeposit', 'aZ09');
1334  $valuestandardinvoice = price2num(str_replace('%', '', GETPOST('valuestandardinvoice', 'alpha')), 'MU');
1335  $valuedeposit = price2num(str_replace('%', '', GETPOST('valuedeposit', 'alpha')), 'MU');
1336 
1337  if (GETPOST('socid', 'int') < 1) {
1338  $error++;
1339  setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("Customer")), null, 'errors');
1340  $action = 'create';
1341  }
1342 
1343  if (empty($dateinvoice)) {
1344  $error++;
1345  setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("Date")), null, 'errors');
1346  $action = 'create';
1347  } elseif ($dateinvoice > (dol_get_last_hour(dol_now('tzuserrel')) + (empty($conf->global->INVOICE_MAX_FUTURE_DELAY) ? 0 : $conf->global->INVOICE_MAX_FUTURE_DELAY))) {
1348  $error++;
1349  setEventMessages($langs->trans("ErrorDateIsInFuture"), null, 'errors');
1350  $action = 'create';
1351  }
1352 
1353 
1354  if (GETPOST('type') == Facture::TYPE_STANDARD) {
1355  if ($valuestandardinvoice < 0 || $valuestandardinvoice > 100) {
1356  setEventMessages($langs->trans("ErrorAPercentIsRequired"), null, 'errors');
1357  $error++;
1358  $action = 'create';
1359  }
1360  } elseif (GETPOST('type') == Facture::TYPE_DEPOSIT) {
1361  if ($typeamount && !empty($origin) && !empty($originid)) {
1362  if ($typeamount == 'amount' && $valuedeposit <= 0) {
1363  setEventMessages($langs->trans("ErrorAnAmountWithoutTaxIsRequired"), null, 'errors');
1364  $error++;
1365  $action = 'create';
1366  }
1367  if ($typeamount == 'variable' && $valuedeposit <= 0) {
1368  setEventMessages($langs->trans("ErrorAPercentIsRequired"), null, 'errors');
1369  $error++;
1370  $action = 'create';
1371  }
1372  if ($typeamount == 'variablealllines' && $valuedeposit <= 0) {
1373  setEventMessages($langs->trans("ErrorAPercentIsRequired"), null, 'errors');
1374  $error++;
1375  $action = 'create';
1376  }
1377  }
1378  }
1379 
1380  if (!$error) {
1381  // Si facture standard
1382  $object->socid = GETPOST('socid', 'int');
1383  $object->type = GETPOST('type');
1384  $object->ref = GETPOST('ref');
1385  $object->date = $dateinvoice;
1386  $object->date_pointoftax = $date_pointoftax;
1387  $object->note_public = trim(GETPOST('note_public', 'restricthtml'));
1388  $object->note_private = trim(GETPOST('note_private', 'restricthtml'));
1389  $object->ref_client = GETPOST('ref_client');
1390  $object->ref_customer = GETPOST('ref_client');
1391  $object->model_pdf = GETPOST('model');
1392  $object->fk_project = GETPOST('projectid', 'int');
1393  $object->cond_reglement_id = (GETPOST('type') == 3 ? 1 : GETPOST('cond_reglement_id'));
1394  $object->mode_reglement_id = GETPOST('mode_reglement_id');
1395  $object->fk_account = GETPOST('fk_account', 'int');
1396  $object->amount = price2num(GETPOST('amount'));
1397  $object->remise_absolue = price2num(GETPOST('remise_absolue'), 'MU');
1398  $object->remise_percent = price2num(GETPOST('remise_percent'), '', 2);
1399  $object->fk_incoterms = GETPOST('incoterm_id', 'int');
1400  $object->location_incoterms = GETPOST('location_incoterms', 'alpha');
1401  $object->multicurrency_code = GETPOST('multicurrency_code', 'alpha');
1402  $object->multicurrency_tx = GETPOST('originmulticurrency_tx', 'int');
1403 
1404  if (GETPOST('type') == Facture::TYPE_SITUATION) {
1405  $object->situation_counter = 1;
1406  $object->situation_final = 0;
1407  $object->situation_cycle_ref = $object->newCycle();
1408  }
1409 
1410  if (in_array($object->type, $retainedWarrantyInvoiceAvailableType)) {
1411  $object->retained_warranty = GETPOST('retained_warranty', 'int');
1412  $object->retained_warranty_fk_cond_reglement = GETPOST('retained_warranty_fk_cond_reglement', 'int');
1413  } else {
1414  $object->retained_warranty = 0;
1415  $object->retained_warranty_fk_cond_reglement = 0;
1416  }
1417 
1418  $retained_warranty_date_limit = GETPOST('retained_warranty_date_limit');
1419  if (!empty($retained_warranty_date_limit) && dol_stringtotime($retained_warranty_date_limit)) {
1420  $object->retained_warranty_date_limit = dol_stringtotime($retained_warranty_date_limit);
1421  }
1422  $object->retained_warranty_date_limit = !empty($object->retained_warranty_date_limit) ? $object->retained_warranty_date_limit : $object->calculate_date_lim_reglement($object->retained_warranty_fk_cond_reglement);
1423 
1424  $object->fetch_thirdparty();
1425 
1426  // If creation from another object of another module (Example: origin=propal, originid=1)
1427  if (!empty($origin) && !empty($originid)) {
1428  $regs = array();
1429  // Parse element/subelement (ex: project_task)
1430  $element = $subelement = $origin;
1431  if (preg_match('/^([^_]+)_([^_]+)/i', $origin, $regs)) {
1432  $element = $regs[1];
1433  $subelement = $regs[2];
1434  }
1435 
1436  // For compatibility
1437  if ($element == 'order') {
1438  $element = $subelement = 'commande';
1439  }
1440  if ($element == 'propal') {
1441  $element = 'comm/propal';
1442  $subelement = 'propal';
1443  }
1444  if ($element == 'contract') {
1445  $element = $subelement = 'contrat';
1446  }
1447  if ($element == 'inter') {
1448  $element = $subelement = 'ficheinter';
1449  }
1450  if ($element == 'shipping') {
1451  $element = $subelement = 'expedition';
1452  }
1453 
1454  $object->origin = $origin;
1455  $object->origin_id = $originid;
1456 
1457  // Possibility to add external linked objects with hooks
1458  $object->linked_objects[$object->origin] = $object->origin_id;
1459  // link with order if it is a shipping invoice
1460  if ($object->origin == 'shipping') {
1461  require_once DOL_DOCUMENT_ROOT.'/expedition/class/expedition.class.php';
1462  $exp = new Expedition($db);
1463  $exp->fetch($object->origin_id);
1464  $exp->fetchObjectLinked();
1465  if (is_array($exp->linkedObjectsIds['commande']) && count($exp->linkedObjectsIds['commande']) > 0) {
1466  foreach ($exp->linkedObjectsIds['commande'] as $key => $value) {
1467  $object->linked_objects['commande'] = $value;
1468  }
1469  }
1470  }
1471 
1472  if (is_array($_POST['other_linked_objects']) && !empty($_POST['other_linked_objects'])) {
1473  $object->linked_objects = array_merge($object->linked_objects, $_POST['other_linked_objects']);
1474  }
1475 
1476  $id = $object->create($user); // This include class to add_object_linked() and add add_contact()
1477 
1478  if ($id > 0) {
1479  dol_include_once('/'.$element.'/class/'.$subelement.'.class.php');
1480 
1481  $classname = ucfirst($subelement);
1482  $srcobject = new $classname($db);
1483 
1484  dol_syslog("Try to find source object origin=".$object->origin." originid=".$object->origin_id." to add lines or deposit lines");
1485  $result = $srcobject->fetch($object->origin_id);
1486 
1487  // If deposit invoice - down payment with 1 line (fixed amount or percent)
1488  if (GETPOST('type') == Facture::TYPE_DEPOSIT && in_array($typeamount, array('amount', 'variable'))) {
1489  // Define the array $amountdeposit
1490  $amountdeposit = array();
1491  if (!empty($conf->global->MAIN_DEPOSIT_MULTI_TVA)) {
1492  if ($typeamount == 'amount') {
1493  $amount = $valuedeposit;
1494  } else {
1495  $amount = $srcobject->total_ttc * ($valuedeposit / 100);
1496  }
1497 
1498  $TTotalByTva = array();
1499  foreach ($srcobject->lines as &$line) {
1500  if (!empty($line->special_code)) {
1501  continue;
1502  }
1503  $TTotalByTva[$line->tva_tx] += $line->total_ttc;
1504  }
1505 
1506  foreach ($TTotalByTva as $tva => &$total) {
1507  $coef = $total / $srcobject->total_ttc; // Calc coef
1508  $am = $amount * $coef;
1509  $amount_ttc_diff += $am;
1510  $amountdeposit[$tva] += $am / (1 + $tva / 100); // Convert into HT for the addline
1511  }
1512  } else {
1513  if ($typeamount == 'amount') {
1514  $amountdeposit[0] = $valuedeposit;
1515  } elseif ($typeamount == 'variable') {
1516  if ($result > 0) {
1517  $totalamount = 0;
1518  $lines = $srcobject->lines;
1519  $numlines = count($lines);
1520  for ($i = 0; $i < $numlines; $i++) {
1521  $qualified = 1;
1522  if (empty($lines[$i]->qty)) {
1523  $qualified = 0; // We discard qty=0, it is an option
1524  }
1525  if (!empty($lines[$i]->special_code)) {
1526  $qualified = 0; // We discard special_code (frais port, ecotaxe, option, ...)
1527  }
1528  if ($qualified) {
1529  $totalamount += $lines[$i]->total_ht; // Fixme : is it not for the customer ? Shouldn't we take total_ttc ?
1530  $tva_tx = $lines[$i]->tva_tx;
1531  $amountdeposit[$tva_tx] += ($lines[$i]->total_ht * $valuedeposit) / 100;
1532  }
1533  }
1534 
1535  if ($totalamount == 0) {
1536  $amountdeposit[0] = 0;
1537  }
1538  } else {
1539  setEventMessages($srcobject->error, $srcobject->errors, 'errors');
1540  $error++;
1541  }
1542  }
1543 
1544  $amount_ttc_diff = $amountdeposit[0];
1545  }
1546 
1547  foreach ($amountdeposit as $tva => $amount) {
1548  if (empty($amount)) {
1549  continue;
1550  }
1551 
1552  $arraylist = array(
1553  'amount' => 'FixAmount',
1554  'variable' => 'VarAmount'
1555  );
1556  $descline = '(DEPOSIT)';
1557  //$descline.= ' - '.$langs->trans($arraylist[$typeamount]);
1558  if ($typeamount == 'amount') {
1559  $descline .= ' ('.price($valuedeposit, '', $langs, 0, - 1, - 1, (!empty($object->multicurrency_code) ? $object->multicurrency_code : $conf->currency)).')';
1560  } elseif ($typeamount == 'variable') {
1561  $descline .= ' ('.$valuedeposit.'%)';
1562  }
1563 
1564  $descline .= ' - '.$srcobject->ref;
1565  $result = $object->addline(
1566  $descline,
1567  $amount, // subprice
1568  1, // quantity
1569  $tva, // vat rate
1570  0, // localtax1_tx
1571  0, // localtax2_tx
1572  (empty($conf->global->INVOICE_PRODUCTID_DEPOSIT) ? 0 : $conf->global->INVOICE_PRODUCTID_DEPOSIT), // fk_product
1573  0, // remise_percent
1574  0, // date_start
1575  0, // date_end
1576  0,
1577  $lines[$i]->info_bits, // info_bits
1578  0,
1579  'HT',
1580  0,
1581  0, // product_type
1582  1,
1583  $lines[$i]->special_code,
1584  $object->origin,
1585  0,
1586  0,
1587  0,
1588  0,
1589  '',
1590  0,
1591  100,
1592  0,
1593  null,
1594  0,
1595  '',
1596  1
1597  );
1598  }
1599 
1600  $diff = $object->total_ttc - $amount_ttc_diff;
1601 
1602  if (!empty($conf->global->MAIN_DEPOSIT_MULTI_TVA) && $diff != 0) {
1603  $object->fetch_lines();
1604  $subprice_diff = $object->lines[0]->subprice - $diff / (1 + $object->lines[0]->tva_tx / 100);
1605  $object->updateline($object->lines[0]->id, $object->lines[0]->desc, $subprice_diff, $object->lines[0]->qty, $object->lines[0]->remise_percent, $object->lines[0]->date_start, $object->lines[0]->date_end, $object->lines[0]->tva_tx, 0, 0, 'HT', $object->lines[0]->info_bits, $object->lines[0]->product_type, 0, 0, 0, $object->lines[0]->pa_ht, $object->lines[0]->label, 0, array(), 100);
1606  }
1607  }
1608 
1609  // standard invoice, credit note, or down payment from a percent of all lines
1610  if (GETPOST('type') != Facture::TYPE_DEPOSIT || (GETPOST('type') == Facture::TYPE_DEPOSIT && $typeamount == 'variablealllines')) {
1611  if ($result > 0) {
1612  $lines = $srcobject->lines;
1613  if (empty($lines) && method_exists($srcobject, 'fetch_lines')) {
1614  $srcobject->fetch_lines();
1615  $lines = $srcobject->lines;
1616  }
1617 
1618  // If we create a standard invoice with a percent, we change amount by changing the qty
1619  if (GETPOST('type') == Facture::TYPE_STANDARD && $valuestandardinvoice > 0 && $valuestandardinvoice < 100) {
1620  if (is_array($lines)) {
1621  foreach ($lines as $line) {
1622  // We keep ->subprice and ->pa_ht, but we change the qty
1623  $line->qty = price2num($line->qty * $valuestandardinvoice / 100, 'MS');
1624  }
1625  }
1626  }
1627  // If we create a down payment with a percent on all lines, we change amount by changing the qty
1628  if (GETPOST('type') == Facture::TYPE_DEPOSIT && $typeamount == 'variablealllines') {
1629  if (is_array($lines)) {
1630  foreach ($lines as $line) {
1631  // We keep ->subprice and ->pa_ht, but we change the qty
1632  $line->qty = price2num($line->qty * $valuedeposit / 100, 'MS');
1633  }
1634  }
1635  }
1636 
1637  $fk_parent_line = 0;
1638  $num = count($lines);
1639 
1640  for ($i = 0; $i < $num; $i++) {
1641  if (!in_array($lines[$i]->id, $selectedLines)) {
1642  continue; // Skip unselected lines
1643  }
1644 
1645  // Don't add lines with qty 0 when coming from a shipment including all order lines
1646  if ($srcobject->element == 'shipping' && getDolGlobalString('SHIPMENT_GETS_ALL_ORDER_PRODUCTS') && $lines[$i]->qty == 0) {
1647  continue;
1648  }
1649  // Don't add closed lines when coming from a contract (Set constant to '0,5' to exclude also inactive lines)
1650  if (!isset($conf->global->CONTRACT_EXCLUDE_SERVICES_STATUS_FOR_INVOICE)) {
1651  $conf->global->CONTRACT_EXCLUDE_SERVICES_STATUS_FOR_INVOICE = '5';
1652  }
1653  if ($srcobject->element == 'contrat' && in_array($lines[$i]->statut, explode(',', $conf->global->CONTRACT_EXCLUDE_SERVICES_STATUS_FOR_INVOICE))) {
1654  continue;
1655  }
1656 
1657  $label = (!empty($lines[$i]->label) ? $lines[$i]->label : '');
1658  $desc = (!empty($lines[$i]->desc) ? $lines[$i]->desc : $lines[$i]->libelle);
1659  if ($object->situation_counter == 1) {
1660  $lines[$i]->situation_percent = 0;
1661  }
1662 
1663  if ($lines[$i]->subprice < 0 && empty($conf->global->INVOICE_KEEP_DISCOUNT_LINES_AS_IN_ORIGIN)) {
1664  // Negative line, we create a discount line
1665  $discount = new DiscountAbsolute($db);
1666  $discount->fk_soc = $object->socid;
1667  $discount->amount_ht = abs($lines[$i]->total_ht);
1668  $discount->amount_tva = abs($lines[$i]->total_tva);
1669  $discount->amount_ttc = abs($lines[$i]->total_ttc);
1670  $discount->tva_tx = $lines[$i]->tva_tx;
1671  $discount->fk_user = $user->id;
1672  $discount->description = $desc;
1673  $discount->multicurrency_subprice = abs($lines[$i]->multicurrency_subprice);
1674  $discount->multicurrency_amount_ht = abs($lines[$i]->multicurrency_total_ht);
1675  $discount->multicurrency_amount_tva = abs($lines[$i]->multicurrency_total_tva);
1676  $discount->multicurrency_amount_ttc = abs($lines[$i]->multicurrency_total_ttc);
1677 
1678  $discountid = $discount->create($user);
1679  if ($discountid > 0) {
1680  $result = $object->insert_discount($discountid); // This include link_to_invoice
1681  } else {
1682  setEventMessages($discount->error, $discount->errors, 'errors');
1683  $error++;
1684  break;
1685  }
1686  } else {
1687  // Positive line
1688  $product_type = ($lines[$i]->product_type ? $lines[$i]->product_type : 0);
1689 
1690  // Date start
1691  $date_start = false;
1692  if ($lines[$i]->date_debut_prevue) {
1693  $date_start = $lines[$i]->date_debut_prevue;
1694  }
1695  if ($lines[$i]->date_debut_reel) {
1696  $date_start = $lines[$i]->date_debut_reel;
1697  }
1698  if ($lines[$i]->date_start) {
1699  $date_start = $lines[$i]->date_start;
1700  }
1701 
1702  // Date end
1703  $date_end = false;
1704  if ($lines[$i]->date_fin_prevue) {
1705  $date_end = $lines[$i]->date_fin_prevue;
1706  }
1707  if ($lines[$i]->date_fin_reel) {
1708  $date_end = $lines[$i]->date_fin_reel;
1709  }
1710  if ($lines[$i]->date_end) {
1711  $date_end = $lines[$i]->date_end;
1712  }
1713 
1714  // Reset fk_parent_line for no child products and special product
1715  if (($lines[$i]->product_type != 9 && empty($lines[$i]->fk_parent_line)) || $lines[$i]->product_type == 9) {
1716  $fk_parent_line = 0;
1717  }
1718 
1719  // Extrafields
1720  if (method_exists($lines[$i], 'fetch_optionals')) {
1721  $lines[$i]->fetch_optionals();
1722  $array_options = $lines[$i]->array_options;
1723  }
1724 
1725  $tva_tx = $lines[$i]->tva_tx;
1726  if (!empty($lines[$i]->vat_src_code) && !preg_match('/\‍(/', $tva_tx)) {
1727  $tva_tx .= ' ('.$lines[$i]->vat_src_code.')';
1728  }
1729 
1730  // View third's localtaxes for NOW and do not use value from origin.
1731  // TODO Is this really what we want ? Yes if source is template invoice but what if proposal or order ?
1732  $localtax1_tx = get_localtax($tva_tx, 1, $object->thirdparty);
1733  $localtax2_tx = get_localtax($tva_tx, 2, $object->thirdparty);
1734 
1735  $result = $object->addline(
1736  $desc,
1737  $lines[$i]->subprice,
1738  $lines[$i]->qty,
1739  $tva_tx,
1740  $localtax1_tx,
1741  $localtax2_tx,
1742  $lines[$i]->fk_product,
1743  $lines[$i]->remise_percent,
1744  $date_start,
1745  $date_end,
1746  0,
1747  $lines[$i]->info_bits,
1748  $lines[$i]->fk_remise_except,
1749  'HT',
1750  0,
1751  $product_type,
1752  $lines[$i]->rang,
1753  $lines[$i]->special_code,
1754  $object->origin,
1755  $lines[$i]->rowid,
1756  $fk_parent_line,
1757  $lines[$i]->fk_fournprice,
1758  $lines[$i]->pa_ht,
1759  $label,
1760  $array_options,
1761  $lines[$i]->situation_percent,
1762  $lines[$i]->fk_prev_id,
1763  $lines[$i]->fk_unit,
1764  0,
1765  '',
1766  1
1767  );
1768 
1769  if ($result > 0) {
1770  $lineid = $result;
1771  } else {
1772  $lineid = 0;
1773  $error++;
1774  break;
1775  }
1776 
1777  // Defined the new fk_parent_line
1778  if ($result > 0 && $lines[$i]->product_type == 9) {
1779  $fk_parent_line = $result;
1780  }
1781  }
1782  }
1783  } else {
1784  setEventMessages($srcobject->error, $srcobject->errors, 'errors');
1785  $error++;
1786  }
1787  }
1788 
1789  $object->update_price(1, 'auto', 0, $mysoc);
1790 
1791  // Now we create same links to contact than the ones found on origin object
1792  /* Useless, already into the create
1793  if (!empty($conf->global->MAIN_PROPAGATE_CONTACTS_FROM_ORIGIN))
1794  {
1795  $originforcontact = $object->origin;
1796  $originidforcontact = $object->origin_id;
1797  if ($originforcontact == 'shipping') // shipment and order share the same contacts. If creating from shipment we take data of order
1798  {
1799  $originforcontact=$srcobject->origin;
1800  $originidforcontact=$srcobject->origin_id;
1801  }
1802  $sqlcontact = "SELECT code, fk_socpeople FROM ".MAIN_DB_PREFIX."element_contact as ec, ".MAIN_DB_PREFIX."c_type_contact as ctc";
1803  $sqlcontact.= " WHERE element_id = ".((int) $originidforcontact)." AND ec.fk_c_type_contact = ctc.rowid AND ctc.element = '".$db->escape($originforcontact)."'";
1804 
1805  $resqlcontact = $db->query($sqlcontact);
1806  if ($resqlcontact)
1807  {
1808  while($objcontact = $db->fetch_object($resqlcontact))
1809  {
1810  //print $objcontact->code.'-'.$objcontact->fk_socpeople."\n";
1811  $object->add_contact($objcontact->fk_socpeople, $objcontact->code);
1812  }
1813  }
1814  else dol_print_error($resqlcontact);
1815  }*/
1816 
1817  // Hooks
1818  $parameters = array('objFrom' => $srcobject);
1819  $reshook = $hookmanager->executeHooks('createFrom', $parameters, $object, $action); // Note that $action and $object may have been
1820  // modified by hook
1821  if ($reshook < 0) {
1822  setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
1823  $error++;
1824  }
1825  } else {
1826  setEventMessages($object->error, $object->errors, 'errors');
1827  $error++;
1828  }
1829  } else { // If some invoice's lines coming from page
1830  $id = $object->create($user);
1831 
1832  for ($i = 1; $i <= $NBLINES; $i++) {
1833  if (GETPOST('idprod'.$i, 'int')) {
1834  $product = new Product($db);
1835  $product->fetch(GETPOST('idprod'.$i, 'int'));
1836  $startday = dol_mktime(12, 0, 0, GETPOST('date_start'.$i.'month'), GETPOST('date_start'.$i.'day'), GETPOST('date_start'.$i.'year'));
1837  $endday = dol_mktime(12, 0, 0, GETPOST('date_end'.$i.'month'), GETPOST('date_end'.$i.'day'), GETPOST('date_end'.$i.'year'));
1838  $result = $object->addline($product->description, $product->price, price2num(GETPOST('qty'.$i), 'MS'), $product->tva_tx, $product->localtax1_tx, $product->localtax2_tx, GETPOST('idprod'.$i, 'int'), price2num(GETPOST('remise_percent'.$i), '', 2), $startday, $endday, 0, 0, '', $product->price_base_type, $product->price_ttc, $product->type, -1, 0, '', 0, 0, null, 0, '', 0, 100, '', $product->fk_unit, 0, '', 1);
1839  }
1840  }
1841 
1842  $object->update_price(1, 'auto', 0, $mysoc);
1843  }
1844  }
1845  }
1846 
1847  // Situation invoices
1848  if (GETPOST('type') == Facture::TYPE_SITUATION && GETPOST('situations')) {
1849  if (empty($dateinvoice)) {
1850  $error++;
1851  $mesg = $langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("Date"));
1852  setEventMessages($mesg, null, 'errors');
1853  } elseif ($dateinvoice > (dol_get_last_hour(dol_now('tzuserrel')) + (empty($conf->global->INVOICE_MAX_FUTURE_DELAY) ? 0 : $conf->global->INVOICE_MAX_FUTURE_DELAY))) {
1854  $error++;
1855  setEventMessages($langs->trans("ErrorDateIsInFuture"), null, 'errors');
1856  $action = 'create';
1857  }
1858 
1859  if (!(GETPOST('situations', 'int') > 0)) {
1860  $error++;
1861  $mesg = $langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("InvoiceSituation"));
1862  setEventMessages($mesg, null, 'errors');
1863  $action = 'create';
1864  }
1865 
1866  if (!$error) {
1867  $result = $object->fetch(GETPOST('situations', 'int'));
1868  $object->fk_facture_source = GETPOST('situations', 'int');
1869  $object->type = Facture::TYPE_SITUATION;
1870 
1871  if (!empty($origin) && !empty($originid)) {
1872  include_once DOL_DOCUMENT_ROOT.'/core/lib/price.lib.php';
1873 
1874  $object->origin = $origin;
1875  $object->origin_id = $originid;
1876 
1877  // retained warranty
1878  if (!empty($conf->global->INVOICE_USE_RETAINED_WARRANTY)) {
1879  $retained_warranty = GETPOST('retained_warranty', 'int');
1880  if (price2num($retained_warranty) > 0) {
1881  $object->retained_warranty = price2num($retained_warranty);
1882  }
1883 
1884  if (GETPOST('retained_warranty_fk_cond_reglement', 'int') > 0) {
1885  $object->retained_warranty_fk_cond_reglement = GETPOST('retained_warranty_fk_cond_reglement', 'int');
1886  }
1887 
1888  $retained_warranty_date_limit = GETPOST('retained_warranty_date_limit');
1889  if (!empty($retained_warranty_date_limit) && $db->jdate($retained_warranty_date_limit)) {
1890  $object->retained_warranty_date_limit = $db->jdate($retained_warranty_date_limit);
1891  }
1892  $object->retained_warranty_date_limit = !empty($object->retained_warranty_date_limit) ? $object->retained_warranty_date_limit : $object->calculate_date_lim_reglement($object->retained_warranty_fk_cond_reglement);
1893  }
1894 
1895  foreach ($object->lines as $i => &$line) {
1896  $line->origin = $object->origin;
1897  $line->origin_id = $line->id;
1898  $line->fk_prev_id = $line->id;
1899  $line->fetch_optionals();
1900  $line->situation_percent = $line->get_prev_progress($object->id); // get good progress including credit note
1901 
1902  // The $line->situation_percent has been modified, so we must recalculate all amounts
1903  $tabprice = calcul_price_total($line->qty, $line->subprice, $line->remise_percent, $line->tva_tx, $line->localtax1_tx, $line->localtax2_tx, 0, 'HT', 0, $line->product_type, $mysoc, '', $line->situation_percent);
1904  $line->total_ht = $tabprice[0];
1905  $line->total_tva = $tabprice[1];
1906  $line->total_ttc = $tabprice[2];
1907  $line->total_localtax1 = $tabprice[9];
1908  $line->total_localtax2 = $tabprice[10];
1909  $line->multicurrency_total_ht = $tabprice[16];
1910  $line->multicurrency_total_tva = $tabprice[17];
1911  $line->multicurrency_total_ttc = $tabprice[18];
1912 
1913  // Si fk_remise_except defini on vérifie si la réduction à déjà été appliquée
1914  if ($line->fk_remise_except) {
1915  $discount = new DiscountAbsolute($line->db);
1916  $result = $discount->fetch($line->fk_remise_except);
1917  if ($result > 0) {
1918  // Check if discount not already affected to another invoice
1919  if ($discount->fk_facture_line > 0) {
1920  $line->fk_remise_except = 0;
1921  }
1922  }
1923  }
1924  }
1925  }
1926 
1927  $object->fetch_thirdparty();
1928  $object->date = $dateinvoice;
1929  $object->date_pointoftax = $date_pointoftax;
1930  $object->note_public = trim(GETPOST('note_public', 'restricthtml'));
1931  $object->note = trim(GETPOST('note', 'restricthtml'));
1932  $object->note_private = trim(GETPOST('note', 'restricthtml'));
1933  $object->ref_client = GETPOST('ref_client', 'alpha');
1934  $object->model_pdf = GETPOST('model', 'alpha');
1935  $object->fk_project = GETPOST('projectid', 'int');
1936  $object->cond_reglement_id = GETPOST('cond_reglement_id', 'int');
1937  $object->mode_reglement_id = GETPOST('mode_reglement_id', 'int');
1938  $object->remise_absolue =price2num(GETPOST('remise_absolue'), 'MU', 2);
1939  $object->remise_percent = price2num(GETPOST('remise_percent'), '', 2);
1940 
1941  // Proprietes particulieres a facture de remplacement
1942 
1943  $object->situation_counter = $object->situation_counter + 1;
1944  $id = $object->createFromCurrent($user);
1945  if ($id <= 0) {
1946  $mesg = $object->error;
1947  } else {
1948  $nextSituationInvoice = new Facture($db);
1949  $nextSituationInvoice->fetch($id);
1950 
1951  // create extrafields with data from create form
1952  $extrafields->fetch_name_optionals_label($nextSituationInvoice->table_element);
1953  $ret = $extrafields->setOptionalsFromPost(null, $nextSituationInvoice);
1954  if ($ret > 0) {
1955  $nextSituationInvoice->insertExtraFields();
1956  }
1957  }
1958  }
1959  }
1960 
1961  // End of object creation, we show it
1962  if ($id > 0 && !$error) {
1963  $db->commit();
1964 
1965  // Define output language
1966  if (empty($conf->global->MAIN_DISABLE_PDF_AUTOUPDATE) && count($object->lines)) {
1967  $outputlangs = $langs;
1968  $newlang = '';
1969  if (getDolGlobalInt('MAIN_MULTILANGS') && empty($newlang) && GETPOST('lang_id', 'aZ09')) {
1970  $newlang = GETPOST('lang_id', 'aZ09');
1971  }
1972  if (getDolGlobalInt('MAIN_MULTILANGS') && empty($newlang)) {
1973  $newlang = $object->thirdparty->default_lang;
1974  }
1975  if (!empty($newlang)) {
1976  $outputlangs = new Translate("", $conf);
1977  $outputlangs->setDefaultLang($newlang);
1978  $outputlangs->load('products');
1979  }
1980  $model = $object->model_pdf;
1981  $ret = $object->fetch($id); // Reload to get new records
1982 
1983  $result = $object->generateDocument($model, $outputlangs, $hidedetails, $hidedesc, $hideref);
1984  if ($result < 0) {
1985  setEventMessages($object->error, $object->errors, 'errors');
1986  }
1987  }
1988 
1989  header('Location: '.$_SERVER["PHP_SELF"].'?facid='.$id);
1990  exit();
1991  } else {
1992  $db->rollback();
1993  $action = 'create';
1994  $_GET["origin"] = $_POST["origin"];
1995  $_GET["originid"] = $_POST["originid"];
1996  setEventMessages($object->error, $object->errors, 'errors');
1997  }
1998  } elseif ($action == 'addline' && GETPOST('submitforalllines', 'alpha') && GETPOST('vatforalllines', 'alpha') !== '') {
1999  // Define vat_rate
2000  $vat_rate = (GETPOST('vatforalllines') ? GETPOST('vatforalllines') : 0);
2001  $vat_rate = str_replace('*', '', $vat_rate);
2002  $localtax1_rate = get_localtax($vat_rate, 1, $object->thirdparty, $mysoc);
2003  $localtax2_rate = get_localtax($vat_rate, 2, $object->thirdparty, $mysoc);
2004  foreach ($object->lines as $line) {
2005  $result = $object->updateline($line->id, $line->desc, $line->subprice, $line->qty, $line->remise_percent, $line->date_start, $line->date_end, $vat_rate, $localtax1_rate, $localtax2_rate, 'HT', $line->info_bits, $line->product_type, $line->fk_parent_line, 0, $line->fk_fournprice, $line->pa_ht, $line->label, $line->special_code, $line->array_options, $line->situation_percent, $line->fk_unit, $line->multicurrency_subprice);
2006  }
2007  } elseif ($action == 'addline' && GETPOST('submitforalllines', 'alpha') && GETPOST('remiseforalllines', 'alpha') !== '' && $usercancreate) {
2008  // Define vat_rate
2009  $remise_percent = (GETPOST('remiseforalllines') ? GETPOST('remiseforalllines') : 0);
2010  $remise_percent = str_replace('*', '', $remise_percent);
2011  foreach ($object->lines as $line) {
2012  $result = $object->updateline($line->id, $line->desc, $line->subprice, $line->qty, $remise_percent, $line->date_start, $line->date_end, $line->tva_tx, $line->localtax1_tx, $line->localtax2_tx, 'HT', $line->info_bits, $line->product_type, $line->fk_parent_line, 0, $line->fk_fournprice, $line->pa_ht, $line->label, $line->special_code, $line->array_options, $line->situation_percent, $line->fk_unit, $line->multicurrency_subprice);
2013  }
2014  } elseif ($action == 'addline' && $usercancreate) { // Add a new line
2015  $langs->load('errors');
2016  $error = 0;
2017 
2018  // Set if we used free entry or predefined product
2019  $predef = '';
2020  $product_desc =(GETPOSTISSET('dp_desc') ? GETPOST('dp_desc', 'restricthtml') : '');
2021 
2022  $price_ht = '';
2023  $price_ht_devise = '';
2024  $price_ttc = '';
2025  $price_ttc_devise = '';
2026 
2027  if (GETPOST('price_ht') !== '') {
2028  $price_ht = price2num(GETPOST('price_ht'), 'MU', 2);
2029  }
2030  if (GETPOST('multicurrency_price_ht') !== '') {
2031  $price_ht_devise = price2num(GETPOST('multicurrency_price_ht'), 'CU', 2);
2032  }
2033  if (GETPOST('price_ttc') !== '') {
2034  $price_ttc = price2num(GETPOST('price_ttc'), 'MU', 2);
2035  }
2036  if (GETPOST('multicurrency_price_ttc') !== '') {
2037  $price_ttc_devise = price2num(GETPOST('multicurrency_price_ttc'), 'CU', 2);
2038  }
2039 
2040  $prod_entry_mode = GETPOST('prod_entry_mode', 'aZ09');
2041  if ($prod_entry_mode == 'free') {
2042  $idprod = 0;
2043  } else {
2044  $idprod = GETPOST('idprod', 'int');
2045 
2046  if (!empty($conf->global->MAIN_DISABLE_FREE_LINES) && $idprod <= 0) {
2047  setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("ProductOrService")), null, 'errors');
2048  $error++;
2049  }
2050  }
2051 
2052  $tva_tx = GETPOST('tva_tx', 'alpha');
2053 
2054  $qty = price2num(GETPOST('qty'.$predef, 'alpha'), 'MS', 2);
2055  $remise_percent = (GETPOSTISSET('remise_percent'.$predef) ? price2num(GETPOST('remise_percent'.$predef, 'alpha'), '', 2) : 0);
2056  if (empty($remise_percent)) {
2057  $remise_percent = 0;
2058  }
2059 
2060  // Extrafields
2061  $extralabelsline = $extrafields->fetch_name_optionals_label($object->table_element_line);
2062  $array_options = $extrafields->getOptionalsFromPost($object->table_element_line, $predef);
2063  // Unset extrafield
2064  if (is_array($extralabelsline)) {
2065  // Get extra fields
2066  foreach ($extralabelsline as $key => $value) {
2067  unset($_POST["options_".$key.$predef]);
2068  }
2069  }
2070 
2071  if ((empty($idprod) || $idprod < 0) && ($price_ht < 0) && ($qty < 0)) {
2072  setEventMessages($langs->trans('ErrorBothFieldCantBeNegative', $langs->transnoentitiesnoconv('UnitPriceHT'), $langs->transnoentitiesnoconv('Qty')), null, 'errors');
2073  $error++;
2074  }
2075  if (!$prod_entry_mode) {
2076  if (GETPOST('type') < 0 && !GETPOST('search_idprod')) {
2077  setEventMessages($langs->trans('ErrorChooseBetweenFreeEntryOrPredefinedProduct'), null, 'errors');
2078  $error++;
2079  }
2080  }
2081  if ($prod_entry_mode == 'free' && (empty($idprod) || $idprod < 0) && GETPOST('type') < 0) {
2082  setEventMessages($langs->trans('ErrorFieldRequired', $langs->transnoentitiesnoconv('Type')), null, 'errors');
2083  $error++;
2084  }
2085  if ($prod_entry_mode == 'free' && (empty($idprod) || $idprod < 0) && (($price_ht < 0 && empty($conf->global->FACTURE_ENABLE_NEGATIVE_LINES)) || $price_ht == '') && (($price_ht_devise < 0 && empty($conf->global->FACTURE_ENABLE_NEGATIVE_LINES)) || $price_ht_devise == '') && $price_ttc === '' && $price_ttc_devise === '' && $object->type != Facture::TYPE_CREDIT_NOTE) { // Unit price can be 0 but not ''
2086  if (($price_ht < 0 || $price_ttc < 0) && empty($conf->global->FACTURE_ENABLE_NEGATIVE_LINES)) {
2087  $langs->load("errors");
2088  if ($object->type == $object::TYPE_DEPOSIT) {
2089  // Using negative lines on deposit lead to headach and blocking problems when you want to consume them.
2090  setEventMessages($langs->trans("ErrorLinesCantBeNegativeOnDeposits"), null, 'errors');
2091  } else {
2092  setEventMessages($langs->trans("ErrorFieldCantBeNegativeOnInvoice", $langs->transnoentitiesnoconv("UnitPriceHT"), $langs->transnoentitiesnoconv("CustomerAbsoluteDiscountShort")), null, 'errors');
2093  }
2094  $error++;
2095  } else {
2096  setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("UnitPriceHT")), null, 'errors');
2097  $error++;
2098  }
2099  }
2100  if ($qty == '') {
2101  setEventMessages($langs->trans('ErrorFieldRequired', $langs->transnoentitiesnoconv('Qty')), null, 'errors');
2102  $error++;
2103  }
2104  if ($prod_entry_mode == 'free' && empty($idprod) && empty($product_desc)) {
2105  setEventMessages($langs->trans('ErrorFieldRequired', $langs->transnoentitiesnoconv('Description')), null, 'errors');
2106  $error++;
2107  }
2108  if ($qty < 0) {
2109  $langs->load("errors");
2110  setEventMessages($langs->trans('ErrorQtyForCustomerInvoiceCantBeNegative'), null, 'errors');
2111  $error++;
2112  }
2113 
2114  if (!$error && isModEnabled('variants') && $prod_entry_mode != 'free') {
2115  if ($combinations = GETPOST('combinations', 'array')) {
2116  //Check if there is a product with the given combination
2117  $prodcomb = new ProductCombination($db);
2118 
2119  if ($res = $prodcomb->fetchByProductCombination2ValuePairs($idprod, $combinations)) {
2120  $idprod = $res->fk_product_child;
2121  } else {
2122  setEventMessages($langs->trans('ErrorProductCombinationNotFound'), null, 'errors');
2123  $error++;
2124  }
2125  }
2126  }
2127 
2128  if (!$error && ($qty >= 0) && (!empty($product_desc) || (!empty($idprod) && $idprod > 0))) {
2129  $ret = $object->fetch($id);
2130  if ($ret < 0) {
2131  dol_print_error($db, $object->error);
2132  exit();
2133  }
2134  $ret = $object->fetch_thirdparty();
2135 
2136  // Clean parameters
2137  $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'));
2138  $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'));
2139  $price_base_type = (GETPOST('price_base_type', 'alpha') ? GETPOST('price_base_type', 'alpha') : 'HT');
2140  $tva_npr = "";
2141 
2142  // Define special_code for special lines
2143  $special_code = 0;
2144  // if (!GETPOST(qty)) $special_code=3; // Options should not exists on invoices
2145 
2146  // Ecrase $pu par celui du produit
2147  // Ecrase $desc par celui du produit
2148  // Ecrase $base_price_type par celui du produit
2149  // Replaces $fk_unit with the product's
2150  if (!empty($idprod) && $idprod > 0) {
2151  $prod = new Product($db);
2152  $prod->fetch($idprod);
2153 
2154  $label = ((GETPOST('product_label') && GETPOST('product_label') != $prod->label) ? GETPOST('product_label') : '');
2155 
2156  // Search the correct price into loaded array product_price_by_qty using id of array retrieved into POST['pqp'].
2157  $pqp = (GETPOST('pbq', 'int') ? GETPOST('pbq', 'int') : 0);
2158 
2159  $datapriceofproduct = $prod->getSellPrice($mysoc, $object->thirdparty, $pqp);
2160 
2161  $pu_ht = $datapriceofproduct['pu_ht'];
2162  $pu_ttc = $datapriceofproduct['pu_ttc'];
2163  $price_min = $datapriceofproduct['price_min'];
2164  $price_min_ttc = (isset($datapriceofproduct['price_min_ttc'])) ? $datapriceofproduct['price_min_ttc'] : null;
2165  $price_base_type = $datapriceofproduct['price_base_type'];
2166 
2167  //$tva_tx = $datapriceofproduct['tva_tx'];
2168  //$tva_npr = $datapriceofproduct['tva_npr'];
2169  $tmpvat = (float) price2num(preg_replace('/\s*\‍(.*\‍)/', '', $tva_tx));
2170  $tmpprodvat = price2num(preg_replace('/\s*\‍(.*\‍)/', '', $prod->tva_tx));
2171 
2172  // Set unit price to use
2173  if (!empty($price_ht) || $price_ht === '0') {
2174  $pu_ht = price2num($price_ht, 'MU');
2175  $pu_ttc = price2num($pu_ht * (1 + ($tmpvat / 100)), 'MU');
2176  } elseif (!empty($price_ttc) || $price_ttc === '0') {
2177  $pu_ttc = price2num($price_ttc, 'MU');
2178  $pu_ht = price2num($pu_ttc / (1 + ($tmpvat / 100)), 'MU');
2179  } elseif ($tmpvat != $tmpprodvat) {
2180  // Is this still used ?
2181  if ($price_base_type != 'HT') {
2182  $pu_ht = price2num($pu_ttc / (1 + ($tmpvat / 100)), 'MU');
2183  } else {
2184  $pu_ttc = price2num($pu_ht * (1 + ($tmpvat / 100)), 'MU');
2185  }
2186  }
2187 
2188  $desc = '';
2189 
2190  // Define output language
2191  if (getDolGlobalInt('MAIN_MULTILANGS') && !empty($conf->global->PRODUIT_TEXTS_IN_THIRDPARTY_LANGUAGE)) {
2192  $outputlangs = $langs;
2193  $newlang = '';
2194  if (empty($newlang) && GETPOST('lang_id', 'aZ09')) {
2195  $newlang = GETPOST('lang_id', 'aZ09');
2196  }
2197  if (empty($newlang)) {
2198  $newlang = $object->thirdparty->default_lang;
2199  }
2200  if (!empty($newlang)) {
2201  $outputlangs = new Translate("", $conf);
2202  $outputlangs->setDefaultLang($newlang);
2203  $outputlangs->load('products');
2204  }
2205 
2206  $desc = (!empty($prod->multilangs [$outputlangs->defaultlang] ["description"])) ? $prod->multilangs [$outputlangs->defaultlang] ["description"] : $prod->description;
2207  } else {
2208  $desc = $prod->description;
2209  }
2210 
2211  //If text set in desc is the same as product descpription (as now it's preloaded) whe add it only one time
2212  if ($product_desc==$desc && !empty($conf->global->PRODUIT_AUTOFILL_DESC)) {
2213  $product_desc='';
2214  }
2215 
2216  if (!empty($product_desc) && !empty($conf->global->MAIN_NO_CONCAT_DESCRIPTION)) {
2217  $desc = $product_desc;
2218  } else {
2219  $desc = dol_concatdesc($desc, $product_desc, '', !empty($conf->global->MAIN_CHANGE_ORDER_CONCAT_DESCRIPTION));
2220  }
2221 
2222  // Add custom code and origin country into description
2223  if (empty($conf->global->MAIN_PRODUCT_DISABLE_CUSTOMCOUNTRYCODE) && (!empty($prod->customcode) || !empty($prod->country_code))) {
2224  $tmptxt = '(';
2225  // Define output language
2226  if (getDolGlobalInt('MAIN_MULTILANGS') && !empty($conf->global->PRODUIT_TEXTS_IN_THIRDPARTY_LANGUAGE)) {
2227  $outputlangs = $langs;
2228  $newlang = '';
2229  if (empty($newlang) && GETPOST('lang_id', 'alpha')) {
2230  $newlang = GETPOST('lang_id', 'alpha');
2231  }
2232  if (empty($newlang)) {
2233  $newlang = $object->thirdparty->default_lang;
2234  }
2235  if (!empty($newlang)) {
2236  $outputlangs = new Translate("", $conf);
2237  $outputlangs->setDefaultLang($newlang);
2238  $outputlangs->load('products');
2239  }
2240  if (!empty($prod->customcode)) {
2241  $tmptxt .= $outputlangs->transnoentitiesnoconv("CustomCode").': '.$prod->customcode;
2242  }
2243  if (!empty($prod->customcode) && !empty($prod->country_code)) {
2244  $tmptxt .= ' - ';
2245  }
2246  if (!empty($prod->country_code)) {
2247  $tmptxt .= $outputlangs->transnoentitiesnoconv("CountryOrigin").': '.getCountry($prod->country_code, 0, $db, $outputlangs, 0);
2248  }
2249  } else {
2250  if (!empty($prod->customcode)) {
2251  $tmptxt .= $langs->transnoentitiesnoconv("CustomCode").': '.$prod->customcode;
2252  }
2253  if (!empty($prod->customcode) && !empty($prod->country_code)) {
2254  $tmptxt .= ' - ';
2255  }
2256  if (!empty($prod->country_code)) {
2257  $tmptxt .= $langs->transnoentitiesnoconv("CountryOrigin").': '.getCountry($prod->country_code, 0, $db, $langs, 0);
2258  }
2259  }
2260  $tmptxt .= ')';
2261  $desc = dol_concatdesc($desc, $tmptxt);
2262  }
2263 
2264  $type = $prod->type;
2265  $fk_unit = $prod->fk_unit;
2266  } else {
2267  $pu_ht = price2num($price_ht, 'MU');
2268  $pu_ttc = price2num($price_ttc, 'MU');
2269  $tva_npr = (preg_match('/\*/', $tva_tx) ? 1 : 0);
2270  $tva_tx = str_replace('*', '', $tva_tx);
2271  if (empty($tva_tx)) {
2272  $tva_npr = 0;
2273  }
2274  $label = (GETPOST('product_label') ? GETPOST('product_label') : '');
2275  $desc = $product_desc;
2276  $type = GETPOST('type');
2277  $fk_unit = GETPOST('units', 'alpha');
2278 
2279  $pu_ht_devise = price2num($price_ht_devise, 'MU');
2280  $pu_ttc_devise = price2num($price_ttc_devise, 'MU');
2281 
2282  if ($pu_ttc && !$pu_ht) {
2283  $price_base_type = 'TTC';
2284  }
2285  }
2286 
2287  $pu_ht_devise = price2num($price_ht_devise, 'MU');
2288 
2289  // Margin
2290  $fournprice = price2num(GETPOST('fournprice'.$predef) ? GETPOST('fournprice'.$predef) : '');
2291  $buyingprice = price2num(GETPOST('buying_price'.$predef) != '' ? GETPOST('buying_price'.$predef) : ''); // If buying_price is '0', we must keep this value
2292 
2293  // Local Taxes
2294  $localtax1_tx = get_localtax($tva_tx, 1, $object->thirdparty, $mysoc, $tva_npr);
2295  $localtax2_tx = get_localtax($tva_tx, 2, $object->thirdparty, $mysoc, $tva_npr);
2296 
2297  $info_bits = 0;
2298  if ($tva_npr) {
2299  $info_bits |= 0x01;
2300  }
2301 
2302  $price2num_pu_ht = price2num($pu_ht);
2303  $price2num_remise_percent = price2num($remise_percent);
2304  $price2num_price_min = price2num($price_min);
2305  $price2num_price_min_ttc = price2num($price_min_ttc);
2306  if (empty($price2num_pu_ht)) {
2307  $price2num_pu_ht = 0;
2308  }
2309  if (empty($price2num_remise_percent)) {
2310  $price2num_remise_percent = 0;
2311  }
2312  if (empty($price2num_price_min)) {
2313  $price2num_price_min = 0;
2314  }
2315  if (empty($price2num_price_min_ttc)) {
2316  $price2num_price_min_ttc = 0;
2317  }
2318 
2319  // Check price is not lower than minimum (check is done only for standard or replacement invoices)
2320  if ($usermustrespectpricemin && ($object->type == Facture::TYPE_STANDARD || $object->type == Facture::TYPE_REPLACEMENT)) {
2321  if ($pu_ht && $price_min && ((price2num($pu_ht) * (1 - $remise_percent / 100)) < price2num($price_min))) {
2322  $mesg = $langs->trans("CantBeLessThanMinPrice", price(price2num($price_min, 'MU'), 0, $langs, 0, 0, -1, $conf->currency));
2323  setEventMessages($mesg, null, 'errors');
2324  $error++;
2325  } elseif ($pu_ttc && $price_min_ttc && ((price2num($pu_ttc) * (1 - $remise_percent / 100)) < price2num($price_min_ttc))) {
2326  $mesg = $langs->trans("CantBeLessThanMinPrice", price(price2num($price_min_ttc, 'MU'), 0, $langs, 0, 0, -1, $conf->currency));
2327  setEventMessages($mesg, null, 'errors');
2328  $error++;
2329  }
2330  }
2331 
2332  if (!$error) {
2333  // Add batchinfo if the detail_batch array is defined
2334  if (isModEnabled('productbatch') && !empty($lines[$i]->detail_batch) && is_array($lines[$i]->detail_batch) && !empty($conf->global->INVOICE_INCUDE_DETAILS_OF_LOTS_SERIALS)) {
2335  $langs->load('productbatch');
2336  foreach ($lines[$i]->detail_batch as $batchline) {
2337  $desc .= ' '.$langs->trans('Batch').' '.$batchline->batch.' '.$langs->trans('printQty', $batchline->qty).' ';
2338  }
2339  }
2340 
2341  // Insert line
2342  $result = $object->addline($desc, $pu_ht, $qty, $tva_tx, $localtax1_tx, $localtax2_tx, $idprod, $remise_percent, $date_start, $date_end, 0, $info_bits, '', $price_base_type, $pu_ttc, $type, min($rank, count($object->lines) + 1), $special_code, '', 0, GETPOST('fk_parent_line'), $fournprice, $buyingprice, $label, $array_options, GETPOST('progress'), '', $fk_unit, $pu_ht_devise);
2343 
2344  if ($result > 0) {
2345  // Define output language and generate document
2346  if (empty($conf->global->MAIN_DISABLE_PDF_AUTOUPDATE)) {
2347  $outputlangs = $langs;
2348  $newlang = '';
2349  if (getDolGlobalInt('MAIN_MULTILANGS') && empty($newlang) && GETPOST('lang_id', 'aZ09')) {
2350  $newlang = GETPOST('lang_id', 'aZ09');
2351  }
2352  if (getDolGlobalInt('MAIN_MULTILANGS') && empty($newlang)) {
2353  $newlang = $object->thirdparty->default_lang;
2354  }
2355  if (!empty($newlang)) {
2356  $outputlangs = new Translate("", $conf);
2357  $outputlangs->setDefaultLang($newlang);
2358  $outputlangs->load('products');
2359  }
2360  $model = $object->model_pdf;
2361  $ret = $object->fetch($id); // Reload to get new records
2362 
2363  $result = $object->generateDocument($model, $outputlangs, $hidedetails, $hidedesc, $hideref);
2364  if ($result < 0) {
2365  setEventMessages($object->error, $object->errors, 'errors');
2366  }
2367  }
2368 
2369  unset($_POST['prod_entry_mode']);
2370 
2371  unset($_POST['qty']);
2372  unset($_POST['type']);
2373  unset($_POST['remise_percent']);
2374  unset($_POST['price_ht']);
2375  unset($_POST['multicurrency_price_ht']);
2376  unset($_POST['price_ttc']);
2377  unset($_POST['tva_tx']);
2378  unset($_POST['product_ref']);
2379  unset($_POST['product_label']);
2380  unset($_POST['product_desc']);
2381  unset($_POST['fournprice']);
2382  unset($_POST['buying_price']);
2383  unset($_POST['np_marginRate']);
2384  unset($_POST['np_markRate']);
2385  unset($_POST['dp_desc']);
2386  unset($_POST['idprod']);
2387  unset($_POST['units']);
2388 
2389  unset($_POST['date_starthour']);
2390  unset($_POST['date_startmin']);
2391  unset($_POST['date_startsec']);
2392  unset($_POST['date_startday']);
2393  unset($_POST['date_startmonth']);
2394  unset($_POST['date_startyear']);
2395  unset($_POST['date_endhour']);
2396  unset($_POST['date_endmin']);
2397  unset($_POST['date_endsec']);
2398  unset($_POST['date_endday']);
2399  unset($_POST['date_endmonth']);
2400  unset($_POST['date_endyear']);
2401 
2402  unset($_POST['situations']);
2403  unset($_POST['progress']);
2404  } else {
2405  setEventMessages($object->error, $object->errors, 'errors');
2406  }
2407 
2408  $action = '';
2409  }
2410  }
2411  } elseif ($action == 'updateline' && $usercancreate && !GETPOST('cancel', 'alpha')) {
2412  if (!$object->fetch($id) > 0) {
2413  dol_print_error($db);
2414  }
2415  $object->fetch_thirdparty();
2416 
2417  // Clean parameters
2418  $date_start = '';
2419  $date_end = '';
2420  $date_start = dol_mktime(GETPOST('date_starthour'), GETPOST('date_startmin'), GETPOST('date_startsec'), GETPOST('date_startmonth'), GETPOST('date_startday'), GETPOST('date_startyear'));
2421  $date_end = dol_mktime(GETPOST('date_endhour'), GETPOST('date_endmin'), GETPOST('date_endsec'), GETPOST('date_endmonth'), GETPOST('date_endday'), GETPOST('date_endyear'));
2422  $description = dol_htmlcleanlastbr(GETPOST('product_desc', 'restricthtml') ? GETPOST('product_desc', 'restricthtml') : GETPOST('desc', 'restricthtml'));
2423  $vat_rate = (GETPOST('tva_tx') ? GETPOST('tva_tx') : 0);
2424  $vat_rate = str_replace('*', '', $vat_rate);
2425 
2426  $pu_ht = price2num(GETPOST('price_ht'), '', 2);
2427  $pu_ttc = price2num(GETPOST('price_ttc'), '', 2);
2428 
2429  $pu_ht_devise = price2num(GETPOST('multicurrency_subprice'), '', 2);
2430  $pu_ttc_devise = price2num(GETPOST('multicurrency_subprice_ttc'), '', 2);
2431 
2432  $qty = price2num(GETPOST('qty', 'alpha'), 'MS');
2433 
2434  // Define info_bits
2435  $info_bits = 0;
2436  if (preg_match('/\*/', $vat_rate)) {
2437  $info_bits |= 0x01;
2438  }
2439 
2440  // Define vat_rate
2441  $vat_rate = str_replace('*', '', $vat_rate);
2442  $localtax1_rate = get_localtax($vat_rate, 1, $object->thirdparty);
2443  $localtax2_rate = get_localtax($vat_rate, 2, $object->thirdparty);
2444 
2445  // Add buying price
2446  $fournprice = price2num(GETPOST('fournprice') ? GETPOST('fournprice') : '');
2447  $buyingprice = price2num(GETPOST('buying_price') != '' ? GETPOST('buying_price') : ''); // If buying_price is '0', we muste keep this value
2448 
2449  // Extrafields
2450  $extralabelsline = $extrafields->fetch_name_optionals_label($object->table_element_line);
2451  $array_options = $extrafields->getOptionalsFromPost($object->table_element_line);
2452  // Unset extrafield
2453  if (is_array($extralabelsline)) {
2454  // Get extra fields
2455  foreach ($extralabelsline as $key => $value) {
2456  unset($_POST["options_".$key]);
2457  }
2458  }
2459 
2460  // Define special_code for special lines
2461  $special_code = GETPOST('special_code', 'int');
2462  if ($special_code == 3) {
2463  $special_code = 0; // Options should not exists on invoices
2464  }
2465 
2466  $line = new FactureLigne($db);
2467  $line->fetch(GETPOST('lineid', 'int'));
2468  $percent = $line->get_prev_progress($object->id);
2469  $progress = price2num(GETPOST('progress', 'alpha'));
2470 
2471  if ($object->type == Facture::TYPE_CREDIT_NOTE && $object->situation_cycle_ref > 0) {
2472  // in case of situation credit note
2473  if ($progress >= 0) {
2474  $mesg = $langs->trans("CantBeNullOrPositive");
2475  setEventMessages($mesg, null, 'warnings');
2476  $error++;
2477  $result = -1;
2478  } elseif ($progress < $line->situation_percent) { // TODO : use a modified $line->get_prev_progress($object->id) result
2479  $mesg = $langs->trans("CantBeLessThanMinPercent");
2480  setEventMessages($mesg, null, 'warnings');
2481  $error++;
2482  $result = -1;
2483  } elseif ($progress < $percent) {
2484  $mesg = '<div class="warning">'.$langs->trans("CantBeLessThanMinPercent").'</div>';
2485  setEventMessages($mesg, null, 'warnings');
2486  $error++;
2487  $result = -1;
2488  }
2489  }
2490 
2491  $remise_percent = price2num(GETPOST('remise_percent'), '', 2);
2492 
2493  // Check minimum price
2494  $productid = GETPOST('productid', 'int');
2495  if (!empty($productid)) {
2496  $product = new Product($db);
2497  $product->fetch($productid);
2498 
2499  $type = $product->type;
2500 
2501  $price_min = $product->price_min;
2502  if ((!empty($conf->global->PRODUIT_MULTIPRICES) || !empty($conf->global->PRODUIT_CUSTOMER_PRICES_BY_QTY_MULTIPRICES)) && !empty($object->thirdparty->price_level)) {
2503  $price_min = $product->multiprices_min[$object->thirdparty->price_level];
2504  }
2505  $price_min_ttc = $product->price_min_ttc;
2506  if ((!empty($conf->global->PRODUIT_MULTIPRICES) || !empty($conf->global->PRODUIT_CUSTOMER_PRICES_BY_QTY_MULTIPRICES)) && !empty($object->thirdparty->price_level)) {
2507  $price_min_ttc = $product->multiprices_min_ttc[$object->thirdparty->price_level];
2508  }
2509 
2510  $label = ((GETPOST('update_label') && GETPOST('product_label')) ? GETPOST('product_label') : '');
2511 
2512  // Check price is not lower than minimum (check is done only for standard or replacement invoices)
2513  if ($usermustrespectpricemin && ($object->type == Facture::TYPE_STANDARD || $object->type == Facture::TYPE_REPLACEMENT)) {
2514  if ($pu_ht && $price_min && (((float) price2num($pu_ht) * (1 - (float) $remise_percent / 100)) < (float) price2num($price_min))) {
2515  $mesg = $langs->trans("CantBeLessThanMinPrice", price(price2num($price_min, 'MU'), 0, $langs, 0, 0, -1, $conf->currency));
2516  setEventMessages($mesg, null, 'errors');
2517  $error++;
2518  $action = 'editline';
2519  } elseif ($pu_ttc && $price_min_ttc && ((price2num($pu_ttc) * (1 - (float) $remise_percent / 100)) < price2num($price_min_ttc))) {
2520  $mesg = $langs->trans("CantBeLessThanMinPrice", price(price2num($price_min_ttc, 'MU'), 0, $langs, 0, 0, -1, $conf->currency));
2521  setEventMessages($mesg, null, 'errors');
2522  $error++;
2523  $action = 'editline';
2524  }
2525  }
2526  } else {
2527  $type = GETPOST('type');
2528  $label = (GETPOST('product_label') ? GETPOST('product_label') : '');
2529 
2530  // Check parameters
2531  if (GETPOST('type') < 0) {
2532  setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("Type")), null, 'errors');
2533  $error++;
2534  }
2535  }
2536  if ($qty < 0) {
2537  $langs->load("errors");
2538  setEventMessages($langs->trans('ErrorQtyForCustomerInvoiceCantBeNegative'), null, 'errors');
2539  $error++;
2540  }
2541  if (empty($productid) && (($pu_ht < 0 && empty($conf->global->FACTURE_ENABLE_NEGATIVE_LINES)) || $pu_ht == '') && (($pu_ht_devise < 0 && empty($conf->global->FACTURE_ENABLE_NEGATIVE_LINES)) || $pu_ht_devise == '') && $pu_ttc === '' && $pu_ttc_devise === '' && $object->type != Facture::TYPE_CREDIT_NOTE) { // Unit price can be 0 but not ''
2542  if (($pu_ht < 0 || $pu_ttc < 0) && empty($conf->global->FACTURE_ENABLE_NEGATIVE_LINES)) {
2543  $langs->load("errors");
2544  if ($object->type == $object::TYPE_DEPOSIT) {
2545  // Using negative lines on deposit lead to headach and blocking problems when you want to consume them.
2546  setEventMessages($langs->trans("ErrorLinesCantBeNegativeOnDeposits"), null, 'errors');
2547  } else {
2548  setEventMessages($langs->trans("ErrorFieldCantBeNegativeOnInvoice", $langs->transnoentitiesnoconv("UnitPriceHT"), $langs->transnoentitiesnoconv("CustomerAbsoluteDiscountShort")), null, 'errors');
2549  }
2550  $error++;
2551  } else {
2552  setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("UnitPriceHT")), null, 'errors');
2553  $error++;
2554  }
2555  }
2556 
2557 
2558  // Update line
2559  if (!$error) {
2560  if (empty($usercancreatemargin)) {
2561  foreach ($object->lines as &$line) {
2562  if ($line->id == GETPOST('lineid', 'int')) {
2563  $fournprice = $line->fk_fournprice;
2564  $buyingprice = $line->pa_ht;
2565  break;
2566  }
2567  }
2568  }
2569 
2570  $price_base_type = 'HT';
2571  $pu = $pu_ht;
2572  if (empty($pu) && !empty($pu_ttc)) {
2573  $pu = $pu_ttc;
2574  $price_base_type = 'TTC';
2575  }
2576 
2577  $result = $object->updateline(
2578  GETPOST('lineid', 'int'),
2579  $description,
2580  $pu,
2581  $qty,
2582  $remise_percent,
2583  $date_start,
2584  $date_end,
2585  $vat_rate,
2586  $localtax1_rate,
2587  $localtax2_rate,
2588  $price_base_type,
2589  $info_bits,
2590  $type,
2591  GETPOST('fk_parent_line', 'int'),
2592  0,
2593  $fournprice,
2594  $buyingprice,
2595  $label,
2596  $special_code,
2597  $array_options,
2598  price2num(GETPOST('progress', 'alpha')),
2599  GETPOST('units', 'alpha'),
2600  $pu_ht_devise
2601  );
2602 
2603  if ($result >= 0) {
2604  if (empty($conf->global->MAIN_DISABLE_PDF_AUTOUPDATE)) {
2605  // Define output language
2606  $outputlangs = $langs;
2607  $newlang = '';
2608  if (getDolGlobalInt('MAIN_MULTILANGS') && empty($newlang) && GETPOST('lang_id', 'aZ09')) {
2609  $newlang = GETPOST('lang_id', 'aZ09');
2610  }
2611  if (getDolGlobalInt('MAIN_MULTILANGS') && empty($newlang)) {
2612  $newlang = $object->thirdparty->default_lang;
2613  }
2614  if (!empty($newlang)) {
2615  $outputlangs = new Translate("", $conf);
2616  $outputlangs->setDefaultLang($newlang);
2617  $outputlangs->load('products');
2618  }
2619 
2620  $ret = $object->fetch($id); // Reload to get new records
2621  $object->generateDocument($object->model_pdf, $outputlangs, $hidedetails, $hidedesc, $hideref);
2622  }
2623 
2624  unset($_POST['qty']);
2625  unset($_POST['type']);
2626  unset($_POST['productid']);
2627  unset($_POST['remise_percent']);
2628  unset($_POST['price_ht']);
2629  unset($_POST['multicurrency_price_ht']);
2630  unset($_POST['price_ttc']);
2631  unset($_POST['tva_tx']);
2632  unset($_POST['product_ref']);
2633  unset($_POST['product_label']);
2634  unset($_POST['product_desc']);
2635  unset($_POST['fournprice']);
2636  unset($_POST['buying_price']);
2637  unset($_POST['np_marginRate']);
2638  unset($_POST['np_markRate']);
2639 
2640  unset($_POST['dp_desc']);
2641  unset($_POST['idprod']);
2642  unset($_POST['units']);
2643 
2644  unset($_POST['date_starthour']);
2645  unset($_POST['date_startmin']);
2646  unset($_POST['date_startsec']);
2647  unset($_POST['date_startday']);
2648  unset($_POST['date_startmonth']);
2649  unset($_POST['date_startyear']);
2650  unset($_POST['date_endhour']);
2651  unset($_POST['date_endmin']);
2652  unset($_POST['date_endsec']);
2653  unset($_POST['date_endday']);
2654  unset($_POST['date_endmonth']);
2655  unset($_POST['date_endyear']);
2656 
2657  unset($_POST['situations']);
2658  unset($_POST['progress']);
2659  } else {
2660  setEventMessages($object->error, $object->errors, 'errors');
2661  }
2662  }
2663  } elseif ($action == 'updatealllines' && $usercancreate && GETPOST('all_percent') == $langs->trans('Modifier')) { // Update all lines of situation invoice
2664  if (!$object->fetch($id) > 0) {
2665  dol_print_error($db);
2666  }
2667  if (GETPOST('all_progress') != "") {
2668  $all_progress = GETPOST('all_progress', 'int');
2669  foreach ($object->lines as $line) {
2670  $percent = $line->get_prev_progress($object->id);
2671  if (floatval($all_progress) < floatval($percent)) {
2672  $mesg = $langs->trans("Line").' '.$i.' : '.$langs->trans("CantBeLessThanMinPercent");
2673  setEventMessages($mesg, null, 'warnings');
2674  $result = -1;
2675  } else {
2676  $object->update_percent($line, GETPOST('all_progress'), false);
2677  }
2678  }
2679  $object->update_price(1);
2680  }
2681  } elseif ($action == 'updateline' && $usercancreate && !$cancel) {
2682  header('Location: '.$_SERVER["PHP_SELF"].'?facid='.$id); // To show again edited page
2683  exit();
2684  } elseif ($action == 'confirm_situationout' && $confirm == 'yes' && $usercancreate) {
2685  // Outing situation invoice from cycle
2686  $object->fetch($id, '', '', '', true);
2687 
2688  if (in_array($object->statut, array(Facture::STATUS_CLOSED, Facture::STATUS_VALIDATED))
2689  && $object->type == Facture::TYPE_SITUATION
2690  && $usercancreate
2691  && !$objectidnext
2692  && $object->is_last_in_cycle()
2693  && $usercanunvalidate
2694  ) {
2695  $outingError = 0;
2696  $newCycle = $object->newCycle(); // we need to keep the "situation behavior" so we place it on a new situation cycle
2697  if ($newCycle > 1) {
2698  // Search credit notes
2699  $lastCycle = $object->situation_cycle_ref;
2700  $lastSituationCounter = $object->situation_counter;
2701  $linkedCreditNotesList = array();
2702 
2703  if (count($object->tab_next_situation_invoice) > 0) {
2704  foreach ($object->tab_next_situation_invoice as $next_invoice) {
2705  if ($next_invoice->type == Facture::TYPE_CREDIT_NOTE
2706  && $next_invoice->situation_counter == $object->situation_counter
2707  && $next_invoice->fk_facture_source == $object->id
2708  ) {
2709  $linkedCreditNotesList[] = $next_invoice->id;
2710  }
2711  }
2712  }
2713 
2714  $object->situation_cycle_ref = $newCycle;
2715  $object->situation_counter = 1;
2716  $object->situation_final = 0;
2717  if ($object->update($user) > 0) {
2718  $errors = 0;
2719  if (count($linkedCreditNotesList) > 0) {
2720  // now, credit note must follow
2721  $sql = 'UPDATE '.MAIN_DB_PREFIX.'facture';
2722  $sql .= ' SET situation_cycle_ref = '.((int) $newCycle);
2723  $sql .= ' , situation_final=0';
2724  $sql .= ' , situation_counter='.((int) $object->situation_counter);
2725  $sql .= ' WHERE rowid IN ('.$db->sanitize(implode(',', $linkedCreditNotesList)).')';
2726 
2727  $resql = $db->query($sql);
2728  if (!$resql) {
2729  $errors++;
2730  }
2731 
2732  // Change each progression persent on each lines
2733  foreach ($object->lines as $line) {
2734  // no traitement for special product
2735  if ($line->product_type == 9) {
2736  continue;
2737  }
2738 
2739 
2740  if (!empty($object->tab_previous_situation_invoice)) {
2741  // search the last invoice in cycle
2742  $lineIndex = count($object->tab_previous_situation_invoice) - 1;
2743  $searchPreviousInvoice = true;
2744  while ($searchPreviousInvoice) {
2745  if ($object->tab_previous_situation_invoice[$lineIndex]->type == Facture::TYPE_SITUATION || $lineIndex < 1) {
2746  $searchPreviousInvoice = false; // find, exit;
2747  break;
2748  } else {
2749  $lineIndex--; // go to previous invoice in cycle
2750  }
2751  }
2752 
2753 
2754  $maxPrevSituationPercent = 0;
2755  foreach ($object->tab_previous_situation_invoice[$lineIndex]->lines as $prevLine) {
2756  if ($prevLine->id == $line->fk_prev_id) {
2757  $maxPrevSituationPercent = max($maxPrevSituationPercent, $prevLine->situation_percent);
2758  }
2759  }
2760 
2761 
2762  $line->situation_percent = $line->situation_percent - $maxPrevSituationPercent;
2763 
2764  if ($line->update() < 0) {
2765  $errors++;
2766  }
2767  }
2768  }
2769  }
2770 
2771  if (!$errors) {
2772  setEventMessages($langs->trans('Updated'), null, 'mesgs');
2773  header("Location: ".$_SERVER['PHP_SELF']."?id=".$id);
2774  } else {
2775  setEventMessages($langs->trans('ErrorOutingSituationInvoiceCreditNote'), array(), 'errors');
2776  }
2777  } else {
2778  setEventMessages($langs->trans('ErrorOutingSituationInvoiceOnUpdate'), array(), 'errors');
2779  }
2780  } else {
2781  setEventMessages($langs->trans('ErrorFindNextSituationInvoice'), array(), 'errors');
2782  }
2783  }
2784  } elseif ($action == 'import_lines_from_object'
2785  && $usercancreate
2786  && $object->statut == Facture::STATUS_DRAFT
2787  && ($object->type == Facture::TYPE_STANDARD || $object->type == Facture::TYPE_REPLACEMENT || $object->type == Facture::TYPE_DEPOSIT || $object->type == Facture::TYPE_PROFORMA || $object->type == Facture::TYPE_SITUATION)) {
2788  // add lines from objectlinked
2789  $fromElement = GETPOST('fromelement');
2790  $fromElementid = GETPOST('fromelementid');
2791  $importLines = GETPOST('line_checkbox');
2792 
2793  if (!empty($importLines) && is_array($importLines) && !empty($fromElement) && ctype_alpha($fromElement) && !empty($fromElementid)) {
2794  if ($fromElement == 'commande') {
2795  dol_include_once('/'.$fromElement.'/class/'.$fromElement.'.class.php');
2796  $lineClassName = 'OrderLine';
2797  } elseif ($fromElement == 'propal') {
2798  dol_include_once('/comm/'.$fromElement.'/class/'.$fromElement.'.class.php');
2799  $lineClassName = 'PropaleLigne';
2800  }
2801  $nextRang = count($object->lines) + 1;
2802  $importCount = 0;
2803  $error = 0;
2804  foreach ($importLines as $lineId) {
2805  $lineId = intval($lineId);
2806  $originLine = new $lineClassName($db);
2807  if (intval($fromElementid) > 0 && $originLine->fetch($lineId) > 0) {
2808  $originLine->fetch_optionals();
2809  $desc = $originLine->desc;
2810  $pu_ht = $originLine->subprice;
2811  $qty = $originLine->qty;
2812  $txtva = $originLine->tva_tx;
2813  $txlocaltax1 = $originLine->localtax1_tx;
2814  $txlocaltax2 = $originLine->localtax2_tx;
2815  $fk_product = $originLine->fk_product;
2816  $remise_percent = $originLine->remise_percent;
2817  $date_start = $originLine->date_start;
2818  $date_end = $originLine->date_end;
2819  $ventil = 0;
2820  $info_bits = $originLine->info_bits;
2821  $fk_remise_except = $originLine->fk_remise_except;
2822  $price_base_type = 'HT';
2823  $pu_ttc = 0;
2824  $type = $originLine->product_type;
2825  $rang = $nextRang++;
2826  $special_code = $originLine->special_code;
2827  $origin = $originLine->element;
2828  $origin_id = $originLine->id;
2829  $fk_parent_line = 0;
2830  $fk_fournprice = $originLine->fk_fournprice;
2831  $pa_ht = $originLine->pa_ht;
2832  $label = $originLine->label;
2833  $array_options = $originLine->array_options;
2834  if ($object->type == Facture::TYPE_SITUATION) {
2835  $situation_percent = 0;
2836  } else {
2837  $situation_percent = 100;
2838  }
2839  $fk_prev_id = '';
2840  $fk_unit = $originLine->fk_unit;
2841  $pu_ht_devise = $originLine->multicurrency_subprice;
2842 
2843  $res = $object->addline($desc, $pu_ht, $qty, $txtva, $txlocaltax1, $txlocaltax2, $fk_product, $remise_percent, $date_start, $date_end, $ventil, $info_bits, $fk_remise_except, $price_base_type, $pu_ttc, $type, $rang, $special_code, $origin, $origin_id, $fk_parent_line, $fk_fournprice, $pa_ht, $label, $array_options, $situation_percent, $fk_prev_id, $fk_unit, $pu_ht_devise);
2844 
2845  if ($res > 0) {
2846  $importCount++;
2847  } else {
2848  $error++;
2849  }
2850  } else {
2851  $error++;
2852  }
2853  }
2854 
2855  if ($error) {
2856  setEventMessages($langs->trans('ErrorsOnXLines', $error), null, 'errors');
2857  }
2858  }
2859  }
2860 
2861  // Actions when printing a doc from card
2862  include DOL_DOCUMENT_ROOT.'/core/actions_printing.inc.php';
2863 
2864  // Actions to send emails
2865  if (empty($id)) {
2866  $id = $facid;
2867  }
2868  $triggersendname = 'BILL_SENTBYMAIL';
2869  $paramname = 'id';
2870  $autocopy = 'MAIN_MAIL_AUTOCOPY_INVOICE_TO';
2871  $trackid = 'inv'.$object->id;
2872  include DOL_DOCUMENT_ROOT.'/core/actions_sendmails.inc.php';
2873 
2874  // Actions to build doc
2875  $upload_dir = $conf->facture->multidir_output[!empty($object->entity) ? $object->entity : $conf->entity];
2876  $permissiontoadd = $usercancreate;
2877  include DOL_DOCUMENT_ROOT.'/core/actions_builddoc.inc.php';
2878 
2879 
2880  if ($action == 'update_extras') {
2881  $object->oldcopy = dol_clone($object);
2882 
2883  // Fill array 'array_options' with data from add form
2884  $ret = $extrafields->setOptionalsFromPost(null, $object, GETPOST('attribute', 'restricthtml'));
2885  if ($ret < 0) {
2886  $error++;
2887  }
2888 
2889  if (!$error) {
2890  // Actions on extra fields
2891  $result = $object->insertExtraFields('BILL_MODIFY');
2892  if ($result < 0) {
2893  setEventMessages($object->error, $object->errors, 'errors');
2894  $error++;
2895  }
2896  }
2897 
2898  if ($error) {
2899  $action = 'edit_extras';
2900  }
2901  }
2902 
2903  if (!empty($conf->global->MAIN_DISABLE_CONTACTS_TAB) && $usercancreate) {
2904  if ($action == 'addcontact') {
2905  $result = $object->fetch($id);
2906 
2907  if ($result > 0 && $id > 0) {
2908  $contactid = (GETPOST('userid') ? GETPOST('userid') : GETPOST('contactid'));
2909  $typeid = (GETPOST('typecontact') ? GETPOST('typecontact') : GETPOST('type'));
2910  $result = $object->add_contact($contactid, $typeid, GETPOST("source", 'aZ09'));
2911  }
2912 
2913  if ($result >= 0) {
2914  header("Location: ".$_SERVER['PHP_SELF']."?id=".$object->id);
2915  exit();
2916  } else {
2917  if ($object->error == 'DB_ERROR_RECORD_ALREADY_EXISTS') {
2918  $langs->load("errors");
2919  setEventMessages($langs->trans("ErrorThisContactIsAlreadyDefinedAsThisType"), null, 'errors');
2920  } else {
2921  setEventMessages($object->error, $object->errors, 'errors');
2922  }
2923  }
2924  } elseif ($action == 'swapstatut') {
2925  // bascule du statut d'un contact
2926  if ($object->fetch($id)) {
2927  $result = $object->swapContactStatus(GETPOST('ligne', 'int'));
2928  } else {
2929  dol_print_error($db);
2930  }
2931  } elseif ($action == 'deletecontact') {
2932  // Efface un contact
2933  $object->fetch($id);
2934  $result = $object->delete_contact($lineid);
2935 
2936  if ($result >= 0) {
2937  header("Location: ".$_SERVER['PHP_SELF']."?id=".$object->id);
2938  exit();
2939  } else {
2940  dol_print_error($db);
2941  }
2942  }
2943 
2944  if ($error) {
2945  $action = 'edit_extras';
2946  }
2947  }
2948 }
2949 
2950 
2951 /*
2952  * View
2953  */
2954 
2955 
2956 $form = new Form($db);
2957 $formother = new FormOther($db);
2958 $formfile = new FormFile($db);
2959 $formmargin = new FormMargin($db);
2960 $soc = new Societe($db);
2961 $paymentstatic = new Paiement($db);
2962 $bankaccountstatic = new Account($db);
2963 if (isModEnabled('project')) {
2964  $formproject = new FormProjets($db);
2965 }
2966 
2967 $now = dol_now();
2968 
2969 $title = $object->ref." - ".$langs->trans('Card');
2970 if ($action == 'create') {
2971  $title = $langs->trans("NewBill");
2972 }
2973 $help_url = "EN:Customers_Invoices|FR:Factures_Clients|ES:Facturas_a_clientes";
2974 
2975 llxHeader('', $title, $help_url);
2976 
2977 // Mode creation
2978 
2979 if ($action == 'create') {
2980  $facturestatic = new Facture($db);
2981  $extrafields->fetch_name_optionals_label($facturestatic->table_element);
2982 
2983  print load_fiche_titre($langs->trans('NewBill'), '', 'bill');
2984 
2985  if ($socid > 0) {
2986  $res = $soc->fetch($socid);
2987  }
2988 
2989  $currency_code = $conf->currency;
2990  $fk_account = 0;
2991 
2992  // Load objectsrc
2993  $remise_absolue = 0;
2994  if (!empty($origin) && !empty($originid)) {
2995  // Parse element/subelement (ex: project_task)
2996  $element = $subelement = $origin;
2997  $regs = array();
2998  if (preg_match('/^([^_]+)_([^_]+)/i', $origin, $regs)) {
2999  $element = $regs[1];
3000  $subelement = $regs[2];
3001  }
3002 
3003  if ($element == 'project') {
3004  $projectid = $originid;
3005 
3006  if (empty($cond_reglement_id)) {
3007  $cond_reglement_id = $soc->cond_reglement_id;
3008  }
3009  if (empty($mode_reglement_id)) {
3010  $mode_reglement_id = $soc->mode_reglement_id;
3011  }
3012  if (empty($fk_account)) {
3013  $fk_account = $soc->fk_account;
3014  }
3015  if (!$remise_percent) {
3016  $remise_percent = $soc->remise_percent;
3017  }
3018  if (!$dateinvoice) {
3019  // Do not set 0 here (0 for a date is 1970)
3020  $dateinvoice = (empty($dateinvoice) ? (empty($conf->global->MAIN_AUTOFILL_DATE) ?-1 : '') : $dateinvoice);
3021  }
3022  } else {
3023  // For compatibility
3024  if ($element == 'order' || $element == 'commande') {
3025  $element = $subelement = 'commande';
3026  }
3027  if ($element == 'propal') {
3028  $element = 'comm/propal';
3029  $subelement = 'propal';
3030  }
3031  if ($element == 'contract') {
3032  $element = $subelement = 'contrat';
3033  }
3034  if ($element == 'shipping') {
3035  $element = $subelement = 'expedition';
3036  }
3037 
3038  dol_include_once('/'.$element.'/class/'.$subelement.'.class.php');
3039 
3040  $classname = ucfirst($subelement);
3041  $objectsrc = new $classname($db);
3042  $objectsrc->fetch($originid);
3043  if (empty($objectsrc->lines) && method_exists($objectsrc, 'fetch_lines')) {
3044  $objectsrc->fetch_lines();
3045  }
3046  $objectsrc->fetch_thirdparty();
3047 
3048  $projectid = (!empty($projectid) ? $projectid : $objectsrc->fk_project);
3049  $ref_client = (!empty($objectsrc->ref_client) ? $objectsrc->ref_client : (!empty($objectsrc->ref_customer) ? $objectsrc->ref_customer : ''));
3050 
3051  // only if socid not filled else it's allready done upper
3052  if (empty($socid)) {
3053  $soc = $objectsrc->thirdparty;
3054  }
3055 
3056  $dateinvoice = (empty($dateinvoice) ? (empty($conf->global->MAIN_AUTOFILL_DATE) ?-1 : '') : $dateinvoice);
3057 
3058  if ($element == 'expedition') {
3059  $ref_client = (!empty($objectsrc->ref_customer) ? $objectsrc->ref_customer : '');
3060 
3061  $elem = $subelem = $objectsrc->origin;
3062  $expeoriginid = $objectsrc->origin_id;
3063  dol_include_once('/'.$elem.'/class/'.$subelem.'.class.php');
3064  $classname = ucfirst($subelem);
3065 
3066  $expesrc = new $classname($db);
3067  $expesrc->fetch($expeoriginid);
3068 
3069  $cond_reglement_id = (!empty($expesrc->cond_reglement_id) ? $expesrc->cond_reglement_id : (!empty($soc->cond_reglement_id) ? $soc->cond_reglement_id : 1));
3070  $mode_reglement_id = (!empty($expesrc->mode_reglement_id) ? $expesrc->mode_reglement_id : (!empty($soc->mode_reglement_id) ? $soc->mode_reglement_id : 0));
3071  $fk_account = (!empty($expesrc->fk_account) ? $expesrc->fk_account : (!empty($soc->fk_account) ? $soc->fk_account : 0));
3072  $remise_percent = (!empty($expesrc->remise_percent) ? $expesrc->remise_percent : (!empty($soc->remise_percent) ? $soc->remise_percent : 0));
3073  $remise_absolue = (!empty($expesrc->remise_absolue) ? $expesrc->remise_absolue : (!empty($soc->remise_absolue) ? $soc->remise_absolue : 0));
3074 
3075  if (isModEnabled('multicurrency')) {
3076  $currency_code = (!empty($expesrc->multicurrency_code) ? $expesrc->multicurrency_code : (!empty($soc->multicurrency_code) ? $soc->multicurrency_code : $objectsrc->multicurrency_code));
3077  $currency_tx = (!empty($expesrc->multicurrency_tx) ? $expesrc->multicurrency_tx : (!empty($soc->multicurrency_tx) ? $soc->multicurrency_tx : $objectsrc->multicurrency_tx));
3078  }
3079 
3080  //Replicate extrafields
3081  $expesrc->fetch_optionals();
3082  $object->array_options = $expesrc->array_options;
3083  } else {
3084  $cond_reglement_id = (!empty($objectsrc->cond_reglement_id) ? $objectsrc->cond_reglement_id : (!empty($soc->cond_reglement_id) ? $soc->cond_reglement_id : 0));
3085  $mode_reglement_id = (!empty($objectsrc->mode_reglement_id) ? $objectsrc->mode_reglement_id : (!empty($soc->mode_reglement_id) ? $soc->mode_reglement_id : 0));
3086  $fk_account = (!empty($objectsrc->fk_account) ? $objectsrc->fk_account : (!empty($soc->fk_account) ? $soc->fk_account : 0));
3087  $remise_percent = (!empty($objectsrc->remise_percent) ? $objectsrc->remise_percent : (!empty($soc->remise_percent) ? $soc->remise_percent : 0));
3088  $remise_absolue = (!empty($objectsrc->remise_absolue) ? $objectsrc->remise_absolue : (!empty($soc->remise_absolue) ? $soc->remise_absolue : 0));
3089 
3090  if (isModEnabled('multicurrency')) {
3091  if (!empty($objectsrc->multicurrency_code)) {
3092  $currency_code = $objectsrc->multicurrency_code;
3093  }
3094  if (!empty($conf->global->MULTICURRENCY_USE_ORIGIN_TX) && !empty($objectsrc->multicurrency_tx)) {
3095  $currency_tx = $objectsrc->multicurrency_tx;
3096  }
3097  }
3098 
3099  // Replicate extrafields
3100  $objectsrc->fetch_optionals();
3101  $object->array_options = $objectsrc->array_options;
3102  }
3103  }
3104  } else {
3105  $cond_reglement_id = $soc->cond_reglement_id;
3106  $mode_reglement_id = $soc->mode_reglement_id;
3107  $fk_account = $soc->fk_account;
3108  $remise_percent = $soc->remise_percent;
3109  $remise_absolue = 0;
3110  $dateinvoice = (empty($dateinvoice) ? (empty($conf->global->MAIN_AUTOFILL_DATE) ?-1 : '') : $dateinvoice); // Do not set 0 here (0 for a date is 1970)
3111 
3112  if (isModEnabled('multicurrency') && !empty($soc->multicurrency_code)) {
3113  $currency_code = $soc->multicurrency_code;
3114  }
3115  }
3116 
3117  // when payment condition is empty (means not override by payment condition form a other object, like third-party), try to use default value
3118  if (empty($cond_reglement_id)) {
3119  $cond_reglement_id = GETPOST("cond_reglement_id", 'int');
3120  }
3121 
3122  // when payment mode is empty (means not override by payment mode form a other object, like third-party), try to use default value
3123  if (empty($mode_reglement_id)) {
3124  $mode_reglement_id = GETPOST("mode_reglement_id", 'int');
3125  }
3126 
3127  // when bank account is empty (means not override by payment mode form a other object, like third-party), try to use default value
3128  if ($socid > 0 && $fk_account) { // A company has already been set and it has a default fk_account
3129  $fk_account = GETPOSTISSET('fk_account') ? GETPOST("fk_account", 'int') : $fk_account; // The GETPOST is used only if form was posted to avoid to take default value, because in such case, the default must be the one of the company
3130  } else { // No company forced
3131  $fk_account = GETPOST("fk_account", 'int');
3132  }
3133 
3134  if (!empty($soc->id)) {
3135  $absolute_discount = $soc->getAvailableDiscounts();
3136  }
3137  $note_public = $object->getDefaultCreateValueFor('note_public', ((!empty($origin) && !empty($originid) && is_object($objectsrc) && !empty($conf->global->FACTURE_REUSE_NOTES_ON_CREATE_FROM)) ? $objectsrc->note_public : null));
3138  $note_private = $object->getDefaultCreateValueFor('note_private', ((!empty($origin) && !empty($originid) && is_object($objectsrc) && !empty($conf->global->FACTURE_REUSE_NOTES_ON_CREATE_FROM)) ? $objectsrc->note_private : null));
3139 
3140  if (!empty($conf->use_javascript_ajax)) {
3141  require_once DOL_DOCUMENT_ROOT.'/core/lib/ajax.lib.php';
3142  print ajax_combobox('fac_replacement');
3143  print ajax_combobox('fac_avoir');
3144  print ajax_combobox('situations');
3145  }
3146 
3147  if ($origin == 'contrat') {
3148  $langs->load("admin");
3149  $text = $langs->trans("ToCreateARecurringInvoice");
3150  $text .= ' '.$langs->trans("ToCreateARecurringInvoiceGene", $langs->transnoentitiesnoconv("MenuFinancial"), $langs->transnoentitiesnoconv("BillsCustomers"), $langs->transnoentitiesnoconv("ListOfTemplates"));
3151  if (empty($conf->global->INVOICE_DISABLE_AUTOMATIC_RECURRING_INVOICE)) {
3152  $text .= ' '.$langs->trans("ToCreateARecurringInvoiceGeneAuto", $langs->transnoentitiesnoconv('Module2300Name'));
3153  }
3154  print info_admin($text, 0, 0, 0, 'opacitymedium').'<br>';
3155  }
3156 
3157  print '<form name="add" action="'.$_SERVER["PHP_SELF"].'" method="POST" id="formtocreate" name="formtocreate">';
3158  print '<input type="hidden" name="token" value="'.newToken().'">';
3159  print '<input type="hidden" name="action" id="formtocreateaction" value="add">';
3160  if ($soc->id > 0) {
3161  print '<input type="hidden" name="socid" value="'.$soc->id.'">'."\n";
3162  }
3163  print '<input type="hidden" name="backtopage" value="'.$backtopage.'">';
3164  print '<input type="hidden" name="backtopage" value="'.$backtopage.'">';
3165  print '<input name="ref" type="hidden" value="provisoire">';
3166  print '<input name="ref_client" type="hidden" value="'.$ref_client.'">';
3167  print '<input name="force_cond_reglement_id" type="hidden" value="0">';
3168  print '<input name="force_mode_reglement_id" type="hidden" value="0">';
3169  print '<input name="force_fk_account" type="hidden" value="0">';
3170  print '<input type="hidden" name="origin" value="'.$origin.'">';
3171  print '<input type="hidden" name="originid" value="'.$originid.'">';
3172  print '<input type="hidden" name="originentity" value="'.GETPOST('originentity').'">';
3173  if (!empty($currency_tx)) {
3174  print '<input type="hidden" name="originmulticurrency_tx" value="'.$currency_tx.'">';
3175  }
3176 
3177  print dol_get_fiche_head('');
3178 
3179  print '<table class="border centpercent">';
3180 
3181  // Ref
3182  //print '<tr><td class="titlefieldcreate fieldrequired">'.$langs->trans('Ref').'</td><td colspan="2">'.$langs->trans('Draft').'</td></tr>';
3183 
3184  $exampletemplateinvoice = new FactureRec($db);
3185  $invoice_predefined = new FactureRec($db);
3186  if (empty($origin) && empty($originid) && GETPOST('fac_rec', 'int') > 0) {
3187  $invoice_predefined->fetch(GETPOST('fac_rec', 'int'));
3188  }
3189 
3190  // Thirdparty
3191  if ($soc->id > 0 && (!GETPOST('fac_rec', 'int') || !empty($invoice_predefined->frequency))) {
3192  // If thirdparty known and not a predefined invoiced without a recurring rule
3193  print '<tr><td class="fieldrequired">'.$langs->trans('Customer').'</td>';
3194  print '<td colspan="2">';
3195  print $soc->getNomUrl(1, 'customer');
3196  print '<input type="hidden" name="socid" value="'.$soc->id.'">';
3197  // Outstanding Bill
3198  $arrayoutstandingbills = $soc->getOutstandingBills();
3199  $outstandingBills = $arrayoutstandingbills['opened'];
3200  print ' - <span class="opacitymedium">'.$langs->trans('CurrentOutstandingBill').':</span> ';
3201  print '<span class="amount">'.price($outstandingBills, '', $langs, 0, 0, -1, $conf->currency).'</span>';
3202  if ($soc->outstanding_limit != '') {
3203  if ($outstandingBills > $soc->outstanding_limit) {
3204  print img_warning($langs->trans("OutstandingBillReached"));
3205  }
3206  print ' / '.price($soc->outstanding_limit, '', $langs, 0, 0, -1, $conf->currency);
3207  }
3208  print '</td>';
3209  print '</tr>'."\n";
3210  } else {
3211  print '<tr><td class="fieldrequired">'.$langs->trans('Customer').'</td>';
3212  print '<td colspan="2">';
3213  $filter = '((s.client:IN:1,2,3) AND (s.status:=:1))';
3214  print img_picto('', 'company', 'class="pictofixedwidth"').$form->select_company($soc->id, 'socid', $filter, 'SelectThirdParty', 1, 0, null, 0, 'minwidth300 widthcentpercentminusxx maxwidth500');
3215  // Option to reload page to retrieve customer informations.
3216  if (empty($conf->global->RELOAD_PAGE_ON_CUSTOMER_CHANGE_DISABLED)) {
3217  print '<script>
3218  $(document).ready(function() {
3219  $("#socid").change(function() {
3220  /*
3221  console.log("Submit page");
3222  $(\'input[name="action"]\').val(\'create\');
3223  $(\'input[name="force_cond_reglement_id"]\').val(\'1\');
3224  $(\'input[name="force_mode_reglement_id"]\').val(\'1\');
3225  $(\'input[name="force_fk_account"]\').val(\'1\');
3226  $("#formtocreate").submit(); */
3227 
3228  // For company change, we must submit page with action=create instead of action=add
3229  console.log("We have changed the company - Resubmit page");
3230  jQuery("#formtocreateaction").val("create");
3231  jQuery("#formtocreate").submit();
3232  });
3233  });
3234  </script>';
3235  }
3236  if (!GETPOST('fac_rec', 'int')) {
3237  print ' <a href="'.DOL_URL_ROOT.'/societe/card.php?action=create&client=3&fournisseur=0&backtopage='.urlencode($_SERVER["PHP_SELF"].'?action=create').'"><span class="fa fa-plus-circle valignmiddle paddingleft" title="'.$langs->trans("AddThirdParty").'"></span></a>';
3238  }
3239  print '</td>';
3240  print '</tr>'."\n";
3241  }
3242 
3243  // Overwrite some values if creation of invoice is from a predefined invoice
3244  if (empty($origin) && empty($originid) && GETPOST('fac_rec', 'int') > 0) {
3245  $invoice_predefined->fetch(GETPOST('fac_rec', 'int'));
3246 
3247  $dateinvoice = $invoice_predefined->date_when; // To use next gen date by default later
3248  if (empty($projectid)) {
3249  $projectid = $invoice_predefined->fk_project;
3250  }
3251  $cond_reglement_id = $invoice_predefined->cond_reglement_id;
3252  $mode_reglement_id = $invoice_predefined->mode_reglement_id;
3253  $fk_account = $invoice_predefined->fk_account;
3254  $note_public = $invoice_predefined->note_public;
3255  $note_private = $invoice_predefined->note_private;
3256 
3257  if (!empty($invoice_predefined->multicurrency_code)) {
3258  $currency_code = $invoice_predefined->multicurrency_code;
3259  }
3260  if (!empty($invoice_predefined->multicurrency_tx)) {
3261  $currency_tx = $invoice_predefined->multicurrency_tx;
3262  }
3263 
3264  $sql = 'SELECT r.rowid, r.titre as title, r.total_ttc';
3265  $sql .= ' FROM '.MAIN_DB_PREFIX.'facture_rec as r';
3266  $sql .= ' WHERE r.fk_soc = '.((int) $invoice_predefined->socid);
3267 
3268  $resql = $db->query($sql);
3269  if ($resql) {
3270  $num = $db->num_rows($resql);
3271  $i = 0;
3272 
3273  if ($num > 0) {
3274  print '<tr><td>'.$langs->trans('CreateFromRepeatableInvoice').'</td><td>';
3275  //print '<input type="hidden" name="fac_rec" id="fac_rec" value="'.GETPOST('fac_rec', 'int').'">';
3276  print '<select class="flat" id="fac_rec" name="fac_rec">'; // We may want to change the template to use
3277  print '<option value="0" selected></option>';
3278  while ($i < $num) {
3279  $objp = $db->fetch_object($resql);
3280  print '<option value="'.$objp->rowid.'"';
3281  if (GETPOST('fac_rec', 'int') == $objp->rowid) {
3282  print ' selected';
3283  $exampletemplateinvoice->fetch(GETPOST('fac_rec', 'int'));
3284  }
3285  print '>'.$objp->title.' ('.price($objp->total_ttc).' '.$langs->trans("TTC").')</option>';
3286  $i++;
3287  }
3288  print '</select>';
3289 
3290  print ajax_combobox("fac_rec");
3291 
3292  // Option to reload page to retrieve customer informations. Note, this clear other input
3293  if (empty($conf->global->RELOAD_PAGE_ON_TEMPLATE_CHANGE_DISABLED)) {
3294  print '<script type="text/javascript">
3295  $(document).ready(function() {
3296  $("#fac_rec").change(function() {
3297  console.log("We have changed the template invoice - Reload page");
3298  var fac_rec = $(this).val();
3299  var socid = $(\'#socid\').val();
3300  // For template invoice change, we must reuse data of template, not input already done, so we call a GET with action=create, not a POST submit.
3301  window.location.href = "'.$_SERVER["PHP_SELF"].'?action=create&socid="+socid+"&fac_rec="+fac_rec;
3302  });
3303  });
3304  </script>';
3305  }
3306  print '</td></tr>';
3307  }
3308  $db->free($resql);
3309  } else {
3310  dol_print_error($db);
3311  }
3312  }
3313 
3314  print '<tr><td class="tdtop fieldrequired">'.$langs->trans('Type').'</td><td colspan="2">';
3315  print '<div class="tagtable">'."\n";
3316 
3317  // Standard invoice
3318  print '<div class="tagtr listofinvoicetype"><div class="tagtd listofinvoicetype">';
3319  $tmp = '<input type="radio" id="radio_standard" name="type" value="0"'.(GETPOST('type', 'int') ? '' : ' checked').'> ';
3320  $tmp = $tmp.'<label for="radio_standard" >'.$langs->trans("InvoiceStandardAsk").'</label>';
3321  $desc = $form->textwithpicto($tmp, $langs->transnoentities("InvoiceStandardDesc"), 1, 'help', '', 0, 3, 'standardonsmartphone');
3322  print '<table class="nobordernopadding"><tr>';
3323  print '<td>';
3324  print $desc;
3325  print '</td>';
3326  if ((($origin == 'propal') || ($origin == 'commande')) && (!empty($originid))) {
3327  /*print '<td class="nowrap" style="padding-left: 5px">';
3328  $arraylist = array(
3329  //'amount' => $langs->transnoentitiesnoconv('FixAmount', $langs->transnoentitiesnoconv('Deposit')),
3330  //'variable' => $langs->transnoentitiesnoconv('VarAmountOneLine', $langs->transnoentitiesnoconv('Deposit')),
3331  'variablealllines' => $langs->transnoentitiesnoconv('VarAmountAllLines')
3332  );
3333  print $form->selectarray('typestandard', $arraylist, GETPOST('typestandard', 'aZ09'), 0, 0, 0, '', 1);
3334  print '</td>';*/
3335  print '<td class="nowrap" style="padding-left: 15px">';
3336  print '<span class="opacitymedium">'.$langs->trans('PercentOfOriginalObject').'</span>:<input class="right" placeholder="100%" type="text" id="valuestandardinvoice" name="valuestandardinvoice" size="3" value="'.(GETPOSTISSET('valuestandardinvoice') ? GETPOST('valuestandardinvoice', 'alpha') : '100%').'"/>';
3337  print '</td>';
3338  }
3339  print '</tr></table>';
3340  print '</div></div>';
3341 
3342  if ((empty($origin)) || ((($origin == 'propal') || ($origin == 'commande')) && (!empty($originid)))) {
3343  // Deposit - Down payment
3344  if (empty($conf->global->INVOICE_DISABLE_DEPOSIT)) {
3345  print '<div class="tagtr listofinvoicetype"><div class="tagtd listofinvoicetype">';
3346  $tmp = '<input type="radio" id="radio_deposit" name="type" value="3"'.(GETPOST('type') == 3 ? ' checked' : '').'> ';
3347  print '<script type="text/javascript">
3348  jQuery(document).ready(function() {
3349  jQuery("#typestandardinvoice, #valuestandardinvoice").click(function() {
3350  jQuery("#radio_standard").prop("checked", true);
3351  });
3352  jQuery("#typedeposit, #valuedeposit").click(function() {
3353  jQuery("#radio_deposit").prop("checked", true);
3354  });
3355  jQuery("#typedeposit").change(function() {
3356  console.log("We change type of down payment");
3357  jQuery("#radio_deposit").prop("checked", true);
3358  setRadioForTypeOfIncoice();
3359  });
3360  jQuery("#radio_standard, #radio_deposit, #radio_replacement, #radio_creditnote, #radio_template").change(function() {
3361  setRadioForTypeOfIncoice();
3362  });
3363  function setRadioForTypeOfIncoice() {
3364  console.log("Change radio");
3365  if (jQuery("#radio_deposit").prop("checked") && (jQuery("#typedeposit").val() == \'amount\' || jQuery("#typedeposit").val() == \'variable\')) {
3366  jQuery(".checkforselect").prop("disabled", true);
3367  jQuery(".checkforselect").prop("checked", false);
3368  } else {
3369  jQuery(".checkforselect").prop("disabled", false);
3370  jQuery(".checkforselect").prop("checked", true);
3371  }
3372  }
3373  });
3374  </script>';
3375 
3376  print '<table class="nobordernopadding"><tr>';
3377  print '<td>';
3378  $tmp = $tmp.'<label for="radio_deposit">'.$langs->trans("InvoiceDeposit").'</label>';
3379  $desc = $form->textwithpicto($tmp, $langs->transnoentities("InvoiceDepositDesc"), 1, 'help', '', 0, 3, 'depositonsmartphone');
3380  print $desc;
3381  print '</td>';
3382  if (($origin == 'propal') || ($origin == 'commande')) {
3383  print '<td class="nowrap" style="padding-left: 15px">';
3384  $arraylist = array(
3385  'amount' => $langs->transnoentitiesnoconv('FixAmount', $langs->transnoentitiesnoconv('Deposit')),
3386  'variable' => $langs->transnoentitiesnoconv('VarAmountOneLine', $langs->transnoentitiesnoconv('Deposit')),
3387  'variablealllines' => $langs->transnoentitiesnoconv('VarAmountAllLines')
3388  );
3389  $typedeposit = GETPOST('typedeposit', 'aZ09');
3390  $valuedeposit = GETPOST('valuedeposit', 'int');
3391  if (empty($typedeposit) && !empty($objectsrc->deposit_percent)) {
3392  $origin_payment_conditions_deposit_percent = getDictionaryValue('c_payment_term', 'deposit_percent', $objectsrc->cond_reglement_id);
3393  if (!empty($origin_payment_conditions_deposit_percent)) {
3394  $typedeposit = 'variable';
3395  }
3396  }
3397  if (empty($valuedeposit) && $typedeposit == 'variable' && !empty($objectsrc->deposit_percent)) {
3398  $valuedeposit = $objectsrc->deposit_percent;
3399  }
3400  print $form->selectarray('typedeposit', $arraylist, $typedeposit, 0, 0, 0, '', 1);
3401  print '</td>';
3402  print '<td class="nowrap" style="padding-left: 5px">';
3403  print '<span class="opacitymedium paddingleft">'.$langs->trans("AmountOrPercent").'</span><input type="text" id="valuedeposit" name="valuedeposit" class="width75 right" value="'.$valuedeposit.'"/>';
3404  print '</td>';
3405  }
3406  print '</tr></table>';
3407 
3408  print '</div></div>';
3409  }
3410  }
3411 
3412  if ($socid > 0) {
3413  if (!empty($conf->global->INVOICE_USE_SITUATION)) {
3414  // First situation invoice
3415  print '<div class="tagtr listofinvoicetype"><div class="tagtd listofinvoicetype">';
3416  $tmp = '<input id="radio_situation" type="radio" name="type" value="5"'.(GETPOST('type') == 5 ? ' checked' : '').'> ';
3417  $tmp = $tmp.'<label for="radio_situation" >'.$langs->trans("InvoiceFirstSituationAsk").'</label>';
3418  $desc = $form->textwithpicto($tmp, $langs->transnoentities("InvoiceFirstSituationDesc"), 1, 'help', '', 0, 3, 'firstsituationonsmartphone');
3419  print $desc;
3420  print '</div></div>';
3421 
3422  // Next situation invoice
3423  $opt = $form->selectSituationInvoices(GETPOST('originid', 'int'), $socid);
3424 
3425  print '<div class="tagtr listofinvoicetype"><div class="tagtd listofinvoicetype">';
3426  $tmp = '<input type="radio" name="type" value="5"'.(GETPOST('type') == 5 && GETPOST('originid', 'int') ? ' checked' : '');
3427  if ($opt == ('<option value ="0" selected>'.$langs->trans('NoSituations').'</option>') || (GETPOST('origin') && GETPOST('origin') != 'facture' && GETPOST('origin') != 'commande')) {
3428  $tmp .= ' disabled';
3429  }
3430  $tmp .= '> ';
3431  $text = $tmp.'<label>'.$langs->trans("InvoiceSituationAsk").'</label> ';
3432  $text .= '<select class="flat" id="situations" name="situations"';
3433  if ($opt == ('<option value ="0" selected>'.$langs->trans('NoSituations').'</option>') || (GETPOST('origin') && GETPOST('origin') != 'facture' && GETPOST('origin') != 'commande')) {
3434  $text .= ' disabled';
3435  }
3436  $text .= '>';
3437  $text .= $opt;
3438  $text .= '</select>';
3439  $desc = $form->textwithpicto($text, $langs->transnoentities("InvoiceSituationDesc"), 1, 'help', '', 0, 3);
3440  print $desc;
3441  print '</div></div>';
3442  }
3443 
3444  // Replacement
3445  if (empty($conf->global->INVOICE_DISABLE_REPLACEMENT)) {
3446  // Type de facture
3447  $facids = $facturestatic->list_replacable_invoices($soc->id);
3448  if ($facids < 0) {
3449  dol_print_error($db, $facturestatic->error, $facturestatic->errors);
3450  exit();
3451  }
3452  $options = "";
3453  if (is_array($facids)) {
3454  foreach ($facids as $facparam) {
3455  $options .= '<option value="'.$facparam ['id'].'"';
3456  if ($facparam['id'] == GETPOST('fac_replacement', 'int')) {
3457  $options .= ' selected';
3458  }
3459  $options .= '>'.$facparam['ref'];
3460  $options .= ' ('.$facturestatic->LibStatut($facparam['paid'], $facparam['status'], 0, $facparam['alreadypaid']).')';
3461  $options .= '</option>';
3462  }
3463  }
3464 
3465  print '<!-- replacement line -->';
3466  print '<div class="tagtr listofinvoicetype"><div class="tagtd listofinvoicetype">';
3467  $tmp = '<input type="radio" name="type" id="radio_replacement" value="1"'.(GETPOST('type') == 1 ? ' checked' : '');
3468  if (!$options || $invoice_predefined->id > 0) {
3469  $tmp .= ' disabled';
3470  }
3471  $tmp .= '> ';
3472  print '<script type="text/javascript">
3473  jQuery(document).ready(function() {
3474  jQuery("#fac_replacement").change(function() {
3475  jQuery("#radio_replacement").prop("checked", true);
3476  });
3477  });
3478  </script>';
3479  $text = $tmp.'<label for="radio_replacement">'.$langs->trans("InvoiceReplacementAsk").'</label>';
3480  $text .= '<select class="flat" name="fac_replacement" id="fac_replacement"';
3481  if (!$options || $invoice_predefined->id > 0) {
3482  $text .= ' disabled';
3483  }
3484  $text .= '>';
3485  if ($options) {
3486  $text .= '<option value="-1">&nbsp;</option>';
3487  $text .= $options;
3488  } else {
3489  $text .= '<option value="-1">'.$langs->trans("NoReplacableInvoice").'</option>';
3490  }
3491  $text .= '</select>';
3492  $desc = $form->textwithpicto($text, $langs->transnoentities("InvoiceReplacementDesc"), 1, 'help', '', 0, 3);
3493  print $desc;
3494  print '</div></div>';
3495  }
3496  } else {
3497  if (!empty($conf->global->INVOICE_USE_SITUATION)) {
3498  print '<div class="tagtr listofinvoicetype"><div class="tagtd listofinvoicetype">';
3499  $tmp = '<input type="radio" name="type" id="radio_situation" value="0" disabled> ';
3500  $text = $tmp.'<label>'.$langs->trans("InvoiceSituationAsk").'</label> ';
3501  $text .= '<span class="opacitymedium">('.$langs->trans("YouMustCreateInvoiceFromThird").')</span> ';
3502  $desc = $form->textwithpicto($text, $langs->transnoentities("InvoiceFirstSituationDesc"), 1, 'help', '', 0, 3, 'firstsituationonsmartphone');
3503  print $desc;
3504  print '</div></div>';
3505  }
3506 
3507  print '<div class="tagtr listofinvoicetype"><div class="tagtd listofinvoicetype">';
3508  $tmp = '<input type="radio" name="type" id="radio_replacement" value="0" disabled> ';
3509  $text = $tmp.'<label for="radio_replacement" class="opacitymedium">'.$langs->trans("InvoiceReplacement").'</label> ';
3510  //$text .= '<span class="opacitymedium hideonsmartphone">('.$langs->trans("YouMustCreateInvoiceFromThird").')</span> ';
3511  $desc = $form->textwithpicto($text, $langs->transnoentities("InvoiceReplacementDesc").'<br><br>'.$langs->trans("YouMustCreateInvoiceFromThird"), 1, 'help', '', 0, 3, 'replacementonsmartphone');
3512  print $desc;
3513  print '</div></div>';
3514  }
3515 
3516  if (empty($origin)) {
3517  if ($socid > 0) {
3518  // Credit note
3519  if (empty($conf->global->INVOICE_DISABLE_CREDIT_NOTE)) {
3520  // Show link for credit note
3521  $facids = $facturestatic->list_qualified_avoir_invoices($soc->id);
3522  if ($facids < 0) {
3523  dol_print_error($db, $facturestatic->error, $facturestatic->errors);
3524  exit;
3525  }
3526  $optionsav = "";
3527  $newinvoice_static = new Facture($db);
3528  foreach ($facids as $key => $valarray) {
3529  $newinvoice_static->id = $key;
3530  $newinvoice_static->ref = $valarray ['ref'];
3531  $newinvoice_static->statut = $valarray ['status'];
3532  $newinvoice_static->type = $valarray ['type'];
3533  $newinvoice_static->paye = $valarray ['paye'];
3534 
3535  $optionsav .= '<option value="'.$key.'"';
3536  if ($key == GETPOST('fac_avoir')) {
3537  $optionsav .= ' selected';
3538 
3539  // pre-filled extra fields with selected credit note
3540  $newinvoice_static->fetch_optionals($key);
3541  $object->array_options = $newinvoice_static->array_options;
3542  }
3543  $optionsav .= '>';
3544  $optionsav .= $newinvoice_static->ref;
3545  $optionsav .= ' ('.$newinvoice_static->getLibStatut(1, $valarray ['paymentornot']).')';
3546  $optionsav .= '</option>';
3547  }
3548 
3549  print '<div class="tagtr listofinvoicetype"><div class="tagtd listofinvoicetype">';
3550  $tmp = '<input type="radio" id="radio_creditnote" name="type" value="2"'.(GETPOST('type') == 2 ? ' checked' : '');
3551  if ((!$optionsav && empty($conf->global->INVOICE_CREDIT_NOTE_STANDALONE)) || $invoice_predefined->id > 0) {
3552  $tmp .= ' disabled';
3553  }
3554  $tmp .= '> ';
3555  // Show credit note options only if we checked credit note and disable standard invoice if "create credit note" button is pressed
3556  print '<script type="text/javascript">
3557  jQuery(document).ready(function() {
3558  if (jQuery("#radio_creditnote").is(":checked"))
3559  {
3560  jQuery("#radio_standard").prop("disabled", true);
3561  } else {
3562  jQuery("#radio_standard").prop("disabled", false);
3563  }
3564  if (! jQuery("#radio_creditnote").is(":checked"))
3565  {
3566  jQuery("#credit_note_options").hide();
3567  }
3568  jQuery("#radio_creditnote").click(function() {
3569  jQuery("#credit_note_options").show();
3570  });
3571  jQuery("#radio_standard, #radio_replacement, #radio_deposit").click(function() {
3572  jQuery("#credit_note_options").hide();
3573  });
3574  });
3575  </script>';
3576  $text = '<label>'.$tmp.$langs->transnoentities("InvoiceAvoirAsk").'</label> ';
3577  $text .= '<select class="flat valignmiddle" name="fac_avoir" id="fac_avoir"';
3578  if (!$optionsav || $invoice_predefined->id > 0) {
3579  $text .= ' disabled';
3580  }
3581  $text .= '>';
3582  if ($optionsav) {
3583  $text .= '<option value="-1"></option>';
3584  $text .= $optionsav;
3585  } else {
3586  $text .= '<option value="-1">'.$langs->trans("NoInvoiceToCorrect").'</option>';
3587  }
3588  $text .= '</select>';
3589  $desc = $form->textwithpicto($text, $langs->transnoentities("InvoiceAvoirDesc"), 1, 'help', '', 0, 3);
3590  print $desc;
3591 
3592  print '<div id="credit_note_options" class="clearboth paddingtop marginbottomonly">';
3593  print '&nbsp;&nbsp;&nbsp; <input type="checkbox" name="invoiceAvoirWithLines" id="invoiceAvoirWithLines" value="1" onclick="$(\'#credit_note_options input[type=checkbox]\').not(this).prop(\'checked\', false);" '.(GETPOST('invoiceAvoirWithLines', 'int') > 0 ? 'checked' : '').' /> <label for="invoiceAvoirWithLines">'.$langs->trans('invoiceAvoirWithLines')."</label>";
3594  print '<br>&nbsp;&nbsp;&nbsp; <input type="checkbox" name="invoiceAvoirWithPaymentRestAmount" id="invoiceAvoirWithPaymentRestAmount" value="1" onclick="$(\'#credit_note_options input[type=checkbox]\').not(this).prop(\'checked\', false);" '.(GETPOST('invoiceAvoirWithPaymentRestAmount', 'int') > 0 ? 'checked' : '').' /> <label for="invoiceAvoirWithPaymentRestAmount">'.$langs->trans('invoiceAvoirWithPaymentRestAmount')."</label>";
3595  print '</div>';
3596 
3597  print '</div></div>';
3598  }
3599  } else {
3600  print '<div class="tagtr listofinvoicetype"><div class="tagtd listofinvoicetype">';
3601  if (empty($conf->global->INVOICE_CREDIT_NOTE_STANDALONE)) {
3602  $tmp = '<input type="radio" name="type" id="radio_creditnote" value="0" disabled> ';
3603  } else {
3604  $tmp = '<input type="radio" name="type" id="radio_creditnote" value="2" > ';
3605  }
3606  $text = $tmp.'<label class="opacitymedium" for="radio_creditnote">'.$langs->trans("InvoiceAvoir").'</label> ';
3607  //$text .= '<span class="opacitymedium hideonsmartphone">('.$langs->trans("YouMustCreateInvoiceFromThird").')</span> ';
3608  $desc = $form->textwithpicto($text, $langs->transnoentities("InvoiceAvoirDesc").'<br><br>'.$langs->trans("YouMustCreateInvoiceFromThird"), 1, 'help', '', 0, 3, 'creditnoteonsmartphone');
3609  print $desc;
3610  print '</div></div>'."\n";
3611  }
3612  }
3613 
3614  // Template invoice
3615  print '<div class="tagtr listofinvoicetype"><div class="tagtd listofinvoicetype">';
3616  $tmp = '<input type="radio" name="type" id="radio_template" value="0" disabled> ';
3617  $text = $tmp.'<label class="opacitymedium" for="radio_template">'.$langs->trans("RepeatableInvoice").'</label> ';
3618  $desc = $form->textwithpicto($text, $langs->transnoentities("YouMustCreateStandardInvoiceFirstDesc"), 1, 'help', '', 0, 3, 'templateonsmartphone');
3619  print $desc;
3620  print '</div></div>';
3621 
3622  print '</div>';
3623 
3624 
3625  if (!empty($conf->global->INVOICE_USE_DEFAULT_DOCUMENT)) { // Hidden conf
3626  // Add auto select default document model
3628  $jsListType = '';
3629  foreach ($listtType as $type) {
3630  $thisTypeConfName = 'FACTURE_ADDON_PDF_'.$type;
3631  $curent = getDolGlobalString($thisTypeConfName, getDolGlobalString('FACTURE_ADDON_PDF'));
3632  $jsListType .= (!empty($jsListType) ? ',' : '').'"'.$type.'":"'.$curent.'"';
3633  }
3634 
3635  print '<script type="text/javascript">
3636  $(document).ready(function() {
3637  var listType = {'.$jsListType.'};
3638  $("[name=\'type\'").change(function() {
3639  console.log("change name=type");
3640  if ($( this ).prop("checked"))
3641  {
3642  if(($( this ).val() in listType))
3643  {
3644  $("#model").val(listType[$( this ).val()]);
3645  }
3646  else
3647  {
3648  $("#model").val("'.$conf->global->FACTURE_ADDON_PDF.'");
3649  }
3650  }
3651  });
3652  });
3653  </script>';
3654  }
3655 
3656 
3657  print '</td></tr>';
3658 
3659  if ($socid > 0) {
3660  // Discounts for third party
3661  print '<tr><td>'.$langs->trans('DiscountStillRemaining').'</td><td colspan="2">';
3662 
3663  $thirdparty = $soc;
3664  $discount_type = 0;
3665  $backtopage = urlencode($_SERVER["PHP_SELF"].'?socid='.$thirdparty->id.'&action='.$action.'&origin='.GETPOST('origin', 'alpha').'&originid='.GETPOST('originid', 'int'));
3666  include DOL_DOCUMENT_ROOT.'/core/tpl/object_discounts.tpl.php';
3667 
3668  print '</td></tr>';
3669  }
3670 
3671  $newdateinvoice = dol_mktime(0, 0, 0, GETPOST('remonth', 'int'), GETPOST('reday', 'int'), GETPOST('reyear', 'int'), 'tzserver');
3672  $date_pointoftax = dol_mktime(0, 0, 0, GETPOST('date_pointoftaxmonth', 'int'), GETPOST('date_pointoftaxday', 'int'), GETPOST('date_pointoftaxyear', 'int'), 'tzserver');
3673 
3674  // Date invoice
3675  print '<tr><td class="fieldrequired">'.$langs->trans('DateInvoice').'</td><td colspan="2">';
3676  print img_picto('', 'action', 'class="pictofixedwidth"');
3677  print $form->selectDate($newdateinvoice ? $newdateinvoice : $dateinvoice, '', '', '', '', "add", 1, 1);
3678  print '</td></tr>';
3679 
3680  // Date point of tax
3681  if (!empty($conf->global->INVOICE_POINTOFTAX_DATE)) {
3682  print '<tr><td class="fieldrequired">'.$langs->trans('DatePointOfTax').'</td><td colspan="2">';
3683  print img_picto('', 'action', 'class="pictofixedwidth"');
3684  print $form->selectDate($date_pointoftax ? $date_pointoftax : -1, 'date_pointoftax', '', '', '', "add", 1, 1);
3685  print '</td></tr>';
3686  }
3687 
3688  // Payment term
3689  print '<tr><td class="nowrap fieldrequired">'.$langs->trans('PaymentConditionsShort').'</td><td colspan="2">';
3690  print img_picto('', 'payment', 'class="pictofixedwidth"');
3691  print $form->getSelectConditionsPaiements((GETPOSTISSET('cond_reglement_id') && GETPOST('cond_reglement_id', 'int') != 0) ? GETPOST('cond_reglement_id', 'int') : $cond_reglement_id, 'cond_reglement_id', -1, 1, 0, 'maxwidth500 widthcentpercentminusx');
3692  print '</td></tr>';
3693 
3694 
3695  if (!empty($conf->global->INVOICE_USE_RETAINED_WARRANTY)) {
3696  $rwStyle = 'display:none;';
3697  if (in_array(GETPOST('type', 'int'), $retainedWarrantyInvoiceAvailableType)) {
3698  $rwStyle = '';
3699  }
3700 
3701  $retained_warranty = GETPOST('retained_warranty', 'int');
3702  if (empty($retained_warranty)) {
3703  if (!empty($objectsrc->retained_warranty)) { // use previous situation value
3704  $retained_warranty = $objectsrc->retained_warranty;
3705  }
3706  }
3707  $retained_warranty_js_default = !empty($retained_warranty) ? $retained_warranty : $conf->global->INVOICE_SITUATION_DEFAULT_RETAINED_WARRANTY_PERCENT;
3708 
3709  print '<tr class="retained-warranty-line" style="'.$rwStyle.'" ><td class="nowrap">'.$langs->trans('RetainedWarranty').'</td><td colspan="2">';
3710  print '<input id="new-situation-invoice-retained-warranty" name="retained_warranty" type="number" value="'.$retained_warranty.'" step="0.01" min="0" max="100" />%';
3711 
3712  // Retained warranty payment term
3713  print '<tr class="retained-warranty-line" style="'.$rwStyle.'" ><td class="nowrap">'.$langs->trans('PaymentConditionsShortRetainedWarranty').'</td><td colspan="2">';
3714  $retained_warranty_fk_cond_reglement = GETPOST('retained_warranty_fk_cond_reglement', 'int');
3715  if (empty($retained_warranty_fk_cond_reglement)) {
3716  $retained_warranty_fk_cond_reglement = $conf->global->INVOICE_SITUATION_DEFAULT_RETAINED_WARRANTY_COND_ID;
3717  if (!empty($objectsrc->retained_warranty_fk_cond_reglement)) { // use previous situation value
3718  $retained_warranty_fk_cond_reglement = $objectsrc->retained_warranty_fk_cond_reglement;
3719  } else {
3720  $retained_warranty_fk_cond_reglement = $conf->global->INVOICE_SITUATION_DEFAULT_RETAINED_WARRANTY_COND_ID;
3721  }
3722  }
3723  print $form->getSelectConditionsPaiements($retained_warranty_fk_cond_reglement, 'retained_warranty_fk_cond_reglement', -1, 1);
3724  print '</td></tr>';
3725 
3726  print '<script type="text/javascript">
3727  $(document).ready(function() {
3728  $("[name=\'type\']").change(function() {
3729  if($( this ).prop("checked") && $.inArray($( this ).val(), '.json_encode($retainedWarrantyInvoiceAvailableType).' ) !== -1)
3730  {
3731  $(".retained-warranty-line").show();
3732  $("#new-situation-invoice-retained-warranty").val("'.floatval($retained_warranty_js_default).'");
3733  }
3734  else{
3735  $(".retained-warranty-line").hide();
3736  $("#new-situation-invoice-retained-warranty").val("");
3737  }
3738  });
3739 
3740  $("[name=\'type\']:checked").trigger("change");
3741  });
3742  </script>';
3743  }
3744 
3745  // Payment mode
3746  print '<tr><td>'.$langs->trans('PaymentMode').'</td><td colspan="2">';
3747  print img_picto('', 'bank', 'class="pictofixedwidth"');
3748  print $form->select_types_paiements((GETPOSTISSET('mode_reglement_id') && GETPOST('mode_reglement_id') != 0)? GETPOST('mode_reglement_id') : $mode_reglement_id, 'mode_reglement_id', 'CRDT', 0, 1, 0, 0, 1, 'maxwidth200 widthcentpercentminusx', 1);
3749  print '</td></tr>';
3750 
3751  // Bank Account
3752  if (isModEnabled("banque")) {
3753  print '<tr><td>'.$langs->trans('BankAccount').'</td><td colspan="2">';
3754  print img_picto('', 'bank_account', 'class="pictofixedwidth"');
3755  print $form->select_comptes(($fk_account < 0 ? '' : $fk_account), 'fk_account', 0, '', 1, '', 0, 'maxwidth200 widthcentpercentminusx', 1);
3756  print '</td></tr>';
3757  }
3758 
3759  // Project
3760  if (isModEnabled('project')) {
3761  $langs->load('projects');
3762  print '<tr><td>'.$langs->trans('Project').'</td><td colspan="2">';
3763  print img_picto('', 'project', 'class="pictofixedwidth"').$formproject->select_projects(($socid > 0 ? $socid : -1), $projectid, 'projectid', 0, 0, 1, 1, 0, 0, 0, '', 1, 0, 'maxwidth500 widthcentpercentminusxx');
3764  print ' <a href="'.DOL_URL_ROOT.'/projet/card.php?socid='.$soc->id.'&action=create&status=1&backtopage='.urlencode($_SERVER["PHP_SELF"].'?action=create&socid='.$soc->id.($fac_rec ? '&fac_rec='.$fac_rec : '')).'"><span class="fa fa-plus-circle valignmiddle" title="'.$langs->trans("AddProject").'"></span></a>';
3765  print '</td></tr>';
3766  }
3767 
3768  // Incoterms
3769  if (isModEnabled('incoterm')) {
3770  print '<tr>';
3771  print '<td><label for="incoterm_id">'.$form->textwithpicto($langs->trans("IncotermLabel"), !empty($objectsrc->label_incoterms) ? $objectsrc->label_incoterms : '', 1).'</label></td>';
3772  print '<td colspan="2" class="maxwidthonsmartphone">';
3773  $incoterm_id = GETPOST('incoterm_id');
3774  $incoterm_location = GETPOST('location_incoterms');
3775  if (empty($incoterm_id)) {
3776  $incoterm_id = (!empty($objectsrc->fk_incoterms) ? $objectsrc->fk_incoterms : $soc->fk_incoterms);
3777  $incoterm_location = (!empty($objectsrc->location_incoterms) ? $objectsrc->location_incoterms : $soc->location_incoterms);
3778  }
3779  print img_picto('', 'incoterm', 'class="pictofixedwidth"');
3780  print $form->select_incoterms($incoterm_id, $incoterm_location);
3781  print '</td></tr>';
3782  }
3783 
3784  // Other attributes
3785  $parameters = array('objectsrc' => !empty($objectsrc) ? $objectsrc : 0, 'colspan' => ' colspan="2"', 'cols' => '2', 'socid'=>$socid);
3786  $reshook = $hookmanager->executeHooks('formObjectOptions', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
3787  print $hookmanager->resPrint;
3788  if (empty($reshook)) {
3789  if (!empty($conf->global->THIRDPARTY_PROPAGATE_EXTRAFIELDS_TO_INVOICE) && !empty($soc->id)) {
3790  // copy from thirdparty
3791  $tpExtrafields = new ExtraFields($db);
3792  $tpExtrafieldLabels = $tpExtrafields->fetch_name_optionals_label($soc->table_element);
3793  if ($soc->fetch_optionals() > 0) {
3794  $object->array_options = array_merge($object->array_options, $soc->array_options);
3795  }
3796  }
3797 
3798  print $object->showOptionals($extrafields, 'create', $parameters);
3799  }
3800 
3801  // Template to use by default
3802  print '<tr><td>'.$langs->trans('Model').'</td>';
3803  print '<td colspan="2">';
3804  print img_picto('', 'pdf', 'class="pictofixedwidth"');
3805  include_once DOL_DOCUMENT_ROOT.'/core/modules/facture/modules_facture.php';
3806  $liste = ModelePDFFactures::liste_modeles($db);
3807  if (!empty($conf->global->INVOICE_USE_DEFAULT_DOCUMENT)) {
3808  // Hidden conf
3809  $paramkey = 'FACTURE_ADDON_PDF_'.$object->type;
3810  $preselected = !empty($conf->global->$paramkey) ? $conf->global->$paramkey : $conf->global->FACTURE_ADDON_PDF;
3811  } else {
3812  $preselected = $conf->global->FACTURE_ADDON_PDF;
3813  }
3814  print $form->selectarray('model', $liste, $preselected, 0, 0, 0, '', 0, 0, 0, '', 'maxwidth200 widthcentpercentminusx', 1);
3815  print "</td></tr>";
3816 
3817  // Multicurrency
3818  if (isModEnabled('multicurrency')) {
3819  print '<tr>';
3820  print '<td>'.$form->editfieldkey('Currency', 'multicurrency_code', '', $object, 0).'</td>';
3821  print '<td colspan="2" class="maxwidthonsmartphone">';
3822  print img_picto('', 'currency', 'class="pictofixedwidth"');
3823  print $form->selectMultiCurrency($currency_code, 'multicurrency_code');
3824  print '</td></tr>';
3825  }
3826 
3827  // Help of substitution key
3828  $htmltext = '';
3829  if (GETPOST('fac_rec', 'int') > 0) {
3830  $dateexample = ($newdateinvoice ? $newdateinvoice : $dateinvoice);
3831  if (empty($dateexample)) {
3832  $dateexample = dol_now();
3833  }
3834  $substitutionarray = array(
3835  '__TOTAL_HT__' => $langs->trans("AmountHT").' ('.$langs->trans("Example").': '.price($exampletemplateinvoice->total_ht).')',
3836  '__TOTAL_TTC__' => $langs->trans("AmountTTC").' ('.$langs->trans("Example").': '.price($exampletemplateinvoice->total_ttc).')',
3837  '__INVOICE_PREVIOUS_MONTH__' => $langs->trans("PreviousMonthOfInvoice").' ('.$langs->trans("Example").': '.dol_print_date(dol_time_plus_duree($dateexample, -1, 'm'), '%m').')',
3838  '__INVOICE_MONTH__' => $langs->trans("MonthOfInvoice").' ('.$langs->trans("Example").': '.dol_print_date($dateexample, '%m').')',
3839  '__INVOICE_NEXT_MONTH__' => $langs->trans("NextMonthOfInvoice").' ('.$langs->trans("Example").': '.dol_print_date(dol_time_plus_duree($dateexample, 1, 'm'), '%m').')',
3840  '__INVOICE_PREVIOUS_MONTH_TEXT__' => $langs->trans("TextPreviousMonthOfInvoice").' ('.$langs->trans("Example").': '.dol_print_date(dol_time_plus_duree($dateexample, -1, 'm'), '%B').')',
3841  '__INVOICE_MONTH_TEXT__' => $langs->trans("TextMonthOfInvoice").' ('.$langs->trans("Example").': '.dol_print_date($dateexample, '%B').')',
3842  '__INVOICE_NEXT_MONTH_TEXT__' => $langs->trans("TextNextMonthOfInvoice").' ('.$langs->trans("Example").': '.dol_print_date(dol_time_plus_duree($dateexample, 1, 'm'), '%B').')',
3843  '__INVOICE_PREVIOUS_YEAR__' => $langs->trans("PreviousYearOfInvoice").' ('.$langs->trans("Example").': '.dol_print_date(dol_time_plus_duree($dateexample, -1, 'y'), '%Y').')',
3844  '__INVOICE_YEAR__' => $langs->trans("YearOfInvoice").' ('.$langs->trans("Example").': '.dol_print_date($dateexample, '%Y').')',
3845  '__INVOICE_NEXT_YEAR__' => $langs->trans("NextYearOfInvoice").' ('.$langs->trans("Example").': '.dol_print_date(dol_time_plus_duree($dateexample, 1, 'y'), '%Y').')'
3846  );
3847 
3848  $htmltext = '<i>'.$langs->trans("FollowingConstantsWillBeSubstituted").':<br>';
3849  foreach ($substitutionarray as $key => $val) {
3850  $htmltext .= $key.' = '.$langs->trans($val).'<br>';
3851  }
3852  $htmltext .= '</i>';
3853  }
3854 
3855  // Public note
3856  print '<tr>';
3857  print '<td class="tdtop">';
3858  print $form->textwithpicto($langs->trans('NotePublic'), $htmltext);
3859  print '</td>';
3860  print '<td valign="top" colspan="2">';
3861  $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%');
3862  print $doleditor->Create(1);
3863 
3864  // Private note
3865  if (empty($user->socid)) {
3866  print '<tr>';
3867  print '<td class="tdtop">';
3868  print $form->textwithpicto($langs->trans('NotePrivate'), $htmltext);
3869  print '</td>';
3870  print '<td valign="top" colspan="2">';
3871  $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%');
3872  print $doleditor->Create(1);
3873  // print '<textarea name="note_private" wrap="soft" cols="70" rows="'.ROWS_3.'">'.$note_private.'.</textarea>
3874  print '</td></tr>';
3875  }
3876 
3877  // Lines from source (TODO Show them also when creating invoice from template invoice)
3878  if (!empty($origin) && !empty($originid) && is_object($objectsrc)) {
3879  $langs->loadLangs(array('orders', 'propal'));
3880 
3881  // TODO for compatibility
3882  if ($origin == 'contrat') {
3883  // Calcul contrat->price (HT), contrat->total (TTC), contrat->tva
3884  $objectsrc->remise_absolue = $remise_absolue;
3885  $objectsrc->remise_percent = $remise_percent;
3886  $objectsrc->update_price(1, 'auto', 1);
3887  }
3888 
3889  print "\n<!-- Show ref of origin ".$classname." -->\n";
3890  print '<input type="hidden" name="amount" value="'.$objectsrc->total_ht.'">'."\n";
3891  print '<input type="hidden" name="total" value="'.$objectsrc->total_ttc.'">'."\n";
3892  print '<input type="hidden" name="tva" value="'.$objectsrc->total_tva.'">'."\n";
3893  // The commented lines below are fields already added as hidden parameters before
3894  //print '<input type="hidden" name="origin" value="'.$objectsrc->element.'">';
3895  //print '<input type="hidden" name="originid" value="'.$objectsrc->id.'">';
3896 
3897  switch (get_class($objectsrc)) {
3898  case 'Propal':
3899  $newclassname = 'CommercialProposal';
3900  break;
3901  case 'Commande':
3902  $newclassname = 'Order';
3903  break;
3904  case 'Expedition':
3905  $newclassname = 'Sending';
3906  break;
3907  case 'Contrat':
3908  $newclassname = 'Contract';
3909  break;
3910  case 'Fichinter':
3911  $newclassname = 'Intervention';
3912  break;
3913  default:
3914  $newclassname = get_class($objectsrc);
3915  }
3916 
3917  // Ref of origin
3918  print '<tr><td>'.$langs->trans($newclassname).'</td>';
3919  print '<td colspan="2">';
3920  print $objectsrc->getNomUrl(1);
3921  // We check if Origin document (id and type is known) has already at least one invoice attached to it
3922  $objectsrc->fetchObjectLinked($originid, $origin, '', 'facture');
3923  if (isset($objectsrc->linkedObjects['facture']) && is_array($objectsrc->linkedObjects['facture']) && count($objectsrc->linkedObjects['facture']) >= 1) {
3924  setEventMessages('WarningBillExist', null, 'warnings');
3925  echo ' - '.$langs->trans('LatestRelatedBill').' '.end($objectsrc->linkedObjects['facture'])->getNomUrl(1);
3926  }
3927  echo '</td></tr>';
3928  print '<tr><td>'.$langs->trans('AmountHT').'</td><td colspan="2">'.price($objectsrc->total_ht).'</td></tr>';
3929  print '<tr><td>'.$langs->trans('AmountVAT').'</td><td colspan="2">'.price($objectsrc->total_tva)."</td></tr>";
3930  if ($mysoc->localtax1_assuj == "1" || $objectsrc->total_localtax1 != 0) { // Localtax1
3931  print '<tr><td>'.$langs->transcountry("AmountLT1", $mysoc->country_code).'</td><td colspan="2">'.price($objectsrc->total_localtax1)."</td></tr>";
3932  }
3933 
3934  if ($mysoc->localtax2_assuj == "1" || $objectsrc->total_localtax2 != 0) { // Localtax2
3935  print '<tr><td>'.$langs->transcountry("AmountLT2", $mysoc->country_code).'</td><td colspan="2">'.price($objectsrc->total_localtax2)."</td></tr>";
3936  }
3937  print '<tr><td>'.$langs->trans('AmountTTC').'</td><td colspan="2">'.price($objectsrc->total_ttc)."</td></tr>";
3938 
3939  if (isModEnabled('multicurrency')) {
3940  print '<tr><td>'.$langs->trans('MulticurrencyAmountHT').'</td><td colspan="2">'.price($objectsrc->multicurrency_total_ht).'</td></tr>';
3941  print '<tr><td>'.$langs->trans('MulticurrencyAmountVAT').'</td><td colspan="2">'.price($objectsrc->multicurrency_total_tva)."</td></tr>";
3942  print '<tr><td>'.$langs->trans('MulticurrencyAmountTTC').'</td><td colspan="2">'.price($objectsrc->multicurrency_total_ttc)."</td></tr>";
3943  }
3944  }
3945 
3946  print "</table>\n";
3947 
3948  print dol_get_fiche_end();
3949 
3950  print $form->buttonsSaveCancel("CreateDraft");
3951 
3952  // Show origin lines
3953  if (!empty($origin) && !empty($originid) && is_object($objectsrc)) {
3954  print '<br>';
3955 
3956  $title = $langs->trans('ProductsAndServices');
3957  print load_fiche_titre($title);
3958 
3959  print '<div class="div-table-responsive-no-min">';
3960  print '<table class="noborder centpercent">';
3961 
3962  $objectsrc->printOriginLinesList('', $selectedLines);
3963 
3964  print '</table>';
3965  print '</div>';
3966  }
3967 
3968  print "</form>\n";
3969 } elseif ($id > 0 || !empty($ref)) {
3970  if (empty($object->id)) {
3971  $langs->load('errors');
3972  echo '<div class="error">'.$langs->trans("ErrorRecordNotFound").'</div>';
3973  llxFooter();
3974  exit;
3975  }
3976 
3977  /*
3978  * Show object in view mode
3979  */
3980 
3981  $result = $object->fetch($id, $ref);
3982  if ($result <= 0) {
3983  dol_print_error($db, $object->error, $object->errors);
3984  exit();
3985  }
3986 
3987  // fetch optionals attributes and labels
3988  $extrafields->fetch_name_optionals_label($object->table_element);
3989 
3990  if ($user->socid > 0 && $user->socid != $object->socid) {
3991  accessforbidden('', 0, 1);
3992  }
3993 
3994  $result = $object->fetch_thirdparty();
3995 
3996  $result = $soc->fetch($object->socid);
3997  if ($result < 0) {
3998  dol_print_error($db);
3999  }
4000  $selleruserevenustamp = $mysoc->useRevenueStamp();
4001 
4002  $totalpaid = $object->getSommePaiement();
4003  $totalcreditnotes = $object->getSumCreditNotesUsed();
4004  $totaldeposits = $object->getSumDepositsUsed();
4005  //print "totalpaid=".$totalpaid." totalcreditnotes=".$totalcreditnotes." totaldeposts=".$totaldeposits."
4006  // selleruserrevenuestamp=".$selleruserevenustamp;
4007 
4008  // We can also use bcadd to avoid pb with floating points
4009  // For example print 239.2 - 229.3 - 9.9; does not return 0.
4010  // $resteapayer=bcadd($object->total_ttc,$totalpaid,$conf->global->MAIN_MAX_DECIMALS_TOT);
4011  // $resteapayer=bcadd($resteapayer,$totalavoir,$conf->global->MAIN_MAX_DECIMALS_TOT);
4012  $resteapayer = price2num($object->total_ttc - $totalpaid - $totalcreditnotes - $totaldeposits, 'MT');
4013 
4014  // Multicurrency
4015  if (isModEnabled('multicurrency')) {
4016  $multicurrency_totalpaid = $object->getSommePaiement(1);
4017  $multicurrency_totalcreditnotes = $object->getSumCreditNotesUsed(1);
4018  $multicurrency_totaldeposits = $object->getSumDepositsUsed(1);
4019  $multicurrency_resteapayer = price2num($object->multicurrency_total_ttc - $multicurrency_totalpaid - $multicurrency_totalcreditnotes - $multicurrency_totaldeposits, 'MT');
4020  // Code to fix case of corrupted data
4021  // TODO We should not need this. Also data comes from a not reliable value of $object->multicurrency_total_ttc that may be wrong if it was
4022  // calculated by summing lines that were in a currency for some of them and into another for others (lines from discount/down payment into another currency for example)
4023  if ($resteapayer == 0 && $multicurrency_resteapayer != 0 && $object->multicurrency_code != $conf->currency) {
4024  $resteapayer = price2num($multicurrency_resteapayer / $object->multicurrency_tx, 'MT');
4025  }
4026  }
4027 
4028  if ($object->paye) {
4029  $resteapayer = 0;
4030  }
4031  $resteapayeraffiche = $resteapayer;
4032 
4033  if (!empty($conf->global->FACTURE_DEPOSITS_ARE_JUST_PAYMENTS)) { // Never use this
4034  $filterabsolutediscount = "fk_facture_source IS NULL"; // If we want deposit to be substracted to payments only and not to total of final invoice
4035  $filtercreditnote = "fk_facture_source IS NOT NULL"; // If we want deposit to be substracted to payments only and not to total of final invoice
4036  } else {
4037  $filterabsolutediscount = "fk_facture_source IS NULL OR (description LIKE '(DEPOSIT)%' AND description NOT LIKE '(EXCESS RECEIVED)%')";
4038  $filtercreditnote = "fk_facture_source IS NOT NULL AND (description NOT LIKE '(DEPOSIT)%' OR description LIKE '(EXCESS RECEIVED)%')";
4039  }
4040 
4041  $absolute_discount = $soc->getAvailableDiscounts('', $filterabsolutediscount);
4042  $absolute_creditnote = $soc->getAvailableDiscounts('', $filtercreditnote);
4043  $absolute_discount = price2num($absolute_discount, 'MT');
4044  $absolute_creditnote = price2num($absolute_creditnote, 'MT');
4045 
4046  $author = new User($db);
4047  if ($object->user_author) {
4048  $author->fetch($object->user_author);
4049  }
4050 
4051  $objectidnext = $object->getIdReplacingInvoice();
4052 
4053  $head = facture_prepare_head($object);
4054 
4055  print dol_get_fiche_head($head, 'compta', $langs->trans('InvoiceCustomer'), -1, 'bill');
4056 
4057  $formconfirm = '';
4058 
4059  // Confirmation de la conversion de l'avoir en reduc
4060  if ($action == 'converttoreduc') {
4061  if ($object->type == Facture::TYPE_STANDARD || $object->type == Facture::TYPE_SITUATION) {
4062  $type_fac = 'ExcessReceived';
4063  } elseif ($object->type == Facture::TYPE_CREDIT_NOTE) {
4064  $type_fac = 'CreditNote';
4065  } elseif ($object->type == Facture::TYPE_DEPOSIT) {
4066  $type_fac = 'Deposit';
4067  }
4068  $text = $langs->trans('ConfirmConvertToReduc', strtolower($langs->transnoentities($type_fac)));
4069  $text .= '<br>'.$langs->trans('ConfirmConvertToReduc2');
4070  $formconfirm = $form->formconfirm($_SERVER['PHP_SELF'].'?facid='.$object->id, $langs->trans('ConvertToReduc'), $text, 'confirm_converttoreduc', '', "yes", 2);
4071  }
4072 
4073  // Confirmation to delete invoice
4074  if ($action == 'delete') {
4075  $text = $langs->trans('ConfirmDeleteBill', $object->ref);
4076  $formquestion = array();
4077 
4078  if ($object->type != Facture::TYPE_DEPOSIT && !empty($conf->global->STOCK_CALCULATE_ON_BILL) && $object->statut >= 1) {
4079  $qualified_for_stock_change = 0;
4080  if (empty($conf->global->STOCK_SUPPORTS_SERVICES)) {
4081  $qualified_for_stock_change = $object->hasProductsOrServices(2);
4082  } else {
4083  $qualified_for_stock_change = $object->hasProductsOrServices(1);
4084  }
4085 
4086  if ($qualified_for_stock_change) {
4087  $langs->load("stocks");
4088  require_once DOL_DOCUMENT_ROOT.'/product/class/html.formproduct.class.php';
4089  $formproduct = new FormProduct($db);
4090  $label = $object->type == Facture::TYPE_CREDIT_NOTE ? $langs->trans("SelectWarehouseForStockDecrease") : $langs->trans("SelectWarehouseForStockIncrease");
4091  $forcecombo = 0;
4092  if ($conf->browser->name == 'ie') {
4093  $forcecombo = 1; // There is a bug in IE10 that make combo inside popup crazy
4094  }
4095  $formquestion = array(
4096  // 'text' => $langs->trans("ConfirmClone"),
4097  // array('type' => 'checkbox', 'name' => 'clone_content', 'label' => $langs->trans("CloneMainAttributes"), 'value' => 1),
4098  // array('type' => 'checkbox', 'name' => 'update_prices', 'label' => $langs->trans("PuttingPricesUpToDate"), 'value' => 1),
4099  array('type' => 'other', 'name' => 'idwarehouse', 'label' => $label, 'value' => $formproduct->selectWarehouses(GETPOST('idwarehouse') ?GETPOST('idwarehouse') : 'ifone', 'idwarehouse', '', 1, 0, 0, $langs->trans("NoStockAction"), 0, $forcecombo))
4100  );
4101  $formconfirm = $form->formconfirm($_SERVER['PHP_SELF'].'?facid='.$object->id, $langs->trans('DeleteBill'), $text, 'confirm_delete', $formquestion, "yes", 1);
4102  } else {
4103  $formconfirm = $form->formconfirm($_SERVER['PHP_SELF'].'?facid='.$object->id, $langs->trans('DeleteBill'), $text, 'confirm_delete', '', 'no', 1);
4104  }
4105  } else {
4106  $formconfirm = $form->formconfirm($_SERVER['PHP_SELF'].'?facid='.$object->id, $langs->trans('DeleteBill'), $text, 'confirm_delete', '', 'no', 1);
4107  }
4108  }
4109 
4110  // Confirmation to remove invoice from cycle
4111  if ($action == 'situationout') {
4112  $text = $langs->trans('ConfirmRemoveSituationFromCycle', $object->ref);
4113  $label = $langs->trans("ConfirmOuting");
4114  $formquestion = array();
4115  // remove situation from cycle
4116  if (in_array($object->statut, array(Facture::STATUS_CLOSED, Facture::STATUS_VALIDATED))
4117  && $usercancreate
4118  && !$objectidnext
4119  && $object->is_last_in_cycle()
4120  && $usercanunvalidate
4121  ) {
4122  $formconfirm = $form->formconfirm($_SERVER['PHP_SELF'].'?facid='.$object->id, $label, $text, 'confirm_situationout', $formquestion, "yes", 1);
4123  }
4124  }
4125 
4126  // Confirmation of validation
4127  if ($action == 'valid') {
4128  // we check object has a draft number
4129  $objectref = substr($object->ref, 1, 4);
4130  if ($objectref == 'PROV') {
4131  $savdate = $object->date;
4132  if (!empty($conf->global->FAC_FORCE_DATE_VALIDATION)) {
4133  $object->date = dol_now();
4134  $object->date_lim_reglement = $object->calculate_date_lim_reglement();
4135  }
4136  $numref = $object->getNextNumRef($soc);
4137  // $object->date=$savdate;
4138  } else {
4139  $numref = $object->ref;
4140  }
4141 
4142  $text = $langs->trans('ConfirmValidateBill', $numref);
4143  if (isModEnabled('notification')) {
4144  require_once DOL_DOCUMENT_ROOT.'/core/class/notify.class.php';
4145  $notify = new Notify($db);
4146  $text .= '<br>';
4147  $text .= $notify->confirmMessage('BILL_VALIDATE', $object->socid, $object);
4148  }
4149  $formquestion = array();
4150 
4151  if ($object->type != Facture::TYPE_DEPOSIT && !empty($conf->global->STOCK_CALCULATE_ON_BILL)) {
4152  $qualified_for_stock_change = 0;
4153  if (empty($conf->global->STOCK_SUPPORTS_SERVICES)) {
4154  $qualified_for_stock_change = $object->hasProductsOrServices(2);
4155  } else {
4156  $qualified_for_stock_change = $object->hasProductsOrServices(1);
4157  }
4158 
4159  if ($qualified_for_stock_change) {
4160  $langs->load("stocks");
4161  require_once DOL_DOCUMENT_ROOT.'/product/class/html.formproduct.class.php';
4162  require_once DOL_DOCUMENT_ROOT.'/product/stock/class/entrepot.class.php';
4163  $formproduct = new FormProduct($db);
4164  $warehouse = new Entrepot($db);
4165  $warehouse_array = $warehouse->list_array();
4166  if (count($warehouse_array) == 1) {
4167  $label = $object->type == Facture::TYPE_CREDIT_NOTE ? $langs->trans("WarehouseForStockIncrease", current($warehouse_array)) : $langs->trans("WarehouseForStockDecrease", current($warehouse_array));
4168  $value = '<input type="hidden" id="idwarehouse" name="idwarehouse" value="'.key($warehouse_array).'">';
4169  } else {
4170  $label = $object->type == Facture::TYPE_CREDIT_NOTE ? $langs->trans("SelectWarehouseForStockIncrease") : $langs->trans("SelectWarehouseForStockDecrease");
4171  $value = $formproduct->selectWarehouses(GETPOST('idwarehouse') ?GETPOST('idwarehouse') : 'ifone', 'idwarehouse', '', 1);
4172  }
4173  $formquestion = array(
4174  // 'text' => $langs->trans("ConfirmClone"),
4175  // array('type' => 'checkbox', 'name' => 'clone_content', 'label' => $langs->trans("CloneMainAttributes"), 'value' =>
4176  // 1),
4177  // array('type' => 'checkbox', 'name' => 'update_prices', 'label' => $langs->trans("PuttingPricesUpToDate"), 'value'
4178  // => 1),
4179  array('type' => 'other', 'name' => 'idwarehouse', 'label' => $label, 'value' => $value));
4180  }
4181  }
4182  if ($object->type != Facture::TYPE_CREDIT_NOTE && $object->total_ttc < 0) { // Can happen only if $conf->global->FACTURE_ENABLE_NEGATIVE is on
4183  $text .= '<br>'.img_warning().' '.$langs->trans("ErrorInvoiceOfThisTypeMustBePositive");
4184  }
4185 
4186  // mandatoryPeriod
4187  $nbMandated = 0;
4188  foreach ($object->lines as $line) {
4189  $res = $line->fetch_product();
4190  if ($res > 0 ) {
4191  if ($line->product->isService() && $line->product->isMandatoryPeriod() && (empty($line->date_start) || empty($line->date_end) )) {
4192  $nbMandated++;
4193  break;
4194  }
4195  }
4196  }
4197  if ($nbMandated > 0 ) $text .= '<div><span class="clearboth nowraponall warning">'.$langs->trans("mandatoryPeriodNeedTobeSetMsgValidate").'</span></div>';
4198 
4199 
4200  $formconfirm = $form->formconfirm($_SERVER["PHP_SELF"].'?facid='.$object->id, $langs->trans('ValidateBill'), $text, 'confirm_valid', $formquestion, (($object->type != Facture::TYPE_CREDIT_NOTE && $object->total_ttc < 0) ? "no" : "yes"), 2);
4201  }
4202 
4203  // Confirm back to draft status
4204  if ($action == 'modif') {
4205  $text = $langs->trans('ConfirmUnvalidateBill', $object->ref);
4206  $formquestion = array();
4207 
4208  if ($object->type != Facture::TYPE_DEPOSIT && !empty($conf->global->STOCK_CALCULATE_ON_BILL)) {
4209  $qualified_for_stock_change = 0;
4210  if (empty($conf->global->STOCK_SUPPORTS_SERVICES)) {
4211  $qualified_for_stock_change = $object->hasProductsOrServices(2);
4212  } else {
4213  $qualified_for_stock_change = $object->hasProductsOrServices(1);
4214  }
4215 
4216  if ($qualified_for_stock_change) {
4217  $langs->load("stocks");
4218  require_once DOL_DOCUMENT_ROOT.'/product/class/html.formproduct.class.php';
4219  require_once DOL_DOCUMENT_ROOT.'/product/stock/class/entrepot.class.php';
4220  $formproduct = new FormProduct($db);
4221  $warehouse = new Entrepot($db);
4222  $warehouse_array = $warehouse->list_array();
4223  if (count($warehouse_array) == 1) {
4224  $label = $object->type == Facture::TYPE_CREDIT_NOTE ? $langs->trans("WarehouseForStockDecrease", current($warehouse_array)) : $langs->trans("WarehouseForStockIncrease", current($warehouse_array));
4225  $value = '<input type="hidden" id="idwarehouse" name="idwarehouse" value="'.key($warehouse_array).'">';
4226  } else {
4227  $label = $object->type == Facture::TYPE_CREDIT_NOTE ? $langs->trans("SelectWarehouseForStockDecrease") : $langs->trans("SelectWarehouseForStockIncrease");
4228  $value = $formproduct->selectWarehouses(GETPOST('idwarehouse') ?GETPOST('idwarehouse') : 'ifone', 'idwarehouse', '', 1);
4229  }
4230  $formquestion = array(
4231  // 'text' => $langs->trans("ConfirmClone"),
4232  // array('type' => 'checkbox', 'name' => 'clone_content', 'label' => $langs->trans("CloneMainAttributes"), 'value' =>
4233  // 1),
4234  // array('type' => 'checkbox', 'name' => 'update_prices', 'label' => $langs->trans("PuttingPricesUpToDate"), 'value'
4235  // => 1),
4236  array('type' => 'other', 'name' => 'idwarehouse', 'label' => $label, 'value' => $value));
4237  }
4238  }
4239 
4240  $formconfirm = $form->formconfirm($_SERVER["PHP_SELF"].'?facid='.$object->id, $langs->trans('UnvalidateBill'), $text, 'confirm_modif', $formquestion, "yes", 1);
4241  }
4242 
4243  // Confirmation du classement paye
4244  if ($action == 'paid' && ($resteapayer <= 0 || (!empty($conf->global->INVOICE_CAN_SET_PAID_EVEN_IF_PARTIALLY_PAID) && $resteapayer == $object->total_ttc))) {
4245  $formconfirm = $form->formconfirm($_SERVER["PHP_SELF"].'?facid='.$object->id, $langs->trans('ClassifyPaid'), $langs->trans('ConfirmClassifyPaidBill', $object->ref), 'confirm_paid', '', "yes", 1);
4246  }
4247  if ($action == 'paid' && $resteapayer > 0 && (empty($conf->global->INVOICE_CAN_SET_PAID_EVEN_IF_PARTIALLY_PAID) || $resteapayer != $object->total_ttc)) {
4248  $close = array();
4249  // Code
4250  $i = 0;
4251  $close[$i]['code'] = 'discount_vat'; // escompte
4252  $i++;
4253  $close[$i]['code'] = 'badcustomer';
4254  $i++;
4255  $close[$i]['code'] = 'bankcharge';
4256  $i++;
4257  $close[$i]['code'] = 'withholdingtax';
4258  $i++;
4259  $close[$i]['code'] = 'other';
4260  $i++;
4261  // Help
4262  $i = 0;
4263  $close[$i]['label'] = $langs->trans("HelpEscompte").'<br><br>'.$langs->trans("ConfirmClassifyPaidPartiallyReasonDiscountVatDesc");
4264  $i++;
4265  $close[$i]['label'] = $langs->trans("ConfirmClassifyPaidPartiallyReasonBadCustomerDesc");
4266  $i++;
4267  $close[$i]['label'] = $langs->trans("ConfirmClassifyPaidPartiallyReasonBankChargeDesc");
4268  $i++;
4269  $close[$i]['label'] = $langs->trans("ConfirmClassifyPaidPartiallyReasonWithholdingTaxDesc");
4270  $i++;
4271  $close[$i]['label'] = $langs->trans("Other");
4272  $i++;
4273  // Texte
4274  $i = 0;
4275  $close[$i]['reason'] = $form->textwithpicto($langs->transnoentities("ConfirmClassifyPaidPartiallyReasonDiscount", $resteapayer, $langs->trans("Currency".$conf->currency)), $close[$i]['label'], 1);
4276  $i++;
4277  $close[$i]['reason'] = $form->textwithpicto($langs->transnoentities("ConfirmClassifyPaidPartiallyReasonBadCustomer", $resteapayer, $langs->trans("Currency".$conf->currency)), $close[$i]['label'], 1);
4278  $i++;
4279  $close[$i]['reason'] = $form->textwithpicto($langs->transnoentities("ConfirmClassifyPaidPartiallyReasonBankCharge", $resteapayer, $langs->trans("Currency".$conf->currency)), $close[$i]['label'], 1);
4280  $i++;
4281  $close[$i]['reason'] = $form->textwithpicto($langs->transnoentities("ConfirmClassifyPaidPartiallyReasonWithholdingTax"), $close[$i]['label'], 1);
4282  $i++;
4283  $close[$i]['reason'] = $form->textwithpicto($langs->transnoentities("Other"), $close[$i]['label'], 1);
4284  $i++;
4285  // arrayreasons[code]=reason
4286  foreach ($close as $key => $val) {
4287  $arrayreasons[$close[$key]['code']] = $close[$key]['reason'];
4288  }
4289 
4290  // Cree un tableau formulaire
4291  $formquestion = array('text' => $langs->trans("ConfirmClassifyPaidPartiallyQuestion"), array('type' => 'radio', 'name' => 'close_code', 'label' => $langs->trans("Reason"), 'values' => $arrayreasons), array('type' => 'text', 'name' => 'close_note', 'label' => $langs->trans("Comment"), 'value' => '', 'morecss' => 'minwidth300'));
4292  // Paiement incomplet. On demande si motif = escompte ou autre
4293  $formconfirm = $form->formconfirm($_SERVER["PHP_SELF"].'?facid='.$object->id, $langs->trans('ClassifyPaid'), $langs->trans('ConfirmClassifyPaidPartially', $object->ref), 'confirm_paid_partially', $formquestion, "yes", 1, 380, 600);
4294  }
4295 
4296  // Confirmation du classement abandonne
4297  if ($action == 'canceled') {
4298  // S'il y a une facture de remplacement pas encore validee (etat brouillon),
4299  // on ne permet pas de classer abandonner la facture.
4300  if ($objectidnext) {
4301  $facturereplacement = new Facture($db);
4302  $facturereplacement->fetch($objectidnext);
4303  $statusreplacement = $facturereplacement->statut;
4304  }
4305  if ($objectidnext && $statusreplacement == 0) {
4306  print '<div class="error">'.$langs->trans("ErrorCantCancelIfReplacementInvoiceNotValidated").'</div>';
4307  } else {
4308  // Code
4309  $close[1]['code'] = 'badcustomer';
4310  $close[2]['code'] = 'abandon';
4311  // Help
4312  $close[1]['label'] = $langs->trans("ConfirmClassifyPaidPartiallyReasonBadCustomerDesc");
4313  $close[2]['label'] = $langs->trans("ConfirmClassifyAbandonReasonOtherDesc");
4314  // Texte
4315  $close[1]['reason'] = $form->textwithpicto($langs->transnoentities("ConfirmClassifyPaidPartiallyReasonBadCustomer", $object->ref), $close[1]['label'], 1);
4316  $close[2]['reason'] = $form->textwithpicto($langs->transnoentities("ConfirmClassifyAbandonReasonOther"), $close[2]['label'], 1);
4317  // arrayreasons
4318  $arrayreasons[$close[1]['code']] = $close[1]['reason'];
4319  $arrayreasons[$close[2]['code']] = $close[2]['reason'];
4320 
4321  // Cree un tableau formulaire
4322  $formquestion = array('text' => $langs->trans("ConfirmCancelBillQuestion"), array('type' => 'radio', 'name' => 'close_code', 'label' => $langs->trans("Reason"), 'values' => $arrayreasons), array('type' => 'text', 'name' => 'close_note', 'label' => $langs->trans("Comment"), 'value' => '', 'morecss' => 'minwidth300'));
4323 
4324  $formconfirm = $form->formconfirm($_SERVER['PHP_SELF'].'?facid='.$object->id, $langs->trans('CancelBill'), $langs->trans('ConfirmCancelBill', $object->ref), 'confirm_canceled', $formquestion, "yes", 1, 270);
4325  }
4326  }
4327 
4328  if ($action == 'deletepayment') {
4329  $payment_id = GETPOST('paiement_id');
4330  $formconfirm = $form->formconfirm($_SERVER["PHP_SELF"].'?id='.$object->id.'&paiement_id='.$payment_id, $langs->trans('DeletePayment'), $langs->trans('ConfirmDeletePayment'), 'confirm_delete_paiement', '', 'no', 1);
4331  }
4332 
4333  // Confirmation de la suppression d'une ligne produit
4334  if ($action == 'ask_deleteline') {
4335  $formconfirm = $form->formconfirm($_SERVER["PHP_SELF"].'?facid='.$object->id.'&lineid='.$lineid, $langs->trans('DeleteProductLine'), $langs->trans('ConfirmDeleteProductLine'), 'confirm_deleteline', '', 'no', 1);
4336  }
4337 
4338  // Clone confirmation
4339  if ($action == 'clone') {
4340  $filter = '(s.client:IN:1,2,3)';
4341  // Create an array for form
4342  $formquestion = array(
4343  array('type' => 'other', 'name' => 'socid', 'label' => $langs->trans("SelectThirdParty"), 'value' => $form->select_company($object->socid, 'socid', $filter, 1)),
4344  array('type' => 'date', 'name' => 'newdate', 'label' => $langs->trans("Date"), 'value' => dol_now())
4345  );
4346  // Request confirmation to clone
4347  $formconfirm = $form->formconfirm($_SERVER["PHP_SELF"].'?facid='.$object->id, $langs->trans('ToClone'), $langs->trans('ConfirmCloneInvoice', $object->ref), 'confirm_clone', $formquestion, 'yes', 1, 250);
4348  }
4349 
4350  if ($action == "remove_file_comfirm") {
4351  $file = GETPOST('file', 'alpha');
4352 
4353  $formconfirm = $form->formconfirm(
4354  $_SERVER["PHP_SELF"].'?facid='.$object->id.'&file='.$file,
4355  $langs->trans('DeleteFileHeader'),
4356  $langs->trans('DeleteFileText')."<br><br>".$file,
4357  'remove_file',
4358  '',
4359  'no',
4360  2
4361  );
4362  }
4363 
4364  // Call Hook formConfirm
4365  $parameters = array('formConfirm' => $formconfirm, 'lineid' => $lineid, 'remainingtopay' => &$resteapayer);
4366  $reshook = $hookmanager->executeHooks('formConfirm', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
4367  if (empty($reshook)) {
4368  $formconfirm .= $hookmanager->resPrint;
4369  } elseif ($reshook > 0) {
4370  $formconfirm = $hookmanager->resPrint;
4371  }
4372 
4373  // Print form confirm
4374  print $formconfirm;
4375 
4376  // Invoice content
4377 
4378  $linkback = '<a href="'.DOL_URL_ROOT.'/compta/facture/list.php?restore_lastsearch_values=1'.(!empty($socid) ? '&socid='.$socid : '').'">'.$langs->trans("BackToList").'</a>';
4379 
4380  $morehtmlref = '<div class="refidno">';
4381  // Ref invoice
4382  if ($object->status == $object::STATUS_DRAFT && !$mysoc->isInEEC() && !empty($conf->global->INVOICE_ALLOW_FREE_REF)) {
4383  $morehtmlref .= $form->editfieldkey("Ref", 'ref', $object->ref, $object, $usercancreate, 'string', '', 0, 1);
4384  $morehtmlref .= $form->editfieldval("Ref", 'ref', $object->ref, $object, $usercancreate, 'string', '', null, null, '', 1);
4385  $morehtmlref .= '<br>';
4386  }
4387  // Ref customer
4388  $morehtmlref .= $form->editfieldkey("RefCustomer", 'ref_client', $object->ref_client, $object, $usercancreate, 'string', '', 0, 1);
4389  $morehtmlref .= $form->editfieldval("RefCustomer", 'ref_client', $object->ref_client, $object, $usercancreate, 'string'.(isset($conf->global->THIRDPARTY_REF_INPUT_SIZE) ? ':'.$conf->global->THIRDPARTY_REF_INPUT_SIZE : ''), '', null, null, '', 1);
4390  // Thirdparty
4391  $morehtmlref .= '<br>'.$object->thirdparty->getNomUrl(1, 'customer');
4392  if (empty($conf->global->MAIN_DISABLE_OTHER_LINK) && $object->thirdparty->id > 0) {
4393  $morehtmlref .= ' (<a href="'.DOL_URL_ROOT.'/compta/facture/list.php?socid='.$object->thirdparty->id.'&search_societe='.urlencode($object->thirdparty->name).'">'.$langs->trans("OtherBills").'</a>)';
4394  }
4395  // Project
4396  if (isModEnabled('project')) {
4397  $langs->load("projects");
4398  $morehtmlref .= '<br>';
4399  if ($usercancreate) {
4400  $morehtmlref .= img_picto($langs->trans("Project"), 'project', 'class="pictofixedwidth"');
4401  if ($action != 'classify') {
4402  $morehtmlref .= '<a class="editfielda" href="'.$_SERVER['PHP_SELF'].'?action=classify&token='.newToken().'&id='.$object->id.'">'.img_edit($langs->transnoentitiesnoconv('SetProject')).'</a> ';
4403  }
4404  $morehtmlref .= $form->form_project($_SERVER['PHP_SELF'].'?id='.$object->id, $object->socid, $object->fk_project, ($action == 'classify' ? 'projectid' : 'none'), 0, 0, 0, 1, '', 'maxwidth300');
4405  } else {
4406  if (!empty($object->fk_project)) {
4407  $proj = new Project($db);
4408  $proj->fetch($object->fk_project);
4409  $morehtmlref .= $proj->getNomUrl(1);
4410  if ($proj->title) {
4411  $morehtmlref .= '<span class="opacitymedium"> - '.dol_escape_htmltag($proj->title).'</span>';
4412  }
4413  }
4414  }
4415  }
4416  $morehtmlref .= '</div>';
4417 
4418  $object->totalpaid = $totalpaid; // To give a chance to dol_banner_tab to use already paid amount to show correct status
4419 
4420  dol_banner_tab($object, 'ref', $linkback, 1, 'ref', 'ref', $morehtmlref, '', 0, '', '');
4421 
4422  print '<div class="fichecenter">';
4423  print '<div class="fichehalfleft">';
4424  print '<div class="underbanner clearboth"></div>';
4425 
4426  print '<table class="border centpercent tableforfield">';
4427 
4428  // Type
4429  print '<tr><td class="titlefield fieldname_type">'.$langs->trans('Type').'</td><td class="valuefield fieldname_type">';
4430  print $object->getLibType(2);
4431  if ($object->module_source) {
4432  print ' <span class="opacitymediumbycolor paddingleft">('.$langs->trans("POS").' '.dol_escape_htmltag(ucfirst($object->module_source)).' - '.$langs->trans("Terminal").' '.dol_escape_htmltag($object->pos_source).')</span>';
4433  }
4434  if ($object->type == Facture::TYPE_REPLACEMENT) {
4435  $facreplaced = new Facture($db);
4436  $facreplaced->fetch($object->fk_facture_source);
4437  print ' <span class="opacitymediumbycolor paddingleft">'.$langs->transnoentities("ReplaceInvoice", $facreplaced->getNomUrl(1, '', 32)).'</span>';
4438  }
4439  if ($object->type == Facture::TYPE_CREDIT_NOTE && !empty($object->fk_facture_source)) {
4440  $facusing = new Facture($db);
4441  $facusing->fetch($object->fk_facture_source);
4442  print ' <span class="opacitymediumbycolor paddingleft">'.$langs->transnoentities("CorrectInvoice", $facusing->getNomUrl(1, '', 32)).'</span>';
4443  }
4444 
4445  $facidavoir = $object->getListIdAvoirFromInvoice();
4446  if (count($facidavoir) > 0) {
4447  print ' <span class="opacitymediumbycolor paddingleft">'.$langs->transnoentities("InvoiceHasAvoir");
4448  $i = 0;
4449  foreach ($facidavoir as $id) {
4450  if ($i == 0) {
4451  print ' ';
4452  } else {
4453  print ',';
4454  }
4455  $facavoir = new Facture($db);
4456  $facavoir->fetch($id);
4457  print $facavoir->getNomUrl(1, '', 32);
4458  }
4459  print '</span>';
4460  }
4461  if ($objectidnext > 0) {
4462  $facthatreplace = new Facture($db);
4463  $facthatreplace->fetch($objectidnext);
4464  print ' <span class="opacitymediumbycolor paddingleft">'.str_replace('{s1}', $facthatreplace->getNomUrl(1), $langs->transnoentities("ReplacedByInvoice", '{s1}')).'</span>';
4465  }
4466 
4467  if ($object->type == Facture::TYPE_CREDIT_NOTE || $object->type == Facture::TYPE_DEPOSIT) {
4468  $discount = new DiscountAbsolute($db);
4469  $result = $discount->fetch(0, $object->id);
4470  if ($result > 0) {
4471  print ' <span class="opacitymediumbycolor paddingleft">';
4472  $s = $langs->trans("CreditNoteConvertedIntoDiscount", '{s1}', '{s2}');
4473  $s = str_replace('{s1}', $object->getLibType(0), $s);
4474  $s = str_replace('{s2}', $discount->getNomUrl(1, 'discount'), $s);
4475  print $s;
4476  print '</span><br>';
4477  }
4478  }
4479 
4480  if ($object->fk_fac_rec_source > 0) {
4481  $tmptemplate = new FactureRec($db);
4482  $result = $tmptemplate->fetch($object->fk_fac_rec_source);
4483  if ($result > 0) {
4484  print ' <span class="opacitymediumbycolor paddingleft">';
4485  $s = $langs->transnoentities("GeneratedFromTemplate", '{s1}');
4486  $s = str_replace('{s1}', $tmptemplate->getNomUrl(1, '', 32), $s);
4487  print $s;
4488  print '</span>';
4489  }
4490  }
4491  print '</td></tr>';
4492 
4493  // Relative and absolute discounts
4494  print '<!-- Discounts -->'."\n";
4495  print '<tr><td>'.$langs->trans('DiscountStillRemaining').'</td>';
4496  print '<td>';
4497  $thirdparty = $soc;
4498  $discount_type = 0;
4499  $backtopage = urlencode($_SERVER["PHP_SELF"].'?facid='.$object->id);
4500  include DOL_DOCUMENT_ROOT.'/core/tpl/object_discounts.tpl.php';
4501  print '</td></tr>';
4502 
4503  // Date invoice
4504  print '<tr><td>';
4505  print '<table class="nobordernopadding centpercent"><tr><td>';
4506  print $langs->trans('DateInvoice');
4507  print '</td>';
4508  if ($action != 'editinvoicedate' && !empty($object->brouillon) && $usercancreate && empty($conf->global->FAC_FORCE_DATE_VALIDATION)) {
4509  print '<td class="right"><a class="editfielda" href="'.$_SERVER["PHP_SELF"].'?action=editinvoicedate&token='.newToken().'&facid='.$object->id.'">'.img_edit($langs->trans('SetDate'), 1).'</a></td>';
4510  }
4511  print '</tr></table>';
4512  print '</td><td>';
4513 
4514  if ($action == 'editinvoicedate') {
4515  $form->form_date($_SERVER['PHP_SELF'].'?facid='.$object->id, $object->date, 'invoicedate');
4516  } else {
4517  print '<span class="valuedate">'.dol_print_date($object->date, 'day').'</span>';
4518  }
4519  print '</td>';
4520 
4521  print '</tr>';
4522 
4523  if (!empty($conf->global->INVOICE_POINTOFTAX_DATE)) {
4524  // Date invoice point of tax
4525  print '<tr><td>';
4526  print '<table class="nobordernopadding centpercent"><tr><td>';
4527  print $langs->trans('DatePointOfTax');
4528  print '</td>';
4529  print '<td class="right"><a class="editfielda" href="'.$_SERVER["PHP_SELF"].'?action=editdate_pointoftax&token='.newToken().'&facid='.$object->id.'">'.img_edit($langs->trans('SetDate'), 1).'</a></td>';
4530  print '</tr></table>';
4531  print '</td><td>';
4532  if ($action == 'editdate_pointoftax') {
4533  $form->form_date($_SERVER['PHP_SELF'].'?facid='.$object->id, $object->date_pointoftax, 'date_pointoftax');
4534  } else {
4535  print '<span class="valuedate">'.dol_print_date($object->date_pointoftax, 'day').'</span>';
4536  }
4537  print '</td></tr>';
4538  }
4539 
4540  // Payment term
4541  print '<tr><td>';
4542  print '<table class="nobordernopadding centpercent"><tr><td>';
4543  print $langs->trans('PaymentConditionsShort');
4544  print '</td>';
4545  if ($object->type != Facture::TYPE_CREDIT_NOTE && $action != 'editconditions' && $usercancreate) {
4546  print '<td class="right"><a class="editfielda" href="'.$_SERVER["PHP_SELF"].'?action=editconditions&token='.newToken().'&facid='.$object->id.'">'.img_edit($langs->trans('SetConditions'), 1).'</a></td>';
4547  }
4548  print '</tr></table>';
4549  print '</td><td>';
4550  if ($object->type != Facture::TYPE_CREDIT_NOTE) {
4551  if ($action == 'editconditions') {
4552  $form->form_conditions_reglement($_SERVER['PHP_SELF'].'?facid='.$object->id, $object->cond_reglement_id, 'cond_reglement_id');
4553  } else {
4554  $form->form_conditions_reglement($_SERVER['PHP_SELF'].'?facid='.$object->id, $object->cond_reglement_id, 'none');
4555  }
4556  } else {
4557  print '&nbsp;';
4558  }
4559  print '</td></tr>';
4560 
4561  // Date payment term
4562  print '<tr><td>';
4563  print '<table class="nobordernopadding centpercent"><tr><td>';
4564  print $langs->trans('DateMaxPayment');
4565  print '</td>';
4566  if ($object->type != Facture::TYPE_CREDIT_NOTE && $action != 'editpaymentterm' && $usercancreate) {
4567  print '<td class="right"><a class="editfielda" href="'.$_SERVER["PHP_SELF"].'?action=editpaymentterm&token='.newToken().'&facid='.$object->id.'">'.img_edit($langs->trans('SetDate'), 1).'</a></td>';
4568  }
4569  print '</tr></table>';
4570  print '</td><td>';
4571  if ($object->type != Facture::TYPE_CREDIT_NOTE) {
4572  if ($action == 'editpaymentterm') {
4573  $form->form_date($_SERVER['PHP_SELF'].'?facid='.$object->id, $object->date_lim_reglement, 'paymentterm');
4574  } else {
4575  print '<span class="valuedate">'.dol_print_date($object->date_lim_reglement, 'day').'</span>';
4576  if ($object->hasDelay()) {
4577  print img_warning($langs->trans('Late'));
4578  }
4579  }
4580  } else {
4581  print '&nbsp;';
4582  }
4583  print '</td></tr>';
4584 
4585  // Payment mode
4586  print '<tr><td>';
4587  print '<table class="nobordernopadding centpercent"><tr><td>';
4588  print $langs->trans('PaymentMode');
4589  print '</td>';
4590  if ($action != 'editmode' && $usercancreate) {
4591  print '<td class="right"><a class="editfielda" href="'.$_SERVER["PHP_SELF"].'?action=editmode&token='.newToken().'&facid='.$object->id.'">'.img_edit($langs->trans('SetMode'), 1).'</a></td>';
4592  }
4593  print '</tr></table>';
4594  print '</td><td>';
4595  if ($action == 'editmode') {
4596  $form->form_modes_reglement($_SERVER['PHP_SELF'].'?facid='.$object->id, $object->mode_reglement_id, 'mode_reglement_id', 'CRDT', 1, 1);
4597  } else {
4598  $form->form_modes_reglement($_SERVER['PHP_SELF'].'?facid='.$object->id, $object->mode_reglement_id, 'none', 'CRDT');
4599  }
4600  print '</td></tr>';
4601 
4602  // Multicurrency
4603  if (isModEnabled('multicurrency')) {
4604  // Multicurrency code
4605  print '<tr>';
4606  print '<td>';
4607  print '<table class="nobordernopadding centpercent"><tr><td>';
4608  print $form->editfieldkey('Currency', 'multicurrency_code', '', $object, 0);
4609  print '</td>';
4610  if ($usercancreate && $action != 'editmulticurrencycode' && !empty($object->brouillon)) {
4611  print '<td class="right"><a class="editfielda" href="'.$_SERVER["PHP_SELF"].'?action=editmulticurrencycode&token='.newToken().'&id='.$object->id.'">'.img_edit($langs->transnoentitiesnoconv('SetMultiCurrencyCode'), 1).'</a></td>';
4612  }
4613  print '</tr></table>';
4614  print '</td><td>';
4615  $htmlname = (($usercancreate && $action == 'editmulticurrencycode') ? 'multicurrency_code' : 'none');
4616  $form->form_multicurrency_code($_SERVER['PHP_SELF'].'?id='.$object->id, $object->multicurrency_code, $htmlname);
4617  print '</td></tr>';
4618 
4619  // Multicurrency rate
4620  if ($object->multicurrency_code != $conf->currency || $object->multicurrency_tx != 1) {
4621  print '<tr>';
4622  print '<td>';
4623  print '<table class="nobordernopadding" width="100%"><tr><td>';
4624  print $form->editfieldkey('CurrencyRate', 'multicurrency_tx', '', $object, 0);
4625  print '</td>';
4626  if ($usercancreate && $action != 'editmulticurrencyrate' && !empty($object->brouillon) && $object->multicurrency_code && $object->multicurrency_code != $conf->currency) {
4627  print '<td class="right"><a class="editfielda" href="'.$_SERVER["PHP_SELF"].'?action=editmulticurrencyrate&token='.newToken().'&id='.$object->id.'">'.img_edit($langs->transnoentitiesnoconv('SetMultiCurrencyCode'), 1).'</a></td>';
4628  }
4629  print '</tr></table>';
4630  print '</td><td>';
4631  if ($action == 'editmulticurrencyrate' || $action == 'actualizemulticurrencyrate') {
4632  if ($action == 'actualizemulticurrencyrate') {
4633  list($object->fk_multicurrency, $object->multicurrency_tx) = MultiCurrency::getIdAndTxFromCode($object->db, $object->multicurrency_code);
4634  }
4635  $form->form_multicurrency_rate($_SERVER['PHP_SELF'].'?id='.$object->id, $object->multicurrency_tx, ($usercancreate ? 'multicurrency_tx' : 'none'), $object->multicurrency_code);
4636  } else {
4637  $form->form_multicurrency_rate($_SERVER['PHP_SELF'].'?id='.$object->id, $object->multicurrency_tx, 'none', $object->multicurrency_code);
4638  if ($object->statut == $object::STATUS_DRAFT && $object->multicurrency_code && $object->multicurrency_code != $conf->currency) {
4639  print '<div class="inline-block"> &nbsp; &nbsp; &nbsp; &nbsp; ';
4640  print '<a href="'.$_SERVER["PHP_SELF"].'?id='.$object->id.'&action=actualizemulticurrencyrate">'.$langs->trans("ActualizeCurrency").'</a>';
4641  print '</div>';
4642  }
4643  }
4644  print '</td></tr>';
4645  }
4646  }
4647 
4648  // Bank Account
4649  if (isModEnabled("banque")) {
4650  print '<tr><td class="nowrap">';
4651  print '<table class="nobordernopadding centpercent"><tr><td class="nowrap">';
4652  print $langs->trans('BankAccount');
4653  print '<td>';
4654  if (($action != 'editbankaccount') && $usercancreate) {
4655  print '<td class="right"><a class="editfielda" href="'.$_SERVER["PHP_SELF"].'?action=editbankaccount&token='.newToken().'&id='.$object->id.'">'.img_edit($langs->trans('SetBankAccount'), 1).'</a></td>';
4656  }
4657  print '</tr></table>';
4658  print '</td><td>';
4659  if ($action == 'editbankaccount') {
4660  $form->formSelectAccount($_SERVER['PHP_SELF'].'?id='.$object->id, $object->fk_account, 'fk_account', 1);
4661  } else {
4662  $form->formSelectAccount($_SERVER['PHP_SELF'].'?id='.$object->id, $object->fk_account, 'none');
4663  }
4664  print "</td>";
4665  print '</tr>';
4666  }
4667 
4668  // Incoterms
4669  if (isModEnabled('incoterm')) {
4670  print '<tr><td>';
4671  print '<table class="nobordernopadding centpercent"><tr><td>';
4672  print $langs->trans('IncotermLabel');
4673  print '<td><td class="right">';
4674  if ($usercancreate) {
4675  print '<a class="editfielda" href="'.DOL_URL_ROOT.'/compta/facture/card.php?facid='.$object->id.'&action=editincoterm&token='.newToken().'">'.img_edit().'</a>';
4676  } else {
4677  print '&nbsp;';
4678  }
4679  print '</td></tr></table>';
4680  print '</td>';
4681  print '<td>';
4682  if ($action != 'editincoterm') {
4683  print $form->textwithpicto($object->display_incoterms(), $object->label_incoterms, 1);
4684  } else {
4685  print $form->select_incoterms((!empty($object->fk_incoterms) ? $object->fk_incoterms : ''), (!empty($object->location_incoterms) ? $object->location_incoterms : ''), $_SERVER['PHP_SELF'].'?id='.$object->id);
4686  }
4687  print '</td></tr>';
4688  }
4689 
4690 
4691 
4692  if (!empty($object->retained_warranty) || !empty($conf->global->INVOICE_USE_RETAINED_WARRANTY)) {
4693  $displayWarranty = true;
4694  if (!in_array($object->type, $retainedWarrantyInvoiceAvailableType) && empty($object->retained_warranty)) {
4695  $displayWarranty = false;
4696  }
4697 
4698  if ($displayWarranty) {
4699  // Retained Warranty
4700  print '<tr class="retained-warranty-lines" ><td>';
4701  print '<table id="retained-warranty-table" class="nobordernopadding centpercent"><tr><td>';
4702  print $langs->trans('RetainedWarranty');
4703  print '</td>';
4704  if ($action != 'editretainedwarranty' && $user->hasRight('facture', 'creer') && $object->statut == Facture::STATUS_DRAFT) {
4705  print '<td align="right"><a class="editfielda" href="'.$_SERVER["PHP_SELF"].'?action=editretainedwarranty&token='.newToken().'&facid='.$object->id.'">'.img_edit($langs->trans('setretainedwarranty'), 1).'</a></td>';
4706  }
4707 
4708  print '</tr></table>';
4709  print '</td><td>';
4710  if ($action == 'editretainedwarranty' && $object->statut == Facture::STATUS_DRAFT) {
4711  print '<form id="retained-warranty-form" method="POST" action="'.$_SERVER['PHP_SELF'].'?facid='.$object->id.'">';
4712  print '<input type="hidden" name="action" value="setretainedwarranty">';
4713  print '<input type="hidden" name="token" value="'.newToken().'">';
4714  print '<input type="hidden" name="backtopage" value="'.$backtopage.'">';
4715  print '<input name="retained_warranty" type="number" step="0.01" min="0" max="100" value="'.$object->retained_warranty.'" >';
4716  print '<input type="submit" class="button valignmiddle" value="'.$langs->trans("Modify").'">';
4717  print '</form>';
4718  } else {
4719  print price($object->retained_warranty).'%';
4720  }
4721  print '</td></tr>';
4722 
4723  // Retained warranty payment term
4724  print '<tr class="retained-warranty-lines" ><td>';
4725  print '<table id="retained-warranty-cond-reglement-table" class="nobordernopadding" width="100%"><tr><td>';
4726  print $langs->trans('PaymentConditionsShortRetainedWarranty');
4727  print '</td>';
4728  if ($action != 'editretainedwarrantypaymentterms' && $user->hasRight('facture', 'creer') && $object->statut == Facture::STATUS_DRAFT) {
4729  print '<td align="right"><a class="editfielda" href="'.$_SERVER["PHP_SELF"].'?action=editretainedwarrantypaymentterms&token='.newToken().'&facid='.$object->id.'">'.img_edit($langs->trans('setPaymentConditionsShortRetainedWarranty'), 1).'</a></td>';
4730  }
4731 
4732  print '</tr></table>';
4733  print '</td><td>';
4734  $defaultDate = !empty($object->retained_warranty_date_limit) ? $object->retained_warranty_date_limit : strtotime('-1 years', $object->date_lim_reglement);
4735  if ($object->date > $defaultDate) {
4736  $defaultDate = $object->date;
4737  }
4738 
4739  if ($action == 'editretainedwarrantypaymentterms' && $object->statut == Facture::STATUS_DRAFT) {
4740  //date('Y-m-d',$object->date_lim_reglement)
4741  print '<form method="POST" action="'.$_SERVER['PHP_SELF'].'?facid='.$object->id.'">';
4742  print '<input type="hidden" name="action" value="setretainedwarrantyconditions">';
4743  print '<input type="hidden" name="token" value="'.newToken().'">';
4744  print '<input type="hidden" name="backtopage" value="'.$backtopage.'">';
4745  $retained_warranty_fk_cond_reglement = GETPOST('retained_warranty_fk_cond_reglement', 'int');
4746  $retained_warranty_fk_cond_reglement = !empty($retained_warranty_fk_cond_reglement) ? $retained_warranty_fk_cond_reglement : $object->retained_warranty_fk_cond_reglement;
4747  $retained_warranty_fk_cond_reglement = !empty($retained_warranty_fk_cond_reglement) ? $retained_warranty_fk_cond_reglement : $conf->global->INVOICE_SITUATION_DEFAULT_RETAINED_WARRANTY_COND_ID;
4748  print $form->getSelectConditionsPaiements($retained_warranty_fk_cond_reglement, 'retained_warranty_fk_cond_reglement', -1, 1);
4749  print '<input type="submit" class="button valignmiddle" value="'.$langs->trans("Modify").'">';
4750  print '</form>';
4751  } else {
4752  $form->form_conditions_reglement($_SERVER['PHP_SELF'].'?facid='.$object->id, $object->retained_warranty_fk_cond_reglement, 'none');
4753  if (!$displayWarranty) {
4754  print img_picto($langs->trans('RetainedWarrantyNeed100Percent'), 'warning.png', 'class="pictowarning valignmiddle" ');
4755  }
4756  }
4757  print '</td></tr>';
4758 
4759  // Retained Warranty payment date limit
4760  print '<tr class="retained-warranty-lines" ><td>';
4761  print '<table id="retained-warranty-date-limit-table" class="nobordernopadding" width="100%"><tr><td>';
4762  print $langs->trans('RetainedWarrantyDateLimit');
4763  print '</td>';
4764  if ($action != 'editretainedwarrantydatelimit' && $user->hasRight('facture', 'creer') && $object->statut == Facture::STATUS_DRAFT) {
4765  print '<td align="right"><a class="editfielda" href="'.$_SERVER["PHP_SELF"].'?action=editretainedwarrantydatelimit&token='.newToken().'&facid='.$object->id.'">'.img_edit($langs->trans('setretainedwarrantyDateLimit'), 1).'</a></td>';
4766  }
4767 
4768  print '</tr></table>';
4769  print '</td><td>';
4770  $defaultDate = !empty($object->retained_warranty_date_limit) ? $object->retained_warranty_date_limit : strtotime('-1 years', $object->date_lim_reglement);
4771  if ($object->date > $defaultDate) {
4772  $defaultDate = $object->date;
4773  }
4774 
4775  if ($action == 'editretainedwarrantydatelimit' && $object->statut == Facture::STATUS_DRAFT) {
4776  //date('Y-m-d',$object->date_lim_reglement)
4777  print '<form method="POST" action="'.$_SERVER['PHP_SELF'].'?facid='.$object->id.'">';
4778  print '<input type="hidden" name="action" value="setretainedwarrantydatelimit">';
4779  print '<input type="hidden" name="token" value="'.newToken().'">';
4780  print '<input type="hidden" name="backtopage" value="'.$backtopage.'">';
4781  print '<input name="retained_warranty_date_limit" type="date" step="1" min="'.dol_print_date($object->date, '%Y-%m-%d').'" value="'.dol_print_date($defaultDate, '%Y-%m-%d').'" >';
4782  print '<input type="submit" class="button valignmiddle" value="'.$langs->trans("Modify").'">';
4783  print '</form>';
4784  } else {
4785  print dol_print_date($object->retained_warranty_date_limit, 'day');
4786  }
4787  print '</td></tr>';
4788  }
4789  }
4790 
4791 
4792  // Other attributes
4793  $cols = 2;
4794  include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_view.tpl.php';
4795 
4796  print '</table>';
4797 
4798  print '</div>';
4799  print '<div class="fichehalfright">';
4800 
4801  print '<!-- amounts -->'."\n";
4802  print '<div class="underbanner clearboth"></div>'."\n";
4803 
4804  print '<table class="border tableforfield centpercent">';
4805 
4806  $sign = 1;
4807  if (!empty($conf->global->INVOICE_POSITIVE_CREDIT_NOTE_SCREEN) && $object->type == $object::TYPE_CREDIT_NOTE) {
4808  $sign = -1; // We invert sign for output
4809  }
4810  print '<tr>';
4811  // Amount HT
4812  print '<td class="titlefieldmiddle">' . $langs->trans('AmountHT') . '</td>';
4813  print '<td class="nowrap amountcard right">' . price($sign * $object->total_ht, '', $langs, 0, -1, -1, $conf->currency) . '</td>';
4814  if (isModEnabled("multicurrency") && ($object->multicurrency_code && $object->multicurrency_code != $conf->currency)) {
4815  // Multicurrency Amount HT
4816  print '<td class="nowrap amountcard right">' . price($sign * $object->multicurrency_total_ht, '', $langs, 0, -1, -1, $object->multicurrency_code) . '</td>';
4817  }
4818  print '</tr>';
4819 
4820  print '<tr>';
4821  // Amount VAT
4822  print '<td class="titlefieldmiddle">' . $langs->trans('AmountVAT') . '</td>';
4823  print '<td class="nowrap amountcard right">' . price($sign * $object->total_tva, '', $langs, 0, -1, -1, $conf->currency) . '</td>';
4824  if (isModEnabled("multicurrency") && ($object->multicurrency_code && $object->multicurrency_code != $conf->currency)) {
4825  // Multicurrency Amount VAT
4826  print '<td class="nowrap amountcard right">' . price($sign * $object->multicurrency_total_tva, '', $langs, 0, -1, -1, $object->multicurrency_code) . '</td>';
4827  }
4828  print '</tr>';
4829 
4830  // Amount Local Taxes
4831  if (($mysoc->localtax1_assuj == "1" && $mysoc->useLocalTax(1)) || $object->total_localtax1 != 0) {
4832  print '<tr>';
4833  print '<td class="titlefieldmiddle">' . $langs->transcountry("AmountLT1", $mysoc->country_code) . '</td>';
4834  print '<td class="nowrap amountcard right">' . price($sign * $object->total_localtax1, '', $langs, 0, -1, -1, $conf->currency) . '</td>';
4835  if (isModEnabled("multicurrency") && ($object->multicurrency_code && $object->multicurrency_code != $conf->currency)) {
4836  print '<td class="nowrap amountcard right">' . price($sign * $object->total_localtax1, '', $langs, 0, -1, -1, $object->multicurrency_code) . '</td>';
4837  }
4838  print '</tr>';
4839 
4840  if (($mysoc->localtax2_assuj == "1" && $mysoc->useLocalTax(2)) || $object->total_localtax2 != 0) {
4841  print '<tr>';
4842  print '<td>' . $langs->transcountry("AmountLT2", $mysoc->country_code) . '</td>';
4843  print '<td class="nowrap amountcard right">' . price($sign * $object->total_localtax2, '', $langs, 0, -1, -1, $conf->currency) . '</td>';
4844  if (isModEnabled("multicurrency") && ($object->multicurrency_code && $object->multicurrency_code != $conf->currency)) {
4845  print '<td class="nowrap amountcard right">' . price($sign * $object->total_localtax2, '', $langs, 0, -1, -1, $object->multicurrency_code) . '</td>';
4846  }
4847  print '</tr>';
4848  }
4849  }
4850 
4851  print '<tr>';
4852  // Amount TTC
4853  print '<td>' . $langs->trans('AmountTTC') . '</td>';
4854  print '<td class="nowrap amountcard right">' . price($sign * $object->total_ttc, '', $langs, 0, -1, -1, $conf->currency) . '</td>';
4855  if (isModEnabled("multicurrency") && ($object->multicurrency_code && $object->multicurrency_code != $conf->currency)) {
4856  // Multicurrency Amount TTC
4857  print '<td class="nowrap amountcard right">' . price($sign * $object->multicurrency_total_ttc, '', $langs, 0, -1, -1, $object->multicurrency_code) . '</td>';
4858  }
4859  print '</tr>';
4860 
4861  print '</table>';
4862 
4863  // Ajouter la première condition
4864  if ($selleruserevenustamp) {
4865  print '<table class="nobordernopadding" width="100%"><tr><td>';
4866  print $langs->trans('RevenueStamp');
4867  print '</td>';
4868  if ($action != 'editrevenuestamp' && !empty($object->brouillon) && $usercancreate) {
4869  print '<td class="right"><a class="editfielda" href="'.$_SERVER["PHP_SELF"].'?action=editrevenuestamp&token='.newToken().'&facid='.$object->id.'">'.img_edit($langs->trans('SetRevenuStamp'), 1).'</a></td>';
4870  }
4871  print '</tr></table>';
4872  print '</td><td>';
4873  if ($action == 'editrevenuestamp') {
4874  print '<form action="'.$_SERVER["PHP_SELF"].'?id='.$object->id.'" method="post">';
4875  print '<input type="hidden" name="token" value="'.newToken().'">';
4876  print '<input type="hidden" name="action" value="setrevenuestamp">';
4877  print '<input type="hidden" name="revenuestamp" id="revenuestamp_val" value="'.price2num($object->revenuestamp).'">';
4878  print '<input type="hidden" name="backtopage" value="'.$backtopage.'">';
4879  print $formother->select_revenue_stamp('', 'revenuestamp_type', $mysoc->country_code);
4880  print ' &rarr; <span id="revenuestamp_span"></span>';
4881  print ' <input type="submit" class="button buttongen button-save" value="'.$langs->trans('Modify').'">';
4882  print '</form>';
4883  print " <script>
4884  $(document).ready(function(){
4885  js_recalculate_revenuestamp();
4886  $('select[name=revenuestamp_type]').on('change',function(){
4887  js_recalculate_revenuestamp();
4888  });
4889  });
4890  function js_recalculate_revenuestamp(){
4891  var valselected = $('select[name=revenuestamp_type]').val();
4892  console.log('Calculate revenue stamp from '+valselected);
4893  var revenue = 0;
4894  if (valselected.indexOf('%') == -1)
4895  {
4896  revenue = valselected;
4897  }
4898  else
4899  {
4900  var revenue_type = parseFloat(valselected);
4901  var amount_net = ".round($object->total_ht, 2).";
4902  revenue = revenue_type * amount_net / 100;
4903  revenue = revenue.toFixed(2);
4904  }
4905  $('#revenuestamp_val').val(revenue);
4906  $('#revenuestamp_span').html(revenue);
4907  }
4908  </script>";
4909  } else {
4910  print price($object->revenuestamp, 1, '', 1, -1, -1, $conf->currency);
4911  }
4912  print '</td></tr>';
4913  }
4914 
4915  $nbrows = 8;
4916  $nbcols = 3;
4917  if (isModEnabled('project')) {
4918  $nbrows++;
4919  }
4920  if (isModEnabled("banque")) {
4921  $nbrows++;
4922  $nbcols++;
4923  }
4924  if ($mysoc->localtax1_assuj == "1" || $object->total_localtax1 != 0) {
4925  $nbrows++;
4926  }
4927  if ($mysoc->localtax2_assuj == "1" || $object->total_localtax2 != 0) {
4928  $nbrows++;
4929  }
4930  if ($selleruserevenustamp) {
4931  $nbrows++;
4932  }
4933  if (isModEnabled('multicurrency')) {
4934  $nbrows += 5;
4935  }
4936  if (isModEnabled('incoterm')) {
4937  $nbrows += 1;
4938  }
4939 
4940  // List of previous situation invoices
4941  if (($object->situation_cycle_ref > 0) && !empty($conf->global->INVOICE_USE_SITUATION)) {
4942  print '<!-- List of situation invoices -->';
4943  print '<table class="noborder situationstable" width="100%">';
4944 
4945  print '<tr class="liste_titre">';
4946  print '<td>'.$langs->trans('ListOfSituationInvoices').'</td>';
4947  print '<td></td>';
4948  print '<td class="center">'.$langs->trans('Situation').'</td>';
4949  if (isModEnabled("banque")) {
4950  print '<td class="right"></td>';
4951  }
4952  print '<td class="right">'.$langs->trans('AmountHT').'</td>';
4953  print '<td class="right">'.$langs->trans('AmountTTC').'</td>';
4954  print '<td width="18">&nbsp;</td>';
4955  print '</tr>';
4956 
4957  $total_prev_ht = $total_prev_ttc = 0;
4958  $total_global_ht = $total_global_ttc = 0;
4959 
4960  if (count($object->tab_previous_situation_invoice) > 0) {
4961  // List of previous invoices
4962 
4963  $current_situation_counter = array();
4964  foreach ($object->tab_previous_situation_invoice as $prev_invoice) {
4965  $tmptotalpaidforthisinvoice = $prev_invoice->getSommePaiement();
4966  $total_prev_ht += $prev_invoice->total_ht;
4967  $total_prev_ttc += $prev_invoice->total_ttc;
4968  $current_situation_counter[] = (($prev_invoice->type == Facture::TYPE_CREDIT_NOTE) ?-1 : 1) * $prev_invoice->situation_counter;
4969  print '<tr class="oddeven">';
4970  print '<td>'.$prev_invoice->getNomUrl(1).'</td>';
4971  print '<td></td>';
4972  print '<td align="center" >'.(($prev_invoice->type == Facture::TYPE_CREDIT_NOTE) ? $langs->trans('situationInvoiceShortcode_AS') : $langs->trans('situationInvoiceShortcode_S')).$prev_invoice->situation_counter.'</td>';
4973  if (isModEnabled("banque")) {
4974  print '<td class="right"></td>';
4975  }
4976  print '<td class="right"><span class="amount">'.price($prev_invoice->total_ht).'</span></td>';
4977  print '<td class="right"><span class="amount">'.price($prev_invoice->total_ttc).'</span></td>';
4978  print '<td class="right">'.$prev_invoice->getLibStatut(3, $tmptotalpaidforthisinvoice).'</td>';
4979  print '</tr>';
4980  }
4981  }
4982 
4983 
4984  $total_global_ht += $total_prev_ht;
4985  $total_global_ttc += $total_prev_ttc;
4986  $total_global_ht += $object->total_ht;
4987  $total_global_ttc += $object->total_ttc;
4988  $current_situation_counter[] = (($object->type == Facture::TYPE_CREDIT_NOTE) ?-1 : 1) * $object->situation_counter;
4989  print '<tr class="oddeven">';
4990  print '<td>'.$object->getNomUrl(1).'</td>';
4991  print '<td></td>';
4992  print '<td class="center">'.(($object->type == Facture::TYPE_CREDIT_NOTE) ? $langs->trans('situationInvoiceShortcode_AS') : $langs->trans('situationInvoiceShortcode_S')).$object->situation_counter.'</td>';
4993  if (isModEnabled("banque")) {
4994  print '<td class="right"></td>';
4995  }
4996  print '<td class="right"><span class="amount">'.price($object->total_ht).'</span></td>';
4997  print '<td class="right"><span class="amount">'.price($object->total_ttc).'</span></td>';
4998  print '<td class="right">'.$object->getLibStatut(3, $object->getSommePaiement()).'</td>';
4999  print '</tr>';
5000 
5001 
5002  print '<tr class="oddeven">';
5003  print '<td colspan="2" class="left"><b>'.$langs->trans('CurrentSituationTotal').'</b></td>';
5004  print '<td>';
5005  $i = 0;
5006  foreach ($current_situation_counter as $sit) {
5007  $curSign = $sit > 0 ? '+' : '-';
5008  $curType = $sit > 0 ? $langs->trans('situationInvoiceShortcode_S') : $langs->trans('situationInvoiceShortcode_AS');
5009  if ($i > 0) {
5010  print ' '.$curSign.' ';
5011  }
5012  print $curType.abs($sit);
5013  $i++;
5014  }
5015  print '</td>';
5016  if (isModEnabled("banque")) {
5017  print '<td></td>';
5018  }
5019  print '<td class="right"><b>'.price($total_global_ht).'</b></td>';
5020  print '<td class="right"><b>'.price($total_global_ttc).'</b></td>';
5021  print '<td width="18">&nbsp;</td>';
5022  print '</tr>';
5023 
5024 
5025  if (count($object->tab_next_situation_invoice) > 0) {
5026  // List of next invoices
5027  /*print '<tr class="liste_titre">';
5028  print '<td>' . $langs->trans('ListOfNextSituationInvoices') . '</td>';
5029  print '<td></td>';
5030  print '<td></td>';
5031  if (isModEnabled('banque')) print '<td class="right"></td>';
5032  print '<td class="right">' . $langs->trans('AmountHT') . '</td>';
5033  print '<td class="right">' . $langs->trans('AmountTTC') . '</td>';
5034  print '<td width="18">&nbsp;</td>';
5035  print '</tr>';*/
5036 
5037  $total_next_ht = $total_next_ttc = 0;
5038 
5039  foreach ($object->tab_next_situation_invoice as $next_invoice) {
5040  $totalpaid = $next_invoice->getSommePaiement();
5041  $total_next_ht += $next_invoice->total_ht;
5042  $total_next_ttc += $next_invoice->total_ttc;
5043 
5044  print '<tr class="oddeven">';
5045  print '<td>'.$next_invoice->getNomUrl(1).'</td>';
5046  print '<td></td>';
5047  print '<td class="center">'.(($next_invoice->type == Facture::TYPE_CREDIT_NOTE) ? $langs->trans('situationInvoiceShortcode_AS') : $langs->trans('situationInvoiceShortcode_S')).$next_invoice->situation_counter.'</td>';
5048  if (isModEnabled("banque")) {
5049  print '<td class="right"></td>';
5050  }
5051  print '<td class="right"><span class="amount">'.price($next_invoice->total_ht).'</span></td>';
5052  print '<td class="right"><span class="amount">'.price($next_invoice->total_ttc).'</span></td>';
5053  print '<td class="right">'.$next_invoice->getLibStatut(3, $totalpaid).'</td>';
5054  print '</tr>';
5055  }
5056 
5057  $total_global_ht += $total_next_ht;
5058  $total_global_ttc += $total_next_ttc;
5059 
5060  print '<tr class="oddeven">';
5061  print '<td colspan="3" class="right"></td>';
5062  if (isModEnabled("banque")) {
5063  print '<td class="right"></td>';
5064  }
5065  print '<td class="right"><b>'.price($total_global_ht).'</b></td>';
5066  print '<td class="right"><b>'.price($total_global_ttc).'</b></td>';
5067  print '<td width="18">&nbsp;</td>';
5068  print '</tr>';
5069  }
5070 
5071  print '</table>';
5072  }
5073 
5074  $sign = 1;
5075  if ($object->type == $object::TYPE_CREDIT_NOTE) {
5076  $sign = -1;
5077  }
5078 
5079  // List of payments already done
5080 
5081  print '<!-- List of payments already done -->';
5082  print '<div class="div-table-responsive-no-min">';
5083  print '<table class="noborder paymenttable centpercent">';
5084 
5085  print '<tr class="liste_titre">';
5086  print '<td class="liste_titre">'.($object->type == Facture::TYPE_CREDIT_NOTE ? $langs->trans("PaymentsBack") : $langs->trans('Payments')).'</td>';
5087  print '<td class="liste_titre"><span class="hideonsmartphone">'.$langs->trans('Date').'</span></td>';
5088  print '<td class="liste_titre"><span class="hideonsmartphone">'.$langs->trans('Type').'</span></td>';
5089  if (isModEnabled("banque")) {
5090  print '<td class="liste_titre"><span class="hideonsmartphone">'.$langs->trans('BankAccount').'</span></td>';
5091  }
5092  print '<td class="liste_titre right">'.$langs->trans('Amount').'</td>';
5093  print '<td class="liste_titre" width="18">&nbsp;</td>';
5094  print '</tr>';
5095 
5096  // Payments already done (from payment on this invoice)
5097  $sql = 'SELECT p.datep as dp, p.ref, p.num_paiement as num_payment, p.rowid, p.fk_bank,';
5098  $sql .= ' c.code as payment_code, c.libelle as payment_label,';
5099  $sql .= ' pf.amount,';
5100  $sql .= ' ba.rowid as baid, ba.ref as baref, ba.label, ba.number as banumber, ba.account_number, ba.fk_accountancy_journal, ba.currency_code as bacurrency_code';
5101  $sql .= ' FROM '.MAIN_DB_PREFIX.'paiement_facture as pf, '.MAIN_DB_PREFIX.'paiement as p';
5102  $sql .= ' LEFT JOIN '.MAIN_DB_PREFIX.'c_paiement as c ON p.fk_paiement = c.id';
5103  $sql .= ' LEFT JOIN '.MAIN_DB_PREFIX.'bank as b ON p.fk_bank = b.rowid';
5104  $sql .= ' LEFT JOIN '.MAIN_DB_PREFIX.'bank_account as ba ON b.fk_account = ba.rowid';
5105  $sql .= ' WHERE pf.fk_facture = '.((int) $object->id).' AND pf.fk_paiement = p.rowid';
5106  $sql .= ' AND p.entity IN ('.getEntity('invoice').')';
5107  $sql .= ' ORDER BY p.datep, p.tms';
5108 
5109  $result = $db->query($sql);
5110  if ($result) {
5111  $num = $db->num_rows($result);
5112  $i = 0;
5113 
5114  if ($num > 0) {
5115  while ($i < $num) {
5116  $objp = $db->fetch_object($result);
5117 
5118  $paymentstatic->id = $objp->rowid;
5119  $paymentstatic->datepaye = $db->jdate($objp->dp);
5120  $paymentstatic->ref = $objp->ref;
5121  $paymentstatic->num_payment = $objp->num_payment;
5122  $paymentstatic->paiementcode = $objp->payment_code;
5123 
5124  print '<tr class="oddeven"><td class="nowraponall">';
5125  print $paymentstatic->getNomUrl(1);
5126  print '</td>';
5127  print '<td>';
5128  $dateofpayment = $db->jdate($objp->dp);
5129  $tmparray = dol_getdate($dateofpayment);
5130  if ($tmparray['seconds'] == 0 && $tmparray['minutes'] == 0 && ($tmparray['hours'] == 0 || $tmparray['hours'] == 12)) { // We set hours to 0:00 or 12:00 because we don't know it
5131  print dol_print_date($dateofpayment, 'day');
5132  } else { // Hours was set to real date of payment (special case for POS for example)
5133  print dol_print_date($dateofpayment, 'dayhour', 'tzuser');
5134  }
5135  print '</td>';
5136  $label = ($langs->trans("PaymentType".$objp->payment_code) != ("PaymentType".$objp->payment_code)) ? $langs->trans("PaymentType".$objp->payment_code) : $objp->payment_label;
5137  print '<td class="tdoverflowmax80" title="'.dol_escape_htmltag($label.' '.$objp->num_payment).'">'.dol_escape_htmltag($label.' '.$objp->num_payment).'</td>';
5138  if (isModEnabled("banque")) {
5139  $bankaccountstatic->id = $objp->baid;
5140  $bankaccountstatic->ref = $objp->baref;
5141  $bankaccountstatic->label = $objp->baref;
5142  $bankaccountstatic->number = $objp->banumber;
5143  $bankaccountstatic->currency_code = $objp->bacurrency_code;
5144 
5145  if (isModEnabled('accounting')) {
5146  $bankaccountstatic->account_number = $objp->account_number;
5147 
5148  $accountingjournal = new AccountingJournal($db);
5149  $accountingjournal->fetch($objp->fk_accountancy_journal);
5150  $bankaccountstatic->accountancy_journal = $accountingjournal->getNomUrl(0, 1, 1, '', 1);
5151  }
5152 
5153  print '<td class="nowraponall">';
5154  if ($bankaccountstatic->id) {
5155  print $bankaccountstatic->getNomUrl(1, 'transactions');
5156  }
5157  print '</td>';
5158  }
5159  print '<td class="right"><span class="amount">'.price($sign * $objp->amount).'</span></td>';
5160  print '<td class="center">';
5161  if ($object->statut == Facture::STATUS_VALIDATED && $object->paye == 0 && $user->socid == 0) {
5162  print '<a href="'.$_SERVER["PHP_SELF"].'?id='.$object->id.'&action=deletepayment&token='.newToken().'&paiement_id='.$objp->rowid.'">';
5163  print img_delete();
5164  print '</a>';
5165  }
5166  print '</td>';
5167  print '</tr>';
5168  $i++;
5169  }
5170  }
5171 
5172  $db->free($result);
5173  } else {
5174  dol_print_error($db);
5175  }
5176 
5177  if ($object->type != Facture::TYPE_CREDIT_NOTE) {
5178  // Total already paid
5179  print '<tr><td colspan="'.$nbcols.'" class="right">';
5180  print '<span class="opacitymedium">';
5181  if ($object->type != Facture::TYPE_DEPOSIT) {
5182  print $langs->trans('AlreadyPaidNoCreditNotesNoDeposits');
5183  } else {
5184  print $langs->trans('AlreadyPaid');
5185  }
5186  print '</span></td><td class="right'.(($totalpaid > 0) ? ' amountalreadypaid' : '').'">'.price($totalpaid).'</td><td>&nbsp;</td></tr>';
5187 
5188  $resteapayeraffiche = $resteapayer;
5189  $cssforamountpaymentcomplete = 'amountpaymentcomplete';
5190 
5191  // Loop on each credit note or deposit amount applied
5192  $creditnoteamount = 0;
5193  $depositamount = 0;
5194  $sql = "SELECT re.rowid, re.amount_ht, re.amount_tva, re.amount_ttc,";
5195  $sql .= " re.description, re.fk_facture_source";
5196  $sql .= " FROM ".MAIN_DB_PREFIX."societe_remise_except as re";
5197  $sql .= " WHERE fk_facture = ".((int) $object->id);
5198  $resql = $db->query($sql);
5199  if ($resql) {
5200  $num = $db->num_rows($resql);
5201  $i = 0;
5202  $invoice = new Facture($db);
5203  while ($i < $num) {
5204  $obj = $db->fetch_object($resql);
5205  $invoice->fetch($obj->fk_facture_source);
5206  print '<tr><td colspan="'.$nbcols.'" class="right">';
5207  print '<span class="opacitymedium">';
5208  if ($invoice->type == Facture::TYPE_CREDIT_NOTE) {
5209  print $langs->trans("CreditNote").' ';
5210  }
5211  if ($invoice->type == Facture::TYPE_DEPOSIT) {
5212  print $langs->trans("Deposit").' ';
5213  }
5214  print $invoice->getNomUrl(0);
5215  print '</span>';
5216  print '</td>';
5217  print '<td class="right"><span class="amount">'.price($obj->amount_ttc).'</span></td>';
5218  print '<td class="right">';
5219  print '<a href="'.$_SERVER["PHP_SELF"].'?facid='.$object->id.'&action=unlinkdiscount&token='.newToken().'&discountid='.$obj->rowid.'">';
5220  print img_picto($langs->transnoentitiesnoconv("RemoveDiscount"), 'unlink');
5221  print '</a>';
5222  print '</td></tr>';
5223  $i++;
5224  if ($invoice->type == Facture::TYPE_CREDIT_NOTE) {
5225  $creditnoteamount += $obj->amount_ttc;
5226  }
5227  if ($invoice->type == Facture::TYPE_DEPOSIT) {
5228  $depositamount += $obj->amount_ttc;
5229  }
5230  }
5231  } else {
5232  dol_print_error($db);
5233  }
5234 
5235  // Paye partiellement 'escompte'
5236  if (($object->statut == Facture::STATUS_CLOSED || $object->statut == Facture::STATUS_ABANDONED) && $object->close_code == 'discount_vat') {
5237  print '<tr><td colspan="'.$nbcols.'" class="nowrap right">';
5238  print '<span class="opacitymedium">';
5239  print $form->textwithpicto($langs->trans("Discount"), $langs->trans("HelpEscompte"), - 1);
5240  print '</span>';
5241  print '</td><td class="right"><span class="amount">'.price(price2num($object->total_ttc - $creditnoteamount - $depositamount - $totalpaid, 'MT')).'</span></td><td>&nbsp;</td></tr>';
5242  $resteapayeraffiche = 0;
5243  $cssforamountpaymentcomplete = 'amountpaymentneutral';
5244  }
5245  // Paye partiellement ou Abandon 'badcustomer'
5246  if (($object->statut == Facture::STATUS_CLOSED || $object->statut == Facture::STATUS_ABANDONED) && $object->close_code == 'badcustomer') {
5247  print '<tr><td colspan="'.$nbcols.'" class="nowrap right">';
5248  print '<span class="opacitymedium">';
5249  print $form->textwithpicto($langs->trans("Abandoned"), $langs->trans("HelpAbandonBadCustomer"), - 1);
5250  print '</span>';
5251  print '</td><td class="right">'.price(price2num($object->total_ttc - $creditnoteamount - $depositamount - $totalpaid, 'MT')).'</td><td>&nbsp;</td></tr>';
5252  // $resteapayeraffiche=0;
5253  $cssforamountpaymentcomplete = 'amountpaymentneutral';
5254  }
5255  // Paye partiellement ou Abandon 'product_returned'
5256  if (($object->statut == Facture::STATUS_CLOSED || $object->statut == Facture::STATUS_ABANDONED) && $object->close_code == 'product_returned') {
5257  print '<tr><td colspan="'.$nbcols.'" class="nowrap right">';
5258  print '<span class="opacitymedium">';
5259  print $form->textwithpicto($langs->trans("ProductReturned"), $langs->trans("HelpAbandonProductReturned"), - 1);
5260  print '</span>';
5261  print '</td><td class="right"><span class="amount">'.price(price2num($object->total_ttc - $creditnoteamount - $depositamount - $totalpaid, 'MT')).'</span></td><td>&nbsp;</td></tr>';
5262  $resteapayeraffiche = 0;
5263  $cssforamountpaymentcomplete = 'amountpaymentneutral';
5264  }
5265  // Paye partiellement ou Abandon 'abandon'
5266  if (($object->statut == Facture::STATUS_CLOSED || $object->statut == Facture::STATUS_ABANDONED) && $object->close_code == 'abandon') {
5267  print '<tr><td colspan="'.$nbcols.'" class="nowrap right">';
5268  $text = $langs->trans("HelpAbandonOther");
5269  if ($object->close_note) {
5270  $text .= '<br><br><b>'.$langs->trans("Reason").'</b>:'.$object->close_note;
5271  }
5272  print '<span class="opacitymedium">';
5273  print $form->textwithpicto($langs->trans("Abandoned"), $text, - 1);
5274  print '</span>';
5275  print '</td><td class="right"><span class="amount">'.price(price2num($object->total_ttc - $creditnoteamount - $depositamount - $totalpaid, 'MT')).'</span></td><td>&nbsp;</td></tr>';
5276  $resteapayeraffiche = 0;
5277  $cssforamountpaymentcomplete = 'amountpaymentneutral';
5278  }
5279 
5280  // Billed
5281  print '<tr><td colspan="'.$nbcols.'" class="right">';
5282  print '<span class="opacitymedium">';
5283  print $langs->trans("Billed");
5284  print '</td><td class="right">'.price($object->total_ttc).'</td><td>&nbsp;</td></tr>';
5285  // Remainder to pay
5286  print '<tr><td colspan="'.$nbcols.'" class="right">';
5287  print '<span class="opacitymedium">';
5288  print $langs->trans('RemainderToPay');
5289  if ($resteapayeraffiche < 0) {
5290  print ' ('.$langs->trans('NegativeIfExcessReceived').')';
5291  }
5292  print '</span>';
5293  print '</td>';
5294  print '<td class="right'.($resteapayeraffiche ? ' amountremaintopay' : (' '.$cssforamountpaymentcomplete)).'">'.price($resteapayeraffiche).'</td><td>&nbsp;</td></tr>';
5295 
5296  // Remainder to pay Multicurrency
5297  if ($object->multicurrency_code != $conf->currency || $object->multicurrency_tx != 1) {
5298  print '<tr><td colspan="'.$nbcols.'" class="right">';
5299  print '<span class="opacitymedium">';
5300  print $langs->trans('RemainderToPayMulticurrency');
5301  if ($resteapayeraffiche < 0) {
5302  print ' ('.$langs->trans('NegativeIfExcessReceived').')';
5303  }
5304  print '</span>';
5305  print '</td>';
5306  print '<td class="right'.($resteapayeraffiche ? ' amountremaintopay' : (' '.$cssforamountpaymentcomplete)).'">';
5307  //print (empty($object->multicurrency_code) ? $conf->currency : $object->multicurrency_code).' ';
5308  print price(price2num($object->multicurrency_tx*$resteapayeraffiche, 'MT'), 1, $langs, 1, -1, -1, (empty($object->multicurrency_code) ? $conf->currency : $object->multicurrency_code)).'</td><td>&nbsp;</td></tr>';
5309  }
5310 
5311  // Retained warranty : usualy use on construction industry
5312  if (!empty($object->situation_final) && !empty($object->retained_warranty) && $displayWarranty) {
5313  // Billed - retained warranty
5314  if ($object->type == Facture::TYPE_SITUATION) {
5315  $retainedWarranty = $total_global_ttc * $object->retained_warranty / 100;
5316  } else {
5317  // Because one day retained warranty could be used on standard invoices
5318  $retainedWarranty = $object->total_ttc * $object->retained_warranty / 100;
5319  }
5320 
5321  $billedWithRetainedWarranty = $object->total_ttc - $retainedWarranty;
5322 
5323  print '<tr><td colspan="'.$nbcols.'" align="right">'.$langs->trans("ToPayOn", dol_print_date($object->date_lim_reglement, 'day')).' :</td><td align="right">'.price($billedWithRetainedWarranty).'</td><td>&nbsp;</td></tr>';
5324 
5325  // retained warranty
5326  print '<tr><td colspan="'.$nbcols.'" align="right">';
5327  print $langs->trans("RetainedWarranty").' ('.$object->retained_warranty.'%)';
5328  print !empty($object->retained_warranty_date_limit) ? ' '.$langs->trans("ToPayOn", dol_print_date($object->retained_warranty_date_limit, 'day')) : '';
5329  print ' :</td><td align="right">'.price($retainedWarranty).'</td><td>&nbsp;</td></tr>';
5330  }
5331  } else { // Credit note
5332  $resteapayeraffiche = $resteapayer;
5333  $cssforamountpaymentcomplete = 'amountpaymentneutral';
5334 
5335  // Total already paid back
5336  print '<tr><td colspan="'.$nbcols.'" class="right">';
5337  print '<span class="opacitymedium">'.$langs->trans('AlreadyPaidBack').'</span>';
5338  print '</td><td class="right"><span class="amount">'.price($sign * $totalpaid).'</span></td><td>&nbsp;</td></tr>';
5339 
5340  // Billed
5341  print '<tr><td colspan="'.$nbcols.'" class="right"><span class="opacitymedium">'.$langs->trans("Billed").'</span></td><td class="right">'.price($sign * $object->total_ttc).'</td><td>&nbsp;</td></tr>';
5342 
5343  // Remainder to pay back
5344  print '<tr><td colspan="'.$nbcols.'" class="right">';
5345  print '<span class="opacitymedium">'.$langs->trans('RemainderToPayBack');
5346  if ($resteapayeraffiche > 0) {
5347  print ' ('.$langs->trans('NegativeIfExcessRefunded').')';
5348  }
5349  print '</span></td>';
5350  print '<td class="right'.($resteapayeraffiche ? ' amountremaintopayback' : (' '.$cssforamountpaymentcomplete)).'">'.price($sign * $resteapayeraffiche).'</td>';
5351  print '<td class="nowrap">&nbsp;</td></tr>';
5352 
5353  // Remainder to pay back Multicurrency
5354  if ($object->multicurrency_code != $conf->currency || $object->multicurrency_tx != 1) {
5355  print '<tr><td colspan="'.$nbcols.'" class="right">';
5356  print '<span class="opacitymedium">'.$langs->trans('RemainderToPayBackMulticurrency');
5357  if ($resteapayeraffiche > 0) {
5358  print ' ('.$langs->trans('NegativeIfExcessRefunded').')';
5359  }
5360  print '</span>';
5361  print '</td>';
5362  print '<td class="right'.($resteapayeraffiche ? ' amountremaintopayback' : (' '.$cssforamountpaymentcomplete)).'">'.(!empty($object->multicurrency_code) ? $object->multicurrency_code : $conf->currency).' '.price(price2num($sign * $object->multicurrency_tx * $resteapayeraffiche, 'MT')).'</td><td>&nbsp;</td></tr>';
5363  }
5364 
5365  // Sold credit note
5366  // print '<tr><td colspan="'.$nbcols.'" class="right">'.$langs->trans('TotalTTC').' :</td>';
5367  // print '<td class="right" style="border: 1px solid;" bgcolor="#f0f0f0"><b>'.price($sign *
5368  // $object->total_ttc).'</b></td><td>&nbsp;</td></tr>';
5369  }
5370 
5371  print '</table>';
5372  print '</div>';
5373 
5374  // Margin Infos
5375  if (isModEnabled('margin')) {
5376  $formmargin->displayMarginInfos($object);
5377  }
5378 
5379  print '</div>';
5380  print '</div>';
5381 
5382  print '<div class="clearboth"></div><br><br>';
5383 
5384  if (!empty($conf->global->MAIN_DISABLE_CONTACTS_TAB)) {
5385  $blocname = 'contacts';
5386  $title = $langs->trans('ContactsAddresses');
5387  include DOL_DOCUMENT_ROOT.'/core/tpl/bloc_showhide.tpl.php';
5388  }
5389 
5390  if (!empty($conf->global->MAIN_DISABLE_NOTES_TAB)) {
5391  $blocname = 'notes';
5392  $title = $langs->trans('Notes');
5393  include DOL_DOCUMENT_ROOT.'/core/tpl/bloc_showhide.tpl.php';
5394  }
5395 
5396  // Get object lines
5397  $result = $object->getLinesArray();
5398 
5399  // Add products/services form
5400  //$forceall = 1;
5401  global $inputalsopricewithtax;
5402  $inputalsopricewithtax = 1;
5403 
5404  // Show global modifiers for situation invoices
5405  if (!empty($conf->global->INVOICE_USE_SITUATION)) {
5406  if ($object->situation_cycle_ref && $object->statut == 0) {
5407  print '<!-- Area to change globally the situation percent -->'."\n";
5408  print '<div class="div-table-responsive">';
5409 
5410  print '<form name="updatealllines" id="updatealllines" action="'.$_SERVER['PHP_SELF'].'?id='.$object->id.'#updatealllines" method="POST">';
5411  print '<input type="hidden" name="token" value="'.newToken().'" />';
5412  print '<input type="hidden" name="action" value="updatealllines" />';
5413  print '<input type="hidden" name="id" value="'.$object->id.'" />';
5414  print '<input type="hidden" name="backtopage" value="'.$backtopage.'">';
5415 
5416  print '<table id="tablelines_all_progress" class="noborder noshadow" width="100%">';
5417 
5418  print '<tr class="liste_titre nodrag nodrop">';
5419 
5420  // Adds a line numbering column
5421  if (!empty($conf->global->MAIN_VIEW_LINE_NUMBER)) {
5422  print '<td align="center" width="5">&nbsp;</td>';
5423  }
5424  print '<td class="minwidth500imp">'.$langs->trans('ModifyAllLines').'</td>';
5425  print '<td class="right">'.$langs->trans('Progress').'</td>';
5426  print '<td>&nbsp;</td>';
5427  print "</tr>\n";
5428 
5429  print '<tr class="nodrag nodrop">';
5430  // Adds a line numbering column
5431  if (!empty($conf->global->MAIN_VIEW_LINE_NUMBER)) {
5432  print '<td align="center" width="5">&nbsp;</td>';
5433  }
5434  print '<td>&nbsp;</td>';
5435  print '<td class="nowrap right"><input type="text" size="1" value="" name="all_progress">%</td>';
5436  print '<td class="right"><input type="submit" class="button" name="all_percent" value="Modifier" /></td>';
5437  print '</tr>';
5438 
5439  print '</table>';
5440 
5441  print '</form>';
5442 
5443  print '</div>';
5444  }
5445  }
5446 
5447  print ' <form name="addproduct" id="addproduct" action="'.$_SERVER["PHP_SELF"].'?id='.$object->id.'" method="POST">
5448  <input type="hidden" name="token" value="' . newToken().'">
5449  <input type="hidden" name="action" value="' . (($action != 'editline') ? 'addline' : 'updateline').'">
5450  <input type="hidden" name="mode" value="">
5451  <input type="hidden" name="page_y" value="">
5452  <input type="hidden" name="id" value="' . $object->id.'">
5453  <input type="hidden" name="backtopage" value="'.$backtopage.'">
5454  ';
5455 
5456  if (!empty($conf->use_javascript_ajax) && $object->statut == 0) {
5457  include DOL_DOCUMENT_ROOT.'/core/tpl/ajaxrow.tpl.php';
5458  }
5459 
5460  print '<div class="div-table-responsive-no-min">';
5461  print '<table id="tablelines" class="noborder noshadow" width="100%">';
5462 
5463  // Show object lines
5464  if (!empty($object->lines)) {
5465  $object->printObjectLines($action, $mysoc, $soc, $lineid, 1);
5466  }
5467 
5468  // Form to add new line
5469  if ($object->statut == 0 && $usercancreate && $action != 'valid' && $action != 'editline') {
5470  if ($action != 'editline' && $action != 'selectlines') {
5471  // Add free products/services
5472 
5473  $parameters = array();
5474  $reshook = $hookmanager->executeHooks('formAddObjectLine', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
5475  if ($reshook < 0) setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
5476  if (empty($reshook))
5477  $object->formAddObjectLine(1, $mysoc, $soc);
5478  }
5479  }
5480 
5481  print "</table>\n";
5482  print "</div>";
5483 
5484  print "</form>\n";
5485 
5486  print dol_get_fiche_end();
5487 
5488 
5489  // Actions buttons
5490 
5491  if ($action != 'prerelance' && $action != 'presend' && $action != 'valid' && $action != 'editline') {
5492  print '<div class="tabsAction">';
5493 
5494  $parameters = array();
5495  $reshook = $hookmanager->executeHooks('addMoreActionsButtons', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
5496  if (empty($reshook)) {
5497  $params = array(
5498  'attr' => array(
5499  'class' => 'classfortooltip'
5500  )
5501  );
5502  // Editer une facture deja validee, sans paiement effectue et pas exporte en compta
5503  if ($object->statut == Facture::STATUS_VALIDATED) {
5504  // We check if lines of invoice are not already transfered into accountancy
5505  $ventilExportCompta = $object->getVentilExportCompta();
5506 
5507  if ($ventilExportCompta == 0) {
5508  if (!empty($conf->global->INVOICE_CAN_BE_EDITED_EVEN_IF_PAYMENT_DONE) || ($resteapayer == price2num($object->total_ttc, 'MT', 1) && empty($object->paye))) {
5509  if (!$objectidnext && $object->is_last_in_cycle()) {
5510  if ($usercanunvalidate) {
5511  $params['attr']['title'] = '';
5512  print dolGetButtonAction($langs->trans('Modify'), '', 'default', $_SERVER['PHP_SELF'].'?facid='.$object->id.'&action=modif&token='.newToken(), '', true, $params);
5513  } else {
5514  $params['attr']['title'] = $langs->trans('NotEnoughPermissions');
5515  print dolGetButtonAction($langs->trans('Modify'), '', 'default', $_SERVER['PHP_SELF'].'?facid='.$object->id.'&action=modif&token='.newToken(), '', false, $params);
5516  }
5517  } elseif (!$object->is_last_in_cycle()) {
5518  $params['attr']['title'] = $langs->trans('NotLastInCycle');
5519  print dolGetButtonAction($langs->trans('Modify'), '', 'default', '#', '', false, $params);
5520  } else {
5521  $params['attr']['title'] = $langs->trans('DisabledBecauseReplacedInvoice');
5522  print dolGetButtonAction($langs->trans('Modify'), '', 'default', '#', '', false, $params);
5523  }
5524  }
5525  } else {
5526  $params['attr']['title'] = $langs->trans('DisabledBecauseDispatchedInBookkeeping');
5527  print dolGetButtonAction($langs->trans('Modify'), '', 'default', '#', '', false, $params);
5528  }
5529  }
5530 
5531  $discount = new DiscountAbsolute($db);
5532  $result = $discount->fetch(0, $object->id);
5533 
5534  // Reopen an invoice
5535  if ((($object->type == Facture::TYPE_STANDARD || $object->type == Facture::TYPE_REPLACEMENT)
5536  || ($object->type == Facture::TYPE_CREDIT_NOTE && empty($discount->id))
5537  || ($object->type == Facture::TYPE_DEPOSIT && empty($discount->id))
5538  || ($object->type == Facture::TYPE_SITUATION && empty($discount->id)))
5539  && ($object->statut == Facture::STATUS_CLOSED || $object->statut == Facture::STATUS_ABANDONED || ($object->statut == 1 && $object->paye == 1)) // Condition ($object->statut == 1 && $object->paye == 1) should not happened but can be found due to corrupted data
5540  && ((empty($conf->global->MAIN_USE_ADVANCED_PERMS) && $usercancreate) || $usercanreopen)) { // A paid invoice (partially or completely)
5541  if ($object->close_code != 'replaced' || (!$objectidnext)) { // Not replaced by another invoice or replaced but the replacement invoice has been deleted
5542  $params['attr']['title'] = '';
5543  print dolGetButtonAction($langs->trans('ReOpen'), '', 'default', $_SERVER['PHP_SELF'].'?facid='.$object->id.'&action=reopen&token='.newToken(), '', true, $params);
5544  } else {
5545  $params['attr']['title'] = $langs->trans("DisabledBecauseReplacedInvoice");
5546  print dolGetButtonAction($langs->trans('ReOpen'), '', 'default', '#', '', false, $params);
5547  }
5548  }
5549 
5550  // Create contract
5551  if (!empty($conf->global->CONTRACT_CREATE_FROM_INVOICE)) {
5552  if (isModEnabled('contrat') && $object->statut == Facture::STATUS_VALIDATED) {
5553  $langs->load("contracts");
5554 
5555  if ($usercancreatecontract) {
5556  print '<a class="butAction" href="' . DOL_URL_ROOT . '/contrat/card.php?action=create&amp;origin=' . $object->element . '&amp;originid=' . $object->id . '&amp;socid=' . $object->socid . '">' . $langs->trans('AddContract') . '</a>';
5557  }
5558  }
5559  }
5560 
5561  // Validate
5562  if ($object->statut == Facture::STATUS_DRAFT && count($object->lines) > 0 && ((($object->type == Facture::TYPE_STANDARD || $object->type == Facture::TYPE_REPLACEMENT || $object->type == Facture::TYPE_DEPOSIT || $object->type == Facture::TYPE_PROFORMA || $object->type == Facture::TYPE_SITUATION) && (!empty($conf->global->FACTURE_ENABLE_NEGATIVE) || $object->total_ttc >= 0)) || ($object->type == Facture::TYPE_CREDIT_NOTE && $object->total_ttc <= 0))) {
5563  if ($usercanvalidate) {
5564  $params['attr']['title'] = '';
5565  print dolGetButtonAction($langs->trans('Validate'), '', 'default', $_SERVER["PHP_SELF"].'?facid='.$object->id.'&action=valid&token='.newToken(), '', true, $params);
5566  }
5567  }
5568 
5569  // Send by mail
5570  if (empty($user->socid)) {
5571  if (($object->statut == Facture::STATUS_VALIDATED || $object->statut == Facture::STATUS_CLOSED) || !empty($conf->global->FACTURE_SENDBYEMAIL_FOR_ALL_STATUS)) {
5572  if ($objectidnext) {
5573  print '<span class="butActionRefused classfortooltip" title="'.$langs->trans("DisabledBecauseReplacedInvoice").'">'.$langs->trans('SendMail').'</span>';
5574  } else {
5575  if ($usercansend) {
5576  $params['attr']['title'] = '';
5577  print dolGetButtonAction('', $langs->trans('SendMail'), 'default', $_SERVER['PHP_SELF'].'?facid='.$object->id.'&action=presend&mode=init#formmailbeforetitle', '', true, $params);
5578  } else {
5579  $params['attr']['title'] = '';
5580  print dolGetButtonAction('', $langs->trans('SendMail'), 'default', '#', '', false, $params);
5581  }
5582  }
5583  }
5584  }
5585 
5586  // Request a direct debit order
5587  if ($object->statut > Facture::STATUS_DRAFT && $object->paye == 0 && $num == 0) {
5588  if ($resteapayer > 0) {
5589  if ($usercancreatewithdrarequest) {
5590  if (!$objectidnext && $object->close_code != 'replaced') { // Not replaced by another invoice
5591  print '<a class="butAction" href="'.DOL_URL_ROOT.'/compta/facture/prelevement.php?facid='.$object->id.'" title="'.dol_escape_htmltag($langs->trans("MakeWithdrawRequest")).'">'.$langs->trans("MakeWithdrawRequest").'</a>';
5592  } else {
5593  print '<span class="butActionRefused classfortooltip" title="'.$langs->trans("DisabledBecauseReplacedInvoice").'">'.$langs->trans('MakeWithdrawRequest').'</span>';
5594  }
5595  } else {
5596  //print '<a class="butActionRefused classfortooltip" href="#" title="'.dol_escape_htmltag($langs->trans("NotEnoughPermissions")).'">'.$langs->trans("MakeWithdrawRequest").'</a>';
5597  }
5598  } else {
5599  //print '<a class="butActionRefused classfortooltip" href="#" title="'.dol_escape_htmltag($langs->trans("AmountMustBePositive")).'">'.$langs->trans("MakeWithdrawRequest").'</a>';
5600  }
5601  }
5602 
5603  // POS Ticket
5604  if (isModEnabled('takepos') && $object->module_source == 'takepos') {
5605  $langs->load("cashdesk");
5606  $receipt_url = DOL_URL_ROOT."/takepos/receipt.php";
5607  print '<a target="_blank" rel="noopener noreferrer" class="butAction" href="'.$receipt_url.'?facid='.((int) $object->id).'">'.$langs->trans('POSTicket').'</a>';
5608  }
5609 
5610  // Create payment
5611  if ($object->type != Facture::TYPE_CREDIT_NOTE && $object->statut == 1 && $object->paye == 0 && $usercanissuepayment) {
5612  if ($objectidnext) {
5613  print '<span class="butActionRefused classfortooltip" title="'.$langs->trans("DisabledBecauseReplacedInvoice").'">'.$langs->trans('DoPayment').'</span>';
5614  } else {
5615  if ($object->type == Facture::TYPE_DEPOSIT && $resteapayer == 0) {
5616  // For down payment, we refuse to receive more than amount to pay.
5617  $params['attr']['title'] = $langs->trans('DisabledBecauseRemainderToPayIsZero');
5618  print dolGetButtonAction($langs->trans('DoPayment'), '', 'default', '#', '', false, $params);
5619  } else {
5620  // Sometimes we can receive more, so we accept to enter more and will offer a button to convert into discount (but it is not a credit note, just a prepayment done)
5621  //print '<a class="butAction" href="'.DOL_URL_ROOT.'/compta/paiement.php?facid='.$object->id.'&amp;action=create&amp;accountid='.$object->fk_account.'">'.$langs->trans('DoPayment').'</a>';
5622  $params['attr']['title'] = '';
5623  print dolGetButtonAction($langs->trans('DoPayment'), '', 'default', DOL_URL_ROOT.'/compta/paiement.php?facid='.$object->id.'&amp;action=create&amp;accountid='.$object->fk_account, '', true, $params);
5624  }
5625  }
5626  }
5627 
5628  $sumofpayment = $totalpaid;
5629  $sumofpaymentall = $totalpaid + $totalcreditnotes + $totaldeposits;
5630 
5631  // Reverse back money or convert to reduction
5632  if ($object->type == Facture::TYPE_CREDIT_NOTE || $object->type == Facture::TYPE_DEPOSIT || $object->type == Facture::TYPE_STANDARD || $object->type == Facture::TYPE_SITUATION) {
5633  // For credit note only
5634  if ($object->type == Facture::TYPE_CREDIT_NOTE && $object->statut == Facture::STATUS_VALIDATED && $object->paye == 0 && $usercanissuepayment) {
5635  if ($resteapayer == 0) {
5636  print '<span class="butActionRefused classfortooltip" title="'.$langs->trans("DisabledBecauseRemainderToPayIsZero").'">'.$langs->trans('DoPaymentBack').'</span>';
5637  } else {
5638  print '<a class="butAction" href="'.DOL_URL_ROOT.'/compta/paiement.php?facid='.$object->id.'&amp;action=create&amp;accountid='.$object->fk_account.'">'.$langs->trans('DoPaymentBack').'</a>';
5639  }
5640  }
5641 
5642  // For standard invoice with excess received
5643  if (($object->type == Facture::TYPE_STANDARD || $object->type == Facture::TYPE_SITUATION) && $object->statut == Facture::STATUS_VALIDATED && empty($object->paye) && $resteapayer < 0 && $usercancreate && empty($discount->id)) {
5644  print '<a class="butAction'.($conf->use_javascript_ajax ? ' reposition' : '').'" href="'.$_SERVER["PHP_SELF"].'?facid='.$object->id.'&amp;action=converttoreduc">'.$langs->trans('ConvertExcessReceivedToReduc').'</a>';
5645  }
5646  // For credit note
5647  if ($object->type == Facture::TYPE_CREDIT_NOTE && $object->statut == Facture::STATUS_VALIDATED && $object->paye == 0 && $usercancreate
5648  && (!empty($conf->global->INVOICE_ALLOW_REUSE_OF_CREDIT_WHEN_PARTIALLY_REFUNDED) || $sumofpayment == 0)
5649  ) {
5650  print '<a class="butAction'.($conf->use_javascript_ajax ? ' reposition' : '').'" href="'.$_SERVER["PHP_SELF"].'?facid='.$object->id.'&amp;action=converttoreduc" title="'.dol_escape_htmltag($langs->trans("ConfirmConvertToReduc2")).'">'.$langs->trans('ConvertToReduc').'</a>';
5651  }
5652  // For down payment invoice (deposit)
5653  if ($object->type == Facture::TYPE_DEPOSIT && $usercancreate && $object->statut > Facture::STATUS_DRAFT && empty($discount->id)) {
5654  if (price2num($object->total_ttc, 'MT') == price2num($sumofpaymentall, 'MT') || ($object->type == Facture::STATUS_ABANDONED && in_array($object->close_code, array('bankcharge', 'discount_vat', 'other')))) {
5655  // We can close a down payment only if paid amount is same than amount of down payment (by definition)
5656  print '<a class="butAction'.($conf->use_javascript_ajax ? ' reposition' : '').'" href="'.$_SERVER["PHP_SELF"].'?facid='.$object->id.'&amp;action=converttoreduc">'.$langs->trans('ConvertToReduc').'</a>';
5657  } else {
5658  print '<span class="butActionRefused" title="'.$langs->trans("AmountPaidMustMatchAmountOfDownPayment").'">'.$langs->trans('ConvertToReduc').'</span>';
5659  }
5660  }
5661  }
5662 
5663  // Classify paid
5664  if ($object->statut == Facture::STATUS_VALIDATED && $object->paye == 0 && $usercanissuepayment && (
5665  ($object->type != Facture::TYPE_CREDIT_NOTE && $object->type != Facture::TYPE_DEPOSIT && ($resteapayer <= 0 || (!empty($conf->global->INVOICE_CAN_SET_PAID_EVEN_IF_PARTIALLY_PAID) && $object->total_ttc == $resteapayer))) ||
5666  ($object->type == Facture::TYPE_CREDIT_NOTE && $resteapayer >= 0) ||
5667  ($object->type == Facture::TYPE_DEPOSIT && $object->total_ttc > 0)
5668  )
5669  ) {
5670  if ($object->type == Facture::TYPE_DEPOSIT && price2num($object->total_ttc, 'MT') != price2num($sumofpaymentall, 'MT')) {
5671  // We can close a down payment only if paid amount is same than amount of down payment (by definition)
5672  $params['attr']['title'] = $langs->trans('AmountPaidMustMatchAmountOfDownPayment');
5673  print dolGetButtonAction($langs->trans('ClassifyPaid'), '', 'default', '#', '', false, $params);
5674  } else {
5675  $params['attr']['title'] = '';
5676  print dolGetButtonAction($langs->trans('ClassifyPaid'), '', 'default', $_SERVER['PHP_SELF'].'?facid='.$object->id.'&amp;action=paid', '', true, $params);
5677  }
5678  }
5679 
5680  // Classify 'closed not completely paid' (possible if validated and not yet filed paid)
5681  if ($object->statut == Facture::STATUS_VALIDATED && $object->paye == 0 && $resteapayer > 0 && (empty($conf->global->INVOICE_CAN_SET_PAID_EVEN_IF_PARTIALLY_PAID) || $resteapayer != $object->total_ttc) && $usercanissuepayment) {
5682  if ($totalpaid > 0 || $totalcreditnotes > 0) {
5683  // If one payment or one credit note was linked to this invoice
5684  print '<a class="butAction'.($conf->use_javascript_ajax ? ' reposition' : '').'" href="'.$_SERVER['PHP_SELF'].'?facid='.$object->id.'&amp;action=paid">'.$langs->trans('ClassifyPaidPartially').'</a>';
5685  } else {
5686  if (empty($conf->global->INVOICE_CAN_NEVER_BE_CANCELED)) {
5687  if ($objectidnext) {
5688  print '<span class="butActionRefused classfortooltip" title="'.$langs->trans("DisabledBecauseReplacedInvoice").'">'.$langs->trans('ClassifyCanceled').'</span>';
5689  } else {
5690  print '<a class="butAction'.($conf->use_javascript_ajax ? ' reposition' : '').'" href="'.$_SERVER['PHP_SELF'].'?facid='.$object->id.'&amp;action=canceled">'.$langs->trans('ClassifyCanceled').'</a>';
5691  }
5692  }
5693  }
5694  }
5695 
5696  // Create a credit note
5697  if (($object->type == Facture::TYPE_STANDARD || ($object->type == Facture::TYPE_DEPOSIT && empty($conf->global->FACTURE_DEPOSITS_ARE_JUST_PAYMENTS)) || $object->type == Facture::TYPE_PROFORMA) && $object->statut > 0 && $usercancreate) {
5698  if (!$objectidnext) {
5699  print '<a class="butAction" href="'.$_SERVER['PHP_SELF'].'?socid='.$object->socid.'&amp;fac_avoir='.$object->id.'&amp;action=create&amp;type=2'.($object->fk_project > 0 ? '&amp;projectid='.$object->fk_project : '').($object->entity > 0 ? '&amp;originentity='.$object->entity : '').'">'.$langs->trans("CreateCreditNote").'</a>';
5700  }
5701  }
5702 
5703  // For situation invoice with excess received
5704  if ($object->statut > Facture::STATUS_DRAFT
5705  && $object->type == Facture::TYPE_SITUATION
5706  && ($object->total_ttc - $totalpaid - $totalcreditnotes - $totaldeposits) > 0
5707  && $usercancreate
5708  && !$objectidnext
5709  && $object->is_last_in_cycle()
5710  && getDolGlobalInt('INVOICE_USE_SITUATION_CREDIT_NOTE')
5711  ) {
5712  if ($usercanunvalidate) {
5713  print '<a class="butAction" href="'.$_SERVER['PHP_SELF'].'?socid='.$object->socid.'&amp;fac_avoir='.$object->id.'&amp;invoiceAvoirWithLines=1&amp;action=create&amp;type=2'.($object->fk_project > 0 ? '&amp;projectid='.$object->fk_project : '').'">'.$langs->trans("CreateCreditNote").'</a>';
5714  } else {
5715  print '<span class="butActionRefused classfortooltip" title="'.$langs->trans("NotEnoughPermissions").'">'.$langs->trans("CreateCreditNote").'</span>';
5716  }
5717  }
5718 
5719  // Clone
5720  if (($object->type == Facture::TYPE_STANDARD || $object->type == Facture::TYPE_DEPOSIT || $object->type == Facture::TYPE_PROFORMA) && $usercancreate) {
5721  $params['attr']['title'] = '';
5722  print dolGetButtonAction($langs->trans('ToClone'), '', 'default', $_SERVER['PHP_SELF'].'?facid='.$object->id.'&amp;action=clone&amp;object=invoice', '', true, $params);
5723  }
5724 
5725  // Clone as predefined / Create template
5726  if (($object->type == Facture::TYPE_STANDARD || $object->type == Facture::TYPE_DEPOSIT || $object->type == Facture::TYPE_PROFORMA) && $object->statut == 0 && $usercancreate) {
5727  if (!$objectidnext && count($object->lines) > 0) {
5728  $params['attr']['title'] = '';
5729  print dolGetButtonAction($langs->trans('ChangeIntoRepeatableInvoice'), '', 'default', DOL_URL_ROOT.'/compta/facture/card-rec.php?facid='.$object->id.'&amp;action=create', '', true, $params);
5730  }
5731  }
5732 
5733  // Remove situation from cycle
5734  if (in_array($object->statut, array(Facture::STATUS_CLOSED, Facture::STATUS_VALIDATED))
5735  && $object->type == Facture::TYPE_SITUATION
5736  && $usercancreate
5737  && !$objectidnext
5738  && $object->situation_counter > 1
5739  && $object->is_last_in_cycle()
5740  && $usercanunvalidate
5741  ) {
5742  if (($object->total_ttc - $totalcreditnotes) == 0) {
5743  print '<a id="butSituationOut" class="butAction" href="'.$_SERVER['PHP_SELF'].'?facid='.$object->id.'&amp;action=situationout">'.$langs->trans("RemoveSituationFromCycle").'</a>';
5744  } else {
5745  print '<a id="butSituationOutRefused" class="butActionRefused classfortooltip" href="#" title="'.$langs->trans("DisabledBecauseNotEnouthCreditNote").'" >'.$langs->trans("RemoveSituationFromCycle").'</a>';
5746  }
5747  }
5748 
5749  // Create next situation invoice
5750  if ($usercancreate && ($object->type == 5) && ($object->statut == 1 || $object->statut == 2)) {
5751  if ($object->is_last_in_cycle() && $object->situation_final != 1) {
5752  print '<a class="butAction" href="'.$_SERVER['PHP_SELF'].'?action=create&amp;type=5&amp;origin=facture&amp;originid='.$object->id.'&amp;socid='.$object->socid.'" >'.$langs->trans('CreateNextSituationInvoice').'</a>';
5753  } elseif (!$object->is_last_in_cycle()) {
5754  print '<a class="butActionRefused classfortooltip" href="#" title="'.$langs->trans("DisabledBecauseNotLastInCycle").'">'.$langs->trans('CreateNextSituationInvoice').'</a>';
5755  } else {
5756  print '<a class="butActionRefused classfortooltip" href="#" title="'.$langs->trans("DisabledBecauseFinal").'">'.$langs->trans('CreateNextSituationInvoice').'</a>';
5757  }
5758  }
5759 
5760  // Delete
5761  $isErasable = $object->is_erasable();
5762  if ($usercandelete || ($usercancreate && $isErasable == 1)) { // isErasable = 1 means draft with temporary ref (draft can always be deleted with no need of permissions)
5763  $enableDelete = false;
5764  $deleteHref = '#';
5765  $htmltooltip = '';
5766  if ($isErasable == -4) {
5767  $htmltooltip = $langs->trans('DisabledBecausePayments');
5768  } elseif ($isErasable == -3) {
5769  $htmltooltip = $langs->trans('DisabledBecauseNotLastSituationInvoice');
5770  } elseif ($isErasable == -2) {
5771  $htmltooltip = $langs->trans('DisabledBecauseNotLastInvoice');
5772  } elseif ($isErasable == -1) {
5773  $htmltooltip = $langs->trans('DisabledBecauseDispatchedInBookkeeping');
5774  } elseif ($isErasable <= 0) { // Any other cases
5775  $htmltooltip = $langs->trans('DisabledBecauseNotErasable');
5776  } elseif ($objectidnext) {
5777  $htmltooltip = $langs->trans('DisabledBecauseReplacedInvoice');
5778  } else {
5779  $deleteHref = $_SERVER["PHP_SELF"].'?facid='.$object->id.'&action=delete&token='.newToken();
5780  $enableDelete = true;
5781  }
5782  $params['attr']['title'] = '';
5783  print dolGetButtonAction($htmltooltip, $langs->trans('Delete'), 'delete', $deleteHref, '', $enableDelete, $params);
5784  } else {
5785  $params['attr']['title'] = '';
5786  print dolGetButtonAction($langs->trans('Delete'), $langs->trans('Delete'), 'delete', '#', '', false);
5787  }
5788  }
5789  print '</div>';
5790  }
5791 
5792  // Select mail models is same action as presend
5793  if (GETPOST('modelselected', 'alpha')) {
5794  $action = 'presend';
5795  }
5796  if ($action != 'prerelance' && $action != 'presend') {
5797  print '<div class="fichecenter"><div class="fichehalfleft">';
5798  print '<a name="builddoc"></a>'; // ancre
5799 
5800  // Generated documents
5801  $filename = dol_sanitizeFileName($object->ref);
5802  $filedir = $conf->facture->multidir_output[$object->entity].'/'.dol_sanitizeFileName($object->ref);
5803  $urlsource = $_SERVER['PHP_SELF'].'?facid='.$object->id;
5804  $genallowed = $usercanread;
5805  $delallowed = $usercancreate;
5806 
5807  print $formfile->showdocuments(
5808  'facture',
5809  $filename,
5810  $filedir,
5811  $urlsource,
5812  $genallowed,
5813  $delallowed,
5814  $object->model_pdf,
5815  1,
5816  0,
5817  0,
5818  28,
5819  0,
5820  '',
5821  '',
5822  '',
5823  $soc->default_lang,
5824  '',
5825  $object,
5826  0,
5827  'remove_file_comfirm'
5828  );
5829 
5830  $somethingshown = $formfile->numoffiles;
5831 
5832  // Show links to link elements
5833  $linktoelem = $form->showLinkToObjectBlock($object, null, array('invoice'));
5834 
5835  $compatibleImportElementsList = false;
5836  if ($usercancreate
5837  && $object->statut == Facture::STATUS_DRAFT
5838  && ($object->type == Facture::TYPE_STANDARD || $object->type == Facture::TYPE_REPLACEMENT || $object->type == Facture::TYPE_DEPOSIT || $object->type == Facture::TYPE_PROFORMA || $object->type == Facture::TYPE_SITUATION)) {
5839  $compatibleImportElementsList = array('commande', 'propal'); // import from linked elements
5840  }
5841  $somethingshown = $form->showLinkedObjectBlock($object, $linktoelem, $compatibleImportElementsList);
5842 
5843 
5844  // Show online payment link
5845  $useonlinepayment = (isModEnabled('paypal') || isModEnabled('stripe') || isModEnabled('paybox'));
5846 
5847  if ($object->statut != Facture::STATUS_DRAFT && $useonlinepayment) {
5848  print '<br><!-- Link to pay -->'."\n";
5849  require_once DOL_DOCUMENT_ROOT.'/core/lib/payments.lib.php';
5850  print showOnlinePaymentUrl('invoice', $object->ref).'<br>';
5851  }
5852 
5853  print '</div><div class="fichehalfright">';
5854 
5855  $MAXEVENT = 10;
5856 
5857  $morehtmlcenter = dolGetButtonTitle($langs->trans('SeeAll'), '', 'fa fa-bars imgforviewmode', DOL_URL_ROOT.'/compta/facture/agenda.php?id='.$object->id);
5858 
5859  // List of actions on element
5860  include_once DOL_DOCUMENT_ROOT.'/core/class/html.formactions.class.php';
5861  $formactions = new FormActions($db);
5862  $somethingshown = $formactions->showactions($object, 'invoice', $socid, 1, '', $MAXEVENT, '', $morehtmlcenter); // Show all action for thirdparty
5863 
5864  print '</div></div>';
5865  }
5866 
5867 
5868  // Presend form
5869  $modelmail = 'facture_send';
5870  $defaulttopic = 'SendBillRef';
5871  $diroutput = $conf->facture->multidir_output[$object->entity];
5872  $trackid = 'inv'.$object->id;
5873 
5874  include DOL_DOCUMENT_ROOT.'/core/tpl/card_presend.tpl.php';
5875 }
5876 
5877 // End of page
5878 llxFooter();
5879 $db->close();
if(GETPOST('button_removefilter_x', 'alpha')||GETPOST('button_removefilter.x', 'alpha')||GETPOST('button_removefilter', 'alpha')) if(GETPOST('button_search_x', 'alpha')||GETPOST('button_search.x', 'alpha')||GETPOST('button_search', 'alpha')) if($action=="save" &&empty($cancel)) $help_url
View.
Definition: agenda.php:118
if(preg_match('/set_([a-z0-9_\-]+)/i', $action, $reg)) if(preg_match('/del_([a-z0-9_\-]+)/i', $action, $reg)) if($action=='set') elseif($action=='specimen') elseif($action=='setmodel') elseif($action=='del') elseif($action=='setdoc') $formactions
View.
ajax_combobox($htmlname, $events=array(), $minLengthToAutocomplete=0, $forcefocus=0, $widthTypeOfAutocomplete='resolve', $idforemptyvalue='-1', $morecss='')
Convert a html select field into an ajax combobox.
Definition: ajax.lib.php:449
if(!defined('NOREQUIRESOC')) if(!defined('NOREQUIRETRAN')) if(!defined('NOTOKENRENEWAL')) if(!defined('NOREQUIREMENU')) if(!defined('NOREQUIREHTML')) if(!defined('NOREQUIREAJAX')) llxHeader()
Empty header.
Definition: wrapper.php:56
llxFooter()
Empty footer.
Definition: wrapper.php:70
Class to manage bank accounts.
Class to manage accounting journals.
Class to manage absolute discounts.
Class to manage a WYSIWYG editor.
Class to manage warehouses.
Class to manage shipments.
Class to manage standard extra fields.
Class to manage invoices.
const TYPE_REPLACEMENT
Replacement invoice.
const STATUS_DRAFT
Draft status.
const TYPE_STANDARD
Standard invoice.
const TYPE_SITUATION
Situation invoice.
const TYPE_PROFORMA
Proforma invoice (should not be used.
const STATUS_VALIDATED
Validated (need to be paid)
const TYPE_DEPOSIT
Deposit invoice.
const STATUS_ABANDONED
Classified abandoned and no payment done.
const TYPE_CREDIT_NOTE
Credit note invoice.
const STATUS_CLOSED
Classified paid.
Class to manage invoice lines.
Class to manage invoice templates.
Class to manage building of HTML components.
Class to offer components to list and upload files.
Class to manage generation of HTML components Only common components must be here.
Classe permettant la generation de composants html autre Only common components are here.
Classe permettant la generation de composants html autre Only common components are here.
Class with static methods for building HTML components related to products Only components common to ...
Class to manage building of HTML components.
static liste_modeles($db, $maxfilenamelength=0)
Return list of active generation modules.
static getIdAndTxFromCode($dbs, $code, $date_document='')
Get id and rate of currency from code.
Class to manage notifications.
Class to manage payments of customer invoices.
Class ProductCombination Used to represent a product combination.
Class to manage products or services.
Class to manage projects.
Class to manage third parties objects (customers, suppliers, prospects...)
Class to manage translations.
Class to manage Dolibarr users.
Definition: user.class.php:48
getCountry($searchkey, $withcode='', $dbtouse=0, $outputlangs='', $entconv=1, $searchlabel='')
Return country label, code or id from an id, code or label.
$parameters
Actions.
Definition: card.php:83
if(isModEnabled('facture') && $user->hasRight('facture', 'lire')) if((isModEnabled('fournisseur') &&empty($conf->global->MAIN_USE_NEW_SUPPLIERMOD) && $user->hasRight("fournisseur", "facture", "lire"))||(isModEnabled('supplier_invoice') && $user->hasRight("supplier_invoice", "lire"))) if(isModEnabled('don') && $user->hasRight('don', 'lire')) if(isModEnabled('tax') &&!empty($user->rights->tax->charges->lire)) if(isModEnabled('facture') &&isModEnabled('commande') && $user->hasRight("commande", "lire") &&empty($conf->global->WORKFLOW_DISABLE_CREATE_INVOICE_FROM_ORDER)) $sql
Social contributions to pay.
Definition: index.php:746
if($cancel &&! $id) if($action=='add' &&! $cancel) if($action=='delete') if($id) $form
Actions.
Definition: card.php:143
dol_get_last_hour($date, $gm='tzserver')
Return GMT time for last hour of a given GMT date (it replaces hours, min and second part to 23:59:59...
Definition: date.lib.php:622
dol_time_plus_duree($time, $duration_value, $duration_unit, $ruleforendofmonth=0)
Add a delay to a date.
Definition: date.lib.php:122
dol_stringtotime($string, $gm=1)
Convert a string date into a GM Timestamps date Warning: YYYY-MM-DDTHH:MM:SS+02:00 (RFC3339) is not s...
Definition: date.lib.php:408
dol_banner_tab($object, $paramid, $morehtml='', $shownav=1, $fieldid='rowid', $fieldref='ref', $morehtmlref='', $moreparam='', $nodbprefix=0, $morehtmlleft='', $morehtmlstatus='', $onlybanner=0, $morehtmlright='')
Show tab footer of a card.
dol_mktime($hour, $minute, $second, $month, $day, $year, $gm='auto', $check=1)
Return a timestamp date built from detailed informations (by default a local PHP server timestamp) Re...
load_fiche_titre($titre, $morehtmlright='', $picto='generic', $pictoisfullpath=0, $id='', $morecssontable='', $morehtmlcenter='')
Load a title with picto.
img_warning($titlealt='default', $moreatt='', $morecss='pictowarning')
Show warning logo.
img_delete($titlealt='default', $other='class="pictodelete"', $morecss='')
Show delete logo.
GETPOSTINT($paramname, $method=0)
Return value of a param into GET or POST supervariable.
dol_get_fiche_head($links=array(), $active='', $title='', $notab=0, $picto='', $pictoisfullpath=0, $morehtmlright='', $morecss='', $limittoshow=0, $moretabssuffix='', $dragdropfile=0)
Show tabs of a record.
price2num($amount, $rounding='', $option=0)
Function that return a number with universal decimal format (decimal separator is '.
dol_print_error($db='', $error='', $errors=null)
Displays error message system with all the information to facilitate the diagnosis and the escalation...
dolGetButtonTitle($label, $helpText='', $iconClass='fa fa-file', $url='', $id='', $status=1, $params=array())
Function dolGetButtonTitle : this kind of buttons are used in title in list.
dol_get_fiche_end($notab=0)
Return tab footer of a card.
price($amount, $form=0, $outlangs='', $trunc=1, $rounding=-1, $forcerounding=-1, $currency_code='')
Function to format a value into an amount for visual output Function used into PDF and HTML pages.
dol_print_date($time, $format='', $tzoutput='auto', $outputlangs='', $encodetooutput=false)
Output date in a string format according to outputlangs (or langs if not defined).
if(!function_exists('dol_getprefix')) dol_include_once($relpath, $classname='')
Make an include_once using default root and alternate root if it fails.
dol_now($mode='auto')
Return date for now.
getDolGlobalInt($key, $default=0)
Return dolibarr global constant int value.
img_picto($titlealt, $picto, $moreatt='', $pictoisfullpath=false, $srconly=0, $notitle=0, $alt='', $morecss='', $marginleftonlyshort=2)
Show picto whatever it's its name (generic function)
newToken()
Return the value of token currently saved into session with name 'newtoken'.
dol_clone($object, $native=0)
Create a clone of instance of object (new instance with same value for each properties) With native =...
dolGetButtonAction($label, $text='', $actionType='default', $url='', $id='', $userRight=1, $params=array())
Function dolGetButtonAction.
dol_htmlcleanlastbr($stringtodecode)
This function remove all ending and br at end.
dol_concatdesc($text1, $text2, $forxml=false, $invert=false)
Concat 2 descriptions with a new line between them (second operand after first one with appropriate n...
GETPOST($paramname, $check='alphanohtml', $method=0, $filter=null, $options=null, $noreplace=0)
Return value of a param into GET or POST supervariable.
info_admin($text, $infoonimgalt=0, $nodiv=0, $admin='1', $morecss='hideonsmartphone', $textfordropdown='')
Show information for admin users or standard users.
setEventMessages($mesg, $mesgs, $style='mesgs', $messagekey='', $noduplicate=0)
Set event messages in dol_events session object.
get_localtax($vatrate, $local, $thirdparty_buyer="", $thirdparty_seller="", $vatnpr=0)
Return localtax rate for a particular vat, when selling a product with vat $vatrate,...
dol_sanitizeFileName($str, $newstr='_', $unaccent=1)
Clean a string to use it as a file name.
GETPOSTISSET($paramname)
Return true if we are in a context of submitting the parameter $paramname from a POST of a form.
getDolGlobalString($key, $default='')
Return dolibarr global constant string value.
isModEnabled($module)
Is Dolibarr module enabled.
img_edit($titlealt='default', $float=0, $other='')
Show logo editer/modifier fiche.
getDictionaryValue($tablename, $field, $id, $checkentity=false, $rowidfield='rowid')
Return the value of a filed into a dictionary for the record $id.
dol_syslog($message, $level=LOG_INFO, $ident=0, $suffixinfilename='', $restricttologhandler='', $logcontext=null)
Write log message into outputs.
dol_getdate($timestamp, $fast=false, $forcetimezone='')
Return an array with locale date info.
dol_escape_htmltag($stringtoescape, $keepb=0, $keepn=0, $noescapetags='', $escapeonlyhtmltags=0, $cleanalsojavascript=0)
Returns text escaped for inclusion in HTML alt or title or value tags, or into values of HTML input f...
facture_prepare_head($object)
Initialize the array of tabs for customer invoice.
Definition: invoice.lib.php:36
if(!defined( 'CSRFCHECK_WITH_TOKEN'))
$formconfirm
if ($action == 'delbookkeepingyear') {
div float
Buy price without taxes.
Definition: style.css.php:921
calcul_price_total($qty, $pu, $remise_percent_ligne, $txtva, $uselocaltax1_rate, $uselocaltax2_rate, $remise_percent_global, $price_base_type, $info_bits, $type, $seller='', $localtaxes_array='', $progress=100, $multicurrency_tx=1, $pu_devise=0, $multicurrency_code='')
Calculate totals (net, vat, ...) of a line.
Definition: price.lib.php:86
restrictedArea(User $user, $features, $object=0, $tableandshare='', $feature2='', $dbt_keyfield='fk_soc', $dbt_select='rowid', $isdraft=0, $mode=0)
Check permissions of a user to show a page and an object.
accessforbidden($message='', $printheader=1, $printfooter=1, $showonlymessage=0, $params=null)
Show a message to say access is forbidden and stop program.