Files
FrontOffice/src/FrontOffice.Main/Utilities/WalletService.cs
T
masoodafar-web 104e4df1a6
Build and Deploy to Kubernetes / build-and-deploy (push) Failing after 6m25s
feat: implement Magic Wallet feature with charging and status display
2026-02-21 19:50:43 +03:30

257 lines
7.8 KiB
C#

using DateTimeConverterCL;
using CMSMicroservice.Protobuf.Protos.UserWallet;
using CMSMicroservice.Protobuf.Protos.UserWalletChangeLog;
using Google.Protobuf.WellKnownTypes;
namespace FrontOffice.Main.Utilities;
public record WalletBalances(long CreditBalance, long DiscountBalance, long NetworkBalance);
public record WalletTransaction(
string Date,
long CreditChange,
long CreditBalance,
long NetworkChange,
long NetworkBalance,
long DiscountChange,
long DiscountBalance,
string Channel,
string Description
);
public record WalletWithdrawal(long Id, long WeekDefinitionId, string WeekDisplayName, long Amount, int Status, int? Method, string? Iban, string Created);
public enum WithdrawalMethodClient
{
Cash = 0,
Diamond = 1
}
public record WithdrawalSettings(long MinWithdrawalAmount);
public record MagicWalletStatus(
int WalletMode,
long MagicTotalDeposited,
long MagicTotalCredited,
long MagicMaxDeposit,
long MagicRemainingDeposit,
long Balance,
DateTime? MagicActivatedAt
);
public class WalletService
{
private readonly CMSMicroservice.Protobuf.Protos.UserWallet.UserWalletContract.UserWalletContractClient _client;
public WalletService(CMSMicroservice.Protobuf.Protos.UserWallet.UserWalletContract.UserWalletContractClient client)
{
_client = client;
}
public async Task<WalletBalances> GetBalancesAsync()
{
try
{
var response = await _client.GetCustomerWalletAsync(new Empty());
return new WalletBalances(response.Balance, response.DiscountBalance, response.NetworkBalance);
}
catch
{
// Return zero balances if backend is unavailable
return new WalletBalances(0, 0, 0);
}
}
public async Task<List<WalletTransaction>> GetTransactionsAsync(long? referenceId = null, bool? isIncrease = null)
{
try
{
var request = new GetCustomerWalletChangeLogRequest();
if (referenceId.HasValue)
{
request.ReferenceId = referenceId.Value;
}
if (isIncrease.HasValue)
{
request.IsIncrease = isIncrease.Value;
}
var response = await _client.GetCustomerWalletChangeLogAsync(request);
return response.Models
.Select(log => new WalletTransaction(
ResolveTransactionDate(log),
log.ChangeValue,
log.CurrentBalance,
log.ChangeNerworkValue,
log.CurrentNetworkBalance,
log.ChangeDiscountValue,
log.CurrentDiscountBalance,
log.RefrenceId?.ToString() ?? "-",
ResolveDescription(log)
))
.OrderByDescending(t => t.Date)
.ToList();
}
catch
{
// Return empty list if backend is unavailable
return new List<WalletTransaction>();
}
}
private static string ResolveTransactionDate(CustomerWalletChangeLogModel model)
{
if (model.CreatedAt is not null)
{
try
{
var utcDate = model.CreatedAt.ToDateTime();
return utcDate.ToLocalTime().MiladiToJalaliWithTime();
}
catch
{
// ignore conversion issues and fall through to default
}
}
return DateTime.Now.MiladiToJalaliWithTime();
}
private static string ResolveDescription(CustomerWalletChangeLogModel model)
{
var parts = new List<string>();
if (model.ChangeValue != 0)
parts.Add(model.ChangeValue > 0 ? "شارژ عادی" : "برداشت عادی");
if (model.ChangeNerworkValue != 0)
parts.Add(model.ChangeNerworkValue > 0 ? "دریافت شبکه" : "برداشت شبکه");
if (model.ChangeDiscountValue != 0)
parts.Add(model.ChangeDiscountValue > 0 ? "شارژ اعتباری" : "خرید اعتباری");
return parts.Count > 0 ? string.Join(" | ", parts) : "تراکنش کیف پول";
}
public async Task<bool> RequestWithdrawalAsync(long payoutId, WithdrawalMethodClient method, string? iban)
{
var request = new CustomerWithdrawBalanceRequest
{
PayoutId = payoutId,
WithdrawalMethod = (int)method
};
if (!string.IsNullOrWhiteSpace(iban))
{
request.IbanNumber = iban;
}
try
{
await _client.CustomerWithdrawBalanceAsync(request);
return true;
}
catch (Grpc.Core.RpcException ex)
{
throw new InvalidOperationException(ex.Status.Detail ?? "خطا در ثبت برداشت", ex);
}
}
public async Task<List<WalletWithdrawal>> GetWithdrawalsAsync(int? status = null)
{
try
{
var request = new GetCustomerWithdrawalsRequest();
if (status.HasValue)
{
request.Status = status.Value;
}
var response = await _client.GetCustomerWithdrawalsAsync(request);
return response.Models
.Select(m => new WalletWithdrawal(
m.Id,
m.WeekDefinitionId,
m.WeekDisplayName,
m.TotalAmount,
m.Status,
m.WithdrawalMethod,
m.IbanNumber,
m.Created?.ToDateTime().MiladiToJalaliWithTime() ?? "-"))
.ToList();
}
catch
{
return new List<WalletWithdrawal>();
}
}
public async Task<WithdrawalSettings> GetWithdrawalSettingsAsync()
{
try
{
var response = await _client.GetCustomerWithdrawalSettingsAsync(new Empty());
return new WithdrawalSettings(response.MinWithdrawalAmount);
}
catch
{
// Return default settings if backend is unavailable
return new WithdrawalSettings(0);
}
}
// ============= Magic Wallet =============
public async Task<MagicWalletStatus> GetMagicWalletStatusAsync()
{
try
{
var response = await _client.GetMagicWalletStatusAsync(new Empty());
DateTime? activatedAt = response.MagicActivatedAt != null
? response.MagicActivatedAt.ToDateTime().ToLocalTime()
: null;
return new MagicWalletStatus(
response.WalletMode,
response.MagicTotalDeposited,
response.MagicTotalCredited,
response.MagicMaxDeposit,
response.MagicRemainingDeposit,
response.Balance,
activatedAt
);
}
catch
{
return new MagicWalletStatus(0, 0, 0, 0, 0, 0, null);
}
}
public async Task<(bool Success, string? GatewayUrl, string? Error)> InitiateMagicChargeAsync(long amount)
{
try
{
var response = await _client.InitiateMagicChargeAsync(new InitiateMagicChargeRequest
{
Amount = amount
});
if (response.IsSuccess)
return (true, response.GatewayUrl, null);
return (false, null, response.ErrorMessage);
}
catch (Grpc.Core.RpcException ex)
{
return (false, null, ex.Status.Detail ?? "خطا در ارتباط با سرور");
}
}
public int GetWalletMode()
{
try
{
var response = _client.GetCustomerWallet(new Empty());
return response.WalletMode;
}
catch
{
return 0;
}
}
}