Files
cfw-autumn/server/src/internal/customers/cusUtils/getCustomerDetails.ts
2025-09-25 15:50:10 +01:00

213 lines
4.9 KiB
TypeScript

import {
APIVersion,
type AppEnv,
CusEntResponseSchema,
CusExpand,
CusProductStatus,
CusResponseSchema,
CustomerResponseSchema,
cusProductsToCusEnts,
cusProductsToCusPrices,
EntityResponseSchema,
type Feature,
FeatureType,
type FullCusProduct,
type FullCustomer,
type Organization,
type RewardResponse,
} from "@autumn/shared";
import type { DrizzleCli } from "@/db/initDrizzle.js";
import { invoicesToResponse } from "@/internal/invoices/invoiceUtils.js";
import { BREAK_API_VERSION } from "@/utils/constants.js";
import { orgToVersion } from "@/utils/versionUtils.js";
import { featuresToObject } from "./cusFeatureResponseUtils/balancesToFeatureResponse.js";
import { getCusBalances } from "./cusFeatureResponseUtils/getCusBalances.js";
import { processFullCusProducts } from "./cusProductResponseUtils/processFullCusProducts.js";
import { getCusPaymentMethodRes } from "./cusResponseUtils/getCusPaymentMethodRes.js";
import { getCusReferrals } from "./cusResponseUtils/getCusReferrals.js";
import { getCusRewards } from "./cusResponseUtils/getCusRewards.js";
import { getCusUpcomingInvoice } from "./cusResponseUtils/getCusUpcomingInvoice.js";
import { getCusInvoices } from "./cusUtils.js";
export const getCustomerDetails = async ({
db,
customer,
features,
org,
env,
params = {},
logger,
cusProducts,
expand,
reqApiVersion,
}: {
db: DrizzleCli;
customer: FullCustomer;
features: Feature[];
org: Organization;
env: AppEnv;
params?: any;
logger: any;
cusProducts: FullCusProduct[];
expand: CusExpand[];
reqApiVersion?: number;
}) => {
const apiVersion = orgToVersion({
org,
reqApiVersion,
});
const withRewards = expand.includes(CusExpand.Rewards);
const inStatuses = org.config.include_past_due
? [CusProductStatus.Active, CusProductStatus.PastDue]
: [CusProductStatus.Active];
const cusEnts = cusProductsToCusEnts({ cusProducts, inStatuses }) as any;
const balances = await getCusBalances({
cusEntsWithCusProduct: cusEnts,
cusPrices: cusProductsToCusPrices({ cusProducts, inStatuses }),
org,
apiVersion,
});
const subIds = cusProducts.flatMap(
(cp: FullCusProduct) => cp.subscription_ids || [],
);
const subs = customer.subscriptions || [];
const { main, addOns } = await processFullCusProducts({
fullCusProducts: cusProducts,
subs,
org,
apiVersion,
features,
});
if (apiVersion >= APIVersion.v1_1) {
let entList: any = balances.map((b) => {
const isBoolean =
features.find((f: Feature) => f.id === b.feature_id)?.type ===
FeatureType.Boolean;
if (b.unlimited || isBoolean) {
return b;
}
return CusEntResponseSchema.parse({
...b,
usage: b.used,
included_usage: b.allowance,
});
});
const products: any = [...main, ...addOns];
if (apiVersion >= APIVersion.v1_2) {
entList = featuresToObject({
features,
entList,
});
}
const withInvoices = expand.includes(CusExpand.Invoices);
const rewards: RewardResponse | undefined = await getCusRewards({
org,
env,
fullCus: customer,
subIds,
expand,
});
const upcomingInvoice = await getCusUpcomingInvoice({
db,
org,
env,
fullCus: customer,
expand,
});
const referrals = await getCusReferrals({
db,
fullCus: customer,
expand,
});
const paymentMethod = await getCusPaymentMethodRes({
org,
env,
fullCus: customer,
expand,
});
const cusResponse = {
...CusResponseSchema.parse({
...customer,
stripe_id: customer.processor?.id,
features: entList,
products,
// invoices: withInvoices ? invoices : undefined,
invoices: withInvoices
? invoicesToResponse({
invoices: customer.invoices || [],
logger,
})
: undefined,
trials_used: expand.includes(CusExpand.TrialsUsed)
? customer.trials_used
: undefined,
rewards: withRewards ? rewards : undefined,
metadata: customer.metadata,
entities: expand.includes(CusExpand.Entities)
? customer.entities.map((e) =>
EntityResponseSchema.parse({
id: e.id,
name: e.name,
customer_id: customer.id,
feature_id: e.feature_id,
created_at: e.created_at,
env: customer.env,
}),
)
: undefined,
referrals,
payment_method: paymentMethod,
upcoming_invoice: upcomingInvoice,
}),
};
if (params?.with_autumn_id === "true") {
return {
...cusResponse,
autumn_id: customer.internal_id,
};
} else {
return cusResponse;
}
} else {
const withItems = org.config.api_version >= BREAK_API_VERSION;
const processedInvoices = await getCusInvoices({
db,
internalCustomerId: customer.internal_id,
invoices: customer.invoices,
limit: 20,
withItems,
features,
});
return {
customer: CustomerResponseSchema.parse(customer),
products: main,
add_ons: addOns,
entitlements: balances,
invoices: processedInvoices,
trials_used: expand.includes(CusExpand.TrialsUsed)
? customer.trials_used
: undefined,
};
}
};