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