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

Kho · warehouse/delete · api

DELETE/api/client/page/warehouse/delete

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

Báo cáo sai lệch — warehouse/delete — vòng 1

0. Kết luận nhanh

  • Điều kiện đạt: G1 ✅ G2 ✅ G3 ✅ G4 — G5 ✅ G6 ✅ → CHỜ KIỂM SONAR (máy đạt hết, chờ người kiểm G4)
  • Trạng thái: SẴN SÀNG CHO NGƯỜI XEM
  • Tầng rủi ro: A (R-02 phân quyền; các quy tắc còn lại B/C) → người cần đọc: spec + báo cáo + toàn bộ diff
  • Số quy tắc: 10 · PASS 4 · DEVIATION có chủ đích 3 · DEVIATION KHÔNG chủ đích 0 · UNVERIFIED 3
  • Coverage thấp nhất: F-01 97,3% dòng / 93,8% nhánh
  • Finding logic: CRITICAL 0 · MAJOR 0 · MINOR 0 · UNSURE 0
  • Nghi vấn bug code cũ (mục 3c): 5 (CAO 0) · Quyết định tự chốt cần xác nhận (mục 3d): 11
  • Chạy bằng: /mig-auto (spec do spec-reviewer kiểm, chưa có người duyệt) · Số vòng: 1 verify / lần sửa 0/3

1. Điều kiện đạt

Mã Mục tiêu Kết quả Bằng chứng
G1 Kiến trúc ADR (mvnw verify: build, test, ArchUnit, Checkstyle/PMD/SpotBugs) ✅ (602 test, 0 lỗi) verify/round-1/build.md
G2 Test khớp test-plan, mọi R-xx có test ✅ (26/26 TC, 10/10 R) verify/round-1/oracle.md
G3 Coverage mỗi luồng (dòng ≥ 80%, nhánh ≥ 70%) ✅ verify/round-1/coverage.md
G4 0 issue Sonar (người kiểm bằng SonarQube for IDE) CHỜ NGƯỜI sonar-ide.md
G5 0 finding logic CRITICAL/MAJOR đã xác nhận ✅ (không có finding) verify/round-1/review-logic.md, verification.md
G6 Không lách cổng, không ghi ngoài phạm vi ✅ verify/round-1/gates.md

Không chặn nhưng cần người: Integration test CHƯA CHẠY · Golden master CHƯA CHẠY (GM-01, chưa cấu hình §4)

Coverage theo luồng

Luồng Tên % dòng % nhánh
F-01 Xoá kho 97,3% (71/73) 93,8% (30/32)

2. Ma trận truy vết

Quy tắc Tầng Code mới Test Golden Kết luận
R-01 C WarehouseController.deleteWarehouse TC-01, TC-02 — PASS (body 400 thiếu tham số khác — D-02)
R-02 A CurrentCompanyService gọi ở WarehouseManagementService.deleteWarehouse TC-03, TC-04 — DEVIATION (có chủ đích, D-01)
R-03 C WarehouseManagementService.deleteWarehouse TC-05 — PASS
R-04 B Warehouse.validateDeletable TC-06, TC-07, TC-08 — PASS
R-05 B WarehouseDeletePolicy, InventoryRelationalRepository.findOnHandsByWarehouse TC-09..TC-14, TC-21..TC-23 GM-01 UNVERIFIED (SQL thật + kiểu cột MSSQL — D-13, K-13)
R-06 B WarehouseUsageChecker, BillRelationalAdapter.existsByWarehouse, RsInoutwardRelationalRepository.existsByFromWarehouse TC-15..TC-17, TC-24, TC-25 GM-01 UNVERIFIED (SQL thật — K-13); chạy tuần tự theo D-07
R-07 B WarehouseRelationalRepository.deleteById TC-18, TC-20 GM-01 UNVERIFIED (SQL thật, khoá ngoại — D-09)
R-08 C WarehouseController.deleteWarehouse TC-01 — PASS
R-09 B WarehouseManagementService.deleteWarehouse (@Transactional) TC-19 — DEVIATION (có chủ đích, D-11)
R-10 B (không chuyển) TC-26 — DEVIATION (có chủ đích, D-12) — kiểm gói thật UNVERIFIED

