Panduan Lengkap Setup Farmasi Multi-Gudang & Floor Stock di SIMRS
T
Kembali ke Blog

Panduan Lengkap Setup Farmasi Multi-Gudang & Floor Stock di SIMRS

Industri Kesehatan
Tim Pilar Inovasi 09 Jul 2026 8 min baca 1,779 kata 1
Kelola inventori farmasi rumah sakit Anda secara efisien dengan panduan setup multi-gudang dan floor stock di SIMRS. Artikel ini membahas konsep, implementasi teknis, contoh kode, hingga best practices untuk akurasi stok dan layanan pasien optimal.

Manajemen farmasi di rumah sakit modern adalah salah satu tulang punggung operasional yang paling kompleks. Bayangkan tantangan mengelola ribuan jenis obat, alat kesehatan, dan bahan habis pakai di berbagai lokasi: mulai dari gudang sentral, apotek rawat jalan, apotek rawat inap, hingga stok darurat di unit-unit perawatan. Tanpa sistem yang terintegrasi dan terstruktur, risiko kesalahan fatal seperti stok kosong di saat kritis, penumpukan obat kadaluarsa, atau ketidaksesuaian data stok fisik dengan sistem menjadi sangat tinggi. Menurut data Kemenkes, kerugian akibat inefisiensi manajemen logistik farmasi bisa mencapai 15% dari total anggaran obat. Artikel ini akan memandu Anda secara mendalam tentang cara mengimplementasikan sistem farmasi multi-gudang dan floor stock (stok lantai) di Sistem Informasi Manajemen Rumah Sakit (SIMRS) Anda. Kami akan mengupas tuntas mulai dari konsep dasar, arsitektur teknis, contoh kode yang bisa dijalankan, hingga praktik terbaik untuk memastikan akurasi inventori, efisiensi operasional, dan yang terpenting, keselamatan pasien.

Konsep Dasar Farmasi Multi-Gudang dan Floor Stock

Sistem farmasi multi-gudang mengacu pada pengelolaan inventori obat dan alat kesehatan yang tersebar di beberapa lokasi fisik dalam satu entitas rumah sakit. Lokasi-lokasi ini biasanya mencakup Gudang Farmasi Utama (pusat distribusi), Apotek Rawat Jalan, Apotek Rawat Inap, dan gudang-gudang satelit di unit-unit khusus seperti Ruang Operasi (OK), Instalasi Gawat Darurat (IGD), atau Intensive Care Unit (ICU). Setiap gudang memiliki fungsi spesifik dan mengelola jenis serta jumlah item yang berbeda, namun semuanya terhubung secara logis dalam SIMRS untuk visibilitas stok yang komprehensif.

Floor stock, atau stok lantai, adalah sub-kategori dari multi-gudang yang merujuk pada persediaan obat dan alat kesehatan yang ditempatkan langsung di unit perawatan pasien (misalnya bangsal, poliklinik, atau IGD) untuk penggunaan segera. Tujuannya adalah mempercepat akses obat bagi pasien, terutama dalam situasi gawat darurat, dan mengurangi waktu tunggu. Floor stock biasanya memiliki jumlah item yang terbatas, seringkali obat-obatan fast-moving atau life-saving, dan dikelola dengan mekanisme pengisian ulang otomatis atau permintaan rutin dari gudang farmasi utama.

Manfaat utama implementasi multi-gudang dan floor stock adalah peningkatan efisiensi operasional yang signifikan. Pertama, mengurangi waktu tunggu pasien untuk mendapatkan obat, yang krusial untuk kasus gawat darurat. Kedua, optimalisasi pengelolaan stok dengan mengurangi risiko stok kosong (stock-out) di unit-unit vital dan meminimalkan penumpukan stok yang berpotensi kadaluarsa. Ketiga, akurasi data inventori meningkat secara drastis karena setiap mutasi tercatat secara real-time. Keempat, kepatuhan terhadap regulasi seperti PMK No. 72 Tahun 2016 tentang Standar Pelayanan Kefarmasian di Rumah Sakit menjadi lebih mudah dipantau dan dipenuhi.

