Panduan Lengkap Setup Farmasi Multi-Gudang & Floor Stock di SIMRS Anda
N
Back to Blog

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

Industri Kesehatan
Nugroho Setiawan 31 Jul 2026 8 min baca 1,689 kata 3 views
Kelola obat secara efisien di berbagai lokasi rumah sakit dengan panduan setup farmasi multi-gudang dan floor stock di SIMRS. Artikel ini membahas arsitektur, implementasi teknis, dan best practices untuk optimalisasi rantai pasok farmasi.

Manajemen farmasi di rumah sakit modern bukan lagi sekadar pencatatan stok di satu lokasi pusat. Dengan kompleksitas operasional, mulai dari apotek rawat jalan, apotek rawat inap, hingga unit gawat darurat (UGD) dan ruang perawatan, tantangan dalam memastikan ketersediaan obat yang tepat di tempat yang tepat pada waktu yang tepat menjadi krusial. Sistem informasi manajemen rumah sakit (SIMRS) yang tidak mendukung konfigurasi multi-gudang dan floor stock seringkali menjadi biang keladi inefisiensi. Data menunjukkan, rumah sakit yang masih mengandalkan sistem manual atau single-gudang dapat mengalami kerugian hingga 15-20% dari nilai inventori akibat kadaluwarsa, stockout, atau inefisiensi distribusi. Hal ini tidak hanya berdampak pada keuangan, tetapi juga pada kualitas pelayanan dan keselamatan pasien. Artikel ini akan memandu Anda secara mendalam, langkah demi langkah, tentang bagaimana mengimplementasikan dan mengoptimalkan farmasi multi-gudang serta floor stock dalam SIMRS Anda, menggunakan pendekatan teknis yang konkret dan best practices yang terbukti.

Konsep Dasar Farmasi Multi-Gudang dan Floor Stock

Sebelum melangkah ke implementasi teknis, penting untuk memahami perbedaan fundamental dan tujuan dari konsep farmasi multi-gudang dan floor stock. Farmasi multi-gudang merujuk pada pembagian inventori obat di beberapa lokasi fisik yang memiliki identitas dan pengelolaan stoknya sendiri dalam SIMRS. Contohnya meliputi Gudang Pusat Farmasi (main warehouse), Apotek Rawat Jalan, Apotek Rawat Inap, Gudang Logistik Medik, atau bahkan unit khusus seperti Gudang ICU atau Gudang Radiologi. Setiap gudang ini memiliki siklus pengadaan, penyimpanan, dan distribusi tersendiri, namun tetap terintegrasi dalam satu sistem untuk visibilitas stok menyeluruh.

Sementara itu, floor stock adalah kategori khusus dari inventori yang disimpan langsung di unit perawatan atau nursing station (misalnya, di Ruang Rawat Inap A, B, atau UGD) untuk kebutuhan mendesak dan penggunaan segera oleh perawat. Karakteristik floor stock adalah jumlahnya yang terbatas, jenis obat esensial yang umum digunakan, dan mekanisme replenishment yang cepat. Tujuannya adalah mempercepat akses obat saat dibutuhkan, mengurangi waktu tunggu pasien, dan meminimalkan pergerakan perawat ke apotek utama untuk obat-obatan rutin. Regulasi seperti Peraturan Menteri Kesehatan (PMK) No. 72 Tahun 2016 tentang Standar Pelayanan Kefarmasian di Rumah Sakit secara implisit mendorong pengelolaan stok yang terdesentralisasi namun terkontrol untuk meningkatkan efisiensi dan keselamatan.

