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