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