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