dolibarr 21.0.0-beta
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 }
317
318 $res = $payment->addPaymentToBank($user, 'payment', '(CustomerInvoicePayment)', $bankaccount, '', '');
319 if ($res < 0) {
320 $error++;
321 dol_htmloutput_errors($langs->trans('ErrorNoPaymentDefined').' '.$payment->error, $payment->errors, 1);
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') && $user->hasRight('takepos', 'run')) {
1252 $sectionwithinvoicelink .= '<!-- Section with invoice link -->'."\n";
1253 $sectionwithinvoicelink .= '<span style="font-size:120%;" class="center">';
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 if ($invoice->paye) {
1260 $sectionwithinvoicelink .= '<span class="amountpaymentcomplete" style="font-size: unset">'.$langs->trans("Paid").'</span>';
1261 } else {
1262 $sectionwithinvoicelink .= $langs->trans('BillShortStatusValidated');
1263 }
1264 }
1265
1266 $sectionwithinvoicelink .= '</span><br>';
1267 if (getDolGlobalInt('TAKEPOS_PRINT_INVOICE_DOC_INSTEAD_OF_RECEIPT')) {
1268 $sectionwithinvoicelink .= ' <a target="_blank" class="button" href="' . DOL_URL_ROOT . '/document.php?token=' . newToken() . '&modulepart=facture&file=' . $invoice->ref . '/' . $invoice->ref . '.pdf">Invoice</a>';
1269 } elseif (getDolGlobalString('TAKEPOS_PRINT_METHOD') == "takeposconnector") {
1270 if (getDolGlobalString('TAKEPOS_PRINT_SERVER') && filter_var(getDolGlobalString('TAKEPOS_PRINT_SERVER'), FILTER_VALIDATE_URL) == true) {
1271 $sectionwithinvoicelink .= ' <button id="buttonprint" type="button" onclick="TakeposConnector('.$placeid.')">'.$langs->trans('PrintTicket').'</button>';
1272 } else {
1273 $sectionwithinvoicelink .= ' <button id="buttonprint" type="button" onclick="TakeposPrinting('.$placeid.')">'.$langs->trans('PrintTicket').'</button>';
1274 }
1275 } elseif ((isModEnabled('receiptprinter') && getDolGlobalInt('TAKEPOS_PRINTER_TO_USE'.$term) > 0) || getDolGlobalString('TAKEPOS_PRINT_METHOD') == "receiptprinter") {
1276 $sectionwithinvoicelink .= ' <button id="buttonprint" type="button" onclick="DolibarrTakeposPrinting('.$placeid.')">'.$langs->trans('PrintTicket').'</button>';
1277 } else {
1278 $sectionwithinvoicelink .= ' <button id="buttonprint" type="button" onclick="Print('.$placeid.')">'.$langs->trans('PrintTicket').'</button>';
1279 if (getDolGlobalString('TAKEPOS_PRINT_WITHOUT_DETAILS')) {
1280 $sectionwithinvoicelink .= ' <button id="buttonprint" type="button" onclick="PrintBox('.$placeid.', \'without_details\')">'.$langs->trans('PrintWithoutDetails').'</button>';
1281 }
1282 if (getDolGlobalString('TAKEPOS_GIFT_RECEIPT')) {
1283 $sectionwithinvoicelink .= ' <button id="buttonprint" type="button" onclick="Print('.$placeid.', 1)">'.$langs->trans('GiftReceipt').'</button>';
1284 }
1285 }
1286 if (getDolGlobalString('TAKEPOS_EMAIL_TEMPLATE_INVOICE') && getDolGlobalInt('TAKEPOS_EMAIL_TEMPLATE_INVOICE') > 0) {
1287 $sectionwithinvoicelink .= ' <button id="buttonsend" type="button" onclick="SendTicket('.$placeid.')">'.$langs->trans('SendTicket').'</button>';
1288 }
1289
1290 if ($remaintopay <= 0 && getDolGlobalString('TAKEPOS_AUTO_PRINT_TICKETS') && $action != "history") {
1291 $sectionwithinvoicelink .= '<script type="text/javascript">$("#buttonprint").click();</script>';
1292 }
1293 }
1294}
1295
1296
1297/*
1298 * View
1299 */
1300
1301$form = new Form($db);
1302
1303// llxHeader
1304if ((getDolGlobalString('TAKEPOS_PHONE_BASIC_LAYOUT') == 1 && $conf->browser->layout == 'phone') || defined('INCLUDE_PHONEPAGE_FROM_PUBLIC_PAGE')) {
1305 $title = 'TakePOS - Dolibarr '.DOL_VERSION;
1306 if (getDolGlobalString('MAIN_APPLICATION_TITLE')) {
1307 $title = 'TakePOS - ' . getDolGlobalString('MAIN_APPLICATION_TITLE');
1308 }
1309 $head = '<meta name="apple-mobile-web-app-title" content="TakePOS"/>
1310 <meta name="apple-mobile-web-app-capable" content="yes">
1311 <meta name="mobile-web-app-capable" content="yes">
1312 <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no"/>';
1313 $arrayofcss = array(
1314 '/takepos/css/pos.css.php',
1315 );
1316 $arrayofjs = array('/takepos/js/jquery.colorbox-min.js');
1317 $disablejs = 0;
1318 $disablehead = 0;
1319 top_htmlhead($head, $title, $disablejs, $disablehead, $arrayofjs, $arrayofcss);
1320
1321 print '<body>'."\n";
1322} else {
1323 top_httphead('text/html', 1);
1324}
1325
1326?>
1327<!-- invoice.php -->
1328<script type="text/javascript">
1329var selectedline=0;
1330var selectedtext="";
1331<?php if ($action == "valid") {
1332 echo "var place=0;";
1333}?> // Set to default place after close sale
1334var placeid=<?php echo($placeid > 0 ? $placeid : 0); ?>;
1335$(document).ready(function() {
1336 var idoflineadded = <?php echo(empty($idoflineadded) ? 0 : $idoflineadded); ?>;
1337
1338 $('.posinvoiceline').click(function(){
1339 console.log("Click done on "+this.id);
1340 $('.posinvoiceline').removeClass("selected");
1341 $(this).addClass("selected");
1342 if (!this.id) {
1343 return;
1344 }
1345 if (selectedline == this.id) {
1346 return; // If is already selected
1347 } else {
1348 selectedline = this.id;
1349 }
1350 selectedtext=$('#'+selectedline).find("td:first").html();
1351 <?php
1352 if (defined('INCLUDE_PHONEPAGE_FROM_PUBLIC_PAGE')) {
1353 print '$("#phonediv1").load("'.DOL_URL_ROOT.'/takepos/public/auto_order.php?action=editline&token='.newToken().'&placeid="+placeid+"&selectedline="+selectedline, function() {
1354 });';
1355 }
1356 ?>
1357 });
1358
1359 /* Autoselect the line */
1360 if (idoflineadded > 0)
1361 {
1362 console.log("Auto select "+idoflineadded);
1363 $('.posinvoiceline#'+idoflineadded).click();
1364 }
1365<?php
1366
1367if ($action == "order" && !empty($order_receipt_printer1)) {
1368 if (filter_var(getDolGlobalString('TAKEPOS_PRINT_SERVER'), FILTER_VALIDATE_URL) == true) {
1369 ?>
1370 $.ajax({
1371 type: "POST",
1372 url: '<?php print getDolGlobalString('TAKEPOS_PRINT_SERVER'); ?>/printer/index.php',
1373 data: 'invoice='+orderprinter1esc
1374 });
1375 <?php
1376 } else {
1377 ?>
1378 $.ajax({
1379 type: "POST",
1380 url: 'http://<?php print getDolGlobalString('TAKEPOS_PRINT_SERVER'); ?>:8111/print',
1381 data: '<?php
1382 print $headerorder.$order_receipt_printer1.$footerorder; ?>'
1383 });
1384 <?php
1385 }
1386}
1387
1388if ($action == "order" && !empty($order_receipt_printer2)) {
1389 if (filter_var(getDolGlobalString('TAKEPOS_PRINT_SERVER'), FILTER_VALIDATE_URL) == true) {
1390 ?>
1391 $.ajax({
1392 type: "POST",
1393 url: '<?php print getDolGlobalString('TAKEPOS_PRINT_SERVER'); ?>/printer/index.php?printer=2',
1394 data: 'invoice='+orderprinter2esc
1395 });
1396 <?php
1397 } else {
1398 ?>
1399 $.ajax({
1400 type: "POST",
1401 url: 'http://<?php print getDolGlobalString('TAKEPOS_PRINT_SERVER'); ?>:8111/print2',
1402 data: '<?php
1403 print $headerorder.$order_receipt_printer2.$footerorder; ?>'
1404 });
1405 <?php
1406 }
1407}
1408
1409if ($action == "order" && !empty($order_receipt_printer3)) {
1410 if (filter_var(getDolGlobalString('TAKEPOS_PRINT_SERVER'), FILTER_VALIDATE_URL) == true) {
1411 ?>
1412 $.ajax({
1413 type: "POST",
1414 url: '<?php print getDolGlobalString('TAKEPOS_PRINT_SERVER'); ?>/printer/index.php?printer=3',
1415 data: 'invoice='+orderprinter3esc
1416 });
1417 <?php
1418 }
1419}
1420
1421// Set focus to search field
1422if ($action == "search" || $action == "valid") {
1423 ?>
1424 parent.ClearSearch(true);
1425 <?php
1426}
1427
1428
1429if ($action == "temp" && !empty($ticket_printer1)) {
1430 ?>
1431 $.ajax({
1432 type: "POST",
1433 url: 'http://<?php print getDolGlobalString('TAKEPOS_PRINT_SERVER'); ?>:8111/print',
1434 data: '<?php
1435 print $header_soc.$header_ticket.$body_ticket.$ticket_printer1.$ticket_total.$footer_ticket; ?>'
1436 });
1437 <?php
1438}
1439
1440if ($action == "search") {
1441 ?>
1442 $('#search').focus();
1443 <?php
1444}
1445
1446?>
1447
1448});
1449
1450function SendTicket(id)
1451{
1452 console.log("Open box to select the Print/Send form");
1453 $.colorbox({href:"send.php?facid="+id, width:"70%", height:"30%", transition:"none", iframe:"true", title:'<?php echo dol_escape_js($langs->trans("SendTicket")); ?>'});
1454 return true;
1455}
1456
1457function PrintBox(id, action) {
1458 console.log("Open box before printing");
1459 $.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"); ?>"});
1460 return true;
1461}
1462
1463function Print(id, gift){
1464 console.log("Call Print() to generate the receipt.");
1465 $.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")); ?>'});
1466 return true;
1467}
1468
1469function TakeposPrinting(id){
1470 var receipt;
1471 console.log("TakeposPrinting" + id);
1472 $.get("receipt.php?facid="+id, function(data, status) {
1473 receipt=data.replace(/([^>\r\n]?)(\r\n|\n\r|\r|\n)/g, '');
1474 $.ajax({
1475 type: "POST",
1476 url: 'http://<?php print getDolGlobalString('TAKEPOS_PRINT_SERVER'); ?>:8111/print',
1477 data: receipt
1478 });
1479 });
1480 return true;
1481}
1482
1483function TakeposConnector(id){
1484 console.log("TakeposConnector" + id);
1485 $.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) {
1486 $.ajax({
1487 type: "POST",
1488 url: '<?php print getDolGlobalString('TAKEPOS_PRINT_SERVER'); ?>/printer/index.php',
1489 data: 'invoice='+data
1490 });
1491 });
1492 return true;
1493}
1494
1495// Call the ajax to execute the print.
1496// With some external module another method may be called.
1497function DolibarrTakeposPrinting(id) {
1498 console.log("DolibarrTakeposPrinting Printing invoice ticket " + id);
1499 $.ajax({
1500 type: "GET",
1501 data: { token: '<?php echo currentToken(); ?>' },
1502 url: "<?php print DOL_URL_ROOT.'/takepos/ajax/ajax.php?action=printinvoiceticket&token='.newToken().'&term='.urlencode(isset($_SESSION["takeposterminal"]) ? $_SESSION["takeposterminal"] : '').'&id='; ?>" + id,
1503
1504 });
1505 return true;
1506}
1507
1508// Call url to generate a credit note (with same lines) from existing invoice
1509function CreditNote() {
1510 $("#poslines").load("<?php print DOL_URL_ROOT; ?>/takepos/invoice.php?action=creditnote&token=<?php echo newToken() ?>&invoiceid="+placeid, function() { });
1511 return true;
1512}
1513
1514// Call url to add notes
1515function SetNote() {
1516 $("#poslines").load("<?php print DOL_URL_ROOT; ?>/takepos/invoice.php?action=addnote&token=<?php echo newToken() ?>&invoiceid="+placeid+"&idline="+selectedline, { "addnote": $("#textinput").val() });
1517 return true;
1518}
1519
1520
1521$( document ).ready(function() {
1522 console.log("Set customer info and sales in header placeid=<?php echo $placeid; ?> status=<?php echo $invoice->statut; ?>");
1523
1524 <?php
1525 $s = $langs->trans("Customer");
1526 if ($invoice->id > 0 && ($invoice->socid != getDolGlobalString($constforcompanyid))) {
1527 $s = $soc->name;
1528 if (getDolGlobalInt('TAKEPOS_CHOOSE_CONTACT')) {
1529 $contactids = $invoice->getIdContact('external', 'BILLING');
1530 $contactid = $contactids[0];
1531 if ($contactid > 0) {
1532 $contact = new Contact($db);
1533 $contact->fetch($contactid);
1534 $s .= " - " . $contact->getFullName($langs);
1535 }
1536 }
1537 } elseif (getDolGlobalInt("TAKEPOS_NO_GENERIC_THIRDPARTY")) {
1538 print '$("#idcustomer").val("");';
1539 }
1540 ?>
1541
1542 $("#customerandsales").html('');
1543 $("#shoppingcart").html('');
1544
1545 <?php if (getDolGlobalInt('TAKEPOS_CHOOSE_CONTACT') == 0) { ?>
1546 $("#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>');
1547 <?php } else { ?>
1548 $("#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>');
1549 <?php } ?>
1550
1551 <?php
1552 $sql = "SELECT rowid, datec, ref FROM ".MAIN_DB_PREFIX."facture";
1553 $sql .= " WHERE entity IN (".getEntity('invoice').")";
1554 if (!getDolGlobalString('TAKEPOS_CAN_EDIT_IF_ALREADY_VALIDATED')) {
1555 // By default, only invoices with a ref not already defined can in list of open invoice we can edit.
1556 $sql .= " AND ref LIKE '(PROV-POS".$db->escape(isset($_SESSION["takeposterminal"]) ? $_SESSION["takeposterminal"] : '')."-0%'";
1557 } else {
1558 // If TAKEPOS_CAN_EDIT_IF_ALREADY_VALIDATED set, we show also draft invoice that already has a reference defined
1559 $sql .= " AND pos_source = '".$db->escape($_SESSION["takeposterminal"])."'";
1560 $sql .= " AND module_source = 'takepos'";
1561 }
1562
1563 $sql .= $db->order('datec', 'ASC');
1564 $resql = $db->query($sql);
1565 if ($resql) {
1566 $max_sale = 0;
1567 while ($obj = $db->fetch_object($resql)) {
1568 echo '$("#shoppingcart").append(\'';
1569 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=\\\'';
1570 $num_sale = str_replace(")", "", str_replace("(PROV-POS".$_SESSION["takeposterminal"]."-", "", $obj->ref));
1571 echo $num_sale;
1572 if (str_replace("-", "", $num_sale) > $max_sale) {
1573 $max_sale = str_replace("-", "", $num_sale);
1574 }
1575 echo '\\\'; invoiceid=\\\'';
1576 echo $obj->rowid;
1577 echo '\\\'; Refresh();">';
1578 if ($placeid == $obj->rowid) {
1579 echo '<span class="basketselected">';
1580 } else {
1581 echo '<span class="basketnotselected">';
1582 }
1583 echo '<span class="fa fa-shopping-cart paddingright"></span>'.dol_print_date($db->jdate($obj->datec), '%H:%M', 'tzuser');
1584 echo '</span>';
1585 echo '</a>\');';
1586 }
1587 echo '$("#shoppingcart").append(\'<a onclick="place=\\\'0-';
1588 echo $max_sale + 1;
1589 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>\');';
1590 } else {
1591 dol_print_error($db);
1592 }
1593
1594 $s = '';
1595
1596 $idwarehouse = 0;
1597 $constantforkey = 'CASHDESK_NO_DECREASE_STOCK'. (isset($_SESSION["takeposterminal"]) ? $_SESSION["takeposterminal"] : '');
1598 if (isModEnabled('stock')) {
1599 if (getDolGlobalString($constantforkey) != "1") {
1600 $constantforkey = 'CASHDESK_ID_WAREHOUSE'. (isset($_SESSION["takeposterminal"]) ? $_SESSION["takeposterminal"] : '');
1601 $idwarehouse = getDolGlobalString($constantforkey);
1602 if ($idwarehouse > 0) {
1603 $s = '<span class="small">';
1604 $warehouse = new Entrepot($db);
1605 $warehouse->fetch($idwarehouse);
1606 $s .= '<span class="hideonsmartphone">'.$langs->trans("Warehouse").'<br></span>'.$warehouse->ref;
1607 if ($warehouse->statut == Entrepot::STATUS_CLOSED) {
1608 $s .= ' ('.$langs->trans("Closed").')';
1609 }
1610 $s .= '</span>';
1611 print "$('#infowarehouse').html('".dol_escape_js($s)."');";
1612 print '$("#infowarehouse").css("display", "inline-block");';
1613 } else {
1614 $s = '<span class="small hideonsmartphone">';
1615 $s .= $langs->trans("StockChangeDisabled").'<br>'.$langs->trans("NoWarehouseDefinedForTerminal");
1616 $s .= '</span>';
1617 print "$('#infowarehouse').html('".dol_escape_js($s)."');";
1618 if (!empty($conf->dol_optimize_smallscreen)) {
1619 print '$("#infowarehouse").css("display", "none");';
1620 }
1621 }
1622 } else {
1623 $s = '<span class="small hideonsmartphone">'.$langs->trans("StockChangeDisabled").'</span>';
1624 print "$('#infowarehouse').html('".dol_escape_js($s)."');";
1625 if (!empty($conf->dol_optimize_smallscreen)) {
1626 print '$("#infowarehouse").css("display", "none");';
1627 }
1628 }
1629 }
1630
1631
1632 // Module Adherent
1633 $s = '';
1634 if (isModEnabled('member') && $invoice->socid > 0 && $invoice->socid != getDolGlobalInt($constforcompanyid)) {
1635 $s = '<span class="small">';
1636 require_once DOL_DOCUMENT_ROOT.'/adherents/class/adherent.class.php';
1637 $langs->load("members");
1638 $s .= $langs->trans("Member").': ';
1639 $adh = new Adherent($db);
1640 $result = $adh->fetch('', '', $invoice->socid);
1641 if ($result > 0) {
1642 $adh->ref = $adh->getFullName($langs);
1643 if (empty($adh->statut) || $adh->statut == Adherent::STATUS_EXCLUDED) {
1644 $s .= "<s>";
1645 }
1646 $s .= $adh->getFullName($langs);
1647 $s .= ' - '.$adh->type;
1648 if ($adh->datefin) {
1649 $s .= '<br>'.$langs->trans("SubscriptionEndDate").': '.dol_print_date($adh->datefin, 'day');
1650 if ($adh->hasDelay()) {
1651 $s .= " ".img_warning($langs->trans("Late"));
1652 }
1653 } else {
1654 $s .= '<br>'.$langs->trans("SubscriptionNotReceived");
1655 if ($adh->statut > 0) {
1656 $s .= " ".img_warning($langs->trans("Late")); // displays delay Pictogram only if not a draft and not terminated
1657 }
1658 }
1659 if (empty($adh->statut) || $adh->statut == Adherent::STATUS_EXCLUDED) {
1660 $s .= "</s>";
1661 }
1662 } else {
1663 $s .= '<br>'.$langs->trans("ThirdpartyNotLinkedToMember");
1664 }
1665 $s .= '</span>';
1666 }
1667 ?>
1668 $("#moreinfo").html('<?php print dol_escape_js($s); ?>');
1669
1670});
1671
1672
1673<?php
1674if (getDolGlobalString('TAKEPOS_CUSTOMER_DISPLAY')) {
1675 echo "function CustomerDisplay(){";
1676 echo "var line1='".$CUSTOMER_DISPLAY_line1."'.substring(0,20);";
1677 echo "line1=line1.padEnd(20);";
1678 echo "var line2='".$CUSTOMER_DISPLAY_line2."'.substring(0,20);";
1679 echo "line2=line2.padEnd(20);";
1680 echo "$.ajax({
1681 type: 'GET',
1682 data: { text: line1+line2 },
1683 url: '".getDolGlobalString('TAKEPOS_PRINT_SERVER')."/display/index.php',
1684 });";
1685 echo "}";
1686}
1687?>
1688
1689</script>
1690
1691<?php
1692// Add again js for footer because this content is injected into index.php page so all init
1693// for tooltip and other js beautifiers must be reexecuted too.
1694if (!empty($conf->use_javascript_ajax)) {
1695 print "\n".'<!-- Includes JS Footer of Dolibarr -->'."\n";
1696 print '<script src="'.DOL_URL_ROOT.'/core/js/lib_foot.js.php?lang='.$langs->defaultlang.'"></script>'."\n";
1697}
1698
1699$usediv = (GETPOST('format') == 'div');
1700
1701print '<!-- 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";
1702print '<div class="div-table-responsive-no-min invoice">';
1703if ($usediv) {
1704 print '<div id="tablelines">';
1705} else {
1706 print '<table id="tablelines" class="noborder noshadow postablelines centpercent">';
1707}
1708if ($sectionwithinvoicelink && ($mobilepage == "invoice" || $mobilepage == "")) {
1709 if (getDolGlobalString('TAKEPOS_SHOW_HT')) {
1710 print '<tr><td colspan="5">'.$sectionwithinvoicelink.'</td></tr>';
1711 } else {
1712 print '<tr><td colspan="4">'.$sectionwithinvoicelink.'</td></tr>';
1713 }
1714}
1715
1716// Show the list of selected product
1717if (!$usediv) {
1718 print '<tr class="liste_titre nodrag nodrop">';
1719 print '<td class="linecoldescription">';
1720}
1721// In phone version only show when it is invoice page
1722if (empty($mobilepage) || $mobilepage == "invoice") {
1723 print '<!-- hidden var used by some js functions -->';
1724 print '<input type="hidden" name="invoiceid" id="invoiceid" value="'.$invoice->id.'">';
1725 print '<input type="hidden" name="thirdpartyid" id="thirdpartyid" value="'.$invoice->socid.'">';
1726}
1727if (!$usediv) {
1728 if (getDolGlobalString('TAKEPOS_BAR_RESTAURANT')) {
1729 $sql = "SELECT floor, label FROM ".MAIN_DB_PREFIX."takepos_floor_tables where rowid=".((int) $place);
1730 $resql = $db->query($sql);
1731 $obj = $db->fetch_object($resql);
1732 if ($obj) {
1733 $label = $obj->label;
1734 $floor = $obj->floor;
1735 }
1736 if ($mobilepage == "invoice" || $mobilepage == "") {
1737 // If not on smartphone version or if it is the invoice page
1738 //print 'mobilepage='.$mobilepage;
1739 print '<span class="opacitymedium">'.$langs->trans('Place')."</span> <b>".(empty($label) ? '?' : $label)."</b><br>";
1740 print '<span class="opacitymedium">'.$langs->trans('Floor')."</span> <b>".(empty($floor) ? '?' : $floor)."</b>";
1741 }
1742 }
1743 print '</td>';
1744}
1745
1746// Complete header by hook
1747$parameters = array();
1748$reshook = $hookmanager->executeHooks('completeTakePosInvoiceHeader', $parameters, $invoice, $action); // Note that $action and $object may have been modified by some hooks
1749if ($reshook < 0) {
1750 setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
1751}
1752print $hookmanager->resPrint;
1753
1754if (empty($_SESSION["basiclayout"]) || $_SESSION["basiclayout"] != 1) {
1755 if (getDolGlobalInt("TAKEPOS_SHOW_SUBPRICE")) {
1756 print '<td class="linecolqty right">'.$langs->trans('PriceUHT').'</td>';
1757 }
1758 print '<td class="linecolqty right">'.$langs->trans('ReductionShort').'</td>';
1759 print '<td class="linecolqty right">'.$langs->trans('Qty').'</td>';
1760 if (getDolGlobalString('TAKEPOS_SHOW_HT')) {
1761 print '<td class="linecolht right nowraponall">';
1762 print '<span class="opacitymedium small">' . $langs->trans('TotalHTShort') . '</span><br>';
1763 // In phone version only show when it is invoice page
1764 if (empty($mobilepage) || $mobilepage == "invoice") {
1765 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>';
1766 if (isModEnabled('multicurrency') && !empty($_SESSION["takeposcustomercurrency"]) && $conf->currency != $_SESSION["takeposcustomercurrency"]) {
1767 //Only show customer currency if multicurrency module is enabled, if currency selected and if this currency selected is not the same as main currency
1768 include_once DOL_DOCUMENT_ROOT . '/multicurrency/class/multicurrency.class.php';
1769 $multicurrency = new MultiCurrency($db);
1770 $multicurrency->fetch(0, $_SESSION["takeposcustomercurrency"]);
1771 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>';
1772 }
1773 }
1774 print '</td>';
1775 }
1776 print '<td class="linecolht right nowraponall">';
1777 print '<span class="opacitymedium small">'.$langs->trans('TotalTTCShort').'</span><br>';
1778 // In phone version only show when it is invoice page
1779 if (empty($mobilepage) || $mobilepage == "invoice") {
1780 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>';
1781 if (isModEnabled('multicurrency') && !empty($_SESSION["takeposcustomercurrency"]) && $conf->currency != $_SESSION["takeposcustomercurrency"]) {
1782 //Only show customer currency if multicurrency module is enabled, if currency selected and if this currency selected is not the same as main currency
1783 include_once DOL_DOCUMENT_ROOT.'/multicurrency/class/multicurrency.class.php';
1784 $multicurrency = new MultiCurrency($db);
1785 $multicurrency->fetch(0, $_SESSION["takeposcustomercurrency"]);
1786 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>';
1787 }
1788 }
1789 print '</td>';
1790} elseif ($mobilepage == "invoice") {
1791 print '<td class="linecolqty right">'.$langs->trans('Qty').'</td>';
1792}
1793if (!$usediv) {
1794 print "</tr>\n";
1795}
1796
1797if (!empty($_SESSION["basiclayout"]) && $_SESSION["basiclayout"] == 1) {
1798 if ($mobilepage == "cats") {
1799 require_once DOL_DOCUMENT_ROOT.'/categories/class/categorie.class.php';
1800 $categorie = new Categorie($db);
1801 $categories = $categorie->get_full_arbo('product');
1802 $htmlforlines = '';
1803 foreach ($categories as $row) {
1804 if (defined('INCLUDE_PHONEPAGE_FROM_PUBLIC_PAGE')) {
1805 $htmlforlines .= '<div class="leftcat"';
1806 } else {
1807 $htmlforlines .= '<tr class="drag drop oddeven posinvoiceline"';
1808 }
1809 $htmlforlines .= ' onclick="LoadProducts('.$row['id'].');">';
1810 if (defined('INCLUDE_PHONEPAGE_FROM_PUBLIC_PAGE')) {
1811 $htmlforlines .= '<img class="imgwrapper" width="33%" src="'.DOL_URL_ROOT.'/takepos/public/auto_order.php?genimg=cat&query=cat&id='.$row['id'].'"><br>';
1812 } else {
1813 $htmlforlines .= '<td class="left">';
1814 }
1815 $htmlforlines .= $row['label'];
1816 if (defined('INCLUDE_PHONEPAGE_FROM_PUBLIC_PAGE')) {
1817 $htmlforlines .= '</div>'."\n";
1818 } else {
1819 $htmlforlines .= '</td></tr>'."\n";
1820 }
1821 }
1822 print $htmlforlines;
1823 }
1824
1825 if ($mobilepage == "products") {
1826 require_once DOL_DOCUMENT_ROOT.'/categories/class/categorie.class.php';
1827 $object = new Categorie($db);
1828 $catid = GETPOSTINT('catid');
1829 $result = $object->fetch($catid);
1830 $prods = $object->getObjectsInCateg("product");
1831 $htmlforlines = '';
1832 foreach ($prods as $row) {
1833 if (defined('INCLUDE_PHONEPAGE_FROM_PUBLIC_PAGE')) {
1834 $htmlforlines .= '<div class="leftcat"';
1835 } else {
1836 $htmlforlines .= '<tr class="drag drop oddeven posinvoiceline"';
1837 }
1838 $htmlforlines .= ' onclick="AddProduct(\''.$place.'\', '.$row->id.')"';
1839 $htmlforlines .= '>';
1840 if (defined('INCLUDE_PHONEPAGE_FROM_PUBLIC_PAGE')) {
1841 $htmlforlines .= '<img class="imgwrapper" width="33%" src="'.DOL_URL_ROOT.'/takepos/public/auto_order.php?genimg=pro&query=pro&id='.$row->id.'"><br>';
1842 $htmlforlines .= $row->label.' '.price($row->price_ttc, 1, $langs, 1, -1, -1, $conf->currency);
1843 $htmlforlines .= '</div>'."\n";
1844 } else {
1845 $htmlforlines .= '<td class="left">';
1846 $htmlforlines .= $row->label;
1847 $htmlforlines .= '<div class="right">'.price($row->price_ttc, 1, $langs, 1, -1, -1, $conf->currency).'</div>';
1848 $htmlforlines .= '</td>';
1849 $htmlforlines .= '</tr>'."\n";
1850 }
1851 }
1852 print $htmlforlines;
1853 }
1854
1855 if ($mobilepage == "places") {
1856 $sql = "SELECT rowid, entity, label, leftpos, toppos, floor FROM ".MAIN_DB_PREFIX."takepos_floor_tables";
1857 $resql = $db->query($sql);
1858 $rows = array();
1859 $htmlforlines = '';
1860 while ($row = $db->fetch_array($resql)) {
1861 $rows[] = $row;
1862 $htmlforlines .= '<tr class="drag drop oddeven posinvoiceline';
1863 $htmlforlines .= '" onclick="LoadPlace(\''.$row['label'].'\')">';
1864 $htmlforlines .= '<td class="left">';
1865 $htmlforlines .= $row['label'];
1866 $htmlforlines .= '</td>';
1867 $htmlforlines .= '</tr>'."\n";
1868 }
1869 print $htmlforlines;
1870 }
1871}
1872
1873if ($placeid > 0) {
1874 //In Phone basic layout hide some content depends situation
1875 if (!empty($_SESSION["basiclayout"]) && $_SESSION["basiclayout"] == 1 && $mobilepage != "invoice" && $action != "order") {
1876 return;
1877 }
1878
1879 // Loop on each lines on invoice
1880 if (is_array($invoice->lines) && count($invoice->lines)) {
1881 print '<!-- invoice.php show lines of invoices -->'."\n";
1882 $tmplines = array_reverse($invoice->lines);
1883 $htmlsupplements = array();
1884 foreach ($tmplines as $line) {
1885 if ($line->fk_parent_line != false) {
1886 $htmlsupplements[$line->fk_parent_line] .= '<tr class="drag drop oddeven posinvoiceline';
1887 if ($line->special_code == "4") {
1888 $htmlsupplements[$line->fk_parent_line] .= ' order';
1889 }
1890 $htmlsupplements[$line->fk_parent_line] .= '" id="'.$line->id.'"';
1891 if ($line->special_code == "4") {
1892 $htmlsupplements[$line->fk_parent_line] .= ' title="'.dol_escape_htmltag($langs->trans("AlreadyPrinted")).'"';
1893 }
1894 $htmlsupplements[$line->fk_parent_line] .= '>';
1895 $htmlsupplements[$line->fk_parent_line] .= '<td class="left">';
1896 $htmlsupplements[$line->fk_parent_line] .= img_picto('', 'rightarrow');
1897 if ($line->product_label) {
1898 $htmlsupplements[$line->fk_parent_line] .= $line->product_label;
1899 }
1900 if ($line->product_label && $line->desc) {
1901 $htmlsupplements[$line->fk_parent_line] .= '<br>';
1902 }
1903 if ($line->product_label != $line->desc) {
1904 $firstline = dolGetFirstLineOfText($line->desc);
1905 if ($firstline != $line->desc) {
1906 $htmlsupplements[$line->fk_parent_line] .= $form->textwithpicto(dolGetFirstLineOfText($line->desc), $line->desc);
1907 } else {
1908 $htmlsupplements[$line->fk_parent_line] .= $line->desc;
1909 }
1910 }
1911 $htmlsupplements[$line->fk_parent_line] .= '</td>';
1912
1913 // complete line by hook
1914 $parameters = array('line' => $line);
1915 $reshook = $hookmanager->executeHooks('completeTakePosInvoiceParentLine', $parameters, $invoice, $action); // Note that $action and $object may have been modified by some hooks
1916 if ($reshook < 0) {
1917 setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
1918 }
1919 $htmlsupplements[$line->fk_parent_line] .= $hookmanager->resPrint;
1920
1921 if (empty($_SESSION["basiclayout"]) || $_SESSION["basiclayout"] != 1) {
1922 $htmlsupplements[$line->fk_parent_line] .= '<td class="right">'.vatrate(price2num($line->remise_percent), true).'</td>';
1923 $htmlsupplements[$line->fk_parent_line] .= '<td class="right">'.$line->qty.'</td>';
1924 $htmlsupplements[$line->fk_parent_line] .= '<td class="right">'.price($line->total_ttc).'</td>';
1925 }
1926 $htmlsupplements[$line->fk_parent_line] .= '</tr>'."\n";
1927 continue;
1928 }
1929 $htmlforlines = '';
1930
1931 $htmlforlines .= '<tr class="drag drop oddeven posinvoiceline';
1932 if ($line->special_code == "4") {
1933 $htmlforlines .= ' order';
1934 }
1935 $htmlforlines .= '" id="'.$line->id.'"';
1936 if ($line->special_code == "4") {
1937 $htmlforlines .= ' title="'.dol_escape_htmltag($langs->trans("AlreadyPrinted")).'"';
1938 }
1939 $htmlforlines .= '>';
1940 $htmlforlines .= '<td class="left">';
1941 if (!empty($_SESSION["basiclayout"]) && $_SESSION["basiclayout"] == 1) {
1942 $htmlforlines .= '<span class="phoneqty">'.$line->qty."</span> x ";
1943 }
1944 if (isset($line->product_type)) {
1945 if (empty($line->product_type)) {
1946 $htmlforlines .= img_object('', 'product').' ';
1947 } else {
1948 $htmlforlines .= img_object('', 'service').' ';
1949 }
1950 }
1951 $tooltiptext = '';
1952 if (!getDolGlobalString('TAKEPOS_SHOW_N_FIRST_LINES')) {
1953 if ($line->product_ref) {
1954 $tooltiptext .= '<b>'.$langs->trans("Ref").'</b> : '.$line->product_ref.'<br>';
1955 $tooltiptext .= '<b>'.$langs->trans("Label").'</b> : '.$line->product_label.'<br>';
1956 if (!empty($line->batch)) {
1957 $tooltiptext .= '<br><b>'.$langs->trans("LotSerial").'</b> : '.$line->batch.'<br>';
1958 }
1959 if (!empty($line->fk_warehouse)) {
1960 $tooltiptext .= '<b>'.$langs->trans("Warehouse").'</b> : '.$line->fk_warehouse.'<br>';
1961 }
1962 if ($line->product_label != $line->desc) {
1963 if ($line->desc) {
1964 $tooltiptext .= '<br>';
1965 }
1966 $tooltiptext .= $line->desc;
1967 }
1968 }
1969 if (getDolGlobalInt('TAKEPOS_SHOW_PRODUCT_REFERENCE') == 1) {
1970 $htmlforlines .= $form->textwithpicto($line->product_label ? '<b>' . $line->product_ref . '</b> - ' . $line->product_label : dolGetFirstLineOfText($line->desc, 1), $tooltiptext);
1971 } elseif (getDolGlobalInt('TAKEPOS_SHOW_PRODUCT_REFERENCE') == 2) {
1972 $htmlforlines .= $form->textwithpicto($line->product_ref ? '<b>'.$line->product_ref.'<b>' : dolGetFirstLineOfText($line->desc, 1), $tooltiptext);
1973 } else {
1974 $htmlforlines .= $form->textwithpicto($line->product_label ? $line->product_label : ($line->product_ref ? $line->product_ref : dolGetFirstLineOfText($line->desc, 1)), $tooltiptext);
1975 }
1976 } else {
1977 if ($line->product_ref) {
1978 $tooltiptext .= '<b>'.$langs->trans("Ref").'</b> : '.$line->product_ref.'<br>';
1979 $tooltiptext .= '<b>'.$langs->trans("Label").'</b> : '.$line->product_label.'<br>';
1980 }
1981 if (!empty($line->batch)) {
1982 $tooltiptext .= '<br><b>'.$langs->trans("LotSerial").'</b> : '.$line->batch.'<br>';
1983 }
1984 if (!empty($line->fk_warehouse)) {
1985 $tooltiptext .= '<b>'.$langs->trans("Warehouse").'</b> : '.$line->fk_warehouse.'<br>';
1986 }
1987
1988 if ($line->product_label) {
1989 $htmlforlines .= $line->product_label;
1990 }
1991 if ($line->product_label != $line->desc) {
1992 if ($line->product_label && $line->desc) {
1993 $htmlforlines .= '<br>';
1994 }
1995 $firstline = dolGetFirstLineOfText($line->desc, getDolGlobalInt('TAKEPOS_SHOW_N_FIRST_LINES'));
1996 if ($firstline != $line->desc) {
1997 $htmlforlines .= $form->textwithpicto(dolGetFirstLineOfText($line->desc), $line->desc);
1998 } else {
1999 $htmlforlines .= $line->desc;
2000 }
2001 }
2002 }
2003 if (!empty($line->array_options['options_order_notes'])) {
2004 $htmlforlines .= "<br>(".$line->array_options['options_order_notes'].")";
2005 }
2006 if (!empty($_SESSION["basiclayout"]) && $_SESSION["basiclayout"] == 1) {
2007 $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>';
2008 }
2009 if (empty($_SESSION["basiclayout"]) || $_SESSION["basiclayout"] != 1) {
2010 $moreinfo = '';
2011 $moreinfo .= $langs->transcountry("TotalHT", $mysoc->country_code).': '.price($line->total_ht);
2012 if ($line->vat_src_code) {
2013 $moreinfo .= '<br>'.$langs->trans("VATCode").': '.$line->vat_src_code;
2014 }
2015 $moreinfo .= '<br>'.$langs->transcountry("TotalVAT", $mysoc->country_code).': '.price($line->total_tva);
2016 $moreinfo .= '<br>'.$langs->transcountry("TotalLT1", $mysoc->country_code).': '.price($line->total_localtax1);
2017 $moreinfo .= '<br>'.$langs->transcountry("TotalLT2", $mysoc->country_code).': '.price($line->total_localtax2);
2018 $moreinfo .= '<hr>';
2019 $moreinfo .= $langs->transcountry("TotalTTC", $mysoc->country_code).': '.price($line->total_ttc);
2020 //$moreinfo .= $langs->trans("TotalHT").': '.$line->total_ht;
2021 if ($line->date_start || $line->date_end) {
2022 $htmlforlines .= '<br><div class="clearboth nowraponall">'.get_date_range($line->date_start, $line->date_end).'</div>';
2023 }
2024 $htmlforlines .= '</td>';
2025
2026 // complete line by hook
2027 $parameters = array('line' => $line);
2028 $reshook = $hookmanager->executeHooks('completeTakePosInvoiceLine', $parameters, $invoice, $action); // Note that $action and $object may have been modified by some hooks
2029 if ($reshook < 0) {
2030 setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
2031 }
2032 $htmlforlines .= $hookmanager->resPrint;
2033
2034 if (getDolGlobalInt("TAKEPOS_SHOW_SUBPRICE")) {
2035 $htmlforlines .= '<td class="right">'.price($line->subprice).'</td>';
2036 }
2037 $htmlforlines .= '<td class="right">'.vatrate(price2num($line->remise_percent), true).'</td>';
2038 $htmlforlines .= '<td class="right">';
2039 if (isModEnabled('stock') && $user->hasRight('stock', 'mouvement', 'lire')) {
2040 $constantforkey = 'CASHDESK_ID_WAREHOUSE'.$_SESSION["takeposterminal"];
2041 if (getDolGlobalString($constantforkey) && $line->fk_product > 0 && !getDolGlobalString('TAKEPOS_HIDE_STOCK_ON_LINE')) {
2042 $sql = "SELECT e.rowid, e.ref, e.lieu, e.fk_parent, e.statut, ps.reel, ps.rowid as product_stock_id, p.pmp";
2043 $sql .= " FROM ".MAIN_DB_PREFIX."entrepot as e,";
2044 $sql .= " ".MAIN_DB_PREFIX."product_stock as ps";
2045 $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."product as p ON p.rowid = ps.fk_product";
2046 $sql .= " WHERE ps.reel != 0";
2047 $sql .= " AND ps.fk_entrepot = ".((int) getDolGlobalString($constantforkey));
2048 $sql .= " AND e.entity IN (".getEntity('stock').")";
2049 $sql .= " AND ps.fk_product = ".((int) $line->fk_product);
2050 $resql = $db->query($sql);
2051 if ($resql) {
2052 $stock_real = 0;
2053 $obj = $db->fetch_object($resql);
2054 if ($obj) {
2055 $stock_real = price2num($obj->reel, 'MS');
2056 }
2057 $htmlforlines .= $line->qty;
2058 $htmlforlines .= '&nbsp; ';
2059 $htmlforlines .= '<span class="opacitylow" title="'.$langs->trans("Stock").' '.price($stock_real, 1, '', 1, 0).'">';
2060 $htmlforlines .= '(';
2061 if ($line->qty && $line->qty > $stock_real) {
2062 $htmlforlines .= '<span style="color: var(--amountremaintopaycolor)">';
2063 }
2064 $htmlforlines .= img_picto('', 'stock', 'class="pictofixedwidth"').price($stock_real, 1, '', 1, 0);
2065 if ($line->qty && $line->qty > $stock_real) {
2066 $htmlforlines .= "</span>";
2067 }
2068 $htmlforlines .= ')';
2069 $htmlforlines .= '</span>';
2070 } else {
2071 dol_print_error($db);
2072 }
2073 } else {
2074 $htmlforlines .= $line->qty;
2075 }
2076 } else {
2077 $htmlforlines .= $line->qty;
2078 }
2079
2080 $htmlforlines .= '</td>';
2081 if (getDolGlobalInt('TAKEPOS_SHOW_HT')) {
2082 $htmlforlines .= '<td class="right classfortooltip" title="'.$moreinfo.'">';
2083 $htmlforlines .= price($line->total_ht, 1, '', 1, -1, -1, $conf->currency);
2084 if (isModEnabled('multicurrency') && !empty($_SESSION["takeposcustomercurrency"]) && $conf->currency != $_SESSION["takeposcustomercurrency"]) {
2085 //Only show customer currency if multicurrency module is enabled, if currency selected and if this currency selected is not the same as main currency
2086 include_once DOL_DOCUMENT_ROOT.'/multicurrency/class/multicurrency.class.php';
2087 $multicurrency = new MultiCurrency($db);
2088 $multicurrency->fetch(0, $_SESSION["takeposcustomercurrency"]);
2089 $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>';
2090 }
2091 $htmlforlines .= '</td>';
2092 }
2093 $htmlforlines .= '<td class="right classfortooltip" title="'.$moreinfo.'">';
2094 $htmlforlines .= price($line->total_ttc, 1, '', 1, -1, -1, $conf->currency);
2095 if (isModEnabled('multicurrency') && !empty($_SESSION["takeposcustomercurrency"]) && $conf->currency != $_SESSION["takeposcustomercurrency"]) {
2096 //Only show customer currency if multicurrency module is enabled, if currency selected and if this currency selected is not the same as main currency
2097 include_once DOL_DOCUMENT_ROOT.'/multicurrency/class/multicurrency.class.php';
2098 $multicurrency = new MultiCurrency($db);
2099 $multicurrency->fetch(0, $_SESSION["takeposcustomercurrency"]);
2100 $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>';
2101 }
2102 $htmlforlines .= '</td>';
2103 }
2104 $htmlforlines .= '</tr>'."\n";
2105 $htmlforlines .= empty($htmlsupplements[$line->id]) ? '' : $htmlsupplements[$line->id];
2106
2107 print $htmlforlines;
2108 }
2109 } else {
2110 print '<tr class="drag drop oddeven"><td class="left"><span class="opacitymedium">'.$langs->trans("Empty").'</span></td><td></td>';
2111 if (empty($_SESSION["basiclayout"]) || $_SESSION["basiclayout"] != 1) {
2112 print '<td></td><td></td>';
2113 if (getDolGlobalString('TAKEPOS_SHOW_HT')) {
2114 print '<td></td>';
2115 }
2116 }
2117 print '</tr>';
2118 }
2119} else { // No invoice generated yet
2120 print '<tr class="drag drop oddeven"><td class="left"><span class="opacitymedium">'.$langs->trans("Empty").'</span></td><td></td>';
2121 if (empty($_SESSION["basiclayout"]) || $_SESSION["basiclayout"] != 1) {
2122 print '<td></td><td></td>';
2123 if (getDolGlobalString('TAKEPOS_SHOW_HT')) {
2124 print '<td></td>';
2125 }
2126 }
2127 print '</tr>';
2128}
2129
2130if ($usediv) {
2131 print '</div>';
2132} else {
2133 print '</table>';
2134}
2135
2136if (($action == "valid" || $action == "history") && $invoice->type != Facture::TYPE_CREDIT_NOTE && !getDolGlobalString('TAKEPOS_NO_CREDITNOTE')) {
2137 print '<button id="buttonprint" type="button" onclick="ModalBox(\'ModalCreditNote\')">'.$langs->trans('CreateCreditNote').'</button>';
2138 if (getDolGlobalInt('TAKEPOS_PRINT_INVOICE_DOC_INSTEAD_OF_RECEIPT')) {
2139 print ' <a target="_blank" class="button" href="' . DOL_URL_ROOT . '/document.php?token=' . newToken() . '&modulepart=facture&file=' . $invoice->ref . '/' . $invoice->ref . '.pdf">Invoice</a>';
2140 }
2141}
2142
2143
2144if ($action == "search") {
2145 print '<center>
2146 <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')).'">
2147 </center>';
2148}
2149
2150print '</div>';
2151
2152// llxFooter
2153if ((getDolGlobalString('TAKEPOS_PHONE_BASIC_LAYOUT') == 1 && $conf->browser->layout == 'phone') || defined('INCLUDE_PHONEPAGE_FROM_PUBLIC_PAGE')) {
2154 print '</body></html>';
2155}
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:149
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