From 1ecbddf4c41ec2b87720fd50e642a8f202bb68d5 Mon Sep 17 00:00:00 2001 From: John Yeo Date: Thu, 29 Jan 2026 10:59:26 +0000 Subject: [PATCH] moved billing types to shared package --- .claude/CLAUDE.md | 12 +++ shared/index.ts | 11 +-- .../context/attachBillingContext.ts | 30 +++++++ .../billingModels/context/billingContext.ts | 59 ++++++++++++ shared/models/billingModels/context/index.ts | 3 + .../updateSubscriptionBillingContext.ts | 8 ++ .../existingRollovers.ts | 0 .../{ => customerProduct}/existingUsages.ts | 0 .../billingModels/customerProduct/index.ts | 3 + .../initFullCustomerProductContext.ts | 12 +-- shared/models/billingModels/index.ts | 6 +- shared/models/billingModels/lineItem/index.ts | 2 + .../{invoicingModels => lineItem}/lineItem.ts | 0 .../lineItemContext.ts | 0 .../billingModels/plan/autumnBillingPlan.ts | 89 +++++++++++++++++++ .../models/billingModels/plan/billingPlan.ts | 35 ++++++++ .../billingModels/plan/billingResult.ts | 17 ++++ shared/models/billingModels/plan/index.ts | 3 + shared/models/billingModels/stripe/index.ts | 8 ++ .../billingModels/stripe/stripeBillingPlan.ts | 48 ++++++++++ .../stripe/stripeCheckoutSessionAction.ts | 11 +++ .../stripeDiscountWithCoupon.ts | 0 .../stripe/stripeInvoiceAction.ts | 8 ++ .../stripe/stripeInvoiceItemsAction.ts | 10 +++ .../stripeItemSpec.ts | 0 .../stripe/stripeSubscriptionAction.ts | 33 +++++++ .../stripeSubscriptionScheduleAction.ts | 25 ++++++ .../fixedPriceToLineDescription.ts | 2 +- .../lineItemToPeriodDescription.ts | 2 +- .../usagePriceToLineDescription.ts | 2 +- .../filterUnchangedPricesFromLineItems.ts | 2 +- .../lineItemBuilders/buildLineItem.ts | 4 +- .../lineItemBuilders/fixedPriceToLineItem.ts | 4 +- .../lineItemBuilders/usagePriceToLineItem.ts | 2 +- .../lineItemToCustomerEntitlement.ts | 2 +- .../prorationUtils/applyProration.ts | 2 +- 36 files changed, 428 insertions(+), 27 deletions(-) create mode 100644 shared/models/billingModels/context/attachBillingContext.ts create mode 100644 shared/models/billingModels/context/billingContext.ts create mode 100644 shared/models/billingModels/context/index.ts create mode 100644 shared/models/billingModels/context/updateSubscriptionBillingContext.ts rename shared/models/billingModels/{ => customerProduct}/existingRollovers.ts (100%) rename shared/models/billingModels/{ => customerProduct}/existingUsages.ts (100%) create mode 100644 shared/models/billingModels/customerProduct/index.ts rename shared/models/billingModels/{ => customerProduct}/initFullCustomerProductContext.ts (71%) create mode 100644 shared/models/billingModels/lineItem/index.ts rename shared/models/billingModels/{invoicingModels => lineItem}/lineItem.ts (100%) rename shared/models/billingModels/{invoicingModels => lineItem}/lineItemContext.ts (100%) create mode 100644 shared/models/billingModels/plan/autumnBillingPlan.ts create mode 100644 shared/models/billingModels/plan/billingPlan.ts create mode 100644 shared/models/billingModels/plan/billingResult.ts create mode 100644 shared/models/billingModels/plan/index.ts create mode 100644 shared/models/billingModels/stripe/index.ts create mode 100644 shared/models/billingModels/stripe/stripeBillingPlan.ts create mode 100644 shared/models/billingModels/stripe/stripeCheckoutSessionAction.ts rename shared/models/billingModels/{stripeAdapterModels => stripe}/stripeDiscountWithCoupon.ts (100%) create mode 100644 shared/models/billingModels/stripe/stripeInvoiceAction.ts create mode 100644 shared/models/billingModels/stripe/stripeInvoiceItemsAction.ts rename shared/models/billingModels/{stripeAdapterModels => stripe}/stripeItemSpec.ts (100%) create mode 100644 shared/models/billingModels/stripe/stripeSubscriptionAction.ts create mode 100644 shared/models/billingModels/stripe/stripeSubscriptionScheduleAction.ts diff --git a/.claude/CLAUDE.md b/.claude/CLAUDE.md index 20ddcd9e0..2e7990f1b 100644 --- a/.claude/CLAUDE.md +++ b/.claude/CLAUDE.md @@ -125,3 +125,15 @@ Biome's linter will catch most issues automatically. Focus your attention on: --- Most formatting and common issues are automatically fixed by Biome. Run `npx ultracite fix` before committing to ensure compliance. + +--- + +## Type Checking + +After making edits to server code, run `bun ts` in the `server/` package to check for type errors: + +```bash +cd server && bun ts +``` + +This ensures TypeScript compilation succeeds before committing changes. diff --git a/shared/index.ts b/shared/index.ts index 079ea1d51..5efc35735 100644 --- a/shared/index.ts +++ b/shared/index.ts @@ -96,16 +96,9 @@ export * from "./models/genModels/processorSchemas.js"; // Attach Function Response export * from "./models/attachModels/attachFunctionResponse.js"; -export * from "./models/billingModels/cusProductActions.js"; -export * from "./models/billingModels/existingRollovers.js"; -export * from "./models/billingModels/existingUsages.js"; + +// Billing Models (all from single index) export * from "./models/billingModels/index.js"; -export * from "./models/billingModels/initFullCustomerProductContext.js"; -export * from "./models/billingModels/invoicingModels/lineItem.js"; -// Billing Models -export * from "./models/billingModels/newProductAction.js"; -export * from "./models/billingModels/stripeAdapterModels/stripeDiscountWithCoupon.js"; -export * from "./models/billingModels/stripeAdapterModels/stripeItemSpec.js"; export * from "./models/cusProductModels/cusPriceModels/customerPriceWithCustomerProduct.js"; export * from "./models/migrationModels/migrationErrorTable.js"; export * from "./models/migrationModels/migrationJobTable.js"; diff --git a/shared/models/billingModels/context/attachBillingContext.ts b/shared/models/billingModels/context/attachBillingContext.ts new file mode 100644 index 000000000..e4b34fd82 --- /dev/null +++ b/shared/models/billingModels/context/attachBillingContext.ts @@ -0,0 +1,30 @@ +import type { FullCusProduct, FullProduct } from "@autumn/shared"; +import { z } from "zod/v4"; +import type { BillingContext } from "./billingContext"; + +// Plan timing for attach operations +export const PlanTimingSchema = z.enum(["immediate", "end_of_cycle"]); +export type PlanTiming = z.infer; + +// Checkout mode for attach operations +export const CheckoutModeSchema = z + .enum(["stripe_checkout", "autumn_checkout"]) + .nullable(); + +export type CheckoutMode = z.infer; + +export interface AttachBillingContext extends BillingContext { + // The product being attached + attachProduct: FullProduct; + + // Transition context (only for main recurring products) + currentCustomerProduct?: FullCusProduct; // To transition from + scheduledCustomerProduct?: FullCusProduct; // To delete + + // Timing + planTiming: PlanTiming; + endOfCycleMs?: number; // Only needed if planTiming === "end_of_cycle" + + // Checkout + checkoutMode: CheckoutMode; +} diff --git a/shared/models/billingModels/context/billingContext.ts b/shared/models/billingModels/context/billingContext.ts new file mode 100644 index 000000000..105977f1e --- /dev/null +++ b/shared/models/billingModels/context/billingContext.ts @@ -0,0 +1,59 @@ +import type { + CancelAction, + Entitlement, + FeatureOptions, + FreeTrial, + Price, +} from "@autumn/shared"; +import type Stripe from "stripe"; +import { z } from "zod/v4"; +import type { FullCustomer } from "../../cusModels/fullCusModel"; +import type { FullProduct } from "../../productModels/productModels"; +import type { StripeDiscountWithCoupon } from "../stripe/stripeDiscountWithCoupon"; + +const InvoiceModeSchema = z.object({ + finalizeInvoice: z.boolean().default(false), + enableProductImmediately: z.boolean().default(true), +}); + +export type InvoiceMode = z.infer; + +export interface TrialContext { + freeTrial?: FreeTrial | null; + trialEndsAt: number | null; + customFreeTrial?: FreeTrial; + appliesToBilling: boolean; + cardRequired: boolean; +} + +export interface BillingContext { + fullCustomer: FullCustomer; + fullProducts: FullProduct[]; + + featureQuantities: FeatureOptions[]; + invoiceMode?: InvoiceMode; + + // Timestamps... + currentEpochMs: number; + billingCycleAnchorMs: number | "now"; + resetCycleAnchorMs: number | "now"; + + // Stripe context + stripeCustomer: Stripe.Customer; + stripeSubscription?: Stripe.Subscription; + stripeSubscriptionSchedule?: Stripe.SubscriptionSchedule; + stripeDiscounts?: StripeDiscountWithCoupon[]; + paymentMethod?: Stripe.PaymentMethod; + + // Unforunately, need to add custom prices, custom entitlements and free trial here, because it's determined in the setup step. + // Optional - only needed for custom plan flows + customPrices?: Price[]; + customEnts?: Entitlement[]; + + // Trial context + trialContext?: TrialContext; + isCustom?: boolean; + + // Cancel action (used by update subscription for uncancel) + cancelAction?: CancelAction; +} diff --git a/shared/models/billingModels/context/index.ts b/shared/models/billingModels/context/index.ts new file mode 100644 index 000000000..1ecbd681a --- /dev/null +++ b/shared/models/billingModels/context/index.ts @@ -0,0 +1,3 @@ +export * from "./attachBillingContext"; +export * from "./billingContext"; +export * from "./updateSubscriptionBillingContext"; diff --git a/shared/models/billingModels/context/updateSubscriptionBillingContext.ts b/shared/models/billingModels/context/updateSubscriptionBillingContext.ts new file mode 100644 index 000000000..0e5f1d420 --- /dev/null +++ b/shared/models/billingModels/context/updateSubscriptionBillingContext.ts @@ -0,0 +1,8 @@ +import type { CancelAction, FullCusProduct, FullProduct } from "@autumn/shared"; +import type { BillingContext } from "./billingContext"; + +export interface UpdateSubscriptionBillingContext extends BillingContext { + customerProduct: FullCusProduct; // target customer product + defaultProduct?: FullProduct; // for cancel flows + cancelAction?: CancelAction; // for cancel flows +} diff --git a/shared/models/billingModels/existingRollovers.ts b/shared/models/billingModels/customerProduct/existingRollovers.ts similarity index 100% rename from shared/models/billingModels/existingRollovers.ts rename to shared/models/billingModels/customerProduct/existingRollovers.ts diff --git a/shared/models/billingModels/existingUsages.ts b/shared/models/billingModels/customerProduct/existingUsages.ts similarity index 100% rename from shared/models/billingModels/existingUsages.ts rename to shared/models/billingModels/customerProduct/existingUsages.ts diff --git a/shared/models/billingModels/customerProduct/index.ts b/shared/models/billingModels/customerProduct/index.ts new file mode 100644 index 000000000..2ba445f63 --- /dev/null +++ b/shared/models/billingModels/customerProduct/index.ts @@ -0,0 +1,3 @@ +export * from "./existingRollovers"; +export * from "./existingUsages"; +export * from "./initFullCustomerProductContext"; diff --git a/shared/models/billingModels/initFullCustomerProductContext.ts b/shared/models/billingModels/customerProduct/initFullCustomerProductContext.ts similarity index 71% rename from shared/models/billingModels/initFullCustomerProductContext.ts rename to shared/models/billingModels/customerProduct/initFullCustomerProductContext.ts index 96777ccba..e883f43e5 100644 --- a/shared/models/billingModels/initFullCustomerProductContext.ts +++ b/shared/models/billingModels/customerProduct/initFullCustomerProductContext.ts @@ -1,13 +1,13 @@ -import type { ExistingRollover } from "@models/billingModels/existingRollovers"; import type { FreeTrial } from "@models/productModels/freeTrialModels/freeTrialModels"; -import type { ApiVersion } from "../../api/versionUtils/ApiVersion"; -import type { FullCustomer } from "../cusModels/fullCusModel"; +import type { ApiVersion } from "../../../api/versionUtils/ApiVersion"; +import type { FullCustomer } from "../../cusModels/fullCusModel"; import type { CollectionMethod, CusProductStatus, -} from "../cusProductModels/cusProductEnums"; -import type { FeatureOptions } from "../cusProductModels/cusProductModels"; -import type { FullProduct } from "../productModels/productModels"; +} from "../../cusProductModels/cusProductEnums"; +import type { FeatureOptions } from "../../cusProductModels/cusProductModels"; +import type { FullProduct } from "../../productModels/productModels"; +import type { ExistingRollover } from "./existingRollovers"; import type { ExistingUsages } from "./existingUsages"; export interface InitFullCustomerProductContext { diff --git a/shared/models/billingModels/index.ts b/shared/models/billingModels/index.ts index 16696ba2b..37993803e 100644 --- a/shared/models/billingModels/index.ts +++ b/shared/models/billingModels/index.ts @@ -1 +1,5 @@ -export * from "./invoicingModels/lineItemContext"; +export * from "./context"; +export * from "./customerProduct"; +export * from "./lineItem"; +export * from "./plan"; +export * from "./stripe"; diff --git a/shared/models/billingModels/lineItem/index.ts b/shared/models/billingModels/lineItem/index.ts new file mode 100644 index 000000000..22c20ba2b --- /dev/null +++ b/shared/models/billingModels/lineItem/index.ts @@ -0,0 +1,2 @@ +export * from "./lineItem"; +export * from "./lineItemContext"; diff --git a/shared/models/billingModels/invoicingModels/lineItem.ts b/shared/models/billingModels/lineItem/lineItem.ts similarity index 100% rename from shared/models/billingModels/invoicingModels/lineItem.ts rename to shared/models/billingModels/lineItem/lineItem.ts diff --git a/shared/models/billingModels/invoicingModels/lineItemContext.ts b/shared/models/billingModels/lineItem/lineItemContext.ts similarity index 100% rename from shared/models/billingModels/invoicingModels/lineItemContext.ts rename to shared/models/billingModels/lineItem/lineItemContext.ts diff --git a/shared/models/billingModels/plan/autumnBillingPlan.ts b/shared/models/billingModels/plan/autumnBillingPlan.ts new file mode 100644 index 000000000..76232e64f --- /dev/null +++ b/shared/models/billingModels/plan/autumnBillingPlan.ts @@ -0,0 +1,89 @@ +import { + type AppEnv, + CusProductStatus, + EntitlementSchema, + EntityBalanceSchema, + FeatureOptionsSchema, + FreeTrialSchema, + FullCusProductSchema, + FullCustomerEntitlementSchema, + PriceSchema, +} from "@autumn/shared"; +import { z } from "zod/v4"; +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(), +}); + +export const AutumnBillingPlanSchema = z.object({ + insertCustomerProducts: z.array(FullCusProductSchema), + + updateCustomerProduct: z + .object({ + customerProduct: FullCusProductSchema, + updates: z.object({ + options: z.array(FeatureOptionsSchema).optional(), + status: z.enum(CusProductStatus).optional(), + // 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(), + }), + }) + .optional(), + + updateByStripeScheduleId: z + .object({ + oldScheduleId: z.string(), + newScheduleId: z.string(), + }) + .optional(), + + deleteCustomerProduct: FullCusProductSchema.optional(), // Scheduled product to delete (e.g., when updating while canceling) + + 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(), + + updateCustomerEntitlements: z + .array(UpdateCustomerEntitlementSchema) + .optional(), +}); + +export type AutumnBillingPlan = z.infer; + +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; +}; diff --git a/shared/models/billingModels/plan/billingPlan.ts b/shared/models/billingModels/plan/billingPlan.ts new file mode 100644 index 000000000..aa5f6f3a6 --- /dev/null +++ b/shared/models/billingModels/plan/billingPlan.ts @@ -0,0 +1,35 @@ +import { z } from "zod/v4"; +import { + type StripeBillingPlan, + StripeBillingPlanSchema, + type StripeCheckoutSessionAction, + type StripeInvoiceAction, + type StripeInvoiceItemsAction, + type StripeInvoiceMetadata, + type StripeSubscriptionAction, + type StripeSubscriptionScheduleAction, +} from "../stripe/stripeBillingPlan"; +import { + type AutumnBillingPlan, + AutumnBillingPlanSchema, + type DeferredAutumnBillingPlanData, +} from "./autumnBillingPlan"; + +export type { + AutumnBillingPlan, + DeferredAutumnBillingPlanData, + StripeBillingPlan, + StripeCheckoutSessionAction, + StripeInvoiceAction, + StripeInvoiceItemsAction, + StripeInvoiceMetadata, + StripeSubscriptionAction, + StripeSubscriptionScheduleAction, +}; + +export const BillingPlanSchema = z.object({ + autumn: AutumnBillingPlanSchema, + stripe: StripeBillingPlanSchema, +}); + +export type BillingPlan = z.infer; diff --git a/shared/models/billingModels/plan/billingResult.ts b/shared/models/billingModels/plan/billingResult.ts new file mode 100644 index 000000000..ffe4f543b --- /dev/null +++ b/shared/models/billingModels/plan/billingResult.ts @@ -0,0 +1,17 @@ +import type { PaymentFailureCode } from "@autumn/shared"; +import type Stripe from "stripe"; + +export interface StripeBillingPlanResult { + deferred?: boolean; + stripeInvoice?: Stripe.Invoice; + stripeSubscription?: Stripe.Subscription; + stripeCheckoutSession?: Stripe.Checkout.Session; + requiredAction?: { + code: PaymentFailureCode; + reason: string; + }; +} + +export interface BillingResult { + stripe: StripeBillingPlanResult; +} diff --git a/shared/models/billingModels/plan/index.ts b/shared/models/billingModels/plan/index.ts new file mode 100644 index 000000000..104443024 --- /dev/null +++ b/shared/models/billingModels/plan/index.ts @@ -0,0 +1,3 @@ +export * from "./autumnBillingPlan"; +export * from "./billingPlan"; +export * from "./billingResult"; diff --git a/shared/models/billingModels/stripe/index.ts b/shared/models/billingModels/stripe/index.ts new file mode 100644 index 000000000..9f694c822 --- /dev/null +++ b/shared/models/billingModels/stripe/index.ts @@ -0,0 +1,8 @@ +export * from "./stripeBillingPlan"; +export * from "./stripeCheckoutSessionAction"; +export * from "./stripeDiscountWithCoupon"; +export * from "./stripeInvoiceAction"; +export * from "./stripeInvoiceItemsAction"; +export * from "./stripeItemSpec"; +export * from "./stripeSubscriptionAction"; +export * from "./stripeSubscriptionScheduleAction"; diff --git a/shared/models/billingModels/stripe/stripeBillingPlan.ts b/shared/models/billingModels/stripe/stripeBillingPlan.ts new file mode 100644 index 000000000..ee5c6fd03 --- /dev/null +++ b/shared/models/billingModels/stripe/stripeBillingPlan.ts @@ -0,0 +1,48 @@ +import { z } from "zod/v4"; +import { + type StripeCheckoutSessionAction, + StripeCheckoutSessionActionSchema, +} from "./stripeCheckoutSessionAction"; +import { + type StripeInvoiceAction, + StripeInvoiceActionSchema, +} from "./stripeInvoiceAction"; +import { + type StripeInvoiceItemsAction, + StripeInvoiceItemsActionSchema, +} from "./stripeInvoiceItemsAction"; +import { + type StripeSubscriptionAction, + StripeSubscriptionActionSchema, +} from "./stripeSubscriptionAction"; +import { + type StripeSubscriptionScheduleAction, + StripeSubscriptionScheduleActionSchema, +} from "./stripeSubscriptionScheduleAction"; + +export { + StripeCheckoutSessionActionSchema, + StripeInvoiceActionSchema, + StripeInvoiceItemsActionSchema, + StripeSubscriptionActionSchema, + StripeSubscriptionScheduleActionSchema, + type StripeCheckoutSessionAction, + type StripeInvoiceAction, + type StripeInvoiceItemsAction, + type StripeSubscriptionAction, + type StripeSubscriptionScheduleAction, +}; + +export const StripeBillingPlanSchema = z.object({ + subscriptionAction: StripeSubscriptionActionSchema.optional(), + subscriptionScheduleAction: StripeSubscriptionScheduleActionSchema.optional(), + invoiceAction: StripeInvoiceActionSchema.optional(), + invoiceItemsAction: StripeInvoiceItemsActionSchema.optional(), + checkoutSessionAction: StripeCheckoutSessionActionSchema.optional(), +}); + +export type StripeBillingPlan = z.infer; + +export type StripeInvoiceMetadata = { + autumn_metadata_id: string; +}; diff --git a/shared/models/billingModels/stripe/stripeCheckoutSessionAction.ts b/shared/models/billingModels/stripe/stripeCheckoutSessionAction.ts new file mode 100644 index 000000000..a10b02a9a --- /dev/null +++ b/shared/models/billingModels/stripe/stripeCheckoutSessionAction.ts @@ -0,0 +1,11 @@ +import type Stripe from "stripe"; +import { z } from "zod/v4"; + +export const StripeCheckoutSessionActionSchema = z.object({ + type: z.literal("create"), + params: z.custom(), +}); + +export type StripeCheckoutSessionAction = z.infer< + typeof StripeCheckoutSessionActionSchema +>; diff --git a/shared/models/billingModels/stripeAdapterModels/stripeDiscountWithCoupon.ts b/shared/models/billingModels/stripe/stripeDiscountWithCoupon.ts similarity index 100% rename from shared/models/billingModels/stripeAdapterModels/stripeDiscountWithCoupon.ts rename to shared/models/billingModels/stripe/stripeDiscountWithCoupon.ts diff --git a/shared/models/billingModels/stripe/stripeInvoiceAction.ts b/shared/models/billingModels/stripe/stripeInvoiceAction.ts new file mode 100644 index 000000000..711a2d364 --- /dev/null +++ b/shared/models/billingModels/stripe/stripeInvoiceAction.ts @@ -0,0 +1,8 @@ +import type Stripe from "stripe"; +import { z } from "zod/v4"; + +export const StripeInvoiceActionSchema = z.object({ + addLineParams: z.custom(), +}); + +export type StripeInvoiceAction = z.infer; diff --git a/shared/models/billingModels/stripe/stripeInvoiceItemsAction.ts b/shared/models/billingModels/stripe/stripeInvoiceItemsAction.ts new file mode 100644 index 000000000..eb993b33e --- /dev/null +++ b/shared/models/billingModels/stripe/stripeInvoiceItemsAction.ts @@ -0,0 +1,10 @@ +import type Stripe from "stripe"; +import { z } from "zod/v4"; + +export const StripeInvoiceItemsActionSchema = z.object({ + createInvoiceItems: z.array(z.custom()), +}); + +export type StripeInvoiceItemsAction = z.infer< + typeof StripeInvoiceItemsActionSchema +>; diff --git a/shared/models/billingModels/stripeAdapterModels/stripeItemSpec.ts b/shared/models/billingModels/stripe/stripeItemSpec.ts similarity index 100% rename from shared/models/billingModels/stripeAdapterModels/stripeItemSpec.ts rename to shared/models/billingModels/stripe/stripeItemSpec.ts diff --git a/shared/models/billingModels/stripe/stripeSubscriptionAction.ts b/shared/models/billingModels/stripe/stripeSubscriptionAction.ts new file mode 100644 index 000000000..96d8f3599 --- /dev/null +++ b/shared/models/billingModels/stripe/stripeSubscriptionAction.ts @@ -0,0 +1,33 @@ +import type Stripe from "stripe"; +import { z } from "zod/v4"; + +export const StripeSubscriptionActionSchema = z.discriminatedUnion("type", [ + z.object({ + type: z.literal("create"), + params: z.custom(), + }), + z.object({ + type: z.literal("update"), + stripeSubscriptionId: z.string(), + params: z.custom(), + }), + z.object({ + type: z.literal("cancel_immediately"), + stripeSubscriptionId: z.string(), + }), + z.object({ + type: z.literal("cancel_at_period_end"), + stripeSubscriptionId: z.string(), + }), + z.object({ + type: z.literal("cancel"), + stripeSubscriptionId: z.string(), + }), + z.object({ + type: z.literal("none"), + }), +]); + +export type StripeSubscriptionAction = z.infer< + typeof StripeSubscriptionActionSchema +>; diff --git a/shared/models/billingModels/stripe/stripeSubscriptionScheduleAction.ts b/shared/models/billingModels/stripe/stripeSubscriptionScheduleAction.ts new file mode 100644 index 000000000..d676822f2 --- /dev/null +++ b/shared/models/billingModels/stripe/stripeSubscriptionScheduleAction.ts @@ -0,0 +1,25 @@ +import type Stripe from "stripe"; +import { z } from "zod/v4"; + +export const StripeSubscriptionScheduleActionSchema = z.discriminatedUnion( + "type", + [ + z.object({ + type: z.literal("create"), + params: z.custom(), + }), + z.object({ + type: z.literal("update"), + stripeSubscriptionScheduleId: z.string(), + params: z.custom(), + }), + z.object({ + type: z.literal("release"), + stripeSubscriptionScheduleId: z.string(), + }), + ], +); + +export type StripeSubscriptionScheduleAction = z.infer< + typeof StripeSubscriptionScheduleActionSchema +>; diff --git a/shared/utils/billingUtils/invoicingUtils/descriptionUtils/fixedPriceToLineDescription.ts b/shared/utils/billingUtils/invoicingUtils/descriptionUtils/fixedPriceToLineDescription.ts index 1ca1240cf..cbeb5c3cc 100644 --- a/shared/utils/billingUtils/invoicingUtils/descriptionUtils/fixedPriceToLineDescription.ts +++ b/shared/utils/billingUtils/invoicingUtils/descriptionUtils/fixedPriceToLineDescription.ts @@ -1,4 +1,4 @@ -import type { LineItemContext } from "../../../../models/billingModels/invoicingModels/lineItemContext"; +import type { LineItemContext } from "../../../../models/billingModels/lineItem/lineItemContext"; import type { FixedPriceConfig } from "../../../../models/productModels/priceModels/priceConfig/fixedPriceConfig"; import type { Price } from "../../../../models/productModels/priceModels/priceModels"; import { formatAmount } from "../../../common/formatUtils/formatAmount"; diff --git a/shared/utils/billingUtils/invoicingUtils/descriptionUtils/lineItemToPeriodDescription.ts b/shared/utils/billingUtils/invoicingUtils/descriptionUtils/lineItemToPeriodDescription.ts index 3544e5f96..793cbb43c 100644 --- a/shared/utils/billingUtils/invoicingUtils/descriptionUtils/lineItemToPeriodDescription.ts +++ b/shared/utils/billingUtils/invoicingUtils/descriptionUtils/lineItemToPeriodDescription.ts @@ -1,4 +1,4 @@ -import type { LineItemContext } from "../../../../models/billingModels/invoicingModels/lineItemContext"; +import type { LineItemContext } from "../../../../models/billingModels/lineItem/lineItemContext"; import { formatMsToDate } from "../../../common/formatUtils"; export const lineItemToPeriodDescription = ({ diff --git a/shared/utils/billingUtils/invoicingUtils/descriptionUtils/usagePriceToLineDescription.ts b/shared/utils/billingUtils/invoicingUtils/descriptionUtils/usagePriceToLineDescription.ts index 86020effa..c63cd0703 100644 --- a/shared/utils/billingUtils/invoicingUtils/descriptionUtils/usagePriceToLineDescription.ts +++ b/shared/utils/billingUtils/invoicingUtils/descriptionUtils/usagePriceToLineDescription.ts @@ -1,5 +1,5 @@ import { InternalError } from "../../../../api/errors"; -import type { LineItemContext } from "../../../../models/billingModels/invoicingModels/lineItemContext"; +import type { LineItemContext } from "../../../../models/billingModels/lineItem/lineItemContext"; import { isOneOffPrice } from "../../../productUtils/priceUtils/classifyPriceUtils"; import { featureUsageToDescription } from "./featureUsageToDescription"; import { lineItemToPeriodDescription } from "./lineItemToPeriodDescription"; diff --git a/shared/utils/billingUtils/invoicingUtils/filterUnchangedPricesFromLineItems.ts b/shared/utils/billingUtils/invoicingUtils/filterUnchangedPricesFromLineItems.ts index db3d5664f..6ee8317b1 100644 --- a/shared/utils/billingUtils/invoicingUtils/filterUnchangedPricesFromLineItems.ts +++ b/shared/utils/billingUtils/invoicingUtils/filterUnchangedPricesFromLineItems.ts @@ -1,4 +1,4 @@ -import type { LineItem } from "@models/billingModels/invoicingModels/lineItem"; +import type { LineItem } from "@models/billingModels/lineItem/lineItem"; /** * Filters out line item pairs where a refund and charge item have the same price ID diff --git a/shared/utils/billingUtils/invoicingUtils/lineItemBuilders/buildLineItem.ts b/shared/utils/billingUtils/invoicingUtils/lineItemBuilders/buildLineItem.ts index e212f71c2..1a707f48f 100644 --- a/shared/utils/billingUtils/invoicingUtils/lineItemBuilders/buildLineItem.ts +++ b/shared/utils/billingUtils/invoicingUtils/lineItemBuilders/buildLineItem.ts @@ -4,8 +4,8 @@ import { type LineItem, type LineItemCreate, LineItemSchema, -} from "../../../../models/billingModels/invoicingModels/lineItem"; -import type { LineItemContext } from "../../../../models/billingModels/invoicingModels/lineItemContext"; +} from "../../../../models/billingModels/lineItem/lineItem"; +import type { LineItemContext } from "../../../../models/billingModels/lineItem/lineItemContext"; import { applyProration } from "../prorationUtils/applyProration"; export const buildLineItem = ({ diff --git a/shared/utils/billingUtils/invoicingUtils/lineItemBuilders/fixedPriceToLineItem.ts b/shared/utils/billingUtils/invoicingUtils/lineItemBuilders/fixedPriceToLineItem.ts index e02fe8f32..1ea581db9 100644 --- a/shared/utils/billingUtils/invoicingUtils/lineItemBuilders/fixedPriceToLineItem.ts +++ b/shared/utils/billingUtils/invoicingUtils/lineItemBuilders/fixedPriceToLineItem.ts @@ -1,5 +1,5 @@ -import type { LineItem } from "../../../../models/billingModels/invoicingModels/lineItem"; -import type { LineItemContext } from "../../../../models/billingModels/invoicingModels/lineItemContext"; +import type { LineItem } from "../../../../models/billingModels/lineItem/lineItem"; +import type { LineItemContext } from "../../../../models/billingModels/lineItem/lineItemContext"; import { fixedPriceToDescription } from "../descriptionUtils/fixedPriceToLineDescription"; import { priceToLineAmount } from "../lineItemUtils/priceToLineAmount"; import { buildLineItem } from "./buildLineItem"; diff --git a/shared/utils/billingUtils/invoicingUtils/lineItemBuilders/usagePriceToLineItem.ts b/shared/utils/billingUtils/invoicingUtils/lineItemBuilders/usagePriceToLineItem.ts index ac5de6ee4..82f483585 100644 --- a/shared/utils/billingUtils/invoicingUtils/lineItemBuilders/usagePriceToLineItem.ts +++ b/shared/utils/billingUtils/invoicingUtils/lineItemBuilders/usagePriceToLineItem.ts @@ -1,5 +1,5 @@ import { InternalError } from "../../../../api/errors/base/InternalError"; -import type { LineItemContext } from "../../../../models/billingModels/invoicingModels/lineItemContext"; +import type { LineItemContext } from "../../../../models/billingModels/lineItem/lineItemContext"; import type { FullCusEntWithFullCusProduct } from "../../../../models/cusProductModels/cusEntModels/cusEntWithProduct"; import { cusEntsToPrepaidQuantity } from "../../../cusEntUtils/balanceUtils/cusEntsToPrepaidQuantity"; import { cusEntToCusPrice } from "../../../cusEntUtils/convertCusEntUtils/cusEntToCusPrice"; diff --git a/shared/utils/billingUtils/invoicingUtils/lineItemUtils/lineItemToCustomerEntitlement.ts b/shared/utils/billingUtils/invoicingUtils/lineItemUtils/lineItemToCustomerEntitlement.ts index 95e32a128..a6f5cd130 100644 --- a/shared/utils/billingUtils/invoicingUtils/lineItemUtils/lineItemToCustomerEntitlement.ts +++ b/shared/utils/billingUtils/invoicingUtils/lineItemUtils/lineItemToCustomerEntitlement.ts @@ -1,4 +1,4 @@ -import type { LineItem } from "../../../../models/billingModels/invoicingModels/lineItem"; +import type { LineItem } from "../../../../models/billingModels/lineItem/lineItem"; import type { FullCustomerEntitlement } from "../../../../models/cusProductModels/cusEntModels/cusEntModels"; import type { FullCusProduct } from "../../../../models/cusProductModels/cusProductModels"; import { cusPriceToCusEnt } from "../../../cusPriceUtils/convertCusPriceUtils"; diff --git a/shared/utils/billingUtils/invoicingUtils/prorationUtils/applyProration.ts b/shared/utils/billingUtils/invoicingUtils/prorationUtils/applyProration.ts index 95aeb83d4..466c826a2 100644 --- a/shared/utils/billingUtils/invoicingUtils/prorationUtils/applyProration.ts +++ b/shared/utils/billingUtils/invoicingUtils/prorationUtils/applyProration.ts @@ -1,5 +1,5 @@ import { Decimal } from "decimal.js"; -import type { BillingPeriod } from "../../../../models/billingModels/invoicingModels/lineItemContext"; +import type { BillingPeriod } from "../../../../models/billingModels/lineItem/lineItemContext"; export const applyProration = ({ now,