const SHEET_SETTINGS = "SETTINGS";
const SHEET_TRX = "TRANSAKSI";
/* ===== WEB APP ===== */
function doGet(){
return HtmlService.createHtmlOutputFromFile("Index")
.setTitle("Dashboard Konter")
.setXFrameOptionsMode(HtmlService.XFrameOptionsMode.ALLOWALL);
}
/* ===== SETTINGS HELPERS ===== */
function _getSettingsSheet(){
const ss = SpreadsheetApp.getActive();
let sh = ss.getSheetByName(SHEET_SETTINGS);
if (!sh){
sh = ss.insertSheet(SHEET_SETTINGS);
sh.getRange("A1:B1").setValues([["KEY","VALUE"]]);
sh.getRange("A2:B3").setValues([["SALDO_AWAL_BANK",0],["SALDO_AWAL_CASH",0]]);
}
return sh;
}
function _getSetting(key, def){
const sh = _getSettingsSheet();
const v = sh.getDataRange().getValues();
for (let i=1;i= a && t <= b;
}
/* ===== API: SALDO AWAL ===== */
function api_getSaldoAwal(){
const bank = _getSetting("SALDO_AWAL_BANK", 0);
const cash = _getSetting("SALDO_AWAL_CASH", 0);
return { bank, cash };
}
function api_setSaldoAwal(data){
const bank = Number(data.bank || 0);
const cash = Number(data.cash || 0);
_setSetting("SALDO_AWAL_BANK", bank);
_setSetting("SALDO_AWAL_CASH", cash);
_appendTrx_([new Date(),"SALDO_AWAL",0,0,"","",0,0,0,0,"Set saldo awal"]);
return true;
}
/* ===== API: SETOR/TARIK ===== */
function api_setorTarik(data){
let bank = _getSetting("SALDO_AWAL_BANK", 0);
let cash = _getSetting("SALDO_AWAL_CASH", 0);
const nominal = Number(data.nominal || 0);
const jenis = String(data.jenis || "").toUpperCase();
const catatan = String(data.catatan || "");
let dCash = 0, dBank = 0;
if (jenis === "SETOR"){ dCash = -nominal; dBank = +nominal; }
else { dBank = -nominal; dCash = +nominal; }
bank += dBank;
cash += dCash;
_setSetting("SALDO_AWAL_BANK", bank);
_setSetting("SALDO_AWAL_CASH", cash);
_appendTrx_([new Date(),"SETOR_TARIK",nominal,0,"",jenis,dCash,dBank,nominal,0,catatan]);
return { bank, cash };
}
/* ===== API: TOPUP DANA ===== */
function api_topupDana(data){
let bank = _getSetting("SALDO_AWAL_BANK", 0);
let cash = _getSetting("SALDO_AWAL_CASH", 0);
const nominal = Number(data.nominal || 0);
const admin = Number(data.admin || 0);
const posisi = String(data.posisi || "LUAR");
const bayar = String(data.bayar || "CASH");
const catatan = String(data.catatan || "");
const totalBayar = posisi === "LUAR" ? nominal + admin : nominal;
let dCash = 0, dBank = 0;
if (bayar === "BANK") dBank += totalBayar;
else dCash += totalBayar;
bank += dBank;
cash += dCash;
_setSetting("SALDO_AWAL_BANK", bank);
_setSetting("SALDO_AWAL_CASH", cash);
_appendTrx_([new Date(),"TOPUP_DANA",nominal,admin,posisi,bayar,dCash,dBank,totalBayar,admin,catatan]);
return { bank, cash, totalBayar, profit: admin };
}
/* ===== DASHBOARD (KPI + SALDO) ===== */
function api_getDashboard(){
const saldo = api_getSaldoAwal();
const today = new Date();
today.setHours(0,0,0,0);
const sh = _getTrxSheet();
const last = sh.getLastRow();
let omset = 0, profit = 0, count = 0;
if (last > 1){
const data = sh.getRange(2,1,last-1,11).getValues();
data.forEach(r=>{
const ts = r[0];
const jenis = String(r[1]||"");
const totalBayar = Number(r[8]||0);
const pr = Number(r[9]||0);
if (_toDateOnly_(ts) === today.getTime()){
// Omset: hitung transaksi jual/topup (setor/tarik tidak dihitung omset)
if (jenis === "TOPUP_DANA"){
omset += totalBayar;
profit += pr;
count++;
}
}
});
}
return { saldo, kpi:{ omset, profit, count } };
}
/* ===== RIWAYAT (dengan search q) ===== */
function api_listRiwayat(payload){
const q = String(payload?.q || "").toLowerCase().trim();
const sh = _getTrxSheet();
const last = sh.getLastRow();
if (last <= 1) return [];
const data = sh.getRange(2,1,last-1,11).getValues();
const rows = data.map(r=>({
ts: r[0],
jenis: String(r[1]||""),
total: Number(r[8]||0),
profit: Number(r[9]||0),
catatan: String(r[10]||"")
})).reverse();
if (!q) return rows.slice(0,50);
return rows.filter(x=>{
return (x.jenis.toLowerCase().includes(q) || x.catatan.toLowerCase().includes(q));
}).slice(0,50);
}
/* ===== LAPORAN RANGE ===== */
function api_laporanRange(payload){
const from = new Date(payload.from);
const to = new Date(payload.to);
from.setHours(0,0,0,0);
to.setHours(0,0,0,0);
const sh = _getTrxSheet();
const last = sh.getLastRow();
if (last <= 1) return { omset:0, profit:0, count:0, rows:[] };
const data = sh.getRange(2,1,last-1,11).getValues();
let omset = 0, profit = 0, count = 0;
const rows = [];
data.forEach(r=>{
const ts = r[0];
const jenis = String(r[1]||"");
const totalBayar = Number(r[8]||0);
const pr = Number(r[9]||0);
const catatan = String(r[10]||"");
if (_inRange_(ts, from, to)){
rows.push({ ts, jenis, total: totalBayar, profit: pr, catatan });
if (jenis === "TOPUP_DANA"){
omset += totalBayar;
profit += pr;
count++;
}
}
});
rows.sort((a,b)=> new Date(b.ts) - new Date(a.ts));
return { omset, profit, count, rows };
}
Dashboard Konter Dashboard Konter Cash & Bank Saldo Awal Topup DANA Setor/Tarik Riwayat Saldo CASH + BANK CASH Rp 0 BANK Rp 0 TOTAL Rp 0 Refresh Laporan Buka Laporan Filter tanggal + ringkasan profit & total transaksi. Saldo Awal Saldo Bank Saldo Cash Catatan: nilai ini jadi saldo dasar (bank & cash). Batal Simpan Topup DANA ...
Komentar
Posting Komentar