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 = GETPOSTINT('ref_client');
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'));
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 $coef = $total / $srcobject->total_ttc; // Calc coef
1611 $am = $amount * $coef;
1612 $amount_ttc_diff += $am;
1613 $amountdeposit[$tva] += $am / (1 + (float) $tva / 100); // Convert into HT for the addline
1614 }
1615 } else {
1616 if ($typeamount == 'amount') {
1617 $amountdeposit[0] = $valuedeposit;
1618 } elseif ($typeamount == 'variable') {
1619 if ($result > 0) {
1620 $totalamount = 0;
1621 $lines = $srcobject->lines;
1622 $numlines = count($lines);
1623 for ($i = 0; $i < $numlines; $i++) {
1624 $qualified = 1;
1625 if (empty($lines[$i]->qty)) {
1626 $qualified = 0; // We discard qty=0, it is an option
1627 }
1628 if (!empty($lines[$i]->special_code)) {
1629 $qualified = 0; // We discard special_code (frais port, ecotaxe, option, ...)
1630 }
1631 if ($qualified) {
1632 $totalamount += $lines[$i]->total_ht; // Fixme : is it not for the customer ? Shouldn't we take total_ttc ?
1633 $tva_tx = $lines[$i]->tva_tx;
1634 $amountdeposit[$tva_tx] += ($lines[$i]->total_ht * (float) $valuedeposit) / 100;
1635 }
1636 }
1637
1638 if ($totalamount == 0) {
1639 $amountdeposit[0] = 0;
1640 }
1641 } else {
1642 setEventMessages($srcobject->error, $srcobject->errors, 'errors');
1643 $error++;
1644 }
1645 }
1646
1647 $amount_ttc_diff = $amountdeposit[0];
1648 }
1649
1650 foreach ($amountdeposit as $tva => $amount) {
1651 if (empty($amount)) {
1652 continue;
1653 }
1654
1655 $arraylist = array(
1656 'amount' => 'FixAmount',
1657 'variable' => 'VarAmount'
1658 );
1659 $descline = '(DEPOSIT)';
1660 //$descline.= ' - '.$langs->trans($arraylist[$typeamount]);
1661 if ($typeamount == 'amount') {
1662 $descline .= ' ('.price($valuedeposit, 0, $langs, 0, - 1, - 1, (!empty($object->multicurrency_code) ? $object->multicurrency_code : $conf->currency)).')';
1663 } elseif ($typeamount == 'variable') {
1664 $descline .= ' ('.$valuedeposit.'%)';
1665 }
1666
1667 $descline .= ' - '.$srcobject->ref;
1668 $result = $object->addline(
1669 $descline,
1670 $amount, // subprice
1671 1, // quantity
1672 $tva, // vat rate
1673 0, // localtax1_tx
1674 0, // localtax2_tx
1675 getDolGlobalInt('INVOICE_PRODUCTID_DEPOSIT'), // fk_product
1676 0, // remise_percent
1677 0, // date_start
1678 0, // date_end
1679 0,
1680 $lines[$i]->info_bits, // info_bits
1681 0,
1682 'HT',
1683 0,
1684 0, // product_type
1685 1,
1686 $lines[$i]->special_code,
1687 $object->origin,
1688 0,
1689 0,
1690 0,
1691 0,
1692 '',
1693 array(), // array_options
1694 100,
1695 0,
1696 null,
1697 0,
1698 '',
1699 (!empty($conf->global->MAIN_DEPOSIT_MULTI_TVA) ? 0 : 1)
1700 );
1701 }
1702
1703 $diff = $object->total_ttc - $amount_ttc_diff;
1704
1705 if (getDolGlobalString('MAIN_DEPOSIT_MULTI_TVA') && $diff != 0) {
1706 $object->fetch_lines();
1707 $subprice_diff = $object->lines[0]->subprice - $diff / (1 + $object->lines[0]->tva_tx / 100);
1708 $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);
1709 }
1710 }
1711
1712 // standard invoice, credit note, or down payment from a percent of all lines
1713 if (GETPOST('type') != Facture::TYPE_DEPOSIT || (GETPOST('type') == Facture::TYPE_DEPOSIT && $typeamount == 'variablealllines')) {
1714 if ($result > 0) {
1715 $lines = $srcobject->lines;
1716 if (empty($lines) && method_exists($srcobject, 'fetch_lines')) {
1717 $srcobject->fetch_lines();
1718 $lines = $srcobject->lines;
1719 }
1720
1721 // If we create a standard invoice with a percent, we change amount by changing the qty
1722 if (GETPOST('type') == Facture::TYPE_STANDARD && $valuestandardinvoice > 0 && $valuestandardinvoice < 100) {
1723 if (is_array($lines)) {
1724 foreach ($lines as $line) {
1725 // We keep ->subprice and ->pa_ht, but we change the qty
1726 $line->qty = price2num((float) $line->qty * (float) $valuestandardinvoice / 100, 'MS');
1727 }
1728 }
1729 }
1730 // If we create a down payment with a percent on all lines, we change amount by changing the qty
1731 if (GETPOST('type') == Facture::TYPE_DEPOSIT && $typeamount == 'variablealllines') {
1732 if (is_array($lines)) {
1733 foreach ($lines as $line) {
1734 // We keep ->subprice and ->pa_ht, but we change the qty
1735 $line->qty = price2num((float) $line->qty * (float) $valuedeposit / 100, 'MS');
1736 }
1737 }
1738 }
1739
1740 $fk_parent_line = 0;
1741 $num = count($lines);
1742
1743 for ($i = 0; $i < $num; $i++) {
1744 if (!in_array($lines[$i]->id, $selectedLines)) {
1745 continue; // Skip unselected lines
1746 }
1747
1748 // Don't add lines with qty 0 when coming from a shipment including all order lines
1749 if ($srcobject->element == 'shipping' && getDolGlobalString('SHIPMENT_GETS_ALL_ORDER_PRODUCTS') && $lines[$i]->qty == 0) {
1750 continue;
1751 }
1752 // Don't add closed lines when coming from a contract (Set constant to '0,5' to exclude also inactive lines)
1753 if (!isset($conf->global->CONTRACT_EXCLUDE_SERVICES_STATUS_FOR_INVOICE)) {
1754 $conf->global->CONTRACT_EXCLUDE_SERVICES_STATUS_FOR_INVOICE = '5';
1755 }
1756 if ($srcobject->element == 'contrat' && in_array($lines[$i]->statut, explode(',', getDolGlobalString('CONTRACT_EXCLUDE_SERVICES_STATUS_FOR_INVOICE')))) {
1757 continue;
1758 }
1759
1760 $label = (!empty($lines[$i]->label) ? $lines[$i]->label : '');
1761 $desc = (!empty($lines[$i]->desc) ? $lines[$i]->desc : '');
1762
1763 if ($object->situation_counter == 1) {
1764 $lines[$i]->situation_percent = 0;
1765 }
1766
1767 if ($lines[$i]->subprice < 0 && !getDolGlobalString('INVOICE_KEEP_DISCOUNT_LINES_AS_IN_ORIGIN')) {
1768 // Negative line, we create a discount line
1769 if (empty($desc)) {
1770 $desc = $label ? $label : $langs->trans('Discount');
1771 }
1772
1773 $discount = new DiscountAbsolute($db);
1774 $discount->fk_soc = $object->socid;
1775 $discount->socid = $object->socid;
1776 $discount->amount_ht = abs($lines[$i]->total_ht);
1777 $discount->amount_tva = abs($lines[$i]->total_tva);
1778 $discount->amount_ttc = abs($lines[$i]->total_ttc);
1779 $discount->tva_tx = $lines[$i]->tva_tx;
1780 $discount->fk_user = $user->id;
1781 $discount->description = $desc;
1782 $discount->multicurrency_subprice = abs($lines[$i]->multicurrency_subprice);
1783 $discount->multicurrency_amount_ht = abs($lines[$i]->multicurrency_total_ht);
1784 $discount->multicurrency_amount_tva = abs($lines[$i]->multicurrency_total_tva);
1785 $discount->multicurrency_amount_ttc = abs($lines[$i]->multicurrency_total_ttc);
1786
1787 $discountid = $discount->create($user);
1788 if ($discountid > 0) {
1789 $result = $object->insert_discount($discountid); // This include link_to_invoice
1790 } else {
1791 setEventMessages($discount->error, $discount->errors, 'errors');
1792 $error++;
1793 break;
1794 }
1795 } else {
1796 // Positive line
1797 // we keep first type from product if exist, otherwise we keep type from line (free line) and at last default Product
1798 $product_type = $lines[$i]->product_type ?? ($lines[$i]->type ?? Product::TYPE_PRODUCT);
1799
1800 // Date start
1801 $date_start = false;
1802 if (isset($lines[$i]->date_debut_prevue)) {
1803 $date_start = $lines[$i]->date_debut_prevue;
1804 }
1805 if (isset($lines[$i]->date_debut_reel)) {
1806 $date_start = $lines[$i]->date_debut_reel;
1807 }
1808 if (isset($lines[$i]->date_start)) {
1809 $date_start = $lines[$i]->date_start;
1810 }
1811
1812 // Date end
1813 $date_end = false;
1814 if (isset($lines[$i]->date_fin_prevue)) {
1815 $date_end = $lines[$i]->date_fin_prevue;
1816 }
1817 if (isset($lines[$i]->date_fin_reel)) {
1818 $date_end = $lines[$i]->date_fin_reel;
1819 }
1820 if (isset($lines[$i]->date_end)) {
1821 $date_end = $lines[$i]->date_end;
1822 }
1823
1824 // Reset fk_parent_line for no child products and special product
1825 if (($lines[$i]->product_type != 9 && empty($lines[$i]->fk_parent_line)) || $lines[$i]->product_type == 9) {
1826 $fk_parent_line = 0;
1827 }
1828
1829 // Extrafields
1830 if (method_exists($lines[$i], 'fetch_optionals')) {
1831 $lines[$i]->fetch_optionals();
1832 $array_options = $lines[$i]->array_options;
1833 }
1834
1835 $tva_tx = $lines[$i]->tva_tx;
1836 if (!empty($lines[$i]->vat_src_code) && !preg_match('/\‍(/', $tva_tx)) {
1837 $tva_tx .= ' ('.$lines[$i]->vat_src_code.')';
1838 }
1839
1840 // View third's localtaxes for NOW and do not use value from origin.
1841 // TODO Is this really what we want ? Yes if source is template invoice but what if proposal or order ?
1842 $localtax1_tx = get_localtax($tva_tx, 1, $object->thirdparty);
1843 $localtax2_tx = get_localtax($tva_tx, 2, $object->thirdparty);
1844
1845 $result = $object->addline(
1846 $desc,
1847 $lines[$i]->subprice,
1848 $lines[$i]->qty,
1849 $tva_tx,
1850 $localtax1_tx,
1851 $localtax2_tx,
1852 $lines[$i]->fk_product,
1853 $lines[$i]->remise_percent,
1854 $date_start,
1855 $date_end,
1856 0,
1857 $lines[$i]->info_bits,
1858 isset($lines[$i]->fk_remise_except) ? $lines[$i]->fk_remise_except : null,
1859 'HT',
1860 0,
1861 $product_type,
1862 $lines[$i]->rang,
1863 $lines[$i]->special_code,
1864 $object->origin,
1865 $lines[$i]->rowid,
1866 $fk_parent_line,
1867 isset($lines[$i]->fk_fournprice) ? $lines[$i]->fk_fournprice : null,
1868 $lines[$i]->pa_ht,
1869 $label,
1870 $array_options,
1871 $lines[$i]->situation_percent ?? 100,
1872 $lines[$i]->fk_prev_id ?? 0,
1873 $lines[$i]->fk_unit,
1874 0,
1875 '',
1876 1
1877 );
1878
1879 if ($result > 0) {
1880 $lineid = $result;
1881 } else {
1882 $lineid = 0;
1883 $error++;
1884 break;
1885 }
1886
1887 // Defined the new fk_parent_line
1888 if ($result > 0 && $lines[$i]->product_type == 9) {
1889 $fk_parent_line = $result;
1890 }
1891 }
1892 }
1893 } else {
1894 setEventMessages($srcobject->error, $srcobject->errors, 'errors');
1895 $error++;
1896 }
1897 }
1898
1899 $object->update_price(1, 'auto', 0, $mysoc);
1900
1901 // Now we create same links to contact than the ones found on origin object
1902 /* Useless, already into the create
1903 if (getDolGlobalString('MAIN_PROPAGATE_CONTACTS_FROM_ORIGIN')) {
1904 $originforcontact = $object->origin;
1905 $originidforcontact = $object->origin_id;
1906 if ($originforcontact == 'shipping') // shipment and order share the same contacts. If creating from shipment we take data of order
1907 {
1908 $originforcontact=$srcobject->origin;
1909 $originidforcontact=$srcobject->origin_id;
1910 }
1911 $sqlcontact = "SELECT code, fk_socpeople FROM ".MAIN_DB_PREFIX."element_contact as ec, ".MAIN_DB_PREFIX."c_type_contact as ctc";
1912 $sqlcontact.= " WHERE element_id = ".((int) $originidforcontact)." AND ec.fk_c_type_contact = ctc.rowid AND ctc.element = '".$db->escape($originforcontact)."'";
1913
1914 $resqlcontact = $db->query($sqlcontact);
1915 if ($resqlcontact)
1916 {
1917 while($objcontact = $db->fetch_object($resqlcontact))
1918 {
1919 //print $objcontact->code.'-'.$objcontact->fk_socpeople."\n";
1920 $object->add_contact($objcontact->fk_socpeople, $objcontact->code);
1921 }
1922 }
1923 else dol_print_error($resqlcontact);
1924 }*/
1925
1926 // Hooks
1927 $parameters = array('origin_type' => $object->origin_type, 'origin_id' => $object->origin_id, 'objFrom' => $srcobject);
1928 $reshook = $hookmanager->executeHooks('createFrom', $parameters, $object, $action); // Note that $action and $object may have been
1929 // modified by hook
1930 if ($reshook < 0) {
1931 setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
1932 $error++;
1933 }
1934 } else {
1935 setEventMessages($object->error, $object->errors, 'errors');
1936 $error++;
1937 }
1938 } else { // If some invoice's lines coming from page
1939 $id = $object->create($user);
1940
1941 for ($i = 1; $i <= $NBLINES; $i++) {
1942 if (GETPOSTINT('idprod'.$i)) {
1943 $product = new Product($db);
1944 $product->fetch(GETPOSTINT('idprod'.$i));
1945 $startday = dol_mktime(12, 0, 0, GETPOST('date_start'.$i.'month'), GETPOST('date_start'.$i.'day'), GETPOST('date_start'.$i.'year'));
1946 $endday = dol_mktime(12, 0, 0, GETPOST('date_end'.$i.'month'), GETPOST('date_end'.$i.'day'), GETPOST('date_end'.$i.'year'));
1947 $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);
1948 }
1949 }
1950
1951 $object->update_price(1, 'auto', 0, $mysoc);
1952 }
1953 }
1954 }
1955
1956 // Situation invoices
1957 if (GETPOST('type') == Facture::TYPE_SITUATION && GETPOST('situations')) {
1958 if (empty($dateinvoice)) {
1959 $error++;
1960 $mesg = $langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("Date"));
1961 setEventMessages($mesg, null, 'errors');
1962 } elseif ($dateinvoice > (dol_get_last_hour(dol_now('tzuserrel')) + getDolGlobalInt('INVOICE_MAX_FUTURE_DELAY'))) {
1963 $error++;
1964 setEventMessages($langs->trans("ErrorDateIsInFuture"), null, 'errors');
1965 $action = 'create';
1966 }
1967
1968 if (!(GETPOSTINT('situations') > 0)) {
1969 $error++;
1970 $mesg = $langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("InvoiceSituation"));
1971 setEventMessages($mesg, null, 'errors');
1972 $action = 'create';
1973 }
1974
1975 if (!$error) {
1976 $result = $object->fetch(GETPOSTINT('situations'));
1977 $object->fk_facture_source = GETPOSTINT('situations');
1979
1980 if (!empty($origin) && !empty($originid)) {
1981 include_once DOL_DOCUMENT_ROOT.'/core/lib/price.lib.php';
1982
1983 $object->origin = $origin; // deprecated
1984 $object->origin_type = $origin;
1985 $object->origin_id = $originid;
1986
1987 // retained warranty
1988 if (getDolGlobalString('INVOICE_USE_RETAINED_WARRANTY')) {
1989 $retained_warranty = GETPOSTINT('retained_warranty');
1990 if (price2num($retained_warranty) > 0) {
1991 $object->retained_warranty = price2num($retained_warranty);
1992 }
1993
1994 if (GETPOSTINT('retained_warranty_fk_cond_reglement') > 0) {
1995 $object->retained_warranty_fk_cond_reglement = GETPOSTINT('retained_warranty_fk_cond_reglement');
1996 }
1997
1998 $retained_warranty_date_limit = GETPOST('retained_warranty_date_limit');
1999 if (!empty($retained_warranty_date_limit) && $db->jdate($retained_warranty_date_limit)) {
2000 $object->retained_warranty_date_limit = $db->jdate($retained_warranty_date_limit);
2001 }
2002 $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);
2003 }
2004
2005 foreach ($object->lines as $i => &$line) {
2006 $line->fk_prev_id = $line->id;
2007 $line->fetch_optionals();
2008 if (getDolGlobalInt('INVOICE_USE_SITUATION') == 2) {
2009 $line->situation_percent = 0; // New situation percent must be 0 (No cumulative)
2010 } else {
2011 $line->situation_percent = $line->get_prev_progress($object->id); // get good progress including credit note
2012 }
2013
2014 // The $line->situation_percent has been modified, so we must recalculate all amounts
2015 $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);
2016 $line->total_ht = $tabprice[0];
2017 $line->total_tva = $tabprice[1];
2018 $line->total_ttc = $tabprice[2];
2019 $line->total_localtax1 = $tabprice[9];
2020 $line->total_localtax2 = $tabprice[10];
2021 $line->multicurrency_total_ht = $tabprice[16];
2022 $line->multicurrency_total_tva = $tabprice[17];
2023 $line->multicurrency_total_ttc = $tabprice[18];
2024
2025 // If fk_remise_except defined we check if the reduction has already been applied
2026 if ($line->fk_remise_except) {
2027 $discount = new DiscountAbsolute($line->db);
2028 $result = $discount->fetch($line->fk_remise_except);
2029 if ($result > 0) {
2030 // Check if discount not already affected to another invoice
2031 if ($discount->fk_facture_line > 0) {
2032 $line->fk_remise_except = 0;
2033 }
2034 }
2035 }
2036 }
2037 }
2038
2039 $object->fetch_thirdparty();
2040 $object->date = $dateinvoice;
2041 $object->date_pointoftax = $date_pointoftax;
2042 $object->note_public = trim(GETPOST('note_public', 'restricthtml'));
2043 $object->note = trim(GETPOST('note', 'restricthtml'));
2044 $object->note_private = trim(GETPOST('note', 'restricthtml'));
2045 $object->ref_client = GETPOST('ref_client', 'alpha');
2046 $object->ref_customer = GETPOST('ref_client', 'alpha');
2047 $object->model_pdf = GETPOST('model', 'alpha');
2048 $object->fk_project = GETPOSTINT('projectid');
2049 $object->cond_reglement_id = GETPOSTINT('cond_reglement_id');
2050 $object->mode_reglement_id = GETPOSTINT('mode_reglement_id');
2051 //$object->remise_absolue =price2num(GETPOST('remise_absolue'), 'MU', 2);
2052 //$object->remise_percent = price2num(GETPOST('remise_percent'), '', 2);
2053 $object->fk_account = GETPOSTINT('fk_account');
2054
2055
2056 // Special properties of replacement invoice
2057
2058 $object->situation_counter += 1;
2059
2060 $id = $object->createFromCurrent($user);
2061 if ($id <= 0) {
2062 $mesg = $object->error;
2063 } else {
2064 $nextSituationInvoice = new Facture($db);
2065 $nextSituationInvoice->fetch($id);
2066
2067 // create extrafields with data from create form
2068 $extrafields->fetch_name_optionals_label($nextSituationInvoice->table_element);
2069 $ret = $extrafields->setOptionalsFromPost(null, $nextSituationInvoice);
2070 if ($ret > 0) {
2071 $nextSituationInvoice->insertExtraFields();
2072 }
2073
2074 // Hooks
2075 $parameters = array('origin_type' => $object->origin_type, 'origin_id' => $object->origin_id);
2076 $reshook = $hookmanager->executeHooks('createFrom', $parameters, $nextSituationInvoice, $action); // Note that $action and $object may have been
2077 // modified by hook
2078 if ($reshook < 0) {
2079 setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
2080 $error++;
2081 }
2082 }
2083 }
2084 }
2085
2086 // End of object creation, we show it
2087 if ($id > 0 && !$error) {
2088 $db->commit();
2089
2090 // Define output language
2091 if (!getDolGlobalString('MAIN_DISABLE_PDF_AUTOUPDATE') && count($object->lines)) {
2092 $outputlangs = $langs;
2093 $newlang = '';
2094 if (getDolGlobalInt('MAIN_MULTILANGS') && empty($newlang) && GETPOST('lang_id', 'aZ09')) {
2095 $newlang = GETPOST('lang_id', 'aZ09');
2096 }
2097 if (getDolGlobalInt('MAIN_MULTILANGS') && empty($newlang)) {
2098 $newlang = $object->thirdparty->default_lang;
2099 }
2100 if (!empty($newlang)) {
2101 $outputlangs = new Translate("", $conf);
2102 $outputlangs->setDefaultLang($newlang);
2103 $outputlangs->load('products');
2104 }
2105 $model = $object->model_pdf;
2106 $ret = $object->fetch($id); // Reload to get new records
2107
2108 $result = $object->generateDocument($model, $outputlangs, $hidedetails, $hidedesc, $hideref);
2109 if ($result < 0) {
2110 setEventMessages($object->error, $object->errors, 'errors');
2111 }
2112 }
2113
2114 header('Location: '.$_SERVER["PHP_SELF"].'?facid='.$id);
2115 exit();
2116 } else {
2117 $db->rollback();
2118 $action = 'create';
2119 $_GET["origin"] = $_POST["origin"]; // Keep GET and POST here ?
2120 $_GET["originid"] = $_POST["originid"]; // Keep GET and POST here ?
2121 setEventMessages($object->error, $object->errors, 'errors');
2122 }
2123 } elseif ($action == 'addline' && GETPOST('submitforalllines', 'aZ09') && (GETPOST('alldate_start', 'alpha') || GETPOST('alldate_end', 'alpha')) && $usercancreate) {
2124 // Define date start and date end for all line
2125 $alldate_start = dol_mktime(GETPOST('alldate_starthour'), GETPOST('alldate_startmin'), 0, GETPOST('alldate_startmonth'), GETPOST('alldate_startday'), GETPOST('alldate_startyear'));
2126 $alldate_end = dol_mktime(GETPOST('alldate_endhour'), GETPOST('alldate_endmin'), 0, GETPOST('alldate_endmonth'), GETPOST('alldate_endday'), GETPOST('alldate_endyear'));
2127 foreach ($object->lines as $line) {
2128 if ($line->product_type == 1) { // only service line
2129 $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);
2130 }
2131 }
2132 } elseif ($action == 'addline' && GETPOST('submitforalllines', 'alpha') && GETPOST('vatforalllines', 'alpha') !== '' && $usercancreate) {
2133 // Define vat_rate
2134 $vat_rate = (GETPOST('vatforalllines') ? GETPOST('vatforalllines') : 0);
2135 $vat_rate = str_replace('*', '', $vat_rate);
2136 $localtax1_rate = get_localtax($vat_rate, 1, $object->thirdparty, $mysoc);
2137 $localtax2_rate = get_localtax($vat_rate, 2, $object->thirdparty, $mysoc);
2138 foreach ($object->lines as $line) {
2139 $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);
2140 }
2141 } elseif ($action == 'addline' && GETPOST('submitforalllines', 'alpha') && GETPOST('remiseforalllines', 'alpha') !== '' && $usercancreate) {
2142 // Define vat_rate
2143 $remise_percent = (GETPOST('remiseforalllines') ? GETPOST('remiseforalllines') : 0);
2144 $remise_percent = str_replace('*', '', $remise_percent);
2145 foreach ($object->lines as $line) {
2146 $tvatx= $line->tva_tx;
2147 if (!empty($line->vat_src_code)) {
2148 $tvatx .= ' ('.$line->vat_src_code.')';
2149 }
2150 $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);
2151 }
2152 } elseif ($action == 'addline' && !GETPOST('submitforalllines', 'alpha') && !GETPOST('submitforallmargins', 'alpha') && $usercancreate) { // Add a new line
2153 $langs->load('errors');
2154 $error = 0;
2155
2156 // Set if we used free entry or predefined product
2157 $predef = '';
2158 $product_desc = (GETPOSTISSET('dp_desc') ? GETPOST('dp_desc', 'restricthtml') : '');
2159
2160 $price_ht = '';
2161 $price_ht_devise = '';
2162 $price_ttc = '';
2163 $price_ttc_devise = '';
2164 $price_min = '';
2165 $price_min_ttc = '';
2166
2167 if (GETPOST('price_ht') !== '') {
2168 $price_ht = price2num(GETPOST('price_ht'), 'MU', 2);
2169 }
2170 if (GETPOST('multicurrency_price_ht') !== '') {
2171 $price_ht_devise = price2num(GETPOST('multicurrency_price_ht'), 'CU', 2);
2172 }
2173 if (GETPOST('price_ttc') !== '') {
2174 $price_ttc = price2num(GETPOST('price_ttc'), 'MU', 2);
2175 }
2176 if (GETPOST('multicurrency_price_ttc') !== '') {
2177 $price_ttc_devise = price2num(GETPOST('multicurrency_price_ttc'), 'CU', 2);
2178 }
2179
2180 $prod_entry_mode = GETPOST('prod_entry_mode', 'aZ09');
2181 if ($prod_entry_mode == 'free') {
2182 $idprod = 0;
2183 } else {
2184 $idprod = GETPOSTINT('idprod');
2185
2186 if (getDolGlobalString('MAIN_DISABLE_FREE_LINES') && $idprod <= 0) {
2187 setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("ProductOrService")), null, 'errors');
2188 $error++;
2189 }
2190 }
2191
2192 $tva_tx = GETPOST('tva_tx', 'alpha');
2193
2194 $qty = price2num(GETPOST('qty'.$predef, 'alpha'), 'MS', 2);
2195 $remise_percent = (GETPOSTISSET('remise_percent'.$predef) ? price2num(GETPOST('remise_percent'.$predef, 'alpha'), '', 2) : 0);
2196 if (empty($remise_percent)) {
2197 $remise_percent = 0;
2198 }
2199
2200 // Extrafields
2201 $extralabelsline = $extrafields->fetch_name_optionals_label($object->table_element_line);
2202 $array_options = $extrafields->getOptionalsFromPost($object->table_element_line, $predef);
2203 // Unset extrafield
2204 if (is_array($extralabelsline)) {
2205 // Get extra fields
2206 foreach ($extralabelsline as $key => $value) {
2207 unset($_POST["options_".$key.$predef]);
2208 }
2209 }
2210
2211 if ((empty($idprod) || $idprod < 0) && ($price_ht < 0) && ($qty < 0)) {
2212 setEventMessages($langs->trans('ErrorBothFieldCantBeNegative', $langs->transnoentitiesnoconv('UnitPriceHT'), $langs->transnoentitiesnoconv('Qty')), null, 'errors');
2213 $error++;
2214 }
2215 if (!$prod_entry_mode) {
2216 if (GETPOST('type') < 0 && !GETPOST('search_idprod')) {
2217 setEventMessages($langs->trans('ErrorChooseBetweenFreeEntryOrPredefinedProduct'), null, 'errors');
2218 $error++;
2219 }
2220 }
2221 if ($prod_entry_mode == 'free' && (empty($idprod) || $idprod < 0) && GETPOST('type') < 0) {
2222 setEventMessages($langs->trans('ErrorFieldRequired', $langs->transnoentitiesnoconv('Type')), null, 'errors');
2223 $error++;
2224 }
2225 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 ''
2226 if (($price_ht < 0 || $price_ttc < 0) && !getDolGlobalString('FACTURE_ENABLE_NEGATIVE_LINES')) {
2227 $langs->load("errors");
2228 if ($object->type == $object::TYPE_DEPOSIT) {
2229 // Using negative lines on deposit lead to headach and blocking problems when you want to consume them.
2230 setEventMessages($langs->trans("ErrorLinesCantBeNegativeOnDeposits"), null, 'errors');
2231 } else {
2232 setEventMessages($langs->trans("ErrorFieldCantBeNegativeOnInvoice", $langs->transnoentitiesnoconv("UnitPriceHT"), $langs->transnoentitiesnoconv("CustomerAbsoluteDiscountShort")), null, 'errors');
2233 }
2234 $error++;
2235 } else {
2236 setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("UnitPriceHT")), null, 'errors');
2237 $error++;
2238 }
2239 }
2240 if ($qty == '') {
2241 setEventMessages($langs->trans('ErrorFieldRequired', $langs->transnoentitiesnoconv('Qty')), null, 'errors');
2242 $error++;
2243 }
2244 if ($prod_entry_mode == 'free' && empty($idprod) && empty($product_desc)) {
2245 setEventMessages($langs->trans('ErrorFieldRequired', $langs->transnoentitiesnoconv('Description')), null, 'errors');
2246 $error++;
2247 }
2248 if ($qty < 0) {
2249 $langs->load("errors");
2250 setEventMessages($langs->trans('ErrorQtyForCustomerInvoiceCantBeNegative'), null, 'errors');
2251 $error++;
2252 }
2253
2254 if (!$error && isModEnabled('variants') && $prod_entry_mode != 'free') {
2255 if ($combinations = GETPOST('combinations', 'array')) {
2256 //Check if there is a product with the given combination
2257 $prodcomb = new ProductCombination($db);
2258
2259 if ($res = $prodcomb->fetchByProductCombination2ValuePairs($idprod, $combinations)) {
2260 $idprod = $res->fk_product_child;
2261 } else {
2262 setEventMessages($langs->trans('ErrorProductCombinationNotFound'), null, 'errors');
2263 $error++;
2264 }
2265 }
2266 }
2267
2268 if (!$error && ($qty >= 0) && (!empty($product_desc) || (!empty($idprod) && $idprod > 0))) {
2269 $ret = $object->fetch($id);
2270 if ($ret < 0) {
2271 dol_print_error($db, $object->error);
2272 exit();
2273 }
2274 $ret = $object->fetch_thirdparty();
2275
2276 // Clean parameters
2277 $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'));
2278 $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'));
2279 $price_base_type = (GETPOST('price_base_type', 'alpha') ? GETPOST('price_base_type', 'alpha') : 'HT');
2280 $tva_npr = "";
2281
2282 // Define special_code for special lines
2283 $special_code = 0;
2284 // if (!GETPOST(qty)) $special_code=3; // Options should not exists on invoices
2285
2286 // Replaces $pu with that of the product
2287 // Replaces $desc with that of the product
2288 // Replaces $base_price_type with that of the product
2289 // Replaces $fk_unit with that of the product
2290 if (!empty($idprod) && $idprod > 0) {
2291 $prod = new Product($db);
2292 $prod->fetch($idprod);
2293
2294 $label = ((GETPOST('product_label') && GETPOST('product_label') != $prod->label) ? GETPOST('product_label') : '');
2295
2296 // Search the correct price into loaded array product_price_by_qty using id of array retrieved into POST['pqp'].
2297 $pqp = (GETPOSTINT('pbq') ? GETPOSTINT('pbq') : 0);
2298
2299 $datapriceofproduct = $prod->getSellPrice($mysoc, $object->thirdparty, $pqp);
2300
2301 $pu_ht = $datapriceofproduct['pu_ht'];
2302 $pu_ttc = $datapriceofproduct['pu_ttc'];
2303 $price_min = $datapriceofproduct['price_min'];
2304 $price_min_ttc = (isset($datapriceofproduct['price_min_ttc'])) ? $datapriceofproduct['price_min_ttc'] : null;
2305 $price_base_type = empty($datapriceofproduct['price_base_type']) ? 'HT' : $datapriceofproduct['price_base_type'];
2306
2307 //$tva_tx = $datapriceofproduct['tva_tx'];
2308 //$tva_npr = $datapriceofproduct['tva_npr'];
2309 $tmpvat = (float) price2num(preg_replace('/\s*\‍(.*\‍)/', '', $tva_tx));
2310 $tmpprodvat = price2num(preg_replace('/\s*\‍(.*\‍)/', '', (string) $prod->tva_tx));
2311
2312 // Set unit price to use
2313 // TODO We should not have this
2314 if (!empty($price_ht) || $price_ht === '0') {
2315 $pu_ht = price2num($price_ht, 'MU');
2316 $pu_ttc = price2num((float) $pu_ht * (1 + ($tmpvat / 100)), 'MU');
2317 } elseif (!empty($price_ht_devise) || $price_ht_devise === '0') {
2318 $pu_ht_devise = price2num($price_ht_devise, 'MU');
2319 $pu_ht = '';
2320 $pu_ttc = '';
2321 } elseif (!empty($price_ttc) || $price_ttc === '0') {
2322 $pu_ttc = price2num($price_ttc, 'MU');
2323 $pu_ht = price2num((float) $pu_ttc / (1 + ($tmpvat / 100)), 'MU');
2324 } elseif ($tmpvat != $tmpprodvat) {
2325 // Is this still used ?
2326 if ($price_base_type != 'HT') {
2327 $pu_ht = price2num($pu_ttc / (1 + ($tmpvat / 100)), 'MU');
2328 } else {
2329 $pu_ttc = price2num($pu_ht * (1 + ($tmpvat / 100)), 'MU');
2330 }
2331 }
2332
2333 $desc = '';
2334
2335 // Define output language
2336 if (getDolGlobalInt('MAIN_MULTILANGS') && getDolGlobalString('PRODUIT_TEXTS_IN_THIRDPARTY_LANGUAGE')) {
2337 $outputlangs = $langs;
2338 $newlang = '';
2339 if (empty($newlang) && GETPOST('lang_id', 'aZ09')) {
2340 $newlang = GETPOST('lang_id', 'aZ09');
2341 }
2342 if (empty($newlang)) {
2343 $newlang = $object->thirdparty->default_lang;
2344 }
2345 if (!empty($newlang)) {
2346 $outputlangs = new Translate("", $conf);
2347 $outputlangs->setDefaultLang($newlang);
2348 $outputlangs->load('products');
2349 }
2350
2351 $desc = (!empty($prod->multilangs [$outputlangs->defaultlang] ["description"])) ? $prod->multilangs [$outputlangs->defaultlang] ["description"] : $prod->description;
2352 } else {
2353 $desc = $prod->description;
2354 }
2355
2356 //If text set in desc is the same as product descpription (as now it's preloaded) we add it only one time
2357 if ($product_desc == $desc && getDolGlobalString('PRODUIT_AUTOFILL_DESC')) {
2358 $product_desc = '';
2359 }
2360
2361 if (!empty($product_desc) && getDolGlobalString('MAIN_NO_CONCAT_DESCRIPTION')) {
2362 $desc = $product_desc;
2363 } else {
2364 $desc = dol_concatdesc($desc, $product_desc, '', getDolGlobalString('MAIN_CHANGE_ORDER_CONCAT_DESCRIPTION'));
2365 }
2366
2367 // Add custom code and origin country into description
2368 if (!getDolGlobalString('MAIN_PRODUCT_DISABLE_CUSTOMCOUNTRYCODE') && (!empty($prod->customcode) || !empty($prod->country_code))) {
2369 $tmptxt = '(';
2370 // Define output language
2371 if (getDolGlobalInt('MAIN_MULTILANGS') && getDolGlobalString('PRODUIT_TEXTS_IN_THIRDPARTY_LANGUAGE')) {
2372 $outputlangs = $langs;
2373 $newlang = '';
2374 if (empty($newlang) && GETPOST('lang_id', 'alpha')) {
2375 $newlang = GETPOST('lang_id', 'alpha');
2376 }
2377 if (empty($newlang)) {
2378 $newlang = $object->thirdparty->default_lang;
2379 }
2380 if (!empty($newlang)) {
2381 $outputlangs = new Translate("", $conf);
2382 $outputlangs->setDefaultLang($newlang);
2383 $outputlangs->load('products');
2384 }
2385 if (!empty($prod->customcode)) {
2386 $tmptxt .= $outputlangs->transnoentitiesnoconv("CustomCode").': '.$prod->customcode;
2387 }
2388 if (!empty($prod->customcode) && !empty($prod->country_code)) {
2389 $tmptxt .= ' - ';
2390 }
2391 if (!empty($prod->country_code)) {
2392 $tmptxt .= $outputlangs->transnoentitiesnoconv("CountryOrigin").': '.getCountry($prod->country_code, 0, $db, $outputlangs, 0);
2393 }
2394 } else {
2395 if (!empty($prod->customcode)) {
2396 $tmptxt .= $langs->transnoentitiesnoconv("CustomCode").': '.$prod->customcode;
2397 }
2398 if (!empty($prod->customcode) && !empty($prod->country_code)) {
2399 $tmptxt .= ' - ';
2400 }
2401 if (!empty($prod->country_code)) {
2402 $tmptxt .= $langs->transnoentitiesnoconv("CountryOrigin").': '.getCountry($prod->country_code, 0, $db, $langs, 0);
2403 }
2404 }
2405 $tmptxt .= ')';
2406 $desc = dol_concatdesc($desc, $tmptxt);
2407 }
2408
2409 $type = $prod->type;
2410 $fk_unit = $prod->fk_unit;
2411 } else {
2412 if (!empty($price_ht)) {
2413 $pu_ht = price2num($price_ht, 'MU');
2414 } else {
2415 $pu_ht = '';
2416 }
2417 if (!empty($price_ttc)) {
2418 $pu_ttc = price2num($price_ttc, 'MU');
2419 } else {
2420 $pu_ttc = '';
2421 }
2422 $tva_npr = (preg_match('/\*/', $tva_tx) ? 1 : 0);
2423 $tva_tx = str_replace('*', '', $tva_tx);
2424 if (empty($tva_tx)) {
2425 $tva_npr = 0;
2426 }
2427 $label = (GETPOST('product_label') ? GETPOST('product_label') : '');
2428 $desc = $product_desc;
2429 $type = GETPOST('type');
2430 $fk_unit = GETPOST('units', 'alpha');
2431
2432 if ($pu_ttc && !$pu_ht) {
2433 $price_base_type = 'TTC';
2434 }
2435 }
2436
2437 // Define info_bits
2438 $info_bits = 0;
2439 if ($tva_npr) {
2440 $info_bits |= 0x01;
2441 }
2442
2443 // Local Taxes
2444 $localtax1_tx = get_localtax($tva_tx, 1, $object->thirdparty, $mysoc, $tva_npr);
2445 $localtax2_tx = get_localtax($tva_tx, 2, $object->thirdparty, $mysoc, $tva_npr);
2446
2447 $pu_ht_devise = price2num($price_ht_devise, '', 2);
2448 $pu_ttc_devise = price2num($price_ttc_devise, '', 2);
2449
2450 // Prepare a price equivalent for minimum price check
2451 $pu_equivalent = $pu_ht;
2452 $pu_equivalent_ttc = $pu_ttc;
2453
2454 $currency_tx = $object->multicurrency_tx;
2455
2456 // Check if we have a foreign currency
2457 // If so, we update the pu_equiv as the equivalent price in base currency
2458 if ($pu_ht == '' && $pu_ht_devise != '' && $currency_tx != '') {
2459 $pu_equivalent = (float) $pu_ht_devise * $currency_tx;
2460 }
2461 if ($pu_ttc == '' && $pu_ttc_devise != '' && $currency_tx != '') {
2462 $pu_equivalent_ttc = (float) $pu_ttc_devise * $currency_tx;
2463 }
2464
2465 // TODO $pu_equivalent or $pu_equivalent_ttc must be calculated from the one not null taking into account all taxes
2466 /*
2467 if ($pu_equivalent) {
2468 $tmp = calcul_price_total(1, $pu_equivalent, 0, $tva_tx, -1, -1, 0, 'HT', $info_bits, $type);
2469 $pu_equivalent_ttc = ...
2470 } else {
2471 $tmp = calcul_price_total(1, $pu_equivalent_ttc, 0, $tva_tx, -1, -1, 0, 'TTC', $info_bits, $type);
2472 $pu_equivalent_ht = ...
2473 }
2474 */
2475
2476 // Margin
2477 $fournprice = price2num(GETPOST('fournprice'.$predef) ? GETPOST('fournprice'.$predef) : '');
2478 $buyingprice = price2num(GETPOST('buying_price'.$predef) != '' ? GETPOST('buying_price'.$predef) : ''); // If buying_price is '0', we must keep this value
2479
2480
2481 $price2num_pu_ht = price2num($pu_ht);
2482 $price2num_remise_percent = price2num($remise_percent);
2483 $price2num_price_min = price2num($price_min);
2484 $price2num_price_min_ttc = price2num($price_min_ttc);
2485 if (empty($price2num_pu_ht)) {
2486 $price2num_pu_ht = 0;
2487 }
2488 if (empty($price2num_remise_percent)) {
2489 $price2num_remise_percent = 0;
2490 }
2491 if (empty($price2num_price_min)) {
2492 $price2num_price_min = 0;
2493 }
2494 if (empty($price2num_price_min_ttc)) {
2495 $price2num_price_min_ttc = 0;
2496 }
2497
2498 // Check price is not lower than minimum (check is done only for standard or replacement invoices)
2499 if ($usermustrespectpricemin && ($object->type == Facture::TYPE_STANDARD || $object->type == Facture::TYPE_REPLACEMENT)) {
2500 if ($pu_equivalent && $price_min && (((float) price2num($pu_equivalent) * (1 - $remise_percent / 100)) < (float) price2num($price_min)) && $price_base_type == 'HT') {
2501 $mesg = $langs->trans("CantBeLessThanMinPrice", price(price2num($price_min, 'MU'), 0, $langs, 0, 0, -1, $conf->currency));
2502 setEventMessages($mesg, null, 'errors');
2503 $error++;
2504 } 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') {
2505 $mesg = $langs->trans("CantBeLessThanMinPriceInclTax", price(price2num($price_min_ttc, 'MU'), 0, $langs, 0, 0, -1, $conf->currency));
2506 setEventMessages($mesg, null, 'errors');
2507 $error++;
2508 }
2509 }
2510
2511 if (!$error) {
2512 '@phan-var-force array<string,mixed> $lines';
2513 // Add batchinfo if the detail_batch array is defined
2514 if (isModEnabled('productbatch') && !empty($lines[$i]->detail_batch) && is_array($lines[$i]->detail_batch) && getDolGlobalString('INVOICE_INCUDE_DETAILS_OF_LOTS_SERIALS')) {
2515 $langs->load('productbatch');
2516 foreach ($lines[$i]->detail_batch as $batchline) {
2517 $desc .= ' '.$langs->trans('Batch').' '.$batchline->batch.' '.$langs->trans('printQty', $batchline->qty).' ';
2518 }
2519 }
2520
2521 // Insert line
2522 $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);
2523
2524 if ($result > 0) {
2525 // Define output language and generate document
2526 if (!getDolGlobalString('MAIN_DISABLE_PDF_AUTOUPDATE')) {
2527 $outputlangs = $langs;
2528 $newlang = '';
2529 if (getDolGlobalInt('MAIN_MULTILANGS') && empty($newlang) && GETPOST('lang_id', 'aZ09')) {
2530 $newlang = GETPOST('lang_id', 'aZ09');
2531 }
2532 if (getDolGlobalInt('MAIN_MULTILANGS') && empty($newlang)) {
2533 $newlang = $object->thirdparty->default_lang;
2534 }
2535 if (!empty($newlang)) {
2536 $outputlangs = new Translate("", $conf);
2537 $outputlangs->setDefaultLang($newlang);
2538 $outputlangs->load('products');
2539 }
2540 $model = $object->model_pdf;
2541 $ret = $object->fetch($id); // Reload to get new records
2542
2543 $result = $object->generateDocument($model, $outputlangs, $hidedetails, $hidedesc, $hideref);
2544 if ($result < 0) {
2545 setEventMessages($object->error, $object->errors, 'errors');
2546 }
2547 }
2548
2549 unset($_POST['prod_entry_mode']);
2550 unset($_POST['qty']);
2551 unset($_POST['type']);
2552 unset($_POST['remise_percent']);
2553 unset($_POST['price_ht']);
2554 unset($_POST['multicurrency_price_ht']);
2555 unset($_POST['price_ttc']);
2556 unset($_POST['tva_tx']);
2557 unset($_POST['product_ref']);
2558 unset($_POST['product_label']);
2559 unset($_POST['product_desc']);
2560 unset($_POST['fournprice']);
2561 unset($_POST['buying_price']);
2562 unset($_POST['np_marginRate']);
2563 unset($_POST['np_markRate']);
2564 unset($_POST['dp_desc']);
2565 unset($_POST['idprod']);
2566 unset($_POST['units']);
2567 unset($_POST['date_starthour']);
2568 unset($_POST['date_startmin']);
2569 unset($_POST['date_startsec']);
2570 unset($_POST['date_startday']);
2571 unset($_POST['date_startmonth']);
2572 unset($_POST['date_startyear']);
2573 unset($_POST['date_endhour']);
2574 unset($_POST['date_endmin']);
2575 unset($_POST['date_endsec']);
2576 unset($_POST['date_endday']);
2577 unset($_POST['date_endmonth']);
2578 unset($_POST['date_endyear']);
2579 unset($_POST['situations']);
2580 unset($_POST['progress']);
2581 } else {
2582 setEventMessages($object->error, $object->errors, 'errors');
2583 }
2584
2585 $action = '';
2586 }
2587 }
2588 } elseif ($action == 'updateline' && $usercancreate && !GETPOST('cancel', 'alpha')) {
2589 if (!$object->fetch($id) > 0) {
2590 dol_print_error($db);
2591 }
2592 $object->fetch_thirdparty();
2593
2594 // Clean parameters
2595 $date_start = '';
2596 $date_end = '';
2597 $date_start = dol_mktime(GETPOST('date_starthour'), GETPOST('date_startmin'), GETPOST('date_startsec'), GETPOST('date_startmonth'), GETPOST('date_startday'), GETPOST('date_startyear'));
2598 $date_end = dol_mktime(GETPOST('date_endhour'), GETPOST('date_endmin'), GETPOST('date_endsec'), GETPOST('date_endmonth'), GETPOST('date_endday'), GETPOST('date_endyear'));
2599 $description = dol_htmlcleanlastbr(GETPOST('product_desc', 'restricthtml') ? GETPOST('product_desc', 'restricthtml') : GETPOST('desc', 'restricthtml'));
2600 $vat_rate = (GETPOST('tva_tx') ? GETPOST('tva_tx') : 0);
2601 $vat_rate = str_replace('*', '', $vat_rate);
2602
2603 $pu_ht = price2num(GETPOST('price_ht'), '', 2);
2604 $pu_ttc = price2num(GETPOST('price_ttc'), '', 2);
2605
2606 $pu_ht_devise = price2num(GETPOST('multicurrency_subprice'), '', 2);
2607 $pu_ttc_devise = price2num(GETPOST('multicurrency_subprice_ttc'), '', 2);
2608
2609 $qty = price2num(GETPOST('qty', 'alpha'), 'MS');
2610
2611 // Define info_bits
2612 $info_bits = 0;
2613 if (preg_match('/\*/', $vat_rate)) {
2614 $info_bits |= 0x01;
2615 }
2616
2617 // Define vat_rate
2618 $vat_rate = str_replace('*', '', $vat_rate);
2619 $localtax1_rate = get_localtax($vat_rate, 1, $object->thirdparty);
2620 $localtax2_rate = get_localtax($vat_rate, 2, $object->thirdparty);
2621
2622 // Add buying price
2623 $fournprice = price2num(GETPOST('fournprice') ? GETPOST('fournprice') : '');
2624 $buyingprice = price2num(GETPOST('buying_price') != '' ? GETPOST('buying_price') : ''); // If buying_price is '0', we must keep this value
2625
2626 // Prepare a price equivalent for minimum price check
2627 $pu_equivalent = $pu_ht;
2628 $pu_equivalent_ttc = $pu_ttc;
2629
2630 $currency_tx = $object->multicurrency_tx;
2631
2632 // Check if we have a foreign currency
2633 // If so, we update the pu_equiv as the equivalent price in base currency
2634 if ($pu_ht == '' && $pu_ht_devise != '' && $currency_tx != '') {
2635 $pu_equivalent = (float) $pu_ht_devise * (float) $currency_tx;
2636 }
2637 if ($pu_ttc == '' && $pu_ttc_devise != '' && $currency_tx != '') {
2638 $pu_equivalent_ttc = (float) $pu_ttc_devise * (float) $currency_tx;
2639 }
2640
2641 // TODO $pu_equivalent or $pu_equivalent_ttc must be calculated from the one not null taking into account all taxes
2642 /*
2643 if ($pu_equivalent) {
2644 $tmp = calcul_price_total(1, $pu_equivalent, 0, $vat_rate, -1, -1, 0, 'HT', $info_bits, $type);
2645 $pu_equivalent_ttc = ...
2646 } else {
2647 $tmp = calcul_price_total(1, $pu_equivalent_ttc, 0, $vat_rate, -1, -1, 0, 'TTC', $info_bits, $type);
2648 $pu_equivalent_ht = ...
2649 }
2650 */
2651
2652 // Extrafields
2653 $extralabelsline = $extrafields->fetch_name_optionals_label($object->table_element_line);
2654 $array_options = $extrafields->getOptionalsFromPost($object->table_element_line);
2655 // Unset extrafield
2656 if (is_array($extralabelsline)) {
2657 // Get extra fields
2658 foreach ($extralabelsline as $key => $value) {
2659 unset($_POST["options_".$key]);
2660 }
2661 }
2662
2663 // Define special_code for special lines
2664 $special_code = GETPOSTINT('special_code');
2665 if ($special_code == 3) {
2666 $special_code = 0; // Options should not exists on invoices
2667 }
2668
2669 $line = new FactureLigne($db);
2670 $line->fetch(GETPOSTINT('lineid'));
2671 $percent = $line->get_prev_progress($object->id);
2672 $progress = price2num(GETPOST('progress', 'alpha'));
2673
2674 if ($object->type == Facture::TYPE_CREDIT_NOTE && $object->situation_cycle_ref > 0) {
2675 // in case of situation credit note
2676 if ($progress >= 0) {
2677 $mesg = $langs->trans("CantBeNullOrPositive");
2678 setEventMessages($mesg, null, 'warnings');
2679 $error++;
2680 $result = -1;
2681 } elseif ($progress < $line->situation_percent) { // TODO : use a modified $line->get_prev_progress($object->id) result
2682 $mesg = $langs->trans("CantBeLessThanMinPercent");
2683 setEventMessages($mesg, null, 'warnings');
2684 $error++;
2685 $result = -1;
2686 } elseif ($progress < $percent) {
2687 $mesg = '<div class="warning">'.$langs->trans("CantBeLessThanMinPercent").'</div>';
2688 setEventMessages($mesg, null, 'warnings');
2689 $error++;
2690 $result = -1;
2691 }
2692 }
2693
2694 $remise_percent = price2num(GETPOST('remise_percent'), '', 2);
2695
2696 // Check minimum price
2697 $productid = GETPOSTINT('productid');
2698 if (!empty($productid)) {
2699 $product = new Product($db);
2700 $product->fetch($productid);
2701
2702 $type = $product->type;
2703
2704 $price_min = $product->price_min;
2705 if ((getDolGlobalString('PRODUIT_MULTIPRICES') || getDolGlobalString('PRODUIT_CUSTOMER_PRICES_BY_QTY_MULTIPRICES')) && !empty($object->thirdparty->price_level)) {
2706 $price_min = $product->multiprices_min[$object->thirdparty->price_level];
2707 }
2708 $price_min_ttc = $product->price_min_ttc;
2709 if ((getDolGlobalString('PRODUIT_MULTIPRICES') || getDolGlobalString('PRODUIT_CUSTOMER_PRICES_BY_QTY_MULTIPRICES')) && !empty($object->thirdparty->price_level)) {
2710 $price_min_ttc = $product->multiprices_min_ttc[$object->thirdparty->price_level];
2711 }
2712
2713 $label = ((GETPOST('update_label') && GETPOST('product_label')) ? GETPOST('product_label') : '');
2714
2715 // Check price is not lower than minimum (check is done only for standard or replacement invoices)
2716 if ($usermustrespectpricemin && ($object->type == Facture::TYPE_STANDARD || $object->type == Facture::TYPE_REPLACEMENT)) {
2717 if ($pu_equivalent && $price_min && (((float) price2num($pu_equivalent) * (1 - (float) $remise_percent / 100)) < (float) price2num($price_min)) && $price_base_type == 'HT') {
2718 $mesg = $langs->trans("CantBeLessThanMinPrice", price(price2num($price_min, 'MU'), 0, $langs, 0, 0, -1, $conf->currency));
2719 setEventMessages($mesg, null, 'errors');
2720 $error++;
2721 $action = 'editline';
2722 } 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') {
2723 $mesg = $langs->trans("CantBeLessThanMinPriceInclTax", price(price2num($price_min_ttc, 'MU'), 0, $langs, 0, 0, -1, $conf->currency));
2724 setEventMessages($mesg, null, 'errors');
2725 $error++;
2726 $action = 'editline';
2727 }
2728 }
2729 } else {
2730 $type = GETPOST('type');
2731 $label = (GETPOST('product_label') ? GETPOST('product_label') : '');
2732
2733 // Check parameters
2734 if (GETPOST('type') < 0) {
2735 setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("Type")), null, 'errors');
2736 $error++;
2737 }
2738 }
2739 if ($qty < 0) {
2740 $langs->load("errors");
2741 setEventMessages($langs->trans('ErrorQtyForCustomerInvoiceCantBeNegative'), null, 'errors');
2742 $error++;
2743 }
2744 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 ''
2745 if (($pu_ht < 0 || $pu_ttc < 0) && !getDolGlobalString('FACTURE_ENABLE_NEGATIVE_LINES')) {
2746 $langs->load("errors");
2747 if ($object->type == $object::TYPE_DEPOSIT) {
2748 // Using negative lines on deposit lead to headach and blocking problems when you want to consume them.
2749 setEventMessages($langs->trans("ErrorLinesCantBeNegativeOnDeposits"), null, 'errors');
2750 } else {
2751 setEventMessages($langs->trans("ErrorFieldCantBeNegativeOnInvoice", $langs->transnoentitiesnoconv("UnitPriceHT"), $langs->transnoentitiesnoconv("CustomerAbsoluteDiscountShort")), null, 'errors');
2752 }
2753 $error++;
2754 } else {
2755 setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("UnitPriceHT")), null, 'errors');
2756 $error++;
2757 }
2758 }
2759
2760 // Invoice situation
2761 if (getDolGlobalInt('INVOICE_USE_SITUATION') == 2) {
2762 $previousprogress = $line->get_allprev_progress($line->fk_facture);
2763 $fullprogress = price2num(GETPOST('progress', 'alpha'), 2);
2764
2765 if ($fullprogress < $previousprogress) {
2766 $error++;
2767 setEventMessages($langs->trans('CantBeLessThanMinPercent'), null, 'errors');
2768 }
2769
2770 // Max 100%
2771 if ($fullprogress > 100) {
2772 $fullprogress = 100;
2773 }
2774 $addprogress = $fullprogress - $previousprogress;
2775 } else {
2776 $addprogress = price2num(GETPOST('progress', 'alpha'));
2777 }
2778
2779 // Update line
2780 if (!$error) {
2781 if (empty($usercancreatemargin)) {
2782 foreach ($object->lines as &$line) {
2783 if ($line->id == GETPOSTINT('lineid')) {
2784 $fournprice = $line->fk_fournprice;
2785 $buyingprice = $line->pa_ht;
2786 break;
2787 }
2788 }
2789 }
2790
2791 $price_base_type = 'HT';
2792 $pu = $pu_ht;
2793 if (empty($pu) && !empty($pu_ttc)) {
2794 $pu = $pu_ttc;
2795 $price_base_type = 'TTC';
2796 }
2797
2798 $result = $object->updateline(
2799 GETPOSTINT('lineid'),
2800 $description,
2801 $pu,
2802 $qty,
2803 $remise_percent,
2804 $date_start,
2805 $date_end,
2806 $vat_rate,
2807 $localtax1_rate,
2808 $localtax2_rate,
2809 $price_base_type,
2810 $info_bits,
2811 $type,
2812 GETPOSTINT('fk_parent_line'),
2813 0,
2814 $fournprice,
2815 $buyingprice,
2816 $label,
2817 $special_code,
2818 $array_options,
2819 $addprogress,
2820 GETPOST('units', 'alpha'),
2821 $pu_ht_devise
2822 );
2823
2824 if ($result >= 0) {
2825 if (!getDolGlobalString('MAIN_DISABLE_PDF_AUTOUPDATE')) {
2826 // Define output language
2827 $outputlangs = $langs;
2828 $newlang = '';
2829 if (getDolGlobalInt('MAIN_MULTILANGS') && empty($newlang) && GETPOST('lang_id', 'aZ09')) {
2830 $newlang = GETPOST('lang_id', 'aZ09');
2831 }
2832 if (getDolGlobalInt('MAIN_MULTILANGS') && empty($newlang)) {
2833 $newlang = $object->thirdparty->default_lang;
2834 }
2835 if (!empty($newlang)) {
2836 $outputlangs = new Translate("", $conf);
2837 $outputlangs->setDefaultLang($newlang);
2838 $outputlangs->load('products');
2839 }
2840
2841 $ret = $object->fetch($id); // Reload to get new records
2842 $object->generateDocument($object->model_pdf, $outputlangs, $hidedetails, $hidedesc, $hideref);
2843 }
2844
2845 unset($_POST['qty']);
2846 unset($_POST['type']);
2847 unset($_POST['productid']);
2848 unset($_POST['remise_percent']);
2849 unset($_POST['price_ht']);
2850 unset($_POST['multicurrency_price_ht']);
2851 unset($_POST['price_ttc']);
2852 unset($_POST['tva_tx']);
2853 unset($_POST['product_ref']);
2854 unset($_POST['product_label']);
2855 unset($_POST['product_desc']);
2856 unset($_POST['fournprice']);
2857 unset($_POST['buying_price']);
2858 unset($_POST['np_marginRate']);
2859 unset($_POST['np_markRate']);
2860 unset($_POST['dp_desc']);
2861 unset($_POST['idprod']);
2862 unset($_POST['units']);
2863 unset($_POST['date_starthour']);
2864 unset($_POST['date_startmin']);
2865 unset($_POST['date_startsec']);
2866 unset($_POST['date_startday']);
2867 unset($_POST['date_startmonth']);
2868 unset($_POST['date_startyear']);
2869 unset($_POST['date_endhour']);
2870 unset($_POST['date_endmin']);
2871 unset($_POST['date_endsec']);
2872 unset($_POST['date_endday']);
2873 unset($_POST['date_endmonth']);
2874 unset($_POST['date_endyear']);
2875 unset($_POST['situations']);
2876 unset($_POST['progress']);
2877 } else {
2878 setEventMessages($object->error, $object->errors, 'errors');
2879 }
2880 }
2881 } elseif ($action == 'updatealllines' && $usercancreate && GETPOST('all_percent') == $langs->trans('Modifier')) { // Update all lines of situation invoice
2882 if (!$object->fetch($id) > 0) {
2883 dol_print_error($db);
2884 }
2885 if (GETPOST('all_progress') != "") {
2886 $all_progress = GETPOSTINT('all_progress');
2887 foreach ($object->lines as $line) {
2888 if (getDolGlobalInt('INVOICE_USE_SITUATION') == 2) {
2889 $percent = $line->get_allprev_progress($object->id);
2890 } else {
2891 $percent = $line->get_prev_progress($object->id);
2892 }
2893 if ((float) $all_progress < (float) $percent) {
2894 $mesg = $langs->trans("Line").' '.$line->rang.' : '.$langs->trans("CantBeLessThanMinPercent");
2895 setEventMessages($mesg, null, 'warnings');
2896 $result = -1;
2897 } else {
2898 $object->update_percent($line, GETPOST('all_progress'), false);
2899 }
2900 }
2901 $object->update_price(1);
2902 }
2903 } elseif ($action == 'updateline' && $usercancreate && !$cancel) {
2904 header('Location: '.$_SERVER["PHP_SELF"].'?facid='.$id); // To show again edited page
2905 exit();
2906 } elseif ($action == 'confirm_situationout' && $confirm == 'yes' && $usercancreate) {
2907 // Outing situation invoice from cycle
2908 $object->fetch($id, '', '', 0, true);
2909
2910 if (in_array($object->status, array(Facture::STATUS_CLOSED, Facture::STATUS_VALIDATED))
2912 && $usercancreate
2913 && !$objectidnext
2914 && $object->is_last_in_cycle()
2915 && $usercanunvalidate
2916 ) {
2917 $outingError = 0;
2918 $newCycle = $object->newCycle(); // we need to keep the "situation behavior" so we place it on a new situation cycle
2919 if ($newCycle > 1) {
2920 // Search credit notes
2921 $lastCycle = $object->situation_cycle_ref;
2922 $lastSituationCounter = $object->situation_counter;
2923 $linkedCreditNotesList = array();
2924
2925 if (count($object->tab_next_situation_invoice) > 0) {
2926 foreach ($object->tab_next_situation_invoice as $next_invoice) {
2927 if ($next_invoice->type == Facture::TYPE_CREDIT_NOTE
2928 && $next_invoice->situation_counter == $object->situation_counter
2929 && $next_invoice->fk_facture_source == $object->id
2930 ) {
2931 $linkedCreditNotesList[] = $next_invoice->id;
2932 }
2933 }
2934 }
2935
2936 $object->situation_cycle_ref = $newCycle;
2937 $object->situation_counter = 1;
2938 $object->situation_final = 0;
2939 if ($object->update($user) > 0) {
2940 $errors = 0;
2941 if (count($linkedCreditNotesList) > 0) {
2942 // now, credit note must follow
2943 $sql = 'UPDATE '.MAIN_DB_PREFIX.'facture';
2944 $sql .= ' SET situation_cycle_ref = '.((int) $newCycle);
2945 $sql .= ' , situation_final=0';
2946 $sql .= ' , situation_counter='.((int) $object->situation_counter);
2947 $sql .= ' WHERE rowid IN ('.$db->sanitize(implode(',', $linkedCreditNotesList)).')';
2948
2949 $resql = $db->query($sql);
2950 if (!$resql) {
2951 $errors++;
2952 }
2953
2954 // Change each progression percent on each lines
2955 foreach ($object->lines as $line) {
2956 // no traitement for special product
2957 if ($line->product_type == 9) {
2958 continue;
2959 }
2960
2961
2962 if (!empty($object->tab_previous_situation_invoice)) {
2963 // search the last invoice in cycle
2964 $lineIndex = count($object->tab_previous_situation_invoice) - 1;
2965 $searchPreviousInvoice = true;
2966 while ($searchPreviousInvoice) {
2967 if ($object->tab_previous_situation_invoice[$lineIndex]->type == Facture::TYPE_SITUATION || $lineIndex < 1) {
2968 $searchPreviousInvoice = false; // find, exit;
2969 break;
2970 } else {
2971 $lineIndex--; // go to previous invoice in cycle
2972 }
2973 }
2974
2975
2976 $maxPrevSituationPercent = 0;
2977 foreach ($object->tab_previous_situation_invoice[$lineIndex]->lines as $prevLine) {
2978 if ($prevLine->id == $line->fk_prev_id) {
2979 $maxPrevSituationPercent = max($maxPrevSituationPercent, $prevLine->situation_percent);
2980 }
2981 }
2982
2983
2984 $line->situation_percent -= $maxPrevSituationPercent;
2985
2986 if ($line->update() < 0) {
2987 $errors++;
2988 }
2989 }
2990 }
2991 }
2992
2993 if (!$errors) {
2994 setEventMessages($langs->trans('Updated'), null, 'mesgs');
2995 header("Location: ".$_SERVER['PHP_SELF']."?id=".$id);
2996 } else {
2997 setEventMessages($langs->trans('ErrorOutingSituationInvoiceCreditNote'), array(), 'errors');
2998 }
2999 } else {
3000 setEventMessages($langs->trans('ErrorOutingSituationInvoiceOnUpdate'), array(), 'errors');
3001 }
3002 } else {
3003 setEventMessages($langs->trans('ErrorFindNextSituationInvoice'), array(), 'errors');
3004 }
3005 }
3006 } elseif ($action == 'import_lines_from_object' && $usercancreate && $object->status == Facture::STATUS_DRAFT
3008 // add lines from objectlinked
3009 $fromElement = GETPOST('fromelement');
3010 $fromElementid = GETPOST('fromelementid');
3011 $importLines = GETPOST('line_checkbox');
3012
3013 if (!empty($importLines) && is_array($importLines) && !empty($fromElement) && ctype_alpha($fromElement) && !empty($fromElementid)) {
3014 if ($fromElement == 'commande') {
3015 dol_include_once('/'.$fromElement.'/class/'.$fromElement.'.class.php');
3016 $lineClassName = 'OrderLine';
3017 } elseif ($fromElement == 'propal') {
3018 dol_include_once('/comm/'.$fromElement.'/class/'.$fromElement.'.class.php');
3019 $lineClassName = 'PropaleLigne';
3020 }
3021 $nextRang = count($object->lines) + 1;
3022 $importCount = 0;
3023 $error = 0;
3024 foreach ($importLines as $lineId) {
3025 $lineId = intval($lineId);
3026 $originLine = new $lineClassName($db);
3027 if (intval($fromElementid) > 0 && $originLine->fetch($lineId) > 0) {
3028 $originLine->fetch_optionals();
3029 $desc = $originLine->desc;
3030 $pu_ht = $originLine->subprice;
3031 $qty = $originLine->qty;
3032 $txtva = $originLine->tva_tx;
3033 $txlocaltax1 = $originLine->localtax1_tx;
3034 $txlocaltax2 = $originLine->localtax2_tx;
3035 $fk_product = $originLine->fk_product;
3036 $remise_percent = $originLine->remise_percent;
3037 $date_start = $originLine->date_start;
3038 $date_end = $originLine->date_end;
3039 $fk_code_ventilation = 0;
3040 $info_bits = $originLine->info_bits;
3041 $fk_remise_except = $originLine->fk_remise_except;
3042 $price_base_type = 'HT';
3043 $pu_ttc = 0;
3044 $type = $originLine->product_type;
3045 $rang = $nextRang++;
3046 $special_code = $originLine->special_code;
3047 $origin = $originLine->element;
3048 $origin_id = $originLine->id;
3049 $fk_parent_line = 0;
3050 $fk_fournprice = $originLine->fk_fournprice;
3051 $pa_ht = $originLine->pa_ht;
3052 $label = $originLine->label;
3053 $array_options = $originLine->array_options;
3054 if ($object->type == Facture::TYPE_SITUATION) {
3055 $situation_percent = 0;
3056 } else {
3057 $situation_percent = 100;
3058 }
3059 $fk_prev_id = 0;
3060 $fk_unit = $originLine->fk_unit;
3061 $pu_ht_devise = $originLine->multicurrency_subprice;
3062
3063 $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);
3064
3065 if ($res > 0) {
3066 $importCount++;
3067 } else {
3068 $error++;
3069 }
3070 } else {
3071 $error++;
3072 }
3073 }
3074
3075 if ($error) {
3076 setEventMessages($langs->trans('ErrorsOnXLines', $error), null, 'errors');
3077 }
3078 }
3079 }
3080
3081 // Actions when printing a doc from card
3082 include DOL_DOCUMENT_ROOT.'/core/actions_printing.inc.php';
3083
3084 // Actions to send emails
3085 if (empty($id)) {
3086 $id = $facid;
3087 }
3088 $triggersendname = 'BILL_SENTBYMAIL';
3089 $paramname = 'id';
3090 $autocopy = 'MAIN_MAIL_AUTOCOPY_INVOICE_TO';
3091 $trackid = 'inv'.$object->id;
3092 include DOL_DOCUMENT_ROOT.'/core/actions_sendmails.inc.php';
3093
3094 // Actions to build doc
3095 $upload_dir = $conf->invoice->multidir_output[!empty($object->entity) ? $object->entity : $conf->entity];
3096 $permissiontoadd = $usercancreate;
3097 include DOL_DOCUMENT_ROOT.'/core/actions_builddoc.inc.php';
3098
3099
3100 if ($action == 'update_extras' && $usercancreate) {
3101 $object->oldcopy = dol_clone($object, 2);
3102
3103 // Fill array 'array_options' with data from add form
3104 $ret = $extrafields->setOptionalsFromPost(null, $object, GETPOST('attribute', 'restricthtml'));
3105 if ($ret < 0) {
3106 $error++;
3107 }
3108
3109 if (!$error) {
3110 // Actions on extra fields
3111 $result = $object->insertExtraFields('BILL_MODIFY');
3112 if ($result < 0) {
3113 setEventMessages($object->error, $object->errors, 'errors');
3114 $error++;
3115 }
3116 }
3117
3118 if ($error) {
3119 $action = 'edit_extras';
3120 }
3121 }
3122
3123 if (getDolGlobalString('MAIN_DISABLE_CONTACTS_TAB')) {
3124 if ($action == 'addcontact' && $usercancreate) {
3125 $result = $object->fetch($id);
3126
3127 if ($result > 0 && $id > 0) {
3128 $contactid = (GETPOST('userid') ? GETPOST('userid') : GETPOST('contactid'));
3129 $typeid = (GETPOST('typecontact') ? GETPOST('typecontact') : GETPOST('type'));
3130 $result = $object->add_contact($contactid, $typeid, GETPOST("source", 'aZ09'));
3131 }
3132
3133 if ($result >= 0) {
3134 header("Location: ".$_SERVER['PHP_SELF']."?id=".$object->id);
3135 exit();
3136 } else {
3137 if ($object->error == 'DB_ERROR_RECORD_ALREADY_EXISTS') {
3138 $langs->load("errors");
3139 setEventMessages($langs->trans("ErrorThisContactIsAlreadyDefinedAsThisType"), null, 'errors');
3140 } else {
3141 setEventMessages($object->error, $object->errors, 'errors');
3142 }
3143 }
3144 } elseif ($action == 'swapstatut' && $usercancreate) {
3145 // toggle the status of a contact
3146 if ($object->fetch($id)) {
3147 $result = $object->swapContactStatus(GETPOSTINT('ligne'));
3148 } else {
3149 dol_print_error($db);
3150 }
3151 } elseif ($action == 'deletecontact' && $usercancreate) {
3152 // Delete a contact
3153 $object->fetch($id);
3154 $result = $object->delete_contact($lineid);
3155
3156 if ($result >= 0) {
3157 header("Location: ".$_SERVER['PHP_SELF']."?id=".$object->id);
3158 exit();
3159 } else {
3160 dol_print_error($db);
3161 }
3162 }
3163
3164 if ($error) {
3165 $action = 'edit_extras';
3166 }
3167 }
3168}
3169
3170
3171/*
3172 * View
3173 */
3174
3175
3176$form = new Form($db);
3177$formother = new FormOther($db);
3178$formfile = new FormFile($db);
3179$formmargin = new FormMargin($db);
3180$soc = new Societe($db);
3181$paymentstatic = new Paiement($db);
3182$bankaccountstatic = new Account($db);
3183if (isModEnabled('project')) {
3184 $formproject = new FormProjets($db);
3185}
3186
3187$now = dol_now();
3188
3189$title = $object->ref." - ".$langs->trans('Card');
3190if ($action == 'create') {
3191 $title = $langs->trans("NewBill");
3192}
3193$help_url = "EN:Customers_Invoices|FR:Factures_Clients|ES:Facturas_a_clientes";
3194
3195llxHeader('', $title, $help_url);
3196
3197// Mode creation
3198
3199if ($action == 'create') {
3200 $facturestatic = new Facture($db);
3201 $extrafields->fetch_name_optionals_label($facturestatic->table_element);
3202
3203 print load_fiche_titre($langs->trans('NewBill'), '', 'bill');
3204
3205 if ($socid > 0) {
3206 $res = $soc->fetch($socid);
3207 }
3208
3209 $currency_code = $conf->currency;
3210
3211 $cond_reglement_id = GETPOSTINT('cond_reglement_id');
3212 $mode_reglement_id = GETPOSTINT('mode_reglement_id');
3213 $fk_account = GETPOSTINT('fk_account');
3214
3215 // Load objectsrc
3216 //$remise_absolue = 0;
3217 if (!empty($origin) && !empty($originid)) {
3218 // Parse element/subelement (ex: project_task)
3219 $element = $subelement = $origin;
3220 $regs = array();
3221 if (preg_match('/^([^_]+)_([^_]+)/i', $origin, $regs)) {
3222 $element = $regs[1];
3223 $subelement = $regs[2];
3224 }
3225
3226 $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
3227 $date_pointoftax = dol_mktime(0, 0, 0, GETPOSTINT('date_pointoftaxmonth'), GETPOSTINT('date_pointoftaxday'), GETPOSTINT('date_pointoftaxyear'), 'tzserver');
3228
3229 if ($element == 'project') {
3230 $projectid = $originid;
3231
3232 if (empty($cond_reglement_id)) {
3233 $cond_reglement_id = $soc->cond_reglement_id;
3234 }
3235 if (empty($mode_reglement_id)) {
3236 $mode_reglement_id = $soc->mode_reglement_id;
3237 }
3238 if (empty($fk_account)) {
3239 $fk_account = $soc->fk_account;
3240 }
3241 if (empty($dateinvoice)) {
3242 // Do not set 0 here (0 for a date is 1970)
3243 $dateinvoice = getDolGlobalString('MAIN_AUTOFILL_DATE') ? '' : -1;
3244 }
3245 } else {
3246 // For compatibility
3247 if ($element == 'order' || $element == 'commande') {
3248 $element = $subelement = 'commande';
3249 }
3250 if ($element == 'propal') {
3251 $element = 'comm/propal';
3252 $subelement = 'propal';
3253 }
3254 if ($element == 'contract') {
3255 $element = $subelement = 'contrat';
3256 }
3257 if ($element == 'shipping') {
3258 $element = $subelement = 'expedition';
3259 }
3260
3261 dol_include_once('/'.$element.'/class/'.$subelement.'.class.php');
3262
3263 $classname = ucfirst($subelement);
3264 $objectsrc = new $classname($db);
3265 $objectsrc->fetch($originid);
3266 if (empty($objectsrc->lines) && method_exists($objectsrc, 'fetch_lines')) {
3267 $objectsrc->fetch_lines();
3268 }
3269 $objectsrc->fetch_thirdparty();
3270
3271 $projectid = (!empty($projectid) ? $projectid : $objectsrc->fk_project);
3272 $ref_client = (!empty($objectsrc->ref_client) ? $objectsrc->ref_client : (!empty($objectsrc->ref_customer) ? $objectsrc->ref_customer : ''));
3273
3274 // only if socid not filled else it's already done above
3275 if (empty($socid)) {
3276 $soc = $objectsrc->thirdparty;
3277 }
3278
3279 $dateinvoice = (empty($dateinvoice) ? (!getDolGlobalString('MAIN_AUTOFILL_DATE') ? -1 : '') : $dateinvoice);
3280
3281 if ($element == 'expedition') {
3282 $ref_client = (!empty($objectsrc->ref_customer) ? $objectsrc->ref_customer : '');
3283
3284 $elem = $subelem = $objectsrc->origin;
3285 $expeoriginid = $objectsrc->origin_id;
3286 dol_include_once('/'.$elem.'/class/'.$subelem.'.class.php');
3287 $classname = ucfirst($subelem);
3288
3289 $expesrc = new $classname($db);
3290 $expesrc->fetch($expeoriginid);
3291
3292 $cond_reglement_id = (!empty($expesrc->cond_reglement_id) ? $expesrc->cond_reglement_id : (!empty($soc->cond_reglement_id) ? $soc->cond_reglement_id : 1));
3293 $mode_reglement_id = (!empty($expesrc->mode_reglement_id) ? $expesrc->mode_reglement_id : (!empty($soc->mode_reglement_id) ? $soc->mode_reglement_id : 0));
3294 $fk_account = (!empty($expesrc->fk_account) ? $expesrc->fk_account : (!empty($soc->fk_account) ? $soc->fk_account : 0));
3295
3296 if (isModEnabled('multicurrency')) {
3297 $currency_code = (!empty($expesrc->multicurrency_code) ? $expesrc->multicurrency_code : (!empty($soc->multicurrency_code) ? $soc->multicurrency_code : $objectsrc->multicurrency_code));
3298 $currency_tx = (!empty($expesrc->multicurrency_tx) ? $expesrc->multicurrency_tx : (!empty($soc->multicurrency_tx) ? $soc->multicurrency_tx : $objectsrc->multicurrency_tx));
3299 }
3300
3301 //Replicate extrafields
3302 $expesrc->fetch_optionals();
3303 $object->array_options = $expesrc->array_options;
3304 } else {
3305 $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)));
3306 $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)));
3307 $fk_account = (!empty($objectsrc->fk_account) ? $objectsrc->fk_account : (!empty($soc->fk_account) ? $soc->fk_account : (!empty($fk_account) ? $fk_account : 0)));
3308
3309 if (isModEnabled('multicurrency')) {
3310 if (!empty($objectsrc->multicurrency_code)) {
3311 $currency_code = $objectsrc->multicurrency_code;
3312 }
3313 if (getDolGlobalString('MULTICURRENCY_USE_ORIGIN_TX') && !empty($objectsrc->multicurrency_tx)) {
3314 $currency_tx = $objectsrc->multicurrency_tx;
3315 }
3316 }
3317
3318 // Replicate extrafields
3319 $objectsrc->fetch_optionals();
3320 $object->array_options = $objectsrc->array_options;
3321 }
3322 }
3323 } else {
3324 $cond_reglement_id = empty($soc->cond_reglement_id) ? $cond_reglement_id : $soc->cond_reglement_id;
3325 $mode_reglement_id = empty($soc->mode_reglement_id) ? $mode_reglement_id : $soc->mode_reglement_id;
3326 $fk_account = empty($soc->fk_account) ? $fk_account : $soc->fk_account;
3327
3328 $dateinvoice = (empty($dateinvoice) ? (!getDolGlobalString('MAIN_AUTOFILL_DATE') ? -1 : '') : $dateinvoice); // Do not set 0 here (0 for a date is 1970)
3329
3330 if (isModEnabled('multicurrency') && !empty($soc->multicurrency_code)) {
3331 $currency_code = $soc->multicurrency_code;
3332 }
3333 }
3334
3335 // If form was posted (but error returned), we must reuse the value posted in priority (standard Dolibarr behaviour)
3336 if (!GETPOST('changecompany')) {
3337 if (GETPOSTISSET('cond_reglement_id')) {
3338 $cond_reglement_id = GETPOSTINT('cond_reglement_id');
3339 }
3340 if (GETPOSTISSET('mode_reglement_id')) {
3341 $mode_reglement_id = GETPOSTINT('mode_reglement_id');
3342 }
3343 if (GETPOSTISSET('cond_reglement_id')) {
3344 $fk_account = GETPOSTINT('fk_account');
3345 }
3346 }
3347
3348 // when payment condition is empty (means not override by payment condition form a other object, like third-party), try to use default value
3349 if (empty($cond_reglement_id)) {
3350 $cond_reglement_id = GETPOSTINT("cond_reglement_id");
3351 }
3352
3353 // when payment mode is empty (means not override by payment mode form a other object, like third-party), try to use default value
3354 if (empty($mode_reglement_id)) {
3355 $mode_reglement_id = GETPOSTINT("mode_reglement_id");
3356 }
3357
3358 // when bank account is empty (means not override by payment mode form a other object, like third-party), try to use default value
3359 // if ($socid > 0 && $fk_account) { // A company has already been set and it has a default fk_account
3360 // $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
3361 // } else { // No company forced
3362 // $fk_account = GETPOST("fk_account", 'int');
3363 // }
3364
3365 if (!empty($soc->id)) {
3366 $absolute_discount = $soc->getAvailableDiscounts();
3367 }
3368 $note_public = $object->getDefaultCreateValueFor('note_public', ((!empty($origin) && !empty($originid) && is_object($objectsrc) && getDolGlobalString('FACTURE_REUSE_NOTES_ON_CREATE_FROM')) ? $objectsrc->note_public : null));
3369 $note_private = $object->getDefaultCreateValueFor('note_private', ((!empty($origin) && !empty($originid) && is_object($objectsrc) && getDolGlobalString('FACTURE_REUSE_NOTES_ON_CREATE_FROM')) ? $objectsrc->note_private : null));
3370
3371 if (!empty($conf->use_javascript_ajax)) {
3372 require_once DOL_DOCUMENT_ROOT.'/core/lib/ajax.lib.php';
3373 print ajax_combobox('fac_replacement');
3374 print ajax_combobox('fac_avoir');
3375 print ajax_combobox('situations');
3376 }
3377
3378 if ($origin == 'contrat') {
3379 $langs->load("admin");
3380 $text = $langs->trans("ToCreateARecurringInvoice");
3381 $text .= ' '.$langs->trans("ToCreateARecurringInvoiceGene", $langs->transnoentitiesnoconv("MenuFinancial"), $langs->transnoentitiesnoconv("BillsCustomers"), $langs->transnoentitiesnoconv("ListOfTemplates"));
3382 if (!getDolGlobalString('INVOICE_DISABLE_AUTOMATIC_RECURRING_INVOICE')) {
3383 $text .= ' '.$langs->trans("ToCreateARecurringInvoiceGeneAuto", $langs->transnoentitiesnoconv('Module2300Name'));
3384 }
3385 print info_admin($text, 0, 0, 0, 'opacitymedium').'<br>';
3386 }
3387
3388 print '<form name="add" action="'.$_SERVER["PHP_SELF"].'" method="POST" id="formtocreate" name="formtocreate">';
3389 print '<input type="hidden" name="token" value="'.newToken().'">';
3390 print '<input type="hidden" name="action" id="formtocreateaction" value="add">';
3391 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
3392 if ($soc->id > 0) {
3393 print '<input type="hidden" name="socid" value="'.$soc->id.'">'."\n";
3394 }
3395 print '<input type="hidden" name="backtopage" value="'.$backtopage.'">';
3396 print '<input name="ref" type="hidden" value="provisoire">';
3397 print '<input name="ref_client" type="hidden" value="'.$ref_client.'">';
3398 print '<input name="force_cond_reglement_id" type="hidden" value="0">';
3399 print '<input name="force_mode_reglement_id" type="hidden" value="0">';
3400 print '<input name="force_fk_account" type="hidden" value="0">';
3401 print '<input type="hidden" name="origin" value="'.$origin.'">';
3402 print '<input type="hidden" name="originid" value="'.$originid.'">';
3403 print '<input type="hidden" name="originentity" value="'.GETPOST('originentity').'">';
3404 if (!empty($currency_tx)) {
3405 print '<input type="hidden" name="originmulticurrency_tx" value="'.$currency_tx.'">';
3406 }
3407
3408 print dol_get_fiche_head();
3409
3410 // Call Hook tabContentCreateInvoice
3411 $parameters = array();
3412 // Note that $action and $object may be modified by hook
3413 $reshook = $hookmanager->executeHooks('tabContentCreateInvoice', $parameters, $object, $action);
3414 if (empty($reshook)) {
3415 print '<table class="border centpercent">';
3416
3417 $exampletemplateinvoice = new FactureRec($db);
3418 $invoice_predefined = new FactureRec($db);
3419 if (empty($origin) && empty($originid) && GETPOSTINT('fac_rec') > 0) {
3420 $invoice_predefined->fetch(GETPOSTINT('fac_rec'));
3421 }
3422
3423 // Thirdparty
3424 if ($soc->id > 0 && (!GETPOSTINT('fac_rec') || !empty($invoice_predefined->frequency))) {
3425 // If thirdparty known and not a predefined invoiced without a recurring rule
3426 print '<tr><td class="fieldrequired">'.$langs->trans('Customer').'</td>';
3427 print '<td colspan="2">';
3428 print $soc->getNomUrl(1, 'customer');
3429 print '<input type="hidden" name="socid" value="'.$soc->id.'">';
3430 // Outstanding Bill
3431 $arrayoutstandingbills = $soc->getOutstandingBills();
3432 $outstandingBills = $arrayoutstandingbills['opened'];
3433 print ' - <span class="opacitymedium">'.$langs->trans('CurrentOutstandingBill').':</span> ';
3434 print '<span class="amount">'.price($outstandingBills, 0, $langs, 0, 0, -1, $conf->currency).'</span>';
3435 if ($soc->outstanding_limit != '') {
3436 if ($outstandingBills > $soc->outstanding_limit) {
3437 print img_warning($langs->trans("OutstandingBillReached"));
3438 }
3439 print ' / '.price($soc->outstanding_limit, 0, $langs, 0, 0, -1, $conf->currency);
3440 }
3441 print '</td>';
3442 print '</tr>'."\n";
3443 } else {
3444 print '<tr><td class="fieldrequired">'.$langs->trans('Customer').'</td>';
3445 print '<td colspan="2">';
3446 $filter = '((s.client:IN:1,2,3) AND (s.status:=:1))';
3447 print img_picto('', 'company', 'class="pictofixedwidth"').$form->select_company($soc->id, 'socid', $filter, 'SelectThirdParty', 1, 0, array(), 0, 'minwidth300 widthcentpercentminusxx maxwidth500');
3448 // Option to reload page to retrieve customer information.
3449 if (!getDolGlobalString('RELOAD_PAGE_ON_CUSTOMER_CHANGE_DISABLED')) {
3450 print '<script>
3451 $(document).ready(function() {
3452 $("#socid").change(function() {
3453 /*
3454 console.log("Submit page");
3455 $(\'input[name="action"]\').val(\'create\');
3456 $(\'input[name="force_cond_reglement_id"]\').val(\'1\');
3457 $(\'input[name="force_mode_reglement_id"]\').val(\'1\');
3458 $(\'input[name="force_fk_account"]\').val(\'1\');
3459 $("#formtocreate").submit(); */
3460
3461 // For company change, we must submit page with action=create instead of action=add
3462 console.log("We have changed the company - Resubmit page");
3463 jQuery("input[name=changecompany]").val("1");
3464 jQuery("#formtocreateaction").val("create");
3465 jQuery("#formtocreate").submit();
3466 });
3467 });
3468 </script>';
3469 }
3470 if (!GETPOSTINT('fac_rec')) {
3471 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>';
3472 }
3473 print '</td>';
3474 print '</tr>'."\n";
3475 }
3476
3477 // Overwrite some values if creation of invoice is from a predefined invoice
3478 if (empty($origin) && empty($originid) && GETPOSTINT('fac_rec') > 0) {
3479 //$invoice_predefined->fetch(GETPOSTINT('fac_rec'));
3480 foreach ($invoice_predefined->array_options as $key => $option) {
3481 if (!isset($object->array_options[$key])) {
3482 $object->array_options[$key] = $invoice_predefined->array_options[$key];
3483 }
3484 }
3485
3486 $dateinvoice = $invoice_predefined->date_when; // To use next gen date by default later
3487 if (empty($projectid)) {
3488 $projectid = $invoice_predefined->fk_project;
3489 }
3490 $cond_reglement_id = $invoice_predefined->cond_reglement_id;
3491 $mode_reglement_id = $invoice_predefined->mode_reglement_id;
3492 $fk_account = $invoice_predefined->fk_account;
3493 $note_public = $invoice_predefined->note_public;
3494 $note_private = $invoice_predefined->note_private;
3495
3496 if (!empty($invoice_predefined->multicurrency_code)) {
3497 $currency_code = $invoice_predefined->multicurrency_code;
3498 }
3499 if (!empty($invoice_predefined->multicurrency_tx)) {
3500 $currency_tx = $invoice_predefined->multicurrency_tx;
3501 }
3502
3503 $sql = 'SELECT r.rowid, r.titre as title, r.total_ttc';
3504 $sql .= ' FROM '.MAIN_DB_PREFIX.'facture_rec as r';
3505 $sql .= ' WHERE r.fk_soc = '.((int) $invoice_predefined->socid);
3506
3507 $resql = $db->query($sql);
3508 if ($resql) {
3509 $num = $db->num_rows($resql);
3510 $i = 0;
3511
3512 if ($num > 0) {
3513 print '<tr><td>'.$langs->trans('CreateFromRepeatableInvoice').'</td><td>';
3514 //print '<input type="hidden" name="fac_rec" id="fac_rec" value="'.GETPOST('fac_rec', 'int').'">';
3515 print '<select class="flat" id="fac_rec" name="fac_rec">'; // We may want to change the template to use
3516 print '<option value="0" selected></option>';
3517 while ($i < $num) {
3518 $objp = $db->fetch_object($resql);
3519 print '<option value="'.$objp->rowid.'"';
3520 if (GETPOSTINT('fac_rec') == $objp->rowid) {
3521 print ' selected';
3522 $exampletemplateinvoice->fetch(GETPOSTINT('fac_rec'));
3523 }
3524 print '>'.$objp->title.' ('.price($objp->total_ttc).' '.$langs->trans("TTC").')</option>';
3525 $i++;
3526 }
3527 print '</select>';
3528
3529 print ajax_combobox("fac_rec");
3530
3531 // Option to reload page to retrieve customer information. Note, this clear other input
3532 if (!getDolGlobalString('RELOAD_PAGE_ON_TEMPLATE_CHANGE_DISABLED')) {
3533 print '<script type="text/javascript">
3534 $(document).ready(function() {
3535 $("#fac_rec").change(function() {
3536 console.log("We have changed the template invoice - Reload page");
3537 var fac_rec = $(this).val();
3538 var socid = $(\'#socid\').val();
3539 // 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.
3540 window.location.href = "'.$_SERVER["PHP_SELF"].'?action=create&socid="+socid+"&fac_rec="+fac_rec;
3541 });
3542 });
3543 </script>';
3544 }
3545 print '</td></tr>';
3546 }
3547 $db->free($resql);
3548 } else {
3549 dol_print_error($db);
3550 }
3551 }
3552
3553 print '<tr><td class="tdtop fieldrequired">'.$langs->trans('Type').'</td><td colspan="2">';
3554 print '<div class="tagtable">'."\n";
3555
3556 // Standard invoice
3557 print '<div class="tagtr listofinvoicetype"><div class="tagtd listofinvoicetype">';
3558 $tmp = '<input type="radio" id="radio_standard" name="type" value="0"'.(GETPOSTINT('type') ? '' : ' checked').'> ';
3559 $tmp = $tmp.'<label for="radio_standard" >'.$langs->trans("InvoiceStandardAsk").'</label>';
3560 // @phan-suppress-next-line PhanPluginSuspiciousParamOrder
3561 $desc = $form->textwithpicto($tmp, $langs->transnoentities("InvoiceStandardDesc"), 1, 'help', 'nowraponall', 0, 3, 'standardonsmartphone');
3562 print '<table class="nobordernopadding"><tr>';
3563 print '<td>';
3564 print $desc;
3565 print '</td>';
3566 if ((($origin == 'propal') || ($origin == 'commande')) && (!empty($originid))) {
3567 /*print '<td class="nowrap" style="padding-left: 5px">';
3568 $arraylist = array(
3569 //'amount' => $langs->transnoentitiesnoconv('FixAmount', $langs->transnoentitiesnoconv('Deposit')),
3570 //'variable' => $langs->transnoentitiesnoconv('VarAmountOneLine', $langs->transnoentitiesnoconv('Deposit')),
3571 'variablealllines' => $langs->transnoentitiesnoconv('VarAmountAllLines')
3572 );
3573 print $form->selectarray('typestandard', $arraylist, GETPOST('typestandard', 'aZ09'), 0, 0, 0, '', 1);
3574 print '</td>';*/
3575 print '<td class="nowrap" style="padding-left: 15px">';
3576 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%').'"/>';
3577 print '</td>';
3578 }
3579 print '</tr></table>';
3580 print '</div></div>';
3581
3582 if ((empty($origin)) || ((($origin == 'propal') || ($origin == 'commande')) && (!empty($originid)))) {
3583 // Deposit - Down payment
3584 if (!getDolGlobalString('INVOICE_DISABLE_DEPOSIT')) {
3585 print '<div class="tagtr listofinvoicetype"><div class="tagtd listofinvoicetype">';
3586 $tmp = '<input type="radio" id="radio_deposit" name="type" value="3"'.(GETPOSTINT('type') == 3 ? ' checked' : '').'> ';
3587 print '<script type="text/javascript">
3588 jQuery(document).ready(function() {
3589 jQuery("#typestandardinvoice, #valuestandardinvoice").click(function() {
3590 jQuery("#radio_standard").prop("checked", true);
3591 });
3592 jQuery("#typedeposit, #valuedeposit").click(function() {
3593 jQuery("#radio_deposit").prop("checked", true);
3594 });
3595 jQuery("#typedeposit").change(function() {
3596 console.log("We change type of down payment");
3597 jQuery("#radio_deposit").prop("checked", true);
3598 setRadioForTypeOfInvoice();
3599 });
3600 jQuery("#radio_standard, #radio_deposit, #radio_replacement, #radio_creditnote, #radio_template").change(function() {
3601 setRadioForTypeOfInvoice();
3602 });
3603 function setRadioForTypeOfInvoice() {
3604 console.log("Change radio for type of invoice");
3605 if (jQuery("#radio_deposit").prop("checked") && (jQuery("#typedeposit").val() == \'amount\' || jQuery("#typedeposit").val() == \'variable\')) {
3606 jQuery("#checkforselects").prop("disabled", true);
3607 jQuery("#checkforselects").prop("checked", false);
3608 jQuery(".checkforselect").prop("disabled", true);
3609 jQuery(".checkforselect").prop("checked", false);
3610 } else {
3611 jQuery("#checkforselects").prop("disabled", false);
3612 jQuery("#checkforselects").prop("checked", true);
3613 jQuery(".checkforselect").prop("disabled", false);
3614 jQuery(".checkforselect").prop("checked", true);
3615 }
3616 }
3617 });
3618 </script>';
3619
3620 print '<table class="nobordernopadding"><tr>';
3621 print '<td>';
3622 $tmp = $tmp.'<label for="radio_deposit">'.$langs->trans("InvoiceDeposit").'</label>';
3623 // @phan-suppress-next-line PhanPluginSuspiciousParamOrder
3624 $desc = $form->textwithpicto($tmp, $langs->transnoentities("InvoiceDepositDesc"), 1, 'help', '', 0, 3, 'depositonsmartphone');
3625 print $desc;
3626 print '</td>';
3627 if (($origin == 'propal') || ($origin == 'commande')) {
3628 print '<td class="nowrap" style="padding-left: 15px">';
3629 $arraylist = array(
3630 'amount' => $langs->transnoentitiesnoconv('FixAmount', $langs->transnoentitiesnoconv('Deposit')),
3631 'variable' => $langs->transnoentitiesnoconv('VarAmountOneLine', $langs->transnoentitiesnoconv('Deposit')),
3632 'variablealllines' => $langs->transnoentitiesnoconv('VarAmountAllLines')
3633 );
3634 $typedeposit = GETPOST('typedeposit', 'aZ09');
3635 $valuedeposit = GETPOSTINT('valuedeposit');
3636 if (empty($typedeposit) && !empty($objectsrc->deposit_percent)) {
3637 $origin_payment_conditions_deposit_percent = getDictionaryValue('c_payment_term', 'deposit_percent', $objectsrc->cond_reglement_id);
3638 if (!empty($origin_payment_conditions_deposit_percent)) {
3639 $typedeposit = 'variable';
3640 }
3641 }
3642 if (empty($valuedeposit) && $typedeposit == 'variable' && !empty($objectsrc->deposit_percent)) {
3643 $valuedeposit = $objectsrc->deposit_percent;
3644 }
3645 print $form->selectarray('typedeposit', $arraylist, $typedeposit, 0, 0, 0, '', 1);
3646 print '</td>';
3647 print '<td class="nowrap" style="padding-left: 5px">';
3648 print '<span class="opacitymedium paddingleft">'.$langs->trans("AmountOrPercent").'</span><input type="text" id="valuedeposit" name="valuedeposit" class="width75 right" value="'.$valuedeposit.'"/>';
3649 print '</td>';
3650 }
3651 print '</tr></table>';
3652
3653 print '</div></div>';
3654 }
3655 }
3656
3657 if ($socid > 0) {
3658 if (getDolGlobalString('INVOICE_USE_SITUATION')) {
3659 // First situation invoice
3660 print '<div class="tagtr listofinvoicetype"><div class="tagtd listofinvoicetype">';
3661 $tmp = '<input id="radio_situation" type="radio" name="type" value="5"'.(GETPOST('type') == 5 ? ' checked' : '').'> ';
3662 $tmp = $tmp.'<label for="radio_situation" >'.$langs->trans("InvoiceFirstSituationAsk").'</label>';
3663 // @phan-suppress-next-line PhanPluginSuspiciousParamOrder
3664 $desc = $form->textwithpicto($tmp, $langs->transnoentities("InvoiceFirstSituationDesc"), 1, 'help', '', 0, 3, 'firstsituationonsmartphone');
3665 print $desc;
3666 print '</div></div>';
3667
3668 // Next situation invoice
3669 $opt = $form->selectSituationInvoices(GETPOSTINT('originid'), $socid);
3670
3671 print '<div class="tagtr listofinvoicetype"><div class="tagtd listofinvoicetype">';
3672 $tmp = '<input type="radio" name="type" value="5"'.(GETPOST('type') == 5 && GETPOSTINT('originid') ? ' checked' : '');
3673 if ($opt == ('<option value ="0" selected>'.$langs->trans('NoSituations').'</option>') || (GETPOST('origin') && GETPOST('origin') != 'facture' && GETPOST('origin') != 'commande')) {
3674 $tmp .= ' disabled';
3675 }
3676 $tmp .= '> ';
3677 $text = $tmp.'<label>'.$langs->trans("InvoiceSituationAsk").'</label> ';
3678 $text .= '<select class="flat" id="situations" name="situations"';
3679 if ($opt == ('<option value ="0" selected>'.$langs->trans('NoSituations').'</option>') || (GETPOST('origin') && GETPOST('origin') != 'facture' && GETPOST('origin') != 'commande')) {
3680 $text .= ' disabled';
3681 }
3682 $text .= '>';
3683 $text .= $opt;
3684 $text .= '</select>';
3685 $desc = $form->textwithpicto($text, $langs->transnoentities("InvoiceSituationDesc"), 1, 'help', '', 0, 3);
3686 print $desc;
3687 print '</div></div>';
3688 }
3689
3690 // Replacement
3691 if (!getDolGlobalString('INVOICE_DISABLE_REPLACEMENT')) {
3692 // Type de facture
3693 $facids = $facturestatic->list_replacable_invoices($soc->id);
3694 if ($facids < 0) {
3695 dol_print_error($db, $facturestatic->error, $facturestatic->errors);
3696 exit();
3697 }
3698 $options = "";
3699 if (is_array($facids)) {
3700 foreach ($facids as $facparam) {
3701 $options .= '<option value="'.$facparam ['id'].'"';
3702 if ($facparam['id'] == GETPOSTINT('fac_replacement')) {
3703 $options .= ' selected';
3704 }
3705 $options .= '>'.$facparam['ref'];
3706 $options .= ' ('.$facturestatic->LibStatut($facparam['paid'], $facparam['status'], 0, $facparam['alreadypaid']).')';
3707 $options .= '</option>';
3708 }
3709 }
3710
3711 print '<!-- replacement line -->';
3712 print '<div class="tagtr listofinvoicetype"><div class="tagtd listofinvoicetype">';
3713 $tmp = '<input type="radio" name="type" id="radio_replacement" value="1"'.(GETPOST('type') == 1 ? ' checked' : '');
3714 if (!$options || $invoice_predefined->id > 0) {
3715 $tmp .= ' disabled';
3716 }
3717 $tmp .= '> ';
3718 print '<script type="text/javascript">
3719 jQuery(document).ready(function() {
3720 jQuery("#fac_replacement").change(function() {
3721 jQuery("#radio_replacement").prop("checked", true);
3722 });
3723 });
3724 </script>';
3725 $text = $tmp.'<label for="radio_replacement">'.$langs->trans("InvoiceReplacementAsk").'</label>';
3726 $text .= '<select class="flat" name="fac_replacement" id="fac_replacement"';
3727 if (!$options || $invoice_predefined->id > 0) {
3728 $text .= ' disabled';
3729 }
3730 $text .= '>';
3731 if ($options) {
3732 $text .= '<option value="-1">&nbsp;</option>';
3733 $text .= $options;
3734 } else {
3735 $text .= '<option value="-1">'.$langs->trans("NoReplacableInvoice").'</option>';
3736 }
3737 $text .= '</select>';
3738 $desc = $form->textwithpicto($text, $langs->transnoentities("InvoiceReplacementDesc"), 1, 'help', '', 0, 3);
3739 print $desc;
3740 print '</div></div>';
3741 }
3742 } else {
3743 if (getDolGlobalString('INVOICE_USE_SITUATION')) {
3744 print '<div class="tagtr listofinvoicetype"><div class="tagtd listofinvoicetype">';
3745 $tmp = '<input type="radio" name="type" id="radio_situation" value="0" disabled> ';
3746 $text = $tmp.'<label>'.$langs->trans("InvoiceSituationAsk").'</label> ';
3747 $text .= '<span class="opacitymedium">('.$langs->trans("YouMustCreateInvoiceFromThird").')</span> ';
3748 $desc = $form->textwithpicto($text, $langs->transnoentities("InvoiceFirstSituationDesc"), 1, 'help', 'nowraponall', 0, 3, 'firstsituationonsmartphone');
3749 print $desc;
3750 print '</div></div>';
3751 }
3752
3753 print '<div class="tagtr listofinvoicetype"><div class="tagtd listofinvoicetype">';
3754 $tmp = '<input type="radio" name="type" id="radio_replacement" value="0" disabled> ';
3755 $text = $tmp.'<label for="radio_replacement" class="opacitymedium">'.$langs->trans("InvoiceReplacement").'</label> ';
3756 //$text .= '<span class="opacitymedium hideonsmartphone">('.$langs->trans("YouMustCreateInvoiceFromThird").')</span> ';
3757 $desc = $form->textwithpicto($text, $langs->transnoentities("InvoiceReplacementDesc").'<br><br>'.$langs->trans("YouMustCreateInvoiceFromThird"), 1, 'help', 'nowraponall', 0, 3, 'replacementonsmartphone');
3758 print $desc;
3759 print '</div></div>';
3760 }
3761
3762 if (empty($origin)) {
3763 if ($socid > 0) {
3764 // Credit note
3765 if (!getDolGlobalString('INVOICE_DISABLE_CREDIT_NOTE')) {
3766 // Show link for credit note
3767 $facids = $facturestatic->list_qualified_avoir_invoices($soc->id);
3768 if ($facids < 0) {
3769 dol_print_error($db, $facturestatic->error, $facturestatic->errors);
3770 exit;
3771 }
3772 $optionsav = "";
3773 $newinvoice_static = new Facture($db);
3774 foreach ($facids as $key => $valarray) {
3775 $newinvoice_static->id = $key;
3776 $newinvoice_static->ref = $valarray ['ref'];
3777 $newinvoice_static->statut = $valarray ['status'];
3778 $newinvoice_static->status = $valarray ['status'];
3779 $newinvoice_static->type = $valarray ['type'];
3780 $newinvoice_static->paye = $valarray ['paye'];
3781
3782 $optionsav .= '<option value="'.$key.'"';
3783 if ($key == GETPOST('fac_avoir')) {
3784 $optionsav .= ' selected';
3785
3786 // pre-filled extra fields with selected credit note
3787 $newinvoice_static->fetch_optionals($key);
3788 $object->array_options = $newinvoice_static->array_options;
3789 }
3790 $optionsav .= '>';
3791 $optionsav .= $newinvoice_static->ref;
3792 $optionsav .= ' ('.$newinvoice_static->getLibStatut(1, $valarray ['paymentornot']).')';
3793 $optionsav .= '</option>';
3794 }
3795
3796 print '<div class="tagtr listofinvoicetype"><div class="tagtd listofinvoicetype">';
3797 $tmp = '<input type="radio" id="radio_creditnote" name="type" value="2"'.(GETPOST('type') == 2 ? ' checked' : '');
3798 if ((!$optionsav && !getDolGlobalString('INVOICE_CREDIT_NOTE_STANDALONE')) || $invoice_predefined->id > 0) {
3799 $tmp .= ' disabled';
3800 }
3801 $tmp .= '> ';
3802 // Show credit note options only if we checked credit note and disable standard invoice if "create credit note" button is pressed
3803 print '<script type="text/javascript">
3804 jQuery(document).ready(function() {
3805 if (jQuery("#radio_creditnote").is(":checked"))
3806 {
3807 jQuery("#radio_standard").prop("disabled", true);
3808 } else {
3809 jQuery("#radio_standard").prop("disabled", false);
3810 }
3811 if (! jQuery("#radio_creditnote").is(":checked"))
3812 {
3813 jQuery("#credit_note_options").hide();
3814 }
3815 jQuery("#radio_creditnote").click(function() {
3816 jQuery("#credit_note_options").show();
3817 });
3818 jQuery("#radio_standard, #radio_replacement, #radio_deposit").click(function() {
3819 jQuery("#credit_note_options").hide();
3820 });
3821 });
3822 </script>';
3823 $text = '<label>'.$tmp.$langs->transnoentities("InvoiceAvoirAsk").'</label> ';
3824 $text .= '<select class="flat valignmiddle" name="fac_avoir" id="fac_avoir"';
3825 if (!$optionsav || $invoice_predefined->id > 0) {
3826 $text .= ' disabled';
3827 }
3828 $text .= '>';
3829 if ($optionsav) {
3830 $text .= '<option value="-1"></option>';
3831 $text .= $optionsav;
3832 } else {
3833 $text .= '<option value="-1">'.$langs->trans("NoInvoiceToCorrect").'</option>';
3834 }
3835 $text .= '</select>';
3836 $desc = $form->textwithpicto($text, $langs->transnoentities("InvoiceAvoirDesc"), 1, 'help', '', 0, 3);
3837 print $desc;
3838
3839 print '<div id="credit_note_options" class="clearboth paddingtop marginbottomonly">';
3840 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>";
3841 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>";
3842 print '</div>';
3843
3844 print '</div></div>';
3845 }
3846 } else {
3847 print '<div class="tagtr listofinvoicetype"><div class="tagtd listofinvoicetype">';
3848 if (!getDolGlobalString('INVOICE_CREDIT_NOTE_STANDALONE')) {
3849 $tmp = '<input type="radio" name="type" id="radio_creditnote" value="0" disabled> ';
3850 } else {
3851 $tmp = '<input type="radio" name="type" id="radio_creditnote" value="2" > ';
3852 }
3853 $text = $tmp.'<label class="opacitymedium" for="radio_creditnote">'.$langs->trans("InvoiceAvoir").'</label> ';
3854 //$text .= '<span class="opacitymedium hideonsmartphone">('.$langs->trans("YouMustCreateInvoiceFromThird").')</span> ';
3855 $desc = $form->textwithpicto($text, $langs->transnoentities("InvoiceAvoirDesc").'<br><br>'.$langs->trans("CreateCreditNoteWhenClientInvoiceExists"), 1, 'help', '', 0, 3, 'creditnoteonsmartphone');
3856 print $desc;
3857 print '</div></div>'."\n";
3858 }
3859 }
3860
3861 // Template invoice
3862 print '<div class="tagtr listofinvoicetype"><div class="tagtd listofinvoicetype">';
3863 $tmp = '<input type="radio" name="type" id="radio_template" value="0" disabled> ';
3864 $text = $tmp.'<label class="opacitymedium" for="radio_template">'.$langs->trans("RepeatableInvoice").'</label> ';
3865 $desc = $form->textwithpicto($text, $langs->transnoentities("YouMustCreateStandardInvoiceFirstDesc"), 1, 'help', '', 0, 3, 'templateonsmartphone');
3866 print $desc;
3867 print '</div></div>';
3868
3869 print '</div>';
3870
3871
3872 if (getDolGlobalString('INVOICE_USE_DEFAULT_DOCUMENT')) { // Hidden conf
3873 // Add auto select default document model
3875 $jsListType = '';
3876 foreach ($listtType as $type) {
3877 $thisTypeConfName = 'FACTURE_ADDON_PDF_'.$type;
3878 $current = getDolGlobalString($thisTypeConfName, getDolGlobalString('FACTURE_ADDON_PDF'));
3879 $jsListType .= (!empty($jsListType) ? ',' : '').'"'.$type.'":"'.$current.'"';
3880 }
3881
3882 print '<script type="text/javascript">
3883 $(document).ready(function() {
3884 var listType = {'.$jsListType.'};
3885 $("[name=\'type\'").change(function() {
3886 console.log("change name=type");
3887 if ($( this ).prop("checked"))
3888 {
3889 if(($( this ).val() in listType))
3890 {
3891 $("#model").val(listType[$( this ).val()]);
3892 }
3893 else
3894 {
3895 $("#model").val("' . getDolGlobalString('FACTURE_ADDON_PDF').'");
3896 }
3897 }
3898 });
3899 });
3900 </script>';
3901 }
3902
3903
3904 print '</td></tr>';
3905
3906 // Invoice Subtype
3907 if (getDolGlobalInt('INVOICE_SUBTYPE_ENABLED')) {
3908 print '<tr><td class="fieldrequired">'.$langs->trans('InvoiceSubtype').'</td><td colspan="2">';
3909 print $form->getSelectInvoiceSubtype(GETPOST('subtype'), 'subtype', 1, 0, '');
3910 print '</td></tr>';
3911 }
3912
3913 // Discounts for the known third party
3914 if ($socid > 0) {
3915 print '<tr><td>'.$langs->trans('DiscountStillRemaining').'</td><td colspan="2">';
3916
3917 $thirdparty = $soc; // used by object_discounts.tpl.php
3918 $discount_type = 0; // used by object_discounts.tpl.php
3919 $backtopage = $_SERVER["PHP_SELF"].'?socid='.$thirdparty->id.'&action='.$action.'&origin='.urlencode((string) (GETPOST('origin'))).'&originid='.urlencode((string) (GETPOSTINT('originid')));
3920 include DOL_DOCUMENT_ROOT.'/core/tpl/object_discounts.tpl.php';
3921
3922 print '</td></tr>';
3923 }
3924
3925 $newdateinvoice = dol_mktime(0, 0, 0, GETPOSTINT('remonth'), GETPOSTINT('reday'), GETPOSTINT('reyear'), 'tzserver');
3926 $date_pointoftax = dol_mktime(0, 0, 0, GETPOSTINT('date_pointoftaxmonth'), GETPOSTINT('date_pointoftaxday'), GETPOSTINT('date_pointoftaxyear'), 'tzserver');
3927
3928 // Date invoice
3929 print '<tr><td class="fieldrequired">'.$langs->trans('DateInvoice').'</td><td colspan="2">';
3930 print img_picto('', 'action', 'class="pictofixedwidth"');
3931 print $form->selectDate($newdateinvoice ? $newdateinvoice : $dateinvoice, '', 0, 0, 0, "add", 1, 1);
3932 print '</td></tr>';
3933
3934 // Date point of tax
3935 if (getDolGlobalString('INVOICE_POINTOFTAX_DATE')) {
3936 print '<tr><td class="fieldrequired">'.$langs->trans('DatePointOfTax').'</td><td colspan="2">';
3937 print img_picto('', 'action', 'class="pictofixedwidth"');
3938 print $form->selectDate($date_pointoftax ? $date_pointoftax : -1, 'date_pointoftax', 0, 0, 0, "add", 1, 1);
3939 print '</td></tr>';
3940 }
3941
3942 // Payment term
3943 print '<tr><td class="nowrap fieldrequired">'.$langs->trans('PaymentConditionsShort').'</td><td colspan="2">';
3944 print img_picto('', 'payment', 'class="pictofixedwidth"');
3945 print $form->getSelectConditionsPaiements($cond_reglement_id, 'cond_reglement_id', -1, 1, 0, 'maxwidth500 widthcentpercentminusx');
3946 print '</td></tr>';
3947
3948 // Warranty
3949 if (getDolGlobalString('INVOICE_USE_RETAINED_WARRANTY')) {
3950 $rwStyle = 'display:none;';
3951 if (in_array(GETPOSTINT('type'), $retainedWarrantyInvoiceAvailableType)) {
3952 $rwStyle = '';
3953 }
3954
3955 $retained_warranty = GETPOSTINT('retained_warranty');
3956 if (empty($retained_warranty)) {
3957 if (!empty($objectsrc->retained_warranty)) { // use previous situation value
3958 $retained_warranty = $objectsrc->retained_warranty;
3959 }
3960 }
3961 $retained_warranty_js_default = !empty($retained_warranty) ? $retained_warranty : getDolGlobalString('INVOICE_SITUATION_DEFAULT_RETAINED_WARRANTY_PERCENT');
3962
3963 print '<tr class="retained-warranty-line" style="'.$rwStyle.'" ><td class="nowrap">'.$langs->trans('RetainedWarranty').'</td><td colspan="2">';
3964 print '<input id="new-situation-invoice-retained-warranty" name="retained_warranty" type="number" value="'.$retained_warranty.'" step="0.01" min="0" max="100" />%';
3965
3966 // Retained warranty payment term
3967 print '<tr class="retained-warranty-line" style="'.$rwStyle.'" ><td class="nowrap">'.$langs->trans('PaymentConditionsShortRetainedWarranty').'</td><td colspan="2">';
3968 $retained_warranty_fk_cond_reglement = GETPOSTINT('retained_warranty_fk_cond_reglement');
3969 if (empty($retained_warranty_fk_cond_reglement)) {
3970 $retained_warranty_fk_cond_reglement = getDolGlobalString('INVOICE_SITUATION_DEFAULT_RETAINED_WARRANTY_COND_ID');
3971 if (!empty($objectsrc->retained_warranty_fk_cond_reglement)) { // use previous situation value
3972 $retained_warranty_fk_cond_reglement = $objectsrc->retained_warranty_fk_cond_reglement;
3973 } else {
3974 $retained_warranty_fk_cond_reglement = getDolGlobalString('INVOICE_SITUATION_DEFAULT_RETAINED_WARRANTY_COND_ID');
3975 }
3976 }
3977 print $form->getSelectConditionsPaiements($retained_warranty_fk_cond_reglement, 'retained_warranty_fk_cond_reglement', -1, 1);
3978 print '</td></tr>';
3979
3980 print '<script type="text/javascript">
3981 $(document).ready(function() {
3982 $("[name=\'type\']").change(function() {
3983 if($( this ).prop("checked") && $.inArray($( this ).val(), '.json_encode($retainedWarrantyInvoiceAvailableType).' ) !== -1)
3984 {
3985 $(".retained-warranty-line").show();
3986 $("#new-situation-invoice-retained-warranty").val("'.(float) $retained_warranty_js_default.'");
3987 }
3988 else{
3989 $(".retained-warranty-line").hide();
3990 $("#new-situation-invoice-retained-warranty").val("");
3991 }
3992 });
3993
3994 $("[name=\'type\']:checked").trigger("change");
3995 });
3996 </script>';
3997 }
3998
3999 // Payment mode
4000 print '<tr><td>'.$langs->trans('PaymentMode').'</td><td colspan="2">';
4001 print img_picto('', 'bank', 'class="pictofixedwidth"');
4002 print $form->select_types_paiements($mode_reglement_id, 'mode_reglement_id', 'CRDT', 0, 1, 0, 0, 1, 'maxwidth200 widthcentpercentminusx', 1);
4003 print '</td></tr>';
4004
4005 // Bank Account
4006 if (isModEnabled("bank")) {
4007 print '<tr><td>'.$langs->trans('BankAccount').'</td><td colspan="2">';
4008 print img_picto('', 'bank_account', 'class="pictofixedwidth"');
4009 print $form->select_comptes($fk_account, 'fk_account', 0, '', 1, '', 0, 'maxwidth200 widthcentpercentminusx', 1);
4010 print '</td></tr>';
4011 }
4012
4013 // Project
4014 if (isModEnabled('project')) {
4015 $langs->load('projects');
4016 print '<tr><td>'.$langs->trans('Project').'</td><td colspan="2">';
4017 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');
4018 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>';
4019 print '</td></tr>';
4020 }
4021
4022 // Incoterms
4023 if (isModEnabled('incoterm')) {
4024 print '<tr>';
4025 print '<td><label for="incoterm_id">'.$form->textwithpicto($langs->trans("IncotermLabel"), !empty($objectsrc->label_incoterms) ? $objectsrc->label_incoterms : '', 1).'</label></td>';
4026 print '<td colspan="2" class="maxwidthonsmartphone">';
4027 $incoterm_id = GETPOST('incoterm_id');
4028 $location_incoterms = GETPOST('location_incoterms');
4029 if (empty($incoterm_id)) {
4030 $incoterm_id = (!empty($objectsrc->fk_incoterms) ? $objectsrc->fk_incoterms : $soc->fk_incoterms);
4031 $location_incoterms = (!empty($objectsrc->location_incoterms) ? $objectsrc->location_incoterms : $soc->location_incoterms);
4032 }
4033 print img_picto('', 'incoterm', 'class="pictofixedwidth"');
4034 print $form->select_incoterms($incoterm_id, $location_incoterms);
4035 print '</td></tr>';
4036 }
4037
4038 // Other attributes
4039 $parameters = array('objectsrc' => !empty($objectsrc) ? $objectsrc : 0, 'colspan' => ' colspan="2"', 'cols' => '2', 'socid' => $socid);
4040 $reshook = $hookmanager->executeHooks('formObjectOptions', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
4041 print $hookmanager->resPrint;
4042 if (empty($reshook)) {
4043 if (getDolGlobalString('THIRDPARTY_PROPAGATE_EXTRAFIELDS_TO_INVOICE') && !empty($soc->id)) {
4044 // copy from thirdparty
4045 $tpExtrafields = new ExtraFields($db);
4046 $tpExtrafieldLabels = $tpExtrafields->fetch_name_optionals_label($soc->table_element);
4047 if ($soc->fetch_optionals() > 0) {
4048 $object->array_options = array_merge($object->array_options, $soc->array_options);
4049 }
4050 }
4051
4052 print $object->showOptionals($extrafields, 'create', $parameters);
4053 }
4054
4055 // Template to use by default
4056 print '<tr><td>'.$langs->trans('Model').'</td>';
4057 print '<td colspan="2">';
4058 print img_picto('', 'pdf', 'class="pictofixedwidth"');
4059 include_once DOL_DOCUMENT_ROOT.'/core/modules/facture/modules_facture.php';
4061 if (getDolGlobalString('INVOICE_USE_DEFAULT_DOCUMENT')) {
4062 $type = GETPOSTISSET('type') ? GETPOSTINT('type') : $object->type;
4063 // Hidden conf
4064 $paramkey = 'FACTURE_ADDON_PDF_'.$type;
4065 $preselected = getDolGlobalString($paramkey, getDolGlobalString('FACTURE_ADDON_PDF'));
4066 } else {
4067 $preselected = getDolGlobalString('FACTURE_ADDON_PDF');
4068 }
4069 print $form->selectarray('model', $liste, $preselected, 0, 0, 0, '', 0, 0, 0, '', 'maxwidth200 widthcentpercentminusx', 1);
4070 print "</td></tr>";
4071
4072 // Multicurrency
4073 if (isModEnabled('multicurrency')) {
4074 print '<tr>';
4075 print '<td>'.$form->editfieldkey('Currency', 'multicurrency_code', '', $object, 0).'</td>';
4076 print '<td colspan="2" class="maxwidthonsmartphone">';
4077 print img_picto('', 'currency', 'class="pictofixedwidth"');
4078 print $form->selectMultiCurrency(((GETPOSTISSET('multicurrency_code') && !GETPOST('changecompany')) ? GETPOST('multicurrency_code') : $currency_code), 'multicurrency_code', 0, '', false, 'maxwidth100 widthcentpercentminusx');
4079 print '</td></tr>';
4080 }
4081
4082 // Help of substitution key
4083 $htmltext = '';
4084 if (GETPOSTINT('fac_rec') > 0) {
4085 $dateexample = ($newdateinvoice ? $newdateinvoice : $dateinvoice);
4086 if (empty($dateexample)) {
4087 $dateexample = dol_now();
4088 }
4089 $substitutionarray = array(
4090 '__TOTAL_HT__' => $langs->trans("AmountHT").' ('.$langs->trans("Example").': '.price($exampletemplateinvoice->total_ht).')',
4091 '__TOTAL_TTC__' => $langs->trans("AmountTTC").' ('.$langs->trans("Example").': '.price($exampletemplateinvoice->total_ttc).')',
4092 '__INVOICE_PREVIOUS_MONTH__' => $langs->trans("PreviousMonthOfInvoice").' ('.$langs->trans("Example").': '.dol_print_date(dol_time_plus_duree($dateexample, -1, 'm'), '%m').')',
4093 '__INVOICE_MONTH__' => $langs->trans("MonthOfInvoice").' ('.$langs->trans("Example").': '.dol_print_date($dateexample, '%m').')',
4094 '__INVOICE_NEXT_MONTH__' => $langs->trans("NextMonthOfInvoice").' ('.$langs->trans("Example").': '.dol_print_date(dol_time_plus_duree($dateexample, 1, 'm'), '%m').')',
4095 '__INVOICE_PREVIOUS_MONTH_TEXT__' => $langs->trans("TextPreviousMonthOfInvoice").' ('.$langs->trans("Example").': '.dol_print_date(dol_time_plus_duree($dateexample, -1, 'm'), '%B').')',
4096 '__INVOICE_MONTH_TEXT__' => $langs->trans("TextMonthOfInvoice").' ('.$langs->trans("Example").': '.dol_print_date($dateexample, '%B').')',
4097 '__INVOICE_NEXT_MONTH_TEXT__' => $langs->trans("TextNextMonthOfInvoice").' ('.$langs->trans("Example").': '.dol_print_date(dol_time_plus_duree($dateexample, 1, 'm'), '%B').')',
4098 '__INVOICE_PREVIOUS_YEAR__' => $langs->trans("PreviousYearOfInvoice").' ('.$langs->trans("Example").': '.dol_print_date(dol_time_plus_duree($dateexample, -1, 'y'), '%Y').')',
4099 '__INVOICE_YEAR__' => $langs->trans("YearOfInvoice").' ('.$langs->trans("Example").': '.dol_print_date($dateexample, '%Y').')',
4100 '__INVOICE_NEXT_YEAR__' => $langs->trans("NextYearOfInvoice").' ('.$langs->trans("Example").': '.dol_print_date(dol_time_plus_duree($dateexample, 1, 'y'), '%Y').')'
4101 );
4102
4103 $htmltext = '<i>'.$langs->trans("FollowingConstantsWillBeSubstituted").':<br>';
4104 foreach ($substitutionarray as $key => $val) {
4105 $htmltext .= $key.' = '.$langs->trans($val).'<br>';
4106 }
4107 $htmltext .= '</i>';
4108 }
4109
4110 // Public note
4111 print '<tr>';
4112 print '<td class="tdtop">';
4113 print $form->textwithpicto($langs->trans('NotePublic'), $htmltext);
4114 print '</td>';
4115 print '<td valign="top" colspan="2">';
4116 $doleditor = new DolEditor('note_public', $note_public, '', 80, 'dolibarr_notes', 'In', 0, false, !getDolGlobalString('FCKEDITOR_ENABLE_NOTE_PUBLIC') ? 0 : 1, ROWS_3, '90%');
4117 print $doleditor->Create(1);
4118
4119 // Private note
4120 if (empty($user->socid)) {
4121 print '<tr>';
4122 print '<td class="tdtop">';
4123 print $form->textwithpicto($langs->trans('NotePrivate'), $htmltext);
4124 print '</td>';
4125 print '<td valign="top" colspan="2">';
4126 $doleditor = new DolEditor('note_private', $note_private, '', 80, 'dolibarr_notes', 'In', 0, false, !getDolGlobalString('FCKEDITOR_ENABLE_NOTE_PRIVATE') ? 0 : 1, ROWS_3, '90%');
4127 print $doleditor->Create(1);
4128 // print '<textarea name="note_private" wrap="soft" cols="70" rows="'.ROWS_3.'">'.$note_private.'.</textarea>
4129 print '</td></tr>';
4130 }
4131
4132 // Lines from source (TODO Show them also when creating invoice from template invoice)
4133 if (!empty($origin) && !empty($originid) && is_object($objectsrc)) {
4134 $langs->loadLangs(array('orders', 'propal'));
4135
4136 // TODO for compatibility
4137 if ($origin == 'contrat') {
4138 // Calcul contrat->price (HT), contrat->total (TTC), contrat->tva
4139 $objectsrc->update_price(1, 'auto', 1);
4140 }
4141
4142 print "\n<!-- Show ref of origin ".$classname." -->\n";
4143 print '<input type="hidden" name="amount" value="'.$objectsrc->total_ht.'">'."\n";
4144 print '<input type="hidden" name="total" value="'.$objectsrc->total_ttc.'">'."\n";
4145 print '<input type="hidden" name="tva" value="'.$objectsrc->total_tva.'">'."\n";
4146 // The commented lines below are fields already added as hidden parameters before
4147 //print '<input type="hidden" name="origin" value="'.$objectsrc->element.'">';
4148 //print '<input type="hidden" name="originid" value="'.$objectsrc->id.'">';
4149
4150 switch (get_class($objectsrc)) {
4151 case 'Propal':
4152 $newclassname = 'CommercialProposal';
4153 break;
4154 case 'Commande':
4155 $newclassname = 'Order';
4156 break;
4157 case 'Expedition':
4158 $newclassname = 'Sending';
4159 break;
4160 case 'Contrat':
4161 $newclassname = 'Contract';
4162 break;
4163 case 'Fichinter':
4164 $newclassname = 'Intervention';
4165 break;
4166 default:
4167 $newclassname = get_class($objectsrc);
4168 }
4169
4170 // Ref of origin
4171 print '<tr><td>'.$langs->trans($newclassname).'</td>';
4172 print '<td colspan="2">';
4173 print $objectsrc->getNomUrl(1);
4174 // We check if Origin document (id and type is known) has already at least one invoice attached to it
4175 $objectsrc->fetchObjectLinked($originid, $origin, null, 'facture');
4176 if (isset($objectsrc->linkedObjects['facture']) && is_array($objectsrc->linkedObjects['facture']) && count($objectsrc->linkedObjects['facture']) >= 1) {
4177 setEventMessages('WarningBillExist', null, 'warnings');
4178 echo ' - '.$langs->trans('LatestRelatedBill').' '.end($objectsrc->linkedObjects['facture'])->getNomUrl(1);
4179 }
4180 echo '</td></tr>';
4181 print '<tr><td>'.$langs->trans('AmountHT').'</td><td colspan="2">'.price($objectsrc->total_ht).'</td></tr>';
4182 print '<tr><td>'.$langs->trans('AmountVAT').'</td><td colspan="2">'.price($objectsrc->total_tva)."</td></tr>";
4183 if ($mysoc->localtax1_assuj == "1" || $objectsrc->total_localtax1 != 0) { // Localtax1
4184 print '<tr><td>'.$langs->transcountry("AmountLT1", $mysoc->country_code).'</td><td colspan="2">'.price($objectsrc->total_localtax1)."</td></tr>";
4185 }
4186
4187 if ($mysoc->localtax2_assuj == "1" || $objectsrc->total_localtax2 != 0) { // Localtax2
4188 print '<tr><td>'.$langs->transcountry("AmountLT2", $mysoc->country_code).'</td><td colspan="2">'.price($objectsrc->total_localtax2)."</td></tr>";
4189 }
4190 print '<tr><td>'.$langs->trans('AmountTTC').'</td><td colspan="2">'.price($objectsrc->total_ttc)."</td></tr>";
4191
4192 if (isModEnabled('multicurrency')) {
4193 print '<tr><td>'.$langs->trans('MulticurrencyAmountHT').'</td><td colspan="2">'.price($objectsrc->multicurrency_total_ht).'</td></tr>';
4194 print '<tr><td>'.$langs->trans('MulticurrencyAmountVAT').'</td><td colspan="2">'.price($objectsrc->multicurrency_total_tva)."</td></tr>";
4195 print '<tr><td>'.$langs->trans('MulticurrencyAmountTTC').'</td><td colspan="2">'.price($objectsrc->multicurrency_total_ttc)."</td></tr>";
4196 }
4197 }
4198
4199 print "</table>\n";
4200 }
4201 print dol_get_fiche_end();
4202
4203 print $form->buttonsSaveCancel("CreateDraft");
4204
4205 // Show origin lines
4206 if (!empty($origin) && !empty($originid) && is_object($objectsrc)) {
4207 print '<br>';
4208
4209 $title = $langs->trans('ProductsAndServices');
4210 print load_fiche_titre($title);
4211
4212 print '<div class="div-table-responsive-no-min">';
4213 print '<table class="noborder centpercent">';
4214
4215 $objectsrc->printOriginLinesList('', $selectedLines);
4216
4217 print '</table>';
4218 print '</div>';
4219 }
4220
4221 print "</form>\n";
4222} elseif ($id > 0 || !empty($ref)) {
4223 if (empty($object->id)) {
4224 $langs->load('errors');
4225 echo '<div class="error">'.$langs->trans("ErrorRecordNotFound").'</div>';
4226 llxFooter();
4227 exit;
4228 }
4229
4230 /*
4231 * Show object in view mode
4232 */
4233
4234 $result = $object->fetch($id, $ref);
4235 if ($result <= 0) {
4236 dol_print_error($db, $object->error, $object->errors);
4237 exit();
4238 }
4239
4240 // fetch optionals attributes and labels
4241 $extrafields->fetch_name_optionals_label($object->table_element);
4242
4243 if ($user->socid > 0 && $user->socid != $object->socid) {
4244 accessforbidden('', 0, 1);
4245 }
4246
4247 $result = $object->fetch_thirdparty();
4248
4249 $result = $soc->fetch($object->socid);
4250 if ($result < 0) {
4251 dol_print_error($db);
4252 }
4253 $selleruserevenustamp = $mysoc->useRevenueStamp();
4254
4255 $totalpaid = $object->getSommePaiement();
4256 $totalcreditnotes = $object->getSumCreditNotesUsed();
4257 $totaldeposits = $object->getSumDepositsUsed();
4258 //print "totalpaid=".$totalpaid." totalcreditnotes=".$totalcreditnotes." totaldeposts=".$totaldeposits."
4259 // selleruserrevenuestamp=".$selleruserevenustamp;
4260
4261 // We can also use bcadd to avoid pb with floating points
4262 // For example print 239.2 - 229.3 - 9.9; does not return 0.
4263 $resteapayer = price2num($object->total_ttc - $totalpaid - $totalcreditnotes - $totaldeposits, 'MT');
4264
4265 // Multicurrency
4266 if (isModEnabled('multicurrency')) {
4267 $multicurrency_totalpaid = $object->getSommePaiement(1);
4268 $multicurrency_totalcreditnotes = $object->getSumCreditNotesUsed(1);
4269 $multicurrency_totaldeposits = $object->getSumDepositsUsed(1);
4270 $multicurrency_resteapayer = price2num($object->multicurrency_total_ttc - $multicurrency_totalpaid - $multicurrency_totalcreditnotes - $multicurrency_totaldeposits, 'MT');
4271 // Code to fix case of corrupted data
4272 // 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
4273 // 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)
4274 if ($resteapayer == 0 && $multicurrency_resteapayer != 0 && $object->multicurrency_code != $conf->currency) {
4275 $resteapayer = price2num((float) $multicurrency_resteapayer / $object->multicurrency_tx, 'MT');
4276 }
4277 }
4278
4279 if ($object->paye) {
4280 $resteapayer = 0;
4281 }
4282 $resteapayeraffiche = $resteapayer;
4283
4284 if (getDolGlobalString('FACTURE_DEPOSITS_ARE_JUST_PAYMENTS')) { // Never use this
4285 $filterabsolutediscount = "fk_facture_source IS NULL"; // If we want deposit to be subtracted to payments only and not to total of final invoice
4286 $filtercreditnote = "fk_facture_source IS NOT NULL"; // If we want deposit to be subtracted to payments only and not to total of final invoice
4287 } else {
4288 $filterabsolutediscount = "fk_facture_source IS NULL OR (description LIKE '(DEPOSIT)%' AND description NOT LIKE '(EXCESS RECEIVED)%')";
4289 $filtercreditnote = "fk_facture_source IS NOT NULL AND (description NOT LIKE '(DEPOSIT)%' OR description LIKE '(EXCESS RECEIVED)%')";
4290 }
4291
4292 $absolute_discount = $soc->getAvailableDiscounts(null, $filterabsolutediscount);
4293 $absolute_creditnote = $soc->getAvailableDiscounts(null, $filtercreditnote);
4294 $absolute_discount = price2num($absolute_discount, 'MT');
4295 $absolute_creditnote = price2num($absolute_creditnote, 'MT');
4296
4297 $author = new User($db);
4298 if ($object->user_creation_id) {
4299 $author->fetch($object->user_creation_id);
4300 }
4301
4302 $objectidnext = $object->getIdReplacingInvoice();
4303
4305
4306 print dol_get_fiche_head($head, 'compta', $langs->trans('InvoiceCustomer'), -1, 'bill');
4307
4308 $formconfirm = '';
4309
4310 // Confirmation of the conversion of the credit into a reduction
4311 if ($action == 'converttoreduc') {
4313 $type_fac = 'ExcessReceived';
4314 } elseif ($object->type == Facture::TYPE_CREDIT_NOTE) {
4315 $type_fac = 'CreditNote';
4316 } elseif ($object->type == Facture::TYPE_DEPOSIT) {
4317 $type_fac = 'Deposit';
4318 }
4319 $text = $langs->trans('ConfirmConvertToReduc', strtolower($langs->transnoentities($type_fac)));
4320 $text .= '<br>'.$langs->trans('ConfirmConvertToReduc2');
4321 $formconfirm = $form->formconfirm($_SERVER['PHP_SELF'].'?facid='.$object->id, $langs->trans('ConvertToReduc'), $text, 'confirm_converttoreduc', '', "yes", 2);
4322 }
4323
4324 // Confirmation to delete invoice
4325 if ($action == 'delete') {
4326 $text = $langs->trans('ConfirmDeleteBill', $object->ref);
4327 $formquestion = array();
4328
4329 if ($object->type != Facture::TYPE_DEPOSIT && getDolGlobalString('STOCK_CALCULATE_ON_BILL') && $object->status >= 1) {
4330 $qualified_for_stock_change = 0;
4331 if (!getDolGlobalString('STOCK_SUPPORTS_SERVICES')) {
4332 $qualified_for_stock_change = $object->hasProductsOrServices(2);
4333 } else {
4334 $qualified_for_stock_change = $object->hasProductsOrServices(1);
4335 }
4336
4337 if ($qualified_for_stock_change) {
4338 $langs->load("stocks");
4339 require_once DOL_DOCUMENT_ROOT.'/product/class/html.formproduct.class.php';
4340 $formproduct = new FormProduct($db);
4341 $label = $object->type == Facture::TYPE_CREDIT_NOTE ? $langs->trans("SelectWarehouseForStockDecrease") : $langs->trans("SelectWarehouseForStockIncrease");
4342 $forcecombo = 0;
4343 if ($conf->browser->name == 'ie') {
4344 $forcecombo = 1; // There is a bug in IE10 that make combo inside popup crazy
4345 }
4346 $formquestion = array(
4347 // 'text' => $langs->trans("ConfirmClone"),
4348 // array('type' => 'checkbox', 'name' => 'clone_content', 'label' => $langs->trans("CloneMainAttributes"), 'value' => 1),
4349 // array('type' => 'checkbox', 'name' => 'update_prices', 'label' => $langs->trans("PuttingPricesUpToDate"), 'value' => 1),
4350 array('type' => 'other', 'name' => 'idwarehouse', 'label' => $label, 'value' => $formproduct->selectWarehouses(GETPOST('idwarehouse') ? GETPOST('idwarehouse') : 'ifone', 'idwarehouse', '', 1, 0, 0, $langs->trans("NoStockAction"), 0, $forcecombo))
4351 );
4352 $formconfirm = $form->formconfirm($_SERVER['PHP_SELF'].'?facid='.$object->id, $langs->trans('DeleteBill'), $text, 'confirm_delete', $formquestion, "yes", 1);
4353 } else {
4354 $formconfirm = $form->formconfirm($_SERVER['PHP_SELF'].'?facid='.$object->id, $langs->trans('DeleteBill'), $text, 'confirm_delete', '', 'no', 1);
4355 }
4356 } else {
4357 $formconfirm = $form->formconfirm($_SERVER['PHP_SELF'].'?facid='.$object->id, $langs->trans('DeleteBill'), $text, 'confirm_delete', '', 'no', 1);
4358 }
4359 }
4360
4361 // Confirmation to remove invoice from cycle
4362 if ($action == 'situationout') {
4363 $text = $langs->trans('ConfirmRemoveSituationFromCycle', $object->ref);
4364 $label = $langs->trans("ConfirmOuting");
4365 $formquestion = array();
4366 // remove situation from cycle
4367 if (in_array($object->status, array(Facture::STATUS_CLOSED, Facture::STATUS_VALIDATED))
4368 && $usercancreate
4369 && !$objectidnext
4370 && $object->is_last_in_cycle()
4371 && $usercanunvalidate
4372 ) {
4373 $formconfirm = $form->formconfirm($_SERVER['PHP_SELF'].'?facid='.$object->id, $label, $text, 'confirm_situationout', $formquestion, "yes", 1);
4374 }
4375 }
4376
4377 // Confirmation of validation
4378 if ($action == 'valid') {
4379 // we check object has a draft number
4380 $objectref = substr($object->ref, 1, 4);
4381 if ($objectref == 'PROV') {
4382 $savdate = $object->date;
4383 if (getDolGlobalString('FAC_FORCE_DATE_VALIDATION')) {
4384 $object->date = dol_now();
4385 $object->date_lim_reglement = $object->calculate_date_lim_reglement();
4386 }
4387 $numref = $object->getNextNumRef($soc);
4388 // $object->date=$savdate;
4389 } else {
4390 $numref = $object->ref;
4391 }
4392
4393 $text = $langs->trans('ConfirmValidateBill', $numref);
4394 if (isModEnabled('notification')) {
4395 require_once DOL_DOCUMENT_ROOT.'/core/class/notify.class.php';
4396 $notify = new Notify($db);
4397 $text .= '<br>';
4398 $text .= $notify->confirmMessage('BILL_VALIDATE', $object->socid, $object);
4399 }
4400 $formquestion = array();
4401
4402 if ($object->type != Facture::TYPE_DEPOSIT && getDolGlobalString('STOCK_CALCULATE_ON_BILL')) {
4403 $qualified_for_stock_change = 0;
4404 if (!getDolGlobalString('STOCK_SUPPORTS_SERVICES')) {
4405 $qualified_for_stock_change = $object->hasProductsOrServices(2);
4406 } else {
4407 $qualified_for_stock_change = $object->hasProductsOrServices(1);
4408 }
4409
4410 if ($qualified_for_stock_change) {
4411 $langs->load("stocks");
4412 require_once DOL_DOCUMENT_ROOT.'/product/class/html.formproduct.class.php';
4413 require_once DOL_DOCUMENT_ROOT.'/product/stock/class/entrepot.class.php';
4414 $formproduct = new FormProduct($db);
4415 $warehouse = new Entrepot($db);
4416 $warehouse_array = $warehouse->list_array();
4417 if (count($warehouse_array) == 1) {
4418 $label = $object->type == Facture::TYPE_CREDIT_NOTE ? $langs->trans("WarehouseForStockIncrease", current($warehouse_array)) : $langs->trans("WarehouseForStockDecrease", current($warehouse_array));
4419 $value = '<input type="hidden" id="idwarehouse" name="idwarehouse" value="'.key($warehouse_array).'">';
4420 } else {
4421 $label = $object->type == Facture::TYPE_CREDIT_NOTE ? $langs->trans("SelectWarehouseForStockIncrease") : $langs->trans("SelectWarehouseForStockDecrease");
4422 $value = $formproduct->selectWarehouses(GETPOST('idwarehouse') ? GETPOST('idwarehouse') : 'ifone', 'idwarehouse', '', 1);
4423 }
4424 $formquestion = array(
4425 // 'text' => $langs->trans("ConfirmClone"),
4426 // array('type' => 'checkbox', 'name' => 'clone_content', 'label' => $langs->trans("CloneMainAttributes"), 'value' =>
4427 // 1),
4428 // array('type' => 'checkbox', 'name' => 'update_prices', 'label' => $langs->trans("PuttingPricesUpToDate"), 'value'
4429 // => 1),
4430 array('type' => 'other', 'name' => 'idwarehouse', 'label' => $label, 'value' => $value));
4431 }
4432 }
4433 if ($object->type != Facture::TYPE_CREDIT_NOTE && $object->total_ttc < 0) { // Can happen only if getDolGlobalString('FACTURE_ENABLE_NEGATIVE') is on
4434 $text .= '<br>'.img_warning().' '.$langs->trans("ErrorInvoiceOfThisTypeMustBePositive");
4435 }
4436
4437 // mandatoryPeriod
4438 $nbMandated = 0;
4439 foreach ($object->lines as $line) {
4440 $res = $line->fetch_product();
4441 if ($res > 0) {
4442 if ($line->product->isService() && $line->product->isMandatoryPeriod() && (empty($line->date_start) || empty($line->date_end))) {
4443 $nbMandated++;
4444 break;
4445 }
4446 }
4447 }
4448 if ($nbMandated > 0) {
4449 if (getDolGlobalString('SERVICE_STRICT_MANDATORY_PERIOD')) {
4450 setEventMessages($langs->trans("mandatoryPeriodNeedTobeSetMsgValidate"), null, 'errors');
4451 $error++;
4452 } else {
4453 $text .= '<div><span class="clearboth nowraponall warning">'.img_warning().$langs->trans("mandatoryPeriodNeedTobeSetMsgValidate").'</span></div>';
4454 }
4455 }
4456
4457 if (!$error) {
4458 $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);
4459 }
4460 }
4461
4462 // Confirm back to draft status
4463 if ($action == 'modif') {
4464 $text = $langs->trans('ConfirmUnvalidateBill', $object->ref);
4465 $formquestion = array();
4466
4467 if ($object->type != Facture::TYPE_DEPOSIT && getDolGlobalString('STOCK_CALCULATE_ON_BILL')) {
4468 $qualified_for_stock_change = 0;
4469 if (!getDolGlobalString('STOCK_SUPPORTS_SERVICES')) {
4470 $qualified_for_stock_change = $object->hasProductsOrServices(2);
4471 } else {
4472 $qualified_for_stock_change = $object->hasProductsOrServices(1);
4473 }
4474
4475 if ($qualified_for_stock_change) {
4476 $langs->load("stocks");
4477 require_once DOL_DOCUMENT_ROOT.'/product/class/html.formproduct.class.php';
4478 require_once DOL_DOCUMENT_ROOT.'/product/stock/class/entrepot.class.php';
4479 $formproduct = new FormProduct($db);
4480 $warehouse = new Entrepot($db);
4481 $warehouse_array = $warehouse->list_array();
4482 if (count($warehouse_array) == 1) {
4483 $label = $object->type == Facture::TYPE_CREDIT_NOTE ? $langs->trans("WarehouseForStockDecrease", current($warehouse_array)) : $langs->trans("WarehouseForStockIncrease", current($warehouse_array));
4484 $value = '<input type="hidden" id="idwarehouse" name="idwarehouse" value="'.key($warehouse_array).'">';
4485 } else {
4486 $label = $object->type == Facture::TYPE_CREDIT_NOTE ? $langs->trans("SelectWarehouseForStockDecrease") : $langs->trans("SelectWarehouseForStockIncrease");
4487 $value = $formproduct->selectWarehouses(GETPOST('idwarehouse') ? GETPOST('idwarehouse') : 'ifone', 'idwarehouse', '', 1);
4488 }
4489 $formquestion = array(
4490 // 'text' => $langs->trans("ConfirmClone"),
4491 // array('type' => 'checkbox', 'name' => 'clone_content', 'label' => $langs->trans("CloneMainAttributes"), 'value' =>
4492 // 1),
4493 // array('type' => 'checkbox', 'name' => 'update_prices', 'label' => $langs->trans("PuttingPricesUpToDate"), 'value'
4494 // => 1),
4495 array('type' => 'other', 'name' => 'idwarehouse', 'label' => $label, 'value' => $value));
4496 }
4497 }
4498
4499 $formconfirm = $form->formconfirm($_SERVER["PHP_SELF"].'?facid='.$object->id, $langs->trans('UnvalidateBill'), $text, 'confirm_modif', $formquestion, "yes", 1);
4500 }
4501
4502 // Confirmation of payment classification
4503 if ($action == 'paid' && ($resteapayer <= 0 || (getDolGlobalString('INVOICE_CAN_SET_PAID_EVEN_IF_PARTIALLY_PAID') && $resteapayer == $object->total_ttc))) {
4504 $formconfirm = $form->formconfirm($_SERVER["PHP_SELF"].'?facid='.$object->id, $langs->trans('ClassifyPaid'), $langs->trans('ConfirmClassifyPaidBill', $object->ref), 'confirm_paid', '', "yes", 1);
4505 }
4506 if ($action == 'paid' && $resteapayer > 0 && (!getDolGlobalString('INVOICE_CAN_SET_PAID_EVEN_IF_PARTIALLY_PAID') || $resteapayer != $object->total_ttc)) {
4507 $close = array();
4508 // Code
4509 $i = 0;
4510 $close[$i]['code'] = 'discount_vat'; // escompte
4511 $i++;
4512 $close[$i]['code'] = 'badcustomer';
4513 $i++;
4514 $close[$i]['code'] = 'bankcharge';
4515 $i++;
4516 $close[$i]['code'] = 'withholdingtax';
4517 $i++;
4518 $close[$i]['code'] = 'other';
4519 $i++;
4520 // Help
4521 $i = 0;
4522 $close[$i]['label'] = $langs->trans("HelpEscompte").'<br><br>'.$langs->trans("ConfirmClassifyPaidPartiallyReasonDiscountVatDesc");
4523 $i++;
4524 $close[$i]['label'] = $langs->trans("ConfirmClassifyPaidPartiallyReasonBadCustomerDesc");
4525 $i++;
4526 $close[$i]['label'] = $langs->trans("ConfirmClassifyPaidPartiallyReasonBankChargeDesc");
4527 $i++;
4528 $close[$i]['label'] = $langs->trans("ConfirmClassifyPaidPartiallyReasonWithholdingTaxDesc");
4529 $i++;
4530 $close[$i]['label'] = $langs->trans("Other");
4531 $i++;
4532 // Texte
4533 $i = 0;
4534 $close[$i]['reason'] = $form->textwithpicto($langs->transnoentities("ConfirmClassifyPaidPartiallyReasonDiscount", $resteapayer, $langs->trans("Currency".$conf->currency)), $close[$i]['label'], 1);
4535 $i++;
4536 $close[$i]['reason'] = $form->textwithpicto($langs->transnoentities("ConfirmClassifyPaidPartiallyReasonBadCustomer", $resteapayer, $langs->trans("Currency".$conf->currency)), $close[$i]['label'], 1);
4537 $i++;
4538 $close[$i]['reason'] = $form->textwithpicto($langs->transnoentities("ConfirmClassifyPaidPartiallyReasonBankCharge", $resteapayer, $langs->trans("Currency".$conf->currency)), $close[$i]['label'], 1);
4539 $i++;
4540 $close[$i]['reason'] = $form->textwithpicto($langs->transnoentities("ConfirmClassifyPaidPartiallyReasonWithholdingTax"), $close[$i]['label'], 1);
4541 $i++;
4542 $close[$i]['reason'] = $form->textwithpicto($langs->transnoentities("Other"), $close[$i]['label'], 1);
4543 $i++;
4544 // arrayreasons[code]=reason
4545 $arrayreasons = [];
4546 foreach ($close as $key => $val) {
4547 $arrayreasons[$close[$key]['code']] = $close[$key]['reason'];
4548 }
4549
4550 // Create a form table
4551 $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'));
4552 // Incomplete payment. We ask if reason = discount or other
4553 $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);
4554 }
4555
4556 // Confirmation of status abandoned
4557 if ($action == 'canceled') {
4558 // If there is a replacement invoice not yet validated (draft state),
4559 // it is not allowed to classify the invoice as abandoned.
4560 if ($objectidnext) {
4561 $facturereplacement = new Facture($db);
4562 $facturereplacement->fetch($objectidnext);
4563 $statusreplacement = $facturereplacement->status;
4564 }
4565 if ($objectidnext && $statusreplacement == 0) {
4566 print '<div class="error">'.$langs->trans("ErrorCantCancelIfReplacementInvoiceNotValidated").'</div>';
4567 } else {
4568 // Code
4569 $close[1]['code'] = 'badcustomer';
4570 $close[2]['code'] = 'abandon';
4571 // Help
4572 $close[1]['label'] = $langs->trans("ConfirmClassifyPaidPartiallyReasonBadCustomerDesc");
4573 $close[2]['label'] = $langs->trans("ConfirmClassifyAbandonReasonOtherDesc");
4574 // Text
4575 $close[1]['reason'] = $form->textwithpicto($langs->transnoentities("ConfirmClassifyPaidPartiallyReasonBadCustomer", $object->ref), $close[1]['label'], 1);
4576 $close[2]['reason'] = $form->textwithpicto($langs->transnoentities("ConfirmClassifyAbandonReasonOther"), $close[2]['label'], 1);
4577 // arrayreasons
4578 $arrayreasons = [];
4579 $arrayreasons[$close[1]['code']] = $close[1]['reason'];
4580 $arrayreasons[$close[2]['code']] = $close[2]['reason'];
4581
4582 // Create a form table
4583 $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'));
4584
4585 $formconfirm = $form->formconfirm($_SERVER['PHP_SELF'].'?facid='.$object->id, $langs->trans('CancelBill'), $langs->trans('ConfirmCancelBill', $object->ref), 'confirm_canceled', $formquestion, "yes", 1, 270);
4586 }
4587 }
4588
4589 if ($action == 'deletepayment') {
4590 $payment_id = GETPOST('paiement_id');
4591 $formconfirm = $form->formconfirm($_SERVER["PHP_SELF"].'?id='.$object->id.'&paiement_id='.$payment_id, $langs->trans('DeletePayment'), $langs->trans('ConfirmDeletePayment'), 'confirm_delete_paiement', '', 'no', 1);
4592 }
4593
4594 // Confirmation de la suppression d'une ligne produit
4595 if ($action == 'ask_deleteline') {
4596 $formconfirm = $form->formconfirm($_SERVER["PHP_SELF"].'?facid='.$object->id.'&lineid='.$lineid, $langs->trans('DeleteProductLine'), $langs->trans('ConfirmDeleteProductLine'), 'confirm_deleteline', '', 'no', 1);
4597 }
4598
4599 // Clone confirmation
4600 if ($action == 'clone') {
4601 $filter = '(s.client:IN:1,2,3)';
4602 // Create an array for form
4603 $formquestion = array(
4604 array('type' => 'other', 'name' => 'socid', 'label' => $langs->trans("SelectThirdParty"), 'value' => $form->select_company($object->socid, 'socid', $filter, 1)),
4605 array('type' => 'date', 'name' => 'newdate', 'label' => $langs->trans("Date"), 'value' => dol_now())
4606 );
4607 // Request confirmation to clone
4608 $formconfirm = $form->formconfirm($_SERVER["PHP_SELF"].'?facid='.$object->id, $langs->trans('ToClone'), $langs->trans('ConfirmCloneInvoice', $object->ref), 'confirm_clone', $formquestion, 'yes', 1, 250);
4609 }
4610
4611 if ($action == "remove_file_comfirm") {
4612 $file = GETPOST('file', 'alpha');
4613
4614 $formconfirm = $form->formconfirm(
4615 $_SERVER["PHP_SELF"].'?facid='.$object->id.'&file='.urlencode($file),
4616 $langs->trans('DeleteFileHeader'),
4617 $langs->trans('DeleteFileText')."<br><br>".$file,
4618 'remove_file',
4619 '',
4620 'no',
4621 1
4622 );
4623 }
4624
4625 // Call Hook formConfirm
4626 $parameters = array('formConfirm' => $formconfirm, 'lineid' => $lineid, 'remainingtopay' => &$resteapayer);
4627 $reshook = $hookmanager->executeHooks('formConfirm', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
4628 if (empty($reshook)) {
4629 $formconfirm .= $hookmanager->resPrint;
4630 } elseif ($reshook > 0) {
4631 $formconfirm = $hookmanager->resPrint;
4632 }
4633
4634 // Print form confirm
4635 print $formconfirm;
4636
4637 // Invoice content
4638
4639 $linkback = '<a href="'.DOL_URL_ROOT.'/compta/facture/list.php?restore_lastsearch_values=1'.(!empty($socid) ? '&socid='.$socid : '').'">'.$langs->trans("BackToList").'</a>';
4640
4641 $morehtmlref = '<div class="refidno">';
4642 // Ref invoice
4643 if ($object->status == $object::STATUS_DRAFT && !$mysoc->isInEEC() && getDolGlobalString('INVOICE_ALLOW_FREE_REF')) {
4644 $morehtmlref .= $form->editfieldkey("Ref", 'ref', $object->ref, $object, $usercancreate, 'string', '', 0, 1);
4645 $morehtmlref .= $form->editfieldval("Ref", 'ref', $object->ref, $object, $usercancreate, 'string', '', null, null, '', 1);
4646 $morehtmlref .= '<br>';
4647 }
4648 // Ref customer
4649 $morehtmlref .= $form->editfieldkey("RefCustomer", 'ref_client', $object->ref_customer, $object, $usercancreate, 'string', '', 0, 1);
4650 $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);
4651 // Thirdparty
4652 $morehtmlref .= '<br>'.$object->thirdparty->getNomUrl(1, 'customer');
4653 if (!getDolGlobalString('MAIN_DISABLE_OTHER_LINK') && $object->thirdparty->id > 0) {
4654 $morehtmlref .= ' (<a href="'.DOL_URL_ROOT.'/compta/facture/list.php?socid='.$object->thirdparty->id.'&search_societe='.urlencode($object->thirdparty->name).'">'.$langs->trans("OtherBills").'</a>)';
4655 }
4656 // Project
4657 if (isModEnabled('project')) {
4658 $langs->load("projects");
4659 $morehtmlref .= '<br>';
4660 if ($usercancreate) {
4661 $morehtmlref .= img_picto($langs->trans("Project"), 'project', 'class="pictofixedwidth"');
4662 if ($action != 'classify') {
4663 $morehtmlref .= '<a class="editfielda" href="'.$_SERVER['PHP_SELF'].'?action=classify&token='.newToken().'&id='.$object->id.'">'.img_edit($langs->transnoentitiesnoconv('SetProject')).'</a> ';
4664 }
4665 $morehtmlref .= $form->form_project($_SERVER['PHP_SELF'].'?id='.$object->id, $object->socid, $object->fk_project, ($action == 'classify' ? 'projectid' : 'none'), 0, 0, 0, 1, '', 'maxwidth300');
4666 } else {
4667 if (!empty($object->fk_project)) {
4668 $proj = new Project($db);
4669 $proj->fetch($object->fk_project);
4670 $morehtmlref .= $proj->getNomUrl(1);
4671 if ($proj->title) {
4672 $morehtmlref .= '<span class="opacitymedium"> - '.dol_escape_htmltag($proj->title).'</span>';
4673 }
4674 }
4675 }
4676 }
4677 $morehtmlref .= '</div>';
4678
4679 $object->totalpaid = $totalpaid; // To give a chance to dol_banner_tab to use already paid amount to show correct status
4680 $object->totalcreditnotes = $totalcreditnotes;
4681 $object->totaldeposits = $totaldeposits;
4682 $object->remaintopay = price2num($object->total_ttc - $object->totalpaid - $object->totalcreditnotes - $object->totaldeposits, 'MT');
4683
4684 dol_banner_tab($object, 'ref', $linkback, 1, 'ref', 'ref', $morehtmlref, '', 0, '', '');
4685
4686 // Call Hook tabContentViewInvoice
4687 $parameters = array();
4688 // Note that $action and $object may be modified by hook
4689 $reshook = $hookmanager->executeHooks('tabContentViewInvoice', $parameters, $object, $action);
4690 if (empty($reshook)) {
4691 print '<div class="fichecenter">';
4692 print '<div class="fichehalfleft">';
4693 print '<div class="underbanner clearboth"></div>';
4694
4695 print '<table class="border centpercent tableforfield">';
4696
4697 // Type
4698 print '<tr><td class="fieldname_type">'.$langs->trans('Type').'</td><td class="valuefield fieldname_type">';
4699 print $object->getLibType(2);
4700 if ($object->subtype > 0) {
4701 print ' '.$object->getSubtypeLabel('facture');
4702 }
4703 if ($object->module_source) {
4704 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>';
4705 }
4706 if ($object->type == Facture::TYPE_REPLACEMENT) {
4707 $facreplaced = new Facture($db);
4708 $facreplaced->fetch($object->fk_facture_source);
4709 print ' <span class="opacitymediumbycolor paddingleft">'.$langs->transnoentities("ReplaceInvoice", $facreplaced->getNomUrl(1, '', 32)).'</span>';
4710 }
4711 if ($object->type == Facture::TYPE_CREDIT_NOTE && !empty($object->fk_facture_source)) {
4712 $facusing = new Facture($db);
4713 $facusing->fetch($object->fk_facture_source);
4714 print ' <span class="opacitymediumbycolor paddingleft">'.$langs->transnoentities("CorrectInvoice", $facusing->getNomUrl(1, '', 32)).'</span>';
4715 }
4716
4717 $facidavoir = $object->getListIdAvoirFromInvoice();
4718 if (count($facidavoir) > 0) {
4719 print ' <span class="opacitymediumbycolor paddingleft">'.$langs->transnoentities("InvoiceHasAvoir");
4720 $i = 0;
4721 foreach ($facidavoir as $id) {
4722 if ($i == 0) {
4723 print ' ';
4724 } else {
4725 print ',';
4726 }
4727 $facavoir = new Facture($db);
4728 $facavoir->fetch($id);
4729 print $facavoir->getNomUrl(1, '', 32);
4730 }
4731 print '</span>';
4732 }
4733 if ($objectidnext > 0) {
4734 $facthatreplace = new Facture($db);
4735 $facthatreplace->fetch($objectidnext);
4736 print ' <span class="opacitymediumbycolor paddingleft">'.str_replace('{s1}', $facthatreplace->getNomUrl(1), $langs->transnoentities("ReplacedByInvoice", '{s1}')).'</span>';
4737 }
4738
4740 $discount = new DiscountAbsolute($db);
4741 $result = $discount->fetch(0, $object->id);
4742 if ($result > 0) {
4743 print ' <span class="opacitymediumbycolor paddingleft">';
4744 $s = $langs->trans("CreditNoteConvertedIntoDiscount", '{s1}', '{s2}');
4745 $s = str_replace('{s1}', $object->getLibType(0), $s);
4746 $s = str_replace('{s2}', $discount->getNomUrl(1, 'discount'), $s);
4747 print $s;
4748 print '</span><br>';
4749 }
4750 }
4751
4752 if ($object->fk_fac_rec_source > 0) {
4753 $tmptemplate = new FactureRec($db);
4754 $result = $tmptemplate->fetch($object->fk_fac_rec_source);
4755 if ($result > 0) {
4756 print ' <span class="opacitymediumbycolor paddingleft">';
4757 $s = $langs->transnoentities("GeneratedFromTemplate", '{s1}');
4758 $s = str_replace('{s1}', $tmptemplate->getNomUrl(1, '', 32), $s);
4759 print $s;
4760 print '</span>';
4761 }
4762 }
4763 print '</td></tr>';
4764
4765 // Relative and absolute discounts
4766 print '<!-- Discounts -->'."\n";
4767 print '<tr><td>'.$langs->trans('DiscountStillRemaining').'</td>';
4768 print '<td>';
4769 $thirdparty = $soc;
4770 $discount_type = 0;
4771 $backtopage = $_SERVER["PHP_SELF"].'?facid='.$object->id;
4772 include DOL_DOCUMENT_ROOT.'/core/tpl/object_discounts.tpl.php';
4773 print '</td></tr>';
4774
4775 // Date invoice
4776 print '<tr><td>';
4777 print '<table class="nobordernopadding centpercent"><tr><td>';
4778 print $langs->trans('DateInvoice');
4779 print '</td>';
4780 if ($action != 'editinvoicedate' && $object->status == $object::STATUS_DRAFT && $usercancreate && !getDolGlobalString('FAC_FORCE_DATE_VALIDATION')) {
4781 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>';
4782 }
4783 print '</tr></table>';
4784 print '</td><td>';
4785
4786 if ($action == 'editinvoicedate') {
4787 $form->form_date($_SERVER['PHP_SELF'].'?facid='.$object->id, $object->date, 'invoicedate');
4788 } else {
4789 print '<span class="valuedate">'.dol_print_date($object->date, 'day').'</span>';
4790 }
4791 print '</td>';
4792
4793 print '</tr>';
4794
4795 if (getDolGlobalString('INVOICE_POINTOFTAX_DATE')) {
4796 // Date invoice point of tax
4797 print '<tr><td>';
4798 print '<table class="nobordernopadding centpercent"><tr><td>';
4799 print $langs->trans('DatePointOfTax');
4800 print '</td>';
4801 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>';
4802 print '</tr></table>';
4803 print '</td><td>';
4804 if ($action == 'editdate_pointoftax') {
4805 $form->form_date($_SERVER['PHP_SELF'].'?facid='.$object->id, $object->date_pointoftax, 'date_pointoftax');
4806 } else {
4807 print '<span class="valuedate">'.dol_print_date($object->date_pointoftax, 'day').'</span>';
4808 }
4809 print '</td></tr>';
4810 }
4811
4812 // Payment term
4813 print '<tr><td>';
4814 print '<table class="nobordernopadding centpercent"><tr><td>';
4815 print $langs->trans('PaymentConditionsShort');
4816 print '</td>';
4817 if ($object->type != Facture::TYPE_CREDIT_NOTE && $action != 'editconditions' && $usercancreate) {
4818 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>';
4819 }
4820 print '</tr></table>';
4821 print '</td><td>';
4822 if ($object->type != Facture::TYPE_CREDIT_NOTE) {
4823 if ($action == 'editconditions') {
4824 $form->form_conditions_reglement($_SERVER['PHP_SELF'].'?facid='.$object->id, $object->cond_reglement_id, 'cond_reglement_id');
4825 } else {
4826 $form->form_conditions_reglement($_SERVER['PHP_SELF'].'?facid='.$object->id, $object->cond_reglement_id, 'none');
4827 }
4828 } else {
4829 print '&nbsp;';
4830 }
4831 print '</td></tr>';
4832
4833 // Date payment term
4834 print '<tr><td>';
4835 print '<table class="nobordernopadding centpercent"><tr><td>';
4836 print $langs->trans('DateMaxPayment');
4837 print '</td>';
4838 if ($object->type != Facture::TYPE_CREDIT_NOTE && $action != 'editpaymentterm' && $usercancreate) {
4839 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>';
4840 }
4841 print '</tr></table>';
4842 print '</td><td>';
4843 if ($object->type != Facture::TYPE_CREDIT_NOTE) {
4844 if ($action == 'editpaymentterm') {
4845 $form->form_date($_SERVER['PHP_SELF'].'?facid='.$object->id, $object->date_lim_reglement, 'paymentterm');
4846 } else {
4847 print '<span class="valuedate">'.dol_print_date($object->date_lim_reglement, 'day').'</span>';
4848 if ($object->hasDelay()) {
4849 print img_warning($langs->trans('Late'));
4850 }
4851 }
4852 } else {
4853 print '&nbsp;';
4854 }
4855 print '</td></tr>';
4856
4857 // Payment mode
4858 print '<tr><td>';
4859 print '<table class="nobordernopadding centpercent"><tr><td>';
4860 print $langs->trans('PaymentMode');
4861 print '</td>';
4862 if ($action != 'editmode' && $usercancreate) {
4863 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>';
4864 }
4865 print '</tr></table>';
4866 print '</td><td>';
4867 if ($action == 'editmode') {
4868 $form->form_modes_reglement($_SERVER['PHP_SELF'].'?facid='.$object->id, $object->mode_reglement_id, 'mode_reglement_id', 'CRDT', 1, 1);
4869 } else {
4870 $form->form_modes_reglement($_SERVER['PHP_SELF'].'?facid='.$object->id, $object->mode_reglement_id, 'none', 'CRDT');
4871 }
4872 print '</td></tr>';
4873
4874 // Multicurrency
4875 if (isModEnabled('multicurrency')) {
4876 // Multicurrency code
4877 print '<tr>';
4878 print '<td>';
4879 print '<table class="nobordernopadding centpercent"><tr><td>';
4880 print $form->editfieldkey('Currency', 'multicurrency_code', '', $object, 0);
4881 print '</td>';
4882 if ($usercancreate && $action != 'editmulticurrencycode' && $object->status == $object::STATUS_DRAFT) {
4883 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>';
4884 }
4885 print '</tr></table>';
4886 print '</td><td>';
4887 $htmlname = (($usercancreate && $action == 'editmulticurrencycode') ? 'multicurrency_code' : 'none');
4888 $form->form_multicurrency_code($_SERVER['PHP_SELF'].'?id='.$object->id, $object->multicurrency_code, $htmlname);
4889 print '</td></tr>';
4890
4891 // Multicurrency rate
4892 if ($object->multicurrency_code != $conf->currency || $object->multicurrency_tx != 1) {
4893 print '<tr>';
4894 print '<td>';
4895 print '<table class="nobordernopadding" width="100%"><tr><td>';
4896 print $form->editfieldkey('CurrencyRate', 'multicurrency_tx', '', $object, 0);
4897 print '</td>';
4898 if ($usercancreate && $action != 'editmulticurrencyrate' && $object->status == $object::STATUS_DRAFT && $object->multicurrency_code && $object->multicurrency_code != $conf->currency) {
4899 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>';
4900 }
4901 print '</tr></table>';
4902 print '</td><td>';
4903 if ($action == 'editmulticurrencyrate' || $action == 'actualizemulticurrencyrate') {
4904 if ($action == 'actualizemulticurrencyrate') {
4905 list($object->fk_multicurrency, $object->multicurrency_tx) = MultiCurrency::getIdAndTxFromCode($object->db, $object->multicurrency_code);
4906 }
4907 $form->form_multicurrency_rate($_SERVER['PHP_SELF'].'?id='.$object->id, $object->multicurrency_tx, ($usercancreate ? 'multicurrency_tx' : 'none'), $object->multicurrency_code);
4908 } else {
4909 $form->form_multicurrency_rate($_SERVER['PHP_SELF'].'?id='.$object->id, $object->multicurrency_tx, 'none', $object->multicurrency_code);
4910 if ($object->status == $object::STATUS_DRAFT && $object->multicurrency_code && $object->multicurrency_code != $conf->currency) {
4911 print '<div class="inline-block"> &nbsp; &nbsp; &nbsp; &nbsp; ';
4912 print '<a href="'.$_SERVER["PHP_SELF"].'?id='.$object->id.'&action=actualizemulticurrencyrate">'.$langs->trans("ActualizeCurrency").'</a>';
4913 print '</div>';
4914 }
4915 }
4916 print '</td></tr>';
4917 }
4918 }
4919
4920 // Bank Account
4921 if (isModEnabled("bank")) {
4922 print '<tr><td class="nowrap">';
4923 print '<table class="nobordernopadding centpercent"><tr><td class="nowrap">';
4924 print $langs->trans('BankAccount');
4925 print '<td>';
4926 if (($action != 'editbankaccount') && $usercancreate) {
4927 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>';
4928 }
4929 print '</tr></table>';
4930 print '</td><td>';
4931 if ($action == 'editbankaccount') {
4932 $form->formSelectAccount($_SERVER['PHP_SELF'].'?id='.$object->id, $object->fk_account, 'fk_account', 1);
4933 } else {
4934 $form->formSelectAccount($_SERVER['PHP_SELF'].'?id='.$object->id, $object->fk_account, 'none');
4935 }
4936 print "</td>";
4937 print '</tr>';
4938 }
4939
4940 // Incoterms
4941 if (isModEnabled('incoterm')) {
4942 print '<tr><td>';
4943 print '<table class="nobordernopadding centpercent"><tr><td>';
4944 print $langs->trans('IncotermLabel');
4945 print '<td><td class="right">';
4946 if ($usercancreate) {
4947 print '<a class="editfielda" href="'.DOL_URL_ROOT.'/compta/facture/card.php?facid='.$object->id.'&action=editincoterm&token='.newToken().'">'.img_edit().'</a>';
4948 } else {
4949 print '&nbsp;';
4950 }
4951 print '</td></tr></table>';
4952 print '</td>';
4953 print '<td>';
4954 if ($action != 'editincoterm') {
4955 print $form->textwithpicto($object->display_incoterms(), $object->label_incoterms, 1);
4956 } else {
4957 print $form->select_incoterms((!empty($object->fk_incoterms) ? $object->fk_incoterms : ''), (!empty($object->location_incoterms) ? $object->location_incoterms : ''), $_SERVER['PHP_SELF'].'?id='.$object->id);
4958 }
4959 print '</td></tr>';
4960 }
4961
4962
4963
4964 if (!empty($object->retained_warranty) || getDolGlobalString('INVOICE_USE_RETAINED_WARRANTY')) {
4965 $displayWarranty = true;
4966 if (!in_array($object->type, $retainedWarrantyInvoiceAvailableType) && empty($object->retained_warranty)) {
4967 $displayWarranty = false;
4968 }
4969
4970 if ($displayWarranty) {
4971 // Retained Warranty
4972 print '<tr class="retained-warranty-lines" ><td>';
4973 print '<table id="retained-warranty-table" class="nobordernopadding centpercent"><tr><td>';
4974 print $langs->trans('RetainedWarranty');
4975 print '</td>';
4976 if ($action != 'editretainedwarranty' && $user->hasRight('facture', 'creer') && $object->status == Facture::STATUS_DRAFT) {
4977 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>';
4978 }
4979
4980 print '</tr></table>';
4981 print '</td><td>';
4982 if ($action == 'editretainedwarranty' && $object->status == Facture::STATUS_DRAFT) {
4983 print '<form id="retained-warranty-form" method="POST" action="'.$_SERVER['PHP_SELF'].'?facid='.$object->id.'">';
4984 print '<input type="hidden" name="action" value="setretainedwarranty">';
4985 print '<input type="hidden" name="token" value="'.newToken().'">';
4986 print '<input type="hidden" name="backtopage" value="'.$backtopage.'">';
4987 print '<input name="retained_warranty" type="number" step="0.01" min="0" max="100" value="'.$object->retained_warranty.'" >';
4988 print '<input type="submit" class="button valignmiddle smallpaddingimp" value="'.$langs->trans("Modify").'">';
4989 print '</form>';
4990 } else {
4991 print price($object->retained_warranty).'%';
4992 }
4993 print '</td></tr>';
4994
4995 // Retained warranty payment term
4996 print '<tr class="retained-warranty-lines" ><td>';
4997 print '<table id="retained-warranty-cond-reglement-table" class="nobordernopadding" width="100%"><tr><td>';
4998 print $langs->trans('PaymentConditionsShortRetainedWarranty');
4999 print '</td>';
5000 if ($action != 'editretainedwarrantypaymentterms' && $user->hasRight('facture', 'creer') && $object->status == Facture::STATUS_DRAFT) {
5001 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>';
5002 }
5003
5004 print '</tr></table>';
5005 print '</td><td>';
5006 $defaultDate = !empty($object->retained_warranty_date_limit) ? $object->retained_warranty_date_limit : strtotime('-1 years', $object->date_lim_reglement);
5007 if ($object->date > $defaultDate) {
5008 $defaultDate = $object->date;
5009 }
5010
5011 if ($action == 'editretainedwarrantypaymentterms' && $object->status == Facture::STATUS_DRAFT) {
5012 //date('Y-m-d',$object->date_lim_reglement)
5013 print '<form method="POST" action="'.$_SERVER['PHP_SELF'].'?facid='.$object->id.'">';
5014 print '<input type="hidden" name="action" value="setretainedwarrantyconditions">';
5015 print '<input type="hidden" name="token" value="'.newToken().'">';
5016 print '<input type="hidden" name="backtopage" value="'.$backtopage.'">';
5017 $retained_warranty_fk_cond_reglement = GETPOSTINT('retained_warranty_fk_cond_reglement');
5018 $retained_warranty_fk_cond_reglement = !empty($retained_warranty_fk_cond_reglement) ? $retained_warranty_fk_cond_reglement : $object->retained_warranty_fk_cond_reglement;
5019 $retained_warranty_fk_cond_reglement = !empty($retained_warranty_fk_cond_reglement) ? $retained_warranty_fk_cond_reglement : getDolGlobalString('INVOICE_SITUATION_DEFAULT_RETAINED_WARRANTY_COND_ID');
5020 print $form->getSelectConditionsPaiements($retained_warranty_fk_cond_reglement, 'retained_warranty_fk_cond_reglement', -1, 1);
5021 print '<input type="submit" class="button valignmiddle" value="'.$langs->trans("Modify").'">';
5022 print '</form>';
5023 } else {
5024 $form->form_conditions_reglement($_SERVER['PHP_SELF'].'?facid='.$object->id, $object->retained_warranty_fk_cond_reglement, 'none');
5025 if (!$displayWarranty) {
5026 print img_picto($langs->trans('RetainedWarrantyNeed100Percent'), 'warning.png', 'class="pictowarning valignmiddle" ');
5027 }
5028 }
5029 print '</td></tr>';
5030
5031 // Retained Warranty payment date limit
5032 print '<tr class="retained-warranty-lines" ><td>';
5033 print '<table id="retained-warranty-date-limit-table" class="nobordernopadding" width="100%"><tr><td>';
5034 print $langs->trans('RetainedWarrantyDateLimit');
5035 print '</td>';
5036 if ($action != 'editretainedwarrantydatelimit' && $user->hasRight('facture', 'creer') && $object->status == Facture::STATUS_DRAFT) {
5037 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>';
5038 }
5039
5040 print '</tr></table>';
5041 print '</td><td>';
5042 $defaultDate = !empty($object->retained_warranty_date_limit) ? $object->retained_warranty_date_limit : strtotime('-1 years', $object->date_lim_reglement);
5043 if ($object->date > $defaultDate) {
5044 $defaultDate = $object->date;
5045 }
5046
5047 if ($action == 'editretainedwarrantydatelimit' && $object->status == Facture::STATUS_DRAFT) {
5048 //date('Y-m-d',$object->date_lim_reglement)
5049 print '<form method="POST" action="'.$_SERVER['PHP_SELF'].'?facid='.$object->id.'">';
5050 print '<input type="hidden" name="action" value="setretainedwarrantydatelimit">';
5051 print '<input type="hidden" name="token" value="'.newToken().'">';
5052 print '<input type="hidden" name="backtopage" value="'.$backtopage.'">';
5053 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').'" >';
5054 print '<input type="submit" class="button valignmiddle" value="'.$langs->trans("Modify").'">';
5055 print '</form>';
5056 } else {
5057 print dol_print_date($object->retained_warranty_date_limit, 'day');
5058 }
5059 print '</td></tr>';
5060 }
5061 }
5062
5063
5064 // Other attributes
5065 $cols = 2;
5066 include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_view.tpl.php';
5067
5068 print '</table>';
5069
5070 print '</div>';
5071 print '<div class="fichehalfright">';
5072
5073 print '<!-- amounts -->'."\n";
5074 print '<div class="underbanner clearboth"></div>'."\n";
5075
5076 print '<table class="border tableforfield centpercent">';
5077
5078 $sign = 1;
5079 if (getDolGlobalString('INVOICE_POSITIVE_CREDIT_NOTE_SCREEN') && $object->type == $object::TYPE_CREDIT_NOTE) {
5080 $sign = -1; // We invert sign for output
5081 }
5082 print '<tr>';
5083 // Amount HT
5084 print '<td class="titlefieldmiddle">' . $langs->trans('AmountHT') . '</td>';
5085 print '<td class="nowrap amountcard right">' . price($sign * $object->total_ht, 0, $langs, 0, -1, -1, $conf->currency) . '</td>';
5086 if (isModEnabled("multicurrency") && ($object->multicurrency_code && $object->multicurrency_code != $conf->currency)) {
5087 // Multicurrency Amount HT
5088 print '<td class="nowrap amountcard right">' . price($sign * $object->multicurrency_total_ht, 0, $langs, 0, -1, -1, $object->multicurrency_code) . '</td>';
5089 }
5090 print '</tr>';
5091
5092 print '<tr>';
5093 // Amount VAT
5094 print '<td class="titlefieldmiddle">' . $langs->trans('AmountVAT') . '</td>';
5095 print '<td class="nowrap amountcard right">' . price($sign * $object->total_tva, 0, $langs, 0, -1, -1, $conf->currency) . '</td>';
5096 if (isModEnabled("multicurrency") && ($object->multicurrency_code && $object->multicurrency_code != $conf->currency)) {
5097 // Multicurrency Amount VAT
5098 print '<td class="nowrap amountcard right">' . price($sign * $object->multicurrency_total_tva, 0, $langs, 0, -1, -1, $object->multicurrency_code) . '</td>';
5099 }
5100 print '</tr>';
5101
5102 // Amount Local Taxes
5103 if (($mysoc->localtax1_assuj == "1" && $mysoc->useLocalTax(1)) || $object->total_localtax1 != 0) {
5104 print '<tr>';
5105 print '<td class="titlefieldmiddle">' . $langs->transcountry("AmountLT1", $mysoc->country_code) . '</td>';
5106 print '<td class="nowrap amountcard right">' . price($sign * $object->total_localtax1, 0, $langs, 0, -1, -1, $conf->currency) . '</td>';
5107 if (isModEnabled("multicurrency") && ($object->multicurrency_code && $object->multicurrency_code != $conf->currency)) {
5108 $object->multicurrency_total_localtax1 = (float) price2num($object->total_localtax1 * $object->multicurrency_tx, 'MT');
5109
5110 print '<td class="nowrap amountcard right">' . price($sign * $object->multicurrency_total_localtax1, 0, $langs, 0, -1, -1, $object->multicurrency_code) . '</td>';
5111 }
5112 print '</tr>';
5113 }
5114
5115 if (($mysoc->localtax2_assuj == "1" && $mysoc->useLocalTax(2)) || $object->total_localtax2 != 0) {
5116 print '<tr>';
5117 print '<td>' . $langs->transcountry("AmountLT2", $mysoc->country_code) . '</td>';
5118 print '<td class="nowrap amountcard right">' . price($sign * $object->total_localtax2, 0, $langs, 0, -1, -1, $conf->currency) . '</td>';
5119 if (isModEnabled("multicurrency") && ($object->multicurrency_code && $object->multicurrency_code != $conf->currency)) {
5120 $object->multicurrency_total_localtax2 = (float) price2num($object->total_localtax2 * $object->multicurrency_tx, 'MT');
5121
5122 print '<td class="nowrap amountcard right">' . price($sign * $object->multicurrency_total_localtax2, 0, $langs, 0, -1, -1, $object->multicurrency_code) . '</td>';
5123 }
5124 print '</tr>';
5125 }
5126
5127 // Add the revenue stamp
5128 if ($selleruserevenustamp) {
5129 print '<tr><td class="titlefieldmiddle">';
5130 print '<table class="nobordernopadding centpercent"><tr><td>';
5131 print $langs->trans('RevenueStamp');
5132 print '</td>';
5133 if ($action != 'editrevenuestamp' && $object->status == $object::STATUS_DRAFT && $usercancreate) {
5134 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>';
5135 }
5136 print '</tr></table>';
5137 print '</td><td class="nowrap amountcard right">';
5138 if ($action == 'editrevenuestamp') {
5139 print '<form action="'.$_SERVER["PHP_SELF"].'?id='.$object->id.'" method="post">';
5140 print '<input type="hidden" name="token" value="'.newToken().'">';
5141 print '<input type="hidden" name="action" value="setrevenuestamp">';
5142 print '<input type="hidden" name="revenuestamp" id="revenuestamp_val" value="'.price2num($object->revenuestamp).'">';
5143 print '<input type="hidden" name="backtopage" value="'.$backtopage.'">';
5144 print $formother->select_revenue_stamp('', 'revenuestamp_type', $mysoc->country_code);
5145 print ' &rarr; <span id="revenuestamp_span"></span>';
5146 print ' <input type="submit" class="button buttongen button-save small" value="'.$langs->trans('Modify').'">';
5147 print '</form>';
5148 print " <script>
5149 $(document).ready(function(){
5150 js_recalculate_revenuestamp();
5151 $('select[name=revenuestamp_type]').on('change',function(){
5152 js_recalculate_revenuestamp();
5153 });
5154 });
5155 function js_recalculate_revenuestamp(){
5156 var valselected = $('select[name=revenuestamp_type]').val();
5157 console.log('Calculate revenue stamp from '+valselected);
5158 var revenue = 0;
5159 if (valselected.indexOf('%') == -1)
5160 {
5161 revenue = valselected;
5162 }
5163 else
5164 {
5165 var revenue_type = parseFloat(valselected);
5166 var amount_net = ".round($object->total_ht, 2).";
5167 revenue = revenue_type * amount_net / 100;
5168 revenue = revenue.toFixed(2);
5169 }
5170 $('#revenuestamp_val').val(revenue);
5171 $('#revenuestamp_span').html(revenue);
5172 }
5173 </script>";
5174 } else {
5175 print price($object->revenuestamp, 1, '', 1, -1, -1, $conf->currency);
5176 }
5177 print '</td></tr>';
5178 }
5179
5180 print '<tr>';
5181 // Amount TTC
5182 print '<td>' . $langs->trans('AmountTTC') . '</td>';
5183 print '<td class="nowrap amountcard right">' . price($sign * $object->total_ttc, 0, $langs, 0, -1, -1, $conf->currency) . '</td>';
5184 if (isModEnabled("multicurrency") && ($object->multicurrency_code && $object->multicurrency_code != $conf->currency)) {
5185 // Multicurrency Amount TTC
5186 print '<td class="nowrap amountcard right">' . price($sign * $object->multicurrency_total_ttc, 0, $langs, 0, -1, -1, $object->multicurrency_code) . '</td>';
5187 }
5188 print '</tr>';
5189
5190 print '</table>';
5191
5192 $nbrows = 8;
5193 $nbcols = 3;
5194 if (isModEnabled('project')) {
5195 $nbrows++;
5196 }
5197 if (isModEnabled("bank")) {
5198 $nbrows++;
5199 $nbcols++;
5200 }
5201 if ($mysoc->localtax1_assuj == "1" || $object->total_localtax1 != 0) {
5202 $nbrows++;
5203 }
5204 if ($mysoc->localtax2_assuj == "1" || $object->total_localtax2 != 0) {
5205 $nbrows++;
5206 }
5207 if ($selleruserevenustamp) {
5208 $nbrows++;
5209 }
5210 if (isModEnabled('multicurrency')) {
5211 $nbrows += 5;
5212 }
5213 if (isModEnabled('incoterm')) {
5214 $nbrows += 1;
5215 }
5216
5217 // List of previous situation invoices
5218 if (($object->situation_cycle_ref > 0) && getDolGlobalString('INVOICE_USE_SITUATION')) {
5219 print '<!-- List of situation invoices -->';
5220 print '<table class="noborder situationstable" width="100%">';
5221
5222 print '<tr class="liste_titre">';
5223 print '<td>'.$langs->trans('ListOfSituationInvoices').'</td>';
5224 print '<td></td>';
5225 print '<td class="center">'.$langs->trans('Situation').'</td>';
5226 if (isModEnabled("bank")) {
5227 print '<td class="right"></td>';
5228 }
5229 print '<td class="right">'.$langs->trans('AmountHT').'</td>';
5230 print '<td class="right">'.$langs->trans('AmountTTC').'</td>';
5231 print '<td width="18">&nbsp;</td>';
5232 print '</tr>';
5233
5234 $total_prev_ht = $total_prev_ttc = 0;
5235 $total_global_ht = $total_global_ttc = 0;
5236
5237 if (count($object->tab_previous_situation_invoice) > 0) {
5238 // List of previous invoices
5239
5240 $current_situation_counter = array();
5241 foreach ($object->tab_previous_situation_invoice as $prev_invoice) {
5242 $tmptotalpaidforthisinvoice = $prev_invoice->getSommePaiement();
5243 $total_prev_ht += $prev_invoice->total_ht;
5244 $total_prev_ttc += $prev_invoice->total_ttc;
5245 $current_situation_counter[] = (($prev_invoice->type == Facture::TYPE_CREDIT_NOTE) ? -1 : 1) * $prev_invoice->situation_counter;
5246 print '<tr class="oddeven">';
5247 print '<td>'.$prev_invoice->getNomUrl(1).'</td>';
5248 print '<td></td>';
5249 print '<td align="center" >'.(($prev_invoice->type == Facture::TYPE_CREDIT_NOTE) ? $langs->trans('situationInvoiceShortcode_AS') : $langs->trans('situationInvoiceShortcode_S')).$prev_invoice->situation_counter.'</td>';
5250 if (isModEnabled("bank")) {
5251 print '<td class="right"></td>';
5252 }
5253 print '<td class="right"><span class="amount">'.price($prev_invoice->total_ht).'</span></td>';
5254 print '<td class="right"><span class="amount">'.price($prev_invoice->total_ttc).'</span></td>';
5255 print '<td class="right">'.$prev_invoice->getLibStatut(3, $tmptotalpaidforthisinvoice).'</td>';
5256 print '</tr>';
5257 }
5258 }
5259
5260
5261 $total_global_ht += $total_prev_ht;
5262 $total_global_ttc += $total_prev_ttc;
5263 $total_global_ht += $object->total_ht;
5264 $total_global_ttc += $object->total_ttc;
5265 $current_situation_counter[] = (($object->type == Facture::TYPE_CREDIT_NOTE) ? -1 : 1) * $object->situation_counter;
5266 print '<tr class="oddeven">';
5267 print '<td>'.$object->getNomUrl(1).'</td>';
5268 print '<td></td>';
5269 print '<td class="center">'.(($object->type == Facture::TYPE_CREDIT_NOTE) ? $langs->trans('situationInvoiceShortcode_AS') : $langs->trans('situationInvoiceShortcode_S')).$object->situation_counter.'</td>';
5270 if (isModEnabled("bank")) {
5271 print '<td class="right"></td>';
5272 }
5273 print '<td class="right"><span class="amount">'.price($object->total_ht).'</span></td>';
5274 print '<td class="right"><span class="amount">'.price($object->total_ttc).'</span></td>';
5275 print '<td class="right">'.$object->getLibStatut(3, $object->getSommePaiement()).'</td>';
5276 print '</tr>';
5277
5278
5279 print '<tr class="oddeven">';
5280 print '<td colspan="2" class="left"><b>'.$langs->trans('CurrentSituationTotal').'</b></td>';
5281 print '<td>';
5282 $i = 0;
5283 foreach ($current_situation_counter as $sit) {
5284 $curSign = $sit > 0 ? '+' : '-';
5285 $curType = $sit > 0 ? $langs->trans('situationInvoiceShortcode_S') : $langs->trans('situationInvoiceShortcode_AS');
5286 if ($i > 0) {
5287 print ' '.$curSign.' ';
5288 }
5289 print $curType.abs($sit);
5290 $i++;
5291 }
5292 print '</td>';
5293 if (isModEnabled("bank")) {
5294 print '<td></td>';
5295 }
5296 print '<td class="right"><b>'.price($total_global_ht).'</b></td>';
5297 print '<td class="right"><b>'.price($total_global_ttc).'</b></td>';
5298 print '<td width="18">&nbsp;</td>';
5299 print '</tr>';
5300
5301
5302 if (count($object->tab_next_situation_invoice) > 0) {
5303 // List of next invoices
5304 /*print '<tr class="liste_titre">';
5305 print '<td>' . $langs->trans('ListOfNextSituationInvoices') . '</td>';
5306 print '<td></td>';
5307 print '<td></td>';
5308 if (isModEnabled('banque')) print '<td class="right"></td>';
5309 print '<td class="right">' . $langs->trans('AmountHT') . '</td>';
5310 print '<td class="right">' . $langs->trans('AmountTTC') . '</td>';
5311 print '<td width="18">&nbsp;</td>';
5312 print '</tr>';*/
5313
5314 $total_next_ht = $total_next_ttc = 0;
5315
5316 foreach ($object->tab_next_situation_invoice as $next_invoice) {
5317 $totalpaid = $next_invoice->getSommePaiement();
5318 $total_next_ht += $next_invoice->total_ht;
5319 $total_next_ttc += $next_invoice->total_ttc;
5320
5321 print '<tr class="oddeven">';
5322 print '<td>'.$next_invoice->getNomUrl(1).'</td>';
5323 print '<td></td>';
5324 print '<td class="center">'.(($next_invoice->type == Facture::TYPE_CREDIT_NOTE) ? $langs->trans('situationInvoiceShortcode_AS') : $langs->trans('situationInvoiceShortcode_S')).$next_invoice->situation_counter.'</td>';
5325 if (isModEnabled("bank")) {
5326 print '<td class="right"></td>';
5327 }
5328 print '<td class="right"><span class="amount">'.price($next_invoice->total_ht).'</span></td>';
5329 print '<td class="right"><span class="amount">'.price($next_invoice->total_ttc).'</span></td>';
5330 print '<td class="right">'.$next_invoice->getLibStatut(3, $totalpaid).'</td>';
5331 print '</tr>';
5332 }
5333
5334 $total_global_ht += $total_next_ht;
5335 $total_global_ttc += $total_next_ttc;
5336
5337 print '<tr class="oddeven">';
5338 print '<td colspan="3" class="right"></td>';
5339 if (isModEnabled("bank")) {
5340 print '<td class="right"></td>';
5341 }
5342 print '<td class="right"><b>'.price($total_global_ht).'</b></td>';
5343 print '<td class="right"><b>'.price($total_global_ttc).'</b></td>';
5344 print '<td width="18">&nbsp;</td>';
5345 print '</tr>';
5346 }
5347
5348 print '</table>';
5349 }
5350
5351 $sign = 1;
5352 if ($object->type == $object::TYPE_CREDIT_NOTE) {
5353 $sign = -1;
5354 }
5355
5356 // List of payments already done
5357
5358 print '<!-- List of payments already done -->';
5359 print '<div class="div-table-responsive-no-min">';
5360 print '<table class="noborder paymenttable centpercent">';
5361
5362 print '<tr class="liste_titre">';
5363 print '<td class="liste_titre">'.($object->type == Facture::TYPE_CREDIT_NOTE ? $langs->trans("PaymentsBack") : $langs->trans('Payments')).'</td>';
5364 print '<td class="liste_titre"><span class="hideonsmartphone">'.$langs->trans('Date').'</span></td>';
5365 print '<td class="liste_titre"><span class="hideonsmartphone">'.$langs->trans('Type').'</span></td>';
5366 if (isModEnabled("bank")) {
5367 print '<td class="liste_titre"><span class="hideonsmartphone">'.$langs->trans('BankAccount').'</span></td>';
5368 }
5369 print '<td class="liste_titre right">'.$langs->trans('Amount').'</td>';
5370 print '<td class="liste_titre" width="18">&nbsp;</td>';
5371 print '</tr>';
5372
5373 // Payments already done (from payment on this invoice)
5374 $sql = 'SELECT p.datep as dp, p.ref, p.num_paiement as num_payment, p.rowid, p.fk_bank,';
5375 $sql .= ' c.code as payment_code, c.libelle as payment_label,';
5376 $sql .= ' pf.amount,';
5377 $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';
5378 $sql .= ' FROM '.MAIN_DB_PREFIX.'paiement_facture as pf, '.MAIN_DB_PREFIX.'paiement as p';
5379 $sql .= ' LEFT JOIN '.MAIN_DB_PREFIX.'c_paiement as c ON p.fk_paiement = c.id';
5380 $sql .= ' LEFT JOIN '.MAIN_DB_PREFIX.'bank as b ON p.fk_bank = b.rowid';
5381 $sql .= ' LEFT JOIN '.MAIN_DB_PREFIX.'bank_account as ba ON b.fk_account = ba.rowid';
5382 $sql .= ' WHERE pf.fk_facture = '.((int) $object->id).' AND pf.fk_paiement = p.rowid';
5383 $sql .= ' AND p.entity IN ('.getEntity('invoice').')';
5384 $sql .= ' ORDER BY p.datep, p.tms';
5385
5386 $result = $db->query($sql);
5387 if ($result) {
5388 $num = $db->num_rows($result);
5389 $i = 0;
5390
5391 if ($num > 0) {
5392 while ($i < $num) {
5393 $objp = $db->fetch_object($result);
5394
5395 $paymentstatic->id = $objp->rowid;
5396 $paymentstatic->datepaye = $db->jdate($objp->dp);
5397 $paymentstatic->ref = $objp->ref;
5398 $paymentstatic->num_payment = $objp->num_payment;
5399 $paymentstatic->paiementcode = $objp->payment_code;
5400
5401 print '<tr class="oddeven"><td class="nowraponall">';
5402 print $paymentstatic->getNomUrl(1);
5403 print '</td>';
5404 print '<td>';
5405 $dateofpayment = $db->jdate($objp->dp);
5406 $tmparray = dol_getdate($dateofpayment);
5407 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
5408 print dol_print_date($dateofpayment, 'day');
5409 } else { // Hours was set to real date of payment (special case for POS for example)
5410 print dol_print_date($dateofpayment, 'dayhour', 'tzuser');
5411 }
5412 print '</td>';
5413
5414 $label = ($langs->trans("PaymentType".$objp->payment_code) != "PaymentType".$objp->payment_code) ? $langs->trans("PaymentType".$objp->payment_code) : $objp->payment_label;
5415 print '<td class="tdoverflowmax80" title="'.dol_escape_htmltag($label.' '.$objp->num_payment).'">'.dol_escape_htmltag($label.' '.$objp->num_payment).'</td>';
5416 if (isModEnabled("bank")) {
5417 $bankaccountstatic->id = $objp->baid;
5418 $bankaccountstatic->ref = $objp->baref;
5419 $bankaccountstatic->label = $objp->baref;
5420 $bankaccountstatic->number = $objp->banumber;
5421 $bankaccountstatic->currency_code = $objp->bacurrency_code;
5422
5423 if (isModEnabled('accounting')) {
5424 $bankaccountstatic->account_number = $objp->account_number;
5425
5426 $accountingjournal = new AccountingJournal($db);
5427 $accountingjournal->fetch($objp->fk_accountancy_journal);
5428 $bankaccountstatic->accountancy_journal = $accountingjournal->getNomUrl(0, 1, 1, '', 1);
5429 }
5430
5431 print '<td class="nowraponall">';
5432 if ($bankaccountstatic->id) {
5433 print $bankaccountstatic->getNomUrl(1, 'transactions');
5434 }
5435 print '</td>';
5436 }
5437 print '<td class="right"><span class="amount">'.price($sign * $objp->amount).'</span></td>';
5438 print '<td class="center">';
5439
5440 $paiement = new Paiement($db);
5441 $paiement->fetch($objp->rowid);
5442 if ($object->status == Facture::STATUS_VALIDATED && $object->paye == 0 && $user->socid == 0 && !$paiement->isReconciled()) {
5443 print '<a href="'.$_SERVER["PHP_SELF"].'?id='.$object->id.'&action=deletepayment&token='.newToken().'&paiement_id='.$objp->rowid.'">';
5444 print img_delete();
5445 print '</a>';
5446 }
5447 print '</td>';
5448 print '</tr>';
5449 $i++;
5450 }
5451 }
5452
5453 $db->free($result);
5454 } else {
5455 dol_print_error($db);
5456 }
5457
5458 if ($object->type != Facture::TYPE_CREDIT_NOTE) {
5459 // Total already paid
5460 print '<tr><td colspan="'.$nbcols.'" class="right">';
5461 print '<span class="opacitymedium">';
5462 if ($object->type != Facture::TYPE_DEPOSIT) {
5463 print $langs->trans('AlreadyPaidNoCreditNotesNoDeposits');
5464 } else {
5465 print $langs->trans('AlreadyPaid');
5466 }
5467 print '</span></td><td class="right'.(($totalpaid > 0) ? ' amountalreadypaid' : '').'">'.price($totalpaid).'</td><td>&nbsp;</td></tr>';
5468
5469 $resteapayeraffiche = $resteapayer;
5470 $cssforamountpaymentcomplete = 'amountpaymentcomplete';
5471
5472 // Loop on each credit note or deposit amount applied
5473 $creditnoteamount = 0;
5474 $depositamount = 0;
5475 $sql = "SELECT re.rowid, re.amount_ht, re.amount_tva, re.amount_ttc,";
5476 $sql .= " re.description, re.fk_facture_source";
5477 $sql .= " FROM ".MAIN_DB_PREFIX."societe_remise_except as re";
5478 $sql .= " WHERE fk_facture = ".((int) $object->id);
5479 $resql = $db->query($sql);
5480 if ($resql) {
5481 $num = $db->num_rows($resql);
5482 $i = 0;
5483 $invoice = new Facture($db);
5484 while ($i < $num) {
5485 $obj = $db->fetch_object($resql);
5486 $invoice->fetch($obj->fk_facture_source);
5487 print '<tr><td colspan="'.$nbcols.'" class="right">';
5488 print '<span class="opacitymedium">';
5489 if ($invoice->type == Facture::TYPE_CREDIT_NOTE) {
5490 print $langs->trans("CreditNote").' ';
5491 }
5492 if ($invoice->type == Facture::TYPE_DEPOSIT) {
5493 print $langs->trans("Deposit").' ';
5494 }
5495 print $invoice->getNomUrl(0);
5496 print '</span>';
5497 print '</td>';
5498 print '<td class="right"><span class="amount">'.price($obj->amount_ttc).'</span></td>';
5499 print '<td class="right">';
5500 print '<a href="'.$_SERVER["PHP_SELF"].'?facid='.$object->id.'&action=unlinkdiscount&token='.newToken().'&discountid='.$obj->rowid.'">';
5501 print img_picto($langs->transnoentitiesnoconv("RemoveDiscount"), 'unlink');
5502 print '</a>';
5503 print '</td></tr>';
5504 $i++;
5505 if ($invoice->type == Facture::TYPE_CREDIT_NOTE) {
5506 $creditnoteamount += $obj->amount_ttc;
5507 }
5508 if ($invoice->type == Facture::TYPE_DEPOSIT) {
5509 $depositamount += $obj->amount_ttc;
5510 }
5511 }
5512 } else {
5513 dol_print_error($db);
5514 }
5515
5516 // Partially paid 'discount'
5517 if (($object->status == Facture::STATUS_CLOSED || $object->status == Facture::STATUS_ABANDONED) && $object->close_code == 'discount_vat') {
5518 print '<tr><td colspan="'.$nbcols.'" class="nowrap right">';
5519 print '<span class="opacitymedium">';
5520 print $form->textwithpicto($langs->trans("Discount"), $langs->trans("HelpEscompte"), - 1);
5521 print '</span>';
5522 print '</td><td class="right"><span class="amount">'.price(price2num($object->total_ttc - $creditnoteamount - $depositamount - $totalpaid, 'MT')).'</span></td><td>&nbsp;</td></tr>';
5523 $resteapayeraffiche = 0;
5524 $cssforamountpaymentcomplete = 'amountpaymentneutral';
5525 }
5526 // Partially paid or abandoned 'badcustomer'
5527 if (($object->status == Facture::STATUS_CLOSED || $object->status == Facture::STATUS_ABANDONED) && $object->close_code == 'badcustomer') {
5528 print '<tr><td colspan="'.$nbcols.'" class="nowrap right">';
5529 print '<span class="opacitymedium">';
5530 print $form->textwithpicto($langs->trans("Abandoned"), $langs->trans("HelpAbandonBadCustomer"), - 1);
5531 print '</span>';
5532 print '</td><td class="right">'.price(price2num($object->total_ttc - $creditnoteamount - $depositamount - $totalpaid, 'MT')).'</td><td>&nbsp;</td></tr>';
5533 // $resteapayeraffiche=0;
5534 $cssforamountpaymentcomplete = 'amountpaymentneutral';
5535 }
5536 // Partially paid or abandoned 'product_returned'
5537 if (($object->status == Facture::STATUS_CLOSED || $object->status == Facture::STATUS_ABANDONED) && $object->close_code == 'product_returned') {
5538 print '<tr><td colspan="'.$nbcols.'" class="nowrap right">';
5539 print '<span class="opacitymedium">';
5540 print $form->textwithpicto($langs->trans("ProductReturned"), $langs->trans("HelpAbandonProductReturned"), - 1);
5541 print '</span>';
5542 print '</td><td class="right"><span class="amount">'.price(price2num($object->total_ttc - $creditnoteamount - $depositamount - $totalpaid, 'MT')).'</span></td><td>&nbsp;</td></tr>';
5543 $resteapayeraffiche = 0;
5544 $cssforamountpaymentcomplete = 'amountpaymentneutral';
5545 }
5546 // Partially paid or abandoned 'abandoned'
5547 if (($object->status == Facture::STATUS_CLOSED || $object->status == Facture::STATUS_ABANDONED) && $object->close_code == 'abandon') {
5548 print '<tr><td colspan="'.$nbcols.'" class="nowrap right">';
5549 $text = $langs->trans("HelpAbandonOther");
5550 if ($object->close_note) {
5551 $text .= '<br><br><b>'.$langs->trans("Reason").'</b>:'.$object->close_note;
5552 }
5553 print '<span class="opacitymedium">';
5554 // @phan-suppress-next-line PhanPluginSuspiciousParamPosition
5555 print $form->textwithpicto($langs->trans("Abandoned"), $text, - 1);
5556 print '</span>';
5557 print '</td><td class="right"><span class="amount">'.price(price2num($object->total_ttc - $creditnoteamount - $depositamount - $totalpaid, 'MT')).'</span></td><td>&nbsp;</td></tr>';
5558 $resteapayeraffiche = 0;
5559 $cssforamountpaymentcomplete = 'amountpaymentneutral';
5560 }
5561
5562 // Billed
5563 print '<tr><td colspan="'.$nbcols.'" class="right">';
5564 print '<span class="opacitymedium">';
5565 print $langs->trans("Billed");
5566 print '</td><td class="right">'.price($object->total_ttc).'</td><td>&nbsp;</td></tr>';
5567 // Remainder to pay
5568 print '<tr><td colspan="'.$nbcols.'" class="right">';
5569 print '<span class="opacitymedium">';
5570 print $langs->trans('RemainderToPay');
5571 if ($resteapayeraffiche < 0) {
5572 print ' ('.$langs->trans('NegativeIfExcessReceived').')';
5573 }
5574 print '</span>';
5575 print '</td>';
5576 print '<td class="right'.($resteapayeraffiche ? ' amountremaintopay' : (' '.$cssforamountpaymentcomplete)).'">'.price($resteapayeraffiche).'</td><td>&nbsp;</td></tr>';
5577
5578 // Remainder to pay Multicurrency
5579 if ($object->multicurrency_code != $conf->currency || $object->multicurrency_tx != 1) {
5580 print '<tr><td colspan="'.$nbcols.'" class="right">';
5581 print '<span class="opacitymedium">';
5582 print $langs->trans('RemainderToPayMulticurrency');
5583 if ($resteapayeraffiche < 0) {
5584 print ' ('.$langs->trans('NegativeIfExcessReceived').')';
5585 }
5586 print '</span>';
5587 print '</td>';
5588 print '<td class="right'.($resteapayeraffiche ? ' amountremaintopay' : (' '.$cssforamountpaymentcomplete)).'">';
5589 //print (empty($object->multicurrency_code) ? $conf->currency : $object->multicurrency_code).' ';
5590 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>';
5591 }
5592
5593 // Retained warranty : usually use on construction industry
5594 if (!empty($object->situation_final) && !empty($object->retained_warranty) && $displayWarranty) {
5595 // Billed - retained warranty
5596 if ($object->type == Facture::TYPE_SITUATION) {
5597 $retainedWarranty = $total_global_ttc * $object->retained_warranty / 100;
5598 } else {
5599 // Because one day retained warranty could be used on standard invoices
5600 $retainedWarranty = $object->total_ttc * $object->retained_warranty / 100;
5601 }
5602
5603 $billedWithRetainedWarranty = $object->total_ttc - $retainedWarranty;
5604
5605 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>';
5606
5607 // retained warranty
5608 print '<tr><td colspan="'.$nbcols.'" align="right">';
5609 print $langs->trans("RetainedWarranty").' ('.$object->retained_warranty.'%)';
5610 print !empty($object->retained_warranty_date_limit) ? ' '.$langs->trans("ToPayOn", dol_print_date($object->retained_warranty_date_limit, 'day')) : '';
5611 print ' :</td><td align="right">'.price($retainedWarranty).'</td><td>&nbsp;</td></tr>';
5612 }
5613 } else { // Credit note
5614 $resteapayeraffiche = $resteapayer;
5615 $cssforamountpaymentcomplete = 'amountpaymentneutral';
5616
5617 // Total already paid back
5618 print '<tr><td colspan="'.$nbcols.'" class="right">';
5619 print '<span class="opacitymedium">'.$langs->trans('AlreadyPaidBack').'</span>';
5620 print '</td><td class="right"><span class="amount">'.price($sign * $totalpaid).'</span></td><td>&nbsp;</td></tr>';
5621
5622 // Billed
5623 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>';
5624
5625 // Remainder to pay back
5626 print '<tr><td colspan="'.$nbcols.'" class="right">';
5627 print '<span class="opacitymedium">'.$langs->trans('RemainderToPayBack');
5628 if ($resteapayeraffiche > 0) {
5629 print ' ('.$langs->trans('NegativeIfExcessRefunded').')';
5630 }
5631 print '</span></td>';
5632 print '<td class="right'.($resteapayeraffiche ? ' amountremaintopayback' : (' '.$cssforamountpaymentcomplete)).'">'.price($sign * $resteapayeraffiche).'</td>';
5633 print '<td class="nowrap">&nbsp;</td></tr>';
5634
5635 // Remainder to pay back Multicurrency
5636 if ($object->multicurrency_code != $conf->currency || $object->multicurrency_tx != 1) {
5637 print '<tr><td colspan="'.$nbcols.'" class="right">';
5638 print '<span class="opacitymedium">'.$langs->trans('RemainderToPayBackMulticurrency');
5639 if ($resteapayeraffiche > 0) {
5640 print ' ('.$langs->trans('NegativeIfExcessRefunded').')';
5641 }
5642 print '</span>';
5643 print '</td>';
5644 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>';
5645 }
5646
5647 // Sold credit note
5648 // print '<tr><td colspan="'.$nbcols.'" class="right">'.$langs->trans('TotalTTC').' :</td>';
5649 // print '<td class="right" style="border: 1px solid;" bgcolor="#f0f0f0"><b>'.price($sign *
5650 // $object->total_ttc).'</b></td><td>&nbsp;</td></tr>';
5651 }
5652
5653 print '</table>';
5654 print '</div>';
5655
5656 // Margin Infos
5657 if (isModEnabled('margin')) {
5658 $formmargin->displayMarginInfos($object);
5659 }
5660
5661 print '</div>';
5662 print '</div>';
5663
5664 print '<div class="clearboth"></div><br><br>';
5665
5666 if (getDolGlobalString('MAIN_DISABLE_CONTACTS_TAB')) {
5667 $blocname = 'contacts';
5668 $title = $langs->trans('ContactsAddresses');
5669 include DOL_DOCUMENT_ROOT.'/core/tpl/bloc_showhide.tpl.php';
5670 }
5671
5672 if (getDolGlobalString('MAIN_DISABLE_NOTES_TAB')) {
5673 $blocname = 'notes';
5674 $title = $langs->trans('Notes');
5675 include DOL_DOCUMENT_ROOT.'/core/tpl/bloc_showhide.tpl.php';
5676 }
5677
5678 // Get object lines
5679 $result = $object->getLinesArray();
5680
5681 // Add products/services form
5682 //$forceall = 1;
5683 global $inputalsopricewithtax;
5684 $inputalsopricewithtax = 1;
5685
5686 // Show global modifiers for situation invoices
5687 if (getDolGlobalString('INVOICE_USE_SITUATION')) {
5688 if ($object->situation_cycle_ref && $object->status == 0) {
5689 print '<!-- Area to change globally the situation percent -->'."\n";
5690 print '<div class="div-table-responsive">';
5691
5692 print '<form name="updatealllines" id="updatealllines" action="'.$_SERVER['PHP_SELF'].'?id='.$object->id.'#updatealllines" method="POST">';
5693 print '<input type="hidden" name="token" value="'.newToken().'" />';
5694 print '<input type="hidden" name="action" value="updatealllines" />';
5695 print '<input type="hidden" name="id" value="'.$object->id.'" />';
5696 print '<input type="hidden" name="backtopage" value="'.$backtopage.'">';
5697
5698 print '<table id="tablelines_all_progress" class="noborder noshadow" width="100%">';
5699
5700 print '<tr class="liste_titre nodrag nodrop">';
5701
5702 // Adds a line numbering column
5703 if (getDolGlobalString('MAIN_VIEW_LINE_NUMBER')) {
5704 print '<td align="center" width="5">&nbsp;</td>';
5705 }
5706 print '<td class="minwidth500imp">'.$langs->trans('ModifyAllLines').'</td>';
5707 print '<td class="right">'.$langs->trans('Progress').'</td>';
5708 print '<td>&nbsp;</td>';
5709 print "</tr>\n";
5710
5711 print '<tr class="nodrag nodrop">';
5712 // Adds a line numbering column
5713 if (getDolGlobalString('MAIN_VIEW_LINE_NUMBER')) {
5714 print '<td align="center" width="5">&nbsp;</td>';
5715 }
5716 print '<td>&nbsp;</td>';
5717 print '<td class="nowrap right"><input type="text" size="1" value="" name="all_progress">%</td>';
5718 print '<td class="right"><input type="submit" class="button" name="all_percent" value="Modifier" /></td>';
5719 print '</tr>';
5720
5721 print '</table>';
5722
5723 print '</form>';
5724
5725 print '</div>';
5726 }
5727 }
5728
5729 print ' <form name="addproduct" id="addproduct" action="'.$_SERVER["PHP_SELF"].'?id='.$object->id.'" method="POST">
5730 <input type="hidden" name="token" value="' . newToken().'">
5731 <input type="hidden" name="action" value="' . (($action != 'editline') ? 'addline' : 'updateline').'">
5732 <input type="hidden" name="mode" value="">
5733 <input type="hidden" name="page_y" value="">
5734 <input type="hidden" name="id" value="' . $object->id.'">
5735 <input type="hidden" name="backtopage" value="'.$backtopage.'">
5736 ';
5737
5738 if (!empty($conf->use_javascript_ajax) && $object->status == 0) {
5739 include DOL_DOCUMENT_ROOT.'/core/tpl/ajaxrow.tpl.php';
5740 }
5741
5742 print '<div class="div-table-responsive-no-min">';
5743 print '<table id="tablelines" class="noborder noshadow" width="100%">';
5744
5745 // Show object lines
5746 if (!empty($object->lines)) {
5747 $object->printObjectLines($action, $mysoc, $soc, $lineid, 1);
5748 }
5749
5750 // Form to add new line
5751 if ($object->status == 0 && $usercancreate && $action != 'valid') {
5752 if ($action != 'editline' && $action != 'selectlines') {
5753 // Add free products/services
5754
5755 $parameters = array();
5756 $reshook = $hookmanager->executeHooks('formAddObjectLine', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
5757 if ($reshook < 0) {
5758 setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
5759 }
5760 if (empty($reshook)) {
5761 $object->formAddObjectLine(1, $mysoc, $soc);
5762 }
5763 } else {
5764 $parameters = array();
5765 $reshook = $hookmanager->executeHooks('formEditObjectLine', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
5766 }
5767 }
5768
5769 print "</table>\n";
5770 print "</div>";
5771
5772 print "</form>\n";
5773 }
5774 print dol_get_fiche_end();
5775
5776
5777 // Actions buttons
5778
5779 if ($action != 'prerelance' && $action != 'presend' && $action != 'valid' && $action != 'editline') {
5780 print '<div class="tabsAction">';
5781
5782 $parameters = array();
5783 $reshook = $hookmanager->executeHooks('addMoreActionsButtons', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
5784 if (empty($reshook)) {
5785 $params = array(
5786 'attr' => array(
5787 'class' => 'classfortooltip',
5788 'title' => ''
5789 )
5790 );
5791 // Edit a validated invoice without any payment and not transferred to accounting
5792 if ($object->status == Facture::STATUS_VALIDATED) {
5793 // We check if lines of invoice are not already transferred into accountancy
5794 $ventilExportCompta = $object->getVentilExportCompta();
5795
5796 if ($ventilExportCompta == 0) {
5797 if (getDolGlobalString('INVOICE_CAN_BE_EDITED_EVEN_IF_PAYMENT_DONE') || ($resteapayer == price2num($object->total_ttc, 'MT', 1) && empty($object->paye))) {
5798 if (!$objectidnext && $object->is_last_in_cycle()) {
5799 if ($usercanunvalidate) {
5800 unset($params['attr']['title']);
5801 print dolGetButtonAction($langs->trans('Modify'), '', 'default', $_SERVER['PHP_SELF'].'?facid='.$object->id.'&action=modif&token='.newToken(), '', true, $params);
5802 } else {
5803 $params['attr']['title'] = $langs->trans('NotEnoughPermissions');
5804 print dolGetButtonAction($langs->trans('Modify'), '', 'default', $_SERVER['PHP_SELF'].'?facid='.$object->id.'&action=modif&token='.newToken(), '', false, $params);
5805 }
5806 } elseif (!$object->is_last_in_cycle()) {
5807 $params['attr']['title'] = $langs->trans('NotLastInCycle');
5808 print dolGetButtonAction($langs->trans('Modify'), '', 'default', '#', '', false, $params);
5809 } else {
5810 $params['attr']['title'] = $langs->trans('DisabledBecauseReplacedInvoice');
5811 print dolGetButtonAction($langs->trans('Modify'), '', 'default', '#', '', false, $params);
5812 }
5813 }
5814 } else {
5815 $params['attr']['title'] = $langs->trans('DisabledBecauseDispatchedInBookkeeping');
5816 print dolGetButtonAction($langs->trans('Modify'), '', 'default', '#', '', false, $params);
5817 }
5818 }
5819
5820 $discount = new DiscountAbsolute($db);
5821 $result = $discount->fetch(0, $object->id);
5822
5823 // Reopen an invoice
5825 || ($object->type == Facture::TYPE_CREDIT_NOTE && empty($discount->id))
5826 || ($object->type == Facture::TYPE_DEPOSIT && empty($discount->id))
5827 || ($object->type == Facture::TYPE_SITUATION && empty($discount->id)))
5828 && ($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
5829 && ((!getDolGlobalString('MAIN_USE_ADVANCED_PERMS') && $usercancreate) || $usercanreopen)) { // A paid invoice (partially or completely)
5830 if ($object->close_code != 'replaced' || (!$objectidnext)) { // Not replaced by another invoice or replaced but the replacement invoice has been deleted
5831 unset($params['attr']['title']);
5832 print dolGetButtonAction($langs->trans('ReOpen'), '', 'default', $_SERVER['PHP_SELF'].'?facid='.$object->id.'&action=reopen&token='.newToken(), '', true, $params);
5833 } else {
5834 $params['attr']['title'] = $langs->trans("DisabledBecauseReplacedInvoice");
5835 print dolGetButtonAction($langs->trans('ReOpen'), '', 'default', '#', '', false, $params);
5836 }
5837 }
5838
5839 // Create contract
5840 if (getDolGlobalString('CONTRACT_CREATE_FROM_INVOICE')) {
5841 if (isModEnabled('contract') && $object->status == Facture::STATUS_VALIDATED) {
5842 $langs->load("contracts");
5843
5844 if ($usercancreatecontract) {
5845 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>';
5846 }
5847 }
5848 }
5849
5850 // Validate
5851 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))) {
5852 if ($usercanvalidate) {
5853 unset($params['attr']['title']);
5854 print dolGetButtonAction($langs->trans('Validate'), '', 'default', $_SERVER["PHP_SELF"].'?facid='.$object->id.'&action=valid&token='.newToken(), '', true, $params);
5855 }
5856 }
5857
5858 // Send by mail
5859 if (empty($user->socid)) {
5860 if (($object->status == Facture::STATUS_VALIDATED || $object->status == Facture::STATUS_CLOSED) || getDolGlobalString('FACTURE_SENDBYEMAIL_FOR_ALL_STATUS')) {
5861 if ($objectidnext) {
5862 print '<span class="butActionRefused classfortooltip" title="'.$langs->trans("DisabledBecauseReplacedInvoice").'">'.$langs->trans('SendMail').'</span>';
5863 } else {
5864 if ($usercansend) {
5865 unset($params['attr']['title']);
5866 print dolGetButtonAction('', $langs->trans('SendMail'), 'default', $_SERVER['PHP_SELF'].'?facid='.$object->id.'&action=presend&mode=init#formmailbeforetitle', '', true, $params);
5867 } else {
5868 unset($params['attr']['title']);
5869 print dolGetButtonAction('', $langs->trans('SendMail'), 'default', '#', '', false, $params);
5870 }
5871 }
5872 }
5873 }
5874
5875 // Request a direct debit order
5876 if ($object->status > Facture::STATUS_DRAFT && $object->paye == 0 && $num == 0) {
5877 if ($resteapayer > 0) {
5878 if ($usercancreatewithdrarequest) {
5879 if (!$objectidnext && $object->close_code != 'replaced') { // Not replaced by another invoice
5880 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>';
5881 } else {
5882 print '<span class="butActionRefused classfortooltip" title="'.$langs->trans("DisabledBecauseReplacedInvoice").'">'.$langs->trans('MakeWithdrawRequest').'</span>';
5883 }
5884 } else {
5885 //print '<a class="butActionRefused classfortooltip" href="#" title="'.dol_escape_htmltag($langs->trans("NotEnoughPermissions")).'">'.$langs->trans("MakeWithdrawRequest").'</a>';
5886 }
5887 } else {
5888 //print '<a class="butActionRefused classfortooltip" href="#" title="'.dol_escape_htmltag($langs->trans("AmountMustBePositive")).'">'.$langs->trans("MakeWithdrawRequest").'</a>';
5889 }
5890 }
5891
5892 // POS Ticket
5893 if (isModEnabled('takepos') && $object->module_source == 'takepos') {
5894 $langs->load("cashdesk");
5895 $receipt_url = DOL_URL_ROOT."/takepos/receipt.php";
5896 print '<a target="_blank" rel="noopener noreferrer" class="butAction" href="'.$receipt_url.'?facid='.((int) $object->id).'">'.$langs->trans('POSTicket').'</a>';
5897 }
5898
5899 // Create payment
5900 if ($object->type != Facture::TYPE_CREDIT_NOTE && $object->status == 1 && $object->paye == 0 && $usercanissuepayment) {
5901 if ($objectidnext) {
5902 print '<span class="butActionRefused classfortooltip" title="'.$langs->trans("DisabledBecauseReplacedInvoice").'">'.$langs->trans('DoPayment').'</span>';
5903 } else {
5904 if ($object->type == Facture::TYPE_DEPOSIT && $resteapayer == 0) {
5905 // For down payment, we refuse to receive more than amount to pay.
5906 $params['attr']['title'] = $langs->trans('DisabledBecauseRemainderToPayIsZero');
5907 print dolGetButtonAction($langs->trans('DoPayment'), '', 'default', '#', '', false, $params);
5908 } else {
5909 // 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)
5910 //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>';
5911 unset($params['attr']['title']);
5912 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);
5913 }
5914 }
5915 }
5916
5917 $sumofpayment = $totalpaid;
5918 $sumofpaymentall = $totalpaid + $totalcreditnotes + $totaldeposits;
5919
5920 // Reverse back money or convert to reduction
5922 // For credit note only
5923 if ($object->type == Facture::TYPE_CREDIT_NOTE && $object->status == Facture::STATUS_VALIDATED && $object->paye == 0 && $usercanissuepayment) {
5924 if ($resteapayer == 0) {
5925 print '<span class="butActionRefused classfortooltip" title="'.$langs->trans("DisabledBecauseRemainderToPayIsZero").'">'.$langs->trans('DoPaymentBack').'</span>';
5926 } else {
5927 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>';
5928 }
5929 }
5930
5931 // For standard invoice with excess received
5932 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)) {
5933 print '<a class="butAction'.($conf->use_javascript_ajax ? ' reposition' : '').'" href="'.$_SERVER["PHP_SELF"].'?facid='.$object->id.'&action=converttoreduc&token='.newToken().'">'.$langs->trans('ConvertExcessReceivedToReduc').'</a>';
5934 }
5935 // For credit note
5936 if ($object->type == Facture::TYPE_CREDIT_NOTE && $object->status == Facture::STATUS_VALIDATED && $object->paye == 0 && $usercancreate
5937 && (getDolGlobalString('INVOICE_ALLOW_REUSE_OF_CREDIT_WHEN_PARTIALLY_REFUNDED') || $sumofpayment == 0) && $object->total_ht < 0
5938 ) {
5939 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>';
5940 }
5941 // For down payment invoice (deposit)
5942
5943 if ($object->type == Facture::TYPE_DEPOSIT && $usercancreate && $object->status > Facture::STATUS_DRAFT && empty($discount->id)) {
5944 // 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.
5945 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')))) {
5946 print '<a class="butAction'.($conf->use_javascript_ajax ? ' reposition' : '').'" href="'.$_SERVER["PHP_SELF"].'?facid='.$object->id.'&action=converttoreduc&token='.newToken().'">'.$langs->trans('ConvertToReduc').'</a>';
5947 } else {
5948 print '<span class="butActionRefused classfortooltip" title="'.$langs->trans("AmountPaidMustMatchAmountOfDownPayment").'">'.$langs->trans('ConvertToReduc').'</span>';
5949 }
5950 }
5951 }
5952
5953 // Classify paid
5954 if ($object->status == Facture::STATUS_VALIDATED && $object->paye == 0 && $usercanissuepayment && (
5955 ($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))) ||
5956 ($object->type == Facture::TYPE_CREDIT_NOTE && $resteapayer >= 0) ||
5957 ($object->type == Facture::TYPE_DEPOSIT && $object->total_ttc > 0)
5958 )
5959 ) {
5960 if ($object->type == Facture::TYPE_DEPOSIT && price2num($object->total_ttc, 'MT') != price2num($sumofpaymentall, 'MT')) {
5961 // We can close a down payment only if paid amount is same than amount of down payment (by definition)
5962 $params['attr']['title'] = $langs->trans('AmountPaidMustMatchAmountOfDownPayment');
5963 print dolGetButtonAction($langs->trans('ClassifyPaid'), '', 'default', '#', '', false, $params);
5964 } else {
5965 unset($params['attr']['title']);
5966 print dolGetButtonAction($langs->trans('ClassifyPaid'), '', 'default', $_SERVER['PHP_SELF'].'?facid='.$object->id.'&action=paid&token='.newToken(), '', true, $params);
5967 }
5968 }
5969
5970 // Classify 'closed not completely paid' (possible if validated and not yet filed paid)
5971 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) {
5972 if ($totalpaid > 0 || $totalcreditnotes > 0) {
5973 // If one payment or one credit note was linked to this invoice
5974 print '<a class="butAction'.($conf->use_javascript_ajax ? ' reposition' : '').'" href="'.$_SERVER['PHP_SELF'].'?facid='.$object->id.'&action=paid&token='.newToken().'">'.$langs->trans('ClassifyPaidPartially').'</a>';
5975 } else {
5976 if (!getDolGlobalString('INVOICE_CAN_NEVER_BE_CANCELED')) {
5977 if ($objectidnext) {
5978 print '<span class="butActionRefused classfortooltip" title="'.$langs->trans("DisabledBecauseReplacedInvoice").'">'.$langs->trans('ClassifyCanceled').'</span>';
5979 } else {
5980 print '<a class="butAction'.($conf->use_javascript_ajax ? ' reposition' : '').'" href="'.$_SERVER['PHP_SELF'].'?facid='.$object->id.'&amp;action=canceled">'.$langs->trans('ClassifyCanceled').'</a>';
5981 }
5982 }
5983 }
5984 }
5985
5986 // Create a credit note
5987 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) {
5988 if (!$objectidnext) {
5989 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>';
5990 }
5991 }
5992
5993 // For situation invoice with excess received
5994 if ($object->status > Facture::STATUS_DRAFT
5996 && ($object->total_ttc - $totalpaid - $totalcreditnotes - $totaldeposits) > 0
5997 && $usercancreate
5998 && !$objectidnext
5999 && $object->is_last_in_cycle()
6000 && getDolGlobalInt('INVOICE_USE_SITUATION_CREDIT_NOTE')
6001 ) {
6002 if ($usercanunvalidate) {
6003 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>';
6004 } else {
6005 print '<span class="butActionRefused classfortooltip" title="'.$langs->trans("NotEnoughPermissions").'">'.$langs->trans("CreateCreditNote").'</span>';
6006 }
6007 }
6008
6009 // Clone
6010 if (($object->type == Facture::TYPE_STANDARD || $object->type == Facture::TYPE_DEPOSIT || $object->type == Facture::TYPE_PROFORMA) && $usercancreate) {
6011 unset($params['attr']['title']);
6012 print dolGetButtonAction($langs->trans('ToClone'), '', 'default', $_SERVER['PHP_SELF'].'?facid='.$object->id.'&action=clone&object=invoice&token='.newToken(), '', true, $params);
6013 }
6014
6015 // Clone as predefined / Create template
6016 if (($object->type == Facture::TYPE_STANDARD || $object->type == Facture::TYPE_DEPOSIT || $object->type == Facture::TYPE_PROFORMA) && $object->status == 0 && $usercancreate) {
6017 if (!$objectidnext && count($object->lines) > 0) {
6018 unset($params['attr']['title']);
6019 print dolGetButtonAction($langs->trans('ChangeIntoRepeatableInvoice'), '', 'default', DOL_URL_ROOT.'/compta/facture/card-rec.php?facid='.$object->id.'&amp;action=create', '', true, $params);
6020 }
6021 }
6022
6023 // Remove situation from cycle
6024 if (in_array($object->status, array(Facture::STATUS_CLOSED, Facture::STATUS_VALIDATED))
6026 && $usercancreate
6027 && !$objectidnext
6028 && $object->situation_counter > 1
6029 && $object->is_last_in_cycle()
6030 && $usercanunvalidate
6031 ) {
6032 if (($object->total_ttc - $totalcreditnotes) == 0) {
6033 print '<a id="butSituationOut" class="butAction" href="'.$_SERVER['PHP_SELF'].'?facid='.$object->id.'&amp;action=situationout">'.$langs->trans("RemoveSituationFromCycle").'</a>';
6034 } else {
6035 print '<a id="butSituationOutRefused" class="butActionRefused classfortooltip" href="#" title="'.$langs->trans("DisabledBecauseNotEnouthCreditNote").'" >'.$langs->trans("RemoveSituationFromCycle").'</a>';
6036 }
6037 }
6038
6039 // Create next situation invoice
6040 if ($usercancreate && ($object->type == 5) && ($object->status == 1 || $object->status == 2)) {
6041 if ($object->is_last_in_cycle() && $object->situation_final != 1) {
6042 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>';
6043 } elseif (!$object->is_last_in_cycle()) {
6044 print '<a class="butActionRefused classfortooltip" href="#" title="'.$langs->trans("DisabledBecauseNotLastInCycle").'">'.$langs->trans('CreateNextSituationInvoice').'</a>';
6045 } else {
6046 print '<a class="butActionRefused classfortooltip" href="#" title="'.$langs->trans("DisabledBecauseFinal").'">'.$langs->trans('CreateNextSituationInvoice').'</a>';
6047 }
6048 }
6049
6050 // Delete
6051 $isErasable = $object->is_erasable();
6052 $htmltooltip = '';
6053 if ($isErasable == -4) {
6054 $htmltooltip = $langs->trans('DisabledBecausePayments');
6055 } elseif ($isErasable == -3) {
6056 $htmltooltip = $langs->trans('DisabledBecauseNotLastSituationInvoice');
6057 } elseif ($isErasable == -2) {
6058 $htmltooltip = $langs->trans('DisabledBecauseNotLastInvoice');
6059 } elseif ($isErasable == -1) {
6060 $htmltooltip = $langs->trans('DisabledBecauseDispatchedInBookkeeping');
6061 } elseif ($isErasable <= 0) { // Any other cases
6062 $htmltooltip = $langs->trans('DisabledBecauseNotErasable');
6063 } elseif ($objectidnext) {
6064 $htmltooltip = $langs->trans('DisabledBecauseReplacedInvoice');
6065 }
6066 if ($usercandelete || ($usercancreate && $isErasable == 1)) { // isErasable = 1 means draft with temporary ref (draft can always be deleted with no need of permissions)
6067 $enableDelete = false;
6068 $deleteHref = '#';
6069 if ($isErasable > 0 && ! $objectidnext) {
6070 $deleteHref = $_SERVER["PHP_SELF"].'?facid='.$object->id.'&action=delete&token='.newToken();
6071 $enableDelete = true;
6072 }
6073 unset($params['attr']['title']);
6074 print dolGetButtonAction($htmltooltip, $langs->trans('Delete'), 'delete', $deleteHref, '', $enableDelete, $params);
6075 } else {
6076 unset($params['attr']['title']);
6077 print dolGetButtonAction($htmltooltip, $langs->trans('Delete'), 'delete', '#', '', false);
6078 }
6079 }
6080 print '</div>';
6081 }
6082
6083 // Select mail models is same action as presend
6084 if (GETPOST('modelselected', 'alpha')) {
6085 $action = 'presend';
6086 }
6087 if ($action != 'prerelance' && $action != 'presend') {
6088 print '<div class="fichecenter"><div class="fichehalfleft">';
6089 print '<a name="builddoc"></a>'; // ancre
6090
6091 // Generated documents
6092 $filename = dol_sanitizeFileName($object->ref);
6093 $filedir = $conf->invoice->multidir_output[$object->entity].'/'.dol_sanitizeFileName($object->ref);
6094 $urlsource = $_SERVER['PHP_SELF'].'?facid='.$object->id;
6095 $genallowed = $usercanread;
6096 $delallowed = $usercancreate;
6097
6098 print $formfile->showdocuments(
6099 'facture',
6100 $filename,
6101 $filedir,
6102 $urlsource,
6103 $genallowed,
6104 $delallowed,
6105 $object->model_pdf,
6106 1,
6107 0,
6108 0,
6109 28,
6110 0,
6111 '',
6112 '',
6113 '',
6114 $soc->default_lang,
6115 '',
6116 $object,
6117 0,
6118 'remove_file_comfirm'
6119 );
6120
6121 $somethingshown = $formfile->numoffiles;
6122
6123 // Show links to link elements
6124 $linktoelem = $form->showLinkToObjectBlock($object, array(), array('invoice'));
6125
6126 $compatibleImportElementsList = false;
6127 if ($usercancreate
6128 && $object->status == Facture::STATUS_DRAFT
6130 $compatibleImportElementsList = array('commande', 'propal'); // import from linked elements
6131 }
6132 $somethingshown = $form->showLinkedObjectBlock($object, $linktoelem, $compatibleImportElementsList);
6133
6134 // Show online payment link
6135 // The list can be complete by the hook 'doValidatePayment' executed inside getValidOnlinePaymentMethods()
6136 include_once DOL_DOCUMENT_ROOT.'/core/lib/payments.lib.php';
6137 $validpaymentmethod = getValidOnlinePaymentMethods('');
6138 $useonlinepayment = count($validpaymentmethod);
6139
6140 if ($object->status != Facture::STATUS_DRAFT && $useonlinepayment) {
6141 print '<br><!-- Link to pay -->'."\n";
6142 require_once DOL_DOCUMENT_ROOT.'/core/lib/payments.lib.php';
6143 print showOnlinePaymentUrl('invoice', $object->ref).'<br>';
6144 }
6145
6146 print '</div><div class="fichehalfright">';
6147
6148 $MAXEVENT = 10;
6149
6150 $morehtmlcenter = dolGetButtonTitle($langs->trans('SeeAll'), '', 'fa fa-bars imgforviewmode', DOL_URL_ROOT.'/compta/facture/agenda.php?id='.$object->id);
6151
6152 // List of actions on element
6153 include_once DOL_DOCUMENT_ROOT.'/core/class/html.formactions.class.php';
6154 $formactions = new FormActions($db);
6155 $somethingshown = $formactions->showactions($object, 'invoice', $socid, 1, '', $MAXEVENT, '', $morehtmlcenter); // Show all action for thirdparty
6156
6157 print '</div></div>';
6158 }
6159
6160
6161 // Presend form
6162 $modelmail = 'facture_send';
6163 $defaulttopic = 'SendBillRef';
6164 $diroutput = $conf->invoice->multidir_output[$object->entity];
6165 $trackid = 'inv'.$object->id;
6166
6167 include DOL_DOCUMENT_ROOT.'/core/tpl/card_presend.tpl.php';
6168}
6169
6170// End of page
6171llxFooter();
6172$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:2010
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:2010