From 5d5cb03c625be74c6109e8871809ebf653e1c7af Mon Sep 17 00:00:00 2001 From: HanslettTheDev Date: Wed, 21 Jun 2023 12:29:00 +0100 Subject: [PATCH 01/13] bump: this commit is a copy of #113 by saliticus to change the signing method Signed-off-by: HanslettTheDev --- requirements.txt | 2 +- wsaa.py | 45 +++++++++++++++------------------------------ 2 files changed, 16 insertions(+), 31 deletions(-) diff --git a/requirements.txt b/requirements.txt index 58c97dbc4..94189e16f 100644 --- a/requirements.txt +++ b/requirements.txt @@ -3,7 +3,7 @@ httplib2==0.20.4; python_version > '3' pysimplesoap==1.08.14; python_version <= '2.7' git+https://github.com/pysimplesoap/pysimplesoap.git@py311#pysimplesoap; python_version > '3' cryptography==3.3.2; python_version <= '2.7' -cryptography==3.4.7; python_version > '3' +cryptography==39.0.2; python_version > '3' fpdf>=1.7.2 dbf>=0.88.019 Pillow>=2.0.0 diff --git a/wsaa.py b/wsaa.py index 30bf49d95..ea945603e 100644 --- a/wsaa.py +++ b/wsaa.py @@ -54,6 +54,8 @@ from cryptography.hazmat.primitives import serialization from cryptography.hazmat.primitives.asymmetric import rsa from cryptography.hazmat.bindings.openssl.binding import Binding + from cryptography.hazmat.primitives.serialization import pkcs7 + except ImportError: ex = exception_info() @@ -116,7 +118,6 @@ def sign_tra(tra, cert=CERT, privatekey=PRIVATEKEY, passphrase=""): _lib = Binding.lib _ffi = Binding.ffi # Crear un buffer desde el texto - bio_in = _lib.BIO_new_mem_buf(tra, len(tra)) # Leer privatekey y cert if not privatekey.startswith(b"-----BEGIN RSA PRIVATE KEY-----"): @@ -136,42 +137,26 @@ def sign_tra(tra, cert=CERT, privatekey=PRIVATEKEY, passphrase=""): cert = open(cert).read() if isinstance(cert, str): cert = cert.encode("utf-8") - cert = x509.load_pem_x509_certificate(cert, default_backend()) - - try: - # Firmar el texto (tra) usando cryptography (openssl bindings para python) - p7 = _lib.PKCS7_sign( - cert._x509, private_key._evp_pkey, _ffi.NULL, bio_in, 0 - ) - finally: - # Liberar memoria asignada - _lib.BIO_free(bio_in) - # Se crea un buffer nuevo porque la firma lo consume - bio_in = _lib.BIO_new_mem_buf(tra, len(tra)) - try: - # Crear buffer de salida - bio_out = _lib.BIO_new(_lib.BIO_s_mem()) - try: - # Instanciar un SMIME - _lib.SMIME_write_PKCS7(bio_out, p7, bio_in, 0) - - # Tomar datos para la salida - result_buffer = _ffi.new("char**") - buffer_length = _lib.BIO_get_mem_data(bio_out, result_buffer) - output = _ffi.buffer(result_buffer[0], buffer_length)[:] - finally: - _lib.BIO_free(bio_out) - finally: - _lib.BIO_free(bio_in) + cert = x509.load_pem_x509_certificate(cert) + + p7 = pkcs7.PKCS7SignatureBuilder().set_data( + tra + ).add_signer( + cert, private_key, hashes.SHA256() + ).sign( + serialization.Encoding.SMIME, [pkcs7.PKCS7Options.DetachedSignature] + ) # Generar p7 en formato mail y recortar headers - msg = email.message_from_string(output.decode("utf8")) + msg = email.message_from_string(p7.decode("utf8")) for part in msg.walk(): filename = part.get_filename() - if filename == "smime.p7m": + if filename == "smime.p7s": # Es la parte firmada? # Devolver CMS return part.get_payload(decode=False) + else: + raise RuntimeError("Part not found") else: # Firmar el texto (tra) usando OPENSSL directamente try: From c145a4d73f3fd994723086cbda101775a648e6e5 Mon Sep 17 00:00:00 2001 From: HanslettTheDev Date: Wed, 21 Jun 2023 12:38:05 +0100 Subject: [PATCH 02/13] feat: backward compatible signing for python2.7 Signed-off-by: HanslettTheDev --- wsaa.py | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/wsaa.py b/wsaa.py index ea945603e..d87ebcda5 100644 --- a/wsaa.py +++ b/wsaa.py @@ -139,6 +139,42 @@ def sign_tra(tra, cert=CERT, privatekey=PRIVATEKEY, passphrase=""): cert = cert.encode("utf-8") cert = x509.load_pem_x509_certificate(cert) + if sys.version.split(" ")[0][0:3] == "2.7": + try: + # Firmar el texto (tra) usando cryptography (openssl bindings para python) + p7 = _lib.PKCS7_sign( + cert._x509, private_key._evp_pkey, _ffi.NULL, bio_in, 0 + ) + finally: + # Liberar memoria asignada + _lib.BIO_free(bio_in) + # Se crea un buffer nuevo porque la firma lo consume + bio_in = _lib.BIO_new_mem_buf(tra, len(tra)) + try: + # Crear buffer de salida + bio_out = _lib.BIO_new(_lib.BIO_s_mem()) + try: + # Instanciar un SMIME + _lib.SMIME_write_PKCS7(bio_out, p7, bio_in, 0) + + # Tomar datos para la salida + result_buffer = _ffi.new("char**") + buffer_length = _lib.BIO_get_mem_data(bio_out, result_buffer) + output = _ffi.buffer(result_buffer[0], buffer_length)[:] + finally: + _lib.BIO_free(bio_out) + finally: + _lib.BIO_free(bio_in) + + # Generar p7 en formato mail y recortar headers + msg = email.message_from_string(output.decode("utf8")) + for part in msg.walk(): + filename = part.get_filename() + if filename == "smime.p7m": + # Es la parte firmada? + # Devolver CMS + return part.get_payload(decode=False) + p7 = pkcs7.PKCS7SignatureBuilder().set_data( tra ).add_signer( From a686dd553d3e0a7345ee5fc73e97ec415d83941f Mon Sep 17 00:00:00 2001 From: HanslettTheDev Date: Wed, 21 Jun 2023 12:49:03 +0100 Subject: [PATCH 03/13] bump: cryptography update 39.0.2 -> 41.0.1 Signed-off-by: HanslettTheDev --- requirements.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/requirements.txt b/requirements.txt index 94189e16f..d48f7e6c9 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,9 +1,9 @@ httplib2==0.9.2; python_version <= '2.7' httplib2==0.20.4; python_version > '3' pysimplesoap==1.08.14; python_version <= '2.7' -git+https://github.com/pysimplesoap/pysimplesoap.git@py311#pysimplesoap; python_version > '3' +git+https://github.com/pysimplesoap/pysimplesoap.git@py311#pysimplesoap ; python_version > '3' cryptography==3.3.2; python_version <= '2.7' -cryptography==39.0.2; python_version > '3' +cryptography==41.0.1; python_version > '3' fpdf>=1.7.2 dbf>=0.88.019 Pillow>=2.0.0 From b75e0d0fdb23b449bbf0adadc4860ee9af6df086 Mon Sep 17 00:00:00 2001 From: HanslettTheDev Date: Tue, 27 Jun 2023 14:14:47 +0100 Subject: [PATCH 04/13] restart actions Signed-off-by: HanslettTheDev --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index d48f7e6c9..f1d01b9d9 100644 --- a/requirements.txt +++ b/requirements.txt @@ -10,4 +10,4 @@ Pillow>=2.0.0 tabulate==0.8.5 certifi>=2020.4.5.1 qrcode==6.1 -future==0.18.2 +future==0.18.2 \ No newline at end of file From 62a94a3591a3c21263205419b19199122c1e68cf Mon Sep 17 00:00:00 2001 From: HanslettTheDev Date: Wed, 28 Jun 2023 13:10:18 +0100 Subject: [PATCH 05/13] bug: added a bug to find an existing issue Signed-off-by: HanslettTheDev --- wsaa.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/wsaa.py b/wsaa.py index d87ebcda5..ee506ad34 100644 --- a/wsaa.py +++ b/wsaa.py @@ -175,13 +175,13 @@ def sign_tra(tra, cert=CERT, privatekey=PRIVATEKEY, passphrase=""): # Devolver CMS return part.get_payload(decode=False) - p7 = pkcs7.PKCS7SignatureBuilder().set_data( - tra - ).add_signer( - cert, private_key, hashes.SHA256() - ).sign( - serialization.Encoding.SMIME, [pkcs7.PKCS7Options.DetachedSignature] - ) + # p7 = pkcs7.PKCS7SignatureBuilder().set_data( + # tra + # ).add_signer( + # cert, private_key, hashes.SHA256() + # ).sign( + # serialization.Encoding.SMIME, [pkcs7.PKCS7Options.DetachedSignature] + # ) # Generar p7 en formato mail y recortar headers msg = email.message_from_string(p7.decode("utf8")) From 3295e1a36b1ddbf2c5f0756afb97e291c9869580 Mon Sep 17 00:00:00 2001 From: HanslettTheDev Date: Wed, 28 Jun 2023 13:15:03 +0100 Subject: [PATCH 06/13] undo-bug: removed the bug Signed-off-by: HanslettTheDev --- wsaa.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/wsaa.py b/wsaa.py index ee506ad34..d87ebcda5 100644 --- a/wsaa.py +++ b/wsaa.py @@ -175,13 +175,13 @@ def sign_tra(tra, cert=CERT, privatekey=PRIVATEKEY, passphrase=""): # Devolver CMS return part.get_payload(decode=False) - # p7 = pkcs7.PKCS7SignatureBuilder().set_data( - # tra - # ).add_signer( - # cert, private_key, hashes.SHA256() - # ).sign( - # serialization.Encoding.SMIME, [pkcs7.PKCS7Options.DetachedSignature] - # ) + p7 = pkcs7.PKCS7SignatureBuilder().set_data( + tra + ).add_signer( + cert, private_key, hashes.SHA256() + ).sign( + serialization.Encoding.SMIME, [pkcs7.PKCS7Options.DetachedSignature] + ) # Generar p7 en formato mail y recortar headers msg = email.message_from_string(p7.decode("utf8")) From 6262822fd68bef1d4aa64870087d99e25e93a75c Mon Sep 17 00:00:00 2001 From: HanslettTheDev Date: Wed, 28 Jun 2023 13:22:01 +0100 Subject: [PATCH 07/13] fix: updated the wsaa.py file Signed-off-by: HanslettTheDev --- wsaa.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/wsaa.py b/wsaa.py index d87ebcda5..2a0ab462f 100644 --- a/wsaa.py +++ b/wsaa.py @@ -56,7 +56,6 @@ from cryptography.hazmat.bindings.openssl.binding import Binding from cryptography.hazmat.primitives.serialization import pkcs7 - except ImportError: ex = exception_info() warnings.warn("No es posible importar cryptography (OpenSSL)") @@ -118,6 +117,8 @@ def sign_tra(tra, cert=CERT, privatekey=PRIVATEKEY, passphrase=""): _lib = Binding.lib _ffi = Binding.ffi # Crear un buffer desde el texto + # Se crea un buffer nuevo porque la firma lo consume + bio_in = _lib.BIO_new_mem_buf(tra, len(tra)) # Leer privatekey y cert if not privatekey.startswith(b"-----BEGIN RSA PRIVATE KEY-----"): @@ -176,11 +177,11 @@ def sign_tra(tra, cert=CERT, privatekey=PRIVATEKEY, passphrase=""): return part.get_payload(decode=False) p7 = pkcs7.PKCS7SignatureBuilder().set_data( - tra + tra ).add_signer( cert, private_key, hashes.SHA256() ).sign( - serialization.Encoding.SMIME, [pkcs7.PKCS7Options.DetachedSignature] + serialization.Encoding.SMIME, [pkcs7.PKCS7Options.Binary] ) # Generar p7 en formato mail y recortar headers From 126eaa057f62f3f8239bfb50ad71ec061028ce97 Mon Sep 17 00:00:00 2001 From: HanslettTheDev Date: Wed, 21 Jun 2023 12:49:03 +0100 Subject: [PATCH 08/13] bump: cryptography update 39.0.2 -> 41.0.1 Signed-off-by: HanslettTheDev restart actions Signed-off-by: HanslettTheDev bug: added a bug to find an existing issue Signed-off-by: HanslettTheDev undo-bug: removed the bug Signed-off-by: HanslettTheDev fix: updated the wsaa.py file Signed-off-by: HanslettTheDev bump: cryptography update 39.0.2 -> 41.0.1 --- requirements.txt | 6 +++--- wsaa.py | 7 ++++--- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/requirements.txt b/requirements.txt index 94189e16f..f1d01b9d9 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,13 +1,13 @@ httplib2==0.9.2; python_version <= '2.7' httplib2==0.20.4; python_version > '3' pysimplesoap==1.08.14; python_version <= '2.7' -git+https://github.com/pysimplesoap/pysimplesoap.git@py311#pysimplesoap; python_version > '3' +git+https://github.com/pysimplesoap/pysimplesoap.git@py311#pysimplesoap ; python_version > '3' cryptography==3.3.2; python_version <= '2.7' -cryptography==39.0.2; python_version > '3' +cryptography==41.0.1; python_version > '3' fpdf>=1.7.2 dbf>=0.88.019 Pillow>=2.0.0 tabulate==0.8.5 certifi>=2020.4.5.1 qrcode==6.1 -future==0.18.2 +future==0.18.2 \ No newline at end of file diff --git a/wsaa.py b/wsaa.py index d87ebcda5..2a0ab462f 100644 --- a/wsaa.py +++ b/wsaa.py @@ -56,7 +56,6 @@ from cryptography.hazmat.bindings.openssl.binding import Binding from cryptography.hazmat.primitives.serialization import pkcs7 - except ImportError: ex = exception_info() warnings.warn("No es posible importar cryptography (OpenSSL)") @@ -118,6 +117,8 @@ def sign_tra(tra, cert=CERT, privatekey=PRIVATEKEY, passphrase=""): _lib = Binding.lib _ffi = Binding.ffi # Crear un buffer desde el texto + # Se crea un buffer nuevo porque la firma lo consume + bio_in = _lib.BIO_new_mem_buf(tra, len(tra)) # Leer privatekey y cert if not privatekey.startswith(b"-----BEGIN RSA PRIVATE KEY-----"): @@ -176,11 +177,11 @@ def sign_tra(tra, cert=CERT, privatekey=PRIVATEKEY, passphrase=""): return part.get_payload(decode=False) p7 = pkcs7.PKCS7SignatureBuilder().set_data( - tra + tra ).add_signer( cert, private_key, hashes.SHA256() ).sign( - serialization.Encoding.SMIME, [pkcs7.PKCS7Options.DetachedSignature] + serialization.Encoding.SMIME, [pkcs7.PKCS7Options.Binary] ) # Generar p7 en formato mail y recortar headers From f890ee645bad1c6498cf82452b24f47ee07fc3b9 Mon Sep 17 00:00:00 2001 From: Hanslett <64011386+HanslettTheDev@users.noreply.github.com> Date: Fri, 30 Jun 2023 08:07:24 +0100 Subject: [PATCH 09/13] refactor: used the sys module to check for the major version Co-authored-by: Nico Sandoval <49107024+NicolasSandoval@users.noreply.github.com> --- wsaa.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wsaa.py b/wsaa.py index 2a0ab462f..5f880cf85 100644 --- a/wsaa.py +++ b/wsaa.py @@ -140,7 +140,7 @@ def sign_tra(tra, cert=CERT, privatekey=PRIVATEKEY, passphrase=""): cert = cert.encode("utf-8") cert = x509.load_pem_x509_certificate(cert) - if sys.version.split(" ")[0][0:3] == "2.7": + if sys.version_info.major == 2: try: # Firmar el texto (tra) usando cryptography (openssl bindings para python) p7 = _lib.PKCS7_sign( From d676cac9e7e661c2d7c0fc521b366cda65b3be0a Mon Sep 17 00:00:00 2001 From: HanslettTheDev Date: Mon, 3 Jul 2023 07:01:16 +0100 Subject: [PATCH 10/13] refactor: removed repeated code in signing certificates Signed-off-by: HanslettTheDev --- wsaa.py | 40 ++++++++++++++++------------------------ 1 file changed, 16 insertions(+), 24 deletions(-) diff --git a/wsaa.py b/wsaa.py index 5f880cf85..894f93972 100644 --- a/wsaa.py +++ b/wsaa.py @@ -114,12 +114,6 @@ def sign_tra(tra, cert=CERT, privatekey=PRIVATEKEY, passphrase=""): tra = tra.encode("utf8") if Binding: - _lib = Binding.lib - _ffi = Binding.ffi - # Crear un buffer desde el texto - # Se crea un buffer nuevo porque la firma lo consume - bio_in = _lib.BIO_new_mem_buf(tra, len(tra)) - # Leer privatekey y cert if not privatekey.startswith(b"-----BEGIN RSA PRIVATE KEY-----"): privatekey = open(privatekey).read() @@ -141,6 +135,12 @@ def sign_tra(tra, cert=CERT, privatekey=PRIVATEKEY, passphrase=""): cert = x509.load_pem_x509_certificate(cert) if sys.version_info.major == 2: + _lib = Binding.lib + _ffi = Binding.ffi + # Crear un buffer desde el texto + # Se crea un buffer nuevo porque la firma lo consume + bio_in = _lib.BIO_new_mem_buf(tra, len(tra)) + try: # Firmar el texto (tra) usando cryptography (openssl bindings para python) p7 = _lib.PKCS7_sign( @@ -161,34 +161,26 @@ def sign_tra(tra, cert=CERT, privatekey=PRIVATEKEY, passphrase=""): # Tomar datos para la salida result_buffer = _ffi.new("char**") buffer_length = _lib.BIO_get_mem_data(bio_out, result_buffer) - output = _ffi.buffer(result_buffer[0], buffer_length)[:] + p7 = _ffi.buffer(result_buffer[0], buffer_length)[:] finally: _lib.BIO_free(bio_out) finally: _lib.BIO_free(bio_in) - # Generar p7 en formato mail y recortar headers - msg = email.message_from_string(output.decode("utf8")) - for part in msg.walk(): - filename = part.get_filename() - if filename == "smime.p7m": - # Es la parte firmada? - # Devolver CMS - return part.get_payload(decode=False) - - p7 = pkcs7.PKCS7SignatureBuilder().set_data( - tra - ).add_signer( - cert, private_key, hashes.SHA256() - ).sign( - serialization.Encoding.SMIME, [pkcs7.PKCS7Options.Binary] - ) + else: + p7 = pkcs7.PKCS7SignatureBuilder().set_data( + tra + ).add_signer( + cert, private_key, hashes.SHA256() + ).sign( + serialization.Encoding.SMIME, [pkcs7.PKCS7Options.Binary] + ) # Generar p7 en formato mail y recortar headers msg = email.message_from_string(p7.decode("utf8")) for part in msg.walk(): filename = part.get_filename() - if filename == "smime.p7s": + if filename and filename.startswith("smime.p7"): # Es la parte firmada? # Devolver CMS return part.get_payload(decode=False) From b4df18d48047a3960900ca406ae0fc311d72d930 Mon Sep 17 00:00:00 2001 From: HanslettTheDev Date: Wed, 21 Jun 2023 12:49:03 +0100 Subject: [PATCH 11/13] bump: cryptography update 39.0.2 -> 41.0.1 Signed-off-by: HanslettTheDev From f9e0acf658d738b1896e83a3188dcc16392a0f23 Mon Sep 17 00:00:00 2001 From: HanslettTheDev Date: Mon, 3 Jul 2023 13:05:09 +0100 Subject: [PATCH 12/13] bump: cryptography update 39.0.2 -> 41.0.1 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: HanslettTheDev restart actions Signed-off-by: HanslettTheDev bug: added a bug to find an existing issue Signed-off-by: HanslettTheDev undo-bug: removed the bug Signed-off-by: HanslettTheDev fix: updated the wsaa.py file Signed-off-by: HanslettTheDev refactor: used the sys module to check for the major version Co-authored-by: Nico Sandoval <49107024+NicolasSandoval@users.noreply.github.com> Only run release on original repository, not forks This avoids errors with dependabot PR: ``` Run marvinpinto/action-automatic-releases@latest Initializing the Automatic Releases action Determining release tags Retrieving commit history Generating changelog Generating release tag Attempting to create or update release tag "beta" Could not create new tag "refs/tags/beta" (Resource not accessible by integration) therefore updating existing tag "tags/beta" Error: Resource not accessible by integration ``` Signed-off-by: Nicolás Sandoval Properly fix dependabot read-only token https://github.com/dependabot/dependabot-core/issues/3253 Signed-off-by: Nicolás Sandoval Bump future from 0.18.2 to 0.18.3 Bumps [future](https://github.com/PythonCharmers/python-future) from 0.18.2 to 0.18.3. - [Release notes](https://github.com/PythonCharmers/python-future/releases) - [Changelog](https://github.com/PythonCharmers/python-future/blob/master/docs/changelog.rst) - [Commits](https://github.com/PythonCharmers/python-future/compare/v0.18.2...v0.18.3) --- updated-dependencies: - dependency-name: future dependency-type: direct:production ... Signed-off-by: dependabot[bot] Signed-off-by: Nicolás Sandoval Cumulative updates f/ develop (python3 conversion) * 2to3 -w file.py * python -m black file.py * iconv -f iso-8859-1 -t utf-8 < file_new.py > file.py Signed-off-by: Nicolás Sandoval Update copyright and remove merge typo Signed-off-by: Nicolás Sandoval WSFEv1: update copyright Signed-off-by: Nicolás Sandoval WSFEv1: re-sync updates Signed-off-by: Nicolás Sandoval WSFEXv1: disable get parameters until UT updated Signed-off-by: Nicolás Sandoval Remove Python 2.7 deprecated GitHub Action Signed-off-by: Nicolás Sandoval refactor: removed repeated code in signing certificates Signed-off-by: HanslettTheDev --- .github/workflows/python-package.yml | 2 +- .github/workflows/windows-installer.yml | 1 + formatos/formato_xml.py | 7 ++ requirements.txt | 2 +- ws_sr_padron.py | 12 ++- wsaa.py | 43 ++++---- wsfev1.py | 55 ++++++----- wsfexv1.py | 75 ++++++++++++-- wslpg.py | 50 +++++----- wsmtx.py | 41 +++++--- wsremharina.py | 124 ++++++++++++++++++------ 11 files changed, 282 insertions(+), 130 deletions(-) diff --git a/.github/workflows/python-package.yml b/.github/workflows/python-package.yml index 10de0b00a..e8aada329 100644 --- a/.github/workflows/python-package.yml +++ b/.github/workflows/python-package.yml @@ -16,7 +16,7 @@ jobs: strategy: fail-fast: false matrix: - python-version: [2.7, 3.9, 3.11] + python-version: [3.9, 3.11] steps: - uses: actions/checkout@v2 diff --git a/.github/workflows/windows-installer.yml b/.github/workflows/windows-installer.yml index b16b5dcb1..dffb9fc7a 100644 --- a/.github/workflows/windows-installer.yml +++ b/.github/workflows/windows-installer.yml @@ -156,6 +156,7 @@ jobs: run: | cat dist-64/.env >> $GITHUB_ENV - uses: "marvinpinto/action-automatic-releases@latest" + if: github.actor != 'dependabot[bot]' with: repo_token: "${{ secrets.GITHUB_TOKEN }}" automatic_release_tag: ${{ (github.ref_name != 'main') && 'beta' || 'latest' }} diff --git a/formatos/formato_xml.py b/formatos/formato_xml.py index ae0abc332..4b8b74882 100644 --- a/formatos/formato_xml.py +++ b/formatos/formato_xml.py @@ -49,6 +49,7 @@ "numero_cotizacion": str, "numero_remito": str, "ape": str, + "permiso_existente": str, "incoterms": str, "detalleincoterms": str, "destinocmp": int, @@ -188,6 +189,12 @@ "fecha_serv_desde": "fechaservdesde", "fecha_serv_hasta": "fechaservhasta", "fecha_venc_pago": "fechavencpago", + "tipo_expo": "concepto", + "incoterms": "incoterms", + "incoterms_ds": "detalleincoterms", + "pais_dst_cmp": "destinocmp", + "idioma_cbte": "idioma", + "permiso_existente": "permiso_existente", "obs_generales": "otrosdatosgenerales", "obs_comerciales": "otrosdatoscomerciales", "resultado": "resultado", diff --git a/requirements.txt b/requirements.txt index f1d01b9d9..c65ebdda1 100644 --- a/requirements.txt +++ b/requirements.txt @@ -10,4 +10,4 @@ Pillow>=2.0.0 tabulate==0.8.5 certifi>=2020.4.5.1 qrcode==6.1 -future==0.18.2 \ No newline at end of file +future==0.18.3 \ No newline at end of file diff --git a/ws_sr_padron.py b/ws_sr_padron.py index d5f305461..9903e20e7 100644 --- a/ws_sr_padron.py +++ b/ws_sr_padron.py @@ -23,9 +23,9 @@ from builtins import next __author__ = "Mariano Reingart " -__copyright__ = "Copyright (C) 2017 Mariano Reingart" -__license__ = "GPL 3.0" -__version__ = "3.04e" +__copyright__ = "Copyright (C) 2017-2023 Mariano Reingart" +__license__ = "LGPL-3.0-or-later" +__version__ = "3.05a" import csv import datetime @@ -42,6 +42,7 @@ abrir_conf, norm, SoapFault, + safe_console, ) from configparser import SafeConfigParser from pyafipws.padron import TIPO_CLAVE, PROVINCIAS @@ -97,6 +98,7 @@ class WSSrPadronA4(BaseWS): "nro_doc", "tipo_persona", "estado", + "es_sucesion", "impuestos", "actividades", "direccion", @@ -125,6 +127,7 @@ def inicializar(self): self.tipo_persona = "" # FISICA o JURIDICA self.tipo_doc = self.nro_doc = 0 self.estado = "" # ACTIVO + self.es_sucesion = "" self.denominacion = "" self.direccion = self.localidad = self.provincia = self.cod_postal = "" self.domicilios = [] @@ -274,6 +277,7 @@ def Consultar(self, id_persona): self.nro_doc = data.get("idPersona") self.cuit = self.nro_doc self.estado = data.get("estadoClave") + self.es_sucesion = data.get("esSucesion") if not "razonSocial" in data: self.denominacion = ", ".join( [data.get("apellido", ""), data.get("nombre", "")] @@ -320,6 +324,7 @@ def main(): global CONFIG_FILE DEBUG = "--debug" in sys.argv + safe_console() if "--constancia" in sys.argv: padron = WSSrPadronA5() @@ -427,6 +432,7 @@ def main(): print("Denominacion:", padron.denominacion) print("Tipo:", padron.tipo_persona, padron.tipo_doc, padron.nro_doc) print("Estado:", padron.estado) + print("Es Sucesion:", padron.es_sucesion) print("Direccion:", padron.direccion) print("Localidad:", padron.localidad) print("Provincia:", padron.provincia) diff --git a/wsaa.py b/wsaa.py index 2a0ab462f..5ffe138bf 100644 --- a/wsaa.py +++ b/wsaa.py @@ -114,12 +114,6 @@ def sign_tra(tra, cert=CERT, privatekey=PRIVATEKEY, passphrase=""): tra = tra.encode("utf8") if Binding: - _lib = Binding.lib - _ffi = Binding.ffi - # Crear un buffer desde el texto - # Se crea un buffer nuevo porque la firma lo consume - bio_in = _lib.BIO_new_mem_buf(tra, len(tra)) - # Leer privatekey y cert if not privatekey.startswith(b"-----BEGIN RSA PRIVATE KEY-----"): privatekey = open(privatekey).read() @@ -140,7 +134,13 @@ def sign_tra(tra, cert=CERT, privatekey=PRIVATEKEY, passphrase=""): cert = cert.encode("utf-8") cert = x509.load_pem_x509_certificate(cert) - if sys.version.split(" ")[0][0:3] == "2.7": + if sys.version_info.major == 2: + _lib = Binding.lib + _ffi = Binding.ffi + # Crear un buffer desde el texto + # Se crea un buffer nuevo porque la firma lo consume + bio_in = _lib.BIO_new_mem_buf(tra, len(tra)) + try: # Firmar el texto (tra) usando cryptography (openssl bindings para python) p7 = _lib.PKCS7_sign( @@ -161,34 +161,27 @@ def sign_tra(tra, cert=CERT, privatekey=PRIVATEKEY, passphrase=""): # Tomar datos para la salida result_buffer = _ffi.new("char**") buffer_length = _lib.BIO_get_mem_data(bio_out, result_buffer) - output = _ffi.buffer(result_buffer[0], buffer_length)[:] + p7 = _ffi.buffer(result_buffer[0], buffer_length)[:] finally: _lib.BIO_free(bio_out) finally: _lib.BIO_free(bio_in) - # Generar p7 en formato mail y recortar headers - msg = email.message_from_string(output.decode("utf8")) - for part in msg.walk(): - filename = part.get_filename() - if filename == "smime.p7m": - # Es la parte firmada? - # Devolver CMS - return part.get_payload(decode=False) - - p7 = pkcs7.PKCS7SignatureBuilder().set_data( - tra - ).add_signer( - cert, private_key, hashes.SHA256() - ).sign( - serialization.Encoding.SMIME, [pkcs7.PKCS7Options.Binary] - ) + else: + p7 = pkcs7.PKCS7SignatureBuilder().set_data( + tra + ).add_signer( + cert, private_key, hashes.SHA256() + ).sign( + serialization.Encoding.SMIME, [pkcs7.PKCS7Options.Binary] + ) + # Generar p7 en formato mail y recortar headers msg = email.message_from_string(p7.decode("utf8")) for part in msg.walk(): filename = part.get_filename() - if filename == "smime.p7s": + if filename and filename.startswith("smime.p7"): # Es la parte firmada? # Devolver CMS return part.get_payload(decode=False) diff --git a/wsfev1.py b/wsfev1.py index abad6385c..034ec6665 100644 --- a/wsfev1.py +++ b/wsfev1.py @@ -29,9 +29,9 @@ from past.builtins import basestring __author__ = "Mariano Reingart " -__copyright__ = "Copyright (C) 2010-2021 Mariano Reingart" +__copyright__ = "Copyright (C) 2010-2023 Mariano Reingart" __license__ = "LGPL-3.0-or-later" -__version__ = "3.26a" +__version__ = "3.27c" import datetime import decimal @@ -140,9 +140,10 @@ class WSFEv1(BaseWS): _reg_class_spec_ = "pyafipws.wsfev1.WSFEv1" if TYPELIB: - _typelib_guid_ = '{8AE2BD1D-A216-4E98-95DB-24A11225EF67}' + _typelib_guid_ = "{8AE2BD1D-A216-4E98-95DB-24A11225EF67}" _typelib_version_ = 1, 26 - _com_interfaces_ = ['IWSFEv1'] + _com_interfaces_ = ["IWSFEv1"] + ##_reg_class_spec_ = "wsfev1.WSFEv1" # Variables globales para BaseWS: HOMO = HOMO @@ -329,8 +330,8 @@ def AgregarComprador(self, doc_tipo=80, doc_nro=0, porcentaje=100.00, **kwarg): def AgregarActividad(self, actividad_id=0, **kwarg): "Agrego actividad a una factura (interna)" - op = { 'actividad_id': actividad_id } - self.factura['actividades'].append(op) + act = {"actividad_id": actividad_id} + self.factura["actividades"].append(act) return True def ObtenerCampoFactura(self, *campos): @@ -381,9 +382,6 @@ def CAESolicitar(self): "FchServDesde": f.get("fecha_serv_desde"), "FchServHasta": f.get("fecha_serv_hasta"), "FchVtoPago": f.get("fecha_venc_pago"), - "FchServDesde": f.get("fecha_serv_desde"), - "FchServHasta": f.get("fecha_serv_hasta"), - "FchVtoPago": f["fecha_venc_pago"], "MonId": f["moneda_id"], "MonCotiz": f["moneda_ctz"], "PeriodoAsoc": { @@ -456,7 +454,7 @@ def CAESolicitar(self): "Actividades": [ { "Actividad": { - 'Id': actividad['actividad_id'], + "Id": actividad["actividad_id"], } } for actividad in f["actividades"] @@ -638,9 +636,9 @@ def CompConsultar(self, tipo_cbte, punto_vta, cbte_nro, reproceso=False): } copia = resultget.copy() # TODO: ordenar / convertir opcionales (por ahora no se verifican) - del verificaciones['Opcionales'] - if 'Opcionales' in copia: - del copia['Opcionales'] + del verificaciones["Opcionales"] + if "Opcionales" in copia: + del copia["Opcionales"] verifica(verificaciones, copia, difs) if difs: print("Diferencias:", difs) @@ -802,9 +800,6 @@ def CAESolicitarX(self): "FchServDesde": f.get("fecha_serv_desde"), "FchServHasta": f.get("fecha_serv_hasta"), "FchVtoPago": f.get("fecha_venc_pago"), - "FchServDesde": f.get("fecha_serv_desde"), - "FchServHasta": f.get("fecha_serv_hasta"), - "FchVtoPago": f["fecha_venc_pago"], "MonId": f["moneda_id"], "MonCotiz": f["moneda_ctz"], "PeriodoAsoc": { @@ -1034,9 +1029,6 @@ def CAEARegInformativo(self): "FchServDesde": f.get("fecha_serv_desde"), "FchServHasta": f.get("fecha_serv_hasta"), "FchVtoPago": f.get("fecha_venc_pago"), - "FchServDesde": f.get("fecha_serv_desde"), - "FchServHasta": f.get("fecha_serv_hasta"), - "FchVtoPago": f["fecha_venc_pago"], "MonId": f["moneda_id"], "MonCotiz": f["moneda_ctz"], "PeriodoAsoc": { @@ -1095,6 +1087,15 @@ def CAEARegInformativo(self): for opcional in f["opcionales"] ] or None, + "Actividades": [ + { + "Actividad": { + "Id": actividad["actividad_id"], + } + } + for actividad in f["actividades"] + ] + or None, "CAEA": f["caea"], "CbteFchHsGen": f.get("fecha_hs_gen"), } @@ -1301,13 +1302,15 @@ def ParamGetPtosVenta(self, sep="|"): @inicializar_y_capturar_excepciones def ParamGetActividades(self, sep="|"): - "Recuperador de valores referenciales de códigos de Actividades" + "Recuperador de valores referenciales de c�digos de Actividades" ret = self.client.FEParamGetActividades( - Auth={'Token': self.Token, 'Sign': self.Sign, 'Cuit': self.Cuit}, - ) - res = ret['FEParamGetActividades'] - return [(u"%(Id)s\t%(Orden)s\t%(Desc)s" % p['ActividadesTipo']).replace("\t", sep) - for p in res['ResultGet']] + Auth={"Token": self.Token, "Sign": self.Sign, "Cuit": self.Cuit}, + ) + res = ret["FEParamGetActividadesResult"] + return [ + ("%(Id)s\t%(Orden)s\t%(Desc)s" % p["ActividadesTipo"]).replace("\t", sep) + for p in res["ResultGet"] + ] def p_assert_eq(a, b): @@ -1500,7 +1503,7 @@ def main(): if "--rg4540" in sys.argv: wsfev1.AgregarPeriodoComprobantesAsociados("20200101", "20200131") - if '--rg5259' in sys.argv: + if "--rg5259" in sys.argv: wsfev1.AgregarActividad(960990) # agregar la factura creada internamente para solicitud múltiple: diff --git a/wsfexv1.py b/wsfexv1.py index d91862ebc..76efd1f51 100644 --- a/wsfexv1.py +++ b/wsfexv1.py @@ -21,9 +21,9 @@ from builtins import str __author__ = "Mariano Reingart (reingart@gmail.com)" -__copyright__ = "Copyright (C) 2011-2021 Mariano Reingart" +__copyright__ = "Copyright (C) 2011-2023 Mariano Reingart" __license__ = "LGPL-3.0-or-later" -__version__ = "3.10a" +__version__ = "3.11a" import datetime import decimal @@ -44,6 +44,7 @@ class WSFEXv1(BaseWS): "GetCMP", "AgregarPermiso", "AgregarCmpAsoc", + "AgregarActividad", "GetParamMon", "GetParamTipoCbte", "GetParamTipoExpo", @@ -67,6 +68,7 @@ class WSFEXv1(BaseWS): "GetParametro", "GetLastCMP", "GetLastID", + "GetParamActividades", "Dummy", "Conectar", "SetTicketAcceso", @@ -192,6 +194,7 @@ def CrearFactura( "cbtes_asoc": [], "permisos": [], "detalles": [], + "actividades": [], } self.factura = fact @@ -237,6 +240,12 @@ def AgregarCmpAsoc( ) return True + def AgregarActividad(self, actividad_id=0, **kwarg): + "Agrego actividad a una factura (interna)" + act = {"actividad_id": actividad_id} + self.factura["actividades"].append(act) + return True + @inicializar_y_capturar_excepciones def Authorize(self, id): "Autoriza la factura cargada en memoria" @@ -304,6 +313,16 @@ def Authorize(self, id): } for d in f["detalles"] ], + "Actividades": f["actividades"] + and [ + { + "Actividad": { + "Id": a["actividad_id"], + } + } + for a in f["actividades"] + ] + or None, }, ) @@ -748,23 +767,57 @@ def GetParamPtosVenta(self, sep="|"): res = ret["FEXGetPARAM_PtoVentaResult"].get("FEXResultGet") ret = [] for pu in res: - u = pu["ClsFEXResponse_PtoVenta"] + p = pu["ClsFEXResponse_PtoVenta"] try: r = { - "nro": u.get("Pve_Nro"), - "baja": u.get("Pve_FchBaj"), - "bloqueado": u.get("Pve_Bloqueado"), + "nro": p.get("Pve_Nro"), + "baja": p.get("Pve_FchBaj"), + "bloqueado": p.get("Pve_Bloqueado"), } except Exception as e: print(e) ret.append(r) return [ - (u"%(nro)s\tBloqueado:%(bloqueado)s\tFchBaja:%(baja)s" % r).replace( + ("%(nro)s\tBloqueado:%(bloqueado)s\tFchBaja:%(baja)s" % r).replace( "\t", sep ) for r in ret ] + @inicializar_y_capturar_excepciones + def GetParamActividades(self, sep="|"): + "Recuperar lista de valores referenciales de códigos de Idiomas" + ret = self.client.FEXGetPARAM_Actividades( + Auth={ + "Token": self.Token, + "Sign": self.Sign, + "Cuit": self.Cuit, + } + ) + result = ret["FEXGetPARAM_ActividadesResult"] + self.__analizar_errores(result) + + ret = [] + for u in result.get("FEXResultGet", []): + u = u["ClsFEXResponse_ActividadTipo"] + try: + r = { + "codigo": u.get("Id"), + "ds": u.get("Desc"), + "orden": u.get("Orden"), + } + except Exception as e: + print(e) + + ret.append(r) + if sep: + return [ + ("\t%(codigo)s\t%(ds)s\t%(orden)s\t" % it).replace("\t", sep) + for it in ret + ] + else: + return ret + class WSFEX(WSFEXv1): "Wrapper para retrocompatibilidad con WSFEX" @@ -936,6 +989,8 @@ def main(): cbteasoc_tipo, cbteasoc_pto_vta, cbteasoc_nro, cbteasoc_cuit ) + ok = wsfexv1.AgregarActividad(1234) + ##id = "99000000000100" # número propio de transacción # obtengo el último ID y le adiciono 1 # (advertencia: evitar overflow y almacenar!) @@ -1039,6 +1094,12 @@ def main(): for r in ret: print("||%(codigo)s||%(ds)s||" % r) + if "--rg5259" in sys.argv: + print("=== Actividades ===") + ret = wsfexv1.GetParamActividades(sep=False) + for r in ret: + print("||%(codigo)s||%(ds)s||" % r) + if "--ctz" in sys.argv: print(wsfexv1.GetParamCtz("DOL")) diff --git a/wslpg.py b/wslpg.py index 2537161b5..a5c40d5d9 100644 --- a/wslpg.py +++ b/wslpg.py @@ -25,9 +25,9 @@ from past.builtins import basestring __author__ = "Mariano Reingart " -__copyright__ = "Copyright (C) 2013-2021 Mariano Reingart" +__copyright__ = "Copyright (C) 2013-2022 Mariano Reingart" __license__ = "LGPL-3.0-or-later" -__version__ = "3.35b" +__version__ = "3.35e" LICENCIA = """ wslpg.py: Interfaz para generar Código de Operación Electrónica para @@ -160,11 +160,11 @@ ("nro_ing_bruto_corredor", 15, N), ("comision_corredor", 5, I, 2), # 3.2 ("fecha_precio_operacion", 10, A), # 26/02/2013 - ("precio_ref_tn", 8, I, 3), # 4.3 + ("precio_ref_tn", 17, I, 3), # 4.3 ("cod_grado_ref", 2, A), ("cod_grado_ent", 2, A), ("factor_ent", 6, I, 3), # 3.3 - ("precio_flete_tn", 7, I, 2), # 5.2 + ("precio_flete_tn", 17, I, 2), # 5.2 ("cont_proteico", 6, I, 3), # 3.3 ("alic_iva_operacion", 5, I, 2), # 3.2 ("campania_ppal", 4, N), @@ -237,7 +237,7 @@ ("tipo_reg", 1, A), # 2: Retencion ("codigo_concepto", 2, A), ("detalle_aclaratorio", 30, A), - ("base_calculo", 10, I, 2), # 8.2 + ("base_calculo", 17, I, 2), # 8.2 ("alicuota", 6, I, 2), # 3.2 ("nro_certificado_retencion", 14, N), ("fecha_certificado_retencion", 10, A), @@ -252,17 +252,17 @@ ("dias_almacenaje", 4, N), ("reservado1", 6, I, 3), ("comision_gastos_adm", 5, I, 2), # 3.2 - ("base_calculo", 10, I, 2), # 8.2 + ("base_calculo", 17, I, 2), # 8.2 ("alicuota", 6, I, 2), # 3.2 ("importe_iva", 17, I, 2), # 17.2 ("importe_deduccion", 17, I, 2), # 17.2 - ("precio_pkg_diario", 11, I, 8), # 3.8, ajustado WSLPGv1.2 + ("precio_pkg_diario", 17, I, 8), # 3.8, ajustado WSLPGv1.2 ] PERCEPCION = [ ("tipo_reg", 1, A), # P: Percepcion ("detalle_aclaratoria", 50, A), # max 50 por WSLPGv1.8 - ("base_calculo", 10, I, 2), # 8.2 + ("base_calculo", 17, I, 2), # 8.2 ("alicuota", 6, I, 2), # 3.2 ("importe_final", 19, I, 2), # 17.2 (LPG WSLPGv1.16) ] @@ -348,10 +348,10 @@ ("servicios_otros", 7, I, 3), ("servicios_forma_de_pago", 20, A), # campos para cgAutorizarRetiroTransferencia (WSLPGv1.6): - ('cuit_receptor', 11, N), - ('fecha', 10, A), # no usado WSLPGv1.8 - ('nro_carta_porte_a_utilizar', 13, N), # obligatorio para retiro - ('cee_carta_porte_a_utilizar', 10, N), # no usado WSLPGv1.8 + ("cuit_receptor", 11, N), + ("fecha", 10, A), # no usado WSLPGv1.8 + ("nro_carta_porte_a_utilizar", 13, N), # obligatorio para retiro + ("cee_carta_porte_a_utilizar", 10, N), # no usado WSLPGv1.8 # para cgAutorizarPreexistente (WSLPGv1.6): ("tipo_certificado_deposito_preexistente", 1, N), # "R": Retiro "T": Tra. ("nro_certificado_deposito_preexistente", 12, N), @@ -386,18 +386,18 @@ ("servicios_otras_percepciones", 10, I, 2), ] -CTG = [ # para cgAutorizarDeposito (WSLPGv1.6) - ('tipo_reg', 1, A), # C: CTG - ('nro_ctg', 12, A), - ('nro_carta_porte', 13, A), - ('porcentaje_secado_humedad', 5, I, 2), - ('importe_secado', 10, I, 2), - ('peso_neto_merma_secado', 10, I, 2), - ('tarifa_secado', 10, I, 2), - ('importe_zarandeo', 10, I, 2), - ('peso_neto_merma_zarandeo', 10, I, 2), - ('tarifa_zarandeo', 10, I, 2), - ('peso_neto_confirmado_definitivo', 10, I, 2), +CTG = [ # para cgAutorizarDeposito (WSLPGv1.6) + ("tipo_reg", 1, A), # C: CTG + ("nro_ctg", 12, A), + ("nro_carta_porte", 13, A), + ("porcentaje_secado_humedad", 5, I, 2), + ("importe_secado", 10, I, 2), + ("peso_neto_merma_secado", 10, I, 2), + ("tarifa_secado", 10, I, 2), + ("importe_zarandeo", 10, I, 2), + ("peso_neto_merma_zarandeo", 10, I, 2), + ("tarifa_zarandeo", 10, I, 2), + ("peso_neto_confirmado_definitivo", 10, I, 2), ] DET_MUESTRA_ANALISIS = [ # para cgAutorizarDeposito (WSLPGv1.6) @@ -4593,7 +4593,7 @@ def main(): if "--lsg" in sys.argv: print("Anulando COE LSG", coe) - ret = wslpg.AnularLiquidacionSecundaria(coe) + ret = wslpg.AnularLiquidacionSecundaria(pto_emision, nro_orden, coe) if "--cg" in sys.argv: print("Anulando COE CG", coe) ret = wslpg.AnularCertificacion(coe) diff --git a/wsmtx.py b/wsmtx.py index 3ff538685..798c66df0 100644 --- a/wsmtx.py +++ b/wsmtx.py @@ -20,9 +20,9 @@ from builtins import str __author__ = "Mariano Reingart " -__copyright__ = "Copyright (C) 2010-2021 Mariano Reingart" +__copyright__ = "Copyright (C) 2010-2023 Mariano Reingart" __license__ = "LGPL-3.0-or-later" -__version__ = "3.16a" +__version__ = "3.16b" import datetime import decimal @@ -362,11 +362,10 @@ def AgregarOpcional( self.factura["opcionales"].append(op) return True - @inicializar_y_capturar_excepciones def AgregarActividad(self, actividad_id=0, **kwarg): "Agrego actividades a una factura (interna)" - act = { 'actividad_id': actividad_id} - self.factura['actividades'].append(act) + act = {"actividad_id": actividad_id} + self.factura["actividades"].append(act) return True @inicializar_y_capturar_excepciones @@ -895,6 +894,16 @@ def InformarComprobanteCAEA(self): for dato in f["opcionales"] ] or None, + "arrayActividades": f["actividades"] + and [ + { + "actividad": { + "codigo": act["actividad_id"], + } + } + for act in f["actividades"] + ] + or None, } # fecha de vencimiento opcional (igual al último día de vigencia del CAEA) @@ -1460,10 +1469,16 @@ def ConsultarPtosVtaCAEANoInformados(self, caea): def ConsultarActividadesVigentes(self): "Este método permite consultar las actividades vigentes para el contribuyente" ret = self.client.consultarActividadesVigentes( - authRequest={'token': self.Token, 'sign': self.Sign, 'cuitRepresentada': self.Cuit}, - ) - return ["%(codigo)s: %(orden)s %(descripcion)s" % p['actividad'] - for p in ret['arrayActividades']] + authRequest={ + "token": self.Token, + "sign": self.Sign, + "cuitRepresentada": self.Cuit, + }, + ) + return [ + "%(codigo)s: %(orden)s %(descripcion)s" % p["actividad"] + for p in ret["arrayActividades"] + ] def main(): @@ -1498,7 +1513,7 @@ def main(): if "--prueba" in sys.argv: ##print wsmtxca.client.help("autorizarComprobante").encode("latin1") try: - tipo_cbte = 1 + tipo_cbte = 201 punto_vta = 4000 cbte_nro = wsmtxca.ConsultarUltimoComprobanteAutorizado( tipo_cbte, punto_vta @@ -1613,7 +1628,7 @@ def main(): if "--rg4540" in sys.argv: wsmtxca.AgregarPeriodoComprobantesAsociados("2020-01-01", "2020-01-31") - if '--rg5259' in sys.argv: + if "--rg5259" in sys.argv: wsmtxca.AgregarActividad(960990) print(wsmtxca.factura) @@ -1772,8 +1787,8 @@ def main(): print(wsmtxca.ConsultarUnidadesMedida()) print(wsmtxca.ConsultarTiposTributo()) print(wsmtxca.ConsultarTiposDatosAdicionales()) - if '--rg5259' in sys.argv: - print(wsmtxca.ConsultarActividadesVigentes()) + if "--rg5259" in sys.argv: + print("\n".join(wsmtxca.ConsultarActividadesVigentes())) if "--puntosventa" in sys.argv: print(wsmtxca.ConsultarPuntosVentaCAE()) diff --git a/wsremharina.py b/wsremharina.py index 03448e33f..abf9905e8 100644 --- a/wsremharina.py +++ b/wsremharina.py @@ -23,9 +23,9 @@ from builtins import input __author__ = "Mariano Reingart " -__copyright__ = "Copyright (C) 2018-2021 Mariano Reingart" +__copyright__ = "Copyright (C) 2018-2023 Mariano Reingart" __license__ = "LGPL-3.0-or-later" -__version__ = "3.06a" +__version__ = "3.07c" LICENCIA = """ wsremhairna.py: Interfaz para generar Remito Electrónico Harinero AFIP v2.0 @@ -104,23 +104,78 @@ class WSRemHarina(BaseWS): "Interfaz para el WebService de Remito Electronico Carnico (Version 3)" - _public_methods_ = ['Conectar', 'Dummy', 'SetTicketAcceso', 'DebugLog', - 'GenerarRemito', 'EmitirRemito', 'AutorizarRemito', 'AnularRemito', 'ConsultarRemito', - 'InformarContingencia', 'ModificarViaje', 'RegistrarRecepcion', 'ConsultarUltimoRemitoEmitido', - 'CrearRemito', 'AgregarViaje', 'AgregarVehiculo', 'AgregarMercaderia', - 'AgregarReceptor', 'AgregarDepositario', 'AgregarTransportista', - 'AgregarDatosAutorizacion', 'AgregarContingencia', - 'ConsultarTiposMercaderia', 'ConsultarTiposEmbalaje', 'ConsultarTiposUnidades', 'ConsultarTiposComprobante', - 'ConsultarPaises', 'ConsultarReceptoresValidos', - 'ConsultarTiposEstado', 'ConsultarTiposContingencia', 'ConsultarCodigosDomicilio', 'ConsultarPuntosEmision', - 'SetParametros', 'SetParametro', 'GetParametro', 'AnalizarXml', 'ObtenerTagXml', 'LoadTestXML', - ] - _public_attrs_ = ['XmlRequest', 'XmlResponse', 'Version', 'Traceback', 'Excepcion', 'LanzarExcepciones', - 'Token', 'Sign', 'Cuit', 'AppServerStatus', 'DbServerStatus', 'AuthServerStatus', - 'CodRemito', 'TipoComprobante', 'PuntoEmision', - 'NroRemito', 'CodAutorizacion', 'FechaVencimiento', 'FechaEmision', 'Estado', 'Resultado', 'QR', - 'ErrCode', 'ErrMsg', 'Errores', 'ErroresFormato', 'Observaciones', 'Obs', 'Evento', 'Eventos', - ] + _public_methods_ = [ + "Conectar", + "Dummy", + "SetTicketAcceso", + "DebugLog", + "GenerarRemito", + "EmitirRemito", + "AutorizarRemito", + "AnularRemito", + "ConsultarRemito", + "InformarContingencia", + "ModificarViaje", + "RegistrarRecepcion", + "ConsultarUltimoRemitoEmitido", + "CrearRemito", + "AgregarViaje", + "AgregarVehiculo", + "AgregarMercaderia", + "AgregarReceptor", + "AgregarDepositario", + "AgregarTransportista", + "AgregarDatosAutorizacion", + "AgregarContingencia", + "ConsultarTiposMercaderia", + "ConsultarTiposEmbalaje", + "ConsultarTiposUnidades", + "ConsultarTiposComprobante", + "ConsultarPaises", + "ConsultarReceptoresValidos", + "ConsultarTiposEstado", + "ConsultarTiposContingencia", + "ConsultarCodigosDomicilio", + "ConsultarPuntosEmision", + "SetParametros", + "SetParametro", + "GetParametro", + "AnalizarXml", + "ObtenerTagXml", + "LoadTestXML", + ] + _public_attrs_ = [ + "XmlRequest", + "XmlResponse", + "Version", + "Traceback", + "Excepcion", + "LanzarExcepciones", + "Token", + "Sign", + "Cuit", + "AppServerStatus", + "DbServerStatus", + "AuthServerStatus", + "CodRemito", + "TipoComprobante", + "PuntoEmision", + "NroRemito", + "CodAutorizacion", + "FechaVencimiento", + "FechaEmision", + "Estado", + "Resultado", + "QR", + "ErrCode", + "ErrMsg", + "Errores", + "ErroresFormato", + "Observaciones", + "Obs", + "Evento", + "Eventos", + ] _reg_progid_ = "WSRemHarina" _reg_clsid_ = "{72BFB9B9-0FD9-497C-8C62-5D41F7029377}" @@ -183,12 +238,14 @@ def CrearRemito( tipo_movimiento, cuit_titular, es_entrega_mostrador=None, + es_mercaderia_consignacion=None, importe_cot=None, tipo_emisor=None, ruca_est_emisor=None, cod_rem_redestinar=None, cod_remito=None, estado=None, + observaciones=None, **kwargs ): "Inicializa internamente los datos de un remito para autorizar" @@ -199,11 +256,13 @@ def CrearRemito( "cuitTitular": cuit_titular, "tipoMovimiento": tipo_movimiento, "esEntregaMostrador": es_entrega_mostrador, # S o N + "esMercaderiaEnConsignacion": es_mercaderia_consignacion, # S o N "importeCot": importe_cot, "estado": estado, "codRemito": cod_remito, "codRemRedestinado": cod_rem_redestinar, "rucaEstEmisor": ruca_est_emisor, + "observaciones": observaciones, "arrayMercaderia": [], "arrayContingencias": [], } @@ -326,12 +385,16 @@ def AgregarMercaderia( peso_neto_per_kg=None, peso_neto_red_kg=None, peso_neto_rei_kg=None, + cod_comer=None, + desc_comer=None, **kwargs ): "Agrega la información referente a la mercadería del remito electrónico harinero" mercaderia = dict( orden=orden, codTipo=cod_tipo, + codComer=cod_comer, + descComer=desc_comer, codTipoEmb=cod_tipo_emb, cantidadEmb=cantidad_emb, codTipoUnidad=cod_tipo_unidad, @@ -398,15 +461,16 @@ def AnalizarRemito(self, ret, archivo=None): self.CodRemito = ret.get("codRemito") self.TipoComprobante = ret.get("tipoComprobante") self.PuntoEmision = ret.get("puntoEmision") - datos_aut = ret.get("datosAutAFIP") + out = ret.get("remitoOutput") + datos_aut = out.get("datosAutAFIP") if datos_aut: self.NroRemito = datos_aut.get("nroRemito") self.CodAutorizacion = datos_aut.get("codAutorizacion") self.FechaEmision = datos_aut.get("fechaEmision") self.FechaVencimiento = datos_aut.get("fechaVencimiento") - self.Estado = ret.get("estado", ret.get("estadoRemito")) + self.Estado = out.get("estado", ret.get("estadoRemito")) self.Resultado = ret.get("resultado") - self.QR = ret.get("qr") or "" + self.QR = out.get("qr") or "" if archivo: f = open(archivo, "wb") f.write(self.QR) @@ -724,12 +788,14 @@ def ConsultarPuntosEmision(self, sep="||"): def ConsultarReceptoresValidos(self, cuit_titular, sep="||"): "Obtener el código de depositos que tiene habilitados para operar el cuit informado" res = self.client.consultarReceptoresValidos( - authRequest={ - 'token': self.Token, 'sign': self.Sign, - 'cuitRepresentada': self.Cuit, }, - arrayReceptores=[{"receptores": {"cuitReceptor": cuit_titular}}], - ) - ret = res['consultarReceptoresValidosReturn'] + authRequest={ + "token": self.Token, + "sign": self.Sign, + "cuitRepresentada": self.Cuit, + }, + arrayReceptores=[{"receptores": {"cuitReceptor": cuit_titular}}], + ) + ret = res["consultarReceptoresValidosReturn"] self.Resultado = ret["resultado"] return True @@ -1032,7 +1098,7 @@ def main(): ret = wsremharina.ConsultarPuntosEmision() print("\n".join(ret)) - if '--receptores' in sys.argv: + if "--receptores" in sys.argv: try: cuit = int(sys.argv[-1]) except: From 945bb16db3272609e88757b393df5344648e3cc4 Mon Sep 17 00:00:00 2001 From: HanslettTheDev Date: Mon, 3 Jul 2023 13:14:26 +0100 Subject: [PATCH 13/13] refactoring the wssa.py file Signed-off-by: HanslettTheDev --- wsaa.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/wsaa.py b/wsaa.py index b41a236d6..894f93972 100644 --- a/wsaa.py +++ b/wsaa.py @@ -175,10 +175,6 @@ def sign_tra(tra, cert=CERT, privatekey=PRIVATEKEY, passphrase=""): ).sign( serialization.Encoding.SMIME, [pkcs7.PKCS7Options.Binary] ) -<<<<<<< HEAD - -======= ->>>>>>> d676cac9e7e661c2d7c0fc521b366cda65b3be0a # Generar p7 en formato mail y recortar headers msg = email.message_from_string(p7.decode("utf8"))