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