Mã Google Apps Script
- Mở sheet Kinh Doanh Indo → Tiện ích mở rộng → Apps Script, dán mã bên dưới vào cuối file.
- Bấm Triển khai (Deploy) → Tùy chọn triển khai mới → Ứng dụng web (Web app) (Quyền truy cập: Bất kỳ ai).
- Dán URL nhận được vào ô phía trên và bấm Lưu & Đồng bộ.
function doGet(e) {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var tasks = [];
var tz = Session.getScriptTimeZone();
function fmtDate(val) {
if (!val) return "";
if (val instanceof Date) return Utilities.formatDate(val, tz, "yyyy-MM-dd");
var s = String(val).trim();
if (/^\d{4}-\d{2}-\d{2}/.test(s)) return s.slice(0, 10);
var m = s.match(/^(\d{1,2})\/(\d{1,2})\/(\d{4})/);
if (m) return m[3] + "-" + ("0" + m[2]).slice(-2) + "-" + ("0" + m[1]).slice(-2);
return "";
}
var cfSheet = ss.getSheetByName("Theo dõi Dòng tiền");
if (cfSheet) {
var cfData = cfSheet.getDataRange().getValues();
for (var i = 0; i < cfData.length; i++) {
var row = cfData[i];
var dStr = fmtDate(row[0]);
if (!dStr) continue;
var title = String(row[2] || row[1] || "").trim();
if (!title || title.toLowerCase().indexOf("tổng cộng") === 0) continue;
var statusRaw = String(row[6] || "").toLowerCase();
var done = statusRaw.indexOf("đã") !== -1 || statusRaw.indexOf("xong") !== -1;
var amtStr = String(row[3] || "").trim();
var channel = String(row[2] || row[7] || "").trim();
var low = (channel + " " + title).toLowerCase();
var cat = low.indexOf("pingpong") !== -1 ? "PINGPONG" :
(low.indexOf("9090") !== -1 || low.indexOf("bca") !== -1) ? "BCA" :
(low.indexOf("lcl") !== -1 || low.indexOf("xưởng") !== -1) ? "LOGISTICS" : "VND";
tasks.push({
id: "gs-cf-" + i + "-" + dStr,
date: dStr,
title: title,
amount: amtStr,
category: cat,
completed: done
});
}
}
var impSheet = ss.getSheetByName("Nhập Hàng Indo");
if (impSheet) {
var impData = impSheet.getDataRange().getValues();
for (var j = 1; j < impData.length; j++) {
var r = impData[j];
var dImp = fmtDate(r[0]);
if (!dImp) continue;
var prod = String(r[2] || r[1] || "").trim();
if (!prod) continue;
var payStatus = String(r[12] || r[11] || "").toLowerCase();
var isPaid = payStatus.indexOf("đã thanh toán") !== -1;
tasks.push({
id: "gs-imp-" + j + "-" + dImp,
date: dImp,
title: "Nhập hàng: " + prod + (r[3] ? " (" + r[3] + " pcs)" : ""),
amount: String(r[7] || r[6] || ""),
category: "LOGISTICS",
completed: isPaid
});
}
}
return ContentService
.createTextOutput(JSON.stringify({ status: "ok", updatedAt: new Date().toISOString(), tasks: tasks }))
.setMimeType(ContentService.MimeType.JSON);
}
function doPost(e) {
try {
var payload = JSON.parse(e.postData.contents);
var ss = SpreadsheetApp.getActiveSpreadsheet();
var logSheet = ss.getSheetByName("Lịch_Nhắc_Việc_Sync") || ss.insertSheet("Lịch_Nhắc_Việc_Sync");
logSheet.clearContents();
logSheet.appendRow(["ID", "Ngày", "Nội dung", "Số tiền / Ghi chú", "Kênh", "Trạng thái", "Cập nhật lúc"]);
var now = Utilities.formatDate(new Date(), Session.getScriptTimeZone(), "yyyy-MM-dd HH:mm:ss");
(payload.tasks || []).forEach(function(t) {
logSheet.appendRow([t.id, t.date, t.title, t.amount || "", t.category, t.completed ? "Đã xong" : "Chưa xong", now]);
});
return ContentService.createTextOutput(JSON.stringify({ status: "saved" })).setMimeType(ContentService.MimeType.JSON);
} catch (err) {
return ContentService.createTextOutput(JSON.stringify({ status: "error", message: err.toString() })).setMimeType(ContentService.MimeType.JSON);
}
}