GoodERP
No puede seleccionar más de 25 temas Los temas deben comenzar con una letra o número, pueden incluir guiones ('-') y pueden tener hasta 35 caracteres de largo.

460 líneas
21KB

  1. # Copyright 2016 上海开阖软件有限公司 (http://www.osbzr.com)
  2. # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
  3. from odoo.exceptions import UserError
  4. from odoo import fields, models, api
  5. from odoo.tools import float_compare
  6. class OtherMoneyOrder(models.Model):
  7. _name = 'other.money.order'
  8. _description = '其他收入/其他支出'
  9. _inherit = ['mail.thread', 'mail.activity.mixin']
  10. _order = 'id desc'
  11. TYPE_SELECTION = [
  12. ('other_pay', '其他支出'),
  13. ('other_get', '其他收入'),
  14. ]
  15. @api.model_create_multi
  16. def create(self, vals_list):
  17. # 创建单据时,更新订单类型的不同,生成不同的单据编号
  18. for values in vals_list:
  19. if self.env.context.get('type') == 'other_get':
  20. values.update(
  21. {'name': self.env['ir.sequence'].next_by_code(
  22. 'other.get.order')})
  23. if self.env.context.get('type') == 'other_pay' \
  24. or values.get('name', '/') == '/':
  25. values.update(
  26. {'name': self.env['ir.sequence'].next_by_code(
  27. 'other.pay.order')})
  28. return super(OtherMoneyOrder, self).create(vals_list)
  29. @api.depends('line_ids.amount', 'line_ids.tax_amount')
  30. def _compute_total_amount(self):
  31. # 计算应付金额/应收金额
  32. for omo in self:
  33. omo.total_amount = sum((line.amount + line.tax_amount)
  34. for line in omo.line_ids)
  35. state = fields.Selection([
  36. ('draft', '草稿'),
  37. ('done', '已确认'),
  38. ('cancel', '已作废'),
  39. ], string='状态', readonly=True,
  40. default='draft', copy=False, index=True,
  41. tracking=True,
  42. help='其他收支单状态标识,新建时状态为草稿;确认后状态为已确认')
  43. partner_id = fields.Many2one('partner', string='往来单位',
  44. ondelete='restrict',
  45. help='单据对应的业务伙伴,单据确认时会影响他的应收应付余额')
  46. date = fields.Date(string='单据日期',
  47. default=lambda self: fields.Date.context_today(self),
  48. copy=False,
  49. help='单据创建日期')
  50. name = fields.Char(string='单据编号', copy=False, readonly=True, default='/',
  51. help='单据编号,创建时会根据类型自动生成')
  52. total_amount = fields.Float(string='金额', compute='_compute_total_amount',
  53. store=True, readonly=True,
  54. digits='Amount',
  55. help='本次其他收支的总金额')
  56. bank_id = fields.Many2one('bank.account', string='结算账户',
  57. required=True, ondelete='restrict',
  58. help='本次其他收支的结算账户')
  59. line_ids = fields.One2many('other.money.order.line', 'other_money_id',
  60. string='收支单行',
  61. copy=True,
  62. help='其他收支单明细行')
  63. type = fields.Selection(TYPE_SELECTION, string='类型',
  64. default=lambda self: self._context.get('type'),
  65. help='类型:其他收入 或者 其他支出')
  66. note = fields.Text('备注',
  67. help='可以为该单据添加一些需要的标识信息')
  68. is_init = fields.Boolean('初始化应收应付', help='此单是否为初始化单')
  69. company_id = fields.Many2one(
  70. 'res.company',
  71. string='公司',
  72. change_default=True,
  73. default=lambda self: self.env.company)
  74. receiver = fields.Char('收款人',
  75. help='收款人')
  76. bank_name = fields.Char('开户行')
  77. bank_num = fields.Char('银行账号')
  78. voucher_id = fields.Many2one('voucher',
  79. '对应凭证',
  80. readonly=True,
  81. ondelete='restrict',
  82. copy=False,
  83. help='其他收支单确认时生成的对应凭证')
  84. currency_id = fields.Many2one('res.currency',
  85. '外币币别',
  86. help='外币币别')
  87. is_multi_currency = fields.Boolean('多币种', related='company_id.is_multi_currency')
  88. currency_rate = fields.Float('汇率', digits='Price')
  89. currency_amount = fields.Float('外币金额',
  90. digits='Amount')
  91. details = fields.Html('明细', compute='_compute_details')
  92. @api.onchange('bank_id')
  93. def onchange_bank_id(self):
  94. for res in self:
  95. res.currency_id = self.env.company.currency_id
  96. res.currency_rate = 1
  97. if res.bank_id:
  98. if res.bank_id.currency_id:
  99. res.currency_id = res.bank_id.currency_id
  100. res.currency_rate = res.env['res.currency'].get_rate_silent(res.date, res.currency_id.id) or 1
  101. @api.depends('line_ids')
  102. def _compute_details(self):
  103. for v in self:
  104. vl = {'col': [], 'val': []}
  105. vl['col'] = ['类别', '会计科目', '辅助核算', '金额']
  106. for li in v.line_ids:
  107. vl['val'].append([
  108. li.category_id.name,
  109. li.account_id.display_name,
  110. li.auxiliary_id.name or '',
  111. li.amount])
  112. v.details = v.company_id._get_html_table(vl)
  113. @api.onchange('date')
  114. def onchange_date(self):
  115. if self._context.get('type') == 'other_get':
  116. return {'domain': {'partner_id': [('c_category_id', '!=', False)]}}
  117. else:
  118. return {'domain': {'partner_id': [('s_category_id', '!=', False)]}}
  119. @api.onchange('partner_id')
  120. def onchange_partner_id(self):
  121. """
  122. 更改业务伙伴,自动填入收款人、开户行和银行帐号
  123. """
  124. if self.partner_id:
  125. self.receiver = self.partner_id.name
  126. self.bank_name = self.partner_id.bank_name
  127. self.bank_num = self.partner_id.bank_num
  128. def other_money_done(self):
  129. '''其他收支单的审核按钮'''
  130. self.ensure_one()
  131. if float_compare(self.total_amount, 0, 3) <= 0:
  132. raise UserError('金额应该大于0。\n金额:%s' % self.total_amount)
  133. if not self.bank_id.account_id:
  134. raise UserError('请配置%s的会计科目' % (self.bank_id.name))
  135. # 根据单据类型更新账户余额
  136. if self.type == 'other_pay':
  137. decimal_amount = self.env.ref('core.decimal_amount')
  138. if float_compare(
  139. self.bank_id.balance,
  140. self.total_amount,
  141. decimal_amount.digits) == -1:
  142. raise UserError('账户余额不足。\n账户余额:%s 本次支出金额:%s' %
  143. (self.bank_id.balance, self.total_amount))
  144. self.bank_id.balance -= self.total_amount
  145. else:
  146. self.bank_id.balance += self.total_amount
  147. # 创建凭证并审核非初始化凭证
  148. vouch_obj = self.create_voucher()
  149. return self.write({
  150. 'voucher_id': vouch_obj.id,
  151. 'state': 'done',
  152. })
  153. def other_money_draft(self, is_init=False):
  154. '''其他收支单的反审核按钮'''
  155. self.ensure_one()
  156. # 根据单据类型更新账户余额
  157. if self.type == 'other_pay':
  158. self.bank_id.balance += self.total_amount
  159. else:
  160. decimal_amount = self.env.ref('core.decimal_amount')
  161. if float_compare(
  162. self.bank_id.balance,
  163. self.total_amount,
  164. decimal_amount.digits) == -1 and not is_init:
  165. raise UserError('账户余额不足。\n账户余额:%s 本次支出金额:%s' %
  166. (self.bank_id.balance, self.total_amount))
  167. self.bank_id.balance -= self.total_amount
  168. voucher = self.voucher_id
  169. self.write({
  170. 'voucher_id': False,
  171. 'state': 'draft',
  172. })
  173. # 反审核凭证并删除
  174. if voucher.state == 'done':
  175. voucher.voucher_draft()
  176. # 始初化单反审核只删除明细行
  177. if self.is_init:
  178. vouch_obj = self.env['voucher'].search([('id', '=', voucher.id)])
  179. vouch_obj_lines = self.env['voucher.line'].search([
  180. ('voucher_id', '=', vouch_obj.id),
  181. ('account_id', '=', self.bank_id.account_id.id),
  182. ('init_obj', '=', 'other_money_order-%s' % (self.id))])
  183. for vouch_obj_line in vouch_obj_lines:
  184. vouch_obj_line.unlink()
  185. else:
  186. voucher.unlink()
  187. return True
  188. def create_voucher(self):
  189. """创建凭证并审核非初始化凭证"""
  190. init_obj = ''
  191. # 初始化单的话,先找是否有初始化凭证,没有则新建一个
  192. if self.is_init:
  193. vouch_obj = self.env['voucher'].search([('is_init', '=', True)])
  194. if not vouch_obj:
  195. vouch_obj = self.env['voucher'].create({
  196. 'date': self.date,
  197. 'is_init': True,
  198. 'ref': '%s,%s' % (self._name, self.id)})
  199. else:
  200. vouch_obj = self.env['voucher'].create(
  201. {'date': self.date, 'ref': '%s,%s' % (self._name, self.id)})
  202. if self.is_init:
  203. init_obj = 'other_money_order-%s' % (self.id)
  204. if self.type == 'other_get': # 其他收入单
  205. self.other_get_create_voucher_line(vouch_obj, init_obj)
  206. else: # 其他支出单
  207. self.other_pay_create_voucher_line(vouch_obj)
  208. # 如果非初始化单则审核
  209. if not self.is_init:
  210. vouch_obj.voucher_done()
  211. return vouch_obj
  212. def other_get_create_voucher_line(self, vouch_obj, init_obj):
  213. """
  214. 其他收入单生成凭证明细行
  215. :param vouch_obj: 凭证
  216. :return:
  217. """
  218. in_currency_id = (
  219. self.bank_id.currency_id.id
  220. or self.env.user.company_id.currency_id.id)
  221. company_currency_id = self.env.user.company_id.currency_id.id
  222. in_is_company_currency = in_currency_id == company_currency_id
  223. vals = {}
  224. for line in self.line_ids:
  225. if not line.category_id.account_id:
  226. raise UserError('请配置%s的会计科目' % (line.category_id.name))
  227. rate_silent = self.env['res.currency'].get_rate_silent(
  228. self.date, self.bank_id.currency_id.id)
  229. vals.update({'vouch_obj_id': vouch_obj.id,
  230. 'name': self.name, 'note': line.note or '',
  231. 'credit_auxiliary_id': line.auxiliary_id.id,
  232. 'amount': abs(line.amount + line.tax_amount),
  233. 'credit_account_id': line.category_id.account_id.id,
  234. 'debit_account_id': self.bank_id.account_id.id,
  235. 'partner_credit': self.partner_id.id,
  236. 'partner_debit': '',
  237. 'sell_tax_amount': line.tax_amount or 0,
  238. 'init_obj': init_obj,
  239. 'currency_id': self.bank_id.currency_id.id,
  240. 'currency_amount': (
  241. not in_is_company_currency
  242. and self.total_amount or 0),
  243. # 判断是否本币
  244. 'rate_silent': rate_silent,
  245. })
  246. # 贷方行
  247. if not init_obj:
  248. self.env['voucher.line'].create({
  249. 'name': "%s %s" % (vals.get('name'), vals.get('note')),
  250. 'partner_id': vals.get('partner_credit', ''),
  251. 'account_id': vals.get('credit_account_id'),
  252. 'credit': (
  253. in_is_company_currency
  254. and line.amount
  255. or line.amount * vals.get('rate_silent')),
  256. 'voucher_id': vals.get('vouch_obj_id'),
  257. 'auxiliary_id': vals.get('credit_auxiliary_id', False),
  258. 'currency_amount': (
  259. not in_is_company_currency
  260. and line.amount or 0),
  261. 'rate_silent': vals.get('rate_silent'),
  262. })
  263. # 销项税行
  264. if vals.get('sell_tax_amount'):
  265. if not self.env.user.company_id.output_tax_account:
  266. raise UserError(
  267. '您还没有配置公司的销项税科目。\n请通过"配置-->高级配置-->公司"菜单来设置销项税科目!')
  268. self.env['voucher.line'].create({
  269. 'name': "%s %s" % (vals.get('name'), vals.get('note')),
  270. 'account_id':
  271. self.env.user.company_id.output_tax_account.id,
  272. 'credit': in_is_company_currency
  273. and line.tax_amount
  274. or line.tax_amount * vals.get('rate_silent') or 0,
  275. 'voucher_id': vals.get('vouch_obj_id'),
  276. 'currency_amount':
  277. not in_is_company_currency
  278. and line.tax_amount or 0,
  279. 'rate_silent': vals.get('rate_silent'),
  280. })
  281. # 借方行
  282. self.env['voucher.line'].create({
  283. 'name': "%s" % (vals.get('name')),
  284. 'account_id': vals.get('debit_account_id'),
  285. # 借方和
  286. 'debit':
  287. in_is_company_currency
  288. and self.total_amount
  289. or self.total_amount * vals.get('rate_silent'),
  290. 'voucher_id': vals.get('vouch_obj_id'),
  291. 'partner_id': vals.get('partner_debit', ''),
  292. 'auxiliary_id': vals.get('debit_auxiliary_id', False),
  293. 'init_obj': vals.get('init_obj', False),
  294. 'currency_id': vals.get('currency_id', False),
  295. 'currency_amount': vals.get('currency_amount'),
  296. 'rate_silent': vals.get('rate_silent'),
  297. })
  298. def other_pay_create_voucher_line(self, vouch_obj):
  299. """
  300. 其他支出单生成凭证明细行
  301. :param vouch_obj: 凭证
  302. :return:
  303. """
  304. out_currency_id = \
  305. self.bank_id.currency_id.id \
  306. or self.env.user.company_id.currency_id.id
  307. company_currency_id = self.env.user.company_id.currency_id.id
  308. out_is_company_currency = out_currency_id == company_currency_id
  309. vals = {}
  310. for line in self.line_ids:
  311. if not line.category_id.account_id:
  312. raise UserError('请配置%s的会计科目' % (line.category_id.name))
  313. rate_silent = self.env['res.currency'].get_rate_silent(
  314. self.date, self.bank_id.currency_id.id)
  315. vals.update({'vouch_obj_id': vouch_obj.id, 'name': self.name,
  316. 'note': line.note or '',
  317. 'debit_auxiliary_id': line.auxiliary_id.id,
  318. 'amount': abs(line.amount + line.tax_amount),
  319. 'credit_account_id': self.bank_id.account_id.id,
  320. 'debit_account_id': line.category_id.account_id.id,
  321. 'partner_credit': '',
  322. 'partner_debit': self.partner_id.id,
  323. 'buy_tax_amount': line.tax_amount or 0,
  324. 'currency_id': self.bank_id.currency_id.id,
  325. 'currency_amount':
  326. not out_is_company_currency
  327. and self.total_amount or 0, # 判断是否本币
  328. 'rate_silent': rate_silent,
  329. })
  330. # 借方行
  331. self.env['voucher.line'].create({
  332. 'name': "%s %s " % (vals.get('name'), vals.get('note')),
  333. 'account_id': vals.get('debit_account_id'),
  334. 'debit':
  335. out_is_company_currency
  336. and line.amount
  337. or line.amount * vals.get('rate_silent'),
  338. 'voucher_id': vals.get('vouch_obj_id'),
  339. 'partner_id': vals.get('partner_debit', ''),
  340. 'auxiliary_id': vals.get('debit_auxiliary_id', False),
  341. 'init_obj': vals.get('init_obj', False),
  342. 'currency_amount':
  343. not out_is_company_currency
  344. and line.amount or 0,
  345. 'rate_silent': vals.get('rate_silent'),
  346. })
  347. # 进项税行
  348. if vals.get('buy_tax_amount'):
  349. if not self.env.user.company_id.import_tax_account:
  350. raise UserError('请通过"配置-->高级配置-->公司"菜单来设置进项税科目')
  351. self.env['voucher.line'].create({
  352. 'name': "%s %s" % (vals.get('name'), vals.get('note')),
  353. 'account_id':
  354. self.env.user.company_id.import_tax_account.id,
  355. 'debit':
  356. out_is_company_currency
  357. and line.tax_amount
  358. or line.tax_amount * vals.get('rate_silent') or 0,
  359. 'voucher_id': vals.get('vouch_obj_id'),
  360. 'currency_amount':
  361. not out_is_company_currency
  362. and line.tax_amount or 0,
  363. 'rate_silent': vals.get('rate_silent'),
  364. })
  365. # 贷方行
  366. self.env['voucher.line'].create({
  367. 'name': "%s" % (vals.get('name')),
  368. 'partner_id': vals.get('partner_credit', ''),
  369. 'account_id': vals.get('credit_account_id'),
  370. # 借方和
  371. 'credit':
  372. out_is_company_currency
  373. and self.total_amount
  374. or self.total_amount * vals.get('rate_silent'),
  375. 'voucher_id': vals.get('vouch_obj_id'),
  376. 'auxiliary_id': vals.get('credit_auxiliary_id', False),
  377. 'init_obj': vals.get('init_obj', False),
  378. 'currency_id': vals.get('currency_id', False),
  379. 'currency_amount': vals.get('currency_amount'),
  380. 'rate_silent': vals.get('rate_silent'),
  381. })
  382. class OtherMoneyOrderLine(models.Model):
  383. _name = 'other.money.order.line'
  384. _description = '其他收支单明细'
  385. @api.onchange('service')
  386. def onchange_service(self):
  387. # 当选择了收支项后,则自动填充上类别和金额
  388. if self.env.context.get('order_type') == 'other_get':
  389. self.category_id = self.service.get_categ_id.id
  390. elif self.env.context.get('order_type') == 'other_pay':
  391. self.category_id = self.service.pay_categ_id.id
  392. self.amount = self.service.price
  393. self.tax_rate = self.tax_rate
  394. @api.onchange('amount', 'tax_rate')
  395. def onchange_tax_amount(self):
  396. '''当订单行的金额、税率改变时,改变税额'''
  397. self.tax_amount = self.amount * self.tax_rate * 0.01
  398. other_money_id = fields.Many2one('other.money.order',
  399. '其他收支', ondelete='cascade',
  400. help='其他收支单行对应的其他收支单')
  401. service = fields.Many2one('service', '收支项', ondelete='restrict',
  402. help='其他收支单行上对应的收支项')
  403. category_id = fields.Many2one('core.category',
  404. '类别', ondelete='restrict',
  405. help='类型:运费、咨询费等')
  406. account_id = fields.Many2one('finance.account',
  407. '科目', related='category_id.account_id')
  408. auxiliary_id = fields.Many2one('auxiliary.financing', '辅助核算',
  409. help='其他收支单行上的辅助核算')
  410. amount = fields.Float('金额',
  411. digits='Amount',
  412. help='其他收支单行上的金额')
  413. tax_rate = fields.Float(
  414. '税率(%)',
  415. default=lambda self: self.env.user.company_id.import_tax_rate,
  416. help='其他收支单行上的税率')
  417. tax_amount = fields.Float('税额',
  418. digits='Amount',
  419. help='其他收支单行上的税额')
  420. note = fields.Char('备注',
  421. help='可以为该单据添加一些需要的标识信息')
  422. company_id = fields.Many2one(
  423. 'res.company',
  424. string='公司',
  425. change_default=True,
  426. default=lambda self: self.env.company)
上海开阖软件有限公司 沪ICP备12045867号-1