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

Tồn kho · inventory/batch-on-hands · api

POST/api/client/rs-inoutward/batch-on-hands

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/batch-on-hands — vòng 1

F-01 Tồn theo lô của danh sách ppu trong một kho

  • Điểm vào: cũ backend:src/main/java/vn/softdreams/easypos/web/rest/RsInoutWardManagementResource.java:337-341 (class @RequestMapping("/api"), dòng 39) → mới src/main/java/com/softdreams/easypos/warehouse/presentation/web/inventory/BatchOnHandController.java:38-48
  • 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 BatchOnHandController.getBatchOnHands
    participant A as InventoryQueryService.getBatchOnHands (@Transactional)
    participant U as CurrentUserAdapter.findCompanyId
    participant P as InventoryRelationalRepository.findBatchOnHands
    participant J as BatchOnHandJdbcRepository.findBatchOnHands
    participant M as InventoryWebMapper.toBatchOnHandResponse
    C->>W: POST /api/client/rs-inoutward/batch-on-hands {comId, warehouseId, ppuIds}
    W->>A: getBatchOnHands(warehouseId, ppuIds)  (comId bị bỏ)
    A->>A: ppuIds == null → SystemException(EXCEPTION_ERROR)
    A->>U: findCompanyId() (claim companyId; rỗng → AuthenticationException TOKEN_INVALID_OR_EXPIRED)
    A->>P: findBatchOnHands(companyId, warehouseId)
    P->>J: JdbcTemplate.query(SQL, comId, comId, warehouseId)
    J-->>P: rows (i ⋈ bd[batch_id not null] ⋈ b[com_id]) ORDER BY b.id, i.id, bd.id
    P-->>A: List<BatchOnHandResult> (DataAccessException → SystemException EXCEPTION_ERROR)
    A->>A: new HashSet(ppuIds); duyệt rows, ppuId ∈ set → HashMap.computeIfAbsent(ppuId).add(row)
    A-->>W: Map<Integer, List<BatchOnHandResult>>
    W->>M: map → LinkedHashMap<Integer, List<BatchOnHandItemResponse>> (id=batchId, minDate/quantity=null)
    W-->>C: 200 BaseResponseDTO.ok(map, GET_BATCH_ON_HANDS_SUCCESS)

