se adiciona comandos soap send-bill-async,send-bill-sync,get-status-zip
FossilOrigin-Name: e3ab64b71d8bfb3acc50f813aec9b97c45cd80c2c4f38e23804d1f17f058ffdf
This commit is contained in:
		
							
								
								
									
										65
									
								
								facho/cli.py
									
									
									
									
									
								
							
							
						
						
									
										65
									
								
								facho/cli.py
									
									
									
									
									
								
							@@ -44,6 +44,48 @@ def consultaResolucionesFacturacion(nit, nit_proveedor, id_software, username, p
 | 
				
			|||||||
    print(str(resp))
 | 
					    print(str(resp))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
 | 
					@click.command()
 | 
				
			||||||
 | 
					@click.option('--private-key', required=True)
 | 
				
			||||||
 | 
					@click.option('--public-key', required=True)
 | 
				
			||||||
 | 
					@click.option('--habilitacion/--produccion', default=False)
 | 
				
			||||||
 | 
					@click.option('--password')
 | 
				
			||||||
 | 
					@click.option('--test-setid', required=True)
 | 
				
			||||||
 | 
					@click.argument('filename', required=True)
 | 
				
			||||||
 | 
					@click.argument('zipfile', type=click.Path(exists=True))
 | 
				
			||||||
 | 
					def soap_send_test_set_async(private_key, public_key, habilitacion, password, test_setid, filename, zipfile):
 | 
				
			||||||
 | 
					    from facho.fe.client import dian
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    client = dian.DianSignatureClient(private_key, public_key, password=password)
 | 
				
			||||||
 | 
					    req = dian.SendTestSetAsync
 | 
				
			||||||
 | 
					    if habilitacion:
 | 
				
			||||||
 | 
					        req = dian.Habilitacion.SendTestSetAsync
 | 
				
			||||||
 | 
					    resp = client.request(req(
 | 
				
			||||||
 | 
					        filename,
 | 
				
			||||||
 | 
					        open(zipfile, 'rb').read(),
 | 
				
			||||||
 | 
					        test_setid,
 | 
				
			||||||
 | 
					    ))
 | 
				
			||||||
 | 
					    print(resp)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@click.command()
 | 
				
			||||||
 | 
					@click.option('--private-key', required=True)
 | 
				
			||||||
 | 
					@click.option('--public-key', required=True)
 | 
				
			||||||
 | 
					@click.option('--habilitacion/--produccion', default=False)
 | 
				
			||||||
 | 
					@click.option('--password')
 | 
				
			||||||
 | 
					@click.argument('filename', required=True)
 | 
				
			||||||
 | 
					@click.argument('zipfile', type=click.Path(exists=True))
 | 
				
			||||||
 | 
					def soap_send_bill_async(private_key, public_key, habilitacion, password, filename, zipfile):
 | 
				
			||||||
 | 
					    from facho.fe.client import dian
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    client = dian.DianSignatureClient(private_key, public_key, password=password)
 | 
				
			||||||
 | 
					    req = dian.SendBillAsync
 | 
				
			||||||
 | 
					    if habilitacion:
 | 
				
			||||||
 | 
					        req = dian.Habilitacion.SendBillAsync
 | 
				
			||||||
 | 
					    resp = client.request(req(
 | 
				
			||||||
 | 
					        filename,
 | 
				
			||||||
 | 
					        open(zipfile, 'rb').read()
 | 
				
			||||||
 | 
					    ))
 | 
				
			||||||
 | 
					    print(resp)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@click.command()
 | 
					@click.command()
 | 
				
			||||||
@click.option('--private-key', required=True)
 | 
					@click.option('--private-key', required=True)
 | 
				
			||||||
@click.option('--public-key', required=True)
 | 
					@click.option('--public-key', required=True)
 | 
				
			||||||
@@ -64,6 +106,24 @@ def soap_send_bill_sync(private_key, public_key, habilitacion, password, filenam
 | 
				
			|||||||
    ))
 | 
					    ))
 | 
				
			||||||
    print(resp)
 | 
					    print(resp)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@click.command()
 | 
				
			||||||
 | 
					@click.option('--private-key', required=True)
 | 
				
			||||||
 | 
					@click.option('--public-key', required=True)
 | 
				
			||||||
 | 
					@click.option('--habilitacion/--produccion', default=False)
 | 
				
			||||||
 | 
					@click.option('--password')
 | 
				
			||||||
 | 
					@click.option('--track-id', required=True)
 | 
				
			||||||
 | 
					def soap_get_status_zip(private_key, public_key, habilitacion, password, track_id):
 | 
				
			||||||
 | 
					    from facho.fe.client import dian
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    client = dian.DianSignatureClient(private_key, public_key, password=password)
 | 
				
			||||||
 | 
					    req = dian.GetStatusZip
 | 
				
			||||||
 | 
					    if habilitacion:
 | 
				
			||||||
 | 
					        req = dian.Habilitacion.GetStatusZip
 | 
				
			||||||
 | 
					    resp = client.request(req(
 | 
				
			||||||
 | 
					        trackId = track_id
 | 
				
			||||||
 | 
					    ))
 | 
				
			||||||
 | 
					    print(resp)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@click.command()
 | 
					@click.command()
 | 
				
			||||||
