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

Kho · warehouse/get-with-paging · api

GET/api/client/page/warehouse/get-with-paging

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

Phân tích luồng sau chuyển — warehouse/get-with-paging — vòng 2

F-01 Danh sách kho theo trang

  • Điểm vào: cũ easyposbackend1:src/main/java/vn/softdreams/easypos/web/rest/WarehouseResource.java:69-78 → mới src/main/java/com/softdreams/easypos/warehouse/presentation/web/warehouse/WarehouseController.java:119-139
  • Quy tắc: R-01 … R-11

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

sequenceDiagram
    participant C as Client
    participant WC as WarehouseController.getWithPaging
    participant QS as WarehouseQueryService.getWarehousePage (@Transactional, không readOnly)
    participant CC as CurrentCompanyService.requireCompanyOfCurrentUser
    participant WR as WarehouseRelationalRepository.findPage
    participant IQ as InventoryQueryService.countActiveProductsByWarehouses
    participant IR as InventoryRelationalRepository.countActiveProductsByWarehouses
    C->>WC: GET ?page&size&comId&keyword&status&countProduct (Pageable + @RequestParam comId + record filter)
    WC->>QS: WarehousePageQuery(comId, keyword, status, countProduct, pageable.getOffset(), pageSize)
    QS->>CC: requireCompanyOfCurrentUser(comId) (null/<=0 → INVALID_COMPANY; khác token → COMPANY_NOT_OF_CURRENT_USER)
    QS->>QS: keywordPattern: null/"" → null, còn lại "%"+WarehouseText.normalizedName([kw])+"%"
    QS->>WR: findPage(WarehousePageFilter)
    WR->>WR: native SELECT COUNT(id) FROM warehouse WHERE com_id [+normalized_name LIKE][+status =]
    alt count > 0
        WR->>WR: (int) offset; âm → SystemException(EXCEPTION_ERROR)
        WR->>WR: native SELECT id,…,is_sellable … setFirstResult/setMaxResults, không ORDER BY
    end
    WR->>WR: pageTotal theo quy tắc PageImpl (long); PersistenceException → SystemException(EXCEPTION_ERROR)
    WR-->>QS: WarehousePage(items countProduct=null, total)
    opt items không rỗng và Boolean.TRUE.equals(countProduct)
        QS->>IQ: countActiveProductsByWarehouses(comId, ids)
        IQ->>IR: native COUNT(DISTINCT product_id) … GROUP BY warehouse_id → Map
        QS->>QS: item.withCountProduct(counts.get(id)) (null → 0)
    end
    WC-->>C: 200 BaseResponseDTO.count(total).ok(items, SUCCESS_GET_LIST) (serialize bằng ObjectMapper NON_EMPTY của starter)

