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