migrated endpoint to new update subscription with cancel action, fixed upgrade schedule detection

This commit is contained in:
John Yeo
2026-01-27 13:09:07 +00:00
parent 98ccf23b02
commit ff4eec9ab4
8 changed files with 69 additions and 31 deletions

View File

@@ -1,7 +1,7 @@
import { Hono } from "hono";
import { handlePreviewUpdateSubscription } from "@/internal/billing/v2/updateSubscription/handlePreviewUpdateSubscription.js";
import { handleAttachPreview } from "@/internal/customers/attach/handleAttachPreview/handleAttachPreview.js";
import { handleCancel } from "@/internal/customers/cancel/handleCancel.js";
import { handleCancelV2 } from "@/internal/customers/cancel/handleCancelV2.js";
import type { HonoEnv } from "../../honoUtils/HonoEnv.js";
import { handleAttach } from "./attach/handleAttach.js";
import { handleCheckoutV2 } from "./checkout/handleCheckoutV2.js";
@@ -13,7 +13,7 @@ export const billingRouter = new Hono<HonoEnv>();
// Legacy
billingRouter.post("/attach/preview", ...handleAttachPreview);
billingRouter.post("/cancel", ...handleCancel);
billingRouter.post("/cancel", ...handleCancelV2);
billingRouter.post("/setup_payment", ...handleSetupPayment);
billingRouter.post("/checkout", ...handleCheckoutV2);

View File

@@ -167,7 +167,15 @@ export const handleUpgradeFlow = async ({
});
}
const schedule = await paramsToCurSubSchedule({ attachParams });
const schedule = await paramsToCurSubSchedule({
attachParams,
scheduleId:
typeof curSub?.schedule === "string"
? curSub.schedule
: typeof curSub?.schedule === "object"
? curSub.schedule?.id
: undefined,
});
if (schedule) {
let removeCusProducts: FullCusProduct[] | undefined;
@@ -186,6 +194,11 @@ export const handleUpgradeFlow = async ({
}
}
console.log(
`REMOVE CUS PRODUCTS: ${removeCusProducts?.map((cp) => cp.product.id).join(", ")}`,
);
console.log(`ADD NEW PRODUCTS: ${addNewProducts}`);
await handleUpgradeFlowSchedule({
ctx,
attachParams,

View File

@@ -9,7 +9,10 @@ import { isFreeProduct } from "@/internal/products/productUtils.js";
import type { AutumnContext } from "../../../../../honoUtils/HonoEnv.js";
import { attachParamsToCurCusProduct } from "../../attachUtils/convertAttachParams.js";
import { paramsToScheduleItems } from "../../mergeUtils/paramsToScheduleItems.js";
import { getCurrentPhaseIndex } from "../../mergeUtils/phaseUtils/phaseUtils.js";
import {
getCurrentPhaseIndex,
logPhases,
} from "../../mergeUtils/phaseUtils/phaseUtils.js";
import { updateCurSchedule } from "../../mergeUtils/updateCurSchedule.js";
export const handleUpgradeFlowSchedule = async ({
@@ -62,7 +65,7 @@ export const handleUpgradeFlowSchedule = async ({
addNewProducts,
});
// await logPhases({ phases: newItems.phases, db: ctx.db });
await logPhases({ phases: newItems.phases, db: ctx.db });
// Should release schedule...
const newCurPhaseIndex = getCurrentPhaseIndex({

View File

@@ -304,10 +304,34 @@ export const paramsToCurSub = async ({
export const paramsToCurSubSchedule = async ({
attachParams,
scheduleId,
}: {
attachParams: AttachParams;
scheduleId?: string;
}) => {
const { stripeCli } = attachParams;
if (scheduleId) {
try {
const schedule = await stripeCli.subscriptionSchedules.retrieve(
scheduleId,
{
expand: ["phases.items.price"],
},
);
if (schedule.status === "canceled" || schedule.status === "released") {
return undefined;
}
return schedule as Stripe.SubscriptionSchedule;
} catch (error: any) {
attachParams.req?.logger.error(
`[paramsToCurSubSchedule] Error getting schedule id: ${scheduleId}, message: ${error.message}`,
);
return undefined;
}
}
const curCusProduct = attachParamsToCurCusProduct({ attachParams });
const subScheduleIds = curCusProduct?.scheduled_ids || [];

View File

@@ -14,14 +14,13 @@ export const handleCancelV2 = createRoute({
// body: CancelBodySchema,
handler: async (c) => {
const ctx = c.get("ctx");
const { db, org, env } = ctx;
const {
customer_id,
product_id,
entity_id,
cancel_immediately = false,
prorate: bodyProrate = true,
customer_product_id,
} = await c.req.json();
const updateSubscriptionBody: UpdateSubscriptionV0Params = {

View File

@@ -69,10 +69,10 @@ describe(`${chalk.yellowBright(`${testCase}: Testing v0.2 / v1.2 response for at
test("should return correct v1.2 responses for attach", async () => {
const autumnV1 = new AutumnInt({ version: ApiVersion.V1_2 });
await autumnV1.cancel({
await autumnV1.subscriptions.update({
customer_id: customerId,
product_id: pro.id,
cancel_immediately: true,
product_id: premium.id,
cancel_action: "uncancel",
});
const attachResponse = await autumnV1.attach({

View File

@@ -17,7 +17,6 @@ import { constructArrearItem } from "@/utils/scriptUtils/constructItem.js";
import { constructProduct } from "@/utils/scriptUtils/createTestProducts.js";
import { initCustomerV3 } from "@/utils/scriptUtils/testUtils/initCustomerV3.js";
import { initProductsV0 } from "@/utils/scriptUtils/testUtils/initProductsV0.js";
import { expectSubToBeCorrect } from "../mergeUtils/expectSubCorrect.js";
// UNCOMMENT FROM HERE
const g1Pro = constructProduct({
@@ -138,18 +137,18 @@ describe(`${chalk.yellowBright("mergedGroup1: Testing products from diff groups"
});
}
test("should cancel scheduled product (g1Pro)", async () => {
await autumn.cancel({
customer_id: customerId,
product_id: g1Pro.id,
cancel_immediately: true,
});
// test("should cancel scheduled product (g1Pro)", async () => {
// await autumn.cancel({
// customer_id: customerId,
// product_id: g1Pro.id,
// cancel_immediately: true,
// });
await expectSubToBeCorrect({
customerId,
db,
org,
env,
});
});
// await expectSubToBeCorrect({
// customerId,
// db,
// org,
// env,
// });
// });
});

View File

@@ -129,11 +129,11 @@ describe(`${chalk.yellowBright("mergedGroup2: Testing products from diff groups"
});
}
test("should cancel scheduled product (g1Pro)", async () => {
await autumn.cancel({
customer_id: customerId,
product_id: g1Pro.id,
cancel_immediately: true,
});
});
// test("should cancel scheduled product (g1Pro)", async () => {
// await autumn.cancel({
// customer_id: customerId,
// product_id: g1Pro.id,
// cancel_immediately: true,
// });
// });
});