GoodERP
選択できるのは25トピックまでです。 トピックは、先頭が英数字で、英数字とダッシュ('-')を使用した35文字以内のものにしてください。

367 行
19KB

  1. # -*- coding: utf-8 -*-
  2. from odoo import models, fields, api, _
  3. from odoo.exceptions import UserError
  4. class CheckoutWizard(models.TransientModel):
  5. '''月末结账的向导'''
  6. _name = 'checkout.wizard'
  7. _description = '月末结账向导'
  8. @api.model
  9. def _get_last_date(self):
  10. period_obj = self.env['finance.period']
  11. period_now = period_obj.get_date_now_period_id()
  12. if period_now:
  13. return period_obj.get_period_month_date_range(period_now)[1]
  14. else:
  15. return fields.Date.context_today(self)
  16. period_id = fields.Many2one('finance.period', '结账会计期间')
  17. date = fields.Date('生成凭证日期', required=True, default=_get_last_date)
  18. company_id = fields.Many2one(
  19. 'res.company',
  20. string='公司',
  21. change_default=True,
  22. default=lambda self: self.env.company)
  23. @api.onchange('date')
  24. def onchange_period_id(self):
  25. for wizard in self:
  26. wizard.period_id = self.env['finance.period'].with_context(
  27. module_name='checkout_wizard').get_period(wizard.date)
  28. def button_checkout(self):
  29. ''' 月末结账:结账 按钮 '''
  30. if self.period_id:
  31. if self.env['ir.module.module'].sudo().search([
  32. ('state', '=', 'installed'),
  33. ('name', '=', 'warehouse')]):
  34. self.env['month.product.cost'].generate_issue_cost(
  35. self.period_id, self.date)
  36. for balance in self:
  37. if balance.period_id:
  38. if balance.period_id.is_closed:
  39. raise UserError(_('本期间%s已结账') % balance.period_id.name)
  40. # 调用 生成科目余额表 向导的 计算上一个会计期间方法,得到 上一个会计期间
  41. last_period = self.env[
  42. 'create.trial.balance.wizard'].compute_last_period_id(
  43. balance.period_id)
  44. if last_period:
  45. if not last_period.is_closed:
  46. raise UserError(_('上一个会计期间%s未结账') % last_period.name)
  47. if balance.period_id.is_closed:
  48. # TODO 此处重复,应去掉
  49. raise UserError(_('本期间%s已结账') % balance.period_id.name)
  50. else:
  51. voucher_obj = self.env['voucher']
  52. voucher_ids = voucher_obj.search(
  53. [('period_id', '=', balance.period_id.id),
  54. ('state', '!=', 'cancel')])
  55. draft_voucher_count = 0 # 未确认凭证个数
  56. for voucher_id in voucher_ids:
  57. if voucher_id.state != 'done':
  58. draft_voucher_count += 1
  59. if draft_voucher_count != 0:
  60. raise UserError(_('该期间有 %s 张凭证未确认', draft_voucher_count))
  61. else:
  62. voucher_line = [] # 生成的结账凭证行
  63. account_obj = self.env['finance.account']
  64. company_obj = self.env['res.company']
  65. voucher_line_obj = self.env['voucher.line']
  66. revenue_account_ids = account_obj.search(
  67. [('costs_types', '=', 'in')]) # 收入类科目
  68. expense_account_ids = account_obj.search(
  69. [('costs_types', '=', 'out')]) # 费用类科目
  70. revenue_total = 0 # 收入类科目合计
  71. expense_total = 0 # 费用类科目合计
  72. for revenue_account_id in revenue_account_ids:
  73. voucher_line_ids = voucher_line_obj.search([
  74. ('account_id', '=', revenue_account_id.id),
  75. ('voucher_id.period_id', '=',
  76. balance.period_id.id),
  77. ('state', '=', 'done')])
  78. credit_total = 0
  79. for voucher_line_id in voucher_line_ids:
  80. credit_total += (voucher_line_id.credit
  81. - voucher_line_id.debit)
  82. revenue_total += credit_total
  83. if round(credit_total, 2) != 0: # 贷方冲借方
  84. res = {
  85. 'name': '月末结账',
  86. 'account_id': revenue_account_id.id,
  87. 'debit': credit_total,
  88. 'credit': 0,
  89. }
  90. voucher_line.append(res)
  91. for expense_account_id in expense_account_ids:
  92. voucher_line_ids = voucher_line_obj.search([
  93. ('account_id', '=', expense_account_id.id),
  94. ('voucher_id.period_id', '=',
  95. balance.period_id.id),
  96. ('state', '=', 'done')])
  97. debit_total = 0
  98. for voucher_line_id in voucher_line_ids:
  99. debit_total += (voucher_line_id.debit
  100. - voucher_line_id.credit)
  101. expense_total += debit_total
  102. if round(debit_total, 2) != 0: # 借方冲贷方
  103. res = {
  104. 'name': '月末结账',
  105. 'account_id': expense_account_id.id,
  106. 'debit': 0,
  107. 'credit': debit_total,
  108. }
  109. voucher_line.append(res)
  110. # 利润结余
  111. year_profit_account = \
  112. self.env.user.company_id.profit_account
  113. remain_account = \
  114. self.env.user.company_id.remain_account
  115. if not year_profit_account:
  116. raise UserError(_('公司本年利润科目未配置'))
  117. if not remain_account:
  118. raise UserError(_('公司未分配利润科目未配置'))
  119. if round(revenue_total - expense_total, 2) > 0:
  120. res = {
  121. 'name': '利润结余',
  122. 'account_id': year_profit_account.id,
  123. 'debit': 0,
  124. 'credit': revenue_total - expense_total,
  125. }
  126. voucher_line.append(res)
  127. if round(revenue_total - expense_total, 2) < 0:
  128. res = {
  129. 'name': '利润结余',
  130. 'account_id': year_profit_account.id,
  131. 'debit': expense_total - revenue_total,
  132. 'credit': 0,
  133. }
  134. voucher_line.append(res)
  135. # 生成凭证
  136. if voucher_line:
  137. valus = {
  138. 'is_checkout': True,
  139. 'date': self.date,
  140. 'line_ids': [
  141. (0, 0, line) for line in voucher_line],
  142. }
  143. voucher_profit = voucher_obj.create(valus)
  144. voucher_profit.voucher_done()
  145. year_account = None
  146. if balance.period_id.month == '12':
  147. year_profit_ids = voucher_line_obj.search([
  148. ('account_id', '=', year_profit_account.id),
  149. ('voucher_id.period_id.year',
  150. '=', balance.period_id.year),
  151. ('state', '=', 'done')])
  152. year_total = 0
  153. for year_profit_id in year_profit_ids:
  154. year_total += (year_profit_id.credit -
  155. year_profit_id.debit)
  156. precision = self.env[
  157. 'decimal.precision'].precision_get('Amount')
  158. year_total = round(year_total, precision)
  159. if year_total != 0:
  160. year_line_ids = [{
  161. 'name': '年度结余',
  162. 'account_id': remain_account.id,
  163. 'debit': 0,
  164. 'credit': year_total,
  165. }, {
  166. 'name': '年度结余',
  167. 'account_id': year_profit_account.id,
  168. 'debit': year_total,
  169. 'credit': 0,
  170. }]
  171. value = {
  172. 'is_checkout': True,
  173. 'date': balance.date,
  174. 'line_ids': [
  175. (0, 0, line) for line in year_line_ids],
  176. }
  177. year_account = voucher_obj.create(value) # 创建结转凭证
  178. year_account.voucher_done() # 凭证确认
  179. # 生成科目余额表
  180. trial_wizard = self.env[
  181. 'create.trial.balance.wizard'].create({
  182. 'period_id': balance.period_id.id,
  183. })
  184. trial_wizard.create_trial_balance()
  185. # 按用户设置重排结账会计期间凭证号(会计要求凭证号必须连续)
  186. self.recreate_voucher_name(balance.period_id)
  187. # 关闭会计期间
  188. balance.period_id.is_closed = True
  189. self.env['dupont'].fill(balance.period_id)
  190. pre_period = last_period
  191. while pre_period:
  192. self.env['dupont'].fill(pre_period)
  193. pre_period = self.env[
  194. 'create.trial.balance.wizard'
  195. ].compute_last_period_id(pre_period)
  196. # 如果下一个会计期间没有,则创建。
  197. next_period = self.env[
  198. 'create.trial.balance.wizard'].compute_next_period_id(
  199. balance.period_id)
  200. if not next_period:
  201. if balance.period_id.month == '12':
  202. self.env['finance.period'].create(
  203. {'year': str(int(balance.period_id.year)+1),
  204. 'month': '1', })
  205. else:
  206. self.env['finance.period'].create({
  207. 'year': balance.period_id.year,
  208. 'month': str(int(balance.period_id.month)+1)})
  209. # 显示凭证
  210. view = self.env.ref('finance.voucher_form')
  211. if voucher_line or year_account:
  212. # 因重置凭证号,查找最后一张结转凭证
  213. voucher = self.env['voucher'].search(
  214. [('is_checkout', '=', True),
  215. ('period_id', '=', balance.period_id.id),
  216. ('state', '=', 'done')], order="create_date desc",
  217. limit=1)
  218. return {
  219. 'name': _('月末结账'),
  220. 'view_mode': 'form',
  221. 'views': [(view.id, 'form')],
  222. 'res_model': 'voucher',
  223. 'type': 'ir.actions.act_window',
  224. 'target': 'main',
  225. 'res_id': voucher.id,
  226. }
  227. # 反结账
  228. def button_counter_checkout(self):
  229. ''' 反结账 删除对应出库成本 '''
  230. if self.period_id:
  231. issue_cost_exists = self.env['month.product.cost'].search(
  232. [('period_id', '=', self.period_id.id)])
  233. issue_cost_exists.unlink()
  234. for balance in self:
  235. if balance.period_id:
  236. if not balance.period_id.is_closed:
  237. raise UserError(_("期间 %s 未结账", balance.period_id.name))
  238. else:
  239. next_period = self.env[
  240. 'create.trial.balance.wizard'
  241. ].compute_next_period_id(
  242. balance.period_id)
  243. if next_period:
  244. if next_period.is_closed:
  245. raise UserError(_("下一个期间 %s 已结账", balance.period_id.name))
  246. # 重新打开会计期间
  247. balance.period_id.is_closed = False
  248. # 删除相关凭证及科目余额表
  249. voucher_ids = self.env['voucher'].search(
  250. [('is_checkout', '=', True),
  251. ('period_id', '=', balance.period_id.id)])
  252. for voucher_id in voucher_ids:
  253. voucher_id.voucher_draft()
  254. voucher_id.unlink()
  255. trial_balance_objs = self.env['trial.balance'].search(
  256. [('period_id', '=', balance.period_id.id)])
  257. trial_balance_objs.unlink()
  258. old = self.env['dupont'].search(
  259. [('period_id', '=', balance.period_id.id)])
  260. for o in old:
  261. o.unlink()
  262. # 按用户设置重排结账会计期间凭证号(会计要求凭证号必须连续)
  263. def recreate_voucher_name(self, period_id):
  264. # 取重排凭证设置
  265. # 是否重置凭证号
  266. context = dict(self.env.context or {})
  267. context['call_module'] = "checkout_wizard"
  268. auto_reset = self.env['ir.default']._get(
  269. 'finance.config.settings', 'defaul_auto_reset')
  270. # 重置凭证间隔:年 月
  271. reset_period = self.env['ir.default']._get(
  272. 'finance.config.settings', 'defaul_reset_period')
  273. # 重置后起始数字
  274. reset_init_number = self.env['ir.default']._get(
  275. 'finance.config.settings', 'defaul_reset_init_number')
  276. if auto_reset is True:
  277. # 取ir.sequence中的会计凭证的参数
  278. force_company = self._context.get('force_company')
  279. if not force_company:
  280. force_company = self.env.user.company_id.id
  281. company_ids = self.env['res.company'].search([]).ids + [False]
  282. seq_ids = self.env['ir.sequence'].search(
  283. ['&', ('code', '=', 'voucher'),
  284. ('company_id', 'in', company_ids)])
  285. preferred_sequences = [
  286. s for s in seq_ids
  287. if s.company_id and s.company_id.id == force_company]
  288. seq_id = preferred_sequences[0] if preferred_sequences \
  289. else seq_ids[0]
  290. voucher_obj = self.env['voucher']
  291. # 按年重置
  292. last_period = self.env[
  293. 'create.trial.balance.wizard'].compute_last_period_id(
  294. period_id)
  295. last_voucher_number = 0
  296. if reset_period == 'year':
  297. if last_period:
  298. while last_period and last_voucher_number < 1:
  299. if not last_period.is_closed:
  300. raise UserError(_('上一个期间%s未结账') % last_period.name)
  301. if period_id.year != last_period.year:
  302. # 按年,而且是第一个会计期间
  303. last_voucher_number = reset_init_number
  304. else:
  305. # 查找上一期间最后凭证号
  306. last_period_voucher_name = voucher_obj.search(
  307. [('period_id', '=', last_period.id),
  308. ('state', '=', 'done')],
  309. order="create_date desc", limit=1).name
  310. # 凭证号转换为数字
  311. if last_period_voucher_name: # 上一期间是否有凭证?
  312. last_voucher_number = int(
  313. list(filter(
  314. str.isdigit,
  315. last_period_voucher_name.encode(
  316. "utf-8")
  317. ))) + 1
  318. last_period = self.env[
  319. 'create.trial.balance.wizard'
  320. ].compute_last_period_id(
  321. last_period)
  322. else:
  323. last_voucher_number = reset_init_number
  324. voucher_ids = voucher_obj.search(
  325. [('period_id', '=', period_id.id),
  326. ('state', '=', 'done')],
  327. order='create_date')
  328. for voucher_id in voucher_ids:
  329. # 产生凭证号
  330. next_voucher_name = \
  331. '%%0%sd' % seq_id.padding % last_voucher_number
  332. last_voucher_number += 1
  333. # 更新凭证号
  334. voucher_id.with_context(context).write(
  335. {'name': next_voucher_name})
  336. # 按月重置
  337. else:
  338. if last_period and not last_period.is_closed:
  339. raise UserError(_('上一个期间%s未结账') % last_period.name)
  340. last_voucher_number = reset_init_number
  341. voucher_ids = voucher_obj.search(
  342. [('period_id', '=', period_id.id),
  343. ('state', '=', 'done')], order='create_date')
  344. for voucher_id in voucher_ids:
  345. # 产生凭证号
  346. next_voucher_name = \
  347. '%%0%sd' % seq_id.padding % last_voucher_number
  348. # 更新凭证号,将老号写到变化表中去!
  349. if voucher_id.name != next_voucher_name:
  350. self.env['change.voucher.name'].create({
  351. 'period_id': self.period_id.id,
  352. 'before_voucher_name': voucher_id.name,
  353. 'after_voucher_name': next_voucher_name,
  354. })
  355. voucher_id.with_context(context).write(
  356. {'name': next_voucher_name})
  357. last_voucher_number += 1
上海开阖软件有限公司 沪ICP备12045867号-1