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