PaymentReconcileLog.cs 1.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051
  1. using System.ComponentModel.DataAnnotations;
  2. using Domain.Entities.Payments.ValueObject;
  3. namespace Domain.Entities.Payments;
  4. /// <summary>
  5. /// 대사(reconciliation) 로그. PG(다날) 호출은 성공했는데 그 이후 로컬 저장(SaveChanges)이 실패해
  6. /// PG-지갑/주문 상태가 어긋날 수 있는 순간을 독립 커밋으로 기록한다. 운영자가 이 로그를 근거로
  7. /// 다날 콘솔과 대조해 수동 대사한다. (Phase 1.5)
  8. /// </summary>
  9. public class PaymentReconcileLog
  10. {
  11. [Key]
  12. public int ID { get; private set; }
  13. /// <summary>대사 대상 주문(PaymentOrder.ID). FK 는 걸지 않는다 — 로그는 best-effort 로 항상 남아야 한다.</summary>
  14. public int PaymentOrderID { get; private set; }
  15. /// <summary>발생 흐름 (Confirm/Cancel/AdminCancel)</summary>
  16. public ReconcileKind Kind { get; private set; }
  17. /// <summary>다날 거래번호 (있으면)</summary>
  18. public string? TransactionID { get; private set; }
  19. /// <summary>대상 금액 (충전/환불 포인트)</summary>
  20. public int Amount { get; private set; }
  21. /// <summary>실패 사유 요약 (예외 메시지)</summary>
  22. public string Reason { get; private set; } = default!;
  23. public DateTime CreatedAt { get; private set; } = DateTime.UtcNow;
  24. private PaymentReconcileLog() { }
  25. public static PaymentReconcileLog Create(
  26. ReconcileKind kind,
  27. int paymentOrderID,
  28. string? transactionID,
  29. int amount,
  30. string reason
  31. ) {
  32. return new PaymentReconcileLog
  33. {
  34. Kind = kind,
  35. PaymentOrderID = paymentOrderID,
  36. TransactionID = transactionID,
  37. Amount = amount,
  38. Reason = string.IsNullOrEmpty(reason) ? "-" : reason.Length > 1000 ? reason[..1000] : reason
  39. };
  40. }
  41. }