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