← Back to team overview

openerp-community-reviewer team mailing list archive

[Merge] lp:~therp-nl/ocb-addons/lp754339 into lp:ocb-addons

 

Holger Brunn (Therp) has proposed merging lp:~therp-nl/ocb-addons/lp754339 into lp:ocb-addons.

Requested reviews:
  Stefan Rijnhart (Therp) (stefan-therp)
  Holger Brunn (Therp) (hbrunn)
Related bugs:
  Bug #754339 in OpenERP Community Backports (Addons): "Partner assigned Price List is not applied with the creation of a customer/supplier invoice."
  https://bugs.launchpad.net/ocb-addons/+bug/754339

For more details, see:
https://code.launchpad.net/~therp-nl/ocb-addons/lp754339/+merge/189107

This is a port of the fix to have prices in manually added invoice lines originate from the partner's pricelist, if any. If there are no pricelists involved, nothing should change.
-- 
https://code.launchpad.net/~therp-nl/ocb-addons/lp754339/+merge/189107
Your team OpenERP Community Backports Team is subscribed to branch lp:ocb-addons.
=== modified file 'account/account_invoice.py'
--- account/account_invoice.py	2013-09-20 09:50:26 +0000
+++ account/account_invoice.py	2013-10-15 14:15:30 +0000
@@ -1519,11 +1519,19 @@
         else:
             taxes = res.supplier_taxes_id and res.supplier_taxes_id or (a and self.pool.get('account.account').browse(cr, uid, a, context=context).tax_ids or False)
         tax_id = fpos_obj.map_tax(cr, uid, fpos, taxes)
-
-        if type in ('in_invoice', 'in_refund'):
-            result.update( {'price_unit': price_unit or res.standard_price,'invoice_line_tax_id': tax_id} )
-        else:
-            result.update({'price_unit': res.list_price, 'invoice_line_tax_id': tax_id})
+        result['invoice_line_tax_id'] = tax_id
+
+        warning = {}
+        # When product changes, price ALWAYS need to be reset. If not price
+        # found in product, or pricelist, it should become False. Only if
+        # product_id has been cleared by user, we will leave price_unit as is.
+        if  product:
+            price_unit, pu_warning = self._price_unit_get(
+                cr, uid, product, uom_id, qty, type, partner_id,
+                currency_id, context=context)
+            result['price_unit'] = price_unit  # might be False
+            warning.update(pu_warning)
+
         result['name'] = res.partner_ref
 
         result['uos_id'] = uom_id or res.uom_id.id
@@ -1532,26 +1540,81 @@
 
         domain = {'uos_id':[('category_id','=',res.uom_id.category_id.id)]}
 
-        res_final = {'value':result, 'domain':domain}
-
-        if not company_id or not currency_id:
-            return res_final
-
-        company = self.pool.get('res.company').browse(cr, uid, company_id, context=context)
-        currency = self.pool.get('res.currency').browse(cr, uid, currency_id, context=context)
-
-        if company.currency_id.id != currency.id:
-            if type in ('in_invoice', 'in_refund'):
-                res_final['value']['price_unit'] = res.standard_price
-            new_price = res_final['value']['price_unit'] * currency.rate
-            res_final['value']['price_unit'] = new_price
-
-        if result['uos_id'] and result['uos_id'] != res.uom_id.id:
-            selected_uom = self.pool.get('product.uom').browse(cr, uid, result['uos_id'], context=context)
-            new_price = self.pool.get('product.uom')._compute_price(cr, uid, res.uom_id.id, res_final['value']['price_unit'], result['uos_id'])
-            res_final['value']['price_unit'] = new_price
+        res_final = {'value': result, 'domain': domain, 'warning': warning}
         return res_final
 
