Compare commits
2 Commits
787fa63f68
...
0f6ae71997
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0f6ae71997 | ||
|
|
79c254905a |
@ -24,7 +24,8 @@
|
|||||||
"Bash(dotnet nuget locals:*)",
|
"Bash(dotnet nuget locals:*)",
|
||||||
"Bash(/mnt/c/vscode/vcart.me.novo/clean-build.sh:*)",
|
"Bash(/mnt/c/vscode/vcart.me.novo/clean-build.sh:*)",
|
||||||
"Bash(sed:*)",
|
"Bash(sed:*)",
|
||||||
"Bash(./clean-build.sh:*)"
|
"Bash(./clean-build.sh:*)",
|
||||||
|
"Bash(git add:*)"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"enableAllProjectMcpServers": false
|
"enableAllProjectMcpServers": false
|
||||||
|
|||||||
@ -1,316 +1,380 @@
|
|||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using Stripe;
|
using Stripe;
|
||||||
using BCards.Web.Services;
|
using BCards.Web.Services;
|
||||||
using BCards.Web.Repositories;
|
using BCards.Web.Repositories;
|
||||||
using BCards.Web.Configuration;
|
using BCards.Web.Configuration;
|
||||||
using Microsoft.Extensions.Options;
|
using Microsoft.Extensions.Options;
|
||||||
|
|
||||||
namespace BCards.Web.Controllers;
|
namespace BCards.Web.Controllers;
|
||||||
|
|
||||||
[ApiController]
|
[ApiController]
|
||||||
[Route("api/stripe")]
|
[Route("api/stripe")]
|
||||||
public class StripeWebhookController : ControllerBase
|
public class StripeWebhookController : ControllerBase
|
||||||
{
|
{
|
||||||
private readonly ILogger<StripeWebhookController> _logger;
|
private readonly ILogger<StripeWebhookController> _logger;
|
||||||
private readonly ISubscriptionRepository _subscriptionRepository;
|
private readonly ISubscriptionRepository _subscriptionRepository;
|
||||||
private readonly IUserPageService _userPageService;
|
private readonly IUserPageService _userPageService;
|
||||||
private readonly string _webhookSecret;
|
private readonly string _webhookSecret;
|
||||||
|
|
||||||
public StripeWebhookController(
|
public StripeWebhookController(
|
||||||
ILogger<StripeWebhookController> logger,
|
ILogger<StripeWebhookController> logger,
|
||||||
ISubscriptionRepository subscriptionRepository,
|
ISubscriptionRepository subscriptionRepository,
|
||||||
IUserPageService userPageService,
|
IUserPageService userPageService,
|
||||||
IOptions<StripeSettings> stripeSettings)
|
IOptions<StripeSettings> stripeSettings)
|
||||||
{
|
{
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
_subscriptionRepository = subscriptionRepository;
|
_subscriptionRepository = subscriptionRepository;
|
||||||
_userPageService = userPageService;
|
_userPageService = userPageService;
|
||||||
_webhookSecret = stripeSettings.Value.WebhookSecret ?? "";
|
_webhookSecret = stripeSettings.Value.WebhookSecret ?? "";
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpPost("webhook")]
|
[HttpPost("webhook")]
|
||||||
public async Task<IActionResult> HandleWebhook()
|
public async Task<IActionResult> HandleWebhook()
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var json = await new StreamReader(HttpContext.Request.Body).ReadToEndAsync();
|
var json = await new StreamReader(HttpContext.Request.Body).ReadToEndAsync();
|
||||||
_logger.LogInformation($"Recebido:{json}");
|
_logger.LogInformation($"Recebido:{json}");
|
||||||
|
|
||||||
if (string.IsNullOrEmpty(_webhookSecret))
|
if (string.IsNullOrEmpty(_webhookSecret))
|
||||||
{
|
{
|
||||||
_logger.LogWarning("Webhook secret not configured");
|
_logger.LogWarning("Webhook secret not configured");
|
||||||
return BadRequest("Webhook secret not configured");
|
return BadRequest("Webhook secret not configured");
|
||||||
}
|
}
|
||||||
_logger.LogWarning($"Recebido:{json}");
|
_logger.LogWarning($"Recebido:{json}");
|
||||||
|
|
||||||
var stripeSignature = Request.Headers["Stripe-Signature"].FirstOrDefault();
|
var stripeSignature = Request.Headers["Stripe-Signature"].FirstOrDefault();
|
||||||
if (string.IsNullOrEmpty(stripeSignature))
|
if (string.IsNullOrEmpty(stripeSignature))
|
||||||
{
|
{
|
||||||
_logger.LogWarning("Missing Stripe signature");
|
_logger.LogWarning("Missing Stripe signature");
|
||||||
return BadRequest("Missing Stripe signature");
|
return BadRequest("Missing Stripe signature");
|
||||||
}
|
}
|
||||||
|
|
||||||
_logger.LogInformation($"Contruir evento Stripe: {json}");
|
_logger.LogInformation($"Contruir evento Stripe: {json}");
|
||||||
var stripeEvent = EventUtility.ConstructEvent(
|
var stripeEvent = EventUtility.ConstructEvent(
|
||||||
json,
|
json,
|
||||||
stripeSignature,
|
stripeSignature,
|
||||||
_webhookSecret,
|
_webhookSecret,
|
||||||
throwOnApiVersionMismatch: false
|
throwOnApiVersionMismatch: false
|
||||||
);
|
);
|
||||||
|
|
||||||
_logger.LogInformation($"Processing Stripe webhook: {stripeEvent.Type}");
|
_logger.LogInformation($"Processing Stripe webhook: {stripeEvent.Type}");
|
||||||
|
|
||||||
switch (stripeEvent.Type)
|
switch (stripeEvent.Type)
|
||||||
{
|
{
|
||||||
case "invoice.payment_succeeded":
|
case "invoice.payment_succeeded":
|
||||||
await HandlePaymentSucceeded(stripeEvent);
|
await HandlePaymentSucceeded(stripeEvent);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case "invoice.payment_failed":
|
case "invoice.payment_failed":
|
||||||
await HandlePaymentFailed(stripeEvent);
|
await HandlePaymentFailed(stripeEvent);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case "customer.subscription.deleted":
|
case "customer.subscription.deleted":
|
||||||
await HandleSubscriptionDeleted(stripeEvent);
|
await HandleSubscriptionDeleted(stripeEvent);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case "customer.subscription.updated":
|
case "customer.subscription.updated":
|
||||||
await HandleSubscriptionUpdated(stripeEvent);
|
await HandleSubscriptionUpdated(stripeEvent);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
case "customer.subscription.created":
|
||||||
_logger.LogInformation($"Unhandled webhook event type: {stripeEvent.Type}");
|
await HandleSubscriptionCreated(stripeEvent);
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
|
default:
|
||||||
await Task.Delay(2000); // 2 segundos
|
_logger.LogInformation($"Unhandled webhook event type: {stripeEvent.Type}");
|
||||||
return Ok();
|
break;
|
||||||
}
|
}
|
||||||
catch (StripeException ex)
|
|
||||||
{
|
await Task.Delay(2000); // 2 segundos
|
||||||
await Task.Delay(2000); // 2 segundos
|
return Ok();
|
||||||
_logger.LogError(ex, "Stripe webhook error");
|
}
|
||||||
return BadRequest($"Stripe error: {ex.Message}");
|
catch (StripeException ex)
|
||||||
}
|
{
|
||||||
catch (Exception ex)
|
await Task.Delay(2000); // 2 segundos
|
||||||
{
|
_logger.LogError(ex, "Stripe webhook error");
|
||||||
await Task.Delay(2000); // 2 segundos
|
return BadRequest($"Stripe error: {ex.Message}");
|
||||||
_logger.LogError(ex, "Webhook processing error");
|
}
|
||||||
return StatusCode(500, "Internal server error");
|
catch (Exception ex)
|
||||||
}
|
{
|
||||||
}
|
await Task.Delay(2000); // 2 segundos
|
||||||
|
_logger.LogError(ex, "Webhook processing error");
|
||||||
private async Task HandlePaymentSucceeded(Event stripeEvent)
|
return StatusCode(500, "Internal server error");
|
||||||
{
|
}
|
||||||
try
|
}
|
||||||
{
|
|
||||||
if (stripeEvent.Data.Object is Invoice invoice)
|
private async Task HandlePaymentSucceeded(Event stripeEvent)
|
||||||
{
|
{
|
||||||
_logger.LogInformation($"Payment succeeded for customer: {invoice.CustomerId}");
|
try
|
||||||
|
{
|
||||||
var subscriptionId = GetSubscriptionId(stripeEvent);
|
if (stripeEvent.Data.Object is Invoice invoice)
|
||||||
var subscription = await _subscriptionRepository.GetByStripeSubscriptionIdAsync(subscriptionId);
|
{
|
||||||
if (subscription != null)
|
_logger.LogInformation($"Payment succeeded for customer: {invoice.CustomerId}");
|
||||||
{
|
|
||||||
subscription.Status = "active";
|
var subscriptionId = GetSubscriptionId(stripeEvent);
|
||||||
subscription.UpdatedAt = DateTime.UtcNow;
|
var subscription = await _subscriptionRepository.GetByStripeSubscriptionIdAsync(subscriptionId);
|
||||||
await _subscriptionRepository.UpdateAsync(subscription);
|
if (subscription != null)
|
||||||
|
{
|
||||||
// Reactivate user pages
|
subscription.Status = "active";
|
||||||
var userPages = await _userPageService.GetUserPagesAsync(subscription.UserId);
|
subscription.UpdatedAt = DateTime.UtcNow;
|
||||||
foreach (var page in userPages.Where(p => p.Status == ViewModels.PageStatus.PendingPayment))
|
await _subscriptionRepository.UpdateAsync(subscription);
|
||||||
{
|
|
||||||
page.Status = ViewModels.PageStatus.Active;
|
// Reactivate user pages
|
||||||
page.UpdatedAt = DateTime.UtcNow;
|
var userPages = await _userPageService.GetUserPagesAsync(subscription.UserId);
|
||||||
await _userPageService.UpdatePageAsync(page);
|
foreach (var page in userPages.Where(p => p.Status == ViewModels.PageStatus.PendingPayment))
|
||||||
}
|
{
|
||||||
|
page.Status = ViewModels.PageStatus.Active;
|
||||||
_logger.LogInformation($"Reactivated {userPages.Count} pages for user {subscription.UserId}");
|
page.UpdatedAt = DateTime.UtcNow;
|
||||||
}
|
await _userPageService.UpdatePageAsync(page);
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
_logger.LogInformation($"Reactivated {userPages.Count} pages for user {subscription.UserId}");
|
||||||
_logger.LogWarning($"Unexpected event type on HandlePaymentSucceeded: {stripeEvent.Type}");
|
}
|
||||||
}
|
}
|
||||||
}
|
else
|
||||||
catch (Exception ex)
|
{
|
||||||
{
|
_logger.LogWarning($"Unexpected event type on HandlePaymentSucceeded: {stripeEvent.Type}");
|
||||||
_logger.LogError(ex, "Error handling payment succeeded event");
|
}
|
||||||
throw new Exception("Error handling payment succeeded event", ex);
|
}
|
||||||
}
|
catch (Exception ex)
|
||||||
}
|
{
|
||||||
|
_logger.LogError(ex, "Error handling payment succeeded event");
|
||||||
private async Task HandlePaymentFailed(Event stripeEvent)
|
throw new Exception("Error handling payment succeeded event", ex);
|
||||||
{
|
}
|
||||||
try
|
}
|
||||||
{
|
|
||||||
if (stripeEvent.Data.Object is Invoice invoice)
|
private async Task HandlePaymentFailed(Event stripeEvent)
|
||||||
{
|
{
|
||||||
_logger.LogInformation($"Payment failed for customer: {invoice.CustomerId}");
|
try
|
||||||
|
{
|
||||||
var subscriptionId = GetSubscriptionId(stripeEvent);
|
if (stripeEvent.Data.Object is Invoice invoice)
|
||||||
var subscription = await _subscriptionRepository.GetByStripeSubscriptionIdAsync(subscriptionId);
|
{
|
||||||
if (subscription != null)
|
_logger.LogInformation($"Payment failed for customer: {invoice.CustomerId}");
|
||||||
{
|
|
||||||
subscription.Status = "past_due";
|
var subscriptionId = GetSubscriptionId(stripeEvent);
|
||||||
subscription.UpdatedAt = DateTime.UtcNow;
|
var subscription = await _subscriptionRepository.GetByStripeSubscriptionIdAsync(subscriptionId);
|
||||||
await _subscriptionRepository.UpdateAsync(subscription);
|
if (subscription != null)
|
||||||
|
{
|
||||||
// Set pages to pending payment
|
subscription.Status = "past_due";
|
||||||
var userPages = await _userPageService.GetUserPagesAsync(subscription.UserId);
|
subscription.UpdatedAt = DateTime.UtcNow;
|
||||||
foreach (var page in userPages.Where(p => p.Status == ViewModels.PageStatus.Active))
|
await _subscriptionRepository.UpdateAsync(subscription);
|
||||||
{
|
|
||||||
page.Status = ViewModels.PageStatus.PendingPayment;
|
// Set pages to pending payment
|
||||||
page.UpdatedAt = DateTime.UtcNow;
|
var userPages = await _userPageService.GetUserPagesAsync(subscription.UserId);
|
||||||
await _userPageService.UpdatePageAsync(page);
|
foreach (var page in userPages.Where(p => p.Status == ViewModels.PageStatus.Active))
|
||||||
}
|
{
|
||||||
|
page.Status = ViewModels.PageStatus.PendingPayment;
|
||||||
_logger.LogInformation($"Set {userPages.Count} pages to pending payment for user {subscription.UserId}");
|
page.UpdatedAt = DateTime.UtcNow;
|
||||||
}
|
await _userPageService.UpdatePageAsync(page);
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
_logger.LogInformation($"Set {userPages.Count} pages to pending payment for user {subscription.UserId}");
|
||||||
_logger.LogWarning($"Unexpected event type on HandlePaymentFailed: {stripeEvent.Type}");
|
}
|
||||||
}
|
}
|
||||||
}
|
else
|
||||||
catch (Exception ex)
|
{
|
||||||
{
|
_logger.LogWarning($"Unexpected event type on HandlePaymentFailed: {stripeEvent.Type}");
|
||||||
_logger.LogError(ex, "Error handling payment failed event");
|
}
|
||||||
throw new Exception("Error handling payment failed event", ex);
|
}
|
||||||
}
|
catch (Exception ex)
|
||||||
}
|
{
|
||||||
|
_logger.LogError(ex, "Error handling payment failed event");
|
||||||
private async Task HandleSubscriptionDeleted(Event stripeEvent)
|
throw new Exception("Error handling payment failed event", ex);
|
||||||
{
|
}
|
||||||
try
|
}
|
||||||
{
|
|
||||||
if (stripeEvent.Data.Object is Subscription stripeSubscription)
|
private async Task HandleSubscriptionDeleted(Event stripeEvent)
|
||||||
{
|
{
|
||||||
_logger.LogInformation($"Subscription cancelled: {stripeSubscription.Id}");
|
try
|
||||||
|
{
|
||||||
var subscription = await _subscriptionRepository.GetByStripeSubscriptionIdAsync(stripeSubscription.Id);
|
if (stripeEvent.Data.Object is Subscription stripeSubscription)
|
||||||
if (subscription != null)
|
{
|
||||||
{
|
_logger.LogInformation($"Subscription cancelled: {stripeSubscription.Id}");
|
||||||
subscription.Status = "cancelled";
|
|
||||||
subscription.UpdatedAt = DateTime.UtcNow;
|
var subscription = await _subscriptionRepository.GetByStripeSubscriptionIdAsync(stripeSubscription.Id);
|
||||||
await _subscriptionRepository.UpdateAsync(subscription);
|
if (subscription != null)
|
||||||
|
{
|
||||||
// Downgrade to trial or deactivate pages
|
subscription.Status = "cancelled";
|
||||||
var userPages = await _userPageService.GetUserPagesAsync(subscription.UserId);
|
subscription.UpdatedAt = DateTime.UtcNow;
|
||||||
foreach (var page in userPages.Where(p => p.Status == ViewModels.PageStatus.Active))
|
await _subscriptionRepository.UpdateAsync(subscription);
|
||||||
{
|
|
||||||
page.Status = ViewModels.PageStatus.Expired;
|
// Downgrade to trial or deactivate pages
|
||||||
page.UpdatedAt = DateTime.UtcNow;
|
var userPages = await _userPageService.GetUserPagesAsync(subscription.UserId);
|
||||||
await _userPageService.UpdatePageAsync(page);
|
foreach (var page in userPages.Where(p => p.Status == ViewModels.PageStatus.Active))
|
||||||
}
|
{
|
||||||
|
page.Status = ViewModels.PageStatus.Expired;
|
||||||
_logger.LogInformation($"Deactivated {userPages.Count} pages for cancelled subscription {subscription.UserId}");
|
page.UpdatedAt = DateTime.UtcNow;
|
||||||
}
|
await _userPageService.UpdatePageAsync(page);
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
_logger.LogInformation($"Deactivated {userPages.Count} pages for cancelled subscription {subscription.UserId}");
|
||||||
_logger.LogWarning($"Unexpected event type on HandlePaymentFailed: {stripeEvent.Type}");
|
}
|
||||||
}
|
}
|
||||||
}
|
else
|
||||||
catch (Exception ex)
|
{
|
||||||
{
|
_logger.LogWarning($"Unexpected event type on HandlePaymentFailed: {stripeEvent.Type}");
|
||||||
_logger.LogError(ex, "Error handling subscription deleted failed event");
|
}
|
||||||
throw new Exception("Error handling subscription deleted failed event", ex);
|
}
|
||||||
}
|
catch (Exception ex)
|
||||||
}
|
{
|
||||||
|
_logger.LogError(ex, "Error handling subscription deleted failed event");
|
||||||
private async Task HandleSubscriptionUpdated(Event stripeEvent)
|
throw new Exception("Error handling subscription deleted failed event", ex);
|
||||||
{
|
}
|
||||||
try
|
}
|
||||||
{
|
|
||||||
if (stripeEvent.Data.Object is Subscription stripeSubscription)
|
private async Task HandleSubscriptionUpdated(Event stripeEvent)
|
||||||
{
|
{
|
||||||
_logger.LogInformation($"Subscription updated: {stripeSubscription.Id}");
|
try
|
||||||
|
{
|
||||||
var subscription = await _subscriptionRepository.GetByStripeSubscriptionIdAsync(stripeSubscription.Id);
|
if (stripeEvent.Data.Object is Subscription stripeSubscription)
|
||||||
if (subscription != null)
|
{
|
||||||
{
|
_logger.LogInformation($"Subscription updated: {stripeSubscription.Id}");
|
||||||
var service = new SubscriptionItemService();
|
|
||||||
var subItem = service.Get(stripeSubscription.Items.Data[0].Id);
|
var subscription = await _subscriptionRepository.GetByStripeSubscriptionIdAsync(stripeSubscription.Id);
|
||||||
|
if (subscription != null)
|
||||||
subscription.Status = stripeSubscription.Status;
|
{
|
||||||
subscription.CurrentPeriodStart = subItem.CurrentPeriodStart;
|
var service = new SubscriptionItemService();
|
||||||
subscription.CurrentPeriodEnd = subItem.CurrentPeriodEnd;
|
var subItem = service.Get(stripeSubscription.Items.Data[0].Id);
|
||||||
subscription.CancelAtPeriodEnd = stripeSubscription.CancelAtPeriodEnd;
|
|
||||||
subscription.UpdatedAt = DateTime.UtcNow;
|
subscription.Status = stripeSubscription.Status;
|
||||||
|
subscription.CurrentPeriodStart = subItem.CurrentPeriodStart;
|
||||||
// Update plan type based on Stripe price ID
|
subscription.CurrentPeriodEnd = subItem.CurrentPeriodEnd;
|
||||||
var priceId = stripeSubscription.Items.Data.FirstOrDefault()?.Price.Id;
|
subscription.CancelAtPeriodEnd = stripeSubscription.CancelAtPeriodEnd;
|
||||||
if (!string.IsNullOrEmpty(priceId))
|
subscription.UpdatedAt = DateTime.UtcNow;
|
||||||
{
|
|
||||||
subscription.PlanType = MapPriceIdToPlanType(priceId);
|
// Update plan type based on Stripe price ID
|
||||||
}
|
var priceId = stripeSubscription.Items.Data.FirstOrDefault()?.Price.Id;
|
||||||
|
if (!string.IsNullOrEmpty(priceId))
|
||||||
await _subscriptionRepository.UpdateAsync(subscription);
|
{
|
||||||
|
subscription.PlanType = MapPriceIdToPlanType(priceId);
|
||||||
_logger.LogInformation($"Updated subscription for user {subscription.UserId}");
|
}
|
||||||
}
|
|
||||||
}
|
await _subscriptionRepository.UpdateAsync(subscription);
|
||||||
else
|
|
||||||
{
|
_logger.LogInformation($"Updated subscription for user {subscription.UserId}");
|
||||||
_logger.LogWarning($"Unexpected event type on HandlePaymentFailed: {stripeEvent.Type}");
|
}
|
||||||
}
|
}
|
||||||
}
|
else
|
||||||
catch (Exception ex)
|
{
|
||||||
{
|
_logger.LogWarning($"Unexpected event type on HandlePaymentFailed: {stripeEvent.Type}");
|
||||||
_logger.LogError(ex, "Error handling subscription updated failed event");
|
}
|
||||||
throw new Exception("Error handling subscription updated failed event", ex);
|
}
|
||||||
}
|
catch (Exception ex)
|
||||||
}
|
{
|
||||||
|
_logger.LogError(ex, "Error handling subscription updated failed event");
|
||||||
private string MapPriceIdToPlanType(string priceId)
|
throw new Exception("Error handling subscription updated failed event", ex);
|
||||||
{
|
}
|
||||||
// Map Stripe price IDs to plan types
|
}
|
||||||
// This would be configured based on your actual Stripe price IDs
|
|
||||||
return priceId switch
|
private async Task HandleSubscriptionCreated(Event stripeEvent)
|
||||||
{
|
{
|
||||||
"price_1RjUskBMIadsOxJVgLwlVo1y" => "Basic",
|
try
|
||||||
"price_1RjUv9BMIadsOxJVORqlM4E9" => "Professional",
|
{
|
||||||
"price_1RjUw0BMIadsOxJVmdouNV1g" => "Premium",
|
if (stripeEvent.Data.Object is Subscription stripeSubscription)
|
||||||
"price_basic_yearly_placeholder" => "BasicYearly",
|
{
|
||||||
"price_professional_yearly_placeholder" => "ProfessionalYearly",
|
_logger.LogInformation($"Subscription created: {stripeSubscription.Id} for customer: {stripeSubscription.CustomerId}");
|
||||||
"price_premium_yearly_placeholder" => "PremiumYearly",
|
|
||||||
var id when id.Contains("basic") && id.Contains("yearly") => "BasicYearly",
|
// Get subscription record from our database
|
||||||
var id when id.Contains("professional") && id.Contains("yearly") => "ProfessionalYearly",
|
var subscription = await _subscriptionRepository.GetByStripeSubscriptionIdAsync(stripeSubscription.Id);
|
||||||
var id when id.Contains("premium") && id.Contains("yearly") => "PremiumYearly",
|
if (subscription != null)
|
||||||
var id when id.Contains("basic") => "Basic",
|
{
|
||||||
var id when id.Contains("professional") => "Professional",
|
var service = new SubscriptionItemService();
|
||||||
var id when id.Contains("premium") => "Premium",
|
var subItem = service.Get(stripeSubscription.Items.Data[0].Id);
|
||||||
_ => "Trial"
|
|
||||||
};
|
// Update subscription status to active
|
||||||
}
|
subscription.Status = "active";
|
||||||
|
subscription.UpdatedAt = DateTime.UtcNow;
|
||||||
private string GetSubscriptionId(Event stripeEvent)
|
subscription.CurrentPeriodStart = subItem.CurrentPeriodStart;
|
||||||
{
|
subscription.CurrentPeriodEnd = subItem.CurrentPeriodEnd;
|
||||||
if (stripeEvent.Data.Object is Invoice invoice)
|
|
||||||
{
|
// Update plan type based on Stripe price ID
|
||||||
var subscriptionLineItem = invoice.Lines?.Data
|
var priceId = stripeSubscription.Items.Data.FirstOrDefault()?.Price.Id;
|
||||||
.FirstOrDefault(line =>
|
if (!string.IsNullOrEmpty(priceId))
|
||||||
!string.IsNullOrEmpty(line.SubscriptionId) ||
|
{
|
||||||
line.Subscription != null
|
subscription.PlanType = MapPriceIdToPlanType(priceId);
|
||||||
);
|
}
|
||||||
|
|
||||||
string subscriptionId = null;
|
await _subscriptionRepository.UpdateAsync(subscription);
|
||||||
|
|
||||||
if (subscriptionLineItem != null)
|
// Activate user pages that were pending payment or trial
|
||||||
{
|
var userPages = await _userPageService.GetUserPagesAsync(subscription.UserId);
|
||||||
// Tenta obter o ID da assinatura de duas formas diferentes
|
foreach (var page in userPages.Where(p =>
|
||||||
subscriptionId = subscriptionLineItem.SubscriptionId
|
p.Status == ViewModels.PageStatus.PendingPayment ||
|
||||||
?? subscriptionLineItem.Subscription?.Id;
|
p.Status == ViewModels.PageStatus.Expired))
|
||||||
}
|
{
|
||||||
|
page.Status = ViewModels.PageStatus.Active;
|
||||||
return subscriptionId;
|
page.UpdatedAt = DateTime.UtcNow;
|
||||||
}
|
await _userPageService.UpdatePageAsync(page);
|
||||||
else if (stripeEvent.Data.Object is Subscription stripeSubscription)
|
}
|
||||||
{
|
|
||||||
return stripeSubscription.Id;
|
_logger.LogInformation($"Activated subscription and {userPages.Count()} pages for user {subscription.UserId}");
|
||||||
}
|
}
|
||||||
|
else
|
||||||
return null;
|
{
|
||||||
}
|
_logger.LogWarning($"Subscription not found in database: {stripeSubscription.Id}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_logger.LogWarning($"Unexpected event type on HandleSubscriptionCreated: {stripeEvent.Type}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex, "Error handling subscription created event");
|
||||||
|
throw new Exception("Error handling subscription created event", ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private string MapPriceIdToPlanType(string priceId)
|
||||||
|
{
|
||||||
|
// Map Stripe price IDs to plan types
|
||||||
|
// This would be configured based on your actual Stripe price IDs
|
||||||
|
return priceId switch
|
||||||
|
{
|
||||||
|
"price_1RjUskBMIadsOxJVgLwlVo1y" => "Basic",
|
||||||
|
"price_1RjUv9BMIadsOxJVORqlM4E9" => "Professional",
|
||||||
|
"price_1RjUw0BMIadsOxJVmdouNV1g" => "Premium",
|
||||||
|
"price_basic_yearly_placeholder" => "BasicYearly",
|
||||||
|
"price_professional_yearly_placeholder" => "ProfessionalYearly",
|
||||||
|
"price_premium_yearly_placeholder" => "PremiumYearly",
|
||||||
|
var id when id.Contains("basic") && id.Contains("yearly") => "BasicYearly",
|
||||||
|
var id when id.Contains("professional") && id.Contains("yearly") => "ProfessionalYearly",
|
||||||
|
var id when id.Contains("premium") && id.Contains("yearly") => "PremiumYearly",
|
||||||
|
var id when id.Contains("basic") => "Basic",
|
||||||
|
var id when id.Contains("professional") => "Professional",
|
||||||
|
var id when id.Contains("premium") => "Premium",
|
||||||
|
_ => "Trial"
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private string GetSubscriptionId(Event stripeEvent)
|
||||||
|
{
|
||||||
|
if (stripeEvent.Data.Object is Invoice invoice)
|
||||||
|
{
|
||||||
|
var subscriptionLineItem = invoice.Lines?.Data
|
||||||
|
.FirstOrDefault(line =>
|
||||||
|
!string.IsNullOrEmpty(line.SubscriptionId) ||
|
||||||
|
line.Subscription != null
|
||||||
|
);
|
||||||
|
|
||||||
|
string subscriptionId = null;
|
||||||
|
|
||||||
|
if (subscriptionLineItem != null)
|
||||||
|
{
|
||||||
|
// Tenta obter o ID da assinatura de duas formas diferentes
|
||||||
|
subscriptionId = subscriptionLineItem.SubscriptionId
|
||||||
|
?? subscriptionLineItem.Subscription?.Id;
|
||||||
|
}
|
||||||
|
|
||||||
|
return subscriptionId;
|
||||||
|
}
|
||||||
|
else if (stripeEvent.Data.Object is Subscription stripeSubscription)
|
||||||
|
{
|
||||||
|
return stripeSubscription.Id;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Loading…
Reference in New Issue
Block a user