Browse Source

Barcode tare.

pull/447/head
François Kawala 5 years ago
parent
commit
95b60c6249
  1. 1
      pos_barcode_tare/__init__.py
  2. 36
      pos_barcode_tare/__openerp__.py
  3. BIN
      pos_barcode_tare/static/description/icon.png
  4. 105
      pos_barcode_tare/static/src/css/tare_screen.css
  5. 36
      pos_barcode_tare/static/src/js/barcode.js
  6. 20
      pos_barcode_tare/static/src/js/open_tare_screen_button.js
  7. 139
      pos_barcode_tare/static/src/js/tare_screen.js
  8. 9
      pos_barcode_tare/static/src/xml/open_tare_screen_button.xml
  9. 38
      pos_barcode_tare/static/src/xml/tare_screen.xml
  10. 12
      pos_barcode_tare/views/templates.xml

1
pos_barcode_tare/__init__.py

@ -0,0 +1 @@
# -*- coding: utf-8 -*-

36
pos_barcode_tare/__openerp__.py

@ -0,0 +1,36 @@
# -*- coding: utf-8 -*-
{
'name': "pos_barecode_tare",
'summary': """
Allows to scan a barcode to tare the latest product.
""",
'description': """
This add-on enable POS to read and print tare bar codes. A tare bar code is used to sell unpackaged goods in a
BYOC (bring your own container) scheme. This scheme has four steps:
1. The cashier weights the container and sticks the tare bar code onto the customer's container.
2. The customer takes the desired quantity of whatever good s-he wants.
3. The cashier weights the filled container and good, POS gives the corresponding price.
4. The cashier scans the tare bar code, POS removes the container's weight from the latest product of the order.
""",
'author': "Le Nid",
'website': "http://www.lenid.ch",
'category': 'Point of Sale',
'version': '0.1',
# any module necessary for this one to work correctly
'depends': ['point_of_sale'],
# always loaded
'data': [
'views/templates.xml',
],
'qweb': [
'static/src/xml/tare_screen.xml',
'static/src/xml/open_tare_screen_button.xml',
],
}

BIN
pos_barcode_tare/static/description/icon.png

After

Width: 1571  |  Height: 1690  |  Size: 90 KiB

105
pos_barcode_tare/static/src/css/tare_screen.css

@ -0,0 +1,105 @@
.pos .print-label.disabled {
background: #e2e2e2;
border: solid 1px #BEBEBE;
opacity: 0.5;
cursor: default;
color: inherit;
}
.pos .pos-tare-label {
width: 300px;
background-color: white;
margin: 20px;
padding: 15px;
font-size: 21px;
padding-bottom:30px;
display: inline-block;
font-family: "Inconsolata";
border: solid 1px rgb(220,220,220);
border-radius: 3px;
overflow: hidden;
}
.pos .tare-screen .pos-directions-for-user {
font-size: 25px;
margin: 8px;
text-align: center;
line-height: 2;
}
.pos .tare-screen .pos-directions-for-user span {
width:100px;
height: 50px;
background-color: rgb(49,174,218);
color: white !important;
font-weight: bold;
border: solid 1px black;
border-radius: 90% 30%;
display: flex;
align-items: center;
overflow: hidden;
vertical-align:middle;
justify-content: center;
margin-left: auto;
margin-right: auto;
}
.pos .pos-tare-label img {
width: 50mm;
height: 45mm;
}
.pos .tare-screen .print-label {
text-align: center;
font-size: 32px;
background: rgb(110,200,155);
color: white;
border-radius: 3px;
padding: 16px;
margin: 16px;
cursor: pointer;
}
@media print {
.pos .tare-screen header,
.pos .tare-screen .top-content,
.pos .tare-screen .centered-content .print-label,
.pos .tare-screen .pos-directions-for-user {
display: none !important;
}
.pos .tare-screen .centered-content {
position: static;
border: none;
}
.pos .pos-tare-paper {
margin: 0;
margin-left: 0 !important;
margin-right: 0 !important;
width: 42mm !important;
height: 29mm !important;
background: white;
display: block;
position: fixed;
display: flex !important;
justify-content: center !important;
align-items: center !important;
}
.pos-tare-label img {
width: 30mm !important;
height: 25mm !important;
}
.pos .pos-tare-label {
margin: 0;
margin-left: 0 !important;
margin-right: 0 !important;
position: fixed !important;
border: none !important;
font-size: 10px !important;
}
}

