Skip to content

Commit

Permalink
feat(credit-note): Add estimate route before creation (#204)
Browse files Browse the repository at this point in the history
* feat(credit-note): Ignore venv file

* feat(credit-note): Add estimate route before creation
  • Loading branch information
vincent-pochet authored Nov 2, 2023
1 parent 6ffa33c commit d87bbb7
Show file tree
Hide file tree
Showing 6 changed files with 125 additions and 13 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ share/python-wheels/
.installed.cfg
*.egg
MANIFEST
.venv

# PyInstaller
# Usually these files are written by a python script from a template
Expand Down
21 changes: 20 additions & 1 deletion lago_python_client/credit_notes/clients.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@

from ..base_client import BaseClient
from ..mixins import CreateCommandMixin, FindAllCommandMixin, FindCommandMixin, UpdateCommandMixin
from ..models.credit_note import CreditNoteResponse
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.response import get_response_data, prepare_object_response, Response

Expand All @@ -15,6 +16,7 @@ class CreditNoteClient(
BaseClient,
):
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'

Expand Down Expand Up @@ -49,3 +51,20 @@ def void(self, resource_id: str) -> CreditNoteResponse:
response_model=self.RESPONSE_MODEL,
data=get_response_data(response=api_response, key=self.ROOT_NAME),
)

def estimate(self, input_object: CreditNoteEstimate) -> CreditNoteEstimatedResponse:
api_response: Response = send_post_request(
url=make_url(
origin=self.base_url,
path_parts=(self.API_RESOURCE, 'estimate'),
),
content=to_json({
self.ROOT_NAME: input_object.dict(),
}),
headers=make_headers(api_key=self.api_key),
)

return prepare_object_response(
response_model=CreditNoteEstimatedResponse,
data=get_response_data(response=api_response, key=self.ESTIMATE_API_RESOURCE),
)
2 changes: 1 addition & 1 deletion lago_python_client/models/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
from .charge import Charge, Charges, ChargesResponse
from .coupon import Coupon, LimitationConfiguration
from .credit import CreditResponse, CreditsResponse
from .credit_note import Item, Items, CreditNote, CreditNoteUpdate
from .credit_note import Item, Items, CreditNote, CreditNoteUpdate, CreditNoteEstimate
from .plan import Plan
from .add_on import AddOn
from .organization import Organization, OrganizationBillingConfiguration
Expand Down
52 changes: 46 additions & 6 deletions lago_python_client/models/credit_note.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,8 @@

class ItemResponse(BaseResponseModel):
lago_id: Optional[str]
credit_amount_cents: Optional[int]
credit_amount_currency: Optional[str]
refund_amount_cents: Optional[int]
refund_amount_currency: Optional[str]
amount_cents: Optional[int]
amount_currency: Optional[str]
fee: Optional[FeeResponse]


Expand Down Expand Up @@ -63,8 +61,7 @@ class CreditNoteResponse(BaseResponseModel):


class Item(BaseModel):
credit_amount_cents: Optional[int]
refund_amount_cents: Optional[int]
amount_cents: Optional[int]
fee_id: Optional[str]


Expand All @@ -79,3 +76,46 @@ class CreditNote(BaseModel):

class CreditNoteUpdate(BaseModel):
refund_status: Optional[str]


class EstimatedItemResponse(BaseResponseModel):
amount_cents: Optional[int]
lago_fee_id: Optional[str]


class EstimatedItemsResponse(BaseResponseModel):
__root__: List[EstimatedItemResponse]


class CreditNoteEstimatedAppliedTax(BaseResponseModel):
lago_tax_id: Optional[str]
tax_name: Optional[str]
tax_code: Optional[str]
tax_rate: Optional[float]
tax_description: Optional[str]
amount_cents: Optional[int]
amount_currency: Optional[str]
base_amount_cents: Optional[int]


class CreditNoteEstimatedAppliedTaxes(BaseResponseModel):
__root__: List[CreditNoteEstimatedAppliedTax]


