chore: added setup payment v1 params
This commit is contained in:
@@ -3,6 +3,7 @@ import { CronJob } from "cron";
|
||||
import { initDrizzle } from "../db/initDrizzle.js";
|
||||
import { logger } from "../external/logtail/logtailUtils.js";
|
||||
import { runInvoiceCron } from "./invoiceCron/runInvoiceCron.js";
|
||||
import { runOneOffCleanup } from "./oneoffCron/runOneOffCleanup.js";
|
||||
import { runProductCron } from "./productCron/runProductCron.js";
|
||||
import { runResetCron } from "./resetCron/runResetCron.js";
|
||||
import type { CronContext } from "./utils/CronContext.js";
|
||||
@@ -23,6 +24,7 @@ const main = async () => {
|
||||
runResetCron({ ctx }),
|
||||
runProductCron(),
|
||||
runInvoiceCron({ ctx }),
|
||||
runOneOffCleanup({ ctx }),
|
||||
]);
|
||||
};
|
||||
|
||||
|
||||
49
server/src/cron/oneoffCron/runOneOffCleanup.ts
Normal file
49
server/src/cron/oneoffCron/runOneOffCleanup.ts
Normal file
@@ -0,0 +1,49 @@
|
||||
import { CusProductStatus } from "@autumn/shared";
|
||||
import { getOneOffCustomerProductsToCleanup } from "@/internal/customers/cusProducts/actions/cleanupOneOff/getOneOffToCleanup.js";
|
||||
import { batchUpdateCustomerProducts } from "@/internal/customers/cusProducts/repos/batchUpdateCustomerProducts.js";
|
||||
import type { CronContext } from "../utils/CronContext.js";
|
||||
|
||||
/** Dry-run: fetches one-off customer products eligible for cleanup and logs them without making any updates. */
|
||||
export const runOneOffCleanup = async ({ ctx }: { ctx: CronContext }) => {
|
||||
const { logger } = ctx;
|
||||
try {
|
||||
const toCleanup = await getOneOffCustomerProductsToCleanup({
|
||||
ctx,
|
||||
});
|
||||
|
||||
console.log(`Found ${toCleanup.length} customer products to cleanup`);
|
||||
logger.info(`Found ${toCleanup.length} customer products to cleanup`);
|
||||
|
||||
// Log the results
|
||||
for (const result of toCleanup) {
|
||||
logger.info(
|
||||
`[One-off Cleanup] expiring customer product: ${result.customer_product.id} (${result.org.slug})`,
|
||||
{
|
||||
context: {
|
||||
org_id: result.org.id,
|
||||
org_slug: result.org.slug,
|
||||
customer_id: result.customer.id,
|
||||
env: result.customer.env,
|
||||
},
|
||||
data: {
|
||||
customerProductId: result.customer_product.id,
|
||||
productId: result.product.id,
|
||||
},
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
await batchUpdateCustomerProducts({
|
||||
db: ctx.db,
|
||||
updates: toCleanup.map((result) => ({
|
||||
id: result.customer_product.id,
|
||||
updates: { status: CusProductStatus.Expired },
|
||||
})),
|
||||
});
|
||||
|
||||
logger.info(`Expired ${toCleanup.length} customer products`);
|
||||
console.log(`Expired ${toCleanup.length} customer products`);
|
||||
} catch (error) {
|
||||
console.error("[One-off Cleanup DRY RUN] Error:", error);
|
||||
}
|
||||
};
|
||||
@@ -180,6 +180,15 @@ export class CusProductService {
|
||||
return cusProducts as FullCusProduct[];
|
||||
}
|
||||
|
||||
static async getFull({ db, id }: { db: DrizzleCli; id: string }) {
|
||||
const data = await db.query.customerProducts.findFirst({
|
||||
where: eq(customerProducts.id, id),
|
||||
with: getFullCusProdRelations(),
|
||||
});
|
||||
|
||||
return data as FullCusProduct | undefined;
|
||||
}
|
||||
|
||||
static async getByInternalProductId({
|
||||
db,
|
||||
internalProductId,
|
||||
|
||||
@@ -11,7 +11,7 @@ import {
|
||||
type Price,
|
||||
type Product,
|
||||
} from "@autumn/shared";
|
||||
import type { AutumnContext } from "@/honoUtils/HonoEnv.js";
|
||||
import type { CronContext } from "@/cron/utils/CronContext";
|
||||
|
||||
export type OneOffCleanupResult = {
|
||||
customer_product: CustomerProduct;
|
||||
@@ -36,7 +36,7 @@ export type OneOffCleanupResult = {
|
||||
export const getOneOffCustomerProductsToCleanup = async ({
|
||||
ctx,
|
||||
}: {
|
||||
ctx: AutumnContext;
|
||||
ctx: CronContext;
|
||||
}): Promise<OneOffCleanupResult[]> => {
|
||||
const result = await ctx.db.execute<{
|
||||
customer_product: CustomerProduct;
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
import type { InsertCustomerProduct } from "@shared/models/cusProductModels/cusProductTable";
|
||||
import type { AutumnContext } from "@/honoUtils/HonoEnv";
|
||||
|
||||
export const batchUpdateCustomerProducts = async ({
|
||||
ctx,
|
||||
updates,
|
||||
}: {
|
||||
ctx: AutumnContext;
|
||||
updates: {
|
||||
id: string;
|
||||
updates: Partial<InsertCustomerProduct>;
|
||||
}[];
|
||||
}) => {
|
||||
const { db } = ctx;
|
||||
};
|
||||
@@ -28,6 +28,11 @@ export const AttachParamsV1Schema = BillingParamsBaseV1Schema.extend({
|
||||
description:
|
||||
"When the plan change should take effect. 'immediate' applies now, 'end_of_cycle' schedules for the end of the current billing cycle. By default, upgrades are immediate and downgrades are scheduled.",
|
||||
}),
|
||||
|
||||
checkout_session_params: z.record(z.string(), z.unknown()).optional().meta({
|
||||
description:
|
||||
"Additional parameters to pass into the creation of the Stripe checkout session.",
|
||||
}),
|
||||
});
|
||||
|
||||
export type AttachParamsV1 = z.infer<typeof AttachParamsV1Schema>;
|
||||
|
||||
@@ -15,6 +15,10 @@ export * from "./checkout/prevVersions/checkoutResponseV0";
|
||||
export * from "./common/index";
|
||||
export * from "./openBillingPortal/openBillingPortalParamsV1";
|
||||
export * from "./openBillingPortal/openBillingPortalResponse";
|
||||
// Setup Payment
|
||||
export * from "./setupPayment/setupPaymentParamsV0";
|
||||
export * from "./setupPayment/setupPaymentParamsV1";
|
||||
|
||||
// Update Subscription
|
||||
export * from "./updateSubscription/previewUpdateSubscriptionResponse";
|
||||
export * from "./updateSubscription/updateSubscriptionV0Params";
|
||||
|
||||
27
shared/api/billing/setupPayment/setupPaymentParamsV0.ts
Normal file
27
shared/api/billing/setupPayment/setupPaymentParamsV0.ts
Normal file
@@ -0,0 +1,27 @@
|
||||
import { z } from "zod/v4";
|
||||
import { CustomerDataSchema } from "../../common/customerData";
|
||||
|
||||
export const SetupPaymentParamsSchema = z.object({
|
||||
customer_id: z.string().meta({
|
||||
description: "The ID of the customer",
|
||||
}),
|
||||
success_url: z.string().optional().meta({
|
||||
description:
|
||||
"URL to redirect to after successful payment setup. Must start with either http:// or https://",
|
||||
}),
|
||||
|
||||
checkout_session_params: z.record(z.string(), z.unknown()).optional().meta({
|
||||
description: "Additional parameters for the checkout session",
|
||||
}),
|
||||
|
||||
customer_data: CustomerDataSchema.optional(),
|
||||
});
|
||||
|
||||
export const SetupPaymentResponseV0Schema = z.object({
|
||||
customer_id: z.string().meta({
|
||||
description: "The ID of the customer",
|
||||
}),
|
||||
url: z.string().meta({
|
||||
description: "URL to the payment setup page",
|
||||
}),
|
||||
});
|
||||
26
shared/api/billing/setupPayment/setupPaymentParamsV1.ts
Normal file
26
shared/api/billing/setupPayment/setupPaymentParamsV1.ts
Normal file
@@ -0,0 +1,26 @@
|
||||
import { AttachParamsV1Schema } from "@api/models";
|
||||
import { z } from "zod/v4";
|
||||
|
||||
export const SetupPaymentParamsV1Schema = AttachParamsV1Schema.omit({
|
||||
invoice_mode: true,
|
||||
redirect_mode: true,
|
||||
new_billing_subscription: true,
|
||||
plan_schedule: true,
|
||||
});
|
||||
|
||||
export const SetupPaymentResponseV1Schema = z.object({
|
||||
customer_id: z.string().meta({
|
||||
description: "The ID of the customer",
|
||||
}),
|
||||
|
||||
entity_id: z.string().optional().meta({
|
||||
description:
|
||||
"The ID of the entity the plan (if specified) will be attached to after setup.",
|
||||
}),
|
||||
|
||||
url: z.string().meta({
|
||||
description: "URL to redirect the customer to setup their payment.",
|
||||
}),
|
||||
});
|
||||
|
||||
export type SetupPaymentParamsV1 = z.infer<typeof SetupPaymentParamsV1Schema>;
|
||||
@@ -1,5 +1,4 @@
|
||||
import { z } from "zod/v4";
|
||||
import { CustomerDataSchema } from "../common/customerData.js";
|
||||
|
||||
// Cancel Schemas
|
||||
export const CancelBodySchema = z.object({
|
||||
@@ -68,29 +67,6 @@ export const QueryResultSchema = z.object({
|
||||
}),
|
||||
});
|
||||
|
||||
export const SetupPaymentParamsSchema = z.object({
|
||||
customer_id: z.string().meta({
|
||||
description: "The ID of the customer",
|
||||
}),
|
||||
success_url: z.string().optional().meta({
|
||||
description:
|
||||
"URL to redirect to after successful payment setup. Must start with either http:// or https://",
|
||||
}),
|
||||
customer_data: CustomerDataSchema.optional(),
|
||||
checkout_session_params: z.record(z.string(), z.unknown()).optional().meta({
|
||||
description: "Additional parameters for the checkout session",
|
||||
}),
|
||||
});
|
||||
|
||||
export const SetupPaymentResultSchema = z.object({
|
||||
customer_id: z.string().meta({
|
||||
description: "The ID of the customer",
|
||||
}),
|
||||
url: z.string().meta({
|
||||
description: "URL to the payment setup page",
|
||||
}),
|
||||
});
|
||||
|
||||
export const BillingPortalParamsSchema = z.object({
|
||||
return_url: z.string().optional().meta({
|
||||
description:
|
||||
@@ -111,6 +87,6 @@ export type CancelBody = z.infer<typeof CancelBodySchema>;
|
||||
export type CancelResult = z.infer<typeof CancelResultSchema>;
|
||||
export type QueryParams = z.infer<typeof QueryParamsSchema>;
|
||||
export type QueryResult = z.infer<typeof QueryResultSchema>;
|
||||
export type SetupPaymentParams = z.infer<typeof SetupPaymentParamsSchema>;
|
||||
|
||||
export type BillingPortalParams = z.infer<typeof BillingPortalParamsSchema>;
|
||||
export type BillingPortalResult = z.infer<typeof BillingPortalResultSchema>;
|
||||
|
||||
Reference in New Issue
Block a user