Skip to content

Định dạng XML Hóa đơn

Tổng quan

Hóa đơn điện tử Việt Nam phải tuân theo định dạng XML được quy định bởi Tổng cục Thuế (GDT). Tài liệu này mô tả cấu trúc XML, các trường bắt buộc và quy tắc xác thực.

Cấu trúc XML

Ví dụ XML Đầy đủ

xml
<?xml version="1.0" encoding="UTF-8"?>
<HDon>
  <DLHDon>
    <!-- Thông tin Chung -->
    <TTChung>
      <PBan>2.0.0</PBan>              <!-- Phiên bản XML -->
      <THDon>Hóa đơn GTGT</THDon>     <!-- Tên Loại Hóa đơn -->
      <KHMSHDon>1</KHMSHDon>          <!-- Mã Mẫu số -->
      <KHHDon>C25TAA</KHHDon>         <!-- Ký hiệu Mẫu -->
      <SHDon>00000001</SHDon>         <!-- Số Hóa đơn -->
      <MHSo>01GTKT0/001</MHSo>        <!-- Mẫu số Hóa đơn -->
      <NLap>2025-01-20</NLap>         <!-- Ngày lập -->
      <SBKe></SBKe>                   <!-- Số Bảng kê -->
      <NBKe></NBKe>                   <!-- Ngày Bảng kê -->
      <DVTTe>VND</DVTTe>              <!-- Đơn vị Tiền tệ -->
      <TGia>1</TGia>                  <!-- Tỷ giá -->
      <HTTToan>TM/CK</HTTToan>        <!-- Hình thức Thanh toán -->
      <MSTTCGP></MSTTCGP>             <!-- MST Tổ chức cung cấp giải pháp -->
      <MSTDVNUNLHDon></MSTDVNUNLHDon> <!-- MST Đơn vị nhận ủy nhiệm lập hóa đơn -->
      <THTToan>1</THTToan>            <!-- Trạng thái Thanh toán -->
    </TTChung>

    <!-- Nội dung Hóa đơn -->
    <NDHDon>
      <!-- Thông tin Người bán -->
      <NBan>
        <Ten>Công ty TNHH ABC</Ten>        <!-- Tên Công ty -->
        <MST>0123456789</MST>               <!-- Mã số Thuế -->
        <DChi>123 Nguyễn Huệ, Q1, TP.HCM</DChi>  <!-- Địa chỉ -->
        <SDThoai>028-1234-5678</SDThoai>    <!-- Điện thoại -->
        <DCTDTu>contact@abc.com.vn</DCTDTu> <!-- Email -->
        <STKNHang>1234567890</STKNHang>     <!-- Số Tài khoản Ngân hàng -->
        <TNHang>Vietcombank</TNHang>        <!-- Tên Ngân hàng -->
        <Fax></Fax>                         <!-- Fax -->
        <Website>www.abc.com.vn</Website>   <!-- Website -->
      </NBan>

      <!-- Thông tin Người mua -->
      <NMua>
        <Ten>Khách hàng XYZ</Ten>           <!-- Tên Khách hàng -->
        <MST>9876543210</MST>               <!-- Mã số Thuế (B2B) -->
        <DChi>456 Lê Lợi, Q1, TP.HCM</DChi> <!-- Địa chỉ -->
        <SDThoai>0901234567</SDThoai>       <!-- Điện thoại -->
        <DCTDTu>customer@xyz.com</DCTDTu>   <!-- Email -->
        <HVTNMHang>Nguyễn Văn A</HVTNMHang> <!-- Họ và tên người mua hàng -->
        <STKNHang></STKNHang>               <!-- Số Tài khoản Ngân hàng -->
        <TNHang></TNHang>                   <!-- Tên Ngân hàng -->
      </NMua>

      <!-- Danh sách Hàng hóa, Dịch vụ -->
      <DSHHDVu>
        <HHDVu>
          <TChat>1</TChat>                  <!-- Tính chất: 1=Hàng hóa, 2=Dịch vụ -->
          <STT>1</STT>                      <!-- Số thứ tự -->
          <MHHDVu>SP001</MHHDVu>            <!-- Mã Hàng hóa/Dịch vụ -->
          <THHDVu>Sản phẩm A</THHDVu>       <!-- Tên Hàng hóa/Dịch vụ -->
          <DVTinh>Cái</DVTinh>              <!-- Đơn vị tính -->
          <SLuong>2</SLuong>                <!-- Số lượng -->
          <DGia>100000</DGia>               <!-- Đơn giá -->
          <TLCKhau>0</TLCKhau>              <!-- Tỷ lệ Chiết khấu -->
          <STCKhau>0</STCKhau>              <!-- Số tiền Chiết khấu -->
          <ThTien>200000</ThTien>           <!-- Thành tiền (trước VAT) -->
          <TSuat>10%</TSuat>                <!-- Thuế suất -->
        </HHDVu>
        <HHDVu>
          <TChat>2</TChat>
          <STT>2</STT>
          <MHHDVu>DV001</MHHDVu>
          <THHDVu>Dịch vụ B</THHDVu>
          <DVTinh>Lần</DVTinh>
          <SLuong>1</SLuong>
          <DGia>50000</DGia>
          <TLCKhau>10</TLCKhau>
          <STCKhau>5000</STCKhau>
          <ThTien>45000</ThTien>
          <TSuat>10%</TSuat>
        </HHDVu>
      </DSHHDVu>

      <!-- Tóm tắt Thanh toán -->
      <TToan>
        <TgTCThue>245000</TgTCThue>         <!-- Tổng tiền chưa thuế -->
        <TgTThue>24500</TgTThue>            <!-- Tổng tiền thuế -->
        <TgTTTBSo>269500</TgTTTBSo>         <!-- Tổng tiền thanh toán bằng số -->
        <TgTTTBChu>Hai trăm sáu mươi chín nghìn năm trăm đồng</TgTTTBChu>
                                            <!-- Tổng tiền thanh toán bằng chữ -->

        <!-- Tóm tắt VAT theo thuế suất -->
        <THTTLTSuat>
          <LTSuat>
            <TSuat>10%</TSuat>              <!-- Thuế suất -->
            <ThTien>245000</ThTien>         <!-- Thành tiền -->
            <TThue>24500</TThue>            <!-- Tiền thuế -->
          </LTSuat>
        </THTTLTSuat>
      </TToan>
    </NDHDon>
  </DLHDon>

  <!-- Chữ ký số -->
  <DSCKS>
    <NBan>
      <Signature xmlns="http://www.w3.org/2000/09/xmldsig#">
        <!-- Chữ ký số của Người bán (PKCS#7) -->
      </Signature>
    </NBan>
  </DSCKS>
</HDon>

Tham khảo Trường

TTChung (Thông tin Chung)

Phần tửBắt buộcMô tảĐịnh dạng
PBanPhiên bản XML"2.0.0"
THDonTên loại hóa đơnVăn bản
KHMSHDonMã mẫu số hóa đơn1-6
KHHDonKý hiệu mẫu hóa đơnTối đa 6 ký tự
SHDonSố hóa đơn8 chữ số
MHSoMẫu sốMẫu: ##GTKT#/###
NLapNgày lậpYYYY-MM-DD
DVTTeĐơn vị tiền tệISO 4217 (VND)
TGiaTỷ giáThập phân
HTTToanHình thức thanh toánTM/CK/TM-CK

NBan (Người bán)

Phần tửBắt buộcMô tả
TenTên công ty
MSTMã số thuế (10 hoặc 13 chữ số)
DChiĐịa chỉ
SDThoaiKhôngSố điện thoại
DCTDTuKhôngEmail
STKNHangKhôngSố tài khoản ngân hàng
TNHangKhôngTên ngân hàng

NMua (Người mua)

Phần tửBắt buộcMô tả
TenTên khách hàng
MSTChỉ B2BMã số thuế
DChiKhôngĐịa chỉ
HVTNMHangKhôngNgười liên hệ

HHDVu (Hàng hóa Dịch vụ)

Phần tửBắt buộcMô tả
TChatTính chất: 1=Hàng hóa, 2=Dịch vụ
STTSố thứ tự
MHHDVuKhôngMã hàng hóa/dịch vụ
THHDVuTên hàng hóa/dịch vụ
DVTinhĐơn vị tính
SLuongSố lượng
DGiaĐơn giá
TLCKhauKhôngTỷ lệ chiết khấu
STCKhauKhôngSố tiền chiết khấu
ThTienThành tiền (trước VAT)
TSuatThuế suất

TToan (Thanh toán)

Phần tửBắt buộcMô tả
TgTCThueTổng tiền chưa thuế
TgTThueTổng tiền thuế
TgTTTBSoTổng tiền thanh toán bằng số
TgTTTBChuTổng tiền thanh toán bằng chữ

Thuế suất VAT

Thuế suấtMô tả
0%0%Xuất khẩu, hàng miễn thuế
5%5%Hàng hóa thiết yếu
8%8%Mức giảm (tạm thời)
10%10%Mức chuẩn
KCTKCTKhông chịu thuế
KKKNTKKKNTKhông kê khai, nộp thuế

XmlGeneratorService

typescript
@injectable()
class XmlGeneratorService {
  /**
   * Tạo XML tuân thủ GDT từ dữ liệu hóa đơn
   */
  async generateXml(invoice: Invoice): Promise<string> {
    const builder = new xml2js.Builder({
      xmldec: { version: '1.0', encoding: 'UTF-8' },
      renderOpts: { pretty: true, indent: '  ' },
    });

    const xmlObject = this.buildXmlObject(invoice);
    return builder.buildObject(xmlObject);
  }

  private buildXmlObject(invoice: Invoice): object {
    return {
      HDon: {
        DLHDon: {
          TTChung: this.buildTTChung(invoice),
          NDHDon: {
            NBan: this.buildNBan(invoice),
            NMua: this.buildNMua(invoice),
            DSHHDVu: this.buildItems(invoice.items),
            TToan: this.buildTToan(invoice),
          },
        },
        // Chữ ký được thêm sau khi ký
      },
    };
  }

  private buildTTChung(invoice: Invoice): object {
    return {
      PBan: '2.0.0',
      THDon: this.getInvoiceTypeName(invoice.type),
      KHMSHDon: invoice.templateCode,
      KHHDon: invoice.templateSymbol,
      SHDon: invoice.invoiceNumber,
      NLap: this.formatDate(invoice.issueDate),
      DVTTe: invoice.currency,
      TGia: invoice.exchangeRate || 1,
      HTTToan: invoice.paymentMethod,
    };
  }

  private buildItems(items: InvoiceItem[]): object {
    return {
      HHDVu: items.map((item, index) => ({
        TChat: item.isService ? '2' : '1',
        STT: index + 1,
        MHHDVu: item.productCode,
        THHDVu: item.productName,
        DVTinh: item.unit,
        SLuong: item.quantity,
        DGia: item.unitPrice,
        TLCKhau: item.discountPercent || 0,
        STCKhau: item.discountAmount || 0,
        ThTien: item.totalBeforeVat,
        TSuat: this.formatVatRate(item.vatRate),
      })),
    };
  }

  private formatVatRate(rate: number): string {
    if (rate === 0) return '0%';
    return `${rate}%`;
  }
}

Chuyển đổi Số sang Chữ Tiếng Việt

typescript
/**
 * Chuyển đổi số sang chữ tiếng Việt cho hóa đơn
 */
function numberToVietnameseWords(num: number): string {
  const ones = ['', 'một', 'hai', 'ba', 'bốn', 'năm', 'sáu', 'bảy', 'tám', 'chín'];
  const tens = ['', 'mười', 'hai mươi', 'ba mươi', 'bốn mươi', 'năm mươi',
                'sáu mươi', 'bảy mươi', 'tám mươi', 'chín mươi'];

  if (num === 0) return 'không đồng';

  let result = '';
  let billions = Math.floor(num / 1000000000);
  let millions = Math.floor((num % 1000000000) / 1000000);
  let thousands = Math.floor((num % 1000000) / 1000);
  let remainder = num % 1000;

  if (billions > 0) {
    result += readThreeDigits(billions) + ' tỷ ';
  }
  if (millions > 0) {
    result += readThreeDigits(millions) + ' triệu ';
  }
  if (thousands > 0) {
    result += readThreeDigits(thousands) + ' nghìn ';
  }
  if (remainder > 0) {
    result += readThreeDigits(remainder);
  }

  return capitalizeFirst(result.trim()) + ' đồng';
}

// Ví dụ: 269500 -> "Hai trăm sáu mươi chín nghìn năm trăm đồng"

Xác thực XML

Xác thực Schema

typescript
import * as libxmljs from 'libxmljs';

async function validateXml(xml: string, schemaPath: string): Promise<ValidationResult> {
  const xmlDoc = libxmljs.parseXml(xml);
  const xsdDoc = libxmljs.parseXml(
    await fs.readFile(schemaPath, 'utf-8')
  );

  const isValid = xmlDoc.validate(xsdDoc);
  const errors = xmlDoc.validationErrors;

  return {
    isValid,
    errors: errors.map(e => ({
      line: e.line,
      message: e.message,
    })),
  };
}

Xác thực Trường Bắt buộc

typescript
interface ValidationRule {
  path: string;
  required: boolean;
  pattern?: RegExp;
  maxLength?: number;
}

const validationRules: ValidationRule[] = [
  { path: 'HDon.DLHDon.TTChung.PBan', required: true, pattern: /^2\.0\.0$/ },
  { path: 'HDon.DLHDon.TTChung.SHDon', required: true, pattern: /^\d{8}$/ },
  { path: 'HDon.DLHDon.NDHDon.NBan.MST', required: true, pattern: /^\d{10}|\d{13}$/ },
  { path: 'HDon.DLHDon.NDHDon.NBan.Ten', required: true, maxLength: 400 },
  { path: 'HDon.DLHDon.NDHDon.NMua.Ten', required: true, maxLength: 400 },
];

Tài liệu Liên quan

Proprietary and Confidential. Unauthorized copying, distribution, or use of this software is strictly prohibited.