Files
lti-api/internal/utils/fifo/README.md
2025-11-17 09:42:16 +07:00

3.6 KiB
Raw Permalink Blame History

Mesin Stok FIFO

Utilitas FIFO bersifat reusable dan dibagi menjadi dua lapis:

  1. Registry (internal/utils/fifo) mendeklarasikan tabel mana yang bersifat Stockable (sumber stok) atau Usable (pemakai stok). Setiap modul cukup menyebutkan nama tabel dan kolom wajib:
    • Stockable: id, product_warehouse_id, total_qty, total_used_qty, created_at
    • Usable: id, product_warehouse_id, usage_qty, pending_qty, created_at
  2. Service (internal/common/service/common.fifo.service.go) memakai registry tersebut untuk:
    • Menambah stok baru (Replenish).
    • Menyinkronkan total pemakaian (Consume). Method ini idempotent: panggil dengan total kuantitas yang diinginkan (mis. saat create/update/delete). Service menghitung selisih terhadap usage_qty + pending_qty, kemudian otomatis mengalokasikan tambahan atau melepaskan selisihnya.
    • Membatalkan pemakaian (ReleaseUsage) yang mengembalikan stok lalu memicu alokasi ulang ke antrian pending.
    • Baik Replenish maupun pelepasan stok akan menjalankan resolvePendingForWarehouse, sehingga pending tertua langsung terisi ketika stok tersedia.

Registrasi tabel

import (
    commonservice "gitlab.com/mbugroup/lti-api.git/internal/common/service"
    "gitlab.com/mbugroup/lti-api.git/internal/utils/fifo"
)

func init() {
    fifoSvc := commonservice.NewFifoService(db, stockAllocRepo, productWarehouseRepo, utils.Log)

    fifoSvc.RegisterStockable(fifo.StockableConfig{
        Key:   fifo.StockableKey("PURCHASE_DETAIL"),
        Table: "purchase_details",
        Columns: fifo.StockableColumns{
            ID:                 "id",
            ProductWarehouseID: "product_warehouse_id",
            TotalQuantity:      "total_qty",
            TotalUsedQuantity:  "total_used_qty",
            CreatedAt:          "created_at",
        },
    })

    fifoSvc.RegisterUsable(fifo.UsableConfig{
        Key:   fifo.UsableKey("RECORDING_STOCK"),
        Table: "recording_stocks",
        Columns: fifo.UsableColumns{
            ID:                 "id",
            ProductWarehouseID: "product_warehouse_id",
            UsageQuantity:      "usage_qty",
            PendingQuantity:    "pending_qty",
            CreatedAt:          "created_at",
        },
    })
}

Each registration optionally accepts an order clause or base scope (e.g. to exclude drafts).

Setiap registrasi bisa diberi klausa urutan atau scope dasar (mis. untuk mengecualikan draft).

Menggunakan service di modul

  1. Saat stok masuk (mis. purchase selesai): panggil fifoSvc.Replenish(...) dengan key stockable, id record, id product warehouse, dan kuantitas yang baru tersedia. Service akan:
    • Menambah total_qty pada tabel stockable,
    • Menambah product_warehouses.quantity,
    • Mencoba membersihkan pending_qty dari semua usable yang terdaftar (sesuai urutan FIFO).
  2. Saat modul memakai stok (recording, marketing, dsb.) panggil fifoSvc.Consume(...) dengan total qty terbaru.
    • Jika qty baru lebih besar, service mengambil stok FIFO dan menambah usage_qty; kekurangan dicatat sebagai pending_qty.
    • Jika qty baru lebih kecil, service otomatis menurunkan pending_qty lebih dulu, lalu melepaskan alokasi aktif (stok kembali ke gudang) dan langsung dipakai untuk mengisi pending milik entitas lain.
    • Hapus data? panggil Consume dengan qty 0 atau gunakan ReleaseUsage.
  3. Jika dibatalkan penuh: fifoSvc.ReleaseUsage(...) mengosongkan usage_qty/pending_qty dan menandai baris pivot sebagai RELEASED.

Tabel pivot (stock_allocations) menyimpan asal pemakaian secara presisi, sehingga audit trail dan rollback stok menjadi deterministik.