Báo Cáo Tự Động Với Phần Mềm Quản Lý: Tiết Kiệm 10 Giờ/Tuần Cho Doanh Nghiệp

Mỗi tuần bạn mất bao nhiêu giờ để tổng hợp báo cáo? Nếu câu trả lời là hơn 2 giờ, bài viết này sẽ giúp bạn lấy lại thời gian đó.
Hướng dẫn thiết lập báo cáo tự động trong SheetStore và Google Sheets: báo cáo doanh thu hàng ngày, tổng kết tồn kho hàng tuần, P&L hàng tháng, email tự động qua Gmail và Apps Script triggers — tiết kiệm trung bình 10 giờ/tuần.
1. Tại Sao Cần Báo Cáo Tự Động?
Hầu hết chủ doanh nghiệp nhỏ và quản lý cấp trung dành 2–5 giờ mỗi tuần chỉ để copy, paste và tổng hợp số liệu từ nhiều nguồn vào báo cáo. Đây là công việc không tạo ra giá trị — nhưng lại không thể bỏ qua vì dữ liệu là cơ sở để ra quyết định.
Khảo Sát: Thời Gian Dành Cho Báo Cáo Thủ Công
3.5h
Trung bình/tuần tổng hợp báo cáo
45%
Báo cáo có lỗi sao chép
2 ngày
Độ trễ trung bình của báo cáo tháng
180h
Tiết kiệm/năm sau khi tự động hóa
Báo cáo tự động giải quyết 3 vấn đề cùng lúc:
- Tiết kiệm thời gian: Người làm báo cáo tập trung vào phân tích thay vì nhập liệu
- Giảm sai sót: Dữ liệu lấy trực tiếp từ nguồn, không qua copy-paste
- Kịp thời hơn: Báo cáo ngày có thể gửi lúc 7h sáng hôm sau thay vì chiều tối
2. Thiết Lập Báo Cáo Doanh Thu Hàng Ngày
Báo cáo doanh thu hàng ngày cần trả lời 5 câu hỏi cốt lõi:
- Hôm qua doanh thu là bao nhiêu?
- Có bao nhiêu đơn hàng?
- Sản phẩm nào bán chạy nhất?
- So với hôm qua và cùng kỳ tuần trước thế nào?
- Có đơn hàng nào chưa xử lý không?
Công Thức Google Sheets Cho Báo Cáo Ngày
-- Doanh thu hom qua (cell B2) =SUMIFS(DonHang!F:F, DonHang!C:C, TODAY()-1, DonHang!E:E, "PAID") -- So don hang hom qua =COUNTIFS(DonHang!C:C, TODAY()-1, DonHang!E:E, "PAID") -- Don trung binh =IFERROR(B2/C2, 0) -- So sanh vs hom kia (%) =IFERROR((B2 - SUMIFS(DonHang!F:F, DonHang!C:C, TODAY()-2, DonHang!E:E, "PAID")) / SUMIFS(DonHang!F:F, DonHang!C:C, TODAY()-2, DonHang!E:E, "PAID"), 0) -- Top 5 san pham ban chay hom qua =QUERY(DonHang!A:G, "SELECT D, SUM(G) WHERE C = date '" & TEXT(TODAY()-1,"yyyy-mm-dd") & "' AND E = 'PAID' GROUP BY D ORDER BY SUM(G) DESC LIMIT 5 LABEL D 'San Pham', SUM(G) 'So Luong'")
Format Báo Cáo Ngày Đẹp Với Conditional Formatting
Dùng Conditional Formatting để highlight tự động:
- Doanh thu tăng so với hôm trước: nền xanh
- Doanh thu giảm hơn 10%: nền đỏ nhạt
- Đơn chưa xử lý sau 2 giờ: in đậm màu cam
3. Tổng Kết Tồn Kho Hàng Tuần
Báo cáo tồn kho hàng tuần giúp bạn chủ động đặt hàng trước khi hết hàng và tránh tồn kho chết.
// Apps Script: Tao bao cao ton kho hang tuan
// Chay vao 8h sang thu 2 hang tuan
function weeklyInventoryReport() {
const ss = SpreadsheetApp.getActiveSpreadsheet()
const tonKhoSheet = ss.getSheetByName("TonKho")
const data = tonKhoSheet.getDataRange().getValues()
// Phan loai san pham theo trang thai ton kho
const hetHang = []
const saptHet = [] // ton < nguong
const tonNhieu = [] // ton > 3 lan nguong
for (let i = 1; i < data.length; i++) {
const [maSP, tenSP, ton, nguong, giaNhap] = data[i]
if (!tenSP) continue
if (ton === 0) hetHang.push({ maSP, tenSP, ton, nguong })
else if (ton <= nguong) saptHet.push({ maSP, tenSP, ton, nguong })
else if (ton > nguong * 3) tonNhieu.push({ maSP, tenSP, ton, nguong, giaNhap, giaTriTon: ton * giaNhap })
}
// Tao noi dung email
let emailBody = "BAO CAO TON KHO TUAN " + getWeekNumber() + "\n"
emailBody += "=".repeat(50) + "\n\n"
if (hetHang.length > 0) {
emailBody += "HET HANG (" + hetHang.length + " san pham):\n"
hetHang.forEach(sp => { emailBody += " - " + sp.tenSP + " (MA: " + sp.maSP + ")\n" })
emailBody += "\n"
}
if (saptHet.length > 0) {
emailBody += "SAP HET HANG (" + saptHet.length + " san pham):\n"
saptHet.forEach(sp => { emailBody += " - " + sp.tenSP + ": con " + sp.ton + "/" + sp.nguong + "\n" })
emailBody += "\n"
}
GmailApp.sendEmail(
Session.getActiveUser().getEmail(),
"Bao Cao Ton Kho Tuan " + getWeekNumber(),
emailBody
)
}
4. Báo Cáo P&L Hàng Tháng Tự Động
Báo cáo Lãi/Lỗ (P&L) là báo cáo quan trọng nhất nhưng cũng tốn thời gian nhất nếu làm thủ công. Tự động hóa P&L yêu cầu dữ liệu đầu vào rõ ràng:
| Chỉ Tiêu | Nguồn Dữ Liệu | Công Thức |
|---|---|---|
| Doanh thu thuần | Sheet DonHang | SUMIFS theo tháng, status PAID |
| Giá vốn hàng bán | Sheet DonHang + GiaVon | SUMPRODUCT(SoLuong * GiaVon) |
| Lợi nhuận gộp | Tính toán | Doanh thu - Giá vốn |
| Chi phí vận hành | Sheet ChiPhi | SUMIFS theo tháng và loại |
| EBITDA | Tính toán | Lợi nhuận gộp - Chi phí VH |
| Lãi/Lỗ ròng | Tính toán | EBITDA - Thuế - Lãi vay |
-- P&L Sheet: Doanh thu thang hien tai (cho cot thang) -- Gia su row 1 la header, row 2 la thang 1, row 3 la thang 2... -- Cot A = Thang, Cot B = Doanh thu, Cot C = Gia von... -- Doanh thu thang N (N = so thang, 1-12) =SUMPRODUCT( (MONTH(DonHang!C$2:C$10000)=A2) * (YEAR(DonHang!C$2:C$10000)=YEAR(TODAY())) * (DonHang!E$2:E$10000="PAID") * DonHang!F$2:F$10000 ) -- Ty le loi nhuan gop (%) =IFERROR((B2 - C2) / B2, 0) -- Bieu do P&L tu dong cap nhat khi them du lieu moi -- (Tao bieu do chon vung A:F, Google Sheets tu dong mo rong)
5. Gửi Email Báo Cáo Tự Động Qua Gmail
Apps Script kết hợp với Gmail cho phép gửi báo cáo định kỳ hoàn toàn tự động — không cần mở máy tính, không cần nhớ gửi.
// Gui bao cao doanh thu hang ngay luc 7:30 sang
function sendDailySalesReport() {
const ss = SpreadsheetApp.getActiveSpreadsheet()
const baoCaoSheet = ss.getSheetByName("BaoCaoNgay")
// Lay du lieu tu sheet bao cao
const doanhThu = baoCaoSheet.getRange("B2").getValue()
const soDon = baoCaoSheet.getRange("C2").getValue()
const donTrungBinh = baoCaoSheet.getRange("D2").getValue()
const tangTruong = baoCaoSheet.getRange("E2").getValue()
const topSanPham = baoCaoSheet.getRange("H2:I6").getValues()
// Dinh dang so tien Viet Nam
const formatVND = (n) => new Intl.NumberFormat("vi-VN", {style:"currency",currency:"VND"}).format(n)
// Tao noi dung email HTML
const yesterday = new Date(Date.now() - 86400000)
const dateStr = yesterday.toLocaleDateString("vi-VN")
let htmlBody = "Bao Cao Doanh Thu Ngay " + dateStr + "
"
htmlBody += "| Doanh Thu | " + formatVND(doanhThu) + " |
| So Don Hang | " + soDon + " |
| Don Trung Binh | " + formatVND(donTrungBinh) + " |
| Tang Truong | " + (tangTruong*100).toFixed(1) + "% |
" htmlBody += "
Top San Pham Ban Chay
- "
topSanPham.forEach(row => {
if (row[0]) htmlBody += "
- " + row[0] + ": " + row[1] + " cai " }) htmlBody += "
Gửi Báo Cáo Cho Nhiều Người
// Danh sach nguoi nhan theo cap bac
const RECIPIENTS = {
daily: ["owner@company.com", "manager@company.com"],
weekly: ["owner@company.com", "manager@company.com", "accountant@company.com"],
monthly: ["owner@company.com", "accountant@company.com", "investor@company.com"]
}
// Gui cho nhieu nguoi
GmailApp.sendEmail(
RECIPIENTS.daily.join(","),
subject,
plainText,
{ htmlBody, cc: "cfo@company.com" }
)
6. Apps Script Triggers: Lập Lịch Chạy Tự Động
Trigger là cơ chế cho phép Apps Script chạy tự động theo lịch hoặc sự kiện. Có 2 loại trigger chính:
Time-Based Trigger (Chạy Theo Lịch)
// Cai dat toan bo trigger cho he thong bao cao
function setupAllTriggers() {
// Xoa trigger cu truoc khi tao moi
ScriptApp.getProjectTriggers().forEach(t => ScriptApp.deleteTrigger(t))
// 1. Bao cao doanh thu hang ngay luc 7:30 sang
ScriptApp.newTrigger("sendDailySalesReport")
.timeBased()
.atHour(7)
.everyDays(1)
.create()
// 2. Tong ket ton kho moi thu 2 luc 8h sang
ScriptApp.newTrigger("weeklyInventoryReport")
.timeBased()
.onWeekDay(ScriptApp.WeekDay.MONDAY)
.atHour(8)
.create()
// 3. Bao cao P&L cuoi thang (ngay 28, phong truong hop thang ngan)
ScriptApp.newTrigger("monthlyPLReport")
.timeBased()
.onMonthDay(28)
.atHour(6)
.create()
// 4. Canh bao ton kho thap moi ngay luc 9h sang
ScriptApp.newTrigger("checkLowStock")
.timeBased()
.atHour(9)
.everyDays(1)
.create()
Logger.log("Tao " + ScriptApp.getProjectTriggers().length + " triggers thanh cong")
}
Event-Based Trigger (Chạy Khi Có Sự Kiện)
// Chay khi co du lieu moi nhap vao Sheet "DonHang"
function onDonHangEdit(e) {
const sheet = e.range.getSheet()
if (sheet.getName() !== "DonHang") return
const row = e.range.getRow()
const statusCol = 5 // Cot E = TrangThai
const status = sheet.getRange(row, statusCol).getValue()
// Khi don hang duoc cap nhat thanh PAID
if (status === "PAID") {
const tenKH = sheet.getRange(row, 2).getValue()
const email = sheet.getRange(row, 9).getValue()
const tongTien = sheet.getRange(row, 6).getValue()
// Gui email xac nhan cho khach hang
if (email) {
sendOrderConfirmation(email, tenKH, tongTien)
}
// Cap nhat bao cao dashboard
refreshDashboard()
}
}
// Cai trigger onChange
// Chu y: Trigger onChange can cai qua giao dien
// Apps Script > Triggers > Add trigger > onEdit > Spreadsheet
7. Google Sheets Scheduled Refresh
Ngoài Apps Script, Google Sheets có một số cơ chế tự động cập nhật dữ liệu:
IMPORTRANGE Tự Động Cập Nhật
IMPORTRANGE làm mới dữ liệu mỗi khi sheet được mở hoặc khoảng mỗi 30 phút. Không cần cấu hình gì thêm.
GOOGLEFINANCE Cập Nhật Thời Gian Thực
Nếu báo cáo của bạn cần tỷ giá USD/VND hoặc giá nguyên liệu liên kết thị trường:
-- Ti gia USD/VND hien tai
=GOOGLEFINANCE("CURRENCY:USDVND")
-- Gia vang (XAU/USD)
=GOOGLEFINANCE("CURRENCY:XAUUSD")
-- Tu dong tinh gia nhap hang nhap khau theo ti gia hom nay
=B2 * GOOGLEFINANCE("CURRENCY:USDVND") -- B2 la gia USD
Cấu Hình Tự Làm Mới Với Apps Script
// Bat buoc refresh cac ham volatile (NOW, TODAY, RAND) moi 5 phut
// Them cot phu "last_refresh" va cap nhat no
function forceRefresh() {
const ss = SpreadsheetApp.getActiveSpreadsheet()
const sheet = ss.getSheetByName("Dashboard")
// Cap nhat gia tri refresh time de trigger recalculation
sheet.getRange("Z1").setValue(new Date())
}
// Cai trigger chay moi 5 phut
ScriptApp.newTrigger("forceRefresh")
.timeBased()
.everyMinutes(5)
.create()
8. Dashboard Tự Động Cập Nhật
Dashboard lý tưởng không cần ai cập nhật — mọi số liệu tự kéo từ dữ liệu gốc và cập nhật liên tục.
Nguyên Tắc Xây Dashboard Tự Động
- Không nhập liệu thủ công vào Dashboard: Mọi ô đều là công thức hoặc IMPORTRANGE
- Dùng Named Ranges: Đặt tên vùng dữ liệu nguồn để công thức dễ đọc và bảo trì
- TODAY() và NOW() trong công thức: Đảm bảo số liệu luôn là "hôm nay"
- Bảo vệ toàn bộ Dashboard: Khóa chỉnh sửa, chỉ cho xem để tránh vô tình xóa công thức
-- Cac cong thuc Dashboard khong can cap nhat thu cong: -- Doanh thu 7 ngay gan nhat =SUMIFS(DonHang!F:F, DonHang!C:C, ">="&TODAY()-7, DonHang!E:E, "PAID") -- Toc do tang truong WoW (so sanh 7 ngay nay vs 7 ngay truoc) =IFERROR( (SUMIFS(DonHang!F:F, DonHang!C:C, ">="&TODAY()-7, DonHang!E:E, "PAID") - SUMIFS(DonHang!F:F, DonHang!C:C, ">="&TODAY()-14, DonHang!C:C, "<"&TODAY()-7, DonHang!E:E, "PAID")) / SUMIFS(DonHang!F:F, DonHang!C:C, ">="&TODAY()-14, DonHang!C:C, "<"&TODAY()-7, DonHang!E:E, "PAID"), 0) -- So san pham con hang (ton > 0) =COUNTIF(TonKho!C:C, ">0") -- So san pham het hang =COUNTIF(TonKho!C:C, 0)
9. Biểu Đồ Tự Động Theo Dữ Liệu
Google Sheets cập nhật biểu đồ tự động khi dữ liệu nguồn thay đổi. Một số mẹo để biểu đồ luôn hiển thị đúng:
Biểu Đồ Doanh Thu Theo Ngày (Rolling 30 Ngày)
Thay vì chọn vùng dữ liệu cố định, tạo một sheet trung gian với công thức kéo 30 ngày gần nhất:
-- Sheet "BaoCao30Ngay": Cot A = Ngay, Cot B = Doanh thu -- A2: =TODAY()-29 -- A3: =A2+1 (keo xuong den A31) -- B2: =SUMIFS(DonHang!F:F, DonHang!C:C, A2, DonHang!E:E, "PAID") -- B3 den B31: tuong tu -- Tao bieu do tu A1:B31 -> bieu do tu dong cap nhat moi ngay -- 30 ngay nay luon la 30 ngay gan nhat
SPARKLINE — Biểu Đồ Nhỏ Trong Ô
-- Bieu do xu huong doanh thu 7 ngay trong 1 o
=SPARKLINE(
ARRAYFORMULA(SUMIFS(DonHang!F:F, DonHang!C:C, TODAY()-{6,5,4,3,2,1,0}, DonHang!E:E, "PAID")),
{"charttype","column"; "color","#4285f4"; "lowcolor","#ea4335"}
)
-- Sparkline ton kho (duong ke)
=SPARKLINE(TonKho!C2:C100, {"charttype","line"; "color","#34a853"})
10. ROI Thực Tế: Tính Toán 10 Giờ/Tuần Tiết Kiệm
Hãy tính toán cụ thể cho một doanh nghiệp bán lẻ có 2 nhân viên phụ trách báo cáo:
| Tác Vụ Báo Cáo | Trước TĐH (giờ/tuần) | Sau TĐH (giờ/tuần) | Tiết Kiệm |
|---|---|---|---|
| Tổng hợp doanh thu ngày | 2.5h | 0h (tự động) | 2.5h |
| Kiểm tra tồn kho hàng tuần | 1.5h | 0.25h (xem email) | 1.25h |
| Báo cáo cho chủ/giám đốc | 2h | 0h (tự gửi) | 2h |
| Tổng hợp P&L cuối tháng | 8h/tháng = 2h/tuần | 0.5h kiểm tra | 1.5h |
| Đối soát công nợ | 1.5h | 0.5h | 1h |
| TỔNG | 9.5h/tuần | 1.25h/tuần | 8.25h/tuần |
Tính ROI Tài Chính
Giả sử nhân viên báo cáo có mức lương 8 triệu đồng/tháng (khoảng 50,000đ/giờ):
- Tiết kiệm: 8.25h/tuần x 4 tuần x 50,000đ = 1,650,000đ/tháng
- Chi phí SheetStore: 699,000đ/tháng
- ROI tháng đầu: +136%
- Tiết kiệm ròng năm đầu: 11,412,000đ
Ngoài tiết kiệm thời gian, lợi ích khó đo lường nhưng quan trọng hơn là: ra quyết định nhanh hơn và chính xác hơn vì dữ liệu luôn cập nhật và ít sai sót.
11. SheetStore: Automation Sẵn Có, Không Cần Cấu Hình
SheetStore đã tích hợp sẵn tất cả các automation trên trong gói sản phẩm:
Báo Cáo Tự Động
- ✓ Email doanh thu 7h sáng
- ✓ Tổng kết tuần thứ 2
- ✓ P&L tự động cuối tháng
- ✓ Cảnh báo tồn kho
Dashboard Real-Time
- ✓ KPI hôm nay/tuần/tháng
- ✓ Biểu đồ xu hướng 30 ngày
- ✓ Top sản phẩm bán chạy
- ✓ Truy cập qua điện thoại
Tùy Chỉnh Linh Hoạt
- ✓ Thêm người nhận email
- ✓ Chỉnh giờ gửi báo cáo
- ✓ Tùy chỉnh nội dung báo cáo
- ✓ Thêm chỉ tiêu theo ngành
12. FAQ — Câu Hỏi Thường Gặp
Apps Script có giới hạn số lần chạy không?
Có. Tài khoản Google miễn phí: 90 phút runtime/ngày, 20 trigger/dự án. Google Workspace: 6 giờ runtime/ngày, 20 trigger/dự án. Với báo cáo định kỳ thông thường, quota miễn phí hoàn toàn đủ dùng.
Nếu có lỗi trong script, tôi có biết không?
Có. Apps Script gửi email thông báo lỗi đến tài khoản Google của bạn khi trigger bị lỗi. Bạn cũng có thể xem log chi tiết tại Apps Script > Executions.
Có thể gửi báo cáo qua Zalo thay vì email không?
Có, qua Zalo OA API. Apps Script gọi Zalo API để gửi tin nhắn qua Zalo Official Account. SheetStore hỗ trợ tích hợp thông báo qua Zalo trong gói nâng cao.
Báo cáo có thể export PDF tự động không?
Có. Apps Script có thể export sheet sang PDF và đính kèm vào email tự động. Dùng UrlFetchApp để call Google Docs API export endpoint với định dạng PDF.
Lấy Lại 10 Giờ Mỗi Tuần Với SheetStore
Báo cáo tự động, tồn kho tự động, email tự động — bạn chỉ cần đọc và ra quyết định.
Chia sẻ bài viết:
Tuân Hoang
Đội ngũ SheetStore
Bạn thấy bài viết hữu ích?
Đăng ký nhận thông báo khi có bài viết mới.