# -*- coding: utf-8 -*- from odoo import models, api, fields, _ from odoo.exceptions import ValidationError, UserError import base64 import time import logging from datetime import date, datetime from dateutil.relativedelta import relativedelta from .account_esignature_certificate import convert_key_cer_to_pem from .portal_sat import PortalSAT _logger = logging.getLogger(__name__) TRY_COUNT = 3 # INTENTOS DE CONEXION class ResCompany(models.Model): _inherit = 'res.company' x_esignature_ids = fields.Many2many(comodel_name='account.esignature.certificate', string='Certificado FIEL') x_last_cfdi_fetch_date = fields.Datetime("Última sincronización") x_only_supplier_cfdi = fields.Boolean("Solo documentos de proveedor") @api.model def auto_import_cfdi_invoices(self): for company in self.search([('x_esignature_ids', '!=', False)]): company.with_company(company.id).download_cfdi_invoices_sat() return True # =================================================PORTAL SAT=========================================================== # DESCARGAR LOS XML DESDE EL SAT def download_cfdi_invoices_sat(self, start_date=False, end_Date=False, document_type=False): esignature_ids = self.x_esignature_ids esignature = esignature_ids.with_user(self.env.user).get_valid_certificate() if not esignature: raise ValidationError("No se encontraron certificados validos, favor de revisar.") if not esignature.content or not esignature.key or not esignature.password: raise ValidationError("Seleccine los archivos FIEL .cer o FIEL .pem.") fiel_cert_data = base64.b64decode(esignature.content) fiel_pem_data = convert_key_cer_to_pem(esignature.key, esignature.password) opt = {'credenciales': None, 'rfc': None, 'uuid': None, 'ano': None, 'mes': None, 'dia': 0, 'intervalo_dias': None, 'fecha_inicial': None, 'fecha_final': None, 'tipo': 't', 'tipo_complemento': '-1', 'rfc_emisor': None, 'rfc_receptor': None, 'sin_descargar': False, 'base_datos': False, 'directorio_fiel': '', 'archivo_uuids': '', 'estatus': False} today = datetime.utcnow() if start_date and end_Date: opt['fecha_inicial'] = datetime.combine(start_date, datetime.min.time()) opt['fecha_final'] = datetime.combine(end_Date, datetime.max.time()) elif self.x_last_cfdi_fetch_date: last_import_date = self.x_last_cfdi_fetch_date last_import_date - relativedelta(days=2) fecha_inicial = last_import_date - relativedelta(days=2) fecha_final = today + relativedelta(days=2) opt['fecha_inicial'] = fecha_inicial opt['fecha_final'] = fecha_final else: year = today.year month = today.month opt['ano'] = year opt['mes'] = month sat = False for i in range(TRY_COUNT): sat = PortalSAT(opt['rfc'], 'cfdi-descarga', False) if sat.login_fiel(fiel_cert_data, fiel_pem_data, esignature, self.env.company): time.sleep(1) break invoice_content_receptor, invoice_content_emisor = {}, {} if sat and sat.is_connect: if document_type == "supplier": invoice_content_receptor, invoice_content_emisor = sat.search(opt, 'supplier') elif document_type == "customer": invoice_content_receptor, invoice_content_emisor = sat.search(opt, 'customer') else: invoice_content_receptor, invoice_content_emisor = sat.search(opt) sat.logout() elif sat: sat.logout() attachment_data = [] if invoice_content_receptor: attachment_data += self.get_cfdi_data(invoice_content_receptor, attachment_data) if invoice_content_emisor: attachment_data += self.get_cfdi_data(invoice_content_emisor, attachment_data) if attachment_data: cfdi_ids = self.env['account.cfdi'].create_cfdis(attachment_data=attachment_data) if cfdi_ids: self.write({'x_last_cfdi_fetch_date': date.today()}) return { "name": _("CFDIs importados"), "view_mode": "list,form", "res_model": "account.cfdi", "type": "ir.actions.act_window", "target": "current", "domain": [("id", "in", cfdi_ids.ids)] } else: return { 'type': 'ir.actions.client', 'tag': 'display_notification', 'params': { 'title': _( "No se cargaron nuevos CFDIs al sistema ya que estos ya existen o no se encontraron, favor de validar."), 'type': 'warning', 'sticky': True, }, } else: return { 'type': 'ir.actions.client', 'tag': 'display_notification', 'params': { 'title': _( "No se encontraron CFDIs que coincidan con las fechas o estos ya se encuentran en el sistema, favor de validar."), 'type': 'warning', 'sticky': True, }, } # ====================================================================================================================== def get_cfdi_data(self, content_sat, attachment_data): uuids = list(content_sat.keys()) cfdi_ids = self.env["account.cfdi"].sudo().search([('uuid', 'in', uuids)]) exist_uuids = cfdi_ids.mapped('uuid') for uuid, data in content_sat.items(): if uuid in exist_uuids: continue xml_content = data[1] pdf_content = data[2] filename = uuid + ".xml" filepdf = uuid + ".pdf" data = dict( name=filename, store_fname=filename, type='binary', datas=base64.b64encode(xml_content), company_id=self.id, mimetype='application/xml' ) data_pdf = dict( name=filepdf, store_fname=filepdf, type='binary', datas=base64.b64encode(pdf_content) if pdf_content else False, company_id=self.id, mimetype='application/pdf' ) data_uuid = { "xml": data, "pdf": data_pdf } attachment_data.append(data_uuid) return attachment_data