From ae7d18dd5f2a712348fc0911777b164c7a273c0a Mon Sep 17 00:00:00 2001 From: roen-odoo Date: Tue, 27 Feb 2024 16:02:10 +0000 Subject: [PATCH] [FIX] point_of_sale: refund payment should be the same as orinal order Current behavior: When you refund an order that was paid with bank and so not rounded, the refund is rounded wich result in a difference between the original order and the refund. This also happens when the original order was paid with multiple payments and one of them was not rounded and the other was. The refund will be rounded as one single payment. This also results in a difference between the original order and the refund. Steps to reproduce: - Setup a rounding method with a precision of 5.0 - Create a product with a price of 138.0 - Open the POS and add the product to the order - Pay the order with 2 payments, one bank of 55 and one cash that will be rounded to 80. - Validate the order - Go in the backend and refund the order - The refund will be rounded to 135.0 opw-3701574 closes odoo/odoo#159395 X-original-commit: cdae1e34eddccd5ce098c79d845a8fc2658c0175 Signed-off-by: Joseph Caburnay (jcb) Signed-off-by: Robin Engels (roen) --- addons/point_of_sale/models/pos_order.py | 3 +- .../static/tests/tours/PaymentScreen.tour.js | 21 +++++++++++ addons/point_of_sale/tests/test_frontend.py | 35 +++++++++++++++++++ 3 files changed, 58 insertions(+), 1 deletion(-) diff --git a/addons/point_of_sale/models/pos_order.py b/addons/point_of_sale/models/pos_order.py index 391ae4cebde..a29f7ba40cc 100644 --- a/addons/point_of_sale/models/pos_order.py +++ b/addons/point_of_sale/models/pos_order.py @@ -538,7 +538,8 @@ class PosOrder(models.Model): } def _is_pos_order_paid(self): - return float_is_zero(self._get_rounded_amount(self.amount_total) - self.amount_paid, precision_rounding=self.currency_id.rounding) + amount_total = -self.refunded_order_ids.amount_paid or self.amount_total + return float_is_zero(self._get_rounded_amount(amount_total) - self.amount_paid, precision_rounding=self.currency_id.rounding) def _get_rounded_amount(self, amount, force_round=False): # TODO: add support for mix of cash and non-cash payments when both cash_rounding and only_round_cash_method are True diff --git a/addons/point_of_sale/static/tests/tours/PaymentScreen.tour.js b/addons/point_of_sale/static/tests/tours/PaymentScreen.tour.js index ac7052a67d6..f1271262cf4 100644 --- a/addons/point_of_sale/static/tests/tours/PaymentScreen.tour.js +++ b/addons/point_of_sale/static/tests/tours/PaymentScreen.tour.js @@ -275,3 +275,24 @@ registry.category("web_tour.tours").add("PaymentScreenTotalDueWithOverPayment", PaymentScreen.totalDueIs("1.95"), ].flat(), }); + +registry.category("web_tour.tours").add("PaymentScreenRoundingDownMultiplePayment", { + test: true, + steps: () => + [ + ProductScreen.clickHomeCategory(), + ProductScreen.addOrderline("Product Test", "1"), + ProductScreen.clickPayButton(), + + PaymentScreen.clickPaymentMethod("Bank"), + PaymentScreen.pressNumpad("5 5"), + + PaymentScreen.clickPaymentMethod("Cash"), + + PaymentScreen.remainingIs("0.0"), + PaymentScreen.changeIs("0.0"), + + PaymentScreen.clickValidate(), + ReceiptScreen.receiptIsThere(), + ].flat(), +}); diff --git a/addons/point_of_sale/tests/test_frontend.py b/addons/point_of_sale/tests/test_frontend.py index 260c616626f..50f53fb8bba 100644 --- a/addons/point_of_sale/tests/test_frontend.py +++ b/addons/point_of_sale/tests/test_frontend.py @@ -1138,6 +1138,41 @@ class TestUi(TestPointOfSaleHttpCommon): self.main_pos_config.with_user(self.pos_user).open_ui() self.start_tour("/pos/ui?config_id=%d" % self.main_pos_config.id, 'MultiProductOptionsTour', login="pos_user") + def test_rounding_down_refund_multiple_payment(self): + """This test makes sure that the refund amount always correspond to what has been paid in the original order. + In this example we have a rounding, so we pay 55 in bank that is not rounded, then we pay the rest in cash + that is rounded. This sum up to 130 paid, so the refund should be 130.""" + rouding_method = self.env['account.cash.rounding'].create({ + 'name': 'Rounding down', + 'rounding': 5.0, + 'rounding_method': 'DOWN', + }) + + self.env['product.product'].create({ + 'name': 'Product Test', + 'available_in_pos': True, + 'list_price': 134.38, + 'taxes_id': False, + }) + + self.main_pos_config.write({ + 'rounding_method': rouding_method.id, + 'cash_rounding': True, + }) + + self.main_pos_config.open_ui() + self.start_tour("/pos/ui?config_id=%d" % self.main_pos_config.id, 'PaymentScreenRoundingDownMultiplePayment', login="accountman") + + last_order = self.env['pos.order'].search([], order='id desc', limit=1) + refund_order = self.env['pos.order'].browse(last_order.refund()['res_id']) + payment = self.env['pos.make.payment'].with_context(active_id=refund_order.id).create({ + 'payment_method_id': self.main_pos_config.payment_method_ids[0].id, + }) + self.assertEqual(payment.amount, -130.0, "The amount should be 130.0") + payment.check() + self.assertEqual(refund_order.amount_paid, -130.0, "The amount should be 130.0") + self.assertEqual(refund_order.state, 'paid', "The order should be paid") + # This class just runs the same tests as above but with mobile emulation class MobileTestUi(TestUi): browser_size = '375x667'