Skip to content

Commit 12c6388

Browse files
authored
[RSDK-11532] Add create_invoice_and_charge_immediately function (#971)
1 parent 3815735 commit 12c6388

File tree

3 files changed

+39
-0
lines changed

3 files changed

+39
-0
lines changed

src/viam/app/billing_client.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@
1313
GetInvoicesSummaryResponse,
1414
GetOrgBillingInformationRequest,
1515
GetOrgBillingInformationResponse,
16+
CreateInvoiceAndChargeImmediatelyRequest,
17+
CreateInvoiceAndChargeImmediatelyResponse,
1618
)
1719

1820
LOGGER = logging.getLogger(__name__)
@@ -141,3 +143,20 @@ async def get_org_billing_information(self, org_id: str, timeout: Optional[float
141143
"""
142144
request = GetOrgBillingInformationRequest(org_id=org_id)
143145
return await self._billing_client.GetOrgBillingInformation(request, metadata=self._metadata, timeout=timeout)
146+
147+
async def create_invoice_and_charge_immediately(self, org_id_to_charge: str, amount: float, description: Optional[str] = None, org_id_for_branding: Optional[str] = None) -> None:
148+
"""Create a flat fee invoice and charge the organization on the spot. The caller must be an owner of the organization being charged.
149+
This function blocks until payment is confirmed, but will time out after 2 minutes if there is no confirmation.
150+
151+
::
152+
153+
await billing_client.create_invoice_and_charge_immediately("<ORG-ID-TO-CHARGE>", <AMOUNT>, <DESCRIPTION>, "<ORG-ID-FOR-BRANDING>")
154+
155+
Args:
156+
org_id_to_charge (str): the organization to charge
157+
amount (float): the amount to charge in dollars
158+
description (str): a short description of the charge to display on the invoice PDF (must be 100 characters or less)
159+
org_id_for_branding (str): the organization whose branding to use in the invoice confirmation email
160+
"""
161+
request = CreateInvoiceAndChargeImmediatelyRequest(org_id_to_charge=org_id_to_charge, amount=amount, description=description, org_id_for_branding=org_id_for_branding)
162+
_: CreateInvoiceAndChargeImmediatelyResponse = await self._billing_client.CreateInvoiceAndChargeImmediately(request, metadata=self._metadata)

tests/mocks/services.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,8 @@
191191
GetInvoicesSummaryResponse,
192192
GetOrgBillingInformationRequest,
193193
GetOrgBillingInformationResponse,
194+
CreateInvoiceAndChargeImmediatelyRequest,
195+
CreateInvoiceAndChargeImmediatelyResponse,
194196
UnimplementedBillingServiceBase,
195197
)
196198
from viam.proto.app.data import (
@@ -1297,6 +1299,14 @@ async def GetOrgBillingInformation(self, stream: Stream[GetOrgBillingInformation
12971299
self.org_id = request.org_id
12981300
await stream.send_message(self.billing_info)
12991301

1302+
async def CreateInvoiceAndChargeImmediately(self, stream: Stream[CreateInvoiceAndChargeImmediatelyRequest, CreateInvoiceAndChargeImmediatelyResponse]) -> None:
1303+
request = await stream.recv_message()
1304+
assert request is not None
1305+
self.org_id_to_charge = request.org_id_to_charge
1306+
self.amount = request.amount
1307+
self.description = request.description
1308+
self.org_id_for_branding = request.org_id_for_branding
1309+
await stream.send_message(CreateInvoiceAndChargeImmediatelyResponse())
13001310

13011311
class MockApp(UnimplementedAppServiceBase):
13021312
def __init__(

tests/test_billing_client.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
GetInvoicesSummaryResponse,
99
GetOrgBillingInformationResponse,
1010
InvoiceSummary,
11+
CreateInvoiceAndChargeImmediatelyResponse,
1112
)
1213

1314
from .mocks.services import MockBilling
@@ -105,3 +106,12 @@ async def test_get_org_billing_information(self, service: MockBilling):
105106
org_billing_info = await client.get_org_billing_information(org_id=org_id)
106107
assert org_billing_info == ORG_BILLING_INFO
107108
assert service.org_id == org_id
109+
110+
async def test_create_invoice_and_charge_immediately(self, service: MockBilling):
111+
async with ChannelFor([service]) as channel:
112+
client = BillingClient(channel, BILLING_SERVICE_METADATA)
113+
_: CreateInvoiceAndChargeImmediatelyResponse = await client.create_invoice_and_charge_immediately(
114+
org_id_to_charge="foo",
115+
amount=42.42,
116+
description="A short description.",
117+
org_id_for_branding="bar")

0 commit comments

Comments
 (0)