stackin-python-sdk 0.1.0__tar.gz → 0.1.1__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.1.0 → stackin_python_sdk-0.1.1}/PKG-INFO +10 -16
- {stackin_python_sdk-0.1.0 → stackin_python_sdk-0.1.1}/README.md +4 -15
- {stackin_python_sdk-0.1.0 → stackin_python_sdk-0.1.1}/pyproject.toml +9 -2
- {stackin_python_sdk-0.1.0 → stackin_python_sdk-0.1.1}/stackin/__init__.py +1 -1
- {stackin_python_sdk-0.1.0 → stackin_python_sdk-0.1.1}/stackin/br/product.py +11 -5
- {stackin_python_sdk-0.1.0 → stackin_python_sdk-0.1.1}/stackin/br/tax.py +9 -3
- {stackin_python_sdk-0.1.0 → stackin_python_sdk-0.1.1}/stackin/core/client.py +7 -3
- {stackin_python_sdk-0.1.0 → stackin_python_sdk-0.1.1}/LICENSE +0 -0
- {stackin_python_sdk-0.1.0 → stackin_python_sdk-0.1.1}/stackin/br/__init__.py +0 -0
- {stackin_python_sdk-0.1.0 → stackin_python_sdk-0.1.1}/stackin/core/__init__.py +0 -0
- {stackin_python_sdk-0.1.0 → stackin_python_sdk-0.1.1}/stackin/core/address.py +0 -0
- {stackin_python_sdk-0.1.0 → stackin_python_sdk-0.1.1}/stackin/core/exceptions.py +0 -0
- {stackin_python_sdk-0.1.0 → stackin_python_sdk-0.1.1}/stackin/core/types.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: stackin-python-sdk
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.1
|
|
4
4
|
Summary: Python SDK for issuing, consulting and cancelling electronic invoices.
|
|
5
5
|
License-Expression: MIT
|
|
6
6
|
License-File: LICENSE
|
|
@@ -20,6 +20,11 @@ Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
|
20
20
|
Classifier: Natural Language :: Portuguese (Brazilian)
|
|
21
21
|
Requires-Dist: pydantic
|
|
22
22
|
Requires-Dist: requests
|
|
23
|
+
Project-URL: Changelog, https://github.com/stackin-io/stackin-python-sdk/releases
|
|
24
|
+
Project-URL: Documentation, https://docs.stackin.io/blog/python-sdk
|
|
25
|
+
Project-URL: Homepage, https://docs.stackin.io
|
|
26
|
+
Project-URL: Issues, https://github.com/stackin-io/stackin-python-sdk/issues
|
|
27
|
+
Project-URL: Repository, https://github.com/stackin-io/stackin-python-sdk
|
|
23
28
|
Description-Content-Type: text/markdown
|
|
24
29
|
|
|
25
30
|
<div align="center">
|
|
@@ -29,8 +34,11 @@ Description-Content-Type: text/markdown
|
|
|
29
34
|
**Integrate once. Issue everywhere.**
|
|
30
35
|
|
|
31
36
|
[](pyproject.toml)
|
|
37
|
+
[](https://pypi.org/project/stackin-python-sdk/)
|
|
32
38
|
[](https://github.com/stackin-io/stackin-python-sdk)
|
|
33
39
|
|
|
40
|
+
[API Reference](https://docs.stackin.io) · [Python SDK guide](https://docs.stackin.io/blog/python-sdk)
|
|
41
|
+
|
|
34
42
|
</div>
|
|
35
43
|
|
|
36
44
|
---
|
|
@@ -49,7 +57,7 @@ pip install stackin-python-sdk
|
|
|
49
57
|
|
|
50
58
|
## Usage
|
|
51
59
|
|
|
52
|
-
Get an `api_key` from the [stackin dashboard](https://app.stackin.io) — select the issuing company, then Settings → API key. One key per issuing company, shown once at creation. The API resolves the issuer (CNPJ, state, address, certificate, environment) entirely from it; nothing about the issuer is ever passed on a call.
|
|
60
|
+
Get an `api_key` from the [stackin dashboard](https://app.stackin.io) — select the issuing company, then Settings → API key (context `sdk`). One key per issuing company, shown once at creation. The API resolves the issuer (CNPJ, state, address, certificate, environment) entirely from it; nothing about the issuer is ever passed on a call.
|
|
53
61
|
|
|
54
62
|
```python
|
|
55
63
|
from stackin import Invoice, DocumentType, Address
|
|
@@ -98,17 +106,3 @@ Building the full fiscal document (issuer data, service code, tax groups, schema
|
|
|
98
106
|
|
|
99
107
|
Runnable end-to-end scripts in [`examples/`](examples/) — `simple_issue_nfe.py` and `simple_issue_nfse.py`, each with a catalog of realistic line items covering every optional field.
|
|
100
108
|
|
|
101
|
-
## Commit Style
|
|
102
|
-
|
|
103
|
-
| Icon | Type | Description |
|
|
104
|
-
|------|-----------|--------------------------------------------|
|
|
105
|
-
| ⚙️ | FEATURE | New feature |
|
|
106
|
-
| 📝 | PEP8 | Formatting fixes following PEP8 |
|
|
107
|
-
| 📌 | ISSUE | Reference to issue |
|
|
108
|
-
| 🪲 | BUG | Bug fix |
|
|
109
|
-
| 📘 | DOCS | Documentation changes |
|
|
110
|
-
| 📦 | PyPI | PyPI releases |
|
|
111
|
-
| ❤️️ | TEST | Automated tests |
|
|
112
|
-
| ⬆️ | CI/CD | Changes in continuous integration/delivery |
|
|
113
|
-
| ⚠️ | SECURITY | Security improvements |
|
|
114
|
-
|
|
@@ -5,8 +5,11 @@
|
|
|
5
5
|
**Integrate once. Issue everywhere.**
|
|
6
6
|
|
|
7
7
|
[](pyproject.toml)
|
|
8
|
+
[](https://pypi.org/project/stackin-python-sdk/)
|
|
8
9
|
[](https://github.com/stackin-io/stackin-python-sdk)
|
|
9
10
|
|
|
11
|
+
[API Reference](https://docs.stackin.io) · [Python SDK guide](https://docs.stackin.io/blog/python-sdk)
|
|
12
|
+
|
|
10
13
|
</div>
|
|
11
14
|
|
|
12
15
|
---
|
|
@@ -25,7 +28,7 @@ pip install stackin-python-sdk
|
|
|
25
28
|
|
|
26
29
|
## Usage
|
|
27
30
|
|
|
28
|
-
Get an `api_key` from the [stackin dashboard](https://app.stackin.io) — select the issuing company, then Settings → API key. One key per issuing company, shown once at creation. The API resolves the issuer (CNPJ, state, address, certificate, environment) entirely from it; nothing about the issuer is ever passed on a call.
|
|
31
|
+
Get an `api_key` from the [stackin dashboard](https://app.stackin.io) — select the issuing company, then Settings → API key (context `sdk`). One key per issuing company, shown once at creation. The API resolves the issuer (CNPJ, state, address, certificate, environment) entirely from it; nothing about the issuer is ever passed on a call.
|
|
29
32
|
|
|
30
33
|
```python
|
|
31
34
|
from stackin import Invoice, DocumentType, Address
|
|
@@ -73,17 +76,3 @@ Building the full fiscal document (issuer data, service code, tax groups, schema
|
|
|
73
76
|
## Examples
|
|
74
77
|
|
|
75
78
|
Runnable end-to-end scripts in [`examples/`](examples/) — `simple_issue_nfe.py` and `simple_issue_nfse.py`, each with a catalog of realistic line items covering every optional field.
|
|
76
|
-
|
|
77
|
-
## Commit Style
|
|
78
|
-
|
|
79
|
-
| Icon | Type | Description |
|
|
80
|
-
|------|-----------|--------------------------------------------|
|
|
81
|
-
| ⚙️ | FEATURE | New feature |
|
|
82
|
-
| 📝 | PEP8 | Formatting fixes following PEP8 |
|
|
83
|
-
| 📌 | ISSUE | Reference to issue |
|
|
84
|
-
| 🪲 | BUG | Bug fix |
|
|
85
|
-
| 📘 | DOCS | Documentation changes |
|
|
86
|
-
| 📦 | PyPI | PyPI releases |
|
|
87
|
-
| ❤️️ | TEST | Automated tests |
|
|
88
|
-
| ⬆️ | CI/CD | Changes in continuous integration/delivery |
|
|
89
|
-
| ⚠️ | SECURITY | Security improvements |
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "stackin-python-sdk"
|
|
3
|
-
version = "0.1.
|
|
3
|
+
version = "0.1.1"
|
|
4
4
|
authors = [
|
|
5
5
|
{ name = "Fernando Celmer", email = "email@fernandocelmer.com" },
|
|
6
6
|
]
|
|
@@ -36,9 +36,16 @@ dependencies = [
|
|
|
36
36
|
"pydantic",
|
|
37
37
|
]
|
|
38
38
|
|
|
39
|
+
[project.urls]
|
|
40
|
+
Homepage = "https://docs.stackin.io"
|
|
41
|
+
Documentation = "https://docs.stackin.io/blog/python-sdk"
|
|
42
|
+
Repository = "https://github.com/stackin-io/stackin-python-sdk"
|
|
43
|
+
Issues = "https://github.com/stackin-io/stackin-python-sdk/issues"
|
|
44
|
+
Changelog = "https://github.com/stackin-io/stackin-python-sdk/releases"
|
|
45
|
+
|
|
39
46
|
[tool.poetry]
|
|
40
47
|
name = "stackin-python-sdk"
|
|
41
|
-
version = "0.1.
|
|
48
|
+
version = "0.1.1"
|
|
42
49
|
description = "Python SDK for issuing, consulting and cancelling electronic invoices."
|
|
43
50
|
authors = ["Fernando Celmer <email@fernandocelmer.com>"]
|
|
44
51
|
readme = "README.md"
|
|
@@ -55,11 +55,13 @@ class Product(BaseModel):
|
|
|
55
55
|
ncm: str | None = Field(default=None, pattern=r"^\d{2}$|^\d{8}$")
|
|
56
56
|
cfop: str | None = Field(default=None, pattern=r"^[123567]\d{3}$")
|
|
57
57
|
cest: str | None = Field(default=None, pattern=r"^\d{7}$")
|
|
58
|
-
nve_codes:
|
|
59
|
-
|
|
60
|
-
)
|
|
58
|
+
nve_codes: (
|
|
59
|
+
list[Annotated[str, Field(pattern=r"^[A-Z]{2}\d{4}$")]] | None
|
|
60
|
+
) = Field(default=None)
|
|
61
61
|
ind_escala: str | None = Field(default=None)
|
|
62
|
-
manufacturer_cnpj: str | None = Field(
|
|
62
|
+
manufacturer_cnpj: str | None = Field(
|
|
63
|
+
default=None, pattern=r"^[0-9A-Z]{12}\d{2}$"
|
|
64
|
+
)
|
|
63
65
|
tax_benefit_code: str | None = Field(default=None, pattern=_CBENEF_PATTERN)
|
|
64
66
|
presumed_credits: list[PresumedCredit] | None = Field(default=None)
|
|
65
67
|
ex_tipi: str | None = Field(default=None, pattern=r"^\d{2,3}$")
|
|
@@ -84,4 +86,8 @@ class Product(BaseModel):
|
|
|
84
86
|
br["tax"] = self.tax
|
|
85
87
|
if br:
|
|
86
88
|
data["br"] = br
|
|
87
|
-
return {
|
|
89
|
+
return {
|
|
90
|
+
"description": self.description,
|
|
91
|
+
"amount": self.amount,
|
|
92
|
+
"product": data,
|
|
93
|
+
}
|
|
@@ -44,7 +44,9 @@ class Icms60(BaseModel):
|
|
|
44
44
|
cst: str = Field(default="60", alias="CST")
|
|
45
45
|
v_bc_st_ret: str | None = Field(default=None, alias="vBCSTRet")
|
|
46
46
|
p_st: str | None = Field(default=None, alias="pST")
|
|
47
|
-
v_icms_substituto: str | None = Field(
|
|
47
|
+
v_icms_substituto: str | None = Field(
|
|
48
|
+
default=None, alias="vICMSSubstituto"
|
|
49
|
+
)
|
|
48
50
|
v_icms_st_ret: str | None = Field(default=None, alias="vICMSSTRet")
|
|
49
51
|
v_bc_fcp_st_ret: str | None = Field(default=None, alias="vBCFCPSTRet")
|
|
50
52
|
p_fcp_st_ret: str | None = Field(default=None, alias="pFCPSTRet")
|
|
@@ -234,7 +236,9 @@ class Tax(BaseModel):
|
|
|
234
236
|
by_alias=True, exclude_none=True
|
|
235
237
|
)
|
|
236
238
|
if self.ipi is not None:
|
|
237
|
-
data["IPI"] =
|
|
239
|
+
data["IPI"] = (
|
|
240
|
+
self.ipi.to_dict() if isinstance(self.ipi, Ipi) else self.ipi
|
|
241
|
+
)
|
|
238
242
|
if self.pis is not None:
|
|
239
243
|
data["PIS"] = _wrap(self.pis, _PIS_TAGS)
|
|
240
244
|
if self.cofins is not None:
|
|
@@ -246,4 +250,6 @@ def _wrap(group: BaseModel | dict, tags: dict[type, str]) -> dict:
|
|
|
246
250
|
"""Nests a tax group under its variant name."""
|
|
247
251
|
if isinstance(group, dict):
|
|
248
252
|
return group
|
|
249
|
-
return {
|
|
253
|
+
return {
|
|
254
|
+
tags[type(group)]: group.model_dump(by_alias=True, exclude_none=True)
|
|
255
|
+
}
|
|
@@ -6,8 +6,8 @@ import os
|
|
|
6
6
|
|
|
7
7
|
import requests
|
|
8
8
|
|
|
9
|
-
from stackin.core.address import Address
|
|
10
9
|
from stackin.br.product import Product
|
|
10
|
+
from stackin.core.address import Address
|
|
11
11
|
from stackin.core.exceptions import APIError, ConnectionFailedError
|
|
12
12
|
from stackin.core.types import DocumentType, Environment
|
|
13
13
|
|
|
@@ -71,7 +71,9 @@ class Invoice:
|
|
|
71
71
|
if not item.ncm:
|
|
72
72
|
raise ValueError(f"items[{index}].ncm is required for NFE")
|
|
73
73
|
if not item.cfop:
|
|
74
|
-
raise ValueError(
|
|
74
|
+
raise ValueError(
|
|
75
|
+
f"items[{index}].cfop is required for NFE"
|
|
76
|
+
)
|
|
75
77
|
|
|
76
78
|
payload = {
|
|
77
79
|
"document_type": document_type.value,
|
|
@@ -108,7 +110,9 @@ class Invoice:
|
|
|
108
110
|
"reason": reason,
|
|
109
111
|
}
|
|
110
112
|
|
|
111
|
-
return self._request(
|
|
113
|
+
return self._request(
|
|
114
|
+
"POST", f"/invoices/{access_key}/cancel", json=payload
|
|
115
|
+
)
|
|
112
116
|
|
|
113
117
|
def _headers(self) -> dict:
|
|
114
118
|
if self.api_key:
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|