Files
tiku-backend.net/Tiku.Infrastructure/Commerce/Refunds/RefundAdministrationService.Notifications.cs
xiong 33375a38d7
Some checks failed
ci / release-gate (push) Has been cancelled
refactor(architecture): harden module boundaries
2026-08-04 12:10:36 +08:00

73 lines
2.9 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 commercePersistence.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 commercePersistence.PaymentEvents.AnyAsync(
item => item.TenantId == tenantId &&
item.Provider == provider &&
item.EventType == "refund" &&
item.EventId == eventId,
cancellationToken);
if (duplicate) return refund;
commercePersistence.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;
}
commercePersistence.CommerceRefundEvents.Add(new CommerceRefundEvent
{
TenantId = tenantId,
RefundRequestId = refund.Id,
FromStatus = fromStatus,
ToStatus = command.Status,
EventType = "provider_notify",
Details = JsonObjectOrDefault(command.Payload)
});
}
await unitOfWork.SaveChangesAsync(cancellationToken);
return refund;
}
}