52f6af2091
Build and Deploy to Kubernetes / build-and-deploy (push) Successful in 8m59s
- userwallet.proto: added string user_name = 5 to GetAllUserWalletByFilterResponseModel - UserWalletService: enriches response with user names from Users table - Proto version bumped to 0.0.183
308 lines
13 KiB
C#
308 lines
13 KiB
C#
using CMSMicroservice.Protobuf.Protos.UserWallet;
|
|
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.WalletCQ.Commands.ChargeDiscountWallet;
|
|
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;
|
|
|
|
namespace CMSMicroservice.WebApi.Services;
|
|
public class UserWalletService : UserWalletContract.UserWalletContractBase
|
|
{
|
|
private readonly IDispatchRequestToCQRS _dispatchRequestToCQRS;
|
|
private readonly ISender _sender;
|
|
private readonly IApplicationDbContext _context;
|
|
private readonly ICurrentUserService _currentUserService;
|
|
|
|
public UserWalletService(
|
|
IDispatchRequestToCQRS dispatchRequestToCQRS,
|
|
ISender sender,
|
|
IApplicationDbContext context,
|
|
ICurrentUserService currentUserService)
|
|
{
|
|
_dispatchRequestToCQRS = dispatchRequestToCQRS;
|
|
_sender = sender;
|
|
_context = context;
|
|
_currentUserService = currentUserService;
|
|
}
|
|
public override async Task<CreateNewUserWalletResponse> CreateNewUserWallet(CreateNewUserWalletRequest request, ServerCallContext context)
|
|
{
|
|
return await _dispatchRequestToCQRS.Handle<CreateNewUserWalletRequest, CreateNewUserWalletCommand, CreateNewUserWalletResponse>(request, context);
|
|
}
|
|
public override async Task<Empty> UpdateUserWallet(UpdateUserWalletRequest request, ServerCallContext context)
|
|
{
|
|
return await _dispatchRequestToCQRS.Handle<UpdateUserWalletRequest, UpdateUserWalletCommand>(request, context);
|
|
}
|
|
public override async Task<Empty> DeleteUserWallet(DeleteUserWalletRequest request, ServerCallContext context)
|
|
{
|
|
return await _dispatchRequestToCQRS.Handle<DeleteUserWalletRequest, DeleteUserWalletCommand>(request, context);
|
|
}
|
|
public override async Task<GetUserWalletResponse> GetUserWallet(GetUserWalletRequest request, ServerCallContext context)
|
|
{
|
|
return await _dispatchRequestToCQRS.Handle<GetUserWalletRequest, GetUserWalletQuery, GetUserWalletResponse>(request, context);
|
|
}
|
|
public override async Task<GetAllUserWalletByFilterResponse> GetAllUserWalletByFilter(GetAllUserWalletByFilterRequest request, ServerCallContext context)
|
|
{
|
|
var response = await _dispatchRequestToCQRS.Handle<GetAllUserWalletByFilterRequest, GetAllUserWalletByFilterQuery, GetAllUserWalletByFilterResponse>(request, context);
|
|
|
|
// Enrich response with user names
|
|
if (response?.Models != null && response.Models.Any())
|
|
{
|
|
var userIds = response.Models.Select(m => m.UserId).Distinct().ToList();
|
|
var users = await _context.Users
|
|
.AsNoTracking()
|
|
.Where(u => userIds.Contains(u.Id))
|
|
.Select(u => new { u.Id, u.FirstName, u.LastName })
|
|
.ToDictionaryAsync(u => u.Id, context.CancellationToken);
|
|
|
|
foreach (var model in response.Models)
|
|
{
|
|
if (users.TryGetValue(model.UserId, out var user))
|
|
{
|
|
model.UserName = $"{user.FirstName} {user.LastName}".Trim();
|
|
}
|
|
}
|
|
}
|
|
|
|
return response;
|
|
}
|
|
|
|
// ============= Customer-specific Methods =============
|
|
|
|
public override async Task<GetCustomerWalletResponse> GetCustomerWallet(Google.Protobuf.WellKnownTypes.Empty request, ServerCallContext context)
|
|
{
|
|
// Customer endpoint: resolve userId from JWT
|
|
if (!long.TryParse(_currentUserService.UserId, out var userId) || userId <= 0)
|
|
throw new RpcException(new Status(StatusCode.Unauthenticated, "کاربر احراز هویت نشده است"));
|
|
|
|
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,
|
|
WalletMode = (int)(walletEntity?.WalletMode ?? WalletMode.Normal)
|
|
};
|
|
}
|
|
|
|
public override async Task<GetCustomerWalletChangeLogResponse> GetCustomerWalletChangeLog(GetCustomerWalletChangeLogRequest request, ServerCallContext context)
|
|
{
|
|
var query = new GetCustomerWalletChangeLogQuery
|
|
{
|
|
ReferenceId = request.ReferenceId,
|
|
IsIncrease = request.IsIncrease
|
|
};
|
|
|
|
var changeLogs = await _sender.Send(query, context.CancellationToken);
|
|
|
|
var response = new GetCustomerWalletChangeLogResponse
|
|
{
|
|
MetaData = new CMSMicroservice.Protobuf.Protos.MetaData
|
|
{
|
|
CurrentPage = 1,
|
|
TotalPage = 1,
|
|
PageSize = changeLogs.Count,
|
|
TotalCount = changeLogs.Count,
|
|
HasPrevious = false,
|
|
HasNext = false
|
|
}
|
|
};
|
|
|
|
foreach (var log in changeLogs)
|
|
{
|
|
response.Models.Add(new CustomerWalletChangeLogModel
|
|
{
|
|
CurrentBalance = log.CurrentBalance,
|
|
ChangeValue = log.ChangeValue,
|
|
CurrentNetworkBalance = log.CurrentNetworkBalance,
|
|
ChangeNerworkValue = log.ChangeNerworkValue,
|
|
CurrentDiscountBalance = log.CurrentDiscountBalance,
|
|
ChangeDiscountValue = log.ChangeDiscountValue,
|
|
IsIncrease = log.IsIncrease,
|
|
RefrenceId = log.RefrenceId,
|
|
CreatedAt = Google.Protobuf.WellKnownTypes.Timestamp.FromDateTime(DateTime.SpecifyKind(log.Created, DateTimeKind.Utc))
|
|
});
|
|
}
|
|
|
|
return response;
|
|
}
|
|
|
|
public override async Task<Google.Protobuf.WellKnownTypes.Empty> CustomerWithdrawBalance(CustomerWithdrawBalanceRequest request, ServerCallContext context)
|
|
{
|
|
var userId = GetCurrentUserId();
|
|
|
|
// Find the commission payout record
|
|
var payout = await _context.UserCommissionPayouts
|
|
.Where(p => p.Id == request.PayoutId && p.UserId == userId && !p.IsDeleted)
|
|
.FirstOrDefaultAsync(context.CancellationToken);
|
|
|
|
if (payout == null)
|
|
throw new RpcException(new Status(StatusCode.NotFound, "رکورد پرداخت کمیسیون یافت نشد"));
|
|
|
|
// Validate status - can only withdraw if already paid to wallet
|
|
if (payout.Status != Domain.Enums.CommissionPayoutStatus.Paid)
|
|
throw new RpcException(new Status(StatusCode.FailedPrecondition,
|
|
"فقط کمیسیونهای واریز شده به کیف پول قابل برداشت هستند"));
|
|
|
|
// Update payout with withdrawal info
|
|
payout.WithdrawalMethod = (Domain.Enums.WithdrawalMethod)request.WithdrawalMethod;
|
|
payout.IbanNumber = request.IbanNumber;
|
|
payout.Status = Domain.Enums.CommissionPayoutStatus.WithdrawRequested;
|
|
|
|
await _context.SaveChangesAsync(context.CancellationToken);
|
|
|
|
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 ?? ""
|
|
};
|
|
}
|
|
|
|
// ============= Discount Wallet Methods =============
|
|
|
|
public override async Task<InitiateDiscountChargeResponse> InitiateDiscountCharge(
|
|
InitiateDiscountChargeRequest request, ServerCallContext context)
|
|
{
|
|
var userId = GetCurrentUserId();
|
|
|
|
var result = await _sender.Send(new ChargeDiscountWalletCommand
|
|
{
|
|
UserId = userId,
|
|
Amount = request.Amount
|
|
}, context.CancellationToken);
|
|
|
|
return new InitiateDiscountChargeResponse
|
|
{
|
|
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 cycleCount = await _context.ClubMembershipCycles
|
|
.CountAsync(c => c.UserId == userId, context.CancellationToken);
|
|
|
|
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,
|
|
PurchaseCycleCount = cycleCount
|
|
};
|
|
|
|
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)
|
|
return userId;
|
|
throw new RpcException(new Status(StatusCode.Unauthenticated, "لطفاً وارد حساب کاربری خود شوید"));
|
|
}
|
|
|
|
public override async Task<GetCustomerWithdrawalsResponse> GetCustomerWithdrawals(GetCustomerWithdrawalsRequest request, ServerCallContext context)
|
|
{
|
|
var query = new GetCustomerWithdrawalsQuery
|
|
{
|
|
Status = request.Status
|
|
};
|
|
|
|
var withdrawals = await _sender.Send(query, context.CancellationToken);
|
|
|
|
var response = new GetCustomerWithdrawalsResponse
|
|
{
|
|
MetaData = new CMSMicroservice.Protobuf.Protos.MetaData
|
|
{
|
|
CurrentPage = 1,
|
|
TotalPage = 1,
|
|
PageSize = withdrawals.Count,
|
|
TotalCount = withdrawals.Count,
|
|
HasPrevious = false,
|
|
HasNext = false
|
|
}
|
|
};
|
|
|
|
foreach (var withdrawal in withdrawals)
|
|
{
|
|
response.Models.Add(new CustomerWithdrawalModel
|
|
{
|
|
Id = withdrawal.Id,
|
|
WeekDefinitionId = withdrawal.WeekDefinitionId,
|
|
WeekDisplayName = withdrawal.WeekDisplayName,
|
|
TotalAmount = withdrawal.TotalAmount,
|
|
Status = withdrawal.Status,
|
|
WithdrawalMethod = withdrawal.WithdrawalMethod,
|
|
IbanNumber = withdrawal.IbanNumber,
|
|
Created = Google.Protobuf.WellKnownTypes.Timestamp.FromDateTime(DateTime.SpecifyKind(withdrawal.Created, DateTimeKind.Utc))
|
|
});
|
|
}
|
|
|
|
return response;
|
|
}
|
|
|
|
public override async Task<GetCustomerWithdrawalSettingsResponse> GetCustomerWithdrawalSettings(Google.Protobuf.WellKnownTypes.Empty request, ServerCallContext context)
|
|
{
|
|
var query = new GetCustomerWithdrawalSettingsQuery();
|
|
var settings = await _sender.Send(query, context.CancellationToken);
|
|
|
|
return new GetCustomerWithdrawalSettingsResponse
|
|
{
|
|
MinWithdrawalAmount = settings.MinWithdrawalAmount
|
|
};
|
|
}
|
|
}
|