fix: ent rollover null / undefined difference
This commit is contained in:
@@ -13,6 +13,7 @@ import { SupabaseClient } from "@supabase/supabase-js";
|
||||
import Stripe from "stripe";
|
||||
import { billingIntervalToStripe } from "../stripePriceUtils.js";
|
||||
import {
|
||||
formatPrice,
|
||||
getBillingType,
|
||||
getPriceEntitlement,
|
||||
} from "@/internal/products/prices/priceUtils.js";
|
||||
|
||||
@@ -22,6 +22,7 @@ import { createStripeCoupon } from "@/external/stripe/stripeCouponUtils/stripeCo
|
||||
import { PriceService } from "../products/prices/PriceService.js";
|
||||
import { OrgService } from "../orgs/OrgService.js";
|
||||
import { formatPrice } from "../products/prices/priceUtils.js";
|
||||
import { ProductService } from "../products/ProductService.js";
|
||||
|
||||
// Helper function to check if tier structures match
|
||||
const tiersMatch = (oldTiers: any[], newTiers: any[]): boolean => {
|
||||
@@ -83,6 +84,8 @@ const findBestMatch = (oldPrice: Price, newPrices: Price[]): Price | null => {
|
||||
// First, filter by basic characteristics
|
||||
|
||||
const candidates = newPrices.filter((newPrice) => {
|
||||
if (newPrice.id === oldPrice.id) return true;
|
||||
|
||||
const oldConfig = oldPrice.config as UsagePriceConfig;
|
||||
const newConfig = newPrice.config as UsagePriceConfig;
|
||||
|
||||
@@ -96,12 +99,6 @@ const findBestMatch = (oldPrice: Price, newPrices: Price[]): Price | null => {
|
||||
);
|
||||
});
|
||||
|
||||
console.log(
|
||||
"Candidates: ",
|
||||
candidates.map((p) => formatPrice({ price: p }))
|
||||
);
|
||||
console.log("--------------------------------");
|
||||
|
||||
if (candidates.length === 0) return null;
|
||||
if (candidates.length === 1) return candidates[0];
|
||||
|
||||
@@ -128,17 +125,27 @@ export async function runRewardMigrationTask({
|
||||
try {
|
||||
const {
|
||||
oldPrices,
|
||||
newPrices,
|
||||
productId,
|
||||
// newPrices,
|
||||
orgId,
|
||||
env,
|
||||
}: {
|
||||
oldPrices: Price[];
|
||||
newPrices: Price[];
|
||||
product: FullProduct;
|
||||
// newPrices: Price[];
|
||||
productId: string;
|
||||
orgId: string;
|
||||
env: AppEnv;
|
||||
} = payload;
|
||||
|
||||
const fullProduct = await ProductService.getFull({
|
||||
db,
|
||||
idOrInternalId: productId,
|
||||
orgId,
|
||||
env,
|
||||
});
|
||||
|
||||
const newPrices = fullProduct.prices;
|
||||
|
||||
// Get organization for Stripe operations
|
||||
const org = await OrgService.get({
|
||||
db,
|
||||
@@ -167,10 +174,8 @@ export async function runRewardMigrationTask({
|
||||
)
|
||||
);
|
||||
|
||||
// console.log(
|
||||
// "New price IDs: ",
|
||||
// newPrices.map((p) => formatPrice({ price: p }))
|
||||
// );
|
||||
let shouldUpdateReward = false;
|
||||
|
||||
for (const reward of filteredRewards) {
|
||||
const newPriceIds: string[] = [];
|
||||
const unmatchedPrices: string[] = [];
|
||||
@@ -178,8 +183,10 @@ export async function runRewardMigrationTask({
|
||||
if (reward.discount_config?.price_ids) {
|
||||
for (const priceId of reward.discount_config.price_ids) {
|
||||
const oldPrice = oldPrices.find((p) => p.id === priceId);
|
||||
|
||||
// From other product
|
||||
if (!oldPrice) {
|
||||
logger.warn(`Old price ${priceId} not found in oldPrices array`);
|
||||
newPriceIds.push(priceId);
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -187,23 +194,28 @@ export async function runRewardMigrationTask({
|
||||
|
||||
if (matchingNewPrice) {
|
||||
newPriceIds.push(matchingNewPrice.id);
|
||||
const shouldUpdate =
|
||||
matchingNewPrice.config.stripe_price_id !==
|
||||
oldPrice.config.stripe_price_id ||
|
||||
matchingNewPrice.config.stripe_product_id !==
|
||||
oldPrice.config.stripe_product_id;
|
||||
|
||||
if (shouldUpdate) {
|
||||
shouldUpdateReward = true;
|
||||
}
|
||||
} else {
|
||||
unmatchedPrices.push(oldPrice.id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
console.log("New price IDs: ", newPriceIds);
|
||||
throw new Error("test");
|
||||
|
||||
// Update the reward with new price IDs
|
||||
if (newPriceIds.length > 0) {
|
||||
if (shouldUpdateReward) {
|
||||
try {
|
||||
// Check if price IDs have actually changed
|
||||
const originalPriceIds = reward.discount_config?.price_ids || [];
|
||||
const priceIdsChanged =
|
||||
originalPriceIds.length !== newPriceIds.length ||
|
||||
!originalPriceIds.every((id) => newPriceIds.includes(id));
|
||||
// Update Stripe coupon and reward if price IDs have changed
|
||||
console.log(
|
||||
`Updating ${reward.id}, updating reward and Stripe coupon...`
|
||||
);
|
||||
|
||||
// Update the reward in the database
|
||||
const updatedReward = await RewardService.update({
|
||||
@@ -219,74 +231,38 @@ export async function runRewardMigrationTask({
|
||||
},
|
||||
});
|
||||
|
||||
// Update Stripe coupon if price IDs have changed
|
||||
if (priceIdsChanged && org) {
|
||||
try {
|
||||
logger.info(
|
||||
`Price IDs changed for reward ${reward.id}, updating Stripe coupon...`
|
||||
);
|
||||
// Get the price objects for the new price IDs
|
||||
const prices = await PriceService.getInIds({
|
||||
db,
|
||||
ids: newPriceIds,
|
||||
});
|
||||
|
||||
// Get the price objects for the new price IDs
|
||||
const prices = await PriceService.getInIds({
|
||||
db,
|
||||
ids: newPriceIds,
|
||||
});
|
||||
// Recreate the Stripe coupon with new product restrictions
|
||||
await createStripeCoupon({
|
||||
reward: updatedReward,
|
||||
org,
|
||||
env,
|
||||
prices,
|
||||
logger,
|
||||
});
|
||||
|
||||
// Recreate the Stripe coupon with new product restrictions
|
||||
await createStripeCoupon({
|
||||
reward: updatedReward,
|
||||
org,
|
||||
env,
|
||||
prices,
|
||||
logger,
|
||||
});
|
||||
|
||||
logger.info(
|
||||
`Successfully updated Stripe coupon for reward ${reward.id} with new product restrictions`
|
||||
);
|
||||
} catch (stripeError) {
|
||||
logger.error(
|
||||
`Failed to update Stripe coupon for reward ${reward.id}:`,
|
||||
stripeError
|
||||
);
|
||||
// Don't throw here - we want to continue with other rewards
|
||||
}
|
||||
}
|
||||
logger.info(
|
||||
`Updated reward "${reward.name}" (${reward.id}) with ${newPriceIds.length} prices`
|
||||
console.log(
|
||||
`Successfully updated Stripe coupon for reward ${reward.id} with new product restrictions`
|
||||
);
|
||||
} catch (error) {
|
||||
logger.error(`Failed to update reward ${reward.id}:`, error);
|
||||
console.error(`Failed to update reward ${reward.id}:`, error);
|
||||
}
|
||||
}
|
||||
|
||||
if (unmatchedPrices.length > 0) {
|
||||
logger.warn(
|
||||
console.warn(
|
||||
`Unmatched prices for reward ${reward.id}:`,
|
||||
unmatchedPrices
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Migration summary
|
||||
const totalRewards = filteredRewards.length;
|
||||
const updatedRewards = filteredRewards.filter((r) =>
|
||||
r.discount_config?.price_ids?.some(
|
||||
(priceId) =>
|
||||
oldPrices.find((p) => p.id === priceId) &&
|
||||
findBestMatch(oldPrices.find((p) => p.id === priceId)!, newPrices)
|
||||
)
|
||||
).length;
|
||||
|
||||
logger.info("================================");
|
||||
logger.info("REWARD MIGRATION SUMMARY FOR ORG: ", orgId);
|
||||
logger.info("================================");
|
||||
logger.info(`Total rewards processed: ${totalRewards}`);
|
||||
logger.info(`Rewards with successful matches: ${updatedRewards}`);
|
||||
logger.info(`Rewards with no matches: ${totalRewards - updatedRewards}`);
|
||||
logger.info("================================");
|
||||
} catch (error) {
|
||||
logger.error("Error running reward migration task", { error });
|
||||
console.error("Error running reward migration task", { error });
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,6 +14,8 @@ import {
|
||||
Price,
|
||||
FullProduct,
|
||||
FullEntitlement,
|
||||
Rollover,
|
||||
RolloverConfig,
|
||||
} from "@autumn/shared";
|
||||
|
||||
import { addDays } from "date-fns";
|
||||
@@ -76,6 +78,24 @@ export const addTrialToNextResetAt = (
|
||||
return addDays(new Date(nextResetAt), freeTrial.length).getTime();
|
||||
};
|
||||
|
||||
export const rolloversAreSame = ({
|
||||
rollover1,
|
||||
rollover2,
|
||||
}: {
|
||||
rollover1?: RolloverConfig | null;
|
||||
rollover2?: RolloverConfig | null;
|
||||
}) => {
|
||||
if (!rollover1 && !rollover2) return true;
|
||||
if (!rollover1 && rollover2) return false;
|
||||
if (rollover1 && !rollover2) return false;
|
||||
|
||||
return (
|
||||
rollover1!.max == rollover2!.max &&
|
||||
rollover1!.duration == rollover2!.duration &&
|
||||
rollover1!.length == rollover2!.length
|
||||
);
|
||||
};
|
||||
|
||||
export const entsAreSame = (ent1: Entitlement, ent2: Entitlement) => {
|
||||
// 1. Check if they have same internal_feature_id
|
||||
if (ent1.internal_feature_id !== ent2.internal_feature_id) {
|
||||
@@ -121,23 +141,25 @@ export const entsAreSame = (ent1: Entitlement, ent2: Entitlement) => {
|
||||
message: `Usage limit different: ${ent1.usage_limit} !== ${ent2.usage_limit}`,
|
||||
},
|
||||
rollover: {
|
||||
condition:
|
||||
JSON.stringify(ent1.rollover) !== JSON.stringify(ent2.rollover),
|
||||
condition: !rolloversAreSame({
|
||||
rollover1: ent1.rollover,
|
||||
rollover2: ent2.rollover,
|
||||
}),
|
||||
message: `Rollover different: ${ent1.rollover} !== ${ent2.rollover}`,
|
||||
},
|
||||
};
|
||||
|
||||
let entsAreDiff = Object.values(diffs).some((d) => d.condition);
|
||||
|
||||
// if (entsAreDiff) {
|
||||
// console.log("Entitlements different");
|
||||
// console.log(
|
||||
// "Differences:",
|
||||
// Object.values(diffs)
|
||||
// .filter((d) => d.condition)
|
||||
// .map((d) => d.message),
|
||||
// );
|
||||
// }
|
||||
if (entsAreDiff) {
|
||||
console.log("Entitlements different");
|
||||
console.log(
|
||||
"Differences:",
|
||||
Object.values(diffs)
|
||||
.filter((d) => d.condition)
|
||||
.map((d) => d.message)
|
||||
);
|
||||
}
|
||||
return !entsAreDiff;
|
||||
};
|
||||
|
||||
|
||||
@@ -22,202 +22,199 @@ import {
|
||||
} from "../handleCreateProduct.js";
|
||||
import { handleVersionProductV2 } from "../handleVersionProduct.js";
|
||||
import { handleUpdateProductDetails } from "./updateProductDetails.js";
|
||||
import { formatPrice } from "../../prices/priceUtils.js";
|
||||
|
||||
export const handleUpdateProductV2 = async (req: any, res: any) =>
|
||||
routeHandler({
|
||||
req,
|
||||
res,
|
||||
action: "Update product",
|
||||
handler: async () => {
|
||||
const { productId } = req.params;
|
||||
const { version, upsert, disable_version } = req.query;
|
||||
const { orgId, env, logger, db } = req;
|
||||
routeHandler({
|
||||
req,
|
||||
res,
|
||||
action: "Update product",
|
||||
handler: async () => {
|
||||
const { productId } = req.params;
|
||||
const { version, upsert, disable_version } = req.query;
|
||||
const { orgId, env, logger, db } = req;
|
||||
|
||||
const [features, org, fullProduct, rewardPrograms, _defaultProds] =
|
||||
await Promise.all([
|
||||
FeatureService.getFromReq(req),
|
||||
OrgService.getFromReq(req),
|
||||
ProductService.getFull({
|
||||
db,
|
||||
idOrInternalId: productId,
|
||||
orgId,
|
||||
env,
|
||||
version: version ? parseInt(version) : undefined,
|
||||
allowNotFound: upsert === "true",
|
||||
}),
|
||||
RewardProgramService.getByProductId({
|
||||
db,
|
||||
productIds: [productId],
|
||||
orgId,
|
||||
env,
|
||||
}),
|
||||
ProductService.listDefault({
|
||||
db,
|
||||
orgId,
|
||||
env,
|
||||
}),
|
||||
]);
|
||||
const [features, org, fullProduct, rewardPrograms, _defaultProds] =
|
||||
await Promise.all([
|
||||
FeatureService.getFromReq(req),
|
||||
OrgService.getFromReq(req),
|
||||
ProductService.getFull({
|
||||
db,
|
||||
idOrInternalId: productId,
|
||||
orgId,
|
||||
env,
|
||||
version: version ? parseInt(version) : undefined,
|
||||
allowNotFound: upsert === "true",
|
||||
}),
|
||||
RewardProgramService.getByProductId({
|
||||
db,
|
||||
productIds: [productId],
|
||||
orgId,
|
||||
env,
|
||||
}),
|
||||
ProductService.listDefault({
|
||||
db,
|
||||
orgId,
|
||||
env,
|
||||
}),
|
||||
]);
|
||||
|
||||
if (!fullProduct) {
|
||||
if (upsert === "true") {
|
||||
await handleCreateProduct(req, res);
|
||||
return;
|
||||
}
|
||||
if (!fullProduct) {
|
||||
if (upsert === "true") {
|
||||
await handleCreateProduct(req, res);
|
||||
return;
|
||||
}
|
||||
|
||||
throw new RecaseError({
|
||||
message: "Product not found",
|
||||
code: ErrCode.ProductNotFound,
|
||||
statusCode: 404,
|
||||
});
|
||||
}
|
||||
throw new RecaseError({
|
||||
message: "Product not found",
|
||||
code: ErrCode.ProductNotFound,
|
||||
statusCode: 404,
|
||||
});
|
||||
}
|
||||
|
||||
const cusProductsCurVersion =
|
||||
await CusProductService.getByInternalProductId({
|
||||
db,
|
||||
internalProductId: fullProduct.internal_id,
|
||||
});
|
||||
const cusProductsCurVersion =
|
||||
await CusProductService.getByInternalProductId({
|
||||
db,
|
||||
internalProductId: fullProduct.internal_id,
|
||||
});
|
||||
|
||||
const cusProductExists = cusProductsCurVersion.length > 0;
|
||||
const cusProductExists = cusProductsCurVersion.length > 0;
|
||||
|
||||
// console.log("Updating product", {
|
||||
// id: fullProduct.id,
|
||||
// body: req.body,
|
||||
// });
|
||||
await disableCurrentDefault({
|
||||
req,
|
||||
newProduct: {
|
||||
...fullProduct,
|
||||
...req.body,
|
||||
},
|
||||
items:
|
||||
req.body.items ||
|
||||
mapToProductItems({
|
||||
prices: fullProduct.prices,
|
||||
entitlements: fullProduct.entitlements,
|
||||
features,
|
||||
}),
|
||||
freeTrial: req.body.free_trial || fullProduct.free_trial || null,
|
||||
});
|
||||
// console.log("Updating product", {
|
||||
// id: fullProduct.id,
|
||||
// body: req.body,
|
||||
// });
|
||||
await disableCurrentDefault({
|
||||
req,
|
||||
newProduct: {
|
||||
...fullProduct,
|
||||
...req.body,
|
||||
},
|
||||
items:
|
||||
req.body.items ||
|
||||
mapToProductItems({
|
||||
prices: fullProduct.prices,
|
||||
entitlements: fullProduct.entitlements,
|
||||
features,
|
||||
}),
|
||||
freeTrial: req.body.free_trial || fullProduct.free_trial || null,
|
||||
});
|
||||
|
||||
await handleUpdateProductDetails({
|
||||
db,
|
||||
curProduct: fullProduct,
|
||||
newProduct: UpdateProductSchema.parse(req.body),
|
||||
newFreeTrial: req.body.free_trial,
|
||||
items: req.body.items,
|
||||
org,
|
||||
rewardPrograms,
|
||||
logger,
|
||||
});
|
||||
await handleUpdateProductDetails({
|
||||
db,
|
||||
curProduct: fullProduct,
|
||||
newProduct: UpdateProductSchema.parse(req.body),
|
||||
newFreeTrial: req.body.free_trial,
|
||||
items: req.body.items,
|
||||
org,
|
||||
rewardPrograms,
|
||||
logger,
|
||||
});
|
||||
|
||||
const itemsExist = notNullish(req.body.items);
|
||||
if (cusProductExists && itemsExist) {
|
||||
if (disable_version === "true") {
|
||||
throw new RecaseError({
|
||||
message: "Cannot auto save product as there are existing customers",
|
||||
code: ErrCode.InvalidRequest,
|
||||
statusCode: 400,
|
||||
});
|
||||
}
|
||||
const itemsExist = notNullish(req.body.items);
|
||||
if (cusProductExists && itemsExist) {
|
||||
if (disable_version === "true") {
|
||||
throw new RecaseError({
|
||||
message: "Cannot auto save product as there are existing customers",
|
||||
code: ErrCode.InvalidRequest,
|
||||
statusCode: 400,
|
||||
});
|
||||
}
|
||||
|
||||
const { itemsSame, freeTrialsSame } = productsAreSame({
|
||||
newProductV2: req.body,
|
||||
curProductV1: fullProduct,
|
||||
features,
|
||||
});
|
||||
const productSame = itemsSame && freeTrialsSame;
|
||||
const { itemsSame, freeTrialsSame } = productsAreSame({
|
||||
newProductV2: req.body,
|
||||
curProductV1: fullProduct,
|
||||
features,
|
||||
});
|
||||
const productSame = itemsSame && freeTrialsSame;
|
||||
|
||||
if (!productSame) {
|
||||
await handleVersionProductV2({
|
||||
req,
|
||||
res,
|
||||
latestProduct: fullProduct,
|
||||
org,
|
||||
env,
|
||||
items: req.body.items,
|
||||
freeTrial: req.body.free_trial,
|
||||
});
|
||||
return;
|
||||
}
|
||||
res.status(200).send(fullProduct);
|
||||
return;
|
||||
}
|
||||
if (!productSame) {
|
||||
await handleVersionProductV2({
|
||||
req,
|
||||
res,
|
||||
latestProduct: fullProduct,
|
||||
org,
|
||||
env,
|
||||
items: req.body.items,
|
||||
freeTrial: req.body.free_trial,
|
||||
});
|
||||
return;
|
||||
}
|
||||
res.status(200).send(fullProduct);
|
||||
return;
|
||||
}
|
||||
|
||||
const { items, free_trial } = req.body;
|
||||
const { items, free_trial } = req.body;
|
||||
|
||||
if (free_trial !== undefined) {
|
||||
await validateOneOffTrial({
|
||||
prices: fullProduct.prices,
|
||||
freeTrial: free_trial,
|
||||
});
|
||||
}
|
||||
if (free_trial !== undefined) {
|
||||
await validateOneOffTrial({
|
||||
prices: fullProduct.prices,
|
||||
freeTrial: free_trial,
|
||||
});
|
||||
}
|
||||
|
||||
const { prices, entitlements } = await handleNewProductItems({
|
||||
db,
|
||||
curPrices: fullProduct.prices,
|
||||
curEnts: fullProduct.entitlements,
|
||||
newItems: items,
|
||||
features,
|
||||
product: fullProduct,
|
||||
logger,
|
||||
isCustom: false,
|
||||
});
|
||||
await handleNewProductItems({
|
||||
db,
|
||||
curPrices: fullProduct.prices,
|
||||
curEnts: fullProduct.entitlements,
|
||||
newItems: items,
|
||||
features,
|
||||
product: fullProduct,
|
||||
logger,
|
||||
isCustom: false,
|
||||
});
|
||||
|
||||
if (free_trial !== undefined) {
|
||||
await validateOneOffTrial({
|
||||
prices,
|
||||
freeTrial: free_trial,
|
||||
});
|
||||
// New full product
|
||||
const newFullProduct = await ProductService.getFull({
|
||||
db,
|
||||
idOrInternalId: fullProduct.id,
|
||||
orgId,
|
||||
env,
|
||||
});
|
||||
|
||||
await handleNewFreeTrial({
|
||||
db,
|
||||
curFreeTrial: fullProduct.free_trial,
|
||||
newFreeTrial: free_trial,
|
||||
internalProductId: fullProduct.internal_id,
|
||||
isCustom: false,
|
||||
product: fullProduct,
|
||||
});
|
||||
}
|
||||
if (free_trial !== undefined) {
|
||||
await validateOneOffTrial({
|
||||
prices: newFullProduct.prices,
|
||||
freeTrial: free_trial,
|
||||
});
|
||||
|
||||
await initProductInStripe({
|
||||
db,
|
||||
product: {
|
||||
...fullProduct,
|
||||
prices,
|
||||
entitlements,
|
||||
} as FullProduct,
|
||||
org,
|
||||
env,
|
||||
logger,
|
||||
});
|
||||
await handleNewFreeTrial({
|
||||
db,
|
||||
curFreeTrial: fullProduct.free_trial,
|
||||
newFreeTrial: free_trial,
|
||||
internalProductId: fullProduct.internal_id,
|
||||
isCustom: false,
|
||||
product: fullProduct,
|
||||
});
|
||||
}
|
||||
|
||||
logger.info("Adding task to queue to detect base variant");
|
||||
await addTaskToQueue({
|
||||
jobName: JobName.DetectBaseVariant,
|
||||
payload: {
|
||||
curProduct: {
|
||||
...fullProduct,
|
||||
prices: prices.length > 0 ? prices : fullProduct.prices,
|
||||
entitlements,
|
||||
},
|
||||
},
|
||||
});
|
||||
// New full product
|
||||
await initProductInStripe({
|
||||
db,
|
||||
product: newFullProduct,
|
||||
org,
|
||||
env,
|
||||
logger,
|
||||
});
|
||||
|
||||
await addTaskToQueue({
|
||||
jobName: JobName.RewardMigration,
|
||||
payload: {
|
||||
oldPrices: fullProduct.prices,
|
||||
newPrices: prices,
|
||||
product: {
|
||||
...fullProduct,
|
||||
prices,
|
||||
entitlements: getEntsWithFeature({ ents: entitlements, features }),
|
||||
},
|
||||
orgId: org.id,
|
||||
env,
|
||||
},
|
||||
});
|
||||
res.status(200).send({ message: "Product updated" });
|
||||
return;
|
||||
},
|
||||
});
|
||||
logger.info("Adding task to queue to detect base variant");
|
||||
await addTaskToQueue({
|
||||
jobName: JobName.DetectBaseVariant,
|
||||
payload: {
|
||||
curProduct: newFullProduct,
|
||||
},
|
||||
});
|
||||
|
||||
await addTaskToQueue({
|
||||
jobName: JobName.RewardMigration,
|
||||
payload: {
|
||||
oldPrices: fullProduct.prices,
|
||||
productId: fullProduct.id,
|
||||
orgId: org.id,
|
||||
env,
|
||||
},
|
||||
});
|
||||
res.status(200).send({ message: "Product updated" });
|
||||
return;
|
||||
},
|
||||
});
|
||||
|
||||
@@ -13,6 +13,7 @@ import { validateProductItems } from "../validateProductItems.js";
|
||||
import { FeatureService } from "@/internal/features/FeatureService.js";
|
||||
import { isFeatureItem } from "./getItemType.js";
|
||||
import { DrizzleCli } from "@/db/initDrizzle.js";
|
||||
import { formatPrice } from "../../prices/priceUtils.js";
|
||||
|
||||
const updateDbPricesAndEnts = async ({
|
||||
db,
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import RecaseError from "@/utils/errorUtils.js";
|
||||
import {
|
||||
AllowanceType,
|
||||
BillingInterval,
|
||||
@@ -19,13 +20,12 @@ import {
|
||||
OnIncrease,
|
||||
OnDecrease,
|
||||
FeatureUsageType,
|
||||
features,
|
||||
} from "@autumn/shared";
|
||||
import { generateId, notNullish, nullish } from "@/utils/genUtils.js";
|
||||
import { pricesAreSame } from "@/internal/products/prices/priceInitUtils.js";
|
||||
import { entsAreSame } from "../../entitlements/entitlementUtils.js";
|
||||
import { getBillingType } from "@/internal/products/prices/priceUtils.js";
|
||||
import RecaseError from "@/utils/errorUtils.js";
|
||||
|
||||
import {
|
||||
isFeatureItem,
|
||||
isFeaturePriceItem,
|
||||
|
||||
@@ -4,40 +4,41 @@ import { JobName } from "./JobName.js";
|
||||
import { QueueManager } from "./QueueManager.js";
|
||||
|
||||
export interface Payloads {
|
||||
[JobName.RewardMigration]: {
|
||||
oldPrices: Price[];
|
||||
newPrices: Price[];
|
||||
product: FullProduct;
|
||||
[JobName.RewardMigration]: {
|
||||
oldPrices: Price[];
|
||||
productId: string;
|
||||
// newPrices: Price[];
|
||||
// product: FullProduct;
|
||||
orgId: string;
|
||||
env: AppEnv;
|
||||
};
|
||||
};
|
||||
[key: string]: any;
|
||||
}
|
||||
|
||||
export const addTaskToQueue = async <T extends keyof Payloads>({
|
||||
jobName,
|
||||
payload,
|
||||
jobName,
|
||||
payload,
|
||||
}: {
|
||||
jobName: T;
|
||||
payload: Payloads[T];
|
||||
jobName: T;
|
||||
payload: Payloads[T];
|
||||
}) => {
|
||||
try {
|
||||
const queue = await QueueManager.getQueue({ useBackup: false });
|
||||
await queue.add(jobName as string, payload);
|
||||
} catch (error: any) {
|
||||
try {
|
||||
console.log(`Adding ${jobName} to backup queue`);
|
||||
const backupQueue = await QueueManager.getQueue({ useBackup: true });
|
||||
await backupQueue.add(jobName as string, payload);
|
||||
} catch (error: any) {
|
||||
throw new RecaseError({
|
||||
message: `Failed to add ${jobName} to queue (backup)`,
|
||||
code: "EVENT_QUEUE_ERROR",
|
||||
statusCode: 500,
|
||||
data: {
|
||||
message: error.message,
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
try {
|
||||
const queue = await QueueManager.getQueue({ useBackup: false });
|
||||
await queue.add(jobName as string, payload);
|
||||
} catch (error: any) {
|
||||
try {
|
||||
console.log(`Adding ${jobName} to backup queue`);
|
||||
const backupQueue = await QueueManager.getQueue({ useBackup: true });
|
||||
await backupQueue.add(jobName as string, payload);
|
||||
} catch (error: any) {
|
||||
throw new RecaseError({
|
||||
message: `Failed to add ${jobName} to queue (backup)`,
|
||||
code: "EVENT_QUEUE_ERROR",
|
||||
statusCode: 500,
|
||||
data: {
|
||||
message: error.message,
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user