3. Người cần xem

# Vị trí Vì sao cần người xem
1 Toàn bộ verify/round-1/changes.diff Tầng A (R-02 phân quyền) — đọc toàn bộ diff
2 infrastructure/relational/inventory/adapter/InventoryRelationalRepository.java (findOnHandsByWarehouse) Mô phỏng kiểm kiểu Tuple Hibernate 5 bằng isInstance; kiểu thật từng cột MSSQL chưa chạy thử — cột trả Byte/Long/Character sẽ ra 500 (D-13, UNVERIFIED)
3 WarehouseRelationalRepository.deleteById, BillRelationalAdapter.existsByWarehouse, RsInoutwardRelationalRepository.existsByFromWarehouse Native SQL chỉ test bằng mock (K-13) — chạy GM-01 trên MSSQL
4 application/warehouse/WarehouseUsageChecker.java Lệch cấu trúc nhỏ so với spec mục 5 (bean phụ trợ để constructor không quá 7 tham số); hành vi/thứ tự không đổi
5 Constructor InventoryRelationalRepository, RsInoutwardRelationalRepository thêm EntityManager; WarehouseManagementService thêm WarehouseUsageChecker Chạm class dùng chung của context khác (chỉ thêm method/tham số, không đổi method cũ)
6 G4 Người chạy SonarQube for IDE

3b. Phân tích luồng sau chuyển

Chi tiết: verify/round-1/flow-analysis.md

Luồng Tên Số bước KHỚP / KHÁC / CHỈ CÓ Ở CŨ / CHỈ CÓ Ở MỚI Lệch luồng đã duyệt (spec mục 6) Điểm dev cần chú ý
F-01 Xoá kho 6 KHỚP / 5 KHÁC có chủ đích (D-01, D-03/D-13, D-07/D-11, D-12) / 0 / 0 Cấu trúc: kiểm tồn/chứng từ qua WarehouseUsageChecker; thứ tự và mã lỗi đúng kiểm kiểu cột (D-13); native DELETE không kiểm số dòng — không đổi sang JPA remove; || đoản mạch hoá đơn → phiếu kho; một transaction trên DB chính, không khoá

3c. Nghi vấn bug / sai ở code cũ (đã GIỮ nguyên khi chuyển)

