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