mirror of
https://github.com/fluxerapp/fluxer
synced 2026-10-17 13:05:32 +09:00
fix(billing): stack gifts from paid period end after trial ends (#3406)
This commit is contained in:
1 parent
bcb30eea88
commit
74c6fad260
3 files changed
+49
-4
No files matched your search
@@ -9,7 +9,7 @@ export function getGiftTrialMetadataKey(giftCode: string): string {
|
||||
return `${GIFT_TRIAL_KEY_PREFIX}${giftCode}`;
|
||||
}
|
||||
|
||||
function isGiftTrialRunning(subscription: Stripe.Subscription, nowMs: number): boolean {
|
||||
export function isGiftTrialRunning(subscription: Stripe.Subscription, nowMs: number): boolean {
|
||||
return subscription.trial_end != null && subscription.trial_end * 1000 > nowMs;
|
||||
}
|
||||
|
||||
|
||||
@@ -10,7 +10,11 @@ import {addGiftCodeDuration} from '@app/api/models/GiftCode';
|
||||
import type {User} from '@app/api/models/User';
|
||||
import type {StoreEntitlementService} from '@app/api/store_billing/StoreEntitlementService';
|
||||
import type {ProductInfo, RecurringBillingCycle} from '@app/api/stripe/ProductRegistry';
|
||||
import {buildGiftTrialMetadata, getGiftTrialPaidUntil} from '@app/api/stripe/StripeGiftTrialMetadata';
|
||||
import {
|
||||
buildGiftTrialMetadata,
|
||||
getGiftTrialPaidUntil,
|
||||
isGiftTrialRunning,
|
||||
} from '@app/api/stripe/StripeGiftTrialMetadata';
|
||||
import {
|
||||
getPrimarySubscriptionItem,
|
||||
getSubscriptionEntitlementPeriodEndUnix,
|
||||
@@ -1293,7 +1297,8 @@ export class StripeSubscriptionService {
|
||||
const currentTrialEnd = subscription.trial_end;
|
||||
const item = getPrimarySubscriptionItem(subscription);
|
||||
const currentPeriodEnd = getSubscriptionItemPeriodEndUnix(item);
|
||||
const baseUnix = currentTrialEnd ?? currentPeriodEnd;
|
||||
const nowMs = Date.now();
|
||||
const baseUnix = isGiftTrialRunning(subscription, nowMs) ? currentTrialEnd : currentPeriodEnd;
|
||||
Logger.debug(
|
||||
{
|
||||
userId: user.id,
|
||||
@@ -1331,7 +1336,7 @@ export class StripeSubscriptionService {
|
||||
{
|
||||
trial_end: newTrialEndUnix,
|
||||
proration_behavior: 'none',
|
||||
metadata: buildGiftTrialMetadata(subscription, idempotencyKey, baseUnix, newTrialEndUnix, Date.now()),
|
||||
metadata: buildGiftTrialMetadata(subscription, idempotencyKey, baseUnix, newTrialEndUnix, nowMs),
|
||||
},
|
||||
{idempotencyKey: stripeIdempotencyKey},
|
||||
);
|
||||
|
||||
@@ -749,5 +749,45 @@ describe('gift time around a Stripe subscription', () => {
|
||||
const afterWebhook = await findUser(account.userId);
|
||||
expect(afterWebhook.premiumGiftExtensionEndsAt?.getTime()).toBe(trialEnd.getTime());
|
||||
});
|
||||
|
||||
test('stacks from the paid period end when an earlier gift trial has ended', async () => {
|
||||
const subscriptionId = 'sub_shift_stale_trial';
|
||||
const periodEnd = Math.floor((Date.now() + ms('20 days')) / 1000);
|
||||
const staleTrialEnd = periodEnd - 60 * 24 * 60 * 60;
|
||||
useStripe({
|
||||
subscriptions: {
|
||||
[subscriptionId]: {
|
||||
current_period_start: periodEnd - 30 * 24 * 60 * 60,
|
||||
current_period_end: periodEnd,
|
||||
trial_end: staleTrialEnd,
|
||||
metadata: giftTrialMetadata('OLDGIFT', 30, staleTrialEnd - 30 * 24 * 60 * 60),
|
||||
},
|
||||
},
|
||||
});
|
||||
const {account} = await createUser({
|
||||
premium_type: UserPremiumTypes.SUBSCRIPTION,
|
||||
stripe_subscription_id: subscriptionId,
|
||||
stripe_customer_id: 'cus_test_1',
|
||||
premium_billing_cycle: 'monthly',
|
||||
premium_until: new Date(periodEnd * 1000),
|
||||
});
|
||||
const gifter = await createTestAccount(harness);
|
||||
await createBuilder(harness, gifter.token)
|
||||
.post('/test/gifts/SHIFTSTALEGIFT')
|
||||
.body({duration_type: 'days', duration_quantity: 30, created_by_user_id: gifter.userId})
|
||||
.execute();
|
||||
|
||||
await createBuilder(harness, account.token).post('/gifts/SHIFTSTALEGIFT/redeem').expect(204).execute();
|
||||
|
||||
const update = stripeHandlers.spies.updatedSubscriptions[0]?.params;
|
||||
expect(Number(update?.trial_end)).toBe(periodEnd + 30 * 24 * 60 * 60);
|
||||
expect(update?.metadata).toEqual({
|
||||
gtrial_OLDGIFT: '',
|
||||
gtrial_paid_until: String(periodEnd),
|
||||
gtrial_SHIFTSTALEGIFT: String(30 * 24 * 60 * 60),
|
||||
});
|
||||
const redeemed = await findUser(account.userId);
|
||||
expect(redeemed.premiumUntil?.getTime()).toBe((periodEnd + 30 * 24 * 60 * 60) * 1000);
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in new issue
Block a user