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