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

Tồn kho · inventory/cogs-calculate · api

POST/api/client/page/warehouse/cogs/calculate

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

Phân tích luồng sau chuyển — inventory/cogs-calculate — vòng 1

Viết tắt: WHS = easyposbase:src/main/java/sds/ep/baseservice/services/impl/BaseWarehouseServiceImpl.java, CHS = easyposbase:src/main/java/sds/ep/baseservice/services/impl/BaseCogsHistoryServiceImpl.java, TLS = easyposbase:src/main/java/sds/ep/baseservice/services/impl/BaseTaskLogServiceImpl.java. Đường dẫn mới tính từ C:/Projects/warehouse-service-wt/ws1/src/main/java/com/softdreams/easypos/warehouse/.

F-01 Nhận yêu cầu, chọn nhánh, gửi task log tính sau

  • Điểm vào: cũ easyposbackend1:src/main/java/vn/softdreams/easypos/web/rest/WarehouseResource.java:136-140 → mới presentation/web/inventory/CogsController.java:42-54
  • Quy tắc: R-01, R-02, R-03, R-04, R-05, R-15, R-16, R-17, R-18

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

sequenceDiagram
    participant C as Client
    participant W as CogsController.calculateCogs
    participant S as CogsCalculationService.calculateCogs (@Transactional)
    participant CC as CurrentCompanyService.requireCompanyOfCurrentUser
    participant R as CogsRelationalRepository
    participant A as CogsTaskLogMongoRabbitAdapter.publishCompletion
    participant Q as SendQueueConfigRelationalAdapter.requireValid
    C->>W: POST /api/client/page/warehouse/cogs/calculate
    W->>S: calculateCogs(InventoryWebMapper.toCalculateCogsCommand)
    S->>CC: comId (null/khác token → 400)
    alt fromDate/toDate null
      S-->>W: Outcome.fail(null)
    end
    S->>S: CogsPeriod.of (00:00 VN, normDate, quarter)
    opt paramCheckAll == TRUE
      S->>R: findPrimaryPpuIds(comId)
    end
    alt rỗng/null
      S-->>W: fail(PRODUCT_LIST_NOT_EMPTY)
    else size > 100 hoặc checkAll
      loop mỗi lô 100 (subList, giữ thứ tự/trùng)
        S->>A: CogsCompletionTask(batch, comId, from, to)
        A->>Q: config.business_type + company.service
        A->>A: mongoTemplate.insert(Document) task_log_reference
        A->>A: rabbitTemplate.send(amq.direct, cogs-completion, "id" JSON) — lỗi AMQP chỉ log
      end
      S-->>W: success(CALCULATE_COGS_SUCCESSFULLY, null, size)
    else ≤ 100
      S->>S: CogsComputationService.calculate (F-02)
    end
    W-->>C: 200 BaseResponseDTO{code, reason, success=true, data, count}

