Gudang Kering
0
0 Total UnitBeras, Bumbu Kering, Kaleng, Tepung
Gudang Basah / Cold
0
0 Total UnitDaging, Seafood, Sayur, Buah Segar
Transaksi Hari Ini
0
0 In / 0 OutPergerakan arus barang harian
Peringatan Stok Rendah
0
Qty ≤ 10Perlu segera dilakukan Restock
Tabel Monitoring Stok Real-Time
Kalkulasi otomatis dari akumulasi barang masuk dikurangi barang keluar.
| Gudang | Kode / Nama Barang | Kategori | Total Masuk | Total Keluar | Sisa Stok | Status | Aksi Cepat |
|---|
Form Input Transaksi Gudang
Catat pergerakan barang Masuk (Inbound) atau Keluar (Outbound).
Laporan Mutasi Persediaan Barang
Gudang Kering & Gudang Basah
Daftar Mutasi / Transaksi
Menampilkan 0 catatan
| Tgl | Tipe | Gudang | Kategori | Nama Barang | Qty | Satuan | Exp Date | Pemasok / Tujuan | Keterangan | Aksi |
|---|
Kategori Gudang Kering
Penyimpanan non-refrigerated & kemasan kering
Kategori ini hanya muncul saat memilih transaksi Gudang Kering.
Kategori Gudang Basah
Penyimpanan cold room, chiller & bahan segar
Kategori ini hanya muncul saat memilih transaksi Gudang Basah.
Koneksi Google Sheets (Website Luar)
Jika Anda meng-upload file ini ke hosting website pribadi (cPanel/Vercel/Netlify), masukkan URL Web App Google Script Anda di bawah ini agar data otomatis tersinkronisasi ke Google Spreadsheet.
Dapat diperoleh dari menu Deploy > Manage deployments > Web app URL di Apps Script (Wajib berakhiran /exec).
Panduan Deployment ke Google Apps Script (GAS)
Cara Memasang di Google Sheets Anda:
- Buat Google Spreadsheet baru di Google Drive Anda.
- Klik menu Extensions (Ekstensi) > Apps Script.
- Ganti isi file
Code.gsdengan kode di bawah. - Klik tombol Deploy > New deployment, pilih jenis Web App, ubah Who has access ke Anyone (Siapa saja), lalu klik Deploy.
- Salin Web app URL yang dihasilkan, lalu masukkan pada tombol Koneksi Sheets di web Anda!
/* Code.gs - Google Apps Script Backend & Web API */
function doGet(e) {
// Cek endpoint ping tes koneksi
if (e && e.parameter && e.parameter.ping) {
return ContentService.createTextOutput(JSON.stringify({
status: 'success',
message: 'Koneksi ke Google Sheets Berhasil Aktif!'
})).setMimeType(ContentService.MimeType.JSON);
}
// Jika dibuka di browser langsung tanpa parameter api
if (!e || !e.parameter || !e.parameter.api) {
try {
return HtmlService.createHtmlOutputFromFile('index')
.setTitle('Sistem Inventaris Gudang Kering & Basah')
.setXFrameOptionsMode(HtmlService.XFrameOptionsMode.ALLOWALL);
} catch(err) {}
}
// Endpoint API GET untuk menarik data transaksi & kategori
var data = getInitialData();
return ContentService.createTextOutput(JSON.stringify(data))
.setMimeType(ContentService.MimeType.JSON);
}
function doPost(e) {
var lock = LockService.getScriptLock();
lock.tryLock(15000);
try {
initSpreadsheet();
var payload;
// Membaca payload baik dari raw body maupun form parameter
if (e && e.postData && e.postData.contents) {
payload = JSON.parse(e.postData.contents);
} else if (e && e.parameter && e.parameter.data) {
payload = JSON.parse(e.parameter.data);
} else {
throw new Error("Payload kosong atau tidak terbaca.");
}
var action = payload.action;
if (action === 'saveTransaction') {
saveTransaction(payload.data);
return ContentService.createTextOutput(JSON.stringify({ status: 'success', message: 'Data transaksi berhasil disimpan' }))
.setMimeType(ContentService.MimeType.JSON);
} else if (action === 'deleteTransaction') {
deleteTransactionById(payload.id);
return ContentService.createTextOutput(JSON.stringify({ status: 'success', message: 'Data transaksi berhasil dihapus' }))
.setMimeType(ContentService.MimeType.JSON);
} else if (action === 'ping') {
return ContentService.createTextOutput(JSON.stringify({ status: 'success', message: 'Koneksi POST ke Spreadsheet Sukses!' }))
.setMimeType(ContentService.MimeType.JSON);
}
return ContentService.createTextOutput(JSON.stringify({ status: 'unknown_action' }))
.setMimeType(ContentService.MimeType.JSON);
} catch (err) {
return ContentService.createTextOutput(JSON.stringify({ status: 'error', message: err.toString() }))
.setMimeType(ContentService.MimeType.JSON);
} finally {
lock.releaseLock();
}
}
// Inisialisasi Spreadsheet Database Otomatis
function initSpreadsheet() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
if (!ss) throw new Error("Spreadsheet tidak terhubung. Buka script dari menu Extensions > Apps Script!");
var txSheet = ss.getSheetByName('TRANSAKSI');
if (!txSheet) {
txSheet = ss.insertSheet('TRANSAKSI');
txSheet.appendRow(['ID', 'Tanggal', 'Tipe', 'Gudang', 'Kategori', 'Nama Barang', 'Qty', 'Satuan', 'Exp Date', 'Pihak Terkait', 'Keterangan']);
txSheet.getRange(1, 1, 1, 11).setFontWeight('bold').setBackground('#dcfce7');
}
var catSheet = ss.getSheetByName('KATEGORI');
if (!catSheet) {
catSheet = ss.insertSheet('KATEGORI');
catSheet.appendRow(['Gudang', 'Nama Kategori']);
catSheet.getRange(1, 1, 1, 2).setFontWeight('bold').setBackground('#e0f2fe');
}
return true;
}
function getInitialData() {
initSpreadsheet();
var ss = SpreadsheetApp.getActiveSpreadsheet();
var txSheet = ss.getSheetByName('TRANSAKSI');
var catSheet = ss.getSheetByName('KATEGORI');
var transactions = [];
var txValues = txSheet.getDataRange().getValues();
for (var i = 1; i < txValues.length; i++) {
if (txValues[i][0]) {
var rawDate = txValues[i][1];
var formattedDate = rawDate instanceof Date
? Utilities.formatDate(rawDate, Session.getScriptTimeZone(), 'yyyy-MM-dd')
: String(rawDate);
var rawExp = txValues[i][8];
var formattedExp = rawExp instanceof Date
? Utilities.formatDate(rawExp, Session.getScriptTimeZone(), 'yyyy-MM-dd')
: String(rawExp || '');
transactions.push({
id: String(txValues[i][0]),
date: formattedDate,
type: String(txValues[i][2]),
warehouse: String(txValues[i][3]),
category: String(txValues[i][4]),
itemName: String(txValues[i][5]),
qty: Number(txValues[i][6]),
unit: String(txValues[i][7]),
expiry: formattedExp,
partner: String(txValues[i][9] || ''),
notes: String(txValues[i][10] || '')
});
}
}
var categories = { "Gudang Kering": [], "Gudang Basah": [] };
var catValues = catSheet.getDataRange().getValues();
for (var j = 1; j < catValues.length; j++) {
var wh = catValues[j][0];
var cat = catValues[j][1];
if (categories[wh]) {
categories[wh].push(cat);
}
}
return { transactions: transactions, categories: categories };
}
function saveTransaction(tx) {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName('TRANSAKSI');
sheet.appendRow([
tx.id, tx.date, tx.type, tx.warehouse, tx.category,
tx.itemName, tx.qty, tx.unit, tx.expiry, tx.partner, tx.notes
]);
return { status: 'success', data: tx };
}
function deleteTransactionById(id) {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName('TRANSAKSI');
var values = sheet.getDataRange().getValues();
for (var i = 1; i < values.length; i++) {
if (String(values[i][0]) === String(id)) {
sheet.deleteRow(i + 1);
return { status: 'success', id: id };
}
}
return { status: 'not_found' };
}