Files
cfw-autumn/shared/utils/cusProductUtils/featureOptionUtils/convertFeatureOptions.ts
2026-02-25 19:39:10 +00:00

51 lines
1.9 KiB
TypeScript

import type { FeatureOptions } from "@models/cusProductModels/cusProductModels";
import type { EntitlementWithFeature } from "@models/productModels/entModels/entModels";
import { TierBehavior } from "@models/productModels/priceModels/priceConfig/usagePriceConfig";
import type { Price } from "@models/productModels/priceModels/priceModels";
import { priceUtils } from "@utils/productUtils/priceUtils/index";
import { Decimal } from "decimal.js";
/**
* Computes the Stripe subscription-item quantity for a V2 prepaid price.
*
* For **graduated** prices the allowance is encoded as a free leading tier in
* the Stripe price object, so Stripe needs the *total* packs (purchased +
* allowance) to bill correctly.
*
* For **volume** prices the Stripe price has no free tier offset (the allowance
* is tracked purely in Autumn), so only the purchased packs are sent. Stripe
* then applies the single matching tier rate to the purchased quantity only,
* which matches Autumn's own `volumeTiersToLineAmount` calculation.
*/
export const featureOptionsToV2StripeQuantity = ({
featureOptions,
price,
entitlement,
}: {
featureOptions?: FeatureOptions;
price: Price;
entitlement: EntitlementWithFeature;
}) => {
const packsExcludingAllowance =
featureOptions?.upcoming_quantity ?? featureOptions?.quantity;
const isVolume = price.tier_behavior === TierBehavior.VolumeBased;
// Volume: the Stripe price has no free-tier offset, so only send purchased
// packs. Autumn tracks the allowance internally.
if (isVolume) {
return packsExcludingAllowance ?? 0;
}
const allowanceInPacks = priceUtils.convert.toAllowanceInPacks({
price,
entitlement,
});
// Graduated: Stripe needs total packs (purchased + allowance) because the
// V2 price has a free leading tier that covers the allowance.
if (!packsExcludingAllowance) return allowanceInPacks;
return new Decimal(packsExcludingAllowance).add(allowanceInPacks).toNumber();
};