Manfaat utama dari penerapan kedua konsep ini sangat signifikan. Pertama, peningkatan efisiensi operasional. Dengan obat tersedia lebih dekat ke titik penggunaan, waktu respons medis dapat dipercepat secara dramatis. Kedua, optimasi inventori. SIMRS dapat memberikan visibilitas real-time untuk setiap lokasi gudang dan floor stock, memungkinkan analisis pergerakan stok yang lebih akurat, pengurangan stok mati, dan pencegahan kadaluwarsa. Ketiga, peningkatan akuntabilitas dan auditabilitas. Setiap transfer, penerimaan, dan pengeluaran obat tercatat dengan jelas pada gudang atau floor stock yang spesifik, mempermudah proses audit internal maupun eksternal. Keempat, kepatuhan regulasi. Sistem yang terstruktur membantu rumah sakit memenuhi standar akreditasi dan regulasi terkait manajemen obat yang ketat. Tanpa sistem yang memadai, risiko kesalahan medikasi dan kerugian finansial akibat stok yang tidak terkontrol akan meningkat secara eksponen.

Meskipun manfaatnya besar, implementasi multi-gudang dan floor stock juga memiliki tantangan. Integrasi data antar gudang, sinkronisasi stok secara real-time, pencegahan duplikasi data, dan rekonsiliasi stok fisik versus sistem adalah beberapa di antaranya. Oleh karena itu, diperlukan perancangan sistem yang matang dan pemanfaatan teknologi yang tepat untuk mengatasi tantangan ini. SIMRS harus dirancang untuk tidak hanya mencatat transaksi, tetapi juga menyediakan laporan analitis yang membantu pengambilan keputusan strategis terkait rantai pasok farmasi.

Arsitektur dan Implementasi Teknis di SIMRS

Implementasi farmasi multi-gudang dan floor stock dalam SIMRS memerlukan modifikasi pada struktur database yang ada serta pengembangan modul baru. Pada dasarnya, kita perlu menambahkan entitas untuk merepresentasikan lokasi gudang dan mengaitkan setiap transaksi stok dengan gudang yang relevan. Kami merekomendasikan penggunaan PostgreSQL versi 16 ke atas sebagai database utama karena keandalannya, fitur JSONB untuk data fleksibel, dan dukungan performa yang baik untuk data transaksional yang besar.

Untuk backend, kami sering menggunakan framework seperti Laravel versi 11.x yang menawarkan ORM Eloquent yang kuat dan API RESTful yang mudah dikembangkan. Frontend dapat dibangun dengan Vue.js atau React untuk pengalaman pengguna yang responsif. Integrasi dengan modul lain seperti E-Resep, Billing, dan Purchasing menjadi kunci, di mana setiap resep yang didispensing atau pembelian yang diterima akan secara otomatis memperbarui stok di gudang yang relevan. Untuk sistem yang lebih kompleks dan terdistribusi, Apache Kafka dapat digunakan untuk antrean pesan asinkron, memastikan konsistensi data antar modul meskipun ada lonjakan transaksi.

Struktur database inti akan melibatkan tabel master gudang (`m_gudang`) dan tabel transaksi stok yang diperkaya (`t_stok_gudang`). Tabel `m_gudang` akan menyimpan informasi dasar setiap lokasi inventori, seperti ID unik, nama, tipe (pusat, satelit, floor stock), dan detail lokasi. Sementara `t_stok_gudang` akan mencatat setiap pergerakan obat (masuk/keluar) untuk obat spesifik di gudang tertentu, lengkap dengan nomor batch dan tanggal kadaluwarsa. Penting untuk mengimplementasikan trigger atau fungsi database untuk memastikan saldo stok selalu akurat.

Dalam konteks interoperabilitas, standar seperti FHIR R4 (Fast Healthcare Interoperability Resources Release 4) menjadi sangat relevan. Resource seperti `Medication`, `MedicationDispense`, dan `InventoryItem` dapat digunakan untuk merepresentasikan data obat dan pergerakan stok secara standar. Jika ada kebutuhan bridging dengan sistem eksternal atau BPJS, HAPI FHIR versi 6.8.x dapat menjadi pilihan yang solid sebagai server FHIR proxy. Untuk sistem legacy, HL7 v2.5.1 mungkin masih diperlukan, namun sebaiknya dipertimbangkan migrasi ke FHIR untuk masa depan.

