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