Refactor billing data loading and schema configuration

This update enhances the capability of the billing system to handle different types of billing modes (subscription-based or one-time payments) and introduces an environment variable for configuring the preferred billing mode. It also refactors the data fetching process in the `loadPersonalAccountBillingPageData` and `loadTeamAccountBillingPageData` to retrieve the proper data depending on the chosen billing mode. Detailed documentation was added in README.md to guide the configuration of the billing schema.
This commit is contained in:
giancarlo
2024-04-22 00:35:03 +08:00
parent b393d94fb2
commit ecb20b8917
6 changed files with 596 additions and 26 deletions

View File

@@ -2,25 +2,105 @@ import 'server-only';
import { cache } from 'react';
import { SupabaseClient } from '@supabase/supabase-js';
import { z } from 'zod';
import { getSupabaseServerComponentClient } from '@kit/supabase/server-component-client';
import { Database } from '~/lib/database.types';
/**
* The variable BILLING_MODE represents the billing mode for a service. It can
* have either the value 'subscription' or 'one-time'. If not provided, the default
* value is 'subscription'. The value can be overridden by the environment variable
* BILLING_MODE.
*
* If the value is 'subscription', we fetch the subscription data for the user.
* If the value is 'one-time', we fetch the orders data for the user.
* if none of these suits your needs, please override the below function.
*/
const BILLING_MODE = z
.enum(['subscription', 'one-time'])
.default('subscription')
.parse(process.env.BILLING_MODE);
export const loadTeamAccountBillingPage = cache((accountId: string) => {
const client = getSupabaseServerComponentClient();
// TODO: improve these queries to only load the necessary data
const subscription = client
const data =
BILLING_MODE === 'subscription'
? getSubscriptionData(client, accountId)
: getOrdersData(client, accountId);
const customerId = getBillingCustomerId(client, accountId);
return Promise.all([data, customerId]);
});
/**
* Get the subscription data for the given user.
* @param client
* @param accountId
*/
function getSubscriptionData(
client: SupabaseClient<Database>,
accountId: string,
) {
return client
.from('subscriptions')
.select('*, items: subscription_items !inner (*)')
.eq('account_id', accountId)
.maybeSingle()
.then(({ data }) => data);
.then((response) => {
if (response.error) {
throw response.error;
}
const customerId = client
return response.data;
});
}
/**
* Get the orders data for the given user.
* @param client
* @param accountId
*/
function getOrdersData(client: SupabaseClient<Database>, accountId: string) {
return client
.from('orders')
.select('*, items: order_items !inner (*)')
.eq('account_id', accountId)
.maybeSingle()
.then((response) => {
if (response.error) {
throw response.error;
}
return response.data;
});
}
/**
* Get the billing customer ID for the given user.
* If the user does not have a billing customer ID, it will return null.
* @param client
* @param accountId
*/
function getBillingCustomerId(
client: SupabaseClient<Database>,
accountId: string,
) {
return client
.from('billing_customers')
.select('customer_id')
.eq('account_id', accountId)
.maybeSingle()
.then(({ data }) => data?.customer_id);
.then((response) => {
if (response.error) {
throw response.error;
}
return Promise.all([subscription, customerId]);
});
return response.data?.customer_id;
});
}