✨ Subscription required level, optimized cancellation logic
This commit is contained in:
parent
fb885e138d
commit
6449926334
@ -92,7 +92,7 @@ public abstract class SubscriptionPaymentMethod
|
||||
public enum SubscriptionStatus
|
||||
{
|
||||
Unpaid,
|
||||
Paid,
|
||||
Active,
|
||||
Expired,
|
||||
Cancelled
|
||||
}
|
||||
@ -152,7 +152,7 @@ public class Subscription : ModelBase
|
||||
if (BegunAt > now) return false;
|
||||
if (EndedAt.HasValue && now > EndedAt.Value) return false;
|
||||
if (RenewalAt.HasValue && now > RenewalAt.Value) return false;
|
||||
if (Status != SubscriptionStatus.Paid) return false;
|
||||
if (Status != SubscriptionStatus.Active) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -29,7 +29,7 @@ public class SubscriptionRenewalJob(
|
||||
// Find subscriptions that need renewal (due for renewal and are still active)
|
||||
var subscriptionsToRenew = await db.WalletSubscriptions
|
||||
.Where(s => s.RenewalAt.HasValue && s.RenewalAt.Value <= now) // Due for renewal
|
||||
.Where(s => s.Status == SubscriptionStatus.Paid) // Only paid subscriptions
|
||||
.Where(s => s.Status == SubscriptionStatus.Active) // Only paid subscriptions
|
||||
.Where(s => s.IsActive) // Only active subscriptions
|
||||
.Where(s => !s.IsFreeTrial) // Exclude free trials
|
||||
.OrderBy(s => s.RenewalAt) // Process oldest first
|
||||
@ -49,6 +49,17 @@ public class SubscriptionRenewalJob(
|
||||
"Processing renewal for subscription {SubscriptionId} (Identifier: {Identifier}) for account {AccountId}",
|
||||
subscription.Id, subscription.Identifier, subscription.AccountId);
|
||||
|
||||
if (subscription.RenewalAt is null)
|
||||
{
|
||||
logger.LogWarning(
|
||||
"Subscription {SubscriptionId} (Identifier: {Identifier}) has no renewal date or has been cancelled.",
|
||||
subscription.Id, subscription.Identifier);
|
||||
subscription.Status = SubscriptionStatus.Cancelled;
|
||||
db.WalletSubscriptions.Update(subscription);
|
||||
await db.SaveChangesAsync();
|
||||
continue;
|
||||
}
|
||||
|
||||
// Calculate next cycle duration based on current cycle
|
||||
var currentCycle = subscription.EndedAt!.Value - subscription.BegunAt;
|
||||
|
||||
|
@ -53,6 +53,18 @@ public class SubscriptionService(
|
||||
if (existingSubscription is not null)
|
||||
return existingSubscription;
|
||||
|
||||
if (subscriptionInfo.RequiredLevel > 0)
|
||||
{
|
||||
var profile = await db.AccountProfiles
|
||||
.Where(p => p.AccountId == account.Id)
|
||||
.FirstOrDefaultAsync();
|
||||
if (profile is null) throw new InvalidOperationException("Account profile was not found.");
|
||||
if (profile.Level < subscriptionInfo.RequiredLevel)
|
||||
throw new InvalidOperationException(
|
||||
$"Account level must be at least {subscriptionInfo.RequiredLevel} to subscribe to {identifier}."
|
||||
);
|
||||
}
|
||||
|
||||
if (isFreeTrial)
|
||||
{
|
||||
var prevFreeTrial = await db.WalletSubscriptions
|
||||
@ -146,7 +158,7 @@ public class SubscriptionService(
|
||||
existingSubscription.PaymentDetails.OrderId = order.Id;
|
||||
existingSubscription.EndedAt = order.BegunAt.Plus(cycleDuration);
|
||||
existingSubscription.RenewalAt = order.BegunAt.Plus(cycleDuration);
|
||||
existingSubscription.Status = SubscriptionStatus.Paid;
|
||||
existingSubscription.Status = SubscriptionStatus.Active;
|
||||
|
||||
db.Update(existingSubscription);
|
||||
await db.SaveChangesAsync();
|
||||
@ -159,7 +171,7 @@ public class SubscriptionService(
|
||||
BegunAt = order.BegunAt,
|
||||
EndedAt = order.BegunAt.Plus(cycleDuration),
|
||||
IsActive = true,
|
||||
Status = SubscriptionStatus.Paid,
|
||||
Status = SubscriptionStatus.Active,
|
||||
Identifier = subscriptionIdentifier,
|
||||
PaymentMethod = provider,
|
||||
PaymentDetails = new PaymentDetails
|
||||
@ -192,10 +204,15 @@ public class SubscriptionService(
|
||||
var subscription = await GetSubscriptionAsync(accountId, identifier);
|
||||
if (subscription is null)
|
||||
throw new InvalidOperationException($"Subscription with identifier {identifier} was not found.");
|
||||
if (subscription.Status == SubscriptionStatus.Cancelled)
|
||||
if (subscription.Status != SubscriptionStatus.Active)
|
||||
throw new InvalidOperationException("Subscription is already cancelled.");
|
||||
if (subscription.RenewalAt is null)
|
||||
throw new InvalidOperationException("Subscription is no need to be cancelled.");
|
||||
if (subscription.PaymentMethod != SubscriptionPaymentMethod.InAppWallet)
|
||||
throw new InvalidOperationException(
|
||||
"Only in-app wallet subscription can be cancelled. For other payment methods, please head to the payment provider."
|
||||
);
|
||||
|
||||
subscription.Status = SubscriptionStatus.Cancelled;
|
||||
subscription.RenewalAt = null;
|
||||
|
||||
await db.SaveChangesAsync();
|
||||
@ -276,7 +293,7 @@ public class SubscriptionService(
|
||||
subscription.EndedAt = nextEndedAt;
|
||||
}
|
||||
|
||||
subscription.Status = SubscriptionStatus.Paid;
|
||||
subscription.Status = SubscriptionStatus.Active;
|
||||
|
||||
db.Update(subscription);
|
||||
await db.SaveChangesAsync();
|
||||
@ -306,7 +323,7 @@ public class SubscriptionService(
|
||||
// Find active subscriptions that have passed their end date
|
||||
var expiredSubscriptions = await db.WalletSubscriptions
|
||||
.Where(s => s.IsActive)
|
||||
.Where(s => s.Status == SubscriptionStatus.Paid)
|
||||
.Where(s => s.Status == SubscriptionStatus.Active)
|
||||
.Where(s => s.EndedAt.HasValue && s.EndedAt.Value < now)
|
||||
.Take(batchSize)
|
||||
.ToListAsync();
|
||||
|
Loading…
x
Reference in New Issue
Block a user