Files
cfw-autumn/shared/utils/cusProductUtils/convertCusProduct.ts
John Yeo b4e5edb2d4 wip
2026-01-14 15:15:18 +00:00

205 lines
5.1 KiB
TypeScript

import { isOneOffPrice } from "@utils/productUtils/priceUtils/classifyPriceUtils.js";
import type { Entity } from "../../models/cusModels/entityModels/entityModels.js";
import type { CustomerEntitlementFilters } from "../../models/cusProductModels/cusEntModels/cusEntModels.js";
import type { FullCusEntWithFullCusProduct } from "../../models/cusProductModels/cusEntModels/cusEntWithProduct.js";
import type { FullCustomerPrice } from "../../models/cusProductModels/cusPriceModels/cusPriceModels.js";
import { CusProductStatus } from "../../models/cusProductModels/cusProductEnums.js";
import type {
CusProduct,
FullCusProduct,
} from "../../models/cusProductModels/cusProductModels.js";
import { ProcessorType } from "../../models/genModels/genEnums.js";
import type { BillingType } from "../../models/productModels/priceModels/priceEnums.js";
import type { FullProduct } from "../../models/productModels/productModels.js";
import { cusEntMatchesEntity } from "../cusEntUtils/filterCusEntUtils.js";
import { sortCusEntsForDeduction } from "../cusEntUtils/sortCusEntsForDeduction.js";
import { getBillingType } from "../productUtils/priceUtils.js";
import { notNullish } from "../utils.js";
export const cusProductsToPrices = ({
cusProducts,
filters,
}: {
cusProducts: FullCusProduct[];
filters?: {
excludeOneOffPrices?: boolean;
};
}) => {
let prices = cusProducts.flatMap((cp) =>
cusProductToPrices({ cusProduct: cp }),
);
if (filters?.excludeOneOffPrices) {
prices = prices.filter((p) => !isOneOffPrice(p));
}
return prices;
};
export const cusProductsToCusPrices = ({
cusProducts,
inStatuses,
billingType,
}: {
cusProducts: FullCusProduct[];
inStatuses?: CusProductStatus[];
billingType?: BillingType;
}) => {
const cusPrices: FullCustomerPrice[] = [];
for (const cusProduct of cusProducts) {
if (inStatuses && !inStatuses.includes(cusProduct.status)) {
continue;
}
let prices = cusProduct.customer_prices;
if (billingType) {
prices = prices.filter(
(cp) => getBillingType(cp.price.config) === billingType,
);
}
cusPrices.push(...prices);
}
return cusPrices;
};
export const cusProductsToCusEnts = ({
cusProducts,
inStatuses = [CusProductStatus.Active, CusProductStatus.PastDue],
reverseOrder = false,
featureId,
internalFeatureId,
featureIds,
entity,
customerEntitlementFilters,
isRefund = false,
}: {
cusProducts: FullCusProduct[];
inStatuses?: CusProductStatus[];
reverseOrder?: boolean;
featureId?: string;
internalFeatureId?: string;
featureIds?: string[];
entity?: Entity;
customerEntitlementFilters?: CustomerEntitlementFilters;
isRefund?: boolean;
}) => {
let cusEnts: FullCusEntWithFullCusProduct[] = [];
for (const cusProduct of cusProducts) {
if (!inStatuses.includes(cusProduct.status)) continue;
cusEnts.push(
...cusProduct.customer_entitlements.map((cusEnt) => ({
...cusEnt,
customer_product: cusProduct,
})),
);
}
if (featureId) {
cusEnts = cusEnts.filter(
(cusEnt) => cusEnt.entitlement.feature.id === featureId,
);
}
if (internalFeatureId) {
cusEnts = cusEnts.filter(
(cusEnt) => cusEnt.entitlement.internal_feature_id === internalFeatureId,
);
}
if (featureIds) {
cusEnts = cusEnts.filter((cusEnt) =>
featureIds.includes(cusEnt.entitlement.feature.id),
);
}
if (entity) {
cusEnts = cusEnts.filter((cusEnt) =>
cusEntMatchesEntity({
cusEnt: cusEnt,
entity,
}),
);
}
sortCusEntsForDeduction({
cusEnts,
reverseOrder,
entityId: entity?.id,
isRefund,
// customerEntitlementFilters,
});
if (
customerEntitlementFilters?.cusEntIds &&
customerEntitlementFilters.cusEntIds.length > 0
) {
cusEnts = cusEnts.filter((cusEnt) =>
customerEntitlementFilters.cusEntIds?.includes(cusEnt.id),
);
}
if (notNullish(customerEntitlementFilters?.interval)) {
cusEnts = cusEnts.filter(
(cusEnt) =>
cusEnt.entitlement.interval === customerEntitlementFilters.interval,
);
}
return cusEnts as FullCusEntWithFullCusProduct[];
};
export const cusProductToPrices = ({
cusProduct,
billingType,
}: {
cusProduct: FullCusProduct;
billingType?: BillingType;
}) => {
let prices = cusProduct.customer_prices.map((cp) => cp.price);
if (billingType) {
prices = prices.filter((p) => getBillingType(p.config) === billingType);
}
return prices;
};
export const cusProductToEnts = ({
cusProduct,
}: {
cusProduct: FullCusProduct;
}) => {
return cusProduct.customer_entitlements.map((ce) => ce.entitlement);
};
export const cusProductToProduct = ({
cusProduct,
}: {
cusProduct: FullCusProduct;
}) => {
return {
...cusProduct.product,
prices: cusProductToPrices({ cusProduct }),
entitlements: cusProductToEnts({ cusProduct }),
free_trial: cusProduct.free_trial,
} as FullProduct;
};
export const cusProductToCusEnts = ({
customerProduct,
}: {
customerProduct: FullCusProduct;
}): FullCusEntWithFullCusProduct[] => {
return customerProduct.customer_entitlements.map((cusEnt) => ({
...cusEnt,
customer_product: customerProduct,
}));
};
export const cusProductToProcessorType = (cusProduct: CusProduct) => {
return cusProduct.processor?.type ?? ProcessorType.Stripe;
};