feat: add withdrawal requests feature and update VAT loading mechanism
Build and Deploy / build (push) Successful in 1m25s
Build and Deploy / build (push) Successful in 1m25s
This commit is contained in:
@@ -1,3 +1,5 @@
|
||||
using DateTimeConverterCL;
|
||||
|
||||
namespace FrontOffice.Main.Utilities;
|
||||
|
||||
/// <summary>
|
||||
@@ -6,8 +8,8 @@ namespace FrontOffice.Main.Utilities;
|
||||
public class CommissionPayoutDto
|
||||
{
|
||||
public long Id { get; set; }
|
||||
public int WeekNumber { get; set; }
|
||||
public string WeekLabel { get; set; } = string.Empty;
|
||||
public long WeekDefinitionId { get; set; }
|
||||
public string WeekDisplayName { get; set; } = string.Empty;
|
||||
public int BalancesEarned { get; set; }
|
||||
public long TotalAmount { get; set; }
|
||||
public string AmountFormatted { get; set; } = string.Empty;
|
||||
@@ -32,8 +34,8 @@ public class CommissionPayoutsResponseDto
|
||||
/// </summary>
|
||||
public class WeeklyBalanceDto
|
||||
{
|
||||
public int WeekNumber { get; set; }
|
||||
public string WeekLabel { get; set; } = string.Empty;
|
||||
public long WeekDefinitionId { get; set; }
|
||||
public string WeekDisplayName { get; set; } = string.Empty;
|
||||
public long LeftBalance { get; set; }
|
||||
public long RightBalance { get; set; }
|
||||
public long MinBalance { get; set; }
|
||||
@@ -45,12 +47,37 @@ public class WeeklyBalanceDto
|
||||
public DateTime EndDate { get; set; }
|
||||
|
||||
// Formatted properties
|
||||
public string LeftBalanceFormatted => $"{LeftBalance:N0} تومان";
|
||||
public string RightBalanceFormatted => $"{RightBalance:N0} تومان";
|
||||
public string MinBalanceFormatted => $"{MinBalance:N0} تومان";
|
||||
public string CalculatedCommissionFormatted => $"{CalculatedCommission:N0} تومان";
|
||||
public string LeftCarryoverFormatted => $"{LeftCarryover:N0} تومان";
|
||||
public string RightCarryoverFormatted => $"{RightCarryover:N0} تومان";
|
||||
public string StartDatePersian => StartDate.ToString("yyyy/MM/dd");
|
||||
public string EndDatePersian => EndDate.ToString("yyyy/MM/dd");
|
||||
public string LeftBalanceFormatted => $"{LeftBalance:N0} ";
|
||||
public string RightBalanceFormatted => $"{RightBalance:N0} ";
|
||||
public string MinBalanceFormatted => $"{MinBalance:N0} ";
|
||||
public string CalculatedCommissionFormatted => $"{CalculatedCommission:N0} ";
|
||||
public string LeftCarryoverFormatted => $"{LeftCarryover:N0} ";
|
||||
public string RightCarryoverFormatted => $"{RightCarryover:N0} ";
|
||||
public string StartDatePersian => StartDate.MiladiToJalali();
|
||||
public string EndDatePersian => EndDate.MiladiToJalali();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// DTO for Week Definition (for dropdowns)
|
||||
/// </summary>
|
||||
public class WeekDefinitionDto
|
||||
{
|
||||
public long Id { get; set; }
|
||||
public int WeekOrder { get; set; }
|
||||
public string DisplayName { get; set; } = string.Empty;
|
||||
public DateTime StartDate { get; set; }
|
||||
public DateTime EndDate { get; set; }
|
||||
public int GregorianYear { get; set; }
|
||||
public int PersianYear { get; set; }
|
||||
public bool IsActive { get; set; }
|
||||
public bool IsCurrentWeek { get; set; }
|
||||
public string StartDatePersian { get; set; } = string.Empty;
|
||||
public string EndDatePersian { get; set; } = string.Empty;
|
||||
|
||||
// For display in dropdown
|
||||
public string DropdownDisplay => IsCurrentWeek
|
||||
? $"{DisplayName} (هفته جاری)"
|
||||
: DisplayName;
|
||||
|
||||
public string DateRangeDisplay => $"{StartDate.MiladiToJalali()} - {EndDate.MiladiToJalali()}";
|
||||
}
|
||||
|
||||
@@ -15,12 +15,67 @@ public class CommissionService
|
||||
_client = client;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get week definitions for dropdown
|
||||
/// Maps to: CommissionCQ.GetWeekDefinitions
|
||||
/// </summary>
|
||||
public async Task<List<WeekDefinitionDto>> GetWeekDefinitionsAsync(
|
||||
string? searchText = null,
|
||||
int? gregorianYear = null,
|
||||
int? persianYear = null,
|
||||
bool? isActive = null,
|
||||
int pageSize = 100)
|
||||
{
|
||||
try
|
||||
{
|
||||
var request = new GetWeekDefinitionsRequest
|
||||
{
|
||||
PageNumber = 1,
|
||||
PageSize = pageSize
|
||||
};
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(searchText))
|
||||
request.SearchText = searchText;
|
||||
|
||||
if (gregorianYear.HasValue)
|
||||
request.GregorianYear = gregorianYear.Value;
|
||||
|
||||
if (persianYear.HasValue)
|
||||
request.PersianYear = persianYear.Value;
|
||||
|
||||
if (isActive.HasValue)
|
||||
request.IsActive = isActive.Value;
|
||||
|
||||
var response = await _client.GetWeekDefinitionsAsync(request);
|
||||
|
||||
return response.Data.Select(w => new WeekDefinitionDto
|
||||
{
|
||||
Id = w.Id,
|
||||
WeekOrder = w.WeekOrder,
|
||||
DisplayName = w.DisplayName,
|
||||
StartDate = w.StartDate?.ToDateTime() ?? DateTime.MinValue,
|
||||
EndDate = w.EndDate?.ToDateTime() ?? DateTime.MinValue,
|
||||
GregorianYear = w.GregorianYear,
|
||||
PersianYear = w.PersianYear,
|
||||
IsActive = w.IsActive,
|
||||
IsCurrentWeek = w.IsCurrentWeek,
|
||||
StartDatePersian = w.StartDatePersian,
|
||||
EndDatePersian = w.EndDatePersian
|
||||
}).ToList();
|
||||
}
|
||||
catch
|
||||
{
|
||||
// Fallback to mock data if backend is unavailable
|
||||
return GenerateMockWeekDefinitions();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get commission payouts with pagination and filters
|
||||
/// Maps to: CommissionCQ.GetMyCommissionPayouts
|
||||
/// </summary>
|
||||
public async Task<CommissionPayoutsResponseDto> GetMyCommissionPayoutsAsync(
|
||||
int? weekNumber,
|
||||
long? weekDefinitionId,
|
||||
string? status,
|
||||
int pageNumber,
|
||||
int pageSize)
|
||||
@@ -33,9 +88,9 @@ public class CommissionService
|
||||
PageSize = pageSize
|
||||
};
|
||||
|
||||
if (weekNumber.HasValue)
|
||||
if (weekDefinitionId.HasValue)
|
||||
{
|
||||
request.WeekNumber = $"2025-W{weekNumber:D2}";
|
||||
request.WeekDefinitionId = weekDefinitionId.Value;
|
||||
}
|
||||
|
||||
// Map status string to int
|
||||
@@ -58,8 +113,8 @@ public class CommissionService
|
||||
Payouts = response.Payouts.Select(p => new CommissionPayoutDto
|
||||
{
|
||||
Id = p.Id,
|
||||
WeekNumber = ExtractWeekNumber(p.WeekNumber),
|
||||
WeekLabel = p.WeekLabel,
|
||||
WeekDefinitionId = p.WeekDefinitionId,
|
||||
WeekDisplayName = p.WeekDisplayName,
|
||||
BalancesEarned = p.BalancesEarned,
|
||||
TotalAmount = p.TotalAmount,
|
||||
AmountFormatted = p.AmountFormatted,
|
||||
@@ -75,7 +130,7 @@ public class CommissionService
|
||||
catch
|
||||
{
|
||||
// Fallback to mock data if backend is unavailable
|
||||
return GenerateMockPayoutsResponse(weekNumber, status, pageNumber, pageSize);
|
||||
return GenerateMockPayoutsResponse(weekDefinitionId, status, pageNumber, pageSize);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -83,7 +138,7 @@ public class CommissionService
|
||||
/// Get weekly balance details for a specific week
|
||||
/// Maps to: CommissionCQ.GetMyWeeklyBalances
|
||||
/// </summary>
|
||||
public async Task<WeeklyBalanceDto> GetMyWeeklyBalanceAsync(int? weekNumber = null)
|
||||
public async Task<WeeklyBalanceDto> GetMyWeeklyBalanceAsync(long? weekDefinitionId = null)
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -94,9 +149,9 @@ public class CommissionService
|
||||
OnlyActive = false
|
||||
};
|
||||
|
||||
if (weekNumber.HasValue)
|
||||
if (weekDefinitionId.HasValue)
|
||||
{
|
||||
request.WeekNumber = $"2025-W{weekNumber:D2}";
|
||||
request.WeekDefinitionId = weekDefinitionId.Value;
|
||||
}
|
||||
|
||||
var response = await _client.GetMyWeeklyBalancesAsync(request);
|
||||
@@ -106,8 +161,8 @@ public class CommissionService
|
||||
var balance = response.Balances[0];
|
||||
return new WeeklyBalanceDto
|
||||
{
|
||||
WeekNumber = ExtractWeekNumber(balance.WeekNumber),
|
||||
WeekLabel = $"هفته {ExtractWeekNumber(balance.WeekNumber)} - سال 1404",
|
||||
WeekDefinitionId = balance.WeekDefinitionId,
|
||||
WeekDisplayName = balance.WeekDisplayName,
|
||||
LeftBalance = balance.LeftLegBalances,
|
||||
RightBalance = balance.RightLegBalances,
|
||||
MinBalance = Math.Min(balance.LeftLegBalances, balance.RightLegBalances),
|
||||
@@ -120,41 +175,28 @@ public class CommissionService
|
||||
};
|
||||
}
|
||||
|
||||
return CreateMockWeeklyBalance(weekNumber ?? 45);
|
||||
return CreateMockWeeklyBalance();
|
||||
}
|
||||
catch
|
||||
{
|
||||
return CreateMockWeeklyBalance(weekNumber ?? 45);
|
||||
return CreateMockWeeklyBalance();
|
||||
}
|
||||
}
|
||||
|
||||
#region Helper Methods
|
||||
|
||||
private static int ExtractWeekNumber(string weekNumberStr)
|
||||
{
|
||||
// Format: "2025-W48" → 48
|
||||
if (string.IsNullOrEmpty(weekNumberStr)) return 0;
|
||||
|
||||
var parts = weekNumberStr.Split('W');
|
||||
if (parts.Length > 1 && int.TryParse(parts[1], out var week))
|
||||
{
|
||||
return week;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
private static WeeklyBalanceDto CreateMockWeeklyBalance(int weekNumber)
|
||||
private static WeeklyBalanceDto CreateMockWeeklyBalance()
|
||||
{
|
||||
return new WeeklyBalanceDto
|
||||
{
|
||||
WeekNumber = weekNumber,
|
||||
WeekLabel = $"هفته {weekNumber} - سال 1404",
|
||||
LeftBalance = 15_000_000,
|
||||
RightBalance = 12_000_000,
|
||||
MinBalance = 12_000_000,
|
||||
BalanceCount = 12,
|
||||
CalculatedCommission = 1_200_000,
|
||||
LeftCarryover = 3_000_000,
|
||||
WeekDefinitionId = 0,
|
||||
WeekDisplayName = "دادهای یافت نشد",
|
||||
LeftBalance = 0,
|
||||
RightBalance = 0,
|
||||
MinBalance = 0,
|
||||
BalanceCount = 0,
|
||||
CalculatedCommission = 0,
|
||||
LeftCarryover = 0,
|
||||
RightCarryover = 0,
|
||||
StartDate = DateTime.Now.AddDays(-7),
|
||||
EndDate = DateTime.Now
|
||||
@@ -162,13 +204,13 @@ public class CommissionService
|
||||
}
|
||||
|
||||
private static CommissionPayoutsResponseDto GenerateMockPayoutsResponse(
|
||||
int? weekNumber, string? status, int pageNumber, int pageSize)
|
||||
long? weekDefinitionId, string? status, int pageNumber, int pageSize)
|
||||
{
|
||||
var allPayouts = GenerateMockPayouts(50);
|
||||
|
||||
var filtered = allPayouts.AsEnumerable();
|
||||
if (weekNumber.HasValue)
|
||||
filtered = filtered.Where(p => p.WeekNumber == weekNumber.Value);
|
||||
if (weekDefinitionId.HasValue)
|
||||
filtered = filtered.Where(p => p.WeekDefinitionId == weekDefinitionId.Value);
|
||||
if (!string.IsNullOrEmpty(status))
|
||||
filtered = filtered.Where(p => p.Status == status);
|
||||
|
||||
@@ -201,8 +243,8 @@ public class CommissionService
|
||||
payouts.Add(new CommissionPayoutDto
|
||||
{
|
||||
Id = i + 1,
|
||||
WeekNumber = weekNum,
|
||||
WeekLabel = $"هفته {weekNum} - سال 1404",
|
||||
WeekDefinitionId = i + 1,
|
||||
WeekDisplayName = $"هفته {weekNum} - سال 1404",
|
||||
BalancesEarned = balances,
|
||||
TotalAmount = amount,
|
||||
AmountFormatted = $"{amount:N0} تومان",
|
||||
@@ -215,5 +257,35 @@ public class CommissionService
|
||||
return payouts;
|
||||
}
|
||||
|
||||
private static List<WeekDefinitionDto> GenerateMockWeekDefinitions()
|
||||
{
|
||||
var weeks = new List<WeekDefinitionDto>();
|
||||
var persianOrdinals = new[] { "یکم", "دوم", "سوم", "چهارم", "پنجم", "ششم", "هفتم", "هشتم", "نهم", "دهم" };
|
||||
|
||||
// Generate 10 weeks starting from week 46
|
||||
for (int i = 0; i < 10; i++)
|
||||
{
|
||||
var weekOrder = i + 1;
|
||||
var startDate = new DateTime(2025, 11, 8).AddDays(i * 7);
|
||||
|
||||
weeks.Add(new WeekDefinitionDto
|
||||
{
|
||||
Id = i + 1,
|
||||
WeekOrder = weekOrder,
|
||||
DisplayName = weekOrder <= 10 ? $"هفته {persianOrdinals[weekOrder - 1]}" : $"هفته {weekOrder}",
|
||||
StartDate = startDate,
|
||||
EndDate = startDate.AddDays(6),
|
||||
GregorianYear = 2025,
|
||||
PersianYear = 1404,
|
||||
IsActive = true,
|
||||
IsCurrentWeek = weekOrder == 6, // Assume week 6 is current
|
||||
StartDatePersian = $"1404/{8 + i}/17",
|
||||
EndDatePersian = $"1404/{8 + i}/23"
|
||||
});
|
||||
}
|
||||
|
||||
return weeks;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@ public static class RouteConstants
|
||||
public const string ChangePassword = "/profile/change-password";
|
||||
public const string Tree = "/profile/tree";
|
||||
public const string Wallet = "/profile/wallet";
|
||||
public const string WithdrawalRequests = "/profile/withdrawal-requests";
|
||||
}
|
||||
|
||||
public static class Club
|
||||
|
||||
@@ -11,6 +11,7 @@ namespace FrontOffice.Main.Utilities;
|
||||
public class VATService
|
||||
{
|
||||
private readonly IServiceProvider _serviceProvider;
|
||||
private readonly ILocalStorageService _localStorageService;
|
||||
|
||||
private const string VAT_RATE_KEY = "vat_rate";
|
||||
private const string VAT_PERCENTAGE_KEY = "vat_percentage";
|
||||
@@ -22,9 +23,10 @@ public class VATService
|
||||
private bool _isEnabled = true;
|
||||
private bool _isLoaded = false;
|
||||
|
||||
public VATService(IServiceProvider serviceProvider)
|
||||
public VATService(IServiceProvider serviceProvider, ILocalStorageService localStorageService)
|
||||
{
|
||||
_serviceProvider = serviceProvider;
|
||||
_localStorageService = localStorageService;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -51,18 +53,18 @@ public class VATService
|
||||
|
||||
try
|
||||
{
|
||||
using var scope = _serviceProvider.CreateScope();
|
||||
var localStorage = scope.ServiceProvider.GetRequiredService<ILocalStorageService>();
|
||||
|
||||
// using var scope = _serviceProvider.CreateScope();
|
||||
// var localStorage = scope.ServiceProvider.GetRequiredService<ILocalStorageService>();
|
||||
//
|
||||
// چک کن آیا امروز قبلاً گرفته شده
|
||||
var savedDate = await localStorage.GetItemAsStringAsync(VAT_DATE_KEY);
|
||||
var savedDate = await _localStorageService.GetItemAsStringAsync(VAT_DATE_KEY);
|
||||
var today = DateTime.Today.ToString("yyyy-MM-dd");
|
||||
|
||||
if (savedDate == today)
|
||||
{
|
||||
// از cache بخوان
|
||||
var savedRate = await localStorage.GetItemAsync<double>(VAT_RATE_KEY);
|
||||
var savedPercentage = await localStorage.GetItemAsync<int>(VAT_PERCENTAGE_KEY);
|
||||
var savedRate = await _localStorageService.GetItemAsync<double>(VAT_RATE_KEY);
|
||||
var savedPercentage = await _localStorageService.GetItemAsync<int>(VAT_PERCENTAGE_KEY);
|
||||
if (savedRate > 0 && savedPercentage > 0)
|
||||
{
|
||||
_vatRate = savedRate;
|
||||
@@ -92,7 +94,7 @@ public class VATService
|
||||
// ایجاد scope برای دریافت client و localStorage
|
||||
using var scope = _serviceProvider.CreateScope();
|
||||
var client = scope.ServiceProvider.GetRequiredService<UserOrderContract.UserOrderContractClient>();
|
||||
var localStorage = scope.ServiceProvider.GetRequiredService<ILocalStorageService>();
|
||||
// var localStorage = scope.ServiceProvider.GetRequiredService<ILocalStorageService>();
|
||||
|
||||
var response = await client.GetVATRateAsync(new Google.Protobuf.WellKnownTypes.Empty());
|
||||
|
||||
@@ -101,9 +103,9 @@ public class VATService
|
||||
_isEnabled = response.IsEnabled;
|
||||
|
||||
// ذخیره در LocalStorage
|
||||
await localStorage.SetItemAsync(VAT_RATE_KEY, _vatRate);
|
||||
await localStorage.SetItemAsync(VAT_PERCENTAGE_KEY, _vatPercentage);
|
||||
await localStorage.SetItemAsStringAsync(VAT_DATE_KEY, DateTime.Today.ToString("yyyy-MM-dd"));
|
||||
await _localStorageService.SetItemAsync(VAT_RATE_KEY, _vatRate);
|
||||
await _localStorageService.SetItemAsync(VAT_PERCENTAGE_KEY, _vatPercentage);
|
||||
await _localStorageService.SetItemAsStringAsync(VAT_DATE_KEY, DateTime.Today.ToString("yyyy-MM-dd"));
|
||||
|
||||
_isLoaded = true;
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ namespace FrontOffice.Main.Utilities;
|
||||
|
||||
public record WalletBalances(long CreditBalance, long DiscountBalance, long NetworkBalance);
|
||||
public record WalletTransaction(string Date, long Amount, string Channel, string Description);
|
||||
public record WalletWithdrawal(long Id, string WeekNumber, long Amount, int Status, int? Method, string? Iban, string Created);
|
||||
public record WalletWithdrawal(long Id, long WeekDefinitionId, string WeekDisplayName, long Amount, int Status, int? Method, string? Iban, string Created);
|
||||
public enum WithdrawalMethodClient
|
||||
{
|
||||
Cash = 0,
|
||||
@@ -134,7 +134,8 @@ public class WalletService
|
||||
return response.Models
|
||||
.Select(m => new WalletWithdrawal(
|
||||
m.Id,
|
||||
m.WeekNumber,
|
||||
m.WeekDefinitionId,
|
||||
m.WeekDisplayName,
|
||||
m.TotalAmount,
|
||||
m.Status,
|
||||
m.WithdrawalMethod,
|
||||
|
||||
Reference in New Issue
Block a user