From a79dfeda98ba11fc9c852fb2d6918c22dbac8d54 Mon Sep 17 00:00:00 2001 From: roen-odoo Date: Tue, 25 Apr 2023 09:40:45 +0000 Subject: [PATCH] [FIX] point_of_sale : use correct account for pos order reversal Current behavior: When you try to invoice an order that was made in a different pos session, a reversed payment is created and then the invoice is created. But the reversed payment was using a different journal than the one used to create the order, which is not correct. Steps to reproduce: - Open a PoS session - Make an order and pay it with the customer account - Close the session - Open a new session - Go to the orders list and show the paid orders, you should see the order you made in the previous session. - Click on it and click on the invoice button - Go to the accounting app and check the entries created for the invoice, you should see a reversed payment entry that uses a different account than the one used to create the order payment. opw-3249116 closes odoo/odoo#127064 X-original-commit: a646baf6901f88434543cb34397c98f1d5c294c4 Signed-off-by: Joseph Caburnay (jcb) Signed-off-by: Robin Engels (roen) --- addons/point_of_sale/models/pos_order.py | 32 +++++--- .../tests/test_point_of_sale_flow.py | 76 +++++++++++++++++++ 2 files changed, 96 insertions(+), 12 deletions(-) diff --git a/addons/point_of_sale/models/pos_order.py b/addons/point_of_sale/models/pos_order.py index 5a89d2d81de..fb485cf16d9 100644 --- a/addons/point_of_sale/models/pos_order.py +++ b/addons/point_of_sale/models/pos_order.py @@ -746,9 +746,6 @@ class PosOrder(models.Model): 'display_type': 'rounding', }) - total_amount_currency += amount_currency - total_balance += balance - # Stock. if self.company_id.anglo_saxon_accounting and self.picking_ids.ids: stock_moves = self.env['stock.move'].sudo().search([ @@ -776,15 +773,26 @@ class PosOrder(models.Model): 'balance': -balance, }) - # Payment terms. - pos_receivable_account = self.company_id.account_default_pos_receivable_account_id - aml_vals_list_per_nature['payment_terms'].append({ - 'name': f"{pos_receivable_account.code} {pos_receivable_account.code}", - 'account_id': pos_receivable_account.id, - 'currency_id': self.currency_id.id, - 'amount_currency': -total_amount_currency, - 'balance': -total_balance, - }) + for payment_id in self.payment_ids: + is_split_transaction = payment_id.payment_method_id.split_transactions + if is_split_transaction: + reversed_move_receivable_account_id = self.partner_id.property_account_receivable_id + else: + reversed_move_receivable_account_id = payment_id.payment_method_id.receivable_account_id or self.company_id.account_default_pos_receivable_account_id + + aml_vals_entry_found = [aml_entry for aml_entry in aml_vals_list_per_nature['payment_terms'] if aml_entry['account_id'] == reversed_move_receivable_account_id.id] + if aml_vals_entry_found and not is_split_transaction: + aml_vals_entry_found[0]['amount_currency'] += self.session_id._amount_converter(payment_id.amount, self.date_order, False) + aml_vals_entry_found[0]['balance'] += payment_id.amount + else: + aml_vals_list_per_nature['payment_terms'].append({ + 'partner_id': self.partner_id.id if is_split_transaction else False, + 'name': f"{reversed_move_receivable_account_id.code} {reversed_move_receivable_account_id.code}", + 'account_id': reversed_move_receivable_account_id.id, + 'currency_id': self.currency_id.id, + 'amount_currency': self.session_id._amount_converter(payment_id.amount, self.date_order, False), + 'balance': payment_id.amount, + }) return aml_vals_list_per_nature 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 7e77ba1335f..c90adb7b3a4 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 @@ -1526,3 +1526,79 @@ class TestPointOfSaleFlow(TestPointOfSaleCommon): credit_notes = self.env['account.move'].search([('move_type', '=', 'out_refund')], order='id desc', limit=1) self.assertEqual(credit_notes.ref, "Reversal of: "+invoices.name) self.assertEqual(credit_notes.reversed_entry_id.id, invoices.id) + + def test_invoicing_after_closing_session(self): + """ Test that an invoice can be created after the session is closed """ + #create customer account payment method + self.customer_account_payment_method = self.env['pos.payment.method'].create({ + 'name': 'Customer Account', + 'split_transactions': True, + }) + + self.product1 = self.env['product.product'].create({ + 'name': 'Product A', + 'type': 'product', + 'categ_id': self.env.ref('product.product_category_all').id, + }) + + #add customer account payment method to pos config + self.pos_config.write({ + 'payment_method_ids': [(4, self.customer_account_payment_method.id, 0)], + }) + self.pos_config.open_ui() + current_session = self.pos_config.current_session_id + + # create pos order + order = self.PosOrder.create({ + 'company_id': self.env.company.id, + 'session_id': current_session.id, + 'partner_id': self.partner1.id, + 'lines': [(0, 0, { + 'name': "OL/0001", + 'product_id': self.product1.id, + 'price_unit': 6, + 'discount': 0, + 'qty': 1, + 'tax_ids': [[6, False, []]], + 'price_subtotal': 6, + 'price_subtotal_incl': 6, + })], + 'pricelist_id': self.pos_config.pricelist_id.id, + 'amount_paid': 6.0, + 'amount_total': 6.0, + 'amount_tax': 0.0, + 'amount_return': 0.0, + 'to_invoice': True, + }) + + #pay for the order with customer account + payment_context = {"active_ids": order.ids, "active_id": order.id} + order_payment = self.PosMakePayment.with_context(**payment_context).create({ + 'amount': 2.0, + 'payment_method_id': self.cash_payment_method.id + }) + order_payment.with_context(**payment_context).check() + + payment_context = {"active_ids": order.ids, "active_id": order.id} + order_payment = self.PosMakePayment.with_context(**payment_context).create({ + 'amount': 4.0, + 'payment_method_id': self.customer_account_payment_method.id + }) + order_payment.with_context(**payment_context).check() + + # close session + current_session.action_pos_session_closing_control() + + # create invoice + order.action_pos_order_invoice() + #get journal entry that does the reverse payment, it the ref must contains Reversal + reverse_payment = self.env['account.move'].search([('ref', 'ilike', "Reversal")]) + original_payment = self.env['account.move'].search([('ref', '=', current_session.display_name)]) + original_customer_payment_entry = original_payment.line_ids.filtered(lambda l: l.account_id.account_type == 'asset_receivable') + reverser_customer_payment_entry = reverse_payment.line_ids.filtered(lambda l: l.account_id.account_type == 'asset_receivable') + #check that both use the same account + self.assertEqual(len(reverser_customer_payment_entry), 2) + self.assertEqual(reverser_customer_payment_entry[0].balance, -2.0) + self.assertEqual(reverser_customer_payment_entry[1].balance, -4.0) + self.assertEqual(original_customer_payment_entry.account_id.id, reverser_customer_payment_entry.account_id.id) + self.assertEqual(reverser_customer_payment_entry.partner_id, original_customer_payment_entry.partner_id)