lago-python-client 1.10.0__tar.gz → 1.11.0__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.
Files changed (127) hide show
  1. {lago-python-client-1.10.0 → lago-python-client-1.11.0}/PKG-INFO +1 -1
  2. {lago-python-client-1.10.0 → lago-python-client-1.11.0}/lago_python_client/base_client.py +2 -1
  3. {lago-python-client-1.10.0 → lago-python-client-1.11.0}/lago_python_client/client.py +19 -2
  4. {lago-python-client-1.10.0 → lago-python-client-1.11.0}/lago_python_client/events/clients.py +31 -3
  5. {lago-python-client-1.10.0 → lago-python-client-1.11.0}/lago_python_client/exceptions.py +2 -1
  6. {lago-python-client-1.10.0 → lago-python-client-1.11.0}/lago_python_client/models/__init__.py +2 -0
  7. {lago-python-client-1.10.0 → lago-python-client-1.11.0}/lago_python_client/models/customer.py +2 -0
  8. {lago-python-client-1.10.0 → lago-python-client-1.11.0}/lago_python_client/models/fee.py +3 -0
  9. lago-python-client-1.11.0/lago_python_client/models/lifetime_usage.py +21 -0
  10. {lago-python-client-1.10.0 → lago-python-client-1.11.0}/lago_python_client/models/organization.py +2 -0
  11. {lago-python-client-1.10.0 → lago-python-client-1.11.0}/lago_python_client/models/payment_request.py +8 -1
  12. {lago-python-client-1.10.0 → lago-python-client-1.11.0}/lago_python_client/payment_requests/clients.py +2 -1
  13. lago-python-client-1.11.0/lago_python_client/subscriptions/clients.py +70 -0
  14. lago-python-client-1.11.0/lago_python_client/version.py +1 -0
  15. {lago-python-client-1.10.0 → lago-python-client-1.11.0}/lago_python_client.egg-info/PKG-INFO +1 -1
  16. {lago-python-client-1.10.0 → lago-python-client-1.11.0}/lago_python_client.egg-info/SOURCES.txt +1 -0
  17. {lago-python-client-1.10.0 → lago-python-client-1.11.0}/tests/test_event_client.py +22 -3
  18. lago-python-client-1.11.0/tests/test_payment_request_client.py +109 -0
  19. {lago-python-client-1.10.0 → lago-python-client-1.11.0}/tests/test_subscription_client.py +64 -0
  20. lago-python-client-1.10.0/lago_python_client/subscriptions/clients.py +0 -24
  21. lago-python-client-1.10.0/lago_python_client/version.py +0 -1
  22. lago-python-client-1.10.0/tests/test_payment_request_client.py +0 -57
  23. {lago-python-client-1.10.0 → lago-python-client-1.11.0}/LICENSE +0 -0
  24. {lago-python-client-1.10.0 → lago-python-client-1.11.0}/README.md +0 -0
  25. {lago-python-client-1.10.0 → lago-python-client-1.11.0}/lago_python_client/__init__.py +0 -0
  26. {lago-python-client-1.10.0 → lago-python-client-1.11.0}/lago_python_client/add_ons/__init__.py +0 -0
  27. {lago-python-client-1.10.0 → lago-python-client-1.11.0}/lago_python_client/add_ons/clients.py +0 -0
  28. {lago-python-client-1.10.0 → lago-python-client-1.11.0}/lago_python_client/base_model.py +0 -0
  29. {lago-python-client-1.10.0 → lago-python-client-1.11.0}/lago_python_client/billable_metrics/__init__.py +0 -0
  30. {lago-python-client-1.10.0 → lago-python-client-1.11.0}/lago_python_client/billable_metrics/clients.py +0 -0
  31. {lago-python-client-1.10.0 → lago-python-client-1.11.0}/lago_python_client/coupons/__init__.py +0 -0
  32. {lago-python-client-1.10.0 → lago-python-client-1.11.0}/lago_python_client/coupons/clients.py +0 -0
  33. {lago-python-client-1.10.0 → lago-python-client-1.11.0}/lago_python_client/credit_notes/__init__.py +0 -0
  34. {lago-python-client-1.10.0 → lago-python-client-1.11.0}/lago_python_client/credit_notes/clients.py +0 -0
  35. {lago-python-client-1.10.0 → lago-python-client-1.11.0}/lago_python_client/customers/__init__.py +0 -0
  36. {lago-python-client-1.10.0 → lago-python-client-1.11.0}/lago_python_client/customers/clients.py +0 -0
  37. {lago-python-client-1.10.0 → lago-python-client-1.11.0}/lago_python_client/events/__init__.py +0 -0
  38. {lago-python-client-1.10.0 → lago-python-client-1.11.0}/lago_python_client/fees/__init__.py +0 -0
  39. {lago-python-client-1.10.0 → lago-python-client-1.11.0}/lago_python_client/fees/clients.py +0 -0
  40. {lago-python-client-1.10.0 → lago-python-client-1.11.0}/lago_python_client/functools_ext.py +0 -0
  41. {lago-python-client-1.10.0 → lago-python-client-1.11.0}/lago_python_client/gross_revenues/__init__.py +0 -0
  42. {lago-python-client-1.10.0 → lago-python-client-1.11.0}/lago_python_client/gross_revenues/clients.py +0 -0
  43. {lago-python-client-1.10.0 → lago-python-client-1.11.0}/lago_python_client/invoice_collections/__init__.py +0 -0
  44. {lago-python-client-1.10.0 → lago-python-client-1.11.0}/lago_python_client/invoice_collections/clients.py +0 -0
  45. {lago-python-client-1.10.0 → lago-python-client-1.11.0}/lago_python_client/invoiced_usages/__init__.py +0 -0
  46. {lago-python-client-1.10.0 → lago-python-client-1.11.0}/lago_python_client/invoiced_usages/clients.py +0 -0
  47. {lago-python-client-1.10.0 → lago-python-client-1.11.0}/lago_python_client/invoices/__init__.py +0 -0
  48. {lago-python-client-1.10.0 → lago-python-client-1.11.0}/lago_python_client/invoices/clients.py +0 -0
  49. {lago-python-client-1.10.0 → lago-python-client-1.11.0}/lago_python_client/mixins.py +0 -0
  50. {lago-python-client-1.10.0 → lago-python-client-1.11.0}/lago_python_client/models/add_on.py +0 -0
  51. {lago-python-client-1.10.0 → lago-python-client-1.11.0}/lago_python_client/models/applied_coupon.py +0 -0
  52. {lago-python-client-1.10.0 → lago-python-client-1.11.0}/lago_python_client/models/billable_metric.py +0 -0
  53. {lago-python-client-1.10.0 → lago-python-client-1.11.0}/lago_python_client/models/charge.py +0 -0
  54. {lago-python-client-1.10.0 → lago-python-client-1.11.0}/lago_python_client/models/coupon.py +0 -0
  55. {lago-python-client-1.10.0 → lago-python-client-1.11.0}/lago_python_client/models/credit.py +0 -0
  56. {lago-python-client-1.10.0 → lago-python-client-1.11.0}/lago_python_client/models/credit_note.py +0 -0
  57. {lago-python-client-1.10.0 → lago-python-client-1.11.0}/lago_python_client/models/customer_usage.py +0 -0
  58. {lago-python-client-1.10.0 → lago-python-client-1.11.0}/lago_python_client/models/event.py +0 -0
  59. {lago-python-client-1.10.0 → lago-python-client-1.11.0}/lago_python_client/models/gross_revenue.py +0 -0
  60. {lago-python-client-1.10.0 → lago-python-client-1.11.0}/lago_python_client/models/invoice.py +0 -0
  61. {lago-python-client-1.10.0 → lago-python-client-1.11.0}/lago_python_client/models/invoice_collection.py +0 -0
  62. {lago-python-client-1.10.0 → lago-python-client-1.11.0}/lago_python_client/models/invoice_item.py +0 -0
  63. {lago-python-client-1.10.0 → lago-python-client-1.11.0}/lago_python_client/models/invoiced_usage.py +0 -0
  64. {lago-python-client-1.10.0 → lago-python-client-1.11.0}/lago_python_client/models/minimum_commitment.py +0 -0
  65. {lago-python-client-1.10.0 → lago-python-client-1.11.0}/lago_python_client/models/mrr.py +0 -0
  66. {lago-python-client-1.10.0 → lago-python-client-1.11.0}/lago_python_client/models/overdue_balance.py +0 -0
  67. {lago-python-client-1.10.0 → lago-python-client-1.11.0}/lago_python_client/models/plan.py +0 -0
  68. {lago-python-client-1.10.0 → lago-python-client-1.11.0}/lago_python_client/models/subscription.py +0 -0
  69. {lago-python-client-1.10.0 → lago-python-client-1.11.0}/lago_python_client/models/tax.py +0 -0
  70. {lago-python-client-1.10.0 → lago-python-client-1.11.0}/lago_python_client/models/usage_threshold.py +0 -0
  71. {lago-python-client-1.10.0 → lago-python-client-1.11.0}/lago_python_client/models/wallet.py +0 -0
  72. {lago-python-client-1.10.0 → lago-python-client-1.11.0}/lago_python_client/models/wallet_transaction.py +0 -0
  73. {lago-python-client-1.10.0 → lago-python-client-1.11.0}/lago_python_client/models/webhook_endpoint.py +0 -0
  74. {lago-python-client-1.10.0 → lago-python-client-1.11.0}/lago_python_client/mrrs/__init__.py +0 -0
  75. {lago-python-client-1.10.0 → lago-python-client-1.11.0}/lago_python_client/mrrs/clients.py +0 -0
  76. {lago-python-client-1.10.0 → lago-python-client-1.11.0}/lago_python_client/organizations/__init__.py +0 -0
  77. {lago-python-client-1.10.0 → lago-python-client-1.11.0}/lago_python_client/organizations/clients.py +0 -0
  78. {lago-python-client-1.10.0 → lago-python-client-1.11.0}/lago_python_client/overdue_balances/__init__.py +0 -0
  79. {lago-python-client-1.10.0 → lago-python-client-1.11.0}/lago_python_client/overdue_balances/clients.py +0 -0
  80. {lago-python-client-1.10.0 → lago-python-client-1.11.0}/lago_python_client/payment_requests/__init__.py +0 -0
  81. {lago-python-client-1.10.0 → lago-python-client-1.11.0}/lago_python_client/plans/__init__.py +0 -0
  82. {lago-python-client-1.10.0 → lago-python-client-1.11.0}/lago_python_client/plans/clients.py +0 -0
  83. {lago-python-client-1.10.0 → lago-python-client-1.11.0}/lago_python_client/py.typed +0 -0
  84. {lago-python-client-1.10.0 → lago-python-client-1.11.0}/lago_python_client/services/__init__.py +0 -0
  85. {lago-python-client-1.10.0 → lago-python-client-1.11.0}/lago_python_client/services/json.py +0 -0
  86. {lago-python-client-1.10.0 → lago-python-client-1.11.0}/lago_python_client/services/request.py +0 -0
  87. {lago-python-client-1.10.0 → lago-python-client-1.11.0}/lago_python_client/services/response.py +0 -0
  88. {lago-python-client-1.10.0 → lago-python-client-1.11.0}/lago_python_client/subscriptions/__init__.py +0 -0
  89. {lago-python-client-1.10.0 → lago-python-client-1.11.0}/lago_python_client/taxes/__init__.py +0 -0
  90. {lago-python-client-1.10.0 → lago-python-client-1.11.0}/lago_python_client/taxes/clients.py +0 -0
  91. {lago-python-client-1.10.0 → lago-python-client-1.11.0}/lago_python_client/wallets/__init__.py +0 -0
  92. {lago-python-client-1.10.0 → lago-python-client-1.11.0}/lago_python_client/wallets/clients.py +0 -0
  93. {lago-python-client-1.10.0 → lago-python-client-1.11.0}/lago_python_client/webhook_endpoints/__init__.py +0 -0
  94. {lago-python-client-1.10.0 → lago-python-client-1.11.0}/lago_python_client/webhook_endpoints/clients.py +0 -0
  95. {lago-python-client-1.10.0 → lago-python-client-1.11.0}/lago_python_client/webhooks/__init__.py +0 -0
  96. {lago-python-client-1.10.0 → lago-python-client-1.11.0}/lago_python_client/webhooks/clients.py +0 -0
  97. {lago-python-client-1.10.0 → lago-python-client-1.11.0}/lago_python_client.egg-info/dependency_links.txt +0 -0
  98. {lago-python-client-1.10.0 → lago-python-client-1.11.0}/lago_python_client.egg-info/requires.txt +0 -0
  99. {lago-python-client-1.10.0 → lago-python-client-1.11.0}/lago_python_client.egg-info/top_level.txt +0 -0
  100. {lago-python-client-1.10.0 → lago-python-client-1.11.0}/pyproject.toml +0 -0
  101. {lago-python-client-1.10.0 → lago-python-client-1.11.0}/setup.cfg +0 -0
  102. {lago-python-client-1.10.0 → lago-python-client-1.11.0}/tests/__init__.py +0 -0
  103. {lago-python-client-1.10.0 → lago-python-client-1.11.0}/tests/test_add_on_client.py +0 -0
  104. {lago-python-client-1.10.0 → lago-python-client-1.11.0}/tests/test_applied_coupon_client.py +0 -0
  105. {lago-python-client-1.10.0 → lago-python-client-1.11.0}/tests/test_billable_metric_client.py +0 -0
  106. {lago-python-client-1.10.0 → lago-python-client-1.11.0}/tests/test_client.py +0 -0
  107. {lago-python-client-1.10.0 → lago-python-client-1.11.0}/tests/test_coupon_client.py +0 -0
  108. {lago-python-client-1.10.0 → lago-python-client-1.11.0}/tests/test_credit_note_client.py +0 -0
  109. {lago-python-client-1.10.0 → lago-python-client-1.11.0}/tests/test_customer_client.py +0 -0
  110. {lago-python-client-1.10.0 → lago-python-client-1.11.0}/tests/test_fee_client.py +0 -0
  111. {lago-python-client-1.10.0 → lago-python-client-1.11.0}/tests/test_functools_ext.py +0 -0
  112. {lago-python-client-1.10.0 → lago-python-client-1.11.0}/tests/test_gross_revenue_client.py +0 -0
  113. {lago-python-client-1.10.0 → lago-python-client-1.11.0}/tests/test_invoice_client.py +0 -0
  114. {lago-python-client-1.10.0 → lago-python-client-1.11.0}/tests/test_invoice_collection_client.py +0 -0
  115. {lago-python-client-1.10.0 → lago-python-client-1.11.0}/tests/test_invoiced_usage_client.py +0 -0
  116. {lago-python-client-1.10.0 → lago-python-client-1.11.0}/tests/test_json_services.py +0 -0
  117. {lago-python-client-1.10.0 → lago-python-client-1.11.0}/tests/test_mrr_client.py +0 -0
  118. {lago-python-client-1.10.0 → lago-python-client-1.11.0}/tests/test_organization_client.py +0 -0
  119. {lago-python-client-1.10.0 → lago-python-client-1.11.0}/tests/test_overdue_balance_client.py +0 -0
  120. {lago-python-client-1.10.0 → lago-python-client-1.11.0}/tests/test_plan_client.py +0 -0
  121. {lago-python-client-1.10.0 → lago-python-client-1.11.0}/tests/test_request_services.py +0 -0
  122. {lago-python-client-1.10.0 → lago-python-client-1.11.0}/tests/test_response_services.py +0 -0
  123. {lago-python-client-1.10.0 → lago-python-client-1.11.0}/tests/test_tax_client.py +0 -0
  124. {lago-python-client-1.10.0 → lago-python-client-1.11.0}/tests/test_wallet_client.py +0 -0
  125. {lago-python-client-1.10.0 → lago-python-client-1.11.0}/tests/test_wallet_transaction_client.py +0 -0
  126. {lago-python-client-1.10.0 → lago-python-client-1.11.0}/tests/test_webhook_client.py +0 -0
  127. {lago-python-client-1.10.0 → lago-python-client-1.11.0}/tests/test_webhook_endpoint_client.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: lago-python-client
