Để xử lý giao dịch trùng khi đối soát thanh toán TPBank qua API, hệ thống cần nhận diện từng giao dịch ngân hàng bằng khóa duy nhất và ghi nhận thanh toán trong một transaction cơ sở dữ liệu. Kiểm tra trùng ở mã ứng dụng nhưng không có ràng buộc dữ liệu vẫn có thể khiến hai tiến trình cùng cộng tiền.
Trước tiên, cần phân biệt một giao dịch được gửi thông báo nhiều lần với việc khách thực sự chuyển khoản hai lần. Hướng dẫn dưới đây giúp chủ website và lập trình viên chọn khóa chống trùng, xử lý đồng thời và kiểm tra kết quả. Các ví dụ đều là giả lập, không phải cấu trúc API chính thức của TPBank.
Cùng một khoản tiền vào có thể xuất hiện nhiều lần vì webhook được gửi lại, tác vụ lấy lịch sử chạy chồng nhau hoặc hệ thống đọc các khoảng thời gian giao nhau. Đây là nhiều lần nhìn thấy một giao dịch, không phải nhiều khoản tiền.

Ngược lại, khách có thể chuyển hai lần với cùng số tiền và nội dung. Nếu ngân hàng ghi nhận hai giao dịch độc lập, hệ thống phải lưu cả hai rồi áp dụng quy tắc xử lý tiền thừa hoặc thanh toán bổ sung.
Không nên dùng tổ hợp số tiền, nội dung và phút giao dịch làm khóa duy nhất. Hai khách có thể chuyển cùng số tiền trong cùng một phút.
Trước khi sửa mã, hãy xác định dữ liệu đến từ kết nối ngân hàng nào hoặc nhà cung cấp tích hợp bên thứ ba nào. Dịch vụ đọc giao dịch TPBank của bên thứ ba không mặc nhiên là API chính thức hay được TPBank bảo chứng.
Cần đối chiếu tài liệu của bên cung cấp để biết trường nào định danh giao dịch ổn định, phạm vi duy nhất của trường đó và cách phân biệt tiền vào, tiền ra, trạng thái chờ hoặc điều chỉnh. Không mặc định mã thông báo webhook chính là mã giao dịch ngân hàng.
Một thiết kế minh họa có thể đặt ràng buộc UNIQUE(source, receiving_account, bank_transaction_id). Chỉ áp dụng cấu trúc này khi ý nghĩa các trường phù hợp với tài liệu thực tế. Mã sự kiện dùng để theo dõi lần gửi; mã giao dịch dùng để nhận diện khoản tiền.
Nếu webhook và tác vụ lấy lịch sử mô tả cùng khoản chuyển bằng hai mã khác nhau, cần quy tắc ánh xạ được nhà cung cấp xác nhận. Nếu chưa có cách xác định chắc chắn, đưa giao dịch vào hàng chờ đối soát thủ công thay vì tự ghép bằng suy đoán.
Mỗi đơn nạp nên có mã nội dung riêng, số tiền dự kiến, tài khoản nhận và trạng thái rõ ràng. Giao dịch nhận được phải được kiểm tra đúng tài khoản, đúng chiều tiền vào, loại tiền và trạng thái đủ điều kiện trước khi ghép với đơn.

