Files
sean-brydonGitHubcoderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
224e606439 feat: pbac org billing (#23709)
* refactor layout to not check session

* add actions for orgs + org admins

* update types on actions to be correctly non nullable

* Add tests for utils

* Apply suggestion from @coderabbitai[bot]

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>

* restore lock file

* add permission check action for org authentication managment

* WIP BRANCH

* Git merge fix conflicts

* Fix imports

* intro to pbac team billing

* restore log

* refactor to be a billing portal factory service

* fix merge conflict

* Fix merge conflicts

* Passing test with non hardcoded vars

* fix migration

* Wip

* remove layout permision checks

* Fix type check

* remove logs

* improve error handling and logs

* Fix nits

* nits

* Use push instead of slice for billing tab

* Add permissions to memo

* Fix credits handlers to use PBAC also

* fix imports

---------

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
2025-09-23 14:01:21 +01:00

52 lines
1.5 KiB
TypeScript

import type { NextApiResponse } from "next";
import logger from "@calcom/lib/logger";
import { getStripeCustomerIdFromUserId } from "../../customer";
import stripe from "../../server";
/**
* Billing portal service for individual users
*/
export class UserBillingPortalService {
/**
* Get customer ID for a user
*/
async getCustomerId(userId: number): Promise<string | null> {
return await getStripeCustomerIdFromUserId(userId);
}
/**
* Process billing portal request for a user
*/
async processBillingPortal(userId: number, returnUrl: string, res: NextApiResponse): Promise<void> {
const customerId = await this.getCustomerId(userId);
if (!customerId) {
res.status(404).json({ message: "CustomerId not found" });
return;
}
const billingPortalUrl = await this.createBillingPortalUrl(customerId, returnUrl);
res.redirect(302, billingPortalUrl);
}
/**
* Creates a billing portal URL for a Stripe customer
*/
private async createBillingPortalUrl(customerId: string, returnUrl: string): Promise<string> {
const log = logger.getSubLogger({ prefix: ["createBillingPortalUrl"] });
try {
const portalSession = await stripe.billingPortal.sessions.create({
customer: customerId,
return_url: returnUrl,
});
return portalSession.url;
} catch (e) {
log.error(`Failed to create billing portal session for ${customerId}: ${e}`);
throw new Error("Failed to create billing portal session");
}
}
}