| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235 |
- using System.ComponentModel.DataAnnotations;
- namespace Domain.Entities.Store;
- /// <summary>
- /// 게임사 제휴 마스터. 상품/쿠폰의 필수 FK.
- /// CommissionRate(게임사 몫) % 만 정의. 채널 보상률은 Channel.StoreCommissionRate 에서 채널별로 동적으로 결정.
- /// dpot 몫 = 100 - Game.CommissionRate (채널 미선택) 또는 100 - Game.CommissionRate - Channel.StoreCommissionRate (채널 선택).
- /// </summary>
- public class Game
- {
- [Key]
- public int ID { get; private set; }
- /// <summary>게임 코드 (예: "LOL", "BG3"). UNIQUE. 외부 연동/내부 식별자.</summary>
- public string? Code { get; private set; }
- /// <summary>게임 한글명 (필수, UNIQUE) — 예: "리그 오브 레전드"</summary>
- public string KorName { get; private set; } = default!;
- /// <summary>게임 영문명 (선택) — 예: "League of Legends"</summary>
- public string? EngName { get; private set; }
- /// <summary>게임사/퍼블리셔 (예: "Riot Games Korea")</summary>
- public string Publisher { get; private set; } = default!;
- /// <summary>작은 이미지 (목록 카드/썸네일용)</summary>
- public string? Thumbnail { get; private set; }
- /// <summary>큰 이미지 (상품 상세 페이지 배너, 상점 메인 배너용)</summary>
- public string? BigImage { get; private set; }
- /// <summary>게임 소개 (HTML — CKEditor)</summary>
- public string? Description { get; private set; }
- /// <summary>게임사 수익률(커미션) % — 0~100. 주문 금액의 이 비율을 게임사 정산 큐에 적재.</summary>
- public decimal CommissionRate { get; private set; }
- /// <summary>게임 내 결제 보고(공개 API /v1/purchases) 채널 수수료율 % — 0~100. 0 이면 해당 게임 결제 등록 거부.</summary>
- public decimal ApiCommissionRate { get; private set; }
- /// <summary>게임 다운로드 또는 공식 사이트 주소 (선택)</summary>
- public string? Link { get; private set; }
- /// <summary>YouTube 예고편 URL (선택). 렌더 시 embed 로 정규화.</summary>
- public string? TrailerUrl { get; private set; }
- /// <summary>최소 사양 (자유 텍스트).</summary>
- public string? MinSpec { get; private set; }
- /// <summary>권장 사양 (자유 텍스트).</summary>
- public string? RecommendedSpec { get; private set; }
- /// <summary>게임 출시일 (선택).</summary>
- public DateOnly? ReleaseDate { get; private set; }
- public virtual List<GameImage> GameImage { get; private set; } = [];
- public virtual List<GameGenreMap> GameGenreMap { get; private set; } = [];
- public virtual List<GameCategoryMap> GameCategoryMap { get; private set; } = [];
- public virtual List<GameLanguageSupport> GameLanguageSupport { get; private set; } = [];
- public bool IsActive { get; private set; } = true;
- public int Order { get; private set; }
- public DateTime CreatedAt { get; private set; } = DateTime.UtcNow;
- public DateTime? UpdatedAt { get; private set; }
- private Game() { }
- public static Game Create(
- string korName,
- string publisher,
- decimal commissionRate,
- string? code = null,
- string? engName = null,
- string? thumbnail = null,
- string? bigImage = null,
- string? description = null,
- string? link = null,
- int order = 0
- ) {
- ValidateRate(commissionRate);
- ValidateNames(korName, engName);
- ValidatePublisher(publisher);
- ValidateCode(code);
- ValidateLink(link);
- return new Game
- {
- Code = NormalizeOptional(code),
- KorName = korName.Trim(),
- EngName = NormalizeOptional(engName),
- Publisher = publisher.Trim(),
- CommissionRate = commissionRate,
- Thumbnail = thumbnail,
- BigImage = bigImage,
- Description = description,
- Link = NormalizeOptional(link),
- Order = order
- };
- }
- public void Update(
- string korName,
- string publisher,
- decimal commissionRate,
- string? code,
- string? engName,
- string? thumbnail,
- string? bigImage,
- string? description,
- string? link,
- int order,
- bool isActive
- ) {
- ValidateRate(commissionRate);
- ValidateNames(korName, engName);
- ValidatePublisher(publisher);
- ValidateCode(code);
- ValidateLink(link);
- Code = NormalizeOptional(code);
- KorName = korName.Trim();
- EngName = NormalizeOptional(engName);
- Publisher = publisher.Trim();
- CommissionRate = commissionRate;
- Thumbnail = thumbnail;
- BigImage = bigImage;
- Description = description;
- Link = NormalizeOptional(link);
- Order = order;
- IsActive = isActive;
- UpdatedAt = DateTime.UtcNow;
- }
- public void Deactivate()
- {
- IsActive = false;
- UpdatedAt = DateTime.UtcNow;
- }
- /// <summary>API 결제 보고 채널 수수료율 설정. Create/Update 시그니처 변경 없이 별도 관리 (Admin 폼 전용).</summary>
- public void SetApiCommissionRate(decimal rate)
- {
- ValidateRate(rate);
- ApiCommissionRate = rate;
- UpdatedAt = DateTime.UtcNow;
- }
- /// <summary>상세 미디어/사양 설정 (Admin 게임 상세 폼 전용). Create/Update 시그니처 변경 회피.</summary>
- public void SetDetail(string? trailerUrl, string? minSpec, string? recommendedSpec, DateOnly? releaseDate)
- {
- if (trailerUrl is not null && trailerUrl.Length > 500)
- {
- throw new ArgumentOutOfRangeException(nameof(trailerUrl), "TrailerUrl 은 500자 이하로 입력하세요.");
- }
- TrailerUrl = NormalizeOptional(trailerUrl);
- MinSpec = NormalizeOptional(minSpec);
- RecommendedSpec = NormalizeOptional(recommendedSpec);
- ReleaseDate = releaseDate;
- UpdatedAt = DateTime.UtcNow;
- }
- private static void ValidateRate(decimal commissionRate)
- {
- if (commissionRate < 0 || commissionRate > 100)
- {
- throw new ArgumentOutOfRangeException(nameof(commissionRate), "0~100 사이의 값이어야 합니다.");
- }
- }
- private static void ValidateNames(string korName, string? engName)
- {
- if (string.IsNullOrWhiteSpace(korName))
- {
- throw new ArgumentException("KorName is required.", nameof(korName));
- }
- if (korName.Length > 255)
- {
- throw new ArgumentOutOfRangeException(nameof(korName), "KorName 은 255자 이하로 입력하세요.");
- }
- if (engName is not null && engName.Length > 255)
- {
- throw new ArgumentOutOfRangeException(nameof(engName), "EngName 은 255자 이하로 입력하세요.");
- }
- }
- private static void ValidatePublisher(string publisher)
- {
- if (string.IsNullOrWhiteSpace(publisher))
- {
- throw new ArgumentException("Publisher is required.", nameof(publisher));
- }
- if (publisher.Length > 100)
- {
- throw new ArgumentOutOfRangeException(nameof(publisher), "Publisher 는 100자 이하로 입력하세요.");
- }
- }
- private static void ValidateCode(string? code)
- {
- if (code is not null && code.Length > 6)
- {
- throw new ArgumentOutOfRangeException(nameof(code), "Code 는 6자 이하로 입력하세요.");
- }
- }
- private static void ValidateLink(string? link)
- {
- if (link is not null && link.Length > 255)
- {
- throw new ArgumentOutOfRangeException(nameof(link), "Link 는 255자 이하로 입력하세요.");
- }
- }
- private static string? NormalizeOptional(string? value)
- {
- if (string.IsNullOrWhiteSpace(value))
- {
- return null;
- }
- return value.Trim();
- }
- }
|