diff --git a/source/cfdi-descarga.py b/source/cfdi-descarga.py index 8160689..a05bb3c 100755 --- a/source/cfdi-descarga.py +++ b/source/cfdi-descarga.py @@ -37,6 +37,10 @@ def _process_command_line_arguments(): help = "Día de la descarga, de forma predeterminada no se usa" parser.add_argument('-d', '--dia', help=help, dest='day', default=0, type=int, choices=range(32)) + help = 'Verificar estatus de descarga' + parser.add_argument('-ve', '--fiel-validar', help=help, + action='store_true', default=False, required=False) + args = parser.parse_args() return args @@ -44,3 +48,10 @@ def _process_command_line_arguments(): if __name__ == '__main__': args = _process_command_line_arguments() main(args) + + +# ~ { + # ~ 'IdSolicitud': '307a22f0-1259-479c-96b1-2852f9072c58', + # ~ 'CodEstatus': '5000', + # ~ 'Mensaje': 'Solicitud Aceptada' +# ~ } diff --git a/source/sat/cfdi_cert.py b/source/sat/cfdi_cert.py index 35fc048..8623356 100644 --- a/source/sat/cfdi_cert.py +++ b/source/sat/cfdi_cert.py @@ -28,6 +28,7 @@ class SATCertificate(object): def _init_values(self): self._rfc = '' self._serial_number = '' + self._serial_number2 = '' self._not_before = None self._not_after = None self._is_fiel = False @@ -66,6 +67,7 @@ class SATCertificate(object): obj = x509.load_der_x509_certificate(cer, default_backend()) self._rfc = obj.subject.get_attributes_for_oid( NameOID.X500_UNIQUE_IDENTIFIER)[0].value.split(' ')[0] + self._serial_number2 = obj.serial_number self._serial_number = '{0:x}'.format(obj.serial_number)[1::2] self._not_before = obj.not_valid_before self._not_after = obj.not_valid_after @@ -167,6 +169,10 @@ class SATCertificate(object): def serial_number(self): return self._serial_number + @property + def serial_number2(self): + return self._serial_number2 + @property def not_before(self): return self._not_before diff --git a/source/sat/sat_web.py b/source/sat/sat_web.py index 57cdf0c..46bc447 100644 --- a/source/sat/sat_web.py +++ b/source/sat/sat_web.py @@ -16,9 +16,10 @@ class SATWebService(): 'REQ': f'{BASE}/SolicitaDescargaService.svc', } XMLNS = 'http://DescargaMasivaTerceros.gob.mx' + XMLNS2 = 'http://DescargaMasivaTerceros.sat.gob.mx' ACTIONS = { 'AUTH': f'{XMLNS}/IAutenticacion/Autentica', - 'REQ': f'{XMLNS}/ISolicitaDescargaService/SolicitaDescarga', + 'REQ': f'{XMLNS2}/ISolicitaDescargaService/SolicitaDescarga', } HEADERS = { 'Content-type': 'text/xml;charset="utf-8"', @@ -33,6 +34,7 @@ class SATWebService(): 'xd': 'http://www.w3.org/2000/09/xmldsig#', } NS_RESULT = {'s': NS['s'], None: XMLNS} + NS_RESULT2 = {'s': NS['s'], None: XMLNS2} def __init__(self, cert): self._cert = cert @@ -169,7 +171,8 @@ class SATWebService(): 'RfcSolicitante': self._cert.rfc, 'FechaFinal': date_end.strftime(FORMAT), 'FechaInicial': date_start.strftime(FORMAT), - 'TipoSolicitud': 'cfdi', + 'TipoSolicitud': 'CFDI', + 'RfcEmisor': self._cert.rfc, } request = ET.SubElement(request_down, node_name, attr) # ~ if rfc_emisor is not None: @@ -183,7 +186,7 @@ class SATWebService(): node_name = 'CanonicalizationMethod' attr1 = {'Algorithm': 'http://www.w3.org/2001/10/xml-exc-c14n#'} - canonicalization = ET.SubElement(signed_info, node_name, attr) + canonicalization = ET.SubElement(signed_info, node_name, attr1) node_name = 'SignatureMethod' attr = {'Algorithm': 'http://www.w3.org/2000/09/xmldsig#rsa-sha1'} @@ -192,24 +195,30 @@ class SATWebService(): attr = {'URI': '#_0'} reference = ET.SubElement(signed_info, 'Reference', attr) transforms = ET.SubElement(reference, 'Transforms') - ET.SubElement(transforms, 'Transform') + ET.SubElement(transforms, 'Transform', attr1) attr = {'Algorithm': 'http://www.w3.org/2000/09/xmldsig#sha1'} ET.SubElement(reference, 'DigestMethod', attr) - - dvalue = ET.tostring(request_down, method='c14n', exclusive=1) - dvalue = base64.b64encode(hashlib.new('sha1', dvalue).digest()) - ET.SubElement(reference, 'DigestValue').text = dvalue - - signature_value = ET.tostring(signed_info, method='c14n', exclusive=1) - signature_value = self._cert.sign_sha1(signature_value) - ET.SubElement(signature, 'SignatureValue').text = signature_value + digest_value = ET.SubElement(reference, 'DigestValue') + signature_value = ET.SubElement(signature, 'SignatureValue') key_info = ET.SubElement(signature, 'KeyInfo') x_data = ET.SubElement(key_info, 'X509Data') x_issuer_serial = ET.SubElement(x_data, 'X509IssuerSerial') - ET.SubElement(x_issuer_serial, 'X509IssuerName').text = self._cert.issuer - ET.SubElement(x_issuer_serial, 'X509SerialNumber').text = self._cert.serial_number - ET.SubElement(x_data, 'X509Certificate').text = self._cert.cer_txt + x_issuer = ET.SubElement(x_issuer_serial, 'X509IssuerName') + x_serial_number = ET.SubElement(x_issuer_serial, 'X509SerialNumber') + x_cert = ET.SubElement(x_data, 'X509Certificate') + + dvalue = ET.tostring(request_down, method='c14n', exclusive=1) + dvalue = base64.b64encode(hashlib.new('sha1', dvalue).digest()) + digest_value.text = dvalue + + sign = ET.tostring(signed_info, method='c14n', exclusive=1) + sign = self._cert.sign_sha1(sign) + signature_value.text = sign + + x_issuer.text = self._cert.issuer + x_serial_number.text = str(self._cert.serial_number2) + x_cert.text = self._cert.cer_txt # ~ soap = ET.tostring(root, pretty_print=True, encoding='utf-8') soap = ET.tostring(root) @@ -229,7 +238,7 @@ class SATWebService(): result = ET.fromstring(response.text) node_name = 's:Body/SolicitaDescargaResponse/SolicitaDescargaResult' - node = result.find(node_name, namespaces=self.NS_RESULT) + node = result.find(node_name, namespaces=self.NS_RESULT2) data = dict(node.attrib) return data diff --git a/source/sat/util.py b/source/sat/util.py index 4067519..8c78a90 100644 --- a/source/sat/util.py +++ b/source/sat/util.py @@ -100,6 +100,7 @@ def fiel_validar(args): log.info(f'\n{cert}') msg = 'Ya puedes descargar del SAT' log.info(msg) + return