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

Tồn kho · inventory/enable-inventory-tracking · api

PUT/api/client/page/product/enable-inventory-tracking

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

Báo cáo sai lệch — inventory/enable-inventory-tracking — vòng 2

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 (ghi product, product_product_unit, inventory, tạo phiếu nhập, gửi Kafka) → người cần đọc: spec + báo cáo + toàn bộ diff
  • Số quy tắc: 13 · PASS 4 (R-04, R-06, R-07, R-10) · DEVIATION có chủ đích 8 (R-01, R-02, R-03, R-05, R-08, R-09, R-11, R-13 — xem mục 2) · DEVIATION KHÔNG chủ đích 0 · UNVERIFIED 1 (R-12) + một phần R-08 (D-11, DEFAULT cột mới)
  • Coverage thấp nhất: F-02 99.5% dòng / 84.6% nhánh
  • Finding logic: CRITICAL 0 · MAJOR 0 (1 đã sửa ở vòng 1) · MINOR 2 · UNSURE 0
  • Nghi vấn bug code cũ (mục 3c): 5 (CAO 1) · Quyết định tự chốt cần xác nhận (mục 3d): 6
  • Chạy bằng: /mig-auto lượt 20261105-1351 (spec qua 2 lần spec-reviewer, chưa có người duyệt) · Số vòng: 2 verify / lần sửa 1/3
  • Phạm vi API còn nghi vấn (❓) — API thuộc màn sản phẩm (/api/client/page/product/...), chuyển vì người yêu cầu đích danh; ghi bảng của context sản phẩm (D-01).

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

Mã Mục tiêu Kết quả Bằng chứng
G1 mvnw verify ✅ verify/round-2/build.md (712 test, SpotBugs 0, ArchUnit 36/36)
G2 Test khớp test-plan ✅ verify/round-2/oracle.md (28/28 TC)
G3 Coverage mỗi luồng ✅ verify/round-2/coverage.md
G4 Sonar CHỜ NGƯỜI sonar-ide.md
G5 0 CRITICAL/MAJOR ✅ verify/round-2/review-logic.md (không cần xác minh); F-logic-1 vòng 1 đã sửa
G6 Không lách cổng ✅ verify/round-2/gates.md; 33 file đều có trong impl-notes.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 — tầng A, nên chạy trước khi commit)

Coverage theo luồng

Luồng Tên % dòng % nhánh
F-01 Kiểm yêu cầu bật theo dõi tồn 100.0% (96/96) 95.8% (23/24)
F-02 Tính và ghi sản phẩm, tồn, phiếu khởi tạo 99.5% (192/193) 84.6% (44/52)

2. Ma trận truy vết

Quy tắc Tầng Code mới Test Golden Kết luận
R-01 A InventoryTrackingController, EnableInventoryTrackingRequest TC-01, 02, 03 GM-01 DEVIATION (có chủ đích, D-02 — body lỗi theo starter)
R-02 A InventoryTrackingService.requireCompany TC-04, 05 — DEVIATION (có chủ đích, D-04)
R-03 A InitialStockRelationalRepository.findDefaultWarehouse TC-06, 20 GM-01 DEVIATION (có chủ đích, D-05 — giữ kết quả, không try/catch)
R-04 A InventoryTrackingService.validateRequest TC-06, 07 — PASS
R-05 A InventoryTrackingService, ProductTrackingRelationalAdapter.findUnit TC-08, 17 — DEVIATION (có chủ đích, D-03 — 417 → 500)
R-06 A ProductTrackingRelationalAdapter.findActiveProduct TC-09, 17 — PASS
R-07 A InventoryTrackingPlan TC-10, 11 GM-01 PASS
R-08 A ProductTrackingRelationalAdapter, InitialStockRelationalRepository, InitialRsInoutwardService TC-12, 14, 17–19, 21–23, 25, 26 GM-01 DEVIATION (có chủ đích, D-09 ngày giờ VN); D-06, D-10, D-11 GIỮ; D-11 + DEFAULT type_doc/ref_id UNVERIFIED
R-09 A InventoryTrackingService (@Transactional, ifPresent) TC-13, 15, 16, 28 — DEVIATION (có chủ đích, D-05)
R-10 A LegacyInventoryLogKafkaProducer, LegacyInventoryLog TC-24, TC-24-EXTRA-1 GM-01 PASS (D-07 GIỮ)
R-11 A InventoryTrackingController TC-01, 27 — DEVIATION (có chủ đích, D-02)
R-12 A — — — UNVERIFIED (D-08 không chuyển kiểm gói)
R-13 A InventoryTrackingPlan.requireFlag/divide, InitialRsInoutwardService TC-11, 15, 16 — DEVIATION (có chủ đích, D-03)

