Cancel by rfc of pac

This commit is contained in:
Mauricio Baeza 2021-01-02 22:23:33 -06:00
parent 348a7f6ecb
commit a7945dba58
6 changed files with 71 additions and 16 deletions

View File

@ -1,7 +1,30 @@
v 1.40.0 [20-12-2020]
v 1.40.0 [04-ene-2021]
----------------------
- Error: Al parsear XML en Python 3.9+
- Mejora: Agregar versión de Empresa Libre a plantilla.
- Mejora: Sellado en memoria
- Mejora: Se agrega un segundo PAC y se refactoriza el timbrado.
* **IMPORTANTE**
Es necesario seguir una serie de pasos **obligatorios** para migrar a esta
versión, **no continues hasta seguir paso a paso** estas instrucciones.
**Antes** de comenzar ten a la mano tus certificados de sello para timbrar, es
necesario subirlos de nuevo. **NO actualices si no tienes tus certificados**
con su respectiva contraseña, te quedarás sin poder timbrar.
1. Entra a la parte administrativa y toma de tus credenciales de timbrado en el
menú "Emisor" ficha "Otros Datos", usuario y token de timbrado.
1. Agregar nuevo requerimiento `pip install xmlsec`
1. Actualizar `git pull origin master`
1. Entrar a `app/controllers/pacs` y copiar `conf.py.example` a `conf.py`
1. Reiniciar el servicio: `sudo systemctl restart empresalibre`
1. Sube de nuevo tus certificados en el menú "Emisor" ficha "Certificado".
1. Ve al menú "Opciones", ficha "Otros".
1. Selecciona tu PAC, si tu usuario es un correo electrónico, invariablemente
debes seleccionar Finkok.
1. Establece las credenciales del punto 1.
1. Guarda los datos.
v 1.39.1 [17-sep-2020]

View File

@ -231,7 +231,7 @@ class PACComercioDigital(object):
return headers
def cancel_xml(self, cfdi, xml, auth={}, info={'tipo': 'cfdi3.3'}):
def cancel_xml(self, xml, auth={}, cfdi='', info={'tipo': 'cfdi3.3'}):
if DEBUG or not auth:
auth = AUTH

View File

@ -47,7 +47,7 @@ logging.getLogger('zeep').setLevel(logging.ERROR)
TIMEOUT = 10
DEBUG_SOAP = True
DEBUG_SOAP = False
class DebugPlugin(Plugin):
@ -113,6 +113,10 @@ class PACFinkok(object):
self._error = 'UUID ' + self.CODE['NE']
return {}
if ce == 'UUID Not Found':
self._error = 'UUID ' + self.CODE['NE']
return {}
if self.CODE['200'] != ce:
log.error('CodEstatus', type(ce), ce)
return result
@ -228,8 +232,8 @@ class PACFinkok(object):
}
return data
def cancel_xml(self, xml, auth={}):
if not auth:
def cancel_xml(self, xml, auth={}, cfdi=''):
if DEBUG or not auth:
auth = AUTH
method = 'cancel'

View File

@ -50,7 +50,7 @@ from dateutil import parser
from .cfdi_xml import CFDI
from settings import DEBUG, DB_COMPANIES, PATHS, TEMPLATE_CANCEL
from settings import DEBUG, DB_COMPANIES, PATHS, TEMPLATE_CANCEL, RFCS
from .pacs.cfdi_cert import SATCertificate
from .pacs import PACComercioDigital
@ -79,6 +79,11 @@ PACS = {
'finkok': PACFinkok,
'comercio': PACComercioDigital,
}
NS_CFDI = {
'cfdi': 'http://www.sat.gob.mx/cfd/3',
'tdf': 'http://www.sat.gob.mx/TimbreFiscalDigital',
}
#~ https://github.com/kennethreitz/requests/blob/v1.2.3/requests/structures.py#L37
class CaseInsensitiveDict(collections.MutableMapping):
@ -645,6 +650,13 @@ def make_xml(data, certificado):
return cfdi.add_sello(stamp, cert.cer_txt)
def get_pac_by_rfc(cfdi):
tree = ET.fromstring(cfdi.encode())
path = 'string(//cfdi:Complemento/tdf:TimbreFiscalDigital/@RfcProvCertif)'
rfc_pac = tree.xpath(path, namespaces=NS_CFDI)
return RFCS[rfc_pac]
def cancel_xml_sign(invoice, auth, certificado):
cert = SATCertificate(certificado.cer, certificado.key_enc.encode())
pac = PACS[auth['pac']]()
@ -658,7 +670,7 @@ def cancel_xml_sign(invoice, auth, certificado):
tree = cert.sign_xml(tree)
sign_xml = ET.tostring(tree).decode()
result = pac.cancel_xml(invoice.xml, sign_xml, auth)
result = pac.cancel_xml(sign_xml, auth, invoice.xml)
if pac.error:
result = {'ok': False, 'msg': pac.error, 'row': {}}
return result

