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