diff --git a/docs/ADMIN-SERVICES.md b/docs/ADMIN-SERVICES.md
index ce55f9b..5ecef76 100644
--- a/docs/ADMIN-SERVICES.md
+++ b/docs/ADMIN-SERVICES.md
@@ -4,7 +4,7 @@
- **مسیر wrapper سرویسها:** `BackOffice/src/BackOffice/Services/`
- **ثبت gRPC:** `BackOffice/src/BackOffice/Common/Configure/ConfigureService.cs`
-- **تاریخ:** ۱۴۰۵/۰۳/۱۷
+- **تاریخ:** ۱۴۰۵/۰۳/۱۷ (بروز: خرداد ۱۴۰۵ — گزارشهای read-only + proto 0.0.201)
---
@@ -388,3 +388,18 @@ flowchart LR
| Wallet | My balances | All users wallet + history log |
مرجع مشابه برای فرانت مشتری: [`FrontOffice/docs/CUSTOMER-SERVICES.md`](../FrontOffice/docs/CUSTOMER-SERVICES.md)
+
+---
+
+## یادداشت deploy (خرداد ۱۴۰۵)
+
+| گام | جزئیات |
+|-----|--------|
+| Proto | `Foursat.CMSMicroservice.Protobuf` **0.0.201** |
+| CMS | deploy WebApi (شامل CQRS + gRPC گزارشها) |
+| BackOffice | NuGet 0.0.201 یا ProjectReference در monorepo |
+| FrontOffice | **redeploy لازم نیست** — روی 0.0.199 میماند؛ RPCهای admin در FO register نشده |
+
+گزارشهای read-only (بخش ۱۰ و ۱۵): فقط فیلتر + grid + summary — بدون CRUD، detail dialog، یا لینک cross-page.
+
+مستندات فنی کامل: [`totalDoc/technical/TECH-08-SESSION-LOG-202606.md`](../../totalDoc/technical/TECH-08-SESSION-LOG-202606.md)
diff --git a/src/BackOffice/BackOffice.csproj b/src/BackOffice/BackOffice.csproj
index 1b6aee7..78d7ffa 100644
--- a/src/BackOffice/BackOffice.csproj
+++ b/src/BackOffice/BackOffice.csproj
@@ -143,7 +143,7 @@
-
+
diff --git a/src/BackOffice/Common/Configure/ConfigureService.cs b/src/BackOffice/Common/Configure/ConfigureService.cs
index 2f6835e..441c667 100644
--- a/src/BackOffice/Common/Configure/ConfigureService.cs
+++ b/src/BackOffice/Common/Configure/ConfigureService.cs
@@ -32,6 +32,7 @@ using CMSMicroservice.Protobuf.Protos.UserContract;
using CMSMicroservice.Protobuf.Protos.UserWallet;
using CMSMicroservice.Protobuf.Protos.UserWalletHistory;
using CMSMicroservice.Protobuf.Protos.PaymentTransaction;
+using CMSMicroservice.Protobuf.Protos.Transactions;
using CMSMicroservice.Protobuf.Protos.UserPackagePurchase;
using CMSMicroservice.Protobuf.Protos.ClubMembershipCycle;
using CMSMicroservice.Protobuf.Protos.ClubMembershipCycleHistory;
@@ -175,6 +176,7 @@ public static class ConfigureServices
// Admin Report Services
services.AddTransient(sp => new PaymentTransactionContract.PaymentTransactionContractClient(sp.GetRequiredService()));
+ services.AddTransient(sp => new TransactionsContract.TransactionsContractClient(sp.GetRequiredService()));
services.AddTransient(sp => new UserPackagePurchaseContract.UserPackagePurchaseContractClient(sp.GetRequiredService()));
services.AddTransient(sp => new ClubMembershipCycleContract.ClubMembershipCycleContractClient(sp.GetRequiredService()));
services.AddTransient(sp => new ClubMembershipCycleHistoryContract.ClubMembershipCycleHistoryContractClient(sp.GetRequiredService()));
diff --git a/src/BackOffice/Common/Utilities/ReportLabels.cs b/src/BackOffice/Common/Utilities/ReportLabels.cs
index 41fd281..4c6c281 100644
--- a/src/BackOffice/Common/Utilities/ReportLabels.cs
+++ b/src/BackOffice/Common/Utilities/ReportLabels.cs
@@ -1,9 +1,44 @@
namespace BackOffice.Common.Utilities;
+using CMSMicroservice.Protobuf.Protos;
+using MudBlazor;
+
public static class ReportLabels
{
public static string GetPaymentStatusLabel(bool success) => success ? "موفق" : "در انتظار / ناموفق";
+ public static string GetTransactionPaymentStatusLabel(PaymentStatus? status) => status switch
+ {
+ PaymentStatus.Success => "موفق",
+ PaymentStatus.Pending => "در انتظار",
+ PaymentStatus.Reject => "رد شده",
+ _ => "—"
+ };
+
+ public static Color GetTransactionPaymentStatusColor(PaymentStatus? status) => status switch
+ {
+ PaymentStatus.Success => Color.Success,
+ PaymentStatus.Pending => Color.Warning,
+ PaymentStatus.Reject => Color.Error,
+ _ => Color.Default
+ };
+
+ public static string GetTransactionTypeLabel(TransactionType? type) => type switch
+ {
+ TransactionType.Buy => "خرید",
+ TransactionType.DepositIpg => "واریز درگاه",
+ TransactionType.DepositExternal1 => "واریز خارجی",
+ TransactionType.Withdraw => "برداشت",
+ TransactionType.NetworkCommission => "کمیسیون شبکه",
+ TransactionType.ClubActivation => "فعالسازی باشگاه",
+ TransactionType.DiscountWalletCharge => "شارژ کیف تخفیف",
+ TransactionType.DiscountShopPurchase => "خرید فروشگاه تخفیف",
+ TransactionType.MagicWalletDeposit => "واریز کیف جادویی",
+ TransactionType.MagicWalletBonus => "بونوس کیف جادویی",
+ TransactionType.CreditWalletCharge => "شارژ کیف اصلی",
+ _ => type?.ToString() ?? "—"
+ };
+
public static string GetPurchaseMethodLabel(int method) => method switch
{
1 => "وام دایا",
diff --git a/src/BackOffice/Pages/Payment/LedgerTransactions.razor b/src/BackOffice/Pages/Payment/LedgerTransactions.razor
new file mode 100644
index 0000000..2ea08eb
--- /dev/null
+++ b/src/BackOffice/Pages/Payment/LedgerTransactions.razor
@@ -0,0 +1,246 @@
+@page "/payment/ledger-transactions"
+@using BackOffice.Common.BaseComponents
+@using CMSMicroservice.Protobuf.Protos
+@using CMSMicroservice.Protobuf.Protos.Transactions
+@using Google.Protobuf.WellKnownTypes
+
+@inject TransactionsContract.TransactionsContractClient TransactionsClient
+
+
+
+
+
+ گزارش read-only دفتر تراکنشهای مالی (جدول Transactions). برای جزئیات درگاه پرداخت به «گزارش تراکنش درگاه» مراجعه کنید.
+
+
+
+
+
+
+
+
+
+
+
+
+
+ موفق
+ در انتظار
+ رد شده
+
+
+
+
+ خرید
+ واریز درگاه
+ واریز خارجی
+ برداشت
+ کمیسیون شبکه
+ فعالسازی باشگاه
+ شارژ کیف تخفیف
+ خرید فروشگاه تخفیف
+ واریز کیف جادویی
+ بونوس کیف جادویی
+ شارژ کیف اصلی
+
+
+
+
+
+
+
+
+
+
+ تعداد
+ @_summaryTotalCount.ToString("N0")
+
+
+
+
+ جمع مبلغ (تومان)
+ @_summaryTotalAmount.ToString("N0")
+
+
+
+
+ موفق
+ @_summarySuccess.ToString("N0")
+
+
+
+
+ در انتظار
+ @_summaryPending.ToString("N0")
+
+
+
+
+ رد شده
+ @_summaryReject.ToString("N0")
+
+
+
+
+
+
+ دفتر تراکنشهای مالی
+
+ CSV
+
+
+
+
+
+
+ @ReportLabels.GetTransactionTypeLabel(context.Item.HasType ? context.Item.Type : null)
+
+
+
+
+ @context.Item.Amount.ToString("N0")
+
+
+
+
+
+ @ReportLabels.GetTransactionPaymentStatusLabel(context.Item.HasPaymentStatus ? context.Item.PaymentStatus : null)
+
+
+
+
+
+
+ @(context.Item.PaymentDate != null
+ ? context.Item.PaymentDate.ToDateTime().ToLocalTime().MiladiToJalaliWithTime()
+ : "—")
+
+
+
+ @context.Item.Created.ToDateTime().ToLocalTime().MiladiToJalaliWithTime()
+
+
+
+
+ با فیلتر فعلی موردی یافت نشد — بازه تاریخ یا فیلترها را تغییر دهید.
+
+
+
+
+
+
+
+
+
+@code {
+ private BasePageComponent? _basePage;
+ private MudDataGrid? _dataGrid;
+ private long? _id;
+ private string? _refId, _description;
+ private PaymentStatus? _paymentStatus;
+ private TransactionType? _type;
+ private DateTime? _createdFrom, _createdTo;
+ private long _summaryTotalCount, _summaryTotalAmount, _summarySuccess, _summaryPending, _summaryReject;
+
+ private GetAllTransactionsByFilterFilter BuildFilter()
+ {
+ var filter = new GetAllTransactionsByFilterFilter
+ {
+ Id = _id > 0 ? _id : null,
+ RefId = string.IsNullOrWhiteSpace(_refId) ? null : _refId,
+ Description = string.IsNullOrWhiteSpace(_description) ? null : _description,
+ CreatedFrom = _createdFrom.HasValue ? Timestamp.FromDateTime(DateTime.SpecifyKind(_createdFrom.Value, DateTimeKind.Utc)) : null,
+ CreatedTo = _createdTo.HasValue ? Timestamp.FromDateTime(DateTime.SpecifyKind(_createdTo.Value.Date.AddDays(1).AddTicks(-1), DateTimeKind.Utc)) : null
+ };
+
+ if (_paymentStatus.HasValue)
+ filter.PaymentStatus = _paymentStatus.Value;
+ else
+ filter.ClearPaymentStatusItem();
+
+ if (_type.HasValue)
+ filter.Type = _type.Value;
+ else
+ filter.ClearTypeItem();
+
+ return filter;
+ }
+
+ private async Task LoadSummary()
+ {
+ try
+ {
+ var s = await TransactionsClient.GetTransactionSummaryAsync(new GetTransactionSummaryRequest { Filter = BuildFilter() });
+ _summaryTotalCount = s.TotalCount;
+ _summaryTotalAmount = s.TotalAmount;
+ _summarySuccess = s.SuccessCount;
+ _summaryPending = s.PendingCount;
+ _summaryReject = s.RejectCount;
+ }
+ catch { }
+ }
+
+ private async Task> LoadData(GridState state)
+ {
+ try
+ {
+ await LoadSummary();
+ var result = await TransactionsClient.GetAllTransactionsByFilterAsync(new GetAllTransactionsByFilterRequest
+ {
+ PaginationState = new PaginationState { PageNumber = state.Page + 1, PageSize = state.PageSize },
+ SortBy = "-Created",
+ Filter = BuildFilter()
+ });
+ return new GridData
+ {
+ Items = result?.Models?.ToList() ?? new(),
+ TotalItems = (int)(result?.MetaData?.TotalCount ?? 0)
+ };
+ }
+ catch (Exception ex)
+ {
+ Snackbar.Add($"خطا: {ex.Message}", Severity.Error);
+ return new GridData();
+ }
+ }
+
+ private async Task OnFilterSubmit() { if (_dataGrid != null) await _dataGrid.ReloadServerData(); }
+ private async Task OnFilterCleared()
+ {
+ _id = null; _refId = _description = null;
+ _paymentStatus = null; _type = null;
+ _createdFrom = _createdTo = null;
+ if (_dataGrid != null) await _dataGrid.ReloadServerData();
+ }
+
+ private async Task ExportCsv()
+ {
+ try
+ {
+ var result = await TransactionsClient.GetAllTransactionsByFilterAsync(new GetAllTransactionsByFilterRequest
+ {
+ PaginationState = new PaginationState { PageNumber = 1, PageSize = 5000 },
+ SortBy = "-Created",
+ Filter = BuildFilter()
+ });
+ var sb = new System.Text.StringBuilder();
+ sb.AppendLine("Id,Type,Amount,Description,Status,RefId,PaymentDate,Created");
+ foreach (var r in result.Models)
+ {
+ var type = r.HasType ? ReportLabels.GetTransactionTypeLabel(r.Type) : "";
+ var status = r.HasPaymentStatus ? ReportLabels.GetTransactionPaymentStatusLabel(r.PaymentStatus) : "";
+ var paymentDate = r.PaymentDate != null ? r.PaymentDate.ToDateTime().ToString("yyyy-MM-dd HH:mm") : "";
+ sb.AppendLine($"{r.Id},{type},{r.Amount},\"{r.Description}\",{status},{r.RefId},{paymentDate},{r.Created.ToDateTime():yyyy-MM-dd HH:mm}");
+ }
+ await jsRuntime.InvokeVoidAsync("jsSaveAsFile", "ledger-transactions.csv", sb.ToString());
+ }
+ catch (Exception ex) { Snackbar.Add($"خطا در export: {ex.Message}", Severity.Error); }
+ }
+}
diff --git a/src/BackOffice/Shared/AppBreadcrumb.razor b/src/BackOffice/Shared/AppBreadcrumb.razor
index e6d7712..630a226 100644
--- a/src/BackOffice/Shared/AppBreadcrumb.razor
+++ b/src/BackOffice/Shared/AppBreadcrumb.razor
@@ -96,6 +96,7 @@
// Payment
"payment" => "پرداخت",
"transactions" => "تراکنشها",
+ "ledger-transactions" => "دفتر تراکنشهای مالی",
"manual-payments" => "پرداخت دستی",
// Network
diff --git a/src/BackOffice/Shared/NavMenu.razor b/src/BackOffice/Shared/NavMenu.razor
index b360d7d..77418c8 100644
--- a/src/BackOffice/Shared/NavMenu.razor
+++ b/src/BackOffice/Shared/NavMenu.razor
@@ -206,6 +206,12 @@
گزارش تراکنش درگاه
+
+ دفتر تراکنشهای مالی
+
+