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