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