Artikel ini memandu konfigurasi modul pembelian DOC dan pakan pada sistem ERP peternakan. Pelajari langkah-langkah praktis, integrasi data, dan optimalisasi rantai pasok untuk efisiensi operasional. Tingkatkan profitabilitas peternakan Anda dengan implementasi yang tepat.
Manajemen operasional peternakan, khususnya pada sektor unggas, menghadapi tantangan signifikan dalam mengelola biaya input utama: Day-Old Chick (DOC) dan pakan. Kedua komponen ini secara konsisten menyumbang 60-70% dari total biaya produksi, menjadikannya area krusial untuk optimalisasi. Tanpa sistem yang terintegrasi, peternakan seringkali bergulat dengan inefisiensi seperti pencatatan manual yang rentan kesalahan, penentuan harga yang tidak optimal akibat kurangnya data historis, risiko kelebihan atau kekurangan stok, serta kesulitan dalam melacak kualitas dan performa pemasok. Situasi ini tidak hanya menghambat pertumbuhan tetapi juga mengikis margin keuntungan yang sudah tipis. Sebuah sistem Enterprise Resource Planning (ERP) yang dirancang khusus untuk peternakan, dengan modul pembelian DOC dan pakan yang terkonfigurasi dengan baik, menjadi solusi esensial untuk mengatasi kompleksitas ini. Artikel ini akan memandu Anda secara mendalam melalui langkah-langkah konfigurasi modul tersebut, dari konsep dasar hingga implementasi teknis, termasuk contoh kode yang dapat dijalankan dan strategi penanganan error, memastikan peternakan Anda dapat mencapai efisiensi operasional dan profitabilitas yang lebih tinggi.
Modul pembelian DOC (Day-Old Chick) dan pakan dalam ERP peternakan berfungsi sebagai pusat kendali untuk semua aktivitas pengadaan input vital. DOC merupakan bibit ayam umur sehari yang akan dibesarkan, sementara pakan adalah sumber nutrisi utama. Keduanya memiliki karakteristik pengadaan yang unik. DOC memerlukan penanganan cepat, pengaturan jadwal pengiriman yang presisi, dan pemilihan strain yang sesuai dengan tujuan produksi (broiler atau layer), seringkali dengan kontrak jangka panjang. Pakan, di sisi lain, melibatkan variasi formulasi, kandungan nutrisi spesifik, manajemen tanggal kedaluwarsa, dan volume pembelian yang sangat besar, seringkali dalam satuan ton.
Pentingnya modul ini terletak pada kemampuannya untuk mengintegrasikan data dari berbagai tahapan rantai pasok. Bayangkan skenario tanpa modul ini: Divisi produksi mengajukan kebutuhan DOC dan pakan secara manual, tim pembelian mencari pemasok, mencatat harga di spreadsheet, dan tim gudang mencatat penerimaan fisik. Seluruh proses ini terpisah dan rawan kesalahan, seperti perbedaan data antara PO dan penerimaan barang, atau bahkan pembelian berlebih yang mengakibatkan pakan kedaluwarsa. Dengan modul terintegrasi, data permintaan dari modul produksi (berdasarkan target panen atau populasi ternak) langsung diteruskan ke modul pembelian, yang kemudian dapat membuat Purchase Requisition (PR) dan Purchase Order (PO) secara otomatis.
Komponen kunci dari modul ini meliputi: Database Pemasok yang komprehensif (nama, kontak, histori harga, performa), Master Data Item (jenis DOC, strain, berat rata-rata, jenis pakan, formulasi, kandungan nutrisi), Manajemen Permintaan Pembelian (PR), Manajemen Pesanan Pembelian (PO), Penerimaan Barang (Goods Receipt), dan Pencocokan Faktur (Invoice Matching). Setiap komponen ini saling terkait. Misalnya, Master Data Item pakan tidak hanya mencatat nama pakan, tetapi juga spesifikasi nutrisi seperti protein kasar minimal 18%, lemak minimal 5%, dan serat maksimal 7%, yang penting untuk kualitas dan performa ternak. Ketika PO dibuat, sistem secara otomatis menarik harga terakhir dari pemasok pilihan dan membandingkannya dengan harga kontrak atau harga pasar rata-rata, memberikan visibilitas penuh pada biaya yang akan dikeluarkan.
Contoh konkret, jika peternakan Anda membutuhkan 10.000 ekor DOC strain Lohmann Brown untuk periode produksi berikutnya dan 20 ton pakan starter, modul akan memfasilitasi pembuatan PR, pemilihan pemasok berdasarkan histori performa dan harga (misalnya, Supplier A menawarkan DOC dengan harga Rp 7.500/ekor dengan FCR rata-rata 1.6, sementara Supplier B Rp 7.300/ekor dengan FCR 1.7), lalu membuat PO yang akurat. Setelah DOC dan pakan diterima, proses Goods Receipt akan memperbarui inventori secara real-time. Estimasi biaya DOC dan pakan dapat mencapai 65% dari biaya operasional per periode, sehingga optimalisasi di area ini dapat meningkatkan profitabilitas hingga 5-10%.
Untuk mengimplementasikan modul pembelian DOC dan pakan, kita akan merujuk pada arsitektur ERP berbasis web menggunakan Laravel 11.x sebagai framework backend, PostgreSQL 16 sebagai database relasional, dan Vue.js 3 untuk antarmuka pengguna. Pendekatan ini menawarkan skalabilitas, keamanan, dan kemudahan pengembangan yang tinggi. Basis data PostgreSQL 16 sangat cocok untuk menangani volume data yang besar dan kompleksitas relasi antar tabel yang dibutuhkan dalam sistem ERP.
Desain skema database adalah langkah fundamental. Kita memerlukan beberapa tabel inti: suppliers, doc_types, feed_types, purchase_orders, purchase_order_items, dan inventory_transactions. Tabel suppliers akan menyimpan informasi detail pemasok seperti id, name, contact_person, phone, email, dan address. Tabel doc_types akan mencatat jenis-jenis DOC yang tersedia, seperti id, name (misalnya, Lohmann Brown, Cobb 500), strain_code, dan description. Demikian pula, feed_types akan berisi id, name (misalnya, Pakan Starter, Pakan Grower), formulation_code, protein_content, fat_content, dan expiry_days.
Tabel purchase_orders akan menjadi pusat transaksi pembelian, mencakup id, po_number (unique), supplier_id (foreign key ke suppliers.id), order_date, delivery_date, total_amount, status (e.g., 'Draft', 'Approved', 'Received', 'Cancelled'), dan user_id (pengguna yang membuat PO). Kunci utama dalam relasi ini adalah tabel purchase_order_items yang menyimpan detail setiap item dalam PO, dengan kolom seperti id, purchase_order_id (foreign key ke purchase_orders.id), item_type ('DOC' atau 'FEED'), item_id (polymorphic relation ke doc_types.id atau feed_types.id), quantity, unit_price, dan subtotal. Pendekatan polymorphic ini memungkinkan satu tabel item PO untuk mereferensikan berbagai jenis item.
Integrasi dengan modul lain sangat penting. Ketika status PO berubah menjadi 'Received', sistem harus secara otomatis memicu penambahan stok ke modul inventori melalui tabel inventory_transactions, mencatat transaction_type ('IN'), item_id, quantity, batch_number, dan expiry_date (khusus pakan). Selanjutnya, data PO juga akan diintegrasikan dengan modul keuangan untuk pencocokan faktur dan proses pembayaran. Untuk pengembangan, kita akan menggunakan PHP 8.2+ dan Composer 2.x untuk manajemen dependensi, memastikan kompatibilitas dan performa terbaik dengan Laravel 11.x.
Misalnya, saat menerima 10.000 ekor DOC dari PO #PO-00123, sistem akan mencatat 10.000 unit penambahan ke inventori DOC strain tertentu. Pada saat yang sama, untuk 20 ton pakan starter, sistem akan mencatat 20.000 kg penambahan stok, dengan nomor batch dan tanggal kedaluwarsa yang spesifik, misalnya 6 bulan dari tanggal produksi. Ini memastikan akurasi data inventori dan meminimalkan risiko kerugian akibat pakan kedaluwarsa atau salah hitung stok.
Berikut adalah contoh implementasi migrasi database dan logika controller untuk modul pembelian menggunakan Laravel 11.x, PHP 8.2+ dan PostgreSQL 16. Kode ini dirancang agar mudah dipahami dan dapat dijalankan.
<?php namespace DatabaseMigrations;use IlluminateDatabaseMigrationsMigration;use IlluminateDatabaseSchemaBlueprint;use IlluminateSupportFacadesSchema;return new class extends Migration{ public function up(): void { Schema::create('suppliers', function (Blueprint $table) { $table->id(); $table->string('name')->unique(); $table->string('contact_person')->nullable(); $table->string('phone')->nullable(); $table->string('email')->unique(); $table->text('address')->nullable(); $table->timestamps(); }); Schema::create('doc_types', function (Blueprint $table) { $table->id(); $table->string('name')->unique(); $table->string('strain_code')->unique(); $table->text('description')->nullable(); $table->timestamps(); }); Schema::create('feed_types', function (Blueprint $table) { $table->id(); $table->string('name')->unique(); $table->string('formulation_code')->unique(); $table->decimal('protein_content', 5, 2); // e.g., 18.50% $table->decimal('fat_content', 5, 2); // e.g., 5.00% $table->decimal('fiber_content', 5, 2); // e.g., 7.00% $table->integer('expiry_days')->default(180); // e.g., 180 days (6 months) $table->timestamps(); }); Schema::create('purchase_orders', function (Blueprint $table) { $table->id(); $table->string('po_number')->unique(); $table->foreignId('supplier_id')->constrained('suppliers'); $table->date('order_date'); $table->date('delivery_date')->nullable(); $table->decimal('total_amount', 15, 2)->default(0.00); $table->enum('status', ['Draft', 'Approved', 'Received', 'Cancelled', 'Completed'])->default('Draft'); $table->foreignId('user_id')->constrained('users'); // Assuming 'users' table exists $table->text('notes')->nullable(); $table->timestamps(); }); Schema::create('purchase_order_items', function (Blueprint $table) { $table->id(); $table->foreignId('purchase_order_id')->constrained('purchase_orders')->onDelete('cascade'); $table->enum('item_type', ['DOC', 'FEED']); $table->unsignedBigInteger('item_id'); // Polymorphic relation $table->string('item_name'); // Store name for easier reporting $table->integer('quantity'); $table->decimal('unit_price', 15, 2); $table->decimal('subtotal', 15, 2); $table->string('batch_number')->nullable(); // For feed/DOC batches $table->date('production_date')->nullable(); // For feed/DOC $table->date('expiry_date')->nullable(); // For feed $table->timestamps(); $table->index(['item_type', 'item_id']); // For polymorphic relation }); } public function down(): void { Schema::dropIfExists('purchase_order_items'); Schema::dropIfExists('purchase_orders'); Schema::dropIfExists('feed_types'); Schema::dropIfExists('doc_types'); Schema::dropIfExists('suppliers'); }};Kode migrasi di atas mendefinisikan struktur tabel yang diperlukan untuk modul pembelian. Tabel suppliers, doc_types, dan feed_types berfungsi sebagai master data. Tabel purchase_orders menyimpan detail pesanan pembelian secara keseluruhan, sementara purchase_order_items menyimpan item-item spesifik dalam setiap pesanan. Penggunaan enum('item_type', ['DOC', 'FEED']) dan unsignedBigInteger('item_id') adalah contoh implementasi relasi polimorfik yang memungkinkan satu tabel purchase_order_items mereferensikan baik doc_types maupun feed_types, menjaga fleksibilitas dan efisiensi database.
<?php namespace AppHttpControllers;use AppModelsPurchaseOrder;use AppModelsPurchaseOrderItem;use IlluminateHttpRequest;use IlluminateSupportFacadesValidator;use IlluminateSupportFacadesDB;use Exception;class PurchaseOrderController extends Controller{ public function store(Request $request) { $validator = Validator::make($request->all(), [ 'supplier_id' => 'required|exists:suppliers,id', 'order_date' => 'required|date', 'delivery_date' => 'nullable|date|after_or_equal:order_date', 'notes' => 'nullable|string|max:500', 'items' => 'required|array|min:1', 'items.*.item_type' => 'required|in:DOC,FEED', 'items.*.item_id' => 'required|integer', 'items.*.quantity' => 'required|integer|min:1', 'items.*.unit_price' => 'required|numeric|min:0', 'items.*.batch_number' => 'nullable|string|max:100', 'items.*.production_date' => 'nullable|date', 'items.*.expiry_date' => 'nullable|date|after_or_equal:production_date' ]); if ($validator->fails()) { return response()->json(['message' => 'Validation Error', 'errors' => $validator->errors()], 422); } DB::beginTransaction(); try { $poNumber = 'PO-' . date('Ymd') . '-' . str_pad(PurchaseOrder::count() + 1, 4, '0', STR_PAD_LEFT); $totalAmount = 0; foreach ($request->items as $item) { $totalAmount += $item['quantity'] * $item['unit_price']; } $purchaseOrder = PurchaseOrder::create([ 'po_number' => $poNumber, 'supplier_id' => $request->supplier_id, 'order_date' => $request->order_date, 'delivery_date' => $request->delivery_date, 'total_amount' => $totalAmount, 'status' => 'Draft', // Initial status 'user_id' => auth()->id(), // Get authenticated user ID ]); foreach ($request->items as $itemData) { PurchaseOrderItem::create([ 'purchase_order_id' => $purchaseOrder->id, 'item_type' => $itemData['item_type'], 'item_id' => $itemData['item_id'], 'item_name' => $this->getItemName($itemData['item_type'], $itemData['item_id']), // Helper function 'quantity' => $itemData['quantity'], 'unit_price' => $itemData['unit_price'], 'subtotal' => $itemData['quantity'] * $itemData['unit_price'], 'batch_number' => $itemData['batch_number'] ?? null, 'production_date' => $itemData['production_date'] ?? null, 'expiry_date' => $itemData['expiry_date'] ?? null ]); } DB::commit(); return response()->json(['message' => 'Purchase Order created successfully', 'data' => $purchaseOrder->load('items')], 201); } catch (Exception $e) { DB::rollBack(); return response()->json(['message' => 'Failed to create Purchase Order', 'error' => $e->getMessage()], 500); } } // Helper function to get item name (e.g., from DocType or FeedType models) private function getItemName(string $itemType, int $itemId): string { if ($itemType === 'DOC') { return
ew AppModelsDocType::find($itemId)->name ?? 'Unknown DOC'; } elseif ($itemType === 'FEED') { return
ew AppModelsFeedType::find($itemId)->name ?? 'Unknown Feed'; } return 'Unknown Item'; }}Controller PurchaseOrderController dengan method store menangani proses pembuatan PO baru. Ini mencakup validasi input menggunakan Laravel Validator, memastikan semua data yang diperlukan (supplier_id, items, quantity, unit_price) terpenuhi dan sesuai format. Penggunaan transaksi database (DB::beginTransaction() dan DB::commit()) sangat penting untuk menjaga integritas data; jika ada kegagalan saat menyimpan item PO, seluruh transaksi akan dibatalkan (DB::rollBack()). Nomor PO dihasilkan secara dinamis, dan total jumlah dihitung secara otomatis. Fungsi pembantu getItemName menunjukkan bagaimana nama item dapat diambil dari model DocType atau FeedType berdasarkan item_type dan item_id yang diberikan.
Integrasi data adalah tulang punggung efisiensi ERP. Untuk modul pembelian DOC dan pakan, integrasi tidak hanya terjadi antar modul internal (inventori, keuangan) tetapi juga dapat diperluas ke sistem eksternal seperti portal pemasok atau platform logistik. Proses ini umumnya dilakukan melalui API (Application Programming Interface), memungkinkan pertukaran data secara terstruktur dan aman. Mari kita lihat contoh payload JSON untuk membuat PO via API dan bagaimana menangani potensi kesalahan.
Berikut adalah contoh payload JSON realistis untuk membuat Purchase Order yang mencakup DOC dan pakan:
{ Belum ada komentar. Jadilah yang pertama!