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