python-easyverein 0.2.1__tar.gz → 0.2.2__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.
- {python_easyverein-0.2.1 → python_easyverein-0.2.2}/PKG-INFO +1 -1
- {python_easyverein-0.2.1 → python_easyverein-0.2.2}/easyverein/__init__.py +1 -1
- {python_easyverein-0.2.1 → python_easyverein-0.2.2}/easyverein/core/client.py +27 -3
- {python_easyverein-0.2.1 → python_easyverein-0.2.2}/easyverein/models/invoice.py +2 -2
- {python_easyverein-0.2.1 → python_easyverein-0.2.2}/easyverein/modules/invoice.py +45 -0
- {python_easyverein-0.2.1 → python_easyverein-0.2.2}/pyproject.toml +1 -1
- {python_easyverein-0.2.1 → python_easyverein-0.2.2}/LICENSE +0 -0
- {python_easyverein-0.2.1 → python_easyverein-0.2.2}/README.md +0 -0
- {python_easyverein-0.2.1 → python_easyverein-0.2.2}/easyverein/api.py +0 -0
- {python_easyverein-0.2.1 → python_easyverein-0.2.2}/easyverein/core/__init__.py +0 -0
- {python_easyverein-0.2.1 → python_easyverein-0.2.2}/easyverein/core/exceptions.py +0 -0
- {python_easyverein-0.2.1 → python_easyverein-0.2.2}/easyverein/core/protocol.py +0 -0
- {python_easyverein-0.2.1 → python_easyverein-0.2.2}/easyverein/core/types.py +0 -0
- {python_easyverein-0.2.1 → python_easyverein-0.2.2}/easyverein/core/validators.py +0 -0
- {python_easyverein-0.2.1 → python_easyverein-0.2.2}/easyverein/models/__init__.py +0 -0
- {python_easyverein-0.2.1 → python_easyverein-0.2.2}/easyverein/models/base.py +0 -0
- {python_easyverein-0.2.1 → python_easyverein-0.2.2}/easyverein/models/contact_details.py +0 -0
- {python_easyverein-0.2.1 → python_easyverein-0.2.2}/easyverein/models/custom_field.py +0 -0
- {python_easyverein-0.2.1 → python_easyverein-0.2.2}/easyverein/models/invoice_item.py +0 -0
- {python_easyverein-0.2.1 → python_easyverein-0.2.2}/easyverein/models/member.py +0 -0
- {python_easyverein-0.2.1 → python_easyverein-0.2.2}/easyverein/models/member_custom_field.py +0 -0
- {python_easyverein-0.2.1 → python_easyverein-0.2.2}/easyverein/models/mixins/__init__.py +0 -0
- {python_easyverein-0.2.1 → python_easyverein-0.2.2}/easyverein/models/mixins/empty_strings_mixin.py +0 -0
- {python_easyverein-0.2.1 → python_easyverein-0.2.2}/easyverein/models/mixins/required_attributes.py +0 -0
- {python_easyverein-0.2.1 → python_easyverein-0.2.2}/easyverein/modules/__init__.py +0 -0
- {python_easyverein-0.2.1 → python_easyverein-0.2.2}/easyverein/modules/contact_details.py +0 -0
- {python_easyverein-0.2.1 → python_easyverein-0.2.2}/easyverein/modules/custom_field.py +0 -0
- {python_easyverein-0.2.1 → python_easyverein-0.2.2}/easyverein/modules/invoice_item.py +0 -0
- {python_easyverein-0.2.1 → python_easyverein-0.2.2}/easyverein/modules/member.py +0 -0
- {python_easyverein-0.2.1 → python_easyverein-0.2.2}/easyverein/modules/member_custom_field.py +0 -0
- {python_easyverein-0.2.1 → python_easyverein-0.2.2}/easyverein/modules/mixins/__init__.py +0 -0
- {python_easyverein-0.2.1 → python_easyverein-0.2.2}/easyverein/modules/mixins/crud.py +0 -0
- {python_easyverein-0.2.1 → python_easyverein-0.2.2}/easyverein/modules/mixins/recycle_bin.py +0 -0
|
@@ -5,10 +5,11 @@ from __future__ import annotations
|
|
|
5
5
|
|
|
6
6
|
import logging
|
|
7
7
|
from pathlib import Path
|
|
8
|
-
from typing import TYPE_CHECKING, TypeVar
|
|
8
|
+
from typing import TYPE_CHECKING, Any, TypeVar
|
|
9
9
|
|
|
10
10
|
import requests
|
|
11
11
|
from pydantic import BaseModel
|
|
12
|
+
from requests.structures import CaseInsensitiveDict
|
|
12
13
|
|
|
13
14
|
from .exceptions import (
|
|
14
15
|
EasyvereinAPIException,
|
|
@@ -76,8 +77,8 @@ class EasyvereinClient:
|
|
|
76
77
|
return url
|
|
77
78
|
|
|
78
79
|
def _do_request( # noqa: PLR0913
|
|
79
|
-
self, method, url, data=None, headers=None, files=None
|
|
80
|
-
):
|
|
80
|
+
self, method, url, binary=False, data=None, headers=None, files=None
|
|
81
|
+
) -> tuple[int, dict[str, Any] | requests.Response | None]:
|
|
81
82
|
"""
|
|
82
83
|
Helper method that performs an actual call against the API,
|
|
83
84
|
fetching the most common errors
|
|
@@ -130,6 +131,10 @@ class EasyvereinClient:
|
|
|
130
131
|
if res.content == b"":
|
|
131
132
|
return res.status_code, None
|
|
132
133
|
|
|
134
|
+
# If content is supposed to be binary, return the entire response to maintain headers
|
|
135
|
+
if binary:
|
|
136
|
+
return res.status_code, res
|
|
137
|
+
|
|
133
138
|
# Try to parse response as JSON and return it for further processing
|
|
134
139
|
try:
|
|
135
140
|
content = res.json()
|
|
@@ -235,6 +240,25 @@ class EasyvereinClient:
|
|
|
235
240
|
|
|
236
241
|
return data, total_count
|
|
237
242
|
|
|
243
|
+
def fetch_file(self, url: str) -> tuple[bytes, CaseInsensitiveDict[str]]:
|
|
244
|
+
"""
|
|
245
|
+
Helper method that fetches a file from the API including the authentication header
|
|
246
|
+
|
|
247
|
+
Returns the raw bytes object and the entire header for further processing
|
|
248
|
+
"""
|
|
249
|
+
status_code, res = self._do_request("get", url, binary=True)
|
|
250
|
+
|
|
251
|
+
# Check if status code is 200
|
|
252
|
+
if status_code != 200:
|
|
253
|
+
self.logger.error(
|
|
254
|
+
f"Request to download file failed with unexpected status code {status_code}"
|
|
255
|
+
)
|
|
256
|
+
raise EasyvereinAPIException(
|
|
257
|
+
f"Request to download file failed with unexpected status code {status_code}"
|
|
258
|
+
)
|
|
259
|
+
|
|
260
|
+
return res.content, res.headers
|
|
261
|
+
|
|
238
262
|
def fetch_one(self, url, model: type[T] = None) -> T | None:
|
|
239
263
|
"""
|
|
240
264
|
Helper method that fetches a result from an API call
|
|
@@ -39,8 +39,7 @@ class Invoice(EasyVereinBase):
|
|
|
39
39
|
tax: float | None = None
|
|
40
40
|
taxRate: float | None = None
|
|
41
41
|
taxName: str | None = None
|
|
42
|
-
|
|
43
|
-
relatedAddress: EasyVereinReference | None = None
|
|
42
|
+
relatedAddress: ContactDetails | EasyVereinReference | None = None
|
|
44
43
|
path: EasyVereinReference | None = None
|
|
45
44
|
kind: Literal[
|
|
46
45
|
"balance", "donation", "membership", "revenue", "expense", "cancel", "credit"
|
|
@@ -129,5 +128,6 @@ class InvoiceFilter(BaseModel):
|
|
|
129
128
|
search: str | None = None
|
|
130
129
|
|
|
131
130
|
|
|
131
|
+
from .contact_details import ContactDetails # noqa: E402
|
|
132
132
|
from .invoice_item import InvoiceItem # noqa: E402
|
|
133
133
|
from .member import Member # noqa: E402
|
|
@@ -2,6 +2,8 @@ import logging
|
|
|
2
2
|
from pathlib import Path
|
|
3
3
|
from typing import List
|
|
4
4
|
|
|
5
|
+
from requests.structures import CaseInsensitiveDict
|
|
6
|
+
|
|
5
7
|
from ..core.client import EasyvereinClient
|
|
6
8
|
from ..core.exceptions import EasyvereinAPIException
|
|
7
9
|
from ..models.invoice import Invoice, InvoiceCreate, InvoiceFilter, InvoiceUpdate
|
|
@@ -125,3 +127,46 @@ class InvoiceMixin(
|
|
|
125
127
|
inv = self.get_by_id(inv.id)
|
|
126
128
|
|
|
127
129
|
return inv
|
|
130
|
+
|
|
131
|
+
def get_attachment(
|
|
132
|
+
self, invoice: Invoice | int
|
|
133
|
+
) -> tuple[bytes, CaseInsensitiveDict[str]]:
|
|
134
|
+
"""
|
|
135
|
+
This method downloads and returns the invoice attachment if available.
|
|
136
|
+
|
|
137
|
+
It accepts either an invoice object or its id. If the invoice is given, and the path attribute is
|
|
138
|
+
set, it will simply use this path to download and return the file. In all other cases, it first retrieves
|
|
139
|
+
the invoice object by id and then proceeds to download the file.
|
|
140
|
+
|
|
141
|
+
Returns a tuple, where the first element is the file and the second contains the headers of the response
|
|
142
|
+
|
|
143
|
+
**Usage**
|
|
144
|
+
|
|
145
|
+
```python
|
|
146
|
+
invoice = ev_connection.invoice.get_by_id(invoice_id, query="{id,path}")
|
|
147
|
+
|
|
148
|
+
attachment, headers = ev_connection.invoice.get_attachment(invoice)
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
Args:
|
|
152
|
+
invoice: The invoice object or its id for which the attachment should be retrieved
|
|
153
|
+
"""
|
|
154
|
+
if isinstance(invoice, Invoice) and invoice.path:
|
|
155
|
+
self.logger.info(
|
|
156
|
+
"Invoice already has the path attribute set, using that path."
|
|
157
|
+
)
|
|
158
|
+
path = invoice.path
|
|
159
|
+
else:
|
|
160
|
+
self.logger.info(
|
|
161
|
+
"Invoice is either given by id or doesn't contain the path attribute"
|
|
162
|
+
)
|
|
163
|
+
invoice_id = invoice.id if isinstance(invoice, Invoice) else invoice
|
|
164
|
+
fetched_invoice = self.get_by_id(invoice_id, query="{id,path}")
|
|
165
|
+
path = fetched_invoice.path
|
|
166
|
+
|
|
167
|
+
if not path:
|
|
168
|
+
raise EasyvereinAPIException(
|
|
169
|
+
"Unable to obtain a valid path for given invoice."
|
|
170
|
+
)
|
|
171
|
+
|
|
172
|
+
return self.c.fetch_file(path)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{python_easyverein-0.2.1 → python_easyverein-0.2.2}/easyverein/models/member_custom_field.py
RENAMED
|
File without changes
|
|
File without changes
|
{python_easyverein-0.2.1 → python_easyverein-0.2.2}/easyverein/models/mixins/empty_strings_mixin.py
RENAMED
|
File without changes
|
{python_easyverein-0.2.1 → python_easyverein-0.2.2}/easyverein/models/mixins/required_attributes.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{python_easyverein-0.2.1 → python_easyverein-0.2.2}/easyverein/modules/member_custom_field.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{python_easyverein-0.2.1 → python_easyverein-0.2.2}/easyverein/modules/mixins/recycle_bin.py
RENAMED
|
File without changes
|