API RESTful yang dirancang harus mencakup endpoint untuk: (1) Melihat stok per gudang, (2) Transfer stok antar gudang, (3) Penerimaan stok (dari pengadaan), (4) Pengeluaran stok (dispensing ke pasien atau penggunaan floor stock), dan (5) Stock opname. Setiap endpoint harus dilengkapi dengan validasi input yang ketat dan otorisasi berdasarkan peran pengguna. Misalnya, hanya apoteker atau staf gudang yang berwenang yang dapat melakukan transfer stok. Penggunaan Redis sebagai cache dapat mempercepat pengambilan data stok yang sering diakses.

Contoh Implementasi Kode dan Query

Berikut adalah contoh implementasi skema database dasar untuk multi-gudang dan tabel transaksi stok, serta contoh fungsi PHP (menggunakan Laravel) untuk melakukan transfer stok antar gudang. Kode ini dirancang agar dapat langsung dijalankan dan memberikan gambaran konkret tentang implementasi teknis.

CREATE TABLE m_gudang (    id SERIAL PRIMARY KEY,    kode_gudang VARCHAR(10) UNIQUE NOT NULL,    nama_gudang VARCHAR(100) NOT NULL,    tipe_gudang VARCHAR(50) NOT NULL, -- Contoh: 'Pusat', 'Satuan', 'Floor Stock'    is_floor_stock BOOLEAN DEFAULT FALSE,    lokasi TEXT,    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP);CREATE TABLE m_obat (    id SERIAL PRIMARY KEY,    kode_obat VARCHAR(20) UNIQUE NOT NULL,    nama_obat VARCHAR(255) NOT NULL,    satuan VARCHAR(20),    harga_beli DECIMAL(15,2) DEFAULT 0,    harga_jual DECIMAL(15,2) DEFAULT 0,    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP);CREATE TABLE t_stok_gudang (    id BIGSERIAL PRIMARY KEY,    id_obat INT NOT NULL, -- Foreign Key ke tabel master obat    id_gudang INT NOT NULL, -- Foreign Key ke m_gudang    no_batch VARCHAR(50) NOT NULL,    tgl_expired DATE NOT NULL,    jumlah_masuk DECIMAL(10,2) DEFAULT 0,    jumlah_keluar DECIMAL(10,2) DEFAULT 0,    saldo_akhir DECIMAL(10,2) GENERATED ALWAYS AS (jumlah_masuk - jumlah_keluar) STORED,    harga_beli_rata DECIMAL(15,2) DEFAULT 0, -- Harga beli rata-rata per batch/entry    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,    CONSTRAINT fk_obat FOREIGN KEY (id_obat) REFERENCES m_obat(id),    CONSTRAINT fk_gudang FOREIGN KEY (id_gudang) REFERENCES m_gudang(id),    CONSTRAINT unique_stok_per_batch UNIQUE (id_obat, id_gudang, no_batch, tgl_expired));CREATE INDEX idx_stok_gudang_obat_gudang ON t_stok_gudang (id_obat, id_gudang);

Penjelasan untuk skema di atas: Tabel `m_gudang` adalah master untuk semua lokasi penyimpanan obat. `m_obat` adalah master obat, dan `t_stok_gudang` adalah tabel transaksi yang mencatat setiap pergerakan stok. Kolom `saldo_akhir` menggunakan `GENERATED ALWAYS AS (...) STORED` di PostgreSQL 12+ untuk memastikan saldo selalu konsisten dan dihitung secara otomatis oleh database, mengurangi risiko inkonsistensi data. Indeks `idx_stok_gudang_obat_gudang` akan mempercepat query pencarian stok berdasarkan obat dan gudang. Constraint `unique_stok_per_batch` memastikan tidak ada entri duplikat untuk kombinasi obat, gudang, batch, dan tanggal kadaluwarsa yang sama, yang sangat penting untuk akurasi stok.

