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