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