dolibarr 25.0.0-alpha
invoice.php
Go to the documentation of this file.
1<?php
2/* Copyright (C) 2018 Andreu Bisquerra <jove@bisquerra.com>
3 * Copyright (C) 2021 Nicolas ZABOURI <info@inovea-conseil.com>
4 * Copyright (C) 2022-2023 Christophe Battarel <christophe.battarel@altairis.fr>
5 * Copyright (C) 2024-2026 MDW <mdeweerd@users.noreply.github.com>
6 * Copyright (C) 2024-2026 Frédéric France <frederic.france@free.fr>
7 * Copyright (C) 2026 Jose Martinez <jose.martinez@pichinov.com>
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 3 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program. If not, see <https://www.gnu.org/licenses/>.
21 */
22
29// if (! defined('NOREQUIREUSER')) define('NOREQUIREUSER', '1'); // Not disabled cause need to load personalized language
30// if (! defined('NOREQUIREDB')) define('NOREQUIREDB', '1'); // Not disabled cause need to load personalized language
31// if (! defined('NOREQUIRESOC')) define('NOREQUIRESOC', '1');
32// if (! defined('NOREQUIRETRAN')) define('NOREQUIRETRAN', '1');
33
34if (!defined('NOTOKENRENEWAL')) {
35 define('NOTOKENRENEWAL', '1');
36}
37if (!defined('NOREQUIREMENU')) {
38 define('NOREQUIREMENU', '1');
39}
40if (!defined('NOREQUIREHTML')) {
41 define('NOREQUIREHTML', '1');
42}
43if (!defined('NOREQUIREAJAX')) {
44 define('NOREQUIREAJAX', '1');
45}
46
47// Load Dolibarr environment
48if (!defined('INCLUDE_PHONEPAGE_FROM_PUBLIC_PAGE')) {
49 require '../main.inc.php';
50}
51require_once DOL_DOCUMENT_ROOT.'/core/class/html.form.class.php';
52require_once DOL_DOCUMENT_ROOT.'/core/class/hookmanager.class.php';
53require_once DOL_DOCUMENT_ROOT.'/compta/facture/class/facture.class.php';
54require_once DOL_DOCUMENT_ROOT.'/compta/paiement/class/paiement.class.php';
55require_once DOL_DOCUMENT_ROOT.'/contact/class/contact.class.php';
65$hookmanager->initHooks(array('takeposinvoice'));
66
67$langs->loadLangs(array("companies", "commercial", "bills", "cashdesk", "stocks", "banks"));
68
69$action = GETPOST('action', 'aZ09');
70$idproduct = GETPOSTINT('idproduct');
71$place = (GETPOST('place', 'aZ09') ? GETPOST('place', 'aZ09') : 0); // $place is id of table for Bar or Restaurant
72$placeid = 0; // $placeid is ID of invoice
73$mobilepage = GETPOST('mobilepage', 'alpha');
74$batch = GETPOST('batch', 'alpha');
75$sourceinvoiceid = GETPOSTINT('sourceinvoiceid');
76
77// Terminal is stored into $_SESSION["takeposterminal"];
78
79if (!$user->hasRight('takepos', 'run') && !defined('INCLUDE_PHONEPAGE_FROM_PUBLIC_PAGE')) {
80 accessforbidden('No permission to use the TakePOS');
81}
82
83if (defined('INCLUDE_PHONEPAGE_FROM_PUBLIC_PAGE')) {
84 // DIRECT LINK TO THIS PAGE FROM MOBILE AND NO TERMINAL SELECTED
85 if ($_SESSION["takeposterminal"] == "") {
86 if (getDolGlobalString('TAKEPOS_NUM_TERMINALS') == "1") {
87 $_SESSION["takeposterminal"] = 1;
88 } else {
89 header("Location: ".DOL_URL_ROOT."/takepos/index.php");
90 exit;
91 }
92 }
93}
94
95
96$takeposterminal = isset($_SESSION["takeposterminal"]) ? $_SESSION["takeposterminal"] : '';
97
98// When session has expired (selected terminal has been lost from session), redirect to the terminal selection.
99if (empty($takeposterminal)) {
100 if (getDolGlobalInt('TAKEPOS_NUM_TERMINALS') == 1) {
101 $_SESSION["takeposterminal"] = 1; // Use terminal 1 if there is only 1 terminal
102 $takeposterminal = 1;
103 } elseif (!empty($_COOKIE["takeposterminal"])) {
104 $_SESSION["takeposterminal"] = preg_replace('/[^a-zA-Z0-9_\-]/', '', $_COOKIE["takeposterminal"]); // Restore takeposterminal from previous session
105 $takeposterminal = $_SESSION["takeposterminal"];
106 } else {
107 print <<<SCRIPT
108<script type="text/javascript">
109 jQuery(function() {
110 ModalBox('ModalTerminal');
111 });
112</script>
113SCRIPT;
114 exit;
115 }
116}
117
118
125function fail($message)
126{
127 header($_SERVER['SERVER_PROTOCOL'].' 500 Internal Server Error', true, 500);
128 die($message);
129}
130
138function takeposDeleteLineWithChildren($invoice, $lineid)
139{
140 $lineid = (int) $lineid;
141 if ($lineid <= 0) {
142 return 0;
143 }
144
145 $childrenbyparent = array();
146 if (is_array($invoice->lines)) {
147 foreach ($invoice->lines as $line) {
148 $parentid = (int) $line->fk_parent_line;
149 if ($parentid > 0) {
150 $childrenbyparent[$parentid][] = (int) $line->id;
151 }
152 }
153 }
154
155 $linestodelete = array();
156 $stack = array($lineid);
157 while (!empty($stack)) {
158 $currentlineid = array_pop($stack);
159 if (in_array($currentlineid, $linestodelete, true)) {
160 continue;
161 }
162
163 $linestodelete[] = $currentlineid;
164 if (!empty($childrenbyparent[$currentlineid])) {
165 foreach ($childrenbyparent[$currentlineid] as $childlineid) {
166 $stack[] = $childlineid;
167 }
168 }
169 }
170
171 // Delete supplements before their parent line so no orphan line remains visible on receipts.
172 foreach (array_reverse($linestodelete) as $deletelineid) {
173 $result = $invoice->deleteLine($deletelineid);
174 if ($result < 0) {
175 return $result;
176 }
177 }
178
179 return 1;
180}
181
182
183
184$number = (float) GETPOST('number', 'alpha');
185$idline = GETPOSTINT('idline');
186$selectedline = GETPOSTINT('selectedline');
187$desc = GETPOST('desc', 'alphanohtml');
188$pay = GETPOST('pay', 'aZ09');
189$amountofpayment = GETPOSTFLOAT('amount');
190
191$invoiceid = GETPOSTINT('invoiceid');
192
193$paycode = $pay;
194if ($pay == 'cash') {
195 $paycode = 'LIQ'; // For backward compatibility
196}
197if ($pay == 'card') {
198 $paycode = 'CB'; // For backward compatibility
199}
200if ($pay == 'cheque') {
201 $paycode = 'CHQ'; // For backward compatibility
202}
203
204// Retrieve paiementid and paiementcode
205$paiementid = 0;
206if ($paycode) {
207 $sql = "SELECT id, code FROM ".MAIN_DB_PREFIX."c_paiement";
208 $sql .= " WHERE entity IN (".getEntity('c_paiement').")";
209 $sql .= " AND code = '".$db->escape($paycode)."'";
210 $resql = $db->query($sql);
211 if ($resql) {
212 $obj = $db->fetch_object($resql);
213 if ($obj) {
214 $paiementid = $obj->id;
215 }
216 }
217}
218
219$invoice = new Facture($db);
220if ($invoiceid > 0) {
221 $ret = $invoice->fetch($invoiceid);
222} else {
223 $ret = $invoice->fetch(0, '(PROV-POS'.$takeposterminal.'-'.$place.')');
224}
225if ($ret > 0) {
226 $placeid = $invoice->id;
227}
228
229$constforcompanyid = 'CASHDESK_ID_THIRDPARTY'.$takeposterminal;
230
231$soc = new Societe($db);
232if ($invoice->socid > 0) {
233 $soc->fetch($invoice->socid);
234} else {
235 $soc->fetch(getDolGlobalInt($constforcompanyid));
236}
237
238// Assign a default project, if relevant
239if (isModEnabled('project') && getDolGlobalInt("CASHDESK_ID_PROJECT".$takeposterminal)) {
240 $invoice->fk_project = getDolGlobalInt("CASHDESK_ID_PROJECT".$takeposterminal);
241}
242
243// Change the currency of invoice if it was modified
244if (isModEnabled('multicurrency') && !empty($_SESSION["takeposcustomercurrency"])) {
245 if ($invoice->multicurrency_code != $_SESSION["takeposcustomercurrency"]) {
246 $invoice->setMulticurrencyCode($_SESSION["takeposcustomercurrency"]);
247 }
248}
249
250$term = empty($_SESSION["takeposterminal"]) ? 1 : $_SESSION["takeposterminal"];
251
252
253/*
254 * Actions
255 */
256$error = 0;
257$parameters = array();
258$reshook = $hookmanager->executeHooks('doActions', $parameters, $invoice, $action); // Note that $action and $object may have been modified by some hooks
259if ($reshook < 0) {
260 setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
261}
262
263
264$sectionwithinvoicelink = '';
265$CUSTOMER_DISPLAY_line1 = '';
266$CUSTOMER_DISPLAY_line2 = '';
267$headerorder = '';
268$footerorder = '';
269$printer = null;
270$idoflineadded = 0;
271$clonebatch = GETPOSTINT('clonebatch');
272
273// Enforce the "edit lines" permission on every action that modifies an existing line
274// (delete, quantity, price, discount). Adding a line, a free zone or a note is gated by
275// the "run" permission elsewhere and must stay available to a plain cashier (#38949).
276if (in_array($action, array('deleteline', 'updateqty', 'updateprice', 'updatereduction', 'update_reduction_global')) && !$user->hasRight('takepos', 'editlines')) {
277 dol_htmloutput_errors($langs->trans("NotEnoughPermissions", "TakePos"), array(), 1);
278 $action = '';
279}
280
281
282if (empty($reshook)) {
283 if ($action == 'cloneticket' && $user->hasRight('takepos', 'run')) {
284 $cloneid = 0;
285 $cloneplace = '';
286 $clonemessage = '';
287 $sourceinvoice = new Facture($db);
288 $result = $sourceinvoice->fetch($sourceinvoiceid);
289 $targetentity = !empty($_SESSION['takeposinvoiceentity']) ? (int) $_SESSION['takeposinvoiceentity'] : (int) $conf->entity;
290
291 if ($result <= 0 || $sourceinvoice->module_source != 'takepos' || !in_array($sourceinvoice->status, array(Facture::STATUS_VALIDATED, Facture::STATUS_CLOSED)) || $sourceinvoice->type == Facture::TYPE_CREDIT_NOTE || (int) $sourceinvoice->entity != $targetentity) {
292 $langs->load('errors');
293 $clonemessage = $langs->trans('ErrorBadValueForParameter', 'sourceinvoiceid');
294 setEventMessages($clonemessage, null, 'errors');
295 } else {
296 $cloneinvoice = dol_clone($sourceinvoice, 1);
297 '@phan-var-force Facture $cloneinvoice';
298 $cloneinvoice->date = dol_now();
299 $cloneid = $cloneinvoice->createFromClone($user, $sourceinvoiceid, $targetentity);
300
301 if ($cloneid > 0) {
302 $cloneplace = '0';
303 $sql = "SELECT rowid FROM ".MAIN_DB_PREFIX."facture WHERE ref = '(PROV-POS".$db->escape((string) $takeposterminal)."-0)' AND entity IN (".getEntity('invoice').")";
304 $resql = $db->query($sql);
305 if ($resql && $db->num_rows($resql) > 0) {
306 $max_sale = 0;
307 $sql = "SELECT ref FROM ".MAIN_DB_PREFIX."facture WHERE entity IN (".getEntity('invoice').") AND ref LIKE '(PROV-POS".$db->escape((string) $takeposterminal)."-0-%'";
308 $resql2 = $db->query($sql);
309 if ($resql2) {
310 while ($obj = $db->fetch_object($resql2)) {
311 $num_sale = str_replace(")", "", str_replace("(PROV-POS".$takeposterminal."-0-", "", $obj->ref));
312 if ((int) $num_sale > $max_sale) {
313 $max_sale = (int) $num_sale;
314 }
315 }
316 }
317 $cloneplace = '0-'.($max_sale + 1);
318 }
319
320 $sql = "UPDATE ".MAIN_DB_PREFIX."facture";
321 $sql .= " SET module_source = 'takepos', pos_source = '".$db->escape((string) $takeposterminal)."',";
322 $sql .= " ref = '".$db->escape("(PROV-POS".((string) $takeposterminal)."-".$cloneplace.")")."'";
323 $sql .= " WHERE rowid = ".((int) $cloneid);
324 $result = $db->query($sql);
325
326 if ($result && isModEnabled('productbatch') && isModEnabled('stock')) {
327 $sql = "UPDATE ".MAIN_DB_PREFIX."facturedet";
328 $sql .= " SET batch = NULL, fk_warehouse = NULL";
329 $sql .= " WHERE fk_facture = ".((int) $cloneid);
330 $sql .= " AND fk_product IN (SELECT rowid FROM ".MAIN_DB_PREFIX."product WHERE tobatch > 0)";
331 $result = $db->query($sql);
332 }
333 }
334
335 if ($cloneid > 0 && $result) {
336 $place = $cloneplace;
337 $placeid = $cloneid;
338 $invoice = new Facture($db);
339 $invoice->fetch($cloneid);
340 $clonebatch = 1;
341 } else {
342 if ($cloneid > 0) {
343 $cloneinvoice->fetch($cloneid);
344 $cloneinvoice->delete($user);
345 $cloneid = 0;
346 }
347 $langs->load('errors');
348 $clonemessage = !empty($cloneinvoice->error) ? $cloneinvoice->error : $langs->trans('ErrorFailedToCloneTicket');
349 setEventMessages($clonemessage, $cloneinvoice->errors, 'errors');
350 }
351 }
352
353 if (GETPOST('format', 'aZ09') == 'json') {
354 $batchlineid = 0;
355 $batchproductid = 0;
356 if ($cloneid > 0 && isModEnabled('productbatch') && isModEnabled('stock')) {
357 $sql = 'SELECT fd.rowid, fd.fk_product';
358 $sql .= ' FROM '.MAIN_DB_PREFIX.'facturedet AS fd, '.MAIN_DB_PREFIX.'product AS p';
359 $sql .= ' WHERE fd.fk_product = p.rowid';
360 $sql .= ' AND fd.fk_facture = '.((int) $cloneid);
361 $sql .= " AND (fd.batch IS NULL OR fd.batch = '') AND p.tobatch > 0";
362 $sql .= ' ORDER BY fd.rang, fd.rowid';
363 $sql .= $db->plimit(1);
364 $resql = $db->query($sql);
365 if ($resql && ($obj = $db->fetch_object($resql))) {
366 $batchlineid = (int) $obj->rowid;
367 $batchproductid = (int) $obj->fk_product;
368 }
369 }
370
371 top_httphead('application/json');
372 echo json_encode(array('success' => $cloneid > 0, 'invoiceid' => $cloneid, 'place' => $cloneplace, 'batchlineid' => $batchlineid, 'batchproductid' => $batchproductid, 'message' => $clonemessage));
373 exit;
374 }
375 }
376
377 // Test that period is not close
378 $tmpcurrentday = dol_getdate(dol_now());
379
380 $sql = "SELECT MIN(ref) as firstref FROM ".MAIN_DB_PREFIX."pos_cash_fence";
381 $sql .= " WHERE entity = ".((int) $conf->entity);
382 $sql .= " AND posnumber = ".((int) $takeposterminal);
383 $sql .= " AND year_close = ".((int) $tmpcurrentday['year']);
384 $sql .= " AND (";
385 $sql .= " (month_close IS NULL AND day_close IS NULL)";
386 $sql .= " OR (month_close = ".((int) $tmpcurrentday['mon'])." AND day_close IS NULL)";
387 $sql .= " OR (month_close = ".((int) $tmpcurrentday['mon'])." AND day_close = ".((int) $tmpcurrentday['mday']).")";
388 $sql .= ")";
389 $sql .= " AND status = 1";
390
391 $refcashcontrol = 0;
392 $resql = $db->query($sql);
393 if ($resql) {
394 $obj = $db->fetch_object($resql);
395 if ($obj) {
396 $refcashcontrol = $obj->firstref;
397 }
398 }
399
400 if ($refcashcontrol) {
401 $error++;
402 $langs->load('errors');
403 dol_htmloutput_errors($langs->trans("ACashControlHasBeenclosedForCurrentDay", $refcashcontrol), [], 1);
404 $action = '';
405 }
406
407 // Action to record a payment on a TakePOS invoice
408 if ($action == 'valid' && $user->hasRight('takepos', 'run')) {
409 $bankaccount = 0;
410 $error = 0;
411
412 if (getDolGlobalString('TAKEPOS_CAN_FORCE_BANK_ACCOUNT_DURING_PAYMENT')) {
413 $bankaccount = GETPOSTINT('accountid');
414 } else {
415 if ($pay == 'LIQ') {
416 $bankaccount = getDolGlobalInt('CASHDESK_ID_BANKACCOUNT_CASH'.$_SESSION["takeposterminal"]); // For backward compatibility
417 } elseif ($pay == "CHQ") {
418 $bankaccount = getDolGlobalInt('CASHDESK_ID_BANKACCOUNT_CHEQUE'.$_SESSION["takeposterminal"]); // For backward compatibility
419 } else {
420 $accountname = "CASHDESK_ID_BANKACCOUNT_".$pay.$_SESSION["takeposterminal"];
421 $bankaccount = getDolGlobalInt($accountname);
422 }
423 }
424
425 if ($bankaccount <= 0 && $pay != "delayed" && isModEnabled("bank")) {
426 $errormsg = $langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("BankAccount"));
427 $error++;
428 }
429
430 $now = dol_now();
431 $res = 0;
432
433 $invoice = new Facture($db);
434 $invoice->fetch($placeid);
435
436 $invoice->oldcopy = dol_clone($invoice, 2);
437
438 $db->begin();
439
440 if ($invoice->total_ttc < 0) {
441 $invoice->type = $invoice::TYPE_CREDIT_NOTE;
442
443 $sql = "SELECT rowid FROM ".MAIN_DB_PREFIX."facture";
444 $sql .= " WHERE entity IN (".getEntity('invoice').")";
445 $sql .= " AND fk_soc = ".((int) $invoice->socid);
446 $sql .= " AND type <> ".Facture::TYPE_CREDIT_NOTE;
447 $sql .= " AND fk_statut >= ".$invoice::STATUS_VALIDATED;
448 $sql .= " ORDER BY rowid DESC";
449
450 $fk_source = 0;
451 $resql = $db->query($sql);
452 if ($resql) {
453 $obj = $db->fetch_object($resql);
454 $fk_source = $obj->rowid;
455 if ((int) $fk_source == 0) {
456 fail($langs->transnoentitiesnoconv("NoPreviousBillForCustomer"));
457 }
458 } else {
459 fail($langs->transnoentitiesnoconv("NoPreviousBillForCustomer"));
460 }
461 $invoice->fk_facture_source = $fk_source;
462 $invoice->update($user);
463 }
464
465 $constantforkey = 'CASHDESK_NO_DECREASE_STOCK'.(isset($_SESSION["takeposterminal"]) ? $_SESSION["takeposterminal"] : '');
466 $allowstockchange = (getDolGlobalString($constantforkey) != "1");
467
468 if ($error) {
469 dol_htmloutput_errors($errormsg, [], 1);
470 } elseif ($invoice->status != Facture::STATUS_DRAFT) {
471 //If invoice is validated but it is not fully paid is not error and make the payment
472 $remaintopay = $invoice->getRemainToPay();
473 if (($remaintopay > 0 && $invoice->type != Facture::TYPE_CREDIT_NOTE) || ($remaintopay < 0 && $invoice->type == Facture::TYPE_CREDIT_NOTE)) {
474 $res = 1;
475 } else {
476 dol_syslog("Sale already validated");
477 dol_htmloutput_errors($langs->trans("InvoiceIsAlreadyValidated", "TakePos"), [], 1);
478 }
479 } elseif (count($invoice->lines) == 0) {
480 $error++;
481 dol_syslog('Sale without lines');
482 dol_htmloutput_errors($langs->trans("NoLinesToBill", "TakePos"), [], 1);
483 } elseif (isModEnabled('stock') && !isModEnabled('productbatch') && $allowstockchange) {
484 // Validation of invoice with change into stock when product/lot module is NOT enabled and stock change NOT disabled.
485 // The case for isModEnabled('productbatch') is processed few lines later.
486 $savconst = getDolGlobalString('STOCK_CALCULATE_ON_BILL');
487
488 $conf->global->STOCK_CALCULATE_ON_BILL = 1; // To force the change of stock during invoice validation
489
490 $constantforkey = 'CASHDESK_ID_WAREHOUSE'.(isset($_SESSION["takeposterminal"]) ? $_SESSION["takeposterminal"] : '');
491 dol_syslog("Validate invoice with stock change. Warehouse defined into constant ".$constantforkey." = ".getDolGlobalString($constantforkey));
492
493 // Validate invoice with stock change into warehouse getDolGlobalInt($constantforkey)
494 // Label of stock movement will be the same as when we validate invoice "Invoice XXXX validated"
495 $batch_rule = 0; // Module productbatch is disabled here, so no need for a batch_rule.
496 $res = $invoice->validate($user, '', getDolGlobalInt($constantforkey), 0, $batch_rule);
497
498 // Restore setup
499 $conf->global->STOCK_CALCULATE_ON_BILL = $savconst;
500 } else {
501 // Validation of invoice with no change into stock (because param $idwarehouse is not fill)
502 dol_syslog("Call validate on invoice ".$invoice->ref, LOG_DEBUG);
503 $res = $invoice->validate($user);
504 if ($res < 0) {
505 $error++;
506 $langs->load("admin");
507 dol_htmloutput_errors($invoice->error == 'NotConfigured' ? $langs->trans("NotConfigured").' (TakePos numbering module)' : $invoice->error, $invoice->errors, 1);
508 }
509 }
510
511 // Add the payment
512 if (!$error && $res >= 0) {
513 $remaintopay = $invoice->getRemainToPay();
514 // Credit notes have negative remaintopay; regular invoices have positive
515 if (($remaintopay > 0 && $invoice->type != Facture::TYPE_CREDIT_NOTE) || ($remaintopay < 0 && $invoice->type == Facture::TYPE_CREDIT_NOTE)) {
516 $payment = new Paiement($db);
517
518 $payment->datepaye = $now;
519 $payment->fk_account = $bankaccount;
520 if ($pay == 'LIQ') {
521 $payment->pos_change = GETPOSTFLOAT('excess');
522 }
523
524 $payment->amounts[$invoice->id] = $amountofpayment;
525 // If user has not used change control, add total invoice payment
526 // Or if user has used change control and the amount of payment is higher than remain to pay, add the remain to pay
527 if ($amountofpayment <= 0 || $amountofpayment > $remaintopay) {
528 $payment->amounts[$invoice->id] = $remaintopay;
529 }
530 // We do not set $payments->multicurrency_amounts because we want payment to be in main currency.
531
532 $payment->paiementid = $paiementid;
533 $payment->paiementcode = $paycode;
534 $payment->num_payment = '';
535
536 if ($pay != "delayed") {
537 $res = $payment->create($user); // This record payment and regenerate the PDF
538 if ($res < 0) {
539 $error++;
540 //setEventMessages($payment->error, $payment->errors, 'error');
541 dol_htmloutput_mesg($payment->error, $payment->errors, 'error', 1);
542 } else {
543 //setEventMessages(null, $payment->warnings, 'warnings');
544 if (!empty($payment->warnings)) {
545 dol_htmloutput_mesg('', $payment->warnings, 'warning', 1);
546 }
547
548 $res = $payment->addPaymentToBank($user, 'payment', '(CustomerInvoicePayment)', $bankaccount, '', '');
549 if ($res < 0) {
550 $error++;
551 dol_htmloutput_mesg($langs->trans('ErrorNoPaymentDefined').' '.$payment->error, $payment->errors, 'error', 1);
552 }
553 }
554 $remaintopay = $invoice->getRemainToPay(); // Recalculate remain to pay after the payment is recorded
555 } elseif (getDolGlobalInt("TAKEPOS_DELAYED_TERMS")) {
556 $invoice->setPaymentTerms(getDolGlobalInt("TAKEPOS_DELAYED_TERMS"));
557 }
558 }
559
560 if ($remaintopay == 0) {
561 dol_syslog("Invoice is paid, so we set it to status Paid");
562 $result = $invoice->setPaid($user);
563 if ($result > 0) {
564 $invoice->paye = 1;
565 $invoice->status = $invoice::STATUS_CLOSED;
566 $invoice->close_code = '';
567 }
568 // set payment method
569 $invoice->setPaymentMethods($paiementid);
570 } else {
571 dol_syslog("Invoice is not paid, remain to pay = ".$remaintopay);
572 }
573 } else {
574 dol_htmloutput_errors($invoice->error, $invoice->errors, 1);
575 }
576
577
578 $warehouseid = 0;
579 // Update stock for batch products
580 if (!$error && $res >= 0) {
581 if (isModEnabled('stock') && isModEnabled('productbatch') && $allowstockchange) {
582 // Update stocks
583 dol_syslog("Now we record the stock movement for each qualified line");
584
585 // The case !isModEnabled('productbatch') was processed few lines before.
586 require_once DOL_DOCUMENT_ROOT . "/product/stock/class/mouvementstock.class.php";
587 $constantforkey = 'CASHDESK_ID_WAREHOUSE'.$_SESSION["takeposterminal"];
588 $inventorycode = dol_print_date(dol_now(), 'dayhourlog');
589 // Label of stock movement will be "TakePOS - Invoice XXXX"
590 $labeltakeposmovement = 'TakePOS - '.$langs->trans("Invoice").' '.$invoice->ref;
591
592 foreach ($invoice->lines as $line) {
593 // Use the warehouse id defined on invoice line else in the setup
594 $warehouseid = ($line->fk_warehouse ? $line->fk_warehouse : getDolGlobalInt($constantforkey));
595
596 // var_dump('fk_product='.$line->fk_product.' batch='.$line->batch.' warehouse='.$line->fk_warehouse.' qty='.$line->qty);
597 if ($line->batch != '' && $warehouseid > 0) {
598 $prod_batch = new Productbatch($db);
599 $prod_batch->find(0, '', '', $line->batch, $warehouseid, (int) $line->fk_product);
600
601 $mouvP = new MouvementStock($db);
602 $mouvP->setOrigin($invoice->element, $invoice->id);
603
604 if ($invoice->type == Facture::TYPE_CREDIT_NOTE) {
605 $res = $mouvP->reception($user, $line->fk_product, $warehouseid, $line->qty, $line->price, $labeltakeposmovement, '', '', $line->batch, '', 0, $inventorycode);
606 } else {
607 $res = $mouvP->livraison($user, $line->fk_product, $warehouseid, $line->qty, $line->price, $labeltakeposmovement, '', '', '', $prod_batch->batch, $prod_batch->id, $inventorycode);
608 }
609
610 if ($res < 0) {
611 dol_htmloutput_errors($mouvP->error, $mouvP->errors, 1);
612 $error++;
613 }
614 } else {
615 $mouvP = new MouvementStock($db);
616 $mouvP->setOrigin($invoice->element, $invoice->id);
617
618 if ($invoice->type == Facture::TYPE_CREDIT_NOTE) {
619 $res = $mouvP->reception($user, $line->fk_product, $warehouseid, $line->qty, $line->price, $labeltakeposmovement, '', '', '', '', 0, $inventorycode);
620 } else {
621 $res = $mouvP->livraison($user, $line->fk_product, $warehouseid, $line->qty, $line->price, $labeltakeposmovement, '', '', '', '', 0, $inventorycode);
622 }
623
624 if ($res < 0) {
625 dol_htmloutput_errors($mouvP->error, $mouvP->errors, 1);
626 $error++;
627 }
628 }
629 }
630 }
631 }
632
633 if (!$error && $res >= 0) {
634 $db->commit();
635 } else {
636 $invoice->ref = $invoice->oldcopy->ref;
637 $invoice->paye = $invoice->oldcopy->paye;
638 $invoice->status = $invoice->oldcopy->status;
639 $invoice->statut = $invoice->oldcopy->statut;
640
641 $db->rollback();
642 }
643 }
644
645 $creditnote = null;
646 if ($action == 'creditnote' && $user->hasRight('takepos', 'run')) {
647 $db->begin();
648
649 $creditnote = new Facture($db);
650 $creditnote->socid = $invoice->socid;
651 $creditnote->date = dol_now();
652 $creditnote->module_source = 'takepos';
653 $creditnote->pos_source = isset($_SESSION["takeposterminal"]) ? $_SESSION["takeposterminal"] : '' ;
654 $creditnote->type = Facture::TYPE_CREDIT_NOTE;
655 $creditnote->fk_facture_source = $placeid;
656
657 $creditnote->create($user);
658
659 $fk_parent_line = 0; // Initialise
660
661 foreach ($invoice->lines as $line) {
662 // Reset fk_parent_line for no child products and special product
663 if (($line->product_type != 9 && empty($line->fk_parent_line)) || $line->product_type == 9) {
664 $fk_parent_line = 0;
665 }
666
667 if (getDolGlobalInt('INVOICE_USE_SITUATION')) {
668 if (!empty($invoice->situation_counter)) {
669 $source_fk_prev_id = $line->fk_prev_id; // temporary storing situation invoice fk_prev_id
670 $line->fk_prev_id = $line->id; // The new line of the new credit note we are creating must be linked to the situation invoice line it is created from
671 if (!empty($invoice->tab_previous_situation_invoice)) {
672 // search the last standard invoice in cycle and the possible credit note between this last and invoice
673 // TODO Move this out of loop of $invoice->lines
674 $tab_jumped_credit_notes = array();
675 $lineIndex = count($invoice->tab_previous_situation_invoice) - 1;
676 $searchPreviousInvoice = true;
677 while ($searchPreviousInvoice) {
678 if ($invoice->tab_previous_situation_invoice[$lineIndex]->situation_cycle_ref || $lineIndex < 1) {
679 $searchPreviousInvoice = false; // find, exit;
680 break;
681 } else {
682 if ($invoice->tab_previous_situation_invoice[$lineIndex]->type == Facture::TYPE_CREDIT_NOTE) {
683 $tab_jumped_credit_notes[$lineIndex] = $invoice->tab_previous_situation_invoice[$lineIndex]->id;
684 }
685 $lineIndex--; // go to previous invoice in cycle
686 }
687 }
688
689 $maxPrevSituationPercent = 0;
690 foreach ($invoice->tab_previous_situation_invoice[$lineIndex]->lines as $prevLine) {
691 if ($prevLine->id == $source_fk_prev_id) {
692 $maxPrevSituationPercent = max($maxPrevSituationPercent, $prevLine->situation_percent);
693
694 //$line->subprice = $line->subprice - $prevLine->subprice;
695 $line->total_ht -= $prevLine->total_ht;
696 $line->total_tva -= $prevLine->total_tva;
697 $line->total_ttc -= $prevLine->total_ttc;
698 $line->total_localtax1 -= $prevLine->total_localtax1;
699 $line->total_localtax2 -= $prevLine->total_localtax2;
700
701 $line->multicurrency_subprice -= $prevLine->multicurrency_subprice;
702 $line->multicurrency_total_ht -= $prevLine->multicurrency_total_ht;
703 $line->multicurrency_total_tva -= $prevLine->multicurrency_total_tva;
704 $line->multicurrency_total_ttc -= $prevLine->multicurrency_total_ttc;
705 }
706 }
707
708 // prorata
709 $line->situation_percent = $maxPrevSituationPercent - $line->situation_percent;
710
711 //print 'New line based on invoice id '.$invoice->tab_previous_situation_invoice[$lineIndex]->id.' fk_prev_id='.$source_fk_prev_id.' will be fk_prev_id='.$line->fk_prev_id.' '.$line->total_ht.' '.$line->situation_percent.'<br>';
712
713 // If there is some credit note between last situation invoice and invoice used for credit note generation (note: credit notes are stored as delta)
714 $maxPrevSituationPercent = 0;
715 foreach ($tab_jumped_credit_notes as $index => $creditnoteid) {
716 foreach ($invoice->tab_previous_situation_invoice[$index]->lines as $prevLine) {
717 if ($prevLine->fk_prev_id == $source_fk_prev_id) {
718 $maxPrevSituationPercent = $prevLine->situation_percent;
719
720 $line->total_ht -= $prevLine->total_ht;
721 $line->total_tva -= $prevLine->total_tva;
722 $line->total_ttc -= $prevLine->total_ttc;
723 $line->total_localtax1 -= $prevLine->total_localtax1;
724 $line->total_localtax2 -= $prevLine->total_localtax2;
725
726 $line->multicurrency_subprice -= $prevLine->multicurrency_subprice;
727 $line->multicurrency_total_ht -= $prevLine->multicurrency_total_ht;
728 $line->multicurrency_total_tva -= $prevLine->multicurrency_total_tva;
729 $line->multicurrency_total_ttc -= $prevLine->multicurrency_total_ttc;
730 }
731 }
732 }
733
734 // prorata
735 $line->situation_percent += $maxPrevSituationPercent;
736
737 //print 'New line based on invoice id '.$invoice->tab_previous_situation_invoice[$lineIndex]->id.' fk_prev_id='.$source_fk_prev_id.' will be fk_prev_id='.$line->fk_prev_id.' '.$line->total_ht.' '.$line->situation_percent.'<br>';
738 }
739 }
740 }
741
742 // We update field for credit notes
743 $line->fk_facture = $creditnote->id;
744 $line->fk_parent_line = $fk_parent_line;
745
746 $line->subprice = -$line->subprice; // invert price for object
747 // $line->pa_ht = $line->pa_ht; // we chose to have the buy/cost price always positive, so no inversion of the sign here
748 $line->total_ht = -$line->total_ht;
749 $line->total_tva = -$line->total_tva;
750 $line->total_ttc = -$line->total_ttc;
751 $line->total_localtax1 = -$line->total_localtax1;
752 $line->total_localtax2 = -$line->total_localtax2;
753
754 $line->multicurrency_subprice = -$line->multicurrency_subprice;
755 $line->multicurrency_total_ht = -$line->multicurrency_total_ht;
756 $line->multicurrency_total_tva = -$line->multicurrency_total_tva;
757 $line->multicurrency_total_ttc = -$line->multicurrency_total_ttc;
758
759 $result = $line->insert(0, 1); // When creating credit note with same lines than source, we must ignore error if discount already linked
760
761 $creditnote->lines[] = $line; // insert new line in current object
762
763 // Defined the new fk_parent_line
764 if ($result > 0 && $line->product_type == 9) {
765 $fk_parent_line = $result;
766 }
767 }
768 $creditnote->update_price(1);
769
770 // The credit note is created here.
771 // If TAKEPOS_VALIDATE_CREDIT_NOTE_ON_CREATION is set, we validate it immediately (old behavior).
772 // Otherwise, it is left as draft so it can be edited from TakePOS (e.g. to modify quantities or batches).
773 // Stock movements will be done when the credit note is validated later (via Payment / Valid action).
774 $res = 1;
775 if (getDolGlobalString('TAKEPOS_VALIDATE_CREDIT_NOTE_ON_CREATION')) {
776 $constantforkey = 'CASHDESK_NO_DECREASE_STOCK'.(isset($_SESSION["takeposterminal"]) ? $_SESSION["takeposterminal"] : '');
777 $allowstockchange = getDolGlobalString($constantforkey) != "1";
778
779 if (isModEnabled('stock') && !isModEnabled('productbatch') && $allowstockchange) {
780 $savconst = getDolGlobalString('STOCK_CALCULATE_ON_BILL');
781 $conf->global->STOCK_CALCULATE_ON_BILL = 1; // Force stock update on invoice validation
782
783 $constantforkey = 'CASHDESK_ID_WAREHOUSE'.(isset($_SESSION["takeposterminal"]) ? $_SESSION["takeposterminal"] : '');
784 $warehouseid = getDolGlobalInt($constantforkey);
785
786 dol_syslog("Validate invoice with stock change into warehouse defined into constant ".$constantforkey." = ".getDolGlobalString($constantforkey)." or warehouseid= ".$warehouseid." if defined.");
787
788 $batch_rule = 0; // Module productbatch is disabled here, so no need for a batch_rule.
789 $res = $creditnote->validate($user, '', $warehouseid, 0, $batch_rule);
790 if ($res < 0) {
791 $error++;
792 dol_htmloutput_errors($creditnote->error, $creditnote->errors, 1);
793 }
794
795 // Restore setup
796 $conf->global->STOCK_CALCULATE_ON_BILL = $savconst;
797 } else {
798 $res = $creditnote->validate($user);
799 }
800
801 // Update stock for batch products
802 if (!$error && $res >= 0) {
803 if (isModEnabled('stock') && isModEnabled('productbatch') && $allowstockchange) {
804 dol_syslog("Now we record the stock movement for each qualified line");
805
806 require_once DOL_DOCUMENT_ROOT . "/product/stock/class/mouvementstock.class.php";
807 $constantforkey = 'CASHDESK_ID_WAREHOUSE'.(isset($_SESSION["takeposterminal"]) ? $_SESSION["takeposterminal"] : '');
808 $inventorycode = dol_print_date(dol_now(), 'dayhourlog');
809 $labeltakeposmovement = 'TakePOS - '.$langs->trans("CreditNote").' '.$creditnote->ref;
810
811 foreach ($creditnote->lines as $line) {
812 // Use the warehouse id defined on invoice line else in the setup
813 $warehouseid = ($line->fk_warehouse ? $line->fk_warehouse : getDolGlobalInt($constantforkey));
814
815 $mouvP = new MouvementStock($db);
816 $mouvP->setOrigin($creditnote->element, $creditnote->id);
817
818 $batch_to_use = ($line->batch != '' && $warehouseid > 0) ? $line->batch : '';
819
820 $res = $mouvP->reception($user, $line->fk_product, $warehouseid, $line->qty, $line->price, $labeltakeposmovement, '', '', $batch_to_use, '', 0, $inventorycode);
821 if ($res < 0) {
822 dol_htmloutput_errors($mouvP->error, $mouvP->errors, 1);
823 $error++;
824 }
825 }
826 }
827 }
828 }
829
830 if (!$error) {
831 $db->commit();
832 } else {
833 $creditnote->id = $placeid; // Creation has failed, we reset to ID of source invoice so we go back to this one in action=history
834 $db->rollback();
835 }
836 }
837
838 if (($action == 'history' || $action == 'creditnote') && $user->hasRight('takepos', 'run')) {
839 if ($action == 'creditnote' && $creditnote !== null && $creditnote->id > 0) { // Test on permission already done
840 $placeid = $creditnote->id;
841 } else {
842 $placeid = GETPOSTINT('placeid');
843 }
844
845 $invoice = new Facture($db);
846 $invoice->fetch($placeid);
847 }
848
849 // If we add a line and no invoice yet, we create the invoice
850 if (($action == "addline" || $action == "freezone") && $placeid == 0 && ($user->hasRight('takepos', 'run') || defined('INCLUDE_PHONEPAGE_FROM_PUBLIC_PAGE'))) {
851 $invoice->socid = getDolGlobalInt($constforcompanyid);
852
853 $dolnowtzuserrel = dol_now('tzuserrel'); // If user is 02 january 22:00, we want to store '02 january'
854 $monthuser = dol_print_date($dolnowtzuserrel, '%m', 'gmt');
855 $dayuser = dol_print_date($dolnowtzuserrel, '%d', 'gmt');
856 $yearuser = dol_print_date($dolnowtzuserrel, '%Y', 'gmt');
857 $dateinvoice = dol_mktime(0, 0, 0, (int) $monthuser, (int) $dayuser, (int) $yearuser, 'tzserver'); // If we enter the 02 january, we need to save the 02 january for server
858
859 include_once DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php';
860 $invoice->date = $dateinvoice; // Invoice::create() needs a date with no hours
861
862 /*
863 print "monthuser=".$monthuser." dayuser=".$dayuser." yearuser=".$yearuser.'<br>';
864 print '---<br>';
865 print 'TZSERVER: '.dol_print_date(dol_now('tzserver'), 'dayhour', 'gmt').'<br>';
866 print 'TZUSER: '.dol_print_date(dol_now('tzuserrel'), 'dayhour', 'gmt').'<br>';
867 print 'GMT: '.dol_print_date(dol_now('gmt'), 'dayhour', 'gmt').'<br>'; // Hour in greenwich
868 print '---<br>';
869 print dol_print_date($invoice->date, 'dayhour', 'gmt').'<br>';
870 print "IN SQL, we will got: ".dol_print_date($db->idate($invoice->date), 'dayhour', 'gmt').'<br>';
871 print dol_print_date($db->idate($invoice->date, 'gmt'), 'dayhour', 'gmt').'<br>';
872 */
873
874 $invoice->module_source = 'takepos';
875 $invoice->pos_source = isset($_SESSION["takeposterminal"]) ? $_SESSION["takeposterminal"] : '' ;
876 $invoice->entity = !empty($_SESSION["takeposinvoiceentity"]) ? $_SESSION["takeposinvoiceentity"] : $conf->entity;
877
878 if ($invoice->socid <= 0) {
879 $langs->load('errors');
880 dol_htmloutput_errors($langs->trans("ErrorModuleSetupNotComplete", "TakePos"), [], 1);
881 } else {
882 $db->begin();
883
884 // Create invoice
885 $placeid = $invoice->create($user);
886
887 if ($placeid < 0) {
888 $error++;
889 dol_htmloutput_errors($invoice->error, $invoice->errors, 1);
890 } else {
891 $sql = "UPDATE ".MAIN_DB_PREFIX."facture";
892 $sql .= " SET ref='(PROV-POS".$_SESSION["takeposterminal"]."-".$place.")'";
893 $sql .= " WHERE rowid = ".((int) $placeid);
894 $resql = $db->query($sql);
895 if (!$resql) {
896 $error++;
897 }
898 }
899
900 if (!$error) {
901 $db->commit();
902 } else {
903 $db->rollback();
904 }
905 }
906 }
907
908 $tva_npr = 0;
909 // If we add a line by clicking on a product (invoice exists here because it was created juste before if it didn't exists)
910 if ($action == "addline" && ($user->hasRight('takepos', 'run') || defined('INCLUDE_PHONEPAGE_FROM_PUBLIC_PAGE'))) {
911 $prod = new Product($db);
912 $prod->fetch($idproduct);
913
914 $customer = new Societe($db);
915 $customer->fetch($invoice->socid);
916
917 $datapriceofproduct = $prod->getSellPrice($mysoc, $customer, 0);
918
919 $qty = GETPOSTISSET('qty') ? GETPOSTFLOAT('qty', '', GETPOSTINT('qty_std') ? 1 : 2) : 1;
920 $price = $datapriceofproduct['pu_ht'];
921 $price_ttc = $datapriceofproduct['pu_ttc'];
922 //$price_min = $datapriceofproduct['price_min'];
923 $price_base_type = empty($datapriceofproduct['price_base_type']) ? 'HT' : $datapriceofproduct['price_base_type'];
924 $tva_tx = $datapriceofproduct['tva_tx'];
925 $tva_npr = (int) $datapriceofproduct['tva_npr'];
926
927 // Local Taxes
928 $localtax1_tx = get_localtax($tva_tx, 1, $customer, $mysoc, $tva_npr);
929 $localtax2_tx = get_localtax($tva_tx, 2, $customer, $mysoc, $tva_npr);
930
931
932 if (isModEnabled('productbatch') && isModEnabled('stock')) {
933 $batch = GETPOST('batch', 'alpha');
934
935 if (!empty($batch)) { // We have just clicked on a batch number, we will execute action=setbatch later...
936 $action = "setbatch";
937 } elseif ($prod->status_batch > 0) {
938 // If product need a lot/serial, we show the list of lot/serial available for the product...
939
940 // Set nb of suggested with nb of batch into the warehouse of the terminal
941 $nbofsuggested = 0;
942 $prod->load_stock('warehouseopen');
943
944 $constantforkey = 'CASHDESK_ID_WAREHOUSE'.$_SESSION["takeposterminal"];
945 $warehouseid = getDolGlobalInt($constantforkey);
946
947 //var_dump($prod->stock_warehouse);
948 foreach ($prod->stock_warehouse as $tmpwarehouseid => $tmpval) {
949 if (getDolGlobalInt($constantforkey) && $tmpwarehouseid != getDolGlobalInt($constantforkey)) {
950 // Product to select is not on the warehouse configured for terminal, so we ignore this warehouse
951 continue;
952 }
953 if (!empty($prod->stock_warehouse[$tmpwarehouseid]) && is_array($prod->stock_warehouse[$tmpwarehouseid]->detail_batch)) {
954 if (is_object($prod->stock_warehouse[$tmpwarehouseid]) && count($prod->stock_warehouse[$tmpwarehouseid]->detail_batch)) {
955 foreach ($prod->stock_warehouse[$tmpwarehouseid]->detail_batch as $dbatch) {
956 $nbofsuggested++;
957 }
958 }
959 }
960 }
961 //var_dump($prod->stock_warehouse);
962
963 echo "<script>\n";
964 echo "function addbatch(batch, warehouseid) {\n";
965 echo "console.log('We add batch '+batch+' from warehouse id '+warehouseid);\n";
966 echo '$("#poslines").load("'.DOL_URL_ROOT.'/takepos/invoice.php?action=addline&batch="+encodeURIComponent(batch)+"&warehouseid="+warehouseid+"&place='.$place.'&idproduct='.$idproduct.'&token='.newToken().'", function() {});'."\n";
967 echo "}\n";
968 echo "</script>\n";
969
970 $suggestednb = 1;
971 echo "<center>".$langs->trans("SearchIntoBatch").": <b> $nbofsuggested </b></center><br><table>";
972 foreach ($prod->stock_warehouse as $tmpwarehouseid => $tmpval) {
973 if (getDolGlobalInt($constantforkey) && $tmpwarehouseid != getDolGlobalInt($constantforkey)) {
974 // Not on the forced warehouse, so we ignore this warehouse
975 continue;
976 }
977 if (!empty($prod->stock_warehouse[$tmpwarehouseid]) && is_array($prod->stock_warehouse[$tmpwarehouseid]->detail_batch)) {
978 foreach ($prod->stock_warehouse[$tmpwarehouseid]->detail_batch as $dbatch) { // $dbatch is instance of Productbatch
979 $batchStock = + $dbatch->qty; // To get a numeric
980 $quantityToBeDelivered = 1;
981 $deliverableQty = min($quantityToBeDelivered, $batchStock);
982 print '<tr>';
983 print '<!-- subj='.$suggestednb.'/'.$nbofsuggested.' -->';
984 print '<!-- Show details of lot/serial in warehouseid='.$tmpwarehouseid.' -->';
985 print '<td class="left">';
986 $detail = '';
987 $detail .= '<span class="opacitymedium">'.$langs->trans("LotSerial").':</span> '.$dbatch->batch;
988 //if (!getDolGlobalString('PRODUCT_DISABLE_SELLBY')) {
989 //$detail .= ' - '.$langs->trans("SellByDate").': '.dol_print_date($dbatch->sellby, "day");
990 //}
991 //if (!getDolGlobalString('PRODUCT_DISABLE_EATBY')) {
992 //$detail .= ' - '.$langs->trans("EatByDate").': '.dol_print_date($dbatch->eatby, "day");
993 //}
994 $detail .= '</td><td>';
995 $detail .= '<span class="opacitymedium">'.$langs->trans("Qty").':</span> '.$dbatch->qty;
996 $detail .= '</td><td>';
997 $detail .= ' <button class="marginleftonly" onclick="addbatch(\''.dol_escape_js($dbatch->batch).'\', '.$tmpwarehouseid.')">'.$langs->trans("Select")."</button>";
998 $detail .= '<br>';
999 print $detail;
1000
1001 $quantityToBeDelivered -= $deliverableQty;
1002 if ($quantityToBeDelivered < 0) {
1003 $quantityToBeDelivered = 0;
1004 }
1005 $suggestednb++;
1006 print '</td></tr>';
1007 }
1008 }
1009 }
1010
1011 if ($nbofsuggested == 0) {
1012 // Add manual entry for returns or new batches when stock is 0
1013 print '<tr><td class="left" style="padding-top: 10px; border-top: 1px solid #ddd; text-align: center;">';
1014 print '<span class="opacitymedium">'.$langs->trans("LotSerial").' (Manual) :</span> ';
1015 print '<input type="text" id="manual_batch_add" class="flat" size="10"> ';
1016 print '<button class="button" onclick="addbatch(document.getElementById(\'manual_batch_add\').value, '.$warehouseid.')">'.$langs->trans("Add").'</button>';
1017 print '</td></tr>';
1018 }
1019
1020 print "</table>";
1021
1022 print '</body></html>';
1023 exit;
1024 }
1025 }
1026
1027
1028 if (getDolGlobalString('TAKEPOS_SUPPLEMENTS')) {
1029 require_once DOL_DOCUMENT_ROOT.'/categories/class/categorie.class.php';
1030 $cat = new Categorie($db);
1031 $categories = $cat->containing($idproduct, 'product');
1032 $found = (array_search(getDolGlobalInt('TAKEPOS_SUPPLEMENTS_CATEGORY'), array_column($categories, 'id')));
1033 if ($found !== false) { // If this product is a supplement
1034 $sql = "SELECT fk_parent_line FROM ".MAIN_DB_PREFIX."facturedet where rowid = ".((int) $selectedline);
1035 $resql = $db->query($sql);
1036 $row = $db->fetch_array($resql);
1037 if ($row[0] == null) {
1038 $parent_line = $selectedline;
1039 } else {
1040 $parent_line = $row[0]; //If the parent line is already a supplement, add the supplement to the main product
1041 }
1042 }
1043 }
1044
1045 $err = 0;
1046 // Group if enabled. Skip group if line already sent to the printer, or if product requires a batch/serial number (cannot group different serials)
1047 if (getDolGlobalString('TAKEPOS_GROUP_SAME_PRODUCT') && empty($prod->status_batch)) {
1048 foreach ($invoice->lines as $line) {
1049 if ($line->product_ref == $prod->ref) {
1050 if ($line->special_code == 4) {
1051 continue;
1052 } // If this line is sended to printer create new line
1053 // check if qty in stock
1054 if (getDolGlobalString('TAKEPOS_QTY_IN_STOCK') && (($line->qty + $qty) > $prod->stock_reel)) {
1055 $invoice->error = $langs->trans("ErrorStockIsNotEnough");
1056 dol_htmloutput_errors($invoice->error, $invoice->errors, 1);
1057 $err++;
1058 break;
1059 }
1060 $result = $invoice->updateline($line->id, $line->desc, $line->subprice, $line->qty + $qty, $line->remise_percent, $line->date_start, $line->date_end, $line->tva_tx, $line->localtax1_tx, $line->localtax2_tx, 'HT', $line->info_bits, $line->product_type, $line->fk_parent_line, 0, $line->fk_fournprice, $line->pa_ht, $line->label, $line->special_code, $line->array_options, $line->situation_percent, $line->fk_unit);
1061 if ($result < 0) {
1062 dol_htmloutput_errors($invoice->error, $invoice->errors, 1);
1063 } else {
1064 $idoflineadded = $line->id;
1065 }
1066 break;
1067 }
1068 }
1069 }
1070 if ($idoflineadded <= 0 && empty($err)) {
1071 $invoice->fetch_thirdparty();
1072 $array_options = array();
1073
1074 $line = array('description' => $prod->description, 'price' => $price, 'tva_tx' => $tva_tx, 'localtax1_tx' => $localtax1_tx, 'localtax2_tx' => $localtax2_tx, 'remise_percent' => $customer->remise_percent, 'price_ttc' => $price_ttc, 'array_options' => $array_options);
1075
1076 /* setup of margin calculation */
1077 if (getDolGlobalString('MARGIN_TYPE')) {
1078 if (getDolGlobalString('MARGIN_TYPE') == 'pmp' && !empty($prod->pmp)) {
1079 $line['fk_fournprice'] = null;
1080 $line['pa_ht'] = $prod->pmp;
1081 } elseif (getDolGlobalString('MARGIN_TYPE') == 'costprice' && !empty($prod->cost_price)) {
1082 $line['fk_fournprice'] = null;
1083 $line['pa_ht'] = $prod->cost_price;
1084 } else {
1085 // default is fournprice
1086 require_once DOL_DOCUMENT_ROOT.'/fourn/class/fournisseur.product.class.php';
1087 $pf = new ProductFournisseur($db);
1088 if ($pf->find_min_price_product_fournisseur($idproduct, $qty) > 0) {
1089 $line['fk_fournprice'] = $pf->product_fourn_price_id;
1090 $line['pa_ht'] = $pf->fourn_unitprice_with_discount;
1091 if (getDolGlobalString('PRODUCT_CHARGES') && $pf->fourn_charges > 0) {
1092 $line['pa_ht'] += (float) $pf->fourn_charges / $pf->fourn_qty;
1093 }
1094 }
1095 }
1096 }
1097
1098 // complete line by hook
1099 $parameters = array('prod' => $prod, 'line' => $line);
1100 $reshook = $hookmanager->executeHooks('completeTakePosAddLine', $parameters, $invoice, $action); // Note that $action and $line may have been modified by some hooks
1101 if ($reshook < 0) {
1102 setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
1103 }
1104
1105
1106 if (empty($reshook)) {
1107 if (!empty($hookmanager->resArray)) {
1108 $line = $hookmanager->resArray;
1109 }
1110
1111 // check if qty in stock
1112 if (getDolGlobalString('TAKEPOS_QTY_IN_STOCK') && $qty > $prod->stock_reel) {
1113 $invoice->error = $langs->trans("ErrorStockIsNotEnough");
1114 dol_htmloutput_errors($invoice->error, $invoice->errors, 1);
1115 $err++;
1116 }
1117
1118 if (empty($err)) {
1119 $idoflineadded = $invoice->addline($line['description'], $line['price'], $qty, $line['tva_tx'], $line['localtax1_tx'], $line['localtax2_tx'], $idproduct, (float) $line['remise_percent'], '', 0, 0, 0, 0, $price_base_type, $line['price_ttc'], $prod->type, -1, 0, '', 0, (empty($parent_line) ? '' : $parent_line), (empty($line['fk_fournprice']) ? 0 : $line['fk_fournprice']), (empty($line['pa_ht']) ? '' : $line['pa_ht']), '', $line['array_options'], 100, 0, $prod->fk_unit, 0);
1120 }
1121 }
1122
1123 if (getDolGlobalString('TAKEPOS_CUSTOMER_DISPLAY')) {
1124 $CUSTOMER_DISPLAY_line1 = $prod->label;
1125 $CUSTOMER_DISPLAY_line2 = price($price_ttc);
1126 }
1127 }
1128
1129 $invoice->fetch($placeid);
1130 }
1131
1132 // If we add a line by submitting freezone form (invoice exists here because it was created just before if it didn't exist)
1133 if ($action == "freezone" && $user->hasRight('takepos', 'run')) {
1134 $customer = new Societe($db);
1135 $customer->fetch($invoice->socid);
1136
1137 $tva_tx = GETPOST('tva_tx', 'alpha');
1138 if ($tva_tx != '') {
1139 if (!preg_match('/\‍((.*)\‍)/', $tva_tx)) {
1140 $tva_tx = price2num($tva_tx);
1141 }
1142 } else {
1143 $tva_tx = get_default_tva($mysoc, $customer);
1144 }
1145
1146 // Local Taxes
1147 $localtax1_tx = get_localtax($tva_tx, 1, $customer, $mysoc, $tva_npr);
1148 $localtax2_tx = get_localtax($tva_tx, 2, $customer, $mysoc, $tva_npr);
1149
1150 $res = $invoice->addline($desc, $number, 1, $tva_tx, $localtax1_tx, $localtax2_tx, 0, 0, '', 0, 0, 0, 0, getDolGlobalInt('TAKEPOS_DISCOUNT_TTC') ? ($number >= 0 ? 'HT' : 'TTC') : (getDolGlobalInt('TAKEPOS_CHANGE_PRICE_HT') ? 'HT' : 'TTC'), $number, 0, -1, 0, '', 0, 0, 0, 0, '', array(), 100, 0, null, 0);
1151 if ($res < 0) {
1152 dol_htmloutput_errors($invoice->error, $invoice->errors, 1);
1153 }
1154 $invoice->fetch($placeid);
1155 }
1156
1157 if ($action == "addnote" && ($user->hasRight('takepos', 'run') || defined('INCLUDE_PHONEPAGE_FROM_PUBLIC_PAGE'))) {
1158 $desc = GETPOST('addnote', 'alpha');
1159 if ($idline == 0) {
1160 $invoice->update_note($desc, '_public');
1161 } else {
1162 foreach ($invoice->lines as $line) {
1163 if ($line->id == $idline) {
1164 $result = $invoice->updateline($line->id, $desc, $line->subprice, $line->qty, $line->remise_percent, $line->date_start, $line->date_end, $line->tva_tx, $line->localtax1_tx, $line->localtax2_tx, 'HT', $line->info_bits, $line->product_type, $line->fk_parent_line, 0, $line->fk_fournprice, $line->pa_ht, $line->label, $line->special_code, $line->array_options, $line->situation_percent, $line->fk_unit);
1165 }
1166 }
1167 }
1168 $invoice->fetch($placeid);
1169 }
1170
1171 if ($action == "deleteline" && ($user->hasRight('takepos', 'editlines') || defined('INCLUDE_PHONEPAGE_FROM_PUBLIC_PAGE'))) {
1172 /*
1173 $permissiontoupdateline = ($user->hasRight('takepos', 'editlines') && ($user->hasRight('takepos', 'editorderedlines') || $line->special_code != "4"));
1174 if (defined('INCLUDE_PHONEPAGE_FROM_PUBLIC_PAGE')) {
1175 if ($invoice->status == $invoice::STATUS_DRAFT && $invoice->pos_source && $invoice->module_source == 'takepos') {
1176 $permissiontoupdateline = true;
1177 // TODO Add also a test on $_SESSION('publicobjectid'] defined at creation of object
1178 // TODO Check also that invoice->ref is (PROV-POS1-2) with 1 = terminal and 2, the table ID
1179 }
1180 }*/
1181 $db->begin();
1182
1183 if ($idline > 0 && $placeid > 0) { // If invoice exists and a line is selected.
1184 $result = takeposDeleteLineWithChildren($invoice, $idline);
1185 if ($result < 0) {
1186 dol_htmloutput_errors($invoice->error, $invoice->errors, 1);
1187 }
1188 $invoice->fetch($placeid);
1189 } elseif ($placeid > 0) { // If invoice exists but no line selected (delete from another device or with no line selected), proceed to delete the last line.
1190 $sql = "SELECT rowid FROM ".MAIN_DB_PREFIX."facturedet where fk_facture = ".((int) $placeid)." ORDER BY rowid DESC";
1191 $resql = $db->query($sql);
1192 $obj = $db->fetch_object($resql);
1193 if ($obj) {
1194 $deletelineid = $obj->rowid;
1195 $result = takeposDeleteLineWithChildren($invoice, $deletelineid);
1196 if ($result < 0) {
1197 dol_htmloutput_errors($invoice->error, $invoice->errors, 1);
1198 }
1199 }
1200 $invoice->fetch($placeid);
1201 }
1202
1203 $db->commit();
1204
1205 if (count($invoice->lines) == 0) {
1206 // Keep an empty draft invoice alive when a non-default customer was
1207 // already attached so deleting the last line does not silently lose
1208 // the customer that was just selected (#38219). Only drop the invoice
1209 // when it is still on the default cashdesk thirdparty (or none).
1210 $defaultsocid = (int) getDolGlobalString('CASHDESK_ID_THIRDPARTY'.$_SESSION["takeposterminal"]);
1211 $invoicesocid = (int) $invoice->socid;
1212 if ($invoicesocid === 0 || $invoicesocid === $defaultsocid) {
1213 $invoice->delete($user);
1214
1215 if (defined('INCLUDE_PHONEPAGE_FROM_PUBLIC_PAGE')) {
1216 header("Location: ".DOL_URL_ROOT."/takepos/public/auto_order.php");
1217 } else {
1218 header("Location: ".DOL_URL_ROOT."/takepos/invoice.php");
1219 }
1220 exit;
1221 }
1222 }
1223 }
1224
1225 // Action to delete or discard an invoice
1226 if ($action == "delete" && ($user->hasRight('takepos', 'run') || defined('INCLUDE_PHONEPAGE_FROM_PUBLIC_PAGE'))) {
1227 // $placeid is the invoice id (it differs from place) and is defined if the place is set and
1228 // the ref of invoice is '(PROV-POS'.$_SESSION["takeposterminal"].'-'.$place.')', so the fetch at beginning of page works.
1229 if ($placeid > 0) {
1230 $result = $invoice->fetch($placeid);
1231
1232 if ($result > 0 && $invoice->status == Facture::STATUS_DRAFT) {
1233 $db->begin();
1234
1235 // We delete the lines
1236 $resdeletelines = 1;
1237 foreach ($invoice->lines as $line) {
1238 // @phan-suppress-next-line PhanPluginSuspiciousParamPosition
1239 $tmpres = $invoice->deleteLine($line->id);
1240 if ($tmpres < 0) {
1241 $resdeletelines = 0;
1242 break;
1243 }
1244 }
1245
1246 $sql = "UPDATE ".MAIN_DB_PREFIX."facture";
1247 $varforconst = 'CASHDESK_ID_THIRDPARTY'.$_SESSION["takeposterminal"];
1248 $sql .= " SET fk_soc = ".((int) getDolGlobalString($varforconst)).", ";
1249 $sql .= " datec = '".$db->idate(dol_now())."'";
1250 $sql .= " WHERE entity IN (".getEntity('invoice').")";
1251 $sql .= " AND ref = '(PROV-POS".$db->escape($_SESSION["takeposterminal"]."-".$place).")'";
1252 $resql1 = $db->query($sql);
1253
1254 if ($resdeletelines && $resql1) {
1255 $db->commit();
1256 } else {
1257 $db->rollback();
1258 }
1259
1260 $invoice->fetch($placeid);
1261 }
1262 }
1263 }
1264
1265 // Action to fully remove (discard) the current sale: delete the draft invoice so its tab disappears
1266 // (the "delete" action above only empties and resets the cart).
1267 if ($action == "discardsale" && ($user->hasRight('takepos', 'run') || defined('INCLUDE_PHONEPAGE_FROM_PUBLIC_PAGE'))) {
1268 if ($placeid > 0) {
1269 $result = $invoice->fetch($placeid);
1270 if ($result > 0 && $invoice->status == Facture::STATUS_DRAFT) {
1271 $invoice->delete($user);
1272 $placeid = 0;
1273 }
1274 }
1275 }
1276
1277 if ($action == "updateqty") { // Test on permission is done later
1278 foreach ($invoice->lines as $line) {
1279 if ($line->id == $idline) {
1280 $permissiontoupdateline = ($user->hasRight('takepos', 'editlines') && ($user->hasRight('takepos', 'editorderedlines') || $line->special_code != "4"));
1281 if (defined('INCLUDE_PHONEPAGE_FROM_PUBLIC_PAGE')) {
1282 if ($invoice->status == $invoice::STATUS_DRAFT && $invoice->pos_source && $invoice->module_source == 'takepos') {
1283 $permissiontoupdateline = true;
1284 // TODO Add also a test on $_SESSION('publicobjectid'] defined at creation of object
1285 // TODO Check also that invoice->ref is (PROV-POS1-2) with 1 = terminal and 2, the table ID
1286 }
1287 }
1288 if (!$permissiontoupdateline) {
1289 dol_htmloutput_errors($langs->trans("NotEnoughPermissions", "TakePos").' - No permission to updateqty', [], 1);
1290 } else {
1291 if ($number <= 0) {
1292 $result = takeposDeleteLineWithChildren($invoice, $line->id);
1293 if ($result < 0) {
1294 dol_htmloutput_errors($invoice->error, $invoice->errors, 1);
1295 }
1296 } else {
1297 $vatratecode = $line->tva_tx;
1298 if ($line->vat_src_code) {
1299 $vatratecode .= ' ('.$line->vat_src_code.')';
1300 }
1301
1302 $result = $invoice->updateline($line->id, $line->desc, $line->subprice, $number, $line->remise_percent, $line->date_start, $line->date_end, $vatratecode, $line->localtax1_tx, $line->localtax2_tx, 'HT', $line->info_bits, $line->product_type, $line->fk_parent_line, 0, $line->fk_fournprice, $line->pa_ht, $line->label, $line->special_code, $line->array_options, $line->situation_percent, $line->fk_unit);
1303 }
1304 }
1305 }
1306 }
1307
1308 $invoice->fetch($placeid);
1309 }
1310
1311 if ($action == "updateprice") { // Test on permission is done later
1312 $customer = new Societe($db);
1313 $customer->fetch($invoice->socid);
1314
1315 foreach ($invoice->lines as $line) {
1316 if ($line->id == $idline) {
1317 $prod = new Product($db);
1318 $prod->fetch($line->fk_product);
1319 $datapriceofproduct = $prod->getSellPrice($mysoc, $customer, 0);
1320 $price_min = $datapriceofproduct['price_min'];
1321 $usercanproductignorepricemin = ((getDolGlobalString('MAIN_USE_ADVANCED_PERMS') && !$user->hasRight('produit', 'ignore_price_min_advance')) || !getDolGlobalString('MAIN_USE_ADVANCED_PERMS'));
1322
1323 $vatratecleaned = $line->tva_tx;
1324 $reg = array();
1325 if (preg_match('/^(.*)\s*\‍((.*)\‍)$/', (string) $line->tva_tx, $reg)) { // If vat is "xx (yy)"
1326 $vatratecleaned = trim($reg[1]);
1327 //$vatratecode = $reg[2];
1328 }
1329
1330 $pu_ht = price2num((float) price2num($number, 'MU') / (1 + ((float) $vatratecleaned / 100)), 'MU');
1331 // Check min price
1332 if ($usercanproductignorepricemin && (!empty($price_min) && ((float) price2num($pu_ht) * (1 - (float) price2num($line->remise_percent) / 100) < price2num($price_min)))) {
1333 $langs->load("products");
1334 dol_htmloutput_errors($langs->trans("CantBeLessThanMinPrice", price(price2num($price_min, 'MU'), 0, $langs, 0, 0, -1, $conf->currency)));
1335 // echo $langs->trans("CantBeLessThanMinPrice");
1336 } else {
1337 $permissiontoupdateline = ($user->hasRight('takepos', 'editlines') && ($user->hasRight('takepos', 'editorderedlines') || $line->special_code != "4"));
1338 if (defined('INCLUDE_PHONEPAGE_FROM_PUBLIC_PAGE')) {
1339 if ($invoice->status == $invoice::STATUS_DRAFT && $invoice->pos_source && $invoice->module_source == 'takepos') {
1340 $permissiontoupdateline = true;
1341 // TODO Add also a test on $_SESSION('publicobjectid'] defined at creation of object
1342 // TODO Check also that invoice->ref is (PROV-POS1-2) with 1 = terminal and 2, the table ID
1343 }
1344 }
1345
1346 $vatratecode = $line->tva_tx;
1347 if ($line->vat_src_code) {
1348 $vatratecode .= ' ('.$line->vat_src_code.')';
1349 }
1350
1351 if (!$permissiontoupdateline) {
1352 dol_htmloutput_errors($langs->trans("NotEnoughPermissions", "TakePos").' - No permission to updateprice', [], 1);
1353 } elseif (getDolGlobalInt('TAKEPOS_CHANGE_PRICE_HT') == 1) {
1354 $result = $invoice->updateline($line->id, $line->desc, $number, $line->qty, $line->remise_percent, $line->date_start, $line->date_end, $vatratecode, $line->localtax1_tx, $line->localtax2_tx, 'HT', $line->info_bits, $line->product_type, $line->fk_parent_line, 0, $line->fk_fournprice, $line->pa_ht, $line->label, $line->special_code, $line->array_options, $line->situation_percent, $line->fk_unit);
1355 } else {
1356 $result = $invoice->updateline($line->id, $line->desc, $number, $line->qty, $line->remise_percent, $line->date_start, $line->date_end, $vatratecode, $line->localtax1_tx, $line->localtax2_tx, 'TTC', $line->info_bits, $line->product_type, $line->fk_parent_line, 0, $line->fk_fournprice, $line->pa_ht, $line->label, $line->special_code, $line->array_options, $line->situation_percent, $line->fk_unit);
1357 }
1358 }
1359 }
1360 }
1361
1362 // Reload data
1363 $invoice->fetch($placeid);
1364 }
1365
1366 if ($action == "updatereduction") { // Test on permission is done later
1367 $customer = new Societe($db);
1368 $customer->fetch($invoice->socid);
1369
1370 foreach ($invoice->lines as $line) {
1371 if ($line->id == $idline) {
1372 dol_syslog("updatereduction Process line ".$line->id.' to apply discount of '.$number.'%');
1373
1374 $prod = new Product($db);
1375 $prod->fetch($line->fk_product);
1376
1377 $datapriceofproduct = $prod->getSellPrice($mysoc, $customer, 0);
1378 $price_min = $datapriceofproduct['price_min'];
1379 $usercanproductignorepricemin = ((getDolGlobalString('MAIN_USE_ADVANCED_PERMS') && !$user->hasRight('produit', 'ignore_price_min_advance')) || !getDolGlobalString('MAIN_USE_ADVANCED_PERMS'));
1380
1381 $pu_ht = price2num($line->subprice / (1 + ($line->tva_tx / 100)), 'MU');
1382
1383 // Check min price
1384 if ($usercanproductignorepricemin && (!empty($price_min) && ((float) price2num($line->subprice) * (1 - (float) price2num($number) / 100) < (float) price2num($price_min)))) {
1385 $langs->load("products");
1386 dol_htmloutput_errors($langs->trans("CantBeLessThanMinPrice", price(price2num($price_min, 'MU'), 0, $langs, 0, 0, -1, $conf->currency)));
1387 } else {
1388 $permissiontoupdateline = ($user->hasRight('takepos', 'editlines') && ($user->hasRight('takepos', 'editorderedlines') || $line->special_code != "4"));
1389 if (defined('INCLUDE_PHONEPAGE_FROM_PUBLIC_PAGE')) {
1390 if ($invoice->status == $invoice::STATUS_DRAFT && $invoice->pos_source && $invoice->module_source == 'takepos') {
1391 $permissiontoupdateline = true;
1392 // TODO Add also a test on $_SESSION('publicobjectid'] defined at creation of object
1393 // TODO Check also that invoice->ref is (PROV-POS1-2) with 1 = terminal and 2, the table ID
1394 }
1395 }
1396 if (!$permissiontoupdateline) {
1397 dol_htmloutput_errors($langs->trans("NotEnoughPermissions", "TakePos"), [], 1);
1398 } else {
1399 $vatratecode = $line->tva_tx;
1400 if ($line->vat_src_code) {
1401 $vatratecode .= ' ('.$line->vat_src_code.')';
1402 }
1403 $result = $invoice->updateline($line->id, $line->desc, $line->subprice, $line->qty, $number, $line->date_start, $line->date_end, $vatratecode, $line->localtax1_tx, $line->localtax2_tx, 'HT', $line->info_bits, $line->product_type, $line->fk_parent_line, 0, $line->fk_fournprice, $line->pa_ht, $line->label, $line->special_code, $line->array_options, $line->situation_percent, $line->fk_unit);
1404 }
1405 }
1406 }
1407 }
1408
1409 // Reload data
1410 $invoice->fetch($placeid);
1411 } elseif ($action == 'update_reduction_global' && $user->hasRight('takepos', 'editlines')) {
1412 foreach ($invoice->lines as $line) {
1413 $vatratecode = $line->tva_tx;
1414 if ($line->vat_src_code) {
1415 $vatratecode .= ' ('.$line->vat_src_code.')';
1416 }
1417 $result = $invoice->updateline($line->id, $line->desc, $line->subprice, $line->qty, $number, $line->date_start, $line->date_end, $vatratecode, $line->localtax1_tx, $line->localtax2_tx, 'HT', $line->info_bits, $line->product_type, $line->fk_parent_line, 0, $line->fk_fournprice, $line->pa_ht, $line->label, $line->special_code, $line->array_options, $line->situation_percent, $line->fk_unit);
1418 }
1419
1420 $invoice->fetch($placeid);
1421 }
1422
1423 if ($action == "editbatch_popup" && ($user->hasRight('takepos', 'run') || defined('INCLUDE_PHONEPAGE_FROM_PUBLIC_PAGE'))) {
1424 $idline = GETPOSTINT('idline');
1425 $idproduct = GETPOSTINT('idproduct');
1426 $prod = new Product($db);
1427 $prod->fetch($idproduct);
1428 $prod->load_stock('warehouseopen');
1429
1430 $constantforkey = 'CASHDESK_ID_WAREHOUSE'.$_SESSION["takeposterminal"];
1431 $warehouseid = getDolGlobalInt($constantforkey);
1432
1433 print '<html><body>';
1434 print '<div class="divscroll">';
1435 print '<div class="marginbottomonly"><b>'.dolPrintLabel($prod->label).'</b>'.(!empty($prod->ref) ? ' <span class="opacitymedium">('.dolPrintLabel($prod->ref).')</span>' : '').'</div>';
1436 print '<table class="noborder">';
1437
1438 $nbofsuggested = 0;
1439 if (is_array($prod->stock_warehouse)) {
1440 foreach ($prod->stock_warehouse as $tmpwarehouseid => $tmpval) {
1441 if (getDolGlobalInt($constantforkey) && $tmpwarehouseid != getDolGlobalInt($constantforkey)) {
1442 continue;
1443 }
1444 if (!empty($prod->stock_warehouse[$tmpwarehouseid]) && is_array($prod->stock_warehouse[$tmpwarehouseid]->detail_batch)) {
1445 foreach ($prod->stock_warehouse[$tmpwarehouseid]->detail_batch as $dbatch) {
1446 $detail = '';
1447 $detail .= '<span class="opacitymedium">'.$langs->trans("LotSerial").':</span> '.$dbatch->batch;
1448 $detail .= ' <span class="opacitymedium">'.$langs->trans("Qty").':</span> '.$dbatch->qty;
1449 $detail .= ' <button class="marginleftonly" onclick="updatebatch(\''.dol_escape_js($dbatch->batch).'\', '.$tmpwarehouseid.', '.$idline.', '.((int) $clonebatch).')">'.$langs->trans("Select")."</button>";
1450
1451 print '<tr><td class="left">'.$detail;
1452 $nbofsuggested++;
1453 print '</td></tr>';
1454 }
1455 }
1456 }
1457 }
1458 if ($nbofsuggested == 0) {
1459 print '<tr><td class="left">'.$langs->trans("NoRecordFound").'</td></tr>';
1460 }
1461
1462 // Add manual entry for returns or new batches
1463 print '<tr><td class="left" style="padding-top: 10px; border-top: 1px solid #ddd;">';
1464 print '<span class="opacitymedium">'.$langs->trans("LotSerial").' (Manual) :</span> ';
1465 print '<input type="text" id="manual_batch" class="flat" size="10"> ';
1466 print '<button class="button" onclick="updatebatch(document.getElementById(\'manual_batch\').value, '.$warehouseid.', '.$idline.', '.((int) $clonebatch).')">'.$langs->trans("Add").'</button>';
1467 print ' &nbsp; <button type="button" class="button button-cancel" onclick="$(\'#poslines\').load(\'invoice.php?place=\'+place+\'&invoiceid=\'+invoiceid);">'.$langs->trans("Cancel").'</button>';
1468 print '</td></tr>';
1469
1470 print "</table>";
1471 print '</div></body></html>';
1472 exit;
1473 }
1474
1475 if ($action == "setbatch" && ($user->hasRight('takepos', 'run') || defined('INCLUDE_PHONEPAGE_FROM_PUBLIC_PAGE'))) {
1476 $constantforkey = 'CASHDESK_ID_WAREHOUSE'.$_SESSION["takeposterminal"];
1477 $warehouseid = (GETPOSTINT('warehouseid') > 0 ? GETPOSTINT('warehouseid') : getDolGlobalInt($constantforkey)); // Get the warehouse id from GETPOSTINT('warehouseid'), otherwise use default setup.
1478 $idline = (empty($idoflineadded) ? GETPOSTINT('idline') : $idoflineadded);
1479 $sql = "UPDATE ".MAIN_DB_PREFIX."facturedet SET batch = '".$db->escape($batch)."', fk_warehouse = ".((int) $warehouseid);
1480 $sql .= " WHERE rowid = ".((int) $idline)." AND fk_facture = ".((int) $placeid);
1481 $db->query($sql);
1482
1483 // Reload data
1484 $invoice->fetch($placeid);
1485
1486 if ($clonebatch && isModEnabled('productbatch') && isModEnabled('stock')) {
1487 $sql = 'SELECT fd.rowid, fd.fk_product';
1488 $sql .= ' FROM '.MAIN_DB_PREFIX.'facturedet AS fd, '.MAIN_DB_PREFIX.'product AS p';
1489 $sql .= ' WHERE fd.fk_product = p.rowid';
1490 $sql .= ' AND fd.fk_facture = '.((int) $placeid);
1491 $sql .= " AND (fd.batch IS NULL OR fd.batch = '') AND p.tobatch > 0";
1492 $sql .= ' ORDER BY fd.rang, fd.rowid';
1493 $sql .= $db->plimit(1);
1494 $resql = $db->query($sql);
1495 if ($resql && ($obj = $db->fetch_object($resql))) {
1496 print '<script>editbatch('.((int) $obj->rowid).', '.((int) $obj->fk_product).', 1);</script>';
1497 exit;
1498 }
1499 }
1500 }
1501
1502 if ($action == "order" && $placeid != 0 && ($user->hasRight('takepos', 'run') || defined('INCLUDE_PHONEPAGE_FROM_PUBLIC_PAGE'))) {
1503 include_once DOL_DOCUMENT_ROOT.'/categories/class/categorie.class.php';
1504 if ((isModEnabled('receiptprinter') && getDolGlobalInt('TAKEPOS_PRINTER_TO_USE'.$term) > 0) || getDolGlobalString('TAKEPOS_PRINT_METHOD') == "receiptprinter" || getDolGlobalString('TAKEPOS_PRINT_METHOD') == "takeposconnector") {
1505 require_once DOL_DOCUMENT_ROOT.'/takepos/class/dolreceiptprinter.class.php';
1506 $printer = new dolReceiptPrinter($db);
1507 }
1508
1509 $sql = "SELECT label FROM ".MAIN_DB_PREFIX."takepos_floor_tables where rowid = ".((int) $place);
1510 $resql = $db->query($sql);
1511 $row = $db->fetch_object($resql);
1512 $headerorder = '<html><br><b>'.$langs->trans('Place').' '.$row->label.'<br><table width="65%"><thead><tr><th class="left">'.$langs->trans("Label").'</th><th class="right">'.$langs->trans("Qty").'</th></tr></thead><tbody>';
1513 $footerorder = '</tbody></table>'.dol_print_date(dol_now(), 'dayhour').'<br></html>';
1514 $order_receipt_printer1 = "";
1515 $order_receipt_printer2 = "";
1516 $order_receipt_printer3 = "";
1517 $catsprinter1 = explode(';', getDolGlobalString('TAKEPOS_PRINTED_CATEGORIES_1'));
1518 $catsprinter2 = explode(';', getDolGlobalString('TAKEPOS_PRINTED_CATEGORIES_2'));
1519 $catsprinter3 = explode(';', getDolGlobalString('TAKEPOS_PRINTED_CATEGORIES_3'));
1520 $linestoprint = 0;
1521 foreach ($invoice->lines as $line) {
1522 if ($line->special_code == "4") {
1523 continue;
1524 }
1525 $c = new Categorie($db);
1526 $existing = $c->containing($line->fk_product, Categorie::TYPE_PRODUCT, 'id');
1527 $result = array_intersect($catsprinter1, $existing);
1528 $count = count($result);
1529 if (!$line->fk_product) {
1530 $count++; // Print Free-text item (Unassigned printer) to Printer 1
1531 }
1532 if ($count > 0) {
1533 $linestoprint++;
1534 $sql = "UPDATE ".MAIN_DB_PREFIX."facturedet set special_code='1' where rowid = ".((int) $line->id); //Set to print on printer 1
1535 $db->query($sql);
1536 $order_receipt_printer1 .= '<tr><td class="left">';
1537 if ($line->fk_product) {
1538 $order_receipt_printer1 .= $line->product_label;
1539 } else {
1540 $order_receipt_printer1 .= $line->description;
1541 }
1542 $order_receipt_printer1 .= '</td><td class="right">'.$line->qty;
1543 if (!empty($line->array_options['options_order_notes'])) {
1544 $order_receipt_printer1 .= "<br>(".$line->array_options['options_order_notes'].")";
1545 }
1546 $order_receipt_printer1 .= '</td></tr>';
1547 }
1548 }
1549 if (((isModEnabled('receiptprinter') && getDolGlobalInt('TAKEPOS_PRINTER_TO_USE'.$term) > 0) || getDolGlobalString('TAKEPOS_PRINT_METHOD') == "receiptprinter" || getDolGlobalString('TAKEPOS_PRINT_METHOD') == "takeposconnector") && $linestoprint > 0 && $printer !== null) {
1550 $invoice->fetch($placeid); //Reload object before send to printer
1551 $printer->orderprinter = 1;
1552 echo "<script>";
1553 echo "var orderprinter1esc='";
1554 $ret = $printer->sendToPrinter($invoice, getDolGlobalInt('TAKEPOS_TEMPLATE_TO_USE_FOR_ORDERS'.$_SESSION["takeposterminal"]), getDolGlobalInt('TAKEPOS_ORDER_PRINTER1_TO_USE'.$_SESSION["takeposterminal"])); // PRINT TO PRINTER 1
1555 echo "';</script>";
1556 }
1557 $sql = "UPDATE ".MAIN_DB_PREFIX."facturedet set special_code='4' where special_code='1' and fk_facture = ".((int) $invoice->id); // Set as printed
1558 $db->query($sql);
1559 $invoice->fetch($placeid); //Reload object after set lines as printed
1560 $linestoprint = 0;
1561
1562 foreach ($invoice->lines as $line) {
1563 if ($line->special_code == "4") {
1564 continue;
1565 }
1566 $c = new Categorie($db);
1567 $existing = $c->containing($line->fk_product, Categorie::TYPE_PRODUCT, 'id');
1568 $result = array_intersect($catsprinter2, $existing);
1569 $count = count($result);
1570 if ($count > 0) {
1571 $linestoprint++;
1572 $sql = "UPDATE ".MAIN_DB_PREFIX."facturedet set special_code='2' where rowid = ".((int) $line->id); //Set to print on printer 2
1573 $db->query($sql);
1574 $order_receipt_printer2 .= '<tr>'.$line->product_label.'<td class="right">'.$line->qty;
1575 if (!empty($line->array_options['options_order_notes'])) {
1576 $order_receipt_printer2 .= "<br>(".$line->array_options['options_order_notes'].")";
1577 }
1578 $order_receipt_printer2 .= '</td></tr>';
1579 }
1580 }
1581 if (((isModEnabled('receiptprinter') && getDolGlobalInt('TAKEPOS_PRINTER_TO_USE'.$term) > 0) || getDolGlobalString('TAKEPOS_PRINT_METHOD') == "receiptprinter" || getDolGlobalString('TAKEPOS_PRINT_METHOD') == "takeposconnector") && $linestoprint > 0) {
1582 $invoice->fetch($placeid); //Reload object before send to printer
1583 $printer->orderprinter = 2;
1584 echo "<script>";
1585 echo "var orderprinter2esc='";
1586 $ret = $printer->sendToPrinter($invoice, getDolGlobalInt('TAKEPOS_TEMPLATE_TO_USE_FOR_ORDERS'.$_SESSION["takeposterminal"]), getDolGlobalInt('TAKEPOS_ORDER_PRINTER2_TO_USE'.$_SESSION["takeposterminal"])); // PRINT TO PRINTER 2
1587 echo "';</script>";
1588 }
1589 $sql = "UPDATE ".MAIN_DB_PREFIX."facturedet set special_code='4' where special_code='2' and fk_facture = ".((int) $invoice->id); // Set as printed
1590 $db->query($sql);
1591 $invoice->fetch($placeid); //Reload object after set lines as printed
1592 $linestoprint = 0;
1593
1594 foreach ($invoice->lines as $line) {
1595 if ($line->special_code == "4") {
1596 continue;
1597 }
1598 $c = new Categorie($db);
1599 $existing = $c->containing($line->fk_product, Categorie::TYPE_PRODUCT, 'id');
1600 $result = array_intersect($catsprinter3, $existing);
1601 $count = count($result);
1602 if ($count > 0) {
1603 $linestoprint++;
1604 $sql = "UPDATE ".MAIN_DB_PREFIX."facturedet set special_code='3' where rowid = ".((int) $line->id); //Set to print on printer 3
1605 $db->query($sql);
1606 $order_receipt_printer3 .= '<tr>'.$line->product_label.'<td class="right">'.$line->qty;
1607 if (!empty($line->array_options['options_order_notes'])) {
1608 $order_receipt_printer3 .= "<br>(".$line->array_options['options_order_notes'].")";
1609 }
1610 $order_receipt_printer3 .= '</td></tr>';
1611 }
1612 }
1613 if (((isModEnabled('receiptprinter') && getDolGlobalInt('TAKEPOS_PRINTER_TO_USE'.$term) > 0) || getDolGlobalString('TAKEPOS_PRINT_METHOD') == "receiptprinter" || getDolGlobalString('TAKEPOS_PRINT_METHOD') == "takeposconnector") && $linestoprint > 0 && $printer !== null) {
1614 $invoice->fetch($placeid); //Reload object before send to printer
1615 $printer->orderprinter = 3;
1616 echo "<script>";
1617 echo "var orderprinter3esc='";
1618 $ret = $printer->sendToPrinter($invoice, getDolGlobalInt('TAKEPOS_TEMPLATE_TO_USE_FOR_ORDERS'.$_SESSION["takeposterminal"]), getDolGlobalInt('TAKEPOS_ORDER_PRINTER3_TO_USE'.$_SESSION["takeposterminal"])); // PRINT TO PRINTER 3
1619 echo "';</script>";
1620 }
1621 $sql = "UPDATE ".MAIN_DB_PREFIX."facturedet set special_code='4' where special_code='3' and fk_facture = ".((int) $invoice->id); // Set as printed
1622 $db->query($sql);
1623 $invoice->fetch($placeid); //Reload object after set lines as printed
1624 }
1625
1626 $sectionwithinvoicelink = '';
1627 if (($action == "valid" || $action == "history" || $action == 'creditnote' || ($action == 'addline' && $invoice->status == $invoice::STATUS_CLOSED)) && $user->hasRight('takepos', 'run')) {
1628 $sectionwithinvoicelink .= '<!-- Section with invoice link -->'."\n";
1629 $sectionwithinvoicelink .= '<span style="font-size:120%;" class="center inline-block marginbottomonly">';
1630 if ($invoice->status == $invoice::STATUS_DRAFT) {
1631 $sectionwithinvoicelink .= $invoice->ref;
1632 } else {
1633 $sectionwithinvoicelink .= $invoice->getNomUrl(1, '', 0, 0, '', 0, 0, -1, '_backoffice');
1634 }
1635 $sectionwithinvoicelink .= " - ";
1636 $remaintopay = $invoice->getRemainToPay();
1637 if ($remaintopay > 0) {
1638 $sectionwithinvoicelink .= $langs->trans('RemainToPay').': <span class="amountremaintopay" style="font-size: unset">'.price($remaintopay, 1, $langs, 1, -1, -1, $conf->currency).'</span>';
1639 } else {
1640 $sectionwithinvoicelink .= $invoice->getLibStatut(2);
1641 }
1642
1643 $sectionwithinvoicelink .= '</span><br>';
1644
1645 $customprinterallowed = false;
1646 $customprinttemplateallowed = true;
1647
1648 // BAR RESTAURANT specific menu
1649 if (getDolGlobalString('TAKEPOS_BAR_RESTAURANT')) {
1650 // Button to print receipt before payment
1651 $customprinterallowed = true;
1652 $customprinttemplateallowed = true;
1653 }
1654
1655 include_once DOL_DOCUMENT_ROOT.'/blockedlog/lib/blockedlog.lib.php';
1656 if (isALNERunningVersion()) {
1657 // Custom printer may be allowed if mandatory information in template are guaranteed. For the moment, we prefer not allow this.
1658 $customprinttemplateallowed = false;
1659 }
1660
1661 if ($invoice->status == $invoice::STATUS_CLOSED) {
1662 if (getDolGlobalInt('TAKEPOS_PRINT_INVOICE_DOC_INSTEAD_OF_RECEIPT')) {
1663 $sectionwithinvoicelink .= ' <a target="_blank" class="button" href="' . DOL_URL_ROOT . '/document.php?token=' . newToken() . '&modulepart=facture&file=' . $invoice->ref . '/' . $invoice->ref . '.pdf">'.$langs->trans("Invoice").'</a>';
1664 } else {
1665 // This section should be same than into index.php
1666 if (getDolGlobalString('TAKEPOS_PRINT_METHOD') == "takeposconnector") {
1667 // Used when the external addon takeposconnector is installed. Deprecated.
1668 if (getDolGlobalString('TAKEPOS_PRINT_SERVER') && filter_var(getDolGlobalString('TAKEPOS_PRINT_SERVER'), FILTER_VALIDATE_URL) == true) {
1669 // If TAKEPOS_PRINT_SERVER is an URL
1670 $sectionwithinvoicelink .= ' <button id="buttonprint" type="button" onclick="PrintByESCPOSOld('.$placeid.')">'.$langs->trans('PrintTicket').'</button>';
1671 } else {
1672 // If TAKEPOS_PRINT_SERVER is an IP
1673 // Print by calling the receipt.php to get HTML content and send the HTML content to TAKEPOS_PRINT_SERVER:8111/print
1674 $sectionwithinvoicelink .= ' <button id="buttonprint" type="button" onclick="PrintHTMLToSlashPrint('.$placeid.')">'.$langs->trans('PrintTicket').'</button>';
1675 }
1676 } elseif ($customprinterallowed && $customprinttemplateallowed && (isModEnabled('receiptprinter') && getDolGlobalInt('TAKEPOS_PRINTER_TO_USE'.$term) > 0) || getDolGlobalString('TAKEPOS_PRINT_METHOD') == "receiptprinter") { // @phpstan-ignore-line
1677 // Button Print Receipt on special custom printer using custom template
1678 $nameOfPrinter = dol_getIdFromCode($db, getDolGlobalInt('TAKEPOS_PRINTER_TO_USE'.$term), 'printer_receipt', 'rowid', 'name', 1);
1679 $sectionwithinvoicelink .= ' <button id="buttonprint" type="button" onclick="PrintByESCPOS('.$placeid.')" title="'.dolPrintHTMLForAttribute($langs->trans("SentToPrinter").' '.$nameOfPrinter).'">'.$langs->trans('PrintTicket').'</button>';
1680 } else {
1681 // Button Print Receipt on browser
1682 $sectionwithinvoicelink .= ' <button id="buttonprint" type="button" onclick="PrintByBrowser('.$placeid.')">'.$langs->trans('PrintTicket').'</button>';
1683
1684 // Additional buttons
1685 if ($customprinttemplateallowed && getDolGlobalString('TAKEPOS_PRINT_WITHOUT_DETAILS')) {
1686 $sectionwithinvoicelink .= ' <button id="buttonprint" type="button" onclick="PrintBox('.$placeid.', \'without_details\')">'.$langs->trans('PrintWithoutDetails').'</button>';
1687 }
1688 if ($customprinttemplateallowed && getDolGlobalString('TAKEPOS_GIFT_RECEIPT')) {
1689 $sectionwithinvoicelink .= ' <button id="buttonprint" type="button" onclick="PrintByBrowser('.$placeid.', 1)">'.$langs->trans('GiftReceipt').'</button>';
1690 }
1691 }
1692 }
1693 if (getDolGlobalString('TAKEPOS_EMAIL_TEMPLATE_INVOICE') && getDolGlobalInt('TAKEPOS_EMAIL_TEMPLATE_INVOICE') > 0) {
1694 $sectionwithinvoicelink .= ' <button id="buttonsend" type="button" onclick="SendTicket('.$placeid.')">'.$langs->trans('SendTicket').'</button>';
1695 }
1696
1697 if ($remaintopay <= 0 && getDolGlobalString('TAKEPOS_AUTO_PRINT_TICKETS') && $action != "history") {
1698 $sectionwithinvoicelink .= '<script type="text/javascript">console.log("Emulate click on #buttonprint"); $("#buttonprint").click();</script>';
1699 }
1700 }
1701 }
1702}
1703
1704
1705/*
1706 * View
1707 */
1708
1709$form = new Form($db);
1710
1711// llxHeader
1712if (defined('INCLUDE_PHONEPAGE_FROM_PUBLIC_PAGE')) {
1713 $title = 'TakePOS - Dolibarr '.DOL_VERSION;
1714 if (getDolGlobalString('MAIN_APPLICATION_TITLE')) {
1715 $title = 'TakePOS - ' . getDolGlobalString('MAIN_APPLICATION_TITLE');
1716 }
1717 $head = '<meta name="apple-mobile-web-app-title" content="TakePOS"/>
1718 <meta name="apple-mobile-web-app-capable" content="yes">
1719 <meta name="mobile-web-app-capable" content="yes">
1720 <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no"/>';
1721 $arrayofcss = array(
1722 '/takepos/css/pos.css.php',
1723 );
1724 $arrayofjs = array('/takepos/js/jquery.colorbox-min.js');
1725 $disablejs = 0;
1726 $disablehead = 0;
1727 top_htmlhead($head, $title, $disablejs, $disablehead, $arrayofjs, $arrayofcss);
1728
1729 print '<body>'."\n";
1730} else {
1731 top_httphead('text/html', 1);
1732}
1733
1734?>
1735<!-- invoice.php -->
1736<script type="text/javascript">
1737var selectedline=0;
1738var selectedtext="";
1739<?php if ($action == "valid") {
1740 echo "var place=0;";
1741}?> // Set to default place after close sale
1742var placeid=<?php echo($placeid > 0 ? $placeid : 0); ?>;
1743$(document).ready(function() {
1744 var idoflineadded = <?php echo(empty($idoflineadded) ? 0 : $idoflineadded); ?>;
1745
1746 $('.posinvoiceline').click(function(){
1747 console.log("Click done on "+this.id);
1748 $('.posinvoiceline').removeClass("selected");
1749 $(this).addClass("selected");
1750 if (!this.id) {
1751 return;
1752 }
1753 if (selectedline == this.id) {
1754 return; // If is already selected
1755 } else {
1756 selectedline = this.id;
1757 }
1758 selectedtext=$('#'+selectedline).find("td:first").html();
1759 <?php
1760 if (defined('INCLUDE_PHONEPAGE_FROM_PUBLIC_PAGE')) {
1761 print '$("#phonediv1").load("'.DOL_URL_ROOT.'/takepos/public/auto_order.php?action=editline&token='.newToken().'&placeid="+placeid+"&selectedline="+selectedline, function() {
1762 });';
1763 }
1764 ?>
1765 });
1766
1767 /* Autoselect the line */
1768 if (idoflineadded > 0)
1769 {
1770 console.log("Auto select "+idoflineadded);
1771 $('.posinvoiceline#'+idoflineadded).click();
1772 }
1773<?php
1774
1775if ($action == "order" && !empty($order_receipt_printer1)) {
1776 if (filter_var(getDolGlobalString('TAKEPOS_PRINT_SERVER'), FILTER_VALIDATE_URL) == true) {
1777 ?>
1778 $.ajax({
1779 type: "POST",
1780 url: '<?php print getDolGlobalString('TAKEPOS_PRINT_SERVER'); ?>/printer/index.php',
1781 data: 'invoice='+orderprinter1esc
1782 });
1783 <?php
1784 } else {
1785 ?>
1786 $.ajax({
1787 type: "POST",
1788 url: 'http://<?php print getDolGlobalString('TAKEPOS_PRINT_SERVER'); ?>:8111/print',
1789 data: '<?php
1790 print $headerorder.$order_receipt_printer1.$footerorder; ?>'
1791 });
1792 <?php
1793 }
1794}
1795
1796if ($action == "order" && !empty($order_receipt_printer2)) {
1797 if (filter_var(getDolGlobalString('TAKEPOS_PRINT_SERVER'), FILTER_VALIDATE_URL) == true) {
1798 ?>
1799 $.ajax({
1800 type: "POST",
1801 url: '<?php print getDolGlobalString('TAKEPOS_PRINT_SERVER'); ?>/printer/index.php?printer=2',
1802 data: 'invoice='+orderprinter2esc
1803 });
1804 <?php
1805 } else {
1806 ?>
1807 $.ajax({
1808 type: "POST",
1809 url: 'http://<?php print getDolGlobalString('TAKEPOS_PRINT_SERVER'); ?>:8111/print2',
1810 data: '<?php
1811 print $headerorder.$order_receipt_printer2.$footerorder; ?>'
1812 });
1813 <?php
1814 }
1815}
1816
1817if ($action == "order" && !empty($order_receipt_printer3)) {
1818 if (filter_var(getDolGlobalString('TAKEPOS_PRINT_SERVER'), FILTER_VALIDATE_URL) == true) {
1819 ?>
1820 $.ajax({
1821 type: "POST",
1822 url: '<?php print getDolGlobalString('TAKEPOS_PRINT_SERVER'); ?>/printer/index.php?printer=3',
1823 data: 'invoice='+orderprinter3esc
1824 });
1825 <?php
1826 }
1827}
1828
1829// Set focus to search field
1830if ($action == "search" || $action == "valid") {
1831 ?>
1832 parent.ClearSearch(true);
1833 <?php
1834}
1835
1836
1837if ($action == "search") {
1838 ?>
1839 $('#search').focus();
1840 <?php
1841}
1842
1843?>
1844
1845});
1846
1847function SendTicket(id)
1848{
1849 console.log("Open box to select the Print/Send form");
1850 $.colorbox({href:"send.php?facid="+id, width:"70%", height:"30%", transition:"none", iframe:"true", title:<?php echo "'".dol_escape_js($langs->trans("SendTicket"))."'" ; ?>});
1851 return true;
1852}
1853
1854/* Open the popup of the receipt to allow printing */
1855function PrintBox(id, action) {
1856 console.log("Open box before printing");
1857 $.colorbox({href:"printbox.php?facid="+id+"&action="+action+"&token=<?php echo newToken(); ?>", width:"80%", height:"200px", transition:"none", iframe:"true", title:"<?php echo $langs->trans("PrintWithoutDetails"); ?>"});
1858 return true;
1859}
1860
1861/* Open the popup of the receipt to allow printing */
1862function PrintByBrowser(id, gift) {
1863 console.log("Call PrintByBrowser() to generate the receipt.");
1864 $.colorbox({href:"receipt.php?facid="+id+"&gift="+gift, width:"40%", height:"90%", transition:"none", iframe:"true", title:<?php echo "'".dol_escape_js($langs->trans("PrintTicket"))."'" ; ?>});
1865 return true;
1866}
1867
1868/* Print of configured printer when TAKEPOS_PRINT_SERVER is IP */
1869function PrintHTMLToSlashPrint(id){
1870 var receipt;
1871 console.log("PrintHTMLToSlashPrint" + id);
1872 $.get("receipt.php?facid="+id, function(data, status) {
1873 receipt=data.replace(/([^>\r\n]?)(\r\n|\n\r|\r|\n)/g, '');
1874 $.ajax({
1875 type: "POST",
1876 url: 'http://<?php print getDolGlobalString('TAKEPOS_PRINT_SERVER'); ?>:8111/print',
1877 data: receipt
1878 });
1879 });
1880 return true;
1881}
1882
1883/* Print of configured printer when TAKEPOS_PRINT_SERVER is URL, using the ESCPOS driver */
1884function PrintByESCPOSOld(id){
1885 console.log("PrintByESCPOSOld id=" + id);
1886 $.get("<?php echo DOL_URL_ROOT; ?>/takepos/ajax/ajax.php?action=printinvoiceticket&token=<?php echo currentToken(); ?>&term=<?php echo urlencode(isset($_SESSION["takeposterminal"]) ? $_SESSION["takeposterminal"] : ''); ?>&id="+id, function(data, status) {
1887 $.ajax({
1888 type: "POST",
1889 url: '<?php print getDolGlobalString('TAKEPOS_PRINT_SERVER'); ?>/printer/index.php',
1890 data: 'invoice='+data
1891 });
1892 });
1893 return true;
1894}
1895
1896<?php
1897$nameOfPrinter = dol_getIdFromCode($db, getDolGlobalInt('TAKEPOS_PRINTER_TO_USE'.$term), 'printer_receipt', 'rowid', 'name', 1);
1898?>
1899// Call the ajax to execute the printinvoiceticket action, using the ESCPOS driver
1900// With some external module another method may be called.
1901function PrintByESCPOS(id) {
1902 console.log("PrintByESCPOS Printing invoice ticket by calling takepos/aja/ajax.php id=" + id);
1903
1904 $.ajax({
1905 type: "GET",
1906 data: { token: '<?php echo currentToken(); ?>' },
1907 url: "<?php print DOL_URL_ROOT.'/takepos/ajax/ajax.php?action=printinvoiceticket&token='.currentToken().'&term='.urlencode(isset($_SESSION["takeposterminal"]) ? $_SESSION["takeposterminal"] : '').'&id='; ?>" + id,
1908 success: function(){
1909 showPrintResultPopup(<?php echo "'".dol_escape_js($langs->trans("SentToPrinter").' '.$nameOfPrinter)."'" ; ?>, 2000);
1910 },
1911 error: function(){
1912 showPrintResultPopup(<?php echo "'".dol_escape_js($langs->trans("FailedToSendToPrinter"))."'" ; ?>, 2000);
1913 }
1914 });
1915 return true;
1916}
1917
1918// Show the message in div popup
1919function showPrintResultPopup(message, duration) {
1920 $("#dialogforpopuptakepos").show().text(message).fadeIn();
1921
1922 setTimeout(function(){
1923 $("#dialogforpopuptakepos").fadeOut().hide();
1924 }, duration);
1925}
1926
1927
1928
1929// Call url to generate a credit note (with same lines) from existing invoice
1930var creditNoteParams="";
1931function CreditNote() {
1932 <?php
1933 $parameters = array();
1934 $reshook = $hookmanager->executeHooks('paramsForCreditNote', $parameters, $invoice, $action);?>
1935 $("#poslines").load("<?php
1936 print DOL_URL_ROOT; ?>/takepos/invoice.php?action=creditnote&token=<?php echo newToken() ?>&invoiceid="+placeid+creditNoteParams, function() { });
1937 return true;
1938}
1939
1940
1941// Call url to add notes
1942function SetNote() {
1943 $("#poslines").load("<?php print DOL_URL_ROOT; ?>/takepos/invoice.php?action=addnote&token=<?php echo newToken() ?>&invoiceid="+placeid+"&idline="+selectedline, { "addnote": $("#textinput").val() });
1944 return true;
1945}
1946
1947
1948$( document ).ready(function() {
1949 console.log("Set customer info and sales in header placeid=<?php echo $placeid; ?> status=<?php echo $invoice->statut; ?>");
1950
1951 <?php
1952 $s = $langs->trans("Customer");
1953 if ($invoice->id > 0 && ($invoice->socid != getDolGlobalString($constforcompanyid))) {
1954 $s = $soc->name;
1955 if (getDolGlobalInt('TAKEPOS_CHOOSE_CONTACT')) {
1956 $contactids = $invoice->getIdContact('external', 'BILLING');
1957 $contactid = $contactids[0];
1958 if ($contactid > 0) {
1959 $contact = new Contact($db);
1960 $contact->fetch($contactid);
1961 $s .= " - " . $contact->getFullName($langs);
1962 }
1963 }
1964 } elseif (getDolGlobalInt("TAKEPOS_NO_GENERIC_THIRDPARTY")) {
1965 print '$("#idcustomer").val("");';
1966 }
1967 ?>
1968
1969 $("#customerandsales").html('');
1970 $("#shoppingcart").html('');
1971
1972 <?php if (getDolGlobalInt('TAKEPOS_CHOOSE_CONTACT') == 0) { ?>
1973 $("#customerandsales").append('<a class="valignmiddle tdoverflowmax100 minwidth100" id="customer" onclick="Customer();" title="<?php print dol_escape_js(dol_escape_htmltag((string) $s)); ?>"><span class="fas fa-building paddingrightonly"></span><?php print dol_escape_js((string) $s); ?></a>');
1974 <?php } else { ?>
1975 $("#customerandsales").append('<a class="valignmiddle tdoverflowmax300 minwidth100" id="contact" onclick="Contact();" title="<?php print dol_escape_js(dol_escape_htmltag((string) $s)); ?>"><span class="fas fa-building paddingrightonly"></span><?php print dol_escape_js((string) $s); ?></a>');
1976 <?php } ?>
1977
1978 <?php
1979 $sql = "SELECT rowid, datec, ref FROM ".MAIN_DB_PREFIX."facture";
1980 $sql .= " WHERE entity IN (".getEntity('invoice').")";
1981 if (!getDolGlobalString('TAKEPOS_CAN_EDIT_IF_ALREADY_VALIDATED')) {
1982 // By default, only invoices with a ref not already defined can in list of open invoice we can edit.
1983 $sql .= " AND ref LIKE '(PROV-POS".$db->escape(isset($_SESSION["takeposterminal"]) ? $_SESSION["takeposterminal"] : '')."-0%'";
1984 } else {
1985 // If TAKEPOS_CAN_EDIT_IF_ALREADY_VALIDATED set, we show also draft invoice that already has a reference defined
1986 $sql .= " AND pos_source = '".$db->escape((string) $_SESSION["takeposterminal"])."'";
1987 $sql .= " AND module_source = 'takepos'";
1988 }
1989
1990 $sql .= $db->order('datec', 'ASC');
1991 $resql = $db->query($sql);
1992 if ($resql) {
1993 $max_sale = 0;
1994 while ($obj = $db->fetch_object($resql)) {
1995 echo '$("#shoppingcart").append(\'';
1996 echo '<a class="valignmiddle" title="'.dol_escape_js($langs->trans("SaleStartedAt", dol_print_date($db->jdate($obj->datec), '%H:%M', 'tzuser')).' - '.$obj->ref).'" onclick="place=\\\'';
1997 $num_sale = str_replace(")", "", str_replace("(PROV-POS".$_SESSION["takeposterminal"]."-", "", $obj->ref));
1998 echo $num_sale;
1999 if (str_replace("-", "", $num_sale) > $max_sale) {
2000 $max_sale = str_replace("-", "", $num_sale);
2001 }
2002 echo '\\\'; invoiceid=\\\'';
2003 echo $obj->rowid;
2004 echo '\\\'; Refresh();">';
2005 if ($placeid == $obj->rowid) {
2006 echo '<span class="basketselected">';
2007 } else {
2008 echo '<span class="basketnotselected">';
2009 }
2010 echo '<span class="fa fa-shopping-cart paddingright"></span>'.dol_print_date($db->jdate($obj->datec), '%H:%M', 'tzuser');
2011 echo '</span>';
2012 echo '</a>\');';
2013 }
2014 echo '$("#shoppingcart").append(\'<a onclick="place=\\\'0-';
2015 echo $max_sale + 1;
2016 echo '\\\'; invoiceid=0; Refresh();"><div><span class="fa fa-plus" title="'.dol_escape_htmltag($langs->trans("StartAParallelSale")).'"><span class="fa fa-shopping-cart"></span></div></a>\');';
2017 } else {
2018 dol_print_error($db);
2019 }
2020
2021 $s = '';
2022
2023 $idwarehouse = 0;
2024 $constantforkey = 'CASHDESK_NO_DECREASE_STOCK'. (isset($_SESSION["takeposterminal"]) ? $_SESSION["takeposterminal"] : '');
2025 if (isModEnabled('stock')) {
2026 if (getDolGlobalString($constantforkey) != "1") {
2027 $constantforkey = 'CASHDESK_ID_WAREHOUSE'. (isset($_SESSION["takeposterminal"]) ? $_SESSION["takeposterminal"] : '');
2028 $idwarehouse = getDolGlobalInt($constantforkey);
2029 if ($idwarehouse > 0) {
2030 $s = '<span class="small">';
2031 $warehouse = new Entrepot($db);
2032 $warehouse->fetch($idwarehouse);
2033 $s .= '<span class="hideonsmartphone">'.$langs->trans("Warehouse").'<br></span>'.$warehouse->ref;
2034 if ($warehouse->statut == Entrepot::STATUS_CLOSED) {
2035 $s .= ' ('.$langs->trans("Closed").')';
2036 }
2037 $s .= '</span>';
2038 print "$('#infowarehouse').html('".dol_escape_js($s)."');";
2039 print '$("#infowarehouse").css("display", "inline-block");';
2040 } else {
2041 $s = '<span class="small hideonsmartphone">';
2042 $s .= $langs->trans("StockChangeDisabled").'<br>'.$langs->trans("NoWarehouseDefinedForTerminal");
2043 $s .= '</span>';
2044 print "$('#infowarehouse').html('".dol_escape_js($s)."');";
2045 if (!empty($conf->dol_optimize_smallscreen)) {
2046 print '$("#infowarehouse").css("display", "none");';
2047 }
2048 }
2049 } else {
2050 $s = '<span class="small hideonsmartphone">'.$langs->trans("StockChangeDisabled").'</span>';
2051 print "$('#infowarehouse').html('".dol_escape_js($s)."');";
2052 if (!empty($conf->dol_optimize_smallscreen)) {
2053 print '$("#infowarehouse").css("display", "none");';
2054 }
2055 }
2056 }
2057
2058
2059 // Module Adherent
2060 $s = '';
2061 if (isModEnabled('member') && $invoice->socid > 0 && $invoice->socid != getDolGlobalInt($constforcompanyid)) {
2062 $s = '<span class="small">';
2063 require_once DOL_DOCUMENT_ROOT.'/adherents/class/adherent.class.php';
2064 $langs->load("members");
2065 $s .= $langs->trans("Member").': ';
2066 $adh = new Adherent($db);
2067 $result = $adh->fetch(0, '', $invoice->socid);
2068 if ($result > 0) {
2069 $adh->ref = $adh->getFullName($langs);
2070 if (empty($adh->status) || $adh->status == Adherent::STATUS_EXCLUDED) {
2071 $s .= "<s>";
2072 }
2073 $s .= $adh->getFullName($langs);
2074 $s .= ' - '.$adh->type;
2075 if ($adh->datefin) {
2076 $s .= '<br>'.$langs->trans("SubscriptionEndDate").': '.dol_print_date($adh->datefin, 'day');
2077 if ($adh->hasDelay()) {
2078 $s .= " ".img_warning($langs->trans("Late"));
2079 }
2080 } else {
2081 $s .= '<br>'.$langs->trans("SubscriptionNotReceived");
2082 if ($adh->status > 0) {
2083 $s .= " ".img_warning($langs->trans("Late")); // displays delay Pictogram only if not a draft and not terminated
2084 }
2085 }
2086 if (empty($adh->status) || $adh->status == Adherent::STATUS_EXCLUDED) {
2087 $s .= "</s>";
2088 }
2089 } else {
2090 $s .= '<br>'.$langs->trans("ThirdpartyNotLinkedToMember");
2091 }
2092 $s .= '</span>';
2093 }
2094 ?>
2095 $("#moreinfo").html(<?php print "'".dol_escape_js($s)."'" ; ?>);
2096
2097});
2098
2099
2100<?php
2101if (getDolGlobalString('TAKEPOS_CUSTOMER_DISPLAY')) {
2102 echo "function CustomerDisplay(){";
2103 echo "var line1='".$CUSTOMER_DISPLAY_line1."'.substring(0,20);";
2104 echo "line1=line1.padEnd(20);";
2105 echo "var line2='".$CUSTOMER_DISPLAY_line2."'.substring(0,20);";
2106 echo "line2=line2.padEnd(20);";
2107 if (getDolGlobalString('TAKEPOS_CONNECTOR_TO_WHB_CUSTOMER_DISPLAY')) {
2108 echo 'webSocketCustomerDisplay.send(line1);';
2109 echo 'webSocketCustomerDisplay.send(line2);';
2110 } else {
2111 echo "$.ajax({
2112 type: 'GET',
2113 data: { text: line1+line2 },
2114 url: '".getDolGlobalString('TAKEPOS_PRINT_SERVER')."/display/index.php',
2115 });";
2116 }
2117 echo "}";
2118}
2119?>
2120
2121</script>
2122
2123
2124<?php
2125// Add again js for footer because this content is injected into index.php page so all init
2126// for tooltip and other js beautifiers must be reexecuted too.
2127if (!empty($conf->use_javascript_ajax)) {
2128 print "\n".'<!-- Includes JS Footer of Dolibarr -->'."\n";
2129 print '<script src="'.DOL_URL_ROOT.'/core/js/lib_foot.js.php?lang='.$langs->defaultlang.'"></script>'."\n";
2130}
2131
2132$usediv = (GETPOST('format', 'aZ09') == 'div');
2133
2134print '<!-- invoice.php place='.(int) $place.' invoice='.$invoice->ref.' usediv='.json_encode($usediv).', mobilepage='.(empty($mobilepage) ? '' : $mobilepage).' $_SESSION["basiclayout"]='.(empty($_SESSION["basiclayout"]) ? '' : $_SESSION["basiclayout"]).' conf TAKEPOS_BAR_RESTAURANT='.getDolGlobalString('TAKEPOS_BAR_RESTAURANT').' -->'."\n";
2135print '<div class="div-table-responsive-no-min invoice">';
2136if ($usediv) {
2137 print '<div id="tablelines">';
2138} else {
2139 print '<table id="tablelines" class="noborder noshadow postablelines centpercent">';
2140}
2141
2142$buttontocreatecreditnote = '';
2143if (($action == "valid" || $action == "history" || $action == "addline")
2144 && $invoice->type != Facture::TYPE_CREDIT_NOTE && !getDolGlobalString('TAKEPOS_NO_CREDITNOTE') && $invoice->status == $invoice::STATUS_CLOSED) {
2145 $buttontocreatecreditnote .= ' &nbsp; <!-- Show button to create a credit note -->'."\n";
2146 $buttontocreatecreditnote .= '<button id="buttonprint" type="button" onclick="ModalBox(\'ModalCreditNote\')">'.$langs->trans('CreateCreditNote').'</button>';
2147 if (getDolGlobalInt('TAKEPOS_PRINT_INVOICE_DOC_INSTEAD_OF_RECEIPT')) {
2148 $buttontocreatecreditnote .= ' <a target="_blank" class="button" href="' . DOL_URL_ROOT . '/document.php?token=' . newToken() . '&modulepart=facture&file=' . urlencode($invoice->ref . '/' . $invoice->ref . '.pdf').'">'.$langs->trans("Invoice").'</a>';
2149 }
2150}
2151
2152$buttontocloneticket = '';
2153if (($action == 'valid' || $action == 'history' || $action == 'addline') && in_array($invoice->status, array(Facture::STATUS_VALIDATED, Facture::STATUS_CLOSED)) && $invoice->type != Facture::TYPE_CREDIT_NOTE) {
2154 $buttontocloneticket .= ' &nbsp;<button id="buttonclone" type="button" onclick="CloneTicket('.((int) $invoice->id).')">'.$langs->trans('CloneTicket').'</button>';
2155}
2156
2157// Show the ref of invoice
2158if ($sectionwithinvoicelink && ($mobilepage == "invoice" || $mobilepage == "")) {
2159 print '<!-- Print table line with link to invoice ref -->';
2160 if (getDolGlobalString('TAKEPOS_SHOW_HT')) {
2161 print '<tr><td colspan="5" class="paddingtopimp paddingbottomimp" style="padding-top: 10px !important; padding-bottom: 10px !important;">';
2162 print $sectionwithinvoicelink;
2163 print $buttontocreatecreditnote;
2164 print $buttontocloneticket;
2165 print '</td></tr>';
2166 } else {
2167 print '<tr><td colspan="4" class="paddingtopimp paddingbottomimp" style="padding-top: 10px !important; padding-bottom: 10px !important;">';
2168 print $sectionwithinvoicelink;
2169 print $buttontocreatecreditnote;
2170 print $buttontocloneticket;
2171 print '</td></tr>';
2172 }
2173}
2174
2175// Show the list of selected product
2176if (!$usediv) {
2177 print '<tr class="liste_titre nodrag nodrop">';
2178 print '<td class="linecoldescription">';
2179}
2180// In phone version only show when it is invoice page
2181if (empty($mobilepage) || $mobilepage == "invoice") {
2182 print '<!-- hidden var used by some js functions -->';
2183 print '<input type="hidden" name="invoiceid" id="invoiceid" value="'.$invoice->id.'">';
2184 print '<input type="hidden" name="thirdpartyid" id="thirdpartyid" value="'.$invoice->socid.'">';
2185}
2186if (!$usediv) {
2187 if (getDolGlobalString('TAKEPOS_BAR_RESTAURANT')) {
2188 $sql = "SELECT floor, label FROM ".MAIN_DB_PREFIX."takepos_floor_tables where rowid = ".((int) $place);
2189 $resql = $db->query($sql);
2190 $obj = $db->fetch_object($resql);
2191 if ($obj) {
2192 $label = $obj->label;
2193 $floor = $obj->floor;
2194 }
2195 if ($mobilepage == "invoice" || $mobilepage == "") {
2196 // If not on smartphone version or if it is the invoice page
2197 //print 'mobilepage='.$mobilepage;
2198 print '<span class="opacitymedium">'.$langs->trans('Place')."</span> <b>".(empty($label) ? '?' : $label)."</b><br>";
2199 print '<span class="opacitymedium">'.$langs->trans('Floor')."</span> <b>".(empty($floor) ? '?' : $floor)."</b>";
2200 }
2201 }
2202 print '</td>';
2203}
2204
2205// Complete header by hook
2206$parameters = array();
2207$reshook = $hookmanager->executeHooks('completeTakePosInvoiceHeader', $parameters, $invoice, $action); // Note that $action and $object may have been modified by some hooks
2208if ($reshook < 0) {
2209 setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
2210}
2211print $hookmanager->resPrint;
2212
2213if (empty($_SESSION["basiclayout"]) || $_SESSION["basiclayout"] != 1) {
2214 if (getDolGlobalInt("TAKEPOS_SHOW_SUBPRICE")) {
2215 print '<td class="linecolqty right">'.$langs->trans('PriceUHT').'</td>';
2216 }
2217 print '<td class="linecolqty right">'.$langs->trans('ReductionShort').'</td>';
2218 print '<td class="linecolqty right">'.$langs->trans('Qty').'</td>';
2219 if (getDolGlobalString('TAKEPOS_SHOW_HT')) {
2220 print '<td class="linecolht right nowraponall">';
2221 print '<span class="opacitymedium small">' . $langs->trans('TotalHTShort') . '</span><br>';
2222 // In phone version only show when it is invoice page
2223 if (empty($mobilepage) || $mobilepage == "invoice") {
2224 print '<span id="linecolht-span-total" style="font-size:1.3em; font-weight: bold;">' . price($invoice->total_ht, 1, '', 1, -1, -1, $conf->currency) . '</span>';
2225 if (isModEnabled('multicurrency') && !empty($_SESSION["takeposcustomercurrency"]) && $conf->currency != $_SESSION["takeposcustomercurrency"]) {
2226 //Only show customer currency if multicurrency module is enabled, if currency selected and if this currency selected is not the same as main currency
2227 include_once DOL_DOCUMENT_ROOT . '/multicurrency/class/multicurrency.class.php';
2228 $multicurrency = new MultiCurrency($db);
2229 $multicurrency->fetch(0, $_SESSION["takeposcustomercurrency"]);
2230 print '<br><span id="linecolht-span-total" style="font-size:0.9em; font-style:italic;">(' . price($invoice->total_ht * $multicurrency->rate->rate) . ' ' . $_SESSION["takeposcustomercurrency"] . ')</span>';
2231 }
2232 }
2233 print '</td>';
2234 }
2235 print '<td class="linecolht right nowraponall">';
2236 print '<span class="opacitymedium small">'.$langs->trans('TotalTTCShort').'</span><br>';
2237 // In phone version only show when it is invoice page
2238 if (empty($mobilepage) || $mobilepage == "invoice") {
2239 print '<span id="linecolht-span-total" style="font-size:1.3em; font-weight: bold;">'.price($invoice->total_ttc, 1, '', 1, -1, -1, $conf->currency).'</span>';
2240 if (isModEnabled('multicurrency') && !empty($_SESSION["takeposcustomercurrency"]) && $conf->currency != $_SESSION["takeposcustomercurrency"]) {
2241 //Only show customer currency if multicurrency module is enabled, if currency selected and if this currency selected is not the same as main currency
2242 include_once DOL_DOCUMENT_ROOT.'/multicurrency/class/multicurrency.class.php';
2243 $multicurrency = new MultiCurrency($db);
2244 $multicurrency->fetch(0, $_SESSION["takeposcustomercurrency"]);
2245 print '<br><span id="linecolht-span-total" style="font-size:0.9em; font-style:italic;">('.price($invoice->total_ttc * $multicurrency->rate->rate).' '.$_SESSION["takeposcustomercurrency"].')</span>';
2246 }
2247 }
2248 print '</td>';
2249} elseif ($mobilepage == "invoice") {
2250 print '<td class="linecolqty right">'.$langs->trans('Qty').'</td>';
2251}
2252if (!$usediv) {
2253 print "</tr>\n";
2254}
2255
2256if (!empty($_SESSION["basiclayout"]) && $_SESSION["basiclayout"] == 1) {
2257 if ($mobilepage == "cats") {
2258 require_once DOL_DOCUMENT_ROOT.'/categories/class/categorie.class.php';
2259 $categorie = new Categorie($db);
2260 $categories = $categorie->get_full_arbo('product');
2261 $htmlforlines = '';
2262 foreach ($categories as $row) {
2263 if (defined('INCLUDE_PHONEPAGE_FROM_PUBLIC_PAGE')) {
2264 $htmlforlines .= '<div class="leftcat"';
2265 } else {
2266 $htmlforlines .= '<tr class="drag drop oddeven posinvoiceline"';
2267 }
2268 $htmlforlines .= ' onclick="LoadProducts('.$row['id'].');">';
2269 if (defined('INCLUDE_PHONEPAGE_FROM_PUBLIC_PAGE')) {
2270 $htmlforlines .= '<img class="imgwrapper" width="33%" src="'.DOL_URL_ROOT.'/takepos/public/auto_order.php?genimg=cat&query=cat&id='.$row['id'].'"><br>';
2271 } else {
2272 $htmlforlines .= '<td class="left">';
2273 }
2274 $htmlforlines .= $row['label'];
2275 if (defined('INCLUDE_PHONEPAGE_FROM_PUBLIC_PAGE')) {
2276 $htmlforlines .= '</div>'."\n";
2277 } else {
2278 $htmlforlines .= '</td></tr>'."\n";
2279 }
2280 }
2281 print $htmlforlines;
2282 }
2283
2284 if ($mobilepage == "products") {
2285 require_once DOL_DOCUMENT_ROOT.'/categories/class/categorie.class.php';
2286 $object = new Categorie($db);
2287 $catid = GETPOSTINT('catid');
2288 $result = $object->fetch($catid);
2289 $prods = $object->getObjectsInCateg("product");
2291 '@phan-var-force Product[] $prods';
2292 $htmlforlines = '';
2293 foreach ($prods as $row) {
2294 if (defined('INCLUDE_PHONEPAGE_FROM_PUBLIC_PAGE')) {
2295 $htmlforlines .= '<div class="leftcat"';
2296 } else {
2297 $htmlforlines .= '<tr class="drag drop oddeven posinvoiceline"';
2298 }
2299 $htmlforlines .= ' onclick="AddProduct(\''.$place.'\', '.$row->id.')"';
2300 $htmlforlines .= '>';
2301 if (defined('INCLUDE_PHONEPAGE_FROM_PUBLIC_PAGE')) {
2302 $htmlforlines .= '<img class="imgwrapper" width="33%" src="'.DOL_URL_ROOT.'/takepos/public/auto_order.php?genimg=pro&query=pro&id='.$row->id.'"><br>';
2303 $htmlforlines .= $row->label.' '.price($row->price_ttc, 1, $langs, 1, -1, -1, $conf->currency);
2304 $htmlforlines .= '</div>'."\n";
2305 } else {
2306 $htmlforlines .= '<td class="left">';
2307 $htmlforlines .= $row->label;
2308 $htmlforlines .= '<div class="right">'.price($row->price_ttc, 1, $langs, 1, -1, -1, $conf->currency).'</div>';
2309 $htmlforlines .= '</td>';
2310 $htmlforlines .= '</tr>'."\n";
2311 }
2312 }
2313 print $htmlforlines;
2314 }
2315
2316 if ($mobilepage == "places") {
2317 $sql = "SELECT rowid, entity, label, leftpos, toppos, floor FROM ".MAIN_DB_PREFIX."takepos_floor_tables";
2318 $resql = $db->query($sql);
2319
2320 $rows = array();
2321 $htmlforlines = '';
2322 while ($row = $db->fetch_array($resql)) {
2323 $rows[] = $row;
2324 $htmlforlines .= '<tr class="drag drop oddeven posinvoiceline';
2325 $htmlforlines .= '" onclick="LoadPlace(\''.$row['label'].'\')">';
2326 $htmlforlines .= '<td class="left">';
2327 $htmlforlines .= $row['label'];
2328 $htmlforlines .= '</td>';
2329 $htmlforlines .= '</tr>'."\n";
2330 }
2331 print $htmlforlines;
2332 }
2333}
2334
2335if ($placeid > 0) {
2336 //In Phone basic layout hide some content depends situation
2337 if (!empty($_SESSION["basiclayout"]) && $_SESSION["basiclayout"] == 1 && $mobilepage != "invoice" && $action != "order") {
2338 return;
2339 }
2340
2341 // Loop on each lines on invoice
2342 if (is_array($invoice->lines) && count($invoice->lines)) {
2343 print '<!-- invoice.php show lines of invoices -->'."\n";
2344 $tmplines = array_reverse($invoice->lines);
2345 $htmlsupplements = array();
2346 foreach ($tmplines as $line) {
2347 if ($line->fk_parent_line != false) {
2348 if (!isset($htmlsupplements[$line->fk_parent_line])) {
2349 $htmlsupplements[$line->fk_parent_line] = '';
2350 }
2351 $htmlsupplements[$line->fk_parent_line] .= '<tr class="drag drop oddeven posinvoiceline';
2352 if ($line->special_code == "4") {
2353 $htmlsupplements[$line->fk_parent_line] .= ' order';
2354 }
2355 $htmlsupplements[$line->fk_parent_line] .= '" id="'.$line->id.'"';
2356 if ($line->special_code == "4") {
2357 $htmlsupplements[$line->fk_parent_line] .= ' title="'.dol_escape_htmltag($langs->trans("AlreadyPrinted")).'"';
2358 }
2359 $htmlsupplements[$line->fk_parent_line] .= '>';
2360 $htmlsupplements[$line->fk_parent_line] .= '<td class="left">';
2361 $htmlsupplements[$line->fk_parent_line] .= img_picto('', 'rightarrow.png');
2362 if ($line->product_label) {
2363 $htmlsupplements[$line->fk_parent_line] .= $line->product_label;
2364 }
2365 if ($line->product_label && $line->desc) {
2366 $htmlsupplements[$line->fk_parent_line] .= '<br>';
2367 }
2368 if ($line->product_label != $line->desc) {
2369 $firstline = dolGetFirstLineOfText($line->desc);
2370 if ($firstline != $line->desc) {
2371 $htmlsupplements[$line->fk_parent_line] .= $form->textwithpicto(dolGetFirstLineOfText($line->desc), $line->desc);
2372 } else {
2373 $htmlsupplements[$line->fk_parent_line] .= $line->desc;
2374 }
2375 }
2376 $htmlsupplements[$line->fk_parent_line] .= '</td>';
2377
2378 // complete line by hook
2379 $parameters = array('line' => $line);
2380 $reshook = $hookmanager->executeHooks('completeTakePosInvoiceParentLine', $parameters, $invoice, $action); // Note that $action and $object may have been modified by some hooks
2381 if ($reshook < 0) {
2382 setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
2383 }
2384 $htmlsupplements[$line->fk_parent_line] .= $hookmanager->resPrint;
2385
2386 if (empty($_SESSION["basiclayout"]) || $_SESSION["basiclayout"] != 1) {
2387 $htmlsupplements[$line->fk_parent_line] .= '<td class="right">'.vatrate(price2num($line->remise_percent), true).'</td>';
2388 $htmlsupplements[$line->fk_parent_line] .= '<td class="right">'.$line->qty.'</td>';
2389 $htmlsupplements[$line->fk_parent_line] .= '<td class="right">'.price($line->total_ttc).'</td>';
2390 }
2391 $htmlsupplements[$line->fk_parent_line] .= '</tr>'."\n";
2392 continue;
2393 }
2394 $htmlforlines = '';
2395
2396 $htmlforlines .= '<tr class="drag drop oddeven posinvoiceline';
2397 if ($line->special_code == "4") {
2398 $htmlforlines .= ' order';
2399 }
2400 $htmlforlines .= '" id="'.$line->id.'"';
2401 if ($line->special_code == "4") {
2402 $htmlforlines .= ' title="'.dol_escape_htmltag($langs->trans("AlreadyPrinted")).'"';
2403 }
2404 $htmlforlines .= '>';
2405 $htmlforlines .= '<td class="left">';
2406 if (!empty($_SESSION["basiclayout"]) && $_SESSION["basiclayout"] == 1) {
2407 $htmlforlines .= '<span class="phoneqty">'.$line->qty."</span> x ";
2408 }
2409 if (isset($line->product_type)) {
2410 if (empty($line->product_type)) {
2411 $htmlforlines .= img_object('', 'product').' ';
2412 } else {
2413 $htmlforlines .= img_object('', 'service').' ';
2414 }
2415 }
2416 $tooltiptext = '';
2417 if (!getDolGlobalString('TAKEPOS_SHOW_N_FIRST_LINES')) {
2418 if ($line->product_ref) {
2419 $tooltiptext .= '<b>'.$langs->trans("Ref").'</b> : '.$line->product_ref.'<br>';
2420 $tooltiptext .= '<b>'.$langs->trans("Label").'</b> : '.$line->product_label.'<br>';
2421 if (!empty($line->batch)) {
2422 $tooltiptext .= '<br><b>'.$langs->trans("LotSerial").'</b> : '.$line->batch.'<br>';
2423 }
2424 if (!empty($line->fk_warehouse)) {
2425 $tooltiptext .= '<b>'.$langs->trans("Warehouse").'</b> : '.$line->fk_warehouse.'<br>';
2426 }
2427 if ($line->product_label != $line->desc) {
2428 if ($line->desc) {
2429 $tooltiptext .= '<br>';
2430 }
2431 $tooltiptext .= $line->desc;
2432 }
2433 }
2434 if (getDolGlobalInt('TAKEPOS_SHOW_PRODUCT_REFERENCE') == 1) {
2435 $htmlforlines .= $form->textwithpicto($line->product_label ? '<b>' . $line->product_ref . '</b> - ' . $line->product_label : dolGetFirstLineOfText($line->desc, 1), $tooltiptext);
2436 } elseif (getDolGlobalInt('TAKEPOS_SHOW_PRODUCT_REFERENCE') == 2) {
2437 $htmlforlines .= $form->textwithpicto($line->product_ref ? '<b>'.$line->product_ref.'<b>' : dolGetFirstLineOfText($line->desc, 1), $tooltiptext);
2438 } else {
2439 $htmlforlines .= $form->textwithpicto($line->product_label ? $line->product_label : ($line->product_ref ? $line->product_ref : dolGetFirstLineOfText($line->desc, 1)), $tooltiptext);
2440 }
2441 } else {
2442 if ($line->product_ref) {
2443 $tooltiptext .= '<b>'.$langs->trans("Ref").'</b> : '.$line->product_ref.'<br>';
2444 $tooltiptext .= '<b>'.$langs->trans("Label").'</b> : '.$line->product_label.'<br>';
2445 }
2446 if (!empty($line->batch)) {
2447 $tooltiptext .= '<br><b>'.$langs->trans("LotSerial").'</b> : '.$line->batch.'<br>';
2448 }
2449 if (!empty($line->fk_warehouse)) {
2450 $tooltiptext .= '<b>'.$langs->trans("Warehouse").'</b> : '.$line->fk_warehouse.'<br>';
2451 }
2452
2453 if ($line->product_label) {
2454 $htmlforlines .= $line->product_label;
2455 }
2456 if ($line->product_label != $line->desc) {
2457 if ($line->product_label && $line->desc) {
2458 $htmlforlines .= '<br>';
2459 }
2460 $firstline = dolGetFirstLineOfText($line->desc, getDolGlobalInt('TAKEPOS_SHOW_N_FIRST_LINES'));
2461 if ($firstline != $line->desc) {
2462 $htmlforlines .= $form->textwithpicto(dolGetFirstLineOfText($line->desc), $line->desc);
2463 } else {
2464 $htmlforlines .= $line->desc;
2465 }
2466 }
2467 }
2468 if (!empty($line->array_options['options_order_notes'])) {
2469 $htmlforlines .= "<br>(".$line->array_options['options_order_notes'].")";
2470 }
2471 if (isModEnabled('productbatch') && $line->fk_product > 0) {
2472 if (!is_object($line->product) || !($line->product->id > 0)) {
2473 $line->fetch_product();
2474 }
2475
2476 if (is_object($line->product) && $line->product->status_batch > 0) {
2477 $batch_display = empty($line->batch) ? $langs->trans("NotDefined") : dol_escape_htmltag($line->batch);
2478 $htmlforlines .= '<br><span class="opacitymedium">'.$langs->trans("LotSerial").' : '.$batch_display.'</span>';
2479 // Only show edit button if invoice is a Draft (status == 0)
2480 if ($invoice->status == Facture::STATUS_DRAFT) {
2481 $htmlforlines .= ' <a href="#" onclick="editbatch('.$line->id.', '.$line->fk_product.'); return false;" title="'.dol_escape_htmltag($langs->trans("Modify")).'">'.img_edit().'</a>';
2482 }
2483 }
2484 }
2485 if (!empty($_SESSION["basiclayout"]) && $_SESSION["basiclayout"] == 1) {
2486 $htmlforlines .= '</td><td class="right phonetable"><button type="button" onclick="SetQty(place, '.$line->rowid.', '.($line->qty - 1).');" class="publicphonebutton2 phonered">-</button>&nbsp;&nbsp;<button type="button" onclick="SetQty(place, '.$line->rowid.', '.($line->qty + 1).');" class="publicphonebutton2 phonegreen">+</button>';
2487 }
2488 if (empty($_SESSION["basiclayout"]) || $_SESSION["basiclayout"] != 1) {
2489 // Set the content of tooltip
2490 $moreinfo = '';
2491 $moreinfo .= $langs->trans("VATRate").': '.price($line->tva_tx).' %<br>';
2492 $moreinfo .= $langs->trans("UnitPrice").': '.price($line->subprice).'<br>';
2493 $moreinfo .= '<br>';
2494 $moreinfo .= $langs->transcountry("TotalHT", $mysoc->country_code).': '.price($line->total_ht);
2495 if ($line->vat_src_code) {
2496 $moreinfo .= '<br>'.$langs->trans("VATCode").': '.$line->vat_src_code;
2497 }
2498 $moreinfo .= '<br>'.$langs->trans("TotalVAT").': '.price($line->total_tva);
2499 if ($mysoc->useLocalTax(1, 1, $mysoc)) {
2500 $moreinfo .= '<br>'.$langs->transcountry("TotalLT1", $mysoc->country_code).': '.price($line->total_localtax1);
2501 }
2502 if ($mysoc->useLocalTax(2, 1, $mysoc)) {
2503 $moreinfo .= '<br>'.$langs->transcountry("TotalLT2", $mysoc->country_code).': '.price($line->total_localtax2);
2504 }
2505 $moreinfo .= '<hr>';
2506 $moreinfo .= $langs->transcountry("TotalTTC", $mysoc->country_code).': '.price($line->total_ttc);
2507 //$moreinfo .= $langs->trans("TotalHT").': '.$line->total_ht;
2508 if ($line->date_start || $line->date_end) {
2509 $htmlforlines .= '<br><div class="clearboth nowraponall">'.get_date_range($line->date_start, $line->date_end).'</div>';
2510 }
2511 $htmlforlines .= '</td>';
2512
2513 // complete line by hook
2514 $parameters = array('line' => $line);
2515 $reshook = $hookmanager->executeHooks('completeTakePosInvoiceLine', $parameters, $invoice, $action); // Note that $action and $object may have been modified by some hooks
2516 if ($reshook < 0) {
2517 setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
2518 }
2519 $htmlforlines .= $hookmanager->resPrint;
2520
2521 if (getDolGlobalInt("TAKEPOS_SHOW_SUBPRICE")) {
2522 $htmlforlines .= '<td class="right">'.price($line->subprice).'</td>';
2523 }
2524 $htmlforlines .= '<td class="right">'.vatrate(price2num($line->remise_percent), true).'</td>';
2525 // nowraponall keeps the qty and its '(stock)' block on one line: on narrow layouts
2526 // the native display otherwise wraps over three lines inside the qty column.
2527 $htmlforlines .= '<td class="right nowraponall">';
2528 $htmlforlines .= $line->qty;
2529 if (isModEnabled('stock') && $user->hasRight('stock', 'mouvement', 'lire')) {
2530 $constantforkey = 'CASHDESK_ID_WAREHOUSE'.$_SESSION["takeposterminal"];
2531 if (getDolGlobalString($constantforkey) && $line->fk_product > 0 && !getDolGlobalString('TAKEPOS_HIDE_STOCK_ON_LINE')) {
2532 $productChildrenNb = 0;
2533 if (getDolGlobalInt('PRODUIT_SOUSPRODUITS')) {
2534 if (!is_object($line->product) || !($line->product->id > 0)) {
2535 $line->fetch_product();
2536 }
2537 if (is_object($line->product)) {
2538 $productChildrenNb = $line->product->hasFatherOrChild(1);
2539 }
2540 }
2541 if ($productChildrenNb == 0) {
2542 $sql = "SELECT e.rowid, e.ref, e.lieu, e.fk_parent, e.statut, ps.reel, ps.rowid as product_stock_id, p.pmp";
2543 $sql .= " FROM ".MAIN_DB_PREFIX."entrepot as e,";
2544 $sql .= " ".MAIN_DB_PREFIX."product_stock as ps";
2545 $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."product as p ON p.rowid = ps.fk_product";
2546 $sql .= " WHERE ps.reel != 0";
2547 $sql .= " AND ps.fk_entrepot = ".((int) getDolGlobalString($constantforkey));
2548 $sql .= " AND e.entity IN (".getEntity('stock').")";
2549 $sql .= " AND ps.fk_product = ".((int) $line->fk_product);
2550 $resql = $db->query($sql);
2551 if ($resql) {
2552 $stock_real = 0;
2553 $obj = $db->fetch_object($resql);
2554 if ($obj) {
2555 $stock_real = price2num($obj->reel, 'MS');
2556 }
2557 $htmlforlines .= $line->qty;
2558 $htmlforlines .= '&nbsp; ';
2559 $htmlforlines .= '<span class="opacitylow" title="'.$langs->trans("Stock").' '.price($stock_real, 1, '', 1, 0).'">';
2560 $htmlforlines .= '(';
2561 if ($line->qty && $line->qty > $stock_real) {
2562 $htmlforlines .= '<span style="color: var(--amountremaintopaycolor)">';
2563 }
2564 $htmlforlines .= img_picto('', 'stock', 'class="pictofixedwidth"').price($stock_real, 1, '', 1, 0);
2565 if ($line->qty && $line->qty > $stock_real) {
2566 $htmlforlines .= "</span>";
2567 }
2568 $htmlforlines .= ')';
2569 $htmlforlines .= '</span>';
2570 } else {
2571 dol_print_error($db);
2572 }
2573 }
2574 }
2575 }
2576
2577 $htmlforlines .= '</td>';
2578 if (getDolGlobalInt('TAKEPOS_SHOW_HT')) {
2579 $htmlforlines .= '<td class="right classfortooltip" title="'.$moreinfo.'">';
2580 $htmlforlines .= price($line->total_ht, 1, '', 1, -1, -1, $conf->currency);
2581 if (isModEnabled('multicurrency') && !empty($_SESSION["takeposcustomercurrency"]) && $conf->currency != $_SESSION["takeposcustomercurrency"]) {
2582 //Only show customer currency if multicurrency module is enabled, if currency selected and if this currency selected is not the same as main currency
2583 include_once DOL_DOCUMENT_ROOT.'/multicurrency/class/multicurrency.class.php';
2584 $multicurrency = new MultiCurrency($db);
2585 $multicurrency->fetch(0, $_SESSION["takeposcustomercurrency"]);
2586 $htmlforlines .= '<br><span id="linecolht-span-total" style="font-size:0.9em; font-style:italic;">('.price($line->total_ht * $multicurrency->rate->rate).' '.$_SESSION["takeposcustomercurrency"].')</span>';
2587 }
2588 $htmlforlines .= '</td>';
2589 }
2590 $htmlforlines .= '<td class="right classfortooltip" title="'.$moreinfo.'">';
2591 $htmlforlines .= price($line->total_ttc, 1, '', 1, -1, -1, $conf->currency);
2592 if (isModEnabled('multicurrency') && !empty($_SESSION["takeposcustomercurrency"]) && $conf->currency != $_SESSION["takeposcustomercurrency"]) {
2593 //Only show customer currency if multicurrency module is enabled, if currency selected and if this currency selected is not the same as main currency
2594 include_once DOL_DOCUMENT_ROOT.'/multicurrency/class/multicurrency.class.php';
2595 $multicurrency = new MultiCurrency($db);
2596 $multicurrency->fetch(0, $_SESSION["takeposcustomercurrency"]);
2597 $htmlforlines .= '<br><span id="linecolht-span-total" style="font-size:0.9em; font-style:italic;">('.price($line->total_ttc * $multicurrency->rate->rate).' '.$_SESSION["takeposcustomercurrency"].')</span>';
2598 }
2599 $htmlforlines .= '</td>';
2600 }
2601 $htmlforlines .= '</tr>'."\n";
2602 $htmlforlines .= empty($htmlsupplements[$line->id]) ? '' : $htmlsupplements[$line->id];
2603
2604 print $htmlforlines;
2605 }
2606 } else {
2607 print '<tr class="drag drop oddeven"><td class="left"><span class="opacitymedium">'.$langs->trans("Empty").'</span></td><td></td>';
2608 if (empty($_SESSION["basiclayout"]) || $_SESSION["basiclayout"] != 1) {
2609 print '<td></td><td></td>';
2610 if (getDolGlobalString('TAKEPOS_SHOW_HT')) {
2611 print '<td></td>';
2612 }
2613 }
2614 print '</tr>';
2615 }
2616} else { // No invoice generated yet
2617 print '<tr class="drag drop oddeven"><td class="left"><span class="opacitymedium">'.$langs->trans("Empty").'</span></td><td></td>';
2618 if (empty($_SESSION["basiclayout"]) || $_SESSION["basiclayout"] != 1) {
2619 print '<td></td><td></td>';
2620 if (getDolGlobalString('TAKEPOS_SHOW_HT')) {
2621 print '<td></td>';
2622 }
2623 }
2624 print '</tr>';
2625}
2626
2627if ($usediv) {
2628 print '</div>';
2629} else {
2630 print '</table>';
2631}
2632
2633if ($action == "search") {
2634 print '<center>
2635 <input type="text" id="search" class="input-nobottom" name="search" onkeyup="Search2(\'\', null);" style="width: 80%; font-size: 150%;" placeholder="'.dol_escape_htmltag($langs->trans('Search')).'">
2636 </center>';
2637}
2638
2639print '</div>';
2640
2641// llxFooter
2642if (defined('INCLUDE_PHONEPAGE_FROM_PUBLIC_PAGE')) {
2643 print '</body></html>';
2644}
if(! $sortfield) if(! $sortorder) $object
Definition account.php:100
$propal type
'integer', 'integer:ObjectClass:PathToClass[:AddCreateButtonOrNot[:Filter[:Sortfield]]]',...
Definition propal.php:280
$c
Definition line.php:346
isALNERunningVersion($blockedlogusagealreadychecked=0, $blockedlogmoduleonalreadychecked=0)
Return if the application is executed with the LNE requirements on.
Class to manage members of a foundation.
const STATUS_EXCLUDED
Excluded.
Class to manage categories.
Class to manage contact/addresses.
Class to manage warehouses.
const STATUS_CLOSED
Warehouse closed, inactive.
Class to manage invoices.
const STATUS_DRAFT
Draft status.
const STATUS_VALIDATED
Validated (need to be paid)
const TYPE_CREDIT_NOTE
Credit note invoice.
const STATUS_CLOSED
Classified paid.
Class to manage generation of HTML components Only common components must be here.
Class to manage stock movements.
Class Currency.
Class to manage payments of customer invoices.
Class to manage predefined suppliers products.
Class to manage products or services.
Manage record for batch number management.
Class to manage third parties objects (customers, suppliers, prospects...)
Class to manage Receipt Printers.
print $langs trans("Ref").' m titre as m m statut as status
Or an array listing all the potential status of the object: array: int of the status => translated la...
Definition index.php:169
global $mysoc
if(!isModEnabled('ai')||!getDolGlobalString('AI_ASSISTANT_ENABLED')) global $conf
The main.inc.php has been included so the following variable are now defined:
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...
dol_getIdFromCode($db, $key, $tablename, $fieldkey='code', $fieldid='id', $entityfilter=0, $filters='', $useCache=true)
Return an id or code from a code or id.
price2num($amount, $rounding='', $option=0)
Function that return a number with universal decimal format (decimal separator is '.
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.
dol_escape_js($stringtoescape, $mode=0, $noescapebackslashn=0)
Returns text escaped for inclusion into JavaScript code.
newToken()
Return the value of token currently saved into session with name 'newtoken'.
GETPOST($paramname, $check='alphanohtml', $method=0, $filter=null, $options=null, $noreplace=0, $nodefault=0)
Return value of a param into GET or POST supervariable.
GETPOSTFLOAT($paramname, $rounding='', $option=2)
Return the value of a $_GET or $_POST supervariable, converted into float.
GETPOSTINT($paramname, $method=0, $nodefault=0)
Return the value of a $_GET or $_POST supervariable, converted into integer.
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).
GETPOSTISSET($paramname)
Return true if we are in a context of submitting the parameter $paramname from a POST of a form.
getDolGlobalString($key, $default='')
Return a Dolibarr global constant string value.
isModEnabled($module)
Is Dolibarr module enabled.
get_default_tva(Societe $thirdparty_seller, Societe $thirdparty_buyer, $idprod=0, $idprodfournprice=0)
Function that return vat rate of a product line (according to seller, buyer and product vat rate) VAT...
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,...
dol_syslog($message, $level=LOG_INFO, $ident=0, $suffixinfilename='', $restricttologhandler='', $logcontext=null)
Write log message into outputs.
getEntity($element, $shared=1, $currentobject=null)
Get list of entity id to use.
dol_getdate($timestamp, $fast=false, $forcetimezone='')
Return an array with locale date info.
multi select button
0 = Do not include form tag and submit button -1 = Do not include form tag but include submit button
dol_htmloutput_mesg($mesgstring='', $mesgarray=array(), $style='ok', $keepembedded=0)
Print formatted messages to output (Used to show messages on html output).
dol_htmloutput_errors($mesgstring='', $mesgarray=array(), $keepembedded=0)
Print formatted error messages to output (Used to show messages on html output).
top_htmlhead($head, $title='', $disablejs=0, $disablehead=0, $arrayofjs=array(), $arrayofcss=array(), $disableforlogin=0, $disablenofollow=0, $disablenoindex=0)
Output html header of a page.
if(!defined( 'NOREQUIREMENU')) if(!empty(GETPOST('seteventmessages', 'alpha'))) if(!function_exists("llxHeader")) top_httphead($contenttype='text/html', $forcenocache=0)
Show HTTP header.
accessforbidden($message='', $printheader=1, $printfooter=1, $showonlymessage=0, $params=null)
Show a message to say access is forbidden and stop program.
if(empty( $takeposterminal)) fail($message)
Abort invoice creation with a given error message.
Definition invoice.php:125