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ớipresentation/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
@TransactionalcủaWHS:66,processMongoTaskLogtham 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ó trongfindPrimaryPpuIds(cảppuvà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ớiapplication/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@Transactionaltham gia transaction của WHS → mới:CogsComputationService.calculate@Transactionaltham giaCogsCalculationService, gọi qua bean khác nên không bị self-invocation. JdbcTemplate dựng từ cùngDataSource(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_historyvà gửi update như cũ. - Idempotency, thời điểm phát: task log gửi trước INSERT
cogs_historyvà 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 = 1bỏ 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. |