From 48619106c5fa975a6f9cc5bd4519c35707128aaf Mon Sep 17 00:00:00 2001
From: bit4bit <bit4bit@noemail.net>
Date: Sun, 15 Nov 2020 23:21:52 +0000
Subject: [PATCH] se adiciona documentacion

FossilOrigin-Name: 20a903a2426d4454a9909c78411b3ad7bd7f7d34d576ed5618e73784f77c8d92
---
 README.rst                                    |  18 ++-
 USAGE.rst                                     |  24 ++++
 ...nvoice.py => generate-invoice-from-cli.py} |  87 +++++++++----
 examples/use-as-lib.py                        | 114 ++++++++++++++++++
 4 files changed, 211 insertions(+), 32 deletions(-)
 create mode 100644 USAGE.rst
 rename examples/{generate-invoice-invoice.py => generate-invoice-from-cli.py} (57%)
 create mode 100644 examples/use-as-lib.py

diff --git a/README.rst b/README.rst
index 187d0f7..dbdaf61 100644
--- a/README.rst
+++ b/README.rst
@@ -24,7 +24,7 @@ usando pip::
 CLI
 ===
 
-tambien se provee linea de comandos **facho** para firmado y envio de documentos::
+tambien se provee linea de comandos **facho** para generacion, firmado y envio de documentos::
   facho --help
 
 CONTRIBUIR
@@ -32,17 +32,13 @@ CONTRIBUIR
 
 ver **CONTRIBUTING.rst**
 
+USO
+===
+
+ver **USAGE.rst**
+
+
 DIAN HABILITACION
 =================
 
 guia oficial actualizada al 2020-04-20: https://www.dian.gov.co/fizcalizacioncontrol/herramienconsulta/FacturaElectronica/Facturaci%C3%B3n_Gratuita_DIAN/Documents/Guia_usuario_08052019.pdf#search=numeracion