3
- Version: 1.10.0
3
+ Version: 1.11.0
4
4
  Summary: Lago Python API Client
5
5
  Home-page: https://github.com/getlago/lago-python-client
6
6
  Author: Lovro Colic
@@ -7,9 +7,10 @@ from lago_python_client.base_model import BaseModel
7
7
  class BaseClient(ABC):
8
8
  """The base class used for each collection client."""
9
9
 
10
- def __init__(self, base_url: str, api_key: str):
10
+ def __init__(self, base_url: str, api_key: str, base_ingest_url: str = ""):
11
11
  self.base_url = base_url
12
12
  self.api_key = api_key
13
+ self.base_ingest_url = base_ingest_url
13
14
 
14
15
  @property
15
16
  @classmethod
@@ -31,16 +31,33 @@ except ImportError: # Python 3.7
31
31
 
32
32
  class Client:
33
33
  BASE_URL: Final[str] = "https://api.getlago.com/"
34
+ BASE_INGEST_URL: Final[str] = "https://ingest.getlago.com/"
34
35
  API_PATH: Final[str] = "api/v1/"
35
36
 
36
- def __init__(self, api_key: str = "", api_url: str = "") -> None:
37
+ def __init__(
38
+ self, api_key: str = "", api_url: str = "", use_ingest_service: bool = False, ingest_api_url: str = ""
39
+ ) -> None:
37
40
  self.api_key: str = api_key
