diff --git a/addons/point_of_sale/models/pos_order.py b/addons/point_of_sale/models/pos_order.py
index cd08a380aba..df754628195 100644
--- a/addons/point_of_sale/models/pos_order.py
+++ b/addons/point_of_sale/models/pos_order.py
@@ -142,6 +142,7 @@ class PosOrder(models.Model):
except Exception as e:
_logger.error('Could not fully process the POS Order: %s', tools.ustr(e))
pos_order._create_order_picking()
+ pos_order._compute_total_cost_in_real_time()
if pos_order.to_invoice and pos_order.state == 'paid':
pos_order.action_pos_order_invoice()
@@ -230,6 +231,10 @@ class PosOrder(models.Model):
amount_paid = fields.Float(string='Paid', states={'draft': [('readonly', False)]},
readonly=True, digits=0, required=True)
amount_return = fields.Float(string='Returned', digits=0, required=True, readonly=True)
+ margin = fields.Monetary(string="Margin", compute='_compute_margin')
+ margin_percent = fields.Float(string="Margin (%)", compute='_compute_margin', digits=(12, 4))
+ is_total_cost_computed = fields.Boolean(compute='_compute_is_total_cost_computed',
+ help="Allows to know if all the total cost of the order lines have already been computed")
lines = fields.One2many('pos.order.line', 'order_id', string='Order Lines', states={'draft': [('readonly', False)]}, readonly=True, copy=True)
company_id = fields.Many2one('res.company', string='Company', required=True, readonly=True)
pricelist_id = fields.Many2one('product.pricelist', string='Pricelist', required=True, states={
@@ -291,6 +296,45 @@ class PosOrder(models.Model):
for order in self:
order.currency_rate = self.env['res.currency']._get_conversion_rate(order.company_id.currency_id, order.currency_id, order.company_id, order.date_order)
+ @api.depends('lines.is_total_cost_computed')
+ def _compute_is_total_cost_computed(self):
+ for order in self:
+ order.is_total_cost_computed = not False in order.lines.mapped('is_total_cost_computed')
+
+ def _compute_total_cost_in_real_time(self):
+ """
+ Compute the total cost of the order when it's processed by the server. It will compute the total cost of all the lines
+ if it's possible. If a margin of one of the order's lines cannot be computed (because of session_id.update_stock_at_closing),
+ then the margin of said order is not computed (it will be computed when closing the session).
+ """
+ for order in self:
+ lines = order.lines
+ if not order._should_create_picking_real_time():
+ storable_fifo_avco_lines = lines.filtered(lambda l: l._is_product_storable_fifo_avco())
+ lines -= storable_fifo_avco_lines
+ stock_moves = order.picking_ids.move_lines
+ lines._compute_total_cost(stock_moves)
+
+ def _compute_total_cost_at_session_closing(self, stock_moves):
+ """
+ Compute the margin at the end of the session. This method should be called to compute the remaining lines margin
+ containing a storable product with a fifo/avco cost method and then compute the order margin
+ """
+ for order in self:
+ storable_fifo_avco_lines = order.lines.filtered(lambda l: l._is_product_storable_fifo_avco())
+ storable_fifo_avco_lines._compute_total_cost(stock_moves)
+
+ @api.depends('lines.margin', 'is_total_cost_computed')
+ def _compute_margin(self):
+ for order in self:
+ if order.is_total_cost_computed:
+ order.margin = sum(order.lines.mapped('margin'))
+ amount_untaxed = order.currency_id.round(sum(line.price_subtotal for line in order.lines))
+ order.margin_percent = not float_is_zero(amount_untaxed, order.currency_id.rounding) and order.margin / amount_untaxed or 0
+ else:
+ order.margin = 0
+ order.margin_percent = 0
+
@api.onchange('payment_ids', 'lines')
def _onchange_amount_all(self):
for order in self:
@@ -566,12 +610,15 @@ class PosOrder(models.Model):
return self.env['pos.order'].search_read(domain = [('id', 'in', order_ids)], fields = ['id', 'pos_reference'])
+ def _should_create_picking_real_time(self):
+ return not self.session_id.update_stock_at_closing or (self.company_id.anglo_saxon_accounting and self.to_invoice)
+
def _create_order_picking(self):
self.ensure_one()
if self.to_ship:
self.lines._launch_stock_rule_from_pos_order_lines()
else:
- if not self.session_id.update_stock_at_closing or (self.company_id.anglo_saxon_accounting and self.to_invoice):
+ if self._should_create_picking_real_time():
picking_type = self.config_id.picking_type_id
if self.partner_id.property_stock_customer:
destination_id = self.partner_id.property_stock_customer.id
@@ -600,6 +647,7 @@ class PosOrder(models.Model):
'amount_tax': -self.amount_tax,
'amount_total': -self.amount_total,
'amount_paid': 0,
+ 'is_total_cost_computed': False
}
def refund(self):
@@ -770,6 +818,10 @@ class PosOrderLine(models.Model):
readonly=True, required=True)
price_subtotal_incl = fields.Float(string='Subtotal', digits=0,
readonly=True, required=True)
+ margin = fields.Monetary(string="Margin", compute='_compute_margin')
+ margin_percent = fields.Float(string="Margin (%)", compute='_compute_margin', digits=(12, 4))
+ total_cost = fields.Float(string='Total cost', digits='Product Price', readonly=True)
+ is_total_cost_computed = fields.Boolean(help="Allows to know if the total cost has already been computed or not")
discount = fields.Float(string='Discount (%)', digits=0, default=0.0)
order_id = fields.Many2one('pos.order', string='Order Ref', ondelete='cascade', required=True)
tax_ids = fields.Many2many('account.tax', string='Taxes', readonly=True)
@@ -801,6 +853,7 @@ class PosOrderLine(models.Model):
'price_subtotal': -self.price_subtotal,
'price_subtotal_incl': -self.price_subtotal_incl,
'pack_lot_ids': PosOrderLineLot,
+ 'is_total_cost_computed': False
}
@api.model
@@ -952,6 +1005,36 @@ class PosOrderLine(models.Model):
pickings_to_confirm.action_confirm()
return True
+ def _is_product_storable_fifo_avco(self):
+ self.ensure_one()
+ return self.product_id.type == 'product' and self.product_id.cost_method in ['fifo', 'average']
+
+ def _compute_total_cost(self, stock_moves):
+ """
+ Compute the total cost of the order lines.
+ :param stock_moves: recordset of `stock.move`, used for fifo/avco lines
+ """
+ for line in self.filtered(lambda l: not l.is_total_cost_computed):
+ product = line.product_id
+ if line._is_product_storable_fifo_avco() and stock_moves:
+ product_cost = product._compute_average_price(0, line.qty, stock_moves.filtered(lambda ml: ml.product_id == product))
+ else:
+ product_cost = product.standard_price
+ line.total_cost = line.qty * product.cost_currency_id._convert(
+ from_amount=product_cost,
+ to_currency=line.currency_id,
+ company=line.company_id or self.env.company,
+ date=line.order_id.date_order or fields.Date.today(),
+ round=False,
+ )
+ line.is_total_cost_computed = True
+
+ @api.depends('price_subtotal', 'total_cost')
+ def _compute_margin(self):
+ for line in self:
+ line.margin = line.price_subtotal - line.total_cost
+ line.margin_percent = not float_is_zero(line.price_subtotal, line.currency_id.rounding) and line.margin / line.price_subtotal or 0
+
class PosOrderLineLot(models.Model):
_name = "pos.pack.operation.lot"
diff --git a/addons/point_of_sale/models/pos_session.py b/addons/point_of_sale/models/pos_session.py
index 02de2bc4a36..316fa5a864a 100644
--- a/addons/point_of_sale/models/pos_session.py
+++ b/addons/point_of_sale/models/pos_session.py
@@ -319,6 +319,7 @@ class PosSession(models.Model):
self._check_if_no_draft_orders()
if self.update_stock_at_closing:
self._create_picking_at_end_of_session()
+ self.order_ids.filtered(lambda o: not o.is_total_cost_computed)._compute_total_cost_at_session_closing(self.picking_ids.move_lines)
try:
data = self.with_company(self.company_id)._create_account_move(balancing_account, amount_to_balance)
except AccessError as e:
diff --git a/addons/point_of_sale/report/pos_order_report.py b/addons/point_of_sale/report/pos_order_report.py
index 1ad50a021ec..c0b483de991 100644
--- a/addons/point_of_sale/report/pos_order_report.py
+++ b/addons/point_of_sale/report/pos_order_report.py
@@ -35,6 +35,7 @@ class PosOrderReport(models.Model):
pos_categ_id = fields.Many2one('pos.category', string='PoS Category', readonly=True)
pricelist_id = fields.Many2one('product.pricelist', string='Pricelist', readonly=True)
session_id = fields.Many2one('pos.session', string='Session', readonly=True)
+ margin = fields.Float(string='Margin', readonly=True)
def _select(self):
return """
@@ -64,7 +65,8 @@ class PosOrderReport(models.Model):
pt.pos_categ_id,
s.pricelist_id,
s.session_id,
- s.account_move IS NOT NULL AS invoiced
+ s.account_move IS NOT NULL AS invoiced,
+ SUM(l.price_subtotal - l.total_cost / CASE COALESCE(s.currency_rate, 0) WHEN 0 THEN 1.0 ELSE s.currency_rate END) AS margin
"""
def _from(self):
diff --git a/addons/point_of_sale/tests/__init__.py b/addons/point_of_sale/tests/__init__.py
index d108782cf17..54ccc6091ce 100644
--- a/addons/point_of_sale/tests/__init__.py
+++ b/addons/point_of_sale/tests/__init__.py
@@ -9,6 +9,7 @@ from . import test_point_of_sale
from . import test_pos_setup
from . import test_pos_basic_config
from . import test_pos_products_with_tax
+from . import test_pos_margin
from . import test_pos_multiple_sale_accounts
from . import test_pos_multiple_receivable_accounts
from . import test_pos_other_currency_config
diff --git a/addons/point_of_sale/tests/test_pos_margin.py b/addons/point_of_sale/tests/test_pos_margin.py
new file mode 100644
index 00000000000..db838600695
--- /dev/null
+++ b/addons/point_of_sale/tests/test_pos_margin.py
@@ -0,0 +1,398 @@
+# -*- coding: utf-8 -*-
+
+import odoo
+from odoo.addons.point_of_sale.tests.common import TestPoSCommon
+
+
+@odoo.tests.tagged('post_install', '-at_install')
+class TestPosMargin(TestPoSCommon):
+ """
+ Test the margin computation on orders with basic configuration
+ The tests contain the base scenarios.
+ """
+
+ def setUp(self):
+ super(TestPosMargin, self).setUp()
+ self.config = self.basic_config
+
+ self.stock_location = self.env['stock.warehouse'].create({
+ 'partner_id': self.env.user.partner_id.id,
+ 'name': 'Stock location',
+ 'code': 'WH'
+ }).lot_stock_id
+ self.customer_location = self.env.ref('stock.stock_location_customers')
+ self.supplier_location = self.env.ref('stock.stock_location_suppliers')
+ self.uom_unit = self.env.ref('uom.product_uom_unit')
+
+
+ def test_positive_margin(self):
+ """
+ Test margin where it should be more than zero
+ """
+
+ product1 = self.create_product('Product 1', self.categ_basic, 10, 5)
+ product2 = self.create_product('Product 2', self.categ_basic, 50, 30)
+
+ # open a session
+ self.open_new_session()
+
+ # create orders
+ orders = [self.create_ui_order_data([(product1, 1)]),
+ self.create_ui_order_data([(product2, 1)]),
+ self.create_ui_order_data([(product1, 2), (product2, 2)])]
+
+ # sync orders
+ self.env['pos.order'].create_from_ui(orders)
+
+ # check margins
+ self.assertEqual(self.pos_session.order_ids[0].margin, 5)
+ self.assertEqual(self.pos_session.order_ids[1].margin, 20)
+ self.assertEqual(self.pos_session.order_ids[2].margin, 50)
+
+ # check margins percent
+ self.assertEqual(self.pos_session.order_ids[0].margin_percent, 0.5)
+ self.assertEqual(self.pos_session.order_ids[1].margin_percent, 0.4)
+ self.assertEqual(round(self.pos_session.order_ids[2].margin_percent, 2), 0.42)
+
+ # close session
+ self.pos_session.action_pos_session_validate()
+
+ def test_negative_margin(self):
+ """
+ Test margin where it should be less than zero
+ """
+
+ product1 = self.create_product('Product 1', self.categ_basic, 10, 15)
+ product2 = self.create_product('Product 2', self.categ_basic, 50, 100)
+
+ # open a session
+ self.open_new_session()
+
+ # create orders
+ orders = [self.create_ui_order_data([(product1, 1)]),
+ self.create_ui_order_data([(product2, 1)]),
+ self.create_ui_order_data([(product1, 2), (product2, 2)])]
+
+ # sync orders
+ self.env['pos.order'].create_from_ui(orders)
+
+ # check margins
+ self.assertEqual(self.pos_session.order_ids[0].margin, -5)
+ self.assertEqual(self.pos_session.order_ids[1].margin, -50)
+ self.assertEqual(self.pos_session.order_ids[2].margin, -110)
+
+ # check margins percent
+ self.assertEqual(self.pos_session.order_ids[0].margin_percent, -0.5)
+ self.assertEqual(self.pos_session.order_ids[1].margin_percent, -1)
+ self.assertEqual(round(self.pos_session.order_ids[2].margin_percent, 2), -0.92)
+
+ # close session
+ self.pos_session.action_pos_session_validate()
+
+ def test_full_margin(self):
+ """
+ Test margin where the product cost is always 0
+ """
+
+ product1 = self.create_product('Product 1', self.categ_basic, 10)
+ product2 = self.create_product('Product 2', self.categ_basic, 50)
+
+ # open a session
+ self.open_new_session()
+
+ # create orders
+ orders = [self.create_ui_order_data([(product1, 1)]),
+ self.create_ui_order_data([(product2, 1)]),
+ self.create_ui_order_data([(product1, 2), (product2, 2)])]
+
+ # sync orders
+ self.env['pos.order'].create_from_ui(orders)
+
+ # check margins
+ self.assertEqual(self.pos_session.order_ids[0].margin, 10)
+ self.assertEqual(self.pos_session.order_ids[1].margin, 50)
+ self.assertEqual(self.pos_session.order_ids[2].margin, 120)
+
+ # check margins percent
+ self.assertEqual(self.pos_session.order_ids[0].margin_percent, 1)
+ self.assertEqual(self.pos_session.order_ids[1].margin_percent, 1)
+ self.assertEqual(self.pos_session.order_ids[2].margin_percent, 1)
+
+ # close session
+ self.pos_session.action_pos_session_validate()
+
+ def test_tax_margin(self):
+ """
+ Test margin with tax on products
+ Product 1 price without tax = 10
+ Product 2 price without tax = 50
+ """
+
+ product1 = self.create_product('Product 1', self.categ_basic, 10, 5, self.taxes['tax7'].ids)
+ product2 = self.create_product('Product 2', self.categ_basic, 55, 30, self.taxes['tax10'].ids)
+
+ # open a session
+ self.open_new_session()
+
+ # create orders
+ orders = [self.create_ui_order_data([(product1, 1)]),
+ self.create_ui_order_data([(product2, 1)]),
+ self.create_ui_order_data([(product1, 2), (product2, 2)])]
+
+ # sync orders
+ self.env['pos.order'].create_from_ui(orders)
+
+ # check margins
+ self.assertEqual(self.pos_session.order_ids[0].margin, 5)
+ self.assertEqual(self.pos_session.order_ids[1].margin, 20)
+ self.assertEqual(self.pos_session.order_ids[2].margin, 50)
+
+ # check margins percent
+ self.assertEqual(self.pos_session.order_ids[0].margin_percent, 0.5)
+ self.assertEqual(self.pos_session.order_ids[1].margin_percent, 0.4)
+ self.assertEqual(round(self.pos_session.order_ids[2].margin_percent, 2), 0.42)
+
+ # close session
+ self.pos_session.action_pos_session_validate()
+
+ def test_other_currency_margin(self):
+ """
+ Test margin with tax on products and with different currency
+ The currency rate is 0.5 so the product price is halved in this currency.
+ """
+
+ # change the config
+ current_config = self.config
+ self.config = self.other_currency_config
+
+ # same parameters as test_positive_margin
+ product1 = self.create_product('Product 1', self.categ_basic, 10, 5)
+ product2 = self.create_product('Product 2', self.categ_basic, 50, 30)
+
+ # open a session
+ self.open_new_session()
+
+ # create orders
+ orders = [self.create_ui_order_data([(product1, 1)]),
+ self.create_ui_order_data([(product2, 1)]),
+ self.create_ui_order_data([(product1, 2), (product2, 2)])]
+
+ # sync orders
+ self.env['pos.order'].create_from_ui(orders)
+
+ # check margins in the config currency
+ self.assertEqual(self.pos_session.order_ids[0].margin, 2.5)
+ self.assertEqual(self.pos_session.order_ids[1].margin, 10)
+ self.assertEqual(self.pos_session.order_ids[2].margin, 25)
+
+ # check margins percent which should be the same as test_positive_margin
+ self.assertEqual(self.pos_session.order_ids[0].margin_percent, 0.5)
+ self.assertEqual(self.pos_session.order_ids[1].margin_percent, 0.4)
+ self.assertEqual(round(self.pos_session.order_ids[2].margin_percent, 2), 0.42)
+
+ # close session
+ self.pos_session.action_pos_session_validate()
+
+ # set the config back
+ self.config = current_config
+
+ def test_tax_and_other_currency_margin(self):
+ """
+ Test margin with different currency between products and config with taxes.
+ Product 1 price without tax = 10
+ Product 2 price without tax = 50
+ The currency rate is 0.5 so the product price is halved in this currency.
+ """
+
+ # change the config
+ current_config = self.config
+ self.config = self.other_currency_config
+
+ product1 = self.create_product('Product 1', self.categ_basic, 10, 5, self.taxes['tax7'].ids)
+ product2 = self.create_product('Product 2', self.categ_basic, 55, 30, self.taxes['tax10'].ids)
+
+ # open a session
+ self.open_new_session()
+
+ # create orders
+ orders = [self.create_ui_order_data([(product1, 1)]),
+ self.create_ui_order_data([(product2, 1)]),
+ self.create_ui_order_data([(product1, 2), (product2, 2)])]
+
+ # sync orders
+ self.env['pos.order'].create_from_ui(orders)
+
+ # check margins in the config currency
+ self.assertEqual(self.pos_session.order_ids[0].margin, 2.5)
+ self.assertEqual(self.pos_session.order_ids[1].margin, 10)
+ self.assertEqual(self.pos_session.order_ids[2].margin, 25)
+
+ # check margins percent which should be the same as test_tax_margin
+ self.assertEqual(self.pos_session.order_ids[0].margin_percent, 0.5)
+ self.assertEqual(self.pos_session.order_ids[1].margin_percent, 0.4)
+ self.assertEqual(self.pos_session.order_ids[2].margin_percent, 0.4167)
+
+ # close session
+ self.pos_session.action_pos_session_validate()
+
+ # set the config back
+ self.config = current_config
+
+ def test_return_margin(self):
+ """
+ Test margin where we return product (negative line quantity)
+ """
+
+ product1 = self.create_product('Product 1', self.categ_basic, 10, 5)
+ product2 = self.create_product('Product 2', self.categ_basic, 50, 30)
+
+ # open a session
+ self.open_new_session()
+
+ # create orders
+ orders = [self.create_ui_order_data([(product1, -1)]),
+ self.create_ui_order_data([(product2, -1)]),
+ self.create_ui_order_data([(product1, -2), (product2, -2)])]
+
+ # sync orders
+ self.env['pos.order'].create_from_ui(orders)
+
+ # check margins
+ self.assertEqual(self.pos_session.order_ids[0].margin, -5)
+ self.assertEqual(self.pos_session.order_ids[1].margin, -20)
+ self.assertEqual(self.pos_session.order_ids[2].margin, -50)
+
+ # check margins percent
+ self.assertEqual(self.pos_session.order_ids[0].margin_percent, 0.5)
+ self.assertEqual(self.pos_session.order_ids[1].margin_percent, 0.4)
+ self.assertEqual(round(self.pos_session.order_ids[2].margin_percent, 2), 0.42)
+
+ # close session
+ self.pos_session.action_pos_session_validate()
+
+ def test_fifo_margin_real_time(self):
+ """
+ Test margin where there is product in FIFO with stock update in real time
+ """
+
+ product1 = self.create_product('Product 1', self.categ_anglo, 10, 5)
+ product2 = self.create_product('Product 2', self.categ_basic, 50, 30)
+
+ move1 = self.env['stock.move'].create({
+ 'name': 'IN 2 unit @ 3 per unit',
+ 'location_id': self.supplier_location.id,
+ 'location_dest_id': self.stock_location.id,
+ 'product_id': product1.id,
+ 'product_uom': self.uom_unit.id,
+ 'product_uom_qty': 2,
+ 'price_unit': 3,
+ }).sudo()
+ move1._action_confirm()
+ move1._action_assign()
+ move1.move_line_ids.qty_done = 2
+ move1._action_done()
+
+ move2 = self.env['stock.move'].create({
+ 'name': 'IN 1 unit @ 7 per unit',
+ 'location_id': self.supplier_location.id,
+ 'location_dest_id': self.stock_location.id,
+ 'product_id': product1.id,
+ 'product_uom': self.uom_unit.id,
+ 'product_uom_qty': 1,
+ 'price_unit': 7,
+ }).sudo()
+ move2._action_confirm()
+ move2._action_assign()
+ move2.move_line_ids.qty_done = 1
+ move2._action_done()
+
+ # open a session
+ self.open_new_session()
+
+ # create orders
+ orders = [self.create_ui_order_data([(product1, 1), (product2, 1)]),
+ self.create_ui_order_data([(product1, 2)])]
+
+ # sync orders
+ self.env['pos.order'].create_from_ui(orders)
+
+ # check margins
+ self.assertEqual(self.pos_session.order_ids[0].margin, 27)
+ self.assertEqual(self.pos_session.order_ids[1].margin, 10)
+
+ # check margins percent
+ self.assertEqual(self.pos_session.order_ids[0].margin_percent, 0.45)
+ self.assertEqual(self.pos_session.order_ids[1].margin_percent, 0.5)
+
+ # close session
+ self.pos_session.action_pos_session_validate()
+
+ def test_avco_margin_closing_time(self):
+ """
+ Test margin where there is product in AVCO with stock update in closing
+ """
+
+ self.categ_anglo.property_cost_method = 'average'
+ product1 = self.create_product('Product 1', self.categ_anglo, 10, 5)
+ product2 = self.create_product('Product 2', self.categ_basic, 50, 30)
+ self.env.company.point_of_sale_update_stock_quantities = 'closing'
+
+
+ move1 = self.env['stock.move'].create({
+ 'name': 'IN 2 unit @ 3 per unit',
+ 'location_id': self.supplier_location.id,
+ 'location_dest_id': self.stock_location.id,
+ 'product_id': product1.id,
+ 'product_uom': self.uom_unit.id,
+ 'product_uom_qty': 2,
+ 'price_unit': 3,
+ }).sudo()
+ move1._action_confirm()
+ move1._action_assign()
+ move1.move_line_ids.qty_done = 2
+ move1._action_done()
+
+ move2 = self.env['stock.move'].create({
+ 'name': 'IN 1 unit @ 6 per unit',
+ 'location_id': self.supplier_location.id,
+ 'location_dest_id': self.stock_location.id,
+ 'product_id': product1.id,
+ 'product_uom': self.uom_unit.id,
+ 'product_uom_qty': 1,
+ 'price_unit': 6,
+ }).sudo()
+ move2._action_confirm()
+ move2._action_assign()
+ move2.move_line_ids.qty_done = 1
+ move2._action_done()
+
+ # open a session
+ self.open_new_session()
+
+ # create orders
+ orders = [self.create_ui_order_data([(product1, 1), (product2, 1)]),
+ self.create_ui_order_data([(product1, 2)])]
+
+ # sync orders
+ self.env['pos.order'].create_from_ui(orders)
+
+ # check margins which are not really computed so it should be 0
+ self.assertEqual(self.pos_session.order_ids[0].margin, 0)
+ self.assertEqual(self.pos_session.order_ids[1].margin, 0)
+
+ # check margins percent (same as above)
+ self.assertEqual(self.pos_session.order_ids[1].margin_percent, 0)
+ self.assertEqual(self.pos_session.order_ids[1].margin_percent, 0)
+
+ # close session
+ self.pos_session.action_pos_session_validate()
+
+ # check margins
+ self.assertEqual(self.pos_session.order_ids[0].margin, 26)
+ self.assertEqual(self.pos_session.order_ids[1].margin, 12)
+
+ # check margins percent
+ self.assertEqual(self.pos_session.order_ids[0].margin_percent, 0.4333)
+ self.assertEqual(self.pos_session.order_ids[1].margin_percent, 0.6)
+
+ self.env.company.point_of_sale_update_stock_quantities = 'real'
diff --git a/addons/point_of_sale/views/pos_order_view.xml b/addons/point_of_sale/views/pos_order_view.xml
index 38b34dece8b..e7e49e3078c 100644
--- a/addons/point_of_sale/views/pos_order_view.xml
+++ b/addons/point_of_sale/views/pos_order_view.xml
@@ -51,6 +51,10 @@