From 813b6a84ab9397508d41e15ffc4bc45f3cdb06c2 Mon Sep 17 00:00:00 2001 From: qsm-odoo Date: Thu, 25 Feb 2016 14:37:31 +0100 Subject: [PATCH 01/15] [FIX] web_tip: tip inside button In FF, there cannot be a clickable element inside a button tag. So the tip on the icon in a button_box button was not able to be dismissed. The tip selector is changed so that the highlighted element is the button itself and not the icon it contains. --- addons/web_tip/web_tip_data.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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) mousedown bottom From 67edccbc7f7169229c3dabfe13f9a334e0a27da9 Mon Sep 17 00:00:00 2001 From: Nicolas Martinelli Date: Wed, 24 Feb 2016 15:02:36 +0100 Subject: [PATCH 02/15] [FIX] sale: wrong forwardport This reverts commits ca40236 and 4ed5d65. The commits were developed in v8.0 and were not meant to be forward ported to 9.0. --- addons/sale/sale.py | 9 --------- 1 file changed, 9 deletions(-) diff --git a/addons/sale/sale.py b/addons/sale/sale.py index c975b90ee05..24bf36fab9c 100644 --- a/addons/sale/sale.py +++ b/addons/sale/sale.py @@ -760,15 +760,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): ''' From 16f698f6be1e9d20b8232900a8990f5383875c8b Mon Sep 17 00:00:00 2001 From: Nicolas Martinelli Date: Thu, 25 Feb 2016 13:44:25 +0100 Subject: [PATCH 03/15] [FIX] sale_margin, delivery: margin at creation The `purchase_price` is filled in automatically thanks to the onchange method `product_id_change_margin`. However, when a SO is created programatically, it is necessary to call manually the method in order to fill in the field. This is not convenient since the module sale_margin might not be installed, and crappy workaround (such as the use of `hasattr`) are necessary. To avoid this, this fix automatically computes the purchase price at creation if no value is provided. --- addons/delivery/models/sale_order.py | 5 --- addons/sale_margin/sale_margin.py | 39 +++++++++++++++------- addons/sale_mrp/tests/test_move_explode.py | 4 +-- 3 files changed, 29 insertions(+), 19 deletions(-) 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/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 From a565f35bae3e47788d396db043292215f356e163 Mon Sep 17 00:00:00 2001 From: Joren Van Onder Date: Thu, 25 Feb 2016 16:18:26 +0100 Subject: [PATCH 04/15] [FIX] pos_mercury: get rid of debug in template Been in there since the introduction of the module at 04fb3dfc. Didn't really affect anything as long as you don't have developer tools open while you're printing a ticket on the POSBox. This explains why it has remained unnoticed for this long. --- addons/pos_mercury/static/src/xml/pos_mercury.xml | 1 - 1 file changed, 1 deletion(-) 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:
From 550fa2650accdc32060c242e09c196ee01b13845 Mon Sep 17 00:00:00 2001 From: Damien Bouvy Date: Thu, 25 Feb 2016 11:33:53 +0100 Subject: [PATCH 05/15] [FIX] account_asset: do not overwrite self.asset_category_id if it's already defined The function _set_additional_fields is used to avoid creating a ton of auto-install modules; account extension extend this function and modules that create invoices call it. But when calling this function, it would be better not to overwrite existing values; hence this check. --- addons/account_asset/account_asset_invoice.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) 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") From 89df4aa5ec9af4e9ac8875d3c4402b3c1a125be9 Mon Sep 17 00:00:00 2001 From: Damien Bouvy Date: Thu, 25 Feb 2016 11:37:04 +0100 Subject: [PATCH 06/15] [FIX] sale: when creating the invoice, call the additional fields helper function This function is there to avoid creating link modules, it is extended by account modules and should be called by methods that create invoices. This call was missing in sale. --- addons/sale/sale.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/addons/sale/sale.py b/addons/sale/sale.py index 24bf36fab9c..bd5eab6c943 100644 --- a/addons/sale/sale.py +++ b/addons/sale/sale.py @@ -319,6 +319,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() From 395c4bdc691528503c6dd4168fcda40d0aecc84d Mon Sep 17 00:00:00 2001 From: qdp-odoo Date: Fri, 26 Feb 2016 11:19:45 +0100 Subject: [PATCH 07/15] [ADD] account_full_reconcile: module that reintroduce the concept of full reconciliation, to have a named reference on journal items --- addons/account_full_reconcile/__init__.py | 97 +++++++++++++++++++ addons/account_full_reconcile/__openerp__.py | 21 ++++ .../account_full_reconcile/models/__init__.py | 4 + .../models/account_full_reconcile.py | 64 ++++++++++++ .../security/ir.model.access.csv | 3 + .../views/account_full_reconcile_view.xml | 50 ++++++++++ 6 files changed, 239 insertions(+) create mode 100644 addons/account_full_reconcile/__init__.py create mode 100644 addons/account_full_reconcile/__openerp__.py create mode 100644 addons/account_full_reconcile/models/__init__.py create mode 100644 addons/account_full_reconcile/models/account_full_reconcile.py create mode 100644 addons/account_full_reconcile/security/ir.model.access.csv create mode 100644 addons/account_full_reconcile/views/account_full_reconcile_view.xml 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 + + + + + + + + + + +
+
+ From bec9c19a2d17e2400162bd4b1b0a2587b605232a Mon Sep 17 00:00:00 2001 From: qdp-odoo Date: Fri, 26 Feb 2016 11:23:13 +0100 Subject: [PATCH 08/15] [FIX] account: unreconciling a journal item partially that has a currency difference linked was not allowed because the exchange rate was still linked to another line, and thus couldn't be reconciled with its reversal --- addons/account/models/account_move.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/addons/account/models/account_move.py b/addons/account/models/account_move.py index 69df6717fbd..56f7adf6cee 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() From c9a1d4d01c2d91c4ab792eb25a83fae5b6cc5756 Mon Sep 17 00:00:00 2001 From: Damien Bouvy Date: Fri, 26 Feb 2016 13:43:05 +0100 Subject: [PATCH 09/15] [FIX] payment: missing delete right for portal user Portal users should be able to delete their credit card/payment method. This ACL in combination with the ir.rule allows them to do so. --- addons/payment/security/ir.model.access.csv | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/payment/security/ir.model.access.csv b/addons/payment/security/ir.model.access.csv index 942718807d5..a3beec07095 100644 --- a/addons/payment/security/ir.model.access.csv +++ b/addons/payment/security/ir.model.access.csv @@ -7,5 +7,5 @@ payment_transaction_user,payment.transaction.user,model_payment_transaction,base 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_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 From a0bc204bb17fd5c75bded6a5730b4e0a6fbbb357 Mon Sep 17 00:00:00 2001 From: Damien Bouvy Date: Fri, 26 Feb 2016 13:48:19 +0100 Subject: [PATCH 10/15] [FIX] payment: missing right for users on payment method Let's be consistent, shall we? If portal users can delete their own card, employees should have the same rights. --- addons/payment/security/ir.model.access.csv | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/payment/security/ir.model.access.csv b/addons/payment/security/ir.model.access.csv index a3beec07095..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_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 From 920ada7054531f63bd9ee8cbc4bf84086c4b0d1e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Fri, 29 Jan 2016 15:41:18 +0100 Subject: [PATCH 11/15] [FIX] website: wrong computation of view get_template should accept ids or xml ids. However the id or xml_id is given to IrUiView.get_view_id that waits for an xml_id. get_template crashed if it received an id. This commit solves this by setting view_id to the given id, or resolve the xml_id through get_view_id. --- addons/website/models/website.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/addons/website/models/website.py b/addons/website/models/website.py index 5ab76974113..5582ba99e07 100644 --- a/addons/website/models/website.py +++ b/addons/website/models/website.py @@ -393,10 +393,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) From de9342fac47c11489cab7dec1d0927a140c6e9ba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9rome=20Maes?= Date: Thu, 25 Feb 2016 15:38:04 +0100 Subject: [PATCH 12/15] [FIX] ir_attachment : potential buggy comma Copy/paste mistake and the comma stays at the end of the line. This causes a wrong affectation : indeed, `index_content` gets a tuple with the desired value. This does not cause crashes, and the representation of the tuple is correctly stored in database, but this is not the expected behavior. --- openerp/addons/base/ir/ir_attachment.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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) From c5b879bfd29a972d8b8f8fb95038694ac8bdc485 Mon Sep 17 00:00:00 2001 From: Olivier Dony Date: Tue, 23 Feb 2016 15:44:04 +0100 Subject: [PATCH 13/15] [FIX] crm.opportunity.report: query performance Using a subselect is more efficient than constructing a complete temporary table of all messages, and then joining them. This way only messages or relevant opportunities are used, as most of the time the report is accessed for a specific subset of opportunities (by date, salesman, stage, etc.). The query planner can then use the dedicated index to quickly access the corresponding messages. On a sample database with 1 million crm.lead entries and 10 million mail.message entries this brings the time for a typical read_group call on crm.opportunity.report down from 300s to 500ms (600x faster) --- addons/crm/report/crm_opportunity_report.py | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) 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 )""") From 602f3423c1fe43ba1af93a05bd5ed2fd76c8f3e9 Mon Sep 17 00:00:00 2001 From: Olivier Dony Date: Wed, 24 Feb 2016 11:06:21 +0100 Subject: [PATCH 14/15] [FIX] crm.activity.report: consider all messages as activities When counting the 'activities' on each opportunity/lead, this view only considered messages with a subtype that matched the subtype of a specific crm.activity. This was not consistent with the crm.opportunity.report which counted *all* messages on an opportunity as "activitiy entries". The latter is considered better because any entry, (even automated one for tracking field value changes or automated system responses) corresponds to an "action" taken on that record. This patch makes crm.activity.report consistent with this decision: it will now count all messages. + also convert the incorrect `left join` to a plain [inner] `join`, as we don't want deleted leads to appear in case orphan messages were left around (which should not happen anyway). --- addons/crm/report/crm_activity_report.py | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) 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') )""") From 4c1c1ec4d47fefe021e7568ed5c5539876b0da08 Mon Sep 17 00:00:00 2001 From: Thibault Francois Date: Wed, 24 Feb 2016 11:07:44 +0100 Subject: [PATCH 15/15] [FIX] web_kanban: float_time widget did not work `instance` was undefined in this context, probably following a forward-port mistake --- addons/web_kanban/static/src/js/kanban_widgets.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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)); } });