天天看点

odoo10 科目余额表跨期间建表--善用向导

基于你已经完全了解odoo10的api,以及关于模型的一些方法。

class CreateTrialBalanceWizard(models.TransientModel):
    """根据输入的期间 生成科目余额表的 向导 """
    _name = "create.trial.balance.wizard"
    _description = u'科目余额表的创建向导'

    @api.model
    def _default_period_id(self):
        return self._default_period_id_impl()

    @api.multi
    def compute_last_period_id(self, period_id):
        """取得参数区间的上个期间"""
        current_period = self.env['finance.period'].search([('id', '=', int(period_id))])
        if int(current_period.month) == 1:
            year = int(period_id.year) - 1
            month = 12
        else:
            year = period_id.year
            month = int(current_period.month) - 1
        return self.env['finance.period'].search([('year', '=', str(year)), ('month', '=', str(month))])

    @api.model
    def _default_period_id_impl(self):
        """
                        默认是当前会计期间
        :return: 当前会计期间的对象
        """
        return self.env['finance.period'].get_date_now_period_id()

    start_date = fields.Many2one('finance.period', string=u'起始会计期间')
    end_date = fields.Many2one('finance.period', string=u'结束会计期间')

    period_id = fields.Many2one('finance.period', default=_default_period_id, string=u'会计期间', help=u'限定生成期间的范围')
    company_id = fields.Many2one('res.company', string=u'公司', change_default=True, default=lambda self: self.env['res.company']._company_default_get())
    # 获取下一个会计期间
    @api.multi
    def compute_next_period_id(self, start_period_id,end_period_id):
        """取得需要的会计期间id列表"""
        period_ids = []
        #重写id列表
        #同一年的情况
        if start_period_id.year == end_period_id.year:
            # 月数相同的情况
            if start_period_id.month == end_period_id.month:
                period_ids.append(start_period_id.id)
                return period_ids
            #月数不同的情况
            else:
                # 同一年内 输入月数是前一个大于后一个,那么就报错
                if int(start_period_id.month) > int(end_period_id.month):
                    return None
                else:
                    year = int(start_period_id.year)  # 获取当时取出的年
                    begin_num = int(start_period_id.month) #如果是1的话
                    end_num = int(end_period_id.month)
                    for month in range(begin_num, end_num + 1):
                        need_date = self.env['finance.period'].search(
                            [('year', '=', str(year)), ('month', '=', str(month))])
                        period_ids.append(need_date.id)
                    return period_ids
        #不同年的情况
        #当输入的前一年大于后一年时,提示错误
        elif int(start_period_id.year) > int(end_period_id.year):
            return None
        elif int(start_period_id.year) < int(end_period_id.year):
            #走到这一步,表示一定跨期间且跨年查询,也就是说这里一定是 前一个是前一年,后一个是后一年
            befro_year = start_period_id.year
            after_year = end_period_id.year
            one_begin_num = int(start_period_id.month)
            two_end_num = int(end_period_id.month)
            for one in range(one_begin_num,13):
                need_date = self.env['finance.period'].search(
                            [('year', '=', str(befro_year)), ('month', '=', str(one))])
                period_ids.append(need_date)
            for two in range(1,two_end_num+1):
                need_date = self.env['finance.period'].search(
                    [('year', '=', str(after_year)), ('month', '=', str(two))])
                period_ids.append(need_date)
            return period_ids
    @api.multi
    def get_period_balance(self, period_ids):
        """取出本期发生额
            返回结果是 科目 借 贷
         """
        context_dic = {}
        for i in period_ids:
            sql = '''select ine.account_id as account_id,
                        sum(ine.debit) as debit,
                        sum(ine.credit) as credit
                     from account_move as ove
                     left join account_move_line as ine
                     on ove.id = ine.move_id
                     where ove.period_id=%s
                     group by ine.account_id'''
            self.env.cr.execute(sql, (i,))
            context_dic[i] = self.env.cr.dictfetchall()
            # print self.env.cr.dictfetchall()  #值已经取到了,接下来就是怎么放进去
        return context_dic   #遍历获取出需要的字典数据

    # 定义一个函数,用来获取会计期间名称
    @api.multi
    def get_period_name(self, start_period_id,end_period_id):
        begin_period_name = start_period_id.name
        end_period_name = end_period_id.name
        if str(begin_period_name) == str(end_period_name):
            return str(begin_period_name)
        else:
            str_name = str(begin_period_name) + '~' + str(end_period_name)
            return str_name
    # 点击创建科目余额表时进行的操作
    @api.multi
    def create_trial_balance(self):
        """ \
            生成科目余额表 \
            1.如果所选区间已经关闭则直接调出已有的科目余额表记录
            2.判断如果所选的区间的 前一个期间没有关闭则报错
            3.如果上一个区间不存在则报错
        """
        period_ids = self.compute_next_period_id(self.start_date,self.end_date) #获取所有的id
        # print period_ids  #测试输出的内容
        if period_ids is None:
            raise UserError(u'期间输入错误,无法取到科目余额表。')
        context_dic = self.get_period_balance(period_ids) #获取到内容,是一个字典
        # print context_dic #测试输出的内容
        my_ids = []
        my_dic = []
        for period_id in period_ids:  #这个列表是有顺序的,所以可以按照顺序来计算
            # 获取对应的内容列表
            current_occurrence_dic_list = context_dic[period_id]
            trial_balance_dict = {}
            """把本期发生额的数量填写到  准备好的dict 中 """
            # 目的是将每个科目id写入到字典,循环完成之后,字典是一个完整的会计期间字典
            for current_occurrence in current_occurrence_dic_list:
                account = self.env['account.account'].browse(current_occurrence.get('account_id'))
                #上面的语法,就是为了获取两个account.account对象,然后可以操作他们
                # print account   #account.account(66,) account.account(65,)
                ending_balance_debit = ending_balance_credit = 0 #期末余额(借方和贷方都归零)
                this_debit = current_occurrence.get('debit', 0) or 0  #获取到的借方额度
                this_credit = current_occurrence.get('credit', 0) or 0  #获取的贷方额度
                if account.balance_directions == 'in':       #判断借方与贷方的依据
                    ending_balance_debit = this_debit - this_credit
                else:
                    ending_balance_credit = this_credit - this_debit
                #写一个字典
                account_dict = {'period_id': 'test',
                                'current_occurrence_debit': this_debit,
                                'current_occurrence_credit': this_credit,
                                'subject_code': account.code,
                                'initial_balance_credit': 0,
                                'initial_balance_debit': 0,
                                'ending_balance_debit': ending_balance_debit,
                                'ending_balance_credit': ending_balance_credit,
                                'cumulative_occurrence_debit': this_debit,
                                'cumulative_occurrence_credit': this_credit,
                                'subject_name_id': account.id}
                trial_balance_dict[account.id] = account_dict  #完善我的字典,最终写入到对应的数据中
                #这个循环的意义就是将每个期间里面的值取出来建立一个记录然后插入到这个列表里面
            trial_balance_ids = [self.env['trial.balance'].create(vals).id for (key, vals) in
                                     trial_balance_dict.items()]  #再次得到这个科目余额表的ID
            my_dic += trial_balance_dict.items()
        # 最终计算
        key_ids = []
        for key,vals in my_dic:
            key_ids.append(key)
        key_ids = set(key_ids)
        my_end_dic = {}
        for newkey in key_ids:
            #初始化每个科目id的所有数据
            cumulative_occurrence_credit = 0
            cumulative_occurrence_debit = 0
            ending_balance_credit = 0
            current_occurrence_debit = 0
            current_occurrence_credit = 0
            ending_balance_debit = 0
            subject_code = ''
            subject_name_id = 0
            #遍历这里面的科目id相同的取出来,然后计算
            for two_key,two_vals in my_dic:
                if two_key == newkey:
                    cumulative_occurrence_credit += float(two_vals['cumulative_occurrence_credit'])
                    cumulative_occurrence_debit +=float(two_vals['cumulative_occurrence_debit'])
                    current_occurrence_debit +=float(two_vals['current_occurrence_debit'])
                    ending_balance_credit +=float(two_vals['ending_balance_credit'])
                    current_occurrence_credit +=float(two_vals['current_occurrence_credit'])
                    ending_balance_debit +=float(two_vals['ending_balance_debit'])
                    subject_code = str(two_vals['subject_code'])
                    subject_name_id = int(two_vals['subject_name_id'])
                else:
                    pass
            account_dict = {'period_id': str(self.get_period_name(self.start_date,self.end_date)),
                            'current_occurrence_debit': current_occurrence_debit,
                            'current_occurrence_credit': current_occurrence_credit,
                            'subject_code': subject_code,
                            'initial_balance_credit': 0,
                            'initial_balance_debit': 0,
                            'ending_balance_debit': ending_balance_debit,
                            'ending_balance_credit': ending_balance_credit,
                            'cumulative_occurrence_debit': cumulative_occurrence_debit,
                            'cumulative_occurrence_credit': cumulative_occurrence_credit,
                            'subject_name_id': subject_name_id}
            my_end_dic[newkey] = account_dict
        trial_balance_ids = [self.env['trial.balance'].create(vals).id for (key, vals) in
                             my_end_dic.items()] 
        # 获取页面的模版id进行数据的插入
        view_id = self.env.ref('juxinerp.trial_balance_tree').id
        if self.period_id == self.period_id.get_init_period():
            view_id = self.env.ref('juxinerp.init_balance_tree').id
        #返回数据开始插入
        return {
                'type': 'ir.actions.act_window',
                'name': u'科目余额表'+str(self.get_period_name(self.start_date,self.end_date)),
                'view_type': 'form',
                'view_mode': 'tree',
                'res_model': 'trial.balance',
                'target': 'current',
                'view_id': False,
                'views': [(view_id, 'tree')],
                'domain': [('id', 'in', trial_balance_ids)] #对应的输出修改对应的接收
                }