GoodERP
Du kannst nicht mehr als 25 Themen auswählen Themen müssen entweder mit einem Buchstaben oder einer Ziffer beginnen. Sie können Bindestriche („-“) enthalten und bis zu 35 Zeichen lang sein.

244 Zeilen
12KB

  1. # Copyright 2016 上海开阖软件有限公司 (http://www.osbzr.com)
  2. # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
  3. from odoo import api, fields, models, _
  4. from odoo.exceptions import UserError
  5. class HrExpense(models.Model):
  6. _name = 'hr.expense'
  7. _inherit = ['mail.thread', 'mail.activity.mixin']
  8. _description = '报销'
  9. name = fields.Char('单据编号', copy=False)
  10. date = fields.Date(string='报销日期', default=fields.Date.today, copy=False, required=True, help='报销发生日期')
  11. staff = fields.Many2one('staff', '报销员工', required=True, help='选择员工')
  12. invoice_all_total = fields.Float(string='费用金额合计', store=True, readonly=True, compute='_compute_invoice_all_total', tracking=True, digits='Amount')
  13. state = fields.Selection([('draft', '草稿'), ('confirm', '已提交'), ('done', '已支付')], '状态', default='draft', tracking=True, store=True, compute='_state_to_done')
  14. type = fields.Selection([('company', '付给公司'), ('my', '付给报销人')], string='支付方式', default='my', required=True, help='支付给个人时走其他付款单,支付给公司时走结算单')
  15. line_ids = fields.One2many('hr.expense.line', 'order_id', '明细发票行', copy=False)
  16. note = fields.Text('备注')
  17. bank_account_id = fields.Many2one('bank.account', '账号', ondelete='restrict', help='付给个人/公司')
  18. partner_id = fields.Many2one('partner', '供应商', help='直接支付给供应商')
  19. money_invoice = fields.Many2one('money.invoice', '对应结算单', readonly=True, ondelete='restrict', copy=False)
  20. other_money_order = fields.Many2one('other.money.order', '对应其他付款单', readonly=True, ondelete='restrict', copy=False)
  21. @api.depends('other_money_order.state')
  22. def _state_to_done(self):
  23. self.state = self.state or 'draft'
  24. if self.other_money_order and self.other_money_order.state == 'done':
  25. self.state = 'done'
  26. if self.other_money_order and self.other_money_order.state == 'draft':
  27. self.state = 'confirm'
  28. @api.depends('line_ids')
  29. def _compute_invoice_all_total(self):
  30. for bill in self:
  31. total = sum(i.invoice_total for i in bill.line_ids)
  32. bill.invoice_all_total = total
  33. def check_consistency(self):
  34. for bill in self:
  35. category_id = []
  36. for line in bill.line_ids:
  37. if line.category_id and line.category_id.id not in category_id:
  38. category_id.append(line.category_id.id)
  39. if line.category_id.type != 'expense' and bill.type == 'company':
  40. raise UserError('申报支付给公司的费用必须属于采购类别!')
  41. if line.staff.id != bill.staff.id:
  42. raise UserError('费用明细必须是同一人!')
  43. if bill.type == 'company' and len(category_id) > 1:
  44. raise UserError('申报支付给公司的费用必须同一类别!')
  45. @api.model_create_multi
  46. def create(self, vals_list):
  47. res = super().create(vals_list)
  48. res.check_consistency()
  49. return res
  50. def write(self, vals):
  51. res = super().write(vals)
  52. self.check_consistency()
  53. return res
  54. def unlink(self):
  55. for record in self:
  56. if record.state != 'draft':
  57. raise UserError('只能删除草稿状态的费用报销单')
  58. super().unlink()
  59. def hr_expense_confirm(self):
  60. for bill in self:
  61. if bill.state == 'confirm':
  62. raise UserError('请不要重复确认')
  63. if bill.type == 'company':
  64. bill.to_money_invoice()
  65. if bill.type == 'my':
  66. bill.to_other_money_order()
  67. bill.state = 'confirm'
  68. def hr_expense_draft(self):
  69. for bill in self:
  70. if bill.state == 'draft':
  71. raise UserError('请不要重复撤销 %s' % bill.name)
  72. if bill.other_money_order:
  73. other_money_order = bill.other_money_order
  74. bill.other_money_order = False
  75. if other_money_order.state == 'done':
  76. other_money_order.other_money_draft()
  77. other_money_order.unlink()
  78. if bill.money_invoice:
  79. money_invoice = bill.money_invoice
  80. bill.money_invoice = False
  81. if money_invoice.state == 'done':
  82. money_invoice.money_invoice_draft()
  83. money_invoice.unlink()
  84. bill.state = 'draft'
  85. def to_money_invoice(self):
  86. for bill in self:
  87. tax = 0
  88. bill_number = ''
  89. for line in bill.line_ids:
  90. if line.invoice_type == 'zy':
  91. tax += line.invoice_tax
  92. if line.invoice_name:
  93. bill_number = '%s, %s' % (line.invoice_name, bill_number)
  94. money_invoice = bill.env['money.invoice'].create({
  95. 'name': bill.name,
  96. 'partner_id': bill.partner_id.id,
  97. 'category_id': bill.line_ids and bill.line_ids[0].category_id.id or False,
  98. 'date': bill.date,
  99. 'amount': bill.invoice_all_total,
  100. 'reconciled': 0,
  101. 'to_reconcile': bill.invoice_all_total,
  102. 'date_due': fields.Date.context_today(bill),
  103. 'state': 'draft',
  104. 'tax_amount': tax,
  105. 'bill_number': bill_number,
  106. })
  107. bill.write({'money_invoice': money_invoice.id})
  108. def to_other_money_order(self):
  109. for bill in self:
  110. other_money_order = bill.with_context(type='other_pay').env['other.money.order'].create({
  111. 'state': 'draft',
  112. 'partner_id': bill.partner_id and bill.partner_id.id or False,
  113. 'date': bill.date,
  114. 'bank_id': bill.bank_account_id.id,
  115. })
  116. bill.write({'other_money_order': other_money_order.id})
  117. for line in bill.line_ids:
  118. if line.invoice_type != 'zy':
  119. invoice_tax = 0
  120. invoice_amount = line.invoice_amount + line.invoice_tax
  121. else:
  122. invoice_tax = line.invoice_tax
  123. invoice_amount = line.invoice_amount
  124. bill.env['other.money.order.line'].create({
  125. 'other_money_id': other_money_order.id,
  126. 'amount': invoice_amount,
  127. 'tax_rate': round(line.invoice_amount and invoice_tax / line.invoice_amount * 100, 0) or 0,
  128. 'tax_amount': invoice_tax,
  129. 'category_id': line.category_id and line.category_id.id or False,
  130. })
  131. class HrExpenseLine(models.Model):
  132. _name = 'hr.expense.line'
  133. _inherit = ['mail.thread']
  134. _description = '报销行'
  135. _order = 'date'
  136. name = fields.Char('单据编号', index=True, copy=False, help='报销单的唯一编号')
  137. staff = fields.Many2one('staff', required=True, string='报销员工', help='用关键字段查找并关联类别')
  138. invoice_type = fields.Selection([('pt', '增值税普通发票'), ('zy', '增值税专用发票'), ('dz', '电子普通发票')], '发票类别')
  139. invoice_code = fields.Char('发票代码', copy=False)
  140. invoice_name = fields.Char('发票号码', copy=False)
  141. invoice_amount = fields.Float(string='发票金额', digits='Amount', required=True, help='如是增值税发票请填不含税金额')
  142. invoice_tax = fields.Float(string='发票税额', digits='Amount', help='如是增值税发票请填不含税金额')
  143. invoice_total = fields.Float(string='发票金额合计', store=True, readonly=True, compute='_compute_cost_total', digits='Amount')
  144. invoice_heck_code = fields.Char('发票校验码', copy=False)
  145. invoice_date = fields.Char('发票日期', copy=False)
  146. note = fields.Text('备注')
  147. state = fields.Selection([('draft', '草稿'), ('confirm', '已提交')], '状态', default='draft', tracking=True, copy=False)
  148. category_id = fields.Many2one('core.category', '类别', ondelete='restrict', required=True, help='类型:运费、咨询费等')
  149. date = fields.Date(string='费用日期', default=fields.Date.context_today, copy=False, required=True, help='费用发生日期')
  150. order_id = fields.Many2one('hr.expense', '报销单号', index=True, copy=False, readonly=True)
  151. is_refused = fields.Boolean(string='已被使用', store=True, compute='_compute_is_choose', readonly=True, copy=False)
  152. is_pay = fields.Boolean(string='已付款', store=True, compute='_compute_is_pay', readonly=True, copy=False)
  153. _sql_constraints = [('unique_invoice_code_name', 'unique (invoice_code, invoice_name)', '发票代码+发票号码不能相同!')]
  154. attachment_number = fields.Integer(compute='_compute_attachment_number', string='附件号')
  155. def hr_expense_line_confirm(self):
  156. for bill in self:
  157. if bill.state == 'confirm':
  158. raise UserError('请不要重复确认')
  159. bill.state = 'confirm'
  160. def hr_expense_line_draft(self):
  161. for bill in self:
  162. if bill.state == 'draft':
  163. raise UserError('请不要重复撤销 %s' % bill.name)
  164. if bill.state == 'confirm' and not bill.order_id:
  165. bill.state = 'draft'
  166. bill.is_refused = False
  167. else:
  168. raise UserError('请先解除关联单据%s' % bill.order_id.name)
  169. @api.depends('invoice_amount', 'invoice_tax')
  170. def _compute_cost_total(self):
  171. for bill in self:
  172. bill.invoice_total = bill.invoice_amount + bill.invoice_tax
  173. @api.depends('order_id')
  174. def _compute_is_choose(self):
  175. for bill in self:
  176. if bill.order_id:
  177. bill.is_refused = True
  178. else:
  179. bill.is_refused = False
  180. @api.model
  181. def saomiaofapiao(self, model_name, barcode, order_id):
  182. barcode = barcode.replace(',', ',').replace('。', '.')
  183. code = barcode.split(',')
  184. invoice_heck_code = ''
  185. if len(code) < 5:
  186. raise UserError('请确认扫描是否正确%s' % code)
  187. if code[0] == '01':
  188. if code[1] == '10':
  189. invoice_type = 'dz'
  190. invoice_heck_code = code[6]
  191. if code[1] == '01':
  192. invoice_type = 'zy'
  193. if code[1] == '04':
  194. invoice_type = 'pt'
  195. invoice_heck_code = code[6]
  196. invoice_code = code[2]
  197. invoice_name = code[3]
  198. invoice_amount = round(float(code[4]), 2)
  199. invoice_date = code[5]
  200. invoice_tax = 0
  201. self.browse(order_id).write({
  202. 'invoice_type': invoice_type, 'invoice_code': invoice_code, 'invoice_name': invoice_name,
  203. 'invoice_amount': invoice_amount, 'invoice_tax': invoice_tax,
  204. 'invoice_heck_code': invoice_heck_code, 'invoice_date': invoice_date,
  205. })
  206. def action_get_attachment_view(self):
  207. res = self.env.ref('base.action_attachment')
  208. res['domain'] = [('res_model', '=', 'hr.expense.line'), ('res_id', 'in', self.ids)]
  209. res['context'] = {'default_res_model': 'hr.expense.line', 'default_res_id': self.id}
  210. return res
  211. def _compute_attachment_number(self):
  212. attachment_data = self.env['ir.attachment'].read_group(
  213. [('res_model', '=', 'hr.expense.line'), ('res_id', 'in', self.ids)], ['res_id'], ['res_id'])
  214. attachment = dict((data['res_id'], data['res_id_count']) for data in attachment_data)
  215. for bill in self:
  216. bill.attachment_number = attachment.get(bill.id, 0)
  217. def unlink(self):
  218. for bill in self:
  219. if bill.state != 'draft':
  220. raise UserError('只能删除草稿状态的费用发票')
  221. super().unlink()
  222. @api.depends('order_id.state')
  223. def _compute_is_pay(self):
  224. for bill in self:
  225. if bill.order_id and bill.order_id.state == 'done':
  226. bill.is_pay = True
  227. else:
  228. bill.is_pay = False
上海开阖软件有限公司 沪ICP备12045867号-1