diff --git a/lago_python_client/models/__init__.py b/lago_python_client/models/__init__.py index 2369a87..55a1c73 100644 --- a/lago_python_client/models/__init__.py +++ b/lago_python_client/models/__init__.py @@ -82,3 +82,4 @@ UsageThresholds as UsageThresholds, UsageThresholdsResponse as UsageThresholdsResponse, ) +from .payment_request import PaymentRequest as PaymentRequest diff --git a/lago_python_client/models/payment_request.py b/lago_python_client/models/payment_request.py index e79198f..1273154 100644 --- a/lago_python_client/models/payment_request.py +++ b/lago_python_client/models/payment_request.py @@ -1,9 +1,15 @@ from typing import List, Optional -from ..base_model import BaseResponseModel +from ..base_model import BaseModel, BaseResponseModel from .customer import CustomerResponse +class PaymentRequest(BaseModel): + email: str + external_customer_id: str + lago_invoice_ids: List[str] + + class PaymentRequestInvoiceResponse(BaseResponseModel): lago_id: str sequential_id: Optional[int] @@ -38,6 +44,7 @@ class PaymentRequestResponse(BaseResponseModel): email: str amount_cents: int amount_currency: str + payment_status: str created_at: str customer: Optional[CustomerResponse] invoices: Optional[PaymentRequestInvoicesResponse] diff --git a/lago_python_client/payment_requests/clients.py b/lago_python_client/payment_requests/clients.py index cb8bf77..9be9202 100644 --- a/lago_python_client/payment_requests/clients.py +++ b/lago_python_client/payment_requests/clients.py @@ -1,11 +1,12 @@ from typing import ClassVar, Type from ..base_client import BaseClient -from ..mixins import FindAllCommandMixin +from ..mixins import CreateCommandMixin, FindAllCommandMixin from ..models.payment_request import PaymentRequestResponse class PaymentRequestClient( + CreateCommandMixin[PaymentRequestResponse], FindAllCommandMixin[PaymentRequestResponse], BaseClient, ): diff --git a/tests/fixtures/payment_request.json b/tests/fixtures/payment_request.json new file mode 100644 index 0000000..5a2ec63 --- /dev/null +++ b/tests/fixtures/payment_request.json @@ -0,0 +1,115 @@ +{ + "payment_request": { + "lago_id": "89b6b61e-4dbc-4307-ac96-4abcfa9e3e2d", + "email": "gavin@overdue.test", + "amount_cents": 19955, + "amount_currency": "EUR", + "payment_status": "pending", + "created_at": "2024-06-30T10:59:51Z", + "customer": { + "lago_id": "1a901a90-1a90-1a90-1a90-1a901a901a90", + "external_id": "gavin_001", + "address_line1": "5230 Penfield Ave", + "address_line2": "fzufuzfuz", + "city": "Woodland Hills", + "country": "US", + "created_at": "2022-04-29T08:59:51Z", + "updated_at": "2022-04-29T08:59:51Z", + "email": "dinesh@piedpiper.test", + "legal_name": "Coleman-Blair", + "legal_number": "49-008-2965", + "logo_url": "http://hooli.com/logo.png", + "name": "Gavin Belson", + "phone": "1-171-883-3711 x245", + "state": "CA", + "url": "http://hooli.com", + "zipcode": "91364", + "currency": "EUR", + "timezone": "Europe/Paris", + "applicable_timezone": "Europe/Paris", + "net_payment_term": 30, + "tax_identification_number": "EU123456789", + "sequential_id": 101, + "slug": "customer_101_slug", + "external_salesforce_id": "salesforce_999", + "finalize_zero_amount_invoice": "skip", + "billing_configuration": { + "invoice_grace_period": 3, + "payment_provider": "stripe", + "payment_provider_code": "stripe-eu-1", + "provider_customer_id": "cus_12345", + "sync_with_provider": true, + "document_locale": "fr", + "provider_payment_methods": ["card"] + }, + "shipping_address": { + "address_line1": "5230 Penfield Ave", + "city": "Woodland Hills", + "zipcode": "91364", + "state": "CA", + "country": "US" + }, + "metadata": [ + { + "lago_id": "7317916c-b64b-45df-8bfd-2fc80ed1679d", + "key": "lead_name", + "value": "John Doe", + "display_in_invoice": true, + "created_at": "2022-04-29T08:59:51Z" + } + ] + }, + "invoices": [ + { + "lago_id": "f8e194df-5d90-4382-b146-c881d2c67f28", + "sequential_id": 15, + "number": "LAG-1234-001-002", + "issuing_date": "2022-06-02", + "payment_dispute_lost_at": "2022-04-29T08:59:51Z", + "payment_due_date": "2022-06-02", + "payment_overdue": true, + "invoice_type": "one_off", + "version_number": 2, + "status": "finalized", + "payment_status": "pending", + "currency": "EUR", + "net_payment_term": 0, + "fees_amount_cents": 10000, + "taxes_amount_cents": 2000, + "coupons_amount_cents": 0, + "credit_notes_amount_cents": 0, + "sub_total_excluding_taxes_amount_cents": 10000, + "sub_total_including_taxes_amount_cents": 12000, + "prepaid_credit_amount_cents": 0, + "total_amount_cents": 12000, + "progressive_billing_credit_amount_cents": 0, + "file_url": "https://lago-files/invoice_002.pdf" + }, + { + "lago_id": "a20b1805-d54c-4e57-873d-721cc153035e", + "sequential_id": 22, + "number": "LAG-1234-009-012", + "issuing_date": "2022-07-08", + "payment_dispute_lost_at": null, + "payment_due_date": "2022-07-08", + "payment_overdue": true, + "invoice_type": "one_off", + "version_number": 3, + "status": "finalized", + "payment_status": "failed", + "currency": "EUR", + "net_payment_term": 0, + "fees_amount_cents": 7000, + "taxes_amount_cents": 955, + "coupons_amount_cents": 0, + "credit_notes_amount_cents": 0, + "sub_total_excluding_taxes_amount_cents": 7000, + "sub_total_including_taxes_amount_cents": 7955, + "prepaid_credit_amount_cents": 0, + "total_amount_cents": 7955, + "progressive_billing_credit_amount_cents": 0, + "file_url": "https://lago-files/invoice_012.pdf" + } + ] + } +} diff --git a/tests/fixtures/payment_request_index.json b/tests/fixtures/payment_request_index.json index 1cdab53..6abaebd 100644 --- a/tests/fixtures/payment_request_index.json +++ b/tests/fixtures/payment_request_index.json @@ -5,6 +5,7 @@ "email": "gavin@overdue.test", "amount_cents": 120, "amount_currency": "EUR", + "payment_status": "pending", "created_at": "2024-06-30T10:59:51Z", "customer": { "lago_id": "1a901a90-1a90-1a90-1a90-1a901a901a90", diff --git a/tests/test_payment_request_client.py b/tests/test_payment_request_client.py index 55749cb..46ec1af 100644 --- a/tests/test_payment_request_client.py +++ b/tests/test_payment_request_client.py @@ -5,6 +5,23 @@ from lago_python_client.client import Client from lago_python_client.exceptions import LagoApiError +from lago_python_client.models import PaymentRequest + + +def payment_request_object(): + return PaymentRequest( + email="gavin@overdue.test", + external_customer_id="gavin_001", + lago_invoice_ids=["f8e194df-5d90-4382-b146-c881d2c67f28", "a20b1805-d54c-4e57-873d-721cc153035e"], + ) + + +def mock_response(): + this_dir = os.path.dirname(os.path.abspath(__file__)) + data_path = os.path.join(this_dir, "fixtures/payment_request.json") + + with open(data_path, "rb") as payment_request_response: + return payment_request_response.read() def mock_collection_response(): @@ -55,3 +72,38 @@ def test_invalid_find_all_payment_requests_request(httpx_mock: HTTPXMock): with pytest.raises(LagoApiError): client.payment_requests.find_all() + + +def test_valid_create_payment_request_request(httpx_mock: HTTPXMock): + client = Client(api_key="886fe239-927d-4072-ab72-6dd345e8dd0d") + + httpx_mock.add_response( + method="POST", + url="https://api.getlago.com/api/v1/payment_requests", + content=mock_response(), + ) + response = client.payment_requests.create(payment_request_object()) + + assert response.lago_id == "89b6b61e-4dbc-4307-ac96-4abcfa9e3e2d" + assert response.email == "gavin@overdue.test" + assert response.amount_cents == 19955 + assert response.amount_currency == "EUR" + assert response.payment_status == "pending" + assert response.customer.lago_id == "1a901a90-1a90-1a90-1a90-1a901a901a90" + assert len(response.invoices.__root__) == 2 + assert response.invoices.__root__[0].lago_id == "f8e194df-5d90-4382-b146-c881d2c67f28" + assert response.invoices.__root__[1].lago_id == "a20b1805-d54c-4e57-873d-721cc153035e" + + +def test_invalid_create_payment_request_request(httpx_mock: HTTPXMock): + client = Client(api_key="invalid") + + httpx_mock.add_response( + method="POST", + url="https://api.getlago.com/api/v1/payment_requests", + status_code=401, + content=b"", + ) + + with pytest.raises(LagoApiError): + client.payment_requests.create(payment_request_object())