feat: Implement Public Message Management Commands and Queries

- Add GetUserPackageStatusQueryValidator for user package status validation.
- Create ArchiveMessageCommand and ArchiveMessageCommandHandler for archiving public messages.
- Implement ArchiveMessageCommandValidator to validate message ID.
- Introduce PublishMessageCommand and PublishMessageCommandHandler for publishing messages.
- Add PublishMessageCommandValidator for validating publish message requests.
- Implement GetPublicMessageQuery and GetPublicMessageQueryHandler for retrieving public messages.
- Create GetPublicMessageQueryValidator for validating public message requests.
- Add ApplyDiscountToOrderCommand and ApplyDiscountToOrderCommandHandler for applying discounts to orders.
- Implement ApplyDiscountToOrderCommandValidator for validating discount application requests.
- Create UpdateOrderStatusCommand and UpdateOrderStatusCommandHandler for changing order statuses.
- Implement UpdateOrderStatusCommandValidator for validating order status updates.
- Add CalculateOrderPVQuery and CalculateOrderPVQueryHandler for calculating order PV.
- Implement CalculateOrderPVQueryValidator for validating PV calculation requests.
- Create GetOrdersByDateRangeQuery and GetOrdersByDateRangeQueryHandler for retrieving orders by date range.
- Implement GetOrdersByDateRangeQueryValidator for validating date range queries.
- Add PublicMessage entity to represent public messages in the system.
- Implement PublicMessageService for handling public message operations via gRPC.
This commit is contained in:
masoodafar-web
2025-12-04 03:43:19 +03:30
parent 84f642e900
commit ba6d74fe35
45 changed files with 1777 additions and 22 deletions

View File

@@ -0,0 +1,16 @@
namespace CMSMicroservice.Application.PublicMessageCQ.Commands.ArchiveMessage;
/// <summary>
/// آرشیو پیام عمومی (غیرفعال و بایگانی)
/// </summary>
public record ArchiveMessageCommand : IRequest<ArchiveMessageResponseDto>
{
public long MessageId { get; init; }
}
public class ArchiveMessageResponseDto
{
public bool Success { get; set; }
public string Message { get; set; } = string.Empty;
public DateTime? ArchivedAt { get; set; }
}

View File

@@ -0,0 +1,52 @@
using CMSMicroservice.Application.Common.Interfaces;
namespace CMSMicroservice.Application.PublicMessageCQ.Commands.ArchiveMessage;
public class ArchiveMessageCommandHandler : IRequestHandler<ArchiveMessageCommand, ArchiveMessageResponseDto>
{
private readonly IApplicationDbContext _context;
private readonly ILogger<ArchiveMessageCommandHandler> _logger;
public ArchiveMessageCommandHandler(
IApplicationDbContext context,
ILogger<ArchiveMessageCommandHandler> logger)
{
_context = context;
_logger = logger;
}
public async Task<ArchiveMessageResponseDto> Handle(ArchiveMessageCommand request, CancellationToken cancellationToken)
{
// TODO: پیاده‌سازی آرشیو پیام
// 1. پیدا کردن پیام:
// - var message = await _context.PublicMessages
// .FirstOrDefaultAsync(m => m.Id == request.MessageId, cancellationToken)
// - بررسی null و پرتاب NotFoundException
//
// 2. بررسی وضعیت:
// - اگر قبلاً آرشیو شده:
// if (message.IsArchived)
// return موفقیت با پیام "این پیام قبلاً آرشیو شده است"
//
// 3. آرشیو کردن:
// - message.IsArchived = true
// - message.IsActive = false // غیرفعال هم می‌شود
// - message.ArchivedAt = DateTime.UtcNow
//
// 4. ذخیره و Log:
// - await _context.SaveChangesAsync(cancellationToken)
// - _logger.LogInformation("Public message {MessageId} archived: {Title}", message.Id, message.Title)
//
// 5. برگشت Response:
// - return new ArchiveMessageResponseDto {
// Success = true,
// Message = "پیام با موفقیت آرشیو شد",
// ArchivedAt = message.ArchivedAt
// }
//
// نکته: پیام‌های آرشیو شده دیگر در GetActiveMessages نمایش داده نمی‌شوند
// نکته: می‌توان پیام‌های آرشیو شده را در یک query جداگانه GetArchivedMessages دریافت کرد
throw new NotImplementedException("ArchiveMessage needs implementation");
}
}

