2d23dbc798
Build and Deploy to Kubernetes / build-and-deploy (push) Successful in 6m38s
- Added IbanNormalizer to validate and normalize IBAN numbers in RequestWithdrawalCommandHandler and UserWalletService. - Implemented error handling for invalid IBAN formats, ensuring compliance with expected standards. - Updated relevant methods to handle normalized IBANs for cash withdrawal requests.
657 lines
27 KiB
C#
657 lines
27 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.WalletCQ.Commands.ChargeCreditWallet;
|
|
using CMSMicroservice.Application.WalletCQ.Commands.VerifyMagicWalletCharge;
|
|
using CMSMicroservice.Application.WalletCQ.Commands.VerifyDiscountWalletCharge;
|
|
using CMSMicroservice.Application.WalletCQ.Commands.VerifyCreditWalletCharge;
|
|
using CMSMicroservice.Application.WalletCQ.Commands.AdminManualCreditCharge;
|
|
using CMSMicroservice.Application.WalletCQ.Queries.GetManualCreditCharges;
|
|
using AppManualChargeFilter = CMSMicroservice.Application.WalletCQ.Queries.GetManualCreditCharges.GetManualCreditChargesFilter;
|
|
using CMSMicroservice.Application.UserWalletCQ.Queries.GetUserWallet;
|
|
using CMSMicroservice.Application.UserWalletCQ.Queries.GetAllUserWalletByFilter;
|
|
using CMSMicroservice.Application.UserWalletCQ.Queries.GetCustomerWalletHistory;
|
|
using CMSMicroservice.Application.UserWalletCQ.Queries.GetCustomerWithdrawals;
|
|
using CMSMicroservice.Application.UserWalletCQ.Queries.GetCustomerWithdrawalSettings;
|
|
using CMSMicroservice.Application.Common.Interfaces;
|
|
using CMSMicroservice.Application.Common;
|
|
using CMSMicroservice.Application.Common.Exceptions;
|
|
using CMSMicroservice.Domain.Common;
|
|
using CMSMicroservice.Domain.Enums;
|
|
using Grpc.Core;
|
|
using Google.Protobuf.WellKnownTypes;
|
|
using Microsoft.EntityFrameworkCore;
|
|
using Microsoft.Extensions.Logging;
|
|
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;
|
|
private readonly ILogger<UserWalletService> _logger;
|
|
|
|
public UserWalletService(
|
|
IDispatchRequestToCQRS dispatchRequestToCQRS,
|
|
ISender sender,
|
|
IApplicationDbContext context,
|
|
ICurrentUserService currentUserService,
|
|
ILogger<UserWalletService> logger)
|
|
{
|
|
_dispatchRequestToCQRS = dispatchRequestToCQRS;
|
|
_sender = sender;
|
|
_context = context;
|
|
_currentUserService = currentUserService;
|
|
_logger = logger;
|
|
}
|
|
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<GetCustomerWalletHistoryResponse> GetCustomerWalletHistory(GetCustomerWalletHistoryRequest request, ServerCallContext context)
|
|
{
|
|
var query = new GetCustomerWalletHistoryQuery
|
|
{
|
|
ReferenceId = request.ReferenceId,
|
|
IsIncrease = request.IsIncrease
|
|
};
|
|
|
|
var changeLogs = await _sender.Send(query, context.CancellationToken);
|
|
|
|
var response = new GetCustomerWalletHistoryResponse
|
|
{
|
|
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 CustomerWalletHistoryModel
|
|
{
|
|
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;
|
|
if (payout.WithdrawalMethod == Domain.Enums.WithdrawalMethod.Cash)
|
|
{
|
|
var normalizedIban = IbanNormalizer.TryNormalize(request.IbanNumber);
|
|
if (normalizedIban is null)
|
|
throw new RpcException(new Status(StatusCode.InvalidArgument,
|
|
"فرمت شماره شبا معتبر نیست. باید IR و ۲۴ رقم باشد."));
|
|
payout.IbanNumber = normalizedIban;
|
|
}
|
|
else
|
|
{
|
|
payout.IbanNumber = null;
|
|
}
|
|
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();
|
|
|
|
try
|
|
{
|
|
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 ?? ""
|
|
};
|
|
}
|
|
catch (PaymentInProgressException ex)
|
|
{
|
|
return new InitiateMagicChargeResponse
|
|
{
|
|
IsSuccess = false,
|
|
ErrorMessage = ex.Message
|
|
};
|
|
}
|
|
}
|
|
|
|
// ============= Discount Wallet Methods =============
|
|
|
|
public override async Task<InitiateDiscountChargeResponse> InitiateDiscountCharge(
|
|
InitiateDiscountChargeRequest request, ServerCallContext context)
|
|
{
|
|
var userId = GetCurrentUserId();
|
|
|
|
try
|
|
{
|
|
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 ?? ""
|
|
};
|
|
}
|
|
catch (PaymentInProgressException ex)
|
|
{
|
|
return new InitiateDiscountChargeResponse
|
|
{
|
|
IsSuccess = false,
|
|
ErrorMessage = ex.Message
|
|
};
|
|
}
|
|
}
|
|
|
|
// ============= Credit (Main) Wallet Methods =============
|
|
|
|
public override async Task<InitiateCreditChargeResponse> 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
|
|
};
|
|
}
|
|
catch (BadRequestException ex)
|
|
{
|
|
return new InitiateCreditChargeResponse
|
|
{
|
|
IsSuccess = false,
|
|
ErrorMessage = ex.Message
|
|
};
|
|
}
|
|
}
|
|
|
|
// ============= Wallet Verify Methods =============
|
|
|
|
public override async Task<VerifyWalletChargeResponse> VerifyMagicCharge(
|
|
VerifyWalletChargeRequest request, ServerCallContext context)
|
|
{
|
|
_logger.LogInformation("VerifyMagicCharge called: Authority={Authority}, Status={Status}",
|
|
request.Authority, request.Status);
|
|
|
|
try
|
|
{
|
|
if (string.IsNullOrEmpty(request.Authority))
|
|
return new VerifyWalletChargeResponse { Success = false, Message = "کد Authority نامعتبر است" };
|
|
|
|
var result = await _sender.Send(new VerifyMagicWalletChargeCommand
|
|
{
|
|
Authority = request.Authority,
|
|
Status = request.Status ?? "NOK"
|
|
}, context.CancellationToken);
|
|
|
|
_logger.LogInformation("VerifyMagicCharge result: {Result}, Authority={Authority}", result, request.Authority);
|
|
|
|
return new VerifyWalletChargeResponse
|
|
{
|
|
Success = result,
|
|
Message = result
|
|
? "شارژ کیفپول جادویی با موفقیت انجام شد"
|
|
: "شارژ کیفپول جادویی ناموفق بود"
|
|
};
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogError(ex, "VerifyMagicCharge error: Authority={Authority}", request.Authority);
|
|
return new VerifyWalletChargeResponse { Success = false, Message = ex.Message };
|
|
}
|
|
}
|
|
|
|
public override async Task<VerifyWalletChargeResponse> VerifyDiscountCharge(
|
|
VerifyWalletChargeRequest request, ServerCallContext context)
|
|
{
|
|
_logger.LogInformation("VerifyDiscountCharge called: Authority={Authority}, Status={Status}",
|
|
request.Authority, request.Status);
|
|
|
|
try
|
|
{
|
|
if (string.IsNullOrEmpty(request.Authority))
|
|
return new VerifyWalletChargeResponse { Success = false, Message = "کد Authority نامعتبر است" };
|
|
|
|
// پیدا کردن PaymentTransaction برای استخراج UserId و Amount
|
|
var paymentTx = await _context.PaymentTransactions
|
|
.FirstOrDefaultAsync(pt => pt.Authority == request.Authority, context.CancellationToken);
|
|
|
|
if (paymentTx == null || !paymentTx.UserId.HasValue)
|
|
{
|
|
_logger.LogError("VerifyDiscountCharge: PaymentTransaction not found for Authority={Authority}", request.Authority);
|
|
return new VerifyWalletChargeResponse { Success = false, Message = "تراکنش یافت نشد" };
|
|
}
|
|
|
|
if (!string.Equals(request.Status, "OK", StringComparison.OrdinalIgnoreCase))
|
|
{
|
|
_logger.LogWarning("VerifyDiscountCharge: Payment cancelled by user. Authority={Authority}", request.Authority);
|
|
return new VerifyWalletChargeResponse { Success = false, Message = "پرداخت توسط کاربر لغو شد" };
|
|
}
|
|
|
|
var result = await _sender.Send(new VerifyDiscountWalletChargeCommand
|
|
{
|
|
UserId = paymentTx.UserId.Value,
|
|
Amount = paymentTx.Amount,
|
|
Authority = request.Authority
|
|
}, context.CancellationToken);
|
|
|
|
_logger.LogInformation("VerifyDiscountCharge 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, "VerifyDiscountCharge error: Authority={Authority}", request.Authority);
|
|
return new VerifyWalletChargeResponse { Success = false, Message = ex.Message };
|
|
}
|
|
}
|
|
|
|
public override async Task<VerifyWalletChargeResponse> 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<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 currentCycle = await _context.ClubMembershipCycles
|
|
.FirstOrDefaultAsync(c => c.UserId == userId && c.IsCurrentCycle, context.CancellationToken);
|
|
var package = currentCycle != null
|
|
? await _context.Packages.FirstOrDefaultAsync(p => p.Id == currentCycle.PackageId, context.CancellationToken)
|
|
: await _context.Packages.FirstOrDefaultAsync(p => p.IsBasePackage && !p.IsDeleted, context.CancellationToken);
|
|
var magicMaxDeposit = package?.MagicWalletMaxDeposit ?? SystemConstants.MagicWalletDefaultMaxDeposit;
|
|
var magicMultiplier = package != null ? (double)package.MagicWalletMultiplier : SystemConstants.MagicWalletDefaultMultiplier;
|
|
var magicMaxCredit = package?.MagicWalletMaxCredit ?? SystemConstants.MagicWalletDefaultMaxCredit;
|
|
|
|
var response = new GetMagicWalletStatusResponse
|
|
{
|
|
WalletMode = (int)wallet.WalletMode,
|
|
MagicTotalDeposited = wallet.MagicTotalDeposited,
|
|
MagicTotalCredited = wallet.MagicTotalCredited,
|
|
MagicMaxDeposit = magicMaxDeposit,
|
|
MagicRemainingDeposit = Math.Max(0, magicMaxDeposit - wallet.MagicTotalDeposited),
|
|
Balance = wallet.Balance,
|
|
PurchaseCycleCount = cycleCount,
|
|
MagicMultiplier = magicMultiplier,
|
|
MagicMaxCredit = magicMaxCredit
|
|
};
|
|
|
|
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
|
|
};
|
|
}
|
|
|
|
// ============= Admin Manual Credit Charge =============
|
|
|
|
public override async Task<AdminManualCreditChargeResponse> AdminManualCreditCharge(
|
|
AdminManualCreditChargeRequest request, ServerCallContext context)
|
|
{
|
|
try
|
|
{
|
|
var result = await _sender.Send(new AdminManualCreditChargeCommand
|
|
{
|
|
UserId = request.UserId,
|
|
Amount = request.Amount,
|
|
Note = request.Note,
|
|
PerformedByAdminId = _currentUserService.GetPerformedBy()
|
|
}, context.CancellationToken);
|
|
|
|
return new AdminManualCreditChargeResponse
|
|
{
|
|
Success = result.Success,
|
|
Message = result.Message ?? string.Empty,
|
|
TransactionId = result.TransactionId,
|
|
NewBalance = result.NewBalance
|
|
};
|
|
}
|
|
catch (PaymentInProgressException ex)
|
|
{
|
|
return new AdminManualCreditChargeResponse
|
|
{
|
|
Success = false,
|
|
Message = ex.Message
|
|
};
|
|
}
|
|
catch (NotFoundException ex)
|
|
{
|
|
return new AdminManualCreditChargeResponse
|
|
{
|
|
Success = false,
|
|
Message = ex.Message
|
|
};
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogError(ex, "AdminManualCreditCharge failed for UserId={UserId}", request.UserId);
|
|
return new AdminManualCreditChargeResponse
|
|
{
|
|
Success = false,
|
|
Message = ex.Message
|
|
};
|
|
}
|
|
}
|
|
|
|
public override async Task<GetManualCreditChargesResponse> GetManualCreditCharges(
|
|
GetManualCreditChargesRequest request, ServerCallContext context)
|
|
{
|
|
var result = await _sender.Send(new GetManualCreditChargesQuery
|
|
{
|
|
SortBy = request.SortBy,
|
|
PaginationState = request.PaginationState != null
|
|
? new Application.Common.Models.PaginationState
|
|
{
|
|
PageNumber = request.PaginationState.PageNumber,
|
|
PageSize = request.PaginationState.PageSize
|
|
}
|
|
: new Application.Common.Models.PaginationState { PageNumber = 1, PageSize = 20 },
|
|
Filter = new AppManualChargeFilter
|
|
{
|
|
UserId = request.Filter?.UserId,
|
|
TransactionId = request.Filter?.TransactionId,
|
|
RefId = request.Filter?.RefId,
|
|
CreatedFrom = request.Filter?.CreatedFrom?.ToDateTime(),
|
|
CreatedTo = request.Filter?.CreatedTo?.ToDateTime()
|
|
}
|
|
}, context.CancellationToken);
|
|
|
|
var response = new GetManualCreditChargesResponse
|
|
{
|
|
MetaData = new CMSMicroservice.Protobuf.Protos.MetaData
|
|
{
|
|
CurrentPage = result.MetaData.CurrentPage,
|
|
TotalPage = result.MetaData.TotalPage,
|
|
PageSize = result.MetaData.PageSize,
|
|
TotalCount = result.MetaData.TotalCount,
|
|
HasPrevious = result.MetaData.HasPrevious,
|
|
HasNext = result.MetaData.HasNext
|
|
}
|
|
};
|
|
|
|
foreach (var m in result.Models)
|
|
{
|
|
var model = new ManualCreditChargeModel
|
|
{
|
|
TransactionId = m.TransactionId,
|
|
UserId = m.UserId,
|
|
UserName = m.UserName ?? string.Empty,
|
|
Amount = m.Amount,
|
|
Description = m.Description ?? string.Empty,
|
|
RefId = m.RefId ?? string.Empty,
|
|
NewBalance = m.NewBalance,
|
|
Created = Timestamp.FromDateTime(DateTime.SpecifyKind(m.Created, DateTimeKind.Utc))
|
|
};
|
|
|
|
if (m.PaymentDate.HasValue)
|
|
{
|
|
model.PaymentDate = Timestamp.FromDateTime(
|
|
DateTime.SpecifyKind(m.PaymentDate.Value, DateTimeKind.Utc));
|
|
}
|
|
|
|
response.Models.Add(model);
|
|
}
|
|
|
|
return response;
|
|
}
|
|
}
|