Files
tiku-backend.net/Tiku.Infrastructure/Commerce/Payments/CommercePaymentService.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

91 lines
3.4 KiB
C#

using System.Text.Json;
using Microsoft.EntityFrameworkCore;
using Tiku.Application.Commerce;
using Tiku.Domain.Commerce;
namespace Tiku.Infrastructure.Commerce;
internal sealed class CommercePaymentService(CommerceServiceDependencies dependencies)
: CommerceServiceBase(dependencies), ICommercePaymentService
{
public async Task<CommercePaymentItem> CreatePaymentAsync(
CommerceActor actor,
CreateCommercePaymentCommand command,
CancellationToken cancellationToken = default)
{
await AssertActiveMemberAsync(actor, cancellationToken);
var order = await FindActorOrderAsync(actor, command.OrderNo, cancellationToken);
if (order.Status != OrderStatus.Pending)
throw new CommerceException("Only pending orders can create payments.", "order_status_invalid");
var provider = NormalizeProvider(command.Provider);
var method = NormalizeMethod(command.Method);
var payment = await commercePersistence.Payments
.Where(item =>
item.TenantId == actor.TenantId &&
item.OrderId == order.Id &&
item.Provider == provider &&
item.Status == PaymentStatus.Pending)
.OrderByDescending(item => item.CreatedAt)
.FirstOrDefaultAsync(cancellationToken);
if (payment is null)
{
payment = new Payment
{
TenantId = actor.TenantId,
OrderId = order.Id,
Provider = provider,
Method = method,
Status = PaymentStatus.Pending,
AmountCents = order.AmountCents
};
commercePersistence.Payments.Add(payment);
}
var result = await paymentGateway.CreatePaymentAsync(
provider,
new CreatePaymentProviderRequest(
actor.TenantId,
order.OrderNo,
order.ProductName ?? order.OrderNo,
order.AmountCents,
method,
command.OpenId,
command.ReturnUrl,
command.QuitUrl,
$"/api/student/commerce/payments/notify/{provider.Replace("_", "-", StringComparison.Ordinal)}?tenantId={actor.TenantId}",
JsonSerializer.SerializeToElement(new { order.Id, actor.UserId })),
cancellationToken);
payment.Method = result.Method;
payment.RawPayload = result.RawPayload;
if (!string.IsNullOrWhiteSpace(result.ProviderTradeNo)) payment.ProviderTradeNo = result.ProviderTradeNo;
if (IsPaid(result.Status))
await MarkPaidAsync(
actor,
order,
payment,
result.ProviderTradeNo,
result.RawPayload,
"payment_paid",
result.ProviderTradeNo,
true,
null,
cancellationToken);
else
commercePersistence.PaymentEvents.Add(new PaymentEvent
{
TenantId = actor.TenantId,
PaymentId = payment.Id,
Provider = provider,
EventType = "payment_created",
Payload = result.RawPayload
});
await commercePersistence.SaveChangesAsync(cancellationToken);
return ToPaymentItem(payment, order.OrderNo, result.ClientPayload);
}
}