Sebagai contoh, Gudang Farmasi Utama mungkin menyimpan 5.000-10.000 jenis item, sedangkan Apotek Rawat Jalan hanya menyimpan 1.500-2.000 item, dan floor stock di bangsal hanya sekitar 50-100 item obat esensial. Setiap transfer atau penggunaan dari floor stock harus tercatat dan memicu permintaan pengisian ulang otomatis ketika mencapai titik minimum yang telah ditentukan. SIMRS harus mampu memfasilitasi mutasi stok antar gudang, permintaan unit, penerimaan barang, penyesuaian stok, serta pelaporan stok yang akurat berdasarkan metode penilaian inventori seperti FIFO (First-In, First-Out) untuk memastikan obat dengan tanggal kadaluarsa terdekat digunakan lebih dahulu.

Detail Implementasi Teknis di SIMRS

Implementasi farmasi multi-gudang dan floor stock di SIMRS memerlukan arsitektur database yang solid dan modul aplikasi yang terintegrasi. Untuk backend, seringkali digunakan kerangka kerja seperti Laravel 11.x karena kemampuannya dalam membangun API RESTful yang efisien dan skalabel. Database relasional seperti PostgreSQL 16 adalah pilihan ideal berkat performa, fitur JSONB untuk data semi-terstruktur, dan dukungan transaksi yang kuat. Untuk kebutuhan caching atau antrian, Redis 7.x dapat diintegrasikan untuk mempercepat operasi yang sering diakses.

Struktur database inti akan melibatkan tabel-tabel seperti m_gudang (master gudang), m_item_farmasi (master item obat/alkes), t_stok_gudang (tabel stok per gudang), dan t_transaksi_stok (log mutasi stok). Tabel m_gudang akan menyimpan informasi setiap lokasi penyimpanan, termasuk jenis gudang (pusat, satelit, floor stock). m_item_farmasi akan berisi detail obat/alkes seperti kode KFA, nama, satuan, dan harga. Tabel t_stok_gudang adalah kunci untuk melacak kuantitas stok untuk setiap item di setiap gudang, seringkali dilengkapi dengan informasi batch number dan tanggal kadaluarsa. Sementara t_transaksi_stok mencatat setiap pergerakan item (penerimaan, pengeluaran, mutasi, penyesuaian) dengan timestamp dan user yang melakukan transaksi.

Modul manajemen stok dalam SIMRS harus memiliki fitur-fitur krusial. Pertama, fungsi mutasi antar gudang yang memungkinkan transfer item dari gudang utama ke apotek satelit atau pengisian floor stock. Kedua, modul permintaan unit yang memungkinkan bangsal atau unit perawatan mengajukan permintaan obat ke apotek. Ketiga, fungsi penerimaan barang dari supplier dan pengeluaran barang untuk pasien. Keempat, fitur penyesuaian stok untuk mengoreksi perbedaan antara stok fisik dan sistem. Kelima, pelaporan stok yang komprehensif, termasuk laporan mutasi, laporan kadaluarsa, dan laporan nilai persediaan.

Integrasi adalah aspek vital. SIMRS harus terintegrasi dengan modul EMR (Electronic Medical Record) agar resep dokter dapat langsung diteruskan ke farmasi. Integrasi dengan modul billing memastikan pencatatan biaya obat ke pasien. Untuk interoperabilitas eksternal, standar seperti FHIR R4 (Fast Healthcare Interoperability Resources) atau HL7 v2.5.1 sangat relevan. Misalnya, data stok dapat diekspos melalui API FHIR untuk pelaporan ke Kementerian Kesehatan melalui SatuSehat, atau melalui pesan HL7 via Mirth Connect 4.x atau HAPI FHIR 6.8 untuk pertukaran data dengan sistem lain. Seluruh proses ini harus dilindungi dengan sistem otorisasi berbasis peran (Role-Based Access Control) untuk memastikan hanya petugas yang berwenang yang dapat melakukan transaksi stok.

Contoh Kode Implementasi

Berikut adalah contoh skema database minimal menggunakan PostgreSQL 16 untuk mendukung manajemen farmasi multi-gudang dan floor stock. Skema ini mencakup tabel master untuk gudang dan item, serta tabel transaksi untuk stok dan mutasi.