<?phpnamespace App\Http\Controllers;use Illuminate\Http\Request;use Illuminate\Support\Facades\DB;use App\Models\StokGudang; // Asumsi model StokGudang sudah ada dan terhubung ke t_stok_gudangclass StokTransferController extends Controller{    public function transferStok(Request $request)    {        $request->validate([            'id_obat' => 'required|integer|exists:m_obat,id',            'id_gudang_asal' => 'required|integer|exists:m_gudang,id',            'id_gudang_tujuan' => 'required|integer|exists:m_gudang,id|different:id_gudang_asal',            'no_batch' => 'required|string|max:50',            'tgl_expired' => 'required|date',            'jumlah' => 'required|numeric|min:0.01',        ]);        DB::beginTransaction();        try {            // Kurangi stok di gudang asal            $stokAsal = StokGudang::where('id_obat', $request->id_obat)                                    ->where('id_gudang', $request->id_gudang_asal)                                    ->where('no_batch', $request->no_batch)                                    ->where('tgl_expired', $request->tgl_expired)                                    ->lockForUpdate() // Penting untuk mencegah race condition                                    ->firstOrFail();            if ($stokAsal->saldo_akhir < $request->jumlah) {                throw new \Exception('Stok tidak mencukupi di gudang asal.');            }            $stokAsal->jumlah_keluar += $request->jumlah;            $stokAsal->save();            // Tambah stok di gudang tujuan            $stokTujuan = StokGudang::firstOrCreate(                [                    'id_obat' => $request->id_obat,                    'id_gudang' => $request->id_gudang_tujuan,                    'no_batch' => $request->no_batch,                    'tgl_expired' => $request->tgl_expired,                ],                [                    'jumlah_masuk' => 0,                    'jumlah_keluar' => 0,                    'harga_beli_rata' => $stokAsal->harga_beli_rata // Asumsi harga beli sama saat transfer                ]            );            $stokTujuan->jumlah_masuk += $request->jumlah;            $stokTujuan->save();            DB::commit();            return response()->json(['message' => 'Transfer stok berhasil.'], 200);        } catch (\Exception $e) {            DB::rollBack();            return response()->json(['message' => 'Transfer stok gagal: ' . $e->getMessage()], 500);        }    }}

Fungsi `transferStok` ini menerima request berisi ID obat, ID gudang asal dan tujuan, nomor batch, tanggal kadaluwarsa, serta jumlah yang akan ditransfer. Validasi input dilakukan di awal untuk memastikan data yang masuk sesuai. Transaksi database (`DB::beginTransaction()`, `DB::commit()`, `DB::rollBack()`) digunakan untuk menjamin atomisitas operasi; jika salah satu bagian gagal, seluruh transaksi dibatalkan. `lockForUpdate()` sangat penting untuk mencegah race condition pada saat multiple user mencoba mentransfer stok yang sama secara bersamaan, memastikan integritas data. Jika stok di gudang asal tidak mencukupi, sistem akan mengembalikan error. Jika berhasil, stok di gudang asal akan berkurang (`jumlah_keluar` bertambah) dan stok di gudang tujuan akan bertambah (`jumlah_masuk` bertambah). Jika item dengan batch dan expired date yang sama belum ada di gudang tujuan, ia akan membuat entri baru (`firstOrCreate`).

Contoh Payload dan Penanganan Error

Dalam konteks integrasi dan otomatisasi, pertukaran data menggunakan payload standar seperti JSON sangat umum. Berikut adalah contoh payload JSON yang mewakili transaksi pengisian ulang floor stock (replenishment) ke sebuah unit perawatan, menggunakan standar FHIR R4 (MedicationDispense resource) yang dapat diintegrasikan dengan sistem lain yang mendukung FHIR.

{  
Terakhir diperbarui 31 Jul 2026

Komentar

Komentar ditinjau sebelum tampil.

Belum ada komentar. Jadilah yang pertama!