Skip to content

Commit d1d12ee

Browse files
author
Jakub Smolar
committed
Add Invoice and LineItems endpoints
1 parent ff43e27 commit d1d12ee

File tree

4 files changed

+188
-1
lines changed

4 files changed

+188
-1
lines changed

tests/integration/conftest.py

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
from threescale_api.resources import (Service, ApplicationPlan, Application,
1212
Proxy, Backend, Metric, MappingRule,
1313
BackendMappingRule, BackendUsage,
14-
ActiveDoc, Webhooks)
14+
ActiveDoc, Webhooks, InvoiceState)
1515

1616
load_dotenv()
1717

@@ -459,3 +459,26 @@ def account_plan(account_plans_params, api):
459459
entity = api.account_plans.create(params=account_plans_params)
460460
yield entity
461461
cleanup(entity)
462+
463+
464+
@pytest.fixture(scope="module")
465+
def invoice(account, api):
466+
entity = api.invoices.create(dict(account_id=account['id']))
467+
yield entity
468+
entity.state_update(InvoiceState.cancelled)
469+
470+
471+
@pytest.fixture(scope='module')
472+
def invoice_line_params():
473+
name = f"test-{get_suffix()}"
474+
return dict(name=name,
475+
description='test_item',
476+
quantity='1',
477+
cost=10)
478+
479+
480+
@pytest.fixture(scope='module')
481+
def invoice_line(invoice, invoice_line_params, api):
482+
entity = invoice.line_items.create(invoice_line_params)
483+
yield entity
484+
cleanup(entity)
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
import pytest
2+
3+
from threescale_api.resources import InvoiceState
4+
from .asserts import assert_resource, assert_resource_params
5+
6+
7+
@pytest.fixture(scope="function")
8+
def invoice_to_update(account, api):
9+
entity = api.invoices.create(dict(account_id=account['id']))
10+
yield entity
11+
entity.state_update(InvoiceState.cancelled)
12+
13+
14+
def test_invoice_create(invoice):
15+
assert_resource(invoice)
16+
17+
18+
def test_invoice_read(invoice, api):
19+
read = api.invoices.read(invoice.entity_id)
20+
assert_resource(read)
21+
assert_resource_params(read, invoice)
22+
23+
24+
def test_invoice_list(invoice, api):
25+
invoices = api.invoices.list()
26+
assert len(invoices) >= 1
27+
28+
29+
def test_invoice_update(invoice, api):
30+
assert invoice['state'] == 'open'
31+
update = api.invoices.update(invoice.entity_id, dict(friendly_id='1111-11111111'))
32+
assert update['friendly_id'] == '1111-11111111'
33+
read = api.invoices.read(invoice.entity_id)
34+
assert read['friendly_id'] == '1111-11111111'
35+
36+
37+
def test_invoice_list_by_account(api, account, invoice):
38+
invoices = api.invoices.list_by_account(account.entity_id)
39+
assert len(invoices) == 1
40+
assert_resource(invoices[0])
41+
assert_resource_params(invoice, invoices[0])
42+
43+
44+
def test_invoice_read_by_account(api, account, invoice):
45+
read = api.invoices.read_by_account(invoice.entity_id, account.entity_id)
46+
assert_resource(read)
47+
assert_resource_params(read, invoice)
48+
49+
50+
def test_invoice_update_state(invoice_to_update, api):
51+
assert invoice_to_update['state'] == 'open'
52+
update = api.invoices.state_update(invoice_to_update.entity_id, InvoiceState.pending)
53+
assert update['state'] == 'pending'
54+
read = api.invoices.read(invoice_to_update.entity_id)
55+
assert read['state'] == 'pending'
56+
57+
58+
def test_invoice_resource_update_state(invoice_to_update, api):
59+
assert invoice_to_update['state'] == 'open'
60+
update = invoice_to_update.state_update(InvoiceState.pending)
61+
assert update['state'] == 'pending'
62+
read = api.invoices.read(invoice_to_update.entity_id)
63+
assert read['state'] == 'pending'
64+
65+
66+
def test_line_invoice_create(invoice_line):
67+
assert_resource(invoice_line)
68+
69+
70+
def test_line_invoice_list(invoice, invoice_line):
71+
lines = invoice.line_items.list()
72+
assert len(lines) == 1
73+
assert_resource_params(invoice_line, lines[0])

threescale_api/client.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ def __init__(self, url: str, token: str, throws: bool = True, ssl_verify: bool =
4040
instance_klass=resources.PolicyRegistry)
4141
self._backends = resources.Backends(self, instance_klass=resources.Backend)
4242
self._webhooks = resources.Webhooks(self)
43+
self._invoices = resources.Invoices(self, instance_klass=resources.Invoice)
4344

