diff --git a/controllers/WarehouseController.php b/controllers/WarehouseController.php index d41a153..83385e0 100644 --- a/controllers/WarehouseController.php +++ b/controllers/WarehouseController.php @@ -8,6 +8,7 @@ class WarehouseController extends Controller private Workshop $workshopModel; private Employee $employeeModel; private Product $productModel; + private WorkshopAssignment $assignmentModel; private ?array $visibleWarehouseIds = null; private const WAREHOUSE_TYPE_KEYWORDS = [ 'finished' => ['thành phẩm', 'thanh pham'], @@ -26,6 +27,7 @@ public function __construct() $this->workshopModel = new Workshop(); $this->employeeModel = new Employee(); $this->productModel = new Product(); + $this->assignmentModel = new WorkshopAssignment(); } public function index(): void @@ -562,6 +564,10 @@ private function getAccessibleWorkshops(): array if (!$employeeId) { return []; } + $managedIds = $this->assignmentModel->getWorkshopsManagedBy($employeeId); + if ($this->hasStorageWorkshop($managedIds)) { + return $this->workshopModel->all(200); + } $workshopIds = $this->employeeModel->getWorkshopIdsForEmployee($employeeId); return $this->workshopModel->findByIds($workshopIds); } @@ -620,7 +626,8 @@ private function resolveWarehouseIdsByWorkshop(array $user): ?array return []; } - if ($this->hasStorageWorkshop($workshopIds)) { + $managedIds = $this->assignmentModel->getWorkshopsManagedBy($employeeId); + if ($this->hasStorageWorkshop($managedIds)) { return null; } diff --git a/controllers/Warehouse_sheetController.php b/controllers/Warehouse_sheetController.php index 1ed1197..cc4b28b 100644 --- a/controllers/Warehouse_sheetController.php +++ b/controllers/Warehouse_sheetController.php @@ -12,6 +12,7 @@ class Warehouse_sheetController extends Controller private Warehouse $warehouseModel; private Workshop $workshopModel; private Employee $employeeModel; + private WorkshopAssignment $assignmentModel; private array $warehouseCache = []; private ?array $accessibleWarehouseIds = null; @@ -36,7 +37,7 @@ class Warehouse_sheetController extends Controller public function __construct() { - $this->authorize(['VT_NHANVIEN_KHO', 'VT_KHO_TRUONG']); + $this->authorize(array_merge(['VT_NHANVIEN_KHO', 'VT_KHO_TRUONG'], $this->getWorkshopManagerRoles())); $this->sheetModel = new InventorySheet(); $this->lotModel = new InventoryLot(); $this->sheetDetailModel = new InventorySheetDetail(); @@ -44,6 +45,7 @@ public function __construct() $this->warehouseModel = new Warehouse(); $this->workshopModel = new Workshop(); $this->employeeModel = new Employee(); + $this->assignmentModel = new WorkshopAssignment(); } public function index(): void @@ -1248,9 +1250,37 @@ private function resolveWarehouseIdsByWorkshop(array $user): ?array return []; } + $managedIds = $this->assignmentModel->getWorkshopsManagedBy($employeeId); + if ($this->hasStorageWorkshop($managedIds)) { + return null; + } + return $this->warehouseModel->getWarehouseIdsByWorkshops($workshopIds); } + private function hasStorageWorkshop(array $workshopIds): bool + { + foreach ($workshopIds as $workshopId) { + $workshop = $this->workshopModel->find($workshopId); + $type = mb_strtolower((string) ($workshop['LoaiXuong'] ?? '')); + if (str_contains($type, 'lưu trữ')) { + return true; + } + } + + return false; + } + + private function getWorkshopManagerRoles(): array + { + return [ + 'VT_TRUONG_XUONG_KIEM_DINH', + 'VT_TRUONG_XUONG_LAP_RAP_DONG_GOI', + 'VT_TRUONG_XUONG_SAN_XUAT', + 'VT_TRUONG_XUONG_LUU_TRU', + ]; + } + private function classifyDocumentType(string $documentType): array { $normalized = $this->normalizeText($documentType); diff --git a/controllers/WorkshopController.php b/controllers/WorkshopController.php index e4cd672..291df59 100644 --- a/controllers/WorkshopController.php +++ b/controllers/WorkshopController.php @@ -9,6 +9,7 @@ class WorkshopController extends Controller private Employee $employeeModel; private WorkshopAssignment $assignmentModel; private Warehouse $warehouseModel; + private WorkShift $workShiftModel; public function __construct() { @@ -20,6 +21,7 @@ public function __construct() $this->employeeModel = new Employee(); $this->assignmentModel = new WorkshopAssignment(); $this->warehouseModel = new Warehouse(); + $this->workShiftModel = new WorkShift(); } public function index(): void @@ -118,6 +120,10 @@ public function store(): void $assignments['warehouse'], $assignments['production'], ); + if ($this->isStorageWorkshopType($data['LoaiXuong'] ?? null)) { + $this->warehouseModel->createDefaultWarehousesForWorkshop($data, $data['XUONGTRUONG_IdNhanVien'] ?? null); + $this->workShiftModel->ensureFixedShiftsForDate(date('Y-m-d')); + } $this->setFlash('success', 'Đã thêm xưởng sản xuất mới.'); } catch (Throwable $exception) { Logger::error('Lỗi khi thêm xưởng: ' . $exception->getMessage()); @@ -1109,4 +1115,13 @@ private function getWorkshopManagerRoles(): array 'VT_TRUONG_XUONG_LUU_TRU', ]; } + + private function isStorageWorkshopType(?string $workshopType): bool + { + if ($workshopType === null) { + return false; + } + + return mb_strtolower(trim($workshopType)) === 'xưởng lưu trữ hàng hóa'; + } } diff --git a/models/Employee.php b/models/Employee.php index ac79496..d4693d5 100644 --- a/models/Employee.php +++ b/models/Employee.php @@ -70,16 +70,18 @@ public function getWorkshopIdsForEmployee(?string $employeeId): array } $sql = 'SELECT DISTINCT IdXuong FROM ( - SELECT idXuong AS IdXuong FROM nhan_vien WHERE IdNhanVien = :employee + SELECT idXuong AS IdXuong FROM nhan_vien WHERE IdNhanVien = ? UNION ALL - SELECT IdXuong FROM xuong_nhan_vien WHERE IdNhanVien = :employee + SELECT IdXuong FROM xuong_nhan_vien WHERE IdNhanVien = ? UNION ALL - SELECT IdXuong FROM xuong WHERE XUONGTRUONG_IdNhanVien = :employee + SELECT IdXuong FROM xuong WHERE XUONGTRUONG_IdNhanVien = ? ) AS workshop_ids WHERE IdXuong IS NOT NULL AND IdXuong <> ""'; $stmt = $this->db->prepare($sql); - $stmt->bindValue(':employee', $employeeId); + $stmt->bindValue(1, $employeeId); + $stmt->bindValue(2, $employeeId); + $stmt->bindValue(3, $employeeId); $stmt->execute(); return array_values(array_unique($stmt->fetchAll(PDO::FETCH_COLUMN) ?: [])); @@ -93,18 +95,20 @@ public function isEmployeeInWorkshop(?string $employeeId, ?string $workshopId): $sql = 'SELECT 1 FROM ( - SELECT idXuong AS IdXuong FROM nhan_vien WHERE IdNhanVien = :employee + SELECT idXuong AS IdXuong FROM nhan_vien WHERE IdNhanVien = ? UNION ALL - SELECT IdXuong FROM xuong_nhan_vien WHERE IdNhanVien = :employee + SELECT IdXuong FROM xuong_nhan_vien WHERE IdNhanVien = ? UNION ALL - SELECT IdXuong FROM xuong WHERE XUONGTRUONG_IdNhanVien = :employee + SELECT IdXuong FROM xuong WHERE XUONGTRUONG_IdNhanVien = ? ) AS workshop_ids - WHERE IdXuong = :workshop + WHERE IdXuong = ? LIMIT 1'; $stmt = $this->db->prepare($sql); - $stmt->bindValue(':employee', $employeeId); - $stmt->bindValue(':workshop', $workshopId); + $stmt->bindValue(1, $employeeId); + $stmt->bindValue(2, $employeeId); + $stmt->bindValue(3, $employeeId); + $stmt->bindValue(4, $workshopId); $stmt->execute(); return (bool) $stmt->fetchColumn(); diff --git a/models/Warehouse.php b/models/Warehouse.php index 90c06ab..63abc20 100644 --- a/models/Warehouse.php +++ b/models/Warehouse.php @@ -393,6 +393,55 @@ public function generateWarehouseId(): string return 'KHO' . date('YmdHis'); } + public function hasWarehousesForWorkshop(string $workshopId): bool + { + $stmt = $this->db->prepare('SELECT 1 FROM KHO WHERE IdXuong = :workshopId LIMIT 1'); + $stmt->bindValue(':workshopId', $workshopId); + $stmt->execute(); + + return (bool) $stmt->fetchColumn(); + } + + public function createDefaultWarehousesForWorkshop(array $workshop, ?string $managerId = null): array + { + $workshopId = $workshop['IdXuong'] ?? null; + if (!$workshopId) { + return []; + } + + if ($this->hasWarehousesForWorkshop($workshopId)) { + return []; + } + + $workshopName = $workshop['TenXuong'] ?? $workshopId; + $location = $workshop['DiaDiem'] ?? null; + $managerId = $managerId ?? ($workshop['XUONGTRUONG_IdNhanVien'] ?? null); + + $created = []; + foreach (self::WAREHOUSE_TYPES as $label) { + $payload = [ + 'IdKho' => uniqid('KHO'), + 'TenKho' => trim($label . ' - ' . $workshopName), + 'TenLoaiKho' => $label, + 'DiaChi' => $location, + 'TongSLLo' => 0, + 'ThanhTien' => 0, + 'TrangThai' => 'Đang sử dụng', + 'TongSL' => 0, + 'IdXuong' => $workshopId, + 'NHAN_VIEN_KHO_IdNhanVien' => $managerId, + ]; + + if (!$this->createWarehouse($payload)) { + throw new RuntimeException('Không thể tạo kho mặc định cho xưởng ' . $workshopId); + } + + $created[] = $payload['IdKho']; + } + + return $created; + } + public function adjustWarehouseStock(string $warehouseId, int $quantityDelta = 0, int $lotDelta = 0): bool { $sql = 'UPDATE KHO diff --git a/views/warehouse/index.php b/views/warehouse/index.php index af5b415..de8123c 100644 --- a/views/warehouse/index.php +++ b/views/warehouse/index.php @@ -35,6 +35,38 @@ ?> -
-
-

Quản lý kho

-

Theo dõi kho nguyên liệu, thành phẩm và kho xử lý lỗi cùng phiếu nhập tương ứng.

+
+
+
+
+
Trung tâm điều phối kho
+

Tổng quan hệ thống kho

+

Theo dõi sức chứa, giá trị tồn, phiếu nhập xuất và trạng thái vận hành của từng nhóm kho.

+
+ +
- Thêm kho mới -
- -
-
+ +
-
-
-
-
-
-
-
- - - -
- $typeSummary): ?> - $typeSummary['label'] ?? '', 'description' => '', 'warehouses' => [], 'statistics' => $typeSummary]; ?> - - - -
-
-
+ + + +
+ $typeSummary): ?> + $typeSummary['label'] ?? '', 'description' => '', 'warehouses' => [], 'statistics' => $typeSummary]; ?> + + + +
+
-
+
+
-

+
@@ -199,24 +301,24 @@
-
-
-
Số kho
-
-
Đang hoạt động:
+
+
+
Số kho
+
+
Đang hoạt động:
-
-
Giá trị tồn
-
đ
-
Sức chứa:
+
+
Giá trị tồn
+
đ
+
Sức chứa:
-
-
Tổng lô
-
+
+
Tổng lô
+
-
-
Tổng lượng
-
+
+
Tổng lượng
+
@@ -226,10 +328,9 @@
-
- -
- + +
+ $group): ?> @@ -240,8 +341,8 @@
-
-
+
+

@@ -262,12 +363,33 @@
+
+
+
Số kho
+
+
Hoạt động:
+
+
+
Giá trị tồn
+
đ
+
Sức chứa:
+
+
+
Tổng lô
+
+
+
+
Tổng lượng
+
+
+
+
Chưa có kho nào thuộc nhóm "". Vui lòng thêm kho mới để bắt đầu quản lý.
-
+
@@ -317,6 +439,9 @@ % +
+ +
@@ -521,6 +646,7 @@ +