Đố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) — CHỈ CÓ Ở CŨ, có chủ đích (D-05)
2 Deserialize BatchOnHandsRequest (backend:dto/rsinoutward/BatchOnHandsRequest.java:8-10), body hỏng → 400 body rỗng record BatchOnHandsRequest (dto/request/BatchOnHandsRequest.java), 400 theo starter KHÁC có chủ đích (D-02)
3 Gọi service với warehouseId, ppuIds, bỏ comId (RsInoutWardManagementResource.java:339) BatchOnHandController.java:43-45 KHỚP
4 @Transactional(readOnly=true), thực tế đọc DB chính (RsInoutWardManagementServiceImpl.java:8797) @Transactional không readOnly (InventoryQueryService.java:91) KHÁC có chủ đích (D-08)
5 getUserWithAuthorities() lấy companyId (:8799) findCompanyId() (InventoryQueryService.java:96-97) KHÁC có chủ đích (D-03)
6 NPE khi ppuList null, xảy ra sau bước 5 và 7 (:8820) kiểm null trước bước 5 (InventoryQueryService.java:93-95) Mã lỗi giữ theo D-06; thứ tự kiểm khác (F-logic-1)
7 findAllByWarehouseId: i ⟕ bd, i.com_id, i.warehouse_id, không ORDER BY (base:repositories/BaseInventoryRepository.java:27-28) một câu JOIN (BatchOnHandJdbcRepository.java:27-41) KHÁC có chủ đích (D-04, D-09); tập dòng tương đương
8 Lọc batchId != null && ppuId ∈ Set (:8820-8824) bd.batch_id IS NOT NULL trong SQL + HashSet.contains (InventoryQueryService.java:98-101) KHỚP (null trong ppuIds được giữ, phần tử trùng tính một lần)
9 findAllByComIdAndIdIn(companyId, batchIds của cả kho) (:8825-8828; BatchesRepository.java:129), lô không thuộc công ty bị bỏ JOIN batches b ON b.id = bd.batch_id AND b.com_id = ? KHỚP về kết quả; kho > 2048 lô cũ lỗi, mới thì không (D-09)
10 Duyệt lô theo thứ tự DB × dòng tồn của lô, đưa vào HashMap (:8829-8845) ORDER BY b.id, i.id, bd.id + computeIfAbsent theo thứ tự dòng (InventoryQueryService.java:99-104) KHÁC có chủ đích (D-04), giống thứ tự DB thường trả
11 Item: id/code/lotNo/status/mfgDate/expDate/onHand=bd.on_hand, minDate/quantity null (:8833-8840; BaseBatchOnHandItem.java:11-22) InventoryWebMapper.toBatchOnHandItem + BatchOnHandItemResponse @JsonInclude(ALWAYS) KHỚP; ngày phụ thuộc múi giờ JVM/Jackson (F-logic-2)
12 BaseResultDTO(SUCCESS, GET_BATCH_ON_HANDS_SUCCESS, true, map) (:8846) BaseResponseDTO.ok(map, GET_BATCH_ON_HANDS_SUCCESS) (BatchOnHandController.java:46-47) KHÁC có chủ đích (D-02); map rỗng mất key data (D-07)
13 Lỗi SQL → 417 EXCEPTION_ERROR (LF-13) InventoryRelationalRepository.java:68-74 bọc DataAccessException → SystemException 500 KHÁC có chủ đích (D-06)

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 mọi dòng của kho, com_id = companyId, warehouse_id = ? Đọc, cùng điều kiện, chỉ dòng có lô tenant giữ nguyên
batches_detail Đọc qua LEFT JOIN, on_hand qua CASE (cả hai cột đều scale 6) Đọc qua INNER JOIN, batch_id IS NOT NULL, lấy thẳng bd.on_hand Kết quả như nhau với dòng có lô; scale như nhau (InventoryJpaEntity/BatchDetailJpaEntity precision 21, scale 6)
batches Đọc com_id = companyId AND id IN (...) JOIN b.com_id = ? Không lọc trạng thái/HSD ở cả hai
Cache user / bảng user, company Đọc (getUserWithAuthorities) Không đọc, chỉ claim JWT D-03
Bảng gói dịch vụ Đọc (interceptor) Không D-05
Ghi / event / cache ghi Không Không Không có side effect

Transaction, khoá, idempotency, tenant

  • Ranh giới transaction: cũ @Transactional(readOnly=true) ở service impl, thực tế đọc DB chính → mới @Transactional không readOnly ở InventoryQueryService.getBatchOnHands, route về primary theo ADR-0201 (D-08). JdbcTemplate dùng bean DataSource giống ProductStockDetailJdbcRepository.
  • 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: i.com_id và b.com_id đều lấy từ claim token; comId trong body bị bỏ như cũ. Không N+1: một câu SQL thay cho hai câu của code cũ.

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

không. Code đi đúng sơ đồ mục 6, kể cả việc kiểm ppuIds null trước findCompanyId (chỗ đó ghi ở F-logic-1 vì chưa có D-xx).

Dev cần chú ý khi review

Vị trí Vì sao
BatchOnHandJdbcRepository.java:27-41 Một câu JOIN thay cho hai truy vấn cũ. Thứ tự tham số comId, comId, warehouseId (dòng 68) phải khớp b.com_id = ? rồi đến i.com_id = ?. ORDER BY thay cho thứ tự không xác định của code cũ (D-04). Mới chỉ test trên H2 (K-13).
BatchOnHandJdbcRepository.java:72-74 Ngày gắn múi giờ JVM; chuỗi JSON còn tùy cấu hình múi giờ của Jackson (F-logic-2).
InventoryQueryService.java:93-97 Thứ tự kiểm ppuIds null và token khác code cũ (F-logic-1).
InventoryQueryService.java:98-104 Phải dùng HashSet (nhận phần tử null); thứ tự item trong list dựa vào thứ tự dòng mà repository trả.
InventoryRelationalRepository.java:68-74 Nhánh lỗi DB → SystemException EXCEPTION_ERROR (500 thay 417, D-06).
BatchOnHandItemResponse.java (@JsonInclude(ALWAYS)) Thiếu annotation này thì mapper NON_EMPTY của starter sẽ bỏ các key null như minDate, quantity, lotNo…

Nguồn của trang này

  • Phân tích luồng migrations/inventory/batch-on-hands/verify/round-1/flow-analysis.md vòng 1 · sha256 e2580d3cfc6c

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