@click.option('--private-key', required=True)
 | 
					@click.option('--private-key', required=True)
 | 
				
			||||||
@click.option('--public-key', required=True)
 | 
					@click.option('--public-key', required=True)
 | 
				
			||||||
@@ -113,7 +173,7 @@ def generate_invoice(private_key, passphrase, scriptname):
 | 
				
			|||||||
    if private_key:
 | 
					    if private_key:
 | 
				
			||||||
        signer = fe.DianXMLExtensionSigner(private_key, passphrase=passphrase)
 | 
					        signer = fe.DianXMLExtensionSigner(private_key, passphrase=passphrase)
 | 
				
			||||||
        xml.add_extension(signer)
 | 
					        xml.add_extension(signer)
 | 
				
			||||||
    print(str(xml))
 | 
					    print(xml.tostring(xml_declaration=True))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
@click.group()
 | 
					@click.group()
 | 
				
			||||||
@@ -121,6 +181,9 @@ def main():
 | 
				
			|||||||
    pass
 | 
					    pass
 | 
				
			||||||
 | 
					
 | 
				
			||||||
main.add_command(consultaResolucionesFacturacion)
 | 
					main.add_command(consultaResolucionesFacturacion)
 | 
				
			||||||
 | 
					main.add_command(soap_send_test_set_async)
 | 
				
			||||||
 | 
					main.add_command(soap_send_bill_async)
 | 
				
			||||||
main.add_command(soap_send_bill_sync)
 | 
					main.add_command(soap_send_bill_sync)
 | 
				
			||||||
main.add_command(soap_get_status)
 | 
					main.add_command(soap_get_status)
 | 
				
			||||||
 | 
					main.add_command(soap_get_status_zip)
 | 
				
			||||||
main.add_command(generate_invoice)
 | 
					main.add_command(generate_invoice)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -98,8 +98,10 @@ class LXMLBuilder:
 | 
				
			|||||||
    def set_attribute(self,  elem, key, value):
 | 
					    def set_attribute(self,  elem, key, value):
 | 
				
			||||||
        elem.attrib[key] = value
 | 
					        elem.attrib[key] = value
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def tostring(self, elem):
 | 
					    def tostring(self, elem, **attrs):
 | 
				
			||||||
        return tostring(elem).decode('utf-8')
 | 
					        attrs['pretty_print'] = attrs.pop('pretty_print', True)
 | 
				
			||||||
 | 
					        attrs['encoding'] = attrs.pop('encoding', 'UTF-8')
 | 
				
			||||||
 | 
					        return tostring(elem, **attrs).decode('utf-8')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class FachoXML:
 | 
					class FachoXML:
 | 
				
			||||||
