feat(payment): add manual credit charge functionality and update related components
Build and Deploy to Kubernetes / build-and-deploy (push) Has been cancelled

- Introduced new manual credit charge endpoints in ADMIN-SERVICES.md.
- Updated ReportLabels.cs and LedgerTransactions.razor to include manual credit wallet charge options.
- Enhanced NavMenu.razor with a link to the manual credit charges page.
- Bumped Foursat.CMSMicroservice.Protobuf version to 0.0.205 for compatibility with new features.
This commit is contained in:
masoodafar-web
2026-07-25 23:54:57 +03:30
parent d757c8220c
commit 4115f64fff
7 changed files with 266 additions and 1 deletions
+2
View File
@@ -167,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) |
---
+1 -1
View File
@@ -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();
}
}
+6
View File
@@ -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">