-
-
-ERROR X509SerialNumber
-======================
-
-
-lxml.etree.DocumentInvalid: Element '{http://www.w3.org/2000/09/xmldsig#}X509SerialNumber': '632837201711293159666920255411738137494572618415' is not a valid value of the atomic type 'xs:integer'
-
-Actualmente el xmlschema usado por xmlsig para el campo X509SerialNumber es tipo
-integer ahi que parchar manualmente a tipo string, en el archivo site-packages/xmlsig/data/xmldsig-core-schema.xsd.
diff --git a/USAGE.rst b/USAGE.rst
new file mode 100644
index 0000000..468fb57
--- /dev/null
+++ b/USAGE.rst
@@ -0,0 +1,24 @@
+uso de la libreria
+==================
+
+**facho** es tanto una libreria para modelar y generar los documentos xml requeridos para la facturacion,
+asi como una herramienta de **consola** para facilitar algunas actividades como: generaciones de xml
+apartir de una especificacion en python, comprimir y enviar archivos según el SOAP vigente.
+
+**facho** es diseñado para ser usado en conjunto con el documento **docs/DIAN/Anexo_Tecnico_Factura_Electronica_Vr1_7_2020.pdf**, ya que en gran medida sigue la terminologia presente en este.
+
+
+Para ejemplos ver **examples/** .
+
+En terminos generales seria modelar la factura usando **facho/fe/form.py**, instanciar las extensiones requeridas ver **facho/fe/fe.py** y
+una vez generado el objeto invoice y las extensiones requeridas se procede a crear el XML, ejemplo:
+
+~~~python
+....
+xml = form_xml.DIANInvoiceXML(invoice)
+extensions = module.extensions(invoice)
+for extension in extensions:
+  xml.add_extension(extension)
+
+form_xml.DIANWriteSigned(xml, "factura.xml", "llave privada", "frase")
+~~~
diff --git a/examples/generate-invoice-invoice.py b/examples/generate-invoice-from-cli.py
similarity index 57%
rename from examples/generate-invoice-invoice.py
rename to examples/generate-invoice-from-cli.py
index 91e2419..9c89ab3 100644
--- a/examples/generate-invoice-invoice.py
+++ b/examples/generate-invoice-from-cli.py
@@ -1,39 +1,49 @@
+# este archivo es un ejemplo para le generacion
+# una factura de venta nacional usando el comando **facho**.
+#
+# ejemplo: facho generate-invoice generate-invoice-from-cli.py
+#
+# importar libreria de modelos
 import facho.fe.form as form
+import facho.fe.form_xml
+
+# importar libreria extensiones xml para cumplir decreto
 from facho.fe import fe
+
+# importar otras necesarias
 from datetime import datetime
 
-def extensions(inv):
-    nit = form.PartyIdentification('nit', '5', '31')
-    security_code = fe.DianXMLExtensionSoftwareSecurityCode('id software', 'pin', inv.invoice_ident)
-    authorization_provider = fe.DianXMLExtensionAuthorizationProvider()
-    cufe = fe.DianXMLExtensionCUFE(inv, fe.DianXMLExtensionCUFE.AMBIENTE_PRUEBAS,
-                                   'clave tecnica')
-    software_provider = fe.DianXMLExtensionSoftwareProvider(nit, nit.dv, 'id software')
-    inv_authorization = fe.DianXMLExtensionInvoiceAuthorization('invoice autorization',
-                                                                datetime(2019, 1, 19),
-                                                                datetime(2030, 1, 19),
-                                                                'SETP', 990000001, 995000000)
-    return [security_code, authorization_provider, cufe, software_provider, inv_authorization]
-
-
+# callback que retorna el modelado de documento electronico
+# a generar
 def invoice():
-    inv = form.Invoice()
+    # factura de venta nacional
+    inv = form.NationalSalesInvoice()
+    # asignar periodo de facturacion
     inv.set_period(datetime.now(), datetime.now())
+    # asignar fecha de emision de la factura
     inv.set_issue(datetime.now())
+    # asignar prefijo y numero del documento
     inv.set_ident('SETP990003033')
+    # asignar tipo de operacion ver DIAN:6.1.5
     inv.set_operation_type('10')
+    # asignar proveedor
     inv.set_supplier(form.Party(
         legal_name = 'FACHO SOS',
         name = 'FACHO SOS',
         ident = form.PartyIdentification('900579212', '5', '31'),
+        # obligaciones del contribuyente ver DIAN:FAK26
         responsability_code = form.Responsability(['O-07', 'O-09', 'O-14', 'O-48']),
+        # ver DIAN:FAJ28
         responsability_regime_code = '48',
+        # tipo de organizacion juridica ver DIAN:6.2.3
         organization_code = '1',
         email = "sdds@sd.com",
         address = form.Address(
-            '', '', form.City('05001', 'Medellín'),
-            form.Country('CO', 'Colombia'),
-            form.CountrySubentity('05', 'Antioquia'))
+            name = '',
+            street = '',
+            city = form.City('05001', 'Medellín'),
+            country = form.Country('CO', 'Colombia'),
+            countrysubentity = form.CountrySubentity('05', 'Antioquia'))
     ))
     inv.set_customer(form.Party(
         legal_name = 'facho-customer',
@@ -44,22 +54,34 @@ def invoice():
         organization_code = '2',
         email = "sdds@sd.com",
         address = form.Address(
-            '', '', form.City('05001', 'Medellín'),
-            form.Country('CO', 'Colombia'),
-            form.CountrySubentity('05', 'Antioquia'))
+            name = '',
+            street = '',
+            city = form.City('05001', 'Medellín'),
+            country = form.Country('CO', 'Colombia'),
+            countrysubentity = form.CountrySubentity('05', 'Antioquia'))
     ))
+    # asignar metodo de pago
     inv.set_payment_mean(form.PaymentMean(
+        # metodo de pago ver DIAN:3.4.1
         id = '1',
+        # codigo correspondiente al medio de pago ver DIAN:3.4.2
         code = '10',
+        # fecha de vencimiento de la factura
         due_at = datetime.now(),
+
+        # identificador numerico
         payment_id = '1'
     ))
+    # adicionar una linea al documento
     inv.add_invoice_line(form.InvoiceLine(
         quantity = form.Quantity(1, '94'),
         description = 'producto facho',
+        # item general de codigo 999
         item = form.StandardItem('test', 9999),
         price = form.Price(
+            # precio base del tiem
             amount = form.Amount(100.00),
+            # ver DIAN:6.3.5.1
             type_code = '01',
             type = 'x'
         ),
@@ -72,3 +94,26 @@ def invoice():
         )
     ))
     return inv
+
+# callback que retonar las extensiones XML necesarias
+# para que el documento final XML cumpla el decreto.
+#
+# muchos de los valores usados son obtenidos
+# del servicio web de la DIAN.
+def extensions(inv):
+    security_code = fe.DianXMLExtensionSoftwareSecurityCode('id software', 'pin', inv.invoice_ident)
+    authorization_provider = fe.DianXMLExtensionAuthorizationProvider()
+    cufe = fe.DianXMLExtensionCUFE(inv, fe.DianXMLExtensionCUFE.AMBIENTE_PRUEBAS,
+                                   'clave tecnica')
+    nit = form.PartyIdentification('nit', '5', '31')
+    software_provider = fe.DianXMLExtensionSoftwareProvider(nit, nit.dv, 'id software')
+    inv_authorization = fe.DianXMLExtensionInvoiceAuthorization('invoice autorization',
+                                                                datetime(2019, 1, 19),
+                                                                datetime(2030, 1, 19),
+                                                                'SETP', 990000001, 995000000)
+    return [security_code, authorization_provider, cufe, software_provider, inv_authorization]
+
+
+# callback con transformador a XML
+def document_xml():
+    return form_xml.DIANInvoiceXML
diff --git a/examples/use-as-lib.py b/examples/use-as-lib.py
new file mode 100644
index 0000000..96dbbaa
--- /dev/null
+++ b/examples/use-as-lib.py
@@ -0,0 +1,114 @@
+# importar libreria de modelos
+import facho.fe.form as form
+import facho.fe.form_xml
+
+PRIVATE_KEY_PATH='ruta a mi llave privada'
+PRIVATE_PASSPHRASE='clave de la llave privada'
+
+# consultar las extensiones necesarias
+def extensions(inv):
+    security_code = fe.DianXMLExtensionSoftwareSecurityCode('id software', 'pin', inv.invoice_ident)
+    authorization_provider = fe.DianXMLExtensionAuthorizationProvider()
+    cufe = fe.DianXMLExtensionCUFE(inv, fe.DianXMLExtensionCUFE.AMBIENTE_PRUEBAS,
+                                   'clave tecnica')
+    nit = form.PartyIdentification('nit', '5', '31')
+    software_provider = fe.DianXMLExtensionSoftwareProvider(nit, nit.dv, 'id software')
+    inv_authorization = fe.DianXMLExtensionInvoiceAuthorization('invoice autorization',
+                                                                datetime(2019, 1, 19),
+                                                                datetime(2030, 1, 19),
+                                                                'SETP', 990000001, 995000000)
+    return [security_code, authorization_provider, cufe, software_provider, inv_authorization]
+
+# generar documento desde modelo a ruta indicada
+def generate_document(invoice, filepath):
+    xml = form_xml.DIANInvoiceXML(invoice)
+    for extension in extensions(invoice):
+        xml.add_extension(extension)
+    form_xml.utils.DIANWriteSigned(xml, filepath, PRIVATE_KEY_PATH, PRIVATE_PASSPHRASE, True)
+
+# Modelars las facturas
+# ...
+
+# factura de venta nacional
+inv = form.NationalSalesInvoice()
+# asignar periodo de facturacion
+inv.set_period(datetime.now(), datetime.now())
+# asignar fecha de emision de la factura
+inv.set_issue(datetime.now())
+# asignar prefijo y numero del documento
+inv.set_ident('SETP990003033')
+# asignar tipo de operacion ver DIAN:6.1.5
+inv.set_operation_type('10')
+# asignar proveedor
+inv.set_supplier(form.Party(
+    legal_name = 'FACHO SOS',
+    name = 'FACHO SOS',
+    ident = form.PartyIdentification('900579212', '5', '31'),
+    # obligaciones del contribuyente ver DIAN:FAK26
+    responsability_code = form.Responsability(['O-07', 'O-09', 'O-14', 'O-48']),
+    # ver DIAN:FAJ28
+    responsability_regime_code = '48',
+    # tipo de organizacion juridica ver DIAN:6.2.3
+    organization_code = '1',
+    email = "sdds@sd.com",
+    address = form.Address(
+        name = '',
+        street = '',
+        city = form.City('05001', 'Medellín'),
+        country = form.Country('CO', 'Colombia'),
+        countrysubentity = form.CountrySubentity('05', 'Antioquia'))
+))
+inv.set_customer(form.Party(
+    legal_name = 'facho-customer',
+    name = 'facho-customer',
+    ident = form.PartyIdentification('999999999', '', '13'),
+    responsability_code = form.Responsability(['R-99-PN']),
+    responsability_regime_code = '49',
+    organization_code = '2',
+    email = "sdds@sd.com",
+    address = form.Address(
+        name = '',
+        street = '',
+        city = form.City('05001', 'Medellín'),
+        country = form.Country('CO', 'Colombia'),
+        countrysubentity = form.CountrySubentity('05', 'Antioquia'))
+))
+# asignar metodo de pago
+inv.set_payment_mean(form.PaymentMean(
+    # metodo de pago ver DIAN:3.4.1
+    id = '1',
+    # codigo correspondiente al medio de pago ver DIAN:3.4.2
+    code = '10',
+    # fecha de vencimiento de la factura
+    due_at = datetime.now(),
+    
+    # identificador numerico
+    payment_id = '1'
+))
+# adicionar una linea al documento
+inv.add_invoice_line(form.InvoiceLine(
+    quantity = form.Quantity(1, '94'),
+    description = 'producto facho',
+    # item general de codigo 999
+    item = form.StandardItem('test', 9999),
+    price = form.Price(
+        # precio base del tiem
+        amount = form.Amount(100.00),
+        # ver DIAN:6.3.5.1
+        type_code = '01',
+        type = 'x'
+    ),
+    tax = form.TaxTotal(
+        subtotals = [
+            form.TaxSubTotal(
+                percent = 19.00,
+            )
+        ]
+    )
+))
+
+# refrescar valores de la factura
+inv.calculate()
+
+# generar el documento xml en la ruta indicada
+generate_document(inv, 'ruta a donde guardar el .xml')