Merge branch 'kub-stage' into production
Build and Deploy to Production / build-and-deploy (push) Successful in 8m56s
Build and Deploy to Production / build-and-deploy (push) Successful in 8m56s
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
using CMSMicroservice.Application.Common.Interfaces;
|
||||
using CMSMicroservice.Application.DiscountShopCQ.Commands.CompleteOrderPayment;
|
||||
using CMSMicroservice.Application.WalletCQ.Commands.VerifyMagicWalletCharge;
|
||||
using MediatR;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
@@ -143,4 +144,46 @@ public class PaymentCallbackController : ControllerBase
|
||||
$"{frontOfficeBaseUrl}/discount-store/order/{orderId}?payment=error");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Callback برای شارژ کیفپول جادویی — زرینپال بعد از پرداخت کاربر را اینجا برمیگرداند
|
||||
/// </summary>
|
||||
[HttpGet("/api/wallet/verify-magic-charge")]
|
||||
public async Task<IActionResult> MagicChargeCallback(
|
||||
[FromQuery(Name = "Authority")] string? authority,
|
||||
[FromQuery(Name = "Status")] string? status,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
var frontOfficeBaseUrl = _configuration["FrontOfficeBaseUrl"] ?? "https://localhost:5268";
|
||||
|
||||
_logger.LogInformation(
|
||||
"Magic charge callback received: Authority={Authority}, Status={Status}",
|
||||
authority, status);
|
||||
|
||||
try
|
||||
{
|
||||
if (string.IsNullOrEmpty(authority))
|
||||
{
|
||||
_logger.LogError("Magic charge callback: Authority is missing");
|
||||
return Redirect($"{frontOfficeBaseUrl}/magic-wallet?payment=error&reason=no-authority");
|
||||
}
|
||||
|
||||
var result = await _sender.Send(new VerifyMagicWalletChargeCommand
|
||||
{
|
||||
Authority = authority,
|
||||
Status = status ?? "NOK"
|
||||
}, cancellationToken);
|
||||
|
||||
_logger.LogInformation(
|
||||
"Magic charge completed successfully. Authority={Authority}",
|
||||
authority);
|
||||
|
||||
return Redirect($"{frontOfficeBaseUrl}/magic-wallet?payment=success");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "Magic charge callback error. Authority={Authority}", authority);
|
||||
return Redirect($"{frontOfficeBaseUrl}/magic-wallet?payment=failed");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,7 +6,9 @@ using CMSMicroservice.Application.UserOrderCQ.Queries.GetCustomerOrderHistory;
|
||||
using CMSMicroservice.Application.OrderManagementCQ.Commands.UpdateOrderStatus;
|
||||
using CMSMicroservice.Application.OrderManagementCQ.Commands.CancelOrderByAdmin;
|
||||
using CMSMicroservice.Application.Common.Interfaces;
|
||||
using CMSMicroservice.Domain.Common;
|
||||
using CMSMicroservice.Domain.Entities;
|
||||
using CMSMicroservice.Domain.Entities.Club;
|
||||
using CMSMicroservice.Domain.Entities.Order;
|
||||
using CMSMicroservice.Domain.Enums;
|
||||
using AppModels = CMSMicroservice.Application.Common.Models;
|
||||
@@ -272,7 +274,7 @@ public class UserOrderService : UserOrderContract.UserOrderContractBase
|
||||
}
|
||||
|
||||
// Calculate amounts
|
||||
const decimal vatRate = 0.09m;
|
||||
const decimal vatRate = 0.10m;
|
||||
long baseAmount = cartItems.Sum(c => c.Product.Price * c.Count);
|
||||
long vatAmount = (long)(baseAmount * vatRate);
|
||||
long totalAmount = baseAmount + vatAmount;
|
||||
@@ -334,7 +336,54 @@ public class UserOrderService : UserOrderContract.UserOrderContractBase
|
||||
};
|
||||
|
||||
_context.UserWalletChangeLogs.Add(walletLog);
|
||||
|
||||
|
||||
// ═══ Magic Wallet: Entry / Exit Trigger ═══
|
||||
if (wallet.Balance == 0)
|
||||
{
|
||||
var user = await _context.Users
|
||||
.Include(u => u.ClubMembership)
|
||||
.FirstOrDefaultAsync(u => u.Id == userId, context.CancellationToken);
|
||||
|
||||
if (wallet.WalletMode == WalletMode.Magic
|
||||
&& wallet.MagicTotalDeposited >= SystemConstants.MagicWalletMaxDeposit)
|
||||
{
|
||||
// ── EXIT Magic Mode ──
|
||||
// هر دو شرط: Balance=0 و سقف 100M پر شده
|
||||
wallet.WalletMode = WalletMode.Normal;
|
||||
wallet.MagicCompletedAt = DateTime.UtcNow;
|
||||
|
||||
var currentCycle = await _context.ClubMembershipCycles
|
||||
.FirstOrDefaultAsync(c => c.UserId == userId && c.IsCurrentCycle,
|
||||
context.CancellationToken);
|
||||
if (currentCycle != null)
|
||||
{
|
||||
currentCycle.MagicCompletedAt = DateTime.UtcNow;
|
||||
}
|
||||
}
|
||||
else if (wallet.WalletMode == WalletMode.Normal
|
||||
&& user != null
|
||||
&& user.PackagePurchaseMethod != PackagePurchaseMethod.None
|
||||
&& user.ClubMembership?.IsActive == true)
|
||||
{
|
||||
// ── ENTER Magic Mode ──
|
||||
wallet.WalletMode = WalletMode.Magic;
|
||||
wallet.MagicActivatedAt = DateTime.UtcNow;
|
||||
wallet.MagicCompletedAt = null;
|
||||
wallet.MagicTotalDeposited = 0;
|
||||
wallet.MagicTotalCredited = 0;
|
||||
|
||||
var currentCycle = await _context.ClubMembershipCycles
|
||||
.FirstOrDefaultAsync(c => c.UserId == userId && c.IsCurrentCycle,
|
||||
context.CancellationToken);
|
||||
if (currentCycle != null)
|
||||
{
|
||||
currentCycle.MagicStartedAt = DateTime.UtcNow;
|
||||
}
|
||||
}
|
||||
// ⚠️ اگه Magic باشه و Balance=0 ولی سقف پر نشده → هنوز Magic!
|
||||
// کاربر میتونه دوباره شارژ کنه
|
||||
}
|
||||
|
||||
// Create order
|
||||
var order = new UserOrder
|
||||
{
|
||||
@@ -935,11 +984,11 @@ public class UserOrderService : UserOrderContract.UserOrderContractBase
|
||||
|
||||
public override Task<GetVATRateResponse> GetVATRate(Google.Protobuf.WellKnownTypes.Empty request, ServerCallContext context)
|
||||
{
|
||||
// VAT Rate for Iran: 9% (نرخ مالیات بر ارزش افزوده ایران)
|
||||
// VAT Rate for Iran: 10% (نرخ مالیات بر ارزش افزوده ایران)
|
||||
return Task.FromResult(new GetVATRateResponse
|
||||
{
|
||||
VatRate = 0.09,
|
||||
VatPercentage = 9,
|
||||
VatRate = 0.10,
|
||||
VatPercentage = 10,
|
||||
IsEnabled = true
|
||||
});
|
||||
}
|
||||
|
||||
@@ -3,13 +3,17 @@ using CMSMicroservice.WebApi.Common.Services;
|
||||
using CMSMicroservice.Application.UserWalletCQ.Commands.CreateNewUserWallet;
|
||||
using CMSMicroservice.Application.UserWalletCQ.Commands.UpdateUserWallet;
|
||||
using CMSMicroservice.Application.UserWalletCQ.Commands.DeleteUserWallet;
|
||||
using CMSMicroservice.Application.WalletCQ.Commands.ChargeMagicWallet;
|
||||
using CMSMicroservice.Application.UserWalletCQ.Queries.GetUserWallet;
|
||||
using CMSMicroservice.Application.UserWalletCQ.Queries.GetAllUserWalletByFilter;
|
||||
using CMSMicroservice.Application.UserWalletCQ.Queries.GetCustomerWalletChangeLog;
|
||||
using CMSMicroservice.Application.UserWalletCQ.Queries.GetCustomerWithdrawals;
|
||||
using CMSMicroservice.Application.UserWalletCQ.Queries.GetCustomerWithdrawalSettings;
|
||||
using CMSMicroservice.Application.Common.Interfaces;
|
||||
using CMSMicroservice.Domain.Common;
|
||||
using CMSMicroservice.Domain.Enums;
|
||||
using Grpc.Core;
|
||||
using Google.Protobuf.WellKnownTypes;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using System.Linq;
|
||||
|
||||
@@ -64,11 +68,15 @@ public class UserWalletService : UserWalletContract.UserWalletContractBase
|
||||
var walletQuery = new GetUserWalletQuery { Id = userId };
|
||||
var wallet = await _sender.Send(walletQuery, context.CancellationToken);
|
||||
|
||||
var walletEntity = await _context.UserWallets
|
||||
.FirstOrDefaultAsync(w => w.UserId == userId, context.CancellationToken);
|
||||
|
||||
return new GetCustomerWalletResponse
|
||||
{
|
||||
Balance = wallet.Balance,
|
||||
NetworkBalance = wallet.NetworkBalance,
|
||||
DiscountBalance = wallet.DiscountBalance
|
||||
DiscountBalance = wallet.DiscountBalance,
|
||||
WalletMode = (int)(walletEntity?.WalletMode ?? WalletMode.Normal)
|
||||
};
|
||||
}
|
||||
|
||||
@@ -141,6 +149,57 @@ public class UserWalletService : UserWalletContract.UserWalletContractBase
|
||||
return new Google.Protobuf.WellKnownTypes.Empty();
|
||||
}
|
||||
|
||||
// ============= Magic Wallet Methods =============
|
||||
|
||||
public override async Task<InitiateMagicChargeResponse> InitiateMagicCharge(
|
||||
InitiateMagicChargeRequest request, ServerCallContext context)
|
||||
{
|
||||
var userId = GetCurrentUserId();
|
||||
|
||||
var result = await _sender.Send(new ChargeMagicWalletCommand
|
||||
{
|
||||
UserId = userId,
|
||||
Amount = request.Amount
|
||||
}, context.CancellationToken);
|
||||
|
||||
return new InitiateMagicChargeResponse
|
||||
{
|
||||
IsSuccess = result.IsSuccess,
|
||||
GatewayUrl = result.GatewayUrl ?? "",
|
||||
ErrorMessage = result.ErrorMessage ?? ""
|
||||
};
|
||||
}
|
||||
|
||||
public override async Task<GetMagicWalletStatusResponse> GetMagicWalletStatus(
|
||||
Google.Protobuf.WellKnownTypes.Empty request, ServerCallContext context)
|
||||
{
|
||||
var userId = GetCurrentUserId();
|
||||
|
||||
var wallet = await _context.UserWallets
|
||||
.FirstOrDefaultAsync(w => w.UserId == userId, context.CancellationToken);
|
||||
|
||||
if (wallet == null)
|
||||
throw new RpcException(new Status(StatusCode.NotFound, "کیف پول یافت نشد"));
|
||||
|
||||
var response = new GetMagicWalletStatusResponse
|
||||
{
|
||||
WalletMode = (int)wallet.WalletMode,
|
||||
MagicTotalDeposited = wallet.MagicTotalDeposited,
|
||||
MagicTotalCredited = wallet.MagicTotalCredited,
|
||||
MagicMaxDeposit = SystemConstants.MagicWalletMaxDeposit,
|
||||
MagicRemainingDeposit = Math.Max(0, SystemConstants.MagicWalletMaxDeposit - wallet.MagicTotalDeposited),
|
||||
Balance = wallet.Balance
|
||||
};
|
||||
|
||||
if (wallet.MagicActivatedAt.HasValue)
|
||||
{
|
||||
response.MagicActivatedAt = Timestamp.FromDateTime(
|
||||
DateTime.SpecifyKind(wallet.MagicActivatedAt.Value, DateTimeKind.Utc));
|
||||
}
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
private long GetCurrentUserId()
|
||||
{
|
||||
if (long.TryParse(_currentUserService.UserId, out var userId) && userId > 0)
|
||||
|
||||
Reference in New Issue
Block a user