From f373482b2963576994a4a36dca71585ac0efca3c Mon Sep 17 00:00:00 2001 From: roen-odoo Date: Fri, 17 Jun 2022 11:11:40 +0000 Subject: [PATCH] [FIX] account: correctly reconcile refund from PoS MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Current behavior: In the PoS if you use 2 differents payment methods (cash and customer account), and that the cash amount given by the client require you to give some money back, the amount due on the customer account would be incorrect on the invoice. Steps to reproduce: - Start a PoS session - Add the 750$ desk to the order - Go in the payment screen - Add customer account with 300$ - Add cash with 460$ - Click on invoice - The invoice show that the client need to pay 290$ which is not correct Before the fix calling `_prepare_reconciliation_partials()` with the sorted lines we had 2 credit lines (750€ and 10€) and 1 debit line (460€). Debit lines | Credit lines 460€ | 750€ | 10€ The function would reconcile the 2 first lines and stop after that because the only debit line was fully reconciled After the fix we have this Debit lines | Credit lines 460€ | 10€ | 750€ After reconciling the 2 first lines we have this Debit lines | Credit lines 450€ | 750€ And after reconciling the 2 last lines we have the correct amount left to pay by the customer (300€) opw-2857064 closes odoo/odoo#98828 X-original-commit: 1201123e272012b7b5ab65eebfd12a911ecc6c1a Signed-off-by: William André (wan) Signed-off-by: Engels Robin (roen) --- addons/account/models/account_move_line.py | 2 +- .../tests/test_point_of_sale_flow.py | 59 +++++++++++++++++++ .../tests/test_stockvaluation.py | 4 +- 3 files changed, 62 insertions(+), 3 deletions(-) diff --git a/addons/account/models/account_move_line.py b/addons/account/models/account_move_line.py index 447665dfaa2..b3856aadefe 100644 --- a/addons/account/models/account_move_line.py +++ b/addons/account/models/account_move_line.py @@ -2140,7 +2140,7 @@ class AccountMoveLine(models.Model): raise UserError(_("Entries are not from the same account: %s != %s") % (account.display_name, line.account_id.display_name)) - sorted_lines = self.sorted(key=lambda line: (line.date_maturity or line.date, line.currency_id)) + sorted_lines = self.sorted(key=lambda line: (line.date_maturity or line.date, line.currency_id, line.amount_currency)) # ==== Collect all involved lines through the existing reconciliation ==== diff --git a/addons/point_of_sale/tests/test_point_of_sale_flow.py b/addons/point_of_sale/tests/test_point_of_sale_flow.py index 23ea83438f4..45a5a50a8c5 100644 --- a/addons/point_of_sale/tests/test_point_of_sale_flow.py +++ b/addons/point_of_sale/tests/test_point_of_sale_flow.py @@ -1154,3 +1154,62 @@ class TestPointOfSaleFlow(TestPointOfSaleCommon): refund.action_pos_order_invoice() self.assertEqual(refund.picking_count, 1) + + def test_order_with_different_payments_and_refund(self): + """ + Test that all the payments are correctly taken into account when the order contains multiple payments and money refund. + In this example, we create an order with two payments for a product of 750$: + - one payment of $300 with customer account + - one payment of $460 with cash + Then, we refund the order with $10, and check that the amount still due is 300$. + """ + + product5 = self.env['product.product'].create({ + 'name': 'product5', + 'type': 'product', + 'categ_id': self.env.ref('product.product_category_all').id, + }) + + # sell product thru pos + self.pos_config.open_ui() + pos_session = self.pos_config.current_session_id + product5_order = {'data': + {'amount_paid': 750, + 'amount_return': 10, + 'amount_tax': 0, + 'amount_total': 750, + 'creation_date': fields.Datetime.to_string(fields.Datetime.now()), + 'fiscal_position_id': False, + 'pricelist_id': self.pos_config.available_pricelist_ids[0].id, + 'lines': [[0, 0, { + 'discount': 0, + 'id': 42, + 'pack_lot_ids': [], + 'price_unit': 750.0, + 'product_id': product5.id, + 'price_subtotal': 750.0, + 'price_subtotal_incl': 750.0, + 'tax_ids': [[6, False, []]], + 'qty': 1, + }]], + 'name': 'Order 12345-123-1234', + 'partner_id': self.partner1.id, + 'pos_session_id': pos_session.id, + 'sequence_number': 2, + 'statement_ids': [[0, 0, { + 'amount': 460, + 'name': fields.Datetime.now(), + 'payment_method_id': self.cash_payment_method.id + }], [0, 0, { + 'amount': 300, + 'name': fields.Datetime.now(), + 'payment_method_id': self.credit_payment_method.id + }]], + 'uid': '12345-123-1234', + 'user_id': self.env.uid, + 'to_invoice': True, } + } + pos_order_id = self.PosOrder.create_from_ui([product5_order])[0]['id'] + pos_order = self.PosOrder.search([('id', '=', pos_order_id)]) + #assert account_move amount_residual is 300 + self.assertEqual(pos_order.account_move.amount_residual, 300) diff --git a/addons/purchase_stock/tests/test_stockvaluation.py b/addons/purchase_stock/tests/test_stockvaluation.py index c35aa1cbfae..e2dc3e6ca2c 100644 --- a/addons/purchase_stock/tests/test_stockvaluation.py +++ b/addons/purchase_stock/tests/test_stockvaluation.py @@ -1095,8 +1095,8 @@ class TestStockValuationWithCOA(AccountTestInvoicingCommon): self.assertRecordValues(inv.line_ids.full_reconcile_id.reconciled_line_ids, [ # pylint: disable=C0326 # Exchange difference lines: - {'balance': 46.43, 'amount_currency': 0.0}, {'balance': 92.86, 'amount_currency': 0.0}, + {'balance': 46.43, 'amount_currency': 0.0}, # Other lines: {'balance': 50.0, 'amount_currency': 100.0}, {'balance': 25.0, 'amount_currency': 50.0}, @@ -1119,8 +1119,8 @@ class TestStockValuationWithCOA(AccountTestInvoicingCommon): # pylint: disable=C0326 # Other lines: {'balance': -187.5, 'amount_currency': -150.0}, - {'balance': 90.91, 'amount_currency': 200.0}, {'balance': -22.73, 'amount_currency': -50.0}, + {'balance': 90.91, 'amount_currency': 200.0}, # Exchange difference lines: {'balance': 119.32, 'amount_currency': 0.0}, ])