using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; using Domain.Entities.Members; namespace Domain.Entities.Payments.Toss; /// /// 토스페이먼츠 결제 승인 요청 + 응답 통합 /// confirm API 호출 시 요청 데이터를 먼저 저장하고, 응답 수신 시 업데이트 /// public class TossConfirm { [ForeignKey(nameof(MemberID))] public virtual Member? Member { get; private set; } [ForeignKey(nameof(PaymentOrderID))] public virtual PaymentOrder? PaymentOrder { get; private set; } [Key] public int ID { get; private set; } public int MemberID { get; private set; } public int PaymentOrderID { get; private set; } /// 토스 결제 키 (unique — 취소·조회 API 호출에 필요) public string PaymentKey { get; private set; } = default!; /// 가맹점 주문번호 public string OrderID { get; private set; } = default!; /// 승인 요청 금액 (서버 저장 주문 금액) public int Amount { get; private set; } // ── 응답 필드 (승인 완료/실패 시 업데이트) ────────────────────── /// 응답 코드 (SUCCESS = 성공, 그 외 = Toss 에러 코드/EXCEPTION) public string? ResponseCode { get; private set; } /// 응답 메시지 (실패 사유) public string? ResponseMessage { get; private set; } /// Toss Payment.status (DONE / WAITING_FOR_DEPOSIT / CANCELED / ABORTED / EXPIRED ...) public string? Status { get; private set; } /// 결제수단 (Toss method 문자열 — 카드/가상계좌/간편결제 등) public string? Method { get; private set; } /// 최종 승인 금액 (Toss totalAmount) public int? TotalAmount { get; private set; } /// 승인 일시 (UTC) public DateTime? ApprovedAt { get; private set; } /// 영수증 URL (Toss receipt.url) public string? ReceiptUrl { get; private set; } /// Toss Payment 객체 원문 JSON — 대사/CS 용 public string? RawResponse { get; private set; } public DateTime CreatedAt { get; private set; } = DateTime.UtcNow; public DateTime? UpdatedAt { get; private set; } private TossConfirm() { } /// 승인 요청 시 생성 (응답 전) public static TossConfirm CreateRequest( int memberID, int paymentOrderID, string paymentKey, string orderID, int amount ) { return new TossConfirm { MemberID = memberID, PaymentOrderID = paymentOrderID, PaymentKey = paymentKey, OrderID = orderID, Amount = amount }; } /// 승인 성공 응답 수신 시 업데이트 public void SetResponse( string status, string? method = null, int? totalAmount = null, DateTime? approvedAt = null, string? receiptUrl = null, string? rawResponse = null ) { ResponseCode = "SUCCESS"; ResponseMessage = null; Status = status; Method = method; TotalAmount = totalAmount; ApprovedAt = approvedAt; ReceiptUrl = receiptUrl; RawResponse = rawResponse; UpdatedAt = DateTime.UtcNow; } /// 승인 실패/예외 시 업데이트 public void SetError(string code, string message) { ResponseCode = code; ResponseMessage = message.Length > 500 ? message[..500] : message; UpdatedAt = DateTime.UtcNow; } /// /// 재승인(대사 재확인) 시 기존 요청 행을 재사용한다. PaymentKey/OrderID unique 인덱스 충돌을 피하려 /// 새 행을 만들지 않고, 결제 키를 갱신하고 이전 응답을 초기화해 "요청 후 응답 미수신" 상태로 되돌린다. (Phase 1.5 승계) /// public void PrepareRetry(string paymentKey) { PaymentKey = paymentKey; ResponseCode = null; ResponseMessage = null; UpdatedAt = DateTime.UtcNow; } public bool IsSuccess => ResponseCode == "SUCCESS"; }