Estimasi Pengumpulan Bahan (BOM)
Konsep, pemodelan DB, alur picking gudang, dan integrasi API
Proyek Lanjutan: Estimasi Pengumpulan Bahan (BOM) oleh Gudang
Dokumen ini memuat konsep arsitektur, pemodelan basis data, alur sinkronisasi data Infor, serta panduan implementasi untuk fitur Estimasi Pengumpulan Bahan (BOM) oleh petugas gudang.
Referensi Mockup Excel
1. Pembagian Peran (PPC/PPIC vs Gudang)
| Peran | Tugas | Di Fitur Ini |
|---|---|---|
| PPC / PPIC (Production Planning & Inventory Control) | Perencana. Menganalisis pesanan pelanggan, memeriksa kapasitas mesin, merilis Work Order (WO) / Production Order ke sistem. | Menentukan produk jadi apa yang harus dibuat (Finished Goods, prefix F) dan berapa jumlahnya (QTY Plan). Data WO diambil dari API PRO Infor. |
| Petugas Gudang (Warehouse Picker) | Eksekutor lapangan. Mencari, mengumpulkan, dan memverifikasi bahan fisik di gudang. | Melihat daftar WO di dashboard → Klik Start → Mengumpulkan bahan BOM satu per satu → Mencatat QTY_ACT → Melaporkan masalah jika ada → Klik Finish → Transfer ke area Produksi. |
2. API Eksternal yang Dibutuhkan (dari Mockup)
Berdasarkan mockup, terdapat 6 sumber data/API yang diperlukan:
| No | Nama API | Fungsi | Status di Backend |
|---|---|---|---|
| 1 | API PRO | Mengambil daftar Production Order / Work Order yang masih OPEN dari Infor | ❌ Belum ada |
| 2 | API BOM | Mengambil daftar bahan (Bill of Materials) per produk jadi | ✅ Ada (GetDataBOMAsync → /Api/GetDataBOMMultiLevel) |
| 3 | API END STOCK WAREHOUSE | Mengambil sisa stok akhir bahan di gudang tertentu | ⚠️ Belum pasti (mungkin bisa pakai /Api/GetDataActualReceipt atau API baru) |
| 4 | API FIFO (LAYOUT) | Mengambil posisi rak/lokasi barang di gudang beserta jumlah per rak | ❌ Belum ada (API FIFO internal, spesifikasinya belum diketahui) |
| 5 | MASTER DATA | Data barang (ms_barang) untuk deskripsi Part Number |
✅ Ada di database lokal |
| 6 | API KARYAWAN | Data karyawan untuk identifikasi User Gudang (picker) | ✅ Ada (GetEmployeeAsync → /Api/GetDataEmployee) |
3. Analisis Mockup Excel — Komponen UI
A. Dashboard List Estimasi (Halaman Utama)
Tabel utama menampilkan daftar pesanan/WO yang masuk. Contoh data dari mockup:
| Kolom | Contoh Data | Sumber Data | Catatan |
|---|---|---|---|
| NO | 1 | Auto-increment UI | Nomor urut tampilan |
| JAM | 11.30 | Dari Infor (API PRO) | Jam masuk pesanan / WO dibuat |
| NO WO / PRO | BASY1234 | API PRO Infor | Nomor Production Order. Format BASYxxxx |
| PN | F1AA01045-TO065-E | API PRO Infor | Part Number produk jadi. Prefix F = Finished Goods |
| DESKRIPSI | TOYOTA YZZ… | ms_barang / Master Data |
Nama produk |
| QTY | 3000 | API PRO Infor | Target qty pesanan. “Dibatasi tidak boleh melebihi QTY yang ada di WO” |
| QTY ACT | 2000 | Kalkulasi Backend | = MIN(qty_actual semua bahan BOM). Awalnya kosong, terisi setelah semua bahan dikumpulkan |
| START | KLIK (11.40) | User action + timestamp | Tombol. Petugas gudang klik untuk mulai mengumpulkan bahan |
| FINISHED | KLIK (12.31) | Otomatis saat semua bahan selesai | Terisi saat semua detail bahan berstatus COMPLETED |
| PROD | KLIK (13.30) | User action | Tombol konfirmasi “siap produksi”. Bisa jadi trigger ke sistem produksi |
| TRANSFER | (placeholder) | Manual / otomatis nanti | Tombol transfer bahan dari Gudang (BWSUP) ke Produksi (BPASY). Untuk saat ini placeholder |
| KETERANGAN | - | Dari tr_wo_picking_log |
Keterangan masalah terbaru. Klik untuk lihat histori |
| USER GUDANG | - | Dari JWT / ms_karyawan |
NPK/Nama petugas yang klik Start |
Mode “PILIHAN”: Dari mockup ada selector ESTIMASI / LABEL — kemungkinan untuk memilih antara mode pengumpulan bahan (estimasi) atau pencetakan label barcode.
B. Detail BOM (Halaman Setelah Klik Start)
Setelah klik Start di dashboard, pengguna masuk ke halaman detail bahan BOM:
| Kolom | Contoh Data | Sumber Data | Catatan |
|---|---|---|---|
| NO | 4, 5, … | Auto-increment | Urutan bahan |
| PN | CPIB00337-01080B | API BOM | Part number bahan. Prefix menunjukkan jenis: CPIB = Inner Box, CPOB = Outer Box/Doos, RRPA = Raw Part/Material |
| DESKRIPSI | - | ms_barang / Master Data |
Nama bahan |
| QTY | 3000 | API BOM × QTY WO | = qty_target_WO × multiplier_BOM. Jika multiplier = 1, maka sama dengan target WO |
| END STOCK | 2000, 6000, 5000 | API END STOCK WAREHOUSE | Stok akhir bahan yang tersedia di gudang asal |
| QTY ACT | 2000, 2000, 2100 | Input petugas gudang | Jumlah riil yang berhasil dikumpulkan |
| LAYOUT | AB1-2 (1000); AB1-3 (5000) | API FIFO | Lokasi rak + jumlah per rak. Memandu picker ke mana harus mengambil |
| WH ASAL | BWSUP | API BOM / Master | Warehouse asal (gudang bahan baku) |
| WH TUJUAN | BPASY | API BOM / Master | Warehouse tujuan (area assembly/produksi) |
| START | KLIK (11.59) | User action + timestamp | Tombol per-bahan. Petugas yang klik = PIC bahan ini |
| FINISHED | KLIK (12.30) | User action + timestamp | Petugas klik setelah mengumpulkan bahan, input QTY ACT |
| KETERANGAN | TEMPEL STICKER | Input petugas | Catatan masalah per bahan. Bisa multiple entries (histori) |
Insight penting dari data contoh:
QTY ACTWO Header (2000) =MIN(2000, 2000, 2100)= 2000 (diambil yang paling sedikit dari semua bahan)- Bahan
CPIB00337-01080Bada di 2 rak: AB1-2 (sisa 1000 pcs) dan AB1-3 (sisa 5000 pcs) - Semua bahan berasal dari gudang
BWSUPdan dituju keBPASY
C. Halaman History (Riwayat Selesai)
Menampilkan WO yang sudah selesai dengan tambahan kolom:
| Kolom Tambahan | Contoh | Keterangan |
|---|---|---|
| SELISIH | 51 MENIT | Waktu total dari Start sampai Finished (durasi picking) |
| USER | 5909876 | NPK petugas gudang |
| NAMA | IVAN | Nama lengkap petugas |
History juga menampilkan sub-rows (1A, 1B, 1C, 1D) untuk setiap bahan yang dikumpulkan.
4. Strategi Sinkronisasi Data Infor
Sinkronisasi BOM
| Strategi | Penjelasan | Kapan |
|---|---|---|
| Batch Sync (Harian) | Backend worker menjalankan job terjadwal untuk menembak /Api/GetDataBOMMultiLevel secara berkala dan menyimpan ke tabel lokal ms_bom |
Setiap tengah malam |
| JIT Sync (Just-In-Time) | Saat WO baru masuk dan BOM produk tersebut belum ada di lokal, backend otomatis menembak API Infor untuk produk spesifik tersebut | Saat WO dibuka pertama kali |
Sinkronisasi Stok & Lokasi
| Data | Strategi | Alasan |
|---|---|---|
| End Stock | Real-time (hit API setiap halaman detail dibuka) | Stok berubah terus-menerus, cache berbahaya |
| Layout / FIFO | Real-time (hit API saat halaman detail dibuka) | Posisi barang di rak bisa berubah setiap saat |
| Production Order / WO | Real-time + Cache pendek (hit API PRO, cache 5-10 menit) | WO baru bisa masuk kapan saja, tapi tidak perlu per-detik |
5. Desain Database Baru (Fscm.DatabaseMigration)
Tabel yang sudah ada tidak cukup. ms_bom hanya menyimpan parent_pn, child_pn, qty (multiplier) — ini bagus untuk referensi BOM, tapi tidak ada tabel transaksional untuk merekam proses picking. Perlu 4 tabel baru:
A. tr_wo_picking (Header Work Order Picking)
CREATE TABLE [dbo].[tr_wo_picking](
[wo_id] VARCHAR(50) NOT NULL, -- No WO / No PRO (e.g., BASY1234)
[fg_pn] VARCHAR(100) NOT NULL, -- Part Number Finished Goods (e.g., F1AA01045-TO065-E)
[fg_desc] NVARCHAR(200) NULL, -- Deskripsi produk (cache dari master)
[qty_plan] INT NOT NULL, -- Target qty pesanan dari Infor
[qty_actual] INT NULL, -- MIN(qty_actual semua bahan), dihitung backend
[wo_received_at] DATETIME NULL, -- Jam pesanan masuk (dari Infor)
[status] VARCHAR(20) NOT NULL DEFAULT 'PENDING', -- PENDING / ON_PROGRESS / COMPLETED
[start_time] DATETIME NULL, -- Timestamp klik Start WO
[finish_time] DATETIME NULL, -- Timestamp semua bahan selesai
[prod_time] DATETIME NULL, -- Timestamp klik tombol PROD
[transfer_status] VARCHAR(20) DEFAULT 'PENDING',-- PENDING / TRANSFERRED
[picker_id] VARCHAR(50) NULL, -- User ID gudang yang klik Start WO
[picker_name] NVARCHAR(100) NULL, -- Nama petugas (cache)
[mode] VARCHAR(20) DEFAULT 'ESTIMASI', -- ESTIMASI / LABEL
[created_at] DATETIME DEFAULT GETDATE(),
PRIMARY KEY ([wo_id])
);
B. tr_wo_picking_detail (Detail Bahan per WO)
CREATE TABLE [dbo].[tr_wo_picking_detail](
[detail_id] INT IDENTITY(1,1) NOT NULL,
[wo_id] VARCHAR(50) NOT NULL, -- FK ke header
[child_pn] VARCHAR(100) NOT NULL, -- Part Number bahan (e.g., CPIB00337-01080B)
[child_desc] NVARCHAR(200) NULL, -- Deskripsi bahan (cache)
[bom_multiplier] DECIMAL(18,4) NOT NULL DEFAULT 1, -- Koefisien BOM (0.5, 1, 1.8, dll)
[qty_required] DECIMAL(18,4) NOT NULL, -- qty_plan × bom_multiplier
[end_stock] DECIMAL(18,4) NULL, -- Stok akhir gudang (dari API END STOCK)
[qty_actual] DECIMAL(18,4) NULL, -- Qty riil yang berhasil dikumpulkan
[layout_info] NVARCHAR(500) NULL, -- Lokasi rak dari API FIFO (e.g. "AB1-2 (1000); AB1-3 (5000)")
[wh_asal] VARCHAR(20) NOT NULL DEFAULT 'BWSUP',
[wh_tujuan] VARCHAR(20) NOT NULL DEFAULT 'BPASY',
[picker_id] VARCHAR(50) NULL, -- PIC gudang yang klik Start per bahan
[start_time] DATETIME NULL, -- Timestamp klik Start bahan
[finish_time] DATETIME NULL, -- Timestamp klik Finish bahan
[status] VARCHAR(20) NOT NULL DEFAULT 'PENDING', -- PENDING/ON_PROGRESS/COMPLETED/PROBLEM
PRIMARY KEY ([detail_id]),
FOREIGN KEY ([wo_id]) REFERENCES [tr_wo_picking]([wo_id])
);
C. tr_wo_picking_log (Histori Keterangan/Masalah per Bahan)
CREATE TABLE [dbo].[tr_wo_picking_log](
[log_id] INT IDENTITY(1,1) NOT NULL,
[detail_id] INT NOT NULL, -- FK ke detail bahan
[keterangan] NVARCHAR(MAX) NOT NULL, -- Isi masalah (e.g., "TEMPEL STICKER", "Stok kurang 1000")
[reported_by] VARCHAR(50) NOT NULL, -- NPK pelapor
[reported_at] DATETIME DEFAULT GETDATE(),
PRIMARY KEY ([log_id]),
FOREIGN KEY ([detail_id]) REFERENCES [tr_wo_picking_detail]([detail_id])
);
D. vw_wo_picking_history (View Riwayat Selesai)
CREATE VIEW [dbo].[vw_wo_picking_history] AS
SELECT
h.wo_id, h.wo_received_at, h.fg_pn, h.fg_desc, h.qty_plan, h.qty_actual,
h.start_time, h.finish_time,
DATEDIFF(MINUTE, h.start_time, h.finish_time) AS selisih_menit,
h.prod_time, h.picker_id, h.picker_name,
d.child_pn, d.qty_required, d.qty_actual AS detail_qty_actual,
d.start_time AS detail_start, d.finish_time AS detail_finish
FROM tr_wo_picking h
JOIN tr_wo_picking_detail d ON h.wo_id = d.wo_id
WHERE h.status = 'COMPLETED';
6. Pemodelan Backend (btb_backend)
A. Struktur File Baru
btb_backend/
├── Controllers/
│ └── WOPickingController.cs ← BARU
├── DTOs/
│ └── WOPicking/ ← BARU
│ ├── WOHeaderDto.cs
│ ├── WODetailDto.cs
│ ├── StartPickingRequestDto.cs
│ ├── FinishPickingRequestDto.cs
│ └── ReportProblemDto.cs
├── Services/
│ ├── Interfaces/IWOPickingService.cs ← BARU
│ └── Implementations/WOPickingService.cs ← BARU
├── Repositories/
│ ├── Interfaces/IWOPickingRepository.cs ← BARU
│ └── Implementations/WOPickingRepository.cs ← BARU
B. Endpoint API
| Method | Route | Fungsi |
|---|---|---|
GET |
/api/WOPicking |
Dashboard: daftar WO yang masuk (dengan filter status) |
POST |
/api/WOPicking/start |
Start WO: catat timestamp, user, ubah status ke ON_PROGRESS |
GET |
/api/WOPicking/{woId}/details |
Daftar bahan BOM + End Stock + Layout FIFO |
POST |
/api/WOPicking/detail/start |
Start picking per bahan: catat picker_id + timestamp |
POST |
/api/WOPicking/detail/finish |
Finish per bahan: input qty_actual + timestamp |
POST |
/api/WOPicking/detail/log |
Kirim keterangan/masalah per bahan |
GET |
/api/WOPicking/detail/{detailId}/logs |
Lihat histori keterangan per bahan |
POST |
/api/WOPicking/{woId}/prod |
Klik tombol PROD: catat prod_time |
GET |
/api/WOPicking/history |
Daftar WO yang sudah selesai (halaman History) |
POST |
/api/WOPicking/sync-bom/{fgPn} |
Manual trigger sinkronisasi BOM dari Infor untuk produk tertentu |
C. Logika Bisnis Utama (Service Layer)
- Kalkulasi QTY ACT Header:
qty_actual = MIN(detail.qty_actual / detail.bom_multiplier)untuk seluruh bahan. - Auto-Finish WO: Jika semua detail bahan berstatus COMPLETED, header otomatis berstatus COMPLETED dan
finish_timeterisi. - Integrasi API Infor:
- Saat
GET /detailsdipanggil, Service harus:- Hit API END STOCK → isi kolom
end_stock - Hit API FIFO → isi kolom
layout_info
- Hit API END STOCK → isi kolom
- Saat WO baru masuk, cek
ms_bomlokal. Jika kosong untukfg_pntersebut, JIT sync dari Infor.
- Saat
7. Pemodelan Frontend (fscm_frontend)
A. File Baru
src/component/page/
└── wo-picking/ ← BARU (folder)
├── Index.jsx ← Dashboard List Estimasi
├── Detail.jsx ← Detail BOM / Bahan per WO
└── History.jsx ← Riwayat WO yang sudah selesai
B. Registrasi Route (CreateRoute.jsx)
const WOPicking = lazy(() => import("../page/wo-picking/Index"));
const WOPickingDetail = lazy(() => import("../page/wo-picking/Detail"));
const WOPickingHistory = lazy(() => import("../page/wo-picking/History"));
// Tambahkan ke routeList:
{ path: "/wo_picking", element: <WOPicking />, title: "Estimasi Pengumpulan Bahan" },
{ path: "/wo_picking/:woId", element: <WOPickingDetail />, title: "Detail BOM" },
{ path: "/wo_picking_history", element: <WOPickingHistory />, title: "Riwayat Picking" },
C. Registrasi Menu Database (sso_msmenu)
INSERT INTO sso_msmenu (app_id, rol_id, men_parent_id, men_nama, men_link, men_urutan, men_status, men_icon)
VALUES
('APP01', 'ROL03', NULL, 'Estimasi BOM', 'wo_picking', 50, 'AKTIF', 'box'),
('APP01', 'ROL03', (SELECT men_id FROM sso_msmenu WHERE men_link='wo_picking' AND rol_id='ROL03'), 'List Estimasi', 'wo_picking', 1, 'AKTIF', 'list'),
('APP01', 'ROL03', (SELECT men_id FROM sso_msmenu WHERE men_link='wo_picking' AND rol_id='ROL03'), 'Riwayat Picking', 'wo_picking_history', 2, 'AKTIF', 'clock');
8. Catatan Tambahan — Prefix Part Number
Dari mockup, setiap Part Number memiliki prefix yang bermakna:
| Prefix | Contoh | Arti |
|---|---|---|
F |
F1AA01045-TO065-E | Finished Goods — Produk jadi |
CPIB |
CPIB00337-01080B | Inner Box — Kemasan dalam |
CPOB |
CPOB18936-00375B | Outer Box / Doos — Kemasan luar |
RRPA |
RRPA04331-00000B | Raw Part — Bahan baku/material mentah |
WK, WP |
WK…, WP… | Work in Progress — Barang setengah jadi |
Semua item ini berada di satu tabel yang sama (ms_barang), dibedakan hanya oleh huruf prefix pada kolom brg_id.
9. Hal yang Masih Perlu Diklarifikasi
| No | Pertanyaan | Dampak |
|---|---|---|
| 1 | Spesifikasi API PRO Infor — endpoint dan format response untuk mengambil daftar WO/Production Order yang masih open | Menentukan bagaimana data WO masuk ke sistem |
| 2 | Spesifikasi API END STOCK WAREHOUSE — apakah sudah ada di Infor atau perlu request ke tim pusat? | Menentukan kolom End Stock bisa diisi atau tidak |
| 3 | Spesifikasi API FIFO — endpoint, format response, dan apakah bisa mengurangi stok rak secara otomatis | Menentukan apakah layout bisa interaktif |
| 4 | Mekanisme Transfer — apakah saat ini sudah ada API/SP untuk transfer material antar warehouse di Infor? | Menentukan apakah tombol Transfer bisa aktif atau placeholder |
| 5 | Mode LABEL — apa yang terjadi di mode Label? Cetak barcode? Print packing list? | Menentukan apakah butuh halaman tambahan untuk mode ini |