From cc721da65f6ccff28e60fefeb26352c32afcf6d3 Mon Sep 17 00:00:00 2001 From: masoodafar-web Date: Fri, 12 Dec 2025 10:24:43 +0330 Subject: [PATCH] feat: Add manual membership payment page and week picker component --- .../Payment/ManualMembershipPayment.razor | 131 ++++++++++++++++++ .../Payment/ManualMembershipPayment.razor.cs | 103 ++++++++++++++ src/BackOffice/BackOffice.csproj | 4 +- .../Pages/AutoComplete/WeekNumberPicker.razor | 21 +++ .../AutoComplete/WeekNumberPicker.razor.cs | 107 ++++++++++++++ .../Pages/Commission/Dashboard.razor | 11 +- .../Pages/Commission/Dashboard.razor.cs | 23 ++- .../Pages/Commission/UserPayouts.razor | 24 ++-- .../Pages/Commission/UserPayouts.razor.cs | 19 ++- .../Pages/Commission/WithdrawalReports.razor | 7 +- .../Pages/Commission/WithdrawalRequests.razor | 11 +- .../Pages/Network/BalancesReport.razor | 7 +- .../Pages/Payment/ManualPayments.razor | 10 +- .../SystemManagement/WorkerControl.razor | 8 +- .../Pages/UserOrder/UserOrderMainPage.razor | 10 +- src/BackOffice/Shared/NavMenu.razor | 18 +++ 16 files changed, 448 insertions(+), 66 deletions(-) create mode 100644 src/BackOffice.Main/Pages/Payment/ManualMembershipPayment.razor create mode 100644 src/BackOffice.Main/Pages/Payment/ManualMembershipPayment.razor.cs create mode 100644 src/BackOffice/Pages/AutoComplete/WeekNumberPicker.razor create mode 100644 src/BackOffice/Pages/AutoComplete/WeekNumberPicker.razor.cs diff --git a/src/BackOffice.Main/Pages/Payment/ManualMembershipPayment.razor b/src/BackOffice.Main/Pages/Payment/ManualMembershipPayment.razor new file mode 100644 index 0000000..18e7710 --- /dev/null +++ b/src/BackOffice.Main/Pages/Payment/ManualMembershipPayment.razor @@ -0,0 +1,131 @@ +@page "/payment/membership" +@using BackOffice.BFF.ManualPayment.Protobuf +@using BackOffice.Main.Pages.AutoComplete +@attribute [Authorize(Roles = "Admin,SuperAdmin")] + +پرداخت دستی عضویت + + + + + + + + پرداخت دستی عضویت + + + + + + + + + + + + + + + + + + + + + + + + + + + + @if (_showResult) + { + + @_resultMessage + شماره تراکنش: @_transactionId + شماره سفارش: @_orderId + موجودی جدید کیف پول: @_newWalletBalance.ToString("N0") ریال + + } + + + + + @if (_isProcessing) + { + + در حال ثبت... + } + else + { + ثبت پرداخت + } + + + + پاک کردن فرم + + + + + + + + + + + راهنما + + + + + این صفحه برای ثبت پرداخت‌های دستی عضویت استفاده می‌شود. پس از ثبت: + + + مبلغ به کیف پول کاربر (Balance و DiscountBalance) اضافه می‌شود + + + لاگ تغییرات کیف پول ثبت می‌شود + + + تراکنش با وضعیت موفق ثبت می‌شود + + + سفارش خرید پکیج عضویت ثبت می‌شود + + + + + diff --git a/src/BackOffice.Main/Pages/Payment/ManualMembershipPayment.razor.cs b/src/BackOffice.Main/Pages/Payment/ManualMembershipPayment.razor.cs new file mode 100644 index 0000000..0f4b079 --- /dev/null +++ b/src/BackOffice.Main/Pages/Payment/ManualMembershipPayment.razor.cs @@ -0,0 +1,103 @@ +using BackOffice.BFF.ManualPayment.Protobuf; +using BackOffice.Main.Components; +using Grpc.Core; +using Microsoft.AspNetCore.Components; + +namespace BackOffice.Main.Pages.Payment; + +public partial class ManualMembershipPayment +{ + [Inject] private ManualPaymentContract.ManualPaymentContractClient ManualPaymentClient { get; set; } = default!; + [Inject] private ISnackbar Snackbar { get; set; } = default!; + + private long? _userId; + private long _amount = 0; + private string _referenceNumber = string.Empty; + private string? _description; + + private bool _isProcessing = false; + private bool _showResult = false; + private string _resultMessage = string.Empty; + private long _transactionId = 0; + private long _orderId = 0; + private long _newWalletBalance = 0; + + private async Task ProcessPayment() + { + // Validation + if (!_userId.HasValue || _userId.Value <= 0) + { + Snackbar.Add("لطفا کاربر را انتخاب کنید", Severity.Warning); + return; + } + + if (_amount <= 0) + { + Snackbar.Add("لطفا مبلغ معتبری وارد کنید", Severity.Warning); + return; + } + + if (string.IsNullOrWhiteSpace(_referenceNumber)) + { + Snackbar.Add("لطفا شماره مرجع را وارد کنید", Severity.Warning); + return; + } + + try + { + _isProcessing = true; + _showResult = false; + + var request = new ProcessManualMembershipPaymentRequest + { + UserId = _userId.Value, + Amount = _amount, + ReferenceNumber = _referenceNumber + }; + + if (!string.IsNullOrWhiteSpace(_description)) + { + request.Description = _description; + } + + var response = await ManualPaymentClient.ProcessManualMembershipPaymentAsync(request); + + _resultMessage = response.Message; + _transactionId = response.TransactionId; + _orderId = response.OrderId; + _newWalletBalance = response.NewWalletBalance; + _showResult = true; + + Snackbar.Add("پرداخت دستی با موفقیت ثبت شد", Severity.Success); + + // Reset form + await Task.Delay(2000); + ResetForm(); + } + catch (RpcException ex) + { + Snackbar.Add($"خطا در ثبت پرداخت: {ex.Status.Detail}", Severity.Error); + } + catch (Exception ex) + { + Snackbar.Add($"خطای غیرمنتظره: {ex.Message}", Severity.Error); + } + finally + { + _isProcessing = false; + } + } + + private void ResetForm() + { + _userId = null; + _amount = 0; + _referenceNumber = string.Empty; + _description = null; + _showResult = false; + _resultMessage = string.Empty; + _transactionId = 0; + _orderId = 0; + _newWalletBalance = 0; + } +} diff --git a/src/BackOffice/BackOffice.csproj b/src/BackOffice/BackOffice.csproj index 679a99d..b204838 100644 --- a/src/BackOffice/BackOffice.csproj +++ b/src/BackOffice/BackOffice.csproj @@ -118,7 +118,7 @@ - + @@ -134,7 +134,7 @@ - + diff --git a/src/BackOffice/Pages/AutoComplete/WeekNumberPicker.razor b/src/BackOffice/Pages/AutoComplete/WeekNumberPicker.razor new file mode 100644 index 0000000..72ab58e --- /dev/null +++ b/src/BackOffice/Pages/AutoComplete/WeekNumberPicker.razor @@ -0,0 +1,21 @@ +@using Foursat.BackOffice.BFF.Commission.Protos + + + + + @week.DisplayText + + + diff --git a/src/BackOffice/Pages/AutoComplete/WeekNumberPicker.razor.cs b/src/BackOffice/Pages/AutoComplete/WeekNumberPicker.razor.cs new file mode 100644 index 0000000..e379674 --- /dev/null +++ b/src/BackOffice/Pages/AutoComplete/WeekNumberPicker.razor.cs @@ -0,0 +1,107 @@ +using BackOffice.Services; +using Foursat.BackOffice.BFF.Commission.Protos; +using Grpc.Core; +using Microsoft.AspNetCore.Components; + +namespace BackOffice.Pages.AutoComplete; + +public partial class WeekNumberPicker +{ + [Inject] public CommissionContract.CommissionContractClient CommissionContract { get; set; } = default!; + [Inject] public IPersianDateTimeService PersianDateTime { get; set; } = default!; + + [Parameter] public string Label { get; set; } = "انتخاب هفته"; + [Parameter] public string? SelectedWeekNumber { get; set; } + [Parameter] public EventCallback SelectedWeekNumberChanged { get; set; } + [Parameter] public bool CoerceText { get; set; } = true; // اجازه ورود دستی + [Parameter] public int FutureWeeksCount { get; set; } = 4; + [Parameter] public int PastWeeksCount { get; set; } = 12; + + private WeekInfo? _selectedWeek; + private List _allWeeks = new(); + private bool _isLoaded = false; + + protected override async Task OnInitializedAsync() + { + await LoadWeeks(); + + if (!string.IsNullOrWhiteSpace(SelectedWeekNumber) && _allWeeks.Any()) + { + _selectedWeek = _allWeeks.FirstOrDefault(w => w.WeekNumber == SelectedWeekNumber); + } + } + + protected override async Task OnParametersSetAsync() + { + if (!string.IsNullOrWhiteSpace(SelectedWeekNumber) && + _selectedWeek?.WeekNumber != SelectedWeekNumber && + _isLoaded) + { + _selectedWeek = _allWeeks.FirstOrDefault(w => w.WeekNumber == SelectedWeekNumber); + } + } + + private async Task LoadWeeks() + { + try + { + var request = new GetAvailableWeeksRequest + { + FutureWeeksCount = FutureWeeksCount, + PastWeeksCount = PastWeeksCount + }; + + var response = await CommissionContract.GetAvailableWeeksAsync(request); + + _allWeeks = new List(); + + // ترتیب: هفته جاری، محاسبه شده، در انتظار، آینده + if (response.CurrentWeek != null) + _allWeeks.Add(response.CurrentWeek); + + if (response.CalculatedWeeks != null) + _allWeeks.AddRange(response.CalculatedWeeks); + + if (response.PendingWeeks != null) + _allWeeks.AddRange(response.PendingWeeks); + + if (response.FutureWeeks != null) + _allWeeks.AddRange(response.FutureWeeks); + + _isLoaded = true; + } + catch + { + _allWeeks = new List(); + _isLoaded = true; + } + } + + private async Task> Search(string value, CancellationToken cancellationToken) + { + if (!_isLoaded) + await LoadWeeks(); + + if (string.IsNullOrWhiteSpace(value)) + return _allWeeks; + + // جستجو در شماره هفته + return _allWeeks + .Where(w => w.WeekNumber.Contains(value, StringComparison.OrdinalIgnoreCase)) + .ToList(); + } + + private async Task OnSelected(WeekInfo? selected) + { + _selectedWeek = selected; + SelectedWeekNumber = selected?.WeekNumber; + await SelectedWeekNumberChanged.InvokeAsync(SelectedWeekNumber); + } + + private async Task OnClear() + { + _selectedWeek = null; + SelectedWeekNumber = null; + await SelectedWeekNumberChanged.InvokeAsync(null); + } +} diff --git a/src/BackOffice/Pages/Commission/Dashboard.razor b/src/BackOffice/Pages/Commission/Dashboard.razor index 510092a..7a11ef4 100644 --- a/src/BackOffice/Pages/Commission/Dashboard.razor +++ b/src/BackOffice/Pages/Commission/Dashboard.razor @@ -3,6 +3,7 @@ @using Foursat.BackOffice.BFF.Commission.Protos @using MudBlazor +@using BackOffice.Pages.AutoComplete داشبورد کمیسیون @@ -151,12 +152,10 @@ } else { - + } - Payout های کاربران + پرداخت های کاربران - لیست Payout ها + لیست پرداخت ها - - + + 0) { - request.UserId = _filterUserId.Value; + request.Filter.UserId = _filterUserId.Value; } - if (!string.IsNullOrEmpty(_filterWeekNumber)) + if (!string.IsNullOrWhiteSpace(_filterWeekNumber)) { - request.WeekNumber = _filterWeekNumber; + request.Filter.WeekNumber = _filterWeekNumber; } if (_filterStatus.HasValue) { - request.Status = _filterStatus.Value; + request.Filter.Status = _filterStatus.Value; } var result = await CommissionContract.GetUserCommissionPayoutsAsync(request); diff --git a/src/BackOffice/Pages/Commission/WithdrawalReports.razor b/src/BackOffice/Pages/Commission/WithdrawalReports.razor index 0c08c56..b67bd41 100644 --- a/src/BackOffice/Pages/Commission/WithdrawalReports.razor +++ b/src/BackOffice/Pages/Commission/WithdrawalReports.razor @@ -6,6 +6,7 @@ @using Google.Protobuf.WellKnownTypes @using Microsoft.JSInterop @using System.Text +@using BackOffice.Pages.AutoComplete گزارش برداشت‌ها @@ -41,10 +42,8 @@ - + diff --git a/src/BackOffice/Pages/Commission/WithdrawalRequests.razor b/src/BackOffice/Pages/Commission/WithdrawalRequests.razor index 298817f..aec0406 100644 --- a/src/BackOffice/Pages/Commission/WithdrawalRequests.razor +++ b/src/BackOffice/Pages/Commission/WithdrawalRequests.razor @@ -2,6 +2,7 @@ @attribute [Authorize] @using Foursat.BackOffice.BFF.Commission.Protos +@using BackOffice.Pages.AutoComplete درخواست‌های برداشت @@ -15,14 +16,8 @@ درخواست‌های برداشت - + - + - + کنترل Worker محاسبات @@ -59,10 +60,9 @@ - + - + } + + @if (CanManagePayments) + { + + + پرداخت‌های دستی + + + پرداخت دستی عضویت + + + } @@ -273,6 +289,7 @@ private bool CanManageTags; private bool CanManageUsers; private bool CanManageRoles; + private bool CanManagePayments; private bool CanManageDiscountShop; private bool CanManagePublicMessages; private bool CanViewSystemAlerts; @@ -300,6 +317,7 @@ CanManageTags = await AuthorizationService.HasPermissionAsync("tags.manage"); CanManageUsers = await AuthorizationService.HasPermissionAsync("users.view"); CanManageRoles = await AuthorizationService.HasPermissionAsync("roles.manage"); + CanManagePayments = await AuthorizationService.HasPermissionAsync("manualpayments.create"); CanManageDiscountShop = await AuthorizationService.HasPermissionAsync("discountshop.manage"); CanManagePublicMessages = await AuthorizationService.HasPermissionAsync("publicmessages.view"); CanViewSystemAlerts = await AuthorizationService.HasPermissionAsync("system.alerts.view");