Logo
Daftar Isi

Bab 13 · Developer API

API Gudang (Warehouse)

Endpoint /warehouse: katalog barang, stok per cabang sebagai snapshot, dan riwayat barang masuk/keluar beserta cara merekonsiliasinya.

Domain gudang punya satu keanehan yang perlu dipahami lebih dulu: Lensiro tidak menyimpan angka stok sebagai kolom. Stok selalu dihitung ulang dari seluruh riwayat pergerakan barang. Itu membuat angkanya selalu konsisten dengan riwayat, tapi juga membuat stok tidak bisa disinkronkan secara inkremental seperti data lain.

GET /warehouse/items — katalog barang

curl -H "Authorization: Bearer $KEY" "$BASE/warehouse/items?category_id=1&limit=200"
{
  "id": 3321,
  "code": "FR3321",
  "custom_code": "8991234567890",
  "display_code": "8991234567890",
  "name": "Frame CONTOH X-01 Black",
  "category": { "id": 1, "code": "FR", "name": "Frame" },
  "sub_category": { "id": 4, "name": "Full Rim" },
  "brand": { "id": 9, "name": "CONTOH" },
  "sub_brand": { "id": 21, "name": "X Series" },
  "color": { "id": 2, "name": "Black" },
  "sub_color": null,
  "prescription": { "spherical": "-2.00", "cylinder": "-0.50", "addition": null },
  "unit": "pcs",
  "sell_price": 1000000,
  "expired_date": null,
  "memo": null,
  "created_at": "2025-03-01T00:00:00.000Z",
  "updated_at": "2026-08-01T00:00:00.000Z",
  "deleted_at": null
}
FieldCatatan
idKunci upsert. Satu-satunya pengenal yang tidak pernah berubah
codeKode internal Lensiro. Bisa berubah kalau kategori barang diganti
custom_codeBarcode toko atau kode dari sistem lama; null kalau tidak diisi
display_codecustom_code bila ada, kalau tidak code — inilah yang tercetak di label barcode
category sampai sub_colorKlasifikasi barang; masing-masing bisa null
prescriptionUkuran lensa (spherical, cylinder, addition) sebagai teks; semuanya null untuk barang non-lensa
unit"pcs" atau null
sell_priceHarga jual standar, Rupiah bulat
expired_dateTanggal kedaluwarsa untuk barang yang punya, misalnya cairan lensa kontak

Selalu upsert berdasarkan id. Kalau Anda memakai code sebagai kunci, katalog Anda akan pecah begitu ada barang yang pindah kategori. Harga modal atau HPP sengaja tidak diekspos di v1.

Detail satu barang: GET /warehouse/items/{id}.

GET /warehouse/items/{id}/stocks

Stok satu barang di seluruh cabang. Tidak berpaginasi (jumlah barisnya sebanyak cabang) dan dibungkus { "data": [...] }. Bentuk barisnya sama dengan /warehouse/stocks di bawah.

GET /warehouse/stocks — snapshot stok

Stok terkini per pasangan (barang, cabang).

curl -H "Authorization: Bearer $KEY" "$BASE/warehouse/stocks?branch_id=2&limit=500"
{
  "item_id": 3321,
  "item_code": "FR3321",
  "item_name": "Frame CONTOH X-01 Black",
  "branch": { "id": 2, "code": "PST", "name": "Cabang Pusat" },
  "on_hand": 4,
  "as_of": "2026-08-16T02:00:00.000Z"
}

Yang perlu diketahui:

  • Ini snapshot, bukan data yang bisa disinkronkan inkremental. Tidak ada updated_since dan tidak ada deleted_at — bukan karena terlewat, tapi karena angka stok tidak punya "waktu terakhir berubah" yang bisa dipercaya. Menyediakan updated_since di sini akan jadi janji palsu.
  • Cara pakainya: tarik ulang seluruh snapshot secara berkala, lalu timpa tabel stok Anda. Jangan mencoba men-diff atau menambahkan selisih.
  • as_of adalah waktu server saat snapshot dihitung. Simpan nilai ini supaya Anda tahu seberapa baru angkanya.
  • Barang nonaktif, yang sudah dihapus dari katalog, tidak muncul.
  • Barang yang tidak punya catatan stok sama sekali di sebuah cabang tidak menghasilkan baris — anggap tidak ada baris sama dengan nol.
  • on_hand bisa negatif kalau ada kesalahan pencatatan di lapangan, misalnya barang terjual sebelum penerimaan dicatat. Jangan asumsikan selalu nol atau lebih.

