diff --git a/addons/product/pricelist.py b/addons/product/pricelist.py index 02b855f73fbb8a18e7c7a207c06fe8c746933094..3f11cde994821b97176bf932d3a6b29539952add 100644 --- a/addons/product/pricelist.py +++ b/addons/product/pricelist.py @@ -247,7 +247,7 @@ class product_pricelist(osv.osv): if qty_uom_id != product.uom_id.id: try: qty_in_product_uom = product_uom_obj._compute_qty( - cr, uid, context['uom'], qty, product.uom_id.id or product.uos_id.id) + cr, uid, context['uom'], qty, product.uom_id.id) except UserError: # Ignored - incompatible UoM in context, use default product UoM pass diff --git a/addons/product/product.py b/addons/product/product.py index e79e6986dbe0e137f0ff216c2627e3f3c067aa5c..adb238969f73d12c11bd9ec89008e82f71611df1 100644 --- a/addons/product/product.py +++ b/addons/product/product.py @@ -412,7 +412,7 @@ class product_template(osv.osv): product = self.browse(cr, uid, id, context=context) if 'uom' in context: - uom = product.uos_id or product.uom_id + uom = product.uom_id value = product_uom_obj._compute_price(cr, uid, context['uom'], value, uom.id) @@ -508,12 +508,6 @@ class product_template(osv.osv): 'uom_id': fields.many2one('product.uom', 'Unit of Measure', required=True, help="Default Unit of Measure used for all stock operation."), 'uom_rel_id': fields.related('uom_id', type="many2one", relation="product.uom", readonly=True, string='Default UoM'), 'uom_po_id': fields.many2one('product.uom', 'Purchase Unit of Measure', required=True, help="Default Unit of Measure used for purchase orders. It must be in the same category than the default unit of measure."), - 'uos_id' : fields.many2one('product.uom', 'Unit of Sale', - help='Specify a unit of measure here if invoicing is made in another unit of measure than inventory. Keep empty to use the default unit of measure.'), - 'uos_coeff': fields.float('Unit of Measure -> UOS Coeff', digits_compute= dp.get_precision('Product UoS'), - help='Coefficient to convert default Unit of Measure to Unit of Sale\n' - ' uos = uom * coeff'), - 'mes_type': fields.selection((('fixed', 'Fixed'), ('variable', 'Variable')), 'Measure Type'), 'company_id': fields.many2one('res.company', 'Company', select=1), # image: all image fields are base64 encoded and PIL-supported 'image': fields.binary("Image", @@ -586,7 +580,7 @@ class product_template(osv.osv): if ptype == 'list_price': res[product.id] += product._name == "product.product" and product.price_extra or 0.0 if 'uom' in context: - uom = product.uom_id or product.uos_id + uom = product.uom_id res[product.id] = product_uom_obj._compute_price(cr, uid, uom.id, res[product.id], context['uom']) # Convert from price_type currency to asked one @@ -746,11 +740,9 @@ class product_template(osv.osv): 'company_id': lambda s,cr,uid,c: s.pool.get('res.company')._company_default_get(cr, uid, 'product.template', context=c), 'list_price': 1, 'standard_price': 0.0, - 'sale_ok': 1, + 'sale_ok': 1, 'uom_id': _get_uom_id, 'uom_po_id': _get_uom_id, - 'uos_coeff': 1.0, - 'mes_type': 'fixed', 'categ_id' : _default_category, 'type' : 'consu', 'active': True, @@ -851,7 +843,7 @@ class product_product(osv.osv): for product in self.browse(cr, uid, ids, context=context): if 'uom' in context: - uom = product.uos_id or product.uom_id + uom = product.uom_id res[product.id] = product_uom_obj._compute_price(cr, uid, uom.id, product.list_price, context['uom']) else: @@ -865,7 +857,7 @@ class product_product(osv.osv): product = self.browse(cr, uid, id, context=context) if 'uom' in context: - uom = product.uos_id or product.uom_id + uom = product.uom_id value = product_uom_obj._compute_price(cr, uid, context['uom'], value, uom.id) value = value - product.price_extra @@ -1157,37 +1149,6 @@ class product_product(osv.osv): ctx = dict(context or {}, create_product_product=True) return super(product_product, self).create(cr, uid, vals, context=ctx) - def need_procurement(self, cr, uid, ids, context=None): - return False - - def _compute_uos_qty(self, cr, uid, ids, uom, qty, uos, context=None): - ''' - Computes product's invoicing quantity in UoS from quantity in UoM. - Takes into account the - :param uom: Source unit - :param qty: Source quantity - :param uos: Target UoS unit. - ''' - if not uom or not qty or not uos: - return qty - uom_obj = self.pool['product.uom'] - product_id = ids[0] if isinstance(ids, (list, tuple)) else ids - product = self.browse(cr, uid, product_id, context=context) - if isinstance(uos, (int, long)): - uos = uom_obj.browse(cr, uid, uos, context=context) - if isinstance(uom, (int, long)): - uom = uom_obj.browse(cr, uid, uom, context=context) - if product.uos_id: # Product has UoS defined - # We cannot convert directly between units even if the units are of the same category - # as we need to apply the conversion coefficient which is valid only between quantities - # in product's default UoM/UoS - qty_default_uom = uom_obj._compute_qty_obj(cr, uid, uom, qty, product.uom_id) # qty in product's default UoM - qty_default_uos = qty_default_uom * product.uos_coeff - return uom_obj._compute_qty_obj(cr, uid, product.uos_id, qty_default_uos, uos) - else: - return uom_obj._compute_qty_obj(cr, uid, uom, qty, uos) - - class product_packaging(osv.osv): _name = "product.packaging" diff --git a/addons/product/product_data.xml b/addons/product/product_data.xml index 785327f9deeeb3fe9e307ac2fbdd5f97ff54f4e6..e24840ba4896aecc538448ed42352b8ae3738b3e 100644 --- a/addons/product/product_data.xml +++ b/addons/product/product_data.xml @@ -48,10 +48,6 @@ <field name="name">Product Unit of Measure</field> <field name="digits" eval="3"/> </record> - <record forcecreate="True" id="decimal_product_uos" model="decimal.precision"> - <field name="name">Product UoS</field> - <field name="digits" eval="3"/> - </record> <!-- Resource: product.uom diff --git a/addons/product/product_demo.xml b/addons/product/product_demo.xml index a63347f50ba7faaf970f277a0c8ff4207c5b8149..4170c3bb16f30359704bb5cfd3d6b18898da53e3 100644 --- a/addons/product/product_demo.xml +++ b/addons/product/product_demo.xml @@ -33,28 +33,49 @@ --> + <record id="product_product_0" model="product.product"> + <field name="name">Prepaid Consulting</field> + <field name="categ_id" ref="product_category_3"/> + <field name="standard_price">40</field> + <field name="list_price">90</field> + <field name="type">service</field> + <field name="uom_id" ref="product_uom_hour"/> + <field name="uom_po_id" ref="product_uom_hour"/> + <field name="description">Example of product to invoice on order.</field> + </record> + <record id="product_product_1" model="product.product"> - <field name="name">On Site Monitoring</field> + <field name="name">GAP Analysis Service</field> <field name="categ_id" ref="product_category_3"/> <field name="standard_price">20.5</field> <field name="list_price">30.75</field> <field name="type">service</field> <field name="uom_id" ref="product_uom_hour"/> <field name="uom_po_id" ref="product_uom_hour"/> - <field name="description">This type of service include basic monitoring of products.</field> - <field name="description_sale">This type of service include basic monitoring of products.</field> + <field name="description">Example of products to invoice based on delivery.</field> + </record> + + <record id="product_product_1b" model="product.product"> + <field name="name">External Audit</field> + <field name="categ_id" ref="product_category_3"/> + <field name="standard_price">160</field> + <field name="list_price">180</field> + <field name="type">service</field> + <field name="uom_id" ref="product_uom_unit"/> + <field name="uom_po_id" ref="product_uom_unit"/> + <field name="description">Example of products to invoice based on cost.</field> </record> <record id="product_product_2" model="product.product"> - <field name="name">On Site Assistance</field> + <field name="name">Support Services</field> <field name="categ_id" ref="product_category_3"/> <field name="standard_price">25.5</field> <field name="list_price">38.25</field> <field name="type">service</field> <field name="uom_id" ref="product_uom_hour"/> <field name="uom_po_id" ref="product_uom_hour"/> - <field name="description">This type of service include assistance for security questions, system configuration requirements, implementation or special needs.</field> + <field name="description">Example of product to invoice based on delivery.</field> </record> diff --git a/addons/product/product_view.xml b/addons/product/product_view.xml index 144b501db4ca20a70db3492c62bec2578cd27240..725222076811f95f842c00fb09fe08b72576474b 100644 --- a/addons/product/product_view.xml +++ b/addons/product/product_view.xml @@ -144,10 +144,6 @@ </group> <group name="email_template_and_project" attrs="{'invisible':[('type', '!=', 'service')]}"/> - <group groups="product.group_uos" string="Unit of Measure"> - <field name="uos_id" options="{'no_open':True,'no_create':True}"/> - <field name="uos_coeff" groups="base.group_no_one"/> - </group> </group> </page> <page string="Notes" name="notes"> @@ -397,7 +393,7 @@ <!-- product product --> - <menuitem id="prod_config_main" name="Products" parent="base.menu_sale_config" sequence="2" groups="base.group_no_one"/> + <menuitem id="prod_config_main" name="Products" parent="base.menu_sale_config" sequence="2"/> <record id="product_product_tree_view" model="ir.ui.view"> <field name="name">product.product.tree</field> diff --git a/addons/product/tests/test_pricelist.py b/addons/product/tests/test_pricelist.py index 37d80360cffb09f094450787ea81ef92980157ed..dc2b4852e7c2978fc1a2b119b29814113df56074 100644 --- a/addons/product/tests/test_pricelist.py +++ b/addons/product/tests/test_pricelist.py @@ -85,9 +85,9 @@ class TestPricelist(TransactionCase): spam_id = self.product_product.copy(cr, uid, self.usb_adapter_id, { 'name': '1 tonne of spam', 'uom_id': self.tonne_id, - 'uos_id': self.tonne_id, 'uom_po_id': self.tonne_id, 'list_price': tonne_price, + 'type': 'consu', }) pricelist_version_id = self.ir_model_data.xmlid_to_res_id(cr, uid, 'product.ver0') self.registry('product.pricelist.item').create(cr, uid, diff --git a/addons/product_expiry/product_expiry_demo.xml b/addons/product_expiry/product_expiry_demo.xml index e42c0591f9bdbe6672066a70cf9d4dabd3b82613..4df0db7459f1f93e14386f174e438ba9d03e3bb4 100644 --- a/addons/product_expiry/product_expiry_demo.xml +++ b/addons/product_expiry/product_expiry_demo.xml @@ -7,8 +7,6 @@ <field name="standard_price">5.0</field> <field name="uom_id" ref="product.product_uom_unit"/> <field name="uom_po_id" ref="product.product_uom_unit"/> - <field name="uos_id" ref="product.product_uom_kgm" /> - <field name="uos_coeff">3</field> <field name="name">French cheese Camembert</field> <field name="life_time">15</field> <field name="use_time">10</field> @@ -31,8 +29,6 @@ <field name="standard_price">6.0</field> <field name="uom_id" ref="product.product_uom_unit"/> <field name="uom_po_id" ref="product.product_uom_unit"/> - <field name="uos_id" ref="product.product_uom_kgm" /> - <field name="uos_coeff">0.5</field> <field name="name">Ham</field> <field name="life_time">30</field> <field name="use_time">25</field> @@ -54,8 +50,6 @@ <field name="standard_price">6.0</field> <field name="uom_id" ref="product.product_uom_unit"/> <field name="uom_po_id" ref="product.product_uom_unit"/> - <field name="uos_id" ref="product.product_uom_kgm" /> - <field name="uos_coeff">0.5</field> <field name="name">Bread</field> <field name="life_time">30</field> <field name="use_time">25</field> @@ -77,8 +71,6 @@ <field name="standard_price">6.0</field> <field name="uom_id" ref="product.product_uom_unit"/> <field name="uom_po_id" ref="product.product_uom_unit"/> - <field name="uos_id" ref="product.product_uom_litre" /> - <field name="uos_coeff">0.5</field> <field name="name">Cow milk</field> <field name="life_time">30</field> <field name="use_time">25</field> diff --git a/addons/product_margin/product_margin.py b/addons/product_margin/product_margin.py index c3a67e2d6622b6f30e2b577a7b602c35b63deafb..7c62a8a97aa18b29994ef577408991419296a9d8 100644 --- a/addons/product_margin/product_margin.py +++ b/addons/product_margin/product_margin.py @@ -73,16 +73,14 @@ class product_product(osv.osv): #Cost price is calculated afterwards as it is a property sqlstr="""select - sum(l.price_unit * l.quantity)/sum(nullif(l.quantity * pu.factor / pu2.factor,0)) as avg_unit_price, - sum(l.quantity * pu.factor / pu2.factor) as num_qty, + sum(l.price_unit * l.quantity)/sum(nullif(l.quantity,0)) as avg_unit_price, + sum(l.quantity) as num_qty, sum(l.quantity * (l.price_subtotal/(nullif(l.quantity,0)))) as total, - sum(l.quantity * pu.factor * pt.list_price / pu2.factor) as sale_expected + sum(l.quantity * pt.list_price) as sale_expected from account_invoice_line l left join account_invoice i on (l.invoice_id = i.id) left join product_product product on (product.id=l.product_id) left join product_template pt on (pt.id = product.product_tmpl_id) - left join product_uom pu on (pt.uom_id = pu.id) - left join product_uom pu2 on (l.uos_id = pu2.id) where l.product_id = %s and i.state in %s and i.type IN %s and (i.date_invoice IS NULL or (i.date_invoice>=%s and i.date_invoice<=%s and i.company_id=%s)) """ invoice_types = ('out_invoice', 'in_refund') diff --git a/addons/product_visible_discount/product_visible_discount.py b/addons/product_visible_discount/product_visible_discount.py index 51a2972149c02fffc68499ec8cf08a88e3d442d5..c4d5ff96be86d143d6ad5ef95f3e123d753f2e2b 100644 --- a/addons/product_visible_discount/product_visible_discount.py +++ b/addons/product_visible_discount/product_visible_discount.py @@ -1,6 +1,6 @@ # -*- encoding: utf-8 -*- # Part of Odoo. See LICENSE file for full copyright and licensing details. - +from openerp import api from openerp.osv import fields, osv from openerp.tools.translate import _ @@ -33,7 +33,7 @@ class sale_order_line(osv.osv): if item_base > 0: price_type = price_type_obj.browse(cr, uid, item_base) field_name = price_type.field - currency_id = price_type.currency_id + currency_id = price_type.currency_id.id product = product_obj.browse(cr, uid, product_id, context=context) if not currency_id: @@ -44,49 +44,57 @@ class sale_order_line(osv.osv): factor = self.pool['product.uom']._compute_qty(cr, uid, uom, 1.0, product.uom_id.id) return product[field_name] * factor, currency_id - def product_id_change(self, cr, uid, ids, pricelist, product, qty=0, - uom=False, qty_uos=0, uos=False, name='', partner_id=False, - lang=False, update_tax=True, date_order=False, packaging=False, - fiscal_position_id=False, flag=False, context=None): - res=super(sale_order_line, self).product_id_change(cr, uid, ids, pricelist, product, qty, - uom, qty_uos, uos, name, partner_id, - lang, update_tax, date_order, packaging=packaging, fiscal_position_id=fiscal_position_id, flag=flag, context=context) + @api.multi + @api.onchange('product_id') + def product_id_change(self): + res = super(sale_order_line, self).product_id_change() + context_partner = dict(self.env.context, partner_id=self.order_id.partner_id.id) + if self.product_id and self.order_id.pricelist_id and self.env.user.has_group('sale.group_discount_per_so_line'): + pricelist_context = dict(context_partner, uom=self.product_uom.id, date=self.order_id.date_order) + list_price = self.order_id.pricelist_id.with_context(pricelist_context).price_rule_get(self.product_id.id, self.product_uom_qty or 1.0, self.order_id.partner_id) - if context is None: - context = {} - context_partner = dict(context, lang=lang, partner_id=partner_id) - result=res['value'] - pricelist_obj=self.pool.get('product.pricelist') - product_obj = self.pool.get('product.product') - if product and pricelist and self.pool.get('res.users').has_group(cr, uid, 'sale.group_discount_per_so_line'): - if result.get('price_unit',False): - price=result['price_unit'] + new_list_price, currency_id = self.with_context(context_partner).get_real_price_currency(self.product_id.id, list_price, self.product_uom_qty, self.product_uom.id, self.order_id.pricelist_id.id) + if self.order_id.pricelist_id.visible_discount and list_price[self.order_id.pricelist_id.id][0] != 0 and new_list_price != 0: + if self.product_id.company_id and self.order_id.pricelist_id.currency_id.id != self.product_id.company_id.currency_id.id: + # new_list_price is in company's currency while price in pricelist currency + ctx = dict(context_partner, date=self.order_id.date_order) + new_list_price = self.env['res.currency'].browse(currency_id).with_context(ctx).compute(new_list_price, self.order_id.pricelist_id.currency_id.id) + discount = (new_list_price - self.price_unit) / new_list_price * 100 + if discount > 0: + self.price_unit = new_list_price + self.discount = discount + else: + self.discount = 0.0 else: - return res - uom = result.get('product_uom', uom) - product = product_obj.browse(cr, uid, product, context=context_partner) - pricelist_context = dict(context_partner, uom=uom, date=date_order) - list_price = pricelist_obj.price_rule_get(cr, uid, [pricelist], - product.id, qty or 1.0, partner_id, context=pricelist_context) - - so_pricelist = pricelist_obj.browse(cr, uid, pricelist, context=context_partner) + self.discount = 0.0 + else: + self.discount = 0.0 + return res - new_list_price, currency_id = self.get_real_price_currency(cr, uid, product.id, list_price, qty, uom, pricelist, context=context_partner) - if so_pricelist.visible_discount and list_price[pricelist][0] != 0 and new_list_price != 0: - if product.company_id and so_pricelist.currency_id.id != product.company_id.currency_id.id: + @api.onchange('product_uom') + def product_uom_change(self): + res = super(sale_order_line, self).product_uom_change() + if not self.product_uom: + self.price_unit = 0.0 + return + if self.order_id.pricelist_id and self.order_id.partner_id and self.env.user.has_group('sale.group_discount_per_so_line'): + context_partner = dict(self.env.context, partner_id=self.order_id.partner_id.id) + pricelist_context = dict(context_partner, uom=self.product_uom.id, date=self.order_id.date_order) + list_price = self.order_id.pricelist_id.with_context(pricelist_context).price_rule_get(self.product_id.id, self.product_uom_qty or 1.0, self.order_id.partner_id) + new_list_price, currency_id = self.with_context(context_partner).get_real_price_currency(self.product_id.id, list_price, self.product_uom_qty, self.product_uom.id, self.order_id.pricelist_id.id) + if self.order_id.pricelist_id.visible_discount and list_price[self.order_id.pricelist_id.id][0] != 0 and new_list_price != 0: + if self.product_id.company_id and self.order_id.pricelist_id.currency_id.id != self.product_id.company_id.currency_id.id: # new_list_price is in company's currency while price in pricelist currency - ctx = dict(context_partner, date=date_order) - new_list_price = self.pool['res.currency'].compute(cr, uid, - currency_id.id, so_pricelist.currency_id.id, - new_list_price, context=ctx) - discount = (new_list_price - price) / new_list_price * 100 + ctx = dict(context_partner, date=self.order_id.date_order) + new_list_price = self.env['res.currency'].browse(currency_id).with_context(ctx).compute(new_list_price, self.order_id.pricelist_id.currency_id.id) + discount = (new_list_price - self.price_unit) / new_list_price * 100 if discount > 0: - result['price_unit'] = new_list_price - result['discount'] = discount + self.price_unit = new_list_price + self.discount = discount else: - result['discount'] = 0.0 + self.discount = 0.0 else: - result['discount'] = 0.0 + self.discount = 0.0 else: - result['discount'] = 0.0 + self.discount = 0.0 return res