[MERGE] web/barcodes: add backend barcode scanning tools
This commit is contained in:
@@ -1 +1,5 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import barcodes
|
||||
|
||||
import models
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import barcode_events_mixin
|
||||
@@ -0,0 +1,24 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from openerp import models, fields, api
|
||||
|
||||
class BarcodeEventsMixin(models.AbstractModel):
|
||||
""" Mixin class for objects reacting when a barcode is scanned in their form views
|
||||
which contains `<field name="_barcode_scanned" widget="barcode_handler"/>`.
|
||||
Models using this mixin must implement the method on_barcode_scanned. It works
|
||||
like an onchange and receives the scanned barcode in parameter.
|
||||
"""
|
||||
|
||||
_name = 'barcodes.barcode_events_mixin'
|
||||
|
||||
_barcode_scanned = fields.Char("Barcode Scanned", help="Value of the last barcode scanned.", store=False)
|
||||
|
||||
@api.onchange('_barcode_scanned')
|
||||
def _on_barcode_scanned(self):
|
||||
barcode = self._barcode_scanned
|
||||
if barcode:
|
||||
self._barcode_scanned = ""
|
||||
return self.on_barcode_scanned(barcode)
|
||||
|
||||
def on_barcode_scanned(self, barcode):
|
||||
raise NotImplementedError("In order to use barcodes.barcode_events_mixin, method on_barcode_scanned must be implemented")
|
||||
@@ -21,12 +21,12 @@ var BarcodeEvents = core.Class.extend(mixins.PropertiesMixin, {
|
||||
init: function() {
|
||||
mixins.PropertiesMixin.init.call(this);
|
||||
// Keep a reference of the handler functions to use when adding and removing event listeners
|
||||
this.__keydown_handler = this.keydown_handler.bind(this);
|
||||
this.__keyup_handler = this.keyup_handler.bind(this);
|
||||
this.__handler = this.handler.bind(this);
|
||||
this.__keydown_handler = _.bind(this.keydown_handler, this);
|
||||
this.__keyup_handler = _.bind(this.keyup_handler, this);
|
||||
this.__handler = _.bind(this.handler, this);
|
||||
// Bind event handler once the DOM is loaded
|
||||
// TODO: find a way to be active only when there are listeners on the bus
|
||||
$(this.start.bind(this, false));
|
||||
$(_.bind(this.start, this, false));
|
||||
},
|
||||
|
||||
handle_buffered_keys: function() {
|
||||
@@ -145,7 +145,7 @@ var BarcodeEvents = core.Class.extend(mixins.PropertiesMixin, {
|
||||
if (String.fromCharCode(e.which).match(this.suffix)) {
|
||||
this.handle_buffered_keys();
|
||||
} else {
|
||||
this.timeout = setTimeout(this.handle_buffered_keys.bind(this), this.max_time_between_keys_in_ms);
|
||||
this.timeout = setTimeout(_.bind(this.handle_buffered_keys, this), this.max_time_between_keys_in_ms);
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
odoo.define('barcodes.BarcodeHandlerMixin', function(require) {
|
||||
"use strict";
|
||||
|
||||
var core = require('web.core');
|
||||
var View = require('web.View');
|
||||
|
||||
// Mixin implementing the common basis for barcode handlers.
|
||||
// The object on which this mixin is applied must also include ParentedMixin. Example :
|
||||
// Widget.extend(BarcodeHandlerMixin, { ... });
|
||||
// Class.extend(PropertiesMixin, BarcodeHandlerMixin, { ... });
|
||||
|
||||
return {
|
||||
init: function() {
|
||||
var self = this;
|
||||
this._super.apply(this, arguments);
|
||||
this.__on_barcode_scanned = function () {
|
||||
self.on_barcode_scanned.apply(self, arguments);
|
||||
};
|
||||
this.start_listening();
|
||||
// Handlers inside a View managed by a ViewManager only listen to barcode events while their view is displayed
|
||||
var view = this.findAncestor(function(ancestor) { return ancestor instanceof View });
|
||||
if (view) {
|
||||
view.on('attached', this, this.start_listening);
|
||||
view.on('detached', this, this.stop_listening);
|
||||
}
|
||||
},
|
||||
|
||||
start_listening: function() {
|
||||
if (! this.is_listening) {
|
||||
core.bus.on('barcode_scanned', this, this.__on_barcode_scanned);
|
||||
this.is_listening = true;
|
||||
}
|
||||
},
|
||||
|
||||
stop_listening: function() {
|
||||
if (this.is_listening) {
|
||||
core.bus.off('barcode_scanned', this, this.__on_barcode_scanned);
|
||||
this.is_listening = false;
|
||||
}
|
||||
},
|
||||
|
||||
on_barcode_scanned: function(barcode) {
|
||||
console.error('A class implementing BarcodeHandlerMixin must redefine method on_barcode_scanned.');
|
||||
},
|
||||
};
|
||||
|
||||
});
|
||||
@@ -0,0 +1,78 @@
|
||||
odoo.define('barcodes.FormViewBarcodeHandler', function(require) {
|
||||
"use strict";
|
||||
|
||||
var core = require('web.core');
|
||||
var utils = require('web.utils');
|
||||
var common = require('web.form_common');
|
||||
var BarcodeHandlerMixin = require('barcodes.BarcodeHandlerMixin');
|
||||
|
||||
var _t = core._t;
|
||||
|
||||
var FormViewBarcodeHandler = common.AbstractField.extend(BarcodeHandlerMixin, {
|
||||
start: function() {
|
||||
this._super();
|
||||
this.form_view = this.field_manager;
|
||||
// Hardcoded barcode actions
|
||||
this.map_barcode_method = {
|
||||
'O-CMD.NEW': _.bind(this.form_view.on_button_new, this.form_view),
|
||||
'O-CMD.CANCEL': _.bind(this.form_view.on_button_cancel, this.form_view),
|
||||
// FIXME: on_button_save shouldn't mix view and model concerns (it expects to be used as onclick handler)
|
||||
'O-CMD.SAVE': _.bind(this.form_view.on_button_save, this.form_view, {target: $('.o_cp_buttons .o_form_button_save')}),
|
||||
};
|
||||
// Old design pager actions
|
||||
if (this.form_view.execute_pager_action) {
|
||||
this.map_barcode_method['O-CMD.PAGER-PREV'] = _.bind(this.form_view.execute_pager_action, this.form_view, 'previous');
|
||||
this.map_barcode_method['O-CMD.PAGER-NEXT'] = _.bind(this.form_view.execute_pager_action, this.form_view, 'next');
|
||||
// New design pager actions
|
||||
} else if (this.form_view.pager) {
|
||||
this.map_barcode_method['O-CMD.PAGER-PREV'] = _.bind(this.form_view.pager.previous, this.form_view.pager);
|
||||
this.map_barcode_method['O-CMD.PAGER-NEXT'] = _.bind(this.form_view.pager.next, this.form_view.pager);
|
||||
}
|
||||
},
|
||||
|
||||
// Let subclasses add custom behaviour before onchange
|
||||
// Return false in order to proceed with the onchange, anything else to prevent it.
|
||||
pre_onchange_hook: function(barcode) {
|
||||
return false;
|
||||
},
|
||||
|
||||
on_barcode_scanned: function(barcode) {
|
||||
var self = this;
|
||||
// Execute a harcoded action
|
||||
var action = this.map_barcode_method[barcode];
|
||||
if (typeof action === "function")
|
||||
return $.when(action());
|
||||
// Warn the user if form view is not editable
|
||||
else if (this.form_view.get('actual_mode') === 'view')
|
||||
this.do_warn(_t('Error : Document not editable'), _t('To modify this document, please first start edition.'));
|
||||
else {
|
||||
// Call hook method possibly implemented by subclass
|
||||
$.when(this.pre_onchange_hook(barcode)).then(function(result) {
|
||||
if (result !== false) {
|
||||
return result;
|
||||
} else {
|
||||
// Wait for hypothetical ongoing onchange to finish
|
||||
self.form_view.onchanges_mutex.exec(function() {
|
||||
// A real onchange is triggered when a value actually changes (which can correspond
|
||||
// to a widget's blur event per example). Commit the value of fields before
|
||||
// programmatically triggering an onchange to be consistent with this.
|
||||
var mutex_commit_value = new utils.Mutex();
|
||||
_.each(self.form_view.fields, function(field) {
|
||||
mutex_commit_value.exec(_.bind(field.commit_value, field));
|
||||
});
|
||||
return mutex_commit_value.def.then(function(){
|
||||
// Trigger the barcode onchange
|
||||
self.set_value(barcode);
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
core.form_widget_registry.add('barcode_handler', FormViewBarcodeHandler);
|
||||
|
||||
return FormViewBarcodeHandler;
|
||||
|
||||
});
|
||||
@@ -0,0 +1,29 @@
|
||||
odoo.define('barcode.InheritedFormWidgetButton', function (require) {
|
||||
"use strict";
|
||||
|
||||
var widgets = require('web.form_widgets');
|
||||
var BarcodeHandlerMixin = require('barcodes.BarcodeHandlerMixin');
|
||||
|
||||
// If the button has a barcode_trigger attribute, dynamically inherit
|
||||
// BarcodeHandlerMixin and redefine on_barcode_scanned
|
||||
|
||||
var ButtonBarcodeHandlerMixin = _.extend({}, BarcodeHandlerMixin, {
|
||||
init: function(field_manager, node) {
|
||||
if (node.attrs.barcode_trigger) {
|
||||
BarcodeHandlerMixin.init.call(this, field_manager, node);
|
||||
var self = this;
|
||||
this.on_barcode_scanned = function(barcode) {
|
||||
var match = barcode.match(/O-BTN\.(.+)/);
|
||||
if (match && match[1] === self.node.attrs.barcode_trigger && self.$el.is(':visible')) {
|
||||
self.on_click();
|
||||
}
|
||||
};
|
||||
} else {
|
||||
this._super(field_manager, node);
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
widgets.WidgetButton.include(ButtonBarcodeHandlerMixin);
|
||||
|
||||
});
|
||||
@@ -6,6 +6,9 @@
|
||||
<xpath expr="." position="inside">
|
||||
<script type="text/javascript" src="/barcodes/static/src/js/barcode_parser.js"></script>
|
||||
<script type="text/javascript" src="/barcodes/static/src/js/barcode_events.js"></script>
|
||||
<script type="text/javascript" src="/barcodes/static/src/js/barcode_handler_mixin.js"></script>
|
||||
<script type="text/javascript" src="/barcodes/static/src/js/form_view_barcode_handler.js"></script>
|
||||
<script type="text/javascript" src="/barcodes/static/src/js/inherited_form_widget_button.js"></script>
|
||||
</xpath>
|
||||
</template>
|
||||
|
||||
|
||||
@@ -1663,7 +1663,8 @@ core.form_tag_registry.add('button', WidgetButton);
|
||||
|
||||
return {
|
||||
FieldChar: FieldChar,
|
||||
FieldMonetary: FieldMonetary
|
||||
FieldMonetary: FieldMonetary,
|
||||
WidgetButton: WidgetButton
|
||||
};
|
||||
|
||||
});
|
||||
|
||||
@@ -666,6 +666,7 @@
|
||||
<span t-att-class="'oe_form_field '+widget.widget_class" t-att-style="widget.node.attrs.style">
|
||||
<t t-if="!widget.get('effective_readonly')">
|
||||
<input t-att-type="widget.password ? 'password' : 'text'"
|
||||
t-att-barcode_events="widget.options.barcode_events"
|
||||
t-att-id="widget.id_for_label"
|
||||
t-att-tabindex="widget.node.attrs.tabindex"
|
||||
t-att-autofocus="widget.node.attrs.autofocus"
|
||||
@@ -820,6 +821,7 @@
|
||||
class="oe_m2o_cm_button fa fa-external-link" draggable="false"/>
|
||||
<div>
|
||||
<input type="text"
|
||||
t-att-barcode_events="widget.options.barcode_events"
|
||||
t-att-id="widget.id_for_label"
|
||||
t-att-tabindex="widget.node.attrs.tabindex"
|
||||
t-att-autofocus="widget.node.attrs.autofocus"
|
||||
|
||||
Reference in New Issue
Block a user