dolibarr 20.0.2
card.php
Go to the documentation of this file.
1<?php
2/* Copyright (C) 2002-2006 Rodolphe Quiedeville <rodolphe@quiedeville.org>
3 * Copyright (C) 2004 Eric Seigne <eric.seigne@ryxeo.com>
4 * Copyright (C) 2004-2020 Laurent Destailleur <eldy@users.sourceforge.net>
5 * Copyright (C) 2005 Marc Barilley / Ocebo <marc@ocebo.com>
6 * Copyright (C) 2005-2015 Regis Houssin <regis.houssin@inodbox.com>
7 * Copyright (C) 2006 Andre Cianfarani <acianfa@free.fr>
8 * Copyright (C) 2010-2015 Juanjo Menent <jmenent@2byte.es>
9 * Copyright (C) 2012-2023 Christophe Battarel <christophe.battarel@altairis.fr>
10 * Copyright (C) 2012-2013 Cédric Salvador <csalvador@gpcsolutions.fr>
11 * Copyright (C) 2012-2014 Raphaël Doursenaud <rdoursenaud@gpcsolutions.fr>
12 * Copyright (C) 2013 Jean-Francois FERRY <jfefe@aternatik.fr>
13 * Copyright (C) 2013-2014 Florian Henry <florian.henry@open-concept.pro>
14 * Copyright (C) 2013 Cédric Salvador <csalvador@gpcsolutions.fr>
15 * Copyright (C) 2014-2024 Ferran Marcet <fmarcet@2byte.es>
16 * Copyright (C) 2015-2016 Marcos García <marcosgdf@gmail.com>
17 * Copyright (C) 2018-2024 Frédéric France <frederic.france@free.fr>
18 * Copyright (C) 2022 Gauthier VERDOL <gauthier.verdol@atm-consulting.fr>
19 * Copyright (C) 2023 Nick Fragoulis
20 * Copyright (C) 2024 MDW <mdeweerd@users.noreply.github.com>
21 * Copyright (C) 2024 Alexandre Spangaro <alexandre@inovea-conseil.com>
22 *
23 * This program is free software; you can redistribute it and/or modify
24 * it under the terms of the GNU General Public License as published by
25 * the Free Software Foundation; either version 3 of the License, or
26 * (at your option) any later version.
27 *
28 * This program is distributed in the hope that it will be useful,
29 * but WITHOUT ANY WARRANTY; without even the implied warranty of
30 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
31 * GNU General Public License for more details.
32 *
33 * You should have received a copy of the GNU General Public License
34 * along with this program. If not, see <https://www.gnu.org/licenses/>.
35 */
36
43// Libraries
44require '../../main.inc.php';
45require_once DOL_DOCUMENT_ROOT.'/compta/facture/class/facture.class.php';
46require_once DOL_DOCUMENT_ROOT.'/compta/facture/class/facture-rec.class.php';
47require_once DOL_DOCUMENT_ROOT.'/compta/bank/class/account.class.php';
48require_once DOL_DOCUMENT_ROOT.'/compta/paiement/class/paiement.class.php';
49require_once DOL_DOCUMENT_ROOT.'/core/modules/facture/modules_facture.php';
50require_once DOL_DOCUMENT_ROOT.'/core/class/discount.class.php';
51require_once DOL_DOCUMENT_ROOT.'/core/class/extrafields.class.php';
52require_once DOL_DOCUMENT_ROOT.'/core/class/html.formfile.class.php';
53require_once DOL_DOCUMENT_ROOT.'/core/class/html.formother.class.php';
54require_once DOL_DOCUMENT_ROOT.'/core/class/html.formmargin.class.php';
55require_once DOL_DOCUMENT_ROOT.'/core/lib/invoice.lib.php';
56require_once DOL_DOCUMENT_ROOT.'/core/lib/functions2.lib.php';
57require_once DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php';
58if (isModEnabled('order')) {
59 require_once DOL_DOCUMENT_ROOT.'/commande/class/commande.class.php';
60}
61if (isModEnabled('project')) {
62 require_once DOL_DOCUMENT_ROOT.'/projet/class/project.class.php';
63 require_once DOL_DOCUMENT_ROOT.'/core/class/html.formprojet.class.php';
64}
65require_once DOL_DOCUMENT_ROOT.'/core/class/doleditor.class.php';
66
67if (isModEnabled('variants')) {
68 require_once DOL_DOCUMENT_ROOT.'/variants/class/ProductCombination.class.php';
69}
70if (isModEnabled('accounting')) {
71 require_once DOL_DOCUMENT_ROOT.'/accountancy/class/accountingjournal.class.php';
72}
73
74// Load translation files required by the page
75$langs->loadLangs(array('bills', 'companies', 'compta', 'products', 'banks', 'main', 'withdrawals'));
76if (isModEnabled('incoterm')) {
77 $langs->load('incoterm');
78}
79if (isModEnabled('margin')) {
80 $langs->load('margins');
81}
82
83// General $Variables
84$id = (GETPOSTINT('id') ? GETPOSTINT('id') : GETPOSTINT('facid')); // For backward compatibility
85$ref = GETPOST('ref', 'alpha');
86$socid = GETPOSTINT('socid');
87$action = GETPOST('action', 'aZ09');
88$confirm = GETPOST('confirm', 'alpha');
89$cancel = GETPOST('cancel', 'alpha');
90$backtopage = GETPOST('backtopage', 'alpha'); // if not set, a default page will be used
91$backtopageforcancel = GETPOST('backtopageforcancel', 'alpha'); // if not set, $backtopage will be used
92$lineid = GETPOSTINT('lineid');
93$userid = GETPOSTINT('userid');
94$search_ref = GETPOST('sf_ref', 'alpha') ? GETPOST('sf_ref', 'alpha') : GETPOST('search_ref', 'alpha');
95$search_societe = GETPOST('search_societe', 'alpha');
96$search_montant_ht = GETPOST('search_montant_ht', 'alpha');
97$search_montant_ttc = GETPOST('search_montant_ttc', 'alpha');
98$origin = GETPOST('origin', 'alpha');
99$originid = (GETPOSTINT('originid') ? GETPOSTINT('originid') : GETPOSTINT('origin_id')); // For backward compatibility
100$fac_rec = GETPOSTINT('fac_rec');
101$facid = GETPOSTINT('facid');
102$ref_client = GETPOSTINT('ref_client');
103$rank = (GETPOSTINT('rank') > 0) ? GETPOSTINT('rank') : -1;
104$projectid = (GETPOSTINT('projectid') ? GETPOSTINT('projectid') : 0);
105$selectedLines = GETPOST('toselect', 'array');
106
107// PDF
108$hidedetails = (GETPOSTINT('hidedetails') ? GETPOSTINT('hidedetails') : (getDolGlobalString('MAIN_GENERATE_DOCUMENTS_HIDE_DETAILS') ? 1 : 0));
109$hidedesc = (GETPOSTINT('hidedesc') ? GETPOSTINT('hidedesc') : (getDolGlobalString('MAIN_GENERATE_DOCUMENTS_HIDE_DESC') ? 1 : 0));
110$hideref = (GETPOSTINT('hideref') ? GETPOSTINT('hideref') : (getDolGlobalString('MAIN_GENERATE_DOCUMENTS_HIDE_REF') ? 1 : 0));
111
112// Number of lines for predefined product/service choices
113$NBLINES = 4;
114
115$usehm = getDolGlobalInt('MAIN_USE_HOURMIN_IN_DATE_RANGE');
116
117$object = new Facture($db);
118$extrafields = new ExtraFields($db);
119
120// Fetch optionals attributes and labels
121$extrafields->fetch_name_optionals_label($object->table_element);
122
123// Load object
124if ($id > 0 || !empty($ref)) {
125 if ($action != 'add') {
126 if (!getDolGlobalString('INVOICE_USE_SITUATION')) {
127 $fetch_situation = false;
128 } else {
129 $fetch_situation = true;
130 }
131 $ret = $object->fetch($id, $ref, '', 0, $fetch_situation);
132 if ($ret > 0 && isset($object->fk_project)) {
133 $ret = $object->fetch_project();
134 }
135 }
136}
137
138// Initialize technical object to manage hooks of page. Note that conf->hooks_modules contains array of hook context
139$hookmanager->initHooks(array('invoicecard', 'globalcard'));
140
141// Permissions
142$usercanread = $user->hasRight("facture", "lire");
143$usercancreate = $user->hasRight("facture", "creer");
144$usercanissuepayment = $user->hasRight("facture", "paiement");
145$usercandelete = $user->hasRight("facture", "supprimer") || ($usercancreate && isset($object->status) && $object->status == $object::STATUS_DRAFT);
146$usercancreatecontract = $user->hasRight("contrat", "creer");
147
148// Advanced Permissions
149$usercanvalidate = ((!getDolGlobalString('MAIN_USE_ADVANCED_PERMS') && $usercancreate) || (getDolGlobalString('MAIN_USE_ADVANCED_PERMS') && $user->hasRight('facture', 'invoice_advance', 'validate')));
150$usercansend = (!getDolGlobalString('MAIN_USE_ADVANCED_PERMS') || (getDolGlobalString('MAIN_USE_ADVANCED_PERMS') && $user->hasRight('facture', 'invoice_advance', 'send')));
151$usercanreopen = ((!getDolGlobalString('MAIN_USE_ADVANCED_PERMS') && $usercancreate) || (getDolGlobalString('MAIN_USE_ADVANCED_PERMS') && $user->hasRight('facture', 'invoice_advance', 'reopen')));
152if (getDolGlobalString('INVOICE_DISALLOW_REOPEN')) {
153 $usercanreopen = false;
154}
155$usercanunvalidate = ((!getDolGlobalString('MAIN_USE_ADVANCED_PERMS') && !empty($usercancreate)) || (getDolGlobalString('MAIN_USE_ADVANCED_PERMS') && $user->hasRight('facture', 'invoice_advance', 'unvalidate')));
156$usermustrespectpricemin = ((getDolGlobalString('MAIN_USE_ADVANCED_PERMS') && !$user->hasRight('produit', 'ignore_price_min_advance')) || !getDolGlobalString('MAIN_USE_ADVANCED_PERMS'));
157
158// Other permissions
159$usercancreatemargin = $user->hasRight('margins', 'creer');
160$usercanreadallmargin = $user->hasRight('margins', 'liretous');
161$usercancreatewithdrarequest = $user->hasRight('prelevement', 'bons', 'creer');
162
163$permissionnote = $usercancreate; // Used by the include of actions_setnotes.inc.php
164$permissiondellink = $usercancreate; // Used by the include of actions_dellink.inc.php
165$permissiontoedit = $usercancreate; // Used by the include of actions_lineupdonw.inc.php
166$permissiontoadd = $usercancreate; // Used by the include of actions_addupdatedelete.inc.php
167
168// retained warranty invoice available type
169$retainedWarrantyInvoiceAvailableType = array();
170if (getDolGlobalString('INVOICE_USE_RETAINED_WARRANTY')) {
171 $retainedWarrantyInvoiceAvailableType = explode('+', getDolGlobalString('INVOICE_USE_RETAINED_WARRANTY'));
172}
173
174// Security check
175if ($user->socid) {
176 $socid = $user->socid;
177}
178$isdraft = (($object->status == Facture::STATUS_DRAFT) ? 1 : 0);
179
180$result = restrictedArea($user, 'facture', $object->id, '', '', 'fk_soc', 'rowid', $isdraft);
181
182
183/*
184 * Actions
185 */
186
187$parameters = array('socid' => $socid);
188$reshook = $hookmanager->executeHooks('doActions', $parameters, $object, $action); // Note that $action and $object may have been modified by some hooks
189if ($reshook < 0) {
190 setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
191}
192
193if (empty($reshook)) {
194 $backurlforlist = DOL_URL_ROOT.'/compta/facture/list.php';
195
196 if (empty($backtopage) || ($cancel && empty($id))) {
197 if (empty($backtopage) || ($cancel && strpos($backtopage, '__ID__'))) {
198 if (empty($id) && (($action != 'add' && $action != 'create') || $cancel)) {
199 $backtopage = $backurlforlist;
200 } else {
201 $backtopage = DOL_URL_ROOT.'/compta/facture/card.php?id='.((!empty($id) && $id > 0) ? $id : '__ID__');
202 }
203 }
204 }
205
206 if ($cancel) {
207 if (!empty($backtopageforcancel)) {
208 header("Location: ".$backtopageforcancel);
209 exit;
210 } elseif (!empty($backtopage)) {
211 header("Location: ".$backtopage);
212 exit;
213 }
214 $action = '';
215 }
216
217 include DOL_DOCUMENT_ROOT.'/core/actions_setnotes.inc.php'; // Must be include, not include_once
218
219 include DOL_DOCUMENT_ROOT.'/core/actions_dellink.inc.php'; // Must be include, not include_once
220
221 include DOL_DOCUMENT_ROOT.'/core/actions_lineupdown.inc.php'; // Must be include, not include_once
222
223 // Action clone object
224 if ($action == 'confirm_clone' && $confirm == 'yes' && $permissiontoadd) {
225 if (!($socid > 0)) {
226 setEventMessages($langs->trans('ErrorFieldRequired', $langs->transnoentitiesnoconv('IdThirdParty')), null, 'errors');
227 } else {
228 $objectutil = dol_clone($object, 1); // We use a clone to avoid to denaturate loaded object when setting some properties for clone. We use native clone to keep this->db valid.
229 '@phan-var-force Facture $objectutil';
230
231 $objectutil->date = dol_mktime(12, 0, 0, GETPOSTINT('newdatemonth'), GETPOSTINT('newdateday'), GETPOSTINT('newdateyear'));
232 $objectutil->socid = $socid;
233 $result = $objectutil->createFromClone($user, $id);
234 if ($result > 0) {
235 $warningMsgLineList = array();
236 // check all product lines are to sell otherwise add a warning message for each product line is not to sell
237 foreach ($objectutil->lines as $line) {
238 if (!is_object($line->product)) {
239 $line->fetch_product();
240 }
241 if (is_object($line->product) && $line->product->id > 0) {
242 if (empty($line->product->status)) {
243 $warningMsgLineList[$line->id] = $langs->trans('WarningLineProductNotToSell', $line->product->ref);
244 }
245 }
246 }
247 if (!empty($warningMsgLineList)) {
248 setEventMessages('', $warningMsgLineList, 'warnings');
249 }
250
251 header("Location: " . $_SERVER['PHP_SELF'] . '?facid=' . $result);
252 exit();
253 } else {
254 $langs->load("errors");
255 setEventMessages($objectutil->error, $objectutil->errors, 'errors');
256 $action = '';
257 }
258 }
259 } elseif ($action == 'reopen' && $usercanreopen) {
260 $result = $object->fetch($id);
261
262 if ($object->status == Facture::STATUS_CLOSED || ($object->status == Facture::STATUS_ABANDONED && ($object->close_code != 'replaced' || $object->getIdReplacingInvoice() == 0)) || ($object->status == Facture::STATUS_VALIDATED && $object->paye == 1)) { // ($object->status == 1 && $object->paye == 1) should not happened but can be found when data are corrupted
263 $result = $object->setUnpaid($user);
264 if ($result > 0) {
265 header('Location: '.$_SERVER["PHP_SELF"].'?facid='.$id);
266 exit();
267 } else {
268 setEventMessages($object->error, $object->errors, 'errors');
269 }
270 }
271 } elseif ($action == 'confirm_delete' && $confirm == 'yes') {
272 // Delete invoice
273 $result = $object->fetch($id);
274 $object->fetch_thirdparty();
275
276 $idwarehouse = GETPOST('idwarehouse');
277
278 $qualified_for_stock_change = 0;
279 if (!getDolGlobalString('STOCK_SUPPORTS_SERVICES')) {
280 $qualified_for_stock_change = $object->hasProductsOrServices(2);
281 } else {
282 $qualified_for_stock_change = $object->hasProductsOrServices(1);
283 }
284
285 $isErasable = $object->is_erasable();
286
287 if (($usercandelete && $isErasable > 0)
288 || ($usercancreate && $isErasable == 1)) {
289 $result = $object->delete($user, 0, $idwarehouse);
290 if ($result > 0) {
291 header('Location: '.DOL_URL_ROOT.'/compta/facture/list.php?restore_lastsearch_values=1');
292 exit();
293 } else {
294 setEventMessages($object->error, $object->errors, 'errors');
295 $action = '';
296 }
297 }
298 } elseif ($action == 'confirm_deleteline' && $confirm == 'yes' && $usercancreate) {
299 // Delete line
300 $object->fetch($id);
301 $object->fetch_thirdparty();
302
303 $result = $object->deleteLine(GETPOSTINT('lineid'));
304 if ($result > 0) {
305 // reorder lines
306 $object->line_order(true);
307 // Define output language
308 $outputlangs = $langs;
309 $newlang = '';
310 if (getDolGlobalInt('MAIN_MULTILANGS') && empty($newlang) && GETPOST('lang_id')) {
311 $newlang = GETPOST('lang_id');
312 }
313 if (getDolGlobalInt('MAIN_MULTILANGS') && empty($newlang)) {
314 $newlang = $object->thirdparty->default_lang;
315 }
316 if (!empty($newlang)) {
317 $outputlangs = new Translate("", $conf);
318 $outputlangs->setDefaultLang($newlang);
319 $outputlangs->load('products');
320 }
321 if (!getDolGlobalString('MAIN_DISABLE_PDF_AUTOUPDATE')) {
322 $ret = $object->fetch($id); // Reload to get new records
323 $result = $object->generateDocument($object->model_pdf, $outputlangs, $hidedetails, $hidedesc, $hideref);
324 }
325 if ($result >= 0) {
326 header('Location: '.$_SERVER["PHP_SELF"].'?facid='.$id);
327 exit();
328 }
329 } else {
330 setEventMessages($object->error, $object->errors, 'errors');
331 $action = '';
332 }
333 } elseif ($action == 'unlinkdiscount' && $usercancreate) {
334 // Delete link of credit note to invoice
335 $discount = new DiscountAbsolute($db);
336 $result = $discount->fetch(GETPOSTINT("discountid"));
337 $discount->unlink_invoice();
338 } elseif ($action == 'valid' && $usercancreate) {
339 // Validation
340 $object->fetch($id);
341
342 if ((preg_match('/^[\‍(]?PROV/i', $object->ref) || empty($object->ref)) && // empty should not happened, but when it occurs, the test save life
343 getDolGlobalString('FAC_FORCE_DATE_VALIDATION') // If option enabled, we force invoice date
344 ) {
345 $object->date = dol_now();
346 }
347
348 if (getDolGlobalString('INVOICE_CHECK_POSTERIOR_DATE')) {
349 $last_of_type = $object->willBeLastOfSameType(true);
350 if (empty($object->date_validation) && !$last_of_type[0]) {
351 setEventMessages($langs->transnoentities("ErrorInvoiceIsNotLastOfSameType", $object->ref, dol_print_date($object->date, 'day'), dol_print_date($last_of_type[1], 'day')), null, 'errors');
352 $action = '';
353 }
354 }
355
356 // We check invoice sign
357 if ($object->type == Facture::TYPE_CREDIT_NOTE) {
358 // If a credit note, the sign must be negative
359 if ($object->total_ht > 0) {
360 setEventMessages($langs->trans("ErrorInvoiceAvoirMustBeNegative"), null, 'errors');
361 $action = '';
362 }
363 } else {
364 // If not a credit note, amount with tax must be positive or nul.
365 // Note that amount excluding tax can be negative because you can have a invoice of 100 with vat of 20 that
366 // consumes a credit note of 100 with vat 0 (total with tax is 0 but without tax is -20).
367 // For some cases, credit notes can have a vat of 0 (for example when selling goods in France).
368 if (!getDolGlobalString('FACTURE_ENABLE_NEGATIVE') && $object->total_ttc < 0) {
369 setEventMessages($langs->trans("ErrorInvoiceOfThisTypeMustBePositive"), null, 'errors');
370 $action = '';
371 }
372
373 // Also negative lines should not be allowed on 'non Credit notes' invoices. A test is done when adding or updating lines but we must
374 // do it again in validation to avoid cases where invoice is created from another object that allow negative lines.
375 // Note that we can accept the negative line if sum with other lines with same vat makes total positive: Because all the lines will be merged together
376 // when converted into 'available credit' and we will get a positive available credit line.
377 // Note: Other solution if you want to add a negative line on invoice, is to create a discount for customer and consumme it (but this is possible on standard invoice only).
378 $array_of_total_ht_per_vat_rate = array();
379 $array_of_total_ht_devise_per_vat_rate = array();
380 foreach ($object->lines as $line) {
381 //$vat_src_code_for_line = $line->vat_src_code; // TODO We check sign of total per vat without taking into account the vat code because for the moment the vat code is lost/unknown when we add a down payment.
382 $vat_src_code_for_line = '';
383 if (empty($array_of_total_ht_per_vat_rate[$line->tva_tx.'_'.$vat_src_code_for_line])) {
384 $array_of_total_ht_per_vat_rate[$line->tva_tx.'_'.$vat_src_code_for_line] = 0;
385 }
386 if (empty($array_of_total_ht_devise_per_vat_rate[$line->tva_tx.'_'.$vat_src_code_for_line])) {
387 $array_of_total_ht_devise_per_vat_rate[$line->tva_tx.'_'.$vat_src_code_for_line] = 0;
388 }
389 $array_of_total_ht_per_vat_rate[$line->tva_tx.'_'.$vat_src_code_for_line] += $line->total_ht;
390 $array_of_total_ht_devise_per_vat_rate[$line->tva_tx.'_'.$vat_src_code_for_line] += $line->multicurrency_total_ht;
391 }
392
393 //var_dump($array_of_total_ht_per_vat_rate);exit;
394 foreach ($array_of_total_ht_per_vat_rate as $vatrate => $tmpvalue) {
395 $tmp_total_ht = price2num($array_of_total_ht_per_vat_rate[$vatrate]);
396 $tmp_total_ht_devise = price2num($array_of_total_ht_devise_per_vat_rate[$vatrate]);
397
398 if (($tmp_total_ht < 0 || $tmp_total_ht_devise < 0) && !getDolGlobalString('FACTURE_ENABLE_NEGATIVE_LINES')) {
399 if ($object->type == $object::TYPE_DEPOSIT) {
400 $langs->load("errors");
401 // Using negative lines on deposit lead to headach and blocking problems when you want to consume them.
402 setEventMessages($langs->trans("ErrorLinesCantBeNegativeOnDeposits"), null, 'errors');
403 $error++;
404 $action = '';
405 } else {
406 $tmpvatratetoshow = explode('_', $vatrate);
407 $tmpvatratetoshow[0] = round((float) $tmpvatratetoshow[0], 2);
408
409 if ($tmpvatratetoshow[0] != 0) {
410 $langs->load("errors");
411 setEventMessages($langs->trans("ErrorLinesCantBeNegativeForOneVATRate", $tmpvatratetoshow[0]), null, 'errors');
412 $error++;
413 $action = '';
414 }
415 }
416 }
417 }
418 }
419 } elseif ($action == 'classin' && $usercancreate) {
420 $object->fetch($id);
421 $object->setProject(GETPOSTINT('projectid'));
422 } elseif ($action == 'setmode' && $usercancreate) {
423 $object->fetch($id);
424 $result = $object->setPaymentMethods(GETPOSTINT('mode_reglement_id'));
425 if ($result < 0) {
426 dol_print_error($db, $object->error);
427 }
428 } elseif ($action == 'setretainedwarrantyconditions' && $usercancreate) {
429 $object->fetch($id);
430 $object->retained_warranty_fk_cond_reglement = 0; // To clean property
431 $result = $object->setRetainedWarrantyPaymentTerms(GETPOSTINT('retained_warranty_fk_cond_reglement'));
432 if ($result < 0) {
433 dol_print_error($db, $object->error);
434 }
435
436 $old_rw_date_lim_reglement = $object->retained_warranty_date_limit;
437 $new_rw_date_lim_reglement = $object->calculate_date_lim_reglement($object->retained_warranty_fk_cond_reglement);
438 if ($new_rw_date_lim_reglement > $old_rw_date_lim_reglement) {
439 $object->retained_warranty_date_limit = $new_rw_date_lim_reglement;
440 }
441 if ($object->retained_warranty_date_limit < $object->date) {
442 $object->retained_warranty_date_limit = $object->date;
443 }
444 $result = $object->update($user);
445 if ($result < 0) {
446 dol_print_error($db, $object->error);
447 }
448 } elseif ($action == 'setretainedwarranty' && $usercancreate) {
449 $object->fetch($id);
450 $result = $object->setRetainedWarranty(GETPOSTFLOAT('retained_warranty'));
451 if ($result < 0) {
452 dol_print_error($db, $object->error);
453 }
454 } elseif ($action == 'setretainedwarrantydatelimit' && $usercancreate) {
455 $object->fetch($id);
456 $result = $object->setRetainedWarrantyDateLimit(GETPOSTFLOAT('retained_warranty_date_limit'));
457 if ($result < 0) {
458 dol_print_error($db, $object->error);
459 }
460 } elseif ($action == 'setmulticurrencycode' && $usercancreate) { // Multicurrency Code
461 $result = $object->setMulticurrencyCode(GETPOST('multicurrency_code', 'alpha'));
462 } elseif ($action == 'setmulticurrencyrate' && $usercancreate) { // Multicurrency rate
463 $result = $object->setMulticurrencyRate(price2num(GETPOST('multicurrency_tx')), GETPOSTINT('calculation_mode'));
464 } elseif ($action == 'setinvoicedate' && $usercancreate) {
465 $object->fetch($id);
466 $old_date_lim_reglement = $object->date_lim_reglement;
467 $newdate = dol_mktime(0, 0, 0, GETPOSTINT('invoicedatemonth'), GETPOSTINT('invoicedateday'), GETPOSTINT('invoicedateyear'), 'tzserver');
468 if (empty($newdate)) {
469 setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("Date")), null, 'errors');
470 header('Location: '.$_SERVER["PHP_SELF"].'?facid='.$id.'&action=editinvoicedate&token='.newToken());
471 exit;
472 }
473 if ($newdate > (dol_now('tzuserrel') + getDolGlobalInt('INVOICE_MAX_FUTURE_DELAY'))) {
474 if (!getDolGlobalString('INVOICE_MAX_FUTURE_DELAY')) {
475 setEventMessages($langs->trans("WarningInvoiceDateInFuture"), null, 'warnings');
476 } else {
477 setEventMessages($langs->trans("WarningInvoiceDateTooFarInFuture"), null, 'warnings');
478 }
479 }
480
481 $object->date = $newdate;
482 $new_date_lim_reglement = $object->calculate_date_lim_reglement();
483 if ($new_date_lim_reglement) {
484 $object->date_lim_reglement = $new_date_lim_reglement;
485 }
486 if ($object->date_lim_reglement < $object->date) {
487 $object->date_lim_reglement = $object->date;
488 }
489 $result = $object->update($user);
490 if ($result < 0) {
491 setEventMessages($object->error, $object->errors, 'errors');
492 $action = 'editinvoicedate';
493 }
494 } elseif ($action == 'setdate_pointoftax' && $usercancreate) {
495 $object->fetch($id);
496
497 $date_pointoftax = dol_mktime(0, 0, 0, GETPOSTINT('date_pointoftaxmonth'), GETPOSTINT('date_pointoftaxday'), GETPOSTINT('date_pointoftaxyear'), 'tzserver');
498
499 $object->date_pointoftax = $date_pointoftax;
500 $result = $object->update($user);
501 if ($result < 0) {
502 dol_print_error($db, $object->error);
503 }
504 } elseif ($action == 'setconditions' && $usercancreate) {
505 $object->fetch($id);
506 $object->cond_reglement_code = 0; // To clean property
507 $object->cond_reglement_id = 0; // To clean property
508
509 $error = 0;
510
511 $db->begin();
512
513 if (!$error) {
514 $result = $object->setPaymentTerms(GETPOSTINT('cond_reglement_id'));
515 if ($result < 0) {
516 $error++;
517 setEventMessages($object->error, $object->errors, 'errors');
518 }
519 }
520
521 if (!$error) {
522 $old_date_lim_reglement = $object->date_lim_reglement;
523 $new_date_lim_reglement = $object->calculate_date_lim_reglement();
524 if ($new_date_lim_reglement) {
525 $object->date_lim_reglement = $new_date_lim_reglement;
526 }
527 if ($object->date_lim_reglement < $object->date) {
528 $object->date_lim_reglement = $object->date;
529 }
530 $result = $object->update($user);
531 if ($result < 0) {
532 $error++;
533 setEventMessages($object->error, $object->errors, 'errors');
534 }
535 }
536
537 if ($error) {
538 $db->rollback();
539 } else {
540 $db->commit();
541 }
542 } elseif ($action == 'setpaymentterm' && $usercancreate) {
543 $object->fetch($id);
544 $object->date_lim_reglement = dol_mktime(12, 0, 0, GETPOSTINT('paymenttermmonth'), GETPOSTINT('paymenttermday'), GETPOSTINT('paymenttermyear'));
545 if ($object->date_lim_reglement < $object->date) {
546 $object->date_lim_reglement = $object->calculate_date_lim_reglement();
547 setEventMessages($langs->trans("DatePaymentTermCantBeLowerThanObjectDate"), null, 'warnings');
548 }
549 $result = $object->update($user);
550 if ($result < 0) {
551 dol_print_error($db, $object->error);
552 }
553 } elseif ($action == 'setrevenuestamp' && $usercancreate) {
554 $object->fetch($id);
555 $object->revenuestamp = (float) price2num(GETPOST('revenuestamp'));
556 $result = $object->update($user);
557 $object->update_price(1);
558 if ($result < 0) {
559 dol_print_error($db, $object->error);
560 } else {
561 // Define output language
562 if (!getDolGlobalString('MAIN_DISABLE_PDF_AUTOUPDATE')) {
563 $outputlangs = $langs;
564 $newlang = '';
565 if (getDolGlobalInt('MAIN_MULTILANGS') && empty($newlang) && GETPOST('lang_id', 'aZ09')) {
566 $newlang = GETPOST('lang_id', 'aZ09');
567 }
568 if (getDolGlobalInt('MAIN_MULTILANGS') && empty($newlang)) {
569 $newlang = $object->thirdparty->default_lang;
570 }
571 if (!empty($newlang)) {
572 $outputlangs = new Translate("", $conf);
573 $outputlangs->setDefaultLang($newlang);
574 $outputlangs->load('products');
575 }
576 $model = $object->model_pdf;
577 $ret = $object->fetch($id); // Reload to get new records
578
579 $result = $object->generateDocument($model, $outputlangs, $hidedetails, $hidedesc, $hideref);
580 if ($result < 0) {
581 setEventMessages($object->error, $object->errors, 'errors');
582 }
583 }
584 }
585 } elseif ($action == 'set_incoterms' && isModEnabled('incoterm') && $usercancreate) { // Set incoterm
586 $result = $object->setIncoterms(GETPOSTINT('incoterm_id'), GETPOST('location_incoterms'));
587 } elseif ($action == 'setbankaccount' && $usercancreate) { // bank account
588 $result = $object->setBankAccount(GETPOSTINT('fk_account'));
589 } elseif ($action == 'setremisepercent' && $usercancreate) {
590 $object->fetch($id);
591 $result = $object->setDiscount($user, price2num(GETPOST('remise_percent'), '', 2));
592 } elseif ($action == "setabsolutediscount" && $usercancreate) {
593 // We have POST[remise_id] or POST[remise_id_for_payment]
594 $db->begin();
595
596 // We use the credit to reduce amount of invoice
597 if (GETPOSTINT("remise_id") > 0) {
598 $ret = $object->fetch($id);
599 if ($ret > 0) {
600 $result = $object->insert_discount(GETPOSTINT("remise_id"));
601 if ($result < 0) {
602 setEventMessages($object->error, $object->errors, 'errors');
603 }
604 } else {
605 $error++;
606 setEventMessages($object->error, $object->errors, 'errors');
607 }
608 }
609 // We use the credit to reduce remain to pay
610 if (GETPOSTINT("remise_id_for_payment") > 0) {
611 require_once DOL_DOCUMENT_ROOT.'/core/class/discount.class.php';
612 $discount = new DiscountAbsolute($db);
613 $discount->fetch(GETPOSTINT("remise_id_for_payment"));
614
615 //var_dump($object->getRemainToPay(0));
616 //var_dump($discount->amount_ttc);exit;
617 $remaintopay = $object->getRemainToPay(0);
618 if (price2num($discount->amount_ttc) > price2num($remaintopay)) {
619 // TODO Split the discount in 2 automatically
620 $error++;
621 setEventMessages($langs->trans("ErrorDiscountLargerThanRemainToPaySplitItBefore"), null, 'errors');
622 }
623
624 if (!$error) {
625 $result = $discount->link_to_invoice(0, $id);
626 if ($result < 0) {
627 $error++;
628 setEventMessages($discount->error, $discount->errors, 'errors');
629 }
630 }
631
632 if (!$error) {
633 $newremaintopay = $object->getRemainToPay(0);
634 if ($newremaintopay == 0) {
635 $object->setPaid($user);
636 }
637 }
638 }
639
640 if (!$error) {
641 $db->commit();
642 } else {
643 $db->rollback();
644 }
645
646 if (empty($error) && !getDolGlobalString('MAIN_DISABLE_PDF_AUTOUPDATE')) {
647 $outputlangs = $langs;
648 $newlang = '';
649 if (getDolGlobalInt('MAIN_MULTILANGS') && empty($newlang) && GETPOST('lang_id', 'aZ09')) {
650 $newlang = GETPOST('lang_id', 'aZ09');
651 }
652 if (getDolGlobalInt('MAIN_MULTILANGS') && empty($newlang)) {
653 $object->fetch_thirdparty();
654 $newlang = $object->thirdparty->default_lang;
655 }
656 if (!empty($newlang)) {
657 $outputlangs = new Translate("", $conf);
658 $outputlangs->setDefaultLang($newlang);
659 }
660 $ret = $object->fetch($id); // Reload to get new records
661
662 $result = $object->generateDocument($object->model_pdf, $outputlangs, $hidedetails, $hidedesc, $hideref);
663 if ($result < 0) {
664 setEventMessages($object->error, $object->errors, 'errors');
665 }
666 }
667 } elseif ($action == 'setref' && $usercancreate) {
668 $object->fetch($id);
669 $object->setValueFrom('ref', GETPOST('ref'), '', 0, '', '', $user, 'BILL_MODIFY');
670 } elseif ($action == 'setref_client' && $usercancreate) {
671 $object->fetch($id);
672 $object->set_ref_client(GETPOST('ref_client'));
673 } elseif ($action == 'confirm_valid' && $confirm == 'yes' && $usercanvalidate) {
674 // Classify to validated
675 $idwarehouse = GETPOSTINT('idwarehouse');
676
677 $object->fetch($id);
678 $object->fetch_thirdparty();
679
680 // Check for warehouse
681 if ($object->type != Facture::TYPE_DEPOSIT && getDolGlobalString('STOCK_CALCULATE_ON_BILL')) {
682 $qualified_for_stock_change = 0;
683 if (!getDolGlobalString('STOCK_SUPPORTS_SERVICES')) {
684 $qualified_for_stock_change = $object->hasProductsOrServices(2);
685 } else {
686 $qualified_for_stock_change = $object->hasProductsOrServices(1);
687 }
688
689 if ($qualified_for_stock_change) {
690 if (!$idwarehouse || $idwarehouse == - 1) {
691 $error++;
692 setEventMessages($langs->trans('ErrorFieldRequired', $langs->transnoentitiesnoconv("Warehouse")), null, 'errors');
693 $action = '';
694 }
695 }
696 }
697
698 if (!$error) {
699 $result = $object->validate($user, '', $idwarehouse);
700 if ($result >= 0) {
701 // Define output language
702 if (!getDolGlobalString('MAIN_DISABLE_PDF_AUTOUPDATE')) {
703 $outputlangs = $langs;
704 $newlang = '';
705 if (getDolGlobalInt('MAIN_MULTILANGS') && empty($newlang) && GETPOST('lang_id', 'aZ09')) {
706 $newlang = GETPOST('lang_id', 'aZ09');
707 }
708 if (getDolGlobalInt('MAIN_MULTILANGS') && empty($newlang)) {
709 $newlang = $object->thirdparty->default_lang;
710 }
711 if (!empty($newlang)) {
712 $outputlangs = new Translate("", $conf);
713 $outputlangs->setDefaultLang($newlang);
714 $outputlangs->load('products');
715 }
716 $model = $object->model_pdf;
717
718 $ret = $object->fetch($id); // Reload to get new records
719
720 $result = $object->generateDocument($model, $outputlangs, $hidedetails, $hidedesc, $hideref);
721 if ($result < 0) {
722 setEventMessages($object->error, $object->errors, 'errors');
723 }
724 }
725 } else {
726 if (count($object->errors)) {
727 setEventMessages(null, $object->errors, 'errors');
728 } else {
729 setEventMessages($object->error, $object->errors, 'errors');
730 }
731 }
732 }
733 } elseif ($action == 'confirm_modif' && $usercanunvalidate) {
734 // Go back to draft status (unvalidate)
735 $idwarehouse = GETPOSTINT('idwarehouse');
736
737 $object->fetch($id);
738 $object->fetch_thirdparty();
739
740 // Check parameters
741 if ($object->type != Facture::TYPE_DEPOSIT && getDolGlobalString('STOCK_CALCULATE_ON_BILL')) {
742 $qualified_for_stock_change = 0;
743 if (!getDolGlobalString('STOCK_SUPPORTS_SERVICES')) {
744 $qualified_for_stock_change = $object->hasProductsOrServices(2);
745 } else {
746 $qualified_for_stock_change = $object->hasProductsOrServices(1);
747 }
748
749 if ($qualified_for_stock_change) {
750 if (!$idwarehouse || $idwarehouse == - 1) {
751 $error++;
752 setEventMessages($langs->trans('ErrorFieldRequired', $langs->transnoentitiesnoconv("Warehouse")), null, 'errors');
753 $action = '';
754 }
755 }
756 }
757
758 if (!$error) {
759 // We check if invoice has payments
760 $totalpaid = 0;
761 $sql = 'SELECT pf.amount';
762 $sql .= ' FROM '.MAIN_DB_PREFIX.'paiement_facture as pf';
763 $sql .= ' WHERE pf.fk_facture = '.((int) $object->id);
764
765 $result = $db->query($sql);
766 if ($result) {
767 $i = 0;
768 $num = $db->num_rows($result);
769
770 while ($i < $num) {
771 $objp = $db->fetch_object($result);
772 $totalpaid += $objp->amount;
773 $i++;
774 }
775 } else {
776 dol_print_error($db, '');
777 }
778
779 $resteapayer = $object->total_ttc - $totalpaid;
780
781 // We check that invoice lines are transferred into accountancy
782 $ventilExportCompta = $object->getVentilExportCompta();
783
784 // We check if no payment has been made
785 if ($ventilExportCompta == 0) {
786 if (getDolGlobalString('INVOICE_CAN_BE_EDITED_EVEN_IF_PAYMENT_DONE') || ($resteapayer == $object->total_ttc && empty($object->paye))) {
787 $result = $object->setDraft($user, $idwarehouse);
788 if ($result < 0) {
789 setEventMessages($object->error, $object->errors, 'errors');
790 }
791
792 // Define output language
793 if (!getDolGlobalString('MAIN_DISABLE_PDF_AUTOUPDATE')) {
794 $outputlangs = $langs;
795 $newlang = '';
796 if (getDolGlobalInt('MAIN_MULTILANGS') && empty($newlang) && GETPOST('lang_id', 'aZ09')) {
797 $newlang = GETPOST('lang_id', 'aZ09');
798 }
799 if (getDolGlobalInt('MAIN_MULTILANGS') && empty($newlang)) {
800 $newlang = $object->thirdparty->default_lang;
801 }
802 if (!empty($newlang)) {
803 $outputlangs = new Translate("", $conf);
804 $outputlangs->setDefaultLang($newlang);
805 $outputlangs->load('products');
806 }
807 $model = $object->model_pdf;
808 $ret = $object->fetch($id); // Reload to get new records
809
810 $object->generateDocument($model, $outputlangs, $hidedetails, $hidedesc, $hideref);
811 }
812 }
813 }
814 }
815 } elseif ($action == 'confirm_paid' && $confirm == 'yes' && $usercanissuepayment) {
816 // Classify "paid"
817 $object->fetch($id);
818 $result = $object->setPaid($user);
819 if ($result < 0) {
820 setEventMessages($object->error, $object->errors, 'errors');
821 }
822 } elseif ($action == 'confirm_paid_partially' && $confirm == 'yes' && $usercanissuepayment) {
823 // Classif "paid partially"
824 $object->fetch($id);
825 $close_code = GETPOST("close_code", 'restricthtml');
826 $close_note = GETPOST("close_note", 'restricthtml');
827 if ($close_code) {
828 $result = $object->setPaid($user, $close_code, $close_note);
829 if ($result < 0) {
830 setEventMessages($object->error, $object->errors, 'errors');
831 }
832 } else {
833 setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("Reason")), null, 'errors');
834 }
835 } elseif ($action == 'confirm_canceled' && $confirm == 'yes' && $usercancreate) {
836 // Classify "abandoned"
837 $object->fetch($id);
838 $close_code = GETPOST("close_code", 'restricthtml');
839 $close_note = GETPOST("close_note", 'restricthtml');
840 if ($close_code) {
841 $result = $object->setCanceled($user, $close_code, $close_note);
842 if ($result < 0) {
843 setEventMessages($object->error, $object->errors, 'errors');
844 }
845 } else {
846 setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("Reason")), null, 'errors');
847 }
848 } elseif ($action == 'confirm_converttoreduc' && $confirm == 'yes' && $usercancreate) {
849 // Convert to reduce
850 $object->fetch($id);
851 $object->fetch_thirdparty();
852 //$object->fetch_lines(); // Already done into fetch
853
854 // Check if there is already a discount (protection to avoid duplicate creation when resubmit post)
855 $discountcheck = new DiscountAbsolute($db);
856 $result = $discountcheck->fetch(0, $object->id);
857
858 $canconvert = 0;
859 if ($object->type == Facture::TYPE_DEPOSIT && empty($discountcheck->id)) {
860 $canconvert = 1; // we can convert deposit into discount if deposit is paid (completely, partially or not at all) and not already converted (see real condition into condition used to show button converttoreduc)
861 }
862 if (($object->type == Facture::TYPE_CREDIT_NOTE || $object->type == Facture::TYPE_STANDARD || $object->type == Facture::TYPE_SITUATION) && $object->paye == 0 && empty($discountcheck->id)) {
863 $canconvert = 1; // we can convert credit note into discount if credit note is not paid back and not already converted and amount of payment is 0 (see real condition into condition used to show button converttoreduc)
864 }
865
866 if ($canconvert) {
867 $db->begin();
868
869 $amount_ht = $amount_tva = $amount_ttc = array();
870 $multicurrency_amount_ht = $multicurrency_amount_tva = $multicurrency_amount_ttc = array();
871
872 // Loop on each vat rate
873 $i = 0;
874 foreach ($object->lines as $line) {
875 if ($line->product_type < 9 && $line->total_ht != 0) { // Remove lines with product_type greater than or equal to 9 and no need to create discount if amount is null
876 $keyforvatrate = $line->tva_tx.($line->vat_src_code ? ' ('.$line->vat_src_code.')' : '');
877
878 $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 $object->totalcreditnotes = $totalcreditnotes;
4658 $object->totaldeposits = $totaldeposits;
4659 $object->remaintopay = price2num($object->total_ttc - $object->totalpaid - $object->totalcreditnotes - $object->totaldeposits, 'MT');
4660
4661 dol_banner_tab($object, 'ref', $linkback, 1, 'ref', 'ref', $morehtmlref, '', 0, '', '');
4662
4663 // Call Hook tabContentViewInvoice
4664 $parameters = array();
4665 // Note that $action and $object may be modified by hook
4666 $reshook = $hookmanager->executeHooks('tabContentViewInvoice', $parameters, $object, $action);
4667 if (empty($reshook)) {
4668 print '<div class="fichecenter">';
4669 print '<div class="fichehalfleft">';
4670 print '<div class="underbanner clearboth"></div>';
4671
4672 print '<table class="border centpercent tableforfield">';
4673
4674 // Type
4675 print '<tr><td class="fieldname_type">'.$langs->trans('Type').'</td><td class="valuefield fieldname_type">';
4676 print $object->getLibType(2);
4677 if ($object->subtype > 0) {
4678 print ' '.$object->getSubtypeLabel('facture');
4679 }
4680 if ($object->module_source) {
4681 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>';
4682 }
4683 if ($object->type == Facture::TYPE_REPLACEMENT) {
4684 $facreplaced = new Facture($db);
4685 $facreplaced->fetch($object->fk_facture_source);
4686 print ' <span class="opacitymediumbycolor paddingleft">'.$langs->transnoentities("ReplaceInvoice", $facreplaced->getNomUrl(1, '', 32)).'</span>';
4687 }
4688 if ($object->type == Facture::TYPE_CREDIT_NOTE && !empty($object->fk_facture_source)) {
4689 $facusing = new Facture($db);
4690 $facusing->fetch($object->fk_facture_source);
4691 print ' <span class="opacitymediumbycolor paddingleft">'.$langs->transnoentities("CorrectInvoice", $facusing->getNomUrl(1, '', 32)).'</span>';
4692 }
4693
4694 $facidavoir = $object->getListIdAvoirFromInvoice();
4695 if (count($facidavoir) > 0) {
4696 print ' <span class="opacitymediumbycolor paddingleft">'.$langs->transnoentities("InvoiceHasAvoir");
4697 $i = 0;
4698 foreach ($facidavoir as $id) {
4699 if ($i == 0) {
4700 print ' ';
4701 } else {
4702 print ',';
4703 }
4704 $facavoir = new Facture($db);
4705 $facavoir->fetch($id);
4706 print $facavoir->getNomUrl(1, '', 32);
4707 }
4708 print '</span>';
4709 }
4710 if ($objectidnext > 0) {
4711 $facthatreplace = new Facture($db);
4712 $facthatreplace->fetch($objectidnext);
4713 print ' <span class="opacitymediumbycolor paddingleft">'.str_replace('{s1}', $facthatreplace->getNomUrl(1), $langs->transnoentities("ReplacedByInvoice", '{s1}')).'</span>';
4714 }
4715
4717 $discount = new DiscountAbsolute($db);
4718 $result = $discount->fetch(0, $object->id);
4719 if ($result > 0) {
4720 print ' <span class="opacitymediumbycolor paddingleft">';
4721 $s = $langs->trans("CreditNoteConvertedIntoDiscount", '{s1}', '{s2}');
4722 $s = str_replace('{s1}', $object->getLibType(0), $s);
4723 $s = str_replace('{s2}', $discount->getNomUrl(1, 'discount'), $s);
4724 print $s;
4725 print '</span><br>';
4726 }
4727 }
4728
4729 if ($object->fk_fac_rec_source > 0) {
4730 $tmptemplate = new FactureRec($db);
4731 $result = $tmptemplate->fetch($object->fk_fac_rec_source);
4732 if ($result > 0) {
4733 print ' <span class="opacitymediumbycolor paddingleft">';
4734 $s = $langs->transnoentities("GeneratedFromTemplate", '{s1}');
4735 $s = str_replace('{s1}', $tmptemplate->getNomUrl(1, '', 32), $s);
4736 print $s;
4737 print '</span>';
4738 }
4739 }
4740 print '</td></tr>';
4741
4742 // Relative and absolute discounts
4743 print '<!-- Discounts -->'."\n";
4744 print '<tr><td>'.$langs->trans('DiscountStillRemaining').'</td>';
4745 print '<td>';
4746 $thirdparty = $soc;
4747 $discount_type = 0;
4748 $backtopage = $_SERVER["PHP_SELF"].'?facid='.$object->id;
4749 include DOL_DOCUMENT_ROOT.'/core/tpl/object_discounts.tpl.php';
4750 print '</td></tr>';
4751
4752 // Date invoice
4753 print '<tr><td>';
4754 print '<table class="nobordernopadding centpercent"><tr><td>';
4755 print $langs->trans('DateInvoice');
4756 print '</td>';
4757 if ($action != 'editinvoicedate' && $object->status == $object::STATUS_DRAFT && $usercancreate && !getDolGlobalString('FAC_FORCE_DATE_VALIDATION')) {
4758 print '<td class="right"><a class="editfielda" href="'.$_SERVER["PHP_SELF"].'?action=editinvoicedate&token='.newToken().'&facid='.$object->id.'">'.img_edit($langs->trans('SetDate'), 1).'</a></td>';
4759 }
4760 print '</tr></table>';
4761 print '</td><td>';
4762
4763 if ($action == 'editinvoicedate') {
4764 $form->form_date($_SERVER['PHP_SELF'].'?facid='.$object->id, $object->date, 'invoicedate');
4765 } else {
4766 print '<span class="valuedate">'.dol_print_date($object->date, 'day').'</span>';
4767 }
4768 print '</td>';
4769
4770 print '</tr>';
4771
4772 if (getDolGlobalString('INVOICE_POINTOFTAX_DATE')) {
4773 // Date invoice point of tax
4774 print '<tr><td>';
4775 print '<table class="nobordernopadding centpercent"><tr><td>';
4776 print $langs->trans('DatePointOfTax');
4777 print '</td>';
4778 print '<td class="right"><a class="editfielda" href="'.$_SERVER["PHP_SELF"].'?action=editdate_pointoftax&token='.newToken().'&facid='.$object->id.'">'.img_edit($langs->trans('SetDate'), 1).'</a></td>';
4779 print '</tr></table>';
4780 print '</td><td>';
4781 if ($action == 'editdate_pointoftax') {
4782 $form->form_date($_SERVER['PHP_SELF'].'?facid='.$object->id, $object->date_pointoftax, 'date_pointoftax');
4783 } else {
4784 print '<span class="valuedate">'.dol_print_date($object->date_pointoftax, 'day').'</span>';
4785 }
4786 print '</td></tr>';
4787 }
4788
4789 // Payment term
4790 print '<tr><td>';
4791 print '<table class="nobordernopadding centpercent"><tr><td>';
4792 print $langs->trans('PaymentConditionsShort');
4793 print '</td>';
4794 if ($object->type != Facture::TYPE_CREDIT_NOTE && $action != 'editconditions' && $usercancreate) {
4795 print '<td class="right"><a class="editfielda" href="'.$_SERVER["PHP_SELF"].'?action=editconditions&token='.newToken().'&facid='.$object->id.'">'.img_edit($langs->trans('SetConditions'), 1).'</a></td>';
4796 }
4797 print '</tr></table>';
4798 print '</td><td>';
4799 if ($object->type != Facture::TYPE_CREDIT_NOTE) {
4800 if ($action == 'editconditions') {
4801 $form->form_conditions_reglement($_SERVER['PHP_SELF'].'?facid='.$object->id, $object->cond_reglement_id, 'cond_reglement_id');
4802 } else {
4803 $form->form_conditions_reglement($_SERVER['PHP_SELF'].'?facid='.$object->id, $object->cond_reglement_id, 'none');
4804 }
4805 } else {
4806 print '&nbsp;';
4807 }
4808 print '</td></tr>';
4809
4810 // Date payment term
4811 print '<tr><td>';
4812 print '<table class="nobordernopadding centpercent"><tr><td>';
4813 print $langs->trans('DateMaxPayment');
4814 print '</td>';
4815 if ($object->type != Facture::TYPE_CREDIT_NOTE && $action != 'editpaymentterm' && $usercancreate) {
4816 print '<td class="right"><a class="editfielda" href="'.$_SERVER["PHP_SELF"].'?action=editpaymentterm&token='.newToken().'&facid='.$object->id.'">'.img_edit($langs->trans('SetDate'), 1).'</a></td>';
4817 }
4818 print '</tr></table>';
4819 print '</td><td>';
4820 if ($object->type != Facture::TYPE_CREDIT_NOTE) {
4821 if ($action == 'editpaymentterm') {
4822 $form->form_date($_SERVER['PHP_SELF'].'?facid='.$object->id, $object->date_lim_reglement, 'paymentterm');
4823 } else {
4824 print '<span class="valuedate">'.dol_print_date($object->date_lim_reglement, 'day').'</span>';
4825 if ($object->hasDelay()) {
4826 print img_warning($langs->trans('Late'));
4827 }
4828 }
4829 } else {
4830 print '&nbsp;';
4831 }
4832 print '</td></tr>';
4833
4834 // Payment mode
4835 print '<tr><td>';
4836 print '<table class="nobordernopadding centpercent"><tr><td>';
4837 print $langs->trans('PaymentMode');
4838 print '</td>';
4839 if ($action != 'editmode' && $usercancreate) {
4840 print '<td class="right"><a class="editfielda" href="'.$_SERVER["PHP_SELF"].'?action=editmode&token='.newToken().'&facid='.$object->id.'">'.img_edit($langs->trans('SetMode'), 1).'</a></td>';
4841 }
4842 print '</tr></table>';
4843 print '</td><td>';
4844 if ($action == 'editmode') {
4845 $form->form_modes_reglement($_SERVER['PHP_SELF'].'?facid='.$object->id, $object->mode_reglement_id, 'mode_reglement_id', 'CRDT', 1, 1);
4846 } else {
4847 $form->form_modes_reglement($_SERVER['PHP_SELF'].'?facid='.$object->id, $object->mode_reglement_id, 'none', 'CRDT');
4848 }
4849 print '</td></tr>';
4850
4851 // Multicurrency
4852 if (isModEnabled('multicurrency')) {
4853 // Multicurrency code
4854 print '<tr>';
4855 print '<td>';
4856 print '<table class="nobordernopadding centpercent"><tr><td>';
4857 print $form->editfieldkey('Currency', 'multicurrency_code', '', $object, 0);
4858 print '</td>';
4859 if ($usercancreate && $action != 'editmulticurrencycode' && $object->status == $object::STATUS_DRAFT) {
4860 print '<td class="right"><a class="editfielda" href="'.$_SERVER["PHP_SELF"].'?action=editmulticurrencycode&token='.newToken().'&id='.$object->id.'">'.img_edit($langs->transnoentitiesnoconv('SetMultiCurrencyCode'), 1).'</a></td>';
4861 }
4862 print '</tr></table>';
4863 print '</td><td>';
4864 $htmlname = (($usercancreate && $action == 'editmulticurrencycode') ? 'multicurrency_code' : 'none');
4865 $form->form_multicurrency_code($_SERVER['PHP_SELF'].'?id='.$object->id, $object->multicurrency_code, $htmlname);
4866 print '</td></tr>';
4867
4868 // Multicurrency rate
4869 if ($object->multicurrency_code != $conf->currency || $object->multicurrency_tx != 1) {
4870 print '<tr>';
4871 print '<td>';
4872 print '<table class="nobordernopadding" width="100%"><tr><td>';
4873 print $form->editfieldkey('CurrencyRate', 'multicurrency_tx', '', $object, 0);
4874 print '</td>';
4875 if ($usercancreate && $action != 'editmulticurrencyrate' && $object->status == $object::STATUS_DRAFT && $object->multicurrency_code && $object->multicurrency_code != $conf->currency) {
4876 print '<td class="right"><a class="editfielda" href="'.$_SERVER["PHP_SELF"].'?action=editmulticurrencyrate&token='.newToken().'&id='.$object->id.'">'.img_edit($langs->transnoentitiesnoconv('SetMultiCurrencyCode'), 1).'</a></td>';
4877 }
4878 print '</tr></table>';
4879 print '</td><td>';
4880 if ($action == 'editmulticurrencyrate' || $action == 'actualizemulticurrencyrate') {
4881 if ($action == 'actualizemulticurrencyrate') {
4882 list($object->fk_multicurrency, $object->multicurrency_tx) = MultiCurrency::getIdAndTxFromCode($object->db, $object->multicurrency_code);
4883 }
4884 $form->form_multicurrency_rate($_SERVER['PHP_SELF'].'?id='.$object->id, $object->multicurrency_tx, ($usercancreate ? 'multicurrency_tx' : 'none'), $object->multicurrency_code);
4885 } else {
4886 $form->form_multicurrency_rate($_SERVER['PHP_SELF'].'?id='.$object->id, $object->multicurrency_tx, 'none', $object->multicurrency_code);
4887 if ($object->status == $object::STATUS_DRAFT && $object->multicurrency_code && $object->multicurrency_code != $conf->currency) {
4888 print '<div class="inline-block"> &nbsp; &nbsp; &nbsp; &nbsp; ';
4889 print '<a href="'.$_SERVER["PHP_SELF"].'?id='.$object->id.'&action=actualizemulticurrencyrate">'.$langs->trans("ActualizeCurrency").'</a>';
4890 print '</div>';
4891 }
4892 }
4893 print '</td></tr>';
4894 }
4895 }
4896
4897 // Bank Account
4898 if (isModEnabled("bank")) {
4899 print '<tr><td class="nowrap">';
4900 print '<table class="nobordernopadding centpercent"><tr><td class="nowrap">';
4901 print $langs->trans('BankAccount');
4902 print '<td>';
4903 if (($action != 'editbankaccount') && $usercancreate) {
4904 print '<td class="right"><a class="editfielda" href="'.$_SERVER["PHP_SELF"].'?action=editbankaccount&token='.newToken().'&id='.$object->id.'">'.img_edit($langs->trans('SetBankAccount'), 1).'</a></td>';
4905 }
4906 print '</tr></table>';
4907 print '</td><td>';
4908 if ($action == 'editbankaccount') {
4909 $form->formSelectAccount($_SERVER['PHP_SELF'].'?id='.$object->id, $object->fk_account, 'fk_account', 1);
4910 } else {
4911 $form->formSelectAccount($_SERVER['PHP_SELF'].'?id='.$object->id, $object->fk_account, 'none');
4912 }
4913 print "</td>";
4914 print '</tr>';
4915 }
4916
4917 // Incoterms
4918 if (isModEnabled('incoterm')) {
4919 print '<tr><td>';
4920 print '<table class="nobordernopadding centpercent"><tr><td>';
4921 print $langs->trans('IncotermLabel');
4922 print '<td><td class="right">';
4923 if ($usercancreate) {
4924 print '<a class="editfielda" href="'.DOL_URL_ROOT.'/compta/facture/card.php?facid='.$object->id.'&action=editincoterm&token='.newToken().'">'.img_edit().'</a>';
4925 } else {
4926 print '&nbsp;';
4927 }
4928 print '</td></tr></table>';
4929 print '</td>';
4930 print '<td>';
4931 if ($action != 'editincoterm') {
4932 print $form->textwithpicto($object->display_incoterms(), $object->label_incoterms, 1);
4933 } else {
4934 print $form->select_incoterms((!empty($object->fk_incoterms) ? $object->fk_incoterms : ''), (!empty($object->location_incoterms) ? $object->location_incoterms : ''), $_SERVER['PHP_SELF'].'?id='.$object->id);
4935 }
4936 print '</td></tr>';
4937 }
4938
4939
4940
4941 if (!empty($object->retained_warranty) || getDolGlobalString('INVOICE_USE_RETAINED_WARRANTY')) {
4942 $displayWarranty = true;
4943 if (!in_array($object->type, $retainedWarrantyInvoiceAvailableType) && empty($object->retained_warranty)) {
4944 $displayWarranty = false;
4945 }
4946
4947 if ($displayWarranty) {
4948 // Retained Warranty
4949 print '<tr class="retained-warranty-lines" ><td>';
4950 print '<table id="retained-warranty-table" class="nobordernopadding centpercent"><tr><td>';
4951 print $langs->trans('RetainedWarranty');
4952 print '</td>';
4953 if ($action != 'editretainedwarranty' && $user->hasRight('facture', 'creer') && $object->status == Facture::STATUS_DRAFT) {
4954 print '<td align="right"><a class="editfielda" href="'.$_SERVER["PHP_SELF"].'?action=editretainedwarranty&token='.newToken().'&facid='.$object->id.'">'.img_edit($langs->trans('setRetainedWarranty'), 1).'</a></td>';
4955 }
4956
4957 print '</tr></table>';
4958 print '</td><td>';
4959 if ($action == 'editretainedwarranty' && $object->status == Facture::STATUS_DRAFT) {
4960 print '<form id="retained-warranty-form" method="POST" action="'.$_SERVER['PHP_SELF'].'?facid='.$object->id.'">';
4961 print '<input type="hidden" name="action" value="setretainedwarranty">';
4962 print '<input type="hidden" name="token" value="'.newToken().'">';
4963 print '<input type="hidden" name="backtopage" value="'.$backtopage.'">';
4964 print '<input name="retained_warranty" type="number" step="0.01" min="0" max="100" value="'.$object->retained_warranty.'" >';
4965 print '<input type="submit" class="button valignmiddle smallpaddingimp" value="'.$langs->trans("Modify").'">';
4966 print '</form>';
4967 } else {
4968 print price($object->retained_warranty).'%';
4969 }
4970 print '</td></tr>';
4971
4972 // Retained warranty payment term
4973 print '<tr class="retained-warranty-lines" ><td>';
4974 print '<table id="retained-warranty-cond-reglement-table" class="nobordernopadding" width="100%"><tr><td>';
4975 print $langs->trans('PaymentConditionsShortRetainedWarranty');
4976 print '</td>';
4977 if ($action != 'editretainedwarrantypaymentterms' && $user->hasRight('facture', 'creer') && $object->status == Facture::STATUS_DRAFT) {
4978 print '<td align="right"><a class="editfielda" href="'.$_SERVER["PHP_SELF"].'?action=editretainedwarrantypaymentterms&token='.newToken().'&facid='.$object->id.'">'.img_edit($langs->trans('setPaymentConditionsShortRetainedWarranty'), 1).'</a></td>';
4979 }
4980
4981 print '</tr></table>';
4982 print '</td><td>';
4983 $defaultDate = !empty($object->retained_warranty_date_limit) ? $object->retained_warranty_date_limit : strtotime('-1 years', $object->date_lim_reglement);
4984 if ($object->date > $defaultDate) {
4985 $defaultDate = $object->date;
4986 }
4987
4988 if ($action == 'editretainedwarrantypaymentterms' && $object->status == Facture::STATUS_DRAFT) {
4989 //date('Y-m-d',$object->date_lim_reglement)
4990 print '<form method="POST" action="'.$_SERVER['PHP_SELF'].'?facid='.$object->id.'">';
4991 print '<input type="hidden" name="action" value="setretainedwarrantyconditions">';
4992 print '<input type="hidden" name="token" value="'.newToken().'">';
4993 print '<input type="hidden" name="backtopage" value="'.$backtopage.'">';
4994 $retained_warranty_fk_cond_reglement = GETPOSTINT('retained_warranty_fk_cond_reglement');
4995 $retained_warranty_fk_cond_reglement = !empty($retained_warranty_fk_cond_reglement) ? $retained_warranty_fk_cond_reglement : $object->retained_warranty_fk_cond_reglement;
4996 $retained_warranty_fk_cond_reglement = !empty($retained_warranty_fk_cond_reglement) ? $retained_warranty_fk_cond_reglement : getDolGlobalString('INVOICE_SITUATION_DEFAULT_RETAINED_WARRANTY_COND_ID');
4997 print $form->getSelectConditionsPaiements($retained_warranty_fk_cond_reglement, 'retained_warranty_fk_cond_reglement', -1, 1);
4998 print '<input type="submit" class="button valignmiddle" value="'.$langs->trans("Modify").'">';
4999 print '</form>';
5000 } else {
5001 $form->form_conditions_reglement($_SERVER['PHP_SELF'].'?facid='.$object->id, $object->retained_warranty_fk_cond_reglement, 'none');
5002 if (!$displayWarranty) {
5003 print img_picto($langs->trans('RetainedWarrantyNeed100Percent'), 'warning.png', 'class="pictowarning valignmiddle" ');
5004 }
5005 }
5006 print '</td></tr>';
5007
5008 // Retained Warranty payment date limit
5009 print '<tr class="retained-warranty-lines" ><td>';
5010 print '<table id="retained-warranty-date-limit-table" class="nobordernopadding" width="100%"><tr><td>';
5011 print $langs->trans('RetainedWarrantyDateLimit');
5012 print '</td>';
5013 if ($action != 'editretainedwarrantydatelimit' && $user->hasRight('facture', 'creer') && $object->status == Facture::STATUS_DRAFT) {
5014 print '<td align="right"><a class="editfielda" href="'.$_SERVER["PHP_SELF"].'?action=editretainedwarrantydatelimit&token='.newToken().'&facid='.$object->id.'">'.img_edit($langs->trans('setRetainedWarrantyDateLimit'), 1).'</a></td>';
5015 }
5016
5017 print '</tr></table>';
5018 print '</td><td>';
5019 $defaultDate = !empty($object->retained_warranty_date_limit) ? $object->retained_warranty_date_limit : strtotime('-1 years', $object->date_lim_reglement);
5020 if ($object->date > $defaultDate) {
5021 $defaultDate = $object->date;
5022 }
5023
5024 if ($action == 'editretainedwarrantydatelimit' && $object->status == Facture::STATUS_DRAFT) {
5025 //date('Y-m-d',$object->date_lim_reglement)
5026 print '<form method="POST" action="'.$_SERVER['PHP_SELF'].'?facid='.$object->id.'">';
5027 print '<input type="hidden" name="action" value="setretainedwarrantydatelimit">';
5028 print '<input type="hidden" name="token" value="'.newToken().'">';
5029 print '<input type="hidden" name="backtopage" value="'.$backtopage.'">';
5030 print '<input name="retained_warranty_date_limit" type="date" step="1" min="'.dol_print_date($object->date, '%Y-%m-%d').'" value="'.dol_print_date($defaultDate, '%Y-%m-%d').'" >';
5031 print '<input type="submit" class="button valignmiddle" value="'.$langs->trans("Modify").'">';
5032 print '</form>';
5033 } else {
5034 print dol_print_date($object->retained_warranty_date_limit, 'day');
5035 }
5036 print '</td></tr>';
5037 }
5038 }
5039
5040
5041 // Other attributes
5042 $cols = 2;
5043 include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_view.tpl.php';
5044
5045 print '</table>';
5046
5047 print '</div>';
5048 print '<div class="fichehalfright">';
5049
5050 print '<!-- amounts -->'."\n";
5051 print '<div class="underbanner clearboth"></div>'."\n";
5052
5053 print '<table class="border tableforfield centpercent">';
5054
5055 $sign = 1;
5056 if (getDolGlobalString('INVOICE_POSITIVE_CREDIT_NOTE_SCREEN') && $object->type == $object::TYPE_CREDIT_NOTE) {
5057 $sign = -1; // We invert sign for output
5058 }
5059 print '<tr>';
5060 // Amount HT
5061 print '<td class="titlefieldmiddle">' . $langs->trans('AmountHT') . '</td>';
5062 print '<td class="nowrap amountcard right">' . price($sign * $object->total_ht, 0, $langs, 0, -1, -1, $conf->currency) . '</td>';
5063 if (isModEnabled("multicurrency") && ($object->multicurrency_code && $object->multicurrency_code != $conf->currency)) {
5064 // Multicurrency Amount HT
5065 print '<td class="nowrap amountcard right">' . price($sign * $object->multicurrency_total_ht, 0, $langs, 0, -1, -1, $object->multicurrency_code) . '</td>';
5066 }
5067 print '</tr>';
5068
5069 print '<tr>';
5070 // Amount VAT
5071 print '<td class="titlefieldmiddle">' . $langs->trans('AmountVAT') . '</td>';
5072 print '<td class="nowrap amountcard right">' . price($sign * $object->total_tva, 0, $langs, 0, -1, -1, $conf->currency) . '</td>';
5073 if (isModEnabled("multicurrency") && ($object->multicurrency_code && $object->multicurrency_code != $conf->currency)) {
5074 // Multicurrency Amount VAT
5075 print '<td class="nowrap amountcard right">' . price($sign * $object->multicurrency_total_tva, 0, $langs, 0, -1, -1, $object->multicurrency_code) . '</td>';
5076 }
5077 print '</tr>';
5078
5079 // Amount Local Taxes
5080 if (($mysoc->localtax1_assuj == "1" && $mysoc->useLocalTax(1)) || $object->total_localtax1 != 0) {
5081 print '<tr>';
5082 print '<td class="titlefieldmiddle">' . $langs->transcountry("AmountLT1", $mysoc->country_code) . '</td>';
5083 print '<td class="nowrap amountcard right">' . price($sign * $object->total_localtax1, 0, $langs, 0, -1, -1, $conf->currency) . '</td>';
5084 if (isModEnabled("multicurrency") && ($object->multicurrency_code && $object->multicurrency_code != $conf->currency)) {
5085 $object->multicurrency_total_localtax1 = (float) price2num($object->total_localtax1 * $object->multicurrency_tx, 'MT');
5086
5087 print '<td class="nowrap amountcard right">' . price($sign * $object->multicurrency_total_localtax1, 0, $langs, 0, -1, -1, $object->multicurrency_code) . '</td>';
5088 }
5089 print '</tr>';
5090 }
5091
5092 if (($mysoc->localtax2_assuj == "1" && $mysoc->useLocalTax(2)) || $object->total_localtax2 != 0) {
5093 print '<tr>';
5094 print '<td>' . $langs->transcountry("AmountLT2", $mysoc->country_code) . '</td>';
5095 print '<td class="nowrap amountcard right">' . price($sign * $object->total_localtax2, 0, $langs, 0, -1, -1, $conf->currency) . '</td>';
5096 if (isModEnabled("multicurrency") && ($object->multicurrency_code && $object->multicurrency_code != $conf->currency)) {
5097 $object->multicurrency_total_localtax2 = (float) price2num($object->total_localtax2 * $object->multicurrency_tx, 'MT');
5098
5099 print '<td class="nowrap amountcard right">' . price($sign * $object->multicurrency_total_localtax2, 0, $langs, 0, -1, -1, $object->multicurrency_code) . '</td>';
5100 }
5101 print '</tr>';
5102 }
5103
5104 // Add the revenue stamp
5105 if ($selleruserevenustamp) {
5106 print '<tr><td class="titlefieldmiddle">';
5107 print '<table class="nobordernopadding centpercent"><tr><td>';
5108 print $langs->trans('RevenueStamp');
5109 print '</td>';
5110 if ($action != 'editrevenuestamp' && $object->status == $object::STATUS_DRAFT && $usercancreate) {
5111 print '<td class="right"><a class="editfielda" href="'.$_SERVER["PHP_SELF"].'?action=editrevenuestamp&token='.newToken().'&facid='.$object->id.'">'.img_edit($langs->trans('SetRevenuStamp'), 1).'</a></td>';
5112 }
5113 print '</tr></table>';
5114 print '</td><td class="nowrap amountcard right">';
5115 if ($action == 'editrevenuestamp') {
5116 print '<form action="'.$_SERVER["PHP_SELF"].'?id='.$object->id.'" method="post">';
5117 print '<input type="hidden" name="token" value="'.newToken().'">';
5118 print '<input type="hidden" name="action" value="setrevenuestamp">';
5119 print '<input type="hidden" name="revenuestamp" id="revenuestamp_val" value="'.price2num($object->revenuestamp).'">';
5120 print '<input type="hidden" name="backtopage" value="'.$backtopage.'">';
5121 print $formother->select_revenue_stamp('', 'revenuestamp_type', $mysoc->country_code);
5122 print ' &rarr; <span id="revenuestamp_span"></span>';
5123 print ' <input type="submit" class="button buttongen button-save small" value="'.$langs->trans('Modify').'">';
5124 print '</form>';
5125 print " <script>
5126 $(document).ready(function(){
5127 js_recalculate_revenuestamp();
5128 $('select[name=revenuestamp_type]').on('change',function(){
5129 js_recalculate_revenuestamp();
5130 });
5131 });
5132 function js_recalculate_revenuestamp(){
5133 var valselected = $('select[name=revenuestamp_type]').val();
5134 console.log('Calculate revenue stamp from '+valselected);
5135 var revenue = 0;
5136 if (valselected.indexOf('%') == -1)
5137 {
5138 revenue = valselected;
5139 }
5140 else
5141 {
5142 var revenue_type = parseFloat(valselected);
5143 var amount_net = ".round($object->total_ht, 2).";
5144 revenue = revenue_type * amount_net / 100;
5145 revenue = revenue.toFixed(2);
5146 }
5147 $('#revenuestamp_val').val(revenue);
5148 $('#revenuestamp_span').html(revenue);
5149 }
5150 </script>";
5151 } else {
5152 print price($object->revenuestamp, 1, '', 1, -1, -1, $conf->currency);
5153 }
5154 print '</td></tr>';
5155 }
5156
5157 print '<tr>';
5158 // Amount TTC
5159 print '<td>' . $langs->trans('AmountTTC') . '</td>';
5160 print '<td class="nowrap amountcard right">' . price($sign * $object->total_ttc, 0, $langs, 0, -1, -1, $conf->currency) . '</td>';
5161 if (isModEnabled("multicurrency") && ($object->multicurrency_code && $object->multicurrency_code != $conf->currency)) {
5162 // Multicurrency Amount TTC
5163 print '<td class="nowrap amountcard right">' . price($sign * $object->multicurrency_total_ttc, 0, $langs, 0, -1, -1, $object->multicurrency_code) . '</td>';
5164 }
5165 print '</tr>';
5166
5167 print '</table>';
5168
5169 $nbrows = 8;
5170 $nbcols = 3;
5171 if (isModEnabled('project')) {
5172 $nbrows++;
5173 }
5174 if (isModEnabled("bank")) {
5175 $nbrows++;
5176 $nbcols++;
5177 }
5178 if ($mysoc->localtax1_assuj == "1" || $object->total_localtax1 != 0) {
5179 $nbrows++;
5180 }
5181 if ($mysoc->localtax2_assuj == "1" || $object->total_localtax2 != 0) {
5182 $nbrows++;
5183 }
5184 if ($selleruserevenustamp) {
5185 $nbrows++;
5186 }
5187 if (isModEnabled('multicurrency')) {
5188 $nbrows += 5;
5189 }
5190 if (isModEnabled('incoterm')) {
5191 $nbrows += 1;
5192 }
5193
5194 // List of previous situation invoices
5195 if (($object->situation_cycle_ref > 0) && getDolGlobalString('INVOICE_USE_SITUATION')) {
5196 print '<!-- List of situation invoices -->';
5197 print '<table class="noborder situationstable" width="100%">';
5198
5199 print '<tr class="liste_titre">';
5200 print '<td>'.$langs->trans('ListOfSituationInvoices').'</td>';
5201 print '<td></td>';
5202 print '<td class="center">'.$langs->trans('Situation').'</td>';
5203 if (isModEnabled("bank")) {
5204 print '<td class="right"></td>';
5205 }
5206 print '<td class="right">'.$langs->trans('AmountHT').'</td>';
5207 print '<td class="right">'.$langs->trans('AmountTTC').'</td>';
5208 print '<td width="18">&nbsp;</td>';
5209 print '</tr>';
5210
5211 $total_prev_ht = $total_prev_ttc = 0;
5212 $total_global_ht = $total_global_ttc = 0;
5213
5214 if (count($object->tab_previous_situation_invoice) > 0) {
5215 // List of previous invoices
5216
5217 $current_situation_counter = array();
5218 foreach ($object->tab_previous_situation_invoice as $prev_invoice) {
5219 $tmptotalpaidforthisinvoice = $prev_invoice->getSommePaiement();
5220 $total_prev_ht += $prev_invoice->total_ht;
5221 $total_prev_ttc += $prev_invoice->total_ttc;
5222 $current_situation_counter[] = (($prev_invoice->type == Facture::TYPE_CREDIT_NOTE) ? -1 : 1) * $prev_invoice->situation_counter;
5223 print '<tr class="oddeven">';
5224 print '<td>'.$prev_invoice->getNomUrl(1).'</td>';
5225 print '<td></td>';
5226 print '<td align="center" >'.(($prev_invoice->type == Facture::TYPE_CREDIT_NOTE) ? $langs->trans('situationInvoiceShortcode_AS') : $langs->trans('situationInvoiceShortcode_S')).$prev_invoice->situation_counter.'</td>';
5227 if (isModEnabled("bank")) {
5228 print '<td class="right"></td>';
5229 }
5230 print '<td class="right"><span class="amount">'.price($prev_invoice->total_ht).'</span></td>';
5231 print '<td class="right"><span class="amount">'.price($prev_invoice->total_ttc).'</span></td>';
5232 print '<td class="right">'.$prev_invoice->getLibStatut(3, $tmptotalpaidforthisinvoice).'</td>';
5233 print '</tr>';
5234 }
5235 }
5236
5237
5238 $total_global_ht += $total_prev_ht;
5239 $total_global_ttc += $total_prev_ttc;
5240 $total_global_ht += $object->total_ht;
5241 $total_global_ttc += $object->total_ttc;
5242 $current_situation_counter[] = (($object->type == Facture::TYPE_CREDIT_NOTE) ? -1 : 1) * $object->situation_counter;
5243 print '<tr class="oddeven">';
5244 print '<td>'.$object->getNomUrl(1).'</td>';
5245 print '<td></td>';
5246 print '<td class="center">'.(($object->type == Facture::TYPE_CREDIT_NOTE) ? $langs->trans('situationInvoiceShortcode_AS') : $langs->trans('situationInvoiceShortcode_S')).$object->situation_counter.'</td>';
5247 if (isModEnabled("bank")) {
5248 print '<td class="right"></td>';
5249 }
5250 print '<td class="right"><span class="amount">'.price($object->total_ht).'</span></td>';
5251 print '<td class="right"><span class="amount">'.price($object->total_ttc).'</span></td>';
5252 print '<td class="right">'.$object->getLibStatut(3, $object->getSommePaiement()).'</td>';
5253 print '</tr>';
5254
5255
5256 print '<tr class="oddeven">';
5257 print '<td colspan="2" class="left"><b>'.$langs->trans('CurrentSituationTotal').'</b></td>';
5258 print '<td>';
5259 $i = 0;
5260 foreach ($current_situation_counter as $sit) {
5261 $curSign = $sit > 0 ? '+' : '-';
5262 $curType = $sit > 0 ? $langs->trans('situationInvoiceShortcode_S') : $langs->trans('situationInvoiceShortcode_AS');
5263 if ($i > 0) {
5264 print ' '.$curSign.' ';
5265 }
5266 print $curType.abs($sit);
5267 $i++;
5268 }
5269 print '</td>';
5270 if (isModEnabled("bank")) {
5271 print '<td></td>';
5272 }
5273 print '<td class="right"><b>'.price($total_global_ht).'</b></td>';
5274 print '<td class="right"><b>'.price($total_global_ttc).'</b></td>';
5275 print '<td width="18">&nbsp;</td>';
5276 print '</tr>';
5277
5278
5279 if (count($object->tab_next_situation_invoice) > 0) {
5280 // List of next invoices
5281 /*print '<tr class="liste_titre">';
5282 print '<td>' . $langs->trans('ListOfNextSituationInvoices') . '</td>';
5283 print '<td></td>';
5284 print '<td></td>';
5285 if (isModEnabled('banque')) print '<td class="right"></td>';
5286 print '<td class="right">' . $langs->trans('AmountHT') . '</td>';
5287 print '<td class="right">' . $langs->trans('AmountTTC') . '</td>';
5288 print '<td width="18">&nbsp;</td>';
5289 print '</tr>';*/
5290
5291 $total_next_ht = $total_next_ttc = 0;
5292
5293 foreach ($object->tab_next_situation_invoice as $next_invoice) {
5294 $totalpaid = $next_invoice->getSommePaiement();
5295 $total_next_ht += $next_invoice->total_ht;
5296 $total_next_ttc += $next_invoice->total_ttc;
5297
5298 print '<tr class="oddeven">';
5299 print '<td>'.$next_invoice->getNomUrl(1).'</td>';
5300 print '<td></td>';
5301 print '<td class="center">'.(($next_invoice->type == Facture::TYPE_CREDIT_NOTE) ? $langs->trans('situationInvoiceShortcode_AS') : $langs->trans('situationInvoiceShortcode_S')).$next_invoice->situation_counter.'</td>';
5302 if (isModEnabled("bank")) {
5303 print '<td class="right"></td>';
5304 }
5305 print '<td class="right"><span class="amount">'.price($next_invoice->total_ht).'</span></td>';
5306 print '<td class="right"><span class="amount">'.price($next_invoice->total_ttc).'</span></td>';
5307 print '<td class="right">'.$next_invoice->getLibStatut(3, $totalpaid).'</td>';
5308 print '</tr>';
5309 }
5310
5311 $total_global_ht += $total_next_ht;
5312 $total_global_ttc += $total_next_ttc;
5313
5314 print '<tr class="oddeven">';
5315 print '<td colspan="3" class="right"></td>';
5316 if (isModEnabled("bank")) {
5317 print '<td class="right"></td>';
5318 }
5319 print '<td class="right"><b>'.price($total_global_ht).'</b></td>';
5320 print '<td class="right"><b>'.price($total_global_ttc).'</b></td>';
5321 print '<td width="18">&nbsp;</td>';
5322 print '</tr>';
5323 }
5324
5325 print '</table>';
5326 }
5327
5328 $sign = 1;
5329 if ($object->type == $object::TYPE_CREDIT_NOTE) {
5330 $sign = -1;
5331 }
5332
5333 // List of payments already done
5334
5335 print '<!-- List of payments already done -->';
5336 print '<div class="div-table-responsive-no-min">';
5337 print '<table class="noborder paymenttable centpercent">';
5338
5339 print '<tr class="liste_titre">';
5340 print '<td class="liste_titre">'.($object->type == Facture::TYPE_CREDIT_NOTE ? $langs->trans("PaymentsBack") : $langs->trans('Payments')).'</td>';
5341 print '<td class="liste_titre"><span class="hideonsmartphone">'.$langs->trans('Date').'</span></td>';
5342 print '<td class="liste_titre"><span class="hideonsmartphone">'.$langs->trans('Type').'</span></td>';
5343 if (isModEnabled("bank")) {
5344 print '<td class="liste_titre"><span class="hideonsmartphone">'.$langs->trans('BankAccount').'</span></td>';
5345 }
5346 print '<td class="liste_titre right">'.$langs->trans('Amount').'</td>';
5347 print '<td class="liste_titre" width="18">&nbsp;</td>';
5348 print '</tr>';
5349
5350 // Payments already done (from payment on this invoice)
5351 $sql = 'SELECT p.datep as dp, p.ref, p.num_paiement as num_payment, p.rowid, p.fk_bank,';
5352 $sql .= ' c.code as payment_code, c.libelle as payment_label,';
5353 $sql .= ' pf.amount,';
5354 $sql .= ' ba.rowid as baid, ba.ref as baref, ba.label, ba.number as banumber, ba.account_number, ba.fk_accountancy_journal, ba.currency_code as bacurrency_code';
5355 $sql .= ' FROM '.MAIN_DB_PREFIX.'paiement_facture as pf, '.MAIN_DB_PREFIX.'paiement as p';
5356 $sql .= ' LEFT JOIN '.MAIN_DB_PREFIX.'c_paiement as c ON p.fk_paiement = c.id';
5357 $sql .= ' LEFT JOIN '.MAIN_DB_PREFIX.'bank as b ON p.fk_bank = b.rowid';
5358 $sql .= ' LEFT JOIN '.MAIN_DB_PREFIX.'bank_account as ba ON b.fk_account = ba.rowid';
5359 $sql .= ' WHERE pf.fk_facture = '.((int) $object->id).' AND pf.fk_paiement = p.rowid';
5360 $sql .= ' AND p.entity IN ('.getEntity('invoice').')';
5361 $sql .= ' ORDER BY p.datep, p.tms';
5362
5363 $result = $db->query($sql);
5364 if ($result) {
5365 $num = $db->num_rows($result);
5366 $i = 0;
5367
5368 if ($num > 0) {
5369 while ($i < $num) {
5370 $objp = $db->fetch_object($result);
5371
5372 $paymentstatic->id = $objp->rowid;
5373 $paymentstatic->datepaye = $db->jdate($objp->dp);
5374 $paymentstatic->ref = $objp->ref;
5375 $paymentstatic->num_payment = $objp->num_payment;
5376 $paymentstatic->paiementcode = $objp->payment_code;
5377
5378 print '<tr class="oddeven"><td class="nowraponall">';
5379 print $paymentstatic->getNomUrl(1);
5380 print '</td>';
5381 print '<td>';
5382 $dateofpayment = $db->jdate($objp->dp);
5383 $tmparray = dol_getdate($dateofpayment);
5384 if ($tmparray['seconds'] == 0 && $tmparray['minutes'] == 0 && ($tmparray['hours'] == 0 || $tmparray['hours'] == 12)) { // We set hours to 0:00 or 12:00 because we don't know it
5385 print dol_print_date($dateofpayment, 'day');
5386 } else { // Hours was set to real date of payment (special case for POS for example)
5387 print dol_print_date($dateofpayment, 'dayhour', 'tzuser');
5388 }
5389 print '</td>';
5390
5391 $label = ($langs->trans("PaymentType".$objp->payment_code) != "PaymentType".$objp->payment_code) ? $langs->trans("PaymentType".$objp->payment_code) : $objp->payment_label;
5392 print '<td class="tdoverflowmax80" title="'.dol_escape_htmltag($label.' '.$objp->num_payment).'">'.dol_escape_htmltag($label.' '.$objp->num_payment).'</td>';
5393 if (isModEnabled("bank")) {
5394 $bankaccountstatic->id = $objp->baid;
5395 $bankaccountstatic->ref = $objp->baref;
5396 $bankaccountstatic->label = $objp->baref;
5397 $bankaccountstatic->number = $objp->banumber;
5398 $bankaccountstatic->currency_code = $objp->bacurrency_code;
5399
5400 if (isModEnabled('accounting')) {
5401 $bankaccountstatic->account_number = $objp->account_number;
5402
5403 $accountingjournal = new AccountingJournal($db);
5404 $accountingjournal->fetch($objp->fk_accountancy_journal);
5405 $bankaccountstatic->accountancy_journal = $accountingjournal->getNomUrl(0, 1, 1, '', 1);
5406 }
5407
5408 print '<td class="nowraponall">';
5409 if ($bankaccountstatic->id) {
5410 print $bankaccountstatic->getNomUrl(1, 'transactions');
5411 }
5412 print '</td>';
5413 }
5414 print '<td class="right"><span class="amount">'.price($sign * $objp->amount).'</span></td>';
5415 print '<td class="center">';
5416
5417 $paiement = new Paiement($db);
5418 $paiement->fetch($objp->rowid);
5419 if ($object->status == Facture::STATUS_VALIDATED && $object->paye == 0 && $user->socid == 0 && !$paiement->isReconciled()) {
5420 print '<a href="'.$_SERVER["PHP_SELF"].'?id='.$object->id.'&action=deletepayment&token='.newToken().'&paiement_id='.$objp->rowid.'">';
5421 print img_delete();
5422 print '</a>';
5423 }
5424 print '</td>';
5425 print '</tr>';
5426 $i++;
5427 }
5428 }
5429
5430 $db->free($result);
5431 } else {
5432 dol_print_error($db);
5433 }
5434
5435 if ($object->type != Facture::TYPE_CREDIT_NOTE) {
5436 // Total already paid
5437 print '<tr><td colspan="'.$nbcols.'" class="right">';
5438 print '<span class="opacitymedium">';
5439 if ($object->type != Facture::TYPE_DEPOSIT) {
5440 print $langs->trans('AlreadyPaidNoCreditNotesNoDeposits');
5441 } else {
5442 print $langs->trans('AlreadyPaid');
5443 }
5444 print '</span></td><td class="right'.(($totalpaid > 0) ? ' amountalreadypaid' : '').'">'.price($totalpaid).'</td><td>&nbsp;</td></tr>';
5445
5446 $resteapayeraffiche = $resteapayer;
5447 $cssforamountpaymentcomplete = 'amountpaymentcomplete';
5448
5449 // Loop on each credit note or deposit amount applied
5450 $creditnoteamount = 0;
5451 $depositamount = 0;
5452 $sql = "SELECT re.rowid, re.amount_ht, re.amount_tva, re.amount_ttc,";
5453 $sql .= " re.description, re.fk_facture_source";
5454 $sql .= " FROM ".MAIN_DB_PREFIX."societe_remise_except as re";
5455 $sql .= " WHERE fk_facture = ".((int) $object->id);
5456 $resql = $db->query($sql);
5457 if ($resql) {
5458 $num = $db->num_rows($resql);
5459 $i = 0;
5460 $invoice = new Facture($db);
5461 while ($i < $num) {
5462 $obj = $db->fetch_object($resql);
5463 $invoice->fetch($obj->fk_facture_source);
5464 print '<tr><td colspan="'.$nbcols.'" class="right">';
5465 print '<span class="opacitymedium">';
5466 if ($invoice->type == Facture::TYPE_CREDIT_NOTE) {
5467 print $langs->trans("CreditNote").' ';
5468 }
5469 if ($invoice->type == Facture::TYPE_DEPOSIT) {
5470 print $langs->trans("Deposit").' ';
5471 }
5472 print $invoice->getNomUrl(0);
5473 print '</span>';
5474 print '</td>';
5475 print '<td class="right"><span class="amount">'.price($obj->amount_ttc).'</span></td>';
5476 print '<td class="right">';
5477 print '<a href="'.$_SERVER["PHP_SELF"].'?facid='.$object->id.'&action=unlinkdiscount&token='.newToken().'&discountid='.$obj->rowid.'">';
5478 print img_picto($langs->transnoentitiesnoconv("RemoveDiscount"), 'unlink');
5479 print '</a>';
5480 print '</td></tr>';
5481 $i++;
5482 if ($invoice->type == Facture::TYPE_CREDIT_NOTE) {
5483 $creditnoteamount += $obj->amount_ttc;
5484 }
5485 if ($invoice->type == Facture::TYPE_DEPOSIT) {
5486 $depositamount += $obj->amount_ttc;
5487 }
5488 }
5489 } else {
5490 dol_print_error($db);
5491 }
5492
5493 // Partially paid 'discount'
5494 if (($object->status == Facture::STATUS_CLOSED || $object->status == Facture::STATUS_ABANDONED) && $object->close_code == 'discount_vat') {
5495 print '<tr><td colspan="'.$nbcols.'" class="nowrap right">';
5496 print '<span class="opacitymedium">';
5497 print $form->textwithpicto($langs->trans("Discount"), $langs->trans("HelpEscompte"), - 1);
5498 print '</span>';
5499 print '</td><td class="right"><span class="amount">'.price(price2num($object->total_ttc - $creditnoteamount - $depositamount - $totalpaid, 'MT')).'</span></td><td>&nbsp;</td></tr>';
5500 $resteapayeraffiche = 0;
5501 $cssforamountpaymentcomplete = 'amountpaymentneutral';
5502 }
5503 // Partially paid or abandoned 'badcustomer'
5504 if (($object->status == Facture::STATUS_CLOSED || $object->status == Facture::STATUS_ABANDONED) && $object->close_code == 'badcustomer') {
5505 print '<tr><td colspan="'.$nbcols.'" class="nowrap right">';
5506 print '<span class="opacitymedium">';
5507 print $form->textwithpicto($langs->trans("Abandoned"), $langs->trans("HelpAbandonBadCustomer"), - 1);
5508 print '</span>';
5509 print '</td><td class="right">'.price(price2num($object->total_ttc - $creditnoteamount - $depositamount - $totalpaid, 'MT')).'</td><td>&nbsp;</td></tr>';
5510 // $resteapayeraffiche=0;
5511 $cssforamountpaymentcomplete = 'amountpaymentneutral';
5512 }
5513 // Partially paid or abandoned 'product_returned'
5514 if (($object->status == Facture::STATUS_CLOSED || $object->status == Facture::STATUS_ABANDONED) && $object->close_code == 'product_returned') {
5515 print '<tr><td colspan="'.$nbcols.'" class="nowrap right">';
5516 print '<span class="opacitymedium">';
5517 print $form->textwithpicto($langs->trans("ProductReturned"), $langs->trans("HelpAbandonProductReturned"), - 1);
5518 print '</span>';
5519 print '</td><td class="right"><span class="amount">'.price(price2num($object->total_ttc - $creditnoteamount - $depositamount - $totalpaid, 'MT')).'</span></td><td>&nbsp;</td></tr>';
5520 $resteapayeraffiche = 0;
5521 $cssforamountpaymentcomplete = 'amountpaymentneutral';
5522 }
5523 // Partially paid or abandoned 'abandoned'
5524 if (($object->status == Facture::STATUS_CLOSED || $object->status == Facture::STATUS_ABANDONED) && $object->close_code == 'abandon') {
5525 print '<tr><td colspan="'.$nbcols.'" class="nowrap right">';
5526 $text = $langs->trans("HelpAbandonOther");
5527 if ($object->close_note) {
5528 $text .= '<br><br><b>'.$langs->trans("Reason").'</b>:'.$object->close_note;
5529 }
5530 print '<span class="opacitymedium">';
5531 // @phan-suppress-next-line PhanPluginSuspiciousParamPosition
5532 print $form->textwithpicto($langs->trans("Abandoned"), $text, - 1);
5533 print '</span>';
5534 print '</td><td class="right"><span class="amount">'.price(price2num($object->total_ttc - $creditnoteamount - $depositamount - $totalpaid, 'MT')).'</span></td><td>&nbsp;</td></tr>';
5535 $resteapayeraffiche = 0;
5536 $cssforamountpaymentcomplete = 'amountpaymentneutral';
5537 }
5538
5539 // Billed
5540 print '<tr><td colspan="'.$nbcols.'" class="right">';
5541 print '<span class="opacitymedium">';
5542 print $langs->trans("Billed");
5543 print '</td><td class="right">'.price($object->total_ttc).'</td><td>&nbsp;</td></tr>';
5544 // Remainder to pay
5545 print '<tr><td colspan="'.$nbcols.'" class="right">';
5546 print '<span class="opacitymedium">';
5547 print $langs->trans('RemainderToPay');
5548 if ($resteapayeraffiche < 0) {
5549 print ' ('.$langs->trans('NegativeIfExcessReceived').')';
5550 }
5551 print '</span>';
5552 print '</td>';
5553 print '<td class="right'.($resteapayeraffiche ? ' amountremaintopay' : (' '.$cssforamountpaymentcomplete)).'">'.price($resteapayeraffiche).'</td><td>&nbsp;</td></tr>';
5554
5555 // Remainder to pay Multicurrency
5556 if ($object->multicurrency_code != $conf->currency || $object->multicurrency_tx != 1) {
5557 print '<tr><td colspan="'.$nbcols.'" class="right">';
5558 print '<span class="opacitymedium">';
5559 print $langs->trans('RemainderToPayMulticurrency');
5560 if ($resteapayeraffiche < 0) {
5561 print ' ('.$langs->trans('NegativeIfExcessReceived').')';
5562 }
5563 print '</span>';
5564 print '</td>';
5565 print '<td class="right'.($resteapayeraffiche ? ' amountremaintopay' : (' '.$cssforamountpaymentcomplete)).'">';
5566 //print (empty($object->multicurrency_code) ? $conf->currency : $object->multicurrency_code).' ';
5567 print price(price2num($object->multicurrency_tx * $resteapayeraffiche, 'MT'), 1, $langs, 1, -1, -1, (empty($object->multicurrency_code) ? $conf->currency : $object->multicurrency_code)).'</td><td>&nbsp;</td></tr>';
5568 }
5569
5570 // Retained warranty : usually use on construction industry
5571 if (!empty($object->situation_final) && !empty($object->retained_warranty) && $displayWarranty) {
5572 // Billed - retained warranty
5573 if ($object->type == Facture::TYPE_SITUATION) {
5574 $retainedWarranty = $total_global_ttc * $object->retained_warranty / 100;
5575 } else {
5576 // Because one day retained warranty could be used on standard invoices
5577 $retainedWarranty = $object->total_ttc * $object->retained_warranty / 100;
5578 }
5579
5580 $billedWithRetainedWarranty = $object->total_ttc - $retainedWarranty;
5581
5582 print '<tr><td colspan="'.$nbcols.'" align="right">'.$langs->trans("ToPayOn", dol_print_date($object->date_lim_reglement, 'day')).' :</td><td align="right">'.price($billedWithRetainedWarranty).'</td><td>&nbsp;</td></tr>';
5583
5584 // retained warranty
5585 print '<tr><td colspan="'.$nbcols.'" align="right">';
5586 print $langs->trans("RetainedWarranty").' ('.$object->retained_warranty.'%)';
5587 print !empty($object->retained_warranty_date_limit) ? ' '.$langs->trans("ToPayOn", dol_print_date($object->retained_warranty_date_limit, 'day')) : '';
5588 print ' :</td><td align="right">'.price($retainedWarranty).'</td><td>&nbsp;</td></tr>';
5589 }
5590 } else { // Credit note
5591 $resteapayeraffiche = $resteapayer;
5592 $cssforamountpaymentcomplete = 'amountpaymentneutral';
5593
5594 // Total already paid back
5595 print '<tr><td colspan="'.$nbcols.'" class="right">';
5596 print '<span class="opacitymedium">'.$langs->trans('AlreadyPaidBack').'</span>';
5597 print '</td><td class="right"><span class="amount">'.price($sign * $totalpaid).'</span></td><td>&nbsp;</td></tr>';
5598
5599 // Billed
5600 print '<tr><td colspan="'.$nbcols.'" class="right"><span class="opacitymedium">'.$langs->trans("Billed").'</span></td><td class="right">'.price($sign * $object->total_ttc).'</td><td>&nbsp;</td></tr>';
5601
5602 // Remainder to pay back
5603 print '<tr><td colspan="'.$nbcols.'" class="right">';
5604 print '<span class="opacitymedium">'.$langs->trans('RemainderToPayBack');
5605 if ($resteapayeraffiche > 0) {
5606 print ' ('.$langs->trans('NegativeIfExcessRefunded').')';
5607 }
5608 print '</span></td>';
5609 print '<td class="right'.($resteapayeraffiche ? ' amountremaintopayback' : (' '.$cssforamountpaymentcomplete)).'">'.price($sign * $resteapayeraffiche).'</td>';
5610 print '<td class="nowrap">&nbsp;</td></tr>';
5611
5612 // Remainder to pay back Multicurrency
5613 if ($object->multicurrency_code != $conf->currency || $object->multicurrency_tx != 1) {
5614 print '<tr><td colspan="'.$nbcols.'" class="right">';
5615 print '<span class="opacitymedium">'.$langs->trans('RemainderToPayBackMulticurrency');
5616 if ($resteapayeraffiche > 0) {
5617 print ' ('.$langs->trans('NegativeIfExcessRefunded').')';
5618 }
5619 print '</span>';
5620 print '</td>';
5621 print '<td class="right'.($resteapayeraffiche ? ' amountremaintopayback' : (' '.$cssforamountpaymentcomplete)).'">'.(!empty($object->multicurrency_code) ? $object->multicurrency_code : $conf->currency).' '.price(price2num($sign * $object->multicurrency_tx * $resteapayeraffiche, 'MT')).'</td><td>&nbsp;</td></tr>';
5622 }
5623
5624 // Sold credit note
5625 // print '<tr><td colspan="'.$nbcols.'" class="right">'.$langs->trans('TotalTTC').' :</td>';
5626 // print '<td class="right" style="border: 1px solid;" bgcolor="#f0f0f0"><b>'.price($sign *
5627 // $object->total_ttc).'</b></td><td>&nbsp;</td></tr>';
5628 }
5629
5630 print '</table>';
5631 print '</div>';
5632
5633 // Margin Infos
5634 if (isModEnabled('margin')) {
5635 $formmargin->displayMarginInfos($object);
5636 }
5637
5638 print '</div>';
5639 print '</div>';
5640
5641 print '<div class="clearboth"></div><br><br>';
5642
5643 if (getDolGlobalString('MAIN_DISABLE_CONTACTS_TAB')) {
5644 $blocname = 'contacts';
5645 $title = $langs->trans('ContactsAddresses');
5646 include DOL_DOCUMENT_ROOT.'/core/tpl/bloc_showhide.tpl.php';
5647 }
5648
5649 if (getDolGlobalString('MAIN_DISABLE_NOTES_TAB')) {
5650 $blocname = 'notes';
5651 $title = $langs->trans('Notes');
5652 include DOL_DOCUMENT_ROOT.'/core/tpl/bloc_showhide.tpl.php';
5653 }
5654
5655 // Get object lines
5656 $result = $object->getLinesArray();
5657
5658 // Add products/services form
5659 //$forceall = 1;
5660 global $inputalsopricewithtax;
5661 $inputalsopricewithtax = 1;
5662
5663 // Show global modifiers for situation invoices
5664 if (getDolGlobalString('INVOICE_USE_SITUATION')) {
5665 if ($object->situation_cycle_ref && $object->status == 0) {
5666 print '<!-- Area to change globally the situation percent -->'."\n";
5667 print '<div class="div-table-responsive">';
5668
5669 print '<form name="updatealllines" id="updatealllines" action="'.$_SERVER['PHP_SELF'].'?id='.$object->id.'#updatealllines" method="POST">';
5670 print '<input type="hidden" name="token" value="'.newToken().'" />';
5671 print '<input type="hidden" name="action" value="updatealllines" />';
5672 print '<input type="hidden" name="id" value="'.$object->id.'" />';
5673 print '<input type="hidden" name="backtopage" value="'.$backtopage.'">';
5674
5675 print '<table id="tablelines_all_progress" class="noborder noshadow" width="100%">';
5676
5677 print '<tr class="liste_titre nodrag nodrop">';
5678
5679 // Adds a line numbering column
5680 if (getDolGlobalString('MAIN_VIEW_LINE_NUMBER')) {
5681 print '<td align="center" width="5">&nbsp;</td>';
5682 }
5683 print '<td class="minwidth500imp">'.$langs->trans('ModifyAllLines').'</td>';
5684 print '<td class="right">'.$langs->trans('Progress').'</td>';
5685 print '<td>&nbsp;</td>';
5686 print "</tr>\n";
5687
5688 print '<tr class="nodrag nodrop">';
5689 // Adds a line numbering column
5690 if (getDolGlobalString('MAIN_VIEW_LINE_NUMBER')) {
5691 print '<td align="center" width="5">&nbsp;</td>';
5692 }
5693 print '<td>&nbsp;</td>';
5694 print '<td class="nowrap right"><input type="text" size="1" value="" name="all_progress">%</td>';
5695 print '<td class="right"><input type="submit" class="button" name="all_percent" value="Modifier" /></td>';
5696 print '</tr>';
5697
5698 print '</table>';
5699
5700 print '</form>';
5701
5702 print '</div>';
5703 }
5704 }
5705
5706 print ' <form name="addproduct" id="addproduct" action="'.$_SERVER["PHP_SELF"].'?id='.$object->id.'" method="POST">
5707 <input type="hidden" name="token" value="' . newToken().'">
5708 <input type="hidden" name="action" value="' . (($action != 'editline') ? 'addline' : 'updateline').'">
5709 <input type="hidden" name="mode" value="">
5710 <input type="hidden" name="page_y" value="">
5711 <input type="hidden" name="id" value="' . $object->id.'">
5712 <input type="hidden" name="backtopage" value="'.$backtopage.'">
5713 ';
5714
5715 if (!empty($conf->use_javascript_ajax) && $object->status == 0) {
5716 include DOL_DOCUMENT_ROOT.'/core/tpl/ajaxrow.tpl.php';
5717 }
5718
5719 print '<div class="div-table-responsive-no-min">';
5720 print '<table id="tablelines" class="noborder noshadow" width="100%">';
5721
5722 // Show object lines
5723 if (!empty($object->lines)) {
5724 $object->printObjectLines($action, $mysoc, $soc, $lineid, 1);
5725 }
5726
5727 // Form to add new line
5728 if ($object->status == 0 && $usercancreate && $action != 'valid') {
5729 if ($action != 'editline' && $action != 'selectlines') {
5730 // Add free products/services
5731
5732 $parameters = array();
5733 $reshook = $hookmanager->executeHooks('formAddObjectLine', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
5734 if ($reshook < 0) {
5735 setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
5736 }
5737 if (empty($reshook)) {
5738 $object->formAddObjectLine(1, $mysoc, $soc);
5739 }
5740 } else {
5741 $parameters = array();
5742 $reshook = $hookmanager->executeHooks('formEditObjectLine', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
5743 }
5744 }
5745
5746 print "</table>\n";
5747 print "</div>";
5748
5749 print "</form>\n";
5750 }
5751 print dol_get_fiche_end();
5752
5753
5754 // Actions buttons
5755
5756 if ($action != 'prerelance' && $action != 'presend' && $action != 'valid' && $action != 'editline') {
5757 print '<div class="tabsAction">';
5758
5759 $parameters = array();
5760 $reshook = $hookmanager->executeHooks('addMoreActionsButtons', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
5761 if (empty($reshook)) {
5762 $params = array(
5763 'attr' => array(
5764 'class' => 'classfortooltip',
5765 'title' => ''
5766 )
5767 );
5768 // Edit a validated invoice without any payment and not transferred to accounting
5769 if ($object->status == Facture::STATUS_VALIDATED) {
5770 // We check if lines of invoice are not already transferred into accountancy
5771 $ventilExportCompta = $object->getVentilExportCompta();
5772
5773 if ($ventilExportCompta == 0) {
5774 if (getDolGlobalString('INVOICE_CAN_BE_EDITED_EVEN_IF_PAYMENT_DONE') || ($resteapayer == price2num($object->total_ttc, 'MT', 1) && empty($object->paye))) {
5775 if (!$objectidnext && $object->is_last_in_cycle()) {
5776 if ($usercanunvalidate) {
5777 unset($params['attr']['title']);
5778 print dolGetButtonAction($langs->trans('Modify'), '', 'default', $_SERVER['PHP_SELF'].'?facid='.$object->id.'&action=modif&token='.newToken(), '', true, $params);
5779 } else {
5780 $params['attr']['title'] = $langs->trans('NotEnoughPermissions');
5781 print dolGetButtonAction($langs->trans('Modify'), '', 'default', $_SERVER['PHP_SELF'].'?facid='.$object->id.'&action=modif&token='.newToken(), '', false, $params);
5782 }
5783 } elseif (!$object->is_last_in_cycle()) {
5784 $params['attr']['title'] = $langs->trans('NotLastInCycle');
5785 print dolGetButtonAction($langs->trans('Modify'), '', 'default', '#', '', false, $params);
5786 } else {
5787 $params['attr']['title'] = $langs->trans('DisabledBecauseReplacedInvoice');
5788 print dolGetButtonAction($langs->trans('Modify'), '', 'default', '#', '', false, $params);
5789 }
5790 }
5791 } else {
5792 $params['attr']['title'] = $langs->trans('DisabledBecauseDispatchedInBookkeeping');
5793 print dolGetButtonAction($langs->trans('Modify'), '', 'default', '#', '', false, $params);
5794 }
5795 }
5796
5797 $discount = new DiscountAbsolute($db);
5798 $result = $discount->fetch(0, $object->id);
5799
5800 // Reopen an invoice
5802 || ($object->type == Facture::TYPE_CREDIT_NOTE && empty($discount->id))
5803 || ($object->type == Facture::TYPE_DEPOSIT && empty($discount->id))
5804 || ($object->type == Facture::TYPE_SITUATION && empty($discount->id)))
5805 && ($object->status == Facture::STATUS_CLOSED || $object->status == Facture::STATUS_ABANDONED || ($object->status == 1 && $object->paye == 1)) // Condition ($object->status == 1 && $object->paye == 1) should not happened but can be found due to corrupted data
5806 && ((!getDolGlobalString('MAIN_USE_ADVANCED_PERMS') && $usercancreate) || $usercanreopen)) { // A paid invoice (partially or completely)
5807 if ($object->close_code != 'replaced' || (!$objectidnext)) { // Not replaced by another invoice or replaced but the replacement invoice has been deleted
5808 unset($params['attr']['title']);
5809 print dolGetButtonAction($langs->trans('ReOpen'), '', 'default', $_SERVER['PHP_SELF'].'?facid='.$object->id.'&action=reopen&token='.newToken(), '', true, $params);
5810 } else {
5811 $params['attr']['title'] = $langs->trans("DisabledBecauseReplacedInvoice");
5812 print dolGetButtonAction($langs->trans('ReOpen'), '', 'default', '#', '', false, $params);
5813 }
5814 }
5815
5816 // Create contract
5817 if (getDolGlobalString('CONTRACT_CREATE_FROM_INVOICE')) {
5818 if (isModEnabled('contract') && $object->status == Facture::STATUS_VALIDATED) {
5819 $langs->load("contracts");
5820
5821 if ($usercancreatecontract) {
5822 print '<a class="butAction" href="' . DOL_URL_ROOT . '/contrat/card.php?action=create&amp;origin=' . $object->element . '&amp;originid=' . $object->id . '&amp;socid=' . $object->socid . '">' . $langs->trans('AddContract') . '</a>';
5823 }
5824 }
5825 }
5826
5827 // Validate
5828 if ($object->status == Facture::STATUS_DRAFT && count($object->lines) > 0 && ((($object->type == Facture::TYPE_STANDARD || $object->type == Facture::TYPE_REPLACEMENT || $object->type == Facture::TYPE_DEPOSIT || $object->type == Facture::TYPE_PROFORMA || $object->type == Facture::TYPE_SITUATION) && (getDolGlobalString('FACTURE_ENABLE_NEGATIVE') || $object->total_ttc >= 0)) || ($object->type == Facture::TYPE_CREDIT_NOTE && $object->total_ttc <= 0))) {
5829 if ($usercanvalidate) {
5830 unset($params['attr']['title']);
5831 print dolGetButtonAction($langs->trans('Validate'), '', 'default', $_SERVER["PHP_SELF"].'?facid='.$object->id.'&action=valid&token='.newToken(), '', true, $params);
5832 }
5833 }
5834
5835 // Send by mail
5836 if (empty($user->socid)) {
5837 if (($object->status == Facture::STATUS_VALIDATED || $object->status == Facture::STATUS_CLOSED) || getDolGlobalString('FACTURE_SENDBYEMAIL_FOR_ALL_STATUS')) {
5838 if ($objectidnext) {
5839 print '<span class="butActionRefused classfortooltip" title="'.$langs->trans("DisabledBecauseReplacedInvoice").'">'.$langs->trans('SendMail').'</span>';
5840 } else {
5841 if ($usercansend) {
5842 unset($params['attr']['title']);
5843 print dolGetButtonAction('', $langs->trans('SendMail'), 'default', $_SERVER['PHP_SELF'].'?facid='.$object->id.'&action=presend&mode=init#formmailbeforetitle', '', true, $params);
5844 } else {
5845 unset($params['attr']['title']);
5846 print dolGetButtonAction('', $langs->trans('SendMail'), 'default', '#', '', false, $params);
5847 }
5848 }
5849 }
5850 }
5851
5852 // Request a direct debit order
5853 if ($object->status > Facture::STATUS_DRAFT && $object->paye == 0 && $num == 0) {
5854 if ($resteapayer > 0) {
5855 if ($usercancreatewithdrarequest) {
5856 if (!$objectidnext && $object->close_code != 'replaced') { // Not replaced by another invoice
5857 print '<a class="butAction" href="'.DOL_URL_ROOT.'/compta/facture/prelevement.php?facid='.$object->id.'" title="'.dol_escape_htmltag($langs->trans("MakeWithdrawRequest")).'">'.$langs->trans("MakeWithdrawRequest").'</a>';
5858 } else {
5859 print '<span class="butActionRefused classfortooltip" title="'.$langs->trans("DisabledBecauseReplacedInvoice").'">'.$langs->trans('MakeWithdrawRequest').'</span>';
5860 }
5861 } else {
5862 //print '<a class="butActionRefused classfortooltip" href="#" title="'.dol_escape_htmltag($langs->trans("NotEnoughPermissions")).'">'.$langs->trans("MakeWithdrawRequest").'</a>';
5863 }
5864 } else {
5865 //print '<a class="butActionRefused classfortooltip" href="#" title="'.dol_escape_htmltag($langs->trans("AmountMustBePositive")).'">'.$langs->trans("MakeWithdrawRequest").'</a>';
5866 }
5867 }
5868
5869 // POS Ticket
5870 if (isModEnabled('takepos') && $object->module_source == 'takepos') {
5871 $langs->load("cashdesk");
5872 $receipt_url = DOL_URL_ROOT."/takepos/receipt.php";
5873 print '<a target="_blank" rel="noopener noreferrer" class="butAction" href="'.$receipt_url.'?facid='.((int) $object->id).'">'.$langs->trans('POSTicket').'</a>';
5874 }
5875
5876 // Create payment
5877 if ($object->type != Facture::TYPE_CREDIT_NOTE && $object->status == 1 && $object->paye == 0 && $usercanissuepayment) {
5878 if ($objectidnext) {
5879 print '<span class="butActionRefused classfortooltip" title="'.$langs->trans("DisabledBecauseReplacedInvoice").'">'.$langs->trans('DoPayment').'</span>';
5880 } else {
5881 if ($object->type == Facture::TYPE_DEPOSIT && $resteapayer == 0) {
5882 // For down payment, we refuse to receive more than amount to pay.
5883 $params['attr']['title'] = $langs->trans('DisabledBecauseRemainderToPayIsZero');
5884 print dolGetButtonAction($langs->trans('DoPayment'), '', 'default', '#', '', false, $params);
5885 } else {
5886 // Sometimes we can receive more, so we accept to enter more and will offer a button to convert into discount (but it is not a credit note, just a prepayment done)
5887 //print '<a class="butAction" href="'.DOL_URL_ROOT.'/compta/paiement.php?facid='.$object->id.'&amp;action=create&amp;accountid='.$object->fk_account.'">'.$langs->trans('DoPayment').'</a>';
5888 unset($params['attr']['title']);
5889 print dolGetButtonAction($langs->trans('DoPayment'), '', 'default', DOL_URL_ROOT.'/compta/paiement.php?facid='.$object->id.'&amp;action=create'.($object->fk_account > 0 ? '&amp;accountid='.$object->fk_account : ''), '', true, $params);
5890 }
5891 }
5892 }
5893
5894 $sumofpayment = $totalpaid;
5895 $sumofpaymentall = $totalpaid + $totalcreditnotes + $totaldeposits;
5896
5897 // Reverse back money or convert to reduction
5899 // For credit note only
5900 if ($object->type == Facture::TYPE_CREDIT_NOTE && $object->status == Facture::STATUS_VALIDATED && $object->paye == 0 && $usercanissuepayment) {
5901 if ($resteapayer == 0) {
5902 print '<span class="butActionRefused classfortooltip" title="'.$langs->trans("DisabledBecauseRemainderToPayIsZero").'">'.$langs->trans('DoPaymentBack').'</span>';
5903 } else {
5904 print '<a class="butAction" href="'.DOL_URL_ROOT.'/compta/paiement.php?facid='.$object->id.'&amp;action=create&amp;accountid='.$object->fk_account.'">'.$langs->trans('DoPaymentBack').'</a>';
5905 }
5906 }
5907
5908 // For standard invoice with excess received
5909 if (($object->type == Facture::TYPE_STANDARD || $object->type == Facture::TYPE_SITUATION) && $object->status == Facture::STATUS_VALIDATED && empty($object->paye) && $resteapayer < 0 && $usercancreate && empty($discount->id)) {
5910 print '<a class="butAction'.($conf->use_javascript_ajax ? ' reposition' : '').'" href="'.$_SERVER["PHP_SELF"].'?facid='.$object->id.'&action=converttoreduc&token='.newToken().'">'.$langs->trans('ConvertExcessReceivedToReduc').'</a>';
5911 }
5912 // For credit note
5913 if ($object->type == Facture::TYPE_CREDIT_NOTE && $object->status == Facture::STATUS_VALIDATED && $object->paye == 0 && $usercancreate
5914 && (getDolGlobalString('INVOICE_ALLOW_REUSE_OF_CREDIT_WHEN_PARTIALLY_REFUNDED') || $sumofpayment == 0) && $object->total_ht < 0
5915 ) {
5916 print '<a class="butAction classfortooltip'.($conf->use_javascript_ajax ? ' reposition' : '').'" href="'.$_SERVER["PHP_SELF"].'?facid='.$object->id.'&action=converttoreduc&token='.newToken().'" title="'.dol_escape_htmltag($langs->trans("ConfirmConvertToReduc2")).'">'.$langs->trans('ConvertToReduc').'</a>';
5917 }
5918 // For down payment invoice (deposit)
5919
5920 if ($object->type == Facture::TYPE_DEPOSIT && $usercancreate && $object->status > Facture::STATUS_DRAFT && empty($discount->id)) {
5921 // We can close a down payment only if paid amount is same than amount of down payment (by definition). We can bypass this if hidden and unstable option DEPOSIT_AS_CREDIT_AVAILABLE_EVEN_UNPAID is set.
5922 if (price2num($object->total_ttc, 'MT') == price2num($sumofpaymentall, 'MT') || getDolGlobalInt('DEPOSIT_AS_CREDIT_AVAILABLE_EVEN_UNPAID') || ($object->type == Facture::STATUS_ABANDONED && in_array($object->close_code, array('bankcharge', 'discount_vat', 'other')))) {
5923 print '<a class="butAction'.($conf->use_javascript_ajax ? ' reposition' : '').'" href="'.$_SERVER["PHP_SELF"].'?facid='.$object->id.'&action=converttoreduc&token='.newToken().'">'.$langs->trans('ConvertToReduc').'</a>';
5924 } else {
5925 print '<span class="butActionRefused classfortooltip" title="'.$langs->trans("AmountPaidMustMatchAmountOfDownPayment").'">'.$langs->trans('ConvertToReduc').'</span>';
5926 }
5927 }
5928 }
5929
5930 // Classify paid
5931 if ($object->status == Facture::STATUS_VALIDATED && $object->paye == 0 && $usercanissuepayment && (
5932 ($object->type != Facture::TYPE_CREDIT_NOTE && $object->type != Facture::TYPE_DEPOSIT && ($resteapayer <= 0 || (getDolGlobalString('INVOICE_CAN_SET_PAID_EVEN_IF_PARTIALLY_PAID') && $object->total_ttc == $resteapayer))) ||
5933 ($object->type == Facture::TYPE_CREDIT_NOTE && $resteapayer >= 0) ||
5934 ($object->type == Facture::TYPE_DEPOSIT && $object->total_ttc > 0)
5935 )
5936 ) {
5937 if ($object->type == Facture::TYPE_DEPOSIT && price2num($object->total_ttc, 'MT') != price2num($sumofpaymentall, 'MT')) {
5938 // We can close a down payment only if paid amount is same than amount of down payment (by definition)
5939 $params['attr']['title'] = $langs->trans('AmountPaidMustMatchAmountOfDownPayment');
5940 print dolGetButtonAction($langs->trans('ClassifyPaid'), '', 'default', '#', '', false, $params);
5941 } else {
5942 unset($params['attr']['title']);
5943 print dolGetButtonAction($langs->trans('ClassifyPaid'), '', 'default', $_SERVER['PHP_SELF'].'?facid='.$object->id.'&action=paid&token='.newToken(), '', true, $params);
5944 }
5945 }
5946
5947 // Classify 'closed not completely paid' (possible if validated and not yet filed paid)
5948 if ($object->status == Facture::STATUS_VALIDATED && $object->paye == 0 && $resteapayer > 0 && (!getDolGlobalString('INVOICE_CAN_SET_PAID_EVEN_IF_PARTIALLY_PAID') || $resteapayer != $object->total_ttc) && $usercanissuepayment) {
5949 if ($totalpaid > 0 || $totalcreditnotes > 0) {
5950 // If one payment or one credit note was linked to this invoice
5951 print '<a class="butAction'.($conf->use_javascript_ajax ? ' reposition' : '').'" href="'.$_SERVER['PHP_SELF'].'?facid='.$object->id.'&action=paid&token='.newToken().'">'.$langs->trans('ClassifyPaidPartially').'</a>';
5952 } else {
5953 if (!getDolGlobalString('INVOICE_CAN_NEVER_BE_CANCELED')) {
5954 if ($objectidnext) {
5955 print '<span class="butActionRefused classfortooltip" title="'.$langs->trans("DisabledBecauseReplacedInvoice").'">'.$langs->trans('ClassifyCanceled').'</span>';
5956 } else {
5957 print '<a class="butAction'.($conf->use_javascript_ajax ? ' reposition' : '').'" href="'.$_SERVER['PHP_SELF'].'?facid='.$object->id.'&amp;action=canceled">'.$langs->trans('ClassifyCanceled').'</a>';
5958 }
5959 }
5960 }
5961 }
5962
5963 // Create a credit note
5964 if (($object->type == Facture::TYPE_STANDARD || ($object->type == Facture::TYPE_DEPOSIT && !getDolGlobalString('FACTURE_DEPOSITS_ARE_JUST_PAYMENTS')) || $object->type == Facture::TYPE_PROFORMA) && $object->status > 0 && $usercancreate) {
5965 if (!$objectidnext) {
5966 print '<a class="butAction" href="'.$_SERVER['PHP_SELF'].'?socid='.$object->socid.'&amp;fac_avoir='.$object->id.'&amp;action=create&amp;type=2'.($object->fk_project > 0 ? '&amp;projectid='.$object->fk_project : '').($object->entity > 0 ? '&amp;originentity='.$object->entity : '').'">'.$langs->trans("CreateCreditNote").'</a>';
5967 }
5968 }
5969
5970 // For situation invoice with excess received
5971 if ($object->status > Facture::STATUS_DRAFT
5973 && ($object->total_ttc - $totalpaid - $totalcreditnotes - $totaldeposits) > 0
5974 && $usercancreate
5975 && !$objectidnext
5976 && $object->is_last_in_cycle()
5977 && getDolGlobalInt('INVOICE_USE_SITUATION_CREDIT_NOTE')
5978 ) {
5979 if ($usercanunvalidate) {
5980 print '<a class="butAction" href="'.$_SERVER['PHP_SELF'].'?socid='.$object->socid.'&amp;fac_avoir='.$object->id.'&amp;invoiceAvoirWithLines=1&amp;action=create&amp;type=2'.($object->fk_project > 0 ? '&amp;projectid='.$object->fk_project : '').'">'.$langs->trans("CreateCreditNote").'</a>';
5981 } else {
5982 print '<span class="butActionRefused classfortooltip" title="'.$langs->trans("NotEnoughPermissions").'">'.$langs->trans("CreateCreditNote").'</span>';
5983 }
5984 }
5985
5986 // Clone
5987 if (($object->type == Facture::TYPE_STANDARD || $object->type == Facture::TYPE_DEPOSIT || $object->type == Facture::TYPE_PROFORMA) && $usercancreate) {
5988 unset($params['attr']['title']);
5989 print dolGetButtonAction($langs->trans('ToClone'), '', 'default', $_SERVER['PHP_SELF'].'?facid='.$object->id.'&action=clone&object=invoice&token='.newToken(), '', true, $params);
5990 }
5991
5992 // Clone as predefined / Create template
5993 if (($object->type == Facture::TYPE_STANDARD || $object->type == Facture::TYPE_DEPOSIT || $object->type == Facture::TYPE_PROFORMA) && $object->status == 0 && $usercancreate) {
5994 if (!$objectidnext && count($object->lines) > 0) {
5995 unset($params['attr']['title']);
5996 print dolGetButtonAction($langs->trans('ChangeIntoRepeatableInvoice'), '', 'default', DOL_URL_ROOT.'/compta/facture/card-rec.php?facid='.$object->id.'&amp;action=create', '', true, $params);
5997 }
5998 }
5999
6000 // Remove situation from cycle
6001 if (in_array($object->status, array(Facture::STATUS_CLOSED, Facture::STATUS_VALIDATED))
6003 && $usercancreate
6004 && !$objectidnext
6005 && $object->situation_counter > 1
6006 && $object->is_last_in_cycle()
6007 && $usercanunvalidate
6008 ) {
6009 if (($object->total_ttc - $totalcreditnotes) == 0) {
6010 print '<a id="butSituationOut" class="butAction" href="'.$_SERVER['PHP_SELF'].'?facid='.$object->id.'&amp;action=situationout">'.$langs->trans("RemoveSituationFromCycle").'</a>';
6011 } else {
6012 print '<a id="butSituationOutRefused" class="butActionRefused classfortooltip" href="#" title="'.$langs->trans("DisabledBecauseNotEnouthCreditNote").'" >'.$langs->trans("RemoveSituationFromCycle").'</a>';
6013 }
6014 }
6015
6016 // Create next situation invoice
6017 if ($usercancreate && ($object->type == 5) && ($object->status == 1 || $object->status == 2)) {
6018 if ($object->is_last_in_cycle() && $object->situation_final != 1) {
6019 print '<a class="butAction" href="'.$_SERVER['PHP_SELF'].'?action=create&amp;type=5&amp;origin=facture&amp;originid='.$object->id.'&amp;socid='.$object->socid.'" >'.$langs->trans('CreateNextSituationInvoice').'</a>';
6020 } elseif (!$object->is_last_in_cycle()) {
6021 print '<a class="butActionRefused classfortooltip" href="#" title="'.$langs->trans("DisabledBecauseNotLastInCycle").'">'.$langs->trans('CreateNextSituationInvoice').'</a>';
6022 } else {
6023 print '<a class="butActionRefused classfortooltip" href="#" title="'.$langs->trans("DisabledBecauseFinal").'">'.$langs->trans('CreateNextSituationInvoice').'</a>';
6024 }
6025 }
6026
6027 // Delete
6028 $isErasable = $object->is_erasable();
6029 $htmltooltip = '';
6030 if ($isErasable == -4) {
6031 $htmltooltip = $langs->trans('DisabledBecausePayments');
6032 } elseif ($isErasable == -3) {
6033 $htmltooltip = $langs->trans('DisabledBecauseNotLastSituationInvoice');
6034 } elseif ($isErasable == -2) {
6035 $htmltooltip = $langs->trans('DisabledBecauseNotLastInvoice');
6036 } elseif ($isErasable == -1) {
6037 $htmltooltip = $langs->trans('DisabledBecauseDispatchedInBookkeeping');
6038 } elseif ($isErasable <= 0) { // Any other cases
6039 $htmltooltip = $langs->trans('DisabledBecauseNotErasable');
6040 } elseif ($objectidnext) {
6041 $htmltooltip = $langs->trans('DisabledBecauseReplacedInvoice');
6042 }
6043 if ($usercandelete || ($usercancreate && $isErasable == 1)) { // isErasable = 1 means draft with temporary ref (draft can always be deleted with no need of permissions)
6044 $enableDelete = false;
6045 $deleteHref = '#';
6046 if ($isErasable > 0 && ! $objectidnext) {
6047 $deleteHref = $_SERVER["PHP_SELF"].'?facid='.$object->id.'&action=delete&token='.newToken();
6048 $enableDelete = true;
6049 }
6050 unset($params['attr']['title']);
6051 print dolGetButtonAction($htmltooltip, $langs->trans('Delete'), 'delete', $deleteHref, '', $enableDelete, $params);
6052 } else {
6053 unset($params['attr']['title']);
6054 print dolGetButtonAction($htmltooltip, $langs->trans('Delete'), 'delete', '#', '', false);
6055 }
6056 }
6057 print '</div>';
6058 }
6059
6060 // Select mail models is same action as presend
6061 if (GETPOST('modelselected', 'alpha')) {
6062 $action = 'presend';
6063 }
6064 if ($action != 'prerelance' && $action != 'presend') {
6065 print '<div class="fichecenter"><div class="fichehalfleft">';
6066 print '<a name="builddoc"></a>'; // ancre
6067
6068 // Generated documents
6069 $filename = dol_sanitizeFileName($object->ref);
6070 $filedir = $conf->invoice->multidir_output[$object->entity].'/'.dol_sanitizeFileName($object->ref);
6071 $urlsource = $_SERVER['PHP_SELF'].'?facid='.$object->id;
6072 $genallowed = $usercanread;
6073 $delallowed = $usercancreate;
6074
6075 print $formfile->showdocuments(
6076 'facture',
6077 $filename,
6078 $filedir,
6079 $urlsource,
6080 $genallowed,
6081 $delallowed,
6082 $object->model_pdf,
6083 1,
6084 0,
6085 0,
6086 28,
6087 0,
6088 '',
6089 '',
6090 '',
6091 $soc->default_lang,
6092 '',
6093 $object,
6094 0,
6095 'remove_file_comfirm'
6096 );
6097
6098 $somethingshown = $formfile->numoffiles;
6099
6100 // Show links to link elements
6101 $linktoelem = $form->showLinkToObjectBlock($object, array(), array('invoice'));
6102
6103 $compatibleImportElementsList = false;
6104 if ($usercancreate
6105 && $object->status == Facture::STATUS_DRAFT
6107 $compatibleImportElementsList = array('commande', 'propal'); // import from linked elements
6108 }
6109 $somethingshown = $form->showLinkedObjectBlock($object, $linktoelem, $compatibleImportElementsList);
6110
6111 // Show online payment link
6112 // The list can be complete by the hook 'doValidatePayment' executed inside getValidOnlinePaymentMethods()
6113 include_once DOL_DOCUMENT_ROOT.'/core/lib/payments.lib.php';
6114 $validpaymentmethod = getValidOnlinePaymentMethods('');
6115 $useonlinepayment = count($validpaymentmethod);
6116
6117 if ($object->status != Facture::STATUS_DRAFT && $useonlinepayment) {
6118 print '<br><!-- Link to pay -->'."\n";
6119 require_once DOL_DOCUMENT_ROOT.'/core/lib/payments.lib.php';
6120 print showOnlinePaymentUrl('invoice', $object->ref).'<br>';
6121 }
6122
6123 print '</div><div class="fichehalfright">';
6124
6125 $MAXEVENT = 10;
6126
6127 $morehtmlcenter = dolGetButtonTitle($langs->trans('SeeAll'), '', 'fa fa-bars imgforviewmode', DOL_URL_ROOT.'/compta/facture/agenda.php?id='.$object->id);
6128
6129 // List of actions on element
6130 include_once DOL_DOCUMENT_ROOT.'/core/class/html.formactions.class.php';
6131 $formactions = new FormActions($db);
6132 $somethingshown = $formactions->showactions($object, 'invoice', $socid, 1, '', $MAXEVENT, '', $morehtmlcenter); // Show all action for thirdparty
6133
6134 print '</div></div>';
6135 }
6136
6137
6138 // Presend form
6139 $modelmail = 'facture_send';
6140 $defaulttopic = 'SendBillRef';
6141 $diroutput = $conf->invoice->multidir_output[$object->entity];
6142 $trackid = 'inv'.$object->id;
6143
6144 include DOL_DOCUMENT_ROOT.'/core/tpl/card_presend.tpl.php';
6145}
6146
6147// End of page
6148llxFooter();
6149$db->close();
if( $user->socid > 0) if(! $user->hasRight('accounting', 'chartofaccount')) $object
Definition card.php:58
ajax_combobox($htmlname, $events=array(), $minLengthToAutocomplete=0, $forcefocus=0, $widthTypeOfAutocomplete='resolve', $idforemptyvalue='-1', $morecss='')
Convert a html select field into an ajax combobox.
Definition ajax.lib.php:456
if(!defined('NOREQUIRESOC')) if(!defined( 'NOREQUIRETRAN')) if(!defined('NOTOKENRENEWAL')) if(!defined( 'NOREQUIREMENU')) if(!defined('NOREQUIREHTML')) if(!defined( 'NOREQUIREAJAX')) llxHeader()
Empty header.
Definition wrapper.php:55
llxFooter()
Empty footer.
Definition wrapper.php:69
Class to manage bank accounts.
Class to manage accounting journals.
Class to manage absolute discounts.
Class to manage a WYSIWYG editor.
Class to manage warehouses.
Class to manage shipments.
Class to manage standard extra fields.
Class to manage invoices.
const TYPE_REPLACEMENT
Replacement invoice.
const STATUS_DRAFT
Draft status.
const TYPE_STANDARD
Standard invoice.
const TYPE_SITUATION
Situation invoice.
const TYPE_PROFORMA
Proforma invoice (should not be used.
const STATUS_VALIDATED
Validated (need to be paid)
const TYPE_DEPOSIT
Deposit invoice.
const STATUS_ABANDONED
Classified abandoned and no payment done.
const TYPE_CREDIT_NOTE
Credit note invoice.
const STATUS_CLOSED
Classified paid.
Class to manage invoice lines.
Class to manage invoice templates.
Class to manage building of HTML components.
Class to offer components to list and upload files.
Class to manage generation of HTML components Only common components must be here.
Class permettant la generation de composants html autre Only common components are here.
Class permettant la generation de composants html autre Only common components are here.
Class with static methods for building HTML components related to products Only components common to ...
Class to manage building of HTML components.
static liste_modeles($db, $maxfilenamelength=0)
Return list of active generation modules.
static getIdAndTxFromCode($dbs, $code, $date_document='')
Get id and rate of currency from code.
Class to manage the table of subscription to notifications.
Class to manage payments of customer invoices.
Class ProductCombination Used to represent the relation between a product and one of its variants.
Class to manage products or services.
const TYPE_PRODUCT
Regular product.
Class to manage projects.
Class to manage third parties objects (customers, suppliers, prospects...)
Class to manage translations.
Class to manage Dolibarr users.
getCountry($searchkey, $withcode='', $dbtouse=null, $outputlangs=null, $entconv=1, $searchlabel='')
Return country label, code or id from an id, code or label.
dol_get_last_hour($date, $gm='tzserver')
Return GMT time for last hour of a given GMT date (it replaces hours, min and second part to 23:59:59...
Definition date.lib.php:641
dol_time_plus_duree($time, $duration_value, $duration_unit, $ruleforendofmonth=0)
Add a delay to a date.
Definition date.lib.php:125
dol_stringtotime($string, $gm=1)
Convert a string date into a GM Timestamps date Warning: YYYY-MM-DDTHH:MM:SS+02:00 (RFC3339) is not s...
Definition date.lib.php:427
print $script_file $mode $langs defaultlang(is_numeric($duration_value) ? " delay=". $duration_value :"").(is_numeric($duration_value2) ? " after cd cd cd description as description
Only used if Module[ID]Desc translation string is not found.
dol_mktime($hour, $minute, $second, $month, $day, $year, $gm='auto', $check=1)
Return a timestamp date built from detailed information (by default a local PHP server timestamp) Rep...
load_fiche_titre($title, $morehtmlright='', $picto='generic', $pictoisfullpath=0, $id='', $morecssontable='', $morehtmlcenter='')
Load a title with picto.
img_warning($titlealt='default', $moreatt='', $morecss='pictowarning')
Show warning logo.
img_delete($titlealt='default', $other='class="pictodelete"', $morecss='')
Show delete logo.
img_picto($titlealt, $picto, $moreatt='', $pictoisfullpath=0, $srconly=0, $notitle=0, $alt='', $morecss='', $marginleftonlyshort=2)
Show picto whatever it's its name (generic function)
GETPOSTINT($paramname, $method=0)
Return the value of a $_GET or $_POST supervariable, converted into integer.
dol_get_fiche_head($links=array(), $active='', $title='', $notab=0, $picto='', $pictoisfullpath=0, $morehtmlright='', $morecss='', $limittoshow=0, $moretabssuffix='', $dragdropfile=0)
Show tabs of a record.
price2num($amount, $rounding='', $option=0)
Function that return a number with universal decimal format (decimal separator is '.
dolGetButtonTitle($label, $helpText='', $iconClass='fa fa-file', $url='', $id='', $status=1, $params=array())
Function dolGetButtonTitle : this kind of buttons are used in title in list.
dol_get_fiche_end($notab=0)
Return tab footer of a card.
price($amount, $form=0, $outlangs='', $trunc=1, $rounding=-1, $forcerounding=-1, $currency_code='')
Function to format a value into an amount for visual output Function used into PDF and HTML pages.
GETPOSTISARRAY($paramname, $method=0)
Return true if the parameter $paramname is submit from a POST OR GET as an array.
dol_now($mode='auto')
Return date for now.
getDolGlobalInt($key, $default=0)
Return a Dolibarr global constant int value.
dol_print_date($time, $format='', $tzoutput='auto', $outputlangs=null, $encodetooutput=false)
Output date in a string format according to outputlangs (or langs if not defined).
if(!function_exists( 'dol_getprefix')) dol_include_once($relpath, $classname='')
Make an include_once using default root and alternate root if it fails.
newToken()
Return the value of token currently saved into session with name 'newtoken'.
dol_clone($object, $native=0)
Create a clone of instance of object (new instance with same value for each properties) With native =...
dolGetButtonAction($label, $text='', $actionType='default', $url='', $id='', $userRight=1, $params=array())
Function dolGetButtonAction.
dol_htmlcleanlastbr($stringtodecode)
This function remove all ending and br at end.
dol_concatdesc($text1, $text2, $forxml=false, $invert=false)
Concat 2 descriptions with a new line between them (second operand after first one with appropriate n...
GETPOST($paramname, $check='alphanohtml', $method=0, $filter=null, $options=null, $noreplace=0)
Return value of a param into GET or POST supervariable.
GETPOSTFLOAT($paramname, $rounding='')
Return the value of a $_GET or $_POST supervariable, converted into float.
setEventMessages($mesg, $mesgs, $style='mesgs', $messagekey='', $noduplicate=0)
Set event messages in dol_events session object.
dol_sanitizeFileName($str, $newstr='_', $unaccent=1)
Clean a string to use it as a file name.
dol_print_error($db=null, $error='', $errors=null)
Displays error message system with all the information to facilitate the diagnosis and the escalation...
getDolGlobalString($key, $default='')
Return dolibarr global constant string value.
info_admin($text, $infoonimgalt=0, $nodiv=0, $admin='1', $morecss='hideonsmartphone', $textfordropdown='', $picto='')
Show information in HTML for admin users or standard users.
img_edit($titlealt='default', $float=0, $other='')
Show logo edit/modify fiche.
get_default_tva(Societe $thirdparty_seller, Societe $thirdparty_buyer, $idprod=0, $idprodfournprice=0)
Function that return vat rate of a product line (according to seller, buyer and product vat rate) VAT...
getDictionaryValue($tablename, $field, $id, $checkentity=false, $rowidfield='rowid')
Return the value of a filed into a dictionary for the record $id.
get_localtax($vatrate, $local, $thirdparty_buyer=null, $thirdparty_seller=null, $vatnpr=0)
Return localtax rate for a particular vat, when selling a product with vat $vatrate,...
dol_syslog($message, $level=LOG_INFO, $ident=0, $suffixinfilename='', $restricttologhandler='', $logcontext=null)
Write log message into outputs.
dol_getdate($timestamp, $fast=false, $forcetimezone='')
Return an array with locale date info.
dol_escape_htmltag($stringtoescape, $keepb=0, $keepn=0, $noescapetags='', $escapeonlyhtmltags=0, $cleanalsojavascript=0)
Returns text escaped for inclusion in HTML alt or title or value tags, or into values of HTML input f...
facture_prepare_head($object)
Initialize the array of tabs for customer invoice.
calcul_price_total($qty, $pu, $remise_percent_ligne, $txtva, $uselocaltax1_rate, $uselocaltax2_rate, $remise_percent_global, $price_base_type, $info_bits, $type, $seller='', $localtaxes_array=[], $progress=100, $multicurrency_tx=1, $pu_devise=0, $multicurrency_code='')
Calculate totals (net, vat, ...) of a line.
Definition price.lib.php:88
if(preg_match('/crypted:/i', $dolibarr_main_db_pass)||!empty($dolibarr_main_db_encrypted_pass)) $conf db type
Definition repair.php:137
restrictedArea(User $user, $features, $object=0, $tableandshare='', $feature2='', $dbt_keyfield='fk_soc', $dbt_select='rowid', $isdraft=0, $mode=0)
Check permissions of a user to show a page and an object.
accessforbidden($message='', $printheader=1, $printfooter=1, $showonlymessage=0, $params=null)
Show a message to say access is forbidden and stop program.
publicphonebutton2 phonegreen basiclayout basiclayout TotalHT VATCode TotalVAT TotalLT1 TotalLT2 TotalTTC TotalHT clearboth nowraponall TAKEPOS_SHOW_SUBPRICE right right right takeposterminal SELECT e e e e e statut
Definition invoice.php:2010
publicphonebutton2 phonegreen basiclayout basiclayout TotalHT VATCode TotalVAT TotalLT1 TotalLT2 TotalTTC TotalHT clearboth nowraponall TAKEPOS_SHOW_SUBPRICE right right right takeposterminal SELECT e rowid
Definition invoice.php:2010