Báo cáo chuyển đổi warehouse-service

Tồn kho · inventory/enable-inventory-tracking · api

PUT/api/client/page/product/enable-inventory-tracking

Vòng
2
Cổng G1–G6
PENDING_SONAR
Bước
sonar-check
Nhánh đích
feat/thongpd/migrate-inventory-ws1

Phân tích luồng sau chuyển — inventory/enable-inventory-tracking — vòng 2

Đường dẫn mới tính từ C:/Projects/warehouse-service-wt/ws1/src/main/java/com/softdreams/easypos/warehouse/; PMS = easyposbackend1:src/main/java/vn/softdreams/easypos/service/impl/ProductManagementServiceImpl.java.

F-01 Kiểm yêu cầu bật theo dõi tồn

  • Điểm vào: cũ easyposbackend1:.../web/rest/ProductManagementResource.java:766-772 → PMS:3279 → mới presentation/web/inventory/InventoryTrackingController.java:45 → application/inventory/InventoryTrackingService.java:69
  • Quy tắc: R-01, R-02, R-03, R-04, R-05, R-06, R-11, R-12, R-13

Sơ đồ luồng mới (theo code thực tế)

sequenceDiagram
    participant W as InventoryTrackingController
    participant S as InventoryTrackingService (@Transactional)
    participant U as CurrentUserPort
    participant I as InitialStockRelationalRepository
    participant P as ProductTrackingRelationalAdapter
    W->>W: Guard.validateInput(validator, request) (mọi vi phạm, 400)
    W->>S: enableInventoryTracking(command)
    S->>U: findCompanyId() — rỗng → 400 TOKEN_EXPIRED; khác comId → 500 COMPANY_NOT_EXISTS_CODE
    S->>I: findDefaultWarehouse(comId) (WH1 ORDER BY id, lấy dòng đầu, Optional)
    S->>S: validateRequest: tracking≠true → 400 FALSE; count null → 400; price null → 400
    S->>P: findUnit(comId, ppuId) — rỗng → 500 PRODUCT_NOT_FOUND; isPrimary null → 500 EXCEPTION_ERROR; false → 500 ENABLE_TRACKING_ERROR
    S->>P: findActiveProduct(comId, productId) — rỗng → 500 PRODUCT_NOT_FOUND; tracking null → 500 EXCEPTION_ERROR; true → 400 INVALID
    S-->>W: (sang F-02) rồi BaseResponseDTO.ok(null, UPDATE_PRODUCT_SUCCESS)

Đối chiếu từng bước

# Luồng cũ Luồng mới Kết luận
1 ProductManagementResource.java:766-772 validateInput (LF-01) InventoryTrackingController.java:46 + EnableInventoryTrackingRequest KHỚP (body hỏng: KHÁC có chủ đích D-02)
2 PMS:3281 getUserWithAuthorities(comId) InventoryTrackingService.java:144-151 KHỚP 2 kiểm; các kiểm user khác: KHÁC có chủ đích (D-04)
3 PMS:3282 getWarehouseDefault InventoryTrackingService.java:71, InitialStockRelationalRepository.java:57 KHỚP (đọc trước kiểm R-04)
4 PMS:3289-3292 kiểm tracking/count/price InventoryTrackingService.java:153-163 KHỚP
5 PMS:3294-3305 ppu, is_primary InventoryTrackingService.java:73-77,166-171 KHỚP; NPE → 500 thay 417: KHÁC có chủ đích (D-03)
6 PMS:3308-3320 product active, inventory_tracking InventoryTrackingService.java:78-82 KHỚP về mã/HTTP; câu thông báo PRODUCT_NOT_FOUND: KHÁC (F-logic-2)
7 Kiểm gói LF-21 không có CHỈ CÓ Ở CŨ (D-08)
8 PMS:3406 BaseResultDTO SUCCESS InventoryTrackingController.java:56 KHÁC có chủ đích (D-02), giữ mã UPDATE_PRODUCT_SUCCESS

Dữ liệu và side effect

