Skip to content

Commit 2965786

Browse files
authored
feat(dunning): Add payment requests endpoint (find_all) (#258)
* feat(dunning): Add payment requests endpoint (find_all) * Remove not used import
1 parent 5c37350 commit 2965786

File tree

5 files changed

+185
-0
lines changed

5 files changed

+185
-0
lines changed

lago_python_client/client.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
from .mrrs.clients import MrrClient
1515
from .organizations.clients import OrganizationClient
1616
from .overdue_balances.clients import OverdueBalanceClient
17+
from .payment_requests.clients import PaymentRequestClient
1718
from .invoice_collections.clients import InvoiceCollectionClient
1819
from .plans.clients import PlanClient
1920
from .subscriptions.clients import SubscriptionClient
@@ -96,6 +97,10 @@ def organizations(self) -> OrganizationClient:
9697
def overdue_balances(self) -> OverdueBalanceClient:
9798
return OverdueBalanceClient(self.base_api_url, self.api_key)
9899

100+
@callable_cached_property
101+
def payment_requests(self) -> PaymentRequestClient:
102+
return PaymentRequestClient(self.base_api_url, self.api_key)
103+
99104
@callable_cached_property
100105
def invoice_collections(self) -> InvoiceCollectionClient:
101106
return InvoiceCollectionClient(self.base_api_url, self.api_key)
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
from typing import List, Optional
2+
3+
from ..base_model import BaseModel, BaseResponseModel
4+
from .customer import CustomerResponse
5+
6+
class PaymentRequestInvoiceResponse(BaseResponseModel):
7+
lago_id: str
8+
sequential_id: Optional[int]
9+
number: str
10+
issuing_date: Optional[str]
11+
payment_dispute_lost_at: Optional[str]
12+
payment_due_date: Optional[str]
13+
payment_overdue: bool
14+
net_payment_term: int
15+
invoice_type: str
16+
version_number: int
17+
status: str
18+
payment_status: str
19+
currency: str
20+
fees_amount_cents: int
21+
coupons_amount_cents: int
22+
taxes_amount_cents: int
23+
credit_notes_amount_cents: int
24+
sub_total_excluding_taxes_amount_cents: int
25+
sub_total_including_taxes_amount_cents: int
26+
total_amount_cents: int
27+
prepaid_credit_amount_cents: int
28+
file_url: Optional[str]
29+
30+
31+
class PaymentRequestInvoicesResponse(BaseResponseModel):
32+
__root__: List[PaymentRequestInvoiceResponse]
33+
34+
35+
class PaymentRequestResponse(BaseResponseModel):
36+
lago_id: str
37+
email: str
38+
amount_cents: int
39+
amount_currency: str
40+
created_at: str
41+
customer: Optional[CustomerResponse]
42+
invoices: Optional[PaymentRequestInvoicesResponse]
43+
44+
45+
class PaymentRequestsResponse(BaseResponseModel):
46+
__root__: List[PaymentRequestResponse]
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import sys
2+
from typing import Any, ClassVar, Type, Union
3+
4+
from ..base_client import BaseClient
5+
from ..mixins import FindAllCommandMixin
6+
from ..models.payment_request import PaymentRequestResponse
7+
from ..services.request import make_headers, make_url, send_get_request
8+
from ..services.response import get_response_data, prepare_index_response, Response
9+
10+
if sys.version_info >= (3, 9):
11+
from collections.abc import Mapping
12+
else:
13+
from typing import Mapping
14+
15+
16+
class PaymentRequestClient(
17+
FindAllCommandMixin[PaymentRequestResponse],
18+
BaseClient,
19+
):
20+
API_RESOURCE: ClassVar[str] = 'payment_requests'
21+
RESPONSE_MODEL: ClassVar[Type[PaymentRequestResponse]] = PaymentRequestResponse
22+
ROOT_NAME: ClassVar[str] = 'payment_request'
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
{
2+
"payment_requests": [
3+
{
4+
"lago_id": "89b6b61e-4dbc-4307-ac96-4abcfa9e3e2d",
5+
"email": "gavin@overdue.test",
6+
"amount_cents": 120,
7+
"amount_currency": "EUR",
8+
"created_at": "2024-06-30T10:59:51Z",
9+
"customer": {
10+
"lago_id": "1a901a90-1a90-1a90-1a90-1a901a901a90",
11+
"external_id": "1a901a90-1a90-1a90-1a90-1a901a901a90",
12+
"address_line1": "5230 Penfield Ave",
13+
"address_line2": null,
14+
"city": "Woodland Hills",
15+
"country": "US",
16+
"created_at": "2022-04-29T08:59:51Z",
17+
"updated_at": "2022-04-29T08:59:51Z",
18+
"email": "dinesh@piedpiper.test",
19+
"legal_name": "Coleman-Blair",
20+
"legal_number": "49-008-2965",
21+
"logo_url": "http://hooli.com/logo.png",
22+
"name": "Gavin Belson",
23+
"phone": "1-171-883-3711 x245",
24+
"state": "CA",
25+
"url": "http://hooli.com",
26+
"zipcode": "91364",
27+
"currency": "EUR",
28+
"timezone": "Europe/Paris",
29+
"applicable_timezone": "Europe/Paris",
30+
"billing_configuration": {
31+
"payment_provider": "stripe",
32+
"payment_provider_code": "stripe-eu-1",
33+
"provider_customer_id": "cus_12345"
34+
},
35+
"metadata": []
36+
},
37+
"invoices": [
38+
{
39+
"lago_id": "1a901a90-1a90-1a90-1a90-1a901a901a90",
40+
"sequential_id": 15,
41+
"number": "LAG-1234-001-002",
42+
"issuing_date": "2022-06-02",
43+
"payment_dispute_lost_at": "2022-04-29T08:59:51Z",
44+
"payment_due_date": "2022-06-02",
45+
"payment_overdue": true,
46+
"invoice_type": "one_off",
47+
"version_number": 2,
48+
"status": "finalized",
49+
"payment_status": "pending",
50+
"currency": "EUR",
51+
"net_payment_term": 0,
52+
"fees_amount_cents": 100,
53+
"taxes_amount_cents": 20,
54+
"coupons_amount_cents": 0,
55+
"credit_notes_amount_cents": 0,
56+
"sub_total_excluding_taxes_amount_cents": 100,
57+
"sub_total_including_taxes_amount_cents": 120,
58+
"prepaid_credit_amount_cents": 0,
59+
"total_amount_cents": 120
60+
}
61+
]
62+
}
63+
],
64+
"meta": {
65+
"current_page": 1
66+
}
67+
}
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
import os
2+
3+
import pytest
4+
from pytest_httpx import HTTPXMock
5+
6+
from lago_python_client.client import Client
7+
from lago_python_client.exceptions import LagoApiError
8+
from lago_python_client.models.payment_request import PaymentRequestResponse
9+
10+
11+
def mock_collection_response():
12+
current_dir = os.path.dirname(os.path.abspath(__file__))
13+
data_path = os.path.join(current_dir, 'fixtures/payment_request_index.json')
14+
15+
with open(data_path, 'rb') as payment_requests_response:
16+
return payment_requests_response.read()
17+
18+
19+
def test_valid_find_all_payment_requests_request(httpx_mock: HTTPXMock):
20+
client = Client(api_key='886fe239-927d-4072-ab72-6dd345e8dd0d')
21+
22+
httpx_mock.add_response(method='GET', url='https://api.getlago.com/api/v1/payment_requests', content=mock_collection_response())
23+
response = client.payment_requests.find_all()
24+
25+
assert response['payment_requests'][0].lago_id == '89b6b61e-4dbc-4307-ac96-4abcfa9e3e2d'
26+
assert response['meta']['current_page'] == 1
27+
28+
29+
def test_valid_find_all_payment_requests_request_with_options(httpx_mock: HTTPXMock):
30+
client = Client(api_key='886fe239-927d-4072-ab72-6dd345e8dd0d')
31+
32+
httpx_mock.add_response(method='GET', url='https://api.getlago.com/api/v1/payment_requests?per_page=2&page=1', content=mock_collection_response())
33+
response = client.payment_requests.find_all({'per_page': 2, 'page': 1})
34+
35+
assert response['payment_requests'][0].lago_id == '89b6b61e-4dbc-4307-ac96-4abcfa9e3e2d'
36+
assert response['meta']['current_page'] == 1
37+
38+
39+
def test_invalid_find_all_payment_requests_request(httpx_mock: HTTPXMock):
40+
client = Client(api_key='invalid')
41+
42+
httpx_mock.add_response(method='GET', url='https://api.getlago.com/api/v1/payment_requests', status_code=404, content=b'')
43+
44+
with pytest.raises(LagoApiError):
45+
client.payment_requests.find_all()

0 commit comments

Comments
 (0)