⏱ Estimasi: 10β15 menit Β· Sekali setup Β· Data masuk real-time tiap transaksi
Langkah 1 β Buka Apps Script
Buka spreadsheet β menu Extensions β Apps Script .
Langkah 2 β Paste script berikut
// ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
// HYBIEFLOWERS POS β Google Apps Script
// Workbook: "Hybieflowers POS"
// Deploy β New Deployment β Web App
// Execute as: Me | Who has access: Anyone
// ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
const SHEET_SALES = "Penjualan";
const SHEET_SUMMARY = "Ringkasan";
const SHEET_DAILY = "Harian";
const SHEET_PRODUCTS = "Produk";
const COLOR_PRIMARY = "#8b2233";
const COLOR_ACCENT = "#f7e6ea";
const COLOR_HEADER = "#ffffff";
const COLOR_ROW_ALT = "#fdf6f0";
function doPost(e) {
try {
var data = JSON.parse(e.postData.contents);
var ss = SpreadsheetApp.getActiveSpreadsheet();
if (data.id && String(data.id).indexOf("TEST") === 0)
return respond({ status:"ok", message:"Test diterima", test:true });
saveSale(ss, data);
updateSummary(ss, data);
updateDailySummary(ss, data);
return respond({ status:"ok", id:data.id, total:data.total });
} catch (err) {
Logger.log("doPost ERROR: " + err);
return respond({ status:"error", message:err.toString() });
}
}
function doGet(e) {
if (e && e.parameter && e.parameter.action === "products")
return getProducts();
return respond({ status:"ok", name:"Hybieflowers POS", time:new Date().toISOString() });
}
function saveSale(ss, d) {
var sheet = getOrCreateSheet(ss, SHEET_SALES);
if (sheet.getLastRow() === 0) {
var H = ["No Transaksi","Tanggal","Waktu","Pelanggan",
"Metode Bayar","Detail Item","Jml Item",
"Subtotal (Rp)","Diskon (Rp)","Total (Rp)","Catatan"];
sheet.appendRow(H);
styleHeaderRow(sheet, H.length);
sheet.setFrozenRows(1);
sheet.setColumnWidth(1,160); sheet.setColumnWidth(6,320);
}
var dtStr = d.datetime || "";
var parts = dtStr.split(" ");
var tglArr = (parts[0]||"").split("/");
var tanggal = tglArr.length===3
? tglArr[2]+"-"+tglArr[1]+"-"+tglArr[0] : (parts[0]||"");
sheet.appendRow([
d.id||"", tanggal, parts[1]||"",
d.customer||"Umum", d.payment||"Tunai",
d.items_summary||"", Number(d.item_count)||0,
Number(d.subtotal)||0, Number(d.discount)||0, Number(d.total)||0, d.note||""
]);
var lr = sheet.getLastRow();
if (lr%2===0) sheet.getRange(lr,1,1,11).setBackground(COLOR_ROW_ALT);
sheet.getRange(lr,8,1,3).setNumberFormat('"Rp "#,##0');
}
function updateSummary(ss, d) {
var s = getOrCreateSheet(ss, SHEET_SUMMARY);
if (s.getLastRow() === 0) {
s.getRange("A1").setValue("RINGKASAN PENJUALAN hy_BieFlowers")
.setFontSize(14).setFontWeight("bold").setFontColor(COLOR_PRIMARY);
s.getRange("A2:B2").setValues([["Metrik","Nilai"]]);
styleHeaderRow(s, 2, 2);
[["Total Transaksi",0],["Total Pendapatan (Rp)",0],
["Rata-rata / Transaksi (Rp)",0],["Total Item Terjual",0],
["Total Diskon (Rp)",0],["Transaksi Pertama",""],
["Transaksi Terakhir",""],["Update Terakhir",""]
].forEach(function(r){ s.appendRow(r); });
s.setColumnWidth(1,260); s.setColumnWidth(2,220);
s.setFrozenRows(2);
}
var cnt = (Number(s.getRange(3,2).getValue())||0) + 1;
var rev = (Number(s.getRange(4,2).getValue())||0) + (Number(d.total)||0);
var itms = (Number(s.getRange(6,2).getValue())||0) + (Number(d.item_count)||0);
var disc = (Number(s.getRange(7,2).getValue())||0) + (Number(d.discount)||0);
s.getRange(3,2).setValue(cnt);
s.getRange(4,2).setValue(rev).setNumberFormat('"Rp "#,##0');
s.getRange(5,2).setValue(cnt>0?Math.round(rev/cnt):0).setNumberFormat('"Rp "#,##0');
s.getRange(6,2).setValue(itms);
s.getRange(7,2).setValue(disc).setNumberFormat('"Rp "#,##0');
if (!s.getRange(8,2).getValue())
s.getRange(8,2).setValue(d.id+" β "+(d.customer||"Umum"));
s.getRange(9,2).setValue(d.id+" β "+(d.customer||"Umum")+" β Rp "+Number(d.total).toLocaleString("id-ID"));
s.getRange(10,2).setValue(new Date()).setNumberFormat("dd/MM/yyyy HH:mm:ss");
}
function updateDailySummary(ss, d) {
var s = getOrCreateSheet(ss, SHEET_DAILY);
if (s.getLastRow() === 0) {
var H = ["Tanggal","Jml Transaksi","Total Pendapatan (Rp)","Total Item","Total Diskon (Rp)"];
s.appendRow(H); styleHeaderRow(s, H.length); s.setFrozenRows(1);
}
var dtStr = d.datetime||"";
var parts = dtStr.split(" ");
var tglArr = (parts[0]||"").split("/");
var key = tglArr.length===3
? tglArr[2]+"-"+tglArr[1]+"-"+tglArr[0] : (parts[0]||"");
var lr = s.getLastRow();
var found = -1;
if (lr > 1) {
var dates = s.getRange(2,1,lr-1,1).getValues();
for (var i=0; i<dates.length; i++)
if (String(dates[i][0])===key) { found=i+2; break; }
}
if (found===-1) {
s.appendRow([key,1,Number(d.total)||0,Number(d.item_count)||0,Number(d.discount)||0]);
var nr=s.getLastRow(); s.getRange(nr,3,1,3).setNumberFormat('"Rp "#,##0');
if (nr%2===0) s.getRange(nr,1,1,5).setBackground(COLOR_ROW_ALT);
} else {
var r=s.getRange(found,1,1,5).getValues()[0];
s.getRange(found,2).setValue((Number(r[1])||0)+1);
s.getRange(found,3).setValue((Number(r[2])||0)+(Number(d.total)||0));
s.getRange(found,4).setValue((Number(r[3])||0)+(Number(d.item_count)||0));
s.getRange(found,5).setValue((Number(r[4])||0)+(Number(d.discount)||0));
}
}
function getProducts() {
try {
var ss=SpreadsheetApp.getActiveSpreadsheet();
var sheet=ss.getSheetByName(SHEET_PRODUCTS);
if (!sheet||sheet.getLastRow()<2) return respond({products:[]});
var data=sheet.getDataRange().getValues();
var hdrs=data[0].map(function(h){return String(h).toLowerCase().trim();});
var products=[];
for (var i=1;i<data.length;i++){
if (!data[i][0]) continue;
var o={};
hdrs.forEach(function(h,idx){o[h]=data[i][idx];});
products.push({id:o.id||String(i),name:o.name||o.nama||"",
cat:o.cat||o.kategori||"",price:o.price||o.harga||0,
img:o.img||o.gambar||"",badge:o.badge||"",desc:o.desc||o.deskripsi||""});
}
return respond({products:products});
} catch(err){ return respond({products:[],error:err.toString()}); }
}
function setupSheets() {
var ss=SpreadsheetApp.getActiveSpreadsheet();
ss.setSpreadsheetTimeZone("Asia/Jakarta");
getOrCreateSheet(ss,SHEET_SALES);
getOrCreateSheet(ss,SHEET_SUMMARY);
getOrCreateSheet(ss,SHEET_DAILY);
var ps=getOrCreateSheet(ss,SHEET_PRODUCTS);
if (ps.getLastRow()===0){
var pH=["id","name","cat","price","img","badge","desc"];
ps.appendRow(pH); styleHeaderRow(ps,pH.length); ps.setFrozenRows(1);
ps.setColumnWidths(1,7,[80,220,140,130,300,110,280]);
}
SpreadsheetApp.getUi().alert("β
Setup selesai! 4 sheet siap digunakan.\n\nSekarang: Deploy β New deployment β Web App\nExecute as: Me | Anyone β Deploy β salin URL.");
}
function resetSalesData() {
var ui=SpreadsheetApp.getUi();
if (ui.alert("Reset?","Hapus semua data Penjualan/Ringkasan/Harian?",ui.ButtonSet.YES_NO)!==ui.Button.YES) return;
var ss=SpreadsheetApp.getActiveSpreadsheet();
[SHEET_SALES,SHEET_SUMMARY,SHEET_DAILY].forEach(function(n){
var sh=ss.getSheetByName(n); if(sh) ss.deleteSheet(sh);
getOrCreateSheet(ss,n);
});
ui.alert("β
Reset selesai.");
}
function getOrCreateSheet(ss,name){ return ss.getSheetByName(name)||ss.insertSheet(name); }
function styleHeaderRow(sheet,numCols,startRow){
var row=startRow||1;
sheet.getRange(row,1,1,numCols)
.setBackground(COLOR_PRIMARY).setFontColor(COLOR_HEADER)
.setFontWeight("bold").setHorizontalAlignment("center");
sheet.setRowHeight(row,32);
}
function respond(obj){
return ContentService.createTextOutput(JSON.stringify(obj))
.setMimeType(ContentService.MimeType.JSON);
}
function onOpen(){
SpreadsheetApp.getUi()
.createMenu("πΈ Hybieflowers POS")
.addItem("Setup Sheet Awal","setupSheets")
.addSeparator()
.addItem("β οΈ Reset Data","resetSalesData")
.addToUi();
}
📋 Salin Script
Langkah 3 β Deploy sebagai Web App
Klik Deploy β New deployment
Klik ikon βοΈ β pilih Web app
"Execute as" β Me
"Who has access" β Anyone β wajib!
Klik Deploy β Authorize β Allow
Salin Web app URL