36
pos_barcode_tare/static/src/js/barcode.js

@ -0,0 +1,36 @@
odoo.define('barcode_tare',function(require) {
"use strict";
var screens = require('point_of_sale.screens');
var gui = require('point_of_sale.gui');
var core = require('web.core');
var _t = core._t;
screens.ScreenWidget.include(
{
barcode_weight_action: function(code){
var self = this;
var order = this.pos.get_order();
var last_order_line = order.get_last_orderline();
var total_weight = last_order_line.get_quantity();
var tare = code.value;
var paid_weight = total_weight - tare;
if (paid_weight <= 0) {
this.gui.show_popup('confirm', {
'title': _t('Poids négatif'),
'body': _t('Le poids à payer est négatif. Avez-vous scanné le bon code bare ?'),
confirm: function(){
last_order_line.set_quantity(paid_weight)
}});
} else {
last_order_line.set_quantity(paid_weight)
}
},
show: function(){
var self = this;
this._super()
this.pos.barcode_reader.set_action_callback('weight', _.bind(self.barcode_weight_action, self))
},
});
});

20
pos_barcode_tare/static/src/js/open_tare_screen_button.js

@ -0,0 +1,20 @@
odoo.define('tare-screen-button.button', function (require) {
"use strict";
var core = require('web.core');
var screens = require('point_of_sale.screens');
var gui = require('point_of_sale.gui');
var TareScreenButton = screens.ActionButtonWidget.extend({
template: 'TareScreenButton',
button_click: function(){
var self = this;
this.gui.show_screen('tare');
}
});
screens.define_action_button({
'name': 'tareScreenButton',
'widget': TareScreenButton,
});
});

139
pos_barcode_tare/static/src/js/tare_screen.js

@ -0,0 +1,139 @@
odoo.define('tare-screen.screen', function (require) {
"use strict";
var chrome = require('point_of_sale.chrome');
var core = require('web.core');
var devices = require('point_of_sale.devices');
var gui = require('point_of_sale.gui');
var models = require('point_of_sale.models');
var screens = require('point_of_sale.screens');
var QWeb = core.qweb;
var TareScreenWidget = screens.ScreenWidget.extend({
template: 'TareScreenWidget',
next_screen: 'products',
previous_screen: 'products',
default_tare_value_kg: 0.0,
show: function(){
this._super();
var self = this;
var queue = this.pos.proxy_queue;
queue.schedule(function(){
return self.pos.proxy.scale_read().then(function(weight){
self.set_weight(weight.weight);
});
},{duration:150, repeat: true});
this.render_receipt();
this.lock_screen(true);
},
set_weight: function(weight){
if (weight > 0){
this.weight = weight;
this.render_receipt();
this.lock_screen(false);
}
},
get_weight: function(){
if (typeof this.weight === 'undefined') {
return this.default_tare_value_kg;
}
return this.weight;
},
ean13_checksum: function(s){
var result = 0;
for (let counter = s.length-1; counter >=0; counter--){
result = result + parseInt(s.charAt(counter)) * (1+(2*(counter % 2)));
}
return (10 - (result % 10)) % 10;
},
barcode_data: function(weight, weight_prefix_id=21){
var padding_size = 5;
var void_product_id = '0'.repeat(padding_size);
var weight_in_gram = weight * 10e2;
var weight_with_padding = '0'.repeat(padding_size) + weight_in_gram;
var padded_weight = weight_with_padding.substr(weight_with_padding.length - padding_size);
var barcode_data = `${weight_prefix_id}${void_product_id}${padded_weight}`;
var checksum = this.ean13_checksum(barcode_data);
console.log(`${barcode_data}${checksum}`);
return `${barcode_data}${checksum}`;
},
get_barcode_data: function(){
return this.barcode_data(this.get_weight());
},
should_auto_print: function() {
return this.pos.config.iface_print_auto && !this.pos.get_order()._printed;
},
should_close_immediately: function() {
return this.pos.config.iface_print_via_proxy && this.pos.config.iface_print_skip_screen;
},
lock_screen: function(locked) {
this._locked = locked;
if (locked) {
this.$('.print-label').addClass('disabled');
} else {
this.$('.print-label').removeClass('disabled');
}
},
print_web: function() {
window.print();
this.pos.get_order()._printed = true;
},
print: function() {
var self = this;
// The problem is that in chrome the print() is asynchronous and doesn't
// execute until all rpc are finished. So it conflicts with the rpc used
// to send the orders to the backend, and the user is able to go to the next
// screen before the printing dialog is opened. The problem is that what's
// printed is whatever is in the page when the dialog is opened and not when it's called,
// and so you end up printing the product list instead of the receipt...
//
// Fixing this would need a re-architecturing
// of the code to postpone sending of orders after printing.
//
// But since the print dialog also blocks the other asynchronous calls, the
// button enabling in the setTimeout() is blocked until the printing dialog is
// closed. But the timeout has to be big enough or else it doesn't work
// 1 seconds is the same as the default timeout for sending orders and so the dialog
// should have appeared before the timeout... so yeah that's not ultra reliable.
this.lock_screen(true);
setTimeout(function(){
self.lock_screen(false);
}, 1000);
this.print_web();
this.click_back();
},
click_back: function() {
this.close()
this.gui.show_screen(this.previous_screen);
},
renderElement: function() {
var self = this;
this._super();
this.$('.back').click(function(){
self.click_back();
});
this.$('.print-label').click(function(){
if (!self._locked) {
self.print();
}
});
},
render_receipt: function() {
this.$('.pos-tare-label-container').html(QWeb.render('PosTareLabel',{widget:this}));
},
close: function(){
this._super();
delete this.weight;
this.pos.proxy_queue.clear();
},
});
gui.define_screen({name:'tare', widget: TareScreenWidget});
});

