Files
cfw-autumn/shared/utils/billingUtils/invoicingUtils/cusProductToArrearLineItems.ts
John Yeo 07340cd79b wip
2025-12-16 13:05:57 +00:00

69 lines
2.0 KiB
TypeScript

import type { LineItem } from "../../../models/billingModels/invoicingModels/lineItem";
import type { LineItemContext } from "../../../models/billingModels/invoicingModels/lineItemContext";
import type { FullCusProduct } from "../../../models/cusProductModels/cusProductModels";
import type { Organization } from "../../../models/orgModels/orgTable";
import { cusPriceToCusEntWithCusProduct } from "../../cusPriceUtils/convertCusPriceUtils";
import { orgToCurrency } from "../../orgUtils/convertOrgUtils";
import { isConsumablePrice } from "../../productUtils/priceUtils/classifyPriceUtils";
import { getLineItemBillingPeriod } from "../cycleUtils/getLineItemBillingPeriod";
import { usagePriceToLineItem } from "./lineItemBuilders/usagePriceToLineItem";
export const cusProductToArrearLineItems = ({
cusProduct,
billingCycleAnchor,
testClockFrozenTime,
org,
}: {
cusProduct: FullCusProduct;
billingCycleAnchor: number;
testClockFrozenTime?: number;
org: Organization;
}) => {
let lineItems: LineItem[] = [];
const productName = cusProduct.product.name;
const now = testClockFrozenTime ?? Date.now();
for (const cusPrice of cusProduct.customer_prices) {
const price = cusPrice.price;
if (!isConsumablePrice(price)) continue;
// Calculate billing period
const billingPeriod = getLineItemBillingPeriod({
anchor: billingCycleAnchor,
price,
now,
});
const cusEnt = cusPriceToCusEntWithCusProduct({
cusProduct,
cusPrice,
cusEnts: cusProduct.customer_entitlements,
});
if (!cusEnt) {
throw new Error(
`[cusProductToConsumableLineItems] No cusEnt found for cusPrice: ${cusPrice.id}`,
);
}
const context: LineItemContext = {
price,
product: cusProduct.product,
feature: cusEnt.entitlement.feature,
billingPeriod,
direction: "charge",
billingTiming: "in_arrear",
now,
currency: orgToCurrency({ org }),
};
lineItems.push(usagePriceToLineItem({ cusEnt, context }));
}
lineItems = lineItems.filter((item) => item.amount !== 0);
return lineItems;
};