Đố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 body, không validate — WarehouseResource.java:137; easyposbase:.../dto/cogsHistory/CogsCalculationRequest.java:11-23 CogsController.java:44; dto/request/CogsCalculationRequest.java:22-29 KHỚP (body hỏng 400: khác có chủ đích D-02)
2 Không kiểm công ty — WHS:1896 CogsCalculationService.java:54 KHÁC có chủ đích (D-01)
3 Ngày null → NPE → catch → 200 FAIL reason null — WHS:1894-1895,1924-1926 CogsCalculationService.java:55-58 KHỚP (mất key null: D-02; kiểm sau bước công ty: D-01)
4 atStartOfDay(VN), normDate/quarter — WHS:1894-1895; CHS:62-65; easyposmodel:.../util/BaseCommon.java:2123-2133,2612-2615 domain/cogs/model/CogsPeriod.java:42-64 KHỚP
5 checkAll → findAllIdByComId — WHS:1902-1904; easyposbase:.../repositories/BaseProductProductUnitRepository.java:250-257 CogsCalculationService.java:60-61; infrastructure/relational/cogs/adapter/CogsRelationalRepository.java:41-46,118-124 KHỚP
6 Rỗng → FAIL PRODUCT_LIST_NOT_EMPTY — WHS:1906-1908 CogsCalculationService.java:62-64 KHỚP
7 > 100 / checkAll → splitList 100, mỗi lô sendTaskLogComplete, trả count = size — WHS:1910-1920; CHS:331-343 CogsCalculationService.java:65-73 KHỚP
8 Kiểm cấu hình gửi queue (Redis → DB + EasyInvoice) — TLS:340,374; easyposbase:.../BaseConfigServiceImpl.java:579-611 infrastructure/relational/config/adapter/SendQueueConfigRelationalAdapter.java:41-54, gọi từ infrastructure/messaging/CogsTaskLogMongoRabbitAdapter.java:98 KHÁC có chủ đích (D-10); value NULL → NPE (F-logic-1)
9 Document Mongo com_id,type,content,status=0,norm_date,creator/updater,create/update_time,_class — TLS:337-371,376; easyposmodel:.../domain/BaseMongoTaskLogReference.java, BaseAbstractAuditingDocument.java:23-37 CogsTaskLogMongoRabbitAdapter.java:99-104,115-136 KHỚP; norm_date theo giờ VN: D-09; adapter mới: D-07
10 RabbitMQ amq.direct/cogs-completion, payload id qua Jackson2JsonMessageConverter, lỗi nuốt — TLS:303-334; easyposbase:.../integraion/BaseEasyPosProducer.java:43-47; easyposconfig:.../rabbitmq/BaseRabbitMqConfiguration.java:30-51 CogsTaskLogMongoRabbitAdapter.java:105-112; infrastructure/messaging/CogsTaskLogRouting.java KHỚP (cũ bắt Exception, mới chỉ bắt AmqpException, xem Dev cần chú ý)
11 Lỗi trong proxy tham gia → rollback-only → 417 — LF-13, LF-35 SystemException(EXCEPTION_ERROR) 500 KHÁC có chủ đích (D-03)
12 Kiểm gói dịch vụ (LF-21) không có CHỈ CÓ Ở CŨ (D-08)

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ú
product_product_unit + product đọc khi checkAll đọc khi checkAll, cùng SQL KHỚP
Redis CONFIG_COM_ID đọc, ghi khi thiếu không D-10
config, company đọc khi Redis lỗi đọc trước mỗi task log D-10
Mongo task_log_reference insert mỗi lô, ngay insert mỗi lô, ngay KHỚP (D-07, D-09)
RabbitMQ amq.direct/cogs-completion gửi id, lỗi nuốt gửi id, lỗi AMQP nuốt KHỚP

Transaction, khoá, idempotency, tenant

  • Ranh giới transaction: cũ: class @Transactional của WHS:66, processMongoTaskLog tham gia → mới: @Transactional ở CogsCalculationService.java:52.
  • Khoá / cập nhật nguyên tử: cả hai đều không có.
  • Idempotency, thời điểm phát: task log ghi Mongo và gửi Rabbit ngay, trước commit SQL, ở cả cũ và mới (D-05). Gọi lại API thì tạo task log mới ở cả hai.
  • Lọc comId: có trong findPrimaryPpuIds (cả ppu và p); comId lấy từ requireCompanyOfCurrentUser (D-01).

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

Không có.

Dev cần chú ý khi review

Vị trí Vì sao
infrastructure/messaging/CogsTaskLogMongoRabbitAdapter.java:96-113 Mongo insert rồi Rabbit send nằm trong transaction SQL (D-05). Chỉ bắt AmqpException, còn cũ bắt mọi Exception (TLS:332-334): một RuntimeException khác từ RabbitTemplate sẽ làm request lỗi, trong khi cũ thì nuốt.
infrastructure/messaging/CogsTaskLogMongoRabbitAdapter.java:115-147 Định dạng document/JSON phải khớp easyposasync (D-07, UNVERIFIED): _class, kiểu Int32, create_time lưu Instant
infrastructure/relational/config/adapter/SendQueueConfigRelationalAdapter.java:43-50 F-logic-1; lấy dòng đầu khi có nhiều dòng business_type, còn cũ ném lỗi do Optional nhận nhiều kết quả
application/cogs/CogsCalculationService.java:65-73 Lỗi ở lô k: các lô trước đã gửi, không thu hồi được (giống cũ)

