mirror of
https://github.com/fluxerapp/fluxer
synced 2026-10-18 21:45:31 +09:00
fix(api): keep premium through cancellation and refund pix exactly (#1995)
This commit is contained in:
1 parent
29e244d4eb
commit
21e806b991
8 files changed
+91
-22
No files matched your search
@@ -128,19 +128,39 @@ function chooseEffectiveSubscription(user: User, subscriptions: Array<Stripe.Sub
|
||||
return sorted[0]!;
|
||||
}
|
||||
|
||||
function trackMostRecentTerminalSubscription(
|
||||
current: Stripe.Subscription | null,
|
||||
candidate: Stripe.Subscription,
|
||||
): Stripe.Subscription | null {
|
||||
if (!candidate.ended_at) {
|
||||
return current;
|
||||
}
|
||||
if (!current || (current.ended_at ?? 0) < candidate.ended_at) {
|
||||
return candidate;
|
||||
}
|
||||
return current;
|
||||
}
|
||||
|
||||
async function getEffectiveActiveStripeSubscription(
|
||||
stripe: Stripe,
|
||||
user: User,
|
||||
): Promise<{
|
||||
subscription: Stripe.Subscription | null;
|
||||
activeCount: number;
|
||||
mostRecentTerminalSubscription: Stripe.Subscription | null;
|
||||
}> {
|
||||
const subscriptionsById = new Map<string, Stripe.Subscription>();
|
||||
let mostRecentTerminalSubscription: Stripe.Subscription | null = null;
|
||||
if (user.stripeSubscriptionId) {
|
||||
try {
|
||||
const subscription = await stripe.subscriptions.retrieve(user.stripeSubscriptionId);
|
||||
if (canProvisionPremiumFromSubscriptionStatus(subscription.status)) {
|
||||
subscriptionsById.set(subscription.id, subscription);
|
||||
} else {
|
||||
mostRecentTerminalSubscription = trackMostRecentTerminalSubscription(
|
||||
mostRecentTerminalSubscription,
|
||||
subscription,
|
||||
);
|
||||
}
|
||||
} catch (error) {
|
||||
Logger.warn(
|
||||
@@ -162,6 +182,10 @@ async function getEffectiveActiveStripeSubscription(
|
||||
});
|
||||
for (const subscription of subscriptions.data) {
|
||||
if (!canProvisionPremiumFromSubscriptionStatus(subscription.status)) {
|
||||
mostRecentTerminalSubscription = trackMostRecentTerminalSubscription(
|
||||
mostRecentTerminalSubscription,
|
||||
subscription,
|
||||
);
|
||||
continue;
|
||||
}
|
||||
subscriptionsById.set(subscription.id, subscription);
|
||||
@@ -182,11 +206,13 @@ async function getEffectiveActiveStripeSubscription(
|
||||
return {
|
||||
subscription: null,
|
||||
activeCount: 0,
|
||||
mostRecentTerminalSubscription,
|
||||
};
|
||||
}
|
||||
return {
|
||||
subscription: chooseEffectiveSubscription(user, activeSubscriptions),
|
||||
activeCount: activeSubscriptions.length,
|
||||
mostRecentTerminalSubscription,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -203,15 +229,29 @@ async function reconcileUserPremiumStateFromStripe(params: {userId: UserID; stri
|
||||
if (!user.stripeSubscriptionId && !user.stripeCustomerId) {
|
||||
return {status: 'skipped', patchedFields: []};
|
||||
}
|
||||
const {subscription, activeCount} = await getEffectiveActiveStripeSubscription(stripe, user);
|
||||
const {subscription, activeCount, mostRecentTerminalSubscription} = await getEffectiveActiveStripeSubscription(
|
||||
stripe,
|
||||
user,
|
||||
);
|
||||
if (!subscription) {
|
||||
const hasStalePremium = user.premiumType === UserPremiumTypes.SUBSCRIPTION;
|
||||
const hasNonStripePremium = Config.instance.selfHosted || (user.premiumFlags & PremiumFlags.ENABLED_OVERRIDE) !== 0;
|
||||
if (hasStalePremium && !hasNonStripePremium) {
|
||||
const effectivePremiumUntil = getEffectivePremiumUntil(user);
|
||||
const patch: Partial<UserRow> = {};
|
||||
let effectivePremiumUntil = getEffectivePremiumUntil(user);
|
||||
if (mostRecentTerminalSubscription?.ended_at && user.premiumUntil) {
|
||||
const subscriptionEndedAt = new Date(mostRecentTerminalSubscription.ended_at * 1000);
|
||||
if (subscriptionEndedAt.getTime() < user.premiumUntil.getTime()) {
|
||||
patch.premium_until = subscriptionEndedAt;
|
||||
patch.premium_grace_ends_at = subscriptionEndedAt;
|
||||
effectivePremiumUntil = getEffectivePremiumUntil({
|
||||
premiumUntil: subscriptionEndedAt,
|
||||
premiumGiftExtensionEndsAt: user.premiumGiftExtensionEndsAt,
|
||||
});
|
||||
}
|
||||
}
|
||||
const hasFutureLocalEntitlement = effectivePremiumUntil != null && Date.now() <= effectivePremiumUntil.getTime();
|
||||
if (hasFutureLocalEntitlement) {
|
||||
const patch: Partial<UserRow> = {};
|
||||
if (user.premiumWillCancel !== true) {
|
||||
patch.premium_will_cancel = true;
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user