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 FinishTransfer 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 ACT WO Header (2000) = MIN(2000, 2000, 2100) = 2000 (diambil yang paling sedikit dari semua bahan)
  • Bahan CPIB00337-01080B ada di 2 rak: AB1-2 (sisa 1000 pcs) dan AB1-3 (sisa 5000 pcs)
  • Semua bahan berasal dari gudang BWSUP dan dituju ke BPASY

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)

  1. Kalkulasi QTY ACT Header: qty_actual = MIN(detail.qty_actual / detail.bom_multiplier) untuk seluruh bahan.
  2. Auto-Finish WO: Jika semua detail bahan berstatus COMPLETED, header otomatis berstatus COMPLETED dan finish_time terisi.
  3. Integrasi API Infor:
    • Saat GET /details dipanggil, Service harus:
      • Hit API END STOCK → isi kolom end_stock
      • Hit API FIFO → isi kolom layout_info
    • Saat WO baru masuk, cek ms_bom lokal. Jika kosong untuk fg_pn tersebut, JIT sync dari Infor.

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