diff --git a/addons/account/report/account_aged_partner_balance.py b/addons/account/report/account_aged_partner_balance.py index fd2fef466fb..d280b6cb850 100644 --- a/addons/account/report/account_aged_partner_balance.py +++ b/addons/account/report/account_aged_partner_balance.py @@ -27,7 +27,7 @@ class ReportAgedPartnerBalance(models.AbstractModel): res = [] total = [] cr = self.env.cr - user_company = self.env.user.company_id.id + company_ids = self.env.context.get('company_ids', (self.env.user.company_id.id,)) move_state = ['draft', 'posted'] if target_move == 'posted': move_state = ['posted'] @@ -41,7 +41,7 @@ class ReportAgedPartnerBalance(models.AbstractModel): if reconciled_after_date: reconciliation_clause = '(l.reconciled IS FALSE OR l.id IN %s)' arg_list += (tuple(reconciled_after_date),) - arg_list += (date_from, user_company) + arg_list += (date_from, tuple(company_ids)) query = ''' SELECT DISTINCT l.partner_id, UPPER(res_partner.name) FROM account_move_line AS l left join res_partner on l.partner_id = res_partner.id, account_account, account_move am @@ -51,7 +51,7 @@ class ReportAgedPartnerBalance(models.AbstractModel): AND (account_account.internal_type IN %s) AND ''' + reconciliation_clause + ''' AND (l.date <= %s) - AND l.company_id = %s + AND l.company_id IN %s ORDER BY UPPER(res_partner.name)''' cr.execute(query, arg_list) @@ -76,8 +76,8 @@ class ReportAgedPartnerBalance(models.AbstractModel): AND (COALESCE(l.date_maturity,l.date) > %s)\ AND ((l.partner_id IN %s) OR (l.partner_id IS NULL)) AND (l.date <= %s) - AND l.company_id = %s''' - cr.execute(query, (tuple(move_state), tuple(account_type), date_from, tuple(partner_ids), date_from, user_company)) + AND l.company_id IN %s''' + cr.execute(query, (tuple(move_state), tuple(account_type), date_from, tuple(partner_ids), date_from, tuple(company_ids))) aml_ids = cr.fetchall() aml_ids = aml_ids and [x[0] for x in aml_ids] or [] for line in self.env['account.move.line'].browse(aml_ids): @@ -117,7 +117,7 @@ class ReportAgedPartnerBalance(models.AbstractModel): else: dates_query += ' <= %s)' args_list += (periods[str(i)]['stop'],) - args_list += (date_from, user_company) + args_list += (date_from, tuple(company_ids)) query = '''SELECT l.id FROM account_move_line AS l, account_account, account_move am @@ -127,7 +127,7 @@ class ReportAgedPartnerBalance(models.AbstractModel): AND ((l.partner_id IN %s) OR (l.partner_id IS NULL)) AND ''' + dates_query + ''' AND (l.date <= %s) - AND l.company_id = %s''' + AND l.company_id IN %s''' cr.execute(query, args_list) partners_amount = {} aml_ids = cr.fetchall() diff --git a/addons/base_gengo/wizard/base_gengo_translations.py b/addons/base_gengo/wizard/base_gengo_translations.py index 0a585934af8..43d2e81ca33 100644 --- a/addons/base_gengo/wizard/base_gengo_translations.py +++ b/addons/base_gengo/wizard/base_gengo_translations.py @@ -62,9 +62,9 @@ class BaseGengoTranslations(models.TransientModel): 'type': 'ir.actions.act_window', 'view_type': 'form', 'view_mode': 'form', - 'res_model': 'res.company', - 'res_id': self.env.user.company_id.id, + 'res_model': 'res.config.settings', 'target': 'current', + 'context': {'module' : 'general_settings'}, } @api.model diff --git a/addons/bus/static/src/js/bus.js b/addons/bus/static/src/js/bus.js index 25a8b86903f..73b69013389 100644 --- a/addons/bus/static/src/js/bus.js +++ b/addons/bus/static/src/js/bus.js @@ -76,7 +76,8 @@ bus.Bus = Widget.extend({ this.last_partners_presence_check = now; } var data = {channels: self.channels, last: self.last, options: options}; - session.rpc('/longpolling/poll', data, {shadow : true}).then(function(result) { + // The backend has a maximum cycle time of 50 seconds so give +10 seconds + session.rpc('/longpolling/poll', data, {shadow : true, timeout: 60000}).then(function(result) { self.on_notification(result); if(!self.stop){ self.poll(); diff --git a/addons/crm/security/crm_security.xml b/addons/crm/security/crm_security.xml index 235d6854f93..83f3197a5b1 100644 --- a/addons/crm/security/crm_security.xml +++ b/addons/crm/security/crm_security.xml @@ -34,16 +34,6 @@ ['|',('company_id','=',False),('company_id','child_of',[user.company_id.id])] - - Leads with assigned activities - - [('activity_ids.user_id','=',user.id)] - - - - - - All Leads diff --git a/addons/hr_expense/models/hr_expense.py b/addons/hr_expense/models/hr_expense.py index 5380365b501..2ed20b6a7c5 100644 --- a/addons/hr_expense/models/hr_expense.py +++ b/addons/hr_expense/models/hr_expense.py @@ -524,7 +524,7 @@ class HrExpenseSheet(models.Model): @api.onchange('employee_id') def _onchange_employee_id(self): - self.address_id = self.employee_id.address_home_id + self.address_id = self.employee_id.sudo().address_home_id self.department_id = self.employee_id.department_id @api.depends('expense_line_ids.total_amount_company') diff --git a/addons/hr_expense/views/hr_expense_views.xml b/addons/hr_expense/views/hr_expense_views.xml index 28a852af5df..c323a71a637 100644 --- a/addons/hr_expense/views/hr_expense_views.xml +++ b/addons/hr_expense/views/hr_expense_views.xml @@ -61,7 +61,7 @@ - + diff --git a/addons/hr_holidays/models/hr.py b/addons/hr_holidays/models/hr.py index e74e60f314d..bf8fbddd5ea 100644 --- a/addons/hr_holidays/models/hr.py +++ b/addons/hr_holidays/models/hr.py @@ -218,7 +218,12 @@ class Employee(models.Model): def write(self, values): res = super(Employee, self).write(values) - if 'parent_id' in values: + if 'parent_id' in values or 'department_id' in values: holidays = self.env['hr.holidays'].search([('state', 'in', ['draft', 'confirm']), ('employee_id', 'in', self.ids)]) - holidays.write({'manager_id': values['parent_id']}) + hr_vals = {} + if values.get('parent_id') is not None: + hr_vals['manager_id'] = values['parent_id'] + if values.get('department_id') is not None: + hr_vals['department_id'] = values['department_id'] + holidays.write(hr_vals) return res diff --git a/addons/hr_holidays/models/hr_holidays.py b/addons/hr_holidays/models/hr_holidays.py index 51664bc1db6..e8672298603 100644 --- a/addons/hr_holidays/models/hr_holidays.py +++ b/addons/hr_holidays/models/hr_holidays.py @@ -217,6 +217,7 @@ class Holidays(models.Model): @api.onchange('employee_id') def _onchange_employee_id(self): self.manager_id = self.employee_id and self.employee_id.parent_id + self.department_id = self.employee_id and self.employee_id.department_id @api.multi @api.depends('number_of_days_temp', 'type') diff --git a/addons/hr_payroll_account/models/hr_payroll_account.py b/addons/hr_payroll_account/models/hr_payroll_account.py index e76173d45a4..da168912095 100644 --- a/addons/hr_payroll_account/models/hr_payroll_account.py +++ b/addons/hr_payroll_account/models/hr_payroll_account.py @@ -158,7 +158,6 @@ class HrContract(models.Model): class HrPayslipRun(models.Model): _inherit = 'hr.payslip.run' - _description = 'Payslip Run' journal_id = fields.Many2one('account.journal', 'Salary Journal', states={'draft': [('readonly', False)]}, readonly=True, required=True, default=lambda self: self.env['account.journal'].search([('type', '=', 'general')], limit=1)) diff --git a/addons/l10n_be_hr_payroll/data/l10n_be_hr_payroll_data.xml b/addons/l10n_be_hr_payroll/data/l10n_be_hr_payroll_data.xml index 14ad3eaefa0..0f6bb86479f 100644 --- a/addons/l10n_be_hr_payroll/data/l10n_be_hr_payroll_data.xml +++ b/addons/l10n_be_hr_payroll/data/l10n_be_hr_payroll_data.xml @@ -545,7 +545,6 @@ result = -contract.car_atn ref('hr_salary_rule_representation_fees'), ref('hr_payroll_rules_suppl_net'), ref('hr_payroll_rules_retained_net'), - ref('hr_salary_rule_commission_on_target'), ref('hr_salary_rule_pp_reduction_employees'), ])]" name="rule_ids"/> @@ -571,7 +570,6 @@ result = -contract.car_atn ref('hr_salary_rule_representation_fees'), ref('hr_payroll_rules_suppl_net'), ref('hr_payroll_rules_retained_net'), - ref('hr_salary_rule_commission_on_target'), ref('hr_salary_rule_pp_reduction_workers') ])]" name="rule_ids"/> diff --git a/addons/l10n_be_hr_payroll/models/l10n_be_hr_payroll.py b/addons/l10n_be_hr_payroll/models/l10n_be_hr_payroll.py index c80ccc983a5..6174699920c 100644 --- a/addons/l10n_be_hr_payroll/models/l10n_be_hr_payroll.py +++ b/addons/l10n_be_hr_payroll/models/l10n_be_hr_payroll.py @@ -116,8 +116,8 @@ class HrContract(models.Model): @api.depends('commission_on_target') def _compute_warrants_cost(self): for contract in self: - contract.warrants_cost = contract.commission_on_target * 1.326 / 1.05 * 12.0 - contract.warrant_value_employee = contract.warrants_cost * 0.54 + contract.warrants_cost = contract.commission_on_target * 1.05 * 12.0 + contract.warrant_value_employee = contract.commission_on_target * (1.00 - 0.535) * 12.0 @api.depends('wage', 'fuel_card', 'representation_fees', 'transport_employer_cost', 'internet', 'mobile', 'mobile_plus') @@ -230,7 +230,7 @@ class HrContract(models.Model): - 12.0 * contract.internet \ - 12.0 * (contract.mobile + contract.mobile_plus) \ - 12.0 * contract.transport_employer_cost \ - - (1.326 / 1.05 * 12.0) * contract.commission_on_target \ + - contract.warrants_cost \ - 220.0 * contract.meal_voucher_paid_by_employer gross = remaining_for_gross / (13.0 + 13.0 * 0.3507 + 0.92) return gross diff --git a/addons/mail/models/ir_model.py b/addons/mail/models/ir_model.py index 3a312cfe843..04529610f0e 100644 --- a/addons/mail/models/ir_model.py +++ b/addons/mail/models/ir_model.py @@ -74,6 +74,6 @@ class IrModelField(models.Model): def _instanciate_attrs(self, field_data): attrs = super(IrModelField, self)._instanciate_attrs(field_data) - if field_data.get('track_visibility'): + if attrs and field_data.get('track_visibility'): attrs['track_visibility'] = field_data['track_visibility'] return attrs diff --git a/addons/mail/models/mail_channel.py b/addons/mail/models/mail_channel.py index f4e79cbf8eb..e24a3193f97 100644 --- a/addons/mail/models/mail_channel.py +++ b/addons/mail/models/mail_channel.py @@ -211,7 +211,7 @@ class Channel(models.Model): # http://blogs.technet.com/b/exchange/archive/2006/10/06/3395024.aspx headers['X-Auto-Response-Suppress'] = 'OOF' if self.alias_domain and self.alias_name: - headers['List-Id'] = '%s.%s' % (self.alias_name, self.alias_domain) + headers['List-Id'] = '<%s.%s>' % (self.alias_name, self.alias_domain) headers['List-Post'] = '' % (self.alias_name, self.alias_domain) # Avoid users thinking it was a personal message # X-Forge-To: will replace To: after SMTP envelope is determined by ir.mail.server @@ -505,7 +505,15 @@ class Channel(models.Model): partners_to_add = partners - channel.channel_partner_ids channel.write({'channel_last_seen_partner_ids': [(0, 0, {'partner_id': partner_id}) for partner_id in partners_to_add.ids]}) for partner in partners_to_add: - notification = _('
joined #%s
') % (self.id, self.name,) + if partner.id != self.env.user.partner_id.id: + notification = _('
%(author)s invited %(new_partner)s to #%(channel_name)s
') % { + 'author': self.env.user.display_name, + 'new_partner': partner.display_name, + 'channel_id': channel.id, + 'channel_name': channel.name, + } + else: + notification = _('
joined #%s
') % (channel.id, channel.name,) self.message_post(body=notification, message_type="notification", subtype="mail.mt_comment", author_id=partner.id) # broadcast the channel header to the added partner diff --git a/addons/mail/models/mail_message.py b/addons/mail/models/mail_message.py index 45d07d5b97c..62f0f524ebf 100644 --- a/addons/mail/models/mail_message.py +++ b/addons/mail/models/mail_message.py @@ -11,7 +11,7 @@ from odoo.exceptions import UserError, AccessError from odoo.osv import expression _logger = logging.getLogger(__name__) -_image_dataurl = re.compile(r'(data:image/[a-z]+?);base64,([a-z0-9+/]{3,}=*)([\'"])', re.I) +_image_dataurl = re.compile(r'(data:image/[a-z]+?);base64,([a-z0-9+/\n]{3,}=*)\n*([\'"])', re.I) class Message(models.Model): diff --git a/addons/mail/static/src/js/thread.js b/addons/mail/static/src/js/thread.js index 68a01df2345..f63c7073af9 100644 --- a/addons/mail/static/src/js/thread.js +++ b/addons/mail/static/src/js/thread.js @@ -210,6 +210,10 @@ var Thread = Widget.extend({ } }, on_click_redirect: function (event) { + // ignore inherited branding + if ($(event.target).data('oe-field') !== undefined) { + return; + } var id = $(event.target).data('oe-id'); if (id) { event.preventDefault(); diff --git a/addons/mail/static/src/js/utils.js b/addons/mail/static/src/js/utils.js index 49d1705eccd..22e9a51b9dd 100644 --- a/addons/mail/static/src/js/utils.js +++ b/addons/mail/static/src/js/utils.js @@ -60,7 +60,7 @@ function _parse_and_transform(nodes, transform_function) { // Suggested URL Javascript regex of http://stackoverflow.com/questions/3809401/what-is-a-good-regular-expression-to-match-a-url // Adapted to make http(s):// not required if (and only if) www. is given. So `should.notmatch` does not match. -var url_regexp = /\b(?:https?:\/\/|(www\.))[-a-zA-Z0-9@:%._\+~#=]{2,256}\.[a-z]{2,13}\b([-a-zA-Z0-9@:%_\+.~#?&//=]*)/gi; +var url_regexp = /\b(?:https?:\/\/\d{1,3}(?:\.\d{1,3}){3}|(?:https?:\/\/|(?:www\.))[-a-z0-9@:%._\+~#=]{2,256}\.[a-z]{2,13})\b(?:[-a-z0-9@:%_\+.~#?&//=]*)/gi; function linkify(text, attrs) { attrs = attrs || {}; if (attrs.target === undefined) { @@ -70,7 +70,7 @@ function linkify(text, attrs) { return key + '="' + _.escape(value) + '"'; }).join(' '); return text.replace(url_regexp, function (url) { - var href = (!/^(f|ht)tps?:\/\//i.test(url)) ? "http://" + url : url; + var href = (!/^https?:\/\//i.test(url)) ? "http://" + url : url; return '' + url + ''; }); } diff --git a/addons/mail/static/tests/mail_utils_tests.js b/addons/mail/static/tests/mail_utils_tests.js new file mode 100644 index 00000000000..e8ec776a8d5 --- /dev/null +++ b/addons/mail/static/tests/mail_utils_tests.js @@ -0,0 +1,34 @@ +odoo.define('mail.mail_utils_tests', function (require) { +"use strict"; + +var utils = require('mail.utils'); + +QUnit.module('mail', {}, function () { + +QUnit.module('Mail utils'); + +QUnit.test('add_link utility function', function (assert) { + assert.expect(7); + + var testInputs = { + 'http://admin:password@example.com:8/%2020': true, + 'https://admin:password@example.com/test': true, + 'www.example.com:8/test': true, + 'https://127.0.0.5:8069': true, + 'www.127.0.0.5': false, + 'should.notmatch': false, + 'fhttps://test.example.com/test': false, + }; + + _.each(testInputs, function (willLinkify, content) { + var output = utils.parse_and_transform(content, utils.add_link); + if (willLinkify) { + assert.strictEqual(output.indexOf(' + diff --git a/addons/mrp/models/mrp_bom.py b/addons/mrp/models/mrp_bom.py index 4d9a0e5bcbe..8e5ce0ad6c8 100644 --- a/addons/mrp/models/mrp_bom.py +++ b/addons/mrp/models/mrp_bom.py @@ -81,6 +81,11 @@ class MrpBom(models.Model): if self.product_tmpl_id: self.product_uom_id = self.product_tmpl_id.uom_id.id + @api.onchange('routing_id') + def onchange_routing_id(self): + for line in self.bom_line_ids: + line.operation_id = False + @api.multi def name_get(self): return [(bom.id, '%s%s' % (bom.code and '%s: ' % bom.code or '', bom.product_tmpl_id.display_name)) for bom in self] diff --git a/addons/mrp_repair/views/mrp_repair_views.xml b/addons/mrp_repair/views/mrp_repair_views.xml index 753e8287096..db899a5b06a 100644 --- a/addons/mrp_repair/views/mrp_repair_views.xml +++ b/addons/mrp_repair/views/mrp_repair_views.xml @@ -50,7 +50,7 @@ - +