Kiểm tra mã số thuế là bước gần như bắt buộc trong mọi biểu mẫu dành cho doanh nghiệp, nhưng rất nhiều dự án chỉ làm được một nửa công việc rồi tưởng mình đã làm xong. Nửa còn lại không thể giải bằng thuật toán, và nếu bạn không nói rõ ranh giới đó với người dùng, hệ thống của bạn sẽ đưa ra những kết luận sai một cách rất tự tin. Bài này tách từng tầng kiểm tra ra và nói rõ mỗi tầng trả lời được câu hỏi gì.
Mã số thuế là gì?
Đây là định danh mà cơ quan thuế gán cho một chủ thể có nghĩa vụ thuế. Cách gọi, độ dài và cấu trúc khác nhau giữa các nước, vì mỗi hệ thống thuế tự quy định cách đánh số của mình. Ở không ít nơi, mã số thuế của doanh nghiệp trùng với mã số đăng ký doanh nghiệp, khiến hai khái niệm bị dùng lẫn; ở nơi khác, chúng là hai mã riêng biệt được cấp bởi hai cơ quan khác nhau. Vì chúng không suy ra được từ nhau, bài mã số đăng ký công ty theo từng quốc gia cần được đọc kèm bài này khi bạn thiết kế trường dữ liệu.
Điều quan trọng nhất cần nắm là mã số thuế không phải một giá trị có thể suy ra từ tên hay địa chỉ. Nó do cơ quan thuế cấp, và chỉ cơ quan thuế mới xác nhận được nó thuộc về ai. Mọi suy luận tự động chỉ có giá trị loại trừ lỗi nhập liệu, không có giá trị xác nhận danh tính.
Vì sao có mã có chữ số kiểm tra, có mã không?
Vì chữ số kiểm tra là một lựa chọn thiết kế của cơ quan cấp, không phải thuộc tính chung của mọi loại mã số thuế. Ở nơi có áp dụng, một hoặc vài chữ số cuối được tính từ các chữ số còn lại theo một quy tắc công bố, giúp phát hiện lỗi gõ và lỗi đảo vị trí. Ở nơi không áp dụng, mã chỉ là một số thứ tự do cơ quan cấp gán ra, và không có cách nào tính toán để biết một số bất kỳ có phải là mã hợp lệ hay không.
Sự khác biệt này dẫn tới một hệ quả thường bị bỏ qua: tính năng kiểm tra của bạn phụ thuộc vào nơi cấp, nên nó phải được bật tắt theo quốc gia chứ không thể bật đồng loạt. Việc áp một thuật toán chữ số kiểm tra của nước này lên mã của nước khác sẽ tạo ra kết quả sai có hệ thống: hoặc chặn nhầm dữ liệu đúng, hoặc cho qua dữ liệu sai.
Kiểm tra định dạng chặn được những lỗi nào?
Kiểm tra định dạng, chạy hoàn toàn cục bộ, chặn được những lỗi đơn giản mà chi phí sửa về sau rất cao: người dùng nhập thiếu ký tự, nhập thừa ký tự, dùng ký tự không được phép, hoặc dán kèm cả khoảng trắng và dấu phân cách. Nếu nơi cấp có công bố quy tắc chữ số kiểm tra, tầng này còn phát hiện được lỗi gõ một chữ số.
Kiểm tra định dạng không làm được gì hơn thế. Nó không biết mã đã từng được cấp hay chưa, không biết chủ thể sau mã đó còn hoạt động hay đã giải thể, không biết người đang nhập có liên quan gì tới chủ thể ấy, và không biết mã đó có đang được dùng đúng mục đích khai báo hay không. Bốn câu hỏi đó đều nằm ngoài tầm với của một biểu thức kiểm tra.
| Tầng kiểm tra | Câu hỏi trả lời được | Cần mạng | Kết luận tối đa có thể đưa ra |
|---|---|---|---|
| Hình dạng | Chuỗi nhập vào có đúng cấu trúc cho phép không | Không | Dữ liệu nhập sai định dạng |
| Chữ số kiểm tra | Mã có vượt qua quy tắc công bố của nơi cấp không | Không | Nhiều khả năng có lỗi gõ |
| Tra cứu chính thức | Mã có đang được ghi nhận ở nguồn chính thức không | Có | Có hoặc không tìm thấy, kèm thời điểm |
| Đối chiếu quyền | Người nhập có quyền đại diện chủ thể không | Có | Cần bằng chứng ngoài mã |
Vì sao không được coi “kiểm tra thất bại” là “công ty không tồn tại”?
Vì hai câu đó khác nhau về bản chất và khác nhau về hậu quả. Khi một mã không vượt qua kiểm tra chữ số kiểm tra, thông tin duy nhất bạn có là chuỗi vừa nhập không khớp với quy tắc đã công bố. Nguyên nhân có thể là người dùng gõ nhầm, có thể là hệ thống đang áp quy tắc của sai quốc gia, cũng có thể là quy tắc bạn dùng đã lỗi thời. Không nguyên nhân nào trong số đó cho phép kết luận rằng doanh nghiệp kia không tồn tại.
Hậu quả của việc đánh đồng hai câu này là rất thực tế: một khách hàng hợp lệ bị từ chối ở bước cuối của luồng đăng ký, hỗ trợ khách hàng không có thông tin để giải thích vì sao, và đội kỹ thuật phải mở lại hộp đen để tìm lỗi. Cách phòng ngừa đơn giản là dùng đúng từ trong thông báo lỗi: nói “mã không đúng định dạng” khi đó là lỗi định dạng, và nói “chưa xác minh được” khi đó là hạn chế của nguồn tra cứu.
Phần dành cho nhà phát triển
Hãy thiết kế phần kiểm tra theo ba tầng, mỗi tầng có một loại kết luận được phép đưa ra, và không tầng nào được nói thay tầng khác. Cách này nghe có vẻ nhiều việc, nhưng nó giúp bạn giải thích được mọi quyết định của hệ thống khi có khiếu nại.
Vài điểm nên chốt:
- Trả về lỗi có thể phân biệt được: lỗi định dạng, lỗi chữ số kiểm tra, không tìm thấy ở nguồn chính thức, và nguồn chưa phản hồi là bốn trạng thái khác nhau, không phải một trạng thái “sai”.
- Không tự cài đặt quy tắc của từng quốc gia nếu bạn không có người chịu trách nhiệm cập nhật; hãy để tầng định dạng rộng và dựa vào tầng tra cứu.
- Lưu lại kết quả tra cứu kèm thời điểm và nguồn, để việc rà soát về sau không phải dựa vào trí nhớ.
- Xử lý thời gian chờ và lỗi mạng như trạng thái tạm thời, có thể chạy lại, thay vì biến chúng thành từ chối vĩnh viễn.
- Đừng để tầng kiểm tra tự động ghi đè dữ liệu người dùng đã nhập; nếu bạn chuẩn hoá, hãy giữ bản gốc và cho người dùng xem kết quả sau khi chuẩn hoá.
- Trong dữ liệu thử, hãy tạo mã đúng hình dạng cho từng nhóm quốc gia để chạy hết các nhánh, và đánh dấu rõ đây là dữ liệu tổng hợp.
- Phân biệt mã số thuế với các mã định danh khác như mã pháp nhân và mã do tổ chức tư nhân cấp, vì mỗi loại có cách kiểm tra riêng; bài LEI và DUNS mô tả khác biệt đó.
Để chạy các nhánh đó, trình tạo dữ liệu công ty để thử nghiệm của trang này sinh hồ sơ công ty tổng hợp kèm mã số đăng ký và mã VAT theo quốc gia bạn chọn, giúp bạn thử cả trường hợp có mã và trường hợp không có. Mọi mã số nêu trong bài đều được mô tả bằng lời; không có mã thật nào được cung cấp ở đây, và nội dung bài không dùng cho mục đích kê khai thuế.
Bước tiếp theo
Hãy rà lại thông báo lỗi của biểu mẫu xem chúng có đang gộp bốn trạng thái nói trên thành một câu hay không, rồi tách ra. Sau đó thêm ca kiểm thử cho tình huống nguồn tra cứu chính thức không phản hồi, vì đây là nhánh dễ bị xử lý thành từ chối sai nhất. Bài mã số VAT theo quốc gia mô tả cách tách hai tầng kiểm tra trong bối cảnh hoá đơn xuyên biên giới.