class CreditNoteEstimatedResponse(BaseResponseModel):
lago_invoice_id: str
invoice_number: str
currency: str
max_creditable_amount_cents: int
max_refundable_amount_cents: int
taxes_amount_cents: str
taxes_rate: float
sub_total_excluding_taxes_amount_cents: int
coupons_adjustment_amount_cents: int
items: EstimatedItemsResponse
applied_taxes: CreditNoteEstimatedAppliedTaxes


class CreditNoteEstimate(BaseModel):
invoice_id: str
items: Items
20 changes: 20 additions & 0 deletions tests/fixtures/credit_note_estimated.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{
"estimated_credit_note": {
"lago_invoice_id": "1a901a90-1a90-1a90-1a90-1a901a901a90",
"invoice_number": "LAG15",
"currency": "EUR",
"max_creditable_amount_cents": 100,
"max_refundable_amount_cents": 100,
"taxes_amount_cents": 40,
"taxes_rate": "20.0",
"sub_total_excluding_taxes_amount_cents": 200,
"coupons_adjustment_amount_cents": 0,
"items": [
{
"lago_fee_id": "1a901a90-1a90-1a90-1a90-1a901a901a90",
"amount_cents": 100
}
],
"applied_taxes": []
}
}
42 changes: 37 additions & 5 deletions tests/test_credit_note_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,20 +6,18 @@
from lago_python_client.client import Client
from lago_python_client.exceptions import LagoApiError
from lago_python_client.models.fee import FeeResponse
from lago_python_client.models.credit_note import Item, Items, CreditNote, CreditNoteUpdate
from lago_python_client.models.credit_note import Item, Items, CreditNote, CreditNoteUpdate, CreditNoteEstimate


def credit_note_object():
item1 = Item(
fee_id="fee_id_1",
credit_amount_cents=10,
refund_amount_cents=10,
amount_cents=10
)

item2 = Item(
fee="fee_id_2",
credit_amount_cents=5,
refund_amount_cents=5,
amount_cents=5
)

return CreditNote(
Expand All @@ -33,6 +31,23 @@ def credit_note_update_object():
return CreditNoteUpdate(refund_status='pending')


def estimate_credit_note():
item1 = Item(
fee_id="fee_id_1",
amount_cents=10,
)

item2 = Item(
fee="fee_id_2",
amount_cents=5,
)

return CreditNoteEstimate(
invoice_id='1a901a90-1a90-1a90-1a90-1a901a901a90',
items= Items(__root__=[item1, item2])
)


def mock_response():
current_dir = os.path.dirname(os.path.abspath(__file__))
data_path = os.path.join(current_dir, 'fixtures/credit_note.json')
Expand All @@ -49,6 +64,14 @@ def mock_collection_response():
return credit_notes_response.read()


def mock_estimated_response():
current_dir = os.path.dirname(os.path.abspath(__file__))
data_path = os.path.join(current_dir, 'fixtures/credit_note_estimated.json')

with open(data_path, 'rb') as credit_note_estimated_response:
return credit_note_estimated_response.read()


def test_valid_find_credit_note_request(httpx_mock: HTTPXMock):
client = Client(api_key='886fe239-927d-4072-ab72-6dd345e8dd0d')
identifier = '5eb02857-a71e-4ea2-bcf9-57d3a41bc6ba'
Expand Down Expand Up @@ -131,3 +154,12 @@ def test_valid_void_credit_note_request(httpx_mock: HTTPXMock):

assert response.lago_id == "5eb02857-a71e-4ea2-bcf9-57d3a41bc6ba"
assert response.refund_status == 'pending'


def test_valid_estimate_credit_note_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/credit_notes/estimate', content=mock_estimated_response())
response = client.credit_notes.estimate(estimate_credit_note())

assert response.lago_invoice_id == '1a901a90-1a90-1a90-1a90-1a901a901a90'

0 comments on commit d87bbb7

Please sign in to comment.