GET /warehouse/stock-movements — barang masuk & keluar

Ledger pergerakan stok, satu baris per kejadian. Ini cerminan laporan Perubahan Stok, dan sumber angka yang menjelaskan kenapa stok bergerak.

curl -H "Authorization: Bearer $KEY" \
  "$BASE/warehouse/stock-movements?occurred_from=2026-08-01T17:00:00Z&item_id=3321"
{
  "id": "sale:90101",
  "type": "SALE",
  "quantity_change": -1,
  "item": { "id": 3321, "code": "FR3321", "name": "Frame CONTOH X-01 Black" },
  "branch": { "id": 2, "code": "PST", "name": "Cabang Pusat" },
  "reference": {
    "sale_id": 18234,
    "sales_order_number": "SO-PST-1042",
    "invoice_number": "INV-PST-987"
  },
  "memo": null,
  "occurred_at": "2026-08-13T02:11:40.000Z"
}
  • quantity_change bertanda: positif berarti stok bertambah, negatif berarti stok berkurang.
  • id berbentuk "{jenis}:{nomor}", misalnya sale:90101 atau purchase-receive:8812. Bentuknya string, bukan angka — pakai apa adanya sebagai kunci upsert.

Jenis pergerakan

typeTandaArtiIsi reference
PURCHASE_RECEIVE+Penerimaan barang dari pembelianpurchase_receive_id
TRANSFER_IN+Mutasi masuk dari cabang lain, setelah diterimastock_mutation_id
ADJUSTMENT+/−Penyesuaian stok opname atau penghapusanadjustment_job_id, adjustment_type
SALEBarang terjualsale_id, sales_order_number, invoice_number
COMP_ITEMBarang bonus atau komplimen dalam transaksisale_id, sales_order_number, invoice_number
PURCHASE_RETURNRetur barang ke supplierpurchase_return_id
PURCHASE_SENTBarang dikirim untuk pesanan pembelianpurchase_order_id
TRANSFER_OUTMutasi keluar ke cabang lainstock_mutation_id
FIT_BUFFERBarang dipesan lewat Lensiro Fitfit_order_id

Nilai-nilai itu juga yang diterima parameter type. Untuk ADJUSTMENT, adjustment_type bernilai OPNAME atau WRITE_OFF.

Catatan sinkronisasi

Endpoint ini sengaja tidak punya updated_since, karena pergerakan stok bukan data yang hanya bertambah:

  • TRANSFER_OUT muncul saat barang dikirim; TRANSFER_IN baru muncul setelah cabang tujuan mengonfirmasi penerimaan. Jadi selama barang di perjalanan, stok berkurang di cabang asal tanpa bertambah di cabang tujuan — itu perilaku yang benar, bukan bug.
  • Waktu occurred_at untuk TRANSFER_IN memakai waktu perubahan terakhir dokumen mutasi, karena waktu penerimaan tidak disimpan terpisah. Nilainya bisa bergeser kalau dokumen mutasi diedit.
  • Penyesuaian opname bisa diubah setelah dibuat.

Pola yang disarankan: tarik ulang jendela 7 hari terakhir secara berkala, misalnya tiap jam, lalu upsert berdasarkan id. Untuk backfill awal, tarik per rentang bulanan dengan occurred_from dan occurred_to.

Rekonsiliasi

Jumlah quantity_change seluruh pergerakan untuk satu pasangan (barang, cabang) sama dengan on_hand di /warehouse/stocks — keduanya dihitung dari sumber yang sama. Kalau angka Anda tidak cocok, penyebab yang paling mungkin:

  1. Rentang occurred_from / occurred_to memotong sebagian riwayat. Jumlah pergerakan sebagian tidak akan pernah sama dengan stok total.
  2. Paginasi berhenti sebelum has_more bernilai false.
  3. Snapshot ditarik pada waktu berbeda dengan pergerakan; bandingkan as_of dengan occurred_at terakhir.

Untuk angka stok yang dipakai mengambil keputusan, /warehouse/stocks adalah sumber kebenarannya. Pakai /warehouse/stock-movements untuk menjelaskan pergerakan dan menyusun kartu stok, bukan untuk menghitung saldo sendiri.

Solusi lengkap untuk toko optik modern dengan teknologi terdepan dan dukungan terbaik.

Fitur

  • Penjualan Optik
  • Faset & QC
  • Inventory & Gudang
  • Membership & After-Service
  • Multi-Cabang & Roles
  • Financial Statement

Solusi

Perusahaan

©Lensiro. All Rights Reserved.

Kebijakan Privasi