feat: add referral crm and commission persistence

This commit is contained in:
xiong
2026-07-26 05:41:47 +08:00
parent fc8e04ebd6
commit 07e2db04d0
7 changed files with 13730 additions and 1 deletions

View File

@@ -0,0 +1,182 @@
using System.Text.Json;
using Tiku.Domain.Common;
namespace Tiku.Domain.Growth;
public sealed class ReferralTrack : AuditableTenantEntity
{
public Guid? LeadId { get; set; }
public Guid? ReferrerUserId { get; set; }
public Guid? TargetUserId { get; set; }
public string? LegacyId { get; set; }
public string EventType { get; set; } = string.Empty;
public string? RefCode { get; set; }
public string? Source { get; set; }
public string? IpAddress { get; set; }
public string? UserAgent { get; set; }
public JsonElement Metadata { get; set; } = JsonDefaults.Object();
}
public sealed class ReferralCode : AuditableTenantEntity
{
public Guid UserId { get; set; }
public string Code { get; set; } = string.Empty;
public ReferralCodeStatus Status { get; set; } = ReferralCodeStatus.Active;
public string? Channel { get; set; }
public string? LandingPath { get; set; }
public JsonElement Metadata { get; set; } = JsonDefaults.Object();
}
public sealed class ReferralLead : AuditableTenantEntity
{
public Guid StudentUserId { get; set; }
public Guid? ReferrerUserId { get; set; }
public Guid? FirstTrackId { get; set; }
public Guid? AssignedToUserId { get; set; }
public Guid? AssignedBy { get; set; }
public string? RefCode { get; set; }
public string? Source { get; set; }
public ReferralLeadBindType BindType { get; set; } = ReferralLeadBindType.FirstTouch;
public ReferralLeadStatus Status { get; set; } = ReferralLeadStatus.Protected;
public DateTimeOffset? ProtectedUntil { get; set; }
public ReferralAssignmentMode? AssignmentMode { get; set; }
public DateTimeOffset? AssignedAt { get; set; }
public JsonElement Metadata { get; set; } = JsonDefaults.Object();
public DateTimeOffset BoundAt { get; set; } = DateTimeOffset.UtcNow;
}
public sealed class ReferralTeamEdge : AuditableTenantEntity
{
public Guid MemberUserId { get; set; }
public Guid? LeaderUserId { get; set; }
public ReferralTeamRelationType RelationType { get; set; } = ReferralTeamRelationType.SalesTeam;
public ReferralTeamEdgeStatus Status { get; set; } = ReferralTeamEdgeStatus.Active;
public JsonElement Metadata { get; set; } = JsonDefaults.Object();
}
public sealed class ReferralQrcode : AuditableTenantEntity
{
public Guid? UserId { get; set; }
public string RefCode { get; set; } = string.Empty;
public string Scene { get; set; } = string.Empty;
public string Page { get; set; } = "pages/index/index";
public string Provider { get; set; } = "wechat-miniapp";
public string? QrcodeUrl { get; set; }
public ReferralQrcodeStatus Status { get; set; } = ReferralQrcodeStatus.Pending;
public string? ErrorMessage { get; set; }
public JsonElement Metadata { get; set; } = JsonDefaults.Object();
}
public sealed class CrmConfig : AuditableTenantEntity
{
public bool Enabled { get; set; }
public string? Url { get; set; }
public string? SecretRef { get; set; }
public string? FormName { get; set; }
public string? ExamType { get; set; }
public int? TimeoutSeconds { get; set; }
public int? DelaySeconds { get; set; }
public ReferralAssignmentMode AssignmentMode { get; set; } = ReferralAssignmentMode.None;
public JsonElement AssignmentPool { get; set; } = JsonDefaults.Array();
public int AssignmentCursor { get; set; }
public JsonElement AssignmentConfig { get; set; } = JsonDefaults.Object();
}
public sealed class CrmWebhookQueueItem : AuditableTenantEntity
{
public string? LegacyId { get; set; }
public string? RecordId { get; set; }
public string? LeadId { get; set; }
public string? Source { get; set; }
public string? Provider { get; set; }
public CrmWebhookQueueStatus Status { get; set; } = CrmWebhookQueueStatus.Pending;
public DateTimeOffset? ScheduledAt { get; set; }
public int Attempts { get; set; }
public DateTimeOffset? NextAttemptAt { get; set; }
public DateTimeOffset? LastAttemptAt { get; set; }
public string? LastError { get; set; }
public int? LastHttpCode { get; set; }
public string? LastResponseSummary { get; set; }
public DateTimeOffset? SentAt { get; set; }
public string? IdempotencyKey { get; set; }
public string? TargetUrl { get; set; }
public JsonElement Payload { get; set; } = JsonDefaults.Object();
}
public sealed class CrmWebhookLog : AuditableTenantEntity
{
public string? LegacyId { get; set; }
public string? RecordId { get; set; }
public string? LeadId { get; set; }
public int? HttpCode { get; set; }
public string? Outcome { get; set; }
public string? ErrorMessage { get; set; }
public string? RequestBody { get; set; }
public JsonElement RequestPayload { get; set; } = JsonDefaults.Object();
public string? ResponseSummary { get; set; }
public DateTimeOffset? SignedAt { get; set; }
public int? Attempt { get; set; }
}
public sealed class TenantCommissionSetting : AuditableTenantEntity
{
public decimal DefaultRate { get; set; } = 0.2m;
public int MinSettlementCents { get; set; }
public CommissionSettlementCycle SettlementCycle { get; set; } = CommissionSettlementCycle.Monthly;
public JsonElement Config { get; set; } = JsonDefaults.Object();
public Guid? UpdatedBy { get; set; }
}
public sealed class CommissionSettlement : AuditableTenantEntity
{
public Guid ReferrerUserId { get; set; }
public Guid? GeneratedBy { get; set; }
public Guid? ReviewedBy { get; set; }
public Guid? PaidBy { get; set; }
public string SettlementNo { get; set; } = string.Empty;
public CommissionSettlementStatus Status { get; set; } = CommissionSettlementStatus.Draft;
public DateOnly PeriodStart { get; set; }
public DateOnly PeriodEnd { get; set; }
public int SourceCount { get; set; }
public int PaidUserCount { get; set; }
public int GrossAmountCents { get; set; }
public int CommissionAmountCents { get; set; }
public decimal DefaultRate { get; set; }
public decimal? EffectiveRate { get; set; }
public DateTimeOffset? ReviewedAt { get; set; }
public DateTimeOffset? PaidAt { get; set; }
public string? PaymentMethod { get; set; }
public string? PaymentAccount { get; set; }
public string? Remark { get; set; }
public JsonElement Metadata { get; set; } = JsonDefaults.Object();
}
public sealed class CommissionSettlementItem : AuditableTenantEntity
{
public Guid? SettlementId { get; set; }
public Guid ReferrerUserId { get; set; }
public Guid? StudentUserId { get; set; }
public CommissionSourceType SourceType { get; set; } = CommissionSourceType.Order;
public Guid SourceId { get; set; }
public string? SourceNo { get; set; }
public DateTimeOffset? SourcePaidAt { get; set; }
public int GrossAmountCents { get; set; }
public decimal CommissionRate { get; set; }
public int CommissionAmountCents { get; set; }
public CommissionRateSource RateSource { get; set; } = CommissionRateSource.Default;
public string AttributionType { get; set; } = "protected_lead";
public JsonElement Metadata { get; set; } = JsonDefaults.Object();
}
public enum ReferralCodeStatus { Active, Disabled }
public enum ReferralLeadBindType { FirstTouch, Manual, Imported }
public enum ReferralLeadStatus { Protected, Invalid, Released }
public enum ReferralAssignmentMode { None, Direct, RoundRobin, Referrer }
public enum ReferralTeamRelationType { SalesTeam, AgentNetwork, TeacherClass }
public enum ReferralTeamEdgeStatus { Active, Disabled }
public enum ReferralQrcodeStatus { Pending, Ready, Failed, Disabled }
public enum CrmWebhookQueueStatus { Pending, Processing, Retrying, Sent, Failed, Discarded }
public enum CommissionSettlementCycle { Manual, Weekly, Monthly }
public enum CommissionSettlementStatus { Draft, PendingReview, Approved, Paid, Rejected, Cancelled }
public enum CommissionSourceType { Order, ActivationCode }
public enum CommissionRateSource { Batch, Member, Default }