3. Người cần xem

# Vị trí Vì sao cần người xem
1 Toàn bộ diff (verify/round-2/changes.diff, 33 file) Tầng A
2 …/infrastructure/relational/product/adapter/ProductTrackingRelationalAdapter.java Ghi thẳng bảng của context sản phẩm (D-01); mô phỏng dirty check/làm sạch chuỗi của Hibernate (D-10, D-11 UNVERIFIED) — nên chạy GM-01
3 …/infrastructure/messaging/LegacyInventoryLogKafkaProducer.java Gửi message định dạng cũ lên inventory-events (D-07); template riêng StringSerializer (F-logic-1 đã sửa)
4 …/application/inventory/InventoryTrackingService.java:95-96 Không có WH1 vẫn báo thành công (D-05)
5 F-logic-2 (MINOR) Câu thông báo PRODUCT_NOT_FOUND của repo đích có {0} không được điền; câu cũ "Không tìm thấy thông tin sản phẩm" — mã/HTTP giữ đúng
6 F-logic-3 (MINOR) UPDATE inventory/product/product_product_unit chỉ theo id (không thêm com_id) — id luôn lấy từ truy vấn đã lọc công ty, như cũ
7 R-12 UNVERIFIED Không kiểm gói dịch vụ (D-08)
8 spec.md:210 Câu "mới chỉ cập nhật cột đổi (D-11)" trong mục Khác biệt viết sót trước khi D-11 chốt GIỮ; code làm theo D-11 (ghi cả cột chuỗi bị làm sạch)

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

Chi tiết: verify/round-2/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 Kiểm yêu cầu bật theo dõi tồn 4 / 3 (D-02, D-04, D-03 + câu thông báo F-logic-2) / 1 (kiểm gói D-08) / 0 không thứ tự token → kho → kiểm request; câu PRODUCT_NOT_FOUND
F-02 Tính và ghi sản phẩm, tồn, phiếu khởi tạo 9 / 2 (D-11, D-05) / 1 (task log rỗng, không side effect) / 0 không template Kafka riêng; nhánh không có WH1; sinh NK mọi ppu chính chỉ lưu phiếu đầu; UPDATE theo id

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

