stackin-python-sdk 0.2.0__py3-none-any.whl → 0.3.0__py3-none-any.whl
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/__init__.py +1 -1
- stackin/core/client.py +47 -6
- {stackin_python_sdk-0.2.0.dist-info → stackin_python_sdk-0.3.0.dist-info}/METADATA +7 -2
- {stackin_python_sdk-0.2.0.dist-info → stackin_python_sdk-0.3.0.dist-info}/RECORD +6 -6
- {stackin_python_sdk-0.2.0.dist-info → stackin_python_sdk-0.3.0.dist-info}/WHEEL +0 -0
- {stackin_python_sdk-0.2.0.dist-info → stackin_python_sdk-0.3.0.dist-info}/licenses/LICENSE +0 -0
stackin/__init__.py
CHANGED
stackin/core/client.py
CHANGED
|
@@ -204,6 +204,26 @@ class Invoice:
|
|
|
204
204
|
idempotency_key=idempotency_key,
|
|
205
205
|
)
|
|
206
206
|
|
|
207
|
+
def pdf(
|
|
208
|
+
self,
|
|
209
|
+
access_key: str,
|
|
210
|
+
*,
|
|
211
|
+
document_type: DocumentType,
|
|
212
|
+
) -> bytes:
|
|
213
|
+
"""The authorizer's rendering of an authorized document.
|
|
214
|
+
|
|
215
|
+
Returns raw bytes — the only method that does not return a
|
|
216
|
+
parsed object. The XML is the legally valid document; this is a
|
|
217
|
+
convenience, and the authorizer's endpoint for it is unstable,
|
|
218
|
+
so an APIError with status 502 means the authorizer is
|
|
219
|
+
unavailable, not that the invoice is wrong. NFS-e only.
|
|
220
|
+
"""
|
|
221
|
+
params = {"document_type": document_type.value}
|
|
222
|
+
response = self._send(
|
|
223
|
+
"GET", f"/invoices/{access_key}/pdf", params=params
|
|
224
|
+
)
|
|
225
|
+
return response.content
|
|
226
|
+
|
|
207
227
|
def _headers(self, idempotency_key: str | None = None) -> dict:
|
|
208
228
|
headers = {}
|
|
209
229
|
if self.api_key:
|
|
@@ -221,6 +241,28 @@ class Invoice:
|
|
|
221
241
|
params: dict | None = None,
|
|
222
242
|
idempotency_key: str | None = None,
|
|
223
243
|
) -> dict:
|
|
244
|
+
response = self._send(
|
|
245
|
+
method,
|
|
246
|
+
path,
|
|
247
|
+
json=json,
|
|
248
|
+
params=params,
|
|
249
|
+
idempotency_key=idempotency_key,
|
|
250
|
+
)
|
|
251
|
+
try:
|
|
252
|
+
body = response.json() if response.content else {}
|
|
253
|
+
except ValueError:
|
|
254
|
+
body = {}
|
|
255
|
+
return body.get("result", body)
|
|
256
|
+
|
|
257
|
+
def _send(
|
|
258
|
+
self,
|
|
259
|
+
method: str,
|
|
260
|
+
path: str,
|
|
261
|
+
*,
|
|
262
|
+
json: dict | None = None,
|
|
263
|
+
params: dict | None = None,
|
|
264
|
+
idempotency_key: str | None = None,
|
|
265
|
+
) -> requests.Response:
|
|
224
266
|
url = f"{self.base_url}/api/v1{path}"
|
|
225
267
|
|
|
226
268
|
try:
|
|
@@ -235,15 +277,14 @@ class Invoice:
|
|
|
235
277
|
except requests.RequestException as error:
|
|
236
278
|
raise ConnectionFailedError(str(error)) from error
|
|
237
279
|
|
|
238
|
-
try:
|
|
239
|
-
body = response.json() if response.content else {}
|
|
240
|
-
except ValueError:
|
|
241
|
-
body = {}
|
|
242
|
-
|
|
243
280
|
if not response.ok:
|
|
281
|
+
try:
|
|
282
|
+
body = response.json() if response.content else {}
|
|
283
|
+
except ValueError:
|
|
284
|
+
body = {}
|
|
244
285
|
raise APIError(
|
|
245
286
|
status_code=response.status_code,
|
|
246
287
|
detail=body.get("detail", response.text),
|
|
247
288
|
)
|
|
248
289
|
|
|
249
|
-
return
|
|
290
|
+
return response
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: stackin-python-sdk
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.3.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()`, 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()`, 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
|
|
|
@@ -80,6 +80,11 @@ client.cancel(
|
|
|
80
80
|
)
|
|
81
81
|
client.reissue(invoice["id"]) # retries a rejected/failed submission
|
|
82
82
|
|
|
83
|
+
# The authorizer's PDF, as raw bytes. NFS-e only; the XML stays the
|
|
84
|
+
# legally valid document, and a 502 here means the authorizer is down.
|
|
85
|
+
with open("nota.pdf", "wb") as file:
|
|
86
|
+
file.write(client.pdf(access_key, document_type=DocumentType.NFSE))
|
|
87
|
+
|
|
83
88
|
# NFE requires ncm/cfop on every item, plus the buyer's full recipient_address:
|
|
84
89
|
client.issue(
|
|
85
90
|
document_type=DocumentType.NFE,
|
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
stackin/__init__.py,sha256=
|
|
1
|
+
stackin/__init__.py,sha256=rsEjE3iiFCRB4EySvHJiK8B-OTrtB35teC6LHX9uo-Y,495
|
|
2
2
|
stackin/br/__init__.py,sha256=Nw5VyeoFFJPqweZI60uADtBrxilXqkpzpkYtR5WZ630,656
|
|
3
3
|
stackin/br/product.py,sha256=nuHQkWMz0eRmWYWPoduwmAfibBQvrcajEMxerwHGa9E,4004
|
|
4
4
|
stackin/br/tax.py,sha256=PdUkg5JdNKy7AHlt5ZpM9svvilZA93FPMr2QNi0SRlw,7716
|
|
5
5
|
stackin/core/__init__.py,sha256=dxtOP1DopMSNFYGh3Hf12RVcs58R9xwLn-gqfKFo-HE,19
|
|
6
6
|
stackin/core/address.py,sha256=-w5R3nzfU5T3VoxIeygu5Dq4DRb_lJHAGc0lmSMwEMU,616
|
|
7
|
-
stackin/core/client.py,sha256=
|
|
7
|
+
stackin/core/client.py,sha256=u8Q14sF844Pd0oMWy8AA0F4ry78p_s17mYprE2E8NNY,8486
|
|
8
8
|
stackin/core/exceptions.py,sha256=enl8GS_WlDV6PyH1M_KTxzLG9Qdr-9MJrMXB_AlCtYg,521
|
|
9
9
|
stackin/core/types.py,sha256=SYpLS2EnqKcudm7wFwCTOVAQe1IYT5T0TGSD0E6z8bo,416
|
|
10
|
-
stackin_python_sdk-0.
|
|
11
|
-
stackin_python_sdk-0.
|
|
12
|
-
stackin_python_sdk-0.
|
|
13
|
-
stackin_python_sdk-0.
|
|
10
|
+
stackin_python_sdk-0.3.0.dist-info/METADATA,sha256=pvDErFOVR0AphHcoXLuIU-cYwsHSgWvgEZLwwbctohI,9628
|
|
11
|
+
stackin_python_sdk-0.3.0.dist-info/WHEEL,sha256=eY7nduwzv-ldUxpzbRlxwvC693Hg6PX8bWDjEHjZ_dk,88
|
|
12
|
+
stackin_python_sdk-0.3.0.dist-info/licenses/LICENSE,sha256=D-XHDcKFFhzEo9C5Dp4QPvt00pb_u__hi4Bc08zpxyU,1072
|
|
13
|
+
stackin_python_sdk-0.3.0.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|