feat: Implement Magic Wallet functionality
Build and Deploy to Kubernetes / build-and-deploy (push) Successful in 8m36s

- Added ClubMembershipCycle entity and DbSet to IApplicationDbContext.
- Updated VAT rate from 9% to 10% in VatCalculator and related areas.
- Introduced Magic Wallet settings in SystemConstants.
- Enhanced UserWallet entity to support Magic Wallet features.
- Updated TransactionType enum to include Magic Wallet transactions.
- Configured UserWallet to handle Magic Wallet properties in ApplicationDbContext.
- Implemented OrmCommissionCalculationStrategy to exclude Magic Wallet users from commission calculations.
- Added Protobuf definitions for Magic Wallet methods and responses.
- Created PaymentCallbackController endpoint for handling Magic Wallet charge callbacks.
- Updated UserOrderService to manage Magic Wallet state transitions.
- Developed UserWalletService to support Magic Wallet operations.
- Created ChargeMagicWalletCommand and its handler for initiating Magic Wallet charges.
- Implemented VerifyMagicWalletChargeCommand and handler for payment verification.
- Added validation for ChargeMagicWalletCommand.
- Established ClubMembershipCycle configuration for EF Core.
- Introduced WalletMode enum to differentiate between Normal and Magic modes.
This commit is contained in:
masoodafar-web
2026-02-21 19:50:28 +03:30
parent 04e8c49fa7
commit 2a569a024f
23 changed files with 914 additions and 22 deletions
@@ -3,13 +3,17 @@ using CMSMicroservice.WebApi.Common.Services;
using CMSMicroservice.Application.UserWalletCQ.Commands.CreateNewUserWallet;
using CMSMicroservice.Application.UserWalletCQ.Commands.UpdateUserWallet;
using CMSMicroservice.Application.UserWalletCQ.Commands.DeleteUserWallet;
using CMSMicroservice.Application.WalletCQ.Commands.ChargeMagicWallet;
using CMSMicroservice.Application.UserWalletCQ.Queries.GetUserWallet;
using CMSMicroservice.Application.UserWalletCQ.Queries.GetAllUserWalletByFilter;
using CMSMicroservice.Application.UserWalletCQ.Queries.GetCustomerWalletChangeLog;
using CMSMicroservice.Application.UserWalletCQ.Queries.GetCustomerWithdrawals;
using CMSMicroservice.Application.UserWalletCQ.Queries.GetCustomerWithdrawalSettings;
using CMSMicroservice.Application.Common.Interfaces;
using CMSMicroservice.Domain.Common;
using CMSMicroservice.Domain.Enums;
using Grpc.Core;
using Google.Protobuf.WellKnownTypes;
using Microsoft.EntityFrameworkCore;
using System.Linq;
@@ -64,11 +68,15 @@ public class UserWalletService : UserWalletContract.UserWalletContractBase
var walletQuery = new GetUserWalletQuery { Id = userId };
var wallet = await _sender.Send(walletQuery, context.CancellationToken);
var walletEntity = await _context.UserWallets
.FirstOrDefaultAsync(w => w.UserId == userId, context.CancellationToken);
return new GetCustomerWalletResponse
{
Balance = wallet.Balance,
NetworkBalance = wallet.NetworkBalance,
DiscountBalance = wallet.DiscountBalance
DiscountBalance = wallet.DiscountBalance,
WalletMode = (int)(walletEntity?.WalletMode ?? WalletMode.Normal)
};
}
@@ -141,6 +149,57 @@ public class UserWalletService : UserWalletContract.UserWalletContractBase
return new Google.Protobuf.WellKnownTypes.Empty();
}
// ============= Magic Wallet Methods =============
public override async Task<InitiateMagicChargeResponse> InitiateMagicCharge(
InitiateMagicChargeRequest request, ServerCallContext context)
{
var userId = GetCurrentUserId();
var result = await _sender.Send(new ChargeMagicWalletCommand
{
UserId = userId,
Amount = request.Amount
}, context.CancellationToken);
return new InitiateMagicChargeResponse
{
IsSuccess = result.IsSuccess,
GatewayUrl = result.GatewayUrl ?? "",
ErrorMessage = result.ErrorMessage ?? ""
};
}
public override async Task<GetMagicWalletStatusResponse> GetMagicWalletStatus(
Google.Protobuf.WellKnownTypes.Empty request, ServerCallContext context)
{
var userId = GetCurrentUserId();
var wallet = await _context.UserWallets
.FirstOrDefaultAsync(w => w.UserId == userId, context.CancellationToken);
if (wallet == null)
throw new RpcException(new Status(StatusCode.NotFound, "کیف پول یافت نشد"));
var response = new GetMagicWalletStatusResponse
{
WalletMode = (int)wallet.WalletMode,
MagicTotalDeposited = wallet.MagicTotalDeposited,
MagicTotalCredited = wallet.MagicTotalCredited,
MagicMaxDeposit = SystemConstants.MagicWalletMaxDeposit,
MagicRemainingDeposit = Math.Max(0, SystemConstants.MagicWalletMaxDeposit - wallet.MagicTotalDeposited),
Balance = wallet.Balance
};
if (wallet.MagicActivatedAt.HasValue)
{
response.MagicActivatedAt = Timestamp.FromDateTime(
DateTime.SpecifyKind(wallet.MagicActivatedAt.Value, DateTimeKind.Utc));
}
return response;
}
private long GetCurrentUserId()
{
if (long.TryParse(_currentUserService.UserId, out var userId) && userId > 0)