Merge branch 'kub-stage' into production
Build and Deploy to Production / build-and-deploy (push) Failing after 2m40s
Build and Deploy to Production / build-and-deploy (push) Failing after 2m40s
This commit is contained in:
@@ -15,7 +15,7 @@ using CMSMicroservice.Protobuf.Protos.User;
|
|||||||
using CMSMicroservice.Protobuf.Protos.UserCarts;
|
using CMSMicroservice.Protobuf.Protos.UserCarts;
|
||||||
using CMSMicroservice.Protobuf.Protos.UserOrder;
|
using CMSMicroservice.Protobuf.Protos.UserOrder;
|
||||||
using CMSMicroservice.Protobuf.Protos.UserWallet;
|
using CMSMicroservice.Protobuf.Protos.UserWallet;
|
||||||
using CMSMicroservice.Protobuf.Protos.UserWalletChangeLog;
|
using CMSMicroservice.Protobuf.Protos.UserWalletHistory;
|
||||||
using CMSMicroservice.Protobuf.Protos.UserAddress;
|
using CMSMicroservice.Protobuf.Protos.UserAddress;
|
||||||
using CMSMicroservice.Protobuf.Protos.Configuration;
|
using CMSMicroservice.Protobuf.Protos.Configuration;
|
||||||
using CMSMicroservice.Protobuf.Protos.NetworkMembership;
|
using CMSMicroservice.Protobuf.Protos.NetworkMembership;
|
||||||
@@ -128,7 +128,7 @@ public static class ConfigureServices
|
|||||||
services.AddScoped(CreateAuthenticatedClient<CMSMicroservice.Protobuf.Protos.UserCarts.UserCartsContract.UserCartsContractClient>);
|
services.AddScoped(CreateAuthenticatedClient<CMSMicroservice.Protobuf.Protos.UserCarts.UserCartsContract.UserCartsContractClient>);
|
||||||
services.AddScoped(CreateAuthenticatedClient<CMSMicroservice.Protobuf.Protos.City.CityContract.CityContractClient>);
|
services.AddScoped(CreateAuthenticatedClient<CMSMicroservice.Protobuf.Protos.City.CityContract.CityContractClient>);
|
||||||
services.AddScoped(CreateAuthenticatedClient<CMSMicroservice.Protobuf.Protos.UserAddress.UserAddressContract.UserAddressContractClient>);
|
services.AddScoped(CreateAuthenticatedClient<CMSMicroservice.Protobuf.Protos.UserAddress.UserAddressContract.UserAddressContractClient>);
|
||||||
services.AddScoped(CreateAuthenticatedClient<CMSMicroservice.Protobuf.Protos.UserWalletChangeLog.UserWalletChangeLogContract.UserWalletChangeLogContractClient>);
|
services.AddScoped(CreateAuthenticatedClient<CMSMicroservice.Protobuf.Protos.UserWalletHistory.UserWalletHistoryContract.UserWalletHistoryContractClient>);
|
||||||
services.AddScoped(CreateAuthenticatedClient<CMSMicroservice.Protobuf.Protos.ClubMembership.ClubMembershipContract.ClubMembershipContractClient>);
|
services.AddScoped(CreateAuthenticatedClient<CMSMicroservice.Protobuf.Protos.ClubMembership.ClubMembershipContract.ClubMembershipContractClient>);
|
||||||
services.AddScoped(CreateAuthenticatedClient<CMSMicroservice.Protobuf.Protos.OtpToken.OtpTokenContract.OtpTokenContractClient>);
|
services.AddScoped(CreateAuthenticatedClient<CMSMicroservice.Protobuf.Protos.OtpToken.OtpTokenContract.OtpTokenContractClient>);
|
||||||
services.AddScoped(CreateAuthenticatedClient<CMSMicroservice.Protobuf.Protos.Configuration.ConfigurationContract.ConfigurationContractClient>);
|
services.AddScoped(CreateAuthenticatedClient<CMSMicroservice.Protobuf.Protos.Configuration.ConfigurationContract.ConfigurationContractClient>);
|
||||||
|
|||||||
@@ -11,7 +11,7 @@
|
|||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="DateTimeConverterCL" Version="1.0.0" />
|
<PackageReference Include="DateTimeConverterCL" Version="1.0.0" />
|
||||||
<!-- Replace all FrontOffice.BFF protobuf packages with CMS protobuf -->
|
<!-- Replace all FrontOffice.BFF protobuf packages with CMS protobuf -->
|
||||||
<PackageReference Include="Foursat.CMSMicroservice.Protobuf" Version="0.0.182" />
|
<PackageReference Include="Foursat.CMSMicroservice.Protobuf" Version="0.0.190" />
|
||||||
<!-- <ProjectReference Include="../../../CMS/src/CMSMicroservice.Protobuf/CMSMicroservice.Protobuf.csproj" />-->
|
<!-- <ProjectReference Include="../../../CMS/src/CMSMicroservice.Protobuf/CMSMicroservice.Protobuf.csproj" />-->
|
||||||
<PackageReference Include="MudBlazor" Version="8.14.0" />
|
<PackageReference Include="MudBlazor" Version="8.14.0" />
|
||||||
<PackageReference Include="Blazored.LocalStorage" Version="4.5.0" />
|
<PackageReference Include="Blazored.LocalStorage" Version="4.5.0" />
|
||||||
@@ -56,12 +56,6 @@
|
|||||||
<Content Include="..\.dockerignore">
|
<Content Include="..\.dockerignore">
|
||||||
<Link>.dockerignore</Link>
|
<Link>.dockerignore</Link>
|
||||||
</Content>
|
</Content>
|
||||||
<Content Remove="Pages\Package\Packages.razor" />
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<Compile Remove="Pages\Package\Packages.razor.cs" />
|
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|||||||
@@ -2,6 +2,8 @@
|
|||||||
<configuration>
|
<configuration>
|
||||||
<packageSources>
|
<packageSources>
|
||||||
<clear />
|
<clear />
|
||||||
|
<!-- Local packages (dev builds) -->
|
||||||
|
<add key="Local" value="/home/masoud/Apps/project/FourSat/nupkg" />
|
||||||
<!-- Nexus (hosts FourSat packages + proxies nuget.org) -->
|
<!-- Nexus (hosts FourSat packages + proxies nuget.org) -->
|
||||||
<add key="Nexus" value="http://194.5.195.53:32081/repository/nuget-all/index.json" allowInsecureConnections="true" />
|
<add key="Nexus" value="http://194.5.195.53:32081/repository/nuget-all/index.json" allowInsecureConnections="true" />
|
||||||
</packageSources>
|
</packageSources>
|
||||||
|
|||||||
@@ -27,6 +27,11 @@
|
|||||||
<MudPaper Elevation="2" Class="pa-4 rounded-lg">
|
<MudPaper Elevation="2" Class="pa-4 rounded-lg">
|
||||||
<MudText Typo="Typo.h5" Class="mb-4">جزئیات پکیج</MudText>
|
<MudText Typo="Typo.h5" Class="mb-4">جزئیات پکیج</MudText>
|
||||||
|
|
||||||
|
@* ── G2: توضیح خرید پکیج (Q28) ── *@
|
||||||
|
<MudAlert Severity="Severity.Info" Variant="Variant.Text" Dense="true" Class="mb-3">
|
||||||
|
با خرید این پکیج، سقف پاداش هفتگی، ضریب کیفپول جادویی و دسترسی به فیچرهای اختصاصی برای شما فعال میشود.
|
||||||
|
</MudAlert>
|
||||||
|
|
||||||
@if (_selectedPackage != null)
|
@if (_selectedPackage != null)
|
||||||
{
|
{
|
||||||
<MudCard>
|
<MudCard>
|
||||||
@@ -207,11 +212,32 @@
|
|||||||
FullWidth="true"
|
FullWidth="true"
|
||||||
StartIcon="@Icons.Material.Filled.Payment"
|
StartIcon="@Icons.Material.Filled.Payment"
|
||||||
OnClick="ProcessPayment"
|
OnClick="ProcessPayment"
|
||||||
Disabled="@(!CanProceedToPayment || _isProcessingPayment)"
|
Disabled="@(!CanProceedToPayment || _isProcessingPayment || !_selectedPackage.SupportsDirectPurchase)"
|
||||||
Class="mt-2">
|
Class="mt-2">
|
||||||
@(_isProcessingPayment ? "در حال پردازش..." : "پرداخت آنلاین")
|
@(_isProcessingPayment ? "در حال پردازش..." : "پرداخت آنلاین")
|
||||||
</MudButton>
|
</MudButton>
|
||||||
|
|
||||||
|
@if (_selectedPackage.SupportsDayaPurchase)
|
||||||
|
{
|
||||||
|
<MudButton Variant="Variant.Filled"
|
||||||
|
Color="Color.Tertiary"
|
||||||
|
Size="Size.Large"
|
||||||
|
FullWidth="true"
|
||||||
|
StartIcon="@Icons.Material.Filled.Diamond"
|
||||||
|
OnClick="DayaLoanPayment"
|
||||||
|
Disabled="@(!CanProceedToPayment)"
|
||||||
|
Class="mt-2">
|
||||||
|
تأمین اعتبار الماسی دایا
|
||||||
|
</MudButton>
|
||||||
|
}
|
||||||
|
|
||||||
|
@if (!_selectedPackage.SupportsDirectPurchase && !_selectedPackage.SupportsDayaPurchase)
|
||||||
|
{
|
||||||
|
<MudAlert Severity="Severity.Warning" Dense="true" Class="mt-2">
|
||||||
|
این پکیج در حال حاضر قابل خرید نیست.
|
||||||
|
</MudAlert>
|
||||||
|
}
|
||||||
|
|
||||||
@if (!CanProceedToPayment)
|
@if (!CanProceedToPayment)
|
||||||
{
|
{
|
||||||
<MudText Typo="Typo.caption" Color="Color.Error" Align="Align.Center">
|
<MudText Typo="Typo.caption" Color="Color.Error" Align="Align.Center">
|
||||||
|
|||||||
@@ -1,11 +1,9 @@
|
|||||||
|
|
||||||
using CMSMicroservice.Protobuf.Protos.Package;
|
using CMSMicroservice.Protobuf.Protos.Package;
|
||||||
using CMSMicroservice.Protobuf.Protos.Transactions;
|
|
||||||
using CMSMicroservice.Protobuf.Protos.UserAddress;
|
using CMSMicroservice.Protobuf.Protos.UserAddress;
|
||||||
using CMSMicroservice.Protobuf.Protos.UserOrder;
|
|
||||||
using FrontOffice.Main.Utilities;
|
using FrontOffice.Main.Utilities;
|
||||||
using Google.Protobuf.WellKnownTypes;
|
|
||||||
using Microsoft.AspNetCore.Components;
|
using Microsoft.AspNetCore.Components;
|
||||||
|
using Microsoft.JSInterop;
|
||||||
using MudBlazor;
|
using MudBlazor;
|
||||||
using Severity = MudBlazor.Severity;
|
using Severity = MudBlazor.Severity;
|
||||||
|
|
||||||
@@ -13,10 +11,9 @@ namespace FrontOffice.Main.Pages;
|
|||||||
|
|
||||||
public partial class Checkout
|
public partial class Checkout
|
||||||
{
|
{
|
||||||
|
[Inject] private PackageService PackageService { get; set; } = default!;
|
||||||
[Inject] private PackageContract.PackageContractClient PackageClient { get; set; } = default!;
|
[Inject] private PackageContract.PackageContractClient PackageClient { get; set; } = default!;
|
||||||
[Inject] private UserAddressContract.UserAddressContractClient UserAddressContract { get; set; } = default!;
|
[Inject] private UserAddressContract.UserAddressContractClient UserAddressContract { get; set; } = default!;
|
||||||
[Inject] private UserOrderContract.UserOrderContractClient UserOrderContract { get; set; } = default!;
|
|
||||||
[Inject] private TransactionsContract.TransactionsContractClient TransactionContract { get; set; } = default!;
|
|
||||||
|
|
||||||
[Parameter] public long? PackageId { get; set; }
|
[Parameter] public long? PackageId { get; set; }
|
||||||
|
|
||||||
@@ -52,15 +49,18 @@ public partial class Checkout
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var response = await PackageClient.GetPackageAsync(new() { Id = PackageId.Value });
|
var packages = await PackageService.GetAllPackagesAsync();
|
||||||
if (response != null)
|
var pkg = packages.FirstOrDefault(p => p.Id == PackageId.Value);
|
||||||
|
if (pkg != null)
|
||||||
{
|
{
|
||||||
_selectedPackage = new Pack(
|
_selectedPackage = new Pack(
|
||||||
Id: response.Id,
|
Id: pkg.Id,
|
||||||
Title: response.Title,
|
Title: pkg.Title,
|
||||||
Body: response.Description,
|
Body: pkg.Description,
|
||||||
Image: response.ImagePath ?? string.Empty,
|
Image: pkg.ImageUrl,
|
||||||
Price: response.Price
|
Price: pkg.Price,
|
||||||
|
SupportsDirectPurchase: pkg.SupportsDirectPurchase,
|
||||||
|
SupportsDayaPurchase: pkg.SupportsDayaPurchase
|
||||||
);
|
);
|
||||||
_finalPrice = _selectedPackage.Price;
|
_finalPrice = _selectedPackage.Price;
|
||||||
}
|
}
|
||||||
@@ -173,9 +173,6 @@ public partial class Checkout
|
|||||||
|
|
||||||
private async Task ProcessPayment()
|
private async Task ProcessPayment()
|
||||||
{
|
{
|
||||||
Snackbar.Add("درگاه پرداخت متصل نیست! لطفا در زمان دیگری مجددا تلاش فرمایید!", Severity.Warning);
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (!CanProceedToPayment || _selectedPackage == null || _selectedAddress == null)
|
if (!CanProceedToPayment || _selectedPackage == null || _selectedAddress == null)
|
||||||
{
|
{
|
||||||
Snackbar.Add("لطفاً پکیج و آدرس را انتخاب کنید.", Severity.Warning);
|
Snackbar.Add("لطفاً پکیج و آدرس را انتخاب کنید.", Severity.Warning);
|
||||||
@@ -186,33 +183,26 @@ public partial class Checkout
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
// Step 1: Create payment request
|
var response = await PackageClient.CustomerPurchasePackageAsync(new CustomerPurchasePackageRequest
|
||||||
var paymentRequest = new CustomerPaymentRequestRequest
|
|
||||||
{
|
{
|
||||||
Amount = _finalPrice,
|
|
||||||
CallbackUrl = $"{Navigation.BaseUri}checkout/callback",
|
|
||||||
Description = $"خرید پکیج {_selectedPackage.Title}",
|
|
||||||
Currency = CurrencyEnum.Irt,
|
|
||||||
Type = TransactionTypeEnum.Real
|
|
||||||
};
|
|
||||||
|
|
||||||
var paymentResponse = await TransactionContract.CustomerPaymentRequestAsync(paymentRequest);
|
|
||||||
|
|
||||||
if (string.IsNullOrEmpty(paymentResponse.PaymentGWUrl))
|
|
||||||
Snackbar.Add("آدرس درگاه پرداخت دریافت نشد.", Severity.Error);
|
|
||||||
|
|
||||||
// Step 2: Create user order
|
|
||||||
var orderRequest = new CreateNewUserOrderRequest
|
|
||||||
{
|
|
||||||
Amount = _finalPrice,
|
|
||||||
PackageId = _selectedPackage.Id,
|
PackageId = _selectedPackage.Id,
|
||||||
PaymentStatus = CMSMicroservice.Protobuf.Protos.PaymentStatus.Pending
|
PurchaseMethod = PurchaseMethodEnum.PurchaseMethodGateway
|
||||||
};
|
});
|
||||||
|
|
||||||
var orderResponse = await UserOrderContract.CreateNewUserOrderAsync(orderRequest);
|
if (!response.Success)
|
||||||
|
{
|
||||||
|
Snackbar.Add(response.Message ?? "خطا در آغاز فرآیند پرداخت", Severity.Error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Step 3: Redirect to payment gateway
|
if (!string.IsNullOrEmpty(response.PaymentGatewayUrl))
|
||||||
Navigation.NavigateTo(paymentResponse.PaymentGWUrl);
|
{
|
||||||
|
Navigation.NavigateTo(response.PaymentGatewayUrl, forceLoad: true);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Snackbar.Add("خطا در دریافت آدرس درگاه پرداخت", Severity.Error);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
@@ -225,5 +215,17 @@ public partial class Checkout
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private record Pack(long Id, string Title, string Body, string Image, long Price);
|
private async Task DayaLoanPayment()
|
||||||
|
{
|
||||||
|
if (_selectedAddress == null)
|
||||||
|
{
|
||||||
|
Snackbar.Add("لطفاً آدرس را انتخاب کنید.", Severity.Warning);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var url = "https://dayadiamond.ir/profile/creditpurchase/?merchantcode=56146364";
|
||||||
|
await JSRuntime.InvokeVoidAsync("open", url, "_blank");
|
||||||
|
}
|
||||||
|
|
||||||
|
private record Pack(long Id, string Title, string Body, string Image, long Price, bool SupportsDirectPurchase = true, bool SupportsDayaPurchase = false);
|
||||||
}
|
}
|
||||||
@@ -4,6 +4,11 @@
|
|||||||
<MudPaper Elevation="2" Class="pa-4 rounded-lg">
|
<MudPaper Elevation="2" Class="pa-4 rounded-lg">
|
||||||
<MudText Typo="Typo.h6" Class="mb-3">فعالسازی یا تمدید عضویت</MudText>
|
<MudText Typo="Typo.h6" Class="mb-3">فعالسازی یا تمدید عضویت</MudText>
|
||||||
|
|
||||||
|
@* ── G7: راهنمای هزینه فعالسازی (Q28) ── *@
|
||||||
|
<MudAlert Severity="Severity.Info" Variant="Variant.Text" Dense="true" Class="mb-3" Icon="@Icons.Material.Filled.Info">
|
||||||
|
هزینه تخمینی بر اساس پکیج انتخابی محاسبه میشود. هر پکیج قیمت و شرایط فعالسازی متفاوتی دارد.
|
||||||
|
</MudAlert>
|
||||||
|
|
||||||
<MudForm @ref="_form" @bind-IsValid="_formIsValid">
|
<MudForm @ref="_form" @bind-IsValid="_formIsValid">
|
||||||
<MudGrid Spacing="2">
|
<MudGrid Spacing="2">
|
||||||
<MudItem xs="12" sm="6">
|
<MudItem xs="12" sm="6">
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ public partial class ActivationSection : ComponentBase
|
|||||||
[Inject] private ClubMembershipService ClubService { get; set; } = default!;
|
[Inject] private ClubMembershipService ClubService { get; set; } = default!;
|
||||||
[Inject] private AuthService AuthService { get; set; } = default!;
|
[Inject] private AuthService AuthService { get; set; } = default!;
|
||||||
[Inject] private UserContract.UserContractClient UserContract { get; set; } = default!;
|
[Inject] private UserContract.UserContractClient UserContract { get; set; } = default!;
|
||||||
|
[Inject] private PackageService PackageService { get; set; } = default!;
|
||||||
|
|
||||||
[Parameter] public EventCallback OnActivationSuccess { get; set; }
|
[Parameter] public EventCallback OnActivationSuccess { get; set; }
|
||||||
|
|
||||||
@@ -21,6 +22,18 @@ public partial class ActivationSection : ComponentBase
|
|||||||
private long _packageId = 1;
|
private long _packageId = 1;
|
||||||
private int _durationMonths = 1;
|
private int _durationMonths = 1;
|
||||||
private string? _activationCode;
|
private string? _activationCode;
|
||||||
|
private long _basePackagePrice;
|
||||||
|
|
||||||
|
protected override async Task OnInitializedAsync()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var packages = await PackageService.GetAllPackagesAsync();
|
||||||
|
var basePackage = packages.FirstOrDefault(p => p.IsBasePackage) ?? packages.FirstOrDefault();
|
||||||
|
_basePackagePrice = basePackage?.Price ?? 0;
|
||||||
|
}
|
||||||
|
catch { /* fallback to 0 */ }
|
||||||
|
}
|
||||||
|
|
||||||
private async Task HandleActivateAsync()
|
private async Task HandleActivateAsync()
|
||||||
{
|
{
|
||||||
@@ -75,9 +88,8 @@ public partial class ActivationSection : ComponentBase
|
|||||||
|
|
||||||
private string GetEstimatedCost()
|
private string GetEstimatedCost()
|
||||||
{
|
{
|
||||||
// فرمول تقریبی: 56M per month (base amount from BFF implementation)
|
if (_basePackagePrice <= 0) return "در حال بارگذاری...";
|
||||||
var baseAmount = 56_000_000;
|
var total = _basePackagePrice * _durationMonths;
|
||||||
var total = baseAmount * _durationMonths;
|
|
||||||
return $"{total:N0} تومان";
|
return $"{total:N0} تومان";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,6 +9,11 @@
|
|||||||
<MudStack Spacing="3">
|
<MudStack Spacing="3">
|
||||||
<PageHeader Title="عضویت باشگاه مشتریان" BackHref="@RouteConstants.Profile.Index" />
|
<PageHeader Title="عضویت باشگاه مشتریان" BackHref="@RouteConstants.Profile.Index" />
|
||||||
|
|
||||||
|
@* ── G6: راهنمای قرارداد باشگاه (Q28) ── *@
|
||||||
|
<MudAlert Severity="Severity.Info" Variant="Variant.Text" Dense="true" Icon="@Icons.Material.Filled.Gavel">
|
||||||
|
قرارداد باشگاه مشتریان فقط یکبار امضا میشود و با هر بار خرید پکیج جدید نیازی به امضای مجدد نیست.
|
||||||
|
</MudAlert>
|
||||||
|
|
||||||
@if (_isLoading)
|
@if (_isLoading)
|
||||||
{
|
{
|
||||||
<LoadingState Message="در حال دریافت اطلاعات عضویت..." />
|
<LoadingState Message="در حال دریافت اطلاعات عضویت..." />
|
||||||
|
|||||||
@@ -10,10 +10,15 @@
|
|||||||
<MudStack Spacing="3">
|
<MudStack Spacing="3">
|
||||||
<PageHeader Title="پاداشهای من" BackHref="@RouteConstants.Profile.Index" />
|
<PageHeader Title="پاداشهای من" BackHref="@RouteConstants.Profile.Index" />
|
||||||
|
|
||||||
|
@* ── G5: توضیح محاسبه پاداش (Q28) ── *@
|
||||||
|
<MudAlert Severity="Severity.Info" Variant="Variant.Text" Dense="true" Icon="@Icons.Material.Filled.Info">
|
||||||
|
پاداش هفتگی بر اساس هر پکیج جداگانه محاسبه میشود. هر پکیج Pool پورسانت مستقل دارد و Carryover بر اساس پکیج زیرمجموعههاست.
|
||||||
|
</MudAlert>
|
||||||
|
|
||||||
<!-- فیلترها -->
|
<!-- فیلترها -->
|
||||||
<MudPaper Elevation="2" Class="pa-3 rounded-lg">
|
<MudPaper Elevation="2" Class="pa-3 rounded-lg">
|
||||||
<MudGrid Spacing="2">
|
<MudGrid Spacing="2">
|
||||||
<MudItem xs="12" sm="6" md="4">
|
<MudItem xs="12" sm="6" md="3">
|
||||||
<WeekSelector @ref="_weekSelector"
|
<WeekSelector @ref="_weekSelector"
|
||||||
@bind-Value="_selectedWeekDefinition"
|
@bind-Value="_selectedWeekDefinition"
|
||||||
Label="انتخاب هفته"
|
Label="انتخاب هفته"
|
||||||
@@ -23,7 +28,7 @@
|
|||||||
Clearable="true"
|
Clearable="true"
|
||||||
OnlyActive="false" />
|
OnlyActive="false" />
|
||||||
</MudItem>
|
</MudItem>
|
||||||
<MudItem xs="12" sm="6" md="4">
|
<MudItem xs="12" sm="6" md="3">
|
||||||
<MudSelect T="string" @bind-Value="_filterStatus" Label="وضعیت" Variant="Variant.Outlined">
|
<MudSelect T="string" @bind-Value="_filterStatus" Label="وضعیت" Variant="Variant.Outlined">
|
||||||
<MudSelectItem T="string" Value="@string.Empty">همه</MudSelectItem>
|
<MudSelectItem T="string" Value="@string.Empty">همه</MudSelectItem>
|
||||||
<MudSelectItem T="string" Value="@("Pending")">در انتظار</MudSelectItem>
|
<MudSelectItem T="string" Value="@("Pending")">در انتظار</MudSelectItem>
|
||||||
@@ -34,7 +39,16 @@
|
|||||||
<MudSelectItem T="string" Value="@("Cancelled")">لغو شده</MudSelectItem>
|
<MudSelectItem T="string" Value="@("Cancelled")">لغو شده</MudSelectItem>
|
||||||
</MudSelect>
|
</MudSelect>
|
||||||
</MudItem>
|
</MudItem>
|
||||||
<MudItem xs="12" sm="12" md="4">
|
<MudItem xs="12" sm="6" md="3">
|
||||||
|
<MudSelect T="long?" @bind-Value="_filterPackageId" Label="پکیج" Variant="Variant.Outlined" Clearable="true">
|
||||||
|
<MudSelectItem T="long?" Value="@((long?)null)">همه پکیجها</MudSelectItem>
|
||||||
|
@foreach (var pkg in _packages)
|
||||||
|
{
|
||||||
|
<MudSelectItem T="long?" Value="@((long?)pkg.Id)">@pkg.Title</MudSelectItem>
|
||||||
|
}
|
||||||
|
</MudSelect>
|
||||||
|
</MudItem>
|
||||||
|
<MudItem xs="12" sm="6" md="3">
|
||||||
<MudStack Row="true" Spacing="2" Style="height: 100%;" AlignItems="AlignItems.End">
|
<MudStack Row="true" Spacing="2" Style="height: 100%;" AlignItems="AlignItems.End">
|
||||||
<MudButton Variant="Variant.Filled" Color="Color.Primary" OnClick="ApplyFiltersAsync" StartIcon="@Icons.Material.Filled.FilterList" FullWidth="true">
|
<MudButton Variant="Variant.Filled" Color="Color.Primary" OnClick="ApplyFiltersAsync" StartIcon="@Icons.Material.Filled.FilterList" FullWidth="true">
|
||||||
اعمال فیلتر
|
اعمال فیلتر
|
||||||
@@ -87,6 +101,7 @@
|
|||||||
<MudTable Items="_payouts" Hover="true" Striped="true" Dense="true" FixedHeader="true" Height="400px">
|
<MudTable Items="_payouts" Hover="true" Striped="true" Dense="true" FixedHeader="true" Height="400px">
|
||||||
<HeaderContent>
|
<HeaderContent>
|
||||||
<MudTh>هفته</MudTh>
|
<MudTh>هفته</MudTh>
|
||||||
|
<MudTh>پکیج</MudTh>
|
||||||
<MudTh>امتیاز</MudTh>
|
<MudTh>امتیاز</MudTh>
|
||||||
<MudTh>مبلغ (تومان)</MudTh>
|
<MudTh>مبلغ (تومان)</MudTh>
|
||||||
<MudTh>وضعیت</MudTh>
|
<MudTh>وضعیت</MudTh>
|
||||||
@@ -97,6 +112,11 @@
|
|||||||
<MudTd DataLabel="هفته">
|
<MudTd DataLabel="هفته">
|
||||||
<MudChip T="string" Color="Color.Primary" Size="Size.Small" Variant="Variant.Outlined">@context.WeekDisplayName</MudChip>
|
<MudChip T="string" Color="Color.Primary" Size="Size.Small" Variant="Variant.Outlined">@context.WeekDisplayName</MudChip>
|
||||||
</MudTd>
|
</MudTd>
|
||||||
|
<MudTd DataLabel="پکیج">
|
||||||
|
<MudChip T="string" Color="Color.Tertiary" Size="Size.Small">
|
||||||
|
@(string.IsNullOrEmpty(context.PackageTitle) ? "-" : context.PackageTitle)
|
||||||
|
</MudChip>
|
||||||
|
</MudTd>
|
||||||
<MudTd DataLabel="امتیاز">@context.BalancesEarned</MudTd>
|
<MudTd DataLabel="امتیاز">@context.BalancesEarned</MudTd>
|
||||||
<MudTd DataLabel="مبلغ">
|
<MudTd DataLabel="مبلغ">
|
||||||
<MudText Color="Color.Success"><strong>@context.AmountFormatted</strong></MudText>
|
<MudText Color="Color.Success"><strong>@context.AmountFormatted</strong></MudText>
|
||||||
@@ -127,6 +147,10 @@
|
|||||||
<MudChip T="string" Color="Color.Primary" Size="Size.Small" Variant="Variant.Outlined">@payout.WeekDisplayName</MudChip>
|
<MudChip T="string" Color="Color.Primary" Size="Size.Small" Variant="Variant.Outlined">@payout.WeekDisplayName</MudChip>
|
||||||
<MudChip T="string" Color="@GetStatusColor(payout.StatusColor)" Size="Size.Small">@payout.StatusText</MudChip>
|
<MudChip T="string" Color="@GetStatusColor(payout.StatusColor)" Size="Size.Small">@payout.StatusText</MudChip>
|
||||||
</MudStack>
|
</MudStack>
|
||||||
|
@if (!string.IsNullOrEmpty(payout.PackageTitle))
|
||||||
|
{
|
||||||
|
<MudChip T="string" Color="Color.Tertiary" Size="Size.Small">@payout.PackageTitle</MudChip>
|
||||||
|
}
|
||||||
<MudStack Row="true" Justify="Justify.SpaceBetween" AlignItems="AlignItems.Center">
|
<MudStack Row="true" Justify="Justify.SpaceBetween" AlignItems="AlignItems.Center">
|
||||||
<MudText Typo="Typo.h6" Color="Color.Success">@payout.AmountFormatted</MudText>
|
<MudText Typo="Typo.h6" Color="Color.Success">@payout.AmountFormatted</MudText>
|
||||||
<MudText Typo="Typo.caption" Class="mud-text-secondary">امتیاز: @payout.BalancesEarned</MudText>
|
<MudText Typo="Typo.caption" Class="mud-text-secondary">امتیاز: @payout.BalancesEarned</MudText>
|
||||||
|
|||||||
@@ -8,8 +8,10 @@ namespace FrontOffice.Main.Pages.Commission;
|
|||||||
public partial class CommissionDashboardPage : ComponentBase
|
public partial class CommissionDashboardPage : ComponentBase
|
||||||
{
|
{
|
||||||
[Inject] private CommissionService CommissionService { get; set; } = default!;
|
[Inject] private CommissionService CommissionService { get; set; } = default!;
|
||||||
|
[Inject] private PackageService PackageService { get; set; } = default!;
|
||||||
|
|
||||||
private List<CommissionPayoutDto> _payouts = new();
|
private List<CommissionPayoutDto> _payouts = new();
|
||||||
|
private List<PackageDto> _packages = new();
|
||||||
private int _totalCount;
|
private int _totalCount;
|
||||||
private long _totalAmount;
|
private long _totalAmount;
|
||||||
private int _pageNumber = 1;
|
private int _pageNumber = 1;
|
||||||
@@ -19,12 +21,26 @@ public partial class CommissionDashboardPage : ComponentBase
|
|||||||
private WeekSelector? _weekSelector;
|
private WeekSelector? _weekSelector;
|
||||||
private WeekDefinitionDto? _selectedWeekDefinition;
|
private WeekDefinitionDto? _selectedWeekDefinition;
|
||||||
private string _filterStatus = string.Empty;
|
private string _filterStatus = string.Empty;
|
||||||
|
private long? _filterPackageId;
|
||||||
|
|
||||||
protected override async Task OnInitializedAsync()
|
protected override async Task OnInitializedAsync()
|
||||||
{
|
{
|
||||||
|
await LoadPackagesAsync();
|
||||||
await LoadPayoutsAsync();
|
await LoadPayoutsAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async Task LoadPackagesAsync()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
_packages = await PackageService.GetAllPackagesAsync();
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
_packages = new List<PackageDto>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private async Task LoadPayoutsAsync()
|
private async Task LoadPayoutsAsync()
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
@@ -35,7 +51,8 @@ public partial class CommissionDashboardPage : ComponentBase
|
|||||||
weekDefinitionId,
|
weekDefinitionId,
|
||||||
_filterStatus,
|
_filterStatus,
|
||||||
_pageNumber,
|
_pageNumber,
|
||||||
_pageSize
|
_pageSize,
|
||||||
|
_filterPackageId
|
||||||
);
|
);
|
||||||
_payouts = result.Payouts;
|
_payouts = result.Payouts;
|
||||||
_totalCount = result.TotalCount;
|
_totalCount = result.TotalCount;
|
||||||
@@ -61,6 +78,7 @@ public partial class CommissionDashboardPage : ComponentBase
|
|||||||
{
|
{
|
||||||
_selectedWeekDefinition = null;
|
_selectedWeekDefinition = null;
|
||||||
_filterStatus = string.Empty;
|
_filterStatus = string.Empty;
|
||||||
|
_filterPackageId = null;
|
||||||
_pageNumber = 1;
|
_pageNumber = 1;
|
||||||
await LoadPayoutsAsync();
|
await LoadPayoutsAsync();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,7 +12,7 @@
|
|||||||
<!-- انتخاب هفته -->
|
<!-- انتخاب هفته -->
|
||||||
<MudPaper Elevation="2" Class="pa-3 rounded-lg">
|
<MudPaper Elevation="2" Class="pa-3 rounded-lg">
|
||||||
<MudGrid Spacing="2">
|
<MudGrid Spacing="2">
|
||||||
<MudItem xs="8" sm="6" md="6">
|
<MudItem xs="8" sm="4" md="4">
|
||||||
<WeekSelector @ref="_weekSelector"
|
<WeekSelector @ref="_weekSelector"
|
||||||
@bind-Value="_selectedWeekDefinition"
|
@bind-Value="_selectedWeekDefinition"
|
||||||
Label="انتخاب هفته"
|
Label="انتخاب هفته"
|
||||||
@@ -21,15 +21,15 @@
|
|||||||
Dense="false"
|
Dense="false"
|
||||||
OnlyActive="true" />
|
OnlyActive="true" />
|
||||||
</MudItem>
|
</MudItem>
|
||||||
@* <MudItem xs="4" sm="3" md="3"> *@
|
<MudItem xs="4" sm="4" md="4">
|
||||||
@* <MudButton Variant="Variant.Outlined" *@
|
<MudSelect T="long?" @bind-Value="_filterPackageId" Label="پکیج" Variant="Variant.Outlined" Clearable="true">
|
||||||
@* OnClick="LoadCurrentWeekAsync" *@
|
<MudSelectItem T="long?" Value="@((long?)null)">همه پکیجها</MudSelectItem>
|
||||||
@* StartIcon="@Icons.Material.Filled.Today" *@
|
@foreach (var pkg in _packages)
|
||||||
@* FullWidth="true" *@
|
{
|
||||||
@* Style="height: 56px;"> *@
|
<MudSelectItem T="long?" Value="@((long?)pkg.Id)">@pkg.Title</MudSelectItem>
|
||||||
@* هفته جاری *@
|
}
|
||||||
@* </MudButton> *@
|
</MudSelect>
|
||||||
@* </MudItem> *@
|
</MudItem>
|
||||||
<MudItem xs="4" sm="3" md="3" Class="pt-6">
|
<MudItem xs="4" sm="3" md="3" Class="pt-6">
|
||||||
<MudButton Variant="Variant.Filled"
|
<MudButton Variant="Variant.Filled"
|
||||||
Color="Color.Primary"
|
Color="Color.Primary"
|
||||||
@@ -66,6 +66,12 @@
|
|||||||
<MudItem xs="6" sm="4">
|
<MudItem xs="6" sm="4">
|
||||||
<MudText Typo="Typo.caption" Class="mud-text-secondary">پایان: <strong>@_weeklyBalance.EndDatePersian</strong></MudText>
|
<MudText Typo="Typo.caption" Class="mud-text-secondary">پایان: <strong>@_weeklyBalance.EndDatePersian</strong></MudText>
|
||||||
</MudItem>
|
</MudItem>
|
||||||
|
@if (!string.IsNullOrEmpty(_weeklyBalance.PackageTitle))
|
||||||
|
{
|
||||||
|
<MudItem xs="12" sm="12">
|
||||||
|
<MudChip T="string" Color="Color.Info" Size="Size.Small" Icon="@Icons.Material.Filled.Inventory2">@_weeklyBalance.PackageTitle</MudChip>
|
||||||
|
</MudItem>
|
||||||
|
}
|
||||||
</MudGrid>
|
</MudGrid>
|
||||||
</MudPaper>
|
</MudPaper>
|
||||||
|
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ namespace FrontOffice.Main.Pages.Commission;
|
|||||||
public partial class WeeklyBalancePage : ComponentBase
|
public partial class WeeklyBalancePage : ComponentBase
|
||||||
{
|
{
|
||||||
[Inject] private CommissionService CommissionService { get; set; } = default!;
|
[Inject] private CommissionService CommissionService { get; set; } = default!;
|
||||||
|
[Inject] private PackageService PackageService { get; set; } = default!;
|
||||||
[Inject] private ISnackbar SnackbarService { get; set; } = default!;
|
[Inject] private ISnackbar SnackbarService { get; set; } = default!;
|
||||||
|
|
||||||
[Parameter]
|
[Parameter]
|
||||||
@@ -17,6 +18,8 @@ public partial class WeeklyBalancePage : ComponentBase
|
|||||||
private WeekSelector? _weekSelector;
|
private WeekSelector? _weekSelector;
|
||||||
private WeekDefinitionDto? _selectedWeekDefinition;
|
private WeekDefinitionDto? _selectedWeekDefinition;
|
||||||
private WeeklyBalanceDto? _weeklyBalance;
|
private WeeklyBalanceDto? _weeklyBalance;
|
||||||
|
private List<PackageDto> _packages = new();
|
||||||
|
private long? _filterPackageId;
|
||||||
private bool _isLoading = true;
|
private bool _isLoading = true;
|
||||||
private bool _hasError = false;
|
private bool _hasError = false;
|
||||||
|
|
||||||
@@ -34,6 +37,8 @@ public partial class WeeklyBalancePage : ComponentBase
|
|||||||
{
|
{
|
||||||
if (firstRender)
|
if (firstRender)
|
||||||
{
|
{
|
||||||
|
await LoadPackagesAsync();
|
||||||
|
|
||||||
// Wait for WeekSelector to initialize and load its cached weeks
|
// Wait for WeekSelector to initialize and load its cached weeks
|
||||||
if (_weekSelector != null)
|
if (_weekSelector != null)
|
||||||
{
|
{
|
||||||
@@ -88,7 +93,7 @@ public partial class WeeklyBalancePage : ComponentBase
|
|||||||
|
|
||||||
long? weekDefinitionId = _selectedWeekDefinition?.Id;
|
long? weekDefinitionId = _selectedWeekDefinition?.Id;
|
||||||
|
|
||||||
_weeklyBalance = await CommissionService.GetMyWeeklyBalanceAsync(weekDefinitionId);
|
_weeklyBalance = await CommissionService.GetMyWeeklyBalanceAsync(weekDefinitionId, _filterPackageId);
|
||||||
|
|
||||||
// Update week display name from selected definition if available
|
// Update week display name from selected definition if available
|
||||||
if (_selectedWeekDefinition != null && _weeklyBalance != null)
|
if (_selectedWeekDefinition != null && _weeklyBalance != null)
|
||||||
@@ -113,6 +118,18 @@ public partial class WeeklyBalancePage : ComponentBase
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async Task LoadPackagesAsync()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
_packages = await PackageService.GetAllPackagesAsync();
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
_packages = new();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private async Task LoadCurrentWeekAsync()
|
private async Task LoadCurrentWeekAsync()
|
||||||
{
|
{
|
||||||
if (_weekSelector != null)
|
if (_weekSelector != null)
|
||||||
|
|||||||
@@ -20,7 +20,7 @@
|
|||||||
<MudIcon Icon="@Icons.Material.Filled.CardGiftcard" Size="Size.Large" Color="Color.Primary" Style="font-size: 80px;" />
|
<MudIcon Icon="@Icons.Material.Filled.CardGiftcard" Size="Size.Large" Color="Color.Primary" Style="font-size: 80px;" />
|
||||||
<MudText Typo="Typo.h5">شما هنوز پکیجی خریداری نکردهاید</MudText>
|
<MudText Typo="Typo.h5">شما هنوز پکیجی خریداری نکردهاید</MudText>
|
||||||
<MudText Typo="Typo.body1" Class="mud-text-secondary" Style="max-width: 500px;">
|
<MudText Typo="Typo.body1" Class="mud-text-secondary" Style="max-width: 500px;">
|
||||||
با خرید پکیج طلایی، به باشگاه مشتریان بپیوندید و از مزایای ویژه مانند پاداش هفتگی و تیمسازی بهرهمند شوید.
|
با خرید پکیج، به باشگاه مشتریان بپیوندید و از مزایای ویژه مانند پاداش هفتگی و تیمسازی بهرهمند شوید.
|
||||||
</MudText>
|
</MudText>
|
||||||
<MudButton Variant="Variant.Filled"
|
<MudButton Variant="Variant.Filled"
|
||||||
Color="Color.Primary"
|
Color="Color.Primary"
|
||||||
@@ -34,7 +34,76 @@
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@* ── G3: راهنمای پکیجهای من (Q28) ── *@
|
||||||
|
<MudAlert Severity="Severity.Info" Variant="Variant.Text" Dense="true" Class="mb-2" Icon="@Icons.Material.Filled.Info">
|
||||||
|
بعد از تکمیل چرخه کیفپول جادویی، میتوانید مجدداً پکیج خریداری کرده و دور جدیدی را آغاز کنید.
|
||||||
|
</MudAlert>
|
||||||
|
|
||||||
<MudGrid Spacing="4">
|
<MudGrid Spacing="4">
|
||||||
|
|
||||||
|
@* Re-Purchase / Cycle Progress Section *@
|
||||||
|
@if (_canRepurchase)
|
||||||
|
{
|
||||||
|
<MudItem xs="12">
|
||||||
|
<MudAlert Severity="Severity.Success" Icon="@Icons.Material.Filled.Celebration" Class="mb-0">
|
||||||
|
<MudStack Row="true" AlignItems="AlignItems.Center" Justify="Justify.SpaceBetween" Style="width:100%">
|
||||||
|
<MudText Typo="Typo.body1">
|
||||||
|
🎉 چرخه جادویی تکمیل شد! میتوانید پکیج جدید بخرید.
|
||||||
|
</MudText>
|
||||||
|
<MudButton Variant="Variant.Filled"
|
||||||
|
Color="Color.Primary"
|
||||||
|
StartIcon="@Icons.Material.Filled.ShoppingCart"
|
||||||
|
OnClick="@(() => Navigation.NavigateTo(RouteConstants.Package.List))">
|
||||||
|
خرید پکیج جدید
|
||||||
|
</MudButton>
|
||||||
|
</MudStack>
|
||||||
|
</MudAlert>
|
||||||
|
</MudItem>
|
||||||
|
}
|
||||||
|
else if (_magicStatus != null && _magicStatus.WalletMode == 1)
|
||||||
|
{
|
||||||
|
<MudItem xs="12">
|
||||||
|
<MudPaper Elevation="2" Class="pa-6">
|
||||||
|
<MudStack Spacing="3">
|
||||||
|
<MudStack Row="true" AlignItems="AlignItems.Center" Spacing="2">
|
||||||
|
<MudIcon Icon="@Icons.Material.Filled.AutoAwesome" Color="Color.Warning" />
|
||||||
|
<MudText Typo="Typo.h6">پیشرفت چرخه جادویی</MudText>
|
||||||
|
@if (_magicStatus.PurchaseCycleCount > 0)
|
||||||
|
{
|
||||||
|
<MudChip T="string" Size="Size.Small" Color="Color.Info">دور @(_magicStatus.PurchaseCycleCount + 1)</MudChip>
|
||||||
|
}
|
||||||
|
</MudStack>
|
||||||
|
|
||||||
|
<MudDivider />
|
||||||
|
|
||||||
|
<MudStack Spacing="2">
|
||||||
|
<MudStack Row="true" Justify="Justify.SpaceBetween">
|
||||||
|
<MudText Typo="Typo.body2" Class="mud-text-secondary">واریز انجامشده:</MudText>
|
||||||
|
<MudText Typo="Typo.body2">@FormatPrice(_magicStatus.MagicTotalDeposited)</MudText>
|
||||||
|
</MudStack>
|
||||||
|
<MudStack Row="true" Justify="Justify.SpaceBetween">
|
||||||
|
<MudText Typo="Typo.body2" Class="mud-text-secondary">سقف واریز:</MudText>
|
||||||
|
<MudText Typo="Typo.body2">@FormatPrice(_magicStatus.MagicMaxDeposit)</MudText>
|
||||||
|
</MudStack>
|
||||||
|
<MudStack Row="true" Justify="Justify.SpaceBetween">
|
||||||
|
<MudText Typo="Typo.body2" Class="mud-text-secondary">باقیمانده:</MudText>
|
||||||
|
<MudText Typo="Typo.body2" Color="Color.Warning">@FormatPrice(_magicStatus.MagicRemainingDeposit)</MudText>
|
||||||
|
</MudStack>
|
||||||
|
|
||||||
|
<MudProgressLinear Color="Color.Primary" Value="@GetDepositProgress()" Class="my-2" Rounded="true" Size="Size.Large">
|
||||||
|
<MudText Typo="Typo.caption"><b>@GetDepositProgress()%</b></MudText>
|
||||||
|
</MudProgressLinear>
|
||||||
|
|
||||||
|
<MudStack Row="true" Justify="Justify.SpaceBetween">
|
||||||
|
<MudText Typo="Typo.body2" Class="mud-text-secondary">اعتبار دریافتی:</MudText>
|
||||||
|
<MudText Typo="Typo.body2" Color="Color.Success">@FormatPrice(_magicStatus.MagicTotalCredited)</MudText>
|
||||||
|
</MudStack>
|
||||||
|
</MudStack>
|
||||||
|
</MudStack>
|
||||||
|
</MudPaper>
|
||||||
|
</MudItem>
|
||||||
|
}
|
||||||
|
|
||||||
<!-- Package Status Card -->
|
<!-- Package Status Card -->
|
||||||
<MudItem xs="12" md="6">
|
<MudItem xs="12" md="6">
|
||||||
<MudPaper Elevation="2" Class="pa-6 h-100">
|
<MudPaper Elevation="2" Class="pa-6 h-100">
|
||||||
@@ -49,7 +118,7 @@
|
|||||||
<MudStack Spacing="2">
|
<MudStack Spacing="2">
|
||||||
<MudStack Row="true" Justify="Justify.SpaceBetween">
|
<MudStack Row="true" Justify="Justify.SpaceBetween">
|
||||||
<MudText Typo="Typo.body2" Class="mud-text-secondary">نوع پکیج:</MudText>
|
<MudText Typo="Typo.body2" Class="mud-text-secondary">نوع پکیج:</MudText>
|
||||||
<MudText Typo="Typo.body2">پکیج طلایی</MudText>
|
<MudText Typo="Typo.body2">@_userStatus.PackageTitle</MudText>
|
||||||
</MudStack>
|
</MudStack>
|
||||||
|
|
||||||
<MudStack Row="true" Justify="Justify.SpaceBetween">
|
<MudStack Row="true" Justify="Justify.SpaceBetween">
|
||||||
@@ -146,7 +215,7 @@
|
|||||||
<MudStack Spacing="3">
|
<MudStack Spacing="3">
|
||||||
<MudStack Row="true" AlignItems="AlignItems.Center" Spacing="2">
|
<MudStack Row="true" AlignItems="AlignItems.Center" Spacing="2">
|
||||||
<MudIcon Icon="@Icons.Material.Filled.Stars" Color="Color.Warning" />
|
<MudIcon Icon="@Icons.Material.Filled.Stars" Color="Color.Warning" />
|
||||||
<MudText Typo="Typo.h6">مزایای پکیج طلایی</MudText>
|
<MudText Typo="Typo.h6">مزایای پکیج</MudText>
|
||||||
</MudStack>
|
</MudStack>
|
||||||
|
|
||||||
<MudDivider />
|
<MudDivider />
|
||||||
|
|||||||
@@ -9,7 +9,9 @@ public partial class MyPackages : ComponentBase
|
|||||||
[Inject] private PackageService PackageService { get; set; } = default!;
|
[Inject] private PackageService PackageService { get; set; } = default!;
|
||||||
|
|
||||||
private UserPackageStatusDto? _userStatus;
|
private UserPackageStatusDto? _userStatus;
|
||||||
|
private MagicWalletStatus? _magicStatus;
|
||||||
private bool _isLoading = true;
|
private bool _isLoading = true;
|
||||||
|
private bool _canRepurchase = false;
|
||||||
|
|
||||||
private List<BreadcrumbItem> _breadcrumbItems = new()
|
private List<BreadcrumbItem> _breadcrumbItems = new()
|
||||||
{
|
{
|
||||||
@@ -30,6 +32,18 @@ public partial class MyPackages : ComponentBase
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
_userStatus = await PackageService.GetUserPackageStatusAsync();
|
_userStatus = await PackageService.GetUserPackageStatusAsync();
|
||||||
|
|
||||||
|
if (_userStatus?.HasPurchasedPackage == true)
|
||||||
|
{
|
||||||
|
_magicStatus = await WalletService.GetMagicWalletStatusAsync();
|
||||||
|
|
||||||
|
// Cycle complete: wallet back to Normal mode, at least one cycle done,
|
||||||
|
// and deposit ceiling fully used (remaining = 0)
|
||||||
|
_canRepurchase = _magicStatus != null
|
||||||
|
&& _magicStatus.WalletMode == 0 // Normal mode
|
||||||
|
&& _magicStatus.PurchaseCycleCount >= 1 // At least one cycle completed
|
||||||
|
&& _magicStatus.MagicRemainingDeposit == 0; // Deposit ceiling used up
|
||||||
|
}
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
@@ -67,4 +81,11 @@ public partial class MyPackages : ComponentBase
|
|||||||
{
|
{
|
||||||
return string.Format("{0:N0} تومان", price);
|
return string.Format("{0:N0} تومان", price);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private int GetDepositProgress()
|
||||||
|
{
|
||||||
|
if (_magicStatus == null || _magicStatus.MagicMaxDeposit <= 0) return 0;
|
||||||
|
var pct = (int)((_magicStatus.MagicTotalDeposited * 100) / _magicStatus.MagicMaxDeposit);
|
||||||
|
return Math.Min(pct, 100);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,11 @@
|
|||||||
<MudContainer MaxWidth="MaxWidth.Large" Class="py-8">
|
<MudContainer MaxWidth="MaxWidth.Large" Class="py-8">
|
||||||
<PageHeader Title="پکیجهای سرمایهگذاری" BackHref="@RouteConstants.Profile.Index" />
|
<PageHeader Title="پکیجهای سرمایهگذاری" BackHref="@RouteConstants.Profile.Index" />
|
||||||
|
|
||||||
|
@* ── G1: راهنمای سیستم پکیجبیس (Q28) ── *@
|
||||||
|
<MudAlert Severity="Severity.Info" Variant="Variant.Text" Dense="true" Class="mb-4" Icon="@Icons.Material.Filled.Info">
|
||||||
|
هر پکیج ویژگیها و مزایای منحصربهفردی دارد. با انتخاب پکیج مناسب، از سقف پاداش و ضریب کیفپول جادویی متفاوتی بهرهمند میشوید.
|
||||||
|
</MudAlert>
|
||||||
|
|
||||||
@if (_isLoading)
|
@if (_isLoading)
|
||||||
{
|
{
|
||||||
<MudStack AlignItems="AlignItems.Center" Class="py-16">
|
<MudStack AlignItems="AlignItems.Center" Class="py-16">
|
||||||
@@ -27,7 +32,7 @@
|
|||||||
{
|
{
|
||||||
<MudAlert Severity="Severity.Success" Class="mb-6" Icon="@Icons.Material.Filled.CheckCircle">
|
<MudAlert Severity="Severity.Success" Class="mb-6" Icon="@Icons.Material.Filled.CheckCircle">
|
||||||
<MudText>
|
<MudText>
|
||||||
شما قبلاً پکیج طلایی را خریداری کردهاید.
|
شما قبلاً پکیج را خریداری کردهاید.
|
||||||
@if (_userStatus.IsClubMemberActive)
|
@if (_userStatus.IsClubMemberActive)
|
||||||
{
|
{
|
||||||
<span>عضویت باشگاه شما فعال است.</span>
|
<span>عضویت باشگاه شما فعال است.</span>
|
||||||
@@ -64,20 +69,43 @@
|
|||||||
<MudText Typo="Typo.h6" Color="Color.Success">@package.FormattedPrice</MudText>
|
<MudText Typo="Typo.h6" Color="Color.Success">@package.FormattedPrice</MudText>
|
||||||
</MudStack>
|
</MudStack>
|
||||||
|
|
||||||
<!-- Features Preview -->
|
<!-- Package Highlights -->
|
||||||
<MudStack Spacing="1" Class="mt-2">
|
<MudStack Spacing="1" Class="mt-2">
|
||||||
<MudStack Row="true" Spacing="1" AlignItems="AlignItems.Center">
|
@if (package.SupportsDirectPurchase)
|
||||||
<MudIcon Icon="@Icons.Material.Filled.Check" Size="Size.Small" Color="Color.Primary" />
|
{
|
||||||
<MudText Typo="Typo.caption">عضویت در باشگاه مشتریان</MudText>
|
<MudStack Row="true" Spacing="1" AlignItems="AlignItems.Center">
|
||||||
</MudStack>
|
<MudIcon Icon="@Icons.Material.Filled.Check" Size="Size.Small" Color="Color.Primary" />
|
||||||
<MudStack Row="true" Spacing="1" AlignItems="AlignItems.Center">
|
<MudText Typo="Typo.caption">پرداخت مستقیم</MudText>
|
||||||
<MudIcon Icon="@Icons.Material.Filled.Check" Size="Size.Small" Color="Color.Primary" />
|
</MudStack>
|
||||||
<MudText Typo="Typo.caption">دریافت پاداش هفتگی</MudText>
|
}
|
||||||
</MudStack>
|
@if (package.SupportsDayaPurchase)
|
||||||
<MudStack Row="true" Spacing="1" AlignItems="AlignItems.Center">
|
{
|
||||||
<MudIcon Icon="@Icons.Material.Filled.Check" Size="Size.Small" Color="Color.Primary" />
|
<MudStack Row="true" Spacing="1" AlignItems="AlignItems.Center">
|
||||||
<MudText Typo="Typo.caption">تیمسازی نامحدود</MudText>
|
<MudIcon Icon="@Icons.Material.Filled.Check" Size="Size.Small" Color="Color.Primary" />
|
||||||
</MudStack>
|
<MudText Typo="Typo.caption">پرداخت با اعتبار دایا</MudText>
|
||||||
|
</MudStack>
|
||||||
|
}
|
||||||
|
@if (package.DiscountMultiplier > 0)
|
||||||
|
{
|
||||||
|
<MudStack Row="true" Spacing="1" AlignItems="AlignItems.Center">
|
||||||
|
<MudIcon Icon="@Icons.Material.Filled.Check" Size="Size.Small" Color="Color.Primary" />
|
||||||
|
<MudText Typo="Typo.caption">ضریب اعتبار: @package.DiscountMultiplier.ToString("F1")x</MudText>
|
||||||
|
</MudStack>
|
||||||
|
}
|
||||||
|
@if (package.MagicWalletMultiplier > 0)
|
||||||
|
{
|
||||||
|
<MudStack Row="true" Spacing="1" AlignItems="AlignItems.Center">
|
||||||
|
<MudIcon Icon="@Icons.Material.Filled.Check" Size="Size.Small" Color="Color.Primary" />
|
||||||
|
<MudText Typo="Typo.caption">کیف پول جادویی: @package.MagicWalletMultiplier.ToString("F1")x</MudText>
|
||||||
|
</MudStack>
|
||||||
|
}
|
||||||
|
@if (package.IsBasePackage)
|
||||||
|
{
|
||||||
|
<MudStack Row="true" Spacing="1" AlignItems="AlignItems.Center">
|
||||||
|
<MudIcon Icon="@Icons.Material.Filled.Star" Size="Size.Small" Color="Color.Warning" />
|
||||||
|
<MudText Typo="Typo.caption">پکیج پایه</MudText>
|
||||||
|
</MudStack>
|
||||||
|
}
|
||||||
</MudStack>
|
</MudStack>
|
||||||
</MudStack>
|
</MudStack>
|
||||||
</MudCardContent>
|
</MudCardContent>
|
||||||
@@ -100,9 +128,9 @@
|
|||||||
<MudGrid Spacing="4">
|
<MudGrid Spacing="4">
|
||||||
<MudItem xs="12" md="8">
|
<MudItem xs="12" md="8">
|
||||||
<MudStack Spacing="2">
|
<MudStack Spacing="2">
|
||||||
<MudText Typo="Typo.h5" Style="color: white;">چرا پکیج طلایی؟</MudText>
|
<MudText Typo="Typo.h5" Style="color: white;">چرا پکیج بخریم؟</MudText>
|
||||||
<MudText Typo="Typo.body1" Style="color: rgba(255,255,255,0.9);">
|
<MudText Typo="Typo.body1" Style="color: rgba(255,255,255,0.9);">
|
||||||
با خرید پکیج طلایی، علاوه بر دسترسی به محصولات ویژه، میتوانید تیم فروش خود را بسازید
|
با خرید پکیج، علاوه بر دسترسی به محصولات ویژه، میتوانید تیم فروش خود را بسازید
|
||||||
و از پاداشهای هفتگی بهرهمند شوید. هر چه تیم شما گستردهتر، درآمد شما بیشتر!
|
و از پاداشهای هفتگی بهرهمند شوید. هر چه تیم شما گستردهتر، درآمد شما بیشتر!
|
||||||
</MudText>
|
</MudText>
|
||||||
</MudStack>
|
</MudStack>
|
||||||
|
|||||||
@@ -64,36 +64,38 @@ public partial class PackageDetail : IDisposable
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
// Load package details
|
// Load package details via Customer RPC
|
||||||
var packageResponse = await PackageClient.GetPackageAsync(request: new() { Id = Id}, cancellationToken: _loadCts.Token);
|
var response = await PackageClient.GetCustomerPackageDetailsAsync(
|
||||||
|
new GetCustomerPackageDetailsRequest { PackageId = Id },
|
||||||
|
cancellationToken: _loadCts.Token);
|
||||||
|
|
||||||
if (packageResponse != null)
|
if (response != null)
|
||||||
{
|
{
|
||||||
|
// Build features from API response
|
||||||
|
var features = response.Features?.Select(f => f.Title).ToList() ?? new List<string>();
|
||||||
|
|
||||||
|
// Build specifications from API features (highlighted ones)
|
||||||
|
var specs = response.Features?
|
||||||
|
.Where(f => f.IsHighlighted)
|
||||||
|
.Select(f => new Specification
|
||||||
|
{
|
||||||
|
Name = f.Title,
|
||||||
|
Value = f.Description,
|
||||||
|
Icon = string.IsNullOrEmpty(f.Icon) ? Icons.Material.Filled.Star : f.Icon
|
||||||
|
}).ToList() ?? new List<Specification>();
|
||||||
|
|
||||||
_package = new PackageDetailDto
|
_package = new PackageDetailDto
|
||||||
{
|
{
|
||||||
Id = packageResponse.Id,
|
Id = response.Id,
|
||||||
Title = packageResponse.Title,
|
Title = response.Title,
|
||||||
Body = packageResponse.Description,
|
Body = response.Description,
|
||||||
Image = packageResponse.ImagePath ?? string.Empty,
|
Image = response.ImagePath ?? string.Empty,
|
||||||
Specifications = new List<Specification>
|
Specifications = specs,
|
||||||
{
|
Features = features,
|
||||||
new() { Name = "ظرفیت", Value = "تا ۲۰۰ عضو", Icon = Icons.Material.Filled.Group },
|
|
||||||
new() { Name = "شجرهنامه", Value = "پیشرفته", Icon = Icons.Material.Filled.AccountTree },
|
|
||||||
new() { Name = "گزارشگیری", Value = "جامع", Icon = Icons.Material.Filled.Analytics },
|
|
||||||
new() { Name = "پشتیبانی", Value = "۲۴ ساعته", Icon = Icons.Material.Filled.Support }
|
|
||||||
},
|
|
||||||
Features = new List<string>
|
|
||||||
{
|
|
||||||
"مدیریت تیم نامحدود",
|
|
||||||
"شجرهنامه بصری",
|
|
||||||
"محاسبه کارمزد خودکار",
|
|
||||||
"گزارشهای مالی",
|
|
||||||
"پشتیبانی اولویتدار"
|
|
||||||
},
|
|
||||||
Pricing = new PricingInfo
|
Pricing = new PricingInfo
|
||||||
{
|
{
|
||||||
OriginalPrice = packageResponse.Price,
|
OriginalPrice = response.Price,
|
||||||
FinalPrice = packageResponse.Price,
|
FinalPrice = response.Price,
|
||||||
HasDiscount = false,
|
HasDiscount = false,
|
||||||
DiscountPercent = 0
|
DiscountPercent = 0
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -44,11 +44,11 @@
|
|||||||
Label="مبلغ (تومان)"
|
Label="مبلغ (تومان)"
|
||||||
Variant="Variant.Outlined"
|
Variant="Variant.Outlined"
|
||||||
Min="10_000"
|
Min="10_000"
|
||||||
Max="100_000_000"
|
Max="1_000_000_000"
|
||||||
Format="N0"
|
Format="N0"
|
||||||
Adornment="Adornment.Start"
|
Adornment="Adornment.Start"
|
||||||
AdornmentIcon="@Icons.Material.Filled.Payments"
|
AdornmentIcon="@Icons.Material.Filled.Payments"
|
||||||
HelperText="حداقل ۱۰,۰۰۰ و حداکثر ۱۰۰,۰۰۰,۰۰۰ تومان" />
|
HelperText="حداقل ۱۰,۰۰۰ و حداکثر ۱,۰۰۰,۰۰۰,۰۰۰ تومان" />
|
||||||
|
|
||||||
@* دکمههای مبلغ سریع *@
|
@* دکمههای مبلغ سریع *@
|
||||||
<MudStack Row="true" Spacing="1" Class="flex-wrap">
|
<MudStack Row="true" Spacing="1" Class="flex-wrap">
|
||||||
|
|||||||
@@ -29,10 +29,8 @@ public partial class ChargeDiscountWallet : ComponentBase
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
// تبدیل تومان به ریال
|
// مبلغ به تومان — CMS خودش موقع ارسال به درگاه ×۱۰ میکنه
|
||||||
var amountInRial = _chargeAmount * 10;
|
var (success, gatewayUrl, error) = await WalletService.InitiateDiscountChargeAsync(_chargeAmount);
|
||||||
|
|
||||||
var (success, gatewayUrl, error) = await WalletService.InitiateDiscountChargeAsync(amountInRial);
|
|
||||||
|
|
||||||
if (success && !string.IsNullOrEmpty(gatewayUrl))
|
if (success && !string.IsNullOrEmpty(gatewayUrl))
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -119,7 +119,7 @@
|
|||||||
لینک دعوت شما هنوز فعال نشده است
|
لینک دعوت شما هنوز فعال نشده است
|
||||||
</MudText>
|
</MudText>
|
||||||
<MudText Typo="Typo.body2" Class="mud-text-secondary mb-1" Style="max-width:560px; margin:0 auto;">
|
<MudText Typo="Typo.body2" Class="mud-text-secondary mb-1" Style="max-width:560px; margin:0 auto;">
|
||||||
برای فعالسازی لینک دعوت، ابتدا <strong>پکیج پایه</strong> را تهیه کنید و سپس در <strong>باشگاه مشتریان</strong> عضو شوید.
|
برای فعالسازی لینک دعوت، ابتدا یکی از <strong>پکیجها</strong> را تهیه کنید و سپس در <strong>باشگاه مشتریان</strong> عضو شوید.
|
||||||
</MudText>
|
</MudText>
|
||||||
<MudText Typo="Typo.body2" Class="mud-text-secondary mb-4" Style="max-width:560px; margin:0 auto;">
|
<MudText Typo="Typo.body2" Class="mud-text-secondary mb-4" Style="max-width:560px; margin:0 auto;">
|
||||||
از مزایای ویژه عضویت بهرهمند شده و با فعالیت در زمینه توسعه فروشگاهها پاداش دریافت کنید.
|
از مزایای ویژه عضویت بهرهمند شده و با فعالیت در زمینه توسعه فروشگاهها پاداش دریافت کنید.
|
||||||
@@ -130,7 +130,7 @@
|
|||||||
Class="rounded-pill"
|
Class="rounded-pill"
|
||||||
StartIcon="@Icons.Material.Filled.ShoppingCart"
|
StartIcon="@Icons.Material.Filled.ShoppingCart"
|
||||||
OnClick="OpenPurchaseOptions">
|
OnClick="OpenPurchaseOptions">
|
||||||
شروع فرآیند تامین اعتبار
|
تهیه پکیج
|
||||||
</MudButton>
|
</MudButton>
|
||||||
</MudPaper>
|
</MudPaper>
|
||||||
}
|
}
|
||||||
@@ -195,88 +195,4 @@
|
|||||||
</MudGrid>
|
</MudGrid>
|
||||||
</MudContainer>
|
</MudContainer>
|
||||||
|
|
||||||
@* ── Purchase Options Dialog ── *@
|
|
||||||
<MudDialog @bind-Visible="_showPurchaseBottomSheet">
|
|
||||||
<DialogContent>
|
|
||||||
<MudStack Spacing="3" Class="pa-2">
|
|
||||||
<MudText Typo="Typo.h6" Align="Align.Center">
|
|
||||||
خرید پکیج پایه ۵۶ میلیون تومان
|
|
||||||
</MudText>
|
|
||||||
<MudDivider />
|
|
||||||
<MudText Typo="Typo.body2" Class="mud-text-secondary">
|
|
||||||
برای خرید پکیج پایه، یکی از روشهای زیر را انتخاب کنید:
|
|
||||||
</MudText>
|
|
||||||
|
|
||||||
<MudPaper Elevation="0" Class="pa-4 rounded-lg" Style="border: 2px solid var(--mud-palette-primary);">
|
|
||||||
<MudStack Spacing="2">
|
|
||||||
<MudStack Row="true" AlignItems="AlignItems.Center" Spacing="2">
|
|
||||||
<MudIcon Icon="@Icons.Material.Filled.CreditCard" Color="Color.Primary" Size="Size.Medium" />
|
|
||||||
<MudText Typo="Typo.subtitle1" Color="Color.Primary"><b>پرداخت مستقیم</b></MudText>
|
|
||||||
</MudStack>
|
|
||||||
<MudText Typo="Typo.body2" Class="mud-text-secondary">پرداخت آنی از طریق درگاه بانکی</MudText>
|
|
||||||
@if (_purchaseCycleCount > 0)
|
|
||||||
{
|
|
||||||
<MudButton Variant="Variant.Filled" Color="Color.Primary" FullWidth="true"
|
|
||||||
Disabled="@_isProcessingPayment"
|
|
||||||
StartIcon="@Icons.Material.Filled.Payment"
|
|
||||||
OnClick="DirectPayment">
|
|
||||||
@if (_isProcessingPayment)
|
|
||||||
{
|
|
||||||
<MudProgressCircular Size="Size.Small" Indeterminate="true" Class="me-2" />
|
|
||||||
<span>در حال انتقال به درگاه...</span>
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
<span>پرداخت با کارت بانکی</span>
|
|
||||||
}
|
|
||||||
</MudButton>
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
<MudButton Variant="Variant.Filled" Color="Color.Primary" FullWidth="true"
|
|
||||||
Disabled="@_isProcessingPayment"
|
|
||||||
StartIcon="@Icons.Material.Filled.Payment"
|
|
||||||
OnClick="DirectPayment">
|
|
||||||
@if (_isProcessingPayment)
|
|
||||||
{
|
|
||||||
<MudProgressCircular Size="Size.Small" Indeterminate="true" Class="me-2" />
|
|
||||||
<span>در حال انتقال به درگاه...</span>
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
<span>پرداخت با کارت بانکی</span>
|
|
||||||
}
|
|
||||||
</MudButton>
|
|
||||||
}
|
|
||||||
</MudStack>
|
|
||||||
</MudPaper>
|
|
||||||
|
|
||||||
@if (_purchaseCycleCount == 0)
|
|
||||||
{
|
|
||||||
<MudPaper Elevation="0" Class="pa-4 rounded-lg" Style="border: 2px solid var(--mud-palette-tertiary);">
|
|
||||||
<MudStack Spacing="2">
|
|
||||||
<MudStack Row="true" AlignItems="AlignItems.Center" Spacing="2">
|
|
||||||
<MudIcon Icon="@Icons.Material.Filled.Diamond" Color="Color.Tertiary" Size="Size.Medium" />
|
|
||||||
<MudText Typo="Typo.subtitle1" Color="Color.Tertiary"><b>اعتبار الماسی دایا</b></MudText>
|
|
||||||
</MudStack>
|
|
||||||
<MudText Typo="Typo.body2" Class="mud-text-secondary">تأمین اعتبار از طریق خرید توکن الماس و دریافت وام</MudText>
|
|
||||||
<MudButton Variant="Variant.Filled" Color="Color.Tertiary" FullWidth="true"
|
|
||||||
StartIcon="@Icons.Material.Filled.AccountBalance" OnClick="DayaLoanPayment">
|
|
||||||
تأمین اعتبار الماسی
|
|
||||||
</MudButton>
|
|
||||||
</MudStack>
|
|
||||||
</MudPaper>
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
<MudAlert Severity="Severity.Info" Dense="true" Class="mt-1">
|
|
||||||
از دور دوم به بعد، خرید پکیج فقط از طریق درگاه بانکی امکانپذیر است.
|
|
||||||
</MudAlert>
|
|
||||||
}
|
|
||||||
|
|
||||||
<MudButton Variant="Variant.Text" Color="Color.Default" FullWidth="true" OnClick="ClosePurchaseOptions">
|
|
||||||
بستن
|
|
||||||
</MudButton>
|
|
||||||
</MudStack>
|
|
||||||
</DialogContent>
|
|
||||||
</MudDialog>
|
|
||||||
|
|||||||
@@ -42,8 +42,7 @@ public partial class Index
|
|||||||
private bool _isClubMemberActive;
|
private bool _isClubMemberActive;
|
||||||
private bool CanShowReferralLink => _hasPurchasedPackage && _isClubMemberActive;
|
private bool CanShowReferralLink => _hasPurchasedPackage && _isClubMemberActive;
|
||||||
|
|
||||||
// Purchase Options Bottom Sheet
|
// Purchase flow
|
||||||
private bool _showPurchaseBottomSheet;
|
|
||||||
private bool _isProcessingPayment;
|
private bool _isProcessingPayment;
|
||||||
private int _purchaseCycleCount; // تعداد دورهای خرید — اگر > 0 فقط IPG مجاز
|
private int _purchaseCycleCount; // تعداد دورهای خرید — اگر > 0 فقط IPG مجاز
|
||||||
|
|
||||||
@@ -55,7 +54,7 @@ public partial class Index
|
|||||||
new(RouteConstants.Profile.Tree, Icons.Material.Filled.AccountTree, "شجرهنامه", "ساختار تیم", "background:rgba(99,102,241,.12); color:#6366f1;"),
|
new(RouteConstants.Profile.Tree, Icons.Material.Filled.AccountTree, "شجرهنامه", "ساختار تیم", "background:rgba(99,102,241,.12); color:#6366f1;"),
|
||||||
new(RouteConstants.Gateway.StoreChooser, Icons.Material.Filled.Store, "فروشگاهها", "ورود به فروشگاه", "background:rgba(16,185,129,.12); color:#10b981;"),
|
new(RouteConstants.Gateway.StoreChooser, Icons.Material.Filled.Store, "فروشگاهها", "ورود به فروشگاه", "background:rgba(16,185,129,.12); color:#10b981;"),
|
||||||
new(RouteConstants.Profile.Wallet, Icons.Material.Filled.AccountBalanceWallet, "کیف پول", "مدیریت و تاریخچه", "background:rgba(16,185,129,.12); color:#10b981;"),
|
new(RouteConstants.Profile.Wallet, Icons.Material.Filled.AccountBalanceWallet, "کیف پول", "مدیریت و تاریخچه", "background:rgba(16,185,129,.12); color:#10b981;"),
|
||||||
new(RouteConstants.Profile.MagicWallet, Icons.Material.Filled.AutoAwesome, "کیفپول جادویی", "شارژ ×2.5", "background:rgba(168,85,247,.12); color:#a855f7;"),
|
new(RouteConstants.Profile.MagicWallet, Icons.Material.Filled.AutoAwesome, "کیفپول جادویی", "شارژ چندبرابری", "background:rgba(168,85,247,.12); color:#a855f7;"),
|
||||||
new(RouteConstants.Profile.WithdrawalRequests, Icons.Material.Filled.RequestPage, "درخواست برداشت", "ثبت و پیگیری", "background:rgba(245,158,11,.12); color:#f59e0b;"),
|
new(RouteConstants.Profile.WithdrawalRequests, Icons.Material.Filled.RequestPage, "درخواست برداشت", "ثبت و پیگیری", "background:rgba(245,158,11,.12); color:#f59e0b;"),
|
||||||
new(RouteConstants.Club.Membership, Icons.Material.Filled.CardMembership, "باشگاه مشتریان", "عضویت و مزایا", "background:rgba(168,85,247,.12); color:#a855f7;"),
|
new(RouteConstants.Club.Membership, Icons.Material.Filled.CardMembership, "باشگاه مشتریان", "عضویت و مزایا", "background:rgba(168,85,247,.12); color:#a855f7;"),
|
||||||
new(RouteConstants.Network.Statistics, Icons.Material.Filled.Groups, "آمار باشگاه", "جزئیات باشگاه", "background:rgba(59,130,246,.12); color:#3b82f6;"),
|
new(RouteConstants.Network.Statistics, Icons.Material.Filled.Groups, "آمار باشگاه", "جزئیات باشگاه", "background:rgba(59,130,246,.12); color:#3b82f6;"),
|
||||||
@@ -394,32 +393,54 @@ public partial class Index
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OpenPurchaseOptions()
|
private async Task OpenPurchaseOptions()
|
||||||
{
|
{
|
||||||
_showPurchaseBottomSheet = true;
|
var options = new DialogOptions
|
||||||
|
{
|
||||||
|
MaxWidth = MaxWidth.Small,
|
||||||
|
FullWidth = true,
|
||||||
|
CloseOnEscapeKey = true,
|
||||||
|
BackdropClick = true
|
||||||
|
};
|
||||||
|
|
||||||
|
var parameters = new DialogParameters<Shared.PackagePurchaseDialog>
|
||||||
|
{
|
||||||
|
{ x => x.PurchaseCycleCount, _purchaseCycleCount }
|
||||||
|
};
|
||||||
|
|
||||||
|
var dialog = await DialogService.ShowAsync<Shared.PackagePurchaseDialog>(
|
||||||
|
string.Empty, parameters, options);
|
||||||
|
var result = await dialog.Result;
|
||||||
|
|
||||||
|
if (result.Canceled) return;
|
||||||
|
|
||||||
|
if (result.Data is Shared.PackagePurchaseDialog.PackagePurchaseResult purchase)
|
||||||
|
{
|
||||||
|
switch (purchase.Method)
|
||||||
|
{
|
||||||
|
case Shared.PackagePurchaseDialog.PaymentMethodType.DirectPayment:
|
||||||
|
await ProcessDirectPayment(purchase.Package.Id);
|
||||||
|
break;
|
||||||
|
case Shared.PackagePurchaseDialog.PaymentMethodType.DayaLoan:
|
||||||
|
await ProcessDayaLoanPayment();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ClosePurchaseOptions()
|
private async Task ProcessDirectPayment(long packageId)
|
||||||
{
|
|
||||||
_showPurchaseBottomSheet = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task DirectPayment()
|
|
||||||
{
|
{
|
||||||
if (_isProcessingPayment) return;
|
if (_isProcessingPayment) return;
|
||||||
|
|
||||||
_isProcessingPayment = true;
|
_isProcessingPayment = true;
|
||||||
_showPurchaseBottomSheet = false;
|
StateHasChanged();
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
// Create callback URL for payment verification
|
var response = await PackageContract.CustomerPurchasePackageAsync(new CustomerPurchasePackageRequest
|
||||||
var callbackUrl = $"{Navigation.BaseUri}profile/payment-callback";
|
|
||||||
|
|
||||||
// Call BFF to initiate payment (UserId is taken from JWT token in BFF)
|
|
||||||
var response = await PackageContract.InitiateBasePackagePaymentAsync(new InitiateBasePackagePaymentRequest
|
|
||||||
{
|
{
|
||||||
CallbackUrl = callbackUrl
|
PackageId = packageId,
|
||||||
|
PurchaseMethod = PurchaseMethodEnum.PurchaseMethodGateway
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!response.Success)
|
if (!response.Success)
|
||||||
@@ -428,7 +449,6 @@ public partial class Index
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Redirect to payment gateway
|
|
||||||
if (!string.IsNullOrEmpty(response.PaymentGatewayUrl))
|
if (!string.IsNullOrEmpty(response.PaymentGatewayUrl))
|
||||||
{
|
{
|
||||||
Navigation.NavigateTo(response.PaymentGatewayUrl, forceLoad: true);
|
Navigation.NavigateTo(response.PaymentGatewayUrl, forceLoad: true);
|
||||||
@@ -449,41 +469,34 @@ public partial class Index
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task DayaLoanPayment()
|
private async Task ProcessDayaLoanPayment()
|
||||||
{
|
{
|
||||||
// Validate user info before redirecting
|
|
||||||
if (string.IsNullOrWhiteSpace(_updateUserRequest.FirstName))
|
if (string.IsNullOrWhiteSpace(_updateUserRequest.FirstName))
|
||||||
{
|
{
|
||||||
_showPurchaseBottomSheet = false;
|
Snackbar.Add("لطفا اطلاعات شخصی خود را تکمیل کنید. (نام وارد نشده)", Severity.Error);
|
||||||
Snackbar.Add($"لطفا اطلاعات شخصی خود را تکمیل کنید. (نام وارد نشده)", Severity.Error);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (string.IsNullOrWhiteSpace(_updateUserRequest.LastName))
|
if (string.IsNullOrWhiteSpace(_updateUserRequest.LastName))
|
||||||
{
|
{
|
||||||
_showPurchaseBottomSheet = false;
|
Snackbar.Add("لطفا اطلاعات شخصی خود را تکمیل کنید. (نام خانوادگی وارد نشده)", Severity.Error);
|
||||||
Snackbar.Add($"لطفا اطلاعات شخصی خود را تکمیل کنید. (نام خانوادگی وارد نشده)", Severity.Error);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (string.IsNullOrWhiteSpace(_updateUserRequest.NationalCode))
|
if (string.IsNullOrWhiteSpace(_updateUserRequest.NationalCode))
|
||||||
{
|
{
|
||||||
_showPurchaseBottomSheet = false;
|
Snackbar.Add("لطفا اطلاعات شخصی خود را تکمیل کنید. (کدملی وارد نشده)", Severity.Error);
|
||||||
Snackbar.Add($"لطفا اطلاعات شخصی خود را تکمیل کنید. (کدملی وارد نشده)", Severity.Error);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (_updateUserRequest.BirthDate == null)
|
if (_updateUserRequest.BirthDate == null)
|
||||||
{
|
{
|
||||||
_showPurchaseBottomSheet = false;
|
Snackbar.Add("لطفا اطلاعات شخصی خود را تکمیل کنید. (تاریخ تولد وارد نشده)", Severity.Error);
|
||||||
Snackbar.Add($"لطفا اطلاعات شخصی خود را تکمیل کنید. (تاریخ تولد وارد نشده)", Severity.Error);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!_addresses.Any())
|
if (!_addresses.Any())
|
||||||
{
|
{
|
||||||
_showPurchaseBottomSheet = false;
|
Snackbar.Add("آدرس محل سکونت شما الزامی است!", Severity.Error);
|
||||||
Snackbar.Add($"آدرس محل سکونت شما الزامی است!", Severity.Error);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
_showPurchaseBottomSheet = false;
|
|
||||||
var url = "https://dayadiamond.ir/profile/creditpurchase/?merchantcode=56146364";
|
var url = "https://dayadiamond.ir/profile/creditpurchase/?merchantcode=56146364";
|
||||||
await JSRuntime.InvokeVoidAsync("open", url, "_blank");
|
await JSRuntime.InvokeVoidAsync("open", url, "_blank");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -36,6 +36,11 @@
|
|||||||
{
|
{
|
||||||
@* ═══ حالت جادویی فعال ═══ *@
|
@* ═══ حالت جادویی فعال ═══ *@
|
||||||
|
|
||||||
|
@* ── G4: هشدار تنظیمات پکیجبیس (Q28) ── *@
|
||||||
|
<MudAlert Severity="Severity.Warning" Variant="Variant.Text" Dense="true" Icon="@Icons.Material.Filled.Warning">
|
||||||
|
سقف واریز و ضریب اعتبار کیفپول جادویی بر اساس پکیج شما تنظیم شده است. پکیجهای بالاتر سقف و ضریب بیشتری دارند.
|
||||||
|
</MudAlert>
|
||||||
|
|
||||||
@* ─── وضعیت و پیشرفت ─── *@
|
@* ─── وضعیت و پیشرفت ─── *@
|
||||||
<MudPaper Elevation="2" Class="pa-5 rounded-xl" Style="background: linear-gradient(135deg, #7c3aed 0%, #a855f7 100%); color: white;">
|
<MudPaper Elevation="2" Class="pa-5 rounded-xl" Style="background: linear-gradient(135deg, #7c3aed 0%, #a855f7 100%); color: white;">
|
||||||
<MudStack Spacing="2">
|
<MudStack Spacing="2">
|
||||||
@@ -92,8 +97,8 @@
|
|||||||
</MudText>
|
</MudText>
|
||||||
|
|
||||||
<MudAlert Severity="MudBlazor.Severity.Info" Dense="true" Class="mb-3" Icon="@Icons.Material.Filled.Info">
|
<MudAlert Severity="MudBlazor.Severity.Info" Dense="true" Class="mb-3" Icon="@Icons.Material.Filled.Info">
|
||||||
مبلغ واریزی شما <strong>×۲.۵</strong> به موجودی اضافه میشود.
|
مبلغ واریزی شما <strong>×@_status.MagicMultiplier.ToString("0.#")</strong> به موجودی اضافه میشود.
|
||||||
مثلاً ۱۰ میلیون واریز = ۲۵ میلیون اعتبار.
|
مثلاً ۱۰ میلیون واریز = @FormatToman((long)(10_000_000 * (decimal)_status.MagicMultiplier)) اعتبار.
|
||||||
</MudAlert>
|
</MudAlert>
|
||||||
|
|
||||||
<MudStack Spacing="2">
|
<MudStack Spacing="2">
|
||||||
@@ -101,7 +106,7 @@
|
|||||||
Label="مبلغ واریز (تومان)"
|
Label="مبلغ واریز (تومان)"
|
||||||
Variant="Variant.Outlined"
|
Variant="Variant.Outlined"
|
||||||
Min="10_000"
|
Min="10_000"
|
||||||
Max="@(_status.MagicRemainingDeposit / 10)"
|
Max="@_status.MagicRemainingDeposit"
|
||||||
Format="N0"
|
Format="N0"
|
||||||
Adornment="Adornment.Start"
|
Adornment="Adornment.Start"
|
||||||
AdornmentIcon="@Icons.Material.Filled.Payments"
|
AdornmentIcon="@Icons.Material.Filled.Payments"
|
||||||
@@ -115,8 +120,8 @@
|
|||||||
<MudText Typo="Typo.body2">@FormatToman(_chargeAmount)</MudText>
|
<MudText Typo="Typo.body2">@FormatToman(_chargeAmount)</MudText>
|
||||||
</MudStack>
|
</MudStack>
|
||||||
<MudStack Row="true" Justify="Justify.SpaceBetween">
|
<MudStack Row="true" Justify="Justify.SpaceBetween">
|
||||||
<MudText Typo="Typo.body2" Color="Color.Success"><strong>اعتبار دریافتی (×۲.۵):</strong></MudText>
|
<MudText Typo="Typo.body2" Color="Color.Success"><strong>اعتبار دریافتی (×@_status.MagicMultiplier.ToString("0.#")):</strong></MudText>
|
||||||
<MudText Typo="Typo.body2" Color="Color.Success"><strong>@FormatToman((long)(_chargeAmount * 2.5m))</strong></MudText>
|
<MudText Typo="Typo.body2" Color="Color.Success"><strong>@FormatToman((long)(_chargeAmount * (decimal)_status.MagicMultiplier))</strong></MudText>
|
||||||
</MudStack>
|
</MudStack>
|
||||||
</MudPaper>
|
</MudPaper>
|
||||||
}
|
}
|
||||||
@@ -125,7 +130,7 @@
|
|||||||
<MudStack Row="true" Spacing="1" Class="flex-wrap">
|
<MudStack Row="true" Spacing="1" Class="flex-wrap">
|
||||||
@foreach (var preset in _presetAmounts)
|
@foreach (var preset in _presetAmounts)
|
||||||
{
|
{
|
||||||
if (preset * 10 <= _status.MagicRemainingDeposit)
|
if (preset <= _status.MagicRemainingDeposit)
|
||||||
{
|
{
|
||||||
<MudButton Variant="Variant.Outlined" Size="Size.Small"
|
<MudButton Variant="Variant.Outlined" Size="Size.Small"
|
||||||
Color="@(_chargeAmount == preset ? Color.Primary : Color.Default)"
|
Color="@(_chargeAmount == preset ? Color.Primary : Color.Default)"
|
||||||
@@ -171,13 +176,13 @@
|
|||||||
<MudExpansionPanel Text="قوانین کیفپول جادویی" MaxHeight="500" IsInitiallyExpanded="false">
|
<MudExpansionPanel Text="قوانین کیفپول جادویی" MaxHeight="500" IsInitiallyExpanded="false">
|
||||||
<MudList T="string" Dense="true">
|
<MudList T="string" Dense="true">
|
||||||
<MudListItem T="string" Icon="@Icons.Material.Filled.CheckCircle" IconColor="Color.Success">
|
<MudListItem T="string" Icon="@Icons.Material.Filled.CheckCircle" IconColor="Color.Success">
|
||||||
هر مبلغ واریزی ×۲.۵ به موجودی اضافه میشود
|
هر مبلغ واریزی ×@_status.MagicMultiplier.ToString("0.#") به موجودی اضافه میشود
|
||||||
</MudListItem>
|
</MudListItem>
|
||||||
<MudListItem T="string" Icon="@Icons.Material.Filled.CheckCircle" IconColor="Color.Success">
|
<MudListItem T="string" Icon="@Icons.Material.Filled.CheckCircle" IconColor="Color.Success">
|
||||||
سقف واریز در هر دور: ۱۰۰ میلیون تومان
|
سقف واریز در هر دور: @FormatPrice(_status.MagicMaxDeposit)
|
||||||
</MudListItem>
|
</MudListItem>
|
||||||
<MudListItem T="string" Icon="@Icons.Material.Filled.CheckCircle" IconColor="Color.Success">
|
<MudListItem T="string" Icon="@Icons.Material.Filled.CheckCircle" IconColor="Color.Success">
|
||||||
حداکثر اعتبار: ۲۵۰ میلیون تومان (سود ۱۵۰٪)
|
حداکثر اعتبار: @FormatPrice(_status.MagicMaxCredit)
|
||||||
</MudListItem>
|
</MudListItem>
|
||||||
<MudListItem T="string" Icon="@Icons.Material.Filled.Warning" IconColor="Color.Warning">
|
<MudListItem T="string" Icon="@Icons.Material.Filled.Warning" IconColor="Color.Warning">
|
||||||
در حالت جادویی، کمیسیون و پاداش تیمی غیرفعال است
|
در حالت جادویی، کمیسیون و پاداش تیمی غیرفعال است
|
||||||
|
|||||||
@@ -46,10 +46,8 @@ public partial class MagicWallet : ComponentBase
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
// تبدیل تومان به ریال
|
// مبلغ به تومان — CMS خودش موقع ارسال به درگاه ×۱۰ میکنه
|
||||||
var amountInRial = _chargeAmount * 10;
|
var (success, gatewayUrl, error) = await WalletService.InitiateMagicChargeAsync(_chargeAmount);
|
||||||
|
|
||||||
var (success, gatewayUrl, error) = await WalletService.InitiateMagicChargeAsync(amountInRial);
|
|
||||||
|
|
||||||
if (success && !string.IsNullOrEmpty(gatewayUrl))
|
if (success && !string.IsNullOrEmpty(gatewayUrl))
|
||||||
{
|
{
|
||||||
@@ -71,8 +69,8 @@ public partial class MagicWallet : ComponentBase
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static string FormatPrice(long priceInRial)
|
private static string FormatPrice(long price)
|
||||||
=> string.Format("{0:N0} تومان", priceInRial / 10);
|
=> string.Format("{0:N0} تومان", price);
|
||||||
|
|
||||||
private static string FormatToman(long toman)
|
private static string FormatToman(long toman)
|
||||||
=> string.Format("{0:N0} تومان", toman);
|
=> string.Format("{0:N0} تومان", toman);
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
@using Blazored.LocalStorage
|
@using Blazored.LocalStorage
|
||||||
@using CMSMicroservice.Protobuf.Protos.Package
|
@using CMSMicroservice.Protobuf.Protos.Package
|
||||||
@using CMSMicroservice.Protobuf.Protos.User
|
@using CMSMicroservice.Protobuf.Protos.User
|
||||||
@inject IJSRuntime JS
|
@using FrontOffice.Main.Utilities
|
||||||
|
|
||||||
|
|
||||||
<PageTitle>نتیجه پرداخت | کارا بازار سلامت</PageTitle>
|
<PageTitle>نتیجه پرداخت | کارا بازار سلامت</PageTitle>
|
||||||
@@ -21,10 +21,10 @@
|
|||||||
<MudText Typo="Typo.h5" Color="Color.Success" Class="mt-4">پرداخت موفق</MudText>
|
<MudText Typo="Typo.h5" Color="Color.Success" Class="mt-4">پرداخت موفق</MudText>
|
||||||
<MudText Typo="Typo.body1" Class="mt-2">@_message</MudText>
|
<MudText Typo="Typo.body1" Class="mt-2">@_message</MudText>
|
||||||
|
|
||||||
@if (!string.IsNullOrEmpty(_refId))
|
@if (_transactionId > 0)
|
||||||
{
|
{
|
||||||
<MudText Typo="Typo.body2" Class="mt-3">
|
<MudText Typo="Typo.body2" Class="mt-3">
|
||||||
<strong>کد پیگیری:</strong> @_refId
|
<strong>کد ارجاعی:</strong> @_transactionId
|
||||||
</MudText>
|
</MudText>
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -33,13 +33,10 @@
|
|||||||
<MudText Typo="Typo.body2" Color="Color.Secondary">
|
<MudText Typo="Typo.body2" Color="Color.Secondary">
|
||||||
موجودی کیف پول اصلی: @FormatPrice(_walletBalance)
|
موجودی کیف پول اصلی: @FormatPrice(_walletBalance)
|
||||||
</MudText>
|
</MudText>
|
||||||
<MudText Typo="Typo.body2" Color="Color.Secondary">
|
|
||||||
موجودی کیف پول اعتباری: @FormatPrice(_discountBalance)
|
|
||||||
</MudText>
|
|
||||||
|
|
||||||
<MudButton Color="Color.Primary" Variant="Variant.Filled" Class="mt-6"
|
<MudButton Color="Color.Primary" Variant="Variant.Filled" Class="mt-6"
|
||||||
OnClick="GoBack">
|
Href="@_successReturnUrl">
|
||||||
بازگشت به پروفایل
|
@_successReturnText
|
||||||
</MudButton>
|
</MudButton>
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -49,8 +46,8 @@
|
|||||||
<MudText Typo="Typo.body1" Class="mt-2">@_message</MudText>
|
<MudText Typo="Typo.body1" Class="mt-2">@_message</MudText>
|
||||||
|
|
||||||
<MudButton Color="Color.Primary" Variant="Variant.Filled" Class="mt-6"
|
<MudButton Color="Color.Primary" Variant="Variant.Filled" Class="mt-6"
|
||||||
OnClick="GoBack">
|
Href="@_failReturnUrl">
|
||||||
بازگشت به پروفایل
|
@_failReturnText
|
||||||
</MudButton>
|
</MudButton>
|
||||||
|
|
||||||
<MudButton Color="Color.Secondary" Variant="Variant.Outlined" Class="mt-3 mr-2"
|
<MudButton Color="Color.Secondary" Variant="Variant.Outlined" Class="mt-3 mr-2"
|
||||||
@@ -64,12 +61,19 @@
|
|||||||
@code {
|
@code {
|
||||||
[Inject] private PackageContract.PackageContractClient PackageContractClient { get; set; } = default!;
|
[Inject] private PackageContract.PackageContractClient PackageContractClient { get; set; } = default!;
|
||||||
[Inject] private UserContract.UserContractClient UserContractClient { get; set; } = default!;
|
[Inject] private UserContract.UserContractClient UserContractClient { get; set; } = default!;
|
||||||
|
[Inject] private DiscountOrderService DiscountOrderService { get; set; } = default!;
|
||||||
[Inject] private ILocalStorageService LocalStorage { get; set; } = default!;
|
[Inject] private ILocalStorageService LocalStorage { get; set; } = default!;
|
||||||
[Inject] private AuthService AuthService { get; set; } = default!;
|
[Inject] private AuthService AuthService { get; set; } = default!;
|
||||||
[Inject] private NavigationManager NavManager { get; set; } = default!;
|
[Inject] private NavigationManager NavManager { get; set; } = default!;
|
||||||
|
|
||||||
private const string TokenStorageKey = "auth:token";
|
private const string TokenStorageKey = "auth:token";
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// نوع پرداخت: package (پیشفرض) | magic-wallet | discount-wallet | discount-order
|
||||||
|
/// </summary>
|
||||||
|
[SupplyParameterFromQuery(Name = "type")]
|
||||||
|
private string? PaymentType { get; set; }
|
||||||
|
|
||||||
[SupplyParameterFromQuery(Name = "orderId")]
|
[SupplyParameterFromQuery(Name = "orderId")]
|
||||||
private long OrderId { get; set; }
|
private long OrderId { get; set; }
|
||||||
|
|
||||||
@@ -85,9 +89,14 @@
|
|||||||
private bool _isLoading = true;
|
private bool _isLoading = true;
|
||||||
private bool _isSuccess;
|
private bool _isSuccess;
|
||||||
private string _message = string.Empty;
|
private string _message = string.Empty;
|
||||||
private string? _refId;
|
private long _transactionId;
|
||||||
private long _walletBalance;
|
private long _walletBalance;
|
||||||
private long _discountBalance;
|
|
||||||
|
// دکمههای بازگشت بسته به نوع پرداخت
|
||||||
|
private string _successReturnUrl = "/profile";
|
||||||
|
private string _successReturnText = "بازگشت به پروفایل";
|
||||||
|
private string _failReturnUrl = "/profile";
|
||||||
|
private string _failReturnText = "بازگشت به پروفایل";
|
||||||
|
|
||||||
protected override async Task OnAfterRenderAsync(bool firstRender)
|
protected override async Task OnAfterRenderAsync(bool firstRender)
|
||||||
{
|
{
|
||||||
@@ -101,35 +110,23 @@
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (OrderId <= 0 || TransactionId <= 0 || string.IsNullOrEmpty(Authority))
|
// تعیین نوع پرداخت — اگر type نباشد، پیشفرض خرید پکیج
|
||||||
{
|
var type = PaymentType?.ToLowerInvariant() ?? "package";
|
||||||
_isSuccess = false;
|
|
||||||
_message = "پارامترهای پرداخت نامعتبر است";
|
|
||||||
_isLoading = false;
|
|
||||||
StateHasChanged();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var response = await PackageContractClient.VerifyBasePackagePaymentAsync(new VerifyBasePackagePaymentRequest
|
switch (type)
|
||||||
{
|
{
|
||||||
OrderId = OrderId,
|
case "magic-wallet":
|
||||||
TransactionId = TransactionId,
|
await VerifyMagicWalletCharge();
|
||||||
PaymentSuccess = Status == "OK",
|
break;
|
||||||
RefId = !string.IsNullOrEmpty(Authority) ? Authority : null,
|
case "discount-wallet":
|
||||||
Message = !string.IsNullOrEmpty(Status) ? Status : null
|
await VerifyDiscountWalletCharge();
|
||||||
});
|
break;
|
||||||
|
case "discount-order":
|
||||||
_isSuccess = response.Success;
|
await VerifyDiscountOrderPayment();
|
||||||
_message = response.Message;
|
break;
|
||||||
_refId = response.ReferenceCode ?? "";
|
default: // "package" or missing
|
||||||
_walletBalance = response.WalletBalance;
|
await VerifyPackagePurchase();
|
||||||
_discountBalance = response.DiscountBalance;
|
break;
|
||||||
|
|
||||||
// اگر پرداخت موفق بود، توکن را refresh میکنیم
|
|
||||||
// چون PackagePurchaseMethod تغییر کرده و باید در claims جدید باشد
|
|
||||||
if (_isSuccess)
|
|
||||||
{
|
|
||||||
await RefreshTokenAsync();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
@@ -144,9 +141,155 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// تأیید خرید پکیج — رفتار فعلی
|
||||||
|
/// </summary>
|
||||||
|
private async Task VerifyPackagePurchase()
|
||||||
|
{
|
||||||
|
_successReturnUrl = "/profile";
|
||||||
|
_successReturnText = "بازگشت به پروفایل";
|
||||||
|
_failReturnUrl = "/profile";
|
||||||
|
_failReturnText = "بازگشت به پروفایل";
|
||||||
|
|
||||||
|
if (OrderId <= 0 || string.IsNullOrEmpty(Authority))
|
||||||
|
{
|
||||||
|
_isSuccess = false;
|
||||||
|
_message = "پارامترهای پرداخت نامعتبر است";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var response = await PackageContractClient.CustomerVerifyPackagePurchaseAsync(new CustomerVerifyPackagePurchaseRequest
|
||||||
|
{
|
||||||
|
OrderId = OrderId,
|
||||||
|
Authority = Authority ?? string.Empty,
|
||||||
|
Status = Status ?? string.Empty
|
||||||
|
});
|
||||||
|
|
||||||
|
_isSuccess = response.Success;
|
||||||
|
_message = response.Message;
|
||||||
|
_transactionId = response.TransactionId;
|
||||||
|
|
||||||
|
if (_isSuccess)
|
||||||
|
{
|
||||||
|
await UpdateWalletBalanceAndRefreshToken();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// تأیید شارژ کیفپول جادویی
|
||||||
|
/// </summary>
|
||||||
|
private async Task VerifyMagicWalletCharge()
|
||||||
|
{
|
||||||
|
_successReturnUrl = "/profile/magic-wallet";
|
||||||
|
_successReturnText = "بازگشت به کیف پول جادویی";
|
||||||
|
_failReturnUrl = "/profile/magic-wallet";
|
||||||
|
_failReturnText = "بازگشت به کیف پول جادویی";
|
||||||
|
|
||||||
|
if (string.IsNullOrEmpty(Authority))
|
||||||
|
{
|
||||||
|
_isSuccess = false;
|
||||||
|
_message = "کد Authority نامعتبر است";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var (success, message) = await WalletService.VerifyMagicChargeAsync(
|
||||||
|
Authority, Status ?? "NOK");
|
||||||
|
|
||||||
|
_isSuccess = success;
|
||||||
|
_message = message;
|
||||||
|
|
||||||
|
if (_isSuccess)
|
||||||
|
{
|
||||||
|
await UpdateWalletBalance();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// تأیید شارژ کیف پول تخفیفی
|
||||||
|
/// </summary>
|
||||||
|
private async Task VerifyDiscountWalletCharge()
|
||||||
|
{
|
||||||
|
_successReturnUrl = "/profile/charge-discount-wallet";
|
||||||
|
_successReturnText = "بازگشت به کیف پول تخفیفی";
|
||||||
|
_failReturnUrl = "/profile/charge-discount-wallet";
|
||||||
|
_failReturnText = "بازگشت به کیف پول تخفیفی";
|
||||||
|
|
||||||
|
if (string.IsNullOrEmpty(Authority))
|
||||||
|
{
|
||||||
|
_isSuccess = false;
|
||||||
|
_message = "کد Authority نامعتبر است";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var (success, message) = await WalletService.VerifyDiscountChargeAsync(
|
||||||
|
Authority, Status ?? "NOK");
|
||||||
|
|
||||||
|
_isSuccess = success;
|
||||||
|
_message = message;
|
||||||
|
|
||||||
|
if (_isSuccess)
|
||||||
|
{
|
||||||
|
await UpdateWalletBalance();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// تأیید پرداخت سفارش فروشگاه تخفیفی
|
||||||
|
/// </summary>
|
||||||
|
private async Task VerifyDiscountOrderPayment()
|
||||||
|
{
|
||||||
|
_successReturnUrl = $"/discount-store/order/{OrderId}";
|
||||||
|
_successReturnText = "مشاهده سفارش";
|
||||||
|
_failReturnUrl = $"/discount-store/order/{OrderId}";
|
||||||
|
_failReturnText = "مشاهده سفارش";
|
||||||
|
|
||||||
|
if (OrderId <= 0 || string.IsNullOrEmpty(Authority))
|
||||||
|
{
|
||||||
|
_isSuccess = false;
|
||||||
|
_message = "پارامترهای پرداخت نامعتبر است";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var (success, message, _) = await DiscountOrderService.VerifyDiscountOrderPaymentAsync(
|
||||||
|
OrderId, Authority, Status ?? "NOK");
|
||||||
|
|
||||||
|
_isSuccess = success;
|
||||||
|
_message = message;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// بروزرسانی موجودی کیف پول
|
||||||
|
/// </summary>
|
||||||
|
private async Task UpdateWalletBalance()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var balances = await WalletService.GetBalancesAsync();
|
||||||
|
_walletBalance = balances.CreditBalance;
|
||||||
|
}
|
||||||
|
catch { /* اگر خطا شد، صفر نمایش بده */ }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// بروزرسانی موجودی + refresh توکن (فقط برای خرید پکیج)
|
||||||
|
/// </summary>
|
||||||
|
private async Task UpdateWalletBalanceAndRefreshToken()
|
||||||
|
{
|
||||||
|
await UpdateWalletBalance();
|
||||||
|
await RefreshTokenAsync();
|
||||||
|
}
|
||||||
|
|
||||||
private void RetryPayment()
|
private void RetryPayment()
|
||||||
{
|
{
|
||||||
NavManager.NavigateTo("/profile");
|
var type = PaymentType?.ToLowerInvariant() ?? "package";
|
||||||
|
var url = type switch
|
||||||
|
{
|
||||||
|
"magic-wallet" => "/profile/magic-wallet",
|
||||||
|
"discount-wallet" => "/profile/charge-discount-wallet",
|
||||||
|
"discount-order" => "/discount-store",
|
||||||
|
_ => "/profile"
|
||||||
|
};
|
||||||
|
NavManager.NavigateTo(url, forceLoad: true);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -174,6 +317,4 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static string FormatPrice(long price) => string.Format("{0:N0} تومان", price);
|
private static string FormatPrice(long price) => string.Format("{0:N0} تومان", price);
|
||||||
|
|
||||||
private async Task GoBack() => await JS.InvokeVoidAsync("history.back");
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -112,6 +112,30 @@ else
|
|||||||
</MudStack>
|
</MudStack>
|
||||||
}
|
}
|
||||||
</MudStack>
|
</MudStack>
|
||||||
|
|
||||||
|
@* نمایش PV سفارش *@
|
||||||
|
@if (_pvData != null && _pvData.TotalPv > 0)
|
||||||
|
{
|
||||||
|
<MudDivider Class="my-2" />
|
||||||
|
<MudStack Spacing="1" Class="pa-2" Style="background-color: var(--mud-palette-background-grey); border-radius: 8px;">
|
||||||
|
<MudStack Row="true" AlignItems="AlignItems.Center" Spacing="1">
|
||||||
|
<MudIcon Icon="@Icons.Material.Filled.TrendingUp" Color="Color.Info" Size="Size.Small" />
|
||||||
|
<MudText Typo="Typo.subtitle2" Color="Color.Info">امتیاز فروش (PV)</MudText>
|
||||||
|
</MudStack>
|
||||||
|
@foreach (var product in _pvData.Products)
|
||||||
|
{
|
||||||
|
<MudStack Row="true" Justify="Justify.SpaceBetween">
|
||||||
|
<MudText Typo="Typo.caption" Class="mud-text-secondary">@product.ProductTitle × @product.Quantity</MudText>
|
||||||
|
<MudText Typo="Typo.caption">@string.Format("{0:N0}", product.TotalPv) PV</MudText>
|
||||||
|
</MudStack>
|
||||||
|
}
|
||||||
|
<MudDivider Class="my-1" />
|
||||||
|
<MudStack Row="true" Justify="Justify.SpaceBetween">
|
||||||
|
<MudText Typo="Typo.body2" Class="fw-bold">جمع PV:</MudText>
|
||||||
|
<MudText Typo="Typo.body2" Color="Color.Info" Class="fw-bold">@string.Format("{0:N0}", _pvData.TotalPv) PV</MudText>
|
||||||
|
</MudStack>
|
||||||
|
</MudStack>
|
||||||
|
}
|
||||||
</MudStack>
|
</MudStack>
|
||||||
</MudPaper>
|
</MudPaper>
|
||||||
</MudContainer>
|
</MudContainer>
|
||||||
|
|||||||
@@ -12,12 +12,17 @@ public partial class OrderDetail : ComponentBase
|
|||||||
[Parameter] public long id { get; set; }
|
[Parameter] public long id { get; set; }
|
||||||
|
|
||||||
private GetUserOrderResponse? _order;
|
private GetUserOrderResponse? _order;
|
||||||
|
private CalculateOrderPVResponse? _pvData;
|
||||||
private bool _loading;
|
private bool _loading;
|
||||||
|
|
||||||
protected override async Task OnParametersSetAsync()
|
protected override async Task OnParametersSetAsync()
|
||||||
{
|
{
|
||||||
_loading = true;
|
_loading = true;
|
||||||
_order = await OrderService.GetOrderAsync(id);
|
_order = await OrderService.GetOrderAsync(id);
|
||||||
|
if (_order != null)
|
||||||
|
{
|
||||||
|
_pvData = await OrderService.CalculateOrderPVAsync(id);
|
||||||
|
}
|
||||||
_loading = false;
|
_loading = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -9,6 +9,7 @@
|
|||||||
@inject AuthService AuthService
|
@inject AuthService AuthService
|
||||||
@inject ISnackbar Snackbar
|
@inject ISnackbar Snackbar
|
||||||
@inject NavigationManager Navigation
|
@inject NavigationManager Navigation
|
||||||
|
@inject PackageService PackageService
|
||||||
|
|
||||||
<MudDialog DisableSidePadding="true">
|
<MudDialog DisableSidePadding="true">
|
||||||
<DialogContent>
|
<DialogContent>
|
||||||
@@ -123,6 +124,23 @@
|
|||||||
private readonly Guid _signGuid = Guid.NewGuid();
|
private readonly Guid _signGuid = Guid.NewGuid();
|
||||||
private System.Timers.Timer? _timer;
|
private System.Timers.Timer? _timer;
|
||||||
private const string TokenStorageKey = "auth:token";
|
private const string TokenStorageKey = "auth:token";
|
||||||
|
private string _packageDisplayName = "پکیج پایه";
|
||||||
|
private string _packageDisplayPrice = "۵۶ میلیون تومان";
|
||||||
|
|
||||||
|
protected override async Task OnInitializedAsync()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var packages = await PackageService.GetAllPackagesAsync();
|
||||||
|
var basePackage = packages.FirstOrDefault(p => p.IsBasePackage) ?? packages.FirstOrDefault();
|
||||||
|
if (basePackage != null)
|
||||||
|
{
|
||||||
|
_packageDisplayName = basePackage.Title;
|
||||||
|
_packageDisplayPrice = $"{basePackage.Price:N0} تومان";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch { /* fallback to defaults */ }
|
||||||
|
}
|
||||||
|
|
||||||
// این Modal غیرقابل بسته شدن است - Options در ShowAsync تنظیم میشوند
|
// این Modal غیرقابل بسته شدن است - Options در ShowAsync تنظیم میشوند
|
||||||
|
|
||||||
@@ -242,7 +260,7 @@
|
|||||||
<p>۱-۳. پاداش معرفی: مبلغی که به ازای هر معرفی موفق به کاربر تعلق میگیرد.</p>
|
<p>۱-۳. پاداش معرفی: مبلغی که به ازای هر معرفی موفق به کاربر تعلق میگیرد.</p>
|
||||||
|
|
||||||
<p><strong>ماده ۲ - شرایط عضویت</strong></p>
|
<p><strong>ماده ۲ - شرایط عضویت</strong></p>
|
||||||
<p>۲-۱. کاربر با پرداخت مبلغ ۵۶ میلیون تومان (پکیج پایه)، امکان عضویت در باشگاه مشتریان را خواهد داشت.</p>
|
<p>۲-۱. کاربر با پرداخت مبلغ {_packageDisplayPrice} ({_packageDisplayName})، امکان عضویت در باشگاه مشتریان را خواهد داشت.</p>
|
||||||
<p>۲-۲. پس از امضای این قرارداد، لینک دعوت کاربر فعال خواهد شد.</p>
|
<p>۲-۲. پس از امضای این قرارداد، لینک دعوت کاربر فعال خواهد شد.</p>
|
||||||
<p>۲-۳. کاربر میتواند حداکثر ۲ نفر را مستقیماً دعوت کند (یک نفر در تیم اول و یک نفر در تیم دوم).</p>
|
<p>۲-۳. کاربر میتواند حداکثر ۲ نفر را مستقیماً دعوت کند (یک نفر در تیم اول و یک نفر در تیم دوم).</p>
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,234 @@
|
|||||||
|
@using FrontOffice.Main.Utilities
|
||||||
|
@inject PackageService PackageService
|
||||||
|
@inject ISnackbar Snackbar
|
||||||
|
|
||||||
|
<MudDialog>
|
||||||
|
<TitleContent>
|
||||||
|
@if (_selectedPackage != null)
|
||||||
|
{
|
||||||
|
<MudStack Row="true" AlignItems="AlignItems.Center" Spacing="2">
|
||||||
|
<MudIconButton Icon="@Icons.Material.Filled.ArrowForward"
|
||||||
|
Size="Size.Small"
|
||||||
|
OnClick="BackToList" />
|
||||||
|
<MudText Typo="Typo.h6">انتخاب روش پرداخت</MudText>
|
||||||
|
</MudStack>
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
<MudStack Row="true" AlignItems="AlignItems.Center" Spacing="2">
|
||||||
|
<MudIcon Icon="@Icons.Material.Filled.ShoppingCart" Color="Color.Primary" />
|
||||||
|
<MudText Typo="Typo.h6">انتخاب پکیج</MudText>
|
||||||
|
</MudStack>
|
||||||
|
}
|
||||||
|
</TitleContent>
|
||||||
|
<DialogContent>
|
||||||
|
@if (_isLoading)
|
||||||
|
{
|
||||||
|
<MudStack AlignItems="AlignItems.Center" Class="py-8">
|
||||||
|
<MudProgressCircular Color="Color.Primary" Indeterminate="true" />
|
||||||
|
<MudText Typo="Typo.body2" Class="mud-text-secondary mt-2">در حال بارگذاری پکیجها...</MudText>
|
||||||
|
</MudStack>
|
||||||
|
}
|
||||||
|
else if (_selectedPackage != null)
|
||||||
|
{
|
||||||
|
@* ── Step 2: Payment method selection ── *@
|
||||||
|
<MudStack Spacing="3">
|
||||||
|
@* Selected Package Summary *@
|
||||||
|
<MudPaper Elevation="0" Class="pa-3 rounded-lg" Style="background:rgba(99,102,241,.06);">
|
||||||
|
<MudStack Row="true" AlignItems="AlignItems.Center" Spacing="2">
|
||||||
|
<MudAvatar Size="Size.Medium" Style="background:rgba(99,102,241,.15); color:#6366f1;">
|
||||||
|
<MudIcon Icon="@Icons.Material.Filled.Inventory2" />
|
||||||
|
</MudAvatar>
|
||||||
|
<MudStack Spacing="0" Class="flex-grow-1">
|
||||||
|
<MudText Typo="Typo.subtitle1"><b>@_selectedPackage.Title</b></MudText>
|
||||||
|
<MudText Typo="Typo.body2" Color="Color.Success">@_selectedPackage.FormattedPrice</MudText>
|
||||||
|
</MudStack>
|
||||||
|
</MudStack>
|
||||||
|
</MudPaper>
|
||||||
|
|
||||||
|
<MudDivider />
|
||||||
|
|
||||||
|
<MudText Typo="Typo.body2" Class="mud-text-secondary">
|
||||||
|
روش پرداخت خود را انتخاب کنید:
|
||||||
|
</MudText>
|
||||||
|
|
||||||
|
@* Direct Payment — always available *@
|
||||||
|
<MudPaper Elevation="0" Class="pa-4 rounded-lg pkg-payment-option"
|
||||||
|
Style="border:2px solid var(--mud-palette-primary); cursor:pointer;"
|
||||||
|
@onclick="() => SelectPaymentMethod(PaymentMethodType.DirectPayment)">
|
||||||
|
<MudStack Spacing="2">
|
||||||
|
<MudStack Row="true" AlignItems="AlignItems.Center" Spacing="2">
|
||||||
|
<MudIcon Icon="@Icons.Material.Filled.CreditCard" Color="Color.Primary" Size="Size.Medium" />
|
||||||
|
<MudStack Spacing="0" Class="flex-grow-1">
|
||||||
|
<MudText Typo="Typo.subtitle1" Color="Color.Primary"><b>پرداخت مستقیم</b></MudText>
|
||||||
|
<MudText Typo="Typo.caption" Class="mud-text-secondary">پرداخت آنی از طریق درگاه بانکی</MudText>
|
||||||
|
</MudStack>
|
||||||
|
<MudIcon Icon="@Icons.Material.Filled.ArrowBack" Color="Color.Primary" Size="Size.Small" />
|
||||||
|
</MudStack>
|
||||||
|
</MudStack>
|
||||||
|
</MudPaper>
|
||||||
|
|
||||||
|
@* Daya Loan — only for base package AND first purchase cycle *@
|
||||||
|
@if (_selectedPackage.SupportsDayaPurchase && PurchaseCycleCount == 0)
|
||||||
|
{
|
||||||
|
<MudPaper Elevation="0" Class="pa-4 rounded-lg pkg-payment-option"
|
||||||
|
Style="border:2px solid var(--mud-palette-tertiary); cursor:pointer;"
|
||||||
|
@onclick="() => SelectPaymentMethod(PaymentMethodType.DayaLoan)">
|
||||||
|
<MudStack Spacing="2">
|
||||||
|
<MudStack Row="true" AlignItems="AlignItems.Center" Spacing="2">
|
||||||
|
<MudIcon Icon="@Icons.Material.Filled.Diamond" Color="Color.Tertiary" Size="Size.Medium" />
|
||||||
|
<MudStack Spacing="0" Class="flex-grow-1">
|
||||||
|
<MudText Typo="Typo.subtitle1" Color="Color.Tertiary"><b>اعتبار الماسی دایا</b></MudText>
|
||||||
|
<MudText Typo="Typo.caption" Class="mud-text-secondary">تأمین اعتبار از طریق خرید توکن الماس</MudText>
|
||||||
|
</MudStack>
|
||||||
|
<MudIcon Icon="@Icons.Material.Filled.ArrowBack" Color="Color.Tertiary" Size="Size.Small" />
|
||||||
|
</MudStack>
|
||||||
|
</MudStack>
|
||||||
|
</MudPaper>
|
||||||
|
}
|
||||||
|
else if (!_selectedPackage.SupportsDayaPurchase)
|
||||||
|
{
|
||||||
|
<MudAlert Severity="Severity.Info" Dense="true" Variant="Variant.Text" Class="mt-1">
|
||||||
|
اعتبار الماسی دایا فقط برای پکیج پایه قابل استفاده است.
|
||||||
|
</MudAlert>
|
||||||
|
}
|
||||||
|
else if (PurchaseCycleCount > 0)
|
||||||
|
{
|
||||||
|
<MudAlert Severity="Severity.Info" Dense="true" Variant="Variant.Text" Class="mt-1">
|
||||||
|
از دور دوم به بعد، خرید پکیج فقط از طریق درگاه بانکی امکانپذیر است.
|
||||||
|
</MudAlert>
|
||||||
|
}
|
||||||
|
</MudStack>
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
@* ── Step 1: Package tile grid ── *@
|
||||||
|
<MudStack Spacing="3">
|
||||||
|
<MudText Typo="Typo.body2" Class="mud-text-secondary">
|
||||||
|
پکیج مورد نظر خود را انتخاب کنید:
|
||||||
|
</MudText>
|
||||||
|
|
||||||
|
<MudGrid Spacing="3">
|
||||||
|
@foreach (var pkg in _packages)
|
||||||
|
{
|
||||||
|
<MudItem xs="12" sm="6" md="@(_packages.Count <= 2 ? 6 : 4)">
|
||||||
|
<MudPaper Elevation="0" Class="pa-4 rounded-xl pkg-tile text-center"
|
||||||
|
Style="@GetTileStyle(pkg)"
|
||||||
|
@onclick="() => SelectPackage(pkg)">
|
||||||
|
@if (pkg.IsBasePackage)
|
||||||
|
{
|
||||||
|
<MudChip T="string" Size="Size.Small" Color="Color.Primary" Variant="Variant.Filled"
|
||||||
|
Class="pkg-tile-badge">پایه</MudChip>
|
||||||
|
}
|
||||||
|
<MudStack Spacing="1" AlignItems="AlignItems.Center">
|
||||||
|
<MudAvatar Size="Size.Large" Style="@GetAvatarStyle(pkg)" Class="mb-1">
|
||||||
|
<MudIcon Icon="@Icons.Material.Filled.Inventory2" Size="Size.Large" />
|
||||||
|
</MudAvatar>
|
||||||
|
<MudText Typo="Typo.subtitle1"><b>@pkg.Title</b></MudText>
|
||||||
|
<MudText Typo="Typo.h6" Color="Color.Success">@pkg.FormattedPrice</MudText>
|
||||||
|
@if (!string.IsNullOrWhiteSpace(pkg.Description))
|
||||||
|
{
|
||||||
|
<MudText Typo="Typo.caption" Class="mud-text-secondary"
|
||||||
|
Style="display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden;">
|
||||||
|
@((MarkupString)pkg.Description)
|
||||||
|
</MudText>
|
||||||
|
}
|
||||||
|
@* Key features *@
|
||||||
|
<MudStack Spacing="0" Class="mt-2" Style="width:100%;">
|
||||||
|
@if (pkg.MagicWalletMultiplier > 0)
|
||||||
|
{
|
||||||
|
<MudText Typo="Typo.caption" Class="mud-text-secondary">
|
||||||
|
<MudIcon Icon="@Icons.Material.Filled.AutoAwesome" Size="Size.Small" Class="me-1" Style="font-size:.85rem;vertical-align:middle;" />
|
||||||
|
ضریب جادویی: @pkg.MagicWalletMultiplier.ToString("F1")x
|
||||||
|
</MudText>
|
||||||
|
}
|
||||||
|
@if (pkg.DiscountMultiplier > 0)
|
||||||
|
{
|
||||||
|
<MudText Typo="Typo.caption" Class="mud-text-secondary">
|
||||||
|
<MudIcon Icon="@Icons.Material.Filled.Discount" Size="Size.Small" Class="me-1" Style="font-size:.85rem;vertical-align:middle;" />
|
||||||
|
ضریب اعتبار: @pkg.DiscountMultiplier.ToString("F1")x
|
||||||
|
</MudText>
|
||||||
|
}
|
||||||
|
@if (pkg.SupportsDayaPurchase)
|
||||||
|
{
|
||||||
|
<MudText Typo="Typo.caption" Color="Color.Tertiary">
|
||||||
|
<MudIcon Icon="@Icons.Material.Filled.Diamond" Size="Size.Small" Class="me-1" Style="font-size:.85rem;vertical-align:middle;" />
|
||||||
|
قابل خرید با دایا
|
||||||
|
</MudText>
|
||||||
|
}
|
||||||
|
</MudStack>
|
||||||
|
</MudStack>
|
||||||
|
</MudPaper>
|
||||||
|
</MudItem>
|
||||||
|
}
|
||||||
|
</MudGrid>
|
||||||
|
</MudStack>
|
||||||
|
}
|
||||||
|
</DialogContent>
|
||||||
|
<DialogActions>
|
||||||
|
<MudButton OnClick="Cancel" Variant="Variant.Text" Color="Color.Default">بستن</MudButton>
|
||||||
|
</DialogActions>
|
||||||
|
</MudDialog>
|
||||||
|
|
||||||
|
@code {
|
||||||
|
[CascadingParameter] private IMudDialogInstance MudDialog { get; set; } = default!;
|
||||||
|
|
||||||
|
/// <summary>Number of previous purchase cycles — controls Daya eligibility</summary>
|
||||||
|
[Parameter] public int PurchaseCycleCount { get; set; }
|
||||||
|
|
||||||
|
private List<PackageDto> _packages = new();
|
||||||
|
private PackageDto? _selectedPackage;
|
||||||
|
private bool _isLoading = true;
|
||||||
|
|
||||||
|
protected override async Task OnInitializedAsync()
|
||||||
|
{
|
||||||
|
_isLoading = true;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
_packages = await PackageService.GetAllPackagesAsync();
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Snackbar.Add("خطا در بارگذاری پکیجها", MudBlazor.Severity.Error);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
_isLoading = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SelectPackage(PackageDto package)
|
||||||
|
{
|
||||||
|
_selectedPackage = package;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void BackToList()
|
||||||
|
{
|
||||||
|
_selectedPackage = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SelectPaymentMethod(PaymentMethodType method)
|
||||||
|
{
|
||||||
|
var result = new PackagePurchaseResult(_selectedPackage!, method);
|
||||||
|
MudDialog.Close(DialogResult.Ok(result));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Cancel() => MudDialog.Cancel();
|
||||||
|
|
||||||
|
private static string GetTileStyle(PackageDto pkg)
|
||||||
|
{
|
||||||
|
return pkg.IsBasePackage
|
||||||
|
? "border:2px solid var(--mud-palette-primary); background:rgba(99,102,241,.04); cursor:pointer;"
|
||||||
|
: "border:2px solid var(--mud-palette-lines-default); background:var(--mud-palette-surface); cursor:pointer;";
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string GetAvatarStyle(PackageDto pkg)
|
||||||
|
{
|
||||||
|
return pkg.IsBasePackage
|
||||||
|
? "background:rgba(99,102,241,.15); color:#6366f1;"
|
||||||
|
: "background:rgba(16,185,129,.12); color:#10b981;";
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum PaymentMethodType { DirectPayment, DayaLoan }
|
||||||
|
public record PackagePurchaseResult(PackageDto Package, PaymentMethodType Method);
|
||||||
|
}
|
||||||
@@ -15,6 +15,8 @@ public class CommissionPayoutDto
|
|||||||
public string AmountFormatted { get; set; } = string.Empty;
|
public string AmountFormatted { get; set; } = string.Empty;
|
||||||
public int Status { get; set; }
|
public int Status { get; set; }
|
||||||
public string DatePersian { get; set; } = string.Empty;
|
public string DatePersian { get; set; } = string.Empty;
|
||||||
|
public long PackageId { get; set; }
|
||||||
|
public string PackageTitle { get; set; } = string.Empty;
|
||||||
|
|
||||||
// Computed properties for UI
|
// Computed properties for UI
|
||||||
public string StatusText => Status switch
|
public string StatusText => Status switch
|
||||||
@@ -69,6 +71,8 @@ public class WeeklyBalanceDto
|
|||||||
public int RightNewMembers { get; set; }
|
public int RightNewMembers { get; set; }
|
||||||
public DateTime StartDate { get; set; }
|
public DateTime StartDate { get; set; }
|
||||||
public DateTime EndDate { get; set; }
|
public DateTime EndDate { get; set; }
|
||||||
|
public long PackageId { get; set; }
|
||||||
|
public string PackageTitle { get; set; } = string.Empty;
|
||||||
|
|
||||||
// Formatted properties
|
// Formatted properties
|
||||||
public string LeftBalanceFormatted => $"{LeftBalance:N0} ";
|
public string LeftBalanceFormatted => $"{LeftBalance:N0} ";
|
||||||
|
|||||||
@@ -78,7 +78,8 @@ public class CommissionService
|
|||||||
long? weekDefinitionId,
|
long? weekDefinitionId,
|
||||||
string? status,
|
string? status,
|
||||||
int pageNumber,
|
int pageNumber,
|
||||||
int pageSize)
|
int pageSize,
|
||||||
|
long? packageId = null)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -108,6 +109,11 @@ public class CommissionService
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (packageId.HasValue && packageId.Value > 0)
|
||||||
|
{
|
||||||
|
request.PackageId = packageId.Value;
|
||||||
|
}
|
||||||
|
|
||||||
var response = await _client.GetMyCommissionPayoutsAsync(request);
|
var response = await _client.GetMyCommissionPayoutsAsync(request);
|
||||||
|
|
||||||
return new CommissionPayoutsResponseDto
|
return new CommissionPayoutsResponseDto
|
||||||
@@ -121,7 +127,9 @@ public class CommissionService
|
|||||||
TotalAmount = p.TotalAmount,
|
TotalAmount = p.TotalAmount,
|
||||||
AmountFormatted = p.AmountFormatted,
|
AmountFormatted = p.AmountFormatted,
|
||||||
Status = p.Status,
|
Status = p.Status,
|
||||||
DatePersian = p.DatePersian
|
DatePersian = p.DatePersian,
|
||||||
|
PackageId = p.PackageId,
|
||||||
|
PackageTitle = p.PackageTitle
|
||||||
}).ToList(),
|
}).ToList(),
|
||||||
TotalCount = (int)(response.MetaData?.TotalCount ?? 0),
|
TotalCount = (int)(response.MetaData?.TotalCount ?? 0),
|
||||||
PageNumber = pageNumber,
|
PageNumber = pageNumber,
|
||||||
@@ -145,7 +153,7 @@ public class CommissionService
|
|||||||
/// Get weekly balance details for a specific week
|
/// Get weekly balance details for a specific week
|
||||||
/// Maps to: CommissionCQ.GetMyWeeklyBalances
|
/// Maps to: CommissionCQ.GetMyWeeklyBalances
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public async Task<WeeklyBalanceDto> GetMyWeeklyBalanceAsync(long? weekDefinitionId = null)
|
public async Task<WeeklyBalanceDto> GetMyWeeklyBalanceAsync(long? weekDefinitionId = null, long? packageId = null)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -164,6 +172,11 @@ public class CommissionService
|
|||||||
request.WeekDefinitionId=7;
|
request.WeekDefinitionId=7;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (packageId.HasValue && packageId.Value > 0)
|
||||||
|
{
|
||||||
|
request.PackageId = packageId.Value;
|
||||||
|
}
|
||||||
|
|
||||||
var response = await _client.GetMyWeeklyBalancesAsync(request);
|
var response = await _client.GetMyWeeklyBalancesAsync(request);
|
||||||
|
|
||||||
if (response.Balances.Count > 0)
|
if (response.Balances.Count > 0)
|
||||||
@@ -183,7 +196,9 @@ public class CommissionService
|
|||||||
LeftNewMembers = balance.LeftLegNewMembers,
|
LeftNewMembers = balance.LeftLegNewMembers,
|
||||||
RightNewMembers = balance.RightLegNewMembers,
|
RightNewMembers = balance.RightLegNewMembers,
|
||||||
StartDate = balance.CalculatedAt?.ToDateTime().AddDays(-7) ?? DateTime.Now.AddDays(-7),
|
StartDate = balance.CalculatedAt?.ToDateTime().AddDays(-7) ?? DateTime.Now.AddDays(-7),
|
||||||
EndDate = balance.CalculatedAt?.ToDateTime() ?? DateTime.Now
|
EndDate = balance.CalculatedAt?.ToDateTime() ?? DateTime.Now,
|
||||||
|
PackageId = balance.PackageId,
|
||||||
|
PackageTitle = balance.PackageTitle
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -227,7 +242,9 @@ public class CommissionService
|
|||||||
TotalAmount = p.TotalAmount,
|
TotalAmount = p.TotalAmount,
|
||||||
AmountFormatted = p.AmountFormatted,
|
AmountFormatted = p.AmountFormatted,
|
||||||
Status = p.Status,
|
Status = p.Status,
|
||||||
DatePersian = p.DatePersian
|
DatePersian = p.DatePersian,
|
||||||
|
PackageId = p.PackageId,
|
||||||
|
PackageTitle = p.PackageTitle
|
||||||
}).ToList();
|
}).ToList();
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
|
|||||||
@@ -112,6 +112,27 @@ public class DiscountOrderService
|
|||||||
catch { return false; }
|
catch { return false; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task<(bool Success, string Message, long OrderId)> VerifyDiscountOrderPaymentAsync(
|
||||||
|
long orderId, string authority, string status)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var response = await _client.CustomerVerifyDiscountOrderPaymentAsync(
|
||||||
|
new CustomerVerifyDiscountOrderPaymentRequest
|
||||||
|
{
|
||||||
|
OrderId = orderId,
|
||||||
|
Authority = authority,
|
||||||
|
Status = status
|
||||||
|
});
|
||||||
|
|
||||||
|
return (response.Success, response.Message, response.OrderId);
|
||||||
|
}
|
||||||
|
catch (Grpc.Core.RpcException ex)
|
||||||
|
{
|
||||||
|
return (false, ex.Status.Detail ?? "خطا در بررسی وضعیت پرداخت", orderId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public async Task<DiscountOrderListResult> GetUserOrdersAsync(int page = 1, int pageSize = 10)
|
public async Task<DiscountOrderListResult> GetUserOrdersAsync(int page = 1, int pageSize = 10)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
|
|||||||
@@ -97,4 +97,22 @@ public class OrderService
|
|||||||
return 0.10;
|
return 0.10;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// محاسبه PV سفارش
|
||||||
|
/// </summary>
|
||||||
|
public async Task<CalculateOrderPVResponse?> CalculateOrderPVAsync(long orderId)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return await _userOrderContractClient.CalculateOrderPVAsync(new CalculateOrderPVRequest
|
||||||
|
{
|
||||||
|
OrderId = orderId
|
||||||
|
});
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -10,8 +10,17 @@ public record PackageDto(
|
|||||||
string Title,
|
string Title,
|
||||||
string Description,
|
string Description,
|
||||||
string ImageUrl,
|
string ImageUrl,
|
||||||
long Price)
|
long Price,
|
||||||
|
long ActivationFee = 0,
|
||||||
|
double DiscountMultiplier = 0,
|
||||||
|
double MagicWalletMultiplier = 0,
|
||||||
|
long MagicWalletMaxDeposit = 0,
|
||||||
|
long MagicWalletMaxCredit = 0,
|
||||||
|
bool IsBasePackage = false,
|
||||||
|
bool SupportsDayaPurchase = false,
|
||||||
|
bool SupportsDirectPurchase = false)
|
||||||
{
|
{
|
||||||
|
/// <summary>قیمت فرمتشده به تومان</summary>
|
||||||
public string FormattedPrice => string.Format("{0:N0} تومان", Price);
|
public string FormattedPrice => string.Format("{0:N0} تومان", Price);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -20,6 +29,7 @@ public record PackageDto(
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public record UserPackageStatusDto(
|
public record UserPackageStatusDto(
|
||||||
bool HasPurchasedPackage,
|
bool HasPurchasedPackage,
|
||||||
|
string? PackageTitle,
|
||||||
string? PurchaseMethod, // DayaLoan, DirectPurchase, or null
|
string? PurchaseMethod, // DayaLoan, DirectPurchase, or null
|
||||||
bool IsClubMemberActive,
|
bool IsClubMemberActive,
|
||||||
long WalletBalance,
|
long WalletBalance,
|
||||||
@@ -55,7 +65,15 @@ public class PackageService
|
|||||||
m.Title,
|
m.Title,
|
||||||
m.Description,
|
m.Description,
|
||||||
m.ImagePath,
|
m.ImagePath,
|
||||||
m.Price))
|
m.Price,
|
||||||
|
m.ActivationFee,
|
||||||
|
m.DiscountMultiplier,
|
||||||
|
m.MagicWalletMultiplier,
|
||||||
|
m.MagicWalletMaxDeposit,
|
||||||
|
m.MagicWalletMaxCredit,
|
||||||
|
m.IsBasePackage,
|
||||||
|
m.SupportsDayaPurchase,
|
||||||
|
m.SupportsDirectPurchase))
|
||||||
.ToList();
|
.ToList();
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
@@ -99,15 +117,32 @@ public class PackageService
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Get user's package purchase status
|
/// Get user's package purchase status
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public Task<UserPackageStatusDto> GetUserPackageStatusAsync(CancellationToken ct = default)
|
public async Task<UserPackageStatusDto> GetUserPackageStatusAsync(CancellationToken ct = default)
|
||||||
{
|
{
|
||||||
// TODO: Connect to GetUserPackageStatus RPC when available in FrontOffice.BFF
|
try
|
||||||
return Task.FromResult(new UserPackageStatusDto(
|
{
|
||||||
HasPurchasedPackage: false,
|
var response = await _client.GetUserPackageStatusAsync(
|
||||||
PurchaseMethod: null,
|
new GetUserPackageStatusRequest(), cancellationToken: ct);
|
||||||
IsClubMemberActive: false,
|
|
||||||
WalletBalance: 0,
|
return new UserPackageStatusDto(
|
||||||
CanActivateClubMembership: false,
|
HasPurchasedPackage: response.HasPurchasedPackage,
|
||||||
PurchaseDate: null));
|
PackageTitle: null,
|
||||||
|
PurchaseMethod: response.PackagePurchaseMethod,
|
||||||
|
IsClubMemberActive: response.IsClubMemberActive,
|
||||||
|
WalletBalance: response.WalletBalance,
|
||||||
|
CanActivateClubMembership: response.CanActivateClubMembership,
|
||||||
|
PurchaseDate: response.LastPurchaseDate?.ToDateTime());
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
return new UserPackageStatusDto(
|
||||||
|
HasPurchasedPackage: false,
|
||||||
|
PackageTitle: null,
|
||||||
|
PurchaseMethod: null,
|
||||||
|
IsClubMemberActive: false,
|
||||||
|
WalletBalance: 0,
|
||||||
|
CanActivateClubMembership: false,
|
||||||
|
PurchaseDate: null);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
using DateTimeConverterCL;
|
using DateTimeConverterCL;
|
||||||
using CMSMicroservice.Protobuf.Protos.UserWallet;
|
using CMSMicroservice.Protobuf.Protos.UserWallet;
|
||||||
using CMSMicroservice.Protobuf.Protos.UserWalletChangeLog;
|
|
||||||
using Google.Protobuf.WellKnownTypes;
|
using Google.Protobuf.WellKnownTypes;
|
||||||
|
|
||||||
namespace FrontOffice.Main.Utilities;
|
namespace FrontOffice.Main.Utilities;
|
||||||
@@ -33,7 +32,9 @@ public record MagicWalletStatus(
|
|||||||
long MagicRemainingDeposit,
|
long MagicRemainingDeposit,
|
||||||
long Balance,
|
long Balance,
|
||||||
DateTime? MagicActivatedAt,
|
DateTime? MagicActivatedAt,
|
||||||
int PurchaseCycleCount
|
int PurchaseCycleCount,
|
||||||
|
double MagicMultiplier = 2.5,
|
||||||
|
long MagicMaxCredit = 2_500_000_000
|
||||||
);
|
);
|
||||||
|
|
||||||
public class WalletService
|
public class WalletService
|
||||||
@@ -63,7 +64,7 @@ public class WalletService
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var request = new GetCustomerWalletChangeLogRequest();
|
var request = new GetCustomerWalletHistoryRequest();
|
||||||
if (referenceId.HasValue)
|
if (referenceId.HasValue)
|
||||||
{
|
{
|
||||||
request.ReferenceId = referenceId.Value;
|
request.ReferenceId = referenceId.Value;
|
||||||
@@ -72,7 +73,7 @@ public class WalletService
|
|||||||
{
|
{
|
||||||
request.IsIncrease = isIncrease.Value;
|
request.IsIncrease = isIncrease.Value;
|
||||||
}
|
}
|
||||||
var response = await _client.GetCustomerWalletChangeLogAsync(request);
|
var response = await _client.GetCustomerWalletHistoryAsync(request);
|
||||||
|
|
||||||
return response.Models
|
return response.Models
|
||||||
.Select(log => new WalletTransaction(
|
.Select(log => new WalletTransaction(
|
||||||
@@ -96,7 +97,7 @@ public class WalletService
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static string ResolveTransactionDate(CustomerWalletChangeLogModel model)
|
private static string ResolveTransactionDate(CustomerWalletHistoryModel model)
|
||||||
{
|
{
|
||||||
if (model.CreatedAt is not null)
|
if (model.CreatedAt is not null)
|
||||||
{
|
{
|
||||||
@@ -114,7 +115,7 @@ public class WalletService
|
|||||||
return DateTime.Now.MiladiToJalaliWithTime();
|
return DateTime.Now.MiladiToJalaliWithTime();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static string ResolveDescription(CustomerWalletChangeLogModel model)
|
private static string ResolveDescription(CustomerWalletHistoryModel model)
|
||||||
{
|
{
|
||||||
var parts = new List<string>();
|
var parts = new List<string>();
|
||||||
|
|
||||||
@@ -214,7 +215,9 @@ public class WalletService
|
|||||||
response.MagicRemainingDeposit,
|
response.MagicRemainingDeposit,
|
||||||
response.Balance,
|
response.Balance,
|
||||||
activatedAt,
|
activatedAt,
|
||||||
response.PurchaseCycleCount
|
response.PurchaseCycleCount,
|
||||||
|
response.MagicMultiplier > 0 ? response.MagicMultiplier : 2.5,
|
||||||
|
response.MagicMaxCredit > 0 ? response.MagicMaxCredit : 2_500_000_000
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
@@ -263,6 +266,44 @@ public class WalletService
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ============= Wallet Verify Methods =============
|
||||||
|
|
||||||
|
public async Task<(bool Success, string Message)> VerifyMagicChargeAsync(string authority, string status)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var response = await _client.VerifyMagicChargeAsync(new VerifyWalletChargeRequest
|
||||||
|
{
|
||||||
|
Authority = authority,
|
||||||
|
Status = status
|
||||||
|
});
|
||||||
|
|
||||||
|
return (response.Success, response.Message);
|
||||||
|
}
|
||||||
|
catch (Grpc.Core.RpcException ex)
|
||||||
|
{
|
||||||
|
return (false, ex.Status.Detail ?? "خطا در بررسی وضعیت پرداخت");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<(bool Success, string Message)> VerifyDiscountChargeAsync(string authority, string status)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var response = await _client.VerifyDiscountChargeAsync(new VerifyWalletChargeRequest
|
||||||
|
{
|
||||||
|
Authority = authority,
|
||||||
|
Status = status
|
||||||
|
});
|
||||||
|
|
||||||
|
return (response.Success, response.Message);
|
||||||
|
}
|
||||||
|
catch (Grpc.Core.RpcException ex)
|
||||||
|
{
|
||||||
|
return (false, ex.Status.Detail ?? "خطا در بررسی وضعیت پرداخت");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public int GetWalletMode()
|
public int GetWalletMode()
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
|
|||||||
@@ -1611,3 +1611,30 @@ html, body {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*#endregion*/
|
/*#endregion*/
|
||||||
|
|
||||||
|
/* ── Package Purchase Dialog tiles ── */
|
||||||
|
.pkg-tile {
|
||||||
|
transition: transform .2s ease, box-shadow .2s ease, border-color .2s ease;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
.pkg-tile:hover {
|
||||||
|
transform: translateY(-3px);
|
||||||
|
box-shadow: 0 6px 20px rgba(0,0,0,.08);
|
||||||
|
border-color: var(--mud-palette-primary) !important;
|
||||||
|
}
|
||||||
|
.pkg-tile-badge {
|
||||||
|
position: absolute;
|
||||||
|
top: 8px;
|
||||||
|
right: 8px;
|
||||||
|
}
|
||||||
|
.pkg-payment-option {
|
||||||
|
transition: transform .15s ease, box-shadow .15s ease;
|
||||||
|
}
|
||||||
|
.pkg-payment-option:hover {
|
||||||
|
transform: translateY(-2px);
|
||||||
|
box-shadow: 0 4px 12px rgba(0,0,0,.06);
|
||||||
|
}
|
||||||
|
@media (max-width: 600px) {
|
||||||
|
.pkg-tile { padding: .8rem !important; }
|
||||||
|
.pkg-tile .mud-avatar-large { width: 48px !important; height: 48px !important; }
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user