@@ -207,8 +209,8 @@ class FachoXML:
 | 
				
			|||||||
        text = self.builder.get_text(elem)
 | 
					        text = self.builder.get_text(elem)
 | 
				
			||||||
        return format_(text)
 | 
					        return format_(text)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def tostring(self):
 | 
					    def tostring(self, **kw):
 | 
				
			||||||
        return self.builder.tostring(self.root)
 | 
					        return self.builder.tostring(self.root, **kw)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def __str__(self):
 | 
					    def __str__(self):
 | 
				
			||||||
        return self.tostring()
 | 
					        return self.tostring()
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -80,7 +80,7 @@ class ConsultaResolucionesFacturacionPeticion(SOAPService):
 | 
				
			|||||||
        return ConsultaResolucionesFacturacionRespuesta.fromdict(as_dict)
 | 
					        return ConsultaResolucionesFacturacionRespuesta.fromdict(as_dict)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@dataclass
 | 
					@dataclass
 | 
				
			||||||
class SendBillAsync:
 | 
					class SendBillAsync(SOAPService):
 | 
				
			||||||
    fileName: str
 | 
					    fileName: str
 | 
				
			||||||
    contentFile: str
 | 
					    contentFile: str
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -91,7 +91,7 @@ class SendBillAsync:
 | 
				
			|||||||
        return 'SendBillAsync'
 | 
					        return 'SendBillAsync'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def build_response(self, as_dict):
 | 
					    def build_response(self, as_dict):
 | 
				
			||||||
        return {}
 | 
					        return as_dict
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -108,7 +108,7 @@ class SendTestSetAsync(SOAPService):
 | 
				
			|||||||
        return 'SendTestSetAsync'
 | 
					        return 'SendTestSetAsync'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def build_response(self, as_dict):
 | 
					    def build_response(self, as_dict):
 | 
				
			||||||
        return {}
 | 
					        return as_dict
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@dataclass
 | 
					@dataclass
 | 
				
			||||||
class SendBillSync(SOAPService):
 | 
					class SendBillSync(SOAPService):
 | 
				
			||||||
@@ -122,7 +122,7 @@ class SendBillSync(SOAPService):
 | 
				
			|||||||
        return 'SendBillSync'
 | 
					        return 'SendBillSync'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def build_response(self, as_dict):
 | 
					    def build_response(self, as_dict):
 | 
				
			||||||
        return {}
 | 
					        return as_dict
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@dataclass
 | 
					@dataclass
 | 
				
			||||||
@@ -136,12 +136,31 @@ class GetStatus(SOAPService):
 | 
				
			|||||||
        return 'GetStatus'
 | 
					        return 'GetStatus'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def build_response(self, as_dict):
 | 
					    def build_response(self, as_dict):
 | 
				
			||||||
        return {}
 | 
					        return as_dict
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@dataclass
 | 
				
			||||||
 | 
					class GetStatusZip(SOAPService):
 | 
				
			||||||
 | 
					    trackId: bytes
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def get_wsdl(self):
 | 
				
			||||||
 | 
					        return 'https://colombia-dian-webservices-input-sbx.azurewebsites.net/WcfDianCustomerServices.svc?wsdl'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def get_service(self):
 | 
				
			||||||
 | 
					        return 'GetStatusZip'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def build_response(self, as_dict):
 | 
				
			||||||
 | 
					        return as_dict
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class Habilitacion:
 | 
					class Habilitacion:
 | 
				
			||||||
    WSDL = 'https://vpfe-hab.dian.gov.co/WcfDianCustomerServices.svc?wsdl'
 | 
					    WSDL = 'https://vpfe-hab.dian.gov.co/WcfDianCustomerServices.svc?wsdl'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    class SendBillAsync(SendBillAsync):
 | 
				
			||||||
 | 
					        def get_wsdl(self):
 | 
				
			||||||
 | 
					            return Habilitacion.WSDL
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    class SendBillSync(SendBillSync):
 | 
					    class SendBillSync(SendBillSync):
 | 
				
			||||||
        def get_wsdl(self):
 | 
					        def get_wsdl(self):
 | 
				
			||||||
            return Habilitacion.WSDL
 | 
					            return Habilitacion.WSDL
 | 
				
			||||||
