Secure Access System
Please select your role at the top right to access operational data.
Please login to continue
User Name
Role
Please select your role at the top right to access operational data.
Complete daily sales and logistics. Data is auto-synced to HQ.
Branch Code & Name
- -
Area Manager
-
Masa Hantar (Malam)
Not submitted yet
Target (RM)
-
Sales Semasa
-
Sales Diperlukan Harian
-
Data has been successfully submitted to the server. Contact AM to reset.
Total Sales
MyKasih
Lorry Cost
Transactions
Difference = (Total Lorry) - (Total Sales)
| Branch | Sales (RM) | Lorry (RM) | Difference (RM) |
|---|
| Branch | Sales (RM) | Trans | MyKasih | Lorry | 1st Bank-In | 2nd Bank-In | Total Bank In | Balance | K. A (Qty/RM) | K. B (Qty) | Remark A/B | Status | Actions |
|---|
A highly focused, lightweight branch operations finder with Google Sheets syncing.
Upload Excel (.xlsx) with columns: Code, Outlet, AM, State.
Set maximum limits to warn branches when inputting data.
Enable or disable heavy features to save server costs.
Calculate and build summaries for fast loading. Only run once to backfill historical data.
Push the currently loaded Firebase data (based on the selected Date/Month in Tracking Tab) directly to your Google Sheets database. This bypasses the old auto-sync and ensures no missing data.
Click this to scan the currently loaded data and fix any records where the Area Manager name is missing (which causes data to be hidden from the Area Manager's view).
Pantau semua aktiviti reset & unlock oleh Area Manager dan Admin. Dilengkapi penapis harian/bulanan & carian.
| Activity Time & Date | User (AM / Admin) | Action Type | Branch | Target Date |
|---|---|---|---|---|
| Loading logs... | ||||
function normalizeDate(d) {
try {
if (!d) return "";
let dObj = new Date(d);
if (isNaN(dObj.getTime())) return String(d).trim();
let m = dObj.getMonth() + 1; let day = dObj.getDate();
return dObj.getFullYear() + "-" + (m<10?"0":"")+m + "-" + (day<10?"0":"")+day;
} catch(e) { return String(d).trim(); }
}
function doGet(e) {
let ss = SpreadsheetApp.getActiveSpreadsheet();
let action = e.parameter.action;
if (action === 'get_branches') {
let bSheet = ss.getSheetByName('Branches');
if (!bSheet) return ContentService.createTextOutput("[]").setMimeType(ContentService.MimeType.JSON);
let bData = bSheet.getDataRange().getValues();
let branches = [];
for (let i = 1; i < bData.length; i++) {
if(bData[i][0]) branches.push({code: parseInt(bData[i][0]), name: String(bData[i][1]||"").trim(), am: String(bData[i][2]||"").trim(), state: String(bData[i][3]||"").trim(), warehouse: String(bData[i][4]||"").trim()});
}
return ContentService.createTextOutput(JSON.stringify(branches)).setMimeType(ContentService.MimeType.JSON);
}
let sheet = ss.getSheets()[0]; // Data jualan WAJIB di Tab Pertama (Sheet1)
let data = sheet.getDataRange().getValues();
let reqDate = e.parameter.date;
let reqMonth = e.parameter.month;
let result = [];
for (let i = 1; i < data.length; i++) {
let dStr = normalizeDate(data[i][0]);
let match = (!reqDate && !reqMonth) || (reqDate && dStr === reqDate) || (reqMonth && dStr.substring(0,7) === reqMonth);
if (match) {
result.push({
date: dStr, code: parseInt(data[i][1]), name: data[i][2],
sales: parseFloat(data[i][3]), transactions: parseInt(data[i][4]), mykasih: parseFloat(data[i][5]), lorry: parseFloat(data[i][6]),
bank1: parseFloat(data[i][7]), bank2: parseFloat(data[i][8]), night_locked: data[i][9] == 1,
night_submit_time: data[i][10], bank1_time: data[i][11], bank2_time: data[i][12]
});
}
}
return ContentService.createTextOutput(JSON.stringify(result)).setMimeType(ContentService.MimeType.JSON);
}
function doPost(e) {
let ss = SpreadsheetApp.getActiveSpreadsheet();
let sheet = ss.getSheets()[0]; // Data jualan WAJIB di Tab Pertama (Sheet1)
let payload = JSON.parse(e.postData.contents);
let action = payload.action; let rec = payload.data;
let data = sheet.getDataRange().getValues();
let rowIndex = -1;
for(let i = 1; i < data.length; i++) {
let dStr = normalizeDate(data[i][0]);
if(rec && dStr === rec.date && data[i][1] == rec.code) { rowIndex = i + 1; break; }
}
if (action === 'batch_upsert') {
let batchData = payload.data;
if(!batchData || !batchData.length) return ContentService.createTextOutput(JSON.stringify({status: "success"})).setMimeType(ContentService.MimeType.JSON);
// Process batch upsert
for(let r of batchData) {
let rIdx = -1;
for(let i = 1; i < data.length; i++) {
let dStr = normalizeDate(data[i][0]);
if(dStr === r.date && data[i][1] == r.code) { rIdx = i + 1; break; }
}
let rowData = [r.date, r.code, r.name, r.sales||0, r.transactions||0, r.mykasih||0, r.lorry||0, r.bank1||0, r.bank2||0, r.night_locked?1:0, r.night_submit_time?"'"+r.night_submit_time:"", r.bank1_time?"'"+r.bank1_time:"", r.bank2_time?"'"+r.bank2_time:""];
if (rIdx > -1) {
sheet.getRange(rIdx, 1, 1, 13).setValues([rowData]);
data[rIdx-1] = rowData; // Update local data array so next iterations find it
} else {
sheet.appendRow(rowData);
data.push(rowData); // Update local data array
}
}
} else if (action === 'upsert') {
let rowData = [rec.date, rec.code, rec.name, rec.sales||0, rec.transactions||0, rec.mykasih||0, rec.lorry||0, rec.bank1||0, rec.bank2||0, rec.night_locked?1:0, rec.night_submit_time?"'"+rec.night_submit_time:"", rec.bank1_time?"'"+rec.bank1_time:"", rec.bank2_time?"'"+rec.bank2_time:""];
if (rowIndex > -1) sheet.getRange(rowIndex, 1, 1, 13).setValues([rowData]);
else sheet.appendRow(rowData);
} else if (action === 'reset_night' && rowIndex > -1) {
sheet.getRange(rowIndex, 4, 1, 4).setValues([[0, 0, 0, 0]]);
sheet.getRange(rowIndex, 10, 1, 2).setValues([[0, ""]]);
} else if (action === 'reset_bank' && rowIndex > -1) {
sheet.getRange(rowIndex, 8, 1, 2).setValues([[0, 0]]);
sheet.getRange(rowIndex, 12, 1, 2).setValues([["", ""]]);
} else if (action === 'master_reset') {
for(let i = data.length - 1; i >= 1; i--) {
let dStr = normalizeDate(data[i][0]);
if(dStr === rec.date) {
sheet.getRange(i+1, 4, 1, 4).setValues([[0, 0, 0, 0]]);
sheet.getRange(i+1, 10, 1, 2).setValues([[0, ""]]);
}
}
}
return ContentService.createTextOutput(JSON.stringify({status: "success"})).setMimeType(ContentService.MimeType.JSON);
}
| No. | Code | Branch Name | AM | Drop Pattern |
|---|---|---|---|---|
| Select dates and run analysis. | ||||
| Date | AM | Branch | Sales (RM) | Lorry (RM) | Sales Issue | Lorry Issue |
|---|---|---|---|---|---|---|
| Please run the check. | ||||||
| Code | Outlet | Area Manager | Jumlah Sales | Jumlah Lorry Trip | Short | |||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Select a month and click Analyze | ||||||||||||||
Total Company Target
Total Sales (Targeted Branches)
0% Achieved
Branches w/o Target
Set monthly sales targets for branches and track their progress.
| Code | Outlet & AM | Target (RM) | Sales Semasa | Progres | Required/Day |
|---|---|---|---|---|---|
| Loading targets... | |||||
If specified, the survey will only appear for branch codes in this list (saving up to 77% database billing costs).
| Date Created | Question | Status | Responses | Action |
|---|---|---|---|---|
| Loading surveys... | ||||
Deep visual analytics for high-impact insights and executive decision-making.
Top 15 Area Managers with the highest revenue & market share.
Percentage contribution for Area Managers ranked #16 and below.
Direct comparison of Actual Sales vs KPI Target for the first half of Area Managers.
Direct comparison of Actual Sales vs KPI Target for the second half of Area Managers.
Comparative analysis of Total Sales vs Lorry Trip Contribution (RM) across Area Managers.
Comparative analysis of Total Sales vs Lorry Trip Contribution (RM) for the second group of AMs.
Sales distribution Monday - Sunday to identify peak operational days.
Interactive company KPI health index with AM performance breakdown.
Achieved (>=100%)
0 AM
On Track (80-99%)
0 AM
Needs Coaching (<80%)
0 AM
Comparative analysis of Actual vs Target Sales, along with Logistics Cost Ratio for each State across Malaysia.
Cumulative sales tracking and run-rate projection for the current month.
Cawangan tertinggi berdasarkan volum (QTY) pelanggan di Kaunter A.
Cawangan tertinggi berdasarkan volum (QTY) pelanggan di Kaunter B.
Laporan prestasi khas untuk kawasan seliaan anda.
Data will be permanently synced to HQ.
List of branches that have not submitted sales for the selected date.
Leave blank for all branches under target.