dolibarr 23.0.3
card-rec.php
Go to the documentation of this file.
1<?php
2/* Copyright (C) 2002-2003 Rodolphe Quiedeville <rodolphe@quiedeville.org>
3 * Copyright (C) 2004-2023 Laurent Destailleur <eldy@users.sourceforge.net>
4 * Copyright (C) 2005-2012 Regis Houssin <regis.houssin@inodbox.com>
5 * Copyright (C) 2013 Florian Henry <florian.henry@open-concept.pro>
6 * Copyright (C) 2013-2023 Juanjo Menent <jmenent@2byte.es>
7 * Copyright (C) 2015 Jean-François Ferry <jfefe@aternatik.fr>
8 * Copyright (C) 2012 Cedric Salvador <csalvador@gpcsolutions.fr>
9 * Copyright (C) 2015 Alexandre Spangaro <aspangaro@open-dsi.fr>
10 * Copyright (C) 2016 Meziane Sof <virtualsof@yahoo.fr>
11 * Copyright (C) 2017-2025 Frédéric France <frederic.france@free.fr>
12 * Copyright (C) 2023 Nick Fragoulis
13 * Copyright (C) 2024-2025 MDW <mdeweerd@users.noreply.github.com>
14 *
15 * This program is free software; you can redistribute it and/or modify
16 * it under the terms of the GNU General Public License as published by
17 * the Free Software Foundation; either version 3 of the License, or
18 * (at your option) any later version.
19 *
20 * This program is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 * GNU General Public License for more details.
24 *
25 * You should have received a copy of the GNU General Public License
26 * along with this program. If not, see <https://www.gnu.org/licenses/>.
27 */
28
35// Load Dolibarr environment
36require '../../main.inc.php';
45require_once DOL_DOCUMENT_ROOT.'/compta/facture/class/facture-rec.class.php';
46require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php';
47require_once DOL_DOCUMENT_ROOT.'/core/class/html.formother.class.php';
48if (isModEnabled('project')) {
49 include_once DOL_DOCUMENT_ROOT.'/projet/class/project.class.php';
50}
51require_once DOL_DOCUMENT_ROOT.'/core/class/html.formprojet.class.php';
52require_once DOL_DOCUMENT_ROOT.'/core/class/doleditor.class.php';
53require_once DOL_DOCUMENT_ROOT.'/core/lib/invoice.lib.php';
54require_once DOL_DOCUMENT_ROOT.'/core/class/extrafields.class.php';
55
56// Load translation files required by the page
57$langs->loadLangs(array('bills', 'companies', 'compta', 'admin', 'other', 'products', 'banks'));
58
59$action = GETPOST('action', 'aZ09');
60$massaction = GETPOST('massaction', 'alpha');
61$show_files = GETPOSTINT('show_files');
62$confirm = GETPOST('confirm', 'alpha');
63$cancel = GETPOST('cancel', 'alpha');
64$toselect = GETPOST('toselect', 'array:int');
65$contextpage = GETPOST('contextpage', 'aZ') ? GETPOST('contextpage', 'aZ') : 'invoicetemplatelist'; // To manage different context of search
66$backtopage = GETPOST('backtopage', 'alpha'); // if not set, a default page will be used
67$backtopageforcancel = GETPOST('backtopageforcancel', 'alpha'); // if not set, $backtopage will be used
68
69
70$id = (GETPOSTINT('facid') ? GETPOSTINT('facid') : GETPOSTINT('id'));
71$lineid = GETPOSTINT('lineid');
72$ref = GETPOST('ref', 'alpha');
73$socid = 0;
74if ($user->socid) {
75 $socid = $user->socid;
76}
77$objecttype = 'facture_rec';
78if ($action == "create" || $action == "add") {
79 $objecttype = '';
80}
81$projectid = GETPOSTINT('projectid');
82
83$year_date_when = GETPOST('year_date_when');
84$month_date_when = GETPOST('month_date_when');
85$selectedLines = GETPOST('toselect', 'array:int');
86
87$limit = GETPOSTINT('limit') ? GETPOSTINT('limit') : $conf->liste_limit;
88$sortfield = GETPOST('sortfield', 'aZ09comma');
89$sortorder = GETPOST('sortorder', 'aZ09comma');
90$page = GETPOSTISSET('pageplusone') ? (GETPOSTINT('pageplusone') - 1) : GETPOSTINT("page");
91if (empty($page) || $page == -1) {
92 $page = 0;
93} // If $page is not defined, or '' or -1
94$offset = $limit * $page;
95if (!$sortorder) {
96 $sortorder = 'DESC';
97}
98if (!$sortfield) {
99 $sortfield = 'f.titre';
100}
101$pageprev = $page - 1;
102$pagenext = $page + 1;
103
104$object = new FactureRec($db);
105if (($id > 0 || $ref) && $action != 'create' && $action != 'add') {
106 $ret = $object->fetch($id, $ref);
107 if ($ret < 0) {
108 dol_print_error($db, $object->error, $object->errors);
109 exit;
110 } elseif (! $ret) {
111 setEventMessages($langs->trans("ErrorRecordNotFound"), null, 'errors');
112 }
113}
114
115// Initialize a technical object to manage hooks of page. Note that conf->hooks_modules contains an array of hook context
116$hookmanager->initHooks(array('invoicereccard', 'globalcard'));
117$extrafields = new ExtraFields($db);
118
119// fetch optionals attributes and labels
120$extrafields->fetch_name_optionals_label($object->table_element);
121
122$search_array_options = $extrafields->getOptionalsFromPost($object->table_element, '', 'search_');
123
124$permissiontoadd = $user->hasRight('facture', 'creer');
125$permissionnote = $user->hasRight('facture', 'creer'); // Used by the include of actions_setnotes.inc.php
126$permissiondellink = $user->hasRight('facture', 'creer'); // Used by the include of actions_dellink.inc.php
127$permissiontoedit = $user->hasRight('facture', 'creer'); // Used by the include of actions_lineupdonw.inc.php
128$permissiontoeditextra = $permissiontoadd;
129if (GETPOST('attribute', 'aZ09') && isset($extrafields->attributes[$object->table_element]['perms'][GETPOST('attribute', 'aZ09')])) {
130 // For action 'update_extras', is there a specific permission set for the attribute to update
131 $permissiontoeditextra = dol_eval((string) $extrafields->attributes[$object->table_element]['perms'][GETPOST('attribute', 'aZ09')]);
132}
133
134$usercanread = $user->hasRight('facture', 'lire');
135$usercancreate = $user->hasRight('facture', 'creer');
136$usercanissuepayment = $user->hasRight('facture', 'paiement');
137$usercandelete = $user->hasRight('facture', 'supprimer');
138
139// Advanced permissions
140$usercanvalidate = ((!getDolGlobalString('MAIN_USE_ADVANCED_PERMS') && $usercancreate) || (getDolGlobalString('MAIN_USE_ADVANCED_PERMS') && $user->hasRight('facture', 'invoice_advance', 'validate')));
141$usercansend = (!getDolGlobalString('MAIN_USE_ADVANCED_PERMS') || $user->hasRight('facture', 'invoice_advance', 'send'));
142$usercanreopen = (!getDolGlobalString('MAIN_USE_ADVANCED_PERMS') || $user->hasRight('facture', 'invoice_advance', 'reopen'));
143$usercanunvalidate = ((!getDolGlobalString('MAIN_USE_ADVANCED_PERMS') && !empty($usercancreate)) || (getDolGlobalString('MAIN_USE_ADVANCED_PERMS') && $user->hasRight('facture', 'invoice_advance', 'unvalidate')));
144$usermustrespectpricemin = ((getDolGlobalString('MAIN_USE_ADVANCED_PERMS') && !$user->hasRight('produit', 'ignore_price_min_advance')) || !getDolGlobalString('MAIN_USE_ADVANCED_PERMS'));
145
146// Other permissions
147$usercanproductignorepricemin = ((getDolGlobalString('MAIN_USE_ADVANCED_PERMS') && !$user->hasRight('produit', 'ignore_price_min_advance')) || !getDolGlobalString('MAIN_USE_ADVANCED_PERMS'));
148$usercancreatemargin = $user->hasRight("margins", "creer");
149$usercanreadallmargin = $user->hasRight("margins", "liretous");
150$usercancreatewithdrarequest = $user->hasRight("prelevement", "bons", "creer");
151
152$now = dol_now();
153
154$error = 0;
155
156// Security check
157$result = restrictedArea($user, 'facture', $object->id, $objecttype);
158
159
160/*
161 * Actions
162 */
163
164if (GETPOST('cancel', 'alpha')) {
165 if ($action != 'updateline') {
166 $action = 'list';
167 $massaction = '';
168 } else {
169 $action = '';
170 $cancel = '';
171 }
172}
173if (!GETPOST('confirmmassaction', 'alpha') && $massaction != 'presend' && $massaction != 'confirm_presend') {
174 $massaction = '';
175}
176
177$parameters = array('socid' => $socid);
178$reshook = $hookmanager->executeHooks('doActions', $parameters, $object, $action); // Note that $action and $object may have been modified by some hooks
179if ($reshook < 0) {
180 setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
181}
182
183if (empty($reshook)) {
184 $backurlforlist = DOL_URL_ROOT.'/compta/facture/invoicetemplate_list.php';
185
186 if (empty($backtopage) || ($cancel && empty($id))) {
187 if (empty($backtopage) || ($cancel && strpos($backtopage, '__ID__'))) {
188 if (empty($id) && (($action != 'add' && $action != 'create') || $cancel)) {
189 $backtopage = $backurlforlist;
190 } else {
191 $backtopage = DOL_URL_ROOT.'/compta/facture/invoicetemplate_list.php?id='.((!empty($id) && $id > 0) ? $id : '__ID__');
192 }
193 }
194 }
195
196 // include DOL_DOCUMENT_ROOT.'/core/actions_addupdatedelete.inc.php';
197 if ($cancel) {
198 /*var_dump($cancel);var_dump($backtopage);var_dump($backtopageforcancel);exit;*/
199 if (!empty($backtopageforcancel)) {
200 header("Location: ".$backtopageforcancel);
201 exit;
202 } elseif (!empty($backtopage)) {
203 header("Location: ".$backtopage);
204 exit;
205 }
206 $action = '';
207 }
208
209 // Selection of new fields
210 include DOL_DOCUMENT_ROOT.'/core/actions_changeselectedfields.inc.php';
211
212 // Set note
213 include DOL_DOCUMENT_ROOT.'/core/actions_setnotes.inc.php'; // Must be 'include', not 'include_once'
214
215 include DOL_DOCUMENT_ROOT.'/core/actions_dellink.inc.php'; // Must be 'include', not 'include_once'
216
217 include DOL_DOCUMENT_ROOT.'/core/actions_lineupdown.inc.php'; // Must be 'include', not 'include_once'
218
219 // Mass actions
220 /*$objectclass='MyObject';
221 $objectlabel='MyObject';
222 $uploaddir = $conf->mymodule->dir_output;
223 include DOL_DOCUMENT_ROOT.'/core/actions_massactions.inc.php';*/
224
225 // Create predefined invoice
226 if ($action == 'add' && $usercancreate) {
227 if (!GETPOST('title', 'alphanohtml')) {
228 setEventMessages($langs->transnoentities("ErrorFieldRequired", $langs->trans("Title")), null, 'errors');
229 $action = "create";
230 $error++;
231 }
232
233 $frequency = GETPOSTINT('frequency');
234 $reyear = GETPOSTINT('reyear');
235 $remonth = GETPOSTINT('remonth');
236 $reday = GETPOSTINT('reday');
237 $rehour = GETPOSTINT('rehour');
238 $remin = GETPOSTINT('remin');
239 $nb_gen_max = GETPOSTINT('nb_gen_max');
240 //if (empty($nb_gen_max)) $nb_gen_max =0;
241
242 if (GETPOSTINT('frequency')) {
243 if (empty($reyear) || empty($remonth) || empty($reday)) {
244 setEventMessages($langs->transnoentities("ErrorFieldRequired", $langs->trans("Date")), null, 'errors');
245 $action = "create";
246 $error++;
247 }
248 /*if ($nb_gen_max === '') {
249 setEventMessages($langs->transnoentities("ErrorFieldRequired", $langs->trans("MaxPeriodNumber")), null, 'errors');
250 $action = "create";
251 $error++;
252 }*/
253 }
254
255 if (!$error) {
256 $object->subtype = GETPOSTINT('subtype');
257 $object->title = GETPOST('title', 'alphanohtml');
258
259 $object->note_private = GETPOST('note_private', 'restricthtml');
260 $object->note_public = GETPOST('note_public', 'restricthtml');
261 $object->model_pdf = GETPOST('modelpdf', 'alphanohtml');
262 $object->usenewprice = GETPOSTINT('usenewprice');
263
264 $object->mode_reglement_id = GETPOSTINT('mode_reglement_id');
265 $object->cond_reglement_id = GETPOSTINT('cond_reglement_id');
266 $object->fk_societe_rib = GETPOSTINT('accountcustomerid');
267 $object->rule_for_lines_dates = GETPOST('rule_for_lines_dates', 'alpha');
268
269 $object->frequency = $frequency;
270 $object->unit_frequency = GETPOST('unit_frequency', 'alpha');
271 $object->nb_gen_max = $nb_gen_max;
272 $object->auto_validate = GETPOSTINT('auto_validate');
273 $object->generate_pdf = GETPOSTINT('generate_pdf');
274 $object->fk_project = $projectid;
275
276 $date_next_execution = dol_mktime($rehour, $remin, 0, $remonth, $reday, $reyear);
277 $object->date_when = $date_next_execution;
278
279 $ret = $extrafields->setOptionalsFromPost(null, $object);
280 if ($ret < 0) {
281 setEventMessages($extrafields->error, $extrafields->errors, 'errors');
282 $error++;
283 }
284
285 // Get first contract linked to invoice (or order or proposal) used to generate template (facid is id of source invoice)
286 if (GETPOSTINT('facid') > 0) {
287 $srcObject = new Facture($db);
288 $srcObject->fetch(GETPOSTINT('facid'));
289
290 $srcObject->fetchObjectLinked();
291
292 if (!empty($srcObject->linkedObjectsIds['contrat'])) {
293 $contractidid = reset($srcObject->linkedObjectsIds['contrat']);
294
295 $object->origin_type = 'contrat';
296 $object->origin_id = $contractidid;
297 $object->linked_objects[$object->origin_type] = $object->origin_id;
298 } elseif (!empty($srcObject->linkedObjectsIds['commande'])) {
299 $orderid = reset($srcObject->linkedObjectsIds['commande']);
300
301 $object->linked_objects['commande'] = $orderid;
302 } elseif (!empty($srcObject->linkedObjectsIds['propal'])) {
303 $proposalid = reset($srcObject->linkedObjectsIds['propal']);
304 $object->linked_objects['propal'] = $proposalid;
305 }
306 }
307
308 $db->begin();
309
310 $oldinvoice = new Facture($db);
311 $oldinvoice->fetch(GETPOSTINT('facid'));
312
313 $onlylines = GETPOST('toselect', 'array:int');
314
315 $result = $object->create($user, $oldinvoice->id, 0, $onlylines);
316 if ($result > 0) {
317 $result = $oldinvoice->delete($user, 1);
318 if ($result < 0) {
319 $error++;
320 setEventMessages($oldinvoice->error, $oldinvoice->errors, 'errors');
321 $action = "create";
322 }
323 } else {
324 $error++;
325 setEventMessages($object->error, $object->errors, 'errors');
326 $action = "create";
327 }
328
329 if (!$error) {
330 $db->commit();
331
332 header("Location: ".$_SERVER['PHP_SELF'].'?facid='.$object->id);
333 exit;
334 } else {
335 $db->rollback();
336
337 $action = "create";
338 }
339 }
340 }
341
342 // Delete
343 if ($action == 'confirm_delete' && $confirm == 'yes' && $user->hasRight('facture', 'supprimer')) {
344 $object->delete($user);
345
346 header("Location: ".DOL_URL_ROOT.'/compta/facture/invoicetemplate_list.php');
347 exit;
348 }
349
350
351 // Update field
352 if ($action == 'setconditions' && $usercancreate) {
353 // Set condition
354 $object->context['actionmsg'] = $langs->trans("FieldXModified", $langs->transnoentitiesnoconv("PaymentTerm"));
355 $result = $object->setPaymentTerms(GETPOSTINT('cond_reglement_id'));
356 } elseif ($action == 'setmode' && $usercancreate) {
357 // Set mode
358 $object->context['actionmsg'] = $langs->trans("FieldXModified", $langs->transnoentitiesnoconv("PaymentMode"));
359 $object->setPaymentMethods(GETPOSTINT('mode_reglement_id'));
360 $object->setValueFrom('fk_societe_rib', 0);
361
362 //Need to reload to display bank customer account field
363 header("Location: ".$_SERVER['PHP_SELF'].'?facid='.$object->id);
364 exit;
365 } elseif ($action == 'classin' && $usercancreate) {
366 // Set project
367 $object->context['actionmsg'] = $langs->trans("FieldXModified", $langs->transnoentitiesnoconv("Project"));
368 $object->setProject(GETPOSTINT('projectid'));
369 } elseif ($action == 'setref' && $usercancreate) {
370 // Set bank account
371 $object->context['actionmsg'] = $langs->trans("FieldXModifiedFromYToZ", $langs->transnoentitiesnoconv("Title"), $object->title, $ref);
372 $result = $object->setValueFrom('titre', $ref, '', null, 'text', '', $user, 'BILLREC_MODIFY');
373 if ($result > 0) {
374 $object->title = $ref;
375 $object->ref = $object->title;
376 } else {
377 $error++;
378 if ($object->error == 'DB_ERROR_RECORD_ALREADY_EXISTS') {
379 $langs->load("errors");
380 setEventMessages($langs->trans('ErrorRefAlreadyExists', $ref), null, 'errors');
381 } else {
382 setEventMessages($object->error, $object->errors, 'errors');
383 }
384 }
385 } elseif ($action == 'setbankaccount' && $usercancreate) {
386 // Set bank account
387 $object->context['actionmsg'] = $langs->trans("FieldXModified", $langs->transnoentitiesnoconv("Bank"));
388 $result = $object->setBankAccount(GETPOSTINT('fk_account'));
389 } elseif ($action == 'setbankaccountcustomer' && $usercancreate) {
390 // Set bank account customer
391 $object->context['actionmsg'] = $langs->trans("FieldXModified", $langs->transnoentitiesnoconv("DebitBankAccount"));
392 $fk_societe_rib = (GETPOSTINT('accountcustomerid') != "-1") ? GETPOSTINT('accountcustomerid') : 0;
393 $result = $object->setValueFrom('fk_societe_rib', $fk_societe_rib);
394 } elseif ($action == 'setfrequency' && $usercancreate) {
395 // Set frequency and unit frequency
396 $object->context['actionmsg'] = $langs->trans("FieldXModified", $langs->transnoentitiesnoconv("Frequency"));
397 $object->setFrequencyAndUnit(GETPOSTINT('frequency'), GETPOST('unit_frequency'));
398 } elseif ($action == 'setdate_when' && $usercancreate) {
399 // Set next date of execution
400 $date = dol_mktime(GETPOSTINT('date_whenhour'), GETPOSTINT('date_whenmin'), 0, GETPOSTINT('date_whenmonth'), GETPOSTINT('date_whenday'), GETPOSTINT('date_whenyear'));
401 if (!empty($date)) {
402 $object->setNextDate($date);
403 }
404 } elseif ($action == 'setnb_gen_max' && $usercancreate) {
405 // Set max period
406 $object->setMaxPeriod(GETPOSTINT('nb_gen_max'));
407 } elseif ($action == 'setauto_validate' && $usercancreate) {
408 // Set auto validate
409 $object->setAutoValidate(GETPOSTINT('auto_validate'));
410 } elseif ($action == 'setgenerate_pdf' && $usercancreate) {
411 // Set generate pdf
412 $object->setGeneratepdf(GETPOSTINT('generate_pdf'));
413 } elseif ($action == 'setmodelpdf' && $usercancreate) {
414 // Set model pdf
415 $object->setModelpdf(GETPOST('modelpdf', 'alpha'));
416 } elseif ($action == 'disable' && $usercancreate) {
417 // Set status disabled
418 $db->begin();
419
420 $object->context['actionmsg'] = $langs->trans("RecordDisabled");
421
422 $res = $object->setValueFrom('suspended', 1, '', null, 'text', '', $user, 'BILLREC_MODIFY');
423 if ($res <= 0) {
424 $error++;
425 }
426
427 if (!$error) {
428 $db->commit();
429 } else {
430 $db->rollback();
431 setEventMessages($object->error, $object->errors, 'errors');
432 }
433 } elseif ($action == 'enable' && $usercancreate) {
434 // Set status enabled
435 $db->begin();
436
437 $object->context['actionmsg'] = $langs->trans("RecordEnabled");
438
439 $res = $object->setValueFrom('suspended', 0, '', null, 'text', '', $user, 'BILLREC_MODIFY');
440 if ($res <= 0) {
441 $error++;
442 }
443
444 if (!$error) {
445 $db->commit();
446 } else {
447 $db->rollback();
448 setEventMessages($object->error, $object->errors, 'errors');
449 }
450 } elseif ($action == 'setmulticurrencycode' && $usercancreate) {
451 // Multicurrency Code
452 $result = $object->setMulticurrencyCode(GETPOST('multicurrency_code', 'alpha'));
453 $object->fetch($object->id); // Reload all.
454 } elseif ($action == 'setmulticurrencyrate' && $usercancreate) {
455 // Multicurrency rate
456 $result = $object->setMulticurrencyRate(GETPOSTFLOAT('multicurrency_tx'), GETPOSTINT('calculation_mode'));
457 $object->fetch($object->id); // Reload all.
458 } elseif ($action == 'setruleforlinesdates' && $usercancreate) {
459 $object->context['actionmsg'] = $langs->trans("FieldXModified", $langs->transnoentitiesnoconv("RuleForLinesDates"));
460 $ruleForLinesDates = GETPOSTISSET('rule_for_lines_dates') ? GETPOST('rule_for_lines_dates', 'alpha') : 'prepaid';
461 $object->setValueFrom('rule_for_lines_dates', $ruleForLinesDates);
462 }
463
464 // Delete line
465 if ($action == 'confirm_deleteline' && $confirm == 'yes' && $usercancreate) {
466 $object->fetch($id);
467 $object->fetch_thirdparty();
468
469 $db->begin();
470
471 $line = new FactureLigneRec($db);
472
473 // For triggers
474 $line->id = $lineid;
475
476 if ($line->delete($user) > 0) {
477 $result = $object->update_price(1);
478
479 if ($result > 0) {
480 $db->commit();
481 $object->fetch($object->id); // Reload lines
482 } else {
483 $db->rollback();
484 setEventMessages($db->lasterror(), null, 'errors');
485 }
486 } else {
487 $db->rollback();
488 setEventMessages($line->error, $line->errors, 'errors');
489 }
490 } elseif ($action == 'confirm_delete_subtotalline' && $confirm == 'yes' && $usercancreate) {
491 // Delete line
492 $object->fetch($id);
493 $object->fetch_thirdparty();
494
495 $result = $object->deleteSubtotalLine($langs, GETPOSTINT('lineid'), (bool) GETPOST('deletecorrespondingsubtotalline'), $user);
496 if ($result > 0) {
497 $result = $object->update_price(1);
498
499 if ($result > 0) {
500 $db->commit();
501 $object->fetch($object->id); // Reload lines
502 header('Location: '.$_SERVER["PHP_SELF"].'?id='.$id);
503 exit();
504 } else {
505 $db->rollback();
506 setEventMessages($db->lasterror(), null, 'errors');
507 }
508 } else {
509 setEventMessages($object->error, $object->errors, 'errors');
510 $action = '';
511 }
512 } elseif ($action == 'update_extras' && $permissiontoeditextra) {
513 $object->oldcopy = dol_clone($object, 2); // @phan-suppress-current-line PhanTypeMismatchProperty
514
515 $attribute_name = GETPOST('attribute', 'aZ09');
516
517 // Fill array 'array_options' with data from update form
518 $ret = $extrafields->setOptionalsFromPost(null, $object, $attribute_name);
519 if ($ret < 0) {
520 $error++;
521 }
522
523 if (!$error) {
524 $result = $object->updateExtraField($attribute_name, 'BILLREC_MODIFY');
525 if ($result < 0) {
526 setEventMessages($object->error, $object->errors, 'errors');
527 $error++;
528 }
529 }
530
531 if ($error) {
532 $action = 'edit_extras';
533 }
534 }
535
536 // Add a new line
537 if ($action == 'addline' && $usercancreate) {
538 $langs->load('errors');
539 $error = 0;
540
541 // Set if we used free entry or predefined product
542 $predef = '';
543 $product_desc = (GETPOSTISSET('dp_desc') ? GETPOST('dp_desc', 'restricthtml') : '');
544 $price_ht = price2num(GETPOST('price_ht'), 'MU', 2);
545 $price_ht_devise = price2num(GETPOST('multicurrency_price_ht'), 'CU', 2);
546 $prod_entry_mode = GETPOST('prod_entry_mode', 'alpha');
547 if ($prod_entry_mode == 'free') {
548 $idprod = 0;
549 } else {
550 $idprod = GETPOSTINT('idprod');
551
552 if (getDolGlobalString('MAIN_DISABLE_FREE_LINES') && $idprod <= 0) {
553 setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("ProductOrService")), null, 'errors');
554 $error++;
555 }
556 }
557
558 $tva_tx = (GETPOST('tva_tx', 'alpha') ? GETPOST('tva_tx', 'alpha') : 0);
559
560 $qty = price2num(GETPOST('qty'.$predef, 'alpha'), 'MS', 2);
561 $remise_percent = price2num(GETPOST('remise_percent'.$predef), '', 2);
562 if (empty($remise_percent)) {
563 $remise_percent = 0;
564 }
565
566 // Extrafields
567 $extralabelsline = $extrafields->fetch_name_optionals_label($object->table_element_line);
568 $array_options = $extrafields->getOptionalsFromPost($object->table_element_line, $predef);
569 // Unset extrafield
570 if (is_array($extralabelsline)) {
571 // Get extra fields
572 foreach ($extralabelsline as $key => $value) {
573 unset($_POST["options_".$key.$predef]);
574 }
575 }
576
577 if ((empty($idprod) || $idprod < 0) && ($price_ht < 0) && ((float) $qty < 0)) {
578 setEventMessages($langs->trans('ErrorBothFieldCantBeNegative', $langs->transnoentitiesnoconv('UnitPriceHT'), $langs->transnoentitiesnoconv('Qty')), null, 'errors');
579 $error++;
580 }
581 if ($prod_entry_mode == 'free' && (empty($idprod) || $idprod < 0) && GETPOST('type') < 0) {
582 setEventMessages($langs->trans('ErrorFieldRequired', $langs->transnoentitiesnoconv('Type')), null, 'errors');
583 $error++;
584 }
585 if ($prod_entry_mode == 'free' && (empty($idprod) || $idprod < 0) && (!($price_ht >= 0) || $price_ht == '')) { // Unit price can be 0 but not ''
586 setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("UnitPriceHT")), null, 'errors');
587 $error++;
588 }
589 if ($qty == '') {
590 setEventMessages($langs->trans('ErrorFieldRequired', $langs->transnoentitiesnoconv('Qty')), null, 'errors');
591 $error++;
592 }
593 if ($prod_entry_mode == 'free' && (empty($idprod) || $idprod < 0) && empty($product_desc)) {
594 setEventMessages($langs->trans('ErrorFieldRequired', $langs->transnoentitiesnoconv('Description')), null, 'errors');
595 $error++;
596 }
597 if ($qty < 0) {
598 $langs->load("errors");
599 setEventMessages($langs->trans('ErrorQtyForCustomerInvoiceCantBeNegative'), null, 'errors');
600 $error++;
601 }
602
603 if (!$error && ($qty >= 0) && (!empty($product_desc) || (!empty($idprod) && $idprod > 0))) {
604 $ret = $object->fetch($id);
605 if ($ret < 0) {
606 dol_print_error($db, $object->error);
607 exit();
608 }
609 $ret = $object->fetch_thirdparty();
610
611 // Clean parameters
612 $date_start = dol_mktime(GETPOSTINT('date_start'.$predef.'hour'), GETPOSTINT('date_start'.$predef.'min'), GETPOSTINT('date_start'.$predef.'sec'), GETPOSTINT('date_start'.$predef.'month'), GETPOSTINT('date_start'.$predef.'day'), GETPOSTINT('date_start'.$predef.'year'));
613 $date_end = dol_mktime(GETPOSTINT('date_end'.$predef.'hour'), GETPOSTINT('date_end'.$predef.'min'), GETPOSTINT('date_end'.$predef.'sec'), GETPOSTINT('date_end'.$predef.'month'), GETPOSTINT('date_end'.$predef.'day'), GETPOSTINT('date_end'.$predef.'year'));
614 $price_base_type = (GETPOST('price_base_type', 'alpha') ? GETPOST('price_base_type', 'alpha') : 'HT');
615 $tva_npr = "";
616
617 // Define special_code for special lines
618 $special_code = 0;
619 // if (!GETPOST('qty')) $special_code=3; // Options should not exists on invoices
620
621 // Ecrase $pu par celui du produit
622 // Ecrase $desc par celui du produit
623 // Ecrase $base_price_type par celui du produit
624 // Replaces $fk_unit with the product's
625 if (!empty($idprod) && $idprod > 0) {
626 $prod = new Product($db);
627 $prod->fetch($idprod);
628
629 $label = ((GETPOST('product_label') && GETPOST('product_label') != $prod->label) ? GETPOST('product_label') : '');
630
631 // Update if prices fields are defined
632 //$tva_tx = get_default_tva($mysoc, $object->thirdparty, $prod->id);
633 //$tva_npr = get_default_npr($mysoc, $object->thirdparty, $prod->id);
634 //if (empty($tva_tx)) {
635 // $tva_npr = 0;
636 //}
637
638 // Search the correct price into loaded array product_price_by_qty using id of array retrieved into POST['pqp'].
639 $pqp = (GETPOSTINT('pbq') ? GETPOSTINT('pbq') : 0);
640
641 $datapriceofproduct = $prod->getSellPrice($mysoc, $object->thirdparty, $pqp);
642
643 $pu_ht = $datapriceofproduct['pu_ht'];
644 $pu_ttc = $datapriceofproduct['pu_ttc'];
645 $price_min = $datapriceofproduct['price_min'];
646 $price_base_type = empty($datapriceofproduct['price_base_type']) ? 'HT' : $datapriceofproduct['price_base_type'];
647 //$tva_tx = $datapriceofproduct['tva_tx'];
648 //$tva_npr = $datapriceofproduct['tva_npr'];
649
650 $tmpvat = (float) price2num(preg_replace('/\s*\‍(.*\‍)/', '', $tva_tx));
651 $tmpprodvat = price2num(preg_replace('/\s*\‍(.*\‍)/', '', (string) $prod->tva_tx));
652
653 // if price ht was forced (ie: from gui when calculated by margin rate and cost price). TODO Why this ?
654 if (!empty($price_ht)) {
655 $pu_ht = price2num($price_ht, 'MU');
656 $pu_ttc = price2num((float) $pu_ht * (1 + ($tmpvat / 100)), 'MU');
657 } elseif ($tmpvat != $tmpprodvat) {
658 // On reevalue prix selon taux tva car taux tva transaction peut etre different
659 // de ceux du produit par default (par example si pays different entre vendeur et acheteur).
660 if ($price_base_type != 'HT') {
661 $pu_ht = price2num((float) $pu_ttc / (1 + ($tmpvat / 100)), 'MU');
662 } else {
663 $pu_ttc = price2num((float) $pu_ht * (1 + ($tmpvat / 100)), 'MU');
664 }
665 }
666
667 $outputlangs = $langs;
668 $newlang = '';
669 $desc = '';
670
671 // Define output language
672 if (getDolGlobalInt('MAIN_MULTILANGS') && getDolGlobalString('PRODUIT_TEXTS_IN_THIRDPARTY_LANGUAGE')) {
673 if (/* empty($newlang) && */ GETPOST('lang_id', 'aZ09')) {
674 $newlang = GETPOST('lang_id', 'aZ09');
675 }
676 if (empty($newlang)) {
677 $newlang = $object->thirdparty->default_lang;
678 }
679 if (!empty($newlang)) {
680 $outputlangs = new Translate("", $conf);
681 $outputlangs->setDefaultLang($newlang);
682 $outputlangs->load('products');
683 }
684
685 $desc = (!empty($prod->multilangs [$outputlangs->defaultlang] ["description"])) ? $prod->multilangs [$outputlangs->defaultlang] ["description"] : $prod->description;
686 } else {
687 $desc = $prod->description;
688 }
689
690 $desc = dol_concatdesc($desc, $product_desc);
691
692 // Add custom code and origin country into description
693 if (!getDolGlobalString('MAIN_PRODUCT_DISABLE_CUSTOMCOUNTRYCODE') && (!empty($prod->customcode) || !empty($prod->country_code))) {
694 $tmptxt = '(';
695 // Define output language
696 if (getDolGlobalInt('MAIN_MULTILANGS') && getDolGlobalString('PRODUIT_TEXTS_IN_THIRDPARTY_LANGUAGE')) {
697 if (!empty($prod->customcode)) {
698 $tmptxt .= $outputlangs->transnoentitiesnoconv("CustomsCode").': '.$prod->customcode;
699 }
700 if (!empty($prod->customcode) && !empty($prod->country_code)) {
701 $tmptxt .= ' - ';
702 }
703 if (!empty($prod->country_code)) {
704 $tmptxt .= $outputlangs->transnoentitiesnoconv("CountryOrigin").': '.getCountry($prod->country_code, '', $db, $outputlangs, 0);
705 }
706 } else {
707 if (!empty($prod->customcode)) {
708 $tmptxt .= $langs->transnoentitiesnoconv("CustomsCode").': '.$prod->customcode;
709 }
710 if (!empty($prod->customcode) && !empty($prod->country_code)) {
711 $tmptxt .= ' - ';
712 }
713 if (!empty($prod->country_code)) {
714 $tmptxt .= $langs->transnoentitiesnoconv("CountryOrigin").': '.getCountry($prod->country_code, '', $db, $langs, 0);
715 }
716 }
717 $tmptxt .= ')';
718 $desc = dol_concatdesc($desc, $tmptxt);
719 }
720
721 $type = $prod->type;
722 $fk_unit = $prod->fk_unit;
723 } else {
724 $pu_ht = price2num($price_ht, 'MU');
725 $pu_ttc = price2num(GETPOST('price_ttc'), 'MU');
726 $tva_npr = (preg_match('/\*/', $tva_tx) ? 1 : 0);
727 $tva_tx = str_replace('*', '', $tva_tx);
728 if (empty($tva_tx)) {
729 $tva_npr = 0;
730 }
731 $label = (GETPOST('product_label') ? GETPOST('product_label') : '');
732 $desc = $product_desc;
733 $type = GETPOST('type');
734 $fk_unit = GETPOSTINT('units');
735 }
736
737 $date_start_fill = GETPOSTINT('date_start_fill');
738 $date_end_fill = GETPOSTINT('date_end_fill');
739
740 // Margin
741 $fournprice = (int) (GETPOST('fournprice'.$predef) ? GETPOST('fournprice'.$predef) : ''); // This can be id of supplier price, or 'pmpprice' or 'costprice', or 'inputprice', we force to keep ID only
742 $buyingprice = price2num(GETPOST('buying_price'.$predef) != '' ? GETPOST('buying_price'.$predef) : ''); // If buying_price is '0', we must keep this value
743
744 // Local Taxes
745 $localtax1_tx = get_localtax($tva_tx, 1, $object->thirdparty, $mysoc, $tva_npr);
746 $localtax2_tx = get_localtax($tva_tx, 2, $object->thirdparty, $mysoc, $tva_npr);
747
748 $info_bits = 0;
749 if ($tva_npr) {
750 $info_bits |= 0x01;
751 }
752
753 $fk_parent_line = GETPOSTINT('fk_parent_line');
754
755 if ($usercanproductignorepricemin && (!empty($price_min) && ((float) price2num($pu_ht) * (1 - (float) price2num($remise_percent) / 100) < (float) price2num($price_min)))) {
756 $mesg = $langs->trans("CantBeLessThanMinPrice", price(price2num($price_min, 'MU'), 0, $langs, 0, 0, -1, $conf->currency));
757 setEventMessages($mesg, null, 'errors');
758 } else {
759 // Insert line
760 $result = $object->addline($desc, $pu_ht, (float) $qty, $tva_tx, $localtax1_tx, $localtax2_tx, $idprod, $remise_percent, $price_base_type, $info_bits, 0, $pu_ttc, $type, -1, $special_code, $label, (int) $fk_unit, 0, $date_start_fill, $date_end_fill, (int) $fournprice, $buyingprice, $fk_parent_line);
761
762 if ($result > 0) {
763 // TODO add "insert" function into FactureLigneRec or add "invoicerecline.class.php" (same of "factureligne.class.php")
764 $objectline = new FactureLigneRec($db);
765 if ($objectline->fetch($result)) {
766 $objectline->array_options = $array_options;
767 $result = $objectline->insertExtraFields();
768 if ($result < 0) {
769 setEventMessages($langs->trans('Error').$result, null, 'errors');
770 }
771 }
772
773 // Define output language and generate document
774 /*if (empty($conf->global->MAIN_DISABLE_PDF_AUTOUPDATE))
775 {
776 // Define output language
777 $outputlangs = $langs;
778 $newlang = '';
779 if (getDolGlobalInt('MAIN_MULTILANGS') && empty($newlang) && GETPOST('lang_id','aZ09')) $newlang = GETPOST('lang_id','aZ09');
780 if (getDolGlobalInt('MAIN_MULTILANGS') && empty($newlang)) $newlang = $object->thirdparty->default_lang;
781 if (!empty($newlang)) {
782 $outputlangs = new Translate("", $conf);
783 $outputlangs->setDefaultLang($newlang);
784 }
785 $model=$object->model_pdf;
786 $ret = $object->fetch($id); // Reload to get new records
787
788 $result = $object->generateDocument($model, $outputlangs, $hidedetails, $hidedesc, $hideref);
789 if ($result < 0) setEventMessages($object->error, $object->errors, 'errors');
790 }*/
791 $object->fetch($object->id); // Reload lines
792
793 unset($_POST['prod_entry_mode']);
794
795 unset($_POST['qty']);
796 unset($_POST['type']);
797 unset($_POST['remise_percent']);
798 unset($_POST['price_ht']);
799 unset($_POST['multicurrency_price_ht']);
800 unset($_POST['price_ttc']);
801 unset($_POST['tva_tx']);
802 unset($_POST['product_ref']);
803 unset($_POST['product_label']);
804 unset($_POST['product_desc']);
805 unset($_POST['fournprice']);
806 unset($_POST['buying_price']);
807 unset($_POST['np_marginRate']);
808 unset($_POST['np_markRate']);
809 unset($_POST['dp_desc']);
810 unset($_POST['idprod']);
811 unset($_POST['units']);
812
813 unset($_POST['date_starthour']);
814 unset($_POST['date_startmin']);
815 unset($_POST['date_startsec']);
816 unset($_POST['date_startday']);
817 unset($_POST['date_startmonth']);
818 unset($_POST['date_startyear']);
819 unset($_POST['date_endhour']);
820 unset($_POST['date_endmin']);
821 unset($_POST['date_endsec']);
822 unset($_POST['date_endday']);
823 unset($_POST['date_endmonth']);
824 unset($_POST['date_endyear']);
825
826 unset($_POST['date_start_fill']);
827 unset($_POST['date_end_fill']);
828
829 unset($_POST['situations']);
830 unset($_POST['progress']);
831 } else {
832 setEventMessages($object->error, $object->errors, 'errors');
833 }
834
835 $action = '';
836 }
837 }
838 } elseif ($action == 'confirm_addtitleline' && $usercancreate) {
839 // Handling adding a new title line for subtotals module
840
841 $langs->load('subtotals');
842
843 $desc = GETPOST('subtotallinedesc', 'alphanohtml');
844 $depth = GETPOSTINT('subtotallinelevel') ?? 1;
845
846 $subtotal_options = array();
847
848 foreach (FactureRec::$TITLE_OPTIONS as $option) {
849 $value = GETPOST($option, 'alphanohtml');
850 if ($value) {
851 $subtotal_options[$option] = $value == 'on' ? 1 : $value;
852 }
853 }
854
855 // Insert line
856 $result = $object->addSubtotalLine($langs, $desc, (int) $depth, $subtotal_options);
857
858 if ($result >= 0) {
859 if ($result == 0) {
860 setEventMessages($object->error, $object->errors, 'warnings');
861 }
862 $ret = $object->fetch($object->id); // Reload to get new records
863 $object->fetch_thirdparty();
864 } else {
865 setEventMessages($object->error, $object->errors, 'errors');
866 }
867 header('Location: '.$_SERVER["PHP_SELF"].'?id='.$id);
868 exit();
869 } elseif ($action == 'confirm_addsubtotalline' && $usercancreate) {
870 // Handling adding a new subtotal line for subtotals module
871
872 $langs->load('subtotals');
873
874 $choosen_line = GETPOST('subtotaltitleline', 'alphanohtml');
875 foreach ($object->lines as $line) {
876 if ($line->desc == $choosen_line && $line->special_code == SUBTOTALS_SPECIAL_CODE) {
877 $desc = $line->desc;
878 $depth = -$line->qty;
879 }
880 }
881
882 $subtotal_options = array();
883
884 foreach (FactureRec::$SUBTOTAL_OPTIONS as $option) {
885 $value = GETPOST($option, 'alphanohtml');
886 if ($value) {
887 $subtotal_options[$option] = $value == 'on' ? 1 : $value;
888 }
889 }
890
891 // Insert line
892 if (isset($desc) && isset($depth)) {
893 $result = $object->addSubtotalLine($langs, $desc, (int) $depth, $subtotal_options);
894 } else {
895 $object->errors[] = $langs->trans("CorrespondingTitleNotFound");
896 }
897
898 if (isset($result) && $result >= 0) {
899 $ret = $object->fetch($object->id); // Reload to get new records
900 $object->fetch_thirdparty();
901 } else {
902 setEventMessages($object->error, $object->errors, 'errors');
903 }
904 header('Location: '.$_SERVER["PHP_SELF"].'?id='.$id);
905 exit();
906 } elseif ($action == 'updateline' && $usercancreate && !GETPOST('cancel', 'alpha')) {
907 if (!$object->fetch($id) > 0) {
908 dol_print_error($db);
909 }
910 $object->fetch_thirdparty();
911
912 // Clean parameters
913 $date_start = '';
914 $date_end = '';
915 //$date_start = dol_mktime(GETPOSTINT('date_starthour'), GETPOSTINT('date_startmin'), GETPOSTINT('date_startsec'), GETPOSTINT('date_startmonth'), GETPOSTINT('date_startday'), GETPOSTINT('date_startyear'));
916 //$date_end = dol_mktime(GETPOSTINT('date_endhour'), GETPOSTINT('date_endmin'), GETPOSTINT('date_endsec'), GETPOSTINT('date_endmonth'), GETPOSTINT('date_endday'), GETPOSTINT('date_endyear'));
917 $description = dol_htmlcleanlastbr(GETPOST('product_desc', 'restricthtml') ? GETPOST('product_desc', 'restricthtml') : GETPOST('desc', 'restricthtml'));
918 $vat_rate = (GETPOST('tva_tx') ? GETPOST('tva_tx') : 0);
919
920 $pu_ht = price2num(GETPOST('price_ht'), '', 2);
921 $pu_ttc = price2num(GETPOST('price_ttc'), '', 2);
922
923 $pu_ht_devise = price2num(GETPOST('multicurrency_subprice'), '', 2);
924 $pu_ttc_devise = price2num(GETPOST('multicurrency_subprice_ttc'), '', 2);
925
926 $qty = (float) price2num(GETPOST('qty', 'alpha'), 'MS');
927
928 // Define info_bits
929 $info_bits = 0;
930 if (preg_match('/\*/', $vat_rate)) {
931 $info_bits |= 0x01;
932 }
933
934 // Define vat_rate
935 $vat_rate = str_replace('*', '', $vat_rate);
936 $localtax1_rate = get_localtax($vat_rate, 1, $object->thirdparty);
937 $localtax2_rate = get_localtax($vat_rate, 2, $object->thirdparty);
938
939 // Add buying price
940 $fournprice = (int) (GETPOST('fournprice') ? GETPOST('fournprice') : '');
941 $buyingprice = price2num(GETPOST('buying_price') != '' ? GETPOST('buying_price') : ''); // If buying_price is '0', we must keep this value
942
943 // Prepare a price equivalent for minimum price check
944 $pu_equivalent = $pu_ht;
945 $pu_equivalent_ttc = $pu_ttc;
946
947 $currency_tx = $object->multicurrency_tx;
948
949 // Check if we have a foreign currency
950 // If so, we update the pu_equiv as the equivalent price in base currency
951 if ($pu_ht == '' && $pu_ht_devise != '' && $currency_tx != '' && !empty((float) $currency_tx)) {
952 $pu_equivalent = (float) $pu_ht_devise / (float) $currency_tx;
953 }
954 if ($pu_ttc == '' && $pu_ttc_devise != '' && $currency_tx != '' && !empty((float) $currency_tx)) {
955 $pu_equivalent_ttc = (float) $pu_ttc_devise / (float) $currency_tx;
956 }
957
958 // TODO $pu_equivalent or $pu_equivalent_ttc must be calculated from the one not null taking into account all taxes
959 /*
960 if ($pu_equivalent) {
961 $tmp = calcul_price_total(1, $pu_equivalent, 0, $vat_rate, -1, -1, 0, 'HT', $info_bits, $type);
962 $pu_equivalent_ttc = ...
963 } else {
964 $tmp = calcul_price_total(1, $pu_equivalent_ttc, 0, $vat_rate, -1, -1, 0, 'TTC', $info_bits, $type);
965 $pu_equivalent_ht = ...
966 }
967 */
968
969 // Extrafields
970 $extralabelsline = $extrafields->fetch_name_optionals_label($object->table_element_line);
971 $array_options = $extrafields->getOptionalsFromPost($object->table_element_line);
972
973 $objectline = new FactureLigneRec($db);
974 if ($objectline->fetch(GETPOSTINT('lineid'))) {
975 $objectline->array_options = $array_options;
976 $result = $objectline->insertExtraFields();
977 if ($result < 0) {
978 setEventMessages($langs->trans('Error').$result, null, 'errors');
979 }
980 }
981 $position = ($objectline->rang >= 0 ? $objectline->rang : 0);
982
983 // Unset extrafield
984 if (is_array($extralabelsline)) {
985 // Get extra fields
986 foreach ($extralabelsline as $key => $value) {
987 unset($_POST["options_".$key]);
988 }
989 }
990
991 // Define special_code for special lines
992 $special_code = GETPOSTINT('special_code');
993 if ($special_code == 3) {
994 $special_code = 0; // Options should not exists on invoices
995 }
996
997 /*
998 $line = new FactureLigne($db);
999 $line->fetch(GETPOST('lineid', 'int'));
1000 $percent = $line->get_prev_progress($object->id);
1001
1002 ...
1003 */
1004
1005 $remise_percent = price2num(GETPOST('remise_percent'), '', 2);
1006 if (empty($remise_percent)) {
1007 $remise_percent = 0;
1008 }
1009
1010 $price_base_type = 'HT';
1011 $pu = $pu_ht;
1012 if (empty($pu) && !empty($pu_ttc)) {
1013 $pu = $pu_ttc;
1014 $price_base_type = 'TTC';
1015 }
1016
1017 // Check minimum price
1018 $productid = GETPOSTINT('productid');
1019 if (!empty($productid)) {
1020 $product = new Product($db);
1021 $product->fetch($productid);
1022
1023 $type = $product->type;
1024
1025 $price_min = $product->price_min;
1026 if ((getDolGlobalString('PRODUIT_MULTIPRICES') || getDolGlobalString('PRODUIT_CUSTOMER_PRICES_BY_QTY_MULTIPRICES')) && !empty($object->thirdparty->price_level)) {
1027 $price_min = $product->multiprices_min[$object->thirdparty->price_level];
1028 }
1029 $price_min_ttc = $product->price_min_ttc;
1030 if ((getDolGlobalString('PRODUIT_MULTIPRICES') || getDolGlobalString('PRODUIT_CUSTOMER_PRICES_BY_QTY_MULTIPRICES')) && !empty($object->thirdparty->price_level)) {
1031 $price_min_ttc = $product->multiprices_min_ttc[$object->thirdparty->price_level];
1032 }
1033
1034 $label = ((GETPOST('update_label') && GETPOST('product_label')) ? GETPOST('product_label') : '');
1035
1036 $typeinvoice = Facture::TYPE_STANDARD;
1037
1038 // Check price is not lower than minimum (check is done only for standard or replacement invoices)
1039 if ($usermustrespectpricemin && ($typeinvoice == Facture::TYPE_STANDARD || $typeinvoice == Facture::TYPE_REPLACEMENT)) {
1040 if ($pu_equivalent && $price_min && (((float) price2num($pu_equivalent) * (1 - (float) $remise_percent / 100)) < (float) price2num($price_min)) && $price_base_type == 'HT') {
1041 $mesg = $langs->trans("CantBeLessThanMinPrice", price(price2num($price_min, 'MU'), 0, $langs, 0, 0, -1, $conf->currency));
1042 setEventMessages($mesg, null, 'errors');
1043 $error++;
1044 $action = 'editline';
1045 } elseif ($pu_equivalent_ttc && $price_min_ttc && (((float) price2num($pu_equivalent_ttc) * (1 - (float) $remise_percent / 100)) < (float) price2num($price_min_ttc)) && $price_base_type == 'TTC') {
1046 $mesg = $langs->trans("CantBeLessThanMinPriceInclTax", price(price2num($price_min_ttc, 'MU'), 0, $langs, 0, 0, -1, $conf->currency));
1047 setEventMessages($mesg, null, 'errors');
1048 $error++;
1049 $action = 'editline';
1050 }
1051 }
1052 } else {
1053 $type = GETPOSTINT('type');
1054 $label = (GETPOST('product_label') ? GETPOST('product_label') : '');
1055
1056 // Check parameters
1057 if (GETPOSTINT('type') < 0) {
1058 setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("Type")), null, 'errors');
1059 $error++;
1060 }
1061 }
1062 if ($qty < 0) {
1063 $langs->load("errors");
1064 setEventMessages($langs->trans('ErrorQtyForCustomerInvoiceCantBeNegative'), null, 'errors');
1065 $error++;
1066 }
1067
1068 $date_start_fill = GETPOSTINT('date_start_fill');
1069 $date_end_fill = GETPOSTINT('date_end_fill');
1070 $fk_parent_line = GETPOST('fk_parent_line', 'int');
1071
1072 // Update line
1073 if (!$error) {
1074 $result = $object->updateline(
1075 GETPOSTINT('lineid'),
1076 $description,
1077 (float) $pu_ht,
1078 (float) $qty,
1079 $vat_rate,
1080 $localtax1_rate,
1081 $localtax1_rate,
1082 GETPOSTINT('productid'),
1083 $remise_percent,
1084 'HT',
1085 $info_bits,
1086 0,
1087 0,
1088 $type,
1089 $position,
1090 $special_code,
1091 $label,
1092 GETPOSTINT('units'),
1093 (float) $pu_ht_devise,
1094 0,
1095 $date_start_fill,
1096 $date_end_fill,
1097 (int) $fournprice,
1098 (float) $buyingprice,
1099 (int) $fk_parent_line
1100 );
1101
1102 if ($result >= 0) {
1103 /*if (empty($conf->global->MAIN_DISABLE_PDF_AUTOUPDATE)) {
1104 // Define output language
1105 $outputlangs = $langs;
1106 $newlang = '';
1107 if (getDolGlobalInt('MAIN_MULTILANGS') && empty($newlang) && GETPOST('lang_id','aZ09'))
1108 $newlang = GETPOST('lang_id','aZ09');
1109 if (getDolGlobalInt('MAIN_MULTILANGS') && empty($newlang))
1110 $newlang = $object->thirdparty->default_lang;
1111 if (!empty($newlang)) {
1112 $outputlangs = new Translate("", $conf);
1113 $outputlangs->setDefaultLang($newlang);
1114 }
1115
1116 $ret = $object->fetch($id); // Reload to get new records
1117 $object->generateDocument($object->model_pdf, $outputlangs, $hidedetails, $hidedesc, $hideref);
1118 }*/
1119
1120 $object->fetch($object->id); // Reload lines
1121
1122 unset($_POST['qty']);
1123 unset($_POST['type']);
1124 unset($_POST['productid']);
1125 unset($_POST['remise_percent']);
1126 unset($_POST['price_ht']);
1127 unset($_POST['multicurrency_price_ht']);
1128 unset($_POST['price_ttc']);
1129 unset($_POST['tva_tx']);
1130 unset($_POST['product_ref']);
1131 unset($_POST['product_label']);
1132 unset($_POST['product_desc']);
1133 unset($_POST['fournprice']);
1134 unset($_POST['buying_price']);
1135 unset($_POST['np_marginRate']);
1136 unset($_POST['np_markRate']);
1137
1138 unset($_POST['dp_desc']);
1139 unset($_POST['idprod']);
1140 unset($_POST['units']);
1141
1142 unset($_POST['date_starthour']);
1143 unset($_POST['date_startmin']);
1144 unset($_POST['date_startsec']);
1145 unset($_POST['date_startday']);
1146 unset($_POST['date_startmonth']);
1147 unset($_POST['date_startyear']);
1148 unset($_POST['date_endhour']);
1149 unset($_POST['date_endmin']);
1150 unset($_POST['date_endsec']);
1151 unset($_POST['date_endday']);
1152 unset($_POST['date_endmonth']);
1153 unset($_POST['date_endyear']);
1154
1155 unset($_POST['situations']);
1156 unset($_POST['progress']);
1157 } else {
1158 setEventMessages($object->error, $object->errors, 'errors');
1159 }
1160 }
1161 } elseif ($action == 'updatetitleline' && GETPOSTISSET("save") && $usercancreate && !GETPOST('cancel', 'alpha')) {
1162 // Handling updating a title line for subtotals module
1163
1164 $langs->load('subtotals');
1165
1166 $desc = GETPOST('line_desc', 'alphanohtml') ?? $langs->trans("Title");
1167 $depth = GETPOSTINT('line_depth') ?? 1;
1168
1169 $subtotal_options = array();
1170
1171 foreach (Facture::$TITLE_OPTIONS as $option) {
1172 $value = GETPOST($option, 'alphanohtml');
1173 if ($value) {
1174 $subtotal_options[$option] = $value == 'on' ? 1 : $value;
1175 }
1176 }
1177
1178 // Update line
1179 $result = $object->updateSubtotalLine($langs, GETPOSTINT('lineid'), $desc, $depth, $subtotal_options);
1180
1181 if ($result >= 0) {
1182 if ($result == 0) {
1183 setEventMessages($object->error, $object->errors, 'warnings');
1184 }
1185 $ret = $object->fetch($object->id); // Reload to get new records
1186 $object->fetch_thirdparty();
1187 } else {
1188 setEventMessages($object->error, $object->errors, 'errors');
1189 }
1190 } elseif ($action == 'updatesubtotalline' && GETPOSTISSET("save") && $usercancreate && !GETPOST('cancel', 'alpha')) {
1191 // Handling updating a subtotal line for subtotals module
1192
1193 $langs->load('subtotals');
1194
1195 $desc = GETPOST('line_desc', 'alphanohtml');
1196 $depth = GETPOSTINT('line_depth');
1197
1198 $subtotal_options = array();
1199
1200 foreach (Facture::$SUBTOTAL_OPTIONS as $option) {
1201 $value = GETPOST($option, 'alphanohtml');
1202 if ($value) {
1203 $subtotal_options[$option] = $value == 'on' ? 1 : $value;
1204 }
1205 }
1206
1207 // Update line
1208 $result = $object->updateSubtotalLine($langs, GETPOSTINT('lineid'), $desc, $depth, $subtotal_options);
1209
1210 if ($result > 0) {
1211 $ret = $object->fetch($object->id); // Reload to get new records
1212 $object->fetch_thirdparty();
1213 } else {
1214 setEventMessages($object->error, $object->errors, 'errors');
1215 }
1216 }
1217}
1218
1219
1220/*
1221 * View
1222 */
1223
1224$title = $object->ref." - ".$langs->trans('Card');
1225$help_url = '';
1226
1227llxHeader('', $title, $help_url);
1228
1229$form = new Form($db);
1230$formother = new FormOther($db);
1231if (isModEnabled('project')) {
1232 $formproject = new FormProjets($db);
1233} else {
1234 $formproject = null;
1235}
1236$companystatic = new Societe($db);
1237$invoicerectmp = new FactureRec($db);
1238
1239$now = dol_now();
1240$nowlasthour = dol_get_last_hour($now);
1241
1242
1243// Create mode
1244if ($action == 'create') {
1245 print load_fiche_titre($langs->trans("CreateRepeatableInvoice"), '', 'bill');
1246
1247 $sourceInvoice = new Facture($db); // Source invoice
1248 $factureRec = new FactureRec($db);
1249 $product_static = new Product($db);
1250
1251 if ($sourceInvoice->fetch($id, $ref) > 0) {
1252 $result = $sourceInvoice->getLinesArray();
1253
1254 print '<form action="'.$_SERVER["PHP_SELF"].'" method="POST">';
1255 print '<input type="hidden" name="token" value="'.newToken().'">';
1256 print '<input type="hidden" name="action" value="add">';
1257 print '<input type="hidden" name="facid" value="'.$sourceInvoice->id.'">';
1258
1259
1260 print dol_get_fiche_head([], '', '', 0);
1261
1262 $rowspan = 4;
1263 if (isModEnabled('project')) {
1264 $rowspan++;
1265 }
1266 if ($sourceInvoice->fk_account > 0) {
1267 $rowspan++;
1268 }
1269
1270 print '<table class="border centpercent">';
1271
1272 $sourceInvoice->fetch_thirdparty();
1273
1274 // Title
1275 print '<tr><td class="titlefieldcreate fieldrequired">'.$langs->trans("Title").'</td><td>';
1276 print '<input class="flat quatrevingtpercent" type="text" name="title" value="'.dol_escape_htmltag(GETPOST("title", 'alphanohtml')).'" autofocus>';
1277 print '</td></tr>';
1278
1279 // Third party
1280 print '<tr><td class="titlefieldcreate">'.$langs->trans("Customer").'</td><td>'.$sourceInvoice->thirdparty->getNomUrl(1, 'customer').'</td>';
1281 print '</tr>';
1282
1283 // Invoice subtype
1284 if (getDolGlobalInt('INVOICE_SUBTYPE_ENABLED')) {
1285 print "<tr><td>".$langs->trans("InvoiceSubtype")."</td><td>";
1286 print $form->getSelectInvoiceSubtype(GETPOSTISSET('subtype') ? GETPOSTINT('subtype') : $sourceInvoice->subtype, 'subtype', 0, 0, '');
1287 print "</td></tr>";
1288 }
1289
1290 $note_public = GETPOSTISSET('note_public') ? GETPOST('note_public', 'restricthtml') : $sourceInvoice->note_public;
1291 $note_private = GETPOSTISSET('note_private') ? GETPOST('note_private', 'restricthtml') : $sourceInvoice->note_private;
1292
1293 // Help of substitution key
1294 $substitutionarray = getCommonSubstitutionArray($langs, 2, null, $sourceInvoice);
1295
1296 $substitutionarray['__INVOICE_PREVIOUS_MONTH__'] = $langs->trans("PreviousMonthOfInvoice").' ('.$langs->trans("Example").': '.dol_print_date(dol_time_plus_duree($sourceInvoice->date, -1, 'm'), '%m').')';
1297 $substitutionarray['__INVOICE_MONTH__'] = $langs->trans("MonthOfInvoice").' ('.$langs->trans("Example").': '.dol_print_date($sourceInvoice->date, '%m').')';
1298 $substitutionarray['__INVOICE_NEXT_MONTH__'] = $langs->trans("NextMonthOfInvoice").' ('.$langs->trans("Example").': '.dol_print_date(dol_time_plus_duree($sourceInvoice->date, 1, 'm'), '%m').')';
1299 $substitutionarray['__INVOICE_PREVIOUS_MONTH_TEXT__'] = $langs->trans("TextPreviousMonthOfInvoice").' ('.$langs->trans("Example").': '.dol_print_date(dol_time_plus_duree($sourceInvoice->date, -1, 'm'), '%B').')';
1300 $substitutionarray['__INVOICE_MONTH_TEXT__'] = $langs->trans("TextMonthOfInvoice").' ('.$langs->trans("Example").': '.dol_print_date($sourceInvoice->date, '%B').')';
1301 $substitutionarray['__INVOICE_NEXT_MONTH_TEXT__'] = $langs->trans("TextNextMonthOfInvoice").' ('.$langs->trans("Example").': '.dol_print_date(dol_time_plus_duree($sourceInvoice->date, 1, 'm'), '%B').')';
1302 $substitutionarray['__INVOICE_PREVIOUS_YEAR__'] = $langs->trans("PreviousYearOfInvoice").' ('.$langs->trans("Example").': '.dol_print_date(dol_time_plus_duree($sourceInvoice->date, -1, 'y'), '%Y').')';
1303 $substitutionarray['__INVOICE_YEAR__'] = $langs->trans("YearOfInvoice").' ('.$langs->trans("Example").': '.dol_print_date($sourceInvoice->date, '%Y').')';
1304 $substitutionarray['__INVOICE_NEXT_YEAR__'] = $langs->trans("NextYearOfInvoice").' ('.$langs->trans("Example").': '.dol_print_date(dol_time_plus_duree($sourceInvoice->date, 1, 'y'), '%Y').')';
1305 // Only on template invoices
1306 $substitutionarray['__INVOICE_DATE_NEXT_INVOICE_BEFORE_GEN__'] = $langs->trans("DateNextInvoiceBeforeGen").' ('.$langs->trans("Example").': '.dol_print_date(dol_time_plus_duree($sourceInvoice->date, 1, 'm'), 'dayhour').')';
1307 $substitutionarray['__INVOICE_DATE_NEXT_INVOICE_AFTER_GEN__'] = $langs->trans("DateNextInvoiceAfterGen").' ('.$langs->trans("Example").': '.dol_print_date(dol_time_plus_duree($sourceInvoice->date, 2, 'm'), 'dayhour').')';
1308 $substitutionarray['__INVOICE_COUNTER_CURRENT__'] = $langs->trans("Count");
1309 $substitutionarray['__INVOICE_COUNTER_MAX__'] = $langs->trans("MaxPeriodNumber");
1310
1311 $htmltext = '<i>'.$langs->trans("FollowingConstantsWillBeSubstituted").':<br>';
1312 foreach ($substitutionarray as $key => $val) {
1313 $htmltext .= $key.' = '.$langs->trans($val).'<br>';
1314 }
1315 $htmltext .= '</i>';
1316
1317 // Author
1318 print "<tr><td>".$langs->trans("Author")."</td><td>".$user->getFullName($langs)."</td></tr>";
1319
1320 // Payment term
1321 print "<tr><td>".$langs->trans("PaymentConditions")."</td><td>";
1322 print $form->getSelectConditionsPaiements(GETPOSTISSET('cond_reglement_id') ? GETPOSTINT('cond_reglement_id') : $sourceInvoice->cond_reglement_id, 'cond_reglement_id', -1, 0, 0, '');
1323 //$form->form_conditions_reglement($_SERVER['PHP_SELF'].'?id='.$object->id, $object->cond_reglement_id, 'cond_reglement_id');
1324 print "</td></tr>";
1325
1326 // Payment mode
1327 print "<tr><td>".$langs->trans("PaymentMode")."</td><td>";
1328 print img_picto('', 'payment', 'class="pictofixedwidth"');
1329 print $form->select_types_paiements((string) (GETPOSTISSET('mode_reglement_id') ? GETPOSTINT('mode_reglement_id') : $sourceInvoice->mode_reglement_id), 'mode_reglement_id', '', 0, 1, 0, 0, 1, '', 1);
1330 //$form->form_modes_reglement($_SERVER['PHP_SELF'].'?id='.$object->id, $object->mode_reglement_id, 'mode_reglement_id', '', 1);
1331 print "</td></tr>";
1332
1333 // Customer Bank Account
1334 print "<tr><td>".$langs->trans('DebitBankAccount')."</td><td>";
1335 $defaultRibId = $sourceInvoice->thirdparty->getDefaultRib();
1336 $form->selectRib(GETPOSTISSET('accountcustomerid') ? GETPOSTINT('accountcustomerid') : $defaultRibId, 'accountcustomerid', 'fk_soc='.$sourceInvoice->socid, 1, '', 1);
1337 print "</td></tr>";
1338
1339 print '<script>
1340 $(document).ready(function() {
1341 if($("#selectmode_reglement_id option:selected").data("code") != "' . $factureRec::PAYMENTCODETOEDITSOCIETERIB . '") {
1342 hideselectfksocieterib();
1343 }
1344 $("#selectmode_reglement_id").change(function() {
1345 if($("#selectmode_reglement_id option:selected").data("code") != "'. $factureRec::PAYMENTCODETOEDITSOCIETERIB .'") {
1346 hideselectfksocieterib(1);
1347 } else {
1348 showselectfksocieterib();
1349 }
1350 });
1351 });
1352
1353 function hideselectfksocieterib(empty = 0){
1354 $("#selectaccountcustomerid").closest("tr").hide();
1355 if(empty == 1){
1356 $("#selectaccountcustomerid").val("-1").change();
1357 }
1358 }
1359
1360 function showselectfksocieterib(){
1361 $("#selectaccountcustomerid").closest("tr").show();
1362 }
1363 </script>';
1364
1365 // Bank account
1366 if ($sourceInvoice->fk_account > 0) {
1367 print "<tr><td>".$langs->trans('BankAccount')."</td><td>";
1368 $form->formSelectAccount($_SERVER['PHP_SELF'].'?id='.$sourceInvoice->id, (string) $sourceInvoice->fk_account, 'none');
1369 print "</td></tr>";
1370 }
1371
1372 // Rule for lines dates
1373 if (getDolGlobalInt("FACTUREREC_SUPPORT_RULE_FOR_LINES")) {
1374 print "<tr><td>".$langs->trans("RuleForLinesDates")."</td><td>";
1375 print $form->getSelectRuleForLinesDates(GETPOSTISSET('rule_for_lines_dates') ? GETPOST('rule_for_lines_dates', 'alpha') : $factureRec->rule_for_lines_dates);
1376 print "</td></tr>";
1377 }
1378
1379 //extrafields
1380 $draft = new Facture($db);
1381 $draft->fetch(GETPOSTINT('facid'));
1382
1383 $extralabels = new ExtraFields($db);
1384 $extralabels = $extrafields->fetch_name_optionals_label($draft->table_element);
1385 if ($draft->fetch_optionals() > 0) {
1386 $sourceInvoice->array_options = array_merge($sourceInvoice->array_options, $draft->array_options);
1387 }
1388
1389 print $sourceInvoice->showOptionals($extrafields, 'create', $parameters);
1390
1391 // Project
1392 if (isModEnabled('project') && is_object($sourceInvoice->thirdparty) && $sourceInvoice->thirdparty->id > 0 && is_object($formproject)) {
1393 $projectid = GETPOST('projectid') ? GETPOST('projectid') : $sourceInvoice->fk_project;
1394 $langs->load('projects');
1395 print '<tr><td>'.$langs->trans('Project').'</td><td>';
1396 print img_picto('', 'project', 'class="pictofixedwidth"');
1397 $numprojet = $formproject->select_projects($sourceInvoice->thirdparty->id, $projectid, 'projectid', 0, 0, 1, 0, 0, 0, 0, '', 0, 0, '');
1398 print ' &nbsp; <a href="'.DOL_URL_ROOT.'/projet/card.php?socid='.$sourceInvoice->thirdparty->id.'&action=create&status=1&backtopage='.urlencode($_SERVER["PHP_SELF"].'?action=create&socid='.$sourceInvoice->thirdparty->id.(!empty($id) ? '&id='.$id : '')).'">'.img_object($langs->trans("AddProject"), 'add').'</a>';
1399 print '</td></tr>';
1400 }
1401
1402 // Model pdf
1403 print "<tr><td>".$langs->trans('Model')."</td><td>";
1404 include_once DOL_DOCUMENT_ROOT.'/core/modules/facture/modules_facture.php';
1406 print img_picto('', 'generic', 'class="pictofixedwidth"');
1407 // @phan-suppress-next-line PhanPluginSuspiciousParamOrder
1408 print $form->selectarray('modelpdf', $list, $conf->global->FACTURE_ADDON_PDF);
1409 print "</td></tr>";
1410
1411 // Public note
1412 print '<tr>';
1413 print '<td class="tdtop">';
1414 print $form->textwithpicto($langs->trans('NotePublic'), $htmltext, 1, 'help', '', 0, 2, 'notepublic');
1415 print '</td>';
1416 print '<td>';
1417 $doleditor = new DolEditor('note_public', $note_public, '', 80, 'dolibarr_notes', 'In', false, false, !getDolGlobalString('FCKEDITOR_ENABLE_NOTE_PUBLIC') ? 0 : 1, ROWS_3, '90%');
1418 print $doleditor->Create(1);
1419
1420 // Private note
1421 if (empty($user->socid)) {
1422 print '<tr>';
1423 print '<td class="tdtop">';
1424 print $form->textwithpicto($langs->trans('NotePrivate'), $htmltext, 1, 'help', '', 0, 2, 'noteprivate');
1425 print '</td>';
1426 print '<td>';
1427 $doleditor = new DolEditor('note_private', $note_private, '', 80, 'dolibarr_notes', 'In', false, false, !getDolGlobalString('FCKEDITOR_ENABLE_NOTE_PRIVATE') ? 0 : 1, ROWS_3, '90%');
1428 print $doleditor->Create(1);
1429 // print '<textarea name="note_private" wrap="soft" cols="70" rows="'.ROWS_3.'">'.$note_private.'.</textarea>
1430 print '</td></tr>';
1431 }
1432
1433 print "</table>";
1434
1435 print dol_get_fiche_end();
1436
1437 // Autogeneration
1438 $title = $langs->trans("Recurrence");
1439 print load_fiche_titre(img_picto('', 'recurring', 'class="pictofixedwidth"').$title, '', '');
1440
1441 print '<span class="opacitymedium">'.$langs->trans("ToCreateARecurringInvoiceGeneAuto", $langs->transnoentitiesnoconv('Module2300Name')).'</span><br><br>';
1442
1443 print dol_get_fiche_head([], '', '', 0);
1444
1445 print '<table class="border centpercent">';
1446
1447 // Frequency + unit
1448 print '<tr><td class="titlefieldcreate">'.$form->textwithpicto($langs->trans("Frequency"), $langs->transnoentitiesnoconv('toolTipFrequency'))."</td><td>";
1449 print '<input type="text" class="width50" name="frequency" value="'.GETPOST('frequency', 'int').'">&nbsp;';
1450 print $form->selectarray('unit_frequency', array('d' => $langs->trans('Day'), 'm' => $langs->trans('Month'), 'y' => $langs->trans('Year')), (GETPOST('unit_frequency') ? GETPOST('unit_frequency') : 'm'));
1451 print "</td></tr>";
1452
1453 // Date next run
1454 print "<tr><td>".$langs->trans('NextDateToExecution')."</td><td>";
1455 $date_next_execution = isset($date_next_execution) ? $date_next_execution : (GETPOSTINT('remonth') ? dol_mktime(12, 0, 0, GETPOSTINT('remonth'), GETPOSTINT('reday'), GETPOSTINT('reyear')) : -1);
1456 print $form->selectDate($date_next_execution, '', 1, 1, 0, "add", 1, 1);
1457 print "</td></tr>";
1458
1459 // Number max of generation
1460 print "<tr><td>".$langs->trans("MaxPeriodNumber")."</td><td>";
1461 print '<input type="text" class="width50" name="nb_gen_max" value="'.GETPOSTINT('nb_gen_max').'">';
1462 print "</td></tr>";
1463
1464 // Auto validate the invoice
1465 print "<tr><td>".$langs->trans("StatusOfAutoGeneratedInvoices")."</td><td>";
1466 $select = array('0' => $langs->trans('BillStatusDraft'), '1' => $langs->trans('BillStatusValidated'));
1467 print $form->selectarray('auto_validate', $select, GETPOSTINT('auto_validate'));
1468 print "</td></tr>";
1469
1470 // Auto generate document
1471 if (getDolGlobalString('INVOICE_REC_CAN_DISABLE_DOCUMENT_FILE_GENERATION')) {
1472 print "<tr><td>".$langs->trans("StatusOfGeneratedDocuments")."</td><td>";
1473 $select = array('0' => $langs->trans('DoNotGenerateDoc'), '1' => $langs->trans('AutoGenerateDoc'));
1474 print $form->selectarray('generate_pdf', $select, GETPOSTINT('generate_pdf'));
1475 print "</td></tr>";
1476 } else {
1477 print '<input type="hidden" name="generate_pdf" value="1">';
1478 }
1479
1480 print "</table>";
1481
1482 print dol_get_fiche_end();
1483
1484
1485 $title = $langs->trans("ProductsAndServices");
1486 if (!isModEnabled('service')) {
1487 $title = $langs->trans("Products");
1488 } elseif (!isModEnabled('product')) {
1489 $title = $langs->trans("Services");
1490 }
1491
1492 print load_fiche_titre($title, '', '');
1493
1494 /*
1495 * Invoice lines
1496 */
1497 print '<div class="div-table-responsive-no-min">';
1498 print '<table id="tablelines" class="noborder noshadow centpercent nomarginbottom">';
1499
1500 // Show object lines
1501 if (!empty($sourceInvoice->lines)) {
1502 $sourceInvoice->printOriginLinesList('', $selectedLines);
1503 }
1504
1505 print "</table>\n";
1506 print '<div>';
1507
1508 print '</td></tr>';
1509
1510 $flag_price_may_change = getDolGlobalString('INVOICE_REC_PRICE_MAY_CHANGE');
1511 if (!empty($flag_price_may_change)) {
1512 print '<tr><td colspan="3" class="left">';
1513 print '<select name="usenewprice" class="flat">';
1514 print '<option value="0">'.$langs->trans("AlwaysUseFixedPrice").'</option>';
1515 print '<option value="1" disabled>'.$langs->trans("AlwaysUseNewPrice").'</option>';
1516 print '</select>';
1517 print '</td></tr>';
1518 }
1519 print "</table>\n";
1520
1521 print '<br>';
1522
1523 print $form->buttonsSaveCancel("Create");
1524
1525 print "</form>\n";
1526 } else {
1527 dol_print_error(null, "Error, no invoice ".$sourceInvoice->id);
1528 }
1529} else {
1530 // View mode
1531 if ($object->id > 0) {
1532 $object->fetch_thirdparty();
1533
1534 $formconfirm = '';
1535 // Confirmation of deletion of product line
1536 if ($action == 'ask_deleteline') {
1537 $formconfirm = $form->formconfirm($_SERVER["PHP_SELF"].'?id='.$object->id.'&lineid='.$lineid, $langs->trans('DeleteProductLine'), $langs->trans('ConfirmDeleteProductLine'), 'confirm_deleteline', '', 'no', 1);
1538 }
1539 // Confirm delete of repeatable invoice
1540 if ($action == 'delete') {
1541 $formconfirm = $form->formconfirm($_SERVER["PHP_SELF"].'?id='.$object->id, $langs->trans('DeleteRepeatableInvoice'), $langs->trans('ConfirmDeleteRepeatableInvoice'), 'confirm_delete', '', 'no', 1);
1542 }
1543 // Confirmation de la suppression d'une ligne subtotal
1544 if ($action == 'ask_subtotal_deleteline') {
1545 $langs->load("subtotals");
1546 $title = "DeleteSubtotalLine";
1547 $question = "ConfirmDeleteSubtotalLine";
1548 if (GETPOST('type') == 'title') {
1549 $formconfirm = array(array('type' => 'checkbox', 'name' => 'deletecorrespondingsubtotalline', 'label' => $langs->trans("DeleteCorrespondingSubtotalLine"), 'value' => 0));
1550 $title = "DeleteTitleLine";
1551 $question = "ConfirmDeleteTitleLine";
1552 }
1553 $formconfirm = $form->formconfirm($_SERVER["PHP_SELF"].'?id='.$object->id.'&lineid='.$lineid, $langs->trans($title), $langs->trans($question), 'confirm_delete_subtotalline', $formconfirm, 'no', 1);
1554 }
1555
1556 // Subtotal line form
1557 if ($action == 'add_title_line') {
1558 $langs->load('subtotals');
1559 $type = 'title';
1560 $depth_array = $object->getPossibleLevels($langs);
1561 require dol_buildpath('/core/tpl/subtotal_create.tpl.php');
1562 } elseif ($action == 'add_subtotal_line') {
1563 $langs->load('subtotals');
1564 $type = 'subtotal';
1565 $titles = $object->getPossibleTitles();
1566 require dol_buildpath('/core/tpl/subtotal_create.tpl.php');
1567 }
1568
1569 // Call Hook formConfirm
1570 $parameters = array('formConfirm' => $formconfirm, 'lineid' => $lineid);
1571 $reshook = $hookmanager->executeHooks('formConfirm', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
1572 if (empty($reshook)) {
1573 $formconfirm .= $hookmanager->resPrint;
1574 } elseif ($reshook > 0) {
1575 $formconfirm = $hookmanager->resPrint;
1576 }
1577
1578 print $formconfirm;
1579
1580 $author = new User($db);
1581 $author->fetch($object->user_creation_id);
1582
1583 $head = invoice_rec_prepare_head($object);
1584
1585 print dol_get_fiche_head($head, 'card', $langs->trans("RepeatableInvoice"), -1, $object->picto); // Add a div
1586
1587 // Recurring invoice content
1588
1589 $linkback = '<a href="'.DOL_URL_ROOT.'/compta/facture/invoicetemplate_list.php?restore_lastsearch_values=1'.(!empty($socid) ? '&socid='.$socid : '').'">'.$langs->trans("BackToList").'</a>';
1590
1591 $morehtmlref = '';
1592 if ($action != 'editref') {
1593 $morehtmlref .= $form->editfieldkey($object->ref, 'ref', $object->ref, $object, $user->hasRight('facture', 'creer'), '', '', 0, 2);
1594 } else {
1595 $morehtmlref .= $form->editfieldval('', 'ref', $object->ref, $object, $user->hasRight('facture', 'creer'), 'string');
1596 }
1597
1598 $morehtmlref .= '<div class="refidno">';
1599 // Ref customer
1600 //$morehtmlref.=$form->editfieldkey("RefCustomer", 'ref_client', $object->ref_customer, $object, $user->hasRight('facture', 'creer'), 'string', '', 0, 1);
1601 //$morehtmlref.=$form->editfieldval("RefCustomer", 'ref_client', $object->ref_customer, $object, $user->hasRight('facture', 'creer'), 'string', '', null, null, '', 1);
1602 // Thirdparty
1603 $morehtmlref .= $object->thirdparty->getNomUrl(1, 'customer');
1604 // Project
1605 if (isModEnabled('project')) {
1606 $langs->load("projects");
1607 $morehtmlref .= '<br>';
1608 if ($user->hasRight('facture', 'creer')) {
1609 $morehtmlref .= img_picto($langs->trans("Project"), 'project', 'class="pictofixedwidth"');
1610 if ($action != 'classify') {
1611 $morehtmlref .= '<a class="editfielda" href="'.dolBuildUrl($_SERVER['PHP_SELF'], ['action' => 'classify', 'id' => $object->id], true).'">'.img_edit($langs->transnoentitiesnoconv('SetProject')).'</a> ';
1612 }
1613 $morehtmlref .= $form->form_project($_SERVER['PHP_SELF'].'?id='.$object->id, $object->socid, (string) $object->fk_project, ($action == 'classify' ? 'projectid' : 'none'), 0, 0, 0, 1, '', 'maxwidth300');
1614 } else {
1615 if (!empty($object->fk_project)) {
1616 $proj = new Project($db);
1617 $proj->fetch($object->fk_project);
1618 $morehtmlref .= ' : '.$proj->getNomUrl(1);
1619 if ($proj->title) {
1620 $morehtmlref .= ' - '.$proj->title;
1621 }
1622 } else {
1623 $morehtmlref .= '';
1624 }
1625 }
1626 }
1627 $morehtmlref .= '</div>';
1628
1629 $morehtmlstatus = '';
1630
1631 dol_banner_tab($object, 'ref', $linkback, 1, 'title', 'none', $morehtmlref, '', 0, '', $morehtmlstatus);
1632
1633 print '<div class="fichecenter">';
1634 print '<div class="fichehalfleft">';
1635 print '<div class="underbanner clearboth"></div>';
1636
1637 print '<table class="border centpercent tableforfield">';
1638
1639 // Invoice subtype
1640 if (getDolGlobalInt('INVOICE_SUBTYPE_ENABLED')) {
1641 print "<tr><td>".$langs->trans("InvoiceSubtype")."</td><td>";
1642 if ($object->subtype > 0) {
1643 print $object->getSubtypeLabel('facture_rec');
1644 }
1645 print "</td></tr>";
1646 }
1647
1648 // Author
1649 print '<tr><td class="titlefieldmiddle">'.$langs->trans("Author").'</td><td>';
1650 print $author->getNomUrl(-1);
1651 print "</td></tr>";
1652
1653 // Payment term
1654 print '<tr><td>';
1655 print '<table class="nobordernopadding centpercent"><tr><td>';
1656 print $langs->trans('PaymentConditionsShort');
1657 print '</td>';
1658 if ($action != 'editconditions' && $user->hasRight('facture', 'creer')) {
1659 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>';
1660 }
1661 print '</tr></table>';
1662 print '</td><td>';
1663 if ($action == 'editconditions') {
1664 $form->form_conditions_reglement($_SERVER['PHP_SELF'].'?facid='.$object->id, (string) $object->cond_reglement_id, 'cond_reglement_id');
1665 } else {
1666 $form->form_conditions_reglement($_SERVER['PHP_SELF'].'?facid='.$object->id, (string) $object->cond_reglement_id, 'none');
1667 }
1668 print '</td></tr>';
1669
1670 // Payment mode
1671 print '<tr><td>';
1672 print '<table class="nobordernopadding" width="100%"><tr><td>';
1673 print $langs->trans('PaymentMode');
1674 print '</td>';
1675 if ($action != 'editmode' && $user->hasRight('facture', 'creer')) {
1676 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>';
1677 }
1678 print '</tr></table>';
1679 print '</td><td>';
1680 if ($action == 'editmode') {
1681 $form->form_modes_reglement($_SERVER['PHP_SELF'].'?facid='.$object->id, (string) $object->mode_reglement_id, 'mode_reglement_id', 'CRDT', 1, 1);
1682 } else {
1683 $form->form_modes_reglement($_SERVER['PHP_SELF'].'?facid='.$object->id, (string) $object->mode_reglement_id, 'none');
1684 }
1685 print '</td></tr>';
1686
1687
1688 // Bank Account Customer
1689 if ($object->mode_reglement_code == $object::PAYMENTCODETOEDITSOCIETERIB) {
1690 print '<tr><td class="nowrap">';
1691 print '<table width="100%" class="nobordernopadding"><tr><td class="nowrap">';
1692 print $langs->trans('DebitBankAccount');
1693 print '<td>';
1694
1695 if (($action != 'editbankaccountcustomer') && $user->hasRight('facture', 'creer') && $object->statut == FactureRec::STATUS_DRAFT) {
1696 print '<td class="right"><a class="editfielda" href="' . $_SERVER["PHP_SELF"] . '?action=editbankaccountcustomer&token=' . newToken() . '&id=' . $object->id . '">' . img_edit($langs->trans('SetDebitBankAccount'), 1) . '</a></td>';
1697 }
1698 print '</tr></table>';
1699 print '</td><td>';
1700
1701 if ($action == 'editbankaccountcustomer') {
1702 $form->formRib($_SERVER['PHP_SELF'] . '?id=' . $object->id, (string) $object->fk_societe_rib, 'accountcustomerid', 'fk_soc='.$object->socid, 1, 1);
1703 } else {
1704 $form->formRib($_SERVER['PHP_SELF'] . '?id=' . $object->id, (string) $object->fk_societe_rib, 'none', '', 0, 1);
1705 }
1706 print "</td>";
1707 print '</tr>';
1708 }
1709
1710 // Bank Account
1711 print '<tr><td class="nowrap">';
1712 print '<table width="100%" class="nobordernopadding"><tr><td class="nowrap">';
1713 print $langs->trans('BankAccount');
1714 print '<td>';
1715 if (($action != 'editbankaccount') && $user->hasRight('facture', 'creer') && $object->statut == FactureRec::STATUS_DRAFT) {
1716 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>';
1717 }
1718 print '</tr></table>';
1719 print '</td><td>';
1720 if ($action == 'editbankaccount') {
1721 $form->formSelectAccount($_SERVER['PHP_SELF'].'?id='.$object->id, (string) $object->fk_account, 'fk_account', 1);
1722 } else {
1723 $form->formSelectAccount($_SERVER['PHP_SELF'].'?id='.$object->id, (string) $object->fk_account, 'none');
1724 }
1725 print "</td>";
1726 print '</tr>';
1727
1728 // Rule for line date. Need a hidden const as this generate unexpected dates into substitution variables
1729 if (getDolGlobalInt("FACTUREREC_SUPPORT_RULE_FOR_LINES")) {
1730 print '<tr><td>';
1731 print '<table class="nobordernopadding centpercent"><tr><td>';
1732 print $langs->trans('RuleForLinesDates');
1733 print '</td>';
1734 if ($action != 'editruleforlinesdates' && $user->hasRight('facture', 'creer')) {
1735 print '<td class="right"><a class="editfielda" href="'.$_SERVER["PHP_SELF"].'?action=editruleforlinesdates&token='.newToken().'&facid='.$object->id.'">'.img_edit($langs->trans('SetRuleForLinesDates'), 1).'</a></td>';
1736 }
1737 print '</tr></table>';
1738 print '</td><td>';
1739 if ($action == 'editruleforlinesdates') {
1740 $form->form_rule_for_lines_dates($_SERVER['PHP_SELF'].'?facid='.$object->id, $object->rule_for_lines_dates, 'rule_for_lines_dates');
1741 } else {
1742 $form->form_rule_for_lines_dates($_SERVER['PHP_SELF'].'?facid='.$object->id, $object->rule_for_lines_dates, 'none');
1743 }
1744 print '</td></tr>';
1745 }
1746
1747 // Extrafields
1748 include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_view.tpl.php';
1749
1750 // Model pdf
1751 print '<tr><td class="nowrap">';
1752 print '<table class="nobordernopadding centpercent"><tr><td class="nowrap">';
1753 print $langs->trans('Model');
1754 print '<td>';
1755 if (($action != 'editmodelpdf') && $user->hasRight('facture', 'creer') && $object->statut == FactureRec::STATUS_DRAFT) {
1756 print '<td class="right"><a class="editfielda" href="'.$_SERVER["PHP_SELF"].'?action=editmodelpdf&token='.newToken().'&id='.$object->id.'">'.img_edit($langs->trans('SetModel'), 1).'</a></td>';
1757 }
1758 print '</tr></table>';
1759 print '</td><td>';
1760 if ($action == 'editmodelpdf') {
1761 include_once DOL_DOCUMENT_ROOT.'/core/modules/facture/modules_facture.php';
1762 $list = array();
1763 $models = ModelePDFFactures::liste_modeles($db);
1764 foreach ($models as $k => $model) {
1765 $list[] = str_replace(':', '|', $k).':'.$model;
1766 }
1767 $select = 'select;'.implode(',', $list);
1768 print $form->editfieldval($langs->trans("Model"), 'modelpdf', $object->model_pdf, $object, $user->hasRight('facture', 'creer'), $select);
1769 } else {
1770 print $object->model_pdf;
1771 }
1772 print "</td>";
1773 print '</tr>';
1774
1775 // Other attributes
1776 $cols = 2;
1777
1778
1779 print '</table>';
1780
1781 print '</div>';
1782 print '<div class="fichehalfright">';
1783
1784 print '<!-- amounts -->'."\n";
1785 print '<div class="underbanner clearboth"></div>'."\n";
1786
1787 // Recurrence
1788 $title = $langs->trans("Recurrence");
1789
1790 print '<table class="border tableforfield centpercent">';
1791
1792 include DOL_DOCUMENT_ROOT.'/core/tpl/object_currency_amount.tpl.php';
1793
1794 $sign = 1;
1795 if (getDolGlobalString('INVOICE_POSITIVE_CREDIT_NOTE_SCREEN') && $object->type == $object::TYPE_CREDIT_NOTE) {
1796 $sign = -1; // We invert sign for output
1797 }
1798
1799 // Amount (excl. tax)
1800 print '<tr><td class="titlefieldmiddle">'.$langs->trans("AmountHT").'</td>';
1801 print '<td class="nowraponall amountcard right">'.price($sign * $object->total_ht, 0, $langs, 1, -1, -1, $conf->currency).'</td>';
1802 if (isModEnabled("multicurrency") && ($object->multicurrency_code && $object->multicurrency_code != $conf->currency)) {
1803 // Multicurrency Amount HT
1804 print '<td class="nowraponall amountcard right">' . price($sign * $object->multicurrency_total_ht, 0, $langs, 0, -1, -1, $object->multicurrency_code) . '</td>';
1805 }
1806 print '</tr>';
1807
1808 // Amount tax
1809 print '<tr><td>'.$langs->trans("AmountVAT").'</td>';
1810 print '<td class="nowrap amountcard right">'.price($sign * $object->total_tva, 0, $langs, 1, -1, -1, $conf->currency).'</td>';
1811 if (isModEnabled("multicurrency") && ($object->multicurrency_code && $object->multicurrency_code != $conf->currency)) {
1812 // Multicurrency Amount VAT
1813 print '<td class="nowraponall amountcard right">' . price($sign * $object->multicurrency_total_tva, 0, $langs, 0, -1, -1, $object->multicurrency_code) . '</td>';
1814 }
1815 print '</tr>';
1816
1817 // Amount Local Taxes
1818 if (($mysoc->localtax1_assuj == "1" && $mysoc->useLocalTax(1)) || $object->total_localtax1 != 0) { // Localtax1
1819 print '<tr>';
1820 print '<td class="titlefieldmiddle">'.$langs->transcountry("AmountLT1", $mysoc->country_code).'</td>';
1821 print '<td class="nowraponall amountcard right">'.price($sign * $object->total_localtax1, 1, '', 1, - 1, - 1, $conf->currency).'</td></tr>';
1822 if (isModEnabled("multicurrency") && ($object->multicurrency_code && $object->multicurrency_code != $conf->currency)) {
1823 $object->multicurrency_total_localtax1 = (float) price2num($object->total_localtax1 * $object->multicurrency_tx, 'MT');
1824
1825 print '<td class="nowraponall amountcard right">' . price($sign * $object->multicurrency_total_localtax1, 0, $langs, 0, -1, -1, $object->multicurrency_code) . '</td>';
1826 }
1827 print '</tr>';
1828 }
1829
1830 if (($mysoc->localtax2_assuj == "1" && $mysoc->useLocalTax(2)) || $object->total_localtax2 != 0) { // Localtax2
1831 print '<tr>';
1832 print '<td>'.$langs->transcountry("AmountLT2", $mysoc->country_code).'</td>';
1833 print '<td class=nowraponall amountcard right">'.price($sign * $object->total_localtax2, 1, '', 1, - 1, - 1, $conf->currency).'</td></tr>';
1834 if (isModEnabled("multicurrency") && ($object->multicurrency_code && $object->multicurrency_code != $conf->currency)) {
1835 $object->multicurrency_total_localtax2 = (float) price2num($object->total_localtax2 * $object->multicurrency_tx, 'MT');
1836
1837 print '<td class="nowraponall amountcard right">' . price($sign * $object->multicurrency_total_localtax2, 0, $langs, 0, -1, -1, $object->multicurrency_code) . '</td>';
1838 }
1839 print '</tr>';
1840 }
1841
1842 // Add the revenue stamp
1843 /*
1844 if ($selleruserevenustamp) {
1845 print '<tr><td class="titlefieldmiddle">';
1846 print '<table class="nobordernopadding centpercent"><tr><td>';
1847 print $langs->trans('RevenueStamp');
1848 print '</td>';
1849 if ($action != 'editrevenuestamp' && $object->status == $object::STATUS_DRAFT && $usercancreate) {
1850 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>';
1851 }
1852 print '</tr></table>';
1853 print '</td><td class="nowrap amountcard right">';
1854 if ($action == 'editrevenuestamp') {
1855 print '<form action="'.$_SERVER["PHP_SELF"].'?id='.$object->id.'" method="post">';
1856 print '<input type="hidden" name="token" value="'.newToken().'">';
1857 print '<input type="hidden" name="action" value="setrevenuestamp">';
1858 print '<input type="hidden" name="revenuestamp" id="revenuestamp_val" value="'.price2num($object->revenuestamp).'">';
1859 print '<input type="hidden" name="backtopage" value="'.$backtopage.'">';
1860 print $formother->select_revenue_stamp('', 'revenuestamp_type', $mysoc->country_code);
1861 print ' &rarr; <span id="revenuestamp_span"></span>';
1862 print ' <input type="submit" class="button buttongen button-save small" value="'.$langs->trans('Modify').'">';
1863 print '</form>';
1864 print " <script>
1865 $(document).ready(function(){
1866 js_recalculate_revenuestamp();
1867 $('select[name=revenuestamp_type]').on('change',function(){
1868 js_recalculate_revenuestamp();
1869 });
1870 });
1871 function js_recalculate_revenuestamp(){
1872 var valselected = $('select[name=revenuestamp_type]').val();
1873 console.log('Calculate revenue stamp from '+valselected);
1874 var revenue = 0;
1875 if (valselected.indexOf('%') == -1)
1876 {
1877 revenue = valselected;
1878 }
1879 else
1880 {
1881 var revenue_type = parseFloat(valselected);
1882 var amount_net = ".round($object->total_ht, 2).";
1883 revenue = revenue_type * amount_net / 100;
1884 revenue = revenue.toFixed(2);
1885 }
1886 $('#revenuestamp_val').val(revenue);
1887 $('#revenuestamp_span').html(revenue);
1888 }
1889 </script>";
1890 } else {
1891 print price($object->revenuestamp, 1, '', 1, -1, -1, $conf->currency);
1892 }
1893 print '</td></tr>';
1894 }
1895 */
1896
1897 // Amount TTC
1898 print '<tr><td>'.$langs->trans("AmountTTC").'</td><td class="nowraponall amountcard right">'.price($sign * $object->total_ttc, 0, $langs, 1, -1, -1, $conf->currency).'</td>';
1899 if (isModEnabled("multicurrency") && ($object->multicurrency_code && $object->multicurrency_code != $conf->currency)) {
1900 // Multicurrency Amount TTC
1901 print '<td class="nowrap amountcard right">' . price($sign * $object->multicurrency_total_ttc, 0, $langs, 0, -1, -1, $object->multicurrency_code) . '</td>';
1902 }
1903 print '</tr>';
1904
1905 // Recurring info
1906 print '<tr class="liste_titre"><td class="liste_titre">'.img_picto('', 'recurring', 'class="pictofixedwidth"').$title.'</td>';
1907 print '<td></td>';
1908 if (isModEnabled("multicurrency") && ($object->multicurrency_code && $object->multicurrency_code != $conf->currency)) {
1909 print '<td></td>';
1910 }
1911 print '</tr>';
1912
1913 // if "frequency" is empty or = 0, the recurrence is disabled
1914 print '<tr><td style="width: 50%">';
1915 print '<table class="nobordernopadding" width="100%"><tr><td>';
1916 print $langs->trans('Frequency');
1917 print '</td>';
1918 if ($action != 'editfrequency' && $user->hasRight('facture', 'creer')) {
1919 print '<td class="right"><a class="editfielda" href="'.$_SERVER["PHP_SELF"].'?action=editfrequency&token='.newToken().'&facid='.$object->id.'">'.img_edit($langs->trans('Edit'), 1).'</a></td>';
1920 }
1921 print '</tr></table>';
1922 print '</td><td>';
1923 if ($action == 'editfrequency') {
1924 print '<form method="post" action="'.$_SERVER["PHP_SELF"].'?facid='.$object->id.'">';
1925 print '<input type="hidden" name="action" value="setfrequency">';
1926 print '<input type="hidden" name="token" value="'.newToken().'">';
1927 print '<table class="nobordernopadding">';
1928 print '<tr><td>';
1929 print '<input type="text" name="frequency" class="width50 marginrightonly right" value="'.$object->frequency.'">';
1930 print $form->selectarray('unit_frequency', array('d' => $langs->trans('Day'), 'm' => $langs->trans('Month'), 'y' => $langs->trans('Year')), ($object->unit_frequency ? $object->unit_frequency : 'm'));
1931 print '</td>';
1932 print '<td class="left"><input type="submit" class="button button-edit smallpaddingimp" value="'.$langs->trans("Modify").'"></td>';
1933 print '</tr></table></form>';
1934 } else {
1935 if ($object->frequency > 0) {
1936 print $langs->trans('FrequencyPer_'.$object->unit_frequency, $object->frequency);
1937 } else {
1938 print '<span class="opacitymedium">'.$langs->trans("NotARecurringInvoiceTemplate").'</span>';
1939 }
1940 }
1941 print '</td>';
1942 if (isModEnabled("multicurrency") && ($object->multicurrency_code && $object->multicurrency_code != $conf->currency)) {
1943 print '<td></td>';
1944 }
1945 print '</tr>';
1946
1947 if ($object->frequency > 0) {
1948 // Date when (next invoice generation)
1949 print '<tr><td>';
1950 if ($action == 'date_when' || $object->frequency > 0) {
1951 print $form->editfieldkey($langs->trans("NextDateToExecution"), 'date_when', $object->date_when, $object, $user->hasRight('facture', 'creer'), 'day');
1952 } else {
1953 print $langs->trans("NextDateToExecution");
1954 }
1955 print '</td><td>';
1956 if ($action == 'date_when' || $object->frequency > 0) {
1957 print $form->editfieldval($langs->trans("NextDateToExecution"), 'date_when', $object->date_when, $object, $user->hasRight('facture', 'creer'), 'day', $object->date_when, null, '', '', 0, 'strikeIfMaxNbGenReached');
1958 }
1959 //var_dump(dol_print_date($object->date_when+60, 'dayhour').' - '.dol_print_date($now, 'dayhour'));
1960 if (!$object->isMaxNbGenReached()) {
1961 if (!$object->suspended && $action != 'editdate_when' && $object->frequency > 0 && $object->date_when && $object->date_when < $now) {
1962 print img_warning($langs->trans("Late"));
1963 }
1964 } else {
1965 print img_info($langs->trans("MaxNumberOfGenerationReached"));
1966 }
1967 print '</td>';
1968 if (isModEnabled("multicurrency") && ($object->multicurrency_code && $object->multicurrency_code != $conf->currency)) {
1969 print '<td></td>';
1970 }
1971 print '</tr>';
1972
1973 // Max period / Rest period
1974 print '<tr><td>';
1975 if ($action == 'nb_gen_max' || $object->frequency > 0) {
1976 print $form->editfieldkey($langs->trans("MaxPeriodNumber"), 'nb_gen_max', (string) $object->nb_gen_max, $object, $user->hasRight('facture', 'creer'));
1977 } else {
1978 print $langs->trans("MaxPeriodNumber");
1979 }
1980 print '</td><td>';
1981 if ($action == 'nb_gen_max' || $object->frequency > 0) {
1982 print $form->editfieldval($langs->trans("MaxPeriodNumber"), 'nb_gen_max', $object->nb_gen_max ? $object->nb_gen_max : '', $object, $user->hasRight('facture', 'creer'));
1983 } else {
1984 print '';
1985 }
1986 print '</td>';
1987 if (isModEnabled("multicurrency") && ($object->multicurrency_code && $object->multicurrency_code != $conf->currency)) {
1988 print '<td></td>';
1989 }
1990 print '</tr>';
1991
1992 // Status of auto generated invoices
1993 print '<tr><td>';
1994 if ($action == 'auto_validate' || $object->frequency > 0) {
1995 print $form->editfieldkey($langs->trans("StatusOfAutoGeneratedInvoices"), 'auto_validate', (string) $object->auto_validate, $object, $user->hasRight('facture', 'creer'));
1996 } else {
1997 print $langs->trans("StatusOfAutoGeneratedInvoices");
1998 }
1999 print '</td><td>';
2000 $select = 'select;0:'.$langs->trans('BillStatusDraft').',1:'.$langs->trans('BillStatusValidated');
2001 if ($action == 'auto_validate' || $object->frequency > 0) {
2002 print $form->editfieldval($langs->trans("StatusOfAutoGeneratedInvoices"), 'auto_validate', $object->auto_validate, $object, $user->hasRight('facture', 'creer'), $select);
2003 }
2004 print '</td>';
2005 if (isModEnabled("multicurrency") && ($object->multicurrency_code && $object->multicurrency_code != $conf->currency)) {
2006 print '<td></td>';
2007 }
2008 print '</tr>';
2009 // Auto generate documents
2010 if (getDolGlobalString('INVOICE_REC_CAN_DISABLE_DOCUMENT_FILE_GENERATION')) {
2011 print '<tr>';
2012 print '<td>';
2013 if ($action == 'generate_pdf' || $object->frequency > 0) {
2014 print $form->editfieldkey($langs->trans("StatusOfGeneratedDocuments"), 'generate_pdf', (string) $object->generate_pdf, $object, $user->hasRight('facture', 'creer'));
2015 } else {
2016 print $langs->trans("StatusOfGeneratedDocuments");
2017 }
2018 print '</td>';
2019 print '<td>';
2020 $select = 'select;0:'.$langs->trans('DoNotGenerateDoc').',1:'.$langs->trans('AutogenerateDoc');
2021 if ($action == 'generate_pdf' || $object->frequency > 0) {
2022 print $form->editfieldval($langs->trans("StatusOfGeneratedDocuments"), 'generate_pdf', $object->generate_pdf, $object, $user->hasRight('facture', 'creer'), $select);
2023 }
2024 print '</td>';
2025 if (isModEnabled("multicurrency") && ($object->multicurrency_code && $object->multicurrency_code != $conf->currency)) {
2026 print '<td></td>';
2027 }
2028 print '</tr>';
2029 } else {
2030 print '<input type="hidden" name="generate_pdf" value="1">';
2031 }
2032 }
2033
2034 print '</table>';
2035
2036 // Frequencry/Recurring section
2037 if ($object->frequency > 0) {
2038 print '<br>';
2039
2040 if (!isModEnabled('cron')) {
2041 print info_admin($langs->trans("EnableAndSetupModuleCron", $langs->transnoentitiesnoconv("Module2300Name")));
2042 }
2043
2044 print '<div class="underbanner clearboth"></div>';
2045 print '<table class="border centpercent tableforfield">';
2046
2047 // Nb of generation already done
2048 print '<tr><td style="width: 50%">'.$langs->trans("NbOfGenerationDone").'</td>';
2049 print '<td>';
2050 print $object->nb_gen_done ? $object->nb_gen_done : '0';
2051 print '</td>';
2052 print '</tr>';
2053
2054 // Date last
2055 print '<tr><td>';
2056 print $langs->trans("DateLastGeneration");
2057 print '</td><td>';
2058 print dol_print_date($object->date_last_gen, 'dayhour');
2059 print '</td>';
2060 print '</tr>';
2061
2062 print '</table>';
2063
2064 print '<br>';
2065 }
2066
2067 print '</div>';
2068 print '</div>';
2069
2070 print '<div class="clearboth"></div><br>';
2071
2072
2073 // Lines
2074 print '<form name="addproduct" id="addproduct" action="'.$_SERVER["PHP_SELF"].'?id='.$object->id.(($action != 'editline') ? '#add' : '#line_'.GETPOSTINT('lineid')).'" method="POST">';
2075 print '<input type="hidden" name="token" value="' . newToken().'">';
2076 print '<input type="hidden" name="action" value="' . (($action != 'editline') ? 'addline' : 'updateline').'">';
2077 print '<input type="hidden" name="mode" value="">';
2078 print '<input type="hidden" name="id" value="' . $object->id.'">';
2079 print '<input type="hidden" name="page_y" value="">';
2080
2081 if (!empty($conf->use_javascript_ajax) && $object->statut == 0) {
2082 if (isModEnabled('subtotals')) {
2083 include DOL_DOCUMENT_ROOT.'/core/tpl/subtotal_ajaxrow.tpl.php';
2084 } else {
2085 include DOL_DOCUMENT_ROOT . '/core/tpl/ajaxrow.tpl.php';
2086 }
2087 }
2088
2089 print '<div class="div-table-responsive-no-min">';
2090 print '<table id="tablelines" class="noborder noshadow centpercent nomarginbottom">';
2091 // Show object lines
2092 if (!empty($object->lines)) {
2093 $canchangeproduct = 1;
2094 $object->printObjectLines($action, $mysoc, $object->thirdparty, $lineid, 0); // No date selector for template invoice
2095 }
2096
2097 // Form to add new line
2098 if ($object->status == $object::STATUS_DRAFT && $user->hasRight('facture', 'creer') && $action != 'valid' && $action != 'editline') {
2099 if ($action != 'editline') {
2100 // Add free products/services
2101
2102 $parameters = array();
2103 $reshook = $hookmanager->executeHooks('formAddObjectLine', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
2104 if ($reshook < 0) {
2105 setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
2106 }
2107 if (empty($reshook)) {
2108 $object->formAddObjectLine(0, $mysoc, $object->thirdparty);
2109 } // No date selector for template invoice
2110 }
2111 }
2112
2113 print "</table>\n";
2114 print '</div>';
2115
2116 print "</form>\n";
2117
2118 print dol_get_fiche_end();
2119
2120
2121 /*
2122 * Action bar
2123 */
2124 print '<div class="tabsAction">';
2125
2126 $parameters = array();
2127 $reshook = $hookmanager->executeHooks('addMoreActionsButtons', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
2128 if (empty($reshook)) {
2129 $params = array(
2130 'attr' => array(
2131 'class' => 'classfortooltip',
2132 ),
2133 );
2134
2135 // Subtotal
2136 if (empty($object->suspended) && isModEnabled('subtotals')
2137 && (getDolGlobalInt('SUBTOTAL_TITLE_'.strtoupper($object->element)) || getDolGlobalInt('SUBTOTAL_'.strtoupper($object->element)))) {
2138 $langs->load("subtotals");
2139
2140 $url_button = array();
2141
2142 $url_button[] = array(
2143 'lang' => 'subtotals',
2144 'enabled' => (isModEnabled('invoice') && $object->status == Facture::STATUS_DRAFT && getDolGlobalInt('SUBTOTAL_TITLE_'.strtoupper($object->element))),
2145 'perm' => (bool) $usercancreate,
2146 'label' => $langs->trans('AddTitleLine'),
2147 'url' => '/compta/facture/card-rec.php?id='.$object->id.'&action=add_title_line&token='.newToken()
2148 );
2149
2150 $url_button[] = array(
2151 'lang' => 'subtotals',
2152 'enabled' => (isModEnabled('invoice') && $object->status == Facture::STATUS_DRAFT && getDolGlobalInt('SUBTOTAL_'.strtoupper($object->element))),
2153 'perm' => (bool) $usercancreate,
2154 'label' => $langs->trans('AddSubtotalLine'),
2155 'url' => '/compta/facture/card-rec.php?id='.$object->id.'&action=add_subtotal_line&token='.newToken()
2156 );
2157 print dolGetButtonAction('', $langs->trans('Subtotal'), 'default', $url_button, '', true);
2158 }
2159
2160 if (empty($object->suspended)) {
2161 if ($user->hasRight('facture', 'creer')) {
2162 if (!empty($object->frequency) && $object->nb_gen_max > 0 && ($object->nb_gen_done >= $object->nb_gen_max)) {
2163 print '<div class="inline-block divButAction"><a class="butActionRefused classfortooltip" href="#" title="' . dol_escape_htmltag($langs->trans("MaxGenerationReached")) . '">' . $langs->trans("CreateBill") . '</a></div>';
2164 } else {
2165 if (empty($object->frequency) || $object->date_when <= $nowlasthour) {
2166 print '<div class="inline-block divButAction"><a class="butAction" href="' . DOL_URL_ROOT . '/compta/facture/card.php?action=create&socid=' . $object->thirdparty->id . '&fac_rec=' . $object->id . '">' . $langs->trans("CreateBill") . '</a></div>';
2167 } else {
2168 print '<div class="inline-block divButAction"><a class="butActionRefused classfortooltip" href="#" title="' . dol_escape_htmltag($langs->trans("DateIsNotEnough")) . '">' . $langs->trans("CreateBill") . '</a></div>';
2169 }
2170 }
2171 } else {
2172 print '<div class="inline-block divButAction"><a class="butActionRefused classfortooltip" href="#">' . $langs->trans("CreateBill") . '</a></div>';
2173 }
2174 }
2175
2176 if ($user->hasRight('facture', 'creer')) {
2177 if (empty($object->suspended)) {
2178 print '<div class="inline-block divButAction"><a class="butActionDelete" href="'.$_SERVER["PHP_SELF"].'?action=disable&id='.$object->id.'&token='.newToken().'">'.$langs->trans("Disable").'</a></div>';
2179 } else {
2180 print '<div class="inline-block divButAction"><a class="butAction" href="'.$_SERVER["PHP_SELF"].'?action=enable&id='.$object->id.'&token='.newToken().'">'.$langs->trans("Enable").'</a></div>';
2181 }
2182 }
2183
2184 // Delete
2185 print dolGetButtonAction($langs->trans("Delete"), '', 'delete', $_SERVER["PHP_SELF"] . '?id=' . $object->id . '&action=delete&token=' . newToken(), 'delete', $user->hasRight('facture', 'supprimer'));
2186 }
2187 print '</div>';
2188
2189
2190
2191 print '<div class="fichecenter"><div class="fichehalfleft">';
2192 print '<a name="builddoc"></a>'; // ancre
2193
2194
2195 // Show links to link elements
2196 $tmparray = $form->showLinkToObjectBlock($object, array(), array('invoice'), 1);
2197 $linktoelem = $tmparray['linktoelem'];
2198 $htmltoenteralink = $tmparray['htmltoenteralink'];
2199 print $htmltoenteralink;
2200
2201 $somethingshown = $form->showLinkedObjectBlock($object, $linktoelem);
2202
2203
2204 print '</div>';
2205 print '<div class="fichehalfright">';
2206
2207 $MAXEVENT = 10;
2208
2209 $morehtmlcenter = '<div class="nowraponall">';
2210 //$morehtmlcenter .= dolGetButtonTitle($langs->trans('FullConversation'), '', 'fa fa-comments imgforviewmode', DOL_URL_ROOT.'/compta/facture/messaging.php?id='.$object->id);
2211 $morehtmlcenter .= dolGetButtonTitle($langs->trans('FullList'), '', 'fa fa-bars imgforviewmode', DOL_URL_ROOT.'/compta/facture/agenda-rec.php?id='.$object->id);
2212 $morehtmlcenter .= '</div>';
2213
2214 // List of actions on element
2215 include_once DOL_DOCUMENT_ROOT.'/core/class/html.formactions.class.php';
2216 $formactions = new FormActions($db);
2217 $somethingshown = $formactions->showactions($object, $object->element, (is_object($object->thirdparty) ? $object->thirdparty->id : 0), 1, '', $MAXEVENT, '', $morehtmlcenter);
2218
2219 print '</div>';
2220 print '</div>';
2221 } else {
2222 print $langs->trans("NoRecordFound");
2223 }
2224}
2225
2226// End of page
2227llxFooter();
2228$db->close();
$id
Support class for third parties, contacts, members, users or resources.
Definition account.php:47
if(! $sortfield) if(! $sortorder) $object
Definition account.php:100
llxFooter($comment='', $zone='private', $disabledoutputofmessages=0)
Empty footer.
Definition wrapper.php:91
if(!defined('NOREQUIRESOC')) if(!defined( 'NOREQUIRETRAN')) if(!defined('NOTOKENRENEWAL')) if(!defined( 'NOREQUIREMENU')) if(!defined('NOREQUIREHTML')) if(!defined( 'NOREQUIREAJAX')) llxHeader($head='', $title='', $help_url='', $target='', $disablejs=0, $disablehead=0, $arrayofjs='', $arrayofcss='', $morequerystring='', $morecssonbody='', $replacemainareaby='', $disablenofollow=0, $disablenoindex=0)
Empty header.
Definition wrapper.php:73
const STATUS_DRAFT
Draft status.
Class to manage a WYSIWYG editor.
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.
Class to manage invoice lines of templates.
Class to manage invoice templates.
Class to manage building of HTML components.
Class to manage generation of HTML components Only common components must be here.
Class permettant la generation de composants html autre Only common components are here.
Class to manage building of HTML components.
static liste_modeles($db, $maxfilenamelength=0)
Return list of active generation modules.
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.
getCountry($searchkey, $withcode='', $dbtouse=null, $outputlangs=null, $entconv=1, $searchlabel='')
Return country label, code or id from an id, code or label.
global $mysoc
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:649
dol_time_plus_duree($time, $duration_value, $duration_unit, $ruleforendofmonth=0)
Add a delay to a date.
Definition date.lib.php:125
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_now($mode='gmt')
Return date for now.
dol_mktime($hour, $minute, $second, $month, $day, $year, $gm='auto', $check=1)
Return a timestamp date built from detailed information (by default a local PHP server timestamp) Rep...
setEventMessages($mesg, $mesgs, $style='mesgs', $messagekey='', $noduplicate=0, $attop=0)
Set event messages in dol_events session object.
img_picto($titlealt, $picto, $moreatt='', $pictoisfullpath=0, $srconly=0, $notitle=0, $alt='', $morecss='', $marginleftonlyshort=2, $allowothertags=array())
Show picto whatever it's its name (generic function)
img_warning($titlealt='default', $moreatt='', $morecss='pictowarning')
Show warning logo.
GETPOSTINT($paramname, $method=0)
Return the value of a $_GET or $_POST supervariable, converted into integer.
dol_get_fiche_head($links=array(), $active='', $title='', $notab=0, $picto='', $pictoisfullpath=0, $morehtmlright='', $morecss='', $limittoshow=0, $moretabssuffix='', $dragdropfile=0, $morecssdiv='')
Show tabs of a record.
price2num($amount, $rounding='', $option=0)
Function that return a number with universal decimal format (decimal separator is '.
dolGetButtonTitle($label, $helpText='', $iconClass='fa fa-file', $url='', $id='', $status=1, $params=array())
Function dolGetButtonTitle : this kind of buttons are used in title in list.
dol_get_fiche_end($notab=0)
Return tab footer of a card.
dol_eval($s, $returnvalue=1, $hideerrors=1, $onlysimplestring='1')
Replace eval function to add more security.
img_object($titlealt, $picto, $moreatt='', $pictoisfullpath=0, $srconly=0, $notitle=0, $allowothertags=array())
Show a picto called object_picto (generic function)
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.
getDolGlobalInt($key, $default=0)
Return a Dolibarr global constant int value.
newToken()
Return the value of token currently saved into session with name 'newtoken'.
GETPOSTFLOAT($paramname, $rounding='', $option=2)
Return the value of a $_GET or $_POST supervariable, converted into float.
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.
dol_buildpath($path, $type=0, $returnemptyifnotfound=0)
Return path of url or filesystem.
dol_clone($srcobject, $native=2)
Create a clone of instance of object (new instance with same value for each properties) With native =...
dol_print_date($time, $format='', $tzoutput='auto', $outputlangs=null, $encodetooutput=false, $decorate=0)
Output date in a string format according to outputlangs (or langs if not defined).
dol_print_error($db=null, $error='', $errors=null)
Displays error message system with all the information to facilitate the diagnosis and the escalation...
load_fiche_titre($title, $morehtmlright='', $picto='generic', $pictoisfullpath=0, $id='', $morecssontable='', $morehtmlcenter='', $morecssonpicto='widthpictotitle')
Load a title with picto.
getDolGlobalString($key, $default='')
Return a Dolibarr global constant string value.
isModEnabled($module)
Is Dolibarr module enabled.
info_admin($text, $infoonimgalt=0, $nodiv=0, $admin='1', $morecss='hideonsmartphone', $textfordropdown='', $picto='')
Show information in HTML for admin users or standard users.
img_edit($titlealt='default', $float=0, $other='')
Show logo edit/modify fiche.
get_localtax($vatrate, $local, $thirdparty_buyer=null, $thirdparty_seller=null, $vatnpr=0)
Return localtax rate for a particular VAT rate, when selling a product with vat $vatrate,...
img_info($titlealt='default')
Show info logo.
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...
invoice_rec_prepare_head($object)
Return array head with list of tabs to view object information.
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.