You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

705 lines
24 KiB

4 years ago
  1. /*
  2. © 2020 Le Filament (<http://www.le-filament.com>)
  3. License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
  4. */
  5. odoo.define('vracoop_pos_free_balance_V2.container_balance', function (require) {
  6. "use strict";
  7. var chrome = require('point_of_sale.chrome');
  8. var gui = require('point_of_sale.gui');
  9. var models = require('point_of_sale.models');
  10. var screens = require('point_of_sale.screens');
  11. var popups = require('point_of_sale.popups');
  12. var container = require('pos_container.container');
  13. var models_and_db = require('pos_container.models_and_db');
  14. var core = require('web.core');
  15. var rpc = require('web.rpc');
  16. var utils = require('web.utils');
  17. var QWeb = core.qweb;
  18. var _t = core._t;
  19. var round_pr = utils.round_precision;
  20. var ConfirmPopupWidgetPesee = popups.extend({
  21. template: 'ConfirmPopupWidgetPesee',
  22. });
  23. gui.define_popup({name:'confirm-pesee', widget: ConfirmPopupWidgetPesee});
  24. // The initial screen that allows you to scan container
  25. var PresentationScreenWidget = screens.ScreenWidget.extend({
  26. template: 'PresentationScreenWidget',
  27. // Ignore products, discounts, and client barcodes
  28. // barcode_product_action: function(code){},
  29. barcode_discount_action: function(code){},
  30. barcode_client_action: function(code){},
  31. init: function(parent, options) {
  32. this._super(parent, options);
  33. this.transactions = [];
  34. this.editing = false;
  35. },
  36. // this method shows the screen and sets up all the widget related to this screen. Extend this method
  37. // if you want to alter the behavior of the screen.
  38. show: function(){
  39. this._super();
  40. var scale_screen = this.gui.screen_instances['balancescale'];
  41. scale_screen.$el.removeClass('oe_hidden');
  42. var screen = this.gui.screen_instances['products'];
  43. screen.$el.removeClass('oe_hidden');
  44. $("#pos-header-text-selec").removeClass('oe_hidden');
  45. $("#validation-bloc").addClass('oe_hidden');
  46. $("#pos-topheader-scale").addClass('oe_hidden');
  47. $("#pos-header-text-confirm").addClass('oe_hidden');
  48. },
  49. // this methods hides the screen. It's not a good place to put your cleanup stuff as it is called on the
  50. // POS initialization.
  51. hide: function(){
  52. this._super();
  53. var screen = this.gui.screen_instances['products'];
  54. screen.$el.addClass('oe_hidden');
  55. $("#pos-header-text-selec").addClass('oe_hidden');
  56. $("#pos-topheader-scale").addClass('oe_hidden');
  57. },
  58. });
  59. gui.define_screen({
  60. 'name': 'presentation',
  61. 'widget': PresentationScreenWidget,
  62. 'condition': function(){
  63. return this.pos.config.balance_id;
  64. },
  65. });
  66. // Screen confirmation de la pesée
  67. var ConfirmationScreen = screens.ScreenWidget.extend({
  68. template: 'ConfirmationScreen',
  69. next_screen: 'presentation',
  70. previous_screen: 'products',
  71. init: function(parent, options) {
  72. this._super(parent, options);
  73. },
  74. show: function(){
  75. this._super();
  76. var self = this;
  77. this.renderElement();
  78. var scale_screen = this.gui.screen_instances['balancescale'];
  79. scale_screen.$el.removeClass('oe_hidden');
  80. this.$('.next,.back-presentation').click(function(){
  81. self.gui.show_screen('presentation');
  82. });
  83. $("#pos-header-text-confirm").removeClass('oe_hidden');
  84. $("#validation-bloc").addClass('oe_hidden');
  85. $("#pos-topheader-scale").addClass('oe_hidden');
  86. },
  87. hide: function(){
  88. this._super();
  89. $("#pos-topheader-scale").addClass('oe_hidden');
  90. },
  91. get_product_name: function(){
  92. var product = this.gui.get_current_screen_param('product');
  93. return (product ? product.display_name : undefined) || 'Unnamed Product';
  94. },
  95. // get_product_price: function(){
  96. // var product = this.gui.get_current_screen_param('product');
  97. // return (product ? product.get_price(pricelist, 2) : 0) || 0;
  98. // },
  99. // get_product_uom: function(){
  100. // var product = this.gui.get_current_screen_param('product');
  101. // if(product){
  102. // return this.pos.units_by_id[product.uom_id[0]].name;
  103. // }else{
  104. // return '';
  105. // }
  106. // },
  107. });
  108. gui.define_screen({
  109. 'name': 'confirmation',
  110. 'widget': ConfirmationScreen,
  111. });
  112. // Add the FloorScreen to the GUI, and set it as the default screen
  113. chrome.Chrome.include({
  114. build_widgets: function(){
  115. this._super();
  116. if (this.pos.config.balance_id) {
  117. this.gui.set_startup_screen('presentation');
  118. }
  119. },
  120. });
  121. gui.Gui.include({
  122. show_saved_screen: function(order,options) {
  123. this._super();
  124. options = options || {};
  125. this.close_popup();
  126. this.show_screen(this.startup_screen);
  127. },
  128. });
  129. // We need to modify the OrderSelector to hide itself when we're on
  130. // the floor plan
  131. chrome.OrderSelectorWidget.include({
  132. hide: function(){
  133. this.$el.addClass('oe_invisible');
  134. },
  135. show: function(){
  136. this.$el.removeClass('oe_invisible');
  137. },
  138. renderElement: function(){
  139. var self = this;
  140. this._super();
  141. if (this.pos.config.balance_id) {
  142. if (this.pos.get_order()) {
  143. this.$el.removeClass('oe_invisible');
  144. } else {
  145. this.$el.addClass('oe_invisible');
  146. }
  147. }
  148. },
  149. });
  150. screens.ProductScreenWidget.include({
  151. previous_screen: 'presentation',
  152. hide: function(){
  153. this._super();
  154. $("#pos-header-text-prod").addClass('oe_hidden');
  155. $("#pos-topheader-scale").addClass('oe_hidden');
  156. var screen = this.gui.screen_instances['products'];
  157. // screen.$el.removeClass('oe_hidden');
  158. },
  159. show: function(){
  160. this._super();
  161. var self = this;
  162. this.product_categories_widget.reset_category();
  163. this.numpad.state.reset();
  164. this.$('.back').click(function(){
  165. self.gui.show_screen('presentation');
  166. });
  167. $("#pos-header-text-prod").removeClass('oe_hidden');
  168. $("#pos-topheader-scale").addClass('oe_hidden');
  169. var container = this.gui.get_current_screen_param('container');
  170. if (container) {
  171. this.pos.proxy.reset_tare();
  172. }
  173. },
  174. renderElement: function(){
  175. this._super();
  176. var self = this;
  177. this.$('.back').click(function () {
  178. self.gui.show_screen('presentation');
  179. });
  180. },
  181. click_product: function(product) {
  182. if (this.pos.config.is_balance_free){
  183. var order = this.pos.get_order();
  184. var selected_orderline = order.get_selected_orderline();
  185. if (product.to_weight && selected_orderline &&
  186. selected_orderline.product === this.pos.get_container_product()){
  187. var container = selected_orderline.get_container();
  188. this.gui.show_screen(
  189. 'balancescale',
  190. {product: product,
  191. container: container,
  192. old_orderline: selected_orderline});
  193. } else {
  194. this._super(product);
  195. }
  196. }
  197. else{
  198. this._super(product);
  199. }
  200. $("#validation-bloc").removeClass('oe_hidden');
  201. },
  202. close: function(){
  203. this._super();
  204. this.pos.proxy_queue.clear();
  205. },
  206. });
  207. screens.ScreenWidget.include({
  208. barcode_container_action: function(code){
  209. var self = this;
  210. if (self.pos.scan_container(code)) {
  211. // Vérfification: est-ce qu'un container vient d'être utilisé dans l'heure
  212. if (self.pos.scan_container_check(code)){
  213. var transaction = self.pos.scan_container_check(code);
  214. this.gui.show_popup('doublon-barcode',{
  215. title: _t('Contenu déjà enregistré récemment:'),
  216. transaction: transaction,
  217. confirm: function(){
  218. var transaction = self.pos.scan_container_check(code)
  219. self.delete_selected_transaction(transaction, code);
  220. self.gui.show_screen('products');
  221. },
  222. });
  223. } else {
  224. self.gui.show_screen('products');
  225. }
  226. } else {
  227. self.gui.show_screen('balancecontainerscale', {barcode: code.base_code});
  228. }
  229. },
  230. delete_selected_transaction: function(transaction, barcode){
  231. var self = this;
  232. if (!transaction.id){
  233. self.deleted_transaction(transaction.container_ean13)
  234. }
  235. else {
  236. rpc.query({
  237. model: 'pos.transaction',
  238. method: 'unlink',
  239. args: [transaction.id],
  240. }).then(function(){
  241. self.deleted_transaction(transaction.container_ean13);
  242. },function(err,ev){
  243. ev.preventDefault();
  244. var error_body = _t('Your Internet connection is probably down.');
  245. if (err.data) {
  246. var except = err.data;
  247. error_body = except.arguments && except.arguments[0] || except.message || error_body;
  248. }
  249. self.gui.show_popup('error',{
  250. 'title': _t('Error: Could not Save Changes'),
  251. 'body': error_body,
  252. });
  253. }
  254. );
  255. }
  256. },
  257. deleted_transaction: function(barcode){
  258. var self = this;
  259. this.pos.db.remove_transactions([barcode]);
  260. },
  261. });
  262. var BalanceScaleScreenWidget = screens.ScaleScreenWidget.extend({
  263. template: 'BalanceScaleScreenWidget',
  264. next_screen: 'confirmation',
  265. previous_screen: 'products',
  266. init: function(parent, options){
  267. this._super(parent, options);
  268. this.weight_container = 0;
  269. this.weight_brut = 0;
  270. this.weight = 0;
  271. },
  272. show: function(){
  273. // $("#validation-bloc").removeClass('oe_hidden');
  274. // this._super();
  275. var self = this;
  276. var queue = this.pos.proxy_queue;
  277. this.set_weight(0);
  278. this.renderElement();
  279. var container = this.gui.get_current_screen_param('container');
  280. queue.schedule(function () {
  281. return self.pos.proxy.reset_weight().then(function () {
  282. self.set_weight(0);
  283. self.set_price(0);
  284. });
  285. }, {duration: 500});
  286. // format price
  287. var price = this.format_price(this.get_product_price());
  288. if (container) {
  289. // format tare
  290. var tare = this.format_tare(container);
  291. queue.schedule(function () {
  292. return self.pos.proxy.scale_read_data_price_tare(price, tare).then(function (scale_answer) {
  293. self.set_weight(scale_answer.weight);
  294. self.set_price(scale_answer.price);
  295. if ((scale_answer.error === '30' || scale_answer.error === '31') && scale_answer.weight !== 0) {
  296. self.gui.show_screen(self.next_screen);
  297. // add product *after* switching screen to scroll properly
  298. self.order_product();
  299. self.pos.proxy.reset_tare();
  300. }
  301. });
  302. }, {duration: 500, repeat: true});
  303. } else {
  304. queue.schedule(function () {
  305. return self.pos.proxy.scale_read_data_price(price).then(function (scale_answer) {
  306. self.set_weight(scale_answer.weight);
  307. self.set_price(scale_answer.price);
  308. if ((scale_answer.error === '30' || scale_answer.error === '31') && scale_answer.weight !== 0) {
  309. self.gui.show_screen(self.next_screen);
  310. // add product *after* switching screen to scroll properly
  311. self.order_product();
  312. }
  313. });
  314. }, {duration: 500, repeat: true});
  315. }
  316. this._super();
  317. var self = this;
  318. this.$('.next,.add-transaction').click(function(){
  319. self.create_transaction();
  320. });
  321. $("#pos-topheader-scale").removeClass('oe_hidden');
  322. $("#pos-header-text-peser").removeClass('oe_hidden');
  323. },
  324. get_container: function(){
  325. return this.gui.get_current_screen_param('container');
  326. },
  327. set_weight: function(weight){
  328. var container = this.get_container();
  329. this.weight = weight;
  330. this.weight_container = container.weight;
  331. this.weight_brut = container.weight + this.weight;
  332. this.$('.weight').text(this.get_product_weight_string());
  333. this.$('.computed-price').text(this.get_computed_price_string());
  334. this.$('.weight-brut').text(this.get_product_weight_string_brut());
  335. },
  336. //////////////////////////////
  337. // Ajout fonction Toledo?
  338. set_price: function (price) {
  339. if (!price) {
  340. this.$('.computed-price').text(this.get_computed_price_string());
  341. } else {
  342. this.price = price;
  343. //this.$('.price').text(this.format_currency(price));
  344. this.$('.computed-price').text(this.format_currency(price));
  345. }
  346. },
  347. get_price: function () {
  348. return this.price;
  349. },
  350. format_tare: function (container) {
  351. var tare = (Math.abs(container.weight) * 1000).toString();
  352. tare = ("0000" + tare).slice(-4);
  353. return tare;
  354. },
  355. format_price: function (product_price) {
  356. var price = (product_price * 1000).toString();
  357. price = ("000000" + price).slice(-6);
  358. return price;
  359. },
  360. // FIN
  361. //////////////////////////////
  362. get_current_container_weight: function(){
  363. var container = this.get_container();
  364. if (container){
  365. return (this.weight_container || 0).toFixed(3) + ' kg';
  366. }
  367. else{
  368. ''
  369. }
  370. },
  371. get_current_container_name: function(){
  372. var container = this.get_container();
  373. if (container){
  374. return container.name;
  375. }
  376. else{
  377. ''
  378. }
  379. },
  380. get_product_weight_string_brut: function(){
  381. var product = this.get_product();
  382. var defaultstr = (this.weight + this.weight_container || 0).toFixed(3) + ' Kg';
  383. if(!product || !this.pos){
  384. return defaultstr;
  385. }
  386. var unit_id = product.uom_id;
  387. if(!unit_id){
  388. return defaultstr;
  389. }
  390. var unit = this.pos.units_by_id[unit_id[0]];
  391. var weight = round_pr(this.weight + this.weight_container || 0, unit.rounding);
  392. var weightstr = weight.toFixed(Math.ceil(Math.log(1.0/unit.rounding) / Math.log(10) ));
  393. weightstr += ' ' + unit.name;
  394. return weightstr;
  395. },
  396. hide: function(){
  397. this._super();
  398. $("#pos-topheader-scale").addClass('oe_hidden');
  399. $("#pos-header-text-peser").addClass('oe_hidden');
  400. },
  401. create_transaction: function(){
  402. var self = this;
  403. var fields = {};
  404. var container = this.get_container();
  405. var product = this.get_product();
  406. var qrcode = '';
  407. var ean13 = '';
  408. var ean13_verif = '';
  409. fields['qrcode'] = qrcode.concat('https://qr.mayam.fr/', container.barcode);
  410. fields['container_ean13'] = container.barcode;
  411. fields['product_id'] = this.get_product().id;
  412. // var product_id = (this.get_product().id).toString();
  413. var product_id = ("00000" + product.default_code.toString()).slice(-5);
  414. var weight_str = (this.weight * 1000).toString();
  415. weight_str = ("00000" + weight_str).slice(-5);
  416. ean13 = ean13.concat(26,product_id,weight_str,4);
  417. var weight_brut_str = (this.weight_brut * 1000).toString();
  418. weight_brut_str = ("00000" + weight_brut_str).slice(-5);
  419. ean13_verif = ean13_verif.concat(26,'00999',weight_brut_str,4);
  420. var ean13_digit = this.pos.barcode_reader.barcode_parser.sanitize_ean(ean13);
  421. var ean13_verif_digit = this.pos.barcode_reader.barcode_parser.sanitize_ean(ean13_verif);
  422. fields['ean13'] = ean13_digit;
  423. fields['ean13_verif'] = ean13_verif_digit;
  424. fields['balance_id'] = this.pos.get_balance_id();
  425. var today = new Date();
  426. var date = today.getFullYear() + '-' + (today.getMonth()+1) + '-' + today.getDate();
  427. var time = today.getHours() + ":" + today.getMinutes() + ":" + today.getSeconds();
  428. var date_time = date + ' ' + time;
  429. fields['write_date'] = date_time;
  430. fields['weight_net'] = this.weight;
  431. var pricelist = this._get_active_pricelist();
  432. fields['price_product'] = (product ? product.get_price(pricelist, this.weight) : 0) || 0;
  433. fields['price_net'] = fields['weight_net'] * fields['price_product'];
  434. fields.name = product.display_name;
  435. this.pos.push_transaction(fields).then(
  436. this.pushed_transaction(fields["ean13"])
  437. );
  438. },
  439. pushed_transaction: function(barcode){
  440. var self = this;
  441. var product = this.get_product();
  442. console.log(product);
  443. this.gui.show_screen('confirmation',{product: product});
  444. // self.gui.show_screen(self.next_screen);
  445. // self.gui.show_popup('confirm-pesee',{
  446. // 'title': _t('Merci'),
  447. // 'body': _t('La pesée est validée'),
  448. // confirm: function(){
  449. // self.gui.show_screen(self.next_screen);
  450. // },
  451. // });
  452. },
  453. });
  454. gui.define_screen({
  455. name:'balancescale',
  456. widget: BalanceScaleScreenWidget,
  457. });
  458. /*--------------------------------------*\
  459. | THE SCALE SCREEN FREE |
  460. | BALANCE CONTAINER |
  461. \*======================================*/
  462. // The free balance container scale screen
  463. // displays the weight of
  464. // a new container on the electronic scale.
  465. var BalanceContainerScaleScreenWidget = screens.ScaleScreenWidget.extend({
  466. template: 'BalanceContainerScaleScreenWidget',
  467. next_screen: 'presentation',
  468. previous_screen: 'presentation',
  469. init: function(parent, options){
  470. this._super(parent, options);
  471. },
  472. show: function(){
  473. var self = this;
  474. var queue = this.pos.proxy_queue;
  475. var priceStr = '001000'; // bizerba doesn't accept '000000' as unit price
  476. queue.schedule(function () {
  477. return self.pos.proxy.reset_weight().then(function () {
  478. self.set_weight(0);
  479. });
  480. }, {duration: 500});
  481. queue.schedule(function () {
  482. return self.pos.proxy.scale_read_data_price(priceStr).then(function (scale_answer) {
  483. self.set_weight(scale_answer.weight);
  484. if ((scale_answer.error === '30' || scale_answer.error === '31') && scale_answer.weight !== 0) {
  485. self.gui.show_screen(self.next_screen);
  486. self.create_container();
  487. }
  488. });
  489. }, {duration: 500, repeat: true});
  490. this._super();
  491. var self = this;
  492. this.$('.next,.add-container').click(function(){
  493. self.create_container();
  494. });
  495. if(this.pos.config.iface_vkeyboard && this.chrome.widget.keyboard){
  496. this.chrome.widget.keyboard.connect($(this.el.querySelector('.container-name input')));
  497. }
  498. $("#pos-header-text-peser").removeClass('oe_hidden');
  499. },
  500. hide: function(){
  501. this._super();
  502. $("#pos-header-text-peser").addClass('oe_hidden');
  503. },
  504. get_product: function(){
  505. return this.pos.get_container_product();
  506. },
  507. create_container: function(){
  508. var self = this;
  509. var fields = {};
  510. fields['weight'] = this.weight;
  511. fields.barcode = this.gui.get_current_screen_param('barcode') || false;
  512. fields.name = fields.name || _t('Container');
  513. this.pos.push_container(fields).then(
  514. this.pushed_container(fields["barcode"],fields)
  515. );
  516. },
  517. pushed_container: function(barcode,container){
  518. var self = this;
  519. var selected_order = this.pos.get_order();
  520. selected_order.add_container(container);
  521. self.gui.show_popup('confirm-pesee',{
  522. 'title': _t('Merci'),
  523. 'body': _t('La pesée est validée'),
  524. confirm: function(){
  525. self.gui.show_screen(self.next_screen);
  526. },
  527. });
  528. },
  529. close: function(){
  530. this._super();
  531. if (this.pos.config.iface_vkeyboard && this.chrome.widget.keyboard) {
  532. this.chrome.widget.keyboard.hide();
  533. }
  534. },
  535. });
  536. gui.define_screen({
  537. name:'balancecontainerscale',
  538. widget: BalanceContainerScaleScreenWidget,
  539. });
  540. var CheckBarcodePopupDoublon = popups.extend({
  541. template:'CheckBarcodePopupDoublon',
  542. show: function(options){
  543. var self = this;
  544. options = options || {};
  545. this.name = options.transaction.name ;
  546. this.weight_net = options.transaction.weight_net ;
  547. this.price_product = options.transaction.price_product.toFixed(2); ;
  548. this.price_net = options.transaction.price_net.toFixed(2);
  549. this._super(options);
  550. this.renderElement();
  551. },
  552. });
  553. gui.define_popup({name:'doublon-barcode', widget: CheckBarcodePopupDoublon});
  554. return {
  555. BalanceContainerScaleScreenWidget: BalanceContainerScaleScreenWidget,
  556. PresentationScreenWidget: PresentationScreenWidget,
  557. BalanceScaleScreenWidget: BalanceScaleScreenWidget,
  558. CheckBarcodePopupDoublon: CheckBarcodePopupDoublon,
  559. ConfirmPopupWidgetPesee: ConfirmPopupWidgetPesee,
  560. ConfirmationScreen: ConfirmationScreen,
  561. };
  562. });