Files
myeasycms-v2/packages/features/team-accounts/src/server/services/account-per-seat-billing.service.ts
giancarlo b6b9a9462f Add data testing attributes and adapt tests for team account invitations
This commit adds data testing attributes to key elements in the team account invitations features. It also modifies e2e tests to make use of these attributes. Additionally, it introduces minor tweaks to other parts of the system to better facilitate testing, such as adjustments in timeouts and update of some log messages.
2024-04-13 15:27:21 +08:00

203 lines
4.7 KiB
TypeScript

import 'server-only';
import { SupabaseClient } from '@supabase/supabase-js';
import { BillingGatewayService } from '@kit/billing-gateway';
import { getLogger } from '@kit/shared/logger';
import { Database } from '@kit/supabase/database';
export class AccountPerSeatBillingService {
private readonly namespace = 'accounts.per-seat-billing';
constructor(private readonly client: SupabaseClient<Database>) {}
async getPerSeatSubscriptionItem(accountId: string) {
const logger = await getLogger();
const ctx = { accountId, name: this.namespace };
logger.info(
ctx,
`Retrieving per-seat subscription item for account ${accountId}...`,
);
const { data, error } = await this.client
.from('subscriptions')
.select(
`
provider: billing_provider,
id,
subscription_items !inner (
quantity,
id: variant_id,
type
)
`,
)
.eq('account_id', accountId)
.eq('subscription_items.type', 'per_seat')
.maybeSingle();
if (error) {
logger.error(
{
...ctx,
error,
},
`Failed to get per-seat subscription item for account ${accountId}`,
);
throw error;
}
if (!data?.subscription_items) {
logger.info(
ctx,
`Account is not subscribed to a per-seat subscription. Exiting...`,
);
return;
}
logger.info(
ctx,
`Per-seat subscription item found for account ${accountId}. Will update...`,
);
return data;
}
async increaseSeats(accountId: string) {
const logger = await getLogger();
const subscription = await this.getPerSeatSubscriptionItem(accountId);
if (!subscription) {
return;
}
const subscriptionItems = subscription.subscription_items.filter((item) => {
return item.type === 'per_seat';
});
if (!subscriptionItems.length) {
return;
}
const billingGateway = new BillingGatewayService(subscription.provider);
const ctx = {
name: this.namespace,
accountId,
subscriptionItems,
};
logger.info(ctx, `Increasing seats for account ${accountId}...`);
const promises = subscriptionItems.map(async (item) => {
try {
logger.info(
{
name: this.namespace,
accountId,
subscriptionItemId: item.id,
quantity: item.quantity + 1,
},
`Updating subscription item...`,
);
await billingGateway.updateSubscriptionItem({
subscriptionId: subscription.id,
subscriptionItemId: item.id,
quantity: item.quantity + 1,
});
logger.info(
{
name: this.namespace,
accountId,
subscriptionItemId: item.id,
quantity: item.quantity + 1,
},
`Subscription item updated successfully`,
);
} catch (error) {
logger.error(
{
...ctx,
error,
},
`Failed to increase seats for account ${accountId}`,
);
}
});
await Promise.all(promises);
}
async decreaseSeats(accountId: string) {
const logger = await getLogger();
const subscription = await this.getPerSeatSubscriptionItem(accountId);
if (!subscription) {
return;
}
const subscriptionItems = subscription.subscription_items.filter((item) => {
return item.type === 'per_seat';
});
if (!subscriptionItems.length) {
return;
}
const ctx = {
name: this.namespace,
accountId,
subscriptionItems,
};
logger.info(ctx, `Decreasing seats for account ${accountId}...`);
const billingGateway = new BillingGatewayService(subscription.provider);
const promises = subscriptionItems.map(async (item) => {
try {
logger.info(
{
name: this.namespace,
accountId,
subscriptionItemId: item.id,
quantity: item.quantity - 1,
},
`Updating subscription item...`,
);
await billingGateway.updateSubscriptionItem({
subscriptionId: subscription.id,
subscriptionItemId: item.id,
quantity: item.quantity - 1,
});
logger.info(
{
name: this.namespace,
accountId,
subscriptionItemId: item.id,
quantity: item.quantity - 1,
},
`Subscription item updated successfully`,
);
} catch (error) {
logger.error(
{
...ctx,
error,
},
`Failed to decrease seats for account ${accountId}`,
);
}
});
await Promise.all(promises);
}
}