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

Tồn kho · inventory/get-detail-product · api

GET/api/client/page/inventory/get-detail-product

Vòng
1
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/get-detail-product — vòng 1

F-01 Tồn chi tiết một ĐVT theo kho và lô

  • Điểm vào: cũ easyposbase:src/main/java/sds/ep/baseservice/controllers/BaseInventoryResource.java:38-44 → mới src/main/java/com/softdreams/easypos/warehouse/presentation/web/inventory/InventoryController.java:42-53
  • Quy tắc: R-01 … R-11

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

sequenceDiagram
    participant C as Client
    participant W as InventoryController.getDetailProduct
    participant A as InventoryQueryService.getProductStockDetails (@Transactional, không readOnly)
    participant K as CurrentCompanyService.requireCompanyOfCurrentUser
    participant P as InventoryRelationalRepository.findProductStockDetails
    participant J as ProductStockDetailJdbcRepository.findProductStockDetails
    participant M as InventoryWebMapper.toResponses
    C->>W: GET /api/client/page/inventory/get-detail-product?comId&ppuId (@RequestParam Integer, thiếu/sai → 400 INVALID_REQUEST)
    W->>A: getProductStockDetails(comId, ppuId)
    A->>K: requireCompanyOfCurrentUser(comId)
    K-->>A: comId<=0 → 400 INVALID_COMPANY / không claim → TOKEN_INVALID_OR_EXPIRED / khác → 400 COMPANY_NOT_OF_CURRENT_USER
    A->>P: findProductStockDetails(comId, ppuId)
    P->>J: findProductStockDetails(comId, ppuId)
    J->>J: JdbcTemplate.query (inventory ⋈ warehouse ⋈ ppu ⟕ batches_detail, ORDER BY như cũ)
    J-->>P: List<ProductStockDetailResult>
    P-->>A: list (DataAccessException → SystemException EXCEPTION_ERROR 500)
    A-->>W: list
    W->>M: toResponses(list) (onHand null→0, ppuidAndWarehouseId)
    W-->>C: 200 BaseResponseDTO.ok(data, SUCCESS_GET_DETAIL)

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

# Luồng cũ (repo:path:dòng) Luồng mới (path:dòng) Kết luận
1 Interceptor kiểm gói dịch vụ (LF-21) không có KHÁC có chủ đích (D-05)
2 @RequestParam Integer comId, ppuId, lỗi → 400 body rỗng base:controllers/BaseInventoryResource.java:39-42, LF-03 InventoryController.java:44-47, lỗi → 400 INVALID_REQUEST KHÁC có chủ đích (D-02)
3 Không kiểm công ty (LF-20) InventoryQueryService.java:44 → CurrentCompanyService.java:30-38 KHÁC có chủ đích (D-01)
4 Transaction đọc-ghi cấp class base:services/impl/BaseInventoryServiceImpl.java:55 @Transactional không readOnly, InventoryQueryService.java:42 KHỚP (D-04)
5 getInventoryProducts(comId, List.of(ppuId), null, 1, null, 1) BaseInventoryServiceImpl.java:1088 → BaseInventoryRepositoryImpl.java:33-36 InventoryRelationalRepository.java:51-53 → ProductStockDetailJdbcRepository.java:75-85 KHỚP (lệch tên class: F-logic-1)
6 SQL JOIN/WHERE/CASE/ORDER BY BaseInventoryRepositoryImpl.java:51-99 ProductStockDetailJdbcRepository.java:30-47 KHỚP
7 Map tuple → PPUInventoryItem, batchId lấy vì isGetBatchId=true :107-122 ROW_MAPPER ProductStockDetailJdbcRepository.java:49-60 KHỚP
8 Lỗi SQL → 417 EXCEPTION_ERROR (LF-13) InventoryRelationalRepository.java:54-56 → 500 EXCEPTION_ERROR KHÁC có chủ đích (D-06)
9 Getter getOnHand null→0, getPPUIdAndWarehouseId PPUInventoryItem.java:142-160 InventoryWebMapper.java:25-38 KHỚP
10 Jackson mặc định, 14 key luôn xuất ProductStockDetailResponse.java:31 @JsonInclude(ALWAYS) KHỚP
11 BaseResultDTO(SUCCESS, SUCCESS_GET_DETAIL, true, list) BaseInventoryServiceImpl.java:1089 InventoryController.java:51-52 ok(response, SUCCESS_GET_DETAIL); list rỗng → mất key data KHÁC có chủ đích (D-02, D-07)

Dữ liệu và side effect

Bảng / topic / cache Cũ (đọc/ghi, điều kiện) Mới (đọc/ghi, điều kiện) Ghi chú
inventory đọc, i.com_id=:comId, i.ppu_id in (:ppuId) đọc, i.com_id=?, i.ppu_id IN (?) khớp
warehouse đọc, w.com_id=:comId, status=1, is_sellable=1 đọc, cùng điều kiện (hằng ở ProductStockDetailJdbcRepository.java:22-24) khớp
product_product_unit đọc, ppu.id=i.ppu_id, không lọc com_id giống cũ khớp
batches_detail LEFT JOIN bd.inventory_id=i.id giống cũ khớp
Gói dịch vụ đọc ở interceptor không D-05

Không ghi bảng nào, không cache, không event, ở cả code cũ và mới.

Transaction, khoá, idempotency, tenant

  • Ranh giới transaction: cũ @Transactional cấp class của BaseInventoryServiceImpl, đọc-ghi → mới @Transactional (không readOnly) ở InventoryQueryService.getProductStockDetails. JdbcTemplate dựng từ DataSource routing nên dùng chung connection với transaction JPA, và vì không readOnly nên đọc DB chính (D-04).
  • Khoá / cập nhật nguyên tử: không có ở cả hai (chỉ đọc).
  • Idempotency, thời điểm phát event: không áp dụng.
  • Lọc comId: w.com_id và i.com_id như cũ. Mới thêm kiểm comId phải là công ty trong token (D-01).

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

Chỉ thêm tầng ProductStockDetailJdbcRepository sau InventoryRelationalRepository (F-logic-1). Thứ tự gọi và điểm kiểm công ty khớp spec mục 6.

Dev cần chú ý khi review

Vị trí Vì sao
ProductStockDetailJdbcRepository.java:30-47, 76-84 Câu SQL native và thứ tự tham số theo vị trí (comId hai lần). Mới chạy trên H2, MSSQL thật UNVERIFIED (K-13). Thứ tự lô trong cùng kho do DB quyết (D-03).
ProductStockDetailJdbcRepository.java:51 getObject("is_primary", Boolean.class) phụ thuộc kiểu cột BIT trên MSSQL.
InventoryRelationalRepository.java:51-57 Nhánh lỗi: chỉ DataAccessException thành EXCEPTION_ERROR. Lỗi khác ra UNCERTAIN_ERROR của starter.
InventoryQueryService.java:42-46 Không readOnly là có chủ đích (D-04). InventoryQueryService vốn dùng cho các context khác, nay phụ thuộc thêm CurrentCompanyService (WarehouseTransferServiceTest.java:135 đã sửa theo).
ProductStockDetailResponse.java:31 @JsonInclude(ALWAYS) giữ đủ 14 key. Bỏ annotation này thì key null hoặc "" biến mất do mapper starter để NON_EMPTY.
InventoryController.java:51-52 List rỗng thì JSON không có key data (D-07, đang chờ người chốt chung với warehouse/get-with-paging).

Nguồn của trang này

  • Phân tích luồng migrations/inventory/get-detail-product/verify/round-1/flow-analysis.md vòng 1 · sha256 06d59f115d7e

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