62 lines
3.1 KiB
C#
62 lines
3.1 KiB
C#
using Microsoft.EntityFrameworkCore;
|
|
using Microsoft.Extensions.DependencyInjection;
|
|
using Tiku.Application.Commerce;
|
|
using Tiku.Application.PlatformBilling;
|
|
using Tiku.Application.Security;
|
|
using Tiku.Infrastructure.Persistence;
|
|
|
|
namespace Tiku.Infrastructure.PlatformBilling;
|
|
|
|
internal sealed class PlatformBillingNotificationService(
|
|
ITenantExecutionScope tenantExecutionScope,
|
|
IPlatformBillingPaymentGateway paymentGateway) : IPlatformBillingNotificationService
|
|
{
|
|
public async Task ProcessAsync(PlatformBillingNotification notification,
|
|
CancellationToken cancellationToken = default)
|
|
{
|
|
var parsed = await paymentGateway.ParseNotificationAsync(
|
|
notification.Provider,
|
|
new PaymentNotificationRequest(Guid.Empty, notification.Provider, notification.Headers,
|
|
notification.RawBody, notification.Body),
|
|
cancellationToken);
|
|
if (!parsed.SignatureValid || !parsed.Paid)
|
|
throw Error("Payment notification was not a valid paid event.", "platform_billing_notification_invalid");
|
|
|
|
await tenantExecutionScope.ExecuteAsync(
|
|
new SystemScopeRequest(null, SystemScopeCallerType.Platform, nameof(PlatformBillingNotificationService),
|
|
"Settle platform billing notification", parsed.EventId, true),
|
|
async (services, token) =>
|
|
{
|
|
var db = services.GetRequiredService<IPlatformBillingPersistence>();
|
|
var order = await db.PlatformBillingOrders.AsNoTracking()
|
|
.SingleOrDefaultAsync(value => value.OrderNo == parsed.OrderNo, token)
|
|
?? throw Error("Platform billing order was not found.", "platform_billing_order_not_found");
|
|
if (order.TotalAmountCents != parsed.AmountCents)
|
|
throw Error("Payment notification amount does not match the order.",
|
|
"platform_billing_payment_amount_mismatch");
|
|
var payment = await db.PlatformBillingPayments.AsNoTracking()
|
|
.Where(value =>
|
|
value.TenantId == order.TenantId && value.OrderId == order.Id &&
|
|
value.Provider == parsed.Provider)
|
|
.OrderByDescending(value => value.CreatedAt)
|
|
.FirstOrDefaultAsync(token)
|
|
?? throw Error("Platform billing payment was not found.",
|
|
"platform_billing_payment_not_found");
|
|
await services.GetRequiredService<IPlatformBillingSettlementService>().MarkPaidAsync(
|
|
payment.Id,
|
|
parsed.EventId,
|
|
parsed.EventType,
|
|
parsed.ProviderTradeNo,
|
|
parsed.PaidAt ?? DateTimeOffset.UtcNow,
|
|
parsed.RawPayload,
|
|
null,
|
|
token);
|
|
},
|
|
cancellationToken);
|
|
}
|
|
|
|
private static PlatformBillingException Error(string message, string code)
|
|
{
|
|
return new PlatformBillingException(message, code);
|
|
}
|
|
} |