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