diff --git a/apps/web-client-tpos-net/src/WebClientTpos.Client/Pages/Admin/Shop/ShopSchedule.razor b/apps/web-client-tpos-net/src/WebClientTpos.Client/Pages/Admin/Shop/ShopSchedule.razor
index b24ef791..366dccae 100644
--- a/apps/web-client-tpos-net/src/WebClientTpos.Client/Pages/Admin/Shop/ShopSchedule.razor
+++ b/apps/web-client-tpos-net/src/WebClientTpos.Client/Pages/Admin/Shop/ShopSchedule.razor
@@ -108,7 +108,10 @@ else if (SubSection == "shifts")
@@ -148,7 +151,8 @@ else if (SubSection == "shifts")
@foreach (var emp in _staff)
{
- | @(emp.EmployeeCode ?? emp.Id.ToString()[..8]) |
+ @{ var empName = !string.IsNullOrWhiteSpace(emp.LastName) || !string.IsNullOrWhiteSpace(emp.FirstName) ? $"{emp.LastName} {emp.FirstName}".Trim() : (emp.EmployeeCode ?? emp.Id.ToString()[..8]); }
+ @empName |
@foreach (var dow in new[] { 1, 2, 3, 4, 5, 6, 0 })
{
var sched = _staffSchedules.FirstOrDefault(s => s.StaffId == emp.Id && s.DayOfWeek == dow);
diff --git a/apps/web-client-tpos-net/src/WebClientTpos.Server/Controllers/StaffController.cs b/apps/web-client-tpos-net/src/WebClientTpos.Server/Controllers/StaffController.cs
index ba3c19cd..27513716 100644
--- a/apps/web-client-tpos-net/src/WebClientTpos.Server/Controllers/StaffController.cs
+++ b/apps/web-client-tpos-net/src/WebClientTpos.Server/Controllers/StaffController.cs
@@ -154,7 +154,7 @@ public class StaffController : ControllerBase
public Task GetStaffSchedules([FromQuery] Guid? shopId = null)
{
var qs = shopId.HasValue ? $"?shopId={shopId}" : "";
- return _booking.GetAsync($"/api/v1/schedules{qs}").ProxyAsync();
+ return _booking.GetAsync($"/api/v1.0/schedules{qs}").ProxyAsync();
}
///
@@ -163,7 +163,7 @@ public class StaffController : ControllerBase
///
[HttpPost("staff/schedules")]
public Task CreateSchedule([FromBody] JsonElement body) =>
- _booking.PostAsJsonAsync("/api/v1/schedules", body).ProxyAsync();
+ _booking.PostAsJsonAsync("/api/v1.0/schedules", body).ProxyAsync();
///
/// EN: Update a staff schedule — proxies to BookingService.
@@ -171,7 +171,7 @@ public class StaffController : ControllerBase
///
[HttpPut("staff/schedules/{scheduleId:guid}")]
public Task UpdateSchedule(Guid scheduleId, [FromBody] JsonElement body) =>
- _booking.PutAsJsonAsync($"/api/v1/schedules/{scheduleId}", body).ProxyAsync();
+ _booking.PutAsJsonAsync($"/api/v1.0/schedules/{scheduleId}", body).ProxyAsync();
///
/// EN: Delete a staff schedule — proxies to BookingService.
@@ -179,5 +179,5 @@ public class StaffController : ControllerBase
///
[HttpDelete("staff/schedules/{scheduleId:guid}")]
public Task DeleteSchedule(Guid scheduleId) =>
- _booking.DeleteAsync($"/api/v1/schedules/{scheduleId}").ProxyAsync();
+ _booking.DeleteAsync($"/api/v1.0/schedules/{scheduleId}").ProxyAsync();
}
diff --git a/services/booking-service-net/src/BookingService.API/Controllers/SchedulesController.cs b/services/booking-service-net/src/BookingService.API/Controllers/SchedulesController.cs
index 27af32d2..44b74962 100644
--- a/services/booking-service-net/src/BookingService.API/Controllers/SchedulesController.cs
+++ b/services/booking-service-net/src/BookingService.API/Controllers/SchedulesController.cs
@@ -5,6 +5,8 @@ using Asp.Versioning;
using BookingService.API.Application.DTOs;
using BookingService.API.Application.Queries;
using BookingService.API.Models.Responses;
+using BookingService.Domain.AggregatesModel.StaffAggregate;
+using BookingService.Infrastructure.Repositories;
using MediatR;
using Microsoft.AspNetCore.Mvc;
@@ -17,11 +19,13 @@ namespace BookingService.API.Controllers;
public class SchedulesController : ControllerBase
{
private readonly IMediator _mediator;
+ private readonly IStaffScheduleRepository _scheduleRepository;
private readonly ILogger _logger;
- public SchedulesController(IMediator mediator, ILogger logger)
+ public SchedulesController(IMediator mediator, IStaffScheduleRepository scheduleRepository, ILogger logger)
{
_mediator = mediator ?? throw new ArgumentNullException(nameof(mediator));
+ _scheduleRepository = scheduleRepository ?? throw new ArgumentNullException(nameof(scheduleRepository));
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
}
@@ -44,4 +48,69 @@ public class SchedulesController : ControllerBase
return Ok(ApiResponse>.Ok(result));
}
+
+ ///
+ /// EN: Create a single schedule entry.
+ /// VI: Tạo một entry lịch làm việc.
+ ///
+ [HttpPost]
+ [ProducesResponseType(typeof(ApiResponse), StatusCodes.Status201Created)]
+ [ProducesResponseType(StatusCodes.Status400BadRequest)]
+ public async Task>> CreateSchedule(
+ [FromBody] CreateScheduleRequest request,
+ CancellationToken cancellationToken = default)
+ {
+ if (request.ShopId == Guid.Empty || request.StaffId == Guid.Empty)
+ return BadRequest(ApiResponse.Fail("ShopId and StaffId are required"));
+
+ if (!TimeOnly.TryParse(request.StartTime, out var startTime) ||
+ !TimeOnly.TryParse(request.EndTime, out var endTime))
+ return BadRequest(ApiResponse.Fail("Invalid time format. Use HH:mm"));
+
+ var schedule = new StaffSchedule(request.StaffId, request.ShopId, request.DayOfWeek, startTime, endTime);
+ _scheduleRepository.Add(schedule);
+ await _scheduleRepository.UnitOfWork.SaveEntitiesAsync(cancellationToken);
+
+ _logger.LogInformation("Schedule created: {Id} for staff {StaffId}", schedule.Id, request.StaffId);
+
+ var dto = new StaffScheduleDto
+ {
+ Id = schedule.Id,
+ StaffId = schedule.StaffId,
+ ShopId = schedule.ShopId,
+ DayOfWeek = schedule.DayOfWeek,
+ StartTime = schedule.StartTime,
+ EndTime = schedule.EndTime
+ };
+ return Created($"/api/v1/schedules/{schedule.Id}", ApiResponse.Ok(dto));
+ }
+
+ ///
+ /// EN: Delete a schedule entry by ID.
+ /// VI: Xóa một entry lịch làm việc theo ID.
+ ///
+ [HttpDelete("{id:guid}")]
+ [ProducesResponseType(StatusCodes.Status200OK)]
+ [ProducesResponseType(StatusCodes.Status404NotFound)]
+ public async Task DeleteSchedule(Guid id, CancellationToken cancellationToken = default)
+ {
+ var schedule = await _scheduleRepository.GetByIdAsync(id, cancellationToken);
+ if (schedule == null)
+ return NotFound(ApiResponse