feat: add withdrawal requests feature and update VAT loading mechanism
Build and Deploy / build (push) Successful in 1m25s

This commit is contained in:
masoodafar-web
2025-12-20 04:03:11 +03:30
parent 9ee464b8b4
commit 025e8d3c3e
24 changed files with 961 additions and 398 deletions
+2 -2
View File
@@ -16,10 +16,10 @@ using FrontOffice.BFF.ShopingCart.Protobuf.Protos.ShopingCart;
// New Proto imports
using FrontOffice.BFF.ClubMembership.Protobuf.Protos.ClubMembership;
using FrontOffice.BFF.Commission.Protobuf.Protos.Commission;
using FrontOffice.BFF.Configuration.Protobuf.Protos.Configuration;
using FrontOffice.BFF.NetworkMembership.Protobuf.Protos.NetworkMembership;
using FrontOffice.BFF.DiscountShop.Protobuf.Protos.DiscountShop;
using FrontOffice.BFF.City.Protobuf;
using FrontOffice.BFF.Configuration.Protobuf.Protos.Configuration;
using FrontOffice.Main.Utilities;
namespace Microsoft.Extensions.DependencyInjection;
@@ -53,7 +53,7 @@ public static class ConfigureServices
services.AddScoped<CategoryService>();
services.AddScoped<OrderService>();
services.AddScoped<WalletService>();
services.AddSingleton<VATService>(); // Singleton برای cache روزانه
services.AddScoped<VATService>(); // Singleton برای cache روزانه
// Package service
services.AddScoped<PackageService>();
// New services for Club, Network, Commission
+29 -18
View File
@@ -10,20 +10,29 @@
<ItemGroup>
<PackageReference Include="DateTimeConverterCL" Version="1.0.0" />
<PackageReference Include="Foursat.FrontOffice.BFF.City.Protobuf" Version="0.0.2" />
<PackageReference Include="Foursat.FrontOffice.BFF.ClubMembership.Protobuf" Version="0.0.4" />
<PackageReference Include="Foursat.FrontOffice.BFF.Commission.Protobuf" Version="0.0.3" />
<PackageReference Include="Foursat.FrontOffice.BFF.Configuration.Protobuf" Version="0.0.3" />
<!-- <PackageReference Include="Foursat.FrontOffice.BFF.ClubMembership.Protobuf" Version="0.0.3" /> -->
<PackageReference Include="Foursat.FrontOffice.BFF.Commission.Protobuf" Version="0.0.2" />
<PackageReference Include="Foursat.FrontOffice.BFF.DiscountShop.Protobuf" Version="0.0.2" />
<!-- <PackageReference Include="Foursat.FrontOffice.BFF.Commission.Protobuf" Version="0.0.2" /> -->
<PackageReference Include="Foursat.FrontOffice.BFF.DiscountShop.Protobuf" Version="0.0.3" />
<PackageReference Include="Foursat.FrontOffice.BFF.NetworkMembership.Protobuf" Version="0.0.4" />
<PackageReference Include="Foursat.FrontOffice.BFF.Package.Protobuf" Version="0.0.114" />
<!-- <PackageReference Include="Foursat.FrontOffice.BFF.NetworkMembership.Protobuf" Version="0.0.2" />-->
<!-- <PackageReference Include="Foursat.FrontOffice.BFF.Package.Protobuf" Version="0.0.113" /> -->
<PackageReference Include="Foursat.FrontOffice.BFF.Products.Protobuf" Version="0.0.17" />
<PackageReference Include="Foursat.FrontOffice.BFF.Transaction.Protobuf" Version="0.0.112" />
<PackageReference Include="Foursat.FrontOffice.BFF.Category.Protobuf" Version="0.0.13" />
<PackageReference Include="Foursat.FrontOffice.BFF.Products.Protobuf" Version="0.0.18" />
<PackageReference Include="Foursat.FrontOffice.BFF.Transaction.Protobuf" Version="0.0.113" />
<PackageReference Include="Foursat.FrontOffice.BFF.Category.Protobuf" Version="0.0.14" />
<PackageReference Include="Foursat.FrontOffice.BFF.User.Protobuf" Version="0.0.118" />
<!-- <PackageReference Include="Foursat.FrontOffice.BFF.User.Protobuf" Version="0.0.117" /> -->
<PackageReference Include="Foursat.FrontOffice.BFF.UserAddress.Protobuf" Version="0.0.115" />
<PackageReference Include="Foursat.FrontOffice.BFF.UserAddress.Protobuf" Version="0.0.116" />
<!-- <PackageReference Include="Foursat.FrontOffice.BFF.UserOrder.Protobuf" Version="0.0.115" />-->
<PackageReference Include="Foursat.FrontOffice.BFF.ShopingCart.Protobuf" Version="0.0.16" />
<PackageReference Include="Foursat.FrontOffice.BFF.UserWallet.Protobuf" Version="0.0.15" />
<!-- UserWallet moved to ProjectReference for latest proto -->
<PackageReference Include="Foursat.FrontOffice.BFF.ShopingCart.Protobuf" Version="0.0.17" />
<PackageReference Include="Foursat.FrontOffice.BFF.UserOrder.Protobuf" Version="0.0.116" />
<PackageReference Include="Foursat.FrontOffice.BFF.UserWallet.Protobuf" Version="0.0.16" />
<!-- UserWallet moved to ProjectReference for latest proto with WeekDefinitionId -->
<!-- <PackageReference Include="Foursat.FrontOffice.BFF.UserWallet.Protobuf" Version="0.0.15" /> -->
<PackageReference Include="MudBlazor" Version="8.14.0" />
<PackageReference Include="Blazored.LocalStorage" Version="4.5.0" />
<PackageReference Include="Mapster" Version="7.4.0" />
@@ -36,15 +45,17 @@
</ItemGroup>
<!-- Local Proto Project Reference for development -->
<ItemGroup>
<ProjectReference Include="..\..\..\FrontOffice.BFF\src\Protobufs\FrontOffice.BFF.Package.Protobuf\FrontOffice.BFF.Package.Protobuf.csproj" />
<ProjectReference Include="..\..\..\FrontOffice.BFF\src\Protobufs\FrontOffice.BFF.ClubMembership.Protobuf\FrontOffice.BFF.ClubMembership.Protobuf.csproj" />
<ProjectReference Include="..\..\..\FrontOffice.BFF\src\Protobufs\FrontOffice.BFF.City.Protobuf\FrontOffice.BFF.City.Protobuf.csproj" />
<ProjectReference Include="..\..\..\FrontOffice.BFF\src\Protobufs\FrontOffice.BFF.Configuration.Protobuf\FrontOffice.BFF.Configuration.Protobuf.csproj" />
<ProjectReference Include="..\..\..\FrontOffice.BFF\src\Protobufs\FrontOffice.BFF.User.Protobuf\FrontOffice.BFF.User.Protobuf.csproj" />
<ProjectReference Include="..\..\..\FrontOffice.BFF\src\Protobufs\FrontOffice.BFF.NetworkMembership.Protobuf\FrontOffice.BFF.NetworkMembership.Protobuf.csproj" />
<ProjectReference Include="..\..\..\FrontOffice.BFF\src\Protobufs\FrontOffice.BFF.UserOrder.Protobuf\FrontOffice.BFF.UserOrder.Protobuf.csproj" />
</ItemGroup>
<!-- <ItemGroup>-->
<!-- <ProjectReference Include="..\..\..\FrontOffice.BFF\src\Protobufs\FrontOffice.BFF.Package.Protobuf\FrontOffice.BFF.Package.Protobuf.csproj" />-->
<!-- <ProjectReference Include="..\..\..\FrontOffice.BFF\src\Protobufs\FrontOffice.BFF.ClubMembership.Protobuf\FrontOffice.BFF.ClubMembership.Protobuf.csproj" />-->
<!-- <ProjectReference Include="..\..\..\FrontOffice.BFF\src\Protobufs\FrontOffice.BFF.City.Protobuf\FrontOffice.BFF.City.Protobuf.csproj" />-->
<!-- <ProjectReference Include="..\..\..\FrontOffice.BFF\src\Protobufs\FrontOffice.BFF.Configuration.Protobuf\FrontOffice.BFF.Configuration.Protobuf.csproj" />-->
<!-- <ProjectReference Include="..\..\..\FrontOffice.BFF\src\Protobufs\FrontOffice.BFF.User.Protobuf\FrontOffice.BFF.User.Protobuf.csproj" />-->
<!-- <ProjectReference Include="..\..\..\FrontOffice.BFF\src\Protobufs\FrontOffice.BFF.NetworkMembership.Protobuf\FrontOffice.BFF.NetworkMembership.Protobuf.csproj" />-->
<!-- <ProjectReference Include="..\..\..\FrontOffice.BFF\src\Protobufs\FrontOffice.BFF.UserOrder.Protobuf\FrontOffice.BFF.UserOrder.Protobuf.csproj" />-->
<!-- <ProjectReference Include="..\..\..\FrontOffice.BFF\src\Protobufs\FrontOffice.BFF.Commission.Protobuf\FrontOffice.BFF.Commission.Protobuf.csproj" />-->
<!-- <ProjectReference Include="..\..\..\FrontOffice.BFF\src\Protobufs\FrontOffice.BFF.UserWallet.Protobuf\FrontOffice.BFF.UserWallet.Protobuf.csproj" />-->
<!-- </ItemGroup>-->
<!-- New Proto Projects (local references until NuGet publish) -->
<!-- <ItemGroup>-->
@@ -58,7 +58,7 @@
</HeaderContent>
<RowTemplate>
<MudTd>
<MudChip T="string" Color="Color.Default" Size="Size.Small">@context.WeekLabel</MudChip>
<MudChip T="string" Color="Color.Default" Size="Size.Small">@context.WeekDisplayName</MudChip>
</MudTd>
<MudTd>@context.BalancesEarned</MudTd>
<MudTd>
@@ -75,7 +75,7 @@
Variant="Variant.Text"
Color="Color.Info"
StartIcon="@Icons.Material.Filled.Info"
Href="@($"{RouteConstants.Commission.WeeklyBalance}?week={context.WeekNumber}")">
Href="@($"{RouteConstants.Commission.WeeklyBalance}?week={context.WeekDefinitionId}")">
جزئیات
</MudButton>
</MudTd>
@@ -90,7 +90,7 @@
<MudPaper Class="pa-3 rounded-lg" Outlined="true">
<MudStack Spacing="1">
<MudStack Row="true" Justify="Justify.SpaceBetween" AlignItems="AlignItems.Center">
<MudChip T="string" Color="Color.Default" Size="Size.Small">@payout.WeekLabel</MudChip>
<MudChip T="string" Color="Color.Default" Size="Size.Small">@payout.WeekDisplayName</MudChip>
<MudChip T="string" Color="@GetStatusColor(payout.StatusBadgeColor)" Size="Size.Small" Variant="Variant.Outlined">
@payout.Status
</MudChip>
@@ -103,7 +103,7 @@
Color="Color.Info"
FullWidth="true"
StartIcon="@Icons.Material.Filled.Info"
Href="@($"{RouteConstants.Commission.WeeklyBalance}?week={payout.WeekNumber}")">
Href="@($"{RouteConstants.Commission.WeeklyBalance}?week={payout.WeekDefinitionId}")">
مشاهده جزئیات هفته
</MudButton>
</MudStack>
@@ -52,7 +52,7 @@
</HeaderContent>
<RowTemplate>
<MudTd DataLabel="هفته">
<MudChip T="string" Color="Color.Primary" Size="Size.Small" Variant="Variant.Outlined">@context.WeekLabel</MudChip>
<MudChip T="string" Color="Color.Primary" Size="Size.Small" Variant="Variant.Outlined">@context.WeekDisplayName</MudChip>
</MudTd>
<MudTd DataLabel="تعادل‌ها">
<MudText>@context.BalancesEarned</MudText>
@@ -73,7 +73,7 @@
Variant="Variant.Text"
Color="Color.Info"
StartIcon="@Icons.Material.Filled.Visibility"
Href="@($"{RouteConstants.Commission.WeeklyBalance}?week={context.WeekNumber}")">
Href="@($"{RouteConstants.Commission.WeeklyBalance}?week={context.WeekDefinitionId}")">
مشاهده
</MudButton>
</MudTd>
@@ -1,5 +1,6 @@
@attribute [Route(RouteConstants.Commission.WeeklyBalance)]
@using FrontOffice.Main.Utilities
@using FrontOffice.Main.Shared
@using MudBlazor
<PageTitle>تعادل هفتگی</PageTitle>
@@ -13,20 +14,38 @@
<!-- انتخاب هفته -->
<MudPaper Elevation="2" Class="pa-3 rounded-lg">
<MudStack Row="true" Spacing="2" AlignItems="AlignItems.End">
<MudNumericField @bind-Value="_selectedWeekNumber"
Label="شماره هفته"
Variant="Variant.Outlined"
Min="1"
HelperText="هفته مورد نظر را انتخاب کنید (خالی = هفته جاری)"
Style="max-width: 200px;" />
<MudButton Variant="Variant.Filled" Color="Color.Primary" OnClick="LoadWeeklyBalanceAsync" StartIcon="@Icons.Material.Filled.Search">
مشاهده
</MudButton>
<MudButton Variant="Variant.Outlined" OnClick="LoadCurrentWeekAsync" StartIcon="@Icons.Material.Filled.Today">
هفته جاری
</MudButton>
</MudStack>
<MudGrid Spacing="2">
<MudItem xs="8" sm="6" md="6">
<WeekSelector @ref="_weekSelector"
@bind-Value="_selectedWeekDefinition"
Label="انتخاب هفته"
Placeholder="هفته را جستجو یا انتخاب کنید"
Variant="Variant.Outlined"
Dense="false"
OnlyActive="true" />
</MudItem>
@* <MudItem xs="4" sm="3" md="3"> *@
@* <MudButton Variant="Variant.Outlined" *@
@* OnClick="LoadCurrentWeekAsync" *@
@* StartIcon="@Icons.Material.Filled.Today" *@
@* FullWidth="true" *@
@* Style="height: 56px;"> *@
@* هفته جاری *@
@* </MudButton> *@
@* </MudItem> *@
<MudItem xs="4" sm="3" md="3" Class="pt-6">
<MudButton Variant="Variant.Filled"
Color="Color.Primary"
OnClick="LoadWeeklyBalanceAsync"
StartIcon="@Icons.Material.Filled.Search"
Disabled="@(_selectedWeekDefinition == null)"
FullWidth="true"
Style="height: 50px;">
جستجو
</MudButton>
</MudItem>
</MudGrid>
</MudPaper>
@if (_isLoading)
@@ -35,113 +54,89 @@
}
else if (_weeklyBalance is not null)
{
<!-- اطلاعات هفته -->
<MudPaper Elevation="2" Class="pa-4 rounded-lg">
<MudStack Spacing="2">
<MudText Typo="Typo.h6">هفته @_weeklyBalance.WeekNumber - @_weeklyBalance.WeekLabel</MudText>
<MudDivider />
<MudGrid Spacing="2">
<MudItem xs="12" sm="6">
<MudText Typo="Typo.subtitle2" Class="mud-text-secondary">تاریخ شروع:</MudText>
<MudText Typo="Typo.body1"><strong>@_weeklyBalance.StartDatePersian</strong></MudText>
</MudItem>
<MudItem xs="12" sm="6">
<MudText Typo="Typo.subtitle2" Class="mud-text-secondary">تاریخ پایان:</MudText>
<MudText Typo="Typo.body1"><strong>@_weeklyBalance.EndDatePersian</strong></MudText>
</MudItem>
</MudGrid>
</MudStack>
<!-- اطلاعات هفته - کامپکت -->
<MudPaper Elevation="2" Class="pa-3 rounded-lg">
<MudGrid Spacing="1">
<MudItem xs="12" sm="4">
<MudStack Row="true" AlignItems="AlignItems.Center" Spacing="1">
<MudIcon Icon="@Icons.Material.Filled.DateRange" Size="Size.Small" Color="Color.Primary" />
<MudText Typo="Typo.body2"><strong>@_weeklyBalance.WeekDisplayName</strong></MudText>
</MudStack>
</MudItem>
<MudItem xs="6" sm="4">
<MudText Typo="Typo.caption" Class="mud-text-secondary">شروع: <strong>@_weeklyBalance.StartDatePersian</strong></MudText>
</MudItem>
<MudItem xs="6" sm="4">
<MudText Typo="Typo.caption" Class="mud-text-secondary">پایان: <strong>@_weeklyBalance.EndDatePersian</strong></MudText>
</MudItem>
</MudGrid>
</MudPaper>
<!-- تعادل چپ و راست -->
<!-- تعادل چپ و راست - کارت‌های بزرگ -->
<MudGrid Spacing="2">
<MudItem xs="12" md="6">
<MudPaper Elevation="2" Class="pa-4 rounded-lg" Style="height: 100%;">
<MudStack Spacing="2">
<MudStack Row="true" AlignItems="AlignItems.Center" Spacing="2">
<MudIcon Icon="@Icons.Material.Filled.ChevronLeft" Color="Color.Info" Size="Size.Large" />
<MudText Typo="Typo.h6" Color="Color.Info">شاخه چپ</MudText>
</MudStack>
<MudText Typo="Typo.h4" Color="Color.Info">@_weeklyBalance.LeftBalanceFormatted</MudText>
<MudItem xs="6">
<MudPaper Elevation="3" Class="pa-4 rounded-lg text-center" Style="background: linear-gradient(135deg, #e3f2fd 0%, #bbdefb 100%);">
<MudStack Spacing="1" AlignItems="AlignItems.Center">
<MudIcon Icon="@Icons.Material.Filled.ChevronLeft" Color="Color.Info" Size="Size.Large" />
<MudText Typo="Typo.subtitle2" Color="Color.Info">شاخه چپ</MudText>
<MudText Typo="Typo.h5" Color="Color.Info" Style="font-weight: bold;">@_weeklyBalance.LeftBalanceFormatted</MudText>
<MudProgressLinear Color="Color.Info"
Value="@GetLeftPercentage()"
Size="Size.Large"
Class="rounded-lg" />
Size="Size.Medium"
Class="rounded-lg mt-2"
Style="width: 100%;" />
<MudText Typo="Typo.caption" Class="mud-text-secondary">
@GetLeftPercentage().ToString("F1")% از کل تعادل
@GetLeftPercentage().ToString("F1")% از کل
</MudText>
</MudStack>
</MudPaper>
</MudItem>
<MudItem xs="12" md="6">
<MudPaper Elevation="2" Class="pa-4 rounded-lg" Style="height: 100%;">
<MudStack Spacing="2">
<MudStack Row="true" AlignItems="AlignItems.Center" Spacing="2">
<MudIcon Icon="@Icons.Material.Filled.ChevronRight" Color="Color.Success" Size="Size.Large" />
<MudText Typo="Typo.h6" Color="Color.Success">شاخه راست</MudText>
</MudStack>
<MudText Typo="Typo.h4" Color="Color.Success">@_weeklyBalance.RightBalanceFormatted</MudText>
<MudItem xs="6">
<MudPaper Elevation="3" Class="pa-4 rounded-lg text-center" Style="background: linear-gradient(135deg, #e8f5e9 0%, #c8e6c9 100%);">
<MudStack Spacing="1" AlignItems="AlignItems.Center">
<MudIcon Icon="@Icons.Material.Filled.ChevronRight" Color="Color.Success" Size="Size.Large" />
<MudText Typo="Typo.subtitle2" Color="Color.Success">شاخه راست</MudText>
<MudText Typo="Typo.h5" Color="Color.Success" Style="font-weight: bold;">@_weeklyBalance.RightBalanceFormatted</MudText>
<MudProgressLinear Color="Color.Success"
Value="@GetRightPercentage()"
Size="Size.Large"
Class="rounded-lg" />
Size="Size.Medium"
Class="rounded-lg mt-2"
Style="width: 100%;" />
<MudText Typo="Typo.caption" Class="mud-text-secondary">
@GetRightPercentage().ToString("F1")% از کل تعادل
@GetRightPercentage().ToString("F1")% از کل
</MudText>
</MudStack>
</MudPaper>
</MudItem>
</MudGrid>
<!-- محاسبات کمیسیون -->
<!-- محاسبات کمیسیون - فشرده‌تر -->
<MudPaper Elevation="2" Class="pa-4 rounded-lg">
<MudText Typo="Typo.h6" Class="mb-3">محاسبات کمیسیون</MudText>
<MudStack Spacing="2">
<MudStack Row="true" Justify="Justify.SpaceBetween" AlignItems="AlignItems.Center">
<MudText Typo="Typo.body1">تعادل چپ:</MudText>
<MudText Typo="Typo.body1" Color="Color.Info"><strong>@_weeklyBalance.LeftBalanceFormatted</strong></MudText>
</MudStack>
<MudStack Row="true" Justify="Justify.SpaceBetween" AlignItems="AlignItems.Center">
<MudText Typo="Typo.body1">تعادل راست:</MudText>
<MudText Typo="Typo.body1" Color="Color.Success"><strong>@_weeklyBalance.RightBalanceFormatted</strong></MudText>
</MudStack>
<MudDivider />
<MudStack Row="true" Justify="Justify.SpaceBetween" AlignItems="AlignItems.Center">
<MudText Typo="Typo.body1">حداقل تعادل (پایه کمیسیون):</MudText>
<MudText Typo="Typo.h6" Color="Color.Warning"><strong>@_weeklyBalance.MinBalanceFormatted</strong></MudText>
</MudStack>
<MudStack Row="true" Justify="Justify.SpaceBetween" AlignItems="AlignItems.Center">
<MudText Typo="Typo.body1">تعداد تعادل (دفعات):</MudText>
<MudText Typo="Typo.h6" Color="Color.Secondary"><strong>@_weeklyBalance.BalanceCount</strong></MudText>
</MudStack>
<MudDivider />
<MudStack Row="true" Justify="Justify.SpaceBetween" AlignItems="AlignItems.Center">
<MudText Typo="Typo.h6">کمیسیون محاسبه شده:</MudText>
<MudText Typo="Typo.h5" Color="Color.Primary"><strong>@_weeklyBalance.CalculatedCommissionFormatted</strong></MudText>
</MudStack>
<MudText Typo="Typo.subtitle1" Class="mb-2" Style="font-weight: bold;">محاسبات کمیسیون</MudText>
<MudSimpleTable Dense="true" Hover="true" Style="background: transparent;">
<tbody>
<tr>
<td><MudText Typo="Typo.body2">حداقل تعادل (پایه کمیسیون):</MudText></td>
<td class="text-end"><MudText Typo="Typo.body1" Color="Color.Warning"><strong>@_weeklyBalance.MinBalanceFormatted</strong></MudText></td>
</tr>
<tr>
<td><MudText Typo="Typo.body2">تعداد تعادل (دفعات):</MudText></td>
<td class="text-end"><MudText Typo="Typo.body1" Color="Color.Secondary"><strong>@_weeklyBalance.BalanceCount</strong></MudText></td>
</tr>
<tr style="background-color: var(--mud-palette-primary-lighten);">
<td><MudText Typo="Typo.subtitle1"><strong>کمیسیون محاسبه شده:</strong></MudText></td>
<td class="text-end"><MudText Typo="Typo.h6" Color="Color.Primary"><strong>@_weeklyBalance.CalculatedCommissionFormatted</strong></MudText></td>
</tr>
</tbody>
</MudSimpleTable>
@if (_weeklyBalance.LeftCarryover > 0 || _weeklyBalance.RightCarryover > 0)
{
<MudAlert Severity="Severity.Info" Variant="Variant.Outlined">
<MudText Typo="Typo.body2">
<strong>Carryover (انتقال به هفته بعد):</strong><br />
چپ: @_weeklyBalance.LeftCarryoverFormatted | راست: @_weeklyBalance.RightCarryoverFormatted
</MudText>
</MudAlert>
}
</MudStack>
</MudPaper>
<!-- نمودار مقایسه -->
<MudPaper Elevation="2" Class="pa-4 rounded-lg">
<MudText Typo="Typo.h6" Class="mb-3">نمودار مقایسه</MudText>
<MudChart ChartType="ChartType.Bar"
Width="100%"
Height="300px"
InputData="@(new double[] { _weeklyBalance.LeftBalance, _weeklyBalance.RightBalance, _weeklyBalance.MinBalance })"
InputLabels="@(new[] { "چپ", "راست", "حداقل" })"
ChartOptions="@_chartOptions" />
@if (_weeklyBalance.LeftCarryover > 0 || _weeklyBalance.RightCarryover > 0)
{
<MudAlert Severity="Severity.Info" Variant="Variant.Text" Dense="true" Class="mt-2">
<strong>انتقال به هفته بعد:</strong> چپ: @_weeklyBalance.LeftCarryoverFormatted | راست: @_weeklyBalance.RightCarryoverFormatted
</MudAlert>
}
</MudPaper>
}
else if (_hasError)
@@ -1,4 +1,5 @@
using FrontOffice.Main.Utilities;
using FrontOffice.Main.Shared;
using Microsoft.AspNetCore.Components;
using MudBlazor;
@@ -7,13 +8,15 @@ namespace FrontOffice.Main.Pages.Commission;
public partial class WeeklyBalancePage : ComponentBase
{
[Inject] private CommissionService CommissionService { get; set; } = default!;
[Inject] private ISnackbar SnackbarService { get; set; } = default!;
[Parameter]
[SupplyParameterFromQuery(Name = "week")]
public int? QueryWeekNumber { get; set; }
public string? QueryWeekNumber { get; set; }
private WeekSelector? _weekSelector;
private WeekDefinitionDto? _selectedWeekDefinition;
private WeeklyBalanceDto? _weeklyBalance;
private int? _selectedWeekNumber;
private bool _isLoading = true;
private bool _hasError = false;
@@ -27,12 +30,44 @@ public partial class WeeklyBalancePage : ComponentBase
}
};
protected override async Task OnInitializedAsync()
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (QueryWeekNumber.HasValue)
_selectedWeekNumber = QueryWeekNumber;
if (firstRender)
{
// Wait for WeekSelector to initialize and load its cached weeks
if (_weekSelector != null)
{
await _weekSelector.EnsureLoadedAsync();
// Handle query parameter ?week=46 (WeekOrder) or ?week=123 (Id)
if (!string.IsNullOrEmpty(QueryWeekNumber))
{
// Try to parse as integer (first try as WeekOrder, then as Id)
if (int.TryParse(QueryWeekNumber, out int weekOrder))
{
_selectedWeekDefinition = _weekSelector.FindByWeekOrder(weekOrder);
if (_selectedWeekDefinition == null && long.TryParse(QueryWeekNumber, out long id))
{
_selectedWeekDefinition = _weekSelector.FindById(id);
}
}
}
// If no week selected and no query param, select current week
if (_selectedWeekDefinition == null)
{
_selectedWeekDefinition = _weekSelector.GetCurrentWeek();
}
StateHasChanged();
await LoadWeeklyBalanceAsync();
}
}
}
await LoadWeeklyBalanceAsync();
protected override void OnInitialized()
{
_isLoading = true;
}
private async Task LoadWeeklyBalanceAsync()
@@ -41,12 +76,27 @@ public partial class WeeklyBalancePage : ComponentBase
{
_isLoading = true;
_hasError = false;
_weeklyBalance = await CommissionService.GetMyWeeklyBalanceAsync(_selectedWeekNumber);
long? weekDefinitionId = _selectedWeekDefinition?.Id;
_weeklyBalance = await CommissionService.GetMyWeeklyBalanceAsync(weekDefinitionId);
// Update week display name from selected definition if available
if (_selectedWeekDefinition != null && _weeklyBalance != null)
{
_weeklyBalance.WeekDisplayName = _selectedWeekDefinition.DisplayName;
return;
}
_weeklyBalance = new WeeklyBalanceDto()
{
};
}
catch (Exception ex)
{
_hasError = true;
Snackbar.Add($"خطا در دریافت تعادل: {ex.Message}", Severity.Error);
SnackbarService.Add($"خطا در دریافت تعادل: {ex.Message}", Severity.Error);
}
finally
{
@@ -56,7 +106,11 @@ public partial class WeeklyBalancePage : ComponentBase
private async Task LoadCurrentWeekAsync()
{
_selectedWeekNumber = null;
if (_weekSelector != null)
{
await _weekSelector.SelectCurrentWeekAsync();
}
_selectedWeekDefinition = _weekSelector?.GetCurrentWeek();
await LoadWeeklyBalanceAsync();
}
@@ -192,6 +192,17 @@
</MudCard>
</MudLink>
</MudItem>
<MudItem xs="6" sm="6" md="3">
<MudLink Href="@RouteConstants.Profile.WithdrawalRequests" Underline="Underline.None" Class="tile-link">
<MudCard Elevation="1" Class="rounded-lg profile-tile">
<MudCardContent Class="d-flex flex-column align-center pa-4">
<MudIcon Icon="@Icons.Material.Filled.RequestPage" Size="Size.Large" Color="Color.Warning" />
<MudText Typo="Typo.subtitle1" Class="mt-2">درخواست برداشت</MudText>
<MudText Typo="Typo.caption" Class="mud-text-secondary">ثبت و پیگیری برداشت</MudText>
</MudCardContent>
</MudCard>
</MudLink>
</MudItem>
<MudItem xs="6" sm="6" md="3">
<MudLink Href="@RouteConstants.Club.Membership" Underline="Underline.None" Class="tile-link">
<MudCard Elevation="1" Class="rounded-lg profile-tile">
+38 -103
View File
@@ -17,14 +17,9 @@
</MudPaper>
</MudItem>
<MudItem xs="12" sm="6" md="4">
<MudPaper Elevation="2" Class="pa-4 rounded-lg" Style="background-color: var(--mud-palette-warning-lighten);">
<MudStack Row="true" AlignItems="AlignItems.Center" Spacing="2">
<MudIcon Icon="@Icons.Material.Filled.Discount" Color="Color.Warning" Size="Size.Large" />
<MudStack Spacing="0">
<MudText Typo="Typo.subtitle2" Style="color: var(--mud-palette-warning-darken);">موجودی تخفیف باشگاه</MudText>
<MudText Typo="Typo.h4" Style="color: var(--mud-palette-warning-darken);"><strong>@_balances.Discount</strong></MudText>
</MudStack>
</MudStack>
<MudPaper Elevation="2" Class="pa-4 rounded-lg">
<MudText Typo="Typo.subtitle2" Class="mud-text-secondary">موجودی فروشگاه تخفیفی</MudText>
<MudText Typo="Typo.h4" Color="Color.Warning">@_balances.Discount</MudText>
</MudPaper>
</MudItem>
<MudItem xs="12" sm="6" md="4">
@@ -35,61 +30,45 @@
</MudItem>
</MudGrid>
<MudPaper Elevation="2" Class="pa-4 rounded-lg">
<MudText Typo="Typo.h6" Class="mb-2">درخواست برداشت از موجودی شبکه</MudText>
<MudStack Spacing="2">
<MudTextField @bind-Value="_withdrawPayoutId"
Label="شناسه واریز (PayoutId)"
Variant="Variant.Outlined"
Type="MudBlazor.InputType.Number"
Required="true" />
<MudRadioGroup T="WithdrawalMethodClient" @bind-SelectedOption="_withdrawMethod" Row="true">
<MudRadio T="WithdrawalMethodClient" Option="@WithdrawalMethodClient.Cash" Label="برداشت نقدی (نیاز به شبا)" />
<MudRadio T="WithdrawalMethodClient" Option="@WithdrawalMethodClient.Diamond" Label="الماس/غیرنقدی" />
</MudRadioGroup>
<MudTextField @bind-Value="_withdrawIban"
Label="شماره شبا"
Variant="Variant.Outlined"
Disabled="_withdrawMethod == WithdrawalMethodClient.Diamond"
Placeholder="IRxxxxxxxxxxxx"
Adornment="Adornment.Start"
AdornmentText="IR" />
<MudText Typo="Typo.caption" Class="mud-text-secondary">
حداقل مبلغ برداشت: @FormatPrice(_minWithdrawalAmount)
</MudText>
<MudButton Disabled="_isSubmittingWithdrawal"
Variant="Variant.Filled"
Color="Color.Primary"
StartIcon="@Icons.Material.Filled.Outbound"
OnClick="SubmitWithdrawal">
@(_isSubmittingWithdrawal ? "در حال ثبت..." : "ثبت درخواست برداشت")
</MudButton>
</MudStack>
</MudPaper>
<!-- دکمه دسترسی سریع به درخواست برداشت -->
<MudButton Variant="Variant.Filled"
Color="Color.Warning"
Size="Size.Large"
FullWidth="true"
StartIcon="@Icons.Material.Filled.RequestPage"
Href="@RouteConstants.Profile.WithdrawalRequests"
Class="rounded-lg">
درخواست‌های برداشت
</MudButton>
<MudPaper Elevation="2" Class="pa-4 rounded-lg">
<MudText Typo="Typo.h6" Class="mb-2">تراکنش‌ها و مسیرهای شارژ</MudText>
<MudStack Row="true" Spacing="2" Class="mb-3" AlignItems="AlignItems.End">
<MudTextField @bind-Value="_filterReferenceId"
Label="شناسه ارجاع"
Variant="Variant.Outlined"
Adornment="Adornment.Start"
AdornmentIcon="@Icons.Material.Filled.Search" />
<MudSelect T="string" @bind-Value="_filterType" Label="نوع تراکنش" Variant="Variant.Outlined">
<MudSelectItem T="string" Value="@("all")">همه</MudSelectItem>
<MudSelectItem T="string" Value="@("in")">ورودی (شارژ)</MudSelectItem>
<MudSelectItem T="string" Value="@("out")">خروجی (برداشت/خرید)</MudSelectItem>
</MudSelect>
<MudSelect T="string" @bind-Value="_withdrawStatusFilter" Label="وضعیت برداشت" Variant="Variant.Outlined">
<MudSelectItem T="string" Value="@("all")">همه</MudSelectItem>
<MudSelectItem T="string" Value="@("pending")">Pending</MudSelectItem>
<MudSelectItem T="string" Value="@("requested")">Requested</MudSelectItem>
<MudSelectItem T="string" Value="@("withdrawn")">Withdrawn</MudSelectItem>
<MudSelectItem T="string" Value="@("cancelled")">Cancelled</MudSelectItem>
</MudSelect>
<MudButton Variant="Variant.Outlined" OnClick="ApplyFilters" StartIcon="@Icons.Material.Filled.FilterList">اعمال فیلتر</MudButton>
</MudStack>
<MudGrid Spacing="2" Class="mb-3">
<MudItem xs="6" md="4">
<MudTextField @bind-Value="_filterReferenceId"
Label="شناسه ارجاع"
Variant="Variant.Outlined"
Adornment="Adornment.Start"
AdornmentIcon="@Icons.Material.Filled.Search"
FullWidth="true" />
</MudItem>
<MudItem xs="6" md="4">
<MudSelect T="string" @bind-Value="_filterType" Label="نوع تراکنش" Variant="Variant.Outlined" FullWidth="true">
<MudSelectItem T="string" Value="@("all")">همه</MudSelectItem>
<MudSelectItem T="string" Value="@("in")">ورودی (شارژ)</MudSelectItem>
<MudSelectItem T="string" Value="@("out")">خروجی (برداشت/خرید)</MudSelectItem>
</MudSelect>
</MudItem>
<MudItem xs="12" md="4" Class="d-flex align-end">
<MudButton Variant="Variant.Outlined"
OnClick="ApplyFilters"
StartIcon="@Icons.Material.Filled.FilterList"
FullWidth="true">
اعمال فیلتر
</MudButton>
</MudItem>
</MudGrid>
<MudHidden Breakpoint="Breakpoint.MdAndUp" Invert="true">
<MudTable Items="_txs" Dense="true">
@@ -126,49 +105,5 @@
</MudStack>
</MudHidden>
</MudPaper>
<MudPaper Elevation="2" Class="pa-4 rounded-lg">
<MudText Typo="Typo.h6" Class="mb-2">درخواست‌های برداشت ثبت‌شده</MudText>
<MudHidden Breakpoint="Breakpoint.MdAndUp" Invert="true">
<MudTable Items="_withdrawals" Dense="true">
<HeaderContent>
<MudTh>هفته</MudTh>
<MudTh>مبلغ</MudTh>
<MudTh>وضعیت</MudTh>
<MudTh>روش</MudTh>
<MudTh>تاریخ</MudTh>
</HeaderContent>
<RowTemplate>
<MudTd>@context.WeekNumber</MudTd>
<MudTd>@FormatPrice(context.Amount)</MudTd>
<MudTd>
<MudChip T="string" Color="@(ResolveStatusColor(context.Status))" Variant="Variant.Outlined" Size="Size.Small">
@ResolveStatusText(context.Status)
</MudChip>
</MudTd>
<MudTd>@ResolveMethodText(context.Method)</MudTd>
<MudTd>@context.Created</MudTd>
</RowTemplate>
</MudTable>
</MudHidden>
<MudHidden Breakpoint="Breakpoint.MdAndUp">
<MudStack Spacing="2">
@foreach (var wd in _withdrawals)
{
<MudPaper Class="pa-3 rounded-lg" Outlined="true">
<MudStack Spacing="1">
<MudStack Row="true" Justify="Justify.SpaceBetween" AlignItems="AlignItems.Center">
<MudText>@wd.WeekNumber</MudText>
<MudText Color="Color.Primary">@FormatPrice(wd.Amount)</MudText>
</MudStack>
<MudText Typo="Typo.caption" Class="mud-text-secondary">وضعیت: @ResolveStatusText(wd.Status) | روش: @ResolveMethodText(wd.Method)</MudText>
<MudText Typo="Typo.caption" Class="mud-text-secondary">@wd.Created</MudText>
</MudStack>
</MudPaper>
}
</MudStack>
</MudHidden>
</MudPaper>
</MudStack>
</MudContainer>
@@ -6,71 +6,20 @@ namespace FrontOffice.Main.Pages.Profile;
public partial class Wallet : ComponentBase
{
private long _minWithdrawalAmount = 1_000_000; // مقدار پیش‌فرض، از CMS خوانده می‌شود
private (string Credit, string Discount, string Network) _balances = ("-", "-", "-");
private List<WalletTransaction> _txs = new();
private List<WalletWithdrawal> _withdrawals = new();
private string? _filterReferenceId;
private string _filterType = "all";
private string _withdrawStatusFilter = "all";
private bool _isSubmittingWithdrawal;
private long _withdrawPayoutId;
private WithdrawalMethodClient _withdrawMethod = WithdrawalMethodClient.Cash;
private string? _withdrawIban;
protected override async Task OnInitializedAsync()
{
var b = await WalletService.GetBalancesAsync();
_balances = (FormatPrice(b.CreditBalance), FormatPrice(b.DiscountBalance), FormatPrice(b.NetworkBalance));
_txs = await WalletService.GetTransactionsAsync();
_withdrawals = await WalletService.GetWithdrawalsAsync();
var settings = await WalletService.GetWithdrawalSettingsAsync();
if (settings.MinWithdrawalAmount > 0)
_minWithdrawalAmount = settings.MinWithdrawalAmount;
}
private static string FormatPrice(long price) => string.Format("{0:N0} تومان", price);
private async Task SubmitWithdrawal()
{
var target = _withdrawals.FirstOrDefault(x => x.Id == _withdrawPayoutId);
if (target is null)
{
_withdrawals = await WalletService.GetWithdrawalsAsync();
target = _withdrawals.FirstOrDefault(x => x.Id == _withdrawPayoutId);
}
if (target != null && target.Amount < _minWithdrawalAmount)
{
Snackbar.Add($"مبلغ این واریز کمتر از حداقل برداشت ({_minWithdrawalAmount:N0} تومان) است.", Severity.Warning);
return;
}
if (_withdrawPayoutId <= 0)
{
Snackbar.Add("شناسه واریز (PayoutId) الزامی است.", Severity.Warning);
return;
}
if (_withdrawMethod == WithdrawalMethodClient.Cash && string.IsNullOrWhiteSpace(_withdrawIban))
{
Snackbar.Add("برای برداشت نقدی، شماره شبا لازم است.", Severity.Warning);
return;
}
try
{
_isSubmittingWithdrawal = true;
await WalletService.RequestWithdrawalAsync(_withdrawPayoutId, _withdrawMethod, _withdrawIban);
Snackbar.Add("درخواست برداشت ثبت شد.", Severity.Success);
}
catch (Exception ex)
{
Snackbar.Add($"خطا در ثبت برداشت: {ex.Message}", Severity.Error);
}
finally
{
_isSubmittingWithdrawal = false;
}
}
private async Task ApplyFilters()
{
long? refId = null;
@@ -85,39 +34,5 @@ public partial class Wallet : ComponentBase
_ => null
};
_txs = await WalletService.GetTransactionsAsync(refId, isIncrease);
int? status = _withdrawStatusFilter switch
{
"pending" => 1,
"requested" => 2,
"withdrawn" => 3,
"cancelled" => 4,
_ => null
};
_withdrawals = await WalletService.GetWithdrawalsAsync(status);
}
private static string ResolveStatusText(int status) => status switch
{
0 => "ایجاد شده",
1 => "پرداخت شده",
2 => "درخواست برداشت",
3 => "برداشت شده",
4 => "لغو شده",
_ => status.ToString()
};
private static Color ResolveStatusColor(int status) => status switch
{
2 => Color.Warning,
3 => Color.Success,
4 => Color.Error,
_ => Color.Info
};
private static string ResolveMethodText(int? method) => method switch
{
0 => "نقدی",
1 => "الماس",
_ => "-"
};
}
@@ -0,0 +1,125 @@
@attribute [Route(RouteConstants.Profile.WithdrawalRequests)]
<PageTitle>درخواست‌های برداشت</PageTitle>
<MudContainer MaxWidth="MaxWidth.Large" Class="py-6">
<MudStack Spacing="3">
<MudStack Row="true" Justify="Justify.SpaceBetween" AlignItems="AlignItems.Center">
<MudText Typo="Typo.h5">درخواست‌های برداشت</MudText>
<MudButton Variant="Variant.Text" StartIcon="@Icons.Material.Filled.ArrowBack" Href="@RouteConstants.Profile.Wallet">بازگشت به کیف پول</MudButton>
</MudStack>
<!-- فرم درخواست برداشت جدید -->
<MudPaper Elevation="2" Class="pa-4 rounded-lg">
<MudText Typo="Typo.h6" Class="mb-2">ثبت درخواست برداشت جدید</MudText>
<MudStack Spacing="2">
<MudTextField @bind-Value="_withdrawPayoutId"
Label="شناسه واریز (PayoutId)"
Variant="Variant.Outlined"
Type="MudBlazor.InputType.Number"
Required="true" />
<MudRadioGroup T="WithdrawalMethodClient" @bind-Value="_withdrawMethod" Row="true">
<MudRadio T="WithdrawalMethodClient" Option="@WithdrawalMethodClient.Cash" Color="Color.Primary">برداشت نقدی (نیاز به شبا)</MudRadio>
<MudRadio T="WithdrawalMethodClient" Option="@WithdrawalMethodClient.Diamond" Color="Color.Secondary">الماس/غیرنقدی</MudRadio>
</MudRadioGroup>
<MudTextField @bind-Value="_withdrawIban"
Label="شماره شبا"
Variant="Variant.Outlined"
Disabled="_withdrawMethod == WithdrawalMethodClient.Diamond"
Placeholder="IRxxxxxxxxxxxx"
Adornment="Adornment.Start"
AdornmentText="IR" />
<MudText Typo="Typo.caption" Class="mud-text-secondary">
حداقل مبلغ برداشت: @FormatPrice(_minWithdrawalAmount)
</MudText>
<MudButton Disabled="_isSubmittingWithdrawal"
Variant="Variant.Filled"
Color="Color.Primary"
StartIcon="@Icons.Material.Filled.Outbound"
OnClick="SubmitWithdrawal">
@(_isSubmittingWithdrawal ? "در حال ثبت..." : "ثبت درخواست برداشت")
</MudButton>
</MudStack>
</MudPaper>
<!-- فیلتر وضعیت -->
<MudPaper Elevation="2" Class="pa-4 rounded-lg">
<MudStack Row="true" Spacing="2" AlignItems="AlignItems.End">
<MudSelect T="string" @bind-Value="_statusFilter" Label="فیلتر وضعیت" Variant="Variant.Outlined" Style="min-width: 180px;">
<MudSelectItem T="string" Value="@("all")">همه</MudSelectItem>
<MudSelectItem T="string" Value="@("pending")">در انتظار</MudSelectItem>
<MudSelectItem T="string" Value="@("requested")">درخواست شده</MudSelectItem>
<MudSelectItem T="string" Value="@("withdrawn")">برداشت شده</MudSelectItem>
<MudSelectItem T="string" Value="@("cancelled")">لغو شده</MudSelectItem>
</MudSelect>
<MudButton Variant="Variant.Outlined" OnClick="ApplyFilter" StartIcon="@Icons.Material.Filled.FilterList">اعمال فیلتر</MudButton>
</MudStack>
</MudPaper>
<!-- لیست درخواست‌های برداشت -->
<MudPaper Elevation="2" Class="pa-4 rounded-lg">
<MudText Typo="Typo.h6" Class="mb-3">لیست درخواست‌ها</MudText>
@if (_isLoading)
{
<MudProgressLinear Color="Color.Primary" Indeterminate="true" />
}
else if (!_withdrawals.Any())
{
<MudAlert Severity="Severity.Info" Variant="Variant.Outlined">
هنوز درخواست برداشتی ثبت نشده است.
</MudAlert>
}
else
{
<!-- نمایش دسکتاپ -->
<MudHidden Breakpoint="Breakpoint.MdAndUp" Invert="true">
<MudTable Items="_withdrawals" Dense="true" Hover="true" Striped="true">
<HeaderContent>
<MudTh>هفته</MudTh>
<MudTh>مبلغ</MudTh>
<MudTh>وضعیت</MudTh>
<MudTh>روش برداشت</MudTh>
<MudTh>تاریخ ثبت</MudTh>
</HeaderContent>
<RowTemplate>
<MudTd DataLabel="هفته">@context.WeekDisplayName</MudTd>
<MudTd DataLabel="مبلغ">@FormatPrice(context.Amount)</MudTd>
<MudTd DataLabel="وضعیت">
<MudChip T="string" Color="@(ResolveStatusColor(context.Status))" Variant="Variant.Filled" Size="Size.Small">
@ResolveStatusText(context.Status)
</MudChip>
</MudTd>
<MudTd DataLabel="روش">@ResolveMethodText(context.Method)</MudTd>
<MudTd DataLabel="تاریخ">@context.Created</MudTd>
</RowTemplate>
</MudTable>
</MudHidden>
<!-- نمایش موبایل -->
<MudHidden Breakpoint="Breakpoint.MdAndUp">
<MudStack Spacing="2">
@foreach (var wd in _withdrawals)
{
<MudPaper Class="pa-3 rounded-lg" Outlined="true">
<MudStack Spacing="1">
<MudStack Row="true" Justify="Justify.SpaceBetween" AlignItems="AlignItems.Center">
<MudText Typo="Typo.subtitle2">@wd.WeekDisplayName</MudText>
<MudChip T="string" Color="@(ResolveStatusColor(wd.Status))" Variant="Variant.Filled" Size="Size.Small">
@ResolveStatusText(wd.Status)
</MudChip>
</MudStack>
<MudStack Row="true" Justify="Justify.SpaceBetween" AlignItems="AlignItems.Center">
<MudText Typo="Typo.h6" Color="Color.Primary">@FormatPrice(wd.Amount)</MudText>
<MudText Typo="Typo.caption" Class="mud-text-secondary">@ResolveMethodText(wd.Method)</MudText>
</MudStack>
<MudText Typo="Typo.caption" Class="mud-text-secondary">@wd.Created</MudText>
</MudStack>
</MudPaper>
}
</MudStack>
</MudHidden>
}
</MudPaper>
</MudStack>
</MudContainer>
@@ -0,0 +1,123 @@
using FrontOffice.Main.Utilities;
using Microsoft.AspNetCore.Components;
using MudBlazor;
namespace FrontOffice.Main.Pages.Profile;
public partial class WithdrawalRequests : ComponentBase
{
private long _minWithdrawalAmount = 1_000_000;
private List<WalletWithdrawal> _withdrawals = new();
private string _statusFilter = "all";
private bool _isLoading = true;
private bool _isSubmittingWithdrawal;
private long _withdrawPayoutId;
private WithdrawalMethodClient _withdrawMethod = WithdrawalMethodClient.Cash;
private string? _withdrawIban;
protected override async Task OnInitializedAsync()
{
await LoadData();
}
private async Task LoadData()
{
_isLoading = true;
try
{
_withdrawals = await WalletService.GetWithdrawalsAsync();
var settings = await WalletService.GetWithdrawalSettingsAsync();
if (settings.MinWithdrawalAmount > 0)
_minWithdrawalAmount = settings.MinWithdrawalAmount;
}
finally
{
_isLoading = false;
}
}
private static string FormatPrice(long price) => string.Format("{0:N0} تومان", price);
private async Task SubmitWithdrawal()
{
if (_withdrawPayoutId <= 0)
{
Snackbar.Add("شناسه واریز (PayoutId) الزامی است.", Severity.Warning);
return;
}
if (_withdrawMethod == WithdrawalMethodClient.Cash && string.IsNullOrWhiteSpace(_withdrawIban))
{
Snackbar.Add("برای برداشت نقدی، شماره شبا لازم است.", Severity.Warning);
return;
}
try
{
_isSubmittingWithdrawal = true;
await WalletService.RequestWithdrawalAsync(_withdrawPayoutId, _withdrawMethod, _withdrawIban);
Snackbar.Add("درخواست برداشت ثبت شد.", Severity.Success);
// بروزرسانی لیست
await LoadData();
// ریست فرم
_withdrawPayoutId = 0;
_withdrawIban = null;
}
catch (Exception ex)
{
Snackbar.Add($"خطا در ثبت برداشت: {ex.Message}", Severity.Error);
}
finally
{
_isSubmittingWithdrawal = false;
}
}
private async Task ApplyFilter()
{
_isLoading = true;
try
{
int? status = _statusFilter switch
{
"pending" => 1,
"requested" => 2,
"withdrawn" => 3,
"cancelled" => 4,
_ => null
};
_withdrawals = await WalletService.GetWithdrawalsAsync(status);
}
finally
{
_isLoading = false;
}
}
private static string ResolveStatusText(int status) => status switch
{
0 => "ایجاد شده",
1 => "در انتظار پرداخت",
2 => "درخواست برداشت",
3 => "برداشت شده",
4 => "لغو شده",
_ => status.ToString()
};
private static Color ResolveStatusColor(int status) => status switch
{
1 => Color.Info,
2 => Color.Warning,
3 => Color.Success,
4 => Color.Error,
_ => Color.Default
};
private static string ResolveMethodText(int? method) => method switch
{
0 => "نقدی (شبا)",
1 => "الماس",
_ => "-"
};
}
+10 -1
View File
@@ -16,7 +16,16 @@ public partial class Cart : ComponentBase, IDisposable
// لود سبد خرید (فقط اگر کاربر لاگین کرده باشد)
await CartService.EnsureInitializedAsync();
CartService.OnChange += StateHasChanged;
await VAT.LoadAsync();
}
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
{
// بارگذاری نرخ VAT
await VAT.LoadAsync();
}
await base.OnAfterRenderAsync(firstRender);
}
private async Task IncrementQty(long productId)
@@ -30,7 +30,16 @@ public partial class CheckoutSummary : ComponentBase
await Cart.EnsureInitializedAsync();
await LoadAddresses();
await LoadWalletBalance();
await VAT.LoadAsync();
}
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
{
// بارگذاری نرخ VAT
await VAT.LoadAsync();
}
await base.OnAfterRenderAsync(firstRender);
}
private async Task LoadWalletBalance()
@@ -79,7 +88,7 @@ public partial class CheckoutSummary : ComponentBase
{
var request = new SubmitShopBuyOrderRequest
{
TotalAmount = Cart.Total
TotalAmount = VAT.AddVAT(Cart.Total)
};
var response = await UserOrderContract.SubmitShopBuyOrderAsync(request);
@@ -19,7 +19,6 @@ public partial class Orders : ComponentBase
_loading = true;
try
{
await VAT.LoadAsync();
_orders = await OrderService.GetOrdersAsync();
}
catch (Exception ex)
@@ -33,6 +32,16 @@ public partial class Orders : ComponentBase
}
}
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
{
// بارگذاری نرخ VAT
await VAT.LoadAsync();
}
await base.OnAfterRenderAsync(firstRender);
}
private static string FormatPrice(long price) => string.Format("{0:N0} تومان", price);
@@ -30,7 +30,7 @@ public partial class ProductDetail : ComponentBase, IDisposable
private IReadOnlyList<ProductCategoryPathInfo> _categoryPaths = Array.Empty<ProductCategoryPathInfo>();
private ProductGalleryImage? _selectedGalleryImage;
private readonly List<BreadcrumbItem> _breadcrumbItems = new();
private long TotalPrice => VAT.AddVAT((_product?.Price ?? 0) * _qty);
private long TotalPrice => (_product?.Price ?? 0) * _qty;
private bool HasDiscount => _product is { Discount: > 0 and < 100 };
private long? OriginalPrice => HasDiscount && _product is not null
@@ -55,8 +55,7 @@ public partial class ProductDetail : ComponentBase, IDisposable
await Cart.EnsureInitializedAsync();
Cart.OnChange += HandleCartChanged;
// بارگذاری نرخ VAT
await VAT.LoadAsync();
_loading = true;
_product = await ProductService.GetByIdAsync(id);
@@ -80,7 +79,15 @@ public partial class ProductDetail : ComponentBase, IDisposable
await base.OnInitializedAsync();
}
protected override async Task OnAfterRenderAsync(bool firstRender)
{
await base.OnAfterRenderAsync(firstRender);
if (firstRender)
{
// بارگذاری نرخ VAT
await VAT.LoadAsync();
}
}
private async Task AddToCart()
{
@@ -26,10 +26,19 @@ public partial class Products : ComponentBase, IDisposable
await Cart.EnsureInitializedAsync();
Cart.OnChange += StateHasChanged;
Navigation.LocationChanged += HandleLocationChanged;
await VAT.LoadAsync();
await Load();
}
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
{
// بارگذاری نرخ VAT
await VAT.LoadAsync();
}
await base.OnAfterRenderAsync(firstRender);
}
private async Task Load()
{
_loading = true;
@@ -0,0 +1,38 @@
@using FrontOffice.Main.Utilities
@using MudBlazor
<MudAutocomplete T="WeekDefinitionDto"
@bind-Value="_selectedWeek"
Label="@Label"
Placeholder="@Placeholder"
SearchFunc="SearchWeeksAsync"
ToStringFunc="@(w => w?.DropdownDisplay ?? string.Empty)"
Variant="@Variant"
Dense="@Dense"
Margin="@Margin"
Clearable="@Clearable"
ShowProgressIndicator="true"
ProgressIndicatorColor="Color.Primary"
AdornmentIcon="@Icons.Material.Filled.CalendarMonth"
AdornmentColor="Color.Primary"
Class="@Class"
Style="@Style">
<ItemTemplate>
<MudStack Spacing="0" Class="py-1">
<MudStack Row="true" Justify="Justify.SpaceBetween" AlignItems="AlignItems.Center">
<MudText Typo="Typo.body1">
@context.DisplayName
@if (context.IsCurrentWeek)
{
<MudChip T="string" Size="Size.Small" Color="Color.Primary" Class="ms-2">هفته جاری</MudChip>
}
</MudText>
<MudText Typo="Typo.caption" Class="mud-text-secondary">@context.PersianYear</MudText>
</MudStack>
<MudText Typo="Typo.caption" Class="mud-text-secondary">@context.DateRangeDisplay</MudText>
</MudStack>
</ItemTemplate>
<NoItemsTemplate>
<MudText Typo="Typo.body2" Class="pa-3">هفته‌ای یافت نشد</MudText>
</NoItemsTemplate>
</MudAutocomplete>
@@ -0,0 +1,210 @@
using FrontOffice.Main.Utilities;
using Microsoft.AspNetCore.Components;
using MudBlazor;
namespace FrontOffice.Main.Shared;
public partial class WeekSelector : ComponentBase
{
[Inject] private CommissionService CommissionService { get; set; } = default!;
/// <summary>
/// Selected week definition
/// </summary>
[Parameter] public WeekDefinitionDto? Value { get; set; }
/// <summary>
/// Callback when week selection changes
/// </summary>
[Parameter] public EventCallback<WeekDefinitionDto?> ValueChanged { get; set; }
/// <summary>
/// Label for the input
/// </summary>
[Parameter] public string Label { get; set; } = "انتخاب هفته";
/// <summary>
/// Placeholder text
/// </summary>
[Parameter] public string Placeholder { get; set; } = "هفته را انتخاب کنید...";
/// <summary>
/// Input variant
/// </summary>
[Parameter] public Variant Variant { get; set; } = Variant.Outlined;
/// <summary>
/// Dense mode
/// </summary>
[Parameter] public bool Dense { get; set; } = false;
/// <summary>
/// Input margin
/// </summary>
[Parameter] public Margin Margin { get; set; } = Margin.Normal;
/// <summary>
/// Allow clearing the selection
/// </summary>
[Parameter] public bool Clearable { get; set; } = true;
/// <summary>
/// CSS class
/// </summary>
[Parameter] public string? Class { get; set; }
/// <summary>
/// Inline style
/// </summary>
[Parameter] public string? Style { get; set; }
/// <summary>
/// Persian year filter
/// </summary>
[Parameter] public int? PersianYear { get; set; }
/// <summary>
/// Gregorian year filter
/// </summary>
[Parameter] public int? GregorianYear { get; set; }
/// <summary>
/// Only show active weeks
/// </summary>
[Parameter] public bool? OnlyActive { get; set; } = true;
private WeekDefinitionDto? _selectedWeek
{
get => Value;
set
{
if (Value != value)
{
Value = value;
ValueChanged.InvokeAsync(value);
}
}
}
private List<WeekDefinitionDto> _cachedWeeks = new();
private bool _isLoading = false;
protected override async Task OnInitializedAsync()
{
// Pre-load weeks
await LoadWeeksAsync();
}
private async Task LoadWeeksAsync()
{
try
{
_isLoading = true;
_cachedWeeks = await CommissionService.GetWeekDefinitionsAsync(
searchText: null,
gregorianYear: GregorianYear,
persianYear: PersianYear,
isActive: OnlyActive,
pageSize: 100
);
}
catch
{
_cachedWeeks = new List<WeekDefinitionDto>();
}
finally
{
_isLoading = false;
}
}
private async Task<IEnumerable<WeekDefinitionDto>> SearchWeeksAsync(string searchText, CancellationToken cancellationToken)
{
// If cached weeks are empty, load them
if (!_cachedWeeks.Any())
{
await LoadWeeksAsync();
}
// Filter locally from cache
if (string.IsNullOrWhiteSpace(searchText))
return _cachedWeeks;
return _cachedWeeks.Where(w =>
w.DisplayName.Contains(searchText, StringComparison.OrdinalIgnoreCase) ||
w.StartDatePersian.Contains(searchText, StringComparison.OrdinalIgnoreCase) ||
w.EndDatePersian.Contains(searchText, StringComparison.OrdinalIgnoreCase));
}
private async Task OnWeekChanged(WeekDefinitionDto? week)
{
_selectedWeek = week;
}
/// <summary>
/// Get current week from cached weeks
/// </summary>
public WeekDefinitionDto? GetCurrentWeek()
{
return _cachedWeeks.FirstOrDefault(w => w.IsCurrentWeek);
}
/// <summary>
/// Select current week
/// </summary>
public async Task SelectCurrentWeekAsync()
{
var currentWeek = GetCurrentWeek();
if (currentWeek != null)
{
_selectedWeek = currentWeek;
StateHasChanged();
}
await Task.CompletedTask;
}
/// <summary>
/// Find week by WeekOrder number (e.g., 46 from ?week=46)
/// </summary>
public WeekDefinitionDto? FindByWeekOrder(int weekOrder)
{
return _cachedWeeks.FirstOrDefault(w => w.WeekOrder == weekOrder);
}
/// <summary>
/// Find week by Id
/// </summary>
public WeekDefinitionDto? FindById(long id)
{
return _cachedWeeks.FirstOrDefault(w => w.Id == id);
}
/// <summary>
/// Select week by WeekOrder
/// </summary>
public async Task SelectByWeekOrderAsync(int weekOrder)
{
var week = FindByWeekOrder(weekOrder);
if (week != null)
{
_selectedWeek = week;
StateHasChanged();
}
await Task.CompletedTask;
}
/// <summary>
/// Ensure weeks are loaded (useful for parent components)
/// </summary>
public async Task EnsureLoadedAsync()
{
if (!_cachedWeeks.Any())
{
await LoadWeeksAsync();
}
}
/// <summary>
/// Get all cached weeks
/// </summary>
public IReadOnlyList<WeekDefinitionDto> GetCachedWeeks() => _cachedWeeks.AsReadOnly();
}
@@ -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
+13 -11
View File
@@ -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,
+2 -2
View File
@@ -1,6 +1,6 @@
{
// "GwUrl": "https://frontoffice-bff.foursat.afrino.co",
"GwUrl": "https://localhost:34781",
"GwUrl": "https://frontoffice-bff.foursat.afrino.co",
// "GwUrl": "https://localhost:34781",
"DownloadUrl": "https://dl.afrino.co",
"EncryptionSettings": {
"Key": "kmcQ3XTmH4mrdh8VHziuscyf8LLYjG//Kyni81nH/0E=",