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