Transaction bảo đảm các thay đổi cùng thành công hoặc cùng bị hủy. Ràng buộc duy nhất ở cơ sở dữ liệu ngăn hai tiến trình cùng ghi nhận một giao dịch. Nếu có bảng sổ cái, bút toán cộng tiền cũng cần ràng buộc duy nhất với giao dịch nguồn.
Đoạn dưới là giả mã minh họa logic, không phải mã tích hợp TPBank:
BEGIN TRANSACTION
INSERT giao_dich WITH khoa_duy_nhat
LOCK don_nap_can_doi_chieu
CHECK tai_khoan_nhan, so_tien, trang_thai
INSERT but_toan WITH giao_dich_nguon_duy_nhat
UPDATE don_nap_va_so_du
COMMIT
IF trung_khoa:
READ ket_qua_da_luu
CHECK du_lieu_co_nhat_quan
RETURN ket_qua_khong_cong_laiNếu đơn đã được thanh toán bằng một giao dịch khác, không tự động cộng lần nữa theo cùng đơn. Hãy lưu khoản mới và chuyển sang quy trình tiền thừa, hoàn tiền hoặc xét duyệt theo chính sách.
Webhook phải được xác minh bằng cơ chế mà tài liệu nhà cung cấp quy định, chẳng hạn chữ ký nếu dịch vụ có hỗ trợ. Không tự đặt thuật toán, tên header hoặc quy tắc ký. Secret và thông tin truy cập phải nằm phía server, không đưa vào JavaScript trình duyệt hay nhật ký công khai.
Không coi callback trên trình duyệt là bằng chứng thanh toán. Trang báo thành công chỉ nên hiển thị trạng thái do server xác nhận. Dữ liệu do khách gửi lên không được tự quyết định việc cộng số dư.
Khi hệ thống đã commit nhưng phản hồi bị mất, nhà cung cấp có thể gửi lại thông báo. Lần xử lý sau phải trả kết quả đã lưu mà không tạo bút toán mới. Nếu cơ sở dữ liệu lỗi trước commit, retry có thể thực hiện lại toàn bộ nghiệp vụ mà không để lại số dư dở dang.
Với xử lý qua hàng đợi, chỉ xác nhận tiếp nhận sau khi đã lưu sự kiện bền vững. Các tác vụ ngoài cơ sở dữ liệu như gửi thông báo nên chạy sau commit; không để lỗi gửi tin nhắn làm lặp thao tác tài chính.
Ví dụ giả lập: đơn NAP-DEMO-42 cần nhận 200.000 đồng. Giao dịch TX-DEMO-A khớp đơn, sau đó xuất hiện lại qua webhook và tác vụ lấy lịch sử.

TX-DEMO-B cùng nội dung: phải lưu riêng và xử lý theo quy tắc đơn đã thanh toán.Kết quả cần kiểm tra gồm số giao dịch nguồn duy nhất, số bút toán, trạng thái đơn và biến động số dư. Nhật ký nên có mã giao dịch, mã đơn, nguồn nhận và kết quả xử lý, nhưng phải che thông tin nhạy cảm. Định kỳ so sánh sổ cái nội bộ với lịch sử giao dịch tin cậy để phát hiện khoản chưa ghép hoặc ghi nhận thiếu.
Lỗi phổ biến là dùng thao tác “kiểm tra tồn tại rồi mới thêm” mà không có khóa duy nhất; webhook và cron vẫn có thể cùng vượt qua bước kiểm tra. Một lỗi khác là đánh dấu đơn thành công trước khi ghi bút toán hoàn tất, khiến trạng thái thanh toán không phản ánh số dư thực.
Không đủ. Mã đơn xác định yêu cầu thanh toán, còn mã giao dịch xác định khoản chuyển thực tế. Cần quản lý cả hai để không bỏ sót khoản chuyển thứ hai.
Có, nếu dùng chung logic chuẩn hóa, khóa giao dịch và transaction. Hai kênh không nên tự cộng tiền bằng hai luồng độc lập.
Yêu cầu nhà cung cấp làm rõ định danh và phạm vi duy nhất. Trong lúc chưa xác nhận, lưu dữ liệu để kiểm tra thủ công; không tự động bỏ giao dịch chỉ vì giống số tiền và nội dung.
Hãy rà soát khóa duy nhất, transaction và cách ghép đơn trước khi bật lại tự động cộng tiền. Sau đó chạy bộ kiểm thử gửi lặp, xử lý đồng thời và mất phản hồi trên môi trường thử nghiệm.
Nếu cần chọn mã nguồn hoặc dịch vụ tích hợp, bạn có thể tham khảo danh mục liên quan tại sieuthicode.com và yêu cầu xác nhận nguồn dữ liệu TPBank, cơ chế chống trùng, khả năng kiểm thử cùng phạm vi hỗ trợ trước khi lựa chọn.