feat: Enhance club membership activation and commission pool validation
Build and Deploy to Kubernetes / build-and-deploy (push) Successful in 8m9s

- Updated AcceptClubMembershipContractCommandHandler to set PackagePurchasedAt to the contract-signing time, ensuring accurate pool charging.
- Modified ActivateClubMembershipCommand to allow specifying a PackageId for forced activation, defaulting to the base package if not provided.
- Improved ActivateClubMembershipCommandHandler to handle new and existing memberships differently regarding pool charging.
- Added validation logic in GetWeeklyCommissionPoolQueryHandler to compare TotalPoolAmount against actual activations.
- Introduced validation fields in WeeklyCommissionPoolDto for tracking discrepancies and expected amounts.
- Updated stored procedures to ensure accurate calculations based on package purchases and to handle empty pools.
- Enhanced protobuf definitions to include validation fields for commission pools and network tree nodes.
- Added mapping for new fields in CommissionProfile and NetworkMembershipProfile.
- Created DiscountProductProfile for mapping discount product requests and responses.
This commit is contained in:
masoodafar-web
2026-05-01 00:07:05 +03:30
parent 789aa0b870
commit 8518c7b3ec
18 changed files with 423 additions and 115 deletions
@@ -51,7 +51,11 @@ public class CommissionProfile : IRegister
: null)
.Map(dest => dest.Created, src => Timestamp.FromDateTimeOffset(src.Created))
.Map(dest => dest.PackageId, src => src.PackageId)
.Map(dest => dest.PackageTitle, src => src.PackageTitle);
.Map(dest => dest.PackageTitle, src => src.PackageTitle)
.Map(dest => dest.ValidationIsValid, src => src.ValidationIsValid)
.Map(dest => dest.ValidationExpectedAmount, src => src.ValidationExpectedAmount)
.Map(dest => dest.ValidationDiscrepancy, src => src.ValidationDiscrepancy)
.Map(dest => dest.ValidationActivationCount, src => src.ValidationActivationCount);
// GetAvailableWeeks Response Mapping
config.NewConfig<GetAvailableWeeksResponseDto, GetAvailableWeeksResponse>()
@@ -0,0 +1,75 @@
using CMSMicroservice.Application.Common.Models;
using CMSMicroservice.Application.DiscountShopCQ.Queries.GetDiscountProducts;
using CMSMicroservice.Protobuf.Protos.DiscountProduct;
using Google.Protobuf.WellKnownTypes;
using Mapster;
using ProtoDiscountProductDto = CMSMicroservice.Protobuf.Protos.DiscountProduct.DiscountProductDto;
namespace CMSMicroservice.WebApi.Common.Mappings;
public class DiscountProductProfile : IRegister
{
void IRegister.Register(TypeAdapterConfig config)
{
// GetDiscountProductsRequest (proto) → GetDiscountProductsQuery (CQRS)
config.NewConfig<GetDiscountProductsRequest, GetDiscountProductsQuery>()
.Map(dest => dest.SearchTerm,
src => string.IsNullOrEmpty(src.SearchQuery) ? null : src.SearchQuery)
.Map(dest => dest.CategoryId,
src => src.CategoryId != null ? src.CategoryId.Value : (long?)null)
.Map(dest => dest.IsActive,
src => src.IsActive != null ? src.IsActive.Value : (bool?)null)
.Map(dest => dest.MinPrice,
src => src.MinPrice != null ? (int?)src.MinPrice.Value : null)
.Map(dest => dest.MaxPrice,
src => src.MaxPrice != null ? (int?)src.MaxPrice.Value : null)
.Map(dest => dest.PaginationQuery, src => new PaginationState
{
PageNumber = src.PageNumber > 0 ? src.PageNumber : 1,
PageSize = src.PageSize > 0 ? src.PageSize : 12
});
// GetDiscountProductsResponseDto (CQRS) → GetDiscountProductsResponse (proto)
config.NewConfig<GetDiscountProductsResponseDto, GetDiscountProductsResponse>()
.MapWith(src => MapToResponse(src));
}
private static GetDiscountProductsResponse MapToResponse(GetDiscountProductsResponseDto src)
{
var response = new GetDiscountProductsResponse();
if (src.MetaData != null)
{
response.MetaData = new CMSMicroservice.Protobuf.Protos.MetaData
{
TotalCount = src.MetaData.TotalCount,
PageSize = src.MetaData.PageSize,
CurrentPage = src.MetaData.CurrentPage,
TotalPage = src.MetaData.TotalPage
};
}
if (src.Models != null)
{
foreach (var p in src.Models)
{
response.Models.Add(new ProtoDiscountProductDto
{
Id = p.Id,
Title = p.Title ?? string.Empty,
ShortInfomation = p.ShortInfomation ?? string.Empty,
Price = p.Price,
MaxDiscountPercent = p.MaxDiscountPercent,
ImagePath = p.ImagePath ?? string.Empty,
ThumbnailPath = p.ThumbnailPath ?? string.Empty,
RemainingCount = p.RemainingCount,
ViewCount = p.ViewCount,
IsActive = p.IsActive,
Created = Timestamp.FromDateTime(DateTime.UtcNow)
});
}
}
return response;
}
}
@@ -92,7 +92,10 @@ public class NetworkMembershipProfile : IRegister
IsActive = true,
IsClubActive = node.IsClubActive,
ActivationWeekDefinitionId = node.ActivationWeekDefinitionId ?? 0,
IsActivatedInTargetWeek = node.IsActivatedInTargetWeek
IsActivatedInTargetWeek = node.IsActivatedInTargetWeek,
PackageName = node.PackageName ?? string.Empty,
PackageId = node.PackageId.HasValue ? node.PackageId.Value : null,
IsNewActivation = node.IsNewActivation.HasValue ? node.IsNewActivation.Value : null
};
if (parentId.HasValue)