From b40b7cebfc135377928d02add7916b5112017d27 Mon Sep 17 00:00:00 2001 From: carcaroff Date: Thu, 5 Apr 2018 18:40:35 -0300 Subject: [PATCH 1/5] [10.0]Date -> user's timezone dependent --- pytrustnfe/nfe/danfe.py | 58 +++++++++++++++++++++++++++++++------------------ 1 file changed, 37 insertions(+), 21 deletions(-) diff --git a/pytrustnfe/nfe/danfe.py b/pytrustnfe/nfe/danfe.py index 4cb1a83..e0ebd6b 100644 --- a/pytrustnfe/nfe/danfe.py +++ b/pytrustnfe/nfe/danfe.py @@ -18,6 +18,11 @@ from reportlab.lib.enums import TA_CENTER from reportlab.platypus import Paragraph, Image from reportlab.lib.styles import ParagraphStyle +import pytz +from datetime import datetime + +from odoo.tools import DEFAULT_SERVER_DATETIME_FORMAT as DTFT + def chunks(cString, nLen): for start in range(0, len(cString), nLen): @@ -34,10 +39,17 @@ def format_cnpj_cpf(value): return cValue -def getdateUTC(cDateUTC): - cDt = cDateUTC[0:10].split('-') +def getdateUTC(cDateUTC, timezone): + print(cDateUTC) + dt = cDateUTC[0:19] + if timezone and len(cDateUTC) > 16: + dt = datetime.strptime(dt, '%Y-%m-%dT%H:%M:%S') + dt = pytz.utc.localize(dt) + dt = timezone.normalize(dt) + dt = dt.strftime('%Y-%m-%dT%H:%M:%S') + cDt = dt[0:10].split('-') cDt.reverse() - return '/'.join(cDt), cDateUTC[11:16] + return '/'.join(cDt), dt[11:16] def format_number(cNumber): @@ -72,7 +84,8 @@ def get_image(path, width=1 * cm): class danfe(object): def __init__(self, sizepage=A4, list_xml=None, recibo=True, - orientation='portrait', logo=None, cce_xml=None): + orientation='portrait', logo=None, cce_xml=None, + timezone=None): self.width = 210 # 21 x 29,7cm self.height = 297 self.nLeft = 10 @@ -144,13 +157,13 @@ class danfe(object): self.NrPages = len(oPaginator) # Calculando nr. páginas if recibo: - self.recibo_entrega(oXML=oXML) + self.recibo_entrega(oXML=oXML, timezone=timezone) - self.ide_emit(oXML=oXML) - self.destinatario(oXML=oXML) + self.ide_emit(oXML=oXML, timezone=timezone) + self.destinatario(oXML=oXML, timezone=timezone) if oXML_cobr is not None: - self.faturas(oXML=oXML_cobr) + self.faturas(oXML=oXML_cobr, timezone=timezone) self.impostos(oXML=oXML) self.transportes(oXML=oXML) @@ -162,7 +175,7 @@ class danfe(object): # Gera o restante das páginas do XML for oPag in oPaginator[1:]: self.newpage() - self.ide_emit(oXML=oXML) + self.ide_emit(oXML=oXML, timezone=timezone) self.produtos(oXML=oXML, el_det=el_det, oPaginator=oPag, list_desc=list_desc, nHeight=77, list_cod_prod=list_cod_prod) @@ -170,11 +183,11 @@ class danfe(object): self.newpage() if cce_xml: for xml in cce_xml: - self._generate_cce(cce_xml=xml, oXML=oXML) + self._generate_cce(cce_xml=xml, oXML=oXML, timezone=timezone) self.newpage() self.canvas.save() - def ide_emit(self, oXML=None): + def ide_emit(self, oXML=None, timezone=None): elem_infNFe = oXML.find( ".//{http://www.portalfiscal.inf.br/nfe}infNFe") elem_protNFe = oXML.find( @@ -252,7 +265,8 @@ class danfe(object): self.stringcenter(self.nLeft + 116.5 + nW_Rect, self.nlin + 19.5, ' '.join(chunks(cChave, 4))) # Chave self.canvas.setFont('NimbusSanL-Regu', 8) - cDt, cHr = getdateUTC(tagtext(oNode=elem_protNFe, cTag='dhRecbto')) + cDt, cHr = getdateUTC( + tagtext(oNode=elem_protNFe, cTag='dhRecbto'), timezone) cProtocolo = tagtext(oNode=elem_protNFe, cTag='nProt') cDt = cProtocolo + ' - ' + cDt + ' ' + cHr nW_Rect = (self.width - self.nLeft - self.nRight - 110) / 2 @@ -322,7 +336,7 @@ class danfe(object): self.nlin += 48 - def destinatario(self, oXML=None): + def destinatario(self, oXML=None, timezone=None): elem_ide = oXML.find(".//{http://www.portalfiscal.inf.br/nfe}ide") elem_dest = oXML.find(".//{http://www.portalfiscal.inf.br/nfe}dest") nMr = self.width - self.nRight @@ -366,9 +380,10 @@ class danfe(object): else: cnpj_cpf = format_cnpj_cpf(tagtext(oNode=elem_dest, cTag='CPF')) self.string(nMr - 69, self.nlin + 7.5, cnpj_cpf) - cDt, cHr = getdateUTC(tagtext(oNode=elem_ide, cTag='dhEmi')) + cDt, cHr = getdateUTC(tagtext(oNode=elem_ide, cTag='dhEmi'), timezone) self.string(nMr - 24, self.nlin + 7.7, cDt + ' ' + cHr) - cDt, cHr = getdateUTC(tagtext(oNode=elem_ide, cTag='dhSaiEnt')) + cDt, cHr = getdateUTC( + tagtext(oNode=elem_ide, cTag='dhSaiEnt'), timezone) self.string(nMr - 24, self.nlin + 14.3, cDt + ' ' + cHr) # Dt saída cEnd = tagtext(oNode=elem_dest, cTag='xLgr') + ', ' + tagtext( oNode=elem_dest, cTag='nro') @@ -388,7 +403,7 @@ class danfe(object): self.nlin += 24 # Nr linhas ocupadas pelo bloco - def faturas(self, oXML=None): + def faturas(self, oXML=None, timezone=None): nMr = self.width - self.nRight @@ -421,7 +436,8 @@ class danfe(object): line_iter = iter(oXML[1:10]) # Salta elemt 1 e considera os próximos 9 for oXML_dup in line_iter: - cDt, cHr = getdateUTC(tagtext(oNode=oXML_dup, cTag='dVenc')) + cDt, cHr = getdateUTC(tagtext(oNode=oXML_dup, cTag='dVenc'), + timezone) self.string(self.nLeft + nCol + 1, self.nlin + nLin, tagtext(oNode=oXML_dup, cTag='nDup')) self.string(self.nLeft + nCol + 17, self.nlin + nLin, cDt) @@ -749,7 +765,7 @@ obsCont[@xCampo='NomeVendedor']") P.drawOn(self.canvas, (self.nLeft + 1) * mm, altura - h) self.nlin += 36 - def recibo_entrega(self, oXML=None): + def recibo_entrega(self, oXML=None, timezone=None): el_ide = oXML.find(".//{http://www.portalfiscal.inf.br/nfe}ide") el_dest = oXML.find(".//{http://www.portalfiscal.inf.br/nfe}dest") el_total = oXML.find(".//{http://www.portalfiscal.inf.br/nfe}total") @@ -781,7 +797,7 @@ obsCont[@xCampo='NomeVendedor']") self.string(self.width - self.nRight - nW + 2, self.nlin + 14, u"SÉRIE %s" % (tagtext(oNode=el_ide, cTag='serie'))) - cDt, cHr = getdateUTC(tagtext(oNode=el_ide, cTag='dhEmi')) + cDt, cHr = getdateUTC(tagtext(oNode=el_ide, cTag='dhEmi'), timezone) cTotal = format_number(tagtext(oNode=el_total, cTag='vNF')) cEnd = tagtext(oNode=el_dest, cTag='xNome') + ' - ' @@ -848,7 +864,7 @@ obsCont[@xCampo='NomeVendedor']") self.oPDF_IO.close() fileObj.write(pdf_out) - def _generate_cce(self, cce_xml=None, oXML=None): + def _generate_cce(self, cce_xml=None, oXML=None, timezone=None): self.canvas.setLineWidth(.2) # labels @@ -888,7 +904,7 @@ obsCont[@xCampo='NomeVendedor']") chave_acesso = tagtext(oNode=elem_infNFe, cTag='chNFe') self.string(82, 30, chave_acesso) data_correcao = getdateUTC(tagtext( - oNode=elem_infNFe, cTag='dhEvento')) + oNode=elem_infNFe, cTag='dhEvento'), timezone) data_correcao = data_correcao[0] + " " + data_correcao[1] self.string(82, 36, data_correcao) cce_id = elem_infNFe.values()[0] From 189d16660edcdd7d302e2d798d80d6924b252f87 Mon Sep 17 00:00:00 2001 From: carcaroff Date: Fri, 6 Apr 2018 17:05:07 -0300 Subject: [PATCH 2/5] [FIX]Agora vai --- pytrustnfe/nfe/danfe.py | 52 ++++++++++++++++++++++++++++++++++++------------- 1 file changed, 39 insertions(+), 13 deletions(-) diff --git a/pytrustnfe/nfe/danfe.py b/pytrustnfe/nfe/danfe.py index e0ebd6b..952310f 100644 --- a/pytrustnfe/nfe/danfe.py +++ b/pytrustnfe/nfe/danfe.py @@ -19,9 +19,7 @@ from reportlab.platypus import Paragraph, Image from reportlab.lib.styles import ParagraphStyle import pytz -from datetime import datetime - -from odoo.tools import DEFAULT_SERVER_DATETIME_FORMAT as DTFT +from datetime import datetime, timedelta def chunks(cString, nLen): @@ -39,14 +37,40 @@ def format_cnpj_cpf(value): return cValue -def getdateUTC(cDateUTC, timezone): - print(cDateUTC) +def getdateByTimezone(cDateUTC, timezone=None): + + ''' + Esse método trata a data recebida de acordo com o timezone do + usuário. O seu retorno é dividido em duas partes: + 1) A data em si; + 2) As horas; + :param cDateUTC: string contendo as informações da data + :param timezone: timezone do usuário do sistema + :return: data e hora convertidos para a timezone do usuário + ''' + + # Aqui cortamos a informação do timezone da string (+03:00) dt = cDateUTC[0:19] - if timezone and len(cDateUTC) > 16: + + # Verificamos se a string está completa (data + hora + timezone) + if timezone and len(cDateUTC) == 25: + + # tz irá conter informações da timezone contida em cDateUTC + tz = cDateUTC[19:25] + tz = int(tz.split(':')[0]) + dt = datetime.strptime(dt, '%Y-%m-%dT%H:%M:%S') + + # dt agora será convertido para o horario em UTC + dt = dt - timedelta(hours=tz) + + # tzinfo passará a apontar para dt = pytz.utc.localize(dt) + + # valor de dt é convertido para a timezone do usuário dt = timezone.normalize(dt) dt = dt.strftime('%Y-%m-%dT%H:%M:%S') + cDt = dt[0:10].split('-') cDt.reverse() return '/'.join(cDt), dt[11:16] @@ -265,7 +289,7 @@ class danfe(object): self.stringcenter(self.nLeft + 116.5 + nW_Rect, self.nlin + 19.5, ' '.join(chunks(cChave, 4))) # Chave self.canvas.setFont('NimbusSanL-Regu', 8) - cDt, cHr = getdateUTC( + cDt, cHr = getdateByTimezone( tagtext(oNode=elem_protNFe, cTag='dhRecbto'), timezone) cProtocolo = tagtext(oNode=elem_protNFe, cTag='nProt') cDt = cProtocolo + ' - ' + cDt + ' ' + cHr @@ -380,9 +404,10 @@ class danfe(object): else: cnpj_cpf = format_cnpj_cpf(tagtext(oNode=elem_dest, cTag='CPF')) self.string(nMr - 69, self.nlin + 7.5, cnpj_cpf) - cDt, cHr = getdateUTC(tagtext(oNode=elem_ide, cTag='dhEmi'), timezone) + cDt, cHr = getdateByTimezone(tagtext(oNode=elem_ide, cTag='dhEmi'), + timezone) self.string(nMr - 24, self.nlin + 7.7, cDt + ' ' + cHr) - cDt, cHr = getdateUTC( + cDt, cHr = getdateByTimezone( tagtext(oNode=elem_ide, cTag='dhSaiEnt'), timezone) self.string(nMr - 24, self.nlin + 14.3, cDt + ' ' + cHr) # Dt saída cEnd = tagtext(oNode=elem_dest, cTag='xLgr') + ', ' + tagtext( @@ -436,8 +461,8 @@ class danfe(object): line_iter = iter(oXML[1:10]) # Salta elemt 1 e considera os próximos 9 for oXML_dup in line_iter: - cDt, cHr = getdateUTC(tagtext(oNode=oXML_dup, cTag='dVenc'), - timezone) + cDt, cHr = getdateByTimezone(tagtext(oNode=oXML_dup, cTag='dVenc'), + timezone) self.string(self.nLeft + nCol + 1, self.nlin + nLin, tagtext(oNode=oXML_dup, cTag='nDup')) self.string(self.nLeft + nCol + 17, self.nlin + nLin, cDt) @@ -797,7 +822,8 @@ obsCont[@xCampo='NomeVendedor']") self.string(self.width - self.nRight - nW + 2, self.nlin + 14, u"SÉRIE %s" % (tagtext(oNode=el_ide, cTag='serie'))) - cDt, cHr = getdateUTC(tagtext(oNode=el_ide, cTag='dhEmi'), timezone) + cDt, cHr = getdateByTimezone( + tagtext(oNode=el_ide, cTag='dhEmi'), timezone) cTotal = format_number(tagtext(oNode=el_total, cTag='vNF')) cEnd = tagtext(oNode=el_dest, cTag='xNome') + ' - ' @@ -903,7 +929,7 @@ obsCont[@xCampo='NomeVendedor']") self.string(82, 24, cnpj) chave_acesso = tagtext(oNode=elem_infNFe, cTag='chNFe') self.string(82, 30, chave_acesso) - data_correcao = getdateUTC(tagtext( + data_correcao = getdateByTimezone(tagtext( oNode=elem_infNFe, cTag='dhEvento'), timezone) data_correcao = data_correcao[0] + " " + data_correcao[1] self.string(82, 36, data_correcao) From f39c1d0c23884b6e4f1a95c1743d38e96d5272cb Mon Sep 17 00:00:00 2001 From: carcaroff Date: Fri, 6 Apr 2018 17:06:44 -0300 Subject: [PATCH 3/5] =?UTF-8?q?Incrementar=20vers=C3=A3o=20e=20adicionaod?= =?UTF-8?q?=20pytz=20nas=20dependencias=20;-;?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- requirements.txt | 1 + setup.py | 5 +++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/requirements.txt b/requirements.txt index 9a94f0c..428cdb7 100644 --- a/requirements.txt +++ b/requirements.txt @@ -14,3 +14,4 @@ cryptography >= 1.8, < 1.10 pyOpenSSL >= 16.0.0, < 17 certifi >= 2015.11.20.1 reportlab +pytz diff --git a/setup.py b/setup.py index 514789b..0a0b402 100644 --- a/setup.py +++ b/setup.py @@ -1,7 +1,7 @@ # coding=utf-8 from setuptools import setup, find_packages -VERSION = "0.1.46" +VERSION = "0.1.47" setup( name="PyTrustNFe", @@ -40,7 +40,8 @@ later (LGPLv2+)', 'lxml >= 3.5.0, < 4', 'suds >= 0.4', 'suds_requests >= 0.3', - 'reportlab' + 'reportlab', + 'pytz' ], test_suite='nose.collector', tests_require=[ From cf9a784c25245603d6235a2f20b373aba502e3eb Mon Sep 17 00:00:00 2001 From: Felipe Date: Mon, 9 Apr 2018 16:36:00 -0300 Subject: [PATCH 4/5] correcao metodo consulta bahia --- pytrustnfe/nfe/__init__.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/pytrustnfe/nfe/__init__.py b/pytrustnfe/nfe/__init__.py index ea57408..b2b0964 100644 --- a/pytrustnfe/nfe/__init__.py +++ b/pytrustnfe/nfe/__init__.py @@ -29,6 +29,9 @@ def _build_header(method, **kwargs): 'RecepcaoEventoManifesto': ('RecepcaoEvento', '1.00'), 'NfeConsulta2': ('NfeConsulta2', '3.10') } + # Método específico para o estado da Bahia + if kwargs['estado'] == '29': + action['NfeConsulta2'] = ('NfeConsulta', '3.10') vals = {'estado': kwargs['estado'], 'soap_action': action[method][0], 'versao': action[method][1]} From 9e3429fbc85c9c4dfc6781f2ab45f34036dafe6b Mon Sep 17 00:00:00 2001 From: Felipe Date: Mon, 9 Apr 2018 16:52:35 -0300 Subject: [PATCH 5/5] incremento de versao --- setup.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/setup.py b/setup.py index 0a0b402..482e504 100644 --- a/setup.py +++ b/setup.py @@ -1,7 +1,7 @@ # coding=utf-8 from setuptools import setup, find_packages -VERSION = "0.1.47" +VERSION = "0.1.48" setup( name="PyTrustNFe", @@ -41,7 +41,7 @@ later (LGPLv2+)', 'suds >= 0.4', 'suds_requests >= 0.3', 'reportlab', - 'pytz' + 'pytz' ], test_suite='nose.collector', tests_require=[