🧋
Trương Dáng Hương
Chuyên Gia F&B — Quản lý nội bộ
Đăng nhập
Quên mật khẩu? Liên hệ admin để đặt lại.
v2.0 — Trương Dáng Hương Academy
Trương Dáng Hương
Chuyên Gia F&B
Đang kết nối...
📊 Tổng quan
👑 CEO Dashboard
0
Học viên đang học
0
Doanh thu (₫)
0
Đơn hàng
0
Kho cảnh báo
🎓 Học viên gần đây
Họ tênKhóaTrạng thái
🛍️ Đơn bán lẻ gần đây
KháchSản phẩmTiềnTT
⚠️ Cảnh báo tồn kho
Nguyên liệuTồn khoTối thiểuTrạng thái
Tất cả
📅 Lịch học
Online
Offline
🗑 Đã xóa
📚 Khóa học
Danh sách học viên
Họ tênKhóa họcKênh LLHọc phíNgày họcThanh toánTrạng thái
🛒 Bán hàng
📋 Đơn hàng
📦 Bán NVL
Chọn sản phẩm
🛒 Giỏ hàng
Tổng cộng 0 ₫
📦 Kho nguyên liệu
🏠 Dashboard
🏭 NCC
📋 PO
🛍 Hàng hóa
Tổng giá trị kho (₫)
Loại nguyên liệu
Sắp hết hàng
Tổng nhập kho (số lượng)
Tổng xuất kho (số lượng)
Tình trạng tồn kho
Mã HHNguyên liệuĐơn vị Tồn khoTối thiểuGiá nhậpGiá trị HHMức tồn
Lịch sử nhập/xuất
Thời gianNguyên liệuLoạiSố lượngGhi chú
0
Tổng khách
0
VIP / Gold
0
Tổng doanh thu (₫)
0
Mới tháng này
👥 Danh sách khách hàng
Khách hàng Nhãn / Điểm Nguồn Tổng chi tiêu Lần mua Lần cuối

👥 Nhân sự

0
👤 Tổng nhân viên
0
💰 Tổng lương tháng này
0
📅 Ngày công TB
0
⏰ Đi trễ tháng này
👤 Nhân viên
📅 Chấm công
💰 Bảng lương
Danh sách nhân viên

🏭 Sản xuất & Đóng gói

0
⏳ Đang sản xuất
0
✅ Hoàn thành tháng này
0
📦 NVL tiêu hao (₫)
0
📊 Sản lượng tháng này
📋 Lệnh SX
🧪 Định mức NVL
📅 Lịch sử
📋 Lệnh sản xuất

📒 Kế toán

0
💼 Tổng tài sản
0
📋 Tổng chi phí
0
💰 Vốn chủ sở hữu
0
📊 Lợi nhuận tháng
📔 Nhật ký chung
📒 Sổ cái
⚖️ Cân đối kế toán
📊 Kết quả KD
🧾 Thuế VAT
📔 Nhật ký chung

🎯 CRM — Chăm sóc khách hàng

0
👥 Tổng khách
0
⚠️ Cần chăm sóc
0
😴 Không hoạt động
0
⭐ VIP/Gold
0₫
💬 Pipeline value
0₫
🏆 Doanh thu SO
0
📋 SO đang xử lý
0
⏰ SO quá hạn
📋 Pipeline
💬 Báo giá
📦 Sales Orders
✅ Công việc
🎯 Phân khúc
📅 Lịch sử

💸 Quản lý Chi phí