Đố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 Bind Pageable mặc định, @RequestParam comId/keyword/status/countProduct — easyposbackend1:…/web/rest/WarehouseResource.java:70-76 Pageable mặc định, @RequestParam comId, record WarehousePageFilterRequest — WarehouseController.java:121-125 KHÁC (F-logic-4): body lỗi khi sai kiểu; mã 400 giữ nguyên; body thuộc D-02
2 Không kiểm công ty — easyposbase:…/BaseWarehouseRepositoryImpl.java:31-32, LF-20 CurrentCompanyService.requireCompanyOfCurrentUser — WarehouseQueryService.java:68 KHÁC có chủ đích (D-01)
3 Kiểm gói dịch vụ qua interceptor — LF-21 không có KHÁC có chủ đích (D-07)
4 !Strings.isNullOrEmpty(keyword) → '%'+normalizedName+'%' — BaseWarehouseRepositoryImpl.java:34-37 keywordPattern — WarehouseQueryService.java:86-91; WarehouseRelationalRepository.pageWhere/setPageParameters KHỚP (D-03, D-04 GIỮ)
5 status khác null → status = :status — BaseWarehouseRepositoryImpl.java:39-45 PAGE_STATUS_SQL khi khác null KHỚP
6 SELECT COUNT(id) trước; count>0 mới lấy trang — BaseWarehouseRepositoryImpl.java:47-62 WarehouseRelationalRepository.java:178-185 KHỚP
7 setFirstResult((int) offset), setMaxResults, không ORDER BY — easyposmodel:…/util/BaseCommon.java:384-385 findPageItems — WarehouseRelationalRepository.java:192-204 (offset âm → SystemException trước khi tạo query) KHỚP về kết quả (D-05, D-08); 417→500 là D-03
8 Map ConstructorResult (Boolean cho status/is_sellable) — easyposmodel:…/domain/BaseWarehouse.java:21-38 toListItem/toBoolean KHỚP với dữ liệu đúng kiểu; lỗi map → KHÁC (F-logic-3)
9 PageImpl(content, pageable, count.longValue()) — BaseWarehouseRepositoryImpl.java:64 pageTotal — WarehouseRelationalRepository.java:228-233 KHỚP
10 Đếm SP khi trang không rỗng và countProduct == TRUE, toMap, setCountProduct null→0 — easyposbase:…/BaseWarehouseServiceImpl.java:251-262; SQL BaseWarehouseRepositoryImpl.java:70-95 WarehouseQueryService.java:74-82; InventoryRelationalRepository.java:101-120; WarehouseListItem.withCountProduct KHỚP (cột 0 = count, cột 1 = warehouse_id map đúng)
11 new BaseResultDTO(SUCCESS, SUCCESS_GET_LIST, true, warehouses, (int) totalElements) — BaseWarehouseServiceImpl.java:263 BaseResponseDTO.count(page.total()).ok(…, SUCCESS_GET_LIST) — WarehouseController.java:136-138 reason là D-02; (int) bị bỏ → KHÁC (F-logic-2)
12a Serialize phần tử WarehouseGetList bằng mapper Boot ALWAYS (giữ key null) — easyposmodel:…/dto/WarehouseGetList.java:35-121 WarehouseListItemResponse.java:13 @JsonInclude(ALWAYS) ghi đè NON_EMPTY của starter KHỚP (đã sửa ở vòng 2)
12b data: [] khi không có kho — BaseWarehouseServiceImpl.java:263, BaseResultDTO.java:10 BaseResponseDTO.data theo NON_EMPTY → bỏ key data — WarehouseController.java:136-138 KHÁC (F-logic-1, còn mở — UNSURE, cần người chọn cách)
13 Lỗi SQL → 417 EXCEPTION_ERROR — LF-13 PersistenceException → SystemException(EXCEPTION_ERROR) 500 (WarehouseRelationalRepository.java:186-189, InventoryRelationalRepository.java:109-112) KHÁC có chủ đích (D-03)

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ú
warehouse đọc: com_id = ? [+ normalized_name like ?] [+ status = ?], COUNT rồi SELECT trang đọc: giống hệt, cùng điều kiện và cùng thứ tự không ghi
inventory + join product đọc khi countProduct=TRUE và trang không rỗng: i.com_id, p.com_id, p.active = TRUE, i.is_primary = 1, warehouse_id in (…) đọc cùng điều kiện, active bind Boolean.TRUE IN :warehouseIds không ngoặc như cũ; chỉ test bằng mock (K-13)
Redis gói dịch vụ đọc (interceptor) không D-07

Transaction, khoá, idempotency, tenant

  • Ranh giới transaction: cũ là @Transactional cấp class của BaseWarehouseServiceImpl (LF-33), đọc DB chính. Mới là @Transactional không readOnly ở WarehouseQueryService.getWarehousePage (gọi từ controller qua proxy, không tự gọi nội bộ), định tuyến về primary (D-06).
  • 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 có event, không ghi.
  • Lọc comId: mọi câu (COUNT, SELECT trang, đếm SP ở cả inventory và product) đều có comId. comId dùng trong truy vấn là giá trị đã kiểm với token (D-01).
  • N+1: không có. Mỗi request tối đa 3 câu, giống code cũ.

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

Không lệch về thứ tự bước. Chỉ lệch ở cách bind tham số lọc (record thay cho @RequestParam, F-logic-4) và cách serialize response (F-logic-1, do hạ tầng starter).

Dev cần chú ý khi review

Vị trí Vì sao
WarehouseController.java:136-138 + DataConverterAutoConfiguration.java:51 (starter-model) Mapper NON_EMPTY làm mất key null và mất data khi rỗng (F-logic-1); count không ép int (F-logic-2)
WarehouseRelationalRepository.java:192-204 Ép (int) offset và nhánh offset âm (D-08); không ORDER BY, Hibernate 6 trên MSSQL tự chèn order by @@version (D-05)
WarehouseRelationalRepository.java:228-233 Tổng theo quy tắc PageImpl, phải khớp tuyệt đối với Spring Data
WarehouseRelationalRepository.java toListItem/toBoolean Ép kiểu thủ công thay cho ConstructorResult; kiểu cột thật trên MSSQL chưa kiểm (F-logic-3, K-13)
InventoryRelationalRepository.java:101-120 IN :warehouseIds không có ngoặc (Hibernate 6 phải tự bọc); thứ tự cột columns[0]=count, columns[1]=warehouse_id; chỉ test bằng mock
WarehouseQueryService.java:66-68 Transaction không readOnly (D-06, trái database-performance.md:290); kiểm công ty trước mọi truy vấn (D-01)

Vòng 2 (thu hẹp): chỉ dòng 12 viết lại theo logic-reviewer vòng 2; các bước khác, dữ liệu, transaction không đổi so với vòng 1. Dev chú ý thêm: WarehouseListItemResponse.java:13 — ALWAYS ở mức class là chỗ duy nhất giữ key null; gỡ đi thì mất key (TC-01-EXTRA-1 khoá).

Nguồn của trang này

  • Phân tích luồng migrations/warehouse/get-with-paging/verify/round-2/flow-analysis.md vòng 2 · sha256 5a1b6150dcd0

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