From 28751419b1d3066820029e301e7c9d1bc493e803 Mon Sep 17 00:00:00 2001 From: Sylvain LE GAL Date: Tue, 19 May 2020 11:18:52 +0200 Subject: [PATCH 01/10] [FIX] minor things in selection fields --- pos_tare/models/barcode_rule.py | 4 ++-- pos_tare/models/pos_config.py | 14 +++++++------- pos_tare/static/src/js/pos_tare.js | 2 +- pos_tare/static/src/xml/pos_tare.xml | 4 ++-- 4 files changed, 12 insertions(+), 12 deletions(-) diff --git a/pos_tare/models/barcode_rule.py b/pos_tare/models/barcode_rule.py index fcdf3609..f48c1147 100644 --- a/pos_tare/models/barcode_rule.py +++ b/pos_tare/models/barcode_rule.py @@ -1,9 +1,9 @@ -from odoo import _, models, fields +from odoo import models, fields class BarcodeRule(models.Model): _inherit = 'barcode.rule' type = fields.Selection(selection_add=[ - ('tare', _('Tare')) + ('tare', 'Tare') ]) diff --git a/pos_tare/models/pos_config.py b/pos_tare/models/pos_config.py index 4ea1217e..a73eee51 100644 --- a/pos_tare/models/pos_config.py +++ b/pos_tare/models/pos_config.py @@ -5,14 +5,14 @@ class PosConfig(models.Model): _inherit = 'pos.config' iface_tare_method = fields.Selection([ - ('Manual', 'Input the tare manually'), - ('Barcode', 'Scan a barcode to set the tare'), - ('Both', 'Manual input and barcode'), + ('manual', 'Input the tare manually'), + ('barcode', 'Scan a barcode to set the tare'), + ('both', 'Manual input and barcode'), ], string='Tare input method', - default='Both', + default='both', help="Select tare method:\n" - "* 'Manual (the scale screen has an extra tare input field)';\n" - "* 'Barecode (scan a barcode to tare the selected order line)';\n" - "* 'Both manual input and barcode methods are enabled';", + "* 'manual' : the scale screen has an extra tare input field;\n" + "* 'barecode' : (scan a barcode to tare the selected order line;\n" + "* 'both' : manual input and barcode methods are enabled;", ) diff --git a/pos_tare/static/src/js/pos_tare.js b/pos_tare/static/src/js/pos_tare.js index 7b6af6da..ea107ed0 100644 --- a/pos_tare/static/src/js/pos_tare.js +++ b/pos_tare/static/src/js/pos_tare.js @@ -88,7 +88,7 @@ odoo.define('pos_barcode_tare.screens', function (require) { console.log("okok"); this._super(); - if (this.pos.config.iface_tare_method !== 'Manual') { + if (this.pos.config.iface_tare_method !== 'manual') { console.log("okokokok"); this.pos.barcode_reader.set_action_callback( diff --git a/pos_tare/static/src/xml/pos_tare.xml b/pos_tare/static/src/xml/pos_tare.xml index eaf21f56..dcf0d6d8 100644 --- a/pos_tare/static/src/xml/pos_tare.xml +++ b/pos_tare/static/src/xml/pos_tare.xml @@ -1,10 +1,10 @@ - + - +
Gross Weight
From 873b9dfa73ecf0a9772c7b274ee455fa4d8e2125 Mon Sep 17 00:00:00 2001 From: Sylvain LE GAL Date: Tue, 19 May 2020 13:47:47 +0200 Subject: [PATCH 02/10] [REF] split JS file into 3 files, following Odoo conventions --- pos_tare/__manifest__.py | 2 +- pos_tare/pos_tare.xml | 8 - pos_tare/static/src/js/models.js | 105 +++++++++++ pos_tare/static/src/js/pos_tare.js | 269 ----------------------------- pos_tare/static/src/js/screens.js | 129 ++++++++++++++ pos_tare/static/src/js/tools.js | 72 ++++++++ pos_tare/views/templates.xml | 10 ++ 7 files changed, 317 insertions(+), 278 deletions(-) delete mode 100644 pos_tare/pos_tare.xml create mode 100644 pos_tare/static/src/js/models.js delete mode 100644 pos_tare/static/src/js/pos_tare.js create mode 100644 pos_tare/static/src/js/screens.js create mode 100644 pos_tare/static/src/js/tools.js create mode 100644 pos_tare/views/templates.xml diff --git a/pos_tare/__manifest__.py b/pos_tare/__manifest__.py index 4b744476..e88d5062 100644 --- a/pos_tare/__manifest__.py +++ b/pos_tare/__manifest__.py @@ -12,7 +12,7 @@ 'depends': ['point_of_sale'], 'demo': ['demo/pos_tare_demo.xml'], 'data': [ - 'pos_tare.xml', + 'views/templates.xml', 'views/pos_config_view.xml', 'data/barcode_rule.xml', ], diff --git a/pos_tare/pos_tare.xml b/pos_tare/pos_tare.xml deleted file mode 100644 index 062f2a94..00000000 --- a/pos_tare/pos_tare.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - diff --git a/pos_tare/static/src/js/models.js b/pos_tare/static/src/js/models.js new file mode 100644 index 00000000..6ac96d35 --- /dev/null +++ b/pos_tare/static/src/js/models.js @@ -0,0 +1,105 @@ +odoo.define('pos_tare.models', function (require) { + + "use strict"; + var core = require('web.core'); + var models = require('point_of_sale.models'); + var pos_tare_tools = require('pos_tare.tools'); + + var _t = core._t; + + var _super_ = models.Orderline.prototype; + var OrderLineWithTare = models.Orderline.extend({ + + // ///////////////////////////// + // Overload Section + // ///////////////////////////// + initialize: function (session, attributes) { + this.tareQuantity = 0; + this.tareQuantityStr = '0'; + return _super_.initialize.call(this, session, attributes); + }, + + init_from_JSON: function (json) { + _super_.init_from_JSON.call(this, json); + this.tareQuantity = json.tareQuantity ||0; + this.tareQuantityStr = json.tareQuantityStr ||'0'; + }, + + clone: function () { + var orderline = _super_.clone.call(this); + orderline.tareQuantity = this.tareQuantity; + orderline.tareQuantityStr = this.tareQuantityStr; + return orderline; + }, + + export_as_JSON: function () { + var json = _super_.export_as_JSON.call(this); + json.tareQuantity = this.get_tare(); + json.tareQuantityStr = this.get_tare_str(); + return json; + }, + + export_for_printing: function () { + var result = _super_.export_for_printing.call(this); + result.tare_quantity = this.get_tare(); + return result; + }, + + // ///////////////////////////// + // Custom Section + // ///////////////////////////// + set_tare: function (quantity) { + this.order.assert_editable(); + + // Prevent to apply multiple times a tare to the same product. + if (this.get_tare() > 0) { + throw new RangeError(_.str.sprintf( + _t("The tare (%s) is already set for the " + + "product \"%s\". We can not re-apply a tare to this " + + "product."), + this.get_tare_str_with_unit(), this.product.display_name)); + } + + // We convert the tare that is always measured in kilogrammes into + // the unit of measure for this order line. + var kg = pos_tare_tools.get_unit(this.pos, "kg"); + var tare = parseFloat(quantity) || 0; + var unit = this.get_unit(); + var tare_in_product_uom = pos_tare_tools.convert_mass(tare, kg, unit); + var tare_in_product_uom_string = pos_tare_tools.format_tare(this.pos, + tare_in_product_uom, unit); + var net_quantity = this.get_quantity() - tare_in_product_uom; + // This method fails when the net weight is negative. + if (net_quantity <= 0) { + throw new RangeError(_.str.sprintf( + _t("The tare weight is %s %s, it's greater or equal to " + + "the product weight %s. We can not apply this tare."), + tare_in_product_uom_string, unit.name, + this.get_quantity_str_with_unit())); + } + // Update tare value. + this.tareQuantity = tare_in_product_uom; + this.tareQuantityStr = tare_in_product_uom_string; + // Update the quantity with the new weight net of tare quantity. + this.set_quantity(net_quantity); + this.trigger('change', this); + }, + + get_tare: function () { + return this.tareQuantity; + }, + + get_tare_str: function () { + return this.tareQuantityStr; + }, + + get_tare_str_with_unit: function () { + var unit = this.get_unit(); + return this.tareQuantityStr + ' ' + unit.name; + }, + + }); + + models.Orderline = OrderLineWithTare; + +}); diff --git a/pos_tare/static/src/js/pos_tare.js b/pos_tare/static/src/js/pos_tare.js deleted file mode 100644 index ea107ed0..00000000 --- a/pos_tare/static/src/js/pos_tare.js +++ /dev/null @@ -1,269 +0,0 @@ -odoo.define('pos_barcode_tare.screens', function (require) { - - "use strict"; - var core = require('web.core'); - var models = require('point_of_sale.models'); - var screens = require('point_of_sale.screens'); - var utils = require('web.utils'); - var field_utils = require('web.field_utils'); - - var _t = core._t; - var round_pr = utils.round_precision; - var round_di = utils.round_decimals; - - // Define functions used to do unit operation. - // Get unit search for unit based on unit name. - var get_unit = function (pos, unit_name) { - return pos.units.filter( - function (u) { - return u.name === unit_name; - })[0]; - }; - - // Convert mass using the reference UOM as pivot unit. - var convert_mass = function (mass, from_unit, to_unit) { - // There is no conversion from one category to another. - if (from_unit.category_id[0] !== to_unit.category_id[0]) { - throw new Error(_.str.sprintf( - _t("We can not cast a weight in %s into %s."), - from_unit.name, to_unit.name)); - } - // No need to convert as weights are measured in same unit. - if (from_unit.id === to_unit.id) { - return mass; - } - // Converts "from_unit" to reference unit of measure. - var result = mass; - if (from_unit.uom_type === "bigger") { - result /= from_unit.factor; - } else { - result *= from_unit.factor_inv; - } - // Converts reference unit of measure to "to_unit". - if (to_unit.uom_type === "bigger") { - result *= to_unit.factor; - } else { - result /= to_unit.factor_inv; - } - - if (to_unit.rounding) { - // Return the rounded result if needed. - return round_pr(result || 0, to_unit.rounding); - } - - return result || 0; - }; - - // Format the tare value. - var format_tare = function (pos, qty, unit) { - if (unit.rounding) { - var q = round_pr(qty, unit.rounding); - var decimals = pos.dp['Product Unit of Measure']; - return field_utils.format.float( - round_di(q, decimals), - {type: 'float', digits: [69, decimals]}); - } - return qty.toFixed(0); - }; - - // This configures read action for tare barcode. A tare barcode contains a - // fake product ID and the weight to be subtracted from the product in the - // latest order line. - screens.ScreenWidget.include( - { - barcode_tare_action: function (code) { - try { - var order = this.pos.get_order(); - var selected_order_line = order.get_selected_orderline(); - var tare_weight = code.value; - selected_order_line.set_tare(tare_weight); - } catch (error) { - var title = _t("We can not apply this tare barcode."); - var popup = {title: title, body: error.message}; - this.gui.show_popup('error', popup); - } - }, - // Setup the callback action for the "weight" barcodes. - show: function () { - - console.log("okok"); - this._super(); - if (this.pos.config.iface_tare_method !== 'manual') { - - console.log("okokokok"); - this.pos.barcode_reader.set_action_callback( - 'tare', - _.bind(this.barcode_tare_action, this)); - } - }, - }); - - screens.ScaleScreenWidget.include({ - - // ///////////////////////////// - // Overload Section - // ///////////////////////////// - - // Overload show function - // add an handler on the - show: function () { - this._super(); - this.tare = 0.0; - var self = this; - this.$('#input_weight_tare').keyup(function (event) { - self.onchange_tare(event); - }); - this.$('#input_weight_tare').focus(); - }, - - // Overload set_weight function - // We assume that the argument is now the gross weight - // we compute the net weight, depending on the tare and the gross weight - // then we call super, with the net weight - set_weight: function (gross_weight) { - this.gross_weight = gross_weight; - var net_weight = gross_weight - (this.tare || 0); - this.$('#container_weight_gross').text( - this.get_product_gross_weight_string()); - this._super(net_weight); - }, - - order_product: function () { - // TODO Set a warning, if the value is incorrect; - if (this.tare === undefined) { - this.gui.show_popup('error', { - 'title': _t('Incorrect Tare Value'), - 'body': _t('Please set a numeric value' + - ' in the tare field, or let empty.'), - }); - } else { - this._super(); - if (this.tare > 0.0) { - var order = this.pos.get_order(); - var orderline = order.get_last_orderline(); - orderline.set_tare(this.tare); - } - } - }, - - // ///////////////////////////// - // Custom Section - // ///////////////////////////// - get_product_gross_weight_string: function () { - var product = this.get_product(); - var defaultstr = (this.gross_weight || 0).toFixed(3) + ' Kg'; - if (!product || !this.pos) { - return defaultstr; - } - var unit_id = product.uom_id; - if (!unit_id) { - return defaultstr; - } - var unit = this.pos.units_by_id[unit_id[0]]; - var weight = round_pr(this.gross_weight || 0, unit.rounding); - var weightstr = weight.toFixed( - Math.ceil(Math.log(1.0/unit.rounding) / Math.log(10) )); - weightstr += ' ' + unit.name; - return weightstr; - }, - - onchange_tare: function () { - this.tare = this.check_sanitize_value('#input_weight_tare'); - this.set_weight(this.gross_weight); - }, - - check_sanitize_value: function (input_name) { - var res = this.$(input_name)[0].value.replace(',', '.').trim(); - if (isNaN(res)) { - this.$(input_name).css("background-color", "#F66"); - return undefined; - } - this.$(input_name).css("background-color", "#FFF"); - return parseFloat(res, 10); - }, - - }); - - // Update Orderline model - var _super_ = models.Orderline.prototype; - var OrderLineWithTare = models.Orderline.extend({ - initialize: function (session, attributes) { - this.tareQuantity = 0; - this.tareQuantityStr = '0'; - return _super_.initialize.call(this, session, attributes); - }, - init_from_JSON: function (json) { - _super_.init_from_JSON.call(this, json); - this.tareQuantity = json.tareQuantity ||0; - this.tareQuantityStr = json.tareQuantityStr ||'0'; - }, - set_tare: function (quantity) { - this.order.assert_editable(); - - // Prevent to apply multiple times a tare to the same product. - if (this.get_tare() > 0) { - throw new RangeError(_.str.sprintf( - _t("The tare (%s) is already set for the " + - "product \"%s\". We can not re-apply a tare to this " + - "product."), - this.get_tare_str_with_unit(), this.product.display_name)); - } - - // We convert the tare that is always measured in kilogrammes into - // the unit of measure for this order line. - var kg = get_unit(this.pos, "kg"); - var tare = parseFloat(quantity) || 0; - var unit = this.get_unit(); - var tare_in_product_uom = convert_mass(tare, kg, unit); - var tare_in_product_uom_string = format_tare(this.pos, - tare_in_product_uom, unit); - var net_quantity = this.get_quantity() - tare_in_product_uom; - // This method fails when the net weight is negative. - if (net_quantity <= 0) { - throw new RangeError(_.str.sprintf( - _t("The tare weight is %s %s, it's greater or equal to " + - "the product weight %s. We can not apply this tare."), - tare_in_product_uom_string, unit.name, - this.get_quantity_str_with_unit())); - } - // Update tare value. - this.tareQuantity = tare_in_product_uom; - this.tareQuantityStr = tare_in_product_uom_string; - // Update the quantity with the new weight net of tare quantity. - this.set_quantity(net_quantity); - this.trigger('change', this); - }, - get_tare: function () { - return this.tareQuantity; - }, - get_tare_str: function () { - return this.tareQuantityStr; - }, - get_tare_str_with_unit: function () { - var unit = this.get_unit(); - return this.tareQuantityStr + ' ' + unit.name; - }, - export_as_JSON: function () { - var json = _super_.export_as_JSON.call(this); - json.tareQuantity = this.get_tare(); - json.tareQuantityStr = this.get_tare_str(); - return json; - }, - clone: function () { - var orderline = _super_.clone.call(this); - orderline.tareQuantity = this.tareQuantity; - orderline.tareQuantityStr = this.tareQuantityStr; - return orderline; - }, - export_for_printing: function () { - var result = _super_.export_for_printing.call(this); - result.tare_quantity = this.get_tare(); - return result; - }, - }); - - models.Orderline = OrderLineWithTare; - - return {OrderLineWithTare: OrderLineWithTare, - get_unit: get_unit}; -}); diff --git a/pos_tare/static/src/js/screens.js b/pos_tare/static/src/js/screens.js new file mode 100644 index 00000000..d9bea361 --- /dev/null +++ b/pos_tare/static/src/js/screens.js @@ -0,0 +1,129 @@ +odoo.define('pos_tare.screens', function (require) { + + "use strict"; + var core = require('web.core'); + var screens = require('point_of_sale.screens'); + var utils = require('web.utils'); + + var _t = core._t; + var round_pr = utils.round_precision; + + // This configures read action for tare barcode. A tare barcode contains a + // fake product ID and the weight to be subtracted from the product in the + // latest order line. + screens.ScreenWidget.include( + { + barcode_tare_action: function (code) { + try { + var order = this.pos.get_order(); + var selected_order_line = order.get_selected_orderline(); + var tare_weight = code.value; + selected_order_line.set_tare(tare_weight); + } catch (error) { + var title = _t("We can not apply this tare barcode."); + var popup = {title: title, body: error.message}; + this.gui.show_popup('error', popup); + } + }, + // Setup the callback action for the "weight" barcodes. + show: function () { + + console.log("okok"); + this._super(); + if (this.pos.config.iface_tare_method !== 'manual') { + + console.log("okokokok"); + this.pos.barcode_reader.set_action_callback( + 'tare', + _.bind(this.barcode_tare_action, this)); + } + }, + }); + + screens.ScaleScreenWidget.include({ + + // ///////////////////////////// + // Overload Section + // ///////////////////////////// + + // Overload show function + // add an handler on the + show: function () { + this._super(); + this.tare = 0.0; + var self = this; + this.$('#input_weight_tare').keyup(function (event) { + self.onchange_tare(event); + }); + this.$('#input_weight_tare').focus(); + }, + + // Overload set_weight function + // We assume that the argument is now the gross weight + // we compute the net weight, depending on the tare and the gross weight + // then we call super, with the net weight + set_weight: function (gross_weight) { + this.gross_weight = gross_weight; + var net_weight = gross_weight - (this.tare || 0); + this.$('#container_weight_gross').text( + this.get_product_gross_weight_string()); + this._super(net_weight); + }, + + order_product: function () { + // TODO Set a warning, if the value is incorrect; + if (this.tare === undefined) { + this.gui.show_popup('error', { + 'title': _t('Incorrect Tare Value'), + 'body': _t('Please set a numeric value' + + ' in the tare field, or let empty.'), + }); + } else { + this._super(); + if (this.tare > 0.0) { + var order = this.pos.get_order(); + var orderline = order.get_last_orderline(); + orderline.set_tare(this.tare); + } + } + }, + + // ///////////////////////////// + // Custom Section + // ///////////////////////////// + get_product_gross_weight_string: function () { + var product = this.get_product(); + var defaultstr = (this.gross_weight || 0).toFixed(3) + ' Kg'; + if (!product || !this.pos) { + return defaultstr; + } + var unit_id = product.uom_id; + if (!unit_id) { + return defaultstr; + } + var unit = this.pos.units_by_id[unit_id[0]]; + var weight = round_pr(this.gross_weight || 0, unit.rounding); + var weightstr = weight.toFixed( + Math.ceil(Math.log(1.0/unit.rounding) / Math.log(10) )); + weightstr += ' ' + unit.name; + return weightstr; + }, + + onchange_tare: function () { + this.tare = this.check_sanitize_value('#input_weight_tare'); + this.set_weight(this.gross_weight); + }, + + check_sanitize_value: function (input_name) { + var res = this.$(input_name)[0].value.replace(',', '.').trim(); + if (isNaN(res)) { + this.$(input_name).css("background-color", "#F66"); + return undefined; + } + this.$(input_name).css("background-color", "#FFF"); + return parseFloat(res, 10); + }, + + }); + +}); diff --git a/pos_tare/static/src/js/tools.js b/pos_tare/static/src/js/tools.js new file mode 100644 index 00000000..fd597952 --- /dev/null +++ b/pos_tare/static/src/js/tools.js @@ -0,0 +1,72 @@ +odoo.define('pos_tare.tools', function (require) { + + "use strict"; + var core = require('web.core'); + var utils = require('web.utils'); + var field_utils = require('web.field_utils'); + + var _t = core._t; + var round_pr = utils.round_precision; + var round_di = utils.round_decimals; + + // Define functions used to do unit operation. + // Get unit search for unit based on unit name. + var get_unit = function (pos, unit_name) { + return pos.units.filter( + function (u) { + return u.name === unit_name; + })[0]; + }; + + // Convert mass using the reference UOM as pivot unit. + var convert_mass = function (mass, from_unit, to_unit) { + // There is no conversion from one category to another. + if (from_unit.category_id[0] !== to_unit.category_id[0]) { + throw new Error(_.str.sprintf( + _t("We can not cast a weight in %s into %s."), + from_unit.name, to_unit.name)); + } + // No need to convert as weights are measured in same unit. + if (from_unit.id === to_unit.id) { + return mass; + } + // Converts "from_unit" to reference unit of measure. + var result = mass; + if (from_unit.uom_type === "bigger") { + result /= from_unit.factor; + } else { + result *= from_unit.factor_inv; + } + // Converts reference unit of measure to "to_unit". + if (to_unit.uom_type === "bigger") { + result *= to_unit.factor; + } else { + result /= to_unit.factor_inv; + } + + if (to_unit.rounding) { + // Return the rounded result if needed. + return round_pr(result || 0, to_unit.rounding); + } + + return result || 0; + }; + + // Format the tare value. + var format_tare = function (pos, qty, unit) { + if (unit.rounding) { + var q = round_pr(qty, unit.rounding); + var decimals = pos.dp['Product Unit of Measure']; + return field_utils.format.float( + round_di(q, decimals), + {type: 'float', digits: [69, decimals]}); + } + return qty.toFixed(0); + }; + + return { + get_unit: get_unit, + convert_mass: convert_mass, + format_tare: format_tare, + }; +}); diff --git a/pos_tare/views/templates.xml b/pos_tare/views/templates.xml new file mode 100644 index 00000000..a8e0bc73 --- /dev/null +++ b/pos_tare/views/templates.xml @@ -0,0 +1,10 @@ + + + From a1c6ffd88dc74fb44161781e284383e6d01c1fc5 Mon Sep 17 00:00:00 2001 From: Sylvain LE GAL Date: Tue, 19 May 2020 13:49:14 +0200 Subject: [PATCH 03/10] [FIX] remove console.log --- pos_tare/static/src/js/screens.js | 4 ---- 1 file changed, 4 deletions(-) diff --git a/pos_tare/static/src/js/screens.js b/pos_tare/static/src/js/screens.js index d9bea361..a5fde269 100644 --- a/pos_tare/static/src/js/screens.js +++ b/pos_tare/static/src/js/screens.js @@ -27,12 +27,8 @@ odoo.define('pos_tare.screens', function (require) { }, // Setup the callback action for the "weight" barcodes. show: function () { - - console.log("okok"); this._super(); if (this.pos.config.iface_tare_method !== 'manual') { - - console.log("okokokok"); this.pos.barcode_reader.set_action_callback( 'tare', _.bind(this.barcode_tare_action, this)); From 8d4d7d56f4607364e6ae86bea56419ce10aba7f5 Mon Sep 17 00:00:00 2001 From: Sylvain LE GAL Date: Tue, 19 May 2020 14:04:23 +0200 Subject: [PATCH 04/10] [IMP+FIX] do not overwrite OrderLine qweb template. Add a t-jquery operation --- .../demo/{pos_tare_demo.xml => uom_uom.xml} | 0 pos_tare/static/src/xml/pos_tare.xml | 47 ++++--------------- 2 files changed, 10 insertions(+), 37 deletions(-) rename pos_tare/demo/{pos_tare_demo.xml => uom_uom.xml} (100%) diff --git a/pos_tare/demo/pos_tare_demo.xml b/pos_tare/demo/uom_uom.xml similarity index 100% rename from pos_tare/demo/pos_tare_demo.xml rename to pos_tare/demo/uom_uom.xml diff --git a/pos_tare/static/src/xml/pos_tare.xml b/pos_tare/static/src/xml/pos_tare.xml index dcf0d6d8..f3fe16dc 100644 --- a/pos_tare/static/src/xml/pos_tare.xml +++ b/pos_tare/static/src/xml/pos_tare.xml @@ -18,43 +18,16 @@
- -
  • - - - - - - -
      - -
    • - - - - - at - - / - -
    • -
      - -
    • - With a - - % - - discount -
    • -
      - -
    • - tare = -
    • -
      -
    -
  • + + + + +
  • + + Tare : +
  • +
    +
    From cc060cacbf88d3a478beb75320046ba142e20c5d Mon Sep 17 00:00:00 2001 From: Sylvain LE GAL Date: Tue, 19 May 2020 14:06:30 +0200 Subject: [PATCH 05/10] [REF] cosmetic changes --- pos_tare/__manifest__.py | 30 +++++++++++++++--------------- pos_tare/readme/CONTRIBUTORS.rst | 1 - pos_tare/views/pos_config_view.xml | 10 +++++----- 3 files changed, 20 insertions(+), 21 deletions(-) diff --git a/pos_tare/__manifest__.py b/pos_tare/__manifest__.py index e88d5062..285edc05 100644 --- a/pos_tare/__manifest__.py +++ b/pos_tare/__manifest__.py @@ -3,21 +3,21 @@ { "name": "Point Of Sale - Tare", "summary": "Manage Tare in Point Of Sale module", - 'version': '12.0.1.0.0', - 'category': 'Point of Sale', - 'author': "GRAP, Le Nid, Odoo Community Association (OCA)", - 'website': "https://github.com/OCA/pos", - 'license': 'AGPL-3', - 'maintainers': ['fkawala'], - 'depends': ['point_of_sale'], - 'demo': ['demo/pos_tare_demo.xml'], - 'data': [ - 'views/templates.xml', - 'views/pos_config_view.xml', - 'data/barcode_rule.xml', + "version": "12.0.1.0.0", + "category": "Point of Sale", + "author": "GRAP, Le Nid, Odoo Community Association (OCA)", + "website": "https://github.com/OCA/pos", + "license": "AGPL-3", + "maintainers": ["fkawala"], + "depends": ["point_of_sale"], + "demo": ["demo/uom_uom.xml"], + "data": [ + "views/templates.xml", + "views/pos_config_view.xml", + "data/barcode_rule.xml", ], - 'qweb': [ - 'static/src/xml/pos_tare.xml', + "qweb": [ + "static/src/xml/pos_tare.xml", ], - 'installable': True, + "installable": True, } diff --git a/pos_tare/readme/CONTRIBUTORS.rst b/pos_tare/readme/CONTRIBUTORS.rst index d75c661f..1434c95d 100644 --- a/pos_tare/readme/CONTRIBUTORS.rst +++ b/pos_tare/readme/CONTRIBUTORS.rst @@ -1,4 +1,3 @@ - Sylvain LE GAL (https://www.twitter.com/legalsylvain) - Le Nid - CoopITEasy - diff --git a/pos_tare/views/pos_config_view.xml b/pos_tare/views/pos_config_view.xml index 35f9df29..faf2f116 100644 --- a/pos_tare/views/pos_config_view.xml +++ b/pos_tare/views/pos_config_view.xml @@ -2,14 +2,14 @@ + - view.pos.config.form pos.config - -
    + +
    -
    - + + From 8765185e95302f6fda9468039e7fa809462254af Mon Sep 17 00:00:00 2001 From: Sylvain LE GAL Date: Tue, 19 May 2020 14:42:53 +0200 Subject: [PATCH 06/10] [ADD] tare field on pos.order.line model --- pos_tare/__manifest__.py | 3 ++- pos_tare/models/__init__.py | 1 + pos_tare/models/pos_order_line.py | 15 +++++++++++ pos_tare/static/src/js/models.js | 26 +++++++++---------- ...os_config_view.xml => view_pos_config.xml} | 0 pos_tare/views/view_pos_order.xml | 16 ++++++++++++ 6 files changed, 47 insertions(+), 14 deletions(-) create mode 100644 pos_tare/models/pos_order_line.py rename pos_tare/views/{pos_config_view.xml => view_pos_config.xml} (100%) create mode 100644 pos_tare/views/view_pos_order.xml diff --git a/pos_tare/__manifest__.py b/pos_tare/__manifest__.py index 285edc05..da757731 100644 --- a/pos_tare/__manifest__.py +++ b/pos_tare/__manifest__.py @@ -13,7 +13,8 @@ "demo": ["demo/uom_uom.xml"], "data": [ "views/templates.xml", - "views/pos_config_view.xml", + "views/view_pos_config.xml", + "views/view_pos_order.xml", "data/barcode_rule.xml", ], "qweb": [ diff --git a/pos_tare/models/__init__.py b/pos_tare/models/__init__.py index c81866fd..c6acc897 100644 --- a/pos_tare/models/__init__.py +++ b/pos_tare/models/__init__.py @@ -1,2 +1,3 @@ from . import pos_config +from . import pos_order_line from . import barcode_rule diff --git a/pos_tare/models/pos_order_line.py b/pos_tare/models/pos_order_line.py new file mode 100644 index 00000000..c86e6260 --- /dev/null +++ b/pos_tare/models/pos_order_line.py @@ -0,0 +1,15 @@ +# Copyright (C) 2020-Today: GRAP () +# @author: Sylvain LE GAL (https://twitter.com/legalsylvain) +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). + +from odoo import models, fields +from odoo.addons import decimal_precision as dp + + +class PosOrderLine(models.Model): + _inherit = "pos.order.line" + + tare = fields.Float( + string="Tare", + digits=dp.get_precision("Product Unit of Measure") + ) diff --git a/pos_tare/static/src/js/models.js b/pos_tare/static/src/js/models.js index 6ac96d35..f594ccd9 100644 --- a/pos_tare/static/src/js/models.js +++ b/pos_tare/static/src/js/models.js @@ -14,28 +14,28 @@ odoo.define('pos_tare.models', function (require) { // Overload Section // ///////////////////////////// initialize: function (session, attributes) { - this.tareQuantity = 0; - this.tareQuantityStr = '0'; + this.tare = 0; + this.tareStr = '0'; return _super_.initialize.call(this, session, attributes); }, init_from_JSON: function (json) { _super_.init_from_JSON.call(this, json); - this.tareQuantity = json.tareQuantity ||0; - this.tareQuantityStr = json.tareQuantityStr ||'0'; + this.tare = json.tare ||0; + this.tareStr = json.tareStr ||'0'; }, clone: function () { var orderline = _super_.clone.call(this); - orderline.tareQuantity = this.tareQuantity; - orderline.tareQuantityStr = this.tareQuantityStr; + orderline.tare = this.tare; + orderline.tareStr = this.tareStr; return orderline; }, export_as_JSON: function () { var json = _super_.export_as_JSON.call(this); - json.tareQuantity = this.get_tare(); - json.tareQuantityStr = this.get_tare_str(); + json.tare = this.get_tare(); + json.tareStr = this.get_tare_str(); return json; }, @@ -78,24 +78,24 @@ odoo.define('pos_tare.models', function (require) { this.get_quantity_str_with_unit())); } // Update tare value. - this.tareQuantity = tare_in_product_uom; - this.tareQuantityStr = tare_in_product_uom_string; + this.tare = tare_in_product_uom; + this.tareStr = tare_in_product_uom_string; // Update the quantity with the new weight net of tare quantity. this.set_quantity(net_quantity); this.trigger('change', this); }, get_tare: function () { - return this.tareQuantity; + return this.tare; }, get_tare_str: function () { - return this.tareQuantityStr; + return this.tareStr; }, get_tare_str_with_unit: function () { var unit = this.get_unit(); - return this.tareQuantityStr + ' ' + unit.name; + return this.tareStr + ' ' + unit.name; }, }); diff --git a/pos_tare/views/pos_config_view.xml b/pos_tare/views/view_pos_config.xml similarity index 100% rename from pos_tare/views/pos_config_view.xml rename to pos_tare/views/view_pos_config.xml diff --git a/pos_tare/views/view_pos_order.xml b/pos_tare/views/view_pos_order.xml new file mode 100644 index 00000000..7df2e933 --- /dev/null +++ b/pos_tare/views/view_pos_order.xml @@ -0,0 +1,16 @@ + + + + + + + pos.order + + + + + + + + + From 9be069878f8a4f153ede54e4ec648c44416dd393 Mon Sep 17 00:00:00 2001 From: Sylvain LE GAL Date: Tue, 19 May 2020 15:15:54 +0200 Subject: [PATCH 07/10] [IMP] make dynamic the UoM used for the tare. (setting in pos.config) --- pos_tare/__manifest__.py | 1 - pos_tare/demo/uom_uom.xml | 10 ---------- pos_tare/models/pos_config.py | 14 +++++++++++++- pos_tare/static/src/js/models.js | 12 ++++++------ pos_tare/static/src/js/tools.js | 10 ---------- pos_tare/views/view_pos_config.xml | 13 +++++++++++++ 6 files changed, 32 insertions(+), 28 deletions(-) delete mode 100644 pos_tare/demo/uom_uom.xml diff --git a/pos_tare/__manifest__.py b/pos_tare/__manifest__.py index da757731..7c7ca29d 100644 --- a/pos_tare/__manifest__.py +++ b/pos_tare/__manifest__.py @@ -10,7 +10,6 @@ "license": "AGPL-3", "maintainers": ["fkawala"], "depends": ["point_of_sale"], - "demo": ["demo/uom_uom.xml"], "data": [ "views/templates.xml", "views/view_pos_config.xml", diff --git a/pos_tare/demo/uom_uom.xml b/pos_tare/demo/uom_uom.xml deleted file mode 100644 index da5fe482..00000000 --- a/pos_tare/demo/uom_uom.xml +++ /dev/null @@ -1,10 +0,0 @@ - - - - - Kg - - - bigger - - diff --git a/pos_tare/models/pos_config.py b/pos_tare/models/pos_config.py index a73eee51..01595485 100644 --- a/pos_tare/models/pos_config.py +++ b/pos_tare/models/pos_config.py @@ -1,4 +1,4 @@ -from odoo import models, fields +from odoo import api, models, fields class PosConfig(models.Model): @@ -11,8 +11,20 @@ class PosConfig(models.Model): ], string='Tare input method', default='both', + required=True, help="Select tare method:\n" "* 'manual' : the scale screen has an extra tare input field;\n" "* 'barecode' : (scan a barcode to tare the selected order line;\n" "* 'both' : manual input and barcode methods are enabled;", ) + + iface_tare_uom_id = fields.Many2one( + string="Unit of Measure of the tare", + comodel_name="uom.uom", + default=lambda s: s._default_iface_tare_uom_id(), + required=True, + ) + + @api.model + def _default_iface_tare_uom_id(self): + return self.env.ref("uom.product_uom_kgm") diff --git a/pos_tare/static/src/js/models.js b/pos_tare/static/src/js/models.js index f594ccd9..36eacebd 100644 --- a/pos_tare/static/src/js/models.js +++ b/pos_tare/static/src/js/models.js @@ -60,21 +60,21 @@ odoo.define('pos_tare.models', function (require) { this.get_tare_str_with_unit(), this.product.display_name)); } - // We convert the tare that is always measured in kilogrammes into + // We convert the tare that is always measured in the same UoM into // the unit of measure for this order line. - var kg = pos_tare_tools.get_unit(this.pos, "kg"); + var tare_unit = this.pos.units_by_id[this.pos.config.iface_tare_uom_id[0]]; var tare = parseFloat(quantity) || 0; - var unit = this.get_unit(); - var tare_in_product_uom = pos_tare_tools.convert_mass(tare, kg, unit); + var line_unit = this.get_unit(); + var tare_in_product_uom = pos_tare_tools.convert_mass(tare, tare_unit, line_unit); var tare_in_product_uom_string = pos_tare_tools.format_tare(this.pos, - tare_in_product_uom, unit); + tare_in_product_uom, line_unit); var net_quantity = this.get_quantity() - tare_in_product_uom; // This method fails when the net weight is negative. if (net_quantity <= 0) { throw new RangeError(_.str.sprintf( _t("The tare weight is %s %s, it's greater or equal to " + "the product weight %s. We can not apply this tare."), - tare_in_product_uom_string, unit.name, + tare_in_product_uom_string, line_unit.name, this.get_quantity_str_with_unit())); } // Update tare value. diff --git a/pos_tare/static/src/js/tools.js b/pos_tare/static/src/js/tools.js index fd597952..e1c349d9 100644 --- a/pos_tare/static/src/js/tools.js +++ b/pos_tare/static/src/js/tools.js @@ -9,15 +9,6 @@ odoo.define('pos_tare.tools', function (require) { var round_pr = utils.round_precision; var round_di = utils.round_decimals; - // Define functions used to do unit operation. - // Get unit search for unit based on unit name. - var get_unit = function (pos, unit_name) { - return pos.units.filter( - function (u) { - return u.name === unit_name; - })[0]; - }; - // Convert mass using the reference UOM as pivot unit. var convert_mass = function (mass, from_unit, to_unit) { // There is no conversion from one category to another. @@ -65,7 +56,6 @@ odoo.define('pos_tare.tools', function (require) { }; return { - get_unit: get_unit, convert_mass: convert_mass, format_tare: format_tare, }; diff --git a/pos_tare/views/view_pos_config.xml b/pos_tare/views/view_pos_config.xml index faf2f116..8e6e667a 100644 --- a/pos_tare/views/view_pos_config.xml +++ b/pos_tare/views/view_pos_config.xml @@ -22,6 +22,19 @@
    +
    +
    +
    +
    From 424b110eb048861bb47d95a14e576b46757eed63 Mon Sep 17 00:00:00 2001 From: Sylvain LE GAL Date: Tue, 19 May 2020 15:23:22 +0200 Subject: [PATCH 08/10] [FIX] remove tareStr that was generating warning in Odoo Logs --- pos_tare/static/src/js/models.js | 16 ++++++---------- pos_tare/static/src/xml/pos_tare.xml | 2 +- 2 files changed, 7 insertions(+), 11 deletions(-) diff --git a/pos_tare/static/src/js/models.js b/pos_tare/static/src/js/models.js index 36eacebd..31a66844 100644 --- a/pos_tare/static/src/js/models.js +++ b/pos_tare/static/src/js/models.js @@ -15,27 +15,23 @@ odoo.define('pos_tare.models', function (require) { // ///////////////////////////// initialize: function (session, attributes) { this.tare = 0; - this.tareStr = '0'; return _super_.initialize.call(this, session, attributes); }, init_from_JSON: function (json) { _super_.init_from_JSON.call(this, json); this.tare = json.tare ||0; - this.tareStr = json.tareStr ||'0'; }, clone: function () { var orderline = _super_.clone.call(this); orderline.tare = this.tare; - orderline.tareStr = this.tareStr; return orderline; }, export_as_JSON: function () { var json = _super_.export_as_JSON.call(this); json.tare = this.get_tare(); - json.tareStr = this.get_tare_str(); return json; }, @@ -79,7 +75,6 @@ odoo.define('pos_tare.models', function (require) { } // Update tare value. this.tare = tare_in_product_uom; - this.tareStr = tare_in_product_uom_string; // Update the quantity with the new weight net of tare quantity. this.set_quantity(net_quantity); this.trigger('change', this); @@ -89,13 +84,14 @@ odoo.define('pos_tare.models', function (require) { return this.tare; }, - get_tare_str: function () { - return this.tareStr; - }, - get_tare_str_with_unit: function () { var unit = this.get_unit(); - return this.tareStr + ' ' + unit.name; + var tare_str = pos_tare_tools.format_tare( + this.pos, + this.tare, + this.get_unit(), + ); + return tare_str + ' ' + unit.name; }, }); diff --git a/pos_tare/static/src/xml/pos_tare.xml b/pos_tare/static/src/xml/pos_tare.xml index f3fe16dc..34dc8e32 100644 --- a/pos_tare/static/src/xml/pos_tare.xml +++ b/pos_tare/static/src/xml/pos_tare.xml @@ -21,7 +21,7 @@ - +
  • Tare : From 96a5d6e6e78eee218053cb443cc253a125498611 Mon Sep 17 00:00:00 2001 From: Sylvain LE GAL Date: Tue, 19 May 2020 16:40:35 +0200 Subject: [PATCH 09/10] [FIX] do not make a substraction when call set_tare in the ScaleScreen. (otherwise, the tare is reduced two times). [ADD] possibility to set manually the gross weight, if the scale doesn't work --- pos_tare/models/pos_config.py | 21 +++++++++++++++------ pos_tare/static/src/js/models.js | 25 ++++++++++++++----------- pos_tare/static/src/js/screens.js | 19 ++++++++++++++++--- pos_tare/static/src/xml/pos_tare.xml | 14 ++++++++++++-- pos_tare/views/view_pos_config.xml | 15 ++++++++++++++- 5 files changed, 71 insertions(+), 23 deletions(-) diff --git a/pos_tare/models/pos_config.py b/pos_tare/models/pos_config.py index 01595485..68e9bf56 100644 --- a/pos_tare/models/pos_config.py +++ b/pos_tare/models/pos_config.py @@ -2,15 +2,15 @@ from odoo import api, models, fields class PosConfig(models.Model): - _inherit = 'pos.config' + _inherit = "pos.config" iface_tare_method = fields.Selection([ - ('manual', 'Input the tare manually'), - ('barcode', 'Scan a barcode to set the tare'), - ('both', 'Manual input and barcode'), + ("manual", "Input the tare manually"), + ("barcode", "Scan a barcode to set the tare"), + ("both", "Manual input and barcode"), ], - string='Tare input method', - default='both', + string="Tare Input Method", + default="both", required=True, help="Select tare method:\n" "* 'manual' : the scale screen has an extra tare input field;\n" @@ -18,6 +18,15 @@ class PosConfig(models.Model): "* 'both' : manual input and barcode methods are enabled;", ) + iface_gross_weight_method = fields.Selection([ + ("manual", "Input the Gross Weight manually"), + ("scale", "Input Gross Weight via Scale") + ], + string="Gross Weight Input Method", + default="scale", + required=True, + ) + iface_tare_uom_id = fields.Many2one( string="Unit of Measure of the tare", comodel_name="uom.uom", diff --git a/pos_tare/static/src/js/models.js b/pos_tare/static/src/js/models.js index 31a66844..2c73c792 100644 --- a/pos_tare/static/src/js/models.js +++ b/pos_tare/static/src/js/models.js @@ -44,7 +44,7 @@ odoo.define('pos_tare.models', function (require) { // ///////////////////////////// // Custom Section // ///////////////////////////// - set_tare: function (quantity) { + set_tare: function (quantity, update_net_weight) { this.order.assert_editable(); // Prevent to apply multiple times a tare to the same product. @@ -64,20 +64,23 @@ odoo.define('pos_tare.models', function (require) { var tare_in_product_uom = pos_tare_tools.convert_mass(tare, tare_unit, line_unit); var tare_in_product_uom_string = pos_tare_tools.format_tare(this.pos, tare_in_product_uom, line_unit); - var net_quantity = this.get_quantity() - tare_in_product_uom; - // This method fails when the net weight is negative. - if (net_quantity <= 0) { - throw new RangeError(_.str.sprintf( - _t("The tare weight is %s %s, it's greater or equal to " + - "the product weight %s. We can not apply this tare."), - tare_in_product_uom_string, line_unit.name, - this.get_quantity_str_with_unit())); + if (update_net_weight) { + var net_quantity = this.get_quantity() - tare_in_product_uom; + // This method fails when the net weight is negative. + if (net_quantity <= 0) { + throw new RangeError(_.str.sprintf( + _t("The tare weight is %s %s, it's greater or equal to " + + "the product weight %s. We can not apply this tare."), + tare_in_product_uom_string, line_unit.name, + this.get_quantity_str_with_unit())); + } + // Update the quantity with the new weight net of tare quantity. + this.set_quantity(net_quantity); } // Update tare value. this.tare = tare_in_product_uom; - // Update the quantity with the new weight net of tare quantity. - this.set_quantity(net_quantity); this.trigger('change', this); + }, get_tare: function () { diff --git a/pos_tare/static/src/js/screens.js b/pos_tare/static/src/js/screens.js index a5fde269..38ba1321 100644 --- a/pos_tare/static/src/js/screens.js +++ b/pos_tare/static/src/js/screens.js @@ -18,7 +18,7 @@ odoo.define('pos_tare.screens', function (require) { var order = this.pos.get_order(); var selected_order_line = order.get_selected_orderline(); var tare_weight = code.value; - selected_order_line.set_tare(tare_weight); + selected_order_line.set_tare(tare_weight, true); } catch (error) { var title = _t("We can not apply this tare barcode."); var popup = {title: title, body: error.message}; @@ -51,7 +51,15 @@ odoo.define('pos_tare.screens', function (require) { this.$('#input_weight_tare').keyup(function (event) { self.onchange_tare(event); }); - this.$('#input_weight_tare').focus(); + this.$('#input_gross_weight').keyup(function (event) { + self.onchange_gross_weight(event); + }); + if (this.pos.config.iface_gross_weight_method === 'scale') { + this.$('#input_weight_tare').focus(); + } else{ + this.pos.proxy_queue.clear(); + this.$('#input_gross_weight').focus(); + } }, // Overload set_weight function @@ -79,7 +87,7 @@ odoo.define('pos_tare.screens', function (require) { if (this.tare > 0.0) { var order = this.pos.get_order(); var orderline = order.get_last_orderline(); - orderline.set_tare(this.tare); + orderline.set_tare(this.tare, false); } } }, @@ -110,6 +118,11 @@ odoo.define('pos_tare.screens', function (require) { this.set_weight(this.gross_weight); }, + onchange_gross_weight: function () { + var gross_weight = this.check_sanitize_value('#input_gross_weight'); + this.set_weight(gross_weight); + }, + check_sanitize_value: function (input_name) { var res = this.$(input_name)[0].value.replace(',', '.').trim(); if (isNaN(res)) { diff --git a/pos_tare/static/src/xml/pos_tare.xml b/pos_tare/static/src/xml/pos_tare.xml index 34dc8e32..af3edb28 100644 --- a/pos_tare/static/src/xml/pos_tare.xml +++ b/pos_tare/static/src/xml/pos_tare.xml @@ -8,12 +8,22 @@
    Gross Weight
    -
    + +
    + + +
    + + +
    +
    Tare
    - Kg + +
    diff --git a/pos_tare/views/view_pos_config.xml b/pos_tare/views/view_pos_config.xml index 8e6e667a..11ca9424 100644 --- a/pos_tare/views/view_pos_config.xml +++ b/pos_tare/views/view_pos_config.xml @@ -11,7 +11,7 @@
    -
    +
    +
    +
    +
    From eafd5e27c4713da24512b6db97aafb78986ea6fe Mon Sep 17 00:00:00 2001 From: Sylvain LE GAL Date: Tue, 19 May 2020 17:32:17 +0200 Subject: [PATCH 10/10] [IMP] display gross weight and tare on ticket (non proxy mode) --- pos_tare/readme/ROADMAP.rst | 1 - pos_tare/static/description/pos_ticket.png | Bin 0 -> 24470 bytes pos_tare/static/src/js/models.js | 10 ++++++++++ pos_tare/static/src/js/screens.js | 5 ++--- pos_tare/static/src/xml/pos_tare.xml | 16 ++++++++++++++++ 5 files changed, 28 insertions(+), 4 deletions(-) delete mode 100644 pos_tare/readme/ROADMAP.rst create mode 100644 pos_tare/static/description/pos_ticket.png diff --git a/pos_tare/readme/ROADMAP.rst b/pos_tare/readme/ROADMAP.rst deleted file mode 100644 index 4e2021e0..00000000 --- a/pos_tare/readme/ROADMAP.rst +++ /dev/null @@ -1 +0,0 @@ -- Print tare value on customer receipt. diff --git a/pos_tare/static/description/pos_ticket.png b/pos_tare/static/description/pos_ticket.png new file mode 100644 index 0000000000000000000000000000000000000000..bf753d40fb2b09520cdc2ee552e26ad172764bd3 GIT binary patch literal 24470 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

    vv5bSc*)%5r^BUH4vLVajW?r3%h9H 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 literal 0 HcmV?d00001 diff --git a/pos_tare/static/src/js/models.js b/pos_tare/static/src/js/models.js index 2c73c792..1a839967 100644 --- a/pos_tare/static/src/js/models.js +++ b/pos_tare/static/src/js/models.js @@ -97,6 +97,16 @@ odoo.define('pos_tare.models', function (require) { return tare_str + ' ' + unit.name; }, + get_gross_weight_str_with_unit: function () { + var unit = this.get_unit(); + var gross_weight_str = pos_tare_tools.format_tare( + this.pos, + this.get_tare() + this.get_quantity(), + this.get_unit(), + ); + return gross_weight_str + ' ' + unit.name; + }, + }); models.Orderline = OrderLineWithTare; diff --git a/pos_tare/static/src/js/screens.js b/pos_tare/static/src/js/screens.js index 38ba1321..e948c14b 100644 --- a/pos_tare/static/src/js/screens.js +++ b/pos_tare/static/src/js/screens.js @@ -42,11 +42,10 @@ odoo.define('pos_tare.screens', function (require) { // Overload Section // ///////////////////////////// - // Overload show function - // add an handler on the show: function () { - this._super(); this.tare = 0.0; + this.gross_weight = 0.0; + this._super(); var self = this; this.$('#input_weight_tare').keyup(function (event) { self.onchange_tare(event); diff --git a/pos_tare/static/src/xml/pos_tare.xml b/pos_tare/static/src/xml/pos_tare.xml index af3edb28..49436af9 100644 --- a/pos_tare/static/src/xml/pos_tare.xml +++ b/pos_tare/static/src/xml/pos_tare.xml @@ -40,4 +40,20 @@ + + + +

    + Gross Weight :
    + Tare :
    +
    +
    + + + + + +