F-02 Tính giá vốn đồng bộ, gửi cập nhật, ghi lịch sử

  • Điểm vào: cũ CHS:59-124 (gọi từ WHS:1923) → mới application/cogs/CogsComputationService.java:65-91 (gọi từ CogsCalculationService.java:74)
  • Quy tắc: R-06 … R-15, R-17, R-18

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

sequenceDiagram
    participant S as CogsComputationService.calculate (@Transactional, tham gia)
    participant R as CogsRelationalRepository
    participant I as CogsItem
    participant A as CogsTaskLogMongoRabbitAdapter.publishUpdate
    S->>R: findChildren(comId, parentPpuIds)
    S->>S: HashSet(parent) ∪ children → ArrayList → subList 100
    loop mỗi lô
      S->>R: findConvertRates, findDetailRows, findBillRows
      S->>I: aggregate(row, rate(ppu dòng), normFrom) theo master
      S->>I: calculate() mọi item
      S->>A: RS_INOUTWARD_DETAIL (chunk 1000) — phiếu xuất trong kỳ
      S->>A: BILL_PRODUCT (chunk 1000) — item master đã có
    end
    S->>A: RS_INOUTWARD (TreeMap theo id, chunk 1000)
    alt items rỗng
      S-->>S: success(EMPTY_DATA_PROCESSS)
    else
      S->>R: findWarehouseIds, findProductUnitIds
      S->>R: saveHistories (batch 2000)
      S-->>S: success(CALCULATE_COGS_SUCCESSFULLY, results, count = số item chính)
    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 Quan hệ cha-con — CHS:70-76; BaseProductProductUnitRepository.java:236-240 CogsComputationService.java:68-72; CogsRelationalRepository.java:48-51,126-136 KHỚP
2 new HashSet(parent) + values().forEach(addAll) + splitList 100 — CHS:78-80; BaseCommon.java:1707-1717 CogsComputationService.java:73-78 KHỚP (cùng cấu trúc JDK, D-04)
3 Tỉ lệ quy đổi, null → 1, trùng lấy đầu — CHS:88-94; BaseProductProductUnitRepository.java:264-267 CogsComputationService.java:95,210-212; CogsRelationalRepository.java:53-56,138-150 KHỚP
4 SQL dòng phiếu / hoá đơn — easyposbase:.../repositories/BaseCogsHistoryRepository.java:22-66 CogsRelationalRepository.java:59-85,152-197 KHỚP (nguyên văn; không lọc status: D-11)
5 Gộp theo master, val/qty, đầu kỳ/trong kỳ — CHS:135-140; easyposbase:.../dto/cogsHistory/CogsItem.java:65-84 CogsComputationService.java:111-114; domain/cogs/model/CogsItem.java:45-59,119-131 KHỚP
6 Tính lại mọi item, scale 6 HALF_UP — CHS:142; CogsItem.java:38-48 (cũ) CogsComputationService.java:115; CogsItem.java:62-71 KHỚP
7 Update phiếu xuất trong kỳ + wardDelta dùng chung + chunk 1000 — CHS:144-168; CogsItem.java:86-100 (cũ) CogsComputationService.java:116-146; CogsItem.java:80-95 KHỚP (giá vốn dở dang giữa các lô: D-04)
8 Update dòng hoá đơn — CHS:183-209 CogsComputationService.java:148-172 KHỚP (D-04)
9 Delta phiếu sắp theo id — CHS:171-181 CogsComputationService.java:174-184 KHỚP
10 Item rỗng → EMPTY_DATA_PROCESSS — CHS:110 CogsComputationService.java:80-82 KHỚP
11 Lọc item chính, kho (bỏ null, giữ trùng), product_unit, mỗi (item, kho) một dòng — CHS:112-119,251-291 CogsComputationService.java:83-87,186-208; CogsRelationalRepository.java:87-95,199-237 KHỚP (trùng kho theo lô: D-12)
12 INSERT cogs_history batch 2000, Timestamp.from(instant), create_time = now — CHS:656-669; easyposbase:.../BaseCogsHistoryRepositoryCustomImpl.java:34-67 CogsRelationalRepository.java:97-102,239-269 KHÁC có chủ đích (D-09: giờ treo tường VN)
13 Response count = số item — CHS:123 CogsComputationService.java:88-90 KHỚP (định dạng D-02)
14 Mỗi task log: kiểm config + Mongo + Rabbit cogs-update-async — CHS:211-223; TLS:121-130,337-388 CogsTaskLogMongoRabbitAdapter.java:91-113 KHÁC có chủ đích (D-07, D-09, D-10); F-logic-1

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ú
product_product_unit đọc quan hệ, tỉ lệ, product_unit như cũ KHỚP
rs_inoutward(_detail) đọc ≤ toDate; ghi gián tiếp qua async như cũ KHỚP (D-07, D-11)
bill, bill_product đọc trong kỳ; ghi gián tiếp như cũ KHỚP
inventory đọc kho theo ppu như cũ KHỚP (D-12)
cogs_history INSERT trong transaction, sau task log như cũ KHỚP (D-09)
Mongo + RabbitMQ cogs-update-async mỗi chunk một document + message, ngay như cũ D-05, D-07

