| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061 |
- using Application.Abstractions.Data;
- using Application.Abstractions.Messaging;
- using Application.Abstractions.Payment;
- using Domain.Entities.Payments;
- using Domain.Entities.Payments.ValueObject;
- using Microsoft.EntityFrameworkCore;
- using SharedKernel.Results;
- namespace Application.Features.Api.Payment.Toss.CreateOrder;
- internal sealed class Handler(
- IAppDbContext db,
- ITossPaymentService tossPay
- ) : ICommandHandler<Command, Result<Response>>
- {
- /// <summary>토스에서 사용할 MerchantID 표기 (PaymentOrder.MerchantID 필수 컬럼)</summary>
- private const string TossMerchantMark = "TOSS";
- public async Task<Result<Response>> Handle(Command r, CancellationToken ct)
- {
- if (r.Amount <= 0)
- {
- return Result.Failure<Response>(new Error("Payment.InvalidAmount", "충전 금액이 올바르지 않습니다.", ErrorType.Validation));
- }
- var member = await db.Member.FirstOrDefaultAsync(c => c.ID == r.MemberID, ct);
- if (member is null)
- {
- return Result.Failure<Response>(Error.NotFound("Payment.MemberNotFound", "회원 정보를 찾을 수 없습니다."));
- }
- // customerKey — 예측 가능 값(SID/이메일/PK) 금지, 회원별 UUID 발급·저장 (Guid 문자열은 '-' 포함 = 특수문자 조건 충족)
- var customerKey = member.EnsurePaymentCustomerKey();
- // 주문번호 생성 — 6~64자, 영숫자와 -_ 만 (기존 prefix 방식 미러링)
- var orderID = $"ANTOOZA-{DateTime.UtcNow:yyyyMMddHHmmss}-{r.MemberID}-{Random.Shared.Next(1000, 9999)}";
- if (orderID.Length is < 6 or > 64 || orderID.Any(c => !char.IsAsciiLetterOrDigit(c) && c != '-' && c != '_'))
- {
- return Result.Failure<Response>(new Error("Payment.InvalidOrderID", "주문번호 생성에 실패했습니다.", ErrorType.Validation));
- }
- // 토스 클라이언트 설정 (ClientKey 획득 — 설정 미비 시 예외로 조기 실패)
- var config = await tossPay.GetClientConfigAsync(ct);
- // 서버가 금액·orderName 확정 저장 — Confirm 시 클라이언트 금액과 대조해 변조 차단
- var order = PaymentOrder.Create(r.MemberID, orderID, TossMerchantMark, r.Amount, PaymentMethod.Integrated, "개미투자 캐시 충전");
- await db.PaymentOrder.AddAsync(order, ct);
- await db.SaveChangesAsync(ct);
- return new Response(
- orderID,
- order.OrderName,
- order.Amount,
- order.PointAmount,
- order.VatAmount,
- config.ClientKey,
- customerKey.ToString()
- );
- }
- }
|