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