Bảng / topic / cache Cũ Mới Ghi chú
warehouse đọc top(1) WH1 theo com_id đọc WH1 theo com_id ORDER BY id, lấy dòng đầu KHỚP
product_product_unit đọc (id, com_id) đọc (id, com_id) KHỚP
product đọc (id, com_id, active) đọc (id, com_id, active = 1) KHỚP
user/company cache đọc chỉ đọc token D-04

Transaction, khoá, idempotency, tenant

  • Ranh giới transaction: cũ là class @Transactional (PMS). Mới đặt @Transactional ở InventoryTrackingService.enableInventoryTracking. Ở F-01 không có lệnh ghi.
  • Khoá: cả hai đều không khoá. Hai request đồng thời có thể cùng qua bước kiểm "chưa theo dõi" ở cả cũ lẫn mới, không tệ hơn cũ.
  • Idempotency: không áp dụng (API đồng bộ).
  • Lọc comId: mọi truy vấn đọc ở F-01 đều có com_id.

Lệch so với luồng mới đã duyệt (spec mục 6)

không

Dev cần chú ý khi review

Vị trí Vì sao
InventoryTrackingService.java:70-72 Thứ tự token → kho → kiểm request phải giữ đúng như cũ (đọc kho trước kiểm R-04)
InventoryTrackingService.java:74,79 Câu thông báo PRODUCT_NOT_FOUND có placeholder không được điền (F-logic-2)

(F-01 chép nguyên từ vòng 1 — không đổi, không có file trong fix.diff.)

F-02 Tính và ghi sản phẩm, tồn, phiếu khởi tạo

  • Điểm vào: cũ PMS:3321-3405 → mới application/inventory/InventoryTrackingService.java:83-97,99-124
  • Quy tắc: R-07, R-08, R-09, R-10, R-13

Sơ đồ luồng mới (theo code thực tế)

sequenceDiagram
    participant S as InventoryTrackingService (@Transactional)
    participant Pl as InventoryTrackingPlan
    participant P as ProductTrackingRelationalAdapter (JDBC)
    participant R as InitialRsInoutwardService
    participant I as InitialStockRelationalRepository (JDBC)
    participant K as LegacyInventoryLogKafkaProducer (KafkaTemplate riêng, value StringSerializer)
    S->>P: findUnitsOfProduct (ORDER BY is_primary DESC)
    S->>Pl: plan(units, count, price) (cờ null / rate 0 → EXCEPTION_ERROR)
    S->>P: updateUnits: on_hand/purchase_price đổi → UPDATE toàn cột chuỗi đã làm sạch + audit
    S->>P: enableTracking: UPDATE inventory_tracking=1, in_price, inventory_count, audit, cột chuỗi đổi
    alt không có WH1
        S-->>S: return (commit, 200)
    else có WH1
        loop mỗi ppu is_primary = true
            S->>R: prepare: N2 (>1 → EXCEPTION_ERROR), SequenceService.nextCode(NK), dựng RsInoutward
        end
        S->>I: findStockRows(comId, WH1, ppuIds) — dòng không lô, trùng ppu giữ dòng cuối
        S->>K: send(LegacyInventoryLog) mỗi dòng — JSON thô, key productId, header messageId (ngay, trước commit)
        S->>I: updateOnHand(id, onHand, actor) mỗi dòng
        S->>R: save(phiếu đầu tiên) → RsInoutwardRepository.saveAll
    end

Đối chiếu từng bước