B-01 Bật theo dõi tồn mà sản phẩm chưa có dòng tồn ở kho chính thì số tồn đầu không được ghi vào kho

  • Mức nghi ngờ: CAO — sản phẩm chưa bật theo dõi tồn thường chưa có dòng inventory nào, nên trường hợp này dễ là trường hợp phổ biến.
  • Ở đâu: code cũ easyposbase:services/impl/BaseInventoryServiceImpl.java:609-701 → code mới (giữ nguyên) …/application/inventory/InventoryTrackingService.java:106-118, …/infrastructure/relational/inventory/adapter/InitialStockRelationalRepository.java:65-85
  • Code cũ đang làm gì: chỉ sửa số tồn của dòng tồn đã có sẵn ở kho WH1 và không có lô; không tạo dòng mới. Phiếu nhập "Khởi tạo kho" thì luôn được tạo.
  • Ví dụ cụ thể: sản phẩm 70 chưa có dòng tồn nào ở WH1, bật với tồn 50 giá 20.000 → có phiếu NK42 "nhập 50" nhưng bảng inventory không có tồn 50. Ngoài ra ppu có 2 dòng tồn không lô trùng nhau → chỉ một dòng (bất kỳ) được đặt 50; sản phẩm có 2 ppu chính → tiêu 2 mã NK, chỉ lưu 1 phiếu.
  • Vì sao nghi là sai: phiếu khởi tạo và tồn thực tế lệch nhau ngay sau khi bật.
  • Ảnh hưởng nếu đúng là bug: tồn trên màn hình kho = 0 trong khi có phiếu nhập 50; báo cáo nhập-xuất-tồn lệch.
  • Đã xử lý khi chuyển: GIỮ nguyên hành vi cũ. Test khoá: TC-21 (InitialStockRelationalRepositoryTest#stockRows), TC-14 (InventoryTrackingServiceTest#twoPrimaryUnits).
  • Nếu muốn sửa: thêm tạo dòng inventory khi thiếu trong InitialStockRelationalRepository/service, đổi TC-21; monolith còn chạy song song sẽ khác hành vi.
  • Liên quan: D-06, R-08

B-02 Công ty không có kho WH1: bật theo dõi tồn vẫn báo thành công nhưng không có tồn, không có phiếu

  • Mức nghi ngờ: TRUNG BÌNH — chỉ xảy ra khi công ty không có kho mã WH1 (hiếm), nhưng sau đó không có cách tạo lại phiếu.
  • Ở đâu: code cũ easyposbackend1:…/service/impl/ProductManagementServiceImpl.java:3347-3349,3357-3367,3396-3399 → code mới …/application/inventory/InventoryTrackingService.java:95-96
  • Code cũ đang làm gì: lỗi do thiếu kho WH1 bị nuốt; sản phẩm/đơn vị tính đã được bật và lưu tồn ở ppu, API trả thành công.
  • Ví dụ cụ thể: công ty 10 không có WH1, bật ppu 701 tồn 50 → product.inventory_tracking = 1, ppu 701 on_hand = 50, không có phiếu, không có tồn kho; gọi lại → 400 PRODUCT_ENABLE_TRACKING_INVALID.
  • Vì sao nghi là sai: người dùng được báo thành công trong khi dữ liệu kho thiếu.
  • Ảnh hưởng nếu đúng là bug: sản phẩm "đã theo dõi tồn" nhưng không có tồn đầu.
  • Đã xử lý khi chuyển: GIỮ. Test khoá: TC-13 (InventoryTrackingServiceTest#noDefaultWarehouse).
  • Nếu muốn sửa: ném lỗi khi không có WH1 (rollback hết), đổi TC-13.
  • Liên quan: D-05, R-03, R-09

B-03 Message log tồn mang loại "xuất bán" và số -99

  • Mức nghi ngờ: TRUNG BÌNH — consumer cũ đang tắt nên hiện chưa ai đọc.
  • Ở đâu: code cũ easyposbase:mapper/InventoryLogMessageMapper.java:17-30,55-66 → code mới …/domain/inventory/model/LegacyInventoryLog.java
  • Code cũ đang làm gì: khi đặt tồn khởi tạo, gửi message type BILL_COMPLETION, direction 2 (xuất), onHandReq/onHandCurrent -99; gửi trước khi lưu và commit.
  • Ví dụ cụ thể: đặt tồn 50 cho dòng 3001 → message {type:"BILL_COMPLETION", direction:2, onHandReq:-99, …, inventoryId:3001}; lưu phiếu lỗi sau đó → DB rollback nhưng message đã đi.
  • Vì sao nghi là sai: đây là nhập khởi tạo +50, không phải xuất bán.
  • Ảnh hưởng nếu đúng là bug: nếu bật lại consumer, log tồn ghi sai.
  • Đã xử lý khi chuyển: GIỮ. Test khoá: TC-24 (LegacyInventoryLogKafkaProducerTest#sendsLegacyMessage).
  • Nếu muốn sửa: gửi InventoryLogsEvent đúng nghĩa qua InventoryLogPort của repo đích, sau commit.
  • Liên quan: D-07, R-10

B-04 Bật theo dõi tồn làm đổi tên đơn vị tính (gộp khoảng trắng, bỏ xuống dòng)

  • Mức nghi ngờ: THẤP — thay đổi nhỏ về chữ.
  • Ở đâu: code cũ easyposbackend1:domain/ProductProductUnit.java:15-18 (CleanTextListener) → code mới …/ProductTrackingRelationalAdapter.java:102-133
  • Code cũ đang làm gì: dòng ppu có đổi tồn/giá được ghi lại toàn bộ, các cột chữ bị làm sạch.
  • Ví dụ cụ thể: ppu 702 unit_name = "Thùng 12" → sau khi bật thành "Thùng 12".
  • Vì sao nghi là sai: dữ liệu chữ bị đổi ngoài ý người dùng.
  • Ảnh hưởng nếu đúng là bug: tìm kiếm/đối chiếu theo tên cũ có thể lệch.
  • Đã xử lý khi chuyển: GIỮ. Test khoá: TC-18 (ProductTrackingRelationalAdapterTest#updateUnits).
  • Nếu muốn sửa: chỉ UPDATE on_hand, purchase_price, audit; đổi TC-18.
  • Liên quan: D-10, R-08

B-05 Bật theo dõi tồn làm đổi tên/mô tả sản phẩm (gộp khoảng trắng, bỏ xuống dòng)

  • Mức nghi ngờ: THẤP — hành vi suy ra từ cách Hibernate 5.6 xử lý @DynamicUpdate + listener, UNVERIFIED.
  • Ở đâu: code cũ easyposbackend1:domain/Product.java:29-32 → code mới …/ProductTrackingRelationalAdapter.java:136-157
  • Code cũ đang làm gì: khi lưu sản phẩm, mọi cột chữ bị làm sạch khác giá trị cũ được ghi lại.
  • Ví dụ cụ thể: name = "Áo thun", description = "dòng 1\ndòng 2" → "Áo thun", "dòng 1dòng 2" (mất ngắt dòng).
  • Vì sao nghi là sai: mô tả nhiều dòng bị dính liền sau khi bật tồn.
  • Ảnh hưởng nếu đúng là bug: mô tả sản phẩm hiển thị sai.
  • Đã xử lý khi chuyển: GIỮ. Test khoá: TC-19 (ProductTrackingRelationalAdapterTest#enableTracking).
  • Nếu muốn sửa: bỏ vòng làm sạch trong enableTracking; đổi TC-19. Cần chạy GM-01 để xác nhận code cũ thật sự làm vậy.
  • Liên quan: D-11, 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 Port + adapter transitional ghi thẳng product, product_product_unit không khác dữ liệu Có chấp nhận warehouse-service ghi bảng của context sản phẩm tạm thời không
2 D-02 Body lỗi/thành công theo starter thành công → cũ reason là câu tiếng Việt / mới mã UPDATE_PRODUCT_SUCCESS Frontend đọc được định dạng mới
3 D-03 Lỗi hệ thống 417 → 500 EXCEPTION_ERROR ppu phụ formula null → cũ 417 / mới 500 Chấp nhận đổi HTTP
4 D-04 Chỉ giữ 2 kiểm token/công ty token cũ sau đổi mật khẩu → cũ 500 TOKEN_EXPIRED / mới chạy tiếp Gateway/auth đã chặn các trường hợp còn lại chưa
5 D-08 Không kiểm gói dịch vụ hết gói → cũ 400 ACCOUNT_EXPIRED / mới vẫn bật Có cần kiểm gói ở gateway không
6 D-09 Mã NK qua SequenceService (không kiểm trùng), ngày phiếu = hôm nay 00:00 giờ VN 06:00 06/11 giờ VN, JVM cũ UTC → cũ 2026-11-05 07:00 / mới 2026-11-06 00:00 Múi giờ JVM của monolith prod

Spec qua 2 lần review (lần 1 có CRITICAL); mọi finding đã CHẤP NHẬN, không còn CHƯA QUYẾT. Không có auto-changes.md.

4. Finding đã xác nhận

F-logic-1 (vòng 1, ĐÃ SỬA ở lần sửa 1)

  • Mức độ: MAJOR · Loại: parity · Quy tắc: R-10
  • Mô tả: message inventory-events đi qua JsonSerializer mặc định của repo đích → payload bị bọc thành chuỗi JSON, khác code cũ (StringSerializer).
  • Xác minh: CONFIRMED (verify/round-1/verification.md). Sửa: template riêng ghi đè StringSerializer; khoá bằng TC-24-EXTRA-1. Vòng 2 reviewer xác nhận đã sửa đúng.

F-logic-2 — MINOR (chưa sửa)

Xem verify/round-1/review-logic.md#F-logic-2: câu thông báo PRODUCT_NOT_FOUND có {0} không điền.

F-logic-3 — MINOR (chưa sửa)

Xem verify/round-1/review-logic.md#F-logic-3: UPDATE theo id không lọc com_id.

5. Finding bị loại

Finding Lý do loại
— —

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

Vấn đề Cổng Chỉ thị
Kiểm Sonar trong IDE (sonar-ide.md) G4

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

Vấn đề Vòng trước Vòng này
F-logic-1 (MAJOR) MỚI ĐÃ HẾT
F-logic-2 (MINOR) MỚI CÒN
F-logic-3 (MINOR) MỚI CÒN

8. Thay đổi trong repo đích

33 file (verify/round-2/changed-files.md): 19 file main mới/sửa trong presentation/web/inventory, application/inventory, application/rsinoutward, domain/inventory, domain/port/{product,messaging,businesstype}, domain/rsinoutward/command, infrastructure/relational/{product,inventory,businesstype}, infrastructure/messaging; i18n vi/en; 8 lớp test mới. Không có file ngoài phạm vi dự kiến. Chưa thêm khoá app.kafka.topics.legacy-inventory-log vào yml (mặc định inventory-events).

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

Đề xuất Đưa vào đâu
Producer Kafka gửi message định dạng monolith (chuỗi JSON tự serialize) phải dùng template riêng ghi đè StringSerializer như TaskLogKafkaProducer — value serializer mặc định của warehouse-service là JsonSerializer knowledge/target-cheatsheet.md / lessons.md
Test dùng ArgumentCaptor generic: khai báo @Captor field thay vì forClass + @SuppressWarnings (G6 chặn @SuppressWarnings) lessons.md
BaseCommon.cleanTextReturnNull(" ") trả "" (không phải null) — ghi vào LF làm sạch chuỗi legacy-facts.md

Nguồn của trang này

  • Báo cáo sai lệch migrations/inventory/enable-inventory-tracking/report.md vòng 2 · sha256 8e45e40e7738

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