-- Tabel Master Gudang (m_gudang)CREATE TABLE m_gudang (    id SERIAL PRIMARY KEY,    nama VARCHAR(100) NOT NULL UNIQUE,    jenis VARCHAR(50) NOT NULL, -- Contoh: 'Utama', 'Apotek Rawat Jalan', 'Floor Stock IGD'    alamat TEXT,    is_active BOOLEAN DEFAULT TRUE,    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP);-- Tabel Master Item Farmasi (m_item_farmasi)CREATE TABLE m_item_farmasi (    id SERIAL PRIMARY KEY,    kode VARCHAR(50) NOT NULL UNIQUE,    nama VARCHAR(255) NOT NULL,    satuan VARCHAR(50) NOT NULL,    harga_beli DECIMAL(15, 2) NOT NULL,    harga_jual DECIMAL(15, 2) NOT NULL,    min_stok INT DEFAULT 0,    max_stok INT DEFAULT 0,    is_active BOOLEAN DEFAULT TRUE,    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP);-- Tabel Stok per Gudang (t_stok_gudang)CREATE TABLE t_stok_gudang (    id SERIAL PRIMARY KEY,    gudang_id INT NOT NULL REFERENCES m_gudang(id) ON DELETE RESTRICT,    item_id INT NOT NULL REFERENCES m_item_farmasi(id) ON DELETE RESTRICT,    batch_number VARCHAR(100),    tanggal_kadaluarsa DATE,    jumlah INT NOT NULL DEFAULT 0,    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,    UNIQUE (gudang_id, item_id, batch_number));-- Tabel Transaksi Mutasi Stok (t_transaksi_stok)CREATE TABLE t_transaksi_stok (    id SERIAL PRIMARY KEY,    nomor_transaksi VARCHAR(100) NOT NULL UNIQUE,    tipe_transaksi VARCHAR(50) NOT NULL, -- Contoh: 'Penerimaan', 'Pengeluaran', 'Mutasi Keluar', 'Mutasi Masuk', 'Penyesuaian'    gudang_id_asal INT REFERENCES m_gudang(id) ON DELETE RESTRICT, -- Nullable jika bukan mutasi    gudang_id_tujuan INT REFERENCES m_gudang(id) ON DELETE RESTRICT, -- Nullable jika bukan mutasi    item_id INT NOT NULL REFERENCES m_item_farmasi(id) ON DELETE RESTRICT,    batch_number VARCHAR(100),    jumlah INT NOT NULL,    harga_satuan DECIMAL(15, 2),    total_harga DECIMAL(15, 2),    keterangan TEXT,    user_id INT, -- Referensi ke tabel user    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP);

Skema di atas menyediakan fondasi yang kuat. Tabel m_gudang mendefinisikan setiap lokasi. m_item_farmasi adalah daftar semua obat. t_stok_gudang menyimpan kuantitas stok spesifik untuk setiap kombinasi gudang, item, dan batch number, yang krusial untuk pelacakan kadaluarsa. t_transaksi_stok adalah audit trail lengkap untuk setiap pergerakan barang. Penting untuk menggunakan transaksi database (ACID) saat melakukan operasi stok untuk menjaga integritas data.

Berikut adalah contoh sederhana fungsi PHP (Laravel) untuk melakukan mutasi stok antar gudang. Fungsi ini harus dijalankan dalam sebuah transaksi database untuk memastikan konsistensi.

