Files
BackOffice/src/BackOffice/Pages/Payment/Components/ManualPaymentDialog.razor.cs
T
masoodafar-web 85208da1b5
Build and Deploy to Kubernetes / build-and-deploy (push) Failing after 1m39s
feat: manual payment - replace amount with package selector
- Remove manual amount input field
- Add package selector dropdown (shows name + price)
- Pre-select base package, show price in alert
- Validate package selection before submit
- Send package_id to CMS, proto NuGet 0.0.192
2026-03-11 23:44:36 +03:30

252 lines
7.5 KiB
C#

using CMSMicroservice.Protobuf.Protos.ManualPayment;
using CMSMicroservice.Protobuf.Protos.Package;
using Google.Protobuf;
using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.Forms;
using MudBlazor;
namespace BackOffice.Pages.Payment.Components;
public enum ManualPaymentDialogMode
{
Create = 0,
Details = 1
}
public enum ManualPaymentDialogStatus
{
Pending = 0,
Approved = 1,
Rejected = 2,
Cancelled = 3
}
public partial class ManualPaymentDialog
{
[CascadingParameter] IMudDialogInstance MudDialog { get; set; } = default!;
[Inject] public ManualPaymentContract.ManualPaymentContractClient ManualPaymentClient { get; set; } = default!;
[Inject] public PackageContract.PackageContractClient PackageClient { get; set; } = default!;
// Snackbar is injected via _Imports.razor
[Parameter] public ManualPaymentDialogMode Mode { get; set; }
[Parameter] public ManualPaymentModel? Model { get; set; }
private ManualPaymentModel _createModel = new(){ Amount = 0 };
private string? _adminNote;
// User selection
private long? _selectedUserId;
// Package selection
private long? _selectedPackageId;
private long? _selectedPackagePrice;
private List<GetAllPackageByFilterResponseModel> _packages = new();
// Type and Description
private int _selectedType = 1; // Default: CashDeposit
private string _description = "عضویت دستی باشگاه مشتریان";
// Image upload
private IBrowserFile? _imageFile;
private string? _imagePreview;
private const long MaxFileSize = 10 * 1024 * 1024; // 10MB
private bool _isSubmitting;
protected override async Task OnInitializedAsync()
{
await LoadPackages();
}
private async Task LoadPackages()
{
try
{
var request = new GetAllPackageByFilterRequest
{
PaginationState = new() { PageNumber = 1, PageSize = 100 },
Filter = new()
};
var result = await PackageClient.GetAllPackageByFilterAsync(request);
_packages = result.Models?.OrderBy(p => p.SortOrder).ToList()
?? new List<GetAllPackageByFilterResponseModel>();
// اگر پکیج پایه وجود دارد، پیش‌فرض انتخاب کن
var basePackage = _packages.FirstOrDefault(p => p.IsBasePackage);
if (basePackage != null)
{
_selectedPackageId = basePackage.Id;
_selectedPackagePrice = basePackage.Price;
}
}
catch
{
_packages = new List<GetAllPackageByFilterResponseModel>();
}
}
private void OnPackageChanged(long? packageId)
{
_selectedPackageId = packageId;
var pkg = _packages.FirstOrDefault(p => p.Id == packageId);
_selectedPackagePrice = pkg?.Price;
}
private async Task OnImageFileSelected(IBrowserFile? file)
{
if (file == null)
{
RemoveImage();
return;
}
_imageFile = file;
// Create preview
var buffer = new byte[file.Size];
await file.OpenReadStream(MaxFileSize).ReadAsync(buffer);
_imagePreview = $"data:{file.ContentType};base64,{Convert.ToBase64String(buffer)}";
}
private void RemoveImage()
{
_imageFile = null;
_imagePreview = null;
}
private async Task CreateAsync()
{
if (_isSubmitting) return;
// Validation
if (!_selectedUserId.HasValue || _selectedUserId.Value <= 0)
{
Snackbar.Add("لطفاً کاربر را انتخاب کنید.", Severity.Warning);
return;
}
if (!_selectedPackageId.HasValue || _selectedPackageId.Value <= 0)
{
Snackbar.Add("لطفاً پکیج را انتخاب کنید.", Severity.Warning);
return;
}
if (_selectedType <= 0)
{
Snackbar.Add("لطفاً نوع پرداخت را انتخاب کنید.", Severity.Warning);
return;
}
if (string.IsNullOrWhiteSpace(_description))
{
Snackbar.Add("لطفاً توضیحات را وارد کنید.", Severity.Warning);
return;
}
_isSubmitting = true;
StateHasChanged();
try
{
var request = new CreateManualPaymentRequest
{
UserId = _selectedUserId.Value,
Amount = 0, // deprecated — مبلغ از پکیج خوانده می‌شود
PackageId = _selectedPackageId.Value,
Type = (ManualPaymentType)_selectedType,
Description = _description
};
if (!string.IsNullOrWhiteSpace(_createModel.ReferenceNumber))
{
request.ReferenceNumber = _createModel.ReferenceNumber;
}
// Upload image file
if (_imageFile != null)
{
var buffer = new byte[_imageFile.Size];
await _imageFile.OpenReadStream(MaxFileSize).ReadAsync(buffer);
request.ImageFile = new FileUploadModel
{
File = ByteString.CopyFrom(buffer),
FileName = _imageFile.Name,
Mime = _imageFile.ContentType
};
}
await ManualPaymentClient.CreateManualPaymentAsync(request);
Snackbar.Add("پرداخت دستی با موفقیت ثبت شد.", Severity.Success);
MudDialog.Close(DialogResult.Ok(true));
}
catch (Exception ex)
{
Snackbar.Add($"خطا در ثبت پرداخت دستی: {ex.Message}", Severity.Error);
}
finally
{
_isSubmitting = false;
StateHasChanged();
}
}
private async Task ApproveAsync()
{
if (Model is null) return;
try
{
var request = new ApproveManualPaymentRequest
{
ManualPaymentId = Model.Id
};
if (!string.IsNullOrWhiteSpace(_adminNote))
{
request.ApprovalNote = _adminNote;
}
await ManualPaymentClient.ApproveManualPaymentAsync(request);
Snackbar.Add("پرداخت دستی تایید شد.", Severity.Success);
MudDialog.Close(DialogResult.Ok(true));
}
catch (Exception ex)
{
Snackbar.Add($"خطا در تایید پرداخت دستی: {ex.Message}", Severity.Error);
}
}
private async Task RejectAsync()
{
if (Model is null) return;
try
{
if (string.IsNullOrWhiteSpace(_adminNote))
{
Snackbar.Add("لطفاً دلیل رد را وارد کنید.", Severity.Warning);
return;
}
var request = new RejectManualPaymentRequest
{
ManualPaymentId = Model.Id,
RejectionReason = _adminNote
};
await ManualPaymentClient.RejectManualPaymentAsync(request);
Snackbar.Add("پرداخت دستی رد شد.", Severity.Success);
MudDialog.Close(DialogResult.Ok(true));
}
catch (Exception ex)
{
Snackbar.Add($"خطا در رد پرداخت دستی: {ex.Message}", Severity.Error);
}
}
private void Close() => MudDialog.Close(DialogResult.Cancel());
}