Ringkasan Utama
Manufaktur mematahkan pola transaksional yang diikuti sebagian besar modul ERP, karena bill of materials bersifat rekursif: barang jadi dibangun dari sub-assembly yang juga dibangun dari komponen. MRP kemudian harus menguraikan pohon itu terhadap permintaan dan stok sebelum bisa menyarankan apa pun.
Sebagian besar modul ERP yang pernah saya bangun bersifat transaksional: sebuah invoice disetujui, permintaan cuti dirutekan, pembayaran dicatat. Manufaktur berbeda. Sifatnya rekursif, karena barang jadi dibangun dari sub-assembly, yang dibangun dari sub-assembly lain, yang dibangun dari bahan baku. Kesalahan pada model data di lapisan bill of materials tidak hanya merusak satu laporan nantinya, tetapi merusak setiap proses perencanaan, setiap roll-up biaya, dan setiap work order di hilir selama modul itu masih digunakan di produksi.
Tulisan ini membahas bagaimana saya mendesain modul bill of materials dan material requirements planning untuk sebuah produsen skala menengah, mencakup skema untuk BOM berjenjang, bagaimana work order mengonsumsi dan menghasilkan stok, bagaimana proses MRP mengubah prakiraan penjualan menjadi rencana pembelian dan produksi, dan mengapa backflushing saat penyelesaian biasanya menjadi pilihan yang lebih tepat dibanding pencatatan transaksi per pengeluaran barang.
Memodelkan Bill of Materials
Bill of materials adalah struktur parent-child yang rekursif: satu record item untuk parent, dan sekumpulan record baris BOM yang menunjuk ke item komponen, masing-masing dengan kuantitas per unit parent yang diproduksi. Jebakan yang paling sering dilakukan pembangun ERP pemula adalah mencoba meratakan struktur ini menjadi satu tabel dengan kolom tetap untuk komponen satu, komponen dua, dan seterusnya. Pendekatan itu langsung runtuh begitu sebuah produk memiliki lebih dari segelintir bahan, dan membuat eksplosi multi-level hampir mustahil untuk dikueri.
- Item master: satu baris per nomor part, baik itu bahan baku, sub-assembly buatan sendiri, atau barang jadi, ditandai dengan flag buat-atau-beli.
- Header BOM: menghubungkan item parent ke sebuah versi BOM, dengan rentang tanggal efektif-dari dan efektif-sampai agar perubahan engineering tidak menulis ulang riwayat secara retroaktif.
- Baris BOM: header BOM parent, item komponen, kuantitas per unit parent, satuan ukur, dan faktor scrap opsional untuk perkiraan kehilangan hasil produksi.
- Routing (opsional tapi disarankan): urutan operasi dan work center yang diperlukan untuk membangun parent, dipakai kemudian untuk perencanaan kapasitas dan costing tenaga kerja.
Dengan memisahkan header BOM dan baris BOM dari item master, dan memberi versi pada header berdasarkan tanggal efektif, kamu bisa menjawab pertanyaan tingkat perencanaan seperti berapa biaya membangun produk ini hari ini, sekaligus pertanyaan tingkat audit seperti apa yang sebenarnya dikonsumsi produk ini ketika work order ditutup enam bulan lalu.
Simpan kuantitas per sebagai desimal dengan setidaknya empat digit presisi. Membulatkan rasio komponen seperti 0,0625 kilogram per unit menjadi dua digit desimal akan berakumulasi menjadi selisih persediaan yang nyata begitu dikalikan sepanjang produksi sepuluh ribu unit.
BOM Single-Level vs Multi-Level Berjenjang
BOM single-level hanya mencantumkan anak langsung dari satu item parent. BOM berjenjang, atau multi-level, secara rekursif mengembangkan setiap sub-assembly hingga ke bahan baku, menunjukkan pohon lengkap dengan kuantitas yang dikalikan di setiap level. Kedua tampilan ini berasal dari tabel baris BOM yang sama; perbedaannya murni pada kuerinya.
| Tampilan | Yang ditunjukkan | Kegunaan utama |
|---|---|---|
| BOM single-level | Komponen langsung dari satu parent, satu level saja | Membeli sub-assembly tertentu, pengecekan biaya cepat |
| BOM multi-level berjenjang | Pohon rekursif lengkap, kuantitas dikalikan di setiap level | Tinjauan engineering, analisis where-used menyeluruh |
| Where-used (BOM terbalik) | Setiap parent yang mengonsumsi komponen tertentu, menyusuri ke atas | Analisis dampak sebelum menghentikan atau mengubah sebuah part |
Di PostgreSQL, common table expression rekursif adalah cara alami untuk menyusuri pohon ke arah mana pun. Menyusuri ke bawah dari barang jadi ke bahan baku, kamu menggabungkan baris BOM dengan dirinya sendiri di mana item parent sama dengan item komponen dari baris sebelumnya; untuk laporan where-used ke atas, kamu membalik arah join tersebut. Batasi kedalaman rekursi secara defensif, karena kesalahan input data yang membuat sebuah item menjadi komponen tidak langsung dari dirinya sendiri akan membuat kueri berjalan tanpa henti.
Work Order: Unit Produksi
Work order adalah record yang menghubungkan BOM dan routing ke sebuah proses produksi nyata: bangun sejumlah item ini, sebelum tanggal ini, mengonsumsi komponen-komponen ini. Record ini melewati state machine kecil seiring produksi berjalan.
- Planned: dibuat oleh MRP atau secara manual, belum ada stok yang bergerak, komponen hanya direservasi.
- Released: material dialokasikan, lantai produksi sudah diberi izin untuk mulai, stok komponen di-soft-commit.
- In progress: kuantitas parsial bisa dilaporkan selesai, konsumsi komponen parsial bisa dicatat.
- Closed: kuantitas final selesai, sisa konsumsi komponen diposting, varians dihitung dan dikembalikan ke persediaan jika konsumsi kurang dari rencana.
Setiap work order harus membawa snapshot dari baris BOM yang menjadi dasarnya, bukan pointer langsung ke BOM yang aktif saat ini. Jika engineering merevisi resep bulan depan, work order yang sedang berjalan harus tetap mengonsumsi resep yang berlaku saat dirilis, kalau tidak pelaporan varians biaya menjadi tidak berarti.
Jangan pernah membiarkan daftar komponen work order menunjuk langsung ke header BOM yang aktif. Snapshot baris BOM yang sudah diexplode ke tabel khusus work order pada saat order dirilis. Kalau tidak, perubahan engineering di tengah bulan akan diam-diam menulis ulang apa yang seharusnya dikonsumsi oleh produksi yang sudah berjalan separuh jalan.
Material Requirements Planning: Mengeksplosi Permintaan
MRP mengambil permintaan independen, sales order dan prakiraan untuk barang jadi, dan mengubahnya menjadi permintaan dependen untuk setiap komponen di bawahnya, digeser ke belakang dalam waktu sesuai lead time. Algoritma klasik, diformalkan oleh Joseph Orlicky pada tahun 1970-an, berjalan level demi level: untuk setiap item, hitung gross requirements, kurangi apa yang sudah tersedia di stok atau sudah dipesan untuk mendapatkan net requirements, dan jika net requirements positif, hasilkan planned order yang harus jatuh tempo pada tanggal kebutuhan lalu digeser lebih awal sesuai lead time item tersebut. Kemudian dorong kuantitas planned order itu ke bawah sebagai gross requirements untuk komponen-komponennya sendiri, dan ulangi.
function explodeMrp(item, requiredQty, dueDate, onHand) {
const gross = requiredQty
const available = onHand.get(item.sku) ?? 0
const net = Math.max(gross - available, 0)
if (net === 0) return []
const orderDate = subtractLeadTime(dueDate, item.leadTimeDays)
const workOrder = { sku: item.sku, qty: net, dueDate, orderDate }
const children = []
for (const line of item.bomLines) {
const childQty = net * line.qtyPer * (1 + line.scrapFactor)
children.push(
...explodeMrp(line.component, childQty, orderDate, onHand)
)
}
return [workOrder, ...children]
}Fungsi rekursif di bawah ini menggambarkan inti dari proses eksplosi tersebut. Dalam implementasi nyata kamu juga perlu memperhitungkan aturan lot sizing, karena memesan tepat sejumlah net requirement jarang praktis ketika pemasok memiliki kuantitas pesanan minimum atau kamu ingin mengelompokkan produksi dalam ukuran lot tetap, dan kamu perlu memisahkan item buat, yang menghasilkan work order, dari item beli, yang menghasilkan requisisi pembelian.
Requisisi Pembelian dan Planned Order
Output dari sebuah proses MRP adalah sekumpulan planned order, sebagian menjadi requisisi pembelian untuk item beli dan sebagian menjadi work order untuk item buat. Modul MRP yang didesain dengan baik tidak pernah menulis langsung ke purchase order atau work order yang firm; ia menghasilkan planned order yang ditinjau dan disahkan oleh seorang planner, karena sistem yang sepenuhnya otomatis menembakkan purchase order tanpa tinjauan manusia cenderung memesan berlebihan begitu prakiraan meleset.
- Sahkan planned order secara manual sebelum proses MRP berjalan sehingga algoritma memperlakukannya sebagai pasokan tetap dan tidak menyarankan duplikasi.
- Kelompokkan planned order menjadi requisisi berdasarkan vendor dan jendela pengiriman untuk mengurangi jumlah purchase order yang harus diproses seorang buyer.
- Tandai pengecualian seperti order yang seharusnya sudah dimulai di masa lalu, sehingga planner melihat daftar ekspedisi yang jelas alih-alih rencana yang diam-diam terlambat.
Pola manusia-dalam-lingkaran ini yang membedakan modul MRP yang benar-benar dipakai dari sekadar spreadsheet yang secara teknis melakukan perhitungan yang sama. Planner jauh lebih percaya pada sistem yang menampilkan pengecualian dan membiarkan mereka mengesahkan komitmen, dibanding sistem yang diam-diam mengikat modal atas nama mereka.
Perlakukan setiap proses MRP sebagai keluaran yang bersifat advisory, bukan transaksi. Menjalankan ulang MRP setiap malam harus aman dilakukan setiap hari tanpa efek samping, karena proses itu hanya menghasilkan ulang planned order dan tidak pernah menyentuh purchase order yang sudah firm atau work order yang sudah dirilis.
Backflushing: Mengonsumsi Stok saat Penyelesaian
Ada dua cara untuk mencatat konsumsi komponen terhadap sebuah work order. Forward flushing mengeluarkan setiap komponen ke work order saat secara fisik diambil dari gudang, memberikan visibilitas real-time atas persediaan di lantai produksi tetapi membutuhkan satu transaksi untuk setiap pengambilan. Backflushing sebaliknya menunggu sampai work order melaporkan kuantitas selesai, lalu secara otomatis menghitung dan memposting konsumsi komponen berdasarkan kuantitas per pada BOM, dikalikan dengan kuantitas yang selesai.
- Backflushing secara drastis mengurangi volume transaksi pada lini produksi berkecepatan tinggi di mana mengeluarkan setiap komponen secara manual akan menyumbat lantai produksi.
- Cara ini menukar visibilitas real-time atas work in process dengan kesederhanaan, yang merupakan trade-off yang tepat untuk manufaktur repetitif tetapi pilihan yang buruk untuk assembly bersiklus panjang dan bernilai tinggi di mana kamu ingin memantau work in process secara ketat.
- Backflushing tetap membutuhkan jalur override manual untuk scrap dan rework, kalau tidak konsumsi yang dihitung otomatis akan diam-diam mengecilkan apa yang sebenarnya dipakai lantai produksi.
Pola yang menyatukan semua ini adalah memperlakukan BOM sebagai satu-satunya sumber kebenaran untuk apa yang seharusnya dikonsumsi, work order sebagai record dari apa yang benar-benar dikonsumsi, dan MRP sebagai lapisan perencanaan yang mengubah permintaan yang diprakirakan menjadi rencana bertahap waktu terhadap keduanya. Pisahkan ketiga peran ini dengan bersih di skema kamu, dan fitur pelaporan, costing, serta perencanaan yang kamu bangun di atasnya akan tetap koheren bahkan ketika katalog produk bertumbuh menjadi ribuan part di puluhan level.

