# -*- coding: utf-8 -*- from collections import defaultdict from datetime import timedelta from odoo import api, models, fields from odoo.exceptions import UserError, MissingError BALANCE_DIRECTION = [('debit', '借'), ('credit', '贷'), ('balance', '平')] def balance_debit_to_balance_direction(balance_debit): if balance_debit > 0: balance = balance_debit direction = 'debit' elif balance_debit < 0: balance = - balance_debit direction = 'credit' else: balance = 0 direction = 'balance' return balance, direction class LedgerInquiryWizard(models.TransientModel): """总账查询向导""" _name = 'ledger.inquiry.wizard' _inherit = 'inquiry.wizard.mixin' _description = '总账查询向导' # company_id = fields.Many2one('res.company', string='公司', default=lambda self: self.env.company.id) def confirm(self): self.ensure_one() # 获取总账窗口动作 act_window = self.env['ir.actions.act_window'].for_xml_id('account_ledger', 'AccountLedgerActionList') act_window['domain'] = eval(act_window['domain']) act_window['context'] = eval(act_window['context']) act_window['display_name'] = '总账:' periods = self.env['fr.account.period'].search( [('date_start', '>=', self.period_from.date_start), ('date_start', '<=', self.period_to.date_start)]) # 添加会计期间筛选 if self.period_from and self.period_to: act_window['domain'] += [('period_id', 'in', periods.ids)] act_window['display_name'] = f'总账:{self.period_from.name} - {self.period_to.name}' # 添加会计科目筛选 if len(self.account_ids) > 0: act_window['domain'] += [('account_id', 'in', self.account_ids.ids)] return act_window def confirm(self): self.ensure_one() # 获取要打印的科目 if self.account_ids: account_ids = self.account_ids else: account_ids = self.env['account.account'].search([('state', '=', 'on_use')]) periods = self.env['fr.account.period'].search( [('date_start', '>=', self.period_from.date_start), ('date_start', '<=', self.period_to.date_start)]) date_start = self.period_from.date_start date = date_start - timedelta(days=1) balance_data = self._fetch_balance_data(self.period_from.company_id.id, date) period_data = self._fetch_period_data(self.period_from.company_id.id) # 生成临时总账报表记录 vals_list = [] for account in account_ids: descendant_ids = account.get_descendant_ids(leaf=True) # 上年结转/初始余额 balance_start = sum([balance_data[descendant_id] for descendant_id in descendant_ids]) balance_temp, direction_temp = balance_debit_to_balance_direction(balance_start) vals_list.append({ 'account_id': account.id, 'name': '初始余额', 'direction': direction_temp, 'balance': balance_temp }) # 期间总账 balance = balance_start debit_fiscalyear = credit_fiscalyear = 0 for period in periods.filtered(lambda x: x.state != 'unuse'): debit_period = credit_period = 0 # 从下级科目获取 for descendant_id in descendant_ids: data_key = f"{descendant_id}-{period.id}" debit_period += period_data[data_key][0] credit_period += period_data[data_key][1] balance += debit_period - credit_period balance, direction = balance_debit_to_balance_direction(balance) # 本期合计 vals_list.append({ 'account_id': account.id, 'period_id': period.id, 'name': '本期合计', 'debit': debit_period, 'credit': credit_period, 'direction': direction, 'balance': balance }) # 本年累计 debit_fiscalyear += debit_period credit_fiscalyear += credit_period vals_list.append({ 'account_id': account.id, 'period_id': period.id, 'name': '本年累计', 'debit': debit_fiscalyear, 'credit': credit_fiscalyear, }) # 创建临时记录集 report_recs = self.env['account.ledger.temp'].create(vals_list) # 获取总账窗口动作 act_window = self.env['ir.actions.act_window']._for_xml_id('account_ledger.AccountLedgerTempActionList') act_window['domain'] = eval(act_window['domain']) act_window['context'] = eval(act_window['context']) act_window['display_name'] = '总账:' # 添加会计期间筛选 if self.period_from and self.period_to: act_window['domain'] += [('id', 'in', report_recs.ids)] act_window['display_name'] = f'总账:{self.period_from.name} - {self.period_to.name}' # 添加会计科目筛选 if len(self.account_ids) > 0: act_window['domain'] += [('account_id', 'in', self.account_ids.ids)] return act_window def _fetch_balance_data(self, company_id, date_end): # 期末余额数据读取 self.env.cr.execute(f""" SELECT account_id, sum( balance ) AS balance FROM account_move_line WHERE company_id = {company_id} and date <= '{date_end}' and fr_state = 'posted' GROUP BY account_id """) balance_data = defaultdict(float) for res in self.env.cr.fetchall(): balance_data[res[0]] = res[1] return balance_data def _fetch_period_data(self, company_id): # 期间借贷发生数据读取 self.env.cr.execute(f""" SELECT account_id, fr_period_id, sum( debit ) AS debit, sum( credit ) AS credit FROM account_move_line WHERE company_id = {company_id} and fr_state = 'posted' GROUP BY account_id, fr_period_id """) period_data = defaultdict(lambda: (0, 0)) for res in self.env.cr.fetchall(): data_key = f"{res[0]}-{res[1]}" period_data[data_key] = (res[2], res[3]) return period_data class AccountLedgerTemp(models.TransientModel): _name = 'account.ledger.temp' _description = '总账' _order = 'account_id, id' # 基础字段 name = fields.Char(string='摘要') debit = fields.Monetary(string='借方') credit = fields.Monetary(string='贷方') direction = fields.Selection(BALANCE_DIRECTION, string='方向') balance = fields.Monetary(string='余额') # 关系字段 period_id = fields.Many2one('fr.account.period', string='会计期间') account_id = fields.Many2one('account.account', strint='会计科目') fiscalyear_id = fields.Many2one('fr.account.fiscalyear', string='会计年度') # 关联字段 company_id = fields.Many2one(related='account_id.company_id', string='公司') currency_id = fields.Many2one(related='account_id.currency_id', string='币种')