pyNFSeSP 0.2.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
pynfsesp-0.2.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2022 Bruno Souza
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,21 @@
1
+ Metadata-Version: 2.3
2
+ Name: pyNFSeSP
3
+ Version: 0.2.0
4
+ Summary: Módulo para emissão de Notas Fiscais de Serviço para a Prefeitura de SP
5
+ License: MIT
6
+ Author: Bruno Souza
7
+ Author-email: bruno@komu.com.br
8
+ Requires-Python: >=3.8,<4.0
9
+ Classifier: License :: OSI Approved :: MIT License
10
+ Classifier: Programming Language :: Python :: 3
11
+ Classifier: Programming Language :: Python :: 3.8
12
+ Classifier: Programming Language :: Python :: 3.9
13
+ Classifier: Programming Language :: Python :: 3.10
14
+ Classifier: Programming Language :: Python :: 3.11
15
+ Classifier: Programming Language :: Python :: 3.12
16
+ Classifier: Programming Language :: Python :: 3.13
17
+ Requires-Dist: lxml (>=6.1.0,<7)
18
+ Requires-Dist: pycrypto (>=2.6.1,<3.0.0)
19
+ Requires-Dist: requests (>=2.27.1,<3.0.0)
20
+ Requires-Dist: rsa (>=4.8,<5.0)
21
+ Requires-Dist: urllib3 (>=1.26.8,<2.0.0)
File without changes
File without changes
@@ -0,0 +1,104 @@
1
+ from ..utils.rps import Rps
2
+ from ..utils.response import Response
3
+ from ..utils.schemas import schemaCreateRps, schemaCancelRps, schemaConsultNfes
4
+ from ..utils.compatibility import stringEncode, stringDecode
5
+ from requests import post
6
+
7
+
8
+ class SaopauloGateway:
9
+
10
+ @classmethod
11
+ def sendRps(cls, privateKey, certificate, **kwargs):
12
+ xml = Rps.xmlCreateRps(
13
+ xml=schemaCreateRps,
14
+ privateKeyContent=privateKey,
15
+ certificateContent=certificate,
16
+ **kwargs
17
+ )
18
+
19
+ return cls.sendRequest(
20
+ xml=xml,
21
+ privateKey=privateKey,
22
+ certificate=certificate,
23
+ method="rps",
24
+ )
25
+
26
+ @classmethod
27
+ def cancelRps(cls, privateKey, certificate, **kwargs):
28
+ xml = Rps.cancelRps(
29
+ xml=schemaCancelRps,
30
+ privateKeyContent=privateKey,
31
+ certificateContent=certificate,
32
+ **kwargs
33
+ )
34
+
35
+ return cls.sendRequest(
36
+ xml=xml,
37
+ privateKey=privateKey,
38
+ certificate=certificate,
39
+ method="rps",
40
+ )
41
+
42
+ @classmethod
43
+ def consultNfes(cls, privateKey, certificate, **kwargs):
44
+ xml = Rps.consultNfes(
45
+ xml=schemaConsultNfes,
46
+ privateKeyContent=privateKey,
47
+ certificateContent=certificate,
48
+ **kwargs
49
+ )
50
+
51
+ return cls.sendRequest(
52
+ xml=xml,
53
+ privateKey=privateKey,
54
+ certificate=certificate,
55
+ method="consult",
56
+ )
57
+
58
+ @classmethod
59
+ def clearedResponse(cls, response):
60
+ xmlResponse = response.replace("&lt;", "<")
61
+ xmlResponse = xmlResponse.replace("&gt;", ">")
62
+ return xmlResponse
63
+
64
+ @classmethod
65
+ def sendRequest(cls, privateKey, certificate, xml, method):
66
+ certPath = "/tmp/cert.crt"
67
+ keyPath = "/tmp/rsaKey.pem"
68
+
69
+ headers = {
70
+ "Content-Type": "application/soap+xml; charset=utf-8;",
71
+ "Accept": "application/soap+xml; charset=utf-8;",
72
+ "Cache-Control": "no-cache",
73
+ "Host": "nfe.prefeitura.sp.gov.br",
74
+ "Accept-Encoding": "gzip, deflate",
75
+ "Connection": "keep-alive",
76
+ }
77
+
78
+ with open(certPath, "w") as tempCert:
79
+ tempCert.write(certificate)
80
+ tempCert.close()
81
+
82
+ with open(keyPath, "w") as tempKey:
83
+ tempKey.write(privateKey)
84
+ tempKey.close()
85
+
86
+ response = post(
87
+ url="https://nfe.prefeitura.sp.gov.br/ws/lotenfe.asmx",
88
+ data=stringEncode(xml),
89
+ headers=headers,
90
+ cert=(certPath, keyPath),
91
+ verify=True
92
+ )
93
+
94
+ status = response.status_code
95
+ content = stringDecode(response.content)
96
+
97
+ if status != 200:
98
+ return {}, status
99
+
100
+ if method == "consult":
101
+ return Response.getTail(cls.clearedResponse(content)), status
102
+
103
+ if method == "rps":
104
+ return Response.resultDict(cls.clearedResponse(content)), status
File without changes
@@ -0,0 +1,10 @@
1
+
2
+
3
+ class Certificate:
4
+
5
+ @classmethod
6
+ def getContent(cls, text):
7
+ certBuffer = text.replace("\n", "")
8
+ certData = certBuffer.split("-----BEGIN CERTIFICATE-----")
9
+ certBuffer = str((certData[1].replace("-----END CERTIFICATE-----", "")))
10
+ return certBuffer
@@ -0,0 +1,31 @@
1
+ from sys import version_info as version
2
+ from lxml import etree
3
+
4
+
5
+ if version.major == 3:
6
+
7
+ def xmlFromString(string):
8
+ return etree.fromstring(string.encode("utf-8"))
9
+
10
+ def getXmlText(element):
11
+ return element.text
12
+
13
+ def stringDecode(string):
14
+ return string.decode("utf-8")
15
+
16
+ def stringEncode(string):
17
+ return string.encode("utf-8")
18
+
19
+ if version.major == 2:
20
+
21
+ def xmlFromString(string):
22
+ return etree.fromstring(string)
23
+
24
+ def getXmlText(element):
25
+ return element.text.encode("utf-8") if element.text else None
26
+
27
+ def stringDecode(string):
28
+ return string
29
+
30
+ def stringEncode(string):
31
+ return string
@@ -0,0 +1,10 @@
1
+
2
+
3
+ class Currency:
4
+
5
+ @classmethod
6
+ def formatted(cls, amount):
7
+ replaceRule = lambda char: {",": ".", ".": ","}.get(char) or char
8
+ converter = lambda amount: "".join(replaceRule(char) for char in '{:0.2f}'.format(float(amount)/100))
9
+ res = converter(amount).replace(",", ".")
10
+ return str(res)
@@ -0,0 +1,40 @@
1
+ from lxml import etree
2
+ from re import search
3
+ from .compatibility import xmlFromString, getXmlText
4
+
5
+
6
+ class Response:
7
+
8
+ @classmethod
9
+ def resultDict(cls, strResult):
10
+ responseGroup = search("\<RetornoXML>(.*)\</Retorno", strResult).group(1)
11
+ res = {}
12
+ root = xmlFromString(responseGroup)
13
+ for element in root.iter():
14
+ text = getXmlText(element)
15
+ if text:
16
+ res.setdefault("{tag}".format(tag=element.tag), "{text}".format(text=str(text)))
17
+ return res
18
+
19
+ @classmethod
20
+ def getTail(cls, strResult):
21
+ responseGroup = search("\<RetornoXML>(.*)\</Retorno", strResult).group(1)
22
+ responseGroup = search("\</Cabecalho>(.*)\</Retorno", responseGroup).group(1)
23
+ try:
24
+ root = "<root>" + responseGroup + "</root>"
25
+ tree = etree.fromstring(root)
26
+ nfeData = []
27
+ res = {}
28
+ for i in tree:
29
+ res.update({
30
+ "SerieRPS": i.find('.//SerieRPS', namespaces={}).text,
31
+ "NumeroRPS": i.find('.//NumeroRPS', namespaces={}).text,
32
+ "DataEmissaoNFe": i.find('.//DataEmissaoNFe', namespaces={}).text,
33
+ "CPFCNPJTomador": i.find('.//CPFCNPJTomador', namespaces={})[0].text,
34
+ "CodigoVerificacao": i.find('.//CodigoVerificacao', namespaces={}).text,
35
+ "NumeroNFe": i.find('.//NumeroNFe', namespaces={}).text
36
+ })
37
+ nfeData.append(res.copy())
38
+ return nfeData
39
+ except Exception as error:
40
+ return error
@@ -0,0 +1,150 @@
1
+ from re import search, sub
2
+ from .rsa import Rsa
3
+ from .currency import Currency
4
+ from .certificate import Certificate
5
+ from ..utils.compatibility import stringDecode
6
+
7
+
8
+ class Rps:
9
+
10
+ @classmethod
11
+ def xmlCreateRps(cls, xml, InscricaoPrestador, SerieRPS, NumeroRPS, TipoRPS, DataEmissao, StatusRPS, ValorServicos,
12
+ ValorDeducoes, CodigoServico, ISSRetido, CPFCNPJTomador, CPFCNPJRemetente, TributacaoRPS, ValorPIS,
13
+ ValorCOFINS, ValorINSS, ValorIR, ValorCSLL, AliquotaServicos, RazaoSocialTomador, Logradouro,
14
+ NumeroEndereco, ComplementoEndereco, Bairro, Cidade, UF, CEP, EmailTomador, Discriminacao,
15
+ privateKeyContent, certificateContent):
16
+
17
+ CPFCNPJTomadorTag = "CPF"
18
+ if len(CPFCNPJTomador) > 11:
19
+ CPFCNPJTomadorTag = "CNPJ"
20
+
21
+ rpsToSign = "{InscricaoPrestador}{SerieRPS}{NumeroRPS}{DataEmissao}{TributacaoRPS}{StatusRPS}" \
22
+ "{ISSRetido}{ValorServicos}{ValorDeducoes}{CodigoServico}{CPFCNPJ}{RazaoSocialTomador}".format(
23
+ InscricaoPrestador=InscricaoPrestador.zfill(8),
24
+ SerieRPS=SerieRPS.ljust(5).upper(),
25
+ NumeroRPS=NumeroRPS.zfill(12),
26
+ DataEmissao=DataEmissao.replace("-", ""),
27
+ TributacaoRPS=TributacaoRPS.upper(),
28
+ StatusRPS=StatusRPS,
29
+ ISSRetido={"false": "N", "true": "S"}.get(ISSRetido),
30
+ ValorServicos=str(ValorServicos).zfill(15),
31
+ ValorDeducoes=str(ValorDeducoes).zfill(15),
32
+ CodigoServico=CodigoServico.zfill(5),
33
+ CPFCNPJ=("1" if CPFCNPJTomadorTag == "CPF" else "2"),
34
+ RazaoSocialTomador=CPFCNPJTomador.zfill(14),
35
+ )
36
+
37
+ rpsSignature = Rsa.sign(text=rpsToSign, privateKeyContent=privateKeyContent)
38
+
39
+ parameters = {
40
+ "CPFCNPJRemetente": CPFCNPJRemetente,
41
+ "Assinatura": stringDecode(rpsSignature),
42
+ "InscricaoPrestador": InscricaoPrestador,
43
+ "SerieRPS": SerieRPS,
44
+ "NumeroRPS": NumeroRPS,
45
+ "TipoRPS": TipoRPS,
46
+ "DataEmissao": DataEmissao,
47
+ "StatusRPS": StatusRPS,
48
+ "TributacaoRPS": TributacaoRPS,
49
+ "ValorServicos": Currency.formatted(ValorServicos),
50
+ "ValorDeducoes": Currency.formatted(ValorDeducoes),
51
+ "ValorPIS": Currency.formatted(ValorPIS),
52
+ "ValorCOFINS": Currency.formatted(ValorCOFINS),
53
+ "ValorINSS": Currency.formatted(ValorINSS),
54
+ "ValorIR": Currency.formatted(ValorIR),
55
+ "ValorCSLL": Currency.formatted(ValorCSLL),
56
+ "CodigoServico": CodigoServico,
57
+ "AliquotaServicos": Currency.formatted(AliquotaServicos),
58
+ "ISSRetido": ISSRetido,
59
+ "CPFCNPJTomador": CPFCNPJTomador,
60
+ "CPFCNPJTomadorTag": CPFCNPJTomadorTag,
61
+ "RazaoSocialTomador": RazaoSocialTomador,
62
+ "Logradouro": Logradouro,
63
+ "NumeroEndereco": NumeroEndereco,
64
+ "ComplementoEndereco": ComplementoEndereco,
65
+ "Bairro": Bairro,
66
+ "Cidade": Cidade,
67
+ "UF": UF,
68
+ "CEP": CEP,
69
+ "EmailTomador": EmailTomador,
70
+ "Discriminacao": Discriminacao,
71
+ }
72
+
73
+ xml = cls.signXml(
74
+ xml=xml,
75
+ privateKeyContent=privateKeyContent,
76
+ certificateContent=certificateContent,
77
+ **parameters
78
+ )
79
+
80
+ return xml
81
+
82
+ @classmethod
83
+ def cancelRps(cls, xml, CPFCNPJRemetente, InscricaoPrestador, NumeroNFe, certificateContent, privateKeyContent):
84
+ cancelToSign = "{InscricaoPrestador}{NumeroNFe}".format(
85
+ InscricaoPrestador=InscricaoPrestador.zfill(8),
86
+ NumeroNFe=NumeroNFe.zfill(12)
87
+ )
88
+
89
+ cancelSignature = Rsa.sign(text=cancelToSign, privateKeyContent=privateKeyContent)
90
+
91
+ parameters = {
92
+ "CPFCNPJRemetente": CPFCNPJRemetente,
93
+ "InscricaoPrestador": InscricaoPrestador,
94
+ "NumeroNFe": NumeroNFe,
95
+ "AssinaturaCancelamento": stringDecode(cancelSignature),
96
+ }
97
+
98
+ xml = cls.signXml(
99
+ xml=xml,
100
+ privateKeyContent=privateKeyContent,
101
+ certificateContent=certificateContent,
102
+ **parameters
103
+ )
104
+
105
+ return xml
106
+
107
+ @classmethod
108
+ def consultNfes(cls, xml, CPFCNPJRemetente, Inscricao, dtInicio, dtFim, certificateContent, privateKeyContent):
109
+ parameters = {
110
+ "CPFCNPJRemetente": CPFCNPJRemetente,
111
+ "Inscricao": Inscricao,
112
+ "dtInicio": dtInicio,
113
+ "dtFim": dtFim,
114
+ }
115
+
116
+ xml = cls.signXml(
117
+ xml=xml,
118
+ privateKeyContent=privateKeyContent,
119
+ certificateContent=certificateContent,
120
+ **parameters
121
+ )
122
+
123
+ return xml
124
+
125
+ @classmethod
126
+ def signXml(cls, xml, privateKeyContent, certificateContent, **kwargs):
127
+ xmlWithoutBreakLine = sub("\n*", "", xml)
128
+ xmlWithoutSpaces = sub("\s{2,}", "", xmlWithoutBreakLine)
129
+
130
+ p1WithSignature = search("<!\[CDATA\[(.*)\]\]>", xmlWithoutSpaces).group(1)
131
+ p1WithoutSignature = sub("<Signature .*</Signature>", "", p1WithSignature)
132
+
133
+ p1 = p1WithoutSignature.format(**kwargs)
134
+
135
+ digestValue = stringDecode(Rsa.digest(p1))
136
+
137
+ namespace = search("<[^> ]+ ?([^>]*)>", p1WithoutSignature).group(1)
138
+ signInfo = search("(<SignedInfo>.*</SignedInfo>)", xmlWithoutSpaces).group(1)
139
+ signInfoWithNamespace = sub("<SignedInfo>", "<SignedInfo xmlns=\"http://www.w3.org/2000/09/xmldsig#\" {namespace}>".format(namespace=namespace), signInfo)
140
+ message = signInfoWithNamespace.format(DigestValue=digestValue)
141
+ signatureValue = stringDecode(Rsa.sign(text=message, privateKeyContent=privateKeyContent))
142
+
143
+ sigendXml = xmlWithoutSpaces.format(
144
+ DigestValue=digestValue,
145
+ SignatureValue=signatureValue,
146
+ X509Certificate=Certificate.getContent(certificateContent),
147
+ **kwargs
148
+ )
149
+
150
+ return sigendXml
@@ -0,0 +1,24 @@
1
+ from base64 import b64encode
2
+ from hashlib import sha1
3
+ from Crypto.Hash import SHA
4
+ from Crypto.Signature import PKCS1_v1_5
5
+ from Crypto.PublicKey import RSA
6
+ from ..utils.compatibility import stringEncode
7
+
8
+
9
+ class Rsa:
10
+
11
+ @classmethod
12
+ def sign(cls, text, privateKeyContent):
13
+ digest = SHA.new(stringEncode(text))
14
+ rsaKey = RSA.importKey(privateKeyContent)
15
+ signer = PKCS1_v1_5.new(rsaKey)
16
+ signature = signer.sign(digest)
17
+ return b64encode(signature)
18
+
19
+ @classmethod
20
+ def digest(cls, text):
21
+ hasher = sha1()
22
+ hasher.update(stringEncode(text))
23
+ digest = hasher.digest()
24
+ return b64encode(digest)
@@ -0,0 +1,178 @@
1
+ schemaCreateRps = """
2
+ <?xml version="1.0" encoding="utf-8"?>
3
+ <soap12:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap12="http://www.w3.org/2003/05/soap-envelope">
4
+ <soap12:Body>
5
+ <EnvioRPSRequest xmlns="http://www.prefeitura.sp.gov.br/nfe">
6
+ <VersaoSchema>1</VersaoSchema>
7
+ <MensagemXML>
8
+ <![CDATA[
9
+ <p1:PedidoEnvioRPS xmlns:p1="http://www.prefeitura.sp.gov.br/nfe" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
10
+ <Cabecalho Versao="1">
11
+ <CPFCNPJRemetente>
12
+ <CNPJ>{CPFCNPJRemetente}</CNPJ>
13
+ </CPFCNPJRemetente>
14
+ </Cabecalho>
15
+ <RPS>
16
+ <Assinatura>{Assinatura}</Assinatura>
17
+ <ChaveRPS>
18
+ <InscricaoPrestador>{InscricaoPrestador}</InscricaoPrestador>
19
+ <SerieRPS>{SerieRPS}</SerieRPS>
20
+ <NumeroRPS>{NumeroRPS}</NumeroRPS>
21
+ </ChaveRPS>
22
+ <TipoRPS>{TipoRPS}</TipoRPS>
23
+ <DataEmissao>{DataEmissao}</DataEmissao>
24
+ <StatusRPS>{StatusRPS}</StatusRPS>
25
+ <TributacaoRPS>{TributacaoRPS}</TributacaoRPS>
26
+ <ValorServicos>{ValorServicos}</ValorServicos>
27
+ <ValorDeducoes>{ValorDeducoes}</ValorDeducoes>
28
+ <ValorPIS>{ValorPIS}</ValorPIS>
29
+ <ValorCOFINS>{ValorCOFINS}</ValorCOFINS>
30
+ <ValorINSS>{ValorINSS}</ValorINSS>
31
+ <ValorIR>{ValorIR}</ValorIR>
32
+ <ValorCSLL>{ValorCSLL}</ValorCSLL>
33
+ <CodigoServico>{CodigoServico}</CodigoServico>
34
+ <AliquotaServicos>{AliquotaServicos}</AliquotaServicos>
35
+ <ISSRetido>{ISSRetido}</ISSRetido>
36
+ <CPFCNPJTomador>
37
+ <{CPFCNPJTomadorTag}>{CPFCNPJTomador}</{CPFCNPJTomadorTag}>
38
+ </CPFCNPJTomador>
39
+ <RazaoSocialTomador>{RazaoSocialTomador}</RazaoSocialTomador>
40
+ <EnderecoTomador>
41
+ <Logradouro>{Logradouro}</Logradouro>
42
+ <NumeroEndereco>{NumeroEndereco}</NumeroEndereco>
43
+ <ComplementoEndereco>{ComplementoEndereco}</ComplementoEndereco>
44
+ <Bairro>{Bairro}</Bairro>
45
+ <Cidade>{Cidade}</Cidade>
46
+ <UF>{UF}</UF>
47
+ <CEP>{CEP}</CEP>
48
+ </EnderecoTomador>
49
+ <EmailTomador>{EmailTomador}</EmailTomador>
50
+ <Discriminacao>{Discriminacao}</Discriminacao>
51
+ </RPS>
52
+ <Signature xmlns="http://www.w3.org/2000/09/xmldsig#">
53
+ <SignedInfo>
54
+ <CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315"></CanonicalizationMethod>
55
+ <SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"></SignatureMethod>
56
+ <Reference URI="">
57
+ <Transforms>
58
+ <Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"></Transform>
59
+ <Transform Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315"></Transform>
60
+ </Transforms>
61
+ <DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"></DigestMethod>
62
+ <DigestValue>{DigestValue}</DigestValue>
63
+ </Reference>
64
+ </SignedInfo>
65
+ <SignatureValue>{SignatureValue}</SignatureValue>
66
+ <KeyInfo>
67
+ <X509Data>
68
+ <X509Certificate>{X509Certificate}</X509Certificate>
69
+ </X509Data>
70
+ </KeyInfo>
71
+ </Signature>
72
+ </p1:PedidoEnvioRPS>
73
+ ]]>
74
+ </MensagemXML>
75
+ </EnvioRPSRequest>
76
+ </soap12:Body>
77
+ </soap12:Envelope>
78
+ """
79
+
80
+
81
+ schemaCancelRps = """
82
+ <?xml version="1.0" encoding="utf-8"?>
83
+ <soap12:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap12="http://www.w3.org/2003/05/soap-envelope">
84
+ <soap12:Body>
85
+ <CancelamentoNFeRequest xmlns="http://www.prefeitura.sp.gov.br/nfe">
86
+ <VersaoSchema>1</VersaoSchema>
87
+ <MensagemXML>
88
+ <![CDATA[
89
+ <p1:PedidoCancelamentoNFe xmlns:p1="http://www.prefeitura.sp.gov.br/nfe" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
90
+ <Cabecalho Versao="1">
91
+ <CPFCNPJRemetente>
92
+ <CNPJ>{CPFCNPJRemetente}</CNPJ>
93
+ </CPFCNPJRemetente>
94
+ <transacao>true</transacao>
95
+ </Cabecalho>
96
+ <Detalhe>
97
+ <ChaveNFe>
98
+ <InscricaoPrestador>{InscricaoPrestador}</InscricaoPrestador>
99
+ <NumeroNFe>{NumeroNFe}</NumeroNFe>
100
+ </ChaveNFe>
101
+ <AssinaturaCancelamento>{AssinaturaCancelamento}</AssinaturaCancelamento>
102
+ </Detalhe>
103
+ <Signature xmlns="http://www.w3.org/2000/09/xmldsig#">
104
+ <SignedInfo>
105
+ <CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315"></CanonicalizationMethod>
106
+ <SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"></SignatureMethod>
107
+ <Reference URI="">
108
+ <Transforms>
109
+ <Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"></Transform>
110
+ <Transform Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315"></Transform>
111
+ </Transforms>
112
+ <DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"></DigestMethod>
113
+ <DigestValue>{DigestValue}</DigestValue>
114
+ </Reference>
115
+ </SignedInfo>
116
+ <SignatureValue>{SignatureValue}</SignatureValue>
117
+ <KeyInfo>
118
+ <X509Data>
119
+ <X509Certificate>{X509Certificate}</X509Certificate>
120
+ </X509Data>
121
+ </KeyInfo>
122
+ </Signature>
123
+ </p1:PedidoCancelamentoNFe>
124
+ ]]>
125
+ </MensagemXML>
126
+ </CancelamentoNFeRequest>
127
+ </soap12:Body>
128
+ </soap12:Envelope>
129
+ """
130
+
131
+ schemaConsultNfes = """
132
+ <?xml version="1.0" encoding="utf-8"?>
133
+ <soap12:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap12="http://www.w3.org/2003/05/soap-envelope">
134
+ <soap12:Body>
135
+ <ConsultaNFeEmitidasRequest xmlns="http://www.prefeitura.sp.gov.br/nfe">
136
+ <VersaoSchema>1</VersaoSchema>
137
+ <MensagemXML>
138
+ <![CDATA[
139
+ <p1:PedidoConsultaNFePeriodo xmlns:p1="http://www.prefeitura.sp.gov.br/nfe" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
140
+ <Cabecalho Versao="1">
141
+ <CPFCNPJRemetente>
142
+ <CNPJ>{CPFCNPJRemetente}</CNPJ>
143
+ </CPFCNPJRemetente>
144
+ <CPFCNPJ>
145
+ <CNPJ>{CPFCNPJRemetente}</CNPJ>
146
+ </CPFCNPJ>
147
+ <Inscricao>{Inscricao}</Inscricao>
148
+ <dtInicio>{dtInicio}</dtInicio>
149
+ <dtFim>{dtFim}</dtFim>
150
+ <NumeroPagina>1</NumeroPagina>
151
+ </Cabecalho>
152
+ <Signature xmlns="http://www.w3.org/2000/09/xmldsig#">
153
+ <SignedInfo>
154
+ <CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315"></CanonicalizationMethod>
155
+ <SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"></SignatureMethod>
156
+ <Reference URI="">
157
+ <Transforms>
158
+ <Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"></Transform>
159
+ <Transform Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315"></Transform>
160
+ </Transforms>
161
+ <DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"></DigestMethod>
162
+ <DigestValue>{DigestValue}</DigestValue>
163
+ </Reference>
164
+ </SignedInfo>
165
+ <SignatureValue>{SignatureValue}</SignatureValue>
166
+ <KeyInfo>
167
+ <X509Data>
168
+ <X509Certificate>{X509Certificate}</X509Certificate>
169
+ </X509Data>
170
+ </KeyInfo>
171
+ </Signature>
172
+ </p1:PedidoConsultaNFePeriodo>
173
+ ]]>
174
+ </MensagemXML>
175
+ </ConsultaNFeEmitidasRequest>
176
+ </soap12:Body>
177
+ </soap12:Envelope>
178
+ """
@@ -0,0 +1,25 @@
1
+ [tool.poetry]
2
+ name = "pyNFSeSP"
3
+ version = "0.2.0"
4
+ description = "Módulo para emissão de Notas Fiscais de Serviço para a Prefeitura de SP"
5
+ authors = ["Bruno Souza <bruno@komu.com.br>"]
6
+ license = "MIT License"
7
+
8
+ [tool.poetry.dependencies]
9
+ python = "^3.8"
10
+ lxml = ">=6.1.0,<7"
11
+ pycrypto = "^2.6.1"
12
+ requests = "^2.27.1"
13
+ rsa = "^4.8"
14
+ urllib3 = "^1.26.8"
15
+
16
+ [tool.poetry.dev-dependencies]
17
+ autoflake = "^1.4"
18
+ black = {version = "^21.11b1", allow-prereleases = true}
19
+ isort = "^5.10.1"
20
+ mypy = "^0.910"
21
+ pylint = "^2.11.1"
22
+
23
+ [build-system]
24
+ requires = ["poetry-core>=1.0.0"]
25
+ build-backend = "poetry.core.masonry.api"