# -*- coding: utf-8 -*- from odoo import api, fields, models from odoo.exceptions import ValidationError, UserError, MissingError class AccountLedgerValue(models.Model): _name = 'account.ledger.value' _description = '报表取值' def _default_from_type(self): if self.report_id and self.report_type == 'cash_flow': from_type = 'cash_flow' else: from_type = 'ledger_line' return from_type # 基础字段 name = fields.Char(string='名称', required=True) from_type = fields.Selection([ ('ledger_line', '科目余额表'), ('cash_flow', '现金流量项目'), ('other_value', '其他取值')], string='取值来源', required=True, default=_default_from_type) # 关系字段 report_id = fields.Many2one('account.ledger.report', string='报表', ondelete='cascade') ledger_line_ids = fields.One2many('account.ledger.value.line', 'value_id', domain=[('from_type', '=', 'ledger_line')]) cash_flow_ids = fields.One2many('account.ledger.value.line', 'value_id', domain=[('from_type', '=', 'cash_flow')]) other_value_ids = fields.One2many('account.ledger.value.line', 'value_id', domain=[('from_type', '=', 'other_value')]) # 关系字段 report_type = fields.Selection(related='report_id.report_type', string='报表类型') company_id = fields.Many2one(related='report_id.company_id', string='公司') # =================== # 公用方法 # =================== def get_value(self, data_cache): """单实例方法:根据期间年度和期间号获取对应值""" self.ensure_one() value = 0 # 直接从缓存获取值 if not data_cache['value_cache'].get(self.id, None) is None: return data_cache['value_cache'][self.id] # 从科目余额表取数 if self.from_type == 'ledger_line': value = round(sum([line.get_value(data_cache) for line in self.ledger_line_ids]), 2) # 从现金流量项目取数 elif self.from_type == 'cash_flow': value = round(sum([line.get_value(data_cache) for line in self.cash_flow_ids]), 2) # 从其他取值取数 elif self.from_type == 'other_value': value = round(sum([line.get_value(data_cache) for line in self.other_value_ids]), 2) # 存入缓存 data_cache['value_cache'][self.id] = value return value class AccountLedgerValueLine(models.Model): _name = 'account.ledger.value.line' _description = '报表取值明细' # 基础字段 value_sign = fields.Selection([('add', '+'), ('minus', '-')], string='符号', default='add', required=True) # 关系字段 value_id = fields.Many2one('account.ledger.value', string='报表取值', required=True, ondelete='cascade') account_id = fields.Many2one('account.account', string='来源科目') cash_flow_id = fields.Many2one('account.cash.flow', string='现金流量项目') value_type = fields.Many2one('account.ledger.value.type', string='取值类型') value_from_id = fields.Many2one('account.ledger.value', string='来源取值') # 关联字段 report_type = fields.Selection(related='value_id.report_id.report_type', string='报表类型') from_type = fields.Selection(related='value_id.from_type', string='取值来源') company_id = fields.Many2one(related='account_id.company_id', string='来源公司') # =================== # 公用方法 # =================== def get_value(self, data_cache): """单实例方法:根据期间年度和期间编号获取明细取值""" self.ensure_one() value = 0 # 从科目余额表取数 if self.from_type == 'ledger_line' and self.account_id and self.value_type: value = self._get_ledger_line_value(data_cache) # 现金流量表取数 elif self.from_type == 'cash_flow' and self.cash_flow_id and self.value_type: value = self._get_cash_flow_value(data_cache) # 从其他取值取数 elif self.from_type == 'other_value' and self.value_from_id: value = self.value_from_id.get_value(data_cache) # 判断是否取负 if self.value_sign == 'minus': value = -value return value # =================== # 约束方法 # =================== @api.constrains('value_id', 'value_from_id', 'value_form_id.line_ids.value_from_id') def _constraints_value_id(self): for rec in self: if rec.value_id == rec.value_from_id: raise ValidationError('来源报表取值不能为当前报表取值!') if rec.value_id in rec.value_from_id.other_value_ids.mapped('value_from_id'): raise ValidationError(f'报表取值{rec.value_from_id.name}存在递归调用{rec.value_id.name}!') # =================== # 私有方法 # =================== def _get_ledger_line_value(self, data_cache): """单实例方法:从科目余额表获取取值""" self.ensure_one() if not self.account_id: raise ValidationError('取值科目不能为空!') value = 0 descendant_ids = self.account_id.get_descendant_ids(leaf=True) # 获取期末借方余额 if self.value_type.code == 'balance_period_end_deb': if not(data_cache.get('co_accounts', False) and self.account_id in data_cache['co_accounts']): balance_data_qm = data_cache.get('balance_data_qm', False) if balance_data_qm is not False: balance_qm = sum([balance_data_qm[descendant_id] for descendant_id in descendant_ids]) if balance_qm > 0: value = balance_qm else: value = data_cache['balance_data_qm_co'][self.account_id.id] # 获取期末贷方余额 elif self.value_type.code == 'balance_period_end_cre': if not(data_cache.get('co_accounts', False) and self.account_id in data_cache['co_accounts']): balance_data_qm = data_cache.get('balance_data_qm', False) if balance_data_qm is not False: balance_qm = sum([balance_data_qm[descendant_id] for descendant_id in descendant_ids]) if balance_qm < 0: value = - balance_qm else: value = - data_cache['balance_data_qm_co'][self.account_id.id] # 获取期初借方余额 if self.value_type.code == 'balance_period_start_deb': if not(data_cache.get('co_accounts', False) and self.account_id in data_cache['co_accounts']): balance_data_qc = data_cache.get('balance_data_qc', False) if balance_data_qc is not False: balance_qc = sum([balance_data_qc[descendant_id] for descendant_id in descendant_ids]) if balance_qc > 0: value = balance_qc # 获取期初贷方余额 elif self.value_type.code == 'balance_period_start_cre': if not(data_cache.get('co_accounts', False) and self.account_id in data_cache['co_accounts']): balance_data_qc = data_cache.get('balance_data_qc', False) if balance_data_qc is not False: balance_qc = sum([balance_data_qc[descendant_id] for descendant_id in descendant_ids]) if balance_qc < 0: value = - balance_qc # 获取年初借方余额 elif self.value_type.code == 'balance_year_start_deb': if not(data_cache.get('co_accounts', False) and self.account_id in data_cache['co_accounts']): balance_data_nc = data_cache.get('balance_data_nc', False) if balance_data_nc is not False: balance_nc = sum([balance_data_nc[descendant_id] for descendant_id in descendant_ids]) if balance_nc > 0: value = balance_nc else: value = data_cache['balance_data_nc_co'][self.account_id.id] # 获取年初贷方余额 elif self.value_type.code == 'balance_year_start_cre': if not(data_cache.get('co_accounts', False) and self.account_id in data_cache['co_accounts']): balance_data_nc = data_cache.get('balance_data_nc', False) if balance_data_nc is not False: balance_nc = sum([balance_data_nc[descendant_id] for descendant_id in descendant_ids]) if balance_nc < 0: value = - balance_nc else: value = - data_cache['balance_data_nc_co'][self.account_id.id] # 获取本期借方发生 elif self.value_type.code == 'period_deb': occur_data_bq = data_cache.get('occur_data_bq', False) if occur_data_bq is not False: value = sum([occur_data_bq[descendant_id][0] for descendant_id in descendant_ids]) # 获取本期贷方发生 elif self.value_type.code == 'period_cre': occur_data_bq = data_cache.get('occur_data_bq', False) if occur_data_bq is not False: value = sum([occur_data_bq[descendant_id][1] for descendant_id in descendant_ids]) # 获取本年借方发生 elif self.value_type.code == 'fiscalyear_deb': occur_data_bn = data_cache.get('occur_data_bn', False) if occur_data_bn is not False: value = sum([occur_data_bn[descendant_id][0] for descendant_id in descendant_ids]) # 获取本年贷方发生 elif self.value_type.code == 'fiscalyear_cre': occur_data_bn = data_cache.get('occur_data_bn', False) if occur_data_bn is not False: value = sum([occur_data_bn[descendant_id][1] for descendant_id in descendant_ids]) # return value return value def _get_profit_value(self, data_cache): self.ensure_one() if not self.account_id: raise ValidationError('取值科目不能为空!') value = 0 occur_data_bn = data_cache['occur_data_bn'] occur_data_bq = data_cache['occur_data_bq'] descendant_ids = self.account_id.get_descendant_ids(leaf=True) # 获取本年借方发生 if self.value_type.code == 'fiscalyear_deb': value = sum([occur_data_bn[descendant_id][0] for descendant_id in descendant_ids]) # 获取本年贷方发生 elif self.value_type.code == 'fiscalyear_cre': value = sum([occur_data_bn[descendant_id][1] for descendant_id in descendant_ids]) # 获取本期借方发生 elif self.value_type.code == 'period_deb': value = sum([occur_data_bq[descendant_id][0] for descendant_id in descendant_ids]) # 获取本期贷方发生 elif self.value_type.code == 'period_cre': value = sum([occur_data_bq[descendant_id][1] for descendant_id in descendant_ids]) return value def _get_cash_flow_value(self, data_cache): """单实例方法:从现金流量项目计算取值""" self.ensure_one() if not self.cash_flow_id: raise ValidationError('现金流量项目不能为空!') value = 0 cash_flow_data_bn = data_cache['cash_flow_data_bn'] cash_flow_data_bq = data_cache['cash_flow_data_bq'] # 获取本年借方差额 if self.value_type.code == 'fiscalyear_deb_diff': value = cash_flow_data_bn[self.cash_flow_id.id][0] elif self.value_type.code == 'fiscalyear_cre_diff': value = cash_flow_data_bn[self.cash_flow_id.id][1] elif self.value_type.code == 'period_deb_diff': value = cash_flow_data_bq[self.cash_flow_id.id][0] elif self.value_type.code == 'period_cre_diff': value = cash_flow_data_bq[self.cash_flow_id.id][1] return value class AccountLedgerValueType(models.Model): _name = 'account.ledger.value.type' _description = '报表取值类型' _order = 'sequence' sequence = fields.Integer(string='序号') code = fields.Char(string='代码', required=True) name = fields.Char(string='名称', required=True) value_type = fields.Selection([ ('ledger_line', '科目余额表'), ('cash_flow', '现金流量表项目'), ], string='取值类型', required=True) class AccountCashFlow(models.Model): _name = 'account.cash.flow' _description = '现金流量项目' name = fields.Char(string='名称') code = fields.Char(string='代码') company_id = fields.Many2one('res.company', string='公司', default=lambda self: self.env.user.company_id.id)