diff --git a/server/src/external/stripe/webhookHandlers/handleSubDeleted.ts b/server/src/external/stripe/webhookHandlers/handleSubDeleted.ts index 32b01006f..1e508f336 100644 --- a/server/src/external/stripe/webhookHandlers/handleSubDeleted.ts +++ b/server/src/external/stripe/webhookHandlers/handleSubDeleted.ts @@ -60,15 +60,15 @@ export const handleSubscriptionDeleted = async ({ return; } - // Delete from subscriptions - try { - await SubService.deleteFromStripeId({ - sb, - stripeId: subscription.id, - }); - } catch (error) { - logger.error("Error deleting from subscriptions table", error); - } + // // Delete from subscriptions + // try { + // await SubService.deleteFromStripeId({ + // sb, + // stripeId: subscription.id, + // }); + // } catch (error) { + // logger.error("Error deleting from subscriptions table", error); + // } // Prematurely canceled if cancel_at_period_end is false or cancel_at is more than 20 seconds apart from current_period_end let prematurelyCanceled = subIsPrematurelyCanceled(subscription); diff --git a/server/src/internal/api/customers/products/attachRouter.ts b/server/src/internal/api/customers/products/attachRouter.ts index bd676e97a..f9940c691 100644 --- a/server/src/internal/api/customers/products/attachRouter.ts +++ b/server/src/internal/api/customers/products/attachRouter.ts @@ -345,7 +345,7 @@ attachRouter.post("/attach", async (req: any, res) => { attachParams.metadata = metadata; attachParams.isCustom = isCustom || false; attachParams.disableFreeTrial = disableFreeTrial; - + logger.info( `Customer: ${chalk.yellow( `${attachParams.customer.id} (${attachParams.customer.name})` diff --git a/server/src/internal/customers/add-product/createFullCusProduct.ts b/server/src/internal/customers/add-product/createFullCusProduct.ts index 0bc3bda2b..21e8b3cf4 100644 --- a/server/src/internal/customers/add-product/createFullCusProduct.ts +++ b/server/src/internal/customers/add-product/createFullCusProduct.ts @@ -274,6 +274,7 @@ export const createFullCusProduct = async ({ anchorToUnix, carryExistingUsages = false, carryOverTrial = false, + isDowngrade = false, }: { sb: SupabaseClient; attachParams: InsertCusProductParams; @@ -294,6 +295,7 @@ export const createFullCusProduct = async ({ anchorToUnix?: number; carryExistingUsages?: boolean; carryOverTrial?: boolean; + isDowngrade?: boolean; }) => { disableFreeTrial = attachParams.disableFreeTrial || disableFreeTrial; @@ -380,6 +382,7 @@ export const createFullCusProduct = async ({ entitlements: entitlements, curCusProduct: curCusProduct as FullCusProduct, carryExistingUsages, + isDowngrade, }); // 2. create customer prices diff --git a/server/src/internal/customers/add-product/handleExistingProduct.ts b/server/src/internal/customers/add-product/handleExistingProduct.ts index b0c01905c..25f828e24 100644 --- a/server/src/internal/customers/add-product/handleExistingProduct.ts +++ b/server/src/internal/customers/add-product/handleExistingProduct.ts @@ -24,6 +24,7 @@ import { } from "@/internal/customers/add-product/handleSameProduct.js"; import { pricesOnlyOneOff } from "@/internal/prices/priceUtils.js"; import { getPricesForCusProduct } from "../change-product/scheduleUtils.js"; +import { ACTIVE_STATUSES } from "../products/CusProductService.js"; export const getExistingCusProducts = async ({ product, @@ -43,9 +44,8 @@ export const getExistingCusProducts = async ({ let curMainProduct = cusProducts.find( (cp: any) => cp.product.group === product.group && - // !cp.from_reward && !cp.product.is_add_on && - cp.status === CusProductStatus.Active && + ACTIVE_STATUSES.includes(cp.status) && !isOneOff(cp.customer_prices.map((cp: any) => cp.price)) ); diff --git a/server/src/internal/customers/change-product/handleDowngrade.ts b/server/src/internal/customers/change-product/handleDowngrade.ts index cbcc21f1c..31ad0d75f 100644 --- a/server/src/internal/customers/change-product/handleDowngrade.ts +++ b/server/src/internal/customers/change-product/handleDowngrade.ts @@ -296,6 +296,7 @@ export const handleDowngrade = async ({ subscriptionScheduleIds: scheduledIds, nextResetAt: latestPeriodEnd * 1000, disableFreeTrial: true, + isDowngrade: true, }); if (attachParams.org.api_version! >= APIVersion.v1_1) { diff --git a/server/src/internal/customers/entitlements/cusEntUtils/getExistingUsage.ts b/server/src/internal/customers/entitlements/cusEntUtils/getExistingUsage.ts index 360d59fa4..677886f85 100644 --- a/server/src/internal/customers/entitlements/cusEntUtils/getExistingUsage.ts +++ b/server/src/internal/customers/entitlements/cusEntUtils/getExistingUsage.ts @@ -125,14 +125,16 @@ export const addExistingUsagesToCusEnts = ({ curCusProduct, carryExistingUsages = false, printLogs = false, + isDowngrade = false, }: { cusEnts: CustomerEntitlement[]; entitlements: EntitlementWithFeature[]; curCusProduct: FullCusProduct; carryExistingUsages?: boolean; printLogs?: boolean; + isDowngrade?: boolean; }) => { - if (!curCusProduct) { + if (!curCusProduct || isDowngrade) { return cusEnts; } diff --git a/server/src/internal/customers/products/CusProductService.ts b/server/src/internal/customers/products/CusProductService.ts index 1a860e1c7..09118c2ba 100644 --- a/server/src/internal/customers/products/CusProductService.ts +++ b/server/src/internal/customers/products/CusProductService.ts @@ -11,10 +11,10 @@ import { } from "@autumn/shared"; import { SupabaseClient } from "@supabase/supabase-js"; -const ACTIVE_STATUSES = [ +export const ACTIVE_STATUSES = [ CusProductStatus.Active, CusProductStatus.Scheduled, - // CusProductStatus.PastDue, + CusProductStatus.PastDue, ]; export class CusProductService { diff --git a/server/src/internal/customers/products/attachUtils.ts b/server/src/internal/customers/products/attachUtils.ts index aea308450..c6b770f75 100644 --- a/server/src/internal/customers/products/attachUtils.ts +++ b/server/src/internal/customers/products/attachUtils.ts @@ -71,7 +71,11 @@ const getOrCreateCustomerAndProducts = async ({ internalCustomerId: customer.internal_id, withProduct: true, withPrices: true, - inStatuses: [CusProductStatus.Active, CusProductStatus.Scheduled], + inStatuses: [ + CusProductStatus.Active, + CusProductStatus.Scheduled, + CusProductStatus.PastDue, + ], logger, }); diff --git a/server/test.sh b/server/test.sh index 7ef60ca34..0b0429052 100755 --- a/server/test.sh +++ b/server/test.sh @@ -5,11 +5,11 @@ MOCHA_CMD="npx mocha --parallel --timeout 10000000 --ignore tests/00_setup.ts" # TEST PARALLEL if [ "$1" == "basic-parallel" ]; then MOCHA_PARALLEL=true $MOCHA_SETUP && $MOCHA_CMD \ - tests/basic/*.ts \ - tests/basic/multi-feature/*.ts \ - tests/basic/entities/*.ts \ - # tests/basic/referrals/*.ts \ - # tests/attach/**/*.ts \ + tests/basic/referrals/*.ts \ + tests/attach/**/*.ts \ + # tests/basic/*.ts \ + # tests/basic/multi-feature/*.ts \ + # tests/basic/entities/*.ts \ elif [ "$1" == "advanced-parallel" ]; then diff --git a/server/tests/attach/01_multi_product4.ts b/server/tests/attach/01_multi_product4.ts index a5687f808..3a033a338 100644 --- a/server/tests/attach/01_multi_product4.ts +++ b/server/tests/attach/01_multi_product4.ts @@ -71,6 +71,7 @@ describe( }); it("should reattach premium group 1", async function () { + await timeout(3000); await AutumnCli.attach({ customerId: customerId, productId: attachProducts.premiumGroup1.id, @@ -113,6 +114,7 @@ describe( }); it("should reattach premium group 2 (scheduled should be cancelled)", async function () { + await timeout(3000); let res = await AutumnCli.attach({ customerId: customerId, productId: attachProducts.premiumGroup2.id,