Tích Hợp WinInvoice VAT Cho CRM Doanh Nghiệp — Tài Liệu Tham Khảo Đầy Đủ Cho AI Agent
Tích Hợp WinInvoice VAT Cho CRM Doanh Nghiệp — Tài Liệu Tham Khảo Đầy Đủ Cho AI Agent
Bài viết này là tài liệu tham khảo toàn diện dành cho AI agent khi làm việc với API WinInvoice — tạo, kiểm tra, ký, tải hóa đơn VAT điện tử. Toàn bộ nội dung được cấu trúc rõ ràng để cả người đọc lẫn AI agent đều có thể scan và nắm bắt ngay trong lần đầu tiên.
1. Xác Thực (Authentication)
WinInvoice sử dụng HTTP Basic Auth theo chuẩn RFC 7617:
<code>Authorization: Basic base64_encode(clientID:clientSecret)</code></pre>
<p>Hai loại credential CRM sử dụng:
<table><thead><tr><th>Loại</th><th>Client ID</th><th>Serial Mẫu</th></tr></thead><tbody><tr><td>Có mã (có tax auth code)</td><td>0312303803-999</td><td>C__TGT / C__TAT</td></tr><tr><td>Không mã (không tax auth code)</td><td>0312303803-998</td><td>K__TGT</td></tr></tbody></table>
Quy ước cho năm 2026: Thay <code>__</code> bằng 2 chữ số cuối của năm → <code>C26THJ</code> (có thể dùng không mã). Form luôn là <code>"1"</code>.
- URL demo: <code>https://demo.evat.vn</code> - URL production khác với demo — kiểm tra <code>config.php</code> - CRM wrapper: <code>vat_invoice_api.php</code> → <code>callWinInvoiceAPI($endpoint, $data, $method='POST')</code>
2. API Endpoints — Tham Khảo Nhanh
2.1 Tạo / Cập Nhật Hóa Đơn — <code>/api/invoice/add_type_2</code>
POST — Tạo hóa đơn nháp. Nếu <code>invRef</code> đã tồn tại và chưa ký → ghi đè. Nếu đã ký → trả lỗi.
Trường bắt buộc:
<table><thead><tr><th>Field</th><th>Giá trị</th><th>Ghi chú</th></tr></thead><tbody><tr><td><code>invName</code></td><td>"1"</td><td>Form number — luôn là "1"</td></tr><tr><td><code>invSerial</code></td><td>"C26THJ"</td><td>Không mã, năm 2026</td></tr><tr><td><code>invDate</code></td><td>yyyy/mm/dd</td><td>⚠️ PHẢI là hôm nay — WinInvoice từ chối backdate</td></tr><tr><td><code>invRef</code></td><td>INV-2026-XXXX</td><td>UNIQUE — dùng <code>$invoice_data['full_id']</code></td></tr><tr><td><code>invRefDate</code></td><td>yyyy/mm/dd</td><td>Ngày bill thực tế (có thể khác invDate)</td></tr><tr><td><code>invSubTotal</code></td><td>number</td><td>Tổng trước VAT, trước discount</td></tr><tr><td><code>invVatRate</code></td><td>0/5/8/10/-1/-2</td><td>-1 = không chịu thuế, -2 = không kê khai</td></tr><tr><td><code>invVatAmount</code></td><td>number</td><td>Tiền VAT</td></tr><tr><td><code>invTotalAmount</code></td><td>number</td><td>Tổng cộng = subtotal + VAT</td></tr><tr><td><code>items</code></td><td>array</td><td>Danh sách line item (xem §2.1a)</td></tr></tbody></table>
Trường người mua (MF = Mandatory per CRM):
- <code>buyerCompany</code> — Tên công ty người mua - <code>buyerTax</code> — Mã số thuế người mua - <code>buyerAddress</code> — Địa chỉ đầy đủ - <code>buyerEmail</code> — Email (không bắt buộc nhưng nên có) - <code>buyerPhone</code> — SĐT (không bắt buộc) - <code>invCustomer</code> — 1 = cá nhân, 0 = công ty
Trường đặc biệt:
- <code>invAutoSign</code> — nên để 0 (không ký tự động). Ký thủ công qua portal. - <code>option</code> — 0=normal, 1=info adjust, 2=tăng, 3=giảm, 4=thay thế - <code>create04SSHDDT</code> — Tự động tạo 04/SS-HĐĐT? Mặc định 1. - <code>isDscnForSaleInv</code> — Áp dụng giảm 8% cho sales invoice
#### 2.1a Cấu Trúc Items Array
<code>{ "itemNo": 1, "itemCode": "CODE", "itemName": "Tên sản phẩm / dịch vụ", "itemPromo": 0, "isDscnItem": 0, "itemUnit": "Gói", "itemQuantity": 1, "itemPrice": 1980000, "itemVatRate": 10, "itemVatAmnt": 198000, "itemDscnAmnt": 0, "itemAmountNoVat": 1980000, "adjustType": "PRICE", "itemNote": "" }</code></pre>
<p>CRM convention: Gộp tất cả items thành 1 dòng duy nhất với <code>itemQuantity=1</code>, <code>itemPrice=subtotal</code>.
2.2 Response Mẫu (add_type_2)
<code>{ "action": "add_type_2", "isSuccess": true, "data": { "oid": "<WinInvoice UID>", "invCode": "0000060", "invRef": "INV-2026-1464", "invSign": "C26THJ", "invDate": "2026-06-05", "invName": "1C26THJ", "autoSign": 0, "isExisting": 0 } }</code></pre>
- <code>invCode = "0000000"</code> → chưa ký - <code>invCode ≠ "0000000"</code> → đã ký và có số thật - <code>isExisting = 1</code> → hóa đơn với invRef này đã tồn tại và được cập nhật
3. Các Endpoint Khác — Tham Khảo Nhanh
<table><thead><tr><th>Endpoint</th><th>Method</th><th>Mục Đích</th><th>Params Chính</th></tr></thead><tbody><tr><td><code>/api/invoice/validate</code></td><td>POST</td><td>Validate trước khi tạo</td><td>Giống add_type_2</td></tr><tr><td><code>/api/invoice/delete_raw_inv</code></td><td>POST</td><td>Xóa hóa đơn chưa ký</td><td>invcCode, invcSign, invRef</td></tr><tr><td><code>/api/invoice/get_link_byref</code> ⭐</td><td>POST</td><td>Lấy link xem/tải hóa đơn</td><td>invRef, invSign, invName, pdf (0/1)</td></tr><tr><td><code>/api/invoice/get_link</code></td><td>POST</td><td>Lấy link hóa đơn ĐÃ KÝ</td><td>invCode, invSign, invName, pdf</td></tr><tr><td><code>/api/invoice/check_signed</code></td><td>POST</td><td>Kiểm tra trạng thái ký</td><td>invRef, invName, invSerial</td></tr><tr><td><code>/api/mailer/send_inv_mail</code></td><td>POST</td><td>Gửi email hóa đơn</td><td>invRef, sendTo, updateMail</td></tr><tr><td><code>/api/mailer/inv_mail_history</code></td><td>POST</td><td>Lịch sử gửi email</td><td>invRef</td></tr><tr><td><code>/api/invoice/sign_invoice</code></td><td>POST</td><td>Yêu cầu ký số</td><td>invName, invSerial, invRef</td></tr><tr><td><code>/api/invoice/delete</code></td><td>POST</td><td>Hủy hóa đơn đã ký</td><td>invcCode, invcSign, invcSample, description</td></tr><tr><td><code>/api/invoice/get_inv_ex</code></td><td>POST</td><td>Lấy toàn bộ thông tin</td><td>invRef (trả về cả relate[])</td></tr><tr><td><code>/api/tk/tk04_ss_hddt</code></td><td>POST</td><td>Khai báo 04/SS-HĐĐT</td><td></td></tr><tr><td><code>/api/tk/tk04_ss_hddt/status</code></td><td>POST</td><td>Trạng thái khai báo</td><td>DRAFT→SIGNED→APPROVED|REFUSED</td></tr><tr><td><code>/api/invoice/tvan_refresh</code></td><td>POST</td><td>Cập nhật trạng thái gửi CQT</td><td>Đợi 3-5 phút sau khi gọi</td></tr></tbody></table>
<p>⚠️ Lưu ý về <code>get_link_byref</code>: Phải gửi đủ 3 field <code>invRef</code> + <code>invSign</code> + <code>invName</code>. Thiếu bất kỳ field nào → lỗi "Missing data". PDF link chỉ có hiệu lực 1 giờ — tải ngay, không lưu link.
4. CRM Workflow Chuẩn
Hàm chính: <code>createVATInvoice()</code> trong <code>vat_invoice_api.php</code>
- Load contact — từ <code>DATA_PATH/contacts/<contact_id>.json</code> - Validate buyer fields — phải có <code>name</code>, <code>tax_code</code> (hoặc <code>vat_number</code>), <code>address</code> - Tính toán — <code>subtotal = sum(quantity × unit_price)</code>, <code>vat_amount = round(subtotal × tax_rate / 100)</code>, <code>total = subtotal + vat_amount</code> - POST /invoice/add_type_2 — tạo hóa đơn nháp - Get PDF link — <code>sleep(3)</code> → <code>/invoice/get_link_byref</code> (pdf=1) → tải về <code>invoices/<full_id>/VAT_<full_id>.pdf</code> - Return — success, pdf_url, pdf_local, pending status
Quy trình ký: Tạo nháp → ký thủ công trên WinInvoice portal → <code>downloadSignedVatPdf()</code> → lưu <code>VAT_<id>_signed.pdf</code> (giữ cả bản unsigned).
5. Phân Biệt 4 Loại Chứng Từ
<table><thead><tr><th>Loại</th><th>Mã</th><th>Mục Đích</th><th>Hệ Thống</th></tr></thead><tbody><tr><td>Báo giá</td><td>QT</td><td>Báo giá trước hợp đồng, chi tiết từng mục</td><td>CRM nội bộ</td></tr><tr><td>Hóa đơn CRM</td><td>INV</td><td>Yêu cầu thanh toán nội bộ</td><td>CRM nội bộ</td></tr><tr><td>Phiếu thu</td><td>DNTT</td><td>Biên nhận thanh toán nội bộ</td><td>CRM nội bộ</td></tr><tr><td>Hóa đơn VAT</td><td>VAT</td><td>Chứng từ thuế chính thức</td><td>WinInvoice</td></tr></tbody></table>
6. Mã Lỗi Thường Gặp
<table><thead><tr><th>Code</th><th>Ý Nghĩa</th></tr></thead><tbody><tr><td>ER00</td><td>Lỗi hệ thống</td></tr><tr><td>ER01</td><td>Thiếu Client ID</td></tr><tr><td>ER02</td><td>Thiếu Token</td></tr><tr><td>ER03</td><td>Client ID không hợp lệ</td></tr><tr><td>ER04</td><td>Client không active</td></tr><tr><td>ER40</td><td>Thiếu dữ liệu bắt buộc</td></tr><tr><td>ER41</td><td>Chuỗi ngày không hợp lệ</td></tr><tr><td>ER42</td><td>Không tìm thấy dữ liệu</td></tr></tbody></table>
7. Pitfalls — Những Lỗi AI Agent Dễ Mắc
- ⚠️ invDate PHẢI là hôm nay — WinInvoice từ chối backdate. Dùng <code>date('Y/m/d')</code> chứ không dùng <code>invoice_date</code> từ DB. - ⚠️ tax_rate phải là float — không dùng int. <code>"tax_rate": "0.1"</code> trong JSON → ép kiểu float. - ⚠️ get_link_byref cần đủ 3 field — invRef + invSign + invName. Thiếu 1 → lỗi "Missing data". - ⚠️ PDF link hết hạn sau 1 giờ — tải ngay, lưu local. Không lưu link. - ⚠️ invRef là unique — nếu hóa đơn chưa ký, API sẽ ghi đè âm thầm. Nếu đã ký → lỗi. - ⚠️ invCode = "0000000" nghĩa là chưa ký — chỉ sau khi ký mới có số thật. - ⚠️ Không set invAutoSign — nên ký thủ công. Để mặc định 0. - ⚠️ Nghị định 70/2025/NĐ-CP (từ 1/6/2025) — hóa đơn sai không được hủy nữa, phải lập hóa đơn thay thế/điều chỉnh. API <code>/api/invoice/delete</code> có thể đã bị vô hiệu.
8. CLI Commands Tham Khảo
<table><thead><tr><th>Command</th><th>Mục Đích</th></tr></thead><tbody><tr><td><code>php cli/gen_vat.php <invoice_id></code></td><td>Tạo VAT đầy đủ: load JSON → createVATInvoice → tải PDF → update JSON</td></tr><tr><td><code>php cli/gen_dntt.php <invoice_id></code></td><td>Tạo phiếu thu DNTT (nội bộ, riêng với VAT)</td></tr><tr><td><code>php cli/debug_add_type2.php</code></td><td>Debug: in payload + raw API response</td></tr><tr><td><code>php cli/check_invc.php</code></td><td>Kiểm tra trạng thái ký theo invCode</td></tr><tr><td><code>php cli/get_unsigned_vat.php</code></td><td>Tải PDF VAT chưa ký</td></tr><tr><td><code>php cli/search_inv2.php</code></td><td>Tìm hóa đơn trên WinInvoice</td></tr></tbody></table>
9. Cấu Trúc Dữ Liệu Invoice JSON (After VAT Creation)
<code>{ "vat_invoice": { "inv_ref": "INV-2026-1464", "oid": "12345", "inv_code": "0000060", "private_code": "ABC123DEF45", "pdf_local": "VAT_INV-2026-1464.pdf", "created_at": "2026-06-05 10:30:00", "last_updated": "2026-06-05 10:30:00", "signed": false } }</code></pre>
<p>Sau khi ký: <code>inv_code</code> thay đổi từ <code>"0000000"</code> thành số thật, <code>signed</code> → <code>true</code>.
10. Data Flow Tổng Thể
<pre><code>Invoice JSON → createVATInvoice() → WinInvoice /add_type_2 → Nếu có PDF ngay: tải → VAT_<id>.pdf → Nếu chờ ký: check_signed → get_link_byref → tải
Sau khi ký (thủ công): → downloadSignedVatPdf() → VAT_<id>_signed.pdf → Giữ cả VAT_<id>.pdf (unsigned)
Email flow: --dry-run → --test → --send test: test@example.com, test2@example.com real: client email từ CUST-XXXX.json</code></pre>
<hr/>
Tài Liệu Tham Khảo
- WinInvoice API Docs: <code>https://demo.evat.vn</code> — tài liệu chính thức từ nhà cung cấp - File CRM liên quan: <code>vat_invoice_api.php</code>, <code>config.php</code>, <code>cli/gen_vat.php</code>, <code>cli/gen_dntt.php</code>, <code>cli/debug_add_type2.php</code>, <code>cli/check_invc.php</code>, <code>cli/get_unsigned_vat.php</code> - Skill gốc: <code>/root/.hermes/skills/crm/wininvoice-vat-invoice/SKILL.md</code> trên cloud100 - Nghị định 70/2025/NĐ-CP: Hiệu lực từ 1/6/2025 — quy định mới về xử lý hóa đơn sai sót - HTTP Basic Auth RFC 7617: Chuẩn xác thực API sử dụng