116 lines
4.8 KiB
Python
116 lines
4.8 KiB
Python
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
|
|
|
from collections import defaultdict
|
|
|
|
from odoo import _, api, fields, models
|
|
from odoo.exceptions import UserError
|
|
|
|
|
|
# Invoice template that needs to be passed to Sinvoice and will determine the format of the resulting
|
|
# invoice pdf on their system
|
|
class SInvoiceTemplate(models.Model):
|
|
_name = 'l10n_vn_edi_viettel.sinvoice.template'
|
|
_description = 'SInvoice template'
|
|
|
|
name = fields.Char(
|
|
string='Template Code',
|
|
required=True,
|
|
)
|
|
template_invoice_type = fields.Selection(
|
|
selection=[
|
|
# Circular 32 being deprecated, only display types according to the Circular 78
|
|
('1', '1 - Value-added invoice'),
|
|
('2', '2 - Sales invoice'),
|
|
('3', '3 - Public assets sales'),
|
|
('4', '4 - National reserve sales'),
|
|
('5', '5 - Invoice for national reserve sales'),
|
|
('6', '6 - Warehouse release note'),
|
|
],
|
|
required=True,
|
|
)
|
|
invoice_symbols_ids = fields.One2many(
|
|
comodel_name='l10n_vn_edi_viettel.sinvoice.symbol',
|
|
inverse_name='invoice_template_id',
|
|
)
|
|
|
|
_sql_constraints = [
|
|
('name_uniq', 'unique (name)', 'The template code must be unique!')
|
|
]
|
|
|
|
@api.constrains('name', 'template_invoice_type')
|
|
def _constrains_changes(self):
|
|
"""
|
|
Multiple API endpoints will use these data, we should thus not allow changing them if they have been used
|
|
for any invoices sent to sinvoice.
|
|
"""
|
|
# The conditions are the same. If any symbols of the template are being used, we shouldn't allow editing it.
|
|
self.invoice_symbols_ids._constrains_changes()
|
|
|
|
|
|
# Invoice symbol that needs to be passed to Sinvoice and will determine the prefix of the
|
|
# invoice number on their system
|
|
class SInvoiceSymbol(models.Model):
|
|
_name = 'l10n_vn_edi_viettel.sinvoice.symbol'
|
|
_description = 'SInvoice symbol'
|
|
"""
|
|
The invoice symbols are made of multiple parts.
|
|
The symbols characters have meanings that will influence the resulting invoices:
|
|
|
|
The first character is either C (invoice with code from tax department) or K (without)
|
|
It is then followed by two number which represent the current year (24 in 2024)
|
|
Next, a single character representing additional invoice information:
|
|
|
|
T: E-invoices registered with tax authorities by enterprises, organizations or household businesses;
|
|
D: E-invoices used for sale of public property or national reserve goods or special e-invoices that do not have some mandatory contents of the “T” invoices;
|
|
L: E-invoices issued separately by tax authorities;
|
|
M: E-invoices generated by cash registers;
|
|
N: Electronic delivery and internal consignment notes;
|
|
B: Electronic delivery notes for goods sent to sales agents;
|
|
G: VAT invoices in the form of electronic stamps, tickets or cards;
|
|
H: Sales invoices in the form of electronic stamps, tickets or cards.
|
|
|
|
Finally, it ends with two characters that shall be decided by the seller for their management requirements.
|
|
"""
|
|
|
|
name = fields.Char(
|
|
string='Symbol',
|
|
required=True,
|
|
)
|
|
invoice_template_id = fields.Many2one(
|
|
comodel_name='l10n_vn_edi_viettel.sinvoice.template',
|
|
required=True,
|
|
)
|
|
|
|
_sql_constraints = [
|
|
('name_template_uniq', 'unique (name, invoice_template_id)', 'The combination symbol/template must be unique!')
|
|
]
|
|
|
|
@api.constrains('name', 'invoice_template_id')
|
|
def _constrains_changes(self):
|
|
"""
|
|
Multiple API endpoints will use these data, we should thus not allow changing them if they have been used
|
|
for any invoices sent to sinvoice.
|
|
"""
|
|
invoice_counts = self.env['account.move']._read_group(
|
|
domain=[
|
|
('l10n_vn_edi_invoice_symbol', 'in', self.ids),
|
|
('l10n_vn_edi_invoice_state', 'not in', ('ready_to_send', False)), # Only matches sent invoices.
|
|
],
|
|
groupby=['l10n_vn_edi_invoice_symbol'],
|
|
aggregates=['__count'],
|
|
)
|
|
invoices_per_symbol = defaultdict(int)
|
|
for symbol, count in invoice_counts:
|
|
invoices_per_symbol[symbol.id] = count
|
|
|
|
for record in self:
|
|
if invoices_per_symbol[record.id] > 0:
|
|
raise UserError(_('You cannot change the symbol value or template of the symbol %s because it has '
|
|
'already been used to send invoices.', record.name))
|
|
|
|
@api.depends('name', 'invoice_template_id')
|
|
def _compute_display_name(self):
|
|
""" As we allow multiple of the same symbol name, we need to also display the template to differentiate. """
|
|
for symbol in self:
|
|
symbol.display_name = f'{symbol.name} ({symbol.invoice_template_id.name})'
|