Compare commits
merge into: felipe:master
felipe:feature/betha
felipe:feature/cte
felipe:feature/nfe-4.0
felipe:feature/nfe-mde
felipe:feature/nota-dsf
felipe:fix-endereco
felipe:fix-invalid-token-bug
felipe:fix-url-df
felipe:fix/warning
felipe:iss-net
felipe:master
felipe:master3
felipe:merge-master3
pull from: felipe:feature/nfe-4.0
felipe:feature/betha
felipe:feature/cte
felipe:feature/nfe-4.0
felipe:feature/nfe-mde
felipe:feature/nota-dsf
felipe:fix-endereco
felipe:fix-invalid-token-bug
felipe:fix-url-df
felipe:fix/warning
felipe:iss-net
felipe:master
felipe:master3
felipe:merge-master3
72 Commits
master
...
feature/nf
120 changed files with 3308 additions and 1547 deletions
-
2.gitignore
-
10.travis.yml
-
26README.md
-
7cidades/dsf.md
-
50pytrustnfe/Servidores.py
-
8pytrustnfe/__init__.py
-
13pytrustnfe/certificado.py
-
19pytrustnfe/client.py
-
159pytrustnfe/nfe/__init__.py
-
4pytrustnfe/nfe/assinatura.py
-
8pytrustnfe/nfe/comunicacao.py
-
460pytrustnfe/nfe/danfce.py
-
139pytrustnfe/nfe/danfe.py
-
BINpytrustnfe/nfe/fonts/NimbusSanL Bold.ttf
-
BINpytrustnfe/nfe/fonts/NimbusSanL Regular.ttf
-
4pytrustnfe/nfe/templates/NfeAutorizacao.xml
-
4pytrustnfe/nfe/templates/RecepcaoEventoCarta.xml
-
90pytrustnfe/nfse/assinatura.py
-
2pytrustnfe/nfse/betha/__init__.py
-
82pytrustnfe/nfse/bh/__init__.py
-
44pytrustnfe/nfse/bh/assinatura.py
-
13pytrustnfe/nfse/bh/templates/CancelarNfse.xml
-
11pytrustnfe/nfse/bh/templates/GerarNfse.xml
-
91pytrustnfe/nfse/bh/templates/Rps.xml
-
74pytrustnfe/nfse/carioca/__init__.py
-
13pytrustnfe/nfse/carioca/templates/CancelarNfse.xml
-
3pytrustnfe/nfse/carioca/templates/GerarNfse.xml
-
91pytrustnfe/nfse/carioca/templates/Rps.xml
-
131pytrustnfe/nfse/dsf/__init__.py
-
18pytrustnfe/nfse/dsf/templates/cancelar.xml
-
11pytrustnfe/nfse/dsf/templates/consulta_notas.xml
-
10pytrustnfe/nfse/dsf/templates/consultarLote.xml
-
22pytrustnfe/nfse/dsf/templates/consultarNFSeRps.xml
-
108pytrustnfe/nfse/dsf/templates/enviar.xml
-
12pytrustnfe/nfse/dsf/templates/soap_header.xml
-
119pytrustnfe/nfse/floripa/__init__.py
-
7pytrustnfe/nfse/floripa/templates/cancelar_nota.xml
-
41pytrustnfe/nfse/floripa/templates/processar_nota.xml
-
31pytrustnfe/nfse/ginfes/__init__.py
-
11pytrustnfe/nfse/imperial/__init__.py
-
82pytrustnfe/nfse/mga/__init__.py
-
44pytrustnfe/nfse/mga/assinatura.py
-
13pytrustnfe/nfse/mga/templates/CancelarNfse.xml
-
11pytrustnfe/nfse/mga/templates/GerarNfse.xml
-
91pytrustnfe/nfse/mga/templates/Rps.xml
-
13pytrustnfe/nfse/paulistana/__init__.py
-
2pytrustnfe/nfse/susesu/__init__.py
-
1pytrustnfe/test/XMLs/paulistana_resultado.xml
-
19pytrustnfe/utils.py
-
24pytrustnfe/xml/__init__.py
-
18pytrustnfe/xml/filters.py
-
0pytrustnfe/xml/schemas/enviNFe_v3.10.xsd
-
0pytrustnfe/xml/schemas/leiauteNFe_v3.10.xsd
-
0pytrustnfe/xml/schemas/nfe_v3.10.xsd
-
2pytrustnfe/xml/schemas/tiposBasico_v3.10.xsd
-
0pytrustnfe/xml/schemas/xmldsig-core-schema_v1.01.xsd
-
31pytrustnfe/xml/validate.py
-
24requirements.txt
-
32setup.py
-
0tests/XMLs/NFe00000857.xml
-
0tests/XMLs/jinja_remove_empty.xml
-
0tests/XMLs/jinja_result.xml
-
0tests/XMLs/jinja_template.xml
-
0tests/XMLs/paulistana_canc.xml
-
1tests/XMLs/paulistana_canc_errado.xml
-
1tests/XMLs/paulistana_canc_ok.xml
-
1tests/XMLs/paulistana_resultado.xml
-
14tests/XMLs/paulistana_signature.xml
-
0tests/XMLs/recibo_envio_1.xml
-
0tests/XMLs/recibo_envio_2.xml
-
0tests/XMLs/recibo_protocolo_sucesso_1.xml
-
0tests/XMLs/recibo_protocolo_sucesso_2.xml
-
0tests/__init__.py
-
6tests/test_add_qr_code.py
-
12tests/test_assinatura.py
-
8tests/test_certificado.py
-
0tests/test_comunicacao.py
-
2tests/test_consulta_cadastro.py
-
2tests/test_danfe.py
-
2tests/test_ginfes.py
-
8tests/test_nfse_paulistana.py
-
0tests/test_servidores.py
-
16tests/test_utils.py
-
4tests/test_xml.py
-
5tests/test_xml_serializacao.py
-
0tests/teste.pfx
-
0tests/xml_assinado.xml
-
6tests/xml_com_qrcode.xml
-
6tests/xml_sem_qrcode.xml
-
0tests/xml_valido_assinado.xml
@ -0,0 +1,7 @@ |
|||||
|
* Belém - PA |
||||
|
* Sorocaba - SP |
||||
|
* Teresina - PI |
||||
|
* Campinas - SP |
||||
|
* Uberlandia - MG |
||||
|
* São Luis - MA |
||||
|
* Campo Grande - MS |
||||
@ -0,0 +1,460 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
# © 2017 Johny Chen Jy, Trustcode |
||||
|
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). |
||||
|
|
||||
|
import re |
||||
|
from textwrap import wrap |
||||
|
from io import BytesIO |
||||
|
|
||||
|
from reportlab.lib import utils |
||||
|
from reportlab.pdfgen import canvas |
||||
|
from reportlab.lib.units import cm, mm |
||||
|
from reportlab.graphics.barcode import qr |
||||
|
from reportlab.graphics import renderPDF |
||||
|
from reportlab.graphics.shapes import Drawing |
||||
|
from reportlab.platypus import Table, TableStyle, Paragraph, Image |
||||
|
from reportlab.lib.enums import TA_CENTER |
||||
|
from reportlab.lib.styles import ParagraphStyle |
||||
|
|
||||
|
|
||||
|
def format_cnpj_cpf(value): |
||||
|
if len(value) < 12: # CPF |
||||
|
cValue = '%s.%s.%s-%s' % (value[:-8], value[-8:-5], |
||||
|
value[-5:-2], value[-2:]) |
||||
|
else: |
||||
|
cValue = '%s.%s.%s/%s-%s' % (value[:-12], value[-12:-9], |
||||
|
value[-9:-6], value[-6:-2], value[-2:]) |
||||
|
return cValue |
||||
|
|
||||
|
|
||||
|
def getdateUTC(cDateUTC): |
||||
|
cDt = cDateUTC[0:10].split('-') |
||||
|
cDt.reverse() |
||||
|
return '/'.join(cDt), cDateUTC[11:16] |
||||
|
|
||||
|
|
||||
|
def format_number(cNumber, precision=0, group_sep='.', decimal_sep=','): |
||||
|
if cNumber: |
||||
|
number = float(cNumber) |
||||
|
return ("{:,." + str(precision) + "f}").format(number).\ |
||||
|
replace(",", "X").replace(".", ",").replace("X", ".") |
||||
|
return "" |
||||
|
|
||||
|
|
||||
|
def tagtext(oNode=None, cTag=None): |
||||
|
try: |
||||
|
xpath = ".//{http://www.portalfiscal.inf.br/nfe}%s" % (cTag) |
||||
|
cText = oNode.find(xpath).text |
||||
|
except: |
||||
|
cText = '' |
||||
|
return cText |
||||
|
|
||||
|
|
||||
|
def get_image(path, width=1 * cm): |
||||
|
img = utils.ImageReader(path) |
||||
|
iw, ih = img.getSize() |
||||
|
aspect = ih / float(iw) |
||||
|
return Image(path, width=width, height=(width * aspect)) |
||||
|
|
||||
|
|
||||
|
def format_telefone(telefone): |
||||
|
telefone = re.sub('[^0-9]', '', telefone) |
||||
|
if len(telefone) == 10: |
||||
|
telefone = '(%s) %s-%s' % (telefone[0:2], |
||||
|
telefone[2:6], |
||||
|
telefone[6:]) |
||||
|
elif len(telefone) == 11: |
||||
|
telefone = '(%s) %s-%s' % (telefone[0:2], |
||||
|
telefone[2:7], |
||||
|
telefone[7:]) |
||||
|
return telefone |
||||
|
|
||||
|
|
||||
|
class danfce(object): |
||||
|
|
||||
|
def __init__(self, list_xml, logo=None): |
||||
|
|
||||
|
self.current_font_size = 7 |
||||
|
self.current_font_name = 'NimbusSanL-Regu' |
||||
|
|
||||
|
self.max_height = 840 |
||||
|
self.min_height = 1 |
||||
|
self.min_width = 5 |
||||
|
self.max_width = 200 |
||||
|
self.current_height = 840 |
||||
|
|
||||
|
self.oPDF_IO = BytesIO() |
||||
|
self.canvas = canvas.Canvas(self.oPDF_IO, pagesize=(7.2 * cm, 30 * cm)) |
||||
|
self.canvas.setTitle('DANFCE') |
||||
|
self.canvas.setLineWidth(.5) |
||||
|
self.canvas.setFont(self.current_font_name, self.current_font_size) |
||||
|
|
||||
|
self.list_xml = list_xml |
||||
|
self.logo = logo |
||||
|
|
||||
|
self.nfce_generate() |
||||
|
|
||||
|
def ide_emit(self, oXML=None): |
||||
|
|
||||
|
elem_emit = oXML.find(".//{http://www.portalfiscal.inf.br/nfe}emit") |
||||
|
|
||||
|
# Razão Social emitente |
||||
|
nomeEmpresa = tagtext(oNode=elem_emit, cTag='xFant') |
||||
|
self.drawTitle(nomeEmpresa, 10) |
||||
|
|
||||
|
if self.logo: |
||||
|
img = get_image(self.logo, width=10 * mm) |
||||
|
img.drawOn(self.canvas, 5, 830) |
||||
|
|
||||
|
cEnd = tagtext(oNode=elem_emit, cTag="xNome") + '<br />' |
||||
|
cEnd += "CNPJ: %s " % (format_cnpj_cpf( |
||||
|
tagtext(oNode=elem_emit, cTag='CNPJ'))) |
||||
|
cEnd += "IE: %s" % (tagtext(oNode=elem_emit, cTag="IE")) + '<br />' |
||||
|
cEnd += tagtext(oNode=elem_emit, cTag='xLgr') + ', ' + tagtext( |
||||
|
oNode=elem_emit, cTag='nro') + ' - ' |
||||
|
cEnd += tagtext(oNode=elem_emit, cTag='xBairro') + '<br />' + tagtext( |
||||
|
oNode=elem_emit, cTag='xMun') + ' - ' |
||||
|
cEnd += tagtext(oNode=elem_emit, cTag='UF') + ' - ' + tagtext( |
||||
|
oNode=elem_emit, cTag='CEP') + '<br />' |
||||
|
cEnd += 'Fone: ' + format_telefone(tagtext( |
||||
|
oNode=elem_emit, cTag='fone')) |
||||
|
|
||||
|
self._drawCenteredParagraph(cEnd) |
||||
|
self.drawLine() |
||||
|
|
||||
|
def danfce_information(self): |
||||
|
self.drawTitle( |
||||
|
"DANFE NFC-e - Documento Auxiliar da Nota Fiscal de", |
||||
|
7, 'NimbusSanL-Bold') |
||||
|
|
||||
|
self.drawTitle("Consumidor Eletrônica", 7, 'NimbusSanL-Bold') |
||||
|
|
||||
|
self.drawString( |
||||
|
"NFC-e não permite aproveitamento de crédito de ICMS", True) |
||||
|
self.drawLine() |
||||
|
|
||||
|
def produtos(self, oXML=None, el_det=None, oPaginator=None, |
||||
|
list_desc=None, list_cod_prod=None): |
||||
|
|
||||
|
rows = [['Cód', 'Descrição', 'Qtde', 'Un', 'Unit.', 'Total']] |
||||
|
colWidths = (25, 90, 15, 15, 25, 25) |
||||
|
rowHeights = [7] |
||||
|
|
||||
|
for id in range(oPaginator[0], oPaginator[1]): |
||||
|
|
||||
|
item = el_det[id] |
||||
|
el_prod = item.find(".//{http://www.portalfiscal.inf.br/nfe}prod") |
||||
|
|
||||
|
cod = tagtext(oNode=el_prod, cTag='cProd') |
||||
|
descricao = tagtext(oNode=el_prod, cTag='xProd') |
||||
|
descricao = (descricao[:20] + '..') if len(descricao) > 20 else descricao |
||||
|
Un = tagtext(oNode=el_prod, cTag='uCom') |
||||
|
Un = (Un[:2]) if len(Un) > 2 else Un |
||||
|
qtde = format_number(tagtext(oNode=el_prod, cTag='qCom'), |
||||
|
precision=2) |
||||
|
vl_unit = format_number(tagtext(oNode=el_prod, cTag='vUnCom'), |
||||
|
precision=2) |
||||
|
vl_total = format_number( |
||||
|
tagtext(oNode=el_prod, cTag='vProd'), precision=2) |
||||
|
|
||||
|
new_row = [cod, descricao, qtde, Un, vl_unit, vl_total] |
||||
|
|
||||
|
rows.append(new_row) |
||||
|
rowHeights.append(self.current_font_size + 2) |
||||
|
|
||||
|
self._draw_product_table(rows, colWidths, rowHeights) |
||||
|
|
||||
|
def _draw_product_table(self, rows, colWidths, rowHeights): |
||||
|
table = Table(rows, colWidths, tuple(rowHeights)) |
||||
|
table.setStyle(TableStyle([ |
||||
|
('FONTSIZE', (0, 0), (-1, -1), 7), |
||||
|
('FONT', (0, 1), (-1, -1), 'NimbusSanL-Regu'), |
||||
|
('FONT', (0, 0), (-1, 0), 'NimbusSanL-Bold'), |
||||
|
('ALIGN', (0, 0), (-1, 0), "LEFT"), |
||||
|
('ALIGN', (1, 0), (-1, 0), "LEFT"), |
||||
|
('ALIGN', (2, 0), (-1, 0), "CENTER"), |
||||
|
('ALIGN', (3, 0), (-1, 0), "CENTER"), |
||||
|
('ALIGN', (0, 1), (-1, -1), "LEFT"), |
||||
|
('ALIGN', (1, 1), (-1, -1), "LEFT"), |
||||
|
('ALIGN', (2, 1), (-1, -1), "CENTER"), |
||||
|
('ALIGN', (3, 1), (-1, -1), "CENTER"), |
||||
|
])) |
||||
|
|
||||
|
w, h = table.wrapOn(self.canvas, 200, 450) |
||||
|
table.drawOn(self.canvas, 0, self.current_height - (h * 1.2)) |
||||
|
self.current_height -= (h * 1.1) |
||||
|
|
||||
|
def totais(self, oXML=None): |
||||
|
# Impostos |
||||
|
el_total = oXML.find(".//{http://www.portalfiscal.inf.br/nfe}total") |
||||
|
|
||||
|
total_tributo = format_number(tagtext(oNode=el_total, cTag='vTotTrib'), |
||||
|
precision=2) |
||||
|
valor_total = format_number(tagtext(oNode=el_total, cTag='vProd'), |
||||
|
precision=2) |
||||
|
desconto = format_number(tagtext(oNode=el_total, cTag='vDesc'), |
||||
|
precision=2) |
||||
|
valor_a_pagar = format_number(tagtext(oNode=el_total, cTag='vNF'), |
||||
|
precision=2) |
||||
|
el_pag = oXML.find(".//{http://www.portalfiscal.inf.br/nfe}pag") |
||||
|
troco = format_number(tagtext(oNode=el_pag, cTag="vTroco")) |
||||
|
|
||||
|
payment_method_list = {'01': 'Dinheiro', |
||||
|
'02': 'Cheque', |
||||
|
'03': 'Cartão de Crédito', |
||||
|
'04': 'Cartão de Débito', |
||||
|
"05": "Crédito Loja", |
||||
|
'10': 'Vale Alimentação', |
||||
|
'11': 'Vale Refeição', |
||||
|
'12': 'Vale Presente', |
||||
|
'13': 'Vale Combustível', |
||||
|
'14': 'Duplicata Mercantil', |
||||
|
'15': 'Boleto Bancario', |
||||
|
'90': 'Sem Pagamento', |
||||
|
'99': 'Outros'} |
||||
|
quant_produtos = len(oXML.findall( |
||||
|
".//{http://www.portalfiscal.inf.br/nfe}det")) |
||||
|
|
||||
|
payment_methods = [] |
||||
|
|
||||
|
for pagId, item in enumerate(el_pag): |
||||
|
if 'tPag' not in item.tag: |
||||
|
continue |
||||
|
|
||||
|
payment = [] |
||||
|
method = payment_method_list[item.text] |
||||
|
|
||||
|
payment.append(method) |
||||
|
payment.append(format_number(item.getnext().text, precision=2)) |
||||
|
payment_methods.append(payment) |
||||
|
|
||||
|
values = {'quantidade_itens': quant_produtos, |
||||
|
'total_tributo': total_tributo, |
||||
|
'valor_total': valor_total, |
||||
|
'desconto': desconto, |
||||
|
'valor_a_pagar': valor_a_pagar, |
||||
|
'formas_de_pagamento': payment_methods, |
||||
|
'troco': troco, |
||||
|
} |
||||
|
|
||||
|
self.draw_totals_table(values) |
||||
|
|
||||
|
self.drawLine() |
||||
|
|
||||
|
def draw_totals_table(self, values): |
||||
|
rowHeights = [7, 7, 7, 7, 10] |
||||
|
data = [['QTD.TOTAL DE ITENS', values['quantidade_itens']], |
||||
|
['VALOR TOTAL R$', values['valor_total']], |
||||
|
['DESCONTO R$', values['desconto']], |
||||
|
['VALOR A PAGAR R$', values['valor_a_pagar']], |
||||
|
['FORMA DE PAGAMENTO', 'VALOR PAGO R$'], |
||||
|
] |
||||
|
|
||||
|
for item in values['formas_de_pagamento']: |
||||
|
data.append([item[0], item[1]]) |
||||
|
rowHeights.append(7) |
||||
|
data.append(['TROCO', format_number(values['troco'], precision=2)]) |
||||
|
rowHeights.append(7) |
||||
|
|
||||
|
table2 = Table(data, colWidths=(150, 50), rowHeights=tuple(rowHeights)) |
||||
|
table2.setStyle(TableStyle([ |
||||
|
('FONTSIZE', (0, 0), (-1, -1), 7), |
||||
|
('FONT', (0, 0), (1, -1), 'NimbusSanL-Regu'), |
||||
|
('FONT', (0, 4), (1, 4), 'NimbusSanL-Bold'), |
||||
|
('ALIGN', (1, 0), (1, -1), "RIGHT") |
||||
|
])) |
||||
|
w, h = table2.wrapOn(self.canvas, 200, 450) |
||||
|
table2.drawOn(self.canvas, 0, self.current_height - (h * 1.1)) |
||||
|
self.current_height -= h |
||||
|
|
||||
|
def inf_authentication(self, oXML=None): |
||||
|
el_infNFe = oXML.find(".//{http://www.portalfiscal.inf.br/nfe}infNFe") |
||||
|
# n nfce, serie e data de solicitacao |
||||
|
el_ide = oXML.find(".//{http://www.portalfiscal.inf.br/nfe}ide") |
||||
|
|
||||
|
el_NFeSupl = oXML.find( |
||||
|
".//{http://www.portalfiscal.inf.br/nfe}infNFeSupl") |
||||
|
|
||||
|
el_dest = el_infNFe.find(".//{http://www.portalfiscal.inf.br/nfe}dest") |
||||
|
# chave, n protocolo, data autorizacao |
||||
|
el_prot_nfe = oXML.find( |
||||
|
".//{http://www.portalfiscal.inf.br/nfe}protNFe") |
||||
|
|
||||
|
el_infAdic = oXML.find( |
||||
|
".//{http://www.portalfiscal.inf.br/nfe}infAdic") |
||||
|
|
||||
|
url_chave = tagtext(oNode=el_NFeSupl, cTag='urlChave') |
||||
|
access_key = tagtext(oNode=el_prot_nfe, cTag="chNFe") |
||||
|
|
||||
|
frase_chave_acesso = 'Consulte pela Chave de Acesso em:<br />\ |
||||
|
%s<br />%s' % (url_chave, access_key) |
||||
|
|
||||
|
qrcode = tagtext(oNode=el_NFeSupl, cTag='qrCode') |
||||
|
|
||||
|
cnpj = tagtext(oNode=el_dest, cTag='CNPJ') |
||||
|
cpf = tagtext(oNode=el_dest, cTag='CPF') |
||||
|
if cnpj: |
||||
|
cnpj_cpf = format_cnpj_cpf(cnpj) |
||||
|
cnpj_cpf = "CONSUMIDOR CNPJ: %s" % (cnpj) |
||||
|
elif cpf: |
||||
|
cnpj_cpf = format_cnpj_cpf(cpf) |
||||
|
cnpj_cpf = "CONSUMIDOR CPF: %s" % (cpf) |
||||
|
else: |
||||
|
cnpj_cpf = u"CONSUMIDOR NÃO IDENTIFICADO" |
||||
|
|
||||
|
nNFC = tagtext(oNode=el_ide, cTag="nNF") |
||||
|
serie = tagtext(oNode=el_ide, cTag='serie') |
||||
|
|
||||
|
dataSolicitacao = getdateUTC(tagtext(oNode=el_ide, cTag="dhEmi")) |
||||
|
dataSolicitacao = dataSolicitacao[0] + " " + dataSolicitacao[1] |
||||
|
|
||||
|
numProtocolo = tagtext(oNode=el_prot_nfe, cTag="nProt") |
||||
|
|
||||
|
dataAutorizacao = getdateUTC(tagtext(oNode=el_prot_nfe, |
||||
|
cTag='dhRecbto')) |
||||
|
dataAutorizacao = dataAutorizacao[0] + " " + dataAutorizacao[1] |
||||
|
|
||||
|
text = u"%s <br />%s <br />NFC-e nº%s Série %s %s<br />\ |
||||
|
Protocolo de autorização: %s<br />Data de autorização %s<br />\ |
||||
|
" % (frase_chave_acesso, cnpj_cpf, nNFC, serie, dataSolicitacao, |
||||
|
numProtocolo, dataAutorizacao) |
||||
|
|
||||
|
self._drawCenteredParagraph(text) |
||||
|
|
||||
|
self.draw_qr_code(qrcode) |
||||
|
|
||||
|
infAdFisco = tagtext(oNode=el_infAdic, cTag='infAdFisco') |
||||
|
self._drawCenteredParagraph(infAdFisco) |
||||
|
|
||||
|
infCpl = tagtext(oNode=el_infAdic, cTag='infCpl') |
||||
|
self._drawCenteredParagraph(infCpl) |
||||
|
|
||||
|
def _drawCenteredParagraph(self, text): |
||||
|
|
||||
|
style = ParagraphStyle( |
||||
|
name='Normal', |
||||
|
fontName='NimbusSanL-Regu', |
||||
|
fontSize=7, |
||||
|
alignment=TA_CENTER, |
||||
|
leading=7, |
||||
|
) |
||||
|
|
||||
|
paragraph = Paragraph(text, style=style) |
||||
|
w, h = paragraph.wrapOn(self.canvas, 180, 300) |
||||
|
paragraph.drawOn(self.canvas, 10, self.current_height - h) |
||||
|
self.current_height -= (h*1.1) |
||||
|
|
||||
|
def drawString(self, string, centered=False): |
||||
|
if centered: |
||||
|
self.canvas.drawCentredString( |
||||
|
self.max_width / 2, self.current_height, string) |
||||
|
self.current_height -= self.current_font_size |
||||
|
else: |
||||
|
self.canvas.drawString(self.min_width, self.current_height, string) |
||||
|
self.current_height -= self.current_font_size |
||||
|
|
||||
|
def drawTitle(self, string, size, font='NimbusSanL-Regu'): |
||||
|
self.canvas.setFont(font, size) |
||||
|
self.canvas.drawCentredString( |
||||
|
self.max_width / 2, self.current_height, string) |
||||
|
self.current_height -= self.current_font_size |
||||
|
self.canvas.setFont(self.current_font_name, self.current_font_size) |
||||
|
|
||||
|
def drawLine(self): |
||||
|
self.canvas.line(self.min_width, self.current_height, |
||||
|
self.max_width, self.current_height) |
||||
|
self.current_height -= self.current_font_size |
||||
|
|
||||
|
def draw_qr_code(self, string): |
||||
|
qr_code = qr.QrCodeWidget(string) |
||||
|
drawing = Drawing(23 * mm, 23 * mm) |
||||
|
drawing.add(qr_code) |
||||
|
renderPDF.draw(drawing, self.canvas, 20 * mm, self.current_height - 85) |
||||
|
self.current_height -= 85 |
||||
|
|
||||
|
def newpage(self): |
||||
|
self.current_height = self.max_height |
||||
|
self.Page += 1 |
||||
|
self.canvas.showPage() |
||||
|
|
||||
|
def nfce_generate(self): |
||||
|
for oXML in self.list_xml: |
||||
|
oXML_cobr = oXML.find( |
||||
|
".//{http://www.portalfiscal.inf.br/nfe}cobr") |
||||
|
|
||||
|
self.NrPages = 1 |
||||
|
self.Page = 1 |
||||
|
|
||||
|
# Calculando total linhas usadas para descrições dos itens |
||||
|
# Com bloco fatura, apenas 29 linhas para itens na primeira folha |
||||
|
nNr_Lin_Pg_1 = 34 if oXML_cobr is None else 30 |
||||
|
# [ rec_ini , rec_fim , lines , limit_lines ] |
||||
|
oPaginator = [[0, 0, 0, nNr_Lin_Pg_1]] |
||||
|
el_det = oXML.findall(".//{http://www.portalfiscal.inf.br/nfe}det") |
||||
|
if el_det is not None: |
||||
|
list_desc = [] |
||||
|
list_cod_prod = [] |
||||
|
nPg = 0 |
||||
|
for nId, item in enumerate(el_det): |
||||
|
el_prod = item.find( |
||||
|
".//{http://www.portalfiscal.inf.br/nfe}prod") |
||||
|
infAdProd = item.find( |
||||
|
".//{http://www.portalfiscal.inf.br/nfe}infAdProd") |
||||
|
|
||||
|
list_ = wrap(tagtext(oNode=el_prod, cTag='xProd'), 56) |
||||
|
if infAdProd is not None: |
||||
|
list_.extend(wrap(infAdProd.text, 56)) |
||||
|
list_desc.append(list_) |
||||
|
|
||||
|
list_cProd = wrap(tagtext(oNode=el_prod, cTag='cProd'), 14) |
||||
|
list_cod_prod.append(list_cProd) |
||||
|
|
||||
|
# Nr linhas necessárias p/ descrição item |
||||
|
nLin_Itens = len(list_) |
||||
|
|
||||
|
if (oPaginator[nPg][2] + nLin_Itens) >= oPaginator[nPg][3]: |
||||
|
oPaginator.append([0, 0, 0, 77]) |
||||
|
nPg += 1 |
||||
|
oPaginator[nPg][0] = nId |
||||
|
oPaginator[nPg][1] = nId + 1 |
||||
|
oPaginator[nPg][2] = nLin_Itens |
||||
|
else: |
||||
|
# adiciona-se 1 pelo funcionamento de xrange |
||||
|
oPaginator[nPg][1] = nId + 1 |
||||
|
oPaginator[nPg][2] += nLin_Itens |
||||
|
|
||||
|
self.NrPages = len(oPaginator) # Calculando nr. páginas |
||||
|
|
||||
|
self.ide_emit(oXML=oXML) |
||||
|
# self.destinatario(oXML=oXML) |
||||
|
self.danfce_information() |
||||
|
|
||||
|
self.produtos(oXML=oXML, el_det=el_det, oPaginator=oPaginator[0], |
||||
|
list_desc=list_desc, list_cod_prod=list_cod_prod) |
||||
|
|
||||
|
self.drawLine() |
||||
|
|
||||
|
self.totais(oXML=oXML) |
||||
|
|
||||
|
self.inf_authentication(oXML=oXML) |
||||
|
|
||||
|
# Gera o restante das páginas do XML |
||||
|
for oPag in oPaginator[1:]: |
||||
|
if oPag: |
||||
|
self.newpage() |
||||
|
self.ide_emit(oXML=oXML) |
||||
|
# self.destinatario(oXML=oXML) |
||||
|
self.produtos(oXML=oXML, el_det=el_det, oPaginator=oPag, |
||||
|
list_desc=list_desc, |
||||
|
list_cod_prod=list_cod_prod) |
||||
|
self.totais(oXML=oXML) |
||||
|
self.inf_authentication(oXML=oXML) |
||||
|
|
||||
|
self.newpage() |
||||
|
|
||||
|
self.canvas.save() |
||||
|
|
||||
|
def writeto_pdf(self, fileObj): |
||||
|
pdf_out = self.oPDF_IO.getvalue() |
||||
|
self.oPDF_IO.close() |
||||
|
fileObj.write(pdf_out) |
||||
@ -0,0 +1,82 @@ |
|||||
|
# © 2018 Danimar Ribeiro, Trustcode |
||||
|
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). |
||||
|
|
||||
|
import os |
||||
|
from lxml import etree |
||||
|
from requests import Session |
||||
|
from zeep import Client |
||||
|
from zeep.transports import Transport |
||||
|
|
||||
|
from pytrustnfe.certificado import extract_cert_and_key_from_pfx, save_cert_key |
||||
|
from pytrustnfe.xml import render_xml, sanitize_response |
||||
|
from pytrustnfe.nfse.bh.assinatura import Assinatura |
||||
|
|
||||
|
|
||||
|
def _render(certificado, method, **kwargs): |
||||
|
path = os.path.join(os.path.dirname(__file__), 'templates') |
||||
|
xml_send = render_xml(path, '%s.xml' % method, True, **kwargs) |
||||
|
|
||||
|
reference = '' |
||||
|
if method == 'GerarNfse': |
||||
|
reference = 'rps:%s' % kwargs['rps']['numero'] |
||||
|
ref_lote = 'lote%s' % kwargs['rps']['numero_lote'] |
||||
|
elif method == 'CancelarNfse': |
||||
|
reference = 'Cancelamento_NF%s' % kwargs['cancelamento']['numero_nfse'] |
||||
|
|
||||
|
signer = Assinatura(certificado.pfx, certificado.password) |
||||
|
xml_send = signer.assina_xml(xml_send, reference) |
||||
|
xml_send = signer.assina_xml(etree.fromstring(xml_send), ref_lote) |
||||
|
return xml_send.encode('utf-8') |
||||
|
|
||||
|
|
||||
|
def _send(certificado, method, **kwargs): |
||||
|
base_url = '' |
||||
|
if kwargs['ambiente'] == 'producao': |
||||
|
base_url = 'https://bhissdigital.pbh.gov.br/bhiss-ws/nfse?wsdl' |
||||
|
else: |
||||
|
base_url = 'https://bhisshomologa.pbh.gov.br/bhiss-ws/nfse?wsdl' |
||||
|
|
||||
|
xml_send = kwargs["xml"].decode('utf-8') |
||||
|
xml_cabecalho = '<?xml version="1.0" encoding="UTF-8"?>\ |
||||
|
<cabecalho xmlns="http://www.abrasf.org.br/nfse.xsd" versao="1.00">\ |
||||
|
<versaoDados>1.00</versaoDados></cabecalho>' |
||||
|
|
||||
|
cert, key = extract_cert_and_key_from_pfx( |
||||
|
certificado.pfx, certificado.password) |
||||
|
cert, key = save_cert_key(cert, key) |
||||
|
|
||||
|
session = Session() |
||||
|
session.cert = (cert, key) |
||||
|
session.verify = False |
||||
|
transport = Transport(session=session) |
||||
|
|
||||
|
client = Client(base_url, transport=transport) |
||||
|
|
||||
|
response = client.service[method](xml_cabecalho, xml_send) |
||||
|
|
||||
|
response, obj = sanitize_response(response.encode('utf-8')) |
||||
|
return { |
||||
|
'sent_xml': xml_send, |
||||
|
'received_xml': response.decode('utf-8'), |
||||
|
'object': obj |
||||
|
} |
||||
|
|
||||
|
|
||||
|
def xml_gerar_nfse(certificado, **kwargs): |
||||
|
return _render(certificado, 'GerarNfse', **kwargs) |
||||
|
|
||||
|
|
||||
|
def gerar_nfse(certificado, **kwargs): |
||||
|
if "xml" not in kwargs: |
||||
|
kwargs['xml'] = xml_gerar_nfse(certificado, **kwargs) |
||||
|
return _send(certificado, 'GerarNfse', **kwargs) |
||||
|
|
||||
|
|
||||
|
def xml_cancelar_nfse(certificado, **kwargs): |
||||
|
return _render(certificado, 'CancelarNfse', **kwargs) |
||||
|
|
||||
|
|
||||
|
def cancelar_nfse(certificado, **kwargs): |
||||
|
if "xml" not in kwargs: |
||||
|
kwargs['xml'] = xml_cancelar_nfse(certificado, **kwargs) |
||||
|
return _send(certificado, 'CancelarNfse', **kwargs) |
||||
@ -0,0 +1,44 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
# © 2016 Danimar Ribeiro, Trustcode |
||||
|
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). |
||||
|
|
||||
|
import signxml |
||||
|
from lxml import etree |
||||
|
from pytrustnfe.certificado import extract_cert_and_key_from_pfx |
||||
|
from signxml import XMLSigner |
||||
|
|
||||
|
|
||||
|
class Assinatura(object): |
||||
|
|
||||
|
def __init__(self, arquivo, senha): |
||||
|
self.arquivo = arquivo |
||||
|
self.senha = senha |
||||
|
|
||||
|
def assina_xml(self, xml_element, reference): |
||||
|
cert, key = extract_cert_and_key_from_pfx(self.arquivo, self.senha) |
||||
|
|
||||
|
for element in xml_element.iter("*"): |
||||
|
if element.text is not None and not element.text.strip(): |
||||
|
element.text = None |
||||
|
|
||||
|
signer = XMLSigner( |
||||
|
method=signxml.methods.enveloped, signature_algorithm="rsa-sha1", |
||||
|
digest_algorithm='sha1', |
||||
|
c14n_algorithm='http://www.w3.org/TR/2001/REC-xml-c14n-20010315') |
||||
|
|
||||
|
ns = {} |
||||
|
ns[None] = signer.namespaces['ds'] |
||||
|
signer.namespaces = ns |
||||
|
|
||||
|
ref_uri = ('#%s' % reference) if reference else None |
||||
|
signed_root = signer.sign( |
||||
|
xml_element, key=key.encode(), cert=cert.encode(), |
||||
|
reference_uri=ref_uri) |
||||
|
if reference: |
||||
|
element_signed = signed_root.find(".//*[@Id='%s']" % reference) |
||||
|
signature = signed_root.find(".//*[@URI='#%s']" % reference).getparent().getparent() |
||||
|
|
||||
|
if element_signed is not None and signature is not None: |
||||
|
parent = element_signed.getparent() |
||||
|
parent.append(signature) |
||||
|
return etree.tostring(signed_root, encoding=str) |
||||
@ -0,0 +1,13 @@ |
|||||
|
<CancelarNfseEnvio xmlns="http://www.abrasf.org.br/ABRASF/arquivos/nfse.xsd"> |
||||
|
<Pedido xmlns="http://www.abrasf.org.br/nfse.xsd"> |
||||
|
<InfPedidoCancelamento Id="pedidoCancelamento_{{ cancelamento.numero_nfse }}"> |
||||
|
<IdentificacaoNfse> |
||||
|
<Numero>{{ cancelamento.numero_nfse }}</Numero> |
||||
|
<Cnpj>{{ cancelamento.cnpj_prestador }}</Cnpj> |
||||
|
<InscricaoMunicipal>{{ cancelamento.inscricao_municipal }}</InscricaoMunicipal> |
||||
|
<CodigoMunicipio>{{ cancelamento.cidade }}</CodigoMunicipio> |
||||
|
</IdentificacaoNfse> |
||||
|
<CodigoCancelamento>1</CodigoCancelamento> |
||||
|
</InfPedidoCancelamento> |
||||
|
</Pedido> |
||||
|
</CancelarNfseEnvio> |
||||
@ -0,0 +1,11 @@ |
|||||
|
<GerarNfseEnvio xmlns="http://www.abrasf.org.br/nfse.xsd"> |
||||
|
<LoteRps Id="lote{{ rps.numero_lote }}" versao="1.00"> |
||||
|
<NumeroLote>{{ rps.numero_lote }}</NumeroLote> |
||||
|
<Cnpj>{{ rps.prestador.cnpj }}</Cnpj> |
||||
|
<InscricaoMunicipal>{{ rps.prestador.inscricao_municipal }}</InscricaoMunicipal> |
||||
|
<QuantidadeRps>1</QuantidadeRps> |
||||
|
<ListaRps xmlns="http://www.abrasf.org.br/nfse.xsd"> |
||||
|
{% include 'Rps.xml' %} |
||||
|
</ListaRps> |
||||
|
</LoteRps> |
||||
|
</GerarNfseEnvio> |
||||
@ -0,0 +1,91 @@ |
|||||
|
<Rps> |
||||
|
<InfRps xmlns="http://www.abrasf.org.br/nfse.xsd" Id="rps:{{ rps.numero }}"> |
||||
|
<IdentificacaoRps> |
||||
|
<Numero>{{ rps.numero }}</Numero> |
||||
|
<Serie>{{ rps.serie }}</Serie> |
||||
|
<Tipo>{{ rps.tipo_rps }}</Tipo> |
||||
|
</IdentificacaoRps> |
||||
|
<DataEmissao>{{ rps.data_emissao }}</DataEmissao> |
||||
|
<NaturezaOperacao>{{ rps.natureza_operacao }}</NaturezaOperacao> |
||||
|
<RegimeEspecialTributacao>{{ rps.regime_tributacao }}</RegimeEspecialTributacao> |
||||
|
<OptanteSimplesNacional>{{ rps.optante_simples }}</OptanteSimplesNacional> |
||||
|
<IncentivadorCultural>{{ rps.incentivador_cultural }}</IncentivadorCultural> |
||||
|
<Status>{{ rps.status }}</Status> |
||||
|
<RpsSubstituido> |
||||
|
<Numero>{{ rps.numero_substituido }}</Numero> |
||||
|
<Serie>{{ rps.serie_substituido }}</Serie> |
||||
|
<Tipo>{{ rps.tipo_substituido }}</Tipo> |
||||
|
</RpsSubstituido> |
||||
|
<Servico> |
||||
|
<Valores> |
||||
|
<ValorServicos>{{ rps.valor_servico }}</ValorServicos> |
||||
|
<ValorDeducoes>{{ rps.valor_deducao }}</ValorDeducoes> |
||||
|
<ValorPis>{{ rps.valor_pis }}</ValorPis> |
||||
|
<ValorCofins>{{ rps.valor_cofins }}</ValorCofins> |
||||
|
<ValorInss>{{ rps.valor_inss }}</ValorInss> |
||||
|
<ValorIr>{{ rps.valor_ir }}</ValorIr> |
||||
|
<ValorCsll>{{ rps.valor_csll }}</ValorCsll> |
||||
|
<IssRetido>{{ rps.iss_retido }}</IssRetido> |
||||
|
<ValorIss>{{ rps.valor_iss }}</ValorIss> |
||||
|
<ValorIssRetido>{{ rps.valor_iss_retido }}</ValorIssRetido> |
||||
|
<OutrasRetencoes>{{ rps.outras_retencoes }}</OutrasRetencoes> |
||||
|
<BaseCalculo>{{ rps.base_calculo }}</BaseCalculo> |
||||
|
<Aliquota>{{ rps.aliquota_issqn }}</Aliquota> |
||||
|
<ValorLiquidoNfse>{{ rps.valor_liquido_nfse }}</ValorLiquidoNfse> |
||||
|
<DescontoIncondicionado>{{ rps.desconto_incondicionado }}</DescontoIncondicionado> |
||||
|
<DescontoCondicionado>{{ rps.desconto_condicionado }}</DescontoCondicionado> |
||||
|
</Valores> |
||||
|
<ItemListaServico>{{ rps.codigo_servico }}</ItemListaServico> |
||||
|
<CodigoCnae>{{ rps.cnae_servico }}</CodigoCnae> |
||||
|
<CodigoTributacaoMunicipio>{{ rps.codigo_tributacao_municipio }}</CodigoTributacaoMunicipio> |
||||
|
<Discriminacao>{{ rps.descricao }}</Discriminacao> |
||||
|
<CodigoMunicipio>{{ rps.codigo_municipio }}</CodigoMunicipio> |
||||
|
</Servico> |
||||
|
<Prestador> |
||||
|
<Cnpj>{{ rps.prestador.cnpj }}</Cnpj> |
||||
|
<InscricaoMunicipal>{{ rps.prestador.inscricao_municipal }}</InscricaoMunicipal> |
||||
|
</Prestador> |
||||
|
<Tomador> |
||||
|
<IdentificacaoTomador> |
||||
|
<CpfCnpj> |
||||
|
{% if rps.tomador.cnpj_cpf|length == 14 %} |
||||
|
<Cnpj>{{ rps.tomador.cnpj_cpf }}</Cnpj> |
||||
|
{% endif %} |
||||
|
{% if rps.tomador.cnpj_cpf|length == 11 %} |
||||
|
<Cpf>{{ rps.tomador.cnpj_cpf }}</Cpf> |
||||
|
{% endif %} |
||||
|
</CpfCnpj> |
||||
|
<InscricaoMunicipal>{{ rps.tomador.inscricao_municipal }}</InscricaoMunicipal> |
||||
|
</IdentificacaoTomador> |
||||
|
<RazaoSocial>{{ rps.tomador.razao_social }}</RazaoSocial> |
||||
|
<Endereco> |
||||
|
<Endereco>{{ rps.tomador.logradouro }}</Endereco> |
||||
|
<Numero>{{ rps.tomador.numero }}</Numero> |
||||
|
<Complemento>{{ rps.tomador.complemento }}</Complemento> |
||||
|
<Bairro>{{ rps.tomador.bairro }}</Bairro> |
||||
|
<CodigoMunicipio>{{ rps.tomador.cidade }}</CodigoMunicipio> |
||||
|
<Uf>{{ rps.tomador.uf }}</Uf> |
||||
|
<Cep>{{ rps.tomador.cep }}</Cep> |
||||
|
</Endereco> |
||||
|
<Contato> |
||||
|
<Telefone>{{ rps.tomador.telefone }}</Telefone> |
||||
|
<Email>{{ rps.tomador.email }}</Email> |
||||
|
</Contato> |
||||
|
</Tomador> |
||||
|
{% if rps.intermediario is defined -%} |
||||
|
<IntermediarioServico> |
||||
|
<RazaoSocial>{{ rps.intermediario.razao_social }}</RazaoSocial> |
||||
|
<CpfCnpj> |
||||
|
<Cnpj>{{ rps.intermediario.cnpj }}</Cnpj> |
||||
|
</CpfCnpj> |
||||
|
<InscricaoMunicipal>{{ rps.intermediario.inscricao_municipal }}</InscricaoMunicipal> |
||||
|
</IntermediarioServico> |
||||
|
{% endif %} |
||||
|
{% if rps.construcao_civil is defined -%} |
||||
|
<ContrucaoCivil> |
||||
|
<CodigoObra>{{ rps.construcao_civil.codigo_obra }}</CodigoObra> |
||||
|
<Art>{{ rps.construcao_civil.art }}</Art> |
||||
|
</ContrucaoCivil> |
||||
|
{% endif %} |
||||
|
</InfRps> |
||||
|
</Rps> |
||||
@ -0,0 +1,74 @@ |
|||||
|
# © 2018 Danimar Ribeiro, Trustcode |
||||
|
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). |
||||
|
|
||||
|
import os |
||||
|
import suds |
||||
|
from pytrustnfe.client import get_authenticated_client |
||||
|
from pytrustnfe.certificado import extract_cert_and_key_from_pfx, save_cert_key |
||||
|
from pytrustnfe.xml import render_xml, sanitize_response |
||||
|
from pytrustnfe.nfe.assinatura import Assinatura |
||||
|
|
||||
|
|
||||
|
def _render(certificado, method, **kwargs): |
||||
|
path = os.path.join(os.path.dirname(__file__), 'templates') |
||||
|
xml_send = render_xml(path, '%s.xml' % method, True, **kwargs) |
||||
|
|
||||
|
reference = '' |
||||
|
if method == 'GerarNfse': |
||||
|
reference = 'r%s' % kwargs['rps']['numero'] |
||||
|
elif method == 'CancelarNfse': |
||||
|
reference = 'Cancelamento_NF%s' % kwargs['cancelamento']['numero_nfse'] |
||||
|
|
||||
|
signer = Assinatura(certificado.pfx, certificado.password) |
||||
|
xml_send = signer.assina_xml(xml_send, reference) |
||||
|
return xml_send.encode('utf-8') |
||||
|
|
||||
|
|
||||
|
def _send(certificado, method, **kwargs): |
||||
|
base_url = '' |
||||
|
if kwargs['ambiente'] == 'producao': |
||||
|
base_url = 'https://notacarioca.rio.gov.br/WSNacional/nfse.asmx?wsdl' |
||||
|
else: |
||||
|
base_url = 'https://homologacao.notacarioca.rio.gov.br/WSNacional/nfse.asmx?wsdl' # noqa |
||||
|
|
||||
|
xml_send = kwargs["xml"].decode('utf-8') |
||||
|
cert, key = extract_cert_and_key_from_pfx( |
||||
|
certificado.pfx, certificado.password) |
||||
|
cert, key = save_cert_key(cert, key) |
||||
|
client = get_authenticated_client(base_url, cert, key) |
||||
|
|
||||
|
try: |
||||
|
response = getattr(client.service, method)(xml_send) |
||||
|
except suds.WebFault as e: |
||||
|
return { |
||||
|
'sent_xml': str(xml_send), |
||||
|
'received_xml': str(e.fault.faultstring), |
||||
|
'object': None |
||||
|
} |
||||
|
|
||||
|
response, obj = sanitize_response(response) |
||||
|
return { |
||||
|
'sent_xml': str(xml_send), |
||||
|
'received_xml': str(response), |
||||
|
'object': obj |
||||
|
} |
||||
|
|
||||
|
|
||||
|
def xml_gerar_nfse(certificado, **kwargs): |
||||
|
return _render(certificado, 'GerarNfse', **kwargs) |
||||
|
|
||||
|
|
||||
|
def gerar_nfse(certificado, **kwargs): |
||||
|
if "xml" not in kwargs: |
||||
|
kwargs['xml'] = xml_gerar_nfse(certificado, **kwargs) |
||||
|
return _send(certificado, 'GerarNfse', **kwargs) |
||||
|
|
||||
|
|
||||
|
def xml_cancelar_nfse(certificado, **kwargs): |
||||
|
return _render(certificado, 'CancelarNfse', **kwargs) |
||||
|
|
||||
|
|
||||
|
def cancelar_nfse(certificado, **kwargs): |
||||
|
if "xml" not in kwargs: |
||||
|
kwargs['xml'] = xml_cancelar_nfse(certificado, **kwargs) |
||||
|
return _send(certificado, 'CancelarNfse', **kwargs) |
||||
@ -0,0 +1,13 @@ |
|||||
|
<CancelarNfseEnvio xmlns="http://www.abrasf.org.br/ABRASF/arquivos/nfse.xsd"> |
||||
|
<Pedido> |
||||
|
<InfPedidoCancelamento Id="Cancelamento_NF{{ cancelamento.numero_nfse }}"> |
||||
|
<IdentificacaoNfse> |
||||
|
<Numero>{{ cancelamento.numero_nfse }}</Numero> |
||||
|
<Cnpj>{{ cancelamento.cnpj_prestador }}</Cnpj> |
||||
|
<InscricaoMunicipal>{{ cancelamento.inscricao_municipal }}</InscricaoMunicipal> |
||||
|
<CodigoMunicipio>{{ cancelamento.cidade }}</CodigoMunicipio> |
||||
|
</IdentificacaoNfse> |
||||
|
<CodigoCancelamento>1</CodigoCancelamento> |
||||
|
</InfPedidoCancelamento> |
||||
|
</Pedido> |
||||
|
</CancelarNfseEnvio> |
||||
@ -0,0 +1,3 @@ |
|||||
|
<GerarNfseEnvio xmlns="http://notacarioca.rio.gov.br/WSNacional/XSD/1/nfse_pcrj_v01.xsd"> |
||||
|
{% include 'Rps.xml' %} |
||||
|
</GerarNfseEnvio> |
||||
@ -0,0 +1,91 @@ |
|||||
|
<Rps> |
||||
|
<InfRps xmlns="http://www.abrasf.org.br/ABRASF/arquivos/nfse.xsd" Id="r{{ rps.numero }}"> |
||||
|
<IdentificacaoRps> |
||||
|
<Numero>{{ rps.numero }}</Numero> |
||||
|
<Serie>{{ rps.serie }}</Serie> |
||||
|
<Tipo>{{ rps.tipo_rps }}</Tipo> |
||||
|
</IdentificacaoRps> |
||||
|
<DataEmissao>{{ rps.data_emissao }}</DataEmissao> |
||||
|
<NaturezaOperacao>{{ rps.natureza_operacao }}</NaturezaOperacao> |
||||
|
<RegimeEspecialTributacao>{{ rps.regime_tributacao }}</RegimeEspecialTributacao> |
||||
|
<OptanteSimplesNacional>{{ rps.optante_simples }}</OptanteSimplesNacional> |
||||
|
<IncentivadorCultural>{{ rps.incentivador_cultural }}</IncentivadorCultural> |
||||
|
<Status>{{ rps.status }}</Status> |
||||
|
<RpsSubstituido> |
||||
|
<Numero>{{ rps.numero_substituido }}</Numero> |
||||
|
<Serie>{{ rps.serie_substituido }}</Serie> |
||||
|
<Tipo>{{ rps.tipo_substituido }}</Tipo> |
||||
|
</RpsSubstituido> |
||||
|
<Servico> |
||||
|
<Valores> |
||||
|
<ValorServicos>{{ rps.valor_servico }}</ValorServicos> |
||||
|
<ValorDeducoes>{{ rps.valor_deducao }}</ValorDeducoes> |
||||
|
<ValorPis>{{ rps.valor_pis }}</ValorPis> |
||||
|
<ValorCofins>{{ rps.valor_cofins }}</ValorCofins> |
||||
|
<ValorInss>{{ rps.valor_inss }}</ValorInss> |
||||
|
<ValorIr>{{ rps.valor_ir }}</ValorIr> |
||||
|
<ValorCsll>{{ rps.valor_csll }}</ValorCsll> |
||||
|
<IssRetido>{{ rps.iss_retido }}</IssRetido> |
||||
|
<ValorIss>{{ rps.valor_iss }}</ValorIss> |
||||
|
<ValorIssRetido>{{ rps.valor_iss_retido }}</ValorIssRetido> |
||||
|
<OutrasRetencoes>{{ rps.outras_retencoes }}</OutrasRetencoes> |
||||
|
<BaseCalculo>{{ rps.base_calculo }}</BaseCalculo> |
||||
|
<Aliquota>{{ rps.aliquota_issqn }}</Aliquota> |
||||
|
<ValorLiquidoNfse>{{ rps.valor_liquido_nfse }}</ValorLiquidoNfse> |
||||
|
<DescontoIncondicionado>{{ rps.desconto_incondicionado }}</DescontoIncondicionado> |
||||
|
<DescontoCondicionado>{{ rps.desconto_condicionado }}</DescontoCondicionado> |
||||
|
</Valores> |
||||
|
<ItemListaServico>{{ rps.codigo_servico }}</ItemListaServico> |
||||
|
<CodigoCnae>{{ rps.cnae_servico }}</CodigoCnae> |
||||
|
<CodigoTributacaoMunicipio>{{ rps.codigo_tributacao_municipio }}</CodigoTributacaoMunicipio> |
||||
|
<Discriminacao>{{ rps.descricao }}</Discriminacao> |
||||
|
<CodigoMunicipio>{{ rps.codigo_municipio }}</CodigoMunicipio> |
||||
|
</Servico> |
||||
|
<Prestador> |
||||
|
<Cnpj>{{ rps.prestador.cnpj }}</Cnpj> |
||||
|
<InscricaoMunicipal>{{ rps.prestador.inscricao_municipal }}</InscricaoMunicipal> |
||||
|
</Prestador> |
||||
|
<Tomador> |
||||
|
<IdentificacaoTomador> |
||||
|
<CpfCnpj> |
||||
|
{% if rps.tomador.cnpj_cpf|length == 14 %} |
||||
|
<Cnpj>{{ rps.tomador.cnpj_cpf }}</Cnpj> |
||||
|
{% endif %} |
||||
|
{% if rps.tomador.cnpj_cpf|length == 11 %} |
||||
|
<Cpf>{{ rps.tomador.cnpj_cpf }}</Cpf> |
||||
|
{% endif %} |
||||
|
</CpfCnpj> |
||||
|
<InscricaoMunicipal>{{ rps.tomador.inscricao_municipal }}</InscricaoMunicipal> |
||||
|
</IdentificacaoTomador> |
||||
|
<RazaoSocial>{{ rps.tomador.razao_social }}</RazaoSocial> |
||||
|
<Endereco> |
||||
|
<Endereco>{{ rps.tomador.logradouro }}</Endereco> |
||||
|
<Numero>{{ rps.tomador.numero }}</Numero> |
||||
|
<Complemento>{{ rps.tomador.complemento }}</Complemento> |
||||
|
<Bairro>{{ rps.tomador.bairro }}</Bairro> |
||||
|
<CodigoMunicipio>{{ rps.tomador.cidade }}</CodigoMunicipio> |
||||
|
<Uf>{{ rps.tomador.uf }}</Uf> |
||||
|
<Cep>{{ rps.tomador.cep }}</Cep> |
||||
|
</Endereco> |
||||
|
<Contato> |
||||
|
<Telefone>{{ rps.tomador.telefone }}</Telefone> |
||||
|
<Email>{{ rps.tomador.email }}</Email> |
||||
|
</Contato> |
||||
|
</Tomador> |
||||
|
{% if rps.intermediario is defined -%} |
||||
|
<IntermediarioServico> |
||||
|
<RazaoSocial>{{ rps.intermediario.razao_social }}</RazaoSocial> |
||||
|
<CpfCnpj> |
||||
|
<Cnpj>{{ rps.intermediario.cnpj }}</Cnpj> |
||||
|
</CpfCnpj> |
||||
|
<InscricaoMunicipal>{{ rps.intermediario.inscricao_municipal }}</InscricaoMunicipal> |
||||
|
</IntermediarioServico> |
||||
|
{% endif %} |
||||
|
{% if rps.construcao_civil is defined -%} |
||||
|
<ContrucaoCivil> |
||||
|
<CodigoObra>{{ rps.construcao_civil.codigo_obra }}</CodigoObra> |
||||
|
<Art>{{ rps.construcao_civil.art }}</Art> |
||||
|
</ContrucaoCivil> |
||||
|
{% endif %} |
||||
|
</InfRps> |
||||
|
</Rps> |
||||
@ -0,0 +1,131 @@ |
|||||
|
# -*- encoding: utf-8 -*- |
||||
|
# © 2017 Fábio Luna, Trustcode |
||||
|
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). |
||||
|
|
||||
|
import os |
||||
|
import suds |
||||
|
from lxml import etree |
||||
|
from pytrustnfe.xml import render_xml, sanitize_response |
||||
|
from pytrustnfe.certificado import extract_cert_and_key_from_pfx, save_cert_key |
||||
|
from pytrustnfe.nfse.assinatura import Assinatura |
||||
|
from pytrustnfe.client import get_client |
||||
|
|
||||
|
|
||||
|
def _render(certificado, method, **kwargs): |
||||
|
path = os.path.join(os.path.dirname(__file__), 'templates') |
||||
|
if method == "testeEnviar": |
||||
|
xml_send = render_xml(path, 'enviar.xml', True, **kwargs) |
||||
|
else: |
||||
|
xml_send = render_xml(path, '%s.xml' % method, False, **kwargs) |
||||
|
|
||||
|
if type(xml_send) != str: |
||||
|
xml_send = etree.tostring(xml_send) |
||||
|
|
||||
|
return xml_send |
||||
|
|
||||
|
|
||||
|
def _get_url(**kwargs): |
||||
|
|
||||
|
try: |
||||
|
cod_cidade = kwargs['nfse']['cidade'] |
||||
|
except (KeyError, TypeError): |
||||
|
raise KeyError("Código de cidade inválido!") |
||||
|
|
||||
|
urls = { |
||||
|
# Belém - PA |
||||
|
'2715': 'http://www.issdigitalbel.com.br/WsNFe2/LoteRps.jws', |
||||
|
# Sorocaba - SP |
||||
|
'7145': 'http://issdigital.sorocaba.sp.gov.br/WsNFe2/LoteRps.jws', |
||||
|
# Teresina - PI |
||||
|
'1219': 'http://www.issdigitalthe.com.br/WsNFe2/LoteRps.jws', |
||||
|
# Campinas - SP |
||||
|
'6291': 'http://issdigital.campinas.sp.gov.br/WsNFe2/LoteRps.jws?wsdl', |
||||
|
# Uberlandia - MG |
||||
|
'5403': 'http://udigital.uberlandia.mg.gov.br/WsNFe2/LoteRps.jws', |
||||
|
# São Luis - MA |
||||
|
'0921': 'https://stm.semfaz.saoluis.ma.gov.br/WsNFe2/LoteRps?wsdl', |
||||
|
# Campo Grande - MS |
||||
|
'2729': 'http://issdigital.pmcg.ms.gov.br/WsNFe2/LoteRps.jws?wsdl', |
||||
|
} |
||||
|
|
||||
|
try: |
||||
|
return urls[str(cod_cidade)] |
||||
|
except KeyError: |
||||
|
raise KeyError("DSF não emite notas da cidade {}!".format( |
||||
|
cod_cidade)) |
||||
|
|
||||
|
|
||||
|
def _send(certificado, method, **kwargs): |
||||
|
url = _get_url(**kwargs) |
||||
|
|
||||
|
path = os.path.join(os.path.dirname(__file__), 'templates') |
||||
|
|
||||
|
xml_send = _render(path, method, **kwargs) |
||||
|
client = get_client(url) |
||||
|
response = False |
||||
|
|
||||
|
if certificado: |
||||
|
cert, key = extract_cert_and_key_from_pfx( |
||||
|
certificado.pfx, certificado.password) |
||||
|
cert, key = save_cert_key(cert, key) |
||||
|
signer = Assinatura(cert, key, certificado.password) |
||||
|
xml_send = signer.assina_xml(xml_send, '') |
||||
|
|
||||
|
try: |
||||
|
response = getattr(client.service, method)(xml_send) |
||||
|
response, obj = sanitize_response(response.encode()) |
||||
|
except suds.WebFault as e: |
||||
|
return { |
||||
|
'sent_xml': xml_send, |
||||
|
'received_xml': e.fault.faultstring, |
||||
|
'object': None |
||||
|
} |
||||
|
except Exception as e: |
||||
|
if response: |
||||
|
raise Exception(response) |
||||
|
else: |
||||
|
raise e |
||||
|
|
||||
|
return { |
||||
|
'sent_xml': xml_send, |
||||
|
'received_xml': response, |
||||
|
'object': obj |
||||
|
} |
||||
|
|
||||
|
|
||||
|
def xml_enviar(certificado, **kwargs): |
||||
|
return _render(certificado, 'enviar', **kwargs) |
||||
|
|
||||
|
|
||||
|
def enviar(certificado, **kwargs): |
||||
|
if "xml" not in kwargs: |
||||
|
kwargs['xml'] = xml_enviar(certificado, **kwargs) |
||||
|
return _send(certificado, 'enviar', **kwargs) |
||||
|
|
||||
|
|
||||
|
def xml_teste_enviar(certificado, **kwargs): |
||||
|
return _render(certificado, 'testeEnviar', **kwargs) |
||||
|
|
||||
|
|
||||
|
def teste_enviar(certificado, **kwargs): |
||||
|
if "xml" not in kwargs: |
||||
|
kwargs['xml'] = xml_teste_enviar(certificado, **kwargs) |
||||
|
return _send(certificado, 'testeEnviar', **kwargs) |
||||
|
|
||||
|
|
||||
|
def cancelar(certificado, ** kwargs): |
||||
|
return _send(certificado, 'cancelar', **kwargs) |
||||
|
|
||||
|
|
||||
|
def consulta_lote(**kwargs): |
||||
|
return _send(False, 'consultarLote', **kwargs) |
||||
|
|
||||
|
|
||||
|
def xml_consultar_nfse_rps(certificado, **kwargs): |
||||
|
return _render(certificado, 'consultarNFSeRps', **kwargs) |
||||
|
|
||||
|
|
||||
|
def consultar_nfse_rps(certificado, **kwargs): |
||||
|
if "xml" not in kwargs: |
||||
|
kwargs['xml'] = xml_consultar_nfse_rps(certificado, **kwargs) |
||||
|
return _send(certificado, 'consultarNFSeRps', **kwargs) |
||||
@ -0,0 +1,18 @@ |
|||||
|
<ns1:ReqCancelamentoNFSe xmlns:ns1="http://localhost:8080/WsNFe2/lote" |
||||
|
xmlns:tipos="http://localhost:8080/WsNFe2/tp" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |
||||
|
xsi:schemaLocation="http://localhost:8080/WsNFe2/lote http://localhost:8080/WsNFe2/xsd/ReqCancelamentoNFSe.xsd"> |
||||
|
<Cabecalho> |
||||
|
<CodCidade>{{ cancelamento.cidade }}</CodCidade> |
||||
|
<CPFCNPJRemetente>{{ cancelamento.cpf_cnpj }}</CPFCNPJRemetente> |
||||
|
<transacao>true</transacao> |
||||
|
<Versao>1</Versao> |
||||
|
</Cabecalho> |
||||
|
<Lote Id="lote:1ABCDZ"> |
||||
|
<Nota Id="nota:{{ cancelamento.nota_id }}"> |
||||
|
<InscricaoMunicipalPrestador>{{ cancelamento.inscricao_municipal }}</InscricaoMunicipalPrestador> |
||||
|
<NumeroNota>{{ cancelamento.nota_id }}</NumeroNota> |
||||
|
<CodigoVerificacao>{{ cancelamento.assinatura }}</CodigoVerificacao> |
||||
|
<MotivoCancelamento>{{ cancelamento.motivo }}</MotivoCancelamento> |
||||
|
</Nota> |
||||
|
</Lote> |
||||
|
</ns1:ReqCancelamentoNFSe> |
||||
@ -0,0 +1,11 @@ |
|||||
|
<ns1:ReqConsultaNotas xmlns:ns1="http://localhost:8080/WsNFe2/lote" xmlns:tipos="http://localhost:8080/WsNFe2/tp" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://localhost:8080/WsNFe2/lote http://localhost:8080/WsNFe2/xsd/ReqConsultaNotas.xsd"> |
||||
|
<Cabecalho Id="Consulta:notas"> |
||||
|
<CodCidade>{{ consulta.cidade }}</CodCidade> |
||||
|
<CPFCNPJRemetente>{{ consulta.cpf_cnpj }}</CPFCNPJRemetente> |
||||
|
<InscricaoMunicipalPrestador>{{ consulta.inscricao_municipal }}</InscricaoMunicipalPrestador> |
||||
|
<dtInicio>{{ consulta.data_inicio }}</dtInicio> |
||||
|
<dtFim>{{ consulta.data_final }}</dtFim> |
||||
|
<NotaInicial>{{ consulta.nota_inicial }}</NotaInicial> |
||||
|
<Versao>1</Versao> |
||||
|
</Cabecalho> |
||||
|
</ns1:ReqConsultaNotas> |
||||
@ -0,0 +1,10 @@ |
|||||
|
<ns1:ReqConsultaLote xmlns:ns1="http://localhost:8080/WsNFe2/lote" |
||||
|
xmlns:tipos="http://localhost:8080/WsNFe2/tp" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |
||||
|
xsi:schemaLocation="http://localhost:8080/WsNFe2/lote http://localhost:8080/WsNFe2/xsd/ReqConsultaLote.xsd"> |
||||
|
<Cabecalho> |
||||
|
<CodCidade>{{ consulta.cidade }}</CodCidade> |
||||
|
<CPFCNPJRemetente>{{ consulta.cpf_cnpj }}</CPFCNPJRemetente> |
||||
|
<Versao>1</Versao> |
||||
|
<NumeroLote>{{ consulta.lote }}</NumeroLote> |
||||
|
</Cabecalho> |
||||
|
</ns1:ReqConsultaLote> |
||||
@ -0,0 +1,22 @@ |
|||||
|
<ns1:ReqConsultaNFSeRPS |
||||
|
xmlns:ns1="http://localhost:8080/WsNFe2/lote" |
||||
|
xmlns:tipos="http://localhost:8080/WsNFe2/tp" |
||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://localhost:8080/WsNFe2/lote http://localhost:8080/WsNFe2/xsd/ReqConsultaNFSeRPS.xsd"> |
||||
|
<Cabecalho> |
||||
|
<CodCidade>{{ nfse.cidade }}</CodCidade> |
||||
|
<CPFCNPJRemetente>{{ nfse.cpf_cnpj }}</CPFCNPJRemetente> |
||||
|
<transacao>true</transacao> |
||||
|
<Versao>1</Versao> |
||||
|
</Cabecalho> |
||||
|
<Lote Id="lote:{{ nfse.lote }}"> |
||||
|
{% for rps in nfse.lista_rps -%} |
||||
|
<RPSConsulta> |
||||
|
<RPS Id="rps:{{ rps.numero }}"> |
||||
|
<InscricaoMunicipalPrestador>{{ rps.prestador.inscricao_municipal }}</InscricaoMunicipalPrestador> |
||||
|
<NumeroRPS>{{ rps.numero }}</NumeroRPS> |
||||
|
<SeriePrestacao>{{ rps.serie_prestacao }}</SeriePrestacao> |
||||
|
</RPS> |
||||
|
</RPSConsulta> |
||||
|
{% endfor %} |
||||
|
</Lote> |
||||
|
</ns1:ReqConsultaNFSeRPS> |
||||
@ -0,0 +1,108 @@ |
|||||
|
<ns1:ReqEnvioLoteRPS xmlns:ns1="http://localhost:8080/WsNFe2/lote" |
||||
|
xmlns:tipos="http://localhost:8080/WsNFe2/tp" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |
||||
|
xsi:schemaLocation="http://localhost:8080/WsNFe2/lote http://localhost:8080/WsNFe2/xsd/ReqEnvioLoteRPS.xsd"> |
||||
|
<Cabecalho> |
||||
|
<CodCidade>{{ nfse.cidade }}</CodCidade> |
||||
|
<CPFCNPJRemetente>{{ nfse.cpf_cnpj }}</CPFCNPJRemetente> |
||||
|
<RazaoSocialRemetente>{{ nfse.remetente }}</RazaoSocialRemetente> |
||||
|
<transacao>{{ nfse.transacao }}</transacao> |
||||
|
<dtInicio>{{ nfse.data_inicio|format_date }}</dtInicio> |
||||
|
<dtFim>{{ nfse.data_fim|format_date }}</dtFim> |
||||
|
<QtdRPS>{{ nfse.total_rps }}</QtdRPS> |
||||
|
<ValorTotalServicos>{{ nfse.total_servicos }}</ValorTotalServicos> |
||||
|
<ValorTotalDeducoes>{{ nfse.total_deducoes }}</ValorTotalDeducoes> |
||||
|
<Versao>1</Versao> |
||||
|
<MetodoEnvio>WS</MetodoEnvio> |
||||
|
</Cabecalho> |
||||
|
<Lote Id="{{ nfse.lote_id }}"> |
||||
|
{% for rps in nfse.lista_rps -%} |
||||
|
<RPS Id="{{ rps.numero }}"> |
||||
|
<Assinatura>{{ rps.assinatura }}</Assinatura> |
||||
|
<InscricaoMunicipalPrestador>{{ rps.prestador.inscricao_municipal }} |
||||
|
</InscricaoMunicipalPrestador> |
||||
|
<RazaoSocialPrestador>{{ rps.prestador.razao_social }}</RazaoSocialPrestador> |
||||
|
<TipoRPS>RPS</TipoRPS> |
||||
|
<SerieRPS>{{ rps.serie }}</SerieRPS> |
||||
|
<NumeroRPS>{{ rps.numero }}</NumeroRPS> |
||||
|
<DataEmissaoRPS>{{ rps.data_emissao|format_datetime }} |
||||
|
</DataEmissaoRPS> |
||||
|
<SituacaoRPS>{{ rps.situacao }}</SituacaoRPS> |
||||
|
<SerieRPSSubstituido></SerieRPSSubstituido> |
||||
|
<NumeroRPSSubstituido>0</NumeroRPSSubstituido> |
||||
|
<NumeroNFSeSubstituida>0</NumeroNFSeSubstituida> |
||||
|
<DataEmissaoNFSeSubstituida>1900-01-01</DataEmissaoNFSeSubstituida> |
||||
|
<SeriePrestacao>{{ rps.serie_prestacao }}</SeriePrestacao> |
||||
|
<InscricaoMunicipalTomador>{{ rps.tomador.inscricao_municipal }}</InscricaoMunicipalTomador> |
||||
|
<CPFCNPJTomador>{{ rps.tomador.cpf_cnpj }}</CPFCNPJTomador> |
||||
|
<RazaoSocialTomador>{{ rps.tomador.razao_social }} |
||||
|
</RazaoSocialTomador> |
||||
|
<TipoLogradouroTomador>{{ rps.tomador.tipo_logradouro }} |
||||
|
</TipoLogradouroTomador> |
||||
|
<LogradouroTomador>{{ rps.tomador.logradouro }}</LogradouroTomador> |
||||
|
<NumeroEnderecoTomador>{{ rps.tomador.numero }} |
||||
|
</NumeroEnderecoTomador> |
||||
|
<TipoBairroTomador>{{ rps.tomador.tipo_bairro }}</TipoBairroTomador> |
||||
|
<BairroTomador>{{ rps.tomador.bairro }}</BairroTomador> |
||||
|
<CidadeTomador>{{ rps.tomador.cidade }}</CidadeTomador> |
||||
|
<CidadeTomadorDescricao>{{ rps.tomador.cidade_descricao }} |
||||
|
</CidadeTomadorDescricao> |
||||
|
<CEPTomador>{{ rps.tomador.cep }}</CEPTomador> |
||||
|
<EmailTomador>{{ rps.tomador.email }}</EmailTomador> |
||||
|
<CodigoAtividade>{{ rps.codigo_atividade }}</CodigoAtividade> |
||||
|
<AliquotaAtividade>{{ rps.aliquota_atividade }}</AliquotaAtividade> |
||||
|
<TipoRecolhimento>{{ rps.tipo_recolhimento }}</TipoRecolhimento> |
||||
|
<MunicipioPrestacao>{{ rps.municipio_prestacao }} |
||||
|
</MunicipioPrestacao> |
||||
|
<MunicipioPrestacaoDescricao>{{ rps.municipio_descricao_prestacao }} |
||||
|
</MunicipioPrestacaoDescricao> |
||||
|
<Operacao>{{ rps.operacao }}</Operacao> |
||||
|
<Tributacao>{{ rps.tributacao }}</Tributacao> |
||||
|
<ValorPIS>{{ rps.valor_pis }}</ValorPIS> |
||||
|
<ValorCOFINS>{{ rps.valor_cofins }}</ValorCOFINS> |
||||
|
<ValorINSS>{{ rps.valor_inss }}</ValorINSS> |
||||
|
<ValorIR>{{ rps.valor_ir }}</ValorIR> |
||||
|
<ValorCSLL>{{ rps.valor_csll }}</ValorCSLL> |
||||
|
<AliquotaPIS>{{ rps.aliquota_pis }}</AliquotaPIS> |
||||
|
<AliquotaCOFINS>{{ rps.aliquota_cofins }}</AliquotaCOFINS> |
||||
|
<AliquotaINSS>{{ rps.aliquota_inss }}</AliquotaINSS> |
||||
|
<AliquotaIR>{{ rps.aliquota_ir }}</AliquotaIR> |
||||
|
<AliquotaCSLL>{{ rps.aliquota_csll }}</AliquotaCSLL> |
||||
|
<DescricaoRPS>{{ rps.descricao }}</DescricaoRPS> |
||||
|
<DDDPrestador>{{ rps.prestador.ddd }}</DDDPrestador> |
||||
|
<TelefonePrestador>{{ rps.prestador.telefone }}</TelefonePrestador> |
||||
|
<DDDTomador>{{ rps.tomador.ddd }}</DDDTomador> |
||||
|
<TelefoneTomador>{{ rps.tomador.telefone }}</TelefoneTomador> |
||||
|
<MotCancelamento>{{ rps.motivo_cancelamento }}</MotCancelamento> |
||||
|
{% if rps.deducoes|count > 0 %} |
||||
|
<Deducoes> |
||||
|
{% for deducao in rps.deducoes -%} |
||||
|
<Deducao> |
||||
|
<DeducaoPor>{{ deducao.por }}</DeducaoPor> |
||||
|
<TipoDeducao>{{ deducao.tipo }}</TipoDeducao> |
||||
|
<CPFCNPJReferencia>{{ deducao.cnpj_referencia }}</CPFCNPJReferencia> |
||||
|
<NumeroNFReferencia>{{ deducao.nf_referencia }}</NumeroNFReferencia> |
||||
|
<ValorTotalReferencia>{{ deducao.valor_referencia }}</ValorTotalReferencia> |
||||
|
<PercentualDeduzir>{{ deducao.percentual_deduzir }}</PercentualDeduzir> |
||||
|
<ValorDeduzir>{{ deducao.valor_deduzir }}</ValorDeduzir> |
||||
|
</Deducao> |
||||
|
{% endfor %} |
||||
|
</Deducoes> |
||||
|
{% endif %} |
||||
|
{% if rps.deducoes|count == 0 %} |
||||
|
<Deducoes /> |
||||
|
{% endif %} |
||||
|
<Itens> |
||||
|
{% for item in rps.itens -%} |
||||
|
<Item> |
||||
|
<DiscriminacaoServico>{{ item.descricao }}</DiscriminacaoServico> |
||||
|
<Quantidade>{{ item.quantidade }}</Quantidade> |
||||
|
<ValorUnitario>{{ item.valor_unitario }}</ValorUnitario> |
||||
|
<ValorTotal>{{ item.valor_total }}</ValorTotal> |
||||
|
<Tributavel>S</Tributavel> |
||||
|
</Item> |
||||
|
{% endfor %} |
||||
|
</Itens> |
||||
|
</RPS> |
||||
|
{% endfor %} |
||||
|
</Lote> |
||||
|
</ns1:ReqEnvioLoteRPS> |
||||
@ -0,0 +1,12 @@ |
|||||
|
<?xml version="1.0" encoding="UTF-8"?> |
||||
|
<soapenv:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |
||||
|
xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" |
||||
|
xmlns:dsf="http://dsfnet.com.br"> |
||||
|
<soapenv:Body> |
||||
|
<dsf:enviar soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"> |
||||
|
<mensagemXml xsi:type="xsd:string"><![CDATA[ |
||||
|
{% block content %}{% endblock %} |
||||
|
]]></mensagemXml> |
||||
|
</dsf:enviar> |
||||
|
</soapenv:Body> |
||||
|
</soapenv:Envelope> |
||||
@ -0,0 +1,119 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
# © 2017 Danimar Ribeiro, Trustcode |
||||
|
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). |
||||
|
|
||||
|
import os |
||||
|
import hashlib |
||||
|
import base64 |
||||
|
import requests |
||||
|
from pytrustnfe.xml import render_xml, sanitize_response |
||||
|
from pytrustnfe.certificado import extract_cert_and_key_from_pfx, save_cert_key |
||||
|
from pytrustnfe.nfse.assinatura import Assinatura |
||||
|
|
||||
|
URLS = { |
||||
|
'producao': { |
||||
|
'processar_nota': 'https://nfps-e.pmf.sc.gov.br/api/v1/processamento/notas/processa', |
||||
|
'cancelar_nota': 'https://nfps-e.pmf.sc.gov.br/api/v1/cancelamento/notas/cancela' |
||||
|
}, |
||||
|
'homologacao': { |
||||
|
'processar_nota': 'https://nfps-e-hml.pmf.sc.gov.br/api/v1/processamento/notas/processa', |
||||
|
'cancelar_nota': 'https://nfps-e-hml.pmf.sc.gov.br/api/v1/cancelamento/notas/cancela' |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
|
||||
|
def _render(certificado, method, **kwargs): |
||||
|
path = os.path.join(os.path.dirname(__file__), 'templates') |
||||
|
xml_send = render_xml(path, '%s.xml' % method, False, **kwargs) |
||||
|
|
||||
|
cert, key = extract_cert_and_key_from_pfx( |
||||
|
certificado.pfx, certificado.password) |
||||
|
cert, key = save_cert_key(cert, key) |
||||
|
signer = Assinatura(cert, key, certificado.password) |
||||
|
xml_send = signer.assina_xml(xml_send, '') |
||||
|
return xml_send |
||||
|
|
||||
|
|
||||
|
def _get_oauth_token(**kwargs): |
||||
|
if kwargs['ambiente'] == 'producao': |
||||
|
url = 'https://nfps-e.pmf.sc.gov.br/api/v1/autenticacao/oauth/token' |
||||
|
else: |
||||
|
url = 'https://nfps-e-hml.pmf.sc.gov.br/api/v1/autenticacao/oauth/token' |
||||
|
|
||||
|
m = hashlib.md5() |
||||
|
secret = "%s:%s" % (kwargs["client_id"], kwargs["secret_id"]) |
||||
|
auth = base64.b64encode(secret.encode('utf-8')) |
||||
|
headers = { |
||||
|
"Content-Type": "application/x-www-form-urlencoded", |
||||
|
"Authorization": "Basic %s" % auth.decode('utf-8').replace('\n', '') |
||||
|
} |
||||
|
m.update(kwargs["password"].encode('utf-8')) |
||||
|
password = m.hexdigest().upper() |
||||
|
|
||||
|
dados = "grant_type=password&username=%s&password=%s&client_id=%s&client_secret=%s" % ( |
||||
|
kwargs["username"], password, kwargs["client_id"], kwargs["secret_id"]) |
||||
|
r = requests.post(url, data=dados, headers=headers) |
||||
|
if r.status_code == 200: |
||||
|
return r.json() |
||||
|
else: |
||||
|
return r.json() |
||||
|
|
||||
|
|
||||
|
def _send(certificado, method, **kwargs): |
||||
|
url = URLS[kwargs['ambiente']][method] |
||||
|
xml_send = kwargs['xml'] |
||||
|
|
||||
|
token = _get_oauth_token(**kwargs) |
||||
|
if "access_token" not in token: |
||||
|
raise Exception("%s - %s: %s" % (token["status"], token["error"], |
||||
|
token["message"])) |
||||
|
kwargs.update({"numero": 1, 'access_token': token["access_token"]}) |
||||
|
|
||||
|
headers = {"Accept": "application/xml;charset=UTF-8", |
||||
|
"Content-Type": "application/xml", |
||||
|
"Authorization": "Bearer %s" % kwargs['access_token']} |
||||
|
r = requests.post(url, headers=headers, data=xml_send) |
||||
|
|
||||
|
response, obj = sanitize_response(r.text.strip().encode('utf-8')) |
||||
|
return { |
||||
|
'sent_xml': xml_send, |
||||
|
'received_xml': response, |
||||
|
'object': obj, |
||||
|
'status_code': r.status_code, |
||||
|
} |
||||
|
|
||||
|
|
||||
|
def xml_processar_nota(certificado, **kwargs): |
||||
|
return _render(certificado, 'processar_nota', **kwargs) |
||||
|
|
||||
|
|
||||
|
def processar_nota(certificado, **kwargs): |
||||
|
if "xml" not in kwargs: |
||||
|
kwargs['xml'] = xml_processar_nota(certificado, **kwargs) |
||||
|
return _send(certificado, 'processar_nota', **kwargs) |
||||
|
|
||||
|
|
||||
|
def xml_cancelar_nota(certificado, **kwargs): |
||||
|
return _render(certificado, 'cancelar_nota', **kwargs) |
||||
|
|
||||
|
|
||||
|
def cancelar_nota(certificado, **kwargs): |
||||
|
if "xml" not in kwargs: |
||||
|
kwargs['xml'] = xml_cancelar_nota(certificado, **kwargs) |
||||
|
return _send(certificado, 'cancelar_nota', **kwargs) |
||||
|
|
||||
|
|
||||
|
def consultar_nota(certificado, **kwargs): |
||||
|
if kwargs['ambiente'] == 'producao': |
||||
|
url = "https://nfps-e.pmf.sc.gov.br/api/v1/consultas/notas/numero/%s" % (kwargs["numero"]) |
||||
|
else: |
||||
|
url = "https://nfps-e-hml.pmf.sc.gov.br/api/v1/consultas/notas/numero/%s" % (kwargs["numero"]) |
||||
|
|
||||
|
headers = {"Accept": "application/json", |
||||
|
"Authorization": "Bearer %s" % kwargs['access_token']} |
||||
|
r = requests.get(url, headers=headers) |
||||
|
print(r.status_code) |
||||
|
if r.status_code == 200: |
||||
|
return r.text |
||||
|
else: |
||||
|
return r.text |
||||
@ -0,0 +1,7 @@ |
|||||
|
<?xml version="1.0"?> |
||||
|
<xmlCancelamentoNfpse> |
||||
|
<motivoCancelamento>{{ cancelamento.motivo }}</motivoCancelamento> |
||||
|
<nuAedf>{{ cancelamento.aedf }}</nuAedf> |
||||
|
<nuNotaFiscal>{{ cancelamento.numero }}</nuNotaFiscal> |
||||
|
<codigoVerificacao>{{ cancelamento.codigo_verificacao }}</codigoVerificacao> |
||||
|
</xmlCancelamentoNfpse> |
||||
@ -0,0 +1,41 @@ |
|||||
|
<?xml version="1.0"?> |
||||
|
<xmlProcessamentoNfpse> |
||||
|
<bairroTomador>{{ rps.tomador.bairro|normalize|escape }}</bairroTomador> |
||||
|
<baseCalculo>{{ rps.base_calculo }}</baseCalculo> |
||||
|
<baseCalculoSubstituicao>0.0</baseCalculoSubstituicao> |
||||
|
<cfps>{{ rps.cfps }}</cfps> |
||||
|
<codigoMunicipioTomador>{{ rps.tomador.cidade }}</codigoMunicipioTomador> |
||||
|
<codigoPostalTomador>{{ rps.tomador.cep }}</codigoPostalTomador> |
||||
|
<complementoEnderecoTomador>{{ rps.tomador.complemento|normalize|escape }}</complementoEnderecoTomador> |
||||
|
<dadosAdicionais>{{ rps.observacoes|normalize|escape }}</dadosAdicionais> |
||||
|
<dataEmissao>{{ rps.data_emissao }}</dataEmissao> |
||||
|
<emailTomador>{{ rps.tomador.email }}</emailTomador> |
||||
|
<identificacao>{{ rps.numero }}</identificacao> |
||||
|
<identificacaoTomador>{{ rps.tomador.cnpj_cpf }}</identificacaoTomador> |
||||
|
<inscricaoMunicipalTomador>{{ rps.tomador.inscricao_municipal }}</inscricaoMunicipalTomador> |
||||
|
<itensServico> |
||||
|
{% for item in rps.itens_servico -%} |
||||
|
<itemServico> |
||||
|
<aliquota>{{ item.aliquota }}</aliquota> |
||||
|
<baseCalculo>{{ item.base_calculo }}</baseCalculo> |
||||
|
<cst>{{ item.cst_servico }}</cst> |
||||
|
<descricaoServico>{{ item.name|normalize|escape }}</descricaoServico> |
||||
|
<idCNAE>{{ item.cnae }}</idCNAE> |
||||
|
<quantidade>{{ item.quantidade }}</quantidade> |
||||
|
<valorTotal>{{ item.valor_total }}</valorTotal> |
||||
|
<valorUnitario>{{ item.valor_unitario }}</valorUnitario> |
||||
|
</itemServico> |
||||
|
{% endfor %} |
||||
|
</itensServico> |
||||
|
<logradouroTomador>{{ rps.tomador.logradouro|normalize|escape }}</logradouroTomador> |
||||
|
<nomeMunicipioTomador></nomeMunicipioTomador> |
||||
|
<numeroAEDF>{{ rps.aedf }}</numeroAEDF> |
||||
|
<numeroEnderecoTomador>{{ rps.tomador.numero }}</numeroEnderecoTomador> |
||||
|
<paisTomador>1058</paisTomador> |
||||
|
<razaoSocialTomador>{{ rps.tomador.razao_social|normalize|escape }}</razaoSocialTomador> |
||||
|
<telefoneTomador>{{ rps.tomador.telefone }}</telefoneTomador> |
||||
|
<ufTomador>{{ rps.tomador.uf }}</ufTomador> |
||||
|
<valorISSQN>{{rps.valor_issqn }}</valorISSQN> |
||||
|
<valorISSQNSubstituicao>0.0</valorISSQNSubstituicao> |
||||
|
<valorTotalServicos>{{ rps.valor_total }}</valorTotalServicos> |
||||
|
</xmlProcessamentoNfpse> |
||||
@ -0,0 +1,82 @@ |
|||||
|
# © 2018 Danimar Ribeiro, Trustcode |
||||
|
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). |
||||
|
|
||||
|
import os |
||||
|
from lxml import etree |
||||
|
from requests import Session |
||||
|
from zeep import Client |
||||
|
from zeep.transports import Transport |
||||
|
|
||||
|
from pytrustnfe.certificado import extract_cert_and_key_from_pfx, save_cert_key |
||||
|
from pytrustnfe.xml import render_xml, sanitize_response |
||||
|
from pytrustnfe.nfse.mga.assinatura import Assinatura |
||||
|
|
||||
|
|
||||
|
def _render(certificado, method, **kwargs): |
||||
|
path = os.path.join(os.path.dirname(__file__), 'templates') |
||||
|
xml_send = render_xml(path, '%s.xml' % method, True, **kwargs) |
||||
|
|
||||
|
reference = '' |
||||
|
if method == 'GerarNfse': |
||||
|
reference = 'rps:%s' % kwargs['rps']['numero'] |
||||
|
ref_lote = 'lote%s' % kwargs['rps']['numero_lote'] |
||||
|
elif method == 'CancelarNfse': |
||||
|
reference = 'Cancelamento_NF%s' % kwargs['cancelamento']['numero_nfse'] |
||||
|
|
||||
|
signer = Assinatura(certificado.pfx, certificado.password) |
||||
|
xml_send = signer.assina_xml(xml_send, reference) |
||||
|
xml_send = signer.assina_xml(etree.fromstring(xml_send), ref_lote) |
||||
|
return xml_send.encode('utf-8') |
||||
|
|
||||
|
|
||||
|
def _send(certificado, method, **kwargs): |
||||
|
base_url = '' |
||||
|
if kwargs['ambiente'] == 'producao': |
||||
|
base_url = 'https://isse.maringa.gov.br/ws/?wsdl' |
||||
|
else: |
||||
|
base_url = 'https://isseteste.maringa.gov.br/ws/?wsdl' |
||||
|
|
||||
|
xml_send = kwargs["xml"].decode('utf-8') |
||||
|
xml_cabecalho = '<?xml version="1.0" encoding="UTF-8"?>\ |
||||
|
<cabecalho xmlns="http://www.abrasf.org.br/nfse.xsd" versao="1.00">\ |
||||
|
<versaoDados>1.00</versaoDados></cabecalho>' |
||||
|
|
||||
|
cert, key = extract_cert_and_key_from_pfx( |
||||
|
certificado.pfx, certificado.password) |
||||
|
cert, key = save_cert_key(cert, key) |
||||
|
|
||||
|
session = Session() |
||||
|
session.cert = (cert, key) |
||||
|
session.verify = False |
||||
|
transport = Transport(session=session) |
||||
|
|
||||
|
client = Client(base_url, transport=transport) |
||||
|
|
||||
|
response = client.service[method](xml_cabecalho, xml_send) |
||||
|
|
||||
|
response, obj = sanitize_response(response.encode('utf-8')) |
||||
|
return { |
||||
|
'sent_xml': str(xml_send), |
||||
|
'received_xml': str(response), |
||||
|
'object': obj |
||||
|
} |
||||
|
|
||||
|
|
||||
|
def xml_gerar_nfse(certificado, **kwargs): |
||||
|
return _render(certificado, 'GerarNfse', **kwargs) |
||||
|
|
||||
|
|
||||
|
def gerar_nfse(certificado, **kwargs): |
||||
|
if "xml" not in kwargs: |
||||
|
kwargs['xml'] = xml_gerar_nfse(certificado, **kwargs) |
||||
|
return _send(certificado, 'GerarNfse', **kwargs) |
||||
|
|
||||
|
|
||||
|
def xml_cancelar_nfse(certificado, **kwargs): |
||||
|
return _render(certificado, 'CancelarNfse', **kwargs) |
||||
|
|
||||
|
|
||||
|
def cancelar_nfse(certificado, **kwargs): |
||||
|
if "xml" not in kwargs: |
||||
|
kwargs['xml'] = xml_cancelar_nfse(certificado, **kwargs) |
||||
|
return _send(certificado, 'CancelarNfse', **kwargs) |
||||
@ -0,0 +1,44 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
# © 2016 Danimar Ribeiro, Trustcode |
||||
|
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). |
||||
|
|
||||
|
import signxml |
||||
|
from lxml import etree |
||||
|
from pytrustnfe.certificado import extract_cert_and_key_from_pfx |
||||
|
from signxml import XMLSigner |
||||
|
|
||||
|
|
||||
|
class Assinatura(object): |
||||
|
|
||||
|
def __init__(self, arquivo, senha): |
||||
|
self.arquivo = arquivo |
||||
|
self.senha = senha |
||||
|
|
||||
|
def assina_xml(self, xml_element, reference): |
||||
|
cert, key = extract_cert_and_key_from_pfx(self.arquivo, self.senha) |
||||
|
|
||||
|
for element in xml_element.iter("*"): |
||||
|
if element.text is not None and not element.text.strip(): |
||||
|
element.text = None |
||||
|
|
||||
|
signer = XMLSigner( |
||||
|
method=signxml.methods.enveloped, signature_algorithm="rsa-sha1", |
||||
|
digest_algorithm='sha1', |
||||
|
c14n_algorithm='http://www.w3.org/TR/2001/REC-xml-c14n-20010315') |
||||
|
|
||||
|
ns = {} |
||||
|
ns[None] = signer.namespaces['ds'] |
||||
|
signer.namespaces = ns |
||||
|
|
||||
|
ref_uri = ('#%s' % reference) if reference else None |
||||
|
signed_root = signer.sign( |
||||
|
xml_element, key=key.encode(), cert=cert.encode(), |
||||
|
reference_uri=ref_uri) |
||||
|
if reference: |
||||
|
element_signed = signed_root.find(".//*[@Id='%s']" % reference) |
||||
|
signature = signed_root.find(".//*[@URI='#%s']" % reference).getparent().getparent() |
||||
|
|
||||
|
if element_signed is not None and signature is not None: |
||||
|
parent = element_signed.getparent() |
||||
|
parent.append(signature) |
||||
|
return etree.tostring(signed_root, encoding=str) |
||||
@ -0,0 +1,13 @@ |
|||||
|
<CancelarNfseEnvio xmlns="http://www.abrasf.org.br/ABRASF/arquivos/nfse.xsd"> |
||||
|
<Pedido xmlns="http://www.abrasf.org.br/nfse.xsd"> |
||||
|
<InfPedidoCancelamento Id="pedidoCancelamento_{{ cancelamento.numero_nfse }}"> |
||||
|
<IdentificacaoNfse> |
||||
|
<Numero>{{ cancelamento.numero_nfse }}</Numero> |
||||
|
<Cnpj>{{ cancelamento.cnpj_prestador }}</Cnpj> |
||||
|
<InscricaoMunicipal>{{ cancelamento.inscricao_municipal }}</InscricaoMunicipal> |
||||
|
<CodigoMunicipio>{{ cancelamento.cidade }}</CodigoMunicipio> |
||||
|
</IdentificacaoNfse> |
||||
|
<CodigoCancelamento>1</CodigoCancelamento> |
||||
|
</InfPedidoCancelamento> |
||||
|
</Pedido> |
||||
|
</CancelarNfseEnvio> |
||||
@ -0,0 +1,11 @@ |
|||||
|
<GerarNfseEnvio xmlns="http://www.abrasf.org.br/nfse.xsd"> |
||||
|
<LoteRps Id="lote{{ rps.numero_lote }}" versao="1.00"> |
||||
|
<NumeroLote>{{ rps.numero_lote }}</NumeroLote> |
||||
|
<Cnpj>{{ rps.prestador.cnpj }}</Cnpj> |
||||
|
<InscricaoMunicipal>{{ rps.prestador.inscricao_municipal }}</InscricaoMunicipal> |
||||
|
<QuantidadeRps>1</QuantidadeRps> |
||||
|
<ListaRps xmlns="http://www.abrasf.org.br/nfse.xsd"> |
||||
|
{% include 'Rps.xml' %} |
||||
|
</ListaRps> |
||||
|
</LoteRps> |
||||
|
</GerarNfseEnvio> |
||||
@ -0,0 +1,91 @@ |
|||||
|
<Rps> |
||||
|
<InfRps xmlns="http://www.abrasf.org.br/nfse.xsd" Id="rps:{{ rps.numero }}"> |
||||
|
<IdentificacaoRps> |
||||
|
<Numero>{{ rps.numero }}</Numero> |
||||
|
<Serie>{{ rps.serie }}</Serie> |
||||
|
<Tipo>{{ rps.tipo_rps }}</Tipo> |
||||
|
</IdentificacaoRps> |
||||
|
<DataEmissao>{{ rps.data_emissao }}</DataEmissao> |
||||
|
<NaturezaOperacao>{{ rps.natureza_operacao }}</NaturezaOperacao> |
||||
|
<RegimeEspecialTributacao>{{ rps.regime_tributacao }}</RegimeEspecialTributacao> |
||||
|
<OptanteSimplesNacional>{{ rps.optante_simples }}</OptanteSimplesNacional> |
||||
|
<IncentivadorCultural>{{ rps.incentivador_cultural }}</IncentivadorCultural> |
||||
|
<Status>{{ rps.status }}</Status> |
||||
|
<RpsSubstituido> |
||||
|
<Numero>{{ rps.numero_substituido }}</Numero> |
||||
|
<Serie>{{ rps.serie_substituido }}</Serie> |
||||
|
<Tipo>{{ rps.tipo_substituido }}</Tipo> |
||||
|
</RpsSubstituido> |
||||
|
<Servico> |
||||
|
<Valores> |
||||
|
<ValorServicos>{{ rps.valor_servico }}</ValorServicos> |
||||
|
<ValorDeducoes>{{ rps.valor_deducao }}</ValorDeducoes> |
||||
|
<ValorPis>{{ rps.valor_pis }}</ValorPis> |
||||
|
<ValorCofins>{{ rps.valor_cofins }}</ValorCofins> |
||||
|
<ValorInss>{{ rps.valor_inss }}</ValorInss> |
||||
|
<ValorIr>{{ rps.valor_ir }}</ValorIr> |
||||
|
<ValorCsll>{{ rps.valor_csll }}</ValorCsll> |
||||
|
<IssRetido>{{ rps.iss_retido }}</IssRetido> |
||||
|
<ValorIss>{{ rps.valor_iss }}</ValorIss> |
||||
|
<ValorIssRetido>{{ rps.valor_iss_retido }}</ValorIssRetido> |
||||
|
<OutrasRetencoes>{{ rps.outras_retencoes }}</OutrasRetencoes> |
||||
|
<BaseCalculo>{{ rps.base_calculo }}</BaseCalculo> |
||||
|
<Aliquota>{{ rps.aliquota_issqn }}</Aliquota> |
||||
|
<ValorLiquidoNfse>{{ rps.valor_liquido_nfse }}</ValorLiquidoNfse> |
||||
|
<DescontoIncondicionado>{{ rps.desconto_incondicionado }}</DescontoIncondicionado> |
||||
|
<DescontoCondicionado>{{ rps.desconto_condicionado }}</DescontoCondicionado> |
||||
|
</Valores> |
||||
|
<ItemListaServico>{{ rps.codigo_servico }}</ItemListaServico> |
||||
|
<CodigoCnae>{{ rps.cnae_servico }}</CodigoCnae> |
||||
|
<CodigoTributacaoMunicipio>{{ rps.codigo_tributacao_municipio }}</CodigoTributacaoMunicipio> |
||||
|
<Discriminacao>{{ rps.descricao }}</Discriminacao> |
||||
|
<CodigoMunicipio>{{ rps.codigo_municipio }}</CodigoMunicipio> |
||||
|
</Servico> |
||||
|
<Prestador> |
||||
|
<Cnpj>{{ rps.prestador.cnpj }}</Cnpj> |
||||
|
<InscricaoMunicipal>{{ rps.prestador.inscricao_municipal }}</InscricaoMunicipal> |
||||
|
</Prestador> |
||||
|
<Tomador> |
||||
|
<IdentificacaoTomador> |
||||
|
<CpfCnpj> |
||||
|
{% if rps.tomador.cnpj_cpf|length == 14 %} |
||||
|
<Cnpj>{{ rps.tomador.cnpj_cpf }}</Cnpj> |
||||
|
{% endif %} |
||||
|
{% if rps.tomador.cnpj_cpf|length == 11 %} |
||||
|
<Cpf>{{ rps.tomador.cnpj_cpf }}</Cpf> |
||||
|
{% endif %} |
||||
|
</CpfCnpj> |
||||
|
<InscricaoMunicipal>{{ rps.tomador.inscricao_municipal }}</InscricaoMunicipal> |
||||
|
</IdentificacaoTomador> |
||||
|
<RazaoSocial>{{ rps.tomador.razao_social }}</RazaoSocial> |
||||
|
<Endereco> |
||||
|
<Endereco>{{ rps.tomador.logradouro }}</Endereco> |
||||
|
<Numero>{{ rps.tomador.numero }}</Numero> |
||||
|
<Complemento>{{ rps.tomador.complemento }}</Complemento> |
||||
|
<Bairro>{{ rps.tomador.bairro }}</Bairro> |
||||
|
<CodigoMunicipio>{{ rps.tomador.cidade }}</CodigoMunicipio> |
||||
|
<Uf>{{ rps.tomador.uf }}</Uf> |
||||
|
<Cep>{{ rps.tomador.cep }}</Cep> |
||||
|
</Endereco> |
||||
|
<Contato> |
||||
|
<Telefone>{{ rps.tomador.telefone }}</Telefone> |
||||
|
<Email>{{ rps.tomador.email }}</Email> |
||||
|
</Contato> |
||||
|
</Tomador> |
||||
|
{% if rps.intermediario is defined -%} |
||||
|
<IntermediarioServico> |
||||
|
<RazaoSocial>{{ rps.intermediario.razao_social }}</RazaoSocial> |
||||
|
<CpfCnpj> |
||||
|
<Cnpj>{{ rps.intermediario.cnpj }}</Cnpj> |
||||
|
</CpfCnpj> |
||||
|
<InscricaoMunicipal>{{ rps.intermediario.inscricao_municipal }}</InscricaoMunicipal> |
||||
|
</IntermediarioServico> |
||||
|
{% endif %} |
||||
|
{% if rps.construcao_civil is defined -%} |
||||
|
<ContrucaoCivil> |
||||
|
<CodigoObra>{{ rps.construcao_civil.codigo_obra }}</CodigoObra> |
||||
|
<Art>{{ rps.construcao_civil.art }}</Art> |
||||
|
</ContrucaoCivil> |
||||
|
{% endif %} |
||||
|
</InfRps> |
||||
|
</Rps> |
||||
@ -1 +0,0 @@ |
|||||
<?xml version="1.0" encoding="UTF-8"?><RetornoEnvioLoteRPS xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://www.prefeitura.sp.gov.br/nfe"><Cabecalho Versao="1" xmlns=""><Sucesso>true</Sucesso><InformacoesLote><NumeroLote>2654364</NumeroLote><InscricaoPrestador>51212</InscricaoPrestador><CPFCNPJRemetente><CNPJ>21332900163</CNPJ></CPFCNPJRemetente><DataEnvioLote>2016-08-29T10:52:15</DataEnvioLote><QtdNotasProcessadas>1</QtdNotasProcessadas><TempoProcessamento>0</TempoProcessamento><ValorTotalServicos>1.35</ValorTotalServicos></InformacoesLote></Cabecalho><ChaveNFeRPS xmlns=""><ChaveNFe><InscricaoPrestador>52382</InscricaoPrestador><NumeroNFe>446</NumeroNFe><CodigoVerificacao>APR9MJR</CodigoVerificacao></ChaveNFe><ChaveRPS><InscricaoPrestador>51282</InscricaoPrestador><SerieRPS>1</SerieRPS><NumeroRPS>6</NumeroRPS></ChaveRPS></ChaveNFeRPS></RetornoEnvioLoteRPS> |
|
||||
@ -1,16 +1,18 @@ |
|||||
lxml >= 3.5.0, < 4 |
|
||||
nose |
|
||||
mock |
|
||||
|
lxml >= 3.5.0, < 5 |
||||
coveralls |
coveralls |
||||
http://xmlsoft.org/sources/python/libxml2-python-2.6.21.tar.gz |
|
||||
https://github.com/odoo-brazil/pyxmlsec/archive/master.zip |
|
||||
Jinja2 |
Jinja2 |
||||
signxml |
signxml |
||||
suds >= 0.4 |
|
||||
suds_requests >= 0.3 |
|
||||
defusedxml >= 0.4.1, < 0.6 |
|
||||
eight >= 0.3.0, < 0.5 |
|
||||
cryptography >= 1.8, < 1.10 |
|
||||
pyOpenSSL >= 16.0.0, < 17 |
|
||||
|
urllib3 >= 1.22 |
||||
|
suds-jurko >= 0.6 |
||||
|
suds-jurko-requests >= 1.1 |
||||
|
defusedxml >= 0.4.1, < 1 |
||||
|
eight >= 0.3.0, < 1 |
||||
|
cryptography >= 1.8, < 3 |
||||
|
pyOpenSSL >= 16.0.0, < 18 |
||||
certifi >= 2015.11.20.1 |
certifi >= 2015.11.20.1 |
||||
|
xmlsec >= 1.3.3 |
||||
reportlab |
reportlab |
||||
|
pytest |
||||
|
pytest-cov |
||||
|
pytz |
||||
|
zeep |
||||
@ -1,4 +1,3 @@ |
|||||
<?xml version="1.0" encoding="UTF-8"?> |
|
||||
<RetornoCancelamentoNFe |
<RetornoCancelamentoNFe |
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |
||||
xmlns:xsd="http://www.w3.org/2001/XMLSchema" |
xmlns:xsd="http://www.w3.org/2001/XMLSchema" |
||||
@ -1,4 +1,3 @@ |
|||||
<?xml version="1.0" encoding="UTF-8"?> |
|
||||
<RetornoCancelamentoNFe |
<RetornoCancelamentoNFe |
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |
||||
xmlns:xsd="http://www.w3.org/2001/XMLSchema" |
xmlns:xsd="http://www.w3.org/2001/XMLSchema" |
||||
@ -0,0 +1 @@ |
|||||
|
<RetornoEnvioLoteRPS xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://www.prefeitura.sp.gov.br/nfe"><Cabecalho Versao="1" xmlns=""><Sucesso>true</Sucesso><InformacoesLote><NumeroLote>2654364</NumeroLote><InscricaoPrestador>51212</InscricaoPrestador><CPFCNPJRemetente><CNPJ>21332900163</CNPJ></CPFCNPJRemetente><DataEnvioLote>2016-08-29T10:52:15</DataEnvioLote><QtdNotasProcessadas>1</QtdNotasProcessadas><TempoProcessamento>0</TempoProcessamento><ValorTotalServicos>1.35</ValorTotalServicos></InformacoesLote></Cabecalho><ChaveNFeRPS xmlns=""><ChaveNFe><InscricaoPrestador>52382</InscricaoPrestador><NumeroNFe>446</NumeroNFe><CodigoVerificacao>APR9MJR</CodigoVerificacao></ChaveNFe><ChaveRPS><InscricaoPrestador>51282</InscricaoPrestador><SerieRPS>1</SerieRPS><NumeroRPS>6</NumeroRPS></ChaveRPS></ChaveNFeRPS></RetornoEnvioLoteRPS> |
||||
Write
Preview
Loading…
Cancel
Save
Reference in new issue