Sale Service
@nx/sale sở hữu vòng đời giỏ hàng và đơn hàng: một SaleOrder đảm nhận cả hai vai trò (giỏ hàng DRAFT + đơn hàng đã chốt). Nó nhận webhook MQ-Pay cho sự kiện thanh toán, điều phối luồng kitchen ticket, quản lý allocation và reservation cho ăn tại chỗ, đồng thời phát các topic Kafka + sự kiện WebSocket tới inventory, finance và các UI phía sau.
1. Tham chiếu nhanh
| Thuộc tính | Giá trị |
|---|---|
| Package | @nx/sale |
| Code | SVC-00030-SALE |
| Loại | Microservice |
| Runtime | Bun |
| Base Class | VerifierApplication |
| Vị trí | packages/sale |
| Base Path | /v1/api/sale |
| Dev Port | 31030 |
| Container Port | 3000 (external 31030) |
| Snowflake ID | 3 |
| DB Schema | sale (đa bảng - xem Domain Model) |
| Binding Namespace | @nx/sale |
2. Mục đích & Phạm vi
| Bao gồm | Loại trừ |
|---|---|
Một entity SaleOrder cho giỏ hàng + đơn hàng (DRAFT → … → COMPLETED / CANCELLED) | Thay đổi tồn kho (uỷ quyền cho @nx/inventory) |
Chế độ item: PRODUCT (tự gộp) và CUSTOM (luôn tạo dòng mới) | Tích hợp nhà cung cấp thanh toán (uỷ quyền cho @nx/mq-pay) |
Định giá lúc checkout qua HTTP call tới @nx/pricing | Bộ máy tính thuế |
| Xử lý webhook thanh toán (MQ-Pay HTTP webhook) | In hoá đơn (thuộc về frontend) |
Tách bill: SaleCheck (nhóm thanh toán độc lập) | Bộ máy tích điểm loyalty |
| Gộp / tách order (có thể đảo ngược) | Menu hướng tới khách hàng |
| Vòng đời kitchen ticket (FOH/BOH) - void, rush, ready, served | Dữ liệu công thức / BOM (thuộc @nx/inventory) |
| Sử dụng allocation (bàn, khu vực, unit cho DINE_IN) | |
| Reservation (đặt trước rồi đến) | |
| Quản lý ca POS - Shift v2 (drawer, enrollment, báo cáo X/Z) | |
| Cộng điểm khách hàng (loyalty) khi thanh toán thành công | |
| Báo cáo bán hàng (tổng hợp ngày, theo sản phẩm/danh mục, tổng kết mua hàng) | |
| Sự kiện WebSocket thời gian thực (phân phối nhiều room) |
3. Tech Stack
External:
| Library | Mục đích |
|---|---|
@venizia/ignis | IoC container, DI, BaseService, BaseController, ControllerFactory |
@venizia/ignis-helpers | Logger, KafkaProducerHelper, Redis helper |
@platformatic/kafka | Kafka client (sale chỉ dùng producer với mặc định của helper - không cấu hình idempotent/lz4 tường minh) |
hono | HTTP server (qua IGNIS) |
@hono/zod-openapi | Sinh OpenAPI từ Zod schema |
@scalar/hono-api-reference | OpenAPI explorer tại /doc |
drizzle-orm | Truy cập DB qua PostgresCoreDataSource |
pg | PostgreSQL driver |
lodash | Tiện ích |
Internal:
| Package | Mục đích |
|---|---|
@nx/core | Schema, repository (re-export), VerifierApplication, KafkaTopics, SaleOrderStatuses, SaleOrderItemModes, SaleConstraints |
@nx/pricing | Chỉ HTTP - PricingNetworkService gọi pricing service để lấy giá động lúc checkout |
4. Cấu trúc Dự án
packages/sale/
├── src/
│ ├── application.ts # VerifierApplication subclass
│ ├── index.ts # bootstrapApplication()
│ ├── migrate.ts # bootstrapMigration()
│ ├── common/
│ │ ├── constants.ts # SaleConstraints, ApplicationRoles
│ │ ├── keys.ts # BindingKeys
│ │ ├── rest-paths.ts # 13 RestPaths
│ │ ├── webhook-types.ts # PaymentWebhookEventTypes + zod schemas
│ │ ├── websocket.ts # 7 WebSocket topics + room helpers
│ │ ├── sale-check.constants.ts # check splitting helpers
│ │ ├── shift.types.ts # shift actor + context types
│ │ └── response.helper.ts # response shaping
│ ├── components/
│ │ ├── kafka/ # ApplicationKafkaComponent (chỉ producer)
│ │ └── websocket/ # ApplicationWebSocketComponent
│ ├── controllers/ # 13 thư mục controller → 16 lớp controller được đăng ký
│ ├── datasources/ # PostgresCoreDataSource
│ ├── migrations/processes/ # 3 migration (seed permission + role-permission, migration grant)
│ ├── models/ # zod request/response schemas
│ ├── repositories/ # re-exports từ @nx/core
│ └── services/ # 20 services
├── package.json
└── tsconfig.json5. Kiến trúc
Chi tiết: xem Architecture.
6. Tổng quan miền
ERD đầy đủ + bảng theo entity: xem Domain Model.
7. Tóm tắt Bề mặt
REST controllers - tham chiếu đầy đủ render trực tiếp từ /v1/api/sale/doc/openapi.json (live spec - Scalar viewer tại /doc, gateway portal):
| Controller | Base path | Ghi chú |
|---|---|---|
SaleOrderController | /sale-orders | + lifecycle (draft, items, checkout, revert, cancel, merge, split) |
SaleOrderItemController | /sale-order-items | CRUD + override để validate quantity |
SaleCheckController | /sale-checks | + split, split-equal, merge, rollback |
SaleOrderCheckController | /sale-orders/:id/checks | nested dưới order |
KitchenStationController | /kitchen-stations | CRUD |
KitchenTicketController | /kitchen-tickets | CRUD |
KitchenTicketSaleOrderController | /sale-orders/:id/kitchen-tickets/... | sendToKitchen |
KitchenTicketActionController | /kitchen-tickets/:id/... | void / rush / mark-ready / mark-served |
KitchenTicketItemActionController | /kitchen-ticket-items/:id/... | start-cooking / mark-ready / mark-served / void |
AllocationUsageController | /allocation-usages | CRUD + batch complete/cancel |
ReservationController | /reservations | + create with allocation |
ShiftController | /shifts | open / current / list / cash-movement / close / reconcile drawer / báo cáo X+Z |
CustomerController | /customers | CRUD |
PointTransactionController | /point-transactions | CRUD (đa số là đọc) |
SalesReportController | /reports/sales | Tổng hợp ngày, theo product, theo category, purchase-summary |
PaymentWebhookController | /webhooks/payment | Tiếp nhận sự kiện MQ-Pay (no auth) |
Bề mặt bất đồng bộ - tham chiếu đầy đủ tại API Events:
| Hướng | Kênh | Số lượng |
|---|---|---|
| Đến | HTTP webhook | 1 endpoint × 6 loại sự kiện |
| Đi ra | Kafka | 2 (PAYMENT_SUCCESS, KITCHEN_TICKET_ITEM_STATUS_CHANGED) |
| Đi ra | WebSocket | 7 topic × nhiều room helper (merchant/order/check/kitchen/allocation/reservation) |
8. Components
| Component | File | Mục đích |
|---|---|---|
ApplicationKafkaComponent | src/components/kafka/component.ts | Idempotent producer; phát PAYMENT_SUCCESS + KITCHEN_TICKET_ITEM_STATUS_CHANGED (không có consumer) |
ApplicationWebSocketComponent | src/components/websocket/component.ts | Phát WebSocket qua signal service; phân phối tới room |
| Redis cache (tùy chọn) | bind tại BindingKeys.APPLICATION_REDIS_CACHE | Cache permission cho authorization |
9. Services
| Service | File | Mô tả ngắn |
|---|---|---|
SaleOrderService | sale.service.ts | CRUD đơn DRAFT, add/clear item, cancel, archive |
SaleOrderItemService | sale-order-item.service.ts | Cập nhật item theo lô với khoá cấp dòng + tính lại tổng kết |
CheckoutService | checkout.service.ts | DRAFT → PROCESSING; pricing v1+v2; revert |
SaleCheckService | sale-check.service.ts | Tách bill: split, split-equal, merge, rollback |
OrderMergeService | order-merge.service.ts | Gộp nhiều draft order; có thể đảo ngược |
OrderSplitService | order-split.service.ts | Tách một order thành nhiều; phân bổ lại item + allocation + pricing |
KitchenTicketService | kitchen-ticket.service.ts | Gửi xuống bếp, void, rush, đánh dấu ready/served |
KitchenTicketItemService | kitchen-ticket-item.service.ts | Chuyển trạng thái theo dòng + phát Kafka |
AllocationUsageService | allocation-usage.service.ts | DINE_IN/TAKEAWAY/DELIVERY; reserved → completed/cancelled |
ReservationService | reservation.service.ts | Luồng đặt chỗ kèm giữ chỗ allocation |
ShiftService | shift.service.ts | Shift v2: open/join, close, ngữ cảnh ca theo thiết bị, list, validate; điều phối enrollment + drawer + report |
ShiftActorService | shift-actor.service.ts | Phân giải ngữ cảnh actor (user / device / merchant / saleChannel) từ request |
ShiftDrawerService | shift-drawer.service.ts | Drawer theo thiết bị: ghi nhận cash movement, đối chiếu, settle tiền mặt |
ShiftPolicyService | shift-policy.service.ts | Phân giải policy ca của merchant; kiểm soát bật/tắt quản lý ca |
ShiftReportService | shift-report.service.ts | Sinh báo cáo X/Z + snapshot (theo thiết bị + toàn ca) |
CustomerService | customer.service.ts | CRUD khách hàng |
CustomerPointService | customer-point.service.ts | Cộng điểm loyalty khi thanh toán thành công (idempotent) |
PaymentWebhookService | payment-webhook.service.ts | Bộ điều phối sự kiện webhook (định tuyến tới handler SaleOrder vs SaleCheck) |
SaleOrderPaymentWebhookService | sale-order-payment-webhook.service.ts | Xử lý sự kiện attempt + transaction cho SaleOrder; phát Kafka |
SaleCheckPaymentWebhookService | sale-check-payment-webhook.service.ts | Cùng luồng cho SaleCheck |
PricingNetworkService | pricing-network.service.ts | HTTP client gọi @nx/pricing cho calculate() + calculateV2() |
AllocationSnapshotService | allocation-snapshot.service.ts | Snapshot trạng thái allocation unit/zone trên sự kiện order để audit |
ProductVariantSnapshotService | product-variant-snapshot.service.ts | Snapshot metadata product variant lúc add order-item |
SalesReportService | sales-report.service.ts | Truy vấn tổng hợp daily / product / category / purchase |
10. Repositories
| Repository | Nguồn | Ghi chú |
|---|---|---|
SaleOrderRepository | @nx/core | + updateSummaryFromItems, getDailySummary, getProductSales, getCategorySales |
SaleOrderItemRepository | @nx/core | + updateAll, deleteAll |
SaleCheckRepository | @nx/core | + recalculateTotals |
SaleCheckItemRepository | @nx/core | + createAll |
KitchenTicketRepository | @nx/core | + findByIdempotencyKey, getNextSequence, evaluateTicketAutoProgression |
KitchenTicketItemRepository | @nx/core | + createAll |
KitchenStationRepository | @nx/core | - |
AllocationUsageRepository | @nx/core | + existsBySaleOrderId |
AllocationUnitRepository / AllocationZoneRepository | @nx/core | - |
ReservationRepository | @nx/core | - |
ShiftRepository | @nx/core | + findLatestByChannel, tổng hợp cash-flow / order-stats / finance-section |
ShiftEnrollmentRepository | @nx/core | + findActiveByPrincipal, findActiveByDevice, tổng hợp enrollment |
ShiftDrawerRepository | @nx/core | + findByShiftEnrollmentId |
ShiftEnrollmentEventRepository | @nx/core | Ledger sự kiện chỉ-ghi-thêm |
ShiftReportRepository | @nx/core | + getNextReportNo, hasZReport, findZReport, findLatestZReportByDevice |
PointTransactionRepository | @nx/core | + existsBySaleOrderId |
CustomerRepository | @nx/core | - |
SaleChannelRepository | @nx/core | - |
ProductVariantRepository, ProductIdentifierRepository, ProductInfoRepository | @nx/core | Đọc liên package |
ConfigurationRepository | @nx/core | Đọc cấu hình thanh toán đã mã hóa |
FinanceTransactionRepository, FinanceWalletRepository | @nx/core | Đọc liên package cho metadata finance lúc checkout |
PurchaseOrderRepository | @nx/core | Đọc liên package cho báo cáo bán hàng |
MetaLinkRepository, SettingRepository, DeviceRepository | @nx/core | Liên package |
11. Điểm vào
| File | Mục đích |
|---|---|
src/index.ts | Service entry → bootstrapApplication() |
src/migrate.ts | Migration entry → bootstrapMigration() |
src/application.ts | Application extends VerifierApplication |
12. Cấu hình
Env vars + dữ liệu seed: xem Configuration.
13. Vận hành
Triển khai + observability + bảo mật + runbook: xem Operations.
14. Trang liên quan
Concepts - vì sao/cách thức:
- Architecture
- Domain Model
- Integration - webhook MQ-Pay + hợp đồng inventory/finance/commerce/identity
Reference - tra cứu:
- API Events
- Configuration
- Operations
- REST endpoints - live OpenAPI tại
/v1/api/sale/doc/openapi.json(live spec - Scalar viewer tại/doc, gateway portal)
Features - đào sâu:
- Sale Order
- Checkout
- Order Operations - merge / split
- Check Splitting
- Kitchen Orders
- Payment Webhooks
- Allocation Usage
- Reservation
- Ca làm việc (Shift)
- Sales Report
- Customer Points
Decisions: