feat: Add ClearCart command and response, implement CancelOrder command with validation, and enhance DeliveryStatus and User models
This commit is contained in:
@@ -187,6 +187,10 @@ using (var scope = app.Services.CreateScope())
|
||||
});
|
||||
|
||||
app.Logger.LogInformation("✅ Hangfire recurring job 'weekly-commission-calculation' registered (Cron: 5 0 * * 0 - Sunday 00:05 UTC)");
|
||||
|
||||
// Daya Loan Check: Every 15 minutes
|
||||
CMSMicroservice.WebApi.Workers.DayaLoanCheckWorker.Schedule(recurringJobManager);
|
||||
app.Logger.LogInformation("✅ Hangfire recurring job 'daya-loan-check' registered (Cron: */15 * * * * - Every 15 minutes)");
|
||||
}
|
||||
|
||||
app.Run();
|
||||
|
||||
@@ -5,6 +5,9 @@ using CMSMicroservice.Application.TransactionsCQ.Commands.UpdateTransactions;
|
||||
using CMSMicroservice.Application.TransactionsCQ.Commands.DeleteTransactions;
|
||||
using CMSMicroservice.Application.TransactionsCQ.Queries.GetTransactions;
|
||||
using CMSMicroservice.Application.TransactionsCQ.Queries.GetAllTransactionsByFilter;
|
||||
using CMSMicroservice.Application.TransactionsCQ.Commands.VerifyTransaction;
|
||||
using CMSMicroservice.Application.TransactionsCQ.Commands.RefundTransaction;
|
||||
|
||||
namespace CMSMicroservice.WebApi.Services;
|
||||
public class TransactionsService : TransactionsContract.TransactionsContractBase
|
||||
{
|
||||
@@ -34,4 +37,14 @@ public class TransactionsService : TransactionsContract.TransactionsContractBase
|
||||
{
|
||||
return await _dispatchRequestToCQRS.Handle<GetAllTransactionsByFilterRequest, GetAllTransactionsByFilterQuery, GetAllTransactionsByFilterResponse>(request, context);
|
||||
}
|
||||
|
||||
public override async Task<VerifyTransactionResponse> VerifyTransaction(VerifyTransactionRequest request, ServerCallContext context)
|
||||
{
|
||||
return await _dispatchRequestToCQRS.Handle<VerifyTransactionRequest, VerifyTransactionCommand, VerifyTransactionResponse>(request, context);
|
||||
}
|
||||
|
||||
public override async Task<RefundTransactionResponse> RefundTransaction(RefundTransactionRequest request, ServerCallContext context)
|
||||
{
|
||||
return await _dispatchRequestToCQRS.Handle<RefundTransactionRequest, RefundTransactionCommand, RefundTransactionResponse>(request, context);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,6 +5,8 @@ using CMSMicroservice.Application.UserCartsCQ.Commands.UpdateUserCarts;
|
||||
using CMSMicroservice.Application.UserCartsCQ.Commands.DeleteUserCarts;
|
||||
using CMSMicroservice.Application.UserCartsCQ.Queries.GetUserCarts;
|
||||
using CMSMicroservice.Application.UserCartsCQ.Queries.GetAllUserCartsByFilter;
|
||||
using CMSMicroservice.Application.UserCartsCQ.Commands.ClearCart;
|
||||
|
||||
namespace CMSMicroservice.WebApi.Services;
|
||||
public class UserCartsService : UserCartsContract.UserCartsContractBase
|
||||
{
|
||||
@@ -34,4 +36,9 @@ public class UserCartsService : UserCartsContract.UserCartsContractBase
|
||||
{
|
||||
return await _dispatchRequestToCQRS.Handle<GetAllUserCartsByFilterRequest, GetAllUserCartsByFilterQuery, GetAllUserCartsByFilterResponse>(request, context);
|
||||
}
|
||||
|
||||
public override async Task<ClearCartResponse> ClearCart(ClearCartRequest request, ServerCallContext context)
|
||||
{
|
||||
return await _dispatchRequestToCQRS.Handle<ClearCartRequest, ClearCartCommand, ClearCartResponse>(request, context);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,6 +6,8 @@ using CMSMicroservice.Application.UserOrderCQ.Commands.DeleteUserOrder;
|
||||
using CMSMicroservice.Application.UserOrderCQ.Queries.GetUserOrder;
|
||||
using CMSMicroservice.Application.UserOrderCQ.Queries.GetAllUserOrderByFilter;
|
||||
using CMSMicroservice.Application.UserOrderCQ.Commands.SubmitShopBuyOrder;
|
||||
using CMSMicroservice.Application.UserOrderCQ.Commands.CancelOrder;
|
||||
|
||||
namespace CMSMicroservice.WebApi.Services;
|
||||
public class UserOrderService : UserOrderContract.UserOrderContractBase
|
||||
{
|
||||
@@ -39,4 +41,9 @@ public class UserOrderService : UserOrderContract.UserOrderContractBase
|
||||
{
|
||||
return await _dispatchRequestToCQRS.Handle<SubmitShopBuyOrderRequest, SubmitShopBuyOrderCommand, SubmitShopBuyOrderResponse>(request, context);
|
||||
}
|
||||
|
||||
public override async Task<CancelOrderResponse> CancelOrder(CancelOrderRequest request, ServerCallContext context)
|
||||
{
|
||||
return await _dispatchRequestToCQRS.Handle<CancelOrderRequest, CancelOrderCommand, CancelOrderResponse>(request, context);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,121 @@
|
||||
using Hangfire;
|
||||
using MediatR;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using CMSMicroservice.Application.DayaLoanCQ.Commands.CheckDayaLoanStatus;
|
||||
using CMSMicroservice.Application.DayaLoanCQ.Commands.ProcessDayaLoanApproval;
|
||||
using CMSMicroservice.Domain.Enums;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using CMSMicroservice.Infrastructure.Persistence;
|
||||
using System.Linq;
|
||||
|
||||
namespace CMSMicroservice.WebApi.Workers;
|
||||
|
||||
/// <summary>
|
||||
/// Worker برای استعلام خودکار وضعیت وام دایا (هر 15 دقیقه)
|
||||
/// </summary>
|
||||
public class DayaLoanCheckWorker
|
||||
{
|
||||
private readonly IMediator _mediator;
|
||||
private readonly ApplicationDbContext _context;
|
||||
private readonly ILogger<DayaLoanCheckWorker> _logger;
|
||||
|
||||
public DayaLoanCheckWorker(
|
||||
IMediator mediator,
|
||||
ApplicationDbContext context,
|
||||
ILogger<DayaLoanCheckWorker> logger)
|
||||
{
|
||||
_mediator = mediator;
|
||||
_context = context;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// متد اصلی که توسط Hangfire فراخوانی میشود
|
||||
/// </summary>
|
||||
[AutomaticRetry(Attempts = 3)]
|
||||
public async Task ExecuteAsync()
|
||||
{
|
||||
_logger.LogInformation("DayaLoanCheckWorker started at {Time}", DateTime.UtcNow);
|
||||
|
||||
try
|
||||
{
|
||||
// پیدا کردن کاربرانی که اعتبار دایا را دریافت نکردهاند
|
||||
var pendingUsers = await _context.Users
|
||||
.Where(u =>
|
||||
u.HasReceivedDayaCredit == false &&
|
||||
u.NationalCode != null &&
|
||||
u.NationalCode != "")
|
||||
.Select(u => new { u.Id, u.NationalCode })
|
||||
.ToListAsync();
|
||||
|
||||
if (!pendingUsers.Any())
|
||||
{
|
||||
_logger.LogInformation("No pending users found for Daya loan check");
|
||||
return;
|
||||
}
|
||||
|
||||
_logger.LogInformation("Found {Count} users with pending Daya loan status", pendingUsers.Count);
|
||||
|
||||
// استعلام از دایا
|
||||
var checkCommand = new CheckDayaLoanStatusCommand
|
||||
{
|
||||
NationalCodes = pendingUsers.Select(u => u.NationalCode).ToList()
|
||||
};
|
||||
|
||||
var checkResult = await _mediator.Send(checkCommand);
|
||||
|
||||
// پردازش نتایج
|
||||
foreach (var result in checkResult.Results)
|
||||
{
|
||||
// فقط وضعیت PendingReceive را پردازش میکنیم (یعنی وام درخواست شده)
|
||||
if (result.Status == DayaLoanStatus.PendingReceive && !string.IsNullOrEmpty(result.ContractNumber))
|
||||
{
|
||||
var user = pendingUsers.FirstOrDefault(u => u.NationalCode == result.NationalCode);
|
||||
if (user != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
// پردازش تایید وام و شارژ کیف پول
|
||||
var processCommand = new ProcessDayaLoanApprovalCommand
|
||||
{
|
||||
UserId = user.Id,
|
||||
ContractNumber = result.ContractNumber
|
||||
};
|
||||
|
||||
var processResult = await _mediator.Send(processCommand);
|
||||
|
||||
_logger.LogInformation("Daya loan processed for user {UserId}. Contract: {ContractNumber}",
|
||||
user.Id, result.ContractNumber);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "Error processing Daya loan for user {UserId}", user.Id);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_logger.LogInformation("DayaLoanCheckWorker completed. Checked: {Total}, Processed: {Success}",
|
||||
checkResult.TotalChecked, checkResult.SuccessCount);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "Error in DayaLoanCheckWorker");
|
||||
throw; // Hangfire will retry
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// متد برای Schedule کردن Worker (هر 15 دقیقه)
|
||||
/// </summary>
|
||||
public static void Schedule(IRecurringJobManager recurringJobManager)
|
||||
{
|
||||
// هر 15 دقیقه: */15 * * * *
|
||||
recurringJobManager.AddOrUpdate<DayaLoanCheckWorker>(
|
||||
"daya-loan-check",
|
||||
worker => worker.ExecuteAsync(),
|
||||
"*/15 * * * *", // هر 15 دقیقه
|
||||
TimeZoneInfo.Utc
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
{
|
||||
"Logging": {
|
||||
"LogLevel": {
|
||||
"Default": "Information",
|
||||
"Microsoft.AspNetCore": "Warning",
|
||||
"Microsoft.EntityFrameworkCore": "Warning"
|
||||
}
|
||||
},
|
||||
"ConnectionStrings": {
|
||||
"DefaultConnection": "Server=YOUR_PRODUCTION_SERVER;Database=FourSat_CMS;User Id=YOUR_USER;Password=YOUR_PASSWORD;TrustServerCertificate=True;MultipleActiveResultSets=true"
|
||||
},
|
||||
"Email": {
|
||||
"Enabled": true,
|
||||
"SmtpHost": "smtp.gmail.com",
|
||||
"SmtpPort": 587,
|
||||
"SmtpUsername": "your-production-email@gmail.com",
|
||||
"SmtpPassword": "your-gmail-app-password",
|
||||
"FromEmail": "noreply@foursat.com",
|
||||
"FromName": "FourSat CMS",
|
||||
"EnableSsl": true
|
||||
},
|
||||
"Sms": {
|
||||
"Enabled": true,
|
||||
"Provider": "Kavenegar",
|
||||
"KavenegarApiKey": "YOUR_PRODUCTION_KAVENEGAR_API_KEY",
|
||||
"Sender": "10008663"
|
||||
},
|
||||
"Jwt": {
|
||||
"Issuer": "https://api.foursat.com",
|
||||
"Audience": "https://foursat.com",
|
||||
"SecretKey": "YOUR_PRODUCTION_SECRET_KEY_MINIMUM_32_CHARACTERS_LONG"
|
||||
},
|
||||
"AllowedHosts": "*"
|
||||
}
|
||||
@@ -1,4 +1,6 @@
|
||||
{
|
||||
"UseRealPaymentGateway": false,
|
||||
"PaymentProvider": "BankMellat",
|
||||
"JwtSecurityKey": "TvlZVx5TJaHs8e9HgUdGzhGP2CIidoI444nAj+8+g7c=",
|
||||
"JwtIssuer": "https://localhost",
|
||||
"JwtAudience": "https://localhost",
|
||||
@@ -39,10 +41,20 @@
|
||||
"KavenegarApiKey": "YOUR_KAVENEGAR_API_KEY",
|
||||
"Sender": "10008663"
|
||||
},
|
||||
"DayaPayment": {
|
||||
"BaseUrl": "https://api.daya.ir",
|
||||
"ApiKey": "YOUR_DAYA_API_KEY"
|
||||
},
|
||||
"BankMellat": {
|
||||
"ServiceUrl": "https://bpm.shaparak.ir/pgwchannel/services/pgw",
|
||||
"TerminalId": "YOUR_TERMINAL_ID",
|
||||
"Username": "YOUR_USERNAME",
|
||||
"Password": "YOUR_PASSWORD"
|
||||
},
|
||||
"AllowedHosts": "*",
|
||||
"Kestrel": {
|
||||
"EndpointDefaults": {
|
||||
"Protocols": "Http2"
|
||||
"Protocols": "Http1AndHttp2"
|
||||
}
|
||||
},
|
||||
"Authentication": {
|
||||
|
||||
Reference in New Issue
Block a user