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

batch · batch/create · api

POST/api/client/page/batches/create

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

Phân tích luồng sau chuyển — batch/create — vòng 1

logic-reviewer viết dựa trên code đã implement (không phải thiết kế trong spec), đối chiếu với code cũ. Dev đọc file này cùng changes.diff: mỗi luồng cho biết code mới đi qua những đâu, khác code cũ ở bước nào, và chỗ nào cần đọc kỹ.

Viết tắt đường dẫn mới: ctl/ = presentation/web/batch/, app/ = application/batch/, dom/ = domain/batch/, inf/ = infrastructure/relational/batch/ (gốc src/main/java/com/softdreams/easypos/warehouse/). Cũ: svc = easyposbackend1:src/main/java/vn/softdreams/easypos/service/impl/BatchesManagementServiceImpl.java.

F-01 Lưu lô (tạo; /create kèm id thì sửa)

  • Điểm vào: cũ easyposbackend1:src/main/java/vn/softdreams/easypos/web/rest/BatchesManagementResource.java:40-45 → mới ctl/BatchController.java:54-59
  • Quy tắc: R-01 … R-14

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

sequenceDiagram
    participant C as Client
    participant BC as BatchController.create
    participant MS as BatchManagementService.save (@Transactional)
    participant BR as BatchRelationalRepository (translate)
    participant BW as BatchWriter
    participant DB as batches
    C->>BC: POST BatchSaveRequest
    BC->>BC: Guard.validateInput (mọi vi phạm, 400)
    BC->>MS: save(BatchWebMapper.toSaveCommand)
    MS->>MS: requireCompany: CurrentUserPort.findCompanyId → TOKEN_EXPIRED 400 / COMPANY_NOT_EXISTS_CODE 500
    MS->>MS: BatchExpiryWarning.requireWithinMax → BatchDateParser.parse(mfg), parse(exp) → MFG_DATE_EXCEED_EXP_DATE
    opt id != null
      MS->>BR: findByIdAndComId(id, comId) → rỗng: LOT_NO_NOT_FOUND 400
    end
    MS->>BR: findDuplicate(comId, lotNo thô, mfg, exp) (JPQL, null → IS NULL)
    alt trùng và (id null hoặc id khác)
      MS-->>BC: BatchSaveResult.duplicated()
      BC-->>C: 200 status=false LOT_NO_DUPLICATE
    else tạo (id null)
      MS->>BW: lockCompanyBatchCode (SELECT TOP 1 batches + sp_getapplock 10s)
      MS->>BW: countByComId → code = "LH"+(n+1)
      MS->>MS: status (BatchStatusPolicy), normalizedName thô → LegacyCleanText.clean(code, lotNo, normalizedName), audit = user/now
      MS->>BW: save → persist (INSERT ngay)
      BC-->>C: 200 SUCCESS_CREATE, data = lô đã làm sạch
    else sửa (id có)
      MS->>MS: code NULL → SystemException EXCEPTION_ERROR
      MS->>MS: gán giá trị thô (lotNo, ngày, status, normalizedName, expiryWarning*) → BatchDirtyCheck.isDirty
      opt dirty
        MS->>BW: save(đã làm sạch, updater/updateTime) → gán entity managed (UPDATE lúc commit)
      end
      BC-->>C: 200 SUCCESS_UPDATE, data.lotNo thô
    end

