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