<?phpnamespace App\'Http\Controllers\Api;use App\Http\Controllers\Controller;use App\Models\MGudang;use App\Models\MItemFarmasi;use App\Models\TStokGudang;use App\Models\TTransaksiStok;use Illuminate\Http\Request;use Illuminate\Support\Facades\DB;use Illuminate\Validation\ValidationException;class FarmasiMutasiController extends Controller{    public function mutasiStok(Request $request)    {        $request->validate([            'gudang_asal_id' => 'required|exists:m_gudang,id',            'gudang_tujuan_id' => 'required|exists:m_gudang,id|different:gudang_asal_id',            'item_id' => 'required|exists:m_item_farmasi,id',            'batch_number' => 'required|string|max:100',            'jumlah' => 'required|integer|min:1',            'user_id' => 'required|exists:users,id', // Asumsi ada tabel users        ]);        $gudangAsalId = $request->input('gudang_asal_id');        $gudangTujuanId = $request->input('gudang_tujuan_id');        $itemId = $request->input('item_id');        $batchNumber = $request->input('batch_number');        $jumlah = $request->input('jumlah');        $userId = $request->input('user_id');        DB::beginTransaction();        try {            // Cek stok di gudang asal            $stokAsal = TStokGudang::where('gudang_id', $gudangAsalId)                ->where('item_id', $itemId)                ->where('batch_number', $batchNumber)                ->lockForUpdate() // Lock baris untuk mencegah race condition                ->first();            if (!$stokAsal || $stokAsal->jumlah < $jumlah) {                throw ValidationException::withMessages([                    'jumlah' => 'Stok tidak mencukupi di gudang asal atau batch tidak ditemukan.'                ]);            }            // Kurangi stok di gudang asal            $stokAsal->jumlah -= $jumlah;            $stokAsal->save();            // Tambah stok di gudang tujuan (atau buat baru jika belum ada)            $stokTujuan = TStokGudang::firstOrCreate(                [                    'gudang_id' => $gudangTujuanId,                    'item_id' => $itemId,                    'batch_number' => $batchNumber                ],                [                    'jumlah' => 0,                    'tanggal_kadaluarsa' => $stokAsal->tanggal_kadaluarsa // Ambil tgl kadaluarsa dari stok asal                ]            );            $stokTujuan->jumlah += $jumlah;            $stokTujuan->save();            // Catat transaksi mutasi keluar dari gudang asal            TTransaksiStok::create([                'nomor_transaksi' => 'MUT-K-'.time(),                'tipe_transaksi' => 'Mutasi Keluar',                'gudang_id_asal' => $gudangAsalId,                'item_id' => $itemId,                'batch_number' => $batchNumber,                'jumlah' => $jumlah,                'harga_satuan' => MItemFarmasi::find($itemId)->harga_beli,                'total_harga' => MItemFarmasi::find($itemId)->harga_beli * $jumlah,                'keterangan' => 'Mutasi ke gudang ' . MGudang::find($gudangTujuanId)->nama,                'user_id' => $userId            ]);            // Catat transaksi mutasi masuk ke gudang tujuan            TTransaksiStok::create([                'nomor_transaksi' => 'MUT-M-'.time(),                'tipe_transaksi' => 'Mutasi Masuk',                'gudang_id_tujuan' => $gudangTujuanId,                'item_id' => $itemId,                'batch_number' => $batchNumber,                'jumlah' => $jumlah,                'harga_satuan' => MItemFarmasi::find($itemId)->harga_beli,                'total_harga' => MItemFarmasi::find($itemId)->harga_beli * $jumlah,                'keterangan' => 'Mutasi dari gudang ' . MGudang::find($gudangAsalId)->nama,                'user_id' => $userId            ]);            DB::commit();            return response()->json(['message' => 'Mutasi stok berhasil.'], 200);        } catch (ValidationException $e) {            DB::rollBack();            return response()->json(['message' => $e->getMessage(), 'errors' => $e->errors()], 422);        } catch (\Exception $e) {            DB::rollBack();            // Log error: $e->getMessage()            return response()->json(['message' => 'Terjadi kesalahan server: ' . $e->getMessage()], 500);        }    }}

Kode PHP di atas menunjukkan bagaimana sebuah API untuk mutasi stok dapat diimplementasikan. Penting untuk melakukan validasi input, memeriksa ketersediaan stok di gudang asal, dan menggunakan `DB::transaction()` untuk memastikan semua operasi (pengurangan stok asal, penambahan stok tujuan, pencatatan log transaksi) berhasil atau gagal secara bersamaan. Penggunaan `lockForUpdate()` mencegah masalah konkurensi saat banyak pengguna mencoba memutasi stok yang sama secara bersamaan. Setiap mutasi akan menciptakan dua entri di `t_transaksi_stok`: satu untuk pengeluaran dari gudang asal dan satu untuk penerimaan di gudang tujuan, menjaga audit trail yang lengkap.

Contoh Payload dan Penanganan Error

Untuk melakukan mutasi stok antar gudang melalui API, payload JSON yang dikirimkan ke endpoint POST /api/v1/farmasi/mutasi akan terlihat seperti ini:

{    
Terakhir diperbarui 09 Jul 2026

Komentar

Komentar ditinjau sebelum tampil.

Belum ada komentar. Jadilah yang pertama!