View File

@@ -0,0 +1,11 @@
namespace CMSMicroservice.Application.PublicMessageCQ.Commands.ArchiveMessage;
public class ArchiveMessageCommandValidator : AbstractValidator<ArchiveMessageCommand>
{
public ArchiveMessageCommandValidator()
{
RuleFor(x => x.MessageId)
.GreaterThan(0)
.WithMessage("شناسه پیام باید بزرگتر از 0 باشد");
}
}

View File

@@ -1,5 +1,5 @@
using CMSMicroservice.Application.Common.Interfaces;
using CMSMicroservice.Domain.Entities.Message;
using CMSMicroservice.Domain.Entities;
using MediatR;
using Microsoft.Extensions.Logging;

View File

@@ -0,0 +1,16 @@
namespace CMSMicroservice.Application.PublicMessageCQ.Commands.PublishMessage;
/// <summary>
/// انتشار پیام عمومی (فعال‌سازی)
/// </summary>
public record PublishMessageCommand : IRequest<PublishMessageResponseDto>
{
public long MessageId { get; init; }
}
public class PublishMessageResponseDto
{
public bool Success { get; set; }
public string Message { get; set; } = string.Empty;
public DateTime? PublishedAt { get; set; }
}

View File

@@ -0,0 +1,56 @@
using CMSMicroservice.Application.Common.Interfaces;
namespace CMSMicroservice.Application.PublicMessageCQ.Commands.PublishMessage;
public class PublishMessageCommandHandler : IRequestHandler<PublishMessageCommand, PublishMessageResponseDto>
{
private readonly IApplicationDbContext _context;
private readonly ILogger<PublishMessageCommandHandler> _logger;
public PublishMessageCommandHandler(
IApplicationDbContext context,
ILogger<PublishMessageCommandHandler> logger)
{
_context = context;
_logger = logger;
}
public async Task<PublishMessageResponseDto> Handle(PublishMessageCommand request, CancellationToken cancellationToken)
{
// TODO: پیاده‌سازی انتشار پیام
// 1. پیدا کردن پیام:
// - var message = await _context.PublicMessages
// .FirstOrDefaultAsync(m => m.Id == request.MessageId, cancellationToken)
// - بررسی null و پرتاب NotFoundException
//
// 2. بررسی شرایط انتشار:
// - اگر قبلاً منتشر شده:
// if (message.IsActive && message.PublishedAt.HasValue)
// return موفقیت با پیام "این پیام قبلاً منتشر شده است"
// - اگر آرشیو شده:
// if (message.IsArchived)
// throw new InvalidOperationException("پیام آرشیو شده قابل انتشار نیست")
//
// 3. فعال‌سازی پیام:
// - message.IsActive = true
// - message.PublishedAt = DateTime.UtcNow
// - اگر StartDate خالی است، از الان شروع کن:
// if (!message.StartDate.HasValue)
// message.StartDate = DateTime.UtcNow
//
// 4. ذخیره و Log:
// - await _context.SaveChangesAsync(cancellationToken)
// - _logger.LogInformation("Public message {MessageId} published: {Title}", message.Id, message.Title)
//
// 5. برگشت Response:
// - return new PublishMessageResponseDto {
// Success = true,
// Message = "پیام با موفقیت منتشر شد",
// PublishedAt = message.PublishedAt
// }
//
// نکته: پس از publish، پیام برای کاربران قابل مشاهده می‌شود (GetActiveMessages)
throw new NotImplementedException("PublishMessage needs implementation");
}
}

View File

@@ -0,0 +1,11 @@
namespace CMSMicroservice.Application.PublicMessageCQ.Commands.PublishMessage;
public class PublishMessageCommandValidator : AbstractValidator<PublishMessageCommand>
{
public PublishMessageCommandValidator()
{
RuleFor(x => x.MessageId)
.GreaterThan(0)
.WithMessage("شناسه پیام باید بزرگتر از 0 باشد");
}
}

View File

