feat(booking-service): add shop-wide staff schedules endpoint

Add GET /api/v1/schedules?shopId= to return all staff schedules
for a shop. Existing per-staff endpoint unchanged. BFF needs this
to display all schedules on the admin dashboard.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Ho Ngoc Hai
2026-03-04 10:36:43 +07:00
parent 9b44e88a6a
commit 4cd172bee5
5 changed files with 101 additions and 0 deletions

View File

@@ -0,0 +1,11 @@
// EN: Query to get all staff schedules for a shop.
// VI: Query lấy tất cả lịch làm việc nhân viên cho một shop.
using BookingService.API.Application.DTOs;
using MediatR;
namespace BookingService.API.Application.Queries;
public record GetSchedulesByShopQuery(
Guid ShopId
) : IRequest<List<StaffScheduleDto>>;

View File

@@ -0,0 +1,33 @@
// EN: Handler for GetSchedulesByShopQuery.
// VI: Handler cho GetSchedulesByShopQuery.
using BookingService.API.Application.DTOs;
using BookingService.Infrastructure.Repositories;
using MediatR;
namespace BookingService.API.Application.Queries;
public class GetSchedulesByShopQueryHandler : IRequestHandler<GetSchedulesByShopQuery, List<StaffScheduleDto>>
{
private readonly IStaffScheduleRepository _staffScheduleRepository;
public GetSchedulesByShopQueryHandler(IStaffScheduleRepository staffScheduleRepository)
{
_staffScheduleRepository = staffScheduleRepository ?? throw new ArgumentNullException(nameof(staffScheduleRepository));
}
public async Task<List<StaffScheduleDto>> Handle(GetSchedulesByShopQuery request, CancellationToken cancellationToken)
{
var schedules = await _staffScheduleRepository.GetByShopIdAsync(request.ShopId, cancellationToken);
return schedules.Select(s => new StaffScheduleDto
{
Id = s.Id,
StaffId = s.StaffId,
ShopId = s.ShopId,
DayOfWeek = s.DayOfWeek,
StartTime = s.StartTime,
EndTime = s.EndTime
}).ToList();
}
}

View File

@@ -0,0 +1,47 @@
// EN: Schedules Controller - Shop-wide staff schedule queries.
// VI: Controller Schedules - Truy vấn lịch làm việc nhân viên theo shop.
using Asp.Versioning;
using BookingService.API.Application.DTOs;
using BookingService.API.Application.Queries;
using BookingService.API.Models.Responses;
using MediatR;
using Microsoft.AspNetCore.Mvc;
namespace BookingService.API.Controllers;
[ApiController]
[ApiVersion("1.0")]
[Route("api/v{version:apiVersion}/schedules")]
[Produces("application/json")]
public class SchedulesController : ControllerBase
{
private readonly IMediator _mediator;
private readonly ILogger<SchedulesController> _logger;
public SchedulesController(IMediator mediator, ILogger<SchedulesController> logger)
{
_mediator = mediator ?? throw new ArgumentNullException(nameof(mediator));
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
}
/// <summary>
/// EN: Get all staff schedules for a shop.
/// VI: Lấy tất cả lịch làm việc nhân viên cho một shop.
/// </summary>
[HttpGet]
[ProducesResponseType(typeof(ApiResponse<List<StaffScheduleDto>>), StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
public async Task<ActionResult<ApiResponse<List<StaffScheduleDto>>>> GetSchedulesByShop(
[FromQuery] Guid shopId,
CancellationToken cancellationToken = default)
{
if (shopId == Guid.Empty)
return BadRequest(ApiResponse<List<StaffScheduleDto>>.Fail("Shop ID is required"));
var query = new GetSchedulesByShopQuery(shopId);
var result = await _mediator.Send(query, cancellationToken);
return Ok(ApiResponse<List<StaffScheduleDto>>.Ok(result));
}
}

View File

@@ -14,4 +14,5 @@ public interface IStaffScheduleRepository
void Remove(StaffSchedule schedule);
Task<List<StaffSchedule>> GetByStaffIdAsync(Guid staffId, Guid shopId, CancellationToken cancellationToken = default);
Task<List<StaffSchedule>> GetByShopIdAndDayAsync(Guid shopId, int dayOfWeek, CancellationToken cancellationToken = default);
Task<List<StaffSchedule>> GetByShopIdAsync(Guid shopId, CancellationToken cancellationToken = default);
}

View File

@@ -46,4 +46,13 @@ public class StaffScheduleRepository : IStaffScheduleRepository
.Where(s => s.ShopId == shopId && s.DayOfWeek == dayOfWeek)
.ToListAsync(cancellationToken);
}
public async Task<List<StaffSchedule>> GetByShopIdAsync(Guid shopId, CancellationToken cancellationToken = default)
{
return await _context.StaffSchedules
.Where(s => s.ShopId == shopId)
.OrderBy(s => s.StaffId)
.ThenBy(s => s.DayOfWeek)
.ToListAsync(cancellationToken);
}
}