Sylvain LE GAL
5 years ago
committed by
François Kawala
14 changed files with 187 additions and 333 deletions
-
64pos_tare/README.rst
-
1pos_tare/__init__.py
-
18pos_tare/__manifest__.py
-
13pos_tare/demo/pos_config.xml
-
49pos_tare/i18n/fr.po
-
2pos_tare/readme/CONFIGURE.rst
-
6pos_tare/readme/DESCRIPTION.rst
-
3pos_tare/readme/ROADMAP.rst
-
BINpos_tare/static/description/pos_tare.png
-
64pos_tare/static/src/css/pos_tare.css
-
140pos_tare/static/src/js/pos_tare.js
-
97pos_tare/static/src/js/screens.js
-
41pos_tare/static/src/xml/pos_tare.xml
-
18pos_tare/views/assets.xml
@ -1 +0,0 @@ |
|||
# coding: utf-8 |
@ -1,13 +0,0 @@ |
|||
<?xml version="1.0" encoding="UTF-8"?> |
|||
<!-- |
|||
Copyright (C) 2018 - Today: GRAP (http://www.grap.coop) |
|||
@author: Sylvain LE GAL (https://twitter.com/legalsylvain) |
|||
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). |
|||
--> |
|||
<openerp><data> |
|||
|
|||
<record id="point_of_sale.pos_config_main" model="pos.config"> |
|||
<field name="iface_electronic_scale" eval="1" /> |
|||
</record> |
|||
|
|||
</data></openerp> |
@ -0,0 +1,2 @@ |
|||
To enable this feature, you should enable "IoT Box" on your Point of Sale, |
|||
and check the box "Electronic Scale" |
@ -1,8 +1,6 @@ |
|||
Give the possibility to the user to provide Gross weight and Tare weight. |
|||
Give the possibility to the user to enter a Tare weight, when weighting |
|||
products in the Point of Sale. |
|||
This will compute automatically net weight and set it to the current |
|||
selected order |
|||
|
|||
.. figure:: ../static/description/pos_tare.png |
|||
|
|||
The screen will be displayed only for 'to_weight' products and if scale is |
|||
enabled in PoS Configuration. |
@ -1 +1,2 @@ |
|||
For the time being, this module disable Scale functionnality. |
|||
* Display the gross weight and the tare on each order line, on the screen |
|||
and on the receipt. |
Before Width: 871 | Height: 388 | Size: 36 KiB After Width: 501 | Height: 480 | Size: 30 KiB |
@ -1,31 +1,49 @@ |
|||
.pos .pos-tare-container .left-block{ |
|||
|
|||
.pos .scale-screen .weight-label { |
|||
font-size: 25px; |
|||
margin: 16px; |
|||
text-align: center; |
|||
display: inline-block; |
|||
width:45%; |
|||
margin:0; |
|||
padding:0; |
|||
text-align:left; |
|||
font-size: 16px; |
|||
color: #555; |
|||
font-weight: bold; |
|||
width: 40%; |
|||
margin-bottom: 0px; |
|||
} |
|||
|
|||
.pos .pos-tare-container .right-block, .pos .pos-tare-container .right-block-readonly{ |
|||
.pos .scale-screen .weight-value { |
|||
font-size: 25px; |
|||
display: inline-block; |
|||
width:45%; |
|||
text-align:right; |
|||
height: 40px; |
|||
font-size: 20px; |
|||
font-family: Lato; |
|||
-moz-box-sizing: border-box; |
|||
outline: none; |
|||
border: none; |
|||
padding: 6px 8px; |
|||
color: #484848; |
|||
border-radius: 3px; |
|||
margin-top: 5px; |
|||
margin: 16px; |
|||
margin-top: 0px; |
|||
padding: 16px; |
|||
width: 40%; |
|||
font-family: Inconsolata; |
|||
font-weight: bold; |
|||
text-shadow: 0px 2px 0px rgb(210,210,210); |
|||
margin-bottom: 0px; |
|||
} |
|||
|
|||
.pos .pos-tare-container .right-block{ |
|||
.pos .scale-screen .weight-value-gross-weight { |
|||
border-radius: 3px; |
|||
box-shadow: 0px 2px 0px rgb(225,225,225) inset; |
|||
text-align: right; |
|||
background: white; |
|||
box-shadow: 0px 2px rgba(143, 143, 143, 0.3) inset; |
|||
} |
|||
|
|||
.pos .scale-screen .weight-value-tare { |
|||
text-align: left; |
|||
padding-bottom: 0px; |
|||
padding-left: 0px; |
|||
} |
|||
.pos .scale-screen .input-weight-tare { |
|||
border: 1px solid #cecbcb; |
|||
border-radius: 20px; |
|||
padding: 15px 20px; |
|||
width: 50%; |
|||
font-family: Inconsolata; |
|||
font-weight: bold; |
|||
font-size: 25px; |
|||
} |
|||
|
|||
.pos .scale-screen .input-weight-tare:focus { |
|||
outline: none; |
|||
box-shadow: 0px 0px 0px 3px #6EC89B; |
|||
} |
@ -1,140 +0,0 @@ |
|||
/* |
|||
Copyright (C) 2015-Today GRAP (http://www.grap.coop)
|
|||
@author: Sylvain LE GAL (https://twitter.com/legalsylvain)
|
|||
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
|||
*/ |
|||
|
|||
"use strict"; |
|||
|
|||
openerp.pos_tare = function(instance){ |
|||
var module = instance.point_of_sale; |
|||
var _t = instance.web._t; |
|||
|
|||
/************************************************************************* |
|||
Extend : Widget 'PosWidget' |
|||
*/ |
|||
module.PosWidget = module.PosWidget.extend({ |
|||
build_widgets: function(){ |
|||
this._super(); |
|||
|
|||
// Add a new screen 'TareScreenWidget'
|
|||
this.tare_screen = new module.TareScreenWidget(this,{}); |
|||
this.tare_screen.appendTo(this.$('.screens')); |
|||
this.screen_selector.add_screen('tare', this.tare_screen); |
|||
}, |
|||
}); |
|||
|
|||
/************************************************************************* |
|||
Extend : Widget 'ScaleScreenWidget' |
|||
*/ |
|||
module.ScaleScreenWidget = module.ScaleScreenWidget.extend({ |
|||
next_screen: 'tare', |
|||
|
|||
// Overwrite 'show' function to display TareScreenWidget
|
|||
show: function(){ |
|||
this.pos_widget.screen_selector.set_current_screen(this.next_screen,{product: this.get_product()}); |
|||
}, |
|||
}); |
|||
|
|||
/************************************************************************* |
|||
Define : New Widget 'TareScreenWidget' |
|||
*/ |
|||
module.TareScreenWidget = module.ScreenWidget.extend({ |
|||
template:'TareScreenWidget', |
|||
next_screen: 'products', |
|||
previous_screen: 'products', |
|||
show_leftpane: false, |
|||
|
|||
show: function(){ |
|||
this._super(); |
|||
this.renderElement(); |
|||
var self = this; |
|||
|
|||
// Initialize values
|
|||
this.net_weight = 0; |
|||
this.current_product = this.get_product(); |
|||
this.$('#product-name').html(this.get_product().display_name); |
|||
this.$('#unit-price').html(this.format_currency(this.get_product().price)); |
|||
|
|||
// Add a 'next' Button
|
|||
this.add_action_button({ |
|||
label: _t('Back'), |
|||
icon: '/point_of_sale/static/src/img/icons/png48/go-previous.png', |
|||
click: function(){ |
|||
self.pos_widget.screen_selector.set_current_screen(self.previous_screen); |
|||
}, |
|||
}); |
|||
this.order_button = this.add_action_button({ |
|||
label: _t('Order'), |
|||
icon: '/point_of_sale/static/src/img/icons/png48/go-next.png', |
|||
click: function() { self.order_product_click(); }, |
|||
}); |
|||
|
|||
// Initialize Display
|
|||
this.onChangeGrossWeightTareWeight(); |
|||
|
|||
this.$('#gross-weight').keyup(function(event){ |
|||
self.onChangeGrossWeightTareWeight(event); |
|||
}); |
|||
this.$('#tare-weight').keyup(function(event){ |
|||
self.onChangeGrossWeightTareWeight(event); |
|||
}); |
|||
|
|||
// Focus on Gross Weight
|
|||
this.$('#gross-weight').focus(); |
|||
|
|||
}, |
|||
|
|||
sanitize_value: function (input_name){ |
|||
var res = this.$(input_name)[0].value.replace(',', '.').trim(); |
|||
if (isNaN(res)){ |
|||
this.$(input_name).css("background-color", "#F66"); |
|||
} |
|||
else{ |
|||
this.$(input_name).css("background-color", "#FFF"); |
|||
} |
|||
return res; |
|||
}, |
|||
|
|||
onChangeGrossWeightTareWeight: function(event){ |
|||
var gross_weight = this.sanitize_value('#gross-weight'); |
|||
var tare_weight = this.sanitize_value('#tare-weight'); |
|||
var ok = false; |
|||
|
|||
if (!isNaN(gross_weight) && (gross_weight !== '') && (parseFloat(gross_weight) !== 0) && !isNaN(tare_weight)){ |
|||
this.net_weight = gross_weight - tare_weight; |
|||
var price = this.get_product().price * this.net_weight; |
|||
this.current_net_weight_text = this.net_weight.toFixed(3); |
|||
this.current_total_price_text = this.format_currency(price); |
|||
ok = true; |
|||
} |
|||
else{ |
|||
this.current_net_weight_text = '/'; |
|||
this.current_total_price_text = '/'; |
|||
} |
|||
this.$('#net-weight').html(this.current_net_weight_text); |
|||
this.$('#total-price').html(this.current_total_price_text); |
|||
this.order_button.set_disabled(!ok); |
|||
}, |
|||
|
|||
get_product: function(){ |
|||
var ss = this.pos_widget.screen_selector; |
|||
if(ss){ |
|||
return ss.get_current_screen_param('product'); |
|||
}else{ |
|||
return undefined; |
|||
} |
|||
}, |
|||
|
|||
order_product_click: function(){ |
|||
this.pos.get('selectedOrder').addProduct(this.current_product,{ quantity:this.net_weight }); |
|||
this.pos_widget.screen_selector.set_current_screen(this.next_screen); |
|||
}, |
|||
|
|||
}); |
|||
}; |
|||
|
|||
|
|||
|
|||
|
|||
|
@ -0,0 +1,97 @@ |
|||
/* |
|||
Copyright (C) 2015-Today GRAP (http://www.grap.coop)
|
|||
@author: Sylvain LE GAL (https://twitter.com/legalsylvain)
|
|||
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
|||
*/ |
|||
|
|||
|
|||
odoo.define('pos_tare.screens', function (require) { |
|||
"use strict"; |
|||
|
|||
var screens = require('point_of_sale.screens'); |
|||
var utils = require('web.utils'); |
|||
var round_pr = utils.round_precision; |
|||
|
|||
|
|||
screens.ScaleScreenWidget.include({ |
|||
|
|||
// /////////////////////////////
|
|||
// Overload Section
|
|||
// /////////////////////////////
|
|||
|
|||
// Overload show function
|
|||
// add an handler on the
|
|||
show: function(){ |
|||
this._super(); |
|||
this.tare = 0.0; |
|||
this.correct_value = true; |
|||
var self = this; |
|||
this.$('#weight_tare').keyup(function(event){ |
|||
self.onchange_tare(event); |
|||
}); |
|||
}, |
|||
|
|||
// 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.$('.weight-value-gross-weight').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(); |
|||
} |
|||
}, |
|||
|
|||
// /////////////////////////////
|
|||
// 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(event){ |
|||
this.tare = this.check_sanitize_value('#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; |
|||
} |
|||
else{ |
|||
this.$(input_name).css("background-color", "#FFF"); |
|||
return res; |
|||
} |
|||
}, |
|||
|
|||
}); |
|||
|
|||
}); |
Write
Preview
Loading…
Cancel
Save
Reference in new issue