# -*- coding: utf-8 -*- from odoo import models, fields, api, _ from odoo.exceptions import ValidationError class AccountTaxInvoice(models.Model): _name = 'account.tax.invoice' _inherit = ['mail.thread', 'mail.activity.mixin'] _description = '税务发票' _rec_name = 'name' name = fields.Char(string='发票编号', default='/') date = fields.Date(string='开票日期', required=True, default=fields.Date.today()) note = fields.Text(string='备注') invoice_type = fields.Selection([ ('normal', '普票'), ('red', '专票'), ('tax', '电子发票'), ], string='发票类型', default='tax', required=True) state = fields.Selection([ ('draft', '草稿'), ('done', '完成'), ('deprecated', '作废'), ], string='状态', default='draft', copy=False, index=True, tracking=True) move_id = fields.Many2one('account.move', string='关联单据', required=True) purchaser_id = fields.Many2one('res.partner', string='购买方', required=True) seller_id = fields.Many2one('res.partner', string='销售方', required=True) purchaser_vat = fields.Char(related='purchaser_id.vat', string='购买方税号', readonly=True, store=True) seller_vat = fields.Char(related='seller_id.vat', string='销售方税号', readonly=True, store=True) company_id = fields.Many2one('res.company', string='公司', default=lambda self: self.env.company) currency_id = fields.Many2one('res.currency', string='币种', default=lambda self: self.env.company.currency_id) line_ids = fields.One2many('account.tax.invoice.line', 'invoice_line_id', string='发票行') # 计算字段 amount = fields.Monetary(string='未税金额', compute='_compute_amount_total', store=True) amount_tax = fields.Monetary(string='税额', compute='_compute_amount_total', store=True) amount_total = fields.Monetary(string='含税总计', compute='_compute_amount_total', store=True) @api.depends('line_ids', 'line_ids.amount', 'line_ids.amount_tax') def _compute_amount_total(self): for rec in self: if rec.line_ids: amount = sum(rec.line_ids.mapped('amount')) amount_tax = sum(rec.line_ids.mapped('amount_tax')) rec.update({ 'amount': amount, 'amount_tax': amount_tax, 'amount_total': amount + amount_tax }) def confirm(self): if set(self.mapped('state')) != {'draft'}: raise ValidationError('非草稿状态无法确认完成开票!') self.write({'state': 'done'}) def deprecated(self): """多实例方法:废弃已完成的税务发票""" if set(self.mapped('state')) != {'done'}: raise ValidationError('无法废弃非已完成状态的发票!') return self.write({'state': 'deprecated'}) def reset_to_draft(self): """多实例方法:重置为草稿""" if set(self.mapped('state')) != {'deprecated'}: raise ValidationError('无法重置非作废状态的发票!') return self.write({'state': 'draft'}) def unlink(self): for rec in self: if rec.state not in ['draft', 'deprecated']: raise ValidationError('非草稿或作废状态的税票无法删除!') return super(AccountTaxInvoice, self).unlink() class AccountTaxInvoiceLine(models.Model): _name = 'account.tax.invoice.line' _description = '税务发票行' # 基础字段 sequence = fields.Integer(string='序列') specification = fields.Char(string='规格') quantity = fields.Float(string='数量', required=True, digits=(16, 4)) price_unit = fields.Float(string='单价', required=True, digits=(16, 4)) # 关系字段 invoice_line_id = fields.Many2one('account.tax.invoice', string='税务发票', required=True, ondelete='cascade') account_id = fields.Many2one('account.account', string='科目', required=True) product_id = fields.Many2one('product.product', string='产品', required=True) uom_id = fields.Many2one('uom.uom', string='单位') tax_id = fields.Many2one('account.tax', string='税率', required=True) # 关联字段 currency_id = fields.Many2one(related='invoice_line_id.currency_id', string='币种') # 计算字段 amount = fields.Monetary(string='金额') amount_tax = fields.Monetary(string='税额') amount_total = fields.Monetary(string='含税小计')