diff --git a/addons/account/models/account_move.py b/addons/account/models/account_move.py
index 65bddb429c1..681d1b28df6 100644
--- a/addons/account/models/account_move.py
+++ b/addons/account/models/account_move.py
@@ -1257,6 +1257,8 @@ class AccountPartialReconcile(models.Model):
cancel the currency difference entry on the partner account (otherwise it will still appear on the aged balance
for example).
"""
+ # we must unlink the reconciliation with the exchange rate difference entry as well, to be able to reconcile it with its reversal entry
+ to_unlink = self
exchange_rate_entries = self.env['account.move'].search([('rate_diff_partial_rec_id', 'in', self.ids)])
# revert the currency difference entry
reversed_moves = exchange_rate_entries.reverse_moves()
@@ -1270,10 +1272,11 @@ class AccountPartialReconcile(models.Model):
if acm_line.account_id.reconcile:
for origin_line in origin_move.line_ids:
if origin_line.account_id == acm_line.account_id and origin_line.debit == acm_line.credit and origin_line.credit == acm_line.debit:
+ to_unlink |= origin_line.matched_debit_ids | origin_line.matched_credit_ids
to_rec = origin_line + acm_line
pairs_to_rec.append(to_rec)
# the call to super() had to be delayed in order to mark the move lines to reconcile together (to use 'rate_diff_partial_rec_id')
- res = super(AccountPartialReconcile, self).unlink()
+ res = super(AccountPartialReconcile, to_unlink).unlink()
# now that the origin currency difference line is not reconciled anymore, we can reconcile it with its reversal entry to cancel it completly
for to_rec in pairs_to_rec:
to_rec.reconcile()
diff --git a/addons/account_asset/account_asset_invoice.py b/addons/account_asset/account_asset_invoice.py
index 7a0b90c3581..db020599202 100644
--- a/addons/account_asset/account_asset_invoice.py
+++ b/addons/account_asset/account_asset_invoice.py
@@ -73,12 +73,14 @@ class AccountInvoiceLine(models.Model):
self.asset_category_id = self.product_id.product_tmpl_id.asset_category_id
def _set_additional_fields(self, invoice):
- if invoice.type == 'out_invoice':
- self.asset_category_id = self.product_id.product_tmpl_id.deferred_revenue_category_id.id
- elif invoice.type == 'in_invoice':
- self.asset_category_id = self.product_id.product_tmpl_id.asset_category_id.id
+ if not self.asset_category_id:
+ if invoice.type == 'out_invoice':
+ self.asset_category_id = self.product_id.product_tmpl_id.deferred_revenue_category_id.id
+ elif invoice.type == 'in_invoice':
+ self.asset_category_id = self.product_id.product_tmpl_id.asset_category_id.id
super(AccountInvoiceLine, self)._set_additional_fields(invoice)
+
class ProductTemplate(models.Model):
_inherit = 'product.template'
asset_category_id = fields.Many2one('account.asset.category', string='Asset Type', ondelete="restrict")
diff --git a/addons/account_full_reconcile/__init__.py b/addons/account_full_reconcile/__init__.py
new file mode 100644
index 00000000000..9c0ea901d41
--- /dev/null
+++ b/addons/account_full_reconcile/__init__.py
@@ -0,0 +1,97 @@
+# -*- coding: utf-8 -*-
+# Part of Odoo. See LICENSE file for full copyright and licensing details.
+
+import models
+
+from openerp import SUPERUSER_ID
+from collections import OrderedDict
+from openerp.tools import float_compare
+
+def _migrate_full_reconcile(cr, registry):
+ #avoid doing anything if the table has already something in it (already migrated)
+ cr.execute("""SELECT count(id) FROM account_full_reconcile""")
+ res = cr.fetchone()[0]
+ if res:
+ return
+ #check column reconcile_id exists on account.move.line
+ cr.execute("""
+ SELECT 1 FROM information_schema.columns
+ WHERE table_name = 'account_move_line'
+ AND column_name = 'reconcile_id'
+ """)
+ if not cr.fetchone():
+ #if no, it's a fresh v9 database and we cannot migrate anything. Rebuild the whole table based on partial
+ all_partial_rec_ids = registry['account.partial.reconcile'].search(cr, SUPERUSER_ID, [])
+ already_processed = {}
+ for partial in registry['account.partial.reconcile'].browse(cr, SUPERUSER_ID, all_partial_rec_ids):
+ partial_rec_set = OrderedDict.fromkeys([partial])
+ aml_set = set()
+ total_debit = 0
+ total_credit = 0
+ for partial_rec in partial_rec_set:
+ if partial_rec in already_processed:
+ continue
+ for aml in [partial_rec.debit_move_id, partial_rec.credit_move_id]:
+ if aml not in aml_set:
+ total_debit += aml.debit
+ total_credit += aml.credit
+ aml_set |= set([aml])
+ for x in aml.matched_debit_ids | aml.matched_credit_ids:
+ partial_rec_set[x] = None
+ partial_rec_ids = []
+ for x in partial_rec_set.keys():
+ partial_rec_ids.append(x.id)
+ already_processed[x] = None
+ aml_ids = [x.id for x in aml_set]
+ if aml_ids and partial_rec_ids:
+ #then, if the total debit and credit are equal, the reconciliation is full
+ digits_rounding_precision = aml.company_id.currency_id.rounding
+ if float_compare(total_debit, total_credit, precision_rounding=digits_rounding_precision) == 0:
+ #in that case, mark the reference on the partial reconciliations and the entries
+ registry['account.full.reconcile'].create(cr, SUPERUSER_ID, {
+ 'partial_reconcile_ids': [(6, 0, partial_rec_ids)],
+ 'reconciled_line_ids': [(6, 0, aml_ids)]
+ }, context={'check_move_validity': False})
+ return
+
+ #otherwise, use the table account_move_reconcile if it exists (not dropped by migration)
+ cr.execute("SELECT 1 FROM information_schema.tables WHERE table_name = 'account_move_reconcile'")
+ if cr.fetchone():
+ #account_move_reconcile exists
+ #copy old table
+ cr.execute("""
+ INSERT INTO account_full_reconcile (id, name, create_date)
+ SELECT id, name, create_date
+ FROM account_move_reconcile
+ WHERE id IN (
+ SELECT DISTINCT reconcile_id FROM account_move_line WHERE reconcile_id IS NOT NULL)
+ """)
+ else:
+ #account_move_reconcile was dropped during migration, rebuild that table
+ cr.execute("""
+ INSERT INTO account_full_reconcile (id, name)
+ SELECT DISTINCT reconcile_id, reconcile_ref FROM account_move_line WHERE reconcile_id IS NOT NULL
+ """)
+ #update the index of account_full_reconcile
+ cr.execute("SELECT setval('account_full_reconcile_id_seq', (SELECT MAX(id) FROM account_full_reconcile))")
+
+ #copy values on account.move.line
+ cr.execute("UPDATE account_move_line SET full_reconcile_id = reconcile_id WHERE reconcile_id IS NOT NULL")
+ #copy the full_reconcile_id existing of account.move.line to their account.partial.reconcile
+ cr.execute("""
+ WITH tmp_table AS (
+ SELECT rec.id AS partial_id, aml.reconcile_id AS full_id
+ FROM account_move_line aml
+ RIGHT JOIN account_partial_reconcile rec
+ ON aml.id = rec.debit_move_id
+ WHERE aml.reconcile_id IS NOT NULL
+ UNION
+ SELECT rec.id AS partial_id, aml.reconcile_id AS full_id
+ FROM account_move_line aml
+ RIGHT JOIN account_partial_reconcile rec
+ ON aml.id = rec.credit_move_id
+ WHERE aml.reconcile_id IS NOT NULL)
+ UPDATE account_partial_reconcile p
+ SET full_reconcile_id = (SELECT full_id FROM tmp_table tmp WHERE p.id = tmp.partial_id)
+ WHERE p.id IN (SELECT partial_id FROM tmp_table)
+ """)
diff --git a/addons/account_full_reconcile/__openerp__.py b/addons/account_full_reconcile/__openerp__.py
new file mode 100644
index 00000000000..f2c54d31d9e
--- /dev/null
+++ b/addons/account_full_reconcile/__openerp__.py
@@ -0,0 +1,21 @@
+# -*- coding: utf-8 -*-
+# Part of Odoo. See LICENSE file for full copyright and licensing details.
+
+{
+ 'name': 'Full Reconciliation Concept',
+ 'version': '1.1',
+ 'category': 'Accounting & Finance',
+ 'description': """
+Add the concept of full reconciliation back into the accounting.
+ """,
+ 'website': 'https://www.odoo.com/page/accounting',
+ 'depends': ['account'],
+ 'data': [
+ 'security/ir.model.access.csv',
+ 'views/account_full_reconcile_view.xml',
+ ],
+ 'demo': [],
+ 'installable': True,
+ 'auto_install': True,
+ 'post_init_hook': '_migrate_full_reconcile',
+}
diff --git a/addons/account_full_reconcile/models/__init__.py b/addons/account_full_reconcile/models/__init__.py
new file mode 100644
index 00000000000..03e58f9db59
--- /dev/null
+++ b/addons/account_full_reconcile/models/__init__.py
@@ -0,0 +1,4 @@
+# -*- coding: utf-8 -*-
+# Part of Odoo. See LICENSE file for full copyright and licensing details.
+
+import account_full_reconcile
diff --git a/addons/account_full_reconcile/models/account_full_reconcile.py b/addons/account_full_reconcile/models/account_full_reconcile.py
new file mode 100644
index 00000000000..4b666f88371
--- /dev/null
+++ b/addons/account_full_reconcile/models/account_full_reconcile.py
@@ -0,0 +1,64 @@
+# -*- coding: utf-8 -*-
+# Part of Odoo. See LICENSE file for full copyright and licensing details.
+
+from collections import OrderedDict
+from openerp.tools import float_compare
+from openerp import api, fields, models
+
+
+class AccountMoveLine(models.Model):
+ _inherit = "account.move.line"
+ full_reconcile_id = fields.Many2one('account.full.reconcile', string="Matching Number")
+
+
+class AccountPartialReconcile(models.Model):
+ _inherit = "account.partial.reconcile"
+
+ full_reconcile_id = fields.Many2one('account.full.reconcile', string="Full Reconcile")
+
+ @api.model
+ def create(self, vals):
+ res = super(AccountPartialReconcile, self).create(vals)
+ #check if the reconcilation is full
+ #first, gather all journal items involved in the reconciliation just created
+ partial_rec_set = OrderedDict.fromkeys([x for x in res])
+ aml_set = self.env['account.move.line']
+ total_debit = 0
+ total_credit = 0
+ for partial_rec in partial_rec_set:
+ for aml in [partial_rec.debit_move_id, partial_rec.credit_move_id]:
+ if aml not in aml_set:
+ total_debit += aml.debit
+ total_credit += aml.credit
+ aml_set |= aml
+ for x in aml.matched_debit_ids | aml.matched_credit_ids:
+ partial_rec_set[x] = None
+ partial_rec_ids = [x.id for x in partial_rec_set.keys()]
+ aml_ids = [x.id for x in aml_set]
+ #then, if the total debit and credit are equal, the reconciliation is full
+ digits_rounding_precision = aml_set[0].company_id.currency_id.rounding
+ if float_compare(total_debit, total_credit, precision_rounding=digits_rounding_precision) == 0:
+ #in that case, mark the reference on the partial reconciliations and the entries
+ self.env['account.full.reconcile'].with_context(check_move_validity=False).create({
+ 'partial_reconcile_ids': [(6, 0, partial_rec_ids)],
+ 'reconciled_line_ids': [(6, 0, aml_ids)]})
+ return res
+
+ @api.multi
+ def unlink(self):
+ """When removing a partial reconciliation, also unlink its full reconciliation if it exists"""
+ full_rec = self.env['account.full.reconcile']
+ for rec in self:
+ if rec.full_reconcile_id:
+ full_rec |= rec.full_reconcile_id
+ full_rec.unlink()
+ return super(AccountPartialReconcile, self).unlink()
+
+
+class AccountFullReconcile(models.Model):
+ _name = "account.full.reconcile"
+ _description = "Full Reconcile"
+
+ name = fields.Char(string='Number', required=True, copy=False, default=lambda self: self.env['ir.sequence'].next_by_code('account.reconcile'))
+ partial_reconcile_ids = fields.One2many('account.partial.reconcile', 'full_reconcile_id', string='Reconciliation Parts')
+ reconciled_line_ids = fields.One2many('account.move.line', 'full_reconcile_id', string='Matched Journal Items')
diff --git a/addons/account_full_reconcile/security/ir.model.access.csv b/addons/account_full_reconcile/security/ir.model.access.csv
new file mode 100644
index 00000000000..08cd0c1b3a9
--- /dev/null
+++ b/addons/account_full_reconcile/security/ir.model.access.csv
@@ -0,0 +1,3 @@
+id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
+access_account_full_reconcile_group_invoice,account.full.reconcile.group.invoice,model_account_full_reconcile,account.group_account_invoice,1,1,1,0
+access_account_full_reconcile,account.full.reconcile,model_account_full_reconcile,account.group_account_user,1,1,1,1
diff --git a/addons/account_full_reconcile/views/account_full_reconcile_view.xml b/addons/account_full_reconcile/views/account_full_reconcile_view.xml
new file mode 100644
index 00000000000..db67f4729b3
--- /dev/null
+++ b/addons/account_full_reconcile/views/account_full_reconcile_view.xml
@@ -0,0 +1,50 @@
+
+
+
+
+
+
+ account.full.reconcile.form
+ account.full.reconcile
+
+
+
+
+
+
+ account.move.line.form.full.reconcile
+ account.move.line
+
+
+
+
+
+
+
+ 1
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/addons/crm/report/crm_activity_report.py b/addons/crm/report/crm_activity_report.py
index 5bf4445fc72..ae7ac6621e0 100644
--- a/addons/crm/report/crm_activity_report.py
+++ b/addons/crm/report/crm_activity_report.py
@@ -44,14 +44,10 @@ class crm_activity_report(models.Model):
l.type as lead_type
from
"mail_message" m
- left join
+ join
"crm_lead" l
on
(m.res_id = l.id)
- inner join
- "crm_activity" a
- on
- (m.subtype_id = a.subtype_id)
WHERE
(m.model = 'crm.lead')
)""")
diff --git a/addons/crm/report/crm_opportunity_report.py b/addons/crm/report/crm_opportunity_report.py
index c690e79799d..b612d3ad349 100644
--- a/addons/crm/report/crm_opportunity_report.py
+++ b/addons/crm/report/crm_opportunity_report.py
@@ -68,7 +68,9 @@ class crm_opportunity_report(osv.Model):
c.company_id,
c.priority,
c.team_id,
- activity.nbr_activities,
+ (SELECT COUNT(*)
+ FROM mail_message m
+ WHERE m.model = 'crm.lead' and m.res_id = c.id) as nbr_activity,
c.active,
c.campaign_id,
c.source_id,
@@ -85,14 +87,7 @@ class crm_opportunity_report(osv.Model):
c.date_conversion as date_conversion
FROM
"crm_lead" c
- LEFT JOIN (
- SELECT m.res_id, COUNT(*) nbr_activities
- FROM "mail_message" m
- WHERE m.model = 'crm.lead'
- GROUP BY m.res_id ) activity
- ON
- (activity.res_id = c.id)
LEFT JOIN "crm_stage" stage
ON stage.id = c.stage_id
- GROUP BY c.id, activity.nbr_activities, stage.name
+ GROUP BY c.id, stage.name
)""")
diff --git a/addons/delivery/models/sale_order.py b/addons/delivery/models/sale_order.py
index 233723ce712..dd9459b38bf 100644
--- a/addons/delivery/models/sale_order.py
+++ b/addons/delivery/models/sale_order.py
@@ -93,11 +93,6 @@ class SaleOrder(models.Model):
if self.order_line:
values['sequence'] = self.order_line[-1].sequence + 1
sol = SaleOrderLine.create(values)
- if hasattr(sol, 'product_id_change_margin'):
- # if `sale_margin` module is installed, force computation of field `purchase_price`
- # As there is not dependency between modules (nor a bridge module), this is the only
- # place we can get the value for this field
- sol.product_id_change_margin()
return sol
diff --git a/addons/payment/security/ir.model.access.csv b/addons/payment/security/ir.model.access.csv
index 942718807d5..4b04317deb3 100644
--- a/addons/payment/security/ir.model.access.csv
+++ b/addons/payment/security/ir.model.access.csv
@@ -6,6 +6,6 @@ payment_transaction_all,payment.transaction.all,model_payment_transaction,,1,0,0
payment_transaction_user,payment.transaction.user,model_payment_transaction,base.group_user,1,1,1,0
payment_transaction_system,payment.transaction.system,model_payment_transaction,base.group_system,1,1,1,1
payment_method_all,payment.method.all,model_payment_method,,1,0,0,0
-payment_method_user,payment.method.user,model_payment_method,base.group_user,1,1,1,0
-payment_method_portal,payment.method.portal,model_payment_method,base.group_portal,1,1,1,0
+payment_method_user,payment.method.user,model_payment_method,base.group_user,1,1,1,1
+payment_method_portal,payment.method.portal,model_payment_method,base.group_portal,1,1,1,1
payment_method_system,payment.method.system,model_payment_method,base.group_system,1,1,1,1
diff --git a/addons/pos_mercury/static/src/xml/pos_mercury.xml b/addons/pos_mercury/static/src/xml/pos_mercury.xml
index bb8071a5a59..02f25588a3c 100644
--- a/addons/pos_mercury/static/src/xml/pos_mercury.xml
+++ b/addons/pos_mercury/static/src/xml/pos_mercury.xml
@@ -55,7 +55,6 @@
-
APPROVAL CODE:
diff --git a/addons/sale/sale.py b/addons/sale/sale.py
index 667c3f79c39..6f9be4c82bb 100644
--- a/addons/sale/sale.py
+++ b/addons/sale/sale.py
@@ -318,6 +318,9 @@ class SaleOrder(models.Model):
invoice.type = 'out_refund'
for line in invoice.invoice_line_ids:
line.quantity = -line.quantity
+ # Use additional field helper function (for account extensions)
+ for line in invoice.invoice_line_ids:
+ line._set_additional_fields(invoice)
# Necessary to force computation of taxes. In account_invoice, they are triggered
# by onchanges, which are not triggered when doing a create.
invoice.compute_taxes()
@@ -759,15 +762,6 @@ class SaleOrderLine(models.Model):
raise UserError(_('You can not remove a sale order line.\nDiscard changes and try setting the quantity to 0.'))
return super(SaleOrderLine, self).unlink()
- def onchange_product_uom(self, cursor, user, ids, pricelist, product, qty=0,
- uom=False, qty_uos=0, uos=False, name='', partner_id=False,
- lang=False, update_tax=True, date_order=False, fiscal_position=False, context=None):
- ctx = dict(context or {}, fiscal_position=fiscal_position)
- return self.product_uom_change(cursor, user, ids, pricelist, product,
- qty=qty, uom=uom, qty_uos=qty_uos, uos=uos, name=name,
- partner_id=partner_id, lang=lang, update_tax=update_tax,
- date_order=date_order, context=ctx)
-
@api.multi
def _get_delivered_qty(self):
'''
diff --git a/addons/sale_margin/sale_margin.py b/addons/sale_margin/sale_margin.py
index 12398dce41e..a585821a32d 100644
--- a/addons/sale_margin/sale_margin.py
+++ b/addons/sale_margin/sale_margin.py
@@ -7,20 +7,35 @@ import openerp.addons.decimal_precision as dp
class sale_order_line(osv.osv):
_inherit = "sale.order.line"
- @api.multi
+ def _compute_margin(self, order_id, product_id, product_uom_id):
+ frm_cur = self.env.user.company_id.currency_id
+ to_cur = order_id.pricelist_id.currency_id
+ purchase_price = product_id.standard_price
+ if product_uom_id != product_id.uom_id:
+ purchase_price = self.env['product.uom']._compute_price(product_id.uom_id.id, purchase_price, to_uom_id=product_uom_id.id)
+ ctx = self.env.context.copy()
+ ctx['date'] = order_id.date_order
+ price = frm_cur.with_context(ctx).compute(purchase_price, to_cur, round=False)
+ return price
+
@api.onchange('product_id', 'product_uom')
def product_id_change_margin(self):
- for line in self:
- if line.order_id.pricelist_id:
- frm_cur = self.env.user.company_id.currency_id
- to_cur = line.order_id.pricelist_id.currency_id
- purchase_price = line.product_id.standard_price
- if line.product_uom != line.product_id.uom_id:
- purchase_price = self.env['product.uom']._compute_price(line.product_id.uom_id.id, purchase_price, to_uom_id=line.product_uom.id)
- ctx = self.env.context.copy()
- ctx['date'] = line.order_id.date_order
- price = frm_cur.with_context(ctx).compute(purchase_price, to_cur, round=False)
- line.purchase_price = price
+ if not self.order_id.pricelist_id or not self.product_id or not self.product_uom:
+ return
+ self.purchase_price = self._compute_margin(self.order_id, self.product_id, self.product_uom)
+
+ @api.model
+ def create(self, vals):
+ # Calculation of the margin for programmatic creation of a SO line. It is therefore not
+ # necessary to call product_id_change_margin manually
+ if 'purchase_price' not in vals:
+ order_id = self.env['sale.order'].browse(vals['order_id'])
+ product_id = self.env['product.product'].browse(vals['product_id'])
+ product_uom_id = self.env['product.uom'].browse(vals['product_uom'])
+
+ vals['purchase_price'] = self._compute_margin(order_id, product_id, product_uom_id)
+
+ return super(sale_order_line, self).create(vals)
def _product_margin(self, cr, uid, ids, field_name, arg, context=None):
cur_obj = self.pool.get('res.currency')
diff --git a/addons/sale_mrp/tests/test_move_explode.py b/addons/sale_mrp/tests/test_move_explode.py
index a7e3bdea946..84a13aff959 100644
--- a/addons/sale_mrp/tests/test_move_explode.py
+++ b/addons/sale_mrp/tests/test_move_explode.py
@@ -48,7 +48,7 @@ class TestMoveExplode(common.TransactionCase):
'partner_shipping_id': self.partner.id,
'pricelist_id': self.pricelist.id,
}
- self.so = self.SaleOrder.create(vals=so_vals)
+ self.so = self.SaleOrder.create(so_vals)
sol_vals = {
'order_id': self.so.id,
'name': self.product_bom.name,
@@ -56,7 +56,7 @@ class TestMoveExplode(common.TransactionCase):
'product_uom': self.product_bom.uom_id.id,
'product_uom_qty': 1.0,
}
- self.SaleOrderLine.create(values=sol_vals)
+ self.SaleOrderLine.create(sol_vals)
#confirm sale order
self.so.action_confirm()
#get all move associated to that sale_order
diff --git a/addons/web_kanban/static/src/js/kanban_widgets.js b/addons/web_kanban/static/src/js/kanban_widgets.js
index 014e50dec3f..53b75bb3bc1 100644
--- a/addons/web_kanban/static/src/js/kanban_widgets.js
+++ b/addons/web_kanban/static/src/js/kanban_widgets.js
@@ -54,7 +54,7 @@ var FormatChar = AbstractField.extend({
this.format_descriptor = _.extend({}, this.field, {'widget': this.$node.attr('widget')});
},
renderElement: function() {
- this.$el.text(instance.web.format_value(this.field.raw_value, this.format_descriptor));
+ this.$el.text(formats.format_value(this.field.raw_value, this.format_descriptor));
}
});
diff --git a/addons/web_tip/web_tip_data.xml b/addons/web_tip/web_tip_data.xml
index 6102d80637d..db24632ce9e 100644
--- a/addons/web_tip/web_tip_data.xml
+++ b/addons/web_tip/web_tip_data.xml
@@ -43,8 +43,8 @@
form
- button > .fa-archive
- button > .fa-archive
+ [name="button_box"] button > .fa-archive
+ [name="button_box"] button:has(.fa-archive)mousedownbottom
diff --git a/addons/website/models/website.py b/addons/website/models/website.py
index c1ca74d7c1d..88ad2afd3ea 100644
--- a/addons/website/models/website.py
+++ b/addons/website/models/website.py
@@ -403,10 +403,13 @@ class website(osv.osv):
return Access.check(cr, uid, 'ir.ui.menu', 'read', False, context=context)
def get_template(self, cr, uid, ids, template, context=None):
- if not isinstance(template, (int, long)) and '.' not in template:
- template = 'website.%s' % template
View = self.pool['ir.ui.view']
- view_id = View.get_view_id(cr, uid, template, context=context)
+ if isinstance(template, (int, long)):
+ view_id = template
+ else:
+ if '.' not in template:
+ template = 'website.%s' % template
+ view_id = View.get_view_id(cr, uid, template, context=context)
if not view_id:
raise NotFound
return View.browse(cr, uid, view_id, context=context)
diff --git a/openerp/addons/base/ir/ir_attachment.py b/openerp/addons/base/ir/ir_attachment.py
index 18311e0ce53..2488726ff48 100644
--- a/openerp/addons/base/ir/ir_attachment.py
+++ b/openerp/addons/base/ir/ir_attachment.py
@@ -165,7 +165,7 @@ class ir_attachment(osv.osv):
fname_to_delete = attach.store_fname
location = self._storage(cr, uid, context)
# compute the index_content field
- vals['index_content'] = self._index(cr, SUPERUSER_ID, bin_data, attach.datas_fname, attach.mimetype),
+ vals['index_content'] = self._index(cr, SUPERUSER_ID, bin_data, attach.datas_fname, attach.mimetype)
if location != 'db':
# create the file
fname = self._file_write(cr, uid, value, checksum)