+    def _price_unit_get(
+            self, cr, uid, product_id, uom_id, qty, invoice_type, partner_id,
+            currency_id, context=None):
+        price_unit = False
+        warning = {}
+        standard_currency_id = currency_id
+        partner_model = self.pool.get('res.partner')
+        partner_obj = partner_model.browse(
+            cr, uid, partner_id, context=context)
+        assert partner_obj, _('No partner found for id %d') % partner_id
+        if invoice_type in ('in_invoice', 'in_refund'):
+            field = 'list_price'
+            pricelist_property = 'property_product_pricelist_purchase'
+        else:
+            field = 'standard_price'
+            pricelist_property = 'property_product_pricelist'
+        if  pricelist_property in partner_obj:
+            pricelist_id = partner_obj[pricelist_property].id
+        else:
+            pricelist_id = False
+        # Check whether standard price p.u. modified by pricelist
+        if  pricelist_id:
+            pricelist_model = self.pool.get('product.pricelist')
+            price_unit = pricelist_model.price_get(
+                cr, uid, [pricelist_id], product_id, qty or 1.0,
+                partner=partner_id,
+                context=dict(context, uom=uom_id))[pricelist_id]
+            if  price_unit is False:  # 0.0 is OK, we night have free products
+                warning = {
+                   'title': _('No valid pricelist line found!'),
+                   'message':
+                    _("Couldn't find a pricelist line matching this product"
+                    " and quantity.\n"
+                    "You have to change either the product, the quantity or"
+                    " the pricelist.")
+                }
+            # Pricelist converts price from standard currency to pricelist
+            # currency. We have to convert this to the invoice currency.
+            # In practice that will often mean undoing the conversion
+            # done by the pricelist object
+            pricelist_obj = pricelist_model.browse(
+                    cr, uid, pricelist_id, context=context)
+            if  pricelist_obj and pricelist_obj.currency_id:
+                standard_currency_id = pricelist_obj.currency_id.id
+        else:
+            # Take standard price per unit directly from product
+            product_model = self.pool.get('product.product')
+            product_obj = product_model.browse(
+                cr, uid, product_id, context=context)
+            assert product_obj, _('No product found for id %d') % product_id
+            assert field in product_obj, _(
+                'Field %s not found in product') % field
+            price_unit = product_obj.uom_id._compute_price(
+                    cr, uid, product_obj.uom_id.id, product_obj[field], uom_id)
+            # When price not taken from pricelist, the currency is
+            # determined by the price_type:
+            price_type_model = self.pool.get('product.price.type')
+            price_type_ids = price_type_model.search(
+                cr, uid, [('field', '=', field)], context=context)
+            if  price_type_ids:
+                price_type_obj = price_type_model.browse(
+                    cr, uid, price_type_ids[0], context=context)
+                if price_type_obj and price_type_obj.currency_id:
+                    standard_currency_id = price_type_obj.currency_id.id
+        # convert price_unit to currency of invoice
+        if  standard_currency_id != currency_id:
+            currency_model = self.pool.get('res.currency')
+            price_unit = currency_model.compute(
+                cr, uid, standard_currency_id, currency_id,
+                price_unit, round=True, context=context)
+        return price_unit, warning
+
     def uos_id_change(self, cr, uid, ids, product, uom, qty=0, name='', type='out_invoice', partner_id=False, fposition_id=False, price_unit=False, currency_id=False, context=None, company_id=None):
         if context is None:
             context = {}

=== modified file 'account/tests/__init__.py'
--- account/tests/__init__.py	2012-11-01 20:39:35 +0000
+++ account/tests/__init__.py	2013-10-15 14:15:30 +0000
@@ -1,4 +1,6 @@
-from . import test_tax
+from . import test_tax, test_product_id_change
 
-fast_suite = [test_tax,
+fast_suite = [
+        test_tax,
+        test_product_id_change,
               ]

=== added file 'account/tests/test_product_id_change.py'
--- account/tests/test_product_id_change.py	1970-01-01 00:00:00 +0000
+++ account/tests/test_product_id_change.py	2013-10-15 14:15:30 +0000
@@ -0,0 +1,94 @@
+from openerp.tests.common import TransactionCase
+
+class TestProductIdChange(TransactionCase):
+    """Test for product_id_change on account.invoice.line
+    """
+
+    def setUp(self):
+        super(TestProductIdChange, self).setUp()
+        self.line_model = self.registry('account.invoice.line')
+
+    def get_line(self):
+        line_id = self.line_model.create(
+                self.cr,
+                self.uid,
+                {
+                    'name': 'testline',
+                })
+        return self.line_model.browse(
+                self.cr, self.uid, line_id)
+
+
+    def get_partner(self):
+        partner_id = self.registry('res.partner').search(
+                self.cr,
+                self.uid,
+                [('customer', '=', True)],
+                limit=1)[0]
+
+        return self.registry('res.partner').browse(
+                self.cr, self.uid, partner_id)
+
+    def get_product(self):
+        product_id = self.registry('product.product').search(
+                self.cr,
+                self.uid,
+                [('uom_id', '!=', False)],
+                limit=1)[0]
+        return self.registry('product.product').browse(
+                self.cr, self.uid, product_id)
+
+    def test_random_product(self):
+        line = self.get_line()
+        product = self.get_product()
+        partner = self.get_partner()
+
+        values = line.product_id_change(
+                product.id, None,
+                partner_id=partner.id)['value']
+
+        self.assertEquals(values['price_unit'], product.list_price)
+        self.assertEquals(values['uos_id'], product.uom_id.id)
+
+    def test_with_pricelist(self):
+        line = self.get_line()
+        product = self.get_product()
+
+        pricelist_id = self.registry('product.pricelist').create(
+                self.cr, 
+                self.uid,
+                {
+                    'name': 'testpricelist',
+                    'type': self.browse_ref('product.pricelist_type_sale').key,
+                    'version_id': [
+                        (0, 0, {
+                            'name': 'testversion',
+                            'items_id': [
+                                (0, 0, {
+                                    'name': 'testitem',
+                                    'product_id': product.id,
+                                    'price_discount': .5,
+                                    'price_surcharge': 42,
+                                    'base': self.browse_ref(
+                                        'product.list_price').id,
+                                    }),
+                                ],
+                            }),
+                        ],
+                })
+
+        partner_id = self.registry('res.partner').create(
+                self.cr,
+                self.uid,
+                {
+                    'name': 'testcustomer',
+                    'customer': True,
+                    'property_product_pricelist':
+                        'product.pricelist,%d' % pricelist_id,
+                })
+
+        values = line.product_id_change(
+                product.id, None,
+                partner_id=partner_id)['value']
+
+        self.assertEquals(values['price_unit'], product.list_price * 1.5 + 42)


Follow ups