diff --git a/addons/account/data/email_template_data_invoice.xml b/addons/account/data/email_template_data_invoice.xml
index 96e55557c1e..41731b7c527 100644
--- a/addons/account/data/email_template_data_invoice.xml
+++ b/addons/account/data/email_template_data_invoice.xml
@@ -16,7 +16,7 @@
Invoice_${(object.number or '').replace('/','_')}_${object.state == 'draft' and 'draft' or ''}${object.partner_id.lang}Dear ${object.partner_id.name}
+
Dear ${object.partner_id.name}
% set access_action = object.get_access_action()
% set access_url = access_action['type'] == 'ir.actions.act_url' and access_action['url'] or '/report/pdf/account.report_invoice/' + str(object.id)
% set is_online = access_action and access_action['type'] == 'ir.actions.act_url'
@@ -69,7 +69,7 @@ from ${object.company_id.name}.
-
+
@@ -100,7 +100,7 @@ from ${object.company_id.name}.
-
+
${user.company_id.name}
diff --git a/addons/account/models/account.py b/addons/account/models/account.py
index 03fc3f6203e..0271cad8aa5 100644
--- a/addons/account/models/account.py
+++ b/addons/account/models/account.py
@@ -136,6 +136,13 @@ class AccountAccount(models.Model):
for account in self:
if (account.company_id.id <> vals['company_id']) and move_lines:
raise UserError(_('You cannot change the owner company of an account that already contains journal items.'))
+ # If user change the reconcile flag, all aml should be recomputed for that account and this is very costly.
+ # So to prevent some bugs we add a constraint saying that you cannot change the reconcile field if there is any aml existing
+ # for that account.
+ if vals.get('reconcile'):
+ move_lines = self.env['account.move.line'].search([('account_id', 'in', self.ids)], limit=1)
+ if len(move_lines):
+ raise UserError(_('You cannot change the value of the reconciliation on this account as it already has some moves'))
return super(AccountAccount, self).write(vals)
@api.multi
diff --git a/addons/account/models/account_invoice.py b/addons/account/models/account_invoice.py
index def1b9484f3..95ae08e8103 100644
--- a/addons/account/models/account_invoice.py
+++ b/addons/account/models/account_invoice.py
@@ -1425,7 +1425,7 @@ class AccountPaymentTerm(models.Model):
class AccountPaymentTermLine(models.Model):
_name = "account.payment.term.line"
_description = "Payment Term Line"
- _order = "sequence"
+ _order = "sequence, id"
value = fields.Selection([
('balance', 'Balance'),
@@ -1433,7 +1433,7 @@ class AccountPaymentTermLine(models.Model):
('fixed', 'Fixed Amount')
], string='Type', required=True, default='balance',
help="Select here the kind of valuation related to this payment term line.")
- value_amount = fields.Float(string='Value', digits=dp.get_precision('Payment Term'), help="For percent enter a ratio between 0-100.")
+ value_amount = fields.Float(string='Value', digits=dp.get_precision('Payment Terms'), help="For percent enter a ratio between 0-100.")
days = fields.Integer(string='Number of Days', required=True, default=0)
option = fields.Selection([
('day_after_invoice_date', 'Day(s) after the invoice date'),
diff --git a/addons/account/models/account_move.py b/addons/account/models/account_move.py
index 3b6ab044353..b9d80ea21cc 100644
--- a/addons/account/models/account_move.py
+++ b/addons/account/models/account_move.py
@@ -885,6 +885,8 @@ class AccountMoveLine(models.Model):
vals['date'] = self._context.get('date_p') or time.strftime('%Y-%m-%d')
if 'name' not in vals:
vals['name'] = self._context.get('comment') or _('Write-Off')
+ if 'analytic_account_id' not in vals:
+ vals['analytic_account_id'] = self.env.context.get('analytic_id', False)
#compute the writeoff amount if not given
if 'credit' not in vals and 'debit' not in vals:
amount = sum([r.amount_residual for r in self])
@@ -901,8 +903,8 @@ class AccountMoveLine(models.Model):
# Writeoff line in the account of self
first_line_dict = vals.copy()
first_line_dict['account_id'] = self[0].account_id.id
- if 'analytic_account_id' in vals:
- del vals['analytic_account_id']
+ if 'analytic_account_id' in first_line_dict:
+ del first_line_dict['analytic_account_id']
# Writeoff line in specified writeoff account
second_line_dict = vals.copy()
diff --git a/addons/account/report/account_aged_partner_balance.py b/addons/account/report/account_aged_partner_balance.py
index fb5f90f96ec..737a07e298a 100644
--- a/addons/account/report/account_aged_partner_balance.py
+++ b/addons/account/report/account_aged_partner_balance.py
@@ -92,11 +92,12 @@ class ReportAgedPartnerBalance(models.AbstractModel):
for partial_line in line.matched_credit_ids:
if partial_line.create_date[:10] <= date_from:
line_amount -= partial_line.amount
- undue_amounts[partner_id] += line_amount
- lines[partner_id].append({
- 'line': line,
- 'amount': line_amount,
- 'period': 6,
+ if not self.env.user.company_id.currency_id.is_zero(line_amount):
+ undue_amounts[partner_id] += line_amount
+ lines[partner_id].append({
+ 'line': line,
+ 'amount': line_amount,
+ 'period': 6,
})
# Use one query per period and store results in history (a list variable)
@@ -144,12 +145,13 @@ class ReportAgedPartnerBalance(models.AbstractModel):
if partial_line.create_date[:10] <= date_from:
line_amount -= partial_line.amount
- partners_amount[partner_id] += line_amount
- lines[partner_id].append({
- 'line': line,
- 'amount': line_amount,
- 'period': i + 1,
- })
+ if not self.env.user.company_id.currency_id.is_zero(line_amount):
+ partners_amount[partner_id] += line_amount
+ lines[partner_id].append({
+ 'line': line,
+ 'amount': line_amount,
+ 'period': i + 1,
+ })
history.append(partners_amount)
for partner in partners:
diff --git a/addons/account/static/description/index.html b/addons/account/static/description/index.html
index fc041102c0b..844515c9b6b 100644
--- a/addons/account/static/description/index.html
+++ b/addons/account/static/description/index.html
@@ -1,6 +1,6 @@
-
Turn Quotes Into Invoices with minimal effort
+
Turn Quotes Into Invoices with minimal effort
Bill automatically based on SO, delivery orders, contracts or time and material
@@ -28,7 +28,7 @@
-
Get paid faster
+
Get paid faster
Online payments and automated follow-ups
Accept online payments via Paypal, Ogone, Buckaroo or Adyen. Eliminate the stress of sending reminders for late or outstanding payments. Simply set up and automate follow-ups to get paid quickly.
@@ -41,7 +41,7 @@
-
Simplify your accounting
+
Simplify your accounting
Keep track of bank account movements and the status of invoices
Use a status overview to help keep track of drafts, paid and unpaid invoices. Automatically record all transactions from your bank accounts by importing and reconciling your bank statements.
@@ -54,7 +54,7 @@
+
diff --git a/addons/account/views/partner_view.xml b/addons/account/views/partner_view.xml
index beda8f4797c..f4bb90a1236 100644
--- a/addons/account/views/partner_view.xml
+++ b/addons/account/views/partner_view.xml
@@ -39,12 +39,12 @@
-
+
diff --git a/addons/account/views/web_planner_data.xml b/addons/account/views/web_planner_data.xml
index c2dc450f6a1..ff796c2859b 100644
--- a/addons/account/views/web_planner_data.xml
+++ b/addons/account/views/web_planner_data.xml
@@ -44,14 +44,24 @@
Your Company
- The first step is to set up your company information. This is mostly used for invoicing.
+ The first step is to set up your company's information. This is mostly used in printed business documents like orders and invoices.
@@ -117,14 +117,14 @@
${object.event_id.user_id.partner_id.name} invited you for the ${object.event_id.name} meeting of ${object.event_id.user_id.company_id.name}.
-
+
${object.event_id.get_interval('dayname', tz=object.partner_id.tz if not object.event_id.allday else None)}
-
+
${object.event_id.get_interval('day', tz=object.partner_id.tz if not object.event_id.allday else None)}
-
${object.event_id.get_interval('month', tz=object.partner_id.tz if not object.event_id.allday else None)}
-
${not object.event_id.allday and object.event_id.get_interval('time', tz=object.partner_id.tz) or ''}
+
${object.event_id.get_interval('month', tz=object.partner_id.tz if not object.event_id.allday else None)}
+
${not object.event_id.allday and object.event_id.get_interval('time', tz=object.partner_id.tz) or ''}
Hi ${object.name}, here is your order confirmation for
% if 'website_url' in object.event_id and object.event_id.website_url:
- ${object.event_id.name}
+ ${object.event_id.name}
% else:
${object.event_id.name}
% endif
@@ -110,7 +110,7 @@
Please keep in mind that the event
% if 'website_url' in object.event_id and object.event_id.website_url:
- ${object.event_id.name}
+ ${object.event_id.name}
% else:
${object.event_id.name}
% endif
@@ -243,7 +243,7 @@
diff --git a/addons/event_sale/wizard/event_edit_registration.py b/addons/event_sale/wizard/event_edit_registration.py
index 5cf4a17969c..a82d45b00ef 100644
--- a/addons/event_sale/wizard/event_edit_registration.py
+++ b/addons/event_sale/wizard/event_edit_registration.py
@@ -53,6 +53,9 @@ class RegistrationEditor(models.TransientModel):
registration_line.registration_id.write(values)
else:
self.env['event.registration'].create(values)
+ if self.env.context.get('active_model') == 'sale.order':
+ for order in self.env['sale.order'].browse(self.env.context.get('active_ids', [])):
+ order.order_line._update_registrations(confirm=True)
return {'type': 'ir.actions.act_window_close'}
diff --git a/addons/fleet/static/description/index.html b/addons/fleet/static/description/index.html
index 14cf7fbe59d..0d43777aeca 100644
--- a/addons/fleet/static/description/index.html
+++ b/addons/fleet/static/description/index.html
@@ -1,6 +1,6 @@
-
Odoo Fleet
+
Odoo Fleet
Manage your vehicles, contracts, costs, insurances and assignments
@@ -12,7 +12,7 @@
-
Fleet management made easy
+
Fleet management made easy
@@ -26,7 +26,7 @@
-
Manage leasing and all other contracts
+
Manage leasing and all other contracts
Supervise all contracts for your vehicles and receive a warning email when contracts reach their expiration date. Several visual tools are put in place to ensure that you'll remember to renew (or end) your contract. Organize the services around the vehicles and communicate with the qualified service providers; manage invoices and notes. Set up a vehicle policy within your company, as well as an insurance policy in order to manage your fleet in the most efficient way.
@@ -40,7 +40,7 @@
-
Monitor all costs at once
+
Monitor all costs at once
@@ -54,7 +54,7 @@
-
Analysis and reporting
+
Analysis and reporting
Show all costs associated with a given vehicle or with a type of service. Compare different types of costs (which vehicles cost the most; which services have been performed on which vehicles etc.) by using the reporting tool. Get really helpful insights about the effective return of each vehicle in order to improve your fleet investments.
diff --git a/addons/hr/static/description/index.html b/addons/hr/static/description/index.html
index ed11a0bf109..7ab62ba0a56 100644
--- a/addons/hr/static/description/index.html
+++ b/addons/hr/static/description/index.html
@@ -1,6 +1,6 @@
-
Modern open source HR solution
+
Modern open source HR solution
Manage the most important asset in your company: People
@@ -12,7 +12,7 @@
-
Successfully manage your employees
+
Successfully manage your employees
Centralize all your HR information
@@ -27,7 +27,7 @@
-
Boost Engagement With Social Tools
+
Boost Engagement With Social Tools
Improve communication between employees and motivate them through rewards
diff --git a/addons/hr_attendance/__manifest__.py b/addons/hr_attendance/__manifest__.py
index 6a8024282b8..c3228573d55 100644
--- a/addons/hr_attendance/__manifest__.py
+++ b/addons/hr_attendance/__manifest__.py
@@ -35,4 +35,5 @@ actions(Check in/Check out) performed by them.
'qweb': [
"static/src/xml/attendance.xml",
],
+ 'application': True,
}
diff --git a/addons/hr_attendance/models/hr_employee.py b/addons/hr_attendance/models/hr_employee.py
index 386daa9907b..7fcd8ee8ff4 100644
--- a/addons/hr_attendance/models/hr_employee.py
+++ b/addons/hr_attendance/models/hr_employee.py
@@ -21,13 +21,13 @@ class HrEmployee(models.Model):
return barcode
barcode = fields.Char(string="Badge ID", help="ID used for employee identification.", default=_default_random_barcode, copy=False)
- pin = fields.Char(string="PIN", default=_default_random_pin, help="PIN used for Check In/Out in Attendance.", copy=False)
+ pin = fields.Char(string="PIN", default=_default_random_pin, help="PIN used to Check In/Out in Kiosk Mode (if enabled in Configuration).", copy=False)
attendance_ids = fields.One2many('hr.attendance', 'employee_id', help='list of attendances for the employee')
last_attendance_id = fields.Many2one('hr.attendance', compute='_compute_last_attendance_id')
attendance_state = fields.Selection(string="Attendance", compute='_compute_attendance_state', selection=[('checked_out', "Checked out"), ('checked_in', "Checked in")])
manual_attendance = fields.Boolean(string='Manual Attendance', compute='_compute_manual_attendance', inverse='_inverse_manual_attendance',
- help='The employee will have access to the "My Attendances" menu to perform his check in and out from his session')
+ help='The employee will have access to the "My Attendances" menu to check in and out from his session')
_sql_constraints = [('barcode_uniq', 'unique (barcode)', "The Badge ID must be unique, this one is already assigned to another employee.")]
@@ -38,7 +38,7 @@ class HrEmployee(models.Model):
@api.multi
def _inverse_manual_attendance(self):
- manual_attendance_group = self.env['res.groups'].search([('name', '=', 'Manual Attendances')])
+ manual_attendance_group = self.env.ref('hr.group_hr_attendance')
for employee in self:
if employee.user_id:
if employee.manual_attendance:
@@ -53,8 +53,6 @@ class HrEmployee(models.Model):
@api.depends('last_attendance_id.check_in', 'last_attendance_id.check_out', 'last_attendance_id')
def _compute_attendance_state(self):
- """compute employee state, last check in and last check out
- """
for employee in self:
employee.attendance_state = employee.last_attendance_id and not employee.last_attendance_id.check_out and 'checked_in' or 'checked_out'
@@ -66,11 +64,11 @@ class HrEmployee(models.Model):
@api.model
def attendance_scan(self, barcode):
- """ Receive a barcode scanned from the main menu and change the attendances of corresponding employee.
+ """ Receive a barcode scanned from the Kiosk Mode and change the attendances of corresponding employee.
Returns either an action or a warning.
"""
employee = self.search([('barcode', '=', barcode)], limit=1)
- return employee and employee.attendance_action('hr_attendance.hr_attendance_action_main_menu') or \
+ return employee and employee.attendance_action('hr_attendance.hr_attendance_action_kiosk_mode') or \
{'warning': _('No employee corresponding to barcode %(barcode)s') % {'barcode': barcode}}
@api.multi
@@ -85,10 +83,10 @@ class HrEmployee(models.Model):
def attendance_action(self, next_action):
""" Changes the attendance of the employee.
Returns an action to the check in/out message,
- next_action defines which menu the check in/out message should return to.
+ next_action defines which menu the check in/out message should return to. ("My Attendances" or "Kiosk Mode")
"""
self.ensure_one()
- action_message = self.env.ref('hr_attendance.hr_attendance_action_message').read()[0]
+ action_message = self.env.ref('hr_attendance.hr_attendance_action_greeting_message').read()[0]
action_message['previous_attendance_change_date'] = self.last_attendance_id and (self.last_attendance_id.check_out or self.last_attendance_id.check_in) or False
if action_message['previous_attendance_change_date']:
action_message['previous_attendance_change_date'] = \
@@ -113,11 +111,7 @@ class HrEmployee(models.Model):
raise exceptions.UserError(_('Cannot perform check in or check out on multiple employees.'))
action_date = fields.Datetime.now()
- action = 'check_in'
- if self.attendance_state == 'checked_in':
- action = 'check_out'
-
- if action == 'check_in':
+ if self.attendance_state != 'checked_in':
vals = {
'employee_id': self.id,
'check_in': action_date,
diff --git a/addons/hr_attendance/models/res_config.py b/addons/hr_attendance/models/res_config.py
index 464b643ca02..d2f06ce6cb5 100644
--- a/addons/hr_attendance/models/res_config.py
+++ b/addons/hr_attendance/models/res_config.py
@@ -7,6 +7,6 @@ from odoo import fields, models
class BaseConfigSettings(models.TransientModel):
_inherit = 'base.config.settings'
- group_attendance_use_pin = fields.Selection([(0, 'Employees do not need to enter their PIN to check in manually in the "Company Screen".'),
- (1, 'Employees must enter their PIN to check in manually in the "Company Screen".')],
+ group_attendance_use_pin = fields.Selection([(0, 'Employees do not need to enter their PIN to check in manually in the "Kiosk Mode".'),
+ (1, 'Employees must enter their PIN to check in manually in the "Kiosk Mode".')],
string='Employee PIN', help='Enable or disable employee PIN identification at check in', implied_group="hr_attendance.group_hr_attendance_use_pin")
diff --git a/addons/hr_attendance/security/hr_attendance_security.xml b/addons/hr_attendance/security/hr_attendance_security.xml
index 559df28e799..76a67019658 100644
--- a/addons/hr_attendance/security/hr_attendance_security.xml
+++ b/addons/hr_attendance/security/hr_attendance_security.xml
@@ -27,7 +27,8 @@
- Manual Attendances
+ Manual Attendance
+ The user will gain access to the human resources attendance menu, enabling him to manage his own attendance.
diff --git a/addons/hr_attendance/static/src/js/employee_kanban_view_handler.js b/addons/hr_attendance/static/src/js/employee_kanban_view_handler.js
index b3810f05a2d..225077b0794 100644
--- a/addons/hr_attendance/static/src/js/employee_kanban_view_handler.js
+++ b/addons/hr_attendance/static/src/js/employee_kanban_view_handler.js
@@ -11,7 +11,7 @@ KanbanRecord.include({
var action = {
type: 'ir.actions.client',
name: 'Confirm',
- tag: 'hr_attendance_main_menu_confirm',
+ tag: 'hr_attendance_kiosk_confirm',
employee_id: this.record.id.raw_value,
employee_name: this.record.name.raw_value,
employee_state: this.record.attendance_state.raw_value,
diff --git a/addons/hr_attendance/static/src/js/message.js b/addons/hr_attendance/static/src/js/greeting_message.js
similarity index 93%
rename from addons/hr_attendance/static/src/js/message.js
rename to addons/hr_attendance/static/src/js/greeting_message.js
index 20cb767692f..113012dbb18 100644
--- a/addons/hr_attendance/static/src/js/message.js
+++ b/addons/hr_attendance/static/src/js/greeting_message.js
@@ -1,4 +1,4 @@
-odoo.define('hr_attendance.Message', function (require) {
+odoo.define('hr_attendance.greeting_message', function (require) {
"use strict";
var core = require('web.core');
@@ -8,8 +8,8 @@ var Widget = require('web.Widget');
var _t = core._t;
-var Message = Widget.extend({
- template: 'HrAttendanceMessage',
+var GreetingMessage = Widget.extend({
+ template: 'HrAttendanceGreetingMessage',
events: {
"click .o_hr_attendance_button_dismiss": function () { this.do_action(this.next_action, {clear_breadcrumbs: true}); },
@@ -18,11 +18,11 @@ var Message = Widget.extend({
init: function(parent, action) {
this._super.apply(this, arguments);
var self = this;
- var default_action = { type: "ir.actions.client", name: 'Attendances', tag: 'hr_attendance_my_main_menu', params: {} };
+ var default_action = { type: "ir.actions.client", name: 'Attendances', tag: 'hr_attendance_my_attendances', params: {} };
if(!action.attendance){
self.session.user_has_group('hr_attendance.group_hr_attendance_user').then(function(has_group){
if(has_group){
- self.next_action = { type: "ir.actions.client", name: 'Attendances', tag: 'hr_attendance_main_menu', target: 'fullscreen', params: {} };
+ self.next_action = { type: "ir.actions.client", name: 'Attendances', tag: 'hr_attendance_kiosk_mode', target: 'fullscreen', params: {} };
}
});
return;
@@ -124,8 +124,8 @@ var Message = Widget.extend({
},
});
-core.action_registry.add('hr_attendance_message', Message);
+core.action_registry.add('hr_attendance_greeting_message', GreetingMessage);
-return Message;
+return GreetingMessage;
});
diff --git a/addons/hr_attendance/static/src/js/main_menu_confirm.js b/addons/hr_attendance/static/src/js/kiosk_confirm.js
similarity index 92%
rename from addons/hr_attendance/static/src/js/main_menu_confirm.js
rename to addons/hr_attendance/static/src/js/kiosk_confirm.js
index 0f54d607732..60e75b73328 100644
--- a/addons/hr_attendance/static/src/js/main_menu_confirm.js
+++ b/addons/hr_attendance/static/src/js/kiosk_confirm.js
@@ -1,4 +1,4 @@
-odoo.define('hr_attendance.MainMenuConfirm', function (require) {
+odoo.define('hr_attendance.kiosk_confirm', function (require) {
"use strict";
var core = require('web.core');
@@ -9,7 +9,7 @@ var QWeb = core.qweb;
var _t = core._t;
-var MainMenuConfirm = Widget.extend({
+var KioskConfirm = Widget.extend({
events: {
"click .o_hr_attendance_back_button": function () { this.do_action(this.next_action, {clear_breadcrumbs: true}); },
"click .o_hr_attendance_sign_in_out_icon": function () {
@@ -55,7 +55,7 @@ var MainMenuConfirm = Widget.extend({
init: function (parent, action) {
this._super.apply(this, arguments);
- this.next_action = { type: "ir.actions.client", name: "Attendances", tag: 'hr_attendance_main_menu', target: "fullscreen", params: {} };
+ this.next_action = { type: "ir.actions.client", name: "Attendances", tag: 'hr_attendance_kiosk_mode', target: "fullscreen", params: {} };
this.employee_id = action.employee_id;
this.employee_name = action.employee_name;
this.employee_state = action.employee_state;
@@ -66,7 +66,7 @@ var MainMenuConfirm = Widget.extend({
var self = this;
self.session.user_has_group('hr_attendance.group_hr_attendance_use_pin').then(function(has_group){
self.use_pin = has_group;
- self.$el.html(QWeb.render("HrAttendanceMainMenuConfirm", {widget: self}));
+ self.$el.html(QWeb.render("HrAttendanceKioskConfirm", {widget: self}));
self.start_clock();
});
return self._super.apply(this, arguments);
@@ -84,8 +84,8 @@ var MainMenuConfirm = Widget.extend({
},
});
-core.action_registry.add('hr_attendance_main_menu_confirm', MainMenuConfirm);
+core.action_registry.add('hr_attendance_kiosk_confirm', KioskConfirm);
-return MainMenuConfirm;
+return KioskConfirm;
});
diff --git a/addons/hr_attendance/static/src/js/main_menu.js b/addons/hr_attendance/static/src/js/kiosk_mode.js
similarity index 89%
rename from addons/hr_attendance/static/src/js/main_menu.js
rename to addons/hr_attendance/static/src/js/kiosk_mode.js
index aa6d6682381..51c78bd34b4 100644
--- a/addons/hr_attendance/static/src/js/main_menu.js
+++ b/addons/hr_attendance/static/src/js/kiosk_mode.js
@@ -1,4 +1,4 @@
-odoo.define('hr_attendance.MainMenu', function (require) {
+odoo.define('hr_attendance.kiosk_mode', function (require) {
"use strict";
var core = require('web.core');
@@ -11,7 +11,7 @@ var QWeb = core.qweb;
var _t = core._t;
-var MainMenu = Widget.extend(BarcodeHandlerMixin, {
+var KioskMode = Widget.extend(BarcodeHandlerMixin, {
events: {
"click .o_hr_attendance_button_employees": function(){ this.do_action('hr_attendance.hr_employee_attendance_action_kanban'); },
},
@@ -33,7 +33,7 @@ var MainMenu = Widget.extend(BarcodeHandlerMixin, {
.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.$el.html(QWeb.render("HrAttendanceMainMenu", {widget: self}));
+ self.$el.html(QWeb.render("HrAttendanceKioskMode", {widget: self}));
self.start_clock();
});
return self._super.apply(this, arguments);
@@ -64,8 +64,8 @@ var MainMenu = Widget.extend(BarcodeHandlerMixin, {
},
});
-core.action_registry.add('hr_attendance_main_menu', MainMenu);
+core.action_registry.add('hr_attendance_kiosk_mode', KioskMode);
-return MainMenu;
+return KioskMode;
});
diff --git a/addons/hr_attendance/static/src/js/my_main_menu.js b/addons/hr_attendance/static/src/js/my_attendances.js
similarity index 85%
rename from addons/hr_attendance/static/src/js/my_main_menu.js
rename to addons/hr_attendance/static/src/js/my_attendances.js
index 3d7d4fb9ed2..beed3c441e6 100644
--- a/addons/hr_attendance/static/src/js/my_main_menu.js
+++ b/addons/hr_attendance/static/src/js/my_attendances.js
@@ -1,4 +1,4 @@
-odoo.define('hr_attendance.MyMainMenu', function (require) {
+odoo.define('hr_attendance.my_attendances', function (require) {
"use strict";
var core = require('web.core');
@@ -9,7 +9,7 @@ var QWeb = core.qweb;
var _t = core._t;
-var MyMainMenu = Widget.extend({
+var MyAttendances = Widget.extend({
events: {
"click .o_hr_attendance_sign_in_out_icon": function() {
this.$('.o_hr_attendance_sign_in_out_icon').attr("disabled", "disabled");
@@ -39,7 +39,7 @@ var MyMainMenu = 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_main_menu'])
+ hr_employee.call('attendance_manual', [[self.employee.id], 'hr_attendance.hr_attendance_action_my_attendances'])
.then(function(result) {
if (result.action) {
self.do_action(result.action);
@@ -50,8 +50,8 @@ var MyMainMenu = Widget.extend({
},
});
-core.action_registry.add('hr_attendance_my_main_menu', MyMainMenu);
+core.action_registry.add('hr_attendance_my_attendances', MyAttendances);
-return MyMainMenu;
+return MyAttendances;
});
diff --git a/addons/hr_attendance/static/src/less/hr_attendance.less b/addons/hr_attendance/static/src/less/hr_attendance.less
index b2b56bbaa0b..12a356159d4 100644
--- a/addons/hr_attendance/static/src/less/hr_attendance.less
+++ b/addons/hr_attendance/static/src/less/hr_attendance.less
@@ -57,7 +57,7 @@
margin: 5px 0px 5px 0px;
}
-.o_hr_attendance_main_menu_container {
+.o_hr_attendance_kiosk_mode_container {
.o-flex-display();
.o-flex-flow(column, nowrap);
.o-justify-content(center);
@@ -80,7 +80,7 @@
.o_hr_attendance_random_message {
font-style: italic;
}
-.o_hr_attendance_main_menu {
+.o_hr_attendance_kiosk_mode {
width: 100%;
text-align: center;
position: relative;
diff --git a/addons/hr_attendance/static/src/xml/attendance.xml b/addons/hr_attendance/static/src/xml/attendance.xml
index 420dc1b4988..8f864341a1f 100644
--- a/addons/hr_attendance/static/src/xml/attendance.xml
+++ b/addons/hr_attendance/static/src/xml/attendance.xml
@@ -5,9 +5,9 @@
-
-
-
+
+
+
Welcome to
Scan your badge
@@ -19,8 +19,8 @@
-
-
+
+
Welcome
@@ -39,9 +39,9 @@
-
-
-
+
+
+
Welcome
@@ -89,7 +89,7 @@
-
+
diff --git a/addons/hr_attendance/views/hr_attendance_view.xml b/addons/hr_attendance/views/hr_attendance_view.xml
index 3555b415080..dae22297373 100644
--- a/addons/hr_attendance/views/hr_attendance_view.xml
+++ b/addons/hr_attendance/views/hr_attendance_view.xml
@@ -86,7 +86,10 @@
tree,form{"search_default_today":1}
- The Time Tracking functionality aims to manage employee attendances from Check in/Check out actions. You can also link this feature to an attendance device using Odoo's web service features.
+
+
The attendance records of your employees will be displayed here.
+
Please make sure you're using the correct filter if you expected to see any.
Manage your employees' daily expenses. Whether it's travel expenses or any other costs, access all your employees' fee notes and complete, validate or refuse them. No need to download any specialized software or program to manage expenses - everything can be done directly in the app!
@@ -25,7 +25,7 @@
-
Stop losing receipts
+
Stop losing receipts
Upload all receipts within expense records
@@ -40,7 +40,7 @@
-
Manage expenses per team
+
Manage expenses per team
Have a clear overview of a team's spendings
As a manager, follow expenses recorded by a full team to keep an eye on the costs and make sure to keep to the target and budget.
@@ -53,7 +53,7 @@
-
Share the workload between departments
+
Share the workload between departments
Get everyone involved to save time
diff --git a/addons/hr_holidays/__init__.py b/addons/hr_holidays/__init__.py
index d84fb182e8f..859f7ca8e08 100644
--- a/addons/hr_holidays/__init__.py
+++ b/addons/hr_holidays/__init__.py
@@ -1,6 +1,7 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
+import controllers
import models
import report
import wizard
diff --git a/addons/hr_holidays/controllers/__init__.py b/addons/hr_holidays/controllers/__init__.py
new file mode 100644
index 00000000000..12d2d759f34
--- /dev/null
+++ b/addons/hr_holidays/controllers/__init__.py
@@ -0,0 +1,2 @@
+# -*- coding: utf-8 -*
+import main
diff --git a/addons/hr_holidays/controllers/main.py b/addons/hr_holidays/controllers/main.py
new file mode 100644
index 00000000000..cac9dbc1f52
--- /dev/null
+++ b/addons/hr_holidays/controllers/main.py
@@ -0,0 +1,28 @@
+# -*- coding: utf-8 -*-
+# Part of Odoo. See LICENSE file for full copyright and licensing details.
+
+from odoo.addons.mail.controllers.main import MailController
+from odoo import http
+
+
+class HrHolidaysController(http.Controller):
+
+ @http.route('/hr_holidays/validate', type='http', auth='user', methods=['GET'])
+ def hr_holidays_validate(self, res_id, token):
+ comparison, record, redirect = MailController._check_token_and_record_or_redirect('hr.holidays', int(res_id), token)
+ if comparison and record:
+ try:
+ record.signal_workflow('validate')
+ except Exception:
+ return MailController._redirect_to_messaging()
+ return redirect
+
+ @http.route('/hr_holidays/refuse', type='http', auth='user', methods=['GET'])
+ def hr_holidays_refuse(self, res_id, token):
+ comparison, record, redirect = MailController._check_token_and_record_or_redirect('hr.holidays', int(res_id), token)
+ if comparison and record:
+ try:
+ record.signal_workflow('refuse')
+ except Exception:
+ return MailController._redirect_to_messaging()
+ return redirect
diff --git a/addons/hr_holidays/models/hr_holidays.py b/addons/hr_holidays/models/hr_holidays.py
index dee086da682..dc515716ca8 100644
--- a/addons/hr_holidays/models/hr_holidays.py
+++ b/addons/hr_holidays/models/hr_holidays.py
@@ -560,10 +560,10 @@ class Holidays(models.Model):
self.ensure_one()
if self.state == 'confirm':
- app_action = self._notification_link_helper('method', method='action_validate')
+ app_action = self._notification_link_helper('controller', controller='/hr_holidays/validate')
hr_actions = [{'url': app_action, 'title': _('Approve')}]
if self.state in ['confirm', 'validate', 'validate1']:
- ref_action = self._notification_link_helper('method', method='action_refuse')
+ ref_action = self._notification_link_helper('controller', controller='/hr_holidays/refuse')
hr_actions = [{'url': ref_action, 'title': _('Refuse')}]
new_group = (
diff --git a/addons/hr_holidays/static/description/index.html b/addons/hr_holidays/static/description/index.html
index 25ca1dc4a95..88d8279db25 100644
--- a/addons/hr_holidays/static/description/index.html
+++ b/addons/hr_holidays/static/description/index.html
@@ -1,6 +1,6 @@
Whether you 're a small business, a freelance or a professional managing employees from different locations, you need your apps to be as mobile as you are. Log in and track your time through any device.
diff --git a/addons/im_livechat/static/description/index.html b/addons/im_livechat/static/description/index.html
index 9743881bd77..75b50edc054 100644
--- a/addons/im_livechat/static/description/index.html
+++ b/addons/im_livechat/static/description/index.html
@@ -1,6 +1,6 @@
-
Answer your customers questions live
+
Answer your customers questions live
Engage with visitors, deliver real time support to customers
@@ -12,7 +12,7 @@
-
Do it live!
+
Do it live!
Convert more visitors into leads and customers
@@ -39,7 +39,7 @@
-
Select your audience
+
Select your audience
Provide direct chat to a specified target
@@ -53,7 +53,7 @@
-
Accessible from anywhere
+
Accessible from anywhere
Chat from within any module
@@ -68,7 +68,7 @@
-
Improve your level of service
+
Improve your level of service
Make sure to keep customers satisfied
@@ -86,7 +86,7 @@
-
Answer more quickly with templates
+
Answer more quickly with templates
Use pre-written answers to be faster
diff --git a/addons/l10n_ar/migrations/2.0/post-migrate_tags_on_taxes.py b/addons/l10n_ar/migrations/9.0.2.0/post-migrate_tags_on_taxes.py
similarity index 100%
rename from addons/l10n_ar/migrations/2.0/post-migrate_tags_on_taxes.py
rename to addons/l10n_ar/migrations/9.0.2.0/post-migrate_tags_on_taxes.py
diff --git a/addons/l10n_at/migrations/2.0/post-migrate_tags_on_taxes.py b/addons/l10n_at/migrations/9.0.2.0/post-migrate_tags_on_taxes.py
similarity index 100%
rename from addons/l10n_at/migrations/2.0/post-migrate_tags_on_taxes.py
rename to addons/l10n_at/migrations/9.0.2.0/post-migrate_tags_on_taxes.py
diff --git a/addons/l10n_at/migrations/2.0/pre-set_tags_and_taxes_updatable.py b/addons/l10n_at/migrations/9.0.2.0/pre-set_tags_and_taxes_updatable.py
similarity index 100%
rename from addons/l10n_at/migrations/2.0/pre-set_tags_and_taxes_updatable.py
rename to addons/l10n_at/migrations/9.0.2.0/pre-set_tags_and_taxes_updatable.py
diff --git a/addons/l10n_bo/migrations/2.0/post-migrate_tags_on_taxes.py b/addons/l10n_bo/migrations/9.0.2.0/post-migrate_tags_on_taxes.py
similarity index 100%
rename from addons/l10n_bo/migrations/2.0/post-migrate_tags_on_taxes.py
rename to addons/l10n_bo/migrations/9.0.2.0/post-migrate_tags_on_taxes.py
diff --git a/addons/l10n_br/migrations/1.0/post-migrate_tags_on_taxes.py b/addons/l10n_br/migrations/9.0.1.0/post-migrate_tags_on_taxes.py
similarity index 100%
rename from addons/l10n_br/migrations/1.0/post-migrate_tags_on_taxes.py
rename to addons/l10n_br/migrations/9.0.1.0/post-migrate_tags_on_taxes.py
diff --git a/addons/l10n_ch/migrations/9.0/post-migrate_tags_on_taxes.py b/addons/l10n_ch/migrations/9.0.9.0/post-migrate_tags_on_taxes.py
similarity index 100%
rename from addons/l10n_ch/migrations/9.0/post-migrate_tags_on_taxes.py
rename to addons/l10n_ch/migrations/9.0.9.0/post-migrate_tags_on_taxes.py
diff --git a/addons/l10n_ch/migrations/9.0/pre-set_tags_and_taxes_updatable.py b/addons/l10n_ch/migrations/9.0.9.0/pre-set_tags_and_taxes_updatable.py
similarity index 100%
rename from addons/l10n_ch/migrations/9.0/pre-set_tags_and_taxes_updatable.py
rename to addons/l10n_ch/migrations/9.0.9.0/pre-set_tags_and_taxes_updatable.py
diff --git a/addons/l10n_cl/migrations/2.0/post-migrate_tags_on_taxes.py b/addons/l10n_cl/migrations/9.0.2.0/post-migrate_tags_on_taxes.py
similarity index 100%
rename from addons/l10n_cl/migrations/2.0/post-migrate_tags_on_taxes.py
rename to addons/l10n_cl/migrations/9.0.2.0/post-migrate_tags_on_taxes.py
diff --git a/addons/l10n_cl/migrations/2.0/pre-set_tags_and_taxes_updatable.py b/addons/l10n_cl/migrations/9.0.2.0/pre-set_tags_and_taxes_updatable.py
similarity index 100%
rename from addons/l10n_cl/migrations/2.0/pre-set_tags_and_taxes_updatable.py
rename to addons/l10n_cl/migrations/9.0.2.0/pre-set_tags_and_taxes_updatable.py
diff --git a/addons/l10n_de_skr03/migrations/2.0/post-migrate_tags_on_taxes.py b/addons/l10n_de_skr03/migrations/9.0.2.0/post-migrate_tags_on_taxes.py
similarity index 100%
rename from addons/l10n_de_skr03/migrations/2.0/post-migrate_tags_on_taxes.py
rename to addons/l10n_de_skr03/migrations/9.0.2.0/post-migrate_tags_on_taxes.py
diff --git a/addons/l10n_de_skr03/migrations/2.0/pre-set_tags_and_taxes_updatable.py b/addons/l10n_de_skr03/migrations/9.0.2.0/pre-set_tags_and_taxes_updatable.py
similarity index 100%
rename from addons/l10n_de_skr03/migrations/2.0/pre-set_tags_and_taxes_updatable.py
rename to addons/l10n_de_skr03/migrations/9.0.2.0/pre-set_tags_and_taxes_updatable.py
diff --git a/addons/l10n_de_skr04/migrations/2.0/post-migrate_tags_on_taxes.py b/addons/l10n_de_skr04/migrations/9.0.2.0/post-migrate_tags_on_taxes.py
similarity index 100%
rename from addons/l10n_de_skr04/migrations/2.0/post-migrate_tags_on_taxes.py
rename to addons/l10n_de_skr04/migrations/9.0.2.0/post-migrate_tags_on_taxes.py
diff --git a/addons/l10n_de_skr04/migrations/2.0/pre-set_tags_and_taxes_updatable.py b/addons/l10n_de_skr04/migrations/9.0.2.0/pre-set_tags_and_taxes_updatable.py
similarity index 100%
rename from addons/l10n_de_skr04/migrations/2.0/pre-set_tags_and_taxes_updatable.py
rename to addons/l10n_de_skr04/migrations/9.0.2.0/pre-set_tags_and_taxes_updatable.py
diff --git a/addons/l10n_et/migrations/2.0/post-migrate_tags_on_taxes.py b/addons/l10n_et/migrations/9.0.2.0/post-migrate_tags_on_taxes.py
similarity index 100%
rename from addons/l10n_et/migrations/2.0/post-migrate_tags_on_taxes.py
rename to addons/l10n_et/migrations/9.0.2.0/post-migrate_tags_on_taxes.py
diff --git a/addons/l10n_gr/migrations/1.0/post-migrate_tags_on_taxes.py b/addons/l10n_gr/migrations/9.0.1.0/post-migrate_tags_on_taxes.py
similarity index 100%
rename from addons/l10n_gr/migrations/1.0/post-migrate_tags_on_taxes.py
rename to addons/l10n_gr/migrations/9.0.1.0/post-migrate_tags_on_taxes.py
diff --git a/addons/l10n_hr/migrations/13.0/post-migrate_tags_on_taxes.py b/addons/l10n_hr/migrations/9.0.13.0/post-migrate_tags_on_taxes.py
similarity index 100%
rename from addons/l10n_hr/migrations/13.0/post-migrate_tags_on_taxes.py
rename to addons/l10n_hr/migrations/9.0.13.0/post-migrate_tags_on_taxes.py
diff --git a/addons/l10n_hr/migrations/13.0/pre-set_tags_and_taxes_updatable.py b/addons/l10n_hr/migrations/9.0.13.0/pre-set_tags_and_taxes_updatable.py
similarity index 100%
rename from addons/l10n_hr/migrations/13.0/pre-set_tags_and_taxes_updatable.py
rename to addons/l10n_hr/migrations/9.0.13.0/pre-set_tags_and_taxes_updatable.py
diff --git a/addons/l10n_hu/migrations/2.0/post-migrate_tags_on_taxes.py b/addons/l10n_hu/migrations/9.0.2.0/post-migrate_tags_on_taxes.py
similarity index 100%
rename from addons/l10n_hu/migrations/2.0/post-migrate_tags_on_taxes.py
rename to addons/l10n_hu/migrations/9.0.2.0/post-migrate_tags_on_taxes.py
diff --git a/addons/l10n_in/migrations/2.0/post-migrate_tags_on_taxes.py b/addons/l10n_in/migrations/9.0.2.0/post-migrate_tags_on_taxes.py
similarity index 100%
rename from addons/l10n_in/migrations/2.0/post-migrate_tags_on_taxes.py
rename to addons/l10n_in/migrations/9.0.2.0/post-migrate_tags_on_taxes.py
diff --git a/addons/l10n_in/migrations/2.0/pre-set_tags_and_taxes_updatable.py b/addons/l10n_in/migrations/9.0.2.0/pre-set_tags_and_taxes_updatable.py
similarity index 100%
rename from addons/l10n_in/migrations/2.0/pre-set_tags_and_taxes_updatable.py
rename to addons/l10n_in/migrations/9.0.2.0/pre-set_tags_and_taxes_updatable.py
diff --git a/addons/l10n_jp/migrations/2.0/post-migrate_tags_on_taxes.py b/addons/l10n_jp/migrations/9.0.2.0/post-migrate_tags_on_taxes.py
similarity index 100%
rename from addons/l10n_jp/migrations/2.0/post-migrate_tags_on_taxes.py
rename to addons/l10n_jp/migrations/9.0.2.0/post-migrate_tags_on_taxes.py
diff --git a/addons/l10n_nl/migrations/2.0/post-migrate_tags_on_taxes.py b/addons/l10n_nl/migrations/9.0.2.0/post-migrate_tags_on_taxes.py
similarity index 100%
rename from addons/l10n_nl/migrations/2.0/post-migrate_tags_on_taxes.py
rename to addons/l10n_nl/migrations/9.0.2.0/post-migrate_tags_on_taxes.py
diff --git a/addons/l10n_nl/migrations/2.0/pre-set_tags_and_taxes_updatable.py b/addons/l10n_nl/migrations/9.0.2.0/pre-set_tags_and_taxes_updatable.py
similarity index 100%
rename from addons/l10n_nl/migrations/2.0/pre-set_tags_and_taxes_updatable.py
rename to addons/l10n_nl/migrations/9.0.2.0/pre-set_tags_and_taxes_updatable.py
diff --git a/addons/mail/controllers/main.py b/addons/mail/controllers/main.py
index e9afcb8fab3..068bd2eeadd 100644
--- a/addons/mail/controllers/main.py
+++ b/addons/mail/controllers/main.py
@@ -3,26 +3,96 @@
import base64
import json
+import logging
import psycopg2
import werkzeug
from operator import itemgetter
from werkzeug import url_encode
-from odoo import api, http, registry, SUPERUSER_ID
+from odoo import api, http, registry, SUPERUSER_ID, _
from odoo.addons.web.controllers.main import binary_content
from odoo.exceptions import AccessError
from odoo.http import request
+from odoo.tools import consteq
+
+_logger = logging.getLogger(__name__)
class MailController(http.Controller):
_cp_path = '/mail'
- def _redirect_to_messaging(self):
+ @classmethod
+ def _redirect_to_messaging(cls):
messaging_action = request.env['mail.thread']._get_inbox_action_xml_id()
url = '/web#%s' % url_encode({'action': messaging_action})
return werkzeug.utils.redirect(url)
+ @classmethod
+ def _check_token(cls, token):
+ base_link = request.httprequest.path
+ params = dict(request.params)
+ params.pop('token', '')
+ valid_token = request.env['mail.thread']._generate_notification_token(base_link, params)
+ return consteq(valid_token, str(token))
+
+ @classmethod
+ def _check_token_and_record_or_redirect(cls, model, res_id, token):
+ comparison = cls._check_token(token)
+ if not comparison:
+ _logger.warning(_('Invalid token in route %s') % request.httprequest.url)
+ return comparison, None, cls._redirect_to_messaging()
+ try:
+ record = request.env[model].browse(res_id).exists()
+ except Exception:
+ record = None
+ redirect = cls._redirect_to_messaging()
+ else:
+ redirect = cls._redirect_to_record(model, res_id)
+ return comparison, record, redirect
+
+ @classmethod
+ def _redirect_to_record(cls, model, res_id):
+ uid = request.session.uid
+
+ # no model / res_id, meaning no possible record -> redirect to login
+ if not model or not res_id or model not in request.env:
+ return cls._redirect_to_messaging()
+
+ # find the access action using sudo to have the details about the access link
+ RecordModel = request.env[model]
+ record_sudo = RecordModel.sudo().browse(res_id).exists()
+ if not record_sudo:
+ # record does not seem to exist -> redirect to login
+ return cls._redirect_to_messaging()
+ record_action = record_sudo.get_access_action()
+
+ # the record has an URL redirection: use it directly
+ if record_action['type'] == 'ir.actions.act_url':
+ return werkzeug.utils.redirect(record_action['url'])
+ # other choice: act_window (no support of anything else currently)
+ elif not record_action['type'] == 'ir.actions.act_window':
+ return cls._redirect_to_messaging()
+
+ # the record has a window redirection: check access rights
+ if not RecordModel.sudo(uid).check_access_rights('read', raise_exception=False):
+ return cls._redirect_to_messaging()
+ try:
+ record_sudo.sudo(uid).check_access_rule('read')
+ except AccessError:
+ return cls._redirect_to_messaging()
+
+ url_params = {
+ 'view_type': record_action['view_type'],
+ 'model': model,
+ 'id': res_id,
+ 'active_id': res_id,
+ 'view_id': record_sudo.get_formview_id(),
+ 'action': record_action.get('id'),
+ }
+ url = '/web?#%s' % url_encode(url_params)
+ return werkzeug.utils.redirect(url)
+
@http.route('/mail/receive', type='json', auth='none')
def receive(self, req):
""" End-point to receive mail from an external SMTP server. """
@@ -94,8 +164,6 @@ class MailController(http.Controller):
- users without read access are redirected to the Messaging
- not logged users are redirected to the login page
"""
- uid = request.session.uid
-
if message_id:
try:
message = request.env['mail.message'].sudo().browse(int(message_id)).exists()
@@ -109,112 +177,48 @@ class MailController(http.Controller):
elif res_id and isinstance(res_id, basestring):
res_id = int(res_id)
- # no model / res_id, meaning no possible record -> redirect to login
- if not model or not res_id or model not in request.env:
- return self._redirect_to_messaging()
+ return self._redirect_to_record(model, res_id)
- # find the access action using sudo to have the details about the access link
- RecordModel = request.env[model].sudo(uid)
- record = RecordModel.browse(res_id).exists()
- if not record:
- # record does not seem to exist -> redirect to login
- return self._redirect_to_messaging()
- record_action = record.get_access_action()
+ @http.route('/mail/follow', type='http', auth='user', methods=['GET'])
+ def mail_action_follow(self, model, res_id, token=None):
+ comparison, record, redirect = self._check_token_and_record_or_redirect(model, int(res_id), token)
+ if comparison and record:
+ try:
+ record.sudo().message_subscribe_users()
+ except Exception:
+ return self._redirect_to_messaging()
+ return redirect
- # only URL redirections or window actions supported currently
- if not record_action['type'] in ('ir.actions.act_url', 'ir.actions.act_window'):
- return self._redirect_to_messaging()
-
- # the record has an URL redirection: use it directly
- if record_action['type'] == 'ir.actions.act_url':
- return werkzeug.utils.redirect(record_action['url'])
-
- # the record has a window redirection: check access rights
- if not RecordModel.check_access_rights('read', raise_exception=False):
- return self._redirect_to_messaging()
- try:
- record.check_access_rule('read')
- except AccessError:
- return self._redirect_to_messaging()
-
- # at this point user can read the document so no issue with get_formview_id
- query = {}
- url_params = {
- 'view_type': record_action['view_type'],
- 'model': model,
- 'id': res_id,
- 'active_id': res_id,
- 'view_id': record.get_formview_id(),
- 'action': record_action.get('id'),
- }
- url = '/web?%s#%s' % (url_encode(query), url_encode(url_params))
- return werkzeug.utils.redirect(url)
-
- @http.route('/mail/follow', type='http', auth='user')
- def mail_action_follow(self, model, res_id):
- if model not in request.env:
- return self._redirect_to_messaging()
- Model = request.env[model]
- try:
- Model.browse(res_id).message_subscribe_users()
- except:
- return self._redirect_to_messaging()
- return werkzeug.utils.redirect('/mail/view?%s' % url_encode({'model': model, 'res_id': res_id}))
-
- @http.route('/mail/unfollow', type='http', auth='user')
- def mail_action_unfollow(self, model, res_id):
- if model not in request.env:
- return self._redirect_to_messaging()
- Model = request.env[model]
- try:
- Model.browse(res_id).sudo().message_unsubscribe_users([request.uid])
- except:
- return self._redirect_to_messaging()
- return werkzeug.utils.redirect('/mail/view?%s' % url_encode({'model': model, 'res_id': res_id}))
+ @http.route('/mail/unfollow', type='http', auth='user', methods=['GET'])
+ def mail_action_unfollow(self, model, res_id, token=None):
+ comparison, record, redirect = self._check_token_and_record_or_redirect(model, int(res_id), token)
+ if comparison and record:
+ try:
+ # TDE CHECKME: is sudo really necessary ?
+ record.sudo().message_unsubscribe_users([request.uid])
+ except Exception:
+ return self._redirect_to_messaging()
+ return redirect
@http.route('/mail/new', type='http', auth='user')
- def mail_action_new(self, model, res_id, **kwargs):
+ def mail_action_new(self, model, res_id, action_id):
if model not in request.env:
return self._redirect_to_messaging()
params = {'view_type': 'form', 'model': model}
- if kwargs.get('action_id'):
- params['action'] = kwargs['action_id']
+ if action_id:
+ # Probably something to do
+ params['action'] = action_id
return werkzeug.utils.redirect('/web?#%s' % url_encode(params))
- @http.route('/mail/method', type='http', auth='user')
- def mail_action_method(self, model, res_id, method, **kwargs):
- # only public methods / check exists
- if method.strip().startswith('_') or model not in request.env:
- return self._redirect_to_messaging()
- Model = request.env[model]
- try:
- record = Model.browse(int(res_id)).exists()
- getattr(record, method)(**json.loads(kwargs.get('params', {})))
- except:
- return self._redirect_to_messaging()
- return werkzeug.utils.redirect('/mail/view?%s' % url_encode({'model': model, 'res_id': res_id}))
-
- @http.route('/mail/assign', type='http', auth='user')
- def mail_action_assign(self, model, res_id):
- if model not in request.env:
- return self._redirect_to_messaging()
- Model = request.env[model]
- try:
- Model.browse(int(res_id)).exists().write({'user_id': request.uid})
- except:
- return self._redirect_to_messaging()
- return werkzeug.utils.redirect('/mail/view?%s' % url_encode({'model': model, 'res_id': res_id}))
-
- @http.route('/mail/workflow', type='http', auth='user')
- def mail_action_workflow(self, model, res_id, signal, **kwargs):
- if model not in request.env:
- return self._redirect_to_messaging()
- Model = request.env[model]
- try:
- Model.browse(int(res_id)).exists().signal_workflow(signal)
- except:
- return self._redirect_to_messaging()
- return werkzeug.utils.redirect('/mail/view?%s' % url_encode({'model': model, 'res_id': res_id}))
+ @http.route('/mail/assign', type='http', auth='user', methods=['GET'])
+ def mail_action_assign(self, model, res_id, token=None):
+ comparison, record, redirect = self._check_token_and_record_or_redirect(model, int(res_id), token)
+ if comparison and record:
+ try:
+ record.write({'user_id': request.uid})
+ except Exception:
+ return self._redirect_to_messaging()
+ return redirect
@http.route('/mail///avatar/', type='http', auth='public')
def avatar(self, res_model, res_id, partner_id):
diff --git a/addons/mail/data/mail_data.xml b/addons/mail/data/mail_data.xml
index c229ef0f54e..4ca940fecd1 100644
--- a/addons/mail/data/mail_data.xml
+++ b/addons/mail/data/mail_data.xml
@@ -82,25 +82,25 @@
]]>
diff --git a/addons/mail/doc/changelog.rst b/addons/mail/doc/changelog.rst
deleted file mode 100644
index 5eee5f136a6..00000000000
--- a/addons/mail/doc/changelog.rst
+++ /dev/null
@@ -1,26 +0,0 @@
-.. _changelog:
-
-Changelog
-=========
-
-`trunk (saas-2)`
-----------------
-
- - ``mass_mailing_campaign`` update
-
- - ``mail_mail`: moved ``reply_to`` computation from ``mail_mail`` to ``mail_message``
- where it belongs, as the field is located onto the ``mail_message`` model.
- - ``mail_compose_message``: template rendering is now done in batch. Each template
- is rendered for all res_ids, instead of all templates one id at a time.
- - ``mail_thread``: to ease inheritance, processing of routes is now done in
- message_route_process, called in message_route
-
- - added support of ``active_domain`` form context, coming from the list view.
- When checking the header hook, the mass mailing will be done on all records
- matching the ``active_domain``.
- - added ``mail_server_id`` to mail_message, removing it from mail_mail. This allows
- to set the preferred mail server to use for notifications emails, when using
- templates.
- - added ``_mail_post_access`` attribute that specifies the access right that
- should have the user in order to post a new message on a given model. Values
- are ``read`` (portal documents), ``write`` (default value), ``unlink`` or ``create``.
diff --git a/addons/mail/doc/index.rst b/addons/mail/doc/index.rst
deleted file mode 100644
index 033b1241af6..00000000000
--- a/addons/mail/doc/index.rst
+++ /dev/null
@@ -1,12 +0,0 @@
-Mail module documentation
-=========================
-
-The Mail module holds all models and logic related to messages management. At low-level, it handles messages and offers an API to message queues for email sending. At an higher level, it provides the OpenChatter feature that is a thread management system inside OpenERP. A model that inherits from the mail module adds OpenChatter to its document. Its gives them the following capabilities :
-
- - messages management with a threaded design
- - subscription mechanism tha allow users to follow/unfollow documents
- - notifications mechanism; notifications are pushed to users to form a Wall page holding the latest pushed messages
-
-The mail module also comes with an email composition wizard, along with discussion groups.
-
-.. include:: index.rst.inc
diff --git a/addons/mail/doc/index.rst.inc b/addons/mail/doc/index.rst.inc
deleted file mode 100644
index 7f56666336b..00000000000
--- a/addons/mail/doc/index.rst.inc
+++ /dev/null
@@ -1,23 +0,0 @@
-
-Mail Module documentation topics
-'''''''''''''''''''''''''''''''''
-
-.. toctree::
- :maxdepth: 1
-
- mail_message
- mail_thread
- mail_openchatter_howto
- mail_needaction_howto
- mail_partner
- mail_state
- mail_subtype
-
-
-Changelog
-'''''''''
-
-.. toctree::
- :maxdepth: 1
-
- changelog.rst
diff --git a/addons/mail/doc/mail_message.rst b/addons/mail/doc/mail_message.rst
deleted file mode 100644
index de58b3bebf2..00000000000
--- a/addons/mail/doc/mail_message.rst
+++ /dev/null
@@ -1,111 +0,0 @@
-.. _mail_message:
-
-mail.message
-============
-
-Models
-++++++
-
-``mail.message`` is a class for holding the main attributes of a message object
-(notification for system message, reciving email message or sent messages). It
-could be reused as parent model for any database model, wall thread view, or
-wizard screen that needs to hold a kind of message.
-
-All internal logic should be in a database-based model while this model
-holds the basics of a message. For example, a wizard for writing emails
-should inherit from this class.
-
-
-.. versionchanged:: 7.0
-
-ClientAction (ir.actions.client)
-++++++++++++++++++++++++++++++++
-
-.. code-block:: xml
-
-
- Inbox
- mail.wall
- mail.message
-
-
-
-
-
- - ``tag`` : 'mail.wall', 'mail_thread' or 'mail.widget'
- 'mail.wall' to have a display like the mail wall with threads, title, search view
- (default value like a wall)
- 'mail_thread' widget for field on standard view. (default value like a thread for
- record, view on flat mode, no reply, no read/unread)
- 'mail.widget' it's the root thread, used by 'mail.wall' and 'mail_thread'
-
- - ``help`` : Text HTML to display if there are no message
- - ``context`` : insert 'default_model' and 'default_res_id'
- - ``params`` : options for the widget
- - ``domain`` : choose the domain of the messages
- - ``truncate_limit`` : {Number} number of character to display before having a "show more"
- link; note that the text will not be truncated if it does not have 110% of the parameter
- - ``show_record_name`` : {Boolean} display the name and link of the related record
- - ``show_reply_button`` : {Boolean} display the reply button
- - ``show_read_unread_button`` : {Boolean} display the read/unread button
- - ``display_indented_thread`` : {int [0,1]} number thread level to indented threads.
- - ``show_compose_message`` : display the composer on top thread
- - ``show_compact_message`` : display the compact message on the thread when the user clic
- on this compact mode, the composer is open
- - ``message_ids`` : {Array | False} List of ids to fetch by the root thread. If no value,
- the root search the message by the domain
- - ``compose_placeholder`` : Message to display on the textareaboxes.
- - ``show_link`` : Display partner (authors, followers...) on link or not
- - ``compose_as_todo`` : The root composer mark automatically the message as todo
- - ``readonly`` : Read only mode, hide all action buttons and composer
-
-Fields
-++++++
-
- - ``type`` : usually 'email', 'comment', 'notification'.
- Message type: email for external email message recieve, notification for system
- message, comment for other messages such as user replies.
- - ``subtype_id`` :
- Subtype of the notification for system message. The users can followe a document
- and choose the subtype of this document (eg: Create, Comment, Done).
- You can defined new subtypes and choose his name, by agreement the id begin by "mt\_" on the model
- "mail.message.subtype".
- - ``partner_ids`` :
- List of recipients, the recipients have this message in their personal mailboxe.
- - ``notified_partner_ids`` :
- Partners that have a notification pushing this message in their mailboxes. Usualy
- it's an automatic system message for a model followed by users.
- - ``notification_ids`` :
- Technical field holding the message notifications. Use notified_partner_ids to access
- notified partners.
- - ``attachment_ids`` :
- List of attachments
- - ``parent_id`` :
- It's the initial thread message. It's use for group message by thread in mailboxes.
- - ``child_ids`` :
- List of child message linked to the initial thread message.
- - ``model`` :
- Related Document Moded. It's use for group message by document.
- - ``res_id`` :
- Related Document ID. It's use for group message by document.
- - ``record_name`` :
- Functionnal field use to get the name of related document.
- - ``vote_user_ids`` :
- List of partner that vote/like this message.
- - ``to_read`` :
- Functional field to search for messages the current user has to read. The messages as
- treat like a need action. When the user recive a message (to_read = True) this message
- or action must be performed and mark done (to_read = False)
- - ``favorite_user_ids`` :
- Users that set this message in their favorites/todo list.
-
-Methods
-+++++++
-
- - ``message_read`` :
- Value: ids, domain, message_unload_ids, thread_level, context, parent_id, limit
- Return: List of dictinary of message. All message is sent with their parented messages and
- sort by id. The messages that the user can read but not in his search, are group in
- expandable messages. The expandable messages contain the domain to expand.
- - ``check_access_rule`` :
- Overwrite the initial message for this model.
diff --git a/addons/mail/doc/mail_needaction_howto.rst b/addons/mail/doc/mail_needaction_howto.rst
deleted file mode 100644
index 8cb41cee374..00000000000
--- a/addons/mail/doc/mail_needaction_howto.rst
+++ /dev/null
@@ -1,15 +0,0 @@
-
-How to use the need action mechanism in my addon
-=================================================
-
-Make your module inheriting from ir.needaction_mixin class
-
-Feature integration
-++++++++++++++++++++
-
-::
-
- class my_module(osv.osv):
- _name = "my.module"
- _description = "My Module"
- _inherit = ['ir.needaction_mixin']
diff --git a/addons/mail/doc/mail_openchatter_howto.rst b/addons/mail/doc/mail_openchatter_howto.rst
deleted file mode 100644
index f8b4fd98934..00000000000
--- a/addons/mail/doc/mail_openchatter_howto.rst
+++ /dev/null
@@ -1,112 +0,0 @@
-
-How to use OpenChatter in my addon
-===================================
-
-Running example
-++++++++++++++++
-
-A small my_task model will be used as example to explain how to use the
-OpenChatter feature. Being simple, it has only the following fields:
-
-- a name
-- a task responsible
-- a related project
-
-::
-
- class my_task(osv.osv):
- _name = "my.task"
- _description = "My Task"
- _columns = {
- 'name': fields.char('Name', required=True, size=64),
- 'user_id':fields.many2one('res.users', string='Responsible',
- ondelete='cascade', required=True, select=1),
- 'project_id':fields.many2one('project.project', string='Related project',
- ondelete='cascade', required=True, select=1),
- }
-
-
-Two-lines feature integration
-++++++++++++++++++++++++++++++
-
-Make your object inherit from :class:`mail.thread`::
-
- class my_task(osv.osv):
- _name = "my.task"
- _description = "My Task"
- # inherit from mail.thread allows the use of OpenChatter
- _inherit = ['mail.thread']
-
-Use the thread viewer widget inside your form view by using the mail_thread
-widget on the message_ids field inherited from :class:`mail.thread`::
-
-
- My Task
- my.task
- 1
-
-
-
-
-
-Send notifications
-+++++++++++++++++++
-
-When sending a notification is required in your workflow or business logic,
-use :meth:`mail.thread.message_post`. It will automatically take care of
-subscriptions and notifications.
-
-Here is a small example of sending a notification when the ``do_something``
-method is called::
-
- def do_something(self, cr, uid, ids, context=None):
- self.do_something_send_note(cr, uid, ids, context=context)
- return res
-
- def do_something_send_note(self, cr, uid, ids, context=None):
- self.message_post(
- cr, uid, ids, _('My subject'),
- _("has received a notification and is happy for it."),
- context=context)
-
-Notifications guidelines
-+++++++++++++++++++++++++
-
-- avoid unnecessary content, swamping users with irrelevant messages will lead
- to them ignoring all messages
-- use short sentences
-- do not include the document name, this is done by the thread widget
-- use a simple and clean style
-
- - html tags are supported: use or mainly
- - put key word(s) in bold
- - avoid fancy styles that will break the OpenERP look and feel
-- create a separate method for sending your notification, use clear method
- names allowing quickly spotting notification code e.g. name notification
- methods by using the original method name postfixed by ``_send_note``
- (``do_something`` -> ``do_something_send_note``)
-
-Subscription management
-++++++++++++++++++++++++
-
-The default subscription behavior is the following:
-
-* Subscriptions are set up by creating a :class:`mail.followers`` entry
-* If a user creates or updates a document, they automatically follow it. The
- corresponding :class:`mail.followers` entry is created
-* If a user explicitly cliks on the document's :guilabel:`Follow` button,
- they follow the document. The corresponding :class:`mail.followers` entry
- is created
-* If a user explicitly clicks on the document's :guilabel:`Unfollow` button,
- they stop following the document. The corresponding :class:`mail.followers`
- entry is deleted
-
-You should not directly manipulate :class:`mail.followers` entry, if you need
-to override the default subscription behavior you should override the relevant
-:class:`mail.thread` methods.
-
-.. TODO: wtf are the relevant mail.thread methds? message_get_subscribers
- has disappeared and nothing looks like a replacement
diff --git a/addons/mail/doc/mail_partner.rst b/addons/mail/doc/mail_partner.rst
deleted file mode 100644
index a99246395d7..00000000000
--- a/addons/mail/doc/mail_partner.rst
+++ /dev/null
@@ -1,10 +0,0 @@
-What is shown
-==============
- - for every module which are related to partner show apporopriate message in the partner view like opportunities, sale orders and invoices.
-
-
-How it is done
-===============
- - _inherit = 'mail.thread'
-
- - Override def message_load_ids(self, cr, uid, ids, limit=100, offset=0, domain=[], ascent=False, root_ids=[], context=None) search by the partner
diff --git a/addons/mail/doc/mail_state.rst b/addons/mail/doc/mail_state.rst
deleted file mode 100644
index cf1874ffca1..00000000000
--- a/addons/mail/doc/mail_state.rst
+++ /dev/null
@@ -1,28 +0,0 @@
-.. _mail_state:
-
-message_unread
-==============
-
-``message_unread`` is a boolean field that states whether the document
-has unread messages. In previous versions, some documents were going
-back to ``pending`` state when receiving an email through the mail
-gateway. Now the state related to messages differs from the state or
-stage of the document itself.
-
-message_unread and need action mechanism
-++++++++++++++++++++++++++++++++++++++++
-
-The ``mail`` module introduces a default behavior for the need_action
-mechanism [REF].
-
-::
-
- def get_needaction_user_ids(self, cr, uid, ids, context=None):
- """ Returns the user_ids that have to perform an action
- :return: dict { record_id: [user_ids], }
- """
- result = super(ir_needaction_mixin, self).get_needaction_user_ids(cr, uid, ids, context=context)
- for obj in self.browse(cr, uid, ids, context=context):
- if obj.message_unread == False and obj.user_id:
- result[obj.id].append(obj.user_id.id)
- return result
diff --git a/addons/mail/doc/mail_subtype.rst b/addons/mail/doc/mail_subtype.rst
deleted file mode 100644
index e63b67936cd..00000000000
--- a/addons/mail/doc/mail_subtype.rst
+++ /dev/null
@@ -1,70 +0,0 @@
-.. _mail_message_subtype:
-
-OpenChatter Pi (3.1415): Message Subtype
-========================================
-
- To overcome the problems of crowdy walls in system notification, We have added features of **Message Subtype** in mail.
-
-mail.message.subtype
-++++++++++++++++++++
-``mail.message.subtype`` has following fields:
-
- - ``Name``: fields.char(' Message Subtype ', size = 128,required = True,help = 'Subtype Of Message'),
- - ``model_ids``: fields.many2many('ir.model','mail_message_subtyp_message_rel','message_subtype_id', 'model_id', 'Model',help = "link some subtypes to several models, for projet/task"),
- - ``default``: fields.boolean('Default', help = "When subscribing to the document, users will receive by default messages related to this subtype unless they uncheck this subtype"),
-
-mail.followers
-++++++++++++++
-
-In ``mail.followers`` we have added additional many2many field subtype ids :
-
- - ``subtype_ids``: fields.many2many('mail.message.subtype','mail_message_subtyp_rel','subscription_id', 'subtype_id', 'Subtype',help = "linking some subscription to several subtype for projet/task")
-
-mail.message
-++++++++++++
-
-In mail_message we have added additional field subtype_id which Indicates the Type of Message
-
- - ``subtype_id``: fields.many2one('mail.message.subtype', 'Subtype')
-
-mail.thread
-+++++++++++
-
- - In **message_post** method add the *subtype_id* field as parameter and set as default subtype 'Other'.
-
- def message_post(self, cr, uid, thread_id, body='', subject=False, msg_type='notification', parent_id=False, attachments=None, subtype='other', context=None, ``**kwargs``):
-
- - In **message_subscribe** method add the *subtype_ids* field as parameter.In this method if subtype_ids is None, it fatch the default true subtypes in mail.message.subtypes otherwise pass selected subtypes.
- For update subtypes call **message_subscribe_udpate_subtypes** method
-
- def message_subscribe(self, cr, uid, ids, partner_ids,subtype_ids = None, context=None):
-
- - Add **message_subscribe_udpate_subtypes** method to update the subtype_ids in followers.
-
- def message_subscribe_udpate_subtypes(self, cr, uid, ids, user_id, subtype_ids,context=None):
- followers_obj = self.pool.get('mail.followers')
- followers_ids = followers_obj.search(cr, uid, [('res_model', '=', self._name), ('res_id', 'in', ids)])
- return followers_obj.write(cr, uid, followers_ids, {'subtype_ids': [(6, 0 , subtype_ids)]}, context = context)
-
-For Each Addons:
-++++++++++++++++
-
- - Add data of subtypes for each addons module.
- - Add subtype field as parameter in **message_post** Method for each addons module.
-
-How It Works:
-+++++++++++++
-
- - In addons module when we Follow a Perticular document It display under the followers button.
- - In sybtypes there are 3 default subtypes for each addons
- 1) Email
- 2) Comment
- 3) Other
- - In document display a default subtypes(which are true) related a perticular model_ids wise.
-
- Example:-
- If I have open crm.lead, It display only subtypes of crm.lead
-
- - When we select subtype it update subtype_ids(which are checked) in mail.follower where match res_model & res_id of the current documents.
- - when message created update subtype_id of that message in mail.message.
- - In Feeds display only those notifications of documents which subtypes are selected
diff --git a/addons/mail/doc/mail_thread.rst b/addons/mail/doc/mail_thread.rst
deleted file mode 100644
index 9a59b7c967c..00000000000
--- a/addons/mail/doc/mail_thread.rst
+++ /dev/null
@@ -1,53 +0,0 @@
-.. _mail_thread:
-
-===========================
-mail.thread and OpenChatter
-===========================
-
-API
-===
-
-Writing messages and notifications
-----------------------------------
-
-``message_append``
-
-Creates a new mail.message through message_create. The new message is attached
-to the current mail.thread, containing all the details passed as parameters.
-All attachments will be attached to the thread record as well as to the
-actual message.
-
-This method calls message_create that will handle management of subscription
-and notifications, and effectively create the message.
-
-If ``email_from`` is not set or ``type`` not set as 'email', a note message
-is created (comment or system notification), without the usual envelope
-attributes (sender, recipients, etc.).
-
-mail.group
-++++++++++
-
-A mail_group is a collection of users sharing messages in a discussion group. Group users are users that follow the mail group, using the subscription/follow mechanism of OpenSocial. A mail group has nothing in common wih res.users.group.
-Additional information on fields:
-
- - ``member_ids``: user member of the groups are calculated with ``message_get_subscribers`` method from mail.thread
- - ``member_count``: calculated with member_ids
- - ``is_subscriber``: calculated with member_ids
-
-res.users
-+++++++++
-
-OpenChatter updates the res.users class:
- - it adds a preference about sending emails when receiving a notification
- - make a new user follow itself automatically
- - create a welcome message when creating a new user, to make his arrival in OpenERP more friendly
-
-
-Misc magic context keys
-+++++++++++++++++++++++
-
- - mail_create_nosubscribe: when creating a new record that inherit from mail_thread,
- do not subscribe the creator to the document followers
- - mail_create_nolog: do not log creation message
- - mail_notify_noemail: do not send email notifications; partners to notify are
- notified, i.e. a mail_notification is created, but no email is actually send
diff --git a/addons/mail/doc/tracked_field.rst b/addons/mail/doc/tracked_field.rst
deleted file mode 100644
index 8d06ae1fa41..00000000000
--- a/addons/mail/doc/tracked_field.rst
+++ /dev/null
@@ -1,18 +0,0 @@
-Tracked fields
----------------
-Tracked fields is generic logging system for the changes applied to some fields in open chatter.
- - In the definition of a fields. you have to simply add tracked=True.
- - When changing one of the fields having tracked=True on saved automatically write a log in openchatter for the changes in fields.
-
-How it works:
-+++++++++++++
- - You have to add tracked=True in field defination as following.
- - ``'stage_id': fields.many2one('project.task.type', 'Stage',tracked=True),``
- - For developed this feature we override write method of mail_thread.
- - And make one mako template which shows old field and updated field.
-
-Open chatter log:
-+++++++++++++++++
- - After changing field follower can show log of tracked field in open chatter as followed.
- - Updated Fields:
- - Stage: Analysis -> Specification
\ No newline at end of file
diff --git a/addons/mail/models/mail_template.py b/addons/mail/models/mail_template.py
index d87cad5fec7..9f870b86ac2 100644
--- a/addons/mail/models/mail_template.py
+++ b/addons/mail/models/mail_template.py
@@ -45,7 +45,7 @@ def format_tz(env, dt, tz=False, format=False):
format_time = langs.time_format or '%I-%M %p'
fdate = ts.strftime(format_date).decode('utf-8')
- ftime = ts.strftime(format_time)
+ ftime = ts.strftime(format_time).decode('utf-8')
return "%s %s%s" % (fdate, ftime, (' (%s)' % tz) if tz else '')
try:
diff --git a/addons/mail/models/mail_thread.py b/addons/mail/models/mail_thread.py
index 71c196cd693..599cec0493c 100644
--- a/addons/mail/models/mail_thread.py
+++ b/addons/mail/models/mail_thread.py
@@ -5,6 +5,8 @@ import base64
import datetime
import dateutil
import email
+import hashlib
+import hmac
import json
import lxml
import logging
@@ -568,6 +570,13 @@ class MailThread(models.AbstractModel):
because portal users have a different Inbox action than classic users. """
return 'mail.mail_channel_action_client_chat'
+ @api.model
+ def _generate_notification_token(self, base_link, params):
+ secret = self.env['ir.config_parameter'].sudo().get_param('database.secret')
+ token = '%s?%s' % (base_link, ' '.join('%s=%s' % (key, params[key]) for key in sorted(params.keys())))
+ hm = hmac.new(str(secret), token, hashlib.sha1).hexdigest()
+ return hm
+
@api.multi
def _notification_link_helper(self, link_type, **kwargs):
if kwargs.get('message_id'):
@@ -576,24 +585,29 @@ class MailThread(models.AbstractModel):
}
else:
base_params = {
- 'model': kwargs.pop('model', self._name),
- 'res_id': kwargs.pop('res_id', self.ids and self.ids[0] or False),
+ 'model': kwargs.get('model', self._name),
+ 'res_id': kwargs.get('res_id', self.ids and self.ids[0] or False),
}
- link = False
if link_type in ['view', 'assign', 'follow', 'unfollow']:
params = dict(base_params)
- link = '/mail/%s?%s' % (link_type, url_encode(params))
- elif link_type == 'workflow':
- params = dict(base_params, signal=kwargs['signal'])
- link = '/mail/workflow?%s' % url_encode(params)
- elif link_type == 'method':
- method = kwargs.pop('method')
- params = dict(base_params, method=method, params=json.dumps(kwargs))
- link = '/mail/method?%s' % url_encode(params)
+ base_link = '/mail/%s' % link_type
elif link_type == 'new':
- params = dict(base_params, action_id=kwargs.get('action_id'))
- link = '/mail/new?%s' % url_encode(params)
+ params = dict(base_params, action_id=kwargs.get('action_id', ''))
+ base_link = '/mail/new'
+ elif link_type == 'controller':
+ controller = kwargs.pop('controller')
+ params = dict(base_params)
+ params.pop('model')
+ base_link = '%s' % controller
+ else:
+ return ''
+
+ if link_type not in ['view', 'new']:
+ token = self._generate_notification_token(base_link, params)
+ params['token'] = token
+
+ link = '%s?%s' % (base_link, url_encode(params))
return link
@api.multi
@@ -1030,7 +1044,7 @@ class MailThread(models.AbstractModel):
tools.decode_message_header(message, 'Cc'),
tools.decode_message_header(message, 'Resent-To'),
tools.decode_message_header(message, 'Resent-Cc')])
- rcpt_tos_localparts = [e.split('@')[0] for e in tools.email_split(rcpt_tos)]
+ rcpt_tos_localparts = [e.split('@')[0].lower() for e in tools.email_split(rcpt_tos)]
# 0. Verify whether this is a bounced email and use it to collect bounce data and update notifications for customers
if bounce_alias and bounce_alias in email_to_localpart:
diff --git a/addons/mail/models/update.py b/addons/mail/models/update.py
index a5717353a79..7e2abfcbfd8 100644
--- a/addons/mail/models/update.py
+++ b/addons/mail/models/update.py
@@ -31,13 +31,13 @@ class PublisherWarrantyContract(AbstractModel):
limit_date = datetime.datetime.now()
limit_date = limit_date - datetime.timedelta(15)
limit_date_str = limit_date.strftime(misc.DEFAULT_SERVER_DATETIME_FORMAT)
- nbr_users = Users.search_count([])
- nbr_active_users = Users.search_count([("login_date", ">=", limit_date_str)])
+ nbr_users = Users.search_count([('active', '=', True)])
+ nbr_active_users = Users.search_count([("login_date", ">=", limit_date_str), ('active', '=', True)])
nbr_share_users = 0
nbr_active_share_users = 0
if "share" in Users._fields:
- nbr_share_users = Users.search_count([("share", "=", True)])
- nbr_active_share_users = Users.search_count([("share", "=", True), ("login_date", ">=", limit_date_str)])
+ nbr_share_users = Users.search_count([("share", "=", True), ('active', '=', True)])
+ nbr_active_share_users = Users.search_count([("share", "=", True), ("login_date", ">=", limit_date_str), ('active', '=', True)])
user = self.env.user
domain = [('application', '=', True), ('state', 'in', ['installed', 'to upgrade', 'to remove'])]
apps = self.env['ir.module.module'].sudo().search_read(domain, ['name'])
diff --git a/addons/mail/static/description/index.html b/addons/mail/static/description/index.html
index 0ac3584090f..54d6016fd9f 100644
--- a/addons/mail/static/description/index.html
+++ b/addons/mail/static/description/index.html
@@ -1,6 +1,6 @@
-
Enhance team communication
+
Enhance team communication
Group and private chat, integrated with all modules
@@ -10,7 +10,7 @@
-
Engage conversation with colleagues
+
Engage conversation with colleagues
A powerful communication tool
@@ -27,7 +27,7 @@
-
Chat in live from anywhere
+
Chat in live from anywhere
Keep conversations open in other modules
@@ -43,7 +43,7 @@
-
Communicate with the right target
+
Communicate with the right target
Create channels and private groups
Start discussion with the right people with channels and allow any employee to join in to the conversation.Create private channels to invite only a selected group of people and prevent unrelated employees to pollute the conversations.
@@ -56,7 +56,7 @@
-
Personalize notifications
+
Personalize notifications
Send notifications only when you want to
@@ -73,7 +73,7 @@
-
Integrated with all modules
+
Integrated with all modules
Keep track of all actions within one window
Follow any discussion from any module to automatically see updates and discussions on those tasks in your news feed. Create public and private groups to invite participants, personalize the notifications system and add those groups to specific tasks to keep track of the evolution of all projects.
diff --git a/addons/mail/static/src/xml/thread.xml b/addons/mail/static/src/xml/thread.xml
index b5ed0081d74..b9579be0790 100644
--- a/addons/mail/static/src/xml/thread.xml
+++ b/addons/mail/static/src/xml/thread.xml
@@ -94,7 +94,7 @@
(from #)
-
+
diff --git a/addons/mail/tests/__init__.py b/addons/mail/tests/__init__.py
index 413ea870c3c..1ff431bd633 100644
--- a/addons/mail/tests/__init__.py
+++ b/addons/mail/tests/__init__.py
@@ -10,3 +10,4 @@ import test_message_track
import test_mail_template
import test_invite
import test_ir_actions
+import test_update_notification
diff --git a/addons/mail/tests/test_update_notification.py b/addons/mail/tests/test_update_notification.py
new file mode 100644
index 00000000000..7621e4056a1
--- /dev/null
+++ b/addons/mail/tests/test_update_notification.py
@@ -0,0 +1,11 @@
+# -*- coding: utf-8 -*-
+from odoo.tests.common import TransactionCase
+
+
+class TestUpdateNotification(TransactionCase):
+ def test_user_count(self):
+ ping_msg = self.env['publisher_warranty.contract'].with_context(active_test=False)._get_message()
+ user_count = self.env['res.users'].search_count([('active', '=', True)])
+ self.assertEqual(ping_msg.get('nbr_users'), user_count, 'Update Notification: Users count is badly computed in ping message')
+ share_user_count = self.env['res.users'].search_count([('active', '=', True), ('share', '=', True)])
+ self.assertEqual(ping_msg.get('nbr_share_users'), share_user_count, 'Update Notification: Portal Users count is badly computed in ping message')
diff --git a/addons/marketing_campaign/models/marketing_campaign.py b/addons/marketing_campaign/models/marketing_campaign.py
index 55df93b4846..2aa745dfaa1 100644
--- a/addons/marketing_campaign/models/marketing_campaign.py
+++ b/addons/marketing_campaign/models/marketing_campaign.py
@@ -144,7 +144,7 @@ class MarketingCampaign(models.Model):
similar_res_ids = self.env[self.object_id.model].search([(unique_field.name, '=', unique_value)])
if similar_res_ids:
duplicate_workitem_domain = [
- ('res_id', 'in', similar_res_ids),
+ ('res_id', 'in', similar_res_ids.ids),
('campaign_id', '=', self.id)
]
return self.env['marketing.campaign.workitem'].search(duplicate_workitem_domain)
diff --git a/addons/marketing_campaign/static/description/index.html b/addons/marketing_campaign/static/description/index.html
index 5711c02e503..cfc189727e7 100644
--- a/addons/marketing_campaign/static/description/index.html
+++ b/addons/marketing_campaign/static/description/index.html
@@ -1,6 +1,6 @@
-
Better manage leads with marketing automation
+
Better manage leads with marketing automation
Nurture all of your prospects with a personal and targeted message
@@ -10,7 +10,7 @@
-
Generate new opportunities effortlessly
+
Generate new opportunities effortlessly
Streamline your marketing & take care of your leads 24/7
@@ -45,7 +45,7 @@
-
Deliver a message that resonates with your prospects
+
Deliver a message that resonates with your prospects
Create advanced and personal emails that don't look automated
@@ -69,7 +69,7 @@
-
Shorten your sales cycle
+
Shorten your sales cycle
Manage your prospects better by combining lead scoring and lead automation
@@ -84,7 +84,7 @@
-
Follow the ROI of all your marketing activities
+
Follow the ROI of all your marketing activities
Make smarter decisions thanks to our powerful analytics reports
diff --git a/addons/mrp/models/mrp_production.py b/addons/mrp/models/mrp_production.py
index d0f5a2f00f4..e21b492af63 100644
--- a/addons/mrp/models/mrp_production.py
+++ b/addons/mrp/models/mrp_production.py
@@ -230,7 +230,10 @@ class MrpProduction(models.Model):
self.bom_id = False
else:
bom = self.env['mrp.bom']._bom_find(product=self.product_id, picking_type=self.picking_type_id, company_id=self.company_id.id)
- self.bom_id = bom.id
+ if bom.type == 'normal':
+ self.bom_id = bom.id
+ else:
+ self.bom_id = False
self.product_uom_id = self.product_id.uom_id.id
return {'domain': {'product_uom_id': [('category_id', '=', self.product_id.uom_id.category_id.id)]}}
diff --git a/addons/mrp/models/stock_move.py b/addons/mrp/models/stock_move.py
index 5c539195444..853bd6d56a4 100644
--- a/addons/mrp/models/stock_move.py
+++ b/addons/mrp/models/stock_move.py
@@ -2,6 +2,7 @@
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from odoo import api, exceptions, fields, models, _
+from odoo.exceptions import UserError
from odoo.tools import float_compare
from odoo.addons import decimal_precision as dp
@@ -241,6 +242,8 @@ class StockMove(models.Model):
else:
for movelot in move.move_lot_ids:
if float_compare(movelot.quantity_done, 0, precision_rounding=rounding) > 0:
+ if not movelot.lot_id:
+ raise UserError(_('You need to supply a lot/serial number.'))
qty = move.product_uom._compute_quantity(movelot.quantity_done, move.product_id.uom_id)
quants = quant_obj.quants_get_preferred_domain(qty, move, lot_id=movelot.lot_id.id, domain=main_domain, preferred_domain_list=preferred_domain_list)
self.env['stock.quant'].quants_move(quants, move, move.location_dest_id, lot_id = movelot.lot_id.id)
diff --git a/addons/mrp/report/mrp_bom_cost_report.py b/addons/mrp/report/mrp_bom_cost_report.py
index 93ae3ad64e1..cbbdf935497 100644
--- a/addons/mrp/report/mrp_bom_cost_report.py
+++ b/addons/mrp/report/mrp_bom_cost_report.py
@@ -26,7 +26,7 @@ class MrpBomCost(models.AbstractModel):
'attributes': attributes}
total = 0.0
for bom_line, line_data in result2:
- price_uom = self.env['product.uom']._compute_qty(bom_line.product_id.uom_id.id, bom_line.product_id.standard_price, bom_line.product_uom_id.id)
+ price_uom = bom_line.product_uom_id._compute_quantity(bom_line.product_id.standard_price, bom_line.product_uom_id)
line = {
'product_id': bom_line.product_id,
'product_uom_qty': line_data['qty'], #line_data needed for phantom bom explosion
diff --git a/addons/mrp/static/description/index.html b/addons/mrp/static/description/index.html
index 5fe98beeb07..878d0b7942c 100644
--- a/addons/mrp/static/description/index.html
+++ b/addons/mrp/static/description/index.html
@@ -1,6 +1,6 @@
-
Simplify manufacturing processes
+
Simplify manufacturing processes
Online and easy MRP application
@@ -10,7 +10,7 @@
-
Efficiently schedule your manufacturing
+
Efficiently schedule your manufacturing
Keep track of resource capacities and avoid bottlenecks
@@ -35,7 +35,7 @@
-
Enjoy complete flexibility
+
Enjoy complete flexibility
A simple and powerful user interface
@@ -50,7 +50,7 @@
-
Work with Lists, Calendars or Gantt charts
+
Work with Lists, Calendars or Gantt charts
Organize manufacturing orders and work orders in any way you like.
Process upcoming orders from the List view, control in the Calendar view and edit the proposed schedule in the Gantt view.
@@ -85,7 +85,7 @@
-
Define Flexible Master Data
+
Define Flexible Master Data
Products, bill of materials and routings
Have the flexibility to create multi-level bills of materials, optional routing, version changes and phantom bills of materials. You can use BoM for kits or for manufacturing orders.
@@ -93,7 +93,7 @@
-
Advanced analytic features
+
Advanced analytic features
Get accurate data on your process
Track the changes in stock value according to the level of manufacturing activities as it progresses through the transformation process.
@@ -105,7 +105,7 @@
-
Fully integrated with Operations
+
Fully integrated with Operations
Sales, purchases, inventory and accounting integration
Achieve your goals and objectives easier than ever
@@ -27,7 +27,7 @@
-
Better manage your tasks and projects
+
Better manage your tasks and projects
Gather ideas on the fly and collaborate with your colleagues
@@ -74,7 +74,7 @@
-
Customize your notes and to-do lists
+
Customize your notes and to-do lists
Odoo Notes adapts to your needs and habits
@@ -89,7 +89,7 @@
-
Integrate Odoo Notes into your workflow
+
Integrate Odoo Notes into your workflow
diff --git a/addons/point_of_sale/security/point_of_sale_security.xml b/addons/point_of_sale/security/point_of_sale_security.xml
index 649d9df8e57..f29a37cfcfd 100644
--- a/addons/point_of_sale/security/point_of_sale_security.xml
+++ b/addons/point_of_sale/security/point_of_sale_security.xml
@@ -36,12 +36,6 @@
[(1, '=', 1)]
-
- Point Of Sale Cashbox Line POS User
-
-
- [('bank_statement_id.pos_session_id', '!=', False)]
- Point Of Sale Cashbox Line Accountant
diff --git a/addons/point_of_sale/static/description/index.html b/addons/point_of_sale/static/description/index.html
index df254603ebf..3635eda13b8 100644
--- a/addons/point_of_sale/static/description/index.html
+++ b/addons/point_of_sale/static/description/index.html
@@ -1,6 +1,6 @@
Add quick notes or attach files to any task and stay connected to your team. Forget endless follow-up meetings to keep track of projects. Communicate through the chatter, write in a shared, real time pad or use live chat - all in a single interface!
@@ -76,7 +76,7 @@
-
Conceptualize project scope within an easy-to-read overview
+
Conceptualize project scope within an easy-to-read overview
A functional and dynamic graph view for every task
Send polished quotation with e-Signature and online payment.
@@ -12,7 +12,7 @@
-
Your quotes online from proposal to eSignature
+
Your quotes online from proposal to eSignature
@@ -78,7 +78,7 @@
-
Sell more with clean quotations
+
Sell more with clean quotations
Better showcase your products and services.
Send clear and complete quotations to your prospects. Add product descriptions, beautiful images and additional information simply by dragging and dropping building blocks.
@@ -92,7 +92,7 @@
-
Great prices for great revenues
+
Great prices for great revenues
@@ -116,7 +116,7 @@
-
Order & contract sorting
+
Order & contract sorting
Automate operations and focus on relations and revenues
The customer can also confirm the order directly from the email he received.
"),
+ content: _t("
Confirm the order if the customer purchases.
"),
position: "bottom"
}, {
trigger: ".breadcrumb li:not(.active):last",
diff --git a/addons/sale_crm/static/src/js/tour.js b/addons/sale_crm/static/src/js/tour.js
index cd3fff9d04e..392c93c0804 100644
--- a/addons/sale_crm/static/src/js/tour.js
+++ b/addons/sale_crm/static/src/js/tour.js
@@ -14,7 +14,7 @@ var quotation_button_step_index = _.findIndex(tour.tours.sale_tour.steps, functi
tour.tours.sale_tour.steps.splice(quotation_button_step_index, 1, {
trigger: ".o_kanban_manage_button_section > a",
content: _t("Click here to see more options."),
- position: "bottom"
+ position: "right"
}, {
trigger: ".o_quotation_view_button",
content: _t("Let's have a look at the quotations of this sales team."),
diff --git a/addons/sale_margin/views/sale_margin_view.xml b/addons/sale_margin/views/sale_margin_view.xml
index fa9c56fe28a..b0da87326fa 100644
--- a/addons/sale_margin/views/sale_margin_view.xml
+++ b/addons/sale_margin/views/sale_margin_view.xml
@@ -20,7 +20,7 @@
-
+
diff --git a/addons/stock/static/description/index.html b/addons/stock/static/description/index.html
index 287088066f9..fad948575af 100644
--- a/addons/stock/static/description/index.html
+++ b/addons/stock/static/description/index.html
@@ -1,6 +1,6 @@
-
Maximize your warehouse efficiency
+
Maximize your warehouse efficiency
Modern online warehouse management software.
@@ -12,7 +12,7 @@
-
Improve performance and process time
+
Improve performance and process time
Better organize your warehouse with the smart double entry inventory system
Get the most efficient stocking method and improve all your internal operations. Odoo's double-entry inventory has no stock input, output or transformation. Instead, all operations are stock moves between locations.
@@ -25,7 +25,7 @@
-
Reduce your stock level and avoid stockouts
+
Reduce your stock level and avoid stockouts
Take advantage of automatic replenishment methods
@@ -42,7 +42,7 @@
-
Enjoy advanced and automated functions
+
Enjoy advanced and automated functions
The most advanced systems in a very simple user interface
- This Planner will help you think about your website and provide tips and ideas to inspire you. There are examp;les and explanations to guide you through the process of creating a top-notch, high quality website that meets all your needs.
+ This Planner will help you think about your website and provide tips and ideas to inspire you. There are examples and explanations to guide you through the process of creating a top-notch, high quality website that meets all your needs.
The whole process may take a few hours, some discussions with your colleagues and
several cups of coffee to go through. But don't worry, you can return to this tool at any time.
@@ -43,7 +43,7 @@
-
Examp;les
+
Examples
Attract new leads
Sell more online
@@ -71,7 +71,7 @@
-
Examp;les
+
Examples
Check your references before deciding to work with you
See and buy your products
@@ -195,13 +195,9 @@
- Install Apps
-
- Before starting to work on your website, make sure you have all the right applications installed.
- It will be much easier for you to organize and create your content if you have all the options activated from the beginning.
-
+ Install Features
- Activate now the apps you need:
+ Install what you need:
@@ -214,43 +210,50 @@
-
-
-
Blogs
-
Attract more leads with a winning content marketing strategy.
@@ -261,9 +264,9 @@
Your homepage is the most important page of your website. This is where visitors get their first impressions of you. An efficient homepage will prompt them to stay on your site, guide them towards your content, strengthen your company's branding and more.
Here are some pointers to help you get started.
-
Find a catchy headline
Make sure anyone who visits your site understands what it’s about without too much reading.
- To do that, the visible section of your homepage (above the fold) needs to be simple and straightforward. For examp;le, use pictures of your work, screenshots of your app, a short and catchy hook.
+ To do that, the visible section of your homepage (above the fold) needs to be simple and straightforward. For example, use pictures of your work, screenshots of your app, a short and catchy hook.
The Banner or Big Picture building blocks are good choices for that.
@@ -299,7 +302,7 @@
paragraphs easy to read and avoid walls of text.
- For examp;le, use pictures to help break up large areas of text by altering
+ For example, use pictures to help break up large areas of text by altering
Text-Image and Image-Text blocks. If you prefer icons, use the Features or Feature Grid blocks.
@@ -406,10 +409,9 @@
Your Footer
- Your visitors won't see the footer immediately. Use it for links you don't want in your main menu (e.g. social media, terms and conditions, privacy
- terms, etc.).
+ Your visitors won't see the footer immediately. Use it for links you don't want in your main menu (e.g. social media, terms and conditions, privacy terms, etc.).
Community & Enterprise users: apply a redirection from your Domain Manager platform
@@ -565,7 +574,7 @@
Promote
It’s time to grow your traffic!
- One way is by optimizing your indexing on search engines like Google naturally. The earliest you show up in the search, the more visitors you get. This strategy called SEO involves several actions.
+ One way is by optimizing your indexing on search engines like Google naturally, without paying anything. The earliest you show up in the search, the more visitors you get. This strategy called SEO involves several actions.
@@ -573,7 +582,7 @@
Use relevant keywords
- Adding relevant and popular keywords (e.g. business name, location) tends to improve your ranking in search engines and consequently increases your traffic. Do it:
+ Adding relevant and popular keywords (e.g. business name, location) tends to improve your ranking in search engines and consequently increases your traffic. Do it:
through the content of your pages;
in their SEO metadata, including tags, title and description.
@@ -587,7 +596,7 @@
If you are an artist or a photographer, you can potentially bring in a lot
of visitors by referencing your images so they are displayed in image
search engines, like Google Images.
- To do that, add keywords in picture's description.
+ To do that, add keywords in picture's description.
@@ -634,7 +643,7 @@
You can also pay for a sponsored indexing and place advertisements on web pages that show results from search
- engine queries. This is called SEA.
+ engine queries. This is called SEA.
@@ -662,91 +671,6 @@
-
- A/B Testing
-
- A/B testing is the process of testing two versions of a page to see which one performs better in reaching your business objectives.
-
-
Here is a basic guide for your first A/B testing:
-
-
-
-
-
1. Define what to test
- The main goal is increasing your ROI. Figure out the best page(s) to
- test. Here are a few examples of good testing variables:
-
-
Call-to-action’s (i.e. button’s) wording, size, color and placement,
4. Create your campaign in Google Analytics
- Simply follow the wizard by creating a new experiment in the Behavior >
- Experiments menu of Google Analytics.
- To learn more, take a look at their online help.
-
-
-
-
-
-
-
Good practices
-
Bad practices
-
-
-
-
Know how long to run a test before giving up
- Don't give up too early! Wait for your test results to be significant. Take a look at the statistical
- confidence in Google Analytics; It should be at least 95%.
- Don't give up too late neither because poorly performing variations could cost you revenues.
-
Don't test versions at different time periods If you
- test one version one week and the second the next one, your results won't be
- accurate, or worse, wrong!
-
-
-
Do many A/B tests
- Don't despair if your first A/B test turns out to be a lemon. The key in optimizing conversion rates is to do a ton of A/B in order to put together all the most effective configurations.
-
Don’t surprise regular visitors
- If you are testing a core part of your website, include only new visitors in
- the test. You want to avoid shocking regular visitors, especially because the
- variations may not ultimately be implemented.
-
-
-
Test only one variable Try only one variable at a time, otherwise you won't be able to clearly interpret the results of your modifications.
- Your website is an important part of your online business strategy, but it shouldn't be
- the only one. There are so many ways to communicate with your customers, visitors and
+ There are so many ways to communicate with your customers, visitors and
prospects that it's sometimes difficult to know what to put your energy into. Here are
- some advice on what to focus on next.
+ some advices on what to focus on next.
-
-
-
Use contact forms
-
Get your opportunities filled up automatically in our integrated CRM application
-
Qualify your visitors better in order to reach them later with marketing campaigns
diff --git a/addons/website_sale/controllers/main.py b/addons/website_sale/controllers/main.py
index ab98a1dcb0b..1c4123a8893 100644
--- a/addons/website_sale/controllers/main.py
+++ b/addons/website_sale/controllers/main.py
@@ -902,6 +902,11 @@ class WebsiteSale(http.Controller):
return request.redirect('/shop/confirmation')
+
+ @http.route(['/shop/terms'], type='http', auth="public", website=True)
+ def terms(self, **kw):
+ return request.render("website_sale.terms")
+
@http.route(['/shop/confirmation'], type='http', auth="public", website=True)
def payment_confirmation(self, **post):
""" End of checkout process controller. Confirmation is basically seing
diff --git a/addons/website_sale/data/web_planner_data.xml b/addons/website_sale/data/web_planner_data.xml
index fd6be83f501..c67fd50e0a6 100644
--- a/addons/website_sale/data/web_planner_data.xml
+++ b/addons/website_sale/data/web_planner_data.xml
@@ -5,15 +5,81 @@
Sell
+
+ Your Company
+
+ The first step is to set up your company's information. This is used in several places: Contact us page, website header & footer, printed business documents like orders and invoices, etc.
+
Reassurance arguments
- Anticipate your customers questions & worries on practical details like shipping rates & policies, return & replacement policies, payment methods & security and your product's availability (In Stock, Not Available, etc.).
+ Anticipate your customers questions & worries on practical details like shipping rates & policies, return & replacement policies, payment methods & security and your product's availability (In Stock, Not Available, etc.).
+
+
+ The last step in setting up your products is configuring the taxes. Taxes are already predefined for most localizations when it comes to regional transactions. However taxes may be specific to customer kinds and localizations. Take some time to check the following parameters:
+
+
+
+
+
+
+ Origin-based vs. destination-based
+
+
+
+
+
Depending on your state or country, you are required to collect sales taxes with either the rate at buyer’s address (destination-based) or the rate effective at your office or warehouse's address (origin-based).
+
+
+ Included vs. excluded in product prices
+
+
+
+
+
+ In North America, prices are shown tax-excluded whatever your business is (default mode in Odoo). In most other countries, only B2B prices are tax-exluded; B2C prices being tax-included.
+
+ Make sure your customers can go through the shopping process in a very short time, otherwise they will leave your website. Here are some actions to tailor the process to your business.
Add a step to request some extra customer data (picking preferences, etc.)
+
+
+
+ Everything is editable in your Odoo website. Feel free to edit any page title, field or button label. Simply hit *Edit* in upper-right corner to start editing the page.
+
+
+
+
+
+
+
+
Delivery Strategy
@@ -117,7 +359,6 @@
Free delivery
- Advised if both cart content and shipping costs are homogeneous
The Intellectual Property disclosure will inform users that the contents, logo and other visual media you created is your property and is protected by copyright laws.
+
A Termination clause will inform that users’ accounts on your website and mobile app or users’ access to your website and mobile (if users can’t have an account with you) can be terminated in case of abuses or at your sole discretion.
+
A Governing Law will inform users which laws govern the agreement. This should the country in which your company is headquartered or the country from which you operate your web site and mobile app.
+
A Links To Other Web Sites clause will inform users that you are not responsible for any third party web sites that you link to. This kind of clause will generally inform users that they are responsible for reading and agreeing (or disagreeing) with the Terms and Conditions or Privacy Policies of these third parties.
+
If your website or mobile apps allows users to create content and make that content public to other users, a Content section will inform users that they own the rights to the content they have created. The “Content” clause usually mentions that users must give you (the website or mobile app developer) a license so that you can share this content on your website/mobile app and to make it available to other users. Because the content created by users is public to other users, a DMCA notice clause (or Copyright Infringement ) section is helpful to inform users and copyright authors that, if any content is found to be a copyright infringement, you will respond to any DMCA take down notices received and you will take down the content.
+
A Limit What Users Can Do clause can inform users that by agreeing to use your service, they’re also agreeing to not do certain things. This can be part of a very long and thorough list in your Terms and Conditions agreements so as to encompass the most amount of negative uses.
diff --git a/doc/_extensions/odoo/__init__.py b/doc/_extensions/odoo_ext/__init__.py
similarity index 98%
rename from doc/_extensions/odoo/__init__.py
rename to doc/_extensions/odoo_ext/__init__.py
index bb0cac5588f..0ec55620497 100644
--- a/doc/_extensions/odoo/__init__.py
+++ b/doc/_extensions/odoo_ext/__init__.py
@@ -11,7 +11,7 @@ def setup(app):
if getattr(app.config, 'html_translator_class', None):
app.warn("Overriding the explicitly set html_translator_class setting",
location="odoo extension")
- app.config.html_translator_class = 'odoo.translator.BootstrapTranslator'
+ app.config.html_translator_class = 'odoo_ext.translator.BootstrapTranslator'
switcher.setup(app)
app.add_config_value('odoo_cover_default', None, 'env')
diff --git a/doc/_extensions/odoo/breadcrumb_list.html b/doc/_extensions/odoo_ext/breadcrumb_list.html
similarity index 100%
rename from doc/_extensions/odoo/breadcrumb_list.html
rename to doc/_extensions/odoo_ext/breadcrumb_list.html
diff --git a/doc/_extensions/odoo/layout.html b/doc/_extensions/odoo_ext/layout.html
similarity index 100%
rename from doc/_extensions/odoo/layout.html
rename to doc/_extensions/odoo_ext/layout.html
diff --git a/doc/_extensions/odoo/pygments_override.py b/doc/_extensions/odoo_ext/pygments_override.py
similarity index 100%
rename from doc/_extensions/odoo/pygments_override.py
rename to doc/_extensions/odoo_ext/pygments_override.py
diff --git a/doc/_extensions/odoo/static/animations.less b/doc/_extensions/odoo_ext/static/animations.less
similarity index 100%
rename from doc/_extensions/odoo/static/animations.less
rename to doc/_extensions/odoo_ext/static/animations.less
diff --git a/doc/_extensions/odoo/static/aside.less b/doc/_extensions/odoo_ext/static/aside.less
similarity index 100%
rename from doc/_extensions/odoo/static/aside.less
rename to doc/_extensions/odoo_ext/static/aside.less
diff --git a/doc/_extensions/odoo/static/bootstrap-3.3.6/less/alerts.less b/doc/_extensions/odoo_ext/static/bootstrap-3.3.6/less/alerts.less
similarity index 100%
rename from doc/_extensions/odoo/static/bootstrap-3.3.6/less/alerts.less
rename to doc/_extensions/odoo_ext/static/bootstrap-3.3.6/less/alerts.less
diff --git a/doc/_extensions/odoo/static/bootstrap-3.3.6/less/badges.less b/doc/_extensions/odoo_ext/static/bootstrap-3.3.6/less/badges.less
similarity index 100%
rename from doc/_extensions/odoo/static/bootstrap-3.3.6/less/badges.less
rename to doc/_extensions/odoo_ext/static/bootstrap-3.3.6/less/badges.less
diff --git a/doc/_extensions/odoo/static/bootstrap-3.3.6/less/bootstrap.less b/doc/_extensions/odoo_ext/static/bootstrap-3.3.6/less/bootstrap.less
similarity index 100%
rename from doc/_extensions/odoo/static/bootstrap-3.3.6/less/bootstrap.less
rename to doc/_extensions/odoo_ext/static/bootstrap-3.3.6/less/bootstrap.less
diff --git a/doc/_extensions/odoo/static/bootstrap-3.3.6/less/breadcrumbs.less b/doc/_extensions/odoo_ext/static/bootstrap-3.3.6/less/breadcrumbs.less
similarity index 100%
rename from doc/_extensions/odoo/static/bootstrap-3.3.6/less/breadcrumbs.less
rename to doc/_extensions/odoo_ext/static/bootstrap-3.3.6/less/breadcrumbs.less
diff --git a/doc/_extensions/odoo/static/bootstrap-3.3.6/less/button-groups.less b/doc/_extensions/odoo_ext/static/bootstrap-3.3.6/less/button-groups.less
similarity index 100%
rename from doc/_extensions/odoo/static/bootstrap-3.3.6/less/button-groups.less
rename to doc/_extensions/odoo_ext/static/bootstrap-3.3.6/less/button-groups.less
diff --git a/doc/_extensions/odoo/static/bootstrap-3.3.6/less/buttons.less b/doc/_extensions/odoo_ext/static/bootstrap-3.3.6/less/buttons.less
similarity index 100%
rename from doc/_extensions/odoo/static/bootstrap-3.3.6/less/buttons.less
rename to doc/_extensions/odoo_ext/static/bootstrap-3.3.6/less/buttons.less
diff --git a/doc/_extensions/odoo/static/bootstrap-3.3.6/less/carousel.less b/doc/_extensions/odoo_ext/static/bootstrap-3.3.6/less/carousel.less
similarity index 100%
rename from doc/_extensions/odoo/static/bootstrap-3.3.6/less/carousel.less
rename to doc/_extensions/odoo_ext/static/bootstrap-3.3.6/less/carousel.less
diff --git a/doc/_extensions/odoo/static/bootstrap-3.3.6/less/close.less b/doc/_extensions/odoo_ext/static/bootstrap-3.3.6/less/close.less
similarity index 100%
rename from doc/_extensions/odoo/static/bootstrap-3.3.6/less/close.less
rename to doc/_extensions/odoo_ext/static/bootstrap-3.3.6/less/close.less
diff --git a/doc/_extensions/odoo/static/bootstrap-3.3.6/less/code.less b/doc/_extensions/odoo_ext/static/bootstrap-3.3.6/less/code.less
similarity index 100%
rename from doc/_extensions/odoo/static/bootstrap-3.3.6/less/code.less
rename to doc/_extensions/odoo_ext/static/bootstrap-3.3.6/less/code.less
diff --git a/doc/_extensions/odoo/static/bootstrap-3.3.6/less/component-animations.less b/doc/_extensions/odoo_ext/static/bootstrap-3.3.6/less/component-animations.less
similarity index 100%
rename from doc/_extensions/odoo/static/bootstrap-3.3.6/less/component-animations.less
rename to doc/_extensions/odoo_ext/static/bootstrap-3.3.6/less/component-animations.less
diff --git a/doc/_extensions/odoo/static/bootstrap-3.3.6/less/dropdowns.less b/doc/_extensions/odoo_ext/static/bootstrap-3.3.6/less/dropdowns.less
similarity index 100%
rename from doc/_extensions/odoo/static/bootstrap-3.3.6/less/dropdowns.less
rename to doc/_extensions/odoo_ext/static/bootstrap-3.3.6/less/dropdowns.less
diff --git a/doc/_extensions/odoo/static/bootstrap-3.3.6/less/forms.less b/doc/_extensions/odoo_ext/static/bootstrap-3.3.6/less/forms.less
similarity index 100%
rename from doc/_extensions/odoo/static/bootstrap-3.3.6/less/forms.less
rename to doc/_extensions/odoo_ext/static/bootstrap-3.3.6/less/forms.less
diff --git a/doc/_extensions/odoo/static/bootstrap-3.3.6/less/glyphicons.less b/doc/_extensions/odoo_ext/static/bootstrap-3.3.6/less/glyphicons.less
similarity index 100%
rename from doc/_extensions/odoo/static/bootstrap-3.3.6/less/glyphicons.less
rename to doc/_extensions/odoo_ext/static/bootstrap-3.3.6/less/glyphicons.less
diff --git a/doc/_extensions/odoo/static/bootstrap-3.3.6/less/grid.less b/doc/_extensions/odoo_ext/static/bootstrap-3.3.6/less/grid.less
similarity index 100%
rename from doc/_extensions/odoo/static/bootstrap-3.3.6/less/grid.less
rename to doc/_extensions/odoo_ext/static/bootstrap-3.3.6/less/grid.less
diff --git a/doc/_extensions/odoo/static/bootstrap-3.3.6/less/input-groups.less b/doc/_extensions/odoo_ext/static/bootstrap-3.3.6/less/input-groups.less
similarity index 100%
rename from doc/_extensions/odoo/static/bootstrap-3.3.6/less/input-groups.less
rename to doc/_extensions/odoo_ext/static/bootstrap-3.3.6/less/input-groups.less
diff --git a/doc/_extensions/odoo/static/bootstrap-3.3.6/less/jumbotron.less b/doc/_extensions/odoo_ext/static/bootstrap-3.3.6/less/jumbotron.less
similarity index 100%
rename from doc/_extensions/odoo/static/bootstrap-3.3.6/less/jumbotron.less
rename to doc/_extensions/odoo_ext/static/bootstrap-3.3.6/less/jumbotron.less
diff --git a/doc/_extensions/odoo/static/bootstrap-3.3.6/less/labels.less b/doc/_extensions/odoo_ext/static/bootstrap-3.3.6/less/labels.less
similarity index 100%
rename from doc/_extensions/odoo/static/bootstrap-3.3.6/less/labels.less
rename to doc/_extensions/odoo_ext/static/bootstrap-3.3.6/less/labels.less
diff --git a/doc/_extensions/odoo/static/bootstrap-3.3.6/less/list-group.less b/doc/_extensions/odoo_ext/static/bootstrap-3.3.6/less/list-group.less
similarity index 100%
rename from doc/_extensions/odoo/static/bootstrap-3.3.6/less/list-group.less
rename to doc/_extensions/odoo_ext/static/bootstrap-3.3.6/less/list-group.less
diff --git a/doc/_extensions/odoo/static/bootstrap-3.3.6/less/media.less b/doc/_extensions/odoo_ext/static/bootstrap-3.3.6/less/media.less
similarity index 100%
rename from doc/_extensions/odoo/static/bootstrap-3.3.6/less/media.less
rename to doc/_extensions/odoo_ext/static/bootstrap-3.3.6/less/media.less
diff --git a/doc/_extensions/odoo/static/bootstrap-3.3.6/less/mixins.less b/doc/_extensions/odoo_ext/static/bootstrap-3.3.6/less/mixins.less
similarity index 100%
rename from doc/_extensions/odoo/static/bootstrap-3.3.6/less/mixins.less
rename to doc/_extensions/odoo_ext/static/bootstrap-3.3.6/less/mixins.less
diff --git a/doc/_extensions/odoo/static/bootstrap-3.3.6/less/mixins/alerts.less b/doc/_extensions/odoo_ext/static/bootstrap-3.3.6/less/mixins/alerts.less
similarity index 100%
rename from doc/_extensions/odoo/static/bootstrap-3.3.6/less/mixins/alerts.less
rename to doc/_extensions/odoo_ext/static/bootstrap-3.3.6/less/mixins/alerts.less
diff --git a/doc/_extensions/odoo/static/bootstrap-3.3.6/less/mixins/background-variant.less b/doc/_extensions/odoo_ext/static/bootstrap-3.3.6/less/mixins/background-variant.less
similarity index 100%
rename from doc/_extensions/odoo/static/bootstrap-3.3.6/less/mixins/background-variant.less
rename to doc/_extensions/odoo_ext/static/bootstrap-3.3.6/less/mixins/background-variant.less
diff --git a/doc/_extensions/odoo/static/bootstrap-3.3.6/less/mixins/border-radius.less b/doc/_extensions/odoo_ext/static/bootstrap-3.3.6/less/mixins/border-radius.less
similarity index 100%
rename from doc/_extensions/odoo/static/bootstrap-3.3.6/less/mixins/border-radius.less
rename to doc/_extensions/odoo_ext/static/bootstrap-3.3.6/less/mixins/border-radius.less
diff --git a/doc/_extensions/odoo/static/bootstrap-3.3.6/less/mixins/buttons.less b/doc/_extensions/odoo_ext/static/bootstrap-3.3.6/less/mixins/buttons.less
similarity index 100%
rename from doc/_extensions/odoo/static/bootstrap-3.3.6/less/mixins/buttons.less
rename to doc/_extensions/odoo_ext/static/bootstrap-3.3.6/less/mixins/buttons.less
diff --git a/doc/_extensions/odoo/static/bootstrap-3.3.6/less/mixins/center-block.less b/doc/_extensions/odoo_ext/static/bootstrap-3.3.6/less/mixins/center-block.less
similarity index 100%
rename from doc/_extensions/odoo/static/bootstrap-3.3.6/less/mixins/center-block.less
rename to doc/_extensions/odoo_ext/static/bootstrap-3.3.6/less/mixins/center-block.less
diff --git a/doc/_extensions/odoo/static/bootstrap-3.3.6/less/mixins/clearfix.less b/doc/_extensions/odoo_ext/static/bootstrap-3.3.6/less/mixins/clearfix.less
similarity index 100%
rename from doc/_extensions/odoo/static/bootstrap-3.3.6/less/mixins/clearfix.less
rename to doc/_extensions/odoo_ext/static/bootstrap-3.3.6/less/mixins/clearfix.less
diff --git a/doc/_extensions/odoo/static/bootstrap-3.3.6/less/mixins/forms.less b/doc/_extensions/odoo_ext/static/bootstrap-3.3.6/less/mixins/forms.less
similarity index 100%
rename from doc/_extensions/odoo/static/bootstrap-3.3.6/less/mixins/forms.less
rename to doc/_extensions/odoo_ext/static/bootstrap-3.3.6/less/mixins/forms.less
diff --git a/doc/_extensions/odoo/static/bootstrap-3.3.6/less/mixins/gradients.less b/doc/_extensions/odoo_ext/static/bootstrap-3.3.6/less/mixins/gradients.less
similarity index 100%
rename from doc/_extensions/odoo/static/bootstrap-3.3.6/less/mixins/gradients.less
rename to doc/_extensions/odoo_ext/static/bootstrap-3.3.6/less/mixins/gradients.less
diff --git a/doc/_extensions/odoo/static/bootstrap-3.3.6/less/mixins/grid-framework.less b/doc/_extensions/odoo_ext/static/bootstrap-3.3.6/less/mixins/grid-framework.less
similarity index 100%
rename from doc/_extensions/odoo/static/bootstrap-3.3.6/less/mixins/grid-framework.less
rename to doc/_extensions/odoo_ext/static/bootstrap-3.3.6/less/mixins/grid-framework.less
diff --git a/doc/_extensions/odoo/static/bootstrap-3.3.6/less/mixins/grid.less b/doc/_extensions/odoo_ext/static/bootstrap-3.3.6/less/mixins/grid.less
similarity index 100%
rename from doc/_extensions/odoo/static/bootstrap-3.3.6/less/mixins/grid.less
rename to doc/_extensions/odoo_ext/static/bootstrap-3.3.6/less/mixins/grid.less
diff --git a/doc/_extensions/odoo/static/bootstrap-3.3.6/less/mixins/hide-text.less b/doc/_extensions/odoo_ext/static/bootstrap-3.3.6/less/mixins/hide-text.less
similarity index 100%
rename from doc/_extensions/odoo/static/bootstrap-3.3.6/less/mixins/hide-text.less
rename to doc/_extensions/odoo_ext/static/bootstrap-3.3.6/less/mixins/hide-text.less
diff --git a/doc/_extensions/odoo/static/bootstrap-3.3.6/less/mixins/image.less b/doc/_extensions/odoo_ext/static/bootstrap-3.3.6/less/mixins/image.less
similarity index 100%
rename from doc/_extensions/odoo/static/bootstrap-3.3.6/less/mixins/image.less
rename to doc/_extensions/odoo_ext/static/bootstrap-3.3.6/less/mixins/image.less
diff --git a/doc/_extensions/odoo/static/bootstrap-3.3.6/less/mixins/labels.less b/doc/_extensions/odoo_ext/static/bootstrap-3.3.6/less/mixins/labels.less
similarity index 100%
rename from doc/_extensions/odoo/static/bootstrap-3.3.6/less/mixins/labels.less
rename to doc/_extensions/odoo_ext/static/bootstrap-3.3.6/less/mixins/labels.less
diff --git a/doc/_extensions/odoo/static/bootstrap-3.3.6/less/mixins/list-group.less b/doc/_extensions/odoo_ext/static/bootstrap-3.3.6/less/mixins/list-group.less
similarity index 100%
rename from doc/_extensions/odoo/static/bootstrap-3.3.6/less/mixins/list-group.less
rename to doc/_extensions/odoo_ext/static/bootstrap-3.3.6/less/mixins/list-group.less
diff --git a/doc/_extensions/odoo/static/bootstrap-3.3.6/less/mixins/nav-divider.less b/doc/_extensions/odoo_ext/static/bootstrap-3.3.6/less/mixins/nav-divider.less
similarity index 100%
rename from doc/_extensions/odoo/static/bootstrap-3.3.6/less/mixins/nav-divider.less
rename to doc/_extensions/odoo_ext/static/bootstrap-3.3.6/less/mixins/nav-divider.less
diff --git a/doc/_extensions/odoo/static/bootstrap-3.3.6/less/mixins/nav-vertical-align.less b/doc/_extensions/odoo_ext/static/bootstrap-3.3.6/less/mixins/nav-vertical-align.less
similarity index 100%
rename from doc/_extensions/odoo/static/bootstrap-3.3.6/less/mixins/nav-vertical-align.less
rename to doc/_extensions/odoo_ext/static/bootstrap-3.3.6/less/mixins/nav-vertical-align.less
diff --git a/doc/_extensions/odoo/static/bootstrap-3.3.6/less/mixins/opacity.less b/doc/_extensions/odoo_ext/static/bootstrap-3.3.6/less/mixins/opacity.less
similarity index 100%
rename from doc/_extensions/odoo/static/bootstrap-3.3.6/less/mixins/opacity.less
rename to doc/_extensions/odoo_ext/static/bootstrap-3.3.6/less/mixins/opacity.less
diff --git a/doc/_extensions/odoo/static/bootstrap-3.3.6/less/mixins/pagination.less b/doc/_extensions/odoo_ext/static/bootstrap-3.3.6/less/mixins/pagination.less
similarity index 100%
rename from doc/_extensions/odoo/static/bootstrap-3.3.6/less/mixins/pagination.less
rename to doc/_extensions/odoo_ext/static/bootstrap-3.3.6/less/mixins/pagination.less
diff --git a/doc/_extensions/odoo/static/bootstrap-3.3.6/less/mixins/panels.less b/doc/_extensions/odoo_ext/static/bootstrap-3.3.6/less/mixins/panels.less
similarity index 100%
rename from doc/_extensions/odoo/static/bootstrap-3.3.6/less/mixins/panels.less
rename to doc/_extensions/odoo_ext/static/bootstrap-3.3.6/less/mixins/panels.less
diff --git a/doc/_extensions/odoo/static/bootstrap-3.3.6/less/mixins/progress-bar.less b/doc/_extensions/odoo_ext/static/bootstrap-3.3.6/less/mixins/progress-bar.less
similarity index 100%
rename from doc/_extensions/odoo/static/bootstrap-3.3.6/less/mixins/progress-bar.less
rename to doc/_extensions/odoo_ext/static/bootstrap-3.3.6/less/mixins/progress-bar.less
diff --git a/doc/_extensions/odoo/static/bootstrap-3.3.6/less/mixins/reset-filter.less b/doc/_extensions/odoo_ext/static/bootstrap-3.3.6/less/mixins/reset-filter.less
similarity index 100%
rename from doc/_extensions/odoo/static/bootstrap-3.3.6/less/mixins/reset-filter.less
rename to doc/_extensions/odoo_ext/static/bootstrap-3.3.6/less/mixins/reset-filter.less
diff --git a/doc/_extensions/odoo/static/bootstrap-3.3.6/less/mixins/reset-text.less b/doc/_extensions/odoo_ext/static/bootstrap-3.3.6/less/mixins/reset-text.less
similarity index 100%
rename from doc/_extensions/odoo/static/bootstrap-3.3.6/less/mixins/reset-text.less
rename to doc/_extensions/odoo_ext/static/bootstrap-3.3.6/less/mixins/reset-text.less
diff --git a/doc/_extensions/odoo/static/bootstrap-3.3.6/less/mixins/resize.less b/doc/_extensions/odoo_ext/static/bootstrap-3.3.6/less/mixins/resize.less
similarity index 100%
rename from doc/_extensions/odoo/static/bootstrap-3.3.6/less/mixins/resize.less
rename to doc/_extensions/odoo_ext/static/bootstrap-3.3.6/less/mixins/resize.less
diff --git a/doc/_extensions/odoo/static/bootstrap-3.3.6/less/mixins/responsive-visibility.less b/doc/_extensions/odoo_ext/static/bootstrap-3.3.6/less/mixins/responsive-visibility.less
similarity index 100%
rename from doc/_extensions/odoo/static/bootstrap-3.3.6/less/mixins/responsive-visibility.less
rename to doc/_extensions/odoo_ext/static/bootstrap-3.3.6/less/mixins/responsive-visibility.less
diff --git a/doc/_extensions/odoo/static/bootstrap-3.3.6/less/mixins/size.less b/doc/_extensions/odoo_ext/static/bootstrap-3.3.6/less/mixins/size.less
similarity index 100%
rename from doc/_extensions/odoo/static/bootstrap-3.3.6/less/mixins/size.less
rename to doc/_extensions/odoo_ext/static/bootstrap-3.3.6/less/mixins/size.less
diff --git a/doc/_extensions/odoo/static/bootstrap-3.3.6/less/mixins/tab-focus.less b/doc/_extensions/odoo_ext/static/bootstrap-3.3.6/less/mixins/tab-focus.less
similarity index 100%
rename from doc/_extensions/odoo/static/bootstrap-3.3.6/less/mixins/tab-focus.less
rename to doc/_extensions/odoo_ext/static/bootstrap-3.3.6/less/mixins/tab-focus.less
diff --git a/doc/_extensions/odoo/static/bootstrap-3.3.6/less/mixins/table-row.less b/doc/_extensions/odoo_ext/static/bootstrap-3.3.6/less/mixins/table-row.less
similarity index 100%
rename from doc/_extensions/odoo/static/bootstrap-3.3.6/less/mixins/table-row.less
rename to doc/_extensions/odoo_ext/static/bootstrap-3.3.6/less/mixins/table-row.less
diff --git a/doc/_extensions/odoo/static/bootstrap-3.3.6/less/mixins/text-emphasis.less b/doc/_extensions/odoo_ext/static/bootstrap-3.3.6/less/mixins/text-emphasis.less
similarity index 100%
rename from doc/_extensions/odoo/static/bootstrap-3.3.6/less/mixins/text-emphasis.less
rename to doc/_extensions/odoo_ext/static/bootstrap-3.3.6/less/mixins/text-emphasis.less
diff --git a/doc/_extensions/odoo/static/bootstrap-3.3.6/less/mixins/text-overflow.less b/doc/_extensions/odoo_ext/static/bootstrap-3.3.6/less/mixins/text-overflow.less
similarity index 100%
rename from doc/_extensions/odoo/static/bootstrap-3.3.6/less/mixins/text-overflow.less
rename to doc/_extensions/odoo_ext/static/bootstrap-3.3.6/less/mixins/text-overflow.less
diff --git a/doc/_extensions/odoo/static/bootstrap-3.3.6/less/mixins/vendor-prefixes.less b/doc/_extensions/odoo_ext/static/bootstrap-3.3.6/less/mixins/vendor-prefixes.less
similarity index 100%
rename from doc/_extensions/odoo/static/bootstrap-3.3.6/less/mixins/vendor-prefixes.less
rename to doc/_extensions/odoo_ext/static/bootstrap-3.3.6/less/mixins/vendor-prefixes.less
diff --git a/doc/_extensions/odoo/static/bootstrap-3.3.6/less/modals.less b/doc/_extensions/odoo_ext/static/bootstrap-3.3.6/less/modals.less
similarity index 100%
rename from doc/_extensions/odoo/static/bootstrap-3.3.6/less/modals.less
rename to doc/_extensions/odoo_ext/static/bootstrap-3.3.6/less/modals.less
diff --git a/doc/_extensions/odoo/static/bootstrap-3.3.6/less/navbar.less b/doc/_extensions/odoo_ext/static/bootstrap-3.3.6/less/navbar.less
similarity index 100%
rename from doc/_extensions/odoo/static/bootstrap-3.3.6/less/navbar.less
rename to doc/_extensions/odoo_ext/static/bootstrap-3.3.6/less/navbar.less
diff --git a/doc/_extensions/odoo/static/bootstrap-3.3.6/less/navs.less b/doc/_extensions/odoo_ext/static/bootstrap-3.3.6/less/navs.less
similarity index 100%
rename from doc/_extensions/odoo/static/bootstrap-3.3.6/less/navs.less
rename to doc/_extensions/odoo_ext/static/bootstrap-3.3.6/less/navs.less
diff --git a/doc/_extensions/odoo/static/bootstrap-3.3.6/less/normalize.less b/doc/_extensions/odoo_ext/static/bootstrap-3.3.6/less/normalize.less
similarity index 100%
rename from doc/_extensions/odoo/static/bootstrap-3.3.6/less/normalize.less
rename to doc/_extensions/odoo_ext/static/bootstrap-3.3.6/less/normalize.less
diff --git a/doc/_extensions/odoo/static/bootstrap-3.3.6/less/pager.less b/doc/_extensions/odoo_ext/static/bootstrap-3.3.6/less/pager.less
similarity index 100%
rename from doc/_extensions/odoo/static/bootstrap-3.3.6/less/pager.less
rename to doc/_extensions/odoo_ext/static/bootstrap-3.3.6/less/pager.less
diff --git a/doc/_extensions/odoo/static/bootstrap-3.3.6/less/pagination.less b/doc/_extensions/odoo_ext/static/bootstrap-3.3.6/less/pagination.less
similarity index 100%
rename from doc/_extensions/odoo/static/bootstrap-3.3.6/less/pagination.less
rename to doc/_extensions/odoo_ext/static/bootstrap-3.3.6/less/pagination.less
diff --git a/doc/_extensions/odoo/static/bootstrap-3.3.6/less/panels.less b/doc/_extensions/odoo_ext/static/bootstrap-3.3.6/less/panels.less
similarity index 100%
rename from doc/_extensions/odoo/static/bootstrap-3.3.6/less/panels.less
rename to doc/_extensions/odoo_ext/static/bootstrap-3.3.6/less/panels.less
diff --git a/doc/_extensions/odoo/static/bootstrap-3.3.6/less/popovers.less b/doc/_extensions/odoo_ext/static/bootstrap-3.3.6/less/popovers.less
similarity index 100%
rename from doc/_extensions/odoo/static/bootstrap-3.3.6/less/popovers.less
rename to doc/_extensions/odoo_ext/static/bootstrap-3.3.6/less/popovers.less
diff --git a/doc/_extensions/odoo/static/bootstrap-3.3.6/less/print.less b/doc/_extensions/odoo_ext/static/bootstrap-3.3.6/less/print.less
similarity index 100%
rename from doc/_extensions/odoo/static/bootstrap-3.3.6/less/print.less
rename to doc/_extensions/odoo_ext/static/bootstrap-3.3.6/less/print.less
diff --git a/doc/_extensions/odoo/static/bootstrap-3.3.6/less/progress-bars.less b/doc/_extensions/odoo_ext/static/bootstrap-3.3.6/less/progress-bars.less
similarity index 100%
rename from doc/_extensions/odoo/static/bootstrap-3.3.6/less/progress-bars.less
rename to doc/_extensions/odoo_ext/static/bootstrap-3.3.6/less/progress-bars.less
diff --git a/doc/_extensions/odoo/static/bootstrap-3.3.6/less/responsive-embed.less b/doc/_extensions/odoo_ext/static/bootstrap-3.3.6/less/responsive-embed.less
similarity index 100%
rename from doc/_extensions/odoo/static/bootstrap-3.3.6/less/responsive-embed.less
rename to doc/_extensions/odoo_ext/static/bootstrap-3.3.6/less/responsive-embed.less
diff --git a/doc/_extensions/odoo/static/bootstrap-3.3.6/less/responsive-utilities.less b/doc/_extensions/odoo_ext/static/bootstrap-3.3.6/less/responsive-utilities.less
similarity index 100%
rename from doc/_extensions/odoo/static/bootstrap-3.3.6/less/responsive-utilities.less
rename to doc/_extensions/odoo_ext/static/bootstrap-3.3.6/less/responsive-utilities.less
diff --git a/doc/_extensions/odoo/static/bootstrap-3.3.6/less/scaffolding.less b/doc/_extensions/odoo_ext/static/bootstrap-3.3.6/less/scaffolding.less
similarity index 100%
rename from doc/_extensions/odoo/static/bootstrap-3.3.6/less/scaffolding.less
rename to doc/_extensions/odoo_ext/static/bootstrap-3.3.6/less/scaffolding.less
diff --git a/doc/_extensions/odoo/static/bootstrap-3.3.6/less/tables.less b/doc/_extensions/odoo_ext/static/bootstrap-3.3.6/less/tables.less
similarity index 100%
rename from doc/_extensions/odoo/static/bootstrap-3.3.6/less/tables.less
rename to doc/_extensions/odoo_ext/static/bootstrap-3.3.6/less/tables.less
diff --git a/doc/_extensions/odoo/static/bootstrap-3.3.6/less/theme.less b/doc/_extensions/odoo_ext/static/bootstrap-3.3.6/less/theme.less
similarity index 100%
rename from doc/_extensions/odoo/static/bootstrap-3.3.6/less/theme.less
rename to doc/_extensions/odoo_ext/static/bootstrap-3.3.6/less/theme.less
diff --git a/doc/_extensions/odoo/static/bootstrap-3.3.6/less/thumbnails.less b/doc/_extensions/odoo_ext/static/bootstrap-3.3.6/less/thumbnails.less
similarity index 100%
rename from doc/_extensions/odoo/static/bootstrap-3.3.6/less/thumbnails.less
rename to doc/_extensions/odoo_ext/static/bootstrap-3.3.6/less/thumbnails.less
diff --git a/doc/_extensions/odoo/static/bootstrap-3.3.6/less/tooltip.less b/doc/_extensions/odoo_ext/static/bootstrap-3.3.6/less/tooltip.less
similarity index 100%
rename from doc/_extensions/odoo/static/bootstrap-3.3.6/less/tooltip.less
rename to doc/_extensions/odoo_ext/static/bootstrap-3.3.6/less/tooltip.less
diff --git a/doc/_extensions/odoo/static/bootstrap-3.3.6/less/type.less b/doc/_extensions/odoo_ext/static/bootstrap-3.3.6/less/type.less
similarity index 100%
rename from doc/_extensions/odoo/static/bootstrap-3.3.6/less/type.less
rename to doc/_extensions/odoo_ext/static/bootstrap-3.3.6/less/type.less
diff --git a/doc/_extensions/odoo/static/bootstrap-3.3.6/less/utilities.less b/doc/_extensions/odoo_ext/static/bootstrap-3.3.6/less/utilities.less
similarity index 100%
rename from doc/_extensions/odoo/static/bootstrap-3.3.6/less/utilities.less
rename to doc/_extensions/odoo_ext/static/bootstrap-3.3.6/less/utilities.less
diff --git a/doc/_extensions/odoo/static/bootstrap-3.3.6/less/variables.less b/doc/_extensions/odoo_ext/static/bootstrap-3.3.6/less/variables.less
similarity index 100%
rename from doc/_extensions/odoo/static/bootstrap-3.3.6/less/variables.less
rename to doc/_extensions/odoo_ext/static/bootstrap-3.3.6/less/variables.less
diff --git a/doc/_extensions/odoo/static/bootstrap-3.3.6/less/wells.less b/doc/_extensions/odoo_ext/static/bootstrap-3.3.6/less/wells.less
similarity index 100%
rename from doc/_extensions/odoo/static/bootstrap-3.3.6/less/wells.less
rename to doc/_extensions/odoo_ext/static/bootstrap-3.3.6/less/wells.less
diff --git a/doc/_extensions/odoo/static/bootstrap.css.map b/doc/_extensions/odoo_ext/static/bootstrap.css.map
similarity index 100%
rename from doc/_extensions/odoo/static/bootstrap.css.map
rename to doc/_extensions/odoo_ext/static/bootstrap.css.map
diff --git a/doc/_extensions/odoo/static/bootstrap.js b/doc/_extensions/odoo_ext/static/bootstrap.js
similarity index 100%
rename from doc/_extensions/odoo/static/bootstrap.js
rename to doc/_extensions/odoo_ext/static/bootstrap.js
diff --git a/doc/_extensions/odoo/static/doc.js b/doc/_extensions/odoo_ext/static/doc.js
similarity index 100%
rename from doc/_extensions/odoo/static/doc.js
rename to doc/_extensions/odoo_ext/static/doc.js
diff --git a/doc/_extensions/odoo/static/fonts/Material-Design-Icons.eot b/doc/_extensions/odoo_ext/static/fonts/Material-Design-Icons.eot
similarity index 100%
rename from doc/_extensions/odoo/static/fonts/Material-Design-Icons.eot
rename to doc/_extensions/odoo_ext/static/fonts/Material-Design-Icons.eot
diff --git a/doc/_extensions/odoo/static/fonts/Material-Design-Icons.svg b/doc/_extensions/odoo_ext/static/fonts/Material-Design-Icons.svg
similarity index 100%
rename from doc/_extensions/odoo/static/fonts/Material-Design-Icons.svg
rename to doc/_extensions/odoo_ext/static/fonts/Material-Design-Icons.svg
diff --git a/doc/_extensions/odoo/static/fonts/Material-Design-Icons.ttf b/doc/_extensions/odoo_ext/static/fonts/Material-Design-Icons.ttf
similarity index 100%
rename from doc/_extensions/odoo/static/fonts/Material-Design-Icons.ttf
rename to doc/_extensions/odoo_ext/static/fonts/Material-Design-Icons.ttf
diff --git a/doc/_extensions/odoo/static/fonts/Material-Design-Icons.woff b/doc/_extensions/odoo_ext/static/fonts/Material-Design-Icons.woff
similarity index 100%
rename from doc/_extensions/odoo/static/fonts/Material-Design-Icons.woff
rename to doc/_extensions/odoo_ext/static/fonts/Material-Design-Icons.woff
diff --git a/doc/_extensions/odoo/static/footer.less b/doc/_extensions/odoo_ext/static/footer.less
similarity index 100%
rename from doc/_extensions/odoo/static/footer.less
rename to doc/_extensions/odoo_ext/static/footer.less
diff --git a/doc/_extensions/odoo/static/header.less b/doc/_extensions/odoo_ext/static/header.less
similarity index 100%
rename from doc/_extensions/odoo/static/header.less
rename to doc/_extensions/odoo_ext/static/header.less
diff --git a/doc/_extensions/odoo/static/img/2x_apps_families_s.png b/doc/_extensions/odoo_ext/static/img/2x_apps_families_s.png
similarity index 100%
rename from doc/_extensions/odoo/static/img/2x_apps_families_s.png
rename to doc/_extensions/odoo_ext/static/img/2x_apps_families_s.png
diff --git a/doc/_extensions/odoo/static/img/apps_families_s.png b/doc/_extensions/odoo_ext/static/img/apps_families_s.png
similarity index 100%
rename from doc/_extensions/odoo/static/img/apps_families_s.png
rename to doc/_extensions/odoo_ext/static/img/apps_families_s.png
diff --git a/doc/_extensions/odoo/static/img/banner_bg.png b/doc/_extensions/odoo_ext/static/img/banner_bg.png
similarity index 100%
rename from doc/_extensions/odoo/static/img/banner_bg.png
rename to doc/_extensions/odoo_ext/static/img/banner_bg.png
diff --git a/doc/_extensions/odoo/static/img/geometric_gradient.png b/doc/_extensions/odoo_ext/static/img/geometric_gradient.png
similarity index 100%
rename from doc/_extensions/odoo/static/img/geometric_gradient.png
rename to doc/_extensions/odoo_ext/static/img/geometric_gradient.png
diff --git a/doc/_extensions/odoo/static/img/github-square_32.png b/doc/_extensions/odoo_ext/static/img/github-square_32.png
similarity index 100%
rename from doc/_extensions/odoo/static/img/github-square_32.png
rename to doc/_extensions/odoo_ext/static/img/github-square_32.png
diff --git a/doc/_extensions/odoo/static/img/logos/odoo_logo.png b/doc/_extensions/odoo_ext/static/img/logos/odoo_logo.png
similarity index 100%
rename from doc/_extensions/odoo/static/img/logos/odoo_logo.png
rename to doc/_extensions/odoo_ext/static/img/logos/odoo_logo.png
diff --git a/doc/_extensions/odoo/static/img/logos/odoo_logo.svg b/doc/_extensions/odoo_ext/static/img/logos/odoo_logo.svg
similarity index 100%
rename from doc/_extensions/odoo/static/img/logos/odoo_logo.svg
rename to doc/_extensions/odoo_ext/static/img/logos/odoo_logo.svg
diff --git a/doc/_extensions/odoo/static/img/logos/odoo_logo_small.png b/doc/_extensions/odoo_ext/static/img/logos/odoo_logo_small.png
similarity index 100%
rename from doc/_extensions/odoo/static/img/logos/odoo_logo_small.png
rename to doc/_extensions/odoo_ext/static/img/logos/odoo_logo_small.png
diff --git a/doc/_extensions/odoo/static/img/odoo_logo_rgb.png b/doc/_extensions/odoo_ext/static/img/odoo_logo_rgb.png
similarity index 100%
rename from doc/_extensions/odoo/static/img/odoo_logo_rgb.png
rename to doc/_extensions/odoo_ext/static/img/odoo_logo_rgb.png
diff --git a/doc/_extensions/odoo/static/img/odoo_logo_white.png b/doc/_extensions/odoo_ext/static/img/odoo_logo_white.png
similarity index 100%
rename from doc/_extensions/odoo/static/img/odoo_logo_white.png
rename to doc/_extensions/odoo_ext/static/img/odoo_logo_white.png
diff --git a/doc/_extensions/odoo/static/jquery.min.js b/doc/_extensions/odoo_ext/static/jquery.min.js
similarity index 100%
rename from doc/_extensions/odoo/static/jquery.min.js
rename to doc/_extensions/odoo_ext/static/jquery.min.js
diff --git a/doc/_extensions/odoo/static/jquery.noconflict.js b/doc/_extensions/odoo_ext/static/jquery.noconflict.js
similarity index 100%
rename from doc/_extensions/odoo/static/jquery.noconflict.js
rename to doc/_extensions/odoo_ext/static/jquery.noconflict.js
diff --git a/doc/_extensions/odoo/static/layout.less b/doc/_extensions/odoo_ext/static/layout.less
similarity index 100%
rename from doc/_extensions/odoo/static/layout.less
rename to doc/_extensions/odoo_ext/static/layout.less
diff --git a/doc/_extensions/odoo/static/mdi.less b/doc/_extensions/odoo_ext/static/mdi.less
similarity index 100%
rename from doc/_extensions/odoo/static/mdi.less
rename to doc/_extensions/odoo_ext/static/mdi.less
diff --git a/doc/_extensions/odoo/static/mixins.less b/doc/_extensions/odoo_ext/static/mixins.less
similarity index 100%
rename from doc/_extensions/odoo/static/mixins.less
rename to doc/_extensions/odoo_ext/static/mixins.less
diff --git a/doc/_extensions/odoo/static/print.less b/doc/_extensions/odoo_ext/static/print.less
similarity index 100%
rename from doc/_extensions/odoo/static/print.less
rename to doc/_extensions/odoo_ext/static/print.less
diff --git a/doc/_extensions/odoo/static/style.css b/doc/_extensions/odoo_ext/static/style.css
similarity index 100%
rename from doc/_extensions/odoo/static/style.css
rename to doc/_extensions/odoo_ext/static/style.css
diff --git a/doc/_extensions/odoo/static/style.less b/doc/_extensions/odoo_ext/static/style.less
similarity index 100%
rename from doc/_extensions/odoo/static/style.less
rename to doc/_extensions/odoo_ext/static/style.less
diff --git a/doc/_extensions/odoo/static/typography.less b/doc/_extensions/odoo_ext/static/typography.less
similarity index 100%
rename from doc/_extensions/odoo/static/typography.less
rename to doc/_extensions/odoo_ext/static/typography.less
diff --git a/doc/_extensions/odoo/static/variables.less b/doc/_extensions/odoo_ext/static/variables.less
similarity index 100%
rename from doc/_extensions/odoo/static/variables.less
rename to doc/_extensions/odoo_ext/static/variables.less
diff --git a/doc/_extensions/odoo/sub-menu_list.html b/doc/_extensions/odoo_ext/sub-menu_list.html
similarity index 100%
rename from doc/_extensions/odoo/sub-menu_list.html
rename to doc/_extensions/odoo_ext/sub-menu_list.html
diff --git a/doc/_extensions/odoo/switcher.py b/doc/_extensions/odoo_ext/switcher.py
similarity index 100%
rename from doc/_extensions/odoo/switcher.py
rename to doc/_extensions/odoo_ext/switcher.py
diff --git a/doc/_extensions/odoo/switchers_list.html b/doc/_extensions/odoo_ext/switchers_list.html
similarity index 100%
rename from doc/_extensions/odoo/switchers_list.html
rename to doc/_extensions/odoo_ext/switchers_list.html
diff --git a/doc/_extensions/odoo/theme.conf b/doc/_extensions/odoo_ext/theme.conf
similarity index 100%
rename from doc/_extensions/odoo/theme.conf
rename to doc/_extensions/odoo_ext/theme.conf
diff --git a/doc/_extensions/odoo/translator.py b/doc/_extensions/odoo_ext/translator.py
similarity index 100%
rename from doc/_extensions/odoo/translator.py
rename to doc/_extensions/odoo_ext/translator.py
diff --git a/doc/_static/banners/mixins.jpg b/doc/_static/banners/mixins.jpg
new file mode 100644
index 00000000000..24854d70bd2
Binary files /dev/null and b/doc/_static/banners/mixins.jpg differ
diff --git a/doc/_static/banners/mixins.small.jpg b/doc/_static/banners/mixins.small.jpg
new file mode 100644
index 00000000000..0abe571399e
Binary files /dev/null and b/doc/_static/banners/mixins.small.jpg differ
diff --git a/doc/api_integration.rst b/doc/api_integration.rst
index 172eb0f3fa4..a0f26d39343 100644
--- a/doc/api_integration.rst
+++ b/doc/api_integration.rst
@@ -15,7 +15,7 @@ easily available over XML-RPC_ and accessible from a variety of languages.
.. Odoo XML-RPC idiosyncracies:
* uses multiple endpoint and a nested call syntax instead of a
- "hierarchical" server structure (e.g. ``openerp.res.partner.read()``)
+ "hierarchical" server structure (e.g. ``odoo.res.partner.read()``)
* uses its own own manual auth system instead of basic auth or sessions
(basic is directly supported the Python and Ruby stdlibs as well as
ws-xmlrpc, not sure about ripcord)
@@ -360,9 +360,9 @@ Each call to ``execute_kw`` takes the following parameters:
List records
------------
-Records can be listed and filtered via :meth:`~openerp.models.Model.search`.
+Records can be listed and filtered via :meth:`~odoo.models.Model.search`.
-:meth:`~openerp.models.Model.search` takes a mandatory
+:meth:`~odoo.models.Model.search` takes a mandatory
:ref:`domain ` filter (possibly empty), and returns the
database identifiers of all records matching the filter. To list customer
companies for instance:
@@ -456,10 +456,10 @@ Count records
-------------
Rather than retrieve a possibly gigantic list of records and count them,
-:meth:`~openerp.models.Model.search_count` can be used to retrieve
+:meth:`~odoo.models.Model.search_count` can be used to retrieve
only the number of records matching the query. It takes the same
:ref:`domain ` filter as
-:meth:`~openerp.models.Model.search` and no other parameter.
+:meth:`~odoo.models.Model.search` and no other parameter.
.. container:: doc-aside
@@ -507,9 +507,9 @@ only the number of records matching the query. It takes the same
Read records
------------
-Record data is accessible via the :meth:`~openerp.models.Model.read` method,
+Record data is accessible via the :meth:`~odoo.models.Model.read` method,
which takes a list of ids (as returned by
-:meth:`~openerp.models.Model.search`) and optionally a list of fields to
+:meth:`~odoo.models.Model.search`) and optionally a list of fields to
fetch. By default, it will fetch all the fields the current user can read,
which tends to be a huge amount.
@@ -620,7 +620,7 @@ Conversedly, picking only three fields deemed interesting.
Listing record fields
---------------------
-:meth:`~openerp.models.Model.fields_get` can be used to inspect
+:meth:`~odoo.models.Model.fields_get` can be used to inspect
a model's fields and check which ones seem to be of interest.
Because it returns a large amount of meta-information (it is also used by client
@@ -705,13 +705,13 @@ Search and read
---------------
Because it is a very common task, Odoo provides a
-:meth:`~openerp.models.Model.search_read` shortcut which as its name suggests is
-equivalent to a :meth:`~openerp.models.Model.search` followed by a
-:meth:`~openerp.models.Model.read`, but avoids having to perform two requests
+:meth:`~odoo.models.Model.search_read` shortcut which as its name suggests is
+equivalent to a :meth:`~odoo.models.Model.search` followed by a
+:meth:`~odoo.models.Model.read`, but avoids having to perform two requests
and keep ids around.
-Its arguments are similar to :meth:`~openerp.models.Model.search`'s, but it
-can also take a list of ``fields`` (like :meth:`~openerp.models.Model.read`,
+Its arguments are similar to :meth:`~odoo.models.Model.search`'s, but it
+can also take a list of ``fields`` (like :meth:`~odoo.models.Model.read`,
if that list is not provided it will fetch all fields of matched records):
.. container:: doc-aside
@@ -793,10 +793,10 @@ if that list is not provided it will fetch all fields of matched records):
Create records
--------------
-Records of a model are created using :meth:`~openerp.models.Model.create`. The
+Records of a model are created using :meth:`~odoo.models.Model.create`. The
method will create a single record and return its database identifier.
-:meth:`~openerp.models.Model.create` takes a mapping of fields to values, used
+:meth:`~odoo.models.Model.create` takes a mapping of fields to values, used
to initialize the record. For any field which has a default value and is not
set through the mapping argument, the default value will be used.
@@ -837,21 +837,21 @@ set through the mapping argument, the default value will be used.
.. warning::
while most value types are what would be expected (integer for
- :class:`~openerp.fields.Integer`, string for :class:`~openerp.fields.Char`
- or :class:`~openerp.fields.Text`),
+ :class:`~odoo.fields.Integer`, string for :class:`~odoo.fields.Char`
+ or :class:`~odoo.fields.Text`),
- * :class:`~openerp.fields.Date`, :class:`~openerp.fields.Datetime` and
- :class:`~openerp.fields.Binary` fields use string values
- * :class:`~openerp.fields.One2many` and :class:`~openerp.fields.Many2many`
+ * :class:`~odoo.fields.Date`, :class:`~odoo.fields.Datetime` and
+ :class:`~odoo.fields.Binary` fields use string values
+ * :class:`~odoo.fields.One2many` and :class:`~odoo.fields.Many2many`
use a special command protocol detailed in :meth:`the documentation to
- the write method `.
+ the write method `.
Update records
--------------
-Records can be updated using :meth:`~openerp.models.Model.write`, it takes
+Records can be updated using :meth:`~odoo.models.Model.write`, it takes
a list of records to update and a mapping of updated fields to values similar
-to :meth:`~openerp.models.Model.create`.
+to :meth:`~odoo.models.Model.create`.
Multiple records can be updated simultanously, but they will all get the same
values for the fields being set. It is not currently possible to perform
@@ -911,7 +911,7 @@ Delete records
--------------
Records can be deleted in bulk by providing their ids to
-:meth:`~openerp.models.Model.unlink`.
+:meth:`~odoo.models.Model.unlink`.
.. container:: doc-aside
@@ -966,7 +966,7 @@ Inspection and introspection
xid currently associated with the record. And operating with xids
isn't exactly fun in RPC.
-While we previously used :meth:`~openerp.models.Model.fields_get` to query a
+While we previously used :meth:`~odoo.models.Model.fields_get` to query a
model and have been using an arbitrary model from the start, Odoo stores
most model metadata inside a few meta-models which allow both querying the
system and altering models and fields (with some limitations) on the fly over
@@ -987,13 +987,13 @@ Provides information about Odoo models via its various fields
whether the model was generated in Python code (``base``) or by creating
an ``ir.model`` record (``manual``)
``field_id``
- list of the model's fields through a :class:`~openerp.fields.One2many` to
+ list of the model's fields through a :class:`~odoo.fields.One2many` to
:ref:`reference/webservice/inspection/fields`
``view_ids``
- :class:`~openerp.fields.One2many` to the :ref:`reference/views` defined
+ :class:`~odoo.fields.One2many` to the :ref:`reference/views` defined
for the model
``access_ids``
- :class:`~openerp.fields.One2many` relation to the
+ :class:`~odoo.fields.One2many` relation to the
:ref:`reference/security/acl` set on the model
``ir.model`` can be used to
@@ -1126,7 +1126,7 @@ Provides information about the fields of Odoo models and allows adding
custom fields without using Python code
``model_id``
- :class:`~openerp.fields.Many2one` to
+ :class:`~odoo.fields.Many2one` to
:ref:`reference/webservice/inspection/models` to which the field belongs
``name``
the field's technical name (used in ``read`` or ``write``)
@@ -1141,7 +1141,7 @@ custom fields without using Python code
enables the corresponding flag on the field
``groups``
:ref:`field-level access control `, a
- :class:`~openerp.fields.Many2many` to ``res.groups``
+ :class:`~odoo.fields.Many2many` to ``res.groups``
``selection``, ``size``, ``on_delete``, ``relation``, ``relation_field``, ``domain``
type-specific properties and customizations, see :ref:`the fields
documentation ` for details
diff --git a/doc/cla/corporate/trobz.md b/doc/cla/corporate/trobz.md
new file mode 100644
index 00000000000..1e302e701cd
--- /dev/null
+++ b/doc/cla/corporate/trobz.md
@@ -0,0 +1,18 @@
+Vietnam, 2016-09-19
+
+Trobz agrees to the terms of the Odoo Corporate Contributor License
+Agreement v1.0.
+
+I declare that I am authorized and able to make this agreement and sign this
+declaration.
+
+Signed,
+
+Denis Barbot dbarbot@trobz.com https://github.com/dbarbot
+
+List of contributors:
+
+Denis Barbot dbarbot@trobz.com https://github.com/dbarbot
+Jean-Charles Drubay jcdrubay@trobz.com https://github.com/jcdrubay
+Bui Ngoc Tu tu@trobz.com https://github.com/tungocbui
+Diep Huu Hoang hoang@trobz.com https://github.com/anothingguy
diff --git a/doc/cla/individual/GoodERPJeff.md b/doc/cla/individual/GoodERPJeff.md
new file mode 100644
index 00000000000..f2d6fde8805
--- /dev/null
+++ b/doc/cla/individual/GoodERPJeff.md
@@ -0,0 +1,11 @@
+China, 2016-10-12
+
+I hereby agree to the terms of the Odoo Individual Contributor License
+Agreement v1.0.
+
+I declare that I am authorized and able to make this agreement and sign this
+declaration.
+
+Signed,
+
+Jeff Wang jeff@osbzr.com https://github.com/GoodERPJeff
diff --git a/doc/cla/individual/tiangolo.md b/doc/cla/individual/tiangolo.md
new file mode 100644
index 00000000000..dfb1c19c218
--- /dev/null
+++ b/doc/cla/individual/tiangolo.md
@@ -0,0 +1,11 @@
+Colombia, 2016-10-04
+
+I hereby agree to the terms of the Odoo Individual Contributor License
+Agreement v1.0.
+
+I declare that I am authorized and able to make this agreement and sign this
+declaration.
+
+Signed,
+
+Sebastián Ramírez tiangolo@gmail.com https://github.com/tiangolo
diff --git a/doc/conf.py b/doc/conf.py
index 67fcc9f14e3..5fb1c9101bc 100644
--- a/doc/conf.py
+++ b/doc/conf.py
@@ -26,7 +26,7 @@ extensions = [
'sphinx.ext.intersphinx',
'sphinx.ext.linkcode',
'github_link',
- 'odoo',
+ 'odoo_ext',
'html_domain',
'exercise_admonition',
'patchqueue'
@@ -91,7 +91,7 @@ pygments_style = 'odoo'
# -- Options for HTML output ---------------------------------------------------
# The theme to use for HTML and HTML Help pages. See the documentation for
# a list of builtin themes.
-html_theme = 'odoo'
+html_theme = 'odoo_ext'
odoo_cover_default = 'banners/installing_odoo.jpg'
odoo_cover_external = {
diff --git a/doc/howtos/backend.rst b/doc/howtos/backend.rst
index b362624a274..a19e9376b9e 100644
--- a/doc/howtos/backend.rst
+++ b/doc/howtos/backend.rst
@@ -20,13 +20,13 @@ Business logic and extension is generally performed on the server side,
although supporting client features (e.g. new data representation such as
interactive maps) can be added to the client.
-In order to start the server, simply invoke the command :ref:`odoo.py
+In order to start the server, simply invoke the command :ref:`odoo-bin
` in the shell, adding the full path to the file if
necessary:
.. code:: bash
- odoo.py
+ odoo-bin
The server is stopped by hitting ``Ctrl-C`` twice from the terminal, or by
killing the corresponding OS process.
@@ -67,7 +67,7 @@ Module structure
----------------
Each module is a directory within a *module directory*. Module directories
-are specified by using the :option:`--addons-path `
+are specified by using the :option:`--addons-path `
option.
.. tip::
@@ -90,13 +90,13 @@ might contain::
from . import mymodule
-Odoo provides a mechanism to help set up a new module, :ref:`odoo.py
+Odoo provides a mechanism to help set up a new module, :ref:`odoo-bin
` has a subcommand :ref:`scaffold
` to create an empty module:
.. code-block:: console
- $ odoo.py scaffold
+ $ odoo-bin scaffold
The command creates a subdirectory for your module, and automatically creates a
bunch of standard files for a module. Most of them simply contain commented code
@@ -109,7 +109,7 @@ or XML. The usage of most of those files will be explained along this tutorial.
.. only:: solutions
- #. Invoke the command ``odoo.py scaffold openacademy addons``.
+ #. Invoke the command ``odoo-bin scaffold openacademy addons``.
#. Adapt the manifest file to your module.
#. Don't bother about the other files.
@@ -123,16 +123,16 @@ This layer avoids having to write most :abbr:`SQL (Structured Query Language)`
by hand and provides extensibility and security services\ [#rawsql]_.
Business objects are declared as Python classes extending
-:class:`~openerp.models.Model` which integrates them into the automated
+:class:`~odoo.models.Model` which integrates them into the automated
persistence system.
Models can be configured by setting a number of attributes at their
definition. The most important attribute is
-:attr:`~openerp.models.Model._name` which is required and defines the name for
+:attr:`~odoo.models.Model._name` which is required and defines the name for
the model in the Odoo system. Here is a minimally complete definition of a
model::
- from openerp import models
+ from odoo import models
class MinimalModel(models.Model):
_name = 'test.model'
@@ -142,7 +142,7 @@ Model fields
Fields are used to define what the model can store and where. Fields are
defined as attributes on the model class::
- from openerp import models, fields
+ from odoo import models, fields
class LessMinimalModel(models.Model):
_name = 'test.model2'
@@ -159,14 +159,14 @@ configuration attributes as parameters::
Some attributes are available on all fields, here are the most common ones:
-:attr:`~openerp.fields.Field.string` (``unicode``, default: field's name)
+:attr:`~odoo.fields.Field.string` (``unicode``, default: field's name)
The label of the field in UI (visible by users).
-:attr:`~openerp.fields.Field.required` (``bool``, default: ``False``)
+:attr:`~odoo.fields.Field.required` (``bool``, default: ``False``)
If ``True``, the field can not be empty, it must either have a default
value or always be given a value when creating a record.
-:attr:`~openerp.fields.Field.help` (``unicode``, default: ``''``)
+:attr:`~odoo.fields.Field.help` (``unicode``, default: ``''``)
Long-form, provides a help tooltip to users in the UI.
-:attr:`~openerp.fields.Field.index` (``bool``, default: ``False``)
+:attr:`~odoo.fields.Field.index` (``bool``, default: ``False``)
Requests that Odoo create a `database index`_ on the column
Simple fields
@@ -176,8 +176,8 @@ There are two broad categories of fields: "simple" fields which are atomic
values stored directly in the model's table and "relational" fields linking
records (of the same model or of different models).
-Example of simple fields are :class:`~openerp.fields.Boolean`,
-:class:`~openerp.fields.Date`, :class:`~openerp.fields.Char`.
+Example of simple fields are :class:`~odoo.fields.Boolean`,
+:class:`~odoo.fields.Date`, :class:`~odoo.fields.Char`.
Reserved fields
###############
@@ -186,15 +186,15 @@ Odoo creates a few fields in all models\ [#autofields]_. These fields are
managed by the system and shouldn't be written to. They can be read if
useful or necessary:
-:attr:`~openerp.fields.Model.id` (:class:`~openerp.fields.Id`)
+:attr:`~odoo.fields.Model.id` (:class:`~odoo.fields.Id`)
the unique identifier for a record in its model
-:attr:`~openerp.fields.Model.create_date` (:class:`~openerp.fields.Datetime`)
+:attr:`~odoo.fields.Model.create_date` (:class:`~odoo.fields.Datetime`)
creation date of the record
-:attr:`~openerp.fields.Model.create_uid` (:class:`~openerp.fields.Many2one`)
+:attr:`~odoo.fields.Model.create_uid` (:class:`~odoo.fields.Many2one`)
user who created the record
-:attr:`~openerp.fields.Model.write_date` (:class:`~openerp.fields.Datetime`)
+:attr:`~odoo.fields.Model.write_date` (:class:`~odoo.fields.Datetime`)
last modification date of the record
-:attr:`~openerp.fields.Model.write_uid` (:class:`~openerp.fields.Many2one`)
+:attr:`~odoo.fields.Model.write_uid` (:class:`~odoo.fields.Many2one`)
user who last modified the record
Special fields
@@ -202,7 +202,7 @@ Special fields
By default, Odoo also requires a ``name`` field on all models for various
display and search behaviors. The field used for these purposes can be
-overridden by setting :attr:`~openerp.models.Model._rec_name`.
+overridden by setting :attr:`~odoo.models.Model._rec_name`.
.. exercise:: Define a model
@@ -211,7 +211,7 @@ overridden by setting :attr:`~openerp.models.Model._rec_name`.
.. only:: solutions
- Edit the file ``openacademy/models.py`` to include a *Course* class.
+ Edit the file ``openacademy/models/models.py`` to include a *Course* class.
.. patch::
@@ -230,13 +230,13 @@ record.
.. code-block:: xml
-
+ {a value}
-
+
* ``model`` is the name of the Odoo model for the record
* ``id`` is an :term:`external identifier`, it allows referring to the record
@@ -255,7 +255,7 @@ be declared in the ``'data'`` list (always loaded) or in the ``'demo'`` list
.. only:: solutions
- Edit the file ``openacademy/demo.xml`` to include some data.
+ Edit the file ``openacademy/demo/demo.xml`` to include some data.
.. patch::
@@ -484,7 +484,7 @@ client data; it is also related to its sale order line records.
.. only:: solutions
- #. Create the class *Session* in ``openacademy/models.py``.
+ #. Create the class *Session* in ``openacademy/models/models.py``.
#. Add access to the session object in ``openacademy/view/openacademy.xml``.
.. patch::
@@ -502,16 +502,16 @@ between different models.
Relational field types are:
-:class:`Many2one(other_model, ondelete='set null') `
+:class:`Many2one(other_model, ondelete='set null') `
A simple link to an other object::
print foo.other_id.name
.. seealso:: `foreign keys `_
-:class:`One2many(other_model, related_field) `
- A virtual relationship, inverse of a :class:`~openerp.fields.Many2one`.
- A :class:`~openerp.fields.One2many` behaves as a container of records,
+:class:`One2many(other_model, related_field) `
+ A virtual relationship, inverse of a :class:`~odoo.fields.Many2one`.
+ A :class:`~odoo.fields.One2many` behaves as a container of records,
accessing it results in a (possibly empty) set of records::
for other in foo.other_ids:
@@ -519,11 +519,11 @@ Relational field types are:
.. danger::
- Because a :class:`~openerp.fields.One2many` is a virtual relationship,
- there *must* be a :class:`~openerp.fields.Many2one` field in the
+ Because a :class:`~odoo.fields.One2many` is a virtual relationship,
+ there *must* be a :class:`~odoo.fields.Many2one` field in the
:samp:`{other_model}`, and its name *must* be :samp:`{related_field}`
-:class:`Many2many(other_model) `
+:class:`Many2many(other_model) `
Bidirectional multiple relationship, any record on one side can be related
to any number of records on the other side. Behaves as a container of
records, accessing it also results in a possibly empty set of records::
@@ -604,8 +604,8 @@ fields of the parent record.
.. seealso::
- * :attr:`~openerp.models.Model._inherit`
- * :attr:`~openerp.models.Model._inherits`
+ * :attr:`~odoo.models.Model._inherit`
+ * :attr:`~odoo.models.Model._inherits`
View inheritance
----------------
@@ -684,7 +684,7 @@ instead of a single view its ``arch`` field is composed of any number of
inspect the view, find its external ID and the place to put the
new field.
- #. Create a file ``openacademy/partner.py`` and import it in
+ #. Create a file ``openacademy/models/partner.py`` and import it in
``__init__.py``
#. Create a file ``openacademy/views/partner.xml`` and add it to
``__manifest__.py``
@@ -757,7 +757,7 @@ retrieved from the database but computed on-the-fly by calling a method of the
model.
To create a computed field, create a field and set its attribute
-:attr:`~openerp.fields.Field.compute` to the name of a method. The computation
+:attr:`~odoo.fields.Field.compute` to the name of a method. The computation
method should simply set the value of the field to compute on every record in
``self``.
@@ -776,7 +776,7 @@ method should simply set the value of the field to compute on every record in
.. code-block:: python
import random
- from openerp import models, fields, api
+ from odoo import models, fields, api
class ComputedModel(models.Model):
_name = 'test.computed'
@@ -794,11 +794,11 @@ Dependencies
The value of a computed field usually depends on the values of other fields on
the computed record. The ORM expects the developer to specify those dependencies
-on the compute method with the decorator :func:`~openerp.api.depends`.
+on the compute method with the decorator :func:`~odoo.api.depends`.
The given dependencies are used by the ORM to trigger the recomputation of the
field whenever some of its dependencies have been modified::
- from openerp import models, fields, api
+ from odoo import models, fields, api
class ComputedModel(models.Model):
_name = 'test.computed'
@@ -850,7 +850,7 @@ float, string), or a function taking a recordset and returning a value::
.. exercise:: Active objects – Default values
* Define the start_date default value as today (see
- :class:`~openerp.fields.Date`).
+ :class:`~odoo.fields.Date`).
* Add a field ``active`` in the class Session, and set sessions as active by
default.
@@ -873,7 +873,7 @@ to the database.
For instance, suppose a model has three fields ``amount``, ``unit_price`` and
``price``, and you want to update the price on the form when any of the other
fields is modified. To achieve this, define a method where ``self`` represents
-the record in the form view, and decorate it with :func:`~openerp.api.onchange`
+the record in the form view, and decorate it with :func:`~odoo.api.onchange`
to specify on which field it has to be triggered. Any change you make on
``self`` will be reflected on the form.
@@ -916,16 +916,16 @@ Model constraints
=================
Odoo provides two ways to set up automatically verified invariants:
-:func:`Python constraints ` and
-:attr:`SQL constraints `.
+:func:`Python constraints ` and
+:attr:`SQL constraints `.
A Python constraint is defined as a method decorated with
-:func:`~openerp.api.constrains`, and invoked on a recordset. The decorator
+:func:`~odoo.api.constrains`, and invoked on a recordset. The decorator
specifies which fields are involved in the constraint, so that the constraint is
automatically evaluated when one of them is modified. The method is expected to
raise an exception if its invariant is not satisfied::
- from openerp.exceptions import ValidationError
+ from odoo.exceptions import ValidationError
@api.constrains('age')
def _check_something(self):
@@ -944,7 +944,7 @@ raise an exception if its invariant is not satisfied::
.. patch::
SQL constraints are defined through the model attribute
-:attr:`~openerp.models.Model._sql_constraints`. The latter is assigned to a list
+:attr:`~odoo.models.Model._sql_constraints`. The latter is assigned to a list
of triples of strings ``(name, sql_definition, message)``, where ``name`` is a
valid SQL constraint name, ``sql_definition`` is a table_constraint_ expression,
and ``message`` is the error message.
@@ -1390,7 +1390,7 @@ access rights are limited.
Here is an example of a rule that prevents the deletion of leads that are not
in state ``cancel``. Notice that the value of the field ``groups`` must follow
-the same convention as the method :meth:`~openerp.models.Model.write` of the ORM.
+the same convention as the method :meth:`~odoo.models.Model.write` of the ORM.
.. code-block:: xml
@@ -1423,9 +1423,9 @@ Wizards
Wizards describe interactive sessions with the user (or dialog boxes) through
dynamic forms. A wizard is simply a model that extends the class
-:class:`~openerp.models.TransientModel` instead of
-:class:`~openerp.models.Model`. The class
-:class:`~openerp.models.TransientModel` extends :class:`~openerp.models.Model`
+:class:`~odoo.models.TransientModel` instead of
+:class:`~odoo.models.Model`. The class
+:class:`~odoo.models.TransientModel` extends :class:`~odoo.models.Model`
and reuse all its existing mechanisms, with the following particularities:
- Wizard records are not meant to be persistent; they are automatically deleted
@@ -1537,7 +1537,7 @@ for editing and merging PO/POT files.
By default Odoo's POT export only extracts labels inside XML files or
inside field definitions in Python code, but any Python string can be
- translated this way by surrounding it with the function :func:`openerp._`
+ translated this way by surrounding it with the function :func:`odoo._`
(e.g. ``_("Label")``)
.. exercise:: Translate a module
@@ -1566,7 +1566,7 @@ for editing and merging PO/POT files.
terms
#. In ``models.py``, add an import statement for the function
- ``openerp._`` and mark missing strings as translatable
+ ``odoo._`` and mark missing strings as translatable
#. Repeat steps 3-6
@@ -1852,12 +1852,12 @@ Examples can be easily adapted from XML-RPC to JSON-RPC.
* https://github.com/akretion/ooor
* https://github.com/syleam/openobject-library
- * https://github.com/nicolas-van/openerp-client-lib
+ * https://github.com/nicolas-van/odoo-client-lib
* https://pypi.python.org/pypi/oersted/
- * https://github.com/abhishek-jaiswal/php-openerp-lib
+ * https://github.com/abhishek-jaiswal/php-odoo-lib
.. [#autofields] it is possible to :attr:`disable the automatic creation of some
- fields `
+ fields `
.. [#rawsql] writing raw SQL queries is possible, but requires care as it
bypasses all Odoo authentication and security mechanisms.
diff --git a/doc/howtos/backend/exercise-access-rights b/doc/howtos/backend/exercise-access-rights
index e653cbadcd5..65165f14b29 100644
--- a/doc/howtos/backend/exercise-access-rights
+++ b/doc/howtos/backend/exercise-access-rights
@@ -31,10 +31,10 @@ Index: addons/openacademy/security/security.xml
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ addons/openacademy/security/security.xml 2014-08-26 17:26:18.135783102 +0200
@@ -0,0 +1,7 @@
-+
++
+
+
+ OpenAcademy / Manager
+
+
-+
++
diff --git a/doc/howtos/backend/exercise-access-rules b/doc/howtos/backend/exercise-access-rules
index 4ec91a3fcd4..40cdacfe03e 100644
--- a/doc/howtos/backend/exercise-access-rules
+++ b/doc/howtos/backend/exercise-access-rules
@@ -24,4 +24,4 @@ Index: addons/openacademy/security/security.xml
+
+
-
+
diff --git a/doc/howtos/backend/exercise-basic-action b/doc/howtos/backend/exercise-basic-action
index f5e5e9be9d5..b8876a1f9e8 100644
--- a/doc/howtos/backend/exercise-basic-action
+++ b/doc/howtos/backend/exercise-basic-action
@@ -18,7 +18,7 @@ Index: addons/openacademy/views/openacademy.xml
+++ addons/openacademy/views/openacademy.xml 2014-08-26 17:25:53.511783468 +0200
@@ -0,0 +1,35 @@
+
-+
++
+
+
+
+
-+
++
diff --git a/doc/howtos/backend/exercise-calendar b/doc/howtos/backend/exercise-calendar
index 6d85a64e05a..9a86e6b03de 100644
--- a/doc/howtos/backend/exercise-calendar
+++ b/doc/howtos/backend/exercise-calendar
@@ -9,7 +9,7 @@ diff --git a/openacademy/models.py b/openacademy/models.py
# -*- coding: utf-8 -*-
+from datetime import timedelta
- from openerp import models, fields, api, exceptions
+ from odoo import models, fields, api, exceptions
class Session(models.Model):
@@ -55,6 +56,8 @@ class Session(models.Model):
diff --git a/doc/howtos/backend/exercise-constraint-python b/doc/howtos/backend/exercise-constraint-python
index 290e09aa5a1..144a64e0325 100644
--- a/doc/howtos/backend/exercise-constraint-python
+++ b/doc/howtos/backend/exercise-constraint-python
@@ -8,8 +8,8 @@ diff --git a/openacademy/models.py b/openacademy/models.py
@@ -1,6 +1,6 @@
# -*- coding: utf-8 -*-
--from openerp import models, fields, api
-+from openerp import models, fields, api, exceptions
+-from odoo import models, fields, api
++from odoo import models, fields, api, exceptions
class Course(models.Model):
_name = 'openacademy.course'
diff --git a/doc/howtos/backend/exercise-creation b/doc/howtos/backend/exercise-creation
index 80911aa160e..490f7fd7a02 100644
--- a/doc/howtos/backend/exercise-creation
+++ b/doc/howtos/backend/exercise-creation
@@ -22,7 +22,7 @@ Index: addons/openacademy/__manifest__.py
+ 'website': "http://www.yourcompany.com",
+
+ # Categories can be used to filter modules in modules listing
-+ # Check https://github.com/odoo/odoo/blob/master/openerp/addons/base/module/module_data.xml
++ # Check https://github.com/odoo/odoo/blob/master/odoo/addons/base/module/module_data.xml
+ # for the full list
+ 'category': 'Test',
+ 'version': '0.1',
@@ -54,7 +54,7 @@ Index: addons/openacademy/controllers.py
+++ addons/openacademy/controllers.py 2014-08-26 17:25:49.791783523 +0200
@@ -0,0 +1,20 @@
+# -*- coding: utf-8 -*-
-+from openerp import http
++from odoo import http
+
+# class Openacademy(http.Controller):
+# @http.route('/openacademy/openacademy/', auth='public')
@@ -78,7 +78,7 @@ Index: addons/openacademy/demo.xml
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ addons/openacademy/demo.xml 2014-08-26 17:25:49.791783523 +0200
@@ -0,0 +1,25 @@
-+
++
+
+
+
@@ -102,7 +102,7 @@ Index: addons/openacademy/demo.xml
+
+
+
-+
++
Index: addons/openacademy/models.py
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
@@ -110,7 +110,7 @@ Index: addons/openacademy/models.py
@@ -0,0 +1,8 @@
+# -*- coding: utf-8 -*-
+
-+from openerp import models, fields, api
++from odoo import models, fields, api
+
+# class openacademy(models.Model):
+# _name = 'openacademy.openacademy'
@@ -128,7 +128,7 @@ Index: addons/openacademy/templates.xml
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ addons/openacademy/templates.xml 2014-08-26 17:25:49.791783523 +0200
@@ -0,0 +1,22 @@
-+
++
+
+
+
@@ -149,4 +149,4 @@ Index: addons/openacademy/templates.xml
+
+
+
-+
++
diff --git a/doc/howtos/backend/exercise-dashboard b/doc/howtos/backend/exercise-dashboard
index b1092479669..4a6eceb8fd9 100644
--- a/doc/howtos/backend/exercise-dashboard
+++ b/doc/howtos/backend/exercise-dashboard
@@ -28,7 +28,7 @@ Index: addons/openacademy/views/session_board.xml
+++ addons/openacademy/views/session_board.xml 2014-08-26 17:26:21.531783052 +0200
@@ -0,0 +1,66 @@
+
-+
++
+
+
+ Attendees by course
@@ -92,4 +92,4 @@ Index: addons/openacademy/views/session_board.xml
+ sequence="1"
+ id="menu_board_session" icon="terp-graph"/>
+
-+
++
diff --git a/doc/howtos/backend/exercise-demo b/doc/howtos/backend/exercise-demo
index 96d591a5fc1..a03007d7fe9 100644
--- a/doc/howtos/backend/exercise-demo
+++ b/doc/howtos/backend/exercise-demo
@@ -6,7 +6,7 @@ Index: addons/openacademy/demo.xml
--- addons.orig/openacademy/demo.xml 2014-08-26 17:25:52.683783480 +0200
+++ addons/openacademy/demo.xml 2014-08-26 17:25:52.679783480 +0200
@@ -1,25 +1,19 @@
-
+
-
-
@@ -45,4 +45,4 @@ Index: addons/openacademy/demo.xml
+ Course 2's description
+
-
+
diff --git a/doc/howtos/backend/exercise-domain-advanced b/doc/howtos/backend/exercise-domain-advanced
index 4b27ad89143..bed90880dcd 100644
--- a/doc/howtos/backend/exercise-domain-advanced
+++ b/doc/howtos/backend/exercise-domain-advanced
@@ -40,4 +40,4 @@ Index: addons/openacademy/views/partner.xml
+ Teacher / Level 2
+
-
+
diff --git a/doc/howtos/backend/exercise-formview b/doc/howtos/backend/exercise-formview
index ad0dd4e9baf..8de3e69f7e6 100644
--- a/doc/howtos/backend/exercise-formview
+++ b/doc/howtos/backend/exercise-formview
@@ -7,7 +7,7 @@ Index: addons/openacademy/views/openacademy.xml
+++ addons/openacademy/views/openacademy.xml 2014-08-26 17:25:54.283783457 +0200
@@ -1,6 +1,21 @@
-
+
+
+ course.form
diff --git a/doc/howtos/backend/exercise-model b/doc/howtos/backend/exercise-model
index 57be0edad57..4c3b8573107 100644
--- a/doc/howtos/backend/exercise-model
+++ b/doc/howtos/backend/exercise-model
@@ -6,7 +6,7 @@ Index: addons/openacademy/models.py
+++ addons/openacademy/models.py 2014-08-26 17:25:51.639783496 +0200
@@ -2,7 +2,8 @@
- from openerp import models, fields, api
+ from odoo import models, fields, api
-# class openacademy(models.Model):
-# _name = 'openacademy.openacademy'
diff --git a/doc/howtos/backend/exercise-model-inheritance b/doc/howtos/backend/exercise-model-inheritance
index 941ce0442df..f74e5e95c33 100644
--- a/doc/howtos/backend/exercise-model-inheritance
+++ b/doc/howtos/backend/exercise-model-inheritance
@@ -28,7 +28,7 @@ Index: addons/openacademy/partner.py
+++ addons/openacademy/partner.py 2014-08-26 17:26:01.223783354 +0200
@@ -0,0 +1,12 @@
+# -*- coding: utf-8 -*-
-+from openerp import fields, models
++from odoo import fields, models
+
+class Partner(models.Model):
+ _inherit = 'res.partner'
@@ -45,7 +45,7 @@ Index: addons/openacademy/views/partner.xml
+++ addons/openacademy/views/partner.xml 2014-08-26 17:26:01.223783354 +0200
@@ -0,0 +1,32 @@
+
-+
++
+
+
+
@@ -75,4 +75,4 @@ Index: addons/openacademy/views/partner.xml
+ parent="configuration_menu"
+ action="contact_list_action"/>
+
-+
++
diff --git a/doc/howtos/backend/exercise-report b/doc/howtos/backend/exercise-report
index b06e3fbf6ee..6e8a2d78705 100644
--- a/doc/howtos/backend/exercise-report
+++ b/doc/howtos/backend/exercise-report
@@ -18,7 +18,7 @@ Index: addons/openacademy/reports.xml
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ addons/openacademy/reports.xml 2014-08-29 08:41:12.663540061 +0200
@@ -0,0 +1,30 @@
-+
++
+
+
+
+
-+
++
diff --git a/doc/howtos/backend/exercise-session b/doc/howtos/backend/exercise-session
index 993ee0a7dd6..9a6fe886932 100644
--- a/doc/howtos/backend/exercise-session
+++ b/doc/howtos/backend/exercise-session
@@ -55,4 +55,4 @@ Index: addons/openacademy/views/openacademy.xml
+ parent="openacademy_menu"
+ action="session_list_action"/>
-
+
diff --git a/doc/howtos/backend/exercise-state-workflow b/doc/howtos/backend/exercise-state-workflow
index 6178913d164..d97dce1b1ea 100644
--- a/doc/howtos/backend/exercise-state-workflow
+++ b/doc/howtos/backend/exercise-state-workflow
@@ -50,7 +50,7 @@ new file mode 100644
--- /dev/null
+++ b/openacademy/views/session_workflow.xml
@@ -0,0 +1,50 @@
-+
++
+
+
+ OpenAcademy sessions workflow
@@ -99,4 +99,4 @@ new file mode 100644
+ done
+
+
-+
++
diff --git a/doc/howtos/backend/exercise-state-workflow-automatic b/doc/howtos/backend/exercise-state-workflow-automatic
index 112d0a3cd20..c1f5d1c7e5a 100644
--- a/doc/howtos/backend/exercise-state-workflow-automatic
+++ b/doc/howtos/backend/exercise-state-workflow-automatic
@@ -16,4 +16,4 @@ Index: addons/openacademy/views/session_workflow.xml
+ taken_seats > 50
+
-
+
diff --git a/doc/howtos/backend/exercise-translations b/doc/howtos/backend/exercise-translations
index 707abe27557..8ade655253d 100644
--- a/doc/howtos/backend/exercise-translations
+++ b/doc/howtos/backend/exercise-translations
@@ -8,8 +8,8 @@ diff --git a/openacademy/models.py b/openacademy/models.py
# -*- coding: utf-8 -*-
from datetime import timedelta
--from openerp import models, fields, api, exceptions
-+from openerp import models, fields, api, exceptions, _
+-from odoo import models, fields, api, exceptions
++from odoo import models, fields, api, exceptions, _
class Course(models.Model):
_name = 'openacademy.course'
diff --git a/doc/howtos/backend/exercise-wizard b/doc/howtos/backend/exercise-wizard
index 906cdef181b..400654c4ff3 100644
--- a/doc/howtos/backend/exercise-wizard
+++ b/doc/howtos/backend/exercise-wizard
@@ -14,7 +14,7 @@ Index: addons/openacademy/wizard.py
@@ -0,0 +1,10 @@
+# -*- coding: utf-8 -*-
+
-+from openerp import models, fields, api
++from odoo import models, fields, api
+
+class Wizard(models.TransientModel):
+ _name = 'openacademy.wizard'
diff --git a/doc/howtos/backend/exercise-wizard-launch b/doc/howtos/backend/exercise-wizard-launch
index bfd0f26bf30..605178e8375 100644
--- a/doc/howtos/backend/exercise-wizard-launch
+++ b/doc/howtos/backend/exercise-wizard-launch
@@ -43,4 +43,4 @@ Index: addons/openacademy/views/openacademy.xml
+ target="new"
+ key2="client_action_multi"/>
-
+
diff --git a/doc/howtos/themes.rst b/doc/howtos/themes.rst
index 3432be40900..531f5e2c8f0 100644
--- a/doc/howtos/themes.rst
+++ b/doc/howtos/themes.rst
@@ -144,17 +144,17 @@ Odoo's XML files, an overview
-----------------------------
Any Odoo XML file starts with encoding specifications.
-After that, you have to write your code inside a ```` tag, placed into an ```` tag.
+After that, you have to write your code inside a ```` tag, placed into an ```` tag.
.. code-block:: xml
[XML]
-
+
## YOUR CODE HERE
-
+
Almost every element and option that you create has to be placed inside a ```` tag, like in this example.
@@ -223,14 +223,14 @@ Odoo’s themes are packaged like modules. Even if you are designing a very simp
.. important::
Use two underscore characters at the beginning
- and two at the end of openerp and init file names.
+ and two at the end of odoo and init file names.
The final result should be something like this:
.. image:: theme_tutorial_assets/img/folder.jpg
Edit ``__manifest__.py``
------------------------
+------------------------
Open the ``__manifest__.py`` you created and copy/paste the following:
@@ -309,11 +309,11 @@ To do so, create a **layout.xml** file in your **views** folder and add the defa
.. code-block:: xml
-
+
-
+
Create a new template into the ```` tag, copy-pasting the following
code.
@@ -379,7 +379,7 @@ default Odoo markup. Inside ```` create a ```` tag, set the
.. code-block:: xml
-
+
@@ -391,7 +391,7 @@ default Odoo markup. Inside ```` create a ```` tag, set the
-
+
The page title will be the template ID. In our case *Services* (from ``website.services``)
@@ -429,7 +429,7 @@ can fill with snippets. To achieve this, just create a ``div`` with
.. code-block:: xml
-
+
@@ -451,7 +451,7 @@ can fill with snippets. To achieve this, just create a ``div`` with
-
+
.. tip::
@@ -787,8 +787,8 @@ the following code
(function() {
'use strict';
- var website = openerp.website;
- website.openerp_website = {};
+ var website = odoo.website;
+ website.odoo_website = {};
})();
Great, we successfully created our javascript editor file. This file will contain all the javascript functions used by our snippets in edit mode. Let’s create a new function for our testimonial snippet using the ``snippet_testimonial_options`` method that we created before.
@@ -797,8 +797,8 @@ Great, we successfully created our javascript editor file. This file will contai
(function() {
'use strict';
- var website = openerp.website;
- website.openerp_website = {};
+ var website = odoo.website;
+ website.odoo_website = {};
website.snippet.options.snippet_testimonial_options = website.snippet.Option.extend({
on_focus: function() {
diff --git a/doc/howtos/web.rst b/doc/howtos/web.rst
index 9c99b02d2ce..10fb797145d 100644
--- a/doc/howtos/web.rst
+++ b/doc/howtos/web.rst
@@ -39,7 +39,7 @@ following command:
This will create a ``petstore`` folder wherever you executed the command.
You then need to add that folder to Odoo's
-:option:`addons path `, create a new database and
+:option:`addons path `, create a new database and
install the ``oepetstore`` module.
If you browse the ``petstore`` folder, you should see the following content:
@@ -86,7 +86,7 @@ sub-folders are conventional and not strictly necessary.
application (or at least its web-browser side) as javascript. It should
currently look like::
- openerp.oepetstore = function(instance, local) {
+ odoo.oepetstore = function(instance, local) {
var _t = instance.web._t,
_lt = instance.web._lt;
var QWeb = instance.web.qweb;
@@ -142,11 +142,11 @@ in order to both namespace code and correctly order its loading.
``oepetstore/static/js/petstore.js`` contains a module declaration::
- openerp.oepetstore = function(instance, local) {
+ odoo.oepetstore = function(instance, local) {
local.xxx = ...;
}
-In Odoo web, modules are declared as functions set on the global ``openerp``
+In Odoo web, modules are declared as functions set on the global ``odoo``
variable. The function's name must be the same as the addon (in this case
``oepetstore``) so the framework can find it, and automatically initialize it.
@@ -173,8 +173,8 @@ equivalent (if lower-level and more verbose) mechanisms.
For simplicity and developer-friendliness Odoo web provides a class
system based on John Resig's `Simple JavaScript Inheritance`_.
-New classes are defined by calling the :func:`~openerp.web.Class.extend`
-method of :class:`openerp.web.Class`::
+New classes are defined by calling the :func:`~odoo.web.Class.extend`
+method of :class:`odoo.web.Class`::
var MyClass = instance.web.Class.extend({
say_hello: function() {
@@ -182,7 +182,7 @@ method of :class:`openerp.web.Class`::
},
});
-The :func:`~openerp.web.Class.extend` method takes a dictionary describing
+The :func:`~odoo.web.Class.extend` method takes a dictionary describing
the new class's content (methods and static attributes). In this case, it will
only have a ``say_hello`` method which takes no parameters.
@@ -223,8 +223,8 @@ parameters passed when using the ``new`` operator::
// print "hello Bob" in the console
It is also possible to create subclasses from existing (used-defined) classes
-by calling :func:`~openerp.web.Class.extend` on the parent class, as is done
-to subclass :class:`~openerp.web.Class`::
+by calling :func:`~odoo.web.Class.extend` on the parent class, as is done
+to subclass :class:`~odoo.web.Class`::
var MySpanishClass = MyClass.extend({
say_hello: function() {
@@ -284,7 +284,7 @@ maintenance.
Much like object-oriented desktop UI toolkits (e.g. Qt_, Cocoa_ or GTK_),
Odoo Web makes specific components responsible for sections of a page. In
-Odoo web, the base for such components is the :class:`~openerp.Widget`
+Odoo web, the base for such components is the :class:`~odoo.Widget`
class, a component specialized in handling a page section and displaying
information for the user.
@@ -299,8 +299,8 @@ The initial demonstration module already provides a basic widget::
},
});
-It extends :class:`~openerp.Widget` and overrides the standard method
-:func:`~openerp.Widget.start`, which — much like the previous ``MyClass``
+It extends :class:`~odoo.Widget` and overrides the standard method
+:func:`~odoo.Widget.start`, which — much like the previous ``MyClass``
— does little for now.
This line at the end of the file::
@@ -327,14 +327,14 @@ Widgets have a number of methods and features, but the basics are simple:
* format the widget's data
* display the widget
-The ``HomePage`` widget already has a :func:`~openerp.Widget.start`
+The ``HomePage`` widget already has a :func:`~odoo.Widget.start`
method. That method is part of the normal widget lifecycle and automatically
called once the widget is inserted in the page. We can use it to display some
content.
-All widgets have a :attr:`~openerp.Widget.$el` which represents the
+All widgets have a :attr:`~odoo.Widget.$el` which represents the
section of page they're in charge of (as a jQuery_ object). Widget content
-should be inserted there. By default, :attr:`~openerp.Widget.$el` is an
+should be inserted there. By default, :attr:`~odoo.Widget.$el` is an
empty ``
`` element.
A ``
`` element is usually invisible to the user if it has no content (or
@@ -367,7 +367,7 @@ To learn how to use a widget "from scratch" let's create a new one::
});
We can now add our ``GreetingsWidget`` to the ``HomePage`` by using the
-``GreetingsWidget``'s :func:`~openerp.Widget.appendTo` method::
+``GreetingsWidget``'s :func:`~odoo.Widget.appendTo` method::
local.HomePage = instance.Widget.extend({
start: function() {
@@ -380,17 +380,17 @@ We can now add our ``GreetingsWidget`` to the ``HomePage`` by using the
* ``HomePage`` first adds its own content to its DOM root
* ``HomePage`` then instantiates ``GreetingsWidget``
* Finally it tells ``GreetingsWidget`` where to insert itself, delegating part
- of its :attr:`~openerp.Widget.$el` to the ``GreetingsWidget``.
+ of its :attr:`~odoo.Widget.$el` to the ``GreetingsWidget``.
-When the :func:`~openerp.Widget.appendTo` method is called, it asks the
+When the :func:`~odoo.Widget.appendTo` method is called, it asks the
widget to insert itself at the specified position and to display its content.
-The :func:`~openerp.Widget.start` method will be called during the call
-to :func:`~openerp.Widget.appendTo`.
+The :func:`~odoo.Widget.start` method will be called during the call
+to :func:`~odoo.Widget.appendTo`.
To see what happens under the displayed interface, we will use the browser's
DOM Explorer. But first let's alter our widgets slightly so we can more easily
find where they are, by :attr:`adding a class to their root elements
-`::
+`::
local.HomePage = instance.Widget.extend({
className: 'oe_petstore_homepage',
@@ -414,7 +414,7 @@ then :guilabel:`Inspect Element`), it should look like this:
Which clearly shows the two ``
`` elements automatically created by
-:class:`~openerp.Widget`, because we added some classes on them.
+:class:`~odoo.Widget`, because we added some classes on them.
We can also see the two message-holding divs we added ourselves
@@ -442,7 +442,7 @@ of another widget, and exist on behalf of it. We call the container the
Due to multiple technical and conceptual reasons, it is necessary for a widget
to know who is its parent and who are its children.
-:func:`~openerp.Widget.getParent`
+:func:`~odoo.Widget.getParent`
can be used to get the parent of a widget::
local.GreetingsWidget = instance.Widget.extend({
@@ -452,7 +452,7 @@ to know who is its parent and who are its children.
},
});
-:func:`~openerp.Widget.getChildren`
+:func:`~odoo.Widget.getChildren`
can be used to get a list of its children::
local.HomePage = instance.Widget.extend({
@@ -464,7 +464,7 @@ to know who is its parent and who are its children.
},
});
-When overriding the :func:`~openerp.Widget.init` method of a widget it is
+When overriding the :func:`~odoo.Widget.init` method of a widget it is
*of the utmost importance* to pass the parent to the ``this._super()`` call,
otherwise the relation will not be set up correctly::
@@ -484,20 +484,20 @@ Destroying Widgets
------------------
If you can display content to your users, you should also be able to erase
-it. This is done via the :func:`~openerp.Widget.destroy` method::
+it. This is done via the :func:`~odoo.Widget.destroy` method::
greeting.destroy();
When a widget is destroyed it will first call
-:func:`~openerp.Widget.destroy` on all its children. Then it erases itself
+:func:`~odoo.Widget.destroy` on all its children. Then it erases itself
from the DOM. If you have set up permanent structures in
-:func:`~openerp.Widget.init` or :func:`~openerp.Widget.start` which
+:func:`~odoo.Widget.init` or :func:`~odoo.Widget.start` which
must be explicitly cleaned up (because the garbage collector will not handle
-them), you can override :func:`~openerp.Widget.destroy`.
+them), you can override :func:`~odoo.Widget.destroy`.
.. danger::
- when overriding :func:`~openerp.Widget.destroy`, ``_super()``
+ when overriding :func:`~odoo.Widget.destroy`, ``_super()``
*must always* be called otherwise the widget and its children are not
correctly cleaned up leaving possible memory leaks and "phantom events",
even if no error is displayed
@@ -525,9 +525,9 @@ characteristics:
* It's implemented fully in JavaScript and rendered in the browser
* Each template file (XML files) contains multiple templates
-* It has special support in Odoo Web's :class:`~openerp.Widget`, though it
+* It has special support in Odoo Web's :class:`~odoo.Widget`, though it
can be used outside of Odoo's web client (and it's possible to use
- :class:`~openerp.Widget` without relying on QWeb)
+ :class:`~odoo.Widget` without relying on QWeb)
.. note::
@@ -569,9 +569,9 @@ template defined in the XML file::
:func:`QWeb.render` looks for the specified template, renders it to a string
and returns the result.
-However, because :class:`~openerp.Widget` has special integration for QWeb
+However, because :class:`~odoo.Widget` has special integration for QWeb
the template can be set directly on the widget via its
-:attr:`~openerp.Widget.template` attribute::
+:attr:`~odoo.Widget.template` attribute::
local.HomePage = instance.Widget.extend({
template: "HomePageTemplate",
@@ -584,7 +584,7 @@ Although the result looks similar, there are two differences between these
usages:
* with the second version, the template is rendered right before
- :func:`~openerp.Widget.start` is called
+ :func:`~odoo.Widget.start` is called
* in the first version the template's content is added to the widget's root
element, whereas in the second version the template's root element is
directly *set as* the widget's root element. Which is why the "greetings"
@@ -593,7 +593,7 @@ usages:
.. warning::
templates should have a single non-``t`` root element, especially if
- they're set as a widget's :attr:`~openerp.Widget.template`. If there are
+ they're set as a widget's :attr:`~odoo.Widget.template`. If there are
multiple "root elements", results are undefined (usually only the first
root element will be used and the others will be ignored)
@@ -621,11 +621,11 @@ will result in:
Hello Klaus
-When using :class:`~openerp.Widget`'s integration it is not possible to
+When using :class:`~odoo.Widget`'s integration it is not possible to
provide additional data to the template. The template will be given a single
``widget`` context variable, referencing the widget being rendered right
-before :func:`~openerp.Widget.start` is called (the widget's state will
-essentially be that set up by :func:`~openerp.Widget.init`):
+before :func:`~odoo.Widget.start` is called (the widget's state will
+essentially be that set up by :func:`~odoo.Widget.init`):
.. code-block:: xml
@@ -850,7 +850,7 @@ Exercise
::
- openerp.oepetstore = function(instance, local) {
+ odoo.oepetstore = function(instance, local) {
var _t = instance.web._t,
_lt = instance.web._lt;
var QWeb = instance.web.qweb;
@@ -918,8 +918,8 @@ Selecting DOM elements within a widget can be performed by calling the
this.$el.find("input.my_input")...
-But because it's a common operation, :class:`~openerp.Widget` provides an
-equivalent shortcut through the :func:`~openerp.Widget.$` method::
+But because it's a common operation, :class:`~odoo.Widget` provides an
+equivalent shortcut through the :func:`~odoo.Widget.$` method::
local.MyWidget = instance.Widget.extend({
start: function() {
@@ -963,7 +963,7 @@ While this works it has a few issues:
3. it requires dealing with ``this``-binding issues
Widgets thus provide a shortcut to DOM event binding via
-:attr:`~openerp.Widget.events`::
+:attr:`~odoo.Widget.events`::
local.MyWidget = instance.Widget.extend({
events: {
@@ -974,7 +974,7 @@ Widgets thus provide a shortcut to DOM event binding via
}
});
-:attr:`~openerp.Widget.events` is an object (mapping) of an event to the
+:attr:`~odoo.Widget.events` is an object (mapping) of an event to the
function or method to call when the event is triggered:
* the key is an event name, possibly refined with a CSS selector in which
@@ -1025,12 +1025,12 @@ This widget acts as a facade, transforming user input (through DOM events)
into a documentable internal event to which parent widgets can bind
themselves.
-:func:`~openerp.Widget.trigger` takes the name of the event to trigger as
+:func:`~odoo.Widget.trigger` takes the name of the event to trigger as
its first (mandatory) argument, any further arguments are treated as event
data and passed directly to listeners.
We can then set up a parent event instantiating our generic widget and
-listening to the ``user_chose`` event using :func:`~openerp.Widget.on`::
+listening to the ``user_chose`` event using :func:`~odoo.Widget.on`::
local.HomePage = instance.Widget.extend({
start: function() {
@@ -1047,11 +1047,11 @@ listening to the ``user_chose`` event using :func:`~openerp.Widget.on`::
},
});
-:func:`~openerp.Widget.on` binds a function to be called when the
+:func:`~odoo.Widget.on` binds a function to be called when the
event identified by ``event_name`` is. The ``func`` argument is the
function to call and ``object`` is the object to which that function is
related if it is a method. The bound function will be called with the
-additional arguments of :func:`~openerp.Widget.trigger` if it has
+additional arguments of :func:`~odoo.Widget.trigger` if it has
any. Example::
start: function() {
@@ -1067,7 +1067,7 @@ any. Example::
.. note::
Triggering events on an other widget is generally a bad idea. The main
- exception to that rule is ``openerp.web.bus`` which exists specifically
+ exception to that rule is ``odoo.web.bus`` which exists specifically
to broadcasts evens in which any widget could be interested throughout
the Odoo web application.
@@ -1087,10 +1087,10 @@ that they trigger events when set::
console.log("The new value of the property 'name' is", this.widget.get("name"));
}
-* :func:`~openerp.Widget.set` sets the value of a property and triggers
+* :func:`~odoo.Widget.set` sets the value of a property and triggers
:samp:`change:{propname}` (where *propname* is the property name passed as
- first parameter to :func:`~openerp.Widget.set`) and ``change``
-* :func:`~openerp.Widget.get` retrieves the value of a property.
+ first parameter to :func:`~odoo.Widget.set`) and ``change``
+* :func:`~odoo.Widget.get` retrieves the value of a property.
Exercise
--------
@@ -1119,7 +1119,7 @@ Exercise
::
- openerp.oepetstore = function(instance, local) {
+ odoo.oepetstore = function(instance, local) {
var _t = instance.web._t,
_lt = instance.web._lt;
var QWeb = instance.web.qweb;
@@ -1189,7 +1189,7 @@ Modify existing widgets and classes
===================================
The class system of the Odoo web framework allows direct modification of
-existing classes using the :func:`~openerp.web.Class.include` method::
+existing classes using the :func:`~odoo.web.Class.include` method::
var TestClass = instance.web.Class.extend({
testMethod: function() {
@@ -1212,9 +1212,9 @@ target class in-place instead of creating a new class.
In that case, ``this._super()`` will call the original implementation of a
method being replaced/redefined. If the class already had sub-classes, all
calls to ``this._super()`` in sub-classes will call the new implementations
-defined in the call to :func:`~openerp.web.Class.include`. This will also work
+defined in the call to :func:`~odoo.web.Class.include`. This will also work
if some instances of the class (or of any of its sub-classes) were created
-prior to the call to :func:`~openerp.Widget.include`.
+prior to the call to :func:`~odoo.Widget.include`.
Translations
============
@@ -1235,7 +1235,7 @@ In Odoo, translations files are automatically generated by scanning the source
code. All piece of code that calls a certain function are detected and their
content is added to a translation file that will then be sent to the
translators. In Python, the function is ``_()``. In JavaScript the function is
-:func:`~openerp.web._t` (and also :func:`~openerp.web._lt`).
+:func:`~odoo.web._t` (and also :func:`~odoo.web._lt`).
``_t()`` will return the translation defined for the text it is given. If no
translation is defined for that text, it will return the original text as-is.
@@ -1255,7 +1255,7 @@ translation is defined for that text, it will return the original text as-is.
This makes translatable strings more readable to translators, and gives
them more flexibility to reorder or ignore parameters.
-:func:`~openerp.web._lt` ("lazy translate") is similar but somewhat more
+:func:`~odoo.web._lt` ("lazy translate") is similar but somewhat more
complex: instead of translating its parameter immediately, it returns
an object which, when converted to a string, will perform the translation.
@@ -1309,11 +1309,11 @@ Here is a sample widget that calls ``my_method()`` and displays the result::
},
});
-The class used to call Odoo models is :class:`openerp.Model`. It is
+The class used to call Odoo models is :class:`odoo.Model`. It is
instantiated with the Odoo model's name as first parameter
(``oepetstore.message_of_the_day`` here).
-:func:`~openerp.web.Model.call` can be used to call any (public) method of an
+:func:`~odoo.web.Model.call` can be used to call any (public) method of an
Odoo model. It takes the following positional arguments:
``name``
@@ -1349,7 +1349,7 @@ Odoo model. It takes the following positional arguments:
model.call("my_method", [], {a: 1, b: 2, c: 3, ...
// with this a=1, b=2 and c=3
-:func:`~openerp.Widget.call` returns a deferred resolved with the value
+:func:`~odoo.Widget.call` returns a deferred resolved with the value
returned by the model's method as first argument.
CompoundContext
@@ -1370,13 +1370,13 @@ is used by people in different countries.
The ``argument`` is necessary in all methods, otherwise bad things could
happen (such as the application not being translated correctly). That's why,
when you call a model's method, you should always provide that argument. The
-solution to achieve that is to use :class:`openerp.web.CompoundContext`.
+solution to achieve that is to use :class:`odoo.web.CompoundContext`.
-:class:`~openerp.web.CompoundContext` is a class used to pass the user's
+:class:`~odoo.web.CompoundContext` is a class used to pass the user's
context (with language, time zone, etc...) to the server as well as adding new
keys to the context (some models' methods use arbitrary keys added to the
context). It is created by giving to its constructor any number of
-dictionaries or other :class:`~openerp.web.CompoundContext` instances. It will
+dictionaries or other :class:`~odoo.web.CompoundContext` instances. It will
merge all those contexts before sending them to the server.
.. code-block:: javascript
@@ -1393,17 +1393,17 @@ merge all those contexts before sending them to the server.
You can see the dictionary in the argument ``context`` contains some keys that
are related to the configuration of the current user in Odoo plus the
``new_key`` key that was added when instantiating
-:class:`~openerp.web.CompoundContext`.
+:class:`~odoo.web.CompoundContext`.
Queries
-------
-While :func:`~openerp.Model.call` is sufficient for any interaction with Odoo
+While :func:`~odoo.Model.call` is sufficient for any interaction with Odoo
models, Odoo Web provides a helper for simpler and clearer querying of models
(fetching of records based on various conditions):
-:func:`~openerp.Model.query` which acts as a shortcut for the common
-combination of :py:meth:`~openerp.models.Model.search` and
-::py:meth:`~openerp.models.Model.read`. It provides a clearer syntax to search
+:func:`~odoo.Model.query` which acts as a shortcut for the common
+combination of :py:meth:`~odoo.models.Model.search` and
+::py:meth:`~odoo.models.Model.read`. It provides a clearer syntax to search
and read models::
model.query(['name', 'login', 'user_email', 'signature'])
@@ -1423,19 +1423,19 @@ versus::
// do work with users records
});
-* :func:`~openerp.web.Model.query` takes an optional list of fields as
+* :func:`~odoo.web.Model.query` takes an optional list of fields as
parameter (if no field is provided, all fields of the model are fetched). It
- returns a :class:`openerp.web.Query` which can be further customized before
+ returns a :class:`odoo.web.Query` which can be further customized before
being executed
-* :class:`~openerp.web.Query` represents the query being built. It is
+* :class:`~odoo.web.Query` represents the query being built. It is
immutable, methods to customize the query actually return a modified copy,
so it's possible to use the original and the new version side-by-side. See
- :class:`~openerp.web.Query` for its customization options.
+ :class:`~odoo.web.Query` for its customization options.
When the query is set up as desired, simply call
-:func:`~openerp.web.Query.all` to execute it and return a
+:func:`~odoo.web.Query.all` to execute it and return a
deferred to its result. The result is the same as
-:py:meth:`~openerp.models.Model.read`'s, an array of dictionaries where each
+:py:meth:`~odoo.models.Model.read`'s, an array of dictionaries where each
dictionary is a requested record, with each requested field a dictionary key.
Exercises
@@ -1453,7 +1453,7 @@ Exercises
.. code-block:: javascript
- openerp.oepetstore = function(instance, local) {
+ odoo.oepetstore = function(instance, local) {
var _t = instance.web._t,
_lt = instance.web._lt;
var QWeb = instance.web.qweb;
@@ -1531,7 +1531,7 @@ Exercises
.. code-block:: javascript
- openerp.oepetstore = function(instance, local) {
+ odoo.oepetstore = function(instance, local) {
var _t = instance.web._t,
_lt = instance.web._lt;
var QWeb = instance.web.qweb;
@@ -1666,7 +1666,7 @@ The action manager can be invoked explicitly from javascript code by creating
a dictionary describing :ref:`an action ` of the right
type, and calling an action manager instance with it.
-:func:`~openerp.Widget.do_action` is a shortcut of :class:`~openerp.Widget`
+:func:`~odoo.Widget.do_action` is a shortcut of :class:`~odoo.Widget`
looking up the "current" action manager and executing the action::
instance.web.TestWidget = instance.Widget.extend({
@@ -1766,9 +1766,9 @@ Our widget is registered as the handler for the client action through this::
instance.web.client_actions.add('petstore.homepage', 'instance.oepetstore.HomePage');
-``instance.web.client_actions`` is a :class:`~openerp.web.Registry` in which
+``instance.web.client_actions`` is a :class:`~odoo.web.Registry` in which
the action manager looks up client action handlers when it needs to execute
-one. The first parameter of :class:`~openerp.web.Registry.add` is the name
+one. The first parameter of :class:`~odoo.web.Registry.add` is the name
(tag) of the client action, and the second parameter is the path to the widget
from the Odoo web client root.
@@ -1817,7 +1817,7 @@ The Views
'''''''''
Most :ref:`Odoo views ` are implemented through a subclass
-of :class:`openerp.web.View` which provides a bit of generic basic structure
+of :class:`odoo.web.View` which provides a bit of generic basic structure
for handling events and displaying model information.
The *search view* is considered a view type by the main Odoo framework, but
@@ -1825,17 +1825,17 @@ handled separately by the web client (as it's a more permanent fixture and
can interact with other views, which regular views don't do).
A view is responsible for loading its own description XML (using
-:py:class:`~openerp.models.Model.fields_view_get`) and any other data source
+:py:class:`~odoo.models.Model.fields_view_get`) and any other data source
it needs. To that purpose, views are provided with an optional view
-identifier set as the :attr:`~openerp.web.View.view_id` attribute.
+identifier set as the :attr:`~odoo.web.View.view_id` attribute.
-Views are also provided with a :class:`~openerp.web.DataSet` instance which
+Views are also provided with a :class:`~odoo.web.DataSet` instance which
holds most necessary model information (the model name and possibly various
record ids).
Views may also want to handle search queries by overriding
-:func:`~openerp.web.View.do_search`, and updating their
-:class:`~openerp.web.DataSet` as necessary.
+:func:`~odoo.web.View.do_search`, and updating their
+:class:`~odoo.web.DataSet` as necessary.
The Form View Fields
--------------------
@@ -1847,7 +1847,7 @@ All built-in fields have a default display implementation, a new
form widget may be necessary to correctly interact with a new field type
(e.g. a :term:`GIS` field) or to provide new representations and ways to
interact with existing field types (e.g. validate
-:py:class:`~openerp.fields.Char` fields which should contain email addresses
+:py:class:`~odoo.fields.Char` fields which should contain email addresses
and display them as email links).
To explicitly specify which form widget should be used to display a field,
@@ -2150,7 +2150,7 @@ abstract class.
Form widgets can interact with form fields by listening for their changes and
fetching or altering their values. They can access form fields through
-their :attr:`~openerp.web.form.FormWidget.field_manager` attribute::
+their :attr:`~odoo.web.form.FormWidget.field_manager` attribute::
local.WidgetMultiplication = instance.web.form.FormWidget.extend({
start: function() {
@@ -2168,14 +2168,14 @@ their :attr:`~openerp.web.form.FormWidget.field_manager` attribute::
instance.web.form.custom_widgets.add('multiplication', 'instance.oepetstore.WidgetMultiplication');
-:attr:`~openerp.web.form.FormWidget` is generally the
-:class:`~openerp.web.form.FormView` itself, but features used from it should
-be limited to those defined by :class:`~openerp.web.form.FieldManagerMixin`,
+:attr:`~odoo.web.form.FormWidget` is generally the
+:class:`~odoo.web.form.FormView` itself, but features used from it should
+be limited to those defined by :class:`~odoo.web.form.FieldManagerMixin`,
the most useful being:
-* :func:`~openerp.web.form.FieldManagerMixin.get_field_value(field_name)`
+* :func:`~odoo.web.form.FieldManagerMixin.get_field_value(field_name)`
which returns the value of a field.
-* :func:`~openerp.web.form.FieldManagerMixin.set_values(values)` sets multiple
+* :func:`~odoo.web.form.FieldManagerMixin.set_values(values)` sets multiple
field values, takes a mapping of ``{field_name: value_to_set}``
* An event :samp:`field_changed:{field_name}` is triggered any time the value
of the field called ``field_name`` is changed
diff --git a/doc/howtos/website.rst b/doc/howtos/website.rst
index 43c3a9a998a..51450f40e5a 100644
--- a/doc/howtos/website.rst
+++ b/doc/howtos/website.rst
@@ -26,7 +26,7 @@ module. To quickly get started simply invoke:
.. code-block:: console
- $ ./odoo.py scaffold Academy my-modules
+ $ ./odoo-bin scaffold Academy my-modules
This will automatically create a ``my-modules`` *module directory* with an
``academy`` module inside. The directory can be an existing module directory
@@ -46,7 +46,7 @@ Although it does absolutely nothing we can install it:
.. code-block:: console
- $ ./odoo.py --addons-path addons,my-modules
+ $ ./odoo-bin --addons-path addons,my-modules
* go to http://localhost:8069
* create a new database including demonstration data
@@ -70,7 +70,7 @@ Shut down your server (:kbd:`^C`) then restart it:
.. code-block:: console
- $ ./odoo.py --addons-path addons,my-modules
+ $ ./odoo-bin --addons-path addons,my-modules
and open a page to http://localhost:8069/academy/academy/, you should see your
"page" appear:
@@ -102,11 +102,11 @@ Academy` and clicking :guilabel:`Upgrade`.
.. tip::
Alternatively, Odoo can be restarted :option:`and update modules at
- the same time`:
+ the same time`:
.. code-block:: console
- $ odoo.py --addons-path addons,my-modules -d academy -u academy
+ $ odoo-bin --addons-path addons,my-modules -d academy -u academy
Going to http://localhost:8069/academy/academy/ should now result in:
@@ -174,7 +174,7 @@ Accessing the data
The last step is to alter model and template to use our demonstration data:
#. fetch the records from the database instead of having a static list
-#. Because :meth:`~openerp.models.Model.search` returns a set of records
+#. Because :meth:`~odoo.models.Model.search` returns a set of records
matching the filter ("all records" here), alter the template to print each
teacher's ``name``
@@ -231,7 +231,7 @@ URLs and routing
================
Controller methods are associated with *routes* via the
-:func:`~openerp.http.route` decorator which takes a routing string and a
+:func:`~odoo.http.route` decorator which takes a routing string and a
number of attributes to customise its behavior or security.
We've seen a "literal" routing string, which matches a URL section exactly,
@@ -384,7 +384,7 @@ let's also add views so we can see and edit a course's teacher:
It should also be possible to create new courses directly from a teacher's
page, or to see all the courses they teach, so add
-:class:`the inverse relationship ` to the *teachers*
+:class:`the inverse relationship ` to the *teachers*
model:
.. patch::
@@ -398,7 +398,7 @@ them by hand.
One of these is the *Chatter* system, part of Odoo's email and messaging
system, which can add notifications and discussion threads to any model.
-The model simply has to :attr:`~openerp.models.Model._inherit`
+The model simply has to :attr:`~odoo.models.Model._inherit`
``mail.thread``, and add the ``message_ids`` field to its form view to display
the discussion thread. Discussion threads are per-record.
@@ -443,8 +443,8 @@ though they may have to be looked for.
.. note::
* to extend a model in-place, it's :attr:`inherited
- ` without giving it a new
- :attr:`~openerp.models.Model._name`
+ ` without giving it a new
+ :attr:`~odoo.models.Model._name`
* ``product.template`` already uses the discussions system, so we can
remove it from our extension model
* we're creating our courses as *published* by default so they can be
diff --git a/doc/howtos/website/basic-controller b/doc/howtos/website/basic-controller
index 7b29c58f013..831ecf6fa25 100644
--- a/doc/howtos/website/basic-controller
+++ b/doc/howtos/website/basic-controller
@@ -7,7 +7,7 @@ diff --git a/academy/controllers.py b/academy/controllers.py
+++ b/academy/controllers.py
@@ -1,10 +1,10 @@
# -*- coding: utf-8 -*-
- from openerp import http
+ from odoo import http
-# class Academy(http.Controller):
-# @http.route('/academy/academy/', auth='public')
diff --git a/doc/howtos/website/basic-model b/doc/howtos/website/basic-model
index 4086c82b13d..a27d0543bce 100644
--- a/doc/howtos/website/basic-model
+++ b/doc/howtos/website/basic-model
@@ -7,7 +7,7 @@ diff --git a/academy/models.py b/academy/models.py
+++ b/academy/models.py
@@ -2,7 +2,7 @@
- from openerp import models, fields, api
+ from odoo import models, fields, api
-# class academy(models.Model):
-# _name = 'academy.academy'
diff --git a/doc/howtos/website/course-product b/doc/howtos/website/course-product
index b6f9bfedff7..f5b25e36068 100644
--- a/doc/howtos/website/course-product
+++ b/doc/howtos/website/course-product
@@ -18,12 +18,12 @@ new file mode 100644
--- /dev/null
+++ b/academy/data.xml
@@ -0,0 +1,6 @@
-+
++
+
+ Courses
+
+
-+
++
diff --git a/academy/demo.xml b/academy/demo.xml
--- a/academy/demo.xml
+++ b/academy/demo.xml
@@ -57,7 +57,7 @@ diff --git a/academy/demo.xml b/academy/demo.xml
+ service
+
-
+
diff --git a/academy/models.py b/academy/models.py
--- a/academy/models.py
+++ b/academy/models.py
diff --git a/doc/howtos/website/data-retrieval-orm b/doc/howtos/website/data-retrieval-orm
index 514777beb14..425ba41b4d0 100644
--- a/doc/howtos/website/data-retrieval-orm
+++ b/doc/howtos/website/data-retrieval-orm
@@ -5,7 +5,7 @@
diff --git a/academy/controllers.py b/academy/controllers.py
--- a/academy/controllers.py
+++ b/academy/controllers.py
-@@ -4,8 +4,9 @@ from openerp import http
+@@ -4,8 +4,9 @@ from odoo import http
class Academy(http.Controller):
@http.route('/academy/academy/', auth='public')
def index(self, **kw):
diff --git a/doc/howtos/website/demo-data b/doc/howtos/website/demo-data
index c8fb7d849ad..18da4bcdf79 100644
--- a/doc/howtos/website/demo-data
+++ b/doc/howtos/website/demo-data
@@ -6,7 +6,7 @@ diff --git a/academy/demo.xml b/academy/demo.xml
--- a/academy/demo.xml
+++ b/academy/demo.xml
@@ -1,25 +1,13 @@
-
+
-
-
@@ -39,4 +39,4 @@ diff --git a/academy/demo.xml b/academy/demo.xml
+ Lester Vaughn
+
-
+
diff --git a/doc/howtos/website/module-empty b/doc/howtos/website/module-empty
index 8a144e05d09..71d56e6fc71 100644
--- a/doc/howtos/website/module-empty
+++ b/doc/howtos/website/module-empty
@@ -21,7 +21,7 @@ new file mode 100644
+
+ 'summary': """
+ Short (1 phrase/line) summary of the module's purpose, used as
-+ subtitle on modules listing or apps.openerp.com""",
++ subtitle on modules listing or apps.odoo.com""",
+
+ 'description': """
+ Long description of module's purpose
@@ -31,7 +31,7 @@ new file mode 100644
+ 'website': "http://www.yourcompany.com",
+
+ # Categories can be used to filter modules in modules listing
-+ # Check https://github.com/odoo/odoo/blob/master/openerp/addons/base/module/module_data.xml
++ # Check https://github.com/odoo/odoo/blob/master/odoo/addons/base/module/module_data.xml
+ # for the full list
+ 'category': 'Uncategorized',
+ 'version': '0.1',
@@ -55,7 +55,7 @@ new file mode 100644
+++ b/academy/controllers.py
@@ -0,0 +1,20 @@
+# -*- coding: utf-8 -*-
-+from openerp import http
++from odoo import http
+
+# class Academy(http.Controller):
+# @http.route('/academy/academy/', auth='public')
@@ -79,7 +79,7 @@ new file mode 100644
--- /dev/null
+++ b/academy/demo.xml
@@ -0,0 +1,25 @@
-+
++
+
+
+
@@ -103,7 +103,7 @@ new file mode 100644
+
+
+
-+
++
diff --git a/academy/models.py b/academy/models.py
new file mode 100644
--- /dev/null
@@ -111,7 +111,7 @@ new file mode 100644
@@ -0,0 +1,8 @@
+# -*- coding: utf-8 -*-
+
-+from openerp import models, fields, api
++from odoo import models, fields, api
+
+# class academy(models.Model):
+# _name = 'academy.academy'
@@ -129,7 +129,7 @@ new file mode 100644
--- /dev/null
+++ b/academy/templates.xml
@@ -0,0 +1,22 @@
-+
++
+
+
+
@@ -150,4 +150,4 @@ new file mode 100644
+
+
+
-+
++
diff --git a/doc/howtos/website/teachers-menu b/doc/howtos/website/teachers-menu
index 27fd53b09aa..f5db4a0fd0e 100644
--- a/doc/howtos/website/teachers-menu
+++ b/doc/howtos/website/teachers-menu
@@ -18,7 +18,7 @@ new file mode 100644
--- /dev/null
+++ b/academy/views.xml
@@ -0,0 +1,13 @@
-+
++
+
+
+ Academy teachers
@@ -32,4 +32,4 @@ new file mode 100644
+ parent="menu_academy_content"
+ action="action_academy_teachers"/>
+
-+
++
diff --git a/doc/howtos/website/template b/doc/howtos/website/template
index 1647c16c1ba..541e39513fe 100644
--- a/doc/howtos/website/template
+++ b/doc/howtos/website/template
@@ -5,7 +5,7 @@
diff --git a/academy/controllers.py b/academy/controllers.py
--- a/academy/controllers.py
+++ b/academy/controllers.py
-@@ -4,7 +4,9 @@ from openerp import http
+@@ -4,7 +4,9 @@ from odoo import http
class Academy(http.Controller):
@http.route('/academy/academy/', auth='public')
def index(self, **kw):
@@ -20,7 +20,7 @@ diff --git a/academy/templates.xml b/academy/templates.xml
--- a/academy/templates.xml
+++ b/academy/templates.xml
@@ -1,14 +1,11 @@
-
+
-
-
diff --git a/doc/howtos/website/website-support b/doc/howtos/website/website-support
index c3deb4f6896..49b2d7e88d7 100644
--- a/doc/howtos/website/website-support
+++ b/doc/howtos/website/website-support
@@ -18,7 +18,7 @@ diff --git a/academy/controllers.py b/academy/controllers.py
--- a/academy/controllers.py
+++ b/academy/controllers.py
@@ -2,7 +2,7 @@
- from openerp import http
+ from odoo import http
class Academy(http.Controller):
- @http.route('/academy/academy/', auth='public')
@@ -30,7 +30,7 @@ diff --git a/academy/templates.xml b/academy/templates.xml
--- a/academy/templates.xml
+++ b/academy/templates.xml
@@ -1,9 +1,15 @@
-
+
- Academy
diff --git a/doc/images/rating_request.png b/doc/images/rating_request.png
new file mode 100644
index 00000000000..d82f69fd67c
Binary files /dev/null and b/doc/images/rating_request.png differ
diff --git a/doc/reference.rst b/doc/reference.rst
index a8ba63b7bfa..7e6e291b7d4 100644
--- a/doc/reference.rst
+++ b/doc/reference.rst
@@ -20,5 +20,6 @@ Reference
reference/translations
reference/reports
reference/workflows
+ reference/mixins
reference/guidelines
reference/upgrade_api
diff --git a/doc/reference/actions.rst b/doc/reference/actions.rst
index 7a796c59322..221c01ecfe6 100644
--- a/doc/reference/actions.rst
+++ b/doc/reference/actions.rst
@@ -52,7 +52,7 @@ Its fields are:
an optional database id (or ``False``). If no id is provided, the client
should fetch the default view of the specified type for the requested
model (this is automatically done by
- :meth:`~openerp.models.Model.fields_view_get`). The first type of the
+ :meth:`~odoo.models.Model.fields_view_get`). The first type of the
list is the default view type and will be open by default when the action
is executed. Each view type should be present at most once in the list
``res_id`` (optional)
@@ -248,8 +248,8 @@ from the UI, but not from :ref:`data files `.
``object_create``
-----------------
-Creates a new record, from scratch (via :meth:`~openerp.models.Model.create`)
-or by copying an existing record (via :meth:`~openerp.models.Model.copy`)
+Creates a new record, from scratch (via :meth:`~odoo.models.Model.create`)
+or by copying an existing record (via :meth:`~odoo.models.Model.copy`)
``use_create``
the creation policy, one of:
@@ -264,7 +264,7 @@ or by copying an existing record (via :meth:`~openerp.models.Model.copy`)
copies an other record, obtained via ``ref_object``
``fields_lines``
fields to override when creating or copying the record.
- :class:`~openerp.fields.One2many` with the fields:
+ :class:`~odoo.fields.One2many` with the fields:
``col1``
``ir.model.fields`` to set in the model implied by ``use_create``
@@ -278,7 +278,7 @@ or by copying an existing record (via :meth:`~openerp.models.Model.copy`)
model in which to create a new record, if ``use_create`` is set to
``new_other``
``ref_object``
- :class:`~openerp.fields.Reference` to an arbitrary record to copy, used if
+ :class:`~odoo.fields.Reference` to an arbitrary record to copy, used if
``use_create`` is set to ``copy_other``
``link_new_record``
boolean flag linking the newly created record to the current one via a
@@ -330,7 +330,7 @@ one will be returned to the client as the multi's own next action
Sends a signal to a workflow.
``wkf_transition_id``
- :class:`~openerp.fields.Many2one` to a ``workflow.transition`` to trigger
+ :class:`~odoo.fields.Many2one` to a ``workflow.transition`` to trigger
``use_relational_model``
if ``base`` (the default), trigger the signal on behalf of the current
record. If ``relational``, trigger the signal on behalf of a field of the
@@ -388,10 +388,10 @@ Triggers the printing of a report
``report_name``
the name of your report (which will be the name of the PDF output)
``groups_id``
- :class:`~openerp.fields.Many2many` field to the groups allowed to view/use
+ :class:`~odoo.fields.Many2many` field to the groups allowed to view/use
the current report
``paperformat_id``
- :class:`~openerp.fields.Many2one` field to the paper format you wish to
+ :class:`~odoo.fields.Many2one` field to the paper format you wish to
use for this report (if not specified, the company format will be used)
``attachment_use``
if set to ``True``, the report is only generated once the first time it is
diff --git a/doc/reference/cmdline.rst b/doc/reference/cmdline.rst
index a14956f2bea..6bd7502f201 100644
--- a/doc/reference/cmdline.rst
+++ b/doc/reference/cmdline.rst
@@ -3,7 +3,7 @@
.. _reference/cmdline:
===============================
-Command-line interface: odoo.py
+Command-line interface: odoo-bin
===============================
.. _reference/cmdline/server:
@@ -11,7 +11,7 @@ Command-line interface: odoo.py
Running the server
==================
-.. program:: odoo.py
+.. program:: odoo-bin
.. option:: -d , --database
@@ -228,7 +228,7 @@ customize the amount of logging output
.. option:: --log-handler
:samp:`{LOGGER}:{LEVEL}`, enables ``LOGGER`` at the provided ``LEVEL``
- e.g. ``openerp.models:DEBUG`` will enable all logging messages at or above
+ e.g. ``odoo.models:DEBUG`` will enable all logging messages at or above
``DEBUG`` level in the models.
* The colon ``:`` is mandatory
@@ -239,34 +239,34 @@ customize the amount of logging output
.. code-block:: console
- $ odoo.py --log-handler :DEBUG --log-handler werkzeug:CRITICAL --log-handler openerp.fields:WARNING
+ $ odoo-bin --log-handler :DEBUG --log-handler werkzeug:CRITICAL --log-handler odoo.fields:WARNING
.. option:: --log-request
enable DEBUG logging for RPC requests, equivalent to
- ``--log-handler=openerp.http.rpc.request:DEBUG``
+ ``--log-handler=odoo.http.rpc.request:DEBUG``
.. option:: --log-response
enable DEBUG logging for RPC responses, equivalent to
- ``--log-handler=openerp.http.rpc.response:DEBUG``
+ ``--log-handler=odoo.http.rpc.response:DEBUG``
.. option:: --log-web
enables DEBUG logging of HTTP requests and responses, equivalent to
- ``--log-handler=openerp.http:DEBUG``
+ ``--log-handler=odoo.http:DEBUG``
.. option:: --log-sql
enables DEBUG logging of SQL querying, equivalent to
- ``--log-handler=openerp.sql_db:DEBUG``
+ ``--log-handler=odoo.sql_db:DEBUG``
.. option:: --log-level
Shortcut to more easily set predefined levels on specific loggers. "real"
levels (``critical``, ``error``, ``warn``, ``debug``) are set on the
- ``openerp`` and ``werkzeug`` loggers (except for ``debug`` which is only
- set on ``openerp``).
+ ``odoo`` and ``werkzeug`` loggers (except for ``debug`` which is only
+ set on ``odoo``).
Odoo also provides debugging pseudo-levels which apply to different sets
of loggers:
@@ -276,11 +276,11 @@ customize the amount of logging output
equivalent to ``--log-sql``
``debug_rpc``
- sets the ``openerp`` and HTTP request loggers to ``debug``
+ sets the ``odoo`` and HTTP request loggers to ``debug``
equivalent to ``--log-level debug --log-request``
``debug_rpc_answer``
- sets the ``openerp`` and HTTP request and response loggers to
+ sets the ``odoo`` and HTTP request and response loggers to
``debug``
equivalent to ``--log-level debug --log-request --log-response``
@@ -296,14 +296,14 @@ customize the amount of logging output
Scaffolding
===========
-.. program:: odoo.py scaffold
+.. program:: odoo-bin scaffold
Scaffolding is the automated creation of a skeleton structure to simplify
bootstrapping (of new modules, in the case of Odoo). While not necessary it
avoids the tedium of setting up basic structures and looking up what all
starting requirements are.
-Scaffolding is available via the :command:`odoo.py scaffold` subcommand.
+Scaffolding is available via the :command:`odoo-bin scaffold` subcommand.
.. option:: -t
@@ -344,8 +344,8 @@ Some conversions don't match the pattern:
from configuration files
The default configuration file is :file:`{$HOME}/.odoorc` which
-can be overridden using :option:`--config `. Specifying
-:option:`--save ` will save the current configuration state back
+can be overridden using :option:`--config `. Specifying
+:option:`--save ` will save the current configuration state back
to that file.
.. _jinja2: http://jinja.pocoo.org
diff --git a/doc/reference/data.rst b/doc/reference/data.rst
index cb17b7e866a..0b2338b6633 100644
--- a/doc/reference/data.rst
+++ b/doc/reference/data.rst
@@ -77,13 +77,13 @@ Nothing
Will evaluate the domain, search the field's model using it and set the
search's result as the field's value. Will only use the first result if
- the field is a :class:`~openerp.fields.Many2one`
+ the field is a :class:`~odoo.fields.Many2one`
``ref``
if a ``ref`` attribute is provided, its value must be a valid
:term:`external id`, which will be looked up and set as the field's value.
- Mostly for :class:`~openerp.fields.Many2one` and
- :class:`~openerp.fields.Reference` fields
+ Mostly for :class:`~odoo.fields.Many2one` and
+ :class:`~odoo.fields.Reference` fields
``type``
if a ``type`` attribute is provided, it is used to interpret and convert
the field's content. The field's content can be provided through an
@@ -253,14 +253,14 @@ For this case, data files can also use csv_, this is often the case for
Here's the first lines of the data file defining US states
``res.country.state.csv``
-.. literalinclude:: ../../openerp/addons/base/res/res.country.state.csv
+.. literalinclude:: ../../odoo/addons/base/res/res.country.state.csv
:language: text
:lines: 1-15
rendered in a more readable format:
.. csv-table::
- :file: ../../openerp/addons/base/res/res.country.state.csv
+ :file: ../../odoo/addons/base/res/res.country.state.csv
:header-rows: 1
:class: table-striped table-hover table-condensed
diff --git a/doc/reference/guidelines.rst b/doc/reference/guidelines.rst
index 8a1831c469d..aa691311cd2 100644
--- a/doc/reference/guidelines.rst
+++ b/doc/reference/guidelines.rst
@@ -902,7 +902,7 @@ Javascript and CSS
.. code-block:: javascript
- openerp.website.if_dom_contains('.jquery_class_selector', function () {
+ odoo.website.if_dom_contains('.jquery_class_selector', function () {
/*your code here*/
});
diff --git a/doc/reference/http.rst b/doc/reference/http.rst
index e6946beda49..9dbb61f7727 100644
--- a/doc/reference/http.rst
+++ b/doc/reference/http.rst
@@ -9,28 +9,28 @@ Web Controllers
Routing
=======
-.. autofunction:: openerp.http.route
+.. autofunction:: odoo.http.route
.. _reference/http/request:
Request
=======
-The request object is automatically set on :data:`openerp.http.request` at
+The request object is automatically set on :data:`odoo.http.request` at
the start of the request
-.. autoclass:: openerp.http.WebRequest
+.. autoclass:: odoo.http.WebRequest
:members:
:member-order: bysource
-.. autoclass:: openerp.http.HttpRequest
+.. autoclass:: odoo.http.HttpRequest
:members:
-.. autoclass:: openerp.http.JsonRequest
+.. autoclass:: odoo.http.JsonRequest
:members:
Response
========
-.. autoclass:: openerp.http.Response
+.. autoclass:: odoo.http.Response
:members:
:member-order: bysource
@@ -44,7 +44,7 @@ Controllers
===========
Controllers need to provide extensibility, much like
-:class:`~openerp.models.Model`, but can't use the same mechanism as the
+:class:`~odoo.models.Model`, but can't use the same mechanism as the
pre-requisites (a database with loaded modules) may not be available yet (e.g.
no database created, or no database selected).
@@ -53,11 +53,11 @@ models:
Controllers are created by :ref:`inheriting ` from
-.. autoclass:: openerp.http.Controller
+.. autoclass:: odoo.http.Controller
-and defining methods decorated with :func:`~openerp.http.route`::
+and defining methods decorated with :func:`~odoo.http.route`::
- class MyController(openerp.http.Controller):
+ class MyController(odoo.http.Controller):
@route('/some_url', auth='public')
def handler(self):
return stuff()
@@ -71,7 +71,7 @@ class and override relevant methods, re-exposing them if necessary::
do_before()
return super(Extension, self).handler()
-* decorating with :func:`~openerp.http.route` is necessary to keep the method
+* decorating with :func:`~odoo.http.route` is necessary to keep the method
(and route) visible: if the method is redefined without decorating, it
will be "unpublished"
* the decorators of all methods are combined, if the overriding method's
diff --git a/doc/reference/javascript.rst b/doc/reference/javascript.rst
index 342d8484b67..2a1e2b3a018 100644
--- a/doc/reference/javascript.rst
+++ b/doc/reference/javascript.rst
@@ -457,8 +457,8 @@ with three differences:
:func:`~Model.query` is a shortcut for a builder-style
interface to searches (``search`` + ``read`` in Odoo RPC terms). It
-returns a :class:`~openerp.web.Query` object which is immutable but
-allows building new :class:`~openerp.web.Query` instances from the
+returns a :class:`~odoo.web.Query` object which is immutable but
+allows building new :class:`~odoo.web.Query` instances from the
first one, adding new properties or modifiying the parent object's::
Users.query(['name', 'login', 'user_email', 'signature'])
@@ -469,8 +469,8 @@ first one, adding new properties or modifiying the parent object's::
});
The query is only actually performed when calling one of the query
-serialization methods, :func:`~openerp.web.Query.all` and
-:func:`~openerp.web.Query.first`. These methods will perform a new
+serialization methods, :func:`~odoo.web.Query.all` and
+:func:`~odoo.web.Query.first`. These methods will perform a new
RPC call every time they are called.
For that reason, it's actually possible to keep "intermediate" queries
@@ -499,38 +499,38 @@ around and use them differently/add new specifications on them.
:param Array fields: list of fields to fetch during
the search
- :returns: a :class:`~openerp.web.Query` object
+ :returns: a :class:`~odoo.web.Query` object
representing the search to perform
-.. class:: openerp.web.Query(fields)
+.. class:: odoo.web.Query(fields)
The first set of methods is the "fetching" methods. They perform
RPC queries using the internal data of the object they're called
on.
- .. function:: openerp.web.Query.all()
+ .. function:: odoo.web.Query.all()
- Fetches the result of the current :class:`~openerp.web.Query` object's
+ Fetches the result of the current :class:`~odoo.web.Query` object's
search.
:rtype: Deferred>
- .. function:: openerp.web.Query.first()
+ .. function:: odoo.web.Query.first()
Fetches the **first** result of the current
- :class:`~openerp.web.Query`, or ``null`` if the current
- :class:`~openerp.web.Query` does have any result.
+ :class:`~odoo.web.Query`, or ``null`` if the current
+ :class:`~odoo.web.Query` does have any result.
:rtype: Deferred
@@ -173,7 +175,9 @@
+ attrs="{'readonly': [('type', '=', 'contact'),('parent_id', '!=', False)]}"
+ context="{'country_id': country_id, 'zip': zip}"
+ domain="[('country_id', '=', country_id')]"/>
=',rec.parent_left)]
doms = []
@@ -739,7 +739,7 @@ class expression(object):
""" Return a domain implementing the parent_of operator for [(left,parent_of,ids)],
either as a range using the parent_left/right tree lookup fields
(when available), or as an expanded [(left,in,parent_ids)] """
- if left_model._parent_store and (not left_model.pool._init):
+ if left_model._parent_store and (not left_model.pool._init) and (not context.get('defer_parent_store_computation')):
doms = []
for rec in left_model.browse(ids):
if doms:
diff --git a/odoo/release.py b/odoo/release.py
index dc4fb406a0a..2c495dca13f 100644
--- a/odoo/release.py
+++ b/odoo/release.py
@@ -12,7 +12,7 @@ RELEASE_LEVELS_DISPLAY = {ALPHA: ALPHA,
# properly comparable using normal operarors, for example:
# (6,1,0,'beta',0) < (6,1,0,'candidate',1) < (6,1,0,'candidate',2)
# (6,1,0,'candidate',2) < (6,1,0,'final',0) < (6,1,2,'final',0)
-version_info = (11, 0, 0, ALPHA, 1, 'c')
+version_info = (11, 0, 0, ALPHA, 1, '')
version = '.'.join(map(str, version_info[:2])) + RELEASE_LEVELS_DISPLAY[version_info[3]] + str(version_info[4] or '') + version_info[5]
series = serie = major_version = '.'.join(map(str, version_info[:2]))
diff --git a/odoo/tools/config.py b/odoo/tools/config.py
index 07af83e7e3e..5584002c520 100644
--- a/odoo/tools/config.py
+++ b/odoo/tools/config.py
@@ -443,7 +443,7 @@ class configmanager(object):
for x in self.options['addons_path'].split(','))
self.options['init'] = opt.init and dict.fromkeys(opt.init.split(','), 1) or {}
- self.options['demo'] = (self.options['init']
+ self.options['demo'] = (dict(self.options['init'])
if not self.options['without_demo'] else {})
self.options['update'] = opt.update and dict.fromkeys(opt.update.split(','), 1) or {}
self.options['translate_modules'] = opt.translate_modules and map(lambda m: m.strip(), opt.translate_modules.split(',')) or ['all']
diff --git a/odoo/tools/convert.py b/odoo/tools/convert.py
index 3c3eba3bec6..0d0b14ab341 100644
--- a/odoo/tools/convert.py
+++ b/odoo/tools/convert.py
@@ -26,11 +26,8 @@ from odoo import SUPERUSER_ID
_logger = logging.getLogger(__name__)
-# Import of XML records requires the unsafe eval as well,
-# almost everywhere, which is ok because it supposedly comes
-# from trusted data, but at least we make it obvious now.
-unsafe_eval = eval
-from .safe_eval import safe_eval
+from .safe_eval import safe_eval as s_eval
+safe_eval = lambda expr, ctx={}: s_eval(expr, ctx, nocopy=True)
class ParseError(Exception):
def __init__(self, msg, text, filename, lineno):
@@ -98,7 +95,7 @@ def _eval_xml(self, node, env):
idref2 = {}
if f_search:
idref2 = _get_idref(self, env, f_model, self.idref)
- q = unsafe_eval(f_search, idref2)
+ q = safe_eval(f_search, idref2)
ids = env[f_model].search(q).ids
if f_use != 'id':
ids = map(lambda x: x[f_use], env[f_model].browse(ids).read([f_use]))
@@ -115,7 +112,7 @@ def _eval_xml(self, node, env):
if a_eval:
idref2 = _get_idref(self, env, f_model, self.idref)
try:
- return unsafe_eval(a_eval, idref2)
+ return safe_eval(a_eval, idref2)
except Exception:
logging.getLogger('odoo.tools.convert.init').error(
'Could not eval(%s) for %s in %s', a_eval, node.get('name'), env.context)
@@ -183,7 +180,7 @@ def _eval_xml(self, node, env):
# FIXME: should probably be exclusive
if a_eval:
self.idref['ref'] = self.id_get
- args = unsafe_eval(a_eval, self.idref)
+ args = safe_eval(a_eval, self.idref)
for n in node:
return_val = _eval_xml(self, n, env)
if return_val is not None:
@@ -221,12 +218,12 @@ class xml_import(object):
for ctx in (data_node_context, node_context):
if ctx:
try:
- ctx_res = unsafe_eval(ctx, eval_dict)
+ ctx_res = safe_eval(ctx, eval_dict)
if isinstance(context, dict):
context.update(ctx_res)
else:
context = ctx_res
- except NameError:
+ except (ValueError, NameError):
# Some contexts contain references that are only valid at runtime at
# client-side, so in that case we keep the original context string
# as it is. We also log it, just in case.
@@ -265,7 +262,7 @@ form: module.record_id""" % (xml_id,)
if d_search:
idref = _get_idref(self, self.env, d_model, {})
try:
- records = records.search(unsafe_eval(d_search, idref))
+ records = records.search(safe_eval(d_search, idref))
except ValueError:
_logger.warning('Skipping deletion for failed search `%r`', d_search, exc_info=True)
pass
@@ -402,8 +399,8 @@ form: module.record_id""" % (xml_id,)
context = self.get_context(data_node, rec, eval_context)
try:
- domain = unsafe_eval(domain, eval_context)
- except NameError:
+ domain = safe_eval(domain, eval_context)
+ except (ValueError, NameError):
# Some domains contain references that are only valid at runtime at
# client-side, so in that case we keep the original domain string
# as it is. We also log it, just in case.
@@ -587,7 +584,7 @@ form: module.record_id""" % (xml_id,)
if rec_id:
records = env[rec_model].browse(self.id_get(rec_id))
elif rec_src:
- q = unsafe_eval(rec_src, eval_dict)
+ q = safe_eval(rec_src, eval_dict)
records = env[rec_model].search(q)
if rec_src_count:
count = int(rec_src_count)
@@ -613,7 +610,7 @@ form: module.record_id""" % (xml_id,)
f_expr = test.get("expr",'').encode('utf-8')
env = self.env(user=uid, context=context)
expected_value = _eval_xml(self, test, env) or True
- expression_value = unsafe_eval(f_expr, globals_dict)
+ expression_value = safe_eval(f_expr, globals_dict)
if expression_value != expected_value: # assertion failed
self.assertion_report.record_failure()
msg = 'assertion "%s" failed!\n' \
@@ -632,7 +629,7 @@ form: module.record_id""" % (xml_id,)
rec_id = rec.get("id",'').encode('ascii')
rec_context = rec.get("context", {})
if rec_context:
- rec_context = unsafe_eval(rec_context)
+ rec_context = safe_eval(rec_context)
if self.xml_filename and rec_id:
rec_context['install_mode_data'] = dict(
@@ -680,7 +677,7 @@ form: module.record_id""" % (xml_id,)
f_val = False
if f_search:
- q = unsafe_eval(f_search, self.idref)
+ q = safe_eval(f_search, self.idref)
assert f_model, 'Define an attribute model="..." in your .XML file !'
# browse the objects searched
s = self.env[f_model].search(q)
diff --git a/odoo/tools/misc.py b/odoo/tools/misc.py
index 533b7277119..1c4cc68283c 100644
--- a/odoo/tools/misc.py
+++ b/odoo/tools/misc.py
@@ -340,13 +340,13 @@ try:
# add some sanitizations to respect the excel sheet name restrictions
# as the sheet name is often translatable, can not control the input
class PatchedWorkbook(xlwt.Workbook):
- def add_sheet(self, name):
+ def add_sheet(self, name, cell_overwrite_ok=False):
# invalid Excel character: []:*?/\
name = re.sub(r'[\[\]:*?/\\]', '', name)
# maximum size is 31 characters
name = name[:31]
- return super(PatchedWorkbook, self).add_sheet(name)
+ return super(PatchedWorkbook, self).add_sheet(name, cell_overwrite_ok=cell_overwrite_ok)
xlwt.Workbook = PatchedWorkbook
diff --git a/setup/package.py b/setup/package.py
index d5bd0564423..6dedb2b78d8 100755
--- a/setup/package.py
+++ b/setup/package.py
@@ -24,6 +24,7 @@ from tempfile import NamedTemporaryFile
#----------------------------------------------------------
execfile(join(dirname(__file__), '..', 'odoo', 'release.py'))
version = version.split('-')[0]
+docker_version = version.replace('+', '')
timestamp = time.strftime("%Y%m%d", time.gmtime())
GPGPASSPHRASE = os.getenv('GPGPASSPHRASE')
GPGID = os.getenv('GPGID')
@@ -279,7 +280,7 @@ def _prepare_testing(o):
# Use rsync to copy requirements.txt in order to keep original permissions
subprocess.call(["rsync", "-a", "requirements.txt", os.path.join(o.build_dir, "docker_src")],
cwd=os.path.join(o.odoo_dir))
- subprocess.call(["docker", "build", "-t", "odoo-%s-src-nightly-tests" % version, "."],
+ subprocess.call(["docker", "build", "-t", "odoo-%s-src-nightly-tests" % docker_version, "."],
cwd=os.path.join(o.build_dir, "docker_src"))
if not o.no_debian:
subprocess.call(["mkdir", "docker_debian"], cwd=o.build_dir)
@@ -288,17 +289,17 @@ def _prepare_testing(o):
# Use rsync to copy requirements.txt in order to keep original permissions
subprocess.call(["rsync", "-a", "requirements.txt", os.path.join(o.build_dir, "docker_debian")],
cwd=os.path.join(o.odoo_dir))
- subprocess.call(["docker", "build", "-t", "odoo-%s-debian-nightly-tests" % version, "."],
+ subprocess.call(["docker", "build", "-t", "odoo-%s-debian-nightly-tests" % docker_version, "."],
cwd=os.path.join(o.build_dir, "docker_debian"))
if not o.no_rpm:
subprocess.call(["mkdir", "docker_fedora"], cwd=o.build_dir)
subprocess.call(["cp", "package.dffedora", os.path.join(o.build_dir, "docker_fedora", "Dockerfile")],
cwd=os.path.join(o.odoo_dir, "setup"))
- subprocess.call(["docker", "build", "-t", "odoo-%s-fedora-nightly-tests" % version, "."],
+ subprocess.call(["docker", "build", "-t", "odoo-%s-fedora-nightly-tests" % docker_version, "."],
cwd=os.path.join(o.build_dir, "docker_fedora"))
def test_tgz(o):
- with docker('odoo-%s-src-nightly-tests' % version, o.build_dir, o.pub) as wheezy:
+ with docker('odoo-%s-src-nightly-tests' % docker_version, o.build_dir, o.pub) as wheezy:
wheezy.release = '*.tar.gz'
wheezy.system("service postgresql start")
wheezy.system('pip install /opt/release/%s' % wheezy.release)
@@ -311,7 +312,7 @@ def test_tgz(o):
wheezy.system('su odoo -s /bin/bash -c "odoo --addons-path=/usr/local/lib/python2.7/dist-packages/odoo/addons -d mycompany &"')
def test_deb(o):
- with docker('odoo-%s-debian-nightly-tests' % version, o.build_dir, o.pub) as wheezy:
+ with docker('odoo-%s-debian-nightly-tests' % docker_version, o.build_dir, o.pub) as wheezy:
wheezy.release = '*.deb'
wheezy.system("service postgresql start")
wheezy.system('su postgres -s /bin/bash -c "createdb mycompany"')
@@ -321,7 +322,7 @@ def test_deb(o):
wheezy.system('su odoo -s /bin/bash -c "odoo -c /etc/odoo/odoo.conf -d mycompany &"')
def test_rpm(o):
- with docker('odoo-%s-fedora-nightly-tests' % version, o.build_dir, o.pub) as fedora24:
+ with docker('odoo-%s-fedora-nightly-tests' % docker_version, o.build_dir, o.pub) as fedora24:
fedora24.release = '*.noarch.rpm'
# Start postgresql
fedora24.system('su postgres -c "/usr/bin/pg_ctl -D /var/lib/postgres/data start"')