Files
tiku-backend.net/Tiku.Infrastructure/Growth/TenantAdmin/ReferralService.TenantAdmin.cs
xiong c497a3ca8d
Some checks failed
ci / release-gate (push) Has been cancelled
清理代码
2026-08-03 12:31:39 +08:00

112 lines
4.7 KiB
C#

using Microsoft.EntityFrameworkCore;
using Tiku.Application.Growth;
using Tiku.Domain.Common;
using Tiku.Domain.Growth;
namespace Tiku.Infrastructure.Growth;
public sealed partial class ReferralService
{
public async Task<ReferralBindResult> ManualBindAsync(
ReferralAdminActor actor,
ManualBindReferralCommand command,
CancellationToken cancellationToken = default)
{
await AssertAdminAsync(actor, cancellationToken);
if (command.StudentUserId == command.ReferrerUserId)
throw new ReferralException("User cannot bind to own referral code.", "self_referral_not_allowed");
var refCode = await dbContext.ReferralCodes
.Where(item =>
item.TenantId == actor.TenantId &&
item.UserId == command.ReferrerUserId &&
item.Status == ReferralCodeStatus.Active)
.Select(item => item.Code)
.FirstOrDefaultAsync(cancellationToken);
if (refCode is null)
refCode = (await GetOrCreateInviteCodeAsync(
new ReferralActor(actor.TenantId, command.ReferrerUserId),
new ReferralInviteCommand("manual"),
cancellationToken)).InviteCode;
var before = await dbContext.ReferralLeads
.AsNoTracking()
.FirstOrDefaultAsync(item =>
item.TenantId == actor.TenantId &&
item.StudentUserId == command.StudentUserId,
cancellationToken);
var lead = await BindLeadCoreAsync(
actor.TenantId,
command.StudentUserId,
command.ReferrerUserId,
refCode,
NormalizeChoice(command.Source, AllowedSources, "manual", "invalid_referral_source"),
ReferralLeadBindType.Manual,
command.Force,
command.Metadata,
cancellationToken);
lead.AssignedBy = actor.UserId;
lead.AssignedAt = DateTimeOffset.UtcNow;
var crmQueue = before?.ReferrerUserId == lead.ReferrerUserId
? null
: await EnqueueCrmIfEnabledAsync(actor.TenantId, lead, "referral.manual_bind", cancellationToken);
await dbContext.SaveChangesAsync(cancellationToken);
return new ReferralBindResult(ToLeadItem(lead, before?.ReferrerUserId != lead.ReferrerUserId),
ToQueuePreview(crmQueue));
}
public async Task<ReferralList<ReferralTeamItem>> GetTeamAsync(
ReferralAdminActor actor,
ReferralTeamQuery query,
CancellationToken cancellationToken = default)
{
await AssertAdminAsync(actor, cancellationToken);
var edges = dbContext.ReferralTeamEdges
.AsNoTracking()
.Where(item => item.TenantId == actor.TenantId);
if (query.LeaderUserId.HasValue) edges = edges.Where(item => item.LeaderUserId == query.LeaderUserId.Value);
var items = await edges
.OrderBy(item => item.RelationType)
.ThenBy(item => item.MemberUserId)
.ToArrayAsync(cancellationToken);
return new ReferralList<ReferralTeamItem>(items.Select(ToTeamItem).ToArray());
}
public async Task<ReferralTeamItem> UpsertTeamAsync(
ReferralAdminActor actor,
UpsertReferralTeamCommand command,
CancellationToken cancellationToken = default)
{
await AssertAdminAsync(actor, cancellationToken);
await AssertActiveMemberAsync(actor.TenantId, command.MemberUserId, cancellationToken);
if (command.LeaderUserId.HasValue)
await AssertActiveMemberAsync(actor.TenantId, command.LeaderUserId.Value, cancellationToken);
var relationType = ParseEnum(command.RelationType, ReferralTeamRelationType.SalesTeam,
"invalid_referral_team_relation");
var status = ParseEnum(command.Status, ReferralTeamEdgeStatus.Active, "invalid_referral_team_status");
var edge = await dbContext.ReferralTeamEdges
.FirstOrDefaultAsync(item =>
item.TenantId == actor.TenantId &&
item.MemberUserId == command.MemberUserId &&
item.RelationType == relationType,
cancellationToken);
if (edge is null)
{
edge = new ReferralTeamEdge
{
TenantId = actor.TenantId,
MemberUserId = command.MemberUserId,
RelationType = relationType
};
dbContext.ReferralTeamEdges.Add(edge);
}
edge.LeaderUserId = command.LeaderUserId;
edge.Status = status;
edge.Metadata = command.Metadata ?? JsonDefaults.Object();
await dbContext.SaveChangesAsync(cancellationToken);
return ToTeamItem(edge);
}
}