Skip to content

Commit

Permalink
feat(ProgressiveBilling) - Add usage_thresholds & progressive_billing…
Browse files Browse the repository at this point in the history
…_credit_amount_cents (#261)

* Add usage_thresholds & progressive_billing_credit_amount_cents attributes

* add ruff and check formatting in CI

* Fix all Ruff remarks

* Force autoformatting with ruff

* allow 120 chars line length

* add applied_usage_thresholds to the api

* Add INP001 rule to ruff linting
  • Loading branch information
nudded authored Aug 30, 2024
1 parent 65176d5 commit 485dd83
Show file tree
Hide file tree
Showing 78 changed files with 2,231 additions and 1,212 deletions.
20 changes: 20 additions & 0 deletions .github/workflows/ruff.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
name: Ruff
on: [push, pull_request]
jobs:
ruff:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set up Python 3.11
uses: actions/setup-python@v3
with:
python-version: 3.11
- name: Install dependencies
run: |
python -m pip install .[test]
- name: Validate linter rules with Ruff
uses: chartboost/ruff-action@v1
- name: Validate formatting with Ruff
uses: chartboost/ruff-action@v1
with:
args: 'format --check'
4 changes: 2 additions & 2 deletions lago_python_client/__init__.py
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
from lago_python_client.client import Client
from lago_python_client.version import LAGO_VERSION
from lago_python_client.client import Client as Client
from lago_python_client.version import LAGO_VERSION as LAGO_VERSION
12 changes: 9 additions & 3 deletions lago_python_client/add_ons/clients.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,13 @@
from typing import ClassVar, Type

from ..base_client import BaseClient
from ..mixins import CreateCommandMixin, DestroyCommandMixin, FindAllCommandMixin, FindCommandMixin, UpdateCommandMixin
from ..mixins import (
CreateCommandMixin,
DestroyCommandMixin,
FindAllCommandMixin,
FindCommandMixin,
UpdateCommandMixin,
)
from ..models.add_on import AddOnResponse


Expand All @@ -13,6 +19,6 @@ class AddOnClient(
UpdateCommandMixin[AddOnResponse],
BaseClient,
):
API_RESOURCE: ClassVar[str] = 'add_ons'
API_RESOURCE: ClassVar[str] = "add_ons"
RESPONSE_MODEL: ClassVar[Type[AddOnResponse]] = AddOnResponse
ROOT_NAME: ClassVar[str] = 'add_on'
ROOT_NAME: ClassVar[str] = "add_on"
22 changes: 10 additions & 12 deletions lago_python_client/billable_metrics/clients.py
Original file line number Diff line number Diff line change
@@ -1,16 +1,14 @@
import sys
from typing import Any, ClassVar, Type, Union
from typing import ClassVar, Type

from ..base_client import BaseClient
from ..mixins import CreateCommandMixin, DestroyCommandMixin, FindAllCommandMixin, FindCommandMixin, UpdateCommandMixin
from ..mixins import (
CreateCommandMixin,
DestroyCommandMixin,
FindAllCommandMixin,
FindCommandMixin,
UpdateCommandMixin,
)
from ..models.billable_metric import BillableMetricResponse
from ..services.request import make_headers, make_url, send_get_request
from ..services.response import get_response_data, prepare_index_response, Response

if sys.version_info >= (3, 9):
from collections.abc import Mapping
else:
from typing import Mapping


class BillableMetricClient(
Expand All @@ -21,6 +19,6 @@ class BillableMetricClient(
UpdateCommandMixin[BillableMetricResponse],
BaseClient,
):
API_RESOURCE: ClassVar[str] = 'billable_metrics'
API_RESOURCE: ClassVar[str] = "billable_metrics"
RESPONSE_MODEL: ClassVar[Type[BillableMetricResponse]] = BillableMetricResponse
ROOT_NAME: ClassVar[str] = 'billable_metric'
ROOT_NAME: ClassVar[str] = "billable_metric"
6 changes: 3 additions & 3 deletions lago_python_client/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,10 @@


class Client:
BASE_URL: Final[str] = 'https://api.getlago.com/'
API_PATH: Final[str] = 'api/v1/'
BASE_URL: Final[str] = "https://api.getlago.com/"
API_PATH: Final[str] = "api/v1/"

def __init__(self, api_key: str = '', api_url: str = '') -> None:
def __init__(self, api_key: str = "", api_url: str = "") -> None:
self.api_key: str = api_key
self.api_url: str = api_url

Expand Down
29 changes: 22 additions & 7 deletions lago_python_client/coupons/clients.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,13 @@
from typing import ClassVar, Type

from ..base_client import BaseClient
from ..mixins import CreateCommandMixin, DestroyCommandMixin, FindAllCommandMixin, FindCommandMixin, UpdateCommandMixin
from ..mixins import (
CreateCommandMixin,
DestroyCommandMixin,
FindAllCommandMixin,
FindCommandMixin,
UpdateCommandMixin,
)
from ..models.coupon import CouponResponse
from ..models.applied_coupon import AppliedCouponResponse
from ..services.request import make_headers, make_url, send_delete_request
Expand All @@ -16,21 +22,30 @@ class CouponClient(
UpdateCommandMixin[CouponResponse],
BaseClient,
):
API_RESOURCE: ClassVar[str] = 'coupons'
API_RESOURCE: ClassVar[str] = "coupons"
RESPONSE_MODEL: ClassVar[Type[CouponResponse]] = CouponResponse
ROOT_NAME: ClassVar[str] = 'coupon'
ROOT_NAME: ClassVar[str] = "coupon"


class AppliedCouponClient(CreateCommandMixin[AppliedCouponResponse], FindAllCommandMixin[AppliedCouponResponse], BaseClient):
API_RESOURCE: ClassVar[str] = 'applied_coupons'
class AppliedCouponClient(
CreateCommandMixin[AppliedCouponResponse],
FindAllCommandMixin[AppliedCouponResponse],
BaseClient,
):
API_RESOURCE: ClassVar[str] = "applied_coupons"
RESPONSE_MODEL: ClassVar[Type[AppliedCouponResponse]] = AppliedCouponResponse
ROOT_NAME: ClassVar[str] = 'applied_coupon'
ROOT_NAME: ClassVar[str] = "applied_coupon"

def destroy(self, external_customer_id: str, applied_coupon_id: str) -> AppliedCouponResponse:
api_response: Response = send_delete_request(
url=make_url(
origin=self.base_url,
path_parts=('customers', external_customer_id, self.API_RESOURCE, applied_coupon_id),
path_parts=(
"customers",
external_customer_id,
self.API_RESOURCE,
applied_coupon_id,
),
),
headers=make_headers(api_key=self.api_key),
)
Expand Down
42 changes: 29 additions & 13 deletions lago_python_client/credit_notes/clients.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,24 @@
from typing import ClassVar, Optional, Type, Union
from typing import ClassVar, Optional, Type

from ..base_client import BaseClient
from ..mixins import CreateCommandMixin, FindAllCommandMixin, FindCommandMixin, UpdateCommandMixin
from ..models.credit_note import CreditNoteResponse, CreditNoteEstimatedResponse, CreditNoteEstimate
from ..mixins import (
CreateCommandMixin,
FindAllCommandMixin,
FindCommandMixin,
UpdateCommandMixin,
)
from ..models.credit_note import (
CreditNoteResponse,
CreditNoteEstimatedResponse,
CreditNoteEstimate,
)
from ..services.json import to_json
from ..services.request import make_headers, make_url, send_post_request, send_put_request
from ..services.request import (
make_headers,
make_url,
send_post_request,
send_put_request,
)
from ..services.response import get_response_data, prepare_object_response, Response


Expand All @@ -15,16 +29,16 @@ class CreditNoteClient(
UpdateCommandMixin[CreditNoteResponse],
BaseClient,
):
API_RESOURCE: ClassVar[str] = 'credit_notes'
ESTIMATE_API_RESOURCE: ClassVar[str] = 'estimated_credit_note'
API_RESOURCE: ClassVar[str] = "credit_notes"
ESTIMATE_API_RESOURCE: ClassVar[str] = "estimated_credit_note"
RESPONSE_MODEL: ClassVar[Type[CreditNoteResponse]] = CreditNoteResponse
ROOT_NAME: ClassVar[str] = 'credit_note'
ROOT_NAME: ClassVar[str] = "credit_note"

def download(self, resource_id: str) -> Optional[CreditNoteResponse]:
api_response: Response = send_post_request(
url=make_url(
origin=self.base_url,
path_parts=(self.API_RESOURCE, resource_id, 'download'),
path_parts=(self.API_RESOURCE, resource_id, "download"),
),
headers=make_headers(api_key=self.api_key),
)
Expand All @@ -42,7 +56,7 @@ def void(self, resource_id: str) -> CreditNoteResponse:
api_response: Response = send_put_request(
url=make_url(
origin=self.base_url,
path_parts=(self.API_RESOURCE, resource_id, 'void'),
path_parts=(self.API_RESOURCE, resource_id, "void"),
),
headers=make_headers(api_key=self.api_key),
)
Expand All @@ -56,11 +70,13 @@ def estimate(self, input_object: CreditNoteEstimate) -> CreditNoteEstimatedRespo
api_response: Response = send_post_request(
url=make_url(
origin=self.base_url,
path_parts=(self.API_RESOURCE, 'estimate'),
path_parts=(self.API_RESOURCE, "estimate"),
),
content=to_json(
{
self.ROOT_NAME: input_object.dict(),
}
),
content=to_json({
self.ROOT_NAME: input_object.dict(),
}),
headers=make_headers(api_key=self.api_key),
)

Expand Down
53 changes: 36 additions & 17 deletions lago_python_client/customers/clients.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,26 @@
from typing import Any, Mapping, ClassVar, Type, Union

from ..base_client import BaseClient
from ..mixins import CreateCommandMixin, DestroyCommandMixin, FindAllCommandMixin, FindCommandMixin
from ..mixins import (
CreateCommandMixin,
DestroyCommandMixin,
FindAllCommandMixin,
FindCommandMixin,
)
from ..models.customer import CustomerResponse
from ..models.customer_usage import CustomerUsageResponse
from ..services.request import make_headers, make_url, send_get_request, send_post_request
from ..services.response import get_response_data, prepare_index_response, prepare_object_response, Response
from ..services.request import (
make_headers,
make_url,
send_get_request,
send_post_request,
)
from ..services.response import (
get_response_data,
prepare_index_response,
prepare_object_response,
Response,
)

if sys.version_info >= (3, 9):
from collections.abc import Mapping
Expand All @@ -21,67 +36,71 @@ class CustomerClient(
FindCommandMixin[CustomerResponse],
BaseClient,
):
API_RESOURCE: ClassVar[str] = 'customers'
API_RESOURCE: ClassVar[str] = "customers"
RESPONSE_MODEL: ClassVar[Type[CustomerResponse]] = CustomerResponse
ROOT_NAME: ClassVar[str] = 'customer'
ROOT_NAME: ClassVar[str] = "customer"

def current_usage(self, resource_id: str, external_subscription_id: str) -> CustomerUsageResponse:
api_response: Response = send_get_request(
url=make_url(
origin=self.base_url,
path_parts=(self.API_RESOURCE, resource_id, 'current_usage'),
path_parts=(self.API_RESOURCE, resource_id, "current_usage"),
query_pairs={
'external_subscription_id': external_subscription_id,
"external_subscription_id": external_subscription_id,
},
),
headers=make_headers(api_key=self.api_key),
)

return prepare_object_response(
response_model=CustomerUsageResponse,
data=get_response_data(response=api_response, key='customer_usage'),
data=get_response_data(response=api_response, key="customer_usage"),
)

def past_usage(self, resource_id: str, external_subscription_id: str, options: Mapping[str, Union[int, str]] = {}) -> Mapping[str, Any]:
def past_usage(
self,
resource_id: str,
external_subscription_id: str,
options: Mapping[str, Union[int, str]] = {},
) -> Mapping[str, Any]:
api_response: Response = send_get_request(
url=make_url(
origin=self.base_url,
path_parts=(self.API_RESOURCE, resource_id, 'past_usage'),
path_parts=(self.API_RESOURCE, resource_id, "past_usage"),
query_pairs={
'external_subscription_id': external_subscription_id,
"external_subscription_id": external_subscription_id,
**options,
},
),
headers=make_headers(api_key=self.api_key),
)

return prepare_index_response(
api_resource='usage_periods',
api_resource="usage_periods",
response_model=CustomerUsageResponse,
data=get_response_data(response=api_response),
)


def portal_url(self, resource_id: str) -> str:
api_response: Response = send_get_request(
url=make_url(
origin=self.base_url,
path_parts=(self.API_RESOURCE, resource_id, 'portal_url'),
path_parts=(self.API_RESOURCE, resource_id, "portal_url"),
),
headers=make_headers(api_key=self.api_key),
)

response_data = get_response_data(response=api_response, key=self.ROOT_NAME)
return response_data.get('portal_url', '') if isinstance(response_data, Mapping) else ''
return response_data.get("portal_url", "") if isinstance(response_data, Mapping) else ""

def checkout_url(self, resource_id: str) -> str:
api_response: Response = send_post_request(
url=make_url(
origin=self.base_url,
path_parts=(self.API_RESOURCE, resource_id, 'checkout_url'),
path_parts=(self.API_RESOURCE, resource_id, "checkout_url"),
),
headers=make_headers(api_key=self.api_key),
)

response_data = get_response_data(response=api_response, key=self.ROOT_NAME)
return response_data.get('checkout_url', '') if isinstance(response_data, Mapping) else ''
return response_data.get("checkout_url", "") if isinstance(response_data, Mapping) else ""
Loading

0 comments on commit 485dd83

Please sign in to comment.