9
pos_barcode_tare/static/src/xml/open_tare_screen_button.xml

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<templates id="template" xml:space="preserve">
<t t-name="TareScreenButton">
<span class="control-button">
<i class="fa fa-print"></i>
Créer une étiquette de tare
</span>
</t>
</templates>

38
pos_barcode_tare/static/src/xml/tare_screen.xml

@ -0,0 +1,38 @@
<?xml version="1.0" encoding="UTF-8"?>
<templates id="template" xml:space="preserve">
<t t-name="TareScreenWidget">
<div class='tare-screen screen'>
<div class='screen-content'>
<div class='top-content'>
<span class='button back'>
<i class='fa fa-angle-double-left'></i>
Back
</span>
<h1>Création d'une étiquette de tare</h1>
</div>
<div class="centered-content">
<div class="pos-tare-label-container"></div>
<div class="pos-directions-for-user">
Appuyez sur la touche <span>print</span> puis vérifiez le poids ci-dessus.
</div>
<div class='print-label'>
Imprimer
<i class='fa fa-angle-double-right'></i>
</div>
</div>
</div>
</div>
</t>
<t t-name="PosTareLabel">
<div class="pos-center-align">
<div class="pos-tare-paper">
<div class="pos-tare-label">
<img t-att-src="'/report/barcode/EAN13/' + widget.get_barcode_data()" />
<br />
tare = <t t-esc="widget.get_weight()" />kg
</div>
</div>
</div>
</t>
</templates>

12
pos_barcode_tare/views/templates.xml

@ -0,0 +1,12 @@
<odoo>
<data>
<template id="assets_backend" name="pos_barcode_tare" inherit_id="point_of_sale.assets">
<xpath expr="." position="inside">
<link rel="stylesheet" href="/pos_barcode_tare/static/src/css/tare_screen.css"/>
<script type="text/javascript" src="/pos_barcode_tare/static/src/js/tare_screen.js"></script>
<script type="text/javascript" src="/pos_barcode_tare/static/src/js/open_tare_screen_button.js"></script>
<script type="text/javascript" src="/pos_barcode_tare/static/src/js/barcode.js"></script>
</xpath>
</template>
</data>
</odoo>
Loading…
Cancel
Save