diff options
| author | Géry Debongnie <ged@odoo.com> | 2017-03-05 09:34:56 +0100 |
|---|---|---|
| committer | Aaron Bohy <aab@odoo.com> | 2017-04-11 19:44:38 +0200 |
| commit | e5740270568404d71a3bc093074a085c9c2eded8 (patch) | |
| tree | 7b84740d92c550236de25a37cf37d244760bdbf3 | |
| parent | 0df9968433389e0d504276cd711473c2eef937ae (diff) | |
[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
64 files changed, 1740 insertions, 1552 deletions
diff --git a/addons/account/static/src/js/reconciliation/reconciliation_model.js b/addons/account/static/src/js/reconciliation/reconciliation_model.js index f69a3f0f279..7b2efb82de1 100644 --- a/addons/account/static/src/js/reconciliation/reconciliation_model.js +++ b/addons/account/static/src/js/reconciliation/reconciliation_model.js @@ -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)); }, }); diff --git a/addons/barcodes/static/src/js/barcode_parser.js b/addons/barcodes/static/src/js/barcode_parser.js index 1f804a40fea..926d8a11c82 100644 --- a/addons/barcodes/static/src/js/barcode_parser.js +++ b/addons/barcodes/static/src/js/barcode_parser.js @@ -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; - - return new Model('barcode.rule') - .query(['name','sequence','type','encoding','pattern','alias']) - .filter([['barcode_nomenclature_id','=',self.nomenclature.id ]]) - .all(); + 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]; + + 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; }); }, diff --git a/addons/barcodes/static/src/js/form_view_barcode_handler.js b/addons/barcodes/static/src/js/form_view_barcode_handler.js index 9e547611591..2b3fe8cfaad 100644 --- a/addons/barcodes/static/src/js/form_view_barcode_handler.js +++ b/addons/barcodes/static/src/js/form_view_barcode_handler.js @@ -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); diff --git a/addons/base_import/static/src/js/base_import.js b/addons/base_import/static/src/js/base_import.js index c965dade072..7e8dc588e10 100644 --- a/addons/base_import/static/src/js/base_import.js +++ b/addons/base_import/static/src/js/base_import.js @@ -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; diff --git a/addons/crm/static/src/js/sales_team_dashboard.js b/addons/crm/static/src/js/sales_team_dashboard.js index 450803bf591..9ab331d70bb 100644 --- a/addons/crm/static/src/js/sales_team_dashboard.js +++ b/addons/crm/static/src/js/sales_team_dashboard.js @@ -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(); }, }); diff --git a/addons/google_drive/static/src/js/gdrive.js b/addons/google_drive/static/src/js/gdrive.js index 6da06dcd8ec..170c992f8f8 100644 --- a/addons/google_drive/static/src/js/gdrive.js +++ b/addons/google_drive/static/src/js/gdrive.js @@ -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'); + } + }); }); - }); }, - }); }); diff --git a/addons/hr_attendance/static/src/js/greeting_message.js b/addons/hr_attendance/static/src/js/greeting_message.js index c0f120983ad..9eef6691baf 100644 --- a/addons/hr_attendance/static/src/js/greeting_message.js +++ b/addons/hr_attendance/static/src/js/greeting_message.js @@ -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); diff --git a/addons/hr_attendance/static/src/js/kiosk_confirm.js b/addons/hr_attendance/static/src/js/kiosk_confirm.js index 70dacd6300b..d66e1982989 100644 --- a/addons/hr_attendance/static/src/js/kiosk_confirm.js +++ b/addons/hr_attendance/static/src/js/kiosk_confirm.js @@ -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 () { diff --git a/addons/hr_attendance/static/src/js/kiosk_mode.js b/addons/hr_attendance/static/src/js/kiosk_mode.js index 51c78bd34b4..24b843028c6 100644 --- a/addons/hr_attendance/static/src/js/kiosk_mode.js +++ b/addons/hr_attendance/static/src/js/kiosk_mode.js @@ -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); diff --git a/addons/hr_attendance/static/src/js/my_attendances.js b/addons/hr_attendance/static/src/js/my_attendances.js index beed3c441e6..f4df4b7306a 100644 --- a/addons/hr_attendance/static/src/js/my_attendances.js +++ b/addons/hr_attendance/static/src/js/my_attendances.js @@ -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); diff --git a/addons/hr_timesheet_sheet/static/src/js/timesheet.js b/addons/hr_timesheet_sheet/static/src/js/timesheet.js index 0cf726548cc..50d6754e006 100644 --- a/addons/hr_timesheet_sheet/static/src/js/timesheet.js +++ b/addons/hr_timesheet_sheet/static/src/js/timesheet.js @@ -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]; - }); - projects = _.sortBy(projects, function(el) { - return project_names[el.project]; + 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]; + }); }); - }); - })).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)); diff --git a/addons/mail/static/src/js/activity.js b/addons/mail/static/src/js/activity.js index 9c81966929a..d1afae2e675 100644 --- a/addons/mail/static/src/js/activity.js +++ b/addons/mail/static/src/js/activity.js @@ -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) { diff --git a/addons/mail/static/src/js/chat_manager.js b/addons/mail/static/src/js/chat_manager.js index 86438de1c9b..709ff965df9 100644 --- a/addons/mail/static/src/js/chat_manager.js +++ b/addons/mail/static/src/js/chat_manager.js @@ -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; diff --git a/addons/mail/static/src/js/chatter.js b/addons/mail/static/src/js/chatter.js index 55b0766dd79..67f29ab1bbb 100644 --- a/addons/mail/static/src/js/chatter.js +++ b/addons/mail/static/src/js/chatter.js @@ -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 }); diff --git a/addons/mail/static/src/js/chatter_composer.js b/addons/mail/static/src/js/chatter_composer.js index e9bc075bf3b..4e7eb6a14ec 100644 --- a/addons/mail/static/src/js/chatter_composer.js +++ b/addons/mail/static/src/js/chatter_composer.js @@ -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 || []; diff --git a/addons/mail/static/src/js/client_action.js b/addons/mail/static/src/js/client_action.js index 1f2e5eb1de7..e461161c437 100644 --- a/addons/mail/static/src/js/client_action.js +++ b/addons/mail/static/src/js/client_action.js @@ -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) { diff --git a/addons/mail/static/src/js/composer.js b/addons/mail/static/src/js/composer.js index 4d471577922..b8a25cda7e3 100644 --- a/addons/mail/static/src/js/composer.js +++ b/addons/mail/static/src/js/composer.js @@ -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, }); diff --git a/addons/mail/static/src/js/followers.js b/addons/mail/static/src/js/followers.js index 9d71039c229..d56d5944d6b 100644 --- a/addons/mail/static/src/js/followers.js +++ b/addons/mail/static/src/js/followers.js @@ -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)); } }, diff --git a/addons/point_of_sale/static/src/js/devices.js b/addons/point_of_sale/static/src/js/devices.js index 50147f46b8b..9e6846e89cc 100644 --- a/addons/point_of_sale/static/src/js/devices.js +++ b/addons/point_of_sale/static/src/js/devices.js @@ -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) { diff --git a/addons/point_of_sale/static/src/js/gui.js b/addons/point_of_sale/static/src/js/gui.js index 3f81181ba87..079159aac6f 100644 --- a/addons/point_of_sale/static/src/js/gui.js +++ b/addons/point_of_sale/static/src/js/gui.js @@ -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'); diff --git a/addons/point_of_sale/static/src/js/models.js b/addons/point_of_sale/static/src/js/models.js index 0ccbfcd95e3..e59f3ddd7c2 100644 --- a/addons/point_of_sale/static/src/js/models.js +++ b/addons/point_of_sale/static/src/js/models.js @@ -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){ diff --git a/addons/point_of_sale/static/src/js/screens.js b/addons/point_of_sale/static/src/js/screens.js index 9505f814cdb..db5e45d93fc 100644 --- a/addons/point_of_sale/static/src/js/screens.js +++ b/addons/point_of_sale/static/src/js/screens.js @@ -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 diff --git a/addons/pos_cache/static/src/js/pos_cache.js b/addons/pos_cache/static/src/js/pos_cache.js index 29d5e3bfbc4..1e49b36e4c9 100644 --- a/addons/pos_cache/static/src/js/pos_cache.js +++ b/addons/pos_cache/static/src/js/pos_cache.js @@ -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; - // 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; + var product_index = _.findIndex(this.models, function (model) { + return model.model === "product.product"; + }); - // 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); - } + // 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; - 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]); + // 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); + } - self.chrome.loading_message(_t('Loading') + ' product.product', 1); - return records.then(function (product) { - self.db.add_products(product); - }); + 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); }); - }, - }); + }); + }, +}); + }); diff --git a/addons/pos_mercury/static/src/js/pos_mercury.js b/addons/pos_mercury/static/src/js/pos_mercury.js index 20e602c7aa2..8e485bcbf4a 100644 --- a/addons/pos_mercury/static/src/js/pos_mercury.js +++ b/addons/pos_mercury/static/src/js/pos_mercury.js @@ -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; - } - - 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; - } + 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; + } - var response = self.pos.decodeMercuryResponse(data); - response.journal_id = parsed_result.journal_id; + if (data === "not setup") { + def.resolve({ + message: _t("Please setup your Mercury merchant account.") + }); + return; + } - 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 === "internal error") { def.resolve({ - message: lookUpCodeTransaction["Approved"][response.error], - auto_close: true, + message: _t("Odoo error while processing transaction.") }); - } 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)); - } + var response = self.pos.decodeMercuryResponse(data); + response.journal_id = 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 { + 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); + 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; + } - 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 + if (data === "internal error") { def.resolve({ - message: _t("Reversal succeeded"), + message: _t("Odoo error while processing transaction.") }); - - self.remove_paymentline_by_ref(line); + 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 { - def.resolve({ - message: "Error " + response.error + ":<br/>" + response.message, - }); + 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]); - }); + }).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++) { diff --git a/addons/pos_restaurant/static/src/js/floors.js b/addons/pos_restaurant/static/src/js/floors.js index df01bcbb9ad..2a7653148ff 100644 --- a/addons/pos_restaurant/static/src/js/floors.js +++ b/addons/pos_restaurant/static/src/js/floors.js @@ -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(); - }); - }, 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.'), + 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(); }); - 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.'), diff --git a/addons/project/static/src/js/project.js b/addons/project/static/src/js/project.js index 33cf8e6c86d..0b2a663cc5c 100644 --- a/addons/project/static/src/js/project.js +++ b/addons/project/static/src/js/project.js @@ -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); } diff --git a/addons/sale/static/src/js/sale.js b/addons/sale/static/src/js/sale.js index 8565f95159c..ee43610dfb7 100644 --- a/addons/sale/static/src/js/sale.js +++ b/addons/sale/static/src/js/sale.js @@ -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}); + }); } }); }, diff --git a/addons/sales_team/static/src/js/sales_team_dashboard.js b/addons/sales_team/static/src/js/sales_team_dashboard.js index 838395a7346..72f053497a9 100644 --- a/addons/sales_team/static/src/js/sales_team_dashboard.js +++ b/addons/sales_team/static/src/js/sales_team_dashboard.js @@ -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({ diff --git a/addons/web/static/src/js/_deprecated/data.js b/addons/web/static/src/js/_deprecated/data.js index f6a58367903..3c95ababc3a 100644 --- a/addons/web/static/src/js/_deprecated/data.js +++ b/addons/web/static/src/js/_deprecated/data.js @@ -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; + }); diff --git a/addons/web/static/src/js/_deprecated/data_model.js b/addons/web/static/src/js/_deprecated/data_model.js deleted file mode 100644 index 3bae06a3f4c..00000000000 --- a/addons/web/static/src/js/_deprecated/data_model.js +++ /dev/null @@ -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; -}); diff --git a/addons/web/static/src/js/_deprecated/model.js b/addons/web/static/src/js/_deprecated/model.js deleted file mode 100644 index 377ff1a1757..00000000000 --- a/addons/web/static/src/js/_deprecated/model.js +++ /dev/null @@ -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; -}); diff --git a/addons/web/static/src/js/apps.js b/addons/web/static/src/js/apps.js index 8c5135f3b7b..a1f85d6ae31 100644 --- a/addons/web/static/src/js/apps.js +++ b/addons/web/static/src/js/apps.js @@ -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); diff --git a/addons/web/static/src/js/chrome/search_inputs.js b/addons/web/static/src/js/chrome/search_inputs.js index a5ff4401006..df5abe22a93 100644 --- a/addons/web/static/src/js/chrome/search_inputs.js +++ b/addons/web/static/src/js/chrome/search_inputs.js @@ -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'); diff --git a/addons/web/static/src/js/chrome/web_client.js b/addons/web/static/src/js/chrome/web_client.js index 17993c73638..f668676673c 100644 --- a/addons/web/static/src/js/chrome/web_client.js +++ b/addons/web/static/src/js/chrome/web_client.js @@ -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'); diff --git a/addons/web/static/src/js/core/mixins.js b/addons/web/static/src/js/core/mixins.js index 6f640cb3300..1a72beefafd 100644 --- a/addons/web/static/src/js/core/mixins.js +++ b/addons/web/static/src/js/core/mixins.js @@ -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) { diff --git a/addons/web/static/src/js/core/widget.js b/addons/web/static/src/js/core/widget.js index 221a127c9dd..84a7c48c20e 100644 --- a/addons/web/static/src/js/core/widget.js +++ b/addons/web/static/src/js/core/widget.js @@ -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; diff --git a/addons/web/static/src/js/fields/basic_fields.js b/addons/web/static/src/js/fields/basic_fields.js index 76275a11d3e..6b2cd4d6754 100644 --- a/addons/web/static/src/js/fields/basic_fields.js +++ b/addons/web/static/src/js/fields/basic_fields.js @@ -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)); }); }, /** diff --git a/addons/web/static/src/js/fields/relational_fields.js b/addons/web/static/src/js/fields/relational_fields.js index b3b3a26c437..c5750c86735 100644 --- a/addons/web/static/src/js/fields/relational_fields.js +++ b/addons/web/static/src/js/fields/relational_fields.js @@ -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(); } diff --git a/addons/web/static/src/js/services/data_manager.js b/addons/web/static/src/js/services/data_manager.js index 7188f7d9126..e86f1b9bb39 100644 --- a/addons/web/static/src/js/services/data_manager.js +++ b/addons/web/static/src/js/services/data_manager.js @@ -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 }); diff --git a/addons/web/static/src/js/views/basic/basic_model.js b/addons/web/static/src/js/views/basic/basic_model.js index a66e3a9d3ab..5c0facecef1 100644 --- a/addons/web/static/src/js/views/basic/basic_model.js +++ b/addons/web/static/src/js/views/basic/basic_model.js @@ -182,7 +182,7 @@ var BasicModel = AbstractModel.extend({ }); }, /** - * Delete a list of records, then, if a parent_id is given, reload the + * Delete a list of records, then, if a parentID is given, reload the * parent. * * @todo we should remove the deleted records from the localData @@ -193,24 +193,26 @@ var BasicModel = AbstractModel.extend({ * @param {string[]} recordIds list of local resources ids. They should all * be of type 'record', and of the same model * @param {string} modelName - * @param {string} parent_id + * @param {string} parentID * @returns {Deferred} */ - deleteRecords: function (recordIds, modelName, parent_id) { + deleteRecords: function (recordIds, modelName, parentID) { var self = this; var records = _.map(recordIds, function (id) { return self.localData[id]; }); - return this.performModelRPC(modelName, 'unlink', [_.pluck(records, 'res_id')], { - context: session.user_context, // todo: combine with view context - }).then(function () { - _.each(records, function (record) { - record.res_ids.splice(record.offset, 1)[0]; - record.res_id = record.res_ids[record.offset]; - record.count--; + return this.rpc(modelName, 'unlink') + .args([_.pluck(records, 'res_id')]) + .withContext(session.user_context) // todo: combine with view context + .exec() + .then(function () { + _.each(records, function (record) { + record.res_ids.splice(record.offset, 1)[0]; + record.res_id = record.res_ids[record.offset]; + record.count--; + }); + if (parentID) { + return self.reload(parentID); + } }); - if (parent_id) { - return self.reload(parent_id); - } - }); }, /** * Discard all changes in a local resource. Basically, it removes @@ -233,20 +235,22 @@ var BasicModel = AbstractModel.extend({ duplicateRecord: function (recordID) { var self = this; var record = this.localData[recordID]; - return this.performModelRPC(record.model, 'copy', [record.data.id], { - context: this._getContext(record), - }).then(function (res_id) { - var index = record.res_ids.indexOf(record.res_id); - record.res_ids.splice(index + 1, 0, res_id); - return self.load({ - fieldAttrs: record.fieldAttrs, - fieldNames: record.fieldNames, - fields: record.fields, - modelName: record.model, - res_id: res_id, - res_ids: record.res_ids.slice(0), + return this.rpc(record.model, 'copy') + .args([record.data.id]) + .withContext(this._getContext(record)) + .exec() + .then(function (res_id) { + var index = record.res_ids.indexOf(record.res_id); + record.res_ids.splice(index + 1, 0, res_id); + return self.load({ + fieldAttrs: record.fieldAttrs, + fieldNames: record.fieldNames, + fields: record.fields, + modelName: record.model, + res_id: res_id, + res_ids: record.res_ids.slice(0), + }); }); - }); }, /** * The get method first argument is the handle returned by the load method. @@ -442,156 +446,158 @@ var BasicModel = AbstractModel.extend({ var self = this; var fields_key = _.without(params.fieldNames, '__last_update'); - return this.performModelRPC(modelName, 'default_get', [fields_key], { - context: params.context, - }).then(function (result) { - // fill default values for missing fields - for (var i = 0; i < params.fieldNames.length; i++) { - var fieldName = params.fieldNames[i]; - if (!(fieldName in result)) { - var field = params.fields[fieldName]; - if (field.type === 'one2many' || field.type === 'many2many') { - result[fieldName] = []; - } else { - result[fieldName] = null; + return this.rpc(modelName, 'default_get') + .args([fields_key]) + .withContext(params.context) + .exec() + .then(function (result) { + // fill default values for missing fields + for (var i = 0; i < params.fieldNames.length; i++) { + var fieldName = params.fieldNames[i]; + if (!(fieldName in result)) { + var field = params.fields[fieldName]; + if (field.type === 'one2many' || field.type === 'many2many') { + result[fieldName] = []; + } else { + result[fieldName] = null; + } } } - } - var data = {}; - var record = self._makeDataPoint({ - modelName: modelName, - data: data, - fields: params.fields, - fieldNames: params.fieldNames, - fieldAttrs: params.fieldAttrs, - context: params.context, - parentID: params.parentID, - relationField: params.relationField, - res_ids: params.res_ids, - }); + var data = {}; + var record = self._makeDataPoint({ + modelName: modelName, + data: data, + fields: params.fields, + fieldNames: params.fieldNames, + fieldAttrs: params.fieldAttrs, + context: params.context, + parentID: params.parentID, + relationField: params.relationField, + res_ids: params.res_ids, + }); - var defs = []; // FIXME: remove defs? - _.each(params.fieldNames, function (name) { - var field = params.fields[name]; - data[name] = null; - record._changes = record._changes || {}; - if (field.type === 'many2one' && result[name]) { - var rec = self._makeDataPoint({ - context: record.context, - data: {id: result[name]}, - modelName: field.relation, - }); - record._changes[name] = rec.id; - } else if (field.type === 'one2many' || field.type === 'many2many') { - var attrs = record.fieldAttrs[name]; - var x2manyList = self._makeDataPoint({ - context: record.context, - fieldAttrs: field.fieldAttrs, - fields: field.relatedFields, - limit: field.limit, - modelName: field.relation, - parentID: record.id, - rawContext: attrs && attrs.context, - relationField: field.relation_field, - res_ids: [], - static: true, - type: 'list', - }); - record._changes[name] = x2manyList.id; - var many2ones = {}; - var r; - _.each(result[name], function (value) { - if (_.isArray(value)) { - // value is a command - if (value[0] === 0) { - // CREATE + var defs = []; // FIXME: remove defs? + _.each(params.fieldNames, function (name) { + var field = params.fields[name]; + data[name] = null; + record._changes = record._changes || {}; + if (field.type === 'many2one' && result[name]) { + var rec = self._makeDataPoint({ + context: record.context, + data: {id: result[name]}, + modelName: field.relation, + }); + record._changes[name] = rec.id; + } else if (field.type === 'one2many' || field.type === 'many2many') { + var attrs = record.fieldAttrs[name]; + var x2manyList = self._makeDataPoint({ + context: record.context, + fieldAttrs: field.fieldAttrs, + fields: field.relatedFields, + limit: field.limit, + modelName: field.relation, + parentID: record.id, + rawContext: attrs && attrs.context, + relationField: field.relation_field, + res_ids: [], + static: true, + type: 'list', + }); + record._changes[name] = x2manyList.id; + var many2ones = {}; + var r; + _.each(result[name], function (value) { + if (_.isArray(value)) { + // value is a command + if (value[0] === 0) { + // CREATE + r = self._makeDataPoint({ + modelName: x2manyList.model, + context: x2manyList.context, + fields: field.relatedFields, + fieldAttrs: field.fieldAttrs, + }); + x2manyList._changes.push(r.id); + r._changes = value[2]; + + // this is necessary so the fields are initialized + for (var fieldName in value[2]) { + r.data[fieldName] = null; + } + + for (var name in r._changes) { + if (r.fields[name].type === 'many2one') { + var rec = self._makeDataPoint({ + context: r.context, + modelName: r.fields[name].relation, + data: {id: r._changes[name]} + }); + r._changes[name] = rec.id; + many2ones[name] = true; + } + } + } + if (value[0] === 6) { + // REPLACE_WITH + x2manyList._changes = []; + } + } else { + // value is an id r = self._makeDataPoint({ modelName: x2manyList.model, context: x2manyList.context, fields: field.relatedFields, fieldAttrs: field.fieldAttrs, + res_id: value, }); - x2manyList._changes.push(r.id); - r._changes = value[2]; - - // this is necessary so the fields are initialized - for (var fieldName in value[2]) { - r.data[fieldName] = null; - } - - for (var name in r._changes) { - if (r.fields[name].type === 'many2one') { - var rec = self._makeDataPoint({ - context: r.context, - modelName: r.fields[name].relation, - data: {id: r._changes[name]} - }); - r._changes[name] = rec.id; - many2ones[name] = true; - } + if (!x2manyList._changes) { + x2manyList._changes = []; } + x2manyList._changes.push(r.id); } - if (value[0] === 6) { - // REPLACE_WITH - x2manyList._changes = []; + }); + + // fetch many2ones display_name + _.each(_.keys(many2ones), function (name) { + defs.push(self._fetchNameGets(x2manyList, name)); + }); + } else if (field.type === 'date') { + // process date: convert into a moment instance + record._changes[name] = fieldUtils.parse.date(result[name]); + } else if (field.type === 'datetime') { + // process datetime: convert into a moment instance + record._changes[name] = fieldUtils.parse.datetime(result[name]); + } else { + record._changes[name] = result[name]; + } + }); + return $.when.apply($, defs) + .then(function () { + var shouldApplyOnchange = false; + var field; + for (var field_name in record.data) { + field = record.fields[field_name]; + if (field.onChange) { + shouldApplyOnchange = true; } + } + if (shouldApplyOnchange) { + return self._applyOnChange(record, fields_key); } else { - // value is an id - r = self._makeDataPoint({ - modelName: x2manyList.model, - context: x2manyList.context, - fields: field.relatedFields, - fieldAttrs: field.fieldAttrs, - res_id: value, - }); - if (!x2manyList._changes) { - x2manyList._changes = []; - } - x2manyList._changes.push(r.id); + return $.when(); } + }) + .then(function () { + return self._fetchRelationalData(record); + }) + .then(function () { + return self._postprocess(record); + }) + .then(function () { + return record.id; }); - - // fetch many2ones display_name - _.each(_.keys(many2ones), function (name) { - defs.push(self._fetchNameGets(x2manyList, name)); - }); - } else if (field.type === 'date') { - // process date: convert into a moment instance - record._changes[name] = fieldUtils.parse.date(result[name]); - } else if (field.type === 'datetime') { - // process datetime: convert into a moment instance - record._changes[name] = fieldUtils.parse.datetime(result[name]); - } else { - record._changes[name] = result[name]; - } }); - return $.when.apply($, defs) - .then(function () { - var shouldApplyOnchange = false; - var field; - for (var field_name in record.data) { - field = record.fields[field_name]; - if (field.onChange) { - shouldApplyOnchange = true; - } - } - if (shouldApplyOnchange) { - return self._applyOnChange(record, fields_key); - } else { - return $.when(); - } - }) - .then(function () { - return self._fetchRelationalData(record); - }) - .then(function () { - return self._postprocess(record); - }) - .then(function () { - return record.id; - }); - }); }, /** * This helper method is designed to help developpers that want to use a @@ -808,21 +814,23 @@ var BasicModel = AbstractModel.extend({ // in the case of a write, only perform the RPC if there are changes to save if (method === 'create' || Object.keys(changes).length) { var args = method === 'write' ? [[record.data.id], changes] : [changes]; - return self.performModelRPC(record.model, method, args, { - context: session.user_context, // todo: combine with view context - }).then(function (id) { - if (method === 'create') { - record.res_id = id; // create returns an id, write returns a boolean - record.data.id = id; - record.offset = record.res_ids.length; - record.res_ids.push(id); - record.count++; - } - // erase changes as they have been applied - record._changes = {}; + return self.rpc(record.model, method) + .args(args) + .withContext(session.user_context) // todo: combine with view context + .exec() + .then(function (id) { + if (method === 'create') { + record.res_id = id; // create returns an id, write returns a boolean + record.data.id = id; + record.offset = record.res_ids.length; + record.res_ids.push(id); + record.count++; + } + // erase changes as they have been applied + record._changes = {}; - return shouldReload ? self._fetchRecord(record) : false; - }); + return shouldReload ? self._fetchRecord(record) : false; + }); } else { return $.when(record_id); } @@ -881,7 +889,7 @@ var BasicModel = AbstractModel.extend({ * @param {Array} recordIDs local ids of the records to (un)archive * @param {boolean} value false to archive, true to unarchive (value of the active field) * @param {string} parentID id of the parent resource to reload - * @returns {Deferred -> string} resolves to the parent id + * @returns {Deferred<string>} resolves to the parent id */ toggleActive: function (recordIDs, value, parentID) { var self = this; @@ -889,8 +897,9 @@ var BasicModel = AbstractModel.extend({ var resIDs = _.map(recordIDs, function (recordID) { return self.localData[recordID].res_id; }); - return this - .performModelRPC(parent.model, 'write', [resIDs, { active: value }]) + return this.rpc(parent.model, 'write') + .args([resIDs, { active: value }]) + .exec() .then(this.reload.bind(this, parentID)); }, @@ -960,11 +969,13 @@ var BasicModel = AbstractModel.extend({ var def; if (!('display_name' in rel_data)) { var field = record.fields[fieldName]; - def = this.performModelRPC(field.relation, 'name_get', [data.id], { - context: record.context, - }).then(function (result) { - rel_data.display_name = result[0][1]; - }); + def = this.rpc(field.relation, 'name_get') + .args([data.id]) + .withContext(record.context) + .exec() + .then(function (result) { + rel_data.display_name = result[0][1]; + }); } return $.when(def).then(function () { var rec = self._makeDataPoint({ @@ -1010,96 +1021,98 @@ var BasicModel = AbstractModel.extend({ fields = fields[0]; } return this.mutex.exec(function () { - var args = [idList, currentData, fields, onchange_spec, context]; - return self.performModelRPC(record.model, 'onchange', args, {}).then(function (result) { - if (result.warning) { - self.trigger_up('warning', { - message: result.warning.message, - title: result.warning.title, - type: 'dialog', - }); - } - var defs = []; - _.each(result.value, function (val, name) { - var field = record.fields[name]; - if (!field) { return; } // ignore changes of unknown fields - - var rec; - if (field.type === 'many2one' ) { - // in some case, the value returned by the onchange can - // be false (no value), so we need to avoid creating a - // local record for that. - // FIXME: shouldn't we erase the value in that case? - if (val) { - // when the value isn't false, it can be either - // an array [id, display_name] or just an id. - var data = _.isArray(val) ? - {id: val[0], display_name: val[1]} : - {id: val}; - rec = self._makeDataPoint({ - context: context, - data: data, - modelName: field.relation, - }); - record._changes[name] = rec.id; - } - } else if (field.type === 'one2many' || field.type === 'many2many') { - record._changes = record._changes || {}; - var listId = record._changes[name] || record.data[name]; - var list = self.localData[listId]; - _.each(val, function (command) { - if (command[0] === 0 || command[0] === 1) { - // CREATE or UPDATE - var params = { + return self.rpc(record.model, 'onchange') + .args([idList, currentData, fields, onchange_spec, context]) + .exec() + .then(function (result) { + if (result.warning) { + self.trigger_up('warning', { + message: result.warning.message, + title: result.warning.title, + type: 'dialog', + }); + } + var defs = []; + _.each(result.value, function (val, name) { + var field = record.fields[name]; + if (!field) { return; } // ignore changes of unknown fields + + var rec; + if (field.type === 'many2one' ) { + // in some case, the value returned by the onchange can + // be false (no value), so we need to avoid creating a + // local record for that. + // FIXME: shouldn't we erase the value in that case? + if (val) { + // when the value isn't false, it can be either + // an array [id, display_name] or just an id. + var data = _.isArray(val) ? + {id: val[0], display_name: val[1]} : + {id: val}; + rec = self._makeDataPoint({ context: context, - fields: list.fields, - fieldAttrs: list.fieldAttrs, - modelName: list.model, - fieldNames: _.keys(command[2]), - }; - if (command[0] === 1) { - params.res_id = command[1]; - } - rec = self._makeDataPoint(params); - var data = command[2]; - _.each(rec.fieldNames, function (name) { - var field = rec.fields[name]; - if (field.type === 'many2one') { - var r = self._makeDataPoint({ - modelName: field.relation, - data: { - id: data[name][0], - display_name: data[name][1], - }, - }); - data[name] = r.id; - } + data: data, + modelName: field.relation, }); - rec._changes = data; - for (var f in rec._changes) { - rec.data[f] = null; - } - list._changes.push(rec.id); - } - if (command[0] === 5) { - // DELETE ALL - list._changes = []; + record._changes[name] = rec.id; } - }); - } else if (field.type === 'date') { - // process data: convert into a moment instance - record._changes[name] = fieldUtils.parse.date(val); - } else if (field.type === 'datetime') { - // process datetime: convert into a moment instance - record._changes[name] = fieldUtils.parse.datetime(val); - } else { - record._changes[name] = val; - } - }); - return $.when.apply($, defs).then(function () { - return result; + } else if (field.type === 'one2many' || field.type === 'many2many') { + record._changes = record._changes || {}; + var listId = record._changes[name] || record.data[name]; + var list = self.localData[listId]; + _.each(val, function (command) { + if (command[0] === 0 || command[0] === 1) { + // CREATE or UPDATE + var params = { + context: context, + fields: list.fields, + fieldAttrs: list.fieldAttrs, + modelName: list.model, + fieldNames: _.keys(command[2]), + }; + if (command[0] === 1) { + params.res_id = command[1]; + } + rec = self._makeDataPoint(params); + var data = command[2]; + _.each(rec.fieldNames, function (name) { + var field = rec.fields[name]; + if (field.type === 'many2one') { + var r = self._makeDataPoint({ + modelName: field.relation, + data: { + id: data[name][0], + display_name: data[name][1], + }, + }); + data[name] = r.id; + } + }); + rec._changes = data; + for (var f in rec._changes) { + rec.data[f] = null; + } + list._changes.push(rec.id); + } + if (command[0] === 5) { + // DELETE ALL + list._changes = []; + } + }); + } else if (field.type === 'date') { + // process data: convert into a moment instance + record._changes[name] = fieldUtils.parse.date(val); + } else if (field.type === 'datetime') { + // process datetime: convert into a moment instance + record._changes[name] = fieldUtils.parse.datetime(val); + } else { + record._changes[name] = val; + } + }); + return $.when.apply($, defs).then(function () { + return result; + }); }); - }); }); }, /** @@ -1158,8 +1171,9 @@ var BasicModel = AbstractModel.extend({ // _changes so this is a very specific case) // this could be optimized by registering the fetched records in the list's _cache // so that if a record is removed and then re-added, it won't be fetched twice - var def = this - .performModelRPC(list.model, 'read', [_.pluck(data, 'id'), list.fieldNames], {}) + var def = this.rpc(list.model, 'read') + .args([_.pluck(data, 'id'), list.fieldNames]) + .exec() .then(function (records) { _.each(records, function (record) { list_records[record.id].data = record; @@ -1241,14 +1255,16 @@ var BasicModel = AbstractModel.extend({ _fetchMany2OneGroup: function (group) { var ids = _.uniq(_.pluck(group, 'res_id')); - return this.performModelRPC(group[0].model, 'name_get', [ids], { - context: group[0].context, - }).then(function (name_gets) { - _.each(group, function (record) { - var nameGet = _.find(name_gets, function (n) { return n[0] === record.res_id;}); - record.data.display_name = nameGet[1]; + return this.rpc(group[0].model, 'name_get') + .args([ids]) + .withContext(group[0].context) + .exec() + .then(function (name_gets) { + _.each(group, function (record) { + var nameGet = _.find(name_gets, function (n) { return n[0] === record.res_id;}); + record.data.display_name = nameGet[1]; + }); }); - }); }, _fetchNameGets: function (list, fieldName) { var self = this; @@ -1263,13 +1279,15 @@ var BasicModel = AbstractModel.extend({ model = many2oneRecord.model; return many2oneRecord.res_id; }); - return this.performModelRPC(model, 'name_get', [ids], { - context: list.context, - }).then(function (name_gets) { - for (var i = 0; i < name_gets.length; i++) { - records[i].data.display_name = name_gets[i][1]; - } - }); + return this.rpc(model, 'name_get') + .args([ids]) + .withContext(list.context) + .exec() + .then(function (name_gets) { + for (var i = 0; i < name_gets.length; i++) { + records[i].data.display_name = name_gets[i][1]; + } + }); }, /** * For a given resource of type 'record', fetch all data. @@ -1283,45 +1301,47 @@ var BasicModel = AbstractModel.extend({ var self = this; fieldNames = fieldNames || _.uniq(record.fieldNames.concat(['display_name'])); var oldData = record.data; - return this.performModelRPC(record.model, 'read', [record.res_id, fieldNames], { - // context: { 'bin_size': true }, // FIXME: when editing a subrecord in the partner form view, it tries to write the bin_size on the image field - }).then(function (result) { - result = result[0]; - record.data = _.extend({}, record.data, result); - }).then(function () { - return self._fetchX2Manys(record, oldData, fieldNames).then(function () { - return self._postprocess(record); - }); - }).then(function (record) { - _.each(fieldNames, function (name) { - var field = record.fields[name]; - var val = record.data[name]; - if (field.type === 'many2one') { - // process many2one: split [id, nameget] and create corresponding record - if (val !== false) { - // the many2one value is of the form [id, display_name] - var r = self._makeDataPoint({ - modelName: field.relation, - data: { - display_name: val[1], - id: val[0], - }, - }); - record.data[name] = r.id; - } else { - // no value for the many2one - record.data[name] = false; + return this.rpc(record.model, 'read') + .args([[record.res_id], fieldNames]) + // .withContext({ bin_size: true }) // FIXME: when editing a subrecord in the partner form view, it tries to write the bin_size on the image field + .exec() + .then(function (result) { + result = result[0]; + record.data = _.extend({}, record.data, result); + }).then(function () { + return self._fetchX2Manys(record, oldData, fieldNames).then(function () { + return self._postprocess(record); + }); + }).then(function (record) { + _.each(fieldNames, function (name) { + var field = record.fields[name]; + var val = record.data[name]; + if (field.type === 'many2one') { + // process many2one: split [id, nameget] and create corresponding record + if (val !== false) { + // the many2one value is of the form [id, display_name] + var r = self._makeDataPoint({ + modelName: field.relation, + data: { + display_name: val[1], + id: val[0], + }, + }); + record.data[name] = r.id; + } else { + // no value for the many2one + record.data[name] = false; + } + } else if (field.type === 'date') { + // process data: convert into a moment instance + record.data[name] = fieldUtils.parse.date(val); + } else if (field.type === 'datetime') { + // process datetime: convert into a moment instance + record.data[name] = fieldUtils.parse.datetime(val); } - } else if (field.type === 'date') { - // process data: convert into a moment instance - record.data[name] = fieldUtils.parse.date(val); - } else if (field.type === 'datetime') { - // process datetime: convert into a moment instance - record.data[name] = fieldUtils.parse.datetime(val); - } + }); + return record; }); - return record; - }); }, /** * This method is incorrectly named. It should be named something like @@ -1473,33 +1493,35 @@ var BasicModel = AbstractModel.extend({ } // step 2: fetch data from server - return this.performModelRPC(field.relation, 'read', [ids, _.keys(field.relatedFields)], { - context: {}, // FIXME - }).then(function (results) { - // step 3: assign values to correct datapoints - var dataPoints = _.map(results, function (result) { - return self._makeDataPoint({ - modelName: field.relation, - data: result, - fields: field.relatedFields, - fieldAttrs: field.fieldAttrs, + return this.rpc(field.relation, 'read') + .args([ids, _.keys(field.relatedFields)]) + .withContext({}) // FIXME + .exec() + .then(function (results) { + // step 3: assign values to correct datapoints + var dataPoints = _.map(results, function (result) { + return self._makeDataPoint({ + modelName: field.relation, + data: result, + fields: field.relatedFields, + fieldAttrs: field.fieldAttrs, + }); }); - }); - _.each(list.data, function (dataPoint) { - var record = self.localData[dataPoint]; - var m2mList = self.localData[record.data[fieldName]]; + _.each(list.data, function (dataPoint) { + var record = self.localData[dataPoint]; + var m2mList = self.localData[record.data[fieldName]]; - m2mList.data = []; - _.each(m2mList.res_ids, function (res_id) { - var dataPoint = _.find(dataPoints, function (d) { - return d.res_id === res_id; + m2mList.data = []; + _.each(m2mList.res_ids, function (res_id) { + var dataPoint = _.find(dataPoints, function (d) { + return d.res_id === res_id; + }); + m2mList.data.push(dataPoint.id); + m2mList.count++; }); - m2mList.data.push(dataPoint.id); - m2mList.count++; }); }); - }); }, /** * batch request for x2ms for datapoint of type list @@ -1740,46 +1762,50 @@ var BasicModel = AbstractModel.extend({ var _domain = new data.CompoundDomain(field.domain || {}).set_eval_context(field_values); var domain = pyeval.eval('domain', _domain); var fold_field = pyeval.py_eval(attrs.options || '{}').fold_field; - var fetch_status_information = self.performRPC('/web/dataset/search_read', { - model: field.relation, - fields: ['id'].concat(fold_field ? [fold_field] : []), - domain: domain, - }).then(function (result) { - var ids = _.pluck(result.records, 'id'); - return self.performModelRPC(field.relation, 'name_get', [ids], { - context: self._getContext(record, {fieldName: name}), - }).then(function (name_gets) { - _.each(result.records, function (record) { - var name_get = _.find(name_gets, function (n) { - return n[0] === record.id; + var fetch_status_information = self.rpc(field.relation, 'search_read') + .withFields(['id'].concat(fold_field ? [fold_field] : [])) + .withDomain(domain) + .exec() + .then(function (result) { + var ids = _.pluck(result.records, 'id'); + return self.rpc(field.relation, 'name_get') + .args([ids]) + .withContext(self._getContext(record, {fieldName: name})) + .exec() + .then(function (name_gets) { + _.each(result.records, function (record) { + var name_get = _.find(name_gets, function (n) { + return n[0] === record.id; + }); + record.display_name = name_get[1]; + }); + field.__status_information = result.records; }); - record.display_name = name_get[1]; - }); - field.__status_information = result.records; }); - }); defs.push(fetch_status_information); } if (field.__always_reload) { if (record.data[name] instanceof Array) { - defs.push(self.performModelRPC(field.relation, 'name_get', [record.data[name][0]], { - context: self._getContext(record, {fieldName: name}), - }).then(function (result) { - record.data[name] = result[0]; - })); + defs.push(self.rpc(field.relation, 'name_get') + .args([record.data[name][0]]) + .withContext(self._getContext(record, {fieldName: name})) + .exec() + .then(function (result) { + record.data[name] = result[0]; + })); } } if (field.__fetch_selection && !self.many2ones[field.relation]) { - var fetchSelection = self - .performModelRPC(field.relation, 'name_search', [], {}) + var fetchSelection = self.rpc(field.relation, 'name_search') + .exec() .then(function (result) { self.many2ones[field.relation] = result; }); defs.push(fetchSelection); } if (field.__fetch_many2manys) { - var fetchMany2Manys = self - .performModelRPC(field.relation, 'name_search', [], {}) + var fetchMany2Manys = self.rpc(field.relation, 'name_search') + .exec() .then(function (result) { self.many2manys[field.relation] = result; }); @@ -1802,69 +1828,68 @@ var BasicModel = AbstractModel.extend({ _readGroup: function (list) { var self = this; var fields = _.uniq(list.fieldNames.concat(list.groupedBy)); - return this.performModelRPC(list.model, 'read_group', [], { - fields: fields, - context: list.context, - groupby: list.groupedBy, - domain: list.domain, - orderby: false, - lazy: true, - }).then(function (groups) { - var rawGroupBy = list.groupedBy[0].split(':')[0]; - var previousGroups = _.map(list.data, function (groupID) { - return self.localData[groupID]; - }); - list.data = []; - list.count = groups.length; - var defs = []; - - _.each(groups, function (group) { - var aggregateValues = {}; - _.each(group, function (value, key) { - if (_.contains(fields, key) && key !== list.groupedBy[0]) { - aggregateValues[key] = value; - } + return this.rpc(list.model, 'read_group') + .withFields(fields) + .withContext(list.context) + .groupBy(list.groupedBy) + .lazy(true) + .exec() + .then(function (groups) { + var rawGroupBy = list.groupedBy[0].split(':')[0]; + var previousGroups = _.map(list.data, function (groupID) { + return self.localData[groupID]; }); - var newGroup = self._makeDataPoint({ - modelName: list.model, - count: group[rawGroupBy + '_count'], - domain: group.__domain, - context: list.context, - fields: list.fields, - fieldNames: list.fieldNames, - fieldAttrs: list.fieldAttrs, - value: group[rawGroupBy], - aggregateValues: aggregateValues, - groupedBy: list.groupedBy.slice(1), - orderedBy: list.orderedBy, - limit: list.limit, - openGroupByDefault: list.openGroupByDefault, - type: 'list', // nested groupedBys not handled yet + list.data = []; + list.count = groups.length; + var defs = []; + + _.each(groups, function (group) { + var aggregateValues = {}; + _.each(group, function (value, key) { + if (_.contains(fields, key) && key !== list.groupedBy[0]) { + aggregateValues[key] = value; + } + }); + var newGroup = self._makeDataPoint({ + modelName: list.model, + count: group[rawGroupBy + '_count'], + domain: group.__domain, + context: list.context, + fields: list.fields, + fieldNames: list.fieldNames, + fieldAttrs: list.fieldAttrs, + value: group[rawGroupBy], + aggregateValues: aggregateValues, + groupedBy: list.groupedBy.slice(1), + orderedBy: list.orderedBy, + limit: list.limit, + openGroupByDefault: list.openGroupByDefault, + type: 'list', // nested groupedBys not handled yet + }); + list.data.push(newGroup.id); + var old_group = _.find(previousGroups, function (g) { + return g.res_id === newGroup.res_id && g.value === newGroup.value; + }); + if (old_group) { + newGroup.isOpen = old_group.isOpen; + } else if (!newGroup.openGroupByDefault) { + newGroup.isOpen = false; + } else { + newGroup.isOpen = '__fold' in group ? !group.__fold : true; + } + if (newGroup.isOpen && newGroup.count > 0) { + defs.push(self._fetchUngroupedList(newGroup)); + } }); - list.data.push(newGroup.id); - var old_group = _.find(previousGroups, function (g) { - return g.res_id === newGroup.res_id && g.value === newGroup.value; + return $.when.apply($, defs).then(function () { + // generate the res_ids of the main list, being the concatenation + // of the fetched res_ids in each group + list.res_ids = _.flatten(_.map(arguments, function (group) { + return group ? group.res_ids : []; + })); + return list; }); - if (old_group) { - newGroup.isOpen = old_group.isOpen; - } else if (!newGroup.openGroupByDefault) { - newGroup.isOpen = false; - } else { - newGroup.isOpen = '__fold' in group ? !group.__fold : true; - } - if (newGroup.isOpen && newGroup.count > 0) { - defs.push(self._fetchUngroupedList(newGroup)); - } }); - return $.when.apply($, defs).then(function () { - // generate the res_ids of the main list, being the concatenation - // of the fetched res_ids in each group - list.res_ids = _.flatten(_.map(arguments, function (group) { - return group ? group.res_ids : []; - })); - return list; - }); - }); }, /** * For 'static' list, such as one2manys in a form view, we can do a /read @@ -1887,9 +1912,10 @@ var BasicModel = AbstractModel.extend({ } } if (missingIds.length) { - def = this.performModelRPC(list.model, 'read', [missingIds, list.fieldNames], { - context: {}, // FIXME - }); + def = this.rpc(list.model, 'read') + .args([missingIds, list.fieldNames]) + .withContext({}) // FIXME + .exec(); } else { def = $.when(); } @@ -1946,67 +1972,52 @@ var BasicModel = AbstractModel.extend({ */ _searchReadUngroupedList: function (list) { var self = this; - return this.performRPC('/web/dataset/search_read', { - model: list.model, - fields: list.fieldNames, - domain: list.domain || [], - offset: list.offset, - limit: list.limit, - sort: this._serializeSort(list.orderedBy), - }).then(function (result) { - list.count = result.length; - var data = _.map(result.records, function (record) { - var dataPoint = self._makeDataPoint({ - data: record, - fields: list.fields, - fieldNames: list.fieldNames, - fieldAttrs: list.fieldAttrs, - modelName: list.model, - parentID: list.id, - }); + return this.rpc(list.model, 'search_read') + .withFields(list.fieldNames) + .withDomain(list.domain || []) + .withLimit(list.limit) + .withOffset(list.offset) + .orderBy(list.orderedBy) + .exec() + .then(function (result) { + list.count = result.length; + var data = _.map(result.records, function (record) { + var dataPoint = self._makeDataPoint({ + data: record, + fields: list.fields, + fieldNames: list.fieldNames, + fieldAttrs: list.fieldAttrs, + modelName: list.model, + parentID: list.id, + }); - // add many2one records - _.each(dataPoint.fieldNames, function (name) { - var field = dataPoint.fields[name]; - if (field.type === 'many2one') { - var r = self._makeDataPoint({ - modelName: field.relation, - data: { - id: dataPoint.data[name][0], - display_name: dataPoint.data[name][1], - } - }); + // add many2one records + _.each(dataPoint.fieldNames, function (name) { + var field = dataPoint.fields[name]; + if (field.type === 'many2one') { + var r = self._makeDataPoint({ + modelName: field.relation, + data: { + id: dataPoint.data[name][0], + display_name: dataPoint.data[name][1], + } + }); - dataPoint.data[name] = r.id; - } - if (field.type === 'date') { - dataPoint.data[name] = fieldUtils.parse.date(dataPoint.data[name]); - } - if (field.type === 'datetime') { - dataPoint.data[name] = fieldUtils.parse.datetime(dataPoint.data[name]); - } + dataPoint.data[name] = r.id; + } + if (field.type === 'date') { + dataPoint.data[name] = fieldUtils.parse.date(dataPoint.data[name]); + } + if (field.type === 'datetime') { + dataPoint.data[name] = fieldUtils.parse.datetime(dataPoint.data[name]); + } + }); + return dataPoint.id; }); - return dataPoint.id; + list.data = data; + list.res_ids = _.pluck(result.records, 'id'); + return list; }); - list.data = data; - list.res_ids = _.pluck(result.records, 'id'); - return list; - }); - }, - /** - * Helper method, generates a string to describe a ordered by sequence for - * SQL. - * - * For example, [{name: 'foo', asc: true}, {name: 'bar', asc: false}] will - * be converted into 'foo ASC, bar DESC' - * - * @param {Object[]} orderBy list of objects {name:..., asc: ...} - * @returns {string} - */ - _serializeSort: function (orderBy) { - return _.map(orderBy, function (order) { - return order.asc ? order.name + ' ASC' : order.name + ' DESC'; - }).join(', '); }, /** * Change the offset of a record. Note that this does not reload the data. diff --git a/addons/web/static/src/js/views/calendar/calendar_controller.js b/addons/web/static/src/js/views/calendar/calendar_controller.js index dbb574176f9..5f1b37a4a32 100644 --- a/addons/web/static/src/js/views/calendar/calendar_controller.js +++ b/addons/web/static/src/js/views/calendar/calendar_controller.js @@ -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)); }, diff --git a/addons/web/static/src/js/widgets/debug_manager.js b/addons/web/static/src/js/widgets/debug_manager.js index b09fa2d498b..59becd8faea 100644 --- a/addons/web/static/src/js/widgets/debug_manager.js +++ b/addons/web/static/src/js/widgets/debug_manager.js @@ -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)) ); diff --git a/addons/web/static/src/js/widgets/switch_company_menu.js b/addons/web/static/src/js/widgets/switch_company_menu.js index 89dc6ae29b3..b953791eec2 100644 --- a/addons/web/static/src/js/widgets/switch_company_menu.js +++ b/addons/web/static/src/js/widgets/switch_company_menu.js @@ -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)); diff --git a/addons/web_diagram/static/src/js/diagram_controller.js b/addons/web_diagram/static/src/js/diagram_controller.js index 9be51c28d08..e22f7ad99ac 100644 --- a/addons/web_diagram/static/src/js/diagram_controller.js +++ b/addons/web_diagram/static/src/js/diagram_controller.js @@ -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)); }, }); diff --git a/addons/web_editor/static/src/js/translator.js b/addons/web_editor/static/src/js/translator.js index bc431f3ba55..b2e7aa483fb 100644 --- a/addons/web_editor/static/src/js/translator.js +++ b/addons/web_editor/static/src/js/translator.js @@ -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); diff --git a/addons/web_planner/static/src/js/web_planner_backend.js b/addons/web_planner/static/src/js/web_planner_backend.js index 3f4391ae8eb..980cd9cb134 100644 --- a/addons/web_planner/static/src/js/web_planner_backend.js +++ b/addons/web_planner/static/src/js/web_planner_backend.js @@ -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]) { diff --git a/addons/web_planner/static/src/js/web_planner_common.js b/addons/web_planner/static/src/js/web_planner_common.js index 240cb4ee75a..457377ac528 100644 --- a/addons/web_planner/static/src/js/web_planner_common.js +++ b/addons/web_planner/static/src/js/web_planner_common.js @@ -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"), diff --git a/addons/web_settings_dashboard/static/src/js/dashboard.js b/addons/web_settings_dashboard/static/src/js/dashboard.js index 27a552fc0d0..2433a0255bd 100644 --- a/addons/web_settings_dashboard/static/src/js/dashboard.js +++ b/addons/web_settings_dashboard/static/src/js/dashboard.js @@ -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(){ diff --git a/addons/web_tour/static/src/js/debug_manager.js b/addons/web_tour/static/src/js/debug_manager.js index 70f323de3bb..484f21b07e2 100644 --- a/addons/web_tour/static/src/js/debug_manager.js +++ b/addons/web_tour/static/src/js/debug_manager.js @@ -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() { diff --git a/addons/web_tour/static/src/js/tour_manager.js b/addons/web_tour/static/src/js/tour_manager.js index 61c5b11dc7c..33a052b5d33 100644 --- a/addons/web_tour/static/src/js/tour_manager.js +++ b/addons/web_tour/static/src/js/tour_manager.js @@ -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({ }, }, }); + }); diff --git a/addons/web_tour/static/src/js/tour_service.js b/addons/web_tour/static/src/js/tour_service.js index 91ee9f620a1..53f11777669 100644 --- a/addons/web_tour/static/src/js/tour_service.js +++ b/addons/web_tour/static/src/js/tour_service.js @@ -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; }); }); diff --git a/addons/website/static/src/js/web_planner_website.js b/addons/website/static/src/js/web_planner_website.js index b2407837481..7f196a0ce9d 100644 --- a/addons/website/static/src/js/web_planner_website.js +++ b/addons/website/static/src/js/web_planner_website.js @@ -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) || {}; diff --git a/addons/website/static/src/js/website.backendDashboard.js b/addons/website/static/src/js/website.backendDashboard.js index 3b5ad204ad7..67a72a6de9e 100644 --- a/addons/website/static/src/js/website.backendDashboard.js +++ b/addons/website/static/src/js/website.backendDashboard.js @@ -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'); }); }, diff --git a/addons/website/static/src/js/website.model.js b/addons/website/static/src/js/website.model.js new file mode 100644 index 00000000000..66b75e398af --- /dev/null +++ b/addons/website/static/src/js/website.model.js @@ -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()); +}); diff --git a/addons/website/static/src/js/website.seo.js b/addons/website/static/src/js/website.seo.js index 09e6c00a701..3a4d6dc5000 100644 --- a/addons/website/static/src/js/website.seo.js +++ b/addons/website/static/src/js/website.seo.js @@ -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 () { diff --git a/addons/website/static/src/js/website.snippets.editor.js b/addons/website/static/src/js/website.snippets.editor.js index 94bb408b9ac..604c8d589f9 100644 --- a/addons/website/static/src/js/website.snippets.editor.js +++ b/addons/website/static/src/js/website.snippets.editor.js @@ -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) ); diff --git a/addons/website/views/website_templates.xml b/addons/website/views/website_templates.xml index 94f8706c41d..b42180246d2 100644 --- a/addons/website/views/website_templates.xml +++ b/addons/website/views/website_templates.xml @@ -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> diff --git a/addons/website_blog/static/src/js/website_blog.editor.js b/addons/website_blog/static/src/js/website_blog.editor.js index f155f25b71b..51ce734f5b5 100644 --- a/addons/website_blog/static/src/js/website_blog.editor.js +++ b/addons/website_blog/static/src/js/website_blog.editor.js @@ -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) { diff --git a/addons/website_crm_partner_assign/static/src/js/crm_partner_assign.js b/addons/website_crm_partner_assign/static/src/js/crm_partner_assign.js index b5920cb31ee..2dd6b6e4c41 100644 --- a/addons/website_crm_partner_assign/static/src/js/crm_partner_assign.js +++ b/addons/website_crm_partner_assign/static/src/js/crm_partner_assign.js @@ -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()), diff --git a/addons/website_links/static/src/js/website_links.js b/addons/website_links/static/src/js/website_links.js index 95580483a9e..d9a729672eb 100644 --- a/addons/website_links/static/src/js/website_links.js +++ b/addons/website_links/static/src/js/website_links.js @@ -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}); }); diff --git a/addons/website_links/static/src/js/website_links_charts.js b/addons/website_links/static/src/js/website_links_charts.js index bd8d2e89064..892aff45494 100644 --- a/addons/website_links/static/src/js/website_links_charts.js +++ b/addons/website_links/static/src/js/website_links_charts.js @@ -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'}); }; diff --git a/addons/website_mail_channel/static/src/js/website_mail_channel.editor.js b/addons/website_mail_channel/static/src/js/website_mail_channel.editor.js index 9bd280cdde6..369f8787adb 100644 --- a/addons/website_mail_channel/static/src/js/website_mail_channel.editor.js +++ b/addons/website_mail_channel/static/src/js/website_mail_channel.editor.js @@ -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); diff --git a/addons/website_mass_mailing/static/src/js/website_mass_mailing.editor.js b/addons/website_mass_mailing/static/src/js/website_mass_mailing.editor.js index 66ad2879725..1da6cc8886b 100644 --- a/addons/website_mass_mailing/static/src/js/website_mass_mailing.editor.js +++ b/addons/website_mass_mailing/static/src/js/website_mass_mailing.editor.js @@ -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) { diff --git a/addons/website_sale/static/src/js/website_sale.editor.js b/addons/website_sale/static/src/js/website_sale.editor.js index 81953834323..f59de3c3b73 100644 --- a/addons/website_sale/static/src/js/website_sale.editor.js +++ b/addons/website_sale/static/src/js/website_sale.editor.js @@ -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) { |