0
Tổng chi (tháng này)
0
Định phí
0
Biến phí
% Ngân sách
Danh sách chi phí
📊 Chi tiết theo nhóm
💰 Thu Chi
💸 Chi phí
📊 Báo cáo
💧 Tính Cost
🚚 COD
🔍 Audit
Tất cả
💚 Thu
🔴 Chi
📦 Thu chi NVL
0
Tổng thu (₫)
0
Tổng chi (₫)
0
Lợi nhuận (₫)
Tất cả giao dịch
Thời gianLoạiDanh mụcSố tiềnGhi chú
🧋 Danh sách món
🧂 Nguyên liệu (DMHH)
🧪 Bán thành phẩm
0
Số món
0%
% Cost trung bình
0
Lợi nhuận TB (₫)
0
Cost cao (>35%)
\
Tên món Size Giá bán Cost NL % Cost LN/ly Đánh giá
💡 Chuẩn cost F&B đồ uống:  🟢 Tốt <25%  |  🟡 Chấp nhận 25–35%  |  🔴 Cần xem lại >35%
🛒 Đơn NVL
💳 Công nợ
📊 Báo cáo
0
Tổng đơn
0
Chờ thanh toán
0
Doanh thu (₫)
0
Còn nợ (₫)
Mã đơnKhách hàngSản phẩm Tổng tiền Đã trả Trạng thái Ngày
0
Học hôm nay
0
Tuần này
0
Đang học
0
Chưa TT
🔔 Báo cáo lịch học ngày mai (Telegram + Zalo)
Báo cáo này chạy tự động phía server mỗi tối (không cần mở app), liệt kê số học viên, tên, khóa học, giờ học, loại và số tiền đã thu — gửi cùng lúc lên cả Telegram và Zalo. Để bật chạy tự động: vào Apps Script → Trình kích hoạt (⏰) → + Thêm trình kích hoạt → chọn hàm sendTomorrowClassReport → Time-driven → Day timer → chọn khung giờ (VD 20:00–21:00). Nút bên phải để gửi thử ngay, kiểm tra nội dung trước khi bật lịch tự động.
T2
T3
T4
T5
T6
T7
CN
Lịch học chi tiết
Học viênKhóa họcNgày học Thanh toán Trạng thái
🛒 Bán hàng
📅 Theo tháng
📊 Lãi Lỗ
💧 Đồ uống
📋 Chuẩn bị hàng
📦 Xuất nhập kho
🎓 Học viên
0
Tổng doanh thu
0
Đơn đã thu tiền
0
Trung bình/đơn
🏆 Sản phẩm bán chạy
💰 Doanh thu theo sản phẩm
📅 Doanh thu theo ngày (30 ngày gần nhất)
Kết nối Telegram Bot
Báo cáo tự động gửi về nhóm của team
Chưa kết nối
Dán URL Apps Script Web App vào đây để sync real-time
Za
Kết nối Zalo Bot
Thông báo tự động gửi qua Zalo — không cần Zalo OA
Chưa kết nối
Cách lấy Bot Token: Mở Zalo trên điện thoại → quét mã QR tại zalo.me/s/botcreator → đặt tên bot (phải bắt đầu bằng chữ "Bot", VD: "Bot Trương Dáng Hương") → Zalo sẽ nhắn Token về ngay trong Zalo. Sau đó, tự nhắn tin cho bot vừa tạo 1 câu bất kỳ rồi bấm "Lấy Chat ID" bên dưới.
⭐ Cài đặt tích điểm khách hàng
Mỗi khi khách thanh toán, hệ thống tự động tích điểm theo tỷ lệ bạn cài đặt bên dưới.
Khách chi 1.000₫ → được 1 điểm
100 điểm = 10.000₫
Ví dụ: Khách mua đơn 100.000₫ → tích được 100 điểm → quy ra 10.000₫
Hạng thành viên:
🥉
Member
điểm trở lên
🥈
Silver
điểm trở lên
🥇
Gold
điểm trở lên
💎
VIP
điểm trở lên
Báo cáo tự động
⏰ Nhắc tự động hàng ngày
ℹ️ Báo cáo gồm: học viên đang học, đơn chờ thu tiền, kho sắp hết. Cần để tab app mở 8h sáng, hoặc set trigger trong Google Apps Script để chạy kể cả khi đóng app.
Báo cáo thủ công
🔑 Đổi mật khẩu
Đang đăng nhập:
💡 Mật khẩu được lưu trên trình duyệt này. Nếu muốn đổi trên thiết bị khác, cần thực hiện lại trên thiết bị đó.
💾 Backup & Restore dữ liệu
🛡️ Backup định kỳ để tránh mất dữ liệu. File JSON có thể dùng để khôi phục toàn bộ. File Excel để xem và lưu trữ lâu dài.
🔧 Cần chạy SQL migration (1 lần) nếu chưa làm
Thêm các cột mới vào bảng orders trong Supabase. Chỉ cần làm 1 lần.
Hoặc chạy thủ công trong Supabase → SQL Editor:
ALTER TABLE orders
  ADD COLUMN IF NOT EXISTS phone TEXT DEFAULT '',
  ADD COLUMN IF NOT EXISTS address TEXT DEFAULT '',
  ADD COLUMN IF NOT EXISTS payment TEXT DEFAULT '',
  ADD COLUMN IF NOT EXISTS shipping TEXT DEFAULT '',
  ADD COLUMN IF NOT EXISTS tracking_url TEXT DEFAULT '',
  ADD COLUMN IF NOT EXISTS discount NUMERIC DEFAULT 0,
  ADD COLUMN IF NOT EXISTS subtotal NUMERIC DEFAULT 0,
  ADD COLUMN IF NOT EXISTS ship_fee NUMERIC DEFAULT 0,
  ADD COLUMN IF NOT EXISTS tracking_code TEXT DEFAULT '';

