Skip to content
This repository was archived by the owner on Apr 19, 2023. It is now read-only.

Commit 4f2437f

Browse files
✨ Subscriptions and pricing
1 parent 58d629d commit 4f2437f

File tree

4 files changed

+94
-3
lines changed

4 files changed

+94
-3
lines changed

src/helpers/stripe.ts

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,3 +43,24 @@ export const updateStripeCustomer = async (
4343
export const getStripeInvoices = async (id: string) => {
4444
return await stripe.invoices.list({ customer: id });
4545
};
46+
47+
/**
48+
* Get the details of a customer
49+
* @param id - Stripe customer ID
50+
*/
51+
export const getStripeSubscriptions = async (id: string) => {
52+
return await stripe.subscriptions.list({ customer: id });
53+
};
54+
55+
/**
56+
* Get the details of a customer
57+
* @param id - Stripe customer ID
58+
*/
59+
export const getStripeProductPricing = async (product: string) => {
60+
const plans = await stripe.plans.list({ product });
61+
// If you have a custom plan for a client, don't show that
62+
plans.data = plans.data.filter(
63+
plan => !(plan.nickname || "").toLowerCase().startsWith("custom plan")
64+
);
65+
return plans;
66+
};

src/rest/organization.ts

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,9 @@ import {
2323
getStripeCustomer,
2424
createStripeCustomer,
2525
updateStripeCustomer,
26-
getStripeInvoices
26+
getStripeInvoices,
27+
getStripeSubscriptions,
28+
getStripeProductPricing
2729
} from "../helpers/stripe";
2830
import { customers } from "stripe";
2931

@@ -161,3 +163,30 @@ export const getOrganizationInvoicesForUser = async (
161163
}
162164
throw new Error(ErrorCode.INSUFFICIENT_PERMISSION);
163165
};
166+
167+
export const getOrganizationSubscriptionsForUser = async (
168+
userId: number,
169+
organizationId: number
170+
) => {
171+
if (await can(userId, Authorizations.READ, "organization", organizationId)) {
172+
const organization = await getOrganization(organizationId);
173+
if (organization.stripeCustomerId)
174+
return await getStripeSubscriptions(organization.stripeCustomerId);
175+
throw new Error(ErrorCode.STRIPE_NO_CUSTOMER);
176+
}
177+
throw new Error(ErrorCode.INSUFFICIENT_PERMISSION);
178+
};
179+
180+
export const getOrganizationPricingPlansForUser = async (
181+
userId: number,
182+
organizationId: number,
183+
productId: string
184+
) => {
185+
if (await can(userId, Authorizations.READ, "organization", organizationId)) {
186+
const organization = await getOrganization(organizationId);
187+
if (organization.stripeCustomerId)
188+
return await getStripeProductPricing(productId);
189+
throw new Error(ErrorCode.STRIPE_NO_CUSTOMER);
190+
}
191+
throw new Error(ErrorCode.INSUFFICIENT_PERMISSION);
192+
};

src/routes/index.ts

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,9 @@ import {
2222
routeOrganizationGet,
2323
routeOrganizationBillingGet,
2424
routeOrganizationBillingUpdate,
25-
routeOrganizationInvoicesGet
25+
routeOrganizationInvoicesGet,
26+
routeOrganizationSubscriptionsGet,
27+
routeOrganizationPricingPlansGet
2628
} from "./organizations";
2729
import { authHandler } from "../helpers/middleware";
2830
import {
@@ -154,6 +156,16 @@ const routesOrganization = (app: Application) => {
154156
authHandler,
155157
asyncHandler(routeOrganizationInvoicesGet)
156158
);
159+
app.get(
160+
"/organizations/:id/subscriptions",
161+
authHandler,
162+
asyncHandler(routeOrganizationSubscriptionsGet)
163+
);
164+
app.get(
165+
"/organizations/:id/pricing/:product",
166+
authHandler,
167+
asyncHandler(routeOrganizationPricingPlansGet)
168+
);
157169
};
158170

159171
const routesMembership = (app: Application) => {

src/routes/organizations.ts

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,9 @@ import {
66
getOrganizationForUser,
77
getOrganizationBillingForUser,
88
updateOrganizationBillingForUser,
9-
getOrganizationInvoicesForUser
9+
getOrganizationInvoicesForUser,
10+
getOrganizationSubscriptionsForUser,
11+
getOrganizationPricingPlansForUser
1012
} from "../rest/organization";
1113
import { ErrorCode } from "../interfaces/enum";
1214

@@ -79,3 +81,30 @@ export const routeOrganizationInvoicesGet = async (
7981
await getOrganizationInvoicesForUser(res.locals.token.id, req.params.id)
8082
);
8183
};
84+
85+
export const routeOrganizationSubscriptionsGet = async (
86+
req: Request,
87+
res: Response
88+
) => {
89+
res.json(
90+
await getOrganizationSubscriptionsForUser(
91+
res.locals.token.id,
92+
req.params.id
93+
)
94+
);
95+
};
96+
97+
export const routeOrganizationPricingPlansGet = async (
98+
req: Request,
99+
res: Response
100+
) => {
101+
const product = req.params.product;
102+
if (!product) throw new Error(ErrorCode.MISSING_FIELD);
103+
res.json(
104+
await getOrganizationPricingPlansForUser(
105+
res.locals.token.id,
106+
req.params.id,
107+
product
108+
)
109+
);
110+
};

0 commit comments

Comments
 (0)