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