"""Drill-down: from a report line to its underlying journal items. Given an account_id and a Period, fetches the matching account.move.line records and returns them in a flat list. Used by the OWL drill-down dialog and the engine's drill_down() public API.""" from dataclasses import dataclass from datetime import date @dataclass class DrillDownRow: move_line_id: int move_id: int move_name: str date: date account_code: str account_name: str partner_name: str | None label: str debit: float credit: float balance: float def to_dict(self): return { 'move_line_id': self.move_line_id, 'move_id': self.move_id, 'move_name': self.move_name, 'date': str(self.date), 'account_code': self.account_code, 'account_name': self.account_name, 'partner_name': self.partner_name or '', 'label': self.label, 'debit': self.debit, 'credit': self.credit, 'balance': self.balance, } def fetch_drill_down( env, *, account_id: int, date_from: date, date_to: date, company_id: int | None = None, limit: int = 500, ) -> list[dict]: """Fetch journal items for an account within a date range. Returns flat list of dicts ready for the drill-down OWL table.""" Line = env['account.move.line'].sudo() domain = [ ('account_id', '=', account_id), ('date', '>=', date_from), ('date', '<=', date_to), ('parent_state', '=', 'posted'), ] if company_id: domain.append(('company_id', '=', company_id)) move_lines = Line.search(domain, limit=limit, order='date asc, id asc') rows = [] for ml in move_lines: rows.append( DrillDownRow( move_line_id=ml.id, move_id=ml.move_id.id, move_name=ml.move_id.name or '', date=ml.date, account_code=ml.account_id.code, account_name=ml.account_id.name, partner_name=ml.partner_id.name if ml.partner_id else None, label=ml.name or '', debit=ml.debit, credit=ml.credit, balance=ml.balance, ).to_dict() ) return rows