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.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 Grpc.Core; 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 CreateNewUserWallet(CreateNewUserWalletRequest request, ServerCallContext context) { return await _dispatchRequestToCQRS.Handle(request, context); } public override async Task UpdateUserWallet(UpdateUserWalletRequest request, ServerCallContext context) { return await _dispatchRequestToCQRS.Handle(request, context); } public override async Task DeleteUserWallet(DeleteUserWalletRequest request, ServerCallContext context) { return await _dispatchRequestToCQRS.Handle(request, context); } public override async Task GetUserWallet(GetUserWalletRequest request, ServerCallContext context) { return await _dispatchRequestToCQRS.Handle(request, context); } public override async Task GetAllUserWalletByFilter(GetAllUserWalletByFilterRequest request, ServerCallContext context) { return await _dispatchRequestToCQRS.Handle(request, context); } // ============= Customer-specific Methods ============= public override async Task 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); return new GetCustomerWalletResponse { Balance = wallet.Balance, NetworkBalance = wallet.NetworkBalance, DiscountBalance = wallet.DiscountBalance }; } public override async Task 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 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(); } 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 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 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 }; } }