# Luồng cũ Luồng mới Kết luận
1 PMS:3324 getAllByProductIdAndComId InventoryTrackingService.java:84, ProductTrackingRelationalAdapter.java:97-99 KHỚP
2 PMS:3326-3343 tính on_hand/giá InventoryTrackingPlan.java:32-51 KHỚP (NPE/chia 0 → 500: D-03)
3 PMS:3353 saveAll ppu ProductTrackingRelationalAdapter.java:102-133 KHỚP (D-10, K-02)
4 PMS:3354 save product ProductTrackingRelationalAdapter.java:136-157 KHÁC có chủ đích (D-11)
5 PMS:3357-3367,3396-3399 NPE thiếu WH1 bị nuốt InventoryTrackingService.java:95-96 KHÁC có chủ đích (D-05), cùng kết quả
6 PMS:6486-6490 N2 + genCode NK mỗi ppu chính InventoryTrackingService.java:101-105, InitialRsInoutwardService.java:71-78 KHỚP (D-03, D-09)
7 PMS:6553-6608 dựng phiếu + 1 dòng InitialRsInoutwardService.java:79-119 KHỚP (D-09)
8 BaseInventoryServiceImpl.java:639-665 gom dòng không lô, giữ dòng cuối InitialStockRelationalRepository.java:65-85 KHỚP (D-06)
9 BaseInventoryServiceImpl.java:691-698,1021-1038 gửi log trước khi lưu, value StringSerializer InventoryTrackingService.java:111-117, LegacyInventoryLogKafkaProducer.java:43-73 KHỚP: nội dung (D-07) và serializer (đã sửa F-logic-1 vòng 1)
10 PMS:3384-3390 saveAll BaseInventory InitialStockRelationalRepository.java:88-95 KHỚP
11 PMS:3391-3393 lưu phiếu đầu tiên InventoryTrackingService.java:121-123 KHỚP
12 PMS:3401-3405 task log (list rỗng) không có CHỈ CÓ Ở CŨ, không có side effect

Dữ liệu và side effect

Bảng / topic / cache Cũ Mới Ghi chú
product_product_unit UPDATE toàn dòng khi đổi như cũ qua JDBC KHỚP; WHERE chỉ theo id (F-logic-3 vòng 1)
product UPDATE cột đổi + cột chuỗi bị làm sạch như cũ D-11
inventory UPDATE on_hand, updater, update_time như cũ KHỚP; WHERE chỉ theo id (F-logic-3 vòng 1)
rs_inoutward, rs_inoutward_detail INSERT 1 + 1 INSERT qua saveAll KHỚP
Redis sequence NK HINCRBY mỗi ppu chính SequenceService.nextCode mỗi ppu chính D-09/LF-44
Kafka inventory-events 1 message JSON thô mỗi dòng tồn 1 message JSON thô mỗi dòng tồn (StringSerializer) KHỚP (D-07)

Transaction, khoá, idempotency, tenant

  • Ranh giới transaction: một @Transactional ở InventoryTrackingService.enableInventoryTracking; mọi lỗi khác thiếu WH1 đều rollback hết (R-09).
    • KafkaTemplate mới dựng từ copyWithConfigurationOverride của factory chung, nên thuộc tính transactional giữ như factory gốc. Cả cũ lẫn mới đều gửi ngay, không chờ commit (D-07).
  • Khoá: không khoá, đặt on_hand tuyệt đối, như cũ.
  • Thời điểm phát event: trước khi đặt tồn, lưu phiếu và commit. Request lỗi sau đó thì message đã gửi vẫn ra ngoài, như cũ.
  • Lọc comId: các truy vấn đọc có com_id; các lệnh UPDATE theo id (F-logic-3 vòng 1).

Lệch so với luồng mới đã duyệt (spec mục 6)

Không.

Dev cần chú ý khi review

Vị trí Vì sao
infrastructure/messaging/LegacyInventoryLogKafkaProducer.java:35-49 Template riêng ghi đè value serializer, không dùng template mặc định (JsonSerializer). Nếu đổi lại inject KafkaTemplate thì payload sẽ bị bọc chuỗi như vòng 1
application/inventory/InventoryTrackingService.java:95-96 Nhánh D-05: không có WH1 vẫn commit ppu/product và trả 200
application/inventory/InventoryTrackingService.java:101-123 Sinh mã NK cho mọi ppu chính nhưng chỉ lưu phiếu đầu (D-06); Kafka gửi trước khi ghi tồn
infrastructure/relational/product/adapter/ProductTrackingRelationalAdapter.java:102-157 Mô phỏng dirty check và làm sạch chuỗi (D-10, D-11); UPDATE theo id
infrastructure/relational/inventory/adapter/InitialStockRelationalRepository.java:65-95 Gom dòng không lô "giữ dòng cuối", không ORDER BY; native SQL chỉ test bằng H2 (K-13)

Nguồn của trang này

  • Phân tích luồng migrations/inventory/enable-inventory-tracking/verify/round-2/flow-analysis.md vòng 2 · sha256 cecb4c7de6b3

v1 dựng 2026-11-06 00:42 · base commit đích a06ccfa6d4