142 lines
3.7 KiB
TypeScript
142 lines
3.7 KiB
TypeScript
import type { FullCusProduct } from "@models/cusProductModels/cusProductModels.js";
|
|
import {
|
|
isFreeProduct,
|
|
isOneOffProduct,
|
|
} from "../productUtils/classifyProduct/classifyProductUtils";
|
|
import { notNullish, nullish } from "../utils";
|
|
import { cusProductToPrices } from "./convertCusProduct";
|
|
import { ACTIVE_STATUSES } from "./cusProductConstants";
|
|
|
|
export const isCustomerProductOneOff = (cusProduct?: FullCusProduct) => {
|
|
if (!cusProduct) return false;
|
|
|
|
const prices = cusProductToPrices({ cusProduct });
|
|
|
|
return isOneOffProduct({ prices });
|
|
};
|
|
|
|
export const isCustomerProductFree = (cusProduct?: FullCusProduct) => {
|
|
if (!cusProduct) return false;
|
|
const prices = cusProductToPrices({ cusProduct });
|
|
|
|
return isFreeProduct({ prices });
|
|
};
|
|
|
|
export const isCustomerProductCanceling = (cusProduct?: FullCusProduct) => {
|
|
if (!cusProduct) return false;
|
|
|
|
return notNullish(cusProduct.canceled_at);
|
|
};
|
|
|
|
export const isCustomerProductExpired = (
|
|
cusProduct: FullCusProduct,
|
|
params: { nowMs?: number },
|
|
) => {
|
|
const nowMs = params.nowMs ?? Date.now();
|
|
|
|
return (
|
|
isCustomerProductCanceling(cusProduct) &&
|
|
notNullish(cusProduct.ended_at) &&
|
|
nowMs >= cusProduct.ended_at
|
|
);
|
|
};
|
|
|
|
export const isCusProductTrialing = ({
|
|
cusProduct,
|
|
now,
|
|
}: {
|
|
cusProduct?: FullCusProduct;
|
|
now?: number;
|
|
}) => {
|
|
if (!cusProduct) return false;
|
|
|
|
return (
|
|
cusProduct.trial_ends_at && cusProduct.trial_ends_at > (now || Date.now())
|
|
);
|
|
};
|
|
|
|
/**
|
|
* Returns true if the customer product is assigned to the given entity,
|
|
* or if no entity is specified, true if the product is not assigned to any entity.
|
|
* @param cusProduct - The customer product object
|
|
* @param internalEntityId - The internal entity ID to check, or undefined to check for unassigned
|
|
*/
|
|
export const isCusProductOnEntity = ({
|
|
cusProduct,
|
|
internalEntityId,
|
|
}: {
|
|
cusProduct: FullCusProduct;
|
|
internalEntityId?: string;
|
|
}) => {
|
|
return internalEntityId
|
|
? cusProduct.internal_entity_id === internalEntityId
|
|
: nullish(cusProduct.internal_entity_id);
|
|
};
|
|
|
|
/**
|
|
* An "ongoing" customer product is one that:
|
|
* - Is NOT a "one off" (recurring or repeating, not a purchase-once type)
|
|
* - Has an "active" status (see ACTIVE_STATUSES)
|
|
*/
|
|
export const isCusProductOngoing = ({
|
|
cusProduct,
|
|
}: {
|
|
cusProduct: FullCusProduct;
|
|
}) => {
|
|
const isActive = ACTIVE_STATUSES.includes(cusProduct.status);
|
|
|
|
const prices = cusProductToPrices({ cusProduct });
|
|
const isNotOneOff = !isOneOffProduct({ prices });
|
|
|
|
return isActive && isNotOneOff;
|
|
};
|
|
|
|
export const isCustomerProductOnStripeSubscription = ({
|
|
customerProduct,
|
|
stripeSubscriptionId,
|
|
}: {
|
|
customerProduct: FullCusProduct;
|
|
stripeSubscriptionId: string;
|
|
}) => {
|
|
return customerProduct.subscription_ids?.includes(stripeSubscriptionId);
|
|
};
|
|
|
|
export const isCustomerProductOnStripeSubscriptionSchedule = ({
|
|
customerProduct,
|
|
stripeSubscriptionScheduleId,
|
|
}: {
|
|
customerProduct: FullCusProduct;
|
|
stripeSubscriptionScheduleId: string;
|
|
}) => {
|
|
return customerProduct.scheduled_ids?.includes(stripeSubscriptionScheduleId);
|
|
};
|
|
|
|
// Note, this does not CONFIRM that the subscription is active (might be canceled in Stripe...)
|
|
export const cusProductHasSubscription = ({
|
|
cusProduct,
|
|
}: {
|
|
cusProduct: FullCusProduct;
|
|
}) => {
|
|
const prices = cusProductToPrices({ cusProduct });
|
|
|
|
if (isFreeProduct({ prices }) || isOneOffProduct({ prices })) return false;
|
|
|
|
const subId = cusProduct.subscription_ids?.[0];
|
|
|
|
return notNullish(subId);
|
|
};
|
|
|
|
export const customerProductHasSubscriptionSchedule = ({
|
|
cusProduct,
|
|
}: {
|
|
cusProduct: FullCusProduct;
|
|
}) => {
|
|
const prices = cusProductToPrices({ cusProduct });
|
|
|
|
if (isFreeProduct({ prices }) || isOneOffProduct({ prices })) return false;
|
|
|
|
const subId = cusProduct.scheduled_ids?.[0];
|
|
|
|
return notNullish(subId);
|
|
};
|