✨ Subscription and stellar program
This commit is contained in:
123
DysonNetwork.Sphere/Wallet/SubscriptionRenewalJob.cs
Normal file
123
DysonNetwork.Sphere/Wallet/SubscriptionRenewalJob.cs
Normal file
@ -0,0 +1,123 @@
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using NodaTime;
|
||||
using Quartz;
|
||||
|
||||
namespace DysonNetwork.Sphere.Wallet;
|
||||
|
||||
public class SubscriptionRenewalJob(
|
||||
AppDatabase db,
|
||||
SubscriptionService subscriptionService,
|
||||
PaymentService paymentService,
|
||||
WalletService walletService,
|
||||
ILogger<SubscriptionRenewalJob> logger
|
||||
) : IJob
|
||||
{
|
||||
public async Task Execute(IJobExecutionContext context)
|
||||
{
|
||||
logger.LogInformation("Starting subscription auto-renewal job...");
|
||||
|
||||
// First update expired subscriptions
|
||||
var expiredCount = await subscriptionService.UpdateExpiredSubscriptionsAsync();
|
||||
logger.LogInformation("Updated {ExpiredCount} expired subscriptions", expiredCount);
|
||||
|
||||
var now = SystemClock.Instance.GetCurrentInstant();
|
||||
const int batchSize = 100; // Process in smaller batches
|
||||
var processedCount = 0;
|
||||
var renewedCount = 0;
|
||||
var failedCount = 0;
|
||||
|
||||
// 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.IsActive) // Only active subscriptions
|
||||
.Where(s => !s.IsFreeTrial) // Exclude free trials
|
||||
.OrderBy(s => s.RenewalAt) // Process oldest first
|
||||
.Take(batchSize)
|
||||
.Include(s => s.Coupon) // Include coupon information
|
||||
.ToListAsync();
|
||||
|
||||
var totalSubscriptions = subscriptionsToRenew.Count;
|
||||
logger.LogInformation("Found {TotalSubscriptions} subscriptions due for renewal", totalSubscriptions);
|
||||
|
||||
foreach (var subscription in subscriptionsToRenew)
|
||||
{
|
||||
try
|
||||
{
|
||||
processedCount++;
|
||||
logger.LogDebug("Processing renewal for subscription {SubscriptionId} (Identifier: {Identifier}) for account {AccountId}",
|
||||
subscription.Id, subscription.Identifier, subscription.AccountId);
|
||||
|
||||
// Calculate next cycle duration based on current cycle
|
||||
var currentCycle = subscription.EndedAt!.Value - subscription.BegunAt;
|
||||
|
||||
// Create an order for the renewal payment
|
||||
var order = await paymentService.CreateOrderAsync(
|
||||
null,
|
||||
WalletCurrency.GoldenPoint,
|
||||
subscription.FinalPrice,
|
||||
appIdentifier: SubscriptionService.SubscriptionOrderIdentifier,
|
||||
meta: new Dictionary<string, object>()
|
||||
{
|
||||
["subscription_id"] = subscription.Id.ToString(),
|
||||
["subscription_identifier"] = subscription.Identifier,
|
||||
["is_renewal"] = true
|
||||
}
|
||||
);
|
||||
|
||||
// Try to process the payment automatically
|
||||
if (subscription.PaymentMethod == SubscriptionPaymentMethod.InAppWallet)
|
||||
{
|
||||
try
|
||||
{
|
||||
var wallet = await walletService.GetWalletAsync(subscription.AccountId);
|
||||
if (wallet is null) continue;
|
||||
|
||||
// Process automatic payment from wallet
|
||||
await paymentService.PayOrderAsync(order.Id, wallet.Id);
|
||||
|
||||
// Update subscription details
|
||||
subscription.BegunAt = subscription.EndedAt!.Value;
|
||||
subscription.EndedAt = subscription.BegunAt.Plus(currentCycle);
|
||||
subscription.RenewalAt = subscription.EndedAt;
|
||||
|
||||
db.WalletSubscriptions.Update(subscription);
|
||||
await db.SaveChangesAsync();
|
||||
|
||||
renewedCount++;
|
||||
logger.LogInformation("Successfully renewed subscription {SubscriptionId}", subscription.Id);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
// If auto-payment fails, mark for manual payment
|
||||
logger.LogWarning(ex, "Failed to auto-renew subscription {SubscriptionId} with wallet payment", subscription.Id);
|
||||
failedCount++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// For other payment methods, mark as pending payment
|
||||
logger.LogInformation("Subscription {SubscriptionId} requires manual payment via {PaymentMethod}",
|
||||
subscription.Id, subscription.PaymentMethod);
|
||||
failedCount++;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
logger.LogError(ex, "Error processing subscription {SubscriptionId}", subscription.Id);
|
||||
failedCount++;
|
||||
}
|
||||
|
||||
// Log progress periodically
|
||||
if (processedCount % 20 == 0 || processedCount == totalSubscriptions)
|
||||
{
|
||||
logger.LogInformation(
|
||||
"Progress: processed {ProcessedCount}/{TotalSubscriptions} subscriptions, {RenewedCount} renewed, {FailedCount} failed",
|
||||
processedCount, totalSubscriptions, renewedCount, failedCount);
|
||||
}
|
||||
}
|
||||
|
||||
logger.LogInformation("Completed subscription renewal job. Processed: {ProcessedCount}, Renewed: {RenewedCount}, Failed: {FailedCount}",
|
||||
processedCount, renewedCount, failedCount);
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user