feat(member): implement points mall backend module

This commit is contained in:
2026-03-04 12:15:18 +08:00
parent 2970134200
commit bd418c5927
53 changed files with 5193 additions and 0 deletions

View File

@@ -0,0 +1,203 @@
using TakeoutSaaS.Application.App.Members.PointsMall.Commands;
using TakeoutSaaS.Application.App.Members.PointsMall.Dto;
using TakeoutSaaS.Domain.Membership.Entities;
using TakeoutSaaS.Domain.Membership.Enums;
using TakeoutSaaS.Domain.Membership.Repositories;
namespace TakeoutSaaS.Application.App.Members.PointsMall;
/// <summary>
/// 积分商城 DTO 构造器。
/// </summary>
internal static class MemberPointMallDtoFactory
{
public static MemberPointMallProductAggregateSnapshot EmptyProductAggregate(long pointMallProductId)
{
return new MemberPointMallProductAggregateSnapshot
{
PointMallProductId = pointMallProductId,
RedeemedCount = 0
};
}
public static MemberPointMallRuleDto ToRuleDto(MemberPointMallRule source)
{
return new MemberPointMallRuleDto
{
StoreId = source.StoreId,
IsConsumeRewardEnabled = source.IsConsumeRewardEnabled,
ConsumeAmountPerStep = source.ConsumeAmountPerStep,
ConsumeRewardPointsPerStep = source.ConsumeRewardPointsPerStep,
IsReviewRewardEnabled = source.IsReviewRewardEnabled,
ReviewRewardPoints = source.ReviewRewardPoints,
IsRegisterRewardEnabled = source.IsRegisterRewardEnabled,
RegisterRewardPoints = source.RegisterRewardPoints,
IsSigninRewardEnabled = source.IsSigninRewardEnabled,
SigninRewardPoints = source.SigninRewardPoints,
ExpiryMode = MemberPointMallMapping.ToExpiryModeText(source.ExpiryMode)
};
}
public static MemberPointMallRuleStatsDto ToRuleStatsDto(MemberPointMallRuleStatsSnapshot source)
{
return new MemberPointMallRuleStatsDto
{
TotalIssuedPoints = source.TotalIssuedPoints,
RedeemedPoints = source.RedeemedPoints,
PointMembers = source.PointMembers,
RedeemRate = decimal.Round(source.RedeemRate, 1, MidpointRounding.AwayFromZero)
};
}
public static MemberPointMallProductDto ToProductDto(
MemberPointMallProduct source,
MemberPointMallProductAggregateSnapshot aggregate)
{
var notifyChannels = MemberPointMallMapping.DeserializeNotifyChannels(source.NotifyChannelsJson)
.Select(MemberPointMallMapping.ToNotifyChannelText)
.ToList();
return new MemberPointMallProductDto
{
PointMallProductId = source.Id,
StoreId = source.StoreId,
Name = source.Name,
ImageUrl = source.ImageUrl,
RedeemType = MemberPointMallMapping.ToRedeemTypeText(source.RedeemType),
ProductId = source.ProductId,
CouponTemplateId = source.CouponTemplateId,
PhysicalName = source.PhysicalName,
PickupMethod = source.PickupMethod.HasValue
? MemberPointMallMapping.ToPickupMethodText(source.PickupMethod.Value)
: null,
Description = source.Description,
ExchangeType = MemberPointMallMapping.ToExchangeTypeText(source.ExchangeType),
RequiredPoints = source.RequiredPoints,
CashAmount = decimal.Round(source.CashAmount, 2, MidpointRounding.AwayFromZero),
StockTotal = source.StockTotal,
StockAvailable = source.StockAvailable,
RedeemedCount = aggregate.RedeemedCount,
PerMemberLimit = source.PerMemberLimit,
NotifyChannels = notifyChannels,
Status = MemberPointMallMapping.ToProductStatusText(source.Status),
UpdatedAt = source.UpdatedAt ?? source.CreatedAt
};
}
public static MemberPointMallRecordDto ToRecordDto(MemberPointMallRecord source)
{
return new MemberPointMallRecordDto
{
RecordId = source.Id,
RecordNo = source.RecordNo,
PointMallProductId = source.PointMallProductId,
ProductName = source.ProductName,
RedeemType = MemberPointMallMapping.ToRedeemTypeText(source.RedeemType),
ExchangeType = MemberPointMallMapping.ToExchangeTypeText(source.ExchangeType),
MemberId = source.MemberId,
MemberName = source.MemberName,
MemberMobileMasked = source.MemberMobileMasked,
UsedPoints = source.UsedPoints,
CashAmount = decimal.Round(source.CashAmount, 2, MidpointRounding.AwayFromZero),
Status = MemberPointMallMapping.ToRecordStatusText(source.Status),
RedeemedAt = source.RedeemedAt,
IssuedAt = source.IssuedAt,
VerifiedAt = source.VerifiedAt
};
}
public static MemberPointMallRecordDetailDto ToRecordDetailDto(MemberPointMallRecord source)
{
return new MemberPointMallRecordDetailDto
{
RecordId = source.Id,
RecordNo = source.RecordNo,
PointMallProductId = source.PointMallProductId,
ProductName = source.ProductName,
RedeemType = MemberPointMallMapping.ToRedeemTypeText(source.RedeemType),
ExchangeType = MemberPointMallMapping.ToExchangeTypeText(source.ExchangeType),
MemberId = source.MemberId,
MemberName = source.MemberName,
MemberMobileMasked = source.MemberMobileMasked,
UsedPoints = source.UsedPoints,
CashAmount = decimal.Round(source.CashAmount, 2, MidpointRounding.AwayFromZero),
Status = MemberPointMallMapping.ToRecordStatusText(source.Status),
RedeemedAt = source.RedeemedAt,
IssuedAt = source.IssuedAt,
VerifiedAt = source.VerifiedAt,
VerifyMethod = source.VerifyMethod.HasValue
? MemberPointMallMapping.ToVerifyMethodText(source.VerifyMethod.Value)
: null,
VerifyRemark = source.VerifyRemark,
VerifiedBy = source.VerifiedBy
};
}
public static MemberPointMallRecordStatsDto ToRecordStatsDto(MemberPointMallRecordStatsSnapshot source)
{
return new MemberPointMallRecordStatsDto
{
TodayRedeemCount = source.TodayRedeemCount,
PendingPhysicalCount = source.PendingPhysicalCount,
CurrentMonthUsedPoints = source.CurrentMonthUsedPoints
};
}
public static MemberPointMallRule CreateRuleEntity(
SavePointMallRuleCommand request,
MemberPointMallExpiryMode expiryMode)
{
return new MemberPointMallRule
{
StoreId = request.StoreId,
IsConsumeRewardEnabled = request.IsConsumeRewardEnabled,
ConsumeAmountPerStep = request.ConsumeAmountPerStep,
ConsumeRewardPointsPerStep = request.ConsumeRewardPointsPerStep,
IsReviewRewardEnabled = request.IsReviewRewardEnabled,
ReviewRewardPoints = request.ReviewRewardPoints,
IsRegisterRewardEnabled = request.IsRegisterRewardEnabled,
RegisterRewardPoints = request.RegisterRewardPoints,
IsSigninRewardEnabled = request.IsSigninRewardEnabled,
SigninRewardPoints = request.SigninRewardPoints,
ExpiryMode = expiryMode
};
}
public static MemberPointMallProduct CreateProductEntity(
SavePointMallProductCommand request,
MemberPointMallRedeemType redeemType,
MemberPointMallExchangeType exchangeType,
MemberPointMallProductStatus status,
string name,
string? imageUrl,
string? physicalName,
MemberPointMallPickupMethod? pickupMethod,
string? description,
int requiredPoints,
decimal cashAmount,
int stockTotal,
int? perMemberLimit,
IReadOnlyCollection<MemberPointMallNotifyChannel> notifyChannels)
{
return new MemberPointMallProduct
{
StoreId = request.StoreId,
Name = name,
ImageUrl = imageUrl,
RedeemType = redeemType,
ProductId = request.ProductId,
CouponTemplateId = request.CouponTemplateId,
PhysicalName = physicalName,
PickupMethod = pickupMethod,
Description = description,
ExchangeType = exchangeType,
RequiredPoints = requiredPoints,
CashAmount = cashAmount,
StockTotal = stockTotal,
StockAvailable = stockTotal,
PerMemberLimit = perMemberLimit,
NotifyChannelsJson = MemberPointMallMapping.SerializeNotifyChannels(notifyChannels),
Status = status
};
}
}