@@ -14,8 +14,8 @@ public class PublicMessageDto
public string TypeName { get; set; } = string.Empty;
public MessagePriority Priority { get; set; }
public string PriorityName { get; set; } = string.Empty;
public DateTime StartsAt { get; set; }
public DateTime ExpiresAt { get; set; }
public DateTime? StartsAt { get; set; }
public DateTime? ExpiresAt { get; set; }
public string? LinkUrl { get; set; }
public string? LinkText { get; set; }
public DateTime Created { get; set; }

View File

@@ -15,9 +15,9 @@ public class AdminPublicMessageDto
public MessagePriority Priority { get; set; }
public string PriorityName { get; set; } = string.Empty;
public bool IsActive { get; set; }
public DateTime StartsAt { get; set; }
public DateTime ExpiresAt { get; set; }
public long CreatedByUserId { get; set; }
public DateTime? StartsAt { get; set; }
public DateTime? ExpiresAt { get; set; }
public long? CreatedByUserId { get; set; }
public int ViewCount { get; set; }
public string? LinkUrl { get; set; }
public string? LinkText { get; set; }

View File

@@ -0,0 +1,25 @@
namespace CMSMicroservice.Application.PublicMessageCQ.Queries.GetPublicMessage;
/// <summary>
/// دریافت یک پیام عمومی با شناسه
/// </summary>
public record GetPublicMessageQuery : IRequest<PublicMessageDto?>
{
public long MessageId { get; init; }
}
public class PublicMessageDto
{
public long Id { get; set; }
public string Title { get; set; } = string.Empty;
public string Content { get; set; } = string.Empty;
public MessageType MessageType { get; set; }
public bool IsActive { get; set; }
public bool IsArchived { get; set; }
public DateTime? StartDate { get; set; }
public DateTime? EndDate { get; set; }
public DateTime? PublishedAt { get; set; }
public DateTime? ArchivedAt { get; set; }
public DateTime CreatedAt { get; set; }
public DateTime? LastModifiedAt { get; set; }
}

View File

@@ -0,0 +1,46 @@
using CMSMicroservice.Application.Common.Interfaces;
namespace CMSMicroservice.Application.PublicMessageCQ.Queries.GetPublicMessage;
public class GetPublicMessageQueryHandler : IRequestHandler<GetPublicMessageQuery, PublicMessageDto?>
{
private readonly IApplicationDbContext _context;
public GetPublicMessageQueryHandler(IApplicationDbContext context)
{
_context = context;
}
public async Task<PublicMessageDto?> Handle(GetPublicMessageQuery request, CancellationToken cancellationToken)
{
// TODO: پیاده‌سازی دریافت پیام
// 1. پیدا کردن پیام:
// - var message = await _context.PublicMessages
// .AsNoTracking()
// .FirstOrDefaultAsync(m => m.Id == request.MessageId, cancellationToken)
//
// 2. چک null:
// - if (message == null) return null
//
// 3. Map به DTO:
// - return new PublicMessageDto {
// Id = message.Id,
// Title = message.Title,
// Content = message.Content,
// MessageType = message.MessageType,
// IsActive = message.IsActive,
// IsArchived = message.IsArchived,
// StartDate = message.StartDate,
// EndDate = message.EndDate,
// PublishedAt = message.PublishedAt,
// ArchivedAt = message.ArchivedAt,
// CreatedAt = message.CreatedAt,
// LastModifiedAt = message.LastModifiedAt
// }
//
// نکته: این query برای Admin است و همه پیام‌ها (حتی آرشیو شده) را برمی‌گرداند
// نکته: برای کاربران عادی از GetActiveMessages استفاده می‌شود
throw new NotImplementedException("GetPublicMessage needs implementation");
}
}

View File

@@ -0,0 +1,11 @@
namespace CMSMicroservice.Application.PublicMessageCQ.Queries.GetPublicMessage;
public class GetPublicMessageQueryValidator : AbstractValidator<GetPublicMessageQuery>
{
public GetPublicMessageQueryValidator()
{
RuleFor(x => x.MessageId)
.GreaterThan(0)
.WithMessage("شناسه پیام باید بزرگتر از 0 باشد");
}
}