[FIX] sale_margin: forbid manual cost specification
Considering recent recurring bug reports and the fact that bridge modules now automatically compute the cost considering logistics, timesheets & expense flows, the ability to manually edit the cost on a sale.order.line is now disabled. In most cases, manually specified costs are automatically reset because of stock/timesheets/expenses added dependencies on the purchase_price field. Also adapt existing tests and use the new Sale tests common. closes odoo/odoo#97977 Signed-off-by: Victor Feyens (vfe) <vfe@odoo.com>
This commit is contained in:
@@ -13,8 +13,8 @@ class SaleOrderLine(models.Model):
|
||||
margin_percent = fields.Float(
|
||||
"Margin (%)", compute='_compute_margin', store=True, groups="base.group_user", precompute=True)
|
||||
purchase_price = fields.Float(
|
||||
string='Cost', compute="_compute_purchase_price",
|
||||
digits='Product Price', store=True, readonly=False, precompute=True,
|
||||
string="Cost", compute="_compute_purchase_price",
|
||||
digits='Product Price', store=True, precompute=True,
|
||||
groups="base.group_user")
|
||||
|
||||
@api.depends('product_id', 'company_id', 'currency_id', 'product_uom')
|
||||
|
||||
@@ -1,154 +1,102 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from odoo.tests import common
|
||||
from datetime import datetime
|
||||
from odoo.fields import Command
|
||||
from odoo.addons.sale.tests.common import SaleCommon
|
||||
|
||||
|
||||
class TestSaleMargin(common.TransactionCase):
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
super().setUpClass()
|
||||
cls.SaleOrder = cls.env['sale.order']
|
||||
|
||||
cls.product_uom_id = cls.env.ref('uom.product_uom_unit').id
|
||||
cls.product = cls.env['product.product'].create({'name': 'Individual Workplace'})
|
||||
cls.product_id = cls.product.id
|
||||
cls.partner_id = cls.env['res.partner'].create({'name': 'A test partner'}).id
|
||||
cls.partner_invoice_address_id = cls.env['res.partner'].create({
|
||||
'name': 'A test partner address',
|
||||
'parent_id': cls.partner_id,
|
||||
}).id
|
||||
cls.pricelist = cls.env.ref('product.list0')
|
||||
cls.pricelist_id = cls.pricelist.id
|
||||
class TestSaleMargin(SaleCommon):
|
||||
|
||||
def test_sale_margin(self):
|
||||
""" Test the sale_margin module in Odoo. """
|
||||
self.pricelist.currency_id = self.env.company.currency_id
|
||||
self.product.standard_price = 700.0
|
||||
sale_order_so11 = self.SaleOrder.create({
|
||||
'date_order': datetime.today(),
|
||||
'name': 'Test_SO011',
|
||||
'order_line': [
|
||||
(0, 0, {
|
||||
'name': '[CARD] Individual Workplace',
|
||||
'price_unit': 1000.0,
|
||||
'product_uom': self.product_uom_id,
|
||||
'product_uom_qty': 10.0,
|
||||
'state': 'draft',
|
||||
'product_id': self.product_id}),
|
||||
(0, 0, {
|
||||
'name': 'Line without product_uom',
|
||||
'price_unit': 1000.0,
|
||||
'product_uom_qty': 10.0,
|
||||
'state': 'draft',
|
||||
'product_id': self.product_id})],
|
||||
'partner_id': self.partner_id,
|
||||
'partner_invoice_id': self.partner_invoice_address_id,
|
||||
'partner_shipping_id': self.partner_invoice_address_id,
|
||||
'pricelist_id': self.pricelist_id})
|
||||
# Confirm the sales order.
|
||||
sale_order_so11.action_confirm()
|
||||
# Verify that margin field gets bind with the value.
|
||||
self.assertEqual(sale_order_so11.margin, 6000.00, "Sales order profit should be 6000.00")
|
||||
self.assertEqual(sale_order_so11.margin_percent, 0.3, "Sales order margin should be 30%")
|
||||
sale_order_so11.order_line[1].purchase_price = 800
|
||||
self.assertEqual(sale_order_so11.margin, 5000.00, "Sales order margin should be 5000.00")
|
||||
order = self.empty_order
|
||||
|
||||
def test_sale_margin1(self):
|
||||
order.order_line = [
|
||||
Command.create({
|
||||
'price_unit': 1000.0,
|
||||
'product_uom_qty': 10.0,
|
||||
'product_id': self.product.id,
|
||||
}),
|
||||
]
|
||||
# Confirm the sales order.
|
||||
order.action_confirm()
|
||||
# Verify that margin field gets bind with the value.
|
||||
self.assertEqual(order.margin, 3000.00, "Sales order profit should be 6000.00")
|
||||
self.assertEqual(order.margin_percent, 0.3, "Sales order margin should be 30%")
|
||||
|
||||
def test_negative_margin(self):
|
||||
""" Test the margin when sales price is less then cost."""
|
||||
sale_order_so12 = self.SaleOrder.create({
|
||||
'date_order': datetime.today(),
|
||||
'name': 'Test_SO012',
|
||||
'order_line': [
|
||||
(0, 0, {
|
||||
'name': '[CARD] Individual Workplace',
|
||||
'purchase_price': 40.0,
|
||||
'price_unit': 20.0,
|
||||
'product_uom': self.product_uom_id,
|
||||
'product_uom_qty': 1.0,
|
||||
'state': 'draft',
|
||||
'product_id': self.product_id}),
|
||||
(0, 0, {
|
||||
'name': 'Line without product_uom',
|
||||
'price_unit': -100.0,
|
||||
'purchase_price': 0.0,
|
||||
'product_uom_qty': 1.0,
|
||||
'state': 'draft',
|
||||
'product_id': self.product_id})],
|
||||
'partner_id': self.partner_id,
|
||||
'partner_invoice_id': self.partner_invoice_address_id,
|
||||
'partner_shipping_id': self.partner_invoice_address_id,
|
||||
'pricelist_id': self.pricelist_id})
|
||||
# Confirm the sales order.
|
||||
sale_order_so12.action_confirm()
|
||||
# Verify that margin field of Sale Order Lines gets bind with the value.
|
||||
self.assertEqual(sale_order_so12.order_line[0].margin, -20.00, "Sales order profit should be -20.00")
|
||||
self.assertEqual(sale_order_so12.order_line[0].margin_percent, -1, "Sales order margin percentage should be -100%")
|
||||
self.assertEqual(sale_order_so12.order_line[1].margin, -100.00, "Sales order profit should be -100.00")
|
||||
self.assertEqual(sale_order_so12.order_line[1].margin_percent, 1.00, "Sales order margin should be 100% when the cost is zero and price defined")
|
||||
# Verify that margin field gets bind with the value.
|
||||
self.assertEqual(sale_order_so12.margin, -120.00, "Sales order margin should be -120.00")
|
||||
self.assertEqual(sale_order_so12.margin_percent, 1.5, "Sales order margin should be 150%")
|
||||
order = self.empty_order
|
||||
self.service_product.standard_price = 40.0
|
||||
|
||||
def test_sale_margin2(self):
|
||||
order.order_line = [
|
||||
Command.create({
|
||||
'price_unit': 20.0,
|
||||
'product_uom_qty': 1.0,
|
||||
'state': 'draft',
|
||||
'product_id': self.service_product.id,
|
||||
}),
|
||||
Command.create({
|
||||
'price_unit': -100.0,
|
||||
'purchase_price': 0.0,
|
||||
'product_uom_qty': 1.0,
|
||||
'state': 'draft',
|
||||
'product_id': self.product.id,
|
||||
}),
|
||||
]
|
||||
# Confirm the sales order.
|
||||
order.action_confirm()
|
||||
# Verify that margin field of Sale Order Lines gets bind with the value.
|
||||
self.assertEqual(order.order_line[0].margin, -20.00, "Sales order profit should be -20.00")
|
||||
self.assertEqual(order.order_line[0].margin_percent, -1, "Sales order margin percentage should be -100%")
|
||||
self.assertEqual(order.order_line[1].margin, -100.00, "Sales order profit should be -100.00")
|
||||
self.assertEqual(order.order_line[1].margin_percent, 1.00, "Sales order margin should be 100% when the cost is zero and price defined")
|
||||
# Verify that margin field gets bind with the value.
|
||||
self.assertEqual(order.margin, -120.00, "Sales order margin should be -120.00")
|
||||
self.assertEqual(order.margin_percent, 1.5, "Sales order margin should be 150%")
|
||||
|
||||
def test_margin_no_cost(self):
|
||||
""" Test the margin when cost is 0 margin percentage should always be 100%."""
|
||||
sale_order_so13 = self.SaleOrder.create({
|
||||
'date_order': datetime.today(),
|
||||
'name': 'Test_SO013',
|
||||
'order_line': [
|
||||
(0, 0, {
|
||||
'name': '[CARD] Individual Workplace',
|
||||
'purchase_price': 0.0,
|
||||
'price_unit': 70.0,
|
||||
'product_uom': self.product_uom_id,
|
||||
'product_uom_qty': 1.0,
|
||||
'state': 'draft',
|
||||
'product_id': self.product_id})],
|
||||
'partner_id': self.partner_id,
|
||||
'partner_invoice_id': self.partner_invoice_address_id,
|
||||
'partner_shipping_id': self.partner_invoice_address_id,
|
||||
'pricelist_id': self.pricelist_id})
|
||||
# Verify that margin field of Sale Order Lines gets bind with the value.
|
||||
self.assertEqual(sale_order_so13.order_line[0].margin, 70.00, "Sales order profit should be 70.00")
|
||||
self.assertEqual(sale_order_so13.order_line[0].margin_percent, 1.0, "Sales order margin percentage should be 100.00")
|
||||
# Verify that margin field gets bind with the value.
|
||||
self.assertEqual(sale_order_so13.margin, 70.00, "Sales order profit should be 70.00")
|
||||
self.assertEqual(sale_order_so13.margin_percent, 1.00, "Sales order margin percentage should be 100.00")
|
||||
order = self.empty_order
|
||||
order.order_line = [Command.create({
|
||||
'product_id': self.product.id,
|
||||
'price_unit': 70.0,
|
||||
'product_uom_qty': 1.0,
|
||||
})]
|
||||
|
||||
def test_sale_margin3(self):
|
||||
""" Test the margin and margin percentage when product with multiple quantity"""
|
||||
sale_order_so14 = self.SaleOrder.create({
|
||||
'date_order': datetime.today(),
|
||||
'name': 'Test_SO014',
|
||||
'order_line': [
|
||||
(0, 0, {
|
||||
'name': '[CARD] Individual Workplace',
|
||||
'purchase_price': 50.0,
|
||||
'price_unit': 100.0,
|
||||
'product_uom': self.product_uom_id,
|
||||
'product_uom_qty': 3.0,
|
||||
'state': 'draft',
|
||||
'product_id': self.product_id}),
|
||||
(0, 0, {
|
||||
'name': 'Line without product_uom',
|
||||
'price_unit': -50.0,
|
||||
'purchase_price': 0.0,
|
||||
'product_uom_qty': 1.0,
|
||||
'state': 'draft',
|
||||
'product_id': self.product_id})],
|
||||
'partner_id': self.partner_id,
|
||||
'partner_invoice_id': self.partner_invoice_address_id,
|
||||
'partner_shipping_id': self.partner_invoice_address_id,
|
||||
'pricelist_id': self.pricelist_id})
|
||||
# Confirm the sales order.
|
||||
sale_order_so14.action_confirm()
|
||||
# Verify that margin field of Sale Order Lines gets bind with the value.
|
||||
self.assertEqual(sale_order_so14.order_line[0].margin, 150.00, "Sales order profit should be 150.00")
|
||||
self.assertEqual(sale_order_so14.order_line[0].margin_percent, 0.5, "Sales order margin should be 100%")
|
||||
self.assertEqual(sale_order_so14.order_line[1].margin, -50.00, "Sales order profit should be -50.00")
|
||||
self.assertEqual(sale_order_so14.order_line[1].margin_percent, 1.0, "Sales order margin should be 100%")
|
||||
self.assertEqual(order.order_line[0].margin, 70.00, "Sales order profit should be 70.00")
|
||||
self.assertEqual(order.order_line[0].margin_percent, 1.0, "Sales order margin percentage should be 100.00")
|
||||
# Verify that margin field gets bind with the value.
|
||||
self.assertEqual(sale_order_so14.margin, 100.00, "Sales order profit should be 100.00")
|
||||
self.assertEqual(sale_order_so14.margin_percent, 0.4, "Sales order margin should be 40%")
|
||||
self.assertEqual(order.margin, 70.00, "Sales order profit should be 70.00")
|
||||
self.assertEqual(order.margin_percent, 1.00, "Sales order margin percentage should be 100.00")
|
||||
|
||||
def test_margin_considering_product_qty(self):
|
||||
""" Test the margin and margin percentage when product with multiple quantity"""
|
||||
order = self.empty_order
|
||||
self.service_product.standard_price = 50.0
|
||||
|
||||
order.order_line = [
|
||||
Command.create({
|
||||
'price_unit': 100.0,
|
||||
'product_uom_qty': 3.0,
|
||||
'product_id': self.service_product.id,
|
||||
}),
|
||||
Command.create({
|
||||
'price_unit': -50.0,
|
||||
'product_uom_qty': 1.0,
|
||||
'product_id': self.product.id,
|
||||
}),
|
||||
]
|
||||
|
||||
# Confirm the sales order.
|
||||
order.action_confirm()
|
||||
# Verify that margin field of Sale Order Lines gets bind with the value.
|
||||
self.assertEqual(order.order_line[0].margin, 150.00, "Sales order profit should be 150.00")
|
||||
self.assertEqual(order.order_line[0].margin_percent, 0.5, "Sales order margin should be 100%")
|
||||
self.assertEqual(order.order_line[1].margin, -50.00, "Sales order profit should be -50.00")
|
||||
self.assertEqual(order.order_line[1].margin_percent, 1.0, "Sales order margin should be 100%")
|
||||
# Verify that margin field gets bind with the value.
|
||||
self.assertEqual(order.margin, 100.00, "Sales order profit should be 100.00")
|
||||
self.assertEqual(order.margin_percent, 0.4, "Sales order margin should be 40%")
|
||||
|
||||
Reference in New Issue
Block a user