diff --git a/apps/web-client-tpos-net/src/WebClientTpos.Client/Pages/Admin/Shop/ShopPage.razor b/apps/web-client-tpos-net/src/WebClientTpos.Client/Pages/Admin/Shop/ShopPage.razor index 7e4bda8f..c346c32e 100644 --- a/apps/web-client-tpos-net/src/WebClientTpos.Client/Pages/Admin/Shop/ShopPage.razor +++ b/apps/web-client-tpos-net/src/WebClientTpos.Client/Pages/Admin/Shop/ShopPage.razor @@ -1257,8 +1257,8 @@
-
-
+
+
@@ -1322,14 +1322,15 @@
Nguyên liệu
- @foreach (var (ing, idx) in _recipeIngredients.Select((x,i) => (x,i))) + @for (var idx = 0; idx < _recipeIngredients.Count; idx++) { + var i = idx;
- - - - - + + + + +
}
@@ -2503,4 +2504,234 @@ await DataService.DeleteMemberAsync(memberId); _members = await DataService.GetMembersAsync(); } + + // ═══ TABLE CRUD ═══ + private void EditTable(PosDataService.TableInfo table) + { + _editingTableId = table.Id; + _newTableNumber = table.TableNumber; + _newTableCapacity = table.Capacity; + _newTableZone = table.Zone ?? ""; + _tableFormMessage = null; + _showTableForm = true; + } + + private async Task AddTable() + { + _tableFormMessage = null; + if (string.IsNullOrWhiteSpace(_newTableNumber) || !_shopGuid.HasValue) + { + _tableFormMessage = "Vui lòng nhập số bàn."; _tableFormSuccess = false; return; + } + try + { + await DataService.CreateTableAsync(new PosDataService.CreateTableRequest(_shopGuid.Value, _newTableNumber, _newTableCapacity, _newTableZone)); + _tableFormMessage = $"Đã thêm bàn '{_newTableNumber}' thành công!"; _tableFormSuccess = true; + _newTableNumber = ""; _newTableCapacity = 4; _newTableZone = ""; + if (_shopGuid.HasValue) _tables = await DataService.GetTablesAsync(_shopGuid.Value); + } + catch (Exception ex) { _tableFormMessage = $"Lỗi: {ex.Message}"; _tableFormSuccess = false; } + } + + private async Task SaveTable() + { + _tableFormMessage = null; + if (string.IsNullOrWhiteSpace(_newTableNumber) || !_shopGuid.HasValue || !_editingTableId.HasValue) + { + _tableFormMessage = "Vui lòng nhập số bàn."; _tableFormSuccess = false; return; + } + try + { + await DataService.UpdateTableAsync(_editingTableId.Value, new PosDataService.CreateTableRequest(_shopGuid.Value, _newTableNumber, _newTableCapacity, _newTableZone)); + _tableFormMessage = $"Đã cập nhật bàn '{_newTableNumber}' thành công!"; _tableFormSuccess = true; + _editingTableId = null; + if (_shopGuid.HasValue) _tables = await DataService.GetTablesAsync(_shopGuid.Value); + } + catch (Exception ex) { _tableFormMessage = $"Lỗi: {ex.Message}"; _tableFormSuccess = false; } + } + + private async Task DeleteTableItem(Guid id) + { + try + { + await DataService.DeleteTableAsync(id); + if (_shopGuid.HasValue) _tables = await DataService.GetTablesAsync(_shopGuid.Value); + } + catch (Exception ex) { _errorMessage = $"Không thể xóa bàn: {ex.Message}"; } + } + + // ═══ APPOINTMENT CRUD ═══ + private async Task AddAppointment() + { + _apptFormMessage = null; + if (!_shopGuid.HasValue) + { + _apptFormMessage = "Thiếu thông tin cửa hàng."; _apptFormSuccess = false; return; + } + try + { + await DataService.CreateAppointmentAsync(new PosDataService.CreateAppointmentRequest( + _shopGuid.Value, null, null, null, null, _newApptStart, _newApptEnd)); + _apptFormMessage = "Đã thêm lịch hẹn thành công!"; _apptFormSuccess = true; + _showApptForm = false; + _appointments = await DataService.GetAppointmentsAsync(_shopGuid.Value); + } + catch (Exception ex) { _apptFormMessage = $"Lỗi: {ex.Message}"; _apptFormSuccess = false; } + } + + private async Task CancelAppt(Guid apptId) + { + try + { + await DataService.CancelAppointmentAsync(apptId); + if (_shopGuid.HasValue) _appointments = await DataService.GetAppointmentsAsync(_shopGuid.Value); + } + catch (Exception ex) { _errorMessage = $"Không thể hủy lịch hẹn: {ex.Message}"; } + } + + // ═══ RESOURCE CRUD ═══ + private void EditResource(PosDataService.ResourceInfo r) + { + _editingResourceId = r.Id; + _newResourceName = r.Name; + _newResourceType = r.ResourceType ?? "Room"; + _newResourceCapacity = r.Capacity; + _resourceFormMessage = null; + _showResourceForm = true; + } + + private async Task AddResource() + { + _resourceFormMessage = null; + if (string.IsNullOrWhiteSpace(_newResourceName) || !_shopGuid.HasValue) + { + _resourceFormMessage = "Vui lòng nhập tên tài nguyên."; _resourceFormSuccess = false; return; + } + try + { + await DataService.CreateResourceAsync(new PosDataService.CreateResourceRequest(_shopGuid.Value, _newResourceName, _newResourceType, _newResourceCapacity)); + _resourceFormMessage = $"Đã thêm '{_newResourceName}' thành công!"; _resourceFormSuccess = true; + _newResourceName = ""; _newResourceType = "Room"; _newResourceCapacity = 1; + _resources = await DataService.GetResourcesAsync(_shopGuid.Value); + } + catch (Exception ex) { _resourceFormMessage = $"Lỗi: {ex.Message}"; _resourceFormSuccess = false; } + } + + private async Task SaveResource() + { + _resourceFormMessage = null; + if (string.IsNullOrWhiteSpace(_newResourceName) || !_shopGuid.HasValue || !_editingResourceId.HasValue) + { + _resourceFormMessage = "Vui lòng nhập tên tài nguyên."; _resourceFormSuccess = false; return; + } + try + { + await DataService.UpdateResourceAsync(_editingResourceId.Value, new PosDataService.CreateResourceRequest(_shopGuid.Value, _newResourceName, _newResourceType, _newResourceCapacity)); + _resourceFormMessage = $"Đã cập nhật '{_newResourceName}' thành công!"; _resourceFormSuccess = true; + _editingResourceId = null; + _resources = await DataService.GetResourcesAsync(_shopGuid.Value); + } + catch (Exception ex) { _resourceFormMessage = $"Lỗi: {ex.Message}"; _resourceFormSuccess = false; } + } + + private async Task DeleteResourceItem(Guid id) + { + try + { + await DataService.DeleteResourceAsync(id); + if (_shopGuid.HasValue) _resources = await DataService.GetResourcesAsync(_shopGuid.Value); + } + catch (Exception ex) { _errorMessage = $"Không thể xóa tài nguyên: {ex.Message}"; } + } + + // ═══ SCHEDULE CRUD ═══ + private async Task AddSchedule() + { + _schedFormMessage = null; + if (!Guid.TryParse(_newSchedStaffIdStr, out var staffId) || !_shopGuid.HasValue) + { + _schedFormMessage = "Vui lòng nhập đúng Staff ID."; _schedFormSuccess = false; return; + } + try + { + _newSchedStaffId = staffId; + await DataService.CreateScheduleAsync(new PosDataService.CreateScheduleRequest(_shopGuid.Value, _newSchedStaffId, _newSchedDay, _newSchedStart, _newSchedEnd)); + _schedFormMessage = "Đã thêm lịch làm việc thành công!"; _schedFormSuccess = true; + _showScheduleForm = false; + _staffSchedules = await DataService.GetStaffSchedulesAsync(_shopGuid); + } + catch (Exception ex) { _schedFormMessage = $"Lỗi: {ex.Message}"; _schedFormSuccess = false; } + } + + private async Task DeleteScheduleItem(Guid id) + { + try + { + await DataService.DeleteScheduleAsync(id); + _staffSchedules = await DataService.GetStaffSchedulesAsync(_shopGuid); + } + catch (Exception ex) { _errorMessage = $"Không thể xóa lịch làm việc: {ex.Message}"; } + } + + // ═══ KITCHEN ═══ + private async Task LoadKitchenTickets(string status) + { + _kitchenStatusFilter = status; + try + { + if (_shopGuid.HasValue) + _kitchenTickets = await DataService.GetKitchenTicketsAsync(_shopGuid, status); + } + catch (Exception ex) { _errorMessage = $"Không thể tải kitchen tickets: {ex.Message}"; } + StateHasChanged(); + } + + private async Task MarkTicketDone(Guid ticketId) + { + try + { + await DataService.UpdateTicketStatusAsync(ticketId, new PosDataService.UpdateTicketStatusRequest("completed")); + if (_shopGuid.HasValue) + _kitchenTickets = await DataService.GetKitchenTicketsAsync(_shopGuid, _kitchenStatusFilter); + } + catch (Exception ex) { _errorMessage = $"Không thể cập nhật trạng thái: {ex.Message}"; } + StateHasChanged(); + } + + // ═══ RECIPE CRUD ═══ + private async Task SaveRecipe() + { + _recipeFormMessage = null; + if (string.IsNullOrWhiteSpace(_newRecipeName) || !_shopGuid.HasValue) + { + _recipeFormMessage = "Vui lòng nhập tên công thức."; _recipeFormSuccess = false; return; + } + try + { + var ingredients = _recipeIngredients + .Where(i => !string.IsNullOrWhiteSpace(i.Name)) + .Select(i => new PosDataService.RecipeIngredientRequest(i.Name, i.Quantity, i.Unit, i.Cost)) + .ToList(); + var req = new PosDataService.CreateRecipeRequest(_shopGuid.Value, Guid.Empty, _newRecipeName, _newRecipeInstructions, _newRecipePrepTime, ingredients); + bool ok; + if (_editingRecipeId.HasValue) + ok = await DataService.UpdateRecipeAsync(_editingRecipeId.Value, req); + else + ok = await DataService.CreateRecipeAsync(req); + _recipeFormMessage = ok ? (_editingRecipeId.HasValue ? "Đã cập nhật công thức!" : "Đã thêm công thức!") : "Lỗi khi lưu công thức."; + _recipeFormSuccess = ok; + if (ok) { _showRecipeForm = false; _editingRecipeId = null; _recipes = await DataService.GetRecipesAsync(_shopGuid); } + } + catch (Exception ex) { _recipeFormMessage = $"Lỗi: {ex.Message}"; _recipeFormSuccess = false; } + } + + private async Task DeleteRecipeItem(Guid id) + { + try + { + await DataService.DeleteRecipeAsync(id); + _recipes = await DataService.GetRecipesAsync(_shopGuid); + } + catch (Exception ex) { _errorMessage = $"Không thể xóa công thức: {ex.Message}"; } + } } diff --git a/apps/web-client-tpos-net/src/WebClientTpos.Server/Controllers/BffDataController.cs b/apps/web-client-tpos-net/src/WebClientTpos.Server/Controllers/BffDataController.cs index 9c0f56d1..c81c442f 100644 --- a/apps/web-client-tpos-net/src/WebClientTpos.Server/Controllers/BffDataController.cs +++ b/apps/web-client-tpos-net/src/WebClientTpos.Server/Controllers/BffDataController.cs @@ -1689,8 +1689,8 @@ public class BffDataController : ControllerBase if (merchantId == null) return Ok(Array.Empty()); var myShopIds = await GetMyShopIdsAsync(merchantId.Value); if (!myShopIds.Any()) return Ok(Array.Empty()); - if (shopId.HasValue && !myShopIds.Contains(shopId.Value)) return Ok(Array.Empty()); - var targetShopIds = shopId.HasValue ? new List { shopId.Value } : myShopIds; + if (!myShopIds.Contains(shopId)) return Ok(Array.Empty()); + var targetShopIds = new List { shopId }; try { await using var conn = new NpgsqlConnection(ConnStr("fnb_engine")); @@ -1733,8 +1733,8 @@ public class BffDataController : ControllerBase if (merchantId == null) return Ok(Array.Empty()); var myShopIds = await GetMyShopIdsAsync(merchantId.Value); if (!myShopIds.Any()) return Ok(Array.Empty()); - if (shopId.HasValue && !myShopIds.Contains(shopId.Value)) return Ok(Array.Empty()); - var targetShopIds = shopId.HasValue ? new List { shopId.Value } : myShopIds; + if (!myShopIds.Contains(shopId)) return Ok(Array.Empty()); + var targetShopIds = new List { shopId }; try { await using var conn = new NpgsqlConnection(ConnStr("catalog_service"));