Transaction, khoá, idempotency, tenant

  • Ranh giới transaction: cũ: calculateByPpuIds @Transactional tham gia transaction của WHS → mới: CogsComputationService.calculate @Transactional tham gia CogsCalculationService, gọi qua bean khác nên không bị self-invocation. JdbcTemplate dựng từ cùng DataSource (cùng mẫu với các adapter khác trong repo) nên dùng chung connection của transaction.
  • Khoá / cập nhật nguyên tử: không có ở cả hai. Hai request song song cùng ppu đều ghi cogs_history và gửi update như cũ.
  • Idempotency, thời điểm phát: task log gửi trước INSERT cogs_history và trước commit. Nếu INSERT lỗi thì task log đã gửi vẫn còn (D-05). Phía tiêu thụ giữ nguyên (status = 1 bỏ qua).
  • Lọc comId: mọi SQL đều có com_id (rio.com_id, b.com_id, inventory.com_id, ppu.com_id), như cũ. Truy vấn theo lô 100, không có N+1.

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

Không có.

Dev cần chú ý khi review

Vị trí Vì sao
application/cogs/CogsComputationService.java:73-78 Thứ tự HashSet/HashMap quyết định ppu rơi vào lô nào, từ đó quyết định số tiền gửi cho phiếu xuất/hoá đơn (D-04). Không được đổi sang LinkedHashSet/sort.
application/cogs/CogsComputationService.java:116-127 wardDeltas dùng chung cho mọi lô, delta = amount − oldAmount. Đây là số tiền phiếu được cộng ở phía async.
application/cogs/CogsComputationService.java:131-146,156-168 Nhánh bỏ qua khi master chưa có item (D-04). Các phép nhân không làm tròn như cũ.
infrastructure/relational/cogs/adapter/CogsRelationalRepository.java:253-269 from_date/to_date/create_time ghi theo giờ treo tường VN (D-09, UNVERIFIED). Một now cho cả lần gọi, cũ thì mỗi dòng một now(), chênh vài micro giây.
infrastructure/relational/cogs/adapter/CogsRelationalRepository.java:59-85 Native SQL chỉ kiểm bằng H2 (K-13). Cần chạy thử trên MSSQL.

Nguồn của trang này

  • Phân tích luồng migrations/inventory/cogs-calculate/verify/round-1/flow-analysis.md vòng 1 · sha256 3d49a8870463

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