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.

711 lines
24 KiB

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