res_company.py 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159
  1. # -*- coding: utf-8 -*-
  2. from odoo import models, api, fields, _
  3. from odoo.exceptions import ValidationError, UserError
  4. import base64
  5. import time
  6. import logging
  7. from datetime import date, datetime
  8. from dateutil.relativedelta import relativedelta
  9. from .account_esignature_certificate import convert_key_cer_to_pem
  10. from .portal_sat import PortalSAT
  11. _logger = logging.getLogger(__name__)
  12. TRY_COUNT = 3 # INTENTOS DE CONEXION
  13. class ResCompany(models.Model):
  14. _inherit = 'res.company'
  15. x_esignature_ids = fields.Many2many(comodel_name='account.esignature.certificate', string='Certificado FIEL')
  16. x_last_cfdi_fetch_date = fields.Datetime("Última sincronización")
  17. x_only_supplier_cfdi = fields.Boolean("Solo documentos de proveedor")
  18. @api.model
  19. def auto_import_cfdi_invoices(self):
  20. for company in self.search([('x_esignature_ids', '!=', False)]):
  21. company.with_company(company.id).download_cfdi_invoices_sat()
  22. return True
  23. # =================================================PORTAL SAT===========================================================
  24. # DESCARGAR LOS XML DESDE EL SAT
  25. def download_cfdi_invoices_sat(self, start_date=False, end_Date=False, document_type=False):
  26. esignature_ids = self.x_esignature_ids
  27. esignature = esignature_ids.with_user(self.env.user).get_valid_certificate()
  28. if not esignature:
  29. raise ValidationError("No se encontraron certificados validos, favor de revisar.")
  30. if not esignature.content or not esignature.key or not esignature.password:
  31. raise ValidationError("Seleccine los archivos FIEL .cer o FIEL .pem.")
  32. fiel_cert_data = base64.b64decode(esignature.content)
  33. fiel_pem_data = convert_key_cer_to_pem(esignature.key, esignature.password)
  34. opt = {'credenciales': None, 'rfc': None, 'uuid': None, 'ano': None, 'mes': None, 'dia': 0,
  35. 'intervalo_dias': None, 'fecha_inicial': None, 'fecha_final': None, 'tipo': 't',
  36. 'tipo_complemento': '-1', 'rfc_emisor': None, 'rfc_receptor': None, 'sin_descargar': False,
  37. 'base_datos': False, 'directorio_fiel': '', 'archivo_uuids': '', 'estatus': False}
  38. today = datetime.utcnow()
  39. if start_date and end_Date:
  40. opt['fecha_inicial'] = datetime.combine(start_date, datetime.min.time())
  41. opt['fecha_final'] = datetime.combine(end_Date, datetime.max.time())
  42. elif self.x_last_cfdi_fetch_date:
  43. last_import_date = self.x_last_cfdi_fetch_date
  44. last_import_date - relativedelta(days=2)
  45. fecha_inicial = last_import_date - relativedelta(days=2)
  46. fecha_final = today + relativedelta(days=2)
  47. opt['fecha_inicial'] = fecha_inicial
  48. opt['fecha_final'] = fecha_final
  49. else:
  50. year = today.year
  51. month = today.month
  52. opt['ano'] = year
  53. opt['mes'] = month
  54. sat = False
  55. for i in range(TRY_COUNT):
  56. sat = PortalSAT(opt['rfc'], 'cfdi-descarga', False)
  57. if sat.login_fiel(fiel_cert_data, fiel_pem_data, esignature, self.env.company):
  58. time.sleep(1)
  59. break
  60. invoice_content_receptor, invoice_content_emisor = {}, {}
  61. if sat and sat.is_connect:
  62. if document_type == "supplier":
  63. invoice_content_receptor, invoice_content_emisor = sat.search(opt, 'supplier')
  64. elif document_type == "customer":
  65. invoice_content_receptor, invoice_content_emisor = sat.search(opt, 'customer')
  66. else:
  67. invoice_content_receptor, invoice_content_emisor = sat.search(opt)
  68. sat.logout()
  69. elif sat:
  70. sat.logout()
  71. attachment_data = []
  72. if invoice_content_receptor:
  73. attachment_data += self.get_cfdi_data(invoice_content_receptor, attachment_data)
  74. if invoice_content_emisor:
  75. attachment_data += self.get_cfdi_data(invoice_content_emisor, attachment_data)
  76. if attachment_data:
  77. cfdi_ids = self.env['account.cfdi'].create_cfdis(attachment_data=attachment_data)
  78. if cfdi_ids:
  79. self.write({'x_last_cfdi_fetch_date': date.today()})
  80. return {
  81. "name": _("CFDIs importados"),
  82. "view_mode": "list,form",
  83. "res_model": "account.cfdi",
  84. "type": "ir.actions.act_window",
  85. "target": "current",
  86. "domain": [("id", "in", cfdi_ids.ids)]
  87. }
  88. else:
  89. return {
  90. 'type': 'ir.actions.client',
  91. 'tag': 'display_notification',
  92. 'params': {
  93. 'title': _(
  94. "No se cargaron nuevos CFDIs al sistema ya que estos ya existen o no se encontraron, favor de validar."),
  95. 'type': 'warning',
  96. 'sticky': True,
  97. },
  98. }
  99. else:
  100. return {
  101. 'type': 'ir.actions.client',
  102. 'tag': 'display_notification',
  103. 'params': {
  104. 'title': _(
  105. "No se encontraron CFDIs que coincidan con las fechas o estos ya se encuentran en el sistema, favor de validar."),
  106. 'type': 'warning',
  107. 'sticky': True,
  108. },
  109. }
  110. # ======================================================================================================================
  111. def get_cfdi_data(self, content_sat, attachment_data):
  112. uuids = list(content_sat.keys())
  113. cfdi_ids = self.env["account.cfdi"].sudo().search([('uuid', 'in', uuids)])
  114. exist_uuids = cfdi_ids.mapped('uuid')
  115. for uuid, data in content_sat.items():
  116. if uuid in exist_uuids:
  117. continue
  118. xml_content = data[1]
  119. pdf_content = data[2]
  120. filename = uuid + ".xml"
  121. filepdf = uuid + ".pdf"
  122. data = dict(
  123. name=filename,
  124. store_fname=filename,
  125. type='binary',
  126. datas=base64.b64encode(xml_content),
  127. company_id=self.id,
  128. mimetype='application/xml'
  129. )
  130. data_pdf = dict(
  131. name=filepdf,
  132. store_fname=filepdf,
  133. type='binary',
  134. datas=base64.b64encode(pdf_content) if pdf_content else False,
  135. company_id=self.id,
  136. mimetype='application/pdf'
  137. )
  138. data_uuid = {
  139. "xml": data,
  140. "pdf": data_pdf
  141. }
  142. attachment_data.append(data_uuid)
  143. return attachment_data