Đố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 Validate SaveBatchRequest, trả mọi vi phạm — BatchesManagementResource.java:42, SaveBatchRequest.java:11-28, LF-01 ctl/BatchController.java:57, ctl/dto/request/BatchSaveRequest.java:26-41 KHỚP (body hỏng: D-02)
2 getUserWithAuthorities(comId) — svc:165, UserService.java:1838-1851 app/BatchManagementService.java:58,80-87 KHÁC có chủ đích (D-01)
3 Giới hạn cảnh báo theo đơn vị — svc:167-185 dom/model/BatchExpiryWarning.java:30-47; app/BatchManagementService.java:59-60 KHỚP
4 Parse NSX rồi HSD, lỗi → DATE_TIME_INVALID — svc:187-194, model:util/BaseCommon.java:1128-1142 dom/model/BatchDateParser.java:29-38; app/BatchManagementService.java:61-62 KHỚP
5 HSD trước NSX → MFG_DATE_EXCEED_EXP_DATE — svc:196-198 app/BatchManagementService.java:63-65 KHỚP
6 id có → findByIdAndComId rỗng → LOT_NO_NOT_FOUND — svc:200-204 app/BatchManagementService.java:66,89-92; inf/adapter/BatchRelationalRepository.java:125-128 KHỚP
7 Kiểm trùng số lô thô + ngày, trả 200 status=false — svc:206-217 app/BatchManagementService.java:67-72; inf/jpa/BatchJpaRepository.java:27-34; ctl/BatchController.java:66-70 KHỚP (định dạng D-02; nhiều dòng → 500 D-05)
8 Nhánh sửa nạp lại lô (SELECT lần 2) — svc:221-222 dùng lại existing (bước 6); inf/adapter/BatchWriter.java:69-71 find lấy entity managed KHỚP (bớt một SELECT, không quan sát được)
9 Sinh mã LH + count + 1, không khoá — svc:224-226, base:services/BaseSequenceService.java:51-72,250-252,296-374, base:repositories/impl/BaseUserRepositoryImpl.java:35-51 app/BatchManagementService.java:95-96; inf/adapter/BatchWriter.java:18-60 KHÁC có chủ đích (D-11); nhánh chờ khoá quá 10s → KHÁC (F-logic-2)
10 Chép lotNo, expiryWarning*, ngày, tính status — svc:229-245,551-568 app/BatchManagementService.java:73-76,107,136; dom/model/BatchStatusPolicy.java:25-33 KHỚP
11 normalizedName(List.of(code, lotNo thô)); code NULL → NPE — svc:247, util/Common.java:1131-1139,1315-1329 dom/model/BatchNormalizedName.java:30-53; app/BatchManagementService.java:108,121-127,137 KHỚP (NPE → 500 EXCEPTION_ERROR, D-05)
12 Tạo: save → persist, CleanTextListener + auditing — svc:248, domain/Batches.java:14-16, LF-30, LF-31 app/BatchManagementService.java:97-116; dom/model/LegacyCleanText.java:24-30; inf/adapter/BatchWriter.java:68-89 KHỚP
13 Sửa: entity managed, UPDATE lúc commit chỉ khi dirty trên giá trị thô, listener làm sạch, @LastModified* — svc:248, K-02 app/BatchManagementService.java:120-169; dom/model/BatchDirtyCheck.java:24-43; inf/adapter/BatchWriter.java:68-89 KHỚP về dữ liệu ghi (D-08); lỗi DB lúc commit ra ngoài translate → KHÁC (F-logic-1)
14 Response BatchItem từ entity; tạo: đã làm sạch, sửa: lotNo thô — svc:250-257 app/BatchManagementService.java:117,149,171-182; ctl/BatchController.java:61-65; ctl/BatchWebMapper.java:49-65; ctl/dto/response/BatchItemResponse.java KHỚP (D-09; data khi trùng D-02)
15 Interceptor kiểm gói dịch vụ — LF-21 (không có) CHỈ CÓ Ở CŨ (D-10)
16 Lỗi không lường trước → 417 EXCEPTION_ERROR — LF-13 inf/adapter/BatchRelationalRepository.java:153-160 → SystemException 500 KHÁC có chủ đích (D-05)

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 (đọc) id+com_id ×2 (nhánh sửa), com_id+lot_no+mfg_date+exp_date (derived), count(*) where com_id (tạo) id+com_id ×1, JPQL trùng (cùng điều kiện, null → IS NULL), SELECT TOP 1 … where com_id trong câu khoá + count(*) where com_id (tạo) thêm một đọc trong câu khoá (K-12)
batches (ghi) INSERT mọi cột (tạo); UPDATE cột đổi + updater, update_time khi dirty (sửa) như cũ: persist (tạo); gán entity @DynamicUpdate chỉ khi BatchDirtyCheck true (sửa) creator, create_time updatable=false
Khoá ứng dụng MSSQL batch-code-<comId> — sp_getapplock Exclusive, owner Transaction, timeout 10s (chỉ nhánh tạo) D-11
Redis, event, cache không không —

Transaction, khoá, idempotency, tenant

  • Ranh giới transaction: cũ @Transactional cấp class trên BatchesManagementServiceImpl (svc:55-57) → mới @Transactional trên BatchManagementService.save (app/BatchManagementService.java:56), gọi từ controller (không self-invocation); kiểm, đếm, ghi trong một transaction; trùng trả bình thường, không ghi.
  • Khoá / cập nhật nguyên tử: cũ không khoá → mới khoá theo công ty ngay trước câu đếm, giữ tới commit (D-11). Kiểm trùng vẫn chạy trước khoá như cũ (hai request cùng số lô/ngày đồng thời vẫn lọt trùng — giống cũ). Nhánh sửa không khoá, không version — giống cũ.
  • Idempotency, thời điểm phát event: không có event/consumer.
  • Lọc comId: mọi truy vấn có comId (= companyId token); BatchWriter.save nhánh sửa find theo id nhưng id đã được xác nhận thuộc comId ở bước 6 cùng transaction.

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

Không lệch thứ tự bước. Chi tiết thêm so với sơ đồ: nhánh sửa không gọi save khi không dirty; khoá nằm trong BatchWriter (thêm lớp) thay vì trực tiếp ở BatchRelationalRepository.

Dev cần chú ý khi review

Vị trí Vì sao
inf/adapter/BatchWriter.java:18-53 Câu khoá nhiều lệnh (SET NOCOUNT ON + đọc bảng + sp_getapplock + SELECT @result) đọc bằng getSingleResult; chưa chạy trên MSSQL thật (K-12, K-13); timeout 10s → 500 (F-logic-2)
inf/adapter/BatchWriter.java:68-89 + BatchRelationalRepository.java:148-160 Nhánh sửa ghi lúc commit, ngoài translate → mã lỗi khi UPDATE thất bại (F-logic-1)
app/BatchManagementService.java:120-150 Mô phỏng dirty-check Hibernate trên giá trị thô (K-02, D-08) và response trả lotNo thô (D-09) — khác dữ liệu lưu
inf/jpa/BatchJpaRepository.java:27-34, inf/jpa/BatchDuplicateParams.java:24-33 Kiểm trùng viết tay thay derived query: null → IS NULL, ngày bind Timestamp theo jdbc.time_zone; nhiều dòng → IncorrectResultSizeDataAccessException → 500
app/BatchManagementService.java:121-127 Mô phỏng NPE của List.of(code, …) khi code NULL — chỉ ở nhánh sửa, sau kiểm trùng

Nguồn của trang này

  • Phân tích luồng migrations/batch/create/verify/round-1/flow-analysis.md vòng 1 · sha256 405b54d953dd

v1 dựng 2026-11-09 14:46 · base commit đích 661efe9b8c