B-01 Xoá kho để lại dữ liệu tồn của kho đó (dòng tồn "mồ côi")

  • Mức nghi ngờ: TRUNG BÌNH — code cũ có sẵn lệnh xoá tồn nhưng bị comment, không rõ cố ý hay quên.
  • Ở đâu: code cũ backend:service/impl/WarehouseServiceImpl.java:80-82 → code mới (giữ nguyên) WarehouseManagementService.deleteWarehouse (chỉ deleteById)
  • Code cũ đang làm gì: chỉ xoá dòng kho; các dòng tồn kho (inventory) đã về 0 của kho đó vẫn ở lại trong DB, trỏ tới một kho không còn tồn tại.
  • Ví dụ cụ thể: kho 6 có 3 sản phẩm đã bán hết (tồn 0), chưa có chứng từ → xoá kho 6 thành công; 3 dòng inventory.warehouse_id = 6 còn lại. Nếu đúng nghiệp vụ thì lẽ ra 3 dòng này bị xoá cùng.
  • Vì sao nghi là sai: dòng inventoryRepository.deleteAll(inventoryList) đã viết sẵn rồi bị comment.
  • Ảnh hưởng nếu đúng là bug: báo cáo/tra cứu tồn theo sản phẩm không join warehouse có thể đếm cả kho đã xoá (tồn 0 nên số lượng không đổi, nhưng danh sách kho có thể lẫn id lạ).
  • Đã xử lý khi chuyển: GIỮ nguyên hành vi cũ. Test khoá: TC-18 (WarehouseManagementServiceTest$DeleteEndpoint#deletesOnlyWarehouseRow).
  • Nếu muốn sửa: thêm xoá inventory của kho trong deleteWarehouse (và quyết định batches_detail), đổi TC-18; cần dọn dữ liệu mồ côi cũ.
  • Liên quan: D-08, R-07

B-02 Kho chỉ từng nhận hàng chuyển đến thì vẫn xoá được dù đã có phiếu chuyển kho

  • Mức nghi ngờ: TRUNG BÌNH — "đã phát sinh chứng từ" thường gồm cả phiếu nhận.
  • Ở đâu: code cũ base:repositories/BaseWarehouseRepository.java:58-69 → code mới (giữ nguyên) RsInoutwardRelationalRepository.existsByFromWarehouse
  • Code cũ đang làm gì: chỉ kiểm phiếu kho mà kho là kho đi (from_warehouse_id); phiếu chuyển kho chỉ có một dòng chi tiết ghi cả kho đi lẫn kho nhận (base:services/impl/BaseWarehouseServiceImpl.java:1320-1321), nên kho nhận không bị tính.
  • Ví dụ cụ thể: chuyển 10 cái từ kho 5 sang kho 9; sau đó sửa phiếu chuyển về 0 (tồn kho 9 = 0), kho 9 không có hoá đơn → xoá kho 9 thành công; phiếu chuyển kho vẫn trỏ tới kho 9 đã xoá. Lẽ ra phải báo "Kho hàng đã phát sinh chứng từ".
  • Vì sao nghi là sai: chứng từ có kho làm kho nhận cũng là chứng từ của kho.
  • Ảnh hưởng nếu đúng là bug: hiếm (kho nhận thường còn tồn hoặc đã bán/chuyển đi — các đường này đều bị chặn); khi xảy ra, màn xem phiếu chuyển kho hiển thị kho không tồn tại.
  • Đã xử lý khi chuyển: GIỮ nguyên. Test khoá: TC-25 (RsInoutwardRelationalRepositoryTest#existsByFromWarehouse, assert không có to_warehouse_id).
  • Nếu muốn sửa: thêm OR rsd.to_warehouse_id = :warehouseId vào câu SQL, đổi TC-25.
  • Liên quan: D-06, R-06

B-03 Kiểm tồn dùng tồn tổng của dòng tồn, không dùng tồn theo lô; dòng tồn trống thì lỗi hệ thống

  • Mức nghi ngờ: THẤP — câu SQL cũ có tính sẵn tồn theo lô nhưng code không dùng; với dữ liệu khớp nhau thì kết quả như nhau.
  • Ở đâu: code cũ backend:service/impl/WarehouseServiceImpl.java:51-74 → code mới (giữ nguyên) InventoryRelationalRepository.findOnHandsByWarehouse + WarehouseDeletePolicy.validateOnHands
  • Code cũ đang làm gì: lấy inventory.on_hand của từng dòng; dòng nào > 0 thì chặn; dòng nào tồn trống (null) gặp trước thì lỗi hệ thống.
  • Ví dụ cụ thể: kho 6, sản phẩm theo lô có inventory.on_hand = 0 nhưng lô L1 trong batches_detail còn 5 (dữ liệu lệch) → vẫn xoá được. Kho 7 có một dòng on_hand = NULL → lỗi hệ thống (cũ 417, mới 500), không xoá được.
  • Vì sao nghi là sai: SQL tính cột onHand theo lô nhưng code đọc cột on_hand.
  • Ảnh hưởng nếu đúng là bug: chỉ khi dữ liệu tồn tổng và tồn lô lệch nhau, hoặc tồn null.
  • Đã xử lý khi chuyển: GIỮ nguyên. Test khoá: TC-12, TC-13 (WarehouseDeletePolicyTest), TC-21 (InventoryRelationalRepositoryTest).
  • Nếu muốn sửa: đọc biểu thức tồn theo lô, coi null là 0; đổi TC-12, TC-21.
  • Liên quan: D-05, R-05

B-04 Xoá kho không tồn tại (bấm xoá hai lần) trả lỗi máy chủ 500

  • Mức nghi ngờ: THẤP — có thể cố ý, nhưng "không tìm thấy" thường không phải lỗi máy chủ.
  • Ở đâu: code cũ backend:service/impl/WarehouseServiceImpl.java:39-41 → code mới WarehouseManagementService.deleteWarehouse
  • Code cũ đang làm gì: không tìm thấy kho → lỗi 500 "Kho hàng không tồn tại".
  • Ví dụ cụ thể: người A xoá kho 8, người B (màn hình cũ) bấm xoá kho 8 → 500. Lẽ ra 404 hoặc coi như đã xoá.
  • Vì sao nghi là sai: lỗi do dữ liệu người gửi, không phải lỗi hệ thống; có thể làm giám sát lỗi 5xx báo động giả.
  • Ảnh hưởng nếu đúng là bug: người dùng thấy "lỗi hệ thống"; thao tác lặp hay gặp.
  • Đã xử lý khi chuyển: GIỮ nguyên. Test khoá: TC-05 (…$DeleteEndpoint#rejectsMissingWarehouse).
  • Nếu muốn sửa: NotFoundException (404), đổi TC-05; frontend kiểm cách hiển thị.
  • Liên quan: D-04, R-03

B-05 Xoá kho thành công nhưng thông báo "Cập nhật thành công!"

  • Mức nghi ngờ: THẤP — chỉ là văn bản thông báo.
  • Ở đâu: code cũ backend:service/impl/WarehouseServiceImpl.java:83 → code mới WarehouseController.deleteWarehouse
  • Code cũ đang làm gì: trả mã SUCCESS_UPDATE.
  • Ví dụ cụ thể: xoá kho 6 → "Cập nhật thành công!". Lẽ ra "Xoá thành công".
  • Vì sao nghi là sai: thông báo không khớp thao tác.
  • Ảnh hưởng nếu đúng là bug: chỉ hiển thị (nếu frontend dùng reason).
  • Đã xử lý khi chuyển: GIỮ nguyên. Test khoá: TC-01.
  • Nếu muốn sửa: đổi mã reason, đổi TC-01; kiểm frontend.
  • Liên quan: D-10, R-08

3d. Quyết định AI tự chốt và thay đổi tự động (cần người xác nhận)

# Nguồn AI đã làm gì Khác code cũ ở điểm nào (input → cũ / mới) Người cần xác nhận gì
1 D-01 (LỖI KỸ THUẬT) Kiểm comId là công ty của token user công ty 10 xoá comId=20&id=7 → cũ 200 xoá được / mới 400 COMPANY_NOT_OF_CURRENT_USER Đồng ý chặn xoá kho công ty khác
2 D-02 (ADR BẮT KHÁC) Body response/lỗi theo starter kho WH1 → cũ reason="Kho mặc định không được xoá" / mới reason="DELETE_WAREHOUSE_DEFAULT_INVALID"; thiếu id → cũ 400 body rỗng / mới 400 body starter Frontend đọc message[0].code, không đọc reason
3 D-03 (ADR BẮT KHÁC) Lỗi hệ thống 417 → 500, giữ mã EXCEPTION_ERROR on_hand null / code null → cũ 417 / mới 500 Frontend không phân biệt 417/500
4 D-07 (LỖI KỸ THUẬT) Kiểm hoá đơn rồi phiếu kho tuần tự kho có hoá đơn, câu phiếu kho trả trước → cũ có thể 200 (race) / mới luôn 400; câu phiếu kho lỗi trả trước → cũ 417 / mới 400 Đồng ý sửa race
5 D-09 (MƠ HỒ) Xoá như cũ, lỗi ràng buộc → 500 có FK inventory.warehouse_id → cũ 417 / mới 500; không FK → 200 Cho biết DB thật có khoá ngoại tới warehouse.id không (chạy GM-01)
6 D-11 (ADR BẮT KHÁC) Một transaction trên DB chính replica trễ → cũ có thể bỏ sót hoá đơn mới / mới thấy Đồng ý
7 D-12 (PHỤ THUỘC NGOÀI) Không chuyển kiểm gói dịch vụ công ty hết hạn gói → cũ 400 ACCOUNT_EXPIRED / mới xoá được Quyết tầng đảm nhận kiểm gói (chung với warehouse/create D-16, warehouse/update D-12)
8 D-13 (MƠ HỒ) Đọc 10 cột, kiểm kiểu mọi dòng trước khi kiểm tồn dòng có cột sai kiểu → cũ 417 (Hibernate 5) / mới 500, nhưng tập kiểu được chấp nhận có thể khác giữa Hibernate 5/6 Chạy GM-01 trên MSSQL thật để xác nhận kho bình thường không bị 500
9 spec-review Spec qua 1 lần review (0 CRITICAL), các R-xx đã sửa theo MAJOR: R-05 (F-spec-1, đọc hết dòng trước khi kiểm), R-07 (F-spec-2, native DELETE không kiểm số dòng) — Đọc kỹ R-05, R-07 trong spec.md
10 Thiết kế (impl) Thêm WarehouseUsageChecker giữa service và 3 nguồn đọc (constructor ≤ 7 tham số) không đổi hành vi Đồng ý cấu trúc này
11 Thiết kế (impl) InventoryErrorCode.EXCEPTION_ERROR mới (cùng giá trị) không đổi mã trả về —

4. Finding đã xác nhận

Không có.

5. Finding bị loại

Finding Lý do loại
— —

6. Xử lý của người

Vấn đề Cổng Chỉ thị
G4 — chưa kiểm Sonar G4

7. So với vòng trước

Vấn đề Vòng trước Vòng này
(vòng đầu) — —

8. Thay đổi trong repo đích

26 file (verify/round-1/changed-files.md): 17 main Java + 2 i18n + 7 test, đều trong src/main, src/test. Mới: WarehouseUsageChecker, WarehouseDeletePolicy, WarehouseDeletePolicyTest, InventoryRelationalRepositoryTest. Chạm class dùng chung của context khác: InventoryRepository/InventoryRelationalRepository/InventoryQueryService/InventoryErrorCode, RsInoutwardRepository/RsInoutwardRelationalRepository/RsInoutwardQueryService, BillPort/BillRelationalAdapter — chỉ thêm, không đổi method cũ. Không có file ngoài phạm vi.

9. Đề xuất bổ sung kinh nghiệm (/mig-learn gom vào proposal để người duyệt)

Đề xuất Đưa vào đâu
Code cũ không có transaction bao ngoài mà xoá bằng SimpleJpaRepository.delete → mới phải xoá bằng native DELETE không kiểm số dòng; JPA remove trên entity đã nạp trong cùng transaction ra StaleStateException khi bị xoá đồng thời (F-spec-2) lessons.md 1a/1b
Tuple.get("snake_case") của Hibernate 5 tra alias không phân biệt hoa thường nhưng on_hand ≠ onHand: kiểm cột thật được đọc; và bước collect dựng đủ mọi dòng trước khi kiểm → lỗi đọc thắng lỗi nghiệp vụ (F-spec-1) lessons.md 1a
CompletableFuture.anyOf + isDone() ? a.join() : b.join() để lấy "kết quả còn lại" là race; gặp thì ghi D-xx LỖI KỸ THUẬT lessons.md 1a
Constructor @Service tối đa 7 tham số (Checkstyle ParameterNumber cho constructor) — thêm use case vào service có sẵn 6 dependency thì tách bean phụ trợ ngay từ thiết kế spec mục 5 target-cheatsheet mục 4
Trong Bash tool, heredoc/node -e làm mất \\ trong chuỗi Java regex — sửa chuỗi có \\ bằng Edit lessons.md 1c

Nguồn của trang này

  • Báo cáo sai lệch migrations/warehouse/delete/report.md vòng 1 · sha256 d52b82a0a235

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