invoice.php 73 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710
  1. <?php
  2. /**
  3. * Copyright (C) 2018 Andreu Bisquerra <jove@bisquerra.com>
  4. * Copyright (C) 2021 Nicolas ZABOURI <info@inovea-conseil.com>
  5. *
  6. * This program is free software; you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation; either version 3 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with this program. If not, see <https://www.gnu.org/licenses/>.
  18. */
  19. /**
  20. * \file htdocs/takepos/invoice.php
  21. * \ingroup takepos
  22. * \brief Page to generate section with list of lines
  23. */
  24. // if (! defined('NOREQUIREUSER')) define('NOREQUIREUSER', '1'); // Not disabled cause need to load personalized language
  25. // if (! defined('NOREQUIREDB')) define('NOREQUIREDB', '1'); // Not disabled cause need to load personalized language
  26. // if (! defined('NOREQUIRESOC')) define('NOREQUIRESOC', '1');
  27. // if (! defined('NOREQUIRETRAN')) define('NOREQUIRETRAN', '1');
  28. if (!defined('NOTOKENRENEWAL')) {
  29. define('NOTOKENRENEWAL', '1');
  30. }
  31. if (!defined('NOREQUIREMENU')) {
  32. define('NOREQUIREMENU', '1');
  33. }
  34. if (!defined('NOREQUIREHTML')) {
  35. define('NOREQUIREHTML', '1');
  36. }
  37. if (!defined('NOREQUIREAJAX')) {
  38. define('NOREQUIREAJAX', '1');
  39. }
  40. // Load Dolibarr environment
  41. if (!defined('INCLUDE_PHONEPAGE_FROM_PUBLIC_PAGE')) {
  42. require '../main.inc.php';
  43. }
  44. require_once DOL_DOCUMENT_ROOT.'/core/class/html.form.class.php';
  45. require_once DOL_DOCUMENT_ROOT.'/core/class/hookmanager.class.php';
  46. require_once DOL_DOCUMENT_ROOT.'/compta/facture/class/facture.class.php';
  47. require_once DOL_DOCUMENT_ROOT.'/compta/paiement/class/paiement.class.php';
  48. $hookmanager->initHooks(array('takeposinvoice'));
  49. $langs->loadLangs(array("companies", "commercial", "bills", "cashdesk", "stocks", "banks"));
  50. $action = GETPOST('action', 'aZ09');
  51. $idproduct = GETPOST('idproduct', 'int');
  52. $place = (GETPOST('place', 'aZ09') ? GETPOST('place', 'aZ09') : 0); // $place is id of table for Bar or Restaurant
  53. $placeid = 0; // $placeid is ID of invoice
  54. $mobilepage = GETPOST('mobilepage', 'alpha');
  55. // Terminal is stored into $_SESSION["takeposterminal"];
  56. if (empty($user->rights->takepos->run) && !defined('INCLUDE_PHONEPAGE_FROM_PUBLIC_PAGE')) {
  57. accessforbidden();
  58. }
  59. if ((getDolGlobalString('TAKEPOS_PHONE_BASIC_LAYOUT') == 1 && $conf->browser->layout == 'phone') || defined('INCLUDE_PHONEPAGE_FROM_PUBLIC_PAGE')) {
  60. // DIRECT LINK TO THIS PAGE FROM MOBILE AND NO TERMINAL SELECTED
  61. if ($_SESSION["takeposterminal"] == "") {
  62. if (getDolGlobalString('TAKEPOS_NUM_TERMINALS') == "1") {
  63. $_SESSION["takeposterminal"] = 1;
  64. } else {
  65. header("Location: ".DOL_URL_ROOT."/takepos/index.php");
  66. exit;
  67. }
  68. }
  69. }
  70. /**
  71. * Abort invoice creationg with a given error message
  72. *
  73. * @param string $message Message explaining the error to the user
  74. * @return void
  75. */
  76. function fail($message)
  77. {
  78. header($_SERVER['SERVER_PROTOCOL'].' 500 Internal Server Error', true, 500);
  79. die($message);
  80. }
  81. $number = GETPOST('number', 'alpha');
  82. $idline = GETPOST('idline', 'int');
  83. $selectedline = GETPOST('selectedline', 'int');
  84. $desc = GETPOST('desc', 'alphanohtml');
  85. $pay = GETPOST('pay', 'aZ09');
  86. $amountofpayment = price2num(GETPOST('amount', 'alpha'));
  87. $invoiceid = GETPOST('invoiceid', 'int');
  88. $paycode = $pay;
  89. if ($pay == 'cash') {
  90. $paycode = 'LIQ'; // For backward compatibility
  91. }
  92. if ($pay == 'card') {
  93. $paycode = 'CB'; // For backward compatibility
  94. }
  95. if ($pay == 'cheque') {
  96. $paycode = 'CHQ'; // For backward compatibility
  97. }
  98. // Retrieve paiementid
  99. $paiementid = 0;
  100. if ($paycode) {
  101. $sql = "SELECT id FROM ".MAIN_DB_PREFIX."c_paiement";
  102. $sql .= " WHERE entity IN (".getEntity('c_paiement').")";
  103. $sql .= " AND code = '".$db->escape($paycode)."'";
  104. $resql = $db->query($sql);
  105. if ($resql) {
  106. $obj = $db->fetch_object($resql);
  107. if ($obj) {
  108. $paiementid = $obj->id;
  109. }
  110. }
  111. }
  112. $invoice = new Facture($db);
  113. if ($invoiceid > 0) {
  114. $ret = $invoice->fetch($invoiceid);
  115. } else {
  116. $ret = $invoice->fetch('', '(PROV-POS'. (isset($_SESSION["takeposterminal"]) ? $_SESSION["takeposterminal"] : '') .'-'.$place.')');
  117. }
  118. if ($ret > 0) {
  119. $placeid = $invoice->id;
  120. }
  121. $constforcompanyid = 'CASHDESK_ID_THIRDPARTY'. (isset($_SESSION["takeposterminal"]) ? $_SESSION["takeposterminal"] : '');
  122. $soc = new Societe($db);
  123. if ($invoice->socid > 0) {
  124. $soc->fetch($invoice->socid);
  125. } else {
  126. $soc->fetch(getDolGlobalString("$constforcompanyid"));
  127. }
  128. // Change the currency of invoice if it was modified
  129. if (isModEnabled('multicurrency') && !empty($_SESSION["takeposcustomercurrency"])) {
  130. if ($invoice->multicurrency_code != $_SESSION["takeposcustomercurrency"]) {
  131. $invoice->setMulticurrencyCode($_SESSION["takeposcustomercurrency"]);
  132. }
  133. }
  134. /*
  135. * Actions
  136. */
  137. $parameters=array();
  138. $reshook=$hookmanager->executeHooks('doActions', $parameters, $invoice, $action); // Note that $action and $object may have been modified by some hooks
  139. if ($reshook < 0) setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
  140. if (empty($reshook)) {
  141. // Action to record a payment on a TakePOS invoice
  142. if ($action == 'valid' && $user->hasRight('facture', 'creer')) {
  143. $bankaccount = 0;
  144. $error = 0;
  145. if (!empty($conf->global->TAKEPOS_CAN_FORCE_BANK_ACCOUNT_DURING_PAYMENT)) {
  146. $bankaccount = GETPOST('accountid', 'int');
  147. } else {
  148. if ($pay == 'LIQ') {
  149. $bankaccount = getDolGlobalString('CASHDESK_ID_BANKACCOUNT_CASH'.$_SESSION["takeposterminal"]); // For backward compatibility
  150. } elseif ($pay == "CHQ") {
  151. $bankaccount = getDolGlobalString('CASHDESK_ID_BANKACCOUNT_CHEQUE'.$_SESSION["takeposterminal"]); // For backward compatibility
  152. } else {
  153. $accountname = "CASHDESK_ID_BANKACCOUNT_".$pay.$_SESSION["takeposterminal"];
  154. $bankaccount = getDolGlobalString($accountname);
  155. }
  156. }
  157. if ($bankaccount <= 0 && $pay != "delayed" && isModEnabled("banque")) {
  158. $errormsg = $langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("BankAccount"));
  159. $error++;
  160. }
  161. $now = dol_now();
  162. $res = 0;
  163. $invoice = new Facture($db);
  164. $invoice->fetch($placeid);
  165. if ($invoice->total_ttc < 0) {
  166. $invoice->type = $invoice::TYPE_CREDIT_NOTE;
  167. $sql = "SELECT rowid FROM ".MAIN_DB_PREFIX."facture WHERE";
  168. $sql .= " fk_soc = ".((int) $invoice->socid);
  169. $sql .= " AND type <> ".Facture::TYPE_CREDIT_NOTE;
  170. $sql .= " AND fk_statut >= ".$invoice::STATUS_VALIDATED;
  171. $sql .= " ORDER BY rowid DESC";
  172. $resql = $db->query($sql);
  173. if ($resql) {
  174. $obj = $db->fetch_object($resql);
  175. $fk_source = $obj->rowid;
  176. if ($fk_source == null) {
  177. fail($langs->transnoentitiesnoconv("NoPreviousBillForCustomer"));
  178. }
  179. } else {
  180. fail($langs->transnoentitiesnoconv("NoPreviousBillForCustomer"));
  181. }
  182. $invoice->fk_facture_source = $fk_source;
  183. $invoice->update($user);
  184. }
  185. $constantforkey = 'CASHDESK_NO_DECREASE_STOCK'.$_SESSION["takeposterminal"];
  186. if ($error) {
  187. dol_htmloutput_errors($errormsg, null, 1);
  188. } elseif ($invoice->statut != Facture::STATUS_DRAFT) {
  189. //If invoice is validated but it is not fully paid is not error and make the payment
  190. if ($invoice->getRemainToPay() > 0) {
  191. $res = 1;
  192. } else {
  193. dol_syslog("Sale already validated");
  194. dol_htmloutput_errors($langs->trans("InvoiceIsAlreadyValidated", "TakePos"), null, 1);
  195. }
  196. } elseif (count($invoice->lines) == 0) {
  197. $error++;
  198. dol_syslog('Sale without lines');
  199. dol_htmloutput_errors($langs->trans("NoLinesToBill", "TakePos"), null, 1);
  200. } elseif (isModEnabled('stock') && $conf->global->$constantforkey != "1") {
  201. $savconst = $conf->global->STOCK_CALCULATE_ON_BILL;
  202. $conf->global->STOCK_CALCULATE_ON_BILL = 1;
  203. $constantforkey = 'CASHDESK_ID_WAREHOUSE'.$_SESSION["takeposterminal"];
  204. dol_syslog("Validate invoice with stock change into warehouse defined into constant ".$constantforkey." = ".$conf->global->$constantforkey);
  205. $batch_rule = 0;
  206. if (isModEnabled('productbatch') && !empty($conf->global->CASHDESK_FORCE_DECREASE_STOCK)) {
  207. require_once DOL_DOCUMENT_ROOT.'/product/class/productbatch.class.php';
  208. $batch_rule = Productbatch::BATCH_RULE_SELLBY_EATBY_DATES_FIRST;
  209. }
  210. $res = $invoice->validate($user, '', $conf->global->$constantforkey, 0, $batch_rule);
  211. $conf->global->STOCK_CALCULATE_ON_BILL = $savconst;
  212. } else {
  213. $res = $invoice->validate($user);
  214. if ($res < 0) {
  215. $error++;
  216. $langs->load("admin");
  217. dol_htmloutput_errors($invoice->error == 'NotConfigured' ? $langs->trans("NotConfigured").' (TakePos numbering module)': $invoice->error, $invoice->errors, 1);
  218. }
  219. }
  220. // Restore save values
  221. //if (!empty($sav_FACTURE_ADDON))
  222. //{
  223. // $conf->global->FACTURE_ADDON = $sav_FACTURE_ADDON;
  224. //}
  225. // Add the payment
  226. if (!$error && $res >= 0) {
  227. $remaintopay = $invoice->getRemainToPay();
  228. if ($remaintopay > 0) {
  229. $payment = new Paiement($db);
  230. $payment->datepaye = $now;
  231. $payment->fk_account = $bankaccount;
  232. $payment->amounts[$invoice->id] = $amountofpayment;
  233. if ($pay == 'LIQ') {
  234. $payment->pos_change = price2num(GETPOST('excess', 'alpha'));
  235. }
  236. // If user has not used change control, add total invoice payment
  237. // Or if user has used change control and the amount of payment is higher than remain to pay, add the remain to pay
  238. if ($amountofpayment <= 0 || $amountofpayment > $remaintopay) {
  239. $payment->amounts[$invoice->id] = $remaintopay;
  240. }
  241. $payment->paiementid = $paiementid;
  242. $payment->num_payment = $invoice->ref;
  243. if ($pay != "delayed") {
  244. $payment->create($user);
  245. $payment->addPaymentToBank($user, 'payment', '(CustomerInvoicePayment)', $bankaccount, '', '');
  246. $remaintopay = $invoice->getRemainToPay(); // Recalculate remain to pay after the payment is recorded
  247. } elseif (getDolGlobalInt("TAKEPOS_DELAYED_TERMS")) {
  248. $invoice->setPaymentTerms(getDolGlobalInt("TAKEPOS_DELAYED_TERMS"));
  249. }
  250. }
  251. if ($remaintopay == 0) {
  252. dol_syslog("Invoice is paid, so we set it to status Paid");
  253. $result = $invoice->setPaid($user);
  254. if ($result > 0) {
  255. $invoice->paye = 1;
  256. }
  257. // set payment method
  258. $invoice->setPaymentMethods($paiementid);
  259. } else {
  260. dol_syslog("Invoice is not paid, remain to pay = ".$remaintopay);
  261. }
  262. } else {
  263. dol_htmloutput_errors($invoice->error, $invoice->errors, 1);
  264. }
  265. }
  266. if ($action == 'creditnote' && $user->hasRight('facture', 'creer')) {
  267. $creditnote = new Facture($db);
  268. $creditnote->socid = $invoice->socid;
  269. $creditnote->date = dol_now();
  270. $creditnote->module_source = 'takepos';
  271. $creditnote->pos_source = isset($_SESSION["takeposterminal"]) ? $_SESSION["takeposterminal"] : '' ;
  272. $creditnote->type = Facture::TYPE_CREDIT_NOTE;
  273. $creditnote->fk_facture_source = $placeid;
  274. $creditnote->remise_absolue = $invoice->remise_absolue;
  275. $creditnote->remise_percent = $invoice->remise_percent;
  276. $creditnote->create($user);
  277. foreach ($invoice->lines as $line) {
  278. // Extrafields
  279. if (method_exists($line, 'fetch_optionals')) {
  280. // load extrafields
  281. $line->fetch_optionals();
  282. }
  283. // Reset fk_parent_line for no child products and special product
  284. if (($line->product_type != 9 && empty($line->fk_parent_line)) || $line->product_type == 9) {
  285. $fk_parent_line = 0;
  286. }
  287. if (getDolGlobalInt('INVOICE_USE_SITUATION')) {
  288. if (!empty($invoice->situation_counter)) {
  289. $source_fk_prev_id = $line->fk_prev_id; // temporary storing situation invoice fk_prev_id
  290. $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
  291. if (!empty($invoice->tab_previous_situation_invoice)) {
  292. // search the last standard invoice in cycle and the possible credit note between this last and invoice
  293. // TODO Move this out of loop of $invoice->lines
  294. $tab_jumped_credit_notes = array();
  295. $lineIndex = count($invoice->tab_previous_situation_invoice) - 1;
  296. $searchPreviousInvoice = true;
  297. while ($searchPreviousInvoice) {
  298. if ($invoice->tab_previous_situation_invoice[$lineIndex]->situation_cycle_ref || $lineIndex < 1) {
  299. $searchPreviousInvoice = false; // find, exit;
  300. break;
  301. } else {
  302. if ($invoice->tab_previous_situation_invoice[$lineIndex]->type == Facture::TYPE_CREDIT_NOTE) {
  303. $tab_jumped_credit_notes[$lineIndex] = $invoice->tab_previous_situation_invoice[$lineIndex]->id;
  304. }
  305. $lineIndex--; // go to previous invoice in cycle
  306. }
  307. }
  308. $maxPrevSituationPercent = 0;
  309. foreach ($invoice->tab_previous_situation_invoice[$lineIndex]->lines as $prevLine) {
  310. if ($prevLine->id == $source_fk_prev_id) {
  311. $maxPrevSituationPercent = max($maxPrevSituationPercent, $prevLine->situation_percent);
  312. //$line->subprice = $line->subprice - $prevLine->subprice;
  313. $line->total_ht = $line->total_ht - $prevLine->total_ht;
  314. $line->total_tva = $line->total_tva - $prevLine->total_tva;
  315. $line->total_ttc = $line->total_ttc - $prevLine->total_ttc;
  316. $line->total_localtax1 = $line->total_localtax1 - $prevLine->total_localtax1;
  317. $line->total_localtax2 = $line->total_localtax2 - $prevLine->total_localtax2;
  318. $line->multicurrency_subprice = $line->multicurrency_subprice - $prevLine->multicurrency_subprice;
  319. $line->multicurrency_total_ht = $line->multicurrency_total_ht - $prevLine->multicurrency_total_ht;
  320. $line->multicurrency_total_tva = $line->multicurrency_total_tva - $prevLine->multicurrency_total_tva;
  321. $line->multicurrency_total_ttc = $line->multicurrency_total_ttc - $prevLine->multicurrency_total_ttc;
  322. }
  323. }
  324. // prorata
  325. $line->situation_percent = $maxPrevSituationPercent - $line->situation_percent;
  326. //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>';
  327. // If there is some credit note between last situation invoice and invoice used for credit note generation (note: credit notes are stored as delta)
  328. $maxPrevSituationPercent = 0;
  329. foreach ($tab_jumped_credit_notes as $index => $creditnoteid) {
  330. foreach ($invoice->tab_previous_situation_invoice[$index]->lines as $prevLine) {
  331. if ($prevLine->fk_prev_id == $source_fk_prev_id) {
  332. $maxPrevSituationPercent = $prevLine->situation_percent;
  333. $line->total_ht -= $prevLine->total_ht;
  334. $line->total_tva -= $prevLine->total_tva;
  335. $line->total_ttc -= $prevLine->total_ttc;
  336. $line->total_localtax1 -= $prevLine->total_localtax1;
  337. $line->total_localtax2 -= $prevLine->total_localtax2;
  338. $line->multicurrency_subprice -= $prevLine->multicurrency_subprice;
  339. $line->multicurrency_total_ht -= $prevLine->multicurrency_total_ht;
  340. $line->multicurrency_total_tva -= $prevLine->multicurrency_total_tva;
  341. $line->multicurrency_total_ttc -= $prevLine->multicurrency_total_ttc;
  342. }
  343. }
  344. }
  345. // prorata
  346. $line->situation_percent += $maxPrevSituationPercent;
  347. //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>';
  348. }
  349. }
  350. }
  351. $line->fk_facture = $creditnote->id;
  352. $line->fk_parent_line = $fk_parent_line;
  353. $line->subprice = -$line->subprice; // invert price for object
  354. $line->pa_ht = $line->pa_ht; // we choosed to have buy/cost price always positive, so no revert of sign here
  355. $line->total_ht = -$line->total_ht;
  356. $line->total_tva = -$line->total_tva;
  357. $line->total_ttc = -$line->total_ttc;
  358. $line->total_localtax1 = -$line->total_localtax1;
  359. $line->total_localtax2 = -$line->total_localtax2;
  360. $line->multicurrency_subprice = -$line->multicurrency_subprice;
  361. $line->multicurrency_total_ht = -$line->multicurrency_total_ht;
  362. $line->multicurrency_total_tva = -$line->multicurrency_total_tva;
  363. $line->multicurrency_total_ttc = -$line->multicurrency_total_ttc;
  364. $result = $line->insert(0, 1); // When creating credit note with same lines than source, we must ignore error if discount alreayd linked
  365. $creditnote->lines[] = $line; // insert new line in current object
  366. // Defined the new fk_parent_line
  367. if ($result > 0 && $line->product_type == 9) {
  368. $fk_parent_line = $result;
  369. }
  370. }
  371. $creditnote->update_price(1);
  372. $constantforkey = 'CASHDESK_NO_DECREASE_STOCK'.$_SESSION["takeposterminal"];
  373. if (isModEnabled('stock') && $conf->global->$constantforkey != "1") {
  374. $savconst = $conf->global->STOCK_CALCULATE_ON_BILL;
  375. $conf->global->STOCK_CALCULATE_ON_BILL = 1;
  376. $constantforkey = 'CASHDESK_ID_WAREHOUSE'.$_SESSION["takeposterminal"];
  377. dol_syslog("Validate invoice with stock change into warehouse defined into constant ".$constantforkey." = ".$conf->global->$constantforkey);
  378. $batch_rule = 0;
  379. if (isModEnabled('productbatch') && !empty($conf->global->CASHDESK_FORCE_DECREASE_STOCK)) {
  380. require_once DOL_DOCUMENT_ROOT.'/product/class/productbatch.class.php';
  381. $batch_rule = Productbatch::BATCH_RULE_SELLBY_EATBY_DATES_FIRST;
  382. }
  383. $res = $creditnote->validate($user, '', $conf->global->$constantforkey, 0, $batch_rule);
  384. $conf->global->STOCK_CALCULATE_ON_BILL = $savconst;
  385. } else {
  386. $res = $creditnote->validate($user);
  387. }
  388. }
  389. if ($action == 'history' || $action == 'creditnote') {
  390. if ($action == 'creditnote') {
  391. $placeid = $creditnote->id;
  392. } else {
  393. $placeid = (int) GETPOST('placeid', 'int');
  394. }
  395. $invoice = new Facture($db);
  396. $invoice->fetch($placeid);
  397. }
  398. if (($action == "addline" || $action == "freezone") && $placeid == 0) {
  399. $invoice->socid = getDolGlobalString("$constforcompanyid");
  400. $invoice->date = dol_now();
  401. $invoice->module_source = 'takepos';
  402. $invoice->pos_source = isset($_SESSION["takeposterminal"]) ? $_SESSION["takeposterminal"] : '' ;
  403. $invoice->entity = !empty($_SESSION["takeposinvoiceentity"]) ? $_SESSION["takeposinvoiceentity"] : $conf->entity;
  404. if ($invoice->socid <= 0) {
  405. $langs->load('errors');
  406. dol_htmloutput_errors($langs->trans("ErrorModuleSetupNotComplete", "TakePos"), null, 1);
  407. } else {
  408. $placeid = $invoice->create($user);
  409. if ($placeid < 0) {
  410. dol_htmloutput_errors($invoice->error, $invoice->errors, 1);
  411. }
  412. $sql = "UPDATE ".MAIN_DB_PREFIX."facture set ref='(PROV-POS".$_SESSION["takeposterminal"]."-".$place.")' where rowid = ".((int) $placeid);
  413. $db->query($sql);
  414. }
  415. }
  416. if ($action == "addline") {
  417. $prod = new Product($db);
  418. $prod->fetch($idproduct);
  419. $customer = new Societe($db);
  420. $customer->fetch($invoice->socid);
  421. $datapriceofproduct = $prod->getSellPrice($mysoc, $customer, 0);
  422. $qty = GETPOSTISSET('qty') ? GETPOST('qty', 'int') : 1;
  423. $price = $datapriceofproduct['pu_ht'];
  424. $price_ttc = $datapriceofproduct['pu_ttc'];
  425. //$price_min = $datapriceofproduct['price_min'];
  426. $price_base_type = $datapriceofproduct['price_base_type'];
  427. $tva_tx = $datapriceofproduct['tva_tx'];
  428. $tva_npr = $datapriceofproduct['tva_npr'];
  429. // Local Taxes
  430. $localtax1_tx = get_localtax($tva_tx, 1, $customer, $mysoc, $tva_npr);
  431. $localtax2_tx = get_localtax($tva_tx, 2, $customer, $mysoc, $tva_npr);
  432. if (!empty($conf->global->TAKEPOS_SUPPLEMENTS)) {
  433. require_once DOL_DOCUMENT_ROOT.'/categories/class/categorie.class.php';
  434. $cat = new Categorie($db);
  435. $categories = $cat->containing($idproduct, 'product');
  436. $found = (array_search($conf->global->TAKEPOS_SUPPLEMENTS_CATEGORY, array_column($categories, 'id')));
  437. if ($found !== false) { // If this product is a supplement
  438. $sql = "SELECT fk_parent_line FROM ".MAIN_DB_PREFIX."facturedet where rowid=$selectedline";
  439. $resql = $db->query($sql);
  440. $row = $db->fetch_array($resql);
  441. if ($row[0] == null) {
  442. $parent_line = $selectedline;
  443. } else {
  444. $parent_line = $row[0]; //If the parent line is already a supplement, add the supplement to the main product
  445. }
  446. }
  447. }
  448. $idoflineadded = 0;
  449. // Group if enabled. Skip group if line already sent to the printer
  450. if (!empty($conf->global->TAKEPOS_GROUP_SAME_PRODUCT)) {
  451. foreach ($invoice->lines as $line) {
  452. if ($line->product_ref == $prod->ref) {
  453. if ($line->special_code==4) continue; // If this line is sended to printer create new line
  454. $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);
  455. if ($result < 0) {
  456. dol_htmloutput_errors($invoice->error, $invoice->errors, 1);
  457. } else {
  458. $idoflineadded = $line->id;
  459. }
  460. break;
  461. }
  462. }
  463. }
  464. if ($idoflineadded <= 0) {
  465. $invoice->fetch_thirdparty();
  466. $array_options = array();
  467. $line = array('description' => $prod->description, 'price' => $price, 'tva_tx' => $tva_tx, 'locatax1_tx' => $localtax1_tx, 'locatax2_tx' => $localtax2_tx, 'remise_percent' => $customer->remise_percent, 'price_ttc' => $price_ttc, 'array_options' => $array_options);
  468. /* setup of margin calculation */
  469. if (isset($conf->global->MARGIN_TYPE)) {
  470. if ($conf->global->MARGIN_TYPE == 'pmp' && !empty($prod->pmp)) {
  471. $line['fk_fournprice'] = null;
  472. $line['pa_ht'] = $prod->pmp;
  473. } elseif ($conf->global->MARGIN_TYPE == 'costprice' && !empty($prod->cost_price)) {
  474. $line['fk_fournprice'] = null;
  475. $line['pa_ht'] = $prod->cost_price;
  476. } else {
  477. // default is fournprice
  478. require_once DOL_DOCUMENT_ROOT.'/fourn/class/fournisseur.product.class.php';
  479. $pf = new ProductFournisseur($db);
  480. if ($pf->find_min_price_product_fournisseur($idproduct, $qty) > 0) {
  481. $line['fk_fournprice'] = $pf->product_fourn_price_id;
  482. $line['pa_ht'] = $pf->fourn_unitprice_with_discount;
  483. if ($pf->fourn_charges > 0)
  484. $line['pa_ht'] += $pf->fourn_charges / $pf->fourn_qty;
  485. }
  486. }
  487. }
  488. // complete line by hook
  489. $parameters = array('prod' => $prod, 'line' => $line);
  490. $reshook=$hookmanager->executeHooks('completeTakePosAddLine', $parameters, $invoice, $action); // Note that $action and $line may have been modified by some hooks
  491. if ($reshook < 0) setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
  492. if (empty($reshook)) {
  493. if (!empty($hookmanager->resArray)) {
  494. $line = $hookmanager->resArray;
  495. }
  496. $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 : '', $line['fk_fournprice'], $line['pa_ht'], '', $line['array_options'], 100, '', null, 0);
  497. }
  498. if (!empty($conf->global->TAKEPOS_CUSTOMER_DISPLAY)) {
  499. $CUSTOMER_DISPLAY_line1 = $prod->label;
  500. $CUSTOMER_DISPLAY_line2 = price($price_ttc);
  501. }
  502. }
  503. $invoice->fetch($placeid);
  504. }
  505. if ($action == "freezone") {
  506. $customer = new Societe($db);
  507. $customer->fetch($invoice->socid);
  508. $tva_tx = GETPOST('tva_tx', 'alpha');
  509. if ($tva_tx != '') {
  510. if (!preg_match('/\((.*)\)/', $tva_tx)) {
  511. $tva_tx = price2num($tva_tx);
  512. }
  513. } else {
  514. $tva_tx = get_default_tva($mysoc, $customer);
  515. }
  516. // Local Taxes
  517. $localtax1_tx = get_localtax($tva_tx, 1, $customer, $mysoc, $tva_npr);
  518. $localtax2_tx = get_localtax($tva_tx, 2, $customer, $mysoc, $tva_npr);
  519. $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);
  520. $invoice->fetch($placeid);
  521. }
  522. if ($action == "addnote") {
  523. $desc = GETPOST('addnote', 'alpha');
  524. if ($idline==0) {
  525. $invoice->update_note($desc, '_public');
  526. } else foreach ($invoice->lines as $line) {
  527. if ($line->id == $idline) {
  528. $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);
  529. }
  530. }
  531. $invoice->fetch($placeid);
  532. }
  533. if ($action == "deleteline") {
  534. if ($idline > 0 and $placeid > 0) { // If invoice exists and line selected. To avoid errors if deleted from another device or no line selected.
  535. $invoice->deleteline($idline);
  536. $invoice->fetch($placeid);
  537. } elseif ($placeid > 0) { // If invoice exists but no line selected, proceed to delete last line.
  538. $sql = "SELECT rowid FROM ".MAIN_DB_PREFIX."facturedet where fk_facture = ".((int) $placeid)." ORDER BY rowid DESC";
  539. $resql = $db->query($sql);
  540. $row = $db->fetch_array($resql);
  541. $deletelineid = $row[0];
  542. $invoice->deleteline($deletelineid);
  543. $invoice->fetch($placeid);
  544. }
  545. if (count($invoice->lines) == 0) {
  546. $invoice->delete($user);
  547. header("Location: ".DOL_URL_ROOT."/takepos/invoice.php");
  548. exit;
  549. }
  550. }
  551. // Action to delete or discard an invoice
  552. if ($action == "delete") {
  553. // $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 begining of page works.
  554. if ($placeid > 0) {
  555. $result = $invoice->fetch($placeid);
  556. if ($result > 0 && $invoice->statut == Facture::STATUS_DRAFT) {
  557. $db->begin();
  558. // We delete the lines
  559. $resdeletelines = 1;
  560. foreach ($invoice->lines as $line) {
  561. $tmpres = $invoice->deleteline($line->id);
  562. if ($tmpres < 0) {
  563. $resdeletelines = 0;
  564. break;
  565. }
  566. }
  567. $sql = "UPDATE ".MAIN_DB_PREFIX."facture";
  568. $varforconst = 'CASHDESK_ID_THIRDPARTY'.$_SESSION["takeposterminal"];
  569. $sql .= " SET fk_soc = ".((int) $conf->global->$varforconst).", ";
  570. $sql .= " datec = '".$db->idate(dol_now())."'";
  571. $sql .= " WHERE ref = '(PROV-POS".$db->escape($_SESSION["takeposterminal"]."-".$place).")'";
  572. $resql1 = $db->query($sql);
  573. if ($resdeletelines && $resql1) {
  574. $db->commit();
  575. } else {
  576. $db->rollback();
  577. }
  578. $invoice->fetch($placeid);
  579. }
  580. }
  581. }
  582. if ($action == "updateqty") {
  583. foreach ($invoice->lines as $line) {
  584. if ($line->id == $idline) {
  585. if (!$user->rights->takepos->editlines || (!$user->rights->takepos->editorderedlines && $line->special_code == "4")) {
  586. dol_htmloutput_errors($langs->trans("NotEnoughPermissions", "TakePos"), null, 1);
  587. } else {
  588. $result = $invoice->updateline($line->id, $line->desc, $line->subprice, $number, $line->remise_percent, $line->date_start, $line->date_end, $line->tva_tx, $line->localtax1_tx, $line->localtax2_tx, 'HT', $line->info_bits, $line->product_type, $line->fk_parent_line, 0, $line->fk_fournprice, $line->pa_ht, $line->label, $line->special_code, $line->array_options, $line->situation_percent, $line->fk_unit);
  589. }
  590. }
  591. }
  592. $invoice->fetch($placeid);
  593. }
  594. if ($action == "updateprice") {
  595. $customer = new Societe($db);
  596. $customer->fetch($invoice->socid);
  597. foreach ($invoice->lines as $line) {
  598. if ($line->id == $idline) {
  599. $prod = new Product($db);
  600. $prod->fetch($line->fk_product);
  601. $datapriceofproduct = $prod->getSellPrice($mysoc, $customer, 0);
  602. $price_min = $datapriceofproduct['price_min'];
  603. $usercanproductignorepricemin = ((!empty($conf->global->MAIN_USE_ADVANCED_PERMS) && empty($user->rights->produit->ignore_price_min_advance)) || empty($conf->global->MAIN_USE_ADVANCED_PERMS));
  604. $pu_ht = price2num($number / (1 + ($line->tva_tx / 100)), 'MU');
  605. //Check min price
  606. if ($usercanproductignorepricemin && (!empty($price_min) && (price2num($pu_ht) * (1 - price2num($line->remise_percent) / 100) < price2num($price_min)))) {
  607. $langs->load("products");
  608. dol_htmloutput_errors($langs->trans("CantBeLessThanMinPrice", price(price2num($price_min, 'MU'), 0, $langs, 0, 0, -1, $conf->currency)));
  609. //echo $langs->trans("CantBeLessThanMinPrice");
  610. } else {
  611. if (empty($user->rights->takepos->editlines) || (empty($user->rights->takepos->editorderedlines) && $line->special_code == "4")) {
  612. dol_htmloutput_errors($langs->trans("NotEnoughPermissions", "TakePos"), null, 1);
  613. } elseif (getDolGlobalInt('TAKEPOS_CHANGE_PRICE_HT') == 1) {
  614. $result = $invoice->updateline($line->id, $line->desc, $number, $line->qty, $line->remise_percent, $line->date_start, $line->date_end, $line->tva_tx, $line->localtax1_tx, $line->localtax2_tx, 'HT', $line->info_bits, $line->product_type, $line->fk_parent_line, 0, $line->fk_fournprice, $line->pa_ht, $line->label, $line->special_code, $line->array_options, $line->situation_percent, $line->fk_unit);
  615. } else {
  616. $result = $invoice->updateline($line->id, $line->desc, $number, $line->qty, $line->remise_percent, $line->date_start, $line->date_end, $line->tva_tx, $line->localtax1_tx, $line->localtax2_tx, 'TTC', $line->info_bits, $line->product_type, $line->fk_parent_line, 0, $line->fk_fournprice, $line->pa_ht, $line->label, $line->special_code, $line->array_options, $line->situation_percent, $line->fk_unit);
  617. }
  618. }
  619. }
  620. }
  621. // Reload data
  622. $invoice->fetch($placeid);
  623. }
  624. if ($action == "updatereduction") {
  625. $customer = new Societe($db);
  626. $customer->fetch($invoice->socid);
  627. foreach ($invoice->lines as $line) {
  628. if ($line->id == $idline) {
  629. dol_syslog("updatereduction Process line ".$line->id.' to apply discount of '.$number.'%');
  630. $prod = new Product($db);
  631. $prod->fetch($line->fk_product);
  632. $datapriceofproduct = $prod->getSellPrice($mysoc, $customer, 0);
  633. $price_min = $datapriceofproduct['price_min'];
  634. $usercanproductignorepricemin = ((!empty($conf->global->MAIN_USE_ADVANCED_PERMS) && empty($user->rights->produit->ignore_price_min_advance)) || empty($conf->global->MAIN_USE_ADVANCED_PERMS));
  635. $pu_ht = price2num($line->subprice / (1 + ($line->tva_tx / 100)), 'MU');
  636. // Check min price
  637. if ($usercanproductignorepricemin && (!empty($price_min) && (price2num($line->subprice) * (1 - price2num($number) / 100) < price2num($price_min)))) {
  638. $langs->load("products");
  639. dol_htmloutput_errors($langs->trans("CantBeLessThanMinPrice", price(price2num($price_min, 'MU'), 0, $langs, 0, 0, -1, $conf->currency)));
  640. } else {
  641. if (empty($user->rights->takepos->editlines) || (empty($user->rights->takepos->editorderedlines) && $line->special_code == "4")) {
  642. dol_htmloutput_errors($langs->trans("NotEnoughPermissions", "TakePos"), null, 1);
  643. } else {
  644. $result = $invoice->updateline($line->id, $line->desc, $line->subprice, $line->qty, $number, $line->date_start, $line->date_end, $line->tva_tx, $line->localtax1_tx, $line->localtax2_tx, 'HT', $line->info_bits, $line->product_type, $line->fk_parent_line, 0, $line->fk_fournprice, $line->pa_ht, $line->label, $line->special_code, $line->array_options, $line->situation_percent, $line->fk_unit);
  645. }
  646. }
  647. }
  648. }
  649. // Reload data
  650. $invoice->fetch($placeid);
  651. } elseif ($action == 'update_reduction_global') {
  652. foreach ($invoice->lines as $line) {
  653. $result = $invoice->updateline($line->id, $line->desc, $line->subprice, $line->qty, $number, $line->date_start, $line->date_end, $line->tva_tx, $line->localtax1_tx, $line->localtax2_tx, 'HT', $line->info_bits, $line->product_type, $line->fk_parent_line, 0, $line->fk_fournprice, $line->pa_ht, $line->label, $line->special_code, $line->array_options, $line->situation_percent, $line->fk_unit);
  654. }
  655. $invoice->fetch($placeid);
  656. }
  657. if ($action == "order" and $placeid != 0) {
  658. include_once DOL_DOCUMENT_ROOT.'/categories/class/categorie.class.php';
  659. if ($conf->global->TAKEPOS_PRINT_METHOD == "receiptprinter" || $conf->global->TAKEPOS_PRINT_METHOD == "takeposconnector") {
  660. require_once DOL_DOCUMENT_ROOT.'/core/class/dolreceiptprinter.class.php';
  661. $printer = new dolReceiptPrinter($db);
  662. }
  663. $sql = "SELECT label FROM ".MAIN_DB_PREFIX."takepos_floor_tables where rowid=".((int) $place);
  664. $resql = $db->query($sql);
  665. $row = $db->fetch_object($resql);
  666. $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>';
  667. $footerorder = '</tbody></table>'.dol_print_date(dol_now(), 'dayhour').'<br></html>';
  668. $order_receipt_printer1 = "";
  669. $order_receipt_printer2 = "";
  670. $order_receipt_printer3 = "";
  671. $catsprinter1 = explode(';', $conf->global->TAKEPOS_PRINTED_CATEGORIES_1);
  672. $catsprinter2 = explode(';', $conf->global->TAKEPOS_PRINTED_CATEGORIES_2);
  673. $catsprinter3 = explode(';', $conf->global->TAKEPOS_PRINTED_CATEGORIES_3);
  674. $linestoprint = 0;
  675. foreach ($invoice->lines as $line) {
  676. if ($line->special_code == "4") {
  677. continue;
  678. }
  679. $c = new Categorie($db);
  680. $existing = $c->containing($line->fk_product, Categorie::TYPE_PRODUCT, 'id');
  681. $result = array_intersect($catsprinter1, $existing);
  682. $count = count($result);
  683. if (!$line->fk_product) {
  684. $count++; // Print Free-text item (Unassigned printer) to Printer 1
  685. }
  686. if ($count > 0) {
  687. $linestoprint++;
  688. $sql = "UPDATE ".MAIN_DB_PREFIX."facturedet set special_code='1' where rowid=".$line->id; //Set to print on printer 1
  689. $db->query($sql);
  690. $order_receipt_printer1 .= '<tr><td class="left">';
  691. if ($line->fk_product) {
  692. $order_receipt_printer1 .= $line->product_label;
  693. } else {
  694. $order_receipt_printer1 .= $line->description;
  695. }
  696. $order_receipt_printer1 .= '</td><td class="right">'.$line->qty;
  697. if (!empty($line->array_options['options_order_notes'])) {
  698. $order_receipt_printer1 .= "<br>(".$line->array_options['options_order_notes'].")";
  699. }
  700. $order_receipt_printer1 .= '</td></tr>';
  701. }
  702. }
  703. if (($conf->global->TAKEPOS_PRINT_METHOD == "receiptprinter" || $conf->global->TAKEPOS_PRINT_METHOD == "takeposconnector") && $linestoprint > 0) {
  704. $invoice->fetch($placeid); //Reload object before send to printer
  705. $printer->orderprinter = 1;
  706. echo "<script>";
  707. echo "var orderprinter1esc='";
  708. $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
  709. echo "';</script>";
  710. }
  711. $sql = "UPDATE ".MAIN_DB_PREFIX."facturedet set special_code='4' where special_code='1' and fk_facture=".$invoice->id; // Set as printed
  712. $db->query($sql);
  713. $invoice->fetch($placeid); //Reload object after set lines as printed
  714. $linestoprint = 0;
  715. foreach ($invoice->lines as $line) {
  716. if ($line->special_code == "4") {
  717. continue;
  718. }
  719. $c = new Categorie($db);
  720. $existing = $c->containing($line->fk_product, Categorie::TYPE_PRODUCT, 'id');
  721. $result = array_intersect($catsprinter2, $existing);
  722. $count = count($result);
  723. if ($count > 0) {
  724. $linestoprint++;
  725. $sql = "UPDATE ".MAIN_DB_PREFIX."facturedet set special_code='2' where rowid=".$line->id; //Set to print on printer 2
  726. $db->query($sql);
  727. $order_receipt_printer2 .= '<tr>'.$line->product_label.'<td class="right">'.$line->qty;
  728. if (!empty($line->array_options['options_order_notes'])) {
  729. $order_receipt_printer2 .= "<br>(".$line->array_options['options_order_notes'].")";
  730. }
  731. $order_receipt_printer2 .= '</td></tr>';
  732. }
  733. }
  734. if (($conf->global->TAKEPOS_PRINT_METHOD == "receiptprinter" || $conf->global->TAKEPOS_PRINT_METHOD == "takeposconnector") && $linestoprint > 0) {
  735. $invoice->fetch($placeid); //Reload object before send to printer
  736. $printer->orderprinter = 2;
  737. echo "<script>";
  738. echo "var orderprinter2esc='";
  739. $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
  740. echo "';</script>";
  741. }
  742. $sql = "UPDATE ".MAIN_DB_PREFIX."facturedet set special_code='4' where special_code='2' and fk_facture=".$invoice->id; // Set as printed
  743. $db->query($sql);
  744. $invoice->fetch($placeid); //Reload object after set lines as printed
  745. $linestoprint = 0;
  746. foreach ($invoice->lines as $line) {
  747. if ($line->special_code == "4") {
  748. continue;
  749. }
  750. $c = new Categorie($db);
  751. $existing = $c->containing($line->fk_product, Categorie::TYPE_PRODUCT, 'id');
  752. $result = array_intersect($catsprinter3, $existing);
  753. $count = count($result);
  754. if ($count > 0) {
  755. $linestoprint++;
  756. $sql = "UPDATE ".MAIN_DB_PREFIX."facturedet set special_code='3' where rowid=".$line->id; //Set to print on printer 3
  757. $db->query($sql);
  758. $order_receipt_printer3 .= '<tr>'.$line->product_label.'<td class="right">'.$line->qty;
  759. if (!empty($line->array_options['options_order_notes'])) {
  760. $order_receipt_printer3 .= "<br>(".$line->array_options['options_order_notes'].")";
  761. }
  762. $order_receipt_printer3 .= '</td></tr>';
  763. }
  764. }
  765. if (($conf->global->TAKEPOS_PRINT_METHOD == "receiptprinter" || $conf->global->TAKEPOS_PRINT_METHOD == "takeposconnector") && $linestoprint > 0) {
  766. $invoice->fetch($placeid); //Reload object before send to printer
  767. $printer->orderprinter = 3;
  768. echo "<script>";
  769. echo "var orderprinter3esc='";
  770. $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
  771. echo "';</script>";
  772. }
  773. $sql = "UPDATE ".MAIN_DB_PREFIX."facturedet set special_code='4' where special_code='3' and fk_facture=".$invoice->id; // Set as printed
  774. $db->query($sql);
  775. $invoice->fetch($placeid); //Reload object after set lines as printed
  776. }
  777. $sectionwithinvoicelink = '';
  778. if ($action == "valid" || $action == "history" || $action == 'creditnote') {
  779. $sectionwithinvoicelink .= '<!-- Section with invoice link -->'."\n";
  780. $sectionwithinvoicelink .= '<span style="font-size:120%;" class="center">';
  781. $sectionwithinvoicelink .= $invoice->getNomUrl(1, '', 0, 0, '', 0, 0, -1, '_backoffice')." - ";
  782. $remaintopay = $invoice->getRemainToPay();
  783. if ($remaintopay > 0) {
  784. $sectionwithinvoicelink .= $langs->trans('RemainToPay').': <span class="amountremaintopay" style="font-size: unset">'.price($remaintopay, 1, $langs, 1, -1, -1, $conf->currency).'</span>';
  785. } else {
  786. if ($invoice->paye) {
  787. $sectionwithinvoicelink .= '<span class="amountpaymentcomplete" style="font-size: unset">'.$langs->trans("Paid").'</span>';
  788. } else {
  789. $sectionwithinvoicelink .= $langs->trans('BillShortStatusValidated');
  790. }
  791. }
  792. $sectionwithinvoicelink .= '</span><br>';
  793. if (getDolGlobalInt('TAKEPOS_PRINT_INVOICE_DOC_INSTEAD_OF_RECEIPT')) {
  794. $sectionwithinvoicelink .= ' <a target="_blank" class="button" href="' . DOL_URL_ROOT . '/document.php?token=' . newToken() . '&modulepart=facture&file=' . $invoice->ref . '/' . $invoice->ref . '.pdf">Invoice</a>';
  795. } elseif (getDolGlobalString('TAKEPOS_PRINT_METHOD') == "takeposconnector") {
  796. if (getDolGlobalString('TAKEPOS_PRINT_SERVER') && filter_var($conf->global->TAKEPOS_PRINT_SERVER, FILTER_VALIDATE_URL) == true) {
  797. $sectionwithinvoicelink .= ' <button id="buttonprint" type="button" onclick="TakeposConnector('.$placeid.')">'.$langs->trans('PrintTicket').'</button>';
  798. } else {
  799. $sectionwithinvoicelink .= ' <button id="buttonprint" type="button" onclick="TakeposPrinting('.$placeid.')">'.$langs->trans('PrintTicket').'</button>';
  800. }
  801. } elseif (getDolGlobalString('TAKEPOS_PRINT_METHOD') == "receiptprinter") {
  802. $sectionwithinvoicelink .= ' <button id="buttonprint" type="button" onclick="DolibarrTakeposPrinting('.$placeid.')">'.$langs->trans('PrintTicket').'</button>';
  803. } else {
  804. $sectionwithinvoicelink .= ' <button id="buttonprint" type="button" onclick="Print('.$placeid.')">'.$langs->trans('PrintTicket').'</button>';
  805. if (getDolGlobalString('TAKEPOS_PRINT_WITHOUT_DETAILS')) {
  806. $sectionwithinvoicelink .= ' <button id="buttonprint" type="button" onclick="PrintBox('.$placeid.', \'without_details\')">'.$langs->trans('PrintWithoutDetails').'</button>';
  807. }
  808. if (getDolGlobalString('TAKEPOS_GIFT_RECEIPT')) {
  809. $sectionwithinvoicelink .= ' <button id="buttonprint" type="button" onclick="Print('.$placeid.', 1)">'.$langs->trans('GiftReceipt').'</button>';
  810. }
  811. }
  812. if (getDolGlobalString('TAKEPOS_EMAIL_TEMPLATE_INVOICE') && $conf->global->TAKEPOS_EMAIL_TEMPLATE_INVOICE > 0) {
  813. $sectionwithinvoicelink .= ' <button id="buttonsend" type="button" onclick="SendTicket('.$placeid.')">'.$langs->trans('SendTicket').'</button>';
  814. }
  815. if ($remaintopay <= 0 && getDolGlobalString('TAKEPOS_AUTO_PRINT_TICKETS') && $action != "history") {
  816. $sectionwithinvoicelink .= '<script type="text/javascript">$("#buttonprint").click();</script>';
  817. }
  818. }
  819. }
  820. /*
  821. * View
  822. */
  823. $form = new Form($db);
  824. // llxHeader
  825. if ((getDolGlobalString('TAKEPOS_PHONE_BASIC_LAYOUT') == 1 && $conf->browser->layout == 'phone') || defined('INCLUDE_PHONEPAGE_FROM_PUBLIC_PAGE')) {
  826. $title = 'TakePOS - Dolibarr '.DOL_VERSION;
  827. if (!empty($conf->global->MAIN_APPLICATION_TITLE)) {
  828. $title = 'TakePOS - '.$conf->global->MAIN_APPLICATION_TITLE;
  829. }
  830. $head = '<meta name="apple-mobile-web-app-title" content="TakePOS"/>
  831. <meta name="apple-mobile-web-app-capable" content="yes">
  832. <meta name="mobile-web-app-capable" content="yes">
  833. <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no"/>';
  834. $arrayofcss = array(
  835. '/takepos/css/pos.css.php',
  836. );
  837. $arrayofjs = array('/takepos/js/jquery.colorbox-min.js');
  838. $disablejs = 0;
  839. $disablehead = 0;
  840. top_htmlhead($head, $title, $disablejs, $disablehead, $arrayofjs, $arrayofcss);
  841. print '<body>'."\n";
  842. } else {
  843. top_httphead('text/html', 1);
  844. }
  845. ?>
  846. <!-- invoice.php -->
  847. <script type="text/javascript">
  848. var selectedline=0;
  849. var selectedtext="";
  850. <?php if ($action=="valid") echo "var place=0;";?> // Set to default place after close sale
  851. var placeid=<?php echo ($placeid > 0 ? $placeid : 0); ?>;
  852. $(document).ready(function() {
  853. var idoflineadded = <?php echo (empty($idoflineadded) ? 0 : $idoflineadded); ?>;
  854. $('.posinvoiceline').click(function(){
  855. console.log("Click done on "+this.id);
  856. $('.posinvoiceline').removeClass("selected");
  857. $(this).addClass("selected");
  858. if (selectedline==this.id) return; // If is already selected
  859. else selectedline=this.id;
  860. selectedtext=$('#'+selectedline).find("td:first").html();
  861. <?php
  862. if (defined('INCLUDE_PHONEPAGE_FROM_PUBLIC_PAGE')) {
  863. print '$("#phonediv1").load("auto_order.php?action=editline&token='.newToken().'&placeid="+placeid+"&selectedline="+selectedline, function() {
  864. });';
  865. }
  866. ?>
  867. });
  868. /* Autoselect the line */
  869. if (idoflineadded > 0)
  870. {
  871. console.log("Auto select "+idoflineadded);
  872. $('.posinvoiceline#'+idoflineadded).click();
  873. }
  874. <?php
  875. if ($action == "order" && !empty($order_receipt_printer1)) {
  876. if (filter_var($conf->global->TAKEPOS_PRINT_SERVER, FILTER_VALIDATE_URL) == true) {
  877. ?>
  878. $.ajax({
  879. type: "POST",
  880. url: '<?php print $conf->global->TAKEPOS_PRINT_SERVER; ?>/printer/index.php',
  881. data: 'invoice='+orderprinter1esc
  882. });
  883. <?php
  884. } else {
  885. ?>
  886. $.ajax({
  887. type: "POST",
  888. url: 'http://<?php print $conf->global->TAKEPOS_PRINT_SERVER; ?>:8111/print',
  889. data: '<?php
  890. print $headerorder.$order_receipt_printer1.$footerorder; ?>'
  891. });
  892. <?php
  893. }
  894. }
  895. if ($action == "order" && !empty($order_receipt_printer2)) {
  896. if (filter_var($conf->global->TAKEPOS_PRINT_SERVER, FILTER_VALIDATE_URL) == true) {
  897. ?>
  898. $.ajax({
  899. type: "POST",
  900. url: '<?php print $conf->global->TAKEPOS_PRINT_SERVER; ?>/printer/index.php?printer=2',
  901. data: 'invoice='+orderprinter2esc
  902. });
  903. <?php
  904. } else {
  905. ?>
  906. $.ajax({
  907. type: "POST",
  908. url: 'http://<?php print $conf->global->TAKEPOS_PRINT_SERVER; ?>:8111/print2',
  909. data: '<?php
  910. print $headerorder.$order_receipt_printer2.$footerorder; ?>'
  911. });
  912. <?php
  913. }
  914. }
  915. if ($action == "order" && !empty($order_receipt_printer3)) {
  916. if (filter_var($conf->global->TAKEPOS_PRINT_SERVER, FILTER_VALIDATE_URL) == true) {
  917. ?>
  918. $.ajax({
  919. type: "POST",
  920. url: '<?php print $conf->global->TAKEPOS_PRINT_SERVER; ?>/printer/index.php?printer=3',
  921. data: 'invoice='+orderprinter3esc
  922. });
  923. <?php
  924. }
  925. }
  926. // Set focus to search field
  927. if ($action == "search" || $action == "valid") {
  928. ?>
  929. parent.setFocusOnSearchField();
  930. <?php
  931. }
  932. if ($action == "temp" && !empty($ticket_printer1)) {
  933. ?>
  934. $.ajax({
  935. type: "POST",
  936. url: 'http://<?php print $conf->global->TAKEPOS_PRINT_SERVER; ?>:8111/print',
  937. data: '<?php
  938. print $header_soc.$header_ticket.$body_ticket.$ticket_printer1.$ticket_total.$footer_ticket; ?>'
  939. });
  940. <?php
  941. }
  942. if ($action == "search") {
  943. ?>
  944. $('#search').focus();
  945. <?php
  946. }
  947. ?>
  948. });
  949. function SendTicket(id)
  950. {
  951. console.log("Open box to select the Print/Send form");
  952. $.colorbox({href:"send.php?facid="+id, width:"70%", height:"30%", transition:"none", iframe:"true", title:'<?php echo dol_escape_js($langs->trans("SendTicket")); ?>'});
  953. return true;
  954. }
  955. function PrintBox(id, action) {
  956. console.log("Open box before printing");
  957. $.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"); ?>"});
  958. return true;
  959. }
  960. function Print(id, gift){
  961. console.log("Call Print() to generate the receipt.");
  962. $.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")); ?>'});
  963. return true;
  964. }
  965. function TakeposPrinting(id){
  966. var receipt;
  967. console.log("TakeposPrinting" + id);
  968. $.get("receipt.php?facid="+id, function(data, status) {
  969. receipt=data.replace(/([^>\r\n]?)(\r\n|\n\r|\r|\n)/g, '');
  970. $.ajax({
  971. type: "POST",
  972. url: 'http://<?php print getDolGlobalString('TAKEPOS_PRINT_SERVER'); ?>:8111/print',
  973. data: receipt
  974. });
  975. });
  976. return true;
  977. }
  978. function TakeposConnector(id){
  979. console.log("TakeposConnector" + id);
  980. $.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) {
  981. $.ajax({
  982. type: "POST",
  983. url: '<?php print getDolGlobalString('TAKEPOS_PRINT_SERVER'); ?>/printer/index.php',
  984. data: 'invoice='+data
  985. });
  986. });
  987. return true;
  988. }
  989. function DolibarrTakeposPrinting(id) {
  990. console.log("DolibarrTakeposPrinting Printing invoice ticket " + id)
  991. $.ajax({
  992. type: "GET",
  993. data: { token: '<?php echo currentToken(); ?>' },
  994. url: "<?php print DOL_URL_ROOT.'/takepos/ajax/ajax.php?action=printinvoiceticket&token='.newToken().'&term='.urlencode(isset($_SESSION["takeposterminal"]) ? $_SESSION["takeposterminal"] : '').'&id='; ?>" + id,
  995. });
  996. return true;
  997. }
  998. function CreditNote() {
  999. $("#poslines").load("invoice.php?action=creditnote&token=<?php echo newToken() ?>&invoiceid="+placeid, function() { });
  1000. return true;
  1001. }
  1002. function SetNote() {
  1003. $("#poslines").load("invoice.php?action=addnote&token=<?php echo newToken() ?>&invoiceid="+placeid+"&idline="+selectedline, { "addnote": $("#textinput").val() });
  1004. return true;
  1005. }
  1006. $( document ).ready(function() {
  1007. console.log("Set customer info and sales in header placeid=<?php echo $placeid; ?> status=<?php echo $invoice->statut; ?>");
  1008. <?php
  1009. $s = $langs->trans("Customer");
  1010. if ($invoice->id > 0 && ($invoice->socid != getDolGlobalString($constforcompanyid))) {
  1011. $s = $soc->name;
  1012. }
  1013. ?>
  1014. $("#customerandsales").html('');
  1015. $("#shoppingcart").html('');
  1016. $("#customerandsales").append('<a class="valignmiddle tdoverflowmax125 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>');
  1017. <?php
  1018. $sql = "SELECT rowid, datec, ref FROM ".MAIN_DB_PREFIX."facture";
  1019. if (empty($conf->global->TAKEPOS_CAN_EDIT_IF_ALREADY_VALIDATED)) {
  1020. // By default, only invoices with a ref not already defined can in list of open invoice we can edit.
  1021. $sql .= " WHERE ref LIKE '(PROV-POS".$db->escape(isset($_SESSION["takeposterminal"]) ? $_SESSION["takeposterminal"] : '')."-0%' AND entity IN (".getEntity('invoice').")";
  1022. } else {
  1023. // If TAKEPOS_CAN_EDIT_IF_ALREADY_VALIDATED set, we show also draft invoice that already has a reference defined
  1024. $sql .= " WHERE pos_source = '".$db->escape($_SESSION["takeposterminal"])."'";
  1025. $sql .= " AND module_source = 'takepos'";
  1026. $sql .= " AND entity IN (".getEntity('invoice').")";
  1027. }
  1028. $sql .= $db->order('datec', 'ASC');
  1029. $resql = $db->query($sql);
  1030. if ($resql) {
  1031. $max_sale = 0;
  1032. while ($obj = $db->fetch_object($resql)) {
  1033. echo '$("#shoppingcart").append(\'';
  1034. 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=\\\'';
  1035. $num_sale = str_replace(")", "", str_replace("(PROV-POS".$_SESSION["takeposterminal"]."-", "", $obj->ref));
  1036. echo $num_sale;
  1037. if (str_replace("-", "", $num_sale) > $max_sale) {
  1038. $max_sale = str_replace("-", "", $num_sale);
  1039. }
  1040. echo '\\\'; invoiceid=\\\'';
  1041. echo $obj->rowid;
  1042. echo '\\\'; Refresh();">';
  1043. if ($placeid == $obj->rowid) {
  1044. echo '<span class="basketselected">';
  1045. } else {
  1046. echo '<span class="basketnotselected">';
  1047. }
  1048. echo '<span class="fa fa-shopping-cart paddingright"></span>'.dol_print_date($db->jdate($obj->datec), '%H:%M', 'tzuser');
  1049. echo '</span>';
  1050. echo '</a>\');';
  1051. }
  1052. echo '$("#shoppingcart").append(\'<a onclick="place=\\\'0-';
  1053. echo $max_sale + 1;
  1054. 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>\');';
  1055. } else {
  1056. dol_print_error($db);
  1057. }
  1058. $s = '';
  1059. $idwarehouse = 0;
  1060. $constantforkey = 'CASHDESK_NO_DECREASE_STOCK'. (isset($_SESSION["takeposterminal"]) ? $_SESSION["takeposterminal"] : '');
  1061. if (isModEnabled('stock')) {
  1062. if (getDolGlobalString("$constantforkey") != "1") {
  1063. $constantforkey = 'CASHDESK_ID_WAREHOUSE'. (isset($_SESSION["takeposterminal"]) ? $_SESSION["takeposterminal"] : '');
  1064. $idwarehouse = getDolGlobalString($constantforkey);
  1065. if ($idwarehouse > 0) {
  1066. $s = '<span class="small">';
  1067. $warehouse = new Entrepot($db);
  1068. $warehouse->fetch($idwarehouse);
  1069. $s .= '<span class="hideonsmartphone">'.$langs->trans("Warehouse").'<br></span>'.$warehouse->ref;
  1070. if ($warehouse->statut == Entrepot::STATUS_CLOSED) {
  1071. $s .= ' ('.$langs->trans("Closed").')';
  1072. }
  1073. $s .= '</span>';
  1074. print "$('#infowarehouse').html('".dol_escape_js($s)."');";
  1075. print '$("#infowarehouse").css("display", "inline-block");';
  1076. } else {
  1077. $s = '<span class="small hideonsmartphone">';
  1078. $s .= $langs->trans("StockChangeDisabled").'<br>'.$langs->trans("NoWarehouseDefinedForTerminal");
  1079. $s .= '</span>';
  1080. print "$('#infowarehouse').html('".dol_escape_js($s)."');";
  1081. if (!empty($conf->dol_optimize_smallscreen)) {
  1082. print '$("#infowarehouse").css("display", "none");';
  1083. }
  1084. }
  1085. } else {
  1086. $s = '<span class="small hideonsmartphone">'.$langs->trans("StockChangeDisabled").'</span>';
  1087. print "$('#infowarehouse').html('".dol_escape_js($s)."');";
  1088. if (!empty($conf->dol_optimize_smallscreen)) {
  1089. print '$("#infowarehouse").css("display", "none");';
  1090. }
  1091. }
  1092. }
  1093. // Module Adherent
  1094. $s = '';
  1095. if (isModEnabled('adherent') && $invoice->socid > 0 && $invoice->socid != $conf->global->$constforcompanyid) {
  1096. $s = '<span class="small">';
  1097. require_once DOL_DOCUMENT_ROOT.'/adherents/class/adherent.class.php';
  1098. $langs->load("members");
  1099. $s .= $langs->trans("Member").': ';
  1100. $adh = new Adherent($db);
  1101. $result = $adh->fetch('', '', $invoice->socid);
  1102. if ($result > 0) {
  1103. $adh->ref = $adh->getFullName($langs);
  1104. if (empty($adh->statut) || $adh->statut == Adherent::STATUS_EXCLUDED ) {
  1105. $s .= "<s>";
  1106. }
  1107. $s .= $adh->getFullName($langs);
  1108. $s .= ' - '.$adh->type;
  1109. if ($adh->datefin) {
  1110. $s .= '<br>'.$langs->trans("SubscriptionEndDate").': '.dol_print_date($adh->datefin, 'day');
  1111. if ($adh->hasDelay()) {
  1112. $s .= " ".img_warning($langs->trans("Late"));
  1113. }
  1114. } else {
  1115. $s .= '<br>'.$langs->trans("SubscriptionNotReceived");
  1116. if ($adh->statut > 0) {
  1117. $s .= " ".img_warning($langs->trans("Late")); // displays delay Pictogram only if not a draft and not terminated
  1118. }
  1119. }
  1120. if (empty($adh->statut) || $adh->statut == Adherent::STATUS_EXCLUDED) {
  1121. $s .= "</s>";
  1122. }
  1123. } else {
  1124. $s .= '<br>'.$langs->trans("ThirdpartyNotLinkedToMember");
  1125. }
  1126. $s .= '</span>';
  1127. }
  1128. ?>
  1129. $("#moreinfo").html('<?php print dol_escape_js($s); ?>');
  1130. });
  1131. <?php
  1132. if (!empty($conf->global->TAKEPOS_CUSTOMER_DISPLAY)) {
  1133. echo "function CustomerDisplay(){";
  1134. echo "var line1='".$CUSTOMER_DISPLAY_line1."'.substring(0,20);";
  1135. echo "line1=line1.padEnd(20);";
  1136. echo "var line2='".$CUSTOMER_DISPLAY_line2."'.substring(0,20);";
  1137. echo "line2=line2.padEnd(20);";
  1138. echo "$.ajax({
  1139. type: 'GET',
  1140. data: { text: line1+line2 },
  1141. url: '".getDolGlobalString('TAKEPOS_PRINT_SERVER')."/display/index.php',
  1142. });";
  1143. echo "}";
  1144. }
  1145. ?>
  1146. </script>
  1147. <?php
  1148. // Add again js for footer because this content is injected into index.php page so all init
  1149. // for tooltip and other js beautifiers must be reexecuted too.
  1150. if (!empty($conf->use_javascript_ajax)) {
  1151. print "\n".'<!-- Includes JS Footer of Dolibarr -->'."\n";
  1152. print '<script src="'.DOL_URL_ROOT.'/core/js/lib_foot.js.php?lang='.$langs->defaultlang.'"></script>'."\n";
  1153. }
  1154. print '<!-- invoice.php place='.(int) $place.' invoice='.$invoice->ref.' mobilepage='.(empty($mobilepage) ? '' : $mobilepage).' $_SESSION["basiclayout"]='.(empty($_SESSION["basiclayout"])?'':$_SESSION["basiclayout"]).' conf->global->TAKEPOS_BAR_RESTAURANT='.getDolGlobalString('TAKEPOS_BAR_RESTAURANT').' -->'."\n";
  1155. print '<div class="div-table-responsive-no-min invoice">';
  1156. print '<table id="tablelines" class="noborder noshadow postablelines centpercent">';
  1157. if ($sectionwithinvoicelink && ($mobilepage == "invoice" || $mobilepage == "")) {
  1158. if (!empty($conf->global->TAKEPOS_SHOW_HT)) {
  1159. print '<tr><td colspan="5">'.$sectionwithinvoicelink.'</td></tr>';
  1160. } else {
  1161. print '<tr><td colspan="4">'.$sectionwithinvoicelink.'</td></tr>';
  1162. }
  1163. }
  1164. print '<tr class="liste_titre nodrag nodrop">';
  1165. print '<td class="linecoldescription">';
  1166. // In phone version only show when it is invoice page
  1167. if (empty($mobilepage) || $mobilepage == "invoice") {
  1168. print '<input type="hidden" name="invoiceid" id="invoiceid" value="'.$invoice->id.'">';
  1169. }
  1170. if (getDolGlobalString('TAKEPOS_BAR_RESTAURANT')) {
  1171. $sql = "SELECT floor, label FROM ".MAIN_DB_PREFIX."takepos_floor_tables where rowid=".((int) $place);
  1172. $resql = $db->query($sql);
  1173. $obj = $db->fetch_object($resql);
  1174. if ($obj) {
  1175. $label = $obj->label;
  1176. $floor = $obj->floor;
  1177. }
  1178. if ($mobilepage == "invoice" || $mobilepage == "") {
  1179. // If not on smartphone version or if it is the invoice page
  1180. //print 'mobilepage='.$mobilepage;
  1181. print '<span class="opacitymedium">'.$langs->trans('Place')."</span> <b>".(empty($label) ? '?' : $label)."</b><br>";
  1182. print '<span class="opacitymedium">'.$langs->trans('Floor')."</span> <b>".(empty($floor) ? '?' : $floor)."</b>";
  1183. } elseif (defined('INCLUDE_PHONEPAGE_FROM_PUBLIC_PAGE')) {
  1184. print $mysoc->name;
  1185. } elseif ($mobilepage == "cats") {
  1186. print $langs->trans('Category');
  1187. } elseif ($mobilepage == "products") {
  1188. print $langs->trans('Label');
  1189. }
  1190. } else {
  1191. print $langs->trans("Products");
  1192. }
  1193. print '</td>';
  1194. // complete header by hook
  1195. $parameters=array();
  1196. $reshook=$hookmanager->executeHooks('completeTakePosInvoiceHeader', $parameters, $invoice, $action); // Note that $action and $object may have been modified by some hooks
  1197. if ($reshook < 0) setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
  1198. print $hookmanager->resPrint;
  1199. if (empty($_SESSION["basiclayout"]) || $_SESSION["basiclayout"] != 1) {
  1200. print '<td class="linecolqty right">'.$langs->trans('ReductionShort').'</td>';
  1201. print '<td class="linecolqty right">'.$langs->trans('Qty').'</td>';
  1202. if (getDolGlobalString('TAKEPOS_SHOW_HT')) {
  1203. print '<td class="linecolht right nowraponall">';
  1204. print '<span class="opacitymedium small">' . $langs->trans('TotalHTShort') . '</span><br>';
  1205. // In phone version only show when it is invoice page
  1206. if (empty($mobilepage) || $mobilepage == "invoice") {
  1207. 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>';
  1208. if (isModEnabled('multicurrency') && $_SESSION["takeposcustomercurrency"] != "" && $conf->currency != $_SESSION["takeposcustomercurrency"]) {
  1209. //Only show customer currency if multicurrency module is enabled, if currency selected and if this currency selected is not the same as main currency
  1210. include_once DOL_DOCUMENT_ROOT . '/multicurrency/class/multicurrency.class.php';
  1211. $multicurrency = new MultiCurrency($db);
  1212. $multicurrency->fetch(0, $_SESSION["takeposcustomercurrency"]);
  1213. 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>';
  1214. }
  1215. print '</td>';
  1216. }
  1217. print '</td>';
  1218. }
  1219. print '<td class="linecolht right nowraponall">';
  1220. print '<span class="opacitymedium small">'.$langs->trans('TotalTTCShort').'</span><br>';
  1221. // In phone version only show when it is invoice page
  1222. if (empty($mobilepage) || $mobilepage == "invoice") {
  1223. 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>';
  1224. if (isModEnabled('multicurrency') && !empty($_SESSION["takeposcustomercurrency"]) && $conf->currency != $_SESSION["takeposcustomercurrency"]) {
  1225. //Only show customer currency if multicurrency module is enabled, if currency selected and if this currency selected is not the same as main currency
  1226. include_once DOL_DOCUMENT_ROOT.'/multicurrency/class/multicurrency.class.php';
  1227. $multicurrency = new MultiCurrency($db);
  1228. $multicurrency->fetch(0, $_SESSION["takeposcustomercurrency"]);
  1229. 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>';
  1230. }
  1231. print '</td>';
  1232. }
  1233. print '</td>';
  1234. } elseif ($mobilepage == "invoice") {
  1235. print '<td class="linecolqty right">'.$langs->trans('Qty').'</td>';
  1236. }
  1237. print "</tr>\n";
  1238. if (!empty($_SESSION["basiclayout"]) && $_SESSION["basiclayout"] == 1) {
  1239. if ($mobilepage == "cats") {
  1240. require_once DOL_DOCUMENT_ROOT.'/categories/class/categorie.class.php';
  1241. $categorie = new Categorie($db);
  1242. $categories = $categorie->get_full_arbo('product');
  1243. $htmlforlines = '';
  1244. foreach ($categories as $row) {
  1245. if (defined('INCLUDE_PHONEPAGE_FROM_PUBLIC_PAGE')) {
  1246. $htmlforlines .= '<div class="leftcat';
  1247. } else {
  1248. $htmlforlines .= '<tr class="drag drop oddeven posinvoiceline';
  1249. }
  1250. $htmlforlines .= '" onclick="LoadProducts('.$row['id'].');">';
  1251. if (defined('INCLUDE_PHONEPAGE_FROM_PUBLIC_PAGE')) {
  1252. $htmlforlines .= '<img class="imgwrapper" width="33%" src="'.DOL_URL_ROOT.'/takepos/public/auto_order.php?genimg=cat&query=cat&id='.$row['id'].'"><br>';
  1253. } else {
  1254. $htmlforlines .= '<td class="left">';
  1255. }
  1256. $htmlforlines .= $row['label'];
  1257. if (defined('INCLUDE_PHONEPAGE_FROM_PUBLIC_PAGE')) {
  1258. $htmlforlines .= '</div>'."\n";
  1259. } else {
  1260. $htmlforlines .= '</td></tr>'."\n";
  1261. }
  1262. }
  1263. $htmlforlines .= '</table>';
  1264. $htmlforlines .= '</table>';
  1265. print $htmlforlines;
  1266. }
  1267. if ($mobilepage == "products") {
  1268. require_once DOL_DOCUMENT_ROOT.'/categories/class/categorie.class.php';
  1269. $object = new Categorie($db);
  1270. $catid = GETPOST('catid', 'int');
  1271. $result = $object->fetch($catid);
  1272. $prods = $object->getObjectsInCateg("product");
  1273. $htmlforlines = '';
  1274. foreach ($prods as $row) {
  1275. if (defined('INCLUDE_PHONEPAGE_FROM_PUBLIC_PAGE')) {
  1276. $htmlforlines .= '<div class="leftcat';
  1277. } else {
  1278. $htmlforlines .= '<tr class="drag drop oddeven posinvoiceline';
  1279. }
  1280. $htmlforlines .= '" onclick="AddProduct(\''.$place.'\', '.$row->id.')">';
  1281. if (defined('INCLUDE_PHONEPAGE_FROM_PUBLIC_PAGE')) {
  1282. $htmlforlines .= '<img class="imgwrapper" width="33%" src="'.DOL_URL_ROOT.'/takepos/public/auto_order.php?genimg=pro&query=pro&id='.$row->id.'"><br>';
  1283. $htmlforlines .= $row->label.' '.price($row->price_ttc, 1, $langs, 1, -1, -1, $conf->currency);
  1284. $htmlforlines .= '</div>'."\n";
  1285. } else {
  1286. $htmlforlines .= '<td class="left">';
  1287. $htmlforlines .= $row->label;
  1288. $htmlforlines .= '<div class="right">'.price($row->price_ttc, 1, $langs, 1, -1, -1, $conf->currency).'</div>';
  1289. $htmlforlines .= '</tr>'."\n";
  1290. }
  1291. }
  1292. $htmlforlines .= '</table>';
  1293. print $htmlforlines;
  1294. }
  1295. if ($mobilepage == "places") {
  1296. $sql = "SELECT rowid, entity, label, leftpos, toppos, floor FROM ".MAIN_DB_PREFIX."takepos_floor_tables";
  1297. $resql = $db->query($sql);
  1298. $rows = array();
  1299. $htmlforlines = '';
  1300. while ($row = $db->fetch_array($resql)) {
  1301. $rows[] = $row;
  1302. $htmlforlines .= '<tr class="drag drop oddeven posinvoiceline';
  1303. $htmlforlines .= '" onclick="LoadPlace(\''.$row['label'].'\')">';
  1304. $htmlforlines .= '<td class="left">';
  1305. $htmlforlines .= $row['label'];
  1306. $htmlforlines .= '</td>';
  1307. $htmlforlines .= '</tr>'."\n";
  1308. }
  1309. $htmlforlines .= '</table>';
  1310. print $htmlforlines;
  1311. }
  1312. }
  1313. if ($placeid > 0) {
  1314. //In Phone basic layout hide some content depends situation
  1315. if (!empty($_SESSION["basiclayout"]) && $_SESSION["basiclayout"] == 1 && $mobilepage != "invoice" && $action != "order") {
  1316. return;
  1317. }
  1318. if (is_array($invoice->lines) && count($invoice->lines)) {
  1319. print '<!-- invoice.php show lines of invoices -->'."\n";
  1320. $tmplines = array_reverse($invoice->lines);
  1321. $htmlsupplements = array();
  1322. foreach ($tmplines as $line) {
  1323. if ($line->fk_parent_line != false) {
  1324. $htmlsupplements[$line->fk_parent_line] .= '<tr class="drag drop oddeven posinvoiceline';
  1325. if ($line->special_code == "4") {
  1326. $htmlsupplements[$line->fk_parent_line] .= ' order';
  1327. }
  1328. $htmlsupplements[$line->fk_parent_line] .= '" id="'.$line->id.'"';
  1329. if ($line->special_code == "4") {
  1330. $htmlsupplements[$line->fk_parent_line] .= ' title="'.dol_escape_htmltag($langs->trans("AlreadyPrinted")).'"';
  1331. }
  1332. $htmlsupplements[$line->fk_parent_line] .= '>';
  1333. $htmlsupplements[$line->fk_parent_line] .= '<td class="left">';
  1334. $htmlsupplements[$line->fk_parent_line] .= img_picto('', 'rightarrow');
  1335. if ($line->product_label) {
  1336. $htmlsupplements[$line->fk_parent_line] .= $line->product_label;
  1337. }
  1338. if ($line->product_label && $line->desc) {
  1339. $htmlsupplements[$line->fk_parent_line] .= '<br>';
  1340. }
  1341. if ($line->product_label != $line->desc) {
  1342. $firstline = dolGetFirstLineOfText($line->desc);
  1343. if ($firstline != $line->desc) {
  1344. $htmlsupplements[$line->fk_parent_line] .= $form->textwithpicto(dolGetFirstLineOfText($line->desc), $line->desc);
  1345. } else {
  1346. $htmlsupplements[$line->fk_parent_line] .= $line->desc;
  1347. }
  1348. }
  1349. $htmlsupplements[$line->fk_parent_line] .= '</td>';
  1350. // complete line by hook
  1351. $parameters=array('line' => $line);
  1352. $reshook=$hookmanager->executeHooks('completeTakePosInvoiceParentLine', $parameters, $invoice, $action); // Note that $action and $object may have been modified by some hooks
  1353. if ($reshook < 0) setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
  1354. $htmlsupplements[$line->fk_parent_line] .= $hookmanager->resPrint;
  1355. if (empty($_SESSION["basiclayout"]) || $_SESSION["basiclayout"] != 1) {
  1356. $htmlsupplements[$line->fk_parent_line] .= '<td class="right">'.vatrate($line->remise_percent, true).'</td>';
  1357. $htmlsupplements[$line->fk_parent_line] .= '<td class="right">'.$line->qty.'</td>';
  1358. $htmlsupplements[$line->fk_parent_line] .= '<td class="right">'.price($line->total_ttc).'</td>';
  1359. }
  1360. $htmlsupplements[$line->fk_parent_line] .= '</tr>'."\n";
  1361. continue;
  1362. }
  1363. $htmlforlines = '';
  1364. $htmlforlines .= '<tr class="drag drop oddeven posinvoiceline';
  1365. if ($line->special_code == "4") {
  1366. $htmlforlines .= ' order';
  1367. }
  1368. $htmlforlines .= '" id="'.$line->id.'"';
  1369. if ($line->special_code == "4") {
  1370. $htmlforlines .= ' title="'.dol_escape_htmltag($langs->trans("AlreadyPrinted")).'"';
  1371. }
  1372. $htmlforlines .= '>';
  1373. $htmlforlines .= '<td class="left">';
  1374. if (!empty($_SESSION["basiclayout"]) && $_SESSION["basiclayout"] == 1) {
  1375. $htmlforlines .= '<span class="phoneqty">'.$line->qty."</span> x ";
  1376. }
  1377. if (isset($line->product_type)) {
  1378. if (empty($line->product_type)) {
  1379. $htmlforlines .= img_object('', 'product').' ';
  1380. } else {
  1381. $htmlforlines .= img_object('', 'service').' ';
  1382. }
  1383. }
  1384. if (empty($conf->global->TAKEPOS_SHOW_N_FIRST_LINES)) {
  1385. $tooltiptext = '';
  1386. if ($line->product_ref) {
  1387. $tooltiptext .= '<b>'.$langs->trans("Ref").'</b> : '.$line->product_ref.'<br>';
  1388. $tooltiptext .= '<b>'.$langs->trans("Label").'</b> : '.$line->product_label.'<br>';
  1389. if ($line->product_label != $line->desc) {
  1390. if ($line->desc) {
  1391. $tooltiptext .= '<br>';
  1392. }
  1393. $tooltiptext .= $line->desc;
  1394. }
  1395. }
  1396. if (getDolGlobalInt('TAKEPOS_SHOW_PRODUCT_REFERENCE') == 1) {
  1397. $htmlforlines .= $form->textwithpicto($line->product_label ? '<b>' . $line->product_ref . '</b> - ' . $line->product_label : dolGetFirstLineOfText($line->desc, 1), $tooltiptext);
  1398. } else {
  1399. $htmlforlines .= $form->textwithpicto($line->product_label ? $line->product_label : ($line->product_ref ? $line->product_ref : dolGetFirstLineOfText($line->desc, 1)), $tooltiptext);
  1400. }
  1401. } else {
  1402. if ($line->product_label) {
  1403. $htmlforlines .= $line->product_label;
  1404. }
  1405. if ($line->product_label != $line->desc) {
  1406. if ($line->product_label && $line->desc) {
  1407. $htmlforlines .= '<br>';
  1408. }
  1409. $firstline = dolGetFirstLineOfText($line->desc, $conf->global->TAKEPOS_SHOW_N_FIRST_LINES);
  1410. if ($firstline != $line->desc) {
  1411. $htmlforlines .= $form->textwithpicto(dolGetFirstLineOfText($line->desc), $line->desc);
  1412. } else {
  1413. $htmlforlines .= $line->desc;
  1414. }
  1415. }
  1416. }
  1417. if (!empty($line->array_options['options_order_notes'])) {
  1418. $htmlforlines .= "<br>(".$line->array_options['options_order_notes'].")";
  1419. }
  1420. if (!empty($_SESSION["basiclayout"]) && $_SESSION["basiclayout"] == 1) {
  1421. $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>';
  1422. }
  1423. if (empty($_SESSION["basiclayout"]) || $_SESSION["basiclayout"] != 1) {
  1424. $moreinfo = '';
  1425. $moreinfo .= $langs->transcountry("TotalHT", $mysoc->country_code).': '.price($line->total_ht);
  1426. if ($line->vat_src_code) {
  1427. $moreinfo .= '<br>'.$langs->trans("VATCode").': '.$line->vat_src_code;
  1428. }
  1429. $moreinfo .= '<br>'.$langs->transcountry("TotalVAT", $mysoc->country_code).': '.price($line->total_tva);
  1430. $moreinfo .= '<br>'.$langs->transcountry("TotalLT1", $mysoc->country_code).': '.price($line->total_localtax1);
  1431. $moreinfo .= '<br>'.$langs->transcountry("TotalLT2", $mysoc->country_code).': '.price($line->total_localtax2);
  1432. $moreinfo .= '<hr>';
  1433. $moreinfo .= $langs->transcountry("TotalTTC", $mysoc->country_code).': '.price($line->total_ttc);
  1434. //$moreinfo .= $langs->trans("TotalHT").': '.$line->total_ht;
  1435. if ($line->date_start || $line->date_end) {
  1436. $htmlforlines .= '<br><div class="clearboth nowraponall">'.get_date_range($line->date_start, $line->date_end).'</div>';
  1437. }
  1438. $htmlforlines .= '</td>';
  1439. // complete line by hook
  1440. $parameters=array('line' => $line);
  1441. $reshook=$hookmanager->executeHooks('completeTakePosInvoiceLine', $parameters, $invoice, $action); // Note that $action and $object may have been modified by some hooks
  1442. if ($reshook < 0) setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
  1443. $htmlforlines .= $hookmanager->resPrint;
  1444. $htmlforlines .= '<td class="right">'.vatrate($line->remise_percent, true).'</td>';
  1445. $htmlforlines .= '<td class="right">';
  1446. if (isModEnabled('stock') && !empty($user->rights->stock->mouvement->lire)) {
  1447. $constantforkey = 'CASHDESK_ID_WAREHOUSE'.$_SESSION["takeposterminal"];
  1448. if (!empty($conf->global->$constantforkey) && $line->fk_product > 0 && empty($conf->global->TAKEPOS_HIDE_STOCK_ON_LINE)) {
  1449. $sql = "SELECT e.rowid, e.ref, e.lieu, e.fk_parent, e.statut, ps.reel, ps.rowid as product_stock_id, p.pmp";
  1450. $sql .= " FROM ".MAIN_DB_PREFIX."entrepot as e,";
  1451. $sql .= " ".MAIN_DB_PREFIX."product_stock as ps";
  1452. $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."product as p ON p.rowid = ps.fk_product";
  1453. $sql .= " WHERE ps.reel != 0";
  1454. $sql .= " AND ps.fk_entrepot = ".((int) $conf->global->$constantforkey);
  1455. $sql .= " AND e.entity IN (".getEntity('stock').")";
  1456. $sql .= " AND ps.fk_product = ".((int) $line->fk_product);
  1457. $resql = $db->query($sql);
  1458. if ($resql) {
  1459. $obj = $db->fetch_object($resql);
  1460. $stock_real = price2num($obj->reel, 'MS');
  1461. $htmlforlines .= $line->qty;
  1462. if ($line->qty && $line->qty > $stock_real) {
  1463. $htmlforlines .= '<span style="color: var(--amountremaintopaycolor)">';
  1464. }
  1465. $htmlforlines .= ' <span class="posstocktoolow">('.$langs->trans("Stock").' '.$stock_real.')</span>';
  1466. if ($line->qty && $line->qty > $stock_real) {
  1467. $htmlforlines .= "</span>";
  1468. }
  1469. } else {
  1470. dol_print_error($db);
  1471. }
  1472. } else {
  1473. $htmlforlines .= $line->qty;
  1474. }
  1475. } else {
  1476. $htmlforlines .= $line->qty;
  1477. }
  1478. $htmlforlines .= '</td>';
  1479. if (getDolGlobalString('TAKEPOS_SHOW_HT')) {
  1480. $htmlforlines .= '<td class="right classfortooltip" title="'.$moreinfo.'">';
  1481. $htmlforlines .= price($line->total_ht, 1, '', 1, -1, -1, $conf->currency);
  1482. if (isModEnabled('multicurrency') && !empty($_SESSION["takeposcustomercurrency"]) && $conf->currency != $_SESSION["takeposcustomercurrency"]) {
  1483. //Only show customer currency if multicurrency module is enabled, if currency selected and if this currency selected is not the same as main currency
  1484. include_once DOL_DOCUMENT_ROOT.'/multicurrency/class/multicurrency.class.php';
  1485. $multicurrency = new MultiCurrency($db);
  1486. $multicurrency->fetch(0, $_SESSION["takeposcustomercurrency"]);
  1487. $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>';
  1488. }
  1489. $htmlforlines .= '</td>';
  1490. }
  1491. $htmlforlines .= '<td class="right classfortooltip" title="'.$moreinfo.'">';
  1492. $htmlforlines .= price($line->total_ttc, 1, '', 1, -1, -1, $conf->currency);
  1493. if (isModEnabled('multicurrency') && !empty($_SESSION["takeposcustomercurrency"]) && $conf->currency != $_SESSION["takeposcustomercurrency"]) {
  1494. //Only show customer currency if multicurrency module is enabled, if currency selected and if this currency selected is not the same as main currency
  1495. include_once DOL_DOCUMENT_ROOT.'/multicurrency/class/multicurrency.class.php';
  1496. $multicurrency = new MultiCurrency($db);
  1497. $multicurrency->fetch(0, $_SESSION["takeposcustomercurrency"]);
  1498. $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>';
  1499. }
  1500. $htmlforlines .= '</td>';
  1501. }
  1502. $htmlforlines .= '</tr>'."\n";
  1503. $htmlforlines .= empty($htmlsupplements[$line->id]) ? '' : $htmlsupplements[$line->id];
  1504. print $htmlforlines;
  1505. }
  1506. } else {
  1507. print '<tr class="drag drop oddeven"><td class="left"><span class="opacitymedium">'.$langs->trans("Empty").'</span></td><td></td><td></td><td></td>';
  1508. if (!empty($conf->global->TAKEPOS_SHOW_HT)) {
  1509. print '<td></td>';
  1510. }
  1511. print '</tr>';
  1512. }
  1513. } else { // No invoice generated yet
  1514. print '<tr class="drag drop oddeven"><td class="left"><span class="opacitymedium">'.$langs->trans("Empty").'</span></td><td></td><td></td><td></td>';
  1515. if (!empty($conf->global->TAKEPOS_SHOW_HT)) {
  1516. print '<td></td>';
  1517. }
  1518. print '</tr>';
  1519. }
  1520. print '</table>';
  1521. if (($action == "valid" || $action == "history") && $invoice->type != Facture::TYPE_CREDIT_NOTE && empty($conf->global->TAKEPOS_NO_CREDITNOTE)) {
  1522. print '<button id="buttonprint" type="button" onclick="ModalBox(\'ModalCreditNote\')">'.$langs->trans('CreateCreditNote').'</button>';
  1523. if (getDolGlobalInt('TAKEPOS_PRINT_INVOICE_DOC_INSTEAD_OF_RECEIPT')) {
  1524. print ' <a target="_blank" class="button" href="' . DOL_URL_ROOT . '/document.php?token=' . newToken() . '&modulepart=facture&file=' . $invoice->ref . '/' . $invoice->ref . '.pdf">Invoice</a>';
  1525. }
  1526. }
  1527. if ($action == "search") {
  1528. print '<center>
  1529. <input type="text" id="search" class="input-search-takepos" name="search" onkeyup="Search2(\'\', null);" style="width: 80%; font-size: 150%;" placeholder="'.dol_escape_htmltag($langs->trans('Search')).'">
  1530. </center>';
  1531. }
  1532. print '</div>';
  1533. // llxFooter
  1534. if ((getDolGlobalString('TAKEPOS_PHONE_BASIC_LAYOUT') == 1 && $conf->browser->layout == 'phone') || defined('INCLUDE_PHONEPAGE_FROM_PUBLIC_PAGE')) {
  1535. print '</body></html>';
  1536. }