73 lines
2.8 KiB
C#
73 lines
2.8 KiB
C#
using System.Text.Json;
|
|
using Microsoft.EntityFrameworkCore;
|
|
using Tiku.Application.Commerce;
|
|
using Tiku.Application.Jobs;
|
|
using Tiku.Domain.Commerce;
|
|
|
|
namespace Tiku.Infrastructure.Commerce;
|
|
|
|
internal sealed partial class RefundAdministrationService
|
|
{
|
|
public async Task<CommerceRefundRequest> ProcessRefundNotificationAsync(
|
|
Guid tenantId,
|
|
RefundNotificationCommand command,
|
|
CancellationToken cancellationToken = default)
|
|
{
|
|
var provider = NormalizeProvider(command.Provider);
|
|
var refund = await dbContext.CommerceRefundRequests.SingleOrDefaultAsync(
|
|
item => item.TenantId == tenantId && item.RefundNo == command.RefundNo,
|
|
cancellationToken) ?? throw new CommerceException("Refund request was not found.", "refund_not_found");
|
|
var eventId = string.IsNullOrWhiteSpace(command.EventId)
|
|
? $"{provider}:{command.RefundNo}:{command.Status}"
|
|
: command.EventId.Trim();
|
|
var duplicate = await dbContext.PaymentEvents.AnyAsync(
|
|
item => item.TenantId == tenantId &&
|
|
item.Provider == provider &&
|
|
item.EventType == "refund" &&
|
|
item.EventId == eventId,
|
|
cancellationToken);
|
|
if (duplicate) return refund;
|
|
|
|
dbContext.PaymentEvents.Add(new PaymentEvent
|
|
{
|
|
TenantId = tenantId,
|
|
Provider = provider,
|
|
EventType = "refund",
|
|
EventId = eventId,
|
|
SignatureValid = true,
|
|
Payload = JsonObjectOrDefault(command.Payload),
|
|
ProcessedAt = DateTimeOffset.UtcNow
|
|
});
|
|
var fromStatus = refund.Status;
|
|
if (fromStatus != command.Status && IsAllowedRefundTransition(fromStatus, command.Status))
|
|
{
|
|
refund.Status = command.Status;
|
|
refund.ProviderRefundNo = string.IsNullOrWhiteSpace(command.ProviderRefundNo)
|
|
? refund.ProviderRefundNo
|
|
: command.ProviderRefundNo.Trim();
|
|
if (command.Status == CommerceRefundStatus.Succeeded)
|
|
{
|
|
refund.SucceededAt = DateTimeOffset.UtcNow;
|
|
await ApplyRefundToOrderAsync(refund, cancellationToken);
|
|
}
|
|
else if (command.Status == CommerceRefundStatus.Failed)
|
|
{
|
|
refund.FailedAt = DateTimeOffset.UtcNow;
|
|
}
|
|
|
|
dbContext.CommerceRefundEvents.Add(new CommerceRefundEvent
|
|
{
|
|
TenantId = tenantId,
|
|
RefundRequestId = refund.Id,
|
|
FromStatus = fromStatus,
|
|
ToStatus = command.Status,
|
|
EventType = "provider_notify",
|
|
Details = JsonObjectOrDefault(command.Payload)
|
|
});
|
|
}
|
|
|
|
await dbContext.SaveChangesAsync(cancellationToken);
|
|
return refund;
|
|
}
|
|
}
|