[FIX] barcodes: form view barcode handler: concurrency
Suppose the following usecase: you scan the first product of the picking. A server onchange is then triggered. You scan the same product a second time, before the first onchange has returned. You expect that the first onchange is completely executed before running the second one. This was not the case. Moreover, some onchanges were not be able to work with the invalid state of the formview at some times, and crashed. The previous implementation was wrong because id didn't run the main barcode processing mechanism inside a Mutex. It was also wrong because it didn't correctly wait for the onchange to execute (a previous barcode onchanges or some classic ones) before setting the barcode field.
This commit is contained in:
@@ -27,6 +27,8 @@ var FormViewBarcodeHandler = common.AbstractField.extend(BarcodeHandlerMixin, {
|
||||
this.__quantity_listener = _.bind(this._set_quantity_listener, this);
|
||||
BarcodeHandlerMixin.init.apply(this, arguments);
|
||||
|
||||
this.process_barcode_mutex = new utils.Mutex();
|
||||
|
||||
return this._super.apply(this, arguments);
|
||||
},
|
||||
|
||||
@@ -136,25 +138,35 @@ var FormViewBarcodeHandler = common.AbstractField.extend(BarcodeHandlerMixin, {
|
||||
else if (this.form_view.get('actual_mode') === 'view')
|
||||
this._display_no_edit_mode_warning();
|
||||
else {
|
||||
// Call hook method possibly implemented by subclass
|
||||
this.pre_onchange_hook(barcode).then(function(proceed) {
|
||||
if (proceed === true) {
|
||||
// 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);
|
||||
});
|
||||
});
|
||||
var process_barcode = function () {
|
||||
// this function can be passed to `Mutex.exec` in order to make sure
|
||||
// that every ongoing onchanges in the form view are done
|
||||
var form_onchanges_mutex = function () {
|
||||
return self.form_view.onchanges_mutex.def;
|
||||
}
|
||||
});
|
||||
|
||||
// before setting the barcode field with the received barcode, we commit
|
||||
// every fields of the form view and we wait for their hypothetical ongoing
|
||||
// onchanges to finish
|
||||
var commit_mutex = new utils.Mutex();
|
||||
_.each(self.form_view.fields, function (field) {
|
||||
commit_mutex.exec(function () {
|
||||
return field.commit_value();
|
||||
});
|
||||
commit_mutex.exec(form_onchanges_mutex);
|
||||
});
|
||||
|
||||
return commit_mutex.def.then(function () {
|
||||
return self.pre_onchange_hook(barcode).then(function (proceed) {
|
||||
if (proceed) {
|
||||
self.set_value(barcode); // set the barcode field with the received one
|
||||
return form_onchanges_mutex(); // wait for its onchange to finish
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
this.process_barcode_mutex.exec(process_barcode);
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
Reference in New Issue
Block a user