Skip to content

Commit cb90cd2

Browse files
committed
Return invoice ID for create_invoice_and_charge_immediately
1 parent 2b37b8c commit cb90cd2

File tree

3 files changed

+22
-8
lines changed

3 files changed

+22
-8
lines changed

src/viam/app/billing_client.py

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -149,20 +149,31 @@ async def create_invoice_and_charge_immediately(
149149
description: Optional[str] = None,
150150
org_id_for_branding: Optional[str] = None,
151151
disable_email: bool = False,
152-
) -> None:
152+
) -> CreateInvoiceAndChargeImmediatelyResponse:
153153
"""Create a flat fee invoice and charge the organization on the spot. The caller must be an owner of the organization being charged.
154-
This function blocks until payment is confirmed, but will time out after 2 minutes if there is no confirmation.
154+
This function returns the invoice id once the payment intent is successfully sent for processing. Callers may poll the invoice for
155+
its status using the `get_invoices_summary` function and the returned invoice id. The status will be "payment_processing" if the
156+
payment is being processed, "paid" if it succeeds, or "outstanding" if it fails.
155157
156158
::
157159
158-
await billing_client.create_invoice_and_charge_immediately("<ORG-ID-TO-CHARGE>", <AMOUNT>, <DESCRIPTION>, "<ORG-ID-FOR-BRANDING>", False)
160+
invoice_id = await billing_client.create_invoice_and_charge_immediately(
161+
"<ORG-ID-TO-CHARGE>",
162+
<AMOUNT>,
163+
<DESCRIPTION>,
164+
"<ORG-ID-FOR-BRANDING>",
165+
False,
166+
)
159167
160168
Args:
161169
org_id_to_charge (str): the organization to charge
162170
amount (float): the amount to charge in dollars
163171
description (str): a short description of the charge to display on the invoice PDF (must be 100 characters or less)
164172
org_id_for_branding (str): the organization whose branding to use in the invoice confirmation email
165173
disable_email (bool): whether or not to disable sending an email confirmation for the invoice
174+
175+
Returns:
176+
viam.proto.app.billing.CreateInvoiceAndChargeImmediatelyResponse: the invoice id
166177
"""
167178
request = CreateInvoiceAndChargeImmediatelyRequest(
168179
org_id_to_charge=org_id_to_charge,
@@ -171,6 +182,4 @@ async def create_invoice_and_charge_immediately(
171182
org_id_for_branding=org_id_for_branding,
172183
disable_email=disable_email,
173184
)
174-
_: CreateInvoiceAndChargeImmediatelyResponse = await self._billing_client.CreateInvoiceAndChargeImmediately(
175-
request, metadata=self._metadata
176-
)
185+
return await self._billing_client.CreateInvoiceAndChargeImmediately(request, metadata=self._metadata)

tests/mocks/services.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1301,11 +1301,13 @@ def __init__(
13011301
curr_month_usage: GetCurrentMonthUsageResponse,
13021302
invoices_summary: GetInvoicesSummaryResponse,
13031303
billing_info: GetOrgBillingInformationResponse,
1304+
invoice_id_response: CreateInvoiceAndChargeImmediatelyResponse,
13041305
):
13051306
self.pdf = pdf
13061307
self.curr_month_usage = curr_month_usage
13071308
self.invoices_summary = invoices_summary
13081309
self.billing_info = billing_info
1310+
self.invoice_id_response = invoice_id_response
13091311
self.disable_email: bool = False
13101312

13111313
async def GetCurrentMonthUsage(self, stream: Stream[GetCurrentMonthUsageRequest, GetCurrentMonthUsageResponse]) -> None:
@@ -1344,7 +1346,7 @@ async def CreateInvoiceAndChargeImmediately(
13441346
self.description = request.description
13451347
self.org_id_for_branding = request.org_id_for_branding
13461348
self.disable_email = request.disable_email
1347-
await stream.send_message(CreateInvoiceAndChargeImmediatelyResponse())
1349+
await stream.send_message(self.invoice_id_response)
13481350

13491351

13501352
class MockApp(UnimplementedAppServiceBase):

tests/test_billing_client.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@
6464
billing_email=EMAIL,
6565
billing_tier=BILLING_TIER,
6666
)
67+
INVOICE_ID_RESPONSE = CreateInvoiceAndChargeImmediatelyResponse(invoice_id=INVOICE_ID)
6768

6869
AUTH_TOKEN = "auth_token"
6970
BILLING_SERVICE_METADATA = {"authorization": f"Bearer {AUTH_TOKEN}"}
@@ -76,6 +77,7 @@ def service() -> MockBilling:
7677
curr_month_usage=CURR_MONTH_USAGE,
7778
invoices_summary=INVOICES_SUMMARY,
7879
billing_info=ORG_BILLING_INFO,
80+
invoice_id_response=INVOICE_ID_RESPONSE,
7981
)
8082

8183

@@ -114,13 +116,14 @@ async def test_create_invoice_and_charge_immediately(self, service: MockBilling)
114116
description = "A short description"
115117
org_id_for_branding = "bar"
116118
disable_email = True
117-
_: CreateInvoiceAndChargeImmediatelyResponse = await client.create_invoice_and_charge_immediately(
119+
invoice_id_response = await client.create_invoice_and_charge_immediately(
118120
org_id_to_charge=org_id,
119121
amount=OUTSTANDING_BALANCE,
120122
description=description,
121123
org_id_for_branding=org_id_for_branding,
122124
disable_email=disable_email,
123125
)
126+
assert invoice_id_response == INVOICE_ID_RESPONSE
124127
assert service.org_id_to_charge == org_id
125128
assert service.description == description
126129
assert service.org_id_for_branding == org_id_for_branding

0 commit comments

Comments
 (0)