38
41
  self.api_url: str = api_url
42
+ self.use_ingest_service: bool = use_ingest_service
43
+ self.ingest_api_url: str = ingest_api_url
39
44
 
40
45
  @property
41
46
  def base_api_url(self) -> str:
42
47
  return urljoin(self.api_url if self.api_url else Client.BASE_URL, Client.API_PATH)
43
48
 
49
+ @property
50
+ def base_ingest_api_url(self) -> str:
51
+ if not self.use_ingest_service:
52
+ return self.base_api_url
53
+
54
+ if self.ingest_api_url == "":
55
+ ingest_url = Client.BASE_INGEST_URL
56
+ else:
57
+ ingest_url = self.ingest_api_url
58
+
59
+ return urljoin(ingest_url, Client.API_PATH)
60
+
44
61
  @callable_cached_property
45
62
  def add_ons(self) -> AddOnClient:
46
63
  return AddOnClient(self.base_api_url, self.api_key)
@@ -67,7 +84,7 @@ class Client:
67
84
 
68
85
  @callable_cached_property
69
86
  def events(self) -> EventClient:
70
- return EventClient(self.base_api_url, self.api_key)
87
+ return EventClient(self.base_api_url, self.api_key, self.base_ingest_api_url)
71
88
 
72
89
  @callable_cached_property
