| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128 |
- using System.ComponentModel.DataAnnotations;
- using System.ComponentModel.DataAnnotations.Schema;
- using Domain.Entities.Store.ValueObject;
- namespace Domain.Entities.Store;
- /// <summary>
- /// 게임사 월별 정산 큐. 매월 1일 새벽 HostedService 가 전월 Order 들의 GameRevenueAmount 를 GameID 별로 집계.
- /// UNIQUE (GameID, Year, Month). Admin 이 다운로드 후 수동 송금하고 Settled 마킹.
- /// </summary>
- public class GameSettlement
- {
- [ForeignKey(nameof(GameID))]
- public virtual Game? Game { get; private set; }
- [Key]
- public int ID { get; private set; }
- public int GameID { get; private set; }
- public int Year { get; private set; }
- public int Month { get; private set; }
- /// <summary>해당 월 누적 게임사 몫 (= Σ Order.GameRevenueAmount).</summary>
- public int TotalRevenueAmount { get; private set; }
- /// <summary>해당 월 주문 건수.</summary>
- public int OrderCount { get; private set; }
- public GameSettlementStatus Status { get; private set; } = GameSettlementStatus.Pending;
- public DateTime CreatedAt { get; private set; } = DateTime.UtcNow;
- public DateTime? SettledAt { get; private set; }
- /// <summary>처리 관리자 (ASP.NET Identity ApplicationUser.Id).</summary>
- public string? SettledByAdminUserId { get; private set; }
- /// <summary>처리 관리자 Email 스냅샷 (표시용).</summary>
- public string? SettledByAdminEmail { get; private set; }
- public string? AdminMemo { get; private set; }
- private GameSettlement() { }
- public static GameSettlement Create(int gameID, int year, int month)
- {
- if (gameID <= 0)
- {
- throw new ArgumentOutOfRangeException(nameof(gameID));
- }
- if (year < 2000 || year > 9999)
- {
- throw new ArgumentOutOfRangeException(nameof(year));
- }
- if (month < 1 || month > 12)
- {
- throw new ArgumentOutOfRangeException(nameof(month));
- }
- return new GameSettlement
- {
- GameID = gameID,
- Year = year,
- Month = month
- };
- }
- /// <summary>월간 집계 시 row 가 이미 있으면 누적. HostedService 에서 멱등 처리용.</summary>
- public void AddRevenue(int revenueAmount, int orderCount = 1)
- {
- if (revenueAmount < 0)
- {
- throw new ArgumentOutOfRangeException(nameof(revenueAmount));
- }
- if (orderCount < 0)
- {
- throw new ArgumentOutOfRangeException(nameof(orderCount));
- }
- if (Status != GameSettlementStatus.Pending)
- {
- throw new InvalidOperationException("이미 정산된 row 에는 추가 적재 불가.");
- }
- TotalRevenueAmount += revenueAmount;
- OrderCount += orderCount;
- }
- /// <summary>환불 시 비례 차감.</summary>
- public void SubtractRevenue(int revenueAmount)
- {
- if (revenueAmount <= 0)
- {
- throw new ArgumentOutOfRangeException(nameof(revenueAmount));
- }
- if (Status != GameSettlementStatus.Pending)
- {
- throw new InvalidOperationException("이미 정산된 row 에는 환불 차감 불가. 별도 정정 정산 row 필요.");
- }
- TotalRevenueAmount = Math.Max(0, TotalRevenueAmount - revenueAmount);
- }
- public void MarkSettled(string adminUserId, string? adminEmail, string? adminMemo = null)
- {
- if (Status != GameSettlementStatus.Pending)
- {
- throw new InvalidOperationException($"Cannot mark settled from status {Status}.");
- }
- if (string.IsNullOrWhiteSpace(adminUserId))
- {
- throw new ArgumentException("AdminUserId is required.", nameof(adminUserId));
- }
- Status = GameSettlementStatus.Settled;
- SettledByAdminUserId = adminUserId;
- SettledByAdminEmail = adminEmail;
- SettledAt = DateTime.UtcNow;
- AdminMemo = adminMemo;
- }
- }
|