ALTER TABLE products
  ADD COLUMN IF NOT EXISTS unit TEXT DEFAULT '';

CREATE TABLE IF NOT EXISTS app_users (
  username TEXT PRIMARY KEY,
  pass_hash TEXT NOT NULL,
  updated_at TIMESTAMPTZ DEFAULT NOW()
);
ALTER TABLE app_users ENABLE ROW LEVEL SECURITY;
CREATE POLICY IF NOT EXISTS "allow_all" ON app_users FOR ALL USING (true) WITH CHECK (true);

CREATE TABLE IF NOT EXISTS nvl_orders (
  id TEXT PRIMARY KEY, customer TEXT, phone TEXT, address TEXT,
  items JSONB DEFAULT '[]', total NUMERIC DEFAULT 0, paid NUMERIC DEFAULT 0,
  status TEXT DEFAULT 'Chờ xác nhận', delivery_date TEXT, note TEXT,
  created_at BIGINT DEFAULT EXTRACT(EPOCH FROM NOW())*1000
);
ALTER TABLE nvl_orders ENABLE ROW LEVEL SECURITY;
CREATE POLICY IF NOT EXISTS "allow_all" ON nvl_orders FOR ALL USING (true) WITH CHECK (true);
Xuất backup
Khôi phục từ backup JSON
Chưa chọn file
📋 Google Apps Script — Cập nhật code đầy đủ
⚠️ Sheet HocVien đang trống? Bạn cần thay toàn bộ nội dung file Apps Script bằng code dưới đây rồi Deploy lại → Manage Deployments → chọn deployment cũ → Edit → New version → Deploy.
const TG_TOKEN = 'YOUR_BOT_TOKEN'; const CHAT_ID = 'YOUR_CHAT_ID'; function doPost(e) { try { // Nhận từ FormData (payload field) hoặc JSON body const raw = (e.parameter && e.parameter.payload) ? e.parameter.payload : e.postData.contents; const data = JSON.parse(raw); const ss = SpreadsheetApp.getActiveSpreadsheet(); const sheet = data.sheet; if (sheet === 'HocVien' && data.rows) { const sh = ss.getSheetByName('HocVien') || ss.insertSheet('HocVien'); sh.clearContents(); const headers = ['ID','Họ tên','SĐT','Loại','Khóa học','Học phí','Ngày ĐK','Trạng thái','Email','Ngày học','Đợt 1','Thời gian Đ1','Đợt 2','Thời gian Đ2','Ghi chú','Cập nhật']; sh.getRange(1, 1, 1, headers.length).setValues([headers]).setFontWeight('bold'); if (data.rows.length) { const rows = data.rows.map(s => [ s.id||'', s.name||'', s.phone||'', s.type||'', s.course||'', s.fee||0, s.start||'', s.status||'', s.email||'', s.class_date||'', s.paid1||'Chưa thu', s.paid1_at||'', s.paid2||'Chưa thu', s.paid2_at||'', s.note||'', data.time||'' ]); sh.getRange(2, 1, rows.length, headers.length).setValues(rows); } } else if (sheet === 'TonKho' && data.rows) { const sh = ss.getSheetByName('TonKho') || ss.insertSheet('TonKho'); sh.clearContents(); const headers = ['ID','Tên nguyên liệu','Tồn kho','Đơn vị','Tối thiểu','Giá nhập','Cập nhật']; sh.getRange(1,1,1,headers.length).setValues([headers]).setFontWeight('bold'); if (data.rows.length) { const rows = data.rows.map(r => [r.id||'',r.name||'',r.qty||0,r.unit||'',r.min||0,r.cost||0,data.time||'']); sh.getRange(2,1,rows.length,headers.length).setValues(rows); } } else if (sheet === 'DonHang') { const sh = ss.getSheetByName('DonHang') || ss.insertSheet('DonHang'); if (sh.getLastRow() === 0) sh.getRange(1,1,1,13).setValues([['Mã ĐH','Khách','Sản phẩm','Tạm tính','CK(%)','VAT(%)','Tổng TT','Thanh toán','Giao hàng','Địa chỉ','Trạng thái','Thời gian','Ghi chú']]).setFontWeight('bold'); // Dedup by ID const existIds=sh.getLastRow()>1?sh.getRange(2,1,sh.getLastRow()-1,1).getValues().map(r=>r[0]):[]; if(existIds.indexOf(data.id)===-1){ sh.appendRow([data.id||'',data.customer||'',data.items||'', data.subtotal||data.total||0,data.discount||0,data.vat||0,data.total||0, data.payment||'',data.shipping||'',data.address||'', data.status||'',data.time||'',data.note||'']); } else { // Update status only const allR=sh.getDataRange().getValues(); for(var ki=1;ki 0) { const r5 = data.rows.map(t => [ t.id||'', t.type||'', t.category||'', t.amount||0, t.note||'', t.time||'', t.auto||'' ]); sh5.getRange(2,1,r5.length,h5.length).setValues(r5); r5.forEach((r,i) => { sh5.getRange(i+2,1,1,h5.length).setBackground(r[1]==='Thu'?'#f0fff4':'#fff0f0'); }); // Dòng tổng kết const thuTotal = r5.filter(r=>r[1]==='Thu').reduce((a,r)=>a+(+r[3]||0),0); const chiTotal = r5.filter(r=>r[1]==='Chi').reduce((a,r)=>a+(+r[3]||0),0); const lastRow = r5.length + 2; sh5.getRange(lastRow,1,1,h5.length).setBackground('#fff8e1'); sh5.getRange(lastRow,1).setValue('TỔNG KẾT').setFontWeight('bold'); sh5.getRange(lastRow,2).setValue('Thu: '+thuTotal.toLocaleString()+'đ').setFontWeight('bold').setFontColor('#1a7a1a'); sh5.getRange(lastRow,3).setValue('Chi: '+chiTotal.toLocaleString()+'đ').setFontWeight('bold').setFontColor('#cc0000'); sh5.getRange(lastRow,4).setValue(thuTotal-chiTotal).setFontWeight('bold').setFontColor(thuTotal>=chiTotal?'#1a7a1a':'#cc0000'); sh5.getRange(lastRow,5).setValue('Lợi nhuận').setFontWeight('bold'); } } return ContentService.createTextOutput(JSON.stringify({ok:true})).setMimeType(ContentService.MimeType.JSON); } catch(err) { return ContentService.createTextOutput(JSON.stringify({ok:false,error:err.toString()})).setMimeType(ContentService.MimeType.JSON); } } // ═══════════════════════════════════════════════════ // BÁO CÁO TỰ ĐỘNG 8H SÁNG // Set Trigger: Apps Script → Triggers → sendDailyReport8am → Time-driven → Day timer → 8-9am // ═══════════════════════════════════════════════════ function sendDailyReport8am() { const ss = SpreadsheetApp.getActiveSpreadsheet(); const shSt = ss.getSheetByName('HocVien'); const shOrd = ss.getSheetByName('DonHang'); const shStock = ss.getSheetByName('TonKho'); const today = new Date(); today.setHours(0, 0, 0, 0); const fmtMoney = n => (+n||0).toLocaleString('vi-VN') + 'đ'; const todayStr = Utilities.formatDate(today, 'Asia/Ho_Chi_Minh', 'dd/MM/yyyy'); // ── Học viên ── let activeCount = 0, activeOnline = 0, activeOffline = 0, unpaid1 = [], unpaid2 = [], endingSoon = []; if (shSt && shSt.getLastRow() > 1) { const rows = shSt.getDataRange().getValues(); const heads = rows[0]; const col = h => heads.indexOf(h); rows.slice(1).forEach(r => { const name = r[col('Họ tên')] || ''; const status = r[col('Trạng thái')] || ''; const course = r[col('Khóa học')] || ''; const fee = +r[col('Học phí')] || 0; const type = r[col('Loại')] || ''; const paid1 = r[col('Đợt 1')] || ''; const paid2 = r[col('Đợt 2')] || ''; const endDate = r[col('Ngày KT')] || ''; if (status === 'Đang học') { activeCount++; if(type==='Online') activeOnline++; else activeOffline++; } if (fee > 0 && paid1 !== 'Đã thu') unpaid1.push(name + ' — ' + fmtMoney(+r[col('paid1_amount')]||Math.round(fee * 0.3))); if (fee > 0 && paid1 === 'Đã thu' && paid2 !== 'Đã thu' && type === 'Offline') { const rest = +r[col('paid2_amount')] || (fee - Math.round(fee * 0.3)); let suffix = ''; if (endDate) { const ed = new Date(endDate); ed.setHours(0,0,0,0); const d = Math.round((ed - today) / 86400000); suffix = d === 0 ? ' ⚠️ KT HÔM NAY' : ' (còn ' + d + ' ngày)'; if (d >= 0 && d <= 3) endingSoon.push(name + ' — ' + (d===0?'HÔM NAY':'còn '+d+' ngày') + (paid2==='Đã thu'?' ✅':' ❌ chưa thu đợt 2')); } unpaid2.push(name + ' — ' + fmtMoney(rest) + suffix); } }); } // ── Đơn hàng hôm nay ── let todayRev = 0, todayCount = 0; if (shOrd && shOrd.getLastRow() > 1) { shOrd.getDataRange().getValues().slice(1).forEach(r => { if ((r[5]||'').toString().includes(todayStr) && r[4]==='Đã thanh toán' && !(r[0]||'').toString().startsWith('HP')) { todayRev += +r[3]||0; todayCount++; } }); } // ── Kho sắp hết ── let lowStock = []; if (shStock && shStock.getLastRow() > 1) { const sRows = shStock.getDataRange().getValues(); const sHeads = sRows[0]; const sc = h => sHeads.indexOf(h); sRows.slice(1).forEach(r => { const qty = +r[sc('Tồn kho')]||0, min = +r[sc('Tối thiểu')]||0; if (qty <= min) lowStock.push(r[sc('Tên nguyên liệu')] + ': còn ' + qty + ' ' + (r[sc('Đơn vị')]||'')); }); } // ── Build message ── const d = Utilities.formatDate(today, 'Asia/Ho_Chi_Minh', 'dd/MM/yyyy'); let msg = '🌅 *BÁO CÁO SÁNG — ' + d + '* ━━━━━━━━━━━━━━━━ '; msg += '🎓 *HỌC VIÊN ĐANG HỌC: ' + activeCount + ' người* '; if(activeOffline>0) msg += '• Offline: ' + activeOffline + ' người '; if(activeOnline>0) msg += '• Online: ' + activeOnline + ' người '; if (unpaid1.length) { msg += ' 💳 *CHƯA THU ĐỢT 1 (' + unpaid1.length + ')* '; unpaid1.forEach(s => msg += '• ' + s + ' '); } if (unpaid2.length) { msg += ' 💸 *CHƯA THU ĐỢT 2 (' + unpaid2.length + ')* '; unpaid2.forEach(s => msg += '• ' + s + ' '); } if (endingSoon.length) { msg += ' 🏁 *KẾT THÚC KHÓA SẮP TỚI* '; endingSoon.forEach(s => msg += '• ' + s + ' '); } if (todayRev > 0) { msg += ' 🛍️ *HÔM NAY* • ' + todayCount + ' đơn — ' + fmtMoney(todayRev) + ' '; } if (lowStock.length) { msg += ' ⚠️ *KHO SẮP HẾT* '; lowStock.forEach(s => msg += '• ' + s + ' '); } msg += ' ━━━━━━━━━━━━━━━━ _Trương Dáng Hương Academy_'; UrlFetchApp.fetch('https://api.telegram.org/bot' + TG_TOKEN + '/sendMessage', { method: 'post', payload: { chat_id: CHAT_ID, text: msg, parse_mode: 'Markdown' } }); } // Giữ hàm cũ để tương thích trigger cũ function sendDailyReminders() { sendDailyReport8am(); }
B1 — Mở Google Apps Script → thay TOÀN BỘ code bằng đoạn trên → điền YOUR_BOT_TOKENYOUR_CHAT_ID
B2 — Deploy → Manage deployments → chọn deployment cũ → ✏️ Edit → New version → Deploy lại
B3 — Triggers → Add trigger → hàm sendDailyReminders → Time-driven → Day timer → 8:00–9:00 AM
B4 — Quay lại app → Cài đặt → bấm "Sync toàn bộ → Google Sheet" để đẩy data lên ngay
Nhật ký gửi
Chưa có hoạt động...
Hướng dẫn tạo Telegram Bot
B1 — Tìm @BotFather trên Telegram → /newbot
B2 — Đặt tên & username (kết thúc _bot) → Copy Bot Token
B3 — Tạo group, thêm bot, đặt bot là Admin
B4 — Vào api.telegram.org/bot[TOKEN]/getUpdates → lấy chat.id