73
90
  def fees(self) -> FeeClient:
@@ -1,17 +1,20 @@
1
1
  import sys
2
- from typing import Any, ClassVar, Type
2
+ from typing import Any, ClassVar, Optional, Type
3
+
4
+ import httpx
3
5
 
4
6
  from lago_python_client.base_model import BaseModel
5
7
 
6
8
  from ..base_client import BaseClient
7
9
  from ..fees.clients import FeeClient
8
- from ..mixins import CreateCommandMixin, FindCommandMixin
10
+ from ..mixins import FindCommandMixin
9
11
  from ..models.event import EventResponse
10
12
  from ..models.fee import FeeResponse
11
13
  from ..services.json import to_json
12
14
  from ..services.request import make_headers, make_url, send_post_request
13
15
  from ..services.response import (
14
16
  get_response_data,
17
+ prepare_object_response,
15
18
  prepare_object_list_response,
16
19
  verify_response,
17
20
  Response,
@@ -23,11 +26,36 @@ else:
23
26
  from typing import Mapping
24
27
 
25
28
 
26
- class EventClient(CreateCommandMixin[EventResponse], FindCommandMixin[EventResponse], BaseClient):
29
+ class EventClient(FindCommandMixin[EventResponse], BaseClient):
27
30
  API_RESOURCE: ClassVar[str] = "events"
28
31
  RESPONSE_MODEL: ClassVar[Type[EventResponse]] = EventResponse
29
32
  ROOT_NAME: ClassVar[str] = "event"
30
33
 
34
+ def create(self, input_object: BaseModel, timeout: Optional[httpx.Timeout] = None) -> Optional[EventResponse]:
35
+ api_response: Response = send_post_request(
36
+ url=make_url(
37
+ origin=self.base_ingest_url,
38
+ path_parts=(self.API_RESOURCE,),
39
+ ),
40
+ content=to_json(
41
+ {
42
+ self.ROOT_NAME: input_object.dict(),
43
+ }
44
+ ),
45
+ headers=make_headers(api_key=self.api_key),
46
+ timeout=timeout,
47
+ )
48
+
49
+ # Process response data
50
+ response_data = get_response_data(response=api_response, key=self.ROOT_NAME)
51
+ if not response_data:
52
+ return None
53
+
54
+ return prepare_object_response(
55
+ response_model=self.RESPONSE_MODEL,
56
+ data=response_data,
57
+ )
58
+
31
59
  def batch_create(self, input_object: BaseModel) -> None:
32
60
  api_response: Response = send_post_request(
33
61
  url=make_url(
@@ -24,7 +24,8 @@ class LagoApiError(Exception):
24
24
  self.response = response
25
25
  self.detail = detail
26
26
  self.headers = headers
27
+ super().__init__(self.response)
27
28
 
28
29
  def __repr__(self) -> str:
29
30
  class_name = self.__class__.__name__
30
- return f"{class_name}(status_code={self.status_code!r}, detail={self.detail!r})"
31
+ return f"{class_name}(response={self.response!r}"
@@ -82,3 +82,5 @@ from .usage_threshold import (
82
82
  UsageThresholds as UsageThresholds,
83
83
  UsageThresholdsResponse as UsageThresholdsResponse,
84
84
  )
85
+ from .payment_request import PaymentRequest as PaymentRequest
86
+ from .lifetime_usage import LifetimeUsageResponse as LifetimeUsageResponse
@@ -95,6 +95,7 @@ class Customer(BaseModel):
95
95
  url: Optional[str]
96
96
  zipcode: Optional[str]
97
97
  metadata: Optional[MetadataList]
98
+ finalize_zero_amount_invoice: Optional[str]
98
99
  billing_configuration: Optional[CustomerBillingConfiguration]
99
100
  shipping_address: Optional[Address]
100
101
  integration_customers: Optional[IntegrationCustomersList]
@@ -125,6 +126,7 @@ class CustomerResponse(BaseResponseModel):
125
126
  url: Optional[str]
126
127
  zipcode: Optional[str]
127
128
  metadata: Optional[MetadataResponseList]
129
+ finalize_zero_amount_invoice: Optional[str]
128
130
  billing_configuration: Optional[CustomerBillingConfiguration]
129
131
  shipping_address: Optional[Address]
130
132
  integration_customers: Optional[IntegrationCustomersResponseList]
@@ -40,6 +40,9 @@ class FeeResponse(BaseResponseModel):
40
40
  total_amount_cents: Optional[int]
41
41
  unit_amount_cents: Optional[int] # deprecated
42
42
  precise_unit_amount: Optional[str]
43
+ precise_amount: Optional[str]
44
+ precise_total_amount: Optional[str]
45
+ taxes_precise_amount: Optional[str]
43
46
  total_amount_currency: Optional[str]
44
47
  units: Optional[float]
45
48
  events_count: Optional[int]
@@ -0,0 +1,21 @@
1
+ from typing import Optional, List
2
+
3
+ from ..base_model import BaseResponseModel
4
+
5
+
6
+ class LifetimeUsageThresholdResponse(BaseResponseModel):
7
+ amount_cents: int
8
+ completion_ratio: float
9
+ reached_at: Optional[str]
10
+
11
+
12
+ class LifetimeUsageResponse(BaseResponseModel):
13
+ lago_id: str
14
+ lago_subscription_id: str
15
+ external_subscription_id: str
16
+ external_historical_usage_amount_cents: int
17
+ invoiced_usage_amount_cents: int
18
+ current_usage_amount_cents: int
19
+ from_datetime: Optional[str]
20
+ to_datetime: Optional[str]
21
+ usage_thresholds: Optional[List[LifetimeUsageThresholdResponse]]
@@ -30,6 +30,7 @@ class Organization(BaseModel):
30
30
  tax_identification_number: Optional[str]
31
31
  timezone: Optional[str]
32
32
  email_settings: Optional[List[str]]
33
+ finalize_zero_amount_invoice: Optional[bool]
33
34
  billing_configuration: Optional[OrganizationBillingConfiguration]
34
35
 
35
36
 
@@ -53,4 +54,5 @@ class OrganizationResponse(BaseResponseModel):
53
54
  tax_identification_number: Optional[str]
54
55
  timezone: Optional[str]
55
56
  email_settings: Optional[List[str]]
57
+ finalize_zero_amount_invoice: Optional[bool]
56
58
  billing_configuration: Optional[OrganizationBillingConfiguration]
@@ -1,9 +1,15 @@
1
1
  from typing import List, Optional
2
2
 
3
- from ..base_model import BaseResponseModel
3
+ from ..base_model import BaseModel, BaseResponseModel
4
4
  from .customer import CustomerResponse
5
5
 
6
6
 
7
+ class PaymentRequest(BaseModel):
8
+ email: str
9
+ external_customer_id: str
10
+ lago_invoice_ids: List[str]
11
+
12
+
7
13
  class PaymentRequestInvoiceResponse(BaseResponseModel):
8
14
  lago_id: str
9
15
  sequential_id: Optional[int]
@@ -38,6 +44,7 @@ class PaymentRequestResponse(BaseResponseModel):
38
44
  email: str
39
45
  amount_cents: int
40
46
  amount_currency: str
47
+ payment_status: str
41
48
  created_at: str
42
49
  customer: Optional[CustomerResponse]
43
50
  invoices: Optional[PaymentRequestInvoicesResponse]
@@ -1,11 +1,12 @@
1
1
  from typing import ClassVar, Type
2
2
 
3
3
  from ..base_client import BaseClient
4
- from ..mixins import FindAllCommandMixin
4
+ from ..mixins import CreateCommandMixin, FindAllCommandMixin
5
5
  from ..models.payment_request import PaymentRequestResponse
6
6
 
7
7
 
8
8
  class PaymentRequestClient(
9
+ CreateCommandMixin[PaymentRequestResponse],
9
10
  FindAllCommandMixin[PaymentRequestResponse],
10
11
  BaseClient,
11
12
  ):
@@ -0,0 +1,70 @@
1
+ from typing import ClassVar, Type
2
+
3
+ from ..base_client import BaseClient
4
+ from ..mixins import (
5
+ CreateCommandMixin,
6
+ DestroyCommandMixin,
7
+ FindAllCommandMixin,
8
+ FindCommandMixin,
9
+ UpdateCommandMixin,
10
+ )
11
+ from ..models.lifetime_usage import LifetimeUsageResponse
12
+ from ..models.subscription import SubscriptionResponse
13
+ from ..services.request import (
14
+ make_headers,
15
+ make_url,
16
+ send_get_request,
17
+ send_put_request,
18
+ )
19
+ from ..services.response import (
20
+ Response,
21
+ get_response_data,
22
+ prepare_object_response,
23
+ )
24
+ from ..services.json import to_json
25
+
26
+
27
+ class SubscriptionClient(
28
+ CreateCommandMixin[SubscriptionResponse],
29
+ DestroyCommandMixin[SubscriptionResponse],
30
+ FindAllCommandMixin[SubscriptionResponse],
31
+ FindCommandMixin[SubscriptionResponse],
32
+ UpdateCommandMixin[SubscriptionResponse],
33
+ BaseClient,
34
+ ):
35
+ API_RESOURCE: ClassVar[str] = "subscriptions"
36
+ RESPONSE_MODEL: ClassVar[Type[SubscriptionResponse]] = SubscriptionResponse
37
+ ROOT_NAME: ClassVar[str] = "subscription"
38
+
39
+ def lifetime_usage(self, resource_id: str) -> LifetimeUsageResponse:
40
+ api_response: Response = send_get_request(
41
+ url=make_url(
42
+ origin=self.base_url,
43
+ path_parts=(self.API_RESOURCE, resource_id, "lifetime_usage"),
44
+ ),
45
+ headers=make_headers(api_key=self.api_key),
46
+ )
47
+
48
+ return prepare_object_response(
49
+ response_model=LifetimeUsageResponse,
50
+ data=get_response_data(response=api_response, key="lifetime_usage"),
51
+ )
52
+
53
+ def update_lifetime_usage(
54
+ self, resource_id: str, external_historical_usage_amount_cents: int
55
+ ) -> LifetimeUsageResponse:
56
+ api_response: Response = send_put_request(
57
+ url=make_url(
58
+ origin=self.base_url,
59
+ path_parts=(self.API_RESOURCE, resource_id, "lifetime_usage"),
60
+ ),
61
+ content=to_json(
62
+ {"lifetime_usage": {"external_historical_usage_amount_cents": external_historical_usage_amount_cents}}
63
+ ),
64
+ headers=make_headers(api_key=self.api_key),
65
+ )
66
+
67
+ return prepare_object_response(
68
+ response_model=LifetimeUsageResponse,
69
+ data=get_response_data(response=api_response, key="lifetime_usage"),
70
+ )
@@ -0,0 +1 @@
1
+ LAGO_VERSION = "1.11.0"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: lago-python-client
3
- Version: 1.10.0
3
+ Version: 1.11.0
4
4
  Summary: Lago Python API Client
5
5
  Home-page: https://github.com/getlago/lago-python-client
6
6
  Author: Lovro Colic
@@ -50,6 +50,7 @@ setup.cfg
50
50
  ./lago_python_client/models/invoice_collection.py
51
51
  ./lago_python_client/models/invoice_item.py
52
52
  ./lago_python_client/models/invoiced_usage.py
53
+ ./lago_python_client/models/lifetime_usage.py
53
54
  ./lago_python_client/models/minimum_commitment.py
54
55
  ./lago_python_client/models/mrr.py
55
56
  ./lago_python_client/models/organization.py
@@ -45,6 +45,14 @@ def mock_response():
45
45
  return event_response.read()
46
46
 
47
47
 
48
+ def mock_unprocessable_entity_response():
49
+ this_dir = os.path.dirname(os.path.abspath(__file__))
50
+ data_path = os.path.join(this_dir, "fixtures/event_unprocessable_entity.json")
51
+
52
+ with open(data_path, "rb") as unprocessable_entity_response:
53
+ return unprocessable_entity_response.read()
54
+
55
+
48
56
  def mock_fees_response():
49
57
  this_dir = os.path.dirname(os.path.abspath(__file__))
50
58
  data_path = os.path.join(this_dir, "fixtures/fees.json")
@@ -68,19 +76,30 @@ def test_valid_create_events_request_with_string_timestamp(httpx_mock: HTTPXMock
68
76
 
69
77
 
70
78
  def test_invalid_create_events_request(httpx_mock: HTTPXMock):
71
- client = Client(api_key="invalid")
79
+ client = Client(api_key="886fe239-927d-4072-ab72-6dd345e8dd0d")
72
80
 
73
81
  httpx_mock.add_response(
74
82
  method="POST",
75
83
  url="https://api.getlago.com/api/v1/events",
76
- status_code=401,
77
- content=b"",
84
+ status_code=422,
85
+ content=mock_unprocessable_entity_response(),
78
86
  )
79
87
 
80
88
  with pytest.raises(LagoApiError):
81
89
  client.events.create(create_event())
82
90
 
83
91
 
92
+ def test_valid_create_event_request_with_custom_ingest_url(httpx_mock: HTTPXMock):
93
+ client = Client(
94
+ api_key="886fe239-927d-4072-ab72-6dd345e8dd0d",
95
+ use_ingest_service=True,
96
+ ingest_api_url="https://custom-ingest.getlago.com",
97
+ )
98
+
99
+ httpx_mock.add_response(method="POST", url="https://custom-ingest.getlago.com/api/v1/events", content=b"")
100
+ client.events.create(create_event()) # Any response means success, any exception - failure
101
+
102
+
84
103
  def test_valid_create_batch_events_request(httpx_mock: HTTPXMock):
85
104
  client = Client(api_key="886fe239-927d-4072-ab72-6dd345e8dd0d")
86
105
 
@@ -0,0 +1,109 @@
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 import PaymentRequest
9
+
10
+
11
+ def payment_request_object():
12
+ return PaymentRequest(
13
+ email="gavin@overdue.test",
14
+ external_customer_id="gavin_001",
15
+ lago_invoice_ids=["f8e194df-5d90-4382-b146-c881d2c67f28", "a20b1805-d54c-4e57-873d-721cc153035e"],
16
+ )
17
+
18
+
19
+ def mock_response():
20
+ this_dir = os.path.dirname(os.path.abspath(__file__))
21
+ data_path = os.path.join(this_dir, "fixtures/payment_request.json")
22
+
23
+ with open(data_path, "rb") as payment_request_response:
24
+ return payment_request_response.read()
25
+
26
+
27
+ def mock_collection_response():
28
+ current_dir = os.path.dirname(os.path.abspath(__file__))
29
+ data_path = os.path.join(current_dir, "fixtures/payment_request_index.json")
30
+
31
+ with open(data_path, "rb") as payment_requests_response:
32
+ return payment_requests_response.read()
33
+
34
+
35
+ def test_valid_find_all_payment_requests_request(httpx_mock: HTTPXMock):
36
+ client = Client(api_key="886fe239-927d-4072-ab72-6dd345e8dd0d")
37
+
38
+ httpx_mock.add_response(
39
+ method="GET",
40
+ url="https://api.getlago.com/api/v1/payment_requests",
41
+ content=mock_collection_response(),
42
+ )
43
+ response = client.payment_requests.find_all()
44
+
45
+ assert response["payment_requests"][0].lago_id == "89b6b61e-4dbc-4307-ac96-4abcfa9e3e2d"
46
+ assert response["meta"]["current_page"] == 1
47
+
48
+
49
+ def test_valid_find_all_payment_requests_request_with_options(httpx_mock: HTTPXMock):
50
+ client = Client(api_key="886fe239-927d-4072-ab72-6dd345e8dd0d")
51
+
52
+ httpx_mock.add_response(
53
+ method="GET",
54
+ url="https://api.getlago.com/api/v1/payment_requests?per_page=2&page=1",
55
+ content=mock_collection_response(),
56
+ )
57
+ response = client.payment_requests.find_all({"per_page": 2, "page": 1})
58
+
59
+ assert response["payment_requests"][0].lago_id == "89b6b61e-4dbc-4307-ac96-4abcfa9e3e2d"
60
+ assert response["meta"]["current_page"] == 1
61
+
62
+
63
+ def test_invalid_find_all_payment_requests_request(httpx_mock: HTTPXMock):
64
+ client = Client(api_key="invalid")
65
+
66
+ httpx_mock.add_response(
67
+ method="GET",
68
+ url="https://api.getlago.com/api/v1/payment_requests",
69
+ status_code=404,
70
+ content=b"",
71
+ )
72
+
73
+ with pytest.raises(LagoApiError):
74
+ client.payment_requests.find_all()
75
+
76
+
77
+ def test_valid_create_payment_request_request(httpx_mock: HTTPXMock):
78
+ client = Client(api_key="886fe239-927d-4072-ab72-6dd345e8dd0d")
79
+
80
+ httpx_mock.add_response(
81
+ method="POST",
82
+ url="https://api.getlago.com/api/v1/payment_requests",
83
+ content=mock_response(),
84
+ )
85
+ response = client.payment_requests.create(payment_request_object())
86
+
87
+ assert response.lago_id == "89b6b61e-4dbc-4307-ac96-4abcfa9e3e2d"
88
+ assert response.email == "gavin@overdue.test"
89
+ assert response.amount_cents == 19955
90
+ assert response.amount_currency == "EUR"
91
+ assert response.payment_status == "pending"
92
+ assert response.customer.lago_id == "1a901a90-1a90-1a90-1a90-1a901a901a90"
93
+ assert len(response.invoices.__root__) == 2
94
+ assert response.invoices.__root__[0].lago_id == "f8e194df-5d90-4382-b146-c881d2c67f28"
95
+ assert response.invoices.__root__[1].lago_id == "a20b1805-d54c-4e57-873d-721cc153035e"
96
+
97
+
98
+ def test_invalid_create_payment_request_request(httpx_mock: HTTPXMock):
99
+ client = Client(api_key="invalid")
100
+
101
+ httpx_mock.add_response(
102
+ method="POST",
103
+ url="https://api.getlago.com/api/v1/payment_requests",
104
+ status_code=401,
105
+ content=b"",
106
+ )
107
+
108
+ with pytest.raises(LagoApiError):
109
+ client.payment_requests.create(payment_request_object())
@@ -27,6 +27,22 @@ def mock_response():
27
27
  return subscription_response.read()
28
28
 
29
29
 
30
+ def mock_lifetime_usage_response():
31
+ this_dir = os.path.dirname(os.path.abspath(__file__))
32
+ my_data_path = os.path.join(this_dir, "fixtures/lifetime_usage.json")
33
+
34
+ with open(my_data_path, "rb") as subscription_response:
35
+ return subscription_response.read()
36
+
37
+
38
+ def mock_update_lifetime_usage_response():
39
+ this_dir = os.path.dirname(os.path.abspath(__file__))
40
+ my_data_path = os.path.join(this_dir, "fixtures/update_lifetime_usage.json")
41
+
42
+ with open(my_data_path, "rb") as subscription_response:
43
+ return subscription_response.read()
44
+
45
+
30
46
  def mock_response_for_pending():
31
47
  this_dir = os.path.dirname(os.path.abspath(__file__))
32
48
  my_data_path = os.path.join(this_dir, "fixtures/pending_subscription.json")
@@ -210,3 +226,51 @@ def test_invalid_find_all_subscription_request(httpx_mock: HTTPXMock):
210
226
 
211
227
  with pytest.raises(LagoApiError):
212
228
  client.subscriptions.find_all()
229
+
230
+
231
+ def test_valid_lifetime_usage_request(httpx_mock: HTTPXMock):
232
+ client = Client(api_key="886fe239-927d-4072-ab72-6dd345e8dd0d")
233
+ external_id = "5eb02857-a71e-4ea2-bcf9-57d3a41bc6ba"
234
+
235
+ httpx_mock.add_response(
236
+ method="GET",
237
+ url="https://api.getlago.com/api/v1/subscriptions/" + external_id + "/lifetime_usage",
238
+ content=mock_lifetime_usage_response(),
239
+ )
240
+ response = client.subscriptions.lifetime_usage(external_id)
241
+
242
+ assert response.lago_id == "ef555447-b017-4345-9846-6b814cfb4148"
243
+ assert response.current_usage_amount_cents == 3000
244
+ assert response.usage_thresholds[0].amount_cents == 2000
245
+ assert response.usage_thresholds[0].completion_ratio == 1
246
+ assert response.usage_thresholds[1].amount_cents == 4000
247
+ assert response.usage_thresholds[1].completion_ratio == 0.5
248
+
249
+
250
+ def test_invalid_lifetime_usage_request(httpx_mock: HTTPXMock):
251
+ client = Client(api_key="886fe239-927d-4072-ab72-6dd345e8dd0d")
252
+ external_id = "notfound"
253
+
254
+ httpx_mock.add_response(
255
+ method="GET",
256
+ url="https://api.getlago.com/api/v1/subscriptions/" + external_id + "/lifetime_usage",
257
+ status_code=404,
258
+ content=b"",
259
+ )
260
+ with pytest.raises(LagoApiError):
261
+ client.subscriptions.lifetime_usage(external_id)
262
+
263
+
264
+ def test_update_lifetime_usage_request(httpx_mock: HTTPXMock):
265
+ client = Client(api_key="886fe239-927d-4072-ab72-6dd345e8dd0d")
266
+ external_id = "5eb02857-a71e-4ea2-bcf9-57d3a41bc6ba"
267
+
268
+ httpx_mock.add_response(
269
+ method="PUT",
270
+ url="https://api.getlago.com/api/v1/subscriptions/" + external_id + "/lifetime_usage",
271
+ content=mock_update_lifetime_usage_response(),
272
+ )
273
+ response = client.subscriptions.update_lifetime_usage(external_id, 2000)
274
+
275
+ assert response.lago_id == "ef555447-b017-4345-9846-6b814cfb4148"
276
+ assert response.external_historical_usage_amount_cents == 2000
@@ -1,24 +0,0 @@
1
- from typing import ClassVar, Type
2
-
3
- from ..base_client import BaseClient
4
- from ..mixins import (
5
- CreateCommandMixin,
6
- DestroyCommandMixin,
7
- FindAllCommandMixin,
8
- FindCommandMixin,
9
- UpdateCommandMixin,
10
- )
11
- from ..models.subscription import SubscriptionResponse
12
-
13
-
14
- class SubscriptionClient(
15
- CreateCommandMixin[SubscriptionResponse],
16
- DestroyCommandMixin[SubscriptionResponse],
17
- FindAllCommandMixin[SubscriptionResponse],
18
- FindCommandMixin[SubscriptionResponse],
19
- UpdateCommandMixin[SubscriptionResponse],
20
- BaseClient,
21
- ):
22
- API_RESOURCE: ClassVar[str] = "subscriptions"
23
- RESPONSE_MODEL: ClassVar[Type[SubscriptionResponse]] = SubscriptionResponse
24
- ROOT_NAME: ClassVar[str] = "subscription"
@@ -1 +0,0 @@
1
- LAGO_VERSION = "1.10.0"
@@ -1,57 +0,0 @@
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
-
9
-
10
- def mock_collection_response():
11
- current_dir = os.path.dirname(os.path.abspath(__file__))
12
- data_path = os.path.join(current_dir, "fixtures/payment_request_index.json")
13
-
14
- with open(data_path, "rb") as payment_requests_response:
15
- return payment_requests_response.read()
16
-
17
-
18
- def test_valid_find_all_payment_requests_request(httpx_mock: HTTPXMock):
19
- client = Client(api_key="886fe239-927d-4072-ab72-6dd345e8dd0d")
20
-
21
- httpx_mock.add_response(
22
- method="GET",
23
- url="https://api.getlago.com/api/v1/payment_requests",
24
- content=mock_collection_response(),
25
- )
26
- response = client.payment_requests.find_all()
27
-
28
- assert response["payment_requests"][0].lago_id == "89b6b61e-4dbc-4307-ac96-4abcfa9e3e2d"
29
- assert response["meta"]["current_page"] == 1
30
-
31
-
32
- def test_valid_find_all_payment_requests_request_with_options(httpx_mock: HTTPXMock):
33
- client = Client(api_key="886fe239-927d-4072-ab72-6dd345e8dd0d")
34
-
35
- httpx_mock.add_response(
36
- method="GET",
37
- url="https://api.getlago.com/api/v1/payment_requests?per_page=2&page=1",
38
- content=mock_collection_response(),
39
- )
40
- response = client.payment_requests.find_all({"per_page": 2, "page": 1})
41
-
42
- assert response["payment_requests"][0].lago_id == "89b6b61e-4dbc-4307-ac96-4abcfa9e3e2d"
43
- assert response["meta"]["current_page"] == 1
44
-
45
-
46
- def test_invalid_find_all_payment_requests_request(httpx_mock: HTTPXMock):
47
- client = Client(api_key="invalid")
48
-
49
- httpx_mock.add_response(
50
- method="GET",
51
- url="https://api.getlago.com/api/v1/payment_requests",
52
- status_code=404,
53
- content=b"",
54
- )
55
-
56
- with pytest.raises(LagoApiError):
57
- client.payment_requests.find_all()