4445
@property
4546
def rest(self) -> 'RestApiClient':
@@ -204,6 +205,10 @@ def policy_registry(self) -> resources.PolicyRegistry:
204205
def webhooks(self) -> resources.Webhooks:
205206
return self._webhooks
206207

208+
@property
209+
def invoices(self) -> resources.Invoices:
210+
return self._invoices
211+
207212

208213
class RestApiClient:
209214
def __init__(self, url: str, token: str, throws: bool = True, ssl_verify: bool = True):

threescale_api/resources.py

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import logging
2+
from enum import Enum
23
from typing import Dict, Union, List, Iterable
34

45
from threescale_api import auth
@@ -778,6 +779,71 @@ def clear(self):
778779
return self.update(params=params)
779780

780781

782+
class LineItems(DefaultClient):
783+
"""Default client for LineItems"""
784+
def __init__(self, *args, entity_name='line_item', entity_collection='line_items', **kwargs):
785+
super().__init__(*args, entity_name=entity_name,
786+
entity_collection=entity_collection, **kwargs)
787+
788+
@property
789+
def url(self) -> str:
790+
return self.parent.url + '/line_items'
791+
792+
793+
class InvoiceState(Enum):
794+
cancelled, failed, paid, unpaid, pending, finalized = range(6)
795+
796+
797+
class Invoices(DefaultClient):
798+
"""Default client for Invoices"""
799+
def __init__(self, *args, entity_name='invoice', entity_collection='invoices', **kwargs):
800+
super().__init__(*args, entity_name=entity_name,
801+
entity_collection=entity_collection, **kwargs)
802+
803+
@property
804+
def url(self) -> str:
805+
return self.threescale_client.url + '/api/invoices'
806+
807+
@property
808+
def line_items(self) -> LineItems:
809+
return LineItems(parent=self, instance_klass=LineItem)
810+
811+
def list_by_account(self, account: Union['Account', int], **kwargs):
812+
account_id = _extract_entity_id(account)
813+
url = self.threescale_client.url + f"/api/accounts/{account_id}/invoices"
814+
response = self.rest.get(url, **kwargs)
815+
instance = self._create_instance(response=response, collection=True)
816+
return instance
817+
818+
def read_by_account(self, entity_id: int, account: Union['Account', int], **kwargs):
819+
account_id = _extract_entity_id(account)
820+
url = self.threescale_client.url + f"/api/accounts/{account_id}/invoices/{entity_id}"
821+
response = self.rest.get(url, **kwargs)
822+
instance = self._create_instance(response=response)
823+
return instance
824+
825+
def state_update(self, entity_id: int, state: InvoiceState, **kwargs):
826+
"""
827+
Update the state of the Invoice.
828+
Values allowed (depend on the previous state):
829+
cancelled, failed, paid, unpaid, pending, finalized
830+
"""
831+
log.info(f"[Invoice] state changed for invoice ({entity_id}): {state}")
832+
params = dict(state=state.name)
833+
url = self._entity_url(entity_id) + '/state'
834+
response = self.rest.put(url=url, json=params, **kwargs)
835+
instance = self._create_instance(response=response)
836+
return instance
837+
838+
def charge(self, entity_id: int):
839+
"""Charge an Invoice."""
840+
log.info(f"[Invoice] charge invoice ({entity_id})")
841+
url = self._entity_url(entity_id) + '/state'
842+
response = self.rest.post(url)
843+
instance = self._create_instance(response=response)
844+
return instance
845+
846+
781847
# Resources
782848

783849

@@ -1242,3 +1308,23 @@ def unsuspend(self):
12421308
def activate(self):
12431309
log.info("Changes the state of the user of the provider account to active")
12441310
return self.set_state(state='activate')
1311+
1312+
1313+
class LineItem(DefaultResource):
1314+
def __init__(self, entity_name='name', **kwargs):
1315+
super().__init__(entity_name=entity_name, **kwargs)
1316+
1317+
1318+
class Invoice(DefaultResource):
1319+
def __init__(self, entity_name='friendly_id', **kwargs):
1320+
super().__init__(entity_name=entity_name, **kwargs)
1321+
1322+
@property
1323+
def line_items(self) -> LineItems:
1324+
return LineItems(parent=self, instance_klass=LineItem)
1325+
1326+
def state_update(self, state: InvoiceState, **kwargs):
1327+
return self.client.state_update(entity_id=self.entity_id, state=state, **kwargs)
1328+
1329+
def charge(self, **kwargs):
1330+
return self.client.charge(entity_id=self.entity_id, **kwargs)

0 commit comments

Comments
 (0)