dolibarr 20.0.0
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'), GETPOSTINT('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 $amount_ht[$keyforvatrate] += $line->total_ht;
879 $amount_tva[$keyforvatrate] += $line->total_tva;
880 $amount_ttc[$keyforvatrate] += $line->total_ttc;
881 $multicurrency_amount_ht[$keyforvatrate] += $line->multicurrency_total_ht;
882 $multicurrency_amount_tva[$keyforvatrate] += $line->multicurrency_total_tva;
883 $multicurrency_amount_ttc[$keyforvatrate] += $line->multicurrency_total_ttc;
884 $i++;
885 }
886 }
887 '@phan-var-force array<string,float> $amount_ht
888 @phan-var-force array<string,float> $amount_tva
889 @phan-var-force array<string,float> $amount_ttc
890 @phan-var-force array<string,float> $multicurrency_amount_ht
891 @phan-var-force array<string,float> $multicurrency_amount_tva
892 @phan-var-force array<string,float> $multicurrency_amount_ttc';
893
894 // If some payments were already done, we change the amount to pay using same prorate
895 if (getDolGlobalString('INVOICE_ALLOW_REUSE_OF_CREDIT_WHEN_PARTIALLY_REFUNDED') && $object->type == Facture::TYPE_CREDIT_NOTE) {
896 $alreadypaid = $object->getSommePaiement(); // This can be not 0 if we allow to create credit to reuse from credit notes partially refunded.
897 if ($alreadypaid && abs($alreadypaid) < abs($object->total_ttc)) {
898 $ratio = abs(($object->total_ttc - $alreadypaid) / $object->total_ttc);
899 foreach ($amount_ht as $vatrate => $val) {
900 $amount_ht[$vatrate] = price2num($amount_ht[$vatrate] * $ratio, 'MU');
901 $amount_tva[$vatrate] = price2num($amount_tva[$vatrate] * $ratio, 'MU');
902 $amount_ttc[$vatrate] = price2num($amount_ttc[$vatrate] * $ratio, 'MU');
903 $multicurrency_amount_ht[$vatrate] = price2num($multicurrency_amount_ht[$vatrate] * $ratio, 'MU');
904 $multicurrency_amount_tva[$vatrate] = price2num($multicurrency_amount_tva[$vatrate] * $ratio, 'MU');
905 $multicurrency_amount_ttc[$vatrate] = price2num($multicurrency_amount_ttc[$vatrate] * $ratio, 'MU');
906 }
907 }
908 }
909 //var_dump($amount_ht);var_dump($amount_tva);var_dump($amount_ttc);exit;
910
911 // Insert one discount by VAT rate category
912 $discount = new DiscountAbsolute($db);
913 if ($object->type == Facture::TYPE_CREDIT_NOTE) {
914 $discount->description = '(CREDIT_NOTE)';
915 } elseif ($object->type == Facture::TYPE_DEPOSIT) {
916 $discount->description = '(DEPOSIT)';
918 $discount->description = '(EXCESS RECEIVED)';
919 } else {
920 setEventMessages($langs->trans('CantConvertToReducAnInvoiceOfThisType'), null, 'errors');
921 }
922 $discount->fk_soc = $object->socid;
923 $discount->socid = $object->socid;
924 $discount->fk_facture_source = $object->id;
925
926 $error = 0;
927
929 // If we're on a standard invoice, we have to get excess received to create a discount in TTC without VAT
930
931 // Total payments
932 $sql = 'SELECT SUM(pf.amount) as total_paiements';
933 $sql .= ' FROM '.MAIN_DB_PREFIX.'paiement_facture as pf, '.MAIN_DB_PREFIX.'paiement as p';
934 $sql .= ' LEFT JOIN '.MAIN_DB_PREFIX.'c_paiement as c ON p.fk_paiement = c.id';
935 $sql .= ' WHERE pf.fk_facture = '.((int) $object->id);
936 $sql .= ' AND pf.fk_paiement = p.rowid';
937 $sql .= ' AND p.entity IN ('.getEntity('invoice').')';
938 $resql = $db->query($sql);
939 if (!$resql) {
940 dol_print_error($db);
941 }
942
943 $res = $db->fetch_object($resql);
944 $total_paiements = $res->total_paiements;
945
946 // Total credit note and deposit
947 $total_creditnote_and_deposit = 0;
948 $sql = "SELECT re.rowid, re.amount_ht, re.amount_tva, re.amount_ttc,";
949 $sql .= " re.description, re.fk_facture_source";
950 $sql .= " FROM ".MAIN_DB_PREFIX."societe_remise_except as re";
951 $sql .= " WHERE fk_facture = ".((int) $object->id);
952 $resql = $db->query($sql);
953 if (!empty($resql)) {
954 while ($obj = $db->fetch_object($resql)) {
955 $total_creditnote_and_deposit += $obj->amount_ttc;
956 }
957 } else {
958 dol_print_error($db);
959 }
960
961 $discount->amount_ht = $discount->amount_ttc = $total_paiements + $total_creditnote_and_deposit - $object->total_ttc;
962 $discount->amount_tva = 0;
963 $discount->tva_tx = 0;
964 $discount->vat_src_code = '';
965
966 $result = $discount->create($user);
967 if ($result < 0) {
968 $error++;
969 }
970 }
972 foreach ($amount_ht as $tva_tx => $xxx) {
973 $discount->amount_ht = abs((float) $amount_ht[$tva_tx]);
974 $discount->amount_tva = abs((float) $amount_tva[$tva_tx]);
975 $discount->amount_ttc = abs((float) $amount_ttc[$tva_tx]);
976 $discount->multicurrency_amount_ht = abs((float) $multicurrency_amount_ht[$tva_tx]);
977 $discount->multicurrency_amount_tva = abs((float) $multicurrency_amount_tva[$tva_tx]);
978 $discount->multicurrency_amount_ttc = abs((float) $multicurrency_amount_ttc[$tva_tx]);
979
980 // Clean vat code
981 $reg = array();
982 $vat_src_code = '';
983 if (preg_match('/\‍((.*)\‍)/', $tva_tx, $reg)) {
984 $vat_src_code = $reg[1];
985 $tva_tx = preg_replace('/\s*\‍(.*\‍)/', '', $tva_tx); // Remove code into vatrate.
986 }
987
988 $discount->tva_tx = abs((float) $tva_tx);
989 $discount->vat_src_code = $vat_src_code;
990
991 $result = $discount->create($user);
992 if ($result < 0) {
993 $error++;
994 break;
995 }
996 }
997 }
998
999 if (empty($error)) {
1000 if ($object->type != Facture::TYPE_DEPOSIT) {
1001 // Set invoice as paid
1002 $result = $object->setPaid($user);
1003 if ($result >= 0) {
1004 $db->commit();
1005 } else {
1006 setEventMessages($object->error, $object->errors, 'errors');
1007 $db->rollback();
1008 }
1009 } else {
1010 $db->commit();
1011 }
1012 } else {
1013 setEventMessages($discount->error, $discount->errors, 'errors');
1014 $db->rollback();
1015 }
1016 }
1017 } elseif ($action == 'confirm_delete_paiement' && $confirm == 'yes' && $usercanissuepayment) {
1018 // Delete payment
1019 $object->fetch($id);
1020 if ($object->status == Facture::STATUS_VALIDATED && $object->paye == 0) {
1021 $paiement = new Paiement($db);
1022 $result = $paiement->fetch(GETPOSTINT('paiement_id'));
1023 if ($result > 0) {
1024 $result = $paiement->delete($user); // If fetch ok and found
1025 if ($result >= 0) {
1026 header("Location: ".$_SERVER['PHP_SELF']."?id=".$id);
1027 exit;
1028 }
1029 }
1030 if ($result < 0) {
1031 setEventMessages($paiement->error, $paiement->errors, 'errors');
1032 }
1033 }
1034 } elseif ($action == 'add' && $usercancreate) {
1035 // Insert new invoice in database
1036 if ($socid > 0) {
1037 $object->socid = GETPOSTINT('socid');
1038 }
1039
1040 if (GETPOST('type') === '') {
1041 setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("Type")), null, 'errors');
1042 }
1043
1044 $db->begin();
1045
1046 $error = 0;
1047 $originentity = GETPOST('originentity');
1048 // Fill array 'array_options' with data from add form
1049 $ret = $extrafields->setOptionalsFromPost(null, $object);
1050 if ($ret < 0) {
1051 $error++;
1052 }
1053
1054 $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
1055 $date_pointoftax = dol_mktime(0, 0, 0, GETPOSTINT('date_pointoftaxmonth'), GETPOSTINT('date_pointoftaxday'), GETPOSTINT('date_pointoftaxyear'), 'tzserver');
1056
1057 // Replacement invoice
1058 if (GETPOST('type') == Facture::TYPE_REPLACEMENT) {
1059 if (empty($dateinvoice)) {
1060 $error++;
1061 setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("Date")), null, 'errors');
1062 $action = 'create';
1063 } elseif ($dateinvoice > (dol_get_last_hour(dol_now('tzuserrel')) + getDolGlobalInt('INVOICE_MAX_FUTURE_DELAY'))) {
1064 $error++;
1065 setEventMessages($langs->trans("ErrorDateIsInFuture"), null, 'errors');
1066 $action = 'create';
1067 }
1068
1069 if (!(GETPOSTINT('fac_replacement') > 0)) {
1070 $error++;
1071 setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("ReplaceInvoice")), null, 'errors');
1072 $action = 'create';
1073 }
1074
1075 if (!$error) {
1076 // This is a replacement invoice
1077 $result = $object->fetch(GETPOSTINT('fac_replacement'));
1078 $object->fetch_thirdparty();
1079
1080 $object->date = $dateinvoice;
1081 $object->date_pointoftax = $date_pointoftax;
1082 $object->note_public = trim(GETPOST('note_public', 'restricthtml'));
1083 $object->note_private = trim(GETPOST('note_private', 'restricthtml'));
1084 $object->ref_client = GETPOST('ref_client', 'alphanohtml');
1085 $object->ref_customer = GETPOST('ref_client', 'alphanohtml');
1086 $object->model_pdf = GETPOST('model', 'alphanohtml');
1087 $object->fk_project = GETPOSTINT('projectid');
1088 $object->cond_reglement_id = GETPOSTINT('cond_reglement_id');
1089 $object->mode_reglement_id = GETPOSTINT('mode_reglement_id');
1090 $object->fk_account = GETPOSTINT('fk_account');
1091 //$object->remise_absolue = price2num(GETPOST('remise_absolue'), 'MU', 2);
1092 //$object->remise_percent = price2num(GETPOST('remise_percent'), '', 2);
1093 $object->fk_incoterms = GETPOSTINT('incoterm_id');
1094 $object->location_incoterms = GETPOST('location_incoterms', 'alpha');
1095 $object->multicurrency_code = GETPOST('multicurrency_code', 'alpha');
1096 $object->multicurrency_tx = GETPOSTINT('originmulticurrency_tx');
1097
1098 // Special properties of replacement invoice
1099 $object->fk_facture_source = GETPOSTINT('fac_replacement');
1101
1102 $id = $object->createFromCurrent($user);
1103 if ($id <= 0) {
1104 setEventMessages($object->error, $object->errors, 'errors');
1105 }
1106 }
1107 }
1108
1109 // Credit note invoice
1110 if (GETPOST('type') == Facture::TYPE_CREDIT_NOTE) {
1111 $sourceinvoice = GETPOSTINT('fac_avoir');
1112 if (!($sourceinvoice > 0) && !getDolGlobalString('INVOICE_CREDIT_NOTE_STANDALONE')) {
1113 $error++;
1114 setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("CorrectInvoice")), null, 'errors');
1115 $action = 'create';
1116 }
1117
1118 if (empty($dateinvoice)) {
1119 $error++;
1120 setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("Date")), null, 'errors');
1121 $action = 'create';
1122 } elseif ($dateinvoice > (dol_get_last_hour(dol_now('tzuserrel')) + getDolGlobalInt('INVOICE_MAX_FUTURE_DELAY'))) {
1123 $error++;
1124 setEventMessages($langs->trans("ErrorDateIsInFuture"), null, 'errors');
1125 $action = 'create';
1126 }
1127
1128 if (getDolGlobalInt('INVOICE_SUBTYPE_ENABLED') && empty(GETPOST("subtype"))) {
1129 $error++;
1130 setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("InvoiceSubtype")), null, 'errors');
1131 $action = 'create';
1132 }
1133
1134 if (!$error) {
1135 if (!empty($originentity)) {
1136 $object->entity = $originentity;
1137 }
1138 $object->socid = GETPOSTINT('socid');
1139 $object->subtype = GETPOSTINT('subtype');
1140 $object->ref = GETPOST('ref');
1141 $object->date = $dateinvoice;
1142 $object->date_pointoftax = $date_pointoftax;
1143 $object->note_public = trim(GETPOST('note_public', 'restricthtml'));
1144 $object->note_private = trim(GETPOST('note_private', 'restricthtml'));
1145 $object->ref_client = GETPOST('ref_client', 'alphanohtml');
1146 $object->ref_customer = GETPOST('ref_client', 'alphanohtml');
1147 $object->model_pdf = GETPOST('model');
1148 $object->fk_project = GETPOSTINT('projectid');
1149 $object->cond_reglement_id = 0; // No payment term for a credit note
1150 $object->mode_reglement_id = GETPOSTINT('mode_reglement_id');
1151 $object->fk_account = GETPOSTINT('fk_account');
1152 //$object->remise_absolue = price2num(GETPOST('remise_absolue'), 'MU');
1153 //$object->remise_percent = price2num(GETPOST('remise_percent'), '', 2);
1154 $object->fk_incoterms = GETPOSTINT('incoterm_id');
1155 $object->location_incoterms = GETPOST('location_incoterms', 'alpha');
1156 $object->multicurrency_code = GETPOST('multicurrency_code', 'alpha');
1157 $object->multicurrency_tx = GETPOSTINT('originmulticurrency_tx');
1158
1159 // Special properties of replacement invoice
1160 $object->fk_facture_source = $sourceinvoice > 0 ? $sourceinvoice : '';
1162
1163 $facture_source = new Facture($db); // fetch origin object
1164 if ($facture_source->fetch($object->fk_facture_source) > 0) {
1165 if ($facture_source->type == Facture::TYPE_SITUATION) {
1166 $object->situation_counter = $facture_source->situation_counter;
1167 $object->situation_cycle_ref = $facture_source->situation_cycle_ref;
1168 $facture_source->fetchPreviousNextSituationInvoice();
1169 }
1170 }
1171
1172
1173 $id = $object->create($user);
1174 if ($id < 0) {
1175 $error++;
1176 } else {
1177 // copy internal contacts
1178 if ($object->copy_linked_contact($facture_source, 'internal') < 0) {
1179 $error++;
1180 } elseif ($facture_source->socid == $object->socid) {
1181 // copy external contacts if same company
1182 if ($object->copy_linked_contact($facture_source, 'external') < 0) {
1183 $error++;
1184 }
1185 }
1186 }
1187
1188 // NOTE: Pb with situation invoice
1189 // NOTE: fields total on situation invoice are stored as cumulative values on total of lines (bad) but delta on invoice total
1190 // NOTE: fields total on credit note are stored as delta both on total of lines and on invoice total (good)
1191 // NOTE: fields situation_percent on situation invoice are stored as cumulative values on lines (bad)
1192 // NOTE: fields situation_percent on credit note are stored as delta on lines (good)
1193 if (GETPOSTINT('invoiceAvoirWithLines') == 1 && $id > 0) {
1194 if (!empty($facture_source->lines)) {
1195 $fk_parent_line = 0;
1196
1197 foreach ($facture_source->lines as $line) {
1198 // Extrafields
1199 if (method_exists($line, 'fetch_optionals')) {
1200 // load extrafields
1201 $line->fetch_optionals();
1202 }
1203
1204 // Reset fk_parent_line for no child products and special product
1205 if (($line->product_type != 9 && empty($line->fk_parent_line)) || $line->product_type == 9) {
1206 $fk_parent_line = 0;
1207 }
1208
1209
1210 if ($facture_source->type == Facture::TYPE_SITUATION) {
1211 $source_fk_prev_id = $line->fk_prev_id; // temporary storing situation invoice fk_prev_id
1212 $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
1213
1214 if (!empty($facture_source->tab_previous_situation_invoice)) {
1215 // search the last standard invoice in cycle and the possible credit note between this last and facture_source
1216 // TODO Move this out of loop of $facture_source->lines
1217 $tab_jumped_credit_notes = array();
1218 $lineIndex = count($facture_source->tab_previous_situation_invoice) - 1;
1219 $searchPreviousInvoice = true;
1220 while ($searchPreviousInvoice) {
1221 if ($facture_source->tab_previous_situation_invoice[$lineIndex]->type == Facture::TYPE_SITUATION || $lineIndex < 1) {
1222 $searchPreviousInvoice = false; // find, exit;
1223 break;
1224 } else {
1225 if ($facture_source->tab_previous_situation_invoice[$lineIndex]->type == Facture::TYPE_CREDIT_NOTE) {
1226 $tab_jumped_credit_notes[$lineIndex] = $facture_source->tab_previous_situation_invoice[$lineIndex]->id;
1227 }
1228 $lineIndex--; // go to previous invoice in cycle
1229 }
1230 }
1231
1232 $maxPrevSituationPercent = 0;
1233 foreach ($facture_source->tab_previous_situation_invoice[$lineIndex]->lines as $prevLine) {
1234 if ($prevLine->id == $source_fk_prev_id) {
1235 $maxPrevSituationPercent = max($maxPrevSituationPercent, $prevLine->situation_percent);
1236
1237 //$line->subprice = $line->subprice - $prevLine->subprice;
1238 $line->total_ht -= $prevLine->total_ht;
1239 $line->total_tva -= $prevLine->total_tva;
1240 $line->total_ttc -= $prevLine->total_ttc;
1241 $line->total_localtax1 -= $prevLine->total_localtax1;
1242 $line->total_localtax2 -= $prevLine->total_localtax2;
1243
1244 $line->multicurrency_subprice -= $prevLine->multicurrency_subprice;
1245 $line->multicurrency_total_ht -= $prevLine->multicurrency_total_ht;
1246 $line->multicurrency_total_tva -= $prevLine->multicurrency_total_tva;
1247 $line->multicurrency_total_ttc -= $prevLine->multicurrency_total_ttc;
1248 }
1249 }
1250
1251 // prorata
1252 $line->situation_percent = $maxPrevSituationPercent - $line->situation_percent;
1253
1254 //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>';
1255
1256 // If there is some credit note between last situation invoice and invoice used for credit note generation (note: credit notes are stored as delta)
1257 $maxPrevSituationPercent = 0;
1258 foreach ($tab_jumped_credit_notes as $index => $creditnoteid) {
1259 foreach ($facture_source->tab_previous_situation_invoice[$index]->lines as $prevLine) {
1260 if ($prevLine->fk_prev_id == $source_fk_prev_id) {
1261 $maxPrevSituationPercent = $prevLine->situation_percent;
1262
1263 $line->total_ht -= $prevLine->total_ht;
1264 $line->total_tva -= $prevLine->total_tva;
1265 $line->total_ttc -= $prevLine->total_ttc;
1266 $line->total_localtax1 -= $prevLine->total_localtax1;
1267 $line->total_localtax2 -= $prevLine->total_localtax2;
1268
1269 $line->multicurrency_subprice -= $prevLine->multicurrency_subprice;
1270 $line->multicurrency_total_ht -= $prevLine->multicurrency_total_ht;
1271 $line->multicurrency_total_tva -= $prevLine->multicurrency_total_tva;
1272 $line->multicurrency_total_ttc -= $prevLine->multicurrency_total_ttc;
1273 }
1274 }
1275 }
1276
1277 // prorata
1278 $line->situation_percent += $maxPrevSituationPercent;
1279
1280 //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>';
1281 }
1282 }
1283
1284 $line->fk_facture = $object->id;
1285 $line->fk_parent_line = $fk_parent_line;
1286
1287 $line->subprice = -$line->subprice; // invert price for object
1288 // $line->pa_ht = $line->pa_ht; // we chose to have buy/cost price always positive, so no revert of sign here
1289 $line->total_ht = -$line->total_ht;
1290 $line->total_tva = -$line->total_tva;
1291 $line->total_ttc = -$line->total_ttc;
1292 $line->total_localtax1 = -$line->total_localtax1;
1293 $line->total_localtax2 = -$line->total_localtax2;
1294
1295 $line->multicurrency_subprice = -$line->multicurrency_subprice;
1296 $line->multicurrency_total_ht = -$line->multicurrency_total_ht;
1297 $line->multicurrency_total_tva = -$line->multicurrency_total_tva;
1298 $line->multicurrency_total_ttc = -$line->multicurrency_total_ttc;
1299
1300 $line->context['createcreditnotefrominvoice'] = 1;
1301 $result = $line->insert(0, 1); // When creating credit note with same lines than source, we must ignore error if discount already linked
1302
1303 $object->lines[] = $line; // insert new line in current object
1304
1305 // Defined the new fk_parent_line
1306 if ($result > 0 && $line->product_type == 9) {
1307 $fk_parent_line = $result;
1308 }
1309 }
1310
1311 $object->update_price(1);
1312 }
1313 }
1314
1315 if (GETPOSTINT('invoiceAvoirWithPaymentRestAmount') == 1 && $id > 0) {
1316 if ($facture_source->fetch($object->fk_facture_source) > 0) {
1317 $totalpaid = $facture_source->getSommePaiement();
1318 $totalcreditnotes = $facture_source->getSumCreditNotesUsed();
1319 $totaldeposits = $facture_source->getSumDepositsUsed();
1320 $remain_to_pay = abs($facture_source->total_ttc - $totalpaid - $totalcreditnotes - $totaldeposits);
1321
1322 if (getDolGlobalString('INVOICE_VAT_TO_USE_ON_CREDIT_NOTE_WHEN_GENERATED_FROM_REMAIN_TO_PAY') == 'default') {
1323 if ((empty($object->thirdparty) || !is_object($object->thirdparty) || get_class($object->thirdparty) != 'Societe')) {
1324 $object->fetch_thirdparty();
1325 }
1326 if (!empty($object->thirdparty) && is_object($object->thirdparty) && get_class($object->thirdparty) == 'Societe') {
1327 $tva_tx = get_default_tva($mysoc, $object->thirdparty);
1328 } else {
1329 $tva_tx = 0;
1330 }
1331 } elseif ((float) getDolGlobalString('INVOICE_VAT_TO_USE_ON_CREDIT_NOTE_WHEN_GENERATED_FROM_REMAIN_TO_PAY') > 0) {
1332 $tva_tx = (float) getDolGlobalString('INVOICE_VAT_TO_USE_ON_CREDIT_NOTE_WHEN_GENERATED_FROM_REMAIN_TO_PAY');
1333 } else {
1334 $tva_tx = 0;
1335 }
1336
1337 $object->addline($langs->trans('invoiceAvoirLineWithPaymentRestAmount'), $remain_to_pay, 1, $tva_tx, 0, 0, 0, 0, '', '', 0, 0, 0, 'TTC');
1338 }
1339 }
1340
1341 // Add link between credit note and origin
1342 if (!empty($object->fk_facture_source) && $id > 0) {
1343 $facture_source->fetch($object->fk_facture_source);
1344 $facture_source->fetchObjectLinked();
1345
1346 if (!empty($facture_source->linkedObjectsIds)) {
1347 foreach ($facture_source->linkedObjectsIds as $sourcetype => $TIds) {
1348 $object->add_object_linked($sourcetype, current($TIds));
1349 }
1350 }
1351 }
1352 }
1353 }
1354
1355 // Standard invoice or Deposit invoice, created from a Predefined template invoice
1356 if ((GETPOST('type') == Facture::TYPE_STANDARD || GETPOST('type') == Facture::TYPE_DEPOSIT) && GETPOSTINT('fac_rec') > 0) {
1357 if (empty($dateinvoice)) {
1358 $error++;
1359 setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("Date")), null, 'errors');
1360 $action = 'create';
1361 } elseif ($dateinvoice > (dol_get_last_hour(dol_now('tzuserrel')) + getDolGlobalInt('INVOICE_MAX_FUTURE_DELAY'))) {
1362 $error++;
1363 setEventMessages($langs->trans("ErrorDateIsInFuture"), null, 'errors');
1364 $action = 'create';
1365 }
1366
1367
1368 if (getDolGlobalInt('INVOICE_SUBTYPE_ENABLED') && empty(GETPOST("subtype"))) {
1369 $error++;
1370 setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("InvoiceSubtype")), null, 'errors');
1371 $action = 'create';
1372 }
1373
1374 if (!$error) {
1375 $object->socid = GETPOSTINT('socid');
1376 $object->type = GETPOSTINT('type');
1377 $object->subtype = GETPOSTINT('subtype');
1378 $object->ref = GETPOST('ref');
1379 $object->date = $dateinvoice;
1380 $object->date_pointoftax = $date_pointoftax;
1381 $object->note_public = trim(GETPOST('note_public', 'restricthtml'));
1382 $object->note_private = trim(GETPOST('note_private', 'restricthtml'));
1383 $object->ref_customer = GETPOST('ref_client');
1384 $object->ref_client = $object->ref_customer;
1385 $object->model_pdf = GETPOST('model');
1386 $object->fk_project = GETPOSTINT('projectid');
1387 $object->cond_reglement_id = (GETPOSTINT('type') == 3 ? 1 : GETPOST('cond_reglement_id'));
1388 $object->mode_reglement_id = GETPOSTINT('mode_reglement_id');
1389 $object->fk_account = GETPOSTINT('fk_account');
1390 $object->amount = price2num(GETPOST('amount'));
1391 //$object->remise_absolue = price2num(GETPOST('remise_absolue'), 'MU');
1392 //$object->remise_percent = price2num(GETPOST('remise_percent'), '', 2);
1393 $object->fk_incoterms = GETPOSTINT('incoterm_id');
1394 $object->location_incoterms = GETPOST('location_incoterms', 'alpha');
1395 $object->multicurrency_code = GETPOST('multicurrency_code', 'alpha');
1396 $object->multicurrency_tx = GETPOSTINT('originmulticurrency_tx');
1397
1398 // Source facture
1399 $object->fac_rec = GETPOSTINT('fac_rec');
1400
1401 $id = $object->create($user); // This include recopy of links from recurring invoice and recurring invoice lines
1402 }
1403 }
1404
1405 // Standard or deposit invoice, not from a Predefined template invoice
1406 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) {
1407 $typeamount = GETPOST('typedeposit', 'aZ09');
1408 $valuestandardinvoice = price2num(str_replace('%', '', GETPOST('valuestandardinvoice', 'alpha')), 'MU');
1409 $valuedeposit = price2num(str_replace('%', '', GETPOST('valuedeposit', 'alpha')), 'MU');
1410
1411 if (GETPOSTINT('socid') < 1) {
1412 $error++;
1413 setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("Customer")), null, 'errors');
1414 $action = 'create';
1415 }
1416
1417 if (empty($dateinvoice)) {
1418 $error++;
1419 setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("Date")), null, 'errors');
1420 $action = 'create';
1421 } elseif ($dateinvoice > (dol_get_last_hour(dol_now('tzuserrel')) + getDolGlobalInt('INVOICE_MAX_FUTURE_DELAY'))) {
1422 $error++;
1423 setEventMessages($langs->trans("ErrorDateIsInFuture"), null, 'errors');
1424 $action = 'create';
1425 }
1426
1427
1428 if (GETPOST('type') == Facture::TYPE_STANDARD) {
1429 if ($valuestandardinvoice < 0 || $valuestandardinvoice > 100) {
1430 setEventMessages($langs->trans("ErrorAPercentIsRequired"), null, 'errors');
1431 $error++;
1432 $action = 'create';
1433 }
1434 } elseif (GETPOST('type') == Facture::TYPE_DEPOSIT) {
1435 if ($typeamount && !empty($origin) && !empty($originid)) {
1436 if ($typeamount == 'amount' && $valuedeposit <= 0) {
1437 setEventMessages($langs->trans("ErrorAnAmountWithoutTaxIsRequired"), null, 'errors');
1438 $error++;
1439 $action = 'create';
1440 }
1441 if ($typeamount == 'variable' && $valuedeposit <= 0) {
1442 setEventMessages($langs->trans("ErrorAPercentIsRequired"), null, 'errors');
1443 $error++;
1444 $action = 'create';
1445 }
1446 if ($typeamount == 'variablealllines' && $valuedeposit <= 0) {
1447 setEventMessages($langs->trans("ErrorAPercentIsRequired"), null, 'errors');
1448 $error++;
1449 $action = 'create';
1450 }
1451 }
1452 }
1453
1454
1455 if (getDolGlobalInt('INVOICE_SUBTYPE_ENABLED') && empty(GETPOST("subtype"))) {
1456 $error++;
1457 setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("InvoiceSubtype")), null, 'errors');
1458 $action = 'create';
1459 }
1460
1461 if (!$error) {
1462 $object->socid = GETPOSTINT('socid');
1463 $object->type = GETPOSTINT('type');
1464 $object->subtype = GETPOSTINT('subtype');
1465 $object->ref = GETPOST('ref');
1466 $object->date = $dateinvoice;
1467 $object->date_pointoftax = $date_pointoftax;
1468 $object->note_public = trim(GETPOST('note_public', 'restricthtml'));
1469 $object->note_private = trim(GETPOST('note_private', 'restricthtml'));
1470 $object->ref_client = GETPOST('ref_client');
1471 $object->ref_customer = GETPOST('ref_client');
1472 $object->model_pdf = GETPOST('model');
1473 $object->fk_project = GETPOSTINT('projectid');
1474 $object->cond_reglement_id = (GETPOSTINT('type') == 3 ? 1 : GETPOST('cond_reglement_id'));
1475 $object->mode_reglement_id = GETPOST('mode_reglement_id');
1476 $object->fk_account = GETPOSTINT('fk_account');
1477 $object->amount = price2num(GETPOST('amount'));
1478 //$object->remise_absolue = price2num(GETPOST('remise_absolue'), 'MU');
1479 //$object->remise_percent = price2num(GETPOST('remise_percent'), '', 2);
1480 $object->fk_incoterms = GETPOSTINT('incoterm_id');
1481 $object->location_incoterms = GETPOST('location_incoterms', 'alpha');
1482 $object->multicurrency_code = GETPOST('multicurrency_code', 'alpha');
1483 $object->multicurrency_tx = GETPOSTINT('originmulticurrency_tx');
1484
1485 if (GETPOST('type') == Facture::TYPE_SITUATION) {
1486 $object->situation_counter = 1;
1487 $object->situation_final = 0;
1488 $object->situation_cycle_ref = $object->newCycle();
1489 }
1490
1491 if (in_array($object->type, $retainedWarrantyInvoiceAvailableType)) {
1492 $object->retained_warranty = GETPOSTINT('retained_warranty');
1493 $object->retained_warranty_fk_cond_reglement = GETPOSTINT('retained_warranty_fk_cond_reglement');
1494 } else {
1495 $object->retained_warranty = 0;
1496 $object->retained_warranty_fk_cond_reglement = 0;
1497 }
1498
1499 $retained_warranty_date_limit = GETPOST('retained_warranty_date_limit');
1500 if (!empty($retained_warranty_date_limit) && dol_stringtotime($retained_warranty_date_limit)) {
1501 $object->retained_warranty_date_limit = dol_stringtotime($retained_warranty_date_limit);
1502 }
1503 $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);
1504
1505 $object->fetch_thirdparty();
1506
1507 // If creation from another object of another module (Example: origin=propal, originid=1)
1508 if (!empty($origin) && !empty($originid)) {
1509 $regs = array();
1510 // Parse element/subelement (ex: project_task)
1511 $element = $subelement = $origin;
1512 if (preg_match('/^([^_]+)_([^_]+)/i', $origin, $regs)) {
1513 $element = $regs[1];
1514 $subelement = $regs[2];
1515 }
1516
1517 // For compatibility
1518 if ($element == 'order') {
1519 $element = $subelement = 'commande';
1520 }
1521 if ($element == 'propal') {
1522 $element = 'comm/propal';
1523 $subelement = 'propal';
1524 }
1525 if ($element == 'contract') {
1526 $element = $subelement = 'contrat';
1527 }
1528 if ($element == 'inter') {
1529 $element = $subelement = 'ficheinter';
1530 }
1531 if ($element == 'shipping') {
1532 $element = $subelement = 'expedition';
1533 }
1534
1535 $object->origin = $origin; // deprecated
1536 $object->origin_type = $origin;
1537 $object->origin_id = $originid;
1538
1539 // Possibility to add external linked objects with hooks
1540 $object->linked_objects[$object->origin_type] = $object->origin_id;
1541 // link with order if it is a shipping invoice
1542 if ($object->origin == 'shipping') {
1543 require_once DOL_DOCUMENT_ROOT.'/expedition/class/expedition.class.php';
1544 $exp = new Expedition($db);
1545 $exp->fetch($object->origin_id);
1546 $exp->fetchObjectLinked();
1547 if (is_array($exp->linkedObjectsIds['commande']) && count($exp->linkedObjectsIds['commande']) > 0) {
1548 foreach ($exp->linkedObjectsIds['commande'] as $key => $value) {
1549 $object->linked_objects['commande'] = $value;
1550 }
1551 }
1552 }
1553
1554 if (GETPOSTISARRAY('other_linked_objects')) {
1555 $object->linked_objects = array_merge($object->linked_objects, GETPOST('other_linked_objects', 'array:int'));
1556 }
1557
1558 $id = $object->create($user); // This include class to add_object_linked() and add add_contact()
1559
1560 if ($id > 0) {
1561 dol_include_once('/'.$element.'/class/'.$subelement.'.class.php');
1562
1563 $classname = ucfirst($subelement);
1564 $srcobject = new $classname($db);
1565 '@phan-var-force CommonObject $srcobject';
1566
1567 dol_syslog("Try to find source object origin=".$object->origin." originid=".$object->origin_id." to add lines or deposit lines");
1568 $result = $srcobject->fetch($object->origin_id);
1569
1570 // If deposit invoice - down payment with 1 line (fixed amount or percent)
1571 if (GETPOST('type') == Facture::TYPE_DEPOSIT && in_array($typeamount, array('amount', 'variable'))) {
1572 // Define the array $amountdeposit
1573 $amountdeposit = array();
1574 if (getDolGlobalString('MAIN_DEPOSIT_MULTI_TVA')) {
1575 if ($typeamount == 'amount') {
1576 $amount = (float) $valuedeposit;
1577 } else {
1578 $amount = $srcobject->total_ttc * ((float) $valuedeposit / 100);
1579 }
1580
1581 $TTotalByTva = array();
1582 foreach ($srcobject->lines as &$line) {
1583 if (!empty($line->special_code)) {
1584 continue;
1585 }
1586 $TTotalByTva[$line->tva_tx] += $line->total_ttc;
1587 }
1588 '@phan-var-force array<string,float> $TTotalByTva';
1589
1590 $amount_ttc_diff = 0.;
1591 foreach ($TTotalByTva as $tva => &$total) {
1592 $coef = $total / $srcobject->total_ttc; // Calc coef
1593 $am = $amount * $coef;
1594 $amount_ttc_diff += $am;
1595 $amountdeposit[$tva] += $am / (1 + (float) $tva / 100); // Convert into HT for the addline
1596 }
1597 } else {
1598 if ($typeamount == 'amount') {
1599 $amountdeposit[0] = $valuedeposit;
1600 } elseif ($typeamount == 'variable') {
1601 if ($result > 0) {
1602 $totalamount = 0;
1603 $lines = $srcobject->lines;
1604 $numlines = count($lines);
1605 for ($i = 0; $i < $numlines; $i++) {
1606 $qualified = 1;
1607 if (empty($lines[$i]->qty)) {
1608 $qualified = 0; // We discard qty=0, it is an option
1609 }
1610 if (!empty($lines[$i]->special_code)) {
1611 $qualified = 0; // We discard special_code (frais port, ecotaxe, option, ...)
1612 }
1613 if ($qualified) {
1614 $totalamount += $lines[$i]->total_ht; // Fixme : is it not for the customer ? Shouldn't we take total_ttc ?
1615 $tva_tx = $lines[$i]->tva_tx;
1616 $amountdeposit[$tva_tx] += ($lines[$i]->total_ht * (float) $valuedeposit) / 100;
1617 }
1618 }
1619
1620 if ($totalamount == 0) {
1621 $amountdeposit[0] = 0;
1622 }
1623 } else {
1624 setEventMessages($srcobject->error, $srcobject->errors, 'errors');
1625 $error++;
1626 }
1627 }
1628
1629 $amount_ttc_diff = $amountdeposit[0];
1630 }
1631
1632 foreach ($amountdeposit as $tva => $amount) {
1633 if (empty($amount)) {
1634 continue;
1635 }
1636
1637 $arraylist = array(
1638 'amount' => 'FixAmount',
1639 'variable' => 'VarAmount'
1640 );
1641 $descline = '(DEPOSIT)';
1642 //$descline.= ' - '.$langs->trans($arraylist[$typeamount]);
1643 if ($typeamount == 'amount') {
1644 $descline .= ' ('.price($valuedeposit, 0, $langs, 0, - 1, - 1, (!empty($object->multicurrency_code) ? $object->multicurrency_code : $conf->currency)).')';
1645 } elseif ($typeamount == 'variable') {
1646 $descline .= ' ('.$valuedeposit.'%)';
1647 }
1648
1649 $descline .= ' - '.$srcobject->ref;
1650 $result = $object->addline(
1651 $descline,
1652 $amount, // subprice
1653 1, // quantity
1654 $tva, // vat rate
1655 0, // localtax1_tx
1656 0, // localtax2_tx
1657 getDolGlobalInt('INVOICE_PRODUCTID_DEPOSIT'), // fk_product
1658 0, // remise_percent
1659 0, // date_start
1660 0, // date_end
1661 0,
1662 $lines[$i]->info_bits, // info_bits
1663 0,
1664 'HT',
1665 0,
1666 0, // product_type
1667 1,
1668 $lines[$i]->special_code,
1669 $object->origin,
1670 0,
1671 0,
1672 0,
1673 0,
1674 '',
1675 array(), // array_options
1676 100,
1677 0,
1678 null,
1679 0,
1680 '',
1681 (!empty($conf->global->MAIN_DEPOSIT_MULTI_TVA) ? 0 : 1)
1682 );
1683 }
1684
1685 $diff = $object->total_ttc - $amount_ttc_diff;
1686
1687 if (getDolGlobalString('MAIN_DEPOSIT_MULTI_TVA') && $diff != 0) {
1688 $object->fetch_lines();
1689 $subprice_diff = $object->lines[0]->subprice - $diff / (1 + $object->lines[0]->tva_tx / 100);
1690 $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);
1691 }
1692 }
1693
1694 // standard invoice, credit note, or down payment from a percent of all lines
1695 if (GETPOST('type') != Facture::TYPE_DEPOSIT || (GETPOST('type') == Facture::TYPE_DEPOSIT && $typeamount == 'variablealllines')) {
1696 if ($result > 0) {
1697 $lines = $srcobject->lines;
1698 if (empty($lines) && method_exists($srcobject, 'fetch_lines')) {
1699 $srcobject->fetch_lines();
1700 $lines = $srcobject->lines;
1701 }
1702
1703 // If we create a standard invoice with a percent, we change amount by changing the qty
1704 if (GETPOST('type') == Facture::TYPE_STANDARD && $valuestandardinvoice > 0 && $valuestandardinvoice < 100) {
1705 if (is_array($lines)) {
1706 foreach ($lines as $line) {
1707 // We keep ->subprice and ->pa_ht, but we change the qty
1708 $line->qty = price2num((float) $line->qty * (float) $valuestandardinvoice / 100, 'MS');
1709 }
1710 }
1711 }
1712 // If we create a down payment with a percent on all lines, we change amount by changing the qty
1713 if (GETPOST('type') == Facture::TYPE_DEPOSIT && $typeamount == 'variablealllines') {
1714 if (is_array($lines)) {
1715 foreach ($lines as $line) {
1716 // We keep ->subprice and ->pa_ht, but we change the qty
1717 $line->qty = price2num((float) $line->qty * (float) $valuedeposit / 100, 'MS');
1718 }
1719 }
1720 }
1721
1722 $fk_parent_line = 0;
1723 $num = count($lines);
1724
1725 for ($i = 0; $i < $num; $i++) {
1726 if (!in_array($lines[$i]->id, $selectedLines)) {
1727 continue; // Skip unselected lines
1728 }
1729
1730 // Don't add lines with qty 0 when coming from a shipment including all order lines
1731 if ($srcobject->element == 'shipping' && getDolGlobalString('SHIPMENT_GETS_ALL_ORDER_PRODUCTS') && $lines[$i]->qty == 0) {
1732 continue;
1733 }
1734 // Don't add closed lines when coming from a contract (Set constant to '0,5' to exclude also inactive lines)
1735 if (!isset($conf->global->CONTRACT_EXCLUDE_SERVICES_STATUS_FOR_INVOICE)) {
1736 $conf->global->CONTRACT_EXCLUDE_SERVICES_STATUS_FOR_INVOICE = '5';
1737 }
1738 if ($srcobject->element == 'contrat' && in_array($lines[$i]->statut, explode(',', getDolGlobalString('CONTRACT_EXCLUDE_SERVICES_STATUS_FOR_INVOICE')))) {
1739 continue;
1740 }
1741
1742 $label = (!empty($lines[$i]->label) ? $lines[$i]->label : '');
1743 $desc = (!empty($lines[$i]->desc) ? $lines[$i]->desc : '');
1744
1745 if ($object->situation_counter == 1) {
1746 $lines[$i]->situation_percent = 0;
1747 }
1748
1749 if ($lines[$i]->subprice < 0 && !getDolGlobalString('INVOICE_KEEP_DISCOUNT_LINES_AS_IN_ORIGIN')) {
1750 // Negative line, we create a discount line
1751 if (empty($desc)) {
1752 $desc = $label ? $label : $langs->trans('Discount');
1753 }
1754
1755 $discount = new DiscountAbsolute($db);
1756 $discount->fk_soc = $object->socid;
1757 $discount->socid = $object->socid;
1758 $discount->amount_ht = abs($lines[$i]->total_ht);
1759 $discount->amount_tva = abs($lines[$i]->total_tva);
1760 $discount->amount_ttc = abs($lines[$i]->total_ttc);
1761 $discount->tva_tx = $lines[$i]->tva_tx;
1762 $discount->fk_user = $user->id;
1763 $discount->description = $desc;
1764 $discount->multicurrency_subprice = abs($lines[$i]->multicurrency_subprice);
1765 $discount->multicurrency_amount_ht = abs($lines[$i]->multicurrency_total_ht);
1766 $discount->multicurrency_amount_tva = abs($lines[$i]->multicurrency_total_tva);
1767 $discount->multicurrency_amount_ttc = abs($lines[$i]->multicurrency_total_ttc);
1768
1769 $discountid = $discount->create($user);
1770 if ($discountid > 0) {
1771 $result = $object->insert_discount($discountid); // This include link_to_invoice
1772 } else {
1773 setEventMessages($discount->error, $discount->errors, 'errors');
1774 $error++;
1775 break;
1776 }
1777 } else {
1778 // Positive line
1779 // we keep first type from product if exist, otherwise we keep type from line (free line) and at last default Product
1780 $product_type = $lines[$i]->product_type ?? ($lines[$i]->type ?? Product::TYPE_PRODUCT);
1781
1782 // Date start
1783 $date_start = false;
1784 if (isset($lines[$i]->date_debut_prevue)) {
1785 $date_start = $lines[$i]->date_debut_prevue;
1786 }
1787 if (isset($lines[$i]->date_debut_reel)) {
1788 $date_start = $lines[$i]->date_debut_reel;
1789 }
1790 if (isset($lines[$i]->date_start)) {
1791 $date_start = $lines[$i]->date_start;
1792 }
1793
1794 // Date end
1795 $date_end = false;
1796 if (isset($lines[$i]->date_fin_prevue)) {
1797 $date_end = $lines[$i]->date_fin_prevue;
1798 }
1799 if (isset($lines[$i]->date_fin_reel)) {
1800 $date_end = $lines[$i]->date_fin_reel;
1801 }
1802 if (isset($lines[$i]->date_end)) {
1803 $date_end = $lines[$i]->date_end;
1804 }
1805
1806 // Reset fk_parent_line for no child products and special product
1807 if (($lines[$i]->product_type != 9 && empty($lines[$i]->fk_parent_line)) || $lines[$i]->product_type == 9) {
1808 $fk_parent_line = 0;
1809 }
1810
1811 // Extrafields
1812 if (method_exists($lines[$i], 'fetch_optionals')) {
1813 $lines[$i]->fetch_optionals();
1814 $array_options = $lines[$i]->array_options;
1815 }
1816
1817 $tva_tx = $lines[$i]->tva_tx;
1818 if (!empty($lines[$i]->vat_src_code) && !preg_match('/\‍(/', $tva_tx)) {
1819 $tva_tx .= ' ('.$lines[$i]->vat_src_code.')';
1820 }
1821
1822 // View third's localtaxes for NOW and do not use value from origin.
1823 // TODO Is this really what we want ? Yes if source is template invoice but what if proposal or order ?
1824 $localtax1_tx = get_localtax($tva_tx, 1, $object->thirdparty);
1825 $localtax2_tx = get_localtax($tva_tx, 2, $object->thirdparty);
1826
1827 $result = $object->addline(
1828 $desc,
1829 $lines[$i]->subprice,
1830 $lines[$i]->qty,
1831 $tva_tx,
1832 $localtax1_tx,
1833 $localtax2_tx,
1834 $lines[$i]->fk_product,
1835 $lines[$i]->remise_percent,
1836 $date_start,
1837 $date_end,
1838 0,
1839 $lines[$i]->info_bits,
1840 isset($lines[$i]->fk_remise_except) ? $lines[$i]->fk_remise_except : null,
1841 'HT',
1842 0,
1843 $product_type,
1844 $lines[$i]->rang,
1845 $lines[$i]->special_code,
1846 $object->origin,
1847 $lines[$i]->rowid,
1848 $fk_parent_line,
1849 isset($lines[$i]->fk_fournprice) ? $lines[$i]->fk_fournprice : null,
1850 $lines[$i]->pa_ht,
1851 $label,
1852 $array_options,
1853 $lines[$i]->situation_percent ?? 100,
1854 $lines[$i]->fk_prev_id ?? 0,
1855 $lines[$i]->fk_unit,
1856 0,
1857 '',
1858 1
1859 );
1860
1861 if ($result > 0) {
1862 $lineid = $result;
1863 } else {
1864 $lineid = 0;
1865 $error++;
1866 break;
1867 }
1868
1869 // Defined the new fk_parent_line
1870 if ($result > 0 && $lines[$i]->product_type == 9) {
1871 $fk_parent_line = $result;
1872 }
1873 }
1874 }
1875 } else {
1876 setEventMessages($srcobject->error, $srcobject->errors, 'errors');
1877 $error++;
1878 }
1879 }
1880
1881 $object->update_price(1, 'auto', 0, $mysoc);
1882
1883 // Now we create same links to contact than the ones found on origin object
1884 /* Useless, already into the create
1885 if (getDolGlobalString('MAIN_PROPAGATE_CONTACTS_FROM_ORIGIN')) {
1886 $originforcontact = $object->origin;
1887 $originidforcontact = $object->origin_id;
1888 if ($originforcontact == 'shipping') // shipment and order share the same contacts. If creating from shipment we take data of order
1889 {
1890 $originforcontact=$srcobject->origin;
1891 $originidforcontact=$srcobject->origin_id;
1892 }
1893 $sqlcontact = "SELECT code, fk_socpeople FROM ".MAIN_DB_PREFIX."element_contact as ec, ".MAIN_DB_PREFIX."c_type_contact as ctc";
1894 $sqlcontact.= " WHERE element_id = ".((int) $originidforcontact)." AND ec.fk_c_type_contact = ctc.rowid AND ctc.element = '".$db->escape($originforcontact)."'";
1895
1896 $resqlcontact = $db->query($sqlcontact);
1897 if ($resqlcontact)
1898 {
1899 while($objcontact = $db->fetch_object($resqlcontact))
1900 {
1901 //print $objcontact->code.'-'.$objcontact->fk_socpeople."\n";
1902 $object->add_contact($objcontact->fk_socpeople, $objcontact->code);
1903 }
1904 }
1905 else dol_print_error($resqlcontact);
1906 }*/
1907
1908 // Hooks
1909 $parameters = array('origin_type' => $object->origin_type, 'origin_id' => $object->origin_id, 'objFrom' => $srcobject);
1910 $reshook = $hookmanager->executeHooks('createFrom', $parameters, $object, $action); // Note that $action and $object may have been
1911 // modified by hook
1912 if ($reshook < 0) {
1913 setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
1914 $error++;
1915 }
1916 } else {
1917 setEventMessages($object->error, $object->errors, 'errors');
1918 $error++;
1919 }
1920 } else { // If some invoice's lines coming from page
1921 $id = $object->create($user);
1922
1923 for ($i = 1; $i <= $NBLINES; $i++) {
1924 if (GETPOSTINT('idprod'.$i)) {
1925 $product = new Product($db);
1926 $product->fetch(GETPOSTINT('idprod'.$i));
1927 $startday = dol_mktime(12, 0, 0, GETPOST('date_start'.$i.'month'), GETPOST('date_start'.$i.'day'), GETPOST('date_start'.$i.'year'));
1928 $endday = dol_mktime(12, 0, 0, GETPOST('date_end'.$i.'month'), GETPOST('date_end'.$i.'day'), GETPOST('date_end'.$i.'year'));
1929 $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);
1930 }
1931 }
1932
1933 $object->update_price(1, 'auto', 0, $mysoc);
1934 }
1935 }
1936 }
1937
1938 // Situation invoices
1939 if (GETPOST('type') == Facture::TYPE_SITUATION && GETPOST('situations')) {
1940 if (empty($dateinvoice)) {
1941 $error++;
1942 $mesg = $langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("Date"));
1943 setEventMessages($mesg, null, 'errors');
1944 } elseif ($dateinvoice > (dol_get_last_hour(dol_now('tzuserrel')) + getDolGlobalInt('INVOICE_MAX_FUTURE_DELAY'))) {
1945 $error++;
1946 setEventMessages($langs->trans("ErrorDateIsInFuture"), null, 'errors');
1947 $action = 'create';
1948 }
1949
1950 if (!(GETPOSTINT('situations') > 0)) {
1951 $error++;
1952 $mesg = $langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("InvoiceSituation"));
1953 setEventMessages($mesg, null, 'errors');
1954 $action = 'create';
1955 }
1956
1957 if (!$error) {
1958 $result = $object->fetch(GETPOSTINT('situations'));
1959 $object->fk_facture_source = GETPOSTINT('situations');
1961
1962 if (!empty($origin) && !empty($originid)) {
1963 include_once DOL_DOCUMENT_ROOT.'/core/lib/price.lib.php';
1964
1965 $object->origin = $origin; // deprecated
1966 $object->origin_type = $origin;
1967 $object->origin_id = $originid;
1968
1969 // retained warranty
1970 if (getDolGlobalString('INVOICE_USE_RETAINED_WARRANTY')) {
1971 $retained_warranty = GETPOSTINT('retained_warranty');
1972 if (price2num($retained_warranty) > 0) {
1973 $object->retained_warranty = price2num($retained_warranty);
1974 }
1975
1976 if (GETPOSTINT('retained_warranty_fk_cond_reglement') > 0) {
1977 $object->retained_warranty_fk_cond_reglement = GETPOSTINT('retained_warranty_fk_cond_reglement');
1978 }
1979
1980 $retained_warranty_date_limit = GETPOST('retained_warranty_date_limit');
1981 if (!empty($retained_warranty_date_limit) && $db->jdate($retained_warranty_date_limit)) {
1982 $object->retained_warranty_date_limit = $db->jdate($retained_warranty_date_limit);
1983 }
1984 $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);
1985 }
1986
1987 foreach ($object->lines as $i => &$line) {
1988 $line->fk_prev_id = $line->id;
1989 $line->fetch_optionals();
1990 if (getDolGlobalInt('INVOICE_USE_SITUATION') == 2) {
1991 $line->situation_percent = $line->get_allprev_progress($object->id);; // get good progress including credit note
1992 } else {
1993 $line->situation_percent = $line->get_prev_progress($object->id); // get good progress including credit note
1994 }
1995
1996 // The $line->situation_percent has been modified, so we must recalculate all amounts
1997 $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);
1998 $line->total_ht = $tabprice[0];
1999 $line->total_tva = $tabprice[1];
2000 $line->total_ttc = $tabprice[2];
2001 $line->total_localtax1 = $tabprice[9];
2002 $line->total_localtax2 = $tabprice[10];
2003 $line->multicurrency_total_ht = $tabprice[16];
2004 $line->multicurrency_total_tva = $tabprice[17];
2005 $line->multicurrency_total_ttc = $tabprice[18];
2006
2007 // If fk_remise_except defined we check if the reduction has already been applied
2008 if ($line->fk_remise_except) {
2009 $discount = new DiscountAbsolute($line->db);
2010 $result = $discount->fetch($line->fk_remise_except);
2011 if ($result > 0) {
2012 // Check if discount not already affected to another invoice
2013 if ($discount->fk_facture_line > 0) {
2014 $line->fk_remise_except = 0;
2015 }
2016 }
2017 }
2018 }
2019 }
2020
2021 $object->fetch_thirdparty();
2022 $object->date = $dateinvoice;
2023 $object->date_pointoftax = $date_pointoftax;
2024 $object->note_public = trim(GETPOST('note_public', 'restricthtml'));
2025 $object->note = trim(GETPOST('note', 'restricthtml'));
2026 $object->note_private = trim(GETPOST('note', 'restricthtml'));
2027 $object->ref_client = GETPOST('ref_client', 'alpha');
2028 $object->ref_customer = GETPOST('ref_client', 'alpha');
2029 $object->model_pdf = GETPOST('model', 'alpha');
2030 $object->fk_project = GETPOSTINT('projectid');
2031 $object->cond_reglement_id = GETPOSTINT('cond_reglement_id');
2032 $object->mode_reglement_id = GETPOSTINT('mode_reglement_id');
2033 //$object->remise_absolue =price2num(GETPOST('remise_absolue'), 'MU', 2);
2034 //$object->remise_percent = price2num(GETPOST('remise_percent'), '', 2);
2035 $object->fk_account = GETPOSTINT('fk_account');
2036
2037
2038 // Special properties of replacement invoice
2039
2040 $object->situation_counter += 1;
2041
2042 $id = $object->createFromCurrent($user);
2043 if ($id <= 0) {
2044 $mesg = $object->error;
2045 } else {
2046 $nextSituationInvoice = new Facture($db);
2047 $nextSituationInvoice->fetch($id);
2048
2049 // create extrafields with data from create form
2050 $extrafields->fetch_name_optionals_label($nextSituationInvoice->table_element);
2051 $ret = $extrafields->setOptionalsFromPost(null, $nextSituationInvoice);
2052 if ($ret > 0) {
2053 $nextSituationInvoice->insertExtraFields();
2054 }
2055
2056 // Hooks
2057 $parameters = array('origin_type' => $object->origin_type, 'origin_id' => $object->origin_id);
2058 $reshook = $hookmanager->executeHooks('createFrom', $parameters, $nextSituationInvoice, $action); // Note that $action and $object may have been
2059 // modified by hook
2060 if ($reshook < 0) {
2061 setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
2062 $error++;
2063 }
2064 }
2065 }
2066 }
2067
2068 // End of object creation, we show it
2069 if ($id > 0 && !$error) {
2070 $db->commit();
2071
2072 // Define output language
2073 if (!getDolGlobalString('MAIN_DISABLE_PDF_AUTOUPDATE') && count($object->lines)) {
2074 $outputlangs = $langs;
2075 $newlang = '';
2076 if (getDolGlobalInt('MAIN_MULTILANGS') && empty($newlang) && GETPOST('lang_id', 'aZ09')) {
2077 $newlang = GETPOST('lang_id', 'aZ09');
2078 }
2079 if (getDolGlobalInt('MAIN_MULTILANGS') && empty($newlang)) {
2080 $newlang = $object->thirdparty->default_lang;
2081 }
2082 if (!empty($newlang)) {
2083 $outputlangs = new Translate("", $conf);
2084 $outputlangs->setDefaultLang($newlang);
2085 $outputlangs->load('products');
2086 }
2087 $model = $object->model_pdf;
2088 $ret = $object->fetch($id); // Reload to get new records
2089
2090 $result = $object->generateDocument($model, $outputlangs, $hidedetails, $hidedesc, $hideref);
2091 if ($result < 0) {
2092 setEventMessages($object->error, $object->errors, 'errors');
2093 }
2094 }
2095
2096 header('Location: '.$_SERVER["PHP_SELF"].'?facid='.$id);
2097 exit();
2098 } else {
2099 $db->rollback();
2100 $action = 'create';
2101 $_GET["origin"] = $_POST["origin"]; // Keep GET and POST here ?
2102 $_GET["originid"] = $_POST["originid"]; // Keep GET and POST here ?
2103 setEventMessages($object->error, $object->errors, 'errors');
2104 }
2105 } elseif ($action == 'addline' && GETPOST('submitforalllines', 'aZ09') && (GETPOST('alldate_start', 'alpha') || GETPOST('alldate_end', 'alpha')) && $usercancreate) {
2106 // Define date start and date end for all line
2107 $alldate_start = dol_mktime(GETPOST('alldate_starthour'), GETPOST('alldate_startmin'), 0, GETPOST('alldate_startmonth'), GETPOST('alldate_startday'), GETPOST('alldate_startyear'));
2108 $alldate_end = dol_mktime(GETPOST('alldate_endhour'), GETPOST('alldate_endmin'), 0, GETPOST('alldate_endmonth'), GETPOST('alldate_endday'), GETPOST('alldate_endyear'));
2109 foreach ($object->lines as $line) {
2110 if ($line->product_type == 1) { // only service line
2111 $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);
2112 }
2113 }
2114 } elseif ($action == 'addline' && GETPOST('submitforalllines', 'alpha') && GETPOST('vatforalllines', 'alpha') !== '' && $usercancreate) {
2115 // Define vat_rate
2116 $vat_rate = (GETPOST('vatforalllines') ? GETPOST('vatforalllines') : 0);
2117 $vat_rate = str_replace('*', '', $vat_rate);
2118 $localtax1_rate = get_localtax($vat_rate, 1, $object->thirdparty, $mysoc);
2119 $localtax2_rate = get_localtax($vat_rate, 2, $object->thirdparty, $mysoc);
2120 foreach ($object->lines as $line) {
2121 $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);
2122 }
2123 } elseif ($action == 'addline' && GETPOST('submitforalllines', 'alpha') && GETPOST('remiseforalllines', 'alpha') !== '' && $usercancreate) {
2124 // Define vat_rate
2125 $remise_percent = (GETPOST('remiseforalllines') ? GETPOST('remiseforalllines') : 0);
2126 $remise_percent = str_replace('*', '', $remise_percent);
2127 foreach ($object->lines as $line) {
2128 $tvatx= $line->tva_tx;
2129 if (!empty($line->vat_src_code)) {
2130 $tvatx .= ' ('.$line->vat_src_code.')';
2131 }
2132 $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);
2133 }
2134 } elseif ($action == 'addline' && !GETPOST('submitforalllines', 'alpha') && !GETPOST('submitforallmargins', 'alpha') && $usercancreate) { // Add a new line
2135 $langs->load('errors');
2136 $error = 0;
2137
2138 // Set if we used free entry or predefined product
2139 $predef = '';
2140 $product_desc = (GETPOSTISSET('dp_desc') ? GETPOST('dp_desc', 'restricthtml') : '');
2141
2142 $price_ht = '';
2143 $price_ht_devise = '';
2144 $price_ttc = '';
2145 $price_ttc_devise = '';
2146 $price_min = '';
2147 $price_min_ttc = '';
2148
2149 if (GETPOST('price_ht') !== '') {
2150 $price_ht = price2num(GETPOST('price_ht'), 'MU', 2);
2151 }
2152 if (GETPOST('multicurrency_price_ht') !== '') {
2153 $price_ht_devise = price2num(GETPOST('multicurrency_price_ht'), 'CU', 2);
2154 }
2155 if (GETPOST('price_ttc') !== '') {
2156 $price_ttc = price2num(GETPOST('price_ttc'), 'MU', 2);
2157 }
2158 if (GETPOST('multicurrency_price_ttc') !== '') {
2159 $price_ttc_devise = price2num(GETPOST('multicurrency_price_ttc'), 'CU', 2);
2160 }
2161
2162 $prod_entry_mode = GETPOST('prod_entry_mode', 'aZ09');
2163 if ($prod_entry_mode == 'free') {
2164 $idprod = 0;
2165 } else {
2166 $idprod = GETPOSTINT('idprod');
2167
2168 if (getDolGlobalString('MAIN_DISABLE_FREE_LINES') && $idprod <= 0) {
2169 setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("ProductOrService")), null, 'errors');
2170 $error++;
2171 }
2172 }
2173
2174 $tva_tx = GETPOST('tva_tx', 'alpha');
2175
2176 $qty = price2num(GETPOST('qty'.$predef, 'alpha'), 'MS', 2);
2177 $remise_percent = (GETPOSTISSET('remise_percent'.$predef) ? price2num(GETPOST('remise_percent'.$predef, 'alpha'), '', 2) : 0);
2178 if (empty($remise_percent)) {
2179 $remise_percent = 0;
2180 }
2181
2182 // Extrafields
2183 $extralabelsline = $extrafields->fetch_name_optionals_label($object->table_element_line);
2184 $array_options = $extrafields->getOptionalsFromPost($object->table_element_line, $predef);
2185 // Unset extrafield
2186 if (is_array($extralabelsline)) {
2187 // Get extra fields
2188 foreach ($extralabelsline as $key => $value) {
2189 unset($_POST["options_".$key.$predef]);
2190 }
2191 }
2192
2193 if ((empty($idprod) || $idprod < 0) && ($price_ht < 0) && ($qty < 0)) {
2194 setEventMessages($langs->trans('ErrorBothFieldCantBeNegative', $langs->transnoentitiesnoconv('UnitPriceHT'), $langs->transnoentitiesnoconv('Qty')), null, 'errors');
2195 $error++;
2196 }
2197 if (!$prod_entry_mode) {
2198 if (GETPOST('type') < 0 && !GETPOST('search_idprod')) {
2199 setEventMessages($langs->trans('ErrorChooseBetweenFreeEntryOrPredefinedProduct'), null, 'errors');
2200 $error++;
2201 }
2202 }
2203 if ($prod_entry_mode == 'free' && (empty($idprod) || $idprod < 0) && GETPOST('type') < 0) {
2204 setEventMessages($langs->trans('ErrorFieldRequired', $langs->transnoentitiesnoconv('Type')), null, 'errors');
2205 $error++;
2206 }
2207 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 ''
2208 if (($price_ht < 0 || $price_ttc < 0) && !getDolGlobalString('FACTURE_ENABLE_NEGATIVE_LINES')) {
2209 $langs->load("errors");
2210 if ($object->type == $object::TYPE_DEPOSIT) {
2211 // Using negative lines on deposit lead to headach and blocking problems when you want to consume them.
2212 setEventMessages($langs->trans("ErrorLinesCantBeNegativeOnDeposits"), null, 'errors');
2213 } else {
2214 setEventMessages($langs->trans("ErrorFieldCantBeNegativeOnInvoice", $langs->transnoentitiesnoconv("UnitPriceHT"), $langs->transnoentitiesnoconv("CustomerAbsoluteDiscountShort")), null, 'errors');
2215 }
2216 $error++;
2217 } else {
2218 setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("UnitPriceHT")), null, 'errors');
2219 $error++;
2220 }
2221 }
2222 if ($qty == '') {
2223 setEventMessages($langs->trans('ErrorFieldRequired', $langs->transnoentitiesnoconv('Qty')), null, 'errors');
2224 $error++;
2225 }
2226 if ($prod_entry_mode == 'free' && empty($idprod) && empty($product_desc)) {
2227 setEventMessages($langs->trans('ErrorFieldRequired', $langs->transnoentitiesnoconv('Description')), null, 'errors');
2228 $error++;
2229 }
2230 if ($qty < 0) {
2231 $langs->load("errors");
2232 setEventMessages($langs->trans('ErrorQtyForCustomerInvoiceCantBeNegative'), null, 'errors');
2233 $error++;
2234 }
2235
2236 if (!$error && isModEnabled('variants') && $prod_entry_mode != 'free') {
2237 if ($combinations = GETPOST('combinations', 'array')) {
2238 //Check if there is a product with the given combination
2239 $prodcomb = new ProductCombination($db);
2240
2241 if ($res = $prodcomb->fetchByProductCombination2ValuePairs($idprod, $combinations)) {
2242 $idprod = $res->fk_product_child;
2243 } else {
2244 setEventMessages($langs->trans('ErrorProductCombinationNotFound'), null, 'errors');
2245 $error++;
2246 }
2247 }
2248 }
2249
2250 if (!$error && ($qty >= 0) && (!empty($product_desc) || (!empty($idprod) && $idprod > 0))) {
2251 $ret = $object->fetch($id);
2252 if ($ret < 0) {
2253 dol_print_error($db, $object->error);
2254 exit();
2255 }
2256 $ret = $object->fetch_thirdparty();
2257
2258 // Clean parameters
2259 $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'));
2260 $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'));
2261 $price_base_type = (GETPOST('price_base_type', 'alpha') ? GETPOST('price_base_type', 'alpha') : 'HT');
2262 $tva_npr = "";
2263
2264 // Define special_code for special lines
2265 $special_code = 0;
2266 // if (!GETPOST(qty)) $special_code=3; // Options should not exists on invoices
2267
2268 // Replaces $pu with that of the product
2269 // Replaces $desc with that of the product
2270 // Replaces $base_price_type with that of the product
2271 // Replaces $fk_unit with that of the product
2272 if (!empty($idprod) && $idprod > 0) {
2273 $prod = new Product($db);
2274 $prod->fetch($idprod);
2275
2276 $label = ((GETPOST('product_label') && GETPOST('product_label') != $prod->label) ? GETPOST('product_label') : '');
2277
2278 // Search the correct price into loaded array product_price_by_qty using id of array retrieved into POST['pqp'].
2279 $pqp = (GETPOSTINT('pbq') ? GETPOSTINT('pbq') : 0);
2280
2281 $datapriceofproduct = $prod->getSellPrice($mysoc, $object->thirdparty, $pqp);
2282
2283 $pu_ht = $datapriceofproduct['pu_ht'];
2284 $pu_ttc = $datapriceofproduct['pu_ttc'];
2285 $price_min = $datapriceofproduct['price_min'];
2286 $price_min_ttc = (isset($datapriceofproduct['price_min_ttc'])) ? $datapriceofproduct['price_min_ttc'] : null;
2287 $price_base_type = empty($datapriceofproduct['price_base_type']) ? 'HT' : $datapriceofproduct['price_base_type'];
2288
2289 //$tva_tx = $datapriceofproduct['tva_tx'];
2290 //$tva_npr = $datapriceofproduct['tva_npr'];
2291 $tmpvat = (float) price2num(preg_replace('/\s*\‍(.*\‍)/', '', $tva_tx));
2292 $tmpprodvat = price2num(preg_replace('/\s*\‍(.*\‍)/', '', (string) $prod->tva_tx));
2293
2294 // Set unit price to use
2295 // TODO We should not have this
2296 if (!empty($price_ht) || $price_ht === '0') {
2297 $pu_ht = price2num($price_ht, 'MU');
2298 $pu_ttc = price2num((float) $pu_ht * (1 + ($tmpvat / 100)), 'MU');
2299 } elseif (!empty($price_ht_devise) || $price_ht_devise === '0') {
2300 $pu_ht_devise = price2num($price_ht_devise, 'MU');
2301 $pu_ht = '';
2302 $pu_ttc = '';
2303 } elseif (!empty($price_ttc) || $price_ttc === '0') {
2304 $pu_ttc = price2num($price_ttc, 'MU');
2305 $pu_ht = price2num((float) $pu_ttc / (1 + ($tmpvat / 100)), 'MU');
2306 } elseif ($tmpvat != $tmpprodvat) {
2307 // Is this still used ?
2308 if ($price_base_type != 'HT') {
2309 $pu_ht = price2num($pu_ttc / (1 + ($tmpvat / 100)), 'MU');
2310 } else {
2311 $pu_ttc = price2num($pu_ht * (1 + ($tmpvat / 100)), 'MU');
2312 }
2313 }
2314
2315 $desc = '';
2316
2317 // Define output language
2318 if (getDolGlobalInt('MAIN_MULTILANGS') && getDolGlobalString('PRODUIT_TEXTS_IN_THIRDPARTY_LANGUAGE')) {
2319 $outputlangs = $langs;
2320 $newlang = '';
2321 if (empty($newlang) && GETPOST('lang_id', 'aZ09')) {
2322 $newlang = GETPOST('lang_id', 'aZ09');
2323 }
2324 if (empty($newlang)) {
2325 $newlang = $object->thirdparty->default_lang;
2326 }
2327 if (!empty($newlang)) {
2328 $outputlangs = new Translate("", $conf);
2329 $outputlangs->setDefaultLang($newlang);
2330 $outputlangs->load('products');
2331 }
2332
2333 $desc = (!empty($prod->multilangs [$outputlangs->defaultlang] ["description"])) ? $prod->multilangs [$outputlangs->defaultlang] ["description"] : $prod->description;
2334 } else {
2335 $desc = $prod->description;
2336 }
2337
2338 //If text set in desc is the same as product descpription (as now it's preloaded) we add it only one time
2339 if ($product_desc == $desc && getDolGlobalString('PRODUIT_AUTOFILL_DESC')) {
2340 $product_desc = '';
2341 }
2342
2343 if (!empty($product_desc) && getDolGlobalString('MAIN_NO_CONCAT_DESCRIPTION')) {
2344 $desc = $product_desc;
2345 } else {
2346 $desc = dol_concatdesc($desc, $product_desc, '', getDolGlobalString('MAIN_CHANGE_ORDER_CONCAT_DESCRIPTION'));
2347 }
2348
2349 // Add custom code and origin country into description
2350 if (!getDolGlobalString('MAIN_PRODUCT_DISABLE_CUSTOMCOUNTRYCODE') && (!empty($prod->customcode) || !empty($prod->country_code))) {
2351 $tmptxt = '(';
2352 // Define output language
2353 if (getDolGlobalInt('MAIN_MULTILANGS') && getDolGlobalString('PRODUIT_TEXTS_IN_THIRDPARTY_LANGUAGE')) {
2354 $outputlangs = $langs;
2355 $newlang = '';
2356 if (empty($newlang) && GETPOST('lang_id', 'alpha')) {
2357 $newlang = GETPOST('lang_id', 'alpha');
2358 }
2359 if (empty($newlang)) {
2360 $newlang = $object->thirdparty->default_lang;
2361 }
2362 if (!empty($newlang)) {
2363 $outputlangs = new Translate("", $conf);
2364 $outputlangs->setDefaultLang($newlang);
2365 $outputlangs->load('products');
2366 }
2367 if (!empty($prod->customcode)) {
2368 $tmptxt .= $outputlangs->transnoentitiesnoconv("CustomCode").': '.$prod->customcode;
2369 }
2370 if (!empty($prod->customcode) && !empty($prod->country_code)) {
2371 $tmptxt .= ' - ';
2372 }
2373 if (!empty($prod->country_code)) {
2374 $tmptxt .= $outputlangs->transnoentitiesnoconv("CountryOrigin").': '.getCountry($prod->country_code, 0, $db, $outputlangs, 0);
2375 }
2376 } else {
2377 if (!empty($prod->customcode)) {
2378 $tmptxt .= $langs->transnoentitiesnoconv("CustomCode").': '.$prod->customcode;
2379 }
2380 if (!empty($prod->customcode) && !empty($prod->country_code)) {
2381 $tmptxt .= ' - ';
2382 }
2383 if (!empty($prod->country_code)) {
2384 $tmptxt .= $langs->transnoentitiesnoconv("CountryOrigin").': '.getCountry($prod->country_code, 0, $db, $langs, 0);
2385 }
2386 }
2387 $tmptxt .= ')';
2388 $desc = dol_concatdesc($desc, $tmptxt);
2389 }
2390
2391 $type = $prod->type;
2392 $fk_unit = $prod->fk_unit;
2393 } else {
2394 if (!empty($price_ht)) {
2395 $pu_ht = price2num($price_ht, 'MU');
2396 } else {
2397 $pu_ht = '';
2398 }
2399 if (!empty($price_ttc)) {
2400 $pu_ttc = price2num($price_ttc, 'MU');
2401 } else {
2402 $pu_ttc = '';
2403 }
2404 $tva_npr = (preg_match('/\*/', $tva_tx) ? 1 : 0);
2405 $tva_tx = str_replace('*', '', $tva_tx);
2406 if (empty($tva_tx)) {
2407 $tva_npr = 0;
2408 }
2409 $label = (GETPOST('product_label') ? GETPOST('product_label') : '');
2410 $desc = $product_desc;
2411 $type = GETPOST('type');
2412 $fk_unit = GETPOST('units', 'alpha');
2413
2414 if ($pu_ttc && !$pu_ht) {
2415 $price_base_type = 'TTC';
2416 }
2417 }
2418
2419 // Define info_bits
2420 $info_bits = 0;
2421 if ($tva_npr) {
2422 $info_bits |= 0x01;
2423 }
2424
2425 // Local Taxes
2426 $localtax1_tx = get_localtax($tva_tx, 1, $object->thirdparty, $mysoc, $tva_npr);
2427 $localtax2_tx = get_localtax($tva_tx, 2, $object->thirdparty, $mysoc, $tva_npr);
2428
2429 $pu_ht_devise = price2num($price_ht_devise, '', 2);
2430 $pu_ttc_devise = price2num($price_ttc_devise, '', 2);
2431
2432 // Prepare a price equivalent for minimum price check
2433 $pu_equivalent = $pu_ht;
2434 $pu_equivalent_ttc = $pu_ttc;
2435
2436 $currency_tx = $object->multicurrency_tx;
2437
2438 // Check if we have a foreign currency
2439 // If so, we update the pu_equiv as the equivalent price in base currency
2440 if ($pu_ht == '' && $pu_ht_devise != '' && $currency_tx != '') {
2441 $pu_equivalent = (float) $pu_ht_devise * $currency_tx;
2442 }
2443 if ($pu_ttc == '' && $pu_ttc_devise != '' && $currency_tx != '') {
2444 $pu_equivalent_ttc = (float) $pu_ttc_devise * $currency_tx;
2445 }
2446
2447 // TODO $pu_equivalent or $pu_equivalent_ttc must be calculated from the one not null taking into account all taxes
2448 /*
2449 if ($pu_equivalent) {
2450 $tmp = calcul_price_total(1, $pu_equivalent, 0, $tva_tx, -1, -1, 0, 'HT', $info_bits, $type);
2451 $pu_equivalent_ttc = ...
2452 } else {
2453 $tmp = calcul_price_total(1, $pu_equivalent_ttc, 0, $tva_tx, -1, -1, 0, 'TTC', $info_bits, $type);
2454 $pu_equivalent_ht = ...
2455 }
2456 */
2457
2458 // Margin
2459 $fournprice = price2num(GETPOST('fournprice'.$predef) ? GETPOST('fournprice'.$predef) : '');
2460 $buyingprice = price2num(GETPOST('buying_price'.$predef) != '' ? GETPOST('buying_price'.$predef) : ''); // If buying_price is '0', we must keep this value
2461
2462
2463 $price2num_pu_ht = price2num($pu_ht);
2464 $price2num_remise_percent = price2num($remise_percent);
2465 $price2num_price_min = price2num($price_min);
2466 $price2num_price_min_ttc = price2num($price_min_ttc);
2467 if (empty($price2num_pu_ht)) {
2468 $price2num_pu_ht = 0;
2469 }
2470 if (empty($price2num_remise_percent)) {
2471 $price2num_remise_percent = 0;
2472 }
2473 if (empty($price2num_price_min)) {
2474 $price2num_price_min = 0;
2475 }
2476 if (empty($price2num_price_min_ttc)) {
2477 $price2num_price_min_ttc = 0;
2478 }
2479
2480 // Check price is not lower than minimum (check is done only for standard or replacement invoices)
2481 if ($usermustrespectpricemin && ($object->type == Facture::TYPE_STANDARD || $object->type == Facture::TYPE_REPLACEMENT)) {
2482 if ($pu_equivalent && $price_min && (((float) price2num($pu_equivalent) * (1 - $remise_percent / 100)) < (float) price2num($price_min)) && $price_base_type == 'HT') {
2483 $mesg = $langs->trans("CantBeLessThanMinPrice", price(price2num($price_min, 'MU'), 0, $langs, 0, 0, -1, $conf->currency));
2484 setEventMessages($mesg, null, 'errors');
2485 $error++;
2486 } 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') {
2487 $mesg = $langs->trans("CantBeLessThanMinPriceInclTax", price(price2num($price_min_ttc, 'MU'), 0, $langs, 0, 0, -1, $conf->currency));
2488 setEventMessages($mesg, null, 'errors');
2489 $error++;
2490 }
2491 }
2492
2493 if (!$error) {
2494 '@phan-var-force array<string,mixed> $lines';
2495 // Add batchinfo if the detail_batch array is defined
2496 if (isModEnabled('productbatch') && !empty($lines[$i]->detail_batch) && is_array($lines[$i]->detail_batch) && getDolGlobalString('INVOICE_INCUDE_DETAILS_OF_LOTS_SERIALS')) {
2497 $langs->load('productbatch');
2498 foreach ($lines[$i]->detail_batch as $batchline) {
2499 $desc .= ' '.$langs->trans('Batch').' '.$batchline->batch.' '.$langs->trans('printQty', $batchline->qty).' ';
2500 }
2501 }
2502
2503 // Insert line
2504 $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);
2505
2506 if ($result > 0) {
2507 // Define output language and generate document
2508 if (!getDolGlobalString('MAIN_DISABLE_PDF_AUTOUPDATE')) {
2509 $outputlangs = $langs;
2510 $newlang = '';
2511 if (getDolGlobalInt('MAIN_MULTILANGS') && empty($newlang) && GETPOST('lang_id', 'aZ09')) {
2512 $newlang = GETPOST('lang_id', 'aZ09');
2513 }
2514 if (getDolGlobalInt('MAIN_MULTILANGS') && empty($newlang)) {
2515 $newlang = $object->thirdparty->default_lang;
2516 }
2517 if (!empty($newlang)) {
2518 $outputlangs = new Translate("", $conf);
2519 $outputlangs->setDefaultLang($newlang);
2520 $outputlangs->load('products');
2521 }
2522 $model = $object->model_pdf;
2523 $ret = $object->fetch($id); // Reload to get new records
2524
2525 $result = $object->generateDocument($model, $outputlangs, $hidedetails, $hidedesc, $hideref);
2526 if ($result < 0) {
2527 setEventMessages($object->error, $object->errors, 'errors');
2528 }
2529 }
2530
2531 unset($_POST['prod_entry_mode']);
2532 unset($_POST['qty']);
2533 unset($_POST['type']);
2534 unset($_POST['remise_percent']);
2535 unset($_POST['price_ht']);
2536 unset($_POST['multicurrency_price_ht']);
2537 unset($_POST['price_ttc']);
2538 unset($_POST['tva_tx']);
2539 unset($_POST['product_ref']);
2540 unset($_POST['product_label']);
2541 unset($_POST['product_desc']);
2542 unset($_POST['fournprice']);
2543 unset($_POST['buying_price']);
2544 unset($_POST['np_marginRate']);
2545 unset($_POST['np_markRate']);
2546 unset($_POST['dp_desc']);
2547 unset($_POST['idprod']);
2548 unset($_POST['units']);
2549 unset($_POST['date_starthour']);
2550 unset($_POST['date_startmin']);
2551 unset($_POST['date_startsec']);
2552 unset($_POST['date_startday']);
2553 unset($_POST['date_startmonth']);
2554 unset($_POST['date_startyear']);
2555 unset($_POST['date_endhour']);
2556 unset($_POST['date_endmin']);
2557 unset($_POST['date_endsec']);
2558 unset($_POST['date_endday']);
2559 unset($_POST['date_endmonth']);
2560 unset($_POST['date_endyear']);
2561 unset($_POST['situations']);
2562 unset($_POST['progress']);
2563 } else {
2564 setEventMessages($object->error, $object->errors, 'errors');
2565 }
2566
2567 $action = '';
2568 }
2569 }
2570 } elseif ($action == 'updateline' && $usercancreate && !GETPOST('cancel', 'alpha')) {
2571 if (!$object->fetch($id) > 0) {
2572 dol_print_error($db);
2573 }
2574 $object->fetch_thirdparty();
2575
2576 // Clean parameters
2577 $date_start = '';
2578 $date_end = '';
2579 $date_start = dol_mktime(GETPOST('date_starthour'), GETPOST('date_startmin'), GETPOST('date_startsec'), GETPOST('date_startmonth'), GETPOST('date_startday'), GETPOST('date_startyear'));
2580 $date_end = dol_mktime(GETPOST('date_endhour'), GETPOST('date_endmin'), GETPOST('date_endsec'), GETPOST('date_endmonth'), GETPOST('date_endday'), GETPOST('date_endyear'));
2581 $description = dol_htmlcleanlastbr(GETPOST('product_desc', 'restricthtml') ? GETPOST('product_desc', 'restricthtml') : GETPOST('desc', 'restricthtml'));
2582 $vat_rate = (GETPOST('tva_tx') ? GETPOST('tva_tx') : 0);
2583 $vat_rate = str_replace('*', '', $vat_rate);
2584
2585 $pu_ht = price2num(GETPOST('price_ht'), '', 2);
2586 $pu_ttc = price2num(GETPOST('price_ttc'), '', 2);
2587
2588 $pu_ht_devise = price2num(GETPOST('multicurrency_subprice'), '', 2);
2589 $pu_ttc_devise = price2num(GETPOST('multicurrency_subprice_ttc'), '', 2);
2590
2591 $qty = price2num(GETPOST('qty', 'alpha'), 'MS');
2592
2593 // Define info_bits
2594 $info_bits = 0;
2595 if (preg_match('/\*/', $vat_rate)) {
2596 $info_bits |= 0x01;
2597 }
2598
2599 // Define vat_rate
2600 $vat_rate = str_replace('*', '', $vat_rate);
2601 $localtax1_rate = get_localtax($vat_rate, 1, $object->thirdparty);
2602 $localtax2_rate = get_localtax($vat_rate, 2, $object->thirdparty);
2603
2604 // Add buying price
2605 $fournprice = price2num(GETPOST('fournprice') ? GETPOST('fournprice') : '');
2606 $buyingprice = price2num(GETPOST('buying_price') != '' ? GETPOST('buying_price') : ''); // If buying_price is '0', we must keep this value
2607
2608 // Prepare a price equivalent for minimum price check
2609 $pu_equivalent = $pu_ht;
2610 $pu_equivalent_ttc = $pu_ttc;
2611
2612 $currency_tx = $object->multicurrency_tx;
2613
2614 // Check if we have a foreign currency
2615 // If so, we update the pu_equiv as the equivalent price in base currency
2616 if ($pu_ht == '' && $pu_ht_devise != '' && $currency_tx != '') {
2617 $pu_equivalent = (float) $pu_ht_devise * (float) $currency_tx;
2618 }
2619 if ($pu_ttc == '' && $pu_ttc_devise != '' && $currency_tx != '') {
2620 $pu_equivalent_ttc = (float) $pu_ttc_devise * (float) $currency_tx;
2621 }
2622
2623 // TODO $pu_equivalent or $pu_equivalent_ttc must be calculated from the one not null taking into account all taxes
2624 /*
2625 if ($pu_equivalent) {
2626 $tmp = calcul_price_total(1, $pu_equivalent, 0, $vat_rate, -1, -1, 0, 'HT', $info_bits, $type);
2627 $pu_equivalent_ttc = ...
2628 } else {
2629 $tmp = calcul_price_total(1, $pu_equivalent_ttc, 0, $vat_rate, -1, -1, 0, 'TTC', $info_bits, $type);
2630 $pu_equivalent_ht = ...
2631 }
2632 */
2633
2634 // Extrafields
2635 $extralabelsline = $extrafields->fetch_name_optionals_label($object->table_element_line);
2636 $array_options = $extrafields->getOptionalsFromPost($object->table_element_line);
2637 // Unset extrafield
2638 if (is_array($extralabelsline)) {
2639 // Get extra fields
2640 foreach ($extralabelsline as $key => $value) {
2641 unset($_POST["options_".$key]);
2642 }
2643 }
2644
2645 // Define special_code for special lines
2646 $special_code = GETPOSTINT('special_code');
2647 if ($special_code == 3) {
2648 $special_code = 0; // Options should not exists on invoices
2649 }
2650
2651 $line = new FactureLigne($db);
2652 $line->fetch(GETPOSTINT('lineid'));
2653 $percent = $line->get_prev_progress($object->id);
2654 $progress = price2num(GETPOST('progress', 'alpha'));
2655
2656 if ($object->type == Facture::TYPE_CREDIT_NOTE && $object->situation_cycle_ref > 0) {
2657 // in case of situation credit note
2658 if ($progress >= 0) {
2659 $mesg = $langs->trans("CantBeNullOrPositive");
2660 setEventMessages($mesg, null, 'warnings');
2661 $error++;
2662 $result = -1;
2663 } elseif ($progress < $line->situation_percent) { // TODO : use a modified $line->get_prev_progress($object->id) result
2664 $mesg = $langs->trans("CantBeLessThanMinPercent");
2665 setEventMessages($mesg, null, 'warnings');
2666 $error++;
2667 $result = -1;
2668 } elseif ($progress < $percent) {
2669 $mesg = '<div class="warning">'.$langs->trans("CantBeLessThanMinPercent").'</div>';
2670 setEventMessages($mesg, null, 'warnings');
2671 $error++;
2672 $result = -1;
2673 }
2674 }
2675
2676 $remise_percent = price2num(GETPOST('remise_percent'), '', 2);
2677
2678 // Check minimum price
2679 $productid = GETPOSTINT('productid');
2680 if (!empty($productid)) {
2681 $product = new Product($db);
2682 $product->fetch($productid);
2683
2684 $type = $product->type;
2685
2686 $price_min = $product->price_min;
2687 if ((getDolGlobalString('PRODUIT_MULTIPRICES') || getDolGlobalString('PRODUIT_CUSTOMER_PRICES_BY_QTY_MULTIPRICES')) && !empty($object->thirdparty->price_level)) {
2688 $price_min = $product->multiprices_min[$object->thirdparty->price_level];
2689 }
2690 $price_min_ttc = $product->price_min_ttc;
2691 if ((getDolGlobalString('PRODUIT_MULTIPRICES') || getDolGlobalString('PRODUIT_CUSTOMER_PRICES_BY_QTY_MULTIPRICES')) && !empty($object->thirdparty->price_level)) {
2692 $price_min_ttc = $product->multiprices_min_ttc[$object->thirdparty->price_level];
2693 }
2694
2695 $label = ((GETPOST('update_label') && GETPOST('product_label')) ? GETPOST('product_label') : '');
2696
2697 // Check price is not lower than minimum (check is done only for standard or replacement invoices)
2698 if ($usermustrespectpricemin && ($object->type == Facture::TYPE_STANDARD || $object->type == Facture::TYPE_REPLACEMENT)) {
2699 if ($pu_equivalent && $price_min && (((float) price2num($pu_equivalent) * (1 - (float) $remise_percent / 100)) < (float) price2num($price_min)) && $price_base_type == 'HT') {
2700 $mesg = $langs->trans("CantBeLessThanMinPrice", price(price2num($price_min, 'MU'), 0, $langs, 0, 0, -1, $conf->currency));
2701 setEventMessages($mesg, null, 'errors');
2702 $error++;
2703 $action = 'editline';
2704 } 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') {
2705 $mesg = $langs->trans("CantBeLessThanMinPriceInclTax", price(price2num($price_min_ttc, 'MU'), 0, $langs, 0, 0, -1, $conf->currency));
2706 setEventMessages($mesg, null, 'errors');
2707 $error++;
2708 $action = 'editline';
2709 }
2710 }
2711 } else {
2712 $type = GETPOST('type');
2713 $label = (GETPOST('product_label') ? GETPOST('product_label') : '');
2714
2715 // Check parameters
2716 if (GETPOST('type') < 0) {
2717 setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("Type")), null, 'errors');
2718 $error++;
2719 }
2720 }
2721 if ($qty < 0) {
2722 $langs->load("errors");
2723 setEventMessages($langs->trans('ErrorQtyForCustomerInvoiceCantBeNegative'), null, 'errors');
2724 $error++;
2725 }
2726 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 ''
2727 if (($pu_ht < 0 || $pu_ttc < 0) && !getDolGlobalString('FACTURE_ENABLE_NEGATIVE_LINES')) {
2728 $langs->load("errors");
2729 if ($object->type == $object::TYPE_DEPOSIT) {
2730 // Using negative lines on deposit lead to headach and blocking problems when you want to consume them.
2731 setEventMessages($langs->trans("ErrorLinesCantBeNegativeOnDeposits"), null, 'errors');
2732 } else {
2733 setEventMessages($langs->trans("ErrorFieldCantBeNegativeOnInvoice", $langs->transnoentitiesnoconv("UnitPriceHT"), $langs->transnoentitiesnoconv("CustomerAbsoluteDiscountShort")), null, 'errors');
2734 }
2735 $error++;
2736 } else {
2737 setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("UnitPriceHT")), null, 'errors');
2738 $error++;
2739 }
2740 }
2741
2742 // Invoice situation
2743 if (getDolGlobalInt('INVOICE_USE_SITUATION') == 2) {
2744 $previousprogress = $line->get_allprev_progress($line->fk_facture);
2745 $fullprogress = price2num(GETPOST('progress', 'alpha'));
2746
2747 if ($fullprogress < $previousprogress) {
2748 $error++;
2749 setEventMessages($langs->trans('CantBeLessThanMinPercent'), null, 'errors');
2750 }
2751
2752 // Max 100%
2753 if ($fullprogress > 100) {
2754 $fullprogress = 100;
2755 }
2756 $addprogress = $fullprogress - $previousprogress;
2757 } else {
2758 $addprogress = price2num(GETPOST('progress', 'alpha'));
2759 }
2760
2761 // Update line
2762 if (!$error) {
2763 if (empty($usercancreatemargin)) {
2764 foreach ($object->lines as &$line) {
2765 if ($line->id == GETPOSTINT('lineid')) {
2766 $fournprice = $line->fk_fournprice;
2767 $buyingprice = $line->pa_ht;
2768 break;
2769 }
2770 }
2771 }
2772
2773 $price_base_type = 'HT';
2774 $pu = $pu_ht;
2775 if (empty($pu) && !empty($pu_ttc)) {
2776 $pu = $pu_ttc;
2777 $price_base_type = 'TTC';
2778 }
2779
2780 $result = $object->updateline(
2781 GETPOSTINT('lineid'),
2782 $description,
2783 $pu,
2784 $qty,
2785 $remise_percent,
2786 $date_start,
2787 $date_end,
2788 $vat_rate,
2789 $localtax1_rate,
2790 $localtax2_rate,
2791 $price_base_type,
2792 $info_bits,
2793 $type,
2794 GETPOSTINT('fk_parent_line'),
2795 0,
2796 $fournprice,
2797 $buyingprice,
2798 $label,
2799 $special_code,
2800 $array_options,
2801 $addprogress,
2802 GETPOST('units', 'alpha'),
2803 $pu_ht_devise
2804 );
2805
2806 if ($result >= 0) {
2807 if (!getDolGlobalString('MAIN_DISABLE_PDF_AUTOUPDATE')) {
2808 // Define output language
2809 $outputlangs = $langs;
2810 $newlang = '';
2811 if (getDolGlobalInt('MAIN_MULTILANGS') && empty($newlang) && GETPOST('lang_id', 'aZ09')) {
2812 $newlang = GETPOST('lang_id', 'aZ09');
2813 }
2814 if (getDolGlobalInt('MAIN_MULTILANGS') && empty($newlang)) {
2815 $newlang = $object->thirdparty->default_lang;
2816 }
2817 if (!empty($newlang)) {
2818 $outputlangs = new Translate("", $conf);
2819 $outputlangs->setDefaultLang($newlang);
2820 $outputlangs->load('products');
2821 }
2822
2823 $ret = $object->fetch($id); // Reload to get new records
2824 $object->generateDocument($object->model_pdf, $outputlangs, $hidedetails, $hidedesc, $hideref);
2825 }
2826
2827 unset($_POST['qty']);
2828 unset($_POST['type']);
2829 unset($_POST['productid']);
2830 unset($_POST['remise_percent']);
2831 unset($_POST['price_ht']);
2832 unset($_POST['multicurrency_price_ht']);
2833 unset($_POST['price_ttc']);
2834 unset($_POST['tva_tx']);
2835 unset($_POST['product_ref']);
2836 unset($_POST['product_label']);
2837 unset($_POST['product_desc']);
2838 unset($_POST['fournprice']);
2839 unset($_POST['buying_price']);
2840 unset($_POST['np_marginRate']);
2841 unset($_POST['np_markRate']);
2842 unset($_POST['dp_desc']);
2843 unset($_POST['idprod']);
2844 unset($_POST['units']);
2845 unset($_POST['date_starthour']);
2846 unset($_POST['date_startmin']);
2847 unset($_POST['date_startsec']);
2848 unset($_POST['date_startday']);
2849 unset($_POST['date_startmonth']);
2850 unset($_POST['date_startyear']);
2851 unset($_POST['date_endhour']);
2852 unset($_POST['date_endmin']);
2853 unset($_POST['date_endsec']);
2854 unset($_POST['date_endday']);
2855 unset($_POST['date_endmonth']);
2856 unset($_POST['date_endyear']);
2857 unset($_POST['situations']);
2858 unset($_POST['progress']);
2859 } else {
2860 setEventMessages($object->error, $object->errors, 'errors');
2861 }
2862 }
2863 } elseif ($action == 'updatealllines' && $usercancreate && GETPOST('all_percent') == $langs->trans('Modifier')) { // Update all lines of situation invoice
2864 if (!$object->fetch($id) > 0) {
2865 dol_print_error($db);
2866 }
2867 if (GETPOST('all_progress') != "") {
2868 $all_progress = GETPOSTINT('all_progress');
2869 foreach ($object->lines as $line) {
2870 if (getDolGlobalInt('INVOICE_USE_SITUATION') == 2) {
2871 $percent = $line->get_allprev_progress($object->id);
2872 } else {
2873 $percent = $line->get_prev_progress($object->id);
2874 }
2875 if ((float) $all_progress < (float) $percent) {
2876 $mesg = $langs->trans("Line").' '.$i.' : '.$langs->trans("CantBeLessThanMinPercent");
2877 setEventMessages($mesg, null, 'warnings');
2878 $result = -1;
2879 } else {
2880 $object->update_percent($line, GETPOST('all_progress'), false);
2881 }
2882 }
2883 $object->update_price(1);
2884 }
2885 } elseif ($action == 'updateline' && $usercancreate && !$cancel) {
2886 header('Location: '.$_SERVER["PHP_SELF"].'?facid='.$id); // To show again edited page
2887 exit();
2888 } elseif ($action == 'confirm_situationout' && $confirm == 'yes' && $usercancreate) {
2889 // Outing situation invoice from cycle
2890 $object->fetch($id, '', '', 0, true);
2891
2892 if (in_array($object->status, array(Facture::STATUS_CLOSED, Facture::STATUS_VALIDATED))
2894 && $usercancreate
2895 && !$objectidnext
2896 && $object->is_last_in_cycle()
2897 && $usercanunvalidate
2898 ) {
2899 $outingError = 0;
2900 $newCycle = $object->newCycle(); // we need to keep the "situation behavior" so we place it on a new situation cycle
2901 if ($newCycle > 1) {
2902 // Search credit notes
2903 $lastCycle = $object->situation_cycle_ref;
2904 $lastSituationCounter = $object->situation_counter;
2905 $linkedCreditNotesList = array();
2906
2907 if (count($object->tab_next_situation_invoice) > 0) {
2908 foreach ($object->tab_next_situation_invoice as $next_invoice) {
2909 if ($next_invoice->type == Facture::TYPE_CREDIT_NOTE
2910 && $next_invoice->situation_counter == $object->situation_counter
2911 && $next_invoice->fk_facture_source == $object->id
2912 ) {
2913 $linkedCreditNotesList[] = $next_invoice->id;
2914 }
2915 }
2916 }
2917
2918 $object->situation_cycle_ref = $newCycle;
2919 $object->situation_counter = 1;
2920 $object->situation_final = 0;
2921 if ($object->update($user) > 0) {
2922 $errors = 0;
2923 if (count($linkedCreditNotesList) > 0) {
2924 // now, credit note must follow
2925 $sql = 'UPDATE '.MAIN_DB_PREFIX.'facture';
2926 $sql .= ' SET situation_cycle_ref = '.((int) $newCycle);
2927 $sql .= ' , situation_final=0';
2928 $sql .= ' , situation_counter='.((int) $object->situation_counter);
2929 $sql .= ' WHERE rowid IN ('.$db->sanitize(implode(',', $linkedCreditNotesList)).')';
2930
2931 $resql = $db->query($sql);
2932 if (!$resql) {
2933 $errors++;
2934 }
2935
2936 // Change each progression percent on each lines
2937 foreach ($object->lines as $line) {
2938 // no traitement for special product
2939 if ($line->product_type == 9) {
2940 continue;
2941 }
2942
2943
2944 if (!empty($object->tab_previous_situation_invoice)) {
2945 // search the last invoice in cycle
2946 $lineIndex = count($object->tab_previous_situation_invoice) - 1;
2947 $searchPreviousInvoice = true;
2948 while ($searchPreviousInvoice) {
2949 if ($object->tab_previous_situation_invoice[$lineIndex]->type == Facture::TYPE_SITUATION || $lineIndex < 1) {
2950 $searchPreviousInvoice = false; // find, exit;
2951 break;
2952 } else {
2953 $lineIndex--; // go to previous invoice in cycle
2954 }
2955 }
2956
2957
2958 $maxPrevSituationPercent = 0;
2959 foreach ($object->tab_previous_situation_invoice[$lineIndex]->lines as $prevLine) {
2960 if ($prevLine->id == $line->fk_prev_id) {
2961 $maxPrevSituationPercent = max($maxPrevSituationPercent, $prevLine->situation_percent);
2962 }
2963 }
2964
2965
2966 $line->situation_percent -= $maxPrevSituationPercent;
2967
2968 if ($line->update() < 0) {
2969 $errors++;
2970 }
2971 }
2972 }
2973 }
2974
2975 if (!$errors) {
2976 setEventMessages($langs->trans('Updated'), null, 'mesgs');
2977 header("Location: ".$_SERVER['PHP_SELF']."?id=".$id);
2978 } else {
2979 setEventMessages($langs->trans('ErrorOutingSituationInvoiceCreditNote'), array(), 'errors');
2980 }
2981 } else {
2982 setEventMessages($langs->trans('ErrorOutingSituationInvoiceOnUpdate'), array(), 'errors');
2983 }
2984 } else {
2985 setEventMessages($langs->trans('ErrorFindNextSituationInvoice'), array(), 'errors');
2986 }
2987 }
2988 } elseif ($action == 'import_lines_from_object' && $usercancreate && $object->status == Facture::STATUS_DRAFT
2990 // add lines from objectlinked
2991 $fromElement = GETPOST('fromelement');
2992 $fromElementid = GETPOST('fromelementid');
2993 $importLines = GETPOST('line_checkbox');
2994
2995 if (!empty($importLines) && is_array($importLines) && !empty($fromElement) && ctype_alpha($fromElement) && !empty($fromElementid)) {
2996 if ($fromElement == 'commande') {
2997 dol_include_once('/'.$fromElement.'/class/'.$fromElement.'.class.php');
2998 $lineClassName = 'OrderLine';
2999 } elseif ($fromElement == 'propal') {
3000 dol_include_once('/comm/'.$fromElement.'/class/'.$fromElement.'.class.php');
3001 $lineClassName = 'PropaleLigne';
3002 }
3003 $nextRang = count($object->lines) + 1;
3004 $importCount = 0;
3005 $error = 0;
3006 foreach ($importLines as $lineId) {
3007 $lineId = intval($lineId);
3008 $originLine = new $lineClassName($db);
3009 if (intval($fromElementid) > 0 && $originLine->fetch($lineId) > 0) {
3010 $originLine->fetch_optionals();
3011 $desc = $originLine->desc;
3012 $pu_ht = $originLine->subprice;
3013 $qty = $originLine->qty;
3014 $txtva = $originLine->tva_tx;
3015 $txlocaltax1 = $originLine->localtax1_tx;
3016 $txlocaltax2 = $originLine->localtax2_tx;
3017 $fk_product = $originLine->fk_product;
3018 $remise_percent = $originLine->remise_percent;
3019 $date_start = $originLine->date_start;
3020 $date_end = $originLine->date_end;
3021 $fk_code_ventilation = 0;
3022 $info_bits = $originLine->info_bits;
3023 $fk_remise_except = $originLine->fk_remise_except;
3024 $price_base_type = 'HT';
3025 $pu_ttc = 0;
3026 $type = $originLine->product_type;
3027 $rang = $nextRang++;
3028 $special_code = $originLine->special_code;
3029 $origin = $originLine->element;
3030 $origin_id = $originLine->id;
3031 $fk_parent_line = 0;
3032 $fk_fournprice = $originLine->fk_fournprice;
3033 $pa_ht = $originLine->pa_ht;
3034 $label = $originLine->label;
3035 $array_options = $originLine->array_options;
3036 if ($object->type == Facture::TYPE_SITUATION) {
3037 $situation_percent = 0;
3038 } else {
3039 $situation_percent = 100;
3040 }
3041 $fk_prev_id = 0;
3042 $fk_unit = $originLine->fk_unit;
3043 $pu_ht_devise = $originLine->multicurrency_subprice;
3044
3045 $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);
3046
3047 if ($res > 0) {
3048 $importCount++;
3049 } else {
3050 $error++;
3051 }
3052 } else {
3053 $error++;
3054 }
3055 }
3056
3057 if ($error) {
3058 setEventMessages($langs->trans('ErrorsOnXLines', $error), null, 'errors');
3059 }
3060 }
3061 }
3062
3063 // Actions when printing a doc from card
3064 include DOL_DOCUMENT_ROOT.'/core/actions_printing.inc.php';
3065
3066 // Actions to send emails
3067 if (empty($id)) {
3068 $id = $facid;
3069 }
3070 $triggersendname = 'BILL_SENTBYMAIL';
3071 $paramname = 'id';
3072 $autocopy = 'MAIN_MAIL_AUTOCOPY_INVOICE_TO';
3073 $trackid = 'inv'.$object->id;
3074 include DOL_DOCUMENT_ROOT.'/core/actions_sendmails.inc.php';
3075
3076 // Actions to build doc
3077 $upload_dir = $conf->invoice->multidir_output[!empty($object->entity) ? $object->entity : $conf->entity];
3078 $permissiontoadd = $usercancreate;
3079 include DOL_DOCUMENT_ROOT.'/core/actions_builddoc.inc.php';
3080
3081
3082 if ($action == 'update_extras' && $usercancreate) {
3083 $object->oldcopy = dol_clone($object, 2);
3084
3085 // Fill array 'array_options' with data from add form
3086 $ret = $extrafields->setOptionalsFromPost(null, $object, GETPOST('attribute', 'restricthtml'));
3087 if ($ret < 0) {
3088 $error++;
3089 }
3090
3091 if (!$error) {
3092 // Actions on extra fields
3093 $result = $object->insertExtraFields('BILL_MODIFY');
3094 if ($result < 0) {
3095 setEventMessages($object->error, $object->errors, 'errors');
3096 $error++;
3097 }
3098 }
3099
3100 if ($error) {
3101 $action = 'edit_extras';
3102 }
3103 }
3104
3105 if (getDolGlobalString('MAIN_DISABLE_CONTACTS_TAB')) {
3106 if ($action == 'addcontact' && $usercancreate) {
3107 $result = $object->fetch($id);
3108
3109 if ($result > 0 && $id > 0) {
3110 $contactid = (GETPOST('userid') ? GETPOST('userid') : GETPOST('contactid'));
3111 $typeid = (GETPOST('typecontact') ? GETPOST('typecontact') : GETPOST('type'));
3112 $result = $object->add_contact($contactid, $typeid, GETPOST("source", 'aZ09'));
3113 }
3114
3115 if ($result >= 0) {
3116 header("Location: ".$_SERVER['PHP_SELF']."?id=".$object->id);
3117 exit();
3118 } else {
3119 if ($object->error == 'DB_ERROR_RECORD_ALREADY_EXISTS') {
3120 $langs->load("errors");
3121 setEventMessages($langs->trans("ErrorThisContactIsAlreadyDefinedAsThisType"), null, 'errors');
3122 } else {
3123 setEventMessages($object->error, $object->errors, 'errors');
3124 }
3125 }
3126 } elseif ($action == 'swapstatut' && $usercancreate) {
3127 // toggle the status of a contact
3128 if ($object->fetch($id)) {
3129 $result = $object->swapContactStatus(GETPOSTINT('ligne'));
3130 } else {
3131 dol_print_error($db);
3132 }
3133 } elseif ($action == 'deletecontact' && $usercancreate) {
3134 // Delete a contact
3135 $object->fetch($id);
3136 $result = $object->delete_contact($lineid);
3137
3138 if ($result >= 0) {
3139 header("Location: ".$_SERVER['PHP_SELF']."?id=".$object->id);
3140 exit();
3141 } else {
3142 dol_print_error($db);
3143 }
3144 }
3145
3146 if ($error) {
3147 $action = 'edit_extras';
3148 }
3149 }
3150}
3151
3152
3153/*
3154 * View
3155 */
3156
3157
3158$form = new Form($db);
3159$formother = new FormOther($db);
3160$formfile = new FormFile($db);
3161$formmargin = new FormMargin($db);
3162$soc = new Societe($db);
3163$paymentstatic = new Paiement($db);
3164$bankaccountstatic = new Account($db);
3165if (isModEnabled('project')) {
3166 $formproject = new FormProjets($db);
3167}
3168
3169$now = dol_now();
3170
3171$title = $object->ref." - ".$langs->trans('Card');
3172if ($action == 'create') {
3173 $title = $langs->trans("NewBill");
3174}
3175$help_url = "EN:Customers_Invoices|FR:Factures_Clients|ES:Facturas_a_clientes";
3176
3177llxHeader('', $title, $help_url);
3178
3179// Mode creation
3180
3181if ($action == 'create') {
3182 $facturestatic = new Facture($db);
3183 $extrafields->fetch_name_optionals_label($facturestatic->table_element);
3184
3185 print load_fiche_titre($langs->trans('NewBill'), '', 'bill');
3186
3187 if ($socid > 0) {
3188 $res = $soc->fetch($socid);
3189 }
3190
3191 $currency_code = $conf->currency;
3192
3193 $cond_reglement_id = GETPOSTINT('cond_reglement_id');
3194 $mode_reglement_id = GETPOSTINT('mode_reglement_id');
3195 $fk_account = GETPOSTINT('fk_account');
3196
3197 // Load objectsrc
3198 //$remise_absolue = 0;
3199 if (!empty($origin) && !empty($originid)) {
3200 // Parse element/subelement (ex: project_task)
3201 $element = $subelement = $origin;
3202 $regs = array();
3203 if (preg_match('/^([^_]+)_([^_]+)/i', $origin, $regs)) {
3204 $element = $regs[1];
3205 $subelement = $regs[2];
3206 }
3207
3208 $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
3209 $date_pointoftax = dol_mktime(0, 0, 0, GETPOSTINT('date_pointoftaxmonth'), GETPOSTINT('date_pointoftaxday'), GETPOSTINT('date_pointoftaxyear'), 'tzserver');
3210
3211 if ($element == 'project') {
3212 $projectid = $originid;
3213
3214 if (empty($cond_reglement_id)) {
3215 $cond_reglement_id = $soc->cond_reglement_id;
3216 }
3217 if (empty($mode_reglement_id)) {
3218 $mode_reglement_id = $soc->mode_reglement_id;
3219 }
3220 if (empty($fk_account)) {
3221 $fk_account = $soc->fk_account;
3222 }
3223 if (empty($dateinvoice)) {
3224 // Do not set 0 here (0 for a date is 1970)
3225 $dateinvoice = getDolGlobalString('MAIN_AUTOFILL_DATE') ? '' : -1;
3226 }
3227 } else {
3228 // For compatibility
3229 if ($element == 'order' || $element == 'commande') {
3230 $element = $subelement = 'commande';
3231 }
3232 if ($element == 'propal') {
3233 $element = 'comm/propal';
3234 $subelement = 'propal';
3235 }
3236 if ($element == 'contract') {
3237 $element = $subelement = 'contrat';
3238 }
3239 if ($element == 'shipping') {
3240 $element = $subelement = 'expedition';
3241 }
3242
3243 dol_include_once('/'.$element.'/class/'.$subelement.'.class.php');
3244
3245 $classname = ucfirst($subelement);
3246 $objectsrc = new $classname($db);
3247 $objectsrc->fetch($originid);
3248 if (empty($objectsrc->lines) && method_exists($objectsrc, 'fetch_lines')) {
3249 $objectsrc->fetch_lines();
3250 }
3251 $objectsrc->fetch_thirdparty();
3252
3253 $projectid = (!empty($projectid) ? $projectid : $objectsrc->fk_project);
3254 $ref_client = (!empty($objectsrc->ref_client) ? $objectsrc->ref_client : (!empty($objectsrc->ref_customer) ? $objectsrc->ref_customer : ''));
3255
3256 // only if socid not filled else it's already done above
3257 if (empty($socid)) {
3258 $soc = $objectsrc->thirdparty;
3259 }
3260
3261 $dateinvoice = (empty($dateinvoice) ? (!getDolGlobalString('MAIN_AUTOFILL_DATE') ? -1 : '') : $dateinvoice);
3262
3263 if ($element == 'expedition') {
3264 $ref_client = (!empty($objectsrc->ref_customer) ? $objectsrc->ref_customer : '');
3265
3266 $elem = $subelem = $objectsrc->origin;
3267 $expeoriginid = $objectsrc->origin_id;
3268 dol_include_once('/'.$elem.'/class/'.$subelem.'.class.php');
3269 $classname = ucfirst($subelem);
3270
3271 $expesrc = new $classname($db);
3272 $expesrc->fetch($expeoriginid);
3273
3274 $cond_reglement_id = (!empty($expesrc->cond_reglement_id) ? $expesrc->cond_reglement_id : (!empty($soc->cond_reglement_id) ? $soc->cond_reglement_id : 1));
3275 $mode_reglement_id = (!empty($expesrc->mode_reglement_id) ? $expesrc->mode_reglement_id : (!empty($soc->mode_reglement_id) ? $soc->mode_reglement_id : 0));
3276 $fk_account = (!empty($expesrc->fk_account) ? $expesrc->fk_account : (!empty($soc->fk_account) ? $soc->fk_account : 0));
3277
3278 if (isModEnabled('multicurrency')) {
3279 $currency_code = (!empty($expesrc->multicurrency_code) ? $expesrc->multicurrency_code : (!empty($soc->multicurrency_code) ? $soc->multicurrency_code : $objectsrc->multicurrency_code));
3280 $currency_tx = (!empty($expesrc->multicurrency_tx) ? $expesrc->multicurrency_tx : (!empty($soc->multicurrency_tx) ? $soc->multicurrency_tx : $objectsrc->multicurrency_tx));
3281 }
3282
3283 //Replicate extrafields
3284 $expesrc->fetch_optionals();
3285 $object->array_options = $expesrc->array_options;
3286 } else {
3287 $cond_reglement_id = (!empty($objectsrc->cond_reglement_id) ? $objectsrc->cond_reglement_id : (!empty($soc->cond_reglement_id) ? $soc->cond_reglement_id : 0));
3288 $mode_reglement_id = (!empty($objectsrc->mode_reglement_id) ? $objectsrc->mode_reglement_id : (!empty($soc->mode_reglement_id) ? $soc->mode_reglement_id : 0));
3289 $fk_account = (!empty($objectsrc->fk_account) ? $objectsrc->fk_account : (!empty($soc->fk_account) ? $soc->fk_account : 0));
3290
3291 if (isModEnabled('multicurrency')) {
3292 if (!empty($objectsrc->multicurrency_code)) {
3293 $currency_code = $objectsrc->multicurrency_code;
3294 }
3295 if (getDolGlobalString('MULTICURRENCY_USE_ORIGIN_TX') && !empty($objectsrc->multicurrency_tx)) {
3296 $currency_tx = $objectsrc->multicurrency_tx;
3297 }
3298 }
3299
3300 // Replicate extrafields
3301 $objectsrc->fetch_optionals();
3302 $object->array_options = $objectsrc->array_options;
3303 }
3304 }
3305 } else {
3306 $cond_reglement_id = empty($soc->cond_reglement_id) ? $cond_reglement_id : $soc->cond_reglement_id;
3307 $mode_reglement_id = empty($soc->mode_reglement_id) ? $mode_reglement_id : $soc->mode_reglement_id;
3308 $fk_account = empty($soc->fk_account) ? $fk_account : $soc->fk_account;
3309
3310 $dateinvoice = (empty($dateinvoice) ? (!getDolGlobalString('MAIN_AUTOFILL_DATE') ? -1 : '') : $dateinvoice); // Do not set 0 here (0 for a date is 1970)
3311
3312 if (isModEnabled('multicurrency') && !empty($soc->multicurrency_code)) {
3313 $currency_code = $soc->multicurrency_code;
3314 }
3315 }
3316
3317 // If form was posted (but error returned), we must reuse the value posted in priority (standard Dolibarr behaviour)
3318 if (!GETPOST('changecompany')) {
3319 if (GETPOSTISSET('cond_reglement_id')) {
3320 $cond_reglement_id = GETPOSTINT('cond_reglement_id');
3321 }
3322 if (GETPOSTISSET('mode_reglement_id')) {
3323 $mode_reglement_id = GETPOSTINT('mode_reglement_id');
3324 }
3325 if (GETPOSTISSET('cond_reglement_id')) {
3326 $fk_account = GETPOSTINT('fk_account');
3327 }
3328 }
3329
3330 // when payment condition is empty (means not override by payment condition form a other object, like third-party), try to use default value
3331 if (empty($cond_reglement_id)) {
3332 $cond_reglement_id = GETPOSTINT("cond_reglement_id");
3333 }
3334
3335 // when payment mode is empty (means not override by payment mode form a other object, like third-party), try to use default value
3336 if (empty($mode_reglement_id)) {
3337 $mode_reglement_id = GETPOSTINT("mode_reglement_id");
3338 }
3339
3340 // when bank account is empty (means not override by payment mode form a other object, like third-party), try to use default value
3341 // if ($socid > 0 && $fk_account) { // A company has already been set and it has a default fk_account
3342 // $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
3343 // } else { // No company forced
3344 // $fk_account = GETPOST("fk_account", 'int');
3345 // }
3346
3347 if (!empty($soc->id)) {
3348 $absolute_discount = $soc->getAvailableDiscounts();
3349 }
3350 $note_public = $object->getDefaultCreateValueFor('note_public', ((!empty($origin) && !empty($originid) && is_object($objectsrc) && getDolGlobalString('FACTURE_REUSE_NOTES_ON_CREATE_FROM')) ? $objectsrc->note_public : null));
3351 $note_private = $object->getDefaultCreateValueFor('note_private', ((!empty($origin) && !empty($originid) && is_object($objectsrc) && getDolGlobalString('FACTURE_REUSE_NOTES_ON_CREATE_FROM')) ? $objectsrc->note_private : null));
3352
3353 if (!empty($conf->use_javascript_ajax)) {
3354 require_once DOL_DOCUMENT_ROOT.'/core/lib/ajax.lib.php';
3355 print ajax_combobox('fac_replacement');
3356 print ajax_combobox('fac_avoir');
3357 print ajax_combobox('situations');
3358 }
3359
3360 if ($origin == 'contrat') {
3361 $langs->load("admin");
3362 $text = $langs->trans("ToCreateARecurringInvoice");
3363 $text .= ' '.$langs->trans("ToCreateARecurringInvoiceGene", $langs->transnoentitiesnoconv("MenuFinancial"), $langs->transnoentitiesnoconv("BillsCustomers"), $langs->transnoentitiesnoconv("ListOfTemplates"));
3364 if (!getDolGlobalString('INVOICE_DISABLE_AUTOMATIC_RECURRING_INVOICE')) {
3365 $text .= ' '.$langs->trans("ToCreateARecurringInvoiceGeneAuto", $langs->transnoentitiesnoconv('Module2300Name'));
3366 }
3367 print info_admin($text, 0, 0, 0, 'opacitymedium').'<br>';
3368 }
3369
3370 print '<form name="add" action="'.$_SERVER["PHP_SELF"].'" method="POST" id="formtocreate" name="formtocreate">';
3371 print '<input type="hidden" name="token" value="'.newToken().'">';
3372 print '<input type="hidden" name="action" id="formtocreateaction" value="add">';
3373 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
3374 if ($soc->id > 0) {
3375 print '<input type="hidden" name="socid" value="'.$soc->id.'">'."\n";
3376 }
3377 print '<input type="hidden" name="backtopage" value="'.$backtopage.'">';
3378 print '<input name="ref" type="hidden" value="provisoire">';
3379 print '<input name="ref_client" type="hidden" value="'.$ref_client.'">';
3380 print '<input name="force_cond_reglement_id" type="hidden" value="0">';
3381 print '<input name="force_mode_reglement_id" type="hidden" value="0">';
3382 print '<input name="force_fk_account" type="hidden" value="0">';
3383 print '<input type="hidden" name="origin" value="'.$origin.'">';
3384 print '<input type="hidden" name="originid" value="'.$originid.'">';
3385 print '<input type="hidden" name="originentity" value="'.GETPOST('originentity').'">';
3386 if (!empty($currency_tx)) {
3387 print '<input type="hidden" name="originmulticurrency_tx" value="'.$currency_tx.'">';
3388 }
3389
3390 print dol_get_fiche_head();
3391
3392 // Call Hook tabContentCreateInvoice
3393 $parameters = array();
3394 // Note that $action and $object may be modified by hook
3395 $reshook = $hookmanager->executeHooks('tabContentCreateInvoice', $parameters, $object, $action);
3396 if (empty($reshook)) {
3397 print '<table class="border centpercent">';
3398
3399 $exampletemplateinvoice = new FactureRec($db);
3400 $invoice_predefined = new FactureRec($db);
3401 if (empty($origin) && empty($originid) && GETPOSTINT('fac_rec') > 0) {
3402 $invoice_predefined->fetch(GETPOSTINT('fac_rec'));
3403 }
3404
3405 // Thirdparty
3406 if ($soc->id > 0 && (!GETPOSTINT('fac_rec') || !empty($invoice_predefined->frequency))) {
3407 // If thirdparty known and not a predefined invoiced without a recurring rule
3408 print '<tr><td class="fieldrequired">'.$langs->trans('Customer').'</td>';
3409 print '<td colspan="2">';
3410 print $soc->getNomUrl(1, 'customer');
3411 print '<input type="hidden" name="socid" value="'.$soc->id.'">';
3412 // Outstanding Bill
3413 $arrayoutstandingbills = $soc->getOutstandingBills();
3414 $outstandingBills = $arrayoutstandingbills['opened'];
3415 print ' - <span class="opacitymedium">'.$langs->trans('CurrentOutstandingBill').':</span> ';
3416 print '<span class="amount">'.price($outstandingBills, 0, $langs, 0, 0, -1, $conf->currency).'</span>';
3417 if ($soc->outstanding_limit != '') {
3418 if ($outstandingBills > $soc->outstanding_limit) {
3419 print img_warning($langs->trans("OutstandingBillReached"));
3420 }
3421 print ' / '.price($soc->outstanding_limit, 0, $langs, 0, 0, -1, $conf->currency);
3422 }
3423 print '</td>';
3424 print '</tr>'."\n";
3425 } else {
3426 print '<tr><td class="fieldrequired">'.$langs->trans('Customer').'</td>';
3427 print '<td colspan="2">';
3428 $filter = '((s.client:IN:1,2,3) AND (s.status:=:1))';
3429 print img_picto('', 'company', 'class="pictofixedwidth"').$form->select_company($soc->id, 'socid', $filter, 'SelectThirdParty', 1, 0, array(), 0, 'minwidth300 widthcentpercentminusxx maxwidth500');
3430 // Option to reload page to retrieve customer information.
3431 if (!getDolGlobalString('RELOAD_PAGE_ON_CUSTOMER_CHANGE_DISABLED')) {
3432 print '<script>
3433 $(document).ready(function() {
3434 $("#socid").change(function() {
3435 /*
3436 console.log("Submit page");
3437 $(\'input[name="action"]\').val(\'create\');
3438 $(\'input[name="force_cond_reglement_id"]\').val(\'1\');
3439 $(\'input[name="force_mode_reglement_id"]\').val(\'1\');
3440 $(\'input[name="force_fk_account"]\').val(\'1\');
3441 $("#formtocreate").submit(); */
3442
3443 // For company change, we must submit page with action=create instead of action=add
3444 console.log("We have changed the company - Resubmit page");
3445 jQuery("input[name=changecompany]").val("1");
3446 jQuery("#formtocreateaction").val("create");
3447 jQuery("#formtocreate").submit();
3448 });
3449 });
3450 </script>';
3451 }
3452 if (!GETPOSTINT('fac_rec')) {
3453 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>';
3454 }
3455 print '</td>';
3456 print '</tr>'."\n";
3457 }
3458
3459 // Overwrite some values if creation of invoice is from a predefined invoice
3460 if (empty($origin) && empty($originid) && GETPOSTINT('fac_rec') > 0) {
3461 $invoice_predefined->fetch(GETPOSTINT('fac_rec'));
3462
3463 $dateinvoice = $invoice_predefined->date_when; // To use next gen date by default later
3464 if (empty($projectid)) {
3465 $projectid = $invoice_predefined->fk_project;
3466 }
3467 $cond_reglement_id = $invoice_predefined->cond_reglement_id;
3468 $mode_reglement_id = $invoice_predefined->mode_reglement_id;
3469 $fk_account = $invoice_predefined->fk_account;
3470 $note_public = $invoice_predefined->note_public;
3471 $note_private = $invoice_predefined->note_private;
3472
3473 if (!empty($invoice_predefined->multicurrency_code)) {
3474 $currency_code = $invoice_predefined->multicurrency_code;
3475 }
3476 if (!empty($invoice_predefined->multicurrency_tx)) {
3477 $currency_tx = $invoice_predefined->multicurrency_tx;
3478 }
3479
3480 $sql = 'SELECT r.rowid, r.titre as title, r.total_ttc';
3481 $sql .= ' FROM '.MAIN_DB_PREFIX.'facture_rec as r';
3482 $sql .= ' WHERE r.fk_soc = '.((int) $invoice_predefined->socid);
3483
3484 $resql = $db->query($sql);
3485 if ($resql) {
3486 $num = $db->num_rows($resql);
3487 $i = 0;
3488
3489 if ($num > 0) {
3490 print '<tr><td>'.$langs->trans('CreateFromRepeatableInvoice').'</td><td>';
3491 //print '<input type="hidden" name="fac_rec" id="fac_rec" value="'.GETPOST('fac_rec', 'int').'">';
3492 print '<select class="flat" id="fac_rec" name="fac_rec">'; // We may want to change the template to use
3493 print '<option value="0" selected></option>';
3494 while ($i < $num) {
3495 $objp = $db->fetch_object($resql);
3496 print '<option value="'.$objp->rowid.'"';
3497 if (GETPOSTINT('fac_rec') == $objp->rowid) {
3498 print ' selected';
3499 $exampletemplateinvoice->fetch(GETPOSTINT('fac_rec'));
3500 }
3501 print '>'.$objp->title.' ('.price($objp->total_ttc).' '.$langs->trans("TTC").')</option>';
3502 $i++;
3503 }
3504 print '</select>';
3505
3506 print ajax_combobox("fac_rec");
3507
3508 // Option to reload page to retrieve customer information. Note, this clear other input
3509 if (!getDolGlobalString('RELOAD_PAGE_ON_TEMPLATE_CHANGE_DISABLED')) {
3510 print '<script type="text/javascript">
3511 $(document).ready(function() {
3512 $("#fac_rec").change(function() {
3513 console.log("We have changed the template invoice - Reload page");
3514 var fac_rec = $(this).val();
3515 var socid = $(\'#socid\').val();
3516 // 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.
3517 window.location.href = "'.$_SERVER["PHP_SELF"].'?action=create&socid="+socid+"&fac_rec="+fac_rec;
3518 });
3519 });
3520 </script>';
3521 }
3522 print '</td></tr>';
3523 }
3524 $db->free($resql);
3525 } else {
3526 dol_print_error($db);
3527 }
3528 }
3529
3530 print '<tr><td class="tdtop fieldrequired">'.$langs->trans('Type').'</td><td colspan="2">';
3531 print '<div class="tagtable">'."\n";
3532
3533 // Standard invoice
3534 print '<div class="tagtr listofinvoicetype"><div class="tagtd listofinvoicetype">';
3535 $tmp = '<input type="radio" id="radio_standard" name="type" value="0"'.(GETPOSTINT('type') ? '' : ' checked').'> ';
3536 $tmp = $tmp.'<label for="radio_standard" >'.$langs->trans("InvoiceStandardAsk").'</label>';
3537 // @phan-suppress-next-line PhanPluginSuspiciousParamOrder
3538 $desc = $form->textwithpicto($tmp, $langs->transnoentities("InvoiceStandardDesc"), 1, 'help', 'nowraponall', 0, 3, 'standardonsmartphone');
3539 print '<table class="nobordernopadding"><tr>';
3540 print '<td>';
3541 print $desc;
3542 print '</td>';
3543 if ((($origin == 'propal') || ($origin == 'commande')) && (!empty($originid))) {
3544 /*print '<td class="nowrap" style="padding-left: 5px">';
3545 $arraylist = array(
3546 //'amount' => $langs->transnoentitiesnoconv('FixAmount', $langs->transnoentitiesnoconv('Deposit')),
3547 //'variable' => $langs->transnoentitiesnoconv('VarAmountOneLine', $langs->transnoentitiesnoconv('Deposit')),
3548 'variablealllines' => $langs->transnoentitiesnoconv('VarAmountAllLines')
3549 );
3550 print $form->selectarray('typestandard', $arraylist, GETPOST('typestandard', 'aZ09'), 0, 0, 0, '', 1);
3551 print '</td>';*/
3552 print '<td class="nowrap" style="padding-left: 15px">';
3553 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%').'"/>';
3554 print '</td>';
3555 }
3556 print '</tr></table>';
3557 print '</div></div>';
3558
3559 if ((empty($origin)) || ((($origin == 'propal') || ($origin == 'commande')) && (!empty($originid)))) {
3560 // Deposit - Down payment
3561 if (!getDolGlobalString('INVOICE_DISABLE_DEPOSIT')) {
3562 print '<div class="tagtr listofinvoicetype"><div class="tagtd listofinvoicetype">';
3563 $tmp = '<input type="radio" id="radio_deposit" name="type" value="3"'.(GETPOSTINT('type') == 3 ? ' checked' : '').'> ';
3564 print '<script type="text/javascript">
3565 jQuery(document).ready(function() {
3566 jQuery("#typestandardinvoice, #valuestandardinvoice").click(function() {
3567 jQuery("#radio_standard").prop("checked", true);
3568 });
3569 jQuery("#typedeposit, #valuedeposit").click(function() {
3570 jQuery("#radio_deposit").prop("checked", true);
3571 });
3572 jQuery("#typedeposit").change(function() {
3573 console.log("We change type of down payment");
3574 jQuery("#radio_deposit").prop("checked", true);
3575 setRadioForTypeOfInvoice();
3576 });
3577 jQuery("#radio_standard, #radio_deposit, #radio_replacement, #radio_creditnote, #radio_template").change(function() {
3578 setRadioForTypeOfInvoice();
3579 });
3580 function setRadioForTypeOfInvoice() {
3581 console.log("Change radio for type of invoice");
3582 if (jQuery("#radio_deposit").prop("checked") && (jQuery("#typedeposit").val() == \'amount\' || jQuery("#typedeposit").val() == \'variable\')) {
3583 jQuery("#checkforselects").prop("disabled", true);
3584 jQuery("#checkforselects").prop("checked", false);
3585 jQuery(".checkforselect").prop("disabled", true);
3586 jQuery(".checkforselect").prop("checked", false);
3587 } else {
3588 jQuery("#checkforselects").prop("disabled", false);
3589 jQuery("#checkforselects").prop("checked", true);
3590 jQuery(".checkforselect").prop("disabled", false);
3591 jQuery(".checkforselect").prop("checked", true);
3592 }
3593 }
3594 });
3595 </script>';
3596
3597 print '<table class="nobordernopadding"><tr>';
3598 print '<td>';
3599 $tmp = $tmp.'<label for="radio_deposit">'.$langs->trans("InvoiceDeposit").'</label>';
3600 // @phan-suppress-next-line PhanPluginSuspiciousParamOrder
3601 $desc = $form->textwithpicto($tmp, $langs->transnoentities("InvoiceDepositDesc"), 1, 'help', '', 0, 3, 'depositonsmartphone');
3602 print $desc;
3603 print '</td>';
3604 if (($origin == 'propal') || ($origin == 'commande')) {
3605 print '<td class="nowrap" style="padding-left: 15px">';
3606 $arraylist = array(
3607 'amount' => $langs->transnoentitiesnoconv('FixAmount', $langs->transnoentitiesnoconv('Deposit')),
3608 'variable' => $langs->transnoentitiesnoconv('VarAmountOneLine', $langs->transnoentitiesnoconv('Deposit')),
3609 'variablealllines' => $langs->transnoentitiesnoconv('VarAmountAllLines')
3610 );
3611 $typedeposit = GETPOST('typedeposit', 'aZ09');
3612 $valuedeposit = GETPOSTINT('valuedeposit');
3613 if (empty($typedeposit) && !empty($objectsrc->deposit_percent)) {
3614 $origin_payment_conditions_deposit_percent = getDictionaryValue('c_payment_term', 'deposit_percent', $objectsrc->cond_reglement_id);
3615 if (!empty($origin_payment_conditions_deposit_percent)) {
3616 $typedeposit = 'variable';
3617 }
3618 }
3619 if (empty($valuedeposit) && $typedeposit == 'variable' && !empty($objectsrc->deposit_percent)) {
3620 $valuedeposit = $objectsrc->deposit_percent;
3621 }
3622 print $form->selectarray('typedeposit', $arraylist, $typedeposit, 0, 0, 0, '', 1);
3623 print '</td>';
3624 print '<td class="nowrap" style="padding-left: 5px">';
3625 print '<span class="opacitymedium paddingleft">'.$langs->trans("AmountOrPercent").'</span><input type="text" id="valuedeposit" name="valuedeposit" class="width75 right" value="'.$valuedeposit.'"/>';
3626 print '</td>';
3627 }
3628 print '</tr></table>';
3629
3630 print '</div></div>';
3631 }
3632 }
3633
3634 if ($socid > 0) {
3635 if (getDolGlobalString('INVOICE_USE_SITUATION')) {
3636 // First situation invoice
3637 print '<div class="tagtr listofinvoicetype"><div class="tagtd listofinvoicetype">';
3638 $tmp = '<input id="radio_situation" type="radio" name="type" value="5"'.(GETPOST('type') == 5 ? ' checked' : '').'> ';
3639 $tmp = $tmp.'<label for="radio_situation" >'.$langs->trans("InvoiceFirstSituationAsk").'</label>';
3640 // @phan-suppress-next-line PhanPluginSuspiciousParamOrder
3641 $desc = $form->textwithpicto($tmp, $langs->transnoentities("InvoiceFirstSituationDesc"), 1, 'help', '', 0, 3, 'firstsituationonsmartphone');
3642 print $desc;
3643 print '</div></div>';
3644
3645 // Next situation invoice
3646 $opt = $form->selectSituationInvoices(GETPOSTINT('originid'), $socid);
3647
3648 print '<div class="tagtr listofinvoicetype"><div class="tagtd listofinvoicetype">';
3649 $tmp = '<input type="radio" name="type" value="5"'.(GETPOST('type') == 5 && GETPOSTINT('originid') ? ' checked' : '');
3650 if ($opt == ('<option value ="0" selected>'.$langs->trans('NoSituations').'</option>') || (GETPOST('origin') && GETPOST('origin') != 'facture' && GETPOST('origin') != 'commande')) {
3651 $tmp .= ' disabled';
3652 }
3653 $tmp .= '> ';
3654 $text = $tmp.'<label>'.$langs->trans("InvoiceSituationAsk").'</label> ';
3655 $text .= '<select class="flat" id="situations" name="situations"';
3656 if ($opt == ('<option value ="0" selected>'.$langs->trans('NoSituations').'</option>') || (GETPOST('origin') && GETPOST('origin') != 'facture' && GETPOST('origin') != 'commande')) {
3657 $text .= ' disabled';
3658 }
3659 $text .= '>';
3660 $text .= $opt;
3661 $text .= '</select>';
3662 $desc = $form->textwithpicto($text, $langs->transnoentities("InvoiceSituationDesc"), 1, 'help', '', 0, 3);
3663 print $desc;
3664 print '</div></div>';
3665 }
3666
3667 // Replacement
3668 if (!getDolGlobalString('INVOICE_DISABLE_REPLACEMENT')) {
3669 // Type de facture
3670 $facids = $facturestatic->list_replacable_invoices($soc->id);
3671 if ($facids < 0) {
3672 dol_print_error($db, $facturestatic->error, $facturestatic->errors);
3673 exit();
3674 }
3675 $options = "";
3676 if (is_array($facids)) {
3677 foreach ($facids as $facparam) {
3678 $options .= '<option value="'.$facparam ['id'].'"';
3679 if ($facparam['id'] == GETPOSTINT('fac_replacement')) {
3680 $options .= ' selected';
3681 }
3682 $options .= '>'.$facparam['ref'];
3683 $options .= ' ('.$facturestatic->LibStatut($facparam['paid'], $facparam['status'], 0, $facparam['alreadypaid']).')';
3684 $options .= '</option>';
3685 }
3686 }
3687
3688 print '<!-- replacement line -->';
3689 print '<div class="tagtr listofinvoicetype"><div class="tagtd listofinvoicetype">';
3690 $tmp = '<input type="radio" name="type" id="radio_replacement" value="1"'.(GETPOST('type') == 1 ? ' checked' : '');
3691 if (!$options || $invoice_predefined->id > 0) {
3692 $tmp .= ' disabled';
3693 }
3694 $tmp .= '> ';
3695 print '<script type="text/javascript">
3696 jQuery(document).ready(function() {
3697 jQuery("#fac_replacement").change(function() {
3698 jQuery("#radio_replacement").prop("checked", true);
3699 });
3700 });
3701 </script>';
3702 $text = $tmp.'<label for="radio_replacement">'.$langs->trans("InvoiceReplacementAsk").'</label>';
3703 $text .= '<select class="flat" name="fac_replacement" id="fac_replacement"';
3704 if (!$options || $invoice_predefined->id > 0) {
3705 $text .= ' disabled';
3706 }
3707 $text .= '>';
3708 if ($options) {
3709 $text .= '<option value="-1">&nbsp;</option>';
3710 $text .= $options;
3711 } else {
3712 $text .= '<option value="-1">'.$langs->trans("NoReplacableInvoice").'</option>';
3713 }
3714 $text .= '</select>';
3715 $desc = $form->textwithpicto($text, $langs->transnoentities("InvoiceReplacementDesc"), 1, 'help', '', 0, 3);
3716 print $desc;
3717 print '</div></div>';
3718 }
3719 } else {
3720 if (getDolGlobalString('INVOICE_USE_SITUATION')) {
3721 print '<div class="tagtr listofinvoicetype"><div class="tagtd listofinvoicetype">';
3722 $tmp = '<input type="radio" name="type" id="radio_situation" value="0" disabled> ';
3723 $text = $tmp.'<label>'.$langs->trans("InvoiceSituationAsk").'</label> ';
3724 $text .= '<span class="opacitymedium">('.$langs->trans("YouMustCreateInvoiceFromThird").')</span> ';
3725 $desc = $form->textwithpicto($text, $langs->transnoentities("InvoiceFirstSituationDesc"), 1, 'help', 'nowraponall', 0, 3, 'firstsituationonsmartphone');
3726 print $desc;
3727 print '</div></div>';
3728 }
3729
3730 print '<div class="tagtr listofinvoicetype"><div class="tagtd listofinvoicetype">';
3731 $tmp = '<input type="radio" name="type" id="radio_replacement" value="0" disabled> ';
3732 $text = $tmp.'<label for="radio_replacement" class="opacitymedium">'.$langs->trans("InvoiceReplacement").'</label> ';
3733 //$text .= '<span class="opacitymedium hideonsmartphone">('.$langs->trans("YouMustCreateInvoiceFromThird").')</span> ';
3734 $desc = $form->textwithpicto($text, $langs->transnoentities("InvoiceReplacementDesc").'<br><br>'.$langs->trans("YouMustCreateInvoiceFromThird"), 1, 'help', 'nowraponall', 0, 3, 'replacementonsmartphone');
3735 print $desc;
3736 print '</div></div>';
3737 }
3738
3739 if (empty($origin)) {
3740 if ($socid > 0) {
3741 // Credit note
3742 if (!getDolGlobalString('INVOICE_DISABLE_CREDIT_NOTE')) {
3743 // Show link for credit note
3744 $facids = $facturestatic->list_qualified_avoir_invoices($soc->id);
3745 if ($facids < 0) {
3746 dol_print_error($db, $facturestatic->error, $facturestatic->errors);
3747 exit;
3748 }
3749 $optionsav = "";
3750 $newinvoice_static = new Facture($db);
3751 foreach ($facids as $key => $valarray) {
3752 $newinvoice_static->id = $key;
3753 $newinvoice_static->ref = $valarray ['ref'];
3754 $newinvoice_static->statut = $valarray ['status'];
3755 $newinvoice_static->status = $valarray ['status'];
3756 $newinvoice_static->type = $valarray ['type'];
3757 $newinvoice_static->paye = $valarray ['paye'];
3758
3759 $optionsav .= '<option value="'.$key.'"';
3760 if ($key == GETPOST('fac_avoir')) {
3761 $optionsav .= ' selected';
3762
3763 // pre-filled extra fields with selected credit note
3764 $newinvoice_static->fetch_optionals($key);
3765 $object->array_options = $newinvoice_static->array_options;
3766 }
3767 $optionsav .= '>';
3768 $optionsav .= $newinvoice_static->ref;
3769 $optionsav .= ' ('.$newinvoice_static->getLibStatut(1, $valarray ['paymentornot']).')';
3770 $optionsav .= '</option>';
3771 }
3772
3773 print '<div class="tagtr listofinvoicetype"><div class="tagtd listofinvoicetype">';
3774 $tmp = '<input type="radio" id="radio_creditnote" name="type" value="2"'.(GETPOST('type') == 2 ? ' checked' : '');
3775 if ((!$optionsav && !getDolGlobalString('INVOICE_CREDIT_NOTE_STANDALONE')) || $invoice_predefined->id > 0) {
3776 $tmp .= ' disabled';
3777 }
3778 $tmp .= '> ';
3779 // Show credit note options only if we checked credit note and disable standard invoice if "create credit note" button is pressed
3780 print '<script type="text/javascript">
3781 jQuery(document).ready(function() {
3782 if (jQuery("#radio_creditnote").is(":checked"))
3783 {
3784 jQuery("#radio_standard").prop("disabled", true);
3785 } else {
3786 jQuery("#radio_standard").prop("disabled", false);
3787 }
3788 if (! jQuery("#radio_creditnote").is(":checked"))
3789 {
3790 jQuery("#credit_note_options").hide();
3791 }
3792 jQuery("#radio_creditnote").click(function() {
3793 jQuery("#credit_note_options").show();
3794 });
3795 jQuery("#radio_standard, #radio_replacement, #radio_deposit").click(function() {
3796 jQuery("#credit_note_options").hide();
3797 });
3798 });
3799 </script>';
3800 $text = '<label>'.$tmp.$langs->transnoentities("InvoiceAvoirAsk").'</label> ';
3801 $text .= '<select class="flat valignmiddle" name="fac_avoir" id="fac_avoir"';
3802 if (!$optionsav || $invoice_predefined->id > 0) {
3803 $text .= ' disabled';
3804 }
3805 $text .= '>';
3806 if ($optionsav) {
3807 $text .= '<option value="-1"></option>';
3808 $text .= $optionsav;
3809 } else {
3810 $text .= '<option value="-1">'.$langs->trans("NoInvoiceToCorrect").'</option>';
3811 }
3812 $text .= '</select>';
3813 $desc = $form->textwithpicto($text, $langs->transnoentities("InvoiceAvoirDesc"), 1, 'help', '', 0, 3);
3814 print $desc;
3815
3816 print '<div id="credit_note_options" class="clearboth paddingtop marginbottomonly">';
3817 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>";
3818 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>";
3819 print '</div>';
3820
3821 print '</div></div>';
3822 }
3823 } else {
3824 print '<div class="tagtr listofinvoicetype"><div class="tagtd listofinvoicetype">';
3825 if (!getDolGlobalString('INVOICE_CREDIT_NOTE_STANDALONE')) {
3826 $tmp = '<input type="radio" name="type" id="radio_creditnote" value="0" disabled> ';
3827 } else {
3828 $tmp = '<input type="radio" name="type" id="radio_creditnote" value="2" > ';
3829 }
3830 $text = $tmp.'<label class="opacitymedium" for="radio_creditnote">'.$langs->trans("InvoiceAvoir").'</label> ';
3831 //$text .= '<span class="opacitymedium hideonsmartphone">('.$langs->trans("YouMustCreateInvoiceFromThird").')</span> ';
3832 $desc = $form->textwithpicto($text, $langs->transnoentities("InvoiceAvoirDesc").'<br><br>'.$langs->trans("CreateCreditNoteWhenClientInvoiceExists"), 1, 'help', '', 0, 3, 'creditnoteonsmartphone');
3833 print $desc;
3834 print '</div></div>'."\n";
3835 }
3836 }
3837
3838 // Template invoice
3839 print '<div class="tagtr listofinvoicetype"><div class="tagtd listofinvoicetype">';
3840 $tmp = '<input type="radio" name="type" id="radio_template" value="0" disabled> ';
3841 $text = $tmp.'<label class="opacitymedium" for="radio_template">'.$langs->trans("RepeatableInvoice").'</label> ';
3842 $desc = $form->textwithpicto($text, $langs->transnoentities("YouMustCreateStandardInvoiceFirstDesc"), 1, 'help', '', 0, 3, 'templateonsmartphone');
3843 print $desc;
3844 print '</div></div>';
3845
3846 print '</div>';
3847
3848
3849 if (getDolGlobalString('INVOICE_USE_DEFAULT_DOCUMENT')) { // Hidden conf
3850 // Add auto select default document model
3852 $jsListType = '';
3853 foreach ($listtType as $type) {
3854 $thisTypeConfName = 'FACTURE_ADDON_PDF_'.$type;
3855 $current = getDolGlobalString($thisTypeConfName, getDolGlobalString('FACTURE_ADDON_PDF'));
3856 $jsListType .= (!empty($jsListType) ? ',' : '').'"'.$type.'":"'.$current.'"';
3857 }
3858
3859 print '<script type="text/javascript">
3860 $(document).ready(function() {
3861 var listType = {'.$jsListType.'};
3862 $("[name=\'type\'").change(function() {
3863 console.log("change name=type");
3864 if ($( this ).prop("checked"))
3865 {
3866 if(($( this ).val() in listType))
3867 {
3868 $("#model").val(listType[$( this ).val()]);
3869 }
3870 else
3871 {
3872 $("#model").val("' . getDolGlobalString('FACTURE_ADDON_PDF').'");
3873 }
3874 }
3875 });
3876 });
3877 </script>';
3878 }
3879
3880
3881 print '</td></tr>';
3882
3883 // Invoice Subtype
3884 if (getDolGlobalInt('INVOICE_SUBTYPE_ENABLED')) {
3885 print '<tr><td class="fieldrequired">'.$langs->trans('InvoiceSubtype').'</td><td colspan="2">';
3886 print $form->getSelectInvoiceSubtype(GETPOST('subtype'), 'subtype', 1, 0, '');
3887 print '</td></tr>';
3888 }
3889
3890 // Discounts for the known third party
3891 if ($socid > 0) {
3892 print '<tr><td>'.$langs->trans('DiscountStillRemaining').'</td><td colspan="2">';
3893
3894 $thirdparty = $soc; // used by object_discounts.tpl.php
3895 $discount_type = 0; // used by object_discounts.tpl.php
3896 $backtopage = $_SERVER["PHP_SELF"].'?socid='.$thirdparty->id.'&action='.$action.'&origin='.urlencode((string) (GETPOST('origin'))).'&originid='.urlencode((string) (GETPOSTINT('originid')));
3897 include DOL_DOCUMENT_ROOT.'/core/tpl/object_discounts.tpl.php';
3898
3899 print '</td></tr>';
3900 }
3901
3902 $newdateinvoice = dol_mktime(0, 0, 0, GETPOSTINT('remonth'), GETPOSTINT('reday'), GETPOSTINT('reyear'), 'tzserver');
3903 $date_pointoftax = dol_mktime(0, 0, 0, GETPOSTINT('date_pointoftaxmonth'), GETPOSTINT('date_pointoftaxday'), GETPOSTINT('date_pointoftaxyear'), 'tzserver');
3904
3905 // Date invoice
3906 print '<tr><td class="fieldrequired">'.$langs->trans('DateInvoice').'</td><td colspan="2">';
3907 print img_picto('', 'action', 'class="pictofixedwidth"');
3908 print $form->selectDate($newdateinvoice ? $newdateinvoice : $dateinvoice, '', 0, 0, 0, "add", 1, 1);
3909 print '</td></tr>';
3910
3911 // Date point of tax
3912 if (getDolGlobalString('INVOICE_POINTOFTAX_DATE')) {
3913 print '<tr><td class="fieldrequired">'.$langs->trans('DatePointOfTax').'</td><td colspan="2">';
3914 print img_picto('', 'action', 'class="pictofixedwidth"');
3915 print $form->selectDate($date_pointoftax ? $date_pointoftax : -1, 'date_pointoftax', 0, 0, 0, "add", 1, 1);
3916 print '</td></tr>';
3917 }
3918
3919 // Payment term
3920 print '<tr><td class="nowrap fieldrequired">'.$langs->trans('PaymentConditionsShort').'</td><td colspan="2">';
3921 print img_picto('', 'payment', 'class="pictofixedwidth"');
3922 print $form->getSelectConditionsPaiements($cond_reglement_id, 'cond_reglement_id', -1, 1, 0, 'maxwidth500 widthcentpercentminusx');
3923 print '</td></tr>';
3924
3925 // Warranty
3926 if (getDolGlobalString('INVOICE_USE_RETAINED_WARRANTY')) {
3927 $rwStyle = 'display:none;';
3928 if (in_array(GETPOSTINT('type'), $retainedWarrantyInvoiceAvailableType)) {
3929 $rwStyle = '';
3930 }
3931
3932 $retained_warranty = GETPOSTINT('retained_warranty');
3933 if (empty($retained_warranty)) {
3934 if (!empty($objectsrc->retained_warranty)) { // use previous situation value
3935 $retained_warranty = $objectsrc->retained_warranty;
3936 }
3937 }
3938 $retained_warranty_js_default = !empty($retained_warranty) ? $retained_warranty : getDolGlobalString('INVOICE_SITUATION_DEFAULT_RETAINED_WARRANTY_PERCENT');
3939
3940 print '<tr class="retained-warranty-line" style="'.$rwStyle.'" ><td class="nowrap">'.$langs->trans('RetainedWarranty').'</td><td colspan="2">';
3941 print '<input id="new-situation-invoice-retained-warranty" name="retained_warranty" type="number" value="'.$retained_warranty.'" step="0.01" min="0" max="100" />%';
3942
3943 // Retained warranty payment term
3944 print '<tr class="retained-warranty-line" style="'.$rwStyle.'" ><td class="nowrap">'.$langs->trans('PaymentConditionsShortRetainedWarranty').'</td><td colspan="2">';
3945 $retained_warranty_fk_cond_reglement = GETPOSTINT('retained_warranty_fk_cond_reglement');
3946 if (empty($retained_warranty_fk_cond_reglement)) {
3947 $retained_warranty_fk_cond_reglement = getDolGlobalString('INVOICE_SITUATION_DEFAULT_RETAINED_WARRANTY_COND_ID');
3948 if (!empty($objectsrc->retained_warranty_fk_cond_reglement)) { // use previous situation value
3949 $retained_warranty_fk_cond_reglement = $objectsrc->retained_warranty_fk_cond_reglement;
3950 } else {
3951 $retained_warranty_fk_cond_reglement = getDolGlobalString('INVOICE_SITUATION_DEFAULT_RETAINED_WARRANTY_COND_ID');
3952 }
3953 }
3954 print $form->getSelectConditionsPaiements($retained_warranty_fk_cond_reglement, 'retained_warranty_fk_cond_reglement', -1, 1);
3955 print '</td></tr>';
3956
3957 print '<script type="text/javascript">
3958 $(document).ready(function() {
3959 $("[name=\'type\']").change(function() {
3960 if($( this ).prop("checked") && $.inArray($( this ).val(), '.json_encode($retainedWarrantyInvoiceAvailableType).' ) !== -1)
3961 {
3962 $(".retained-warranty-line").show();
3963 $("#new-situation-invoice-retained-warranty").val("'.(float) $retained_warranty_js_default.'");
3964 }
3965 else{
3966 $(".retained-warranty-line").hide();
3967 $("#new-situation-invoice-retained-warranty").val("");
3968 }
3969 });
3970
3971 $("[name=\'type\']:checked").trigger("change");
3972 });
3973 </script>';
3974 }
3975
3976 // Payment mode
3977 print '<tr><td>'.$langs->trans('PaymentMode').'</td><td colspan="2">';
3978 print img_picto('', 'bank', 'class="pictofixedwidth"');
3979 print $form->select_types_paiements($mode_reglement_id, 'mode_reglement_id', 'CRDT', 0, 1, 0, 0, 1, 'maxwidth200 widthcentpercentminusx', 1);
3980 print '</td></tr>';
3981
3982 // Bank Account
3983 if (isModEnabled("bank")) {
3984 print '<tr><td>'.$langs->trans('BankAccount').'</td><td colspan="2">';
3985 print img_picto('', 'bank_account', 'class="pictofixedwidth"');
3986 print $form->select_comptes($fk_account, 'fk_account', 0, '', 1, '', 0, 'maxwidth200 widthcentpercentminusx', 1);
3987 print '</td></tr>';
3988 }
3989
3990 // Project
3991 if (isModEnabled('project')) {
3992 $langs->load('projects');
3993 print '<tr><td>'.$langs->trans('Project').'</td><td colspan="2">';
3994 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');
3995 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>';
3996 print '</td></tr>';
3997 }
3998
3999 // Incoterms
4000 if (isModEnabled('incoterm')) {
4001 print '<tr>';
4002 print '<td><label for="incoterm_id">'.$form->textwithpicto($langs->trans("IncotermLabel"), !empty($objectsrc->label_incoterms) ? $objectsrc->label_incoterms : '', 1).'</label></td>';
4003 print '<td colspan="2" class="maxwidthonsmartphone">';
4004 $incoterm_id = GETPOST('incoterm_id');
4005 $location_incoterms = GETPOST('location_incoterms');
4006 if (empty($incoterm_id)) {
4007 $incoterm_id = (!empty($objectsrc->fk_incoterms) ? $objectsrc->fk_incoterms : $soc->fk_incoterms);
4008 $location_incoterms = (!empty($objectsrc->location_incoterms) ? $objectsrc->location_incoterms : $soc->location_incoterms);
4009 }
4010 print img_picto('', 'incoterm', 'class="pictofixedwidth"');
4011 print $form->select_incoterms($incoterm_id, $location_incoterms);
4012 print '</td></tr>';
4013 }
4014
4015 // Other attributes
4016 $parameters = array('objectsrc' => !empty($objectsrc) ? $objectsrc : 0, 'colspan' => ' colspan="2"', 'cols' => '2', 'socid' => $socid);
4017 $reshook = $hookmanager->executeHooks('formObjectOptions', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
4018 print $hookmanager->resPrint;
4019 if (empty($reshook)) {
4020 if (getDolGlobalString('THIRDPARTY_PROPAGATE_EXTRAFIELDS_TO_INVOICE') && !empty($soc->id)) {
4021 // copy from thirdparty
4022 $tpExtrafields = new ExtraFields($db);
4023 $tpExtrafieldLabels = $tpExtrafields->fetch_name_optionals_label($soc->table_element);
4024 if ($soc->fetch_optionals() > 0) {
4025 $object->array_options = array_merge($object->array_options, $soc->array_options);
4026 }
4027 }
4028
4029 print $object->showOptionals($extrafields, 'create', $parameters);
4030 }
4031
4032 // Template to use by default
4033 print '<tr><td>'.$langs->trans('Model').'</td>';
4034 print '<td colspan="2">';
4035 print img_picto('', 'pdf', 'class="pictofixedwidth"');
4036 include_once DOL_DOCUMENT_ROOT.'/core/modules/facture/modules_facture.php';
4038 if (getDolGlobalString('INVOICE_USE_DEFAULT_DOCUMENT')) {
4039 $type = GETPOSTISSET('type') ? GETPOSTINT('type') : $object->type;
4040 // Hidden conf
4041 $paramkey = 'FACTURE_ADDON_PDF_'.$type;
4042 $preselected = getDolGlobalString($paramkey, getDolGlobalString('FACTURE_ADDON_PDF'));
4043 } else {
4044 $preselected = getDolGlobalString('FACTURE_ADDON_PDF');
4045 }
4046 print $form->selectarray('model', $liste, $preselected, 0, 0, 0, '', 0, 0, 0, '', 'maxwidth200 widthcentpercentminusx', 1);
4047 print "</td></tr>";
4048
4049 // Multicurrency
4050 if (isModEnabled('multicurrency')) {
4051 print '<tr>';
4052 print '<td>'.$form->editfieldkey('Currency', 'multicurrency_code', '', $object, 0).'</td>';
4053 print '<td colspan="2" class="maxwidthonsmartphone">';
4054 print img_picto('', 'currency', 'class="pictofixedwidth"');
4055 print $form->selectMultiCurrency(((GETPOSTISSET('multicurrency_code') && !GETPOST('changecompany')) ? GETPOST('multicurrency_code') : $currency_code), 'multicurrency_code', 0, '', false, 'maxwidth100 widthcentpercentminusx');
4056 print '</td></tr>';
4057 }
4058
4059 // Help of substitution key
4060 $htmltext = '';
4061 if (GETPOSTINT('fac_rec') > 0) {
4062 $dateexample = ($newdateinvoice ? $newdateinvoice : $dateinvoice);
4063 if (empty($dateexample)) {
4064 $dateexample = dol_now();
4065 }
4066 $substitutionarray = array(
4067 '__TOTAL_HT__' => $langs->trans("AmountHT").' ('.$langs->trans("Example").': '.price($exampletemplateinvoice->total_ht).')',
4068 '__TOTAL_TTC__' => $langs->trans("AmountTTC").' ('.$langs->trans("Example").': '.price($exampletemplateinvoice->total_ttc).')',
4069 '__INVOICE_PREVIOUS_MONTH__' => $langs->trans("PreviousMonthOfInvoice").' ('.$langs->trans("Example").': '.dol_print_date(dol_time_plus_duree($dateexample, -1, 'm'), '%m').')',
4070 '__INVOICE_MONTH__' => $langs->trans("MonthOfInvoice").' ('.$langs->trans("Example").': '.dol_print_date($dateexample, '%m').')',
4071 '__INVOICE_NEXT_MONTH__' => $langs->trans("NextMonthOfInvoice").' ('.$langs->trans("Example").': '.dol_print_date(dol_time_plus_duree($dateexample, 1, 'm'), '%m').')',
4072 '__INVOICE_PREVIOUS_MONTH_TEXT__' => $langs->trans("TextPreviousMonthOfInvoice").' ('.$langs->trans("Example").': '.dol_print_date(dol_time_plus_duree($dateexample, -1, 'm'), '%B').')',
4073 '__INVOICE_MONTH_TEXT__' => $langs->trans("TextMonthOfInvoice").' ('.$langs->trans("Example").': '.dol_print_date($dateexample, '%B').')',
4074 '__INVOICE_NEXT_MONTH_TEXT__' => $langs->trans("TextNextMonthOfInvoice").' ('.$langs->trans("Example").': '.dol_print_date(dol_time_plus_duree($dateexample, 1, 'm'), '%B').')',
4075 '__INVOICE_PREVIOUS_YEAR__' => $langs->trans("PreviousYearOfInvoice").' ('.$langs->trans("Example").': '.dol_print_date(dol_time_plus_duree($dateexample, -1, 'y'), '%Y').')',
4076 '__INVOICE_YEAR__' => $langs->trans("YearOfInvoice").' ('.$langs->trans("Example").': '.dol_print_date($dateexample, '%Y').')',
4077 '__INVOICE_NEXT_YEAR__' => $langs->trans("NextYearOfInvoice").' ('.$langs->trans("Example").': '.dol_print_date(dol_time_plus_duree($dateexample, 1, 'y'), '%Y').')'
4078 );
4079
4080 $htmltext = '<i>'.$langs->trans("FollowingConstantsWillBeSubstituted").':<br>';
4081 foreach ($substitutionarray as $key => $val) {
4082 $htmltext .= $key.' = '.$langs->trans($val).'<br>';
4083 }
4084 $htmltext .= '</i>';
4085 }
4086
4087 // Public note
4088 print '<tr>';
4089 print '<td class="tdtop">';
4090 print $form->textwithpicto($langs->trans('NotePublic'), $htmltext);
4091 print '</td>';
4092 print '<td valign="top" colspan="2">';
4093 $doleditor = new DolEditor('note_public', $note_public, '', 80, 'dolibarr_notes', 'In', 0, false, !getDolGlobalString('FCKEDITOR_ENABLE_NOTE_PUBLIC') ? 0 : 1, ROWS_3, '90%');
4094 print $doleditor->Create(1);
4095
4096 // Private note
4097 if (empty($user->socid)) {
4098 print '<tr>';
4099 print '<td class="tdtop">';
4100 print $form->textwithpicto($langs->trans('NotePrivate'), $htmltext);
4101 print '</td>';
4102 print '<td valign="top" colspan="2">';
4103 $doleditor = new DolEditor('note_private', $note_private, '', 80, 'dolibarr_notes', 'In', 0, false, !getDolGlobalString('FCKEDITOR_ENABLE_NOTE_PRIVATE') ? 0 : 1, ROWS_3, '90%');
4104 print $doleditor->Create(1);
4105 // print '<textarea name="note_private" wrap="soft" cols="70" rows="'.ROWS_3.'">'.$note_private.'.</textarea>
4106 print '</td></tr>';
4107 }
4108
4109 // Lines from source (TODO Show them also when creating invoice from template invoice)
4110 if (!empty($origin) && !empty($originid) && is_object($objectsrc)) {
4111 $langs->loadLangs(array('orders', 'propal'));
4112
4113 // TODO for compatibility
4114 if ($origin == 'contrat') {
4115 // Calcul contrat->price (HT), contrat->total (TTC), contrat->tva
4116 $objectsrc->update_price(1, 'auto', 1);
4117 }
4118
4119 print "\n<!-- Show ref of origin ".$classname." -->\n";
4120 print '<input type="hidden" name="amount" value="'.$objectsrc->total_ht.'">'."\n";
4121 print '<input type="hidden" name="total" value="'.$objectsrc->total_ttc.'">'."\n";
4122 print '<input type="hidden" name="tva" value="'.$objectsrc->total_tva.'">'."\n";
4123 // The commented lines below are fields already added as hidden parameters before
4124 //print '<input type="hidden" name="origin" value="'.$objectsrc->element.'">';
4125 //print '<input type="hidden" name="originid" value="'.$objectsrc->id.'">';
4126
4127 switch (get_class($objectsrc)) {
4128 case 'Propal':
4129 $newclassname = 'CommercialProposal';
4130 break;
4131 case 'Commande':
4132 $newclassname = 'Order';
4133 break;
4134 case 'Expedition':
4135 $newclassname = 'Sending';
4136 break;
4137 case 'Contrat':
4138 $newclassname = 'Contract';
4139 break;
4140 case 'Fichinter':
4141 $newclassname = 'Intervention';
4142 break;
4143 default:
4144 $newclassname = get_class($objectsrc);
4145 }
4146
4147 // Ref of origin
4148 print '<tr><td>'.$langs->trans($newclassname).'</td>';
4149 print '<td colspan="2">';
4150 print $objectsrc->getNomUrl(1);
4151 // We check if Origin document (id and type is known) has already at least one invoice attached to it
4152 $objectsrc->fetchObjectLinked($originid, $origin, null, 'facture');
4153 if (isset($objectsrc->linkedObjects['facture']) && is_array($objectsrc->linkedObjects['facture']) && count($objectsrc->linkedObjects['facture']) >= 1) {
4154 setEventMessages('WarningBillExist', null, 'warnings');
4155 echo ' - '.$langs->trans('LatestRelatedBill').' '.end($objectsrc->linkedObjects['facture'])->getNomUrl(1);
4156 }
4157 echo '</td></tr>';
4158 print '<tr><td>'.$langs->trans('AmountHT').'</td><td colspan="2">'.price($objectsrc->total_ht).'</td></tr>';
4159 print '<tr><td>'.$langs->trans('AmountVAT').'</td><td colspan="2">'.price($objectsrc->total_tva)."</td></tr>";
4160 if ($mysoc->localtax1_assuj == "1" || $objectsrc->total_localtax1 != 0) { // Localtax1
4161 print '<tr><td>'.$langs->transcountry("AmountLT1", $mysoc->country_code).'</td><td colspan="2">'.price($objectsrc->total_localtax1)."</td></tr>";
4162 }
4163
4164 if ($mysoc->localtax2_assuj == "1" || $objectsrc->total_localtax2 != 0) { // Localtax2
4165 print '<tr><td>'.$langs->transcountry("AmountLT2", $mysoc->country_code).'</td><td colspan="2">'.price($objectsrc->total_localtax2)."</td></tr>";
4166 }
4167 print '<tr><td>'.$langs->trans('AmountTTC').'</td><td colspan="2">'.price($objectsrc->total_ttc)."</td></tr>";
4168
4169 if (isModEnabled('multicurrency')) {
4170 print '<tr><td>'.$langs->trans('MulticurrencyAmountHT').'</td><td colspan="2">'.price($objectsrc->multicurrency_total_ht).'</td></tr>';
4171 print '<tr><td>'.$langs->trans('MulticurrencyAmountVAT').'</td><td colspan="2">'.price($objectsrc->multicurrency_total_tva)."</td></tr>";
4172 print '<tr><td>'.$langs->trans('MulticurrencyAmountTTC').'</td><td colspan="2">'.price($objectsrc->multicurrency_total_ttc)."</td></tr>";
4173 }
4174 }
4175
4176 print "</table>\n";
4177 }
4178 print dol_get_fiche_end();
4179
4180 print $form->buttonsSaveCancel("CreateDraft");
4181
4182 // Show origin lines
4183 if (!empty($origin) && !empty($originid) && is_object($objectsrc)) {
4184 print '<br>';
4185
4186 $title = $langs->trans('ProductsAndServices');
4187 print load_fiche_titre($title);
4188
4189 print '<div class="div-table-responsive-no-min">';
4190 print '<table class="noborder centpercent">';
4191
4192 $objectsrc->printOriginLinesList('', $selectedLines);
4193
4194 print '</table>';
4195 print '</div>';
4196 }
4197
4198 print "</form>\n";
4199} elseif ($id > 0 || !empty($ref)) {
4200 if (empty($object->id)) {
4201 $langs->load('errors');
4202 echo '<div class="error">'.$langs->trans("ErrorRecordNotFound").'</div>';
4203 llxFooter();
4204 exit;
4205 }
4206
4207 /*
4208 * Show object in view mode
4209 */
4210
4211 $result = $object->fetch($id, $ref);
4212 if ($result <= 0) {
4213 dol_print_error($db, $object->error, $object->errors);
4214 exit();
4215 }
4216
4217 // fetch optionals attributes and labels
4218 $extrafields->fetch_name_optionals_label($object->table_element);
4219
4220 if ($user->socid > 0 && $user->socid != $object->socid) {
4221 accessforbidden('', 0, 1);
4222 }
4223
4224 $result = $object->fetch_thirdparty();
4225
4226 $result = $soc->fetch($object->socid);
4227 if ($result < 0) {
4228 dol_print_error($db);
4229 }
4230 $selleruserevenustamp = $mysoc->useRevenueStamp();
4231
4232 $totalpaid = $object->getSommePaiement();
4233 $totalcreditnotes = $object->getSumCreditNotesUsed();
4234 $totaldeposits = $object->getSumDepositsUsed();
4235 //print "totalpaid=".$totalpaid." totalcreditnotes=".$totalcreditnotes." totaldeposts=".$totaldeposits."
4236 // selleruserrevenuestamp=".$selleruserevenustamp;
4237
4238 // We can also use bcadd to avoid pb with floating points
4239 // For example print 239.2 - 229.3 - 9.9; does not return 0.
4240 $resteapayer = price2num($object->total_ttc - $totalpaid - $totalcreditnotes - $totaldeposits, 'MT');
4241
4242 // Multicurrency
4243 if (isModEnabled('multicurrency')) {
4244 $multicurrency_totalpaid = $object->getSommePaiement(1);
4245 $multicurrency_totalcreditnotes = $object->getSumCreditNotesUsed(1);
4246 $multicurrency_totaldeposits = $object->getSumDepositsUsed(1);
4247 $multicurrency_resteapayer = price2num($object->multicurrency_total_ttc - $multicurrency_totalpaid - $multicurrency_totalcreditnotes - $multicurrency_totaldeposits, 'MT');
4248 // Code to fix case of corrupted data
4249 // 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
4250 // 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)
4251 if ($resteapayer == 0 && $multicurrency_resteapayer != 0 && $object->multicurrency_code != $conf->currency) {
4252 $resteapayer = price2num((float) $multicurrency_resteapayer / $object->multicurrency_tx, 'MT');
4253 }
4254 }
4255
4256 if ($object->paye) {
4257 $resteapayer = 0;
4258 }
4259 $resteapayeraffiche = $resteapayer;
4260
4261 if (getDolGlobalString('FACTURE_DEPOSITS_ARE_JUST_PAYMENTS')) { // Never use this
4262 $filterabsolutediscount = "fk_facture_source IS NULL"; // If we want deposit to be subtracted to payments only and not to total of final invoice
4263 $filtercreditnote = "fk_facture_source IS NOT NULL"; // If we want deposit to be subtracted to payments only and not to total of final invoice
4264 } else {
4265 $filterabsolutediscount = "fk_facture_source IS NULL OR (description LIKE '(DEPOSIT)%' AND description NOT LIKE '(EXCESS RECEIVED)%')";
4266 $filtercreditnote = "fk_facture_source IS NOT NULL AND (description NOT LIKE '(DEPOSIT)%' OR description LIKE '(EXCESS RECEIVED)%')";
4267 }
4268
4269 $absolute_discount = $soc->getAvailableDiscounts(null, $filterabsolutediscount);
4270 $absolute_creditnote = $soc->getAvailableDiscounts(null, $filtercreditnote);
4271 $absolute_discount = price2num($absolute_discount, 'MT');
4272 $absolute_creditnote = price2num($absolute_creditnote, 'MT');
4273
4274 $author = new User($db);
4275 if ($object->user_creation_id) {
4276 $author->fetch($object->user_creation_id);
4277 }
4278
4279 $objectidnext = $object->getIdReplacingInvoice();
4280
4282
4283 print dol_get_fiche_head($head, 'compta', $langs->trans('InvoiceCustomer'), -1, 'bill');
4284
4285 $formconfirm = '';
4286
4287 // Confirmation of the conversion of the credit into a reduction
4288 if ($action == 'converttoreduc') {
4290 $type_fac = 'ExcessReceived';
4291 } elseif ($object->type == Facture::TYPE_CREDIT_NOTE) {
4292 $type_fac = 'CreditNote';
4293 } elseif ($object->type == Facture::TYPE_DEPOSIT) {
4294 $type_fac = 'Deposit';
4295 }
4296 $text = $langs->trans('ConfirmConvertToReduc', strtolower($langs->transnoentities($type_fac)));
4297 $text .= '<br>'.$langs->trans('ConfirmConvertToReduc2');
4298 $formconfirm = $form->formconfirm($_SERVER['PHP_SELF'].'?facid='.$object->id, $langs->trans('ConvertToReduc'), $text, 'confirm_converttoreduc', '', "yes", 2);
4299 }
4300
4301 // Confirmation to delete invoice
4302 if ($action == 'delete') {
4303 $text = $langs->trans('ConfirmDeleteBill', $object->ref);
4304 $formquestion = array();
4305
4306 if ($object->type != Facture::TYPE_DEPOSIT && getDolGlobalString('STOCK_CALCULATE_ON_BILL') && $object->status >= 1) {
4307 $qualified_for_stock_change = 0;
4308 if (!getDolGlobalString('STOCK_SUPPORTS_SERVICES')) {
4309 $qualified_for_stock_change = $object->hasProductsOrServices(2);
4310 } else {
4311 $qualified_for_stock_change = $object->hasProductsOrServices(1);
4312 }
4313
4314 if ($qualified_for_stock_change) {
4315 $langs->load("stocks");
4316 require_once DOL_DOCUMENT_ROOT.'/product/class/html.formproduct.class.php';
4317 $formproduct = new FormProduct($db);
4318 $label = $object->type == Facture::TYPE_CREDIT_NOTE ? $langs->trans("SelectWarehouseForStockDecrease") : $langs->trans("SelectWarehouseForStockIncrease");
4319 $forcecombo = 0;
4320 if ($conf->browser->name == 'ie') {
4321 $forcecombo = 1; // There is a bug in IE10 that make combo inside popup crazy
4322 }
4323 $formquestion = array(
4324 // 'text' => $langs->trans("ConfirmClone"),
4325 // array('type' => 'checkbox', 'name' => 'clone_content', 'label' => $langs->trans("CloneMainAttributes"), 'value' => 1),
4326 // array('type' => 'checkbox', 'name' => 'update_prices', 'label' => $langs->trans("PuttingPricesUpToDate"), 'value' => 1),
4327 array('type' => 'other', 'name' => 'idwarehouse', 'label' => $label, 'value' => $formproduct->selectWarehouses(GETPOST('idwarehouse') ? GETPOST('idwarehouse') : 'ifone', 'idwarehouse', '', 1, 0, 0, $langs->trans("NoStockAction"), 0, $forcecombo))
4328 );
4329 $formconfirm = $form->formconfirm($_SERVER['PHP_SELF'].'?facid='.$object->id, $langs->trans('DeleteBill'), $text, 'confirm_delete', $formquestion, "yes", 1);
4330 } else {
4331 $formconfirm = $form->formconfirm($_SERVER['PHP_SELF'].'?facid='.$object->id, $langs->trans('DeleteBill'), $text, 'confirm_delete', '', 'no', 1);
4332 }
4333 } else {
4334 $formconfirm = $form->formconfirm($_SERVER['PHP_SELF'].'?facid='.$object->id, $langs->trans('DeleteBill'), $text, 'confirm_delete', '', 'no', 1);
4335 }
4336 }
4337
4338 // Confirmation to remove invoice from cycle
4339 if ($action == 'situationout') {
4340 $text = $langs->trans('ConfirmRemoveSituationFromCycle', $object->ref);
4341 $label = $langs->trans("ConfirmOuting");
4342 $formquestion = array();
4343 // remove situation from cycle
4344 if (in_array($object->status, array(Facture::STATUS_CLOSED, Facture::STATUS_VALIDATED))
4345 && $usercancreate
4346 && !$objectidnext
4347 && $object->is_last_in_cycle()
4348 && $usercanunvalidate
4349 ) {
4350 $formconfirm = $form->formconfirm($_SERVER['PHP_SELF'].'?facid='.$object->id, $label, $text, 'confirm_situationout', $formquestion, "yes", 1);
4351 }
4352 }
4353
4354 // Confirmation of validation
4355 if ($action == 'valid') {
4356 // we check object has a draft number
4357 $objectref = substr($object->ref, 1, 4);
4358 if ($objectref == 'PROV') {
4359 $savdate = $object->date;
4360 if (getDolGlobalString('FAC_FORCE_DATE_VALIDATION')) {
4361 $object->date = dol_now();
4362 $object->date_lim_reglement = $object->calculate_date_lim_reglement();
4363 }
4364 $numref = $object->getNextNumRef($soc);
4365 // $object->date=$savdate;
4366 } else {
4367 $numref = $object->ref;
4368 }
4369
4370 $text = $langs->trans('ConfirmValidateBill', $numref);
4371 if (isModEnabled('notification')) {
4372 require_once DOL_DOCUMENT_ROOT.'/core/class/notify.class.php';
4373 $notify = new Notify($db);
4374 $text .= '<br>';
4375 $text .= $notify->confirmMessage('BILL_VALIDATE', $object->socid, $object);
4376 }
4377 $formquestion = array();
4378
4379 if ($object->type != Facture::TYPE_DEPOSIT && getDolGlobalString('STOCK_CALCULATE_ON_BILL')) {
4380 $qualified_for_stock_change = 0;
4381 if (!getDolGlobalString('STOCK_SUPPORTS_SERVICES')) {
4382 $qualified_for_stock_change = $object->hasProductsOrServices(2);
4383 } else {
4384 $qualified_for_stock_change = $object->hasProductsOrServices(1);
4385 }
4386
4387 if ($qualified_for_stock_change) {
4388 $langs->load("stocks");
4389 require_once DOL_DOCUMENT_ROOT.'/product/class/html.formproduct.class.php';
4390 require_once DOL_DOCUMENT_ROOT.'/product/stock/class/entrepot.class.php';
4391 $formproduct = new FormProduct($db);
4392 $warehouse = new Entrepot($db);
4393 $warehouse_array = $warehouse->list_array();
4394 if (count($warehouse_array) == 1) {
4395 $label = $object->type == Facture::TYPE_CREDIT_NOTE ? $langs->trans("WarehouseForStockIncrease", current($warehouse_array)) : $langs->trans("WarehouseForStockDecrease", current($warehouse_array));
4396 $value = '<input type="hidden" id="idwarehouse" name="idwarehouse" value="'.key($warehouse_array).'">';
4397 } else {
4398 $label = $object->type == Facture::TYPE_CREDIT_NOTE ? $langs->trans("SelectWarehouseForStockIncrease") : $langs->trans("SelectWarehouseForStockDecrease");
4399 $value = $formproduct->selectWarehouses(GETPOST('idwarehouse') ? GETPOST('idwarehouse') : 'ifone', 'idwarehouse', '', 1);
4400 }
4401 $formquestion = array(
4402 // 'text' => $langs->trans("ConfirmClone"),
4403 // array('type' => 'checkbox', 'name' => 'clone_content', 'label' => $langs->trans("CloneMainAttributes"), 'value' =>
4404 // 1),
4405 // array('type' => 'checkbox', 'name' => 'update_prices', 'label' => $langs->trans("PuttingPricesUpToDate"), 'value'
4406 // => 1),
4407 array('type' => 'other', 'name' => 'idwarehouse', 'label' => $label, 'value' => $value));
4408 }
4409 }
4410 if ($object->type != Facture::TYPE_CREDIT_NOTE && $object->total_ttc < 0) { // Can happen only if getDolGlobalString('FACTURE_ENABLE_NEGATIVE') is on
4411 $text .= '<br>'.img_warning().' '.$langs->trans("ErrorInvoiceOfThisTypeMustBePositive");
4412 }
4413
4414 // mandatoryPeriod
4415 $nbMandated = 0;
4416 foreach ($object->lines as $line) {
4417 $res = $line->fetch_product();
4418 if ($res > 0) {
4419 if ($line->product->isService() && $line->product->isMandatoryPeriod() && (empty($line->date_start) || empty($line->date_end))) {
4420 $nbMandated++;
4421 break;
4422 }
4423 }
4424 }
4425 if ($nbMandated > 0) {
4426 if (getDolGlobalString('SERVICE_STRICT_MANDATORY_PERIOD')) {
4427 setEventMessages($langs->trans("mandatoryPeriodNeedTobeSetMsgValidate"), null, 'errors');
4428 $error++;
4429 } else {
4430 $text .= '<div><span class="clearboth nowraponall warning">'.img_warning().$langs->trans("mandatoryPeriodNeedTobeSetMsgValidate").'</span></div>';
4431 }
4432 }
4433
4434 if (!$error) {
4435 $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);
4436 }
4437 }
4438
4439 // Confirm back to draft status
4440 if ($action == 'modif') {
4441 $text = $langs->trans('ConfirmUnvalidateBill', $object->ref);
4442 $formquestion = array();
4443
4444 if ($object->type != Facture::TYPE_DEPOSIT && getDolGlobalString('STOCK_CALCULATE_ON_BILL')) {
4445 $qualified_for_stock_change = 0;
4446 if (!getDolGlobalString('STOCK_SUPPORTS_SERVICES')) {
4447 $qualified_for_stock_change = $object->hasProductsOrServices(2);
4448 } else {
4449 $qualified_for_stock_change = $object->hasProductsOrServices(1);
4450 }
4451
4452 if ($qualified_for_stock_change) {
4453 $langs->load("stocks");
4454 require_once DOL_DOCUMENT_ROOT.'/product/class/html.formproduct.class.php';
4455 require_once DOL_DOCUMENT_ROOT.'/product/stock/class/entrepot.class.php';
4456 $formproduct = new FormProduct($db);
4457 $warehouse = new Entrepot($db);
4458 $warehouse_array = $warehouse->list_array();
4459 if (count($warehouse_array) == 1) {
4460 $label = $object->type == Facture::TYPE_CREDIT_NOTE ? $langs->trans("WarehouseForStockDecrease", current($warehouse_array)) : $langs->trans("WarehouseForStockIncrease", current($warehouse_array));
4461 $value = '<input type="hidden" id="idwarehouse" name="idwarehouse" value="'.key($warehouse_array).'">';
4462 } else {
4463 $label = $object->type == Facture::TYPE_CREDIT_NOTE ? $langs->trans("SelectWarehouseForStockDecrease") : $langs->trans("SelectWarehouseForStockIncrease");
4464 $value = $formproduct->selectWarehouses(GETPOST('idwarehouse') ? GETPOST('idwarehouse') : 'ifone', 'idwarehouse', '', 1);
4465 }
4466 $formquestion = array(
4467 // 'text' => $langs->trans("ConfirmClone"),
4468 // array('type' => 'checkbox', 'name' => 'clone_content', 'label' => $langs->trans("CloneMainAttributes"), 'value' =>
4469 // 1),
4470 // array('type' => 'checkbox', 'name' => 'update_prices', 'label' => $langs->trans("PuttingPricesUpToDate"), 'value'
4471 // => 1),
4472 array('type' => 'other', 'name' => 'idwarehouse', 'label' => $label, 'value' => $value));
4473 }
4474 }
4475
4476 $formconfirm = $form->formconfirm($_SERVER["PHP_SELF"].'?facid='.$object->id, $langs->trans('UnvalidateBill'), $text, 'confirm_modif', $formquestion, "yes", 1);
4477 }
4478
4479 // Confirmation of payment classification
4480 if ($action == 'paid' && ($resteapayer <= 0 || (getDolGlobalString('INVOICE_CAN_SET_PAID_EVEN_IF_PARTIALLY_PAID') && $resteapayer == $object->total_ttc))) {
4481 $formconfirm = $form->formconfirm($_SERVER["PHP_SELF"].'?facid='.$object->id, $langs->trans('ClassifyPaid'), $langs->trans('ConfirmClassifyPaidBill', $object->ref), 'confirm_paid', '', "yes", 1);
4482 }
4483 if ($action == 'paid' && $resteapayer > 0 && (!getDolGlobalString('INVOICE_CAN_SET_PAID_EVEN_IF_PARTIALLY_PAID') || $resteapayer != $object->total_ttc)) {
4484 $close = array();
4485 // Code
4486 $i = 0;
4487 $close[$i]['code'] = 'discount_vat'; // escompte
4488 $i++;
4489 $close[$i]['code'] = 'badcustomer';
4490 $i++;
4491 $close[$i]['code'] = 'bankcharge';
4492 $i++;
4493 $close[$i]['code'] = 'withholdingtax';
4494 $i++;
4495 $close[$i]['code'] = 'other';
4496 $i++;
4497 // Help
4498 $i = 0;
4499 $close[$i]['label'] = $langs->trans("HelpEscompte").'<br><br>'.$langs->trans("ConfirmClassifyPaidPartiallyReasonDiscountVatDesc");
4500 $i++;
4501 $close[$i]['label'] = $langs->trans("ConfirmClassifyPaidPartiallyReasonBadCustomerDesc");
4502 $i++;
4503 $close[$i]['label'] = $langs->trans("ConfirmClassifyPaidPartiallyReasonBankChargeDesc");
4504 $i++;
4505 $close[$i]['label'] = $langs->trans("ConfirmClassifyPaidPartiallyReasonWithholdingTaxDesc");
4506 $i++;
4507 $close[$i]['label'] = $langs->trans("Other");
4508 $i++;
4509 // Texte
4510 $i = 0;
4511 $close[$i]['reason'] = $form->textwithpicto($langs->transnoentities("ConfirmClassifyPaidPartiallyReasonDiscount", $resteapayer, $langs->trans("Currency".$conf->currency)), $close[$i]['label'], 1);
4512 $i++;
4513 $close[$i]['reason'] = $form->textwithpicto($langs->transnoentities("ConfirmClassifyPaidPartiallyReasonBadCustomer", $resteapayer, $langs->trans("Currency".$conf->currency)), $close[$i]['label'], 1);
4514 $i++;
4515 $close[$i]['reason'] = $form->textwithpicto($langs->transnoentities("ConfirmClassifyPaidPartiallyReasonBankCharge", $resteapayer, $langs->trans("Currency".$conf->currency)), $close[$i]['label'], 1);
4516 $i++;
4517 $close[$i]['reason'] = $form->textwithpicto($langs->transnoentities("ConfirmClassifyPaidPartiallyReasonWithholdingTax"), $close[$i]['label'], 1);
4518 $i++;
4519 $close[$i]['reason'] = $form->textwithpicto($langs->transnoentities("Other"), $close[$i]['label'], 1);
4520 $i++;
4521 // arrayreasons[code]=reason
4522 $arrayreasons = [];
4523 foreach ($close as $key => $val) {
4524 $arrayreasons[$close[$key]['code']] = $close[$key]['reason'];
4525 }
4526
4527 // Create a form table
4528 $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'));
4529 // Incomplete payment. We ask if reason = discount or other
4530 $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);
4531 }
4532
4533 // Confirmation of status abandoned
4534 if ($action == 'canceled') {
4535 // If there is a replacement invoice not yet validated (draft state),
4536 // it is not allowed to classify the invoice as abandoned.
4537 if ($objectidnext) {
4538 $facturereplacement = new Facture($db);
4539 $facturereplacement->fetch($objectidnext);
4540 $statusreplacement = $facturereplacement->status;
4541 }
4542 if ($objectidnext && $statusreplacement == 0) {
4543 print '<div class="error">'.$langs->trans("ErrorCantCancelIfReplacementInvoiceNotValidated").'</div>';
4544 } else {
4545 // Code
4546 $close[1]['code'] = 'badcustomer';
4547 $close[2]['code'] = 'abandon';
4548 // Help
4549 $close[1]['label'] = $langs->trans("ConfirmClassifyPaidPartiallyReasonBadCustomerDesc");
4550 $close[2]['label'] = $langs->trans("ConfirmClassifyAbandonReasonOtherDesc");
4551 // Text
4552 $close[1]['reason'] = $form->textwithpicto($langs->transnoentities("ConfirmClassifyPaidPartiallyReasonBadCustomer", $object->ref), $close[1]['label'], 1);
4553 $close[2]['reason'] = $form->textwithpicto($langs->transnoentities("ConfirmClassifyAbandonReasonOther"), $close[2]['label'], 1);
4554 // arrayreasons
4555 $arrayreasons = [];
4556 $arrayreasons[$close[1]['code']] = $close[1]['reason'];
4557 $arrayreasons[$close[2]['code']] = $close[2]['reason'];
4558
4559 // Create a form table
4560 $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'));
4561
4562 $formconfirm = $form->formconfirm($_SERVER['PHP_SELF'].'?facid='.$object->id, $langs->trans('CancelBill'), $langs->trans('ConfirmCancelBill', $object->ref), 'confirm_canceled', $formquestion, "yes", 1, 270);
4563 }
4564 }
4565
4566 if ($action == 'deletepayment') {
4567 $payment_id = GETPOST('paiement_id');
4568 $formconfirm = $form->formconfirm($_SERVER["PHP_SELF"].'?id='.$object->id.'&paiement_id='.$payment_id, $langs->trans('DeletePayment'), $langs->trans('ConfirmDeletePayment'), 'confirm_delete_paiement', '', 'no', 1);
4569 }
4570
4571 // Confirmation de la suppression d'une ligne produit
4572 if ($action == 'ask_deleteline') {
4573 $formconfirm = $form->formconfirm($_SERVER["PHP_SELF"].'?facid='.$object->id.'&lineid='.$lineid, $langs->trans('DeleteProductLine'), $langs->trans('ConfirmDeleteProductLine'), 'confirm_deleteline', '', 'no', 1);
4574 }
4575
4576 // Clone confirmation
4577 if ($action == 'clone') {
4578 $filter = '(s.client:IN:1,2,3)';
4579 // Create an array for form
4580 $formquestion = array(
4581 array('type' => 'other', 'name' => 'socid', 'label' => $langs->trans("SelectThirdParty"), 'value' => $form->select_company($object->socid, 'socid', $filter, 1)),
4582 array('type' => 'date', 'name' => 'newdate', 'label' => $langs->trans("Date"), 'value' => dol_now())
4583 );
4584 // Request confirmation to clone
4585 $formconfirm = $form->formconfirm($_SERVER["PHP_SELF"].'?facid='.$object->id, $langs->trans('ToClone'), $langs->trans('ConfirmCloneInvoice', $object->ref), 'confirm_clone', $formquestion, 'yes', 1, 250);
4586 }
4587
4588 if ($action == "remove_file_comfirm") {
4589 $file = GETPOST('file', 'alpha');
4590
4591 $formconfirm = $form->formconfirm(
4592 $_SERVER["PHP_SELF"].'?facid='.$object->id.'&file='.urlencode($file),
4593 $langs->trans('DeleteFileHeader'),
4594 $langs->trans('DeleteFileText')."<br><br>".$file,
4595 'remove_file',
4596 '',
4597 'no',
4598 1
4599 );
4600 }
4601
4602 // Call Hook formConfirm
4603 $parameters = array('formConfirm' => $formconfirm, 'lineid' => $lineid, 'remainingtopay' => &$resteapayer);
4604 $reshook = $hookmanager->executeHooks('formConfirm', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
4605 if (empty($reshook)) {
4606 $formconfirm .= $hookmanager->resPrint;
4607 } elseif ($reshook > 0) {
4608 $formconfirm = $hookmanager->resPrint;
4609 }
4610
4611 // Print form confirm
4612 print $formconfirm;
4613
4614 // Invoice content
4615
4616 $linkback = '<a href="'.DOL_URL_ROOT.'/compta/facture/list.php?restore_lastsearch_values=1'.(!empty($socid) ? '&socid='.$socid : '').'">'.$langs->trans("BackToList").'</a>';
4617
4618 $morehtmlref = '<div class="refidno">';
4619 // Ref invoice
4620 if ($object->status == $object::STATUS_DRAFT && !$mysoc->isInEEC() && getDolGlobalString('INVOICE_ALLOW_FREE_REF')) {
4621 $morehtmlref .= $form->editfieldkey("Ref", 'ref', $object->ref, $object, $usercancreate, 'string', '', 0, 1);
4622 $morehtmlref .= $form->editfieldval("Ref", 'ref', $object->ref, $object, $usercancreate, 'string', '', null, null, '', 1);
4623 $morehtmlref .= '<br>';
4624 }
4625 // Ref customer
4626 $morehtmlref .= $form->editfieldkey("RefCustomer", 'ref_client', $object->ref_customer, $object, $usercancreate, 'string', '', 0, 1);
4627 $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);
4628 // Thirdparty
4629 $morehtmlref .= '<br>'.$object->thirdparty->getNomUrl(1, 'customer');
4630 if (!getDolGlobalString('MAIN_DISABLE_OTHER_LINK') && $object->thirdparty->id > 0) {
4631 $morehtmlref .= ' (<a href="'.DOL_URL_ROOT.'/compta/facture/list.php?socid='.$object->thirdparty->id.'&search_societe='.urlencode($object->thirdparty->name).'">'.$langs->trans("OtherBills").'</a>)';
4632 }
4633 // Project
4634 if (isModEnabled('project')) {
4635 $langs->load("projects");
4636 $morehtmlref .= '<br>';
4637 if ($usercancreate) {
4638 $morehtmlref .= img_picto($langs->trans("Project"), 'project', 'class="pictofixedwidth"');
4639 if ($action != 'classify') {
4640 $morehtmlref .= '<a class="editfielda" href="'.$_SERVER['PHP_SELF'].'?action=classify&token='.newToken().'&id='.$object->id.'">'.img_edit($langs->transnoentitiesnoconv('SetProject')).'</a> ';
4641 }
4642 $morehtmlref .= $form->form_project($_SERVER['PHP_SELF'].'?id='.$object->id, $object->socid, $object->fk_project, ($action == 'classify' ? 'projectid' : 'none'), 0, 0, 0, 1, '', 'maxwidth300');
4643 } else {
4644 if (!empty($object->fk_project)) {
4645 $proj = new Project($db);
4646 $proj->fetch($object->fk_project);
4647 $morehtmlref .= $proj->getNomUrl(1);
4648 if ($proj->title) {
4649 $morehtmlref .= '<span class="opacitymedium"> - '.dol_escape_htmltag($proj->title).'</span>';
4650 }
4651 }
4652 }
4653 }
4654 $morehtmlref .= '</div>';
4655
4656 $object->totalpaid = $totalpaid; // To give a chance to dol_banner_tab to use already paid amount to show correct status
4657
4658 dol_banner_tab($object, 'ref', $linkback, 1, 'ref', 'ref', $morehtmlref, '', 0, '', '');
4659
4660 // Call Hook tabContentViewInvoice
4661 $parameters = array();
4662 // Note that $action and $object may be modified by hook
4663 $reshook = $hookmanager->executeHooks('tabContentViewInvoice', $parameters, $object, $action);
4664 if (empty($reshook)) {
4665 print '<div class="fichecenter">';
4666 print '<div class="fichehalfleft">';
4667 print '<div class="underbanner clearboth"></div>';
4668
4669 print '<table class="border centpercent tableforfield">';
4670
4671 // Type
4672 print '<tr><td class="fieldname_type">'.$langs->trans('Type').'</td><td class="valuefield fieldname_type">';
4673 print $object->getLibType(2);
4674 if ($object->subtype > 0) {
4675 print ' '.$object->getSubtypeLabel('facture');
4676 }
4677 if ($object->module_source) {
4678 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>';
4679 }
4680 if ($object->type == Facture::TYPE_REPLACEMENT) {
4681 $facreplaced = new Facture($db);
4682 $facreplaced->fetch($object->fk_facture_source);
4683 print ' <span class="opacitymediumbycolor paddingleft">'.$langs->transnoentities("ReplaceInvoice", $facreplaced->getNomUrl(1, '', 32)).'</span>';
4684 }
4685 if ($object->type == Facture::TYPE_CREDIT_NOTE && !empty($object->fk_facture_source)) {
4686 $facusing = new Facture($db);
4687 $facusing->fetch($object->fk_facture_source);
4688 print ' <span class="opacitymediumbycolor paddingleft">'.$langs->transnoentities("CorrectInvoice", $facusing->getNomUrl(1, '', 32)).'</span>';
4689 }
4690
4691 $facidavoir = $object->getListIdAvoirFromInvoice();
4692 if (count($facidavoir) > 0) {
4693 print ' <span class="opacitymediumbycolor paddingleft">'.$langs->transnoentities("InvoiceHasAvoir");
4694 $i = 0;
4695 foreach ($facidavoir as $id) {
4696 if ($i == 0) {
4697 print ' ';
4698 } else {
4699 print ',';
4700 }
4701 $facavoir = new Facture($db);
4702 $facavoir->fetch($id);
4703 print $facavoir->getNomUrl(1, '', 32);
4704 }
4705 print '</span>';
4706 }
4707 if ($objectidnext > 0) {
4708 $facthatreplace = new Facture($db);
4709 $facthatreplace->fetch($objectidnext);
4710 print ' <span class="opacitymediumbycolor paddingleft">'.str_replace('{s1}', $facthatreplace->getNomUrl(1), $langs->transnoentities("ReplacedByInvoice", '{s1}')).'</span>';
4711 }
4712
4714 $discount = new DiscountAbsolute($db);
4715 $result = $discount->fetch(0, $object->id);
4716 if ($result > 0) {
4717 print ' <span class="opacitymediumbycolor paddingleft">';
4718 $s = $langs->trans("CreditNoteConvertedIntoDiscount", '{s1}', '{s2}');
4719 $s = str_replace('{s1}', $object->getLibType(0), $s);
4720 $s = str_replace('{s2}', $discount->getNomUrl(1, 'discount'), $s);
4721 print $s;
4722 print '</span><br>';
4723 }
4724 }
4725
4726 if ($object->fk_fac_rec_source > 0) {
4727 $tmptemplate = new FactureRec($db);
4728 $result = $tmptemplate->fetch($object->fk_fac_rec_source);
4729 if ($result > 0) {
4730 print ' <span class="opacitymediumbycolor paddingleft">';
4731 $s = $langs->transnoentities("GeneratedFromTemplate", '{s1}');
4732 $s = str_replace('{s1}', $tmptemplate->getNomUrl(1, '', 32), $s);
4733 print $s;
4734 print '</span>';
4735 }
4736 }
4737 print '</td></tr>';
4738
4739 // Relative and absolute discounts
4740 print '<!-- Discounts -->'."\n";
4741 print '<tr><td>'.$langs->trans('DiscountStillRemaining').'</td>';
4742 print '<td>';
4743 $thirdparty = $soc;
4744 $discount_type = 0;
4745 $backtopage = $_SERVER["PHP_SELF"].'?facid='.$object->id;
4746 include DOL_DOCUMENT_ROOT.'/core/tpl/object_discounts.tpl.php';
4747 print '</td></tr>';
4748
4749 // Date invoice
4750 print '<tr><td>';
4751 print '<table class="nobordernopadding centpercent"><tr><td>';
4752 print $langs->trans('DateInvoice');
4753 print '</td>';