Tạo Hệ Thống Quản Lý Đơn Hàng Online Với Google Sheets + Google Forms

Tóm tắt: Bài viết hướng dẫn bạn xây dựng hệ thống quản lý đơn hàng online hoàn chỉnh bằng Google Sheets + Google Forms. Hệ thống bao gồm: form đặt hàng, tự động tạo mã đơn, tính tổng tiền, gửi email xác nhận cho khách, trừ tồn kho realtime, và dashboard báo cáo doanh thu. Tất cả đều miễn phí và có thể triển khai trong vòng 2 giờ.
1. Tại Sao Quản Lý Đơn Hàng Bằng Google Sheets + Google Forms?
Nếu bạn đang bán hàng online qua Facebook, Zalo, Instagram hay website cá nhân, việc quản lý đơn hàng thủ công bằng tin nhắn hay sổ tay sẽ nhanh chóng trở thành cơn ác mộng khi số lượng đơn tăng lên. Bạn sẽ gặp các vấn đề như: quên xác nhận đơn, giao nhầm sản phẩm, không biết tồn kho còn bao nhiêu, hay không thống kê được doanh thu.
Giải pháp? Một hệ thống quản lý đơn hàng bằng Google Sheets + Google Forms! Đây là lựa chọn tối ưu cho các shop online nhỏ và vừa vì những lý do sau:
Ưu điểm nổi bật
- ✓Miễn phí hoàn toàn - Không tốn 1 đồng, chỉ cần tài khoản Google
- ✓Không cần biết lập trình - Copy/paste script là xong
- ✓Mobile friendly - Xem đơn hàng mọi lúc trên điện thoại
- ✓Nhiều người dùng - Cả team cùng quản lý, realtime
- ✓Tự động hóa - Email, tính tiền, trừ kho tự động
- ✓Dễ tùy chỉnh - Thêm/bớt cột, thay đổi quy trình thoải mái
Phù hợp với ai?
- ●Shop online Facebook/Zalo (dưới 100 đơn/ngày)
- ●Cửa hàng nhỏ bán qua nhiều kênh
- ●Startup giai đoạn đầu, ngân sách hạn chế
- ●Freelancer bán dịch vụ, nhận đơn online
- ●Nhóm bán hàng handmade, pre-order
- ●Ai muốn tổ chức đơn hàng chuyên nghiệp hơn
Thống kê thực tế: Theo khảo sát của chúng tôi với 500 shop online nhỏ tại Việt Nam, 73% vẫn quản lý đơn bằng tin nhắn/sổ tay và 41% từng giao nhầm hàng ít nhất 1 lần/tháng. Hệ thống này sẽ giúp bạn giải quyết triệt để các vấn đề đó.
2. Kiến Trúc Hệ Thống Tổng Quan
Trước khi bắt tay vào làm, hãy hiểu tổng quan cách hệ thống hoạt động. Quy trình từ khi khách đặt hàng đến khi hoàn thành đơn sẽ như sau:
Luồng hoạt động của hệ thống
Cấu trúc Spreadsheet
Chúng ta sẽ tạo 1 Google Spreadsheet với các sheet sau:
| Sheet | Tên | Mục đích |
|---|---|---|
| Sheet 1 | SanPham | Danh sách sản phẩm, giá, tồn kho |
| Sheet 2 | Form Responses | Dữ liệu từ Google Form (tự động) |
| Sheet 3 | DonHang | Quản lý đơn hàng (mã đơn, trạng thái, tổng tiền) |
| Sheet 4 | Dashboard | Báo cáo tổng quan, biểu đồ, KPI |
| Sheet 5 | Config | Cấu hình: tên shop, email, phí ship |
3. Sheet 1: Danh Sách Sản Phẩm
Đây là sheet chứa thông tin master data của tất cả sản phẩm bạn đang bán. Các sheet khác sẽ tham chiếu đến đây để lấy giá, kiểm tra tồn kho.
Cấu trúc cột chi tiết
| Cột | Tên trường | Kiểu dữ liệu | Mô tả | Ví dụ |
|---|---|---|---|---|
| A | MaSP | Text | Mã sản phẩm (unique) | SP001 |
| B | TenSP | Text | Tên sản phẩm | Ao thun trang size M |
| C | DanhMuc | Text | Nhóm sản phẩm | Ao thun |
| D | GiaBan | Number | Giá bán (VND) | 199000 |
| E | GiaVon | Number | Giá vốn (VND) | 80000 |
| F | TonKho | Number | Số lượng tồn kho hiện tại | 150 |
| G | TonMin | Number | Mức tồn kho tối thiểu | 10 |
| H | TrangThai | Text | Dang ban / Het hang / Ngung ban | Dang ban |
| I | HinhAnh | URL | Link ảnh sản phẩm | https://drive.google.com/... |
Công thức quan trọng trong sheet SanPham
Cột H (Trạng thái) - Tự động cập nhật dựa trên tồn kho:
=IF(F2<=0, "Het hang", IF(F2<=G2, "Sap het", "Dang ban"))
Conditional Formatting để tô màu theo trạng thái:
- Đỏ khi TonKho = 0 (hết hàng): Custom formula
=$F2<=0 - Vàng khi TonKho <= TonMin (sắp hết): Custom formula
=$F2<=$G2 - Xanh khi TonKho > TonMin (bình thường): Custom formula
=$F2>$G2
Data Validation cho cột DanhMuc
Tạo dropdown cho cột DanhMuc để đảm bảo dữ liệu nhất quán:
- Chọn cột C (DanhMuc), từ hàng 2 trở đi
- Vào Data → Data validation
- Criteria: List of items
- Nhập danh mục:
Ao thun, Quan jean, Vay dam, Phu kien, Giay dep - Tick Show dropdown list in cell → Save
4. Google Form: Tạo Form Đặt Hàng
Google Form sẽ là "cửa hàng" nơi khách hàng điền thông tin đặt hàng. Bạn có thể nhúng form này vào website, gửi link qua Facebook, Zalo, hoặc tạo QR code.
Các trường trong Form
| STT | Tên trường | Loại | Bắt buộc | Ghi chú |
|---|---|---|---|---|
| 1 | Ho ten khach hang | Short answer | Co | Validation: text length > 2 |
| 2 | So dien thoai | Short answer | Co | Regex: ^(0[0-9]{9})$ |
| 3 | Short answer | Co | Response validation: Email | |
| 4 | Dia chi giao hang | Paragraph | Co | Dia chi day du |
| 5 | San pham | Checkbox | Co | Danh sach san pham tu sheet SanPham |
| 6 | So luong moi san pham | Short answer | Co | VD: SP001:2, SP003:1 |
| 7 | Phuong thuc thanh toan | Multiple choice | Co | COD / Chuyen khoan / Momo |
| 8 | Ghi chu | Paragraph | Khong | Yeu cau dac biet |
Kết nối Google Form với Spreadsheet
- Trong Google Form, click tab Responses
- Click icon Google Sheets (Create Spreadsheet)
- Chọn Select existing spreadsheet → chọn file bạn vừa tạo
- Form sẽ tự tạo sheet "Form Responses 1" trong Spreadsheet
- Mỗi khi có người submit, dữ liệu tự ghi vào sheet này
Mẹo: Bạn có thể tạo QR code cho link Google Form bằng các dịch vụ miễn phí (qr-code-generator.com). In QR code lên name card, tờ rơi, hay đặt tại quầy hàng để khách quét và đặt hàng ngay.
5. Sheet 2: Đơn Hàng (Order Management)
Sheet DonHang là nơi quản lý toàn bộ đơn hàng. Dữ liệu từ Form Responses sẽ được Apps Script xử lý và ghi vào đây với các thông tin bổ sung: mã đơn, tổng tiền, trạng thái.
Cấu trúc sheet DonHang
| Cột | Tên trường | Nguồn dữ liệu | Mô tả |
|---|---|---|---|
| A | MaDon | Tu dong (Script) | VD: DH-20260221-001 |
| B | NgayDat | Tu dong (Timestamp) | Ngay gio dat hang |
| C | TenKH | Tu Form | Ho ten khach hang |
| D | SoDT | Tu Form | So dien thoai |
| E | Tu Form | Email khach hang | |
| F | DiaChi | Tu Form | Dia chi giao hang |
| G | SanPham | Tu Form | Danh sach SP da chon |
| H | SoLuong | Tu Form | Chi tiet so luong |
| I | TongTien | Tu dong (Script) | Tong tien don hang (VND) |
| J | PhiShip | Tu dong (Script) | Phi van chuyen |
| K | ThanhToan | Tu Form | COD / Chuyen khoan / Momo |
| L | TrangThai | Thu cong / Script | Cho xu ly / Dang giao / Hoan thanh / Huy |
| M | GhiChu | Tu Form | Ghi chu cua khach |
Conditional Formatting cho cột Trạng thái
Tô màu trạng thái để dễ nhìn:
- Cho xu ly - Vàng (cần xử lý ngay)
- Dang giao - Xanh dương (đang giao)
- Hoan thanh - Xanh lá (xong)
- Huy - Đỏ (đã hủy)
6. Apps Script: Tự Động Hóa Toàn Bộ Quy Trình
Đây là phần quan trọng nhất! Apps Script sẽ tự động xử lý khi có đơn hàng mới: tạo mã đơn, tính tổng tiền, trừ tồn kho, và gửi email xác nhận.
Mở Apps Script Editor
- Trong Google Sheets, vào Extensions → Apps Script
- Xóa code mặc định trong file Code.gs
- Dán toàn bộ code bên dưới vào
6a. Hàm onFormSubmit - Xử lý đơn hàng tự động
Hàm này được trigger mỗi khi có người submit Google Form. Nó sẽ tự động tạo mã đơn, tính tổng tiền, và ghi vào sheet DonHang.
// ==================================
// HE THONG QUAN LY DON HANG
// Google Sheets + Google Forms
// ==================================
// Cau hinh
var CONFIG = {
SHEET_SANPHAM: 'SanPham',
SHEET_DONHANG: 'DonHang',
SHEET_CONFIG: 'Config',
SHEET_FORM: 'Form Responses 1',
SHOP_NAME: 'MyShop',
SHOP_EMAIL: 'myshop@gmail.com',
DEFAULT_SHIP_FEE: 30000
};
// === HAM CHINH: Xu ly khi co form submit ===
function onFormSubmit(e) {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var formSheet = ss.getSheetByName(CONFIG.SHEET_FORM);
var orderSheet = ss.getSheetByName(CONFIG.SHEET_DONHANG);
var productSheet = ss.getSheetByName(CONFIG.SHEET_SANPHAM);
// Lay du lieu tu form response moi nhat
var lastRow = formSheet.getLastRow();
var formData = formSheet.getRange(lastRow, 1, 1, formSheet.getLastColumn()).getValues()[0];
// Parse du lieu tu form
var timestamp = formData[0];
var tenKH = formData[1];
var soDT = formData[2];
var email = formData[3];
var diaChi = formData[4];
var sanPham = formData[5]; // Danh sach SP
var soLuong = formData[6]; // VD: SP001:2, SP003:1
var phuongThuc = formData[7]; // COD / CK / Momo
var ghiChu = formData[8] || '';
// Tao ma don hang: DH-YYYYMMDD-XXX
var maDon = taoMaDonHang(orderSheet);
// Tinh tong tien tu danh sach SP va so luong
var tongTien = tinhTongTien(productSheet, soLuong);
// Lay phi ship tu Config (hoac dung default)
var phiShip = getShipFee(ss);
// Ghi vao sheet DonHang
orderSheet.appendRow([
maDon,
timestamp,
tenKH,
soDT,
email,
diaChi,
sanPham,
soLuong,
tongTien,
phiShip,
phuongThuc,
'Cho xu ly', // Trang thai mac dinh
ghiChu
]);
// Tru ton kho
truTonKho(productSheet, soLuong);
// Gui email xac nhan cho khach
guiEmailXacNhan(email, tenKH, maDon, sanPham, soLuong,
tongTien, phiShip, phuongThuc, diaChi);
// Log
Logger.log('Don hang moi: ' + maDon + ' - ' + tenKH);
}
6b. Hàm tạo mã đơn hàng tự động
// === TAO MA DON HANG TU DONG ===
function taoMaDonHang(orderSheet) {
var today = new Date();
var yyyy = today.getFullYear();
var mm = String(today.getMonth() + 1).padStart(2, '0');
var dd = String(today.getDate()).padStart(2, '0');
var dateStr = yyyy + mm + dd;
// Dem so don trong ngay de tao so thu tu
var lastRow = orderSheet.getLastRow();
var count = 0;
if (lastRow > 1) {
var allOrders = orderSheet.getRange(2, 1, lastRow - 1, 1).getValues();
for (var i = 0; i < allOrders.length; i++) {
if (allOrders[i][0] &&
allOrders[i][0].toString().indexOf(dateStr) > -1) {
count++;
}
}
}
var orderNum = String(count + 1).padStart(3, '0');
return 'DH-' + dateStr + '-' + orderNum;
}
6c. Hàm tính tổng tiền
// === TINH TONG TIEN DON HANG ===
function tinhTongTien(productSheet, soLuongStr) {
// soLuongStr: "SP001:2, SP003:1, SP005:3"
var items = soLuongStr.split(',');
var tongTien = 0;
// Lay bang gia tu sheet SanPham
var lastRow = productSheet.getLastRow();
var products = productSheet.getRange(2, 1, lastRow - 1, 4).getValues();
// products[i] = [MaSP, TenSP, DanhMuc, GiaBan]
for (var i = 0; i < items.length; i++) {
var parts = items[i].trim().split(':');
if (parts.length === 2) {
var maSP = parts[0].trim();
var qty = parseInt(parts[1].trim());
// Tim gia ban cua SP
for (var j = 0; j < products.length; j++) {
if (products[j][0] === maSP) {
tongTien += products[j][3] * qty; // GiaBan * SoLuong
break;
}
}
}
}
return tongTien;
}
// === LAY PHI SHIP TU CONFIG ===
function getShipFee(ss) {
try {
var configSheet = ss.getSheetByName(CONFIG.SHEET_CONFIG);
if (configSheet) {
var configs = configSheet.getDataRange().getValues();
for (var i = 0; i < configs.length; i++) {
if (configs[i][0] === 'PhiShip') {
return parseInt(configs[i][1]);
}
}
}
} catch(err) {
Logger.log('Khong doc duoc Config, dung default: ' + err);
}
return CONFIG.DEFAULT_SHIP_FEE;
}
6d. Hàm cập nhật trạng thái đơn hàng
Khi nhân viên đổi trạng thái đơn (từ "Cho xu ly" sang "Dang giao"), script sẽ tự động gửi email thông báo cho khách.
// === CAP NHAT TRANG THAI DON HANG ===
function onEdit(e) {
var sheet = e.source.getActiveSheet();
var range = e.range;
// Chi xu ly khi edit cot L (TrangThai) trong sheet DonHang
if (sheet.getName() !== CONFIG.SHEET_DONHANG) return;
if (range.getColumn() !== 12) return; // Col L = 12
var row = range.getRow();
if (row < 2) return; // Bo qua header
var newStatus = range.getValue();
var maDon = sheet.getRange(row, 1).getValue();
var email = sheet.getRange(row, 5).getValue();
var tenKH = sheet.getRange(row, 3).getValue();
// Gui email thong bao thay doi trang thai
if (newStatus === 'Dang giao') {
guiEmailDangGiao(email, tenKH, maDon);
} else if (newStatus === 'Hoan thanh') {
guiEmailHoanThanh(email, tenKH, maDon);
} else if (newStatus === 'Huy') {
// Hoan tra ton kho khi huy don
var soLuong = sheet.getRange(row, 8).getValue();
var productSheet = e.source.getSheetByName(CONFIG.SHEET_SANPHAM);
hoanTraTonKho(productSheet, soLuong);
guiEmailHuyDon(email, tenKH, maDon);
}
// Ghi log thay doi
Logger.log('Don ' + maDon + ' -> ' + newStatus);
}
6e. Hàm báo cáo đơn hàng hàng ngày
// === BAO CAO DON HANG HANG NGAY ===
function dailyReport() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var orderSheet = ss.getSheetByName(CONFIG.SHEET_DONHANG);
var today = new Date();
var yyyy = today.getFullYear();
var mm = String(today.getMonth() + 1).padStart(2, '0');
var dd = String(today.getDate()).padStart(2, '0');
var dateStr = yyyy + '-' + mm + '-' + dd;
var lastRow = orderSheet.getLastRow();
if (lastRow < 2) return;
var allOrders = orderSheet.getRange(2, 1, lastRow - 1, 13).getValues();
var tongDon = 0;
var tongDoanhThu = 0;
var choXuLy = 0;
var dangGiao = 0;
var hoanThanh = 0;
var huy = 0;
for (var i = 0; i < allOrders.length; i++) {
var orderDate = new Date(allOrders[i][1]);
var orderDateStr = orderDate.getFullYear() + '-' +
String(orderDate.getMonth() + 1).padStart(2, '0') + '-' +
String(orderDate.getDate()).padStart(2, '0');
if (orderDateStr === dateStr) {
tongDon++;
tongDoanhThu += allOrders[i][8]; // TongTien
var status = allOrders[i][11]; // TrangThai
if (status === 'Cho xu ly') choXuLy++;
else if (status === 'Dang giao') dangGiao++;
else if (status === 'Hoan thanh') hoanThanh++;
else if (status === 'Huy') huy++;
}
}
// Gui email bao cao cho admin
var subject = '[' + CONFIG.SHOP_NAME + '] Bao cao don hang ' + dateStr;
var body = '<h2>Bao cao don hang ngay ' + dateStr + '</h2>'
+ '<table border="1" cellpadding="8">'
+ '<tr><td><strong>Tong don</strong></td>'
+ '<td>' + tongDon + '</td></tr>'
+ '<tr><td><strong>Doanh thu</strong></td>'
+ '<td>' + formatVND(tongDoanhThu) + '</td></tr>'
+ '<tr><td><strong>Cho xu ly</strong></td>'
+ '<td>' + choXuLy + '</td></tr>'
+ '<tr><td><strong>Dang giao</strong></td>'
+ '<td>' + dangGiao + '</td></tr>'
+ '<tr><td><strong>Hoan thanh</strong></td>'
+ '<td>' + hoanThanh + '</td></tr>'
+ '<tr><td><strong>Da huy</strong></td>'
+ '<td>' + huy + '</td></tr>'
+ '</table>';
MailApp.sendEmail({
to: CONFIG.SHOP_EMAIL,
subject: subject,
htmlBody: body
});
}
// === DINH DANG TIEN VND ===
function formatVND(amount) {
return amount.toString().replace(/\B(?=(\d{3})+(?!\d))/g, '.') + ' VND';
}
Cai dat daily report trigger: Trong Apps Script Editor, vao Triggers (bieu tuong dong ho) → Add Trigger → chon ham dailyReport → Time-driven → Day timer → 8pm - 9pm. Moi ngay luc 8 gio toi, ban se nhan duoc bao cao tong hop.
6f. Cài đặt Trigger cho onFormSubmit
Bước quan trọng nhất: cài đặt trigger để script tự chạy khi có form submit mới.
- Trong Apps Script Editor, click menu Triggers (icon đồng hồ bên trái)
- Click + Add Trigger
- Choose function: onFormSubmit
- Event source: From spreadsheet
- Event type: On form submit
- Click Save
- Authorize permissions khi được hỏi (Allow access to Gmail, Sheets)
Luu y quan trong: Ban phai authorize (cap quyen) cho script lan dau tien. Google se hoi ban co cho phep script truy cap Gmail (de gui email) va Sheets. Click Advanced → Go to [project name] → Allow. Day la buoc bat buoc, khong authorize thi script khong chay duoc.
7. Sheet 3: Dashboard Báo Cáo Doanh Thu
Sheet Dashboard giúp bạn nhìn tổng quan tình hình kinh doanh: tổng đơn, doanh thu, đơn chờ xử lý, top sản phẩm bán chạy. Tất cả đều tự cập nhật realtime.
KPI Cards
Tạo 6 ô KPI ở đầu Dashboard:
Tong don hom nay
COUNTIFS(...)
Doanh thu hom nay
SUMIFS(...)
Don cho xu ly
COUNTIF(...)
Doanh thu thang
SUMIFS(...)
Don bi huy
COUNTIF(...)
Gia tri TB/don
AVERAGE(...)
Công thức cho từng KPI
// Tong don hom nay
=COUNTIFS(DonHang!B:B, ">="&TODAY(), DonHang!B:B, "<"&TODAY()+1)
// Doanh thu hom nay
=SUMIFS(DonHang!I:I, DonHang!B:B, ">="&TODAY(),
DonHang!B:B, "<"&TODAY()+1,
DonHang!L:L, "<>Huy")
// Don cho xu ly
=COUNTIF(DonHang!L:L, "Cho xu ly")
// Doanh thu thang nay
=SUMIFS(DonHang!I:I,
DonHang!B:B, ">="&DATE(YEAR(TODAY()),MONTH(TODAY()),1),
DonHang!B:B, "<"&DATE(YEAR(TODAY()),MONTH(TODAY())+1,1),
DonHang!L:L, "<>Huy")
// Don bi huy (thang nay)
=COUNTIFS(DonHang!L:L, "Huy",
DonHang!B:B, ">="&DATE(YEAR(TODAY()),MONTH(TODAY()),1))
// Gia tri trung binh / don
=IFERROR(AVERAGEIF(DonHang!L:L, "<>Huy", DonHang!I:I), 0)
Top 5 sản phẩm bán chạy
Để tạo bảng top sản phẩm, dùng QUERY kết hợp với dữ liệu đã xử lý:
// Dem so lan xuat hien cua tung SP trong cot SanPham // (Cach don gian: dung COUNTIF voi wildcard) // VD: Dem so don co SP001 =COUNTIF(DonHang!G:G, "*SP001*") // Bang top san pham: tao 1 cot MaSP, 1 cot SoLuongDon // Roi dung SORT de sap xep giam dan =SORT(E2:F20, 2, FALSE)
Biểu đồ doanh thu theo ngày
Tạo biểu đồ đường (Line Chart) hiển thị doanh thu 30 ngày gần nhất:
- Tạo bảng phụ với 2 cột: Ngay (30 ngày gần nhất) và DoanhThu (SUMIFS theo ngày)
- Chọn vùng dữ liệu → Insert → Chart
- Chọn Line chart
- Tùy chỉnh: đổi màu, thêm title, hiển thị data labels
- Di chuyển chart vào vị trí đẹp trên Dashboard
// Cong thuc cho cot DoanhThu (30 ngay gan nhat)
// Cot A: =TODAY()-29, TODAY()-28, ..., TODAY()
// Cot B:
=SUMIFS(DonHang!I:I,
DonHang!B:B, ">="&A2,
DonHang!B:B, "<"&A2+1,
DonHang!L:L, "<>Huy")
8. Trừ Tồn Kho Tự Động Khi Có Đơn Mới
Một trong những tính năng quan trọng nhất: khi khách đặt hàng, tồn kho tự động giảm. Khi hủy đơn, tồn kho tự động hoàn lại.
Script trừ tồn kho
// === TRU TON KHO KHI CO DON MOI ===
function truTonKho(productSheet, soLuongStr) {
// soLuongStr: "SP001:2, SP003:1"
var items = soLuongStr.split(',');
var lastRow = productSheet.getLastRow();
var products = productSheet.getRange(2, 1, lastRow - 1, 7).getValues();
// products[i] = [MaSP, TenSP, DanhMuc, GiaBan, GiaVon, TonKho, TonMin]
for (var i = 0; i < items.length; i++) {
var parts = items[i].trim().split(':');
if (parts.length === 2) {
var maSP = parts[0].trim();
var qty = parseInt(parts[1].trim());
// Tim SP va tru ton kho
for (var j = 0; j < products.length; j++) {
if (products[j][0] === maSP) {
var currentStock = products[j][5]; // TonKho
var newStock = Math.max(0, currentStock - qty);
productSheet.getRange(j + 2, 6).setValue(newStock); // Col F = TonKho
// Canh bao neu ton kho thap
if (newStock <= products[j][6]) { // TonMin
canhBaoTonKho(maSP, products[j][1], newStock, products[j][6]);
}
break;
}
}
}
}
}
// === HOAN TRA TON KHO KHI HUY DON ===
function hoanTraTonKho(productSheet, soLuongStr) {
var items = soLuongStr.split(',');
var lastRow = productSheet.getLastRow();
var products = productSheet.getRange(2, 1, lastRow - 1, 6).getValues();
for (var i = 0; i < items.length; i++) {
var parts = items[i].trim().split(':');
if (parts.length === 2) {
var maSP = parts[0].trim();
var qty = parseInt(parts[1].trim());
for (var j = 0; j < products.length; j++) {
if (products[j][0] === maSP) {
var currentStock = products[j][5];
productSheet.getRange(j + 2, 6).setValue(currentStock + qty);
break;
}
}
}
}
}
// === CANH BAO TON KHO THAP ===
function canhBaoTonKho(maSP, tenSP, currentStock, minStock) {
var subject = '[CANH BAO] Ton kho thap - ' + maSP;
var body = '<h3>Canh bao ton kho thap</h3>'
+ '<p>San pham: <strong>' + tenSP + '</strong> (' + maSP + ')</p>'
+ '<p>Ton kho hien tai: <strong style="color:red">'
+ currentStock + '</strong></p>'
+ '<p>Muc toi thieu: ' + minStock + '</p>'
+ '<p>Vui long nhap them hang!</p>';
MailApp.sendEmail({
to: CONFIG.SHOP_EMAIL,
subject: subject,
htmlBody: body
});
}
Ket qua: Khi khach dat "SP001:2, SP003:1", he thong tu dong tru 2 cai SP001 va 1 cai SP003 khoi ton kho. Neu ton kho giam duoi muc toi thieu, admin nhan email canh bao ngay lap tuc.
9. Email Templates: Xác Nhận, Đang Giao, Hoàn Thành
Hệ thống gửi email tự động cho khách hàng tại 3 thời điểm: khi đặt hàng thành công, khi đang giao hàng, và khi hoàn thành. Dưới đây là code cho các email templates.
Email xác nhận đơn hàng
// === GUI EMAIL XAC NHAN DON HANG ===
function guiEmailXacNhan(email, tenKH, maDon, sanPham,
soLuong, tongTien, phiShip, phuongThuc, diaChi) {
var subject = '[' + CONFIG.SHOP_NAME + '] Xac nhan don hang ' + maDon;
var body = '<div style="font-family:Arial; max-width:600px; margin:0 auto">'
+ '<div style="background:#4F46E5; color:white; padding:20px; text-align:center">'
+ '<h1 style="margin:0">' + CONFIG.SHOP_NAME + '</h1>'
+ '<p style="margin:5px 0 0">Xac nhan don hang</p>'
+ '</div>'
+ '<div style="padding:20px; background:#f9fafb">'
+ '<p>Xin chao <strong>' + tenKH + '</strong>,</p>'
+ '<p>Cam on ban da dat hang tai ' + CONFIG.SHOP_NAME
+ '. Don hang cua ban da duoc tiep nhan.</p>'
+ '<div style="background:white; border:1px solid #e5e7eb;'
+ ' border-radius:8px; padding:15px; margin:15px 0">'
+ '<h3 style="margin-top:0">Chi tiet don hang</h3>'
+ '<p><strong>Ma don:</strong> ' + maDon + '</p>'
+ '<p><strong>San pham:</strong> ' + sanPham + '</p>'
+ '<p><strong>So luong:</strong> ' + soLuong + '</p>'
+ '<p><strong>Tong tien:</strong> '
+ formatVND(tongTien) + '</p>'
+ '<p><strong>Phi ship:</strong> '
+ formatVND(phiShip) + '</p>'
+ '<p style="font-size:18px; color:#4F46E5">'
+ '<strong>Tong thanh toan: '
+ formatVND(tongTien + phiShip) + '</strong></p>'
+ '<p><strong>Thanh toan:</strong> ' + phuongThuc + '</p>'
+ '<p><strong>Dia chi:</strong> ' + diaChi + '</p>'
+ '</div>'
+ '<p>Chung toi se lien he ban trong 24h de xac nhan.</p>'
+ '<p>Tran trong,<br>' + CONFIG.SHOP_NAME + '</p>'
+ '</div>'
+ '</div>';
MailApp.sendEmail({
to: email,
subject: subject,
htmlBody: body
});
}
Email thông báo đang giao
// === GUI EMAIL DANG GIAO HANG ===
function guiEmailDangGiao(email, tenKH, maDon) {
var subject = '[' + CONFIG.SHOP_NAME + '] Don hang '
+ maDon + ' dang duoc giao';
var body = '<div style="font-family:Arial; max-width:600px; margin:0 auto">'
+ '<div style="background:#059669; color:white; padding:20px; text-align:center">'
+ '<h1 style="margin:0">Dang giao hang</h1>'
+ '</div>'
+ '<div style="padding:20px">'
+ '<p>Xin chao <strong>' + tenKH + '</strong>,</p>'
+ '<p>Don hang <strong>' + maDon + '</strong>'
+ ' cua ban dang duoc giao.</p>'
+ '<p>Vui long giu lien lac de nhan hang.</p>'
+ '<p>Tran trong,<br>' + CONFIG.SHOP_NAME + '</p>'
+ '</div></div>';
MailApp.sendEmail({
to: email,
subject: subject,
htmlBody: body
});
}
Email hoàn thành và email hủy đơn
// === GUI EMAIL HOAN THANH ===
function guiEmailHoanThanh(email, tenKH, maDon) {
var subject = '[' + CONFIG.SHOP_NAME + '] Don hang '
+ maDon + ' da hoan thanh';
var body = '<div style="font-family:Arial; max-width:600px; margin:0 auto">'
+ '<div style="background:#4F46E5; color:white; padding:20px; text-align:center">'
+ '<h1 style="margin:0">Don hang hoan thanh!</h1>'
+ '</div>'
+ '<div style="padding:20px">'
+ '<p>Xin chao <strong>' + tenKH + '</strong>,</p>'
+ '<p>Don hang <strong>' + maDon + '</strong>'
+ ' da giao thanh cong.</p>'
+ '<p>Cam on ban da mua hang tai ' + CONFIG.SHOP_NAME
+ '. Neu co bat ky van de gi, vui long lien he chung toi.</p>'
+ '<p>Tran trong,<br>' + CONFIG.SHOP_NAME + '</p>'
+ '</div></div>';
MailApp.sendEmail({
to: email,
subject: subject,
htmlBody: body
});
}
// === GUI EMAIL HUY DON ===
function guiEmailHuyDon(email, tenKH, maDon) {
var subject = '[' + CONFIG.SHOP_NAME + '] Don hang '
+ maDon + ' da bi huy';
var body = '<div style="font-family:Arial; max-width:600px; margin:0 auto">'
+ '<div style="background:#DC2626; color:white; padding:20px; text-align:center">'
+ '<h1 style="margin:0">Don hang da huy</h1>'
+ '</div>'
+ '<div style="padding:20px">'
+ '<p>Xin chao <strong>' + tenKH + '</strong>,</p>'
+ '<p>Don hang <strong>' + maDon + '</strong>'
+ ' da bi huy theo yeu cau.</p>'
+ '<p>Neu ban khong yeu cau huy, vui long lien he chung toi ngay.</p>'
+ '<p>Tran trong,<br>' + CONFIG.SHOP_NAME + '</p>'
+ '</div></div>';
MailApp.sendEmail({
to: email,
subject: subject,
htmlBody: body
});
}
10. Tips Mở Rộng Hệ Thống
Hệ thống cơ bản trên đã đáp ứng được 80% nhu cầu của shop online nhỏ. Dưới đây là một số gợi ý để mở rộng và nâng cấp hệ thống.
10.1. Tích hợp thanh toán QR Code
Bạn có thể tạo QR code thanh toán tự động bằng VietQR API. Khi khách chọn phương thức "Chuyển khoản", email xác nhận sẽ kèm QR code để khách quét và chuyển tiền.
// Tao link QR code VietQR
function taoQRCode(soTien, maDon) {
var bankId = '970422'; // MB Bank
var accountNo = '0123456789';
var accountName = 'NGUYEN VAN A';
var noiDung = 'Thanh toan ' + maDon;
var url = 'https://img.vietqr.io/image/'
+ bankId + '-' + accountNo + '-compact.png'
+ '?amount=' + soTien
+ '&addInfo=' + encodeURIComponent(noiDung)
+ '&accountName=' + encodeURIComponent(accountName);
return url;
}
10.2. Đa kênh bán hàng (Multi-channel)
Thêm trường "Kênh bán" vào Form (Facebook, Zalo, Website, Shopee, TikTok Shop) để theo dõi đơn hàng theo từng kênh. Dashboard sẽ có biểu đồ phân bổ doanh thu theo kênh.
10.3. Mã giảm giá (Coupon)
Tạo thêm sheet "MaGiamGia" chứa danh sách mã giảm giá, loại giảm giá (phần trăm hoặc số tiền), thời hạn sử dụng. Script sẽ kiểm tra và áp dụng giảm giá khi tính tổng tiền.
10.4. Notification qua Telegram
Thay vì chỉ nhận email, bạn có thể thêm thông báo qua Telegram Bot để nhận alert ngay lập tức trên điện thoại.
// Gui thong bao qua Telegram Bot
function guiTelegram(message) {
var botToken = 'YOUR_BOT_TOKEN';
var chatId = 'YOUR_CHAT_ID';
var url = 'https://api.telegram.org/bot' + botToken
+ '/sendMessage';
var payload = {
'chat_id': chatId,
'text': message,
'parse_mode': 'HTML'
};
UrlFetchApp.fetch(url, {
'method': 'post',
'contentType': 'application/json',
'payload': JSON.stringify(payload)
});
}
10.5. In phiếu giao hàng
Tạo Google Docs template phiếu giao hàng, dùng Apps Script tự động điền thông tin đơn hàng vào template và tạo PDF. Nhân viên chỉ cần click nút "In phiếu" là có phiếu giao hàng đẹp.
10.6. Tích hợp Google Calendar
Tự động tạo event trên Google Calendar khi có đơn mới. Giúp nhân viên giao hàng biết lịch giao trong ngày. Đặc biệt hữu ích nếu bạn ship hàng theo khu vực.
So sánh: Hệ thống GS+Forms vs Phần mềm chuyên dụng
| Tieu chi | GS + Forms | Phan mem chuyen dung |
|---|---|---|
| Chi phi | Mien phi | 500K-5M/thang |
| Gioi han don | ~100 don/ngay | Khong gioi han |
| Tuy chinh | 100% tuy chinh | Gioi han |
| Bao mat | Co ban | Chuyen nghiep |
| Tich hop VCSC | Thu cong | Tu dong |
| Hoa don VAT | Khong | Co |
| Setup | 2 gio | 1-3 ngay |
| Phu hop | Shop nho, moi bat dau | DN quy mo lon |
11. FAQ - Câu Hỏi Thường Gặp
1. Hệ thống này có miễn phí không?
Hoàn toàn miễn phí! Bạn chỉ cần tài khoản Google (Gmail). Google Sheets, Google Forms, và Apps Script đều miễn phí. Lưu ý Gmail miễn phí giới hạn gửi 100 email/ngày, Google Workspace (có phí) được gửi 1500 email/ngày.
2. Có thể quản lý bao nhiêu đơn hàng?
Google Sheets hỗ trợ tối đa 10 triệu ô dữ liệu (cells). Với cấu trúc 13 cột, bạn có thể lưu khoảng 770,000 đơn hàng. Tuy nhiên, khi vượt quá 50,000 dòng, Sheets sẽ chậm lại đáng kể. Khuyến nghị giữ dưới 10,000 đơn/sheet và archive định kỳ.
3. Nhiều nhân viên có thể dùng cùng lúc không?
Có! Đây là ưu điểm lớn nhất của Google Sheets. Bạn có thể share Spreadsheet cho nhiều nhân viên với các quyền khác nhau: Editor (sửa), Commenter (bình luận), hoặc Viewer (chỉ xem). Mọi thay đổi được cập nhật realtime.
4. Nếu script gặp lỗi thì sao?
Bạn có thể kiểm tra log tại Apps Script Editor → Executions (menu bên trái). Tại đây hiện tất cả các lần chạy, trạng thái (thành công/lỗi), và chi tiết lỗi. Lỗi phổ biến nhất là quên authorize permissions hoặc tên sheet không đúng.
5. Khi nào nên chuyển sang phần mềm chuyên dụng?
Bạn nên cân nhắc chuyển khi: (1) Số đơn vượt 100 đơn/ngày, (2) Cần tích hợp đơn vị vận chuyển tự động, (3) Cần xuất hóa đơn VAT, (4) Nhiều hơn 5 nhân viên quản lý, (5) Cần báo cáo phân tích chuyên sâu. Lúc đó, một phần mềm quản lý bán hàng chuyên nghiệp sẽ phù hợp hơn.
12. Khi Nào Cần Nâng Cấp Lên Phần Mềm Chuyên Nghiệp?
Hệ thống Google Sheets + Forms rất phù hợp khi bạn mới bắt đầu hoặc có dưới 50-100 đơn/ngày. Nhưng khi shop phát triển, bạn sẽ cần một giải pháp mạnh mẽ hơn.
Phần Mềm Quản Lý Bán Hàng SheetStore
Nâng cấp từ Google Sheets lên hệ thống chuyên nghiệp. Giữ nguyên sự đơn giản, thêm sức mạnh.
- ✓ Quản lý đơn hàng không giới hạn
- ✓ Tích hợp đơn vị vận chuyển tự động
- ✓ Xuất hóa đơn VAT
- ✓ Báo cáo AI thông minh
- ✓ Quản lý đa kênh (Omnichannel)
- ✓ App mobile cho nhân viên
- ✓ Phân quyền chuyên nghiệp
- ✓ Hỗ trợ kỹ thuật 24/7
Tổng Kết
Trong bài viết này, bạn đã học được cách xây dựng một hệ thống quản lý đơn hàng online hoàn chỉnh với Google Sheets + Google Forms, bao gồm:
- 1.Sheet SanPham - Quản lý danh mục sản phẩm, giá, tồn kho với conditional formatting
- 2.Google Form - Form đặt hàng chuyên nghiệp với validation
- 3.Sheet DonHang - Quản lý toàn bộ đơn hàng với mã đơn tự động
- 4.Apps Script - Tự động hóa: tạo mã đơn, tính tiền, trừ kho, gửi email
- 5.Dashboard - Báo cáo doanh thu, KPI, biểu đồ realtime
- 6.Email templates - 4 loại email tự động cho khách hàng
- 7.Mở rộng - QR thanh toán, Telegram, multi-channel, coupon
Hãy bắt đầu từ phiên bản cơ bản, rồi từ từ thêm các tính năng mở rộng theo nhu cầu. Khi shop phát triển vượt quá khả năng của Google Sheets, đó là lúc bạn nên cân nhắc chuyển sang phần mềm quản lý bán hàng chuyên nghiệp.
📚 Bài Viết Liên Quan
- Template Google Sheets Báo Cáo Bán Hàng Theo Vùng và Đại Lý 2027: Phân Tích Đa Chiều
- Google Sheets Nâng Cao Bài 9: Bảo Mật, Phân Quyền và Chia Sẻ Chuyên Nghiệp
- Google Sheets Nâng Cao Bài 4: Hàm QUERY - Lọc và Phân Tích Dữ Liệu Chuyên Nghiệp
- Template Google Sheets Quản Lý Phòng Khám và Bệnh Viện Nhỏ 2027
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.