From 3bffc13ffd700b9eb8f7ff29716ce175b5b30c6a Mon Sep 17 00:00:00 2001 From: masoodafar-web Date: Thu, 26 Feb 2026 22:01:55 +0330 Subject: [PATCH] feat(T4.2+T4.3+F3): conditional payment, re-purchase, PV display T4.2: Conditional Payment in Checkout - Load package flags via PackageService.GetAllPackagesAsync - Respect SupportsDirectPurchase/SupportsDayaPurchase flags - Add Daya loan payment button when supported - Show alert when no payment method available T4.3: MyPackages Re-Purchase Logic - Load MagicWallet status to detect cycle completion - Show re-purchase CTA when magic cycle is complete - Show magic wallet progress bar during active cycle - Display deposit progress, remaining, and credited amounts F3: PV Display in Order Details - Add CalculateOrderPVAsync to OrderService - Show per-product PV and total PV in Store OrderDetail - Update NuGet to v0.0.188 --- src/FrontOffice.Main/FrontOffice.Main.csproj | 2 +- src/FrontOffice.Main/Pages/Checkout.razor | 23 ++++++- src/FrontOffice.Main/Pages/Checkout.razor.cs | 33 +++++++--- .../Pages/Package/MyPackages.razor | 64 +++++++++++++++++++ .../Pages/Package/MyPackages.razor.cs | 21 ++++++ .../Pages/Store/OrderDetail.razor | 24 +++++++ .../Pages/Store/OrderDetail.razor.cs | 5 ++ .../Utilities/OrderService.cs | 18 ++++++ 8 files changed, 180 insertions(+), 10 deletions(-) diff --git a/src/FrontOffice.Main/FrontOffice.Main.csproj b/src/FrontOffice.Main/FrontOffice.Main.csproj index 9f61d09..9be664d 100644 --- a/src/FrontOffice.Main/FrontOffice.Main.csproj +++ b/src/FrontOffice.Main/FrontOffice.Main.csproj @@ -11,7 +11,7 @@ - + diff --git a/src/FrontOffice.Main/Pages/Checkout.razor b/src/FrontOffice.Main/Pages/Checkout.razor index 6662eb7..036390a 100644 --- a/src/FrontOffice.Main/Pages/Checkout.razor +++ b/src/FrontOffice.Main/Pages/Checkout.razor @@ -207,11 +207,32 @@ FullWidth="true" StartIcon="@Icons.Material.Filled.Payment" OnClick="ProcessPayment" - Disabled="@(!CanProceedToPayment || _isProcessingPayment)" + Disabled="@(!CanProceedToPayment || _isProcessingPayment || !_selectedPackage.SupportsDirectPurchase)" Class="mt-2"> @(_isProcessingPayment ? "در حال پردازش..." : "پرداخت آنلاین") + @if (_selectedPackage.SupportsDayaPurchase) + { + + تأمین اعتبار الماسی دایا + + } + + @if (!_selectedPackage.SupportsDirectPurchase && !_selectedPackage.SupportsDayaPurchase) + { + + این پکیج در حال حاضر قابل خرید نیست. + + } + @if (!CanProceedToPayment) { diff --git a/src/FrontOffice.Main/Pages/Checkout.razor.cs b/src/FrontOffice.Main/Pages/Checkout.razor.cs index cdb5cb2..770a4b8 100644 --- a/src/FrontOffice.Main/Pages/Checkout.razor.cs +++ b/src/FrontOffice.Main/Pages/Checkout.razor.cs @@ -3,6 +3,7 @@ using CMSMicroservice.Protobuf.Protos.Package; using CMSMicroservice.Protobuf.Protos.UserAddress; using FrontOffice.Main.Utilities; using Microsoft.AspNetCore.Components; +using Microsoft.JSInterop; using MudBlazor; using Severity = MudBlazor.Severity; @@ -10,6 +11,7 @@ namespace FrontOffice.Main.Pages; public partial class Checkout { + [Inject] private PackageService PackageService { get; set; } = default!; [Inject] private PackageContract.PackageContractClient PackageClient { get; set; } = default!; [Inject] private UserAddressContract.UserAddressContractClient UserAddressContract { get; set; } = default!; @@ -47,15 +49,18 @@ public partial class Checkout { try { - var response = await PackageClient.GetPackageAsync(new() { Id = PackageId.Value }); - if (response != null) + var packages = await PackageService.GetAllPackagesAsync(); + var pkg = packages.FirstOrDefault(p => p.Id == PackageId.Value); + if (pkg != null) { _selectedPackage = new Pack( - Id: response.Id, - Title: response.Title, - Body: response.Description, - Image: response.ImagePath ?? string.Empty, - Price: response.Price + Id: pkg.Id, + Title: pkg.Title, + Body: pkg.Description, + Image: pkg.ImageUrl, + Price: pkg.Price, + SupportsDirectPurchase: pkg.SupportsDirectPurchase, + SupportsDayaPurchase: pkg.SupportsDayaPurchase ); _finalPrice = _selectedPackage.Price; } @@ -213,5 +218,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); } \ No newline at end of file diff --git a/src/FrontOffice.Main/Pages/Package/MyPackages.razor b/src/FrontOffice.Main/Pages/Package/MyPackages.razor index f8ea30b..8aba2d6 100644 --- a/src/FrontOffice.Main/Pages/Package/MyPackages.razor +++ b/src/FrontOffice.Main/Pages/Package/MyPackages.razor @@ -35,6 +35,70 @@ else { + + @* Re-Purchase / Cycle Progress Section *@ + @if (_canRepurchase) + { + + + + + 🎉 چرخه جادویی تکمیل شد! می‌توانید پکیج جدید بخرید. + + + خرید پکیج جدید + + + + + } + else if (_magicStatus != null && _magicStatus.WalletMode == 1) + { + + + + + + پیشرفت چرخه جادویی + @if (_magicStatus.PurchaseCycleCount > 0) + { + دور @(_magicStatus.PurchaseCycleCount + 1) + } + + + + + + + واریز انجام‌شده: + @FormatPrice(_magicStatus.MagicTotalDeposited) + + + سقف واریز: + @FormatPrice(_magicStatus.MagicMaxDeposit) + + + باقیمانده: + @FormatPrice(_magicStatus.MagicRemainingDeposit) + + + + @GetDepositProgress()% + + + + اعتبار دریافتی: + @FormatPrice(_magicStatus.MagicTotalCredited) + + + + + + } + diff --git a/src/FrontOffice.Main/Pages/Package/MyPackages.razor.cs b/src/FrontOffice.Main/Pages/Package/MyPackages.razor.cs index 21ec012..4644f92 100644 --- a/src/FrontOffice.Main/Pages/Package/MyPackages.razor.cs +++ b/src/FrontOffice.Main/Pages/Package/MyPackages.razor.cs @@ -9,7 +9,9 @@ public partial class MyPackages : ComponentBase [Inject] private PackageService PackageService { get; set; } = default!; private UserPackageStatusDto? _userStatus; + private MagicWalletStatus? _magicStatus; private bool _isLoading = true; + private bool _canRepurchase = false; private List _breadcrumbItems = new() { @@ -30,6 +32,18 @@ public partial class MyPackages : ComponentBase try { _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) { @@ -67,4 +81,11 @@ public partial class MyPackages : ComponentBase { 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); + } } diff --git a/src/FrontOffice.Main/Pages/Store/OrderDetail.razor b/src/FrontOffice.Main/Pages/Store/OrderDetail.razor index d94751d..abfd053 100644 --- a/src/FrontOffice.Main/Pages/Store/OrderDetail.razor +++ b/src/FrontOffice.Main/Pages/Store/OrderDetail.razor @@ -112,6 +112,30 @@ else } + + @* نمایش PV سفارش *@ + @if (_pvData != null && _pvData.TotalPv > 0) + { + + + + + امتیاز فروش (PV) + + @foreach (var product in _pvData.Products) + { + + @product.ProductTitle × @product.Quantity + @string.Format("{0:N0}", product.TotalPv) PV + + } + + + جمع PV: + @string.Format("{0:N0}", _pvData.TotalPv) PV + + + } diff --git a/src/FrontOffice.Main/Pages/Store/OrderDetail.razor.cs b/src/FrontOffice.Main/Pages/Store/OrderDetail.razor.cs index 5961f8e..a8ed6fa 100644 --- a/src/FrontOffice.Main/Pages/Store/OrderDetail.razor.cs +++ b/src/FrontOffice.Main/Pages/Store/OrderDetail.razor.cs @@ -12,12 +12,17 @@ public partial class OrderDetail : ComponentBase [Parameter] public long id { get; set; } private GetUserOrderResponse? _order; + private CalculateOrderPVResponse? _pvData; private bool _loading; protected override async Task OnParametersSetAsync() { _loading = true; _order = await OrderService.GetOrderAsync(id); + if (_order != null) + { + _pvData = await OrderService.CalculateOrderPVAsync(id); + } _loading = false; } diff --git a/src/FrontOffice.Main/Utilities/OrderService.cs b/src/FrontOffice.Main/Utilities/OrderService.cs index 5f3ca8f..39d9cfb 100644 --- a/src/FrontOffice.Main/Utilities/OrderService.cs +++ b/src/FrontOffice.Main/Utilities/OrderService.cs @@ -97,4 +97,22 @@ public class OrderService return 0.10; } } + + /// + /// محاسبه PV سفارش + /// + public async Task CalculateOrderPVAsync(long orderId) + { + try + { + return await _userOrderContractClient.CalculateOrderPVAsync(new CalculateOrderPVRequest + { + OrderId = orderId + }); + } + catch + { + return null; + } + } } \ No newline at end of file