diff --git a/addons/point_of_sale/models/pos_session.py b/addons/point_of_sale/models/pos_session.py index 3a31d2be7bd82751000c4484e040fb3e2eb69da9..444764c42676d0978ca6505a170c56aa4dd340af 100644 --- a/addons/point_of_sale/models/pos_session.py +++ b/addons/point_of_sale/models/pos_session.py @@ -417,7 +417,7 @@ class PosSession(models.Model): if order.is_invoiced: # Combine invoice receivable lines - key = order.partner_id.property_account_receivable_id.id + key = order.partner_id invoice_receivables[key] = self._update_amounts(invoice_receivables[key], {'amount': order._get_amount_receivable()}, order.date_order) # side loop to gather receivable lines by account for reconciliation for move_line in order.account_move.line_ids.filtered(lambda aml: aml.account_id.internal_type == 'receivable' and not aml.reconciled): @@ -542,7 +542,7 @@ class PosSession(models.Model): split_cash_receivable_vals = defaultdict(list) for payment, amounts in split_receivables_cash.items(): statement = statements_by_journal_id[payment.payment_method_id.cash_journal_id.id] - split_cash_statement_line_vals[statement].append(self._get_statement_line_vals(statement, payment.payment_method_id.receivable_account_id, amounts['amount'], payment.payment_date)) + split_cash_statement_line_vals[statement].append(self._get_statement_line_vals(statement, payment.payment_method_id.receivable_account_id, amounts['amount'], date=payment.payment_date, partner=payment.pos_order_id.partner_id)) split_cash_receivable_vals[statement].append(self._get_split_receivable_vals(payment, amounts['amount'], amounts['amount_converted'])) # handle combine cash payments combine_cash_statement_line_vals = defaultdict(list) @@ -581,12 +581,18 @@ class PosSession(models.Model): invoice_receivable_vals = defaultdict(list) invoice_receivable_lines = {} - for receivable_account_id, amounts in invoice_receivables.items(): - invoice_receivable_vals[receivable_account_id].append(self._get_invoice_receivable_vals(receivable_account_id, amounts['amount'], amounts['amount_converted'])) - for receivable_account_id, vals in invoice_receivable_vals.items(): + for partner, amounts in invoice_receivables.items(): + commercial_partner = partner.commercial_partner_id + account_id = commercial_partner.property_account_receivable_id.id + invoice_receivable_vals[commercial_partner].append(self._get_invoice_receivable_vals(account_id, amounts['amount'], amounts['amount_converted'], partner=commercial_partner)) + for commercial_partner, vals in invoice_receivable_vals.items(): + account_id = commercial_partner.property_account_receivable_id.id receivable_line = MoveLine.create(vals) if (not receivable_line.reconciled): - invoice_receivable_lines[receivable_account_id] = receivable_line + if account_id not in invoice_receivable_lines: + invoice_receivable_lines[account_id] = receivable_line + else: + invoice_receivable_lines[account_id] |= receivable_line data.update({'invoice_receivable_lines': invoice_receivable_lines}) return data @@ -720,11 +726,13 @@ class PosSession(models.Model): } return self._debit_amounts(partial_vals, amount, amount_converted) - def _get_invoice_receivable_vals(self, account_id, amount, amount_converted): + def _get_invoice_receivable_vals(self, account_id, amount, amount_converted, **kwargs): + partner = kwargs.get('partner', False) partial_vals = { 'account_id': account_id, 'move_id': self.move_id.id, - 'name': 'From invoiced orders' + 'name': 'From invoiced orders', + 'partner_id': partner and partner.id or False, } return self._credit_amounts(partial_vals, amount, amount_converted) @@ -766,13 +774,14 @@ class PosSession(models.Model): partial_args = {'account_id': out_account.id, 'move_id': self.move_id.id} return self._credit_amounts(partial_args, amount, amount_converted, force_company_currency=True) - def _get_statement_line_vals(self, statement, receivable_account, amount, date=False): + def _get_statement_line_vals(self, statement, receivable_account, amount, date=False, partner=False): return { 'date': fields.Date.context_today(self, timestamp=date), 'amount': amount, 'name': self.name, 'statement_id': statement.id, 'account_id': receivable_account.id, + 'partner_id': partner and self.env["res.partner"]._find_accounting_partner(partner).id } def _update_amounts(self, old_amounts, amounts_to_add, date, round=True, force_company_currency=False): diff --git a/addons/point_of_sale/tests/common.py b/addons/point_of_sale/tests/common.py index 6579b1f42ffc784b5c96ff5ae5503c0408219216..3c704060178cbd9d9512d3e7eb75a95ec70dd8e9 100644 --- a/addons/point_of_sale/tests/common.py +++ b/addons/point_of_sale/tests/common.py @@ -203,7 +203,12 @@ class TestPoSCommon(TransactionCase): 'is_cash_count': True, 'cash_journal_id': cash_journal.id, }) - config.write({'payment_method_ids': [(4,cash_split_pm.id,0)]}) + bank_split_pm = self.env['pos.payment.method'].create({ + 'name': 'Split (Bank) PM', + 'receivable_account_id': self.pos_receivable_account.id, + 'split_transactions': True, + }) + config.write({'payment_method_ids': [(4, cash_split_pm.id, 0), (4, bank_split_pm.id, 0)]}) return config def _create_other_currency_config(self): @@ -444,6 +449,7 @@ class TestPoSCommon(TransactionCase): * cash_pm : cash payment method of the session * bank_pm : bank payment method of the session * cash_split_pm : credit payment method of the session + * bank_split_pm : split bank payment method of the session """ self.config.open_session_cb() self.pos_session = self.config.current_session_id @@ -452,3 +458,4 @@ class TestPoSCommon(TransactionCase): self.cash_pm = self.pos_session.payment_method_ids.filtered(lambda pm: pm.is_cash_count and not pm.split_transactions)[:1] self.bank_pm = self.pos_session.payment_method_ids.filtered(lambda pm: not pm.is_cash_count and not pm.split_transactions)[:1] self.cash_split_pm = self.pos_session.payment_method_ids.filtered(lambda pm: pm.is_cash_count and pm.split_transactions)[:1] + self.bank_split_pm = self.pos_session.payment_method_ids.filtered(lambda pm: not pm.is_cash_count and pm.split_transactions)[:1] diff --git a/addons/point_of_sale/tests/test_pos_basic_config.py b/addons/point_of_sale/tests/test_pos_basic_config.py index 2cda91984649e217e6d024d311cbb2531e7092cc..52cce24e00a475e81fb2993ae45cef24c1fc8990 100644 --- a/addons/point_of_sale/tests/test_pos_basic_config.py +++ b/addons/point_of_sale/tests/test_pos_basic_config.py @@ -452,3 +452,54 @@ class TestPoSBasicConfig(TestPoSCommon): for line in cash_receivable_lines: self.assertTrue(line.full_reconcile_id, msg='Each cash receivable line should be fully-reconciled.') + + + def test_correct_partner_on_invoice_receivables(self): + self.open_new_session() + + # create orders + # each order with total amount of 100. + orders = [] + # from 1st to 8th order: use the same customer (self.customer) but varies with is_invoiced and payment method. + orders.append(self.create_ui_order_data([(self.product1, 10)], payments=[(self.cash_pm, 100)], customer=self.customer, is_invoiced=True, uid='00100-010-0001')) + orders.append(self.create_ui_order_data([(self.product1, 10)], payments=[(self.bank_pm, 100)], customer=self.customer, is_invoiced=True, uid='00100-010-0002')) + orders.append(self.create_ui_order_data([(self.product1, 10)], payments=[(self.cash_split_pm, 100)], customer=self.customer, is_invoiced=True, uid='00100-010-0003')) + orders.append(self.create_ui_order_data([(self.product1, 10)], payments=[(self.bank_split_pm, 100)], customer=self.customer, is_invoiced=True, uid='00100-010-0004')) + orders.append(self.create_ui_order_data([(self.product1, 10)], payments=[(self.cash_pm, 100)], customer=self.customer, uid='00100-010-0005')) + orders.append(self.create_ui_order_data([(self.product1, 10)], payments=[(self.bank_pm, 100)], customer=self.customer, uid='00100-010-0006')) + orders.append(self.create_ui_order_data([(self.product1, 10)], payments=[(self.cash_split_pm, 100)], customer=self.customer, uid='00100-010-0007')) + orders.append(self.create_ui_order_data([(self.product1, 10)], payments=[(self.bank_split_pm, 100)], customer=self.customer, uid='00100-010-0008')) + # 9th and 10th orders for self.other_customer, both invoiced and paid by bank + orders.append(self.create_ui_order_data([(self.product1, 10)], payments=[(self.bank_pm, 100)], customer=self.other_customer, is_invoiced=True, uid='00100-010-0009')) + orders.append(self.create_ui_order_data([(self.product1, 10)], payments=[(self.bank_pm, 100)], customer=self.other_customer, is_invoiced=True, uid='00100-010-0010')) + # 11th order: invoiced to self.customer with bank payment method + orders.append(self.create_ui_order_data([(self.product1, 10)], payments=[(self.bank_pm, 100)], customer=self.customer, is_invoiced=True, uid='00100-010-0011')) + + # sync orders + order = self.env['pos.order'].create_from_ui(orders) + + # close the session + self.pos_session.action_pos_session_validate() + + # self.customer's bank split payments + customer_pos_receivable_bank = self.pos_session.move_id.line_ids.filtered(lambda line: line.partner_id == self.customer and 'Split (Bank) PM' in line.name) + self.assertEqual(len(customer_pos_receivable_bank), 2, msg='there are 2 bank split payments from self.customer') + self.assertEqual(bool(customer_pos_receivable_bank.full_reconcile_id), False, msg="the pos (bank) receivable lines shouldn't be reconciled") + + # self.customer's cash split payments + customer_pos_receivable_cash = self.pos_session.move_id.line_ids.filtered(lambda line: line.partner_id == self.customer and 'Split (Cash) PM' in line.name) + self.assertEqual(len(customer_pos_receivable_cash), 2, msg='there are 2 cash split payments from self.customer') + self.assertEqual(bool(customer_pos_receivable_cash.full_reconcile_id), True, msg="cash pos (cash) receivable lines should be reconciled") + + # self.customer's invoice receivable counterpart + customer_invoice_receivable_counterpart = self.pos_session.move_id.line_ids.filtered(lambda line: line.partner_id == self.customer and 'From invoiced orders' in line.name) + self.assertEqual(len(customer_invoice_receivable_counterpart), 1, msg='there should one aggregated invoice receivable counterpart for self.customer') + self.assertEqual(bool(customer_invoice_receivable_counterpart.full_reconcile_id), True, msg='the aggregated receivable for self.customer should be reconciled') + self.assertEqual(customer_invoice_receivable_counterpart.balance, -500, msg='aggregated balance should be -500') + + # self.other_customer also made invoiced orders + # therefore, it should also have aggregated receivable counterpart in the session's account_move + other_customer_invoice_receivable_counterpart = self.pos_session.move_id.line_ids.filtered(lambda line: line.partner_id == self.other_customer and 'From invoiced orders' in line.name) + self.assertEqual(len(other_customer_invoice_receivable_counterpart), 1, msg='there should one aggregated invoice receivable counterpart for self.other_customer') + self.assertEqual(bool(other_customer_invoice_receivable_counterpart.full_reconcile_id), True, msg='the aggregated receivable for self.other_customer should be reconciled') + self.assertEqual(other_customer_invoice_receivable_counterpart.balance, -200, msg='aggregated balance should be -200')