Add typed Pydantic models for positions and document payments, enhance EasybillClient with pagination and retry handling, and implement unit tests for workflow helpers.
This commit is contained in:
parent
b324671286
commit
57d6a49986
6 changed files with 375 additions and 5 deletions
155
tests/test_workflow_helpers.py
Normal file
155
tests/test_workflow_helpers.py
Normal file
|
|
@ -0,0 +1,155 @@
|
|||
import httpx
|
||||
import pytest
|
||||
|
||||
from easybill_client import AsyncEasybillClient, EasybillClient
|
||||
|
||||
|
||||
class WorkflowTransport(httpx.MockTransport):
|
||||
def __init__(self):
|
||||
self.rate_limit_hits = 0
|
||||
super().__init__(self._handler)
|
||||
|
||||
def _handler(self, request: httpx.Request) -> httpx.Response:
|
||||
if request.url.path == "/positions/5":
|
||||
return httpx.Response(
|
||||
200,
|
||||
json={
|
||||
"id": 5,
|
||||
"number": "ART-5",
|
||||
"type": "PRODUCT",
|
||||
"description": "Premium Support",
|
||||
"price": 4900,
|
||||
},
|
||||
)
|
||||
|
||||
if request.url.path == "/document-payments":
|
||||
if request.method == "POST":
|
||||
body = request.read().decode()
|
||||
assert "INV-1" in body
|
||||
return httpx.Response(
|
||||
201,
|
||||
json={
|
||||
"id": 88,
|
||||
"document_id": 10,
|
||||
"amount": 1999,
|
||||
"reference": "INV-1",
|
||||
"type": "CASH",
|
||||
},
|
||||
)
|
||||
|
||||
return httpx.Response(
|
||||
200,
|
||||
json={
|
||||
"page": 1,
|
||||
"pages": 1,
|
||||
"limit": 100,
|
||||
"total": 1,
|
||||
"items": [
|
||||
{
|
||||
"id": 88,
|
||||
"document_id": 10,
|
||||
"amount": 1999,
|
||||
"reference": "INV-1",
|
||||
"type": "CASH",
|
||||
}
|
||||
],
|
||||
},
|
||||
)
|
||||
|
||||
if request.url.path == "/customers":
|
||||
page = request.url.params.get("page", "1")
|
||||
if page == "1":
|
||||
return httpx.Response(
|
||||
200,
|
||||
json={
|
||||
"page": 1,
|
||||
"pages": 2,
|
||||
"limit": 1,
|
||||
"total": 2,
|
||||
"items": [{"id": 1, "company_name": "ACME GmbH"}],
|
||||
},
|
||||
)
|
||||
return httpx.Response(
|
||||
200,
|
||||
json={
|
||||
"page": 2,
|
||||
"pages": 2,
|
||||
"limit": 1,
|
||||
"total": 2,
|
||||
"items": [{"id": 2, "company_name": "Example AG"}],
|
||||
},
|
||||
)
|
||||
|
||||
if request.url.path == "/documents":
|
||||
if self.rate_limit_hits == 0:
|
||||
self.rate_limit_hits += 1
|
||||
return httpx.Response(429, headers={"Retry-After": "0"}, json={"error": "slow down"})
|
||||
|
||||
return httpx.Response(
|
||||
200,
|
||||
json={
|
||||
"page": 1,
|
||||
"pages": 1,
|
||||
"limit": 100,
|
||||
"total": 1,
|
||||
"items": [{"id": 10, "number": "RE-10", "amount": 1999}],
|
||||
},
|
||||
)
|
||||
|
||||
return httpx.Response(404, json={"error": "not found"})
|
||||
|
||||
|
||||
class AsyncWorkflowTransport(httpx.MockTransport):
|
||||
def __init__(self):
|
||||
super().__init__(self._handler)
|
||||
|
||||
@staticmethod
|
||||
def _handler(request: httpx.Request) -> httpx.Response:
|
||||
if request.url.path == "/positions":
|
||||
return httpx.Response(
|
||||
200,
|
||||
json={
|
||||
"page": 1,
|
||||
"pages": 1,
|
||||
"limit": 100,
|
||||
"total": 1,
|
||||
"items": [{"id": 7, "number": "ART-7", "description": "Hosting"}],
|
||||
},
|
||||
)
|
||||
return httpx.Response(404, json={"error": "not found"})
|
||||
|
||||
|
||||
def test_sync_workflow_helpers_cover_positions_payments_pagination_and_retry():
|
||||
transport = WorkflowTransport()
|
||||
client = EasybillClient(api_key="token", transport=transport, max_retries=1, retry_backoff=0)
|
||||
try:
|
||||
position = client.get_position(5)
|
||||
payments = client.list_document_payments(document_id=10)
|
||||
created_payment = client.create_document_payment(document_id=10, amount=1999, reference="INV-1")
|
||||
all_customers = list(client.iter_all_customers(limit=1))
|
||||
all_payments = list(client.iter_all_document_payments(document_id=10))
|
||||
documents = client.list_documents()
|
||||
finally:
|
||||
client.close()
|
||||
|
||||
assert position.id == 5
|
||||
assert position.price == 4900
|
||||
assert payments.items[0].reference == "INV-1"
|
||||
assert created_payment.id == 88
|
||||
assert [customer.id for customer in all_customers] == [1, 2]
|
||||
assert [payment.id for payment in all_payments] == [88]
|
||||
assert documents.items[0].number == "RE-10"
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_async_workflow_helpers_list_positions_as_models():
|
||||
client = AsyncEasybillClient(api_key="token", transport=AsyncWorkflowTransport())
|
||||
try:
|
||||
positions = await client.list_positions()
|
||||
iterated = [item async for item in client.iter_all_positions()]
|
||||
finally:
|
||||
await client.aclose()
|
||||
|
||||
assert positions.total == 1
|
||||
assert positions.items[0].number == "ART-7"
|
||||
assert iterated[0].id == 7
|
||||
Loading…
Add table
Add a link
Reference in a new issue