From f8794bbb633b59f0308b80928913ca17e87ed96c Mon Sep 17 00:00:00 2001 From: masoodafar-web Date: Mon, 22 Jun 2026 22:19:44 +0330 Subject: [PATCH 1/8] feat(club-membership): enhance club membership history queries and responses - Added filtering capabilities to GetClubMembershipHistoryQuery, allowing optional filters for UserId, ClubMembershipId, Action, and date range. - Updated GetClubMembershipHistoryQueryHandler to utilize the new filter structure. - Enhanced GetAllClubMembershipsQueryHandler to include LastPackage details in the response. - Introduced new properties in GetAllClubMembershipsResponseModel for PackageId and PackageName. - Updated Protobuf definitions to reflect changes in club membership history queries and responses. - Refactored mapping configurations to accommodate new DTOs and filters. --- .../ActivateClubMembershipCommandHandler.cs | 5 + .../GetAllClubMembershipsQueryHandler.cs | 5 +- .../GetAllClubMembershipsResponseDto.cs | 2 + .../GetClubMembershipHistoryQuery.cs | 30 ++---- .../GetClubMembershipHistoryQueryHandler.cs | 29 +++-- .../GetClubMembershipHistoryQueryValidator.cs | 27 +---- .../GetClubMembershipHistoryResponseDto.cs | 1 + .../ClubMembershipCycleFilterExtensions.cs | 46 ++++++++ .../GetAllClubMembershipCycleByFilterQuery.cs | 47 ++++++++ ...ClubMembershipCycleByFilterQueryHandler.cs | 49 +++++++++ .../GetClubMembershipCycleSummaryQuery.cs | 13 +++ ...tClubMembershipCycleSummaryQueryHandler.cs | 36 +++++++ ...bMembershipCycleHistoryFilterExtensions.cs | 33 ++++++ ...ClubMembershipCycleHistoryByFilterQuery.cs | 45 ++++++++ ...bershipCycleHistoryByFilterQueryHandler.cs | 52 +++++++++ .../ClubMembershipCycleHistoryWriter.cs | 54 ++++++++++ .../GetAllPaymentTransactionByFilterQuery.cs | 46 ++++++++ ...lPaymentTransactionByFilterQueryHandler.cs | 48 +++++++++ .../PaymentTransactionFilterExtensions.cs | 42 ++++++++ .../GetPaymentTransactionSummaryQuery.cs | 14 +++ ...etPaymentTransactionSummaryQueryHandler.cs | 36 +++++++ .../GetAllUserPackagePurchaseByFilterQuery.cs | 43 ++++++++ ...UserPackagePurchaseByFilterQueryHandler.cs | 47 ++++++++ .../UserPackagePurchaseFilterExtensions.cs | 36 +++++++ .../GetUserPackagePurchaseSummaryQuery.cs | 12 +++ ...tUserPackagePurchaseSummaryQueryHandler.cs | 32 ++++++ .../CMSMicroservice.Protobuf.csproj | 7 +- .../Protos/clubmembership.proto | 33 +++--- .../Protos/clubmembershipcycle.proto | 79 ++++++++++++++ .../Protos/clubmembershipcyclehistory.proto | 61 +++++++++++ .../Protos/paymenttransaction.proto | 82 ++++++++++++++ .../Protos/userpackagepurchase.proto | 75 +++++++++++++ .../ClubMembershipCycleHistoryProfile.cs | 81 ++++++++++++++ .../Mappings/ClubMembershipCycleProfile.cs | 92 ++++++++++++++++ .../Common/Mappings/ClubMembershipProfile.cs | 60 ++++++++++- .../Mappings/PaymentTransactionProfile.cs | 102 ++++++++++++++++++ .../Mappings/UserPackagePurchaseProfile.cs | 83 ++++++++++++++ .../ClubMembershipCycleHistoryService.cs | 16 +++ .../Services/ClubMembershipCycleService.cs | 21 ++++ .../Services/PaymentTransactionService.cs | 21 ++++ .../Services/UserPackagePurchaseService.cs | 21 ++++ 41 files changed, 1590 insertions(+), 74 deletions(-) create mode 100644 src/CMSMicroservice.Application/ClubMembershipCycleCQ/Queries/GetAllClubMembershipCycleByFilter/ClubMembershipCycleFilterExtensions.cs create mode 100644 src/CMSMicroservice.Application/ClubMembershipCycleCQ/Queries/GetAllClubMembershipCycleByFilter/GetAllClubMembershipCycleByFilterQuery.cs create mode 100644 src/CMSMicroservice.Application/ClubMembershipCycleCQ/Queries/GetAllClubMembershipCycleByFilter/GetAllClubMembershipCycleByFilterQueryHandler.cs create mode 100644 src/CMSMicroservice.Application/ClubMembershipCycleCQ/Queries/GetClubMembershipCycleSummary/GetClubMembershipCycleSummaryQuery.cs create mode 100644 src/CMSMicroservice.Application/ClubMembershipCycleCQ/Queries/GetClubMembershipCycleSummary/GetClubMembershipCycleSummaryQueryHandler.cs create mode 100644 src/CMSMicroservice.Application/ClubMembershipCycleHistoryCQ/Queries/GetAllClubMembershipCycleHistoryByFilter/ClubMembershipCycleHistoryFilterExtensions.cs create mode 100644 src/CMSMicroservice.Application/ClubMembershipCycleHistoryCQ/Queries/GetAllClubMembershipCycleHistoryByFilter/GetAllClubMembershipCycleHistoryByFilterQuery.cs create mode 100644 src/CMSMicroservice.Application/ClubMembershipCycleHistoryCQ/Queries/GetAllClubMembershipCycleHistoryByFilter/GetAllClubMembershipCycleHistoryByFilterQueryHandler.cs create mode 100644 src/CMSMicroservice.Application/Common/Helpers/ClubMembershipCycleHistoryWriter.cs create mode 100644 src/CMSMicroservice.Application/PaymentTransactionCQ/Queries/GetAllPaymentTransactionByFilter/GetAllPaymentTransactionByFilterQuery.cs create mode 100644 src/CMSMicroservice.Application/PaymentTransactionCQ/Queries/GetAllPaymentTransactionByFilter/GetAllPaymentTransactionByFilterQueryHandler.cs create mode 100644 src/CMSMicroservice.Application/PaymentTransactionCQ/Queries/GetAllPaymentTransactionByFilter/PaymentTransactionFilterExtensions.cs create mode 100644 src/CMSMicroservice.Application/PaymentTransactionCQ/Queries/GetPaymentTransactionSummary/GetPaymentTransactionSummaryQuery.cs create mode 100644 src/CMSMicroservice.Application/PaymentTransactionCQ/Queries/GetPaymentTransactionSummary/GetPaymentTransactionSummaryQueryHandler.cs create mode 100644 src/CMSMicroservice.Application/UserPackagePurchaseCQ/Queries/GetAllUserPackagePurchaseByFilter/GetAllUserPackagePurchaseByFilterQuery.cs create mode 100644 src/CMSMicroservice.Application/UserPackagePurchaseCQ/Queries/GetAllUserPackagePurchaseByFilter/GetAllUserPackagePurchaseByFilterQueryHandler.cs create mode 100644 src/CMSMicroservice.Application/UserPackagePurchaseCQ/Queries/GetAllUserPackagePurchaseByFilter/UserPackagePurchaseFilterExtensions.cs create mode 100644 src/CMSMicroservice.Application/UserPackagePurchaseCQ/Queries/GetUserPackagePurchaseSummary/GetUserPackagePurchaseSummaryQuery.cs create mode 100644 src/CMSMicroservice.Application/UserPackagePurchaseCQ/Queries/GetUserPackagePurchaseSummary/GetUserPackagePurchaseSummaryQueryHandler.cs create mode 100644 src/CMSMicroservice.Protobuf/Protos/clubmembershipcycle.proto create mode 100644 src/CMSMicroservice.Protobuf/Protos/clubmembershipcyclehistory.proto create mode 100644 src/CMSMicroservice.Protobuf/Protos/paymenttransaction.proto create mode 100644 src/CMSMicroservice.Protobuf/Protos/userpackagepurchase.proto create mode 100644 src/CMSMicroservice.WebApi/Common/Mappings/ClubMembershipCycleHistoryProfile.cs create mode 100644 src/CMSMicroservice.WebApi/Common/Mappings/ClubMembershipCycleProfile.cs create mode 100644 src/CMSMicroservice.WebApi/Common/Mappings/PaymentTransactionProfile.cs create mode 100644 src/CMSMicroservice.WebApi/Common/Mappings/UserPackagePurchaseProfile.cs create mode 100644 src/CMSMicroservice.WebApi/Services/ClubMembershipCycleHistoryService.cs create mode 100644 src/CMSMicroservice.WebApi/Services/ClubMembershipCycleService.cs create mode 100644 src/CMSMicroservice.WebApi/Services/PaymentTransactionService.cs create mode 100644 src/CMSMicroservice.WebApi/Services/UserPackagePurchaseService.cs diff --git a/src/CMSMicroservice.Application/ClubMembershipCQ/Commands/ActivateClubMembership/ActivateClubMembershipCommandHandler.cs b/src/CMSMicroservice.Application/ClubMembershipCQ/Commands/ActivateClubMembership/ActivateClubMembershipCommandHandler.cs index 15006e1..0735b07 100644 --- a/src/CMSMicroservice.Application/ClubMembershipCQ/Commands/ActivateClubMembership/ActivateClubMembershipCommandHandler.cs +++ b/src/CMSMicroservice.Application/ClubMembershipCQ/Commands/ActivateClubMembership/ActivateClubMembershipCommandHandler.cs @@ -1,4 +1,5 @@ using CMSMicroservice.Application.Common.Exceptions; +using CMSMicroservice.Application.Common.Helpers; using CMSMicroservice.Application.Common.Interfaces; using CMSMicroservice.Application.Common.Models; using CMSMicroservice.Domain.Common; @@ -272,6 +273,7 @@ public class ActivateClubMembershipCommandHandler : IRequestHandler x.User) + .Include(x => x.LastPackage) .ApplyOrder(sortBy: request.SortBy) .AsNoTracking() .AsQueryable(); @@ -35,8 +36,10 @@ public class GetAllClubMembershipsQueryHandler : IRequestHandler -/// Query برای دریافت تاریخچه تغییرات عضویت باشگاه -/// public record GetClubMembershipHistoryQuery : IRequest { - /// - /// شناسه عضویت (اختیاری) - /// - public long? MembershipId { get; init; } - - /// - /// شناسه کاربر (اختیاری) - /// - public long? UserId { get; init; } - - /// - /// موقعیت صفحه‌بندی - /// public PaginationState? PaginationState { get; init; } - - /// - /// مرتب‌سازی بر اساس - /// public string? SortBy { get; init; } + public GetClubMembershipHistoryFilter? Filter { get; init; } +} + +public class GetClubMembershipHistoryFilter +{ + public long? UserId { get; set; } + public long? ClubMembershipId { get; set; } + public ClubMembershipAction? Action { get; set; } + public DateTime? CreatedFrom { get; set; } + public DateTime? CreatedTo { get; set; } } diff --git a/src/CMSMicroservice.Application/ClubMembershipCQ/Queries/GetClubMembershipHistory/GetClubMembershipHistoryQueryHandler.cs b/src/CMSMicroservice.Application/ClubMembershipCQ/Queries/GetClubMembershipHistory/GetClubMembershipHistoryQueryHandler.cs index 32c9d5a..47bfc6e 100644 --- a/src/CMSMicroservice.Application/ClubMembershipCQ/Queries/GetClubMembershipHistory/GetClubMembershipHistoryQueryHandler.cs +++ b/src/CMSMicroservice.Application/ClubMembershipCQ/Queries/GetClubMembershipHistory/GetClubMembershipHistoryQueryHandler.cs @@ -12,20 +12,30 @@ public class GetClubMembershipHistoryQueryHandler : IRequestHandler Handle(GetClubMembershipHistoryQuery request, CancellationToken cancellationToken) { var query = _context.ClubMembershipHistories + .Include(x => x.ClubMembership) + .ThenInclude(m => m!.User) .AsNoTracking() .AsQueryable(); - if (request.MembershipId.HasValue) + if (request.Filter != null) { - query = query.Where(x => x.ClubMembershipId == request.MembershipId.Value); + if (request.Filter.ClubMembershipId.HasValue) + query = query.Where(x => x.ClubMembershipId == request.Filter.ClubMembershipId.Value); + + if (request.Filter.UserId.HasValue) + query = query.Where(x => x.UserId == request.Filter.UserId.Value); + + if (request.Filter.Action.HasValue) + query = query.Where(x => x.Action == request.Filter.Action.Value); + + if (request.Filter.CreatedFrom.HasValue) + query = query.Where(x => x.Created >= request.Filter.CreatedFrom.Value); + + if (request.Filter.CreatedTo.HasValue) + query = query.Where(x => x.Created <= request.Filter.CreatedTo.Value); } - if (request.UserId.HasValue) - { - query = query.Where(x => x.UserId == request.UserId.Value); - } - - query = query.ApplyOrder(sortBy: request.SortBy ?? "Created"); // پیش‌فرض: جدیدترین اول + query = query.ApplyOrder(sortBy: request.SortBy ?? "-Created"); var meta = await query.GetMetaData(request.PaginationState, cancellationToken); @@ -36,6 +46,9 @@ public class GetClubMembershipHistoryQueryHandler : IRequestHandler x.MembershipId) - .GreaterThan(0) - .WithMessage("شناسه عضویت معتبر نیست") - .When(x => x.MembershipId.HasValue); - - RuleFor(x => x.UserId) - .GreaterThan(0) - .WithMessage("شناسه کاربر معتبر نیست") - .When(x => x.UserId.HasValue); - - RuleFor(x => x) - .Must(x => x.MembershipId.HasValue || x.UserId.HasValue) - .WithMessage("حداقل یکی از MembershipId یا UserId باید مقداردهی شود"); + // Admin report: filters are all optional } - - public Func>> ValidateValue => async (model, propertyName) => - { - var result = await ValidateAsync( - ValidationContext.CreateWithOptions( - (GetClubMembershipHistoryQuery)model, - x => x.IncludeProperties(propertyName))); - - if (result.IsValid) - return Array.Empty(); - - return result.Errors.Select(e => e.ErrorMessage); - }; } diff --git a/src/CMSMicroservice.Application/ClubMembershipCQ/Queries/GetClubMembershipHistory/GetClubMembershipHistoryResponseDto.cs b/src/CMSMicroservice.Application/ClubMembershipCQ/Queries/GetClubMembershipHistory/GetClubMembershipHistoryResponseDto.cs index 1411d7b..da661a9 100644 --- a/src/CMSMicroservice.Application/ClubMembershipCQ/Queries/GetClubMembershipHistory/GetClubMembershipHistoryResponseDto.cs +++ b/src/CMSMicroservice.Application/ClubMembershipCQ/Queries/GetClubMembershipHistory/GetClubMembershipHistoryResponseDto.cs @@ -11,6 +11,7 @@ public class GetClubMembershipHistoryResponseModel public long Id { get; set; } public long ClubMembershipId { get; set; } public long UserId { get; set; } + public string UserName { get; set; } = string.Empty; public bool OldIsActive { get; set; } public bool NewIsActive { get; set; } public long? OldInitialContribution { get; set; } diff --git a/src/CMSMicroservice.Application/ClubMembershipCycleCQ/Queries/GetAllClubMembershipCycleByFilter/ClubMembershipCycleFilterExtensions.cs b/src/CMSMicroservice.Application/ClubMembershipCycleCQ/Queries/GetAllClubMembershipCycleByFilter/ClubMembershipCycleFilterExtensions.cs new file mode 100644 index 0000000..646c173 --- /dev/null +++ b/src/CMSMicroservice.Application/ClubMembershipCycleCQ/Queries/GetAllClubMembershipCycleByFilter/ClubMembershipCycleFilterExtensions.cs @@ -0,0 +1,46 @@ +using CMSMicroservice.Domain.Entities.Club; + +namespace CMSMicroservice.Application.ClubMembershipCycleCQ.Queries.GetAllClubMembershipCycleByFilter; + +public static class ClubMembershipCycleFilterExtensions +{ + public static IQueryable ApplyClubMembershipCycleFilter( + this IQueryable query, + GetAllClubMembershipCycleByFilterFilter? filter) + { + if (filter == null) return query; + + if (filter.UserId.HasValue) + query = query.Where(x => x.UserId == filter.UserId.Value); + + if (filter.IsCurrentCycle.HasValue) + query = query.Where(x => x.IsCurrentCycle == filter.IsCurrentCycle.Value); + + if (filter.PackageId.HasValue) + query = query.Where(x => x.PackageId == filter.PackageId.Value); + + if (filter.CycleNumber.HasValue) + query = query.Where(x => x.CycleNumber == filter.CycleNumber.Value); + + if (filter.PurchaseMethod.HasValue) + query = query.Where(x => x.PurchaseMethod == filter.PurchaseMethod.Value); + + if (filter.MagicState.HasValue) + { + query = filter.MagicState.Value switch + { + 1 => query.Where(x => x.MagicStartedAt != null && x.MagicCompletedAt == null), + 2 => query.Where(x => x.MagicCompletedAt != null), + _ => query.Where(x => x.MagicStartedAt == null && x.MagicCompletedAt == null) + }; + } + + if (filter.PackagePurchasedFrom.HasValue) + query = query.Where(x => x.PackagePurchasedAt >= filter.PackagePurchasedFrom.Value); + + if (filter.PackagePurchasedTo.HasValue) + query = query.Where(x => x.PackagePurchasedAt <= filter.PackagePurchasedTo.Value); + + return query; + } +} diff --git a/src/CMSMicroservice.Application/ClubMembershipCycleCQ/Queries/GetAllClubMembershipCycleByFilter/GetAllClubMembershipCycleByFilterQuery.cs b/src/CMSMicroservice.Application/ClubMembershipCycleCQ/Queries/GetAllClubMembershipCycleByFilter/GetAllClubMembershipCycleByFilterQuery.cs new file mode 100644 index 0000000..a79d1a4 --- /dev/null +++ b/src/CMSMicroservice.Application/ClubMembershipCycleCQ/Queries/GetAllClubMembershipCycleByFilter/GetAllClubMembershipCycleByFilterQuery.cs @@ -0,0 +1,47 @@ +using CMSMicroservice.Domain.Enums; + +namespace CMSMicroservice.Application.ClubMembershipCycleCQ.Queries.GetAllClubMembershipCycleByFilter; + +public record GetAllClubMembershipCycleByFilterQuery : IRequest +{ + public PaginationState? PaginationState { get; init; } + public string? SortBy { get; init; } + public GetAllClubMembershipCycleByFilterFilter? Filter { get; init; } +} + +public class GetAllClubMembershipCycleByFilterFilter +{ + public long? UserId { get; set; } + public bool? IsCurrentCycle { get; set; } + public long? PackageId { get; set; } + public int? CycleNumber { get; set; } + public PackagePurchaseMethod? PurchaseMethod { get; set; } + /// 0=none, 1=active magic, 2=completed magic + public int? MagicState { get; set; } + public DateTime? PackagePurchasedFrom { get; set; } + public DateTime? PackagePurchasedTo { get; set; } +} + +public class GetAllClubMembershipCycleByFilterResponseDto +{ + public MetaData MetaData { get; set; } + public List? Models { get; set; } +} + +public class GetAllClubMembershipCycleByFilterResponseModel +{ + public long Id { get; set; } + public long UserId { get; set; } + public string UserName { get; set; } = string.Empty; + public long ClubMembershipId { get; set; } + public int CycleNumber { get; set; } + public long PackageId { get; set; } + public string PackageName { get; set; } = string.Empty; + public long PackageAmount { get; set; } + public PackagePurchaseMethod PurchaseMethod { get; set; } + public DateTime PackagePurchasedAt { get; set; } + public DateTime? MagicStartedAt { get; set; } + public DateTime? MagicCompletedAt { get; set; } + public bool IsCurrentCycle { get; set; } + public DateTimeOffset Created { get; set; } +} diff --git a/src/CMSMicroservice.Application/ClubMembershipCycleCQ/Queries/GetAllClubMembershipCycleByFilter/GetAllClubMembershipCycleByFilterQueryHandler.cs b/src/CMSMicroservice.Application/ClubMembershipCycleCQ/Queries/GetAllClubMembershipCycleByFilter/GetAllClubMembershipCycleByFilterQueryHandler.cs new file mode 100644 index 0000000..9434541 --- /dev/null +++ b/src/CMSMicroservice.Application/ClubMembershipCycleCQ/Queries/GetAllClubMembershipCycleByFilter/GetAllClubMembershipCycleByFilterQueryHandler.cs @@ -0,0 +1,49 @@ +namespace CMSMicroservice.Application.ClubMembershipCycleCQ.Queries.GetAllClubMembershipCycleByFilter; + +public class GetAllClubMembershipCycleByFilterQueryHandler + : IRequestHandler +{ + private readonly IApplicationDbContext _context; + + public GetAllClubMembershipCycleByFilterQueryHandler(IApplicationDbContext context) + { + _context = context; + } + + public async Task Handle( + GetAllClubMembershipCycleByFilterQuery request, + CancellationToken cancellationToken) + { + var query = _context.ClubMembershipCycles + .Include(x => x.User) + .Include(x => x.Package) + .AsNoTracking() + .ApplyClubMembershipCycleFilter(request.Filter) + .ApplyOrder(sortBy: request.SortBy ?? "-PackagePurchasedAt"); + + return new GetAllClubMembershipCycleByFilterResponseDto + { + MetaData = await query.GetMetaData(request.PaginationState, cancellationToken), + Models = await query + .PaginatedListAsync(paginationState: request.PaginationState) + .Select(x => new GetAllClubMembershipCycleByFilterResponseModel + { + Id = x.Id, + UserId = x.UserId, + UserName = x.User != null ? $"{x.User.FirstName} {x.User.LastName}" : string.Empty, + ClubMembershipId = x.ClubMembershipId, + CycleNumber = x.CycleNumber, + PackageId = x.PackageId, + PackageName = x.Package != null ? x.Package.Title : string.Empty, + PackageAmount = x.PackageAmount, + PurchaseMethod = x.PurchaseMethod, + PackagePurchasedAt = x.PackagePurchasedAt, + MagicStartedAt = x.MagicStartedAt, + MagicCompletedAt = x.MagicCompletedAt, + IsCurrentCycle = x.IsCurrentCycle, + Created = x.Created + }) + .ToListAsync(cancellationToken) + }; + } +} diff --git a/src/CMSMicroservice.Application/ClubMembershipCycleCQ/Queries/GetClubMembershipCycleSummary/GetClubMembershipCycleSummaryQuery.cs b/src/CMSMicroservice.Application/ClubMembershipCycleCQ/Queries/GetClubMembershipCycleSummary/GetClubMembershipCycleSummaryQuery.cs new file mode 100644 index 0000000..b5953f9 --- /dev/null +++ b/src/CMSMicroservice.Application/ClubMembershipCycleCQ/Queries/GetClubMembershipCycleSummary/GetClubMembershipCycleSummaryQuery.cs @@ -0,0 +1,13 @@ +namespace CMSMicroservice.Application.ClubMembershipCycleCQ.Queries.GetClubMembershipCycleSummary; + +public record GetClubMembershipCycleSummaryQuery : IRequest +{ + public GetAllClubMembershipCycleByFilter.GetAllClubMembershipCycleByFilterFilter? Filter { get; init; } +} + +public class GetClubMembershipCycleSummaryResponseDto +{ + public long TotalCount { get; set; } + public long CurrentCycleCount { get; set; } + public long MagicActiveCount { get; set; } +} diff --git a/src/CMSMicroservice.Application/ClubMembershipCycleCQ/Queries/GetClubMembershipCycleSummary/GetClubMembershipCycleSummaryQueryHandler.cs b/src/CMSMicroservice.Application/ClubMembershipCycleCQ/Queries/GetClubMembershipCycleSummary/GetClubMembershipCycleSummaryQueryHandler.cs new file mode 100644 index 0000000..7fe755a --- /dev/null +++ b/src/CMSMicroservice.Application/ClubMembershipCycleCQ/Queries/GetClubMembershipCycleSummary/GetClubMembershipCycleSummaryQueryHandler.cs @@ -0,0 +1,36 @@ +using CMSMicroservice.Application.ClubMembershipCycleCQ.Queries.GetAllClubMembershipCycleByFilter; + +namespace CMSMicroservice.Application.ClubMembershipCycleCQ.Queries.GetClubMembershipCycleSummary; + +public class GetClubMembershipCycleSummaryQueryHandler + : IRequestHandler +{ + private readonly IApplicationDbContext _context; + + public GetClubMembershipCycleSummaryQueryHandler(IApplicationDbContext context) + { + _context = context; + } + + public async Task Handle( + GetClubMembershipCycleSummaryQuery request, + CancellationToken cancellationToken) + { + var query = _context.ClubMembershipCycles + .AsNoTracking() + .ApplyClubMembershipCycleFilter(request.Filter); + + var totalCount = await query.LongCountAsync(cancellationToken); + var currentCycleCount = await query.LongCountAsync(x => x.IsCurrentCycle, cancellationToken); + var magicActiveCount = await query.LongCountAsync( + x => x.MagicStartedAt != null && x.MagicCompletedAt == null, + cancellationToken); + + return new GetClubMembershipCycleSummaryResponseDto + { + TotalCount = totalCount, + CurrentCycleCount = currentCycleCount, + MagicActiveCount = magicActiveCount + }; + } +} diff --git a/src/CMSMicroservice.Application/ClubMembershipCycleHistoryCQ/Queries/GetAllClubMembershipCycleHistoryByFilter/ClubMembershipCycleHistoryFilterExtensions.cs b/src/CMSMicroservice.Application/ClubMembershipCycleHistoryCQ/Queries/GetAllClubMembershipCycleHistoryByFilter/ClubMembershipCycleHistoryFilterExtensions.cs new file mode 100644 index 0000000..72bc414 --- /dev/null +++ b/src/CMSMicroservice.Application/ClubMembershipCycleHistoryCQ/Queries/GetAllClubMembershipCycleHistoryByFilter/ClubMembershipCycleHistoryFilterExtensions.cs @@ -0,0 +1,33 @@ +using CMSMicroservice.Domain.Entities.History; + +namespace CMSMicroservice.Application.ClubMembershipCycleHistoryCQ.Queries.GetAllClubMembershipCycleHistoryByFilter; + +public static class ClubMembershipCycleHistoryFilterExtensions +{ + public static IQueryable ApplyClubMembershipCycleHistoryFilter( + this IQueryable query, + GetAllClubMembershipCycleHistoryByFilterFilter? filter) + { + if (filter == null) return query; + + if (filter.UserId.HasValue) + query = query.Where(x => x.UserId == filter.UserId.Value); + + if (filter.ClubMembershipCycleId.HasValue) + query = query.Where(x => x.ClubMembershipCycleId == filter.ClubMembershipCycleId.Value); + + if (filter.CycleNumber.HasValue) + query = query.Where(x => x.CycleNumber == filter.CycleNumber.Value); + + if (filter.Action.HasValue) + query = query.Where(x => x.Action == filter.Action.Value); + + if (filter.CreatedFrom.HasValue) + query = query.Where(x => x.Created >= filter.CreatedFrom.Value); + + if (filter.CreatedTo.HasValue) + query = query.Where(x => x.Created <= filter.CreatedTo.Value); + + return query; + } +} diff --git a/src/CMSMicroservice.Application/ClubMembershipCycleHistoryCQ/Queries/GetAllClubMembershipCycleHistoryByFilter/GetAllClubMembershipCycleHistoryByFilterQuery.cs b/src/CMSMicroservice.Application/ClubMembershipCycleHistoryCQ/Queries/GetAllClubMembershipCycleHistoryByFilter/GetAllClubMembershipCycleHistoryByFilterQuery.cs new file mode 100644 index 0000000..dfb458d --- /dev/null +++ b/src/CMSMicroservice.Application/ClubMembershipCycleHistoryCQ/Queries/GetAllClubMembershipCycleHistoryByFilter/GetAllClubMembershipCycleHistoryByFilterQuery.cs @@ -0,0 +1,45 @@ +using CMSMicroservice.Domain.Enums; + +namespace CMSMicroservice.Application.ClubMembershipCycleHistoryCQ.Queries.GetAllClubMembershipCycleHistoryByFilter; + +public record GetAllClubMembershipCycleHistoryByFilterQuery : IRequest +{ + public PaginationState? PaginationState { get; init; } + public string? SortBy { get; init; } + public GetAllClubMembershipCycleHistoryByFilterFilter? Filter { get; init; } +} + +public class GetAllClubMembershipCycleHistoryByFilterFilter +{ + public long? UserId { get; set; } + public long? ClubMembershipCycleId { get; set; } + public int? CycleNumber { get; set; } + public ClubMembershipCycleAction? Action { get; set; } + public DateTime? CreatedFrom { get; set; } + public DateTime? CreatedTo { get; set; } +} + +public class GetAllClubMembershipCycleHistoryByFilterResponseDto +{ + public MetaData MetaData { get; set; } + public List? Models { get; set; } +} + +public class GetAllClubMembershipCycleHistoryByFilterResponseModel +{ + public long Id { get; set; } + public long ClubMembershipCycleId { get; set; } + public long UserId { get; set; } + public string UserName { get; set; } = string.Empty; + public int CycleNumber { get; set; } + public bool OldIsCurrentCycle { get; set; } + public bool NewIsCurrentCycle { get; set; } + public DateTime? OldMagicStartedAt { get; set; } + public DateTime? NewMagicStartedAt { get; set; } + public DateTime? OldMagicCompletedAt { get; set; } + public DateTime? NewMagicCompletedAt { get; set; } + public ClubMembershipCycleAction Action { get; set; } + public string? PerformedBy { get; set; } + public string? Reason { get; set; } + public DateTimeOffset Created { get; set; } +} diff --git a/src/CMSMicroservice.Application/ClubMembershipCycleHistoryCQ/Queries/GetAllClubMembershipCycleHistoryByFilter/GetAllClubMembershipCycleHistoryByFilterQueryHandler.cs b/src/CMSMicroservice.Application/ClubMembershipCycleHistoryCQ/Queries/GetAllClubMembershipCycleHistoryByFilter/GetAllClubMembershipCycleHistoryByFilterQueryHandler.cs new file mode 100644 index 0000000..97ede8d --- /dev/null +++ b/src/CMSMicroservice.Application/ClubMembershipCycleHistoryCQ/Queries/GetAllClubMembershipCycleHistoryByFilter/GetAllClubMembershipCycleHistoryByFilterQueryHandler.cs @@ -0,0 +1,52 @@ +namespace CMSMicroservice.Application.ClubMembershipCycleHistoryCQ.Queries.GetAllClubMembershipCycleHistoryByFilter; + +public class GetAllClubMembershipCycleHistoryByFilterQueryHandler + : IRequestHandler +{ + private readonly IApplicationDbContext _context; + + public GetAllClubMembershipCycleHistoryByFilterQueryHandler(IApplicationDbContext context) + { + _context = context; + } + + public async Task Handle( + GetAllClubMembershipCycleHistoryByFilterQuery request, + CancellationToken cancellationToken) + { + var query = _context.ClubMembershipCycleHistories + .Include(x => x.ClubMembershipCycle) + .ThenInclude(c => c!.User) + .AsNoTracking() + .ApplyClubMembershipCycleHistoryFilter(request.Filter) + .ApplyOrder(sortBy: request.SortBy ?? "-Created"); + + return new GetAllClubMembershipCycleHistoryByFilterResponseDto + { + MetaData = await query.GetMetaData(request.PaginationState, cancellationToken), + Models = await query + .PaginatedListAsync(paginationState: request.PaginationState) + .Select(x => new GetAllClubMembershipCycleHistoryByFilterResponseModel + { + Id = x.Id, + ClubMembershipCycleId = x.ClubMembershipCycleId, + UserId = x.UserId, + UserName = x.ClubMembershipCycle != null && x.ClubMembershipCycle.User != null + ? $"{x.ClubMembershipCycle.User.FirstName} {x.ClubMembershipCycle.User.LastName}" + : string.Empty, + CycleNumber = x.CycleNumber, + OldIsCurrentCycle = x.OldIsCurrentCycle, + NewIsCurrentCycle = x.NewIsCurrentCycle, + OldMagicStartedAt = x.OldMagicStartedAt, + NewMagicStartedAt = x.NewMagicStartedAt, + OldMagicCompletedAt = x.OldMagicCompletedAt, + NewMagicCompletedAt = x.NewMagicCompletedAt, + Action = x.Action, + PerformedBy = x.PerformedBy, + Reason = x.Reason, + Created = x.Created + }) + .ToListAsync(cancellationToken) + }; + } +} diff --git a/src/CMSMicroservice.Application/Common/Helpers/ClubMembershipCycleHistoryWriter.cs b/src/CMSMicroservice.Application/Common/Helpers/ClubMembershipCycleHistoryWriter.cs new file mode 100644 index 0000000..8689374 --- /dev/null +++ b/src/CMSMicroservice.Application/Common/Helpers/ClubMembershipCycleHistoryWriter.cs @@ -0,0 +1,54 @@ +using CMSMicroservice.Domain.Entities.Club; +using CMSMicroservice.Domain.Entities.History; +using CMSMicroservice.Domain.Enums; + +namespace CMSMicroservice.Application.Common.Helpers; + +public static class ClubMembershipCycleHistoryWriter +{ + public static void WriteCycleStarted( + IApplicationDbContext context, + ClubMembershipCycle cycle, + string? performedBy = "System", + string? reason = null) + { + context.ClubMembershipCycleHistories.Add(new ClubMembershipCycleHistory + { + ClubMembershipCycleId = cycle.Id, + UserId = cycle.UserId, + CycleNumber = cycle.CycleNumber, + OldIsCurrentCycle = false, + NewIsCurrentCycle = cycle.IsCurrentCycle, + OldMagicStartedAt = null, + NewMagicStartedAt = cycle.MagicStartedAt, + OldMagicCompletedAt = null, + NewMagicCompletedAt = cycle.MagicCompletedAt, + Action = ClubMembershipCycleAction.Started, + PerformedBy = performedBy, + Reason = reason + }); + } + + public static void WriteCycleClosed( + IApplicationDbContext context, + ClubMembershipCycle cycle, + string? performedBy = "System", + string? reason = null) + { + context.ClubMembershipCycleHistories.Add(new ClubMembershipCycleHistory + { + ClubMembershipCycleId = cycle.Id, + UserId = cycle.UserId, + CycleNumber = cycle.CycleNumber, + OldIsCurrentCycle = true, + NewIsCurrentCycle = false, + OldMagicStartedAt = cycle.MagicStartedAt, + NewMagicStartedAt = cycle.MagicStartedAt, + OldMagicCompletedAt = cycle.MagicCompletedAt, + NewMagicCompletedAt = cycle.MagicCompletedAt, + Action = ClubMembershipCycleAction.Completed, + PerformedBy = performedBy, + Reason = reason ?? "دوره جدید جایگزین شد" + }); + } +} diff --git a/src/CMSMicroservice.Application/PaymentTransactionCQ/Queries/GetAllPaymentTransactionByFilter/GetAllPaymentTransactionByFilterQuery.cs b/src/CMSMicroservice.Application/PaymentTransactionCQ/Queries/GetAllPaymentTransactionByFilter/GetAllPaymentTransactionByFilterQuery.cs new file mode 100644 index 0000000..e9205d9 --- /dev/null +++ b/src/CMSMicroservice.Application/PaymentTransactionCQ/Queries/GetAllPaymentTransactionByFilter/GetAllPaymentTransactionByFilterQuery.cs @@ -0,0 +1,46 @@ +namespace CMSMicroservice.Application.PaymentTransactionCQ.Queries.GetAllPaymentTransactionByFilter; + +public record GetAllPaymentTransactionByFilterQuery : IRequest +{ + public PaginationState? PaginationState { get; init; } + public string? SortBy { get; init; } + public GetAllPaymentTransactionByFilterFilter? Filter { get; init; } +} + +public class GetAllPaymentTransactionByFilterFilter +{ + public long? UserId { get; set; } + public string? Mobile { get; set; } + public string? GatewayProvider { get; set; } + public bool? PaymentStatus { get; set; } + public string? Authority { get; set; } + public string? RefId { get; set; } + public string? OrderId { get; set; } + public DateTime? CreatedFrom { get; set; } + public DateTime? CreatedTo { get; set; } +} + +public class GetAllPaymentTransactionByFilterResponseDto +{ + public MetaData MetaData { get; set; } + public List? Models { get; set; } +} + +public class GetAllPaymentTransactionByFilterResponseModel +{ + public long Id { get; set; } + public long? UserId { get; set; } + public string? Mobile { get; set; } + public string GatewayProvider { get; set; } = string.Empty; + public long Amount { get; set; } + public string? Authority { get; set; } + public bool PaymentStatus { get; set; } + public int? VerificationStatusCode { get; set; } + public string? VerificationStatusMessage { get; set; } + public string? RefId { get; set; } + public string? CardPan { get; set; } + public string? OrderId { get; set; } + public long? TransactionId { get; set; } + public string? Description { get; set; } + public DateTimeOffset Created { get; set; } +} diff --git a/src/CMSMicroservice.Application/PaymentTransactionCQ/Queries/GetAllPaymentTransactionByFilter/GetAllPaymentTransactionByFilterQueryHandler.cs b/src/CMSMicroservice.Application/PaymentTransactionCQ/Queries/GetAllPaymentTransactionByFilter/GetAllPaymentTransactionByFilterQueryHandler.cs new file mode 100644 index 0000000..57e3e0f --- /dev/null +++ b/src/CMSMicroservice.Application/PaymentTransactionCQ/Queries/GetAllPaymentTransactionByFilter/GetAllPaymentTransactionByFilterQueryHandler.cs @@ -0,0 +1,48 @@ +namespace CMSMicroservice.Application.PaymentTransactionCQ.Queries.GetAllPaymentTransactionByFilter; + +public class GetAllPaymentTransactionByFilterQueryHandler + : IRequestHandler +{ + private readonly IApplicationDbContext _context; + + public GetAllPaymentTransactionByFilterQueryHandler(IApplicationDbContext context) + { + _context = context; + } + + public async Task Handle( + GetAllPaymentTransactionByFilterQuery request, + CancellationToken cancellationToken) + { + var query = _context.PaymentTransactions + .AsNoTracking() + .ApplyPaymentTransactionFilter(request.Filter) + .ApplyOrder(sortBy: request.SortBy ?? "-Created"); + + return new GetAllPaymentTransactionByFilterResponseDto + { + MetaData = await query.GetMetaData(request.PaginationState, cancellationToken), + Models = await query + .PaginatedListAsync(paginationState: request.PaginationState) + .Select(x => new GetAllPaymentTransactionByFilterResponseModel + { + Id = x.Id, + UserId = x.UserId, + Mobile = x.Mobile, + GatewayProvider = x.GatewayProvider, + Amount = x.Amount, + Authority = x.Authority, + PaymentStatus = x.PaymentStatus, + VerificationStatusCode = x.VerificationStatusCode, + VerificationStatusMessage = x.VerificationStatusMessage, + RefId = x.RefId, + CardPan = x.CardPan, + OrderId = x.OrderId, + TransactionId = x.TransactionId, + Description = x.Description, + Created = x.Created + }) + .ToListAsync(cancellationToken) + }; + } +} diff --git a/src/CMSMicroservice.Application/PaymentTransactionCQ/Queries/GetAllPaymentTransactionByFilter/PaymentTransactionFilterExtensions.cs b/src/CMSMicroservice.Application/PaymentTransactionCQ/Queries/GetAllPaymentTransactionByFilter/PaymentTransactionFilterExtensions.cs new file mode 100644 index 0000000..93d14eb --- /dev/null +++ b/src/CMSMicroservice.Application/PaymentTransactionCQ/Queries/GetAllPaymentTransactionByFilter/PaymentTransactionFilterExtensions.cs @@ -0,0 +1,42 @@ +using CMSMicroservice.Domain.Entities.Payment; + +namespace CMSMicroservice.Application.PaymentTransactionCQ.Queries.GetAllPaymentTransactionByFilter; + +public static class PaymentTransactionFilterExtensions +{ + public static IQueryable ApplyPaymentTransactionFilter( + this IQueryable query, + GetAllPaymentTransactionByFilterFilter? filter) + { + if (filter == null) return query; + + if (filter.UserId.HasValue) + query = query.Where(x => x.UserId == filter.UserId.Value); + + if (!string.IsNullOrWhiteSpace(filter.Mobile)) + query = query.Where(x => x.Mobile != null && x.Mobile.Contains(filter.Mobile)); + + if (!string.IsNullOrWhiteSpace(filter.GatewayProvider)) + query = query.Where(x => x.GatewayProvider == filter.GatewayProvider); + + if (filter.PaymentStatus.HasValue) + query = query.Where(x => x.PaymentStatus == filter.PaymentStatus.Value); + + if (!string.IsNullOrWhiteSpace(filter.Authority)) + query = query.Where(x => x.Authority != null && x.Authority.Contains(filter.Authority)); + + if (!string.IsNullOrWhiteSpace(filter.RefId)) + query = query.Where(x => x.RefId != null && x.RefId.Contains(filter.RefId)); + + if (!string.IsNullOrWhiteSpace(filter.OrderId)) + query = query.Where(x => x.OrderId != null && x.OrderId.Contains(filter.OrderId)); + + if (filter.CreatedFrom.HasValue) + query = query.Where(x => x.Created >= filter.CreatedFrom.Value); + + if (filter.CreatedTo.HasValue) + query = query.Where(x => x.Created <= filter.CreatedTo.Value); + + return query; + } +} diff --git a/src/CMSMicroservice.Application/PaymentTransactionCQ/Queries/GetPaymentTransactionSummary/GetPaymentTransactionSummaryQuery.cs b/src/CMSMicroservice.Application/PaymentTransactionCQ/Queries/GetPaymentTransactionSummary/GetPaymentTransactionSummaryQuery.cs new file mode 100644 index 0000000..6abd4e5 --- /dev/null +++ b/src/CMSMicroservice.Application/PaymentTransactionCQ/Queries/GetPaymentTransactionSummary/GetPaymentTransactionSummaryQuery.cs @@ -0,0 +1,14 @@ +namespace CMSMicroservice.Application.PaymentTransactionCQ.Queries.GetPaymentTransactionSummary; + +public record GetPaymentTransactionSummaryQuery : IRequest +{ + public GetAllPaymentTransactionByFilter.GetAllPaymentTransactionByFilterFilter? Filter { get; init; } +} + +public class GetPaymentTransactionSummaryResponseDto +{ + public long TotalCount { get; set; } + public long TotalAmount { get; set; } + public long SuccessfulCount { get; set; } + public long PendingCount { get; set; } +} diff --git a/src/CMSMicroservice.Application/PaymentTransactionCQ/Queries/GetPaymentTransactionSummary/GetPaymentTransactionSummaryQueryHandler.cs b/src/CMSMicroservice.Application/PaymentTransactionCQ/Queries/GetPaymentTransactionSummary/GetPaymentTransactionSummaryQueryHandler.cs new file mode 100644 index 0000000..218d845 --- /dev/null +++ b/src/CMSMicroservice.Application/PaymentTransactionCQ/Queries/GetPaymentTransactionSummary/GetPaymentTransactionSummaryQueryHandler.cs @@ -0,0 +1,36 @@ +using CMSMicroservice.Application.PaymentTransactionCQ.Queries.GetAllPaymentTransactionByFilter; + +namespace CMSMicroservice.Application.PaymentTransactionCQ.Queries.GetPaymentTransactionSummary; + +public class GetPaymentTransactionSummaryQueryHandler + : IRequestHandler +{ + private readonly IApplicationDbContext _context; + + public GetPaymentTransactionSummaryQueryHandler(IApplicationDbContext context) + { + _context = context; + } + + public async Task Handle( + GetPaymentTransactionSummaryQuery request, + CancellationToken cancellationToken) + { + var query = _context.PaymentTransactions + .AsNoTracking() + .ApplyPaymentTransactionFilter(request.Filter); + + var totalCount = await query.LongCountAsync(cancellationToken); + var totalAmount = totalCount > 0 ? await query.SumAsync(x => x.Amount, cancellationToken) : 0; + var successfulCount = await query.LongCountAsync(x => x.PaymentStatus, cancellationToken); + var pendingCount = await query.LongCountAsync(x => !x.PaymentStatus, cancellationToken); + + return new GetPaymentTransactionSummaryResponseDto + { + TotalCount = totalCount, + TotalAmount = totalAmount, + SuccessfulCount = successfulCount, + PendingCount = pendingCount + }; + } +} diff --git a/src/CMSMicroservice.Application/UserPackagePurchaseCQ/Queries/GetAllUserPackagePurchaseByFilter/GetAllUserPackagePurchaseByFilterQuery.cs b/src/CMSMicroservice.Application/UserPackagePurchaseCQ/Queries/GetAllUserPackagePurchaseByFilter/GetAllUserPackagePurchaseByFilterQuery.cs new file mode 100644 index 0000000..5fe581a --- /dev/null +++ b/src/CMSMicroservice.Application/UserPackagePurchaseCQ/Queries/GetAllUserPackagePurchaseByFilter/GetAllUserPackagePurchaseByFilterQuery.cs @@ -0,0 +1,43 @@ +using CMSMicroservice.Domain.Enums; + +namespace CMSMicroservice.Application.UserPackagePurchaseCQ.Queries.GetAllUserPackagePurchaseByFilter; + +public record GetAllUserPackagePurchaseByFilterQuery : IRequest +{ + public PaginationState? PaginationState { get; init; } + public string? SortBy { get; init; } + public GetAllUserPackagePurchaseByFilterFilter? Filter { get; init; } +} + +public class GetAllUserPackagePurchaseByFilterFilter +{ + public long? UserId { get; set; } + public long? PackageId { get; set; } + public PackagePurchaseMethod? PurchaseMethod { get; set; } + public DateTime? PurchasedFrom { get; set; } + public DateTime? PurchasedTo { get; set; } + public long? MinAmount { get; set; } + public long? MaxAmount { get; set; } +} + +public class GetAllUserPackagePurchaseByFilterResponseDto +{ + public MetaData MetaData { get; set; } + public List? Models { get; set; } +} + +public class GetAllUserPackagePurchaseByFilterResponseModel +{ + public long Id { get; set; } + public long UserId { get; set; } + public string UserName { get; set; } = string.Empty; + public string UserMobile { get; set; } = string.Empty; + public long PackageId { get; set; } + public string PackageName { get; set; } = string.Empty; + public PackagePurchaseMethod PurchaseMethod { get; set; } + public DateTime PurchasedAt { get; set; } + public long Amount { get; set; } + public long? OrderId { get; set; } + public long? TransactionId { get; set; } + public DateTimeOffset Created { get; set; } +} diff --git a/src/CMSMicroservice.Application/UserPackagePurchaseCQ/Queries/GetAllUserPackagePurchaseByFilter/GetAllUserPackagePurchaseByFilterQueryHandler.cs b/src/CMSMicroservice.Application/UserPackagePurchaseCQ/Queries/GetAllUserPackagePurchaseByFilter/GetAllUserPackagePurchaseByFilterQueryHandler.cs new file mode 100644 index 0000000..bfdcdfc --- /dev/null +++ b/src/CMSMicroservice.Application/UserPackagePurchaseCQ/Queries/GetAllUserPackagePurchaseByFilter/GetAllUserPackagePurchaseByFilterQueryHandler.cs @@ -0,0 +1,47 @@ +namespace CMSMicroservice.Application.UserPackagePurchaseCQ.Queries.GetAllUserPackagePurchaseByFilter; + +public class GetAllUserPackagePurchaseByFilterQueryHandler + : IRequestHandler +{ + private readonly IApplicationDbContext _context; + + public GetAllUserPackagePurchaseByFilterQueryHandler(IApplicationDbContext context) + { + _context = context; + } + + public async Task Handle( + GetAllUserPackagePurchaseByFilterQuery request, + CancellationToken cancellationToken) + { + var query = _context.UserPackagePurchases + .Include(x => x.User) + .Include(x => x.Package) + .AsNoTracking() + .ApplyUserPackagePurchaseFilter(request.Filter) + .ApplyOrder(sortBy: request.SortBy ?? "-PurchasedAt"); + + return new GetAllUserPackagePurchaseByFilterResponseDto + { + MetaData = await query.GetMetaData(request.PaginationState, cancellationToken), + Models = await query + .PaginatedListAsync(paginationState: request.PaginationState) + .Select(x => new GetAllUserPackagePurchaseByFilterResponseModel + { + Id = x.Id, + UserId = x.UserId, + UserName = x.User != null ? $"{x.User.FirstName} {x.User.LastName}" : string.Empty, + UserMobile = x.User != null ? x.User.Mobile : string.Empty, + PackageId = x.PackageId, + PackageName = x.Package != null ? x.Package.Title : string.Empty, + PurchaseMethod = x.PurchaseMethod, + PurchasedAt = x.PurchasedAt, + Amount = x.Amount, + OrderId = x.OrderId, + TransactionId = x.TransactionId, + Created = x.Created + }) + .ToListAsync(cancellationToken) + }; + } +} diff --git a/src/CMSMicroservice.Application/UserPackagePurchaseCQ/Queries/GetAllUserPackagePurchaseByFilter/UserPackagePurchaseFilterExtensions.cs b/src/CMSMicroservice.Application/UserPackagePurchaseCQ/Queries/GetAllUserPackagePurchaseByFilter/UserPackagePurchaseFilterExtensions.cs new file mode 100644 index 0000000..62aa625 --- /dev/null +++ b/src/CMSMicroservice.Application/UserPackagePurchaseCQ/Queries/GetAllUserPackagePurchaseByFilter/UserPackagePurchaseFilterExtensions.cs @@ -0,0 +1,36 @@ +using CMSMicroservice.Domain.Entities; + +namespace CMSMicroservice.Application.UserPackagePurchaseCQ.Queries.GetAllUserPackagePurchaseByFilter; + +public static class UserPackagePurchaseFilterExtensions +{ + public static IQueryable ApplyUserPackagePurchaseFilter( + this IQueryable query, + GetAllUserPackagePurchaseByFilterFilter? filter) + { + if (filter == null) return query; + + if (filter.UserId.HasValue) + query = query.Where(x => x.UserId == filter.UserId.Value); + + if (filter.PackageId.HasValue) + query = query.Where(x => x.PackageId == filter.PackageId.Value); + + if (filter.PurchaseMethod.HasValue) + query = query.Where(x => x.PurchaseMethod == filter.PurchaseMethod.Value); + + if (filter.PurchasedFrom.HasValue) + query = query.Where(x => x.PurchasedAt >= filter.PurchasedFrom.Value); + + if (filter.PurchasedTo.HasValue) + query = query.Where(x => x.PurchasedAt <= filter.PurchasedTo.Value); + + if (filter.MinAmount.HasValue) + query = query.Where(x => x.Amount >= filter.MinAmount.Value); + + if (filter.MaxAmount.HasValue) + query = query.Where(x => x.Amount <= filter.MaxAmount.Value); + + return query; + } +} diff --git a/src/CMSMicroservice.Application/UserPackagePurchaseCQ/Queries/GetUserPackagePurchaseSummary/GetUserPackagePurchaseSummaryQuery.cs b/src/CMSMicroservice.Application/UserPackagePurchaseCQ/Queries/GetUserPackagePurchaseSummary/GetUserPackagePurchaseSummaryQuery.cs new file mode 100644 index 0000000..abfe52b --- /dev/null +++ b/src/CMSMicroservice.Application/UserPackagePurchaseCQ/Queries/GetUserPackagePurchaseSummary/GetUserPackagePurchaseSummaryQuery.cs @@ -0,0 +1,12 @@ +namespace CMSMicroservice.Application.UserPackagePurchaseCQ.Queries.GetUserPackagePurchaseSummary; + +public record GetUserPackagePurchaseSummaryQuery : IRequest +{ + public GetAllUserPackagePurchaseByFilter.GetAllUserPackagePurchaseByFilterFilter? Filter { get; init; } +} + +public class GetUserPackagePurchaseSummaryResponseDto +{ + public long TotalCount { get; set; } + public long TotalAmount { get; set; } +} diff --git a/src/CMSMicroservice.Application/UserPackagePurchaseCQ/Queries/GetUserPackagePurchaseSummary/GetUserPackagePurchaseSummaryQueryHandler.cs b/src/CMSMicroservice.Application/UserPackagePurchaseCQ/Queries/GetUserPackagePurchaseSummary/GetUserPackagePurchaseSummaryQueryHandler.cs new file mode 100644 index 0000000..654cb75 --- /dev/null +++ b/src/CMSMicroservice.Application/UserPackagePurchaseCQ/Queries/GetUserPackagePurchaseSummary/GetUserPackagePurchaseSummaryQueryHandler.cs @@ -0,0 +1,32 @@ +using CMSMicroservice.Application.UserPackagePurchaseCQ.Queries.GetAllUserPackagePurchaseByFilter; + +namespace CMSMicroservice.Application.UserPackagePurchaseCQ.Queries.GetUserPackagePurchaseSummary; + +public class GetUserPackagePurchaseSummaryQueryHandler + : IRequestHandler +{ + private readonly IApplicationDbContext _context; + + public GetUserPackagePurchaseSummaryQueryHandler(IApplicationDbContext context) + { + _context = context; + } + + public async Task Handle( + GetUserPackagePurchaseSummaryQuery request, + CancellationToken cancellationToken) + { + var query = _context.UserPackagePurchases + .AsNoTracking() + .ApplyUserPackagePurchaseFilter(request.Filter); + + var totalCount = await query.LongCountAsync(cancellationToken); + var totalAmount = totalCount > 0 ? await query.SumAsync(x => x.Amount, cancellationToken) : 0; + + return new GetUserPackagePurchaseSummaryResponseDto + { + TotalCount = totalCount, + TotalAmount = totalAmount + }; + } +} diff --git a/src/CMSMicroservice.Protobuf/CMSMicroservice.Protobuf.csproj b/src/CMSMicroservice.Protobuf/CMSMicroservice.Protobuf.csproj index 8525e81..02bd97b 100644 --- a/src/CMSMicroservice.Protobuf/CMSMicroservice.Protobuf.csproj +++ b/src/CMSMicroservice.Protobuf/CMSMicroservice.Protobuf.csproj @@ -3,7 +3,7 @@ net9.0 enable enable - 0.0.200 + 0.0.201 None False False @@ -74,6 +74,11 @@ + + + + + diff --git a/src/CMSMicroservice.Protobuf/Protos/clubmembership.proto b/src/CMSMicroservice.Protobuf/Protos/clubmembership.proto index 9520d8d..eb5957e 100644 --- a/src/CMSMicroservice.Protobuf/Protos/clubmembership.proto +++ b/src/CMSMicroservice.Protobuf/Protos/clubmembership.proto @@ -164,11 +164,19 @@ message ClubMembershipModel // GetHistory Query message GetClubMembershipHistoryRequest +{ + messages.PaginationState pagination_state = 1; + google.protobuf.StringValue sort_by = 2; + GetClubMembershipHistoryFilter filter = 3; +} + +message GetClubMembershipHistoryFilter { google.protobuf.Int64Value user_id = 1; - google.protobuf.Int64Value package_id = 2; - int32 page_index = 3; - int32 page_size = 4; + google.protobuf.Int64Value club_membership_id = 2; + google.protobuf.Int32Value action = 3; + google.protobuf.Timestamp created_from = 4; + google.protobuf.Timestamp created_to = 5; } message GetClubMembershipHistoryResponse @@ -182,16 +190,15 @@ message ClubMembershipHistoryModel int64 id = 1; int64 club_membership_id = 2; int64 user_id = 3; - google.protobuf.Int64Value old_package_id = 4; - google.protobuf.Int64Value new_package_id = 5; - google.protobuf.Timestamp old_activated_at = 6; - google.protobuf.Timestamp new_activated_at = 7; - google.protobuf.Timestamp old_expires_at = 8; - google.protobuf.Timestamp new_expires_at = 9; - int32 action = 10; // ClubMembershipAction enum - string performed_by = 11; - string reason = 12; - google.protobuf.Timestamp created = 13; + string user_name = 4; + bool old_is_active = 5; + bool new_is_active = 6; + google.protobuf.Int64Value old_initial_contribution = 7; + google.protobuf.Int64Value new_initial_contribution = 8; + int32 action = 9; // ClubMembershipAction enum + string performed_by = 10; + string reason = 11; + google.protobuf.Timestamp created_at = 12; } // GetClubStatistics Query diff --git a/src/CMSMicroservice.Protobuf/Protos/clubmembershipcycle.proto b/src/CMSMicroservice.Protobuf/Protos/clubmembershipcycle.proto new file mode 100644 index 0000000..e68ecf7 --- /dev/null +++ b/src/CMSMicroservice.Protobuf/Protos/clubmembershipcycle.proto @@ -0,0 +1,79 @@ +syntax = "proto3"; + +package clubmembershipcycle; + +import "public_messages.proto"; +import "google/protobuf/wrappers.proto"; +import "google/protobuf/timestamp.proto"; +import "google/api/annotations.proto"; + +option csharp_namespace = "CMSMicroservice.Protobuf.Protos.ClubMembershipCycle"; + +service ClubMembershipCycleContract +{ + rpc GetAllClubMembershipCycleByFilter(GetAllClubMembershipCycleByFilterRequest) returns (GetAllClubMembershipCycleByFilterResponse){ + option (google.api.http) = { + get: "/ClubMembershipCycle/GetAllByFilter" + }; + }; + rpc GetClubMembershipCycleSummary(GetClubMembershipCycleSummaryRequest) returns (GetClubMembershipCycleSummaryResponse){ + option (google.api.http) = { + get: "/ClubMembershipCycle/GetSummary" + }; + }; +} + +message GetAllClubMembershipCycleByFilterRequest +{ + messages.PaginationState pagination_state = 1; + google.protobuf.StringValue sort_by = 2; + GetAllClubMembershipCycleByFilterFilter filter = 3; +} + +message GetAllClubMembershipCycleByFilterFilter +{ + google.protobuf.Int64Value user_id = 1; + google.protobuf.BoolValue is_current_cycle = 2; + google.protobuf.Int64Value package_id = 3; + google.protobuf.Int32Value cycle_number = 4; + google.protobuf.Int32Value purchase_method = 5; + google.protobuf.Int32Value magic_state = 6; // 0=none, 1=active, 2=completed + google.protobuf.Timestamp package_purchased_from = 7; + google.protobuf.Timestamp package_purchased_to = 8; +} + +message GetAllClubMembershipCycleByFilterResponse +{ + messages.MetaData meta_data = 1; + repeated ClubMembershipCycleModel models = 2; +} + +message ClubMembershipCycleModel +{ + int64 id = 1; + int64 user_id = 2; + string user_name = 3; + int64 club_membership_id = 4; + int32 cycle_number = 5; + int64 package_id = 6; + string package_name = 7; + int64 package_amount = 8; + int32 purchase_method = 9; + google.protobuf.Timestamp package_purchased_at = 10; + google.protobuf.Timestamp magic_started_at = 11; + google.protobuf.Timestamp magic_completed_at = 12; + bool is_current_cycle = 13; + google.protobuf.Timestamp created_at = 14; +} + +message GetClubMembershipCycleSummaryRequest +{ + GetAllClubMembershipCycleByFilterFilter filter = 1; +} + +message GetClubMembershipCycleSummaryResponse +{ + int64 total_count = 1; + int64 current_cycle_count = 2; + int64 magic_active_count = 3; +} diff --git a/src/CMSMicroservice.Protobuf/Protos/clubmembershipcyclehistory.proto b/src/CMSMicroservice.Protobuf/Protos/clubmembershipcyclehistory.proto new file mode 100644 index 0000000..44fe61f --- /dev/null +++ b/src/CMSMicroservice.Protobuf/Protos/clubmembershipcyclehistory.proto @@ -0,0 +1,61 @@ +syntax = "proto3"; + +package clubmembershipcyclehistory; + +import "public_messages.proto"; +import "google/protobuf/wrappers.proto"; +import "google/protobuf/timestamp.proto"; +import "google/api/annotations.proto"; + +option csharp_namespace = "CMSMicroservice.Protobuf.Protos.ClubMembershipCycleHistory"; + +service ClubMembershipCycleHistoryContract +{ + rpc GetAllClubMembershipCycleHistoryByFilter(GetAllClubMembershipCycleHistoryByFilterRequest) returns (GetAllClubMembershipCycleHistoryByFilterResponse){ + option (google.api.http) = { + get: "/ClubMembershipCycleHistory/GetAllByFilter" + }; + }; +} + +message GetAllClubMembershipCycleHistoryByFilterRequest +{ + messages.PaginationState pagination_state = 1; + google.protobuf.StringValue sort_by = 2; + GetAllClubMembershipCycleHistoryByFilterFilter filter = 3; +} + +message GetAllClubMembershipCycleHistoryByFilterFilter +{ + google.protobuf.Int64Value user_id = 1; + google.protobuf.Int64Value club_membership_cycle_id = 2; + google.protobuf.Int32Value cycle_number = 3; + google.protobuf.Int32Value action = 4; + google.protobuf.Timestamp created_from = 5; + google.protobuf.Timestamp created_to = 6; +} + +message GetAllClubMembershipCycleHistoryByFilterResponse +{ + messages.MetaData meta_data = 1; + repeated ClubMembershipCycleHistoryModel models = 2; +} + +message ClubMembershipCycleHistoryModel +{ + int64 id = 1; + int64 club_membership_cycle_id = 2; + int64 user_id = 3; + string user_name = 4; + int32 cycle_number = 5; + bool old_is_current_cycle = 6; + bool new_is_current_cycle = 7; + google.protobuf.Timestamp old_magic_started_at = 8; + google.protobuf.Timestamp new_magic_started_at = 9; + google.protobuf.Timestamp old_magic_completed_at = 10; + google.protobuf.Timestamp new_magic_completed_at = 11; + int32 action = 12; + string performed_by = 13; + string reason = 14; + google.protobuf.Timestamp created_at = 15; +} diff --git a/src/CMSMicroservice.Protobuf/Protos/paymenttransaction.proto b/src/CMSMicroservice.Protobuf/Protos/paymenttransaction.proto new file mode 100644 index 0000000..488c6b6 --- /dev/null +++ b/src/CMSMicroservice.Protobuf/Protos/paymenttransaction.proto @@ -0,0 +1,82 @@ +syntax = "proto3"; + +package paymenttransaction; + +import "public_messages.proto"; +import "google/protobuf/wrappers.proto"; +import "google/protobuf/timestamp.proto"; +import "google/api/annotations.proto"; + +option csharp_namespace = "CMSMicroservice.Protobuf.Protos.PaymentTransaction"; + +service PaymentTransactionContract +{ + rpc GetAllPaymentTransactionByFilter(GetAllPaymentTransactionByFilterRequest) returns (GetAllPaymentTransactionByFilterResponse){ + option (google.api.http) = { + get: "/PaymentTransaction/GetAllByFilter" + }; + }; + rpc GetPaymentTransactionSummary(GetPaymentTransactionSummaryRequest) returns (GetPaymentTransactionSummaryResponse){ + option (google.api.http) = { + get: "/PaymentTransaction/GetSummary" + }; + }; +} + +message GetAllPaymentTransactionByFilterRequest +{ + messages.PaginationState pagination_state = 1; + google.protobuf.StringValue sort_by = 2; + GetAllPaymentTransactionByFilterFilter filter = 3; +} + +message GetAllPaymentTransactionByFilterFilter +{ + google.protobuf.Int64Value user_id = 1; + google.protobuf.StringValue mobile = 2; + google.protobuf.StringValue gateway_provider = 3; + google.protobuf.BoolValue payment_status = 4; + google.protobuf.StringValue authority = 5; + google.protobuf.StringValue ref_id = 6; + google.protobuf.StringValue order_id = 7; + google.protobuf.Timestamp created_from = 8; + google.protobuf.Timestamp created_to = 9; +} + +message GetAllPaymentTransactionByFilterResponse +{ + messages.MetaData meta_data = 1; + repeated PaymentTransactionModel models = 2; +} + +message PaymentTransactionModel +{ + int64 id = 1; + int64 user_id = 2; + string mobile = 3; + string gateway_provider = 4; + int64 amount = 5; + string authority = 6; + bool payment_status = 7; + google.protobuf.Int32Value verification_status_code = 8; + string verification_status_message = 9; + string ref_id = 10; + string card_pan = 11; + string order_id = 12; + google.protobuf.Int64Value transaction_id = 13; + string description = 14; + google.protobuf.Timestamp created_at = 15; +} + +message GetPaymentTransactionSummaryRequest +{ + GetAllPaymentTransactionByFilterFilter filter = 1; +} + +message GetPaymentTransactionSummaryResponse +{ + int64 total_count = 1; + int64 total_amount = 2; + int64 successful_count = 3; + int64 pending_count = 4; +} diff --git a/src/CMSMicroservice.Protobuf/Protos/userpackagepurchase.proto b/src/CMSMicroservice.Protobuf/Protos/userpackagepurchase.proto new file mode 100644 index 0000000..8a52aa4 --- /dev/null +++ b/src/CMSMicroservice.Protobuf/Protos/userpackagepurchase.proto @@ -0,0 +1,75 @@ +syntax = "proto3"; + +package userpackagepurchase; + +import "public_messages.proto"; +import "google/protobuf/wrappers.proto"; +import "google/protobuf/timestamp.proto"; +import "google/api/annotations.proto"; + +option csharp_namespace = "CMSMicroservice.Protobuf.Protos.UserPackagePurchase"; + +service UserPackagePurchaseContract +{ + rpc GetAllUserPackagePurchaseByFilter(GetAllUserPackagePurchaseByFilterRequest) returns (GetAllUserPackagePurchaseByFilterResponse){ + option (google.api.http) = { + get: "/UserPackagePurchase/GetAllByFilter" + }; + }; + rpc GetUserPackagePurchaseSummary(GetUserPackagePurchaseSummaryRequest) returns (GetUserPackagePurchaseSummaryResponse){ + option (google.api.http) = { + get: "/UserPackagePurchase/GetSummary" + }; + }; +} + +message GetAllUserPackagePurchaseByFilterRequest +{ + messages.PaginationState pagination_state = 1; + google.protobuf.StringValue sort_by = 2; + GetAllUserPackagePurchaseByFilterFilter filter = 3; +} + +message GetAllUserPackagePurchaseByFilterFilter +{ + google.protobuf.Int64Value user_id = 1; + google.protobuf.Int64Value package_id = 2; + google.protobuf.Int32Value purchase_method = 3; + google.protobuf.Timestamp purchased_from = 4; + google.protobuf.Timestamp purchased_to = 5; + google.protobuf.Int64Value min_amount = 6; + google.protobuf.Int64Value max_amount = 7; +} + +message GetAllUserPackagePurchaseByFilterResponse +{ + messages.MetaData meta_data = 1; + repeated UserPackagePurchaseModel models = 2; +} + +message UserPackagePurchaseModel +{ + int64 id = 1; + int64 user_id = 2; + string user_name = 3; + string user_mobile = 4; + int64 package_id = 5; + string package_name = 6; + int32 purchase_method = 7; + google.protobuf.Timestamp purchased_at = 8; + int64 amount = 9; + google.protobuf.Int64Value order_id = 10; + google.protobuf.Int64Value transaction_id = 11; + google.protobuf.Timestamp created_at = 12; +} + +message GetUserPackagePurchaseSummaryRequest +{ + GetAllUserPackagePurchaseByFilterFilter filter = 1; +} + +message GetUserPackagePurchaseSummaryResponse +{ + int64 total_count = 1; + int64 total_amount = 2; +} diff --git a/src/CMSMicroservice.WebApi/Common/Mappings/ClubMembershipCycleHistoryProfile.cs b/src/CMSMicroservice.WebApi/Common/Mappings/ClubMembershipCycleHistoryProfile.cs new file mode 100644 index 0000000..eec483a --- /dev/null +++ b/src/CMSMicroservice.WebApi/Common/Mappings/ClubMembershipCycleHistoryProfile.cs @@ -0,0 +1,81 @@ +using CMSMicroservice.Application.ClubMembershipCycleHistoryCQ.Queries.GetAllClubMembershipCycleHistoryByFilter; +using CMSMicroservice.Protobuf.Protos.ClubMembershipCycleHistory; +using Google.Protobuf.WellKnownTypes; +using Mapster; + +namespace CMSMicroservice.WebApi.Common.Mappings; + +public class ClubMembershipCycleHistoryProfile : IRegister +{ + public void Register(TypeAdapterConfig config) + { + config.NewConfig() + .MapWith(src => new GetAllClubMembershipCycleHistoryByFilterQuery + { + PaginationState = MapPagination(src.PaginationState), + SortBy = src.HasSortBy ? src.SortBy : null, + Filter = MapFilter(src.Filter) + }); + + config.NewConfig() + .MapWith(src => new GetAllClubMembershipCycleHistoryByFilterResponse + { + MetaData = MapMeta(src.MetaData), + Models = { src.Models?.Select(MapModel) ?? [] } + }); + } + + private static GetAllClubMembershipCycleHistoryByFilterFilter? MapFilter(GetAllClubMembershipCycleHistoryByFilterFilter? src) + { + if (src == null) return null; + return new GetAllClubMembershipCycleHistoryByFilterFilter + { + UserId = src.HasUserId ? src.UserId : null, + ClubMembershipCycleId = src.HasClubMembershipCycleId ? src.ClubMembershipCycleId : null, + CycleNumber = src.HasCycleNumber ? src.CycleNumber : null, + Action = src.HasAction ? (Domain.Enums.ClubMembershipCycleAction)src.Action : null, + CreatedFrom = src.CreatedFrom?.ToDateTime(), + CreatedTo = src.CreatedTo?.ToDateTime() + }; + } + + private static ClubMembershipCycleHistoryModel MapModel(GetAllClubMembershipCycleHistoryByFilterResponseModel m) => + new() + { + Id = m.Id, + ClubMembershipCycleId = m.ClubMembershipCycleId, + UserId = m.UserId, + UserName = m.UserName, + CycleNumber = m.CycleNumber, + OldIsCurrentCycle = m.OldIsCurrentCycle, + NewIsCurrentCycle = m.NewIsCurrentCycle, + OldMagicStartedAt = m.OldMagicStartedAt.HasValue + ? Timestamp.FromDateTime(DateTime.SpecifyKind(m.OldMagicStartedAt.Value, DateTimeKind.Utc)) : null, + NewMagicStartedAt = m.NewMagicStartedAt.HasValue + ? Timestamp.FromDateTime(DateTime.SpecifyKind(m.NewMagicStartedAt.Value, DateTimeKind.Utc)) : null, + OldMagicCompletedAt = m.OldMagicCompletedAt.HasValue + ? Timestamp.FromDateTime(DateTime.SpecifyKind(m.OldMagicCompletedAt.Value, DateTimeKind.Utc)) : null, + NewMagicCompletedAt = m.NewMagicCompletedAt.HasValue + ? Timestamp.FromDateTime(DateTime.SpecifyKind(m.NewMagicCompletedAt.Value, DateTimeKind.Utc)) : null, + Action = (int)m.Action, + PerformedBy = m.PerformedBy ?? string.Empty, + Reason = m.Reason ?? string.Empty, + CreatedAt = Timestamp.FromDateTimeOffset(m.Created) + }; + + private static Application.Common.Models.PaginationState? MapPagination(CMSMicroservice.Protobuf.Protos.PaginationState? ps) => + ps == null ? null : new Application.Common.Models.PaginationState + { + PageNumber = ps.PageNumber > 0 ? ps.PageNumber : 1, + PageSize = ps.PageSize > 0 ? ps.PageSize : 20 + }; + + private static CMSMicroservice.Protobuf.Protos.MetaData MapMeta(Application.Common.Models.MetaData meta) => + new() + { + CurrentPage = meta.CurrentPage, + PageSize = meta.PageSize, + TotalCount = meta.TotalCount, + TotalPage = meta.TotalPage + }; +} diff --git a/src/CMSMicroservice.WebApi/Common/Mappings/ClubMembershipCycleProfile.cs b/src/CMSMicroservice.WebApi/Common/Mappings/ClubMembershipCycleProfile.cs new file mode 100644 index 0000000..10f961d --- /dev/null +++ b/src/CMSMicroservice.WebApi/Common/Mappings/ClubMembershipCycleProfile.cs @@ -0,0 +1,92 @@ +using CMSMicroservice.Application.ClubMembershipCycleCQ.Queries.GetAllClubMembershipCycleByFilter; +using CMSMicroservice.Application.ClubMembershipCycleCQ.Queries.GetClubMembershipCycleSummary; +using CMSMicroservice.Protobuf.Protos.ClubMembershipCycle; +using Google.Protobuf.WellKnownTypes; +using Mapster; + +namespace CMSMicroservice.WebApi.Common.Mappings; + +public class ClubMembershipCycleProfile : IRegister +{ + public void Register(TypeAdapterConfig config) + { + config.NewConfig() + .MapWith(src => new GetAllClubMembershipCycleByFilterQuery + { + PaginationState = MapPagination(src.PaginationState), + SortBy = src.HasSortBy ? src.SortBy : null, + Filter = MapFilter(src.Filter) + }); + + config.NewConfig() + .MapWith(src => new GetAllClubMembershipCycleByFilterResponse + { + MetaData = MapMeta(src.MetaData), + Models = { src.Models?.Select(MapModel) ?? [] } + }); + + config.NewConfig() + .MapWith(src => new GetClubMembershipCycleSummaryQuery { Filter = MapFilter(src.Filter) }); + + config.NewConfig() + .MapWith(src => new GetClubMembershipCycleSummaryResponse + { + TotalCount = src.TotalCount, + CurrentCycleCount = src.CurrentCycleCount, + MagicActiveCount = src.MagicActiveCount + }); + } + + private static GetAllClubMembershipCycleByFilterFilter? MapFilter(GetAllClubMembershipCycleByFilterFilter? src) + { + if (src == null) return null; + return new GetAllClubMembershipCycleByFilterFilter + { + UserId = src.HasUserId ? src.UserId : null, + IsCurrentCycle = src.HasIsCurrentCycle ? src.IsCurrentCycle : null, + PackageId = src.HasPackageId ? src.PackageId : null, + CycleNumber = src.HasCycleNumber ? src.CycleNumber : null, + PurchaseMethod = src.HasPurchaseMethod ? (Domain.Enums.PackagePurchaseMethod)src.PurchaseMethod : null, + MagicState = src.HasMagicState ? src.MagicState : null, + PackagePurchasedFrom = src.PackagePurchasedFrom?.ToDateTime(), + PackagePurchasedTo = src.PackagePurchasedTo?.ToDateTime() + }; + } + + private static ClubMembershipCycleModel MapModel(GetAllClubMembershipCycleByFilterResponseModel m) => + new() + { + Id = m.Id, + UserId = m.UserId, + UserName = m.UserName, + ClubMembershipId = m.ClubMembershipId, + CycleNumber = m.CycleNumber, + PackageId = m.PackageId, + PackageName = m.PackageName, + PackageAmount = m.PackageAmount, + PurchaseMethod = (int)m.PurchaseMethod, + PackagePurchasedAt = Timestamp.FromDateTime(DateTime.SpecifyKind(m.PackagePurchasedAt, DateTimeKind.Utc)), + MagicStartedAt = m.MagicStartedAt.HasValue + ? Timestamp.FromDateTime(DateTime.SpecifyKind(m.MagicStartedAt.Value, DateTimeKind.Utc)) : null, + MagicCompletedAt = m.MagicCompletedAt.HasValue + ? Timestamp.FromDateTime(DateTime.SpecifyKind(m.MagicCompletedAt.Value, DateTimeKind.Utc)) : null, + IsCurrentCycle = m.IsCurrentCycle, + CreatedAt = Timestamp.FromDateTimeOffset(m.Created) + }; + + private static Application.Common.Models.PaginationState? MapPagination(CMSMicroservice.Protobuf.Protos.PaginationState? ps) => + ps == null ? null : new Application.Common.Models.PaginationState + { + PageNumber = ps.PageNumber > 0 ? ps.PageNumber : 1, + PageSize = ps.PageSize > 0 ? ps.PageSize : 20 + }; + + private static CMSMicroservice.Protobuf.Protos.MetaData MapMeta(Application.Common.Models.MetaData meta) => + new() + { + CurrentPage = meta.CurrentPage, + PageSize = meta.PageSize, + TotalCount = meta.TotalCount, + TotalPage = meta.TotalPage + }; +} diff --git a/src/CMSMicroservice.WebApi/Common/Mappings/ClubMembershipProfile.cs b/src/CMSMicroservice.WebApi/Common/Mappings/ClubMembershipProfile.cs index 170a483..e131f82 100644 --- a/src/CMSMicroservice.WebApi/Common/Mappings/ClubMembershipProfile.cs +++ b/src/CMSMicroservice.WebApi/Common/Mappings/ClubMembershipProfile.cs @@ -1,5 +1,6 @@ using CMSMicroservice.Application.ClubMembershipCQ.Queries.GetAllClubMemberships; using CMSMicroservice.Application.ClubMembershipCQ.Queries.GetClubMembership; +using CMSMicroservice.Application.ClubMembershipCQ.Queries.GetClubMembershipHistory; using CMSMicroservice.Application.ClubMembershipCQ.Queries.GetClubStatistics; using CMSMicroservice.Protobuf.Protos.ClubMembership; using Google.Protobuf.WellKnownTypes; @@ -112,6 +113,55 @@ public class ClubMembershipProfile : IRegister NetChange = t.NetChange }) } }); + + // GetClubMembershipHistory + config.NewConfig() + .MapWith(src => new GetClubMembershipHistoryQuery + { + PaginationState = src.PaginationState != null + ? new Application.Common.Models.PaginationState + { + PageNumber = src.PaginationState.PageNumber > 0 ? src.PaginationState.PageNumber : 1, + PageSize = src.PaginationState.PageSize > 0 ? src.PaginationState.PageSize : 20 + } + : null, + SortBy = src.HasSortBy ? src.SortBy : null, + Filter = src.Filter != null ? new GetClubMembershipHistoryFilter + { + UserId = src.Filter.HasUserId ? src.Filter.UserId : null, + ClubMembershipId = src.Filter.HasClubMembershipId ? src.Filter.ClubMembershipId : null, + Action = src.Filter.HasAction ? (Domain.Enums.ClubMembershipAction)src.Filter.Action : null, + CreatedFrom = src.Filter.CreatedFrom?.ToDateTime(), + CreatedTo = src.Filter.CreatedTo?.ToDateTime() + } : null + }); + + config.NewConfig() + .MapWith(src => new GetClubMembershipHistoryResponse + { + MetaData = new CMSMicroservice.Protobuf.Protos.MetaData + { + CurrentPage = src.MetaData.CurrentPage, + PageSize = src.MetaData.PageSize, + TotalCount = src.MetaData.TotalCount, + TotalPage = src.MetaData.TotalPage + }, + Models = { src.Models.Select(m => new ClubMembershipHistoryModel + { + Id = m.Id, + ClubMembershipId = m.ClubMembershipId, + UserId = m.UserId, + UserName = m.UserName ?? string.Empty, + OldIsActive = m.OldIsActive, + NewIsActive = m.NewIsActive, + OldInitialContribution = m.OldInitialContribution, + NewInitialContribution = m.NewInitialContribution, + Action = (int)m.Action, + PerformedBy = m.PerformedBy ?? string.Empty, + Reason = m.Reason ?? string.Empty, + CreatedAt = Timestamp.FromDateTimeOffset(m.Created) + }) } + }); } private static ClubMembershipModel MapToModel(GetAllClubMembershipsResponseModel src) @@ -121,15 +171,15 @@ public class ClubMembershipProfile : IRegister Id = src.Id, UserId = src.UserId, UserName = src.UserName ?? string.Empty, - PackageId = 0, // Not available in current entity - PackageName = string.Empty, // Not available in current entity - ActivationCode = string.Empty, // Not available in current entity + PackageId = src.PackageId, + PackageName = src.PackageName ?? string.Empty, + ActivationCode = string.Empty, ActivatedAt = src.ActivatedAt.HasValue ? Timestamp.FromDateTime(DateTime.SpecifyKind(src.ActivatedAt.Value, DateTimeKind.Utc)) : null, - ExpiresAt = null, // Not available in current entity + ExpiresAt = null, IsActive = src.IsActive, - IsExpired = false, // Calculate based on ExpiresAt if available + IsExpired = false, Created = Timestamp.FromDateTime(src.Created.UtcDateTime) }; } diff --git a/src/CMSMicroservice.WebApi/Common/Mappings/PaymentTransactionProfile.cs b/src/CMSMicroservice.WebApi/Common/Mappings/PaymentTransactionProfile.cs new file mode 100644 index 0000000..1a4cf8d --- /dev/null +++ b/src/CMSMicroservice.WebApi/Common/Mappings/PaymentTransactionProfile.cs @@ -0,0 +1,102 @@ +using CMSMicroservice.Application.PaymentTransactionCQ.Queries.GetAllPaymentTransactionByFilter; +using CMSMicroservice.Application.PaymentTransactionCQ.Queries.GetPaymentTransactionSummary; +using CMSMicroservice.Protobuf.Protos.PaymentTransaction; +using Google.Protobuf.WellKnownTypes; +using Mapster; + +namespace CMSMicroservice.WebApi.Common.Mappings; + +public class PaymentTransactionProfile : IRegister +{ + public void Register(TypeAdapterConfig config) + { + config.NewConfig() + .MapWith(MapListQuery); + + config.NewConfig() + .MapWith(MapListResponse); + + config.NewConfig() + .MapWith(src => new GetPaymentTransactionSummaryQuery + { + Filter = MapFilter(src.Filter) + }); + + config.NewConfig() + .MapWith(src => new GetPaymentTransactionSummaryResponse + { + TotalCount = src.TotalCount, + TotalAmount = src.TotalAmount, + SuccessfulCount = src.SuccessfulCount, + PendingCount = src.PendingCount + }); + } + + private static GetAllPaymentTransactionByFilterQuery MapListQuery(GetAllPaymentTransactionByFilterRequest src) => + new() + { + PaginationState = MapPagination(src.PaginationState), + SortBy = src.HasSortBy ? src.SortBy : null, + Filter = MapFilter(src.Filter) + }; + + private static GetAllPaymentTransactionByFilterResponse MapListResponse(GetAllPaymentTransactionByFilterResponseDto src) => + new() + { + MetaData = MapMeta(src.MetaData), + Models = { src.Models?.Select(MapModel) ?? [] } + }; + + private static GetAllPaymentTransactionByFilterFilter? MapFilter(GetAllPaymentTransactionByFilterFilter? src) + { + if (src == null) return null; + return new GetAllPaymentTransactionByFilterFilter + { + UserId = src.HasUserId ? src.UserId : null, + Mobile = src.HasMobile ? src.Mobile : null, + GatewayProvider = src.HasGatewayProvider ? src.GatewayProvider : null, + PaymentStatus = src.HasPaymentStatus ? src.PaymentStatus : null, + Authority = src.HasAuthority ? src.Authority : null, + RefId = src.HasRefId ? src.RefId : null, + OrderId = src.HasOrderId ? src.OrderId : null, + CreatedFrom = src.CreatedFrom?.ToDateTime(), + CreatedTo = src.CreatedTo?.ToDateTime() + }; + } + + private static PaymentTransactionModel MapModel(GetAllPaymentTransactionByFilterResponseModel m) => + new() + { + Id = m.Id, + UserId = m.UserId ?? 0, + Mobile = m.Mobile ?? string.Empty, + GatewayProvider = m.GatewayProvider, + Amount = m.Amount, + Authority = m.Authority ?? string.Empty, + PaymentStatus = m.PaymentStatus, + VerificationStatusCode = m.VerificationStatusCode, + VerificationStatusMessage = m.VerificationStatusMessage ?? string.Empty, + RefId = m.RefId ?? string.Empty, + CardPan = m.CardPan ?? string.Empty, + OrderId = m.OrderId ?? string.Empty, + TransactionId = m.TransactionId, + Description = m.Description ?? string.Empty, + CreatedAt = Timestamp.FromDateTimeOffset(m.Created) + }; + + private static Application.Common.Models.PaginationState? MapPagination(CMSMicroservice.Protobuf.Protos.PaginationState? ps) => + ps == null ? null : new Application.Common.Models.PaginationState + { + PageNumber = ps.PageNumber > 0 ? ps.PageNumber : 1, + PageSize = ps.PageSize > 0 ? ps.PageSize : 20 + }; + + private static CMSMicroservice.Protobuf.Protos.MetaData MapMeta(Application.Common.Models.MetaData meta) => + new() + { + CurrentPage = meta.CurrentPage, + PageSize = meta.PageSize, + TotalCount = meta.TotalCount, + TotalPage = meta.TotalPage + }; +} diff --git a/src/CMSMicroservice.WebApi/Common/Mappings/UserPackagePurchaseProfile.cs b/src/CMSMicroservice.WebApi/Common/Mappings/UserPackagePurchaseProfile.cs new file mode 100644 index 0000000..33202a3 --- /dev/null +++ b/src/CMSMicroservice.WebApi/Common/Mappings/UserPackagePurchaseProfile.cs @@ -0,0 +1,83 @@ +using CMSMicroservice.Application.UserPackagePurchaseCQ.Queries.GetAllUserPackagePurchaseByFilter; +using CMSMicroservice.Application.UserPackagePurchaseCQ.Queries.GetUserPackagePurchaseSummary; +using CMSMicroservice.Protobuf.Protos.UserPackagePurchase; +using Google.Protobuf.WellKnownTypes; +using Mapster; + +namespace CMSMicroservice.WebApi.Common.Mappings; + +public class UserPackagePurchaseProfile : IRegister +{ + public void Register(TypeAdapterConfig config) + { + config.NewConfig() + .MapWith(src => new GetAllUserPackagePurchaseByFilterQuery + { + PaginationState = MapPagination(src.PaginationState), + SortBy = src.HasSortBy ? src.SortBy : null, + Filter = MapFilter(src.Filter) + }); + + config.NewConfig() + .MapWith(src => new GetAllUserPackagePurchaseByFilterResponse + { + MetaData = MapMeta(src.MetaData), + Models = { src.Models?.Select(m => new UserPackagePurchaseModel + { + Id = m.Id, + UserId = m.UserId, + UserName = m.UserName, + UserMobile = m.UserMobile, + PackageId = m.PackageId, + PackageName = m.PackageName, + PurchaseMethod = (int)m.PurchaseMethod, + PurchasedAt = Timestamp.FromDateTime(DateTime.SpecifyKind(m.PurchasedAt, DateTimeKind.Utc)), + Amount = m.Amount, + OrderId = m.OrderId, + TransactionId = m.TransactionId, + CreatedAt = Timestamp.FromDateTimeOffset(m.Created) + }) ?? [] } + }); + + config.NewConfig() + .MapWith(src => new GetUserPackagePurchaseSummaryQuery { Filter = MapFilter(src.Filter) }); + + config.NewConfig() + .MapWith(src => new GetUserPackagePurchaseSummaryResponse + { + TotalCount = src.TotalCount, + TotalAmount = src.TotalAmount + }); + } + + private static GetAllUserPackagePurchaseByFilterFilter? MapFilter(GetAllUserPackagePurchaseByFilterFilter? src) + { + if (src == null) return null; + return new GetAllUserPackagePurchaseByFilterFilter + { + UserId = src.HasUserId ? src.UserId : null, + PackageId = src.HasPackageId ? src.PackageId : null, + PurchaseMethod = src.HasPurchaseMethod ? (Domain.Enums.PackagePurchaseMethod)src.PurchaseMethod : null, + PurchasedFrom = src.PurchasedFrom?.ToDateTime(), + PurchasedTo = src.PurchasedTo?.ToDateTime(), + MinAmount = src.HasMinAmount ? src.MinAmount : null, + MaxAmount = src.HasMaxAmount ? src.MaxAmount : null + }; + } + + private static Application.Common.Models.PaginationState? MapPagination(CMSMicroservice.Protobuf.Protos.PaginationState? ps) => + ps == null ? null : new Application.Common.Models.PaginationState + { + PageNumber = ps.PageNumber > 0 ? ps.PageNumber : 1, + PageSize = ps.PageSize > 0 ? ps.PageSize : 20 + }; + + private static CMSMicroservice.Protobuf.Protos.MetaData MapMeta(Application.Common.Models.MetaData meta) => + new() + { + CurrentPage = meta.CurrentPage, + PageSize = meta.PageSize, + TotalCount = meta.TotalCount, + TotalPage = meta.TotalPage + }; +} diff --git a/src/CMSMicroservice.WebApi/Services/ClubMembershipCycleHistoryService.cs b/src/CMSMicroservice.WebApi/Services/ClubMembershipCycleHistoryService.cs new file mode 100644 index 0000000..0db9ae3 --- /dev/null +++ b/src/CMSMicroservice.WebApi/Services/ClubMembershipCycleHistoryService.cs @@ -0,0 +1,16 @@ +using CMSMicroservice.Protobuf.Protos.ClubMembershipCycleHistory; +using CMSMicroservice.WebApi.Common.Services; +using CMSMicroservice.Application.ClubMembershipCycleHistoryCQ.Queries.GetAllClubMembershipCycleHistoryByFilter; + +namespace CMSMicroservice.WebApi.Services; + +public class ClubMembershipCycleHistoryService : ClubMembershipCycleHistoryContract.ClubMembershipCycleHistoryContractBase +{ + private readonly IDispatchRequestToCQRS _dispatch; + + public ClubMembershipCycleHistoryService(IDispatchRequestToCQRS dispatch) => _dispatch = dispatch; + + public override Task GetAllClubMembershipCycleHistoryByFilter( + GetAllClubMembershipCycleHistoryByFilterRequest request, ServerCallContext context) => + _dispatch.Handle(request, context); +} diff --git a/src/CMSMicroservice.WebApi/Services/ClubMembershipCycleService.cs b/src/CMSMicroservice.WebApi/Services/ClubMembershipCycleService.cs new file mode 100644 index 0000000..0cfc25a --- /dev/null +++ b/src/CMSMicroservice.WebApi/Services/ClubMembershipCycleService.cs @@ -0,0 +1,21 @@ +using CMSMicroservice.Protobuf.Protos.ClubMembershipCycle; +using CMSMicroservice.WebApi.Common.Services; +using CMSMicroservice.Application.ClubMembershipCycleCQ.Queries.GetAllClubMembershipCycleByFilter; +using CMSMicroservice.Application.ClubMembershipCycleCQ.Queries.GetClubMembershipCycleSummary; + +namespace CMSMicroservice.WebApi.Services; + +public class ClubMembershipCycleService : ClubMembershipCycleContract.ClubMembershipCycleContractBase +{ + private readonly IDispatchRequestToCQRS _dispatch; + + public ClubMembershipCycleService(IDispatchRequestToCQRS dispatch) => _dispatch = dispatch; + + public override Task GetAllClubMembershipCycleByFilter( + GetAllClubMembershipCycleByFilterRequest request, ServerCallContext context) => + _dispatch.Handle(request, context); + + public override Task GetClubMembershipCycleSummary( + GetClubMembershipCycleSummaryRequest request, ServerCallContext context) => + _dispatch.Handle(request, context); +} diff --git a/src/CMSMicroservice.WebApi/Services/PaymentTransactionService.cs b/src/CMSMicroservice.WebApi/Services/PaymentTransactionService.cs new file mode 100644 index 0000000..509b4e2 --- /dev/null +++ b/src/CMSMicroservice.WebApi/Services/PaymentTransactionService.cs @@ -0,0 +1,21 @@ +using CMSMicroservice.Protobuf.Protos.PaymentTransaction; +using CMSMicroservice.WebApi.Common.Services; +using CMSMicroservice.Application.PaymentTransactionCQ.Queries.GetAllPaymentTransactionByFilter; +using CMSMicroservice.Application.PaymentTransactionCQ.Queries.GetPaymentTransactionSummary; + +namespace CMSMicroservice.WebApi.Services; + +public class PaymentTransactionService : PaymentTransactionContract.PaymentTransactionContractBase +{ + private readonly IDispatchRequestToCQRS _dispatch; + + public PaymentTransactionService(IDispatchRequestToCQRS dispatch) => _dispatch = dispatch; + + public override Task GetAllPaymentTransactionByFilter( + GetAllPaymentTransactionByFilterRequest request, ServerCallContext context) => + _dispatch.Handle(request, context); + + public override Task GetPaymentTransactionSummary( + GetPaymentTransactionSummaryRequest request, ServerCallContext context) => + _dispatch.Handle(request, context); +} diff --git a/src/CMSMicroservice.WebApi/Services/UserPackagePurchaseService.cs b/src/CMSMicroservice.WebApi/Services/UserPackagePurchaseService.cs new file mode 100644 index 0000000..239d7c8 --- /dev/null +++ b/src/CMSMicroservice.WebApi/Services/UserPackagePurchaseService.cs @@ -0,0 +1,21 @@ +using CMSMicroservice.Protobuf.Protos.UserPackagePurchase; +using CMSMicroservice.WebApi.Common.Services; +using CMSMicroservice.Application.UserPackagePurchaseCQ.Queries.GetAllUserPackagePurchaseByFilter; +using CMSMicroservice.Application.UserPackagePurchaseCQ.Queries.GetUserPackagePurchaseSummary; + +namespace CMSMicroservice.WebApi.Services; + +public class UserPackagePurchaseService : UserPackagePurchaseContract.UserPackagePurchaseContractBase +{ + private readonly IDispatchRequestToCQRS _dispatch; + + public UserPackagePurchaseService(IDispatchRequestToCQRS dispatch) => _dispatch = dispatch; + + public override Task GetAllUserPackagePurchaseByFilter( + GetAllUserPackagePurchaseByFilterRequest request, ServerCallContext context) => + _dispatch.Handle(request, context); + + public override Task GetUserPackagePurchaseSummary( + GetUserPackagePurchaseSummaryRequest request, ServerCallContext context) => + _dispatch.Handle(request, context); +} From db20d95b43737a9692e737d780280f195175b6e1 Mon Sep 17 00:00:00 2001 From: masoodafar-web Date: Mon, 22 Jun 2026 22:36:33 +0330 Subject: [PATCH 2/8] refactor(mappings): update filter mappings for club membership and payment transaction profiles - Renamed filter types in ClubMembershipCycleHistoryProfile, ClubMembershipCycleProfile, PaymentTransactionProfile, UserPackagePurchaseProfile to improve clarity and consistency. - Adjusted mapping methods to utilize new filter type aliases for better readability and maintainability. - Ensured all relevant profiles are aligned with the updated filter structures. --- .../Common/Mappings/ClubMembershipCycleHistoryProfile.cs | 6 ++++-- .../Common/Mappings/ClubMembershipCycleProfile.cs | 6 ++++-- .../Common/Mappings/ClubMembershipProfile.cs | 3 ++- .../Common/Mappings/PaymentTransactionProfile.cs | 6 ++++-- .../Common/Mappings/UserPackagePurchaseProfile.cs | 6 ++++-- 5 files changed, 18 insertions(+), 9 deletions(-) diff --git a/src/CMSMicroservice.WebApi/Common/Mappings/ClubMembershipCycleHistoryProfile.cs b/src/CMSMicroservice.WebApi/Common/Mappings/ClubMembershipCycleHistoryProfile.cs index eec483a..7a0433a 100644 --- a/src/CMSMicroservice.WebApi/Common/Mappings/ClubMembershipCycleHistoryProfile.cs +++ b/src/CMSMicroservice.WebApi/Common/Mappings/ClubMembershipCycleHistoryProfile.cs @@ -2,6 +2,8 @@ using CMSMicroservice.Application.ClubMembershipCycleHistoryCQ.Queries.GetAllClu using CMSMicroservice.Protobuf.Protos.ClubMembershipCycleHistory; using Google.Protobuf.WellKnownTypes; using Mapster; +using AppFilter = CMSMicroservice.Application.ClubMembershipCycleHistoryCQ.Queries.GetAllClubMembershipCycleHistoryByFilter.GetAllClubMembershipCycleHistoryByFilterFilter; +using ProtoFilter = CMSMicroservice.Protobuf.Protos.ClubMembershipCycleHistory.GetAllClubMembershipCycleHistoryByFilterFilter; namespace CMSMicroservice.WebApi.Common.Mappings; @@ -25,10 +27,10 @@ public class ClubMembershipCycleHistoryProfile : IRegister }); } - private static GetAllClubMembershipCycleHistoryByFilterFilter? MapFilter(GetAllClubMembershipCycleHistoryByFilterFilter? src) + private static AppFilter? MapFilter(ProtoFilter? src) { if (src == null) return null; - return new GetAllClubMembershipCycleHistoryByFilterFilter + return new AppFilter { UserId = src.HasUserId ? src.UserId : null, ClubMembershipCycleId = src.HasClubMembershipCycleId ? src.ClubMembershipCycleId : null, diff --git a/src/CMSMicroservice.WebApi/Common/Mappings/ClubMembershipCycleProfile.cs b/src/CMSMicroservice.WebApi/Common/Mappings/ClubMembershipCycleProfile.cs index 10f961d..c866541 100644 --- a/src/CMSMicroservice.WebApi/Common/Mappings/ClubMembershipCycleProfile.cs +++ b/src/CMSMicroservice.WebApi/Common/Mappings/ClubMembershipCycleProfile.cs @@ -3,6 +3,8 @@ using CMSMicroservice.Application.ClubMembershipCycleCQ.Queries.GetClubMembershi using CMSMicroservice.Protobuf.Protos.ClubMembershipCycle; using Google.Protobuf.WellKnownTypes; using Mapster; +using AppFilter = CMSMicroservice.Application.ClubMembershipCycleCQ.Queries.GetAllClubMembershipCycleByFilter.GetAllClubMembershipCycleByFilterFilter; +using ProtoFilter = CMSMicroservice.Protobuf.Protos.ClubMembershipCycle.GetAllClubMembershipCycleByFilterFilter; namespace CMSMicroservice.WebApi.Common.Mappings; @@ -37,10 +39,10 @@ public class ClubMembershipCycleProfile : IRegister }); } - private static GetAllClubMembershipCycleByFilterFilter? MapFilter(GetAllClubMembershipCycleByFilterFilter? src) + private static AppFilter? MapFilter(ProtoFilter? src) { if (src == null) return null; - return new GetAllClubMembershipCycleByFilterFilter + return new AppFilter { UserId = src.HasUserId ? src.UserId : null, IsCurrentCycle = src.HasIsCurrentCycle ? src.IsCurrentCycle : null, diff --git a/src/CMSMicroservice.WebApi/Common/Mappings/ClubMembershipProfile.cs b/src/CMSMicroservice.WebApi/Common/Mappings/ClubMembershipProfile.cs index e131f82..f7ba6d5 100644 --- a/src/CMSMicroservice.WebApi/Common/Mappings/ClubMembershipProfile.cs +++ b/src/CMSMicroservice.WebApi/Common/Mappings/ClubMembershipProfile.cs @@ -2,6 +2,7 @@ using CMSMicroservice.Application.ClubMembershipCQ.Queries.GetAllClubMemberships using CMSMicroservice.Application.ClubMembershipCQ.Queries.GetClubMembership; using CMSMicroservice.Application.ClubMembershipCQ.Queries.GetClubMembershipHistory; using CMSMicroservice.Application.ClubMembershipCQ.Queries.GetClubStatistics; +using AppHistoryFilter = CMSMicroservice.Application.ClubMembershipCQ.Queries.GetClubMembershipHistory.GetClubMembershipHistoryFilter; using CMSMicroservice.Protobuf.Protos.ClubMembership; using Google.Protobuf.WellKnownTypes; using Mapster; @@ -126,7 +127,7 @@ public class ClubMembershipProfile : IRegister } : null, SortBy = src.HasSortBy ? src.SortBy : null, - Filter = src.Filter != null ? new GetClubMembershipHistoryFilter + Filter = src.Filter != null ? new AppHistoryFilter { UserId = src.Filter.HasUserId ? src.Filter.UserId : null, ClubMembershipId = src.Filter.HasClubMembershipId ? src.Filter.ClubMembershipId : null, diff --git a/src/CMSMicroservice.WebApi/Common/Mappings/PaymentTransactionProfile.cs b/src/CMSMicroservice.WebApi/Common/Mappings/PaymentTransactionProfile.cs index 1a4cf8d..c7dffd7 100644 --- a/src/CMSMicroservice.WebApi/Common/Mappings/PaymentTransactionProfile.cs +++ b/src/CMSMicroservice.WebApi/Common/Mappings/PaymentTransactionProfile.cs @@ -3,6 +3,8 @@ using CMSMicroservice.Application.PaymentTransactionCQ.Queries.GetPaymentTransac using CMSMicroservice.Protobuf.Protos.PaymentTransaction; using Google.Protobuf.WellKnownTypes; using Mapster; +using AppFilter = CMSMicroservice.Application.PaymentTransactionCQ.Queries.GetAllPaymentTransactionByFilter.GetAllPaymentTransactionByFilterFilter; +using ProtoFilter = CMSMicroservice.Protobuf.Protos.PaymentTransaction.GetAllPaymentTransactionByFilterFilter; namespace CMSMicroservice.WebApi.Common.Mappings; @@ -47,10 +49,10 @@ public class PaymentTransactionProfile : IRegister Models = { src.Models?.Select(MapModel) ?? [] } }; - private static GetAllPaymentTransactionByFilterFilter? MapFilter(GetAllPaymentTransactionByFilterFilter? src) + private static AppFilter? MapFilter(ProtoFilter? src) { if (src == null) return null; - return new GetAllPaymentTransactionByFilterFilter + return new AppFilter { UserId = src.HasUserId ? src.UserId : null, Mobile = src.HasMobile ? src.Mobile : null, diff --git a/src/CMSMicroservice.WebApi/Common/Mappings/UserPackagePurchaseProfile.cs b/src/CMSMicroservice.WebApi/Common/Mappings/UserPackagePurchaseProfile.cs index 33202a3..87543be 100644 --- a/src/CMSMicroservice.WebApi/Common/Mappings/UserPackagePurchaseProfile.cs +++ b/src/CMSMicroservice.WebApi/Common/Mappings/UserPackagePurchaseProfile.cs @@ -3,6 +3,8 @@ using CMSMicroservice.Application.UserPackagePurchaseCQ.Queries.GetUserPackagePu using CMSMicroservice.Protobuf.Protos.UserPackagePurchase; using Google.Protobuf.WellKnownTypes; using Mapster; +using AppFilter = CMSMicroservice.Application.UserPackagePurchaseCQ.Queries.GetAllUserPackagePurchaseByFilter.GetAllUserPackagePurchaseByFilterFilter; +using ProtoFilter = CMSMicroservice.Protobuf.Protos.UserPackagePurchase.GetAllUserPackagePurchaseByFilterFilter; namespace CMSMicroservice.WebApi.Common.Mappings; @@ -50,10 +52,10 @@ public class UserPackagePurchaseProfile : IRegister }); } - private static GetAllUserPackagePurchaseByFilterFilter? MapFilter(GetAllUserPackagePurchaseByFilterFilter? src) + private static AppFilter? MapFilter(ProtoFilter? src) { if (src == null) return null; - return new GetAllUserPackagePurchaseByFilterFilter + return new AppFilter { UserId = src.HasUserId ? src.UserId : null, PackageId = src.HasPackageId ? src.PackageId : null, From 46ac1d817e47213c76c8217face2366626ba0157 Mon Sep 17 00:00:00 2001 From: masoodafar-web Date: Mon, 22 Jun 2026 22:54:25 +0330 Subject: [PATCH 3/8] refactor(mappings): streamline mapping configurations for user package purchases and payment transactions - Updated mapping configurations in UserPackagePurchaseProfile and PaymentTransactionProfile to utilize new Protobuf definitions for improved clarity and consistency. - Simplified filter mappings and removed redundant mapping methods to enhance maintainability. - Ensured alignment of all relevant profiles with the latest filter structures and DTOs. --- .../ClubMembershipCycleHistoryProfile.cs | 106 +++++--------- .../Mappings/ClubMembershipCycleProfile.cs | 123 ++++++---------- .../Common/Mappings/ClubMembershipProfile.cs | 106 ++++++-------- .../Mappings/PaymentTransactionProfile.cs | 136 ++++++------------ .../Mappings/UserPackagePurchaseProfile.cs | 110 +++++--------- 5 files changed, 207 insertions(+), 374 deletions(-) diff --git a/src/CMSMicroservice.WebApi/Common/Mappings/ClubMembershipCycleHistoryProfile.cs b/src/CMSMicroservice.WebApi/Common/Mappings/ClubMembershipCycleHistoryProfile.cs index 7a0433a..8f6b32d 100644 --- a/src/CMSMicroservice.WebApi/Common/Mappings/ClubMembershipCycleHistoryProfile.cs +++ b/src/CMSMicroservice.WebApi/Common/Mappings/ClubMembershipCycleHistoryProfile.cs @@ -1,9 +1,8 @@ -using CMSMicroservice.Application.ClubMembershipCycleHistoryCQ.Queries.GetAllClubMembershipCycleHistoryByFilter; -using CMSMicroservice.Protobuf.Protos.ClubMembershipCycleHistory; using Google.Protobuf.WellKnownTypes; +using CMSMicroservice.Domain.Enums; using Mapster; -using AppFilter = CMSMicroservice.Application.ClubMembershipCycleHistoryCQ.Queries.GetAllClubMembershipCycleHistoryByFilter.GetAllClubMembershipCycleHistoryByFilterFilter; -using ProtoFilter = CMSMicroservice.Protobuf.Protos.ClubMembershipCycleHistory.GetAllClubMembershipCycleHistoryByFilterFilter; +using AppHistory = CMSMicroservice.Application.ClubMembershipCycleHistoryCQ.Queries.GetAllClubMembershipCycleHistoryByFilter; +using ProtoHistory = CMSMicroservice.Protobuf.Protos.ClubMembershipCycleHistory; namespace CMSMicroservice.WebApi.Common.Mappings; @@ -11,73 +10,38 @@ public class ClubMembershipCycleHistoryProfile : IRegister { public void Register(TypeAdapterConfig config) { - config.NewConfig() - .MapWith(src => new GetAllClubMembershipCycleHistoryByFilterQuery - { - PaginationState = MapPagination(src.PaginationState), - SortBy = src.HasSortBy ? src.SortBy : null, - Filter = MapFilter(src.Filter) - }); + config.NewConfig() + .Map(dest => dest.PaginationState, src => src.PaginationState) + .Map(dest => dest.SortBy, src => src.SortBy) + .Map(dest => dest.Filter, src => src.Filter); - config.NewConfig() - .MapWith(src => new GetAllClubMembershipCycleHistoryByFilterResponse - { - MetaData = MapMeta(src.MetaData), - Models = { src.Models?.Select(MapModel) ?? [] } - }); + config.NewConfig() + .Map(dest => dest.UserId, src => src.UserId) + .Map(dest => dest.ClubMembershipCycleId, src => src.ClubMembershipCycleId) + .Map(dest => dest.CycleNumber, src => src.CycleNumber) + .Map(dest => dest.Action, src => src.Action == null ? null : (ClubMembershipCycleAction?)src.Action) + .Map(dest => dest.CreatedFrom, src => src.CreatedFrom != null ? src.CreatedFrom.ToDateTime() : (DateTime?)null) + .Map(dest => dest.CreatedTo, src => src.CreatedTo != null ? src.CreatedTo.ToDateTime() : (DateTime?)null); + + config.NewConfig() + .Map(dest => dest.MetaData, src => src.MetaData) + .Map(dest => dest.Models, src => src.Models); + + config.NewConfig() + .Map(dest => dest.Id, src => src.Id) + .Map(dest => dest.ClubMembershipCycleId, src => src.ClubMembershipCycleId) + .Map(dest => dest.UserId, src => src.UserId) + .Map(dest => dest.UserName, src => src.UserName) + .Map(dest => dest.CycleNumber, src => src.CycleNumber) + .Map(dest => dest.OldIsCurrentCycle, src => src.OldIsCurrentCycle) + .Map(dest => dest.NewIsCurrentCycle, src => src.NewIsCurrentCycle) + .Map(dest => dest.OldMagicStartedAt, src => src.OldMagicStartedAt) + .Map(dest => dest.NewMagicStartedAt, src => src.NewMagicStartedAt) + .Map(dest => dest.OldMagicCompletedAt, src => src.OldMagicCompletedAt) + .Map(dest => dest.NewMagicCompletedAt, src => src.NewMagicCompletedAt) + .Map(dest => dest.Action, src => (int)src.Action) + .Map(dest => dest.PerformedBy, src => src.PerformedBy ?? string.Empty) + .Map(dest => dest.Reason, src => src.Reason ?? string.Empty) + .Map(dest => dest.CreatedAt, src => Timestamp.FromDateTimeOffset(src.Created)); } - - private static AppFilter? MapFilter(ProtoFilter? src) - { - if (src == null) return null; - return new AppFilter - { - UserId = src.HasUserId ? src.UserId : null, - ClubMembershipCycleId = src.HasClubMembershipCycleId ? src.ClubMembershipCycleId : null, - CycleNumber = src.HasCycleNumber ? src.CycleNumber : null, - Action = src.HasAction ? (Domain.Enums.ClubMembershipCycleAction)src.Action : null, - CreatedFrom = src.CreatedFrom?.ToDateTime(), - CreatedTo = src.CreatedTo?.ToDateTime() - }; - } - - private static ClubMembershipCycleHistoryModel MapModel(GetAllClubMembershipCycleHistoryByFilterResponseModel m) => - new() - { - Id = m.Id, - ClubMembershipCycleId = m.ClubMembershipCycleId, - UserId = m.UserId, - UserName = m.UserName, - CycleNumber = m.CycleNumber, - OldIsCurrentCycle = m.OldIsCurrentCycle, - NewIsCurrentCycle = m.NewIsCurrentCycle, - OldMagicStartedAt = m.OldMagicStartedAt.HasValue - ? Timestamp.FromDateTime(DateTime.SpecifyKind(m.OldMagicStartedAt.Value, DateTimeKind.Utc)) : null, - NewMagicStartedAt = m.NewMagicStartedAt.HasValue - ? Timestamp.FromDateTime(DateTime.SpecifyKind(m.NewMagicStartedAt.Value, DateTimeKind.Utc)) : null, - OldMagicCompletedAt = m.OldMagicCompletedAt.HasValue - ? Timestamp.FromDateTime(DateTime.SpecifyKind(m.OldMagicCompletedAt.Value, DateTimeKind.Utc)) : null, - NewMagicCompletedAt = m.NewMagicCompletedAt.HasValue - ? Timestamp.FromDateTime(DateTime.SpecifyKind(m.NewMagicCompletedAt.Value, DateTimeKind.Utc)) : null, - Action = (int)m.Action, - PerformedBy = m.PerformedBy ?? string.Empty, - Reason = m.Reason ?? string.Empty, - CreatedAt = Timestamp.FromDateTimeOffset(m.Created) - }; - - private static Application.Common.Models.PaginationState? MapPagination(CMSMicroservice.Protobuf.Protos.PaginationState? ps) => - ps == null ? null : new Application.Common.Models.PaginationState - { - PageNumber = ps.PageNumber > 0 ? ps.PageNumber : 1, - PageSize = ps.PageSize > 0 ? ps.PageSize : 20 - }; - - private static CMSMicroservice.Protobuf.Protos.MetaData MapMeta(Application.Common.Models.MetaData meta) => - new() - { - CurrentPage = meta.CurrentPage, - PageSize = meta.PageSize, - TotalCount = meta.TotalCount, - TotalPage = meta.TotalPage - }; } diff --git a/src/CMSMicroservice.WebApi/Common/Mappings/ClubMembershipCycleProfile.cs b/src/CMSMicroservice.WebApi/Common/Mappings/ClubMembershipCycleProfile.cs index c866541..0d0fb48 100644 --- a/src/CMSMicroservice.WebApi/Common/Mappings/ClubMembershipCycleProfile.cs +++ b/src/CMSMicroservice.WebApi/Common/Mappings/ClubMembershipCycleProfile.cs @@ -1,10 +1,9 @@ -using CMSMicroservice.Application.ClubMembershipCycleCQ.Queries.GetAllClubMembershipCycleByFilter; -using CMSMicroservice.Application.ClubMembershipCycleCQ.Queries.GetClubMembershipCycleSummary; -using CMSMicroservice.Protobuf.Protos.ClubMembershipCycle; using Google.Protobuf.WellKnownTypes; +using CMSMicroservice.Domain.Enums; using Mapster; -using AppFilter = CMSMicroservice.Application.ClubMembershipCycleCQ.Queries.GetAllClubMembershipCycleByFilter.GetAllClubMembershipCycleByFilterFilter; -using ProtoFilter = CMSMicroservice.Protobuf.Protos.ClubMembershipCycle.GetAllClubMembershipCycleByFilterFilter; +using AppCycle = CMSMicroservice.Application.ClubMembershipCycleCQ.Queries.GetAllClubMembershipCycleByFilter; +using AppCycleSummary = CMSMicroservice.Application.ClubMembershipCycleCQ.Queries.GetClubMembershipCycleSummary; +using ProtoCycle = CMSMicroservice.Protobuf.Protos.ClubMembershipCycle; namespace CMSMicroservice.WebApi.Common.Mappings; @@ -12,83 +11,47 @@ public class ClubMembershipCycleProfile : IRegister { public void Register(TypeAdapterConfig config) { - config.NewConfig() - .MapWith(src => new GetAllClubMembershipCycleByFilterQuery - { - PaginationState = MapPagination(src.PaginationState), - SortBy = src.HasSortBy ? src.SortBy : null, - Filter = MapFilter(src.Filter) - }); + config.NewConfig() + .Map(dest => dest.PaginationState, src => src.PaginationState) + .Map(dest => dest.SortBy, src => src.SortBy) + .Map(dest => dest.Filter, src => src.Filter); - config.NewConfig() - .MapWith(src => new GetAllClubMembershipCycleByFilterResponse - { - MetaData = MapMeta(src.MetaData), - Models = { src.Models?.Select(MapModel) ?? [] } - }); + config.NewConfig() + .Map(dest => dest.UserId, src => src.UserId) + .Map(dest => dest.IsCurrentCycle, src => src.IsCurrentCycle) + .Map(dest => dest.PackageId, src => src.PackageId) + .Map(dest => dest.CycleNumber, src => src.CycleNumber) + .Map(dest => dest.PurchaseMethod, src => src.PurchaseMethod == null ? null : (PackagePurchaseMethod?)src.PurchaseMethod) + .Map(dest => dest.MagicState, src => src.MagicState) + .Map(dest => dest.PackagePurchasedFrom, src => src.PackagePurchasedFrom != null ? src.PackagePurchasedFrom.ToDateTime() : (DateTime?)null) + .Map(dest => dest.PackagePurchasedTo, src => src.PackagePurchasedTo != null ? src.PackagePurchasedTo.ToDateTime() : (DateTime?)null); - config.NewConfig() - .MapWith(src => new GetClubMembershipCycleSummaryQuery { Filter = MapFilter(src.Filter) }); + config.NewConfig() + .Map(dest => dest.MetaData, src => src.MetaData) + .Map(dest => dest.Models, src => src.Models); - config.NewConfig() - .MapWith(src => new GetClubMembershipCycleSummaryResponse - { - TotalCount = src.TotalCount, - CurrentCycleCount = src.CurrentCycleCount, - MagicActiveCount = src.MagicActiveCount - }); + config.NewConfig() + .Map(dest => dest.Id, src => src.Id) + .Map(dest => dest.UserId, src => src.UserId) + .Map(dest => dest.UserName, src => src.UserName) + .Map(dest => dest.ClubMembershipId, src => src.ClubMembershipId) + .Map(dest => dest.CycleNumber, src => src.CycleNumber) + .Map(dest => dest.PackageId, src => src.PackageId) + .Map(dest => dest.PackageName, src => src.PackageName) + .Map(dest => dest.PackageAmount, src => src.PackageAmount) + .Map(dest => dest.PurchaseMethod, src => (int)src.PurchaseMethod) + .Map(dest => dest.PackagePurchasedAt, src => Timestamp.FromDateTime(DateTime.SpecifyKind(src.PackagePurchasedAt, DateTimeKind.Utc))) + .Map(dest => dest.MagicStartedAt, src => src.MagicStartedAt) + .Map(dest => dest.MagicCompletedAt, src => src.MagicCompletedAt) + .Map(dest => dest.IsCurrentCycle, src => src.IsCurrentCycle) + .Map(dest => dest.CreatedAt, src => Timestamp.FromDateTimeOffset(src.Created)); + + config.NewConfig() + .Map(dest => dest.Filter, src => src.Filter); + + config.NewConfig() + .Map(dest => dest.TotalCount, src => src.TotalCount) + .Map(dest => dest.CurrentCycleCount, src => src.CurrentCycleCount) + .Map(dest => dest.MagicActiveCount, src => src.MagicActiveCount); } - - private static AppFilter? MapFilter(ProtoFilter? src) - { - if (src == null) return null; - return new AppFilter - { - UserId = src.HasUserId ? src.UserId : null, - IsCurrentCycle = src.HasIsCurrentCycle ? src.IsCurrentCycle : null, - PackageId = src.HasPackageId ? src.PackageId : null, - CycleNumber = src.HasCycleNumber ? src.CycleNumber : null, - PurchaseMethod = src.HasPurchaseMethod ? (Domain.Enums.PackagePurchaseMethod)src.PurchaseMethod : null, - MagicState = src.HasMagicState ? src.MagicState : null, - PackagePurchasedFrom = src.PackagePurchasedFrom?.ToDateTime(), - PackagePurchasedTo = src.PackagePurchasedTo?.ToDateTime() - }; - } - - private static ClubMembershipCycleModel MapModel(GetAllClubMembershipCycleByFilterResponseModel m) => - new() - { - Id = m.Id, - UserId = m.UserId, - UserName = m.UserName, - ClubMembershipId = m.ClubMembershipId, - CycleNumber = m.CycleNumber, - PackageId = m.PackageId, - PackageName = m.PackageName, - PackageAmount = m.PackageAmount, - PurchaseMethod = (int)m.PurchaseMethod, - PackagePurchasedAt = Timestamp.FromDateTime(DateTime.SpecifyKind(m.PackagePurchasedAt, DateTimeKind.Utc)), - MagicStartedAt = m.MagicStartedAt.HasValue - ? Timestamp.FromDateTime(DateTime.SpecifyKind(m.MagicStartedAt.Value, DateTimeKind.Utc)) : null, - MagicCompletedAt = m.MagicCompletedAt.HasValue - ? Timestamp.FromDateTime(DateTime.SpecifyKind(m.MagicCompletedAt.Value, DateTimeKind.Utc)) : null, - IsCurrentCycle = m.IsCurrentCycle, - CreatedAt = Timestamp.FromDateTimeOffset(m.Created) - }; - - private static Application.Common.Models.PaginationState? MapPagination(CMSMicroservice.Protobuf.Protos.PaginationState? ps) => - ps == null ? null : new Application.Common.Models.PaginationState - { - PageNumber = ps.PageNumber > 0 ? ps.PageNumber : 1, - PageSize = ps.PageSize > 0 ? ps.PageSize : 20 - }; - - private static CMSMicroservice.Protobuf.Protos.MetaData MapMeta(Application.Common.Models.MetaData meta) => - new() - { - CurrentPage = meta.CurrentPage, - PageSize = meta.PageSize, - TotalCount = meta.TotalCount, - TotalPage = meta.TotalPage - }; } diff --git a/src/CMSMicroservice.WebApi/Common/Mappings/ClubMembershipProfile.cs b/src/CMSMicroservice.WebApi/Common/Mappings/ClubMembershipProfile.cs index f7ba6d5..3d99bd2 100644 --- a/src/CMSMicroservice.WebApi/Common/Mappings/ClubMembershipProfile.cs +++ b/src/CMSMicroservice.WebApi/Common/Mappings/ClubMembershipProfile.cs @@ -1,9 +1,9 @@ using CMSMicroservice.Application.ClubMembershipCQ.Queries.GetAllClubMemberships; using CMSMicroservice.Application.ClubMembershipCQ.Queries.GetClubMembership; -using CMSMicroservice.Application.ClubMembershipCQ.Queries.GetClubMembershipHistory; using CMSMicroservice.Application.ClubMembershipCQ.Queries.GetClubStatistics; -using AppHistoryFilter = CMSMicroservice.Application.ClubMembershipCQ.Queries.GetClubMembershipHistory.GetClubMembershipHistoryFilter; -using CMSMicroservice.Protobuf.Protos.ClubMembership; +using CMSMicroservice.Domain.Enums; +using AppHistory = CMSMicroservice.Application.ClubMembershipCQ.Queries.GetClubMembershipHistory; +using ProtoClub = CMSMicroservice.Protobuf.Protos.ClubMembership; using Google.Protobuf.WellKnownTypes; using Mapster; using System.Linq; @@ -19,15 +19,15 @@ public class ClubMembershipProfile : IRegister // ===================== // GetClubMembershipRequest -> GetClubMembershipQuery - config.NewConfig() + config.NewConfig() .MapWith(src => new GetClubMembershipQuery { UserId = src.UserId }); // ClubMembershipDto -> GetClubMembershipResponse - config.NewConfig() - .MapWith(src => new GetClubMembershipResponse + config.NewConfig() + .MapWith(src => new ProtoClub.GetClubMembershipResponse { Id = src.Id, UserId = src.UserId, @@ -50,7 +50,7 @@ public class ClubMembershipProfile : IRegister // ===================== // GetAllClubMembershipsRequest -> GetAllClubMembershipsQuery - config.NewConfig() + config.NewConfig() .MapWith(src => new GetAllClubMembershipsQuery { PaginationState = new Application.Common.Models.PaginationState @@ -66,8 +66,8 @@ public class ClubMembershipProfile : IRegister }); // GetAllClubMembershipsResponseDto -> GetAllClubMembershipsResponse - config.NewConfig() - .MapWith(src => new GetAllClubMembershipsResponse + config.NewConfig() + .MapWith(src => new ProtoClub.GetAllClubMembershipsResponse { MetaData = new CMSMicroservice.Protobuf.Protos.MetaData { @@ -84,12 +84,12 @@ public class ClubMembershipProfile : IRegister // ===================== // GetClubStatisticsRequest -> GetClubStatisticsQuery - config.NewConfig() + config.NewConfig() .MapWith(src => new GetClubStatisticsQuery()); // GetClubStatisticsResponseDto -> GetClubStatisticsResponse - config.NewConfig() - .MapWith(src => new GetClubStatisticsResponse + config.NewConfig() + .MapWith(src => new ProtoClub.GetClubStatisticsResponse { TotalMembers = src.TotalMembers, ActiveMembers = src.ActiveMembers, @@ -99,14 +99,14 @@ public class ClubMembershipProfile : IRegister TotalRevenue = src.TotalRevenue, AverageMembershipDurationDays = src.AverageMembershipDurationDays, ExpiringSoonCount = src.ExpiringSoonCount, - PackageDistribution = { src.PackageDistribution.Select(p => new PackageLevelDistribution + PackageDistribution = { src.PackageDistribution.Select(p => new ProtoClub.PackageLevelDistribution { PackageId = p.PackageId, PackageName = p.PackageName ?? string.Empty, MemberCount = p.MemberCount, Percentage = p.Percentage }) }, - MonthlyTrend = { src.MonthlyTrend.Select(t => new MonthlyMembershipTrend + MonthlyTrend = { src.MonthlyTrend.Select(t => new ProtoClub.MonthlyMembershipTrend { Month = t.Month ?? string.Empty, Activations = t.Activations, @@ -116,58 +116,40 @@ public class ClubMembershipProfile : IRegister }); // GetClubMembershipHistory - config.NewConfig() - .MapWith(src => new GetClubMembershipHistoryQuery - { - PaginationState = src.PaginationState != null - ? new Application.Common.Models.PaginationState - { - PageNumber = src.PaginationState.PageNumber > 0 ? src.PaginationState.PageNumber : 1, - PageSize = src.PaginationState.PageSize > 0 ? src.PaginationState.PageSize : 20 - } - : null, - SortBy = src.HasSortBy ? src.SortBy : null, - Filter = src.Filter != null ? new AppHistoryFilter - { - UserId = src.Filter.HasUserId ? src.Filter.UserId : null, - ClubMembershipId = src.Filter.HasClubMembershipId ? src.Filter.ClubMembershipId : null, - Action = src.Filter.HasAction ? (Domain.Enums.ClubMembershipAction)src.Filter.Action : null, - CreatedFrom = src.Filter.CreatedFrom?.ToDateTime(), - CreatedTo = src.Filter.CreatedTo?.ToDateTime() - } : null - }); + config.NewConfig() + .Map(dest => dest.PaginationState, src => src.PaginationState) + .Map(dest => dest.SortBy, src => src.SortBy) + .Map(dest => dest.Filter, src => src.Filter); - config.NewConfig() - .MapWith(src => new GetClubMembershipHistoryResponse - { - MetaData = new CMSMicroservice.Protobuf.Protos.MetaData - { - CurrentPage = src.MetaData.CurrentPage, - PageSize = src.MetaData.PageSize, - TotalCount = src.MetaData.TotalCount, - TotalPage = src.MetaData.TotalPage - }, - Models = { src.Models.Select(m => new ClubMembershipHistoryModel - { - Id = m.Id, - ClubMembershipId = m.ClubMembershipId, - UserId = m.UserId, - UserName = m.UserName ?? string.Empty, - OldIsActive = m.OldIsActive, - NewIsActive = m.NewIsActive, - OldInitialContribution = m.OldInitialContribution, - NewInitialContribution = m.NewInitialContribution, - Action = (int)m.Action, - PerformedBy = m.PerformedBy ?? string.Empty, - Reason = m.Reason ?? string.Empty, - CreatedAt = Timestamp.FromDateTimeOffset(m.Created) - }) } - }); + config.NewConfig() + .Map(dest => dest.UserId, src => src.UserId) + .Map(dest => dest.ClubMembershipId, src => src.ClubMembershipId) + .Map(dest => dest.Action, src => src.Action == null ? null : (ClubMembershipAction?)src.Action) + .Map(dest => dest.CreatedFrom, src => src.CreatedFrom != null ? src.CreatedFrom.ToDateTime() : (DateTime?)null) + .Map(dest => dest.CreatedTo, src => src.CreatedTo != null ? src.CreatedTo.ToDateTime() : (DateTime?)null); + + config.NewConfig() + .Map(dest => dest.MetaData, src => src.MetaData) + .Map(dest => dest.Models, src => src.Models); + + config.NewConfig() + .Map(dest => dest.Id, src => src.Id) + .Map(dest => dest.ClubMembershipId, src => src.ClubMembershipId) + .Map(dest => dest.UserId, src => src.UserId) + .Map(dest => dest.UserName, src => src.UserName ?? string.Empty) + .Map(dest => dest.OldIsActive, src => src.OldIsActive) + .Map(dest => dest.NewIsActive, src => src.NewIsActive) + .Map(dest => dest.OldInitialContribution, src => src.OldInitialContribution) + .Map(dest => dest.NewInitialContribution, src => src.NewInitialContribution) + .Map(dest => dest.Action, src => (int)src.Action) + .Map(dest => dest.PerformedBy, src => src.PerformedBy ?? string.Empty) + .Map(dest => dest.Reason, src => src.Reason ?? string.Empty) + .Map(dest => dest.CreatedAt, src => Timestamp.FromDateTimeOffset(src.Created)); } - private static ClubMembershipModel MapToModel(GetAllClubMembershipsResponseModel src) + private static ProtoClub.ClubMembershipModel MapToModel(GetAllClubMembershipsResponseModel src) { - return new ClubMembershipModel + return new ProtoClub.ClubMembershipModel { Id = src.Id, UserId = src.UserId, diff --git a/src/CMSMicroservice.WebApi/Common/Mappings/PaymentTransactionProfile.cs b/src/CMSMicroservice.WebApi/Common/Mappings/PaymentTransactionProfile.cs index c7dffd7..00eba3c 100644 --- a/src/CMSMicroservice.WebApi/Common/Mappings/PaymentTransactionProfile.cs +++ b/src/CMSMicroservice.WebApi/Common/Mappings/PaymentTransactionProfile.cs @@ -1,10 +1,9 @@ -using CMSMicroservice.Application.PaymentTransactionCQ.Queries.GetAllPaymentTransactionByFilter; -using CMSMicroservice.Application.PaymentTransactionCQ.Queries.GetPaymentTransactionSummary; -using CMSMicroservice.Protobuf.Protos.PaymentTransaction; using Google.Protobuf.WellKnownTypes; +using CMSMicroservice.Domain.Enums; using Mapster; -using AppFilter = CMSMicroservice.Application.PaymentTransactionCQ.Queries.GetAllPaymentTransactionByFilter.GetAllPaymentTransactionByFilterFilter; -using ProtoFilter = CMSMicroservice.Protobuf.Protos.PaymentTransaction.GetAllPaymentTransactionByFilterFilter; +using AppPt = CMSMicroservice.Application.PaymentTransactionCQ.Queries.GetAllPaymentTransactionByFilter; +using AppPtSummary = CMSMicroservice.Application.PaymentTransactionCQ.Queries.GetPaymentTransactionSummary; +using ProtoPt = CMSMicroservice.Protobuf.Protos.PaymentTransaction; namespace CMSMicroservice.WebApi.Common.Mappings; @@ -12,93 +11,50 @@ public class PaymentTransactionProfile : IRegister { public void Register(TypeAdapterConfig config) { - config.NewConfig() - .MapWith(MapListQuery); + config.NewConfig() + .Map(dest => dest.PaginationState, src => src.PaginationState) + .Map(dest => dest.SortBy, src => src.SortBy) + .Map(dest => dest.Filter, src => src.Filter); - config.NewConfig() - .MapWith(MapListResponse); + config.NewConfig() + .Map(dest => dest.UserId, src => src.UserId) + .Map(dest => dest.Mobile, src => src.Mobile) + .Map(dest => dest.GatewayProvider, src => src.GatewayProvider) + .Map(dest => dest.PaymentStatus, src => src.PaymentStatus) + .Map(dest => dest.Authority, src => src.Authority) + .Map(dest => dest.RefId, src => src.RefId) + .Map(dest => dest.OrderId, src => src.OrderId) + .Map(dest => dest.CreatedFrom, src => src.CreatedFrom != null ? src.CreatedFrom.ToDateTime() : (DateTime?)null) + .Map(dest => dest.CreatedTo, src => src.CreatedTo != null ? src.CreatedTo.ToDateTime() : (DateTime?)null); - config.NewConfig() - .MapWith(src => new GetPaymentTransactionSummaryQuery - { - Filter = MapFilter(src.Filter) - }); + config.NewConfig() + .Map(dest => dest.MetaData, src => src.MetaData) + .Map(dest => dest.Models, src => src.Models); - config.NewConfig() - .MapWith(src => new GetPaymentTransactionSummaryResponse - { - TotalCount = src.TotalCount, - TotalAmount = src.TotalAmount, - SuccessfulCount = src.SuccessfulCount, - PendingCount = src.PendingCount - }); + config.NewConfig() + .Map(dest => dest.Id, src => src.Id) + .Map(dest => dest.UserId, src => src.UserId ?? 0) + .Map(dest => dest.Mobile, src => src.Mobile ?? string.Empty) + .Map(dest => dest.GatewayProvider, src => src.GatewayProvider) + .Map(dest => dest.Amount, src => src.Amount) + .Map(dest => dest.Authority, src => src.Authority ?? string.Empty) + .Map(dest => dest.PaymentStatus, src => src.PaymentStatus) + .Map(dest => dest.VerificationStatusCode, src => src.VerificationStatusCode) + .Map(dest => dest.VerificationStatusMessage, src => src.VerificationStatusMessage ?? string.Empty) + .Map(dest => dest.RefId, src => src.RefId ?? string.Empty) + .Map(dest => dest.CardPan, src => src.CardPan ?? string.Empty) + .Map(dest => dest.OrderId, src => src.OrderId ?? string.Empty) + .Map(dest => dest.TransactionId, src => src.TransactionId) + .Map(dest => dest.Description, src => src.Description ?? string.Empty) + .Map(dest => dest.CreatedAt, src => Timestamp.FromDateTimeOffset(src.Created)); + + config.NewConfig() + .Map(dest => dest.Filter, src => src.Filter); + + config.NewConfig() + .Map(dest => dest.TotalCount, src => src.TotalCount) + .Map(dest => dest.TotalAmount, src => src.TotalAmount) + .Map(dest => dest.SuccessfulCount, src => src.SuccessfulCount) + .Map(dest => dest.PendingCount, src => src.PendingCount); } - - private static GetAllPaymentTransactionByFilterQuery MapListQuery(GetAllPaymentTransactionByFilterRequest src) => - new() - { - PaginationState = MapPagination(src.PaginationState), - SortBy = src.HasSortBy ? src.SortBy : null, - Filter = MapFilter(src.Filter) - }; - - private static GetAllPaymentTransactionByFilterResponse MapListResponse(GetAllPaymentTransactionByFilterResponseDto src) => - new() - { - MetaData = MapMeta(src.MetaData), - Models = { src.Models?.Select(MapModel) ?? [] } - }; - - private static AppFilter? MapFilter(ProtoFilter? src) - { - if (src == null) return null; - return new AppFilter - { - UserId = src.HasUserId ? src.UserId : null, - Mobile = src.HasMobile ? src.Mobile : null, - GatewayProvider = src.HasGatewayProvider ? src.GatewayProvider : null, - PaymentStatus = src.HasPaymentStatus ? src.PaymentStatus : null, - Authority = src.HasAuthority ? src.Authority : null, - RefId = src.HasRefId ? src.RefId : null, - OrderId = src.HasOrderId ? src.OrderId : null, - CreatedFrom = src.CreatedFrom?.ToDateTime(), - CreatedTo = src.CreatedTo?.ToDateTime() - }; - } - - private static PaymentTransactionModel MapModel(GetAllPaymentTransactionByFilterResponseModel m) => - new() - { - Id = m.Id, - UserId = m.UserId ?? 0, - Mobile = m.Mobile ?? string.Empty, - GatewayProvider = m.GatewayProvider, - Amount = m.Amount, - Authority = m.Authority ?? string.Empty, - PaymentStatus = m.PaymentStatus, - VerificationStatusCode = m.VerificationStatusCode, - VerificationStatusMessage = m.VerificationStatusMessage ?? string.Empty, - RefId = m.RefId ?? string.Empty, - CardPan = m.CardPan ?? string.Empty, - OrderId = m.OrderId ?? string.Empty, - TransactionId = m.TransactionId, - Description = m.Description ?? string.Empty, - CreatedAt = Timestamp.FromDateTimeOffset(m.Created) - }; - - private static Application.Common.Models.PaginationState? MapPagination(CMSMicroservice.Protobuf.Protos.PaginationState? ps) => - ps == null ? null : new Application.Common.Models.PaginationState - { - PageNumber = ps.PageNumber > 0 ? ps.PageNumber : 1, - PageSize = ps.PageSize > 0 ? ps.PageSize : 20 - }; - - private static CMSMicroservice.Protobuf.Protos.MetaData MapMeta(Application.Common.Models.MetaData meta) => - new() - { - CurrentPage = meta.CurrentPage, - PageSize = meta.PageSize, - TotalCount = meta.TotalCount, - TotalPage = meta.TotalPage - }; } diff --git a/src/CMSMicroservice.WebApi/Common/Mappings/UserPackagePurchaseProfile.cs b/src/CMSMicroservice.WebApi/Common/Mappings/UserPackagePurchaseProfile.cs index 87543be..ba02b15 100644 --- a/src/CMSMicroservice.WebApi/Common/Mappings/UserPackagePurchaseProfile.cs +++ b/src/CMSMicroservice.WebApi/Common/Mappings/UserPackagePurchaseProfile.cs @@ -1,10 +1,9 @@ -using CMSMicroservice.Application.UserPackagePurchaseCQ.Queries.GetAllUserPackagePurchaseByFilter; -using CMSMicroservice.Application.UserPackagePurchaseCQ.Queries.GetUserPackagePurchaseSummary; -using CMSMicroservice.Protobuf.Protos.UserPackagePurchase; using Google.Protobuf.WellKnownTypes; +using CMSMicroservice.Domain.Enums; using Mapster; -using AppFilter = CMSMicroservice.Application.UserPackagePurchaseCQ.Queries.GetAllUserPackagePurchaseByFilter.GetAllUserPackagePurchaseByFilterFilter; -using ProtoFilter = CMSMicroservice.Protobuf.Protos.UserPackagePurchase.GetAllUserPackagePurchaseByFilterFilter; +using AppUp = CMSMicroservice.Application.UserPackagePurchaseCQ.Queries.GetAllUserPackagePurchaseByFilter; +using AppUpSummary = CMSMicroservice.Application.UserPackagePurchaseCQ.Queries.GetUserPackagePurchaseSummary; +using ProtoUp = CMSMicroservice.Protobuf.Protos.UserPackagePurchase; namespace CMSMicroservice.WebApi.Common.Mappings; @@ -12,74 +11,43 @@ public class UserPackagePurchaseProfile : IRegister { public void Register(TypeAdapterConfig config) { - config.NewConfig() - .MapWith(src => new GetAllUserPackagePurchaseByFilterQuery - { - PaginationState = MapPagination(src.PaginationState), - SortBy = src.HasSortBy ? src.SortBy : null, - Filter = MapFilter(src.Filter) - }); + config.NewConfig() + .Map(dest => dest.PaginationState, src => src.PaginationState) + .Map(dest => dest.SortBy, src => src.SortBy) + .Map(dest => dest.Filter, src => src.Filter); - config.NewConfig() - .MapWith(src => new GetAllUserPackagePurchaseByFilterResponse - { - MetaData = MapMeta(src.MetaData), - Models = { src.Models?.Select(m => new UserPackagePurchaseModel - { - Id = m.Id, - UserId = m.UserId, - UserName = m.UserName, - UserMobile = m.UserMobile, - PackageId = m.PackageId, - PackageName = m.PackageName, - PurchaseMethod = (int)m.PurchaseMethod, - PurchasedAt = Timestamp.FromDateTime(DateTime.SpecifyKind(m.PurchasedAt, DateTimeKind.Utc)), - Amount = m.Amount, - OrderId = m.OrderId, - TransactionId = m.TransactionId, - CreatedAt = Timestamp.FromDateTimeOffset(m.Created) - }) ?? [] } - }); + config.NewConfig() + .Map(dest => dest.UserId, src => src.UserId) + .Map(dest => dest.PackageId, src => src.PackageId) + .Map(dest => dest.PurchaseMethod, src => src.PurchaseMethod == null ? null : (PackagePurchaseMethod?)src.PurchaseMethod) + .Map(dest => dest.PurchasedFrom, src => src.PurchasedFrom != null ? src.PurchasedFrom.ToDateTime() : (DateTime?)null) + .Map(dest => dest.PurchasedTo, src => src.PurchasedTo != null ? src.PurchasedTo.ToDateTime() : (DateTime?)null) + .Map(dest => dest.MinAmount, src => src.MinAmount) + .Map(dest => dest.MaxAmount, src => src.MaxAmount); - config.NewConfig() - .MapWith(src => new GetUserPackagePurchaseSummaryQuery { Filter = MapFilter(src.Filter) }); + config.NewConfig() + .Map(dest => dest.MetaData, src => src.MetaData) + .Map(dest => dest.Models, src => src.Models); - config.NewConfig() - .MapWith(src => new GetUserPackagePurchaseSummaryResponse - { - TotalCount = src.TotalCount, - TotalAmount = src.TotalAmount - }); + config.NewConfig() + .Map(dest => dest.Id, src => src.Id) + .Map(dest => dest.UserId, src => src.UserId) + .Map(dest => dest.UserName, src => src.UserName) + .Map(dest => dest.UserMobile, src => src.UserMobile) + .Map(dest => dest.PackageId, src => src.PackageId) + .Map(dest => dest.PackageName, src => src.PackageName) + .Map(dest => dest.PurchaseMethod, src => (int)src.PurchaseMethod) + .Map(dest => dest.PurchasedAt, src => Timestamp.FromDateTime(DateTime.SpecifyKind(src.PurchasedAt, DateTimeKind.Utc))) + .Map(dest => dest.Amount, src => src.Amount) + .Map(dest => dest.OrderId, src => src.OrderId) + .Map(dest => dest.TransactionId, src => src.TransactionId) + .Map(dest => dest.CreatedAt, src => Timestamp.FromDateTimeOffset(src.Created)); + + config.NewConfig() + .Map(dest => dest.Filter, src => src.Filter); + + config.NewConfig() + .Map(dest => dest.TotalCount, src => src.TotalCount) + .Map(dest => dest.TotalAmount, src => src.TotalAmount); } - - private static AppFilter? MapFilter(ProtoFilter? src) - { - if (src == null) return null; - return new AppFilter - { - UserId = src.HasUserId ? src.UserId : null, - PackageId = src.HasPackageId ? src.PackageId : null, - PurchaseMethod = src.HasPurchaseMethod ? (Domain.Enums.PackagePurchaseMethod)src.PurchaseMethod : null, - PurchasedFrom = src.PurchasedFrom?.ToDateTime(), - PurchasedTo = src.PurchasedTo?.ToDateTime(), - MinAmount = src.HasMinAmount ? src.MinAmount : null, - MaxAmount = src.HasMaxAmount ? src.MaxAmount : null - }; - } - - private static Application.Common.Models.PaginationState? MapPagination(CMSMicroservice.Protobuf.Protos.PaginationState? ps) => - ps == null ? null : new Application.Common.Models.PaginationState - { - PageNumber = ps.PageNumber > 0 ? ps.PageNumber : 1, - PageSize = ps.PageSize > 0 ? ps.PageSize : 20 - }; - - private static CMSMicroservice.Protobuf.Protos.MetaData MapMeta(Application.Common.Models.MetaData meta) => - new() - { - CurrentPage = meta.CurrentPage, - PageSize = meta.PageSize, - TotalCount = meta.TotalCount, - TotalPage = meta.TotalPage - }; } From 7570c39e65f24c98b07e36dbfc67fc169ab25c48 Mon Sep 17 00:00:00 2001 From: masoodafar-web Date: Tue, 23 Jun 2026 00:11:37 +0330 Subject: [PATCH 4/8] refactor(extensions): improve sorting logic in ApplyOrder method - Simplified the default sorting approach by directly returning the ordered source. - Introduced NormalizeSortBy method to handle dynamic LINQ sorting, accommodating leading '+' and '-' for ascending and descending order respectively. - Enhanced code clarity and maintainability by reducing unnecessary variable assignments. --- .../Common/Extensions/SortByExtensions.cs | 27 ++++++++++++++----- 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/src/CMSMicroservice.Application/Common/Extensions/SortByExtensions.cs b/src/CMSMicroservice.Application/Common/Extensions/SortByExtensions.cs index 3f0d9c8..439e9a5 100644 --- a/src/CMSMicroservice.Application/Common/Extensions/SortByExtensions.cs +++ b/src/CMSMicroservice.Application/Common/Extensions/SortByExtensions.cs @@ -8,16 +8,31 @@ public static class SortByExtensions public static IQueryable ApplyOrder(this IQueryable source, string? sortBy) where TSource : BaseAuditableEntity { - // default sort approach if (sortBy is null or "") { - source = source.OrderByDescending(p => p.Created); - return source; + return source.OrderByDescending(p => p.Created); } - // sort using dynamic linq - source = source.OrderBy(sortBy); + return source.OrderBy(NormalizeSortBy(sortBy)); + } - return source; + /// + /// Dynamic LINQ treats "-Created" as unary minus on DateTime (invalid). + /// Project convention: leading '-' means descending sort. + /// + private static string NormalizeSortBy(string sortBy) + { + sortBy = sortBy.Trim(); + if (sortBy.StartsWith('-') && sortBy.Length > 1) + { + return $"{sortBy[1..]} descending"; + } + + if (sortBy.StartsWith('+') && sortBy.Length > 1) + { + return $"{sortBy[1..]} ascending"; + } + + return sortBy; } } From 6c3fbe43b18f5162cb80ad311e1cfd1b199d03d6 Mon Sep 17 00:00:00 2001 From: masoodafar-web Date: Fri, 26 Jun 2026 16:11:18 +0330 Subject: [PATCH 5/8] feat(wallet): add credit wallet functionality and update Protobuf definitions - Introduced new CreditWalletCharge enum value to TransactionType for clarity. - Implemented InitiateCreditCharge and VerifyCreditCharge methods in UserWalletService for handling credit wallet transactions. - Updated ZarinpalReconciliationJob to support credit wallet payment verification. - Enhanced Protobuf definitions with new messages and RPC methods for credit wallet operations. - Bumped Protobuf project version to reflect the addition of new features. --- .../ChargeCreditWalletCommand.cs | 13 ++ .../ChargeCreditWalletCommandHandler.cs | 123 ++++++++++++++ .../ChargeCreditWalletCommandValidator.cs | 20 +++ .../VerifyCreditWalletChargeCommand.cs | 13 ++ .../VerifyCreditWalletChargeCommandHandler.cs | 157 ++++++++++++++++++ .../Enums/TransactionType.cs | 5 + .../ZarinpalReconciliationJob.cs | 16 ++ .../CMSMicroservice.Protobuf.csproj | 2 +- .../Protos/userwallet.proto | 29 ++++ .../Services/UserWalletService.cs | 85 ++++++++++ 10 files changed, 462 insertions(+), 1 deletion(-) create mode 100644 src/CMSMicroservice.Application/WalletCQ/Commands/ChargeCreditWallet/ChargeCreditWalletCommand.cs create mode 100644 src/CMSMicroservice.Application/WalletCQ/Commands/ChargeCreditWallet/ChargeCreditWalletCommandHandler.cs create mode 100644 src/CMSMicroservice.Application/WalletCQ/Commands/ChargeCreditWallet/ChargeCreditWalletCommandValidator.cs create mode 100644 src/CMSMicroservice.Application/WalletCQ/Commands/VerifyCreditWalletCharge/VerifyCreditWalletChargeCommand.cs create mode 100644 src/CMSMicroservice.Application/WalletCQ/Commands/VerifyCreditWalletCharge/VerifyCreditWalletChargeCommandHandler.cs diff --git a/src/CMSMicroservice.Application/WalletCQ/Commands/ChargeCreditWallet/ChargeCreditWalletCommand.cs b/src/CMSMicroservice.Application/WalletCQ/Commands/ChargeCreditWallet/ChargeCreditWalletCommand.cs new file mode 100644 index 0000000..fc6dab9 --- /dev/null +++ b/src/CMSMicroservice.Application/WalletCQ/Commands/ChargeCreditWallet/ChargeCreditWalletCommand.cs @@ -0,0 +1,13 @@ +using CMSMicroservice.Application.Common.Models; +using MediatR; + +namespace CMSMicroservice.Application.WalletCQ.Commands.ChargeCreditWallet; + +/// +/// دستور شارژ کیف پول اصلی از طریق درگاه +/// +public class ChargeCreditWalletCommand : IRequest +{ + public long UserId { get; set; } + public long Amount { get; set; } +} diff --git a/src/CMSMicroservice.Application/WalletCQ/Commands/ChargeCreditWallet/ChargeCreditWalletCommandHandler.cs b/src/CMSMicroservice.Application/WalletCQ/Commands/ChargeCreditWallet/ChargeCreditWalletCommandHandler.cs new file mode 100644 index 0000000..d983cb7 --- /dev/null +++ b/src/CMSMicroservice.Application/WalletCQ/Commands/ChargeCreditWallet/ChargeCreditWalletCommandHandler.cs @@ -0,0 +1,123 @@ +using CMSMicroservice.Application.Common; +using CMSMicroservice.Application.Common.Exceptions; +using CMSMicroservice.Application.Common.Interfaces; +using CMSMicroservice.Application.Common.Models; +using CMSMicroservice.Domain.Entities; +using CMSMicroservice.Domain.Entities.Payment; +using MediatR; +using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.Logging; + +namespace CMSMicroservice.Application.WalletCQ.Commands.ChargeCreditWallet; + +public class ChargeCreditWalletCommandHandler + : IRequestHandler +{ + private readonly IApplicationDbContext _context; + private readonly IPaymentGatewayService _paymentGateway; + private readonly IConfiguration _configuration; + private readonly ILogger _logger; + private readonly IUserPaymentLock _paymentLock; + + public ChargeCreditWalletCommandHandler( + IApplicationDbContext context, + IPaymentGatewayService paymentGateway, + IConfiguration configuration, + ILogger logger, + IUserPaymentLock paymentLock) + { + _context = context; + _paymentGateway = paymentGateway; + _configuration = configuration; + _logger = logger; + _paymentLock = paymentLock; + } + + public Task Handle( + ChargeCreditWalletCommand request, + CancellationToken cancellationToken) => + _paymentLock.ExecuteAsync( + PaymentLockScopes.Initiate(request.UserId), + PaymentLockStrategy.FailFast, + ct => HandleCore(request, ct), + cancellationToken); + + private async Task HandleCore( + ChargeCreditWalletCommand request, + CancellationToken cancellationToken) + { + try + { + _logger.LogInformation( + "Charging credit wallet for UserId: {UserId}, Amount: {Amount}", + request.UserId, + request.Amount); + + var user = await _context.Users + .FirstOrDefaultAsync(u => u.Id == request.UserId, cancellationToken) + ?? throw new NotFoundException(nameof(User), request.UserId); + + var wallet = await _context.UserWallets + .FirstOrDefaultAsync(w => w.UserId == request.UserId, cancellationToken) + ?? throw new NotFoundException("کیف پول کاربر یافت نشد"); + + var frontOfficeBaseUrl = _configuration["FrontOfficeBaseUrl"] ?? "https://localhost:5268"; + var callbackUrl = $"{frontOfficeBaseUrl}/profile/payment-callback?type=credit-wallet"; + + var paymentRequest = new PaymentRequest + { + Amount = request.Amount, + UserId = user.Id, + Mobile = user.Mobile ?? "", + CallbackUrl = callbackUrl, + Description = $"شارژ کیف پول اصلی - کاربر {user.Id}" + }; + + var paymentResult = await _paymentGateway.InitiatePaymentAsync(paymentRequest); + + if (!paymentResult.IsSuccess) + { + _logger.LogError( + "Payment gateway failed for UserId {UserId}: {ErrorMessage}", + user.Id, + paymentResult.ErrorMessage); + + throw new Exception($"خطا در ارتباط با درگاه پرداخت: {paymentResult.ErrorMessage}"); + } + + var paymentTx = new PaymentTransaction + { + GatewayProvider = _configuration["PaymentProvider"] ?? "zarinpal", + MerchantId = _configuration["ZarinPal:MerchantId"] ?? "", + Amount = request.Amount, + CallbackUrl = callbackUrl, + Description = $"شارژ کیف پول اصلی - کاربر {user.Id}", + Mobile = user.Mobile, + UserId = user.Id, + RequestStatusCode = 100, + RequestStatusMessage = "Success", + Authority = paymentResult.RefId, + PaymentStatus = false + }; + _context.PaymentTransactions.Add(paymentTx); + await _context.SaveChangesAsync(cancellationToken); + + _logger.LogInformation( + "Credit wallet charge initiated. UserId: {UserId}, RefId: {RefId}, PaymentTxId: {PaymentTxId}", + user.Id, + paymentResult.RefId, + paymentTx.Id); + + return paymentResult; + } + catch (Exception ex) + { + _logger.LogError( + ex, + "Error in ChargeCreditWalletCommand for UserId: {UserId}", + request.UserId); + throw; + } + } +} diff --git a/src/CMSMicroservice.Application/WalletCQ/Commands/ChargeCreditWallet/ChargeCreditWalletCommandValidator.cs b/src/CMSMicroservice.Application/WalletCQ/Commands/ChargeCreditWallet/ChargeCreditWalletCommandValidator.cs new file mode 100644 index 0000000..8e106b7 --- /dev/null +++ b/src/CMSMicroservice.Application/WalletCQ/Commands/ChargeCreditWallet/ChargeCreditWalletCommandValidator.cs @@ -0,0 +1,20 @@ +using CMSMicroservice.Domain.Common; +using FluentValidation; + +namespace CMSMicroservice.Application.WalletCQ.Commands.ChargeCreditWallet; + +public class ChargeCreditWalletCommandValidator : AbstractValidator +{ + public ChargeCreditWalletCommandValidator() + { + RuleFor(x => x.UserId) + .GreaterThan(0) + .WithMessage("شناسه کاربر باید بزرگتر از صفر باشد"); + + RuleFor(x => x.Amount) + .GreaterThanOrEqualTo(SystemConstants.DiscountWalletMinCharge) + .WithMessage("حداقل مبلغ شارژ ۱۰,۰۰۰ تومان است") + .LessThanOrEqualTo(SystemConstants.WalletMaxSafeAmount) + .WithMessage("مبلغ وارد شده بیش از حد مجاز است"); + } +} diff --git a/src/CMSMicroservice.Application/WalletCQ/Commands/VerifyCreditWalletCharge/VerifyCreditWalletChargeCommand.cs b/src/CMSMicroservice.Application/WalletCQ/Commands/VerifyCreditWalletCharge/VerifyCreditWalletChargeCommand.cs new file mode 100644 index 0000000..4ec5aad --- /dev/null +++ b/src/CMSMicroservice.Application/WalletCQ/Commands/VerifyCreditWalletCharge/VerifyCreditWalletChargeCommand.cs @@ -0,0 +1,13 @@ +using MediatR; + +namespace CMSMicroservice.Application.WalletCQ.Commands.VerifyCreditWalletCharge; + +/// +/// دستور تأیید شارژ کیف پول اصلی +/// +public class VerifyCreditWalletChargeCommand : IRequest +{ + public long UserId { get; set; } + public long Amount { get; set; } + public string Authority { get; set; } = string.Empty; +} diff --git a/src/CMSMicroservice.Application/WalletCQ/Commands/VerifyCreditWalletCharge/VerifyCreditWalletChargeCommandHandler.cs b/src/CMSMicroservice.Application/WalletCQ/Commands/VerifyCreditWalletCharge/VerifyCreditWalletChargeCommandHandler.cs new file mode 100644 index 0000000..c3985a5 --- /dev/null +++ b/src/CMSMicroservice.Application/WalletCQ/Commands/VerifyCreditWalletCharge/VerifyCreditWalletChargeCommandHandler.cs @@ -0,0 +1,157 @@ +using CMSMicroservice.Application.Common; +using CMSMicroservice.Application.Common.Exceptions; +using CMSMicroservice.Application.Common.Interfaces; +using CMSMicroservice.Domain.Entities; +using CMSMicroservice.Domain.Enums; +using MediatR; +using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.Logging; + +namespace CMSMicroservice.Application.WalletCQ.Commands.VerifyCreditWalletCharge; + +public class VerifyCreditWalletChargeCommandHandler + : IRequestHandler +{ + private readonly IApplicationDbContext _context; + private readonly IPaymentGatewayService _paymentGateway; + private readonly ILogger _logger; + private readonly IUserPaymentLock _paymentLock; + + public VerifyCreditWalletChargeCommandHandler( + IApplicationDbContext context, + IPaymentGatewayService paymentGateway, + ILogger logger, + IUserPaymentLock paymentLock) + { + _context = context; + _paymentGateway = paymentGateway; + _logger = logger; + _paymentLock = paymentLock; + } + + public Task Handle( + VerifyCreditWalletChargeCommand request, + CancellationToken cancellationToken) => + _paymentLock.ExecuteAsync( + PaymentLockScopes.Verify(request.UserId, request.Authority), + PaymentLockStrategy.WaitForRelease, + ct => HandleCore(request, ct), + cancellationToken); + + private async Task HandleCore( + VerifyCreditWalletChargeCommand request, + CancellationToken cancellationToken) + { + try + { + _logger.LogInformation( + "Verifying credit wallet charge. UserId: {UserId}, Amount: {Amount}, Authority: {Authority}", + request.UserId, + request.Amount, + request.Authority); + + var user = await _context.Users + .FirstOrDefaultAsync(u => u.Id == request.UserId, cancellationToken) + ?? throw new NotFoundException(nameof(User), request.UserId); + + var paymentTx = await _context.PaymentTransactions + .FirstOrDefaultAsync(pt => pt.Authority == request.Authority, cancellationToken); + + if (paymentTx?.PaymentStatus == true) + { + _logger.LogWarning("PaymentTransaction already verified: {Authority}", request.Authority); + return true; + } + + var amountInToman = (decimal)(paymentTx?.Amount ?? 0); + + var verifyResult = await _paymentGateway.VerifyPaymentAsync( + request.Authority, + "OK", + amountInToman, + cancellationToken); + + if (paymentTx != null) + { + paymentTx.PaymentStatus = verifyResult.IsSuccess; + paymentTx.VerificationStatusCode = verifyResult.VerificationCode; + paymentTx.VerificationStatusMessage = verifyResult.Message; + paymentTx.CardPan = verifyResult.CardPan; + paymentTx.CardHash = verifyResult.CardHash; + paymentTx.RefId = verifyResult.TrackingCode; + } + + if (!verifyResult.IsSuccess) + { + _logger.LogWarning( + "Credit wallet charge verification failed for UserId {UserId}: {Message}", + request.UserId, + verifyResult.Message); + + throw new Exception($"تراکنش ناموفق: {verifyResult.Message}"); + } + + var wallet = await _context.UserWallets + .FirstOrDefaultAsync(w => w.UserId == user.Id, cancellationToken) + ?? throw new NotFoundException($"کیف پول کاربر با شناسه {request.UserId} یافت نشد"); + + var oldBalance = wallet.Balance; + wallet.Balance += request.Amount; + + _logger.LogInformation( + "Charging credit balance for UserId {UserId}: {OldBalance} -> {NewBalance}", + request.UserId, + oldBalance, + wallet.Balance); + + var transaction = new Transaction + { + Amount = request.Amount, + Description = $"شارژ کیف پول اصلی - کاربر {user.Id}", + PaymentStatus = PaymentStatus.Success, + PaymentDate = DateTime.Now, + RefId = verifyResult.RefId, + Type = TransactionType.CreditWalletCharge + }; + + _context.Transactions.Add(transaction); + await _context.SaveChangesAsync(cancellationToken); + + _context.UserWalletHistories.Add(new Domain.Entities.UserWalletHistory + { + WalletId = wallet.Id, + CurrentBalance = wallet.Balance, + ChangeValue = request.Amount, + CurrentNetworkBalance = wallet.NetworkBalance, + ChangeNerworkValue = 0, + CurrentDiscountBalance = wallet.DiscountBalance, + ChangeDiscountValue = 0, + IsIncrease = true, + RefrenceId = transaction.Id + }); + await _context.SaveChangesAsync(cancellationToken); + + if (paymentTx != null) + { + paymentTx.TransactionId = transaction.Id; + await _context.SaveChangesAsync(cancellationToken); + } + + _logger.LogInformation( + "Credit wallet charged successfully. UserId: {UserId}, TransactionId: {TransactionId}, RefId: {RefId}", + user.Id, + transaction.Id, + verifyResult.RefId); + + return true; + } + catch (Exception ex) + { + _logger.LogError( + ex, + "Error in VerifyCreditWalletChargeCommand for UserId: {UserId}", + request.UserId); + throw; + } + } +} diff --git a/src/CMSMicroservice.Domain/Enums/TransactionType.cs b/src/CMSMicroservice.Domain/Enums/TransactionType.cs index f93f9b6..7b32d15 100644 --- a/src/CMSMicroservice.Domain/Enums/TransactionType.cs +++ b/src/CMSMicroservice.Domain/Enums/TransactionType.cs @@ -36,4 +36,9 @@ public enum TransactionType /// بونوس داخلی کیف‌پول جادویی (مبلغ × 1.5) /// MagicWalletBonus = 15, + + /// + /// شارژ کیف پول اصلی از درگاه + /// + CreditWalletCharge = 16, } diff --git a/src/CMSMicroservice.Infrastructure/BackgroundJobs/ZarinpalReconciliationJob.cs b/src/CMSMicroservice.Infrastructure/BackgroundJobs/ZarinpalReconciliationJob.cs index 4e402f7..0e39c69 100644 --- a/src/CMSMicroservice.Infrastructure/BackgroundJobs/ZarinpalReconciliationJob.cs +++ b/src/CMSMicroservice.Infrastructure/BackgroundJobs/ZarinpalReconciliationJob.cs @@ -3,6 +3,7 @@ using CMSMicroservice.Application.PackageCQ.Commands.VerifyUserPackagePurchasePa using CMSMicroservice.Application.Common.Interfaces; using CMSMicroservice.Application.DiscountShopCQ.Commands.CompleteOrderPayment; using CMSMicroservice.Application.WalletCQ.Commands.VerifyDiscountWalletCharge; +using CMSMicroservice.Application.WalletCQ.Commands.VerifyCreditWalletCharge; using CMSMicroservice.Application.WalletCQ.Commands.VerifyMagicWalletCharge; using CMSMicroservice.Domain.Entities; using CMSMicroservice.Domain.Entities.Payment; @@ -174,6 +175,19 @@ public class ZarinpalReconciliationJob }, ct); break; + case "credit-wallet": + if (!paymentTx.UserId.HasValue) + throw new InvalidOperationException( + $"UserId is null for credit-wallet authority {authority}"); + + await _sender.Send(new VerifyCreditWalletChargeCommand + { + Authority = authority, + UserId = paymentTx.UserId.Value, + Amount = paymentTx.Amount + }, ct); + break; + case "discount-order": await ReconcileDiscountOrderAsync(paymentTx, ct); break; @@ -194,6 +208,8 @@ public class ZarinpalReconciliationJob return "magic-wallet"; if (callbackUrl.Contains("type=discount-wallet", StringComparison.OrdinalIgnoreCase)) return "discount-wallet"; + if (callbackUrl.Contains("type=credit-wallet", StringComparison.OrdinalIgnoreCase)) + return "credit-wallet"; if (callbackUrl.Contains("type=discount-order", StringComparison.OrdinalIgnoreCase)) return "discount-order"; // Package callbacks have orderId= but no type= parameter diff --git a/src/CMSMicroservice.Protobuf/CMSMicroservice.Protobuf.csproj b/src/CMSMicroservice.Protobuf/CMSMicroservice.Protobuf.csproj index 02bd97b..b403094 100644 --- a/src/CMSMicroservice.Protobuf/CMSMicroservice.Protobuf.csproj +++ b/src/CMSMicroservice.Protobuf/CMSMicroservice.Protobuf.csproj @@ -3,7 +3,7 @@ net9.0 enable enable - 0.0.201 + 0.0.202 None False False diff --git a/src/CMSMicroservice.Protobuf/Protos/userwallet.proto b/src/CMSMicroservice.Protobuf/Protos/userwallet.proto index c574685..ab9a1a8 100644 --- a/src/CMSMicroservice.Protobuf/Protos/userwallet.proto +++ b/src/CMSMicroservice.Protobuf/Protos/userwallet.proto @@ -110,6 +110,21 @@ service UserWalletContract body: "*" }; }; + + // ============= Credit (Main) Wallet Methods ============= + + rpc InitiateCreditCharge(InitiateCreditChargeRequest) returns (InitiateCreditChargeResponse){ + option (google.api.http) = { + post: "/Customer/InitiateCreditCharge" + body: "*" + }; + }; + rpc VerifyCreditCharge(VerifyWalletChargeRequest) returns (VerifyWalletChargeResponse){ + option (google.api.http) = { + post: "/Customer/VerifyCreditCharge" + body: "*" + }; + }; } message CreateNewUserWalletRequest { @@ -283,6 +298,20 @@ message InitiateDiscountChargeResponse string error_message = 3; } +// ============= Credit (Main) Wallet Messages ============= + +message InitiateCreditChargeRequest +{ + int64 amount = 1; // مبلغ واریزی (تومان) +} + +message InitiateCreditChargeResponse +{ + bool is_success = 1; + string gateway_url = 2; + string error_message = 3; +} + // ============= Wallet Verify Messages ============= message VerifyWalletChargeRequest diff --git a/src/CMSMicroservice.WebApi/Services/UserWalletService.cs b/src/CMSMicroservice.WebApi/Services/UserWalletService.cs index 3863aa5..72338f0 100644 --- a/src/CMSMicroservice.WebApi/Services/UserWalletService.cs +++ b/src/CMSMicroservice.WebApi/Services/UserWalletService.cs @@ -5,8 +5,10 @@ using CMSMicroservice.Application.UserWalletCQ.Commands.UpdateUserWallet; using CMSMicroservice.Application.UserWalletCQ.Commands.DeleteUserWallet; using CMSMicroservice.Application.WalletCQ.Commands.ChargeMagicWallet; using CMSMicroservice.Application.WalletCQ.Commands.ChargeDiscountWallet; +using CMSMicroservice.Application.WalletCQ.Commands.ChargeCreditWallet; using CMSMicroservice.Application.WalletCQ.Commands.VerifyMagicWalletCharge; using CMSMicroservice.Application.WalletCQ.Commands.VerifyDiscountWalletCharge; +using CMSMicroservice.Application.WalletCQ.Commands.VerifyCreditWalletCharge; using CMSMicroservice.Application.UserWalletCQ.Queries.GetUserWallet; using CMSMicroservice.Application.UserWalletCQ.Queries.GetAllUserWalletByFilter; using CMSMicroservice.Application.UserWalletCQ.Queries.GetCustomerWalletHistory; @@ -242,6 +244,38 @@ public class UserWalletService : UserWalletContract.UserWalletContractBase } } + // ============= Credit (Main) Wallet Methods ============= + + public override async Task InitiateCreditCharge( + InitiateCreditChargeRequest request, ServerCallContext context) + { + var userId = GetCurrentUserId(); + + try + { + var result = await _sender.Send(new ChargeCreditWalletCommand + { + UserId = userId, + Amount = request.Amount + }, context.CancellationToken); + + return new InitiateCreditChargeResponse + { + IsSuccess = result.IsSuccess, + GatewayUrl = result.GatewayUrl ?? "", + ErrorMessage = result.ErrorMessage ?? "" + }; + } + catch (PaymentInProgressException ex) + { + return new InitiateCreditChargeResponse + { + IsSuccess = false, + ErrorMessage = ex.Message + }; + } + } + // ============= Wallet Verify Methods ============= public override async Task VerifyMagicCharge( @@ -330,6 +364,57 @@ public class UserWalletService : UserWalletContract.UserWalletContractBase } } + public override async Task VerifyCreditCharge( + VerifyWalletChargeRequest request, ServerCallContext context) + { + _logger.LogInformation("VerifyCreditCharge called: Authority={Authority}, Status={Status}", + request.Authority, request.Status); + + try + { + if (string.IsNullOrEmpty(request.Authority)) + return new VerifyWalletChargeResponse { Success = false, Message = "کد Authority نامعتبر است" }; + + var paymentTx = await _context.PaymentTransactions + .FirstOrDefaultAsync(pt => pt.Authority == request.Authority, context.CancellationToken); + + if (paymentTx == null || !paymentTx.UserId.HasValue) + { + _logger.LogError("VerifyCreditCharge: PaymentTransaction not found for Authority={Authority}", request.Authority); + return new VerifyWalletChargeResponse { Success = false, Message = "تراکنش یافت نشد" }; + } + + if (!string.Equals(request.Status, "OK", StringComparison.OrdinalIgnoreCase)) + { + _logger.LogWarning("VerifyCreditCharge: Payment cancelled by user. Authority={Authority}", request.Authority); + return new VerifyWalletChargeResponse { Success = false, Message = "پرداخت توسط کاربر لغو شد" }; + } + + var result = await _sender.Send(new VerifyCreditWalletChargeCommand + { + UserId = paymentTx.UserId.Value, + Amount = paymentTx.Amount, + Authority = request.Authority + }, context.CancellationToken); + + _logger.LogInformation("VerifyCreditCharge result: {Result}, Authority={Authority}, UserId={UserId}", + result, request.Authority, paymentTx.UserId.Value); + + return new VerifyWalletChargeResponse + { + Success = result, + Message = result + ? "شارژ کیف پول اصلی با موفقیت انجام شد" + : "شارژ کیف پول اصلی ناموفق بود" + }; + } + catch (Exception ex) + { + _logger.LogError(ex, "VerifyCreditCharge error: Authority={Authority}", request.Authority); + return new VerifyWalletChargeResponse { Success = false, Message = ex.Message }; + } + } + public override async Task GetMagicWalletStatus( Google.Protobuf.WellKnownTypes.Empty request, ServerCallContext context) { From 58aeddf004d0a6f5209057b6f50979184ac7d5d7 Mon Sep 17 00:00:00 2001 From: masoodafar-web Date: Fri, 26 Jun 2026 16:33:20 +0330 Subject: [PATCH 6/8] feat(transactions): enhance transaction filtering and summary capabilities - Added new date range filters (CreatedFrom, CreatedTo, PaymentDateFrom, PaymentDateTo) to GetAllTransactionsByFilterQuery for improved transaction querying. - Updated GetAllTransactionsByFilterQueryHandler to apply new filters and return detailed transaction models. - Introduced GetTransactionSummary RPC method in Protobuf for summarizing transaction data. - Enhanced mapping configurations to accommodate new filter properties and response models. - Bumped Protobuf project version to reflect the addition of new features. --- .../GetAllTransactionsByFilterQuery.cs | 4 ++ .../GetAllTransactionsByFilterQueryHandler.cs | 36 +++++++------ .../GetAllTransactionsByFilterResponseDto.cs | 1 + .../TransactionFilterExtensions.cs | 48 +++++++++++++++++ .../GetTransactionSummaryQuery.cs | 17 ++++++ .../GetTransactionSummaryQueryHandler.cs | 39 ++++++++++++++ .../CMSMicroservice.Protobuf.csproj | 2 +- .../Protos/public_messages.proto | 7 +++ .../Protos/transactions.proto | 24 +++++++++ .../Common/Mappings/TransactionsProfile.cs | 54 +++++++++++++++++-- .../Services/TransactionsService.cs | 5 ++ 11 files changed, 214 insertions(+), 23 deletions(-) create mode 100644 src/CMSMicroservice.Application/TransactionsCQ/Queries/GetAllTransactionsByFilter/TransactionFilterExtensions.cs create mode 100644 src/CMSMicroservice.Application/TransactionsCQ/Queries/GetTransactionSummary/GetTransactionSummaryQuery.cs create mode 100644 src/CMSMicroservice.Application/TransactionsCQ/Queries/GetTransactionSummary/GetTransactionSummaryQueryHandler.cs diff --git a/src/CMSMicroservice.Application/TransactionsCQ/Queries/GetAllTransactionsByFilter/GetAllTransactionsByFilterQuery.cs b/src/CMSMicroservice.Application/TransactionsCQ/Queries/GetAllTransactionsByFilter/GetAllTransactionsByFilterQuery.cs index 2601756..f8f647f 100644 --- a/src/CMSMicroservice.Application/TransactionsCQ/Queries/GetAllTransactionsByFilter/GetAllTransactionsByFilterQuery.cs +++ b/src/CMSMicroservice.Application/TransactionsCQ/Queries/GetAllTransactionsByFilter/GetAllTransactionsByFilterQuery.cs @@ -26,4 +26,8 @@ public record GetAllTransactionsByFilterQuery : IRequest { private readonly IApplicationDbContext _context; @@ -11,26 +12,27 @@ public class GetAllTransactionsByFilterQueryHandler : IRequestHandler Handle(GetAllTransactionsByFilterQuery request, CancellationToken cancellationToken) { var query = _context.Transactions - .ApplyOrder(sortBy: request.SortBy) .AsNoTracking() - .AsQueryable(); - if (request.Filter is not null) - { - query = query - .Where(x => request.Filter.Id == null || x.Id == request.Filter.Id) - .Where(x => request.Filter.Amount == null || x.Amount == request.Filter.Amount) - .Where(x => request.Filter.Description == null || x.Description.Contains(request.Filter.Description)) - .Where(x => request.Filter.PaymentStatus == null || x.PaymentStatus== request.Filter.PaymentStatus) - .Where(x => request.Filter.PaymentDate == null || x.PaymentDate == request.Filter.PaymentDate) - .Where(x => request.Filter.RefId == null || x.RefId.Contains(request.Filter.RefId)) - .Where(x => request.Filter.Type == null || x.Type == request.Filter.Type) -; - } + .ApplyTransactionFilter(request.Filter) + .ApplyOrder(sortBy: request.SortBy ?? "-Created"); + return new GetAllTransactionsByFilterResponseDto { MetaData = await query.GetMetaData(request.PaginationState, cancellationToken), - Models = await query.PaginatedListAsync(paginationState: request.PaginationState) - .ProjectToType().ToListAsync(cancellationToken) - }; + Models = await query + .PaginatedListAsync(paginationState: request.PaginationState) + .Select(x => new GetAllTransactionsByFilterResponseModel + { + Id = x.Id, + Amount = x.Amount, + Description = x.Description, + PaymentStatus = x.PaymentStatus, + PaymentDate = x.PaymentDate, + RefId = x.RefId, + Type = x.Type, + Created = x.Created + }) + .ToListAsync(cancellationToken) + }; } } diff --git a/src/CMSMicroservice.Application/TransactionsCQ/Queries/GetAllTransactionsByFilter/GetAllTransactionsByFilterResponseDto.cs b/src/CMSMicroservice.Application/TransactionsCQ/Queries/GetAllTransactionsByFilter/GetAllTransactionsByFilterResponseDto.cs index 6e3937d..ed4e290 100644 --- a/src/CMSMicroservice.Application/TransactionsCQ/Queries/GetAllTransactionsByFilter/GetAllTransactionsByFilterResponseDto.cs +++ b/src/CMSMicroservice.Application/TransactionsCQ/Queries/GetAllTransactionsByFilter/GetAllTransactionsByFilterResponseDto.cs @@ -24,4 +24,5 @@ public class GetAllTransactionsByFilterResponseDto public string? RefId { get; set; } // public TransactionType Type { get; set; } + public DateTime Created { get; set; } } diff --git a/src/CMSMicroservice.Application/TransactionsCQ/Queries/GetAllTransactionsByFilter/TransactionFilterExtensions.cs b/src/CMSMicroservice.Application/TransactionsCQ/Queries/GetAllTransactionsByFilter/TransactionFilterExtensions.cs new file mode 100644 index 0000000..06dd97f --- /dev/null +++ b/src/CMSMicroservice.Application/TransactionsCQ/Queries/GetAllTransactionsByFilter/TransactionFilterExtensions.cs @@ -0,0 +1,48 @@ +using CMSMicroservice.Domain.Entities; + +namespace CMSMicroservice.Application.TransactionsCQ.Queries.GetAllTransactionsByFilter; + +public static class TransactionFilterExtensions +{ + public static IQueryable ApplyTransactionFilter( + this IQueryable query, + GetAllTransactionsByFilterFilter? filter) + { + if (filter == null) return query; + + if (filter.Id.HasValue) + query = query.Where(x => x.Id == filter.Id.Value); + + if (filter.Amount.HasValue) + query = query.Where(x => x.Amount == filter.Amount.Value); + + if (!string.IsNullOrWhiteSpace(filter.Description)) + query = query.Where(x => x.Description.Contains(filter.Description)); + + if (filter.PaymentStatus.HasValue) + query = query.Where(x => x.PaymentStatus == filter.PaymentStatus.Value); + + if (filter.PaymentDate.HasValue) + query = query.Where(x => x.PaymentDate == filter.PaymentDate.Value); + + if (!string.IsNullOrWhiteSpace(filter.RefId)) + query = query.Where(x => x.RefId != null && x.RefId.Contains(filter.RefId)); + + if (filter.Type.HasValue) + query = query.Where(x => x.Type == filter.Type.Value); + + if (filter.CreatedFrom.HasValue) + query = query.Where(x => x.Created >= filter.CreatedFrom.Value); + + if (filter.CreatedTo.HasValue) + query = query.Where(x => x.Created <= filter.CreatedTo.Value); + + if (filter.PaymentDateFrom.HasValue) + query = query.Where(x => x.PaymentDate >= filter.PaymentDateFrom.Value); + + if (filter.PaymentDateTo.HasValue) + query = query.Where(x => x.PaymentDate <= filter.PaymentDateTo.Value); + + return query; + } +} diff --git a/src/CMSMicroservice.Application/TransactionsCQ/Queries/GetTransactionSummary/GetTransactionSummaryQuery.cs b/src/CMSMicroservice.Application/TransactionsCQ/Queries/GetTransactionSummary/GetTransactionSummaryQuery.cs new file mode 100644 index 0000000..05c24bf --- /dev/null +++ b/src/CMSMicroservice.Application/TransactionsCQ/Queries/GetTransactionSummary/GetTransactionSummaryQuery.cs @@ -0,0 +1,17 @@ +using CMSMicroservice.Application.TransactionsCQ.Queries.GetAllTransactionsByFilter; + +namespace CMSMicroservice.Application.TransactionsCQ.Queries.GetTransactionSummary; + +public record GetTransactionSummaryQuery : IRequest +{ + public GetAllTransactionsByFilterFilter? Filter { get; init; } +} + +public class GetTransactionSummaryResponseDto +{ + public long TotalCount { get; set; } + public long TotalAmount { get; set; } + public long SuccessCount { get; set; } + public long PendingCount { get; set; } + public long RejectCount { get; set; } +} diff --git a/src/CMSMicroservice.Application/TransactionsCQ/Queries/GetTransactionSummary/GetTransactionSummaryQueryHandler.cs b/src/CMSMicroservice.Application/TransactionsCQ/Queries/GetTransactionSummary/GetTransactionSummaryQueryHandler.cs new file mode 100644 index 0000000..08bc11f --- /dev/null +++ b/src/CMSMicroservice.Application/TransactionsCQ/Queries/GetTransactionSummary/GetTransactionSummaryQueryHandler.cs @@ -0,0 +1,39 @@ +using CMSMicroservice.Application.TransactionsCQ.Queries.GetAllTransactionsByFilter; +using CMSMicroservice.Domain.Enums; + +namespace CMSMicroservice.Application.TransactionsCQ.Queries.GetTransactionSummary; + +public class GetTransactionSummaryQueryHandler + : IRequestHandler +{ + private readonly IApplicationDbContext _context; + + public GetTransactionSummaryQueryHandler(IApplicationDbContext context) + { + _context = context; + } + + public async Task Handle( + GetTransactionSummaryQuery request, + CancellationToken cancellationToken) + { + var query = _context.Transactions + .AsNoTracking() + .ApplyTransactionFilter(request.Filter); + + var totalCount = await query.LongCountAsync(cancellationToken); + var totalAmount = totalCount > 0 ? await query.SumAsync(x => x.Amount, cancellationToken) : 0; + var successCount = await query.LongCountAsync(x => x.PaymentStatus == PaymentStatus.Success, cancellationToken); + var pendingCount = await query.LongCountAsync(x => x.PaymentStatus == PaymentStatus.Pending, cancellationToken); + var rejectCount = await query.LongCountAsync(x => x.PaymentStatus == PaymentStatus.Reject, cancellationToken); + + return new GetTransactionSummaryResponseDto + { + TotalCount = totalCount, + TotalAmount = totalAmount, + SuccessCount = successCount, + PendingCount = pendingCount, + RejectCount = rejectCount + }; + } +} diff --git a/src/CMSMicroservice.Protobuf/CMSMicroservice.Protobuf.csproj b/src/CMSMicroservice.Protobuf/CMSMicroservice.Protobuf.csproj index b403094..911d4c6 100644 --- a/src/CMSMicroservice.Protobuf/CMSMicroservice.Protobuf.csproj +++ b/src/CMSMicroservice.Protobuf/CMSMicroservice.Protobuf.csproj @@ -3,7 +3,7 @@ net9.0 enable enable - 0.0.202 + 0.0.203 None False False diff --git a/src/CMSMicroservice.Protobuf/Protos/public_messages.proto b/src/CMSMicroservice.Protobuf/Protos/public_messages.proto index 095918c..a3c55c6 100644 --- a/src/CMSMicroservice.Protobuf/Protos/public_messages.proto +++ b/src/CMSMicroservice.Protobuf/Protos/public_messages.proto @@ -109,6 +109,13 @@ enum TransactionType DepositIpg = 1; DepositExternal1 = 2; Withdraw = 3; + NetworkCommission = 10; + ClubActivation = 11; + DiscountWalletCharge = 12; + DiscountShopPurchase = 13; + MagicWalletDeposit = 14; + MagicWalletBonus = 15; + CreditWalletCharge = 16; } enum ContractType { diff --git a/src/CMSMicroservice.Protobuf/Protos/transactions.proto b/src/CMSMicroservice.Protobuf/Protos/transactions.proto index 2255bac..07a78ff 100644 --- a/src/CMSMicroservice.Protobuf/Protos/transactions.proto +++ b/src/CMSMicroservice.Protobuf/Protos/transactions.proto @@ -43,6 +43,11 @@ service TransactionsContract }; }; + rpc GetTransactionSummary(GetTransactionSummaryRequest) returns (GetTransactionSummaryResponse){ + option (google.api.http) = { + get: "/GetTransactionSummary" + }; + }; rpc VerifyTransaction(VerifyTransactionRequest) returns (VerifyTransactionResponse){ option (google.api.http) = { post: "/VerifyTransaction" @@ -161,6 +166,10 @@ message GetAllTransactionsByFilterFilter { messages.TransactionType type = 7; } + google.protobuf.Timestamp created_from = 8; + google.protobuf.Timestamp created_to = 9; + google.protobuf.Timestamp payment_date_from = 10; + google.protobuf.Timestamp payment_date_to = 11; } message GetAllTransactionsByFilterResponse { @@ -182,6 +191,21 @@ message GetAllTransactionsByFilterResponseModel { messages.TransactionType type = 7; } + google.protobuf.Timestamp created = 8; +} + +message GetTransactionSummaryRequest +{ + GetAllTransactionsByFilterFilter filter = 1; +} + +message GetTransactionSummaryResponse +{ + int64 total_count = 1; + int64 total_amount = 2; + int64 success_count = 3; + int64 pending_count = 4; + int64 reject_count = 5; } // VerifyTransaction Messages diff --git a/src/CMSMicroservice.WebApi/Common/Mappings/TransactionsProfile.cs b/src/CMSMicroservice.WebApi/Common/Mappings/TransactionsProfile.cs index 34689ba..f9228ad 100644 --- a/src/CMSMicroservice.WebApi/Common/Mappings/TransactionsProfile.cs +++ b/src/CMSMicroservice.WebApi/Common/Mappings/TransactionsProfile.cs @@ -1,11 +1,55 @@ +using Google.Protobuf.WellKnownTypes; +using Mapster; +using AppTx = CMSMicroservice.Application.TransactionsCQ.Queries.GetAllTransactionsByFilter; +using AppTxSummary = CMSMicroservice.Application.TransactionsCQ.Queries.GetTransactionSummary; +using ProtoTx = CMSMicroservice.Protobuf.Protos.Transactions; + namespace CMSMicroservice.WebApi.Common.Mappings; public class TransactionsProfile : IRegister { - void IRegister.Register(TypeAdapterConfig config) - { - config.NewConfig() - .IgnoreIf((src, dest) => !src.Filter.HasPaymentStatus, dest => dest.Filter.PaymentStatus) - .IgnoreIf((src, dest) => !src.Filter.HasType, dest => dest.Filter.Type); + public void Register(TypeAdapterConfig config) + { + config.NewConfig() + .Map(dest => dest.PaginationState, src => src.PaginationState) + .Map(dest => dest.SortBy, src => src.SortBy) + .Map(dest => dest.Filter, src => src.Filter); + + config.NewConfig() + .Map(dest => dest.Id, src => src.Id) + .Map(dest => dest.Amount, src => src.Amount) + .Map(dest => dest.Description, src => src.Description) + .Map(dest => dest.PaymentStatus, src => src.HasPaymentStatus ? (Domain.Enums.PaymentStatus?)src.PaymentStatus : null) + .Map(dest => dest.PaymentDate, src => src.PaymentDate != null ? src.PaymentDate.ToDateTime() : (DateTime?)null) + .Map(dest => dest.RefId, src => src.RefId) + .Map(dest => dest.Type, src => src.HasType ? (Domain.Enums.TransactionType?)src.Type : null) + .Map(dest => dest.CreatedFrom, src => src.CreatedFrom != null ? src.CreatedFrom.ToDateTime() : (DateTime?)null) + .Map(dest => dest.CreatedTo, src => src.CreatedTo != null ? src.CreatedTo.ToDateTime() : (DateTime?)null) + .Map(dest => dest.PaymentDateFrom, src => src.PaymentDateFrom != null ? src.PaymentDateFrom.ToDateTime() : (DateTime?)null) + .Map(dest => dest.PaymentDateTo, src => src.PaymentDateTo != null ? src.PaymentDateTo.ToDateTime() : (DateTime?)null); + + config.NewConfig() + .Map(dest => dest.MetaData, src => src.MetaData) + .Map(dest => dest.Models, src => src.Models); + + config.NewConfig() + .Map(dest => dest.Id, src => src.Id) + .Map(dest => dest.Amount, src => src.Amount) + .Map(dest => dest.Description, src => src.Description) + .Map(dest => dest.PaymentStatus, src => src.PaymentStatus) + .Map(dest => dest.PaymentDate, src => src.PaymentDate.HasValue ? Timestamp.FromDateTime(DateTime.SpecifyKind(src.PaymentDate.Value, DateTimeKind.Utc)) : null) + .Map(dest => dest.RefId, src => src.RefId) + .Map(dest => dest.Type, src => src.Type) + .Map(dest => dest.Created, src => Timestamp.FromDateTime(DateTime.SpecifyKind(src.Created, DateTimeKind.Utc))); + + config.NewConfig() + .Map(dest => dest.Filter, src => src.Filter); + + config.NewConfig() + .Map(dest => dest.TotalCount, src => src.TotalCount) + .Map(dest => dest.TotalAmount, src => src.TotalAmount) + .Map(dest => dest.SuccessCount, src => src.SuccessCount) + .Map(dest => dest.PendingCount, src => src.PendingCount) + .Map(dest => dest.RejectCount, src => src.RejectCount); } } diff --git a/src/CMSMicroservice.WebApi/Services/TransactionsService.cs b/src/CMSMicroservice.WebApi/Services/TransactionsService.cs index c88b48b..96c1ade 100644 --- a/src/CMSMicroservice.WebApi/Services/TransactionsService.cs +++ b/src/CMSMicroservice.WebApi/Services/TransactionsService.cs @@ -5,6 +5,7 @@ using CMSMicroservice.Application.TransactionsCQ.Commands.UpdateTransactions; using CMSMicroservice.Application.TransactionsCQ.Commands.DeleteTransactions; using CMSMicroservice.Application.TransactionsCQ.Queries.GetTransactions; using CMSMicroservice.Application.TransactionsCQ.Queries.GetAllTransactionsByFilter; +using CMSMicroservice.Application.TransactionsCQ.Queries.GetTransactionSummary; using CMSMicroservice.Application.TransactionsCQ.Commands.VerifyTransaction; using CMSMicroservice.Application.TransactionsCQ.Commands.RefundTransaction; using CMSMicroservice.Application.TransactionsCQ.Queries.GetCustomerTransaction; @@ -69,6 +70,10 @@ public class TransactionsService : TransactionsContract.TransactionsContractBase { return await _dispatchRequestToCQRS.Handle(request, context); } + + public override Task GetTransactionSummary( + GetTransactionSummaryRequest request, ServerCallContext context) => + _dispatchRequestToCQRS.Handle(request, context); public override async Task VerifyTransaction(VerifyTransactionRequest request, ServerCallContext context) { From 89af07c1222df64f347d7ec4d476f513a2d6d2d3 Mon Sep 17 00:00:00 2001 From: masoodafar-web Date: Fri, 26 Jun 2026 17:12:43 +0330 Subject: [PATCH 7/8] feat(config): add CMS and Front Office base URLs to configuration files - Introduced CmsBaseUrl and FrontOfficeBaseUrl properties in both cms-config.yaml and appsettings.Staging.json for improved service integration. - Ensured consistency across configuration files for easier management of base URLs. --- k8s/staging/cms-config.yaml | 2 ++ src/CMSMicroservice.WebApi/appsettings.Staging.json | 2 ++ 2 files changed, 4 insertions(+) diff --git a/k8s/staging/cms-config.yaml b/k8s/staging/cms-config.yaml index 1acf1dd..5e213cd 100644 --- a/k8s/staging/cms-config.yaml +++ b/k8s/staging/cms-config.yaml @@ -24,6 +24,8 @@ stringData: "MerchantId": "4225d555-5fa9-4df0-9b61-1ce152cbbba8", "UseSandbox": true }, + "CmsBaseUrl": "https://cms.se.kbs1.ir", + "FrontOfficeBaseUrl": "https://kbs1.ir", "FMS": { "Address": "https://dl.afrino.co" }, diff --git a/src/CMSMicroservice.WebApi/appsettings.Staging.json b/src/CMSMicroservice.WebApi/appsettings.Staging.json index 8fdf2ca..175960c 100644 --- a/src/CMSMicroservice.WebApi/appsettings.Staging.json +++ b/src/CMSMicroservice.WebApi/appsettings.Staging.json @@ -4,6 +4,8 @@ "MerchantId": "4225d555-5fa9-4df0-9b61-1ce152cbbba8", "UseSandbox": true }, + "CmsBaseUrl": "https://cms.se.kbs1.ir", + "FrontOfficeBaseUrl": "https://kbs1.ir", "FMS": { "Address": "https://dl.afrino.co" }, From 728f28f5258bdab0c7449d5a2534e8e3acc97865 Mon Sep 17 00:00:00 2001 From: masoodafar-web Date: Fri, 26 Jun 2026 17:49:42 +0330 Subject: [PATCH 8/8] fix(config): update FrontOfficeBaseUrl in configuration files - Changed FrontOfficeBaseUrl from "https://kbs1.ir" to "https://frontoffice.se.kbs1.ir" in both cms-config.yaml and appsettings.Staging.json for consistency across environments. --- k8s/staging/cms-config.yaml | 2 +- src/CMSMicroservice.WebApi/appsettings.Staging.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/k8s/staging/cms-config.yaml b/k8s/staging/cms-config.yaml index 5e213cd..c9c5562 100644 --- a/k8s/staging/cms-config.yaml +++ b/k8s/staging/cms-config.yaml @@ -25,7 +25,7 @@ stringData: "UseSandbox": true }, "CmsBaseUrl": "https://cms.se.kbs1.ir", - "FrontOfficeBaseUrl": "https://kbs1.ir", + "FrontOfficeBaseUrl": "https://frontoffice.se.kbs1.ir", "FMS": { "Address": "https://dl.afrino.co" }, diff --git a/src/CMSMicroservice.WebApi/appsettings.Staging.json b/src/CMSMicroservice.WebApi/appsettings.Staging.json index 175960c..ba9c060 100644 --- a/src/CMSMicroservice.WebApi/appsettings.Staging.json +++ b/src/CMSMicroservice.WebApi/appsettings.Staging.json @@ -5,7 +5,7 @@ "UseSandbox": true }, "CmsBaseUrl": "https://cms.se.kbs1.ir", - "FrontOfficeBaseUrl": "https://kbs1.ir", + "FrontOfficeBaseUrl": "https://frontoffice.se.kbs1.ir", "FMS": { "Address": "https://dl.afrino.co" },