Compare commits
	
		
			131 Commits
		
	
	
		
			model
			...
			MigrationP
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| f98ab98c9c | |||
| d04596ed3a | |||
| 9297be22e0 | |||
|  | 30773e042b | ||
| fb44498e53 | |||
| 9f7349ccee | |||
| 9cc41e1c5d | |||
| fc75126ca0 | |||
| d061077b30 | |||
| a3d2176068 | |||
| 98677bc162 | |||
| 398d27d049 | |||
| 8765a3d2c8 | |||
| 1935ed3048 | |||
| 097cf97fc3 | |||
| de99633211 | |||
|  | 028cf8b687 | ||
| e7a3976b14 | |||
| f08954ee43 | |||
| a0321020c7 | |||
| dde24b9739 | |||
| 6e5d358c73 | |||
| c12d985f76 | |||
| 9c126d961b | |||
| 95f16b2842 | |||
| 8f327f7abc | |||
|  | b7c9f2b201 | ||
| 7f974b7077 | |||
| 78477de2c2 | |||
|   | 75b41379c4 | ||
|   | d26cc2bef7 | ||
|   | 1abf34d4f0 | ||
|  | 3862b3e934 | ||
|   | 5cf929cca9 | ||
|   | 7e51726a0d | ||
|  | f05eb61d6e | ||
|  | 5a045ccdef | ||
|   | bd0fe70f33 | ||
|   | 7c4c9648fe | ||
|  | 5eecae0740 | ||
|  | a59df60fc2 | ||
|  | 19c5a5bca6 | ||
|  | c50f1df1e7 | ||
|  | 2a1f3b6b43 | ||
|  | a208d924dd | ||
|  | c3b0f7cfe8 | ||
|  | 005f90166e | ||
|  | 73bb90b74b | ||
|  | 6bed600dd4 | ||
|  | aa3c83933d | ||
|  | ac1678b1cc | ||
|  | 29db6b0342 | ||
|  | 417de535f3 | ||
|  | a9564f9a70 | ||
|  | 48c56631ec | ||
|  | d5f484ac30 | ||
|  | fc904f8f92 | ||
|  | 6e2f450ee9 | ||
|  | 099b23df74 | ||
|  | 82e043e01d | ||
|  | 7054e2da22 | ||
|  | dc9e0d9ad7 | ||
|  | c08629337c | ||
|  | 95bc4e73f5 | ||
|  | a411562af1 | ||
|  | 27ebbecc01 | ||
|  | 7181c004cb | ||
|  | 012615f984 | ||
|  | a320b5a7b0 | ||
|  | ebc67d1327 | ||
|  | 9c2c3d9ce3 | ||
|  | d36259d121 | ||
|  | 23d6f668bf | ||
|  | dd445b59f0 | ||
|  | 1a302f605f | ||
|  | cbe0c512eb | ||
|  | 1e03d4f289 | ||
|  | ec391f93f6 | ||
|  | 27208c46ec | ||
|  | c861cf5a79 | ||
|  | e88c2dd83b | ||
|  | 67f29fcca6 | ||
|  | ee3910136d | ||
|  | ab1646f156 | ||
|  | e13896db28 | ||
|  | 44f551ff77 | ||
|  | c1cdd4815c | ||
|  | b52a90dd76 | ||
|  | a4d0d214dc | ||
|  | 248ec4304d | ||
|  | 4ceec2ca53 | ||
|  | 49a6cb75ff | ||
|  | 6d02ad0bf5 | ||
|  | 0c28eea6e2 | ||
|  | 56c7e2c453 | ||
|  | cd1b14ff1d | ||
|  | 903b1bad64 | ||
|  | aa3e14de95 | ||
|  | fb88d56652 | ||
|  | a34963ca49 | ||
|  | 8deebbdfa4 | ||
|  | b23be4b42f | ||
|  | f7a29b6daa | ||
|  | 080014cbb6 | ||
|  | d152da31ed | ||
|  | 311bfef3e3 | ||
|  | bb16b5e968 | ||
|  | b60fe675c1 | ||
|  | 0e5235b095 | ||
|  | d5fd7db23c | ||
|  | 3ec31c36b4 | ||
|  | 8d17c282e3 | ||
|  | 35e1c5b609 | ||
|  | 3b2e3ff8a0 | ||
|  | 4b11f6b06d | ||
|  | 791d534653 | ||
|  | 74d98e249d | ||
|  | 3ef002e137 | ||
|  | c758912cf2 | ||
|  | 18342b7e23 | ||
|  | 1602dd35e3 | ||
|  | 7f72bab06a | ||
|  | adbd6d0d0e | ||
|  | 2b76cf6a10 | ||
|  | f975e666ee | ||
|  | fcd5060485 | ||
|  | f627e3e22a | ||
|  | 58307bf9cf | ||
|  | 9199af9b68 | ||
|  | 4c871afb73 | ||
|  | 50b1a13c0a | 
							
								
								
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							| @@ -215,3 +215,4 @@ tags | |||||||
| pyvenv.cfg | pyvenv.cfg | ||||||
| .venv | .venv | ||||||
| pip-selfcheck.json | pip-selfcheck.json | ||||||
|  | invoice.xml | ||||||
| @@ -94,6 +94,14 @@ Ready to contribute? Here's how to set up `facho` for local development. | |||||||
|  |  | ||||||
| 7. Submit a pull request through the GitHub website. | 7. Submit a pull request through the GitHub website. | ||||||
|  |  | ||||||
|  | Using docker | ||||||
|  | ------------ | ||||||
|  |  | ||||||
|  | 1. make -f Makefile.dev build | ||||||
|  | 2. make -f Makefile.dev dev-shell | ||||||
|  | 3. make -f Makefile.dev python3.8 setup.py develop | ||||||
|  | 4. make -f Makefile.dev python3.8 setup.py test | ||||||
|  |  | ||||||
| Pull Request Guidelines | Pull Request Guidelines | ||||||
| ----------------------- | ----------------------- | ||||||
|  |  | ||||||
|   | |||||||
							
								
								
									
										40
									
								
								Dockerfile
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										40
									
								
								Dockerfile
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,40 @@ | |||||||
|  | # DERIVADO DE https://alextereshenkov.github.io/run-python-tests-with-tox-in-docker.html | ||||||
|  | FROM ubuntu:24.04 | ||||||
|  |  | ||||||
|  | RUN apt-get -qq update | ||||||
|  |  | ||||||
|  | RUN apt install software-properties-common -y \ | ||||||
|  |     && add-apt-repository ppa:deadsnakes/ppa | ||||||
|  |  | ||||||
|  | RUN apt-get install -y --no-install-recommends \ | ||||||
|  |   python3.9 python3.9-distutils python3.9-dev \ | ||||||
|  |   python3.10 python3.10-distutils python3.10-dev \ | ||||||
|  |   python3.11 python3.11-distutils python3.11-dev \ | ||||||
|  |   python3.12 python3-setuptools python3.12-dev \ | ||||||
|  |   wget \ | ||||||
|  |   ca-certificates | ||||||
|  |  | ||||||
|  | RUN wget https://bootstrap.pypa.io/get-pip.py \ | ||||||
|  |   && python3.9 get-pip.py pip==23.2.1 --break-system-packages \ | ||||||
|  |   && python3.10 get-pip.py pip==23.2.1 --break-system-packages \ | ||||||
|  |   && python3.11 get-pip.py pip==23.2.1 --break-system-packages \ | ||||||
|  |   && python3.12 get-pip.py pip==23.2.1  --break-system-packages \ | ||||||
|  |   && rm get-pip.py | ||||||
|  |  | ||||||
|  | RUN apt-get install -y --no-install-recommends \ | ||||||
|  |         libxml2-dev \ | ||||||
|  |         libxmlsec1-dev \ | ||||||
|  |         build-essential \ | ||||||
|  |         zip | ||||||
|  |  | ||||||
|  | RUN python3.9 --version | ||||||
|  | RUN python3.10 --version | ||||||
|  | RUN python3.11 --version | ||||||
|  | RUN python3.12 --version | ||||||
|  |  | ||||||
|  | RUN pip3.9 install setuptools setuptools-rust | ||||||
|  | RUN pip3.10 install setuptools setuptools-rust | ||||||
|  | RUN pip3.11 install setuptools setuptools-rust --break-system-packages | ||||||
|  | RUN pip3.12 install setuptools setuptools-rust --break-system-packages | ||||||
|  |  | ||||||
|  | RUN pip3 install tox pytest --break-system-packages | ||||||
| @@ -3,4 +3,4 @@ History | |||||||
| ======= | ======= | ||||||
|  |  | ||||||
|  |  | ||||||
| * 0.2.1 version usada en produccion. | * First release on PyPI. | ||||||
|   | |||||||
							
								
								
									
										21
									
								
								Makefile.dev
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								Makefile.dev
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,21 @@ | |||||||
|  | # Entorno de desarrollo | ||||||
|  | # | ||||||
|  | # solo es necesario una vez: | ||||||
|  | #  * make -f Makefile.dev dev-setup | ||||||
|  | # | ||||||
|  | # luego se pueden ejecutar las pruebas: | ||||||
|  | #  * make -f Makefile.dev test | ||||||
|  |  | ||||||
|  | .PHONY: dev-setup dev-shell py-develop test tox | ||||||
|  |  | ||||||
|  | dev-setup: | ||||||
|  | 	docker build -t facho . | ||||||
|  |  | ||||||
|  | dev-shell: | ||||||
|  | 	docker run --rm -ti -v "$(PWD):/app" -w /app --name facho-cli facho bash | ||||||
|  |  | ||||||
|  | test: | ||||||
|  | 	docker run -t -v $(PWD):/app -w /app facho sh -c 'cd /app; python3.12 setup.py test' | ||||||
|  |  | ||||||
|  | tox: | ||||||
|  | 	docker run -it -v $(PWD)/:/app -w /app facho tox | ||||||
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										14706
									
								
								docs/DIAN/nomina/Anexo Tecnico 11-02-2021.pdf
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14706
									
								
								docs/DIAN/nomina/Anexo Tecnico 11-02-2021.pdf
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										13
									
								
								docs/DIAN/nomina/README.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								docs/DIAN/nomina/README.md
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,13 @@ | |||||||
|  | # notas | ||||||
|  |  | ||||||
|  | * se extrae documento tecnico de resolucion usando **pdfarranger** | ||||||
|  |  | ||||||
|  | ## CUNE | ||||||
|  |  | ||||||
|  |  ver 8.1.1.1 del archivo **Resolucion 000013 de 11-02-2021.pdf** | ||||||
|  |  | ||||||
|  | # enlaces | ||||||
|  |  | ||||||
|  | * https://www.dian.gov.co/impuestos/Paginas/Sistema-de-Factura-Electronica/documento-soporte-de-pago-de-nomina-electronica.aspx | ||||||
|  | * https://bitbucket.org/presik/electronic_payroll.git | ||||||
|  | * https://bitbucket.org/presik/trytonpsk-staff_payroll_co.git | ||||||
							
								
								
									
										
											BIN
										
									
								
								docs/DIAN/nomina/Resolución 000013 de 11-02-2021.pdf
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								docs/DIAN/nomina/Resolución 000013 de 11-02-2021.pdf
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| @@ -36,6 +36,7 @@ def extensions(inv): | |||||||
|                                                                 'SETP', 990000000, 995000000)#del SET de pruebas |                                                                 'SETP', 990000000, 995000000)#del SET de pruebas | ||||||
|     return [security_code, authorization_provider, cufe, software_provider, inv_authorization] |     return [security_code, authorization_provider, cufe, software_provider, inv_authorization] | ||||||
|  |  | ||||||
|  |  | ||||||
| def invoice(): | def invoice(): | ||||||
|     # factura de venta nacional |     # factura de venta nacional | ||||||
|     inv = form.Invoice('01') |     inv = form.Invoice('01') | ||||||
| @@ -50,9 +51,10 @@ def invoice(): | |||||||
|     inv.set_supplier(form.Party( |     inv.set_supplier(form.Party( | ||||||
|         legal_name = 'Nombre registrado de la empresa', |         legal_name = 'Nombre registrado de la empresa', | ||||||
|         name='Nombre comercial o él mismo nombre registrado', |         name='Nombre comercial o él mismo nombre registrado', | ||||||
|         ident = form.PartyIdentification('nit_empresa', 'digito_verificación', '31'), |         ident=form.PartyIdentification( | ||||||
|  |             'nit_empresa', 'digito_verificación', '31'), | ||||||
|         # obligaciones del contribuyente ver DIAN:FAK26 |         # obligaciones del contribuyente ver DIAN:FAK26 | ||||||
|         responsability_code = form.Responsability(['O-07', 'O-14', 'O-48']), |         responsability_code=form.Responsability(['ZZ', 'O-14', 'O-48']), | ||||||
|         # ver DIAN:FAJ28 |         # ver DIAN:FAJ28 | ||||||
|         responsability_regime_code='48', |         responsability_regime_code='48', | ||||||
|         # tipo de organizacion juridica ver DIAN:6.2.3 |         # tipo de organizacion juridica ver DIAN:6.2.3 | ||||||
| @@ -90,11 +92,12 @@ def invoice(): | |||||||
|         payment_id='2' |         payment_id='2' | ||||||
|     )) |     )) | ||||||
|     # adicionar una linea al documento |     # adicionar una linea al documento | ||||||
|     inv.add_invoice_line(form.InvoiceLine( |     inv.add_invoice_line( | ||||||
|  |         form.InvoiceLine( | ||||||
|             quantity=form.Quantity(int(20.5), '94'), |             quantity=form.Quantity(int(20.5), '94'), | ||||||
|             # item general de codigo 999 |             # item general de codigo 999 | ||||||
|             description='productO3', |             description='productO3', | ||||||
|         item = form.StandardItem('test', 9999), |             sitem=form.StandardItem('test', 9999), | ||||||
|             price=form.Price( |             price=form.Price( | ||||||
|                 # precio base del item (sin iva) |                 # precio base del item (sin iva) | ||||||
|                 amount=form.Amount(200.00), |                 amount=form.Amount(200.00), | ||||||
| @@ -107,11 +110,11 @@ def invoice(): | |||||||
|                     form.TaxSubTotal( |                     form.TaxSubTotal( | ||||||
|                         percent=19.00, |                         percent=19.00, | ||||||
|                         scheme=form.TaxScheme('01') |                         scheme=form.TaxScheme('01') | ||||||
|                 ) |                     )] | ||||||
|             ] |  | ||||||
|             ) |             ) | ||||||
|         )) |         )) | ||||||
|     return inv |     return inv | ||||||
|  |  | ||||||
|  |  | ||||||
| def document_xml(): | def document_xml(): | ||||||
|     return form_xml.DIANInvoiceXML |     return form_xml.DIANInvoiceXML | ||||||
|   | |||||||
							
								
								
									
										93
									
								
								examples/generate-nomina-from-cli.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										93
									
								
								examples/generate-nomina-from-cli.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,93 @@ | |||||||
|  |  | ||||||
|  | from facho import fe | ||||||
|  |  | ||||||
|  | def extensions(nomina): | ||||||
|  |     return [] | ||||||
|  |  | ||||||
|  | def nomina(): | ||||||
|  |     nomina = fe.nomina.DIANNominaIndividual() | ||||||
|  |  | ||||||
|  |     nomina.asignar_metadata(fe.nomina.Metadata( | ||||||
|  |         secuencia=fe.nomina.NumeroSecuencia( | ||||||
|  |             numero = 'N00001', | ||||||
|  |             consecutivo=232 | ||||||
|  |         ), | ||||||
|  |         lugar_generacion=fe.nomina.Lugar( | ||||||
|  |             pais = fe.nomina.Pais( | ||||||
|  |                 code = 'CO' | ||||||
|  |             ), | ||||||
|  |             departamento = fe.nomina.Departamento( | ||||||
|  |                 code = '05' | ||||||
|  |             ), | ||||||
|  |             municipio = fe.nomina.Municipio( | ||||||
|  |                 code = '05001' | ||||||
|  |             ), | ||||||
|  |         ), | ||||||
|  |         proveedor=fe.nomina.Proveedor( | ||||||
|  |             nit='999999', | ||||||
|  |             dv=2, | ||||||
|  |             software_id='xx', | ||||||
|  |             software_sc='yy' | ||||||
|  |         ) | ||||||
|  |     )) | ||||||
|  |  | ||||||
|  |     nomina.asignar_informacion_general(fe.nomina.InformacionGeneral( | ||||||
|  |         fecha_generacion = '2020-01-16', | ||||||
|  |         hora_generacion = '1053:10-05:00', | ||||||
|  |         tipo_ambiente = fe.nomina.InformacionGeneral.AMBIENTE_PRODUCCION, | ||||||
|  |         software_pin = '693', | ||||||
|  |         periodo_nomina = fe.nomina.PeriodoNomina(code='1'), | ||||||
|  |         tipo_moneda = fe.nomina.TipoMoneda(code='COP') | ||||||
|  |     )) | ||||||
|  |  | ||||||
|  |     nomina.asignar_empleador(fe.nomina.Empleador( | ||||||
|  |         nit = '700085371', | ||||||
|  |         dv = '1', | ||||||
|  |         pais = fe.nomina.Pais( | ||||||
|  |             code = 'CO' | ||||||
|  |         ), | ||||||
|  |         departamento = fe.nomina.Departamento( | ||||||
|  |             code = '05' | ||||||
|  |         ), | ||||||
|  |         municipio = fe.nomina.Municipio( | ||||||
|  |             code = '05001' | ||||||
|  |         ), | ||||||
|  |         direccion = 'calle etrivial' | ||||||
|  |     )) | ||||||
|  |  | ||||||
|  |     nomina.asignar_trabajador(fe.nomina.Trabajador( | ||||||
|  |         tipo_contrato = fe.nomina.TipoContrato( | ||||||
|  |             code = '1' | ||||||
|  |         ), | ||||||
|  |         alto_riesgo = False, | ||||||
|  |         tipo_documento = fe.nomina.TipoDocumento( | ||||||
|  |             code = '11' | ||||||
|  |         ), | ||||||
|  |         primer_apellido = 'gnu', | ||||||
|  |         segundo_apellido = 'emacs', | ||||||
|  |         primer_nombre = 'facho', | ||||||
|  |         lugar_trabajo = fe.nomina.LugarTrabajo( | ||||||
|  |             pais = fe.nomina.Pais(code='CO'), | ||||||
|  |             departamento = fe.nomina.Departamento(code='05'), | ||||||
|  |             municipio = fe.nomina.Municipio(code='05001'), | ||||||
|  |             direccion = 'calle facho' | ||||||
|  |         ), | ||||||
|  |         numero_documento = '800199436', | ||||||
|  |         tipo = fe.nomina.TipoTrabajador( | ||||||
|  |             code = '01' | ||||||
|  |         ), | ||||||
|  |         salario_integral = True, | ||||||
|  |         sueldo = fe.nomina.Amount(1_500_000) | ||||||
|  |     )) | ||||||
|  |  | ||||||
|  |     nomina.adicionar_devengado(fe.nomina.DevengadoBasico( | ||||||
|  |         dias_trabajados = 60, | ||||||
|  |         sueldo_trabajado = fe.nomina.Amount(3_500_000) | ||||||
|  |     )) | ||||||
|  |  | ||||||
|  |     nomina.adicionar_deduccion(fe.nomina.DeduccionSalud( | ||||||
|  |         porcentaje = fe.nomina.Amount(19), | ||||||
|  |         deduccion = fe.nomina.Amount(1_000_000) | ||||||
|  |     )) | ||||||
|  |  | ||||||
|  |     return nomina | ||||||
| @@ -1,51 +1,70 @@ | |||||||
| # importar libreria de modelos | # importar libreria de modelos | ||||||
|  | from facho import fe, form_xml | ||||||
| import facho.fe.form as form | import facho.fe.form as form | ||||||
| import facho.fe.form_xml | import datetime | ||||||
|  |  | ||||||
| PRIVATE_KEY_PATH = 'ruta a mi llave privada' | PRIVATE_KEY_PATH = 'ruta a mi llave privada' | ||||||
| PRIVATE_PASSPHRASE = 'clave de la llave privada' | PRIVATE_PASSPHRASE = 'clave de la llave privada' | ||||||
|  |  | ||||||
|  |  | ||||||
| # consultar las extensiones necesarias | # consultar las extensiones necesarias | ||||||
| def extensions(inv): | def extensions(inv): | ||||||
|     security_code = fe.DianXMLExtensionSoftwareSecurityCode('id software', 'pin', inv.invoice_ident) |     security_code = fe.DianXMLExtensionSoftwareSecurityCode( | ||||||
|  |         'id software', 'pin', inv.invoice_ident) | ||||||
|     authorization_provider = fe.DianXMLExtensionAuthorizationProvider() |     authorization_provider = fe.DianXMLExtensionAuthorizationProvider() | ||||||
|     cufe = fe.DianXMLExtensionCUFE(inv, fe.DianXMLExtensionCUFE.AMBIENTE_PRUEBAS, |     cufe = fe.DianXMLExtensionCUFE( | ||||||
|  |         inv, fe.DianXMLExtensionCUFE.AMBIENTE_PRUEBAS, | ||||||
|         'clave tecnica') |         'clave tecnica') | ||||||
|     nit = form.PartyIdentification('nit', '5', '31') |     nit = form.PartyIdentification('nit', '5', '31') | ||||||
|     software_provider = fe.DianXMLExtensionSoftwareProvider(nit, nit.dv, 'id software') |     software_provider = fe.DianXMLExtensionSoftwareProvider( | ||||||
|     inv_authorization = fe.DianXMLExtensionInvoiceAuthorization('invoice autorization', |         nit, nit.dv, 'id software') | ||||||
|  |     inv_authorization = fe.DianXMLExtensionInvoiceAuthorization( | ||||||
|  |         'invoice autorization', | ||||||
|         datetime(2019, 1, 19), |         datetime(2019, 1, 19), | ||||||
|         datetime(2030, 1, 19), |         datetime(2030, 1, 19), | ||||||
|         'SETP', 990000001, 995000000) |         'SETP', 990000001, 995000000) | ||||||
|     return [security_code, authorization_provider, cufe, software_provider, inv_authorization] |     return [ | ||||||
|  |         security_code, | ||||||
|  |         authorization_provider, | ||||||
|  |         cufe, software_provider, | ||||||
|  |         inv_authorization | ||||||
|  |     ] | ||||||
|  |  | ||||||
|  |  | ||||||
| # generar documento desde modelo a ruta indicada | # generar documento desde modelo a ruta indicada | ||||||
| def generate_document(invoice, filepath): | def generate_document(invoice, filepath): | ||||||
|     xml = form_xml.DIANInvoiceXML(invoice) |     xml = form_xml.DIANInvoiceXML(invoice) | ||||||
|     for extension in extensions(invoice): |     for extension in extensions(invoice): | ||||||
|         xml.add_extension(extension) |         xml.add_extension(extension) | ||||||
|     form_xml.utils.DIANWriteSigned(xml, filepath, PRIVATE_KEY_PATH, PRIVATE_PASSPHRASE, True) |     form_xml.utils.DIANWriteSigned( | ||||||
|  |         xml, filepath, PRIVATE_KEY_PATH, PRIVATE_PASSPHRASE, True) | ||||||
|  |  | ||||||
|  |  | ||||||
| # Modelars las facturas | # Modelars las facturas | ||||||
| # ... | # ... | ||||||
|  |  | ||||||
| # factura de venta nacional | # factura de venta nacional | ||||||
| inv = form.NationalSalesInvoice() | inv = form.NationalSalesInvoice() | ||||||
|  |  | ||||||
| # asignar periodo de facturacion | # asignar periodo de facturacion | ||||||
| inv.set_period(datetime.now(), datetime.now()) | inv.set_period(datetime.now(), datetime.now()) | ||||||
|  |  | ||||||
| # asignar fecha de emision de la factura | # asignar fecha de emision de la factura | ||||||
|  |  | ||||||
| inv.set_issue(datetime.now()) | inv.set_issue(datetime.now()) | ||||||
| # asignar prefijo y numero del documento | # asignar prefijo y numero del documento | ||||||
|  |  | ||||||
| inv.set_ident('SETP990003033') | inv.set_ident('SETP990003033') | ||||||
| # asignar tipo de operacion ver DIAN:6.1.5 | # asignar tipo de operacion ver DIAN:6.1.5 | ||||||
| inv.set_operation_type('10') | inv.set_operation_type('10') | ||||||
|  |  | ||||||
| # asignar proveedor | # asignar proveedor | ||||||
| inv.set_supplier(form.Party( | inv.set_supplier(form.Party( | ||||||
|     legal_name='FACHOSOS', |     legal_name='FACHOSOS', | ||||||
|     name='FACHOSOS', |     name='FACHOSOS', | ||||||
|     ident=form.PartyIdentification('900579212', '5', '31'), |     ident=form.PartyIdentification('900579212', '5', '31'), | ||||||
|     # obligaciones del contribuyente ver DIAN:FAK26 |     # obligaciones del contribuyente ver DIAN:FAK26 | ||||||
|     responsability_code = form.Responsability(['O-07', 'O-09', 'O-14', 'O-48']), |     responsability_code=form.Responsability(['ZZ', 'O-09', 'O-14', 'O-48']), | ||||||
|     # ver DIAN:FAJ28 |     # ver DIAN:FAJ28 | ||||||
|     responsability_regime_code='48', |     responsability_regime_code='48', | ||||||
|     # tipo de organizacion juridica ver DIAN:6.2.3 |     # tipo de organizacion juridica ver DIAN:6.2.3 | ||||||
| @@ -58,6 +77,7 @@ inv.set_supplier(form.Party( | |||||||
|         country=form.Country('CO', 'Colombia'), |         country=form.Country('CO', 'Colombia'), | ||||||
|         countrysubentity=form.CountrySubentity('05', 'Antioquia')) |         countrysubentity=form.CountrySubentity('05', 'Antioquia')) | ||||||
| )) | )) | ||||||
|  |  | ||||||
| inv.set_customer(form.Party( | inv.set_customer(form.Party( | ||||||
|     legal_name='facho-customer', |     legal_name='facho-customer', | ||||||
|     name='facho-customer', |     name='facho-customer', | ||||||
| @@ -81,7 +101,6 @@ inv.set_payment_mean(form.PaymentMean( | |||||||
|     code='10', |     code='10', | ||||||
|     # fecha de vencimiento de la factura |     # fecha de vencimiento de la factura | ||||||
|     due_at=datetime.now(), |     due_at=datetime.now(), | ||||||
|      |  | ||||||
|     # identificador numerico |     # identificador numerico | ||||||
|     payment_id='1' |     payment_id='1' | ||||||
| )) | )) | ||||||
| @@ -102,8 +121,7 @@ inv.add_invoice_line(form.InvoiceLine( | |||||||
|         subtotals=[ |         subtotals=[ | ||||||
|             form.TaxSubTotal( |             form.TaxSubTotal( | ||||||
|                 percent=19.00, |                 percent=19.00, | ||||||
|             ) |             )] | ||||||
|         ] |  | ||||||
|     ) |     ) | ||||||
| )) | )) | ||||||
|  |  | ||||||
|   | |||||||
							
								
								
									
										0
									
								
								experimental/facho-signer/AUTHORS
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								experimental/facho-signer/AUTHORS
									
									
									
									
									
										Normal file
									
								
							
							
								
								
									
										674
									
								
								experimental/facho-signer/COPYING
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										674
									
								
								experimental/facho-signer/COPYING
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,674 @@ | |||||||
|  |                     GNU GENERAL PUBLIC LICENSE | ||||||
|  |                        Version 3, 29 June 2007 | ||||||
|  |  | ||||||
|  |  Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/> | ||||||
|  |  Everyone is permitted to copy and distribute verbatim copies | ||||||
|  |  of this license document, but changing it is not allowed. | ||||||
|  |  | ||||||
|  |                             Preamble | ||||||
|  |  | ||||||
|  |   The GNU General Public License is a free, copyleft license for | ||||||
|  | software and other kinds of works. | ||||||
|  |  | ||||||
|  |   The licenses for most software and other practical works are designed | ||||||
|  | to take away your freedom to share and change the works.  By contrast, | ||||||
|  | the GNU General Public License is intended to guarantee your freedom to | ||||||
|  | share and change all versions of a program--to make sure it remains free | ||||||
|  | software for all its users.  We, the Free Software Foundation, use the | ||||||
|  | GNU General Public License for most of our software; it applies also to | ||||||
|  | any other work released this way by its authors.  You can apply it to | ||||||
|  | your programs, too. | ||||||
|  |  | ||||||
|  |   When we speak of free software, we are referring to freedom, not | ||||||
|  | price.  Our General Public Licenses are designed to make sure that you | ||||||
|  | have the freedom to distribute copies of free software (and charge for | ||||||
|  | them if you wish), that you receive source code or can get it if you | ||||||
|  | want it, that you can change the software or use pieces of it in new | ||||||
|  | free programs, and that you know you can do these things. | ||||||
|  |  | ||||||
|  |   To protect your rights, we need to prevent others from denying you | ||||||
|  | these rights or asking you to surrender the rights.  Therefore, you have | ||||||
|  | certain responsibilities if you distribute copies of the software, or if | ||||||
|  | you modify it: responsibilities to respect the freedom of others. | ||||||
|  |  | ||||||
|  |   For example, if you distribute copies of such a program, whether | ||||||
|  | gratis or for a fee, you must pass on to the recipients the same | ||||||
|  | freedoms that you received.  You must make sure that they, too, receive | ||||||
|  | or can get the source code.  And you must show them these terms so they | ||||||
|  | know their rights. | ||||||
|  |  | ||||||
|  |   Developers that use the GNU GPL protect your rights with two steps: | ||||||
|  | (1) assert copyright on the software, and (2) offer you this License | ||||||
|  | giving you legal permission to copy, distribute and/or modify it. | ||||||
|  |  | ||||||
|  |   For the developers' and authors' protection, the GPL clearly explains | ||||||
|  | that there is no warranty for this free software.  For both users' and | ||||||
|  | authors' sake, the GPL requires that modified versions be marked as | ||||||
|  | changed, so that their problems will not be attributed erroneously to | ||||||
|  | authors of previous versions. | ||||||
|  |  | ||||||
|  |   Some devices are designed to deny users access to install or run | ||||||
|  | modified versions of the software inside them, although the manufacturer | ||||||
|  | can do so.  This is fundamentally incompatible with the aim of | ||||||
|  | protecting users' freedom to change the software.  The systematic | ||||||
|  | pattern of such abuse occurs in the area of products for individuals to | ||||||
|  | use, which is precisely where it is most unacceptable.  Therefore, we | ||||||
|  | have designed this version of the GPL to prohibit the practice for those | ||||||
|  | products.  If such problems arise substantially in other domains, we | ||||||
|  | stand ready to extend this provision to those domains in future versions | ||||||
|  | of the GPL, as needed to protect the freedom of users. | ||||||
|  |  | ||||||
|  |   Finally, every program is threatened constantly by software patents. | ||||||
|  | States should not allow patents to restrict development and use of | ||||||
|  | software on general-purpose computers, but in those that do, we wish to | ||||||
|  | avoid the special danger that patents applied to a free program could | ||||||
|  | make it effectively proprietary.  To prevent this, the GPL assures that | ||||||
|  | patents cannot be used to render the program non-free. | ||||||
|  |  | ||||||
|  |   The precise terms and conditions for copying, distribution and | ||||||
|  | modification follow. | ||||||
|  |  | ||||||
|  |                        TERMS AND CONDITIONS | ||||||
|  |  | ||||||
|  |   0. Definitions. | ||||||
|  |  | ||||||
|  |   "This License" refers to version 3 of the GNU General Public License. | ||||||
|  |  | ||||||
|  |   "Copyright" also means copyright-like laws that apply to other kinds of | ||||||
|  | works, such as semiconductor masks. | ||||||
|  |  | ||||||
|  |   "The Program" refers to any copyrightable work licensed under this | ||||||
|  | License.  Each licensee is addressed as "you".  "Licensees" and | ||||||
|  | "recipients" may be individuals or organizations. | ||||||
|  |  | ||||||
|  |   To "modify" a work means to copy from or adapt all or part of the work | ||||||
|  | in a fashion requiring copyright permission, other than the making of an | ||||||
|  | exact copy.  The resulting work is called a "modified version" of the | ||||||
|  | earlier work or a work "based on" the earlier work. | ||||||
|  |  | ||||||
|  |   A "covered work" means either the unmodified Program or a work based | ||||||
|  | on the Program. | ||||||
|  |  | ||||||
|  |   To "propagate" a work means to do anything with it that, without | ||||||
|  | permission, would make you directly or secondarily liable for | ||||||
|  | infringement under applicable copyright law, except executing it on a | ||||||
|  | computer or modifying a private copy.  Propagation includes copying, | ||||||
|  | distribution (with or without modification), making available to the | ||||||
|  | public, and in some countries other activities as well. | ||||||
|  |  | ||||||
|  |   To "convey" a work means any kind of propagation that enables other | ||||||
|  | parties to make or receive copies.  Mere interaction with a user through | ||||||
|  | a computer network, with no transfer of a copy, is not conveying. | ||||||
|  |  | ||||||
|  |   An interactive user interface displays "Appropriate Legal Notices" | ||||||
|  | to the extent that it includes a convenient and prominently visible | ||||||
|  | feature that (1) displays an appropriate copyright notice, and (2) | ||||||
|  | tells the user that there is no warranty for the work (except to the | ||||||
|  | extent that warranties are provided), that licensees may convey the | ||||||
|  | work under this License, and how to view a copy of this License.  If | ||||||
|  | the interface presents a list of user commands or options, such as a | ||||||
|  | menu, a prominent item in the list meets this criterion. | ||||||
|  |  | ||||||
|  |   1. Source Code. | ||||||
|  |  | ||||||
|  |   The "source code" for a work means the preferred form of the work | ||||||
|  | for making modifications to it.  "Object code" means any non-source | ||||||
|  | form of a work. | ||||||
|  |  | ||||||
|  |   A "Standard Interface" means an interface that either is an official | ||||||
|  | standard defined by a recognized standards body, or, in the case of | ||||||
|  | interfaces specified for a particular programming language, one that | ||||||
|  | is widely used among developers working in that language. | ||||||
|  |  | ||||||
|  |   The "System Libraries" of an executable work include anything, other | ||||||
|  | than the work as a whole, that (a) is included in the normal form of | ||||||
|  | packaging a Major Component, but which is not part of that Major | ||||||
|  | Component, and (b) serves only to enable use of the work with that | ||||||
|  | Major Component, or to implement a Standard Interface for which an | ||||||
|  | implementation is available to the public in source code form.  A | ||||||
|  | "Major Component", in this context, means a major essential component | ||||||
|  | (kernel, window system, and so on) of the specific operating system | ||||||
|  | (if any) on which the executable work runs, or a compiler used to | ||||||
|  | produce the work, or an object code interpreter used to run it. | ||||||
|  |  | ||||||
|  |   The "Corresponding Source" for a work in object code form means all | ||||||
|  | the source code needed to generate, install, and (for an executable | ||||||
|  | work) run the object code and to modify the work, including scripts to | ||||||
|  | control those activities.  However, it does not include the work's | ||||||
|  | System Libraries, or general-purpose tools or generally available free | ||||||
|  | programs which are used unmodified in performing those activities but | ||||||
|  | which are not part of the work.  For example, Corresponding Source | ||||||
|  | includes interface definition files associated with source files for | ||||||
|  | the work, and the source code for shared libraries and dynamically | ||||||
|  | linked subprograms that the work is specifically designed to require, | ||||||
|  | such as by intimate data communication or control flow between those | ||||||
|  | subprograms and other parts of the work. | ||||||
|  |  | ||||||
|  |   The Corresponding Source need not include anything that users | ||||||
|  | can regenerate automatically from other parts of the Corresponding | ||||||
|  | Source. | ||||||
|  |  | ||||||
|  |   The Corresponding Source for a work in source code form is that | ||||||
|  | same work. | ||||||
|  |  | ||||||
|  |   2. Basic Permissions. | ||||||
|  |  | ||||||
|  |   All rights granted under this License are granted for the term of | ||||||
|  | copyright on the Program, and are irrevocable provided the stated | ||||||
|  | conditions are met.  This License explicitly affirms your unlimited | ||||||
|  | permission to run the unmodified Program.  The output from running a | ||||||
|  | covered work is covered by this License only if the output, given its | ||||||
|  | content, constitutes a covered work.  This License acknowledges your | ||||||
|  | rights of fair use or other equivalent, as provided by copyright law. | ||||||
|  |  | ||||||
|  |   You may make, run and propagate covered works that you do not | ||||||
|  | convey, without conditions so long as your license otherwise remains | ||||||
|  | in force.  You may convey covered works to others for the sole purpose | ||||||
|  | of having them make modifications exclusively for you, or provide you | ||||||
|  | with facilities for running those works, provided that you comply with | ||||||
|  | the terms of this License in conveying all material for which you do | ||||||
|  | not control copyright.  Those thus making or running the covered works | ||||||
|  | for you must do so exclusively on your behalf, under your direction | ||||||
|  | and control, on terms that prohibit them from making any copies of | ||||||
|  | your copyrighted material outside their relationship with you. | ||||||
|  |  | ||||||
|  |   Conveying under any other circumstances is permitted solely under | ||||||
|  | the conditions stated below.  Sublicensing is not allowed; section 10 | ||||||
|  | makes it unnecessary. | ||||||
|  |  | ||||||
|  |   3. Protecting Users' Legal Rights From Anti-Circumvention Law. | ||||||
|  |  | ||||||
|  |   No covered work shall be deemed part of an effective technological | ||||||
|  | measure under any applicable law fulfilling obligations under article | ||||||
|  | 11 of the WIPO copyright treaty adopted on 20 December 1996, or | ||||||
|  | similar laws prohibiting or restricting circumvention of such | ||||||
|  | measures. | ||||||
|  |  | ||||||
|  |   When you convey a covered work, you waive any legal power to forbid | ||||||
|  | circumvention of technological measures to the extent such circumvention | ||||||
|  | is effected by exercising rights under this License with respect to | ||||||
|  | the covered work, and you disclaim any intention to limit operation or | ||||||
|  | modification of the work as a means of enforcing, against the work's | ||||||
|  | users, your or third parties' legal rights to forbid circumvention of | ||||||
|  | technological measures. | ||||||
|  |  | ||||||
|  |   4. Conveying Verbatim Copies. | ||||||
|  |  | ||||||
|  |   You may convey verbatim copies of the Program's source code as you | ||||||
|  | receive it, in any medium, provided that you conspicuously and | ||||||
|  | appropriately publish on each copy an appropriate copyright notice; | ||||||
|  | keep intact all notices stating that this License and any | ||||||
|  | non-permissive terms added in accord with section 7 apply to the code; | ||||||
|  | keep intact all notices of the absence of any warranty; and give all | ||||||
|  | recipients a copy of this License along with the Program. | ||||||
|  |  | ||||||
|  |   You may charge any price or no price for each copy that you convey, | ||||||
|  | and you may offer support or warranty protection for a fee. | ||||||
|  |  | ||||||
|  |   5. Conveying Modified Source Versions. | ||||||
|  |  | ||||||
|  |   You may convey a work based on the Program, or the modifications to | ||||||
|  | produce it from the Program, in the form of source code under the | ||||||
|  | terms of section 4, provided that you also meet all of these conditions: | ||||||
|  |  | ||||||
|  |     a) The work must carry prominent notices stating that you modified | ||||||
|  |     it, and giving a relevant date. | ||||||
|  |  | ||||||
|  |     b) The work must carry prominent notices stating that it is | ||||||
|  |     released under this License and any conditions added under section | ||||||
|  |     7.  This requirement modifies the requirement in section 4 to | ||||||
|  |     "keep intact all notices". | ||||||
|  |  | ||||||
|  |     c) You must license the entire work, as a whole, under this | ||||||
|  |     License to anyone who comes into possession of a copy.  This | ||||||
|  |     License will therefore apply, along with any applicable section 7 | ||||||
|  |     additional terms, to the whole of the work, and all its parts, | ||||||
|  |     regardless of how they are packaged.  This License gives no | ||||||
|  |     permission to license the work in any other way, but it does not | ||||||
|  |     invalidate such permission if you have separately received it. | ||||||
|  |  | ||||||
|  |     d) If the work has interactive user interfaces, each must display | ||||||
|  |     Appropriate Legal Notices; however, if the Program has interactive | ||||||
|  |     interfaces that do not display Appropriate Legal Notices, your | ||||||
|  |     work need not make them do so. | ||||||
|  |  | ||||||
|  |   A compilation of a covered work with other separate and independent | ||||||
|  | works, which are not by their nature extensions of the covered work, | ||||||
|  | and which are not combined with it such as to form a larger program, | ||||||
|  | in or on a volume of a storage or distribution medium, is called an | ||||||
|  | "aggregate" if the compilation and its resulting copyright are not | ||||||
|  | used to limit the access or legal rights of the compilation's users | ||||||
|  | beyond what the individual works permit.  Inclusion of a covered work | ||||||
|  | in an aggregate does not cause this License to apply to the other | ||||||
|  | parts of the aggregate. | ||||||
|  |  | ||||||
|  |   6. Conveying Non-Source Forms. | ||||||
|  |  | ||||||
|  |   You may convey a covered work in object code form under the terms | ||||||
|  | of sections 4 and 5, provided that you also convey the | ||||||
|  | machine-readable Corresponding Source under the terms of this License, | ||||||
|  | in one of these ways: | ||||||
|  |  | ||||||
|  |     a) Convey the object code in, or embodied in, a physical product | ||||||
|  |     (including a physical distribution medium), accompanied by the | ||||||
|  |     Corresponding Source fixed on a durable physical medium | ||||||
|  |     customarily used for software interchange. | ||||||
|  |  | ||||||
|  |     b) Convey the object code in, or embodied in, a physical product | ||||||
|  |     (including a physical distribution medium), accompanied by a | ||||||
|  |     written offer, valid for at least three years and valid for as | ||||||
|  |     long as you offer spare parts or customer support for that product | ||||||
|  |     model, to give anyone who possesses the object code either (1) a | ||||||
|  |     copy of the Corresponding Source for all the software in the | ||||||
|  |     product that is covered by this License, on a durable physical | ||||||
|  |     medium customarily used for software interchange, for a price no | ||||||
|  |     more than your reasonable cost of physically performing this | ||||||
|  |     conveying of source, or (2) access to copy the | ||||||
|  |     Corresponding Source from a network server at no charge. | ||||||
|  |  | ||||||
|  |     c) Convey individual copies of the object code with a copy of the | ||||||
|  |     written offer to provide the Corresponding Source.  This | ||||||
|  |     alternative is allowed only occasionally and noncommercially, and | ||||||
|  |     only if you received the object code with such an offer, in accord | ||||||
|  |     with subsection 6b. | ||||||
|  |  | ||||||
|  |     d) Convey the object code by offering access from a designated | ||||||
|  |     place (gratis or for a charge), and offer equivalent access to the | ||||||
|  |     Corresponding Source in the same way through the same place at no | ||||||
|  |     further charge.  You need not require recipients to copy the | ||||||
|  |     Corresponding Source along with the object code.  If the place to | ||||||
|  |     copy the object code is a network server, the Corresponding Source | ||||||
|  |     may be on a different server (operated by you or a third party) | ||||||
|  |     that supports equivalent copying facilities, provided you maintain | ||||||
|  |     clear directions next to the object code saying where to find the | ||||||
|  |     Corresponding Source.  Regardless of what server hosts the | ||||||
|  |     Corresponding Source, you remain obligated to ensure that it is | ||||||
|  |     available for as long as needed to satisfy these requirements. | ||||||
|  |  | ||||||
|  |     e) Convey the object code using peer-to-peer transmission, provided | ||||||
|  |     you inform other peers where the object code and Corresponding | ||||||
|  |     Source of the work are being offered to the general public at no | ||||||
|  |     charge under subsection 6d. | ||||||
|  |  | ||||||
|  |   A separable portion of the object code, whose source code is excluded | ||||||
|  | from the Corresponding Source as a System Library, need not be | ||||||
|  | included in conveying the object code work. | ||||||
|  |  | ||||||
|  |   A "User Product" is either (1) a "consumer product", which means any | ||||||
|  | tangible personal property which is normally used for personal, family, | ||||||
|  | or household purposes, or (2) anything designed or sold for incorporation | ||||||
|  | into a dwelling.  In determining whether a product is a consumer product, | ||||||
|  | doubtful cases shall be resolved in favor of coverage.  For a particular | ||||||
|  | product received by a particular user, "normally used" refers to a | ||||||
|  | typical or common use of that class of product, regardless of the status | ||||||
|  | of the particular user or of the way in which the particular user | ||||||
|  | actually uses, or expects or is expected to use, the product.  A product | ||||||
|  | is a consumer product regardless of whether the product has substantial | ||||||
|  | commercial, industrial or non-consumer uses, unless such uses represent | ||||||
|  | the only significant mode of use of the product. | ||||||
|  |  | ||||||
|  |   "Installation Information" for a User Product means any methods, | ||||||
|  | procedures, authorization keys, or other information required to install | ||||||
|  | and execute modified versions of a covered work in that User Product from | ||||||
|  | a modified version of its Corresponding Source.  The information must | ||||||
|  | suffice to ensure that the continued functioning of the modified object | ||||||
|  | code is in no case prevented or interfered with solely because | ||||||
|  | modification has been made. | ||||||
|  |  | ||||||
|  |   If you convey an object code work under this section in, or with, or | ||||||
|  | specifically for use in, a User Product, and the conveying occurs as | ||||||
|  | part of a transaction in which the right of possession and use of the | ||||||
|  | User Product is transferred to the recipient in perpetuity or for a | ||||||
|  | fixed term (regardless of how the transaction is characterized), the | ||||||
|  | Corresponding Source conveyed under this section must be accompanied | ||||||
|  | by the Installation Information.  But this requirement does not apply | ||||||
|  | if neither you nor any third party retains the ability to install | ||||||
|  | modified object code on the User Product (for example, the work has | ||||||
|  | been installed in ROM). | ||||||
|  |  | ||||||
|  |   The requirement to provide Installation Information does not include a | ||||||
|  | requirement to continue to provide support service, warranty, or updates | ||||||
|  | for a work that has been modified or installed by the recipient, or for | ||||||
|  | the User Product in which it has been modified or installed.  Access to a | ||||||
|  | network may be denied when the modification itself materially and | ||||||
|  | adversely affects the operation of the network or violates the rules and | ||||||
|  | protocols for communication across the network. | ||||||
|  |  | ||||||
|  |   Corresponding Source conveyed, and Installation Information provided, | ||||||
|  | in accord with this section must be in a format that is publicly | ||||||
|  | documented (and with an implementation available to the public in | ||||||
|  | source code form), and must require no special password or key for | ||||||
|  | unpacking, reading or copying. | ||||||
|  |  | ||||||
|  |   7. Additional Terms. | ||||||
|  |  | ||||||
|  |   "Additional permissions" are terms that supplement the terms of this | ||||||
|  | License by making exceptions from one or more of its conditions. | ||||||
|  | Additional permissions that are applicable to the entire Program shall | ||||||
|  | be treated as though they were included in this License, to the extent | ||||||
|  | that they are valid under applicable law.  If additional permissions | ||||||
|  | apply only to part of the Program, that part may be used separately | ||||||
|  | under those permissions, but the entire Program remains governed by | ||||||
|  | this License without regard to the additional permissions. | ||||||
|  |  | ||||||
|  |   When you convey a copy of a covered work, you may at your option | ||||||
|  | remove any additional permissions from that copy, or from any part of | ||||||
|  | it.  (Additional permissions may be written to require their own | ||||||
|  | removal in certain cases when you modify the work.)  You may place | ||||||
|  | additional permissions on material, added by you to a covered work, | ||||||
|  | for which you have or can give appropriate copyright permission. | ||||||
|  |  | ||||||
|  |   Notwithstanding any other provision of this License, for material you | ||||||
|  | add to a covered work, you may (if authorized by the copyright holders of | ||||||
|  | that material) supplement the terms of this License with terms: | ||||||
|  |  | ||||||
|  |     a) Disclaiming warranty or limiting liability differently from the | ||||||
|  |     terms of sections 15 and 16 of this License; or | ||||||
|  |  | ||||||
|  |     b) Requiring preservation of specified reasonable legal notices or | ||||||
|  |     author attributions in that material or in the Appropriate Legal | ||||||
|  |     Notices displayed by works containing it; or | ||||||
|  |  | ||||||
|  |     c) Prohibiting misrepresentation of the origin of that material, or | ||||||
|  |     requiring that modified versions of such material be marked in | ||||||
|  |     reasonable ways as different from the original version; or | ||||||
|  |  | ||||||
|  |     d) Limiting the use for publicity purposes of names of licensors or | ||||||
|  |     authors of the material; or | ||||||
|  |  | ||||||
|  |     e) Declining to grant rights under trademark law for use of some | ||||||
|  |     trade names, trademarks, or service marks; or | ||||||
|  |  | ||||||
|  |     f) Requiring indemnification of licensors and authors of that | ||||||
|  |     material by anyone who conveys the material (or modified versions of | ||||||
|  |     it) with contractual assumptions of liability to the recipient, for | ||||||
|  |     any liability that these contractual assumptions directly impose on | ||||||
|  |     those licensors and authors. | ||||||
|  |  | ||||||
|  |   All other non-permissive additional terms are considered "further | ||||||
|  | restrictions" within the meaning of section 10.  If the Program as you | ||||||
|  | received it, or any part of it, contains a notice stating that it is | ||||||
|  | governed by this License along with a term that is a further | ||||||
|  | restriction, you may remove that term.  If a license document contains | ||||||
|  | a further restriction but permits relicensing or conveying under this | ||||||
|  | License, you may add to a covered work material governed by the terms | ||||||
|  | of that license document, provided that the further restriction does | ||||||
|  | not survive such relicensing or conveying. | ||||||
|  |  | ||||||
|  |   If you add terms to a covered work in accord with this section, you | ||||||
|  | must place, in the relevant source files, a statement of the | ||||||
|  | additional terms that apply to those files, or a notice indicating | ||||||
|  | where to find the applicable terms. | ||||||
|  |  | ||||||
|  |   Additional terms, permissive or non-permissive, may be stated in the | ||||||
|  | form of a separately written license, or stated as exceptions; | ||||||
|  | the above requirements apply either way. | ||||||
|  |  | ||||||
|  |   8. Termination. | ||||||
|  |  | ||||||
|  |   You may not propagate or modify a covered work except as expressly | ||||||
|  | provided under this License.  Any attempt otherwise to propagate or | ||||||
|  | modify it is void, and will automatically terminate your rights under | ||||||
|  | this License (including any patent licenses granted under the third | ||||||
|  | paragraph of section 11). | ||||||
|  |  | ||||||
|  |   However, if you cease all violation of this License, then your | ||||||
|  | license from a particular copyright holder is reinstated (a) | ||||||
|  | provisionally, unless and until the copyright holder explicitly and | ||||||
|  | finally terminates your license, and (b) permanently, if the copyright | ||||||
|  | holder fails to notify you of the violation by some reasonable means | ||||||
|  | prior to 60 days after the cessation. | ||||||
|  |  | ||||||
|  |   Moreover, your license from a particular copyright holder is | ||||||
|  | reinstated permanently if the copyright holder notifies you of the | ||||||
|  | violation by some reasonable means, this is the first time you have | ||||||
|  | received notice of violation of this License (for any work) from that | ||||||
|  | copyright holder, and you cure the violation prior to 30 days after | ||||||
|  | your receipt of the notice. | ||||||
|  |  | ||||||
|  |   Termination of your rights under this section does not terminate the | ||||||
|  | licenses of parties who have received copies or rights from you under | ||||||
|  | this License.  If your rights have been terminated and not permanently | ||||||
|  | reinstated, you do not qualify to receive new licenses for the same | ||||||
|  | material under section 10. | ||||||
|  |  | ||||||
|  |   9. Acceptance Not Required for Having Copies. | ||||||
|  |  | ||||||
|  |   You are not required to accept this License in order to receive or | ||||||
|  | run a copy of the Program.  Ancillary propagation of a covered work | ||||||
|  | occurring solely as a consequence of using peer-to-peer transmission | ||||||
|  | to receive a copy likewise does not require acceptance.  However, | ||||||
|  | nothing other than this License grants you permission to propagate or | ||||||
|  | modify any covered work.  These actions infringe copyright if you do | ||||||
|  | not accept this License.  Therefore, by modifying or propagating a | ||||||
|  | covered work, you indicate your acceptance of this License to do so. | ||||||
|  |  | ||||||
|  |   10. Automatic Licensing of Downstream Recipients. | ||||||
|  |  | ||||||
|  |   Each time you convey a covered work, the recipient automatically | ||||||
|  | receives a license from the original licensors, to run, modify and | ||||||
|  | propagate that work, subject to this License.  You are not responsible | ||||||
|  | for enforcing compliance by third parties with this License. | ||||||
|  |  | ||||||
|  |   An "entity transaction" is a transaction transferring control of an | ||||||
|  | organization, or substantially all assets of one, or subdividing an | ||||||
|  | organization, or merging organizations.  If propagation of a covered | ||||||
|  | work results from an entity transaction, each party to that | ||||||
|  | transaction who receives a copy of the work also receives whatever | ||||||
|  | licenses to the work the party's predecessor in interest had or could | ||||||
|  | give under the previous paragraph, plus a right to possession of the | ||||||
|  | Corresponding Source of the work from the predecessor in interest, if | ||||||
|  | the predecessor has it or can get it with reasonable efforts. | ||||||
|  |  | ||||||
|  |   You may not impose any further restrictions on the exercise of the | ||||||
|  | rights granted or affirmed under this License.  For example, you may | ||||||
|  | not impose a license fee, royalty, or other charge for exercise of | ||||||
|  | rights granted under this License, and you may not initiate litigation | ||||||
|  | (including a cross-claim or counterclaim in a lawsuit) alleging that | ||||||
|  | any patent claim is infringed by making, using, selling, offering for | ||||||
|  | sale, or importing the Program or any portion of it. | ||||||
|  |  | ||||||
|  |   11. Patents. | ||||||
|  |  | ||||||
|  |   A "contributor" is a copyright holder who authorizes use under this | ||||||
|  | License of the Program or a work on which the Program is based.  The | ||||||
|  | work thus licensed is called the contributor's "contributor version". | ||||||
|  |  | ||||||
|  |   A contributor's "essential patent claims" are all patent claims | ||||||
|  | owned or controlled by the contributor, whether already acquired or | ||||||
|  | hereafter acquired, that would be infringed by some manner, permitted | ||||||
|  | by this License, of making, using, or selling its contributor version, | ||||||
|  | but do not include claims that would be infringed only as a | ||||||
|  | consequence of further modification of the contributor version.  For | ||||||
|  | purposes of this definition, "control" includes the right to grant | ||||||
|  | patent sublicenses in a manner consistent with the requirements of | ||||||
|  | this License. | ||||||
|  |  | ||||||
|  |   Each contributor grants you a non-exclusive, worldwide, royalty-free | ||||||
|  | patent license under the contributor's essential patent claims, to | ||||||
|  | make, use, sell, offer for sale, import and otherwise run, modify and | ||||||
|  | propagate the contents of its contributor version. | ||||||
|  |  | ||||||
|  |   In the following three paragraphs, a "patent license" is any express | ||||||
|  | agreement or commitment, however denominated, not to enforce a patent | ||||||
|  | (such as an express permission to practice a patent or covenant not to | ||||||
|  | sue for patent infringement).  To "grant" such a patent license to a | ||||||
|  | party means to make such an agreement or commitment not to enforce a | ||||||
|  | patent against the party. | ||||||
|  |  | ||||||
|  |   If you convey a covered work, knowingly relying on a patent license, | ||||||
|  | and the Corresponding Source of the work is not available for anyone | ||||||
|  | to copy, free of charge and under the terms of this License, through a | ||||||
|  | publicly available network server or other readily accessible means, | ||||||
|  | then you must either (1) cause the Corresponding Source to be so | ||||||
|  | available, or (2) arrange to deprive yourself of the benefit of the | ||||||
|  | patent license for this particular work, or (3) arrange, in a manner | ||||||
|  | consistent with the requirements of this License, to extend the patent | ||||||
|  | license to downstream recipients.  "Knowingly relying" means you have | ||||||
|  | actual knowledge that, but for the patent license, your conveying the | ||||||
|  | covered work in a country, or your recipient's use of the covered work | ||||||
|  | in a country, would infringe one or more identifiable patents in that | ||||||
|  | country that you have reason to believe are valid. | ||||||
|  |  | ||||||
|  |   If, pursuant to or in connection with a single transaction or | ||||||
|  | arrangement, you convey, or propagate by procuring conveyance of, a | ||||||
|  | covered work, and grant a patent license to some of the parties | ||||||
|  | receiving the covered work authorizing them to use, propagate, modify | ||||||
|  | or convey a specific copy of the covered work, then the patent license | ||||||
|  | you grant is automatically extended to all recipients of the covered | ||||||
|  | work and works based on it. | ||||||
|  |  | ||||||
|  |   A patent license is "discriminatory" if it does not include within | ||||||
|  | the scope of its coverage, prohibits the exercise of, or is | ||||||
|  | conditioned on the non-exercise of one or more of the rights that are | ||||||
|  | specifically granted under this License.  You may not convey a covered | ||||||
|  | work if you are a party to an arrangement with a third party that is | ||||||
|  | in the business of distributing software, under which you make payment | ||||||
|  | to the third party based on the extent of your activity of conveying | ||||||
|  | the work, and under which the third party grants, to any of the | ||||||
|  | parties who would receive the covered work from you, a discriminatory | ||||||
|  | patent license (a) in connection with copies of the covered work | ||||||
|  | conveyed by you (or copies made from those copies), or (b) primarily | ||||||
|  | for and in connection with specific products or compilations that | ||||||
|  | contain the covered work, unless you entered into that arrangement, | ||||||
|  | or that patent license was granted, prior to 28 March 2007. | ||||||
|  |  | ||||||
|  |   Nothing in this License shall be construed as excluding or limiting | ||||||
|  | any implied license or other defenses to infringement that may | ||||||
|  | otherwise be available to you under applicable patent law. | ||||||
|  |  | ||||||
|  |   12. No Surrender of Others' Freedom. | ||||||
|  |  | ||||||
|  |   If conditions are imposed on you (whether by court order, agreement or | ||||||
|  | otherwise) that contradict the conditions of this License, they do not | ||||||
|  | excuse you from the conditions of this License.  If you cannot convey a | ||||||
|  | covered work so as to satisfy simultaneously your obligations under this | ||||||
|  | License and any other pertinent obligations, then as a consequence you may | ||||||
|  | not convey it at all.  For example, if you agree to terms that obligate you | ||||||
|  | to collect a royalty for further conveying from those to whom you convey | ||||||
|  | the Program, the only way you could satisfy both those terms and this | ||||||
|  | License would be to refrain entirely from conveying the Program. | ||||||
|  |  | ||||||
|  |   13. Use with the GNU Affero General Public License. | ||||||
|  |  | ||||||
|  |   Notwithstanding any other provision of this License, you have | ||||||
|  | permission to link or combine any covered work with a work licensed | ||||||
|  | under version 3 of the GNU Affero General Public License into a single | ||||||
|  | combined work, and to convey the resulting work.  The terms of this | ||||||
|  | License will continue to apply to the part which is the covered work, | ||||||
|  | but the special requirements of the GNU Affero General Public License, | ||||||
|  | section 13, concerning interaction through a network will apply to the | ||||||
|  | combination as such. | ||||||
|  |  | ||||||
|  |   14. Revised Versions of this License. | ||||||
|  |  | ||||||
|  |   The Free Software Foundation may publish revised and/or new versions of | ||||||
|  | the GNU General Public License from time to time.  Such new versions will | ||||||
|  | be similar in spirit to the present version, but may differ in detail to | ||||||
|  | address new problems or concerns. | ||||||
|  |  | ||||||
|  |   Each version is given a distinguishing version number.  If the | ||||||
|  | Program specifies that a certain numbered version of the GNU General | ||||||
|  | Public License "or any later version" applies to it, you have the | ||||||
|  | option of following the terms and conditions either of that numbered | ||||||
|  | version or of any later version published by the Free Software | ||||||
|  | Foundation.  If the Program does not specify a version number of the | ||||||
|  | GNU General Public License, you may choose any version ever published | ||||||
|  | by the Free Software Foundation. | ||||||
|  |  | ||||||
|  |   If the Program specifies that a proxy can decide which future | ||||||
|  | versions of the GNU General Public License can be used, that proxy's | ||||||
|  | public statement of acceptance of a version permanently authorizes you | ||||||
|  | to choose that version for the Program. | ||||||
|  |  | ||||||
|  |   Later license versions may give you additional or different | ||||||
|  | permissions.  However, no additional obligations are imposed on any | ||||||
|  | author or copyright holder as a result of your choosing to follow a | ||||||
|  | later version. | ||||||
|  |  | ||||||
|  |   15. Disclaimer of Warranty. | ||||||
|  |  | ||||||
|  |   THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY | ||||||
|  | APPLICABLE LAW.  EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT | ||||||
|  | HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY | ||||||
|  | OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, | ||||||
|  | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | ||||||
|  | PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM | ||||||
|  | IS WITH YOU.  SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF | ||||||
|  | ALL NECESSARY SERVICING, REPAIR OR CORRECTION. | ||||||
|  |  | ||||||
|  |   16. Limitation of Liability. | ||||||
|  |  | ||||||
|  |   IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING | ||||||
|  | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS | ||||||
|  | THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY | ||||||
|  | GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE | ||||||
|  | USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF | ||||||
|  | DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD | ||||||
|  | PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), | ||||||
|  | EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF | ||||||
|  | SUCH DAMAGES. | ||||||
|  |  | ||||||
|  |   17. Interpretation of Sections 15 and 16. | ||||||
|  |  | ||||||
|  |   If the disclaimer of warranty and limitation of liability provided | ||||||
|  | above cannot be given local legal effect according to their terms, | ||||||
|  | reviewing courts shall apply local law that most closely approximates | ||||||
|  | an absolute waiver of all civil liability in connection with the | ||||||
|  | Program, unless a warranty or assumption of liability accompanies a | ||||||
|  | copy of the Program in return for a fee. | ||||||
|  |  | ||||||
|  |                      END OF TERMS AND CONDITIONS | ||||||
|  |  | ||||||
|  |             How to Apply These Terms to Your New Programs | ||||||
|  |  | ||||||
|  |   If you develop a new program, and you want it to be of the greatest | ||||||
|  | possible use to the public, the best way to achieve this is to make it | ||||||
|  | free software which everyone can redistribute and change under these terms. | ||||||
|  |  | ||||||
|  |   To do so, attach the following notices to the program.  It is safest | ||||||
|  | to attach them to the start of each source file to most effectively | ||||||
|  | state the exclusion of warranty; and each file should have at least | ||||||
|  | the "copyright" line and a pointer to where the full notice is found. | ||||||
|  |  | ||||||
|  |     <one line to give the program's name and a brief idea of what it does.> | ||||||
|  |     Copyright (C) <year>  <name of author> | ||||||
|  |  | ||||||
|  |     This program is free software: you can redistribute it and/or modify | ||||||
|  |     it under the terms of the GNU General Public License as published by | ||||||
|  |     the Free Software Foundation, either version 3 of the License, or | ||||||
|  |     (at your option) any later version. | ||||||
|  |  | ||||||
|  |     This program is distributed in the hope that it will be useful, | ||||||
|  |     but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||||
|  |     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||||
|  |     GNU General Public License for more details. | ||||||
|  |  | ||||||
|  |     You should have received a copy of the GNU General Public License | ||||||
|  |     along with this program.  If not, see <https://www.gnu.org/licenses/>. | ||||||
|  |  | ||||||
|  | Also add information on how to contact you by electronic and paper mail. | ||||||
|  |  | ||||||
|  |   If the program does terminal interaction, make it output a short | ||||||
|  | notice like this when it starts in an interactive mode: | ||||||
|  |  | ||||||
|  |     facho-signer  Copyright (C) 2021  Jovany Leandro G.C <bit4bit@riseup.net> | ||||||
|  |     This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. | ||||||
|  |     This is free software, and you are welcome to redistribute it | ||||||
|  |     under certain conditions; type `show c' for details. | ||||||
|  |  | ||||||
|  | The hypothetical commands `show w' and `show c' should show the appropriate | ||||||
|  | parts of the General Public License.  Of course, your program's commands | ||||||
|  | might be different; for a GUI interface, you would use an "about box". | ||||||
|  |  | ||||||
|  |   You should also get your employer (if you work as a programmer) or school, | ||||||
|  | if any, to sign a "copyright disclaimer" for the program, if necessary. | ||||||
|  | For more information on this, and how to apply and follow the GNU GPL, see | ||||||
|  | <https://www.gnu.org/licenses/>. | ||||||
|  |  | ||||||
|  |   The GNU General Public License does not permit incorporating your program | ||||||
|  | into proprietary programs.  If your program is a subroutine library, you | ||||||
|  | may consider it more useful to permit linking proprietary applications with | ||||||
|  | the library.  If this is what you want to do, use the GNU Lesser General | ||||||
|  | Public License instead of this License.  But first, please read | ||||||
|  | <https://www.gnu.org/licenses/why-not-lgpl.html>. | ||||||
							
								
								
									
										0
									
								
								experimental/facho-signer/ChangeLog
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								experimental/facho-signer/ChangeLog
									
									
									
									
									
										Normal file
									
								
							
							
								
								
									
										1
									
								
								experimental/facho-signer/Makefile.am
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								experimental/facho-signer/Makefile.am
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1 @@ | |||||||
|  | SUBDIRS = src | ||||||
							
								
								
									
										0
									
								
								experimental/facho-signer/NEWS
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								experimental/facho-signer/NEWS
									
									
									
									
									
										Normal file
									
								
							
							
								
								
									
										0
									
								
								experimental/facho-signer/README
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								experimental/facho-signer/README
									
									
									
									
									
										Normal file
									
								
							
							
								
								
									
										3
									
								
								experimental/facho-signer/boostrap.sh
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								experimental/facho-signer/boostrap.sh
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,3 @@ | |||||||
|  | #!/bin/sh | ||||||
|  | libtoolize -c --force | ||||||
|  | autoreconf --install --force | ||||||
							
								
								
									
										56
									
								
								experimental/facho-signer/configure.ac
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										56
									
								
								experimental/facho-signer/configure.ac
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,56 @@ | |||||||
|  | #                                               -*- Autoconf -*- | ||||||
|  | # Process this file with autoconf to produce a configure script. | ||||||
|  |  | ||||||
|  | AC_PREREQ([2.71]) | ||||||
|  | AC_INIT([facho-signer], [0.0.1], [bit4bit@riseup.net]) | ||||||
|  | AM_INIT_AUTOMAKE | ||||||
|  | AC_CONFIG_SRCDIR([src/facho_signer.c]) | ||||||
|  | AC_CONFIG_HEADERS([config.h]) | ||||||
|  | AC_CONFIG_MACRO_DIRS([m4]) | ||||||
|  |  | ||||||
|  | # Checks for programs. | ||||||
|  | AC_PROG_CC | ||||||
|  |  | ||||||
|  | # Checks for libraries. | ||||||
|  | PKG_CHECK_MODULES([OPENSSL], [openssl]) | ||||||
|  | PKG_CHECK_MODULES([XMLSEC1], [xmlsec1-openssl], [ | ||||||
|  |                              AC_DEFINE([XMLSEC_CRYPTO_OPENSSL], [1], [enable crypto openssl]) | ||||||
|  |                              ]) | ||||||
|  | PKG_CHECK_MODULES([LZMA], [liblzma]) | ||||||
|  |  | ||||||
|  | AC_ARG_ENABLE([xmlsec-crypto-dynamic-loading], | ||||||
|  |         AS_HELP_STRING([--enable-xmlsec-crypto-dynamic-loading], | ||||||
|  |         [enable crypto xmlsec dynamic loading]) | ||||||
|  |        ) | ||||||
|  |  | ||||||
|  | if test "x$enable_xmlsec_crypto_dynamic_loading" == xyes; then | ||||||
|  |   AC_DEFINE([XMLSEC_CRYPTO_DYNAMIC_LOADING], [1], [enable xmlsec crypto dynamic loading]) | ||||||
|  |   AC_CHECK_HEADER([ltdl.h], [ | ||||||
|  | 		AC_CHECK_LIB( | ||||||
|  | 			[ltdl], | ||||||
|  | 			[lt_dlopenext], | ||||||
|  | 			[LIBLTDL=-lltdl], | ||||||
|  | 			[LIBLTDL=] | ||||||
|  | 			) | ||||||
|  | 		], [ LIBLTDL= ]) | ||||||
|  |  | ||||||
|  | else | ||||||
|  |   AC_DEFINE([XMLSEC_NO_CRYPTO_DYNAMIC_LOADING], [1], [disable xmlsec crypto dynamic loading]) | ||||||
|  | fi | ||||||
|  |  | ||||||
|  | # Checks for header files. | ||||||
|  | AC_CHECK_HEADERS([sys/time.h unistd.h]) | ||||||
|  |  | ||||||
|  | # Checks for typedefs, structures, and compiler characteristics. | ||||||
|  | AC_TYPE_SIZE_T | ||||||
|  |  | ||||||
|  | # Checks for library functions. | ||||||
|  | AC_FUNC_MALLOC | ||||||
|  | AC_CHECK_FUNCS([clock_gettime gethrtime gettimeofday memset strdup]) | ||||||
|  |  | ||||||
|  | # libtool | ||||||
|  |  | ||||||
|  | LT_INIT | ||||||
|  |  | ||||||
|  | AC_CONFIG_FILES([Makefile src/Makefile]) | ||||||
|  | AC_OUTPUT | ||||||
							
								
								
									
										12
									
								
								experimental/facho-signer/src/Makefile.am
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								experimental/facho-signer/src/Makefile.am
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,12 @@ | |||||||
|  | SOURCES = xades/xmlsec1/xmltree.c xades/xmlsec1/errors.c xades/templates.c xades/xades.c facho_signer.c | ||||||
|  |  | ||||||
|  | lib_LTLIBRARIES = libfachosigner.la | ||||||
|  | libfachosigner_la_SOURCES = $(LTDL_SOURCE_FILES) $(SOURCES) | ||||||
|  | libfachosigner_la_CFLAGS = $(OPENSSL_CFLAGS) $(XMLSEC1_CFLAGS) -DXMLSEC_NOT_CRYPTO_DYNAMIC_LOADING | ||||||
|  | libfachosigner_la_LDFLAGS = $(OPENSSL_LIBS) $(LIBLTDL) $(XMLSEC1_LIBS) | ||||||
|  |  | ||||||
|  | bin_PROGRAMS = facho_signer | ||||||
|  | facho_signer_SOURCES = main.c | ||||||
|  | facho_signer_CFLAGS = $(OPENSSL_CFLAGS) $(XMLSEC1_CFLAGS) -DXMLSEC_NOT_CRYPTO_DYNAMIC_LOADING | ||||||
|  | facho_signer_LDADD = libfachosigner.la | ||||||
|  |  | ||||||
							
								
								
									
										11
									
								
								experimental/facho-signer/src/README.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								experimental/facho-signer/src/README.md
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,11 @@ | |||||||
|  | # facho-signer | ||||||
|  |  | ||||||
|  |  | ||||||
|  | ## guia | ||||||
|  |  | ||||||
|  | - http://xmlsoft.org/html/libxml-tree.html | ||||||
|  | - http://xmlsoft.org/html/libxml-xpath.html | ||||||
|  | - http://xmlsoft.org/examples/xpath1.c | ||||||
|  | - http://xmlsoft.org/tutorial/ar01s05.html | ||||||
|  | - https://www.aleksey.com/xmlsec/api/xmlsec-reference.html | ||||||
|  | - https://zakird.com/2013/10/13/certificate-parsing-with-openssl | ||||||
							
								
								
									
										371
									
								
								experimental/facho-signer/src/facho_signer.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										371
									
								
								experimental/facho-signer/src/facho_signer.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,371 @@ | |||||||
|  | /** | ||||||
|  |  * This file is part of facho.  The COPYRIGHT file at the top level of | ||||||
|  |  * this repository contains the full copyright notices and license terms. | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | #include "config.h" | ||||||
|  | #include "xades/xades.h" | ||||||
|  |  | ||||||
|  | #include <xmlsec/xmlsec.h> | ||||||
|  | #include <xmlsec/xmltree.h> | ||||||
|  | #include <xmlsec/xmldsig.h> | ||||||
|  | #include <xmlsec/templates.h> | ||||||
|  | #include <xmlsec/crypto.h> | ||||||
|  |  | ||||||
|  | #include <stdio.h> | ||||||
|  | #include <stdlib.h> | ||||||
|  |  | ||||||
|  | #define xmlFachoPrintError(fmt, ...) fprintf(stderr, fmt, ##__VA_ARGS__) | ||||||
|  | #define xmlFachoPrintInfo(fmt, ...) fprintf(stdout, fmt, ##__VA_ARGS__) | ||||||
|  |  | ||||||
|  | static const xmlChar ublExtensionDSigNs[] = "urn:oasis:names:specification:ubl:schema:xsd:CommonExtensionComponents-2"; | ||||||
|  | static const xmlChar policyIdDescription[] = "Política de firma para facturas electrónicas de la República de Colombia."; | ||||||
|  | static const xmlChar policyIdIdentifier[] = "https://facturaelectronica.dian.gov.co/politicadefirma/v2/politicadefirmav2.pdf"; | ||||||
|  |    | ||||||
|  | // crea elemento /Invoice/ext:UBLExtensions/ext:UBLExtension/ext:ExtensionContent | ||||||
|  | static xmlNodePtr | ||||||
|  | xmlFachoTmplUBLExtensionAddExtensionContent(xmlDocPtr doc); | ||||||
|  |  | ||||||
|  | // FeC requiere que el digest value del policy identifier sea | ||||||
|  | // apartir del contenido de la url. | ||||||
|  | static int | ||||||
|  | xmlFachoPolicyIdentifierCtxFromFilename(const xmlChar *, xmlSecBufferPtr); | ||||||
|  |  | ||||||
|  |  | ||||||
|  | static int | ||||||
|  | xmlFachoTmplXadesCreate(xmlDocPtr doc, xmlNodePtr signNode) { | ||||||
|  |   xmlNodePtr qualifyingPropertiesNode = NULL; | ||||||
|  |   xmlNodePtr signedPropertiesNode = NULL; | ||||||
|  |   xmlNodePtr signedSignaturePropertiesNode = NULL; | ||||||
|  |   xmlNodePtr signingCertificateNode = NULL; | ||||||
|  |   xmlNodePtr signaturePolicyIdentifierNode = NULL; | ||||||
|  |   xmlNodePtr signaturePolicyIdNode = NULL; | ||||||
|  |   xmlNodePtr sigPolicyIdNode = NULL; | ||||||
|  |   xmlNodePtr sigPolicyHashNode = NULL; | ||||||
|  |   xmlNodePtr signerRoleNode = NULL; | ||||||
|  |   xmlNodePtr refNode = NULL; | ||||||
|  |   const xmlChar signedPropertiesId[] = "xmldsig-facho-signed-props"; | ||||||
|  |   const xmlChar signedPropertiesRef[] = "#xmldsig-facho-signed-props"; | ||||||
|  |    | ||||||
|  |   qualifyingPropertiesNode = xmlXadesTmplQualifyingPropertiesCreate(doc, signNode, BAD_CAST "xades-ref1"); | ||||||
|  |   if (  qualifyingPropertiesNode == NULL ) { | ||||||
|  |     xmlFachoPrintError("error: failed to add QualifyingProperties node.\n"); | ||||||
|  |     goto fail; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   signedPropertiesNode = xmlXadesTmplAddSignedProperties(qualifyingPropertiesNode, signedPropertiesId); | ||||||
|  |   if ( signedPropertiesNode == NULL ) { | ||||||
|  |     xmlFachoPrintError("error: xades failed to add signed properties node.\n"); | ||||||
|  |     goto fail; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   refNode = xmlSecTmplSignatureAddReference(signNode, | ||||||
|  |                                             xmlSecTransformSha256Id, | ||||||
|  |                                             BAD_CAST "xmldsig-facho-ref1", | ||||||
|  |                                             signedPropertiesRef, | ||||||
|  |                                             BAD_CAST "http://uri.etsi.org/01903#SignedProperties"); | ||||||
|  |   if ( refNode == NULL ) { | ||||||
|  |     xmlFachoPrintError("error: failed to add reference to signature template xades.\n"); | ||||||
|  |     goto fail; | ||||||
|  |   } | ||||||
|  |   if ( xmlSecTmplReferenceAddTransform(refNode, xmlSecTransformInclC14NId) == NULL ) { | ||||||
|  |     xmlFachoPrintError("error: failed to add enveloped transform to reference for xades\n"); | ||||||
|  |     goto fail; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   const time_t now = time(NULL); | ||||||
|  |   signedSignaturePropertiesNode = xmlXadesTmplAddSignedSignatureProperties(signedPropertiesNode, localtime(&now)); | ||||||
|  |   if ( signedSignaturePropertiesNode == NULL ) { | ||||||
|  |     xmlFachoPrintError("error: xades failed to add signed signature properties node.\n"); | ||||||
|  |     goto fail; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   signingCertificateNode = xmlXadesTmplAddSigningCertificate(signedSignaturePropertiesNode, xmlSecTransformSha256Id); | ||||||
|  |   if ( signingCertificateNode == NULL ) { | ||||||
|  |     xmlFachoPrintError("error: failed to add SigningCertificate node \n"); | ||||||
|  |     goto fail; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   signaturePolicyIdentifierNode = xmlXadesTmplAddSignaturePolicyIdentifier(signedSignaturePropertiesNode); | ||||||
|  |   if ( signaturePolicyIdentifierNode == NULL ) { | ||||||
|  |     xmlFachoPrintError("error: failed to add PolicyIdentifier node\n"); | ||||||
|  |     goto fail; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   signaturePolicyIdNode = xmlXadesTmplAddSignaturePolicyId(signaturePolicyIdentifierNode); | ||||||
|  |   if ( signaturePolicyIdNode == NULL ) { | ||||||
|  |     xmlFachoPrintError("error: failed to add SignaturePolicyId node.\n"); | ||||||
|  |     goto fail; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   sigPolicyIdNode = xmlXadesTmplAddSigPolicyId(signaturePolicyIdNode, policyIdIdentifier, policyIdDescription); | ||||||
|  |   if ( sigPolicyIdNode == NULL ) { | ||||||
|  |     xmlFachoPrintError("error: failed to add SigPolicyId node.\n"); | ||||||
|  |     goto fail; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   sigPolicyHashNode = xmlXadesTmplAddSigPolicyHash(signaturePolicyIdNode, xmlSecTransformSha256Id); | ||||||
|  |   if ( sigPolicyHashNode == NULL ) { | ||||||
|  |     xmlFachoPrintError("error: failed to add SigPolicyHash node.\n"); | ||||||
|  |     goto fail; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   signerRoleNode = xmlXadesTmplAddSignerRole(signedSignaturePropertiesNode, BAD_CAST "supplier"); | ||||||
|  |   if ( signerRoleNode == NULL ) { | ||||||
|  |     xmlFachoPrintError("error: failed to add SignerRole node.\n"); | ||||||
|  |     goto fail; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |    | ||||||
|  |   return(0); | ||||||
|  |  fail: | ||||||
|  |   xmlUnlinkNode(qualifyingPropertiesNode); | ||||||
|  |   xmlFreeNode(qualifyingPropertiesNode); | ||||||
|  |   return(-1); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | int | ||||||
|  | xmlFachoInit() { | ||||||
|  |   xmlInitParser(); | ||||||
|  |   LIBXML_TEST_VERSION; | ||||||
|  |    | ||||||
|  |   if ( xmlSecInit() < 0 ) { | ||||||
|  |     xmlFachoPrintError("xmlsec initialization failed.\n"); | ||||||
|  |     return(-1); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   if ( xmlSecCheckVersion() != 1 ) { | ||||||
|  |     xmlFachoPrintError("loaded xmlsec library version is not compatible.\n"); | ||||||
|  |     return(-1); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  | #ifdef XMLSEC_CRYPTO_DYNAMIC_LOADING | ||||||
|  |     if(xmlSecCryptoDLLoadLibrary( NULL ) < 0) { | ||||||
|  |         fprintf(stderr, "Error: unable to load default xmlsec-crypto library. Make sure\n" | ||||||
|  |                         "that you have it installed and check shared libraries path\n" | ||||||
|  |                         "(LD_LIBRARY_PATH and/or LTDL_LIBRARY_PATH) environment variables.\n"); | ||||||
|  |         return(-1);      | ||||||
|  |     } | ||||||
|  | #endif /* XMLSEC_CRYPTO_DYNAMIC_LOADING */ | ||||||
|  |     | ||||||
|  |   if ( xmlSecCryptoAppInit(NULL) < 0 ) { | ||||||
|  |     xmlFachoPrintError("crypto initialization failed.\n"); | ||||||
|  |     return(-1); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   if ( xmlSecCryptoInit() < 0 ) { | ||||||
|  |     xmlFachoPrintError("xmlsec-crypto initialization failed.\n"); | ||||||
|  |     return(-1); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   return(0); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | int | ||||||
|  | xmlFachoShutdown() { | ||||||
|  |  | ||||||
|  |   if ( xmlSecCryptoShutdown() < 0 ) { | ||||||
|  |     xmlFachoPrintError("xmlSecCryptoShutdown failed.\n"); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   if ( xmlSecCryptoAppShutdown() < 0 ) { | ||||||
|  |     xmlFachoPrintError("xmlSecCryptoAppShutdown failed.\n"); | ||||||
|  |   } | ||||||
|  |    | ||||||
|  |   if ( xmlSecShutdown() < 0 ) { | ||||||
|  |     xmlFachoPrintError("xmlsec shutdown failed.\n"); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   xmlCleanupParser(); | ||||||
|  |   return(0); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | int | ||||||
|  | xmlFachoSignFile(FILE *out, const char *filename, const char *pkcs12name, const char *password) { | ||||||
|  |   xmlDocPtr doc = NULL; | ||||||
|  |   xmlNodePtr signNode = NULL; | ||||||
|  |   xmlNodePtr refNode = NULL; | ||||||
|  |   xmlNodePtr keyInfoNode = NULL; | ||||||
|  |   xmlNodePtr x509DataNode = NULL; | ||||||
|  |   xmlNodePtr node = NULL; | ||||||
|  |   xmlSecDSigCtxPtr dsigCtx = NULL; | ||||||
|  |   xmlXadesDSigCtxPtr xadesDsigCtx = NULL; | ||||||
|  |  | ||||||
|  |   int res = -1; | ||||||
|  |    | ||||||
|  |   if (filename == NULL) { | ||||||
|  |    return(-1); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   doc = xmlParseFile(filename); | ||||||
|  |   if ( (doc == NULL) || (xmlDocGetRootElement(doc) == NULL) ) { | ||||||
|  |     xmlFachoPrintError("error: unable to parse file %s\n", filename); | ||||||
|  |     goto done; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   signNode = xmlSecTmplSignatureCreate(doc, xmlSecTransformInclC14NId, | ||||||
|  |                                        xmlSecTransformRsaSha256Id, NULL); | ||||||
|  |   if ( signNode == NULL ) { | ||||||
|  |     xmlFachoPrintError("error: failed to create signature template.\n"); | ||||||
|  |     goto done; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   xmlAddChild(xmlDocGetRootElement(doc), signNode); | ||||||
|  |  | ||||||
|  |   refNode = xmlSecTmplSignatureAddReference(signNode, | ||||||
|  |                                             xmlSecTransformSha256Id, | ||||||
|  |                                             BAD_CAST "xmldsig-facho-ref0", // id | ||||||
|  |                                             BAD_CAST "", //uri | ||||||
|  |                                             NULL); //type | ||||||
|  |   if ( refNode == NULL ) { | ||||||
|  |     xmlFachoPrintError("error: failed to add reference to signature template.\n"); | ||||||
|  |     goto done; | ||||||
|  |   } | ||||||
|  |   if ( xmlSecTmplReferenceAddTransform(refNode, xmlSecTransformEnvelopedId) == NULL ) { | ||||||
|  |     xmlFachoPrintError("error: failed to add enveloped transform to reference\n"); | ||||||
|  |     goto done; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   refNode = xmlSecTmplSignatureAddReference(signNode, | ||||||
|  |                                             xmlSecTransformSha256Id, | ||||||
|  |                                             BAD_CAST "xmldsig-facho-ref2", | ||||||
|  |                                             BAD_CAST "#xmldsig-facho-KeyInfo", | ||||||
|  |                                             NULL); | ||||||
|  |   if ( refNode == NULL ) { | ||||||
|  |     xmlFachoPrintError("error: failed to add reference to signature template key-info.\n"); | ||||||
|  |     goto done; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   keyInfoNode = xmlSecTmplSignatureEnsureKeyInfo(signNode, BAD_CAST "xmldsig-facho-KeyInfo"); | ||||||
|  |   if ( keyInfoNode == NULL ) { | ||||||
|  |     xmlFachoPrintError("error: failed to add key info.\n"); | ||||||
|  |     goto done; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   x509DataNode = xmlSecTmplKeyInfoAddX509Data(keyInfoNode); | ||||||
|  |   if ( x509DataNode == NULL ) { | ||||||
|  |     xmlFachoPrintError("error: failde to add x509 DATA \n"); | ||||||
|  |     goto done; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   if ( xmlSecTmplX509DataAddCertificate(x509DataNode) == NULL ) { | ||||||
|  |     xmlFachoPrintError("error: failde to add x509Certificate node\n"); | ||||||
|  |     goto done; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |  | ||||||
|  |   if ( xmlFachoTmplXadesCreate(doc, signNode) < 0 ){ | ||||||
|  |     xmlFachoPrintError("error: xmlFachoTmplXadesCreate failed.\n"); | ||||||
|  |     goto done; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   dsigCtx = xmlSecDSigCtxCreate(NULL); | ||||||
|  |   if ( dsigCtx == NULL ) { | ||||||
|  |     xmlFachoPrintError("error: dsig context creating failed\n"); | ||||||
|  |     return(-1); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   // cargamos el archivo pkcs12 con llave privado y certificados x509 | ||||||
|  |   dsigCtx->signKey = xmlSecCryptoAppKeyLoad(pkcs12name, | ||||||
|  |                                             xmlSecKeyDataFormatPkcs12, | ||||||
|  |                                             password, | ||||||
|  |                                             NULL, NULL); | ||||||
|  |   if ( dsigCtx->signKey == NULL ) { | ||||||
|  |     xmlFachoPrintError("error: failed to load pkcs12\n"); | ||||||
|  |     goto done; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   xmlXadesPolicyIdentifierCtx policyIdCtx; | ||||||
|  |  | ||||||
|  |   // por ahora el hash del identificador lo tomamos del pdf de la dian | ||||||
|  |   policyIdCtx.contentCallback = &xmlFachoPolicyIdentifierCtxFromFilename; | ||||||
|  |      | ||||||
|  |   xadesDsigCtx = xmlXadesDSigCtxCreate(dsigCtx, XADES_DIGEST_SHA256, &policyIdCtx); | ||||||
|  |   if ( xadesDsigCtx == NULL ) { | ||||||
|  |     xmlFachoPrintError("error: xades context creating failed.\n"); | ||||||
|  |     return(-1); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   // debe existir el elemento antes del firmado | ||||||
|  |   node = xmlFachoTmplUBLExtensionAddExtensionContent(doc); | ||||||
|  |   if ( node == NULL ) { | ||||||
|  |     xmlFachoPrintError("error: failed to add UBLExtensions/UBLExtension/ExtensionContent\n"); | ||||||
|  |     goto done; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |  | ||||||
|  |   // realizar firma de documento | ||||||
|  |   if ( xmlXadesDSigCtxSign(xadesDsigCtx, signNode) < 0 ) { | ||||||
|  |     xmlFachoPrintError("error: signature failed\n"); | ||||||
|  |     goto done; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |  | ||||||
|  |   xmlUnlinkNode(signNode); | ||||||
|  |   xmlSecAddChildNode(node, signNode); | ||||||
|  |  | ||||||
|  |   xmlDocDump(out, doc); | ||||||
|  |  | ||||||
|  |   res = 0; | ||||||
|  |  | ||||||
|  |  done: | ||||||
|  |   if ( xadesDsigCtx != NULL ) { | ||||||
|  |     xmlXadesDSigCtxDestroy(xadesDsigCtx); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   if ( dsigCtx != NULL ) { | ||||||
|  |     xmlSecDSigCtxDestroy(dsigCtx); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   if ( doc != NULL ) { | ||||||
|  |     xmlFreeDoc(doc); | ||||||
|  |   } | ||||||
|  |   return(res); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static xmlNodePtr | ||||||
|  | xmlFachoTmplUBLExtensionAddExtensionContent(xmlDocPtr doc) { | ||||||
|  |   xmlNodePtr node = NULL; | ||||||
|  |   xmlNodePtr parent = NULL; | ||||||
|  |   const xmlChar ublExtensionsName[] = "UBLExtensions"; | ||||||
|  |   const xmlChar ublExtensionName[] = "UBLExtension"; | ||||||
|  |   const xmlChar extensionContentName[] = "ExtensionContent"; | ||||||
|  |      | ||||||
|  |   parent = xmlSecFindNode(xmlDocGetRootElement(doc), ublExtensionsName, ublExtensionDSigNs); | ||||||
|  |   if ( parent == NULL ) { | ||||||
|  |     parent = xmlSecAddChild(xmlDocGetRootElement(doc), ublExtensionsName,  ublExtensionDSigNs); | ||||||
|  |     if ( parent == NULL ) { | ||||||
|  |       xmlFachoPrintError("error: failed to cleate UBLExtensions.\n"); | ||||||
|  |       return(NULL); | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   // adicionamos nuevo elemento UBLExtension | ||||||
|  |   node = xmlSecAddChild(parent, ublExtensionName, ublExtensionDSigNs); | ||||||
|  |   if ( node == NULL ) { | ||||||
|  |     xmlFachoPrintError("error: failed to add UBLExtension\n"); | ||||||
|  |     xmlFreeNode(parent); | ||||||
|  |     return(NULL); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   // adicionamos nuevo elemento ExtensionContent | ||||||
|  |   node = xmlSecAddChild(node, extensionContentName, ublExtensionDSigNs); | ||||||
|  |   if ( node == NULL ) { | ||||||
|  |     xmlFachoPrintError("error: failed to add ExtensionContent"); | ||||||
|  |     return(NULL); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   return(node); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static int | ||||||
|  | xmlFachoPolicyIdentifierCtxFromFilename(const xmlChar *policyId, xmlSecBufferPtr buffer) { | ||||||
|  |   static unsigned char politicafirmav2[] = { | ||||||
|  |     /** | ||||||
|  |      * generado con https://github.com/Jamesits/bin2array | ||||||
|  |      */ | ||||||
|  | #include "politicafirmav2.c" | ||||||
|  |   }; | ||||||
|  |  | ||||||
|  |   return xmlSecBufferAppend(buffer, politicafirmav2, sizeof(politicafirmav2)); | ||||||
|  | } | ||||||
							
								
								
									
										20
									
								
								experimental/facho-signer/src/facho_signer.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								experimental/facho-signer/src/facho_signer.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,20 @@ | |||||||
|  | /** | ||||||
|  |  * This file is part of facho.  The COPYRIGHT file at the top level of | ||||||
|  |  * this repository contains the full copyright notices and license terms. | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | #ifndef FACHO_SIGNER_H | ||||||
|  | #define FACHO_SIGNER_H | ||||||
|  |  | ||||||
|  | #include <stdio.h> | ||||||
|  |  | ||||||
|  | int | ||||||
|  | xmlFachoInit(); | ||||||
|  |  | ||||||
|  | int | ||||||
|  | xmlFachoShutdown(); | ||||||
|  |  | ||||||
|  | int | ||||||
|  | xmlFachoSignFile(FILE *out, const char *filename, const char *pkcs12name, const char *password); | ||||||
|  |  | ||||||
|  | #endif /* FACHO_SIGNER_H */ | ||||||
							
								
								
									
										47
									
								
								experimental/facho-signer/src/main.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										47
									
								
								experimental/facho-signer/src/main.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,47 @@ | |||||||
|  | /** | ||||||
|  |  * This file is part of facho.  The COPYRIGHT file at the top level of | ||||||
|  |  * this repository contains the full copyright notices and license terms. | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | #include "xades/xades.h" | ||||||
|  | #include "facho_signer.h" | ||||||
|  |  | ||||||
|  | #include <stdio.h> | ||||||
|  | #include <stdlib.h> | ||||||
|  |  | ||||||
|  |  | ||||||
|  | static char *basename = NULL; | ||||||
|  |  | ||||||
|  | void usage(FILE *out); | ||||||
|  |  | ||||||
|  | int main(int argc, char *argv[]) { | ||||||
|  |   int exitStatus = EXIT_SUCCESS; | ||||||
|  |   basename = argv[0]; | ||||||
|  |    | ||||||
|  |   if (argc != 4) { | ||||||
|  |     usage(stderr); | ||||||
|  |     return(EXIT_FAILURE); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   if ( xmlFachoInit() < 0 ) { | ||||||
|  |     fprintf(stderr, "initialization failed.\n"); | ||||||
|  |     return(EXIT_FAILURE); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   if ( xmlFachoSignFile( stdout, argv[1], argv[2], argv[3] ) != 0 ) { | ||||||
|  |     fprintf(stderr, "fail to sign file\n"); | ||||||
|  |     exitStatus = EXIT_FAILURE; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   xmlFachoShutdown();   | ||||||
|  |   return(exitStatus); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void | ||||||
|  | usage(FILE *out) { | ||||||
|  |   fprintf(out, "%s: <factura.xml> <pc12> <password>\n", basename); | ||||||
|  |   fprintf(out, "%s", "Firmado electronico para facturacion en Colombia.\n" | ||||||
|  |           "Segun el documento (Anexo Técnico de Factura Electrónica de Venta – Versión 1.7.-2020).\n" | ||||||
|  |           "A considerar:\n" \ | ||||||
|  |           " * adiciona un nuevo elemento //ext:UBLExtensions/ext:UBLExtension/ext:ExtensionContent\n"); | ||||||
|  | } | ||||||
							
								
								
									
										1
									
								
								experimental/facho-signer/src/politicafirmav2.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								experimental/facho-signer/src/politicafirmav2.c
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										391
									
								
								experimental/facho-signer/src/xades/minunit.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										391
									
								
								experimental/facho-signer/src/xades/minunit.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,391 @@ | |||||||
|  | /* | ||||||
|  |  * Copyright (c) 2012 David Siñuela Pastor, siu.4coders@gmail.com | ||||||
|  |  *  | ||||||
|  |  * Permission is hereby granted, free of charge, to any person obtaining | ||||||
|  |  * a copy of this software and associated documentation files (the | ||||||
|  |  * "Software"), to deal in the Software without restriction, including | ||||||
|  |  * without limitation the rights to use, copy, modify, merge, publish, | ||||||
|  |  * distribute, sublicense, and/or sell copies of the Software, and to | ||||||
|  |  * permit persons to whom the Software is furnished to do so, subject to | ||||||
|  |  * the following conditions: | ||||||
|  |  *  | ||||||
|  |  * The above copyright notice and this permission notice shall be | ||||||
|  |  * included in all copies or substantial portions of the Software. | ||||||
|  |  *  | ||||||
|  |  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | ||||||
|  |  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | ||||||
|  |  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | ||||||
|  |  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE | ||||||
|  |  * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION | ||||||
|  |  * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION | ||||||
|  |  * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | ||||||
|  |  */ | ||||||
|  | #ifndef MINUNIT_MINUNIT_H | ||||||
|  | #define MINUNIT_MINUNIT_H | ||||||
|  |  | ||||||
|  | #ifdef __cplusplus | ||||||
|  | 	extern "C" { | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | #if defined(_WIN32) | ||||||
|  | #include <Windows.h> | ||||||
|  | #if defined(_MSC_VER) && _MSC_VER < 1900 | ||||||
|  |   #define snprintf _snprintf | ||||||
|  |   #define __func__ __FUNCTION__ | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | #elif defined(__unix__) || defined(__unix) || defined(unix) || (defined(__APPLE__) && defined(__MACH__)) | ||||||
|  |  | ||||||
|  | /* Change POSIX C SOURCE version for pure c99 compilers */ | ||||||
|  | #if !defined(_POSIX_C_SOURCE) || _POSIX_C_SOURCE < 200112L | ||||||
|  | #undef _POSIX_C_SOURCE | ||||||
|  | #define _POSIX_C_SOURCE 200112L | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | #include <unistd.h>	/* POSIX flags */ | ||||||
|  | #include <time.h>	/* clock_gettime(), time() */ | ||||||
|  | #include <sys/time.h>	/* gethrtime(), gettimeofday() */ | ||||||
|  | #include <sys/resource.h> | ||||||
|  | #include <sys/times.h> | ||||||
|  | #include <string.h> | ||||||
|  |  | ||||||
|  | #if defined(__MACH__) && defined(__APPLE__) | ||||||
|  | #include <mach/mach.h> | ||||||
|  | #include <mach/mach_time.h> | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | #if __GNUC__ >= 5 && !defined(__STDC_VERSION__) | ||||||
|  | #define __func__ __extension__ __FUNCTION__ | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | #else | ||||||
|  | #error "Unable to define timers for an unknown OS." | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | #include <stdio.h> | ||||||
|  | #include <math.h> | ||||||
|  |  | ||||||
|  | /*  Maximum length of last message */ | ||||||
|  | #define MINUNIT_MESSAGE_LEN 1024 | ||||||
|  | /*  Accuracy with which floats are compared */ | ||||||
|  | #define MINUNIT_EPSILON 1E-12 | ||||||
|  |  | ||||||
|  | /*  Misc. counters */ | ||||||
|  | static int minunit_run = 0; | ||||||
|  | static int minunit_assert = 0; | ||||||
|  | static int minunit_fail = 0; | ||||||
|  | static int minunit_status = 0; | ||||||
|  |  | ||||||
|  | /*  Timers */ | ||||||
|  | static double minunit_real_timer = 0; | ||||||
|  | static double minunit_proc_timer = 0; | ||||||
|  |  | ||||||
|  | /*  Last message */ | ||||||
|  | static char minunit_last_message[MINUNIT_MESSAGE_LEN]; | ||||||
|  |  | ||||||
|  | /*  Test setup and teardown function pointers */ | ||||||
|  | static void (*minunit_setup)(void) = NULL; | ||||||
|  | static void (*minunit_teardown)(void) = NULL; | ||||||
|  |  | ||||||
|  | /*  Definitions */ | ||||||
|  | #define MU_TEST(method_name) static void method_name(void) | ||||||
|  | #define MU_TEST_SUITE(suite_name) static void suite_name(void) | ||||||
|  |  | ||||||
|  | #define MU__SAFE_BLOCK(block) do {\ | ||||||
|  | 	block\ | ||||||
|  | } while(0) | ||||||
|  |  | ||||||
|  | /*  Run test suite and unset setup and teardown functions */ | ||||||
|  | #define MU_RUN_SUITE(suite_name) MU__SAFE_BLOCK(\ | ||||||
|  | 	suite_name();\ | ||||||
|  | 	minunit_setup = NULL;\ | ||||||
|  | 	minunit_teardown = NULL;\ | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | /*  Configure setup and teardown functions */ | ||||||
|  | #define MU_SUITE_CONFIGURE(setup_fun, teardown_fun) MU__SAFE_BLOCK(\ | ||||||
|  | 	minunit_setup = setup_fun;\ | ||||||
|  | 	minunit_teardown = teardown_fun;\ | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | /*  Test runner */ | ||||||
|  | #define MU_RUN_TEST(test) MU__SAFE_BLOCK(\ | ||||||
|  | 	if (minunit_real_timer==0 && minunit_proc_timer==0) {\ | ||||||
|  | 		minunit_real_timer = mu_timer_real();\ | ||||||
|  | 		minunit_proc_timer = mu_timer_cpu();\ | ||||||
|  | 	}\ | ||||||
|  | 	if (minunit_setup) (*minunit_setup)();\ | ||||||
|  | 	minunit_status = 0;\ | ||||||
|  | 	test();\ | ||||||
|  | 	minunit_run++;\ | ||||||
|  | 	if (minunit_status) {\ | ||||||
|  | 		minunit_fail++;\ | ||||||
|  | 		printf("F");\ | ||||||
|  | 		printf("\n%s\n", minunit_last_message);\ | ||||||
|  | 	}\ | ||||||
|  | 	fflush(stdout);\ | ||||||
|  | 	if (minunit_teardown) (*minunit_teardown)();\ | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | /*  Report */ | ||||||
|  | #define MU_REPORT() MU__SAFE_BLOCK(\ | ||||||
|  | 	double minunit_end_real_timer;\ | ||||||
|  | 	double minunit_end_proc_timer;\ | ||||||
|  | 	printf("\n\n%d tests, %d assertions, %d failures\n", minunit_run, minunit_assert, minunit_fail);\ | ||||||
|  | 	minunit_end_real_timer = mu_timer_real();\ | ||||||
|  | 	minunit_end_proc_timer = mu_timer_cpu();\ | ||||||
|  | 	printf("\nFinished in %.8f seconds (real) %.8f seconds (proc)\n\n",\ | ||||||
|  | 		minunit_end_real_timer - minunit_real_timer,\ | ||||||
|  | 		minunit_end_proc_timer - minunit_proc_timer);\ | ||||||
|  | ) | ||||||
|  | #define MU_EXIT_CODE minunit_fail | ||||||
|  |  | ||||||
|  | /*  Assertions */ | ||||||
|  | #define mu_check(test) MU__SAFE_BLOCK(\ | ||||||
|  | 	minunit_assert++;\ | ||||||
|  | 	if (!(test)) {\ | ||||||
|  | 		snprintf(minunit_last_message, MINUNIT_MESSAGE_LEN, "%s failed:\n\t%s:%d: %s", __func__, __FILE__, __LINE__, #test);\ | ||||||
|  | 		minunit_status = 1;\ | ||||||
|  | 		return;\ | ||||||
|  | 	} else {\ | ||||||
|  | 		printf(".");\ | ||||||
|  | 	}\ | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | #define mu_fail(message) MU__SAFE_BLOCK(\ | ||||||
|  | 	minunit_assert++;\ | ||||||
|  | 	snprintf(minunit_last_message, MINUNIT_MESSAGE_LEN, "%s failed:\n\t%s:%d: %s", __func__, __FILE__, __LINE__, message);\ | ||||||
|  | 	minunit_status = 1;\ | ||||||
|  | 	return;\ | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | #define mu_assert(test, message) MU__SAFE_BLOCK(\ | ||||||
|  | 	minunit_assert++;\ | ||||||
|  | 	if (!(test)) {\ | ||||||
|  | 		snprintf(minunit_last_message, MINUNIT_MESSAGE_LEN, "%s failed:\n\t%s:%d: %s", __func__, __FILE__, __LINE__, message);\ | ||||||
|  | 		minunit_status = 1;\ | ||||||
|  | 		return;\ | ||||||
|  | 	} else {\ | ||||||
|  | 		printf(".");\ | ||||||
|  | 	}\ | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | #define mu_assert_int_eq(expected, result) MU__SAFE_BLOCK(\ | ||||||
|  | 	int minunit_tmp_e;\ | ||||||
|  | 	int minunit_tmp_r;\ | ||||||
|  | 	minunit_assert++;\ | ||||||
|  | 	minunit_tmp_e = (expected);\ | ||||||
|  | 	minunit_tmp_r = (result);\ | ||||||
|  | 	if (minunit_tmp_e != minunit_tmp_r) {\ | ||||||
|  | 		snprintf(minunit_last_message, MINUNIT_MESSAGE_LEN, "%s failed:\n\t%s:%d: %d expected but was %d", __func__, __FILE__, __LINE__, minunit_tmp_e, minunit_tmp_r);\ | ||||||
|  | 		minunit_status = 1;\ | ||||||
|  | 		return;\ | ||||||
|  | 	} else {\ | ||||||
|  | 		printf(".");\ | ||||||
|  | 	}\ | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | #define mu_assert_double_eq(expected, result) MU__SAFE_BLOCK(\ | ||||||
|  | 	double minunit_tmp_e;\ | ||||||
|  | 	double minunit_tmp_r;\ | ||||||
|  | 	minunit_assert++;\ | ||||||
|  | 	minunit_tmp_e = (expected);\ | ||||||
|  | 	minunit_tmp_r = (result);\ | ||||||
|  | 	if (fabs(minunit_tmp_e-minunit_tmp_r) > MINUNIT_EPSILON) {\ | ||||||
|  | 		int minunit_significant_figures = 1 - log10(MINUNIT_EPSILON);\ | ||||||
|  | 		snprintf(minunit_last_message, MINUNIT_MESSAGE_LEN, "%s failed:\n\t%s:%d: %.*g expected but was %.*g", __func__, __FILE__, __LINE__, minunit_significant_figures, minunit_tmp_e, minunit_significant_figures, minunit_tmp_r);\ | ||||||
|  | 		minunit_status = 1;\ | ||||||
|  | 		return;\ | ||||||
|  | 	} else {\ | ||||||
|  | 		printf(".");\ | ||||||
|  | 	}\ | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | #define mu_assert_string_eq(expected, result) MU__SAFE_BLOCK(\ | ||||||
|  | 	const char* minunit_tmp_e = expected;\ | ||||||
|  | 	const char* minunit_tmp_r = result;\ | ||||||
|  | 	minunit_assert++;\ | ||||||
|  | 	if (!minunit_tmp_e) {\ | ||||||
|  | 		minunit_tmp_e = "<null pointer>";\ | ||||||
|  | 	}\ | ||||||
|  | 	if (!minunit_tmp_r) {\ | ||||||
|  | 		minunit_tmp_r = "<null pointer>";\ | ||||||
|  | 	}\ | ||||||
|  | 	if(strcmp(minunit_tmp_e, minunit_tmp_r)) {\ | ||||||
|  | 		snprintf(minunit_last_message, MINUNIT_MESSAGE_LEN, "%s failed:\n\t%s:%d: '%s' expected but was '%s'", __func__, __FILE__, __LINE__, minunit_tmp_e, minunit_tmp_r);\ | ||||||
|  | 		minunit_status = 1;\ | ||||||
|  | 		return;\ | ||||||
|  | 	} else {\ | ||||||
|  | 		printf(".");\ | ||||||
|  | 	}\ | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | /* | ||||||
|  |  * The following two functions were written by David Robert Nadeau | ||||||
|  |  * from http://NadeauSoftware.com/ and distributed under the | ||||||
|  |  * Creative Commons Attribution 3.0 Unported License | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * Returns the real time, in seconds, or -1.0 if an error occurred. | ||||||
|  |  * | ||||||
|  |  * Time is measured since an arbitrary and OS-dependent start time. | ||||||
|  |  * The returned real time is only useful for computing an elapsed time | ||||||
|  |  * between two calls to this function. | ||||||
|  |  */ | ||||||
|  | static double mu_timer_real(void) | ||||||
|  | { | ||||||
|  | #if defined(_WIN32) | ||||||
|  | 	/* Windows 2000 and later. ---------------------------------- */ | ||||||
|  | 	LARGE_INTEGER Time; | ||||||
|  | 	LARGE_INTEGER Frequency; | ||||||
|  | 	 | ||||||
|  | 	QueryPerformanceFrequency(&Frequency); | ||||||
|  | 	QueryPerformanceCounter(&Time); | ||||||
|  | 	 | ||||||
|  | 	Time.QuadPart *= 1000000; | ||||||
|  | 	Time.QuadPart /= Frequency.QuadPart; | ||||||
|  | 	 | ||||||
|  | 	return (double)Time.QuadPart / 1000000.0; | ||||||
|  |  | ||||||
|  | #elif (defined(__hpux) || defined(hpux)) || ((defined(__sun__) || defined(__sun) || defined(sun)) && (defined(__SVR4) || defined(__svr4__))) | ||||||
|  | 	/* HP-UX, Solaris. ------------------------------------------ */ | ||||||
|  | 	return (double)gethrtime( ) / 1000000000.0; | ||||||
|  |  | ||||||
|  | #elif defined(__MACH__) && defined(__APPLE__) | ||||||
|  | 	/* OSX. ----------------------------------------------------- */ | ||||||
|  | 	static double timeConvert = 0.0; | ||||||
|  | 	if ( timeConvert == 0.0 ) | ||||||
|  | 	{ | ||||||
|  | 		mach_timebase_info_data_t timeBase; | ||||||
|  | 		(void)mach_timebase_info( &timeBase ); | ||||||
|  | 		timeConvert = (double)timeBase.numer / | ||||||
|  | 			(double)timeBase.denom / | ||||||
|  | 			1000000000.0; | ||||||
|  | 	} | ||||||
|  | 	return (double)mach_absolute_time( ) * timeConvert; | ||||||
|  |  | ||||||
|  | #elif defined(_POSIX_VERSION) | ||||||
|  | 	/* POSIX. --------------------------------------------------- */ | ||||||
|  | 	struct timeval tm; | ||||||
|  | #if defined(_POSIX_TIMERS) && (_POSIX_TIMERS > 0) | ||||||
|  | 	{ | ||||||
|  | 		struct timespec ts; | ||||||
|  | #if defined(CLOCK_MONOTONIC_PRECISE) | ||||||
|  | 		/* BSD. --------------------------------------------- */ | ||||||
|  | 		const clockid_t id = CLOCK_MONOTONIC_PRECISE; | ||||||
|  | #elif defined(CLOCK_MONOTONIC_RAW) | ||||||
|  | 		/* Linux. ------------------------------------------- */ | ||||||
|  | 		const clockid_t id = CLOCK_MONOTONIC_RAW; | ||||||
|  | #elif defined(CLOCK_HIGHRES) | ||||||
|  | 		/* Solaris. ----------------------------------------- */ | ||||||
|  | 		const clockid_t id = CLOCK_HIGHRES; | ||||||
|  | #elif defined(CLOCK_MONOTONIC) | ||||||
|  | 		/* AIX, BSD, Linux, POSIX, Solaris. ----------------- */ | ||||||
|  | 		const clockid_t id = CLOCK_MONOTONIC; | ||||||
|  | #elif defined(CLOCK_REALTIME) | ||||||
|  | 		/* AIX, BSD, HP-UX, Linux, POSIX. ------------------- */ | ||||||
|  | 		const clockid_t id = CLOCK_REALTIME; | ||||||
|  | #else | ||||||
|  | 		const clockid_t id = (clockid_t)-1;	/* Unknown. */ | ||||||
|  | #endif /* CLOCK_* */ | ||||||
|  | 		if ( id != (clockid_t)-1 && clock_gettime( id, &ts ) != -1 ) | ||||||
|  | 			return (double)ts.tv_sec + | ||||||
|  | 				(double)ts.tv_nsec / 1000000000.0; | ||||||
|  | 		/* Fall thru. */ | ||||||
|  | 	} | ||||||
|  | #endif /* _POSIX_TIMERS */ | ||||||
|  |  | ||||||
|  | 	/* AIX, BSD, Cygwin, HP-UX, Linux, OSX, POSIX, Solaris. ----- */ | ||||||
|  | 	gettimeofday( &tm, NULL ); | ||||||
|  | 	return (double)tm.tv_sec + (double)tm.tv_usec / 1000000.0; | ||||||
|  | #else | ||||||
|  | 	return -1.0;		/* Failed. */ | ||||||
|  | #endif | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * Returns the amount of CPU time used by the current process, | ||||||
|  |  * in seconds, or -1.0 if an error occurred. | ||||||
|  |  */ | ||||||
|  | static double mu_timer_cpu(void) | ||||||
|  | { | ||||||
|  | #if defined(_WIN32) | ||||||
|  | 	/* Windows -------------------------------------------------- */ | ||||||
|  | 	FILETIME createTime; | ||||||
|  | 	FILETIME exitTime; | ||||||
|  | 	FILETIME kernelTime; | ||||||
|  | 	FILETIME userTime; | ||||||
|  |  | ||||||
|  | 	/* This approach has a resolution of 1/64 second. Unfortunately, Windows' API does not offer better */ | ||||||
|  | 	if ( GetProcessTimes( GetCurrentProcess( ), | ||||||
|  | 		&createTime, &exitTime, &kernelTime, &userTime ) != 0 ) | ||||||
|  | 	{ | ||||||
|  | 		ULARGE_INTEGER userSystemTime; | ||||||
|  | 		memcpy(&userSystemTime, &userTime, sizeof(ULARGE_INTEGER)); | ||||||
|  | 		return (double)userSystemTime.QuadPart / 10000000.0; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | #elif defined(__unix__) || defined(__unix) || defined(unix) || (defined(__APPLE__) && defined(__MACH__)) | ||||||
|  | 	/* AIX, BSD, Cygwin, HP-UX, Linux, OSX, and Solaris --------- */ | ||||||
|  |  | ||||||
|  | #if defined(_POSIX_TIMERS) && (_POSIX_TIMERS > 0) | ||||||
|  | 	/* Prefer high-res POSIX timers, when available. */ | ||||||
|  | 	{ | ||||||
|  | 		clockid_t id; | ||||||
|  | 		struct timespec ts; | ||||||
|  | #if _POSIX_CPUTIME > 0 | ||||||
|  | 		/* Clock ids vary by OS.  Query the id, if possible. */ | ||||||
|  | 		if ( clock_getcpuclockid( 0, &id ) == -1 ) | ||||||
|  | #endif | ||||||
|  | #if defined(CLOCK_PROCESS_CPUTIME_ID) | ||||||
|  | 			/* Use known clock id for AIX, Linux, or Solaris. */ | ||||||
|  | 			id = CLOCK_PROCESS_CPUTIME_ID; | ||||||
|  | #elif defined(CLOCK_VIRTUAL) | ||||||
|  | 			/* Use known clock id for BSD or HP-UX. */ | ||||||
|  | 			id = CLOCK_VIRTUAL; | ||||||
|  | #else | ||||||
|  | 			id = (clockid_t)-1; | ||||||
|  | #endif | ||||||
|  | 		if ( id != (clockid_t)-1 && clock_gettime( id, &ts ) != -1 ) | ||||||
|  | 			return (double)ts.tv_sec + | ||||||
|  | 				(double)ts.tv_nsec / 1000000000.0; | ||||||
|  | 	} | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | #if defined(RUSAGE_SELF) | ||||||
|  | 	{ | ||||||
|  | 		struct rusage rusage; | ||||||
|  | 		if ( getrusage( RUSAGE_SELF, &rusage ) != -1 ) | ||||||
|  | 			return (double)rusage.ru_utime.tv_sec + | ||||||
|  | 				(double)rusage.ru_utime.tv_usec / 1000000.0; | ||||||
|  | 	} | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | #if defined(_SC_CLK_TCK) | ||||||
|  | 	{ | ||||||
|  | 		const double ticks = (double)sysconf( _SC_CLK_TCK ); | ||||||
|  | 		struct tms tms; | ||||||
|  | 		if ( times( &tms ) != (clock_t)-1 ) | ||||||
|  | 			return (double)tms.tms_utime / ticks; | ||||||
|  | 	} | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | #if defined(CLOCKS_PER_SEC) | ||||||
|  | 	{ | ||||||
|  | 		clock_t cl = clock( ); | ||||||
|  | 		if ( cl != (clock_t)-1 ) | ||||||
|  | 			return (double)cl / (double)CLOCKS_PER_SEC; | ||||||
|  | 	} | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | 	return -1;		/* Failed. */ | ||||||
|  | } | ||||||
|  |  | ||||||
|  | #ifdef __cplusplus | ||||||
|  | } | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | #endif /* MINUNIT_MINUNIT_H */ | ||||||
							
								
								
									
										13
									
								
								experimental/facho-signer/src/xades/minunit_ext.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								experimental/facho-signer/src/xades/minunit_ext.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,13 @@ | |||||||
|  | #ifndef MINUNIT_EXT_H | ||||||
|  |  | ||||||
|  | #include <string.h> | ||||||
|  |  | ||||||
|  | #include "minunit.h" | ||||||
|  |  | ||||||
|  | // cuando escribe esto el compilar me arrojo que si no era | ||||||
|  | // mejor usar mu_assert_string_eq increble a  | ||||||
|  | //int mu_assert_string_equals(const char *a, const char *b) { | ||||||
|  | //  return mu_assert(strcmp(a, b) == 0, "string not equals"); | ||||||
|  | //} | ||||||
|  |  | ||||||
|  | #endif //MINUNIT_EXT_H | ||||||
							
								
								
									
										456
									
								
								experimental/facho-signer/src/xades/templates.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										456
									
								
								experimental/facho-signer/src/xades/templates.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,456 @@ | |||||||
|  | /** | ||||||
|  |  * This file is part of facho.  The COPYRIGHT file at the top level of | ||||||
|  |  * this repository contains the full copyright notices and license terms. | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | #include "xades.h" | ||||||
|  |  | ||||||
|  | #include <xmlsec/templates.h> | ||||||
|  |  | ||||||
|  | #include <time.h> | ||||||
|  | #include <string.h> | ||||||
|  |  | ||||||
|  | static const xmlChar xmlXadesNodeQualifyingProperties[] = "QualifyingProperties"; | ||||||
|  | static const xmlChar xmlXadesNodeSignedProperties[] = "SignedProperties"; | ||||||
|  |  | ||||||
|  | static const xmlChar xmlXadesNodeSignedSignatureProperties[] = "SignedSignatureProperties"; | ||||||
|  | static const xmlChar xmlXadesNodeSigningTime[] = "SigningTime"; | ||||||
|  | static const xmlChar xmlXadesNodeSigningCertificate[] = "SigningCertificate"; | ||||||
|  | static const xmlChar xmlXadesNodeCert[] = "Cert"; | ||||||
|  | static const xmlChar xmlXadesNodeCertDigest[] = "CertDigest"; | ||||||
|  | static const xmlChar xmlXadesNodeSignaturePolicyIdentifier[] = "SignaturePolicyIdentifier"; | ||||||
|  | static const xmlChar xmlXadesNodeSignaturePolicyId[] = "SignaturePolicyId"; | ||||||
|  | static const xmlChar xmlXadesNodeSigPolicyId[] = "SigPolicyId"; | ||||||
|  | static const xmlChar xmlXadesNodeIdentifier[] = "Identifier"; | ||||||
|  | static const xmlChar xmlXadesNodeDescription[] = "Description"; | ||||||
|  | static const xmlChar xmlXadesNodeSigPolicyHash[] = "SigPolicyHash"; | ||||||
|  |  | ||||||
|  | static const xmlChar xmlXadesNodeSignerRole[] = "SignerRole"; | ||||||
|  | static const xmlChar xmlXadesNodeClaimedRoles[] = "ClaimedRoles"; | ||||||
|  | static const xmlChar xmlXadesNodeClaimedRole[] = "ClaimedRole"; | ||||||
|  | static const xmlChar xmlXadesNodeIssuerSerial[] = "IssuerSerial"; | ||||||
|  | static const xmlChar xmlXadesNodeX509IssuerName[] = "X509IssuerName"; | ||||||
|  | static const xmlChar xmlXadesNodeX509IssuerNumber[] = "X509IssuerNumber"; | ||||||
|  |    | ||||||
|  | static const xmlChar xmlXadesDSigNs[] = "http://uri.etsi.org/01903/v1.3.2#"; | ||||||
|  |  | ||||||
|  | xmlNodePtr | ||||||
|  | xmlXadesAddChildRecursiveNs(xmlNodePtr startNode, const xmlChar* path, const xmlChar* nsPrefix) { | ||||||
|  |   char *curToken; | ||||||
|  |   char* cpath = strdup((char *)path); | ||||||
|  |   char* savePtr; | ||||||
|  |   xmlNodePtr curNode = NULL; | ||||||
|  |   xmlNodePtr parentNode = startNode; | ||||||
|  |  | ||||||
|  |  | ||||||
|  |   curToken = strtok_r(cpath, "/", &savePtr); | ||||||
|  |   while(curToken != NULL) { | ||||||
|  |     curNode = xmlSecFindChild(parentNode, BAD_CAST curToken, nsPrefix); | ||||||
|  |     if (curNode == NULL) { | ||||||
|  |       curNode = xmlSecAddChild(parentNode, BAD_CAST curToken, nsPrefix); | ||||||
|  |       if (curNode == NULL) { | ||||||
|  |         xmlXadesInternalError("xmlSecAddChild(%s)", curToken); | ||||||
|  |         return(NULL); | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     parentNode = curNode; | ||||||
|  |  | ||||||
|  |     curToken = strtok_r(NULL, "/", &savePtr); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   free(cpath); | ||||||
|  |   return(curNode); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | xmlNodePtr | ||||||
|  | xmlXadesTmplQualifyingPropertiesCreate(xmlDocPtr doc, xmlNodePtr signatureNode, const xmlChar *id) { | ||||||
|  |   xmlNodePtr objectNode; | ||||||
|  |   xmlNodePtr qualifyingPropertiesNode; | ||||||
|  |  | ||||||
|  |   xmlNewGlobalNs(doc, xmlXadesDSigNs, BAD_CAST "xades"); | ||||||
|  |  | ||||||
|  |   objectNode = xmlSecTmplSignatureAddObject(signatureNode, NULL, NULL, NULL); | ||||||
|  |   if (objectNode == NULL) { | ||||||
|  |     xmlXadesInternalError("xmlSecTmplSignatureAddObject(signatureNode)", NULL); | ||||||
|  |     return(NULL); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   qualifyingPropertiesNode = xmlSecAddChild(objectNode, xmlXadesNodeQualifyingProperties, xmlXadesDSigNs); | ||||||
|  |   if (qualifyingPropertiesNode == NULL) { | ||||||
|  |     xmlXadesXmlError2("xmlNewDocNode", NULL, "node=%s", xmlXadesErrorsSafeString(xmlXadesNodeQualifyingProperties)); | ||||||
|  |     return(NULL); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   if (id != NULL) { | ||||||
|  |     xmlSetProp(qualifyingPropertiesNode, BAD_CAST "Id", id); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   return(qualifyingPropertiesNode); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | xmlNodePtr | ||||||
|  | xmlXadesTmplQualifyingPropertiesCreateNsPref(xmlDocPtr doc, const xmlChar* id, const xmlChar* nsPrefix) { | ||||||
|  |   xmlNodePtr qualifyingPropertiesNode; | ||||||
|  |   xmlNsPtr ns; | ||||||
|  |  | ||||||
|  |   // crear nodo | ||||||
|  |   qualifyingPropertiesNode = xmlNewDocNode(doc, NULL, xmlXadesNodeQualifyingProperties, NULL); | ||||||
|  |   if (qualifyingPropertiesNode == NULL) { | ||||||
|  |     xmlXadesXmlError2("xmlNewDocNode", NULL, "node=%s", xmlXadesErrorsSafeString(xmlXadesNodeQualifyingProperties)); | ||||||
|  |     return(NULL); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   // crear namespace y asignar | ||||||
|  |   ns = xmlNewNs(qualifyingPropertiesNode, xmlXadesDSigNs, nsPrefix); | ||||||
|  |   if (ns == NULL) { | ||||||
|  |     xmlXadesXmlError2("xmlNewNs", NULL, | ||||||
|  |                    "ns=%s", xmlXadesErrorsSafeString(xmlXadesDSigNs)); | ||||||
|  |     xmlFreeNode(qualifyingPropertiesNode); | ||||||
|  |     return(NULL); | ||||||
|  |   } | ||||||
|  |   xmlSetNs(qualifyingPropertiesNode, ns); | ||||||
|  |  | ||||||
|  |   if (id != NULL) { | ||||||
|  |     xmlSetProp(qualifyingPropertiesNode, BAD_CAST "Id", id); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   | ||||||
|  |   return (qualifyingPropertiesNode); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | xmlNodePtr | ||||||
|  | xmlXadesTmplAddSignedProperties(xmlNodePtr qualifyingPropertiesNode, const xmlChar* id) { | ||||||
|  |   xmlNodePtr cur; | ||||||
|  |  | ||||||
|  |   xmlXadesAssert2(qualifyingPropertiesNode != NULL, NULL); | ||||||
|  |    | ||||||
|  |   cur = xmlSecAddChild(qualifyingPropertiesNode, xmlXadesNodeSignedProperties, xmlXadesDSigNs); | ||||||
|  |   if (cur == NULL) { | ||||||
|  |     xmlXadesInternalError("xmlSecAddChild(xmlXadesNodeSignedProperties)", NULL); | ||||||
|  |     return(NULL); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   if (id != NULL) { | ||||||
|  |     xmlSetProp(cur, BAD_CAST "Id", id); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   return(cur); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | xmlNodePtr | ||||||
|  | xmlXadesTmplAddSignedSignatureProperties(xmlNodePtr signedPropertiesNode, struct tm* signingTime) { | ||||||
|  |   xmlNodePtr cur; | ||||||
|  |   xmlNodePtr node; | ||||||
|  |  | ||||||
|  |   xmlXadesAssert2(signedPropertiesNode != NULL, NULL); | ||||||
|  |    | ||||||
|  |   // add SignedSignatureProperties | ||||||
|  |   node = xmlSecAddChild(signedPropertiesNode, xmlXadesNodeSignedSignatureProperties, xmlXadesDSigNs); | ||||||
|  |   if (node == NULL) { | ||||||
|  |     xmlXadesInternalError("xmlSecAddChild(xmlXadesNodeSignedSignatureProperties)", NULL); | ||||||
|  |     return(NULL); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   // add SignigTime | ||||||
|  |   cur = xmlSecAddChild(node, xmlXadesNodeSigningTime, xmlXadesDSigNs); | ||||||
|  |   if (cur == NULL) { | ||||||
|  |     xmlXadesInternalError("xmlSecAddChild(xmlXadesNodeSigningTime)", NULL); | ||||||
|  |     xmlFreeNode(node); | ||||||
|  |     return(NULL); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   { | ||||||
|  |     int ret; | ||||||
|  |     char strtime[200]; | ||||||
|  |  | ||||||
|  |     if (strftime(strtime, sizeof(strtime), "%Y-%m-%dT%T", signingTime) == 0) { | ||||||
|  |       xmlXadesInternalError("strftime", NULL); | ||||||
|  |       xmlFreeNode(cur); | ||||||
|  |       xmlFreeNode(node); | ||||||
|  |       return(NULL); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     ret = xmlSecNodeEncodeAndSetContent(cur, BAD_CAST strtime); | ||||||
|  |     if (ret < 0) { | ||||||
|  |       xmlXadesInternalError("xmlSecNodeEncodeAndSetContent", NULL); | ||||||
|  |       xmlFreeNode(cur); | ||||||
|  |       xmlFreeNode(node); | ||||||
|  |       return(NULL); | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   return(node); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | xmlNodePtr | ||||||
|  | xmlXadesTmplAddSigningCertificate(xmlNodePtr signedSignaturePropertiesNode, xmlSecTransformId digestMethodId) { | ||||||
|  |   xmlNodePtr node; | ||||||
|  |  | ||||||
|  |   xmlXadesAssert2(signedSignaturePropertiesNode != NULL, NULL); | ||||||
|  |   if (xmlSecFindChild(signedSignaturePropertiesNode, xmlXadesNodeSigningCertificate, xmlXadesDSigNs) != NULL) { | ||||||
|  |     xmlXadesNodeAlreadyPresentError(signedSignaturePropertiesNode, xmlXadesNodeSigningCertificate, NULL); | ||||||
|  |     return(NULL); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   node = xmlSecAddChild(signedSignaturePropertiesNode, xmlXadesNodeSigningCertificate, xmlXadesDSigNs); | ||||||
|  |   if (node == NULL) { | ||||||
|  |     xmlXadesInternalError("xmlsecAddChild(xmlXadesNodeSigningCertificate)", NULL); | ||||||
|  |     return(NULL); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   return(node); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | xmlNodePtr | ||||||
|  | xmlXadesTmplAddCert(xmlNodePtr signingCertificateNode) { | ||||||
|  |   xmlNodePtr certNode; | ||||||
|  |  | ||||||
|  |   xmlXadesAssert2(signingCertificateNode != NULL, NULL); | ||||||
|  |  | ||||||
|  |   certNode = xmlSecAddChild(signingCertificateNode, xmlXadesNodeCert, xmlXadesDSigNs); | ||||||
|  |   if (certNode == NULL) { | ||||||
|  |     xmlXadesInternalError("xmlSecAddChild(xmlXadesNodeCert)", NULL); | ||||||
|  |     return(NULL); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   return(certNode); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | xmlNodePtr | ||||||
|  | xmlXadesTmplAddCertDigest(xmlNodePtr certNode, const xmlChar *digestMethod, const xmlChar *digestValue) { | ||||||
|  |   xmlNodePtr node; | ||||||
|  |  | ||||||
|  |   xmlXadesAssert2(certNode != NULL, NULL); | ||||||
|  |  | ||||||
|  |   node = xmlSecAddChild(certNode, xmlXadesNodeCertDigest, xmlXadesDSigNs); | ||||||
|  |   if ( node == NULL ) { | ||||||
|  |     xmlXadesInternalError("xmlSecAddChild(xmlXadesNodeCertDigest)", NULL); | ||||||
|  |     return(NULL); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   if ( xmlXadesTmplAddDigest(node, digestMethod, digestValue) == NULL) { | ||||||
|  |     xmlXadesInternalError("xmlXadesTmplAddDigest(node, digestMethodId)", NULL); | ||||||
|  |     return(NULL); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   return(certNode); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | xmlNodePtr | ||||||
|  | xmlXadesTmplAddSignaturePolicyIdentifier(xmlNodePtr signedSignaturePropertiesNode) { | ||||||
|  |   xmlNodePtr cur; | ||||||
|  |  | ||||||
|  |   xmlXadesAssert2(signedSignaturePropertiesNode != NULL, NULL); | ||||||
|  |  | ||||||
|  |   cur = xmlSecAddChild(signedSignaturePropertiesNode, xmlXadesNodeSignaturePolicyIdentifier, xmlXadesDSigNs); | ||||||
|  |   if (cur == NULL) { | ||||||
|  |     xmlXadesInternalError("xmlsecAddChild(xmlXadesNodeSignaturePolicyIdentifier)", NULL); | ||||||
|  |     return(NULL); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   return(cur); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | xmlNodePtr | ||||||
|  | xmlXadesTmplAddSignaturePolicyId(xmlNodePtr signaturePolicyIdentifierNode) { | ||||||
|  |   xmlNodePtr cur; | ||||||
|  |  | ||||||
|  |   xmlXadesAssert2(signaturePolicyIdentifierNode != NULL, NULL); | ||||||
|  |  | ||||||
|  |   cur = xmlSecAddChild(signaturePolicyIdentifierNode, xmlXadesNodeSignaturePolicyId, xmlXadesDSigNs); | ||||||
|  |   if (cur == NULL) { | ||||||
|  |     xmlXadesInternalError("xmlsecAddChild(cur)", NULL); | ||||||
|  |     return(NULL); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   return(cur); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | xmlNodePtr | ||||||
|  | xmlXadesTmplAddSigPolicyId(xmlNodePtr signaturePolicyId, const xmlChar* identifier, const xmlChar *description) { | ||||||
|  |   xmlNodePtr sigPolicyIdNode; | ||||||
|  |   xmlNodePtr node; | ||||||
|  |   int ret; | ||||||
|  |    | ||||||
|  |   sigPolicyIdNode = xmlSecAddChild(signaturePolicyId, xmlXadesNodeSigPolicyId, xmlXadesDSigNs); | ||||||
|  |   if (sigPolicyIdNode == NULL) { | ||||||
|  |     xmlXadesInternalError("xmlSecAddChild(xmlXadesNodeSigPolicyId)", NULL); | ||||||
|  |     return(NULL); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   node = xmlSecAddChild(sigPolicyIdNode, xmlXadesNodeIdentifier, xmlXadesDSigNs); | ||||||
|  |   if (node == NULL) { | ||||||
|  |     xmlXadesInternalError("xmlSecAddChild(xmlXadesNodeIdentifier)", NULL); | ||||||
|  |     xmlFreeNode(sigPolicyIdNode); | ||||||
|  |     return(NULL); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   ret = xmlSecNodeEncodeAndSetContent(node, identifier); | ||||||
|  |   if (ret < 0) { | ||||||
|  |     xmlXadesInternalError("xmlSecNodeEncodeAndSetContent", NULL); | ||||||
|  |     xmlFreeNode(sigPolicyIdNode); | ||||||
|  |     xmlFreeNode(node); | ||||||
|  |     return(NULL); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   node = xmlSecAddChild(sigPolicyIdNode, xmlXadesNodeDescription, xmlXadesDSigNs); | ||||||
|  |   if (node == NULL) { | ||||||
|  |     xmlXadesInternalError("xmlSecAddChild(xmlXadesNodeDescription)", NULL); | ||||||
|  |     xmlFreeNode(sigPolicyIdNode); | ||||||
|  |     return(NULL); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   ret = xmlSecNodeEncodeAndSetContent(node, description); | ||||||
|  |   if (ret < 0) { | ||||||
|  |     xmlXadesInternalError("xmlSecNodeEncodeAndSetContent", NULL); | ||||||
|  |     xmlFreeNode(sigPolicyIdNode); | ||||||
|  |     xmlFreeNode(node); | ||||||
|  |     return(NULL); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   return(sigPolicyIdNode); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | xmlNodePtr | ||||||
|  | xmlXadesTmplAddSigPolicyHash(xmlNodePtr parentNode, xmlSecTransformId digestMethodId) { | ||||||
|  |   xmlNodePtr node; | ||||||
|  |   xmlXadesAssert2(parentNode != NULL, NULL); | ||||||
|  |  | ||||||
|  |   //add policyHash | ||||||
|  |   node = xmlSecAddChild(parentNode, xmlXadesNodeSigPolicyHash, xmlXadesDSigNs); | ||||||
|  |   if (node == NULL) { | ||||||
|  |     xmlXadesInternalError("xmlSecAddChild(xmlXadesNodeSigPolicyHash)", NULL); | ||||||
|  |     return(NULL); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   if ( xmlXadesTmplAddDigest(node, digestMethodId->href, NULL) == NULL) { | ||||||
|  |     xmlXadesInternalError("xmlXadesTmplAddDigest(node, digestMethodId)", NULL); | ||||||
|  |     return(NULL); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   return node; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // MACHETE(bit4bit) como usar SecTransform para almacenar el digest | ||||||
|  | xmlNodePtr | ||||||
|  | xmlXadesTmplAddDigest(xmlNodePtr parentNode, const xmlChar *digestMethod, const xmlChar *digestValue) { | ||||||
|  |   xmlNodePtr node; | ||||||
|  |    | ||||||
|  |   xmlXadesAssert2(parentNode != NULL, NULL); | ||||||
|  |  | ||||||
|  |   if ( digestMethod != NULL ) { | ||||||
|  |     node = xmlSecAddChild(parentNode, xmlSecNodeDigestMethod, xmlSecDSigNs); | ||||||
|  |     if (node == NULL) { | ||||||
|  |       xmlXadesInternalError("xmlSecAddChild(xmlSecNodeDigestMethod)", NULL); | ||||||
|  |       return(NULL); | ||||||
|  |     } | ||||||
|  |     if (xmlSetProp(node, xmlSecAttrAlgorithm, digestMethod) == NULL) { | ||||||
|  |       xmlXadesXmlError2("xmlSetProp", NULL, | ||||||
|  |                         "name=%s", xmlXadesErrorsSafeString(xmlSecAttrAlgorithm)); | ||||||
|  |       xmlUnlinkNode(node); | ||||||
|  |       xmlFreeNode(node); | ||||||
|  |       return(NULL); | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   if ( digestValue != NULL ) { | ||||||
|  |     node = xmlSecAddChild(parentNode, xmlSecNodeDigestValue, xmlSecDSigNs); | ||||||
|  |     if (node == NULL) { | ||||||
|  |       xmlXadesInternalError("xmlSecAddChild(xmlSecNodeDigestValue)", NULL); | ||||||
|  |       return(NULL); | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     if (xmlSecNodeEncodeAndSetContent(node, digestValue) < 0) { | ||||||
|  |       xmlXadesInternalError("xmlSecNodeEncodeAndSetContent", NULL); | ||||||
|  |       return(NULL); | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |    | ||||||
|  |   return parentNode; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | xmlNodePtr | ||||||
|  | xmlXadesTmplAddSignerRole(xmlNodePtr signedSignaturePropertiesNode, const xmlChar* role) { | ||||||
|  |   xmlNodePtr signerRoleNode; | ||||||
|  |   xmlNodePtr claimedRolesNode; | ||||||
|  |   xmlNodePtr claimedRoleNode; | ||||||
|  |   int ret; | ||||||
|  |  | ||||||
|  |   signerRoleNode = xmlSecAddChild(signedSignaturePropertiesNode, xmlXadesNodeSignerRole, xmlXadesDSigNs); | ||||||
|  |   if (signerRoleNode == NULL) { | ||||||
|  |     xmlXadesInternalError("xmlSecAddChild(xmlXadesNodeSignerRole)", NULL); | ||||||
|  |     return(NULL); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   claimedRolesNode = xmlSecAddChild(signerRoleNode, xmlXadesNodeClaimedRoles, xmlXadesDSigNs); | ||||||
|  |   if (claimedRolesNode == NULL) { | ||||||
|  |     xmlXadesInternalError("xmlSecAddChild(xmlXadesNodeClaimedRoles)", NULL); | ||||||
|  |     xmlUnlinkNode(signerRoleNode); | ||||||
|  |     xmlFreeNode(signerRoleNode); | ||||||
|  |     return(NULL); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   claimedRoleNode = xmlSecAddChild(claimedRolesNode, xmlXadesNodeClaimedRole, xmlXadesDSigNs); | ||||||
|  |   if (claimedRoleNode == NULL) { | ||||||
|  |     xmlXadesInternalError("xmlSecAddChild(xmlXadesNodeClaimedRole)", NULL); | ||||||
|  |     xmlUnlinkNode(signerRoleNode); | ||||||
|  |     xmlFreeNode(signerRoleNode); | ||||||
|  |     return(NULL); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   ret = xmlSecNodeEncodeAndSetContent(claimedRoleNode, role); | ||||||
|  |   if (ret < 0) { | ||||||
|  |     xmlXadesInternalError("xmlSecNodeEncodeAndSetContent", NULL); | ||||||
|  |     xmlUnlinkNode(signerRoleNode); | ||||||
|  |     xmlFreeNode(signerRoleNode); | ||||||
|  |     return(NULL); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   return(signerRoleNode); | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | xmlNodePtr | ||||||
|  | xmlXadesTmplAddIssuerSerial(xmlNodePtr certNode, const xmlChar *issuerName, const xmlChar *issuerNumber) { | ||||||
|  |   xmlNodePtr issuerSerialNode; | ||||||
|  |   xmlNodePtr node; | ||||||
|  |  | ||||||
|  |   xmlXadesAssert2(certNode != NULL, NULL); | ||||||
|  |  | ||||||
|  |   issuerSerialNode = xmlSecAddChild(certNode, xmlXadesNodeIssuerSerial, xmlXadesDSigNs); | ||||||
|  |   if ( issuerSerialNode == NULL ) { | ||||||
|  |     xmlXadesInternalError("xmlSecAddChild(certNode, xmlXadesIssuerSerial)", NULL); | ||||||
|  |     return(NULL); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   node = xmlSecAddChild(issuerSerialNode, xmlXadesNodeX509IssuerName, xmlSecDSigNs); | ||||||
|  |   if ( node == NULL ) { | ||||||
|  |     xmlXadesInternalError("xmlSecAddChild(xmlXadesNodeX509IssuerName)", NULL); | ||||||
|  |     xmlFreeNode(issuerSerialNode); | ||||||
|  |     return(NULL); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   if (xmlSecNodeEncodeAndSetContent(node, issuerName) < 0) { | ||||||
|  |     xmlXadesInternalError("xmlSecNodeEncodeAndSetContent", NULL); | ||||||
|  |     xmlUnlinkNode(issuerSerialNode); | ||||||
|  |     xmlFreeNode(issuerSerialNode); | ||||||
|  |     return(NULL); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   node = xmlSecAddChild(issuerSerialNode, xmlXadesNodeX509IssuerNumber, xmlSecDSigNs); | ||||||
|  |   if ( node == NULL ) { | ||||||
|  |     xmlXadesInternalError("xmlSecAddChild(xmlXadesNodeX509IssuerNumber)", NULL); | ||||||
|  |     xmlFreeNode(issuerSerialNode); | ||||||
|  |     return(NULL); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   if (xmlSecNodeEncodeAndSetContent(node, issuerNumber) < 0) { | ||||||
|  |     xmlXadesInternalError("xmlSecNodeEncodeAndSetContent", NULL); | ||||||
|  |     xmlUnlinkNode(issuerSerialNode); | ||||||
|  |     xmlFreeNode(issuerSerialNode); | ||||||
|  |     return(NULL); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   return(issuerSerialNode); | ||||||
|  | } | ||||||
							
								
								
									
										301
									
								
								experimental/facho-signer/src/xades/xades.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										301
									
								
								experimental/facho-signer/src/xades/xades.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,301 @@ | |||||||
|  | /** | ||||||
|  |  * This file is part of facho.  The COPYRIGHT file at the top level of | ||||||
|  |  * this repository contains the full copyright notices and license terms. | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | #include "config.h" | ||||||
|  |  | ||||||
|  | #include "xades.h" | ||||||
|  |  | ||||||
|  | #include <libxml/xpath.h> | ||||||
|  | #include <libxml/xpathInternals.h> | ||||||
|  | #include <openssl/x509.h> | ||||||
|  | #include <openssl/x509v3.h> | ||||||
|  | #include <openssl/bio.h> | ||||||
|  | #include <openssl/asn1.h> | ||||||
|  | #include <openssl/bn.h> | ||||||
|  |  | ||||||
|  | #include <xmlsec/buffer.h> | ||||||
|  | #include <xmlsec/app.h> | ||||||
|  | #include <xmlsec/transforms.h> | ||||||
|  | #include <xmlsec/keysdata.h> | ||||||
|  |  | ||||||
|  | #ifdef XMLSEC_NO_CRYPTO_DYNAMIC_LOADING | ||||||
|  | #include <xmlsec/openssl/x509.h> | ||||||
|  | #include <xmlsec/openssl/crypto.h> | ||||||
|  | #include <xmlsec/openssl/symbols.h> | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | #include <string.h> | ||||||
|  | #include <ctype.h> | ||||||
|  |  | ||||||
|  |  | ||||||
|  | static xmlChar * | ||||||
|  | xmlXadesSha256DigestValueInBase64(const unsigned char *message, size_t message_len); | ||||||
|  |  | ||||||
|  | static xmlNodePtr | ||||||
|  | xmlXadesXPathFirstElement(xmlDocPtr doc, const xmlChar *xpath); | ||||||
|  |  | ||||||
|  | xmlXadesDSigCtxPtr | ||||||
|  | xmlXadesDSigCtxCreate(xmlSecDSigCtxPtr dsigCtx, XADES_DIGEST_METHOD digestMethod, xmlXadesPolicyIdentifierCtxPtr policyCtx) { | ||||||
|  |   xmlXadesDSigCtxPtr ctx = NULL; | ||||||
|  |  | ||||||
|  |   ctx = malloc(sizeof(xmlXadesDSigCtx)); | ||||||
|  |   if ( ctx == NULL ) { | ||||||
|  |     return(NULL); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   ctx->dsigCtx = dsigCtx; | ||||||
|  |   ctx->digestMethod = digestMethod; | ||||||
|  |   ctx->policyCtx = policyCtx; | ||||||
|  |   return ctx; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | int | ||||||
|  | xmlXadesDSigCtxSign(xmlXadesDSigCtxPtr ctx, xmlNodePtr signNode) { | ||||||
|  |   xmlNodePtr signingCertificateNode = NULL; | ||||||
|  |   xmlSecKeyDataPtr keyDataX509; | ||||||
|  |   xmlSecSize certsSize; | ||||||
|  |  | ||||||
|  |   signingCertificateNode = xmlXadesXPathFirstElement(signNode->doc, BAD_CAST "//ds:Object/xades:QualifyingProperties//xades:SigningCertificate[1]"); | ||||||
|  |   if ( signingCertificateNode == NULL ) { | ||||||
|  |     return(-1); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   keyDataX509 = xmlSecKeyEnsureData(ctx->dsigCtx->signKey, xmlSecKeyDataX509Id); | ||||||
|  |   if ( keyDataX509 == NULL ) { | ||||||
|  |     xmlXadesInternalError("failed to get X509.\n", NULL); | ||||||
|  |     return(-1); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   certsSize = xmlSecOpenSSLKeyDataX509GetCertsSize(keyDataX509); | ||||||
|  |   for (xmlSecSize i = 0; i < certsSize; i++) { | ||||||
|  |     // calculamos el digest del certificado | ||||||
|  |     unsigned char md[EVP_MAX_MD_SIZE]; | ||||||
|  |     unsigned int md_n; | ||||||
|  |     // TODO(bit4bit) podemos obtener el digest de openssl por medio de la transformacion? o se puede usar la transformacion para generar el digest? | ||||||
|  |     xmlChar *digestMethod = NULL; | ||||||
|  |     EVP_MD *digest = NULL; | ||||||
|  |  | ||||||
|  |     switch(ctx->digestMethod) { | ||||||
|  |     case XADES_DIGEST_SHA256: | ||||||
|  |       digestMethod = (xmlChar *)xmlSecTransformSha256Id->href; | ||||||
|  |       digest = (EVP_MD *) EVP_sha256(); | ||||||
|  |       break; | ||||||
|  |     default: | ||||||
|  |       xmlXadesInternalError("xmlXadesDSigCtxSign not known how to handle digest method.\n", NULL); | ||||||
|  |       return(-1); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     X509 *cert = xmlSecOpenSSLKeyDataX509GetCert(keyDataX509, i); | ||||||
|  |     if ( cert == NULL ) { | ||||||
|  |       xmlXadesInternalError("openssl: failed to get X509 cert.\n", NULL); | ||||||
|  |       return(-1); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     X509_digest(cert, digest, md, &md_n); | ||||||
|  |     xmlChar *digestValue = xmlSecBase64Encode(md, md_n, 0); | ||||||
|  |  | ||||||
|  |     xmlNodePtr certNode = xmlXadesTmplAddCert(signingCertificateNode); | ||||||
|  |     if ( certNode == NULL ) { | ||||||
|  |       xmlXadesInternalError("xmlXadesTmplAddCert(signingCertificateNode)\n", NULL); | ||||||
|  |       return(-1); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     // adicionamos digest  | ||||||
|  |     xmlXadesTmplAddCertDigest(certNode, | ||||||
|  |                               digestMethod, | ||||||
|  |                               digestValue); | ||||||
|  |  | ||||||
|  |     char *issuerName = X509_NAME_oneline(X509_get_issuer_name(cert), NULL, 0); | ||||||
|  |  | ||||||
|  |     /* TODO(bit4bit) formatear? | ||||||
|  |     char *issuerNamePtr = issuerName; | ||||||
|  |      | ||||||
|  |     for(issuerNamePtr = strchr(issuerNamePtr, '/'); issuerNamePtr != NULL; issuerNamePtr = strchr(issuerNamePtr, '/')) { | ||||||
|  |       if (issuerNamePtr == issuerName) { | ||||||
|  |         issuerName += 1; | ||||||
|  |       } else { | ||||||
|  |         *issuerNamePtr = ','; | ||||||
|  |       } | ||||||
|  |       }*/ | ||||||
|  |  | ||||||
|  |     ASN1_INTEGER *serial = X509_get_serialNumber(cert); | ||||||
|  |     BIGNUM *bn = ASN1_INTEGER_to_BN(serial, NULL); | ||||||
|  |     if ( bn == NULL ) { | ||||||
|  |       xmlXadesInternalError("unable to convert ASN1_INTEGER_to_BN to BN\n", NULL); | ||||||
|  |       return(-1); | ||||||
|  |     } | ||||||
|  |     char *issuerNumber = BN_bn2dec(bn); | ||||||
|  |     if ( issuerNumber == NULL ) { | ||||||
|  |       xmlXadesInternalError("unable to convert BN to decimal string\n", NULL); | ||||||
|  |       return(-1); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     if (xmlXadesTmplAddIssuerSerial(certNode, BAD_CAST issuerName, BAD_CAST issuerNumber) == NULL) { | ||||||
|  |       xmlXadesInternalError("xmlXadesTmplAddIssuerSerial", NULL); | ||||||
|  |       return(-1); | ||||||
|  |     } | ||||||
|  |     BN_free(bn); | ||||||
|  |     OPENSSL_free(issuerNumber); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   // digest de policy identifier | ||||||
|  |   xmlNodePtr sigPolicyId = xmlXadesXPathFirstElement(signNode->doc, BAD_CAST "//xades:SigPolicyId/xades:Identifier[1]"); | ||||||
|  |   if ( sigPolicyId == NULL ) { | ||||||
|  |     xmlXadesInternalError("xmlXadesXPathFirstElement(xades:SigPolicyId/xades:Identifier\n", NULL); | ||||||
|  |     return(-1); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   if ( ctx->policyCtx == NULL ) { | ||||||
|  |     xmlXadesInternalError("not found policy context.\n", NULL); | ||||||
|  |     return(-1); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   if ( ctx->policyCtx != NULL ) { | ||||||
|  |  | ||||||
|  |  | ||||||
|  |     if ( ctx->policyCtx->contentCallback == NULL ) { | ||||||
|  |       xmlXadesInternalError("not found policy content callback.\n", NULL); | ||||||
|  |       return(-1); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |  | ||||||
|  |     xmlSecTransformCtxPtr transformCtx = xmlSecTransformCtxCreate(); | ||||||
|  |     if (transformCtx == NULL ) { | ||||||
|  |       xmlXadesInternalError("xmlSecTransformCtxCreate().\n", NULL); | ||||||
|  |       return(-1); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     // elemento del digest | ||||||
|  |     xmlNodePtr sigPolicyHashDigestMethod = xmlXadesXPathFirstElement(signNode->doc, BAD_CAST "//xades:SigPolicyHash/ds:DigestMethod[1]"); | ||||||
|  |     if ( sigPolicyHashDigestMethod == NULL ) { | ||||||
|  |       xmlXadesInternalError("xmlXadesXPathFirstElement(xades:SigPolicyHash/xades:DigestMethod\n", NULL); | ||||||
|  |       return(-1); | ||||||
|  |     } | ||||||
|  |     xmlSecTransformPtr transformPolicyDigestMethod = xmlSecTransformNodeRead(sigPolicyHashDigestMethod, | ||||||
|  |                                                                              xmlSecTransformUsageDigestMethod, | ||||||
|  |                                                                              transformCtx); | ||||||
|  |     if ( transformPolicyDigestMethod == NULL ) { | ||||||
|  |       xmlXadesInternalError("xmlSecTransformNodeRead\n", NULL); | ||||||
|  |       xmlFreeNode(sigPolicyHashDigestMethod); | ||||||
|  |       return(-1); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     if ( xmlSecTransformCheckId(transformPolicyDigestMethod, xmlSecTransformSha256Id) == 0 ) { | ||||||
|  |       xmlXadesInternalError("sigPolicyHash only support sha256 digest method .\n", NULL); | ||||||
|  |       xmlFreeNode(sigPolicyHashDigestMethod); | ||||||
|  |       return(-1); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     // TODO(bit4bit) podemos usar xmlSecTransform para calcular el digest? | ||||||
|  |     xmlNodePtr sigPolicyHashNode = xmlXadesXPathFirstElement(signNode->doc, BAD_CAST "//xades:SigPolicyHash[1]"); | ||||||
|  |     if ( sigPolicyHashNode == NULL ) { | ||||||
|  |       xmlXadesInternalError("failed to find sigPolicyHash node.\n", NULL); | ||||||
|  |       xmlFreeNode(sigPolicyHashDigestMethod); | ||||||
|  |       return(-1); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     // obtenemos contenido de la policy | ||||||
|  |     xmlChar *identifier = xmlNodeListGetString(signNode->doc, sigPolicyId->xmlChildrenNode, 1); | ||||||
|  |     xmlSecBufferPtr policyContent = xmlSecBufferCreate(1024); | ||||||
|  |     ; | ||||||
|  |     if ( (ctx->policyCtx->contentCallback)(identifier, policyContent) < 0 ) { | ||||||
|  |       xmlXadesInternalError("policyContext callback fails.\n", NULL); | ||||||
|  |       xmlFree(identifier); | ||||||
|  |       return(-1); | ||||||
|  |     } | ||||||
|  |     xmlFree(identifier); | ||||||
|  |  | ||||||
|  |     xmlChar *policyHashValue = xmlXadesSha256DigestValueInBase64(xmlSecBufferGetData(policyContent), | ||||||
|  |                                                                  xmlSecBufferGetSize(policyContent)); | ||||||
|  |  | ||||||
|  |     xmlSecBufferDestroy(policyContent); | ||||||
|  |     xmlXadesTmplAddDigest(sigPolicyHashNode, NULL, policyHashValue); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   return xmlSecDSigCtxSign(ctx->dsigCtx, signNode); | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | int | ||||||
|  | xmlXadesDSigCtxDestroy(xmlXadesDSigCtxPtr ctx) { | ||||||
|  |   if ( ctx == NULL ) { | ||||||
|  |     return(-1); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   free(ctx); | ||||||
|  |   return(0); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | xmlNodePtr | ||||||
|  | xmlXadesXPathFirstElement(xmlDocPtr doc, const xmlChar *xpath) { | ||||||
|  |   xmlXPathContextPtr xpathCtx; | ||||||
|  |   xmlXPathObjectPtr xpathResult; | ||||||
|  |   xmlNodePtr node; | ||||||
|  |  | ||||||
|  |   // obtener QualifyingProteries | ||||||
|  |  | ||||||
|  |   xpathCtx = xmlXPathNewContext(doc); | ||||||
|  |   /* register namespaces */ | ||||||
|  |   // TOMADO DE: xmlsec1/src/xpath.c | ||||||
|  |   for(xmlNsPtr ns = xmlDocGetRootElement(doc)->nsDef; ns != NULL; ns = ns->next) { | ||||||
|  |     /* check that we have no other namespace with same prefix already */ | ||||||
|  |     if((ns->prefix != NULL) && (xmlXPathNsLookup(xpathCtx, ns->prefix) == NULL)){ | ||||||
|  |       int ret = xmlXPathRegisterNs(xpathCtx, ns->prefix, ns->href); | ||||||
|  |       if(ret != 0) { | ||||||
|  |         xmlXadesXmlError2("xmlXPathRegisterNs", NULL, | ||||||
|  |                           "prefix=%s", xmlSecErrorsSafeString(ns->prefix)); | ||||||
|  |         return(NULL); | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |  | ||||||
|  |   xpathResult = xmlXPathEvalExpression(xpath, xpathCtx); | ||||||
|  |   if ( xmlXPathNodeSetIsEmpty( xpathResult->nodesetval ) ) { | ||||||
|  |     xmlXadesInternalError("can't find %s \n", xpath); | ||||||
|  |     xmlXPathFreeObject(xpathResult); | ||||||
|  |     return(NULL); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   // obtener puntero a nodo | ||||||
|  |   node = xpathResult->nodesetval->nodeTab[0]; | ||||||
|  |   if ( node->type != XML_ELEMENT_NODE ) { | ||||||
|  |     xmlXadesInternalError("expected element\n", NULL); | ||||||
|  |     return(NULL); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   return(node); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static xmlChar * | ||||||
|  | xmlXadesSha256DigestValueInBase64(const unsigned char *message, size_t message_len) | ||||||
|  | { | ||||||
|  |   unsigned char digest[2048]; | ||||||
|  |   unsigned int digest_len; | ||||||
|  |   EVP_MD_CTX *mdctx; | ||||||
|  |  | ||||||
|  |   if((mdctx = EVP_MD_CTX_new()) == NULL) { | ||||||
|  |     xmlXadesInternalError("EVP_MD_CTX_new().\n", NULL); | ||||||
|  |     return(NULL); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   if(1 != EVP_DigestInit_ex(mdctx, EVP_sha256(), NULL)) { | ||||||
|  |     xmlXadesInternalError("EVP_DigestInit_ex().\n", NULL); | ||||||
|  |     return(NULL); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   if(1 != EVP_DigestUpdate(mdctx, message, message_len)) { | ||||||
|  |     xmlXadesInternalError("EVP_DigestUpdate().\n", NULL); | ||||||
|  |     return(NULL); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   if(1 != EVP_DigestFinal_ex(mdctx, digest, &digest_len)) { | ||||||
|  |     xmlXadesInternalError("EVP_DigestFinal_ex().\n", NULL); | ||||||
|  |     return(NULL); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   EVP_MD_CTX_free(mdctx); | ||||||
|  |   return(xmlSecBase64Encode(digest, digest_len, 0)); | ||||||
|  | } | ||||||
							
								
								
									
										108
									
								
								experimental/facho-signer/src/xades/xades.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										108
									
								
								experimental/facho-signer/src/xades/xades.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,108 @@ | |||||||
|  | /** | ||||||
|  |  * This file is part of facho.  The COPYRIGHT file at the top level of | ||||||
|  |  * this repository contains the full copyright notices and license terms. | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | #ifndef XADES_H | ||||||
|  | #define XADES_H | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  | #include <libxml/tree.h> | ||||||
|  |  | ||||||
|  | #define XMLSEC_NO_XSLT 1 | ||||||
|  |  | ||||||
|  | #include <xmlsec/xmltree.h> | ||||||
|  | #include <xmlsec/transforms.h> | ||||||
|  | #include <xmlsec/xmldsig.h> | ||||||
|  | #include <xmlsec/base64.h> | ||||||
|  |  | ||||||
|  | #include "xmlsec1/errors_helpers.h" | ||||||
|  |  | ||||||
|  | #define xmlXadesAssert2(p, ret) \ | ||||||
|  |   xmlSecAssert2(p, ret) | ||||||
|  |  | ||||||
|  | #define xmlXadesNodeNotFoundError(errorFunction, startNode, targetNodeName, errorObject) \ | ||||||
|  |   xmlSecNodeNotFoundError(errorFunction, startNode, targetNodeName, errorObject) | ||||||
|  |  | ||||||
|  | #define xmlXadesXmlError2(errorFunction, errorObject, msg, param) \ | ||||||
|  |   xmlSecXmlError2(errorFunction, errorObject, msg, param) | ||||||
|  |  | ||||||
|  | #define xmlXadesErrorsSafeString(msg) \ | ||||||
|  |   xmlSecErrorsSafeString(msg) | ||||||
|  |  | ||||||
|  | #define xmlXadesInternalError(errorFunction, errorObject) \ | ||||||
|  |   xmlSecInternalError(errorFunction, errorObject) | ||||||
|  |  | ||||||
|  | #define xmlXadesNodeAlreadyPresentError(parent, nodeName, errObject) \ | ||||||
|  |   xmlSecNodeAlreadyPresentError(parent, nodeName, errObject) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | typedef int xmlXadesSize; | ||||||
|  | typedef enum _XADES_DIGEST_METHOD{ | ||||||
|  |   XADES_DIGEST_SHA256 | ||||||
|  | } XADES_DIGEST_METHOD; | ||||||
|  |  | ||||||
|  | typedef int(*xmlXadesPolicyIdentifierContentCallback)(const xmlChar *policyId, xmlSecBuffer *); | ||||||
|  |  | ||||||
|  | typedef struct _xmlXadesPolicyIdentifierCtx  xmlXadesPolicyIdentifierCtx, *xmlXadesPolicyIdentifierCtxPtr; | ||||||
|  | struct _xmlXadesPolicyIdentifierCtx { | ||||||
|  |   xmlXadesPolicyIdentifierContentCallback contentCallback; | ||||||
|  | }; | ||||||
|  |    | ||||||
|  | typedef struct _xmlXadesDSigCtx xmlXadesDSigCtx, *xmlXadesDSigCtxPtr; | ||||||
|  | struct _xmlXadesDSigCtx { | ||||||
|  |   xmlSecDSigCtxPtr dsigCtx; | ||||||
|  |   XADES_DIGEST_METHOD digestMethod; | ||||||
|  |   xmlXadesPolicyIdentifierCtxPtr policyCtx; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | xmlXadesDSigCtxPtr | ||||||
|  | xmlXadesDSigCtxCreate(xmlSecDSigCtxPtr dsigCtx, XADES_DIGEST_METHOD digestMethod,  xmlXadesPolicyIdentifierCtxPtr policyCtx); | ||||||
|  |  | ||||||
|  | int | ||||||
|  | xmlXadesDSigCtxSign(xmlXadesDSigCtxPtr ctx, xmlNodePtr signNode); | ||||||
|  |  | ||||||
|  | int | ||||||
|  | xmlXadesDSigCtxDestroy(xmlXadesDSigCtxPtr ctx); | ||||||
|  |  | ||||||
|  | xmlNodePtr | ||||||
|  | xmlXadesTmplQualifyingPropertiesCreate(xmlDocPtr doc, xmlNodePtr signatureNode, const xmlChar *id); | ||||||
|  |  | ||||||
|  | xmlNodePtr | ||||||
|  | xmlXadesTmplAddSignedProperties(xmlNodePtr qualifyingPropertiesNode, const xmlChar* id); | ||||||
|  |  | ||||||
|  | xmlNodePtr | ||||||
|  | xmlXadesTmplAddSigningCertificate(xmlNodePtr parentNode, xmlSecTransformId digestMethodId); | ||||||
|  |  | ||||||
|  | xmlNodePtr | ||||||
|  | xmlXadesTmplAddCert(xmlNodePtr signingCertificateNode); | ||||||
|  |  | ||||||
|  | xmlNodePtr | ||||||
|  | xmlXadesTmplAddCertDigest(xmlNodePtr signingCertificateNode, const xmlChar *digestMethod, const xmlChar *digestValue); | ||||||
|  |  | ||||||
|  | xmlNodePtr | ||||||
|  | xmlXadesTmplAddSignedSignatureProperties(xmlNodePtr parentNode, struct tm* signingTime); | ||||||
|  |  | ||||||
|  | xmlNodePtr | ||||||
|  | xmlXadesTmplAddSignaturePolicyIdentifier(xmlNodePtr signedSignaturePropertiesNode); | ||||||
|  |  | ||||||
|  | xmlNodePtr | ||||||
|  | xmlXadesTmplAddSignaturePolicyId(xmlNodePtr signaturePolicyIdentifierNode); | ||||||
|  |  | ||||||
|  | xmlNodePtr | ||||||
|  | xmlXadesTmplAddSigPolicyId(xmlNodePtr signaturePolicyId, const xmlChar* identifier, const xmlChar *description); | ||||||
|  |  | ||||||
|  | xmlNodePtr | ||||||
|  | xmlXadesTmplAddSigPolicyHash(xmlNodePtr parentNode, xmlSecTransformId digestMethodId); | ||||||
|  |  | ||||||
|  | xmlNodePtr | ||||||
|  | xmlXadesTmplAddSignerRole(xmlNodePtr signedSignaturePropertiesNode, const xmlChar* role); | ||||||
|  |  | ||||||
|  | xmlNodePtr | ||||||
|  | xmlXadesTmplAddDigest(xmlNodePtr parentNode, const xmlChar *digestMethod, const xmlChar *digestValue); | ||||||
|  |  | ||||||
|  | xmlNodePtr | ||||||
|  | xmlXadesTmplAddIssuerSerial(xmlNodePtr certNode, const xmlChar *issuerName, const xmlChar *issuerNumber); | ||||||
|  |  | ||||||
|  | #endif //XADES_H | ||||||
							
								
								
									
										94
									
								
								experimental/facho-signer/src/xades/xades_test.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										94
									
								
								experimental/facho-signer/src/xades/xades_test.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,94 @@ | |||||||
|  | /** | ||||||
|  |  * This file is part of facho.  The COPYRIGHT file at the top level of | ||||||
|  |  * this repository contains the full copyright notices and license terms. | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | #include <time.h> | ||||||
|  |  | ||||||
|  | #include <libxml/tree.h> | ||||||
|  | #include "minunit.h" | ||||||
|  |  | ||||||
|  | #include "xades.h" | ||||||
|  |  | ||||||
|  |  | ||||||
|  | MU_TEST(test_xml_add_node_recursive) { | ||||||
|  |   xmlDocPtr doc; | ||||||
|  |   xmlNodePtr root; | ||||||
|  |   xmlNodePtr child; | ||||||
|  |   xmlChar* xmlbuff; | ||||||
|  |   int xmlbuffsize; | ||||||
|  |    | ||||||
|  |   doc = xmlNewDoc(BAD_CAST "1.0"); | ||||||
|  |   root = xmlNewNode(NULL, BAD_CAST "root"); | ||||||
|  |   xmlDocSetRootElement(doc, root); | ||||||
|  |  | ||||||
|  |   child = xmlXadesAddChildRecursiveNs(root, BAD_CAST "A/B/C", NULL); | ||||||
|  |   mu_check(child != NULL); | ||||||
|  |  | ||||||
|  |   xmlDocDumpMemory(doc, &xmlbuff, &xmlbuffsize); | ||||||
|  |   mu_assert_string_eq("<?xml version=\"1.0\"?>\n" | ||||||
|  |                       "<root>\n" | ||||||
|  |                       "<A>\n" | ||||||
|  |                       "<B>\n" | ||||||
|  |                       "<C/>\n" | ||||||
|  |                       "</B>\n" | ||||||
|  |                       "</A>\n" | ||||||
|  |                       "</root>\n" | ||||||
|  |                       , (char *)xmlbuff); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | MU_TEST(test_qualifying_properties_layout) { | ||||||
|  |   xmlDocPtr doc; | ||||||
|  |   xmlNodePtr root; | ||||||
|  |   xmlNodePtr node; | ||||||
|  |   xmlChar* xmlbuff; | ||||||
|  |   int buffersize; | ||||||
|  |   struct tm tm; | ||||||
|  |  | ||||||
|  |   memset(&tm, 0, sizeof(tm)); | ||||||
|  |   tm.tm_year = 2021 - 1900; | ||||||
|  |   tm.tm_mon = 11; | ||||||
|  |   tm.tm_mday = 6; | ||||||
|  |   tm.tm_hour = 12; | ||||||
|  |   tm.tm_min = 0; | ||||||
|  |   tm.tm_sec = 50; | ||||||
|  |  | ||||||
|  |  | ||||||
|  |   doc = xmlNewDoc(BAD_CAST "1.0"); | ||||||
|  |   root = xmlNewNode(NULL, BAD_CAST "root"); | ||||||
|  |   xmlDocSetRootElement(doc, root); | ||||||
|  |    | ||||||
|  |   node = xmlXadesTmplQualifyingPropertiesCreateNsPref(doc, BAD_CAST "123", NULL); | ||||||
|  |   xmlXadesTmplAddSignedSignatureProperties(node, &tm); | ||||||
|  |   mu_check(node != NULL); | ||||||
|  |    | ||||||
|  |   xmlSecAddChildNode(root, node); | ||||||
|  |   xmlDocDumpMemory(doc, &xmlbuff, &buffersize); | ||||||
|  |  | ||||||
|  |   // bit4bit: no se como pasar el namespace al root | ||||||
|  |   mu_assert_string_eq("<?xml version=\"1.0\"?>\n" | ||||||
|  |                       "<root>\n" | ||||||
|  |                       "<QualifyingProperties xmlns=\"http://uri.etsi.org/01903/v1.3.2#\" id=\"123\">\n" | ||||||
|  |                       "<SignedProperties>\n" | ||||||
|  |                       "<SignedSignatureProperties>\n" | ||||||
|  |                       "<SigningTime>2021-12-06T12:00:50</SigningTime>\n" | ||||||
|  |                       "</SignedSignatureProperties>\n" | ||||||
|  |                       "</SignedProperties>\n" | ||||||
|  |                       "</QualifyingProperties>\n" | ||||||
|  |                       "</root>\n" | ||||||
|  |                       , (char *)xmlbuff); | ||||||
|  |    | ||||||
|  |   xmlFree(xmlbuff); | ||||||
|  |   xmlFreeDoc(doc); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | MU_TEST_SUITE(test_suite) { | ||||||
|  |   MU_RUN_TEST(test_xml_add_node_recursive); | ||||||
|  |   MU_RUN_TEST(test_qualifying_properties_layout); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | int main() { | ||||||
|  |   MU_RUN_SUITE(test_suite); | ||||||
|  |   MU_REPORT(); | ||||||
|  |   return MU_EXIT_CODE; | ||||||
|  | } | ||||||
							
								
								
									
										260
									
								
								experimental/facho-signer/src/xades/xmlsec1/errors.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										260
									
								
								experimental/facho-signer/src/xades/xmlsec1/errors.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,260 @@ | |||||||
|  | /* | ||||||
|  |  * XML Security Library (http://www.aleksey.com/xmlsec). | ||||||
|  |  * | ||||||
|  |  * | ||||||
|  |  * This is free software; see Copyright file in the source | ||||||
|  |  * distribution for preciese wording. | ||||||
|  |  * | ||||||
|  |  * Copyright (C) 2002-2016 Aleksey Sanin <aleksey@aleksey.com>. All Rights Reserved. | ||||||
|  |  */ | ||||||
|  | /** | ||||||
|  |  * SECTION:errors | ||||||
|  |  * @Short_description: Error reporting and logging functions. | ||||||
|  |  * @Stability: Stable | ||||||
|  |  * | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | #define XMLSEC_PRIVATE 1 | ||||||
|  | #define XMLSEC_NO_XSLT 1 | ||||||
|  |  | ||||||
|  | #include <stdlib.h> | ||||||
|  | #include <stdio.h> | ||||||
|  | #include <stdarg.h> | ||||||
|  | #include <time.h> | ||||||
|  | #include <string.h> | ||||||
|  |  | ||||||
|  | #include <libxml/tree.h> | ||||||
|  |  | ||||||
|  | #include <xmlsec/xmlsec.h> | ||||||
|  | #include <xmlsec/xmltree.h> | ||||||
|  | #include <xmlsec/private.h> | ||||||
|  | #include <xmlsec/errors.h> | ||||||
|  |  | ||||||
|  | /* Must be bigger than fatal_error */ | ||||||
|  | #define XMLSEC_ERRORS_BUFFER_SIZE       1024 | ||||||
|  |  | ||||||
|  | /* Must fit into xmlChar[XMLSEC_ERRORS_BUFFER_SIZE] */ | ||||||
|  | static const xmlChar fatal_error[] = "Can not format error message"; | ||||||
|  |  | ||||||
|  | typedef struct _xmlSecErrorDescription                  xmlSecErrorDescription, *xmlSecErrorDescriptionPtr; | ||||||
|  | struct _xmlSecErrorDescription { | ||||||
|  |     int                 errorCode; | ||||||
|  |     const char*         errorMsg; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | static xmlSecErrorDescription xmlSecErrorsTable[XMLSEC_ERRORS_MAX_NUMBER + 1] = { | ||||||
|  |   { XMLSEC_ERRORS_R_XMLSEC_FAILED,              "xmlsec library function failed" }, | ||||||
|  |   { XMLSEC_ERRORS_R_MALLOC_FAILED,              "malloc function failed" }, | ||||||
|  |   { XMLSEC_ERRORS_R_STRDUP_FAILED,              "strdup function failed" }, | ||||||
|  |   { XMLSEC_ERRORS_R_CRYPTO_FAILED,              "crypto library function failed" }, | ||||||
|  |   { XMLSEC_ERRORS_R_XML_FAILED,                 "libxml2 library function failed" }, | ||||||
|  |   { XMLSEC_ERRORS_R_XSLT_FAILED,                "libxslt library function failed" }, | ||||||
|  |   { XMLSEC_ERRORS_R_IO_FAILED,                  "io function failed" }, | ||||||
|  |   { XMLSEC_ERRORS_R_DISABLED,                   "feature is disabled" }, | ||||||
|  |   { XMLSEC_ERRORS_R_NOT_IMPLEMENTED,            "feature is not implemented" }, | ||||||
|  |   { XMLSEC_ERRORS_R_INVALID_CONFIG,             "invalid configuration" }, | ||||||
|  |   { XMLSEC_ERRORS_R_INVALID_SIZE,               "invalid size" }, | ||||||
|  |   { XMLSEC_ERRORS_R_INVALID_DATA,               "invalid data" }, | ||||||
|  |   { XMLSEC_ERRORS_R_INVALID_RESULT,             "invalid result" }, | ||||||
|  |   { XMLSEC_ERRORS_R_INVALID_TYPE,               "invalid type" }, | ||||||
|  |   { XMLSEC_ERRORS_R_INVALID_OPERATION,          "invalid operation" }, | ||||||
|  |   { XMLSEC_ERRORS_R_INVALID_STATUS,             "invalid status" }, | ||||||
|  |   { XMLSEC_ERRORS_R_INVALID_FORMAT,             "invalid format" }, | ||||||
|  |   { XMLSEC_ERRORS_R_DATA_NOT_MATCH,             "data do not match" }, | ||||||
|  |   { XMLSEC_ERRORS_R_INVALID_VERSION,            "invalid version" }, | ||||||
|  |   { XMLSEC_ERRORS_R_INVALID_NODE,               "invalid node" }, | ||||||
|  |   { XMLSEC_ERRORS_R_INVALID_NODE_CONTENT,       "invalid node content" }, | ||||||
|  |   { XMLSEC_ERRORS_R_INVALID_NODE_ATTRIBUTE,     "invalid node attribute" }, | ||||||
|  |   { XMLSEC_ERRORS_R_MISSING_NODE_ATTRIBUTE,     "missing node attribute" }, | ||||||
|  |   { XMLSEC_ERRORS_R_NODE_ALREADY_PRESENT,       "node already present" }, | ||||||
|  |   { XMLSEC_ERRORS_R_UNEXPECTED_NODE,            "unexpected node" }, | ||||||
|  |   { XMLSEC_ERRORS_R_NODE_NOT_FOUND,             "node node found" }, | ||||||
|  |   { XMLSEC_ERRORS_R_INVALID_TRANSFORM,          "invalid transform" }, | ||||||
|  |   { XMLSEC_ERRORS_R_INVALID_TRANSFORM_KEY,      "invalid transform key" }, | ||||||
|  |   { XMLSEC_ERRORS_R_INVALID_URI_TYPE,           "invalid URI type" }, | ||||||
|  |   { XMLSEC_ERRORS_R_TRANSFORM_SAME_DOCUMENT_REQUIRED,   "same document is required for transform" }, | ||||||
|  |   { XMLSEC_ERRORS_R_TRANSFORM_DISABLED,         "transform is disabled" }, | ||||||
|  |   { XMLSEC_ERRORS_R_INVALID_KEY_DATA,           "invalid key data" }, | ||||||
|  |   { XMLSEC_ERRORS_R_KEY_DATA_NOT_FOUND,         "key data is not found" }, | ||||||
|  |   { XMLSEC_ERRORS_R_KEY_DATA_ALREADY_EXIST,     "key data already exist" }, | ||||||
|  |   { XMLSEC_ERRORS_R_INVALID_KEY_DATA_SIZE,      "invalid key data size" }, | ||||||
|  |   { XMLSEC_ERRORS_R_KEY_NOT_FOUND,              "key is not found" }, | ||||||
|  |   { XMLSEC_ERRORS_R_KEYDATA_DISABLED,           "key data is disabled" }, | ||||||
|  |   { XMLSEC_ERRORS_R_MAX_RETRIEVALS_LEVEL,       "maximum key retrieval level" }, | ||||||
|  |   { XMLSEC_ERRORS_R_MAX_RETRIEVAL_TYPE_MISMATCH,"key retrieval type mismatch" }, | ||||||
|  |   { XMLSEC_ERRORS_R_MAX_ENCKEY_LEVEL,           "maximum encrypted key level" }, | ||||||
|  |   { XMLSEC_ERRORS_R_CERT_VERIFY_FAILED,         "certificate verification failed" }, | ||||||
|  |   { XMLSEC_ERRORS_R_CERT_NOT_FOUND,             "certificate is not found" }, | ||||||
|  |   { XMLSEC_ERRORS_R_CERT_REVOKED,               "certificate is revoked" }, | ||||||
|  |   { XMLSEC_ERRORS_R_CERT_ISSUER_FAILED,         "certificate issuer check failed" }, | ||||||
|  |   { XMLSEC_ERRORS_R_CERT_NOT_YET_VALID,         "certificate is not yet valid" }, | ||||||
|  |   { XMLSEC_ERRORS_R_CERT_HAS_EXPIRED,           "certificate has expired" }, | ||||||
|  |   { XMLSEC_ERRORS_R_DSIG_NO_REFERENCES,         "Reference nodes are not found" }, | ||||||
|  |   { XMLSEC_ERRORS_R_DSIG_INVALID_REFERENCE,     "Reference verification failed" }, | ||||||
|  |   { XMLSEC_ERRORS_R_ASSERTION,                  "assertion" }, | ||||||
|  |   { 0,                                          NULL} | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | static xmlSecErrorsCallback xmlSecErrorsClbk = xmlSecErrorsDefaultCallback; | ||||||
|  | static int  xmlSecPrintErrorMessages = 1;       /* whether the error messages will be printed immediately */ | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * xmlSecErrorsInit: | ||||||
|  |  * | ||||||
|  |  * Initializes the errors reporting. It is called from #xmlSecInit function. | ||||||
|  |  * and applications must not call this function directly. | ||||||
|  |  */ | ||||||
|  | void | ||||||
|  | xmlSecErrorsInit(void) { | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * xmlSecErrorsShutdown: | ||||||
|  |  * | ||||||
|  |  * Cleanups the errors reporting. It is called from #xmlSecShutdown function. | ||||||
|  |  * and applications must not call this function directly. | ||||||
|  |  */ | ||||||
|  | void | ||||||
|  | xmlSecErrorsShutdown(void) { | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * xmlSecErrorsSetCallback: | ||||||
|  |  * @callback:           the new errors callback function. | ||||||
|  |  * | ||||||
|  |  * Sets the errors callback function to @callback that will be called | ||||||
|  |  * every time an error occurs. | ||||||
|  |  */ | ||||||
|  | void | ||||||
|  | xmlSecErrorsSetCallback(xmlSecErrorsCallback callback) { | ||||||
|  |     xmlSecErrorsClbk = callback; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * xmlSecErrorsDefaultCallback: | ||||||
|  |  * @file:               the error location file name (__FILE__ macro). | ||||||
|  |  * @line:               the error location line number (__LINE__ macro). | ||||||
|  |  * @func:               the error location function name (__FUNCTION__ macro). | ||||||
|  |  * @errorObject:        the error specific error object | ||||||
|  |  * @errorSubject:       the error specific error subject. | ||||||
|  |  * @reason:             the error code. | ||||||
|  |  * @msg:                the additional error message. | ||||||
|  |  * | ||||||
|  |  * The default error reporting callback that utilizes LibXML | ||||||
|  |  * error reporting #xmlGenericError function. | ||||||
|  |  */ | ||||||
|  | void | ||||||
|  | xmlSecErrorsDefaultCallback(const char* file, int line, const char* func, | ||||||
|  |                             const char* errorObject, const char* errorSubject, | ||||||
|  |                             int reason, const char* msg) { | ||||||
|  |     if(xmlSecPrintErrorMessages) { | ||||||
|  |         const char* error_msg = NULL; | ||||||
|  |         xmlSecSize i; | ||||||
|  |  | ||||||
|  |         for(i = 0; (i < XMLSEC_ERRORS_MAX_NUMBER) && (xmlSecErrorsGetMsg(i) != NULL); ++i) { | ||||||
|  |             if(xmlSecErrorsGetCode(i) == reason) { | ||||||
|  |                 error_msg = xmlSecErrorsGetMsg(i); | ||||||
|  |                 break; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         xmlGenericError(xmlGenericErrorContext, | ||||||
|  |             "func=%s:file=%s:line=%d:obj=%s:subj=%s:error=%d:%s:%s\n", | ||||||
|  |             (func != NULL) ? func : "unknown", | ||||||
|  |             (file != NULL) ? file : "unknown", | ||||||
|  |             line, | ||||||
|  |             (errorObject != NULL) ? errorObject : "unknown", | ||||||
|  |             (errorSubject != NULL) ? errorSubject : "unknown", | ||||||
|  |             reason, | ||||||
|  |             (error_msg != NULL) ? error_msg : "", | ||||||
|  |             (msg != NULL) ? msg : ""); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * xmlSecErrorsDefaultCallbackEnableOutput: | ||||||
|  |  * @enabled:            the flag. | ||||||
|  |  * | ||||||
|  |  * Enables or disables calling LibXML2 callback from the default | ||||||
|  |  * errors callback. | ||||||
|  |  */ | ||||||
|  | void | ||||||
|  | xmlSecErrorsDefaultCallbackEnableOutput(int enabled) { | ||||||
|  |     xmlSecPrintErrorMessages = enabled; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * xmlSecErrorsGetCode: | ||||||
|  |  * @pos:                the error position. | ||||||
|  |  * | ||||||
|  |  * Gets the known error code at position @pos. | ||||||
|  |  * | ||||||
|  |  * Returns: the known error code or 0 if @pos is greater than | ||||||
|  |  * total number of known error codes. | ||||||
|  |  */ | ||||||
|  | int | ||||||
|  | xmlSecErrorsGetCode(xmlSecSize pos) { | ||||||
|  |     /* could not use asserts here! */ | ||||||
|  |     if(pos < sizeof(xmlSecErrorsTable) / sizeof(xmlSecErrorsTable[0])) { | ||||||
|  |         return(xmlSecErrorsTable[pos].errorCode); | ||||||
|  |     } | ||||||
|  |     return(0); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * xmlSecErrorsGetMsg: | ||||||
|  |  * @pos:                the error position. | ||||||
|  |  * | ||||||
|  |  * Gets the known error message at position @pos. | ||||||
|  |  * | ||||||
|  |  * Returns: the known error message or NULL if @pos is greater than | ||||||
|  |  * total number of known error codes. | ||||||
|  |  */ | ||||||
|  | const char* | ||||||
|  | xmlSecErrorsGetMsg(xmlSecSize pos) { | ||||||
|  |     /* could not use asserts here! */ | ||||||
|  |     if(pos < sizeof(xmlSecErrorsTable) / sizeof(xmlSecErrorsTable[0])) { | ||||||
|  |         return(xmlSecErrorsTable[pos].errorMsg); | ||||||
|  |     } | ||||||
|  |     return(NULL); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * xmlSecError: | ||||||
|  |  * @file:               the error location filename (__FILE__). | ||||||
|  |  * @line:               the error location line number (__LINE__). | ||||||
|  |  * @func:               the error location function (__FUNCTION__). | ||||||
|  |  * @errorObject:        the error specific error object (e.g. transform, key data, etc). | ||||||
|  |  * @errorSubject:       the error specific error subject (e.g. failed function name). | ||||||
|  |  * @reason:             the error code. | ||||||
|  |  * @msg:                the error message in printf format. | ||||||
|  |  * @...:                the parameters for the @msg. | ||||||
|  |  * | ||||||
|  |  * Reports an error to the default (#xmlSecErrorsDefaultCallback) or | ||||||
|  |  * application specific callback installed using #xmlSecErrorsSetCallback | ||||||
|  |  * function. | ||||||
|  |  */ | ||||||
|  | void | ||||||
|  | xmlSecError(const char* file, int line, const char* func, | ||||||
|  |             const char* errorObject, const char* errorSubject, | ||||||
|  |             int reason, const char* msg, ...) { | ||||||
|  |     if(xmlSecErrorsClbk != NULL) { | ||||||
|  |         xmlChar error_msg[XMLSEC_ERRORS_BUFFER_SIZE]; | ||||||
|  |         int ret; | ||||||
|  |  | ||||||
|  |         if(msg != NULL) { | ||||||
|  |             va_list va; | ||||||
|  |  | ||||||
|  |             va_start(va, msg); | ||||||
|  |             ret = xmlStrVPrintf(error_msg, sizeof(error_msg), msg, va); | ||||||
|  |             if(ret < 0) { | ||||||
|  |                 /* Can't really report an error from an error callback */ | ||||||
|  |                 memcpy(error_msg, fatal_error, sizeof(fatal_error)); | ||||||
|  |             } | ||||||
|  |             error_msg[sizeof(error_msg) - 1] = '\0'; /* just in case */ | ||||||
|  |             va_end(va); | ||||||
|  |         } else { | ||||||
|  |             error_msg[0] = '\0'; | ||||||
|  |         } | ||||||
|  |         xmlSecErrorsClbk(file, line, func, errorObject, errorSubject, reason, (char*)error_msg); | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										869
									
								
								experimental/facho-signer/src/xades/xmlsec1/errors_helpers.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										869
									
								
								experimental/facho-signer/src/xades/xmlsec1/errors_helpers.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,869 @@ | |||||||
|  | /* | ||||||
|  |  * XML Security Library (http://www.aleksey.com/xmlsec). | ||||||
|  |  * | ||||||
|  |  * Internal header only used during the compilation, | ||||||
|  |  * | ||||||
|  |  * This is free software; see Copyright file in the source | ||||||
|  |  * distribution for preciese wording. | ||||||
|  |  * | ||||||
|  |  * Copyright (C) 2002-2016 Aleksey Sanin <aleksey@aleksey.com>. All Rights Reserved. | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | #ifndef __XMLSEC_ERROR_HELPERS_H__ | ||||||
|  | #define __XMLSEC_ERROR_HELPERS_H__ | ||||||
|  |  | ||||||
|  | #include <errno.h> | ||||||
|  | #include <xmlsec/errors.h> | ||||||
|  |  | ||||||
|  | #ifdef __cplusplus | ||||||
|  | extern "C" { | ||||||
|  | #endif /* __cplusplus */ | ||||||
|  |  | ||||||
|  | /********************************************************************** | ||||||
|  |  * | ||||||
|  |  * Error handling macros. | ||||||
|  |  * | ||||||
|  |  **********************************************************************/ | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * xmlSecInternalError: | ||||||
|  |  * @errorFunction:      the failed function name. | ||||||
|  |  * @errorObject:        the error specific error object (e.g. transform, key data, etc). | ||||||
|  |  * | ||||||
|  |  * Macro. The XMLSec library macro for reporting internal XMLSec errors. | ||||||
|  |  */ | ||||||
|  | #define xmlSecInternalError(errorFunction, errorObject) \ | ||||||
|  |         xmlSecError(XMLSEC_ERRORS_HERE,                     \ | ||||||
|  |                     (const char*)(errorObject),             \ | ||||||
|  |                     (errorFunction),                        \ | ||||||
|  |                     XMLSEC_ERRORS_R_XMLSEC_FAILED,          \ | ||||||
|  |                     XMLSEC_ERRORS_NO_MESSAGE                \ | ||||||
|  |         ) | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * xmlSecInternalError2: | ||||||
|  |  * @errorFunction:      the failed function name. | ||||||
|  |  * @errorObject:        the error specific error object (e.g. transform, key data, etc). | ||||||
|  |  * @msg:                the extra message. | ||||||
|  |  * @param:              the extra message param. | ||||||
|  |  * | ||||||
|  |  * Macro. The XMLSec library macro for reporting internal XMLSec errors. | ||||||
|  |  */ | ||||||
|  | #define xmlSecInternalError2(errorFunction, errorObject, msg, param) \ | ||||||
|  |         xmlSecError(XMLSEC_ERRORS_HERE,                     \ | ||||||
|  |                     (const char*)(errorObject),             \ | ||||||
|  |                     (errorFunction),                        \ | ||||||
|  |                     XMLSEC_ERRORS_R_XMLSEC_FAILED,          \ | ||||||
|  |                     (msg), (param)                          \ | ||||||
|  |         ) | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * xmlSecInternalError3: | ||||||
|  |  * @errorFunction:      the failed function name. | ||||||
|  |  * @errorObject:        the error specific error object (e.g. transform, key data, etc). | ||||||
|  |  * @msg:                the extra message. | ||||||
|  |  * @param1:             the extra message param1. | ||||||
|  |  * @param2:             the extra message param2. | ||||||
|  |  * | ||||||
|  |  * Macro. The XMLSec library macro for reporting internal XMLSec errors. | ||||||
|  |  */ | ||||||
|  | #define xmlSecInternalError3(errorFunction, errorObject, msg, param1, param2) \ | ||||||
|  |         xmlSecError(XMLSEC_ERRORS_HERE,                     \ | ||||||
|  |                     (const char*)(errorObject),             \ | ||||||
|  |                     (errorFunction),                        \ | ||||||
|  |                     XMLSEC_ERRORS_R_XMLSEC_FAILED,          \ | ||||||
|  |                     (msg), (param1), (param2)               \ | ||||||
|  |         ) | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * xmlSecInternalError4: | ||||||
|  |  * @errorFunction:      the failed function name. | ||||||
|  |  * @errorObject:        the error specific error object (e.g. transform, key data, etc). | ||||||
|  |  * @msg:                the extra message. | ||||||
|  |  * @param1:             the extra message param1. | ||||||
|  |  * @param2:             the extra message param2. | ||||||
|  |  * @param3:             the extra message param3. | ||||||
|  |  * | ||||||
|  |  * Macro. The XMLSec library macro for reporting internal XMLSec errors. | ||||||
|  |  */ | ||||||
|  | #define xmlSecInternalError4(errorFunction, errorObject, msg, param1, param2, param3) \ | ||||||
|  |         xmlSecError(XMLSEC_ERRORS_HERE,                     \ | ||||||
|  |                     (const char*)(errorObject),             \ | ||||||
|  |                     (errorFunction),                        \ | ||||||
|  |                     XMLSEC_ERRORS_R_XMLSEC_FAILED,          \ | ||||||
|  |                     (msg), (param1), (param2), (param3)     \ | ||||||
|  |         ) | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * xmlSecMallocError: | ||||||
|  |  * @allocSize:          the failed allocation size. | ||||||
|  |  * @errorObject:        the error specific error object (e.g. transform, key data, etc). | ||||||
|  |  * | ||||||
|  |  * Macro. The XMLSec library macro for reporting xmlMalloc() errors. | ||||||
|  |  */ | ||||||
|  | #define xmlSecMallocError(allocSize, errorObject) \ | ||||||
|  |         xmlSecError(XMLSEC_ERRORS_HERE,                     \ | ||||||
|  |                     (const char*)(errorObject),             \ | ||||||
|  |                     "xmlMalloc",                            \ | ||||||
|  |                     XMLSEC_ERRORS_R_MALLOC_FAILED,          \ | ||||||
|  |                     "size=%lu", (unsigned long)(allocSize)  \ | ||||||
|  |         ) | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * xmlSecStrdupError: | ||||||
|  |  * @str:                the failed string. | ||||||
|  |  * @errorObject:        the error specific error object (e.g. transform, key data, etc). | ||||||
|  |  * | ||||||
|  |  * Macro. The XMLSec library macro for reporting xmlStrdup() errors. | ||||||
|  |  */ | ||||||
|  | #define xmlSecStrdupError(str, errorObject) \ | ||||||
|  |         xmlSecError(XMLSEC_ERRORS_HERE,                     \ | ||||||
|  |                     (const char*)(errorObject),             \ | ||||||
|  |                     "xmlStrdup",                            \ | ||||||
|  |                     XMLSEC_ERRORS_R_STRDUP_FAILED,          \ | ||||||
|  |                     "size=%lu", (unsigned long)xmlStrlen(str) \ | ||||||
|  |         ) | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * xmlSecXmlError: | ||||||
|  |  * @errorFunction:      the failed function. | ||||||
|  |  * @errorObject:        the error specific error object (e.g. transform, key data, etc). | ||||||
|  |  * | ||||||
|  |  * Macro. The XMLSec library macro for reporting generic XML errors. | ||||||
|  |  */ | ||||||
|  | #define xmlSecXmlError(errorFunction, errorObject) \ | ||||||
|  |     {                                                 \ | ||||||
|  |         xmlErrorPtr error = xmlGetLastError();        \ | ||||||
|  |         int code = (error != NULL) ? error->code : 0; \ | ||||||
|  |         const char* message = (error != NULL) ? error->message : NULL; \ | ||||||
|  |         xmlSecError(XMLSEC_ERRORS_HERE,               \ | ||||||
|  |                    (const char*)(errorObject),        \ | ||||||
|  |                    (errorFunction),                   \ | ||||||
|  |                    XMLSEC_ERRORS_R_XML_FAILED,        \ | ||||||
|  |                    "xml error: %lu: %s",              \ | ||||||
|  |                    (unsigned long)code,               \ | ||||||
|  |                    xmlSecErrorsSafeString(message)    \ | ||||||
|  |         );                                            \ | ||||||
|  |     } | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * xmlSecXmlError2: | ||||||
|  |  * @errorFunction:      the failed function. | ||||||
|  |  * @errorObject:        the error specific error object (e.g. transform, key data, etc). | ||||||
|  |  * @msg:                the extra message. | ||||||
|  |  * @param:              the extra message param. | ||||||
|  |  * | ||||||
|  |  * Macro. The XMLSec library macro for reporting generic XML errors. | ||||||
|  |  */ | ||||||
|  | #define xmlSecXmlError2(errorFunction, errorObject, msg, param) \ | ||||||
|  |     {                                                 \ | ||||||
|  |         xmlErrorPtr error = xmlGetLastError();        \ | ||||||
|  |         int code = (error != NULL) ? error->code : 0; \ | ||||||
|  |         const char* message = (error != NULL) ? error->message : NULL; \ | ||||||
|  |         xmlSecError(XMLSEC_ERRORS_HERE,               \ | ||||||
|  |                    (const char*)(errorObject),        \ | ||||||
|  |                    (errorFunction),                   \ | ||||||
|  |                    XMLSEC_ERRORS_R_XML_FAILED,        \ | ||||||
|  |                    msg "; xml error: %lu: %s",        \ | ||||||
|  |                    (param),                           \ | ||||||
|  |                    (unsigned long)code,               \ | ||||||
|  |                    xmlSecErrorsSafeString(message)    \ | ||||||
|  |         );                                            \ | ||||||
|  |     } | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * xmlSecXmlParserError: | ||||||
|  |  * @errorFunction:      the failed function. | ||||||
|  |  * @ctxt:               the parser context. | ||||||
|  |  * @errorObject:        the error specific error object (e.g. transform, key data, etc). | ||||||
|  |  * | ||||||
|  |  * Macro. The XMLSec library macro for reporting XML parser errors. | ||||||
|  |  */ | ||||||
|  | #define xmlSecXmlParserError(errorFunction, ctxt, errorObject) \ | ||||||
|  |     {                                                 \ | ||||||
|  |         xmlErrorPtr error = xmlCtxtGetLastError(ctxt);\ | ||||||
|  |         int code = (error != NULL) ? error->code : 0; \ | ||||||
|  |         const char* message = (error != NULL) ? error->message : NULL; \ | ||||||
|  |         xmlSecError(XMLSEC_ERRORS_HERE,               \ | ||||||
|  |                    (const char*)(errorObject),        \ | ||||||
|  |                    (errorFunction),                   \ | ||||||
|  |                    XMLSEC_ERRORS_R_XML_FAILED,        \ | ||||||
|  |                    "xml error: %lu: %s",              \ | ||||||
|  |                    (unsigned long)code,               \ | ||||||
|  |                    xmlSecErrorsSafeString(message)    \ | ||||||
|  |         );                                            \ | ||||||
|  |     } | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * xmlSecXmlParserError2: | ||||||
|  |  * @errorFunction:      the failed function. | ||||||
|  |  * @ctxt:               the parser context. | ||||||
|  |  * @errorObject:        the error specific error object (e.g. transform, key data, etc). | ||||||
|  |  * @msg:                the extra message. | ||||||
|  |  * @param:              the extra message param. | ||||||
|  |  * | ||||||
|  |  * Macro. The XMLSec library macro for reporting XML parser errors. | ||||||
|  |  */ | ||||||
|  | #define xmlSecXmlParserError2(errorFunction, ctxt, errorObject, msg, param) \ | ||||||
|  |     {                                                 \ | ||||||
|  |         xmlErrorPtr error = xmlCtxtGetLastError(ctxt);\ | ||||||
|  |         int code = (error != NULL) ? error->code : 0; \ | ||||||
|  |         const char* message = (error != NULL) ? error->message : NULL; \ | ||||||
|  |         xmlSecError(XMLSEC_ERRORS_HERE,               \ | ||||||
|  |                    (const char*)(errorObject),        \ | ||||||
|  |                    (errorFunction),                   \ | ||||||
|  |                    XMLSEC_ERRORS_R_XML_FAILED,        \ | ||||||
|  |                    msg "; xml error: %lu: %s",        \ | ||||||
|  |                    (param),                           \ | ||||||
|  |                    (unsigned long)code,               \ | ||||||
|  |                    xmlSecErrorsSafeString(message)    \ | ||||||
|  |         );                                            \ | ||||||
|  |     } | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * xmlSecXsltError: | ||||||
|  |  * @errorFunction:      the failed function. | ||||||
|  |  * @ctxt:               the parser context. | ||||||
|  |  * @errorObject:        the error specific error object (e.g. transform, key data, etc). | ||||||
|  |  * | ||||||
|  |  * Macro. The XMLSec library macro for reporting XSLT errors. | ||||||
|  |  */ | ||||||
|  | #define xmlSecXsltError(errorFunction, ctxt, errorObject) \ | ||||||
|  |     {                                                 \ | ||||||
|  |         xmlErrorPtr error = xmlGetLastError();        \ | ||||||
|  |         int code = (error != NULL) ? error->code : 0; \ | ||||||
|  |         const char* message = (error != NULL) ? error->message : NULL; \ | ||||||
|  |         xmlSecError(XMLSEC_ERRORS_HERE,               \ | ||||||
|  |                    (const char*)(errorObject),        \ | ||||||
|  |                    (errorFunction),                   \ | ||||||
|  |                    XMLSEC_ERRORS_R_XSLT_FAILED,       \ | ||||||
|  |                    "xslt error: %lu: %s",             \ | ||||||
|  |                    (unsigned long)code,               \ | ||||||
|  |                    xmlSecErrorsSafeString(message)    \ | ||||||
|  |         );                                            \ | ||||||
|  |     } | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * xmlSecIOError: | ||||||
|  |  * @errorFunction:      the failed function. | ||||||
|  |  * @name:               the filename, function name, uri, etc. | ||||||
|  |  * @errorObject:        the error specific error object (e.g. transform, key data, etc). | ||||||
|  |  * | ||||||
|  |  * Macro. The XMLSec library macro for reporting IO errors. | ||||||
|  |  */ | ||||||
|  | #define xmlSecIOError(errorFunction, name, errorObject) \ | ||||||
|  |     {                                                 \ | ||||||
|  |         xmlSecError(XMLSEC_ERRORS_HERE,               \ | ||||||
|  |                    (const char*)(errorObject),        \ | ||||||
|  |                    (errorFunction),                   \ | ||||||
|  |                    XMLSEC_ERRORS_R_IO_FAILED,         \ | ||||||
|  |                    "name=\"%s\"; errno=%d",           \ | ||||||
|  |                    xmlSecErrorsSafeString(name),      \ | ||||||
|  |                    errno                              \ | ||||||
|  |         );                                            \ | ||||||
|  |     } | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * xmlSecNotImplementedError: | ||||||
|  |  * @details:           the additional details. | ||||||
|  |  * | ||||||
|  |  * Macro. The XMLSec library macro for reporting "not implemented" errors. | ||||||
|  |  */ | ||||||
|  | #define xmlSecNotImplementedError(details) \ | ||||||
|  |         xmlSecError(XMLSEC_ERRORS_HERE,                     \ | ||||||
|  |                     NULL,                                   \ | ||||||
|  |                     NULL,                                   \ | ||||||
|  |                     XMLSEC_ERRORS_R_NOT_IMPLEMENTED,        \ | ||||||
|  |                     "details=%s",                           \ | ||||||
|  |                     xmlSecErrorsSafeString(details)         \ | ||||||
|  |         ) | ||||||
|  | /** | ||||||
|  |  * xmlSecInvalidSizeError: | ||||||
|  |  * @name:               the name of the variable, parameter, etc. | ||||||
|  |  * @actual:             the actual value. | ||||||
|  |  * @expected:           the expected value. | ||||||
|  |  * @errorObject:        the error specific error object (e.g. transform, key data, etc). | ||||||
|  |  * | ||||||
|  |  * Macro. The XMLSec library macro for reporting "invalid size" errors when | ||||||
|  |  * we expect exact match. | ||||||
|  |  */ | ||||||
|  | #define xmlSecInvalidSizeError(name, actual, expected, errorObject) \ | ||||||
|  |         xmlSecError(XMLSEC_ERRORS_HERE,                     \ | ||||||
|  |                     (const char*)(errorObject),             \ | ||||||
|  |                     NULL,                                   \ | ||||||
|  |                     XMLSEC_ERRORS_R_INVALID_SIZE,           \ | ||||||
|  |                     "invalid size for '%s': actual=%lu is not equal to expected=%lu", \ | ||||||
|  |                     xmlSecErrorsSafeString(name),           \ | ||||||
|  |                     (unsigned long)(actual),                \ | ||||||
|  |                     (unsigned long)(expected)               \ | ||||||
|  |         ) | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * xmlSecInvalidSizeLessThanError: | ||||||
|  |  * @name:               the name of the variable, parameter, etc. | ||||||
|  |  * @actual:             the actual value. | ||||||
|  |  * @expected:           the expected value. | ||||||
|  |  * @errorObject:        the error specific error object (e.g. transform, key data, etc). | ||||||
|  |  * | ||||||
|  |  * Macro. The XMLSec library macro for reporting "invalid size" errors when | ||||||
|  |  * we expect at least the expected size. | ||||||
|  |  */ | ||||||
|  | #define xmlSecInvalidSizeLessThanError(name, actual, expected, errorObject) \ | ||||||
|  |         xmlSecError(XMLSEC_ERRORS_HERE,                     \ | ||||||
|  |                     (const char*)(errorObject),             \ | ||||||
|  |                     NULL,                                   \ | ||||||
|  |                     XMLSEC_ERRORS_R_INVALID_SIZE,           \ | ||||||
|  |                     "invalid size for '%s': actual=%lu is less than expected=%lu", \ | ||||||
|  |                     xmlSecErrorsSafeString(name),           \ | ||||||
|  |                     (unsigned long)(actual),                \ | ||||||
|  |                     (unsigned long)(expected)               \ | ||||||
|  |         ) | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * xmlSecInvalidSizeMoreThanError: | ||||||
|  |  * @name:               the name of the variable, parameter, etc. | ||||||
|  |  * @actual:             the actual value. | ||||||
|  |  * @expected:           the expected value. | ||||||
|  |  * @errorObject:        the error specific error object (e.g. transform, key data, etc). | ||||||
|  |  * | ||||||
|  |  * Macro. The XMLSec library macro for reporting "invalid size" errors when | ||||||
|  |  * we expect at most the expected size. | ||||||
|  |  */ | ||||||
|  | #define xmlSecInvalidSizeMoreThanError(name, actual, expected, errorObject) \ | ||||||
|  |         xmlSecError(XMLSEC_ERRORS_HERE,                     \ | ||||||
|  |                     (const char*)(errorObject),             \ | ||||||
|  |                     NULL,                                   \ | ||||||
|  |                     XMLSEC_ERRORS_R_NOT_IMPLEMENTED,        \ | ||||||
|  |                     "invalid size for '%s': actual=%lu is more than expected=%lu", \ | ||||||
|  |                     xmlSecErrorsSafeString(name),           \ | ||||||
|  |                     (unsigned long)(actual),                \ | ||||||
|  |                     (unsigned long)(expected)               \ | ||||||
|  |         ) | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * xmlSecInvalidSizeNotMultipleOfError: | ||||||
|  |  * @name:               the name of the variable, parameter, etc. | ||||||
|  |  * @actual:             the actual value. | ||||||
|  |  * @divider:            the expected divider. | ||||||
|  |  * @errorObject:        the error specific error object (e.g. transform, key data, etc). | ||||||
|  |  * | ||||||
|  |  * Macro. The XMLSec library macro for reporting "invalid size" errors when | ||||||
|  |  * we expect the size to be a multiple of the divider. | ||||||
|  |  */ | ||||||
|  | #define xmlSecInvalidSizeNotMultipleOfError(name, actual, divider, errorObject) \ | ||||||
|  |         xmlSecError(XMLSEC_ERRORS_HERE,                     \ | ||||||
|  |                     (const char*)(errorObject),             \ | ||||||
|  |                     NULL,                                   \ | ||||||
|  |                     XMLSEC_ERRORS_R_NOT_IMPLEMENTED,        \ | ||||||
|  |                     "invalid size for '%s': actual=%lu is not a multiple of %lu", \ | ||||||
|  |                     xmlSecErrorsSafeString(name),           \ | ||||||
|  |                     (unsigned long)(actual),                \ | ||||||
|  |                     (unsigned long)(divider)               \ | ||||||
|  |         ) | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * xmlSecInvalidSizeOtherError: | ||||||
|  |  * @msg:                the message about the error. | ||||||
|  |  * @errorObject:        the error specific error object (e.g. transform, key data, etc). | ||||||
|  |  * | ||||||
|  |  * Macro. The XMLSec library macro for reporting "invalid size" errors when | ||||||
|  |  * we expect exact match. | ||||||
|  |  */ | ||||||
|  | #define xmlSecInvalidSizeOtherError(msg, errorObject) \ | ||||||
|  |         xmlSecError(XMLSEC_ERRORS_HERE,                     \ | ||||||
|  |                     (const char*)(errorObject),             \ | ||||||
|  |                     NULL,                                   \ | ||||||
|  |                     XMLSEC_ERRORS_R_INVALID_SIZE,           \ | ||||||
|  |                     "invalid size: %s",                     \ | ||||||
|  |                     xmlSecErrorsSafeString(msg)             \ | ||||||
|  |         ) | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * xmlSecInvalidDataError: | ||||||
|  |  * @msg:                the msg with explanation. | ||||||
|  |  * @errorObject:        the error specific error object (e.g. transform, key data, etc). | ||||||
|  |  * | ||||||
|  |  * Macro. The XMLSec library macro for reporting "invalid data" errors. | ||||||
|  |  */ | ||||||
|  | #define xmlSecInvalidDataError(msg, errorObject) \ | ||||||
|  |         xmlSecError(XMLSEC_ERRORS_HERE,                     \ | ||||||
|  |                     (const char*)(errorObject),             \ | ||||||
|  |                     NULL,                                   \ | ||||||
|  |                     XMLSEC_ERRORS_R_INVALID_DATA,           \ | ||||||
|  |                     "%s",                                   \ | ||||||
|  |                     xmlSecErrorsSafeString(msg)             \ | ||||||
|  |         ) | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * xmlSecInvalidStringDataError: | ||||||
|  |  * @name:               the name of the variable, parameter, etc. | ||||||
|  |  * @actual:             the actual value as a string. | ||||||
|  |  * @expected:           the expected value(s) as a string. | ||||||
|  |  * @errorObject:        the error specific error object (e.g. transform, key data, etc). | ||||||
|  |  * | ||||||
|  |  * Macro. The XMLSec library macro for reporting "invalid data" errors for string. | ||||||
|  |  */ | ||||||
|  | #define xmlSecInvalidStringDataError(name, actual, expected, errorObject) \ | ||||||
|  |         xmlSecError(XMLSEC_ERRORS_HERE,                     \ | ||||||
|  |                     (const char*)(errorObject),             \ | ||||||
|  |                     NULL,                                   \ | ||||||
|  |                     XMLSEC_ERRORS_R_INVALID_DATA,           \ | ||||||
|  |                     "invalid data for '%s': actual='%s' and expected %s", \ | ||||||
|  |                     xmlSecErrorsSafeString(name),           \ | ||||||
|  |                     xmlSecErrorsSafeString(actual),         \ | ||||||
|  |                     (expected)                              \ | ||||||
|  |         ) | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * xmlSecInvalidIntegerDataError: | ||||||
|  |  * @name:               the name of the variable, parameter, etc. | ||||||
|  |  * @actual:             the actual value as an integer. | ||||||
|  |  * @expected:           the expected value(s) as a string. | ||||||
|  |  * @errorObject:        the error specific error object (e.g. transform, key data, etc). | ||||||
|  |  * | ||||||
|  |  * Macro. The XMLSec library macro for reporting "invalid data" errors for integers. | ||||||
|  |  */ | ||||||
|  | #define xmlSecInvalidIntegerDataError(name, actual, expected, errorObject) \ | ||||||
|  |         xmlSecError(XMLSEC_ERRORS_HERE,                     \ | ||||||
|  |                     (const char*)(errorObject),             \ | ||||||
|  |                     NULL,                                   \ | ||||||
|  |                     XMLSEC_ERRORS_R_INVALID_DATA,           \ | ||||||
|  |                     "invalid data for '%s': actual=%ld and expected %s", \ | ||||||
|  |                     xmlSecErrorsSafeString(name),           \ | ||||||
|  |                     (unsigned long)(actual),                \ | ||||||
|  |                     (expected)                              \ | ||||||
|  |         ) | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * xmlSecInvalidIntegerDataError2: | ||||||
|  |  * @name1:              the name of the first variable, parameter, etc. | ||||||
|  |  * @actual1:            the actual first value as an integer. | ||||||
|  |  * @name2:              the name of the second variable, parameter, etc. | ||||||
|  |  * @actual2:            the actual second value as an integer. | ||||||
|  |  * @expected:           the expected value(s) as a string. | ||||||
|  |  * @errorObject:        the error specific error object (e.g. transform, key data, etc). | ||||||
|  |  * | ||||||
|  |  * Macro. The XMLSec library macro for reporting "invalid data" errors for integers. | ||||||
|  |  */ | ||||||
|  | #define xmlSecInvalidIntegerDataError2(name1, actual1, name2, actual2, expected, errorObject) \ | ||||||
|  |         xmlSecError(XMLSEC_ERRORS_HERE,                     \ | ||||||
|  |                     (const char*)(errorObject),             \ | ||||||
|  |                     NULL,                                   \ | ||||||
|  |                     XMLSEC_ERRORS_R_INVALID_DATA,           \ | ||||||
|  |                     "invalid data: actual value '%s'=%ld, actual value '%s'=%ld and expected %s", \ | ||||||
|  |                     xmlSecErrorsSafeString(name1),          \ | ||||||
|  |                     (unsigned long)(actual1),               \ | ||||||
|  |                     xmlSecErrorsSafeString(name2),          \ | ||||||
|  |                     (unsigned long)(actual2),               \ | ||||||
|  |                     (expected)                              \ | ||||||
|  |         ) | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * xmlSecInvalidTypeError: | ||||||
|  |  * @msg:                the msg with explanation. | ||||||
|  |  * @errorObject:        the error specific error object (e.g. transform, key data, etc). | ||||||
|  |  * | ||||||
|  |  * Macro. The XMLSec library macro for reporting "invalid type" errors. | ||||||
|  |  */ | ||||||
|  | #define xmlSecInvalidTypeError(msg, errorObject) \ | ||||||
|  |         xmlSecError(XMLSEC_ERRORS_HERE,                     \ | ||||||
|  |                     (const char*)(errorObject),             \ | ||||||
|  |                     NULL,                                   \ | ||||||
|  |                     XMLSEC_ERRORS_R_INVALID_TYPE,           \ | ||||||
|  |                     "%s",                                   \ | ||||||
|  |                     xmlSecErrorsSafeString(msg)             \ | ||||||
|  |         ) | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * xmlSecInvalidStringTypeError: | ||||||
|  |  * @name:               the name of the variable, parameter, etc. | ||||||
|  |  * @actual:             the actual value as a string. | ||||||
|  |  * @expected:           the expected value(s) as a string. | ||||||
|  |  * @errorObject:        the error specific error object (e.g. transform, key data, etc). | ||||||
|  |  * | ||||||
|  |  * Macro. The XMLSec library macro for reporting "invalid type" errors for string. | ||||||
|  |  */ | ||||||
|  | #define xmlSecInvalidStringTypeError(name, actual, expected, errorObject) \ | ||||||
|  |         xmlSecError(XMLSEC_ERRORS_HERE,                     \ | ||||||
|  |                     (const char*)(errorObject),             \ | ||||||
|  |                     NULL,                                   \ | ||||||
|  |                     XMLSEC_ERRORS_R_INVALID_TYPE,           \ | ||||||
|  |                     "invalid type for '%s': actual='%s' and expected %s", \ | ||||||
|  |                     xmlSecErrorsSafeString(name),           \ | ||||||
|  |                     xmlSecErrorsSafeString(actual),         \ | ||||||
|  |                     (expected)                              \ | ||||||
|  |         ) | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * xmlSecInvalidIntegerTypeError: | ||||||
|  |  * @name:               the name of the variable, parameter, etc. | ||||||
|  |  * @actual:             the actual value as an integer. | ||||||
|  |  * @expected:           the expected value(s) as a string. | ||||||
|  |  * @errorObject:        the error specific error object (e.g. transform, key data, etc). | ||||||
|  |  * | ||||||
|  |  * Macro. The XMLSec library macro for reporting "invalid type" errors for integers. | ||||||
|  |  */ | ||||||
|  | #define xmlSecInvalidIntegerTypeError(name, actual, expected, errorObject) \ | ||||||
|  |         xmlSecError(XMLSEC_ERRORS_HERE,                     \ | ||||||
|  |                     (const char*)(errorObject),             \ | ||||||
|  |                     NULL,                                   \ | ||||||
|  |                     XMLSEC_ERRORS_R_INVALID_TYPE,           \ | ||||||
|  |                     "invalid type for '%s': actual=%ld and expected %s", \ | ||||||
|  |                     xmlSecErrorsSafeString(name),           \ | ||||||
|  |                     (unsigned long)(actual),                \ | ||||||
|  |                     (expected)                              \ | ||||||
|  |         ) | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * xmlSecInvalidIntegerTypeError2: | ||||||
|  |  * @name1:              the name of the first variable, parameter, etc. | ||||||
|  |  * @actual1:            the actual first value as an integer. | ||||||
|  |  * @name2:              the name of the second variable, parameter, etc. | ||||||
|  |  * @actual2:            the actual second value as an integer. | ||||||
|  |  * @expected:           the expected value(s) as a string. | ||||||
|  |  * @errorObject:        the error specific error object (e.g. transform, key data, etc). | ||||||
|  |  * | ||||||
|  |  * Macro. The XMLSec library macro for reporting "invalid type" errors for integers. | ||||||
|  |  */ | ||||||
|  | #define xmlSecInvalidIntegerTypeError2(name1, actual1, name2, actual2, expected, errorObject) \ | ||||||
|  |         xmlSecError(XMLSEC_ERRORS_HERE,                     \ | ||||||
|  |                     (const char*)(errorObject),             \ | ||||||
|  |                     NULL,                                   \ | ||||||
|  |                     XMLSEC_ERRORS_R_INVALID_TYPE,           \ | ||||||
|  |                     "invalid type: actual value '%s'=%ld, actual value '%s'=%ld and expected %s", \ | ||||||
|  |                     xmlSecErrorsSafeString(name1),          \ | ||||||
|  |                     (unsigned long)(actual1),               \ | ||||||
|  |                     xmlSecErrorsSafeString(name2),          \ | ||||||
|  |                     (unsigned long)(actual2),               \ | ||||||
|  |                     (expected)                              \ | ||||||
|  |         ) | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * xmlSecInvalidNodeError: | ||||||
|  |  * @actualNode:         the actual node. | ||||||
|  |  * @expectedNodeName:   the expected node name. | ||||||
|  |  * @errorObject:        the error specific error object (e.g. transform, key data, etc). | ||||||
|  |  * | ||||||
|  |  * Macro. The XMLSec library macro for reporting an invalid node errors. | ||||||
|  |  */ | ||||||
|  | #define xmlSecInvalidNodeError(actualNode, expectedNodeName, errorObject) \ | ||||||
|  |     {                                                 \ | ||||||
|  |         const char* actualNodeName = xmlSecNodeGetName(actualNode); \ | ||||||
|  |         xmlSecError(XMLSEC_ERRORS_HERE,               \ | ||||||
|  |                    (const char*)(errorObject),        \ | ||||||
|  |                    NULL,                              \ | ||||||
|  |                    XMLSEC_ERRORS_R_INVALID_NODE,      \ | ||||||
|  |                    "actual=%s; expected=%s",          \ | ||||||
|  |                    xmlSecErrorsSafeString(actualNodeName),  \ | ||||||
|  |                    xmlSecErrorsSafeString(expectedNodeName) \ | ||||||
|  |         );                                            \ | ||||||
|  |     } | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * xmlSecInvalidNodeContentError: | ||||||
|  |  * @node:               the node. | ||||||
|  |  * @errorObject:        the error specific error object (e.g. transform, key data, etc). | ||||||
|  |  * @reason:             the reason why node content is invalid. | ||||||
|  |  * | ||||||
|  |  * Macro. The XMLSec library macro for reporting an invalid node content errors. | ||||||
|  |  */ | ||||||
|  | #define xmlSecInvalidNodeContentError(node, errorObject, reason) \ | ||||||
|  |     {                                                 \ | ||||||
|  |         const char* nName = xmlSecNodeGetName(node);  \ | ||||||
|  |         xmlSecError(XMLSEC_ERRORS_HERE,               \ | ||||||
|  |                    (const char*)(errorObject),        \ | ||||||
|  |                    NULL,                              \ | ||||||
|  |                    XMLSEC_ERRORS_R_INVALID_NODE_CONTENT, \ | ||||||
|  |                    "node=%s; reason=%s",              \ | ||||||
|  |                    xmlSecErrorsSafeString(nName),     \ | ||||||
|  |                    xmlSecErrorsSafeString(reason)     \ | ||||||
|  |         );                                            \ | ||||||
|  |     } | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * xmlSecInvalidNodeAttributeError: | ||||||
|  |  * @node:               the node. | ||||||
|  |  * @attrName:           the attribute name. | ||||||
|  |  * @errorObject:        the error specific error object (e.g. transform, key data, etc). | ||||||
|  |  * @reason:             the reason why node content is invalid. | ||||||
|  |  * | ||||||
|  |  * Macro. The XMLSec library macro for reporting an invalid node attribute errors. | ||||||
|  |  */ | ||||||
|  | #define xmlSecInvalidNodeAttributeError(node, attrName, errorObject, reason) \ | ||||||
|  |     {                                                 \ | ||||||
|  |         const char* nName = xmlSecNodeGetName(node);  \ | ||||||
|  |         xmlSecError(XMLSEC_ERRORS_HERE,               \ | ||||||
|  |                    (const char*)(errorObject),        \ | ||||||
|  |                    NULL,                              \ | ||||||
|  |                    XMLSEC_ERRORS_R_INVALID_NODE_ATTRIBUTE, \ | ||||||
|  |                    "node=%s; attribute=%s; reason=%s",\ | ||||||
|  |                    xmlSecErrorsSafeString(nName),     \ | ||||||
|  |                    xmlSecErrorsSafeString(attrName),  \ | ||||||
|  |                    xmlSecErrorsSafeString(reason)     \ | ||||||
|  |         );                                            \ | ||||||
|  |     } | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * xmlSecNodeAlreadyPresentError: | ||||||
|  |  * @parent:             the parent node. | ||||||
|  |  * @nodeName:           the node name. | ||||||
|  |  * @errorObject:        the error specific error object (e.g. transform, key data, etc). | ||||||
|  |  * | ||||||
|  |  * Macro. The XMLSec library macro for reporting node already present errors. | ||||||
|  |  */ | ||||||
|  | #define xmlSecNodeAlreadyPresentError(parent, nodeName, errorObject) \ | ||||||
|  |     {                                                 \ | ||||||
|  |         const char* pName = xmlSecNodeGetName(parent);\ | ||||||
|  |         xmlSecError(XMLSEC_ERRORS_HERE,               \ | ||||||
|  |                    (const char*)(errorObject),        \ | ||||||
|  |                    NULL,                              \ | ||||||
|  |                    XMLSEC_ERRORS_R_NODE_ALREADY_PRESENT, \ | ||||||
|  |                    "parent=%s; node=%s",              \ | ||||||
|  |                    xmlSecErrorsSafeString(pName),     \ | ||||||
|  |                    xmlSecErrorsSafeString(nodeName)   \ | ||||||
|  |         );                                            \ | ||||||
|  |     } | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * xmlSecUnexpectedNodeError: | ||||||
|  |  * @node:               the node. | ||||||
|  |  * @errorObject:        the error specific error object (e.g. transform, key data, etc). | ||||||
|  |  * | ||||||
|  |  * Macro. The XMLSec library macro for reporting an invalid node errors. | ||||||
|  |  */ | ||||||
|  | #define xmlSecUnexpectedNodeError(node, errorObject) \ | ||||||
|  |     {                                                 \ | ||||||
|  |         const char* nName = xmlSecNodeGetName(node);  \ | ||||||
|  |         xmlSecError(XMLSEC_ERRORS_HERE,               \ | ||||||
|  |                    (const char*)(errorObject),        \ | ||||||
|  |                    NULL,                              \ | ||||||
|  |                    XMLSEC_ERRORS_R_UNEXPECTED_NODE,   \ | ||||||
|  |                    "node=%s",                         \ | ||||||
|  |                    xmlSecErrorsSafeString(nName)      \ | ||||||
|  |         );                                            \ | ||||||
|  |     } | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * xmlSecNodeNotFoundError: | ||||||
|  |  * @errorFunction:      the failed function. | ||||||
|  |  * @startNode:          the search start node. | ||||||
|  |  * @targetNodeName:     the expected child node name. | ||||||
|  |  * @errorObject:        the error specific error object (e.g. transform, key data, etc). | ||||||
|  |  * | ||||||
|  |  * Macro. The XMLSec library macro for reporting node not found errors. | ||||||
|  |  */ | ||||||
|  | #define xmlSecNodeNotFoundError(errorFunction, startNode, targetNodeName, errorObject) \ | ||||||
|  |     {                                                 \ | ||||||
|  |         const char* startNodeName = xmlSecNodeGetName(startNode); \ | ||||||
|  |         xmlSecError(XMLSEC_ERRORS_HERE,               \ | ||||||
|  |                    (const char*)(errorObject),        \ | ||||||
|  |                    (errorFunction),                   \ | ||||||
|  |                    XMLSEC_ERRORS_R_NODE_NOT_FOUND,    \ | ||||||
|  |                    "startNode=%s; target=%s",         \ | ||||||
|  |                    xmlSecErrorsSafeString(startNodeName), \ | ||||||
|  |                    xmlSecErrorsSafeString(targetNodeName) \ | ||||||
|  |         );                                            \ | ||||||
|  |     } | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * xmlSecInvalidTransfromError: | ||||||
|  |  * @transform:          the transform. | ||||||
|  |  * | ||||||
|  |  * Macro. The XMLSec library macro for reporting an invalid transform errors. | ||||||
|  |  */ | ||||||
|  | #define xmlSecInvalidTransfromError(transform) \ | ||||||
|  |     {                                                 \ | ||||||
|  |         xmlSecError(XMLSEC_ERRORS_HERE,               \ | ||||||
|  |                    (const char*)xmlSecTransformGetName(transform), \ | ||||||
|  |                    NULL,                              \ | ||||||
|  |                    XMLSEC_ERRORS_R_INVALID_TRANSFORM, \ | ||||||
|  |                    XMLSEC_ERRORS_NO_MESSAGE           \ | ||||||
|  |         );                                            \ | ||||||
|  |     } | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * xmlSecInvalidTransfromError2: | ||||||
|  |  * @transform:          the transform. | ||||||
|  |  * @msg:                the extra message. | ||||||
|  |  * @param:              the extra message param. | ||||||
|  |  * | ||||||
|  |  * | ||||||
|  |  * Macro. The XMLSec library macro for reporting an invalid transform errors. | ||||||
|  |  */ | ||||||
|  | #define xmlSecInvalidTransfromError2(transform, msg, param) \ | ||||||
|  |     {                                                 \ | ||||||
|  |         xmlSecError(XMLSEC_ERRORS_HERE,               \ | ||||||
|  |                    (const char*)xmlSecTransformGetName(transform), \ | ||||||
|  |                    NULL,                              \ | ||||||
|  |                    XMLSEC_ERRORS_R_INVALID_TRANSFORM, \ | ||||||
|  |                    (msg), (param)                     \ | ||||||
|  |         );                                            \ | ||||||
|  |     } | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * xmlSecInvalidTransfromStatusError: | ||||||
|  |  * @transform:          the transform. | ||||||
|  |  * | ||||||
|  |  * Macro. The XMLSec library macro for reporting an invalid transform status errors. | ||||||
|  |  */ | ||||||
|  | #define xmlSecInvalidTransfromStatusError(transform) \ | ||||||
|  |     {                                                 \ | ||||||
|  |         xmlSecError(XMLSEC_ERRORS_HERE,               \ | ||||||
|  |                    (const char*)xmlSecTransformGetName(transform), \ | ||||||
|  |                    NULL,                              \ | ||||||
|  |                    XMLSEC_ERRORS_R_INVALID_STATUS,    \ | ||||||
|  |                    "transformStatus=%d",              \ | ||||||
|  |                    (int)((transform)->status)         \ | ||||||
|  |         );                                            \ | ||||||
|  |     } | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * xmlSecInvalidTransfromStatusError2: | ||||||
|  |  * @transform:          the transform. | ||||||
|  |  * @msg:                the extra message. | ||||||
|  |  * | ||||||
|  |  * Macro. The XMLSec library macro for reporting an invalid transform status errors. | ||||||
|  |  */ | ||||||
|  | #define xmlSecInvalidTransfromStatusError2(transform, msg) \ | ||||||
|  |     {                                                 \ | ||||||
|  |         xmlSecError(XMLSEC_ERRORS_HERE,               \ | ||||||
|  |                    (const char*)xmlSecTransformGetName(transform), \ | ||||||
|  |                    NULL,                              \ | ||||||
|  |                    XMLSEC_ERRORS_R_INVALID_STATUS,    \ | ||||||
|  |                    "transformStatus=%ld, msg=%s",     \ | ||||||
|  |                    (long int)((transform)->status),   \ | ||||||
|  |                    msg                                \ | ||||||
|  |         );                                            \ | ||||||
|  |     } | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * xmlSecInvalidKeyDataSizeError: | ||||||
|  |  * @name:               the name of the variable, parameter, etc. | ||||||
|  |  * @actual:             the actual value. | ||||||
|  |  * @expected:           the expected value(s). | ||||||
|  |  * @errorObject:        the error specific error object (e.g. transform, key data, etc). | ||||||
|  |  * | ||||||
|  |  * Macro. The XMLSec library macro for reporting "invalid keydata size" errors. | ||||||
|  |  */ | ||||||
|  | #define xmlSecInvalidKeyDataSizeError(actual, expected, errorObject) \ | ||||||
|  |         xmlSecError(XMLSEC_ERRORS_HERE,                     \ | ||||||
|  |                     (const char*)(errorObject),             \ | ||||||
|  |                     NULL,                                   \ | ||||||
|  |                     XMLSEC_ERRORS_R_INVALID_KEY_DATA_SIZE,  \ | ||||||
|  |                     "invalid key data size: actual=%ld and expected=%ld", \ | ||||||
|  |                     (unsigned long)(actual),                \ | ||||||
|  |                     (unsigned long)(expected)               \ | ||||||
|  |         ) | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * xmlSecInvalidZeroKeyDataSizeError: | ||||||
|  |  * @name:               the name of the variable, parameter, etc. | ||||||
|  |  * @errorObject:        the error specific error object (e.g. transform, key data, etc). | ||||||
|  |  * | ||||||
|  |  * Macro. The XMLSec library macro for reporting "invalid keydata size" errors. | ||||||
|  |  */ | ||||||
|  | #define xmlSecInvalidZeroKeyDataSizeError(errorObject) \ | ||||||
|  |         xmlSecError(XMLSEC_ERRORS_HERE,                     \ | ||||||
|  |                     (const char*)(errorObject),             \ | ||||||
|  |                     NULL,                                   \ | ||||||
|  |                     XMLSEC_ERRORS_R_INVALID_KEY_DATA_SIZE,  \ | ||||||
|  |                     "invalid zero key data size"            \ | ||||||
|  |         ) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * xmlSecOtherError: | ||||||
|  |  * @code:               the error code. | ||||||
|  |  * @errorObject:        the error specific error object (e.g. transform, key data, etc). | ||||||
|  |  * @details:            the error message. | ||||||
|  |  * | ||||||
|  |  * Macro. The XMLSec library macro for reporting other XMLSec errors. | ||||||
|  |  */ | ||||||
|  | #define xmlSecOtherError(code, errorObject, details) \ | ||||||
|  |         xmlSecError(XMLSEC_ERRORS_HERE,                     \ | ||||||
|  |                     (const char*)(errorObject),             \ | ||||||
|  |                     NULL,                                   \ | ||||||
|  |                     (code),                                 \ | ||||||
|  |                     "details=%s",                           \ | ||||||
|  |                     xmlSecErrorsSafeString(details)         \ | ||||||
|  |         ) | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * xmlSecOtherError2: | ||||||
|  |  * @code:               the error code. | ||||||
|  |  * @errorObject:        the error specific error object (e.g. transform, key data, etc). | ||||||
|  |  * @msg:                the extra message. | ||||||
|  |  * @param:              the extra message param. | ||||||
|  |  * | ||||||
|  |  * Macro. The XMLSec library macro for reporting other XMLSec errors. | ||||||
|  |  */ | ||||||
|  | #define xmlSecOtherError2(code, errorObject, msg, param) \ | ||||||
|  |         xmlSecError(XMLSEC_ERRORS_HERE,                     \ | ||||||
|  |                     (const char*)(errorObject),             \ | ||||||
|  |                     NULL,                                   \ | ||||||
|  |                     (code),                                 \ | ||||||
|  |                     (msg), (param)                          \ | ||||||
|  |         ) | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * xmlSecOtherError3: | ||||||
|  |  * @code:               the error code. | ||||||
|  |  * @errorObject:        the error specific error object (e.g. transform, key data, etc). | ||||||
|  |  * @msg:                the extra message. | ||||||
|  |  * @param1:             the extra message param. | ||||||
|  |  * @param2:             the extra message param. | ||||||
|  |  * | ||||||
|  |  * Macro. The XMLSec library macro for reporting other XMLSec errors. | ||||||
|  |  */ | ||||||
|  | #define xmlSecOtherError3(code, errorObject, msg, param1, param2) \ | ||||||
|  |         xmlSecError(XMLSEC_ERRORS_HERE,                     \ | ||||||
|  |                     (const char*)(errorObject),             \ | ||||||
|  |                     NULL,                                   \ | ||||||
|  |                     (code),                                 \ | ||||||
|  |                     (msg), (param1), (param2)               \ | ||||||
|  |         ) | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * xmlSecOtherError4: | ||||||
|  |  * @code:               the error code. | ||||||
|  |  * @errorObject:        the error specific error object (e.g. transform, key data, etc). | ||||||
|  |  * @msg:                the extra message. | ||||||
|  |  * @param1:             the extra message param. | ||||||
|  |  * @param2:             the extra message param. | ||||||
|  |  * @param3:             the extra message param. | ||||||
|  |  * | ||||||
|  |  * Macro. The XMLSec library macro for reporting other XMLSec errors. | ||||||
|  |  */ | ||||||
|  | #define xmlSecOtherError4(code, errorObject, msg, param1, param2, param3) \ | ||||||
|  |         xmlSecError(XMLSEC_ERRORS_HERE,                     \ | ||||||
|  |                     (const char*)(errorObject),             \ | ||||||
|  |                     NULL,                                   \ | ||||||
|  |                     (code),                                 \ | ||||||
|  |                     (msg), (param1), (param2), (param3)     \ | ||||||
|  |         ) | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * xmlSecOtherError5: | ||||||
|  |  * @code:               the error code. | ||||||
|  |  * @errorObject:        the error specific error object (e.g. transform, key data, etc). | ||||||
|  |  * @msg:                the extra message. | ||||||
|  |  * @param1:             the extra message param. | ||||||
|  |  * @param2:             the extra message param. | ||||||
|  |  * @param3:             the extra message param. | ||||||
|  |  * @param4:             the extra message param. | ||||||
|  |  * | ||||||
|  |  * Macro. The XMLSec library macro for reporting other XMLSec errors. | ||||||
|  |  */ | ||||||
|  | #define xmlSecOtherError5(code, errorObject, msg, param1, param2, param3, param4) \ | ||||||
|  |         xmlSecError(XMLSEC_ERRORS_HERE,                     \ | ||||||
|  |                     (const char*)(errorObject),             \ | ||||||
|  |                     NULL,                                   \ | ||||||
|  |                     (code),                                 \ | ||||||
|  |                     (msg), (param1), (param2), (param3), (param4) \ | ||||||
|  |         ) | ||||||
|  |  | ||||||
|  | #ifdef __cplusplus | ||||||
|  | } | ||||||
|  | #endif /* __cplusplus */ | ||||||
|  |  | ||||||
|  | #endif /* __XMLSEC_ERROR_HELPERS_H__ */ | ||||||
							
								
								
									
										1952
									
								
								experimental/facho-signer/src/xades/xmlsec1/xmltree.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1952
									
								
								experimental/facho-signer/src/xades/xmlsec1/xmltree.c
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										259
									
								
								experimental/facho-signer/src/xmlsec1/errors.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										259
									
								
								experimental/facho-signer/src/xmlsec1/errors.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,259 @@ | |||||||
|  | /* | ||||||
|  |  * XML Security Library (http://www.aleksey.com/xmlsec). | ||||||
|  |  * | ||||||
|  |  * | ||||||
|  |  * This is free software; see Copyright file in the source | ||||||
|  |  * distribution for preciese wording. | ||||||
|  |  * | ||||||
|  |  * Copyright (C) 2002-2016 Aleksey Sanin <aleksey@aleksey.com>. All Rights Reserved. | ||||||
|  |  */ | ||||||
|  | /** | ||||||
|  |  * SECTION:errors | ||||||
|  |  * @Short_description: Error reporting and logging functions. | ||||||
|  |  * @Stability: Stable | ||||||
|  |  * | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | #define XMLSEC_PRIVATE 1 | ||||||
|  |  | ||||||
|  | #include <stdlib.h> | ||||||
|  | #include <stdio.h> | ||||||
|  | #include <stdarg.h> | ||||||
|  | #include <time.h> | ||||||
|  | #include <string.h> | ||||||
|  |  | ||||||
|  | #include <libxml/tree.h> | ||||||
|  |  | ||||||
|  | #include <xmlsec/xmlsec.h> | ||||||
|  | #include <xmlsec/xmltree.h> | ||||||
|  | #include <xmlsec/private.h> | ||||||
|  | #include <xmlsec/errors.h> | ||||||
|  |  | ||||||
|  | /* Must be bigger than fatal_error */ | ||||||
|  | #define XMLSEC_ERRORS_BUFFER_SIZE       1024 | ||||||
|  |  | ||||||
|  | /* Must fit into xmlChar[XMLSEC_ERRORS_BUFFER_SIZE] */ | ||||||
|  | static const xmlChar fatal_error[] = "Can not format error message"; | ||||||
|  |  | ||||||
|  | typedef struct _xmlSecErrorDescription                  xmlSecErrorDescription, *xmlSecErrorDescriptionPtr; | ||||||
|  | struct _xmlSecErrorDescription { | ||||||
|  |     int                 errorCode; | ||||||
|  |     const char*         errorMsg; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | static xmlSecErrorDescription xmlSecErrorsTable[XMLSEC_ERRORS_MAX_NUMBER + 1] = { | ||||||
|  |   { XMLSEC_ERRORS_R_XMLSEC_FAILED,              "xmlsec library function failed" }, | ||||||
|  |   { XMLSEC_ERRORS_R_MALLOC_FAILED,              "malloc function failed" }, | ||||||
|  |   { XMLSEC_ERRORS_R_STRDUP_FAILED,              "strdup function failed" }, | ||||||
|  |   { XMLSEC_ERRORS_R_CRYPTO_FAILED,              "crypto library function failed" }, | ||||||
|  |   { XMLSEC_ERRORS_R_XML_FAILED,                 "libxml2 library function failed" }, | ||||||
|  |   { XMLSEC_ERRORS_R_XSLT_FAILED,                "libxslt library function failed" }, | ||||||
|  |   { XMLSEC_ERRORS_R_IO_FAILED,                  "io function failed" }, | ||||||
|  |   { XMLSEC_ERRORS_R_DISABLED,                   "feature is disabled" }, | ||||||
|  |   { XMLSEC_ERRORS_R_NOT_IMPLEMENTED,            "feature is not implemented" }, | ||||||
|  |   { XMLSEC_ERRORS_R_INVALID_CONFIG,             "invalid configuration" }, | ||||||
|  |   { XMLSEC_ERRORS_R_INVALID_SIZE,               "invalid size" }, | ||||||
|  |   { XMLSEC_ERRORS_R_INVALID_DATA,               "invalid data" }, | ||||||
|  |   { XMLSEC_ERRORS_R_INVALID_RESULT,             "invalid result" }, | ||||||
|  |   { XMLSEC_ERRORS_R_INVALID_TYPE,               "invalid type" }, | ||||||
|  |   { XMLSEC_ERRORS_R_INVALID_OPERATION,          "invalid operation" }, | ||||||
|  |   { XMLSEC_ERRORS_R_INVALID_STATUS,             "invalid status" }, | ||||||
|  |   { XMLSEC_ERRORS_R_INVALID_FORMAT,             "invalid format" }, | ||||||
|  |   { XMLSEC_ERRORS_R_DATA_NOT_MATCH,             "data do not match" }, | ||||||
|  |   { XMLSEC_ERRORS_R_INVALID_VERSION,            "invalid version" }, | ||||||
|  |   { XMLSEC_ERRORS_R_INVALID_NODE,               "invalid node" }, | ||||||
|  |   { XMLSEC_ERRORS_R_INVALID_NODE_CONTENT,       "invalid node content" }, | ||||||
|  |   { XMLSEC_ERRORS_R_INVALID_NODE_ATTRIBUTE,     "invalid node attribute" }, | ||||||
|  |   { XMLSEC_ERRORS_R_MISSING_NODE_ATTRIBUTE,     "missing node attribute" }, | ||||||
|  |   { XMLSEC_ERRORS_R_NODE_ALREADY_PRESENT,       "node already present" }, | ||||||
|  |   { XMLSEC_ERRORS_R_UNEXPECTED_NODE,            "unexpected node" }, | ||||||
|  |   { XMLSEC_ERRORS_R_NODE_NOT_FOUND,             "node node found" }, | ||||||
|  |   { XMLSEC_ERRORS_R_INVALID_TRANSFORM,          "invalid transform" }, | ||||||
|  |   { XMLSEC_ERRORS_R_INVALID_TRANSFORM_KEY,      "invalid transform key" }, | ||||||
|  |   { XMLSEC_ERRORS_R_INVALID_URI_TYPE,           "invalid URI type" }, | ||||||
|  |   { XMLSEC_ERRORS_R_TRANSFORM_SAME_DOCUMENT_REQUIRED,   "same document is required for transform" }, | ||||||
|  |   { XMLSEC_ERRORS_R_TRANSFORM_DISABLED,         "transform is disabled" }, | ||||||
|  |   { XMLSEC_ERRORS_R_INVALID_KEY_DATA,           "invalid key data" }, | ||||||
|  |   { XMLSEC_ERRORS_R_KEY_DATA_NOT_FOUND,         "key data is not found" }, | ||||||
|  |   { XMLSEC_ERRORS_R_KEY_DATA_ALREADY_EXIST,     "key data already exist" }, | ||||||
|  |   { XMLSEC_ERRORS_R_INVALID_KEY_DATA_SIZE,      "invalid key data size" }, | ||||||
|  |   { XMLSEC_ERRORS_R_KEY_NOT_FOUND,              "key is not found" }, | ||||||
|  |   { XMLSEC_ERRORS_R_KEYDATA_DISABLED,           "key data is disabled" }, | ||||||
|  |   { XMLSEC_ERRORS_R_MAX_RETRIEVALS_LEVEL,       "maximum key retrieval level" }, | ||||||
|  |   { XMLSEC_ERRORS_R_MAX_RETRIEVAL_TYPE_MISMATCH,"key retrieval type mismatch" }, | ||||||
|  |   { XMLSEC_ERRORS_R_MAX_ENCKEY_LEVEL,           "maximum encrypted key level" }, | ||||||
|  |   { XMLSEC_ERRORS_R_CERT_VERIFY_FAILED,         "certificate verification failed" }, | ||||||
|  |   { XMLSEC_ERRORS_R_CERT_NOT_FOUND,             "certificate is not found" }, | ||||||
|  |   { XMLSEC_ERRORS_R_CERT_REVOKED,               "certificate is revoked" }, | ||||||
|  |   { XMLSEC_ERRORS_R_CERT_ISSUER_FAILED,         "certificate issuer check failed" }, | ||||||
|  |   { XMLSEC_ERRORS_R_CERT_NOT_YET_VALID,         "certificate is not yet valid" }, | ||||||
|  |   { XMLSEC_ERRORS_R_CERT_HAS_EXPIRED,           "certificate has expired" }, | ||||||
|  |   { XMLSEC_ERRORS_R_DSIG_NO_REFERENCES,         "Reference nodes are not found" }, | ||||||
|  |   { XMLSEC_ERRORS_R_DSIG_INVALID_REFERENCE,     "Reference verification failed" }, | ||||||
|  |   { XMLSEC_ERRORS_R_ASSERTION,                  "assertion" }, | ||||||
|  |   { 0,                                          NULL} | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | static xmlSecErrorsCallback xmlSecErrorsClbk = xmlSecErrorsDefaultCallback; | ||||||
|  | static int  xmlSecPrintErrorMessages = 1;       /* whether the error messages will be printed immediately */ | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * xmlSecErrorsInit: | ||||||
|  |  * | ||||||
|  |  * Initializes the errors reporting. It is called from #xmlSecInit function. | ||||||
|  |  * and applications must not call this function directly. | ||||||
|  |  */ | ||||||
|  | void | ||||||
|  | xmlSecErrorsInit(void) { | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * xmlSecErrorsShutdown: | ||||||
|  |  * | ||||||
|  |  * Cleanups the errors reporting. It is called from #xmlSecShutdown function. | ||||||
|  |  * and applications must not call this function directly. | ||||||
|  |  */ | ||||||
|  | void | ||||||
|  | xmlSecErrorsShutdown(void) { | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * xmlSecErrorsSetCallback: | ||||||
|  |  * @callback:           the new errors callback function. | ||||||
|  |  * | ||||||
|  |  * Sets the errors callback function to @callback that will be called | ||||||
|  |  * every time an error occurs. | ||||||
|  |  */ | ||||||
|  | void | ||||||
|  | xmlSecErrorsSetCallback(xmlSecErrorsCallback callback) { | ||||||
|  |     xmlSecErrorsClbk = callback; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * xmlSecErrorsDefaultCallback: | ||||||
|  |  * @file:               the error location file name (__FILE__ macro). | ||||||
|  |  * @line:               the error location line number (__LINE__ macro). | ||||||
|  |  * @func:               the error location function name (__FUNCTION__ macro). | ||||||
|  |  * @errorObject:        the error specific error object | ||||||
|  |  * @errorSubject:       the error specific error subject. | ||||||
|  |  * @reason:             the error code. | ||||||
|  |  * @msg:                the additional error message. | ||||||
|  |  * | ||||||
|  |  * The default error reporting callback that utilizes LibXML | ||||||
|  |  * error reporting #xmlGenericError function. | ||||||
|  |  */ | ||||||
|  | void | ||||||
|  | xmlSecErrorsDefaultCallback(const char* file, int line, const char* func, | ||||||
|  |                             const char* errorObject, const char* errorSubject, | ||||||
|  |                             int reason, const char* msg) { | ||||||
|  |     if(xmlSecPrintErrorMessages) { | ||||||
|  |         const char* error_msg = NULL; | ||||||
|  |         xmlSecSize i; | ||||||
|  |  | ||||||
|  |         for(i = 0; (i < XMLSEC_ERRORS_MAX_NUMBER) && (xmlSecErrorsGetMsg(i) != NULL); ++i) { | ||||||
|  |             if(xmlSecErrorsGetCode(i) == reason) { | ||||||
|  |                 error_msg = xmlSecErrorsGetMsg(i); | ||||||
|  |                 break; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         xmlGenericError(xmlGenericErrorContext, | ||||||
|  |             "func=%s:file=%s:line=%d:obj=%s:subj=%s:error=%d:%s:%s\n", | ||||||
|  |             (func != NULL) ? func : "unknown", | ||||||
|  |             (file != NULL) ? file : "unknown", | ||||||
|  |             line, | ||||||
|  |             (errorObject != NULL) ? errorObject : "unknown", | ||||||
|  |             (errorSubject != NULL) ? errorSubject : "unknown", | ||||||
|  |             reason, | ||||||
|  |             (error_msg != NULL) ? error_msg : "", | ||||||
|  |             (msg != NULL) ? msg : ""); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * xmlSecErrorsDefaultCallbackEnableOutput: | ||||||
|  |  * @enabled:            the flag. | ||||||
|  |  * | ||||||
|  |  * Enables or disables calling LibXML2 callback from the default | ||||||
|  |  * errors callback. | ||||||
|  |  */ | ||||||
|  | void | ||||||
|  | xmlSecErrorsDefaultCallbackEnableOutput(int enabled) { | ||||||
|  |     xmlSecPrintErrorMessages = enabled; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * xmlSecErrorsGetCode: | ||||||
|  |  * @pos:                the error position. | ||||||
|  |  * | ||||||
|  |  * Gets the known error code at position @pos. | ||||||
|  |  * | ||||||
|  |  * Returns: the known error code or 0 if @pos is greater than | ||||||
|  |  * total number of known error codes. | ||||||
|  |  */ | ||||||
|  | int | ||||||
|  | xmlSecErrorsGetCode(xmlSecSize pos) { | ||||||
|  |     /* could not use asserts here! */ | ||||||
|  |     if(pos < sizeof(xmlSecErrorsTable) / sizeof(xmlSecErrorsTable[0])) { | ||||||
|  |         return(xmlSecErrorsTable[pos].errorCode); | ||||||
|  |     } | ||||||
|  |     return(0); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * xmlSecErrorsGetMsg: | ||||||
|  |  * @pos:                the error position. | ||||||
|  |  * | ||||||
|  |  * Gets the known error message at position @pos. | ||||||
|  |  * | ||||||
|  |  * Returns: the known error message or NULL if @pos is greater than | ||||||
|  |  * total number of known error codes. | ||||||
|  |  */ | ||||||
|  | const char* | ||||||
|  | xmlSecErrorsGetMsg(xmlSecSize pos) { | ||||||
|  |     /* could not use asserts here! */ | ||||||
|  |     if(pos < sizeof(xmlSecErrorsTable) / sizeof(xmlSecErrorsTable[0])) { | ||||||
|  |         return(xmlSecErrorsTable[pos].errorMsg); | ||||||
|  |     } | ||||||
|  |     return(NULL); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * xmlSecError: | ||||||
|  |  * @file:               the error location filename (__FILE__). | ||||||
|  |  * @line:               the error location line number (__LINE__). | ||||||
|  |  * @func:               the error location function (__FUNCTION__). | ||||||
|  |  * @errorObject:        the error specific error object (e.g. transform, key data, etc). | ||||||
|  |  * @errorSubject:       the error specific error subject (e.g. failed function name). | ||||||
|  |  * @reason:             the error code. | ||||||
|  |  * @msg:                the error message in printf format. | ||||||
|  |  * @...:                the parameters for the @msg. | ||||||
|  |  * | ||||||
|  |  * Reports an error to the default (#xmlSecErrorsDefaultCallback) or | ||||||
|  |  * application specific callback installed using #xmlSecErrorsSetCallback | ||||||
|  |  * function. | ||||||
|  |  */ | ||||||
|  | void | ||||||
|  | xmlSecError(const char* file, int line, const char* func, | ||||||
|  |             const char* errorObject, const char* errorSubject, | ||||||
|  |             int reason, const char* msg, ...) { | ||||||
|  |     if(xmlSecErrorsClbk != NULL) { | ||||||
|  |         xmlChar error_msg[XMLSEC_ERRORS_BUFFER_SIZE]; | ||||||
|  |         int ret; | ||||||
|  |  | ||||||
|  |         if(msg != NULL) { | ||||||
|  |             va_list va; | ||||||
|  |  | ||||||
|  |             va_start(va, msg); | ||||||
|  |             ret = xmlStrVPrintf(error_msg, sizeof(error_msg), msg, va); | ||||||
|  |             if(ret < 0) { | ||||||
|  |                 /* Can't really report an error from an error callback */ | ||||||
|  |                 memcpy(error_msg, fatal_error, sizeof(fatal_error)); | ||||||
|  |             } | ||||||
|  |             error_msg[sizeof(error_msg) - 1] = '\0'; /* just in case */ | ||||||
|  |             va_end(va); | ||||||
|  |         } else { | ||||||
|  |             error_msg[0] = '\0'; | ||||||
|  |         } | ||||||
|  |         xmlSecErrorsClbk(file, line, func, errorObject, errorSubject, reason, (char*)error_msg); | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										869
									
								
								experimental/facho-signer/src/xmlsec1/errors_helpers.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										869
									
								
								experimental/facho-signer/src/xmlsec1/errors_helpers.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,869 @@ | |||||||
|  | /* | ||||||
|  |  * XML Security Library (http://www.aleksey.com/xmlsec). | ||||||
|  |  * | ||||||
|  |  * Internal header only used during the compilation, | ||||||
|  |  * | ||||||
|  |  * This is free software; see Copyright file in the source | ||||||
|  |  * distribution for preciese wording. | ||||||
|  |  * | ||||||
|  |  * Copyright (C) 2002-2016 Aleksey Sanin <aleksey@aleksey.com>. All Rights Reserved. | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | #ifndef __XMLSEC_ERROR_HELPERS_H__ | ||||||
|  | #define __XMLSEC_ERROR_HELPERS_H__ | ||||||
|  |  | ||||||
|  | #include <errno.h> | ||||||
|  | #include <xmlsec/errors.h> | ||||||
|  |  | ||||||
|  | #ifdef __cplusplus | ||||||
|  | extern "C" { | ||||||
|  | #endif /* __cplusplus */ | ||||||
|  |  | ||||||
|  | /********************************************************************** | ||||||
|  |  * | ||||||
|  |  * Error handling macros. | ||||||
|  |  * | ||||||
|  |  **********************************************************************/ | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * xmlSecInternalError: | ||||||
|  |  * @errorFunction:      the failed function name. | ||||||
|  |  * @errorObject:        the error specific error object (e.g. transform, key data, etc). | ||||||
|  |  * | ||||||
|  |  * Macro. The XMLSec library macro for reporting internal XMLSec errors. | ||||||
|  |  */ | ||||||
|  | #define xmlSecInternalError(errorFunction, errorObject) \ | ||||||
|  |         xmlSecError(XMLSEC_ERRORS_HERE,                     \ | ||||||
|  |                     (const char*)(errorObject),             \ | ||||||
|  |                     (errorFunction),                        \ | ||||||
|  |                     XMLSEC_ERRORS_R_XMLSEC_FAILED,          \ | ||||||
|  |                     XMLSEC_ERRORS_NO_MESSAGE                \ | ||||||
|  |         ) | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * xmlSecInternalError2: | ||||||
|  |  * @errorFunction:      the failed function name. | ||||||
|  |  * @errorObject:        the error specific error object (e.g. transform, key data, etc). | ||||||
|  |  * @msg:                the extra message. | ||||||
|  |  * @param:              the extra message param. | ||||||
|  |  * | ||||||
|  |  * Macro. The XMLSec library macro for reporting internal XMLSec errors. | ||||||
|  |  */ | ||||||
|  | #define xmlSecInternalError2(errorFunction, errorObject, msg, param) \ | ||||||
|  |         xmlSecError(XMLSEC_ERRORS_HERE,                     \ | ||||||
|  |                     (const char*)(errorObject),             \ | ||||||
|  |                     (errorFunction),                        \ | ||||||
|  |                     XMLSEC_ERRORS_R_XMLSEC_FAILED,          \ | ||||||
|  |                     (msg), (param)                          \ | ||||||
|  |         ) | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * xmlSecInternalError3: | ||||||
|  |  * @errorFunction:      the failed function name. | ||||||
|  |  * @errorObject:        the error specific error object (e.g. transform, key data, etc). | ||||||
|  |  * @msg:                the extra message. | ||||||
|  |  * @param1:             the extra message param1. | ||||||
|  |  * @param2:             the extra message param2. | ||||||
|  |  * | ||||||
|  |  * Macro. The XMLSec library macro for reporting internal XMLSec errors. | ||||||
|  |  */ | ||||||
|  | #define xmlSecInternalError3(errorFunction, errorObject, msg, param1, param2) \ | ||||||
|  |         xmlSecError(XMLSEC_ERRORS_HERE,                     \ | ||||||
|  |                     (const char*)(errorObject),             \ | ||||||
|  |                     (errorFunction),                        \ | ||||||
|  |                     XMLSEC_ERRORS_R_XMLSEC_FAILED,          \ | ||||||
|  |                     (msg), (param1), (param2)               \ | ||||||
|  |         ) | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * xmlSecInternalError4: | ||||||
|  |  * @errorFunction:      the failed function name. | ||||||
|  |  * @errorObject:        the error specific error object (e.g. transform, key data, etc). | ||||||
|  |  * @msg:                the extra message. | ||||||
|  |  * @param1:             the extra message param1. | ||||||
|  |  * @param2:             the extra message param2. | ||||||
|  |  * @param3:             the extra message param3. | ||||||
|  |  * | ||||||
|  |  * Macro. The XMLSec library macro for reporting internal XMLSec errors. | ||||||
|  |  */ | ||||||
|  | #define xmlSecInternalError4(errorFunction, errorObject, msg, param1, param2, param3) \ | ||||||
|  |         xmlSecError(XMLSEC_ERRORS_HERE,                     \ | ||||||
|  |                     (const char*)(errorObject),             \ | ||||||
|  |                     (errorFunction),                        \ | ||||||
|  |                     XMLSEC_ERRORS_R_XMLSEC_FAILED,          \ | ||||||
|  |                     (msg), (param1), (param2), (param3)     \ | ||||||
|  |         ) | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * xmlSecMallocError: | ||||||
|  |  * @allocSize:          the failed allocation size. | ||||||
|  |  * @errorObject:        the error specific error object (e.g. transform, key data, etc). | ||||||
|  |  * | ||||||
|  |  * Macro. The XMLSec library macro for reporting xmlMalloc() errors. | ||||||
|  |  */ | ||||||
|  | #define xmlSecMallocError(allocSize, errorObject) \ | ||||||
|  |         xmlSecError(XMLSEC_ERRORS_HERE,                     \ | ||||||
|  |                     (const char*)(errorObject),             \ | ||||||
|  |                     "xmlMalloc",                            \ | ||||||
|  |                     XMLSEC_ERRORS_R_MALLOC_FAILED,          \ | ||||||
|  |                     "size=%lu", (unsigned long)(allocSize)  \ | ||||||
|  |         ) | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * xmlSecStrdupError: | ||||||
|  |  * @str:                the failed string. | ||||||
|  |  * @errorObject:        the error specific error object (e.g. transform, key data, etc). | ||||||
|  |  * | ||||||
|  |  * Macro. The XMLSec library macro for reporting xmlStrdup() errors. | ||||||
|  |  */ | ||||||
|  | #define xmlSecStrdupError(str, errorObject) \ | ||||||
|  |         xmlSecError(XMLSEC_ERRORS_HERE,                     \ | ||||||
|  |                     (const char*)(errorObject),             \ | ||||||
|  |                     "xmlStrdup",                            \ | ||||||
|  |                     XMLSEC_ERRORS_R_STRDUP_FAILED,          \ | ||||||
|  |                     "size=%lu", (unsigned long)xmlStrlen(str) \ | ||||||
|  |         ) | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * xmlSecXmlError: | ||||||
|  |  * @errorFunction:      the failed function. | ||||||
|  |  * @errorObject:        the error specific error object (e.g. transform, key data, etc). | ||||||
|  |  * | ||||||
|  |  * Macro. The XMLSec library macro for reporting generic XML errors. | ||||||
|  |  */ | ||||||
|  | #define xmlSecXmlError(errorFunction, errorObject) \ | ||||||
|  |     {                                                 \ | ||||||
|  |         xmlErrorPtr error = xmlGetLastError();        \ | ||||||
|  |         int code = (error != NULL) ? error->code : 0; \ | ||||||
|  |         const char* message = (error != NULL) ? error->message : NULL; \ | ||||||
|  |         xmlSecError(XMLSEC_ERRORS_HERE,               \ | ||||||
|  |                    (const char*)(errorObject),        \ | ||||||
|  |                    (errorFunction),                   \ | ||||||
|  |                    XMLSEC_ERRORS_R_XML_FAILED,        \ | ||||||
|  |                    "xml error: %lu: %s",              \ | ||||||
|  |                    (unsigned long)code,               \ | ||||||
|  |                    xmlSecErrorsSafeString(message)    \ | ||||||
|  |         );                                            \ | ||||||
|  |     } | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * xmlSecXmlError2: | ||||||
|  |  * @errorFunction:      the failed function. | ||||||
|  |  * @errorObject:        the error specific error object (e.g. transform, key data, etc). | ||||||
|  |  * @msg:                the extra message. | ||||||
|  |  * @param:              the extra message param. | ||||||
|  |  * | ||||||
|  |  * Macro. The XMLSec library macro for reporting generic XML errors. | ||||||
|  |  */ | ||||||
|  | #define xmlSecXmlError2(errorFunction, errorObject, msg, param) \ | ||||||
|  |     {                                                 \ | ||||||
|  |         xmlErrorPtr error = xmlGetLastError();        \ | ||||||
|  |         int code = (error != NULL) ? error->code : 0; \ | ||||||
|  |         const char* message = (error != NULL) ? error->message : NULL; \ | ||||||
|  |         xmlSecError(XMLSEC_ERRORS_HERE,               \ | ||||||
|  |                    (const char*)(errorObject),        \ | ||||||
|  |                    (errorFunction),                   \ | ||||||
|  |                    XMLSEC_ERRORS_R_XML_FAILED,        \ | ||||||
|  |                    msg "; xml error: %lu: %s",        \ | ||||||
|  |                    (param),                           \ | ||||||
|  |                    (unsigned long)code,               \ | ||||||
|  |                    xmlSecErrorsSafeString(message)    \ | ||||||
|  |         );                                            \ | ||||||
|  |     } | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * xmlSecXmlParserError: | ||||||
|  |  * @errorFunction:      the failed function. | ||||||
|  |  * @ctxt:               the parser context. | ||||||
|  |  * @errorObject:        the error specific error object (e.g. transform, key data, etc). | ||||||
|  |  * | ||||||
|  |  * Macro. The XMLSec library macro for reporting XML parser errors. | ||||||
|  |  */ | ||||||
|  | #define xmlSecXmlParserError(errorFunction, ctxt, errorObject) \ | ||||||
|  |     {                                                 \ | ||||||
|  |         xmlErrorPtr error = xmlCtxtGetLastError(ctxt);\ | ||||||
|  |         int code = (error != NULL) ? error->code : 0; \ | ||||||
|  |         const char* message = (error != NULL) ? error->message : NULL; \ | ||||||
|  |         xmlSecError(XMLSEC_ERRORS_HERE,               \ | ||||||
|  |                    (const char*)(errorObject),        \ | ||||||
|  |                    (errorFunction),                   \ | ||||||
|  |                    XMLSEC_ERRORS_R_XML_FAILED,        \ | ||||||
|  |                    "xml error: %lu: %s",              \ | ||||||
|  |                    (unsigned long)code,               \ | ||||||
|  |                    xmlSecErrorsSafeString(message)    \ | ||||||
|  |         );                                            \ | ||||||
|  |     } | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * xmlSecXmlParserError2: | ||||||
|  |  * @errorFunction:      the failed function. | ||||||
|  |  * @ctxt:               the parser context. | ||||||
|  |  * @errorObject:        the error specific error object (e.g. transform, key data, etc). | ||||||
|  |  * @msg:                the extra message. | ||||||
|  |  * @param:              the extra message param. | ||||||
|  |  * | ||||||
|  |  * Macro. The XMLSec library macro for reporting XML parser errors. | ||||||
|  |  */ | ||||||
|  | #define xmlSecXmlParserError2(errorFunction, ctxt, errorObject, msg, param) \ | ||||||
|  |     {                                                 \ | ||||||
|  |         xmlErrorPtr error = xmlCtxtGetLastError(ctxt);\ | ||||||
|  |         int code = (error != NULL) ? error->code : 0; \ | ||||||
|  |         const char* message = (error != NULL) ? error->message : NULL; \ | ||||||
|  |         xmlSecError(XMLSEC_ERRORS_HERE,               \ | ||||||
|  |                    (const char*)(errorObject),        \ | ||||||
|  |                    (errorFunction),                   \ | ||||||
|  |                    XMLSEC_ERRORS_R_XML_FAILED,        \ | ||||||
|  |                    msg "; xml error: %lu: %s",        \ | ||||||
|  |                    (param),                           \ | ||||||
|  |                    (unsigned long)code,               \ | ||||||
|  |                    xmlSecErrorsSafeString(message)    \ | ||||||
|  |         );                                            \ | ||||||
|  |     } | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * xmlSecXsltError: | ||||||
|  |  * @errorFunction:      the failed function. | ||||||
|  |  * @ctxt:               the parser context. | ||||||
|  |  * @errorObject:        the error specific error object (e.g. transform, key data, etc). | ||||||
|  |  * | ||||||
|  |  * Macro. The XMLSec library macro for reporting XSLT errors. | ||||||
|  |  */ | ||||||
|  | #define xmlSecXsltError(errorFunction, ctxt, errorObject) \ | ||||||
|  |     {                                                 \ | ||||||
|  |         xmlErrorPtr error = xmlGetLastError();        \ | ||||||
|  |         int code = (error != NULL) ? error->code : 0; \ | ||||||
|  |         const char* message = (error != NULL) ? error->message : NULL; \ | ||||||
|  |         xmlSecError(XMLSEC_ERRORS_HERE,               \ | ||||||
|  |                    (const char*)(errorObject),        \ | ||||||
|  |                    (errorFunction),                   \ | ||||||
|  |                    XMLSEC_ERRORS_R_XSLT_FAILED,       \ | ||||||
|  |                    "xslt error: %lu: %s",             \ | ||||||
|  |                    (unsigned long)code,               \ | ||||||
|  |                    xmlSecErrorsSafeString(message)    \ | ||||||
|  |         );                                            \ | ||||||
|  |     } | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * xmlSecIOError: | ||||||
|  |  * @errorFunction:      the failed function. | ||||||
|  |  * @name:               the filename, function name, uri, etc. | ||||||
|  |  * @errorObject:        the error specific error object (e.g. transform, key data, etc). | ||||||
|  |  * | ||||||
|  |  * Macro. The XMLSec library macro for reporting IO errors. | ||||||
|  |  */ | ||||||
|  | #define xmlSecIOError(errorFunction, name, errorObject) \ | ||||||
|  |     {                                                 \ | ||||||
|  |         xmlSecError(XMLSEC_ERRORS_HERE,               \ | ||||||
|  |                    (const char*)(errorObject),        \ | ||||||
|  |                    (errorFunction),                   \ | ||||||
|  |                    XMLSEC_ERRORS_R_IO_FAILED,         \ | ||||||
|  |                    "name=\"%s\"; errno=%d",           \ | ||||||
|  |                    xmlSecErrorsSafeString(name),      \ | ||||||
|  |                    errno                              \ | ||||||
|  |         );                                            \ | ||||||
|  |     } | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * xmlSecNotImplementedError: | ||||||
|  |  * @details:           the additional details. | ||||||
|  |  * | ||||||
|  |  * Macro. The XMLSec library macro for reporting "not implemented" errors. | ||||||
|  |  */ | ||||||
|  | #define xmlSecNotImplementedError(details) \ | ||||||
|  |         xmlSecError(XMLSEC_ERRORS_HERE,                     \ | ||||||
|  |                     NULL,                                   \ | ||||||
|  |                     NULL,                                   \ | ||||||
|  |                     XMLSEC_ERRORS_R_NOT_IMPLEMENTED,        \ | ||||||
|  |                     "details=%s",                           \ | ||||||
|  |                     xmlSecErrorsSafeString(details)         \ | ||||||
|  |         ) | ||||||
|  | /** | ||||||
|  |  * xmlSecInvalidSizeError: | ||||||
|  |  * @name:               the name of the variable, parameter, etc. | ||||||
|  |  * @actual:             the actual value. | ||||||
|  |  * @expected:           the expected value. | ||||||
|  |  * @errorObject:        the error specific error object (e.g. transform, key data, etc). | ||||||
|  |  * | ||||||
|  |  * Macro. The XMLSec library macro for reporting "invalid size" errors when | ||||||
|  |  * we expect exact match. | ||||||
|  |  */ | ||||||
|  | #define xmlSecInvalidSizeError(name, actual, expected, errorObject) \ | ||||||
|  |         xmlSecError(XMLSEC_ERRORS_HERE,                     \ | ||||||
|  |                     (const char*)(errorObject),             \ | ||||||
|  |                     NULL,                                   \ | ||||||
|  |                     XMLSEC_ERRORS_R_INVALID_SIZE,           \ | ||||||
|  |                     "invalid size for '%s': actual=%lu is not equal to expected=%lu", \ | ||||||
|  |                     xmlSecErrorsSafeString(name),           \ | ||||||
|  |                     (unsigned long)(actual),                \ | ||||||
|  |                     (unsigned long)(expected)               \ | ||||||
|  |         ) | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * xmlSecInvalidSizeLessThanError: | ||||||
|  |  * @name:               the name of the variable, parameter, etc. | ||||||
|  |  * @actual:             the actual value. | ||||||
|  |  * @expected:           the expected value. | ||||||
|  |  * @errorObject:        the error specific error object (e.g. transform, key data, etc). | ||||||
|  |  * | ||||||
|  |  * Macro. The XMLSec library macro for reporting "invalid size" errors when | ||||||
|  |  * we expect at least the expected size. | ||||||
|  |  */ | ||||||
|  | #define xmlSecInvalidSizeLessThanError(name, actual, expected, errorObject) \ | ||||||
|  |         xmlSecError(XMLSEC_ERRORS_HERE,                     \ | ||||||
|  |                     (const char*)(errorObject),             \ | ||||||
|  |                     NULL,                                   \ | ||||||
|  |                     XMLSEC_ERRORS_R_INVALID_SIZE,           \ | ||||||
|  |                     "invalid size for '%s': actual=%lu is less than expected=%lu", \ | ||||||
|  |                     xmlSecErrorsSafeString(name),           \ | ||||||
|  |                     (unsigned long)(actual),                \ | ||||||
|  |                     (unsigned long)(expected)               \ | ||||||
|  |         ) | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * xmlSecInvalidSizeMoreThanError: | ||||||
|  |  * @name:               the name of the variable, parameter, etc. | ||||||
|  |  * @actual:             the actual value. | ||||||
|  |  * @expected:           the expected value. | ||||||
|  |  * @errorObject:        the error specific error object (e.g. transform, key data, etc). | ||||||
|  |  * | ||||||
|  |  * Macro. The XMLSec library macro for reporting "invalid size" errors when | ||||||
|  |  * we expect at most the expected size. | ||||||
|  |  */ | ||||||
|  | #define xmlSecInvalidSizeMoreThanError(name, actual, expected, errorObject) \ | ||||||
|  |         xmlSecError(XMLSEC_ERRORS_HERE,                     \ | ||||||
|  |                     (const char*)(errorObject),             \ | ||||||
|  |                     NULL,                                   \ | ||||||
|  |                     XMLSEC_ERRORS_R_NOT_IMPLEMENTED,        \ | ||||||
|  |                     "invalid size for '%s': actual=%lu is more than expected=%lu", \ | ||||||
|  |                     xmlSecErrorsSafeString(name),           \ | ||||||
|  |                     (unsigned long)(actual),                \ | ||||||
|  |                     (unsigned long)(expected)               \ | ||||||
|  |         ) | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * xmlSecInvalidSizeNotMultipleOfError: | ||||||
|  |  * @name:               the name of the variable, parameter, etc. | ||||||
|  |  * @actual:             the actual value. | ||||||
|  |  * @divider:            the expected divider. | ||||||
|  |  * @errorObject:        the error specific error object (e.g. transform, key data, etc). | ||||||
|  |  * | ||||||
|  |  * Macro. The XMLSec library macro for reporting "invalid size" errors when | ||||||
|  |  * we expect the size to be a multiple of the divider. | ||||||
|  |  */ | ||||||
|  | #define xmlSecInvalidSizeNotMultipleOfError(name, actual, divider, errorObject) \ | ||||||
|  |         xmlSecError(XMLSEC_ERRORS_HERE,                     \ | ||||||
|  |                     (const char*)(errorObject),             \ | ||||||
|  |                     NULL,                                   \ | ||||||
|  |                     XMLSEC_ERRORS_R_NOT_IMPLEMENTED,        \ | ||||||
|  |                     "invalid size for '%s': actual=%lu is not a multiple of %lu", \ | ||||||
|  |                     xmlSecErrorsSafeString(name),           \ | ||||||
|  |                     (unsigned long)(actual),                \ | ||||||
|  |                     (unsigned long)(divider)               \ | ||||||
|  |         ) | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * xmlSecInvalidSizeOtherError: | ||||||
|  |  * @msg:                the message about the error. | ||||||
|  |  * @errorObject:        the error specific error object (e.g. transform, key data, etc). | ||||||
|  |  * | ||||||
|  |  * Macro. The XMLSec library macro for reporting "invalid size" errors when | ||||||
|  |  * we expect exact match. | ||||||
|  |  */ | ||||||
|  | #define xmlSecInvalidSizeOtherError(msg, errorObject) \ | ||||||
|  |         xmlSecError(XMLSEC_ERRORS_HERE,                     \ | ||||||
|  |                     (const char*)(errorObject),             \ | ||||||
|  |                     NULL,                                   \ | ||||||
|  |                     XMLSEC_ERRORS_R_INVALID_SIZE,           \ | ||||||
|  |                     "invalid size: %s",                     \ | ||||||
|  |                     xmlSecErrorsSafeString(msg)             \ | ||||||
|  |         ) | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * xmlSecInvalidDataError: | ||||||
|  |  * @msg:                the msg with explanation. | ||||||
|  |  * @errorObject:        the error specific error object (e.g. transform, key data, etc). | ||||||
|  |  * | ||||||
|  |  * Macro. The XMLSec library macro for reporting "invalid data" errors. | ||||||
|  |  */ | ||||||
|  | #define xmlSecInvalidDataError(msg, errorObject) \ | ||||||
|  |         xmlSecError(XMLSEC_ERRORS_HERE,                     \ | ||||||
|  |                     (const char*)(errorObject),             \ | ||||||
|  |                     NULL,                                   \ | ||||||
|  |                     XMLSEC_ERRORS_R_INVALID_DATA,           \ | ||||||
|  |                     "%s",                                   \ | ||||||
|  |                     xmlSecErrorsSafeString(msg)             \ | ||||||
|  |         ) | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * xmlSecInvalidStringDataError: | ||||||
|  |  * @name:               the name of the variable, parameter, etc. | ||||||
|  |  * @actual:             the actual value as a string. | ||||||
|  |  * @expected:           the expected value(s) as a string. | ||||||
|  |  * @errorObject:        the error specific error object (e.g. transform, key data, etc). | ||||||
|  |  * | ||||||
|  |  * Macro. The XMLSec library macro for reporting "invalid data" errors for string. | ||||||
|  |  */ | ||||||
|  | #define xmlSecInvalidStringDataError(name, actual, expected, errorObject) \ | ||||||
|  |         xmlSecError(XMLSEC_ERRORS_HERE,                     \ | ||||||
|  |                     (const char*)(errorObject),             \ | ||||||
|  |                     NULL,                                   \ | ||||||
|  |                     XMLSEC_ERRORS_R_INVALID_DATA,           \ | ||||||
|  |                     "invalid data for '%s': actual='%s' and expected %s", \ | ||||||
|  |                     xmlSecErrorsSafeString(name),           \ | ||||||
|  |                     xmlSecErrorsSafeString(actual),         \ | ||||||
|  |                     (expected)                              \ | ||||||
|  |         ) | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * xmlSecInvalidIntegerDataError: | ||||||
|  |  * @name:               the name of the variable, parameter, etc. | ||||||
|  |  * @actual:             the actual value as an integer. | ||||||
|  |  * @expected:           the expected value(s) as a string. | ||||||
|  |  * @errorObject:        the error specific error object (e.g. transform, key data, etc). | ||||||
|  |  * | ||||||
|  |  * Macro. The XMLSec library macro for reporting "invalid data" errors for integers. | ||||||
|  |  */ | ||||||
|  | #define xmlSecInvalidIntegerDataError(name, actual, expected, errorObject) \ | ||||||
|  |         xmlSecError(XMLSEC_ERRORS_HERE,                     \ | ||||||
|  |                     (const char*)(errorObject),             \ | ||||||
|  |                     NULL,                                   \ | ||||||
|  |                     XMLSEC_ERRORS_R_INVALID_DATA,           \ | ||||||
|  |                     "invalid data for '%s': actual=%ld and expected %s", \ | ||||||
|  |                     xmlSecErrorsSafeString(name),           \ | ||||||
|  |                     (unsigned long)(actual),                \ | ||||||
|  |                     (expected)                              \ | ||||||
|  |         ) | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * xmlSecInvalidIntegerDataError2: | ||||||
|  |  * @name1:              the name of the first variable, parameter, etc. | ||||||
|  |  * @actual1:            the actual first value as an integer. | ||||||
|  |  * @name2:              the name of the second variable, parameter, etc. | ||||||
|  |  * @actual2:            the actual second value as an integer. | ||||||
|  |  * @expected:           the expected value(s) as a string. | ||||||
|  |  * @errorObject:        the error specific error object (e.g. transform, key data, etc). | ||||||
|  |  * | ||||||
|  |  * Macro. The XMLSec library macro for reporting "invalid data" errors for integers. | ||||||
|  |  */ | ||||||
|  | #define xmlSecInvalidIntegerDataError2(name1, actual1, name2, actual2, expected, errorObject) \ | ||||||
|  |         xmlSecError(XMLSEC_ERRORS_HERE,                     \ | ||||||
|  |                     (const char*)(errorObject),             \ | ||||||
|  |                     NULL,                                   \ | ||||||
|  |                     XMLSEC_ERRORS_R_INVALID_DATA,           \ | ||||||
|  |                     "invalid data: actual value '%s'=%ld, actual value '%s'=%ld and expected %s", \ | ||||||
|  |                     xmlSecErrorsSafeString(name1),          \ | ||||||
|  |                     (unsigned long)(actual1),               \ | ||||||
|  |                     xmlSecErrorsSafeString(name2),          \ | ||||||
|  |                     (unsigned long)(actual2),               \ | ||||||
|  |                     (expected)                              \ | ||||||
|  |         ) | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * xmlSecInvalidTypeError: | ||||||
|  |  * @msg:                the msg with explanation. | ||||||
|  |  * @errorObject:        the error specific error object (e.g. transform, key data, etc). | ||||||
|  |  * | ||||||
|  |  * Macro. The XMLSec library macro for reporting "invalid type" errors. | ||||||
|  |  */ | ||||||
|  | #define xmlSecInvalidTypeError(msg, errorObject) \ | ||||||
|  |         xmlSecError(XMLSEC_ERRORS_HERE,                     \ | ||||||
|  |                     (const char*)(errorObject),             \ | ||||||
|  |                     NULL,                                   \ | ||||||
|  |                     XMLSEC_ERRORS_R_INVALID_TYPE,           \ | ||||||
|  |                     "%s",                                   \ | ||||||
|  |                     xmlSecErrorsSafeString(msg)             \ | ||||||
|  |         ) | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * xmlSecInvalidStringTypeError: | ||||||
|  |  * @name:               the name of the variable, parameter, etc. | ||||||
|  |  * @actual:             the actual value as a string. | ||||||
|  |  * @expected:           the expected value(s) as a string. | ||||||
|  |  * @errorObject:        the error specific error object (e.g. transform, key data, etc). | ||||||
|  |  * | ||||||
|  |  * Macro. The XMLSec library macro for reporting "invalid type" errors for string. | ||||||
|  |  */ | ||||||
|  | #define xmlSecInvalidStringTypeError(name, actual, expected, errorObject) \ | ||||||
|  |         xmlSecError(XMLSEC_ERRORS_HERE,                     \ | ||||||
|  |                     (const char*)(errorObject),             \ | ||||||
|  |                     NULL,                                   \ | ||||||
|  |                     XMLSEC_ERRORS_R_INVALID_TYPE,           \ | ||||||
|  |                     "invalid type for '%s': actual='%s' and expected %s", \ | ||||||
|  |                     xmlSecErrorsSafeString(name),           \ | ||||||
|  |                     xmlSecErrorsSafeString(actual),         \ | ||||||
|  |                     (expected)                              \ | ||||||
|  |         ) | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * xmlSecInvalidIntegerTypeError: | ||||||
|  |  * @name:               the name of the variable, parameter, etc. | ||||||
|  |  * @actual:             the actual value as an integer. | ||||||
|  |  * @expected:           the expected value(s) as a string. | ||||||
|  |  * @errorObject:        the error specific error object (e.g. transform, key data, etc). | ||||||
|  |  * | ||||||
|  |  * Macro. The XMLSec library macro for reporting "invalid type" errors for integers. | ||||||
|  |  */ | ||||||
|  | #define xmlSecInvalidIntegerTypeError(name, actual, expected, errorObject) \ | ||||||
|  |         xmlSecError(XMLSEC_ERRORS_HERE,                     \ | ||||||
|  |                     (const char*)(errorObject),             \ | ||||||
|  |                     NULL,                                   \ | ||||||
|  |                     XMLSEC_ERRORS_R_INVALID_TYPE,           \ | ||||||
|  |                     "invalid type for '%s': actual=%ld and expected %s", \ | ||||||
|  |                     xmlSecErrorsSafeString(name),           \ | ||||||
|  |                     (unsigned long)(actual),                \ | ||||||
|  |                     (expected)                              \ | ||||||
|  |         ) | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * xmlSecInvalidIntegerTypeError2: | ||||||
|  |  * @name1:              the name of the first variable, parameter, etc. | ||||||
|  |  * @actual1:            the actual first value as an integer. | ||||||
|  |  * @name2:              the name of the second variable, parameter, etc. | ||||||
|  |  * @actual2:            the actual second value as an integer. | ||||||
|  |  * @expected:           the expected value(s) as a string. | ||||||
|  |  * @errorObject:        the error specific error object (e.g. transform, key data, etc). | ||||||
|  |  * | ||||||
|  |  * Macro. The XMLSec library macro for reporting "invalid type" errors for integers. | ||||||
|  |  */ | ||||||
|  | #define xmlSecInvalidIntegerTypeError2(name1, actual1, name2, actual2, expected, errorObject) \ | ||||||
|  |         xmlSecError(XMLSEC_ERRORS_HERE,                     \ | ||||||
|  |                     (const char*)(errorObject),             \ | ||||||
|  |                     NULL,                                   \ | ||||||
|  |                     XMLSEC_ERRORS_R_INVALID_TYPE,           \ | ||||||
|  |                     "invalid type: actual value '%s'=%ld, actual value '%s'=%ld and expected %s", \ | ||||||
|  |                     xmlSecErrorsSafeString(name1),          \ | ||||||
|  |                     (unsigned long)(actual1),               \ | ||||||
|  |                     xmlSecErrorsSafeString(name2),          \ | ||||||
|  |                     (unsigned long)(actual2),               \ | ||||||
|  |                     (expected)                              \ | ||||||
|  |         ) | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * xmlSecInvalidNodeError: | ||||||
|  |  * @actualNode:         the actual node. | ||||||
|  |  * @expectedNodeName:   the expected node name. | ||||||
|  |  * @errorObject:        the error specific error object (e.g. transform, key data, etc). | ||||||
|  |  * | ||||||
|  |  * Macro. The XMLSec library macro for reporting an invalid node errors. | ||||||
|  |  */ | ||||||
|  | #define xmlSecInvalidNodeError(actualNode, expectedNodeName, errorObject) \ | ||||||
|  |     {                                                 \ | ||||||
|  |         const char* actualNodeName = xmlSecNodeGetName(actualNode); \ | ||||||
|  |         xmlSecError(XMLSEC_ERRORS_HERE,               \ | ||||||
|  |                    (const char*)(errorObject),        \ | ||||||
|  |                    NULL,                              \ | ||||||
|  |                    XMLSEC_ERRORS_R_INVALID_NODE,      \ | ||||||
|  |                    "actual=%s; expected=%s",          \ | ||||||
|  |                    xmlSecErrorsSafeString(actualNodeName),  \ | ||||||
|  |                    xmlSecErrorsSafeString(expectedNodeName) \ | ||||||
|  |         );                                            \ | ||||||
|  |     } | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * xmlSecInvalidNodeContentError: | ||||||
|  |  * @node:               the node. | ||||||
|  |  * @errorObject:        the error specific error object (e.g. transform, key data, etc). | ||||||
|  |  * @reason:             the reason why node content is invalid. | ||||||
|  |  * | ||||||
|  |  * Macro. The XMLSec library macro for reporting an invalid node content errors. | ||||||
|  |  */ | ||||||
|  | #define xmlSecInvalidNodeContentError(node, errorObject, reason) \ | ||||||
|  |     {                                                 \ | ||||||
|  |         const char* nName = xmlSecNodeGetName(node);  \ | ||||||
|  |         xmlSecError(XMLSEC_ERRORS_HERE,               \ | ||||||
|  |                    (const char*)(errorObject),        \ | ||||||
|  |                    NULL,                              \ | ||||||
|  |                    XMLSEC_ERRORS_R_INVALID_NODE_CONTENT, \ | ||||||
|  |                    "node=%s; reason=%s",              \ | ||||||
|  |                    xmlSecErrorsSafeString(nName),     \ | ||||||
|  |                    xmlSecErrorsSafeString(reason)     \ | ||||||
|  |         );                                            \ | ||||||
|  |     } | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * xmlSecInvalidNodeAttributeError: | ||||||
|  |  * @node:               the node. | ||||||
|  |  * @attrName:           the attribute name. | ||||||
|  |  * @errorObject:        the error specific error object (e.g. transform, key data, etc). | ||||||
|  |  * @reason:             the reason why node content is invalid. | ||||||
|  |  * | ||||||
|  |  * Macro. The XMLSec library macro for reporting an invalid node attribute errors. | ||||||
|  |  */ | ||||||
|  | #define xmlSecInvalidNodeAttributeError(node, attrName, errorObject, reason) \ | ||||||
|  |     {                                                 \ | ||||||
|  |         const char* nName = xmlSecNodeGetName(node);  \ | ||||||
|  |         xmlSecError(XMLSEC_ERRORS_HERE,               \ | ||||||
|  |                    (const char*)(errorObject),        \ | ||||||
|  |                    NULL,                              \ | ||||||
|  |                    XMLSEC_ERRORS_R_INVALID_NODE_ATTRIBUTE, \ | ||||||
|  |                    "node=%s; attribute=%s; reason=%s",\ | ||||||
|  |                    xmlSecErrorsSafeString(nName),     \ | ||||||
|  |                    xmlSecErrorsSafeString(attrName),  \ | ||||||
|  |                    xmlSecErrorsSafeString(reason)     \ | ||||||
|  |         );                                            \ | ||||||
|  |     } | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * xmlSecNodeAlreadyPresentError: | ||||||
|  |  * @parent:             the parent node. | ||||||
|  |  * @nodeName:           the node name. | ||||||
|  |  * @errorObject:        the error specific error object (e.g. transform, key data, etc). | ||||||
|  |  * | ||||||
|  |  * Macro. The XMLSec library macro for reporting node already present errors. | ||||||
|  |  */ | ||||||
|  | #define xmlSecNodeAlreadyPresentError(parent, nodeName, errorObject) \ | ||||||
|  |     {                                                 \ | ||||||
|  |         const char* pName = xmlSecNodeGetName(parent);\ | ||||||
|  |         xmlSecError(XMLSEC_ERRORS_HERE,               \ | ||||||
|  |                    (const char*)(errorObject),        \ | ||||||
|  |                    NULL,                              \ | ||||||
|  |                    XMLSEC_ERRORS_R_NODE_ALREADY_PRESENT, \ | ||||||
|  |                    "parent=%s; node=%s",              \ | ||||||
|  |                    xmlSecErrorsSafeString(pName),     \ | ||||||
|  |                    xmlSecErrorsSafeString(nodeName)   \ | ||||||
|  |         );                                            \ | ||||||
|  |     } | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * xmlSecUnexpectedNodeError: | ||||||
|  |  * @node:               the node. | ||||||
|  |  * @errorObject:        the error specific error object (e.g. transform, key data, etc). | ||||||
|  |  * | ||||||
|  |  * Macro. The XMLSec library macro for reporting an invalid node errors. | ||||||
|  |  */ | ||||||
|  | #define xmlSecUnexpectedNodeError(node, errorObject) \ | ||||||
|  |     {                                                 \ | ||||||
|  |         const char* nName = xmlSecNodeGetName(node);  \ | ||||||
|  |         xmlSecError(XMLSEC_ERRORS_HERE,               \ | ||||||
|  |                    (const char*)(errorObject),        \ | ||||||
|  |                    NULL,                              \ | ||||||
|  |                    XMLSEC_ERRORS_R_UNEXPECTED_NODE,   \ | ||||||
|  |                    "node=%s",                         \ | ||||||
|  |                    xmlSecErrorsSafeString(nName)      \ | ||||||
|  |         );                                            \ | ||||||
|  |     } | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * xmlSecNodeNotFoundError: | ||||||
|  |  * @errorFunction:      the failed function. | ||||||
|  |  * @startNode:          the search start node. | ||||||
|  |  * @targetNodeName:     the expected child node name. | ||||||
|  |  * @errorObject:        the error specific error object (e.g. transform, key data, etc). | ||||||
|  |  * | ||||||
|  |  * Macro. The XMLSec library macro for reporting node not found errors. | ||||||
|  |  */ | ||||||
|  | #define xmlSecNodeNotFoundError(errorFunction, startNode, targetNodeName, errorObject) \ | ||||||
|  |     {                                                 \ | ||||||
|  |         const char* startNodeName = xmlSecNodeGetName(startNode); \ | ||||||
|  |         xmlSecError(XMLSEC_ERRORS_HERE,               \ | ||||||
|  |                    (const char*)(errorObject),        \ | ||||||
|  |                    (errorFunction),                   \ | ||||||
|  |                    XMLSEC_ERRORS_R_NODE_NOT_FOUND,    \ | ||||||
|  |                    "startNode=%s; target=%s",         \ | ||||||
|  |                    xmlSecErrorsSafeString(startNodeName), \ | ||||||
|  |                    xmlSecErrorsSafeString(targetNodeName) \ | ||||||
|  |         );                                            \ | ||||||
|  |     } | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * xmlSecInvalidTransfromError: | ||||||
|  |  * @transform:          the transform. | ||||||
|  |  * | ||||||
|  |  * Macro. The XMLSec library macro for reporting an invalid transform errors. | ||||||
|  |  */ | ||||||
|  | #define xmlSecInvalidTransfromError(transform) \ | ||||||
|  |     {                                                 \ | ||||||
|  |         xmlSecError(XMLSEC_ERRORS_HERE,               \ | ||||||
|  |                    (const char*)xmlSecTransformGetName(transform), \ | ||||||
|  |                    NULL,                              \ | ||||||
|  |                    XMLSEC_ERRORS_R_INVALID_TRANSFORM, \ | ||||||
|  |                    XMLSEC_ERRORS_NO_MESSAGE           \ | ||||||
|  |         );                                            \ | ||||||
|  |     } | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * xmlSecInvalidTransfromError2: | ||||||
|  |  * @transform:          the transform. | ||||||
|  |  * @msg:                the extra message. | ||||||
|  |  * @param:              the extra message param. | ||||||
|  |  * | ||||||
|  |  * | ||||||
|  |  * Macro. The XMLSec library macro for reporting an invalid transform errors. | ||||||
|  |  */ | ||||||
|  | #define xmlSecInvalidTransfromError2(transform, msg, param) \ | ||||||
|  |     {                                                 \ | ||||||
|  |         xmlSecError(XMLSEC_ERRORS_HERE,               \ | ||||||
|  |                    (const char*)xmlSecTransformGetName(transform), \ | ||||||
|  |                    NULL,                              \ | ||||||
|  |                    XMLSEC_ERRORS_R_INVALID_TRANSFORM, \ | ||||||
|  |                    (msg), (param)                     \ | ||||||
|  |         );                                            \ | ||||||
|  |     } | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * xmlSecInvalidTransfromStatusError: | ||||||
|  |  * @transform:          the transform. | ||||||
|  |  * | ||||||
|  |  * Macro. The XMLSec library macro for reporting an invalid transform status errors. | ||||||
|  |  */ | ||||||
|  | #define xmlSecInvalidTransfromStatusError(transform) \ | ||||||
|  |     {                                                 \ | ||||||
|  |         xmlSecError(XMLSEC_ERRORS_HERE,               \ | ||||||
|  |                    (const char*)xmlSecTransformGetName(transform), \ | ||||||
|  |                    NULL,                              \ | ||||||
|  |                    XMLSEC_ERRORS_R_INVALID_STATUS,    \ | ||||||
|  |                    "transformStatus=%d",              \ | ||||||
|  |                    (int)((transform)->status)         \ | ||||||
|  |         );                                            \ | ||||||
|  |     } | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * xmlSecInvalidTransfromStatusError2: | ||||||
|  |  * @transform:          the transform. | ||||||
|  |  * @msg:                the extra message. | ||||||
|  |  * | ||||||
|  |  * Macro. The XMLSec library macro for reporting an invalid transform status errors. | ||||||
|  |  */ | ||||||
|  | #define xmlSecInvalidTransfromStatusError2(transform, msg) \ | ||||||
|  |     {                                                 \ | ||||||
|  |         xmlSecError(XMLSEC_ERRORS_HERE,               \ | ||||||
|  |                    (const char*)xmlSecTransformGetName(transform), \ | ||||||
|  |                    NULL,                              \ | ||||||
|  |                    XMLSEC_ERRORS_R_INVALID_STATUS,    \ | ||||||
|  |                    "transformStatus=%ld, msg=%s",     \ | ||||||
|  |                    (long int)((transform)->status),   \ | ||||||
|  |                    msg                                \ | ||||||
|  |         );                                            \ | ||||||
|  |     } | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * xmlSecInvalidKeyDataSizeError: | ||||||
|  |  * @name:               the name of the variable, parameter, etc. | ||||||
|  |  * @actual:             the actual value. | ||||||
|  |  * @expected:           the expected value(s). | ||||||
|  |  * @errorObject:        the error specific error object (e.g. transform, key data, etc). | ||||||
|  |  * | ||||||
|  |  * Macro. The XMLSec library macro for reporting "invalid keydata size" errors. | ||||||
|  |  */ | ||||||
|  | #define xmlSecInvalidKeyDataSizeError(actual, expected, errorObject) \ | ||||||
|  |         xmlSecError(XMLSEC_ERRORS_HERE,                     \ | ||||||
|  |                     (const char*)(errorObject),             \ | ||||||
|  |                     NULL,                                   \ | ||||||
|  |                     XMLSEC_ERRORS_R_INVALID_KEY_DATA_SIZE,  \ | ||||||
|  |                     "invalid key data size: actual=%ld and expected=%ld", \ | ||||||
|  |                     (unsigned long)(actual),                \ | ||||||
|  |                     (unsigned long)(expected)               \ | ||||||
|  |         ) | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * xmlSecInvalidZeroKeyDataSizeError: | ||||||
|  |  * @name:               the name of the variable, parameter, etc. | ||||||
|  |  * @errorObject:        the error specific error object (e.g. transform, key data, etc). | ||||||
|  |  * | ||||||
|  |  * Macro. The XMLSec library macro for reporting "invalid keydata size" errors. | ||||||
|  |  */ | ||||||
|  | #define xmlSecInvalidZeroKeyDataSizeError(errorObject) \ | ||||||
|  |         xmlSecError(XMLSEC_ERRORS_HERE,                     \ | ||||||
|  |                     (const char*)(errorObject),             \ | ||||||
|  |                     NULL,                                   \ | ||||||
|  |                     XMLSEC_ERRORS_R_INVALID_KEY_DATA_SIZE,  \ | ||||||
|  |                     "invalid zero key data size"            \ | ||||||
|  |         ) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * xmlSecOtherError: | ||||||
|  |  * @code:               the error code. | ||||||
|  |  * @errorObject:        the error specific error object (e.g. transform, key data, etc). | ||||||
|  |  * @details:            the error message. | ||||||
|  |  * | ||||||
|  |  * Macro. The XMLSec library macro for reporting other XMLSec errors. | ||||||
|  |  */ | ||||||
|  | #define xmlSecOtherError(code, errorObject, details) \ | ||||||
|  |         xmlSecError(XMLSEC_ERRORS_HERE,                     \ | ||||||
|  |                     (const char*)(errorObject),             \ | ||||||
|  |                     NULL,                                   \ | ||||||
|  |                     (code),                                 \ | ||||||
|  |                     "details=%s",                           \ | ||||||
|  |                     xmlSecErrorsSafeString(details)         \ | ||||||
|  |         ) | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * xmlSecOtherError2: | ||||||
|  |  * @code:               the error code. | ||||||
|  |  * @errorObject:        the error specific error object (e.g. transform, key data, etc). | ||||||
|  |  * @msg:                the extra message. | ||||||
|  |  * @param:              the extra message param. | ||||||
|  |  * | ||||||
|  |  * Macro. The XMLSec library macro for reporting other XMLSec errors. | ||||||
|  |  */ | ||||||
|  | #define xmlSecOtherError2(code, errorObject, msg, param) \ | ||||||
|  |         xmlSecError(XMLSEC_ERRORS_HERE,                     \ | ||||||
|  |                     (const char*)(errorObject),             \ | ||||||
|  |                     NULL,                                   \ | ||||||
|  |                     (code),                                 \ | ||||||
|  |                     (msg), (param)                          \ | ||||||
|  |         ) | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * xmlSecOtherError3: | ||||||
|  |  * @code:               the error code. | ||||||
|  |  * @errorObject:        the error specific error object (e.g. transform, key data, etc). | ||||||
|  |  * @msg:                the extra message. | ||||||
|  |  * @param1:             the extra message param. | ||||||
|  |  * @param2:             the extra message param. | ||||||
|  |  * | ||||||
|  |  * Macro. The XMLSec library macro for reporting other XMLSec errors. | ||||||
|  |  */ | ||||||
|  | #define xmlSecOtherError3(code, errorObject, msg, param1, param2) \ | ||||||
|  |         xmlSecError(XMLSEC_ERRORS_HERE,                     \ | ||||||
|  |                     (const char*)(errorObject),             \ | ||||||
|  |                     NULL,                                   \ | ||||||
|  |                     (code),                                 \ | ||||||
|  |                     (msg), (param1), (param2)               \ | ||||||
|  |         ) | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * xmlSecOtherError4: | ||||||
|  |  * @code:               the error code. | ||||||
|  |  * @errorObject:        the error specific error object (e.g. transform, key data, etc). | ||||||
|  |  * @msg:                the extra message. | ||||||
|  |  * @param1:             the extra message param. | ||||||
|  |  * @param2:             the extra message param. | ||||||
|  |  * @param3:             the extra message param. | ||||||
|  |  * | ||||||
|  |  * Macro. The XMLSec library macro for reporting other XMLSec errors. | ||||||
|  |  */ | ||||||
|  | #define xmlSecOtherError4(code, errorObject, msg, param1, param2, param3) \ | ||||||
|  |         xmlSecError(XMLSEC_ERRORS_HERE,                     \ | ||||||
|  |                     (const char*)(errorObject),             \ | ||||||
|  |                     NULL,                                   \ | ||||||
|  |                     (code),                                 \ | ||||||
|  |                     (msg), (param1), (param2), (param3)     \ | ||||||
|  |         ) | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * xmlSecOtherError5: | ||||||
|  |  * @code:               the error code. | ||||||
|  |  * @errorObject:        the error specific error object (e.g. transform, key data, etc). | ||||||
|  |  * @msg:                the extra message. | ||||||
|  |  * @param1:             the extra message param. | ||||||
|  |  * @param2:             the extra message param. | ||||||
|  |  * @param3:             the extra message param. | ||||||
|  |  * @param4:             the extra message param. | ||||||
|  |  * | ||||||
|  |  * Macro. The XMLSec library macro for reporting other XMLSec errors. | ||||||
|  |  */ | ||||||
|  | #define xmlSecOtherError5(code, errorObject, msg, param1, param2, param3, param4) \ | ||||||
|  |         xmlSecError(XMLSEC_ERRORS_HERE,                     \ | ||||||
|  |                     (const char*)(errorObject),             \ | ||||||
|  |                     NULL,                                   \ | ||||||
|  |                     (code),                                 \ | ||||||
|  |                     (msg), (param1), (param2), (param3), (param4) \ | ||||||
|  |         ) | ||||||
|  |  | ||||||
|  | #ifdef __cplusplus | ||||||
|  | } | ||||||
|  | #endif /* __cplusplus */ | ||||||
|  |  | ||||||
|  | #endif /* __XMLSEC_ERROR_HELPERS_H__ */ | ||||||
							
								
								
									
										1950
									
								
								experimental/facho-signer/src/xmlsec1/xmltree.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1950
									
								
								experimental/facho-signer/src/xmlsec1/xmltree.c
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										200
									
								
								experimental/facho-signer/src/xmlusigned.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										200
									
								
								experimental/facho-signer/src/xmlusigned.xml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,200 @@ | |||||||
|  | <?xml version="1.0" encoding="UTF-8"?> | ||||||
|  | <Invoice xmlns="http://www.dian.gov.co/contratos/facturaelectronica/v1" xmlns:cac="urn:oasis:names:specification:ubl:schema:xsd:CommonAggregateComponents-2" xmlns:cbc="urn:oasis:names:specification:ubl:schema:xsd:CommonBasicComponents-2" xmlns:cdt="urn:DocumentInformation:names:specification:ubl:colombia:schema:xsd:DocumentInformationAggregateComponents-1" xmlns:clm54217="urn:un:unece:uncefact:codelist:specification:54217:2001" xmlns:clmIANAMIMEMediaType="urn:un:unece:uncefact:codelist:specification:IANAMIMEMediaType:2003" xmlns:ext="urn:oasis:names:specification:ubl:schema:xsd:CommonExtensionComponents-2" xmlns:qdt="urn:oasis:names:specification:ubl:schema:xsd:QualifiedDatatypes-2" xmlns:sts="http://www.dian.gov.co/contratos/facturaelectronica/v1/Structures" xmlns:udt="urn:un:unece:uncefact:data:specification:UnqualifiedDataTypesSchemaModule:2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xades="http://uri.etsi.org/01903/v1.3.2#" xmlns:ds="http://www.w3.org/2000/09/xmldsig#" xmlns:sig="http://www.w3.org/2000/09/xmldsig#"> | ||||||
|  |   <ext:UBLExtensions> | ||||||
|  |     <ext:UBLExtension> | ||||||
|  |       <ext:ExtensionContent> | ||||||
|  |         <sts:DianExtensions> | ||||||
|  |           <sts:SoftwareSecurityCode schemeAgencyName="CO, DIAN (Dirección de Impuestos y Aduanas Nacionales)" schemeAgencyID="195">2bd9a18f23cf1188d36888d218e9b0c31df77aa00bc036eaeaa1619184054237eee56d2d8db4ecab0173f65f8dab7753</sts:SoftwareSecurityCode> | ||||||
|  |           <sts:AuthorizationProvider> | ||||||
|  |             <sts:AuthorizationProviderID schemeID="4" schemeName="31" schemeAgencyName="CO, DIAN (Dirección de Impuestos y Aduanas Nacionales)" schemeAgencyID="195">800197268</sts:AuthorizationProviderID> | ||||||
|  |           </sts:AuthorizationProvider> | ||||||
|  |           <sts:SoftwareProvider> | ||||||
|  |             <sts:ProviderID schemeAgencyName="CO, DIAN (Dirección de Impuestos y Aduanas Nacionales)" schemeAgencyID="195" schemeID="5" schemaName="31">900579212</sts:ProviderID> | ||||||
|  |             <sts:SoftwareID schemeAgencyName="CO, DIAN (Dirección de Impuestos y Aduanas Nacionales)" schemeAgencyID="195">01ab9caa-6838-461e-82fb-da44da36a084</sts:SoftwareID> | ||||||
|  |           </sts:SoftwareProvider> | ||||||
|  |           <sts:InvoiceSource> | ||||||
|  |             <cbc:IdentificationCode>CO</cbc:IdentificationCode> | ||||||
|  |           </sts:InvoiceSource> | ||||||
|  |           <sts:InvoiceControl> | ||||||
|  |             <sts:InvoiceAuthorization>fc8eac422eba16e22ffd8c6f94b3f40a6e38162c</sts:InvoiceAuthorization> | ||||||
|  |             <sts:AuthorizationPeriod> | ||||||
|  |               <cbc:StartDate>2019-01-19</cbc:StartDate> | ||||||
|  |               <cbc:EndDate>2030-01-19</cbc:EndDate> | ||||||
|  |             </sts:AuthorizationPeriod> | ||||||
|  |             <sts:AuthorizedInvoices> | ||||||
|  |               <sts:Prefix>SETP</sts:Prefix> | ||||||
|  |               <sts:From>990000000</sts:From> | ||||||
|  |               <sts:To>995000000</sts:To> | ||||||
|  |             </sts:AuthorizedInvoices> | ||||||
|  |           </sts:InvoiceControl> | ||||||
|  |         </sts:DianExtensions> | ||||||
|  |       </ext:ExtensionContent> | ||||||
|  |     </ext:UBLExtension> | ||||||
|  |   </ext:UBLExtensions> | ||||||
|  |   <cbc:UBLVersionID>UBL 2.1</cbc:UBLVersionID> | ||||||
|  |   <cbc:CustomizationID>10</cbc:CustomizationID> | ||||||
|  |   <cbc:ProfileID>DIAN 2.1</cbc:ProfileID> | ||||||
|  |   <cbc:ProfileExecutionID>2</cbc:ProfileExecutionID> | ||||||
|  |   <cbc:ID>SETP990000001</cbc:ID> | ||||||
|  |   <cbc:UUID schemeID="2" schemeName="CUFE-SHA384">50578625ce1fb2f6bb2bc57b22180d2763c8a868c4e62da72e0e43001f9c7f3459c81e2bf9324830175b1225af37e435</cbc:UUID> | ||||||
|  |   <cbc:DocumentCurrencyCode>COP</cbc:DocumentCurrencyCode> | ||||||
|  |   <cbc:IssueDate>2020-09-05</cbc:IssueDate> | ||||||
|  |   <cbc:IssueTime>22:38:53-05:00</cbc:IssueTime> | ||||||
|  |   <cbc:InvoiceTypeCode listAgencyID="195" listAgencyName="No matching global declaration available for the validation root" listURI="http://www.dian.gov.co">01</cbc:InvoiceTypeCode> | ||||||
|  |   <cbc:LineCountNumeric>1</cbc:LineCountNumeric> | ||||||
|  |   <cac:InvoicePeriod> | ||||||
|  |     <cbc:StartDate>2020-09-05</cbc:StartDate> | ||||||
|  |     <cbc:EndDate>2020-09-05</cbc:EndDate> | ||||||
|  |   </cac:InvoicePeriod> | ||||||
|  |   <cac:AccountingSupplierParty> | ||||||
|  |     <cbc:AdditionalAccountID>1</cbc:AdditionalAccountID> | ||||||
|  |     <cac:Party> | ||||||
|  |       <cac:PartyName> | ||||||
|  |         <cbc:Name>NEUROTEC TECNOLOGIA S.A.S</cbc:Name> | ||||||
|  |       </cac:PartyName> | ||||||
|  |       <cac:PhysicalLocation> | ||||||
|  |         <cac:Address> | ||||||
|  |           <cac:AddressLine> | ||||||
|  |             <cbc:Line/> | ||||||
|  |           </cac:AddressLine> | ||||||
|  |         </cac:Address> | ||||||
|  |       </cac:PhysicalLocation> | ||||||
|  |       <cac:PartyLegalEntity> | ||||||
|  |         <cbc:CompanyID schemeAgencyName="CO, DIAN (Dirección de Impuestos y Aduanas Nacionales)" schemeAgencyID="195" schemeID="5" schemeName="31">900579212</cbc:CompanyID> | ||||||
|  |         <cbc:RegistrationName>NEUROTEC TECNOLOGIA S.A.S</cbc:RegistrationName> | ||||||
|  |         <cac:RegistrationAddress> | ||||||
|  |           <cbc:CityName/> | ||||||
|  |           <cac:AddressLine> | ||||||
|  |             <cbc:Line/> | ||||||
|  |           </cac:AddressLine> | ||||||
|  |           <cac:Country> | ||||||
|  |             <cbc:IdentificationCode>CO</cbc:IdentificationCode> | ||||||
|  |             <cbc:Name>COLOMBIA</cbc:Name> | ||||||
|  |           </cac:Country> | ||||||
|  |         </cac:RegistrationAddress> | ||||||
|  |       </cac:PartyLegalEntity> | ||||||
|  |       <cac:PartyTaxScheme> | ||||||
|  |         <cbc:RegistrationName>NEUROTEC TECNOLOGIA S.A.S</cbc:RegistrationName> | ||||||
|  |         <cbc:CompanyID schemeAgencyName="CO, DIAN (Dirección de Impuestos y Aduanas Nacionales)" schemeAgencyID="195" schemeID="5" schemeName="31">900579212</cbc:CompanyID> | ||||||
|  |         <cbc:TaxLevelCode listName="48">ZZ;O-09;O-14;O-48</cbc:TaxLevelCode> | ||||||
|  |         <cac:TaxScheme/> | ||||||
|  |       </cac:PartyTaxScheme> | ||||||
|  |       <cac:Contact> | ||||||
|  |         <cbc:ElectronicMail>sdds@sd.com</cbc:ElectronicMail> | ||||||
|  |       </cac:Contact> | ||||||
|  |     </cac:Party> | ||||||
|  |   </cac:AccountingSupplierParty> | ||||||
|  |   <cac:AccountingCustomerParty> | ||||||
|  |     <cbc:AdditionalAccountID>2</cbc:AdditionalAccountID> | ||||||
|  |     <cac:Party> | ||||||
|  |       <cac:PartyName> | ||||||
|  |         <cbc:Name>facho-customer</cbc:Name> | ||||||
|  |       </cac:PartyName> | ||||||
|  |       <cac:PhysicalLocation> | ||||||
|  |         <cac:Address> | ||||||
|  |           <cac:AddressLine> | ||||||
|  |             <cbc:Line/> | ||||||
|  |           </cac:AddressLine> | ||||||
|  |         </cac:Address> | ||||||
|  |       </cac:PhysicalLocation> | ||||||
|  |       <cac:PartyTaxScheme> | ||||||
|  |         <cbc:CompanyID schemeAgencyName="CO, DIAN (Dirección de Impuestos y Aduanas Nacionales)" schemeAgencyID="195" schemeID="" schemeName="13">43851425</cbc:CompanyID> | ||||||
|  |         <cbc:RegistrationName>facho-customer</cbc:RegistrationName> | ||||||
|  |         <cbc:TaxLevelCode>ZZ</cbc:TaxLevelCode> | ||||||
|  |         <cac:TaxScheme/> | ||||||
|  |       </cac:PartyTaxScheme> | ||||||
|  |       <cac:PartyLegalEntity> | ||||||
|  |         <cbc:RegistrationName>facho-customer</cbc:RegistrationName> | ||||||
|  |         <cac:RegistrationAddress> | ||||||
|  |           <cbc:CityName/> | ||||||
|  |           <cac:AddressLine> | ||||||
|  |             <cbc:Line/> | ||||||
|  |           </cac:AddressLine> | ||||||
|  |           <cac:Country> | ||||||
|  |             <cbc:IdentificationCode>CO</cbc:IdentificationCode> | ||||||
|  |             <cbc:Name>COLOMBIA</cbc:Name> | ||||||
|  |           </cac:Country> | ||||||
|  |         </cac:RegistrationAddress> | ||||||
|  |       </cac:PartyLegalEntity> | ||||||
|  |     </cac:Party> | ||||||
|  |   </cac:AccountingCustomerParty> | ||||||
|  |   <cac:LegalMonetaryTotal> | ||||||
|  |     <cbc:LineExtensionAmount currencyID="COP">100.00</cbc:LineExtensionAmount> | ||||||
|  |     <cbc:TaxExclusiveAmount currencyID="COP">100.00</cbc:TaxExclusiveAmount> | ||||||
|  |     <cbc:TaxInclusiveAmount currencyID="COP">119.00</cbc:TaxInclusiveAmount> | ||||||
|  |     <cbc:ChargeTotalAmount currencyID="COP">19.00</cbc:ChargeTotalAmount> | ||||||
|  |     <cbc:PayableAmount currencyID="COP">119.00</cbc:PayableAmount> | ||||||
|  |   </cac:LegalMonetaryTotal> | ||||||
|  |   <cac:TaxTotal/> | ||||||
|  |   <cac:TaxTotal> | ||||||
|  |     <cac:TaxSubtotal> | ||||||
|  |       <cac:TaxCategory> | ||||||
|  |         <cac:TaxScheme> | ||||||
|  |           <cbc:ID>01</cbc:ID> | ||||||
|  |         </cac:TaxScheme> | ||||||
|  |       </cac:TaxCategory> | ||||||
|  |     </cac:TaxSubtotal> | ||||||
|  |     <cbc:TaxAmount>19.00</cbc:TaxAmount> | ||||||
|  |   </cac:TaxTotal> | ||||||
|  |   <cac:TaxTotal> | ||||||
|  |     <cac:TaxSubtotal> | ||||||
|  |       <cac:TaxCategory> | ||||||
|  |         <cac:TaxScheme> | ||||||
|  |           <cbc:ID>04</cbc:ID> | ||||||
|  |         </cac:TaxScheme> | ||||||
|  |       </cac:TaxCategory> | ||||||
|  |     </cac:TaxSubtotal> | ||||||
|  |     <cbc:TaxAmount>0.00</cbc:TaxAmount> | ||||||
|  |   </cac:TaxTotal> | ||||||
|  |   <cac:TaxTotal> | ||||||
|  |     <cac:TaxSubtotal> | ||||||
|  |       <cac:TaxCategory> | ||||||
|  |         <cac:TaxScheme> | ||||||
|  |           <cbc:ID>03</cbc:ID> | ||||||
|  |         </cac:TaxScheme> | ||||||
|  |       </cac:TaxCategory> | ||||||
|  |     </cac:TaxSubtotal> | ||||||
|  |     <cbc:TaxAmount>0.00</cbc:TaxAmount> | ||||||
|  |   </cac:TaxTotal> | ||||||
|  |   <cac:InvoiceLine> | ||||||
|  |     <cbc:ID>1</cbc:ID> | ||||||
|  |     <cbc:InvoicedQuantity unitCode="NAR">1</cbc:InvoicedQuantity> | ||||||
|  |     <cbc:LineExtensionAmount currencyID="COP">100.0</cbc:LineExtensionAmount> | ||||||
|  |     <cac:TaxTotal> | ||||||
|  |       <cbc:TaxAmount currencyID="COP">19.0</cbc:TaxAmount> | ||||||
|  |       <cac:TaxSubtotal> | ||||||
|  |         <cbc:TaxableAmount currencyID="COP">100.0</cbc:TaxableAmount> | ||||||
|  |         <cbc:TaxAmount currencyID="COP">19.0</cbc:TaxAmount> | ||||||
|  |         <cac:TaxCategory> | ||||||
|  |           <cbc:Percent>19.0</cbc:Percent> | ||||||
|  |           <cac:TaxScheme> | ||||||
|  |             <cbc:ID>01</cbc:ID> | ||||||
|  |             <cbc:Name>IVA</cbc:Name> | ||||||
|  |           </cac:TaxScheme> | ||||||
|  |         </cac:TaxCategory> | ||||||
|  |       </cac:TaxSubtotal> | ||||||
|  |     </cac:TaxTotal> | ||||||
|  |     <cac:PricingReference> | ||||||
|  |       <cac:AlternativeConditionPrice> | ||||||
|  |         <cbc:PriceAmount currencyID="COP">100.0</cbc:PriceAmount> | ||||||
|  |         <cbc:PriceTypeCode>01</cbc:PriceTypeCode> | ||||||
|  |         <cbc:PriceType>x</cbc:PriceType> | ||||||
|  |       </cac:AlternativeConditionPrice> | ||||||
|  |     </cac:PricingReference> | ||||||
|  |     <cac:Item> | ||||||
|  |       <cbc:Description>test</cbc:Description> | ||||||
|  |       <cac:StandardItemIdentification> | ||||||
|  |         <cbc:ID>9999</cbc:ID> | ||||||
|  |       </cac:StandardItemIdentification> | ||||||
|  |     </cac:Item> | ||||||
|  |     <cac:Price> | ||||||
|  |       <cbc:PriceAmount currencyID="COP">100.0</cbc:PriceAmount> | ||||||
|  |     </cac:Price> | ||||||
|  |   </cac:InvoiceLine> | ||||||
|  |   <cac:PaymentMeans> | ||||||
|  |     <cbc:ID>1</cbc:ID> | ||||||
|  |     <cbc:PaymentMeansCode>10</cbc:PaymentMeansCode> | ||||||
|  |     <cbc:PaymentDueDate>2020-09-05</cbc:PaymentDueDate> | ||||||
|  |     <cbc:PaymentID>1</cbc:PaymentID> | ||||||
|  |   </cac:PaymentMeans> | ||||||
|  | </Invoice> | ||||||
							
								
								
									
										7
									
								
								experimental/facho-wasm/xmlsec-wasm/build.sh
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								experimental/facho-wasm/xmlsec-wasm/build.sh
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,7 @@ | |||||||
|  | #!/bin/sh | ||||||
|  |  | ||||||
|  | set -ex | ||||||
|  |  | ||||||
|  | sh build_openssl.sh | ||||||
|  | sh build_libxml2.sh | ||||||
|  | sh build_xmlsec.sh | ||||||
							
								
								
									
										21
									
								
								experimental/facho-wasm/xmlsec-wasm/build_libxml2.sh
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								experimental/facho-wasm/xmlsec-wasm/build_libxml2.sh
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,21 @@ | |||||||
|  | #!/bin/sh | ||||||
|  |  | ||||||
|  | LIBXML2_VERSION=2.9.12 | ||||||
|  |  | ||||||
|  | tar xf libxml2-${LIBXML2_VERSION}.tar.gz | ||||||
|  |  | ||||||
|  | mv libxml2-${LIBXML2_VERSION} libxml2 | ||||||
|  |  | ||||||
|  | pushd libxml2 | ||||||
|  |  | ||||||
|  | wasiconfigure  ./configure --enable-static --without-http --without-ftp --without-modules --without-python --without-zlib --without-lzma --without-threads --host=x86_64 | ||||||
|  |  | ||||||
|  | wasimake make clean | ||||||
|  | wasimake make -j4 | ||||||
|  |  | ||||||
|  | popd | ||||||
|  |  | ||||||
|  | mkdir -p vendor/libxml2/lib | ||||||
|  | mkdir -p vendor/libxml2/include | ||||||
|  | cp -r libxml2/include/libxml2 vendor/libxml2/include | ||||||
|  | cp -r libxml2/.libs/libxml2.a vendor/libxml2/lib | ||||||
							
								
								
									
										41
									
								
								experimental/facho-wasm/xmlsec-wasm/build_openssl.sh
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										41
									
								
								experimental/facho-wasm/xmlsec-wasm/build_openssl.sh
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,41 @@ | |||||||
|  | #!/bin/sh | ||||||
|  | # TOMADO DE: https://github.com/voltbuilder/openssl-wasm | ||||||
|  |  | ||||||
|  | OPENSSL_VERSION=1.1.1l | ||||||
|  |  | ||||||
|  | # get the source | ||||||
|  | tar xf openssl-${OPENSSL_VERSION}.tar.gz | ||||||
|  |  | ||||||
|  | patch -p0 < openssl-${OPENSSL_VERSION}.patch | ||||||
|  |  | ||||||
|  | cd openssl-${OPENSSL_VERSION} | ||||||
|  | make clean | ||||||
|  |  | ||||||
|  | set -e | ||||||
|  |  | ||||||
|  | # why ./Configure instead of ./config? We want to force using the generic gcc profile which is more conservative than linux-x32 | ||||||
|  | # -no-sock - we don't have sockets in WASI | ||||||
|  | # new -no-ui-console - sdk 12 has no termios??? | ||||||
|  | # check in 12 -DHAVE_FORK=0 - no fork() in WASI | ||||||
|  | # new -D_WASI_EMULATED_MMAN - works with the library below to enable WASI mman emulation | ||||||
|  | # new -D_WASI_EMULATED_SIGNAL - with sdk 12 | ||||||
|  | # new -DOPENSSL_NO_SECURE_MEMORY - wasi doesn't have secure mem (madvise, mlock, etc...) | ||||||
|  | # new -DNO_SYSLOG - get rid of need for patch above | ||||||
|  | # --with-rand-seed=getrandom (needed to force using getentropy because WASI has no /dev/random or getrandom) | ||||||
|  | wasiconfigure ./Configure gcc -no-sock -no-ui-console -DHAVE_FORK=0 -D_WASI_EMULATED_MMAN -D_WASI_EMULATED_SIGNAL -DOPENSSL_NO_SECURE_MEMORY -DNO_SYSLOG --with-rand-seed=getrandom | ||||||
|  |  | ||||||
|  | # enables stuff from mman.h (see define above) also add -lwasi-emulated-signal | ||||||
|  | #sed -i -e "s/CNF_EX_LIBS=/CNF_EX_LIBS=-lwasi-emulated-mman -lwasi-emulated-signal /g" Makefile | ||||||
|  |  | ||||||
|  | # build! | ||||||
|  | wasimake make -j4 build_generated libssl.a libcrypto.a | ||||||
|  |  | ||||||
|  | rm -rf ../vendor/openssl/include | ||||||
|  | mkdir -p ../vendor/openssl/include | ||||||
|  | cp -R include/openssl ../vendor/openssl/include | ||||||
|  |  | ||||||
|  | mkdir -p ../vendor/openssl/lib/ | ||||||
|  | cp libssl.a ../vendor/openssl/lib/ | ||||||
|  | cp libcrypto.a ../vendor/openssl/lib/ | ||||||
|  |  | ||||||
|  | exit 0 | ||||||
							
								
								
									
										14
									
								
								experimental/facho-wasm/xmlsec-wasm/build_xmlsec.sh
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								experimental/facho-wasm/xmlsec-wasm/build_xmlsec.sh
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,14 @@ | |||||||
|  | #!/bin/sh | ||||||
|  |  | ||||||
|  | XMLSEC1_VERSION=1.2.33 | ||||||
|  |  | ||||||
|  | tar xf xmlsec1-${XMLSEC1_VERSION}.tar.gz | ||||||
|  |  | ||||||
|  | cd xmlsec1-${XMLSEC1_VERSION} | ||||||
|  |  | ||||||
|  | cp -r ../libxml2 . | ||||||
|  | cp -r ../vendor . | ||||||
|  |  | ||||||
|  | wasiconfigure ./configure --with-libxml-src=`pwd`/libxml2 --with-openssl=`pwd`/vendor/openssl  --enable-static-linking  --disable-folders-search --disable-apps --disable-apps-crypto-dl --disable-crypto-dl | ||||||
|  |  | ||||||
|  | wasimake make -j4 | ||||||
							
								
								
									
										6
									
								
								experimental/facho-wasm/xmlsec-wasm/examples/README.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								experimental/facho-wasm/xmlsec-wasm/examples/README.md
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,6 @@ | |||||||
|  | # ejemplo | ||||||
|  |  | ||||||
|  | ~~~ | ||||||
|  | $ bash build.sh | ||||||
|  | $ wasirun ./a.out sign1-tmpl.xml example.key | ||||||
|  | ~~~ | ||||||
							
								
								
									
										12
									
								
								experimental/facho-wasm/xmlsec-wasm/examples/build.sh
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								experimental/facho-wasm/xmlsec-wasm/examples/build.sh
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,12 @@ | |||||||
|  | cp ../vendor/openssl/lib/*.a . | ||||||
|  | cp ../xmlsec1-1.2.33/src/.libs/*.a . | ||||||
|  | cp ../xmlsec1-1.2.33/src/openssl/.libs/*.a . | ||||||
|  | cp ../libxml2/.libs/libxml2.a . | ||||||
|  |  | ||||||
|  | mkdir -p include | ||||||
|  |  | ||||||
|  | cp -r ../libxml2/include/libxml include/ | ||||||
|  | cp -r ../xmlsec1-1.2.33/include/xmlsec include/ | ||||||
|  | cp -r ../vendor/openssl/include/* include/ | ||||||
|  |  | ||||||
|  | wasicc -Iinclude libxml2.a libcrypto.a libssl.a libxmlsec1.a libxmlsec1-openssl.a sign.c  | ||||||
							
								
								
									
										216
									
								
								experimental/facho-wasm/xmlsec-wasm/examples/sign.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										216
									
								
								experimental/facho-wasm/xmlsec-wasm/examples/sign.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,216 @@ | |||||||
|  | /**  | ||||||
|  |  * XML Security Library example: Signing a template file. | ||||||
|  |  *  | ||||||
|  |  * Signs a template file using a key from PEM file | ||||||
|  |  *  | ||||||
|  |  * Usage:  | ||||||
|  |  *      ./sign1 <xml-tmpl> <pem-key>  | ||||||
|  |  * | ||||||
|  |  * Example: | ||||||
|  |  *      ./sign1 sign1-tmpl.xml rsakey.pem > sign1-res.xml | ||||||
|  |  * | ||||||
|  |  * The result signature could be validated using verify1 example: | ||||||
|  |  *      ./verify1 sign1-res.xml rsapub.pem | ||||||
|  |  * | ||||||
|  |  * This is free software; see Copyright file in the source | ||||||
|  |  * distribution for preciese wording. | ||||||
|  |  *  | ||||||
|  |  * Copyright (C) 2002-2016 Aleksey Sanin <aleksey@aleksey.com>. All Rights Reserved. | ||||||
|  |  */ | ||||||
|  | #include <stdlib.h> | ||||||
|  | #include <string.h> | ||||||
|  | #include <assert.h> | ||||||
|  |  | ||||||
|  | #include <libxml/tree.h> | ||||||
|  | #include <libxml/xmlmemory.h> | ||||||
|  | #include <libxml/parser.h> | ||||||
|  |  | ||||||
|  | #define XMLSEC_NO_XSLT | ||||||
|  | #define XMLSEC_CRYPTO_OPENSSL | ||||||
|  |  | ||||||
|  | #ifndef XMLSEC_NO_XSLT | ||||||
|  | #include <libxslt/xslt.h> | ||||||
|  | #include <libxslt/security.h> | ||||||
|  | #endif /* XMLSEC_NO_XSLT */ | ||||||
|  |  | ||||||
|  | #include <xmlsec/xmlsec.h> | ||||||
|  | #include <xmlsec/xmltree.h> | ||||||
|  | #include <xmlsec/xmldsig.h> | ||||||
|  | #include <xmlsec/crypto.h> | ||||||
|  |  | ||||||
|  | int sign_file(const char* tmpl_file, const char* key_file); | ||||||
|  |  | ||||||
|  | int  | ||||||
|  | main(int argc, char **argv) { | ||||||
|  | #ifndef XMLSEC_NO_XSLT | ||||||
|  |     xsltSecurityPrefsPtr xsltSecPrefs = NULL; | ||||||
|  | #endif /* XMLSEC_NO_XSLT */ | ||||||
|  | 	setenv("RANDFILE", "/dev/random", 1); | ||||||
|  |     assert(argv); | ||||||
|  |  | ||||||
|  |     if(argc != 3) { | ||||||
|  |         fprintf(stderr, "Error: wrong number of arguments.\n"); | ||||||
|  |         fprintf(stderr, "Usage: %s <tmpl-file> <key-file>\n", argv[0]); | ||||||
|  |         return(1); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     printf("template %s key %s\n", argv[1], argv[2]); | ||||||
|  |     /* Init libxml and libxslt libraries */ | ||||||
|  |     xmlInitParser(); | ||||||
|  |     LIBXML_TEST_VERSION | ||||||
|  |     xmlLoadExtDtdDefaultValue = XML_DETECT_IDS | XML_COMPLETE_ATTRS; | ||||||
|  |     xmlSubstituteEntitiesDefault(1); | ||||||
|  | #ifndef XMLSEC_NO_XSLT | ||||||
|  |     xmlIndentTreeOutput = 1;  | ||||||
|  | #endif /* XMLSEC_NO_XSLT */ | ||||||
|  |  | ||||||
|  |     /* Init libxslt */ | ||||||
|  | #ifndef XMLSEC_NO_XSLT | ||||||
|  |     /* disable everything */ | ||||||
|  |     xsltSecPrefs = xsltNewSecurityPrefs();  | ||||||
|  |     xsltSetSecurityPrefs(xsltSecPrefs,  XSLT_SECPREF_READ_FILE,        xsltSecurityForbid); | ||||||
|  |     xsltSetSecurityPrefs(xsltSecPrefs,  XSLT_SECPREF_WRITE_FILE,       xsltSecurityForbid); | ||||||
|  |     xsltSetSecurityPrefs(xsltSecPrefs,  XSLT_SECPREF_CREATE_DIRECTORY, xsltSecurityForbid); | ||||||
|  |     xsltSetSecurityPrefs(xsltSecPrefs,  XSLT_SECPREF_READ_NETWORK,     xsltSecurityForbid); | ||||||
|  |     xsltSetSecurityPrefs(xsltSecPrefs,  XSLT_SECPREF_WRITE_NETWORK,    xsltSecurityForbid); | ||||||
|  |     xsltSetDefaultSecurityPrefs(xsltSecPrefs);  | ||||||
|  | #endif /* XMLSEC_NO_XSLT */                 | ||||||
|  |  | ||||||
|  |     /* Init xmlsec library */ | ||||||
|  |     if(xmlSecInit() < 0) { | ||||||
|  |         fprintf(stderr, "Error: xmlsec initialization failed.\n"); | ||||||
|  |         return(-1); | ||||||
|  |     } | ||||||
|  | 	puts("done xmlSecInit"); | ||||||
|  |  | ||||||
|  |     /* Check loaded library version */ | ||||||
|  |     if(xmlSecCheckVersion() != 1) { | ||||||
|  |         fprintf(stderr, "Error: loaded xmlsec library version is not compatible.\n"); | ||||||
|  |         return(-1); | ||||||
|  |     } | ||||||
|  | 	puts("done xmlSecCheckVersion"); | ||||||
|  |     /* Load default crypto engine if we are supporting dynamic | ||||||
|  |      * loading for xmlsec-crypto libraries. Use the crypto library | ||||||
|  |      * name ("openssl", "nss", etc.) to load corresponding  | ||||||
|  |      * xmlsec-crypto library. | ||||||
|  |      */ | ||||||
|  | #ifdef XMLSEC_CRYPTO_DYNAMIC_LOADING | ||||||
|  |     if(xmlSecCryptoDLLoadLibrary(NULL) < 0) { | ||||||
|  |         fprintf(stderr, "Error: unable to load default xmlsec-crypto library. Make sure\n" | ||||||
|  |                         "that you have it installed and check shared libraries path\n" | ||||||
|  |                         "(LD_LIBRARY_PATH and/or LTDL_LIBRARY_PATH) environment variables.\n"); | ||||||
|  |         return(-1);      | ||||||
|  |     } | ||||||
|  | #endif /* XMLSEC_CRYPTO_DYNAMIC_LOADING */ | ||||||
|  |  | ||||||
|  |     /* Init crypto library */ | ||||||
|  |     if(xmlSecCryptoAppInit(NULL) < 0) { | ||||||
|  |         fprintf(stderr, "Error: crypto initialization failed.\n"); | ||||||
|  |         return(-1); | ||||||
|  |     } | ||||||
|  | puts("done xmlSecCryptoAppInit"); | ||||||
|  |     /* Init xmlsec-crypto library */ | ||||||
|  |     if(xmlSecCryptoInit() < 0) { | ||||||
|  |         fprintf(stderr, "Error: xmlsec-crypto initialization failed.\n"); | ||||||
|  |         return(-1); | ||||||
|  |     } | ||||||
|  | puts("done xmlSecCryptoInit"); | ||||||
|  |     if(sign_file(argv[1], argv[2]) < 0) { | ||||||
|  |         return(-1); | ||||||
|  |     }     | ||||||
|  |      | ||||||
|  |     /* Shutdown xmlsec-crypto library */ | ||||||
|  |     xmlSecCryptoShutdown(); | ||||||
|  |      | ||||||
|  |     /* Shutdown crypto library */ | ||||||
|  |     xmlSecCryptoAppShutdown(); | ||||||
|  |      | ||||||
|  |     /* Shutdown xmlsec library */ | ||||||
|  |     xmlSecShutdown(); | ||||||
|  |  | ||||||
|  |     /* Shutdown libxslt/libxml */ | ||||||
|  | #ifndef XMLSEC_NO_XSLT | ||||||
|  |     xsltFreeSecurityPrefs(xsltSecPrefs); | ||||||
|  |     xsltCleanupGlobals(); | ||||||
|  | #endif /* XMLSEC_NO_XSLT */ | ||||||
|  |     xmlCleanupParser(); | ||||||
|  |      | ||||||
|  |     return(0); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /**  | ||||||
|  |  * sign_file: | ||||||
|  |  * @tmpl_file:          the signature template file name. | ||||||
|  |  * @key_file:           the PEM private key file name. | ||||||
|  |  * | ||||||
|  |  * Signs the #tmpl_file using private key from #key_file. | ||||||
|  |  * | ||||||
|  |  * Returns 0 on success or a negative value if an error occurs. | ||||||
|  |  */ | ||||||
|  | int  | ||||||
|  | sign_file(const char* tmpl_file, const char* key_file) { | ||||||
|  |     xmlDocPtr doc = NULL; | ||||||
|  |     xmlNodePtr node = NULL; | ||||||
|  |     xmlSecDSigCtxPtr dsigCtx = NULL; | ||||||
|  |     int res = -1; | ||||||
|  |      | ||||||
|  |     assert(tmpl_file); | ||||||
|  |     assert(key_file); | ||||||
|  |  | ||||||
|  |     /* load template */ | ||||||
|  |     doc = xmlParseFile(tmpl_file); | ||||||
|  |     if ((doc == NULL) || (xmlDocGetRootElement(doc) == NULL)){ | ||||||
|  |         fprintf(stderr, "Error: unable to parse file \"%s\"\n", tmpl_file); | ||||||
|  |         goto done;       | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /* find start node */ | ||||||
|  |     node = xmlSecFindNode(xmlDocGetRootElement(doc), xmlSecNodeSignature, xmlSecDSigNs); | ||||||
|  |     if(node == NULL) { | ||||||
|  |         fprintf(stderr, "Error: start node not found in \"%s\"\n", tmpl_file); | ||||||
|  |         goto done;       | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /* create signature context, we don't need keys manager in this example */ | ||||||
|  |     dsigCtx = xmlSecDSigCtxCreate(NULL); | ||||||
|  |     if(dsigCtx == NULL) { | ||||||
|  |         fprintf(stderr,"Error: failed to create signature context\n"); | ||||||
|  |         goto done; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /* load private key, assuming that there is not password */ | ||||||
|  |     dsigCtx->signKey = xmlSecCryptoAppKeyLoad(key_file, xmlSecKeyDataFormatPem, NULL, NULL, NULL); | ||||||
|  |     if(dsigCtx->signKey == NULL) { | ||||||
|  |         fprintf(stderr,"Error: failed to load private pem key from \"%s\"\n", key_file); | ||||||
|  |         goto done; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /* set key name to the file name, this is just an example! */ | ||||||
|  |     if(xmlSecKeySetName(dsigCtx->signKey, key_file) < 0) { | ||||||
|  |         fprintf(stderr,"Error: failed to set key name for key from \"%s\"\n", key_file); | ||||||
|  |         goto done; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /* sign the template */ | ||||||
|  |     if(xmlSecDSigCtxSign(dsigCtx, node) < 0) { | ||||||
|  |         fprintf(stderr,"Error: signature failed\n"); | ||||||
|  |         goto done; | ||||||
|  |     } | ||||||
|  |          | ||||||
|  |     /* print signed document to stdout */ | ||||||
|  |     xmlDocDump(stdout, doc); | ||||||
|  |      | ||||||
|  |     /* success */ | ||||||
|  |     res = 0; | ||||||
|  |  | ||||||
|  | done:     | ||||||
|  |     /* cleanup */ | ||||||
|  |     if(dsigCtx != NULL) { | ||||||
|  |         xmlSecDSigCtxDestroy(dsigCtx); | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     if(doc != NULL) { | ||||||
|  |         xmlFreeDoc(doc);  | ||||||
|  |     } | ||||||
|  |     return(res); | ||||||
|  | } | ||||||
							
								
								
									
										27
									
								
								experimental/facho-wasm/xmlsec-wasm/examples/sign1-tmpl.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								experimental/facho-wasm/xmlsec-wasm/examples/sign1-tmpl.xml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,27 @@ | |||||||
|  | <?xml version="1.0" encoding="UTF-8"?> | ||||||
|  | <!--  | ||||||
|  | XML Security Library example: Simple signature template file for sign1 example.  | ||||||
|  | --> | ||||||
|  | <Envelope xmlns="urn:envelope"> | ||||||
|  |   <Data> | ||||||
|  | 	Hello, World! | ||||||
|  |   </Data> | ||||||
|  |   <Signature xmlns="http://www.w3.org/2000/09/xmldsig#"> | ||||||
|  |     <SignedInfo> | ||||||
|  |       <CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315" /> | ||||||
|  |       <SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1" /> | ||||||
|  |       <Reference URI=""> | ||||||
|  |         <Transforms> | ||||||
|  |           <Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature" /> | ||||||
|  |         </Transforms> | ||||||
|  |         <DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1" /> | ||||||
|  |         <DigestValue></DigestValue> | ||||||
|  |       </Reference> | ||||||
|  |     </SignedInfo> | ||||||
|  |     <SignatureValue/> | ||||||
|  |     <KeyInfo> | ||||||
|  | 	<KeyName/> | ||||||
|  |     </KeyInfo> | ||||||
|  |   </Signature> | ||||||
|  | </Envelope> | ||||||
|  |  | ||||||
							
								
								
									
										199
									
								
								experimental/facho-wasm/xmlsec-wasm/openssl-1.1.1l.patch
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										199
									
								
								experimental/facho-wasm/xmlsec-wasm/openssl-1.1.1l.patch
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,199 @@ | |||||||
|  | diff '--color=auto' -ruN openssl-1.1.1l/crypto/rand/rand_unix.c patch-1.1.1l/crypto/rand/rand_unix.c | ||||||
|  | --- openssl-1.1.1l/crypto/rand/rand_unix.c	2021-08-24 09:38:47.000000000 -0400 | ||||||
|  | +++ patch-1.1.1l/crypto/rand/rand_unix.c	2021-09-12 02:26:35.765347423 -0400 | ||||||
|  | @@ -372,36 +372,36 @@ | ||||||
|  |       * Note: Sometimes getentropy() can be provided but not implemented | ||||||
|  |       * internally. So we need to check errno for ENOSYS | ||||||
|  |       */ | ||||||
|  | -#  if defined(__GNUC__) && __GNUC__>=2 && defined(__ELF__) && !defined(__hpux) | ||||||
|  | -    extern int getentropy(void *buffer, size_t length) __attribute__((weak)); | ||||||
|  | +/* #  if defined(__GNUC__) && __GNUC__>=2 && defined(__ELF__) && !defined(__hpux) */ | ||||||
|  | +/*     extern int getentropy(void *buffer, size_t length) __attribute__((weak)); */ | ||||||
|  |   | ||||||
|  | -    if (getentropy != NULL) { | ||||||
|  | +/*     if (getentropy != NULL) { */ | ||||||
|  |          if (getentropy(buf, buflen) == 0) | ||||||
|  |              return (ssize_t)buflen; | ||||||
|  |          if (errno != ENOSYS) | ||||||
|  |              return -1; | ||||||
|  | -    } | ||||||
|  | -#  elif defined(__APPLE__) | ||||||
|  | -    if (CCRandomGenerateBytes(buf, buflen) == kCCSuccess) | ||||||
|  | -	    return (ssize_t)buflen; | ||||||
|  | - | ||||||
|  | -    return -1; | ||||||
|  | -#  else | ||||||
|  | -    union { | ||||||
|  | -        void *p; | ||||||
|  | -        int (*f)(void *buffer, size_t length); | ||||||
|  | -    } p_getentropy; | ||||||
|  | - | ||||||
|  | -    /* | ||||||
|  | -     * We could cache the result of the lookup, but we normally don't | ||||||
|  | -     * call this function often. | ||||||
|  | -     */ | ||||||
|  | -    ERR_set_mark(); | ||||||
|  | -    p_getentropy.p = DSO_global_lookup("getentropy"); | ||||||
|  | -    ERR_pop_to_mark(); | ||||||
|  | -    if (p_getentropy.p != NULL) | ||||||
|  | -        return p_getentropy.f(buf, buflen) == 0 ? (ssize_t)buflen : -1; | ||||||
|  | -#  endif | ||||||
|  | +/*     } */ | ||||||
|  | +/* #  elif defined(__APPLE__) */ | ||||||
|  | +/*     if (CCRandomGenerateBytes(buf, buflen) == kCCSuccess) */ | ||||||
|  | +/* 	    return (ssize_t)buflen; */ | ||||||
|  | + | ||||||
|  | +/*     return -1; */ | ||||||
|  | +/* #  else */ | ||||||
|  | +/*     union { */ | ||||||
|  | +/*         void *p; */ | ||||||
|  | +/*         int (*f)(void *buffer, size_t length); */ | ||||||
|  | +/*     } p_getentropy; */ | ||||||
|  | + | ||||||
|  | +/*     /\* */ | ||||||
|  | +/*      * We could cache the result of the lookup, but we normally don't */ | ||||||
|  | +/*      * call this function often. */ | ||||||
|  | +/*      *\/ */ | ||||||
|  | +/*     ERR_set_mark(); */ | ||||||
|  | +/*     p_getentropy.p = DSO_global_lookup("getentropy"); */ | ||||||
|  | +/*     ERR_pop_to_mark(); */ | ||||||
|  | +/*     if (p_getentropy.p != NULL) */ | ||||||
|  | +/*         return p_getentropy.f(buf, buflen) == 0 ? (ssize_t)buflen : -1; */ | ||||||
|  | +/* #  endif */ | ||||||
|  |   | ||||||
|  |      /* Linux supports this since version 3.17 */ | ||||||
|  |  #  if defined(__linux) && defined(__NR_getrandom) | ||||||
|  | @@ -635,12 +635,12 @@ | ||||||
|  |   */ | ||||||
|  |  size_t rand_pool_acquire_entropy(RAND_POOL *pool) | ||||||
|  |  { | ||||||
|  | -#  if defined(OPENSSL_RAND_SEED_NONE) | ||||||
|  | -    return rand_pool_entropy_available(pool); | ||||||
|  | -#  else | ||||||
|  | +/* #  if defined(OPENSSL_RAND_SEED_NONE) */ | ||||||
|  | +/*     return rand_pool_entropy_available(pool); */ | ||||||
|  | +/* #  else */ | ||||||
|  |      size_t entropy_available; | ||||||
|  |   | ||||||
|  | -#   if defined(OPENSSL_RAND_SEED_GETRANDOM) | ||||||
|  | +/* #   if defined(OPENSSL_RAND_SEED_GETRANDOM) */ | ||||||
|  |      { | ||||||
|  |          size_t bytes_needed; | ||||||
|  |          unsigned char *buffer; | ||||||
|  | @@ -664,7 +664,7 @@ | ||||||
|  |      entropy_available = rand_pool_entropy_available(pool); | ||||||
|  |      if (entropy_available > 0) | ||||||
|  |          return entropy_available; | ||||||
|  | -#   endif | ||||||
|  | +/* #   endif */ | ||||||
|  |   | ||||||
|  |  #   if defined(OPENSSL_RAND_SEED_LIBRANDOM) | ||||||
|  |      { | ||||||
|  | @@ -752,7 +752,7 @@ | ||||||
|  |  #   endif | ||||||
|  |   | ||||||
|  |      return rand_pool_entropy_available(pool); | ||||||
|  | -#  endif | ||||||
|  | +/* #  endif */ | ||||||
|  |  } | ||||||
|  |  # endif | ||||||
|  |  #endif | ||||||
|  | diff '--color=auto' -ruN openssl-1.1.1l/test/drbgtest.c patch-1.1.1l/test/drbgtest.c | ||||||
|  | --- openssl-1.1.1l/test/drbgtest.c	2021-08-24 09:38:47.000000000 -0400 | ||||||
|  | +++ patch-1.1.1l/test/drbgtest.c	2021-09-12 02:07:38.062332301 -0400 | ||||||
|  | @@ -22,8 +22,21 @@ | ||||||
|  |  # include <windows.h> | ||||||
|  |  #endif | ||||||
|  |   | ||||||
|  | +#ifndef HAVE_FORK | ||||||
|  | +# if defined(OPENSSL_SYS_VMS) || defined(OPENSSL_SYS_WINDOWS) || defined(OPENSSL_SYS_VXWORKS) | ||||||
|  | +#  define HAVE_FORK 0 | ||||||
|  | +# else | ||||||
|  | +#  define HAVE_FORK 1 | ||||||
|  | +# endif | ||||||
|  | +#endif | ||||||
|  | + | ||||||
|  | +#if HAVE_FORK | ||||||
|  | +# undef NO_FORK | ||||||
|  | +#else | ||||||
|  | +# define NO_FORK | ||||||
|  | +#endif | ||||||
|  |   | ||||||
|  | -#if defined(OPENSSL_SYS_UNIX) | ||||||
|  | +#if defined(OPENSSL_SYS_UNIX) && !defined(NO_FORK) | ||||||
|  |  # include <sys/types.h> | ||||||
|  |  # include <sys/wait.h> | ||||||
|  |  # include <unistd.h> | ||||||
|  | @@ -676,7 +689,7 @@ | ||||||
|  |  } | ||||||
|  |   | ||||||
|  |   | ||||||
|  | -#if defined(OPENSSL_SYS_UNIX) | ||||||
|  | +#if defined(OPENSSL_SYS_UNIX) && !defined(NO_FORK) | ||||||
|  |  /* | ||||||
|  |   * Test whether master, public and private DRBG are reseeded after | ||||||
|  |   * forking the process. | ||||||
|  | @@ -795,7 +808,7 @@ | ||||||
|  |          goto error; | ||||||
|  |      reset_drbg_hook_ctx(); | ||||||
|  |   | ||||||
|  | -#if defined(OPENSSL_SYS_UNIX) | ||||||
|  | +#if defined(OPENSSL_SYS_UNIX) && !defined(NO_FORK) | ||||||
|  |      if (!TEST_true(test_drbg_reseed_after_fork(master, public, private))) | ||||||
|  |          goto error; | ||||||
|  |  #endif | ||||||
|  | diff '--color=auto' -ruN openssl-1.1.1l/test/run_tests.pl patch-1.1.1l/test/run_tests.pl | ||||||
|  | --- openssl-1.1.1l/test/run_tests.pl	2021-08-24 09:38:47.000000000 -0400 | ||||||
|  | +++ patch-1.1.1l/test/run_tests.pl	2021-09-12 02:03:57.603451471 -0400 | ||||||
|  | @@ -28,7 +28,7 @@ | ||||||
|  |  my $recipesdir = catdir($srctop, "test", "recipes"); | ||||||
|  |  my $libdir = rel2abs(catdir($srctop, "util", "perl")); | ||||||
|  |   | ||||||
|  | -$ENV{OPENSSL_CONF} = catdir($srctop, "apps", "openssl.cnf"); | ||||||
|  | +$ENV{OPENSSL_CONF} = rel2abs(catdir($srctop, "apps", "openssl.cnf")); | ||||||
|  |   | ||||||
|  |  my %tapargs = | ||||||
|  |      ( verbosity => $ENV{VERBOSE} || $ENV{V} || $ENV{HARNESS_VERBOSE} ? 1 : 0, | ||||||
|  | diff '--color=auto' -ruN openssl-1.1.1l/util/perl/OpenSSL/Test.pm patch-1.1.1l/util/perl/OpenSSL/Test.pm | ||||||
|  | --- openssl-1.1.1l/util/perl/OpenSSL/Test.pm	2021-08-24 09:38:47.000000000 -0400 | ||||||
|  | +++ patch-1.1.1l/util/perl/OpenSSL/Test.pm	2021-09-12 02:01:14.155136681 -0400 | ||||||
|  | @@ -65,7 +65,7 @@ | ||||||
|  |                               rel2abs/; | ||||||
|  |  use File::Path 2.00 qw/rmtree mkpath/; | ||||||
|  |  use File::Basename; | ||||||
|  | -use Cwd qw/getcwd abs_path/; | ||||||
|  | +use Cwd qw/abs_path/; | ||||||
|  |   | ||||||
|  |  my $level = 0; | ||||||
|  |   | ||||||
|  | @@ -904,26 +904,26 @@ | ||||||
|  |      BAIL_OUT("Must run setup() first") if (! $test_name); | ||||||
|  |   | ||||||
|  |      my $f = pop; | ||||||
|  | -    return abs2rel(catfile($directories{SRCTOP},@_,$f),getcwd); | ||||||
|  | +    return catfile($directories{SRCTOP},@_,$f); | ||||||
|  |  } | ||||||
|  |   | ||||||
|  |  sub __srctop_dir { | ||||||
|  |      BAIL_OUT("Must run setup() first") if (! $test_name); | ||||||
|  |   | ||||||
|  | -    return abs2rel(catdir($directories{SRCTOP},@_), getcwd); | ||||||
|  | +    return catdir($directories{SRCTOP},@_); | ||||||
|  |  } | ||||||
|  |   | ||||||
|  |  sub __bldtop_file { | ||||||
|  |      BAIL_OUT("Must run setup() first") if (! $test_name); | ||||||
|  |   | ||||||
|  |      my $f = pop; | ||||||
|  | -    return abs2rel(catfile($directories{BLDTOP},@_,$f), getcwd); | ||||||
|  | +    return catfile($directories{BLDTOP},@_,$f); | ||||||
|  |  } | ||||||
|  |   | ||||||
|  |  sub __bldtop_dir { | ||||||
|  |      BAIL_OUT("Must run setup() first") if (! $test_name); | ||||||
|  |   | ||||||
|  | -    return abs2rel(catdir($directories{BLDTOP},@_), getcwd); | ||||||
|  | +    return catdir($directories{BLDTOP},@_); | ||||||
|  |  } | ||||||
|  |   | ||||||
|  |  # __exeext is a function that returns the platform dependent file extension | ||||||
							
								
								
									
										104
									
								
								facho/cli.py
									
									
									
									
									
								
							
							
						
						
									
										104
									
								
								facho/cli.py
									
									
									
									
									
								
							| @@ -200,6 +200,18 @@ def validate_invoice(invoice_path): | |||||||
|     XSD.validate(content, XSD.UBLInvoice) |     XSD.validate(content, XSD.UBLInvoice) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | @click.command() | ||||||
|  | @click.argument('nomina_path') | ||||||
|  | def validate_nominaindividual(nomina_path): | ||||||
|  |     from facho.fe.data.dian import XSD | ||||||
|  |     content = open(nomina_path, 'r').read() | ||||||
|  |     content = content.replace( | ||||||
|  |         'xmlns="http://www.dian.gov.co/contratos/facturaelectronica/v1"', | ||||||
|  |         'xmlns="dian:gov:co:facturaelectronica:NominaIndividual"', | ||||||
|  |     ) | ||||||
|  |     XSD.validate(content, XSD.NominaIndividual) | ||||||
|  |  | ||||||
|  |  | ||||||
| @click.command() | @click.command() | ||||||
| @click.option('--private-key', type=click.Path(exists=True)) | @click.option('--private-key', type=click.Path(exists=True)) | ||||||
| @click.option('--passphrase') | @click.option('--passphrase') | ||||||
| @@ -215,7 +227,7 @@ def sign_xml(private_key, passphrase, xmlfile, ssl=True, use_cache_policy=False, | |||||||
|     if use_cache_policy: |     if use_cache_policy: | ||||||
|         warnings.warn("xades using cache policy") |         warnings.warn("xades using cache policy") | ||||||
|  |  | ||||||
|     signer = fe.DianXMLExtensionSigner(private_key, passphrase=passphrase, mockpolicy=use_cache_policy) |     signer = fe.DianXMLExtensionSigner(private_key, passphrase=passphrase, localpolicy=use_cache_policy) | ||||||
|     document = open(xmlfile, 'r').read().encode('utf-8') |     document = open(xmlfile, 'r').read().encode('utf-8') | ||||||
|     with open(output, 'w') as f: |     with open(output, 'w') as f: | ||||||
|         f.write(signer.sign_xml_string(document)) |         f.write(signer.sign_xml_string(document)) | ||||||
| @@ -247,14 +259,14 @@ def generate_invoice(private_key, passphrase, scriptname, generate=False, ssl=Tr | |||||||
|     spec.loader.exec_module(module) |     spec.loader.exec_module(module) | ||||||
|  |  | ||||||
|     import facho.fe.form as form |     import facho.fe.form as form | ||||||
|     from facho.fe.form_xml import DIANInvoiceXML, DIANWriteSigned,DIANWrite |     from facho.fe.form_xml import DIANInvoiceXML, DIANWriteSigned, DIANWrite, DIANSupportDocumentXML | ||||||
|     from facho import fe |     from facho import fe | ||||||
|  |  | ||||||
|     try: |     try: | ||||||
|         invoice_xml = module.document_xml() |         invoice_xml = module.document_xml() | ||||||
|     except AttributeError: |     except AttributeError: | ||||||
|         invoice_xml = DIANInvoiceXML |         #invoice_xml = DIANInvoiceXML | ||||||
|  |         invoice_xml = DIANSupportDocumentXML  | ||||||
|     print("Using document xml:", invoice_xml) |     print("Using document xml:", invoice_xml) | ||||||
|     invoice = module.invoice() |     invoice = module.invoice() | ||||||
|     invoice.calculate() |     invoice.calculate() | ||||||
| @@ -271,6 +283,65 @@ def generate_invoice(private_key, passphrase, scriptname, generate=False, ssl=Tr | |||||||
|         else: |         else: | ||||||
|             DIANWrite(xml, output) |             DIANWrite(xml, output) | ||||||
|  |  | ||||||
|  | @click.command() | ||||||
|  | @click.option('--private-key', type=click.Path(exists=True)) | ||||||
|  | @click.option('--passphrase') | ||||||
|  | @click.option('--ssl/--no-ssl', default=False) | ||||||
|  | @click.option('--sign/--no-sign', default=False) | ||||||
|  | @click.option('--use-cache-policy/--no-use-cache-policy', default=False) | ||||||
|  | @click.argument('scriptname', type=click.Path(exists=True), required=True) | ||||||
|  | @click.argument('output', required=True) | ||||||
|  | def generate_nomina(private_key, passphrase, scriptname, ssl=True, sign=False, use_cache_policy=False, output=None): | ||||||
|  |     """ | ||||||
|  |     imprime xml en pantalla. | ||||||
|  |     SCRIPTNAME espera | ||||||
|  |      def nomina() -> fe.nomina.NominaIndividual | ||||||
|  |      def extensions(fe.nomina.NominaIndividual): -> List[facho.FachoXMLExtension] | ||||||
|  |     """ | ||||||
|  |  | ||||||
|  |     if not ssl: | ||||||
|  |         disable_ssl() | ||||||
|  |  | ||||||
|  |     import importlib.util | ||||||
|  |  | ||||||
|  |     spec = importlib.util.spec_from_file_location('nomina', scriptname) | ||||||
|  |     module = importlib.util.module_from_spec(spec) | ||||||
|  |     spec.loader.exec_module(module) | ||||||
|  |  | ||||||
|  |     from facho.fe.form_xml import DIANWriteSigned, DIANWrite | ||||||
|  |     import facho.fe | ||||||
|  |  | ||||||
|  |     nomina = module.nomina() | ||||||
|  |  | ||||||
|  |     xml = nomina.toFachoXML() | ||||||
|  |  | ||||||
|  |     extensions = module.extensions(nomina) | ||||||
|  |     for extension in extensions: | ||||||
|  |         xml.add_extension(extension) | ||||||
|  |  | ||||||
|  |     if sign: | ||||||
|  |         DIANWriteSigned(xml, output, private_key, passphrase, use_cache_policy, dian_signer=facho.fe.nomina.DianXMLExtensionSigner) | ||||||
|  |     else: | ||||||
|  |         DIANWrite(xml, output) | ||||||
|  |  | ||||||
|  | @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_nomina_sync(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.SendNominaSync | ||||||
|  |     if habilitacion: | ||||||
|  |         req = dian.Habilitacion.SendNominaSync | ||||||
|  |     resp = client.request(req( | ||||||
|  |         open(zipfile, 'rb').read() | ||||||
|  |     )) | ||||||
|  |     print(resp) | ||||||
|  |  | ||||||
| @click.command() | @click.command() | ||||||
| @click.option('--private-key', type=click.Path(exists=True)) | @click.option('--private-key', type=click.Path(exists=True)) | ||||||
| @@ -287,7 +358,7 @@ def sign_verify_xml(private_key, passphrase, xmlfile, ssl=True, use_cache_policy | |||||||
|         warnings.warn("xades using cache policy") |         warnings.warn("xades using cache policy") | ||||||
|  |  | ||||||
|     print("THIS ONLY WORKS FOR DOCUMENTS GENERATE WITH FACHO") |     print("THIS ONLY WORKS FOR DOCUMENTS GENERATE WITH FACHO") | ||||||
|     signer = fe.DianXMLExtensionSignerVerifier(private_key, passphrase=passphrase, mockpolicy=use_cache_policy) |     signer = fe.DianXMLExtensionSignerVerifier(private_key, passphrase=passphrase, localpolicy=use_cache_policy) | ||||||
|     document = open(xmlfile, 'r').read().encode('utf-8') |     document = open(xmlfile, 'r').read().encode('utf-8') | ||||||
|  |  | ||||||
|     if signer.verify_string(document): |     if signer.verify_string(document): | ||||||
| @@ -295,6 +366,25 @@ def sign_verify_xml(private_key, passphrase, xmlfile, ssl=True, use_cache_policy | |||||||
|     else: |     else: | ||||||
|         print("-INVALID") |         print("-INVALID") | ||||||
|  |  | ||||||
|  | @click.command() | ||||||
|  | @click.option('--software-id') | ||||||
|  | @click.option('--software-pin') | ||||||
|  | @click.option('--nit') | ||||||
|  | @click.option('--dv') | ||||||
|  | @click.option('--output-zippath') | ||||||
|  | def generate_nomina_habilitacion(software_id, software_pin, nit, dv, output_zippath): | ||||||
|  |     from facho import fe | ||||||
|  |  | ||||||
|  |     generador = fe.nomina.habilitacion.Habilitacion( | ||||||
|  |         fe.nomina.habilitacion.Habilitacion.Metadata( | ||||||
|  |             software_id=software_id, | ||||||
|  |             software_pin=software_pin, | ||||||
|  |             nit=nit, | ||||||
|  |             dv=dv | ||||||
|  |         ) | ||||||
|  |     ) | ||||||
|  |     generador.generar(output_zippath) | ||||||
|  |  | ||||||
| @click.group() | @click.group() | ||||||
| def main(): | def main(): | ||||||
|     pass |     pass | ||||||
| @@ -310,3 +400,7 @@ main.add_command(generate_invoice) | |||||||
| main.add_command(validate_invoice) | main.add_command(validate_invoice) | ||||||
| main.add_command(sign_xml) | main.add_command(sign_xml) | ||||||
| main.add_command(sign_verify_xml) | main.add_command(sign_verify_xml) | ||||||
|  | main.add_command(generate_nomina) | ||||||
|  | main.add_command(soap_send_nomina_sync) | ||||||
|  | main.add_command(validate_nominaindividual) | ||||||
|  | main.add_command(generate_nomina_habilitacion) | ||||||
|   | |||||||
							
								
								
									
										291
									
								
								facho/facho.py
									
									
									
									
									
								
							
							
						
						
									
										291
									
								
								facho/facho.py
									
									
									
									
									
								
							| @@ -1,9 +1,15 @@ | |||||||
| # This file is part of facho.  The COPYRIGHT file at the top level of | # This file is part of facho.  The COPYRIGHT file at the top level of | ||||||
| # this repository contains the full copyright notices and license terms. | # this repository contains the full copyright notices and license terms. | ||||||
|  |  | ||||||
| from lxml import etree | from lxml import etree | ||||||
| from lxml.etree import Element, SubElement, tostring | from lxml.etree import Element, tostring | ||||||
| import re | import re | ||||||
|  | from collections import defaultdict | ||||||
|  | from copy import deepcopy | ||||||
|  |  | ||||||
|  |  | ||||||
|  | class FachoValueInvalid(Exception): | ||||||
|  |     def __init__(self, xpath): | ||||||
|  |         super().__init__('FachoValueInvalid invalid xpath %s' % (xpath)) | ||||||
|  |  | ||||||
|  |  | ||||||
| class FachoXMLExtension: | class FachoXMLExtension: | ||||||
| @@ -25,7 +31,10 @@ class LXMLBuilder: | |||||||
|  |  | ||||||
|     def __init__(self, nsmap): |     def __init__(self, nsmap): | ||||||
|         self.nsmap = nsmap |         self.nsmap = nsmap | ||||||
|         self._re_node_expr = re.compile(r'^(?P<path>((?P<ns>\w+):)?(?P<tag>[a-zA-Z0-9_-]+))(?P<attrs>\[.+\])?') |         self._re_node_expr = \ | ||||||
|  |             re.compile( | ||||||
|  |                 r'^(?P<path>((?P<ns>\w+):)?(?P<tag>[a-zA-Z0-9_-]+))' | ||||||
|  |                 r'(?P<attrs>\[.+\])?') | ||||||
|         self._re_attrs = re.compile(r'(\w+)\s*=\s*\"?(\w+)\"?') |         self._re_attrs = re.compile(r'(\w+)\s*=\s*\"?(\w+)\"?') | ||||||
|  |  | ||||||
|     def match_expression(self, node_expr): |     def match_expression(self, node_expr): | ||||||
| @@ -82,15 +91,21 @@ class LXMLBuilder: | |||||||
|     def append(self, elem, child): |     def append(self, elem, child): | ||||||
|         elem.append(child) |         elem.append(child) | ||||||
|  |  | ||||||
|  |     def append_next(self, elem, slibing): | ||||||
|  |         elem.addnext(slibing) | ||||||
|  |  | ||||||
|     def remove(self, elem): |     def remove(self, elem): | ||||||
|         elem.getparent().remove(elem) |         elem.getparent().remove(elem) | ||||||
|  |  | ||||||
|     def set_text(self, elem, text): |     def set_text(self, elem, text): | ||||||
|         elem.text = text |         elem.text = text | ||||||
|  |  | ||||||
|     def xpath(self, elem, xpath): |     def xpath(self, elem, xpath, multiple=False): | ||||||
|         elems = elem.xpath(xpath, namespaces=self.nsmap) |         elems = elem.xpath(xpath, namespaces=self.nsmap) | ||||||
|         if elems: |         if elems: | ||||||
|  |             if multiple: | ||||||
|  |                 return elems | ||||||
|  |             else: | ||||||
|                 return elems[0] |                 return elems[0] | ||||||
|  |  | ||||||
|         return None |         return None | ||||||
| @@ -98,13 +113,42 @@ class LXMLBuilder: | |||||||
|     def get_text(self, elem): |     def get_text(self, elem): | ||||||
|         return elem.text |         return elem.text | ||||||
|  |  | ||||||
|  |     def get_attribute(self, elem, key): | ||||||
|  |         return elem.attrib[key] | ||||||
|  |  | ||||||
|  |     def is_attribute(self, elem, key, value): | ||||||
|  |         return elem.get(key, False) == value | ||||||
|  |  | ||||||
|     def set_attribute(self,  elem, key, value): |     def set_attribute(self,  elem, key, value): | ||||||
|         elem.attrib[key] = value |         elem.attrib[key] = value | ||||||
|  |  | ||||||
|     @classmethod |     @classmethod | ||||||
|     def tostring(self, elem, **attrs): |     def remove_attributes(cls, elem, keys, exclude=[]): | ||||||
|  |         for key in keys: | ||||||
|  |             if key in exclude: | ||||||
|  |                 continue | ||||||
|  |  | ||||||
|  |             try: | ||||||
|  |                 del elem.attrib[key] | ||||||
|  |             except KeyError: | ||||||
|  |                 pass | ||||||
|  |  | ||||||
|  |     @classmethod | ||||||
|  |     def tostring(self, oelem, **attrs): | ||||||
|  |         elem = deepcopy(oelem) | ||||||
|  |  | ||||||
|         attrs['pretty_print'] = attrs.pop('pretty_print', False) |         attrs['pretty_print'] = attrs.pop('pretty_print', False) | ||||||
|         attrs['encoding'] = attrs.pop('encoding', 'UTF-8') |         attrs['encoding'] = attrs.pop('encoding', 'UTF-8') | ||||||
|  |  | ||||||
|  |         for el in elem.getiterator(): | ||||||
|  |             keys = filter(lambda key: key.startswith('facho_'), el.keys()) | ||||||
|  |             self.remove_attributes(el, keys, exclude=['facho_optional']) | ||||||
|  |  | ||||||
|  |             is_optional = el.get('facho_optional', 'False') == 'True' | ||||||
|  |             if is_optional and el.getchildren() == [] and el.keys() == [ | ||||||
|  |                     'facho_optional']: | ||||||
|  |                 el.getparent().remove(el) | ||||||
|  |  | ||||||
|         return tostring(elem, **attrs).decode('utf-8') |         return tostring(elem, **attrs).decode('utf-8') | ||||||
|  |  | ||||||
|  |  | ||||||
| @@ -112,7 +156,8 @@ class FachoXML: | |||||||
|     """ |     """ | ||||||
|     Decora XML con funciones de consulta XPATH de un solo elemento |     Decora XML con funciones de consulta XPATH de un solo elemento | ||||||
|     """ |     """ | ||||||
|     def __init__(self, root, builder=None, nsmap=None, fragment_prefix=''): |     def __init__(self, root, builder=None, nsmap=None, fragment_prefix='', | ||||||
|  |                  fragment_root_element=None): | ||||||
|         if builder is None: |         if builder is None: | ||||||
|             self.builder = LXMLBuilder(nsmap) |             self.builder = LXMLBuilder(nsmap) | ||||||
|         else: |         else: | ||||||
| @@ -125,15 +170,23 @@ class FachoXML: | |||||||
|         else: |         else: | ||||||
|             self.root = root |             self.root = root | ||||||
|  |  | ||||||
|  |         self.fragment_root_element = fragment_root_element | ||||||
|         self.fragment_prefix = fragment_prefix |         self.fragment_prefix = fragment_prefix | ||||||
|         self.xpath_for = {} |         self.xpath_for = {} | ||||||
|         self.extensions = [] |         self.extensions = [] | ||||||
|  |         self._validators = defaultdict(lambda: lambda v, attrs: True) | ||||||
|  |  | ||||||
|     @classmethod |     @classmethod | ||||||
|     def from_string(cls, document: str, namespaces: dict() = []) -> 'FachoXML': |     def from_string(cls, document: str, namespaces: dict() = []) -> 'FachoXML': | ||||||
|         xml = LXMLBuilder.from_string(document) |         xml = LXMLBuilder.from_string(document) | ||||||
|         return FachoXML(xml, nsmap=namespaces) |         return FachoXML(xml, nsmap=namespaces) | ||||||
|  |  | ||||||
|  |     def root_namespace(self): | ||||||
|  |         return etree.QName(self.root).namespace | ||||||
|  |  | ||||||
|  |     def root_localname(self): | ||||||
|  |         return etree.QName(self.root).localname | ||||||
|  |  | ||||||
|     def append_element(self, elem, new_elem): |     def append_element(self, elem, new_elem): | ||||||
|         # elem = self.find_or_create_element(xpath, append=append) |         # elem = self.find_or_create_element(xpath, append=append) | ||||||
|         # self.builder.append(elem, new_elem) |         # self.builder.append(elem, new_elem) | ||||||
| @@ -142,8 +195,8 @@ class FachoXML: | |||||||
|     def add_extension(self, extension): |     def add_extension(self, extension): | ||||||
|         extension.build(self) |         extension.build(self) | ||||||
|  |  | ||||||
|  |     def fragment( | ||||||
|     def fragment(self, xpath, append=False, append_not_exists=False): |             self, xpath, append=False, append_not_exists=False): | ||||||
|         nodes = xpath.split('/') |         nodes = xpath.split('/') | ||||||
|         nodes.pop() |         nodes.pop() | ||||||
|         root_prefix = '/'.join(nodes) |         root_prefix = '/'.join(nodes) | ||||||
| @@ -153,7 +206,9 @@ class FachoXML: | |||||||
|  |  | ||||||
|         if parent is None: |         if parent is None: | ||||||
|             parent = self.find_or_create_element(xpath, append=append) |             parent = self.find_or_create_element(xpath, append=append) | ||||||
|         return FachoXML(parent, nsmap=self.nsmap, fragment_prefix=root_prefix) |         return FachoXML( | ||||||
|  |             parent, nsmap=self.nsmap, fragment_prefix=root_prefix, | ||||||
|  |             fragment_root_element=self.root) | ||||||
|  |  | ||||||
|     def register_alias_xpath(self, alias, xpath): |     def register_alias_xpath(self, alias, xpath): | ||||||
|         self.xpath_for[alias] = xpath |         self.xpath_for[alias] = xpath | ||||||
| @@ -169,8 +224,12 @@ class FachoXML: | |||||||
|     def _path_xpath_for(self, xpath): |     def _path_xpath_for(self, xpath): | ||||||
|         return self._normalize_xpath(self._translate_xpath_for(xpath)) |         return self._normalize_xpath(self._translate_xpath_for(xpath)) | ||||||
|  |  | ||||||
|     def placeholder_for(self, xpath, append=False): |     def placeholder_for(self, xpath, append=False, optional=False): | ||||||
|         return self.find_or_create_element(xpath, append) |         elem = self.find_or_create_element(xpath, append) | ||||||
|  |         if optional: | ||||||
|  |             elem.set('facho_optional', 'True') | ||||||
|  |         elem.set('facho_placeholder', 'True') | ||||||
|  |         return elem | ||||||
|  |  | ||||||
|     def replacement_for(self, xpath, new_xpath, content, **attrs): |     def replacement_for(self, xpath, new_xpath, content, **attrs): | ||||||
|         elem = self.get_element(xpath) |         elem = self.get_element(xpath) | ||||||
| @@ -185,7 +244,8 @@ class FachoXML: | |||||||
|         """ |         """ | ||||||
|         xpath = self._path_xpath_for(xpath) |         xpath = self._path_xpath_for(xpath) | ||||||
|         node_paths = xpath.split('/') |         node_paths = xpath.split('/') | ||||||
|         node_paths.pop(0) #remove empty / |         # remove empty / | ||||||
|  |         node_paths.pop(0) | ||||||
|         root_tag = node_paths.pop(0) |         root_tag = node_paths.pop(0) | ||||||
|  |  | ||||||
|         root_node = self.builder.build_from_expression(root_tag) |         root_node = self.builder.build_from_expression(root_tag) | ||||||
| @@ -195,16 +255,19 @@ class FachoXML: | |||||||
|             root_node = self.root |             root_node = self.root | ||||||
|  |  | ||||||
|         if not self.builder.same_tag(root_node.tag, self.root.tag): |         if not self.builder.same_tag(root_node.tag, self.root.tag): | ||||||
|              |             raise ValueError('xpath %s must be absolute to /%s' % ( | ||||||
|             raise ValueError('xpath %s must be absolute to /%s' % (xpath, self.root.tag)) |                 xpath, self.root.tag)) | ||||||
|  |  | ||||||
|         # crea jerarquia segun xpath indicado |         # crea jerarquia segun xpath indicado | ||||||
|         parent = None |         parent = None | ||||||
|         current_elem = self.root |         current_elem = self.root | ||||||
|  |         node_tag = node_paths.pop(-1) | ||||||
|  |  | ||||||
|         for node_path in node_paths: |         for node_path in node_paths: | ||||||
|             node_expr = self.builder.match_expression(node_path) |             node_expr = self.builder.match_expression(node_path) | ||||||
|             node = self.builder.build_from_expression(node_path) |             node = self.builder.build_from_expression(node_path) | ||||||
|             child = self.builder.find_relative(current_elem, node_expr['path'], self.nsmap) |             child = self.builder.find_relative( | ||||||
|  |                 current_elem, node_expr['path'], self.nsmap) | ||||||
|  |  | ||||||
|             parent = current_elem |             parent = current_elem | ||||||
|             if child is not None: |             if child is not None: | ||||||
| @@ -213,15 +276,61 @@ class FachoXML: | |||||||
|                 self.builder.append(current_elem, node) |                 self.builder.append(current_elem, node) | ||||||
|                 current_elem = node |                 current_elem = node | ||||||
|  |  | ||||||
|         # se fuerza la adicion como un nuevo elemento |         node_expr = self.builder.match_expression(node_tag) | ||||||
|         if append: |         node = self.builder.build_from_expression(node_tag) | ||||||
|             node = self.builder.build_from_expression(node_paths[-1]) |         child = self.builder.find_relative( | ||||||
|  |             current_elem, node_expr['path'], self.nsmap) | ||||||
|  |         parent = current_elem | ||||||
|  |         if child is not None: | ||||||
|  |             current_elem = child | ||||||
|  |  | ||||||
|  |         if parent == current_elem: | ||||||
|             self.builder.append(parent, node) |             self.builder.append(parent, node) | ||||||
|             return node |             return node | ||||||
|  |  | ||||||
|  |         # se fuerza la adicion como un nuevo elemento | ||||||
|  |         if append: | ||||||
|  |             last_slibing = None | ||||||
|  |             for child in parent.getchildren(): | ||||||
|  |                 if child.tag == node_tag: | ||||||
|  |                     last_slibing = child | ||||||
|  |  | ||||||
|  |             # si no ahi primos se adiciona como hijo | ||||||
|  |             if last_slibing is None: | ||||||
|  |                 self.builder.append(parent, node) | ||||||
|  |                 return node | ||||||
|  |  | ||||||
|  |             if self.builder.is_attribute( | ||||||
|  |                     last_slibing, 'facho_placeholder', 'True'): | ||||||
|  |                 self._remove_facho_attributes(last_slibing) | ||||||
|  |                 return last_slibing | ||||||
|  |             self.builder.append_next(last_slibing, node) | ||||||
|  |             return node | ||||||
|  |  | ||||||
|  |         if child is None: | ||||||
|  |             self.builder.append(current_elem, node) | ||||||
|  |             return node | ||||||
|  |  | ||||||
|  |         self._remove_facho_attributes(current_elem) | ||||||
|         return current_elem |         return current_elem | ||||||
|  |  | ||||||
|     def set_element(self, xpath, content, **attrs): |     def set_element_validator( | ||||||
|  |             self, xpath, validator=False): | ||||||
|  |         """ | ||||||
|  |         validador al asignar contenido a xpath indicado | ||||||
|  |  | ||||||
|  |         @param xpath ruta tipo XPath | ||||||
|  |         @param validator callback(content, attributes) | ||||||
|  |         """ | ||||||
|  |  | ||||||
|  |         key = self._path_xpath_for(xpath) | ||||||
|  |         if not validator: | ||||||
|  |             self._validators[key] = lambda v, attrs: True | ||||||
|  |         else: | ||||||
|  |             self._validators[key] = validator | ||||||
|  |  | ||||||
|  |     def set_element( | ||||||
|  |             self, xpath, content, **attrs): | ||||||
|         """ |         """ | ||||||
|         asigna contenido ubicado por ruta tipo XPATH. |         asigna contenido ubicado por ruta tipo XPATH. | ||||||
|         @param xpath ruta tipo XPATH |         @param xpath ruta tipo XPATH | ||||||
| @@ -232,10 +341,18 @@ class FachoXML: | |||||||
|         format_ = attrs.pop('format_', '%s') |         format_ = attrs.pop('format_', '%s') | ||||||
|         append_ = attrs.pop('append_', False) |         append_ = attrs.pop('append_', False) | ||||||
|         elem = self.find_or_create_element(xpath, append=append_) |         elem = self.find_or_create_element(xpath, append=append_) | ||||||
|  |  | ||||||
|  |         validator = self._validators[xpath] | ||||||
|  |  | ||||||
|  |         if not validator(content, attrs): | ||||||
|  |             raise FachoValueInvalid(xpath) | ||||||
|  |  | ||||||
|         if content: |         if content: | ||||||
|             self.builder.set_text(elem, format_ % content) |             self.builder.set_text(elem, format_ % content) | ||||||
|         for k, v in attrs.items(): |         for k, v in attrs.items(): | ||||||
|             self.builder.set_attribute(elem, k, v) |             if v is not None or str(v) != 'None': | ||||||
|  |                 self.builder.set_attribute(elem, k, str(v)) | ||||||
|  |  | ||||||
|         return elem |         return elem | ||||||
|  |  | ||||||
|     def set_attributes(self, xpath, **attrs): |     def set_attributes(self, xpath, **attrs): | ||||||
| @@ -246,25 +363,143 @@ class FachoXML: | |||||||
|         """ |         """ | ||||||
|         xpath = self._path_xpath_for(xpath) |         xpath = self._path_xpath_for(xpath) | ||||||
|         elem = self.get_element(xpath) |         elem = self.get_element(xpath) | ||||||
|  |  | ||||||
|  |         if elem is None: | ||||||
|  |             raise ValueError("xpath %s not found" % (xpath)) | ||||||
|  |  | ||||||
|         for k, v in attrs.items(): |         for k, v in attrs.items(): | ||||||
|             self.builder.set_attribute(elem, k, v) |             if v is not None or str(v) != 'None': | ||||||
|  |                 self.builder.set_attribute(elem, k, str(v)) | ||||||
|         return self |         return self | ||||||
|  |  | ||||||
|     def get_element(self, xpath): |     def get_element_attribute( | ||||||
|         xpath = self.fragment_prefix + self._path_xpath_for(xpath) |             self, xpath, attribute, multiple=False): | ||||||
|         return self.builder.xpath(self.root, xpath) |         elem = self.get_element(xpath, multiple=multiple) | ||||||
|  |  | ||||||
|     def get_element_text(self, xpath, format_=str): |  | ||||||
|         xpath = self.fragment_prefix + self._path_xpath_for(xpath) |  | ||||||
|         elem = self.builder.xpath(self.root, xpath) |  | ||||||
|         if elem is None: |         if elem is None: | ||||||
|             raise AttributeError('xpath %s invalid' % (xpath)) |             raise ValueError("xpath %s not found" % (xpath)) | ||||||
|  |  | ||||||
|  |         if multiple: | ||||||
|  |             vals = [] | ||||||
|  |             for e in elem: | ||||||
|  |                 vals.append(self.builder.get_attribute(e, attribute)) | ||||||
|  |             return vals | ||||||
|  |         else: | ||||||
|  |             return self.builder.get_attribute(elem, attribute) | ||||||
|  |  | ||||||
|  |     def get_element(self, xpath, multiple=False): | ||||||
|  |         xpath = self.fragment_prefix + self._path_xpath_for(xpath) | ||||||
|  |         return self.builder.xpath(self.root, xpath, multiple=multiple) | ||||||
|  |  | ||||||
|  |     def get_element_text(self, xpath, format_=str, multiple=False): | ||||||
|  |         xpath = self.fragment_prefix + self._path_xpath_for(xpath) | ||||||
|  |         # MACHETE(bit4bit) al usar ./ queda ../ | ||||||
|  |         xpath = re.sub(r'^\.\.+', '.', xpath) | ||||||
|  |  | ||||||
|  |         elem = self.builder.xpath(self.root, xpath, multiple=multiple) | ||||||
|  |         if multiple: | ||||||
|  |             vals = [] | ||||||
|  |             for e in elem: | ||||||
|  |                 text = self.builder.get_text(e) | ||||||
|  |                 if text is not None: | ||||||
|  |                     vals.append(format_(text)) | ||||||
|  |             return vals | ||||||
|  |         else: | ||||||
|             text = self.builder.get_text(elem) |             text = self.builder.get_text(elem) | ||||||
|  |             if text is None: | ||||||
|  |                 return None | ||||||
|             return format_(text) |             return format_(text) | ||||||
|  |  | ||||||
|  |     def get_element_text_or_attribute( | ||||||
|  |             self, xpath, default=None, multiple=False, raise_on_fail=False): | ||||||
|  |         parts = xpath.split('/') | ||||||
|  |         is_attribute = parts[-1].startswith('@') | ||||||
|  |         if is_attribute: | ||||||
|  |             attribute_name = parts.pop(-1).lstrip('@') | ||||||
|  |             element_path = "/".join(parts) | ||||||
|  |             try: | ||||||
|  |                 val = self.get_element_attribute( | ||||||
|  |                     element_path, attribute_name, multiple=multiple) | ||||||
|  |                 if val is None: | ||||||
|  |                     return default | ||||||
|  |                 return val | ||||||
|  |             except KeyError as e: | ||||||
|  |                 if raise_on_fail: | ||||||
|  |                     raise e | ||||||
|  |                 return default | ||||||
|  |             except ValueError as e: | ||||||
|  |                 if raise_on_fail: | ||||||
|  |                     raise e | ||||||
|  |                 return default | ||||||
|  |         else: | ||||||
|  |             try: | ||||||
|  |                 val = self.get_element_text(xpath, multiple=multiple) | ||||||
|  |                 if val is None: | ||||||
|  |                     return default | ||||||
|  |                 return val | ||||||
|  |             except ValueError as e: | ||||||
|  |                 if raise_on_fail: | ||||||
|  |                     raise e | ||||||
|  |                 return default | ||||||
|  |  | ||||||
|  |     def get_elements_text_or_attributes(self, xpaths, raise_on_fail=True): | ||||||
|  |         """ | ||||||
|  |         returna el contenido o attributos de un conjunto de XPATHS | ||||||
|  |         si algun XPATH es una tupla se retorna el primer elemento del mismo. | ||||||
|  |         """ | ||||||
|  |         vals = [] | ||||||
|  |         for xpath in xpaths: | ||||||
|  |             if isinstance(xpath, tuple): | ||||||
|  |                 val = xpath[0] | ||||||
|  |             else: | ||||||
|  |                 val = self.get_element_text_or_attribute( | ||||||
|  |                     xpath, raise_on_fail=raise_on_fail) | ||||||
|  |             vals.append(val) | ||||||
|  |         return vals | ||||||
|  |  | ||||||
|  |     def exist_element(self, xpath): | ||||||
|  |         elem = self.get_element(xpath) | ||||||
|  |  | ||||||
|  |         # no se encontro elemento | ||||||
|  |         if elem is None: | ||||||
|  |             return False | ||||||
|  |  | ||||||
|  |         # el placeholder no ha sido populado | ||||||
|  |         if elem.get('facho_placeholder') == 'True': | ||||||
|  |             return False | ||||||
|  |  | ||||||
|  |         # el valor opcional no ha sido populado | ||||||
|  |         if elem.get('facho_optional') == 'True': | ||||||
|  |             return False | ||||||
|  |  | ||||||
|  |         return True | ||||||
|  |  | ||||||
|  |     def _remove_facho_attributes(self, elem): | ||||||
|  |         self.builder.remove_attributes( | ||||||
|  |             elem, ['facho_optional', 'facho_placeholder']) | ||||||
|  |  | ||||||
|     def tostring(self, **kw): |     def tostring(self, **kw): | ||||||
|         return self.builder.tostring(self.root, **kw) |         return self.builder.tostring(self.root, **kw) | ||||||
|  |  | ||||||
|  |     def xpath_from_root(self, xpath): | ||||||
|  |         nsmap = {} | ||||||
|  |         ns = '' | ||||||
|  |  | ||||||
|  |         root = self.root | ||||||
|  |         if self.fragment_root_element is not None: | ||||||
|  |             root = self.fragment_root_element | ||||||
|  |  | ||||||
|  |         if isinstance(self.nsmap, dict): | ||||||
|  |             nsmap = dict(map(reversed, self.nsmap.items())) | ||||||
|  |             ns = nsmap[etree.QName(root).namespace] + ':' | ||||||
|  |  | ||||||
|  |         if self.fragment_root_element is not None: | ||||||
|  |             new_xpath = '/' + ns + etree.QName(root).localname + '/' + \ | ||||||
|  |                 etree.QName(self.root).localname + '/' + xpath.lstrip('/') | ||||||
|  |         else: | ||||||
|  |             new_xpath = '/' + ns + etree.QName(root).localname + '/' + \ | ||||||
|  |                 xpath.lstrip('/') | ||||||
|  |         return new_xpath | ||||||
|  |  | ||||||
|     def __str__(self): |     def __str__(self): | ||||||
|         return self.tostring() |         return self.tostring() | ||||||
|   | |||||||
| @@ -5,6 +5,7 @@ from .fe import DianXMLExtensionSigner | |||||||
| from .fe import DianXMLExtensionSoftwareSecurityCode | from .fe import DianXMLExtensionSoftwareSecurityCode | ||||||
| from .fe import DianXMLExtensionCUFE | from .fe import DianXMLExtensionCUFE | ||||||
| from .fe import DianXMLExtensionCUDE | from .fe import DianXMLExtensionCUDE | ||||||
|  | from .fe import DianXMLExtensionCUDS | ||||||
| from .fe import DianXMLExtensionInvoiceAuthorization | from .fe import DianXMLExtensionInvoiceAuthorization | ||||||
| from .fe import DianXMLExtensionSoftwareProvider | from .fe import DianXMLExtensionSoftwareProvider | ||||||
| from .fe import DianXMLExtensionAuthorizationProvider | from .fe import DianXMLExtensionAuthorizationProvider | ||||||
| @@ -12,3 +13,4 @@ from .fe import DianZIP | |||||||
| from .fe import AMBIENTE_PRUEBAS | from .fe import AMBIENTE_PRUEBAS | ||||||
| from .fe import AMBIENTE_PRODUCCION | from .fe import AMBIENTE_PRODUCCION | ||||||
| from . import form_xml | from . import form_xml | ||||||
|  | from . import nomina | ||||||
|   | |||||||
| @@ -27,7 +27,7 @@ class SOAPService: | |||||||
|     def get_service(self): |     def get_service(self): | ||||||
|         raise NotImplementedError() |         raise NotImplementedError() | ||||||
|  |  | ||||||
|     def builder_response(self, as_dict): |     def build_response(self, as_dict): | ||||||
|         raise NotImplementedError() |         raise NotImplementedError() | ||||||
|  |  | ||||||
|     def todict(self): |     def todict(self): | ||||||
| @@ -175,6 +175,19 @@ class GetStatusZip(SOAPService): | |||||||
|     def build_response(self, as_dict): |     def build_response(self, as_dict): | ||||||
|         return GetStatusResponse.fromdict(as_dict[0]) |         return GetStatusResponse.fromdict(as_dict[0]) | ||||||
|  |  | ||||||
|  | @dataclass | ||||||
|  | class SendNominaSync(SOAPService): | ||||||
|  |     contentFile: bytes | ||||||
|  |  | ||||||
|  |     def get_wsdl(self): | ||||||
|  |         return 'https://vpfe.dian.gov.co/WcfDianCustomerServices.svc?wsdl' | ||||||
|  |  | ||||||
|  |     def get_service(self): | ||||||
|  |         return 'SendNominaSync' | ||||||
|  |  | ||||||
|  |     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' | ||||||
| @@ -203,6 +216,9 @@ class Habilitacion: | |||||||
|         def get_wsdl(self): |         def get_wsdl(self): | ||||||
|             return Habilitacion.WSDL |             return Habilitacion.WSDL | ||||||
|  |  | ||||||
|  |     class SendNominaSync(SendNominaSync): | ||||||
|  |         def get_wsdl(self): | ||||||
|  |             return Habilitacion.WSDL | ||||||
|  |  | ||||||
| class DianGateway: | class DianGateway: | ||||||
|  |  | ||||||
|   | |||||||
| @@ -9,5 +9,8 @@ def path_for_xsd(dirname, xsdname): | |||||||
|  |  | ||||||
| UBLInvoice= xmlschema.XMLSchema(path_for_xsd('maindoc', 'UBL-Invoice-2.1.xsd')) | UBLInvoice= xmlschema.XMLSchema(path_for_xsd('maindoc', 'UBL-Invoice-2.1.xsd')) | ||||||
|  |  | ||||||
|  | NominaIndividual = xmlschema.XMLSchema(path_for_xsd('nomina', 'NominaIndividualElectronicaXSDV1.0.6.xsd')) | ||||||
|  | NominaIndividualDeAjuste = xmlschema.XMLSchema(path_for_xsd('nomina', 'NominaIndividualDeAjusteElectronicaXSDV1.0.6.xsd')) | ||||||
|  |  | ||||||
| def validate(xml, schema): | def validate(xml, schema): | ||||||
|     schema.validate(xml) |     schema.validate(xml) | ||||||
|   | |||||||
							
								
								
									
										36
									
								
								facho/fe/data/dian/codelist/Idioma-2.1.gc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										36
									
								
								facho/fe/data/dian/codelist/Idioma-2.1.gc
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,36 @@ | |||||||
|  | <?xml version="1.0" encoding="UTF-8"?> | ||||||
|  | <!-- | ||||||
|  |      creado por facho, la dian tiene oficial? | ||||||
|  |      poblar usando anexo tecnico 5.3.1 | ||||||
|  | --> | ||||||
|  | <gc:CodeList xmlns:gc="http://docs.oasis-open.org/codelist/ns/genericode/1.0/"> | ||||||
|  | 	<Identification> | ||||||
|  | 		<ShortName>Idioma</ShortName> | ||||||
|  | 		<LongName xml:lang="es">Idioma</LongName> | ||||||
|  | 		<Version>1</Version> | ||||||
|  | 	</Identification> | ||||||
|  | 	<ColumnSet> | ||||||
|  | 		<Column Id="iso-639-1" Use="required"> | ||||||
|  | 			<ShortName>ISO 639 1</ShortName> | ||||||
|  | 			<Data Type="normalizedString"/> | ||||||
|  | 		</Column> | ||||||
|  | 		<Column Id="name" Use="required"> | ||||||
|  | 			<ShortName>Nombre</ShortName> | ||||||
|  | 			<Data Type="normalizedString"/> | ||||||
|  | 		</Column> | ||||||
|  | 		<Key Id="codeKey"> | ||||||
|  | 			<ShortName>CodeKey</ShortName> | ||||||
|  | 			<ColumnRef Ref="code"/> | ||||||
|  | 		</Key> | ||||||
|  | 	</ColumnSet> | ||||||
|  | 	<SimpleCodeList> | ||||||
|  | 		<Row> | ||||||
|  | 			<Value ColumnRef="iso-639-1"> | ||||||
|  | 				<SimpleValue>es</SimpleValue> | ||||||
|  | 			</Value> | ||||||
|  | 			<Value ColumnRef="name"> | ||||||
|  | 				<SimpleValue>Español, castellano</SimpleValue> | ||||||
|  | 			</Value> | ||||||
|  | 		</Row> | ||||||
|  |         </SimpleCodeList> | ||||||
|  | </gc:CodeList> | ||||||
							
								
								
									
										76
									
								
								facho/fe/data/dian/codelist/PeriodoNomina-2.1.gc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										76
									
								
								facho/fe/data/dian/codelist/PeriodoNomina-2.1.gc
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,76 @@ | |||||||
|  | <?xml version="1.0" encoding="UTF-8"?> | ||||||
|  | <!-- | ||||||
|  |      creado por facho, la dian tiene oficial? | ||||||
|  |      poblar usando anexo tecnico 5.5.1 | ||||||
|  | --> | ||||||
|  | <gc:CodeList xmlns:gc="http://docs.oasis-open.org/codelist/ns/genericode/1.0/"> | ||||||
|  | 	<Identification> | ||||||
|  | 		<ShortName>PeriodoNomina</ShortName> | ||||||
|  | 		<LongName xml:lang="es">Periodos Nomina</LongName> | ||||||
|  | 		<Version>1</Version> | ||||||
|  | 	</Identification> | ||||||
|  | 	<ColumnSet> | ||||||
|  | 		<Column Id="code" Use="required"> | ||||||
|  | 			<ShortName>Code</ShortName> | ||||||
|  | 			<Data Type="normalizedString"/> | ||||||
|  | 		</Column> | ||||||
|  | 		<Column Id="name" Use="required"> | ||||||
|  | 			<ShortName>Nombre</ShortName> | ||||||
|  | 			<Data Type="normalizedString"/> | ||||||
|  | 		</Column> | ||||||
|  | 		<Key Id="codeKey"> | ||||||
|  | 			<ShortName>CodeKey</ShortName> | ||||||
|  | 			<ColumnRef Ref="code"/> | ||||||
|  | 		</Key> | ||||||
|  | 	</ColumnSet> | ||||||
|  | 	<SimpleCodeList> | ||||||
|  | 		<Row> | ||||||
|  | 			<Value ColumnRef="code"> | ||||||
|  | 				<SimpleValue>1</SimpleValue> | ||||||
|  | 			</Value> | ||||||
|  | 			<Value ColumnRef="name"> | ||||||
|  | 				<SimpleValue>Semanal</SimpleValue> | ||||||
|  | 			</Value> | ||||||
|  | 		</Row> | ||||||
|  | 		<Row> | ||||||
|  | 			<Value ColumnRef="code"> | ||||||
|  | 				<SimpleValue>2</SimpleValue> | ||||||
|  | 			</Value> | ||||||
|  | 			<Value ColumnRef="name"> | ||||||
|  | 				<SimpleValue>Decenal</SimpleValue> | ||||||
|  | 			</Value> | ||||||
|  | 		</Row> | ||||||
|  | 		<Row> | ||||||
|  | 			<Value ColumnRef="code"> | ||||||
|  | 				<SimpleValue>3</SimpleValue> | ||||||
|  | 			</Value> | ||||||
|  | 			<Value ColumnRef="name"> | ||||||
|  | 				<SimpleValue>Catorcenal</SimpleValue> | ||||||
|  | 			</Value> | ||||||
|  | 		</Row> | ||||||
|  | 		<Row> | ||||||
|  | 			<Value ColumnRef="code"> | ||||||
|  | 				<SimpleValue>4</SimpleValue> | ||||||
|  | 			</Value> | ||||||
|  | 			<Value ColumnRef="name"> | ||||||
|  | 				<SimpleValue>Quincenal</SimpleValue> | ||||||
|  | 			</Value> | ||||||
|  | 		</Row> | ||||||
|  | 		<Row> | ||||||
|  | 			<Value ColumnRef="code"> | ||||||
|  | 				<SimpleValue>5</SimpleValue> | ||||||
|  | 			</Value> | ||||||
|  | 			<Value ColumnRef="name"> | ||||||
|  | 				<SimpleValue>Mensual</SimpleValue> | ||||||
|  | 			</Value> | ||||||
|  | 		</Row> | ||||||
|  | 		<Row> | ||||||
|  | 			<Value ColumnRef="code"> | ||||||
|  | 				<SimpleValue>6</SimpleValue> | ||||||
|  | 			</Value> | ||||||
|  | 			<Value ColumnRef="name"> | ||||||
|  | 				<SimpleValue>Otro</SimpleValue> | ||||||
|  | 			</Value> | ||||||
|  | 		</Row> | ||||||
|  |         </SimpleCodeList> | ||||||
|  | </gc:CodeList> | ||||||
							
								
								
									
										44
									
								
								facho/fe/data/dian/codelist/SubTipoTrabajador-2.1.gc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										44
									
								
								facho/fe/data/dian/codelist/SubTipoTrabajador-2.1.gc
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,44 @@ | |||||||
|  | <?xml version="1.0" encoding="UTF-8"?> | ||||||
|  | <!-- | ||||||
|  |      creado por facho, la dian tiene oficial? | ||||||
|  |      poblar usando anexo tecnico 5.5.4 | ||||||
|  | --> | ||||||
|  | <gc:CodeList xmlns:gc="http://docs.oasis-open.org/codelist/ns/genericode/1.0/"> | ||||||
|  | 	<Identification> | ||||||
|  | 		<ShortName>SubTipoTrabajador</ShortName> | ||||||
|  | 		<LongName xml:lang="es">Sub tipos de trabajador</LongName> | ||||||
|  | 		<Version>1</Version> | ||||||
|  | 	</Identification> | ||||||
|  | 	<ColumnSet> | ||||||
|  | 		<Column Id="code" Use="required"> | ||||||
|  | 			<ShortName>Code</ShortName> | ||||||
|  | 			<Data Type="normalizedString"/> | ||||||
|  | 		</Column> | ||||||
|  | 		<Column Id="name" Use="required"> | ||||||
|  | 			<ShortName>Nombre</ShortName> | ||||||
|  | 			<Data Type="normalizedString"/> | ||||||
|  | 		</Column> | ||||||
|  | 		<Key Id="codeKey"> | ||||||
|  | 			<ShortName>CodeKey</ShortName> | ||||||
|  | 			<ColumnRef Ref="code"/> | ||||||
|  | 		</Key> | ||||||
|  | 	</ColumnSet> | ||||||
|  | 	<SimpleCodeList> | ||||||
|  | 		<Row> | ||||||
|  | 			<Value ColumnRef="code"> | ||||||
|  | 				<SimpleValue>00</SimpleValue> | ||||||
|  | 			</Value> | ||||||
|  | 			<Value ColumnRef="name"> | ||||||
|  | 				<SimpleValue>No Aplica</SimpleValue> | ||||||
|  | 			</Value> | ||||||
|  | 		</Row> | ||||||
|  | 		<Row> | ||||||
|  | 			<Value ColumnRef="code"> | ||||||
|  | 				<SimpleValue>01</SimpleValue> | ||||||
|  | 			</Value> | ||||||
|  | 			<Value ColumnRef="name"> | ||||||
|  | 				<SimpleValue>Dependiente pensionado por vejez activo</SimpleValue> | ||||||
|  | 			</Value> | ||||||
|  | 		</Row> | ||||||
|  |         </SimpleCodeList> | ||||||
|  | </gc:CodeList> | ||||||
| @@ -46,5 +46,16 @@ | |||||||
|             <SimpleValue>ReteIVA</SimpleValue> |             <SimpleValue>ReteIVA</SimpleValue> | ||||||
|          </Value> |          </Value> | ||||||
|       </Row> |       </Row> | ||||||
|  |       <Row> | ||||||
|  |          <Value ColumnRef="code"> | ||||||
|  |             <SimpleValue>100.00</SimpleValue> | ||||||
|  |          </Value> | ||||||
|  |          <Value ColumnRef="name"> | ||||||
|  |             <SimpleValue>ReteIVA</SimpleValue> | ||||||
|  |          </Value> | ||||||
|  |          <Value ColumnRef="description"> | ||||||
|  |             <SimpleValue>ReteIVA</SimpleValue> | ||||||
|  |          </Value> | ||||||
|  |       </Row> | ||||||
|    </SimpleCodeList> |    </SimpleCodeList> | ||||||
| </gc:CodeList> | </gc:CodeList> | ||||||
|   | |||||||
							
								
								
									
										68
									
								
								facho/fe/data/dian/codelist/TipoContrato-2.1.gc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										68
									
								
								facho/fe/data/dian/codelist/TipoContrato-2.1.gc
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,68 @@ | |||||||
|  | <?xml version="1.0" encoding="UTF-8"?> | ||||||
|  | <!-- | ||||||
|  |      creado por facho, la dian tiene oficial? | ||||||
|  |      poblar usando anexo tecnico 5.5.2 | ||||||
|  | --> | ||||||
|  | <gc:CodeList xmlns:gc="http://docs.oasis-open.org/codelist/ns/genericode/1.0/"> | ||||||
|  | 	<Identification> | ||||||
|  | 		<ShortName>TipoContrato</ShortName> | ||||||
|  | 		<LongName xml:lang="es">Tipos de contratos</LongName> | ||||||
|  | 		<Version>1</Version> | ||||||
|  | 	</Identification> | ||||||
|  | 	<ColumnSet> | ||||||
|  | 		<Column Id="code" Use="required"> | ||||||
|  | 			<ShortName>Code</ShortName> | ||||||
|  | 			<Data Type="normalizedString"/> | ||||||
|  | 		</Column> | ||||||
|  | 		<Column Id="name" Use="required"> | ||||||
|  | 			<ShortName>Nombre</ShortName> | ||||||
|  | 			<Data Type="normalizedString"/> | ||||||
|  | 		</Column> | ||||||
|  | 		<Key Id="codeKey"> | ||||||
|  | 			<ShortName>CodeKey</ShortName> | ||||||
|  | 			<ColumnRef Ref="code"/> | ||||||
|  | 		</Key> | ||||||
|  | 	</ColumnSet> | ||||||
|  | 	<SimpleCodeList> | ||||||
|  | 		<Row> | ||||||
|  | 			<Value ColumnRef="code"> | ||||||
|  | 				<SimpleValue>1</SimpleValue> | ||||||
|  | 			</Value> | ||||||
|  | 			<Value ColumnRef="name"> | ||||||
|  | 				<SimpleValue>Termino Fijo</SimpleValue> | ||||||
|  | 			</Value> | ||||||
|  | 		</Row> | ||||||
|  | 		<Row> | ||||||
|  | 			<Value ColumnRef="code"> | ||||||
|  | 				<SimpleValue>2</SimpleValue> | ||||||
|  | 			</Value> | ||||||
|  | 			<Value ColumnRef="name"> | ||||||
|  | 				<SimpleValue>Término Indefinido</SimpleValue> | ||||||
|  | 			</Value> | ||||||
|  | 		</Row> | ||||||
|  | 		<Row> | ||||||
|  | 			<Value ColumnRef="code"> | ||||||
|  | 				<SimpleValue>3</SimpleValue> | ||||||
|  | 			</Value> | ||||||
|  | 			<Value ColumnRef="name"> | ||||||
|  | 				<SimpleValue>Obra o Labor</SimpleValue> | ||||||
|  | 			</Value> | ||||||
|  | 		</Row> | ||||||
|  | 		<Row> | ||||||
|  | 			<Value ColumnRef="code"> | ||||||
|  | 				<SimpleValue>4</SimpleValue> | ||||||
|  | 			</Value> | ||||||
|  | 			<Value ColumnRef="name"> | ||||||
|  | 				<SimpleValue>Aprendizaje</SimpleValue> | ||||||
|  | 			</Value> | ||||||
|  | 		</Row> | ||||||
|  | 		<Row> | ||||||
|  | 			<Value ColumnRef="code"> | ||||||
|  | 				<SimpleValue>5</SimpleValue> | ||||||
|  | 			</Value> | ||||||
|  | 			<Value ColumnRef="name"> | ||||||
|  | 				<SimpleValue>Pŕacticas o Pasantías</SimpleValue> | ||||||
|  | 			</Value> | ||||||
|  | 		</Row> | ||||||
|  |         </SimpleCodeList> | ||||||
|  | </gc:CodeList> | ||||||
| @@ -1,5 +1,5 @@ | |||||||
| <?xml version="1.0" encoding="UTF-8"?> | <?xml version="1.0" encoding="UTF-8"?> | ||||||
| <!-- DIAN Genericode listas de valores:: Ultima modificación 18-02-2019 - evb--> | <!-- DIAN Genericode listas de valores: Ultima modificación 03-04-2022 - wcbr--> | ||||||
| <gc:CodeList xmlns:gc="http://docs.oasis-open.org/codelist/ns/genericode/1.0/"> | <gc:CodeList xmlns:gc="http://docs.oasis-open.org/codelist/ns/genericode/1.0/"> | ||||||
| 	<Identification> | 	<Identification> | ||||||
| 		<ShortName>TipoDocumento</ShortName> | 		<ShortName>TipoDocumento</ShortName> | ||||||
| @@ -35,7 +35,10 @@ | |||||||
| 				<SimpleValue>01</SimpleValue> | 				<SimpleValue>01</SimpleValue> | ||||||
| 			</Value> | 			</Value> | ||||||
| 			<Value ColumnRef="name"> | 			<Value ColumnRef="name"> | ||||||
| 				<SimpleValue>Factura de Venta Nacional</SimpleValue> | 				<SimpleValue>Factura electrónica de Venta</SimpleValue> | ||||||
|  | 			</Value> | ||||||
|  | 			<Value ColumnRef="description"> | ||||||
|  | 				<SimpleValue>Tipos de factura</SimpleValue> | ||||||
| 			</Value> | 			</Value> | ||||||
| 		</Row> | 		</Row> | ||||||
| 		<Row> | 		<Row> | ||||||
| @@ -43,7 +46,10 @@ | |||||||
| 				<SimpleValue>02</SimpleValue> | 				<SimpleValue>02</SimpleValue> | ||||||
| 			</Value> | 			</Value> | ||||||
| 			<Value ColumnRef="name"> | 			<Value ColumnRef="name"> | ||||||
| 				<SimpleValue>Factura de Exportación </SimpleValue> | 				<SimpleValue>Factura electrónica de venta con propósito de exportación</SimpleValue> | ||||||
|  | 			</Value> | ||||||
|  | 			<Value ColumnRef="description"> | ||||||
|  | 				<SimpleValue>Tipos de factura</SimpleValue> | ||||||
| 			</Value> | 			</Value> | ||||||
| 		</Row> | 		</Row> | ||||||
| 		<Row> | 		<Row> | ||||||
| @@ -51,7 +57,21 @@ | |||||||
| 				<SimpleValue>03</SimpleValue> | 				<SimpleValue>03</SimpleValue> | ||||||
| 			</Value> | 			</Value> | ||||||
| 			<Value ColumnRef="name"> | 			<Value ColumnRef="name"> | ||||||
| 				<SimpleValue>Factura de Contingencia</SimpleValue> | 				<SimpleValue>Factura de talonario o papel con numeración de contingencia.</SimpleValue> | ||||||
|  | 			</Value> | ||||||
|  | 			<Value ColumnRef="description"> | ||||||
|  | 				<SimpleValue>Tipos de factura</SimpleValue> | ||||||
|  | 			</Value> | ||||||
|  | 		</Row> | ||||||
|  | 		<Row> | ||||||
|  | 			<Value ColumnRef="code"> | ||||||
|  | 				<SimpleValue>04</SimpleValue> | ||||||
|  | 			</Value> | ||||||
|  | 			<Value ColumnRef="name"> | ||||||
|  | 				<SimpleValue>Factura electrónica de Venta  por Contingencia DIAN</SimpleValue> | ||||||
|  | 			</Value> | ||||||
|  | 			<Value ColumnRef="description"> | ||||||
|  | 				<SimpleValue>Tipos de factura</SimpleValue> | ||||||
| 			</Value> | 			</Value> | ||||||
| 		</Row> | 		</Row> | ||||||
| 		<Row> | 		<Row> | ||||||
| @@ -61,6 +81,9 @@ | |||||||
| 			<Value ColumnRef="name"> | 			<Value ColumnRef="name"> | ||||||
| 				<SimpleValue>Nota Crédito</SimpleValue> | 				<SimpleValue>Nota Crédito</SimpleValue> | ||||||
| 			</Value> | 			</Value> | ||||||
|  | 			<Value ColumnRef="description"> | ||||||
|  | 				<SimpleValue>Exclusivo en referencias a documentos (elementos DocumentReference)</SimpleValue> | ||||||
|  | 			</Value> | ||||||
| 		</Row> | 		</Row> | ||||||
| 		<Row> | 		<Row> | ||||||
| 			<Value ColumnRef="code"> | 			<Value ColumnRef="code"> | ||||||
| @@ -69,6 +92,9 @@ | |||||||
| 			<Value ColumnRef="name"> | 			<Value ColumnRef="name"> | ||||||
| 				<SimpleValue>Nota Débito</SimpleValue> | 				<SimpleValue>Nota Débito</SimpleValue> | ||||||
| 			</Value> | 			</Value> | ||||||
|  | 			<Value ColumnRef="description"> | ||||||
|  | 				<SimpleValue>Exclusivo en referencias a documentos (elementos DocumentReference)</SimpleValue> | ||||||
|  | 			</Value> | ||||||
| 		</Row> | 		</Row> | ||||||
| 	</SimpleCodeList> | 	</SimpleCodeList> | ||||||
| </gc:CodeList> | </gc:CodeList> | ||||||
|   | |||||||
| @@ -75,7 +75,7 @@ | |||||||
| 				<SimpleValue>06</SimpleValue> | 				<SimpleValue>06</SimpleValue> | ||||||
| 			</Value> | 			</Value> | ||||||
| 			<Value ColumnRef="name"> | 			<Value ColumnRef="name"> | ||||||
| 				<SimpleValue>ReteFuente</SimpleValue> | 				<SimpleValue>ReteRenta</SimpleValue> | ||||||
| 			</Value> | 			</Value> | ||||||
| 		</Row> | 		</Row> | ||||||
| 		<Row> | 		<Row> | ||||||
| @@ -150,6 +150,15 @@ | |||||||
| 				<SimpleValue>Sordicom</SimpleValue> | 				<SimpleValue>Sordicom</SimpleValue> | ||||||
| 			</Value> | 			</Value> | ||||||
| 		</Row> | 		</Row> | ||||||
|  | 		<Row> | ||||||
|  | 			<Value ColumnRef="code"> | ||||||
|  | 				<SimpleValue>30</SimpleValue> | ||||||
|  | 			</Value> | ||||||
|  | 			<Value ColumnRef="name"> | ||||||
|  | 				<SimpleValue>Impuesto al Consumo de Datos</SimpleValue> | ||||||
|  | 			</Value> | ||||||
|  | 		</Row> | ||||||
|  |   | ||||||
| 		<Row> | 		<Row> | ||||||
| 			<Value ColumnRef="code"> | 			<Value ColumnRef="code"> | ||||||
| 				<SimpleValue>ZZ</SimpleValue> | 				<SimpleValue>ZZ</SimpleValue> | ||||||
|   | |||||||
							
								
								
									
										47
									
								
								facho/fe/data/dian/codelist/TipoOperacionNCDS-2.1.gc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										47
									
								
								facho/fe/data/dian/codelist/TipoOperacionNCDS-2.1.gc
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,47 @@ | |||||||
|  | <?xml version="1.0" encoding="UTF-8"?> | ||||||
|  | <gc:CodeList xmlns:gc="http://docs.oasis-open.org/codelist/ns/genericode/1.0/"> | ||||||
|  |    <Identification> | ||||||
|  |       <ShortName>TipoOperacion</ShortName> | ||||||
|  |       <LongName xml:lang="es">Tipo de operacion</LongName> | ||||||
|  |       <Version>1</Version> | ||||||
|  |       <CanonicalUri>urn:dian:names:especificacion:ubl:listacodigos:gc:TipoOperacion</CanonicalUri> | ||||||
|  |       <CanonicalVersionUri>urn:dian:names:especificacion:ubl:listacodigos:gc:TipoOperacion-2.1</CanonicalVersionUri> | ||||||
|  |       <LocationUri>http://dian.gov.co/ubl/os-ubl-2.0/cl/gc/default/TipoOperacion-2.1.gc</LocationUri> | ||||||
|  |       <Agency> | ||||||
|  |          <LongName xml:lang="es">DIAN (Dirección de Impuestos y Aduanas Nacionales)</LongName> | ||||||
|  |          <Identifier>195</Identifier> | ||||||
|  |       </Agency> | ||||||
|  |    </Identification> | ||||||
|  |    <ColumnSet> | ||||||
|  |       <Column Id="code" Use="required"> | ||||||
|  |          <ShortName>Code</ShortName> | ||||||
|  |          <Data Type="normalizedString"/> | ||||||
|  |       </Column> | ||||||
|  |       <Column Id="name" Use="required"> | ||||||
|  |          <ShortName>Nombre</ShortName> | ||||||
|  |          <Data Type="normalizedString"/> | ||||||
|  |       </Column> | ||||||
|  |       <Key Id="codeKey"> | ||||||
|  |          <ShortName>CodeKey</ShortName> | ||||||
|  |          <ColumnRef Ref="code"/> | ||||||
|  |       </Key> | ||||||
|  |    </ColumnSet> | ||||||
|  |    <SimpleCodeList> | ||||||
|  |       <Row> | ||||||
|  |          <Value ColumnRef="code"> | ||||||
|  |             <SimpleValue>10</SimpleValue> | ||||||
|  |          </Value> | ||||||
|  |          <Value ColumnRef="name"> | ||||||
|  |             <SimpleValue>Residente</SimpleValue> | ||||||
|  |          </Value> | ||||||
|  |       </Row> | ||||||
|  |       <Row> | ||||||
|  |          <Value ColumnRef="code"> | ||||||
|  |             <SimpleValue>11</SimpleValue> | ||||||
|  |          </Value> | ||||||
|  |          <Value ColumnRef="name"> | ||||||
|  |             <SimpleValue>No Residente</SimpleValue> | ||||||
|  |          </Value> | ||||||
|  |       </Row> | ||||||
|  |    </SimpleCodeList> | ||||||
|  | </gc:CodeList> | ||||||
| @@ -30,46 +30,6 @@ | |||||||
| 		</Key> | 		</Key> | ||||||
| 	</ColumnSet> | 	</ColumnSet> | ||||||
| 	<SimpleCodeList> | 	<SimpleCodeList> | ||||||
| 		<Row> |  | ||||||
| 			<Value ColumnRef="code"> |  | ||||||
| 				<SimpleValue>O-99</SimpleValue> |  | ||||||
| 			</Value> |  | ||||||
| 			<Value ColumnRef="name"> |  | ||||||
| 				<SimpleValue>Otro tipo de obligado</SimpleValue> |  | ||||||
| 			</Value> |  | ||||||
| 		</Row> |  | ||||||
| 		<Row> |  | ||||||
| 			<Value ColumnRef="code"> |  | ||||||
| 				<SimpleValue>O-06</SimpleValue> |  | ||||||
| 			</Value> |  | ||||||
| 			<Value ColumnRef="name"> |  | ||||||
| 				<SimpleValue>Ingresos y patrimonio</SimpleValue> |  | ||||||
| 			</Value> |  | ||||||
| 		</Row> |  | ||||||
| 		<Row> |  | ||||||
| 			<Value ColumnRef="code"> |  | ||||||
| 				<SimpleValue>O-07</SimpleValue> |  | ||||||
| 			</Value> |  | ||||||
| 			<Value ColumnRef="name"> |  | ||||||
| 				<SimpleValue>Retención en la fuente a título de renta</SimpleValue> |  | ||||||
| 			</Value> |  | ||||||
| 		</Row> |  | ||||||
| 		<Row> |  | ||||||
| 			<Value ColumnRef="code"> |  | ||||||
| 				<SimpleValue>O-08</SimpleValue> |  | ||||||
| 			</Value> |  | ||||||
| 			<Value ColumnRef="name"> |  | ||||||
| 				<SimpleValue>Retención timbre nacional</SimpleValue> |  | ||||||
| 			</Value> |  | ||||||
| 		</Row> |  | ||||||
| 		<Row> |  | ||||||
| 			<Value ColumnRef="code"> |  | ||||||
| 				<SimpleValue>O-09</SimpleValue> |  | ||||||
| 			</Value> |  | ||||||
| 			<Value ColumnRef="name"> |  | ||||||
| 				<SimpleValue>Retención en la fuente en el impuesto sobre las ventas</SimpleValue> |  | ||||||
| 			</Value> |  | ||||||
| 		</Row> |  | ||||||
| 		<Row> | 		<Row> | ||||||
| 			<Value ColumnRef="code"> | 			<Value ColumnRef="code"> | ||||||
| 				<SimpleValue>O-13</SimpleValue> | 				<SimpleValue>O-13</SimpleValue> | ||||||
| @@ -78,14 +38,6 @@ | |||||||
| 				<SimpleValue>Gran contribuyente</SimpleValue> | 				<SimpleValue>Gran contribuyente</SimpleValue> | ||||||
| 			</Value> | 			</Value> | ||||||
| 		</Row> | 		</Row> | ||||||
| 		<Row> |  | ||||||
| 			<Value ColumnRef="code"> |  | ||||||
| 				<SimpleValue>O-14</SimpleValue> |  | ||||||
| 			</Value> |  | ||||||
| 			<Value ColumnRef="name"> |  | ||||||
| 				<SimpleValue>Informante de exógena</SimpleValue> |  | ||||||
| 			</Value> |  | ||||||
| 		</Row> |  | ||||||
| 		<Row> | 		<Row> | ||||||
| 			<Value ColumnRef="code"> | 			<Value ColumnRef="code"> | ||||||
| 				<SimpleValue>O-15</SimpleValue> | 				<SimpleValue>O-15</SimpleValue> | ||||||
| @@ -94,38 +46,6 @@ | |||||||
| 				<SimpleValue>Autorretenedor</SimpleValue> | 				<SimpleValue>Autorretenedor</SimpleValue> | ||||||
| 			</Value> | 			</Value> | ||||||
| 		</Row> | 		</Row> | ||||||
| 		<Row> |  | ||||||
| 			<Value ColumnRef="code"> |  | ||||||
| 				<SimpleValue>O-16</SimpleValue> |  | ||||||
| 			</Value> |  | ||||||
| 			<Value ColumnRef="name"> |  | ||||||
| 				<SimpleValue>Obligación de facturar por ingresos de bienes y/o servicios excluidos</SimpleValue> |  | ||||||
| 			</Value> |  | ||||||
| 		</Row> |  | ||||||
| 		<Row> |  | ||||||
| 			<Value ColumnRef="code"> |  | ||||||
| 				<SimpleValue>O-17</SimpleValue> |  | ||||||
| 			</Value> |  | ||||||
| 			<Value ColumnRef="name"> |  | ||||||
| 				<SimpleValue>Profesionales de compra y venta de divisas</SimpleValue> |  | ||||||
| 			</Value> |  | ||||||
| 		</Row> |  | ||||||
| 		<Row> |  | ||||||
| 			<Value ColumnRef="code"> |  | ||||||
| 				<SimpleValue>O-19</SimpleValue> |  | ||||||
| 			</Value> |  | ||||||
| 			<Value ColumnRef="name"> |  | ||||||
| 				<SimpleValue>Productor y/o exportador de bienes exentos</SimpleValue> |  | ||||||
| 			</Value> |  | ||||||
| 		</Row> |  | ||||||
| 		<Row> |  | ||||||
| 			<Value ColumnRef="code"> |  | ||||||
| 				<SimpleValue>O-22</SimpleValue> |  | ||||||
| 			</Value> |  | ||||||
| 			<Value ColumnRef="name"> |  | ||||||
| 				<SimpleValue>Obligado a cumplir deberes formales a nombre de terceros</SimpleValue> |  | ||||||
| 			</Value> |  | ||||||
| 		</Row> |  | ||||||
| 		<Row> | 		<Row> | ||||||
| 			<Value ColumnRef="code"> | 			<Value ColumnRef="code"> | ||||||
| 				<SimpleValue>O-23</SimpleValue> | 				<SimpleValue>O-23</SimpleValue> | ||||||
| @@ -134,62 +54,6 @@ | |||||||
| 				<SimpleValue>Agente de retención en el impuesto sobre las ventas</SimpleValue> | 				<SimpleValue>Agente de retención en el impuesto sobre las ventas</SimpleValue> | ||||||
| 			</Value> | 			</Value> | ||||||
| 		</Row> | 		</Row> | ||||||
| 		<Row> |  | ||||||
| 			<Value ColumnRef="code"> |  | ||||||
| 				<SimpleValue>O-32</SimpleValue> |  | ||||||
| 			</Value> |  | ||||||
| 			<Value ColumnRef="name"> |  | ||||||
| 				<SimpleValue>Impuesto Nacional a la Gasolina y al ACPM</SimpleValue> |  | ||||||
| 			</Value> |  | ||||||
| 		</Row> |  | ||||||
| 		<Row> |  | ||||||
| 			<Value ColumnRef="code"> |  | ||||||
| 				<SimpleValue>O-33</SimpleValue> |  | ||||||
| 			</Value> |  | ||||||
| 			<Value ColumnRef="name"> |  | ||||||
| 				<SimpleValue>Impuesto Nacional al consumo</SimpleValue> |  | ||||||
| 			</Value> |  | ||||||
| 		</Row> |  | ||||||
| 		<Row> |  | ||||||
| 			<Value ColumnRef="code"> |  | ||||||
| 				<SimpleValue>O-34</SimpleValue> |  | ||||||
| 			</Value> |  | ||||||
| 			<Value ColumnRef="name"> |  | ||||||
| 				<SimpleValue>Régimen simplificado impuesto nacional consumo rest y bares</SimpleValue> |  | ||||||
| 			</Value> |  | ||||||
| 		</Row> |  | ||||||
| 		<Row> |  | ||||||
| 			<Value ColumnRef="code"> |  | ||||||
| 				<SimpleValue>O-36</SimpleValue> |  | ||||||
| 			</Value> |  | ||||||
| 			<Value ColumnRef="name"> |  | ||||||
| 				<SimpleValue>Establecimiento Permanente</SimpleValue> |  | ||||||
| 			</Value> |  | ||||||
| 		</Row> |  | ||||||
| 		<Row> |  | ||||||
| 			<Value ColumnRef="code"> |  | ||||||
| 				<SimpleValue>O-37</SimpleValue> |  | ||||||
| 			</Value> |  | ||||||
| 			<Value ColumnRef="name"> |  | ||||||
| 				<SimpleValue>Obligado a Facturar Electrónicamente Modelo 2242</SimpleValue> |  | ||||||
| 			</Value> |  | ||||||
| 		</Row> |  | ||||||
| 		<Row> |  | ||||||
| 			<Value ColumnRef="code"> |  | ||||||
| 				<SimpleValue>O-38</SimpleValue> |  | ||||||
| 			</Value> |  | ||||||
| 			<Value ColumnRef="name"> |  | ||||||
| 				<SimpleValue>Facturación Electrónica Voluntaria Modelo 2242</SimpleValue> |  | ||||||
| 			</Value> |  | ||||||
| 		</Row> |  | ||||||
| 		<Row> |  | ||||||
| 			<Value ColumnRef="code"> |  | ||||||
| 				<SimpleValue>O-39</SimpleValue> |  | ||||||
| 			</Value> |  | ||||||
| 			<Value ColumnRef="name"> |  | ||||||
| 				<SimpleValue>Proveedor de Servicios Tecnológicos PST Modelo 2242</SimpleValue> |  | ||||||
| 			</Value> |  | ||||||
| 		</Row> |  | ||||||
| 		<Row> | 		<Row> | ||||||
| 			<Value ColumnRef="code"> | 			<Value ColumnRef="code"> | ||||||
| 				<SimpleValue>O-47</SimpleValue> | 				<SimpleValue>O-47</SimpleValue> | ||||||
| @@ -214,782 +78,6 @@ | |||||||
| 				<SimpleValue>No responsable de IVA</SimpleValue> | 				<SimpleValue>No responsable de IVA</SimpleValue> | ||||||
| 			</Value> | 			</Value> | ||||||
| 		</Row> | 		</Row> | ||||||
| 		<Row> |  | ||||||
| 			<Value ColumnRef="code"> |  | ||||||
| 				<SimpleValue>O-52</SimpleValue> |  | ||||||
| 			</Value> |  | ||||||
| 			<Value ColumnRef="name"> |  | ||||||
| 				<SimpleValue>Facturador electrónico</SimpleValue> |  | ||||||
| 			</Value> |  | ||||||
| 		</Row> |  | ||||||
| 		<Row> |  | ||||||
| 			<Value ColumnRef="code"> |  | ||||||
| 				<SimpleValue>O-99</SimpleValue> |  | ||||||
| 			</Value> |  | ||||||
| 			<Value ColumnRef="name"> |  | ||||||
| 				<SimpleValue>Otro tipo de obligado</SimpleValue> |  | ||||||
| 			</Value> |  | ||||||
| 		</Row> |  | ||||||
| 		<Row> |  | ||||||
| 			<Value ColumnRef="code"> |  | ||||||
| 				<SimpleValue>R-00-PN</SimpleValue> |  | ||||||
| 			</Value> |  | ||||||
| 			<Value ColumnRef="name"> |  | ||||||
| 				<SimpleValue>Clientes del Exterior</SimpleValue> |  | ||||||
| 			</Value> |  | ||||||
| 		</Row> |  | ||||||
| 		<Row> |  | ||||||
| 			<Value ColumnRef="code"> |  | ||||||
| 				<SimpleValue>R-12-PN</SimpleValue> |  | ||||||
| 			</Value> |  | ||||||
| 			<Value ColumnRef="name"> |  | ||||||
| 				<SimpleValue>Factor PN</SimpleValue> |  | ||||||
| 			</Value> |  | ||||||
| 		</Row> |  | ||||||
| 		<Row> |  | ||||||
| 			<Value ColumnRef="code"> |  | ||||||
| 				<SimpleValue>R-16-PN</SimpleValue> |  | ||||||
| 			</Value> |  | ||||||
| 			<Value ColumnRef="name"> |  | ||||||
| 				<SimpleValue>Mandatario</SimpleValue> |  | ||||||
| 			</Value> |  | ||||||
| 		</Row> |  | ||||||
| 		<Row> |  | ||||||
| 			<Value ColumnRef="code"> |  | ||||||
| 				<SimpleValue>R-25-PN</SimpleValue> |  | ||||||
| 			</Value> |  | ||||||
| 			<Value ColumnRef="name"> |  | ||||||
| 				<SimpleValue>Agente Interventor</SimpleValue> |  | ||||||
| 			</Value> |  | ||||||
| 		</Row> |  | ||||||
| 		<Row> |  | ||||||
| 			<Value ColumnRef="code"> |  | ||||||
| 				<SimpleValue>R-99-PN</SimpleValue> |  | ||||||
| 			</Value> |  | ||||||
| 			<Value ColumnRef="name"> |  | ||||||
| 				<SimpleValue>No responsable</SimpleValue> |  | ||||||
| 			</Value> |  | ||||||
| 		</Row> |  | ||||||
| 		<Row> |  | ||||||
| 			<Value ColumnRef="code"> |  | ||||||
| 				<SimpleValue>R-06-PJ</SimpleValue> |  | ||||||
| 			</Value> |  | ||||||
| 			<Value ColumnRef="name"> |  | ||||||
| 				<SimpleValue>Apoderado especial</SimpleValue> |  | ||||||
| 			</Value> |  | ||||||
| 		</Row> |  | ||||||
| 		<Row> |  | ||||||
| 			<Value ColumnRef="code"> |  | ||||||
| 				<SimpleValue>R-07-PJ</SimpleValue> |  | ||||||
| 			</Value> |  | ||||||
| 			<Value ColumnRef="name"> |  | ||||||
| 				<SimpleValue>Apoderado general</SimpleValue> |  | ||||||
| 			</Value> |  | ||||||
| 		</Row> |  | ||||||
| 		<Row> |  | ||||||
| 			<Value ColumnRef="code"> |  | ||||||
| 				<SimpleValue>R-12-PJ</SimpleValue> |  | ||||||
| 			</Value> |  | ||||||
| 			<Value ColumnRef="name"> |  | ||||||
| 				<SimpleValue>Factor</SimpleValue> |  | ||||||
| 			</Value> |  | ||||||
| 		</Row> |  | ||||||
| 		<Row> |  | ||||||
| 			<Value ColumnRef="code"> |  | ||||||
| 				<SimpleValue>R-16-PJ</SimpleValue> |  | ||||||
| 			</Value> |  | ||||||
| 			<Value ColumnRef="name"> |  | ||||||
| 				<SimpleValue>Mandatario</SimpleValue> |  | ||||||
| 			</Value> |  | ||||||
| 		</Row> |  | ||||||
| 		<Row> |  | ||||||
| 			<Value ColumnRef="code"> |  | ||||||
| 				<SimpleValue>R-99-PJ</SimpleValue> |  | ||||||
| 			</Value> |  | ||||||
| 			<Value ColumnRef="name"> |  | ||||||
| 				<SimpleValue>Otro tipo de responsable</SimpleValue> |  | ||||||
| 			</Value> |  | ||||||
| 		</Row> |  | ||||||
| 		<Row> |  | ||||||
| 			<Value ColumnRef="code"> |  | ||||||
| 				<SimpleValue>A-01</SimpleValue> |  | ||||||
| 			</Value> |  | ||||||
| 			<Value ColumnRef="name"> |  | ||||||
| 				<SimpleValue>Agente de carga internacional</SimpleValue> |  | ||||||
| 			</Value> |  | ||||||
| 		</Row> |  | ||||||
| 		<Row> |  | ||||||
| 			<Value ColumnRef="code"> |  | ||||||
| 				<SimpleValue>A-02</SimpleValue> |  | ||||||
| 			</Value> |  | ||||||
| 			<Value ColumnRef="name"> |  | ||||||
| 				<SimpleValue>Agente marítimo</SimpleValue> |  | ||||||
| 			</Value> |  | ||||||
| 		</Row> |  | ||||||
| 		<Row> |  | ||||||
| 			<Value ColumnRef="code"> |  | ||||||
| 				<SimpleValue>A-03</SimpleValue> |  | ||||||
| 			</Value> |  | ||||||
| 			<Value ColumnRef="name"> |  | ||||||
| 				<SimpleValue>Almacén general de depósito</SimpleValue> |  | ||||||
| 			</Value> |  | ||||||
| 		</Row> |  | ||||||
| 		<Row> |  | ||||||
| 			<Value ColumnRef="code"> |  | ||||||
| 				<SimpleValue>A-04</SimpleValue> |  | ||||||
| 			</Value> |  | ||||||
| 			<Value ColumnRef="name"> |  | ||||||
| 				<SimpleValue>Comercializadora internacional (C.I.)</SimpleValue> |  | ||||||
| 			</Value> |  | ||||||
| 		</Row> |  | ||||||
| 		<Row> |  | ||||||
| 			<Value ColumnRef="code"> |  | ||||||
| 				<SimpleValue>A-05</SimpleValue> |  | ||||||
| 			</Value> |  | ||||||
| 			<Value ColumnRef="name"> |  | ||||||
| 				<SimpleValue>Comerciante de la zona aduanera especial de Inírida, Puerto Carreño, Cumaribo y Primavera</SimpleValue> |  | ||||||
| 			</Value> |  | ||||||
| 		</Row> |  | ||||||
| 		<Row> |  | ||||||
| 			<Value ColumnRef="code"> |  | ||||||
| 				<SimpleValue>A-06</SimpleValue> |  | ||||||
| 			</Value> |  | ||||||
| 			<Value ColumnRef="name"> |  | ||||||
| 				<SimpleValue>Comerciantes de la zona de régimen aduanero especial de Leticia</SimpleValue> |  | ||||||
| 			</Value> |  | ||||||
| 		</Row> |  | ||||||
| 		<Row> |  | ||||||
| 			<Value ColumnRef="code"> |  | ||||||
| 				<SimpleValue>A-07</SimpleValue> |  | ||||||
| 			</Value> |  | ||||||
| 			<Value ColumnRef="name"> |  | ||||||
| 				<SimpleValue>Comerciantes de la zona de régimen aduanero especial de Maicao, Uribia y Manaure</SimpleValue> |  | ||||||
| 			</Value> |  | ||||||
| 		</Row> |  | ||||||
| 		<Row> |  | ||||||
| 			<Value ColumnRef="code"> |  | ||||||
| 				<SimpleValue>A-08</SimpleValue> |  | ||||||
| 			</Value> |  | ||||||
| 			<Value ColumnRef="name"> |  | ||||||
| 				<SimpleValue>Comerciantes de la zona de régimen aduanero especial de Urabá, Tumaco y Guapí</SimpleValue> |  | ||||||
| 			</Value> |  | ||||||
| 		</Row> |  | ||||||
| 		<Row> |  | ||||||
| 			<Value ColumnRef="code"> |  | ||||||
| 				<SimpleValue>A-09</SimpleValue> |  | ||||||
| 			</Value> |  | ||||||
| 			<Value ColumnRef="name"> |  | ||||||
| 				<SimpleValue>Comerciantes del puerto libre de San Andrés, Providencia y Santa Catalina</SimpleValue> |  | ||||||
| 			</Value> |  | ||||||
| 		</Row> |  | ||||||
| 		<Row> |  | ||||||
| 			<Value ColumnRef="code"> |  | ||||||
| 				<SimpleValue>A-10</SimpleValue> |  | ||||||
| 			</Value> |  | ||||||
| 			<Value ColumnRef="name"> |  | ||||||
| 				<SimpleValue>Depósito público de apoyo logístico internacional</SimpleValue> |  | ||||||
| 			</Value> |  | ||||||
| 		</Row> |  | ||||||
| 		<Row> |  | ||||||
| 			<Value ColumnRef="code"> |  | ||||||
| 				<SimpleValue>A-11</SimpleValue> |  | ||||||
| 			</Value> |  | ||||||
| 			<Value ColumnRef="name"> |  | ||||||
| 				<SimpleValue>Depósito privado para procesamiento industrial</SimpleValue> |  | ||||||
| 			</Value> |  | ||||||
| 		</Row> |  | ||||||
| 		<Row> |  | ||||||
| 			<Value ColumnRef="code"> |  | ||||||
| 				<SimpleValue>A-12</SimpleValue> |  | ||||||
| 			</Value> |  | ||||||
| 			<Value ColumnRef="name"> |  | ||||||
| 				<SimpleValue>Depósito privado de transformación o ensamble</SimpleValue> |  | ||||||
| 			</Value> |  | ||||||
| 		</Row> |  | ||||||
| 		<Row> |  | ||||||
| 			<Value ColumnRef="code"> |  | ||||||
| 				<SimpleValue>A-13</SimpleValue> |  | ||||||
| 			</Value> |  | ||||||
| 			<Value ColumnRef="name"> |  | ||||||
| 				<SimpleValue>Depósito franco</SimpleValue> |  | ||||||
| 			</Value> |  | ||||||
| 		</Row> |  | ||||||
| 		<Row> |  | ||||||
| 			<Value ColumnRef="code"> |  | ||||||
| 				<SimpleValue>A-14</SimpleValue> |  | ||||||
| 			</Value> |  | ||||||
| 			<Value ColumnRef="name"> |  | ||||||
| 				<SimpleValue>Depósito privado aeronáutico</SimpleValue> |  | ||||||
| 			</Value> |  | ||||||
| 		</Row> |  | ||||||
| 		<Row> |  | ||||||
| 			<Value ColumnRef="code"> |  | ||||||
| 				<SimpleValue>A-15</SimpleValue> |  | ||||||
| 			</Value> |  | ||||||
| 			<Value ColumnRef="name"> |  | ||||||
| 				<SimpleValue>Depósito privado para distribución internacional</SimpleValue> |  | ||||||
| 			</Value> |  | ||||||
| 		</Row> |  | ||||||
| 		<Row> |  | ||||||
| 			<Value ColumnRef="code"> |  | ||||||
| 				<SimpleValue>A-16</SimpleValue> |  | ||||||
| 			</Value> |  | ||||||
| 			<Value ColumnRef="name"> |  | ||||||
| 				<SimpleValue>Depósito privado de provisiones de a bordo para consumo y para llevar</SimpleValue> |  | ||||||
| 			</Value> |  | ||||||
| 		</Row> |  | ||||||
| 		<Row> |  | ||||||
| 			<Value ColumnRef="code"> |  | ||||||
| 				<SimpleValue>A-17</SimpleValue> |  | ||||||
| 			</Value> |  | ||||||
| 			<Value ColumnRef="name"> |  | ||||||
| 				<SimpleValue>Depósito privado para envíos urgentes</SimpleValue> |  | ||||||
| 			</Value> |  | ||||||
| 		</Row> |  | ||||||
| 		<Row> |  | ||||||
| 			<Value ColumnRef="code"> |  | ||||||
| 				<SimpleValue>A-18</SimpleValue> |  | ||||||
| 			</Value> |  | ||||||
| 			<Value ColumnRef="name"> |  | ||||||
| 				<SimpleValue>Depósito privado</SimpleValue> |  | ||||||
| 			</Value> |  | ||||||
| 		</Row> |  | ||||||
| 		<Row> |  | ||||||
| 			<Value ColumnRef="code"> |  | ||||||
| 				<SimpleValue>A-19</SimpleValue> |  | ||||||
| 			</Value> |  | ||||||
| 			<Value ColumnRef="name"> |  | ||||||
| 				<SimpleValue>Depósito público</SimpleValue> |  | ||||||
| 			</Value> |  | ||||||
| 		</Row> |  | ||||||
| 		<Row> |  | ||||||
| 			<Value ColumnRef="code"> |  | ||||||
| 				<SimpleValue>A-20</SimpleValue> |  | ||||||
| 			</Value> |  | ||||||
| 			<Value ColumnRef="name"> |  | ||||||
| 				<SimpleValue>Depósito público para distribución internacional</SimpleValue> |  | ||||||
| 			</Value> |  | ||||||
| 		</Row> |  | ||||||
| 		<Row> |  | ||||||
| 			<Value ColumnRef="code"> |  | ||||||
| 				<SimpleValue>A-21</SimpleValue> |  | ||||||
| 			</Value> |  | ||||||
| 			<Value ColumnRef="name"> |  | ||||||
| 				<SimpleValue>Exportador de café</SimpleValue> |  | ||||||
| 			</Value> |  | ||||||
| 		</Row> |  | ||||||
| 		<Row> |  | ||||||
| 			<Value ColumnRef="code"> |  | ||||||
| 				<SimpleValue>A-22</SimpleValue> |  | ||||||
| 			</Value> |  | ||||||
| 			<Value ColumnRef="name"> |  | ||||||
| 				<SimpleValue>Exportador</SimpleValue> |  | ||||||
| 			</Value> |  | ||||||
| 		</Row> |  | ||||||
| 		<Row> |  | ||||||
| 			<Value ColumnRef="code"> |  | ||||||
| 				<SimpleValue>A-23</SimpleValue> |  | ||||||
| 			</Value> |  | ||||||
| 			<Value ColumnRef="name"> |  | ||||||
| 				<SimpleValue>Importador</SimpleValue> |  | ||||||
| 			</Value> |  | ||||||
| 		</Row> |  | ||||||
| 		<Row> |  | ||||||
| 			<Value ColumnRef="code"> |  | ||||||
| 				<SimpleValue>A-24</SimpleValue> |  | ||||||
| 			</Value> |  | ||||||
| 			<Value ColumnRef="name"> |  | ||||||
| 				<SimpleValue>Intermediario de tráfico postal y envíos urgentes</SimpleValue> |  | ||||||
| 			</Value> |  | ||||||
| 		</Row> |  | ||||||
| 		<Row> |  | ||||||
| 			<Value ColumnRef="code"> |  | ||||||
| 				<SimpleValue>A-25</SimpleValue> |  | ||||||
| 			</Value> |  | ||||||
| 			<Value ColumnRef="name"> |  | ||||||
| 				<SimpleValue>Operador de transporte multimodal</SimpleValue> |  | ||||||
| 			</Value> |  | ||||||
| 		</Row> |  | ||||||
| 		<Row> |  | ||||||
| 			<Value ColumnRef="code"> |  | ||||||
| 				<SimpleValue>A-26</SimpleValue> |  | ||||||
| 			</Value> |  | ||||||
| 			<Value ColumnRef="name"> |  | ||||||
| 				<SimpleValue>Sociedad de intermediación aduanera</SimpleValue> |  | ||||||
| 			</Value> |  | ||||||
| 		</Row> |  | ||||||
| 		<Row> |  | ||||||
| 			<Value ColumnRef="code"> |  | ||||||
| 				<SimpleValue>A-27</SimpleValue> |  | ||||||
| 			</Value> |  | ||||||
| 			<Value ColumnRef="name"> |  | ||||||
| 				<SimpleValue>Titular de puertos y muelles de servicio público o privado</SimpleValue> |  | ||||||
| 			</Value> |  | ||||||
| 		</Row> |  | ||||||
| 		<Row> |  | ||||||
| 			<Value ColumnRef="code"> |  | ||||||
| 				<SimpleValue>A-28</SimpleValue> |  | ||||||
| 			</Value> |  | ||||||
| 			<Value ColumnRef="name"> |  | ||||||
| 				<SimpleValue>Transportador 263nfor régimen de importación y/o exportación</SimpleValue> |  | ||||||
| 			</Value> |  | ||||||
| 		</Row> |  | ||||||
| 		<Row> |  | ||||||
| 			<Value ColumnRef="code"> |  | ||||||
| 				<SimpleValue>A-29</SimpleValue> |  | ||||||
| 			</Value> |  | ||||||
| 			<Value ColumnRef="name"> |  | ||||||
| 				<SimpleValue>Transportista nacional para operaciones del régimen de tránsito aduanero</SimpleValue> |  | ||||||
| 			</Value> |  | ||||||
| 		</Row> |  | ||||||
| 		<Row> |  | ||||||
| 			<Value ColumnRef="code"> |  | ||||||
| 				<SimpleValue>A-30</SimpleValue> |  | ||||||
| 			</Value> |  | ||||||
| 			<Value ColumnRef="name"> |  | ||||||
| 				<SimpleValue>Usuario comercial zona franca</SimpleValue> |  | ||||||
| 			</Value> |  | ||||||
| 		</Row> |  | ||||||
| 		<Row> |  | ||||||
| 			<Value ColumnRef="code"> |  | ||||||
| 				<SimpleValue>A-32</SimpleValue> |  | ||||||
| 			</Value> |  | ||||||
| 			<Value ColumnRef="name"> |  | ||||||
| 				<SimpleValue>Usuario industrial de bienes zona franca</SimpleValue> |  | ||||||
| 			</Value> |  | ||||||
| 		</Row> |  | ||||||
| 		<Row> |  | ||||||
| 			<Value ColumnRef="code"> |  | ||||||
| 				<SimpleValue>A-34</SimpleValue> |  | ||||||
| 			</Value> |  | ||||||
| 			<Value ColumnRef="name"> |  | ||||||
| 				<SimpleValue>Usuario industrial de servicios zona franca</SimpleValue> |  | ||||||
| 			</Value> |  | ||||||
| 		</Row> |  | ||||||
| 		<Row> |  | ||||||
| 			<Value ColumnRef="code"> |  | ||||||
| 				<SimpleValue>A-36</SimpleValue> |  | ||||||
| 			</Value> |  | ||||||
| 			<Value ColumnRef="name"> |  | ||||||
| 				<SimpleValue>Usuario operador de zona franca</SimpleValue> |  | ||||||
| 			</Value> |  | ||||||
| 		</Row> |  | ||||||
| 		<Row> |  | ||||||
| 			<Value ColumnRef="code"> |  | ||||||
| 				<SimpleValue>A-37</SimpleValue> |  | ||||||
| 			</Value> |  | ||||||
| 			<Value ColumnRef="name"> |  | ||||||
| 				<SimpleValue>Usuario aduanero permanente</SimpleValue> |  | ||||||
| 			</Value> |  | ||||||
| 		</Row> |  | ||||||
| 		<Row> |  | ||||||
| 			<Value ColumnRef="code"> |  | ||||||
| 				<SimpleValue>A-38</SimpleValue> |  | ||||||
| 			</Value> |  | ||||||
| 			<Value ColumnRef="name"> |  | ||||||
| 				<SimpleValue>Usuario altamente exportador</SimpleValue> |  | ||||||
| 			</Value> |  | ||||||
| 		</Row> |  | ||||||
| 		<Row> |  | ||||||
| 			<Value ColumnRef="code"> |  | ||||||
| 				<SimpleValue>A-39</SimpleValue> |  | ||||||
| 			</Value> |  | ||||||
| 			<Value ColumnRef="name"> |  | ||||||
| 				<SimpleValue>Usuario de zonas económicas especiales de exportación</SimpleValue> |  | ||||||
| 			</Value> |  | ||||||
| 		</Row> |  | ||||||
| 		<Row> |  | ||||||
| 			<Value ColumnRef="code"> |  | ||||||
| 				<SimpleValue>A-40</SimpleValue> |  | ||||||
| 			</Value> |  | ||||||
| 			<Value ColumnRef="name"> |  | ||||||
| 				<SimpleValue>Deposito privado de instalaciones industriales</SimpleValue> |  | ||||||
| 			</Value> |  | ||||||
| 		</Row> |  | ||||||
| 		<Row> |  | ||||||
| 			<Value ColumnRef="code"> |  | ||||||
| 				<SimpleValue>A-41</SimpleValue> |  | ||||||
| 			</Value> |  | ||||||
| 			<Value ColumnRef="name"> |  | ||||||
| 				<SimpleValue>Beneficiarios de programas especiales de exportación PEX</SimpleValue> |  | ||||||
| 			</Value> |  | ||||||
| 		</Row> |  | ||||||
| 		<Row> |  | ||||||
| 			<Value ColumnRef="code"> |  | ||||||
| 				<SimpleValue>A-42</SimpleValue> |  | ||||||
| 			</Value> |  | ||||||
| 			<Value ColumnRef="name"> |  | ||||||
| 				<SimpleValue>Depósitos privados para mercancías en tránsito San Andrés</SimpleValue> |  | ||||||
| 			</Value> |  | ||||||
| 		</Row> |  | ||||||
| 		<Row> |  | ||||||
| 			<Value ColumnRef="code"> |  | ||||||
| 				<SimpleValue>A-43</SimpleValue> |  | ||||||
| 			</Value> |  | ||||||
| 			<Value ColumnRef="name"> |  | ||||||
| 				<SimpleValue>Observadores de las operaciones de importación</SimpleValue> |  | ||||||
| 			</Value> |  | ||||||
| 		</Row> |  | ||||||
| 		<Row> |  | ||||||
| 			<Value ColumnRef="code"> |  | ||||||
| 				<SimpleValue>A-44</SimpleValue> |  | ||||||
| 			</Value> |  | ||||||
| 			<Value ColumnRef="name"> |  | ||||||
| 				<SimpleValue>Usuarios sistemas especiales Importación exportación</SimpleValue> |  | ||||||
| 			</Value> |  | ||||||
| 		</Row> |  | ||||||
| 		<Row> |  | ||||||
| 			<Value ColumnRef="code"> |  | ||||||
| 				<SimpleValue>A-46</SimpleValue> |  | ||||||
| 			</Value> |  | ||||||
| 			<Value ColumnRef="name"> |  | ||||||
| 				<SimpleValue>Transportador 263nformac régimen de importación y/o exportación</SimpleValue> |  | ||||||
| 			</Value> |  | ||||||
| 		</Row> |  | ||||||
| 		<Row> |  | ||||||
| 			<Value ColumnRef="code"> |  | ||||||
| 				<SimpleValue>A-47</SimpleValue> |  | ||||||
| 			</Value> |  | ||||||
| 			<Value ColumnRef="name"> |  | ||||||
| 				<SimpleValue>Transportador terrestre régimen de importación y/o exportación</SimpleValue> |  | ||||||
| 			</Value> |  | ||||||
| 		</Row> |  | ||||||
| 		<Row> |  | ||||||
| 			<Value ColumnRef="code"> |  | ||||||
| 				<SimpleValue>A-48</SimpleValue> |  | ||||||
| 			</Value> |  | ||||||
| 			<Value ColumnRef="name"> |  | ||||||
| 				<SimpleValue>Aeropuerto de servicio publico o privado</SimpleValue> |  | ||||||
| 			</Value> |  | ||||||
| 		</Row> |  | ||||||
| 		<Row> |  | ||||||
| 			<Value ColumnRef="code"> |  | ||||||
| 				<SimpleValue>A-49</SimpleValue> |  | ||||||
| 			</Value> |  | ||||||
| 			<Value ColumnRef="name"> |  | ||||||
| 				<SimpleValue>Transportador fluvial régimen de importación</SimpleValue> |  | ||||||
| 			</Value> |  | ||||||
| 		</Row> |  | ||||||
| 		<Row> |  | ||||||
| 			<Value ColumnRef="code"> |  | ||||||
| 				<SimpleValue>A-50</SimpleValue> |  | ||||||
| 			</Value> |  | ||||||
| 			<Value ColumnRef="name"> |  | ||||||
| 				<SimpleValue>Usuario industrial zona franca especial</SimpleValue> |  | ||||||
| 			</Value> |  | ||||||
| 		</Row> |  | ||||||
| 		<Row> |  | ||||||
| 			<Value ColumnRef="code"> |  | ||||||
| 				<SimpleValue>A-53</SimpleValue> |  | ||||||
| 			</Value> |  | ||||||
| 			<Value ColumnRef="name"> |  | ||||||
| 				<SimpleValue>Agencias de aduanas 1</SimpleValue> |  | ||||||
| 			</Value> |  | ||||||
| 		</Row> |  | ||||||
| 		<Row> |  | ||||||
| 			<Value ColumnRef="code"> |  | ||||||
| 				<SimpleValue>A-54</SimpleValue> |  | ||||||
| 			</Value> |  | ||||||
| 			<Value ColumnRef="name"> |  | ||||||
| 				<SimpleValue>Usuario Operador Zona Franca Especial</SimpleValue> |  | ||||||
| 			</Value> |  | ||||||
| 		</Row> |  | ||||||
| 		<Row> |  | ||||||
| 			<Value ColumnRef="code"> |  | ||||||
| 				<SimpleValue>A-55</SimpleValue> |  | ||||||
| 			</Value> |  | ||||||
| 			<Value ColumnRef="name"> |  | ||||||
| 				<SimpleValue>Agencias de aduanas 2</SimpleValue> |  | ||||||
| 			</Value> |  | ||||||
| 		</Row> |  | ||||||
| 		<Row> |  | ||||||
| 			<Value ColumnRef="code"> |  | ||||||
| 				<SimpleValue>A-56</SimpleValue> |  | ||||||
| 			</Value> |  | ||||||
| 			<Value ColumnRef="name"> |  | ||||||
| 				<SimpleValue>Agencias de aduanas 3</SimpleValue> |  | ||||||
| 			</Value> |  | ||||||
| 		</Row> |  | ||||||
| 		<Row> |  | ||||||
| 			<Value ColumnRef="code"> |  | ||||||
| 				<SimpleValue>A-57</SimpleValue> |  | ||||||
| 			</Value> |  | ||||||
| 			<Value ColumnRef="name"> |  | ||||||
| 				<SimpleValue>Agencias de aduanas 4</SimpleValue> |  | ||||||
| 			</Value> |  | ||||||
| 		</Row> |  | ||||||
| 		<Row> |  | ||||||
| 			<Value ColumnRef="code"> |  | ||||||
| 				<SimpleValue>A-58</SimpleValue> |  | ||||||
| 			</Value> |  | ||||||
| 			<Value ColumnRef="name"> |  | ||||||
| 				<SimpleValue>Transportador aéreo nacional</SimpleValue> |  | ||||||
| 			</Value> |  | ||||||
| 		</Row> |  | ||||||
| 		<Row> |  | ||||||
| 			<Value ColumnRef="code"> |  | ||||||
| 				<SimpleValue>A-60</SimpleValue> |  | ||||||
| 			</Value> |  | ||||||
| 			<Value ColumnRef="name"> |  | ||||||
| 				<SimpleValue>Transportador aéreo, marítimo o fluvial modalidad Cabotaje</SimpleValue> |  | ||||||
| 			</Value> |  | ||||||
| 		</Row> |  | ||||||
| 		<Row> |  | ||||||
| 			<Value ColumnRef="code"> |  | ||||||
| 				<SimpleValue>A-61</SimpleValue> |  | ||||||
| 			</Value> |  | ||||||
| 			<Value ColumnRef="name"> |  | ||||||
| 				<SimpleValue>Importador de alimentos de consumo humano y animal</SimpleValue> |  | ||||||
| 			</Value> |  | ||||||
| 		</Row> |  | ||||||
| 		<Row> |  | ||||||
| 			<Value ColumnRef="code"> |  | ||||||
| 				<SimpleValue>A-62</SimpleValue> |  | ||||||
| 			</Value> |  | ||||||
| 			<Value ColumnRef="name"> |  | ||||||
| 				<SimpleValue>Importador Ocasional</SimpleValue> |  | ||||||
| 			</Value> |  | ||||||
| 		</Row> |  | ||||||
| 		<Row> |  | ||||||
| 			<Value ColumnRef="code"> |  | ||||||
| 				<SimpleValue>A-63</SimpleValue> |  | ||||||
| 			</Value> |  | ||||||
| 			<Value ColumnRef="name"> |  | ||||||
| 				<SimpleValue>Importador de maquinaría y sus partes Decreto 2261 de 2012</SimpleValue> |  | ||||||
| 			</Value> |  | ||||||
| 		</Row> |  | ||||||
| 		<Row> |  | ||||||
| 			<Value ColumnRef="code"> |  | ||||||
| 				<SimpleValue>A-64</SimpleValue> |  | ||||||
| 			</Value> |  | ||||||
| 			<Value ColumnRef="name"> |  | ||||||
| 				<SimpleValue>Beneficiario Programa de Fomento Industria Automotriz-PROFIA</SimpleValue> |  | ||||||
| 			</Value> |  | ||||||
| 		</Row> |  | ||||||
| 		<Row> |  | ||||||
| 			<Value ColumnRef="code"> |  | ||||||
| 				<SimpleValue>A-99</SimpleValue> |  | ||||||
| 			</Value> |  | ||||||
| 			<Value ColumnRef="name"> |  | ||||||
| 				<SimpleValue>Otro tipo de agente aduanero</SimpleValue> |  | ||||||
| 			</Value> |  | ||||||
| 		</Row> |  | ||||||
| 		<Row> |  | ||||||
| 			<Value ColumnRef="code"> |  | ||||||
| 				<SimpleValue>E-01</SimpleValue> |  | ||||||
| 			</Value> |  | ||||||
| 			<Value ColumnRef="name"> |  | ||||||
| 				<SimpleValue>Agencia</SimpleValue> |  | ||||||
| 			</Value> |  | ||||||
| 		</Row> |  | ||||||
| 		<Row> |  | ||||||
| 			<Value ColumnRef="code"> |  | ||||||
| 				<SimpleValue>E-02</SimpleValue> |  | ||||||
| 			</Value> |  | ||||||
| 			<Value ColumnRef="name"> |  | ||||||
| 				<SimpleValue>Establecimiento de comercio</SimpleValue> |  | ||||||
| 			</Value> |  | ||||||
| 		</Row> |  | ||||||
| 		<Row> |  | ||||||
| 			<Value ColumnRef="code"> |  | ||||||
| 				<SimpleValue>E-03</SimpleValue> |  | ||||||
| 			</Value> |  | ||||||
| 			<Value ColumnRef="name"> |  | ||||||
| 				<SimpleValue>Centro de explotación agrícola</SimpleValue> |  | ||||||
| 			</Value> |  | ||||||
| 		</Row> |  | ||||||
| 		<Row> |  | ||||||
| 			<Value ColumnRef="code"> |  | ||||||
| 				<SimpleValue>E-04</SimpleValue> |  | ||||||
| 			</Value> |  | ||||||
| 			<Value ColumnRef="name"> |  | ||||||
| 				<SimpleValue>Centro de explotación animal</SimpleValue> |  | ||||||
| 			</Value> |  | ||||||
| 		</Row> |  | ||||||
| 		<Row> |  | ||||||
| 			<Value ColumnRef="code"> |  | ||||||
| 				<SimpleValue>E-05</SimpleValue> |  | ||||||
| 			</Value> |  | ||||||
| 			<Value ColumnRef="name"> |  | ||||||
| 				<SimpleValue>Centro de explotación minera</SimpleValue> |  | ||||||
| 			</Value> |  | ||||||
| 		</Row> |  | ||||||
| 		<Row> |  | ||||||
| 			<Value ColumnRef="code"> |  | ||||||
| 				<SimpleValue>E-06</SimpleValue> |  | ||||||
| 			</Value> |  | ||||||
| 			<Value ColumnRef="name"> |  | ||||||
| 				<SimpleValue>Centro de explotación de transformación</SimpleValue> |  | ||||||
| 			</Value> |  | ||||||
| 		</Row> |  | ||||||
| 		<Row> |  | ||||||
| 			<Value ColumnRef="code"> |  | ||||||
| 				<SimpleValue>E-07</SimpleValue> |  | ||||||
| 			</Value> |  | ||||||
| 			<Value ColumnRef="name"> |  | ||||||
| 				<SimpleValue>Centro de explotación de servicios</SimpleValue> |  | ||||||
| 			</Value> |  | ||||||
| 		</Row> |  | ||||||
| 		<Row> |  | ||||||
| 			<Value ColumnRef="code"> |  | ||||||
| 				<SimpleValue>E-08</SimpleValue> |  | ||||||
| 			</Value> |  | ||||||
| 			<Value ColumnRef="name"> |  | ||||||
| 				<SimpleValue>Oficina</SimpleValue> |  | ||||||
| 			</Value> |  | ||||||
| 		</Row> |  | ||||||
| 		<Row> |  | ||||||
| 			<Value ColumnRef="code"> |  | ||||||
| 				<SimpleValue>E-09</SimpleValue> |  | ||||||
| 			</Value> |  | ||||||
| 			<Value ColumnRef="name"> |  | ||||||
| 				<SimpleValue>Sede</SimpleValue> |  | ||||||
| 			</Value> |  | ||||||
| 		</Row> |  | ||||||
| 		<Row> |  | ||||||
| 			<Value ColumnRef="code"> |  | ||||||
| 				<SimpleValue>E-10</SimpleValue> |  | ||||||
| 			</Value> |  | ||||||
| 			<Value ColumnRef="name"> |  | ||||||
| 				<SimpleValue>Sucursal</SimpleValue> |  | ||||||
| 			</Value> |  | ||||||
| 		</Row> |  | ||||||
| 		<Row> |  | ||||||
| 			<Value ColumnRef="code"> |  | ||||||
| 				<SimpleValue>E-11</SimpleValue> |  | ||||||
| 			</Value> |  | ||||||
| 			<Value ColumnRef="name"> |  | ||||||
| 				<SimpleValue>Consultorio</SimpleValue> |  | ||||||
| 			</Value> |  | ||||||
| 		</Row> |  | ||||||
| 		<Row> |  | ||||||
| 			<Value ColumnRef="code"> |  | ||||||
| 				<SimpleValue>E-12</SimpleValue> |  | ||||||
| 			</Value> |  | ||||||
| 			<Value ColumnRef="name"> |  | ||||||
| 				<SimpleValue>Administraciones</SimpleValue> |  | ||||||
| 			</Value> |  | ||||||
| 		</Row> |  | ||||||
| 		<Row> |  | ||||||
| 			<Value ColumnRef="code"> |  | ||||||
| 				<SimpleValue>E-13</SimpleValue> |  | ||||||
| 			</Value> |  | ||||||
| 			<Value ColumnRef="name"> |  | ||||||
| 				<SimpleValue>Seccionales</SimpleValue> |  | ||||||
| 			</Value> |  | ||||||
| 		</Row> |  | ||||||
| 		<Row> |  | ||||||
| 			<Value ColumnRef="code"> |  | ||||||
| 				<SimpleValue>E-14</SimpleValue> |  | ||||||
| 			</Value> |  | ||||||
| 			<Value ColumnRef="name"> |  | ||||||
| 				<SimpleValue>Regionales</SimpleValue> |  | ||||||
| 			</Value> |  | ||||||
| 		</Row> |  | ||||||
| 		<Row> |  | ||||||
| 			<Value ColumnRef="code"> |  | ||||||
| 				<SimpleValue>E-15</SimpleValue> |  | ||||||
| 			</Value> |  | ||||||
| 			<Value ColumnRef="name"> |  | ||||||
| 				<SimpleValue>Intendencias</SimpleValue> |  | ||||||
| 			</Value> |  | ||||||
| 		</Row> |  | ||||||
| 		<Row> |  | ||||||
| 			<Value ColumnRef="code"> |  | ||||||
| 				<SimpleValue>E-16</SimpleValue> |  | ||||||
| 			</Value> |  | ||||||
| 			<Value ColumnRef="name"> |  | ||||||
| 				<SimpleValue>Local o negocio</SimpleValue> |  | ||||||
| 			</Value> |  | ||||||
| 		</Row> |  | ||||||
| 		<Row> |  | ||||||
| 			<Value ColumnRef="code"> |  | ||||||
| 				<SimpleValue>E-17</SimpleValue> |  | ||||||
| 			</Value> |  | ||||||
| 			<Value ColumnRef="name"> |  | ||||||
| 				<SimpleValue>Punto de venta</SimpleValue> |  | ||||||
| 			</Value> |  | ||||||
| 		</Row> |  | ||||||
| 		<Row> |  | ||||||
| 			<Value ColumnRef="code"> |  | ||||||
| 				<SimpleValue>E-18</SimpleValue> |  | ||||||
| 			</Value> |  | ||||||
| 			<Value ColumnRef="name"> |  | ||||||
| 				<SimpleValue>Fábrica</SimpleValue> |  | ||||||
| 			</Value> |  | ||||||
| 		</Row> |  | ||||||
| 		<Row> |  | ||||||
| 			<Value ColumnRef="code"> |  | ||||||
| 				<SimpleValue>E-19</SimpleValue> |  | ||||||
| 			</Value> |  | ||||||
| 			<Value ColumnRef="name"> |  | ||||||
| 				<SimpleValue>Taller</SimpleValue> |  | ||||||
| 			</Value> |  | ||||||
| 		</Row> |  | ||||||
| 		<Row> |  | ||||||
| 			<Value ColumnRef="code"> |  | ||||||
| 				<SimpleValue>E-20</SimpleValue> |  | ||||||
| 			</Value> |  | ||||||
| 			<Value ColumnRef="name"> |  | ||||||
| 				<SimpleValue>Cantera</SimpleValue> |  | ||||||
| 			</Value> |  | ||||||
| 		</Row> |  | ||||||
| 		<Row> |  | ||||||
| 			<Value ColumnRef="code"> |  | ||||||
| 				<SimpleValue>E-21</SimpleValue> |  | ||||||
| 			</Value> |  | ||||||
| 			<Value ColumnRef="name"> |  | ||||||
| 				<SimpleValue>Pozo de Petróleo y Gas</SimpleValue> |  | ||||||
| 			</Value> |  | ||||||
| 		</Row> |  | ||||||
| 		<Row> |  | ||||||
| 			<Value ColumnRef="code"> |  | ||||||
| 				<SimpleValue>E-22</SimpleValue> |  | ||||||
| 			</Value> |  | ||||||
| 			<Value ColumnRef="name"> |  | ||||||
| 				<SimpleValue>Otro lug de tipo de extrac explotación de recursos naturales</SimpleValue> |  | ||||||
| 			</Value> |  | ||||||
| 		</Row> |  | ||||||
| 		<Row> |  | ||||||
| 			<Value ColumnRef="code"> |  | ||||||
| 				<SimpleValue>E-99</SimpleValue> |  | ||||||
| 			</Value> |  | ||||||
| 			<Value ColumnRef="name"> |  | ||||||
| 				<SimpleValue>Otro tipo de establecimiento</SimpleValue> |  | ||||||
| 			</Value> |  | ||||||
| 		</Row> |  | ||||||
| 		<Row> |  | ||||||
| 			<Value ColumnRef="code"> |  | ||||||
| 				<SimpleValue>O-13</SimpleValue> |  | ||||||
| 			</Value> |  | ||||||
| 			<Value ColumnRef="name"> |  | ||||||
| 				<SimpleValue>Gran contribuyente</SimpleValue> |  | ||||||
| 			</Value> |  | ||||||
| 		</Row> |  | ||||||
| 		<Row> |  | ||||||
| 			<Value ColumnRef="code"> |  | ||||||
| 				<SimpleValue>O-15</SimpleValue> |  | ||||||
| 			</Value> |  | ||||||
| 			<Value ColumnRef="name"> |  | ||||||
| 				<SimpleValue>Autorretenedor</SimpleValue> |  | ||||||
| 			</Value> |  | ||||||
| 		</Row> |  | ||||||
| 		<Row> |  | ||||||
| 			<Value ColumnRef="code"> |  | ||||||
| 				<SimpleValue>O-23</SimpleValue> |  | ||||||
| 			</Value> |  | ||||||
| 			<Value ColumnRef="name"> |  | ||||||
| 				<SimpleValue>Agente de retención IVA</SimpleValue> |  | ||||||
| 			</Value> |  | ||||||
| 		</Row> |  | ||||||
| 		<Row> |  | ||||||
| 			<Value ColumnRef="code"> |  | ||||||
| 				<SimpleValue>O-47</SimpleValue> |  | ||||||
| 			</Value> |  | ||||||
| 			<Value ColumnRef="name"> |  | ||||||
| 				<SimpleValue>Régimen simple de tributación</SimpleValue> |  | ||||||
| 			</Value> |  | ||||||
| 		</Row> |  | ||||||
| 		<Row> | 		<Row> | ||||||
| 			<Value ColumnRef="code"> | 			<Value ColumnRef="code"> | ||||||
| 				<SimpleValue>R-99-PN</SimpleValue> | 				<SimpleValue>R-99-PN</SimpleValue> | ||||||
|   | |||||||
| @@ -62,5 +62,13 @@ | |||||||
| 				<SimpleValue>Régimen simple de tributación</SimpleValue> | 				<SimpleValue>Régimen simple de tributación</SimpleValue> | ||||||
| 			</Value> | 			</Value> | ||||||
| 		</Row> | 		</Row> | ||||||
|  | 		<Row> | ||||||
|  | 			<Value ColumnRef="code"> | ||||||
|  | 				<SimpleValue>ZZ</SimpleValue> | ||||||
|  | 			</Value> | ||||||
|  | 			<Value ColumnRef="name"> | ||||||
|  | 				<SimpleValue>No aplica</SimpleValue> | ||||||
|  | 			</Value> | ||||||
|  | 		</Row> | ||||||
| 	</SimpleCodeList> | 	</SimpleCodeList> | ||||||
| </gc:CodeList> | </gc:CodeList> | ||||||
|   | |||||||
							
								
								
									
										156
									
								
								facho/fe/data/dian/codelist/TipoTrabajador-2.1.gc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										156
									
								
								facho/fe/data/dian/codelist/TipoTrabajador-2.1.gc
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,156 @@ | |||||||
|  | <?xml version="1.0" encoding="UTF-8"?> | ||||||
|  | <!-- | ||||||
|  |      creado por facho, la dian tiene oficial? | ||||||
|  |      poblar usando anexo tecnico 5.5.3 | ||||||
|  | --> | ||||||
|  | <gc:CodeList xmlns:gc="http://docs.oasis-open.org/codelist/ns/genericode/1.0/"> | ||||||
|  | 	<Identification> | ||||||
|  | 		<ShortName>TipoTrabajador</ShortName> | ||||||
|  | 		<LongName xml:lang="es">Tipos de trabajadores</LongName> | ||||||
|  | 		<Version>1</Version> | ||||||
|  | 	</Identification> | ||||||
|  | 	<ColumnSet> | ||||||
|  | 		<Column Id="code" Use="required"> | ||||||
|  | 			<ShortName>Code</ShortName> | ||||||
|  | 			<Data Type="normalizedString"/> | ||||||
|  | 		</Column> | ||||||
|  | 		<Column Id="name" Use="required"> | ||||||
|  | 			<ShortName>Nombre</ShortName> | ||||||
|  | 			<Data Type="normalizedString"/> | ||||||
|  | 		</Column> | ||||||
|  | 		<Key Id="codeKey"> | ||||||
|  | 			<ShortName>CodeKey</ShortName> | ||||||
|  | 			<ColumnRef Ref="code"/> | ||||||
|  | 		</Key> | ||||||
|  | 	</ColumnSet> | ||||||
|  | 	<SimpleCodeList> | ||||||
|  | 		<Row> | ||||||
|  | 			<Value ColumnRef="code"> | ||||||
|  | 				<SimpleValue>01</SimpleValue> | ||||||
|  | 			</Value> | ||||||
|  | 			<Value ColumnRef="name"> | ||||||
|  | 				<SimpleValue>Dependiente</SimpleValue> | ||||||
|  | 			</Value> | ||||||
|  | 		</Row> | ||||||
|  | 		<Row> | ||||||
|  | 			<Value ColumnRef="code"> | ||||||
|  | 				<SimpleValue>02</SimpleValue> | ||||||
|  | 			</Value> | ||||||
|  | 			<Value ColumnRef="name"> | ||||||
|  | 				<SimpleValue>Servicio domestico</SimpleValue> | ||||||
|  | 			</Value> | ||||||
|  | 		</Row> | ||||||
|  | 		<Row> | ||||||
|  | 			<Value ColumnRef="code"> | ||||||
|  | 				<SimpleValue>04</SimpleValue> | ||||||
|  | 			</Value> | ||||||
|  | 			<Value ColumnRef="name"> | ||||||
|  | 				<SimpleValue>Madre comunitaria</SimpleValue> | ||||||
|  | 			</Value> | ||||||
|  | 		</Row> | ||||||
|  | 		<Row> | ||||||
|  | 			<Value ColumnRef="code"> | ||||||
|  | 				<SimpleValue>12</SimpleValue> | ||||||
|  | 			</Value> | ||||||
|  | 			<Value ColumnRef="name"> | ||||||
|  | 				<SimpleValue>Aprendices del Sena en etapa lectiva</SimpleValue> | ||||||
|  | 			</Value> | ||||||
|  | 		</Row> | ||||||
|  | 		<Row> | ||||||
|  | 			<Value ColumnRef="code"> | ||||||
|  | 				<SimpleValue>18</SimpleValue> | ||||||
|  | 			</Value> | ||||||
|  | 			<Value ColumnRef="name"> | ||||||
|  | 				<SimpleValue>Funcionarios públicos sin tope máximo de ibc</SimpleValue> | ||||||
|  | 			</Value> | ||||||
|  | 		</Row> | ||||||
|  | 		<Row> | ||||||
|  | 			<Value ColumnRef="code"> | ||||||
|  | 				<SimpleValue>19</SimpleValue> | ||||||
|  | 			</Value> | ||||||
|  | 			<Value ColumnRef="name"> | ||||||
|  | 				<SimpleValue>Aprendices del SENA en etapa productiva</SimpleValue> | ||||||
|  | 			</Value> | ||||||
|  | 		</Row> | ||||||
|  | 		<Row> | ||||||
|  | 			<Value ColumnRef="code"> | ||||||
|  | 				<SimpleValue>21</SimpleValue> | ||||||
|  | 			</Value> | ||||||
|  | 			<Value ColumnRef="name"> | ||||||
|  | 				<SimpleValue>Estudiantes de postgrado en salud</SimpleValue> | ||||||
|  | 			</Value> | ||||||
|  | 		</Row> | ||||||
|  | 		<Row> | ||||||
|  | 			<Value ColumnRef="code"> | ||||||
|  | 				<SimpleValue>22</SimpleValue> | ||||||
|  | 			</Value> | ||||||
|  | 			<Value ColumnRef="name"> | ||||||
|  | 				<SimpleValue>Profesor de establecimiento particular</SimpleValue> | ||||||
|  | 			</Value> | ||||||
|  | 		</Row> | ||||||
|  | 		<Row> | ||||||
|  | 			<Value ColumnRef="code"> | ||||||
|  | 				<SimpleValue>23</SimpleValue> | ||||||
|  | 			</Value> | ||||||
|  | 			<Value ColumnRef="name"> | ||||||
|  | 				<SimpleValue>Estudiantes aportes solo riesgos laborales</SimpleValue> | ||||||
|  | 			</Value> | ||||||
|  | 		</Row> | ||||||
|  | 		<Row> | ||||||
|  | 			<Value ColumnRef="code"> | ||||||
|  | 				<SimpleValue>30</SimpleValue> | ||||||
|  | 			</Value> | ||||||
|  | 			<Value ColumnRef="name"> | ||||||
|  | 				<SimpleValue>Dependiente entidades o universidades públicas con régimen especial en salud</SimpleValue> | ||||||
|  | 			</Value> | ||||||
|  | 		</Row> | ||||||
|  | 		<Row> | ||||||
|  | 			<Value ColumnRef="code"> | ||||||
|  | 				<SimpleValue>31</SimpleValue> | ||||||
|  | 			</Value> | ||||||
|  | 			<Value ColumnRef="name"> | ||||||
|  | 				<SimpleValue>Cooperados o pre cooperativas de trabajo asociado</SimpleValue> | ||||||
|  | 			</Value> | ||||||
|  | 		</Row> | ||||||
|  | 		<Row> | ||||||
|  | 			<Value ColumnRef="code"> | ||||||
|  | 				<SimpleValue>47</SimpleValue> | ||||||
|  | 			</Value> | ||||||
|  | 			<Value ColumnRef="name"> | ||||||
|  | 				<SimpleValue>Trabajador dependiente de entidad beneficiaria del sistema general de participaciones ‐ aportes patronales</SimpleValue> | ||||||
|  | 			</Value> | ||||||
|  | 		</Row> | ||||||
|  | 		<Row> | ||||||
|  | 			<Value ColumnRef="code"> | ||||||
|  | 				<SimpleValue>51</SimpleValue> | ||||||
|  | 			</Value> | ||||||
|  | 			<Value ColumnRef="name"> | ||||||
|  | 				<SimpleValue>Trabajador de tiempo parcial</SimpleValue> | ||||||
|  | 			</Value> | ||||||
|  | 		</Row> | ||||||
|  | 		<Row> | ||||||
|  | 			<Value ColumnRef="code"> | ||||||
|  | 				<SimpleValue>54</SimpleValue> | ||||||
|  | 			</Value> | ||||||
|  | 			<Value ColumnRef="name"> | ||||||
|  | 				<SimpleValue>Pre pensionado de entidad en liquidación.</SimpleValue> | ||||||
|  | 			</Value> | ||||||
|  | 		</Row> | ||||||
|  | 		<Row> | ||||||
|  | 			<Value ColumnRef="code"> | ||||||
|  | 				<SimpleValue>56</SimpleValue> | ||||||
|  | 			</Value> | ||||||
|  | 			<Value ColumnRef="name"> | ||||||
|  | 				<SimpleValue>Pre pensionado con aporte voluntario a salud</SimpleValue> | ||||||
|  | 			</Value> | ||||||
|  | 		</Row> | ||||||
|  | 		<Row> | ||||||
|  | 			<Value ColumnRef="code"> | ||||||
|  | 				<SimpleValue>58</SimpleValue> | ||||||
|  | 			</Value> | ||||||
|  | 			<Value ColumnRef="name"> | ||||||
|  | 				<SimpleValue>Estudiantes de prácticas laborales en el sector público</SimpleValue> | ||||||
|  | 			</Value> | ||||||
|  | 		</Row> | ||||||
|  |         </SimpleCodeList> | ||||||
|  | </gc:CodeList> | ||||||
| @@ -12,9 +12,6 @@ class CodeList: | |||||||
|         self.short_name = '' |         self.short_name = '' | ||||||
|         self.long_name = '' |         self.long_name = '' | ||||||
|         self.version = 1 |         self.version = 1 | ||||||
|         self.canonical_uri = '' |  | ||||||
|         self.canonical_version_uri = '' |  | ||||||
|         self.location_uri = '' |  | ||||||
|  |  | ||||||
|         self.name_column = name_column |         self.name_column = name_column | ||||||
|         self.rows = {} |         self.rows = {} | ||||||
| @@ -27,9 +24,6 @@ class CodeList: | |||||||
|         self.short_name = tree.find('./Identification/ShortName').text |         self.short_name = tree.find('./Identification/ShortName').text | ||||||
|         self.long_name = tree.find('./Identification/LongName').text |         self.long_name = tree.find('./Identification/LongName').text | ||||||
|         self.version = tree.find('./Identification/Version').text |         self.version = tree.find('./Identification/Version').text | ||||||
|         self.canonical_uri = tree.find('./Identification/CanonicalUri').text |  | ||||||
|         self.canonical_version_uri = tree.find('./Identification/CanonicalVersionUri').text |  | ||||||
|         self.location_uri = tree.find('./Identification/LocationUri').text |  | ||||||
|  |  | ||||||
|         #obtener registros... |         #obtener registros... | ||||||
|         for row in tree.findall('./SimpleCodeList/Row'): |         for row in tree.findall('./SimpleCodeList/Row'): | ||||||
| @@ -88,10 +82,16 @@ TipoAmbiente = CodeList(path_for_codelist('TipoAmbiente-2.1.gc'), 'code', 'name' | |||||||
| TipoDocumento = CodeList(path_for_codelist('TipoDocumento-2.1.gc'), 'code', 'name') | TipoDocumento = CodeList(path_for_codelist('TipoDocumento-2.1.gc'), 'code', 'name') | ||||||
| TipoImpuesto = CodeList(path_for_codelist('TipoImpuesto-2.1.gc'), 'code', 'name')\ | TipoImpuesto = CodeList(path_for_codelist('TipoImpuesto-2.1.gc'), 'code', 'name')\ | ||||||
|     .update(CodeList(path_for_codelist('TipoImpuesto-2.1.custom.gc'), 'code', 'name')) |     .update(CodeList(path_for_codelist('TipoImpuesto-2.1.custom.gc'), 'code', 'name')) | ||||||
|  | TarifaImpuesto = CodeList(path_for_codelist('TarifaImpuestoINC-2.1.gc'), 'code', 'name')\ | ||||||
|  |         .update(CodeList(path_for_codelist('TarifaImpuestoIVA-2.1.gc'), 'code', 'name'))\ | ||||||
|  |         .update(CodeList(path_for_codelist('TarifaImpuestoReteIVA-2.1.gc'), 'code', 'name'))\ | ||||||
|  |         .update(CodeList(path_for_codelist('TarifaImpuestoReteRenta-2.1.gc'), 'code', 'name')) | ||||||
| CodigoPrecioReferencia = CodeList(path_for_codelist('CodigoPrecioReferencia-2.1.gc'), 'code', 'name') | CodigoPrecioReferencia = CodeList(path_for_codelist('CodigoPrecioReferencia-2.1.gc'), 'code', 'name') | ||||||
| MediosPago = CodeList(path_for_codelist('MediosPago-2.1.gc'), 'code', 'name') | MediosPago = CodeList(path_for_codelist('MediosPago-2.1.gc'), 'code', 'name') | ||||||
|  | FormasPago = CodeList(path_for_codelist('FormasPago-2.1.gc'), 'code', 'name') | ||||||
| RegimenFiscal = CodeList(path_for_codelist('RegimenFiscal-2.1.custom.gc'), 'code', 'name') | RegimenFiscal = CodeList(path_for_codelist('RegimenFiscal-2.1.custom.gc'), 'code', 'name') | ||||||
| TipoOperacionNC = CodeList(path_for_codelist('TipoOperacionNC-2.1.gc'), 'code', 'name') | TipoOperacionNC = CodeList(path_for_codelist('TipoOperacionNC-2.1.gc'), 'code', 'name') | ||||||
|  | TipoOperacionNCDS = CodeList(path_for_codelist('TipoOperacionNCDS-2.1.gc'), 'code', 'name') | ||||||
| TipoOperacionND = CodeList(path_for_codelist('TipoOperacionND-2.1 - copia.gc'), 'code', 'name') | TipoOperacionND = CodeList(path_for_codelist('TipoOperacionND-2.1 - copia.gc'), 'code', 'name') | ||||||
| TipoOperacionF = CodeList(path_for_codelist('TipoOperacionF-2.1.gc'), 'code', 'name')\ | TipoOperacionF = CodeList(path_for_codelist('TipoOperacionF-2.1.gc'), 'code', 'name')\ | ||||||
|     .update(CodeList(path_for_codelist('TipoOperacionF-2.1.custom.gc'), 'code', 'name')) |     .update(CodeList(path_for_codelist('TipoOperacionF-2.1.custom.gc'), 'code', 'name')) | ||||||
| @@ -101,3 +101,9 @@ Paises = CodeList(path_for_codelist('Paises-2.1.gc'), 'code', 'name') | |||||||
| TipoIdFiscal = CodeList(path_for_codelist('TipoIdFiscal-2.1.gc'), 'code', 'name') | TipoIdFiscal = CodeList(path_for_codelist('TipoIdFiscal-2.1.gc'), 'code', 'name') | ||||||
| CodigoDescuento = CodeList(path_for_codelist('CodigoDescuento-2.1.gc'), 'code', 'name') | CodigoDescuento = CodeList(path_for_codelist('CodigoDescuento-2.1.gc'), 'code', 'name') | ||||||
| UnidadesMedida = CodeList(path_for_codelist('UnidadesMedida-2.1.gc'), 'code', 'name') | UnidadesMedida = CodeList(path_for_codelist('UnidadesMedida-2.1.gc'), 'code', 'name') | ||||||
|  | TipoTrabajador = CodeList(path_for_codelist('TipoTrabajador-2.1.gc'), 'code', 'name') | ||||||
|  | SubTipoTrabajador = CodeList(path_for_codelist('SubTipoTrabajador-2.1.gc'), 'code', 'name') | ||||||
|  | TipoContrato = CodeList(path_for_codelist('TipoContrato-2.1.gc'), 'code', 'name') | ||||||
|  | PeriodoNomina = CodeList(path_for_codelist('PeriodoNomina-2.1.gc'), 'code', 'name') | ||||||
|  | TipoMoneda = CodeList(path_for_codelist('TipoMoneda-2.1.gc'), 'code', 'name') | ||||||
|  | IdiomaISO6391 = CodeList(path_for_codelist('Idioma-2.1.gc'), 'iso-639-1', 'name') | ||||||
|   | |||||||
							
								
								
									
										213
									
								
								facho/fe/fe.py
									
									
									
									
									
								
							
							
						
						
									
										213
									
								
								facho/fe/fe.py
									
									
									
									
									
								
							| @@ -1,6 +1,5 @@ | |||||||
| # This file is part of facho.  The COPYRIGHT file at the top level of | # This file is part of facho.  The COPYRIGHT file at the top level of | ||||||
| # this repository contains the full copyright notices and license terms. | # this repository contains the full copyright notices and license terms. | ||||||
|  |  | ||||||
| from ..facho import FachoXML, FachoXMLExtension, LXMLBuilder | from ..facho import FachoXML, FachoXMLExtension, LXMLBuilder | ||||||
| import uuid | import uuid | ||||||
| import xmlsig | import xmlsig | ||||||
| @@ -8,13 +7,16 @@ import xades | |||||||
| from datetime import datetime | from datetime import datetime | ||||||
| import OpenSSL | import OpenSSL | ||||||
| import zipfile | import zipfile | ||||||
| import warnings | # import warnings | ||||||
| import hashlib | import hashlib | ||||||
| from contextlib import contextmanager | from contextlib import contextmanager | ||||||
| from .data.dian import codelist | from .data.dian import codelist | ||||||
| from . import form | from . import form | ||||||
| from collections import defaultdict | from collections import defaultdict | ||||||
| from pathlib import Path | # from pathlib import Path | ||||||
|  | from dateutil import tz | ||||||
|  |  | ||||||
|  | from cryptography.hazmat.primitives.serialization import pkcs12 | ||||||
|  |  | ||||||
| AMBIENTE_PRUEBAS = codelist.TipoAmbiente.by_name('Pruebas')['code'] | AMBIENTE_PRUEBAS = codelist.TipoAmbiente.by_name('Pruebas')['code'] | ||||||
| AMBIENTE_PRODUCCION = codelist.TipoAmbiente.by_name('Producción')['code'] | AMBIENTE_PRODUCCION = codelist.TipoAmbiente.by_name('Producción')['code'] | ||||||
| @@ -26,34 +28,53 @@ SCHEME_AGENCY_ATTRS = { | |||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| pwd = Path(__file__).parent |  | ||||||
| # RESOLUCION 0001: pagina 516 | # RESOLUCION 0001: pagina 516 | ||||||
| POLICY_ID = 'file://'+str(pwd)+'/data/dian/politicadefirmav2.pdf' | POLICY_ID = 'https://facturaelectronica.dian.gov.co/politicadefirma/v2/politicadefirmav2.pdf' | ||||||
| POLICY_NAME = u'Política de firma para facturas electrónicas de la República de Colombia.' | POLICY_NAME = u'Política de firma para facturas electrónicas de la República de Colombia.' | ||||||
|  |  | ||||||
|  | Bogota = tz.gettz('America/Bogota') | ||||||
|  | # NAMESPACES = { | ||||||
|  | #     'atd': 'urn:oasis:names:specification:ubl:schema:xsd:AttachedDocument-2', | ||||||
|  | #     'nomina': 'dian:gov:co:facturaelectronica:NominaIndividual', | ||||||
|  | #     'nominaajuste': 'dian:gov:co:facturaelectronica:NominaIndividualDeAjuste',     | ||||||
|  | #     'fe': 'http://www.dian.gov.co/contratos/facturaelectronica/v1', | ||||||
|  | #     'xs': 'http://www.w3.org/2001/XMLSchema-instance',     | ||||||
|  | #     'cac': 'urn:oasis:names:specification:ubl:schema:xsd:CommonAggregateComponents-2', | ||||||
|  | #     'cbc': 'urn:oasis:names:specification:ubl:schema:xsd:CommonBasicComponents-2', | ||||||
|  | #     'cdt': 'urn:DocumentInformation:names:specification:ubl:colombia:schema:xsd:DocumentInformationAggregateComponents-1', | ||||||
|  | #     'clm54217': 'urn:un:unece:uncefact:codelist:specification:54217:2001', | ||||||
|  | #     'clmIANAMIMEMediaType': 'urn:un:unece:uncefact:codelist:specification:IANAMIMEMediaType:2003', | ||||||
|  | #     'ext': 'urn:oasis:names:specification:ubl:schema:xsd:CommonExtensionComponents-2', | ||||||
|  | #     'qdt': 'urn:oasis:names:specification:ubl:schema:xsd:QualifiedDatatypes-2', | ||||||
|  | #     'sts': 'dian:gov:co:facturaelectronica:Structures-2-1', | ||||||
|  | #     'udt': 'urn:un:unece:uncefact:data:specification:UnqualifiedDataTypesSchemaModule:2', | ||||||
|  | #     'xsi': 'http://www.w3.org/2001/XMLSchema-instance', | ||||||
|  | #     'xades': 'http://uri.etsi.org/01903/v1.3.2#', | ||||||
|  | #     'xades141': 'http://uri.etsi.org/01903/v1.4.1#',     | ||||||
|  | #     'ds': 'http://www.w3.org/2000/09/xmldsig#', | ||||||
|  | #     'sig': 'http://www.w3.org/2000/09/xmldsig#', | ||||||
|  | # } | ||||||
|  |  | ||||||
|  |  | ||||||
| NAMESPACES = { | NAMESPACES = { | ||||||
|     'facho': 'http://git.disroot.org/Etrivial/facho', |  | ||||||
|     'fe': 'http://www.dian.gov.co/contratos/facturaelectronica/v1', |     'fe': 'http://www.dian.gov.co/contratos/facturaelectronica/v1', | ||||||
|     'cac': 'urn:oasis:names:specification:ubl:schema:xsd:CommonAggregateComponents-2', |     'cac': 'urn:oasis:names:specification:ubl:schema:xsd:CommonAggregateComponents-2', | ||||||
|     'cbc': 'urn:oasis:names:specification:ubl:schema:xsd:CommonBasicComponents-2', |     'cbc': 'urn:oasis:names:specification:ubl:schema:xsd:CommonBasicComponents-2', | ||||||
|     'cdt': 'urn:DocumentInformation:names:specification:ubl:colombia:schema:xsd:DocumentInformationAggregateComponents-1', |  | ||||||
|     'clm54217': 'urn:un:unece:uncefact:codelist:specification:54217:2001', |  | ||||||
|     'clmIANAMIMEMediaType': 'urn:un:unece:uncefact:codelist:specification:IANAMIMEMediaType:2003', |  | ||||||
|     'ext': 'urn:oasis:names:specification:ubl:schema:xsd:CommonExtensionComponents-2', |     'ext': 'urn:oasis:names:specification:ubl:schema:xsd:CommonExtensionComponents-2', | ||||||
|     'qdt': 'urn:oasis:names:specification:ubl:schema:xsd:QualifiedDatatypes-2', |     'qdt': 'urn:oasis:names:specification:ubl:schema:xsd:QualifiedDatatypes-2', | ||||||
|     'sts': 'dian:gov:co:facturaelectronica:Structures-2-1', |     'sts': 'dian:gov:co:facturaelectronica:Structures-2-1', | ||||||
|     'udt': 'urn:un:unece:uncefact:data:specification:UnqualifiedDataTypesSchemaModule:2',  |     'udt': 'urn:un:unece:uncefact:data:specification:UnqualifiedDataTypesSchemaModule:2',  | ||||||
|     'xsi': 'http://www.w3.org/2001/XMLSchema-instance', |     'xsi': 'http://www.w3.org/2001/XMLSchema-instance', | ||||||
|     'xades': 'http://uri.etsi.org/01903/v1.3.2#', |  | ||||||
|     'ds': 'http://www.w3.org/2000/09/xmldsig#', |     'ds': 'http://www.w3.org/2000/09/xmldsig#', | ||||||
|     'sig': 'http://www.w3.org/2000/09/xmldsig#', |     'xades': 'http://uri.etsi.org/01903/v1.3.2#', | ||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| def fe_from_string(document: str) -> FachoXML: | def fe_from_string(document: str) -> FachoXML: | ||||||
|     return FeXML.from_string(document) |     return FeXML.from_string(document) | ||||||
|  |  | ||||||
| from contextlib import contextmanager |  | ||||||
|  | # from contextlib import contextmanager | ||||||
| @contextmanager | @contextmanager | ||||||
| def mock_xades_policy(): | def mock_xades_policy(): | ||||||
|     from mock import patch |     from mock import patch | ||||||
| @@ -61,6 +82,7 @@ def mock_xades_policy(): | |||||||
|     with patch('xades.policy.urllib.urlopen') as mock: |     with patch('xades.policy.urllib.urlopen') as mock: | ||||||
|         class UrllibPolicyMock: |         class UrllibPolicyMock: | ||||||
|             def read(self): |             def read(self): | ||||||
|  |                 # Usamos contenido de archivo local | ||||||
|                 cur_dir = os.path.dirname(os.path.abspath(__file__)) |                 cur_dir = os.path.dirname(os.path.abspath(__file__)) | ||||||
|                 data_dir = os.path.join(cur_dir, 'data', 'dian') |                 data_dir = os.path.join(cur_dir, 'data', 'dian') | ||||||
|                 policy_file = os.path.join(data_dir, 'politicadefirmav2.pdf') |                 policy_file = os.path.join(data_dir, 'politicadefirmav2.pdf') | ||||||
| @@ -74,26 +96,30 @@ def mock_xades_policy(): | |||||||
| class FeXML(FachoXML): | class FeXML(FachoXML): | ||||||
|  |  | ||||||
|     def __init__(self, root, namespace): |     def __init__(self, root, namespace): | ||||||
|  |         # raise Exception(namespace) | ||||||
|         super().__init__("{%s}%s" % (namespace, root), |         super().__init__("{%s}%s" % (namespace, root), | ||||||
|                          nsmap=NAMESPACES) |                          nsmap=NAMESPACES) | ||||||
|  |  | ||||||
|         self._cn = root.rstrip('/') |  | ||||||
|         #self.find_or_create_element(self._cn) |  | ||||||
|  |  | ||||||
|     @classmethod |     @classmethod | ||||||
|     def from_string(cls, document: str) -> 'FeXML': |     def from_string(cls, document: str) -> 'FeXML': | ||||||
|         return super().from_string(document, namespaces=NAMESPACES) |         return super().from_string(document, namespaces=NAMESPACES) | ||||||
|  |  | ||||||
|     def tostring(self, **kw): |     def tostring(self, **kw): | ||||||
|  |         # MACHETE(bit4bit) la DIAN espera que la etiqueta raiz no este en un namespace | ||||||
|  |         root_namespace = self.root_namespace() | ||||||
|  |         root_localname = self.root_localname() | ||||||
|  |         xmlns_name = {v: k for k, v in NAMESPACES.items()}[root_namespace] | ||||||
|  |         if root_localname == 'Invoice': | ||||||
|  |             urn_oasis = 'urn:oasis:names:specification:ubl:schema:xsd:Invoice-2' | ||||||
|  |         if root_localname == 'CreditNote': | ||||||
|  |             urn_oasis = 'urn:oasis:names:specification:ubl:schema:xsd:CreditNote-2' | ||||||
|         return super().tostring(**kw)\ |         return super().tostring(**kw)\ | ||||||
|             .replace("fe:", "")\ |                         .replace(xmlns_name + ':', '')\ | ||||||
|             .replace("xmlns:fe", "xmlns") |                         .replace('xmlns:'+xmlns_name, 'xmlns')\ | ||||||
|  |                         .replace(root_namespace, urn_oasis) | ||||||
|  |  | ||||||
|  |  | ||||||
| class DianXMLExtensionCUDFE(FachoXMLExtension): | class DianXMLExtensionCUDFE(FachoXMLExtension): | ||||||
|  |  | ||||||
|     def __init__(self, invoice, tipo_ambiente=AMBIENTE_PRUEBAS): |     def __init__(self, invoice, tipo_ambiente=AMBIENTE_PRUEBAS): | ||||||
|         self.tipo_ambiente = tipo_ambiente |         self.tipo_ambiente = tipo_ambiente | ||||||
|         self.invoice = invoice |         self.invoice = invoice | ||||||
| @@ -119,10 +145,24 @@ class DianXMLExtensionCUDFE(FachoXMLExtension): | |||||||
|         fachoxml.set_element('./cbc:UUID', cufe, |         fachoxml.set_element('./cbc:UUID', cufe, | ||||||
|                              schemeID=self.tipo_ambiente, |                              schemeID=self.tipo_ambiente, | ||||||
|                              schemeName=self.schemeName()) |                              schemeName=self.schemeName()) | ||||||
|         fachoxml.set_element('./cbc:ProfileID', 'DIAN 2.1') |  | ||||||
|         fachoxml.set_element('./cbc:ProfileExecutionID', self._tipo_ambiente_int()) |         if self.schemeName() == "CUDS-SHA384": | ||||||
|  |             if fachoxml.tag_document() == 'Invoice': | ||||||
|  |                 fachoxml.set_element('./cbc:ProfileID', | ||||||
|  |                         'DIAN 2.1: documento soporte en adquisiciones efectuadas a no obligados a facturar.') | ||||||
|  |             else: | ||||||
|  |                 fachoxml.set_element('./cbc:ProfileID', | ||||||
|  |                         'DIAN 2.1: Nota de ajuste al documento soporte en adquisiciones efectuadas a sujetos no obligados a expedir factura o documento equivalente') | ||||||
|  |         else: | ||||||
|  |             fachoxml.set_element('./cbc:ProfileID', 'DIAN 2.1: Factura Electrónica de Venta') | ||||||
|  |  | ||||||
|  |         # #DIAN 1.8.-2021: FAD03 | ||||||
|  |         # fachoxml.set_element('./cbc:ProfileID', 'DIAN 2.1: Factura Electrónica de Venta') | ||||||
|  |         fachoxml.set_element( | ||||||
|  |             './cbc:ProfileExecutionID', self._tipo_ambiente_int()) | ||||||
|         #DIAN 1.7.-2020: FAB36 |         #DIAN 1.7.-2020: FAB36 | ||||||
|         fachoxml.set_element('./ext:UBLExtensions/ext:UBLExtension/ext:ExtensionContent/sts:DianExtensions/sts:QRCode', |         fachoxml.set_element( | ||||||
|  |             './ext:UBLExtensions/ext:UBLExtension/ext:ExtensionContent/sts:DianExtensions/sts:QRCode', | ||||||
|             self._get_qrcode(cufe)) |             self._get_qrcode(cufe)) | ||||||
|  |  | ||||||
|     def issue_time(self, datetime_): |     def issue_time(self, datetime_): | ||||||
| @@ -139,7 +179,8 @@ class DianXMLExtensionCUDFE(FachoXMLExtension): | |||||||
|         build_vars['HoraFac'] = self.issue_time(invoice.invoice_issue) |         build_vars['HoraFac'] = self.issue_time(invoice.invoice_issue) | ||||||
|         # PAG 601 |         # PAG 601 | ||||||
|         build_vars['ValorBruto'] = invoice.invoice_legal_monetary_total.line_extension_amount |         build_vars['ValorBruto'] = invoice.invoice_legal_monetary_total.line_extension_amount | ||||||
|         build_vars['ValorTotalPagar'] = invoice.invoice_legal_monetary_total.payable_amount |         build_vars['ValorTotalPagar' | ||||||
|  |                    ] = invoice.invoice_legal_monetary_total.payable_amount | ||||||
|         ValorImpuestoPara = defaultdict(lambda: form.Amount(0.0)) |         ValorImpuestoPara = defaultdict(lambda: form.Amount(0.0)) | ||||||
|         build_vars['CodImpuesto1'] = '01' |         build_vars['CodImpuesto1'] = '01' | ||||||
|         build_vars['CodImpuesto2'] = '04' |         build_vars['CodImpuesto2'] = '04' | ||||||
| @@ -169,7 +210,8 @@ class DianXMLExtensionCUDFE(FachoXMLExtension): | |||||||
|  |  | ||||||
|  |  | ||||||
| class DianXMLExtensionCUFE(DianXMLExtensionCUDFE): | class DianXMLExtensionCUFE(DianXMLExtensionCUDFE): | ||||||
|     def __init__(self, invoice,  clave_tecnica = '', tipo_ambiente = AMBIENTE_PRUEBAS): |     def __init__( | ||||||
|  |             self, invoice,  clave_tecnica='', tipo_ambiente=AMBIENTE_PRUEBAS): | ||||||
|         self.tipo_ambiente = tipo_ambiente |         self.tipo_ambiente = tipo_ambiente | ||||||
|         self.clave_tecnica = clave_tecnica |         self.clave_tecnica = clave_tecnica | ||||||
|         self.invoice = invoice |         self.invoice = invoice | ||||||
| @@ -205,6 +247,7 @@ class DianXMLExtensionCUFE(DianXMLExtensionCUDFE): | |||||||
|             '%d' % build_vars['TipoAmb'], |             '%d' % build_vars['TipoAmb'], | ||||||
|         ] |         ] | ||||||
|  |  | ||||||
|  |  | ||||||
| class DianXMLExtensionCUDE(DianXMLExtensionCUDFE): | class DianXMLExtensionCUDE(DianXMLExtensionCUDFE): | ||||||
|     def __init__(self, invoice, software_pin, tipo_ambiente = AMBIENTE_PRUEBAS): |     def __init__(self, invoice, software_pin, tipo_ambiente = AMBIENTE_PRUEBAS): | ||||||
|         self.tipo_ambiente = tipo_ambiente |         self.tipo_ambiente = tipo_ambiente | ||||||
| @@ -242,6 +285,41 @@ class DianXMLExtensionCUDE(DianXMLExtensionCUDFE): | |||||||
|             '%d' % build_vars['TipoAmb'], |             '%d' % build_vars['TipoAmb'], | ||||||
|         ] |         ] | ||||||
|  |  | ||||||
|  |  | ||||||
|  | class DianXMLExtensionCUDS(DianXMLExtensionCUDFE): | ||||||
|  |     def __init__(self, invoice, software_pin, tipo_ambiente = AMBIENTE_PRUEBAS): | ||||||
|  |         self.tipo_ambiente = tipo_ambiente | ||||||
|  |         self.software_pin = software_pin | ||||||
|  |         self.invoice = invoice | ||||||
|  |  | ||||||
|  |     def schemeName(self): | ||||||
|  |         return 'CUDS-SHA384' | ||||||
|  |  | ||||||
|  |     def buildVars(self): | ||||||
|  |         build_vars = super().buildVars() | ||||||
|  |         build_vars['Software-PIN'] = str(self.software_pin) | ||||||
|  |         return build_vars | ||||||
|  |  | ||||||
|  |     def formatVars(self): | ||||||
|  |         build_vars = self.buildVars() | ||||||
|  |         CodImpuesto1 = build_vars['CodImpuesto1'] | ||||||
|  |         CodImpuesto2 = build_vars['CodImpuesto2'] | ||||||
|  |         CodImpuesto3 = build_vars['CodImpuesto3'] | ||||||
|  |         return [ | ||||||
|  |             '%s' % build_vars['NumFac'], | ||||||
|  |             '%s' % build_vars['FecFac'], | ||||||
|  |             '%s' % build_vars['HoraFac'], | ||||||
|  |             form.Amount(build_vars['ValorBruto']).truncate_as_string(2), | ||||||
|  |             CodImpuesto1, | ||||||
|  |             form.Amount(build_vars['ValorImpuestoPara'].get(CodImpuesto1, 0.0)).truncate_as_string(2), | ||||||
|  |             form.Amount(build_vars['ValorTotalPagar']).truncate_as_string(2), | ||||||
|  |             '%s' % build_vars['NitOFE'], | ||||||
|  |             '%s' % build_vars['NumAdq'],             | ||||||
|  |             '%s' % build_vars['Software-PIN'], | ||||||
|  |             '%d' % build_vars['TipoAmb'], | ||||||
|  |         ] | ||||||
|  |  | ||||||
|  |  | ||||||
| class DianXMLExtensionSoftwareProvider(FachoXMLExtension): | class DianXMLExtensionSoftwareProvider(FachoXMLExtension): | ||||||
|     # RESOLUCION 0004: pagina 108 |     # RESOLUCION 0004: pagina 108 | ||||||
|  |  | ||||||
| @@ -251,7 +329,8 @@ class DianXMLExtensionSoftwareProvider(FachoXMLExtension): | |||||||
|         self.id_software = id_software |         self.id_software = id_software | ||||||
|  |  | ||||||
|     def build(self, fexml): |     def build(self, fexml): | ||||||
|         software_provider = fexml.fragment('./ext:UBLExtensions/ext:UBLExtension/ext:ExtensionContent/sts:DianExtensions/sts:SoftwareProvider') |         software_provider = fexml.fragment( | ||||||
|  |             './ext:UBLExtensions/ext:UBLExtension/ext:ExtensionContent/sts:DianExtensions/sts:SoftwareProvider') | ||||||
|         provider_id_attrs = SCHEME_AGENCY_ATTRS.copy() |         provider_id_attrs = SCHEME_AGENCY_ATTRS.copy() | ||||||
|         provider_id_attrs.update({'schemeID': self.dv}) |         provider_id_attrs.update({'schemeID': self.dv}) | ||||||
|         #DIAN 1.7.-2020: FAB23 |         #DIAN 1.7.-2020: FAB23 | ||||||
| @@ -281,33 +360,36 @@ class DianXMLExtensionSoftwareSecurityCode(FachoXMLExtension): | |||||||
|  |  | ||||||
|  |  | ||||||
| class DianXMLExtensionSigner: | class DianXMLExtensionSigner: | ||||||
|  |     def __init__(self, pkcs12_path, passphrase=None, localpolicy=True): | ||||||
|     def __init__(self, pkcs12_path, passphrase=None, mockpolicy=False): |  | ||||||
|         self._pkcs12_data = open(pkcs12_path, 'rb').read() |         self._pkcs12_data = open(pkcs12_path, 'rb').read() | ||||||
|         self._passphrase = None |         self._passphrase = None | ||||||
|         self._mockpolicy = mockpolicy |         self._localpolicy = localpolicy | ||||||
|         if passphrase: |         if passphrase: | ||||||
|             self._passphrase = passphrase.encode('utf-8') |             self._passphrase = passphrase.encode('utf-8') | ||||||
|  |  | ||||||
|     @classmethod |     @classmethod | ||||||
|     def from_bytes(cls, data, passphrase=None, mockpolicy=False): |     def from_bytes(cls, data, passphrase=None, localpolicy=True): | ||||||
|         self = cls.__new__(cls) |         self = cls.__new__(cls) | ||||||
|          |  | ||||||
|         self._pkcs12_data = data |         self._pkcs12_data = data | ||||||
|         self._passphrase = None |         self._passphrase = None | ||||||
|         self._mockpolicy = mockpolicy |         self._localpolicy = localpolicy | ||||||
|         if passphrase: |         if passphrase: | ||||||
|             self._passphrase = passphrase.encode('utf-8') |             self._passphrase = passphrase.encode('utf-8') | ||||||
|  |  | ||||||
|         return self |         return self | ||||||
|  |  | ||||||
|  |     def _element_extension_content(self, fachoxml): | ||||||
|  |         return fachoxml.builder.xpath( | ||||||
|  |             fachoxml.root, | ||||||
|  |             './ext:UBLExtensions/ext:UBLExtension[2]/ext:ExtensionContent') | ||||||
|  |  | ||||||
|     def sign_xml_string(self, document): |     def sign_xml_string(self, document): | ||||||
|         xml = LXMLBuilder.from_string(document) |         xml = LXMLBuilder.from_string(document) | ||||||
|         signature = self.sign_xml_element(xml) |         signature = self.sign_xml_element(xml) | ||||||
|  |  | ||||||
|         fachoxml = FachoXML(xml,nsmap=NAMESPACES) |         fachoxml = FachoXML(xml,nsmap=NAMESPACES) | ||||||
|         #DIAN 1.7.-2020: FAB01 |         #DIAN 1.7.-2020: FAB01 | ||||||
|         extcontent = fachoxml.builder.xpath(fachoxml.root, './ext:UBLExtensions/ext:UBLExtension[2]/ext:ExtensionContent') |         extcontent = self._element_extension_content(fachoxml) | ||||||
|         fachoxml.append_element(extcontent, signature) |         fachoxml.append_element(extcontent, signature) | ||||||
|  |  | ||||||
|         return fachoxml.tostring(xml_declaration=True, encoding='UTF-8') |         return fachoxml.tostring(xml_declaration=True, encoding='UTF-8') | ||||||
| @@ -321,7 +403,6 @@ class DianXMLExtensionSigner: | |||||||
|         ) |         ) | ||||||
|         xml.append(signature) |         xml.append(signature) | ||||||
|  |  | ||||||
|  |  | ||||||
|         ref = xmlsig.template.add_reference( |         ref = xmlsig.template.add_reference( | ||||||
|             signature, xmlsig.constants.TransformSha256, uri="", name="xmldsig-%s-ref0" % (id_uuid) |             signature, xmlsig.constants.TransformSha256, uri="", name="xmldsig-%s-ref0" % (id_uuid) | ||||||
|         ) |         ) | ||||||
| @@ -329,14 +410,16 @@ class DianXMLExtensionSigner: | |||||||
|  |  | ||||||
|         id_keyinfo = "xmldsig-%s-KeyInfo" % (id_uuid) |         id_keyinfo = "xmldsig-%s-KeyInfo" % (id_uuid) | ||||||
|         xmlsig.template.add_reference( |         xmlsig.template.add_reference( | ||||||
|             signature, xmlsig.constants.TransformSha256, uri="#%s" % (id_keyinfo), name="xmldsig-%s-ref1" % (id_uuid), |             signature, xmlsig.constants.TransformSha256, uri="#%s" % ( | ||||||
|  |                 id_keyinfo), name="xmldsig-%s-ref1" % (id_uuid), | ||||||
|         ) |         ) | ||||||
|         ki = xmlsig.template.ensure_key_info(signature, name=id_keyinfo) |         ki = xmlsig.template.ensure_key_info(signature, name=id_keyinfo) | ||||||
|         data = xmlsig.template.add_x509_data(ki) |         data = xmlsig.template.add_x509_data(ki) | ||||||
|         xmlsig.template.x509_data_add_certificate(data) |         xmlsig.template.x509_data_add_certificate(data) | ||||||
|         xmlsig.template.add_key_value(ki) |         xmlsig.template.add_key_value(ki) | ||||||
|  |  | ||||||
|         qualifying = xades.template.create_qualifying_properties(signature, 'XadesObjects', 'xades') |         qualifying = xades.template.create_qualifying_properties( | ||||||
|  |             signature, 'XadesObjects', 'xades') | ||||||
|         xades.utils.ensure_id(qualifying) |         xades.utils.ensure_id(qualifying) | ||||||
|  |  | ||||||
|         id_props = "xmldsig-%s-signedprops" % (id_uuid) |         id_props = "xmldsig-%s-signedprops" % (id_uuid) | ||||||
| @@ -344,10 +427,12 @@ class DianXMLExtensionSigner: | |||||||
|             signature, xmlsig.constants.TransformSha256, uri="#%s" % (id_props), |             signature, xmlsig.constants.TransformSha256, uri="#%s" % (id_props), | ||||||
|             uri_type="http://uri.etsi.org/01903#SignedProperties" |             uri_type="http://uri.etsi.org/01903#SignedProperties" | ||||||
|         ) |         ) | ||||||
|         xmlsig.template.add_transform(props_ref, xmlsig.constants.TransformInclC14N) |         xmlsig.template.add_transform( | ||||||
|  |             props_ref, xmlsig.constants.TransformInclC14N) | ||||||
|  |  | ||||||
|         # TODO assert with http://www.sic.gov.co/hora-legal-colombiana |         # TODO assert with http://www.sic.gov.co/hora-legal-colombiana | ||||||
|         props = xades.template.create_signed_properties(qualifying, name=id_props, datetime=datetime.now()) |         props = xades.template.create_signed_properties( | ||||||
|  |             qualifying, name=id_props, datetime=datetime.now(tz=Bogota)) | ||||||
|         xades.template.add_claimed_role(props, "supplier") |         xades.template.add_claimed_role(props, "supplier") | ||||||
|  |  | ||||||
|         policy = xades.policy.GenericPolicyId( |         policy = xades.policy.GenericPolicyId( | ||||||
| @@ -355,10 +440,14 @@ class DianXMLExtensionSigner: | |||||||
|             POLICY_NAME, |             POLICY_NAME, | ||||||
|             xmlsig.constants.TransformSha256) |             xmlsig.constants.TransformSha256) | ||||||
|         ctx = xades.XAdESContext(policy) |         ctx = xades.XAdESContext(policy) | ||||||
|         ctx.load_pkcs12(OpenSSL.crypto.load_pkcs12(self._pkcs12_data, |         ctx.load_pkcs12(pkcs12.load_key_and_certificates( | ||||||
|  |             self._pkcs12_data, | ||||||
|             self._passphrase)) |             self._passphrase)) | ||||||
|  |  | ||||||
|         if self._mockpolicy: |         # ctx.load_pkcs12(OpenSSL.crypto.load_pkcs12( | ||||||
|  |         #     self._pkcs12_data, | ||||||
|  |         #     self._passphrase)) | ||||||
|  |         if self._localpolicy: | ||||||
|             with mock_xades_policy(): |             with mock_xades_policy(): | ||||||
|                 ctx.sign(signature) |                 ctx.sign(signature) | ||||||
|                 ctx.verify(signature) |                 ctx.verify(signature) | ||||||
| @@ -371,7 +460,7 @@ class DianXMLExtensionSigner: | |||||||
|  |  | ||||||
|     def build(self, fachoxml): |     def build(self, fachoxml): | ||||||
|         signature = self.sign_xml_element(fachoxml.root) |         signature = self.sign_xml_element(fachoxml.root) | ||||||
|         extcontent = fachoxml.builder.xpath(fachoxml.root, './ext:UBLExtensions/ext:UBLExtension[2]/ext:ExtensionContent') |         extcontent = self._element_extension_content(fachoxml) | ||||||
|         fachoxml.append_element(extcontent, signature) |         fachoxml.append_element(extcontent, signature) | ||||||
|  |  | ||||||
|  |  | ||||||
| @@ -381,19 +470,18 @@ class DianXMLExtensionAuthorizationProvider(FachoXMLExtension): | |||||||
|     def build(self, fexml): |     def build(self, fexml): | ||||||
|         attrs = {'schemeID': '4', 'schemeName': '31'} |         attrs = {'schemeID': '4', 'schemeName': '31'} | ||||||
|         attrs.update(SCHEME_AGENCY_ATTRS) |         attrs.update(SCHEME_AGENCY_ATTRS) | ||||||
|          |  | ||||||
|         authorization_provider = fexml.fragment('./ext:UBLExtensions/ext:UBLExtension/ext:ExtensionContent/sts:DianExtensions/sts:AuthorizationProvider') |         authorization_provider = fexml.fragment('./ext:UBLExtensions/ext:UBLExtension/ext:ExtensionContent/sts:DianExtensions/sts:AuthorizationProvider') | ||||||
|         authorization_provider.set_element('./sts:AuthorizationProviderID', |         authorization_provider.set_element('./sts:AuthorizationProviderID', | ||||||
|                                            '800197268', |                                            '800197268', | ||||||
|                                            **attrs) |                                            **attrs) | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| class DianXMLExtensionInvoiceSource(FachoXMLExtension): | class DianXMLExtensionInvoiceSource(FachoXMLExtension): | ||||||
|     # CAB13 |     # CAB13 | ||||||
|     def build(self, fexml): |     def build(self, fexml): | ||||||
|         dian_path = '/fe:CreditNote/ext:UBLExtensions/ext:UBLExtension/ext:ExtensionContent/sts:DianExtensions/sts:InvoiceSource/cbc:IdentificationCode' |         dian_path = '/fe:CreditNote/ext:UBLExtensions/ext:UBLExtension/ext:ExtensionContent/sts:DianExtensions/sts:InvoiceSource/cbc:IdentificationCode' | ||||||
|         fexml.set_element(dian_path, 'CO', |         fexml.set_element( | ||||||
|  |             dian_path, 'CO', | ||||||
|             listAgencyID="6", |             listAgencyID="6", | ||||||
|             listAgencyName="United Nations Economic Commission for Europe", |             listAgencyName="United Nations Economic Commission for Europe", | ||||||
|             listSchemeURI="urn:oasis:names:specification:ubl:codelist:gc:CountryIdentificationCode-2.1") |             listSchemeURI="urn:oasis:names:specification:ubl:codelist:gc:CountryIdentificationCode-2.1") | ||||||
| @@ -426,16 +514,15 @@ class DianXMLExtensionInvoiceAuthorization(FachoXMLExtension): | |||||||
|         invoice_control.set_element('/sts:InvoiceControl/sts:AuthorizedInvoices/sts:To', |         invoice_control.set_element('/sts:InvoiceControl/sts:AuthorizedInvoices/sts:To', | ||||||
|                                     self.to) |                                     self.to) | ||||||
|  |  | ||||||
|         fexml.set_element('./ext:UBLExtensions/ext:UBLExtension/ext:ExtensionContent/sts:DianExtensions/sts:InvoiceSource/cbc:IdentificationCode', |         fexml.set_element( | ||||||
|  |             './ext:UBLExtensions/ext:UBLExtension/ext:ExtensionContent/sts:DianExtensions/sts:InvoiceSource/cbc:IdentificationCode', | ||||||
|             'CO', |             'CO', | ||||||
|             # DIAN 1.7.-2020: FAB15 |             # DIAN 1.7.-2020: FAB15 | ||||||
|             listAgencyID="6", |             listAgencyID="6", | ||||||
|             # DIAN 1.7.-2020: FAB16 |             # DIAN 1.7.-2020: FAB16 | ||||||
|             listAgencyName="United Nations Economic Commission for Europe", |             listAgencyName="United Nations Economic Commission for Europe", | ||||||
|             # DIAN 1.7.-2020: FAB17 |             # DIAN 1.7.-2020: FAB17 | ||||||
|                           listSchemeURI="urn:oasis:names:specification:ubl:codelist:gc:CountryIdentificationCode-2.1" |             listSchemeURI="urn:oasis:names:specification:ubl:codelist:gc:CountryIdentificationCode-2.1") | ||||||
|                           ) |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| class DianZIP: | class DianZIP: | ||||||
| @@ -444,10 +531,11 @@ class DianZIP: | |||||||
|     MAX_FILES = 50 |     MAX_FILES = 50 | ||||||
|  |  | ||||||
|     def __init__(self, file_like): |     def __init__(self, file_like): | ||||||
|         self.zipfile = zipfile.ZipFile(file_like, mode='w', compression=zipfile.ZIP_DEFLATED) |         self.zipfile = zipfile.ZipFile( | ||||||
|  |             file_like, mode='w', compression=zipfile.ZIP_DEFLATED) | ||||||
|         self.num_files = 0 |         self.num_files = 0 | ||||||
|  |  | ||||||
|     def add_invoice_xml(self, name, xml_data): |     def add_xml(self, name, xml_data): | ||||||
|         self.num_files += 1 |         self.num_files += 1 | ||||||
|         # TODO cual es la norma para los nombres de archivos? |         # TODO cual es la norma para los nombres de archivos? | ||||||
|         m = hashlib.sha256() |         m = hashlib.sha256() | ||||||
| @@ -458,7 +546,17 @@ class DianZIP: | |||||||
|  |  | ||||||
|         return filename |         return filename | ||||||
|  |  | ||||||
|  |     # DEPRECATED usar add_xml | ||||||
|  |     def add_invoice_xml(self, name, xml_data): | ||||||
|  |         return self.add_xml(name, xml_data) | ||||||
|  |  | ||||||
|     def __enter__(self): |     def __enter__(self): | ||||||
|  |         """ | ||||||
|  |         Facilita el uso de esta manera: | ||||||
|  |         f = open('xxx', 'rb') | ||||||
|  |         with DianZIP(f) as zip: | ||||||
|  |           zip.add_invoice_xml('name', 'data xml') | ||||||
|  |         """ | ||||||
|         return self |         return self | ||||||
|  |  | ||||||
|     def __exit__(self, type, value, traceback): |     def __exit__(self, type, value, traceback): | ||||||
| @@ -467,34 +565,35 @@ class DianZIP: | |||||||
|  |  | ||||||
| class DianXMLExtensionSignerVerifier: | class DianXMLExtensionSignerVerifier: | ||||||
|  |  | ||||||
|     def __init__(self, pkcs12_path_or_bytes, passphrase=None, mockpolicy=False): |     def __init__(self, pkcs12_path_or_bytes, passphrase=None, localpolicy=True): | ||||||
|         self._pkcs12_path_or_bytes = pkcs12_path_or_bytes |         self._pkcs12_path_or_bytes = pkcs12_path_or_bytes | ||||||
|         self._passphrase = None |         self._passphrase = None | ||||||
|         self._mockpolicy = mockpolicy |         self._localpolicy = localpolicy | ||||||
|         if passphrase: |         if passphrase: | ||||||
|             self._passphrase = passphrase.encode('utf-8') |             self._passphrase = passphrase.encode('utf-8') | ||||||
|  |  | ||||||
|     def verify_string(self, document): |     def verify_string(self, document): | ||||||
|  |         # Obtener FachoXML | ||||||
|         xml = LXMLBuilder.from_string(document) |         xml = LXMLBuilder.from_string(document) | ||||||
|         fachoxml = FachoXML(xml, nsmap=NAMESPACES) |         fachoxml = FachoXML(xml, nsmap=NAMESPACES) | ||||||
|  |  | ||||||
|  |         # Obtener Signature | ||||||
|         signature = fachoxml.builder.xpath(fachoxml.root, '//ds:Signature') |         signature = fachoxml.builder.xpath(fachoxml.root, '//ds:Signature') | ||||||
|         assert signature is not None |         assert signature is not None | ||||||
|  |  | ||||||
|  |         # Se mueve Signature a elemento raiz para realizar verificaion | ||||||
|         signature.getparent().remove(signature) |         signature.getparent().remove(signature) | ||||||
|         fachoxml.root.append(signature) |         fachoxml.root.append(signature) | ||||||
|  |  | ||||||
|         ctx = xades.XAdESContext() |         # Verificar archivo usando Signature | ||||||
|  |  | ||||||
|         pkcs12_data = self._pkcs12_path_or_bytes |         pkcs12_data = self._pkcs12_path_or_bytes | ||||||
|         if isinstance(self._pkcs12_path_or_bytes, str): |         if isinstance(self._pkcs12_path_or_bytes, str): | ||||||
|             pkcs12_data = open(self._pkcs12_path_or_bytes, 'rb').read() |             pkcs12_data = open(self._pkcs12_path_or_bytes, 'rb').read() | ||||||
|  |         ctx = xades.XAdESContext() | ||||||
|         ctx.load_pkcs12(OpenSSL.crypto.load_pkcs12(pkcs12_data, |         ctx.load_pkcs12(OpenSSL.crypto.load_pkcs12(pkcs12_data, | ||||||
|                                                    self._passphrase)) |                                                    self._passphrase)) | ||||||
|  |  | ||||||
|         try: |         try: | ||||||
|             if self._mockpolicy: |             if self._localpolicy: | ||||||
|                 with mock_xades_policy(): |                 with mock_xades_policy(): | ||||||
|                     ctx.verify(signature) |                     ctx.verify(signature) | ||||||
|             else: |             else: | ||||||
|   | |||||||
| @@ -1,24 +1,26 @@ | |||||||
| # This file is part of facho.  The COPYRIGHT file at the top level of | # This file is part of facho.  The COPYRIGHT file at the top level of | ||||||
| # this repository contains the full copyright notices and license terms. | # this repository contains the full copyright notices and license terms. | ||||||
|  |  | ||||||
| import hashlib | # import hashlib | ||||||
| from functools import reduce | # from functools import reduce | ||||||
| import copy | # import copy | ||||||
|  |  | ||||||
| import dataclasses | import dataclasses | ||||||
| from dataclasses import dataclass | from dataclasses import dataclass, field | ||||||
| from datetime import datetime, date | from datetime import datetime, date | ||||||
| from collections import defaultdict | # from collections import defaultdict | ||||||
| import decimal | import decimal | ||||||
| from decimal import Decimal | from decimal import Decimal | ||||||
| import typing | import typing | ||||||
|  |  | ||||||
| from ..data.dian import codelist | from ..data.dian import codelist | ||||||
|  |  | ||||||
| DECIMAL_PRECISION = 6 | DECIMAL_PRECISION = 6 | ||||||
|  |  | ||||||
|  |  | ||||||
| class AmountCurrencyError(TypeError): | class AmountCurrencyError(TypeError): | ||||||
|     pass |     pass | ||||||
|  |  | ||||||
|  |  | ||||||
| @dataclass | @dataclass | ||||||
| class Currency: | class Currency: | ||||||
|     code: str |     code: str | ||||||
| @@ -29,6 +31,7 @@ class Currency: | |||||||
|     def __str__(self): |     def __str__(self): | ||||||
|         return self.code |         return self.code | ||||||
|  |  | ||||||
|  |  | ||||||
| class Collection: | class Collection: | ||||||
|  |  | ||||||
|     def __init__(self, array): |     def __init__(self, array): | ||||||
| @@ -45,6 +48,7 @@ class Collection: | |||||||
|     def sum(self): |     def sum(self): | ||||||
|         return sum(self.array) |         return sum(self.array) | ||||||
|  |  | ||||||
|  |  | ||||||
| class AmountCollection(Collection): | class AmountCollection(Collection): | ||||||
|  |  | ||||||
|     def sum(self): |     def sum(self): | ||||||
| @@ -53,9 +57,12 @@ class AmountCollection(Collection): | |||||||
|             total += v |             total += v | ||||||
|         return total |         return total | ||||||
|  |  | ||||||
|  |  | ||||||
| class Amount: | class Amount: | ||||||
|     def __init__(self, amount: int or float or str or Amount, currency: Currency = Currency('COP'), precision = DECIMAL_PRECISION): |     def __init__( | ||||||
|         self.precision = precision |             self, amount: typing.Union[int, float, str, "Amount"], | ||||||
|  |             currency: Currency = Currency('COP')): | ||||||
|  |  | ||||||
|         # DIAN 1.7.-2020: 1.2.3.1 |         # DIAN 1.7.-2020: 1.2.3.1 | ||||||
|         if isinstance(amount, Amount): |         if isinstance(amount, Amount): | ||||||
|             if amount < Amount(0.0): |             if amount < Amount(0.0): | ||||||
| @@ -67,7 +74,9 @@ class Amount: | |||||||
|             if float(amount) < 0: |             if float(amount) < 0: | ||||||
|                 raise ValueError('amount must be positive >= 0') |                 raise ValueError('amount must be positive >= 0') | ||||||
|  |  | ||||||
|             self.amount = Decimal(amount, decimal.Context(prec=self.precision, |             self.amount = Decimal( | ||||||
|  |                 amount, decimal.Context( | ||||||
|  |                     prec=DECIMAL_PRECISION, | ||||||
|                     # DIAN 1.7.-2020: 1.2.1.1 |                     # DIAN 1.7.-2020: 1.2.1.1 | ||||||
|                     rounding=decimal.ROUND_HALF_EVEN)) |                     rounding=decimal.ROUND_HALF_EVEN)) | ||||||
|             self.currency = currency |             self.currency = currency | ||||||
| @@ -87,22 +96,20 @@ class Amount: | |||||||
|     def __lt__(self, other): |     def __lt__(self, other): | ||||||
|         if not self.is_same_currency(other): |         if not self.is_same_currency(other): | ||||||
|             raise AmountCurrencyError() |             raise AmountCurrencyError() | ||||||
|         return round(self.amount, self.precision) < round(other, 2) |         return round(self.amount, DECIMAL_PRECISION) < round(other, 2) | ||||||
|  |  | ||||||
|     def __eq__(self, other): |     def __eq__(self, other): | ||||||
|         if not self.is_same_currency(other): |         if not self.is_same_currency(other): | ||||||
|             raise AmountCurrencyError() |             raise AmountCurrencyError() | ||||||
|         return round(self.amount, self.precision) == round(other.amount, self.precision) |         return round(self.amount, DECIMAL_PRECISION) == round( | ||||||
|  |             other.amount, DECIMAL_PRECISION) | ||||||
|  |  | ||||||
|     def _cast(self, val): |     def _cast(self, val): | ||||||
|         if type(val) in [int, float]: |         if type(val) in [int, float]: | ||||||
|             return self.fromNumber(val) |             return self.fromNumber(val) | ||||||
|         if isinstance(val, Amount): |         if isinstance(val, Amount): | ||||||
|             return val |             return val | ||||||
|         if isinstance(val, Decimal): |         raise TypeError("cant cast to amount") | ||||||
|             return self.fromNumber(float(val)) |  | ||||||
|  |  | ||||||
|         raise TypeError("cant cast %s to amount" % (type(val))) |  | ||||||
|  |  | ||||||
|     def __add__(self, rother): |     def __add__(self, rother): | ||||||
|         other = self._cast(rother) |         other = self._cast(rother) | ||||||
| @@ -156,6 +163,7 @@ class Quantity: | |||||||
|     def __repr__(self): |     def __repr__(self): | ||||||
|         return str(self) |         return str(self) | ||||||
|  |  | ||||||
|  |  | ||||||
| @dataclass | @dataclass | ||||||
| class Item: | class Item: | ||||||
|     scheme_name: str |     scheme_name: str | ||||||
| @@ -166,10 +174,10 @@ class Item: | |||||||
|  |  | ||||||
|  |  | ||||||
| class StandardItem(Item): | class StandardItem(Item): | ||||||
|     def __init__(self, id_: str, description: str = ''): |     def __init__(self, id_: str, description: str = '', name: str = ''): | ||||||
|         super().__init__(id=id_, |         super().__init__(id=id_, | ||||||
|                          description=description, |                          description=description, | ||||||
|                          scheme_name='', |                          scheme_name=name, | ||||||
|                          scheme_id='999', |                          scheme_id='999', | ||||||
|                          scheme_agency_id='') |                          scheme_agency_id='') | ||||||
|  |  | ||||||
| @@ -193,6 +201,7 @@ class Country: | |||||||
|             raise ValueError("code [%s] not found" % (self.code)) |             raise ValueError("code [%s] not found" % (self.code)) | ||||||
|         self.name = codelist.Paises[self.code]['name'] |         self.name = codelist.Paises[self.code]['name'] | ||||||
|  |  | ||||||
|  |  | ||||||
| @dataclass | @dataclass | ||||||
| class CountrySubentity: | class CountrySubentity: | ||||||
|     code: str |     code: str | ||||||
| @@ -203,6 +212,7 @@ class CountrySubentity: | |||||||
|             raise ValueError("code [%s] not found" % (self.code)) |             raise ValueError("code [%s] not found" % (self.code)) | ||||||
|         self.name = codelist.Departamento[self.code]['name'] |         self.name = codelist.Departamento[self.code]['name'] | ||||||
|  |  | ||||||
|  |  | ||||||
| @dataclass | @dataclass | ||||||
| class City: | class City: | ||||||
|     code: str |     code: str | ||||||
| @@ -213,13 +223,22 @@ class City: | |||||||
|             raise ValueError("code [%s] not found" % (self.code)) |             raise ValueError("code [%s] not found" % (self.code)) | ||||||
|         self.name = codelist.Municipio[self.code]['name'] |         self.name = codelist.Municipio[self.code]['name'] | ||||||
|  |  | ||||||
|  |  | ||||||
|  | @dataclass | ||||||
|  | class PostalZone: | ||||||
|  |     code: str = '' | ||||||
|  |  | ||||||
|  |  | ||||||
| @dataclass | @dataclass | ||||||
| class Address: | class Address: | ||||||
|     name: str |     name: str | ||||||
|     street: str = '' |     street: str = '' | ||||||
|     city: City = City('05001') |     city: City = field(default_factory=lambda: City('05001')) | ||||||
|     country: Country = Country('CO') |     country: Country = field(default_factory=lambda: Country('CO')) | ||||||
|     countrysubentity: CountrySubentity = CountrySubentity('05') |     countrysubentity: CountrySubentity = field( | ||||||
|  |         default_factory=lambda: CountrySubentity('05')) | ||||||
|  |     postalzone: PostalZone = field(default_factory=lambda: PostalZone('')) | ||||||
|  |  | ||||||
|  |  | ||||||
| @dataclass | @dataclass | ||||||
| class PartyIdentification: | class PartyIdentification: | ||||||
| @@ -240,6 +259,7 @@ class PartyIdentification: | |||||||
|         if self.type_fiscal not in codelist.TipoIdFiscal: |         if self.type_fiscal not in codelist.TipoIdFiscal: | ||||||
|             raise ValueError("type_fiscal [%s] not found" % (self.type_fiscal)) |             raise ValueError("type_fiscal [%s] not found" % (self.type_fiscal)) | ||||||
|  |  | ||||||
|  |  | ||||||
| @dataclass | @dataclass | ||||||
| class Responsability: | class Responsability: | ||||||
|     codes: list |     codes: list | ||||||
| @@ -264,12 +284,12 @@ class TaxScheme: | |||||||
|     code: str |     code: str | ||||||
|     name: str = '' |     name: str = '' | ||||||
|  |  | ||||||
|  |  | ||||||
|     def __post_init__(self): |     def __post_init__(self): | ||||||
|         if self.code not in codelist.TipoImpuesto: |         if self.code not in codelist.TipoImpuesto: | ||||||
|             raise ValueError("code not found") |             raise ValueError("code not found") | ||||||
|         self.name = codelist.TipoImpuesto[self.code]['name'] |         self.name = codelist.TipoImpuesto[self.code]['name'] | ||||||
|  |  | ||||||
|  |  | ||||||
| @dataclass | @dataclass | ||||||
| class Party: | class Party: | ||||||
|     name: str |     name: str | ||||||
| @@ -277,10 +297,10 @@ class Party: | |||||||
|     responsability_code: typing.List[Responsability] |     responsability_code: typing.List[Responsability] | ||||||
|     responsability_regime_code: str |     responsability_regime_code: str | ||||||
|     organization_code: str |     organization_code: str | ||||||
|     tax_scheme: TaxScheme = TaxScheme('01') |     tax_scheme: TaxScheme = field(default_factory=lambda: TaxScheme('01')) | ||||||
|  |  | ||||||
|     phone: str = '' |     phone: str = '' | ||||||
|     address: Address = Address('') |     address: Address = field(default_factory=lambda: Address('')) | ||||||
|     email: str = '' |     email: str = '' | ||||||
|     legal_name: str = '' |     legal_name: str = '' | ||||||
|     legal_company_ident: str = '' |     legal_company_ident: str = '' | ||||||
| @@ -308,7 +328,7 @@ class TaxScheme: | |||||||
| class TaxSubTotal: | class TaxSubTotal: | ||||||
|     percent: float |     percent: float | ||||||
|     scheme: typing.Optional[TaxScheme] = None |     scheme: typing.Optional[TaxScheme] = None | ||||||
|     tax_amount: Amount = Amount(0.0) |     tax_amount: Amount = field(default_factory=lambda: Amount(0.0)) | ||||||
|  |  | ||||||
|     def calculate(self, invline): |     def calculate(self, invline): | ||||||
|         if self.percent is not None: |         if self.percent is not None: | ||||||
| @@ -318,12 +338,11 @@ class TaxSubTotal: | |||||||
| @dataclass | @dataclass | ||||||
| class TaxTotal: | class TaxTotal: | ||||||
|     subtotals: list |     subtotals: list | ||||||
|     tax_amount: Amount = Amount(0.0) |     tax_amount: Amount = field(default_factory=lambda: Amount(0.0)) | ||||||
|     taxable_amount: Amount = Amount(0.0) |     taxable_amount: Amount = field(default_factory=lambda: Amount(0.0)) | ||||||
|  |  | ||||||
|     def calculate(self, invline): |     def calculate(self, invline): | ||||||
|         self.taxable_amount = invline.total_amount |         self.taxable_amount = invline.total_amount | ||||||
|  |  | ||||||
|         for subtax in self.subtotals: |         for subtax in self.subtotals: | ||||||
|             subtax.calculate(invline) |             subtax.calculate(invline) | ||||||
|             self.tax_amount += subtax.tax_amount |             self.tax_amount += subtax.tax_amount | ||||||
| @@ -336,6 +355,40 @@ class TaxTotalOmit(TaxTotal): | |||||||
|     def calculate(self, invline): |     def calculate(self, invline): | ||||||
|         pass |         pass | ||||||
|  |  | ||||||
|  |  | ||||||
|  | @dataclass | ||||||
|  | class WithholdingTaxSubTotal: | ||||||
|  |     percent: float | ||||||
|  |     scheme: typing.Optional[TaxScheme] = None | ||||||
|  |     tax_amount: Amount = field(default_factory=lambda: Amount(0.0)) | ||||||
|  |  | ||||||
|  |     def calculate(self, invline): | ||||||
|  |         if self.percent is not None: | ||||||
|  |             self.tax_amount = invline.total_amount * Amount(self.percent / 100) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | @dataclass | ||||||
|  | class WithholdingTaxTotal: | ||||||
|  |     subtotals: list | ||||||
|  |     tax_amount: Amount = field(default_factory=lambda: Amount(0.0)) | ||||||
|  |     taxable_amount: Amount = field(default_factory=lambda: Amount(0.0)) | ||||||
|  |  | ||||||
|  |     def calculate(self, invline): | ||||||
|  |         self.taxable_amount = invline.total_amount | ||||||
|  |  | ||||||
|  |         for subtax in self.subtotals: | ||||||
|  |             subtax.calculate(invline) | ||||||
|  |             self.tax_amount += subtax.tax_amount | ||||||
|  |  | ||||||
|  |  | ||||||
|  | class WithholdingTaxTotalOmit(WithholdingTaxTotal): | ||||||
|  |     def __init__(self): | ||||||
|  |         super().__init__([]) | ||||||
|  |  | ||||||
|  |     def calculate(self, invline): | ||||||
|  |         pass | ||||||
|  |  | ||||||
|  |  | ||||||
| @dataclass | @dataclass | ||||||
| class Price: | class Price: | ||||||
|     amount: Amount |     amount: Amount | ||||||
| @@ -351,6 +404,7 @@ class Price: | |||||||
|  |  | ||||||
|         self.amount *= self.quantity |         self.amount *= self.quantity | ||||||
|  |  | ||||||
|  |  | ||||||
| @dataclass | @dataclass | ||||||
| class PaymentMean: | class PaymentMean: | ||||||
|     DEBIT = '01' |     DEBIT = '01' | ||||||
| @@ -369,7 +423,23 @@ class PaymentMean: | |||||||
| @dataclass | @dataclass | ||||||
| class PrePaidPayment: | class PrePaidPayment: | ||||||
|     # DIAN 1.7.-2020: FBD03 |     # DIAN 1.7.-2020: FBD03 | ||||||
|     paid_amount: Amount = Amount(0.0) |     paid_amount: Amount = field(default_factory=lambda: Amount(0.0)) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | @dataclass | ||||||
|  | class BillingResponse: | ||||||
|  |     id: str | ||||||
|  |     code: str | ||||||
|  |     description: str | ||||||
|  |  | ||||||
|  |  | ||||||
|  | class SupportDocumentCreditNoteResponse(BillingResponse): | ||||||
|  |     """ | ||||||
|  |     ReferenceID: Identifica la sección del Documento | ||||||
|  |     Soporte original a la cual se aplica la corrección. | ||||||
|  |     ResponseCode: Código de descripción de la corrección. | ||||||
|  |     Description: Descripción de la naturaleza de la corrección. | ||||||
|  |     """ | ||||||
|  |  | ||||||
|  |  | ||||||
| @dataclass | @dataclass | ||||||
| @@ -378,6 +448,7 @@ class BillingReference: | |||||||
|     uuid: str |     uuid: str | ||||||
|     date: date |     date: date | ||||||
|  |  | ||||||
|  |  | ||||||
| class CreditNoteDocumentReference(BillingReference): | class CreditNoteDocumentReference(BillingReference): | ||||||
|     """ |     """ | ||||||
|     ident: Prefijo + Numero de la factura relacionada |     ident: Prefijo + Numero de la factura relacionada | ||||||
| @@ -393,6 +464,7 @@ class DebitNoteDocumentReference(BillingReference): | |||||||
|     date: fecha de emision de la factura relacionada |     date: fecha de emision de la factura relacionada | ||||||
|     """ |     """ | ||||||
|  |  | ||||||
|  |  | ||||||
| class InvoiceDocumentReference(BillingReference): | class InvoiceDocumentReference(BillingReference): | ||||||
|     """ |     """ | ||||||
|     ident: Prefijo + Numero de la nota credito relacionada |     ident: Prefijo + Numero de la nota credito relacionada | ||||||
| @@ -400,6 +472,7 @@ class InvoiceDocumentReference(BillingReference): | |||||||
|     date: fecha de emision de la nota credito relacionada |     date: fecha de emision de la nota credito relacionada | ||||||
|     """ |     """ | ||||||
|  |  | ||||||
|  |  | ||||||
| @dataclass | @dataclass | ||||||
| class AllowanceChargeReason: | class AllowanceChargeReason: | ||||||
|     code: str |     code: str | ||||||
| @@ -414,20 +487,24 @@ class AllowanceChargeReason: | |||||||
| class AllowanceCharge: | class AllowanceCharge: | ||||||
|     # DIAN 1.7.-2020: FAQ03 |     # DIAN 1.7.-2020: FAQ03 | ||||||
|     charge_indicator: bool = True |     charge_indicator: bool = True | ||||||
|     amount: Amount = Amount(0.0) |     amount: Amount = field(default_factory=lambda: Amount(0.0)) | ||||||
|     reason: AllowanceChargeReason = None |     reason: AllowanceChargeReason = None | ||||||
|  |  | ||||||
|     # Valor Base para calcular el descuento o el cargo |     # Valor Base para calcular el descuento o el cargo | ||||||
|     base_amount: typing.Optional[Amount] = Amount(0.0) |     base_amount: typing.Optional[Amount] = field( | ||||||
|  |         default_factory=lambda: Amount(0.0)) | ||||||
|  |  | ||||||
|     # Porcentaje: Porcentaje que aplicar. |     # Porcentaje: Porcentaje que aplicar. | ||||||
|     multiplier_factor_numeric: Amount = Amount(1.0) |     multiplier_factor_numeric: Amount = field( | ||||||
|  |         default_factory=lambda: Amount(1.0)) | ||||||
|  |  | ||||||
|     def isCharge(self): |     def isCharge(self): | ||||||
|         return self.charge_indicator == True |         charge_indicator = self.charge_indicator is True | ||||||
|  |         return charge_indicator | ||||||
|  |  | ||||||
|     def isDiscount(self): |     def isDiscount(self): | ||||||
|         return self.charge_indicator == False |         charge_indicator = self.charge_indicator is False | ||||||
|  |         return charge_indicator | ||||||
|  |  | ||||||
|     def asCharge(self): |     def asCharge(self): | ||||||
|         self.charge_indicator = True |         self.charge_indicator = True | ||||||
| @@ -441,11 +518,13 @@ class AllowanceCharge: | |||||||
|     def set_base_amount(self, amount): |     def set_base_amount(self, amount): | ||||||
|         self.base_amount = amount |         self.base_amount = amount | ||||||
|  |  | ||||||
|  |  | ||||||
| class AllowanceChargeAsDiscount(AllowanceCharge): | class AllowanceChargeAsDiscount(AllowanceCharge): | ||||||
|     def __init__(self, amount: Amount = Amount(0.0)): |     def __init__(self, amount: Amount = Amount(0.0)): | ||||||
|         self.charge_indicator = False |         self.charge_indicator = False | ||||||
|         self.amount = amount |         self.amount = amount | ||||||
|  |  | ||||||
|  |  | ||||||
| @dataclass | @dataclass | ||||||
| class InvoiceLine: | class InvoiceLine: | ||||||
|     # RESOLUCION 0004: pagina 155 |     # RESOLUCION 0004: pagina 155 | ||||||
| @@ -458,8 +537,9 @@ class InvoiceLine: | |||||||
|     # la factura y el percent es unico por type_code |     # la factura y el percent es unico por type_code | ||||||
|     # de subtotal |     # de subtotal | ||||||
|     tax: typing.Optional[TaxTotal] |     tax: typing.Optional[TaxTotal] | ||||||
|  |     withholding: typing.Optional[WithholdingTaxTotal] | ||||||
|     allowance_charge: typing.List[AllowanceCharge] = dataclasses.field(default_factory=list) |     allowance_charge: typing.List[AllowanceCharge] = dataclasses.field( | ||||||
|  |         default_factory=list) | ||||||
|  |  | ||||||
|     def add_allowance_charge(self, charge): |     def add_allowance_charge(self, charge): | ||||||
|         if not isinstance(charge, AllowanceCharge): |         if not isinstance(charge, AllowanceCharge): | ||||||
| @@ -502,8 +582,17 @@ class InvoiceLine: | |||||||
|     def taxable_amount(self): |     def taxable_amount(self): | ||||||
|         return self.tax.taxable_amount |         return self.tax.taxable_amount | ||||||
|  |  | ||||||
|  |     @property | ||||||
|  |     def withholding_amount(self): | ||||||
|  |         return self.withholding.tax_amount | ||||||
|  |  | ||||||
|  |     @property | ||||||
|  |     def withholding_taxable_amount(self): | ||||||
|  |         return self.withholding.taxable_amount | ||||||
|  |  | ||||||
|     def calculate(self): |     def calculate(self): | ||||||
|         self.tax.calculate(self) |         self.tax.calculate(self) | ||||||
|  |         self.withholding.calculate(self) | ||||||
|  |  | ||||||
|     def __post_init__(self): |     def __post_init__(self): | ||||||
|         if not isinstance(self.quantity, Quantity): |         if not isinstance(self.quantity, Quantity): | ||||||
| @@ -512,15 +601,19 @@ class InvoiceLine: | |||||||
|         if self.tax is None: |         if self.tax is None: | ||||||
|             self.tax = TaxTotalOmit() |             self.tax = TaxTotalOmit() | ||||||
|  |  | ||||||
|  |         if self.withholding is None: | ||||||
|  |             self.withholding = WithholdingTaxTotalOmit() | ||||||
|  |  | ||||||
|  |  | ||||||
| @dataclass | @dataclass | ||||||
| class LegalMonetaryTotal: | class LegalMonetaryTotal: | ||||||
|     line_extension_amount: Amount = Amount(0.0) |     line_extension_amount: Amount = field(default_factory=lambda: Amount(0.0)) | ||||||
|     tax_exclusive_amount: Amount = Amount(0.0) |     tax_exclusive_amount: Amount = field(default_factory=lambda: Amount(0.0)) | ||||||
|     tax_inclusive_amount: Amount = Amount(0.0) |     tax_inclusive_amount: Amount = field(default_factory=lambda: Amount(0.0)) | ||||||
|     charge_total_amount: Amount = Amount(0.0) |     charge_total_amount: Amount = field(default_factory=lambda: Amount(0.0)) | ||||||
|     allowance_total_amount: Amount = Amount(0.0) |     allowance_total_amount: Amount = field(default_factory=lambda: Amount(0.0)) | ||||||
|     payable_amount: Amount = Amount(0.0) |     payable_amount: Amount = field(default_factory=lambda: Amount(0.0)) | ||||||
|     prepaid_amount: Amount = Amount(0.0) |     prepaid_amount: Amount = field(default_factory=lambda: Amount(0.0)) | ||||||
|  |  | ||||||
|     def calculate(self): |     def calculate(self): | ||||||
|         # DIAN 1.7.-2020: FAU14 |         # DIAN 1.7.-2020: FAU14 | ||||||
| @@ -531,22 +624,29 @@ class LegalMonetaryTotal: | |||||||
|             - self.prepaid_amount |             - self.prepaid_amount | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| class NationalSalesInvoiceDocumentType(str): | class NationalSalesInvoiceDocumentType(str): | ||||||
|     def __str__(self): |     def __str__(self): | ||||||
|         # 6.1.3 |         # 6.1.3 | ||||||
|         return '01' |         return '01' | ||||||
|  |  | ||||||
|  |  | ||||||
| class CreditNoteDocumentType(str): | class CreditNoteDocumentType(str): | ||||||
|     def __str__(self): |     def __str__(self): | ||||||
|         # 6.1.3 |         # 6.1.3 | ||||||
|         return '91' |         return '91' | ||||||
|  |  | ||||||
|  |  | ||||||
| class DebitNoteDocumentType(str): | class DebitNoteDocumentType(str): | ||||||
|     def __str__(self): |     def __str__(self): | ||||||
|         # 6.1.3 |         # 6.1.3 | ||||||
|         return '92' |         return '92' | ||||||
|  |  | ||||||
|  |  | ||||||
|  | class CreditNoteSupportDocumentType(str): | ||||||
|  |     def __str__(self): | ||||||
|  |         return '95' | ||||||
|  |  | ||||||
|  |  | ||||||
| class Invoice: | class Invoice: | ||||||
|     def __init__(self, type_code: str): |     def __init__(self, type_code: str): | ||||||
|         if str(type_code) not in codelist.TipoDocumento: |         if str(type_code) not in codelist.TipoDocumento: | ||||||
| @@ -566,6 +666,7 @@ class Invoice: | |||||||
|         self.invoice_allowance_charge = [] |         self.invoice_allowance_charge = [] | ||||||
|         self.invoice_prepaid_payment = [] |         self.invoice_prepaid_payment = [] | ||||||
|         self.invoice_billing_reference = None |         self.invoice_billing_reference = None | ||||||
|  |         self.invoice_discrepancy_response = None | ||||||
|         self.invoice_type_code = str(type_code) |         self.invoice_type_code = str(type_code) | ||||||
|         self.invoice_ident_prefix = None |         self.invoice_ident_prefix = None | ||||||
|  |  | ||||||
| @@ -591,7 +692,8 @@ class Invoice: | |||||||
|             if len(prefix) <= 4: |             if len(prefix) <= 4: | ||||||
|                 self.invoice_ident_prefix = prefix |                 self.invoice_ident_prefix = prefix | ||||||
|             else: |             else: | ||||||
|                 raise ValueError('ident prefix failed to get, expected 0  to 4 chars') |                 raise ValueError( | ||||||
|  |                     'ident prefix failed to get, expected 0  to 4 chars') | ||||||
|  |  | ||||||
|     def set_ident(self, ident: str): |     def set_ident(self, ident: str): | ||||||
|         """ |         """ | ||||||
| @@ -641,6 +743,9 @@ class Invoice: | |||||||
|     def set_billing_reference(self, billing_reference: BillingReference): |     def set_billing_reference(self, billing_reference: BillingReference): | ||||||
|         self.invoice_billing_reference = billing_reference |         self.invoice_billing_reference = billing_reference | ||||||
|  |  | ||||||
|  |     def set_discrepancy_response(self, billing_response: BillingResponse): | ||||||
|  |         self.invoice_discrepancy_response = billing_response | ||||||
|  |  | ||||||
|     def accept(self, visitor): |     def accept(self, visitor): | ||||||
|         visitor.visit_payment_mean(self.invoice_payment_mean) |         visitor.visit_payment_mean(self.invoice_payment_mean) | ||||||
|         visitor.visit_customer(self.invoice_customer) |         visitor.visit_customer(self.invoice_customer) | ||||||
| @@ -652,27 +757,32 @@ class Invoice: | |||||||
|  |  | ||||||
|     def _calculate_legal_monetary_total(self): |     def _calculate_legal_monetary_total(self): | ||||||
|         for invline in self.invoice_lines: |         for invline in self.invoice_lines: | ||||||
|             self.invoice_legal_monetary_total.line_extension_amount += invline.total_amount |             self.invoice_legal_monetary_total.line_extension_amount +=\ | ||||||
|             self.invoice_legal_monetary_total.tax_exclusive_amount += invline.total_tax_exclusive_amount |                 invline.total_amount | ||||||
|  |             self.invoice_legal_monetary_total.tax_exclusive_amount +=\ | ||||||
|  |                 invline.total_tax_exclusive_amount | ||||||
|             # DIAN 1.7.-2020: FAU6 |             # DIAN 1.7.-2020: FAU6 | ||||||
|             self.invoice_legal_monetary_total.tax_inclusive_amount += invline.total_tax_inclusive_amount |             self.invoice_legal_monetary_total.tax_inclusive_amount +=\ | ||||||
|  |                 invline.total_tax_inclusive_amount | ||||||
|  |  | ||||||
|         # DIAN 1.7.-2020: FAU08 |         # DIAN 1.7.-2020: FAU08 | ||||||
|         self.invoice_legal_monetary_total.allowance_total_amount = AmountCollection(self.invoice_allowance_charge)\ |         self.invoice_legal_monetary_total.allowance_total_amount =\ | ||||||
|  |             AmountCollection(self.invoice_allowance_charge)\ | ||||||
|             .filter(lambda charge: charge.isDiscount())\ |             .filter(lambda charge: charge.isDiscount())\ | ||||||
|             .map(lambda charge: charge.amount)\ |             .map(lambda charge: charge.amount)\ | ||||||
|             .sum() |             .sum() | ||||||
|  |  | ||||||
|         # DIAN 1.7.-2020: FAU10 |         # DIAN 1.7.-2020: FAU10 | ||||||
|         self.invoice_legal_monetary_total.charge_total_amount = AmountCollection(self.invoice_allowance_charge)\ |         self.invoice_legal_monetary_total.charge_total_amount =\ | ||||||
|  |             AmountCollection(self.invoice_allowance_charge)\ | ||||||
|             .filter(lambda charge: charge.isCharge())\ |             .filter(lambda charge: charge.isCharge())\ | ||||||
|             .map(lambda charge: charge.amount)\ |             .map(lambda charge: charge.amount)\ | ||||||
|             .sum() |             .sum() | ||||||
|  |  | ||||||
|         # DIAN 1.7.-2020: FAU12 |         # DIAN 1.7.-2020: FAU12 | ||||||
|         self.invoice_legal_monetary_total.prepaid_amount = AmountCollection(self.invoice_prepaid_payment)\ |         self.invoice_legal_monetary_total.prepaid_amount = AmountCollection( | ||||||
|             .map(lambda paid: paid.paid_amount)\ |             self.invoice_prepaid_payment).map( | ||||||
|             .sum() |                 lambda paid: paid.paid_amount).sum() | ||||||
|  |  | ||||||
|         # DIAN 1.7.-2020: FAU14 |         # DIAN 1.7.-2020: FAU14 | ||||||
|         self.invoice_legal_monetary_total.calculate() |         self.invoice_legal_monetary_total.calculate() | ||||||
| @@ -682,11 +792,13 @@ class Invoice: | |||||||
|             for invline in self.invoice_lines: |             for invline in self.invoice_lines: | ||||||
|                 if invline.allowance_charge: |                 if invline.allowance_charge: | ||||||
|                     # TODO actualmente solo uno de los cargos es permitido |                     # TODO actualmente solo uno de los cargos es permitido | ||||||
|                     raise ValueError('allowance charge in invoice exclude invoice line') |                     raise ValueError( | ||||||
|  |                         'allowance charge in invoice exclude invoice line') | ||||||
|  |  | ||||||
|         # cargos a nivel de factura |         # cargos a nivel de factura | ||||||
|         for charge in self.invoice_allowance_charge: |         for charge in self.invoice_allowance_charge: | ||||||
|             charge.set_base_amount(self.invoice_legal_monetary_total.line_extension_amount) |             charge.set_base_amount( | ||||||
|  |                 self.invoice_legal_monetary_total.line_extension_amount) | ||||||
|  |  | ||||||
|     def calculate(self): |     def calculate(self): | ||||||
|         for invline in self.invoice_lines: |         for invline in self.invoice_lines: | ||||||
| @@ -694,6 +806,7 @@ class Invoice: | |||||||
|         self._calculate_legal_monetary_total() |         self._calculate_legal_monetary_total() | ||||||
|         self._refresh_charges_base_amount() |         self._refresh_charges_base_amount() | ||||||
|  |  | ||||||
|  |  | ||||||
| class NationalSalesInvoice(Invoice): | class NationalSalesInvoice(Invoice): | ||||||
|     def __init__(self): |     def __init__(self): | ||||||
|         super().__init__(NationalSalesInvoiceDocumentType()) |         super().__init__(NationalSalesInvoiceDocumentType()) | ||||||
| @@ -738,3 +851,30 @@ class DebitNote(Invoice): | |||||||
|         if not self.invoice_ident_prefix: |         if not self.invoice_ident_prefix: | ||||||
|             self.invoice_ident_prefix = self.invoice_ident[0:6] |             self.invoice_ident_prefix = self.invoice_ident[0:6] | ||||||
|  |  | ||||||
|  |  | ||||||
|  | class SupportDocument(Invoice): | ||||||
|  |     pass | ||||||
|  |  | ||||||
|  |  | ||||||
|  | class SupportDocumentCreditNote(SupportDocument): | ||||||
|  |     def __init__( | ||||||
|  |             self, invoice_document_reference: BillingReference, | ||||||
|  |             invoice_discrepancy_response: BillingResponse): | ||||||
|  |         super().__init__(CreditNoteSupportDocumentType()) | ||||||
|  |  | ||||||
|  |         if not isinstance(invoice_document_reference, BillingReference): | ||||||
|  |             raise TypeError('invoice_document_reference invalid type') | ||||||
|  |         self.invoice_billing_reference = invoice_document_reference | ||||||
|  |         self.invoice_discrepancy_response = invoice_discrepancy_response | ||||||
|  |  | ||||||
|  |     def _get_codelist_tipo_operacion(self): | ||||||
|  |         return codelist.TipoOperacionNCDS | ||||||
|  |  | ||||||
|  |     def _check_ident_prefix(self, prefix): | ||||||
|  |         if len(prefix) != 6: | ||||||
|  |             raise ValueError('prefix must be 6 length') | ||||||
|  |  | ||||||
|  |     def _set_ident_prefix_automatic(self): | ||||||
|  |         if not self.invoice_ident_prefix: | ||||||
|  |             self.invoice_ident_prefix = self.invoice_ident[0:6] | ||||||
|  |     pass | ||||||
|   | |||||||
| @@ -2,3 +2,6 @@ from .invoice import * | |||||||
| from .credit_note import * | from .credit_note import * | ||||||
| from .debit_note import * | from .debit_note import * | ||||||
| from .utils import * | from .utils import * | ||||||
|  | from .attached_document import * | ||||||
|  | from .support_document import * | ||||||
|  | from .support_document_credit_note import * | ||||||
|   | |||||||
							
								
								
									
										15
									
								
								facho/fe/form_xml/attached_document.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								facho/fe/form_xml/attached_document.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,15 @@ | |||||||
|  | from .. import fe | ||||||
|  |  | ||||||
|  | __all__ = ['AttachedDocument'] | ||||||
|  |  | ||||||
|  |  | ||||||
|  | class AttachedDocument(): | ||||||
|  |  | ||||||
|  |     def __init__(self, id): | ||||||
|  |         schema =\ | ||||||
|  |             'urn:oasis:names:specification:ubl:schema:xsd:AttachedDocument-2' | ||||||
|  |         self.fexml = fe.FeXML('AttachedDocument', schema) | ||||||
|  |         self.fexml.set_element('./cbc:ID', id) | ||||||
|  |  | ||||||
|  |     def toFachoXML(self): | ||||||
|  |         return self.fexml | ||||||
| @@ -1,9 +1,10 @@ | |||||||
| from .. import fe | # from .. import fe | ||||||
| from ..form import * | # from ..form import * | ||||||
| from .invoice import DIANInvoiceXML | from .invoice import DIANInvoiceXML | ||||||
|  |  | ||||||
| __all__ = ['DIANCreditNoteXML'] | __all__ = ['DIANCreditNoteXML'] | ||||||
|  |  | ||||||
|  |  | ||||||
| class DIANCreditNoteXML(DIANInvoiceXML): | class DIANCreditNoteXML(DIANInvoiceXML): | ||||||
|     """ |     """ | ||||||
|     DianInvoiceXML mapea objeto form.Invoice a XML segun |     DianInvoiceXML mapea objeto form.Invoice a XML segun | ||||||
|   | |||||||
| @@ -1,9 +1,10 @@ | |||||||
| from .. import fe | # from .. import fe | ||||||
| from ..form import * | # from ..form import * | ||||||
| from .invoice import DIANInvoiceXML | from .invoice import DIANInvoiceXML | ||||||
|  |  | ||||||
| __all__ = ['DIANDebitNoteXML'] | __all__ = ['DIANDebitNoteXML'] | ||||||
|  |  | ||||||
|  |  | ||||||
| class DIANDebitNoteXML(DIANInvoiceXML): | class DIANDebitNoteXML(DIANInvoiceXML): | ||||||
|     """ |     """ | ||||||
|     DianInvoiceXML mapea objeto form.Invoice a XML segun |     DianInvoiceXML mapea objeto form.Invoice a XML segun | ||||||
| @@ -21,17 +22,22 @@ class DIANDebitNoteXML(DIANInvoiceXML): | |||||||
|  |  | ||||||
|     # DIAN 1.7.-2020: DAU03 |     # DIAN 1.7.-2020: DAU03 | ||||||
|     def set_legal_monetary(fexml, invoice): |     def set_legal_monetary(fexml, invoice): | ||||||
|         fexml.set_element_amount('./cac:RequestedMonetaryTotal/cbc:LineExtensionAmount', |         fexml.set_element_amount( | ||||||
|  |             './cac:RequestedMonetaryTotal/cbc:LineExtensionAmount', | ||||||
|             invoice.invoice_legal_monetary_total.line_extension_amount) |             invoice.invoice_legal_monetary_total.line_extension_amount) | ||||||
|  |  | ||||||
|         fexml.set_element_amount('./cac:RequestedMonetaryTotal/cbc:TaxExclusiveAmount', |         fexml.set_element_amount( | ||||||
|  |             './cac:RequestedMonetaryTotal/cbc:TaxExclusiveAmount', | ||||||
|             invoice.invoice_legal_monetary_total.tax_exclusive_amount) |             invoice.invoice_legal_monetary_total.tax_exclusive_amount) | ||||||
|  |  | ||||||
|         fexml.set_element_amount('./cac:RequestedMonetaryTotal/cbc:TaxInclusiveAmount', |         fexml.set_element_amount( | ||||||
|  |             './cac:RequestedMonetaryTotal/cbc:TaxInclusiveAmount', | ||||||
|             invoice.invoice_legal_monetary_total.tax_inclusive_amount) |             invoice.invoice_legal_monetary_total.tax_inclusive_amount) | ||||||
|  |  | ||||||
|         fexml.set_element_amount('./cac:RequestedMonetaryTotal/cbc:ChargeTotalAmount', |         fexml.set_element_amount( | ||||||
|  |             './cac:RequestedMonetaryTotal/cbc:ChargeTotalAmount', | ||||||
|             invoice.invoice_legal_monetary_total.charge_total_amount) |             invoice.invoice_legal_monetary_total.charge_total_amount) | ||||||
|  |  | ||||||
|         fexml.set_element_amount('./cac:RequestedMonetaryTotal/cbc:PayableAmount', |         fexml.set_element_amount( | ||||||
|  |             './cac:RequestedMonetaryTotal/cbc:PayableAmount', | ||||||
|             invoice.invoice_legal_monetary_total.payable_amount) |             invoice.invoice_legal_monetary_total.payable_amount) | ||||||
|   | |||||||
| @@ -1,5 +1,6 @@ | |||||||
| from .. import fe | from .. import fe | ||||||
| from ..form import * | from ..form import * | ||||||
|  | from collections import defaultdict | ||||||
|  |  | ||||||
| __all__ = ['DIANInvoiceXML'] | __all__ = ['DIANInvoiceXML'] | ||||||
|  |  | ||||||
| @@ -147,7 +148,6 @@ class DIANInvoiceXML(fe.FeXML): | |||||||
|         fexml.set_element('./cac:AccountingSupplierParty/cac:Party/cac:PartyTaxScheme/cac:TaxScheme/cbc:ID', |         fexml.set_element('./cac:AccountingSupplierParty/cac:Party/cac:PartyTaxScheme/cac:TaxScheme/cbc:ID', | ||||||
|                           invoice.invoice_customer.tax_scheme.code) |                           invoice.invoice_customer.tax_scheme.code) | ||||||
|  |  | ||||||
|  |  | ||||||
|         #DIAN 1.7.-2020: CAJ41 |         #DIAN 1.7.-2020: CAJ41 | ||||||
|         fexml.set_element('./cac:AccountingSupplierParty/cac:Party/cac:PartyTaxScheme/cac:TaxScheme/cbc:Name', |         fexml.set_element('./cac:AccountingSupplierParty/cac:Party/cac:PartyTaxScheme/cac:TaxScheme/cbc:Name', | ||||||
|                           invoice.invoice_customer.tax_scheme.name) |                           invoice.invoice_customer.tax_scheme.name) | ||||||
| @@ -421,42 +421,55 @@ class DIANInvoiceXML(fe.FeXML): | |||||||
|  |  | ||||||
|     def set_invoice_totals(fexml, invoice): |     def set_invoice_totals(fexml, invoice): | ||||||
|         tax_amount_for = defaultdict(lambda: defaultdict(lambda: Amount(0.0))) |         tax_amount_for = defaultdict(lambda: defaultdict(lambda: Amount(0.0))) | ||||||
|  |         withholding_amount_for = defaultdict(lambda: defaultdict(lambda: Amount(0.0))) | ||||||
|         percent_for = defaultdict(lambda: None) |         percent_for = defaultdict(lambda: None) | ||||||
|  |  | ||||||
|         #requeridos para CUFE |         #requeridos para CUFE | ||||||
|         #tax_amount_for['01']['tax_amount'] = Amount(0.0) |         #tax_amount_for['01']['tax_amount'] = Amount(0.0) | ||||||
|         #tax_amount_for['01']['taxable_amount'] = Amount(0.0) |         #tax_amount_for['01']['taxable_amount'] = Amount(0.0) | ||||||
|         #DIAN 1.7.-2020: FAS07 => Se debe construir estrategia para  su manejo |         #DIAN 1.7.-2020: FAS07 => Se debe construir estrategia para  su manejo | ||||||
|         #tax_amount_for['04']['tax_amount'] = 0.0 |         #tax_amount_for['04']['tax_amount'] += 0.0 | ||||||
|         #tax_amount_for['04']['taxable_amount'] = 0.0 |         #tax_amount_for['04']['taxable_amount'] += 0.0 | ||||||
|         #tax_amount_for['03']['tax_amount'] = 0.0 |         #tax_amount_for['03']['tax_amount'] += 0.0 | ||||||
|         #tax_amount_for['03']['taxable_amount'] = 0.0 |         #tax_amount_for['03']['taxable_amount'] += 0.0 | ||||||
|  |  | ||||||
|         total_tax_amount = Amount(0.0) |         total_tax_amount = Amount(0.0) | ||||||
|  |         total_withholding_amount = Amount(0.0) | ||||||
|  |  | ||||||
|         for invoice_line in invoice.invoice_lines: |         for invoice_line in invoice.invoice_lines: | ||||||
|             for subtotal in invoice_line.tax.subtotals: |             for subtotal in invoice_line.tax.subtotals: | ||||||
|                 if subtotal.scheme is not None: |                 if subtotal.scheme is not None: | ||||||
|                     tax_amount_for[subtotal.scheme.code]['tax_amount'] += subtotal.tax_amount |                     tax_amount_for[subtotal.scheme.code]['tax_amount'] += subtotal.tax_amount | ||||||
|                     tax_amount_for[subtotal.scheme.code]['taxable_amount'] += invoice_line.taxable_amount |                     tax_amount_for[subtotal.scheme.code]['taxable_amount'] += invoice_line.taxable_amount | ||||||
|  |                     tax_amount_for[subtotal.scheme.code]['name'] = subtotal.scheme.name | ||||||
|  |  | ||||||
|                     # MACHETE ojo InvoiceLine.tax pasar a Invoice |                     # MACHETE ojo InvoiceLine.tax pasar a Invoice | ||||||
|                     percent_for[subtotal.scheme.code] = subtotal.percent |                     percent_for[subtotal.scheme.code] = subtotal.percent | ||||||
|  |  | ||||||
|                 total_tax_amount += subtotal.tax_amount |                 total_tax_amount += subtotal.tax_amount | ||||||
|  |  | ||||||
|  |             for subtotal_withholding in invoice_line.withholding.subtotals: | ||||||
|  |                 if subtotal_withholding.scheme is not None: | ||||||
|  |                     withholding_amount_for[subtotal_withholding.scheme.code]['tax_amount'] += subtotal_withholding.tax_amount | ||||||
|  |                     withholding_amount_for[subtotal_withholding.scheme.code]['taxable_amount'] += invoice_line.withholding_taxable_amount | ||||||
|  |  | ||||||
|  |                     # MACHETE ojo InvoiceLine.tax pasar a Invoice | ||||||
|  |                      | ||||||
|  |                     percent_for[subtotal_withholding.scheme.code] = subtotal_withholding.percent | ||||||
|  |  | ||||||
|  |                 total_withholding_amount += subtotal_withholding.tax_amount | ||||||
|  |  | ||||||
|  |         if total_tax_amount != Amount(0.0): | ||||||
|             fexml.placeholder_for('./cac:TaxTotal') |             fexml.placeholder_for('./cac:TaxTotal') | ||||||
|             fexml.set_element_amount('./cac:TaxTotal/cbc:TaxAmount', |             fexml.set_element_amount('./cac:TaxTotal/cbc:TaxAmount', | ||||||
|                     total_tax_amount) |                     total_tax_amount) | ||||||
|          |          | ||||||
|  |  | ||||||
|         for index, item in enumerate(tax_amount_for.items()): |         for index, item in enumerate(tax_amount_for.items()): | ||||||
|             cod_impuesto, amount_of = item |             cod_impuesto, amount_of = item | ||||||
|             next_append = index > 0 |             next_append = index > 0 | ||||||
|  |  | ||||||
|             #DIAN 1.7.-2020: FAS01 |             #DIAN 1.7.-2020: FAS01 | ||||||
|             line = fexml.fragment('./cac:TaxTotal', append=next_append) |             line = fexml.fragment('./cac:TaxTotal', append=next_append) | ||||||
|  |  | ||||||
|             #DIAN 1.7.-2020: FAU06 |             #DIAN 1.7.-2020: FAU06 | ||||||
|             tax_amount = amount_of['tax_amount'] |             tax_amount = amount_of['tax_amount'] | ||||||
|             fexml.set_element_amount_for(line, |             fexml.set_element_amount_for(line, | ||||||
| @@ -482,8 +495,48 @@ class DIANInvoiceXML(fe.FeXML): | |||||||
|             if percent_for[cod_impuesto]: |             if percent_for[cod_impuesto]: | ||||||
|                 line.set_element('/cac:TaxTotal/cac:TaxSubtotal/cac:TaxCategory/cbc:Percent', |                 line.set_element('/cac:TaxTotal/cac:TaxSubtotal/cac:TaxCategory/cbc:Percent', | ||||||
|                                  percent_for[cod_impuesto]) |                                  percent_for[cod_impuesto]) | ||||||
|  |                  | ||||||
|             line.set_element('/cac:TaxTotal/cac:TaxSubtotal/cac:TaxCategory/cac:TaxScheme/cbc:ID', |             line.set_element('/cac:TaxTotal/cac:TaxSubtotal/cac:TaxCategory/cac:TaxScheme/cbc:ID', | ||||||
|                     cod_impuesto) |                     cod_impuesto) | ||||||
|  |             line.set_element('/cac:TaxTotal/cac:TaxSubtotal/cac:TaxCategory/cac:TaxScheme/cbc:Name', | ||||||
|  |                              amount_of['name']) | ||||||
|  |              | ||||||
|  |         for index, item in enumerate(withholding_amount_for.items()): | ||||||
|  |             cod_impuesto, amount_of = item | ||||||
|  |             next_append = index > 0 | ||||||
|  |  | ||||||
|  |             #DIAN 1.7.-2020: FAS01 | ||||||
|  |             line = fexml.fragment('./cac:WithholdingTaxTotal', append=next_append) | ||||||
|  |             #DIAN 1.7.-2020: FAU06 | ||||||
|  |             tax_amount = amount_of['tax_amount'] | ||||||
|  |             fexml.set_element_amount_for(line, | ||||||
|  |                                          '/cac:WithholdingTaxTotal/cbc:TaxAmount', | ||||||
|  |                                          tax_amount) | ||||||
|  |  | ||||||
|  |             #DIAN 1.7.-2020: FAS05 | ||||||
|  |             fexml.set_element_amount_for(line, | ||||||
|  |                                          '/cac:WithholdingTaxTotal/cac:TaxSubtotal/cbc:TaxableAmount', | ||||||
|  |                                          amount_of['taxable_amount']) | ||||||
|  |  | ||||||
|  |             #DIAN 1.7.-2020: FAU06 | ||||||
|  |             fexml.set_element_amount_for(line, | ||||||
|  |                                          '/cac:WithholdingTaxTotal/cac:TaxSubtotal/cbc:TaxAmount', | ||||||
|  |                                          amount_of['tax_amount']) | ||||||
|  |  | ||||||
|  |             #DIAN 1.7.-2020: FAS07 | ||||||
|  |             if percent_for[cod_impuesto]: | ||||||
|  |                 line.set_element('/cac:WithholdingTaxTotal/cac:TaxSubtotal/cbc:Percent', | ||||||
|  |                                  percent_for[cod_impuesto]) | ||||||
|  |  | ||||||
|  |  | ||||||
|  |             if percent_for[cod_impuesto]: | ||||||
|  |                 line.set_element('/cac:WithholdingTaxTotal/cac:TaxSubtotal/cac:TaxCategory/cbc:Percent', | ||||||
|  |                                  percent_for[cod_impuesto]) | ||||||
|  |                  | ||||||
|  |             line.set_element('/cac:WithholdingTaxTotal/cac:TaxSubtotal/cac:TaxCategory/cac:TaxScheme/cbc:ID', | ||||||
|  |                     cod_impuesto) | ||||||
|  |             line.set_element('/cac:WithholdingTaxTotal/cac:TaxSubtotal/cac:TaxCategory/cac:TaxScheme/cbc:Name', | ||||||
|  |                     'ReteRenta') | ||||||
|  |  | ||||||
|     # abstract method |     # abstract method | ||||||
|     def tag_document(fexml): |     def tag_document(fexml): | ||||||
| @@ -502,7 +555,6 @@ class DIANInvoiceXML(fe.FeXML): | |||||||
|         fexml.set_element_amount_for(line, |         fexml.set_element_amount_for(line, | ||||||
|                                      './cac:TaxTotal/cac:TaxSubtotal/cbc:TaxableAmount', |                                      './cac:TaxTotal/cac:TaxSubtotal/cbc:TaxableAmount', | ||||||
|                                      invoice_line.taxable_amount) |                                      invoice_line.taxable_amount) | ||||||
|  |  | ||||||
|         for subtotal in invoice_line.tax.subtotals: |         for subtotal in invoice_line.tax.subtotals: | ||||||
|             line.set_element('./cac:TaxTotal/cac:TaxSubtotal/cbc:TaxAmount', subtotal.tax_amount, currencyID='COP') |             line.set_element('./cac:TaxTotal/cac:TaxSubtotal/cbc:TaxAmount', subtotal.tax_amount, currencyID='COP') | ||||||
|  |  | ||||||
| @@ -514,6 +566,28 @@ class DIANInvoiceXML(fe.FeXML): | |||||||
|                 line.set_element('./cac:TaxTotal/cac:TaxSubtotal/cac:TaxCategory/cac:TaxScheme/cbc:ID', subtotal.scheme.code) |                 line.set_element('./cac:TaxTotal/cac:TaxSubtotal/cac:TaxCategory/cac:TaxScheme/cbc:ID', subtotal.scheme.code) | ||||||
|                 line.set_element('./cac:TaxTotal/cac:TaxSubtotal/cac:TaxCategory/cac:TaxScheme/cbc:Name', subtotal.scheme.name) |                 line.set_element('./cac:TaxTotal/cac:TaxSubtotal/cac:TaxCategory/cac:TaxScheme/cbc:Name', subtotal.scheme.name) | ||||||
|  |  | ||||||
|  |  | ||||||
|  |     def set_invoice_line_withholding(fexml, line, invoice_line): | ||||||
|  |         fexml.set_element_amount_for(line, | ||||||
|  |                                      './cac:WithholdingTaxTotal/cbc:TaxAmount', | ||||||
|  |                                      invoice_line.withholding_amount) | ||||||
|  |         #DIAN 1.7.-2020: FAX05 | ||||||
|  |         fexml.set_element_amount_for(line, | ||||||
|  |                                      './cac:WithholdingTaxTotal/cac:TaxSubtotal/cbc:TaxableAmount', | ||||||
|  |                                      invoice_line.withholding_taxable_amount) | ||||||
|  |  | ||||||
|  |         for subtotal in invoice_line.withholding.subtotals: | ||||||
|  |             line.set_element('./cac:WithholdingTaxTotal/cac:TaxSubtotal/cbc:TaxAmount', subtotal.tax_amount, currencyID='COP') | ||||||
|  |  | ||||||
|  |             if subtotal.percent is not None: | ||||||
|  |                 line.set_element('./cac:WithholdingTaxTotal/cac:TaxSubtotal/cac:TaxCategory/cbc:Percent', '%0.2f' % round(subtotal.percent, 2)) | ||||||
|  |  | ||||||
|  |             if subtotal.scheme is not None: | ||||||
|  |                 #DIAN 1.7.-2020: FAX15 | ||||||
|  |                 line.set_element('./cac:WithholdingTaxTotal/cac:TaxSubtotal/cac:TaxCategory/cac:TaxScheme/cbc:ID', subtotal.scheme.code) | ||||||
|  |                 line.set_element('./cac:WithholdingTaxTotal/cac:TaxSubtotal/cac:TaxCategory/cac:TaxScheme/cbc:Name', subtotal.scheme.name) | ||||||
|  |  | ||||||
|  |                  | ||||||
|     def set_invoice_lines(fexml, invoice): |     def set_invoice_lines(fexml, invoice): | ||||||
|         next_append = False |         next_append = False | ||||||
|         for index, invoice_line in enumerate(invoice.invoice_lines): |         for index, invoice_line in enumerate(invoice.invoice_lines): | ||||||
| @@ -529,6 +603,9 @@ class DIANInvoiceXML(fe.FeXML): | |||||||
|             if not isinstance(invoice_line.tax, TaxTotalOmit): |             if not isinstance(invoice_line.tax, TaxTotalOmit): | ||||||
|                 fexml.set_invoice_line_tax(line, invoice_line) |                 fexml.set_invoice_line_tax(line, invoice_line) | ||||||
|  |  | ||||||
|  |             if not isinstance(invoice_line.withholding, WithholdingTaxTotalOmit): | ||||||
|  |                 fexml.set_invoice_line_withholding(line, invoice_line) | ||||||
|  |  | ||||||
|             line.set_element('./cac:Item/cbc:Description', invoice_line.item.description) |             line.set_element('./cac:Item/cbc:Description', invoice_line.item.description) | ||||||
|  |  | ||||||
|             line.set_element('./cac:Item/cac:StandardItemIdentification/cbc:ID', |             line.set_element('./cac:Item/cac:StandardItemIdentification/cbc:ID', | ||||||
| @@ -550,20 +627,28 @@ class DIANInvoiceXML(fe.FeXML): | |||||||
|     def set_allowance_charge(fexml, invoice): |     def set_allowance_charge(fexml, invoice): | ||||||
|         for idx, charge in enumerate(invoice.invoice_allowance_charge): |         for idx, charge in enumerate(invoice.invoice_allowance_charge): | ||||||
|             next_append = idx > 0 |             next_append = idx > 0 | ||||||
|             fexml.append_allowance_charge(fexml, idx + 1, charge, append=next_append) |             fexml.append_allowance_charge( | ||||||
|  |                 fexml, idx + 1, charge, append=next_append) | ||||||
|  |  | ||||||
|     def append_allowance_charge(fexml, parent, idx, charge, append=False): |     def append_allowance_charge(fexml, parent, idx, charge, append=False): | ||||||
|         line = parent.fragment('./cac:AllowanceCharge', append=append) |         line = parent.fragment('./cac:AllowanceCharge', append=append) | ||||||
|         # DIAN 1.7.-2020: FAQ02 |         # DIAN 1.7.-2020: FAQ02 | ||||||
|         line.set_element('./cbc:ID', idx) |         line.set_element('./cbc:ID', idx) | ||||||
|         # DIAN 1.7.-2020: FAQ03 |         # DIAN 1.7.-2020: FAQ03 | ||||||
|             line.set_element('./cbc:ChargeIndicator', str(charge.charge_indicator).lower()) |         line.set_element('./cbc:ChargeIndicator', str( | ||||||
|  |             charge.charge_indicator).lower()) | ||||||
|         if charge.reason: |         if charge.reason: | ||||||
|                 line.set_element('./cbc:AllowanceChargeReasonCode', charge.reason.code) |             line.set_element( | ||||||
|                 line.set_element('./cbc:allowanceChargeReason', charge.reason.reason) |                 './cbc:AllowanceChargeReasonCode', charge.reason.code) | ||||||
|             line.set_element('./cbc:MultiplierFactorNumeric', str(round(charge.multiplier_factor_numeric, 2))) |             line.set_element( | ||||||
|             fexml.set_element_amount_for(line, './cbc:Amount', charge.amount) |                 './cbc:allowanceChargeReason', charge.reason.reason) | ||||||
|             fexml.set_element_amount_for(line, './cbc:BaseAmount', charge.base_amount) |         line.set_element( | ||||||
|  |             './cbc:MultiplierFactorNumeric', str( | ||||||
|  |                 round(charge.multiplier_factor_numeric, 2))) | ||||||
|  |         fexml.set_element_amount_for( | ||||||
|  |             line, './cbc:Amount', charge.amount) | ||||||
|  |         fexml.set_element_amount_for( | ||||||
|  |             line, './cbc:BaseAmount', charge.base_amount) | ||||||
|  |  | ||||||
|     def attach_invoice(fexml, invoice): |     def attach_invoice(fexml, invoice): | ||||||
|         """adiciona etiquetas a FEXML y retorna FEXML |         """adiciona etiquetas a FEXML y retorna FEXML | ||||||
| @@ -576,7 +661,6 @@ class DIANInvoiceXML(fe.FeXML): | |||||||
|         fexml.placeholder_for('./cbc:ProfileExecutionID') |         fexml.placeholder_for('./cbc:ProfileExecutionID') | ||||||
|         fexml.set_element('./cbc:ID', invoice.invoice_ident) |         fexml.set_element('./cbc:ID', invoice.invoice_ident) | ||||||
|         fexml.placeholder_for('./cbc:UUID') |         fexml.placeholder_for('./cbc:UUID') | ||||||
|         fexml.set_element('./cbc:DocumentCurrencyCode', 'COP') |  | ||||||
|         fexml.set_element('./cbc:IssueDate', invoice.invoice_issue.strftime('%Y-%m-%d')) |         fexml.set_element('./cbc:IssueDate', invoice.invoice_issue.strftime('%Y-%m-%d')) | ||||||
|         #DIAN 1.7.-2020: FAD10 |         #DIAN 1.7.-2020: FAD10 | ||||||
|         fexml.set_element('./cbc:IssueTime', invoice.invoice_issue.strftime('%H:%M:%S-05:00')) |         fexml.set_element('./cbc:IssueTime', invoice.invoice_issue.strftime('%H:%M:%S-05:00')) | ||||||
| @@ -585,24 +669,25 @@ class DIANInvoiceXML(fe.FeXML): | |||||||
|                         listAgencyID='195', |                         listAgencyID='195', | ||||||
|                         listAgencyName='No matching global declaration available for the validation root', |                         listAgencyName='No matching global declaration available for the validation root', | ||||||
|                         listURI='http://www.dian.gov.co') |                         listURI='http://www.dian.gov.co') | ||||||
|  |         fexml.set_element('./cbc:DocumentCurrencyCode', 'COP') | ||||||
|         fexml.set_element('./cbc:LineCountNumeric', len(invoice.invoice_lines)) |         fexml.set_element('./cbc:LineCountNumeric', len(invoice.invoice_lines)) | ||||||
|         fexml.set_element('./cac:%sPeriod/cbc:StartDate' % (fexml.tag_document()), |         if fexml.tag_document() == 'Invoice': | ||||||
|  |             fexml.set_element('./cac:%sPeriod/cbc:StartDate' % ( | ||||||
|  |                 fexml.tag_document()), | ||||||
|                               invoice.invoice_period_start.strftime('%Y-%m-%d')) |                               invoice.invoice_period_start.strftime('%Y-%m-%d')) | ||||||
|  |  | ||||||
|         fexml.set_element('./cac:%sPeriod/cbc:EndDate' % (fexml.tag_document()), |             fexml.set_element('./cac:%sPeriod/cbc:EndDate' % ( | ||||||
|  |                 fexml.tag_document()), | ||||||
|                               invoice.invoice_period_end.strftime('%Y-%m-%d')) |                               invoice.invoice_period_end.strftime('%Y-%m-%d')) | ||||||
|  |         fexml.set_billing_reference(invoice) | ||||||
|         fexml.customize(invoice) |         fexml.customize(invoice) | ||||||
|  |  | ||||||
|         fexml.set_supplier(invoice) |         fexml.set_supplier(invoice) | ||||||
|         fexml.set_customer(invoice) |         fexml.set_customer(invoice) | ||||||
|         fexml.set_legal_monetary(invoice) |  | ||||||
|         fexml.set_invoice_totals(invoice) |  | ||||||
|         fexml.set_invoice_lines(invoice) |  | ||||||
|         fexml.set_payment_mean(invoice) |         fexml.set_payment_mean(invoice) | ||||||
|  |         fexml.set_invoice_totals(invoice) | ||||||
|  |         fexml.set_legal_monetary(invoice) | ||||||
|  |         fexml.set_invoice_lines(invoice) | ||||||
|         fexml.set_allowance_charge(invoice) |         fexml.set_allowance_charge(invoice) | ||||||
|         fexml.set_billing_reference(invoice) |  | ||||||
|  |  | ||||||
|         return fexml |         return fexml | ||||||
|  |  | ||||||
|     def customize(fexml, invoice): |     def customize(fexml, invoice): | ||||||
|   | |||||||
							
								
								
									
										647
									
								
								facho/fe/form_xml/support_document.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										647
									
								
								facho/fe/form_xml/support_document.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,647 @@ | |||||||
|  | from .. import fe | ||||||
|  | from ..form import ( | ||||||
|  |     Amount, DebitNoteDocumentReference, CreditNoteDocumentReference, | ||||||
|  |     InvoiceDocumentReference, TaxTotalOmit, WithholdingTaxTotalOmit | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | from collections import defaultdict | ||||||
|  | from datetime import datetime | ||||||
|  | # from .attached_document import * | ||||||
|  |  | ||||||
|  | __all__ = ['DIANSupportDocumentXML'] | ||||||
|  |  | ||||||
|  |  | ||||||
|  | class DIANSupportDocumentXML(fe.FeXML): | ||||||
|  |     """ | ||||||
|  |     DianSupportDocumentXML mapea objeto form.Invoice a XML segun | ||||||
|  |     lo indicado para él Documento soporte en adquisiciones efectuadas con sujetos no obligados a expedir factura de venta o documento equivalente. | ||||||
|  |     """ | ||||||
|  |  | ||||||
|  |     def __init__(self, invoice, tag_document='Invoice'): | ||||||
|  |         super().__init__(tag_document, 'http://www.dian.gov.co/contratos/facturaelectronica/v1') | ||||||
|  |  | ||||||
|  |         # DIAN 1.1.-2021: DSAB03 | ||||||
|  |         # DIAN 1.1.-2021: NSAB03 | ||||||
|  |         self.placeholder_for( | ||||||
|  |             './ext:UBLExtensions/ext:UBLExtension/ext:ExtensionContent/sts:DianExtensions/sts:InvoiceControl') | ||||||
|  |  | ||||||
|  |         # DIAN 1.1.-2021: DSAB13 | ||||||
|  |         # DIAN 1.1.-2021: NSAB13 | ||||||
|  |         self.placeholder_for( | ||||||
|  |             './ext:UBLExtensions/ext:UBLExtension/ext:ExtensionContent/sts:DianExtensions/sts:InvoiceSource') | ||||||
|  |  | ||||||
|  |         # DIAN 1.1.-2021: DSAB18 | ||||||
|  |         # DIAN 1.1.-2021: NSAB18 | ||||||
|  |         self.placeholder_for( | ||||||
|  |             './ext:UBLExtensions/ext:UBLExtension/ext:ExtensionContent/sts:DianExtensions/sts:SoftwareProvider') | ||||||
|  |  | ||||||
|  |         # DIAN 1.1.-2021: DSAB27 | ||||||
|  |         # DIAN 1.1.-2021: NSAB27 | ||||||
|  |         self.placeholder_for( | ||||||
|  |             './ext:UBLExtensions/ext:UBLExtension/ext:ExtensionContent/sts:DianExtensions/sts:SoftwareSecurityCode') | ||||||
|  |  | ||||||
|  |         # DIAN 1.1.-2021: DSAB30 DSAB31 | ||||||
|  |         # DIAN 1.1.-2021: NSAB30 NSAB31 | ||||||
|  |         self.placeholder_for( | ||||||
|  |             './ext:UBLExtensions/ext:UBLExtension/ext:ExtensionContent/sts:DianExtensions/sts:AuthorizationProvider/sts:AuthorizationProviderID') | ||||||
|  |  | ||||||
|  |         # ZE02 se requiere existencia para firmar | ||||||
|  |         # DIAN 1.1.-2021: DSAA02 DSAB01 | ||||||
|  |         # DIAN 1.1.-2021: NSAA02 NSAB01 | ||||||
|  |         ublextension = self.fragment( | ||||||
|  |             './ext:UBLExtensions/ext:UBLExtension', append=True) | ||||||
|  |         # DIAN 1.1.-2021: DSAB02 | ||||||
|  |         # DIAN 1.1.-2021: NSAB02 | ||||||
|  |         extcontent = ublextension.find_or_create_element( | ||||||
|  |             '/ext:UBLExtension/ext:ExtensionContent') | ||||||
|  |         self.attach_invoice(invoice) | ||||||
|  |  | ||||||
|  |     def set_supplier(fexml, invoice): | ||||||
|  |         # DIAN 1.1.-2021: DSAJ01 | ||||||
|  |         # DIAN 1.1.-2021: NSAB01 | ||||||
|  |         fexml.placeholder_for('./cac:AccountingSupplierParty') | ||||||
|  |  | ||||||
|  |         # DIAN 1.1.-2021: DSAJ02 | ||||||
|  |         # DIAN 1.1.-2021: NSAJ02 | ||||||
|  |         fexml.set_element( | ||||||
|  |             './cac:AccountingSupplierParty/cbc:AdditionalAccountID', | ||||||
|  |             invoice.invoice_supplier.organization_code) | ||||||
|  |  | ||||||
|  |         # DIAN 1.1.-2021: DSAJ07 DSAJ08 | ||||||
|  |         # DIAN 1.1.-2021: NSAJ07 NSAJ08 | ||||||
|  |         fexml.placeholder_for( | ||||||
|  |             './cac:AccountingSupplierParty/cac:Party/cac:PhysicalLocation/cac:Address') | ||||||
|  |  | ||||||
|  |         # DIAN 1.1.-2021: DSAJ09 | ||||||
|  |         # DIAN 1.1.-2021: NSAJ09 | ||||||
|  |         fexml.set_element( | ||||||
|  |             './cac:AccountingSupplierParty/cac:Party/cac:PhysicalLocation/cac:Address/cbc:ID', | ||||||
|  |             invoice.invoice_supplier.address.city.code) | ||||||
|  |  | ||||||
|  |         # DIAN 1.1.-2021: DSAJ10 | ||||||
|  |         # DIAN 1.1.-2021: NSAJ10 | ||||||
|  |         fexml.set_element( | ||||||
|  |             './cac:AccountingSupplierParty/cac:Party/cac:PhysicalLocation/cac:Address/cbc:CityName', | ||||||
|  |             invoice.invoice_supplier.address.city.name) | ||||||
|  |  | ||||||
|  |         # DIAN 1.1.-2021: DSAJ73 | ||||||
|  |         # DIAN 1.1.-2021: NSAJ73 | ||||||
|  |         fexml.set_element( | ||||||
|  |             './cac:AccountingSupplierParty/cac:Party/cac:PhysicalLocation/cac:Address/cbc:PostalZone', | ||||||
|  |             invoice.invoice_supplier.address.postalzone.code) | ||||||
|  |  | ||||||
|  |         # DIAN 1.1.-2021: DSAJ11 | ||||||
|  |         # DIAN 1.1.-2021: NSAJ11 | ||||||
|  |         fexml.set_element( | ||||||
|  |             './cac:AccountingSupplierParty/cac:Party/cac:PhysicalLocation/cac:Address/cbc:CountrySubentity', | ||||||
|  |             invoice.invoice_supplier.address.countrysubentity.name) | ||||||
|  |  | ||||||
|  |         # DIAN 1.1.-2021: DSAJ12 | ||||||
|  |         # DIAN 1.1.-2021: NSAJ12 | ||||||
|  |         fexml.set_element( | ||||||
|  |             './cac:AccountingSupplierParty/cac:Party/cac:PhysicalLocation/cac:Address/cbc:CountrySubentityCode', | ||||||
|  |             invoice.invoice_supplier.address.countrysubentity.code) | ||||||
|  |         # DIAN 1.1.-2021: NSAJ13 NSAJ14 | ||||||
|  |         fexml.set_element( | ||||||
|  |             './cac:AccountingSupplierParty/cac:Party/cac:PhysicalLocation/cac:Address/cac:AddressLine/cbc:Line', | ||||||
|  |             invoice.invoice_supplier.address.street) | ||||||
|  |  | ||||||
|  |         # DIAN 1.1.-2021: DSAJ15 DSAJ16 | ||||||
|  |         # DIAN 1.1.-2021: NSAJ15 NSAJ16 | ||||||
|  |         fexml.set_element( | ||||||
|  |             './cac:AccountingSupplierParty/cac:Party/cac:PhysicalLocation/cac:Address/cac:Country/cbc:IdentificationCode', | ||||||
|  |             invoice.invoice_supplier.address.country.code) | ||||||
|  |  | ||||||
|  |         # DIAN 1.1.-2021: DSAJ17 | ||||||
|  |         # DIAN 1.1.-2021: NSAJ17 | ||||||
|  |         fexml.set_element('./cac:AccountingSupplierParty/cac:Party/cac:PhysicalLocation/cac:Address/cac:Country/cbc:Name', | ||||||
|  |                           invoice.invoice_supplier.address.country.name, | ||||||
|  |                           # DIAN 1.1.-2021: DSAJ18 | ||||||
|  |                           # # DIAN 1.1.-2021: NSAJ18 | ||||||
|  |                           languageID='es') | ||||||
|  |  | ||||||
|  |         supplier_company_id_attrs = fe.SCHEME_AGENCY_ATTRS.copy() | ||||||
|  |         supplier_company_id_attrs.update( | ||||||
|  |             { | ||||||
|  |                 'schemeID': invoice.invoice_supplier.ident.dv, | ||||||
|  |                 'schemeName': invoice.invoice_supplier.ident.type_fiscal}) | ||||||
|  |  | ||||||
|  |         # DIAN 1.1.-2021: DSAJ19 | ||||||
|  |         # DIAN 1.1.-2021: NSAJ19 | ||||||
|  |         fexml.placeholder_for( | ||||||
|  |             './cac:AccountingSupplierParty/cac:Party/cac:PartyTaxScheme') | ||||||
|  |  | ||||||
|  |         # DIAN 1.1.-2021: DSAJ20 | ||||||
|  |         # DIAN 1.1.-2021: NSAJ20 | ||||||
|  |         fexml.set_element( | ||||||
|  |             './cac:AccountingSupplierParty/cac:Party/cac:PartyTaxScheme/cbc:RegistrationName', | ||||||
|  |             invoice.invoice_supplier.legal_name) | ||||||
|  |  | ||||||
|  |         # DIAN 1.1.-2021: DSAJ21 | ||||||
|  |         # DIAN 1.1.-2021: NSAJ21 | ||||||
|  |         fexml.set_element( | ||||||
|  |             './cac:AccountingSupplierParty/cac:Party/cac:PartyTaxScheme/cbc:CompanyID', | ||||||
|  |             invoice.invoice_supplier.ident, | ||||||
|  |             # DIAN 1.1.-2021: DSAJ22 DSAJ23 DSAJ24 DSAJ25 | ||||||
|  |             # DIAN 1.1.-2021: NSAJ22 NSAJ23 NSAJ24 NSAJ25 | ||||||
|  |             **supplier_company_id_attrs) | ||||||
|  |  | ||||||
|  |         # DIAN 1.1.-2021: DSAJ26 | ||||||
|  |         # DIAN 1.1.-2021: NSAJ26 | ||||||
|  |         fexml.set_element( | ||||||
|  |             './cac:AccountingSupplierParty/cac:Party/cac:PartyTaxScheme/cbc:TaxLevelCode', | ||||||
|  |             invoice.invoice_supplier.responsability_code, | ||||||
|  |             listName=invoice.invoice_supplier.responsability_regime_code) | ||||||
|  |  | ||||||
|  |         # DIAN 1.1.-2021: DSAJ39 | ||||||
|  |         # DIAN 1.1.-2021: NSAJ39 | ||||||
|  |         fexml.placeholder_for( | ||||||
|  |             './cac:AccountingSupplierParty/cac:Party/cac:PartyTaxScheme/cac:TaxScheme') | ||||||
|  |  | ||||||
|  |         # DIAN 1.1.-2021: DSAJ40 | ||||||
|  |         # DIAN 1.1.-2021: NSAJ40 | ||||||
|  |         fexml.set_element( | ||||||
|  |             './cac:AccountingSupplierParty/cac:Party/cac:PartyTaxScheme/cac:TaxScheme/cbc:ID', | ||||||
|  |             invoice.invoice_customer.tax_scheme.code) | ||||||
|  |  | ||||||
|  |         # DIAN 1.1.-2021: DSAJ41 | ||||||
|  |         # DIAN 1.1.-2021: NSAJ41 | ||||||
|  |         fexml.set_element( | ||||||
|  |             './cac:AccountingSupplierParty/cac:Party/cac:PartyTaxScheme/cac:TaxScheme/cbc:Name', | ||||||
|  |             invoice.invoice_customer.tax_scheme.name) | ||||||
|  |  | ||||||
|  |     def set_customer(fexml, invoice): | ||||||
|  |         # DIAN 1.1.-2021: DSAK01 | ||||||
|  |         # DIAN 1.1.-2021: NSAK01 | ||||||
|  |         fexml.placeholder_for('./cac:AccountingCustomerParty') | ||||||
|  |  | ||||||
|  |         # DIAN 1.1.-2021: DSAK02 | ||||||
|  |         # DIAN 1.1.-2021: NSAK02 | ||||||
|  |         fexml.set_element( | ||||||
|  |             './cac:AccountingCustomerParty/cbc:AdditionalAccountID', | ||||||
|  |             invoice.invoice_customer.organization_code) | ||||||
|  |  | ||||||
|  |         # DIAN 1.1.-2021: DSAK03 | ||||||
|  |         # DIAN 1.1.-2021: NSAK03 | ||||||
|  |         fexml.placeholder_for('./cac:AccountingCustomerParty/cac:Party') | ||||||
|  |  | ||||||
|  |         # DIAN 1.1.-2021: DSAK19 | ||||||
|  |         # DIAN 1.1.-2021: NSAK19 | ||||||
|  |         fexml.placeholder_for( | ||||||
|  |             './cac:AccountingCustomerParty/cac:Party/cac:PartyTaxScheme') | ||||||
|  |  | ||||||
|  |         # DIAN 1.1.-2021: DSAK20 | ||||||
|  |         # DIAN 1.1.-2021: NSAK20 | ||||||
|  |         fexml.set_element( | ||||||
|  |             './cac:AccountingCustomerParty/cac:Party/cac:PartyTaxScheme/cbc:RegistrationName', | ||||||
|  |             invoice.invoice_customer.legal_name) | ||||||
|  |  | ||||||
|  |         customer_company_id_attrs = fe.SCHEME_AGENCY_ATTRS.copy() | ||||||
|  |         customer_company_id_attrs.update( | ||||||
|  |             { | ||||||
|  |                 'schemeID': invoice.invoice_customer.ident.dv, | ||||||
|  |                 'schemeName': invoice.invoice_customer.ident.type_fiscal}) | ||||||
|  |  | ||||||
|  |         # DIAN 1.1.-2021: DSAK21 | ||||||
|  |         # DIAN 1.1.-2021: NSAK21 | ||||||
|  |         fexml.set_element( | ||||||
|  |             './cac:AccountingCustomerParty/cac:Party/cac:PartyTaxScheme/cbc:CompanyID', | ||||||
|  |             invoice.invoice_customer.ident, | ||||||
|  |             # DIAN 1.1.-2021: DSAK22 DSAK23 DSAK24 DSAK25 | ||||||
|  |             # DIAN 1.1.-2021: NSAK22 NSAK23 NSAK24 NSAK25 | ||||||
|  |             **customer_company_id_attrs) | ||||||
|  |  | ||||||
|  |         # DIAN 1.1.-2021: DSAK26 | ||||||
|  |         # DIAN 1.1.-2021: NSAK26 | ||||||
|  |         fexml.set_element( | ||||||
|  |             './cac:AccountingCustomerParty/cac:Party/cac:PartyTaxScheme/cbc:TaxLevelCode', | ||||||
|  |             invoice.invoice_customer.responsability_code) | ||||||
|  |  | ||||||
|  |         # DIAN 1.1.-2021: DSAK39 | ||||||
|  |         # DIAN 1.1.-2021: NSAK39 | ||||||
|  |         fexml.placeholder_for( | ||||||
|  |             './cac:AccountingCustomerParty/cac:Party/cac:PartyTaxScheme/cac:TaxScheme') | ||||||
|  |  | ||||||
|  |         # DIAN 1.1.-2021: DSAK40 | ||||||
|  |         # DIAN 1.1.-2021: NSAK40 | ||||||
|  |         fexml.set_element( | ||||||
|  |             './cac:AccountingCustomerParty/cac:Party/cac:PartyTaxScheme/cac:TaxScheme/cbc:ID', | ||||||
|  |             invoice.invoice_customer.tax_scheme.code) | ||||||
|  |  | ||||||
|  |         # DIAN 1.1.-2021: DSAK41 | ||||||
|  |         # DIAN 1.1.-2021: NSAK41 | ||||||
|  |         fexml.set_element( | ||||||
|  |             './cac:AccountingCustomerParty/cac:Party/cac:PartyTaxScheme/cac:TaxScheme/cbc:Name', | ||||||
|  |             invoice.invoice_customer.tax_scheme.name) | ||||||
|  |  | ||||||
|  |     def set_payment_mean(fexml, invoice): | ||||||
|  |         payment_mean = invoice.invoice_payment_mean | ||||||
|  |  | ||||||
|  |         # DIAN 1.1.-2021: DSAN01 DSAN02 | ||||||
|  |         # DIAN 1.1.-2021: NSAN02 NSAN02 | ||||||
|  |         fexml.set_element('./cac:PaymentMeans/cbc:ID', payment_mean.id) | ||||||
|  |  | ||||||
|  |         # DIAN 1.1.-2021: DSAN03 | ||||||
|  |         # DIAN 1.1.-2021: NSAN03 | ||||||
|  |         fexml.set_element( | ||||||
|  |             './cac:PaymentMeans/cbc:PaymentMeansCode', | ||||||
|  |             payment_mean.code) | ||||||
|  |  | ||||||
|  |         # DIAN 1.1.-2021: DSAN04 | ||||||
|  |         # DIAN 1.1.-2021: NSAN04 | ||||||
|  |         fexml.set_element( | ||||||
|  |             './cac:PaymentMeans/cbc:PaymentDueDate', | ||||||
|  |             payment_mean.due_at.strftime('%Y-%m-%d')) | ||||||
|  |  | ||||||
|  |         # DIAN 1.1.-2021: DSAN05 | ||||||
|  |         # DIAN 1.1.-2021: NSAN05 | ||||||
|  |         fexml.set_element( | ||||||
|  |             './cac:PaymentMeans/cbc:PaymentID', | ||||||
|  |             payment_mean.payment_id) | ||||||
|  |  | ||||||
|  |     def set_element_amount_for(fexml, xml, xpath, amount): | ||||||
|  |         if not isinstance(amount, Amount): | ||||||
|  |             raise TypeError("amount not is Amount") | ||||||
|  |  | ||||||
|  |         xml.set_element(xpath, amount, currencyID=amount.currency.code) | ||||||
|  |  | ||||||
|  |     def set_element_amount(fexml, xpath, amount): | ||||||
|  |         if not isinstance(amount, Amount): | ||||||
|  |             raise TypeError("amount not is Amount") | ||||||
|  |  | ||||||
|  |         fexml.set_element(xpath, amount, currencyID=amount.currency.code) | ||||||
|  |  | ||||||
|  |     def set_legal_monetary(fexml, invoice): | ||||||
|  |         # DIAN 1.1.-2021: DSAU01 DSAU02 DSAU03 | ||||||
|  |         # DIAN 1.1.-2021: NSAU01 NSAU02 NSAU03 | ||||||
|  |         fexml.set_element_amount( | ||||||
|  |             './cac:LegalMonetaryTotal/cbc:LineExtensionAmount', | ||||||
|  |             invoice.invoice_legal_monetary_total.line_extension_amount) | ||||||
|  |  | ||||||
|  |         # DIAN 1.1.-2021: DSAU04 DSAU05 | ||||||
|  |         # DIAN 1.1.-2021: NSAU04 NSAU05 | ||||||
|  |         fexml.set_element_amount( | ||||||
|  |             './cac:LegalMonetaryTotal/cbc:TaxExclusiveAmount', | ||||||
|  |             invoice.invoice_legal_monetary_total.tax_exclusive_amount) | ||||||
|  |  | ||||||
|  |         # DIAN 1.1.-2021: DSAU06 DSAU07 | ||||||
|  |         # DIAN 1.1.-2021: NSAU06 DSAU07 | ||||||
|  |         fexml.set_element_amount( | ||||||
|  |             './cac:LegalMonetaryTotal/cbc:TaxInclusiveAmount', | ||||||
|  |             invoice.invoice_legal_monetary_total.tax_inclusive_amount) | ||||||
|  |  | ||||||
|  |         # DIAN 1.1.-2021: DSAU10 DSAU11 | ||||||
|  |         # DIAN 1.1.-2021: NSAU10 DSAU11 | ||||||
|  |         fexml.set_element_amount( | ||||||
|  |             './cac:LegalMonetaryTotal/cbc:ChargeTotalAmount', | ||||||
|  |             invoice.invoice_legal_monetary_total.charge_total_amount) | ||||||
|  |  | ||||||
|  |         # DIAN 1.1.-2021: DSAU14 DSAU15 | ||||||
|  |         # DIAN 1.1.-2021: NSAU14 DSAU15 | ||||||
|  |         fexml.set_element_amount( | ||||||
|  |             './cac:LegalMonetaryTotal/cbc:PayableAmount', | ||||||
|  |             invoice.invoice_legal_monetary_total.payable_amount) | ||||||
|  |  | ||||||
|  |     def _set_invoice_document_reference(fexml, reference): | ||||||
|  |         fexml._do_set_billing_reference( | ||||||
|  |             reference, 'cac:InvoiceDocumentReference') | ||||||
|  |  | ||||||
|  |     def _set_credit_note_document_reference(fexml, reference): | ||||||
|  |         fexml._do_set_billing_reference( | ||||||
|  |             reference, 'cac:CreditNoteDocumentReference') | ||||||
|  |  | ||||||
|  |     def _set_debit_note_document_reference(fexml, reference): | ||||||
|  |         fexml._do_set_billing_reference( | ||||||
|  |             reference, 'cac:DebitNoteDocumentReference') | ||||||
|  |  | ||||||
|  |     def _do_set_billing_reference(fexml, reference, tag_document): | ||||||
|  |  | ||||||
|  |         if tag_document == 'Invoice': | ||||||
|  |             schemeName = 'CUFE-SHA384' | ||||||
|  |         else: | ||||||
|  |             schemeName = 'CUDS-SHA384' | ||||||
|  |  | ||||||
|  |         fexml.set_element('./cac:BillingReference/%s/cbc:ID' % (tag_document), | ||||||
|  |                           reference.ident) | ||||||
|  |         fexml.set_element( | ||||||
|  |             './cac:BillingReference/cac:InvoiceDocumentReference/cbc:UUID', | ||||||
|  |             reference.uuid, | ||||||
|  |             schemeName=schemeName) | ||||||
|  |         fexml.set_element( | ||||||
|  |             './cac:BillingReference/cac:InvoiceDocumentReference/cbc:IssueDate', | ||||||
|  |             reference.date.strftime("%Y-%m-%d")) | ||||||
|  |  | ||||||
|  |     def set_billing_reference(fexml, invoice): | ||||||
|  |         reference = invoice.invoice_billing_reference | ||||||
|  |         if reference is None: | ||||||
|  |             return | ||||||
|  |  | ||||||
|  |         if isinstance(reference, DebitNoteDocumentReference): | ||||||
|  |             return fexml._set_debit_note_document_reference(reference) | ||||||
|  |         if isinstance(reference, CreditNoteDocumentReference): | ||||||
|  |             return fexml._set_credit_note_document_reference(reference) | ||||||
|  |  | ||||||
|  |         if isinstance(reference, InvoiceDocumentReference): | ||||||
|  |             return fexml._set_invoice_document_reference(reference) | ||||||
|  |  | ||||||
|  |     def set_discrepancy_response(fexml, invoice): | ||||||
|  |         reference = invoice.invoice_discrepancy_response | ||||||
|  |         if reference is None: | ||||||
|  |             return | ||||||
|  |         if isinstance(reference, DebitNoteDocumentReference): | ||||||
|  |             return fexml._set_debit_note_document_reference(reference) | ||||||
|  |         if isinstance(reference, CreditNoteDocumentReference): | ||||||
|  |             return fexml._set_credit_note_document_reference(reference) | ||||||
|  |  | ||||||
|  |         if isinstance(reference, InvoiceDocumentReference): | ||||||
|  |             return fexml._set_invoice_document_reference(reference) | ||||||
|  |  | ||||||
|  |         fexml.set_element('./cac:DiscrepancyResponse/cbc:ReferenceID', | ||||||
|  |                           reference.id) | ||||||
|  |         fexml.set_element('./cac:DiscrepancyResponse/cbc:ResponseCode', | ||||||
|  |                           reference.code) | ||||||
|  |         fexml.set_element('./cac:DiscrepancyResponse/cbc:Description', | ||||||
|  |                           reference.description) | ||||||
|  |  | ||||||
|  |     def set_invoice_totals(fexml, invoice): | ||||||
|  |         tax_amount_for = defaultdict(lambda: defaultdict(lambda: Amount(0.0))) | ||||||
|  |         percent_for = defaultdict(lambda: None) | ||||||
|  |  | ||||||
|  |         total_tax_amount = Amount(0.0) | ||||||
|  |  | ||||||
|  |         for invoice_line in invoice.invoice_lines: | ||||||
|  |             for subtotal in invoice_line.tax.subtotals: | ||||||
|  |                 if subtotal.scheme is not None: | ||||||
|  |                     tax_amount_for[ | ||||||
|  |                         subtotal.scheme.code][ | ||||||
|  |                             'tax_amount'] += subtotal.tax_amount | ||||||
|  |                     tax_amount_for[subtotal.scheme.code][ | ||||||
|  |                         'taxable_amount'] += invoice_line.taxable_amount | ||||||
|  |  | ||||||
|  |                     # MACHETE ojo InvoiceLine.tax pasar a Invoice | ||||||
|  |                     percent_for[subtotal.scheme.code] = subtotal.percent | ||||||
|  |  | ||||||
|  |                 total_tax_amount += subtotal.tax_amount | ||||||
|  |  | ||||||
|  |         if total_tax_amount != Amount(0.0): | ||||||
|  |             fexml.placeholder_for('./cac:TaxTotal') | ||||||
|  |             fexml.set_element_amount('./cac:TaxTotal/cbc:TaxAmount', | ||||||
|  |                                      total_tax_amount) | ||||||
|  |  | ||||||
|  |         for index, item in enumerate(tax_amount_for.items()): | ||||||
|  |             cod_impuesto, amount_of = item | ||||||
|  |             next_append = index > 0 | ||||||
|  |  | ||||||
|  |             # DIAN 1.7.-2020: FAS01 | ||||||
|  |             line = fexml.fragment('./cac:TaxTotal', append=next_append) | ||||||
|  |             # DIAN 1.7.-2020: FAU06 | ||||||
|  |             tax_amount = amount_of['tax_amount'] | ||||||
|  |             fexml.set_element_amount_for(line, | ||||||
|  |                                          '/cac:TaxTotal/cbc:TaxAmount', | ||||||
|  |                                          tax_amount) | ||||||
|  |  | ||||||
|  |             # DIAN 1.7.-2020: FAS05 | ||||||
|  |             fexml.set_element_amount_for( | ||||||
|  |                 line, | ||||||
|  |                 '/cac:TaxTotal/cac:TaxSubtotal/cbc:TaxableAmount', | ||||||
|  |                 amount_of['taxable_amount']) | ||||||
|  |  | ||||||
|  |             # DIAN 1.7.-2020: FAU06 | ||||||
|  |             fexml.set_element_amount_for( | ||||||
|  |                 line, | ||||||
|  |                 '/cac:TaxTotal/cac:TaxSubtotal/cbc:TaxAmount', | ||||||
|  |                 amount_of['tax_amount']) | ||||||
|  |  | ||||||
|  |             # DIAN 1.7.-2020: FAS07 | ||||||
|  |             if percent_for[cod_impuesto]: | ||||||
|  |                 line.set_element('/cac:TaxTotal/cac:TaxSubtotal/cbc:Percent', | ||||||
|  |                                  percent_for[cod_impuesto]) | ||||||
|  |  | ||||||
|  |             if percent_for[cod_impuesto]: | ||||||
|  |                 line.set_element( | ||||||
|  |                     '/cac:TaxTotal/cac:TaxSubtotal/cac:TaxCategory/cbc:Percent', | ||||||
|  |                     percent_for[cod_impuesto]) | ||||||
|  |  | ||||||
|  |             line.set_element( | ||||||
|  |                 '/cac:TaxTotal/cac:TaxSubtotal/cac:TaxCategory/cac:TaxScheme/cbc:ID', | ||||||
|  |                 cod_impuesto) | ||||||
|  |             line.set_element( | ||||||
|  |                 '/cac:TaxTotal/cac:TaxSubtotal/cac:TaxCategory/cac:TaxScheme/cbc:Name', 'IVA') | ||||||
|  |  | ||||||
|  |     # abstract method | ||||||
|  |  | ||||||
|  |     def tag_document(fexml): | ||||||
|  |         return 'Invoice' | ||||||
|  |  | ||||||
|  |     # abstract method | ||||||
|  |     def tag_document_concilied(fexml): | ||||||
|  |         return 'Invoiced' | ||||||
|  |  | ||||||
|  |     def set_invoice_line_withholding(fexml, line, invoice_line): | ||||||
|  |         fexml.set_element_amount_for(line, | ||||||
|  |                                      './cac:WithholdingTaxTotal/cbc:TaxAmount', | ||||||
|  |                                      invoice_line.withholding_amount) | ||||||
|  |         # DIAN 1.7.-2020: FAX05 | ||||||
|  |         fexml.set_element_amount_for( | ||||||
|  |             line, | ||||||
|  |             './cac:WithholdingTaxTotal/cac:TaxSubtotal/cbc:TaxableAmount', | ||||||
|  |             invoice_line.withholding_taxable_amount) | ||||||
|  |  | ||||||
|  |         for subtotal in invoice_line.withholding.subtotals: | ||||||
|  |             line.set_element( | ||||||
|  |                 './cac:WithholdingTaxTotal/cac:TaxSubtotal/cbc:TaxAmount', | ||||||
|  |                 subtotal.tax_amount, | ||||||
|  |                 currencyID='COP') | ||||||
|  |  | ||||||
|  |             if subtotal.percent is not None: | ||||||
|  |                 line.set_element( | ||||||
|  |                     './cac:WithholdingTaxTotal/cac:TaxSubtotal/cac:TaxCategory/cbc:Percent', | ||||||
|  |                     '%0.2f' % | ||||||
|  |                     round( | ||||||
|  |                         subtotal.percent, | ||||||
|  |                         2)) | ||||||
|  |  | ||||||
|  |             if subtotal.scheme is not None: | ||||||
|  |                 # DIAN 1.7.-2020: FAX15 | ||||||
|  |                 line.set_element( | ||||||
|  |                     './cac:WithholdingTaxTotal/cac:TaxSubtotal/cac:TaxCategory/cac:TaxScheme/cbc:ID', | ||||||
|  |                     subtotal.scheme.code) | ||||||
|  |                 line.set_element( | ||||||
|  |                     './cac:WithholdingTaxTotal/cac:TaxSubtotal/cac:TaxCategory/cac:TaxScheme/cbc:Name', | ||||||
|  |                     subtotal.scheme.name) | ||||||
|  |  | ||||||
|  |     def set_invoice_line_tax(fexml, line, invoice_line): | ||||||
|  |         fexml.set_element_amount_for(line, | ||||||
|  |                                      './cac:TaxTotal/cbc:TaxAmount', | ||||||
|  |                                      invoice_line.tax_amount) | ||||||
|  |  | ||||||
|  |         # DIAN 1.7.-2020: FAX05 | ||||||
|  |         fexml.set_element_amount_for( | ||||||
|  |             line, | ||||||
|  |             './cac:TaxTotal/cac:TaxSubtotal/cbc:TaxableAmount', | ||||||
|  |             invoice_line.taxable_amount) | ||||||
|  |         for subtotal in invoice_line.tax.subtotals: | ||||||
|  |             line.set_element( | ||||||
|  |                 './cac:TaxTotal/cac:TaxSubtotal/cbc:TaxAmount', | ||||||
|  |                 subtotal.tax_amount, | ||||||
|  |                 currencyID='COP') | ||||||
|  |  | ||||||
|  |             if subtotal.percent is not None: | ||||||
|  |                 line.set_element( | ||||||
|  |                     './cac:TaxTotal/cac:TaxSubtotal/cac:TaxCategory/cbc:Percent', | ||||||
|  |                     '%0.2f' % | ||||||
|  |                     round( | ||||||
|  |                         subtotal.percent, | ||||||
|  |                         2)) | ||||||
|  |  | ||||||
|  |             if subtotal.scheme is not None: | ||||||
|  |                 # DIAN 1.7.-2020: FAX15 | ||||||
|  |                 line.set_element( | ||||||
|  |                     './cac:TaxTotal/cac:TaxSubtotal/cac:TaxCategory/cac:TaxScheme/cbc:ID', | ||||||
|  |                     subtotal.scheme.code) | ||||||
|  |                 line.set_element( | ||||||
|  |                     './cac:TaxTotal/cac:TaxSubtotal/cac:TaxCategory/cac:TaxScheme/cbc:Name', | ||||||
|  |                     subtotal.scheme.name) | ||||||
|  |  | ||||||
|  |     def set_invoice_lines(fexml, invoice): | ||||||
|  |         next_append = False | ||||||
|  |         for index, invoice_line in enumerate(invoice.invoice_lines): | ||||||
|  |             line = fexml.fragment( | ||||||
|  |                 './cac:%sLine' % | ||||||
|  |                 (fexml.tag_document()), | ||||||
|  |                 append=next_append) | ||||||
|  |             next_append = True | ||||||
|  |  | ||||||
|  |             line.set_element('./cbc:ID', index + 1) | ||||||
|  |             line.set_element( | ||||||
|  |                 './cbc:%sQuantity' % | ||||||
|  |                 (fexml.tag_document_concilied()), | ||||||
|  |                 invoice_line.quantity, | ||||||
|  |                 unitCode='NAR') | ||||||
|  |             fexml.set_element_amount_for(line, | ||||||
|  |                                          './cbc:LineExtensionAmount', | ||||||
|  |                                          invoice_line.total_amount) | ||||||
|  |  | ||||||
|  |             period = line.fragment('./cac:InvoicePeriod') | ||||||
|  |             period.set_element('./cbc:StartDate', | ||||||
|  |                                datetime.now().strftime('%Y-%m-%d')) | ||||||
|  |             period.set_element( | ||||||
|  |                 './cbc:DescriptionCode', '1') | ||||||
|  |             period.set_element('./cbc:Description', | ||||||
|  |                                'Por operación') | ||||||
|  |  | ||||||
|  |             if not isinstance(invoice_line.tax, TaxTotalOmit): | ||||||
|  |                 fexml.set_invoice_line_tax(line, invoice_line) | ||||||
|  |  | ||||||
|  |             if not isinstance( | ||||||
|  |                     invoice_line.withholding, | ||||||
|  |                     WithholdingTaxTotalOmit): | ||||||
|  |                 fexml.set_invoice_line_withholding(line, invoice_line) | ||||||
|  |  | ||||||
|  |             line.set_element( | ||||||
|  |                 './cac:Item/cbc:Description', | ||||||
|  |                 invoice_line.item.description) | ||||||
|  |  | ||||||
|  |             line.set_element( | ||||||
|  |                 './cac:Item/cac:StandardItemIdentification/cbc:ID', | ||||||
|  |                 invoice_line.item.id, | ||||||
|  |                 schemeID=invoice_line.item.scheme_id, | ||||||
|  |                 schemeName=invoice_line.item.scheme_name, | ||||||
|  |                 schemeAgencyID=invoice_line.item.scheme_agency_id) | ||||||
|  |  | ||||||
|  |             line.set_element( | ||||||
|  |                 './cac:Price/cbc:PriceAmount', | ||||||
|  |                 invoice_line.price.amount, | ||||||
|  |                 currencyID=invoice_line.price.amount.currency.code) | ||||||
|  |             # DIAN 1.7.-2020: FBB04 | ||||||
|  |             line.set_element('./cac:Price/cbc:BaseQuantity', | ||||||
|  |                              invoice_line.quantity, | ||||||
|  |                              unitCode=invoice_line.quantity.code) | ||||||
|  |  | ||||||
|  |             for idx, charge in enumerate(invoice_line.allowance_charge): | ||||||
|  |                 next_append_charge = idx > 0 | ||||||
|  |                 fexml.append_allowance_charge( | ||||||
|  |                     line, index + 1, charge, append=next_append_charge) | ||||||
|  |  | ||||||
|  |     def set_allowance_charge(fexml, invoice): | ||||||
|  |         for idx, charge in enumerate(invoice.invoice_allowance_charge): | ||||||
|  |             next_append = idx > 0 | ||||||
|  |             fexml.append_allowance_charge( | ||||||
|  |                 fexml, idx + 1, charge, append=next_append) | ||||||
|  |  | ||||||
|  |     def append_allowance_charge(fexml, parent, idx, charge, append=False): | ||||||
|  |         line = parent.fragment('./cac:AllowanceCharge', append=append) | ||||||
|  |         # DIAN 1.7.-2020: FAQ02 | ||||||
|  |         line.set_element('./cbc:ID', idx) | ||||||
|  |         # DIAN 1.7.-2020: FAQ03 | ||||||
|  |         line.set_element('./cbc:ChargeIndicator', | ||||||
|  |                          str(charge.charge_indicator).lower()) | ||||||
|  |         if charge.reason: | ||||||
|  |             line.set_element( | ||||||
|  |                 './cbc:AllowanceChargeReasonCode', | ||||||
|  |                 charge.reason.code) | ||||||
|  |             line.set_element( | ||||||
|  |                 './cbc:allowanceChargeReason', | ||||||
|  |                 charge.reason.reason) | ||||||
|  |         line.set_element('./cbc:MultiplierFactorNumeric', | ||||||
|  |                          str(round(charge.multiplier_factor_numeric, 2))) | ||||||
|  |         fexml.set_element_amount_for(line, './cbc:Amount', charge.amount) | ||||||
|  |         fexml.set_element_amount_for( | ||||||
|  |             line, './cbc:BaseAmount', charge.base_amount) | ||||||
|  |  | ||||||
|  |     def attach_invoice(fexml, invoice): | ||||||
|  |         """adiciona etiquetas a FEXML y retorna FEXML | ||||||
|  |         en caso de fallar validacion retorna None""" | ||||||
|  |  | ||||||
|  |         fexml.placeholder_for('./ext:UBLExtensions') | ||||||
|  |         fexml.set_element('./cbc:UBLVersionID', 'UBL 2.1') | ||||||
|  |         fexml.set_element( | ||||||
|  |             './cbc:CustomizationID', | ||||||
|  |             invoice.invoice_operation_type) | ||||||
|  |         fexml.placeholder_for('./cbc:ProfileID') | ||||||
|  |         fexml.placeholder_for('./cbc:ProfileExecutionID') | ||||||
|  |         fexml.set_element('./cbc:ID', invoice.invoice_ident) | ||||||
|  |         fexml.placeholder_for('./cbc:UUID') | ||||||
|  |         fexml.set_element('./cbc:DocumentCurrencyCode', 'COP') | ||||||
|  |         fexml.set_element( | ||||||
|  |             './cbc:IssueDate', | ||||||
|  |             invoice.invoice_issue.strftime('%Y-%m-%d')) | ||||||
|  |         # DIAN 1.7.-2020: FAD10 | ||||||
|  |         fexml.set_element( | ||||||
|  |             './cbc:IssueTime', | ||||||
|  |             invoice.invoice_issue.strftime('%H:%M:%S-05:00')) | ||||||
|  |         fexml.set_element( | ||||||
|  |             './cbc:%sTypeCode' % | ||||||
|  |             (fexml.tag_document()), | ||||||
|  |             invoice.invoice_type_code, | ||||||
|  |             listAgencyID='195', | ||||||
|  |             listAgencyName='No matching global declaration available for the validation root', | ||||||
|  |             listURI='http://www.dian.gov.co') | ||||||
|  |         fexml.set_element('./cbc:LineCountNumeric', len(invoice.invoice_lines)) | ||||||
|  |         fexml.set_element( | ||||||
|  |             './cac:%sPeriod/cbc:StartDate' % | ||||||
|  |             (fexml.tag_document()), | ||||||
|  |             invoice.invoice_period_start.strftime('%Y-%m-%d')) | ||||||
|  |  | ||||||
|  |         fexml.set_element( | ||||||
|  |             './cac:%sPeriod/cbc:EndDate' % | ||||||
|  |             (fexml.tag_document()), | ||||||
|  |             invoice.invoice_period_end.strftime('%Y-%m-%d')) | ||||||
|  |  | ||||||
|  |         fexml.customize(invoice) | ||||||
|  |  | ||||||
|  |         fexml.set_supplier(invoice) | ||||||
|  |         fexml.set_customer(invoice) | ||||||
|  |         fexml.set_legal_monetary(invoice) | ||||||
|  |         fexml.set_invoice_totals(invoice) | ||||||
|  |         fexml.set_invoice_lines(invoice) | ||||||
|  |         fexml.set_payment_mean(invoice) | ||||||
|  |         fexml.set_allowance_charge(invoice) | ||||||
|  |         fexml.set_discrepancy_response(invoice) | ||||||
|  |         fexml.set_billing_reference(invoice) | ||||||
|  |  | ||||||
|  |         return fexml | ||||||
|  |  | ||||||
|  |     def customize(fexml, invoice): | ||||||
|  |         """adiciona etiquetas a FEXML y retorna FEXML | ||||||
|  |         en caso de fallar validacion retorna None""" | ||||||
							
								
								
									
										25
									
								
								facho/fe/form_xml/support_document_credit_note.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								facho/fe/form_xml/support_document_credit_note.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,25 @@ | |||||||
|  | # from .. import fe | ||||||
|  | # from ..form import * | ||||||
|  | from .support_document import DIANSupportDocumentXML | ||||||
|  |  | ||||||
|  | __all__ = ['DIANSupportDocumentCreditNoteXML'] | ||||||
|  |  | ||||||
|  |  | ||||||
|  | class DIANSupportDocumentCreditNoteXML(DIANSupportDocumentXML): | ||||||
|  |     """ | ||||||
|  |     DianInvoiceXML mapea objeto form.Invoice a XML segun | ||||||
|  |     lo indicado para la facturacion electronica. | ||||||
|  |     """ | ||||||
|  |  | ||||||
|  |     def __init__(self, invoice): | ||||||
|  |         super( | ||||||
|  |             DIANSupportDocumentCreditNoteXML, | ||||||
|  |             self).__init__( | ||||||
|  |             invoice, | ||||||
|  |             'CreditNote') | ||||||
|  |  | ||||||
|  |     def tag_document(fexml): | ||||||
|  |         return 'CreditNote' | ||||||
|  |  | ||||||
|  |     def tag_document_concilied(fexml): | ||||||
|  |         return 'Credited' | ||||||
| @@ -2,14 +2,30 @@ from .. import fe | |||||||
|  |  | ||||||
| __all__ = ['DIANWrite', 'DIANWriteSigned'] | __all__ = ['DIANWrite', 'DIANWriteSigned'] | ||||||
|  |  | ||||||
|  |  | ||||||
| def DIANWrite(xml, filename): | def DIANWrite(xml, filename): | ||||||
|     document = xml.tostring(xml_declaration=True, encoding='UTF-8') |     document = xml.tostring(xml_declaration=True, encoding='UTF-8') | ||||||
|     with open(filename, 'w') as f: |     with open(filename, 'w') as f: | ||||||
|         f.write(document) |         f.write(document) | ||||||
|  |  | ||||||
|  |  | ||||||
| def DIANWriteSigned(xml, filename, private_key, passphrase, use_cache_policy=False): | def DIANWriteSigned( | ||||||
|     document = xml.tostring(xml_declaration=True, encoding='UTF-8').encode('utf-8') |         xml, | ||||||
|     signer = fe.DianXMLExtensionSigner(private_key, passphrase=passphrase, mockpolicy=use_cache_policy) |         filename, | ||||||
|  |         private_key, | ||||||
|  |         passphrase, | ||||||
|  |         use_cache_policy=False, | ||||||
|  |         dian_signer=None): | ||||||
|  |     document = xml.tostring( | ||||||
|  |         xml_declaration=True, | ||||||
|  |         encoding='UTF-8').encode('utf-8') | ||||||
|  |     if dian_signer is None: | ||||||
|  |         dian_signer = fe.DianXMLExtensionSigner | ||||||
|  |  | ||||||
|  |     signer = dian_signer( | ||||||
|  |         private_key, | ||||||
|  |         passphrase=passphrase, | ||||||
|  |         localpolicy=use_cache_policy) | ||||||
|  |  | ||||||
|     with open(filename, 'w') as f: |     with open(filename, 'w') as f: | ||||||
|         f.write(signer.sign_xml_string(document)) |         f.write(signer.sign_xml_string(document)) | ||||||
|   | |||||||
| @@ -1,367 +0,0 @@ | |||||||
| import facho.model as model |  | ||||||
| import facho.model.fields as fields |  | ||||||
| import facho.fe.form as form |  | ||||||
| from facho import fe |  | ||||||
| from .common import * |  | ||||||
| from . import dian |  | ||||||
|  |  | ||||||
| from datetime import date, datetime |  | ||||||
| from collections import defaultdict |  | ||||||
| from copy import copy |  | ||||||
| import hashlib |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| class PhysicalLocation(model.Model): |  | ||||||
|     __name__ = 'PhysicalLocation' |  | ||||||
|  |  | ||||||
|     address = fields.Many2One(Address, namespace='cac') |  | ||||||
|      |  | ||||||
| class PartyTaxScheme(model.Model): |  | ||||||
|     __name__ = 'PartyTaxScheme' |  | ||||||
|  |  | ||||||
|     registration_name = fields.Many2One(Name, name='RegistrationName', namespace='cbc') |  | ||||||
|     company_id = fields.Many2One(ID, name='CompanyID', namespace='cbc') |  | ||||||
|     tax_level_code = fields.Many2One(ID, name='TaxLevelCode', namespace='cbc', default='ZZ') |  | ||||||
|  |  | ||||||
|  |  | ||||||
| class Party(model.Model): |  | ||||||
|     __name__ = 'Party' |  | ||||||
|  |  | ||||||
|     id = fields.Virtual(setter='_on_set_id') |  | ||||||
|     name = fields.Many2One(PartyName, namespace='cac') |  | ||||||
|  |  | ||||||
|     tax_scheme = fields.Many2One(PartyTaxScheme, namespace='cac') |  | ||||||
|     location = fields.Many2One(PhysicalLocation, namespace='cac') |  | ||||||
|     contact = fields.Many2One(Contact, namespace='cac') |  | ||||||
|      |  | ||||||
|     def _on_set_id(self, name, value): |  | ||||||
|         self.tax_scheme.company_id = value |  | ||||||
|         return value |  | ||||||
|  |  | ||||||
| class AccountingCustomerParty(model.Model): |  | ||||||
|     __name__ = 'AccountingCustomerParty' |  | ||||||
|  |  | ||||||
|     party = fields.Many2One(Party, namespace='cac') |  | ||||||
|  |  | ||||||
| class AccountingSupplierParty(model.Model): |  | ||||||
|     __name__ = 'AccountingSupplierParty' |  | ||||||
|  |  | ||||||
|     party = fields.Many2One(Party, namespace='cac') |  | ||||||
|  |  | ||||||
| class Quantity(model.Model): |  | ||||||
|     __name__  = 'Quantity' |  | ||||||
|  |  | ||||||
|     code = fields.Attribute('unitCode', default='NAR') |  | ||||||
|  |  | ||||||
|     def __setup__(self): |  | ||||||
|         self.value = 0 |  | ||||||
|  |  | ||||||
|     def __default_set__(self, value): |  | ||||||
|         self.value = value |  | ||||||
|         return value |  | ||||||
|  |  | ||||||
|     def __default_get__(self, name, value): |  | ||||||
|         return self.value |  | ||||||
|  |  | ||||||
| class Amount(model.Model): |  | ||||||
|     __name__ = 'Amount' |  | ||||||
|  |  | ||||||
|     currency = fields.Attribute('currencyID', default='COP') |  | ||||||
|     value = fields.Amount(name='amount', default=0.00, precision=2) |  | ||||||
|  |  | ||||||
|     def __default_set__(self, value): |  | ||||||
|         self.value = value |  | ||||||
|         return value |  | ||||||
|  |  | ||||||
|     def __default_get__(self, name, value): |  | ||||||
|         return self.value |  | ||||||
|  |  | ||||||
|     def __str__(self): |  | ||||||
|         return str(self.value) |  | ||||||
|  |  | ||||||
| class Price(model.Model): |  | ||||||
|     __name__ = 'Price' |  | ||||||
|  |  | ||||||
|     amount = fields.Many2One(Amount, name='PriceAmount', namespace='cbc') |  | ||||||
|      |  | ||||||
|     def __default_set__(self, value): |  | ||||||
|         self.amount = value |  | ||||||
|         return value |  | ||||||
|  |  | ||||||
|     def __default_get__(self, name, value): |  | ||||||
|         return self.amount |  | ||||||
|  |  | ||||||
| class Percent(model.Model): |  | ||||||
|     __name__ = 'Percent' |  | ||||||
|  |  | ||||||
| class TaxScheme(model.Model): |  | ||||||
|     __name__ = 'TaxScheme' |  | ||||||
|  |  | ||||||
|     id = fields.Many2One(ID, namespace='cbc') |  | ||||||
|     name= fields.Many2One(Name, namespace='cbc') |  | ||||||
|  |  | ||||||
| class TaxCategory(model.Model): |  | ||||||
|     __name__ = 'TaxCategory' |  | ||||||
|  |  | ||||||
|     percent = fields.Many2One(Percent, namespace='cbc') |  | ||||||
|     tax_scheme = fields.Many2One(TaxScheme, namespace='cac') |  | ||||||
|      |  | ||||||
| class TaxSubTotal(model.Model): |  | ||||||
|     __name__ = 'TaxSubTotal' |  | ||||||
|  |  | ||||||
|     taxable_amount = fields.Many2One(Amount, name='TaxableAmount', namespace='cbc', default=0.00) |  | ||||||
|     tax_amount = fields.Many2One(Amount, name='TaxAmount', namespace='cbc', default=0.00) |  | ||||||
|     tax_percent = fields.Many2One(Percent, namespace='cbc') |  | ||||||
|     tax_category = fields.Many2One(TaxCategory, namespace='cac') |  | ||||||
|  |  | ||||||
|     percent = fields.Virtual(setter='set_category', getter='get_category') |  | ||||||
|     scheme = fields.Virtual(setter='set_category', getter='get_category') |  | ||||||
|  |  | ||||||
|     def set_category(self, name, value): |  | ||||||
|         if name == 'percent': |  | ||||||
|             self.tax_category.percent = value |  | ||||||
|             # TODO(bit4bit) debe variar en conjunto? |  | ||||||
|             self.tax_percent = value |  | ||||||
|         elif name == 'scheme': |  | ||||||
|             self.tax_category.tax_scheme.id = value |  | ||||||
|  |  | ||||||
|         return value |  | ||||||
|  |  | ||||||
|     def get_category(self, name, value): |  | ||||||
|         if name == 'percent': |  | ||||||
|             return value |  | ||||||
|         elif name == 'scheme': |  | ||||||
|             return self.tax_category.tax_scheme |  | ||||||
|  |  | ||||||
| class TaxTotal(model.Model): |  | ||||||
|     __name__ = 'TaxTotal' |  | ||||||
|  |  | ||||||
|     tax_amount = fields.Many2One(Amount, name='TaxAmount', namespace='cbc', default=0.00) |  | ||||||
|     subtotals = fields.One2Many(TaxSubTotal, namespace='cac') |  | ||||||
|  |  | ||||||
|  |  | ||||||
| class AllowanceCharge(model.Model): |  | ||||||
|     __name__ = 'AllowanceCharge' |  | ||||||
|  |  | ||||||
|     amount = fields.Many2One(Amount, namespace='cbc') |  | ||||||
|     is_discount = fields.Virtual(default=False) |  | ||||||
|      |  | ||||||
|     def isCharge(self): |  | ||||||
|         return self.is_discount == False |  | ||||||
|  |  | ||||||
|     def isDiscount(self): |  | ||||||
|         return self.is_discount == True |  | ||||||
|  |  | ||||||
| class Taxes: |  | ||||||
|     class Scheme: |  | ||||||
|         def __init__(self, scheme): |  | ||||||
|             self.scheme = scheme |  | ||||||
|  |  | ||||||
|     class Iva(Scheme): |  | ||||||
|         def __init__(self, percent): |  | ||||||
|             super().__init__('01') |  | ||||||
|             self.percent = percent |  | ||||||
|  |  | ||||||
|         def calculate(self, amount): |  | ||||||
|             return form.Amount(amount) * form.Amount(self.percent / 100) |  | ||||||
|      |  | ||||||
| class InvoiceLine(model.Model): |  | ||||||
|     __name__ = 'InvoiceLine' |  | ||||||
|  |  | ||||||
|     id = fields.Many2One(ID, namespace='cbc') |  | ||||||
|     quantity = fields.Many2One(Quantity, name='InvoicedQuantity', namespace='cbc') |  | ||||||
|     taxtotal = fields.Many2One(TaxTotal, namespace='cac') |  | ||||||
|     price = fields.Many2One(Price, namespace='cac') |  | ||||||
|     amount = fields.Many2One(Amount, name='LineExtensionAmount', namespace='cbc') |  | ||||||
|     allowance_charge = fields.One2Many(AllowanceCharge, 'cac') |  | ||||||
|     tax_amount = fields.Virtual(getter='get_tax_amount') |  | ||||||
|      |  | ||||||
|     def __setup__(self): |  | ||||||
|         self._taxs = defaultdict(list) |  | ||||||
|         self._subtotals = {} |  | ||||||
|  |  | ||||||
|     def add_tax(self, tax): |  | ||||||
|         if not isinstance(tax, Taxes.Scheme): |  | ||||||
|             raise ValueError('tax expected TaxIva') |  | ||||||
|  |  | ||||||
|         # inicialiamos subtotal para impuesto |  | ||||||
|         if not tax.scheme in self._subtotals: |  | ||||||
|             subtotal = self.taxtotal.subtotals.create() |  | ||||||
|             subtotal.scheme = tax.scheme |  | ||||||
|              |  | ||||||
|             self._subtotals[tax.scheme] = subtotal |  | ||||||
|          |  | ||||||
|         self._taxs[tax.scheme].append(tax) |  | ||||||
|  |  | ||||||
|     def get_tax_amount(self, name, value): |  | ||||||
|         total = form.Amount(0) |  | ||||||
|         for (scheme, subtotal) in self._subtotals.items(): |  | ||||||
|             total += subtotal.tax_amount |  | ||||||
|  |  | ||||||
|         return total |  | ||||||
|  |  | ||||||
|     @fields.on_change(['price', 'quantity']) |  | ||||||
|     def update_amount(self, name, value): |  | ||||||
|         charge = form.AmountCollection(self.allowance_charge)\ |  | ||||||
|             .filter(lambda charge: charge.isCharge())\ |  | ||||||
|             .map(lambda charge: charge.amount)\ |  | ||||||
|             .sum() |  | ||||||
|  |  | ||||||
|         discount = form.AmountCollection(self.allowance_charge)\ |  | ||||||
|             .filter(lambda charge: charge.isDiscount())\ |  | ||||||
|             .map(lambda charge: charge.amount)\ |  | ||||||
|             .sum() |  | ||||||
|  |  | ||||||
|         total = form.Amount(self.quantity)  * form.Amount(self.price) |  | ||||||
|         self.amount = total + charge - discount |  | ||||||
|          |  | ||||||
|         for (scheme, subtotal) in self._subtotals.items(): |  | ||||||
|             subtotal.tax_amount = 0 |  | ||||||
|  |  | ||||||
|         for (scheme, taxes) in self._taxs.items(): |  | ||||||
|             for tax in taxes: |  | ||||||
|                 self._subtotals[scheme].tax_amount += tax.calculate(self.amount) |  | ||||||
|  |  | ||||||
| class LegalMonetaryTotal(model.Model): |  | ||||||
|     __name__ = 'LegalMonetaryTotal' |  | ||||||
|  |  | ||||||
|     line_extension_amount = fields.Many2One(Amount, name='LineExtensionAmount', namespace='cbc', default=0) |  | ||||||
|  |  | ||||||
|     tax_exclusive_amount = fields.Many2One(Amount, name='TaxExclusiveAmount', namespace='cbc', default=form.Amount(0)) |  | ||||||
|     tax_inclusive_amount = fields.Many2One(Amount, name='TaxInclusiveAmount', namespace='cbc', default=form.Amount(0)) |  | ||||||
|     charge_total_amount = fields.Many2One(Amount, name='ChargeTotalAmount', namespace='cbc', default=form.Amount(0)) |  | ||||||
|     payable_amount = fields.Many2One(Amount, name='PayableAmount', namespace='cbc', default=form.Amount(0)) |  | ||||||
|  |  | ||||||
|     @fields.on_change(['tax_inclusive_amount', 'charge_total']) |  | ||||||
|     def update_payable_amount(self, name, value): |  | ||||||
|         self.payable_amount = self.tax_inclusive_amount + self.charge_total_amount |  | ||||||
|  |  | ||||||
|  |  | ||||||
| class DIANExtensionContent(model.Model): |  | ||||||
|     __name__ = 'ExtensionContent' |  | ||||||
|      |  | ||||||
|     dian = fields.Many2One(dian.DianExtensions, name='DianExtensions', namespace='sts') |  | ||||||
|  |  | ||||||
| class DIANExtension(model.Model): |  | ||||||
|     __name__ = 'UBLExtension' |  | ||||||
|  |  | ||||||
|     content = fields.Many2One(DIANExtensionContent, namespace='ext') |  | ||||||
|  |  | ||||||
|     def __default_get__(self, name, value): |  | ||||||
|         return self.content.dian |  | ||||||
|  |  | ||||||
| class UBLExtension(model.Model): |  | ||||||
|     __name__ = 'UBLExtension' |  | ||||||
|  |  | ||||||
|     content = fields.Many2One(Element, name='ExtensionContent', namespace='ext', default='') |  | ||||||
|      |  | ||||||
| class UBLExtensions(model.Model): |  | ||||||
|     __name__ = 'UBLExtensions' |  | ||||||
|  |  | ||||||
|     dian = fields.Many2One(DIANExtension, namespace='ext', create=True) |  | ||||||
|     extension = fields.Many2One(UBLExtension, namespace='ext', create=True) |  | ||||||
|  |  | ||||||
| class Invoice(model.Model): |  | ||||||
|     __name__ = 'Invoice' |  | ||||||
|     __namespace__ = fe.NAMESPACES |  | ||||||
|  |  | ||||||
|     _ubl_extensions = fields.Many2One(UBLExtensions, namespace='ext') |  | ||||||
|     # nos interesa el acceso solo los atributos de la DIAN |  | ||||||
|     dian = fields.Virtual(getter='get_dian_extension') |  | ||||||
|      |  | ||||||
|     profile_id = fields.Many2One(Element, name='ProfileID', namespace='cbc', default='DIAN 2.1') |  | ||||||
|     profile_execute_id = fields.Many2One(Element, name='ProfileExecuteID', namespace='cbc', default='2') |  | ||||||
|      |  | ||||||
|     id = fields.Many2One(ID, namespace='cbc') |  | ||||||
|     issue = fields.Virtual(setter='set_issue') |  | ||||||
|     issue_date = fields.Many2One(Date, name='IssueDate', namespace='cbc') |  | ||||||
|     issue_time = fields.Many2One(Time, name='IssueTime', namespace='cbc') |  | ||||||
|      |  | ||||||
|     period = fields.Many2One(Period, name='InvoicePeriod', namespace='cac') |  | ||||||
|  |  | ||||||
|     supplier = fields.Many2One(AccountingSupplierParty, namespace='cac') |  | ||||||
|     customer = fields.Many2One(AccountingCustomerParty, namespace='cac') |  | ||||||
|     legal_monetary_total = fields.Many2One(LegalMonetaryTotal, namespace='cac') |  | ||||||
|     lines = fields.One2Many(InvoiceLine, namespace='cac') |  | ||||||
|      |  | ||||||
|     taxtotal_01 = fields.Many2One(TaxTotal) |  | ||||||
|     taxtotal_04 = fields.Many2One(TaxTotal) |  | ||||||
|     taxtotal_03 = fields.Many2One(TaxTotal) |  | ||||||
|  |  | ||||||
|     def __setup__(self): |  | ||||||
|         self._namespace_prefix = 'fe' |  | ||||||
|         # Se requieren minimo estos impuestos para |  | ||||||
|         # validar el cufe |  | ||||||
|         self._subtotal_01 = self.taxtotal_01.subtotals.create() |  | ||||||
|         self._subtotal_01.scheme = '01' |  | ||||||
|         self._subtotal_01.percent = 19.0 |  | ||||||
|  |  | ||||||
|         self._subtotal_04 = self.taxtotal_04.subtotals.create() |  | ||||||
|         self._subtotal_04.scheme = '04' |  | ||||||
|          |  | ||||||
|         self._subtotal_03 = self.taxtotal_03.subtotals.create() |  | ||||||
|         self._subtotal_03.scheme = '03' |  | ||||||
|  |  | ||||||
|     def cufe(self, token, environment): |  | ||||||
|  |  | ||||||
|         valor_bruto = self.legal_monetary_total.line_extension_amount |  | ||||||
|         valor_total_pagar = self.legal_monetary_total.payable_amount |  | ||||||
|  |  | ||||||
|         valor_impuesto_01 = form.Amount(0.0) |  | ||||||
|         valor_impuesto_04 = form.Amount(0.0) |  | ||||||
|         valor_impuesto_03 = form.Amount(0.0) |  | ||||||
|  |  | ||||||
|         for line in self.lines: |  | ||||||
|             for subtotal in line.taxtotal.subtotals: |  | ||||||
|                 if subtotal.scheme.id == '01': |  | ||||||
|                     valor_impuesto_01 += subtotal.tax_amount |  | ||||||
|                 elif subtotal.scheme.id == '04': |  | ||||||
|                     valor_impuesto_04 += subtotal.tax_amount |  | ||||||
|                 elif subtotal.scheme.id == '03': |  | ||||||
|                     valor_impuesto_03 += subtotal.tax_amount |  | ||||||
|  |  | ||||||
|         pattern = [ |  | ||||||
|             '%s' % str(self.id), |  | ||||||
|             '%s' % str(self.issue_date), |  | ||||||
|             '%s' % str(self.issue_time), |  | ||||||
|             valor_bruto.truncate_as_string(2), |  | ||||||
|             '01', valor_impuesto_01.truncate_as_string(2), |  | ||||||
|             '04', valor_impuesto_04.truncate_as_string(2), |  | ||||||
|             '03', valor_impuesto_03.truncate_as_string(2), |  | ||||||
|             valor_total_pagar.truncate_as_string(2), |  | ||||||
|             str(self.supplier.party.id), |  | ||||||
|             str(self.customer.party.id), |  | ||||||
|             str(token), |  | ||||||
|             str(environment) |  | ||||||
|         ] |  | ||||||
|  |  | ||||||
|         cufe = "".join(pattern) |  | ||||||
|         h = hashlib.sha384() |  | ||||||
|         h.update(cufe.encode('utf-8')) |  | ||||||
|         return h.hexdigest() |  | ||||||
|  |  | ||||||
|     @fields.on_change(['lines']) |  | ||||||
|     def update_legal_monetary_total(self, name, value): |  | ||||||
|         self.legal_monetary_total.line_extension_amount = 0 |  | ||||||
|         self.legal_monetary_total.tax_inclusive_amount = 0 |  | ||||||
|  |  | ||||||
|         for line in self.lines: |  | ||||||
|             self.legal_monetary_total.line_extension_amount += line.amount |  | ||||||
|             self.legal_monetary_total.tax_inclusive_amount += line.amount + line.tax_amount |  | ||||||
|  |  | ||||||
|     def set_issue(self, name, value): |  | ||||||
|         if not isinstance(value, datetime): |  | ||||||
|             raise ValueError('expected type datetime') |  | ||||||
|         self.issue_date = value.date() |  | ||||||
|         self.issue_time = value |  | ||||||
|  |  | ||||||
|     def get_dian_extension(self, name, _value): |  | ||||||
|         return self._ubl_extensions.dian |  | ||||||
|  |  | ||||||
|     def to_xml(self, **kw): |  | ||||||
|         # al generar documento el namespace |  | ||||||
|         # se hace respecto a la raiz |  | ||||||
|         return super().to_xml(**kw)\ |  | ||||||
|             .replace("fe:", "")\ |  | ||||||
|             .replace("xmlns:fe", "xmlns") |  | ||||||
| @@ -1,90 +0,0 @@ | |||||||
| import facho.model as model |  | ||||||
| import facho.model.fields as fields |  | ||||||
|  |  | ||||||
| from datetime import date, datetime |  | ||||||
|  |  | ||||||
| __all__ = ['Element', 'PartyName', 'Name', 'Date', 'Time', 'Period', 'ID', 'Address', 'Country', 'Contact'] |  | ||||||
|  |  | ||||||
| class Element(model.Model): |  | ||||||
|     """ |  | ||||||
|     Lo usuamos para elementos que solo manejan contenido |  | ||||||
|     """ |  | ||||||
|     __name__ = 'Element' |  | ||||||
|  |  | ||||||
| class Name(model.Model): |  | ||||||
|     __name__ = 'Name' |  | ||||||
|  |  | ||||||
| class Date(model.Model): |  | ||||||
|     __name__ = 'Date' |  | ||||||
|  |  | ||||||
|     def __default_set__(self, value): |  | ||||||
|         if isinstance(value, str): |  | ||||||
|             return value |  | ||||||
|         if isinstance(value, date): |  | ||||||
|             return value.isoformat() |  | ||||||
|  |  | ||||||
|     def __str__(self): |  | ||||||
|         return str(self._value) |  | ||||||
|  |  | ||||||
| class Time(model.Model): |  | ||||||
|     __name__ = 'Time' |  | ||||||
|  |  | ||||||
|     def __default_set__(self, value): |  | ||||||
|         if isinstance(value, str): |  | ||||||
|             return value |  | ||||||
|         if isinstance(value, date): |  | ||||||
|             return value.strftime('%H:%M:%S-05:00') |  | ||||||
|  |  | ||||||
|     def __str__(self): |  | ||||||
|         return str(self._value) |  | ||||||
|  |  | ||||||
| class Period(model.Model): |  | ||||||
|     __name__ = 'Period' |  | ||||||
|  |  | ||||||
|     start_date = fields.Many2One(Date, name='StartDate', namespace='cbc') |  | ||||||
|  |  | ||||||
|     end_date = fields.Many2One(Date, name='EndDate', namespace='cbc') |  | ||||||
|  |  | ||||||
| class ID(model.Model): |  | ||||||
|     __name__ = 'ID' |  | ||||||
|  |  | ||||||
|     def __default_get__(self, name, value): |  | ||||||
|         return self._value |  | ||||||
|  |  | ||||||
|     def __str__(self): |  | ||||||
|         return str(self._value) |  | ||||||
|  |  | ||||||
|  |  | ||||||
| class Country(model.Model): |  | ||||||
|     __name__ = 'Country' |  | ||||||
|  |  | ||||||
|     name = fields.Many2One(Element, name='Name', namespace='cbc') |  | ||||||
|  |  | ||||||
| class Address(model.Model): |  | ||||||
|     __name__ = 'Address' |  | ||||||
|  |  | ||||||
|     #DIAN 1.7.-2020: FAJ08 |  | ||||||
|     #DIAN 1.7.-2020: CAJ09 |  | ||||||
|     id = fields.Many2One(Element, name='ID', namespace='cbc') |  | ||||||
|  |  | ||||||
|     #DIAN 1.7.-2020: FAJ09 |  | ||||||
|     #DIAN 1.7.-2020: CAJ10 |  | ||||||
|     city = fields.Many2One(Element, name='CityName', namespace='cbc') |  | ||||||
|      |  | ||||||
|  |  | ||||||
| class PartyName(model.Model): |  | ||||||
|     __name__ = 'PartyName' |  | ||||||
|      |  | ||||||
|     name = fields.Many2One(Name, namespace='cbc') |  | ||||||
|  |  | ||||||
|     def __default_set__(self, value): |  | ||||||
|         self.name = value |  | ||||||
|         return value |  | ||||||
|  |  | ||||||
|     def __default_get__(self, name, value): |  | ||||||
|         return self.name |  | ||||||
|  |  | ||||||
| class Contact(model.Model): |  | ||||||
|     __name__ = 'Contact' |  | ||||||
|  |  | ||||||
|     email = fields.Many2One(Name, name='ElectronicEmail', namespace='cbc') |  | ||||||
| @@ -1,58 +0,0 @@ | |||||||
| import facho.model as model |  | ||||||
| import facho.model.fields as fields |  | ||||||
| from .common import * |  | ||||||
|  |  | ||||||
| class DIANElement(Element): |  | ||||||
|     """ |  | ||||||
|     Elemento que contiene atributos por defecto. |  | ||||||
|      |  | ||||||
|     Puede extender esta clase y modificar los atributos nuevamente |  | ||||||
|     """ |  | ||||||
|     __name__ = 'DIANElement' |  | ||||||
|      |  | ||||||
|     scheme_id = fields.Attribute('schemeID', default='4') |  | ||||||
|     scheme_name = fields.Attribute('schemeName', default='31') |  | ||||||
|     scheme_agency_name = fields.Attribute('schemeAgencyName', default='CO, DIAN (Dirección de Impuestos y Aduanas Nacionales)') |  | ||||||
|     scheme_agency_id = fields.Attribute('schemeAgencyID', default='195') |  | ||||||
|      |  | ||||||
| class SoftwareProvider(model.Model): |  | ||||||
|     __name__ = 'SoftwareProvider' |  | ||||||
|  |  | ||||||
|     provider_id = fields.Many2One(Element, name='ProviderID', namespace='sts') |  | ||||||
|     software_id = fields.Many2One(Element, name='SoftwareID', namespace='sts') |  | ||||||
|  |  | ||||||
| class InvoiceSource(model.Model): |  | ||||||
|     __name__ = 'InvoiceSource' |  | ||||||
|  |  | ||||||
|     identification_code = fields.Many2One(Element, name='IdentificationCode', namespace='sts', default='CO') |  | ||||||
|      |  | ||||||
| class AuthorizedInvoices(model.Model): |  | ||||||
|     __name__ = 'AuthorizedInvoices' |  | ||||||
|  |  | ||||||
|     prefix = fields.Many2One(Element, name='Prefix', namespace='sts') |  | ||||||
|     from_range = fields.Many2One(Element, name='From', namespace='sts') |  | ||||||
|     to_range = fields.Many2One(Element, name='To', namespace='sts') |  | ||||||
|      |  | ||||||
| class InvoiceControl(model.Model): |  | ||||||
|     __name__ = 'InvoiceControl' |  | ||||||
|  |  | ||||||
|     authorization = fields.Many2One(Element, name='InvoiceAuthorization', namespace='sts') |  | ||||||
|     period = fields.Many2One(Period, name='AuthorizationPeriod', namespace='sts') |  | ||||||
|     invoices = fields.Many2One(AuthorizedInvoices, namespace='sts') |  | ||||||
|  |  | ||||||
| class AuthorizationProvider(model.Model): |  | ||||||
|     __name__ = 'AuthorizationProvider' |  | ||||||
|  |  | ||||||
|  |  | ||||||
|     id = fields.Many2One(DIANElement, name='AuthorizationProviderID', namespace='sts', default='800197268') |  | ||||||
|      |  | ||||||
| class DianExtensions(model.Model): |  | ||||||
|     __name__ = 'DianExtensions' |  | ||||||
|  |  | ||||||
|     authorization_provider = fields.Many2One(AuthorizationProvider, namespace='sts', create=True) |  | ||||||
|  |  | ||||||
|     software_security_code = fields.Many2One(Element, name='SoftwareSecurityCode', namespace='sts') |  | ||||||
|     software_provider = fields.Many2One(SoftwareProvider, namespace='sts') |  | ||||||
|     source = fields.Many2One(InvoiceSource, namespace='sts') |  | ||||||
|     control = fields.Many2One(InvoiceControl, namespace='sts') |  | ||||||
|  |  | ||||||
							
								
								
									
										651
									
								
								facho/fe/nomina/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										651
									
								
								facho/fe/nomina/__init__.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,651 @@ | |||||||
|  | # | ||||||
|  | # Para esta implementacion se usa BDD | ||||||
|  | # ver **test_nomina.py**. | ||||||
|  | # | ||||||
|  | # La idea en general es validar comportamiento desde el XML, | ||||||
|  | # creando las estructuras minimas necesaras. | ||||||
|  |  | ||||||
|  | from dataclasses import dataclass | ||||||
|  | from datetime import datetime | ||||||
|  | import hashlib | ||||||
|  | import typing | ||||||
|  |  | ||||||
|  | from .. import fe | ||||||
|  | from .. import form | ||||||
|  | from ..data.dian import codelist | ||||||
|  |  | ||||||
|  | from .devengado import * | ||||||
|  | from .deduccion import * | ||||||
|  | from .trabajador import * | ||||||
|  | from .empleador import * | ||||||
|  | from .pago import * | ||||||
|  | from .lugar import Lugar | ||||||
|  |  | ||||||
|  | from .amount import Amount | ||||||
|  | from .exception import * | ||||||
|  |  | ||||||
|  | class Fecha: | ||||||
|  |     def __init__(self, fecha): | ||||||
|  |         try: | ||||||
|  |             datetime.strptime(fecha, "%Y-%m-%d") | ||||||
|  |         except ValueError: | ||||||
|  |             raise ValueError("fecha debe ser formato YYYY-MM-DD") | ||||||
|  |         self.value = fecha | ||||||
|  |  | ||||||
|  |     @classmethod | ||||||
|  |     def cast(cls, data, optional=False): | ||||||
|  |         if isinstance(data, str): | ||||||
|  |             return cls(data) | ||||||
|  |         elif isinstance(data, cls): | ||||||
|  |             return data | ||||||
|  |         elif data is None and optional: | ||||||
|  |             return None | ||||||
|  |         else: | ||||||
|  |             raise ValueError('no se logra hacer casting a Fecha') | ||||||
|  |  | ||||||
|  |     def __str__(self): | ||||||
|  |         return self.value | ||||||
|  |  | ||||||
|  | class FechaPago(Fecha): | ||||||
|  |     def apply(self, fragment): | ||||||
|  |         fragment.set_element('./FechaPago', self.value) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | @dataclass | ||||||
|  | class Novedad: | ||||||
|  |     # cune de nomina a relacionar | ||||||
|  |     # NIE204 | ||||||
|  |     cune: str | ||||||
|  |     # NIE199 | ||||||
|  |     activa: bool = False | ||||||
|  |  | ||||||
|  |     def apply(self, fragment): | ||||||
|  |         if self.cune != "": | ||||||
|  |             fragment.set_attributes('./Novedad', | ||||||
|  |                                     CUNENov=self.cune, | ||||||
|  |                                     ) | ||||||
|  |  | ||||||
|  |     def post_apply(self, fexml, scopexml, fragment): | ||||||
|  |         scopexml.set_element('./Novedad', self.activa) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | @dataclass | ||||||
|  | class NumeroSecuencia: | ||||||
|  |     consecutivo: int | ||||||
|  |     prefijo: str | ||||||
|  |  | ||||||
|  |     def apply(self, fragment): | ||||||
|  |         numero = f"{self.prefijo}{self.consecutivo}" | ||||||
|  |         fragment.set_attributes('./NumeroSecuenciaXML', | ||||||
|  |                                 # NIE010 | ||||||
|  |                                 Prefijo=self.prefijo, | ||||||
|  |                                 # NIE011 | ||||||
|  |                                 Consecutivo=self.consecutivo, | ||||||
|  |                                 # NIE012 | ||||||
|  |                                 Numero = numero) | ||||||
|  |  | ||||||
|  | @dataclass | ||||||
|  | class Periodo: | ||||||
|  |     fecha_ingreso: typing.Union[str, Fecha] | ||||||
|  |     fecha_liquidacion_inicio: typing.Union[str, Fecha] | ||||||
|  |     fecha_liquidacion_fin: typing.Union[str, Fecha] | ||||||
|  |     fecha_generacion: typing.Union[str, Fecha] | ||||||
|  |  | ||||||
|  |     tiempo_laborado: int = 1 | ||||||
|  |     fecha_retiro: typing.Union[str, Fecha] = None | ||||||
|  |  | ||||||
|  |     def __post_init__(self): | ||||||
|  |         self.fecha_ingreso = Fecha.cast(self.fecha_ingreso) | ||||||
|  |         self.fecha_liquidacion_inicio = Fecha.cast(self.fecha_liquidacion_inicio) | ||||||
|  |         self.fecha_liquidacion_fin = Fecha.cast(self.fecha_liquidacion_fin) | ||||||
|  |         self.fecha_retiro = Fecha.cast(self.fecha_retiro, optional=True) | ||||||
|  |          | ||||||
|  |     def apply(self, fragment): | ||||||
|  |         fragment.set_attributes('./Periodo', | ||||||
|  |                                 #NIE002 | ||||||
|  |                                 FechaIngreso=self.fecha_ingreso, | ||||||
|  |                                 #NIE003 | ||||||
|  |                                 FechaRetiro=self.fecha_retiro, | ||||||
|  |                                 #NIE004 | ||||||
|  |                                 FechaLiquidacionInicio=self.fecha_liquidacion_inicio, | ||||||
|  |                                 #NIE005 | ||||||
|  |                                 FechaLiquidacionFin=self.fecha_liquidacion_fin, | ||||||
|  |                                 #NIE006 | ||||||
|  |                                 TiempoLaborado=self.tiempo_laborado, | ||||||
|  |                                 #NIE008 | ||||||
|  |                                 FechaGen=self.fecha_generacion) | ||||||
|  |          | ||||||
|  | @dataclass | ||||||
|  | class Proveedor: | ||||||
|  |     razon_social: str | ||||||
|  |     nit: str | ||||||
|  |     dv: int | ||||||
|  |     software_id: str | ||||||
|  |     software_pin: str | ||||||
|  |  | ||||||
|  |     def apply(self, fragment): | ||||||
|  |         fragment.set_attributes('./ProveedorXML', | ||||||
|  |                                 # NIE017 | ||||||
|  |                                 NIT=self.nit, | ||||||
|  |                                 # NIE018 | ||||||
|  |                                 DV=self.dv, | ||||||
|  |                                 # NIE019 | ||||||
|  |                                 SoftwareID=self.software_id, | ||||||
|  |  | ||||||
|  |                                 SoftwareSC=None, | ||||||
|  |                                 # NIE025 | ||||||
|  |                                 RazonSocial=self.razon_social | ||||||
|  |                                 ) | ||||||
|  |  | ||||||
|  |     def post_apply(self, fexml, scopexml, fragment): | ||||||
|  |         cune_xpath = scopexml.xpath_from_root('/InformacionGeneral') | ||||||
|  |         cune = fexml.get_element_attribute(cune_xpath, 'CUNE') | ||||||
|  |          | ||||||
|  |         ambiente = fexml.get_element_attribute(scopexml.xpath_from_root('/InformacionGeneral'), 'Ambiente') | ||||||
|  |         codigo_qr = f"https://catalogo-vpfe.dian.gov.co/document/searchqr?documentkey={cune}" | ||||||
|  |  | ||||||
|  |         if InformacionGeneral.AMBIENTE_PRUEBAS == ambiente: | ||||||
|  |             codigo_qr = f"https://catalogo-vpfe-hab.dian.gov.co/document/searchqr?documentkey={cune}" | ||||||
|  |         elif ambiente is None: | ||||||
|  |             raise RuntimeError('fail to get InformacionGeneral/@Ambiente') | ||||||
|  |          | ||||||
|  |         scopexml.set_element('./CodigoQR', codigo_qr) | ||||||
|  |  | ||||||
|  |         # NIE020 | ||||||
|  |         software_code = self._software_security_code(fexml, scopexml) | ||||||
|  |         fexml.set_attributes(scopexml.xpath_from_root('/ProveedorXML'), SoftwareSC=software_code) | ||||||
|  |  | ||||||
|  |     def _software_security_code(self, fexml, scopexml): | ||||||
|  |          | ||||||
|  |  | ||||||
|  |         # 8.2 | ||||||
|  |         numero = fexml.get_element_attribute(scopexml.xpath_from_root('/NumeroSecuenciaXML'), 'Numero') | ||||||
|  |         if numero is None: | ||||||
|  |             raise RuntimeError('fallo obtener NumeroSequenciaXML/@Numero') | ||||||
|  |          | ||||||
|  |         id_software = self.software_id | ||||||
|  |         software_pin = self.software_pin | ||||||
|  |  | ||||||
|  |         code = "".join([id_software, software_pin, numero]) | ||||||
|  |  | ||||||
|  |         fexml.set_attributes(scopexml.xpath_from_root('/ProveedorXML')) | ||||||
|  |         h = hashlib.sha384() | ||||||
|  |         h.update(code.encode('utf-8')) | ||||||
|  |         return h.hexdigest() | ||||||
|  |      | ||||||
|  | @dataclass | ||||||
|  | class Metadata: | ||||||
|  |     novedad: Novedad | ||||||
|  |     secuencia: NumeroSecuencia | ||||||
|  |     # NIE013, NIE014, NIE015, NIE016 | ||||||
|  |     lugar_generacion: Lugar | ||||||
|  |     proveedor: Proveedor | ||||||
|  |  | ||||||
|  |     def apply(self, novedad, numero_secuencia_xml, lugar_generacion_xml, proveedor_xml): | ||||||
|  |         if novedad: | ||||||
|  |             self.novedad.apply(novedad) | ||||||
|  |         self.secuencia.apply(numero_secuencia_xml) | ||||||
|  |         self.lugar_generacion.apply(lugar_generacion_xml, './LugarGeneracionXML') | ||||||
|  |         self.proveedor.apply(proveedor_xml) | ||||||
|  |  | ||||||
|  |     def post_apply(self, fexml, scopexml, novedad, numero_secuencia_xml, lugar_generacion_xml, proveedor_xml): | ||||||
|  |         self.proveedor.post_apply(fexml, scopexml, proveedor_xml) | ||||||
|  |         if novedad: | ||||||
|  |             self.novedad.post_apply(fexml, scopexml, proveedor_xml)         | ||||||
|  |          | ||||||
|  | @dataclass | ||||||
|  | class PeriodoNomina: | ||||||
|  |     code: str | ||||||
|  |     name: str = '' | ||||||
|  |  | ||||||
|  |     def __post_init__(self): | ||||||
|  |         if self.code not in codelist.PeriodoNomina: | ||||||
|  |             raise ValueError("code [%s] not found" % (self.code)) | ||||||
|  |         self.name = codelist.PeriodoNomina[self.code]['name'] | ||||||
|  |  | ||||||
|  | @dataclass | ||||||
|  | class TipoMoneda: | ||||||
|  |     code: str | ||||||
|  |     name: str = '' | ||||||
|  |  | ||||||
|  |     def __post_init__(self): | ||||||
|  |         if self.code not in codelist.TipoMoneda: | ||||||
|  |             raise ValueError("code [%s] not found" % (self.code)) | ||||||
|  |         self.name = codelist.TipoMoneda[self.code]['name'] | ||||||
|  |  | ||||||
|  | @dataclass | ||||||
|  | class InformacionGeneral: | ||||||
|  |     @dataclass | ||||||
|  |     class TIPO_AMBIENTE: | ||||||
|  |         valor: str | ||||||
|  |  | ||||||
|  |         def __eq__(self, other): | ||||||
|  |             return self.valor == str(other) | ||||||
|  |  | ||||||
|  |     # TABLA 5.1.1 | ||||||
|  |     @dataclass | ||||||
|  |     class AMBIENTE_PRODUCCION(TIPO_AMBIENTE): | ||||||
|  |         valor: str = '1' | ||||||
|  |  | ||||||
|  |         def __str__(self): | ||||||
|  |             self.valor | ||||||
|  |  | ||||||
|  |     @dataclass | ||||||
|  |     class AMBIENTE_PRUEBAS(TIPO_AMBIENTE): | ||||||
|  |         valor: str = '2' | ||||||
|  |  | ||||||
|  |         def __str__(self): | ||||||
|  |             self.valor             | ||||||
|  |  | ||||||
|  |     # TABLA 5.5.7 | ||||||
|  |     @dataclass | ||||||
|  |     class TIPO_XML: | ||||||
|  |         valor: str | ||||||
|  |  | ||||||
|  |         def __eq__(self, other): | ||||||
|  |             return self.valor == str(other) | ||||||
|  |  | ||||||
|  |     @dataclass | ||||||
|  |     class TIPO_XML_NORMAL(TIPO_XML): | ||||||
|  |         valor: str = '102' | ||||||
|  |  | ||||||
|  |         def __str__(self): | ||||||
|  |             self.valor             | ||||||
|  |  | ||||||
|  |     @dataclass | ||||||
|  |     class TIPO_XML_AJUSTES(TIPO_XML): | ||||||
|  |         valor: str = '103' | ||||||
|  |  | ||||||
|  |         def __str__(self): | ||||||
|  |             self.valor | ||||||
|  |  | ||||||
|  |     fecha_generacion: typing.Union[str, Fecha] | ||||||
|  |     hora_generacion: str | ||||||
|  |     periodo_nomina: PeriodoNomina | ||||||
|  |     tipo_moneda: TipoMoneda | ||||||
|  |     tipo_ambiente: TIPO_AMBIENTE | ||||||
|  |     tipo_xml: TIPO_XML | ||||||
|  |     software_pin: str | ||||||
|  |  | ||||||
|  |     def __post_init__(self): | ||||||
|  |         self.fecha_generacion = Fecha.cast(self.fecha_generacion) | ||||||
|  |  | ||||||
|  |     def apply(self, fragment, version): | ||||||
|  |         fragment.set_attributes('./InformacionGeneral', | ||||||
|  |                                 # NIE022 | ||||||
|  |                                 Version = version, | ||||||
|  |                                 # NIE023 | ||||||
|  |                                 Ambiente = self.tipo_ambiente.valor, | ||||||
|  |                                 # NIE202 | ||||||
|  |                                 # TABLA 5.5.2 | ||||||
|  |                                 # TODO(bit4bit) solo NominaIndividual | ||||||
|  |                                 TipoXML = self.tipo_xml.valor, | ||||||
|  |                                 # NIE024 | ||||||
|  |                                 CUNE = None, | ||||||
|  |                                 # NIE025 | ||||||
|  |                                 EncripCUNE = 'CUNE-SHA384', | ||||||
|  |                                 # NIE026 | ||||||
|  |                                 FechaGen = self.fecha_generacion, | ||||||
|  |                                 # NIE027 | ||||||
|  |                                 HoraGen = self.hora_generacion, | ||||||
|  |                                 # NIE029 | ||||||
|  |                                 PeriodoNomina = self.periodo_nomina.code, | ||||||
|  |                                 # NIE030 | ||||||
|  |                                 TipoMoneda = self.tipo_moneda.code, | ||||||
|  |                                 TRM = 0 | ||||||
|  |                                 # TODO(bit4bit) resto... | ||||||
|  |                                 # ..... | ||||||
|  |                                 ) | ||||||
|  |  | ||||||
|  |     def post_apply(self, fexml, scopexml, fragment): | ||||||
|  |         # generar cune | ||||||
|  |         # ver 8.1.1.1 | ||||||
|  |         xpaths = [ | ||||||
|  |             scopexml.xpath_from_root('/NumeroSecuenciaXML/@Numero'), | ||||||
|  |             scopexml.xpath_from_root('/InformacionGeneral/@FechaGen'), | ||||||
|  |             scopexml.xpath_from_root('/InformacionGeneral/@HoraGen'), | ||||||
|  |             scopexml.xpath_from_root('/DevengadosTotal'), | ||||||
|  |             scopexml.xpath_from_root('/DeduccionesTotal'), | ||||||
|  |             scopexml.xpath_from_root('/ComprobanteTotal'), | ||||||
|  |             scopexml.xpath_from_root('/Empleador/@NIT'), | ||||||
|  |             scopexml.xpath_from_root('/Trabajador/@NumeroDocumento'), | ||||||
|  |             scopexml.xpath_from_root('/InformacionGeneral/@TipoXML'), | ||||||
|  |             tuple([self.software_pin]), | ||||||
|  |             scopexml.xpath_from_root('/InformacionGeneral/@Ambiente') | ||||||
|  |         ] | ||||||
|  |  | ||||||
|  |         campos = fexml.get_elements_text_or_attributes(xpaths) | ||||||
|  |  | ||||||
|  |         cune = "".join(campos) | ||||||
|  |  | ||||||
|  |         h = hashlib.sha384() | ||||||
|  |         h.update(cune.encode('utf-8')) | ||||||
|  |         cune_hash = h.hexdigest() | ||||||
|  |      | ||||||
|  |         fragment.set_attributes( | ||||||
|  |             './InformacionGeneral', | ||||||
|  |             # NIE024 | ||||||
|  |             CUNE = cune_hash | ||||||
|  |         ) | ||||||
|  |  | ||||||
|  | class DianXMLExtensionSigner(fe.DianXMLExtensionSigner): | ||||||
|  |  | ||||||
|  |     def __init__(self, pkcs12_path, passphrase=None, localpolicy=True): | ||||||
|  |         super().__init__(pkcs12_path, passphrase=passphrase, localpolicy=localpolicy) | ||||||
|  |  | ||||||
|  |     def _element_extension_content(self, fachoxml): | ||||||
|  |         return fachoxml.builder.xpath(fachoxml.root, './ext:UBLExtensions/ext:UBLExtension/ext:ExtensionContent') | ||||||
|  |  | ||||||
|  |  | ||||||
|  | class DIANNominaXML: | ||||||
|  |     def __init__(self, tag_document, xpath_ajuste=None, schemaLocation=None, namespace_ajuste=None): | ||||||
|  |         self.informacion_general_version = None | ||||||
|  |  | ||||||
|  |         self.tag_document = tag_document | ||||||
|  |  | ||||||
|  |         if namespace_ajuste: | ||||||
|  |             self.fexml = fe.FeXML(tag_document, namespace_ajuste) | ||||||
|  |         else: | ||||||
|  |             self.fexml = fe.FeXML(tag_document, 'dian:gov:co:facturaelectronica:NominaIndividual') | ||||||
|  |  | ||||||
|  |         self.fexml.root.set("SchemaLocation", "") | ||||||
|  |         self.fexml.root.set("schemaLocation", schemaLocation) | ||||||
|  |  | ||||||
|  |         # layout, la dian requiere que los elementos | ||||||
|  |         # esten ordenados segun el anexo tecnico | ||||||
|  |         self.fexml.placeholder_for('./ext:UBLExtensions/ext:UBLExtension/ext:ExtensionContent') | ||||||
|  |         self.fexml.placeholder_for('./TipoNota', optional=True) | ||||||
|  |  | ||||||
|  |         self.root_fragment = self.fexml | ||||||
|  |         if xpath_ajuste is not None: | ||||||
|  |             self.root_fragment = self.fexml.fragment(xpath_ajuste) | ||||||
|  |         self.root_fragment.placeholder_for('./ReemplazandoPredecesor', optional=True) | ||||||
|  |         self.root_fragment.placeholder_for('./EliminandoPredecesor', optional=True) | ||||||
|  |         if not namespace_ajuste: | ||||||
|  |             self.root_fragment.placeholder_for('./Novedad', optional=False) | ||||||
|  |         self.root_fragment.placeholder_for('./Periodo') | ||||||
|  |         self.root_fragment.placeholder_for('./NumeroSecuenciaXML') | ||||||
|  |         self.root_fragment.placeholder_for('./LugarGeneracionXML') | ||||||
|  |         self.root_fragment.placeholder_for('./ProveedorXML') | ||||||
|  |         self.root_fragment.placeholder_for('./CodigoQR') | ||||||
|  |         self.root_fragment.placeholder_for('./InformacionGeneral') | ||||||
|  |         self.root_fragment.placeholder_for('./Empleador') | ||||||
|  |         self.root_fragment.placeholder_for('./Trabajador') | ||||||
|  |         self.root_fragment.placeholder_for('./Pago') | ||||||
|  |         self.root_fragment.placeholder_for('./FechasPagos') | ||||||
|  |         self.root_fragment.placeholder_for('./Devengados/Basico') | ||||||
|  |         self.root_fragment.placeholder_for('./Devengados/Transporte', optional=True) | ||||||
|  |         if not namespace_ajuste: | ||||||
|  |             self.novedad = self.root_fragment.fragment('./Novedad') | ||||||
|  |         else: | ||||||
|  |             self.novedad = None | ||||||
|  |         self.informacion_general_xml = self.root_fragment.fragment('./InformacionGeneral') | ||||||
|  |         self.periodo_xml = self.root_fragment.fragment('./Periodo') | ||||||
|  |         self.fecha_pagos_xml = self.root_fragment.fragment('./FechasPagos') | ||||||
|  |         self.numero_secuencia_xml = self.root_fragment.fragment('./NumeroSecuenciaXML') | ||||||
|  |         self.lugar_generacion_xml = self.root_fragment.fragment('./LugarGeneracionXML') | ||||||
|  |         self.proveedor_xml = self.root_fragment.fragment('./ProveedorXML') | ||||||
|  |         self.empleador = self.root_fragment.fragment('./Empleador') | ||||||
|  |         self.trabajador = self.root_fragment.fragment('./Trabajador') | ||||||
|  |         self.pago_xml = self.root_fragment.fragment('./Pago') | ||||||
|  |         self.devengados = self.root_fragment.fragment('./Devengados') | ||||||
|  |         self.deducciones = self.root_fragment.fragment('./Deducciones') | ||||||
|  |  | ||||||
|  |         self.informacion_general = None | ||||||
|  |         self.metadata = None | ||||||
|  |  | ||||||
|  |     def asignar_metadata(self, metadata): | ||||||
|  |         if not isinstance(metadata, Metadata): | ||||||
|  |             raise ValueError('se espera tipo Metadata') | ||||||
|  |         self.metadata = metadata | ||||||
|  |                  | ||||||
|  |         self.metadata.apply(self.novedad, self.numero_secuencia_xml, self.lugar_generacion_xml, self.proveedor_xml) | ||||||
|  |          | ||||||
|  |     def asignar_informacion_general(self, general): | ||||||
|  |         if not isinstance(general, InformacionGeneral): | ||||||
|  |             raise ValueError('se espera tipo InformacionGeneral') | ||||||
|  |         self.informacion_general = general | ||||||
|  |         self.informacion_general.apply(self.informacion_general_xml, self.informacion_general_version) | ||||||
|  |  | ||||||
|  |     def asignar_periodo(self, periodo): | ||||||
|  |         if not isinstance(periodo, Periodo): | ||||||
|  |             raise ValueError('se espera tipo Periodo') | ||||||
|  |  | ||||||
|  |         periodo.apply(self.periodo_xml) | ||||||
|  |  | ||||||
|  |     def asignar_pago(self, pago): | ||||||
|  |         if not isinstance(pago, Pago): | ||||||
|  |             raise ValueError('se espera tipo Pago') | ||||||
|  |         pago.apply(self.pago_xml) | ||||||
|  |  | ||||||
|  |     def asignar_fecha_pago(self, data): | ||||||
|  |         if isinstance(data, str): | ||||||
|  |             fecha = FechaPago(data) | ||||||
|  |         elif isinstance(data, FechaPago): | ||||||
|  |             fecha = data | ||||||
|  |  | ||||||
|  |         fecha.apply(self.fecha_pagos_xml) | ||||||
|  |  | ||||||
|  |     def asignar_empleador(self, empleador): | ||||||
|  |         if not isinstance(empleador, Empleador): | ||||||
|  |             raise ValueError('se espera tipo Empleador') | ||||||
|  |         empleador.apply(self.empleador) | ||||||
|  |  | ||||||
|  |     def asignar_trabajador(self, trabajador): | ||||||
|  |         if not isinstance(trabajador, Trabajador): | ||||||
|  |             raise ValueError('se espera tipo Trabajador') | ||||||
|  |         trabajador.apply(self.trabajador) | ||||||
|  |          | ||||||
|  |     def adicionar_devengado(self, devengado): | ||||||
|  |         if not isinstance(devengado, Devengado): | ||||||
|  |             raise ValueError('se espera tipo Devengado') | ||||||
|  |  | ||||||
|  |         devengado.apply(self.devengados) | ||||||
|  |  | ||||||
|  |     def adicionar_deduccion(self, deduccion): | ||||||
|  |         if not isinstance(deduccion, Deduccion): | ||||||
|  |             raise ValueError('se espera tipo Devengado') | ||||||
|  |  | ||||||
|  |         deduccion.apply(self.deducciones) | ||||||
|  |  | ||||||
|  |     def validate(self): | ||||||
|  |         """ | ||||||
|  |         Valida requisitos segun anexo tecnico | ||||||
|  |         """ | ||||||
|  |         errors = [] | ||||||
|  |  | ||||||
|  |         def check_element(xpath, msg): | ||||||
|  |             if not self.fexml.exist_element(xpath): | ||||||
|  |                 errors.append(DIANNominaIndividualError(msg)) | ||||||
|  |  | ||||||
|  |         def check_attribute(xpath, key, msg): | ||||||
|  |             err = DIANNominaIndividualError(msg) | ||||||
|  |             elem = self.fexml.get_element(xpath) | ||||||
|  |  | ||||||
|  |             if elem is None: | ||||||
|  |                 return errors.append(err) | ||||||
|  |  | ||||||
|  |             if elem.get(key, None) is None: | ||||||
|  |                 return errors.append(err) | ||||||
|  |  | ||||||
|  |         check_attribute( | ||||||
|  |             self.fexml.xpath_from_root('/Periodo'), | ||||||
|  |             'FechaIngreso', | ||||||
|  |             'se requiere Periodo') | ||||||
|  |  | ||||||
|  |         check_element( | ||||||
|  |             self.fexml.xpath_from_root('/Pago'), | ||||||
|  |             'se requiere Pago' | ||||||
|  |         ) | ||||||
|  |  | ||||||
|  |         check_element( | ||||||
|  |             self.fexml.xpath_from_root('/Devengados/Basico'), | ||||||
|  |             'se requiere DevengadoBasico' | ||||||
|  |         ) | ||||||
|  |          | ||||||
|  |         check_element( | ||||||
|  |             self.fexml.xpath_from_root('/Deducciones/Salud'), | ||||||
|  |             'se requiere DeduccionSalud' | ||||||
|  |         ) | ||||||
|  |  | ||||||
|  |         check_element( | ||||||
|  |             self.fexml.xpath_from_root('/Deducciones/FondoPension'), | ||||||
|  |             'se requiere DeduccionFondoPension' | ||||||
|  |         ) | ||||||
|  |  | ||||||
|  |         return errors | ||||||
|  |  | ||||||
|  |     def informacion_general(self): | ||||||
|  |         xpath = self.root_fragment.xpath_from_root('/InformacionGeneral') | ||||||
|  |         return { | ||||||
|  |             'cune': self.fexml.get_element_attribute(cune_xpath, 'CUNE'), | ||||||
|  |             'fecha_generacion': self.fexml.get_element_attribute(xpath, 'FechaGen'), | ||||||
|  |             'numero': self.fexml.get_element_attribute(self.root_fragment('/NumeroSecuenciaXML', 'Numero')) | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |     def toFachoXML(self): | ||||||
|  |         self._devengados_total() | ||||||
|  |         self._deducciones_total() | ||||||
|  |         self._comprobante_total() | ||||||
|  |  | ||||||
|  |         if self.informacion_general is not None: | ||||||
|  |             #TODO(bit4bit) acoplamiento temporal | ||||||
|  |             # es importante el orden de ejecucion | ||||||
|  |  | ||||||
|  |             self.informacion_general.post_apply(self.fexml, self.root_fragment, self.informacion_general_xml) | ||||||
|  |  | ||||||
|  |         if self.metadata is not None: | ||||||
|  |             self.metadata.post_apply(self.fexml, self.root_fragment, self.novedad, self.numero_secuencia_xml, self.lugar_generacion_xml, self.proveedor_xml) | ||||||
|  |  | ||||||
|  |         return self.fexml | ||||||
|  |  | ||||||
|  |     def _comprobante_total(self): | ||||||
|  |         devengados_total = self.root_fragment.get_element_text_or_attribute('./DevengadosTotal', '0.0') | ||||||
|  |         deducciones_total = self.root_fragment.get_element_text_or_attribute('./DeduccionesTotal', '0.0') | ||||||
|  |  | ||||||
|  |         comprobante_total = Amount(devengados_total) - Amount(deducciones_total) | ||||||
|  |  | ||||||
|  |         self.root_fragment.set_element('./ComprobanteTotal', str(round(comprobante_total, 2))) | ||||||
|  |  | ||||||
|  |     def _deducciones_total(self): | ||||||
|  |         xpaths = [ | ||||||
|  |             self.root_fragment.xpath_from_root('/Deducciones/Salud/@Deduccion'), | ||||||
|  |             self.root_fragment.xpath_from_root('/Deducciones/FondoPension/@Deduccion') | ||||||
|  |         ] | ||||||
|  |         deducciones = map(lambda valor: Amount(valor), | ||||||
|  |                           self._values_of_xpaths(xpaths)) | ||||||
|  |  | ||||||
|  |         deducciones_total = Amount(0.0) | ||||||
|  |          | ||||||
|  |         for deduccion in deducciones: | ||||||
|  |             deducciones_total += deduccion | ||||||
|  |  | ||||||
|  |         self.root_fragment.set_element('./DeduccionesTotal', str(round(deducciones_total, 2))) | ||||||
|  |  | ||||||
|  |     def _devengados_total(self): | ||||||
|  |         xpaths = [ | ||||||
|  |             self.root_fragment.xpath_from_root('/Devengados/Basico/@SueldoTrabajado'), | ||||||
|  |             self.root_fragment.xpath_from_root('/Devengados/Transporte/@AuxilioTransporte'), | ||||||
|  |             self.root_fragment.xpath_from_root('/Devengados/Transporte/@ViaticoManuAlojS'), | ||||||
|  |             self.root_fragment.xpath_from_root('/Devengados/Transporte/@ViaticoManuAlojNS') | ||||||
|  |         ] | ||||||
|  |         devengados = map(lambda valor: Amount(valor), | ||||||
|  |                          self._values_of_xpaths(xpaths)) | ||||||
|  |          | ||||||
|  |         devengados_total = Amount(0.0) | ||||||
|  |         for devengado in devengados: | ||||||
|  |             devengados_total += devengado | ||||||
|  |         # TODO(bit4bit) nque valor va redondeado? | ||||||
|  |         # NIE186 | ||||||
|  |         self.root_fragment.set_element('./Redondeo', str(round(0,2)))           | ||||||
|  |         self.root_fragment.set_element('./DevengadosTotal', str(round(devengados_total,2))) | ||||||
|  |  | ||||||
|  |     def _values_of_xpaths(self, xpaths): | ||||||
|  |         xpaths_values_of_values = map(lambda val: self.fexml.get_element_text_or_attribute(val, multiple=True), xpaths) | ||||||
|  |         xpaths_values = [] | ||||||
|  |         # toda esta carreta para hacer un aplano de lista | ||||||
|  |         for xpath_values in xpaths_values_of_values: | ||||||
|  |             if xpath_values is None: | ||||||
|  |                 continue | ||||||
|  |  | ||||||
|  |             for xpath_value in xpath_values: | ||||||
|  |                 xpaths_values.append(xpath_value) | ||||||
|  |  | ||||||
|  |         return filter(lambda val: val is not None, xpaths_values) | ||||||
|  |  | ||||||
|  | class DIANNominaIndividual(DIANNominaXML): | ||||||
|  |  | ||||||
|  |     def __init__(self): | ||||||
|  |         schema = "dian:gov:co:facturaelectronica:NominaIndividual NominaIndividualElectronicaXSD.xsd" | ||||||
|  |  | ||||||
|  |         super().__init__('NominaIndividual', schemaLocation=schema) | ||||||
|  |         self.informacion_general_version = 'V1.0: Documento Soporte de Pago de Nómina Electrónica' | ||||||
|  |  | ||||||
|  | # TODO(bit4bit) confirmar que no tienen en comun con NominaIndividual | ||||||
|  | class DIANNominaIndividualDeAjuste(DIANNominaXML): | ||||||
|  |  | ||||||
|  |     class Reemplazar(DIANNominaXML): | ||||||
|  |         @dataclass | ||||||
|  |         class Predecesor: | ||||||
|  |             numero: str | ||||||
|  |             cune: str | ||||||
|  |             fecha_generacion: str | ||||||
|  |  | ||||||
|  |             def apply(self, fragment): | ||||||
|  |                 # NIAE214 | ||||||
|  |                 fragment.set_element('./TipoNota', '1')                 | ||||||
|  |                 fragment.set_element('./Reemplazar/ReemplazandoPredecesor', None, | ||||||
|  |                                      # NIAE090 | ||||||
|  |                                      NumeroPred = self.numero, | ||||||
|  |                                      # NIAE191 | ||||||
|  |                                      CUNEPred = self.cune, | ||||||
|  |                                      # NIAE192 | ||||||
|  |                                      FechaGenPred = self.fecha_generacion | ||||||
|  |                                      ) | ||||||
|  |  | ||||||
|  |         def __init__(self): | ||||||
|  |             schema = "dian:gov:co:facturaelectronica:NominaIndividualDeAjuste NominaIndividualDeAjusteElectronicaXSD.xsd" | ||||||
|  |              | ||||||
|  |             super().__init__('NominaIndividualDeAjuste', './Reemplazar', schemaLocation=schema, namespace_ajuste='dian:gov:co:facturaelectronica:NominaIndividualDeAjuste') | ||||||
|  |              | ||||||
|  |             self.informacion_general_version = 'V1.0: Nota de Ajuste de Documento Soporte de Pago de Nómina Electrónica' | ||||||
|  |  | ||||||
|  |         def asignar_predecesor(self, predecesor): | ||||||
|  |             if not isinstance(predecesor, self.Predecesor): | ||||||
|  |                 raise ValueError("se espera tipo Predecesor") | ||||||
|  |             predecesor.apply(self.fexml) | ||||||
|  |  | ||||||
|  |          | ||||||
|  |     class Eliminar(DIANNominaXML): | ||||||
|  |          | ||||||
|  |         @dataclass | ||||||
|  |         class Predecesor: | ||||||
|  |             numero: str | ||||||
|  |             cune: str | ||||||
|  |             fecha_generacion: str | ||||||
|  |  | ||||||
|  |             def apply(self, fragment): | ||||||
|  |                 fragment.set_element('./TipoNota', '2') | ||||||
|  |                 fragment.set_element('./Eliminar/EliminandoPredecesor', None, | ||||||
|  |                                      # NIAE090 | ||||||
|  |                                      NumeroPred = self.numero, | ||||||
|  |                                      # NIAE191 | ||||||
|  |                                      CUNEPred = self.cune, | ||||||
|  |                                      # NIAE192 | ||||||
|  |                                      FechaGenPred = self.fecha_generacion | ||||||
|  |                                      ) | ||||||
|  |  | ||||||
|  |         def __init__(self): | ||||||
|  |             schema = "dian:gov:co:facturaelectronica:NominaIndividualDeAjuste NominaIndividualDeAjusteElectronicaXSD.xsd"             | ||||||
|  |             super().__init__('NominaIndividualDeAjuste', './Eliminar', schemaLocation=schema, namespace_ajuste='dian:gov:co:facturaelectronica:NominaIndividualDeAjuste') | ||||||
|  |  | ||||||
|  |             self.informacion_general_version = "V1.0: Nota de Ajuste de Documento Soporte de Pago de Nómina Electrónica" | ||||||
|  |  | ||||||
|  |         def asignar_predecesor(self, predecesor): | ||||||
|  |             if not isinstance(predecesor, self.Predecesor): | ||||||
|  |                 raise ValueError("se espera tipo Eliminar.Predecesor") | ||||||
|  |             predecesor.apply(self.fexml) | ||||||
|  |              | ||||||
|  |     def __init__(self): | ||||||
|  |         super().__init__('NominaIndividualDeAjuste') | ||||||
|  |  | ||||||
							
								
								
									
										4
									
								
								facho/fe/nomina/amount.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								facho/fe/nomina/amount.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,4 @@ | |||||||
|  | from .. import form | ||||||
|  |  | ||||||
|  | class Amount(form.Amount): | ||||||
|  |     pass | ||||||
							
								
								
									
										3
									
								
								facho/fe/nomina/deduccion/README.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								facho/fe/nomina/deduccion/README.md
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,3 @@ | |||||||
|  | # contributing | ||||||
|  |  | ||||||
|  | crear nuevo objeto de valor y exportar en **__init__.py** atributo **__all__**. | ||||||
							
								
								
									
										13
									
								
								facho/fe/nomina/deduccion/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								facho/fe/nomina/deduccion/__init__.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,13 @@ | |||||||
|  | # | ||||||
|  | # al crear objetos de valor | ||||||
|  | # se debe exportar en __all__ | ||||||
|  |  | ||||||
|  | from .deduccion import * | ||||||
|  | from .salud import * | ||||||
|  | from .fondo_pension import * | ||||||
|  |  | ||||||
|  | __all__ = [ | ||||||
|  |     'Deduccion', | ||||||
|  |     'DeduccionSalud', | ||||||
|  |     'DeduccionFondoPension' | ||||||
|  | ] | ||||||
							
								
								
									
										2
									
								
								facho/fe/nomina/deduccion/deduccion.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								facho/fe/nomina/deduccion/deduccion.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,2 @@ | |||||||
|  | class Deduccion: | ||||||
|  |     pass | ||||||
							
								
								
									
										18
									
								
								facho/fe/nomina/deduccion/fondo_pension.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								facho/fe/nomina/deduccion/fondo_pension.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,18 @@ | |||||||
|  | from dataclasses import dataclass | ||||||
|  |  | ||||||
|  | from ..amount import Amount | ||||||
|  | from .deduccion import Deduccion | ||||||
|  |  | ||||||
|  | @dataclass | ||||||
|  | class DeduccionFondoPension(Deduccion): | ||||||
|  |     porcentaje: Amount | ||||||
|  |     deduccion: Amount | ||||||
|  |  | ||||||
|  |     def apply(self, fragment): | ||||||
|  |         fragment.set_element('./FondoPension', None, | ||||||
|  |                              append_ = True, | ||||||
|  |                              # NIE164 | ||||||
|  |                              Porcentaje = str(round(self.porcentaje, 2)), | ||||||
|  |                              #  NIE166 | ||||||
|  |                              Deduccion = self.deduccion | ||||||
|  |                              ) | ||||||
							
								
								
									
										19
									
								
								facho/fe/nomina/deduccion/salud.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								facho/fe/nomina/deduccion/salud.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,19 @@ | |||||||
|  | from dataclasses import dataclass | ||||||
|  |  | ||||||
|  | from ..amount import Amount | ||||||
|  | from .deduccion import Deduccion | ||||||
|  |  | ||||||
|  | @dataclass | ||||||
|  | class DeduccionSalud(Deduccion): | ||||||
|  |     porcentaje: Amount | ||||||
|  |     deduccion: Amount | ||||||
|  |  | ||||||
|  |     def apply(self, fragment): | ||||||
|  |         fragment.set_element('./Salud', None, | ||||||
|  |                              append_ = True, | ||||||
|  |                              # NIE161 | ||||||
|  |                              Porcentaje = str(round(self.porcentaje, 2)), | ||||||
|  |                              #  NIE163 | ||||||
|  |                              Deduccion = self.deduccion | ||||||
|  |                              ) | ||||||
|  |  | ||||||
							
								
								
									
										4
									
								
								facho/fe/nomina/departamento.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								facho/fe/nomina/departamento.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,4 @@ | |||||||
|  | from .. import form | ||||||
|  |  | ||||||
|  | class Departamento(form.CountrySubentity): | ||||||
|  |     pass | ||||||
							
								
								
									
										3
									
								
								facho/fe/nomina/devengado/README.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								facho/fe/nomina/devengado/README.md
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,3 @@ | |||||||
|  | # contributing | ||||||
|  |  | ||||||
|  | crear nuevo objeto de valor y exportar en **__init__.py** atributo **__all__**. | ||||||
							
								
								
									
										19
									
								
								facho/fe/nomina/devengado/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								facho/fe/nomina/devengado/__init__.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,19 @@ | |||||||
|  |  | ||||||
|  | from .basico import * | ||||||
|  | from .transporte import * | ||||||
|  | from .devengado import * | ||||||
|  | from .horas_extras import * | ||||||
|  |  | ||||||
|  | __all__ = [ | ||||||
|  |     'Devengado', | ||||||
|  |     'DevengadoBasico', | ||||||
|  |     'DevengadoTransporte', | ||||||
|  |     'DevengadoHoraExtra', | ||||||
|  |     'DevengadoHorasExtrasDiarias', | ||||||
|  |     'DevengadoHorasExtrasNocturnas', | ||||||
|  |     'DevengadoHorasRecargoNocturno', | ||||||
|  |     'DevengadoHorasExtrasDiariasDominicalesYFestivos', | ||||||
|  |     'DevengadoHorasRecargoDiariasDominicalesYFestivos', | ||||||
|  |     'DevengadoHorasExtrasNocturnasDominicalesYFestivos', | ||||||
|  |     'DevengadoHorasRecargoNocturnoDominicalesYFestivos' | ||||||
|  | ] | ||||||
							
								
								
									
										20
									
								
								facho/fe/nomina/devengado/basico.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								facho/fe/nomina/devengado/basico.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,20 @@ | |||||||
|  | from dataclasses import dataclass | ||||||
|  |  | ||||||
|  | from ..amount import Amount | ||||||
|  | from .devengado import Devengado | ||||||
|  |  | ||||||
|  |  | ||||||
|  | @dataclass | ||||||
|  | class DevengadoBasico(Devengado): | ||||||
|  |     dias_trabajados: int | ||||||
|  |     sueldo_trabajado: Amount | ||||||
|  |  | ||||||
|  |     def apply(self, fragment): | ||||||
|  |         fragment.find_or_create_element('./Basico') | ||||||
|  |          | ||||||
|  |         fragment.set_attributes('/Basico', | ||||||
|  |                                 # NIE069 | ||||||
|  |                                 DiasTrabajados = str(self.dias_trabajados), | ||||||
|  |                                 # NIE070 | ||||||
|  |                                 SueldoTrabajado = round(self.sueldo_trabajado, 2) | ||||||
|  |                                 ) | ||||||
							
								
								
									
										2
									
								
								facho/fe/nomina/devengado/devengado.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								facho/fe/nomina/devengado/devengado.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,2 @@ | |||||||
|  | class Devengado: | ||||||
|  |     pass | ||||||
							
								
								
									
										93
									
								
								facho/fe/nomina/devengado/horas_extras.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										93
									
								
								facho/fe/nomina/devengado/horas_extras.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,93 @@ | |||||||
|  | from dataclasses import dataclass | ||||||
|  | from typing import List | ||||||
|  |  | ||||||
|  | from ..amount import Amount | ||||||
|  | from .devengado import Devengado | ||||||
|  |  | ||||||
|  |  | ||||||
|  | @dataclass | ||||||
|  | class DevengadoHoraExtra: | ||||||
|  |     hora_inicio: str | ||||||
|  |     hora_fin: str | ||||||
|  |     cantidad: int | ||||||
|  |     porcentaje: Amount | ||||||
|  |     pago: Amount | ||||||
|  |  | ||||||
|  |     def apply(self, child_path, fragment): | ||||||
|  |         fragment.set_element(child_path, None, | ||||||
|  |                              append_=True, | ||||||
|  |                              # NIE074 | ||||||
|  |                              HoraInicio=self.hora_inicio, | ||||||
|  |                              # NIE075 | ||||||
|  |                              HoraFin=self.hora_fin, | ||||||
|  |                              # NIE076 | ||||||
|  |                              Cantidad=self.cantidad, | ||||||
|  |                              # NIE077 | ||||||
|  |                              Porcentaje=str(round(self.porcentaje, 2)), | ||||||
|  |                              # NIE078 | ||||||
|  |                              Pago=str(round(self.pago, 2))) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | @dataclass | ||||||
|  | class DevengadoHorasExtrasDiarias(Devengado): | ||||||
|  |     horas_extras: List[DevengadoHoraExtra] | ||||||
|  |      | ||||||
|  |     def apply(self, fragment): | ||||||
|  |         hora_extra_xml = fragment.fragment('./HEDs') | ||||||
|  |         for hora_extra in self.horas_extras: | ||||||
|  |             hora_extra.apply('./HED', hora_extra_xml) | ||||||
|  |  | ||||||
|  | @dataclass | ||||||
|  | class DevengadoHorasExtrasNocturnas(Devengado): | ||||||
|  |     horas_extras: List[DevengadoHoraExtra] | ||||||
|  |      | ||||||
|  |     def apply(self, fragment): | ||||||
|  |         hora_extra_xml = fragment.fragment('./HENs') | ||||||
|  |         for hora_extra in self.horas_extras: | ||||||
|  |             hora_extra.apply('./HEN', hora_extra_xml) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | @dataclass | ||||||
|  | class DevengadoHorasRecargoNocturno(Devengado): | ||||||
|  |     horas_extras: List[DevengadoHoraExtra] | ||||||
|  |      | ||||||
|  |     def apply(self, fragment): | ||||||
|  |         hora_extra_xml = fragment.fragment('./HRNs') | ||||||
|  |         for hora_extra in self.horas_extras: | ||||||
|  |             hora_extra.apply('./HRN', hora_extra_xml) | ||||||
|  |  | ||||||
|  | @dataclass | ||||||
|  | class DevengadoHorasExtrasDiariasDominicalesYFestivos(Devengado): | ||||||
|  |     horas_extras: List[DevengadoHoraExtra] | ||||||
|  |      | ||||||
|  |     def apply(self, fragment): | ||||||
|  |         hora_extra_xml = fragment.fragment('./HEDDFs') | ||||||
|  |         for hora_extra in self.horas_extras: | ||||||
|  |             hora_extra.apply('./HEDDF', hora_extra_xml) | ||||||
|  |  | ||||||
|  | @dataclass | ||||||
|  | class DevengadoHorasRecargoDiariasDominicalesYFestivos(Devengado): | ||||||
|  |     horas_extras: List[DevengadoHoraExtra] | ||||||
|  |      | ||||||
|  |     def apply(self, fragment): | ||||||
|  |         hora_extra_xml = fragment.fragment('./HRDDFs') | ||||||
|  |         for hora_extra in self.horas_extras: | ||||||
|  |             hora_extra.apply('./HRDDF', hora_extra_xml) | ||||||
|  |  | ||||||
|  | @dataclass | ||||||
|  | class DevengadoHorasExtrasNocturnasDominicalesYFestivos(Devengado): | ||||||
|  |     horas_extras: List[DevengadoHoraExtra] | ||||||
|  |      | ||||||
|  |     def apply(self, fragment): | ||||||
|  |         hora_extra_xml = fragment.fragment('./HENDFs') | ||||||
|  |         for hora_extra in self.horas_extras: | ||||||
|  |             hora_extra.apply('./HENDF', hora_extra_xml) | ||||||
|  |  | ||||||
|  | @dataclass | ||||||
|  | class DevengadoHorasRecargoNocturnoDominicalesYFestivos(Devengado): | ||||||
|  |     horas_extras: List[DevengadoHoraExtra] | ||||||
|  |      | ||||||
|  |     def apply(self, fragment): | ||||||
|  |         hora_extra_xml = fragment.fragment('./HRNDFs') | ||||||
|  |         for hora_extra in self.horas_extras: | ||||||
|  |             hora_extra.apply('./HRNDF', hora_extra_xml) | ||||||
							
								
								
									
										21
									
								
								facho/fe/nomina/devengado/transporte.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								facho/fe/nomina/devengado/transporte.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,21 @@ | |||||||
|  | from dataclasses import dataclass | ||||||
|  |  | ||||||
|  | from ..amount import Amount | ||||||
|  | from .devengado import Devengado | ||||||
|  |  | ||||||
|  | @dataclass | ||||||
|  | class DevengadoTransporte(Devengado): | ||||||
|  |     auxilio_transporte: Amount = None | ||||||
|  |     viatico_manutencion: Amount = None | ||||||
|  |     viatico_manutencion_no_salarial: Amount = None | ||||||
|  |  | ||||||
|  |     def apply(self, fragment): | ||||||
|  |         fragment.set_element('./Transporte', None, | ||||||
|  |                              append_ = True, | ||||||
|  |                              # NIE071 | ||||||
|  |                              AuxilioTransporte = self.auxilio_transporte, | ||||||
|  |                              # NIE072 | ||||||
|  |                              ViaticoManuAlojS = self.viatico_manutencion, | ||||||
|  |                              # NIE073 | ||||||
|  |                              ViaticoManuAlojNS = self.viatico_manutencion_no_salarial | ||||||
|  |                              ) | ||||||
							
								
								
									
										35
									
								
								facho/fe/nomina/empleador/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								facho/fe/nomina/empleador/__init__.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,35 @@ | |||||||
|  | from dataclasses import dataclass | ||||||
|  |  | ||||||
|  | from ..pais import Pais | ||||||
|  | from ..departamento import Departamento | ||||||
|  | from ..municipio import Municipio | ||||||
|  |  | ||||||
|  | @dataclass | ||||||
|  | class Empleador: | ||||||
|  |     razon_social: str | ||||||
|  |     nit: str | ||||||
|  |     dv: str | ||||||
|  |     pais: Pais | ||||||
|  |     departamento: Departamento | ||||||
|  |     municipio: Municipio | ||||||
|  |     direccion: str | ||||||
|  |  | ||||||
|  |     def apply(self, fragment): | ||||||
|  |         fragment.set_attributes('./Empleador', | ||||||
|  |                                 # NIE033 | ||||||
|  |                                 NIT = self.nit, | ||||||
|  |                                 # NIE034 | ||||||
|  |                                 DV = self.dv, | ||||||
|  |                                 # NIE035 | ||||||
|  |                                 Pais = self.pais.code, | ||||||
|  |                                 # NIE036 | ||||||
|  |                                 DepartamentoEstado = self.departamento.code, | ||||||
|  |                                 # NIE037 | ||||||
|  |                                 MunicipioCiudad = self.municipio.code, | ||||||
|  |                                 # NIE038 | ||||||
|  |                                 Direccion = self.direccion, | ||||||
|  |  | ||||||
|  |                                 RazonSocial=self.razon_social | ||||||
|  |                                 ) | ||||||
|  |  | ||||||
|  |  | ||||||
							
								
								
									
										2
									
								
								facho/fe/nomina/exception.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								facho/fe/nomina/exception.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,2 @@ | |||||||
|  | class DIANNominaIndividualError(Exception): | ||||||
|  |     pass | ||||||
							
								
								
									
										155
									
								
								facho/fe/nomina/hablitacion.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										155
									
								
								facho/fe/nomina/hablitacion.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,155 @@ | |||||||
|  | from dataclasses import dataclass | ||||||
|  | import datetime | ||||||
|  |  | ||||||
|  | from facho import fe | ||||||
|  |  | ||||||
|  | class Habilitacion: | ||||||
|  |  | ||||||
|  |     @dataclass | ||||||
|  |     class Metadata: | ||||||
|  |         software_pin: str | ||||||
|  |         software_id: str | ||||||
|  |         nit: str | ||||||
|  |         dv: str | ||||||
|  |  | ||||||
|  |     def __init__(self, metadata): | ||||||
|  |         self.metadata = metadata | ||||||
|  |  | ||||||
|  |     def generar(self, zipname, fecha): | ||||||
|  |         nominas = [] | ||||||
|  |         dianzip = fe.DianZIP(open(zipname, 'w')) | ||||||
|  |  | ||||||
|  |         fechabase = datetime.datetime.now() | ||||||
|  |         consecutivo = 0 | ||||||
|  |         for _ in range(1, 11): | ||||||
|  |             consecutivo += 1 | ||||||
|  |             fechabase += datetime.timedelta(days=1) | ||||||
|  |             nomina = self._crear_nomina_individual() | ||||||
|  |  | ||||||
|  |             # pag 96 | ||||||
|  |             nombre = "nie%010d%s%08x.xml" % (int(self.nit), fecha.strftime('%s'), consecutivo) | ||||||
|  |          | ||||||
|  |     def _crear_nomina_individual_reemplazar(self, nomina, fechabase): | ||||||
|  |         metadata = self.metadata | ||||||
|  |  | ||||||
|  |         fecha = fechabase.strftime('%Y-%m-%d') | ||||||
|  |  | ||||||
|  |         nomina_ajuste = fe.nomina.DIANNominaIndividualDeAjuste.Reemplazar() | ||||||
|  |         self._poblar_nomina(nomina_ajuste, metadata, fecha, prefijo='R') | ||||||
|  |         informacion_general = nomina.informacion_general() | ||||||
|  |          | ||||||
|  |          | ||||||
|  |     def _poblar_nomina(self, nomina, metadata, fecha, prefijo='N', consecutivo='0001'): | ||||||
|  |         nomina.asignar_fecha_pago(fecha) | ||||||
|  |  | ||||||
|  |         nomina.asignar_metadata(fe.nomina.Metadata( | ||||||
|  |             secuencia=fe.nomina.NumeroSecuencia( | ||||||
|  |                 prefijo=prefijo, | ||||||
|  |                 consecutivo=consecutivo | ||||||
|  |             ), | ||||||
|  |             lugar_generacion=fe.nomina.Lugar( | ||||||
|  |                 pais = fe.nomina.Pais( | ||||||
|  |                     code = 'CO' | ||||||
|  |                 ), | ||||||
|  |                 departamento = fe.nomina.Departamento( | ||||||
|  |                     code = '05' | ||||||
|  |                 ), | ||||||
|  |                 municipio = fe.nomina.Municipio( | ||||||
|  |                     code = '05001' | ||||||
|  |                 ), | ||||||
|  |             ), | ||||||
|  |             proveedor=fe.nomina.Proveedor( | ||||||
|  |                 nit=metadata.nit, | ||||||
|  |                 dv=metadata.dv, | ||||||
|  |                 software_id=metadata.software_id, | ||||||
|  |                 software_pin=metadata.software_pin | ||||||
|  |             ) | ||||||
|  |         )) | ||||||
|  |  | ||||||
|  |         nomina.asignar_periodo(fe.nomina.Periodo( | ||||||
|  |             fecha_ingreso=fecha, | ||||||
|  |             fecha_liquidacion_inicio=fecha, | ||||||
|  |             fecha_liquidacion_fin=fecha, | ||||||
|  |             fecha_generacion=fecha, | ||||||
|  |         )) | ||||||
|  |          | ||||||
|  |         nomina.asignar_informacion_general(fe.nomina.InformacionGeneral( | ||||||
|  |             fecha_generacion = fecha, | ||||||
|  |             hora_generacion = '20:09:00-05:00', | ||||||
|  |             tipo_ambiente = fe.nomina.InformacionGeneral.AMBIENTE_PRUEBAS, | ||||||
|  |             software_pin = metadata.software_pin, | ||||||
|  |             periodo_nomina = fe.nomina.PeriodoNomina(code='1'), | ||||||
|  |             tipo_moneda = fe.nomina.TipoMoneda(code='COP') | ||||||
|  |         )) | ||||||
|  |  | ||||||
|  |         nomina.asignar_pago(fe.nomina.Pago( | ||||||
|  |             forma=fe.nomina.FormaPago( | ||||||
|  |                 code='1', | ||||||
|  |             ), | ||||||
|  |             metodo=fe.nomina.MetodoPago( | ||||||
|  |                 code='10' | ||||||
|  |             ) | ||||||
|  |         )) | ||||||
|  |         nomina.asignar_empleador(fe.nomina.Empleador( | ||||||
|  |             nit = metadata.nit, | ||||||
|  |             dv = '0', | ||||||
|  |             pais = fe.nomina.Pais( | ||||||
|  |                 code = 'CO' | ||||||
|  |             ), | ||||||
|  |             departamento = fe.nomina.Departamento( | ||||||
|  |                 code = '05' | ||||||
|  |             ), | ||||||
|  |             municipio = fe.nomina.Municipio( | ||||||
|  |                 code = '05001' | ||||||
|  |             ), | ||||||
|  |             direccion = 'calle etrivial' | ||||||
|  |         )) | ||||||
|  |  | ||||||
|  |         nomina.asignar_trabajador(fe.nomina.Trabajador( | ||||||
|  |             tipo_contrato = fe.nomina.TipoContrato( | ||||||
|  |                 code = '1' | ||||||
|  |             ), | ||||||
|  |             alto_riesgo = False, | ||||||
|  |             tipo_documento = fe.nomina.TipoDocumento( | ||||||
|  |                 code = '11' | ||||||
|  |             ), | ||||||
|  |             primer_apellido = 'gnu', | ||||||
|  |             segundo_apellido = 'emacs', | ||||||
|  |             primer_nombre = 'facho', | ||||||
|  |             lugar_trabajo = fe.nomina.LugarTrabajo( | ||||||
|  |                 pais = fe.nomina.Pais(code='CO'), | ||||||
|  |                 departamento = fe.nomina.Departamento(code='05'), | ||||||
|  |                 municipio = fe.nomina.Municipio(code='05001'), | ||||||
|  |                 direccion = 'calle facho' | ||||||
|  |             ), | ||||||
|  |             numero_documento = metadata.nit, | ||||||
|  |             tipo = fe.nomina.TipoTrabajador( | ||||||
|  |                 code = '01' | ||||||
|  |             ), | ||||||
|  |             salario_integral = True, | ||||||
|  |             sueldo = fe.nomina.Amount(1_500_000) | ||||||
|  |         )) | ||||||
|  |          | ||||||
|  |         nomina.adicionar_devengado(fe.nomina.DevengadoBasico( | ||||||
|  |             dias_trabajados = 60, | ||||||
|  |             sueldo_trabajado = fe.nomina.Amount(3_500_000) | ||||||
|  |         )) | ||||||
|  |  | ||||||
|  |         nomina.adicionar_deduccion(fe.nomina.DeduccionSalud( | ||||||
|  |             porcentaje = fe.nomina.Amount(19), | ||||||
|  |             deduccion = fe.nomina.Amount(1_000_000) | ||||||
|  |         )) | ||||||
|  |  | ||||||
|  |         nomina.adicionar_deduccion(fe.nomina.DeduccionFondoPension( | ||||||
|  |             porcentaje=fe.nomina.Amount(1), | ||||||
|  |             deduccion=fe.nomina.Amount(10) | ||||||
|  |         )) | ||||||
|  |  | ||||||
|  |     def _crear_nomina_individual(self, fechabase): | ||||||
|  |         metadata = self.metadata | ||||||
|  |  | ||||||
|  |         fecha = fechabase.strftime('%Y-%m-%d') | ||||||
|  |  | ||||||
|  |         nomina = fe.nomina.DIANNominaIndividual() | ||||||
|  |         self._poblar_nomina(nomina, metadata, fecha) | ||||||
|  |                  | ||||||
							
								
								
									
										25
									
								
								facho/fe/nomina/lugar.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								facho/fe/nomina/lugar.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,25 @@ | |||||||
|  | from dataclasses import dataclass | ||||||
|  |  | ||||||
|  | from .pais import Pais | ||||||
|  | from .departamento import Departamento | ||||||
|  | from .municipio import Municipio | ||||||
|  | from facho.fe.data.dian import codelist | ||||||
|  |  | ||||||
|  | @dataclass | ||||||
|  | class Lugar: | ||||||
|  |     pais: Pais | ||||||
|  |     departamento: Departamento | ||||||
|  |     municipio: Municipio | ||||||
|  |     idioma: str = 'es' | ||||||
|  |  | ||||||
|  |     def __post_init__(self): | ||||||
|  |         if self.idioma not in codelist.IdiomaISO6391: | ||||||
|  |             raise ValueError("idioma [%s] not found" % (self.code)) | ||||||
|  |         codelist.IdiomaISO6391[self.idioma]['iso-639-1'] | ||||||
|  |  | ||||||
|  |     def apply(self, fragment, root): | ||||||
|  |         fragment.set_attributes(root, | ||||||
|  |                                 Pais=self.pais.code, | ||||||
|  |                                 DepartamentoEstado=self.departamento.code, | ||||||
|  |                                 MunicipioCiudad=self.municipio.code, | ||||||
|  |                                 Idioma=self.idioma) | ||||||
							
								
								
									
										5
									
								
								facho/fe/nomina/municipio.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								facho/fe/nomina/municipio.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,5 @@ | |||||||
|  | from .. import form | ||||||
|  |  | ||||||
|  | class Municipio(form.City): | ||||||
|  |     pass | ||||||
|  |  | ||||||
							
								
								
									
										16
									
								
								facho/fe/nomina/pago/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								facho/fe/nomina/pago/__init__.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,16 @@ | |||||||
|  | from dataclasses import dataclass | ||||||
|  |  | ||||||
|  | from .forma_pago import FormaPago | ||||||
|  | from .metodo_pago import MetodoPago | ||||||
|  |  | ||||||
|  | @dataclass | ||||||
|  | class Pago: | ||||||
|  |     forma: FormaPago | ||||||
|  |     metodo: MetodoPago | ||||||
|  |  | ||||||
|  |     def apply(self, fragment): | ||||||
|  |         fragment.set_attributes('./Pago', | ||||||
|  |                                 # NIE064 | ||||||
|  |                                 Forma = self.forma.code, | ||||||
|  |                                 # NIE065 | ||||||
|  |                                 Metodo = self.metodo.code) | ||||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user