using System.Text.Json; using Tiku.Domain.Common; namespace Tiku.Domain.Commerce; public sealed class Product : AuditableTenantEntity { public Guid? RegionId { get; set; } public string? LegacyId { get; set; } public string Title { get; set; } = string.Empty; public string? LegacyPriceText { get; set; } public string? Link { get; set; } public ProductType Type { get; set; } = ProductType.Material; public JsonElement Tags { get; set; } = JsonDefaults.Array(); public int SortOrder { get; set; } public string? Cover { get; set; } public string? PreviewIframe { get; set; } public JsonElement DetailImages { get; set; } = JsonDefaults.Array(); } public sealed class SvipPlan : AuditableTenantEntity { public Guid? RegionId { get; set; } public string? LegacyId { get; set; } public string Name { get; set; } = string.Empty; public int PriceCents { get; set; } public int? OriginalPriceCents { get; set; } public int Days { get; set; } public string? Description { get; set; } public string? PerDayLabel { get; set; } public string? Badge { get; set; } public bool Recommended { get; set; } public bool CouponOnly { get; set; } public string? VpProductId { get; set; } public bool VpEnabled { get; set; } public int SortOrder { get; set; } public bool IsActive { get; set; } = true; } public sealed class Order : AuditableTenantEntity { public Guid? UserId { get; set; } public Guid? PlanId { get; set; } public Guid? RegionId { get; set; } public string? LegacyId { get; set; } public string? LegacyUserId { get; set; } public string? LegacyPlanId { get; set; } public string? LegacyRegionId { get; set; } public string OrderNo { get; set; } = string.Empty; public OrderStatus Status { get; set; } = OrderStatus.Pending; public string? ProductType { get; set; } public string? ProductName { get; set; } public int AmountCents { get; set; } public string? PayMethod { get; set; } public string? PayProvider { get; set; } public string? TradeNo { get; set; } public int? Days { get; set; } public DateTimeOffset? PaidAt { get; set; } public JsonElement RawPayload { get; set; } = JsonDefaults.Object(); } public sealed class OrderItem : AuditableTenantEntity { public Guid OrderId { get; set; } public string? LegacyId { get; set; } public string ItemType { get; set; } = string.Empty; public Guid? ItemId { get; set; } public string Name { get; set; } = string.Empty; public int Quantity { get; set; } = 1; public int UnitAmountCents { get; set; } public int TotalAmountCents { get; set; } public JsonElement Metadata { get; set; } = JsonDefaults.Object(); } public sealed class Payment : AuditableTenantEntity { public Guid OrderId { get; set; } public string? LegacyId { get; set; } public string? LegacyOrderId { get; set; } public string Provider { get; set; } = string.Empty; public string? Method { get; set; } public PaymentStatus Status { get; set; } = PaymentStatus.Pending; public int AmountCents { get; set; } public string? ProviderTradeNo { get; set; } public DateTimeOffset? PaidAt { get; set; } public JsonElement RawPayload { get; set; } = JsonDefaults.Object(); } public sealed class PaymentEvent : Entity { public Guid TenantId { get; set; } public Guid? PaymentId { get; set; } public string Provider { get; set; } = string.Empty; public string EventType { get; set; } = string.Empty; public string? EventId { get; set; } public bool? SignatureValid { get; set; } public JsonElement Payload { get; set; } = JsonDefaults.Object(); public DateTimeOffset? ProcessedAt { get; set; } public string? Error { get; set; } public DateTimeOffset CreatedAt { get; set; } = DateTimeOffset.UtcNow; } public sealed class Entitlement : Entity { public Guid TenantId { get; set; } public Guid UserId { get; set; } public string EntitlementType { get; set; } = "svip"; public EntitlementScopeType ScopeType { get; set; } = EntitlementScopeType.Tenant; public Guid? ScopeId { get; set; } public string SourceType { get; set; } = "migration"; public Guid? SourceId { get; set; } public string? LegacySourceId { get; set; } public DateTimeOffset StartsAt { get; set; } = DateTimeOffset.UtcNow; public DateTimeOffset? ExpiresAt { get; set; } public EntitlementStatus Status { get; set; } = EntitlementStatus.Active; public JsonElement Metadata { get; set; } = JsonDefaults.Object(); public DateTimeOffset CreatedAt { get; set; } = DateTimeOffset.UtcNow; } public sealed class CodeBatch : AuditableTenantEntity { public Guid? RegionId { get; set; } public Guid? CreatedBy { get; set; } public string? LegacyId { get; set; } public string Name { get; set; } = string.Empty; public string? SaleType { get; set; } public string? Channel { get; set; } public string? CampaignName { get; set; } public int DefaultUnitPriceCents { get; set; } public int CostPriceCents { get; set; } public int TotalCount { get; set; } public int? Days { get; set; } public string? LegacyRegionId { get; set; } public DateTimeOffset? IssuedAt { get; set; } public string? Remark { get; set; } public decimal? CommissionRate { get; set; } } public sealed class ActivationCode : AuditableTenantEntity { public Guid? UsedBy { get; set; } public Guid? AgentUserId { get; set; } public Guid? BatchId { get; set; } public Guid? UsedRegionId { get; set; } public Guid? CouponRedemptionId { get; set; } public string? LegacyId { get; set; } public string Code { get; set; } = string.Empty; public int Days { get; set; } public bool IsUsed { get; set; } public DateTimeOffset? UsedAt { get; set; } public string? SaleType { get; set; } public int? UnitPriceCents { get; set; } public string? SoldTo { get; set; } public string? CouponCode { get; set; } public string? Remark { get; set; } } public sealed class Coupon : AuditableTenantEntity { public Guid? PlanId { get; set; } public string? LegacyId { get; set; } public string Code { get; set; } = string.Empty; public DiscountType? DiscountType { get; set; } public decimal? DiscountValue { get; set; } public DateTimeOffset? ValidFrom { get; set; } public DateTimeOffset? ValidTo { get; set; } public int? MaxUses { get; set; } public int UsedCount { get; set; } public string? Source { get; set; } public string? Remark { get; set; } } public sealed class CouponRedemption : AuditableTenantEntity { public Guid? CouponId { get; set; } public Guid? UserId { get; set; } public Guid? PlanId { get; set; } public Guid? OrderId { get; set; } public Guid? RegionId { get; set; } public string? LegacyId { get; set; } public string? CouponCode { get; set; } public CouponRedemptionStatus Status { get; set; } = CouponRedemptionStatus.Claimed; public int? DiscountAppliedCents { get; set; } public string? Source { get; set; } public string? Remark { get; set; } public DateTimeOffset? ClaimedAt { get; set; } public DateTimeOffset? UsedAt { get; set; } } public sealed class TenantPaymentAccount : AuditableTenantEntity { public string Provider { get; set; } = string.Empty; public TenantPaymentMode Mode { get; set; } = TenantPaymentMode.PlatformCollect; public string? DisplayName { get; set; } public TenantPaymentAccountStatus Status { get; set; } = TenantPaymentAccountStatus.Disabled; public JsonElement ConfigPublic { get; set; } = JsonDefaults.Object(); } public sealed class TenantSubscription : AuditableTenantEntity { public string PlanCode { get; set; } = string.Empty; public TenantSubscriptionStatus Status { get; set; } = TenantSubscriptionStatus.Trial; public DateTimeOffset? StartsAt { get; set; } public DateTimeOffset? ExpiresAt { get; set; } public string? BillingCycle { get; set; } = "yearly"; public int AmountCents { get; set; } public JsonElement Metadata { get; set; } = JsonDefaults.Object(); } public sealed class TenantUsageRecord : Entity { public Guid TenantId { get; set; } public string MetricKey { get; set; } = string.Empty; public decimal MetricValue { get; set; } public DateOnly PeriodStart { get; set; } public DateOnly PeriodEnd { get; set; } public JsonElement Metadata { get; set; } = JsonDefaults.Object(); public DateTimeOffset CreatedAt { get; set; } = DateTimeOffset.UtcNow; } public enum ProductType { Material, Course, Service, Link, Other } public enum OrderStatus { Pending, Paid, Failed, Closed, Refunded } public enum PaymentStatus { Pending, Paid, Failed, Cancelled, Refunded } public enum EntitlementScopeType { Tenant, Region, Module, Subject, QuestionBank } public enum EntitlementStatus { Active, Revoked, Expired } public enum DiscountType { Percent, Fixed } public enum CouponRedemptionStatus { Claimed, Used, Expired, Cancelled } public enum TenantPaymentMode { PlatformCollect, TenantCollect, ServiceProvider } public enum TenantPaymentAccountStatus { Active, Disabled, Pending } public enum TenantSubscriptionStatus { Trial, Active, PastDue, Cancelled }