Fakebox là máy chủ HTTP chạy cục bộ, nói đúng thứ API hw_proxy như một IoT Box của Odoo, nhờ đó kiểm thử được máy thanh toán, cân và máy in biên lai của POS mà không cần phần cứng.
Chúng tôi làm Fakebox vì muốn tái hiện các sự cố liên quan tới PosBox mà không phải thật sự chạy một cái PosBox. Nó là một máy chủ HTTP chạy cục bộ, nói đúng thứ API hw_proxy mà một IoT Box hay POSbox thật của Odoo dùng. Trỏ cấu hình POS của bạn vào nó và client Odoo trên trình duyệt không nhận ra khác biệt.
Bài này nói về vì sao việc thay thế này chạy được ở tầng giao thức, Fakebox giả lập những thiết bị nào, cách điều khiển kết quả kiểm thử lúc chạy, và nó khớp vào quy trình phát triển POS Odoo trên máy cá nhân ra sao.
Vì sao việc thay thế này chạy được
Trước khi nói Fakebox làm gì, nên hiểu vì sao một máy chủ phần mềm lại thay được phần cứng vật lý.
Bức tường bảo mật của trình duyệt
POS của Odoo là một ứng dụng web một trang. Trình duyệt không truy cập trực tiếp được cổng USB, cổng serial hay bất kỳ giao diện phần cứng nào ở tầng hệ điều hành. Mọi tương tác với phần cứng đều phải đi qua HTTP. IoT Box (hay POSbox) tồn tại chính là để bắc cầu qua khoảng cách đó: nó là một máy chủ HTTP chạy cục bộ trên cùng mạng với máy trạm POS, và client Odoo trên trình duyệt gọi nó như gọi bất kỳ API nào khác.
Chính thiết kế này làm cho Fakebox khả thi. Dưới góc nhìn của Odoo, IoT Box chẳng qua là một nhóm endpoint HTTP nằm dưới /hw_proxy/. Bất kỳ máy chủ nào phản hồi đúng cho các endpoint đó đều là một IoT Box hợp lệ. Fakebox chính là máy chủ ấy.
Giao thức
Mọi tương tác với thiết bị đều theo cùng một khuôn: trình duyệt Odoo gửi một HTTP POST tới /hw_proxy/<command> kèm một payload JSON-RPC, và IoT Box trả về một kết quả JSON. Trong mã nguồn Odoo, phía trình duyệt không có chút logic nào riêng cho phần cứng. Nó gọi proxy, đọc kết quả, rồi cập nhật giao diện POS tương ứng.
Fakebox cài đặt mọi endpoint mà trình duyệt POS của Odoo gọi tới. Nó không mô phỏng phần cứng ở mức driver. Nó nói đúng giao thức.
Bắt đầu
Fakebox phát hành theo giấy phép AGPL-3.0 và đặt tại gitlab.trobz.com/services/fakebox.
Cài từ mã nguồn:
git clone https://gitlab.trobz.com/services/fakebox.git
cd fakebox
pip install -e .
Chép file cấu hình mẫu:
cp fakebox/config.sample.py fakebox/config.py
Mặc định là 127.0.0.1:5000 cho máy chủ HTTP và 127.0.0.1:2121 cho máy chủ FTP (dùng cho cân Bizerba). Sửa config.py nếu muốn đổi.
Khởi động Fakebox:
fakebox
Kiểm tra nó đang chạy:
curl http://127.0.0.1:5000/hw_proxy/hello
Rồi đặt URL của IoT Box trong cấu hình POS của bạn thành http://127.0.0.1:5000. POS sẽ bắt tay, hỏi trạng thái thiết bị, và hành xử như thể có một cái box thật đang kết nối.
Các thiết bị được giả lập
Máy thanh toán
Phần giả lập máy thanh toán mặc định dùng một quy tắc tất định theo số tiền: đơn từ 100 EUR trở xuống cho ra giao dịch thất bại; đơn trên 100 EUR thì thành công. Nhờ vậy bạn phủ được cả hai kết cục trong một phiên kiểm thử mà không cần cấu hình gì.
Amount <= 100 EUR -> transaction failed
Amount > 100 EUR -> transaction succeeded
Muốn điều khiển theo kiểu tương tác, hãy đặt PAYMENT_TERMINAL_DRIVER=mock trước khi khởi động Fakebox. Ở chế độ mock, máy chủ sẽ hỏi trên stdin mỗi lần một giao dịch bắt đầu. Gõ ok để thành công, hoặc gõ bất kỳ chuỗi nào khác để đặt một trạng thái lỗi cụ thể. Cách này hữu ích khi bạn cần kiểm tra một thông báo lỗi nhất định mà POS hiển thị.
Ngăn kéo tiền tự động Cashlogy
Phần giả lập Cashlogy cài đặt trọn giao thức giao dịch mà Odoo dùng:
start_add_change: được gọi khi hộp thoại giao dịch với khách hàng mở raget_amount_accepted: được hỏi mỗi 0,1 giây để cập nhật số tiền hiển thị trong hộp thoạistop_acceptance: được gọi khi hộp thoại được xác nhận, bằng tay hoặc tự độngdispense: được gọi để nhả tiền thối cho khách
Các truy vấn số dư đầu và cuối ca cũng được hỗ trợ: get_total_amount trả về tổng tiền mặt trong máy, còn get_inventory trả về chi tiết theo tiền xu và tiền giấy. Chúng được dùng trong luồng mở và đóng phiên POS khi pos.config.cash_control được bật.
Mọi số tiền đều do output/values.ini chi phối:
[cashlogy]
amount_accepted = 50.00
amount_recycler = 200.00
amount_stacker = 50.00
amount_recycler cộng amount_stacker là tổng tiền mặt trong máy (get_total_amount trả về tổng của hai giá trị này). amount_accepted là số tiền khách đã nhét vào tới thời điểm hiện tại.
Cân
Fakebox hỗ trợ hai loại cân mà POS của Odoo dùng trong những cấu hình khác nhau.
Toledo (cân nối trực tiếp với POS): phản hồi các request HTTP đến thẳng từ phiên POS. Fakebox cài đặt scale_read, scale_price, scale_price_tare, scale_price_text, scale_price_tare_text và reset_weight. Giá trị trọng lượng và giá được đọc từ values.ini.
Bizerba (cân tự phục vụ): dùng FTP để đẩy dữ liệu món đã cân lên một máy chủ cân. Fakebox chạy một máy chủ FTP bằng pyftpdlib ở cổng 2121, nhận các lượt tải lên từ cân. File nhận được nằm trong output/scale/ và xem được tại http://127.0.0.1:5000/scale. Nếu mẫu Bizerba của bạn dùng bảng mã không phải UTF-8, hãy khai báo trong values.ini:
[scale]
encoding = iso8859-1
Máy in biên lai và các thiết bị ngoại vi khác
Các endpoint của máy in biên lai (print_receipt, print_xml_receipt) lưu mỗi biên lai in ra thành một file trong output/receipts/. Xem chúng tại http://127.0.0.1:5000/receipt để soi chính xác POS gửi ra cái gì, mà không cần cắm máy in thật. Cách này hữu ích khi debug template biên lai hoặc kiểm tra cấu trúc XML của một bố cục biên lai tùy chỉnh.
Các endpoint của màn hình hướng về khách (send_text_customer_display, send_currency_data_customer_display) ghi log payload của chúng. Endpoint của máy quét mã vạch (/hw_proxy/scanner) là một stub trả về phản hồi thành công.
Điều khiển kết quả kiểm thử bằng values.ini
File output/values.ini được đọc lại ở mọi request liên quan, nên thay đổi có hiệu lực ngay mà không cần khởi động lại máy chủ hay phiên POS. Đây là cần gạt chính để điều khiển những gì Fakebox trả về lúc chạy.
Kiểm thử thủ công
Trong lúc một phiên POS đang mở, hãy sửa values.ini để đổi trạng thái mà Fakebox báo về. Đổi amount_accepted thì hộp thoại Cashlogy cập nhật ở lần hỏi kế tiếp (mỗi 0,1 giây). Đổi trọng lượng của cân thì lần cân sau trả về giá trị mới. Không tải lại trang, không khởi động lại máy chủ.
Kiểm thử bằng script
Một script kiểm thử ghi các giá trị cụ thể vào values.ini trước khi kích hoạt một thao tác POS, rồi khẳng định trên kết quả. Không mock, không monkey-patch, không có test double nào trong mã ứng dụng.
Ví dụ, mô phỏng một phiên Cashlogy trong đó khách nhét vào đúng số tiền của đơn hàng:
echo "[cashlogy]
amount_accepted = 150.00
amount_recycler = 0.00
amount_stacker = 150.00" > output/values.ini
POS hỏi get_amount_accepted, thấy 150.00, tự xác nhận giao dịch (options.auto_accept = true), rồi duyệt đơn hàng. Trọn luồng thuận lợi chạy hết mà không cần can thiệp tay.
Pipeline CI
Fakebox khởi động bằng lệnh fakebox và không có phụ thuộc bên ngoài nào ngoài các gói Python cài lúc thiết lập. Một job CI có thể chạy nó như một tiến trình nền, chạy bộ test POS lên nó, rồi dẹp đi. File values.ini có thể được phần thiết lập test ghi sẵn để mỗi ca kiểm thử cho ra kết quả tất định.
Nhờ vậy, những luồng POS phụ thuộc phần cứng trở nên kiểm thử được ở những môi trường sẽ chẳng bao giờ có một IoT Box thật cắm vào.
Kết luận
Fakebox chạy được vì IoT Box của Odoo là một giao thức, không phải một thiết bị. Bất kỳ máy chủ HTTP nào phản hồi đúng cho các endpoint hw_proxy đều là một vật thay thế hợp lệ. Fakebox cài đặt những endpoint đó, thêm phần điều khiển kiểm thử tất định qua values.ini, và chạy trên máy của lập trình viên chỉ bằng một lệnh.
Cài nó từ gitlab.trobz.com/services/fakebox rồi trỏ cấu hình POS của bạn vào http://127.0.0.1:5000.