stackin-python-sdk 0.3.0__tar.gz → 0.4.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.
- {stackin_python_sdk-0.3.0 → stackin_python_sdk-0.4.0}/PKG-INFO +36 -2
- {stackin_python_sdk-0.3.0 → stackin_python_sdk-0.4.0}/README.md +35 -1
- {stackin_python_sdk-0.3.0 → stackin_python_sdk-0.4.0}/pyproject.toml +2 -2
- {stackin_python_sdk-0.3.0 → stackin_python_sdk-0.4.0}/stackin/__init__.py +3 -2
- {stackin_python_sdk-0.3.0 → stackin_python_sdk-0.4.0}/stackin/br/__init__.py +38 -0
- {stackin_python_sdk-0.3.0 → stackin_python_sdk-0.4.0}/stackin/br/product.py +4 -1
- stackin_python_sdk-0.4.0/stackin/br/tax.py +1866 -0
- {stackin_python_sdk-0.3.0 → stackin_python_sdk-0.4.0}/stackin/core/client.py +58 -3
- {stackin_python_sdk-0.3.0 → stackin_python_sdk-0.4.0}/stackin/core/exceptions.py +1 -1
- {stackin_python_sdk-0.3.0 → stackin_python_sdk-0.4.0}/stackin/core/types.py +10 -1
- stackin_python_sdk-0.3.0/stackin/br/tax.py +0 -277
- {stackin_python_sdk-0.3.0 → stackin_python_sdk-0.4.0}/LICENSE +0 -0
- {stackin_python_sdk-0.3.0 → stackin_python_sdk-0.4.0}/stackin/core/__init__.py +0 -0
- {stackin_python_sdk-0.3.0 → stackin_python_sdk-0.4.0}/stackin/core/address.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: stackin-python-sdk
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.4.0
|
|
4
4
|
Summary: Python SDK for issuing, consulting and cancelling electronic invoices.
|
|
5
5
|
License-Expression: MIT
|
|
6
6
|
License-File: LICENSE
|
|
@@ -47,7 +47,7 @@ Description-Content-Type: text/markdown
|
|
|
47
47
|
|
|
48
48
|
Python SDK for fiscal document issuance — a handful of business fields, nothing about certificates, XML, XSD, signing or SOAP. The API resolves all of that from the issuer's own configuration, identified by `api_key`.
|
|
49
49
|
|
|
50
|
-
**One class, `Invoice`** — `issue()`/`consult()`/`cancel()`/`reissue()`/`correct()`/`invalidate()`/`pdf()`, nothing else to instantiate. Each line item is a `Product` (`stackin.br`) — `description`/`amount` are universal, everything else (`ncm`/`cfop`/`cest`/tax groups...) is Brazil-specific and only required for NFE; NFSE ignores it.
|
|
50
|
+
**One class, `Invoice`** — `issue()`/`consult()`/`cancel()`/`reissue()`/`correct()`/`invalidate()`/`pdf()`/`received()`/`manifest()`, nothing else to instantiate. Each line item is a `Product` (`stackin.br`) — `description`/`amount` are universal, everything else (`ncm`/`cfop`/`cest`/tax groups...) is Brazil-specific and only required for NFE; NFSE ignores it.
|
|
51
51
|
|
|
52
52
|
## Install
|
|
53
53
|
|
|
@@ -200,6 +200,40 @@ round trip — and the authorizer checks again for what we can't see from here.
|
|
|
200
200
|
|
|
201
201
|
**NF-e only**, and it takes no access key: there is no document to point at.
|
|
202
202
|
|
|
203
|
+
## Documents issued against you
|
|
204
|
+
|
|
205
|
+
Everything above serves the **issuer**. These two serve the **recipient**: what
|
|
206
|
+
suppliers billed to this CNPJ, and the formal answer to it.
|
|
207
|
+
|
|
208
|
+
Reading the list never calls the SEFAZ. The authorizer caps how many times a CNPJ
|
|
209
|
+
may ask for its distribution per day, so collecting runs on a schedule on the API
|
|
210
|
+
side and a page refresh cannot spend that allowance.
|
|
211
|
+
|
|
212
|
+
```python
|
|
213
|
+
from stackin import Manifestation
|
|
214
|
+
|
|
215
|
+
page = client.received(limit=20)
|
|
216
|
+
for document in page["data"]:
|
|
217
|
+
print(document["access_key"], document["issuer_name"], document["amount"])
|
|
218
|
+
|
|
219
|
+
client.manifest(access_key, manifestation=Manifestation.CIENCIA)
|
|
220
|
+
client.manifest(
|
|
221
|
+
access_key,
|
|
222
|
+
manifestation=Manifestation.OPERACAO_NAO_REALIZADA,
|
|
223
|
+
reason="Mercadoria nunca chegou ao endereco",
|
|
224
|
+
)
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
Before you answer a document the SEFAZ sends only a **summary** (`resNFe`): access
|
|
228
|
+
key, issuer, amount, date. The **full document** (`nfeProc`) arrives after a
|
|
229
|
+
manifestation, and the `schema` field on each row says which one you hold.
|
|
230
|
+
|
|
231
|
+
The four answers are `210200` Confirmação da Operação, `210210` Ciência da
|
|
232
|
+
Operação, `210220` Desconhecimento da Operação and `210240` Operação não
|
|
233
|
+
Realizada. Only the last one takes a reason, and it requires one — both rules are
|
|
234
|
+
checked locally, before the request goes out, because a round trip to be told a
|
|
235
|
+
fixed rule is a round trip wasted.
|
|
236
|
+
|
|
203
237
|
## Errors
|
|
204
238
|
|
|
205
239
|
- `stackin.APIError` — the API responded with a non-2xx status (`status_code`, `detail`) — a 401 here means `api_key` is missing, wrong, or was rotated.
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
|
|
19
19
|
Python SDK for fiscal document issuance — a handful of business fields, nothing about certificates, XML, XSD, signing or SOAP. The API resolves all of that from the issuer's own configuration, identified by `api_key`.
|
|
20
20
|
|
|
21
|
-
**One class, `Invoice`** — `issue()`/`consult()`/`cancel()`/`reissue()`/`correct()`/`invalidate()`/`pdf()`, nothing else to instantiate. Each line item is a `Product` (`stackin.br`) — `description`/`amount` are universal, everything else (`ncm`/`cfop`/`cest`/tax groups...) is Brazil-specific and only required for NFE; NFSE ignores it.
|
|
21
|
+
**One class, `Invoice`** — `issue()`/`consult()`/`cancel()`/`reissue()`/`correct()`/`invalidate()`/`pdf()`/`received()`/`manifest()`, nothing else to instantiate. Each line item is a `Product` (`stackin.br`) — `description`/`amount` are universal, everything else (`ncm`/`cfop`/`cest`/tax groups...) is Brazil-specific and only required for NFE; NFSE ignores it.
|
|
22
22
|
|
|
23
23
|
## Install
|
|
24
24
|
|
|
@@ -171,6 +171,40 @@ round trip — and the authorizer checks again for what we can't see from here.
|
|
|
171
171
|
|
|
172
172
|
**NF-e only**, and it takes no access key: there is no document to point at.
|
|
173
173
|
|
|
174
|
+
## Documents issued against you
|
|
175
|
+
|
|
176
|
+
Everything above serves the **issuer**. These two serve the **recipient**: what
|
|
177
|
+
suppliers billed to this CNPJ, and the formal answer to it.
|
|
178
|
+
|
|
179
|
+
Reading the list never calls the SEFAZ. The authorizer caps how many times a CNPJ
|
|
180
|
+
may ask for its distribution per day, so collecting runs on a schedule on the API
|
|
181
|
+
side and a page refresh cannot spend that allowance.
|
|
182
|
+
|
|
183
|
+
```python
|
|
184
|
+
from stackin import Manifestation
|
|
185
|
+
|
|
186
|
+
page = client.received(limit=20)
|
|
187
|
+
for document in page["data"]:
|
|
188
|
+
print(document["access_key"], document["issuer_name"], document["amount"])
|
|
189
|
+
|
|
190
|
+
client.manifest(access_key, manifestation=Manifestation.CIENCIA)
|
|
191
|
+
client.manifest(
|
|
192
|
+
access_key,
|
|
193
|
+
manifestation=Manifestation.OPERACAO_NAO_REALIZADA,
|
|
194
|
+
reason="Mercadoria nunca chegou ao endereco",
|
|
195
|
+
)
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
Before you answer a document the SEFAZ sends only a **summary** (`resNFe`): access
|
|
199
|
+
key, issuer, amount, date. The **full document** (`nfeProc`) arrives after a
|
|
200
|
+
manifestation, and the `schema` field on each row says which one you hold.
|
|
201
|
+
|
|
202
|
+
The four answers are `210200` Confirmação da Operação, `210210` Ciência da
|
|
203
|
+
Operação, `210220` Desconhecimento da Operação and `210240` Operação não
|
|
204
|
+
Realizada. Only the last one takes a reason, and it requires one — both rules are
|
|
205
|
+
checked locally, before the request goes out, because a round trip to be told a
|
|
206
|
+
fixed rule is a round trip wasted.
|
|
207
|
+
|
|
174
208
|
## Errors
|
|
175
209
|
|
|
176
210
|
- `stackin.APIError` — the API responded with a non-2xx status (`status_code`, `detail`) — a 401 here means `api_key` is missing, wrong, or was rotated.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "stackin-python-sdk"
|
|
3
|
-
version = "0.
|
|
3
|
+
version = "0.4.0"
|
|
4
4
|
authors = [
|
|
5
5
|
{ name = "Fernando Celmer", email = "email@fernandocelmer.com" },
|
|
6
6
|
]
|
|
@@ -45,7 +45,7 @@ Changelog = "https://github.com/stackin-io/stackin-python-sdk/releases"
|
|
|
45
45
|
|
|
46
46
|
[tool.poetry]
|
|
47
47
|
name = "stackin-python-sdk"
|
|
48
|
-
version = "0.
|
|
48
|
+
version = "0.4.0"
|
|
49
49
|
description = "Python SDK for issuing, consulting and cancelling electronic invoices."
|
|
50
50
|
authors = ["Fernando Celmer <email@fernandocelmer.com>"]
|
|
51
51
|
readme = "README.md"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"""Invoice __init__ module."""
|
|
2
2
|
|
|
3
|
-
__version__ = "0.
|
|
3
|
+
__version__ = "0.4.0"
|
|
4
4
|
__description__ = (
|
|
5
5
|
"Python SDK for issuing, consulting and cancelling electronic invoices."
|
|
6
6
|
)
|
|
@@ -8,12 +8,13 @@ __description__ = (
|
|
|
8
8
|
from .core.address import Address
|
|
9
9
|
from .core.client import Invoice
|
|
10
10
|
from .core.exceptions import APIError, ConnectionFailedError, InvoiceError
|
|
11
|
-
from .core.types import DocumentType, Environment
|
|
11
|
+
from .core.types import DocumentType, Environment, Manifestation
|
|
12
12
|
|
|
13
13
|
__all__ = [
|
|
14
14
|
"Invoice",
|
|
15
15
|
"DocumentType",
|
|
16
16
|
"Environment",
|
|
17
|
+
"Manifestation",
|
|
17
18
|
"Address",
|
|
18
19
|
"InvoiceError",
|
|
19
20
|
"APIError",
|
|
@@ -5,12 +5,29 @@ from stackin.br.tax import (
|
|
|
5
5
|
CofinsAliq,
|
|
6
6
|
CofinsNt,
|
|
7
7
|
CofinsOutr,
|
|
8
|
+
CofinsQtde,
|
|
9
|
+
CofinsSt,
|
|
8
10
|
Icms00,
|
|
11
|
+
Icms02,
|
|
12
|
+
Icms10,
|
|
13
|
+
Icms15,
|
|
14
|
+
Icms20,
|
|
15
|
+
Icms30,
|
|
9
16
|
Icms40,
|
|
17
|
+
Icms51,
|
|
18
|
+
Icms53,
|
|
10
19
|
Icms60,
|
|
20
|
+
Icms61,
|
|
21
|
+
Icms70,
|
|
22
|
+
Icms90,
|
|
23
|
+
IcmsPart,
|
|
11
24
|
IcmsSn101,
|
|
12
25
|
IcmsSn102,
|
|
26
|
+
IcmsSn201,
|
|
27
|
+
IcmsSn202,
|
|
28
|
+
IcmsSn500,
|
|
13
29
|
IcmsSn900,
|
|
30
|
+
IcmsSt,
|
|
14
31
|
IcmsUfDest,
|
|
15
32
|
Ipi,
|
|
16
33
|
IpiNt,
|
|
@@ -18,6 +35,8 @@ from stackin.br.tax import (
|
|
|
18
35
|
PisAliq,
|
|
19
36
|
PisNt,
|
|
20
37
|
PisOutr,
|
|
38
|
+
PisQtde,
|
|
39
|
+
PisSt,
|
|
21
40
|
Tax,
|
|
22
41
|
)
|
|
23
42
|
|
|
@@ -26,19 +45,38 @@ __all__ = [
|
|
|
26
45
|
"PresumedCredit",
|
|
27
46
|
"Tax",
|
|
28
47
|
"Icms00",
|
|
48
|
+
"Icms02",
|
|
49
|
+
"Icms10",
|
|
50
|
+
"Icms15",
|
|
51
|
+
"Icms20",
|
|
52
|
+
"Icms30",
|
|
29
53
|
"Icms40",
|
|
54
|
+
"Icms51",
|
|
55
|
+
"Icms53",
|
|
30
56
|
"Icms60",
|
|
57
|
+
"Icms61",
|
|
58
|
+
"Icms70",
|
|
59
|
+
"Icms90",
|
|
60
|
+
"IcmsPart",
|
|
61
|
+
"IcmsSt",
|
|
31
62
|
"IcmsSn101",
|
|
32
63
|
"IcmsSn102",
|
|
64
|
+
"IcmsSn201",
|
|
65
|
+
"IcmsSn202",
|
|
66
|
+
"IcmsSn500",
|
|
33
67
|
"IcmsSn900",
|
|
34
68
|
"IcmsUfDest",
|
|
35
69
|
"Ipi",
|
|
36
70
|
"IpiTrib",
|
|
37
71
|
"IpiNt",
|
|
38
72
|
"PisAliq",
|
|
73
|
+
"PisQtde",
|
|
39
74
|
"PisNt",
|
|
40
75
|
"PisOutr",
|
|
76
|
+
"PisSt",
|
|
41
77
|
"CofinsAliq",
|
|
78
|
+
"CofinsQtde",
|
|
42
79
|
"CofinsNt",
|
|
43
80
|
"CofinsOutr",
|
|
81
|
+
"CofinsSt",
|
|
44
82
|
]
|
|
@@ -67,7 +67,10 @@ class Product(BaseModel):
|
|
|
67
67
|
ex_tipi: str | None = Field(default=None, pattern=r"^\d{2,3}$")
|
|
68
68
|
import_content_control_number: str | None = Field(
|
|
69
69
|
default=None,
|
|
70
|
-
pattern=
|
|
70
|
+
pattern=(
|
|
71
|
+
r"^[A-F0-9]{8}-[A-F0-9]{4}-[A-F0-9]{4}"
|
|
72
|
+
r"-[A-F0-9]{4}-[A-F0-9]{12}$"
|
|
73
|
+
),
|
|
71
74
|
)
|
|
72
75
|
recopi_number: str | None = Field(default=None, pattern=r"^\d{20}$")
|
|
73
76
|
extra_groups: dict[str, Any] | None = Field(default=None)
|