176 lines
5.4 KiB
TypeScript
176 lines
5.4 KiB
TypeScript
import { CustomLineItemSchema } from "@api/billing/common/customLineItem";
|
|
import type { SetupPaymentParamsV1 } from "@api/billing/setupPayment/setupPaymentParamsV1";
|
|
import type { InsertCustomerEntitlement } from "@autumn/shared";
|
|
import {
|
|
type AppEnv,
|
|
BillingVersion,
|
|
CusProductStatus,
|
|
EntitlementSchema,
|
|
EntityBalanceSchema,
|
|
FeatureOptionsSchema,
|
|
FreeTrialSchema,
|
|
FullCusProductSchema,
|
|
FullCustomerEntitlementSchema,
|
|
FullCustomerPriceSchema,
|
|
type InsertInvoice,
|
|
PriceSchema,
|
|
ReplaceableSchema,
|
|
SubscriptionSchema,
|
|
} from "@autumn/shared";
|
|
import { z } from "zod/v4";
|
|
import type { InsertReplaceable } from "../../cusProductModels/cusEntModels/replaceableTable";
|
|
import type { BillingContext } from "../context/billingContext";
|
|
import { LineItemSchema } from "../lineItem/lineItem";
|
|
import type { BillingPlan } from "./billingPlan";
|
|
|
|
export const UpdateCustomerEntitlementSchema = z.object({
|
|
customerEntitlement: FullCustomerEntitlementSchema,
|
|
balanceChange: z.number().optional(),
|
|
|
|
// For arrear billing:
|
|
updates: z
|
|
.object({
|
|
next_reset_at: z.number().optional(),
|
|
adjustment: z.number().optional(),
|
|
entities: z.record(z.string(), EntityBalanceSchema).optional(),
|
|
balance: z.number().optional(),
|
|
})
|
|
.optional(),
|
|
|
|
deletedReplaceables: z.array(ReplaceableSchema).optional(),
|
|
insertReplaceables: z.array(z.custom<InsertReplaceable>()).optional(),
|
|
});
|
|
|
|
export const CustomerProductUpdateSchema = z.object({
|
|
customerProduct: FullCusProductSchema,
|
|
updates: z.object({
|
|
options: z.array(FeatureOptionsSchema).optional(),
|
|
status: z.enum(CusProductStatus).optional(),
|
|
billing_cycle_anchor_resets_at: z.number().nullish(),
|
|
free_trial_id: z.string().nullish(),
|
|
trial_ends_at: z.number().nullish(),
|
|
// Cancel fields (nullish to support uncancel - setting to null)
|
|
canceled: z.boolean().nullish(),
|
|
canceled_at: z.number().nullish(),
|
|
ended_at: z.number().nullish(),
|
|
scheduled_ids: z.array(z.string()).optional(),
|
|
subscription_ids: z.array(z.string()).optional(),
|
|
updated_at: z.number().optional(),
|
|
billing_version: z.enum(BillingVersion).optional(),
|
|
is_custom: z.boolean().optional(),
|
|
}),
|
|
});
|
|
|
|
export const PatchCustomerProductSchema = z.object({
|
|
customerProduct: FullCusProductSchema,
|
|
insertCustomerEntitlements: z.array(FullCustomerEntitlementSchema),
|
|
insertCustomerPrices: z.array(FullCustomerPriceSchema),
|
|
deleteCustomerEntitlements: z.array(FullCustomerEntitlementSchema),
|
|
deleteCustomerPrices: z.array(FullCustomerPriceSchema),
|
|
});
|
|
|
|
export const AutumnBillingPlanSchema = z.object({
|
|
customerId: z.string(),
|
|
insertCustomerProducts: z.array(FullCusProductSchema),
|
|
|
|
updateCustomerProduct: CustomerProductUpdateSchema.optional(),
|
|
updateCustomerProducts: z.array(CustomerProductUpdateSchema).optional(),
|
|
|
|
updateByStripeScheduleId: z
|
|
.object({
|
|
oldScheduleId: z.string(),
|
|
newScheduleId: z.string(),
|
|
})
|
|
.optional(),
|
|
|
|
schedulePhaseCustomerProductReplacements: z
|
|
.array(
|
|
z.object({
|
|
oldCustomerProductId: z.string(),
|
|
newCustomerProductId: z.string(),
|
|
internalCustomerId: z.string(),
|
|
internalEntityId: z.string().nullish(),
|
|
}),
|
|
)
|
|
.optional(),
|
|
|
|
deleteCustomerProduct: FullCusProductSchema.optional(), // Scheduled product to delete (e.g., when updating while canceling)
|
|
deleteCustomerProducts: z.array(FullCusProductSchema).optional(),
|
|
|
|
customPrices: z.array(PriceSchema).optional(), // Custom prices to insert
|
|
customEntitlements: z.array(EntitlementSchema).optional(), // Custom entitlements to insert
|
|
customFreeTrial: FreeTrialSchema.optional(), // Custom free trial to insert
|
|
|
|
lineItems: z.array(LineItemSchema).optional(),
|
|
customLineItems: z.array(CustomLineItemSchema).optional(),
|
|
|
|
insertCustomerEntitlements: z
|
|
.array(z.custom<InsertCustomerEntitlement>())
|
|
.optional(),
|
|
patchCustomerProducts: z.array(PatchCustomerProductSchema).optional(),
|
|
updateCustomerEntitlements: z
|
|
.array(UpdateCustomerEntitlementSchema)
|
|
.optional(),
|
|
|
|
/**
|
|
* Pre-computed auto top-up rebalance deltas. The compute step sizes paydown + prepaid
|
|
* remainder from the context's FullCustomer snapshot; the executor just loops these
|
|
* and applies each via adjustBalanceDbAndCache (atomic SQL balance + delta).
|
|
*/
|
|
autoTopupRebalance: z
|
|
.object({
|
|
deltas: z.array(
|
|
z.object({
|
|
cusEntId: z.string(),
|
|
featureId: z.string(),
|
|
delta: z.number(),
|
|
}),
|
|
),
|
|
})
|
|
.optional(),
|
|
|
|
// Upsert operations (populated during webhook handling, e.g., checkout.session.completed)
|
|
upsertSubscription: SubscriptionSchema.optional(),
|
|
upsertInvoice: z.custom<InsertInvoice>().optional(),
|
|
|
|
/** Refund plan computed by computeRefundPlan: the amount to refund and source invoice */
|
|
refundPlan: z
|
|
.object({
|
|
amount: z.number(),
|
|
invoice: z.object({
|
|
stripe_id: z.string(),
|
|
total: z.number(),
|
|
current_refunded_amount: z.number(),
|
|
currency: z.string(),
|
|
}),
|
|
})
|
|
.optional(),
|
|
});
|
|
|
|
export type AutumnBillingPlan = z.infer<typeof AutumnBillingPlanSchema>;
|
|
|
|
export type UpdateCustomerEntitlement = z.infer<
|
|
typeof UpdateCustomerEntitlementSchema
|
|
>;
|
|
|
|
export enum StripeBillingStage {
|
|
InvoiceAction = "invoice_action",
|
|
SubscriptionAction = "subscription_action",
|
|
}
|
|
|
|
export type DeferredAutumnBillingPlanData = {
|
|
requestId: string;
|
|
orgId: string;
|
|
env: AppEnv;
|
|
billingPlan: BillingPlan;
|
|
billingContext: BillingContext;
|
|
resumeAfter?: StripeBillingStage;
|
|
};
|
|
|
|
export type DeferredSetupPaymentData = {
|
|
requestId: string;
|
|
orgId: string;
|
|
env: AppEnv;
|
|
params: SetupPaymentParamsV1;
|
|
};
|