Skip to content

Instantly share code, notes, and snippets.

@gigidn
Created May 9, 2020 13:41
Show Gist options
  • Save gigidn/c4d1ded1410981f0b7d102dfb44cbad8 to your computer and use it in GitHub Desktop.
Save gigidn/c4d1ded1410981f0b7d102dfb44cbad8 to your computer and use it in GitHub Desktop.
class OdooFatturaElettronica(models.Model):
_inherit = 'account.invoice'
state = fields.Selection(selection_add=[
('waiting', 'Waiting'),
('send_sdi', 'Send SDI'),
])
electronic_invoice_state = fields.Selection([
('0', 'Non Elaborata'),
('1', 'Presa in carico',),
('2', 'Errore Elaborazione'),
('3', 'Inviata'),
('4', 'Scartata'),
('5', 'Non Consegnata'),
('6', 'Recapito Impossibile'),
('7', 'Consegnata'),
('8', 'Accettata'),
('9', 'Rifiutata'),
('10', 'Decorrenza Termini')
],string='e-Invoice Status', index=True, readonly=True, default='0',
track_visibility='onchange', copy=False,
help = " 1 - Presa in carico: La fattura è in attesa di essere elaborata dai sistemi di Teuron/Aruba e " \
"non risulta ancora trasmessa a SDI.\n " \
" 2 - Errore Elaborazione: Si è verificato un errore nell’elaborazione della fattura " \
"(Problema tecnico nell'invio allo SDI).\n " \
" 3 - Inviata: La fattura è stata inviata al Sistema di Interscambio(SDI).\n " \
" 4 - Scartata: [NS] La fattura è stata rifiutata dal Sistema di Interscambio(SDI) " \
"che ha restituito un codice di errore specifico.\n" \
" 5 - Non Consegnata: [MC] La consegna della fattura da parte del " \
"Sistema di Interscambio(SDI) è fallita. Solo per le PA, verranno fatti " \
"ulteriori tentativi di consegna nei 10 giorni seguenti.\n " \
" 6 - Recapito Impossibile: [AT] La consegna della fattura da parte del " \
"Sistema di Intercambio(SDI) non è andata a buon fine. " \
"Non verranno effettuati ulteriori tentativi di consegna.\n" \
" 7 - Consegnata: [RC] La fattura è stata consegnata da parte del Sistema di Interscambio(SDI).\n" \
" 8 - Accettata: [NE(EC01)] Il cliente ha accettato la fattura consegnata " \
"dal Sistema di Interscambio(SDI).\n" \
" 9 - Rifiutata: [NE(EC02)] Il cliente ha rifiutato la fattura consegnata " \
"dal Sistema di Interscambio(SDI).\n" \
" 10 - Decorrenza Termini: [DT] La fattura è stata consegnata da parte del " \
"sistema di Interscambio(SDI) ma il cliente non ha inoltrato alcuna risposta " \
"nei 15 successivi alla consegna.\n" \
" 0 - La fattura non è ancora stata inviata."
)
doc_count = fields.Integer(compute='_compute_attached_docs_count',
string="Number of documents attached")
message_count = fields.Integer(compute='_compute_message_count',
string="Number of elettronic invoice message")
is_elettronic_invoice = fields.Boolean(compute='_compute_fe_nature', readonly=True)
@api.multi
def _compute_message_state(self):
StatiMsg ={'0': 'Non Elaborata',
'1': 'Presa in carico',
'2': 'Errore Elaborazione',
'3': 'Inviata',
'4': 'Scartata',
'5': 'Non Consegnata',
'6': 'Recapito Impossibile',
'7': 'Consegnata',
'8': 'Accettata',
'9': 'Rifiutata',
'10': 'Decorrenza Termini' }
for invoice in self:
messages_ids = self.env['fe.message'].search([
('res_id', '=', invoice.id)
])
last_messages= messages_ids and max(messages_ids)
if str(last_messages.state):
if str(last_messages.state) in StatiMsg.keys():
invoice.electronic_invoice_state = StatiMsg[str(last_messages.state)]
# timestamp = last_messages.create_date
# date_time = datetime.fromtimestamp(timestamp)
# data = datetime.fromtimestamp(timestamp)
if type(last_messages.date_receipt) is fields.datetime:
invoice.datereceipt=last_messages.create_date.strftime('%Y-%m-%d %H:%M:%S')
datereceipt = fields.Datetime(compute='_compute_message_state', store=True, track_visibility='onchange',
string="Date of Message of elettronic invoice")
related_documents = fields.One2many(
'fatturaelettronica.related_document', 'invoice_id',
'Related Documents', copy=False
)
# other_management_data = fields.One2many(
# 'account.invoice.line', 'id', 'test'
# #'Other Management Data'#, copy=False
#)
stamp_amount = fields.Monetary('Digital Stamp')
autoinvoice = fields.Boolean('Autoinvoice')
@api.multi
def _check_duplicate_supplier_reference(self):
for invoice in self:
# refuse to validate a vendor bill/credit note if there already exists one with the same reference for the same partner,
# because it's probably a double encoding of the same bill/credit note
if invoice.type in ('in_invoice', 'in_refund') and invoice.reference:
if self.search([('type', '=', invoice.type), ('reference', '=', invoice.reference), ('company_id', '=', invoice.company_id.id),
('commercial_partner_id', '=', invoice.commercial_partner_id.id), ('id', '!=', invoice.id)]).filtered(lambda r: r.date_invoice.year == invoice.date_invoice.year):
# if self.search([('type', '=', invoice.type), ('reference', '=', invoice.reference), ('company_id', '=', invoice.company_id.id), ('commercial_partner_id', '=', invoice.commercial_partner_id.id), ('id', '!=', invoice.id)]):
raise UserError(_("Duplicated vendor reference detected. You probably encoded twice the same vendor bill/credit note."))
def _check_exist_xml(self,inv_id):
messages = self.env['fe.message'].search(
[('res_model', '=', 'account.invoice'),
('res_id', '=', inv_id),
('is_part', '=', False),
('state', '=', '0')
]
)
for message in messages:
message.ir_attachment_id.unlink()
@api.multi
def action_invoice_open(self):
#self.ensure_one()
# if self:
#self.ensure_one()
for invoice in self:
messages_ids = self.env['fe.message'].search([
('res_id', '=', invoice.id)
])
for msg in messages_ids:
if msg.fe_version == 'FSM10':
if invoice.amount_total <= 0:
raise UserError(_("E' possibile confermare solo fatture positive"))
if invoice.is_elettronic_invoice:
self._check_exist_xml(invoice.id)
return super(OdooFatturaElettronica, self).action_invoice_open()
#Metodi per gestire il workflow ed i passaggi di stato della fattura
@api.multi
def sign_invoice(self):
"""
Questo metodo ha il solo scopo di essere esteso ma moduli
specilizzati che ne gestiscono il comportamento.
L'implementazione base imposta lo stato della fattura come firmata
ma non esegue nessuna firma reale sul file.
Lo stato della fattura elettronica passa ad 1 . presa in carico.
:return:
"""
for invoice in self:
if invoice.state != 'open':
raise UserError(_("E' possibile firmare solo fatture validate"))
self.write({
'electronic_invoice_state': '0'
})
@api.multi
def waiting(self):
"""
Segna la fattura come attesa invio al sistema di interscambio (SDI)
e ne blocca ogni azione su di esse in attesa di conferma.
:return:
"""
self.write({
'state': 'waiting',
'electronic_invoice_state': '0'
})
@api.multi
def force_open(self):
"""
Metodo tecnico, da user con funzioni di amministrazione per riportare
la fattura nello stato aperto in caso di errori sulla sincronia
degli stati
:return:
"""
self.write({
'state': 'open',
'electronic_invoice_state': '2'
})
@api.multi
def send_sdi(self):
"""
Segna la fattura come inviata al sistema di interscambio (SDI)
e ne blocca ogni azione su di esse in attesa di conferma.
Se le fatture si trovano nello stato bozza vengono validate.
:return:
"""
for inv in self:
try:
if inv.state == 'draft':
inv.action_invoice_open()
elif inv.state in ('paid', 'open'):
if inv.state == 'paid':
self.env['account.move.line'].search([
('invoice_id', '=', inv.id)
]).remove_move_reconcile()
date = inv.date
inv.action_cancel()
inv.action_invoice_draft()
inv.write({
'electronic_invoice_state': '0',
'state': 'draft',
'date': date
})
self._check_exist_xml(inv.id)
inv.action_invoice_open()
femessage = self.env['fe.message'].search([
('res_id','=',inv.id),
('res_model','=','account.invoice'),
('state','=','0')
])
femessage.send_sdi()
inv.write({
'state': 'send_sdi',
'electronic_invoice_state': femessage.state
})
except Exception as ex:
raise UserError('***GENERIC ERROR ON:' + '\n' + str(ex))
def error_process(self, err_msg=None):
"""
Il sistema di interscambio ha rifiutato la fattura.
:return:
"""
for inv in self:
inv.action_cancel()
inv.action_invoice_draft()
inv.write({
'electronic_invoice_state': '2'
})
inv.message_post(
subject=_("Error Processing"),
body=_("HUB error sending invoice: %s "
) % err_msg
)
def reject_sdi(self, datarec=None):
"""
Il sistema di interscambio ha rifiutato la fattura.
:return:
"""
for inv in self:
date = inv.date
inv.action_cancel()
inv.action_invoice_draft()
if datarec:
inv.write({
'electronic_invoice_state': '4',
'date' : date,
'datereceipt': datarec
})
else:
inv.write({
'electronic_invoice_state': '4'
})
def delivery_sdi(self, datarec=None):
"""
Il sistema di interscambio ha correttamente inviato la fattura
al cliente.
:return:
"""
if datarec:
self.write({
'state': 'open',
'electronic_invoice_state': '7',
'datereceipt': datarec
})
else:
self.write({
'state': 'open',
'electronic_invoice_state': '7'
})
def delivery_sdi_fail(self, datarec=None):
"""
Il sistema di interscambio non è riuscito ad inviare la fattura
al cliente. La fattura si considera emessa ma bisogna informare
il cliente in altro modo.
:return:
"""
if datarec:
self.write({
'state': 'open',
'electronic_invoice_state': '6',
'datereceipt': datarec
})
else:
self.write({
'state': 'open',
'electronic_invoice_state': '6'
})
# self.write({
# 'state': 'open',
# 'electronic_invoice_state': '6'
# })
def sdi_unable_to_delivery(self, datarec=None):
vals = {
'state': 'open',
'electronic_invoice_state': '5',
}
if datarec:
vals['datereceipt'] = datarec
self.write(vals)
def accept_from_client(self, datarec=None):
"""
Il cliente ha accettato la fattura, lo stato della fattura elettronica
passa a 8 - Accettata: [NE(EC01)]. Si ha a disposizione la notifica esito
che andrebbe allegata al file della comunicazione.
:return:
"""
if datarec:
self.write({
'state': 'open',
'electronic_invoice_state': '8',
'datereceipt': datarec
})
else:
self.write({
'electronic_invoice_state': '8'
})
def maxtime_reached(self, datarec=None):
"""
Il cliente ha accettato la fattura, lo stato della fattura elettronica
passa a 8 - Accettata: [NE(EC01)]. Si ha a disposizione la notifica esito
che andrebbe allegata al file della comunicazione.
:return:
"""
if datarec:
self.write({
'state': 'open',
'electronic_invoice_state': '10',
'datereceipt': datarec
})
else:
self.write({
'electronic_invoice_state': '10'
})
def reject_from_client(self, datarec=None):
"""
Il cliente ha rifiutato la fattura. Solo per le fatture emesse verso una PA
il sistema di interscambio restituisce NE
Stato fattura elettronica: 9 - Rifiutata: [NE(EC02)].
La fattura viene riportata in bozza.
:return:
"""
for inv in self:
inv.action_cancel()
inv.action_invoice_draft()
if datarec:
inv.write({
'electronic_invoice_state': '9',
'datereceipt': datarec
})
else:
inv.write({
'electronic_invoice_state': '9'
})
@api.multi
def get_receivable_payable_line(self):
# return the move line receivable or payable
self.ensure_one()
return self.sudo().move_id.line_ids.filtered(
lambda r: r.account_id.internal_type in ('receivable', 'payable'))
def pre_validate(self):
raise Warning(
_("Funzione non ancora implementata "))
def _get_vat(self,tax_ids):
tax_ids = [tax_id for tax_id in tax_ids if tax_id.is_vat]
if len(tax_ids) != 1:
raise ValidationError(
_('One and only one VAT for line are allowed'))
return tax_ids[0]
def _compute_attached_docs_count(self):
attachment = self.env['ir.attachment']
for invoice in self:
invoice.doc_count = attachment.search_count([
'&',
('res_model', '=', 'account.invoice'),
('res_id', '=', invoice.id)
])
def _compute_message_count(self):
message = self.env['fe.message']
for invoice in self:
invoice.message_count = message.search_count([
'&',
('res_model', '=', 'account.invoice'),
('res_id', '=', invoice.id)
])
def _compute_message_state(self):
StatiMsg ={'0': 'Non Elaborata',
'1': 'Presa in carico',
'2': 'Errore Elaborazione',
'3': 'Inviata',
'4': 'Scartata',
'5': 'Non Consegnata',
'6': 'Recapito Impossibile',
'7': 'Consegnata',
'8': 'Accettata',
'9': 'Rifiutata',
'10': 'Decorrenza Termini' }
for invoice in self:
messages_ids = self.env['fe.message'].search([
('res_id', '=', invoice.id)
])
last_messages= messages_ids and max(messages_ids)
if str(last_messages.state):
if str(last_messages.state) in StatiMsg.keys():
invoice.messagestate = StatiMsg[str(last_messages.state)]
# timestamp = last_messages.create_date
# date_time = datetime.fromtimestamp(timestamp)
# data = datetime.fromtimestamp(timestamp)
if type(last_messages.create_date) is fields.datetime:
invoice.date_create=last_messages.create_date.strftime('%Y-%m-%d %H:%M:%S')
def _compute_fe_nature(self):
for invoice in self:
if (invoice.partner_id and invoice.partner_id.electronic_invoice_subjected) or invoice.autoinvoice:
invoice.is_elettronic_invoice = True
@api.multi
def invoice_validate(self):
result = super(OdooFatturaElettronica, self).invoice_validate()
for invoice in self:
if invoice.is_elettronic_invoice and \
(invoice.type == 'out_invoice' or invoice.type == 'out_refund' or invoice.autoinvoice):
num_line = 0
for line in invoice.invoice_line_ids:
num_line += 1
line.sequence = num_line
line.xml_line_id = num_line
try:
invoice.crea_fattura_elettronica()
except (
SimpleFacetValueError,
SimpleTypeValueError,
pyxb.ValidationError
) as ve:
raise UserError(ve.details())
invoice.waiting()
return result
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment