GameProductCatalog.cs 2.3 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182
  1. using System.ComponentModel.DataAnnotations;
  2. using System.ComponentModel.DataAnnotations.Schema;
  3. namespace Domain.Entities.Store;
  4. /// <summary>
  5. /// 게임별 인앱 상품 SKU 정가 카탈로그. 파트너 결제 보고(ApiPurchase) 금액 검증용 —
  6. /// 보고가가 정가와 다르면 ApiPurchase.PriceMismatched flag (등록은 통과, Admin 검토).
  7. /// 카탈로그 미등록 SKU 는 검증 없이 통과.
  8. /// </summary>
  9. public class GameProductCatalog
  10. {
  11. [ForeignKey(nameof(GameID))]
  12. public virtual Game? Game { get; private set; }
  13. [Key]
  14. public int ID { get; private set; }
  15. public int GameID { get; private set; }
  16. /// <summary>인앱 상품 SKU (예: "diamond_100"). (GameID, ProductID) UNIQUE.</summary>
  17. public string ProductID { get; private set; } = default!;
  18. /// <summary>정가 (KRW)</summary>
  19. public int Price { get; private set; }
  20. public bool IsActive { get; private set; } = true;
  21. public DateTime CreatedAt { get; private set; } = DateTime.UtcNow;
  22. public DateTime? UpdatedAt { get; private set; }
  23. private GameProductCatalog() { }
  24. public static GameProductCatalog Create(int gameID, string productID, int price)
  25. {
  26. if (gameID <= 0)
  27. {
  28. throw new ArgumentOutOfRangeException(nameof(gameID));
  29. }
  30. ValidateProductID(productID);
  31. ValidatePrice(price);
  32. return new GameProductCatalog
  33. {
  34. GameID = gameID,
  35. ProductID = productID.Trim(),
  36. Price = price
  37. };
  38. }
  39. public void Update(int price, bool isActive)
  40. {
  41. ValidatePrice(price);
  42. Price = price;
  43. IsActive = isActive;
  44. UpdatedAt = DateTime.UtcNow;
  45. }
  46. private static void ValidateProductID(string productID)
  47. {
  48. if (string.IsNullOrWhiteSpace(productID))
  49. {
  50. throw new ArgumentException("ProductID is required.", nameof(productID));
  51. }
  52. if (productID.Length > 100)
  53. {
  54. throw new ArgumentOutOfRangeException(nameof(productID), "ProductID 는 100자 이하로 입력하세요.");
  55. }
  56. }
  57. private static void ValidatePrice(int price)
  58. {
  59. if (price <= 0)
  60. {
  61. throw new ArgumentOutOfRangeException(nameof(price), "Price must be positive.");
  62. }
  63. }
  64. }