using MediatR;
using TakeoutSaaS.Application.App.Coupons.NewCustomer.Commands;
using TakeoutSaaS.Application.App.Coupons.NewCustomer.Dto;
using TakeoutSaaS.Domain.Coupons.Entities;
using TakeoutSaaS.Domain.Coupons.Enums;
using TakeoutSaaS.Domain.Coupons.Repositories;
using TakeoutSaaS.Shared.Abstractions.Constants;
using TakeoutSaaS.Shared.Abstractions.Exceptions;
using TakeoutSaaS.Shared.Abstractions.Tenancy;
namespace TakeoutSaaS.Application.App.Coupons.NewCustomer.Handlers;
///
/// 保存新客有礼配置处理器。
///
public sealed class SaveNewCustomerSettingsCommandHandler(
INewCustomerGiftRepository repository,
ITenantProvider tenantProvider)
: IRequestHandler
{
///
public async Task Handle(
SaveNewCustomerSettingsCommand request,
CancellationToken cancellationToken)
{
if (request.StoreId <= 0)
{
throw new BusinessException(ErrorCodes.BadRequest, "storeId 参数不合法");
}
var tenantId = tenantProvider.GetCurrentTenantId();
var giftType = NewCustomerMapping.ParseGiftType(request.GiftType);
var shareChannels = NewCustomerMapping.NormalizeShareChannels(request.ShareChannels);
var welcomeRules = NewCustomerMapping.NormalizeCouponRulesForSave(
request.StoreId,
NewCustomerCouponScene.Welcome,
request.WelcomeCoupons);
var inviterRules = NewCustomerMapping.NormalizeCouponRulesForSave(
request.StoreId,
NewCustomerCouponScene.InviterReward,
request.InviterCoupons);
var inviteeRules = NewCustomerMapping.NormalizeCouponRulesForSave(
request.StoreId,
NewCustomerCouponScene.InviteeReward,
request.InviteeCoupons);
if (giftType == NewCustomerGiftType.Coupon && welcomeRules.Count == 0)
{
throw new BusinessException(ErrorCodes.BadRequest, "优惠券包至少需要一张券");
}
if (giftType == NewCustomerGiftType.Direct)
{
if (!request.DirectReduceAmount.HasValue || request.DirectReduceAmount.Value <= 0m)
{
throw new BusinessException(ErrorCodes.BadRequest, "directReduceAmount 必须大于 0");
}
if (!request.DirectMinimumSpend.HasValue || request.DirectMinimumSpend.Value < 0m)
{
throw new BusinessException(ErrorCodes.BadRequest, "directMinimumSpend 不能小于 0");
}
}
if (request.InviteEnabled && (inviterRules.Count == 0 || inviteeRules.Count == 0))
{
throw new BusinessException(ErrorCodes.BadRequest, "开启邀请后必须配置邀请人和被邀请人奖励券");
}
var setting = await repository.FindSettingByStoreIdAsync(tenantId, request.StoreId, cancellationToken);
var isNewSetting = setting is null;
if (setting is null)
{
setting = new NewCustomerGiftSetting
{
StoreId = request.StoreId
};
await repository.AddSettingAsync(setting, cancellationToken);
}
setting.GiftEnabled = request.GiftEnabled;
setting.GiftType = giftType;
setting.DirectReduceAmount = giftType == NewCustomerGiftType.Direct
? decimal.Round(request.DirectReduceAmount!.Value, 2, MidpointRounding.AwayFromZero)
: null;
setting.DirectMinimumSpend = giftType == NewCustomerGiftType.Direct
? decimal.Round(request.DirectMinimumSpend!.Value, 2, MidpointRounding.AwayFromZero)
: null;
setting.InviteEnabled = request.InviteEnabled;
setting.ShareChannelsJson = NewCustomerMapping.SerializeShareChannels(shareChannels);
if (!isNewSetting)
{
await repository.UpdateSettingAsync(setting, cancellationToken);
}
var allRules = new List(welcomeRules.Count + inviterRules.Count + inviteeRules.Count);
allRules.AddRange(welcomeRules);
allRules.AddRange(inviterRules);
allRules.AddRange(inviteeRules);
await repository.ReplaceCouponRulesAsync(
tenantId,
request.StoreId,
allRules,
cancellationToken);
await repository.SaveChangesAsync(cancellationToken);
return new NewCustomerSettingsDto
{
StoreId = request.StoreId,
GiftEnabled = setting.GiftEnabled,
GiftType = NewCustomerMapping.ToGiftTypeText(setting.GiftType),
DirectReduceAmount = setting.DirectReduceAmount,
DirectMinimumSpend = setting.DirectMinimumSpend,
InviteEnabled = setting.InviteEnabled,
ShareChannels = shareChannels,
WelcomeCoupons = welcomeRules.Select(NewCustomerMapping.ToCouponRuleDto).ToList(),
InviterCoupons = inviterRules.Select(NewCustomerMapping.ToCouponRuleDto).ToList(),
InviteeCoupons = inviteeRules.Select(NewCustomerMapping.ToCouponRuleDto).ToList(),
UpdatedAt = DateTime.UtcNow
};
}
}