[REF] web,*: remove 'web.model' and 'web.dataModel

Use this.rpc instead of Model object, with web.ajax if necessary.

nb: EventDispatcherMixin include now the custom_events managment instead
of widget
This commit is contained in:
Géry Debongnie
2017-04-11 19:44:38 +02:00
committed by Aaron Bohy
parent 0df9968433
commit e574027056
64 changed files with 1748 additions and 1560 deletions
@@ -147,18 +147,21 @@ var StatementModel = BasicModel.extend({
autoReconciliation: function () {
var self = this;
var ids = _.pluck(_.filter(_.values(this.lines), {'reconciled': false}), 'id');
return this.performModelRPC("account.bank.statement.line", 'reconciliation_widget_auto_reconcile', [ids, self.valuenow]).then(function (result) {
var reconciled_ids = _.difference(ids, result.st_lines_ids);
self.valuenow += reconciled_ids.length;
result.handles = [];
_.each(self.lines, function (line, handle) {
if (reconciled_ids.indexOf(line.id) !== -1) {
line.reconciled = true;
result.handles.push(handle);
}
return this.rpc("account.bank.statement.line", 'reconciliation_widget_auto_reconcile')
.args([ids, self.valuenow])
.exec()
.then(function (result) {
var reconciled_ids = _.difference(ids, result.st_lines_ids);
self.valuenow += reconciled_ids.length;
result.handles = [];
_.each(self.lines, function (line, handle) {
if (reconciled_ids.indexOf(line.id) !== -1) {
line.reconciled = true;
result.handles.push(handle);
}
});
return result;
});
return result;
});
},
/**
* change the filter for the target line and fetch the new matched lines
@@ -209,8 +212,9 @@ var StatementModel = BasicModel.extend({
* @returns {Deferred}
*/
changeName: function (name) {
return this.performModelRPC("account.bank.statement", "write",
[this.bank_statement_id.id, {name: name}]);
return this.rpc("account.bank.statement", "write")
.args([this.bank_statement_id.id, {name: name}])
.exec();
},
/**
* change the offset for the matched lines, and fetch the new matched lines
@@ -289,7 +293,9 @@ var StatementModel = BasicModel.extend({
if (!statement_ids) {
return $.when();
}
var def_statement = this.performModelRPC("account.bank.statement", 'reconciliation_widget_preprocess', [statement_ids])
var def_statement = this.rpc("account.bank.statement", 'reconciliation_widget_preprocess')
.args([statement_ids])
.exec()
.then(function (statement) {
self.bank_statement_id = statement_ids.length === 1 ? {id: statement_ids[0], display_name: statement.statement_name} : false;
self.valuenow = 0;
@@ -318,7 +324,9 @@ var StatementModel = BasicModel.extend({
line.reconcileModels = self.reconcileModels;
});
var ids = _.pluck(self.lines, 'id');
return self.performModelRPC("account.bank.statement.line", 'get_data_for_reconciliation_widget', [ids])
return self.rpc("account.bank.statement.line", 'get_data_for_reconciliation_widget')
.args([ids])
.exec()
.then(self._formatLine.bind(self));
});
},
@@ -469,9 +477,12 @@ var StatementModel = BasicModel.extend({
self.valuenow++;
});
return this.performModelRPC("account.bank.statement.line", 'process_reconciliations', [ids, values]).then(function () {
return {handles: handles};
});
return this.rpc("account.bank.statement.line", 'process_reconciliations')
.args([ids, values])
.exec()
.then(function () {
return {handles: handles};
});
},
//--------------------------------------------------------------------------
@@ -530,28 +541,31 @@ var StatementModel = BasicModel.extend({
});
var args = [[prop.tax_id.id], prop.base_amount, line.st_line.currency_id];
tax_defs.push(self.performModelRPC("account.tax", 'json_friendly_compute_all', args).then(function (result) {
var tax = result.taxes[0];
var tax_prop = self._formatQuickCreate(line, {
'link': prop.id,
'tax_id': tax.id,
'amount': tax.amount,
'label': tax.name,
'account_id': tax.account_id ? [tax.account_id, null] : prop.account_id,
'analytic': tax.analytic,
'is_tax': true,
'__focus': false
});
tax_defs.push(self.rpc("account.tax", 'json_friendly_compute_all')
.args(args)
.exec()
.then(function (result) {
var tax = result.taxes[0];
var tax_prop = self._formatQuickCreate(line, {
'link': prop.id,
'tax_id': tax.id,
'amount': tax.amount,
'label': tax.name,
'account_id': tax.account_id ? [tax.account_id, null] : prop.account_id,
'analytic': tax.analytic,
'is_tax': true,
'__focus': false
});
prop.amount = tax.base;
prop.amount_str = field_utils.format.monetary(Math.abs(prop.amount), {}, format_options);
prop.invalid = !self._isValid(prop);
prop.amount = tax.base;
prop.amount_str = field_utils.format.monetary(Math.abs(prop.amount), {}, format_options);
prop.invalid = !self._isValid(prop);
tax_prop.amount_str = field_utils.format.monetary(Math.abs(tax_prop.amount), {}, format_options);
tax_prop.invalid = prop.invalid;
tax_prop.amount_str = field_utils.format.monetary(Math.abs(tax_prop.amount), {}, format_options);
tax_prop.invalid = prop.invalid;
reconciliation_proposition.push(tax_prop);
}));
reconciliation_proposition.push(tax_prop);
}));
} else {
var currencyData = {
currency_id: line.st_line.currency_id
@@ -761,7 +775,9 @@ var StatementModel = BasicModel.extend({
var offset = line.offset;
var limit = 6;
var args = [line.id, line.st_line.partner_id, excluded_ids, filter, offset, limit];
return this.performModelRPC("account.bank.statement.line", 'get_move_lines_for_reconciliation_widget', args)
return this.rpc("account.bank.statement.line", 'get_move_lines_for_reconciliation_widget')
.args(args)
.exec()
.then(this._formatMoveLine.bind(this, handle));
},
/**
@@ -829,7 +845,9 @@ var ManualModel = StatementModel.extend({
case 'suppliers':
var mode = context.mode === 'customers' ? 'receivable' : 'payable';
var args = ['partner', context.partner_ids || null, mode];
return self.performModelRPC("account.move.line", 'get_data_for_manual_reconciliation', args )
return self.rpc("account.move.line", 'get_data_for_manual_reconciliation')
.args(args)
.exec()
.then(function (result) {
var defs = _.map(result, self._formatLine.bind(self, context.mode));
self.valuenow = 0;
@@ -838,7 +856,9 @@ var ManualModel = StatementModel.extend({
});
case 'accounts':
var args = ['account', self.account_ids];
return self.performModelRPC("account.move.line", 'get_data_for_manual_reconciliation', args)
return self.rpc("account.move.line", 'get_data_for_manual_reconciliation')
.args(args)
.exec()
.then(function (result) {
var defs = _.map(result, self._formatLine.bind(self, 'accounts'));
self.valuenow = 0;
@@ -853,7 +873,9 @@ var ManualModel = StatementModel.extend({
account_ids = null; // TOFIX: REMOVE ME
partner_ids = null; // TOFIX: REMOVE ME
var args = [partner_ids, account_ids];
return self.performModelRPC("account.move.line", 'get_data_for_manual_reconciliation_widget', args)
return self.rpc("account.move.line", 'get_data_for_manual_reconciliation_widget')
.args(args)
.exec()
.then(function (result) {
var defs = _.map(result.accounts, self._formatLine.bind(self, 'accounts'));
defs = defs.concat(_.map(result.customers, self._formatLine.bind(self, 'customers')));
@@ -917,7 +939,9 @@ var ManualModel = StatementModel.extend({
});
if (process_reconciliations.length) {
def = self.performModelRPC("account.move.line", 'process_reconciliations', [process_reconciliations]);
def = self.rpc("account.move.line", 'process_reconciliations')
.args([process_reconciliations])
.exec();
}
return def.then(function() {
@@ -944,10 +968,14 @@ var ManualModel = StatementModel.extend({
});
return $.when(defs).then(function() {
if (account_ids.length) {
self.performModelRPC("account.account", 'mark_as_reconciled', [account_ids]);
self.rpc("account.account", 'mark_as_reconciled')
.args([account_ids])
.exec();
}
if (partner_ids.length) {
self.performModelRPC("res.partner", 'mark_as_reconciled', [partner_ids]);
self.rpc("res.partner", 'mark_as_reconciled')
.args([partner_ids])
.exec();
}
return {reconciled: reconciled, updated: _.difference(handles, reconciled)};
});
@@ -1057,7 +1085,9 @@ var ManualModel = StatementModel.extend({
var offset = line.offset;
var limit = 6;
var args = [line.account_id.id, line.partner_id, excluded_ids, filter, offset, limit];
return this.performModelRPC("account.move.line", 'get_move_lines_for_manual_reconciliation', args)
return this.rpc("account.move.line", 'get_move_lines_for_manual_reconciliation')
.args(args)
.exec()
.then(this._formatMoveLine.bind(this, handle));
},
});
+17 -12
View File
@@ -1,8 +1,9 @@
odoo.define('barcodes.BarcodeParser', function (require) {
"use strict";
var ajax = require('web.ajax');
var Class = require('web.Class');
var Model = require('web.DataModel');
var rpc = require('web.rpc');
// The BarcodeParser is used to detect what is the category
// of a barcode (product, partner, ...) and extract an encoded value
@@ -18,19 +19,23 @@ var BarcodeParser = Class.extend({
// only when those data have been loaded
load: function(){
var self = this;
return new Model('barcode.nomenclature')
.query(['name','rule_ids','upc_ean_conv'])
.filter([['id','=',this.nomenclature_id[0]]])
.first()
.then(function(nomenclature){
self.nomenclature = nomenclature;
var id = this.nomenclature_id[0];
rpc.query({model: 'barcode.nomenclature', method: 'read'})
.args([[id], ['name','rule_ids','upc_ean_conv']])
.exec({callback: ajax.rpc.bind(ajax)})
.then(function (nomenclatures){
self.nomenclature = nomenclatures[0];
return new Model('barcode.rule')
.query(['name','sequence','type','encoding','pattern','alias'])
.filter([['barcode_nomenclature_id','=',self.nomenclature.id ]])
.all();
var args = [
[['barcode_nomenclature_id', '=', self.nomenclature.id]],
['name', 'sequence', 'type', 'encoding', 'pattern', 'alias'],
];
return rpc
.query({model: 'barcode.rule', method: 'search_read'})
.args(args)
.exec({callback: ajax.rpc.bind(ajax)});
}).then(function(rules){
rules = rules.sort(function(a,b){ return a.sequence - b.sequence; });
rules = rules.records.sort(function(a, b){ return a.sequence - b.sequence; });
self.nomenclature.rules = rules;
});
},
@@ -7,6 +7,7 @@ var BarcodeEvents = require('barcodes.BarcodeEvents');
var BarcodeHandlerMixin = require('barcodes.BarcodeHandlerMixin');
var KanbanRecord = require('web.KanbanRecord');
var Dialog = require('web.Dialog');
var AbstractField = require('web.AbstractField');
var _t = core._t;
@@ -22,7 +23,7 @@ KanbanRecord.include({
},
});
var FormViewBarcodeHandler = common.AbstractField.extend(BarcodeHandlerMixin, {
var FormViewBarcodeHandler = AbstractField.extend(BarcodeHandlerMixin, {
init: function(parent, context) {
this.__quantity_listener = _.bind(this._set_quantity_listener, this);
BarcodeHandlerMixin.init.apply(this, arguments);
@@ -6,7 +6,6 @@ var core = require('web.core');
var time = require('web.time');
var ListView = require('web.ListView');
var ListController = require('web.ListController');
var Model = require('web.DataModel');
var session = require('web.session');
var Widget = require('web.Widget');
@@ -151,7 +150,6 @@ var DataImport = Widget.extend(ControlPanelMixin, {
this.parent_context = action.params.context || {};
// import object id
this.id = null;
this.Import = new Model('base_import.import');
this.session = session;
action.display_name = _t('Import a File'); // Displayed in the breadcrumbs
this.do_not_change_match = false;
@@ -178,9 +176,9 @@ var DataImport = Widget.extend(ControlPanelMixin, {
);
},
create_model: function() {
return this.Import.call('create', [{
'res_model': this.res_model
}]);
return this.rpc('base_import.import', 'create')
.args([{res_model: this.res_model}])
.exec();
},
renderButtons: function() {
var self = this;
@@ -5,7 +5,7 @@ var SalesTeamDashboard = require('sales_team.dashboard');
SalesTeamDashboard.Model.include({
_fetchDashboardData: function() {
return this.performModelRPC('crm.lead', 'retrieve_sales_dashboard');
return this.rpc('crm.lead', 'retrieve_sales_dashboard').exec();
},
});
+11 -15
View File
@@ -2,7 +2,6 @@ odoo.define('google_drive.google_drive', function (require) {
"use strict";
var data = require('web.data');
var Model = require('web.DataModel');
var Sidebar = require('web.Sidebar');
Sidebar.include({
@@ -56,25 +55,22 @@ Sidebar.include({
});
}
},
fetch: function (model, fields, domain, ctx) {
return new Model(model).query(fields).filter(domain).context(ctx).all();
},
on_google_doc: function (doc_item) {
var self = this;
this.config = doc_item;
var loaded = this.fetch('google.drive.config', ['google_drive_resource_id', 'google_drive_client_id'], [['id', '=', doc_item.config_id]])
var domain = [['id', '=', doc_item.config_id]];
var fields = ['google_drive_resource_id', 'google_drive_client_id'];
this.rpc('google.drive.config', 'search_read')
.args([domain, fields])
.exec()
.then(function (configs) {
var ds = new data.DataSet(self, 'google.drive.config');
ds.call('get_google_drive_url', [doc_item.config_id, doc_item.res_id,configs[0].google_drive_resource_id, self.dataset.context]).done(function (url) {
if (url){
window.open(url, '_blank');
}
var ds = new data.DataSet(self, 'google.drive.config');
ds.call('get_google_drive_url', [doc_item.config_id, doc_item.res_id,configs[0].google_drive_resource_id, self.dataset.context]).done(function (url) {
if (url){
window.open(url, '_blank');
}
});
});
});
},
});
});
@@ -4,7 +4,6 @@ odoo.define('hr_attendance.greeting_message', function (require) {
var BarcodeHandlerMixin = require('barcodes.BarcodeHandlerMixin');
var core = require('web.core');
var Model = require('web.Model');
var Widget = require('web.Widget');
var _t = core._t;
@@ -132,8 +131,9 @@ var GreetingMessage = Widget.extend(BarcodeHandlerMixin, {
if (this.return_to_main_menu) { // in case of multiple scans in the greeting message view, delete the timer, a new one will be created.
clearTimeout(this.return_to_main_menu);
}
var hr_employee = new Model('hr.employee');
hr_employee.call('attendance_scan', [barcode, ])
this.rpc('hr.employee', 'attendance_scan')
.args([barcode, ])
.exec()
.then(function (result) {
if (result.action) {
self.do_action(result.action);
@@ -2,11 +2,8 @@ odoo.define('hr_attendance.kiosk_confirm', function (require) {
"use strict";
var core = require('web.core');
var Model = require('web.Model');
var Widget = require('web.Widget');
var QWeb = core.qweb;
var _t = core._t;
var KioskConfirm = Widget.extend({
@@ -15,16 +12,17 @@ var KioskConfirm = Widget.extend({
"click .o_hr_attendance_sign_in_out_icon": function () {
var self = this;
this.$('.o_hr_attendance_sign_in_out_icon').attr("disabled", "disabled");
var hr_employee = new Model('hr.employee');
hr_employee.call('attendance_manual', [[this.employee_id], this.next_action])
.then(function(result) {
if (result.action) {
self.do_action(result.action);
} else if (result.warning) {
self.do_warn(result.warning);
self.$('.o_hr_attendance_sign_in_out_icon').removeAttr("disabled");
}
});
this.rpc('hr.employee', 'attendance_manual')
.args([[this.employee_id], this.next_action])
.exec()
.then(function(result) {
if (result.action) {
self.do_action(result.action);
} else if (result.warning) {
self.do_warn(result.warning);
self.$('.o_hr_attendance_sign_in_out_icon').removeAttr("disabled");
}
});
},
'click .o_hr_attendance_pin_pad_button_0': function() { this.$('.o_hr_attendance_PINbox').val(this.$('.o_hr_attendance_PINbox').val() + 0); },
'click .o_hr_attendance_pin_pad_button_1': function() { this.$('.o_hr_attendance_PINbox').val(this.$('.o_hr_attendance_PINbox').val() + 1); },
@@ -40,17 +38,18 @@ var KioskConfirm = Widget.extend({
'click .o_hr_attendance_pin_pad_button_ok': function() {
var self = this;
this.$('.o_hr_attendance_pin_pad_button_ok').attr("disabled", "disabled");
var hr_employee = new Model('hr.employee');
hr_employee.call('attendance_manual', [[this.employee_id], this.next_action, this.$('.o_hr_attendance_PINbox').val()])
.then(function(result) {
if (result.action) {
self.do_action(result.action);
} else if (result.warning) {
self.do_warn(result.warning);
self.$('.o_hr_attendance_PINbox').val('');
setTimeout( function() { self.$('.o_hr_attendance_pin_pad_button_ok').removeAttr("disabled"); }, 500);
}
});
this.rpc('hr.employee', 'attendance_manual')
.args([[this.employee_id], this.next_action, this.$('.o_hr_attendance_PINbox').val()])
.exec()
.then(function(result) {
if (result.action) {
self.do_action(result.action);
} else if (result.warning) {
self.do_warn(result.warning);
self.$('.o_hr_attendance_PINbox').val('');
setTimeout( function() { self.$('.o_hr_attendance_pin_pad_button_ok').removeAttr("disabled"); }, 500);
}
});
},
},
@@ -60,7 +59,6 @@ var KioskConfirm = Widget.extend({
this.employee_id = action.employee_id;
this.employee_name = action.employee_name;
this.employee_state = action.employee_state;
var self = this;
},
start: function () {
@@ -2,13 +2,10 @@ odoo.define('hr_attendance.kiosk_mode', function (require) {
"use strict";
var core = require('web.core');
var Model = require('web.Model');
var Widget = require('web.Widget');
var Session = require('web.session');
var BarcodeHandlerMixin = require('barcodes.BarcodeHandlerMixin');
var QWeb = core.qweb;
var _t = core._t;
var KioskMode = Widget.extend(BarcodeHandlerMixin, {
@@ -26,13 +23,12 @@ var KioskMode = Widget.extend(BarcodeHandlerMixin, {
start: function () {
var self = this;
self.session = Session;
var res_company = new Model('res.company');
res_company.query(['name'])
.filter([['id', '=', self.session.company_id]])
.all()
.then(function (companies){
this.rpc('res.company', 'search_read')
.args([[['id', '=', self.session.company_id]], ['name']])
.exec()
.then(function (companies){
self.company_name = companies[0].name;
self.company_image_url = self.session.url('/web/image', {model: 'res.company', id: self.session.company_id, field: 'logo',})
self.company_image_url = self.session.url('/web/image', {model: 'res.company', id: self.session.company_id, field: 'logo',});
self.$el.html(QWeb.render("HrAttendanceKioskMode", {widget: self}));
self.start_clock();
});
@@ -41,8 +37,9 @@ var KioskMode = Widget.extend(BarcodeHandlerMixin, {
on_barcode_scanned: function(barcode) {
var self = this;
var hr_employee = new Model('hr.employee');
hr_employee.call('attendance_scan', [barcode, ])
this.rpc('hr.employee', 'attendance_scan')
.args([barcode, ])
.exec()
.then(function (result) {
if (result.action) {
self.do_action(result.action);
@@ -2,7 +2,6 @@ odoo.define('hr_attendance.my_attendances', function (require) {
"use strict";
var core = require('web.core');
var Model = require('web.Model');
var Widget = require('web.Widget');
var QWeb = core.qweb;
@@ -20,10 +19,9 @@ var MyAttendances = Widget.extend({
start: function () {
var self = this;
var hr_employee = new Model('hr.employee');
hr_employee.query(['attendance_state', 'name'])
.filter([['user_id', '=', self.session.uid]])
.all()
this.rpc('hr.employee', 'search_read')
.args([[['user_id', '=', self.session.uid]], ['attendance_state', 'name']])
.exec()
.then(function (res) {
if (_.isEmpty(res) ) {
self.$('.o_hr_attendance_employee').append(_t("Error : Could not find employee linked to user"));
@@ -38,8 +36,9 @@ var MyAttendances = Widget.extend({
update_attendance: function () {
var self = this;
var hr_employee = new Model('hr.employee');
hr_employee.call('attendance_manual', [[self.employee.id], 'hr_attendance.hr_attendance_action_my_attendances'])
this.rpc('hr.employee', 'attendance_manual')
.args([[self.employee.id], 'hr_attendance.hr_attendance_action_my_attendances'])
.exec()
.then(function(result) {
if (result.action) {
self.do_action(result.action);
@@ -2,12 +2,9 @@ odoo.define('hr_timesheet_sheet.sheet', function (require) {
"use strict";
var concurrency = require('web.concurrency');
var Context = require('web.Context');
var core = require('web.core');
var data = require('web.data');
var form_common = require('web.view_dialogs');
var field_utils = require('web.field_utils');
var Model = require('web.DataModel');
var time = require('web.time');
var QWeb = core.qweb;
@@ -59,8 +56,10 @@ var WeeklyTimesheet = form_common.FormWidget.extend(form_common.ReinitializeWidg
this.querying = true;
var commands = this.field_manager.get_field_value("timesheet_ids");
var self = this;
this.res_o2m_drop.add(new Model(this.view.model).call("resolve_2many_commands",
["timesheet_ids", commands, [], new Context()]))
this.rpc(this.view.model, "resolve_2many_commands")
.args(["timesheet_ids", commands, []])
.exec()
.done(function(result) {
self.set({sheets: result});
self.querying = false;
@@ -111,10 +110,12 @@ var WeeklyTimesheet = form_common.FormWidget.extend(form_common.ReinitializeWidg
var project_names;
var default_get;
var self = this;
return this.render_drop.add(new Model("account.analytic.line").call("default_get", [
['account_id','general_account_id','journal_id','date','name','user_id','product_id','product_uom_id','amount','unit_amount','project_id'],
new Context({'user_id': self.get('user_id')})
]).then(function(result) {
return this.render_drop.add(
this.rpc("account.analytic.line", "default_get")
.args([['account_id','general_account_id','journal_id','date','name','user_id','product_id','product_uom_id','amount','unit_amount','project_id']])
.withContext({'user_id': self.get('user_id')} )
.exec()
.then(function(result) {
default_get = result;
// calculating dates
dates = [];
@@ -136,8 +137,6 @@ var WeeklyTimesheet = form_common.FormWidget.extend(form_common.ReinitializeWidg
})
.groupBy("project_id").value();
var project_ids = _.map(_.keys(projects), function(el) { return el === "false" ? false : Number(el); });
projects = _(projects).chain().map(function(lines, project_id) {
var projects_defaults = _.extend({}, default_get, (projects[project_id] || {}).value || {});
// group by days
@@ -164,17 +163,19 @@ var WeeklyTimesheet = form_common.FormWidget.extend(form_common.ReinitializeWidg
}).value();
// we need the name_get of the projects
return new Model("project.project").call("name_get", [_.pluck(projects, "project"),
new Context()]).then(function(result) {
project_names = {};
_.each(result, function(el) {
project_names[el[0]] = el[1];
this.rpc("project.project", "name_get")
.args([_.pluck(projects, "project")])
.exec()
.then(function(result) {
project_names = {};
_.each(result, function(el) {
project_names[el[0]] = el[1];
});
projects = _.sortBy(projects, function(el) {
return project_names[el.project];
});
});
projects = _.sortBy(projects, function(el) {
return project_names[el.project];
});
});
})).then(function(result) {
})).then(function () {
// we put all the gathered data in self, then we render
self.dates = dates;
self.projects = projects;
@@ -219,8 +220,6 @@ var WeeklyTimesheet = form_common.FormWidget.extend(form_common.ReinitializeWidg
$(this).val(self.sum_box(project, day_count, true));
} else {
project.days[day_count].lines[0].unit_amount += num - self.sum_box(project, day_count);
var product = (project.days[day_count].lines[0].product_id instanceof Array) ? project.days[day_count].lines[0].product_id[0] : project.days[day_count].lines[0].product_id;
var journal = (project.days[day_count].lines[0].journal_id instanceof Array) ? project.days[day_count].lines[0].journal_id[0] : project.days[day_count].lines[0].journal_id;
if(!isNaN($(this).val())){
$(this).val(self.sum_box(project, day_count, true));
+9 -4
View File
@@ -52,14 +52,18 @@ var AbstractActivityField = AbstractField.extend({
// private
_markActivityDone: function (id) {
return this.performModelRPC('mail.activity', 'action_done', [[id]]);
return this.rpc('mail.activity', 'action_done')
.args([[id]])
.exec();
},
_readActivities: function () {
var self = this;
var missing_ids = _.difference(this.value.res_ids, _.pluck(this.activities, 'id'));
var fetch_def;
if (missing_ids.length) {
fetch_def = this.performModelRPC('mail.activity', 'read', [missing_ids]);
fetch_def = this.rpc('mail.activity', 'read')
.args([missing_ids])
.exec();
}
return $.when(fetch_def).then(function (results) {
// filter out activities that are no longer linked to this record
@@ -164,8 +168,9 @@ var Activity = AbstractActivityField.extend({
_onUnlinkActivity: function (event) {
event.preventDefault();
var activity_id = $(event.currentTarget).data('activity-id');
return this
.performModelRPC('mail.activity', 'unlink', [[activity_id]])
return this.rpc('mail.activity', 'unlink')
.args([[activity_id]])
.exec()
.then(this._reload.bind(this, {activity: true}));
},
_onMarkActivityDone: function (event) {
+234 -167
View File
@@ -7,10 +7,11 @@ var config = require('web.config');
var Bus = require('web.Bus');
var core = require('web.core');
var data = require('web.data');
var Model = require('web.Model');
var session = require('web.session');
var time = require('web.time');
var web_client = require('web.web_client');
var Class = require('web.Class');
var Mixins = require('web.mixins');
var _t = core._t;
var _lt = core._lt;
@@ -18,11 +19,6 @@ var LIMIT = 25;
var preview_msg_max_size = 350; // optimal for native english speakers
var ODOOBOT_ID = "ODOOBOT";
var MessageModel = new Model('mail.message', session.user_context);
var ChannelModel = new Model('mail.channel', session.user_context);
var UserModel = new Model('res.users', session.user_context);
var PartnerModel = new Model('res.partner', session.user_context);
// Private model
//----------------------------------------------------------------------------------
var messages = [];
@@ -367,62 +363,6 @@ function remove_message_from_channel (channel_id, message) {
});
}
// options: domain, load_more
function fetch_from_channel (channel, options) {
options = options || {};
var domain =
(channel.id === "channel_inbox") ? [['needaction', '=', true]] :
(channel.id === "channel_starred") ? [['starred', '=', true]] :
[['channel_ids', 'in', channel.id]];
var cache = get_channel_cache(channel, options.domain);
if (options.domain) {
domain = new data.CompoundDomain(domain, options.domain || []);
}
if (options.load_more) {
var min_message_id = cache.messages[0].id;
domain = new data.CompoundDomain([['id', '<', min_message_id]], domain);
}
return MessageModel.call('message_fetch', [domain], {limit: LIMIT, context: session.user_context}).then(function (msgs) {
if (!cache.all_history_loaded) {
cache.all_history_loaded = msgs.length < LIMIT;
}
cache.loaded = true;
_.each(msgs, function (msg) {
add_message(msg, {channel_id: channel.id, silent: true, domain: options.domain});
});
var channel_cache = get_channel_cache(channel, options.domain || []);
return channel_cache.messages;
});
}
// options: force_fetch
function fetch_document_messages (ids, options) {
var loaded_msgs = _.filter(messages, function (message) {
return _.contains(ids, message.id);
});
var loaded_msg_ids = _.pluck(loaded_msgs, 'id');
options = options || {};
if (options.force_fetch || _.difference(ids.slice(0, LIMIT), loaded_msg_ids).length) {
var ids_to_load = _.difference(ids, loaded_msg_ids).slice(0, LIMIT);
return MessageModel.call('message_format', [ids_to_load], {context: session.user_context}).then(function (msgs) {
var processed_msgs = [];
_.each(msgs, function (msg) {
processed_msgs.push(add_message(msg, {silent: true}));
});
return _.sortBy(loaded_msgs.concat(processed_msgs), function (msg) {
return msg.id;
});
});
} else {
return $.when(loaded_msgs);
}
}
function update_channel_unread_counter (channel, counter) {
if (channel.unread_counter > 0 && counter === 0) {
unread_conversation_counter = Math.max(0, unread_conversation_counter-1);
@@ -436,10 +376,6 @@ function update_channel_unread_counter (channel, counter) {
chat_manager.bus.trigger("update_channel_unread_counter", channel);
}
var channel_seen = _.throttle(function (channel) {
return ChannelModel.call('channel_seen', [[channel.id]], {}, {shadow: true});
}, 3000);
// Notification handlers
// ---------------------------------------------------------------------------------
function on_notification (notifications) {
@@ -657,12 +593,137 @@ function on_transient_message_notification (data) {
// Public interface
//----------------------------------------------------------------------------------
var chat_manager = {
var ChatManager = Class.extend(Mixins.EventDispatcherMixin, Mixins.ServicesMixin, {
// these two functions are exposed for extensibility purposes and shouldn't be called by other modules
make_message: make_message,
make_channel: make_channel,
init: function (parent) {
var self = this;
Mixins.EventDispatcherMixin.init.call(this);
this.setParent(parent);
this.bus = new Bus();
this.bus.on('client_action_open', null, function (open) {
client_action_open = open;
});
bus.on('notification', null, on_notification);
this.channel_seen = _.throttle(function (channel) {
return self.rpc('mail.channel', 'channel_seen')
.args([[channel.id]])
.exec({shadow: true});
}, 3000);
},
start: function () {
this.is_ready = session.is_bound.then(function(){
return session.rpc('/mail/client_action');
}).then(this._onMailClientAction.bind(this));
add_channel({
id: "channel_inbox",
name: _lt("Inbox"),
type: "static",
}, { display_needactions: true });
add_channel({
id: "channel_starred",
name: _lt("Starred"),
type: "static"
});
},
_onMailClientAction: function (result) {
_.each(result.channel_slots, function (channels) {
_.each(channels, add_channel);
});
needaction_counter = result.needaction_inbox_counter;
starred_counter = result.starred_counter;
commands = _.map(result.commands, function (command) {
return _.extend({ id: command.name }, command);
});
mention_partner_suggestions = result.mention_partner_suggestions;
discuss_menu_id = result.menu_id;
// Shortcodes: canned responses and emojis
_.each(result.shortcodes, function (s) {
if (s.shortcode_type === 'text') {
canned_responses.push(_.pick(s, ['id', 'source', 'substitution']));
} else {
emojis.push(_.pick(s, ['id', 'source', 'substitution', 'description']));
emoji_substitutions[_.escape(s.source)] = s.substitution;
}
});
bus.start_polling();
},
// options: domain, load_more
_fetchFromChannel: function (channel, options) {
options = options || {};
var domain =
(channel.id === "channel_inbox") ? [['needaction', '=', true]] :
(channel.id === "channel_starred") ? [['starred', '=', true]] :
[['channel_ids', 'in', channel.id]];
var cache = get_channel_cache(channel, options.domain);
if (options.domain) {
domain = new data.CompoundDomain(domain, options.domain || []).eval();
}
if (options.load_more) {
var min_message_id = cache.messages[0].id;
domain = new data.CompoundDomain([['id', '<', min_message_id]], domain).eval();
}
return this.rpc('mail.message', 'message_fetch')
.args([domain])
.kwargs({limit: LIMIT, context: session.user_context})
.exec()
.then(function (msgs) {
if (!cache.all_history_loaded) {
cache.all_history_loaded = msgs.length < LIMIT;
}
cache.loaded = true;
_.each(msgs, function (msg) {
add_message(msg, {channel_id: channel.id, silent: true, domain: options.domain});
});
var channel_cache = get_channel_cache(channel, options.domain || []);
return channel_cache.messages;
});
},
// options: force_fetch
_fetchDocumentMessages : function (ids, options) {
var loaded_msgs = _.filter(messages, function (message) {
return _.contains(ids, message.id);
});
var loaded_msg_ids = _.pluck(loaded_msgs, 'id');
options = options || {};
if (options.force_fetch || _.difference(ids.slice(0, LIMIT), loaded_msg_ids).length) {
var ids_to_load = _.difference(ids, loaded_msg_ids).slice(0, LIMIT);
return this.rpc('mail.message', 'message_format')
.args([ids_to_load])
.kwargs({context: session.user_context})
.exec()
.then(function (msgs) {
var processed_msgs = [];
_.each(msgs, function (msg) {
processed_msgs.push(add_message(msg, {silent: true}));
});
return _.sortBy(loaded_msgs.concat(processed_msgs), function (msg) {
return msg.id;
});
});
} else {
return $.when(loaded_msgs);
}
},
post_message: function (data, options) {
var self = this;
options = options || {};
// This message will be received from the mail composer as html content subtype
@@ -682,12 +743,15 @@ var chat_manager = {
}
if ('channel_id' in options) {
// post a message in a channel or execute a command
return ChannelModel.call(data.command ? 'execute_command' : 'message_post', [options.channel_id], _.extend(msg, {
message_type: 'comment',
content_subtype: 'html',
subtype: 'mail.mt_comment',
command: data.command,
}));
return this.rpc('mail.channel', data.command ? 'execute_command' : 'message_post')
.args([options.channel_id])
.kwargs(_.extend(msg, {
message_type: 'comment',
content_subtype: 'html',
subtype: 'mail.mt_comment',
command: data.command,
}))
.exec();
}
if ('model' in options && 'res_id' in options) {
// post a message in a chatter
@@ -699,14 +763,20 @@ var chat_manager = {
subtype_id: data.subtype_id,
});
var model = new Model(options.model);
return model.call('message_post', [options.res_id], msg).then(function (msg_id) {
return MessageModel.call('message_format', [msg_id]).then(function (msgs) {
msgs[0].model = options.model;
msgs[0].res_id = options.res_id;
add_message(msgs[0]);
return this.rpc(options.model, 'message_post')
.args([options.res_id])
.kwargs(msg)
.exec()
.then(function (msg_id) {
return self.rpc('mail.message', 'message_format')
.args([msg_id])
.exec()
.then(function (msgs) {
msgs[0].model = options.model;
msgs[0].res_id = options.res_id;
add_message(msgs[0]);
});
});
});
}
},
@@ -719,7 +789,7 @@ var chat_manager = {
if ('channel_id' in options && options.load_more) {
// get channel messages, force load_more
channel = this.get_channel(options.channel_id);
return fetch_from_channel(channel, {domain: options.domain || {}, load_more: true});
return this._fetchFromChannel(channel, {domain: options.domain || {}, load_more: true});
}
if ('channel_id' in options) {
// channel message, check in cache first
@@ -728,12 +798,12 @@ var chat_manager = {
if (channel_cache.loaded) {
return $.when(channel_cache.messages);
} else {
return fetch_from_channel(channel, {domain: options.domain});
return this._fetchFromChannel(channel, {domain: options.domain});
}
}
if ('ids' in options) {
// get messages from their ids (chatter is the main use case)
return fetch_document_messages(options.ids, options).then(function(result) {
return this._fetchDocumentMessages(options.ids, options).then(function(result) {
chat_manager.mark_as_read(options.ids);
return result;
});
@@ -742,16 +812,24 @@ var chat_manager = {
// get messages for a chatter, when it doesn't know the ids (use
// case is when using the full composer)
var domain = [['model', '=', options.model], ['res_id', '=', options.res_id]];
MessageModel.call('message_fetch', [domain], {limit: 30}).then(function (msgs) {
return _.map(msgs, add_message);
});
this.rpc('mail.message', 'message_fetch')
.args([domain])
.kwargs({limit: 30})
.exec()
.then(function (msgs) {
return _.map(msgs, add_message);
});
}
},
toggle_star_status: function (message_id) {
return MessageModel.call('toggle_message_starred', [[message_id]]);
return this.rpc('mail.message', 'toggle_message_starred')
.args([[message_id]])
.exec();
},
unstar_all: function () {
return MessageModel.call('unstar_all', [[]], {});
return this.rpc('mail.message', 'unstar_all')
.args([[]])
.exec();
},
mark_as_read: function (message_ids) {
var ids = _.filter(message_ids, function (id) {
@@ -760,24 +838,30 @@ var chat_manager = {
return !message || message.is_needaction;
});
if (ids.length) {
return MessageModel.call('set_message_done', [ids]);
return this.rpc('mail.message', 'set_message_done')
.args([ids])
.exec();
} else {
return $.when();
}
},
mark_all_as_read: function (channel, domain) {
if ((channel.id === "channel_inbox" && needaction_counter) || (channel && channel.needaction_counter)) {
return MessageModel.call('mark_all_as_read', [], {channel_ids: channel.id !== "channel_inbox" ? [channel.id] : [], domain: domain});
return this.rpc('mail.message', 'mark_all_as_read')
.kwargs({channel_ids: channel.id !== "channel_inbox" ? [channel.id] : [], domain: domain})
.exec();
}
return $.when();
},
undo_mark_as_read: function (message_ids, channel) {
return MessageModel.call('mark_as_unread', [message_ids, [channel.id]]);
return this.rpc('mail.message', 'mark_as_unread')
.args([message_ids, [channel.id]])
.exec();
},
mark_channel_as_seen: function (channel) {
if (channel.unread_counter > 0 && channel.type !== 'static') {
update_channel_unread_counter(channel, 0);
channel_seen(channel);
this.channel_seen(channel);
}
},
@@ -802,8 +886,9 @@ var chat_manager = {
return mention_partner_suggestions;
}
if (!channel.members_deferred) {
channel.members_deferred = ChannelModel
.call("channel_fetch_listeners", [channel.uuid], {}, {shadow: true})
channel.members_deferred = this.rpc('mail.channel', "channel_fetch_listeners")
.args([channel.uuid])
.exec({shadow: true})
.then(function (members) {
var suggestions = [];
_.each(mention_partner_suggestions, function (partners) {
@@ -864,21 +949,23 @@ var chat_manager = {
},
detach_channel: function (channel) {
return ChannelModel.call("channel_minimize", [channel.uuid, true], {}, {shadow: true});
return this.rpc('mail.channel', "channel_minimize")
.args([channel.uuid, true])
.exec({shadow: true});
},
remove_chatter_messages: function (model) {
messages = _.reject(messages, function (message) {
return message.channel_ids.length === 0 && message.model === model;
});
},
bus: new Bus(),
create_channel: function (name, type) {
var method = type === "dm" ? "channel_get" : "channel_create";
var args = type === "dm" ? [[name]] : [name, type];
return ChannelModel
.call(method, args)
return this.rpc('mail.channel', method)
.args(args)
.exec()
.then(add_channel);
},
join_channel: function (channel_id, options) {
@@ -891,8 +978,9 @@ var chat_manager = {
// channel already joined
channel_defs[channel_id] = $.when(channel);
} else {
channel_defs[channel_id] = ChannelModel
.call('channel_join_and_get_info', [[channel_id]])
channel_defs[channel_id] = this.rpc('mail.channel', 'channel_join_and_get_info')
.args([[channel_id]])
.exec()
.then(function (result) {
return add_channel(result, options);
});
@@ -900,7 +988,10 @@ var chat_manager = {
return channel_defs[channel_id];
},
open_and_detach_dm: function (partner_id) {
return ChannelModel.call('channel_get_and_minimize', [[partner_id]]).then(add_channel);
return this.rpc('mail.channel', 'channel_get_and_minimize')
.args([[partner_id]])
.exec()
.then(add_channel);
},
open_channel: function (channel) {
chat_manager.bus.trigger(client_action_open ? 'open_channel' : 'detach_channel', channel);
@@ -908,14 +999,20 @@ var chat_manager = {
unsubscribe: function (channel) {
if (_.contains(['public', 'private'], channel.type)) {
return ChannelModel.call('action_unfollow', [[channel.id]]);
return this.rpc('mail.channel', 'action_unfollow')
.args([[channel.id]])
.exec();
} else {
return ChannelModel.call('channel_pin', [channel.uuid, false]);
return this.rpc('mail.channel', 'channel_pin')
.args([channel.uuid, false])
.exec();
}
},
close_chat_session: function (channel_id) {
var channel = this.get_channel(channel_id);
ChannelModel.call("channel_fold", [], {uuid : channel.uuid, state : "closed"}, {shadow: true});
this.rpc('mail.channel', "channel_fold")
.kwargs({uuid : channel.uuid, state : "closed"})
.exec({shadow: true});
},
fold_channel: function (channel_id, folded) {
var args = {
@@ -924,7 +1021,9 @@ var chat_manager = {
if (_.isBoolean(folded)) {
args.state = folded ? 'folded' : 'open';
}
return ChannelModel.call("channel_fold", [], args, {shadow: true});
return this.rpc('mail.channel', "channel_fold")
.kwargs(args)
.exec({shadow: true});
},
/**
* Special redirection handling for given model and id
@@ -947,17 +1046,23 @@ var chat_manager = {
};
if (res_model === "res.partner") {
var domain = [["partner_id", "=", res_id]];
UserModel.call("search", [domain]).then(function (user_ids) {
if (user_ids.length && user_ids[0] !== session.uid && dm_redirection_callback) {
self.create_channel(res_id, 'dm').then(dm_redirection_callback);
} else {
redirect_to_document(res_model, res_id);
}
});
this.rpc('res.users', "search")
.args([domain])
.exec()
.then(function (user_ids) {
if (user_ids.length && user_ids[0] !== session.uid && dm_redirection_callback) {
self.create_channel(res_id, 'dm').then(dm_redirection_callback);
} else {
redirect_to_document(res_model, res_id);
}
});
} else {
new Model(res_model).call('get_formview_id', [[res_id], session.user_context]).then(function (view_id) {
redirect_to_document(res_model, res_id, view_id);
});
this.rpc(res_model, 'get_formview_id')
.args([[res_id], session.user_context])
.exec()
.then(function (view_id) {
redirect_to_document(res_model, res_id, view_id);
});
}
},
@@ -978,7 +1083,9 @@ var chat_manager = {
if (!channels_preview_def) {
if (missing_channels.length) {
var missing_channel_ids = _.pluck(missing_channels, 'id');
channels_preview_def = ChannelModel.call('channel_fetch_preview', [missing_channel_ids], {}, {shadow: true});
channels_preview_def = this.rpc('mail.channel', 'channel_fetch_preview')
.args([missing_channel_ids])
.exec({shadow: true});
} else {
channels_preview_def = $.when();
}
@@ -1013,7 +1120,9 @@ var chat_manager = {
});
if (!values.length) {
// extend the research to all users
def = PartnerModel.call('im_search', [search_val, limit || 20], {}, {shadow: true});
def = this.rpc('res.partner', 'im_search')
.args([search_val, limit || 20])
.exec({shadow: true});
} else {
def = $.when(values);
}
@@ -1024,58 +1133,16 @@ var chat_manager = {
return _.sortBy(autocomplete_data, 'label');
});
},
};
chat_manager.bus.on('client_action_open', null, function (open) {
client_action_open = open;
});
// Initialization
// ---------------------------------------------------------------------------------
function init () {
add_channel({
id: "channel_inbox",
name: _lt("Inbox"),
type: "static",
}, { display_needactions: true });
add_channel({
id: "channel_starred",
name: _lt("Starred"),
type: "static"
});
bus.on('notification', null, on_notification);
return session.is_bound.then(function(){
return session.rpc('/mail/client_action');
}).then(function (result) {
_.each(result.channel_slots, function (channels) {
_.each(channels, add_channel);
});
needaction_counter = result.needaction_inbox_counter;
starred_counter = result.starred_counter;
commands = _.map(result.commands, function (command) {
return _.extend({ id: command.name }, command);
});
mention_partner_suggestions = result.mention_partner_suggestions;
discuss_menu_id = result.menu_id;
// Shortcodes: canned responses and emojis
_.each(result.shortcodes, function (s) {
if (s.shortcode_type === 'text') {
canned_responses.push(_.pick(s, ['id', 'source', 'substitution']));
} else {
emojis.push(_.pick(s, ['id', 'source', 'substitution', 'description']));
emoji_substitutions[_.escape(s.source)] = s.substitution;
}
});
bus.start_polling();
});
}
chat_manager.is_ready = init();
var CallService = Class.extend(Mixins.EventDispatcherMixin, Mixins.ServiceProvider, {
init: function () {
Mixins.ServiceProvider.init.call(this);
Mixins.EventDispatcherMixin.init.call(this);
},
});
var chat_manager = new ChatManager(new CallService());
chat_manager.start();
return chat_manager;
+20 -17
View File
@@ -245,25 +245,28 @@ var Chatter = Widget.extend(chat_mixin, {
this.suggested_partners_def = $.Deferred();
var method = 'message_get_suggested_recipients';
var args = [[this.context.default_res_id], this.context];
this.performModelRPC(this.record.model, method, args).then(function (result) {
if (!self.suggested_partners_def) {
return; // widget has been reset (e.g. we just switched to another record)
}
var suggested_partners = [];
var thread_recipients = result[self.context.default_res_id];
_.each(thread_recipients, function (recipient) {
var parsed_email = utils.parse_email(recipient[1]);
suggested_partners.push({
checked: true,
partner_id: recipient[0],
full_name: recipient[1],
name: parsed_email[0],
email_address: parsed_email[1],
reason: recipient[2],
this.rpc(this.record.model, method)
.args(args)
.exec()
.then(function (result) {
if (!self.suggested_partners_def) {
return; // widget has been reset (e.g. we just switched to another record)
}
var suggested_partners = [];
var thread_recipients = result[self.context.default_res_id];
_.each(thread_recipients, function (recipient) {
var parsed_email = utils.parse_email(recipient[1]);
suggested_partners.push({
checked: true,
partner_id: recipient[0],
full_name: recipient[1],
name: parsed_email[0],
email_address: parsed_email[1],
reason: recipient[2],
});
});
self.suggested_partners_def.resolve(suggested_partners);
});
self.suggested_partners_def.resolve(suggested_partners);
});
}
this.suggested_partners_def.then(function (suggested_partners) {
self._openComposer({ is_log: false, suggested_partners: suggested_partners });
@@ -125,7 +125,9 @@ var ChatterComposer = composer.BasicComposer.extend({
var def;
if (names_to_find.length > 0) {
var args = [[this.context.default_res_id], names_to_find];
def = this.performModelRPC(this.model, 'message_partner_info_from_emails', args);
def = this.rpc(this.model, 'message_partner_info_from_emails')
.args(args)
.exec();
}
// for unknown names + incomplete partners -> open popup - cancel = remove from recipients
@@ -171,7 +173,9 @@ var ChatterComposer = composer.BasicComposer.extend({
var def;
if (new_names_to_find.length > 0) {
var args = [[self.context.default_res_id], new_names_to_find, true];
self.performModelRPC(self.model, 'message_partner_info_from_emails', args);
self.rpc(self.model, 'message_partner_info_from_emails')
.args(args)
.exec();
}
$.when(def).pipe(function (result) {
result = result || [];
+17 -14
View File
@@ -12,7 +12,6 @@ var core = require('web.core');
var data = require('web.data');
var Dialog = require('web.Dialog');
var dom = require('web.dom');
var Model = require('web.Model');
var pyeval = require('web.pyeval');
var SearchView = require('web.SearchView');
@@ -70,8 +69,10 @@ var PartnerInviteDialog = Dialog.extend({
var self = this;
var data = this.$input.select2('data');
if(data.length >= 1){
var ChannelModel = new Model('mail.channel');
return ChannelModel.call('channel_invite', [this.channel_id], {partner_ids: _.pluck(data, 'id')})
return this.rpc('mail.channel', 'channel_invite')
.args([this.channel_id])
.kwargs({partner_ids: _.pluck(data, 'id')})
.exec()
.then(function(){
var names = _.escape(_.pluck(data, 'text').join(', '));
var notification = _.str.sprintf(_t('You added <b>%s</b> to the conversation.'), names);
@@ -380,18 +381,20 @@ var ChatAction = Widget.extend(ControlPanelMixin, {
},
do_search_channel: function(search_val){
var Channel = new Model("mail.channel");
return Channel.call('channel_search_to_join', [search_val]).then(function(result){
var values = [];
_.each(result, function(channel){
var escaped_name = _.escape(channel.name);
values.push(_.extend(channel, {
'value': escaped_name,
'label': escaped_name,
}));
return this.rpc('mail.channel', 'channel_search_to_join')
.args([search_val])
.exec()
.then(function(result){
var values = [];
_.each(result, function(channel){
var escaped_name = _.escape(channel.name);
values.push(_.extend(channel, {
'value': escaped_name,
'label': escaped_name,
}));
});
return values;
});
return values;
});
},
set_channel: function (channel) {
+9 -9
View File
@@ -7,7 +7,6 @@ var utils = require('mail.utils');
var core = require('web.core');
var data = require('web.data');
var dom = require('web.dom');
var Model = require('web.Model');
var session = require('web.session');
var Widget = require('web.Widget');
@@ -417,9 +416,6 @@ var BasicComposer = Widget.extend(chat_mixin, {
// Emojis
this.emoji_container_classname = 'o_composer_emoji';
this.PartnerModel = new Model('res.partner');
this.ChannelModel = new Model('mail.channel');
},
start: function () {
@@ -665,18 +661,22 @@ var BasicComposer = Widget.extend(chat_mixin, {
// Mention
mention_fetch_throttled: function (model, method, kwargs) {
var self = this;
// Delays the execution of the RPC to prevent unnecessary RPCs when the user is still typing
var def = $.Deferred();
clearTimeout(this.mention_fetch_timer);
this.mention_fetch_timer = setTimeout(function () {
return model.call(method, kwargs).then(function (results) {
def.resolve(results);
});
return self.rpc(model, method)
.kwargs(kwargs)
.exec()
.then(function (results) {
def.resolve(results);
});
}, 200);
return def;
},
mention_fetch_channels: function (search) {
return this.mention_fetch_throttled(this.ChannelModel, 'get_mention_suggestions', {
return this.mention_fetch_throttled('mail.channel', 'get_mention_suggestions', {
limit: this.options.mention_fetch_limit,
search: search,
}).then(function (suggestions) {
@@ -706,7 +706,7 @@ var BasicComposer = Widget.extend(chat_mixin, {
});
if (!suggestions.length && !self.options.mention_partners_restricted) {
// no result found among prefetched partners, fetch other suggestions
suggestions = self.mention_fetch_throttled(self.PartnerModel, 'get_mention_suggestions', {
suggestions = mention_fetch_throttled('res.partner', 'get_mention_suggestions', {
limit: limit,
search: search,
});
+11 -3
View File
@@ -219,7 +219,10 @@ var Followers = AbstractField.extend({
partner_ids: [this.partnerID],
context: {}, // new Context(this.build_context(), {}) // fixme
};
this.performModelRPC(this.model, 'message_subscribe', [[this.res_id]], kwargs)
this.rpc(this.model, 'message_subscribe')
.args([[this.res_id]])
.kwargs(kwargs)
.exec()
.then(this._reload.bind(this));
},
/**
@@ -239,7 +242,9 @@ var Followers = AbstractField.extend({
ids.channel_ids,
{}, // new Context(self.build_context(), {}) // fixme
];
self.performModelRPC(self.model, 'message_unsubscribe', args)
self.rpc(self.model, 'message_unsubscribe')
.args(args)
.exec()
.then(self._reload.bind(self));
def.resolve();
},
@@ -281,7 +286,10 @@ var Followers = AbstractField.extend({
var kwargs = _.extend({}, ids);
kwargs.subtype_ids = checklist;
kwargs.context = {}; // new Context(this.build_context(), {}); // fixme
this.performModelRPC(this.model, 'message_subscribe', [[this.res_id]], kwargs)
this.rpc(this.model, 'message_subscribe')
.args([[this.res_id]])
.kwargs(kwargs)
.exec()
.then(this._reload.bind(this));
}
},
+17 -14
View File
@@ -1,8 +1,9 @@
odoo.define('point_of_sale.devices', function (require) {
"use strict";
var ajax = require('web.ajax');
var core = require('web.core');
var Model = require('web.DataModel');
var rpc = require('web.rpc');
var Session = require('web.Session');
var QWeb = core.qweb;
@@ -440,19 +441,21 @@ var ProxyDevice = core.Class.extend(core.mixins.PropertiesMixin,{
print_sale_details: function() {
var self = this;
new Model('report.point_of_sale.report_saledetails').call('get_sale_details').then(function(result){
var env = {
company: self.pos.company,
pos: self.pos,
products: result.products,
payments: result.payments,
taxes: result.taxes,
total_paid: result.total_paid,
date: (new Date()).toLocaleString(),
};
var report = QWeb.render('SaleDetailsReport', env);
self.print_receipt(report);
})
rpc.query({model: 'report.point_of_sale.report_saledetails', method: 'get_sale_details'})
.exec({callback: ajax.rpc.bind(ajax)})
.then(function(result){
var env = {
company: self.pos.company,
pos: self.pos,
products: result.products,
payments: result.payments,
taxes: result.taxes,
total_paid: result.total_paid,
date: (new Date()).toLocaleString(),
};
var report = QWeb.render('SaleDetailsReport', env);
self.print_receipt(report);
});
},
update_customer_facing_display: function(html) {
@@ -7,7 +7,6 @@ odoo.define('point_of_sale.gui', function (require) {
// it is available to all pos objects trough the '.gui' field.
var core = require('web.core');
var Model = require('web.DataModel');
var field_utils = require('web.field_utils');
var session = require('web.session');
+64 -64
View File
@@ -1,13 +1,14 @@
odoo.define('point_of_sale.models', function (require) {
"use strict";
var ajax = require('web.ajax');
var BarcodeParser = require('barcodes.BarcodeParser');
var PosDB = require('point_of_sale.DB');
var devices = require('point_of_sale.devices');
var concurrency = require('web.concurrency');
var core = require('web.core');
var Model = require('web.DataModel');
var field_utils = require('web.field_utils');
var rpc = require('web.rpc');
var session = require('web.session');
var time = require('web.time');
var utils = require('web.utils');
@@ -316,7 +317,7 @@ exports.PosModel = Backbone.Model.extend({
fields: ['display_name', 'list_price','price','pos_categ_id', 'taxes_id', 'barcode', 'default_code',
'to_weight', 'uom_id', 'description_sale', 'description',
'product_tmpl_id','tracking'],
order: ['sequence','default_code','name'],
order: _.map(['sequence','default_code','name'], function (name) { return {name: name}; }),
domain: [['sale_ok','=',true],['available_in_pos','=',true]],
context: function(self){ return { pricelist: self.pricelist.id, display_default_code: false }; },
loaded: function(self, products){
@@ -494,31 +495,32 @@ exports.PosModel = Backbone.Model.extend({
var ids = typeof model.ids === 'function' ? model.ids(self,tmp) : model.ids;
var order = typeof model.order === 'function' ? model.order(self,tmp): model.order;
progress += progress_step;
var records;
if( model.model ){
if (model.ids) {
records = new Model(model.model).call('read',[ids,fields],context);
} else {
records = new Model(model.model)
.query(fields)
.filter(domain)
.order_by(order)
.context(context)
.all();
var method = model.ids ? 'read' : 'search_read';
var args = model.ids ? [ids, fields] : [domain, fields];
var query = rpc
.query({model: model.model, method: method})
.args(args)
.withContext(context);
if (method === 'search_read') {
query = query.orderBy(order);
}
records.then(function(result){
try{ // catching exceptions in model.loaded(...)
$.when(model.loaded(self,result,tmp))
.then(function(){ load_model(index + 1); },
function(err){ loaded.reject(err); });
}catch(err){
console.error(err.stack);
loaded.reject(err);
query.exec({callback: ajax.rpc.bind(ajax)}).then(function(result){
try{ // catching exceptions in model.loaded(...)
if (method === 'search_read') {
result = result.records;
}
},function(err){
$.when(model.loaded(self,result,tmp))
.then(function(){ load_model(index + 1); },
function(err){ loaded.reject(err); });
}catch(err){
console.error(err.stack);
loaded.reject(err);
});
}
},function(err){
loaded.reject(err);
});
}else if( model.loaded ){
try{ // catching exceptions in model.loaded(...)
$.when(model.loaded(self,tmp))
@@ -548,17 +550,18 @@ exports.PosModel = Backbone.Model.extend({
var self = this;
var def = new $.Deferred();
var fields = _.find(this.models,function(model){ return model.model === 'res.partner'; }).fields;
new Model('res.partner')
.query(fields)
.filter([['customer','=',true],['write_date','>',this.db.get_partner_write_date()]])
.all({'timeout':3000, 'shadow': true})
.then(function(partners){
if (self.db.add_partners(partners)) { // check if the partners we got were real updates
var domain = [['customer','=',true],['write_date','>',this.db.get_partner_write_date()]];
var rpcOptions = {timeout:3000, shadow: true};
rpc.query({model: 'res.partner', method: 'search_read'})
.args([domain, fields])
.exec({callback: ajax.rpc.bind(ajax), callbackOptions: rpcOptions})
.then(function(partners){
if (self.db.add_partners(partners.records)) { // check if the partners we got were real updates
def.resolve();
} else {
def.reject();
}
}, function(err,event){ event.preventDefault(); def.reject(); });
}, function(err,event){ event.preventDefault(); def.reject(); });
return def;
},
@@ -882,44 +885,41 @@ exports.PosModel = Backbone.Model.extend({
// we try to send the order. shadow prevents a spinner if it takes too long. (unless we are sending an invoice,
// then we want to notify the user that we are waiting on something )
var posOrderModel = new Model('pos.order');
return posOrderModel.call('create_from_ui',
[_.map(orders, function (order) {
var args = [_.map(orders, function (order) {
order.to_invoice = options.to_invoice || false;
return order;
})],
undefined,
{
shadow: !options.to_invoice,
timeout: timeout
}
).then(function (server_ids) {
_.each(order_ids_to_sync, function (order_id) {
self.db.remove_order(order_id);
});
self.set('failed',false);
return server_ids;
}).fail(function (error, event){
if(error.code === 200 ){ // Business Logic Error, not a connection problem
//if warning do not need to display traceback!!
if (error.data.exception_type == 'warning') {
delete error.data.debug;
}
})];
var rpcOptions = {timeout: timeout, shadow: !options.to_invoice};
rpc.query({model: 'pos.order', method: 'create_from_ui'})
.args(args)
.exec({callback: ajax.rpc.bind(ajax), callbackOptions: rpcOptions})
.then(function (server_ids) {
_.each(order_ids_to_sync, function (order_id) {
self.db.remove_order(order_id);
});
self.set('failed',false);
return server_ids;
}).fail(function (error, event){
if(error.code === 200 ){ // Business Logic Error, not a connection problem
//if warning do not need to display traceback!!
if (error.data.exception_type == 'warning') {
delete error.data.debug;
}
// Hide error if already shown before ...
if ((!self.get('failed') || options.show_error) && !options.to_invoice) {
self.gui.show_popup('error-traceback',{
'title': error.data.message,
'body': error.data.debug
});
// Hide error if already shown before ...
if ((!self.get('failed') || options.show_error) && !options.to_invoice) {
self.gui.show_popup('error-traceback',{
'title': error.data.message,
'body': error.data.debug
});
}
self.set('failed',error);
}
self.set('failed',error)
}
// prevent an error popup creation by the rpc failure
// we want the failure to be silent as we send the orders in the background
event.preventDefault();
console.error('Failed to send orders:', orders);
});
// prevent an error popup creation by the rpc failure
// we want the failure to be silent as we send the orders in the background
event.preventDefault();
console.error('Failed to send orders:', orders);
});
},
scan_product: function(parsed_code){
+13 -9
View File
@@ -30,8 +30,9 @@ odoo.define('point_of_sale.screens', function (require) {
var PosBaseWidget = require('point_of_sale.BaseWidget');
var gui = require('point_of_sale.gui');
var models = require('point_of_sale.models');
var ajax = require('web.ajax');
var core = require('web.core');
var Model = require('web.DataModel');
var rpc = require('web.rpc');
var utils = require('web.utils');
var field_utils = require('web.field_utils');
@@ -1209,15 +1210,18 @@ var ClientListScreenWidget = ScreenWidget.extend({
fields.id = partner.id || false;
fields.country_id = fields.country_id || false;
new Model('res.partner').call('create_from_ui',[fields]).then(function(partner_id){
self.saved_client_details(partner_id);
},function(err,event){
event.preventDefault();
self.gui.show_popup('error',{
'title': _t('Error: Could not Save Changes'),
'body': _t('Your Internet connection is probably down.'),
rpc.query({model: 'res.partner', method: 'create_from_ui'})
.args([fields])
.exec({callback: ajax.rpc.bind(ajax)})
.then(function(partner_id){
self.saved_client_details(partner_id);
},function(err,event){
event.preventDefault();
self.gui.show_popup('error',{
'title': _t('Error: Could not Save Changes'),
'body': _t('Your Internet connection is probably down.'),
});
});
});
},
// what happens when we've just pushed modifications for a partner of id partner_id
+41 -38
View File
@@ -1,43 +1,46 @@
odoo.define('pos_cache.pos_cache', function (require) {
"use strict";
var core = require('web.core');
var models = require('point_of_sale.models');
var Model = require('web.DataModel');
var _t = core._t;
"use strict";
var posmodel_super = models.PosModel.prototype;
models.PosModel = models.PosModel.extend({
load_server_data: function () {
var self = this;
var models = require('point_of_sale.models');
var ajax = require('web.ajax');
var core = require('web.core');
var rpc = require('web.rpc');
var _t = core._t;
var product_index = _.findIndex(this.models, function (model) {
return model.model === "product.product";
var posmodel_super = models.PosModel.prototype;
models.PosModel = models.PosModel.extend({
load_server_data: function () {
var self = this;
var product_index = _.findIndex(this.models, function (model) {
return model.model === "product.product";
});
// Give both the fields and domain to pos_cache in the
// backend. This way we don't have to hardcode these
// values in the backend and they automatically stay in
// sync with whatever is defined (and maybe extended by
// other modules) in js.
var product_model = this.models[product_index];
var product_fields = product_model.fields;
var product_domain = product_model.domain;
// We don't want to load product.product the normal
// uncached way, so get rid of it.
if (product_index !== -1) {
this.models.splice(product_index, 1);
}
return posmodel_super.load_server_data.apply(this, arguments).then(function () {
var records = rpc.query({model: 'pos.config', method: 'get_products_from_cache'})
.args([self.pos_session.config_id[0], product_fields, product_domain])
.exec({callback: ajax.rpc.bind(ajax)});
self.chrome.loading_message(_t('Loading') + ' product.product', 1);
return records.then(function (product) {
self.db.add_products(product);
});
// Give both the fields and domain to pos_cache in the
// backend. This way we don't have to hardcode these
// values in the backend and they automatically stay in
// sync with whatever is defined (and maybe extended by
// other modules) in js.
var product_model = this.models[product_index];
var product_fields = product_model.fields;
var product_domain = product_model.domain;
// We don't want to load product.product the normal
// uncached way, so get rid of it.
if (product_index !== -1) {
this.models.splice(product_index, 1);
}
return posmodel_super.load_server_data.apply(this, arguments).then(function () {
var records = new Model('pos.config').call('get_products_from_cache',
[self.pos_session.config_id[0], product_fields, product_domain]);
self.chrome.loading_message(_t('Loading') + ' product.product', 1);
return records.then(function (product) {
self.db.add_products(product);
});
});
},
});
});
},
});
});
+122 -124
View File
@@ -1,26 +1,21 @@
odoo.define('pos_mercury.pos_mercury', function (require) {
"use strict";
var Class = require('web.Class');
var Model = require('web.Model');
var session = require('web.session');
var ajax = require('web.ajax');
var core = require('web.core');
var rpc = require('web.rpc');
var screens = require('point_of_sale.screens');
var gui = require('point_of_sale.gui');
var pos_model = require('point_of_sale.models');
var utils = require('web.utils');
var _t = core._t;
var BarcodeParser = require('barcodes.BarcodeParser');
var PopupWidget = require('point_of_sale.popups');
var ScreenWidget = screens.ScreenWidget;
var PaymentScreenWidget = screens.PaymentScreenWidget;
var round_pr = utils.round_precision;
pos_model.load_fields("account.journal", "pos_mercury_config_id");
var _modelproto = pos_model.PosModel.prototype;
pos_model.PosModel = pos_model.PosModel.extend({
getOnlinePaymentJournals: function () {
var self = this;
@@ -394,97 +389,99 @@ PaymentScreenWidget.include({
});
}
var mercury_transaction = new Model('pos_mercury.mercury_transaction');
mercury_transaction.call('do_payment', [transaction], undefined, {timeout: self.server_timeout_in_ms}).then(function (data) {
// if not receiving a response from Mercury, we should retry
if (data === "timeout") {
self.retry_mercury_transaction(def, null, retry_nr, true, self.credit_code_transaction, [parsed_result, def, retry_nr + 1]);
return;
}
rpc.query({model: 'pos_mercury.mercury_transaction', method: 'do_payment'})
.args([transaction])
.exec({timeout: self.server_timeout_in_ms, callback: ajax.rpc.bind(ajax)})
.then(function (data) {
// if not receiving a response from Mercury, we should retry
if (data === "timeout") {
self.retry_mercury_transaction(def, null, retry_nr, true, self.credit_code_transaction, [parsed_result, def, retry_nr + 1]);
return;
}
if (data === "not setup") {
def.resolve({
message: _t("Please setup your Mercury merchant account.")
});
return;
}
if (data === "internal error") {
def.resolve({
message: _t("Odoo error while processing transaction.")
});
return;
}
var response = self.pos.decodeMercuryResponse(data);
response.journal_id = parsed_result.journal_id;
if (response.status === 'Approved') {
// AP* indicates a duplicate request, so don't add anything for those
if (response.message === "AP*" && self._does_credit_payment_line_exist(response.authorize, decodedMagtek['number'],
response.card_type, decodedMagtek['name'])) {
if (data === "not setup") {
def.resolve({
message: lookUpCodeTransaction["Approved"][response.error],
auto_close: true,
message: _t("Please setup your Mercury merchant account.")
});
} else {
// If the payment is approved, add a payment line
var order = self.pos.get_order();
return;
}
if (swipe_pending_line) {
order.select_paymentline(swipe_pending_line);
} else {
order.add_paymentline(self.pos.getCashRegisterByJournalID(parsed_result.journal_id));
}
if (data === "internal error") {
def.resolve({
message: _t("Odoo error while processing transaction.")
});
return;
}
order.selected_paymentline.paid = true;
order.selected_paymentline.mercury_swipe_pending = false;
order.selected_paymentline.mercury_amount = response.authorize;
order.selected_paymentline.mercury_card_number = decodedMagtek['number'];
order.selected_paymentline.mercury_card_brand = response.card_type;
order.selected_paymentline.mercury_card_owner_name = decodedMagtek['name'];
order.selected_paymentline.mercury_ref_no = response.ref_no;
order.selected_paymentline.mercury_record_no = response.record_no;
order.selected_paymentline.mercury_invoice_no = response.invoice_no;
order.selected_paymentline.mercury_auth_code = response.auth_code;
order.selected_paymentline.mercury_data = response; // used to reverse transactions
order.selected_paymentline.set_credit_card_name();
var response = self.pos.decodeMercuryResponse(data);
response.journal_id = parsed_result.journal_id;
self.order_changes();
self.reset_input();
self.render_paymentlines();
order.trigger('change', order); // needed so that export_to_JSON gets triggered
if (response.message === "PARTIAL AP") {
def.resolve({
message: _t("Partially approved"),
auto_close: false,
});
} else {
if (response.status === 'Approved') {
// AP* indicates a duplicate request, so don't add anything for those
if (response.message === "AP*" && self._does_credit_payment_line_exist(response.authorize, decodedMagtek['number'],
response.card_type, decodedMagtek['name'])) {
def.resolve({
message: lookUpCodeTransaction["Approved"][response.error],
auto_close: true,
});
} else {
// If the payment is approved, add a payment line
var order = self.pos.get_order();
if (swipe_pending_line) {
order.select_paymentline(swipe_pending_line);
} else {
order.add_paymentline(self.pos.getCashRegisterByJournalID(parsed_result.journal_id));
}
order.selected_paymentline.paid = true;
order.selected_paymentline.mercury_swipe_pending = false;
order.selected_paymentline.mercury_amount = response.authorize;
order.selected_paymentline.mercury_card_number = decodedMagtek['number'];
order.selected_paymentline.mercury_card_brand = response.card_type;
order.selected_paymentline.mercury_card_owner_name = decodedMagtek['name'];
order.selected_paymentline.mercury_ref_no = response.ref_no;
order.selected_paymentline.mercury_record_no = response.record_no;
order.selected_paymentline.mercury_invoice_no = response.invoice_no;
order.selected_paymentline.mercury_auth_code = response.auth_code;
order.selected_paymentline.mercury_data = response; // used to reverse transactions
order.selected_paymentline.set_credit_card_name();
self.order_changes();
self.reset_input();
self.render_paymentlines();
order.trigger('change', order); // needed so that export_to_JSON gets triggered
if (response.message === "PARTIAL AP") {
def.resolve({
message: _t("Partially approved"),
auto_close: false,
});
} else {
def.resolve({
message: lookUpCodeTransaction["Approved"][response.error],
auto_close: true,
});
}
}
}
}
// if an error related to timeout or connectivity issues arised, then retry the same transaction
else {
if (lookUpCodeTransaction["TimeoutError"][response.error]) { // recoverable error
self.retry_mercury_transaction(def, response, retry_nr, true, self.credit_code_transaction, [parsed_result, def, retry_nr + 1]);
} else { // not recoverable
def.resolve({
message: "Error " + response.error + ":<br/>" + response.message,
auto_close: false
});
// if an error related to timeout or connectivity issues arised, then retry the same transaction
else {
if (lookUpCodeTransaction["TimeoutError"][response.error]) { // recoverable error
self.retry_mercury_transaction(def, response, retry_nr, true, self.credit_code_transaction, [parsed_result, def, retry_nr + 1]);
} else { // not recoverable
def.resolve({
message: "Error " + response.error + ":<br/>" + response.message,
auto_close: false
});
}
}
}
}).fail(function (error, event) {
event.preventDefault();
self.retry_mercury_transaction(def, null, retry_nr, false, self.credit_code_transaction, [parsed_result, def, retry_nr + 1]);
});
}).fail(function (error, event) {
event.preventDefault();
self.retry_mercury_transaction(def, null, retry_nr, false, self.credit_code_transaction, [parsed_result, def, retry_nr + 1]);
});
},
credit_code_cancel: function () {
@@ -550,55 +547,56 @@ PaymentScreenWidget.include({
});
}
var mercury_transaction = new Model('pos_mercury.mercury_transaction');
mercury_transaction.call(rpc_method, [request_data], undefined, {timeout: self.server_timeout_in_ms}).then(function (data) {
if (data === "timeout") {
self.retry_mercury_transaction(def, null, retry_nr, true, self.do_reversal, [line, is_voidsale, def, retry_nr + 1]);
return;
}
if (data === "internal error") {
def.resolve({
message: _t("Odoo error while processing transaction.")
});
return;
}
var response = self.pos.decodeMercuryResponse(data);
if (! is_voidsale) {
if (response.status != 'Approved' || response.message != 'REVERSED') {
// reversal was not successful, send voidsale
self.do_reversal(line, true);
} else {
// reversal was successful
def.resolve({
message: _t("Reversal succeeded"),
});
self.remove_paymentline_by_ref(line);
rpc.query({model: 'pos_mercury.mercury_transaction', method: rpc_method})
.args([request_data])
.exec({timeout: self.server_timeout_in_ms, callback: ajax.rpc.bind(ajax)})
.then(function (data) {
if (data === "timeout") {
self.retry_mercury_transaction(def, null, retry_nr, true, self.do_reversal, [line, is_voidsale, def, retry_nr + 1]);
return;
}
} else { // voidsale ended, nothing more we can do
if (response.status === 'Approved') {
def.resolve({
message: _t("VoidSale succeeded"),
});
self.remove_paymentline_by_ref(line);
} else {
if (data === "internal error") {
def.resolve({
message: "Error " + response.error + ":<br/>" + response.message,
message: _t("Odoo error while processing transaction.")
});
return;
}
}
}).fail(function (error, event) {
event.preventDefault();
self.retry_mercury_transaction(def, null, retry_nr, false, self.do_reversal, [line, is_voidsale, def, retry_nr + 1]);
});
var response = self.pos.decodeMercuryResponse(data);
if (! is_voidsale) {
if (response.status != 'Approved' || response.message != 'REVERSED') {
// reversal was not successful, send voidsale
self.do_reversal(line, true);
} else {
// reversal was successful
def.resolve({
message: _t("Reversal succeeded"),
});
self.remove_paymentline_by_ref(line);
}
} else { // voidsale ended, nothing more we can do
if (response.status === 'Approved') {
def.resolve({
message: _t("VoidSale succeeded"),
});
self.remove_paymentline_by_ref(line);
} else {
def.resolve({
message: "Error " + response.error + ":<br/>" + response.message,
});
}
}
}).fail(function (error, event) {
event.preventDefault();
self.retry_mercury_transaction(def, null, retry_nr, false, self.do_reversal, [line, is_voidsale, def, retry_nr + 1]);
});
},
click_delete_paymentline: function (cid) {
var self = this;
var lines = this.pos.get_order().get_paymentlines();
for (var i = 0; i < lines.length; i++) {
+56 -45
View File
@@ -6,8 +6,9 @@ var chrome = require('point_of_sale.chrome');
var gui = require('point_of_sale.gui');
var models = require('point_of_sale.models');
var screens = require('point_of_sale.screens');
var ajax = require('web.ajax');
var core = require('web.core');
var Model = require('web.DataModel');
var rpc = require('web.rpc');
var QWeb = core.qweb;
var _t = core._t;
@@ -235,7 +236,6 @@ var TableWidget = PosBaseWidget.extend({
// sends the table's modification to the server
save_changes: function(){
var self = this;
var model = new Model('restaurant.table');
var fields = _.find(this.pos.models,function(model){ return model.model === 'restaurant.table'; }).fields;
// we need a serializable copy of the table, containing only the fields defined on the server
@@ -248,58 +248,67 @@ var TableWidget = PosBaseWidget.extend({
// and the id ...
serializable_table.id = this.table.id;
model.call('create_from_ui',[serializable_table]).then(function(table_id){
model.query(fields).filter([['id','=',table_id]]).first().then(function(table){
for (var field in table) {
self.table[field] = table[field];
}
self.renderElement();
rpc.query({model: 'restaurant.table', method: 'create_from_ui'})
.args([serializable_table])
.exec({callback: ajax.rpc.bind(ajax)})
.then(function (table_id){
rpc.query({model: 'restaurant.table', method: 'search_read'})
.args([[['id', '=', table_id]], fields])
.withLimit(1)
.exec({callback: ajax.rpc.bind(this)})
.then(function (table){
for (var field in table) {
self.table[field] = table[field];
}
self.renderElement();
});
}, function(err,event) {
self.gui.show_popup('error',{
'title':_t('Changes could not be saved'),
'body': _t('You must be connected to the internet to save your changes.'),
});
event.stopPropagation();
event.preventDefault();
});
}, function(err,event) {
self.gui.show_popup('error',{
'title':_t('Changes could not be saved'),
'body': _t('You must be connected to the internet to save your changes.'),
});
event.stopPropagation();
event.preventDefault();
});
},
// destroy the table. We do not really destroy it, we set it
// to inactive so that it doesn't show up anymore, but it still
// available on the database for the orders that depend on it.
trash: function(){
var self = this;
var model = new Model('restaurant.table');
return model.call('create_from_ui',[{'active':false,'id':this.table.id}]).then(function(table_id){
// Removing all references from the table and the table_widget in in the UI ...
for (var i = 0; i < self.pos.floors.length; i++) {
var floor = self.pos.floors[i];
for (var j = 0; j < floor.tables.length; j++) {
if (floor.tables[j].id === table_id) {
floor.tables.splice(j,1);
break;
rpc.query({model: 'restaurant.table', method: 'create_from_ui'})
.args([{'active':false,'id':this.table.id}])
.exec(ajax.rpc.bind(rpc))
.then(function (table_id){
// Removing all references from the table and the table_widget in in the UI ...
for (var i = 0; i < self.pos.floors.length; i++) {
var floor = self.pos.floors[i];
for (var j = 0; j < floor.tables.length; j++) {
if (floor.tables[j].id === table_id) {
floor.tables.splice(j,1);
break;
}
}
}
}
var floorplan = self.getParent();
for (var i = 0; i < floorplan.table_widgets.length; i++) {
if (floorplan.table_widgets[i] === self) {
floorplan.table_widgets.splice(i,1);
var floorplan = self.getParent();
for (var i = 0; i < floorplan.table_widgets.length; i++) {
if (floorplan.table_widgets[i] === self) {
floorplan.table_widgets.splice(i,1);
}
}
}
if (floorplan.selected_table === self) {
floorplan.selected_table = null;
}
floorplan.update_toolbar();
self.destroy();
}, function(err, event) {
self.gui.show_popup('error', {
'title':_t('Changes could not be saved'),
'body': _t('You must be connected to the internet to save your changes.'),
if (floorplan.selected_table === self) {
floorplan.selected_table = null;
}
floorplan.update_toolbar();
self.destroy();
}, function(err, event) {
self.gui.show_popup('error', {
'title':_t('Changes could not be saved'),
'body': _t('You must be connected to the internet to save your changes.'),
});
event.stopPropagation();
event.preventDefault();
});
event.stopPropagation();
event.preventDefault();
});
},
get_notifications: function(){ //FIXME : Make this faster
var orders = this.pos.get_table_orders(this.table);
@@ -405,8 +414,10 @@ var FloorScreenWidget = screens.ScreenWidget.extend({
set_background_color: function(background) {
var self = this;
this.floor.background_color = background;
(new Model('restaurant.floor'))
.call('write',[[this.floor.id], {'background_color': background}]).fail(function(err, event){
rpc.query({model: 'restaurant.floor', method: 'write'})
.args([[this.floor.id], {'background_color': background}])
.exec({callback: ajax.rpc.bind(ajax)})
.fail(function (err, event){
self.gui.show_popup('error',{
'title':_t('Changes could not be saved'),
'body': _t('You must be connected to the internet to save your changes.'),
+6 -8
View File
@@ -2,12 +2,7 @@ odoo.define('project.update_kanban', function (require) {
'use strict';
var core = require('web.core');
var data = require('web.data');
var Dialog = require('web.Dialog');
var Model = require('web.Model');
var session = require('web.session');
var KanbanView = require('web.KanbanView');
var KanbanRecord = require('web.KanbanRecord');
var QWeb = core.qweb;
@@ -26,9 +21,12 @@ KanbanRecord.include({
if (this.modelName === 'project.task' && $(ev.currentTarget).data('type') === 'set_cover') {
ev.preventDefault();
new Model('ir.attachment').query(['id', 'name'])
.filter([['res_model', '=', 'project.task'], ['res_id', '=', this.id], ['mimetype', 'ilike', 'image']])
.all().then(open_cover_images_dialog);
var domain = [['res_model', '=', 'project.task'], ['res_id', '=', this.id], ['mimetype', 'ilike', 'image']];
this.rpc('ir.attachment', 'search_read')
.withDomain(domain)
.withFields(['id', 'name'])
.exec()
.then(open_cover_images_dialog);
} else {
this._super.apply(this, arguments, ev);
}
+6 -4
View File
@@ -3,7 +3,6 @@ odoo.define('sale.sales_team_dashboard', function (require) {
var core = require('web.core');
var KanbanRecord = require('web.KanbanRecord');
var Model = require('web.Model');
var _t = core._t;
KanbanRecord.include({
@@ -25,9 +24,12 @@ KanbanRecord.include({
if (isNaN(value)) {
self.do_warn(_t("Wrong value entered!"), _t("Only Integer Value should be valid."));
} else {
new Model('crm.team').call('write', [[self.id], { 'invoiced_target': value }]).done(function() {
self.trigger_up('kanban_record_update', {id: self.id});
});
self.rpc('crm.team', 'write')
.args([[self.id], { 'invoiced_target': value }])
.exec()
.done(function() {
self.trigger_up('kanban_record_update', {id: self.id});
});
}
});
},
@@ -193,17 +193,17 @@ var SalesTeamDashboardController = KanbanController.extend({
* @param {OdooEvent} e
*/
_onDashboardEditTarget: function (e) {
var target_name = e.data.target_name;
var target_value = e.data.target_value;
if(isNaN(target_value)) {
var targetName = e.data.target_name;
var targetValue = e.data.target_value;
if(isNaN(targetValue)) {
this.do_warn(_t("Wrong value entered!"), _t("Only Integer Value should be valid."));
} else {
var args = [target_name, parseInt(target_value)];
this.performModelRPC('crm.lead', 'modify_target_sales_dashboard', args)
this.rpc('crm.lead', 'modify_target_sales_dashboard')
.args([targetName, parseInt(targetValue)])
.exec()
.then(this.reload.bind(this));
}
},
/**
* @private
* @param {OdooEvent} e
@@ -215,7 +215,6 @@ var SalesTeamDashboardController = KanbanController.extend({
additional_context: action_context,
});
},
});
var SalesTeamDashboardView = KanbanView.extend({
+98 -2
View File
@@ -5,7 +5,6 @@ var Class = require('web.Class');
var Context = require('web.Context');
var concurrency = require('web.concurrency');
var mixins = require('web.mixins');
var Model = require('web.Model');
var session = require('web.session');
var translation = require('web.translation');
var pyeval = require('web.pyeval');
@@ -792,7 +791,7 @@ function build_domain(record, domain) {
return new CompoundDomain(domain).set_eval_context(eval_context);
}
return {
var data = {
Query: Query,
DataSet: DataSet,
DataSetStatic: DataSetStatic,
@@ -803,4 +802,101 @@ return {
build_domain: build_domain,
};
var Model = Class.extend({
/**
new openerp.web.Model(name[, context[, domain]])
@constructs instance.web.Model
@extends instance.web.Class
@param {String} name name of the OpenERP model this object is bound to
@param {Object} [context]
@param {Array} [domain]
*/
init: function(name, context, domain) {
this.name = name;
this._context = context || {};
this._domain = domain || [];
},
/**
* @deprecated does not allow to specify kwargs, directly use call() instead
*/
get_func: function (method_name) {
var self = this;
return function () {
return self.call(method_name, _.toArray(arguments));
};
},
/**
* Fetches a Query instance bound to this model, for searching
*
* @param {Array<String>} [fields] fields to ultimately fetch during the search
* @returns {instance.web.Query}
*/
query: function (fields) {
return new data.Query(this, fields);
},
/**
* Fetches the model's domain, combined with the provided domain if any
*
* @param {Array} [domain] to combine with the model's internal domain
* @returns {instance.web.CompoundDomain} The model's internal domain, or the AND-ed union of the model's internal domain and the provided domain
*/
domain: function (domain) {
if (!domain) { return this._domain; }
return new data.CompoundDomain(this._domain, domain);
},
/**
* Fetches the combination of the user's context and the domain context,
* combined with the provided context if any
*
* @param {Object} [context] to combine with the model's internal context
* @returns {web.Context} The union of the user's context and the model's internal context, as well as the provided context if any. In that order.
*/
context: function (context) {
return new Context(session.user_context, this._context, context || {});
},
/**
* Call a method (over RPC) on the bound OpenERP model.
*
* @param {String} method name of the method to call
* @param {Array} [args] positional arguments
* @param {Object} [kwargs] keyword arguments
* @param {Object} [options] additional options for the rpc() method
* @returns {jQuery.Deferred<>} call result
*/
call: function (method, args, kwargs, options) {
args = args || [];
kwargs = kwargs || {};
if (!_.isArray(args)) {
// call(method, kwargs)
kwargs = args;
args = [];
}
pyeval.ensure_evaluated(args, kwargs);
var call_kw = '/web/dataset/call_kw/' + this.name + '/' + method;
return session.rpc(call_kw, {
model: this.name,
method: method,
args: args,
kwargs: kwargs
}, options);
},
call_button: function (method, args) {
pyeval.ensure_evaluated(args, {});
return session.rpc('/web/dataset/call_button', {
model: this.name,
method: method,
// Should not be necessary anymore. Integrate remote in this?
domain_id: null,
context_id: args.length - 1,
args: args || []
});
},
});
return data;
});
@@ -1,81 +0,0 @@
odoo.define('web.DataModel', function (require) {
"use strict";
var Context = require('web.Context');
var data = require('web.data');
var Model = require('web.Model');
var pyeval = require('web.pyeval');
var session = require('web.session');
Model.include({
/**
* Fetches a Query instance bound to this model, for searching
*
* @param {Array<String>} [fields] fields to ultimately fetch during the search
* @returns {instance.web.Query}
*/
query: function (fields) {
return new data.Query(this, fields);
},
/**
* Fetches the model's domain, combined with the provided domain if any
*
* @param {Array} [domain] to combine with the model's internal domain
* @returns {instance.web.CompoundDomain} The model's internal domain, or the AND-ed union of the model's internal domain and the provided domain
*/
domain: function (domain) {
if (!domain) { return this._domain; }
return new data.CompoundDomain(this._domain, domain);
},
/**
* Fetches the combination of the user's context and the domain context,
* combined with the provided context if any
*
* @param {Object} [context] to combine with the model's internal context
* @returns {web.Context} The union of the user's context and the model's internal context, as well as the provided context if any. In that order.
*/
context: function (context) {
return new Context(session.user_context, this._context, context || {});
},
/**
* Call a method (over RPC) on the bound OpenERP model.
*
* @param {String} method name of the method to call
* @param {Array} [args] positional arguments
* @param {Object} [kwargs] keyword arguments
* @param {Object} [options] additional options for the rpc() method
* @returns {jQuery.Deferred<>} call result
*/
call: function (method, args, kwargs, options) {
args = args || [];
kwargs = kwargs || {};
if (!_.isArray(args)) {
// call(method, kwargs)
kwargs = args;
args = [];
}
pyeval.ensure_evaluated(args, kwargs);
var call_kw = '/web/dataset/call_kw/' + this.name + '/' + method;
return session.rpc(call_kw, {
model: this.name,
method: method,
args: args,
kwargs: kwargs
}, options);
},
call_button: function (method, args) {
pyeval.ensure_evaluated(args, {});
return session.rpc('/web/dataset/call_button', {
model: this.name,
method: method,
// Should not be necessary anymore. Integrate remote in this?
domain_id: null,
context_id: args.length - 1,
args: args || []
});
},
});
return Model;
});
@@ -1,60 +0,0 @@
odoo.define('web.Model', function (require) {
"use strict";
var Class = require('web.Class');
var session = require('web.session');
var Model = Class.extend({
/**
new openerp.web.Model(name[, context[, domain]])
@constructs instance.web.Model
@extends instance.web.Class
@param {String} name name of the OpenERP model this object is bound to
@param {Object} [context]
@param {Array} [domain]
*/
init: function(name, context, domain) {
this.name = name;
this._context = context || {};
this._domain = domain || [];
},
/**
* @deprecated does not allow to specify kwargs, directly use call() instead
*/
get_func: function (method_name) {
var self = this;
return function () {
return self.call(method_name, _.toArray(arguments));
};
},
/**
* Call a method (over RPC) on the bound OpenERP model.
*
* @param {String} method name of the method to call
* @param {Array} [args] positional arguments
* @param {Object} [kwargs] keyword arguments
* @param {Object} [options] additional options for the rpc() method
* @returns {jQuery.Deferred<>} call result
*/
call: function (method, args, kwargs, options) {
args = args || [];
kwargs = kwargs || {};
if (!_.isArray(args)) {
// call(method, kwargs)
kwargs = args;
args = [];
}
var call_kw = '/web/dataset/call_kw/' + this.name + '/' + method;
return session.rpc(call_kw, {
model: this.name,
method: method,
args: args,
kwargs: kwargs
}, options);
},
});
return Model;
});
+23 -21
View File
@@ -3,7 +3,6 @@ odoo.define('web.Apps', function (require) {
var core = require('web.core');
var framework = require('web.framework');
var Model = require('web.DataModel');
var session = require('web.session');
var Widget = require('web.Widget');
@@ -41,21 +40,22 @@ var Apps = Widget.extend({
if (apps_client) {
return check_client_available(apps_client);
} else {
var Mod = new Model('ir.module.module');
return Mod.call('get_apps_server').then(function(u) {
var link = $(_.str.sprintf('<a href="%s"></a>', u))[0];
var host = _.str.sprintf('%s//%s', link.protocol, link.host);
var dbname = link.pathname;
if (dbname[0] === '/') {
dbname = dbname.substr(1);
}
var client = {
origin: host,
dbname: dbname
};
apps_client = client;
return check_client_available(client);
});
return this.rpc('ir.module.module', 'get_apps_server')
.exec()
.then(function(u) {
var link = $(_.str.sprintf('<a href="%s"></a>', u))[0];
var host = _.str.sprintf('%s//%s', link.protocol, link.host);
var dbname = link.pathname;
if (dbname[0] === '/') {
dbname = dbname.substr(1);
}
var client = {
origin: host,
dbname: dbname
};
apps_client = client;
return check_client_available(client);
});
}
},
@@ -90,11 +90,13 @@ var Apps = Widget.extend({
});
},
'Model': function(m) {
var M = new Model(m.model);
M[m.method].apply(M, m.args).then(function(r) {
var w = self.$ifr[0].contentWindow;
w.postMessage({id: m.id, result: r}, client.origin);
});
return this.rpc(m.model, m.method)
.args(m.args)
.exec()
.then(function(r) {
var w = self.$ifr[0].contentWindow;
w.postMessage({id: m.id, result: r}, client.origin);
});
},
};
// console.log(e.data);
@@ -5,7 +5,6 @@ var Context = require('web.Context');
var core = require('web.core');
var data = require('web.data');
var field_utils = require('web.field_utils');
var Model = require('web.DataModel');
var pyeval = require('web.pyeval');
var time = require('web.time');
var utils = require('web.utils');
@@ -394,7 +393,6 @@ var ManyToOneField = CharField.extend({
default_operator: {},
init: function (view_section, field, parent) {
this._super(view_section, field, parent);
this.model = new Model(this.attrs.relation);
this.searchview = parent;
},
@@ -428,20 +426,23 @@ var ManyToOneField = CharField.extend({
args = [];
}
}
return this.model.call('name_search', [], {
name: needle,
args: args,
limit: 8,
context: context
}).then(function (results) {
if (_.isEmpty(results)) { return null; }
return _(results).map(function (result) {
return {
label: _.escape(result[1]),
facet: facet_from(self, result)
};
return this.rpc(this.attrs.relation, 'name_search')
.kwargs({
name: needle,
args: args,
limit: 8,
context: context
})
.exec()
.then(function (results) {
if (_.isEmpty(results)) { return null; }
return _(results).map(function (result) {
return {
label: _.escape(result[1]),
facet: facet_from(self, result)
};
});
});
});
},
facet_for: function (value) {
var self = this;
@@ -456,10 +457,15 @@ var ManyToOneField = CharField.extend({
value = value[0];
}
var context = pyeval.eval('contexts', [this.searchview.dataset.get_context()]);
return this.model.call('name_get', [value], {context: context}).then(function (names) {
if (_(names).isEmpty()) { return null; }
return facet_from(self, names[0]);
});
return this.rpc(this.attrs.relation, 'name_get')
.args([value])
.withContext(context)
.exec()
.then(function (names) {
if (_(names).isEmpty()) { return null; }
return facet_from(self, names[0]);
});
},
value_from: function (facetValue) {
return facetValue.get('label');
+37 -29
View File
@@ -6,7 +6,6 @@ var core = require('web.core');
var data_manager = require('web.data_manager');
var framework = require('web.framework');
var Menu = require('web.Menu');
var Model = require('web.DataModel');
var session = require('web.session');
var SystrayMenu = require('web.SystrayMenu');
var UserMenu = require('web.UserMenu');
@@ -66,25 +65,31 @@ return AbstractWebClient.extend({
logo_edit: function(ev) {
var self = this;
ev.preventDefault();
self.alive(new Model("res.users").call("read", [[session.uid], ["company_id"]])).then(function(data) {
self.rpc("/web/action/load", { action_id: "base.action_res_company_form" }).done(function(result) {
result.res_id = data[0].company_id[0];
result.target = "new";
result.views = [[false, 'form']];
result.flags = {
action_buttons: true,
headless: true,
};
self.action_manager.do_action(result).then(function () {
var form = self.action_manager.dialog_widget.views.form.controller;
form.on("on_button_cancel", self.action_manager, self.action_manager.dialog_stop);
form.on('record_saved', self, function() {
self.action_manager.dialog_stop();
self.update_logo();
this.rpc("res.users", "read")
.args([[session.uid], ["company_id"]])
.exec()
.then(function(data) {
self.rpc("/web/action/load")
.kwargs({ action_id: "base.action_res_company_form" })
.exec()
.done(function(result) {
result.res_id = data[0].company_id[0];
result.target = "new";
result.views = [[false, 'form']];
result.flags = {
action_buttons: true,
headless: true,
};
self.action_manager.do_action(result).then(function () {
var form = self.action_manager.dialog_widget.views.form.controller;
form.on("on_button_cancel", self.action_manager, self.action_manager.dialog_stop);
form.on('record_saved', self, function() {
self.action_manager.dialog_stop();
self.update_logo();
});
});
});
});
});
});
return false;
},
bind_hashchange: function() {
@@ -94,18 +99,21 @@ return AbstractWebClient.extend({
var state = $.bbq.getState(true);
if (_.isEmpty(state) || state.action === "login") {
self.menu.is_bound.done(function() {
new Model("res.users").call("read", [[session.uid], ["action_id"]]).done(function(result) {
var data = result[0];
if(data.action_id) {
self.action_manager.do_action(data.action_id[0]);
self.menu.open_action(data.action_id[0]);
} else {
var first_menu_id = self.menu.$el.find("a:first").data("menu");
if(first_menu_id) {
self.menu.menu_click(first_menu_id);
self.rpc("res.users", "read")
.args([[session.uid], ["action_id"]])
.exec()
.done(function(result) {
var data = result[0];
if(data.action_id) {
self.action_manager.do_action(data.action_id[0]);
self.menu.open_action(data.action_id[0]);
} else {
var first_menu_id = self.menu.$el.find("a:first").data("menu");
if(first_menu_id) {
self.menu.menu_click(first_menu_id);
}
}
}
});
});
});
} else {
$(window).trigger('hashchange');
+57
View File
@@ -2,6 +2,7 @@ odoo.define('web.mixins', function (require) {
"use strict";
var Class = require('web.Class');
var rpc = require('web.rpc');
var utils = require('web.utils');
var AbstractService = require('web.AbstractService');
@@ -237,10 +238,50 @@ var Events = Class.extend({
*/
var EventDispatcherMixin = _.extend({}, ParentedMixin, {
__eventDispatcherMixin: true,
custom_events: {},
init: function () {
ParentedMixin.init.call(this);
this.__edispatcherEvents = new Events();
this.__edispatcherRegisteredEvents = [];
this._delegateCustomEvents();
},
/**
* Proxies a method of the object, in order to keep the right ``this`` on
* method invocations.
*
* This method is similar to ``Function.prototype.bind`` or ``_.bind``, and
* even more so to ``jQuery.proxy`` with a fundamental difference: its
* resolution of the method being called is lazy, meaning it will use the
* method as it is when the proxy is called, not when the proxy is created.
*
* Other methods will fix the bound method to what it is when creating the
* binding/proxy, which is fine in most javascript code but problematic in
* OpenERP Web where developers may want to replace existing callbacks with
* theirs.
*
* The semantics of this precisely replace closing over the method call.
*
* @param {String|Function} method function or name of the method to invoke
* @returns {Function} proxied method
*/
proxy: function (method) {
var self = this;
return function () {
var fn = (typeof method === 'string') ? self[method] : method;
if (fn === void 0) {
throw new Error("Couldn't find method '" + method + "' in widget " + self);
}
return fn.apply(self, arguments);
};
},
_delegateCustomEvents: function () {
if (_.isEmpty(this.custom_events)) { return; }
for (var key in this.custom_events) {
if (!this.custom_events.hasOwnProperty(key)) { continue; }
var method = this.proxy(this.custom_events[key]);
this.on(key, this, method);
}
},
on: function (events, dest, func) {
var self = this;
@@ -373,6 +414,21 @@ var ServicesMixin = {
});
return result;
},
/**
* Build a RPC query
*
* @param {string} arg1 either a route or a model
* @param {string} method if a model is given, this argument is a method
* @returns {RPCBuilder}
*/
rpc: function (arg1, method) {
return rpc.query({
method: method,
model: method && arg1,
parent: this,
route: !method && arg1,
});
},
// AJAX calls
performRPC: function (route, args, options) {
return this.call('ajax', 'rpc', route, args || {}, options || {});
@@ -452,6 +508,7 @@ var ServiceProvider = {
var service = new Service();
self.services[service.name] = service;
});
this.custom_events = _.clone(this.custom_events);
this.custom_events.call_service = this._call_service.bind(this);
},
_call_service: function (event) {
-40
View File
@@ -62,7 +62,6 @@ var Widget = core.Class.extend(mixins.PropertiesMixin, mixins.ServicesMixin, {
className: null,
attributes: {},
events: {},
custom_events: {},
/**
* The name of the QWeb template that will be used for rendering. Must be
* redefined in subclasses or the default render() method can not be used.
@@ -93,7 +92,6 @@ var Widget = core.Class.extend(mixins.PropertiesMixin, mixins.ServicesMixin, {
}
// FIXME: this should not be
this.setElement(this._make_descriptive());
this.delegateCustomEvents();
},
/**
* Method called between init and start. Performs asynchronous calls required by start.
@@ -315,15 +313,6 @@ var Widget = core.Class.extend(mixins.PropertiesMixin, mixins.ServicesMixin, {
}
}
},
delegateCustomEvents: function () {
if (_.isEmpty(this.custom_events)) { return; }
for (var key in this.custom_events) {
if (!this.custom_events.hasOwnProperty(key)) { continue; }
var method = this.proxy(this.custom_events[key]);
this.on(key, this, method);
}
},
undelegateEvents: function () {
this.$el.off('.widget_events');
},
@@ -361,35 +350,6 @@ var Widget = core.Class.extend(mixins.PropertiesMixin, mixins.ServicesMixin, {
this.$el.hasClass('o_hidden') ? this.do_show() : this.do_hide();
}
},
/**
* Proxies a method of the object, in order to keep the right ``this`` on
* method invocations.
*
* This method is similar to ``Function.prototype.bind`` or ``_.bind``, and
* even more so to ``jQuery.proxy`` with a fundamental difference: its
* resolution of the method being called is lazy, meaning it will use the
* method as it is when the proxy is called, not when the proxy is created.
*
* Other methods will fix the bound method to what it is when creating the
* binding/proxy, which is fine in most javascript code but problematic in
* OpenERP Web where developers may want to replace existing callbacks with
* theirs.
*
* The semantics of this precisely replace closing over the method call.
*
* @param {String|Function} method function or name of the method to invoke
* @returns {Function} proxied method
*/
proxy: function (method) {
var self = this;
return function () {
var fn = (typeof method === 'string') ? self[method] : method;
if (fn === void 0) {
throw new Error("Couldn't find method '" + method + "' in widget " + self);
}
return fn.apply(self, arguments);
};
},
});
return Widget;
@@ -1299,19 +1299,17 @@ var FieldDomain = AbstractField.extend({
var self = this;
return def.then(function () {
var context = {}; // FIXME ?
return self.performModelRPC(self.domainModel, "search_count", [
domain,
context
]).then(
function (data) {
return self.rpc(self.domainModel, "search_count")
.args([domain,context])
.exec()
.then(function (data) {
self._isValidForModel = true;
return data;
},
function (error, e) {
}, function (error, e) {
e.preventDefault();
self._isValidForModel = false;
}
).always(self._replaceContent.bind(self));
})
.always(self._replaceContent.bind(self));
});
},
/**
@@ -227,14 +227,14 @@ var FieldMany2One = AbstractRelationalField.extend({
var self = this;
var slowCreate = this._searchCreatePopup.bind(this, "form", false, this._createContext(name));
if (this.nodeOptions.quick_create) {
this.performModelRPC(this.field.relation, "name_create", [name]).then(
function (result) {
this.rpc(this.field.relation, "name_create")
.args([name])
.exec()
.then(function (result) {
if (self.mode === "edit") {
self.reinitialize({id: result[0], display_name: result[1]});
}
},
slowCreate
);
}, slowCreate);
} else {
slowCreate();
}
@@ -2,13 +2,11 @@ odoo.define('web.DataManager', function (require) {
"use strict";
var core = require('web.core');
var Model = require('web.DataModel');
var session = require('web.session');
var utils = require('web.utils');
return core.Class.extend({
init: function () {
this.Filters = new Model('ir.filters');
this._init_cache();
},
@@ -128,8 +126,13 @@ return core.Class.extend({
load_filters: function (dataset, action_id) {
var key = this._gen_key(dataset.model, action_id);
if (!this._cache.filters[key]) {
this._cache.filters[key] = this.Filters.call('get_filters', [dataset.model, action_id], {
context: dataset.get_context(),
this._cache.filters[key] = session.rpc('/web/dataset/call_kw/ir.filters/get_filters', {
args: [dataset.model, action_id],
kwargs: {
context: dataset.get_context(),
},
model: 'ir.filters',
method: 'get_filters',
}).fail(this._invalidate.bind(this, this._cache.filters, key));
}
return this._cache.filters[key];
@@ -143,8 +146,11 @@ return core.Class.extend({
*/
create_filter: function (filter) {
var self = this;
return this.Filters
.call('create_or_replace', [filter])
return session.rpc('/web/dataset/call_kw/ir.filters/create_or_replace', {
args: [filter],
model: 'ir.filters',
method: 'create_or_replace',
})
.then(function (filter_id) {
var key = [
filter.model_id,
@@ -163,8 +169,11 @@ return core.Class.extend({
*/
delete_filter: function (filter) {
var self = this;
return this.Filters
.call('unlink', [filter.id])
return session.rpc('/web/dataset/call_kw/ir.filters/unlink', {
args: [filter.id],
model: 'ir.filters',
method: 'unlink',
})
.then(function () {
self._cache.filters = {}; // invalidate cache
});
File diff suppressed because it is too large Load Diff
@@ -103,7 +103,7 @@ var CalendarController = AbstractController.extend({
_updateRecord: function (record) {
// Cannot modify actual name yet
var data = _.omit(this.model.calendarEventToRecord(record), 'name');
this.performModelRPC(this.model, 'write', [record.id, data])
this.performModelRPC(this.model.modelName, 'write', [record.id, data])
.then(this.reload.bind(this));
},
@@ -7,7 +7,6 @@ var core = require('web.core');
var Dialog = require('web.Dialog');
var field_utils = require('web.field_utils');
var framework = require('web.framework');
var Model = require('web.Model');
var session = require('web.session');
var SystrayMenu = require('web.SystrayMenu');
var utils = require('web.utils');
@@ -18,8 +17,6 @@ var Widget = require('web.Widget');
var QWeb = core.qweb;
var _t = core._t;
var ADD = function (id) { return [4, id, false]; },
REMOVE = function (id) { return [3, id, false]; };
/**
* DebugManager base + general features (applicable to any context)
*/
@@ -66,9 +63,9 @@ var DebugManager = Widget.extend({
// whether the current user is an administrator
this._is_admin = session.is_system;
return $.when(
new Model('res.users').call('check_access_rights', {operation: 'write', raise_exception: false}),
this.performModelRPC('res.users', 'check_access_rights', {operation: 'write', raise_exception: false}),
session.user_has_group('base.group_no_one'),
new Model('ir.model.data').call('xmlid_to_res_id', {xmlid: 'base.group_no_one'}),
this.performModelRPC('ir.model.data', 'xmlid_to_res_id', {xmlid: 'base.group_no_one'}),
this._super()
).then(function (can_write_user, has_group_no_one, group_no_one_id) {
this._features_group = can_write_user && group_no_one_id;
@@ -164,11 +161,7 @@ var DebugManager = Widget.extend({
title: _t('Select a view'),
disable_multiple_selection: true,
on_selected: function (element_ids) {
new Model('ir.ui.view')
.query(['name', 'model', 'type'])
.filter([['id', '=', element_ids[0]]])
.first()
.then(function (view) {
self.performModelRPC('ir.ui.view', [[['id', '=', element_ids[0]]], ['name', 'model', 'type']], {limit: 1}).then(function (view) {
self.do_action({
type: 'ir.actions.act_window',
name: view.name,
@@ -226,7 +219,7 @@ DebugManager.include({
get_view_fields: function () {
var self = this;
var model = this._action.res_model;
new Model(model).call('fields_get', {
this.performModelRPC(model, 'fields_get', [], {
attributes: ['string', 'searchable', 'required', 'readonly', 'type', 'store', 'sortable', 'relation', 'help']
}).done(function (fields) {
new Dialog(self, {
@@ -262,9 +255,7 @@ DebugManager.include({
},
translate: function() {
var model = this._action.res_model;
new Model("ir.translation")
.call('get_technical_translations', [model])
.then(this.do_action);
this.performModelRPC("ir.translation", 'get_technical_translations', [model]).then(this.do_action);
}
});
@@ -278,9 +269,8 @@ DebugManager.include({
this._can_edit_views = false;
return $.when(
this._super(),
new Model('ir.ui.view').call(
'check_access_rights', {operation: 'write', raise_exception: false}
).then(function (ar) {
this.performModelRPC('ir.ui.view', 'check_access_rights', {operation: 'write', raise_exception: false})
.then(function (ar) {
this._can_edit_views = ar;
}.bind(this))
);
@@ -1,7 +1,6 @@
odoo.define('web.SwitchCompanyMenu', function(require) {
"use strict";
var Model = require('web.Model');
var session = require('web.session');
var SystrayMenu = require('web.SystrayMenu');
var Widget = require('web.Widget');
@@ -19,7 +18,7 @@ var SwitchCompanyMenu = Widget.extend({
this.$el.on('click', '.dropdown-menu li a[data-menu]', _.debounce(function(ev) {
ev.preventDefault();
var company_id = $(ev.currentTarget).data('company-id');
new Model('res.users').call('write', [[session.uid], {'company_id': company_id}]).then(function() {
self.performModelRPC('res.users', 'write', [[session.uid], {'company_id': company_id}]).then(function() {
location.reload();
});
}, 1500, true));
@@ -172,7 +172,9 @@ var DiagramController = AbstractController.extend({
Dialog.confirm(this, (_t("Are you sure you want to remove this transition?")), {
confirm_callback: function () {
var state = self.model.get();
self.performModelRPC(state.connector_model, 'unlink', [event.data.id])
self.rpc(state.connector_model, 'unlink')
.args([event.data.id])
.exec()
.then(self.reload.bind(self));
},
});
@@ -189,7 +191,9 @@ var DiagramController = AbstractController.extend({
Dialog.confirm(this, (msg), {
confirm_callback: function () {
var state = self.model.get();
self.performModelRPC(state.node_model, 'unlink', [event.data.id])
self.rpc(state.node_model, 'unlink')
.args([event.data.id])
.exec()
.then(self.reload.bind(self));
},
});
@@ -2,7 +2,6 @@ odoo.define('web_editor.translate', function (require) {
'use strict';
var core = require('web.core');
var Model = require('web.Model');
var ajax = require('web.ajax');
var Widget = require('web.Widget');
var base = require('web_editor.base');
@@ -106,7 +105,6 @@ var Translate = Widget.extend({
template: 'web_editor.editorbar',
init: function (parent, $target, lang) {
this.parent = parent;
this.ir_translation = new Model('ir.translation');
this.lang = lang || base.get_context().lang;
this.setTarget($target);
this._super.apply(this, arguments);
@@ -2,7 +2,6 @@ odoo.define('web.planner', function (require) {
"use strict";
var core = require('web.core');
var Model = require('web.Model');
var SystrayMenu = require('web.SystrayMenu');
var planner = require('web.planner.common');
var session = require('web.session');
@@ -14,12 +13,14 @@ var PlannerLauncher = planner.PlannerLauncher.extend({
},
_fetch_planner_data: function () {
var planner_by_menu = this.planner_by_menu = {};
return (new Model('web.planner')).query().all().then(function (res) {
_.each(res, function (planner) {
planner.data = $.parseJSON(planner.data) || {};
planner_by_menu[planner.menu_id[0]] = planner;
return this.rpc('web.planner', 'search_read')
.exec()
.then(function (res) {
_.each(res.records, function (planner) {
planner.data = $.parseJSON(planner.data) || {};
planner_by_menu[planner.menu_id[0]] = planner;
});
});
});
},
on_menu_clicked: function (menu_id) {
if (this.planner_by_menu[menu_id]) {
@@ -4,7 +4,6 @@ odoo.define('web.planner.common', function (require) {
var core = require('web.core');
var Dialog = require('web.Dialog');
var dom = require('web.dom');
var Model = require('web.Model');
var Widget = require('web.Widget');
var session = require('web.session');
var utils = require('web.utils');
@@ -67,14 +66,13 @@ var PlannerDialog = Dialog.extend({
* Fetch the planner's rendered template
*/
willStart: function() {
var def = (new Model('web.planner')).call('render', [
this.planner.view_id[0],
this.planner.planner_application
], {
context: session.user_context
}).then((function (template) {
this.$template = $(template);
}).bind(this));
var def = this.rpc('web.planner', 'render')
.args([this.planner.view_id[0], this.planner.planner_application])
.withContext(session.user_context)
.exec()
.then((function (template) {
this.$template = $(template);
}).bind(this));
return $.when(this._super.apply(this, arguments), def);
},
@@ -353,17 +351,23 @@ var PlannerDialog = Dialog.extend({
this._save_planner_data();
},
_save_planner_data: function() {
return (new Model('web.planner')).call('write', [this.planner.id, {'data': JSON.stringify(this.planner.data), 'progress': this.planner.progress}]);
return this.rpc('web.planner', 'write')
.args([this.planner.id, {'data': JSON.stringify(this.planner.data), 'progress': this.planner.progress}])
.exec();
},
show_enterprise: function () {
var self = this;
var buttons = [{
text: _t("Upgrade now"),
classes: 'btn-primary',
close: true,
click: function () {
new Model("res.users").call("search_count", [[["share", "=", false]]]).then(function (data) {
window.location = "https://www.odoo.com/odoo-enterprise/upgrade?utm_medium=community_upgrade&num_users=" + data;
});
self.rpc("res.users", "search_count")
.args([[["share", "=", false]]])
.exec()
.then(function (data) {
window.location = "https://www.odoo.com/odoo-enterprise/upgrade?utm_medium=community_upgrade&num_users=" + data;
});
},
}, {
text: _t("Cancel"),
@@ -3,7 +3,6 @@ odoo.define('web_settings_dashboard', function (require) {
var core = require('web.core');
var framework = require('web.framework');
var Model = require('web.Model');
var PlannerCommon = require('web.planner.common');
var PlannerDialog = PlannerCommon.PlannerDialog;
var Widget = require('web.Widget');
@@ -89,8 +88,9 @@ var DashboardInvitations = Widget.extend({
$target.prop('disabled', true);
$target.find('i.fa-cog').removeClass('hidden');
// Try to create user accountst
new Model("res.users")
.call("web_dashboard_create_users", [user_emails])
this.rpc("res.users", "web_dashboard_create_users")
.args([user_emails])
.exec()
.then(function() {
self.reload();
})
@@ -165,14 +165,16 @@ var DashboardPlanner = Widget.extend({
willStart: function () {
var self = this;
return new Model('web.planner').query().all().then(function(res) {
self.planners = res;
_.each(self.planners, function(planner) {
self.planner_by_menu[planner.menu_id[0]] = planner;
self.planner_by_menu[planner.menu_id[0]].data = $.parseJSON(planner.data) || {};
return this.rpc('web.planner', 'search_read')
.exec()
.then(function(res) {
self.planners = res.records;
_.each(self.planners, function(planner) {
self.planner_by_menu[planner.menu_id[0]] = planner;
self.planner_by_menu[planner.menu_id[0]].data = $.parseJSON(planner.data) || {};
});
self.set_overall_progress();
});
self.set_overall_progress();
});
},
update_planner_progress: function(){
@@ -4,7 +4,6 @@ odoo.define('web_tour.DebugManager', function (require) {
var core = require("web.core");
var DebugManager = require('web.DebugManager');
var Dialog = require("web.Dialog");
var Model = require('web.Model');
var tour = require('web_tour.tour');
@@ -20,9 +19,12 @@ DebugManager.include({
consume_tours: function () {
var active_tours = get_active_tours();
if (active_tours.length > 0) { // tours might have been consumed meanwhile
new Model('web_tour.tour').call('consume', [active_tours]).then(function () {
window.location.reload();
});
this.rpc('web_tour.tour', 'consume')
.args([active_tours])
.exec()
.then(function () {
window.location.reload();
});
}
},
start_tour: function() {
+14 -7
View File
@@ -3,7 +3,7 @@ odoo.define('web_tour.TourManager', function(require) {
var core = require('web.core');
var local_storage = require('web.local_storage');
var Model = require('web.Model');
var mixins = require('web.mixins');
var session = require('web.session');
var Tip = require('web_tour.Tip');
@@ -187,15 +187,17 @@ var RunningTourActionHelper = core.Class.extend({
},
});
return core.Class.extend({
init: function(consumed_tours) {
return core.Class.extend(mixins.EventDispatcherMixin, mixins.ServicesMixin, {
init: function(parent, consumed_tours) {
mixins.EventDispatcherMixin.init.call(this);
this.setParent(parent);
this.$body = $('body');
this.active_tooltips = {};
this.tours = {};
this.consumed_tours = consumed_tours || [];
this.running_tour = local_storage.getItem(get_running_key());
this.running_step_delay = parseInt(local_storage.getItem(get_running_delay_key()), 10) || 10;
this.TourModel = new Model('web_tour.tour');
this.edition = (_.last(session.server_version_info) === 'e') ? 'enterprise' : 'community';
this._log = [];
},
@@ -447,9 +449,13 @@ return core.Class.extend({
}
this._log = [];
} else {
this.TourModel.call('consume', [[tour_name]]).then((function () {
this.consumed_tours.push(tour_name);
}).bind(this));
var self = this;
this.rpc('web_tour.tour', 'consume')
.args([[tour_name]])
.exec()
.then(function () {
self.consumed_tours.push(tour_name);
});
}
},
_set_running_tour_timeout: function (tour_name, step) {
@@ -509,4 +515,5 @@ return core.Class.extend({
},
},
});
});
+25 -11
View File
@@ -2,9 +2,10 @@ odoo.define('web_tour.tour', function(require) {
"use strict";
var ajax = require('web.ajax');
var Class = require('web.Class');
var config = require('web.config');
var core = require('web.core');
var Model = require('web.Model');
var mixins = require('web.mixins');
var session = require('web.session');
var TourManager = require('web_tour.TourManager');
@@ -14,16 +15,29 @@ if (config.device.size_class <= config.device.SIZES.XS) {
return $.Deferred().reject();
}
var CallService = Class.extend(mixins.EventDispatcherMixin, mixins.ServiceProvider, {
init: function () {
mixins.ServiceProvider.init.call(this);
mixins.EventDispatcherMixin.init.call(this);
},
});
return session.is_bound.then(function () {
var defs = [];
// Load the list of consumed tours and the tip template only if we are admin, in the frontend,
// tours being only available for the admin. For the backend, the list of consumed is directly
// in the page source.
if (session.is_frontend && session.is_superuser) {
defs.push(new Model('web_tour.tour').call('get_consumed_tours'));
defs.push(ajax.rpc('/web/dataset/call_kw/web_tour.tour/get_consumed_tours', {
model: 'web_tour.tour',
method: 'get_consumed_tours',
args: [],
kwargs: {}
}));
}
return $.when.apply($, defs).then(function (consumed_tours) {
var tour = new TourManager(session.is_frontend ? consumed_tours : session.web_tours);
consumed_tours = session.is_frontend ? consumed_tours : session.web_tours;
var tour_manager = new TourManager(new CallService(), consumed_tours);
// Use a MutationObserver to detect DOM changes
var untracked_classnames = ["o_tooltip", "o_tooltip_content", "o_tooltip_overlay"];
@@ -40,7 +54,7 @@ return session.is_bound.then(function () {
}
});
if (update) { // ignore mutations which concern the tooltips
tour.update();
tour_manager.update();
}
}, 500);
var observer = new MutationObserver(check_tooltip);
@@ -60,7 +74,7 @@ return session.is_bound.then(function () {
*/
$.when(load_def).then(function () {
_.defer(function () {
tour._register_all(observe);
tour_manager._register_all(observe);
if (observe) {
observer.observe(document.body, {
attributes: true,
@@ -77,12 +91,12 @@ return session.is_bound.then(function () {
})();
// Enable the MutationObserver for the admin or if a tour is running, when the DOM is ready
start_service(session.is_superuser || tour.running_tour);
start_service(session.is_superuser || tour_manager.running_tour);
// Override the TourManager so that it enables/disables the observer when necessary
if (!session.is_superuser) {
var run = tour.run;
tour.run = function () {
var run = tour_manager.run;
tour_manager.run = function () {
var self = this;
var args = arguments;
@@ -93,14 +107,14 @@ return session.is_bound.then(function () {
}
});
};
var _consume_tour = tour._consume_tour;
tour._consume_tour = function () {
var _consume_tour = tour_manager._consume_tour;
tour_manager._consume_tour = function () {
_consume_tour.apply(this, arguments);
observer.disconnect();
};
}
return tour;
return tour_manager;
});
});
@@ -3,16 +3,16 @@ odoo.define('web.planner.website', function (require) {
var ajax = require('web.ajax');
var core = require('web.core');
var Model = require('web.Model');
var planner = require('web.planner.common');
var session = require('web.session');
var website = require('website.website');
var model = require('website.model');
var qweb = core.qweb;
var WebsitePlannerLauncher = planner.PlannerLauncher.extend({
_fetch_planner_data: function () {
return (new Model('web.planner')).call('search_read', [[['planner_application', '=', 'planner_website']]]).then((function (planner) {
return model.performModelRPC('web.planner', 'search_read', [[['planner_application', '=', 'planner_website']]]).then((function (planner) {
if (!planner.length) return;
planner[0].data = $.parseJSON(planner[0].data) || {};
@@ -7,7 +7,6 @@ var ControlPanelMixin = require('web.ControlPanelMixin');
var core = require('web.core');
var Dialog = require('web.Dialog');
var formats = require('web.formats');
var Model = require('web.Model');
var session = require('web.session');
var web_client = require('web.web_client');
var Widget = require('web.Widget');
@@ -104,7 +103,7 @@ var Dashboard = Widget.extend(ControlPanelMixin, {
}
var self = this;
new Model('ir.config_parameter').call('set_param', ['google_management_client_id', ga_client_id]).then(function(){
this.performModelRPC('ir.config_parameter', 'set_param', ['google_management_client_id', ga_client_id]).then(function(){
self.on_date_range_button('week');
});
},
@@ -0,0 +1,41 @@
/**
* Service to fetch data, websites Javascript must use performModelRPC of this module
*/
odoo.define('website.model', function (require) {
"use strict";
var Class = require('web.Class');
var Mixins = require('web.mixins');
var ajax = require('web.ajax');
var CallService = Class.extend(Mixins.EventDispatcherMixin, {
custom_events: {
call_service: '_callService'
},
init: function () {
Mixins.EventDispatcherMixin.init.call(this);
},
//--------------------------------------------------------------------------
// Private
//--------------------------------------------------------------------------
/**
* @private
* @param {OdooEvent} event
*/
_callService: function (event) {
var result = ajax[event.data.method].apply(ajax, event.data.args);
event.data.callback(result);
},
});
var Model = Class.extend(Mixins.EventDispatcherMixin, Mixins.ServicesMixin, {
init: function (parent) {
Mixins.EventDispatcherMixin.init.call(this);
this.setParent(parent);
},
});
return new Model(new CallService());
});
+2 -3
View File
@@ -6,7 +6,6 @@ var ajax = require('web.ajax');
var Class = require('web.Class');
var Dialog = require('web.Dialog');
var mixins = require('web.mixins');
var Model = require('web.Model');
var Widget = require('web.Widget');
var base = require('web_editor.base');
var website = require('website.website');
@@ -491,7 +490,7 @@ var Configurator = Dialog.extend({
def.resolve(null);
} else {
var fields = ['website_meta_title', 'website_meta_description', 'website_meta_keywords'];
var model = new Model(obj.model).call('read', [[obj.id], fields, base.get_context()]).then(function (data) {
this.performModelRPC(obj.model, 'read', [[obj.id], fields, base.get_context()]).then(function (data) {
if (data.length) {
var meta = data[0];
meta.model = obj.model;
@@ -510,7 +509,7 @@ var Configurator = Dialog.extend({
if (!obj) {
return $.Deferred().reject();
} else {
return new Model(obj.model).call('write', [[obj.id], data, base.get_context()]);
return this.performModelRPC(obj.model, 'write', [[obj.id], data, base.get_context()]);
}
},
titleChanged: function () {
@@ -4,7 +4,6 @@ odoo.define('website.snippets.editor', function (require) {
var ajax = require("web.ajax");
var core = require("web.core");
var Dialog = require("web.Dialog");
var Model = require("web.Model");
var editor = require("web_editor.editor");
var animation = require('web_editor.snippets.animation');
var options = require('web_editor.snippets.options');
@@ -55,6 +54,7 @@ options.registry.menu_data = options.Class.extend({
options.registry.company_data = options.Class.extend({
start: function () {
var self = this;
this._super.apply(this, arguments);
var proto = options.registry.company_data.prototype;
@@ -62,7 +62,7 @@ options.registry.company_data = options.Class.extend({
if (proto.__link_deferred === undefined) {
proto.__link_deferred = $.Deferred();
return ajax.jsonRpc("/web/session/get_session_info", "call").then(function (session) {
return (new Model("res.users")).get_func("read")(session.uid, ["company_id"]).then(function (res) {
return self.performModelRPC("res.users", "read", [session.uid, ["company_id"]]).then(function (res) {
proto.__link_deferred.resolve(
"/web#action=base.action_res_company_form&view_type=form&id=" + (res && res[0] && res[0].company_id[0] || 1)
);
@@ -21,6 +21,7 @@
</xpath>
<xpath expr="//script[last()]" position="after">
<script type="text/javascript" src="/website/static/src/js/website.js"></script>
<script type="text/javascript" src="/website/static/src/js/website.model.js"></script>
<script type="text/javascript" src="/website/static/src/js/website.share.js"></script>
<script type="text/javascript" src="/website/static/src/js/website.snippets.animation.js"></script>
<script type="text/javascript" src="/website/static/src/js/website.zoomodoo.js"></script>
@@ -3,7 +3,6 @@ odoo.define('website_blog.new_blog_post', function (require) {
var core = require('web.core');
var base = require('web_editor.base');
var Model = require('web.Model');
var website = require('website.website');
var contentMenu = require('website.contentMenu');
@@ -11,8 +10,7 @@ var _t = core._t;
contentMenu.TopBar.include({
new_blog_post: function () {
var model = new Model('blog.blog');
model.call('name_search', [], { context: base.get_context() }).then(function (blog_ids) {
this.performModelRPC('blog.blog', 'name_search', [], { context: base.get_context() }).then(function (blog_ids) {
if (blog_ids.length === 1) {
document.location = '/blog/' + blog_ids[0][0] + '/post/new';
} else if (blog_ids.length > 1) {
@@ -1,7 +1,7 @@
odoo.define('crm.partner_assign', function (require) {
'use strict';
var Model = require('web.Model');
var model = require('website.model');
var website = require('website.website');
/*
* This file is intended to add interactivity to survey forms rendered by
@@ -21,8 +21,8 @@ $('.interested_partner_assign_confirm').on('click',function(e){
var $btn = $(this);
if ($('.interested_partner_assign_form .comment_interested').val() && $('.interested_partner_assign_form .contacted_interested').prop('checked')){
$btn.prop('disabled', true);
new Model('crm.lead')
.call("partner_interested",[[parseInt($('.interested_partner_assign_form .assign_lead_id').val())], $('.interested_partner_assign_form .comment_interested').val()])
model.performModelRPC('crm.lead', "partner_interested",
[[parseInt($('.interested_partner_assign_form .assign_lead_id').val())], $('.interested_partner_assign_form .comment_interested').val()])
.then(function(){
window.location.href = '/my/leads';
})
@@ -39,8 +39,7 @@ $('.interested_partner_assign_confirm').on('click',function(e){
$('.desinterested_partner_assign_confirm').on('click',function(){
var $btn = $(this);
$btn.prop('disabled', true);
new Model('crm.lead')
.call("partner_desinterested",
model.performModelRPC('crm.lead', "partner_desinterested",
[[parseInt($('.desinterested_partner_assign_form .assign_lead_id').val())],
$('.desinterested_partner_assign_form .comment_desinterested').val(),
$('.desinterested_partner_assign_form .contacted_desinterested').prop('checked'),
@@ -57,8 +56,7 @@ $('.desinterested_partner_assign_confirm').on('click',function(){
opp_stage_buttons.on('click',function(e){
var $btn = $(this);
$btn.prop('disabled', true);
new Model('crm.lead')
.call("write", [[parseInt(e.currentTarget.getAttribute('opp'))],{
model.performModelRPC('crm.lead', "write", [[parseInt(e.currentTarget.getAttribute('opp'))],{
stage_id: parseInt(e.currentTarget.getAttribute('data')),
},], {context: {website_partner_assign:1}})
.fail(function() {
@@ -78,8 +76,7 @@ $('.edit_contact_form .country_id').on('change', function(){
$('.edit_contact_confirm').on('click',function(){
var $btn = $(this);
$btn.prop('disabled', true);
new Model('crm.lead')
.call("write", [[parseInt($('.edit_contact_form .opportunity_id').val())],{
model.performModelRPC('crm.lead', "write", [[parseInt($('.edit_contact_form .opportunity_id').val())],{
partner_name: $('.edit_contact_form .partner_name').val(),
phone: $('.edit_contact_form .phone').val(),
mobile: $('.edit_contact_form .mobile').val(),
@@ -103,8 +100,7 @@ $('.edit_contact_confirm').on('click',function(){
$('.new_opp_confirm').on('click',function(e){
var $btn = $(this);
$btn.prop('disabled', true);
new Model('crm.lead')
.call("create_opp_portal", [{
model.performModelRPC('crm.lead', "create_opp_portal", [{
contact_name: $('.new_opp_form .contact_name').val(),
title: $('.new_opp_form .title').val(),
description: $('.new_opp_form .description').val(),
@@ -129,8 +125,7 @@ $('.new_opp_confirm').on('click',function(e){
$('.edit_opp_confirm').on('click',function(){
var $btn = $(this);
$btn.prop('disabled', true);
new Model('crm.lead')
.call("update_lead_portal", [[parseInt($('.edit_opp_form .opportunity_id').val())],{
model.performModelRPC('crm.lead', "update_lead_portal", [[parseInt($('.edit_opp_form .opportunity_id').val())],{
date_deadline: $('.edit_opp_form .date_deadline').val(),
planned_revenue: parseFloat($('.edit_opp_form .planned_revenue').val()),
probability: parseFloat($('.edit_opp_form .probability').val()),
@@ -6,7 +6,7 @@ var core = require('web.core');
var Widget = require('web.Widget');
var base = require('web_editor.base');
var website = require('website.website');
var Model = require('web.Model');
var model = require('website.model');
var qweb = core.qweb;
var _t = core._t;
@@ -20,7 +20,7 @@ if(!$('.o_website_links_create_tracked_url').length) {
var SelectBox = Widget.extend({
init: function(obj) {
this.obj = new Model(obj);
this.obj = obj;
},
start: function(element, placeholder) {
var self = this;
@@ -49,7 +49,7 @@ if(!$('.o_website_links_create_tracked_url').length) {
});
},
fetch_objects: function() {
return this.obj.call('search_read', [[]]).then(function(result) {
return model.performModelRPC(this.obj, 'search_read', [[]]).then(function(result) {
return _.map(result, function(val) {
return {id: val.id, text:val.name};
});
@@ -68,7 +68,7 @@ if(!$('.o_website_links_create_tracked_url').length) {
create_object: function(name) {
var self = this;
return this.obj.call('create', [{name:name}]).then(function(record) {
return model.performModelRPC(this.obj, 'create', [{name:name}]).then(function(record) {
self.element.attr('value', record);
self.objects.push({'id': record, 'text': name});
});
@@ -4,7 +4,7 @@ odoo.define('website_links.charts', function (require) {
var Widget = require('web.Widget');
var base = require('web_editor.base');
var website = require('website.website');
var Model = require('web.Model');
var model = require('website.model');
var exports = {};
@@ -130,7 +130,6 @@ if(!$('.o_website_links_chart').length) {
// Get the code of the link
var link_id = $('#link_id').val();
var clicks = new Model('link.tracker.click');
var links_domain = ['link_id', '=', parseInt(link_id)];
var total_clicks = function() {
@@ -138,24 +137,24 @@ if(!$('.o_website_links_chart').length) {
};
var clicks_by_day = function() {
return clicks.call('read_group', [[links_domain], ['create_date']],
return model.performModelRPC('link.tracker.click', 'read_group', [[links_domain], ['create_date']],
{'groupby':'create_date:day'});
};
var clicks_by_country = function() {
return clicks.call('read_group', [[links_domain], ['country_id']],
return model.performModelRPC('link.tracker.click', 'read_group', [[links_domain], ['country_id']],
{'groupby':'country_id'});
};
var last_week_clicks_by_country = function() {
var interval = moment().subtract(7, 'days').format("YYYY-MM-DD");
return clicks.call('read_group', [[links_domain, ['create_date', '>', interval]], ['country_id']],
return model.performModelRPC('link.tracker.click', 'read_group', [[links_domain, ['create_date', '>', interval]], ['country_id']],
{'groupby':'country_id'});
};
var last_month_clicks_by_country = function() {
var interval = moment().subtract(30, 'days').format("YYYY-MM-DD");
return clicks.call('read_group', [[links_domain, ['create_date', '>', interval]], ['country_id']],
return model.performModelRPC('link.tracker.click', 'read_group', [[links_domain, ['create_date', '>', interval]], ['country_id']],
{'groupby':'country_id'});
};
@@ -2,7 +2,7 @@ odoo.define('website_mail_channel.editor', function (require) {
'use strict';
var core = require('web.core');
var Model = require('web.Model');
var model = require('website.model');
var base = require('web_editor.base');
var options = require('web_editor.snippets.options');
var website = require('website.website');
@@ -18,8 +18,8 @@ options.registry.subscribe = options.Class.extend({
window_title: _t("Add a Subscribe Button"),
select: _t("Discussion List"),
init: function (field) {
return new Model('mail.channel')
.call('name_search', ['', [['public','=','public']]], { context: base.get_context() });
return model.performModelRPC('mail.channel', 'name_search',
['', [['public','=','public']]], { context: base.get_context() });
},
}).then(function (mail_channel_id) {
self.$target.attr("data-id", mail_channel_id);
@@ -1,7 +1,7 @@
odoo.define('website_mass_mailing.editor', function (require) {
'use strict';
var Model = require('web.Model');
var model = require('website.model');
var ajax = require('web.ajax');
var core = require('web.core');
var base = require('web_editor.base');
@@ -21,7 +21,7 @@ var mass_mailing_common = options.Class.extend({
'window_title': this.popup_title,
'select': _t("Newsletter"),
'init': function (field) {
return new Model('mail.mass_mailing.list').call('name_search', ['', []], { context: base.get_context() });
return model.performModelRPC('mail.mass_mailing.list', 'name_search', ['', []], { context: base.get_context() });
},
});
def.then(function (mailing_list_id) {
@@ -3,7 +3,7 @@ odoo.define('website_sale.editor', function (require) {
var ajax = require('web.ajax');
var core = require('web.core');
var Model = require('web.Model');
var model = require('website.model');
var contentMenu = require('website.contentMenu');
var options = require('web_editor.snippets.options');
@@ -44,8 +44,7 @@ options.registry.website_sale = options.Class.extend({
if (size_y >= 4) $select = $select.add($size.find('tr:eq(3) td:lt('+size_x+')'));
$select.addClass("selected");
new Model('product.style')
.call('search_read', [[]])
model.performModelRPC('product.style', 'search_read', [[]])
.then(function (data) {
var $ul = self.$el.find('ul[name="style"]');
for (var k in data) {