diff --git a/server/shell/g2.sh b/server/shell/g2.sh index 874455cf9..3c900d8db 100755 --- a/server/shell/g2.sh +++ b/server/shell/g2.sh @@ -10,14 +10,14 @@ fi $MOCHA_CMD \ 'tests/attach/migrations/*.ts' \ -'tests/attach/newVersion/*.ts' \ -'tests/attach/upgradeOld/*.ts' \ -'tests/attach/others/*.ts' \ -'tests/attach/updateEnts/*.ts' \ -'tests/advanced/check/*.ts' \ -'tests/attach/others/*.ts' -# 'tests/attach/entities/*.ts' \ +# 'tests/attach/newVersion/*.ts' \ +# 'tests/attach/upgradeOld/*.ts' \ +# 'tests/attach/others/*.ts' \ +# 'tests/attach/updateEnts/*.ts' \ +# 'tests/advanced/check/*.ts' \ +# 'tests/attach/others/*.ts' +# # 'tests/attach/entities/*.ts' \ -$MOCHA_CMD 'tests/attach/prepaid/*.ts' \ -'tests/interval/upgrade/*.ts' \ -'tests/interval/multiSub/*.ts' +# $MOCHA_CMD 'tests/attach/prepaid/*.ts' \ +# 'tests/interval/upgrade/*.ts' \ +# 'tests/interval/multiSub/*.ts' diff --git a/server/src/check.ts b/server/src/check.ts index 577955911..f2588162c 100644 --- a/server/src/check.ts +++ b/server/src/check.ts @@ -36,14 +36,14 @@ import { checkCusSubCorrect } from "./utils/checkUtils/checkCustomerCorrect.js"; const { db } = initDrizzle({ maxConnections: 5 }); -const orgSlugs = process.env.ORG_SLUGS!.split(","); +let orgSlugs = process.env.ORG_SLUGS!.split(","); const skipEmails = process.env.SKIP_EMAILS!.split(","); const skipIds = [ "cus_2tXCCwC6iyiftgA6ndSo1Ubb2dx", "DxG668K7uDd0Vahk54YWjvCGVgf2", ]; -// orgSlugs = ["welcome-back-1747670264"]; +orgSlugs = ["nithiiyan_skhanthan_52620936"]; // let customerId = null; const customerId = null; diff --git a/server/src/initHono.ts b/server/src/initHono.ts index 749333882..aa8d0bad3 100644 --- a/server/src/initHono.ts +++ b/server/src/initHono.ts @@ -20,7 +20,10 @@ import { handleOAuthCallback } from "./internal/orgs/handlers/stripeHandlers/han import { honoOrgRouter } from "./internal/orgs/orgRouter.js"; import { platformBetaRouter } from "./internal/platform/platformBeta/platformBetaRouter.js"; import { internalProductRouter } from "./internal/products/internalProductRouter.js"; -import { honoProductRouter } from "./internal/products/productRouter.js"; +import { + honoProductRouter, + migrationRouter, +} from "./internal/products/productRouter.js"; import { auth } from "./utils/auth.js"; const ALLOWED_ORIGINS = [ @@ -92,6 +95,7 @@ export const createHonoApp = () => { app.use("/v1/*", queryMiddleware()); // API Routes + app.route("v1", migrationRouter); app.post("/v1/entitled", ...handleCheck); app.post("/v1/check", ...handleCheck); app.route("v1/customers", cusRouter); diff --git a/server/src/internal/api/apiRouter.ts b/server/src/internal/api/apiRouter.ts index 60a4cf8b4..fe354128e 100644 --- a/server/src/internal/api/apiRouter.ts +++ b/server/src/internal/api/apiRouter.ts @@ -12,13 +12,11 @@ import { expressCusRouter } from "../customers/cusRouter.js"; import { handleCreateBillingPortal } from "../customers/handlers/handleCreateBillingPortal.js"; import { featureRouter } from "../features/featureRouter.js"; import { internalFeatureRouter } from "../features/internalFeatureRouter.js"; -import { migrationRouter } from "../migrations/migrationRouter.js"; import { handleGetOrg } from "../orgs/handlers/handleGetOrg.js"; import { platformRouter } from "../platform/platformLegacy/platformRouter.js"; import { productBetaRouter, productRouter } from "../products/productRouter.js"; import { componentRouter } from "./components/componentRouter.js"; import { entityRouter } from "./entities/entityRouter.js"; -// import { checkRouter } from "./entitled/checkRouter.js"; import { eventsRouter } from "./events/eventRouter.js"; import { usageRouter } from "./events/usageRouter.js"; import { invoiceRouter } from "./invoiceRouter.js"; @@ -45,7 +43,6 @@ apiRouter.use("/internal_features", internalFeatureRouter); apiRouter.use("/usage", usageRouter); apiRouter.use("/entities", entityRouter); -apiRouter.use("/migrations", migrationRouter); // REWARDS apiRouter.use("/reward_programs", rewardProgramRouter); @@ -56,9 +53,6 @@ apiRouter.use("/redemptions", redemptionRouter); apiRouter.use("", attachRouter); apiRouter.use("/cancel", cancelRouter); -// apiRouter.use("/entitled", checkRouter); -// apiRouter.use("/check", checkRouter); - apiRouter.use("/events", eventsRouter); apiRouter.use("/track", eventsRouter); apiRouter.post("/setup_payment", handleSetupPayment); diff --git a/server/src/internal/migrations/migrationRouter.ts b/server/src/internal/migrations/migrationRouter.ts index 47a558f9c..dd92eda55 100644 --- a/server/src/internal/migrations/migrationRouter.ts +++ b/server/src/internal/migrations/migrationRouter.ts @@ -1,162 +1,162 @@ -import { - BillingType, - ErrCode, - ProductNotFoundError, - type UsagePriceConfig, -} from "@autumn/shared"; -import express, { type Router } from "express"; -import { MigrationService } from "@/internal/migrations/MigrationService.js"; -import { constructMigrationJob } from "@/internal/migrations/migrationUtils.js"; -import { ProductService } from "@/internal/products/ProductService.js"; -import { - getBillingType, - pricesOnlyOneOff, -} from "@/internal/products/prices/priceUtils.js"; -import { isFreeProduct } from "@/internal/products/productUtils.js"; -import { JobName } from "@/queue/JobName.js"; -import { addTaskToQueue } from "@/queue/queueUtils.js"; -import RecaseError from "@/utils/errorUtils.js"; -import type { - ExtendedRequest, - ExtendedResponse, -} from "@/utils/models/Request.js"; -import { routeHandler } from "@/utils/routerUtils.js"; -import { findPrepaidPrice } from "../products/prices/priceUtils/findPriceUtils.js"; +// import { +// BillingType, +// ErrCode, +// ProductNotFoundError, +// type UsagePriceConfig, +// } from "@autumn/shared"; +// import express, { type Router } from "express"; +// import { MigrationService } from "@/internal/migrations/MigrationService.js"; +// import { constructMigrationJob } from "@/internal/migrations/migrationUtils.js"; +// import { ProductService } from "@/internal/products/ProductService.js"; +// import { +// getBillingType, +// pricesOnlyOneOff, +// } from "@/internal/products/prices/priceUtils.js"; +// import { isFreeProduct } from "@/internal/products/productUtils.js"; +// import { JobName } from "@/queue/JobName.js"; +// import { addTaskToQueue } from "@/queue/queueUtils.js"; +// import RecaseError from "@/utils/errorUtils.js"; +// import type { +// ExtendedRequest, +// ExtendedResponse, +// } from "@/utils/models/Request.js"; +// import { routeHandler } from "@/utils/routerUtils.js"; +// import { findPrepaidPrice } from "../products/prices/priceUtils/findPriceUtils.js"; -export const migrationRouter: Router = express.Router(); +// export const migrationRouter: Router = express.Router(); -export const handleMigrate = async ( - req: ExtendedRequest, - res?: ExtendedResponse, -) => { - const { orgId, env, db, features } = req; +// export const handleMigrate = async ( +// req: ExtendedRequest, +// res?: ExtendedResponse, +// ) => { +// const { orgId, env, db, features } = req; - const { from_product_id, from_version, to_product_id, to_version } = req.body; +// const { from_product_id, from_version, to_product_id, to_version } = req.body; - const fromProduct = await ProductService.getFull({ - db, - env, - orgId, - idOrInternalId: from_product_id, - version: from_version, - }); +// const fromProduct = await ProductService.getFull({ +// db, +// env, +// orgId, +// idOrInternalId: from_product_id, +// version: from_version, +// }); - const toProduct = await ProductService.getFull({ - db, - env, - orgId, - idOrInternalId: to_product_id, - version: to_version, - }); +// const toProduct = await ProductService.getFull({ +// db, +// env, +// orgId, +// idOrInternalId: to_product_id, +// version: to_version, +// }); - if (isFreeProduct(fromProduct.prices) && !isFreeProduct(toProduct.prices)) { - throw new RecaseError({ - message: `Cannot migrate customers from free product to paid product`, - code: ErrCode.InvalidRequest, - statusCode: 400, - }); - } +// if (isFreeProduct(fromProduct.prices) && !isFreeProduct(toProduct.prices)) { +// throw new RecaseError({ +// message: `Cannot migrate customers from free product to paid product`, +// code: ErrCode.InvalidRequest, +// statusCode: 400, +// }); +// } - // Check if from product is one off, or to product is one off - if ( - pricesOnlyOneOff(fromProduct.prices) || - pricesOnlyOneOff(toProduct.prices) - ) { - const fromIsOneOff = pricesOnlyOneOff(fromProduct.prices); - const msg = fromIsOneOff - ? `${fromProduct.name} is a one off product, cannot migrate customers on it` - : `${toProduct.name} is a one off product, cannot migrate customers to this product`; +// // Check if from product is one off, or to product is one off +// if ( +// pricesOnlyOneOff(fromProduct.prices) || +// pricesOnlyOneOff(toProduct.prices) +// ) { +// const fromIsOneOff = pricesOnlyOneOff(fromProduct.prices); +// const msg = fromIsOneOff +// ? `${fromProduct.name} is a one off product, cannot migrate customers on it` +// : `${toProduct.name} is a one off product, cannot migrate customers to this product`; - throw new RecaseError({ - message: msg, - code: ErrCode.InvalidRequest, - statusCode: 400, - }); - } +// throw new RecaseError({ +// message: msg, +// code: ErrCode.InvalidRequest, +// statusCode: 400, +// }); +// } - // if (fromProduct.is_add_on || toProduct.is_add_on) { - // throw new RecaseError({ - // message: `Cannot migrate customers for add on products`, - // code: ErrCode.InvalidRequest, - // statusCode: 400, - // }); - // } +// // if (fromProduct.is_add_on || toProduct.is_add_on) { +// // throw new RecaseError({ +// // message: `Cannot migrate customers for add on products`, +// // code: ErrCode.InvalidRequest, +// // statusCode: 400, +// // }); +// // } - for (const price of toProduct.prices) { - const billingType = getBillingType(price.config); - if (billingType !== BillingType.UsageInAdvance) continue; +// for (const price of toProduct.prices) { +// const billingType = getBillingType(price.config); +// if (billingType !== BillingType.UsageInAdvance) continue; - const config = price.config as UsagePriceConfig; - const internalFeatureId = config.internal_feature_id; - const feature = features.find((f) => f.internal_id === internalFeatureId); +// const config = price.config as UsagePriceConfig; +// const internalFeatureId = config.internal_feature_id; +// const feature = features.find((f) => f.internal_id === internalFeatureId); - const prepaidPrice = findPrepaidPrice({ - prices: fromProduct.prices, - internalFeatureId, - }); +// const prepaidPrice = findPrepaidPrice({ +// prices: fromProduct.prices, +// internalFeatureId, +// }); - if (!prepaidPrice) { - throw new RecaseError({ - message: `New product has prepaid price for feature ${feature?.name}, but old product does not, can't perform migration`, - code: ErrCode.InvalidRequest, - statusCode: 400, - }); - } - } +// if (!prepaidPrice) { +// throw new RecaseError({ +// message: `New product has prepaid price for feature ${feature?.name}, but old product does not, can't perform migration`, +// code: ErrCode.InvalidRequest, +// statusCode: 400, +// }); +// } +// } - if (!isFreeProduct(fromProduct.prices) && isFreeProduct(toProduct.prices)) { - throw new RecaseError({ - message: `Cannot migrate customers from paid product to free product`, - code: ErrCode.InvalidRequest, - statusCode: 400, - }); - } +// if (!isFreeProduct(fromProduct.prices) && isFreeProduct(toProduct.prices)) { +// throw new RecaseError({ +// message: `Cannot migrate customers from paid product to free product`, +// code: ErrCode.InvalidRequest, +// statusCode: 400, +// }); +// } - if (isFreeProduct(fromProduct.prices) && !isFreeProduct(toProduct.prices)) { - throw new RecaseError({ - message: `Cannot migrate customers from free product to paid product`, - code: ErrCode.InvalidRequest, - statusCode: 400, - }); - } +// if (isFreeProduct(fromProduct.prices) && !isFreeProduct(toProduct.prices)) { +// throw new RecaseError({ +// message: `Cannot migrate customers from free product to paid product`, +// code: ErrCode.InvalidRequest, +// statusCode: 400, +// }); +// } - // 1. Create migration JOB - const migrationJob = constructMigrationJob({ - fromProduct, - toProduct, - }); +// // 1. Create migration JOB +// const migrationJob = constructMigrationJob({ +// fromProduct, +// toProduct, +// }); - await MigrationService.createJob({ - db, - data: migrationJob, - }); +// await MigrationService.createJob({ +// db, +// data: migrationJob, +// }); - if (!fromProduct || !toProduct) { - throw new ProductNotFoundError({ - productId: !fromProduct ? from_product_id : to_product_id, - version: !fromProduct ? from_version : to_version, - }); - } +// if (!fromProduct || !toProduct) { +// throw new ProductNotFoundError({ +// productId: !fromProduct ? from_product_id : to_product_id, +// version: !fromProduct ? from_version : to_version, +// }); +// } - await addTaskToQueue({ - jobName: JobName.Migration, - payload: { - migrationJobId: migrationJob.id, - }, - }); +// await addTaskToQueue({ +// jobName: JobName.Migration, +// payload: { +// migrationJobId: migrationJob.id, +// }, +// }); - if (res) { - res.status(200).json(migrationJob); - } -}; +// if (res) { +// res.status(200).json(migrationJob); +// } +// }; -migrationRouter.post("", async (req: any, res: any) => { - return routeHandler({ - req, - res, - action: "migrate", - handler: async (req: ExtendedRequest, res: ExtendedResponse) => { - await handleMigrate(req, res); - }, - }); -}); +// migrationRouter.post("", async (req: any, res: any) => { +// return routeHandler({ +// req, +// res, +// action: "migrate", +// handler: async (req: ExtendedRequest, res: ExtendedResponse) => { +// await handleMigrate(req, res); +// }, +// }); +// }); diff --git a/server/src/internal/products/productRouter.ts b/server/src/internal/products/productRouter.ts index 1bca6f85b..4a706ebfa 100644 --- a/server/src/internal/products/productRouter.ts +++ b/server/src/internal/products/productRouter.ts @@ -150,8 +150,9 @@ import { handleUpdateProductV2 } from "./handlers/handleUpdateProduct/handleUpda // Create a Hono app for products export const honoProductRouter = new Hono(); +export const migrationRouter = new Hono(); honoProductRouter.post("", ...createProduct); honoProductRouter.post("/:productId", ...handleUpdateProductV2); honoProductRouter.post("/:productId/copy", ...handleCopyProductV2); -honoProductRouter.post("/migrate", ...handleMigrateProductV2); +migrationRouter.post("migrations", ...handleMigrateProductV2); diff --git a/server/tests/_temp/temp1.test.ts b/server/tests/_temp/temp1.test.ts index 1d608e350..0f4a0ca39 100644 --- a/server/tests/_temp/temp1.test.ts +++ b/server/tests/_temp/temp1.test.ts @@ -21,9 +21,25 @@ import { initCustomerV3 } from "@/utils/scriptUtils/testUtils/initCustomerV3.js" import { initProductsV0 } from "@/utils/scriptUtils/testUtils/initProductsV0.js"; // UNCOMMENT FROM HERE -const addOn = constructProduct({ +const pro = constructProduct({ type: "pro", - isAddOn: true, + + items: [ + // constructFeatureItem({ featureId: TestFeature.Words, includedUsage: 100 }), + constructArrearProratedItem({ + featureId: TestFeature.Users, + includedUsage: 1, + pricePerUnit: 10, + config: { + on_increase: OnIncrease.BillImmediately, + on_decrease: OnDecrease.Prorate, + }, + }), + ], +}); +const premium = constructProduct({ + type: "premium", + items: [ // constructFeatureItem({ featureId: TestFeature.Words, includedUsage: 100 }), constructArrearProratedItem({ @@ -38,8 +54,8 @@ const addOn = constructProduct({ ], }); -describe(`${chalk.yellowBright("temp1: Testing add ons")}`, () => { - const customerId = "temp1"; +describe(`${chalk.yellowBright("temp: Testing add ons")}`, () => { + const customerId = "temp"; const autumn: AutumnInt = new AutumnInt({ version: LegacyVersion.v1_4 }); let stripeCli: Stripe; @@ -65,7 +81,7 @@ describe(`${chalk.yellowBright("temp1: Testing add ons")}`, () => { await initProductsV0({ ctx, - products: [addOn], + products: [pro, premium], prefix: customerId, }); @@ -75,31 +91,8 @@ describe(`${chalk.yellowBright("temp1: Testing add ons")}`, () => { test("should attach pro product", async () => { await autumn.attach({ customer_id: customerId, - product_id: addOn.id, + product_id: pro.id, }); - - await autumn.entities.create(customerId, [ - { - id: "1", - name: "Entity 1", - feature_id: TestFeature.Users, - }, - { - id: "2", - name: "Entity 2", - feature_id: TestFeature.Users, - }, - ]); - - await autumn.entities.delete(customerId, "1"); - // await autumn.attach({ - // customer_id: customerId, - // product_id: addOn.id, - // }); - // await autumn.attach({ - // customer_id: customerId, - // product_id: addOn.id, - // }); }); // test("should cancel one add on", async () => {