376 lines
13 KiB
Plaintext
376 lines
13 KiB
Plaintext
@page "/profile/payment-callback"
|
|
@attribute [Authorize]
|
|
@using Blazored.LocalStorage
|
|
@using CMSMicroservice.Protobuf.Protos.Package
|
|
@using CMSMicroservice.Protobuf.Protos.User
|
|
@using FrontOffice.Main.Utilities
|
|
|
|
|
|
<PageTitle>نتیجه پرداخت | کارا بازار سلامت</PageTitle>
|
|
|
|
<MudContainer MaxWidth="MaxWidth.Small" Class="py-8">
|
|
<MudPaper Class="pa-6 text-center">
|
|
@if (_isLoading)
|
|
{
|
|
<MudProgressCircular Color="Color.Primary" Indeterminate="true" Size="Size.Large" />
|
|
<MudText Typo="Typo.h6" Class="mt-4">در حال بررسی وضعیت پرداخت...</MudText>
|
|
}
|
|
else if (_isSuccess)
|
|
{
|
|
<MudIcon Icon="@Icons.Material.Filled.CheckCircle" Color="Color.Success" Size="Size.Large" Style="font-size: 80px" />
|
|
<MudText Typo="Typo.h5" Color="Color.Success" Class="mt-4">پرداخت موفق</MudText>
|
|
<MudText Typo="Typo.body1" Class="mt-2">@_message</MudText>
|
|
|
|
@if (_transactionId > 0)
|
|
{
|
|
<MudText Typo="Typo.body2" Class="mt-3">
|
|
<strong>کد ارجاعی:</strong> @_transactionId
|
|
</MudText>
|
|
}
|
|
|
|
<MudDivider Class="my-4" />
|
|
|
|
<MudText Typo="Typo.body2" Color="Color.Secondary">
|
|
موجودی کیف پول اصلی: @FormatPrice(_walletBalance)
|
|
</MudText>
|
|
|
|
<MudButton Color="Color.Primary" Variant="Variant.Filled" Class="mt-6"
|
|
Href="@_successReturnUrl">
|
|
@_successReturnText
|
|
</MudButton>
|
|
}
|
|
else
|
|
{
|
|
<MudIcon Icon="@Icons.Material.Filled.Error" Color="Color.Error" Size="Size.Large" Style="font-size: 80px" />
|
|
<MudText Typo="Typo.h5" Color="Color.Error" Class="mt-4">پرداخت ناموفق</MudText>
|
|
<MudText Typo="Typo.body1" Class="mt-2">@_message</MudText>
|
|
|
|
<MudButton Color="Color.Primary" Variant="Variant.Filled" Class="mt-6"
|
|
Href="@_failReturnUrl">
|
|
@_failReturnText
|
|
</MudButton>
|
|
|
|
<MudButton Color="Color.Secondary" Variant="Variant.Outlined" Class="mt-3 mr-2"
|
|
OnClick="RetryPayment">
|
|
تلاش مجدد
|
|
</MudButton>
|
|
}
|
|
</MudPaper>
|
|
</MudContainer>
|
|
|
|
@code {
|
|
[Inject] private PackageContract.PackageContractClient PackageContractClient { get; set; } = default!;
|
|
[Inject] private UserContract.UserContractClient UserContractClient { get; set; } = default!;
|
|
[Inject] private DiscountOrderService DiscountOrderService { get; set; } = default!;
|
|
[Inject] private ILocalStorageService LocalStorage { get; set; } = default!;
|
|
[Inject] private AuthService AuthService { get; set; } = default!;
|
|
[Inject] private NavigationManager NavManager { get; set; } = default!;
|
|
|
|
private const string TokenStorageKey = "auth:token";
|
|
|
|
/// <summary>
|
|
/// نوع پرداخت: package (پیشفرض) | magic-wallet | discount-wallet | discount-order
|
|
/// </summary>
|
|
[SupplyParameterFromQuery(Name = "type")]
|
|
private string? PaymentType { get; set; }
|
|
|
|
[SupplyParameterFromQuery(Name = "orderId")]
|
|
private long OrderId { get; set; }
|
|
|
|
[SupplyParameterFromQuery(Name = "transactionId")]
|
|
private long TransactionId { get; set; }
|
|
|
|
[SupplyParameterFromQuery(Name = "Authority")]
|
|
private string? Authority { get; set; }
|
|
|
|
[SupplyParameterFromQuery(Name = "Status")]
|
|
private string? Status { get; set; }
|
|
|
|
private bool _isLoading = true;
|
|
private bool _isSuccess;
|
|
private string _message = string.Empty;
|
|
private long _transactionId;
|
|
private long _walletBalance;
|
|
private bool _verifyCompleted;
|
|
private readonly SemaphoreSlim _verifyGate = new(1, 1);
|
|
|
|
// دکمههای بازگشت بسته به نوع پرداخت
|
|
private string _successReturnUrl = "/profile";
|
|
private string _successReturnText = "بازگشت به پروفایل";
|
|
private string _failReturnUrl = "/profile";
|
|
private string _failReturnText = "بازگشت به پروفایل";
|
|
|
|
protected override async Task OnAfterRenderAsync(bool firstRender)
|
|
{
|
|
if (firstRender && !_verifyCompleted)
|
|
{
|
|
await VerifyPaymentOnceAsync();
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Blazor Server may invoke render/verify twice in quick succession — gate with semaphore.
|
|
/// </summary>
|
|
private async Task VerifyPaymentOnceAsync()
|
|
{
|
|
if (_verifyCompleted) return;
|
|
|
|
await _verifyGate.WaitAsync();
|
|
try
|
|
{
|
|
if (_verifyCompleted) return;
|
|
await VerifyPayment();
|
|
_verifyCompleted = true;
|
|
}
|
|
finally
|
|
{
|
|
_verifyGate.Release();
|
|
}
|
|
}
|
|
|
|
private async Task VerifyPayment()
|
|
{
|
|
try
|
|
{
|
|
// تعیین نوع پرداخت — اگر type نباشد، پیشفرض خرید پکیج
|
|
var type = PaymentType?.ToLowerInvariant() ?? "package";
|
|
|
|
switch (type)
|
|
{
|
|
case "magic-wallet":
|
|
await VerifyMagicWalletCharge();
|
|
break;
|
|
case "discount-wallet":
|
|
await VerifyDiscountWalletCharge();
|
|
break;
|
|
case "credit-wallet":
|
|
await VerifyCreditWalletCharge();
|
|
break;
|
|
case "discount-order":
|
|
await VerifyDiscountOrderPayment();
|
|
break;
|
|
default: // "package" or missing
|
|
await VerifyPackagePurchase();
|
|
break;
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_isSuccess = false;
|
|
_message = $"خطا در بررسی وضعیت پرداخت: {ex.Message}";
|
|
}
|
|
finally
|
|
{
|
|
_isLoading = false;
|
|
StateHasChanged();
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// تأیید خرید پکیج — رفتار فعلی
|
|
/// </summary>
|
|
private async Task VerifyPackagePurchase()
|
|
{
|
|
_successReturnUrl = "/profile";
|
|
_successReturnText = "بازگشت به پروفایل";
|
|
_failReturnUrl = "/profile";
|
|
_failReturnText = "بازگشت به پروفایل";
|
|
|
|
if (OrderId <= 0 || string.IsNullOrEmpty(Authority))
|
|
{
|
|
_isSuccess = false;
|
|
_message = "پارامترهای پرداخت نامعتبر است";
|
|
return;
|
|
}
|
|
|
|
var response = await PackageContractClient.CustomerVerifyPackagePurchaseAsync(new CustomerVerifyPackagePurchaseRequest
|
|
{
|
|
OrderId = OrderId,
|
|
Authority = Authority ?? string.Empty,
|
|
Status = Status ?? string.Empty
|
|
});
|
|
|
|
_isSuccess = response.Success;
|
|
_message = response.Message;
|
|
_transactionId = response.TransactionId;
|
|
|
|
if (_isSuccess)
|
|
{
|
|
await UpdateWalletBalanceAndRefreshToken();
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// تأیید شارژ کیفپول جادویی
|
|
/// </summary>
|
|
private async Task VerifyMagicWalletCharge()
|
|
{
|
|
_successReturnUrl = "/profile/magic-wallet";
|
|
_successReturnText = "بازگشت به کیف پول جادویی";
|
|
_failReturnUrl = "/profile/magic-wallet";
|
|
_failReturnText = "بازگشت به کیف پول جادویی";
|
|
|
|
if (string.IsNullOrEmpty(Authority))
|
|
{
|
|
_isSuccess = false;
|
|
_message = "کد Authority نامعتبر است";
|
|
return;
|
|
}
|
|
|
|
var (success, message) = await WalletService.VerifyMagicChargeAsync(
|
|
Authority, Status ?? "NOK");
|
|
|
|
_isSuccess = success;
|
|
_message = message;
|
|
|
|
if (_isSuccess)
|
|
{
|
|
await UpdateWalletBalance();
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// تأیید شارژ کیف پول تخفیفی
|
|
/// </summary>
|
|
private async Task VerifyDiscountWalletCharge()
|
|
{
|
|
_successReturnUrl = "/profile/charge-discount-wallet";
|
|
_successReturnText = "بازگشت به کیف پول تخفیفی";
|
|
_failReturnUrl = "/profile/charge-discount-wallet";
|
|
_failReturnText = "بازگشت به کیف پول تخفیفی";
|
|
|
|
if (string.IsNullOrEmpty(Authority))
|
|
{
|
|
_isSuccess = false;
|
|
_message = "کد Authority نامعتبر است";
|
|
return;
|
|
}
|
|
|
|
var (success, message) = await WalletService.VerifyDiscountChargeAsync(
|
|
Authority, Status ?? "NOK");
|
|
|
|
_isSuccess = success;
|
|
_message = message;
|
|
|
|
if (_isSuccess)
|
|
{
|
|
await UpdateWalletBalance();
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// تأیید شارژ کیف پول اصلی
|
|
/// </summary>
|
|
private async Task VerifyCreditWalletCharge()
|
|
{
|
|
_successReturnUrl = "/profile/charge-credit-wallet?payment=success";
|
|
_successReturnText = "بازگشت به شارژ کیف پول اصلی";
|
|
_failReturnUrl = "/profile/charge-credit-wallet?payment=failed";
|
|
_failReturnText = "بازگشت به شارژ کیف پول اصلی";
|
|
|
|
if (string.IsNullOrEmpty(Authority))
|
|
{
|
|
_isSuccess = false;
|
|
_message = "کد Authority نامعتبر است";
|
|
return;
|
|
}
|
|
|
|
var (success, message) = await WalletService.VerifyCreditChargeAsync(
|
|
Authority, Status ?? "NOK");
|
|
|
|
_isSuccess = success;
|
|
_message = message;
|
|
|
|
if (_isSuccess)
|
|
{
|
|
await UpdateWalletBalance();
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// تأیید پرداخت سفارش فروشگاه تخفیفی
|
|
/// </summary>
|
|
private async Task VerifyDiscountOrderPayment()
|
|
{
|
|
_successReturnUrl = $"/discount-store/order/{OrderId}";
|
|
_successReturnText = "مشاهده سفارش";
|
|
_failReturnUrl = $"/discount-store/order/{OrderId}";
|
|
_failReturnText = "مشاهده سفارش";
|
|
|
|
if (OrderId <= 0 || string.IsNullOrEmpty(Authority))
|
|
{
|
|
_isSuccess = false;
|
|
_message = "پارامترهای پرداخت نامعتبر است";
|
|
return;
|
|
}
|
|
|
|
var (success, message, _) = await DiscountOrderService.VerifyDiscountOrderPaymentAsync(
|
|
OrderId, Authority, Status ?? "NOK");
|
|
|
|
_isSuccess = success;
|
|
_message = message;
|
|
}
|
|
|
|
/// <summary>
|
|
/// بروزرسانی موجودی کیف پول
|
|
/// </summary>
|
|
private async Task UpdateWalletBalance()
|
|
{
|
|
try
|
|
{
|
|
var balances = await WalletService.GetBalancesAsync();
|
|
_walletBalance = balances.CreditBalance;
|
|
}
|
|
catch { /* اگر خطا شد، صفر نمایش بده */ }
|
|
}
|
|
|
|
/// <summary>
|
|
/// بروزرسانی موجودی + refresh توکن (فقط برای خرید پکیج)
|
|
/// </summary>
|
|
private async Task UpdateWalletBalanceAndRefreshToken()
|
|
{
|
|
await UpdateWalletBalance();
|
|
await RefreshTokenAsync();
|
|
}
|
|
|
|
private void RetryPayment()
|
|
{
|
|
var type = PaymentType?.ToLowerInvariant() ?? "package";
|
|
var url = type switch
|
|
{
|
|
"magic-wallet" => "/profile/magic-wallet",
|
|
"discount-wallet" => "/profile/charge-discount-wallet",
|
|
"credit-wallet" => "/profile/charge-credit-wallet",
|
|
"discount-order" => "/discount-store",
|
|
_ => "/profile"
|
|
};
|
|
NavManager.NavigateTo(url, forceLoad: true);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Refresh token after successful payment to update PackagePurchaseMethod claim
|
|
/// </summary>
|
|
private async Task RefreshTokenAsync()
|
|
{
|
|
try
|
|
{
|
|
var userResponse = await UserContractClient.GetUserForCustomerAsync(new CMSMicroservice.Protobuf.Protos.User.GetUserForCustomerRequest());
|
|
if (!string.IsNullOrWhiteSpace(userResponse.Token))
|
|
{
|
|
// ذخیره توکن جدید در localStorage
|
|
await LocalStorage.SetItemAsync(TokenStorageKey, userResponse.Token);
|
|
|
|
// بهروزرسانی UserAuthInfo با claims جدید
|
|
await AuthService.InitUserAuthInfo();
|
|
}
|
|
}
|
|
catch
|
|
{
|
|
// اگر refresh ناموفق بود، پرداخت همچنان موفق است
|
|
// کاربر میتواند با logout/login دوباره token جدید بگیرد
|
|
}
|
|
}
|
|
|
|
private static string FormatPrice(long price) => string.Format("{0:N0} تومان", price);
|
|
}
|