@@ -154,6 +173,10 @@ class Habilitacion:
 | 
				
			|||||||
        def get_wsdl(self):
 | 
					        def get_wsdl(self):
 | 
				
			||||||
            return Habilitacion.WSDL
 | 
					            return Habilitacion.WSDL
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    class GetStatusZip(GetStatusZip):
 | 
				
			||||||
 | 
					        def get_wsdl(self):
 | 
				
			||||||
 | 
					            return Habilitacion.WSDL
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class DianGateway:
 | 
					class DianGateway:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -200,12 +223,11 @@ class DianSignatureClient(DianGateway):
 | 
				
			|||||||
        from zeep.wsse import utils
 | 
					        from zeep.wsse import utils
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        client = zeep.Client(service.get_wsdl(), wsse=
 | 
					        client = zeep.Client(service.get_wsdl(), wsse=
 | 
				
			||||||
                           [
 | 
					 | 
				
			||||||
                             BinarySignature(
 | 
					                             BinarySignature(
 | 
				
			||||||
                                 self.private_key_path, self.public_key_path, self.password,
 | 
					                                 self.private_key_path, self.public_key_path, self.password,
 | 
				
			||||||
                                 signature_method=xmlsec.Transform.RSA_SHA256,
 | 
					                                 signature_method=xmlsec.Transform.RSA_SHA256,
 | 
				
			||||||
                                 digest_method=xmlsec.Transform.SHA256)
 | 
					                                 digest_method=xmlsec.Transform.SHA256)
 | 
				
			||||||
                           ],
 | 
					                             ,
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
        return client
 | 
					        return client
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -346,6 +346,9 @@ def _verify_envelope_with_key(envelope, key):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    security = header.find(QName(ns.WSSE, "Security"))
 | 
					    security = header.find(QName(ns.WSSE, "Security"))
 | 
				
			||||||
    signature = security.find(QName(ns.DS, "Signature"))
 | 
					    signature = security.find(QName(ns.DS, "Signature"))
 | 
				
			||||||
 | 
					    # la DIAN no cumple a cabalidad token-profile 1.0
 | 
				
			||||||
 | 
					    if signature is None:
 | 
				
			||||||
 | 
					        return SignatureVerificationFailed()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    ctx = xmlsec.SignatureContext()
 | 
					    ctx = xmlsec.SignatureContext()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -55,6 +55,7 @@ class DianXMLExtensionCUFE(FachoXMLExtension):
 | 
				
			|||||||
    def build(self, fachoxml):
 | 
					    def build(self, fachoxml):
 | 
				
			||||||
        cufe = self._generate_cufe(self.invoice, fachoxml)
 | 
					        cufe = self._generate_cufe(self.invoice, fachoxml)
 | 
				
			||||||
        fachoxml.set_element('/fe:Invoice/cbc:UUID[schemaName="CUFE-SHA384"]', cufe)
 | 
					        fachoxml.set_element('/fe:Invoice/cbc:UUID[schemaName="CUFE-SHA384"]', cufe)
 | 
				
			||||||
 | 
					        fachoxml.set_element('/fe:Invoice/cbc:ProfileID', 'DIAN 2.1')
 | 
				
			||||||
        fachoxml.set_element('/fe:Invoice/cbc:ProfileExecutionID', self._tipo_ambiente())
 | 
					        fachoxml.set_element('/fe:Invoice/cbc:ProfileExecutionID', self._tipo_ambiente())
 | 
				
			||||||
        return '', []
 | 
					        return '', []
 | 
				
			||||||
        
 | 
					        
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -181,6 +181,7 @@ class DIANInvoiceXML(fe.FeXML):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        invoice.calculate()
 | 
					        invoice.calculate()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        fexml.set_element('/fe:Invoice/cbc:UBLVersionID', 'UBL 2.1')
 | 
				
			||||||
        fexml.set_element('/fe:Invoice/cbc:ID', invoice.invoice_ident)
 | 
					        fexml.set_element('/fe:Invoice/cbc:ID', invoice.invoice_ident)
 | 
				
			||||||
        fexml.set_element('/fe:Invoice/cbc:IssueDate', invoice.invoice_issue.strftime('%Y-%m-%d'))
 | 
					        fexml.set_element('/fe:Invoice/cbc:IssueDate', invoice.invoice_issue.strftime('%Y-%m-%d'))
 | 
				
			||||||
        fexml.set_element('/fe:Invoice/cbc:IssueTime', invoice.invoice_issue.strftime('%H:%M:%S%z'))
 | 
					        fexml.set_element('/fe:Invoice/cbc:IssueTime', invoice.invoice_issue.strftime('%H:%M:%S%z'))
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user