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