Files
pos-system/services/merchant-service-net/src/MerchantService.API/Controllers/Admin/AdminShopsController.cs

186 lines
6.3 KiB
C#

// EN: Admin controller for shop management (Backoffice).
// VI: Controller Admin cho quản lý shop (Backoffice).
using MediatR;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using MerchantService.API.Application.Queries.Admin;
using MerchantService.Domain.AggregatesModel.ShopAggregate;
using MerchantService.Domain.Exceptions;
namespace MerchantService.API.Controllers.Admin;
/// <summary>
/// EN: Admin controller for shop management operations (Backoffice).
/// VI: Controller Admin cho các thao tác quản lý shop (Backoffice).
/// </summary>
[ApiController]
[Route("api/v1/admin/shops")]
[Authorize(Roles = "Admin,SuperAdmin")]
public class AdminShopsController : ControllerBase
{
private readonly IMediator _mediator;
private readonly IShopRepository _shopRepository;
private readonly ILogger<AdminShopsController> _logger;
public AdminShopsController(
IMediator mediator,
IShopRepository shopRepository,
ILogger<AdminShopsController> logger)
{
_mediator = mediator;
_shopRepository = shopRepository;
_logger = logger;
}
/// <summary>
/// EN: Get all shops with pagination.
/// VI: Lấy tất cả shops với phân trang.
/// </summary>
[HttpGet]
[ProducesResponseType(typeof(AdminShopListResultDto), StatusCodes.Status200OK)]
public async Task<IActionResult> GetAllShops(
[FromQuery] int page = 1,
[FromQuery] int pageSize = 20,
[FromQuery] string? status = null,
[FromQuery] Guid? merchantId = null,
[FromQuery] string? search = null)
{
var query = new GetAllShopsQuery(page, pageSize, status, merchantId, search);
var result = await _mediator.Send(query);
return Ok(result);
}
/// <summary>
/// EN: Get shop details by ID.
/// VI: Lấy chi tiết shop theo ID.
/// </summary>
[HttpGet("{shopId:guid}")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
public async Task<IActionResult> GetShopById(Guid shopId)
{
var shop = await _shopRepository.GetByIdAsync(shopId);
if (shop == null)
return NotFound(new { message = "Shop not found" });
return Ok(new
{
shop.Id,
shop.MerchantId,
shop.Name,
shop.Slug,
Status = shop.Status.Name,
Category = shop.Category?.Name,
shop.Description,
shop.CreatedAt,
shop.UpdatedAt
});
}
/// <summary>
/// EN: Suspend a shop.
/// VI: Tạm ngưng shop.
/// </summary>
[HttpPost("{shopId:guid}/suspend")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
public async Task<IActionResult> SuspendShop(Guid shopId, [FromBody] AdminActionRequest request)
{
try
{
var shop = await _shopRepository.GetByIdAsync(shopId)
?? throw new DomainException("Shop not found");
shop.SetInactive();
_shopRepository.Update(shop);
await _shopRepository.UnitOfWork.SaveEntitiesAsync();
_logger.LogInformation("Shop {ShopId} suspended by Admin {AdminId}. Reason: {Reason}",
shopId, GetAdminId(), request.Reason);
return Ok(new { message = "Shop suspended successfully", shopId, status = shop.Status.Name });
}
catch (DomainException ex)
{
if (ex.Message.Contains("not found"))
return NotFound(new { message = ex.Message });
return BadRequest(new { message = ex.Message });
}
}
/// <summary>
/// EN: Reactivate a suspended shop.
/// VI: Kích hoạt lại shop bị tạm ngưng.
/// </summary>
[HttpPost("{shopId:guid}/reactivate")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
public async Task<IActionResult> ReactivateShop(Guid shopId)
{
try
{
var shop = await _shopRepository.GetByIdAsync(shopId)
?? throw new DomainException("Shop not found");
shop.Publish();
_shopRepository.Update(shop);
await _shopRepository.UnitOfWork.SaveEntitiesAsync();
_logger.LogInformation("Shop {ShopId} reactivated by Admin {AdminId}", shopId, GetAdminId());
return Ok(new { message = "Shop reactivated successfully", shopId, status = shop.Status.Name });
}
catch (DomainException ex)
{
if (ex.Message.Contains("not found"))
return NotFound(new { message = ex.Message });
return BadRequest(new { message = ex.Message });
}
}
/// <summary>
/// EN: Close a shop permanently.
/// VI: Đóng cửa shop vĩnh viễn.
/// </summary>
[HttpPost("{shopId:guid}/close")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
public async Task<IActionResult> CloseShop(Guid shopId, [FromBody] AdminActionRequest request)
{
try
{
var shop = await _shopRepository.GetByIdAsync(shopId)
?? throw new DomainException("Shop not found");
shop.Close();
_shopRepository.Update(shop);
await _shopRepository.UnitOfWork.SaveEntitiesAsync();
_logger.LogWarning("Shop {ShopId} CLOSED by Admin {AdminId}. Reason: {Reason}",
shopId, GetAdminId(), request.Reason);
return Ok(new { message = "Shop closed successfully", shopId, status = shop.Status.Name });
}
catch (DomainException ex)
{
if (ex.Message.Contains("not found"))
return NotFound(new { message = ex.Message });
return BadRequest(new { message = ex.Message });
}
}
private Guid GetAdminId()
{
var userIdClaim = User.FindFirst("sub")?.Value
?? User.FindFirst("http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier")?.Value;
return Guid.TryParse(userIdClaim, out var userId) ? userId : Guid.Empty;
}
}