GoodERP
Ви не можете вибрати більше 25 тем Теми мають розпочинатися з літери або цифри, можуть містити дефіси (-) і не повинні перевищувати 35 символів.

366 lines
19KB

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