chore: ran tests

This commit is contained in:
John Yeo
2025-11-12 10:53:21 +00:00
parent 9e1c1a568a
commit 6e0f93e45b
7 changed files with 182 additions and 190 deletions

View File

@@ -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'

View File

@@ -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;

View File

@@ -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);

View File

@@ -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);

View File

@@ -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);
// },
// });
// });

View File

@@ -150,8 +150,9 @@ import { handleUpdateProductV2 } from "./handlers/handleUpdateProduct/handleUpda
// Create a Hono app for products
export const honoProductRouter = new Hono<HonoEnv>();
export const migrationRouter = new Hono<HonoEnv>();
honoProductRouter.post("", ...createProduct);
honoProductRouter.post("/:productId", ...handleUpdateProductV2);
honoProductRouter.post("/:productId/copy", ...handleCopyProductV2);
honoProductRouter.post("/migrate", ...handleMigrateProductV2);
migrationRouter.post("migrations", ...handleMigrateProductV2);

View File

@@ -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 () => {