diff --git a/addons/account/models/account_invoice.py b/addons/account/models/account_invoice.py
index 6cee000e51c..d8828794475 100644
--- a/addons/account/models/account_invoice.py
+++ b/addons/account/models/account_invoice.py
@@ -570,7 +570,7 @@ class AccountInvoice(models.Model):
# lots of duplicate calls to action_invoice_paid, so we remove those already paid
to_pay_invoices = self.filtered(lambda inv: inv.state != 'paid')
if to_pay_invoices.filtered(lambda inv: inv.state != 'open'):
- raise UserError(_('Invoice must be validated in order to set it to register payemnt.'))
+ raise UserError(_('Invoice must be validated in order to set it to register payment.'))
if to_pay_invoices.filtered(lambda inv: not inv.reconciled):
raise UserError(_('You cannot pay an invoice which is partially paid. You need to reconcile payment entries first.'))
return to_pay_invoices.write({'state': 'paid'})
@@ -578,13 +578,13 @@ class AccountInvoice(models.Model):
@api.multi
def action_invoice_re_open(self):
if self.filtered(lambda inv: inv.state != 'paid'):
- raise UserError(_('Invoice must be paid in order to set it to register payemnt.'))
+ raise UserError(_('Invoice must be paid in order to set it to register payment.'))
return self.write({'state': 'open'})
@api.multi
def action_invoice_cancel(self):
if self.filtered(lambda inv: inv.state not in ['proforma2', 'draft', 'open']):
- raise UserError(_("Invoice must be in draft,Pro-forma or open state in order to be cancelled."))
+ raise UserError(_("Invoice must be in draft, Pro-forma or open state in order to be cancelled."))
return self.action_cancel()
@api.multi
@@ -1151,7 +1151,8 @@ class AccountInvoiceLine(models.Model):
@api.one
@api.depends('price_unit', 'discount', 'invoice_line_tax_ids', 'quantity',
- 'product_id', 'invoice_id.partner_id', 'invoice_id.currency_id', 'invoice_id.company_id')
+ 'product_id', 'invoice_id.partner_id', 'invoice_id.currency_id', 'invoice_id.company_id',
+ 'invoice_id.date_invoice')
def _compute_price(self):
currency = self.invoice_id and self.invoice_id.currency_id or None
price = self.price_unit * (1 - (self.discount or 0.0) / 100.0)
@@ -1160,7 +1161,7 @@ class AccountInvoiceLine(models.Model):
taxes = self.invoice_line_tax_ids.compute_all(price, currency, self.quantity, product=self.product_id, partner=self.invoice_id.partner_id)
self.price_subtotal = price_subtotal_signed = taxes['total_excluded'] if taxes else self.quantity * price
if self.invoice_id.currency_id and self.invoice_id.company_id and self.invoice_id.currency_id != self.invoice_id.company_id.currency_id:
- price_subtotal_signed = self.invoice_id.currency_id.compute(price_subtotal_signed, self.invoice_id.company_id.currency_id)
+ price_subtotal_signed = self.invoice_id.currency_id.with_context(date=self.invoice_id.date_invoice).compute(price_subtotal_signed, self.invoice_id.company_id.currency_id)
sign = self.invoice_id.type in ['in_refund', 'out_refund'] and -1 or 1
self.price_subtotal_signed = price_subtotal_signed * sign
diff --git a/addons/account/models/account_move.py b/addons/account/models/account_move.py
index 683dff63037..1af8d118375 100644
--- a/addons/account/models/account_move.py
+++ b/addons/account/models/account_move.py
@@ -394,7 +394,7 @@ class AccountMoveLine(models.Model):
statement_id = fields.Many2one('account.bank.statement', related='statement_line_id.statement_id', string='Statement', store=True,
help="The bank statement used for bank reconciliation", index=True, copy=False)
reconciled = fields.Boolean(compute='_amount_residual', store=True)
- full_reconcile_id = fields.Many2one('account.full.reconcile', string="Matching Number")
+ full_reconcile_id = fields.Many2one('account.full.reconcile', string="Matching Number", copy=False)
matched_debit_ids = fields.One2many('account.partial.reconcile', 'credit_move_id', String='Matched Debits',
help='Debit journal items that are matched with this journal item.')
matched_credit_ids = fields.One2many('account.partial.reconcile', 'debit_move_id', String='Matched Credits',
@@ -1020,7 +1020,7 @@ class AccountMoveLine(models.Model):
rec_move_ids = self.env['account.partial.reconcile']
for account_move_line in self:
for invoice in account_move_line.payment_id.invoice_ids:
- if account_move_line in invoice.payment_move_line_ids:
+ if invoice.id == self.env.context.get('invoice_id') and account_move_line in invoice.payment_move_line_ids:
account_move_line.payment_id.write({'invoice_ids': [(3, invoice.id, None)]})
rec_move_ids += account_move_line.matched_debit_ids
rec_move_ids += account_move_line.matched_credit_ids
@@ -1388,7 +1388,7 @@ class AccountPartialReconcile(models.Model):
company_currency_id = fields.Many2one('res.currency', related='company_id.currency_id', readonly=True,
help='Utility field to express amount currency')
company_id = fields.Many2one('res.company', related='debit_move_id.company_id', store=True, string='Currency')
- full_reconcile_id = fields.Many2one('account.full.reconcile', string="Full Reconcile")
+ full_reconcile_id = fields.Many2one('account.full.reconcile', string="Full Reconcile", copy=False)
def create_exchange_rate_entry(self, aml_to_fix, amount_diff, diff_in_currency, currency, move_date):
""" Automatically create a journal entry to book the exchange rate difference.
diff --git a/addons/account/models/account_payment.py b/addons/account/models/account_payment.py
index 36164be72f7..dbdd7c16335 100644
--- a/addons/account/models/account_payment.py
+++ b/addons/account/models/account_payment.py
@@ -400,9 +400,12 @@ class account_payment(models.Model):
# the writeoff debit and credit must be computed from the invoice residual in company currency
# minus the payment amount in company currency, and not from the payment difference in the payment currency
# to avoid loss of precision during the currency rate computations. See revision 20935462a0cabeb45480ce70114ff2f4e91eaf79 for a detailed example.
- total_residual_company_signed = sum(invoice.residual_company_signed for invoice in self.invoice_ids)
+ total_residual_company_signed = self._compute_total_invoices_amount()
total_payment_company_signed = self.currency_id.with_context(date=self.payment_date).compute(self.amount, self.company_id.currency_id)
- amount_wo = total_residual_company_signed - total_payment_company_signed
+ if self.invoice_ids[0].type in ['in_invoice', 'out_refund']:
+ amount_wo = total_payment_company_signed - total_residual_company_signed
+ else:
+ amount_wo = total_residual_company_signed - total_payment_company_signed
debit_wo = amount_wo > 0 and amount_wo or 0.0
credit_wo = amount_wo < 0 and -amount_wo or 0.0
writeoff_line['name'] = _('Counterpart')
diff --git a/addons/account/models/chart_template.py b/addons/account/models/chart_template.py
index 37bcefb2675..65f33c4d748 100644
--- a/addons/account/models/chart_template.py
+++ b/addons/account/models/chart_template.py
@@ -226,7 +226,7 @@ class AccountChartTemplate(models.Model):
account = getattr(self, record[0])
value = account and 'account.account,' + str(acc_template_ref[account.id]) or False
if value:
- field = self.env['ir.model.fields'].sudo().search([('name', '=', record[0]), ('model', '=', record[1]), ('relation', '=', record[2])])
+ field = self.env['ir.model.fields'].search([('name', '=', record[0]), ('model', '=', record[1]), ('relation', '=', record[2])], limit=1)
vals = {
'name': record[0],
'company_id': company.id,
@@ -394,22 +394,11 @@ class AccountChartTemplate(models.Model):
acc_template_ref[account_template.id] = new_account
return acc_template_ref
- @api.multi
- def generate_account_reconcile_model(self, tax_template_ref, acc_template_ref, company):
- """ This method for generating accounts from templates.
-
- :param tax_template_ref: Taxes templates reference for write taxes_id in account_account.
- :param acc_template_ref: dictionary with the mappping between the account templates and the real accounts.
- :param company_id: company_id selected from wizard.multi.charts.accounts.
- :returns: return new_account_reconcile_model for reference purpose.
- :rtype: dict
+ def _prepare_reconcile_model_vals(self, company, account_reconcile_model, acc_template_ref, tax_template_ref):
+ """ This method generates a dictionnary of all the values for the account.reconcile.model that will be created.
"""
self.ensure_one()
- account_reconcile_models = self.env['account.reconcile.model.template'].search([
- ('account_id.chart_template_id', '=', self.id)
- ])
- for account_reconcile_model in account_reconcile_models:
- vals = {
+ return {
'name': account_reconcile_model.name,
'sequence': account_reconcile_model.sequence,
'has_second_line': account_reconcile_model.has_second_line,
@@ -425,6 +414,23 @@ class AccountChartTemplate(models.Model):
'second_amount': account_reconcile_model.second_amount,
'second_tax_id': account_reconcile_model.second_tax_id and tax_template_ref[account_reconcile_model.second_tax_id.id] or False,
}
+
+ @api.multi
+ def generate_account_reconcile_model(self, tax_template_ref, acc_template_ref, company):
+ """ This method for generating accounts from templates.
+
+ :param tax_template_ref: Taxes templates reference for write taxes_id in account_account.
+ :param acc_template_ref: dictionary with the mappping between the account templates and the real accounts.
+ :param company_id: company_id selected from wizard.multi.charts.accounts.
+ :returns: return new_account_reconcile_model for reference purpose.
+ :rtype: dict
+ """
+ self.ensure_one()
+ account_reconcile_models = self.env['account.reconcile.model.template'].search([
+ ('account_id.chart_template_id', '=', self.id)
+ ])
+ for account_reconcile_model in account_reconcile_models:
+ vals = self._prepare_reconcile_model_vals(company, account_reconcile_model, acc_template_ref, tax_template_ref)
self.create_record_with_xmlid(company, account_reconcile_model, 'account.reconcile.model', vals)
return True
@@ -511,9 +517,14 @@ class AccountTaxTemplate(models.Model):
res.append((record.id, name))
return res
- def _get_tax_vals(self, company):
+ def _get_tax_vals(self, company, tax_template_to_tax):
""" This method generates a dictionnary of all the values for the tax that will be created.
"""
+ # Compute children tax ids
+ children_ids = []
+ for child_tax in self.children_tax_ids:
+ if tax_template_to_tax.get(child_tax.id):
+ children_ids.append(tax_template_to_tax[child_tax.id])
self.ensure_one()
val = {
'name': self.name,
@@ -528,6 +539,7 @@ class AccountTaxTemplate(models.Model):
'include_base_amount': self.include_base_amount,
'analytic': self.analytic,
'tag_ids': [(6, 0, [t.id for t in self.tag_ids])],
+ 'children_tax_ids': [(6, 0, children_ids)],
'tax_adjustment': self.tax_adjustment,
'use_cash_basis': self.use_cash_basis,
'cash_basis_account': self.cash_basis_account,
@@ -549,13 +561,7 @@ class AccountTaxTemplate(models.Model):
todo_dict = {}
tax_template_to_tax = {}
for tax in self:
- # Compute children tax ids
- children_ids = []
- for child_tax in tax.children_tax_ids:
- if tax_template_to_tax.get(child_tax.id):
- children_ids.append(tax_template_to_tax[child_tax.id])
- vals_tax = tax._get_tax_vals(company)
- vals_tax['children_tax_ids'] = children_ids and [(6, 0, children_ids)] or []
+ vals_tax = tax._get_tax_vals(company, tax_template_to_tax)
new_tax = self.env['account.chart.template'].create_record_with_xmlid(company, tax, 'account.tax', vals_tax)
tax_template_to_tax[tax.id] = new_tax
# Since the accounts have not been created yet, we have to wait before filling these fields
diff --git a/addons/account/security/account_security.xml b/addons/account/security/account_security.xml
index fdfcb1caaa5..846a86724b2 100644
--- a/addons/account/security/account_security.xml
+++ b/addons/account/security/account_security.xml
@@ -5,10 +5,14 @@
Billing
-
+
+
+
+
+
Accountant
diff --git a/addons/account/static/src/js/account_payment_widget.js b/addons/account/static/src/js/account_payment_widget.js
index 932de22eef5..a7f2b64c413 100644
--- a/addons/account/static/src/js/account_payment_widget.js
+++ b/addons/account/static/src/js/account_payment_widget.js
@@ -59,7 +59,7 @@ var ShowPaymentLineWidget = form_common.AbstractField.extend({
var payment_id = parseInt($(this).attr('payment-id'))
if (payment_id !== undefined && payment_id !== NaN){
new Model("account.move.line")
- .call("remove_move_reconcile", [payment_id])
+ .call("remove_move_reconcile", [payment_id, {'invoice_id': self.view.datarecord.id}])
.then(function (result) {
self.view.reload();
});
diff --git a/addons/account/views/account_invoice_view.xml b/addons/account/views/account_invoice_view.xml
index bcd1434e454..7154cb65c66 100644
--- a/addons/account/views/account_invoice_view.xml
+++ b/addons/account/views/account_invoice_view.xml
@@ -46,7 +46,7 @@
-
+
@@ -68,7 +68,7 @@
-
+
@@ -272,7 +272,7 @@
-
+
@@ -411,7 +411,7 @@
-
+
diff --git a/addons/account/views/report_invoice.xml b/addons/account/views/report_invoice.xml
index 25bb8089b78..74011168e11 100644
--- a/addons/account/views/report_invoice.xml
+++ b/addons/account/views/report_invoice.xml
@@ -61,7 +61,7 @@
Source Document
Quantity
Unit Price
-
Disc.(%)
+
Disc.(%)
Taxes
Subtotal
@@ -77,7 +77,7 @@
-
+
diff --git a/addons/account_asset/models/account_asset.py b/addons/account_asset/models/account_asset.py
index c2b57cd7d2c..6f1251ccaca 100644
--- a/addons/account_asset/models/account_asset.py
+++ b/addons/account_asset/models/account_asset.py
@@ -42,7 +42,10 @@ class AccountAssetCategory(models.Model):
@api.onchange('account_asset_id')
def onchange_account_asset(self):
- self.account_depreciation_id = self.account_asset_id
+ if self.type == "purchase":
+ self.account_depreciation_id = self.account_asset_id
+ elif self.type == "sale":
+ self.account_depreciation_expense_id = self.account_asset_id
@api.onchange('type')
def onchange_type(self):
diff --git a/addons/account_asset/models/account_invoice.py b/addons/account_asset/models/account_invoice.py
index 3e45b722976..d6fb00358c9 100644
--- a/addons/account_asset/models/account_invoice.py
+++ b/addons/account_asset/models/account_invoice.py
@@ -12,14 +12,16 @@ import odoo.addons.decimal_precision as dp
class AccountInvoice(models.Model):
_inherit = 'account.invoice'
+ @api.multi
+ def action_cancel(self):
+ res = super(AccountInvoice, self).action_cancel()
+ self.env['account.asset.asset'].sudo().search([('invoice_id', 'in', self.ids)]).write({'active': False})
+ return res
+
@api.multi
def action_move_create(self):
result = super(AccountInvoice, self).action_move_create()
for inv in self:
- if inv.number:
- asset_ids = self.env['account.asset.asset'].sudo().search([('invoice_id', '=', inv.id), ('company_id', '=', inv.company_id.id)])
- if asset_ids:
- asset_ids.write({'active': False})
context = dict(self.env.context)
# Within the context of an invoice,
# this default value is for the type of the invoice, not the type of the asset.
@@ -83,7 +85,7 @@ class AccountInvoiceLine(models.Model):
if self.invoice_id.type == 'out_invoice' and self.asset_category_id:
self.account_id = self.asset_category_id.account_asset_id.id
elif self.invoice_id.type == 'in_invoice' and self.asset_category_id:
- self.account_id = self.asset_category_id.account_depreciation_id.id
+ self.account_id = self.asset_category_id.account_asset_id.id
@api.onchange('uom_id')
def _onchange_uom_id(self):
diff --git a/addons/account_check_printing/models/account_payment.py b/addons/account_check_printing/models/account_payment.py
index fc3e200840e..8ee9a40a11f 100644
--- a/addons/account_check_printing/models/account_payment.py
+++ b/addons/account_check_printing/models/account_payment.py
@@ -88,7 +88,7 @@ class AccountPayment(models.Model):
and vals.get('check_manual_sequencing'):
sequence = self.env['account.journal'].browse(vals['journal_id']).check_sequence_id
vals.update({'check_number': sequence.next_by_id()})
- return super(AccountPayment, self.sudo()).create(vals)
+ return super(AccountPayment, self).create(vals)
@api.multi
def print_checks(self):
diff --git a/addons/account_tax_python/models/account_tax.py b/addons/account_tax_python/models/account_tax.py
index 01f8576ec8e..7ab0c2bbe1f 100644
--- a/addons/account_tax_python/models/account_tax.py
+++ b/addons/account_tax_python/models/account_tax.py
@@ -66,11 +66,11 @@ class AccountTaxTemplatePython(models.Model):
":param product: product.product recordset singleton or None\n"
":param partner: res.partner recordset singleton or None")
- def _get_tax_vals(self, company):
+ def _get_tax_vals(self, company, tax_template_to_tax):
""" This method generates a dictionnary of all the values for the tax that will be created.
"""
self.ensure_one()
- res = super(AccountTaxTemplatePython, self)._get_tax_vals(company)
+ res = super(AccountTaxTemplatePython, self)._get_tax_vals(company, tax_template_to_tax)
res['python_compute'] = self.python_compute
res['python_applicable'] = self.python_applicable
return res
diff --git a/addons/auth_oauth/controllers/main.py b/addons/auth_oauth/controllers/main.py
index 233cd839e6b..aa3f4e69b5c 100644
--- a/addons/auth_oauth/controllers/main.py
+++ b/addons/auth_oauth/controllers/main.py
@@ -111,8 +111,6 @@ class OAuthLogin(Home):
@http.route()
def web_auth_signup(self, *args, **kw):
providers = self.list_providers()
- if len(providers) == 1:
- werkzeug.exceptions.abort(werkzeug.utils.redirect(providers[0]['auth_link'], 303))
response = super(OAuthLogin, self).web_auth_signup(*args, **kw)
response.qcontext.update(providers=providers)
return response
diff --git a/addons/base_address_city/models/res_partner.py b/addons/base_address_city/models/res_partner.py
index ab1f0518864..afa5cd759e8 100644
--- a/addons/base_address_city/models/res_partner.py
+++ b/addons/base_address_city/models/res_partner.py
@@ -26,8 +26,8 @@ class Partner(models.Model):
replacement_xml = """
Set selection based on a search filter:
+ context="{'default_model_id': model_name, 'default_active': False, 'active_test': False}"/>
+
+ base.automation.search
+ base.automation
+
+
+
+
+
+
+
+
Automated Actions
diff --git a/addons/board/controllers/main.py b/addons/board/controllers/main.py
index 5f17afd8bb9..2ba236ea109 100644
--- a/addons/board/controllers/main.py
+++ b/addons/board/controllers/main.py
@@ -13,7 +13,7 @@ class Board(Controller):
# Retrieve the 'My Dashboard' action from its xmlid
action = request.env.ref('board.open_board_my_dash_action')
- if action and action['res_model'] == 'board.board' and action['views'][0][1] == 'form':
+ if action and action['res_model'] == 'board.board' and action['views'][0][1] == 'form' and action_id:
# Maybe should check the content instead of model board.board ?
view_id = action['views'][0][0]
board = request.env['board.board'].fields_view_get(view_id, 'form')
diff --git a/addons/board/static/src/js/dashboard.js b/addons/board/static/src/js/dashboard.js
index 7d881187fe0..eb458812a57 100644
--- a/addons/board/static/src/js/dashboard.js
+++ b/addons/board/static/src/js/dashboard.js
@@ -413,7 +413,7 @@ FavoriteMenu.include({
name = self.$add_dashboard_input.val();
return self.rpc('/board/add_to_dashboard', {
- action_id: self.action_id,
+ action_id: self.action_id || false,
context_to_save: c,
domain: d,
view_mode: self.view_manager.active_view.type,
diff --git a/addons/bus/models/res_partner.py b/addons/bus/models/res_partner.py
index 4e97437720d..b0b4c23d74f 100644
--- a/addons/bus/models/res_partner.py
+++ b/addons/bus/models/res_partner.py
@@ -34,24 +34,30 @@ class ResPartner(models.Model):
:param name : the partner name to search
:param limit : the limit of result to return
"""
- name = '%' + name + '%'
- excluded_partner_ids = [self.env.user.partner_id.id]
- self.env.cr.execute("""
- SELECT
- U.id as user_id,
- P.id as id,
- P.name as name,
- CASE WHEN B.last_poll IS NULL THEN 'offline'
- WHEN age(now() AT TIME ZONE 'UTC', B.last_poll) > interval %s THEN 'offline'
- WHEN age(now() AT TIME ZONE 'UTC', B.last_presence) > interval %s THEN 'away'
- ELSE 'online'
- END as im_status
- FROM res_users U
- JOIN res_partner P ON P.id = U.partner_id
- LEFT JOIN bus_presence B ON B.user_id = U.id
- WHERE P.name ILIKE %s
- AND P.id NOT IN %s
- AND U.active = 't'
- LIMIT %s
- """, ("%s seconds" % DISCONNECTION_TIMER, "%s seconds" % AWAY_TIMER, name, tuple(excluded_partner_ids), limit))
- return self.env.cr.dictfetchall()
+ # This method is supposed to be used only in the context of channel creation or
+ # extension via an invite. As both of these actions require the 'create' access
+ # right, we check this specific ACL.
+ if self.env['mail.channel'].check_access_rights('create', raise_exception=False):
+ name = '%' + name + '%'
+ excluded_partner_ids = [self.env.user.partner_id.id]
+ self.env.cr.execute("""
+ SELECT
+ U.id as user_id,
+ P.id as id,
+ P.name as name,
+ CASE WHEN B.last_poll IS NULL THEN 'offline'
+ WHEN age(now() AT TIME ZONE 'UTC', B.last_poll) > interval %s THEN 'offline'
+ WHEN age(now() AT TIME ZONE 'UTC', B.last_presence) > interval %s THEN 'away'
+ ELSE 'online'
+ END as im_status
+ FROM res_users U
+ JOIN res_partner P ON P.id = U.partner_id
+ LEFT JOIN bus_presence B ON B.user_id = U.id
+ WHERE P.name ILIKE %s
+ AND P.id NOT IN %s
+ AND U.active = 't'
+ LIMIT %s
+ """, ("%s seconds" % DISCONNECTION_TIMER, "%s seconds" % AWAY_TIMER, name, tuple(excluded_partner_ids), limit))
+ return self.env.cr.dictfetchall()
+ else:
+ return {}
diff --git a/addons/calendar/models/calendar.py b/addons/calendar/models/calendar.py
index dc398afed3c..d55b35ae36c 100644
--- a/addons/calendar/models/calendar.py
+++ b/addons/calendar/models/calendar.py
@@ -173,6 +173,7 @@ class Attendee(models.Model):
'datas_fname': 'invitation.ics',
'datas': str(ics_file).encode('base64')})]
vals['model'] = None # We don't want to have the mail in the tchatter while in queue!
+ vals['res_id'] = False
current_mail = self.env['mail.mail'].browse(mail_id)
current_mail.mail_message_id.write(vals)
mails_to_send |= current_mail
@@ -1360,11 +1361,11 @@ class Meeting(models.Model):
super(Meeting, real_meetings).write(values)
# set end_date for calendar searching
- if values.get('recurrency') and values.get('end_type', 'count') in ('count', unicode('count')) and \
- (values.get('rrule_type') or values.get('count') or values.get('start') or values.get('stop')):
+ if any(field in values for field in ['recurrency', 'end_type', 'count', 'rrule_type', 'start', 'stop']):
for real_meeting in real_meetings:
- final_date = real_meeting._get_recurrency_end_date()
- super(Meeting, real_meeting).write({'final_date': final_date})
+ if real_meeting.recurrency and real_meeting.end_type in ('count', unicode('count')):
+ final_date = real_meeting._get_recurrency_end_date()
+ super(Meeting, real_meeting).write({'final_date': final_date})
attendees_create = False
if values.get('partner_ids', False):
@@ -1464,7 +1465,8 @@ class Meeting(models.Model):
for r in result:
if r['user_id']:
user_id = type(r['user_id']) in (tuple, list) and r['user_id'][0] or r['user_id']
- if user_id == self.env.user.id:
+ partner_id = self.env.user.partner_id.id
+ if user_id == self.env.user.id or partner_id in r.get("partner_ids", []):
continue
if r['privacy'] == 'private':
for f in r.keys():
diff --git a/addons/calendar/security/calendar_security.xml b/addons/calendar/security/calendar_security.xml
index e448e61a075..8b5385e3cdf 100644
--- a/addons/calendar/security/calendar_security.xml
+++ b/addons/calendar/security/calendar_security.xml
@@ -23,5 +23,15 @@
+
+
+ Private events
+ ['|', ('privacy', '!=', 'private'), '&', ('privacy', '=', 'private'), ('partner_ids', 'in', user.partner_id.id)]
+
+
+
+
+
+
diff --git a/addons/crm/__manifest__.py b/addons/crm/__manifest__.py
index dff59a6481b..7781e15184b 100644
--- a/addons/crm/__manifest__.py
+++ b/addons/crm/__manifest__.py
@@ -40,6 +40,9 @@ Dashboard for CRM will include:
'web_tour',
],
'data': [
+ 'security/crm_security.xml',
+ 'security/ir.model.access.csv',
+
'data/crm_data.xml',
'data/crm_stage_data.xml',
'data/sales_config_settings_data.xml',
@@ -47,9 +50,6 @@ Dashboard for CRM will include:
'data/web_planner_data.xml',
'data/mail_template_data.xml',
- 'security/crm_security.xml',
- 'security/ir.model.access.csv',
-
'wizard/base_partner_merge_views.xml',
'wizard/crm_lead_lost_views.xml',
'wizard/crm_lead_to_opportunity_views.xml',
diff --git a/addons/crm/data/mail_template_data.xml b/addons/crm/data/mail_template_data.xml
index ac84bea844c..7da44977f2a 100644
--- a/addons/crm/data/mail_template_data.xml
+++ b/addons/crm/data/mail_template_data.xml
@@ -91,11 +91,10 @@
You’re not alone
diff --git a/addons/web_diagram/controllers/main.py b/addons/web_diagram/controllers/main.py
index 0cc360f064b..22761f6cd22 100644
--- a/addons/web_diagram/controllers/main.py
+++ b/addons/web_diagram/controllers/main.py
@@ -76,7 +76,7 @@ class DiagramView(http.Controller):
for i, fld in enumerate(connector_fields):
t['options'][connector_fields_string[i]] = tr[fld]
- fields = http.request.env['ir.model.fields'].sudo()
+ fields = http.request.env['ir.model.fields']
field = fields.search([('model', '=', model), ('relation', '=', node)])
node_act = http.request.env[node]
search_acts = node_act.search([(field.relation_field, '=', id)])
diff --git a/addons/web_editor/static/src/js/summernote.js b/addons/web_editor/static/src/js/summernote.js
index 5c344fbbcd1..9d7304caf75 100644
--- a/addons/web_editor/static/src/js/summernote.js
+++ b/addons/web_editor/static/src/js/summernote.js
@@ -134,7 +134,7 @@ dom.hasProgrammaticStyle = function (node) {
};
dom.mergeFilter = function (prev, cur, parent) {
// merge text nodes
- if (prev && (dom.isText(prev) || ("H1 H2 H3 H4 H5 H6 LI P".indexOf(prev.tagName) !== -1 && prev !== cur.parentNode)) && dom.isText(cur)) {
+ if (prev && (dom.isText(prev) || (['H1', 'H2', 'H3', 'H4', 'H5', 'H6', 'LI', 'P'].indexOf(prev.tagName) !== -1 && prev !== cur.parentNode)) && dom.isText(cur)) {
return true;
}
if (prev && prev.tagName === "P" && dom.isText(cur)) {
diff --git a/addons/web_kanban/static/src/js/kanban_record.js b/addons/web_kanban/static/src/js/kanban_record.js
index c784073f2a5..72df38bf761 100644
--- a/addons/web_kanban/static/src/js/kanban_record.js
+++ b/addons/web_kanban/static/src/js/kanban_record.js
@@ -78,9 +78,24 @@ var KanbanRecord = Widget.extend({
var widget = new Widget(self, field, $field);
widget.replace($field);
self.sub_widgets.push(widget);
+ self._set_field_display(widget, field);
});
},
+ _set_field_display: function(widget, field) {
+ // attribute display
+ if (field.__attrs.display === 'right') {
+ widget.$el.addClass('pull-right');
+ } else if (field.__attrs.display === 'full') {
+ widget.$el.addClass('o_text_block');
+ }
+
+ // attribute bold
+ if (field.__attrs.bold) {
+ widget.$el.addClass('o_text_bold');
+ }
+ },
+
start: function() {
var self = this;
this.add_widgets();
@@ -98,6 +113,7 @@ var KanbanRecord = Widget.extend({
renderElement: function () {
this._super();
+ this.setup_color();
this.setup_color_picker();
this.$el.addClass('o_kanban_record');
this.$el.data('record', this);
@@ -267,6 +283,17 @@ var KanbanRecord = Widget.extend({
this.trigger_up('kanban_record_update', event.data);
},
+ /*
+ * If an attribute `color` is set on the kanban record,
+ * this will add the corresponding color class.
+ */
+ setup_color: function() {
+ var color_field = this.$el.attr('color');
+ if (color_field && color_field in this.fields) {
+ this.$el.addClass(this.kanban_color(this.values[color_field].value));
+ }
+ },
+
setup_color_picker: function() {
var self = this;
var $colorpicker = this.$('ul.oe_kanban_colorpicker');
diff --git a/addons/web_kanban/static/src/js/kanban_view.js b/addons/web_kanban/static/src/js/kanban_view.js
index 7cce7617da9..07aa116c634 100644
--- a/addons/web_kanban/static/src/js/kanban_view.js
+++ b/addons/web_kanban/static/src/js/kanban_view.js
@@ -812,20 +812,26 @@ function transform_qweb_template (node, fvg, many2manys) {
} else if (fields_registry.contains(ftype)) {
// do nothing, the kanban record will handle it
} else {
- if (node.attrs.bold) {
- node.tag = 'strong';
- var children_node = {
- attrs: {},
- children: [],
- tag: qweb.prefix,
- };
- children_node.attrs[qweb.prefix + '-esc'] = 'record.' + node.attrs.name + '.value';
- node.children.push(children_node);
- } else {
- node.tag = qweb.prefix;
- node.attrs[qweb.prefix + '-esc'] = 'record.' + node.attrs.name + '.value';
- }
+ node.tag = 'span';
+ var child_node = {
+ attrs: {},
+ children: [],
+ tag: qweb.prefix,
+ };
+ child_node.attrs[qweb.prefix + '-esc'] = 'record.' + node.attrs.name + '.value';
+ node.children.push(child_node);
+ // set class according to field attribute
+ var child_classes = [];
+ if (node.attrs.display === 'right') {
+ child_classes.push('pull-right');
+ } else if (node.attrs.display === 'full') {
+ child_classes.push('o_text_block');
+ }
+ if (node.attrs.bold) {
+ child_classes.push('o_text_bold');
+ }
+ node.attrs['class'] = child_classes.join(' ');
}
break;
case 'button':
diff --git a/addons/web_kanban/static/src/less/kanban_view.less b/addons/web_kanban/static/src/less/kanban_view.less
index 0640fe9f3e3..bc4166c7df4 100644
--- a/addons/web_kanban/static/src/less/kanban_view.less
+++ b/addons/web_kanban/static/src/less/kanban_view.less
@@ -130,6 +130,12 @@
color: #A61300;
font-weight: bold;
}
+ .o_text_bold {
+ font-weight: bold;
+ }
+ .o_text_block {
+ display: block;
+ }
}
.o_kanban_quick_create {
diff --git a/addons/website/models/ir_http.py b/addons/website/models/ir_http.py
index f5054202f61..012802649f1 100644
--- a/addons/website/models/ir_http.py
+++ b/addons/website/models/ir_http.py
@@ -371,7 +371,7 @@ class PageConverter(werkzeug.routing.PathConverter):
query = query and query.startswith('website.') and query[8:] or query
if query:
domain += [('key', 'like', query)]
- website_id = request.context.get('website_id') or request.registry['website'].search(cr, uid, [], limit=1)[0]
+ website_id = request.context.get('website_id') or request.env['website'].search([], limit=1).id
domain += ['|', ('website_id', '=', website_id), ('website_id', '=', False)]
views = View.search_read(domain, fields=['key', 'priority', 'write_date'], order='name')
diff --git a/addons/website/models/website.py b/addons/website/models/website.py
index a747b85726b..f630eef13a9 100644
--- a/addons/website/models/website.py
+++ b/addons/website/models/website.py
@@ -527,7 +527,7 @@ class Website(models.Model):
of the same.
:rtype: list({name: str, url: str})
"""
- request.context = dict(request.context, **context)
+ request.context = dict(request.context, **self.env.context)
router = request.httprequest.app.get_db_router(request.db)
# Force enumeration to be performed as public user
url_set = set()
diff --git a/addons/website/static/src/less/website.snippets.less b/addons/website/static/src/less/website.snippets.less
index 1a290e65767..4a9e304299f 100644
--- a/addons/website/static/src/less/website.snippets.less
+++ b/addons/website/static/src/less/website.snippets.less
@@ -112,7 +112,6 @@ table.table_desc tr td {
height: 100%;
.item {
height: 100%;
- background-size: cover;
}
.carousel-control {
cursor: pointer;
diff --git a/addons/website/static/src/less/website.wrapwrap.less b/addons/website/static/src/less/website.wrapwrap.less
index 9151e26e7ba..e572a11a975 100644
--- a/addons/website/static/src/less/website.wrapwrap.less
+++ b/addons/website/static/src/less/website.wrapwrap.less
@@ -37,6 +37,16 @@ footer {
display: none!important;
}
+.o_text_overflow {
+ .text-overflow()
+}
+
+.o_div_text_overflow * > div {
+ // .text-overflow() we don't want wordwrap
+ overflow: hidden;
+ text-overflow: ellipsis;
+}
+
// Odoo options classes
.jumbotron {
diff --git a/addons/website/views/website_templates.xml b/addons/website/views/website_templates.xml
index 6cce24534a4..c791d330435 100644
--- a/addons/website/views/website_templates.xml
+++ b/addons/website/views/website_templates.xml
@@ -77,7 +77,7 @@
+ }' groups="sale.group_show_price_subtotal"/>
+
diff --git a/addons/website_hr/views/hr_employee_views.xml b/addons/website_hr/views/hr_employee_views.xml
index cc38353ca06..702bad88009 100644
--- a/addons/website_hr/views/hr_employee_views.xml
+++ b/addons/website_hr/views/hr_employee_views.xml
@@ -8,7 +8,7 @@
diff --git a/addons/website_mail/data/mail_channel_data.xml b/addons/website_mail/data/mail_channel_data.xml
index 27f83e71beb..16081671efe 100644
--- a/addons/website_mail/data/mail_channel_data.xml
+++ b/addons/website_mail/data/mail_channel_data.xml
@@ -93,10 +93,9 @@
You’re not alone
- We would be delighted to assist you along the way. Contact us at
-
- help@odoo.com if you have any question. You can also discover
- how to get the best out of Odoo with our
+ We would be delighted to assist you along the way. Contact us through our
+ support form if you have any question.
+ You can also discover how to get the best out of Odoo with our User Documentation or with our
diff --git a/addons/website_portal/views/website_portal_templates.xml b/addons/website_portal/views/website_portal_templates.xml
index 67a240a8343..3e5924938a7 100644
--- a/addons/website_portal/views/website_portal_templates.xml
+++ b/addons/website_portal/views/website_portal_templates.xml
@@ -133,7 +133,7 @@
-
Contact
+
Saleman
diff --git a/addons/website_portal_sale/models/payment.py b/addons/website_portal_sale/models/payment.py
index ec601dd1d36..d94b429bf18 100644
--- a/addons/website_portal_sale/models/payment.py
+++ b/addons/website_portal_sale/models/payment.py
@@ -16,8 +16,13 @@ class PaymentTransaction(models.Model):
def _generate_and_pay_invoice(self, tx, acquirer_name):
tx.sale_order_id._force_lines_to_invoice_policy_order()
- created_invoice = tx.sale_order_id.action_invoice_create()
- created_invoice = self.env['account.invoice'].browse(created_invoice)
+ # force company to ensure journals/accounts etc. are correct
+ # company_id needed for default_get on account.journal
+ # force_company needed for company_dependent fields
+ ctx_company = {'company_id': tx.sale_order_id.company_id.id,
+ 'force_company': tx.sale_order_id.company_id.id}
+ created_invoice = tx.sale_order_id.with_context(**ctx_company).action_invoice_create()
+ created_invoice = self.env['account.invoice'].browse(created_invoice).with_context(**ctx_company)
if created_invoice:
_logger.info('<%s> transaction completed, auto-generated invoice %s (ID %s) for %s (ID %s)',
diff --git a/addons/website_sale/__manifest__.py b/addons/website_sale/__manifest__.py
index 45fa7f8f8ec..a02e4627ce1 100644
--- a/addons/website_sale/__manifest__.py
+++ b/addons/website_sale/__manifest__.py
@@ -12,6 +12,8 @@ Odoo E-Commerce
""",
'depends': ['website', 'sale', 'payment', 'website_payment', 'website_portal_sale', 'website_mail', 'website_form', 'rating'],
'data': [
+ 'security/ir.model.access.csv',
+ 'security/website_sale.xml',
'data/data.xml',
'data/web_planner_data.xml',
'views/views.xml',
@@ -24,8 +26,6 @@ Odoo E-Commerce
'views/snippets.xml',
'views/report_shop_saleorder.xml',
'views/res_config_view.xml',
- 'security/ir.model.access.csv',
- 'security/website_sale.xml',
],
'demo': [
'data/demo.xml',
diff --git a/addons/website_sale/models/sale_order.py b/addons/website_sale/models/sale_order.py
index d22932915a0..1d7c24abcb1 100644
--- a/addons/website_sale/models/sale_order.py
+++ b/addons/website_sale/models/sale_order.py
@@ -302,6 +302,27 @@ class Website(models.Model):
DEFAULT_PAYMENT_TERM = 'account.account_payment_term_immediate'
return self.env.ref(DEFAULT_PAYMENT_TERM, False).id or partner.property_payment_term_id.id
+ @api.multi
+ def _prepare_sale_order_values(self, partner, pricelist):
+ self.ensure_one()
+ affiliate_id = request.session.get('affiliate_id')
+ salesperson_id = affiliate_id if self.env['res.users'].sudo().browse(affiliate_id).exists() else request.website.salesperson_id.id
+ addr = partner.address_get(['delivery', 'invoice'])
+ values = {
+ 'partner_id': partner.id,
+ 'pricelist_id': pricelist.id,
+ 'payment_term_id': self.sale_get_payment_term(partner),
+ 'team_id': self.salesteam_id.id,
+ 'partner_invoice_id': addr['invoice'],
+ 'partner_shipping_id': addr['delivery'],
+ 'user_id': salesperson_id or self.salesperson_id.id,
+ }
+ company = self.company_id or pricelist.company_id
+ if company:
+ values['company_id'] = company.id
+
+ return values
+
@api.multi
def sale_get_order(self, force_create=False, code=None, update_pricelist=False, force_pricelist=False):
""" Return the current sales order after mofications specified by params.
@@ -337,25 +358,8 @@ class Website(models.Model):
# create so if needed
if not sale_order and (force_create or code):
# TODO cache partner_id session
- affiliate_id = request.session.get('affiliate_id')
- if self.env['res.users'].sudo().browse(affiliate_id).exists():
- salesperson_id = affiliate_id
- else:
- salesperson_id = request.website.salesperson_id.id
- addr = partner.address_get(['delivery', 'invoice'])
- so_data = {
- 'partner_id': partner.id,
- 'pricelist_id': pricelist_id,
- 'payment_term_id': self.sale_get_payment_term(partner),
- 'team_id': self.salesteam_id.id,
- 'partner_invoice_id': addr['invoice'],
- 'partner_shipping_id': addr['delivery'],
- 'user_id': salesperson_id or self.salesperson_id.id,
- }
- company = self.company_id or self.env['product.pricelist'].browse(pricelist_id).sudo().company_id
- if company:
- so_data['company_id'] = company.id
-
+ pricelist = self.env['product.pricelist'].browse(pricelist_id).sudo()
+ so_data = self._prepare_sale_order_values(partner, pricelist)
sale_order = self.env['sale.order'].sudo().create(so_data)
# set fiscal position
diff --git a/addons/website_sale/static/src/js/website_sale.js b/addons/website_sale/static/src/js/website_sale.js
index 1205951b039..1bb49194f37 100644
--- a/addons/website_sale/static/src/js/website_sale.js
+++ b/addons/website_sale/static/src/js/website_sale.js
@@ -233,7 +233,7 @@ odoo.define('website_sale.website_sale', function (require) {
var precision = 2;
if ($(".decimal_precision").length) {
- precision = parseInt($(".decimal_precision").first().data('precision'));
+ precision = parseInt($(".decimal_precision").last().data('precision'));
}
var formatted = _.str.sprintf('%.' + precision + 'f', price).split('.');
formatted[0] = utils.insert_thousand_seps(formatted[0]);
diff --git a/addons/website_sale/views/templates.xml b/addons/website_sale/views/templates.xml
index 71b110dfca0..bec827eac68 100644
--- a/addons/website_sale/views/templates.xml
+++ b/addons/website_sale/views/templates.xml
@@ -1735,14 +1735,14 @@
Bill To:
-
+
Ship To:
-
+
diff --git a/addons/website_sale_stock/__init__.py b/addons/website_sale_stock/__init__.py
index 67dee8c60db..5f9ef702708 100644
--- a/addons/website_sale_stock/__init__.py
+++ b/addons/website_sale_stock/__init__.py
@@ -1,2 +1,3 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
+import models
\ No newline at end of file
diff --git a/addons/website_sale_stock/models/__init__.py b/addons/website_sale_stock/models/__init__.py
new file mode 100644
index 00000000000..b8b239729b6
--- /dev/null
+++ b/addons/website_sale_stock/models/__init__.py
@@ -0,0 +1 @@
+import website
\ No newline at end of file
diff --git a/addons/website_sale_stock/models/website.py b/addons/website_sale_stock/models/website.py
new file mode 100644
index 00000000000..b5c866c27bb
--- /dev/null
+++ b/addons/website_sale_stock/models/website.py
@@ -0,0 +1,15 @@
+# -*- coding: utf-8 -*-
+from odoo import api, models
+
+class Website(models.Model):
+ _inherit = 'website'
+
+ @api.multi
+ def _prepare_sale_order_values(self, partner, pricelist):
+ self.ensure_one()
+ values = super(Website, self)._prepare_sale_order_values(partner, pricelist)
+ if values['company_id']:
+ warehouses = self.env['stock.warehouse'].sudo().search([('company_id', '=', values['company_id'])], limit=1)
+ if warehouses:
+ values['warehouse_id'] = warehouses.id
+ return values
diff --git a/addons/website_slides/models/slides.py b/addons/website_slides/models/slides.py
index 247094d605f..16604d1f5fd 100644
--- a/addons/website_slides/models/slides.py
+++ b/addons/website_slides/models/slides.py
@@ -476,7 +476,7 @@ class Slide(models.Model):
base_url = self.env['ir.config_parameter'].sudo().get_param('web.base.url')
for slide in self.filtered(lambda slide: slide.website_published and slide.channel_id.publish_template_id):
publish_template = slide.channel_id.publish_template_id
- html_body = publish_template.with_context({'base_url': base_url}).render_template(publish_template.body_html, 'slide.slide', slide.id)
+ html_body = publish_template.with_context(base_url=base_url).render_template(publish_template.body_html, 'slide.slide', slide.id)
subject = publish_template.render_template(publish_template.subject, 'slide.slide', slide.id)
slide.channel_id.message_post(
subject=subject,
@@ -487,7 +487,7 @@ class Slide(models.Model):
@api.one
def send_share_email(self, email):
base_url = self.env['ir.config_parameter'].sudo().get_param('web.base.url')
- return self.channel_id.share_template_id.with_context({'email': email, 'base_url': base_url}).send_mail(self.id)
+ return self.channel_id.share_template_id.with_context(email=email, base_url=base_url).send_mail(self.id)
# --------------------------------------------------
# Parsing methods
diff --git a/doc/cla/corporate/bacgroup.md b/doc/cla/corporate/bacgroup.md
new file mode 100644
index 00000000000..140a12e2e31
--- /dev/null
+++ b/doc/cla/corporate/bacgroup.md
@@ -0,0 +1,21 @@
+Honduras, 2017-01-12
+
+Business Analytics Consulting Group S.A. de C.V. 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,
+
+Leandro Gabriel Di Pasquale dipasquale@bacgroup.net https://github.com/leodipasquale
+
+List of contributors:
+
+Allan Daniel Aguilar Archaga aguilar@bacgroup.net https://github.com/allanaguilar
+Cesar Alejandro Rodriguez Castillo rodriguez@bacgroup.net https://github.com/hondurasopen
+Dewin Javier Garcia Armijo garcia@bacgroup.net https://github.com/dewingarcia
+Jose Reynaldo Cabrera Ayala cabrera@bacgroup.net https://github.com/jcabrera1990
+Leandro Gabriel Di Pasquale dipasquale@bacgroup.net https://github.com/leodipasquale
+Edwin Omar McClellan Salinas mcclellan@bacgroup.net https://github.com/prometeomcclellan
+Salvatore Josue Trimarchi Pinto trimarchi@bacgroup.net https://github.com/salvatoretrimarchi
diff --git a/doc/cla/individual/boogerlad.md b/doc/cla/individual/boogerlad.md
new file mode 100644
index 00000000000..af450cfd20a
--- /dev/null
+++ b/doc/cla/individual/boogerlad.md
@@ -0,0 +1,11 @@
+canada, 2017/1/3
+
+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,
+
+kevin hua boogerlad@gmail.com https://github.com/boogerlad
diff --git a/doc/cla/individual/dansanti.md b/doc/cla/individual/dansanti.md
new file mode 100644
index 00000000000..a13d64b6e27
--- /dev/null
+++ b/doc/cla/individual/dansanti.md
@@ -0,0 +1,9 @@
+Chile, 2016-05-31
+
+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,
+
+Daniel Santibáñez Polanco dansanti@gmail.com https://github.com/dansanti
\ No newline at end of file
diff --git a/doc/cla/individual/daramousk.md b/doc/cla/individual/daramousk.md
new file mode 100644
index 00000000000..6a38655a8bf
--- /dev/null
+++ b/doc/cla/individual/daramousk.md
@@ -0,0 +1,11 @@
+Greece, 2017-01-22
+
+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,
+
+George Daramouskas george.daramouskas@gmail.com https://github.com/daramousk
\ No newline at end of file
diff --git a/doc/cla/individual/jirizatloukal.md b/doc/cla/individual/jirizatloukal.md
new file mode 100644
index 00000000000..0dd581cf090
--- /dev/null
+++ b/doc/cla/individual/jirizatloukal.md
@@ -0,0 +1,11 @@
+The Czech Republic, 18.01.2017
+
+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,
+
+Jiri Zatloukal zatloukal@apitea.com https://github.com/jirizatloukal
\ No newline at end of file
diff --git a/doc/cla/individual/norlinhenrik.md b/doc/cla/individual/norlinhenrik.md
new file mode 100644
index 00000000000..fe15cf251a4
--- /dev/null
+++ b/doc/cla/individual/norlinhenrik.md
@@ -0,0 +1,11 @@
+Norway, 08.01.2017
+
+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,
+
+Henrik Norlin henrik.norl@gmail.com https://github.com/norlinhenrik
diff --git a/doc/cla/individual/zakiuu.md b/doc/cla/individual/zakiuu.md
new file mode 100644
index 00000000000..535c6e1d94a
--- /dev/null
+++ b/doc/cla/individual/zakiuu.md
@@ -0,0 +1,11 @@
+Algeria, 18/01/2017
+
+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,
+
+Zakria Makrelouf z.makrelouf@gmail.com https://github.com/zakiuu
diff --git a/odoo/addons/base/base.sql b/odoo/addons/base/base.sql
index 7372d2ff14f..31b7061cf78 100644
--- a/odoo/addons/base/base.sql
+++ b/odoo/addons/base/base.sql
@@ -67,6 +67,12 @@ CREATE TABLE res_users (
primary key(id)
);
+CREATE TABLE res_groups (
+ id serial NOT NULL,
+ name varchar NOT NULL,
+ primary key(id)
+);
+
CREATE TABLE ir_module_category (
id serial NOT NULL,
create_uid integer, -- references res_users on delete set null,
@@ -200,3 +206,7 @@ select setval('res_partner_id_seq', 2);
insert into res_users (id, login, password, active, partner_id, company_id) VALUES (1, 'admin', 'admin', true, 1, 1);
insert into ir_model_data (name, module, model, noupdate, res_id) VALUES ('user_root', 'base', 'res.users', true, 1);
select setval('res_users_id_seq', 2);
+
+insert into res_groups (id, name) VALUES (1, 'Employee');
+insert into ir_model_data (name, module, model, noupdate, res_id) VALUES ('group_user', 'base', 'res.groups', true, 1);
+select setval('res_groups_id_seq', 2);
diff --git a/odoo/addons/base/ir/ir_actions.py b/odoo/addons/base/ir/ir_actions.py
index d66abd39c67..44df2bc4770 100644
--- a/odoo/addons/base/ir/ir_actions.py
+++ b/odoo/addons/base/ir/ir_actions.py
@@ -659,6 +659,7 @@ class IrActionsServer(models.Model):
:return: an action_id to be executed, or False is finished correctly without
return action
"""
+ res = False
for action in self:
eval_context = self._get_eval_context(action)
if hasattr(self, 'run_action_%s_multi' % action.state):
diff --git a/odoo/addons/base/ir/ir_actions.xml b/odoo/addons/base/ir/ir_actions.xml
index 47e8e93418f..e43c06b1a69 100644
--- a/odoo/addons/base/ir/ir_actions.xml
+++ b/odoo/addons/base/ir/ir_actions.xml
@@ -167,7 +167,7 @@
-
+
@@ -263,13 +263,13 @@