Phân tích luồng sau chuyển — batch/delete-multiple — vòng 1
logic-reviewerviết dựa trên code đã implement (repoC:/Projects/warehouse-service-wt/ws1), đối chiếu với code cũ. Viết tắt:backend:=easyposbackend1:src/main/java/vn/softdreams/easypos/; đường dẫn mới tính từsrc/main/java/com/softdreams/easypos/warehouse/.
F-01 Xoá nhiều lô theo danh sách
- Điểm vào: cũ
backend:web/rest/BatchesManagementResource.java:60-64→ mớipresentation/web/batch/BatchController.java:96-104 - Quy tắc: R-01, R-03, R-04, R-05, R-06, R-07
Sơ đồ luồng mới (theo code thực tế)
sequenceDiagram
participant C as Client
participant BC as BatchController.deleteMultiple
participant M as BatchWebMapper.toDeleteMultipleCommand
participant S as BatchManagementService.deleteMultiple (@Transactional)
participant R as BatchRelationalRepository.deleteAllWithoutDetails (translate)
participant W as BatchWriter.deleteAllWithoutDetails
C->>BC: POST BatchDeleteMultipleRequest (không validate)
BC->>M: request
M-->>BC: Command(ids, paramCheckAll, BatchFilter)
BC->>S: command
S->>S: paramCheckAll khác TRUE → ids = command.ids()
S->>S: ids null/rỗng → return 0
S->>R: deleteAllWithoutDetails(ids)
R->>W: DELETE b FROM batches b WHERE b.id IN (:ids) AND NOT EXISTS(batches_detail)
W-->>S: n (PersistenceException → SystemException EXCEPTION_ERROR)
S->>S: n != ids.size() → BadRequestException LOT_HAS_TRANSACTIONS_CANNOT_DELETE (rollback)
BC-->>C: 200 ok(n, DELETE_BATCHES_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 | Body DeleteBatchRequest, không validate — backend:web/rest/BatchesManagementResource.java:60-62 |
BatchController.java:96-98, BatchDeleteMultipleRequest (9 field) |
KHỚP |
| 2 | Body hỏng → 400 body rỗng (LF-03) | 400 starter | KHÁC có chủ đích (D-02) |
| 3 | ids = request.getIds(); Objects.equals(paramCheckAll, true) sai → giữ ids — backend:service/impl/BatchesManagementServiceImpl.java:360-361 |
BatchManagementService.java:107-109 (Boolean.TRUE.equals) |
KHỚP |
| 4 | Không kiểm token/công ty | Không gọi CurrentUserPort |
KHÁC có chủ đích? — không: giữ như cũ (D-01 GIỮ) → KHỚP |
| 5 | ids null/rỗng → 200 data 0 — …ServiceImpl.java:377-379 |
BatchManagementService.java:110-112 |
KHỚP |
| 6 | Một câu DELETE IN (?1) + NOT EXISTS trên writeEntityManager — backend:repository/impl/BatchRepositoryImpl.java:355-363 |
BatchWriter.java:42-49,78-80 (IN (:ids)) |
KHỚP |
| 7 | numberRowsDeleted != ids.size() → BaseBadRequestAlertException → 400, rollback — …ServiceImpl.java:381-384 |
BatchManagementService.java:113-116 |
KHỚP |
| 8 | Lỗi SQL → 417 EXCEPTION_ERROR (LF-13) |
BatchRelationalRepository.java:151-154,172-178 → 500 EXCEPTION_ERROR |
KHÁC có chủ đích (D-03) |
| 9 | Kiểm gói dịch vụ (LF-21) | không có | KHÁC có chủ đích (D-04) |
| 10 | 200 DELETE_BATCHES_SUCCESS, data = số dòng — …ServiceImpl.java:386 |
BatchController.java:99-103 |
KHÁC có chủ đích về khung response (D-02); mã và data KHỚP |
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ú |
|---|---|---|---|
batches |
DELETE id IN (:ids), không lọc com_id |
như cũ | D-01 |
batches_detail |
đọc trong NOT EXISTS | như cũ | |
| event/cache | không | không |
Transaction, khoá, idempotency, tenant
- Ranh giới transaction: cũ
@Transactionalcấp classBatchesManagementServiceImpl(:55-57) → mới@TransactionaltrênBatchManagementService.deleteMultiple(:105), gọi từ controller qua proxy; ngoại lệ unchecked → rollback cả câu xoá. - Khoá / cập nhật nguyên tử: một câu DELETE duy nhất ở cả hai bên; không đọc-sửa-ghi.
- Idempotency, event: không áp dụng (API, không phát event). Gọi lại cùng
idssau khi đã xoá → 0 ≠ size → 400 như cũ. - Lọc
comId: không có ở câu xoá ở cả hai bên (D-01).
Lệch so với luồng mới đã duyệt (spec mục 6)
Không (port tên deleteAllWithoutDetails thay cho deleteWithoutDetails(List) — chỉ đổi tên).
Dev cần chú ý khi review
| Vị trí | Vì sao |
|---|---|
application/batch/BatchManagementService.java:113-116 |
Rollback cả lượt dựa vào việc ném BadRequestException (unchecked) trong method @Transactional; đừng bắt/nuốt ngoại lệ này ở tầng trên trong cùng transaction. |
infrastructure/relational/batch/adapter/BatchWriter.java:78-80 |
Một câu IN cho mọi id; > ~2100 tham số (padding bật) → lỗi 500 (D-06). ids chứa null (đặc biệt [null]) chưa chạy thật trên MSSQL/Hibernate 6 — đưa vào GM-01. |
infrastructure/relational/batch/adapter/BatchRelationalRepository.java:151-154 |
Câu xoá không lọc com_id — cố ý theo D-01 (NGHI BUG mức CAO, người cần chốt). |
F-02 Xoá mọi lô khớp bộ lọc
- Điểm vào: cũ
backend:web/rest/BatchesManagementResource.java:60-64→ mớipresentation/web/batch/BatchController.java:96-104 - Quy tắc: R-01, R-02, R-03, R-04, R-05, R-06, R-07
Sơ đồ luồng mới (theo code thực tế)
sequenceDiagram
participant C as Client
participant BC as BatchController.deleteMultiple
participant S as BatchManagementService.deleteMultiple (@Transactional)
participant R as BatchRelationalRepository
participant F as BatchFilterReader.findIds
participant K as BatchKeyword.likePattern
participant W as BatchWriter.deleteAllWithoutDetails
C->>BC: POST {comId, paramCheckAll:true, keyword, status, inventoryQuantityStatus, ...}
BC->>S: Command(ids bị bỏ qua, TRUE, BatchFilter(comId, keyword, status, invQtyStatus))
S->>R: findIdsByFilter(filter)
R->>F: findIds(filter)
F->>K: likePattern(keyword) (null/"" → không lọc)
F->>F: SELECT b.id FROM batches b ⟕ batches_detail ⟕ ppu WHERE com_id=:comId(null→"") [+LIKE][+status] GROUP BY [+HAVING]
F-->>S: ids (PersistenceException → SystemException EXCEPTION_ERROR)
S->>S: rỗng → return 0
S->>R: deleteAllWithoutDetails(ids)
R->>W: DELETE ... IN (:ids) AND NOT EXISTS(...)
S->>S: n != ids.size() → 400 LOT_HAS_TRANSACTIONS_CANNOT_DELETE (rollback)
BC-->>C: 200 ok(n, DELETE_BATCHES_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 | Body, không validate, không kiểm token — BatchesManagementResource.java:60-62 |
BatchController.java:96-104; BatchWebMapper.java:58 dựng BatchFilter từ body |
KHỚP (D-01 GIỮ) |
| 2 | Dựng SearchBatchRequest từ comId/keyword/status/invQtyStatus/ppuId — …ServiceImpl.java:362-367 |
BatchWebMapper.java:58-63 (bỏ ppuId) |
KHỚP — ppuId chỉ đổi ORDER BY/cột SELECT (BatchRepositoryImpl.java:125-179), không đổi tập id |
| 3 | comId null → Common.setParams bind "" — backend:util/Common.java:227-236 |
BatchFilterReader.java:90 |
KHỚP |
| 4 | FROM/JOIN/WHERE b.com_id = :comId — BatchRepositoryImpl.java:39-42 |
BatchFilterReader.java:22-27 |
KHỚP |
| 5 | Keyword khác null/"" → LIKE '%'+normalizedName+'%' — BatchRepositoryImpl.java:43-46, Common.java:1315-1329 |
BatchFilterReader.java:92-96, domain/batch/model/BatchKeyword.java:17-21 → BatchNormalizedName.of |
KHỚP (" " → %%) |
| 6 | status 0/2/1 với CASE kẹp, khác/null không lọc — BatchRepositoryImpl.java:48-107 |
BatchFilterReader.java:29-54,108-119 |
KHỚP |
| 7 | GROUP BY 8 cột; HAVING tồn 1/2 — BatchRepositoryImpl.java:108-117 |
BatchFilterReader.java:55-63,121-129 |
KHỚP |
| 8 | Câu COUNT + SELECT đầy đủ + ORDER BY, map BatchItem, lấy id — BatchRepositoryImpl.java:118-189, …ServiceImpl.java:368-374 |
Chỉ SELECT b.id — BatchFilterReader.java:99-102 |
KHÁC có chủ đích (D-07) |
| 9 | Đọc bằng field entityManager (@Autowired + @PersistenceContext(readOnly)) — BatchRepositoryImpl.java:27-29 |
EM chung trong transaction ghi (primary) | KHÁC có chủ đích / UNVERIFIED (D-08 GIỮ DB chính) |
| 10 | Rỗng → 200 data 0 — …ServiceImpl.java:377-379 |
BatchManagementService.java:110-112 |
KHỚP |
| 11 | DELETE IN + so size → 400 rollback — …ServiceImpl.java:381-384, BatchRepositoryImpl.java:355-363 |
BatchManagementService.java:113-116, BatchWriter.java:78-80 |
KHỚP |
| 12 | Lỗi SQL ở lọc/xoá → 417 EXCEPTION_ERROR |
BatchFilterReader.java:103-105, BatchRelationalRepository.java:172-178 → 500 EXCEPTION_ERROR |
KHÁC có chủ đích (D-03) |
| 13 | Response 200 DELETE_BATCHES_SUCCESS |
BatchController.java:99-103 |
KHỚP (khung response D-02) |
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ú |
|---|---|---|---|
batches ⟕ batches_detail ⟕ product_product_unit |
đọc 2 câu (COUNT, SELECT), com_id = :comId body |
đọc 1 câu SELECT b.id, cùng điều kiện |
D-07, D-08 |
batches |
DELETE id IN (:ids) |
như cũ | D-01 |
| event/cache | không | không |
Transaction, khoá, idempotency, tenant
- Ranh giới transaction: cũ cả lọc + xoá trong transaction cấp class (nguồn đọc lọc chưa chắc — D-08) → mới cả hai trong
BatchManagementService.deleteMultiple@Transactional(readOnly=false). - Khoá / cập nhật nguyên tử: SELECT id rồi DELETE; lô được thêm chi tiết giữa hai câu → NOT EXISTS loại ra → 400 rollback, như cũ.
- Idempotency, event: không áp dụng.
- Lọc
comId: theocomIdbody, không đối chiếu token (D-01); câu xoá không lọccom_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 |
|---|---|
infrastructure/relational/batch/adapter/BatchFilterReader.java:22-63 |
SQL nguyên văn ghép từ text block với \ cuối dòng — sửa xoá dấu cách trước \ sẽ làm dính từ khoá SQL; chỉ khoá bằng mock (K-13), cần GM-01. |
infrastructure/relational/batch/adapter/BatchFilterReader.java:90 |
comId null bind "" → so cột int với '' (SQL Server đổi thành 0) — UNVERIFIED. |
application/batch/BatchManagementService.java:107-109 |
Chọn tất cả lấy comId từ body, xoá được lô công ty khác (D-01, mức CAO, người cần chốt). |
infrastructure/relational/batch/adapter/BatchRelationalRepository.java:157-159 |
Đọc lọc trên DB chính trong transaction ghi (D-08), khác cũ nếu cũ thực sự đọc replica. |