Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 4115f64fff | |||
| d757c8220c |
+28
-12
@@ -4,7 +4,7 @@
|
||||
|
||||
- **مسیر wrapper سرویسها:** `BackOffice/src/BackOffice/Services/`
|
||||
- **ثبت gRPC:** `BackOffice/src/BackOffice/Common/Configure/ConfigureService.cs`
|
||||
- **تاریخ:** ۱۴۰۵/۰۳/۱۷ (بروز: خرداد ۱۴۰۵ — گزارشهای read-only + proto 0.0.201)
|
||||
- **تاریخ:** ۱۴۰۵/۰۳/۱۷ (بروز: خرداد ۱۴۰۵ — گزارشهای read-only + proto 0.0.201؛ **بروز ۱۴۰۵/۰۳/۱۸ — دفتر تراکنشهای مالی proto 0.0.203**)
|
||||
|
||||
---
|
||||
|
||||
@@ -138,16 +138,26 @@
|
||||
|
||||
## ۱۰. پرداخت دستی و تراکنشها
|
||||
|
||||
> **دو گزارش تراکنش — اشتباه نگیرید:**
|
||||
>
|
||||
> | مسیر | جدول DB | کاربرد |
|
||||
> |------|---------|--------|
|
||||
> | `/payment/transactions` | `PaymentTransactions` | ممیزی درگاه (Authority، ZarinPal، کارت) |
|
||||
> | `/payment/ledger-transactions` | `Transactions` | دفتر مالی داخلی (نوع تراکنش، وضعیت، RefId) |
|
||||
|
||||
| # | سرویس / متد | gRPC Contract | صفحه / کامپوننت | کاربرد |
|
||||
|---|-------------|---------------|-----------------|--------|
|
||||
| 10.1 | `ManualPaymentContract.GetAllManualPayments` | `ManualPaymentContract` | `/payment/manual-payments` | لیست پرداختهای دستی |
|
||||
| 10.2 | `ManualPaymentContract.CreateManualPayment` | `ManualPaymentContract` | `ManualPaymentDialog` | ثبت پرداخت دستی (مثلاً Daya) |
|
||||
| 10.3 | `ManualPaymentContract.ApproveManualPayment` | `ManualPaymentContract` | ManualPayments, Dialog | تأیید پرداخت |
|
||||
| 10.4 | `ManualPaymentContract.RejectManualPayment` | `ManualPaymentContract` | ManualPayments, Dialog | رد پرداخت |
|
||||
| 10.5 | `PaymentTransactionContract.GetAllPaymentTransactionByFilter` | `PaymentTransactionContract` | `/payment/transactions` | گزارش read-only تراکنش درگاه |
|
||||
| 10.6 | `UserPackagePurchaseContract.GetAllUserPackagePurchaseByFilter` | `UserPackagePurchaseContract` | `/club/purchases` | گزارش خرید پکیج |
|
||||
| 10.7 | `ClubMembershipCycleContract.GetAllClubMembershipCycleByFilter` | `ClubMembershipCycleContract` | `/club/cycles` | گزارش دوره عضویت |
|
||||
| 10.8 | `ClubMembershipCycleHistoryContract.GetAllClubMembershipCycleHistoryByFilter` | `ClubMembershipCycleHistoryContract` | `/club/history` (زیرتب دوره) | تاریخچه تغییرات دوره |
|
||||
| 10.5 | `PaymentTransactionContract.GetAllPaymentTransactionByFilter` | `PaymentTransactionContract` | `/payment/transactions` | گزارش read-only تراکنش **درگاه** (`PaymentTransactions`) |
|
||||
| 10.5b | `PaymentTransactionContract.GetPaymentTransactionSummary` | `PaymentTransactionContract` | `/payment/transactions` | کارت خلاصه گزارش درگاه |
|
||||
| 10.6 | `TransactionsContract.GetAllTransactionsByFilter` | `TransactionsContract` | `/payment/ledger-transactions` | گزارش read-only **دفتر مالی** (`Transactions`) |
|
||||
| 10.7 | `TransactionsContract.GetTransactionSummary` | `TransactionsContract` | `/payment/ledger-transactions` | کارت خلاصه دفتر تراکنش |
|
||||
| 10.8 | `UserPackagePurchaseContract.GetAllUserPackagePurchaseByFilter` | `UserPackagePurchaseContract` | `/club/purchases` | گزارش خرید پکیج |
|
||||
| 10.9 | `ClubMembershipCycleContract.GetAllClubMembershipCycleByFilter` | `ClubMembershipCycleContract` | `/club/cycles` | گزارش دوره عضویت |
|
||||
| 10.10 | `ClubMembershipCycleHistoryContract.GetAllClubMembershipCycleHistoryByFilter` | `ClubMembershipCycleHistoryContract` | `/club/history` (زیرتب دوره) | تاریخچه تغییرات دوره |
|
||||
|
||||
---
|
||||
|
||||
@@ -157,6 +167,8 @@
|
||||
|---|-------------|---------------|-----------------|--------|
|
||||
| 11.1 | `UserWalletContract.GetAllUserWalletByFilter` | `UserWalletContract` | `/wallets` | لیست کیف پول کاربران |
|
||||
| 11.2 | `UserWalletHistoryContract.GetAllUserWalletHistoryByFilter` | `UserWalletHistoryContract` | `/wallets` (تب تاریخچه) | لاگ تغییرات کیف پول |
|
||||
| 11.3 | `UserWalletContract.AdminManualCreditCharge` | `UserWalletContract` | `/payment/manual-credit-charges` | شارژ دستی کیف پول اصلی (Balance) |
|
||||
| 11.4 | `UserWalletContract.GetManualCreditCharges` | `UserWalletContract` | `/payment/manual-credit-charges` | لیست شارژهای دستی (Type=17) |
|
||||
|
||||
---
|
||||
|
||||
@@ -319,7 +331,6 @@
|
||||
| سرویس / صفحه | وضعیت |
|
||||
|--------------|--------|
|
||||
| `IBlogPostImageService` (`BlogPostImageContract`) | ثبت در DI؛ **هیچ صفحهای inject نمیکند** |
|
||||
| `/payment/transactions` | UI آماده؛ **LoadData خالی — API وصل نشده** |
|
||||
| `RolePermissionsDialog` | UI permission؛ **ذخیره در backend TODO** |
|
||||
| `AuthorizationService` | فقط JWT role؛ **Permission API از CMS/BFF TODO** |
|
||||
| `/system/alerts` | داده mock؛ **AlertContract وجود ندارد** |
|
||||
@@ -352,6 +363,11 @@ flowchart LR
|
||||
| `CategoryContract` | Categories |
|
||||
| `UserOrderContract` | Orders |
|
||||
| `ManualPaymentContract` | Manual payments |
|
||||
| `PaymentTransactionContract` | Gateway transaction report (`/payment/transactions`) |
|
||||
| `TransactionsContract` | Ledger transaction report (`/payment/ledger-transactions`) |
|
||||
| `UserPackagePurchaseContract` | Club package purchase report |
|
||||
| `ClubMembershipCycleContract` | Club cycle report |
|
||||
| `ClubMembershipCycleHistoryContract` | Club cycle history report |
|
||||
| `UserWalletContract` | Wallet management |
|
||||
| `UserWalletHistoryContract` | Wallet change log |
|
||||
| `UserContractContract` | Signed contracts |
|
||||
@@ -395,11 +411,11 @@ flowchart LR
|
||||
|
||||
| گام | جزئیات |
|
||||
|-----|--------|
|
||||
| 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 نشده |
|
||||
| Proto | `Foursat.CMSMicroservice.Protobuf` **0.0.203** (گزارش دفتر تراکنش) |
|
||||
| CMS | deploy WebApi (شامل `GetTransactionSummary` + فیلتر تاریخ) |
|
||||
| BackOffice | NuGet 0.0.203 یا ProjectReference در monorepo |
|
||||
| FrontOffice | **redeploy لازم نیست** برای گزارش ledger؛ برای شارژ کیف اصلی proto **0.0.202** لازم است |
|
||||
|
||||
گزارشهای read-only (بخش ۱۰ و ۱۵): فقط فیلتر + grid + summary — بدون CRUD، detail dialog، یا لینک cross-page.
|
||||
گزارشهای read-only (بخش ۱۰ و ۱۵): فقط فیلتر + grid + summary + CSV — بدون CRUD یا detail dialog.
|
||||
|
||||
مستندات فنی کامل: [`totalDoc/technical/TECH-08-SESSION-LOG-202606.md`](../../totalDoc/technical/TECH-08-SESSION-LOG-202606.md)
|
||||
مستندات فنی کامل: [`totalDoc/technical/TECH-08-SESSION-LOG-202606.md`](../../totalDoc/technical/TECH-08-SESSION-LOG-202606.md) — §10 Ledger transactions
|
||||
|
||||
@@ -143,7 +143,7 @@
|
||||
<ProjectReference Include="../../../CMS/src/CMSMicroservice.Protobuf/CMSMicroservice.Protobuf.csproj" />
|
||||
</ItemGroup>
|
||||
<ItemGroup Condition="!Exists('../../../CMS/src/CMSMicroservice.Protobuf/CMSMicroservice.Protobuf.csproj')">
|
||||
<PackageReference Include="Foursat.CMSMicroservice.Protobuf" Version="0.0.203" />
|
||||
<PackageReference Include="Foursat.CMSMicroservice.Protobuf" Version="0.0.205" />
|
||||
</ItemGroup>
|
||||
|
||||
<!-- ============================================================ -->
|
||||
|
||||
@@ -36,6 +36,7 @@ public static class ReportLabels
|
||||
TransactionType.MagicWalletDeposit => "واریز کیف جادویی",
|
||||
TransactionType.MagicWalletBonus => "بونوس کیف جادویی",
|
||||
TransactionType.CreditWalletCharge => "شارژ کیف اصلی",
|
||||
TransactionType.ManualCreditWalletCharge => "شارژ دستی کیف اصلی",
|
||||
_ => type?.ToString() ?? "—"
|
||||
};
|
||||
|
||||
|
||||
@@ -0,0 +1,106 @@
|
||||
@using BackOffice.Pages.AutoComplete
|
||||
@using CMSMicroservice.Protobuf.Protos.UserWallet
|
||||
|
||||
@inject UserWalletContract.UserWalletContractClient WalletClient
|
||||
|
||||
<MudDialog>
|
||||
<DialogContent>
|
||||
<MudStack Spacing="3">
|
||||
<MudAlert Severity="Severity.Warning" Dense="true" Variant="Variant.Outlined">
|
||||
مبلغ مستقیماً به کیف پول اصلی (Balance) کاربر اضافه میشود و در دفتر مالی با نوع «شارژ دستی کیف اصلی» ثبت میگردد.
|
||||
</MudAlert>
|
||||
|
||||
<UserAutoComplete Label="کاربر" @bind-SelectedUserId="_userId" />
|
||||
|
||||
<MudNumericField T="long" @bind-Value="_amount"
|
||||
Label="مبلغ (تومان)"
|
||||
Variant="Variant.Outlined"
|
||||
Min="10000"
|
||||
HelperText="حداقل ۱۰,۰۰۰ تومان" />
|
||||
|
||||
<MudTextField T="string" @bind-Value="_note"
|
||||
Label="توضیحات ادمین (اختیاری)"
|
||||
Variant="Variant.Outlined"
|
||||
Lines="2" />
|
||||
</MudStack>
|
||||
</DialogContent>
|
||||
<DialogActions>
|
||||
<MudButton OnClick="Cancel" Disabled="_isSubmitting">انصراف</MudButton>
|
||||
<MudButton Color="Color.Primary" Variant="Variant.Filled"
|
||||
OnClick="Submit" Disabled="_isSubmitting || !_userId.HasValue || _amount < 10000">
|
||||
@if (_isSubmitting)
|
||||
{
|
||||
<MudProgressCircular Size="Size.Small" Indeterminate="true" Class="mr-2" />
|
||||
}
|
||||
ثبت شارژ
|
||||
</MudButton>
|
||||
</DialogActions>
|
||||
</MudDialog>
|
||||
|
||||
@code {
|
||||
[CascadingParameter] IMudDialogInstance MudDialog { get; set; } = default!;
|
||||
|
||||
private long? _userId;
|
||||
private long _amount = 10000;
|
||||
private string? _note;
|
||||
private bool _isSubmitting;
|
||||
|
||||
private void Cancel() => MudDialog.Cancel();
|
||||
|
||||
private async Task Submit()
|
||||
{
|
||||
if (!_userId.HasValue || _userId.Value <= 0)
|
||||
{
|
||||
Snackbar.Add("لطفاً کاربر را انتخاب کنید", Severity.Warning);
|
||||
return;
|
||||
}
|
||||
|
||||
if (_amount < 10000)
|
||||
{
|
||||
Snackbar.Add("حداقل مبلغ شارژ ۱۰,۰۰۰ تومان است", Severity.Warning);
|
||||
return;
|
||||
}
|
||||
|
||||
bool? confirm = await DialogService.ShowMessageBox(
|
||||
"تأیید شارژ دستی",
|
||||
$"آیا از شارژ {_amount:N0} تومان به کیف پول اصلی کاربر #{_userId.Value} مطمئن هستید؟",
|
||||
yesText: "بله، شارژ شود", cancelText: "لغو");
|
||||
|
||||
if (confirm != true)
|
||||
return;
|
||||
|
||||
_isSubmitting = true;
|
||||
try
|
||||
{
|
||||
var request = new AdminManualCreditChargeRequest
|
||||
{
|
||||
UserId = _userId.Value,
|
||||
Amount = _amount
|
||||
};
|
||||
if (!string.IsNullOrWhiteSpace(_note))
|
||||
request.Note = _note.Trim();
|
||||
|
||||
var response = await WalletClient.AdminManualCreditChargeAsync(request);
|
||||
|
||||
if (response.Success)
|
||||
{
|
||||
Snackbar.Add(
|
||||
$"شارژ موفق — تراکنش #{response.TransactionId}، موجودی جدید: {response.NewBalance:N0}",
|
||||
Severity.Success);
|
||||
MudDialog.Close(DialogResult.Ok(true));
|
||||
}
|
||||
else
|
||||
{
|
||||
Snackbar.Add(response.Message ?? "شارژ ناموفق بود", Severity.Error);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Snackbar.Add($"خطا: {ex.Message}", Severity.Error);
|
||||
}
|
||||
finally
|
||||
{
|
||||
_isSubmitting = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -44,6 +44,7 @@
|
||||
<MudSelectItem T="TransactionType?" Value="TransactionType.MagicWalletDeposit">واریز کیف جادویی</MudSelectItem>
|
||||
<MudSelectItem T="TransactionType?" Value="TransactionType.MagicWalletBonus">بونوس کیف جادویی</MudSelectItem>
|
||||
<MudSelectItem T="TransactionType?" Value="TransactionType.CreditWalletCharge">شارژ کیف اصلی</MudSelectItem>
|
||||
<MudSelectItem T="TransactionType?" Value="TransactionType.ManualCreditWalletCharge">شارژ دستی کیف اصلی</MudSelectItem>
|
||||
</MudSelect>
|
||||
</MudItem>
|
||||
<MudItem xs="12" sm="6" md="4">
|
||||
|
||||
@@ -0,0 +1,149 @@
|
||||
@page "/payment/manual-credit-charges"
|
||||
@attribute [Authorize(Roles = "Administrator")]
|
||||
|
||||
@using BackOffice.Common.BaseComponents
|
||||
@using BackOffice.Pages.AutoComplete
|
||||
@using BackOffice.Pages.Payment.Components
|
||||
@using CMSMicroservice.Protobuf.Protos
|
||||
@using CMSMicroservice.Protobuf.Protos.UserWallet
|
||||
@using DateTimeConverterCL
|
||||
@using Google.Protobuf.WellKnownTypes
|
||||
|
||||
@inject UserWalletContract.UserWalletContractClient WalletClient
|
||||
|
||||
<BasePageComponent @ref="_basePage" OnSubmitClick="OnFilterSubmit" OnClearFilterClick="OnFilterCleared">
|
||||
<Filters>
|
||||
<MudItem xs="12">
|
||||
<MudAlert Severity="Severity.Info" Variant="Variant.Text" Dense="true">
|
||||
شارژ دستی کیف پول اصلی (Balance) — بدون درگاه. جدا از «پرداختهای دستی» عضویت باشگاه.
|
||||
</MudAlert>
|
||||
</MudItem>
|
||||
<MudItem xs="12" sm="6" md="3">
|
||||
<UserAutoComplete Label="جستجوی کاربر" @bind-SelectedUserId="_userIdFilter" />
|
||||
</MudItem>
|
||||
<MudItem xs="12" sm="6" md="3">
|
||||
<MudTextField T="long?" Label="شناسه تراکنش" Variant="Variant.Outlined"
|
||||
Margin="Margin.Dense" @bind-Value="_transactionIdFilter" />
|
||||
</MudItem>
|
||||
<MudItem xs="12" sm="6" md="3">
|
||||
<MudTextField T="string" Label="RefId" Variant="Variant.Outlined"
|
||||
Margin="Margin.Dense" @bind-Value="_refIdFilter" />
|
||||
</MudItem>
|
||||
<MudItem xs="12" sm="6" md="4">
|
||||
<DateRangePicker @bind-From="_createdFrom" @bind-To="_createdTo" Label="بازه ثبت" />
|
||||
</MudItem>
|
||||
</Filters>
|
||||
<Content>
|
||||
<MudDataGrid @ref="_dataGrid" T="ManualCreditChargeModel"
|
||||
ServerData="LoadData"
|
||||
Hover="true" Dense="true"
|
||||
Height="calc(100vh - 240px)">
|
||||
<ToolBarContent>
|
||||
<MudText Typo="Typo.subtitle1">شارژ دستی کیف پول اصلی</MudText>
|
||||
<MudSpacer />
|
||||
<MudButton Variant="Variant.Filled" Color="Color.Primary" Size="Size.Small"
|
||||
StartIcon="@Icons.Material.Filled.Add" OnClick="OpenCreateDialog">
|
||||
شارژ دستی جدید
|
||||
</MudButton>
|
||||
</ToolBarContent>
|
||||
<Columns>
|
||||
<PropertyColumn Property="x => x.TransactionId" Title="شناسه تراکنش" />
|
||||
<PropertyColumn Property="x => x.UserId" Title="شناسه کاربر" />
|
||||
<PropertyColumn Property="x => x.UserName" Title="نام کاربر" />
|
||||
<PropertyColumn Property="x => x.Amount" Title="مبلغ">
|
||||
<CellTemplate>
|
||||
@context.Item.Amount.ToString("N0")
|
||||
</CellTemplate>
|
||||
</PropertyColumn>
|
||||
<PropertyColumn Property="x => x.NewBalance" Title="موجودی بعد از شارژ">
|
||||
<CellTemplate>
|
||||
@context.Item.NewBalance.ToString("N0")
|
||||
</CellTemplate>
|
||||
</PropertyColumn>
|
||||
<PropertyColumn Property="x => x.RefId" Title="RefId" />
|
||||
<PropertyColumn Property="x => x.Description" Title="توضیحات" />
|
||||
<TemplateColumn Title="تاریخ">
|
||||
<CellTemplate>
|
||||
@(context.Item.Created?.ToDateTime().ToLocalTime().MiladiToJalaliWithTime() ?? "-")
|
||||
</CellTemplate>
|
||||
</TemplateColumn>
|
||||
</Columns>
|
||||
<NoRecordsContent>
|
||||
<MudAlert Severity="Severity.Info" Dense="true" Variant="Variant.Text" Class="my-4">موردی یافت نشد.</MudAlert>
|
||||
</NoRecordsContent>
|
||||
<PagerContent>
|
||||
<MudDataGridPager T="ManualCreditChargeModel" PageSizeOptions="@(new int[] { 20, 50, 100 })"
|
||||
InfoFormat="سطر {first_item} تا {last_item} از {all_items}"
|
||||
RowsPerPageString="تعداد در صفحه" />
|
||||
</PagerContent>
|
||||
</MudDataGrid>
|
||||
</Content>
|
||||
</BasePageComponent>
|
||||
|
||||
@code {
|
||||
private BasePageComponent? _basePage;
|
||||
private MudDataGrid<ManualCreditChargeModel>? _dataGrid;
|
||||
private long? _userIdFilter;
|
||||
private long? _transactionIdFilter;
|
||||
private string? _refIdFilter;
|
||||
private DateTime? _createdFrom;
|
||||
private DateTime? _createdTo;
|
||||
|
||||
private async Task<GridData<ManualCreditChargeModel>> LoadData(GridState<ManualCreditChargeModel> state)
|
||||
{
|
||||
var request = new GetManualCreditChargesRequest
|
||||
{
|
||||
PaginationState = new PaginationState
|
||||
{
|
||||
PageNumber = state.Page + 1,
|
||||
PageSize = state.PageSize
|
||||
},
|
||||
Filter = new GetManualCreditChargesFilter()
|
||||
};
|
||||
|
||||
if (_userIdFilter.HasValue)
|
||||
request.Filter.UserId = _userIdFilter.Value;
|
||||
if (_transactionIdFilter.HasValue)
|
||||
request.Filter.TransactionId = _transactionIdFilter.Value;
|
||||
if (!string.IsNullOrWhiteSpace(_refIdFilter))
|
||||
request.Filter.RefId = _refIdFilter.Trim();
|
||||
if (_createdFrom.HasValue)
|
||||
request.Filter.CreatedFrom = Timestamp.FromDateTime(DateTime.SpecifyKind(_createdFrom.Value, DateTimeKind.Utc));
|
||||
if (_createdTo.HasValue)
|
||||
request.Filter.CreatedTo = Timestamp.FromDateTime(DateTime.SpecifyKind(_createdTo.Value, DateTimeKind.Utc));
|
||||
|
||||
var response = await WalletClient.GetManualCreditChargesAsync(request);
|
||||
|
||||
return new GridData<ManualCreditChargeModel>
|
||||
{
|
||||
Items = response.Models.ToList(),
|
||||
TotalItems = (int)(response.MetaData?.TotalCount ?? 0)
|
||||
};
|
||||
}
|
||||
|
||||
private async Task OnFilterSubmit()
|
||||
{
|
||||
if (_dataGrid != null)
|
||||
await _dataGrid.ReloadServerData();
|
||||
}
|
||||
|
||||
private async Task OnFilterCleared()
|
||||
{
|
||||
_userIdFilter = null;
|
||||
_transactionIdFilter = null;
|
||||
_refIdFilter = null;
|
||||
_createdFrom = null;
|
||||
_createdTo = null;
|
||||
if (_dataGrid != null)
|
||||
await _dataGrid.ReloadServerData();
|
||||
}
|
||||
|
||||
private async Task OpenCreateDialog()
|
||||
{
|
||||
var options = new DialogOptions { CloseButton = true, MaxWidth = MaxWidth.Small, FullWidth = true };
|
||||
var dialog = DialogService.Show<ManualCreditChargeDialog>("شارژ دستی کیف پول اصلی", options);
|
||||
var result = await dialog.Result;
|
||||
if (result is { Canceled: false } && _dataGrid != null)
|
||||
await _dataGrid.ReloadServerData();
|
||||
}
|
||||
}
|
||||
@@ -200,6 +200,12 @@
|
||||
</MudNavLink>
|
||||
}
|
||||
|
||||
<MudNavLink Match="NavLinkMatch.Prefix"
|
||||
Href="/payment/manual-credit-charges"
|
||||
Icon="@Icons.Material.Filled.AddCard">
|
||||
شارژ دستی کیف پول
|
||||
</MudNavLink>
|
||||
|
||||
<MudNavLink Match="NavLinkMatch.Prefix"
|
||||
Href="/payment/transactions"
|
||||
Icon="@Icons.Material.Filled.ReceiptLong">
|
||||
|
||||
Reference in New Issue
Block a user