|
|
|
@ -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] |
|
|
|
|