From a719340806e8521a6dd889070269cc0a9242ae98 Mon Sep 17 00:00:00 2001 From: Sando Date: Sun, 7 Apr 2019 23:19:13 -0300 Subject: [PATCH 01/16] WSFEv1: Agrego los cambios de FCE al branch py3k --- wsfev1.py | 60 +++++++++++++++++++++++++++++++++++++------------------ 1 file changed, 41 insertions(+), 19 deletions(-) diff --git a/wsfev1.py b/wsfev1.py index 45e801e54..f47653306 100644 --- a/wsfev1.py +++ b/wsfev1.py @@ -11,20 +11,21 @@ # for more details. """Módulo para obtener CAE/CAEA, código de autorización electrónico webservice -WSFEv1 de AFIP (Factura Electrónica Nacional - Proyecto Version 1 - 2.10) +WSFEv1 de AFIP (Factura Electrónica Nacional - Proyecto Version 1 - 2.12) Según RG 2485/08, RG 2757/2010, RG 2904/2010 y RG2926/10 (CAE anticipado), RG 3067/2011 (RS - Monotributo), RG 3571/2013 (Responsables inscriptos IVA), RG 3668/2014 (Factura A IVA F.8001), RG 3749/2015 (R.I. y exentos) RG 4004-E Alquiler de inmuebles con destino casa habitación). RG 4109-E Venta de bienes muebles registrables. RG 4291/2018 Régimen especial de emisión y almacenamiento electrónico +RG 4367/2018 Régimen de Facturas de Crédito Electrónicas MiPyMEs Ley 27.440 Más info: http://www.sistemasagiles.com.ar/trac/wiki/ProyectoWSFEv1 """ __author__ = "Mariano Reingart " -__copyright__ = "Copyright (C) 2010-2017 Mariano Reingart" +__copyright__ = "Copyright (C) 2010-2019 Mariano Reingart" __license__ = "GPL 3.0" -__version__ = "1.21a" +__version__ = "1.22a" import datetime import decimal @@ -42,7 +43,7 @@ class WSFEv1(BaseWS): - "Interfaz para el WebService de Factura Electrónica Version 1 - 2.10" + "Interfaz para el WebService de Factura Electrónica Version 1 - 2.12" _public_methods_ = ['CrearFactura', 'AgregarIva', 'CAESolicitar', 'AgregarTributo', 'AgregarCmpAsoc', 'AgregarOpcional', 'AgregarComprador', @@ -170,11 +171,13 @@ def EstablecerCampoFactura(self, campo, valor): else: return False - def AgregarCmpAsoc(self, tipo=1, pto_vta=0, nro=0, cuit=None, **kwarg): + def AgregarCmpAsoc(self, tipo=1, pto_vta=0, nro=0, cuit=None, fecha=None, **kwarg): "Agrego un comprobante asociado a una factura (interna)" cmp_asoc = {'tipo': tipo, 'pto_vta': pto_vta, 'nro': nro} if cuit is not None: cmp_asoc['cuit'] = cuit + if fecha is not None: + cmp_asoc['fecha'] = fecha self.factura['cbtes_asoc'].append(cmp_asoc) return True @@ -259,6 +262,7 @@ def CAESolicitar(self): 'PtoVta': cbte_asoc['pto_vta'], 'Nro': cbte_asoc['nro'], 'Cuit': cbte_asoc.get('cuit'), + 'CbteFch': cbte_asoc.get('fecha'), }} for cbte_asoc in f['cbtes_asoc']] or None, 'Tributos': f['tributos'] and [ @@ -1004,11 +1008,18 @@ def main(): if "--prueba" in sys.argv: print(wsfev1.client.help("FECAESolicitar").encode("latin1")) - tipo_cbte = 6 if '--usados' not in sys.argv else 49 + if '--usados' in sys.argv: + tipo_cbte = 49 + concepto = 1 + elif '--fce' in sys.argv: + tipo_cbte = 201 + concepto = 1 + else: + tipo_cbte = 6 + concepto = 3 if ('--rg4109' not in sys.argv) else 1 punto_vta = 4001 cbte_nro = int(wsfev1.CompUltimoAutorizado(tipo_cbte, punto_vta) or 0) fecha = datetime.datetime.now().strftime("%Y%m%d") - concepto = 2 if ('--usados' not in sys.argv and '--rg4109' not in sys.argv) else 1 tipo_doc = 80 if '--usados' not in sys.argv else 30 nro_doc = "30500010912" cbt_desde = cbte_nro + 1 @@ -1020,13 +1031,15 @@ def main(): imp_trib = "1.00" imp_op_ex = "0.00" fecha_cbte = fecha + fecha_venc_pago = fecha_serv_desde = fecha_serv_hasta = None # Fechas del período del servicio facturado y vencimiento de pago: if concepto > 1: fecha_venc_pago = fecha fecha_serv_desde = fecha fecha_serv_hasta = fecha - else: - fecha_venc_pago = fecha_serv_desde = fecha_serv_hasta = None + elif '--fce' in sys.argv: + # obligatorio en Factura de Crédito Electrónica MiPyMEs (FCE): + fecha_venc_pago = fecha moneda_id = 'PES' moneda_ctz = '1.000' @@ -1053,12 +1066,14 @@ def main(): wsfev1.EstablecerCampoFactura("caea", caea) # comprobantes asociados (notas de crédito / débito) - if tipo_cbte in (2, 3, 7, 8, 12, 13): - tipo = 3 - pto_vta = 2 - nro = 1234 + if tipo_cbte in (2, 3, 7, 8, 12, 13, 203, 208, 213): + tipo = 201 if tipo_cbte in (203, 208, 213) else 3 + pto_vta = 4001 + nro = 1 cuit = "20267565393" - wsfev1.AgregarCmpAsoc(tipo, pto_vta, nro, cuit) + # obligatorio en Factura de Crédito Electrónica MiPyMEs (FCE): + fecha_cbte = fecha if tipo_cbte in (203, 208, 213) else None + wsfev1.AgregarCmpAsoc(tipo, pto_vta, nro, cuit, fecha_cbte) # otros tributos: tributo_id = 99 @@ -1098,20 +1113,27 @@ def main(): if '--rg4004' in sys.argv: wsfev1.AgregarOpcional(17, "1") # Intermediario wsfev1.AgregarOpcional(1801, "30500010912") # CUIT Propietario - wsfev1.AgregarOpcional(1802, "BNA") # Nombr e Titular + wsfev1.AgregarOpcional(1802, "BNA") # Nombre Titular # datos de compradores RG 4109-E bienes muebles registrables (%) if '--rg4109' in sys.argv: wsfev1.AgregarComprador(80, "30500010912", 99.99) wsfev1.AgregarComprador(80, "30999032083", 0.01) + # datos de Factura de Crédito Electrónica MiPyMEs (FCE): + if '--fce' in sys.argv: # 0110001900000000000000 + wsfev1.AgregarOpcional(2101, "2850590940090418135201") # CBU + wsfev1.AgregarOpcional(2102, "pyafipws") # alias + if tipo_cbte in (203, 208, 213): + wsfev1.AgregarOpcional(22, "S") # Anulación + # agregar la factura creada internamente para solicitud múltiple: if "--multiple" in sys.argv: wsfev1.AgregarFacturaX() - import time + # import time t0 = time.time() - if not '--caea' in sys.argv: - if not "--multiple" in sys.argv: + if '--caea' not in sys.argv: + if "--multiple" not in sys.argv: wsfev1.CAESolicitar() else: cant = wsfev1.CAESolicitarX() @@ -1139,7 +1161,7 @@ def main(): open("xmlrequest.xml", "wb").write(wsfev1.XmlRequest) open("xmlresponse.xml", "wb").write(wsfev1.XmlResponse) - if not "--multiple" in sys.argv: + if "--multiple" not in sys.argv: wsfev1.AnalizarXml("XmlResponse") p_assert_eq(wsfev1.ObtenerTagXml('CAE'), str(wsfev1.CAE)) p_assert_eq(wsfev1.ObtenerTagXml('Concepto'), '2') From dd5c4f24391756607ef48d4efe7d685f6448de4f Mon Sep 17 00:00:00 2001 From: Sando Date: Fri, 7 Jun 2019 15:56:45 -0300 Subject: [PATCH 02/16] =?UTF-8?q?WSFEXv1:=20Se=20agrega=20m=C3=A9todo=20Ge?= =?UTF-8?q?tParamMonConCotizacion=20(Aduana)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- wsfexv1.py | 88 ++++++++++++++++++++++++++++++++++-------------------- 1 file changed, 55 insertions(+), 33 deletions(-) diff --git a/wsfexv1.py b/wsfexv1.py index 26677d10c..fc75e9fe0 100644 --- a/wsfexv1.py +++ b/wsfexv1.py @@ -25,7 +25,7 @@ import decimal import os import sys -from .utils import inicializar_y_capturar_excepciones, BaseWS, get_install_dir +from utils import inicializar_y_capturar_excepciones, BaseWS, get_install_dir HOMO = False WSDL = "https://wswhomo.afip.gov.ar/wsfexv1/service.asmx?WSDL" @@ -39,6 +39,7 @@ class WSFEXv1(BaseWS): 'GetParamIdiomas', 'GetParamUMed', 'GetParamIncoterms', 'GetParamDstPais', 'GetParamDstCUIT', 'GetParamIdiomas', 'GetParamIncoterms', 'GetParamDstCUIT', + 'GetParamMonConCotizacion', 'GetParamPtosVenta', 'GetParamCtz', 'LoadTestXML', 'AnalizarXml', 'ObtenerTagXml', 'DebugLog', 'SetParametros', 'SetTicketAcceso', 'GetParametro', @@ -461,6 +462,7 @@ def GetParamIdiomas(self, sep="|"): else: return ret + @inicializar_y_capturar_excepciones def GetParamIncoterms(self, sep="|"): "Recuperar lista de valores referenciales de Incoterms" ret = self.client.FEXGetPARAM_Incoterms( @@ -500,6 +502,38 @@ def GetParamCtz(self, moneda_id): ctz = '' return ctz + @inicializar_y_capturar_excepciones + def GetParamMonConCotizacion(self, fecha=None, sep='|'): + "Recupera el listado de monedas que tengan cotizacion de ADUANA" + if not fecha: + fecha = datetime.date.today().strftime('%Y%m%d') + + ret = self.client.FEXGetPARAM_MON_CON_COTIZACION( + Auth={'Token': self.Token, 'Sign': self.Sign, 'Cuit': self.Cuit}, + Fecha_CTZ=fecha, + ) + result = ret['FEXGetPARAM_MON_CON_COTIZACIONResult'] + self.__analizar_errores(result) + + mons = [] # Monedas + for u in result['FEXResultGet']: + u = u['ClsFEXResponse_Mon_CON_Cotizacion'] + try: + mon = {'id': u.get('Mon_Id'), 'ctz': u.get('Mon_ctz'), + 'fecha': u.get('Fecha_ctz')} + except Exception as e: + print(e) + if u is None: + mon = {'id': '', 'ctz': '', 'fecha': ''} + mons.append(mon) + + if sep: + return [("\t%(id)s\t%(ctz)s\t%(fecha)s\t" % it).replace('\t', sep) + for it in mons] + else: + return mons + + @inicializar_y_capturar_excepciones def GetParamPtosVenta(self, sep="|"): "Recupera el listado de los puntos de venta para exportacion y estado" @@ -567,10 +601,10 @@ def p_assert_eq(a, b): # Crear objeto interface Web Service de Factura Electrónica de Exportación wsfexv1 = WSFEXv1() - # Setear token y sing de autorización (pasos previos) + # Setear token y sign de autorización (pasos previos) # obteniendo el TA para pruebas - from .wsaa import WSAA + from wsaa import WSAA ta = WSAA().Autenticar("wsfex", "reingart.crt", "reingart.key") wsfexv1.SetTicketAcceso(ta) @@ -709,50 +743,38 @@ def p_assert_eq(a, b): if "--params" in sys.argv: import codecs import locale - sys.stdout = codecs.getwriter('latin1')(sys.stdout) + if sys.stdout.encoding is None: + sys.stdout = codecs.getwriter(locale.getpreferredencoding())(sys.stdout, "replace") + sys.stderr = codecs.getwriter(locale.getpreferredencoding())(sys.stderr, "replace") + + print("\n=== Cotizacion ===") + print('\n'.join(wsfexv1.GetParamMonConCotizacion(sep='|'))) + - print("=== Incoterms ===") - idiomas = wsfexv1.GetParamIncoterms(sep="||") - for idioma in idiomas: - print(idioma) + print("\n=== Incoterms ===") + print('\n'.join(wsfexv1.GetParamIncoterms(sep='||'))) print("=== Idiomas ===") - idiomas = wsfexv1.GetParamIdiomas(sep="||") - for idioma in idiomas: - print(idioma) + print('\n'.join(wsfexv1.GetParamIdiomas(sep='||'))) print("=== Tipos Comprobantes ===") - tipos = wsfexv1.GetParamTipoCbte(sep=False) - for t in tipos: - print("||%(codigo)s||%(ds)s||" % t) + print('\n'.join(wsfexv1.GetParamTipoCbte(sep='||'))) print("=== Tipos Expo ===") - tipos = wsfexv1.GetParamTipoExpo(sep=False) - for t in tipos: - print("||%(codigo)s||%(ds)s||%(vig_desde)s||%(vig_hasta)s||" % t) - #umeds = dict([(u.get('id', ""),u.get('ds', "")) for u in umedidas]) + print('\n'.join(wsfexv1.GetParamTipoExpo(sep='||'))) - print("=== Monedas ===") - mons = wsfexv1.GetParamMon(sep=False) - for m in mons: - print("||%(id)s||%(ds)s||%(vig_desde)s||%(vig_hasta)s||" % m) - #umeds = dict([(u.get('id', ""),u.get('ds', "")) for u in umedidas]) + print ("=== Monedas ===") + print('\n'.join(wsfexv1.GetParamMon(sep='||'))) print("=== Unidades de medida ===") - umedidas = wsfexv1.GetParamUMed(sep=False) - for u in umedidas: - print("||%(id)s||%(ds)s||%(vig_desde)s||%(vig_hasta)s||" % u) - umeds = dict([(u.get('id', ""), u.get('ds', "")) for u in umedidas]) + print('\n'.join(wsfexv1.GetParamUMed(sep='||'))) + #umeds = dict([(u.get('id', ""), u.get('ds', "")) for u in umedidas]) print("=== Código Pais Destino ===") - ret = wsfexv1.GetParamDstPais(sep=False) - for r in ret: - print("||%(codigo)s||%(ds)s||" % r) + print('\n'.join(wsfexv1.GetParamDstPais(sep='||'))) print("=== CUIT Pais Destino ===") - ret = wsfexv1.GetParamDstCUIT(sep=False) - for r in ret: - print("||%(codigo)s||%(ds)s||" % r) + print('\n'.join(wsfexv1.GetParamDstCUIT(sep='||'))) if "--ctz" in sys.argv: print(wsfexv1.GetParamCtz('DOL')) From d43408d12de54d30518911391d8fb26897217352 Mon Sep 17 00:00:00 2001 From: Sando Date: Fri, 7 Jun 2019 20:09:26 -0300 Subject: [PATCH 03/16] WSFEv1: Agrego los ultimos cambios de fce --- wsfev1.py | 33 +++++++++++++++++++-------------- 1 file changed, 19 insertions(+), 14 deletions(-) diff --git a/wsfev1.py b/wsfev1.py index f47653306..8411a94c8 100644 --- a/wsfev1.py +++ b/wsfev1.py @@ -11,7 +11,7 @@ # for more details. """Módulo para obtener CAE/CAEA, código de autorización electrónico webservice -WSFEv1 de AFIP (Factura Electrónica Nacional - Proyecto Version 1 - 2.12) +WSFEv1 de AFIP (Factura Electrónica Nacional - Proyecto Version 1 - 2.13) Según RG 2485/08, RG 2757/2010, RG 2904/2010 y RG2926/10 (CAE anticipado), RG 3067/2011 (RS - Monotributo), RG 3571/2013 (Responsables inscriptos IVA), RG 3668/2014 (Factura A IVA F.8001), RG 3749/2015 (R.I. y exentos) @@ -25,13 +25,13 @@ __author__ = "Mariano Reingart " __copyright__ = "Copyright (C) 2010-2019 Mariano Reingart" __license__ = "GPL 3.0" -__version__ = "1.22a" +__version__ = "1.22b" import datetime import decimal import os import sys -from .utils import verifica, inicializar_y_capturar_excepciones, BaseWS, get_install_dir +from utils import verifica, inicializar_y_capturar_excepciones, BaseWS, get_install_dir HOMO = False # solo homologación TYPELIB = False # usar librería de tipos (TLB) @@ -43,7 +43,7 @@ class WSFEv1(BaseWS): - "Interfaz para el WebService de Factura Electrónica Version 1 - 2.12" + "Interfaz para el WebService de Factura Electrónica Version 1 - 2.13" _public_methods_ = ['CrearFactura', 'AgregarIva', 'CAESolicitar', 'AgregarTributo', 'AgregarCmpAsoc', 'AgregarOpcional', 'AgregarComprador', @@ -400,6 +400,7 @@ def CompConsultar(self, tipo_cbte, punto_vta, cbte_nro, reproceso=False): 'PtoVta': cbte_asoc['pto_vta'], 'Nro': cbte_asoc['nro'], 'Cuit': cbte_asoc.get('cuit'), + 'CbteFch': cbte_asoc.get('fecha') or None, }} for cbte_asoc in f['cbtes_asoc']], 'Tributos': [ @@ -461,7 +462,9 @@ def CompConsultar(self, tipo_cbte, punto_vta, cbte_nro, reproceso=False): 'tipo': cbte_asoc['CbteAsoc']['Tipo'], 'pto_vta': cbte_asoc['CbteAsoc']['PtoVta'], 'nro': cbte_asoc['CbteAsoc']['Nro'], - 'cuit': cbte_asoc['CbteAsoc'].get('Cuit')} + 'cuit': cbte_asoc['CbteAsoc'].get('Cuit'), + 'fecha': cbte_asoc['CbteAsoc'].get('CbteFch'), + } for cbte_asoc in resultget.get('CbtesAsoc', [])], 'tributos': [ { @@ -582,6 +585,7 @@ def CAESolicitarX(self): 'PtoVta': cbte_asoc['pto_vta'], 'Nro': cbte_asoc['nro'], 'Cuit': cbte_asoc.get('cuit'), + 'CbteFch': cbte_asoc.get('fecha'), }} for cbte_asoc in f['cbtes_asoc']] or None, 'Tributos': [ @@ -773,6 +777,7 @@ def CAEARegInformativo(self): 'PtoVta': cbte_asoc['pto_vta'], 'Nro': cbte_asoc['nro'], 'Cuit': cbte_asoc.get('cuit'), + 'CbteFch': cbtes_asoc.get('fecha'), }} for cbte_asoc in f['cbtes_asoc']] if f['cbtes_asoc'] else None, @@ -1000,22 +1005,22 @@ def main(): sys.exit(0) # obteniendo el TA para pruebas - from .wsaa import WSAA + from wsaa import WSAA ta = WSAA().Autenticar("wsfe", "reingart.crt", "reingart.key", debug=True) wsfev1.SetTicketAcceso(ta) wsfev1.Cuit = "20267565393" if "--prueba" in sys.argv: - print(wsfev1.client.help("FECAESolicitar").encode("latin1")) + print(wsfev1.client.help("FECAESolicitar").encode('latin1')) if '--usados' in sys.argv: tipo_cbte = 49 concepto = 1 elif '--fce' in sys.argv: - tipo_cbte = 201 + tipo_cbte = 203 concepto = 1 else: - tipo_cbte = 6 + tipo_cbte = 3 concepto = 3 if ('--rg4109' not in sys.argv) else 1 punto_vta = 4001 cbte_nro = int(wsfev1.CompUltimoAutorizado(tipo_cbte, punto_vta) or 0) @@ -1037,9 +1042,10 @@ def main(): fecha_venc_pago = fecha fecha_serv_desde = fecha fecha_serv_hasta = fecha - elif '--fce' in sys.argv: + if '--fce' in sys.argv: # obligatorio en Factura de Crédito Electrónica MiPyMEs (FCE): fecha_venc_pago = fecha + print(fecha_venc_pago) moneda_id = 'PES' moneda_ctz = '1.000' @@ -1120,7 +1126,7 @@ def main(): wsfev1.AgregarComprador(80, "30999032083", 0.01) # datos de Factura de Crédito Electrónica MiPyMEs (FCE): - if '--fce' in sys.argv: # 0110001900000000000000 + if '--fce' in sys.argv: wsfev1.AgregarOpcional(2101, "2850590940090418135201") # CBU wsfev1.AgregarOpcional(2102, "pyafipws") # alias if tipo_cbte in (203, 208, 213): @@ -1164,7 +1170,7 @@ def main(): if "--multiple" not in sys.argv: wsfev1.AnalizarXml("XmlResponse") p_assert_eq(wsfev1.ObtenerTagXml('CAE'), str(wsfev1.CAE)) - p_assert_eq(wsfev1.ObtenerTagXml('Concepto'), '2') + p_assert_eq(wsfev1.ObtenerTagXml('Concepto'), '3') p_assert_eq(wsfev1.ObtenerTagXml('Obs', 0, 'Code'), "10017") print(wsfev1.ObtenerTagXml('Obs', 0, 'Msg')) @@ -1228,8 +1234,7 @@ def main(): sys.stdout = codecs.getwriter(locale.getpreferredencoding())(sys.stdout, "replace") sys.stderr = codecs.getwriter(locale.getpreferredencoding())(sys.stderr, "replace") - print('\n'.join(wsfev1.ParamGetTiposDoc())) - print("=== Tipos de Comprobante ===") + print("\n=== Tipos de Comprobante ===") print('\n'.join(wsfev1.ParamGetTiposCbte())) print("=== Tipos de Concepto ===") print('\n'.join(wsfev1.ParamGetTiposConcepto())) From 752a486ea5bfc2a1a8adc0aecd6370326d513a10 Mon Sep 17 00:00:00 2001 From: Sando Date: Fri, 7 Jun 2019 22:58:07 -0300 Subject: [PATCH 04/16] =?UTF-8?q?RECEX1:=20Se=20agrega=20/monctz=20cotizac?= =?UTF-8?q?i=C3=B3n=20aduana?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- recex1.py | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/recex1.py b/recex1.py index e27b11421..ba6435cc7 100644 --- a/recex1.py +++ b/recex1.py @@ -13,7 +13,7 @@ "Módulo de Intefase para archivos de texto (exportación version 1)" __author__ = "Mariano Reingart (reingart@gmail.com)" -__copyright__ = "Copyright (C) 2011 Mariano Reingart" +__copyright__ = "Copyright (C) 2019 Mariano Reingart" __license__ = "GPL 3.0" __version__ = "1.27e" @@ -23,10 +23,10 @@ import time import traceback -# revisar la instalación de pyafip.ws: +# revisar la instalación de pyafipws: from . import wsfexv1 -from .utils import SimpleXMLElement, SoapClient, SoapFault, date -from .utils import leer, escribir, leer_dbf, guardar_dbf, N, A, I, abrir_conf +from utils import SimpleXMLElement, SoapClient, SoapFault, date +from utils import leer, escribir, leer_dbf, guardar_dbf, N, A, I, abrir_conf HOMO = wsfexv1.HOMO @@ -465,6 +465,17 @@ def depurar_xml(client): print(ws.ErrMsg) sys.exit(0) + if '/monctz' in sys.argv: + i = sys.argv.index("/monctz") + if i+1 Date: Sat, 8 Jun 2019 10:55:57 -0300 Subject: [PATCH 05/16] WSFEv1: Ajusto claves en diccionarios --- wsfev1.py | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/wsfev1.py b/wsfev1.py index 8411a94c8..47f1810e7 100644 --- a/wsfev1.py +++ b/wsfev1.py @@ -251,9 +251,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'], 'CbtesAsoc': f['cbtes_asoc'] and [ @@ -574,9 +571,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'], 'CbtesAsoc': [ @@ -766,9 +760,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'], 'CbtesAsoc': [ @@ -1045,7 +1036,7 @@ def main(): if '--fce' in sys.argv: # obligatorio en Factura de Crédito Electrónica MiPyMEs (FCE): fecha_venc_pago = fecha - print(fecha_venc_pago) + moneda_id = 'PES' moneda_ctz = '1.000' @@ -1136,7 +1127,6 @@ def main(): if "--multiple" in sys.argv: wsfev1.AgregarFacturaX() - # import time t0 = time.time() if '--caea' not in sys.argv: if "--multiple" not in sys.argv: From eb9772d3ea33481040d88721fffa5eb5deef40c7 Mon Sep 17 00:00:00 2001 From: Sando Date: Sat, 8 Jun 2019 12:05:14 -0300 Subject: [PATCH 06/16] RECEX1: Agrego cbtes asoc para RG4401/19 --- recex1.py | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/recex1.py b/recex1.py index ba6435cc7..2b228af53 100644 --- a/recex1.py +++ b/recex1.py @@ -25,8 +25,8 @@ # revisar la instalación de pyafipws: from . import wsfexv1 -from utils import SimpleXMLElement, SoapClient, SoapFault, date -from utils import leer, escribir, leer_dbf, guardar_dbf, N, A, I, abrir_conf +from .utils import SimpleXMLElement, SoapClient, SoapFault, date +from .utils import leer, escribir, leer_dbf, guardar_dbf, N, A, I, abrir_conf HOMO = wsfexv1.HOMO @@ -212,6 +212,10 @@ def escribir_factura(dic, archivo, agrega=False): for it in dic['permisos']: it['tipo_reg'] = TIPOS_REG[2] archivo.write(escribir(it, PERMISO)) + if 'cbtes_asoc' in dic: + for it in dic['cbtes_asoc']: + it['tipo_reg'] = TIPOS_REG[3] + archivo.write(escribir(it, CMP_ASOC)) if '/dbf' in sys.argv: formatos = [('Encabezado', ENCABEZADO, [dic]), ('Permisos', PERMISO, dic.get('permisos', [])), ('Comprobante Asociado', CMP_ASOC, dic.get('cbtes_asoc', [])), ('Detalles', DETALLE, dic.get('detalles', []))] @@ -342,7 +346,7 @@ def depurar_xml(client): # generar el archivo de prueba para la próxima factura f_entrada = open(entrada, "w") - tipo_cbte = 19 # FC Expo (ver tabla de parámetros) + tipo_cbte = 21 # FC Expo (ver tabla de parámetros) punto_vta = 7 # Obtengo el último número de comprobante y le agrego 1 cbte_nro = int(ws.GetLastCMP(tipo_cbte, punto_vta)) + 1 @@ -467,7 +471,7 @@ def depurar_xml(client): if '/monctz' in sys.argv: i = sys.argv.index("/monctz") - if i+1 Date: Sat, 8 Jun 2019 18:20:13 -0300 Subject: [PATCH 07/16] WSLPGv1: Ajusto campo IvaRg2300_07 -> IvaRg4310_18(.csv) --- plantillas/liquidacion_form_c1116b_wslpg.csv | 4 ++-- plantillas/liquidacion_wslpg_ajuste_base.csv | 4 ++-- plantillas/liquidacion_wslpg_ajuste_debcred.csv | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/plantillas/liquidacion_form_c1116b_wslpg.csv b/plantillas/liquidacion_form_c1116b_wslpg.csv index a1c613c7f..4e44a9300 100644 --- a/plantillas/liquidacion_form_c1116b_wslpg.csv +++ b/plantillas/liquidacion_form_c1116b_wslpg.csv @@ -137,8 +137,8 @@ 'tipo_operacion';'T';58.60;32.70;127.90;38.50;'Arial';9;False;False;False;0;16777215;'L';'tipo_operacion';0 'total_deduccion';'T';50.00;250.90;78.40;255.00;'Arial';9;False;False;False;0;16777215;'R';'total_deduccion';0 'total_deduccion.L';'T';19.10;250.80;47.50;254.90;'Arial';9;False;False;False;0;16777215;'L';'Total deducciones:';0 -'total_iva_rg_2300_07';'T';111.10;255.80;139.50;259.90;'Arial';9;False;False;False;0;16777215;'R';'total_iva_rg_2300_07';0 -'total_iva_rg_2300_07.L';'T';79.30;255.80;107.70;259.90;'Arial';9;False;False;False;0;16777215;'L';'Total IVA RG 2300/07:';0 +'total_iva_rg_4310_18';'T';111.10;255.80;139.50;259.90;'Arial';9;False;False;False;0;16777215;'R';'total_iva_rg_4310_18';0 +'total_iva_rg_4310_18.L';'T';79.30;255.80;107.70;259.90;'Arial';9;False;False;False;0;16777215;'L';'Total IVA RG 4310/18:';0 'total_neto_a_pagar';'T';50.10;255.80;78.50;259.90;'Arial';9;False;False;False;0;16777215;'R';'total_neto_a_pagar';0 'total_neto_a_pagar.L_copy';'T';19.40;255.90;47.80;260.00;'Arial';9;False;False;False;0;16777215;'L';'Total Neto a Pagar:';0 'total_operacion.L';'T';19.10;246.10;47.50;250.20;'Arial';9;False;False;False;0;16777215;'L';'Total operacion:';0 diff --git a/plantillas/liquidacion_wslpg_ajuste_base.csv b/plantillas/liquidacion_wslpg_ajuste_base.csv index 0399713bb..a795a8f47 100644 --- a/plantillas/liquidacion_wslpg_ajuste_base.csv +++ b/plantillas/liquidacion_wslpg_ajuste_base.csv @@ -63,8 +63,8 @@ 'total_deduccion.L_copy_copy_copy';'T';22.40;197.70;50.80;201.80;'Arial';9;False;False;False;0;16777215;'L';'IVA 21%:';0 'total_iva_10_5';'T';53.80;193.70;82.20;197.80;'Arial';9;False;False;False;0;16777215;'R';'total_iva_10_5';0 'total_iva_21';'T';53.80;197.70;82.20;201.80;'Arial';9;False;False;False;0;16777215;'R';'total_iva_21';0 -'total_iva_rg_2300_07';'T';53.80;217.70;82.20;221.80;'Arial';9;False;False;False;0;16777215;'R';'total_iva_rg_2300_07';0 -'total_iva_rg_2300_07.L';'T';22.40;217.70;50.80;221.80;'Arial';9;False;False;False;0;16777215;'L';'Total IVA RG 2300/07:';0 +'total_iva_rg_4310_18';'T';53.80;217.70;82.20;221.80;'Arial';9;False;False;False;0;16777215;'R';'total_iva_rg_4310_18';0 +'total_iva_rg_4310_18.L';'T';22.40;217.70;50.80;221.80;'Arial';9;False;False;False;0;16777215;'L';'Total IVA RG 4310/18:';0 'total_neto_a_pagar';'T';53.80;213.70;82.20;217.80;'Arial';9;False;False;False;0;16777215;'R';'total_neto_a_pagar';0 'total_neto_a_pagar.L_copy';'T';22.30;213.80;50.70;217.90;'Arial';9;False;False;False;0;16777215;'L';'Importe Neto:';0 'total_operacion.L';'T';22.40;177.80;50.80;181.90;'Arial';9;False;False;False;0;16777215;'L';'Subtotal general:';0 diff --git a/plantillas/liquidacion_wslpg_ajuste_debcred.csv b/plantillas/liquidacion_wslpg_ajuste_debcred.csv index 1e250053f..1ffdaf92f 100644 --- a/plantillas/liquidacion_wslpg_ajuste_debcred.csv +++ b/plantillas/liquidacion_wslpg_ajuste_debcred.csv @@ -139,8 +139,8 @@ 'tipo_operacion';'T';58.70;32.80;128.00;38.60;'Arial';9;False;False;False;0;16777215;'L';'tipo_operacion';0 'total_deduccion';'T';50.10;251.00;78.50;255.10;'Arial';9;False;False;False;0;16777215;'R';'total_deduccion';0 'total_deduccion.L';'T';19.20;250.90;47.60;255.00;'Arial';9;False;False;False;0;16777215;'L';'Total deducciones:';0 -'total_iva_rg_2300_07';'T';111.20;255.90;139.60;260.00;'Arial';9;False;False;False;0;16777215;'R';'total_iva_rg_2300_07';0 -'total_iva_rg_2300_07.L';'T';79.40;255.90;107.80;260.00;'Arial';9;False;False;False;0;16777215;'L';'Total IVA RG 2300/07:';0 +'total_iva_rg_4310_18';'T';111.20;255.90;139.60;260.00;'Arial';9;False;False;False;0;16777215;'R';'total_iva_rg_4310_18';0 +'total_iva_rg_4310_18.L';'T';79.40;255.90;107.80;260.00;'Arial';9;False;False;False;0;16777215;'L';'Total IVA RG 4310/18:';0 'total_neto_a_pagar';'T';50.20;255.90;78.60;260.00;'Arial';9;False;False;False;0;16777215;'R';'total_neto_a_pagar';0 'total_neto_a_pagar.L_copy';'T';19.50;256.00;47.90;260.10;'Arial';9;False;False;False;0;16777215;'L';'Total Neto a Pagar:';0 'total_operacion.L';'T';19.20;246.20;47.60;250.30;'Arial';9;False;False;False;0;16777215;'L';'Total operacion:';0 From f045dfa811c031f03073f71735c40071571c3d5e Mon Sep 17 00:00:00 2001 From: Sando Date: Sat, 8 Jun 2019 22:47:54 -0300 Subject: [PATCH 08/16] PYFEPDF: Ajusto leyenda FCE RG4367/18 --- pyfepdf.py | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/pyfepdf.py b/pyfepdf.py index 3d366b06d..c64f1a1e0 100644 --- a/pyfepdf.py +++ b/pyfepdf.py @@ -23,9 +23,9 @@ "Módulo para generar PDF de facturas electrónicas" __author__ = "Mariano Reingart " -__copyright__ = "Copyright (C) 2011-2018 Mariano Reingart" +__copyright__ = "Copyright (C) 2011-2019 Mariano Reingart" __license__ = "GPL 3.0" -__version__ = "1.09b" +__version__ = "1.09c" DEBUG = False HOMO = False @@ -120,6 +120,9 @@ class FEPDF: (1, 6, 11, 19, 51): 'Factura', (2, 7, 12, 20, 52): 'Nota de Débito', (3, 8, 13, 21, 53): 'Nota de Crédito', + (201, 206, 211): 'Factura de Crédito MiPyMEs', + (202, 207, 212): 'Nota de Débito MiPyMEs', + (203, 208, 213): 'Nota de Crédito MiPyMEs', (4, 9, 15, 54): 'Recibo', (10, 5): 'Nota de Venta al contado', (60, 61): 'Cuenta de Venta y Líquido producto', @@ -127,9 +130,9 @@ class FEPDF: (91, ): 'Remito', (39, 40): '???? (R.G. N° 3419)'} - letras_fact = {(1, 2, 3, 4, 5, 39, 60, 63): 'A', - (6, 7, 8, 9, 10, 40, 61, 64): 'B', - (11, 12, 13, 15): 'C', + letras_fact = {(1, 2, 3, 4, 5, 39, 60, 63, 201, 202, 203): 'A', + (6, 7, 8, 9, 10, 40, 61, 64, 206, 207, 208): 'B', + (11, 12, 13, 15, 211, 212, 213): 'C', (51, 52, 53, 54): 'M', (19, 20, 21): 'E', (91, ): 'R', @@ -299,9 +302,14 @@ def fmt_num(self, i, fmt="%0.2f", monetary=True): else: return '' - def fmt_imp(self, i): return self.fmt_num(i, "%0.2f") - def fmt_qty(self, i): return self.fmt_num(i, "%" + self.FmtCantidad + "f", False) - def fmt_pre(self, i): return self.fmt_num(i, "%" + self.FmtPrecio + "f") + def fmt_imp(self, i): + return self.fmt_num(i, "%0.2f") + + def fmt_qty(self, i): + return self.fmt_num(i, "%" + self.FmtCantidad + "f", False) + + def fmt_pre(self, i): + return self.fmt_num(i, "%" + self.FmtPrecio + "f") def fmt_iva(self, i): if int(i) in self.ivas_ds: @@ -1028,7 +1036,7 @@ def MostrarPDF(self, archivo, imprimir=False): HOMO = True # datos generales del encabezado: - tipo_cbte = 19 if '--expo' in sys.argv else 1 + tipo_cbte = 19 if '--expo' in sys.argv else 201 punto_vta = 4000 fecha = datetime.datetime.now().strftime("%Y%m%d") concepto = 3 From 56a56eb68dff2acd60f1de8d38ca6802945ed849 Mon Sep 17 00:00:00 2001 From: Sando Date: Sat, 8 Jun 2019 23:03:08 -0300 Subject: [PATCH 09/16] RECE1: Agrego fecha cbte asoc a archivo de entrada --- rece1.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/rece1.py b/rece1.py index 4d5342031..59bc560b2 100644 --- a/rece1.py +++ b/rece1.py @@ -13,9 +13,9 @@ "Módulo de Intefase para archivos de texto (mercado interno versión 1)" __author__ = "Mariano Reingart (reingart@gmail.com)" -__copyright__ = "Copyright (C) 2010-2015 Mariano Reingart" +__copyright__ = "Copyright (C) 2010-2019 Mariano Reingart" __license__ = "GPL 3.0" -__version__ = "1.37b" +__version__ = "1.37c" import datetime import os @@ -111,6 +111,7 @@ ('tipo_reg', 1, N), # 3: comprobante asociado ('tipo', 3, N), ('pto_vta', 4, N), ('nro', 8, N), + ('fecha', 8, N), ] OPCIONAL = [ @@ -214,7 +215,7 @@ def autorizar(ws, entrada, salida, informar_caea=False): raise RuntimeError("No se pudieron leer los registros de la entrada") # ajusto datos para pruebas en depuración (nro de cbte. / fecha) - if '--testing' in sys.argv and DEBUG: + if '--testing' in sys.argv: encabezado['punto_vta'] = 9998 cbte_nro = int(ws.CompUltimoAutorizado(encabezado['tipo_cbte'], encabezado['punto_vta'])) + 1 @@ -271,6 +272,9 @@ def autorizar(ws, entrada, salida, informar_caea=False): 'motivos_obs': ws.Obs, 'err_code': str(ws.ErrCode), 'err_msg': ws.ErrMsg, + 'cbt_desde': ws.CbtDesde, + 'cbt_hasta': ws.CbtHasta, + 'fecha_cbte': ws.FechaCbte, 'reproceso': ws.Reproceso, 'emision_tipo': ws.EmisionTipo, }) From acfc582c36df915840ed5b69dec89301e10056f9 Mon Sep 17 00:00:00 2001 From: Sando Date: Sun, 9 Jun 2019 17:57:09 -0300 Subject: [PATCH 10/16] Padron: Agrego metodo buscar CUIT por nombre via FTS (full text search) --- padron.py | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/padron.py b/padron.py index a131c7b0a..d60614dfc 100644 --- a/padron.py +++ b/padron.py @@ -16,9 +16,9 @@ # http://www.sistemasagiles.com.ar/trac/wiki/PadronContribuyentesAFIP __author__ = "Mariano Reingart " -__copyright__ = "Copyright (C) 2014-2016 Mariano Reingart" +__copyright__ = "Copyright (C) 2014-2019 Mariano Reingart" __license__ = "GPL 3.0" -__version__ = "1.07e" +__version__ = "1.08a" import csv @@ -34,7 +34,7 @@ from email.utils import formatdate import sys import warnings -from .utils import leer, escribir, N, A, I, get_install_dir, safe_console, \ +from utils import leer, escribir, N, A, I, get_install_dir, safe_console, \ inicializar_y_capturar_excepciones_simple, WebClient, norm, \ exception_info @@ -77,7 +77,7 @@ class PadronAFIP(): _public_methods_ = ['Buscar', 'Descargar', 'Procesar', 'Guardar', 'ConsultarDomicilios', 'Consultar', 'Conectar', - 'DescargarConstancia', 'MostrarPDF', + 'DescargarConstancia', 'MostrarPDF', 'BuscarCUIT', "ObtenerTablaParametros", ] _public_attrs_ = ['InstallDir', 'Traceback', 'Excepcion', 'Version', @@ -288,6 +288,17 @@ def ConsultarDomicilios(self, nro_doc, tipo_doc=80, cat_iva=None): self.domicilios = [fila['direccion'] for fila in filas] return len(filas) + @inicializar_y_capturar_excepciones_simple + def BuscarCUIT(self, denominacion, limite=10): + "Busca por nombre, devuelve una lista con tipo y nro de documento" + sql = ("SELECT tipo_doc, nro_doc, denominacion " + "FROM padron_fts WHERE denominacion MATCH ? " + "LIMIT ?") + denominacion = denominacion.replace(" ", "*") + self.cursor.execute(sql, ["*{}*".format(denominacion), limite]) + filas = self.cursor.fetchall() + return [dict(fila) for fila in filas] + @inicializar_y_capturar_excepciones_simple def Guardar(self, tipo_doc, nro_doc, denominacion, cat_iva, direccion, email, imp_ganancias='NI', imp_iva='NI', monotributo='NI', From ac601a90088906ea9076a7afbbfd199beaeef60c Mon Sep 17 00:00:00 2001 From: Sando Date: Sun, 9 Jun 2019 18:23:33 -0300 Subject: [PATCH 11/16] WSRemCarne: Ajusto v3 * QR * CodAutorizacion * Serializacion fecha (JSON) * ConfigParser --- wsremcarne.py | 41 ++++++++++++++++++++--------------------- 1 file changed, 20 insertions(+), 21 deletions(-) diff --git a/wsremcarne.py b/wsremcarne.py index 9ad87b67c..e2a8f1156 100644 --- a/wsremcarne.py +++ b/wsremcarne.py @@ -14,25 +14,25 @@ import time import sys import os -from .utils import json, BaseWS, inicializar_y_capturar_excepciones, get_install_dir -from . import utils +from utils import json, BaseWS, inicializar_y_capturar_excepciones, get_install_dir, json_serializer +import utils from pysimplesoap.client import SoapFault import traceback -from .utils import date + """Módulo para obtener Remito Electronico Carnico: -del web service WSRemCarne versión 1.0 de AFIP (RG4256/18 y RG4303/18) +del web service WSRemCarne versión 3.0 de AFIP (RG4256/18 y RG4303/18) """ __author__ = "Mariano Reingart " -__copyright__ = "Copyright (C) 2018 Mariano Reingart" +__copyright__ = "Copyright (C) 2018-2019 Mariano Reingart" __license__ = "LGPL 3.0" -__version__ = "1.01a" +__version__ = "1.01b" LICENCIA = """ wsremcarne.py: Interfaz para generar Remito Electrónico Cárnico AFIP v1.0 Remito de Carnes y subproductos derivados de la faena de bovinos y porcinos Resolución General 4256/18 y Resolución General 4303/18. -Copyright (C) 2018 Mariano Reingart reingart@gmail.com +Copyright (C) 2018-2019 Mariano Reingart reingart@gmail.com http://www.sistemasagiles.com.ar/trac/wiki/RemitoElectronicoCarnico Este progarma es software libre, se entrega ABSOLUTAMENTE SIN GARANTIA @@ -184,9 +184,10 @@ def AgregarVehiculo(self, dominio_vehiculo=None, dominio_acoplado=None, **kwargs return True @inicializar_y_capturar_excepciones - def AgregarMercaderia(self, orden=None, cod_tipo_prod=None, cantidad=None, unidades=None, tropa=None, **kwargs): + def AgregarMercaderia(self, orden=None, cod_tipo_prod=None, kilos=None, unidades=None, tropa=None, kilos_rec=None, unidades_rec=None, **kwargs): "Agrega la información referente a la mercadería del remito electrónico cárnico" - mercaderia = dict(orden=orden, tropa=tropa, codTipoProd=cod_tipo_prod, cantidad=cantidad, unidadMedida=unidades) + mercaderia = dict(orden=orden, tropa=tropa, codTipoProd=cod_tipo_prod, kilos=kilos, unidades=unidades, + kilosRec=kilos_rec, unidadesRec=unidades_rec) self.remito['arrayMercaderias'].append(dict(mercaderia=mercaderia)) return True @@ -227,7 +228,7 @@ 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('datosAutorizacion') + datos_aut = ret.get('datosEmision') if datos_aut: self.NroRemito = datos_aut.get('nroRemito') self.CodAutorizacion = datos_aut.get('codAutorizacion') @@ -237,10 +238,8 @@ def AnalizarRemito(self, ret, archivo=None): self.Resultado = ret.get('resultado') self.QR = ret.get('qr') or "" if archivo: - qr = base64.b64decode(self.QR) - f = open(archivo, "wb") - f.write(qr) - f.close() + with open(archivo, "wb") as f: + f.write(self.QR) @inicializar_y_capturar_excepciones def EmitirRemito(self, archivo="qr.png"): @@ -460,7 +459,7 @@ def ConsultarCodigosDomicilio(self, cuit_titular=1, sep="||"): win32com.server.register.UseCommandLine(WSRemCarne) sys.exit(0) - from configparser import SafeConfigParser + from configparser import ConfigParser try: @@ -473,7 +472,7 @@ def ConsultarCodigosDomicilio(self, cuit_titular=1, sep="||"): print("Usando configuración:", arg) CONFIG_FILE = arg - config = SafeConfigParser() + config = ConfigParser() config.read(CONFIG_FILE) CERT = config.get('WSAA', 'CERT') PRIVATEKEY = config.get('WSAA', 'PRIVATEKEY') @@ -506,7 +505,7 @@ def ConsultarCodigosDomicilio(self, cuit_titular=1, sep="||"): print("wsremcarne_url:", wsremcarne_url) # obteniendo el TA - from .wsaa import WSAA + from wsaa import WSAA wsaa = WSAA() ta = wsaa.Autenticar("wsremcarne", CERT, PRIVATEKEY, wsaa_url, debug=DEBUG) if not ta: @@ -578,7 +577,7 @@ def ConsultarCodigosDomicilio(self, cuit_titular=1, sep="||"): rec['viaje'] = dict(cuit_transportista='20333333334', cuit_conductor='20333333334', fecha_inicio_viaje='2018-10-01', distancia_km=999) rec['viaje']['vehiculo'] = dict(dominio_vehiculo='AAA000', dominio_acoplado='ZZZ000') - rec['mercaderias'] = [dict(orden=1, tropa=1, cod_tipo_prod='2.13', cantidad=10, unidades=1)] + rec['mercaderias'] = [dict(orden=1, tropa=1, cod_tipo_prod='2.13', kilos=10, unidades=1)] rec['datos_autorizacion'] = None # dict(nro_remito=None, cod_autorizacion=None, fecha_emision=None, fecha_vencimiento=None) rec['contingencias'] = [dict(tipo=1, observacion="anulacion")] with open(ENTRADA, "w") as archivo: @@ -600,9 +599,9 @@ def ConsultarCodigosDomicilio(self, cuit_titular=1, sep="||"): if '--generar' in sys.argv: if '--testing' in sys.argv: - wsremcarne.LoadTestXML("tests/xml/wsremcarne_generar_response_ok_beta.xml") # cargo respuesta + wsremcarne.LoadTestXML("tests/xml/wsremcarne.xml") # cargo respuesta - ok = wsremcarne.GenerarRemito(id_req=rec['id_req']) + ok = wsremcarne.GenerarRemito(id_req=rec['id_req'], archivo="qr.jpg") if '--emitir' in sys.argv: ok = wsremcarne.EmitirRemito() @@ -637,7 +636,7 @@ def ConsultarCodigosDomicilio(self, cuit_titular=1, sep="||"): if '--grabar' in sys.argv: with open(SALIDA, "w") as archivo: - json.dump(rec, archivo, sort_keys=True, indent=4) + json.dump(rec, archivo, sort_keys=True, indent=4, default=json_serializer) # Recuperar parámetros: From af9da9b22bc639effcf7acc4e3513b463e603420 Mon Sep 17 00:00:00 2001 From: Sando Date: Sun, 9 Jun 2019 18:47:25 -0300 Subject: [PATCH 12/16] WSBFEV1: Factura de Credito Electronica MiPyme (FCE) RG4367/18 * Metodo AgregarCmpAsoc(tipo, pto_vta, nro, cuit, fecha) * Metodo AgregarOpcional(opcional_id, valor) * Ajuste fecha_venc_pago --- wsbfev1.py | 69 +++++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 60 insertions(+), 9 deletions(-) diff --git a/wsbfev1.py b/wsbfev1.py index 34f6b90fc..2ec5a5fee 100644 --- a/wsbfev1.py +++ b/wsbfev1.py @@ -16,15 +16,15 @@ """ __author__ = "Mariano Reingart (reingart@gmail.com)" -__copyright__ = "Copyright (C) 2013-2016 Mariano Reingart" +__copyright__ = "Copyright (C) 2013-2019 Mariano Reingart" __license__ = "GPL 3.0" -__version__ = "1.06g" +__version__ = "1.07a" import datetime import decimal import os import sys -from .utils import inicializar_y_capturar_excepciones, BaseWS, get_install_dir +from utils import inicializar_y_capturar_excepciones, BaseWS, get_install_dir HOMO = False LANZAR_EXCEPCIONES = True # valor por defecto: True @@ -33,7 +33,8 @@ class WSBFEv1(BaseWS): "Interfaz para el WebService de Bono Fiscal Electrónico V1 (FE Bs. Capital)" - _public_methods_ = ['CrearFactura', 'AgregarItem', 'Authorize', 'GetCMP', + _public_methods_ = ['CrearFactura', 'AgregarItem', 'AgregarCmpAsoc', + 'Authorize', 'GetCMP', 'AgregarOpcional', 'GetParamMon', 'GetParamTipoCbte', 'GetParamUMed', 'GetParamTipoIVA', 'GetParamNCM', 'GetParamZonas', 'GetParamTipoDoc', @@ -41,7 +42,7 @@ class WSBFEv1(BaseWS): 'GetParamCtz', 'LoadTestXML', 'AnalizarXml', 'ObtenerTagXml', 'DebugLog', 'SetParametros', 'SetTicketAcceso', 'GetParametro', - 'Dummy', 'Conectar', 'SetTicketAcceso'] + 'Dummy', 'Conectar'] _public_attrs_ = ['Token', 'Sign', 'Cuit', 'AppServerStatus', 'DbServerStatus', 'AuthServerStatus', 'XmlRequest', 'XmlResponse', 'Version', @@ -91,7 +92,7 @@ def CrearFactura(self, tipo_doc=80, nro_doc=23111111113, imp_total=0.0, imp_neto=0.0, impto_liq=0.0, imp_tot_conc=0.0, impto_liq_rni=0.00, imp_op_ex=0.00, imp_perc=0.00, imp_iibb=0.00, imp_perc_mun=0.00, imp_internos=0.00, - imp_moneda_id=0, imp_moneda_ctz=1.0, **kwargs): + imp_moneda_id=0, imp_moneda_ctz=1.0, fecha_venc_pago=None, **kwargs): "Creo un objeto factura (interna)" # Creo una factura para bonos fiscales electrónicos @@ -104,7 +105,9 @@ def CrearFactura(self, tipo_doc=80, nro_doc=23111111113, 'imp_perc': imp_perc, 'imp_perc_mun': imp_perc_mun, 'imp_iibb': imp_iibb, 'imp_internos': imp_internos, 'imp_moneda_id': imp_moneda_id, 'imp_moneda_ctz': imp_moneda_ctz, + 'fecha_venc_pago': fecha_venc_pago, 'cbtes_asoc': [], + 'opcionales': [], 'iva': [], 'detalles': [], } @@ -127,6 +130,22 @@ def AgregarItem(self, ncm, sec, ds, qty, umed, precio, bonif, iva_id, imp_total, }) return True + def AgregarCmpAsoc(self, tipo=1, pto_vta=0, nro=0, cuit=None, fecha=None, **kwarg): + "Agrego un comprobante asociado a una factura (interna)" + cmp_asoc = {'tipo': tipo, 'pto_vta': pto_vta, 'nro': nro} + if cuit is not None: + cmp_asoc['cuit'] = cuit + if fecha is not None: + cmp_asoc['fecha'] = fecha + self.factura['cbtes_asoc'].append(cmp_asoc) + return True + + def AgregarOpcional(self, opcional_id=0, valor="", **kwarg): + "Agrego un dato opcional a una factura (interna)" + op = { 'opcional_id': opcional_id, 'valor': valor } + self.factura['opcionales'].append(op) + return True + @inicializar_y_capturar_excepciones def Authorize(self, id): "Autoriza la factura cargada en memoria" @@ -150,6 +169,7 @@ def Authorize(self, id): 'Imp_perc': f['imp_perc'], 'Imp_perc_mun': f['imp_perc_mun'], 'Imp_iibb': f['imp_iibb'], 'Imp_internos': f['imp_internos'], + 'Fecha_vto_pago': f['fecha_venc_pago'], 'Items': [ {'Item': { 'Pro_codigo_ncm': d['ncm'], @@ -162,6 +182,19 @@ def Authorize(self, id): 'Imp_total': d['imp_total'], 'Iva_id': d['iva_id'], }} for d in f['detalles']], + 'CbtesAsoc': f['cbtes_asoc'] and [ + {'CbteAsoc': { + 'Tipo_cbte': cbte_asoc['tipo'], + 'Punto_vta': cbte_asoc['pto_vta'], + 'Cbte_nro': cbte_asoc['nro'], + 'Cuit': cbte_asoc.get('cuit'), + 'Fecha_cbte': cbte_asoc.get('fecha'), + }} for cbte_asoc in f['cbtes_asoc']] or None, + 'Opcionales': [ + {'Opcional': { + 'Id': opcional['opcional_id'], + 'Valor': opcional['valor'], + }} for opcional in f['opcionales']] or None, }) result = ret['BFEAuthorizeResult'] @@ -456,7 +489,7 @@ def p_assert_eq(a, b): # Setear token y sing de autorización (pasos previos) # obteniendo el TA para pruebas - from .wsaa import WSAA + from wsaa import WSAA ta = WSAA().Autenticar("wsbfe", "reingart.crt", "reingart.key") wsbfev1.SetTicketAcceso(ta) @@ -480,7 +513,7 @@ def p_assert_eq(a, b): if "--prueba" in sys.argv: try: # Establezco los valores de la factura a autorizar: - tipo_cbte = '--nc' in sys.argv and 3 or 1 # FC/NC Expo (ver tabla de parámetros) + tipo_cbte = '--nc' in sys.argv and 3 or 201 # FC/NC Expo (ver tabla de parámetros) punto_vta = 5 tipo_doc = 80 nro_doc = 23111111113 @@ -495,6 +528,7 @@ def p_assert_eq(a, b): impto_liq_rni = imp_tot_conc = imp_op_ex = "0.00" imp_perc = imp_iibb = imp_perc_mun = imp_internos = "0.00" imp_total = "471.90" + fecha_venc_pago = fecha_cbte if "--fce" in sys.argv else None # Creo una factura (internamente, no se llama al WebService): ok = wsbfev1.CrearFactura(tipo_doc, nro_doc, @@ -502,7 +536,7 @@ def p_assert_eq(a, b): imp_total, imp_neto, impto_liq, imp_tot_conc, impto_liq_rni, imp_op_ex, imp_perc, imp_iibb, imp_perc_mun, imp_internos, - imp_moneda_id, imp_moneda_ctz) + imp_moneda_id, imp_moneda_ctz, fecha_venc_pago) # Agrego un item: ncm = '7308.10.00' @@ -528,6 +562,23 @@ def p_assert_eq(a, b): imp_total = "229.90" ok = wsbfev1.AgregarItem(ncm, sec, ds, qty, umed, precio, bonif, iva_id, imp_total) + # comprobantes asociados (notas de crédito / débito) + if True: + tipo = 91 + pto_vta = 4001 + nro = 1 + cuit = "20267565393" + # obligatorio en Factura de Crédito Electrónica MiPyMEs (FCE): + fecha_cbte = fecha_cbte if "--fce" in sys.argv else None + wsbfev1.AgregarCmpAsoc(tipo, pto_vta, nro, cuit, fecha_cbte) + + # datos de Factura de Crédito Electrónica MiPyMEs (FCE): + if '--fce' in sys.argv: + wsbfev1.AgregarOpcional(2101, "2850590940090418135201") # CBU + wsbfev1.AgregarOpcional(2102, "pyafipws") # alias + if tipo_cbte in (203, 208, 213): + wsbfev1.AgregarOpcional(22, "S") # Anulación + # id = "99000000000100" # número propio de transacción # obtengo el último ID y le adiciono 1 # (advertencia: evitar overflow y almacenar!) From da580ef4a5dbc447dec1339d9fd3f5d193a7714c Mon Sep 17 00:00:00 2001 From: Sando Date: Sun, 9 Jun 2019 19:49:46 -0300 Subject: [PATCH 13/16] COT: Agrego cambios menores (.pyw) --- cot.pyw | 110 ++++++++++++++++++++++++++++---------------------------- 1 file changed, 55 insertions(+), 55 deletions(-) diff --git a/cot.pyw b/cot.pyw index c37b88156..a4c4f3ee7 100644 --- a/cot.pyw +++ b/cot.pyw @@ -4,9 +4,9 @@ "Aplicativo Visual (Front-end) Remito Electrónico (COT) ARBA" from __future__ import with_statement - + __author__ = "Mariano Reingart (reingart@gmail.com)" -__copyright__ = "Copyright (C) 2013- Mariano Reingart" +__copyright__ = "Copyright (C) 2013-2019 Mariano Reingart" __license__ = "LGPL 3.0" import datetime @@ -19,10 +19,11 @@ import sys # importar gui2py (atajos) -import gui +import gui # establecer la configuración regional por defecto: -import wx, locale +import wx +import locale if sys.platform == "win32": locale.setlocale(locale.LC_ALL, 'Spanish_Argentina.1252') elif sys.platform == "linux2": @@ -38,71 +39,71 @@ from cot import COT # --- gui2py designer generated code starts --- -with gui.Window(name='mywin', title=u'COT: Remito Electr\xf3nico ARBA', - resizable=True, height='450px', left='180', top='24', - width='550px', bgcolor=u'#E0E0E0', fgcolor=u'#4C4C4C', +with gui.Window(name='mywin', title=u'COT: Remito Electr\xf3nico ARBA', + resizable=True, height='450px', left='180', top='24', + width='550px', bgcolor=u'#E0E0E0', fgcolor=u'#4C4C4C', image='', ): gui.StatusBar(name='statusbar', ) with gui.Panel(label=u'', name='panel', image='', ): - gui.TextBox(name='usuario', left='299', top='10', width='105', + gui.TextBox(name='usuario', left='299', top='10', width='105', value=u'20267565393', ) - gui.TextBox(name='clave', password=True, left='455', top='10', + gui.TextBox(name='clave', password=True, left='455', top='10', width='75', ) - gui.Line(name='line_25_556', height='3', left='24', top='390', + gui.Line(name='line_25_556', height='3', left='24', top='390', width='499', ) - gui.Button(label=u'Salir', name='salir', left='440', top='394', + gui.Button(label=u'Salir', name='salir', left='440', top='394', width='85', onclick='import sys; sys.exit(0)', ) - gui.ComboBox(name=u'url', - text=u'http://cot.test.arba.gov.ar/TransporteBienes/SeguridadCliente/presentarRemitos.do', - height='29', left='79', top='42', width='250', - bgcolor=u'#FFFFFF', - data_selection=u'http://cot.test.arba.gov.ar/TransporteBienes/SeguridadCliente/presentarRemitos.do', - fgcolor=u'#4C4C4C', - items=[u'https://cot.arba.gov.ar/TransporteBienes/SeguridadCliente/presentarRemitos.do', u'http://cot.test.arba.gov.ar/TransporteBienes/SeguridadCliente/presentarRemitos.do'], - selection=1, + gui.ComboBox(name=u'url', + text=u'http://cot.test.arba.gov.ar/TransporteBienes/SeguridadCliente/presentarRemitos.do', + height='29', left='79', top='42', width='250', + bgcolor=u'#FFFFFF', + data_selection=u'http://cot.test.arba.gov.ar/TransporteBienes/SeguridadCliente/presentarRemitos.do', + fgcolor=u'#4C4C4C', + items=[u'https://cot.arba.gov.ar/TransporteBienes/SeguridadCliente/presentarRemitos.do', u'http://cot.test.arba.gov.ar/TransporteBienes/SeguridadCliente/presentarRemitos.do'], + selection=1, string_selection=u'http://cot.test.arba.gov.ar/TransporteBienes/SeguridadCliente/presentarRemitos.do', ) - gui.Label(name='lblTest_273_363', height='17', left='234', top='15', + gui.Label(name='lblTest_273_363', height='17', left='234', top='15', width='58', text=u'Usuario:', ) - gui.Label(name='lblTest_273', height='17', left='410', top='14', + gui.Label(name='lblTest_273', height='17', left='410', top='14', width='58', text=u'Clave:', ) - gui.Gauge(name='gauge', height='18', left='20', top='365', + gui.Gauge(name='gauge', height='18', left='20', top='365', width='507', ) - gui.Label(id=228, name='lblTest_228', height='17', left='341', + gui.Label(id=228, name='lblTest_228', height='17', left='341', top='47', width='32', text=u'Carpeta:', ) - with gui.ListView(id=213, name=u'remitos', height='74', left='20', + with gui.ListView(id=213, name=u'remitos', height='74', left='20', top='180', width='510', item_count=0, sort_column=0, ): - gui.ListColumn(name=u'nro', text=u'N\xb0 \xdanico Remito', + gui.ListColumn(name=u'nro', text=u'N\xb0 \xdanico Remito', width=250, ) gui.ListColumn(name=u'proc', text=u'Procesado', ) - with gui.ListView(name=u'archivos', height='99', left='21', top='77', + with gui.ListView(name=u'archivos', height='99', left='21', top='77', width='509', item_count=0, sort_column=2, ): gui.ListColumn(name=u'txt', text='Archivo TXT', width=200, ) gui.ListColumn(name=u'xml', text='Archivo XML', ) gui.ListColumn(name=u'cuit', text='CUIT Empresa', ) gui.ListColumn(name=u'nro', text=u'N\xb0 Comprobante', ) gui.ListColumn(name=u'md5', text=u'C\xf3digo Integridad', ) - with gui.ListView(id=309, name=u'errores', height='99', left='20', + with gui.ListView(id=309, name=u'errores', height='99', left='20', top='259', width='510', item_count=0, sort_column=0, ): gui.ListColumn(name=u'codigo', text=u'C\xf3digo', width=100, ) - gui.ListColumn(name=u'descripcion', text=u'Descripci\xf3n Error', + gui.ListColumn(name=u'descripcion', text=u'Descripci\xf3n Error', width=400, ) - gui.TextBox(id=488, mask='date', name='fecha', - left='101', top='10', width='127', enabled=False, + gui.TextBox(id=488, mask='date', name='fecha', + left='101', top='10', width='127', enabled=False, value=datetime.date(2014, 4, 5), ) - gui.CheckBox(label=u'Fecha:', name=u'filtrar_fecha', height='24', - left='22', top='11', width='73', + gui.CheckBox(label=u'Fecha:', name=u'filtrar_fecha', height='24', + left='22', top='11', width='73', tooltip=u'filtrar por fecha', ) - gui.Label(id=2084, name='lblTest_228_2084', height='17', left='24', + gui.Label(id=2084, name='lblTest_228_2084', height='17', left='24', top='47', width='32', text=u'URL:', ) - gui.ComboBox(id=961, name=u'carpeta', text=u'datos', height='29', - left='412', top='42', width='118', bgcolor=u'#FFFFFF', - data_selection=u'datos', fgcolor=u'#4C4C4C', - items=[u'datos', u'procesados'], selection=0, + gui.ComboBox(id=961, name=u'carpeta', text=u'datos', height='29', + left='412', top='42', width='118', bgcolor=u'#FFFFFF', + data_selection=u'datos', fgcolor=u'#4C4C4C', + items=[u'datos', u'procesados'], selection=0, string_selection=u'datos', ) - gui.Button(label=u'Procesar', name=u'procesar', left='20', top='394', + gui.Button(label=u'Procesar', name=u'procesar', left='20', top='394', tooltip="Presentar el remito en ARBA", width='85', default=True, fgcolor=u'#4C4C4C', ) - gui.Button(label=u'Mover Procesados', name=u'mover', left='112', + gui.Button(label=u'Mover Procesados', name=u'mover', left='112', top='394', width='166', fgcolor=u'#4C4C4C', ) # --- gui2py designer generated code ends --- @@ -119,7 +120,7 @@ def getpass(username): password = passwd_db.get(str(username)) if not password: password = gui.prompt(message=u"Ingrese contraseña", - title="Usuario: %s" % username, + title="Usuario: %s" % username, password=True) or "" return password @@ -182,9 +183,9 @@ def abrir_archivo(evt): def procesar_archivo(item, enviar=False): "Enviar archivo a ARBA y analizar la respuesta" - + # establezco credenciales: - cuit = item['txt'][3:14] + cuit = item['txt'][3:14] cot.Usuario = panel['usuario'].value = cuit cot.Password = panel['clave'].value = getpass(cuit) cot.Conectar(panel['url'].text, trace=True) @@ -209,11 +210,11 @@ def procesar_archivo(item, enviar=False): if cot.Excepcion and enviar: gui.alert(cot.Traceback, cot.Excepcion) - + if cot.TipoError and enviar: gui.alert(cot.MensajeError, "Error %s: %s" % (cot.TipoError, cot.CodigoError)) - # actualizo los datos devueltos en el listado + # actualizo los datos devueltos en el listado item['cuit'] = cot.CuitEmpresa item['nro'] = cot.NumeroComprobante item['md5'] = cot.CodigoIntegridad @@ -226,7 +227,7 @@ def procesar_archivo(item, enviar=False): remitos.items = [] i = 0 while cot.LeerValidacionRemito(): - print "REMITO", i + print("REMITO", i) errores = [] remito = {'nro': cot.NumeroUnico, 'proc': cot.Procesado, 'errores': errores} @@ -234,7 +235,7 @@ def procesar_archivo(item, enviar=False): item['remitos'].append(remito) i += 1 while cot.LeerErrorValidacion(): - print "Error Validacion:", "|", cot.CodigoError, "|", cot.MensajeError + print("Error Validacion:", "|", cot.CodigoError, "|", cot.MensajeError) errores.append({'codigo': cot.CodigoError, 'descripcion': cot.MensajeError}) @@ -245,7 +246,7 @@ def cargar_errores(evt): errores = panel['errores'] errores.items = [] for i, error in enumerate(item['errores']): - print i, error + print(i, error) errores.items[i] = error def filtro_fecha(evt): @@ -257,11 +258,11 @@ def mover_archivos(evt=None): carpeta = panel['carpeta'].text if carpeta != "datos": gui.alert("No se puede mover archivos de carpeta %s" % carpeta) - + i = 0 - print panel['archivos'].items + print(panel['archivos'].items) for item in panel['archivos'].items: - procesado = all([remito.get('proc', 'NO') == 'SI' + procesado = all([remito.get('proc', 'NO') == 'SI' for remito in item.get('remitos', [])]) if procesado and item.get('remitos'): for fn in (item['txt'], item['xml']): @@ -270,13 +271,13 @@ def mover_archivos(evt=None): try: os.rename(fn0, fn1) i += 1 - except Exception, e: - gui.alert(unicode(e), "No se puede mover %s" % fn) + except Exception as e: + gui.alert(e, "No se puede mover %s" % fn) gui.alert("Se movieron: %s archivos" % i) listar_archivos() -panel['archivos'].onitemselected = cargar_archivo +panel['archivos'].onitemselected = cargar_archivo panel['archivos'].onmousedclick = abrir_archivo panel['remitos'].onitemselected = cargar_errores panel['filtrar_fecha'].onclick = filtro_fecha @@ -290,8 +291,7 @@ panel['clave'].onchange = grabar_clave if __name__ == "__main__": mywin.show() mywin.title = u"%s - %s" % (mywin.title, cot.Version.decode("latin1")) - mywin['statusbar'].text = "" + mywin['statusbar'].text = "" listar_archivos() gui.main_loop() passwd_db.close() - From 37f6d2876467dd5b2a83382b8329af7ccaeee19f Mon Sep 17 00:00:00 2001 From: Sando Date: Tue, 11 Jun 2019 17:43:27 -0300 Subject: [PATCH 14/16] Utils: Remuevo dependencia parse_version [Python3] --- utils.py | 43 +++++++++++++++++++++---------------------- 1 file changed, 21 insertions(+), 22 deletions(-) diff --git a/utils.py b/utils.py index 719298543..fc5e9b229 100644 --- a/utils.py +++ b/utils.py @@ -13,34 +13,39 @@ "Módulo con funciones auxiliares para el manejo de errores y temas comunes" __author__ = "Mariano Reingart " -__copyright__ = "Copyright (C) 2013 Mariano Reingart" +__copyright__ = "Copyright (C) 2013-2019 Mariano Reingart" __license__ = "GPL 3.0" -from io import IOBase import datetime import functools +import httplib2 import inspect import locale -import socket -import sys +import mimetypes import os +import socket import stat +import sys import time import traceback +import unicodedata import warnings -from io import StringIO + +from configparser import SafeConfigParser from decimal import Decimal -from urllib.parse import urlencode -from urllib.parse import urlparse -import unicodedata -import mimetypes from email.generator import _make_boundary from html.parser import HTMLParser from http.cookies import SimpleCookie -from configparser import SafeConfigParser +from io import IOBase +from io import StringIO +from pysimplesoap.client import SimpleXMLElement +from pysimplesoap.client import SoapClient +from pysimplesoap.client import SoapFault +from pysimplesoap.client import parse_proxy +from pysimplesoap.client import set_http_wrapper +from urllib.parse import urlencode +from urllib.parse import urlparse -from pysimplesoap.client import SimpleXMLElement, SoapClient, SoapFault, parse_proxy, set_http_wrapper -from pkg_resources import parse_version try: import json @@ -51,11 +56,9 @@ print("para soporte de JSON debe instalar simplejson") json = None -import httplib2 DEBUG = False - # Funciones para manejo de errores: @@ -410,11 +413,9 @@ class WebClient: def __init__(self, location, enctype="multipart/form-data", trace=False, cacert=None, timeout=30): kwargs = {} - if parse_version(httplib2.__version__) >= parse_version('0.3.0'): - kwargs['timeout'] = timeout - if parse_version(httplib2.__version__) >= parse_version('0.7.0'): - kwargs['disable_ssl_certificate_validation'] = cacert is None - kwargs['ca_certs'] = cacert + kwargs['timeout'] = timeout + kwargs['disable_ssl_certificate_validation'] = cacert is None + kwargs['ca_certs'] = cacert self.http = httplib2.Http(**kwargs) self.trace = trace self.location = location @@ -754,7 +755,6 @@ def leer_dbf(formatos, conf_dbf): claves = [] for fmt in formato: clave, longitud, tipo = fmt[0:3] - #import pdb; pdb.set_trace() clave_dbf = dar_nombre_campo_dbf(clave, claves) claves.append(clave_dbf) v = d.get(clave_dbf) @@ -787,7 +787,7 @@ def verifica(ver_list, res_dict, difs): res_dict[k] = float(res_dict[k]) if isinstance(v, list): # verifico que ambas listas tengan la misma cantidad de elementos: - if v and not k in res_dict and v: + if v and k not in res_dict and v: difs.append("falta tag %s: %s %s" % (k, repr(v), repr(res_dict.get(k)))) elif len(res_dict.get(k, [])) != len(v or []): difs.append("tag %s len !=: %s %s" % (k, repr(v), repr(res_dict.get(k)))) @@ -846,7 +846,6 @@ def intercept(self, s): return s.encode(self.encoding, self.errors) sys.stdout = SafeWriter(sys.stdout) - #sys.stderr = SafeWriter(sys.stderr) print("Encodign in %s" % locale.getpreferredencoding()) From 765695d5f8aeeedb62624c37259d86da35808990 Mon Sep 17 00:00:00 2001 From: Sando Date: Thu, 13 Jun 2019 14:45:46 -0300 Subject: [PATCH 15/16] Restauro imports --- padron.py | 10 ++++++---- wsbfev1.py | 8 +++++--- wsfev1.py | 6 +++--- wsfexv1.py | 13 ++++++------- wsremcarne.py | 6 +++--- 5 files changed, 23 insertions(+), 20 deletions(-) diff --git a/padron.py b/padron.py index d60614dfc..85ee5b4a4 100644 --- a/padron.py +++ b/padron.py @@ -31,12 +31,14 @@ import urllib.error import urllib.parse import zipfile -from email.utils import formatdate import sys import warnings -from utils import leer, escribir, N, A, I, get_install_dir, safe_console, \ - inicializar_y_capturar_excepciones_simple, WebClient, norm, \ - exception_info + +from email.utils import formatdate +from .utils import (leer, escribir, N, A, I, get_install_dir, safe_console, + inicializar_y_capturar_excepciones_simple, WebClient, norm, + exception_info, + ) # formato y ubicación archivo completo de la condición tributaria según RG 1817 diff --git a/wsbfev1.py b/wsbfev1.py index 2ec5a5fee..ef846afa0 100644 --- a/wsbfev1.py +++ b/wsbfev1.py @@ -24,7 +24,7 @@ import decimal import os import sys -from utils import inicializar_y_capturar_excepciones, BaseWS, get_install_dir +from .utils import inicializar_y_capturar_excepciones, BaseWS, get_install_dir HOMO = False LANZAR_EXCEPCIONES = True # valor por defecto: True @@ -489,7 +489,7 @@ def p_assert_eq(a, b): # Setear token y sing de autorización (pasos previos) # obteniendo el TA para pruebas - from wsaa import WSAA + from .wsaa import WSAA ta = WSAA().Autenticar("wsbfe", "reingart.crt", "reingart.key") wsbfev1.SetTicketAcceso(ta) @@ -632,7 +632,9 @@ def p_assert_eq(a, b): if "--params" in sys.argv: import codecs import locale - sys.stdout = codecs.getwriter('latin1')(sys.stdout) + if sys.stdout.encoding is None: + sys.stdout = codecs.getwriter(locale.getpreferredencoding())(sys.stdout, "replace") + sys.stderr = codecs.getwriter(locale.getpreferredencoding())(sys.stderr, "replace") print("=== Tipos de Comprobante ===") print('\n'.join(wsbfev1.GetParamTipoCbte())) diff --git a/wsfev1.py b/wsfev1.py index 47f1810e7..08d27d14f 100644 --- a/wsfev1.py +++ b/wsfev1.py @@ -31,7 +31,7 @@ import decimal import os import sys -from utils import verifica, inicializar_y_capturar_excepciones, BaseWS, get_install_dir +from .utils import verifica, inicializar_y_capturar_excepciones, BaseWS, get_install_dir HOMO = False # solo homologación TYPELIB = False # usar librería de tipos (TLB) @@ -768,7 +768,7 @@ def CAEARegInformativo(self): 'PtoVta': cbte_asoc['pto_vta'], 'Nro': cbte_asoc['nro'], 'Cuit': cbte_asoc.get('cuit'), - 'CbteFch': cbtes_asoc.get('fecha'), + 'CbteFch': cbte_asoc.get('fecha'), }} for cbte_asoc in f['cbtes_asoc']] if f['cbtes_asoc'] else None, @@ -996,7 +996,7 @@ def main(): sys.exit(0) # obteniendo el TA para pruebas - from wsaa import WSAA + from .wsaa import WSAA ta = WSAA().Autenticar("wsfe", "reingart.crt", "reingart.key", debug=True) wsfev1.SetTicketAcceso(ta) wsfev1.Cuit = "20267565393" diff --git a/wsfexv1.py b/wsfexv1.py index fc75e9fe0..057822c54 100644 --- a/wsfexv1.py +++ b/wsfexv1.py @@ -17,15 +17,15 @@ """ __author__ = "Mariano Reingart (reingart@gmail.com)" -__copyright__ = "Copyright (C) 2011-2015 Mariano Reingart" +__copyright__ = "Copyright (C) 2011-2019 Mariano Reingart" __license__ = "GPL 3.0" -__version__ = "1.08f" +__version__ = "1.09a" import datetime import decimal import os import sys -from utils import inicializar_y_capturar_excepciones, BaseWS, get_install_dir +from .utils import inicializar_y_capturar_excepciones, BaseWS, get_install_dir HOMO = False WSDL = "https://wswhomo.afip.gov.ar/wsfexv1/service.asmx?WSDL" @@ -604,7 +604,7 @@ def p_assert_eq(a, b): # Setear token y sign de autorización (pasos previos) # obteniendo el TA para pruebas - from wsaa import WSAA + from .wsaa import WSAA ta = WSAA().Autenticar("wsfex", "reingart.crt", "reingart.key") wsfexv1.SetTicketAcceso(ta) @@ -748,8 +748,7 @@ def p_assert_eq(a, b): sys.stderr = codecs.getwriter(locale.getpreferredencoding())(sys.stderr, "replace") print("\n=== Cotizacion ===") - print('\n'.join(wsfexv1.GetParamMonConCotizacion(sep='|'))) - + print('\n'.join(wsfexv1.GetParamMonConCotizacion())) print("\n=== Incoterms ===") print('\n'.join(wsfexv1.GetParamIncoterms(sep='||'))) @@ -763,7 +762,7 @@ def p_assert_eq(a, b): print("=== Tipos Expo ===") print('\n'.join(wsfexv1.GetParamTipoExpo(sep='||'))) - print ("=== Monedas ===") + print("=== Monedas ===") print('\n'.join(wsfexv1.GetParamMon(sep='||'))) print("=== Unidades de medida ===") diff --git a/wsremcarne.py b/wsremcarne.py index e2a8f1156..b4d0c6d45 100644 --- a/wsremcarne.py +++ b/wsremcarne.py @@ -14,8 +14,8 @@ import time import sys import os -from utils import json, BaseWS, inicializar_y_capturar_excepciones, get_install_dir, json_serializer -import utils +from .utils import json, BaseWS, inicializar_y_capturar_excepciones, get_install_dir, json_serializer +from . import utils from pysimplesoap.client import SoapFault import traceback @@ -505,7 +505,7 @@ def ConsultarCodigosDomicilio(self, cuit_titular=1, sep="||"): print("wsremcarne_url:", wsremcarne_url) # obteniendo el TA - from wsaa import WSAA + from .wsaa import WSAA wsaa = WSAA() ta = wsaa.Autenticar("wsremcarne", CERT, PRIVATEKEY, wsaa_url, debug=DEBUG) if not ta: From 3528d49f6e68b74423dd9555bf48bbf40db5e486 Mon Sep 17 00:00:00 2001 From: Sando Date: Thu, 13 Jun 2019 15:03:22 -0300 Subject: [PATCH 16/16] Setup: Agrego dependencias #PyAr#2 --- setup.py | 36 +++++++++++++++++++++++++++--------- 1 file changed, 27 insertions(+), 9 deletions(-) diff --git a/setup.py b/setup.py index 4be73f64e..c7192ae69 100644 --- a/setup.py +++ b/setup.py @@ -8,14 +8,16 @@ "Creador de instalador para PyAfipWs" __author__ = "Mariano Reingart (reingart@gmail.com)" -__copyright__ = "Copyright (C) 2008-2016 Mariano Reingart" +__copyright__ = "Copyright (C) 2008-2019 Mariano Reingart" + -from distutils.core import setup import glob import os import subprocess -import warnings import sys +import warnings + +from setuptools import setup try: rev = subprocess.check_output(['hg', 'tip', '--template', '{rev}'], @@ -89,8 +91,8 @@ # add "Microsoft Visual C++ 2008 Redistributable Package (x86)" if os.path.exists(r"c:\Program Files\Mercurial"): data_files += [( - ".", glob.glob(r'c:\Program Files\Mercurial\msvc*.dll') - + glob.glob(r'c:\Program Files\Mercurial\Microsoft.VC90.CRT.manifest'), + ".", glob.glob(r'c:\Program Files\Mercurial\msvc*.dll') + + glob.glob(r'c:\Program Files\Mercurial\Microsoft.VC90.CRT.manifest'), )] # fix permission denied runtime error on win32com.client.gencache.GenGeneratePath # (expects a __init__.py not pyc, also dicts.dat pickled or _LoadDicts/_SaveDicts will fail too) @@ -105,8 +107,8 @@ sys.path.insert(0, r"C:\Python27\Lib\site-packages\pythonwin") WX_DLL = ( - ".", glob.glob(r'C:\Python27\Lib\site-packages\pythonwin\mfc*.*') - + glob.glob(r'C:\Python27\Lib\site-packages\pythonwin\Microsoft.VC90.MFC.manifest'), + ".", glob.glob(r'C:\Python27\Lib\site-packages\pythonwin\mfc*.*') + + glob.glob(r'C:\Python27\Lib\site-packages\pythonwin\Microsoft.VC90.MFC.manifest'), ) else: WX_DLL = (".", [ @@ -600,6 +602,19 @@ except Exception as e: warnings.warn("Exception when converting the README format: %s" % e) +# dependencias + +requires_path = 'requirements.txt' +requires = [] + +if os.path.isfile(requires_path): + with open(requires_path) as f: + requires = f.read().splitlines() + +dependency_links = ['https://github.com/pysimplesoap/pysimplesoap/tarball/stable_py3k#egg=pysimplesoap', ] + # otras url probadas + # 'https://github.com/pysimplesoap/pysimplesoap/archivo/stable_py3k.zip#egg=pysimplesoap', + # 'git+https://github.com/pysimplesoap/pysimplesoap.git@stable_py3k#egg=pysimplesoap', setup(name="PyAfipWs", version=__version__, @@ -607,7 +622,7 @@ long_description=long_desc, author="Mariano Reingart", author_email="reingart@gmail.com", - url="https://github.com/reingart/pyafipws" if not 'py2exe' in sys.argv + url="https://github.com/reingart/pyafipws" if 'py2exe' not in sys.argv else "http://www.sistemasagiles.com.ar", license="GNU GPL v3+", options=opts, @@ -632,5 +647,8 @@ "Topic :: Software Development :: Object Brokering", ], keywords="webservice electronic invoice pdf traceability", - **kwargs + **kwargs, + install_requires=requires, + dependency_links=dependency_links, + zip_safe=False, )