From fccc1a7cbf5a34161d9ca7f2412b8651104bedf9 Mon Sep 17 00:00:00 2001 From: Suherdy Yacob Date: Tue, 5 May 2026 18:45:06 +0700 Subject: [PATCH] refactor: aggregate parent mirror journal entries per journal in POS session closing --- models/pos_session.py | 177 +++++++++++++++++++++++------------------- 1 file changed, 97 insertions(+), 80 deletions(-) diff --git a/models/pos_session.py b/models/pos_session.py index d72dffc..afc95c3 100644 --- a/models/pos_session.py +++ b/models/pos_session.py @@ -182,9 +182,8 @@ class PosSession(models.Model): except Exception as re_e: _logger.warning("Could not auto-reconcile aggregated clearing lines for session %s: %s", session.name, re_e) - # 2. Create parent mirror moves (separate per PM as requested) - for data in pm_level_data: - self._create_parent_mirror_move(session, data['pm'], data['amount'], data['amount_company_curr'], clearing_move) + # 2. Create parent mirror move (aggregated into one entry but separate lines per PM) + self._create_aggregated_parent_mirror_move(session, pm_level_data, clearing_move) except Exception as e: _logger.error("Failed to create/post aggregated inter-company clearing move for session %s: %s", session.name, e) @@ -201,96 +200,114 @@ class PosSession(models.Model): res |= clearing_moves return res - def _create_parent_mirror_move(self, session, pm, amount, amount_company_curr, branch_clearing_move): - """Create the mirror journal entry in the parent company. + def _create_aggregated_parent_mirror_move(self, session, pm_level_data, branch_clearing_move): + """Create a single mirror journal entry in the parent company, with separate lines per PM. + For each PM: Debit: Outstanding receipt account of the parent bank journal - (for bank statement reconciliation in the parent) Credit: Hubungan RK liability (229101) in the parent - (records the parent's liability to the branch) """ - # Determine parent company - parent_company = pm.parent_company_id or session.company_id.parent_id - if not parent_company: - _logger.info("No parent company configured for PM %s, skipping parent mirror entry.", pm.name) - return - - # Validate required parent configuration - parent_bank_journal = pm.parent_bank_journal_id - parent_rk_account = pm.parent_intercompany_account_id - parent_clearing_journal = pm.parent_clearing_journal_id - - if not parent_bank_journal or not parent_rk_account or not parent_clearing_journal: - _logger.warning( - "Parent clearing not fully configured for PM %s. " - "Need: parent_bank_journal_id, parent_intercompany_account_id, parent_clearing_journal_id. " - "Skipping parent mirror entry.", - pm.name - ) - return - - # Get the outstanding receipt account from the parent bank journal - outstanding_receipt_account = None - for pml in parent_bank_journal.inbound_payment_method_line_ids: - if pml.payment_account_id: - outstanding_receipt_account = pml.payment_account_id - break - - if not outstanding_receipt_account: - _logger.warning( - "No outstanding receipt account found on parent bank journal %s. " - "Skipping parent mirror entry for PM %s.", - parent_bank_journal.name, pm.name - ) - return - - # Convert amount to parent company currency if needed - parent_currency = parent_company.currency_id - if session.currency_id != parent_currency: - amount_parent_curr = session.currency_id._convert( - amount, parent_currency, parent_company, - session.stop_at or fields.Date.context_today(session) - ) - else: - amount_parent_curr = amount - + parent_groups = {} + for data in pm_level_data: + pm = data['pm'] + parent_company = pm.parent_company_id or session.company_id.parent_id + if not parent_company: + _logger.info("No parent company configured for PM %s, skipping parent mirror entry.", pm.name) + continue + + parent_bank_journal = pm.parent_bank_journal_id + parent_rk_account = pm.parent_intercompany_account_id + parent_clearing_journal = pm.parent_clearing_journal_id + + if not parent_bank_journal or not parent_rk_account or not parent_clearing_journal: + _logger.warning("Parent clearing not fully configured for PM %s. Skipping.", pm.name) + continue + + outstanding_receipt_account = None + for pml in parent_bank_journal.inbound_payment_method_line_ids: + if pml.payment_account_id: + outstanding_receipt_account = pml.payment_account_id + break + + if not outstanding_receipt_account: + _logger.warning("No outstanding receipt account found on parent bank journal %s. Skipping PM %s.", parent_bank_journal.name, pm.name) + continue + + group_key = (parent_company.id, parent_clearing_journal.id) + if group_key not in parent_groups: + parent_groups[group_key] = { + 'parent_company': parent_company, + 'parent_clearing_journal': parent_clearing_journal, + 'lines_data': [] + } + + parent_groups[group_key]['lines_data'].append({ + 'pm': pm, + 'amount': data['amount'], + 'amount_company_curr': data['amount_company_curr'], + 'outstanding_receipt_account': outstanding_receipt_account, + 'parent_rk_account': parent_rk_account, + }) + entry_date = session.stop_at or fields.Date.context_today(session) - parent_move_vals = { - 'journal_id': parent_clearing_journal.id, - 'date': entry_date, - 'ref': f"POS Mirror: {session.name} ({pm.name}) - {session.company_id.name}", - 'move_type': 'entry', - 'company_id': parent_company.id, - 'line_ids': [ - Command.create({ + for group_key, group_data in parent_groups.items(): + parent_company = group_data['parent_company'] + parent_clearing_journal = group_data['parent_clearing_journal'] + + line_ids = [] + + for line_data in group_data['lines_data']: + pm = line_data['pm'] + amount = line_data['amount'] + + parent_currency = parent_company.currency_id + if session.currency_id != parent_currency: + amount_parent_curr = session.currency_id._convert( + amount, parent_currency, parent_company, entry_date + ) + else: + amount_parent_curr = amount + + line_ids.append(Command.create({ 'name': f"POS Receipt: {pm.name} ({session.company_id.name})", - 'account_id': outstanding_receipt_account.id, + 'account_id': line_data['outstanding_receipt_account'].id, 'debit': amount_parent_curr, 'credit': 0.0, 'currency_id': session.currency_id.id, 'amount_currency': amount, - }), - Command.create({ + })) + + line_ids.append(Command.create({ 'name': f"Due to Branch: {pm.name} ({session.company_id.name})", - 'account_id': parent_rk_account.id, + 'account_id': line_data['parent_rk_account'].id, 'debit': 0.0, 'credit': amount_parent_curr, 'currency_id': session.currency_id.id, 'amount_currency': -amount, - }), - ] - } - - try: - parent_move = self.env['account.move'].sudo().with_company(parent_company).create(parent_move_vals) - parent_move._post() - _logger.info( - "Created parent mirror entry %s in company %s for session %s PM %s (amount: %s)", - parent_move.name, parent_company.name, session.name, pm.name, amount_parent_curr - ) - except Exception as e: - _logger.error( - "Failed to create parent mirror entry for session %s, PM %s in company %s: %s", - session.name, pm.name, parent_company.name, e - ) + })) + + if not line_ids: + continue + + parent_move_vals = { + 'journal_id': parent_clearing_journal.id, + 'date': entry_date, + 'ref': f"POS Mirror: {session.name} - {session.company_id.name}", + 'move_type': 'entry', + 'company_id': parent_company.id, + 'line_ids': line_ids, + } + + try: + parent_move = self.env['account.move'].sudo().with_company(parent_company).create(parent_move_vals) + parent_move._post() + _logger.info( + "Created aggregated parent mirror entry %s in company %s for session %s (Lines: %s)", + parent_move.name, parent_company.name, session.name, len(line_ids) + ) + except Exception as e: + _logger.error( + "Failed to create aggregated parent mirror entry for session %s in company %s: %s", + session.name, parent_company.name, e + )