|
|
|
|
# -*- coding: utf-8 -*-
|
|
|
|
|
from collections import defaultdict
|
|
|
|
|
import datetime
|
|
|
|
|
|
|
|
|
|
from odoo import models, fields, api
|
|
|
|
|
from odoo.exceptions import ValidationError, MissingError, UserError
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class AccountPeriod(models.Model):
|
|
|
|
|
"""会计期间"""
|
|
|
|
|
_name = 'fr.account.period'
|
|
|
|
|
_description = '会计期间'
|
|
|
|
|
|
|
|
|
|
_sql_constraints = [('unique_year_num_company', 'UNIQUE (year, num, company_id)', '会计期间已存在!')]
|
|
|
|
|
|
|
|
|
|
# 基础字段
|
|
|
|
|
name = fields.Char(string='会计期间', required=True)
|
|
|
|
|
num = fields.Integer(string='期间号', required=True, index=True)
|
|
|
|
|
date_start = fields.Date(string='开始日期', required=True)
|
|
|
|
|
date_end = fields.Date(string='结束日期', required=True)
|
|
|
|
|
|
|
|
|
|
# 关系字段
|
|
|
|
|
fiscalyear_id = fields.Many2one('fr.account.fiscalyear', string='会计年度', required=True, ondelete='cascade')
|
|
|
|
|
unpost_move_ids = fields.One2many('account.move', 'fr_period_id', string='未过账凭证', domain=[('state', '!=', 'posted')])
|
|
|
|
|
|
|
|
|
|
# 关联字段
|
|
|
|
|
company_id = fields.Many2one(related='fiscalyear_id.company_id', string='公司', store=True)
|
|
|
|
|
|
|
|
|
|
# 计算字段
|
|
|
|
|
year = fields.Integer(compute='_compute_year', string='期间年度', store=True, index=True)
|
|
|
|
|
|
|
|
|
|
# 状态
|
|
|
|
|
state = fields.Selection([
|
|
|
|
|
('unuse', '无效'),
|
|
|
|
|
('open', '开启'),
|
|
|
|
|
('close', '关闭'),
|
|
|
|
|
('ongoing', '当前'),
|
|
|
|
|
], string='状态', copy=False, index=True, default='open')
|
|
|
|
|
|
|
|
|
|
# ===================
|
|
|
|
|
# 公用方法
|
|
|
|
|
# ===================
|
|
|
|
|
|
|
|
|
|
def get_prev_period(self):
|
|
|
|
|
"""单实例方法:获取当前期间的上一会计期间
|
|
|
|
|
|
|
|
|
|
:return: 会计期间对象,单实例或空对象
|
|
|
|
|
"""
|
|
|
|
|
self.ensure_one()
|
|
|
|
|
|
|
|
|
|
# 获取上一会计期间
|
|
|
|
|
if self.num != 1:
|
|
|
|
|
prev_period = self.get_prev_period_in_fiscalyear()
|
|
|
|
|
|
|
|
|
|
else:
|
|
|
|
|
prev_fiscalyear = self.fiscalyear_id.get_prev_fiscalyear()
|
|
|
|
|
if prev_fiscalyear:
|
|
|
|
|
prev_period = prev_fiscalyear.get_period_by_num(12)
|
|
|
|
|
else:
|
|
|
|
|
prev_period = self.env['fr.account.period']
|
|
|
|
|
|
|
|
|
|
return prev_period
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def get_next_period(self):
|
|
|
|
|
"""单实例方法:获取当前期间的下一会计期间
|
|
|
|
|
|
|
|
|
|
:return: 会计期间对象,单实例或空对象
|
|
|
|
|
"""
|
|
|
|
|
self.ensure_one()
|
|
|
|
|
|
|
|
|
|
# 获取下一会计期间
|
|
|
|
|
if self.num != 12:
|
|
|
|
|
next_period = self.get_next_period_in_fiscalyear()
|
|
|
|
|
|
|
|
|
|
else:
|
|
|
|
|
next_fiscalyear = self.fiscalyear_id.get_next_fiscalyear()
|
|
|
|
|
if next_fiscalyear:
|
|
|
|
|
next_period = next_fiscalyear.get_period_by_num(12)
|
|
|
|
|
else:
|
|
|
|
|
next_period = self.env['fr.account.period']
|
|
|
|
|
|
|
|
|
|
return next_period
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def get_prev_period_in_fiscalyear(self):
|
|
|
|
|
"""单实例方法:获取当前期间该年度的上一会计期间
|
|
|
|
|
|
|
|
|
|
:return: 会计期间对象,单实例或空对象
|
|
|
|
|
"""
|
|
|
|
|
self.ensure_one()
|
|
|
|
|
|
|
|
|
|
prev_period = self.fiscalyear_id.get_period_by_num(self.num - 1)
|
|
|
|
|
return prev_period
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def get_next_period_in_fiscalyear(self):
|
|
|
|
|
"""单实例方法:获取当前期间该年度的下一会计期间
|
|
|
|
|
|
|
|
|
|
:return: 会计期间对象,单实例或空对象
|
|
|
|
|
"""
|
|
|
|
|
self.ensure_one()
|
|
|
|
|
|
|
|
|
|
next_period = self.fiscalyear_id.get_period_by_num(self.num + 1)
|
|
|
|
|
return next_period
|
|
|
|
|
|
|
|
|
|
# ===================
|
|
|
|
|
# 公用方法
|
|
|
|
|
# ===================
|
|
|
|
|
|
|
|
|
|
def check_carry_over(self):
|
|
|
|
|
"""单实例方法:检查是否存在未结转损益科目余额"""
|
|
|
|
|
self.ensure_one()
|
|
|
|
|
|
|
|
|
|
balance_data = self._fetch_balance_data(self.company_id.id, self.date_end)
|
|
|
|
|
|
|
|
|
|
accounts = self.env['account.account'].search([
|
|
|
|
|
('company_id', '=', self.company_id.id), ('fr_as_leaf', '=', True), ('internal_group', 'in', ['income', 'expense'])])
|
|
|
|
|
|
|
|
|
|
for account in accounts:
|
|
|
|
|
balance = balance_data[account.id]
|
|
|
|
|
if balance != 0:
|
|
|
|
|
return False
|
|
|
|
|
|
|
|
|
|
return True
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def execute_carry_over(self, account_id, journal_id):
|
|
|
|
|
"""单实例方法:结转当前期间对应的损益科目余额
|
|
|
|
|
损益结转逻辑:收入本来的贷方变为借方,费用类本来的借方值变为贷方,本年利润值=借方-贷方值,
|
|
|
|
|
使得借贷平衡。具体参考下列截图,暂不考虑负数(21_7_20 负数结转问题一解决)
|
|
|
|
|
"""
|
|
|
|
|
self.ensure_one()
|
|
|
|
|
move_lines = []
|
|
|
|
|
balance_total = 0
|
|
|
|
|
debit_sum = 0
|
|
|
|
|
credit_sum = 0
|
|
|
|
|
|
|
|
|
|
balance_data = self._fetch_balance_data(self.company_id.id, self.date_end)
|
|
|
|
|
accounts = self.env['account.account'].search([
|
|
|
|
|
('company_id', '=', self.company_id.id), ('fr_as_leaf', '=', True), ('internal_group', 'in', ['income', 'expense'])])
|
|
|
|
|
|
|
|
|
|
# 结转收入, 收入类的贷方,变为借方。
|
|
|
|
|
for account in accounts.filtered(lambda acc: acc.internal_group == 'income'):
|
|
|
|
|
balance = balance_data[account.id]
|
|
|
|
|
|
|
|
|
|
if balance != 0:
|
|
|
|
|
balance_total += balance
|
|
|
|
|
|
|
|
|
|
# 注释内容,为7_20
|
|
|
|
|
# if balance < 0:
|
|
|
|
|
debit_sum += balance
|
|
|
|
|
move_lines.append((0, 0, {
|
|
|
|
|
'name': '期间损益结转-结转收入',
|
|
|
|
|
'account_id': account.id,
|
|
|
|
|
'debit': -balance,
|
|
|
|
|
'credit': 0,
|
|
|
|
|
}))
|
|
|
|
|
|
|
|
|
|
# else:
|
|
|
|
|
# debit_sum += balance
|
|
|
|
|
# move_lines.append((0, 0, {
|
|
|
|
|
# 'name': '期间损益结转-结转收入',
|
|
|
|
|
# 'account_id': account.id,
|
|
|
|
|
# 'debit': balance,
|
|
|
|
|
# 'credit': 0,
|
|
|
|
|
# }))
|
|
|
|
|
|
|
|
|
|
# 结转费用 费用类本来的借方值变为贷方
|
|
|
|
|
for account in accounts.filtered(lambda acc: acc.internal_group == 'expense'):
|
|
|
|
|
balance = balance_data[account.id]
|
|
|
|
|
if balance != 0:
|
|
|
|
|
balance_total += balance
|
|
|
|
|
# if balance > 0:
|
|
|
|
|
credit_sum += balance
|
|
|
|
|
move_lines.append((0, 0, {
|
|
|
|
|
'name': '期间损益结转-结转费用',
|
|
|
|
|
'account_id': account.id,
|
|
|
|
|
'debit': 0,
|
|
|
|
|
'credit': balance,
|
|
|
|
|
}))
|
|
|
|
|
|
|
|
|
|
# else:
|
|
|
|
|
# credit_sum += -balance
|
|
|
|
|
# move_lines.append((0, 0, {
|
|
|
|
|
# 'name': '期间损益结转-结转费用',
|
|
|
|
|
# 'account_id': account.id,
|
|
|
|
|
# 'debit': 0,
|
|
|
|
|
# 'credit': -balance,
|
|
|
|
|
# }))
|
|
|
|
|
# move_lines.append((0, 0, {
|
|
|
|
|
# 'name': '期间损益结转-结转费用',
|
|
|
|
|
# 'account_id': account.id,
|
|
|
|
|
# 'debit': 0,
|
|
|
|
|
# 'credit': - balance,
|
|
|
|
|
# }))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# 添加结转科目行,7-20本年利润计算。自带凭证明细行为负数结转问题
|
|
|
|
|
if balance_total > 0:
|
|
|
|
|
move_lines.append((0, 0, {
|
|
|
|
|
'name': '期间损益结转-本年利润',
|
|
|
|
|
'account_id': account_id,
|
|
|
|
|
'debit': balance_total,
|
|
|
|
|
'credit': 0,
|
|
|
|
|
}))
|
|
|
|
|
elif balance_total < 0:
|
|
|
|
|
move_lines.append((0, 0, {
|
|
|
|
|
'name': '期间损益结转-本年利润',
|
|
|
|
|
'account_id': account_id,
|
|
|
|
|
'debit': 0,
|
|
|
|
|
'credit': - balance_total,
|
|
|
|
|
}))
|
|
|
|
|
|
|
|
|
|
# 添加结转科目行
|
|
|
|
|
# if balance_total > 0:
|
|
|
|
|
# move_lines.append((0, 0, {
|
|
|
|
|
# 'name': '期间损益结转-本年利润',
|
|
|
|
|
# 'account_id': account_id,
|
|
|
|
|
# 'debit': - (debit_sum - credit_sum),
|
|
|
|
|
# 'credit': 0,
|
|
|
|
|
# }))
|
|
|
|
|
# elif balance_total < 0:
|
|
|
|
|
# move_lines.append((0, 0, {
|
|
|
|
|
# 'name': '期间损益结转-本年利润',
|
|
|
|
|
# 'account_id': account_id,
|
|
|
|
|
# 'debit': 0,
|
|
|
|
|
# 'credit': debit_sum - credit_sum,
|
|
|
|
|
# }))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#创建凭证
|
|
|
|
|
if len(move_lines) > 0:
|
|
|
|
|
move = self.env['account.move'].create({
|
|
|
|
|
'journal_id': journal_id,
|
|
|
|
|
'ref': '期间损益结转',
|
|
|
|
|
'date': self.date_end,
|
|
|
|
|
'line_ids': move_lines,
|
|
|
|
|
'state': 'draft',
|
|
|
|
|
})
|
|
|
|
|
# 凭证审核过账
|
|
|
|
|
# move.voucher_approved_posted()
|
|
|
|
|
# 此处跟之前损益结转 生成凭证,判断科目 必填 方法冲突。需要修改单独,执行新的审核过账方法
|
|
|
|
|
move.voucher_approved_posted_execute_carry()
|
|
|
|
|
return move
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def check_move_num(self):
|
|
|
|
|
"""单实例方法:检查期间凭证编号"""
|
|
|
|
|
self.ensure_one()
|
|
|
|
|
check_res = False
|
|
|
|
|
|
|
|
|
|
moves = self.env['account.move'].search([('fr_period_id', '=', self.id), ('state', '!=', 'draft')])
|
|
|
|
|
str_nums = moves.filtered(lambda move: move.num and move.num != '/').mapped('num')
|
|
|
|
|
|
|
|
|
|
if not moves:
|
|
|
|
|
check_res = True
|
|
|
|
|
elif len(str_nums) == len(moves):
|
|
|
|
|
nums = set([int(str_num.split('-')[-1]) for str_num in str_nums])
|
|
|
|
|
if max(nums) == len(moves):
|
|
|
|
|
check_res = True
|
|
|
|
|
return check_res
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def reset_move_num(self):
|
|
|
|
|
"""【凭证编号日期重排】单实例方法:重置期间凭证编号"""
|
|
|
|
|
self.ensure_one()
|
|
|
|
|
# moves = self.env['account.move'].search([('fr_period_id', '=', self.id), ('state', '!=', 'draft')])
|
|
|
|
|
moves = self.env['account.move'].search([('fr_period_id', '=', self.id)])
|
|
|
|
|
# 重置序列号
|
|
|
|
|
sequence = self.env['ir.sequence'].search([('code', '=', 'move.sequence'),
|
|
|
|
|
('company_id', '=', self.company_id.id)])
|
|
|
|
|
|
|
|
|
|
sub_sequence = sequence.date_range_ids.filtered \
|
|
|
|
|
(lambda x: x.date_from == self.date_start and x.date_to == self.date_end)
|
|
|
|
|
if sub_sequence:
|
|
|
|
|
sub_sequence.unlink()
|
|
|
|
|
|
|
|
|
|
# 重置凭证编号
|
|
|
|
|
moves.write({'num': '/'})
|
|
|
|
|
moves._generate_move_num(moves)
|
|
|
|
|
return True
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def reset_move_num_approved(self):
|
|
|
|
|
"""【凭证编号审核日期重排】 单实例方法:根据审批日期重置凭证编号"""
|
|
|
|
|
self.ensure_one()
|
|
|
|
|
moves = self.env['account.move'].search([('fr_period_id', '=', self.id)])
|
|
|
|
|
# 重置序列号
|
|
|
|
|
sequence = self.env['ir.sequence'].search([('code', '=', 'move.sequence.approved'),
|
|
|
|
|
('company_id', '=', self.company_id.id)])
|
|
|
|
|
sub_sequence = sequence.date_range_ids.filtered \
|
|
|
|
|
(lambda x: x.date_from == self.date_start and x.date_to == self.date_end)
|
|
|
|
|
if sub_sequence:
|
|
|
|
|
sub_sequence.unlink()
|
|
|
|
|
|
|
|
|
|
moves._generate_move_num_approved(moves)
|
|
|
|
|
return True
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def reset_move_num_fill(self, move_id):
|
|
|
|
|
"""单实例方法:填补凭证编号"""
|
|
|
|
|
self.ensure_one()
|
|
|
|
|
moves = self.env['account.move'].search([('fr_period_id', '=', self.id)])
|
|
|
|
|
# 重置序列号
|
|
|
|
|
sequence = self.env['ir.sequence'].search([('code', '=', 'move.sequence'),
|
|
|
|
|
('company_id', '=', self.company_id.id)])
|
|
|
|
|
|
|
|
|
|
sub_sequence = sequence.date_range_ids.filtered \
|
|
|
|
|
(lambda x: x.date_from == self.date_start and x.date_to == self.date_end)
|
|
|
|
|
if not sub_sequence:
|
|
|
|
|
# 创建子序列
|
|
|
|
|
self.env['ir.sequence.date_range'].sudo().create({
|
|
|
|
|
'date_from': self.date_start,
|
|
|
|
|
'date_to': self.date_end,
|
|
|
|
|
'sequence_id': sequence.id,
|
|
|
|
|
'number_next_actual': len(moves) + 1
|
|
|
|
|
})
|
|
|
|
|
moves._generate_move_num_fill(moves, move_id, sub_sequence)
|
|
|
|
|
return True
|
|
|
|
|
|
|
|
|
|
# 手动凭证补号操作。
|
|
|
|
|
def reset_move_num_manual(self, move_id):
|
|
|
|
|
"""单实例方法:手动凭证补号操作"""
|
|
|
|
|
self.ensure_one()
|
|
|
|
|
# 获取当前期间全部凭证,并且进行编号排序
|
|
|
|
|
moves = self.env['account.move'].search([('fr_period_id', '=', self.id)]).sorted(key=lambda m: m.num)
|
|
|
|
|
# 获取编号最后一位,截取数字。
|
|
|
|
|
last_moves = moves[-1].num[2:]
|
|
|
|
|
# 没有的编号列表
|
|
|
|
|
not_move_list = []
|
|
|
|
|
# 获取没有的编号
|
|
|
|
|
for move_x in range(1, (int(last_moves) + 1)):
|
|
|
|
|
move_num = '记-' + str(move_x).zfill(4)
|
|
|
|
|
if move_num not in moves.mapped('num'):
|
|
|
|
|
not_move_list.append(move_num)
|
|
|
|
|
return not_move_list
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def reset_move_num_next(self):
|
|
|
|
|
"""【凭证编号重排】单实例方法:凭证编号重排"""
|
|
|
|
|
self.ensure_one()
|
|
|
|
|
moves = self.env['account.move'].search([('fr_period_id', '=', self.id)])
|
|
|
|
|
# 检查序列号是否存在
|
|
|
|
|
sequence = self.env['ir.sequence'].search([('code', '=', 'move.sequence'),
|
|
|
|
|
('company_id', '=', self.company_id.id)])
|
|
|
|
|
sub_sequence = sequence.date_range_ids.filtered \
|
|
|
|
|
(lambda x: x.date_from == self.date_start and x.date_to == self.date_end)
|
|
|
|
|
# 如果没有子序列,则创建子序列。
|
|
|
|
|
if not sub_sequence:
|
|
|
|
|
self.env['ir.sequence.date_range'].sudo().create({
|
|
|
|
|
'date_from': self.date_start,
|
|
|
|
|
'date_to': self.date_end,
|
|
|
|
|
'sequence_id': sequence.id,
|
|
|
|
|
'number_next_actual': len(moves) + 1
|
|
|
|
|
})
|
|
|
|
|
moves._generate_move_num_next(moves, sub_sequence)
|
|
|
|
|
return True
|
|
|
|
|
|
|
|
|
|
# 系统编号重排
|
|
|
|
|
def reset_move_name_next(self):
|
|
|
|
|
"""单实例方法:系统编号重排"""
|
|
|
|
|
self.ensure_one()
|
|
|
|
|
moves = self.env['account.move'].search([('fr_period_id', '=', self.id)])
|
|
|
|
|
# 先重置所有凭证的序列号
|
|
|
|
|
for i, move in enumerate(moves):
|
|
|
|
|
move.name = '/' + str(i)
|
|
|
|
|
# 重置序列号
|
|
|
|
|
sequence = self.env['ir.sequence'].search([('code', '=', 'move.sequence.sys.number'),
|
|
|
|
|
('company_id', '=', self.company_id.id)])
|
|
|
|
|
if sequence:
|
|
|
|
|
sequence.unlink()
|
|
|
|
|
|
|
|
|
|
sequence = self.env['ir.sequence'].create({
|
|
|
|
|
'name': '%s系统编号序列(重置)' % self.company_id.name,
|
|
|
|
|
'code': 'move.sequence.sys.number',
|
|
|
|
|
'implementation': 'no_gap',
|
|
|
|
|
'padding': 4,
|
|
|
|
|
'prefix': '%(year)s/%(month)s/',
|
|
|
|
|
'use_date_range': False,
|
|
|
|
|
'date_range_type': 'month',
|
|
|
|
|
'company_id': self.company_id.id,
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
moves._generate_move_name_next(moves, sequence)
|
|
|
|
|
return True
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def carry_forward(self):
|
|
|
|
|
"""单实例方法:期末月结,关闭会计期间"""
|
|
|
|
|
self.ensure_one()
|
|
|
|
|
if self.fiscalyear_id.state == 'draft':
|
|
|
|
|
raise ValidationError('期间所属会计年度尚未激活,无法进行期末月结!')
|
|
|
|
|
|
|
|
|
|
# 无效期间无法月结
|
|
|
|
|
if self.state == 'unuse':
|
|
|
|
|
raise ValidationError('无法月结无效的期间!')
|
|
|
|
|
|
|
|
|
|
# 当前期间无法月结
|
|
|
|
|
elif self.state == 'ongoing':
|
|
|
|
|
raise ValidationError('无法月结进行中的期间!')
|
|
|
|
|
|
|
|
|
|
# 已结账期间无法月结
|
|
|
|
|
elif self.state == 'close':
|
|
|
|
|
raise ValidationError('无法月结已结账的期间!')
|
|
|
|
|
|
|
|
|
|
else:
|
|
|
|
|
# 上一期间未结账无法月结
|
|
|
|
|
last_period = self.get_prev_period()
|
|
|
|
|
if last_period.state == 'open' or last_period.state == 'ongoing':
|
|
|
|
|
raise ValidationError('在当前期间之前有未结账的期间,请先处理上一期间!')
|
|
|
|
|
|
|
|
|
|
# 存在未过账凭证
|
|
|
|
|
if len(self.unpost_move_ids) > 0:
|
|
|
|
|
raise ValidationError('期间存在未过账凭证,无法结账!')
|
|
|
|
|
|
|
|
|
|
# 凭证编号不连续
|
|
|
|
|
if self.check_move_num() is False:
|
|
|
|
|
raise ValidationError('期间凭证编号不连续,无法结账!')
|
|
|
|
|
|
|
|
|
|
# 存在未结转的损益科目
|
|
|
|
|
if self.check_carry_over() is False:
|
|
|
|
|
raise ValidationError('期间存在未结转的损益科目,无法结账!')
|
|
|
|
|
|
|
|
|
|
# 更改会计期间状态
|
|
|
|
|
self.write({'state': 'close'})
|
|
|
|
|
|
|
|
|
|
# 关闭会计年度
|
|
|
|
|
if self.num == 12:
|
|
|
|
|
self.fiscalyear_id.close_fiscalyear()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def carry_forward_cancel(self):
|
|
|
|
|
"""单实例方法:取消月结,开启会计期间"""
|
|
|
|
|
self.ensure_one()
|
|
|
|
|
if self.fiscalyear_id.state == 'draft':
|
|
|
|
|
raise ValidationError('期间所属会计年度尚未激活,无法进行取消月结!')
|
|
|
|
|
|
|
|
|
|
# 无效期间无法取消月结
|
|
|
|
|
if self.state == 'unuse':
|
|
|
|
|
raise ValidationError('无法取消月结无效的期间!')
|
|
|
|
|
|
|
|
|
|
# 当前期间无法月结
|
|
|
|
|
elif self.state == 'ongoing':
|
|
|
|
|
raise ValidationError('无法取消月结进行中的期间!')
|
|
|
|
|
|
|
|
|
|
# 未结账期间无法取消月结
|
|
|
|
|
elif self.state == 'open':
|
|
|
|
|
raise ValidationError('无法取消月结未结账的期间!')
|
|
|
|
|
|
|
|
|
|
else:
|
|
|
|
|
# 下一期间已结账无法取消月结
|
|
|
|
|
next_period = self.get_next_period()
|
|
|
|
|
if next_period.state == 'close':
|
|
|
|
|
raise ValidationError('在当前期间之后有已结账的期间,请先处理下一期间!')
|
|
|
|
|
|
|
|
|
|
# 更新会计期间状态
|
|
|
|
|
self.write({'state': 'open'})
|
|
|
|
|
|
|
|
|
|
# 关闭会计年度
|
|
|
|
|
if self.num == 12:
|
|
|
|
|
self.fiscalyear_id.reopen_fiscalyear()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# ===================
|
|
|
|
|
# 定时任务
|
|
|
|
|
# ===================
|
|
|
|
|
@api.model
|
|
|
|
|
def refresh_current_period(self):
|
|
|
|
|
"""模型方法:根据当前时间更新会计期间状态(用于定时任务)"""
|
|
|
|
|
|
|
|
|
|
current_date = datetime.date.today()
|
|
|
|
|
periods_current_old = self.search([('state', '=', 'ongoing')])
|
|
|
|
|
if periods_current_old:
|
|
|
|
|
periods_current_old.write({'state': 'open'})
|
|
|
|
|
|
|
|
|
|
periods_current_new = self.search([('date_start', '<=', current_date), ('date_end', '>=', current_date)])
|
|
|
|
|
if periods_current_new:
|
|
|
|
|
periods_current_new.write({'state': 'ongoing'})
|
|
|
|
|
|
|
|
|
|
# ===================
|
|
|
|
|
# 计算方法
|
|
|
|
|
# ===================
|
|
|
|
|
@api.depends('fiscalyear_id', 'fiscalyear_id.name')
|
|
|
|
|
def _compute_year(self):
|
|
|
|
|
"""计算方法:计算期间年份"""
|
|
|
|
|
for rec in self:
|
|
|
|
|
rec.year = int(rec.fiscalyear_id.name)
|
|
|
|
|
|
|
|
|
|
# ===================
|
|
|
|
|
# 私有方法
|
|
|
|
|
# ===================
|
|
|
|
|
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
|