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