Hướng Dẫn Apps Script

10 Custom Function (UDF) Thường Dùng Trong Google Sheets

Tuân HoangTuân Hoang
14 tháng 5, 2026
5 phút đọc
Ảnh minh họa bài viết: 10 Custom Function (UDF) Thường Dùng Trong Google Sheets

Custom Function (UDF) Là Gì?

UDF (User Defined Function) là hàm tự viết bằng Apps Script, dùng trực tiếp trong ô Sheets như =SOTIEN_BANGCHU(A2). Không cần macro hay trigger — chỉ cần gõ tên hàm vào ô là Google Sheets gọi code của bạn.

Cách Tạo Custom Function

// Trong Apps Script Editor, viết hàm với JSDoc:
/**
 * Chuyển số thành chữ tiếng Việt.
 * @param {number} amount Số tiền cần chuyển.
 * @return {string} Số tiền bằng chữ.
 * @customfunction
 */
function SOTIEN_BANGCHU(amount) {
  if (!amount || isNaN(amount)) return '';
  // Rút gọn: dùng thư viện hoặc logic chuyển đổi
  const units = ['', 'một', 'hai', 'ba', 'bốn', 'năm', 'sáu', 'bảy', 'tám', 'chín'];
  // ... (logic đầy đủ theo chuẩn đọc số tiếng Việt)
  return String(amount).replace(/B(?=(d{3})+(?!d))/g, '.') + ' đồng';
}

10 UDF Thường Dùng Nhất

1. Tính Số Ngày Làm Việc (Loại Trừ Cuối Tuần)

/**
 * Tính số ngày làm việc giữa 2 ngày (không kể T7, CN).
 * @customfunction
 */
function WORKDAYS(startDate, endDate) {
  if (!startDate || !endDate) return 0;
  const start = new Date(startDate);
  const end = new Date(endDate);
  let count = 0;
  const current = new Date(start);
  while (current <= end) {
    const day = current.getDay();
    if (day !== 0 && day !== 6) count++;
    current.setDate(current.getDate() + 1);
  }
  return count;
}

2. Lấy Tỷ Giá Thực Từ API

/**
 * Lấy tỷ giá hiện tại từ ExchangeRate API.
 * @param {string} from Mã tiền gốc (vd: "USD").
 * @param {string} to Mã tiền đích (vd: "VND").
 * @customfunction
 */
function EXCHANGE_RATE(from, to) {
  try {
    const url = 'https://api.exchangerate-api.com/v4/latest/' + from.toUpperCase();
    const resp = UrlFetchApp.fetch(url, { muteHttpExceptions: true });
    const data = JSON.parse(resp.getContentText());
    return data.rates[to.toUpperCase()] || 'N/A';
  } catch (e) {
    return 'ERROR';
  }
}

3. Chuẩn Hóa Số Điện Thoại Việt Nam

/**
 * Chuẩn hóa số điện thoại VN về dạng 0xxxxxxxxx.
 * @customfunction
 */
function NORMALIZE_PHONE(phone) {
  if (!phone) return '';
  let p = String(phone).replace(/D/g, '');
  if (p.startsWith('84')) p = '0' + p.slice(2);
  if (p.startsWith('+84')) p = '0' + p.slice(3);
  if (p.length === 9) p = '0' + p;
  return p.length === 10 ? p : 'Không hợp lệ';
}

4. Tính Tuổi Từ Ngày Sinh

/** @customfunction */
function TUOI(birthDate) {
  if (!birthDate) return '';
  const dob = new Date(birthDate);
  const today = new Date();
  let age = today.getFullYear() - dob.getFullYear();
  const m = today.getMonth() - dob.getMonth();
  if (m < 0 || (m === 0 && today.getDate() < dob.getDate())) age--;
  return age;
}

5. Tính VAT

/**
 * Tính giá sau VAT.
 * @param {number} price Giá chưa VAT.
 * @param {number} rate Thuế suất % (mặc định 10).
 * @customfunction
 */
function TINH_VAT(price, rate) {
  rate = rate || 10;
  return price * (1 + rate / 100);
}

6. Slugify Tiêu Đề Tiếng Việt

/** @customfunction */
function SLUGIFY(text) {
  if (!text) return '';
  const map = { 'à':'a','á':'a','ả':'a','ã':'a','ạ':'a','â':'a','ă':'a','đ':'d','è':'e','é':'e','ê':'e','ì':'i','í':'i','ò':'o','ó':'o','ô':'o','ơ':'o','ù':'u','ú':'u','ư':'u','ỳ':'y','ý':'y' };
  return text.toLowerCase()
    .replace(/[àáảãạâăđèéêìíòóôơùúưỳý]/g, c => map[c] || c)
    .replace(/[^a-z0-9s-]/g, '')
    .trim().replace(/s+/g, '-');
}

7–10. Các UDF Tiện Ích Khác

/** Kiểm tra email hợp lệ. @customfunction */
function IS_EMAIL(email) {
  return /^[^s@]+@[^s@]+.[^s@]+$/.test(String(email));
}

/** Lấy tháng năm dạng "Tháng 6/2026". @customfunction */
function THANG_NAM(date) {
  const d = date ? new Date(date) : new Date();
  return 'Tháng ' + (d.getMonth() + 1) + '/' + d.getFullYear();
}

/** Mã hóa base64. @customfunction */
function BASE64_ENCODE(text) {
  return Utilities.base64Encode(text, Utilities.Charset.UTF_8);
}

/** Đếm từ trong chuỗi. @customfunction */
function DEM_TU(text) {
  if (!text) return 0;
  return String(text).trim().split(/s+/).length;
}

Lưu Ý Khi Dùng Custom Function

  • Cache kết quả: UDF gọi UrlFetchApp sẽ không tự cập nhật. Dùng CacheService hoặc trigger để refresh định kỳ.
  • Không dùng UI services: UDF không được gọi SpreadsheetApp.getUi(), Browser, hay MailApp.
  • Xử lý mảng: UDF nhận và trả về mảng 2 chiều — phù hợp với công thức dạng array formula.
  • Timeout: UDF có giới hạn 30 giây — không dùng cho tác vụ nặng.

Chia sẻ bài viết:

Tuân Hoang

Tuân Hoang

Đội ngũ SheetStore

Google SheetsGoogle Apps ScriptCRMAutomationPhần mềm quản lý doanh nghiệp

Google Workspace Certified, 5+ years experience

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.

Nhận thông báo khi có bài viết mới. Không spam, hứa luôn! 😊

Bình luận (0)

Vui lòng đăng nhập để tham gia thảo luận