diff --git a/DysonNetwork.Sphere/Wallet/Subscription.cs b/DysonNetwork.Sphere/Wallet/Subscription.cs index 131363a..d089f5c 100644 --- a/DysonNetwork.Sphere/Wallet/Subscription.cs +++ b/DysonNetwork.Sphere/Wallet/Subscription.cs @@ -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; } diff --git a/DysonNetwork.Sphere/Wallet/SubscriptionRenewalJob.cs b/DysonNetwork.Sphere/Wallet/SubscriptionRenewalJob.cs index ad74bcb..116fe51 100644 --- a/DysonNetwork.Sphere/Wallet/SubscriptionRenewalJob.cs +++ b/DysonNetwork.Sphere/Wallet/SubscriptionRenewalJob.cs @@ -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; diff --git a/DysonNetwork.Sphere/Wallet/SubscriptionService.cs b/DysonNetwork.Sphere/Wallet/SubscriptionService.cs index 88f4e6d..a46dcf6 100644 --- a/DysonNetwork.Sphere/Wallet/SubscriptionService.cs +++ b/DysonNetwork.Sphere/Wallet/SubscriptionService.cs @@ -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(); @@ -226,7 +243,7 @@ public class SubscriptionService( .OrderByDescending(s => s.BegunAt) .FirstOrDefaultAsync(); if (subscription is null) throw new InvalidOperationException("No matching subscription found."); - + var subscriptionInfo = SubscriptionTypeData.SubscriptionDict .TryGetValue(subscription.Identifier, out var template) ? template @@ -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();