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