View File

@ -404,7 +404,7 @@ class Configuracion(BaseModel):
return values
def _get_admin_products(self):
def _get_admin_products(self, args={}):
fields = (
'chk_config_cuenta_predial',
'chk_config_codigo_barras',
@ -419,7 +419,7 @@ class Configuracion(BaseModel):
values = {r.clave: util.get_bool(r.valor) for r in data}
return values
def _get_main_products(self):
def _get_main_products(self, args={}):
fields = (
'chk_config_cuenta_predial',
'chk_config_codigo_barras',
@ -436,7 +436,7 @@ class Configuracion(BaseModel):
values['default_unidad'] = SATUnidades.get_default()
return values
def _get_complements(self):
def _get_complements(self, args={}):
fields = (
'chk_config_ine',
'chk_config_edu',
@ -464,7 +464,7 @@ class Configuracion(BaseModel):
return values
def _get_folios(self):
def _get_folios(self, args={}):
fields = (
'chk_folio_custom',
)
@ -475,7 +475,7 @@ class Configuracion(BaseModel):
values = {r.clave: util.get_bool(r.valor) for r in data}
return values
def _get_correo(self):
def _get_correo(self, args={}):
fields = ('correo_servidor', 'correo_puerto', 'correo_ssl',
'correo_usuario', 'correo_copia', 'correo_asunto',
'correo_mensaje', 'correo_directo', 'correo_confirmacion')
@ -486,7 +486,7 @@ class Configuracion(BaseModel):
values = {r.clave: r.valor for r in data}
return values
def _get_admin_config_users(self):
def _get_admin_config_users(self, args={}):
fields = (
'chk_users_notify_access',
)
@ -523,7 +523,7 @@ class Configuracion(BaseModel):
}
return values
def _get_pac_auth(cls):
def _get_pac_auth(cls, args={}):
pac = cls.get_('lst_pac').lower()
user = cls.get_(f'user_timbrado_{pac}')
token = cls.get_(f'token_timbrado_{pac}')
@ -534,6 +534,17 @@ class Configuracion(BaseModel):
data['pass'] = token
return data
def _get_auth_by_pac(cls, args):
pac = args['pac']
user = cls.get_(f'user_timbrado_{pac}')
token = cls.get_(f'token_timbrado_{pac}')
data = {}
if pac and user and token:
data['pac'] = pac
data['user'] = user
data['pass'] = token
return data
@classmethod
def get_(cls, keys):
if isinstance(keys, str):
@ -553,10 +564,11 @@ class Configuracion(BaseModel):
'correo',
'admin_config_users',
'pac_auth',
'auth_by_pac',
)
opt = keys['fields']
if opt in options:
return getattr(cls, '_get_{}'.format(opt))(cls)
return getattr(cls, f'_get_{opt}')(cls, keys)
if opt == 'pac':
return cls._get_pac(cls, keys['pac'])
@ -3857,7 +3869,9 @@ class Facturas(BaseModel):
msg = 'Solo es posible cancelar CFDI 3.3'
return {'ok': False, 'msg': msg}
auth = Configuracion.get_({'fields': 'pac_auth'})
pac = utils.get_pac_by_rfc(invoice.xml)
auth = Configuracion.get_({'fields': 'auth_by_pac', 'pac': pac})
certificado = Certificado.get(Certificado.es_fiel==False)
result = utils.cancel_xml_sign(invoice, auth, certificado)

View File

@ -233,6 +233,8 @@ VALUES_PDF = {
RFCS = {
'PUBLIC': 'XAXX010101000',
'FOREIGN': 'XEXX010101000',
'CVD110412TF6': 'finkok',
'SCD110105654': 'comercio',
}
URL = {