diff --git a/server/tests/unit/shared/getPriceStripeReuseLevel.test.ts b/server/tests/unit/shared/getPriceStripeReuseLevel.test.ts index b4861bb47..745543b75 100644 --- a/server/tests/unit/shared/getPriceStripeReuseLevel.test.ts +++ b/server/tests/unit/shared/getPriceStripeReuseLevel.test.ts @@ -132,6 +132,41 @@ describe("getPriceStripeReuseLevel", () => { expect(level).toBe("none"); }); + test("returns full when both usage prices share configs and lack paired entitlements", () => { + const orphan = usagePrice({ id: "pr_orphan", entitlement_id: null }); + const orphanNew = usagePrice({ id: "pr_orphan_new", entitlement_id: null }); + + const level = getPriceStripeReuseLevel({ + newPrice: orphanNew, + candidatePrice: orphan, + newEntitlements: [], + candidateEntitlements: [], + }); + + expect(level).toBe("full"); + }); + + test("returns stripeProductOnly when both usage prices lack entitlements but configs differ", () => { + const cheaper = usagePrice({ + id: "pr_orphan_cheaper", + entitlement_id: null, + config: { + ...usageConfig, + usage_tiers: [{ amount: 0.05, to: TierInfinite }], + }, + }); + const original = usagePrice({ id: "pr_orphan", entitlement_id: null }); + + const level = getPriceStripeReuseLevel({ + newPrice: cheaper, + candidatePrice: original, + newEntitlements: [], + candidateEntitlements: [], + }); + + expect(level).toBe("stripeProductOnly"); + }); + test("returns full for matching fixed prices regardless of paired entitlements", () => { const fixed: Price = { id: "pr_base", diff --git a/shared/utils/productUtils/priceUtils/match/getPriceStripeReuseLevel.ts b/shared/utils/productUtils/priceUtils/match/getPriceStripeReuseLevel.ts index 0c04b351e..bdd014d29 100644 --- a/shared/utils/productUtils/priceUtils/match/getPriceStripeReuseLevel.ts +++ b/shared/utils/productUtils/priceUtils/match/getPriceStripeReuseLevel.ts @@ -77,6 +77,8 @@ export const getPriceStripeReuseLevel = ({ entitlements: candidateEntitlements, }); + // Both null = same (null) entity scope; both have ents = compare them. + if (!newEnt && !candidateEnt) return "full"; if (!newEnt || !candidateEnt) return "none"; if (entsAreSame(candidateEnt, newEnt)) return "full"; } @@ -98,6 +100,7 @@ export const getPriceStripeReuseLevel = ({ entitlements: candidateEntitlements, }); + if (!newEnt && !candidateEnt) return "stripeProductOnly"; if (!newEnt || !candidateEnt) return "none"; if (newEnt.entity_feature_id !== candidateEnt.entity_feature_id) { return "none";