# -*- coding: utf-8 -*- import base64 from psycopg2 import OperationalError from markupsafe import Markup from odoo import _, _lt, models, fields from odoo.exceptions import UserError from odoo.tools import html_escape class AccountMove(models.Model): _inherit = 'account.move' def _l10n_cl_edi_post_validation(self): if self.l10n_latam_document_type_id.code == '39': if self.line_ids.filtered(lambda x: x.tax_group_id.id in [ self.env['account.chart.template'].with_company(self.company_id).ref('tax_group_ila').id, self.env['account.chart.template'].with_company(self.company_id).ref('tax_group_retenciones').id, ]): raise UserError(_('Receipts with withholding taxes are not allowed')) if self.company_id.currency_id != self.currency_id: raise UserError(_('It is not allowed to create receipts in a different currency than CLP')) super()._l10n_cl_edi_post_validation() def _l10n_cl_edi_validate_boletas(self): # Override the method to allow create ticket. return None def l10n_cl_send_dte_to_sii(self, retry_send=True): if not self.l10n_latam_document_type_id._is_doc_type_ticket(): return super().l10n_cl_send_dte_to_sii(retry_send) try: with self.env.cr.savepoint(flush=False): self.env.cr.execute(f'SELECT 1 FROM {self._table} WHERE id IN %s FOR UPDATE NOWAIT', [tuple(self.ids)]) except OperationalError as e: if e.pgcode == '55P03': if not self.env.context.get('cron_skip_connection_errs'): raise UserError(_('This electronic document is being processed already.')) return raise e # To avoid double send on double-click if self.l10n_cl_dte_status != "not_sent": return None digital_signature_sudo = self.company_id.sudo()._get_digital_signature(user_id=self.env.user.id) if self.company_id.l10n_cl_dte_service_provider == 'SIIDEMO': self.message_post(body=_('This DTE has been generated in DEMO Mode. It is considered as accepted and ' 'it won\'t be sent to SII.')) self.l10n_cl_dte_status = 'accepted' return None response = self._send_xml_to_sii_rest( self.company_id.l10n_cl_dte_service_provider, self.company_id.vat, self.l10n_cl_sii_send_file.name, base64.b64decode(self.l10n_cl_sii_send_file.datas), digital_signature_sudo ) if not response: return None self.l10n_cl_sii_send_ident = response.get('trackid') sii_response_status = response.get('estado') self.l10n_cl_dte_status = 'ask_for_status' if sii_response_status == 'REC' else 'rejected' self.message_post(body=_('DTE has been sent to SII with response: %s', self._l10n_cl_get_sii_reception_status_message_rest(sii_response_status))) def l10n_cl_verify_dte_status(self, send_dte_to_partner=True): if not self.l10n_latam_document_type_id._is_doc_type_ticket(): return super().l10n_cl_verify_dte_status(send_dte_to_partner) digital_signature_sudo = self.company_id.sudo()._get_digital_signature(user_id=self.env.user.id) response = self._get_send_status_rest( self.company_id.l10n_cl_dte_service_provider, self.l10n_cl_sii_send_ident, self._l10n_cl_format_vat(self.company_id.vat), digital_signature_sudo) if not response: self.l10n_cl_dte_status = 'ask_for_status' return None self.l10n_cl_dte_status = self._analyze_sii_result_rest(response) message_body = self._l10n_cl_get_verify_status_msg_rest(response) if self.l10n_cl_dte_status in ['accepted', 'objected']: self.l10n_cl_dte_partner_status = 'not_sent' if send_dte_to_partner: self._l10n_cl_send_dte_to_partner() self.message_post(body=message_body) def _l10n_cl_get_verify_status_msg_rest(self, data): msg = _('Asking for DTE status with response:') if self.l10n_cl_dte_status in ['rejected', 'objected']: detail = data['detalle_rep_rech'] if detail: msg += Markup('
  • ESTADO: %s
  • ') % detail[0]['estado'] errors = detail[0].get('error', []) for error in errors: msg += Markup('
  • ERROR: %s %s
  • ') % ( error['descripcion'], error['detalle'] or "") return msg return msg + Markup('
  • ESTADO: %s
  • ') % data['estado'] def _l10n_cl_get_sii_reception_status_message_rest(self, sii_response_status): return { 'REC': _lt('Submission received'), 'EPR': _lt('Submission processed'), 'CRT': _lt('Cover OK'), 'FOK': _lt('Submission signature validated'), 'PRD': _lt('Submission in process'), 'RCH': _lt('Rejected due to information errors'), 'RCO': _lt('Rejected for consistency'), 'VOF': _lt('The .xml file was not found'), 'RFR': _lt('Rejected due to error in signature'), 'RPR': _lt('Accepted with objections'), 'RPT': _lt('Repeat submission rejected'), 'RSC': _lt('Rejected by schema'), 'SOK': _lt('Validated schema'), 'RCT': _lt('Rejected by error in covert'), }.get(sii_response_status, sii_response_status)