fix(intake): isolate basic info confirmation by batch

This commit is contained in:
WuYongJie 2026-08-26 16:23:46 +08:00
parent d0ddbb6ccf
commit 71e746b5f5
4 changed files with 145 additions and 1 deletions

View File

@ -83,6 +83,7 @@ describe("useNonIntegratedDocumentActionControllers", () => {
},
documentState: {
activeDocumentWorkspaceCategory: "basicInfo",
activeWorkflowBatchNo: 2,
documentWorkspaceApprovedAt: {},
documentWorkspaceConfirmations: {},
selectedUploadFileIds: new Set(),
@ -148,6 +149,11 @@ describe("useNonIntegratedDocumentActionControllers", () => {
});
expect(result.current.basicInfoConfirmationAction).toBeTruthy();
expect(result.current.documentWorkspaceConfirmationAction).toBeTruthy();
expect(
jest.mocked(useNonIntegratedWorkflowConfirmActionController),
).toHaveBeenCalledWith(
expect.objectContaining({ activeWorkflowBatchNo: 2 }),
);
act(() => {
expect(

View File

@ -185,6 +185,7 @@ export function useNonIntegratedDocumentActionControllers({
});
const workflowConfirmActions =
useNonIntegratedWorkflowConfirmActionController({
activeWorkflowBatchNo: documentState.activeWorkflowBatchNo,
basicInfoHasContent: documentDerived.basicInfoHasContent,
basicInfoWorkspaceCategory:
NON_INTEGRATED_BASIC_INFO_WORKSPACE_CATEGORY,

View File

@ -0,0 +1,132 @@
import { act, renderHook } from "@testing-library/react";
import { NON_INTEGRATED_BASIC_INFO_WORKSPACE_CATEGORY } from "./core/nonIntegratedStorage";
import type { NonIntegratedSkuItem } from "./core/nonIntegratedStorage";
import { useNonIntegratedWorkflowConfirmActionController } from "./useNonIntegratedWorkflowConfirmActionController";
function createSkuItem(
overrides: Partial<NonIntegratedSkuItem>,
): NonIntegratedSkuItem {
return {
id: "sku-1",
model: "XG0012K01",
skuCode: "XG001254",
barcode: "XG001254N160V01",
setCount: "1",
specName: "款式一 100/17/130 珍珠白色",
size: "100/17/130",
color: "珍珠白色",
material: "12+15密度板",
boardMaterialType: "非ENF级",
versionNo: "V01",
attributeCode: "A",
drawingId: "XG0012K01AV01",
installMethod: "整装",
executeStandard: "T/CZFA 0001-2025",
nationalStandardCompliant: "否",
batchNo: 2,
...overrides,
} as NonIntegratedSkuItem;
}
function createControllerParams({
activeWorkflowBatchNo = 2,
derivedSkuItems,
}: {
activeWorkflowBatchNo?: number;
derivedSkuItems: NonIntegratedSkuItem[];
}) {
return {
activeWorkflowBatchNo,
basicInfoHasContent: true,
basicInfoWorkspaceCategory: NON_INTEGRATED_BASIC_INFO_WORKSPACE_CATEGORY,
derivedSkuItems,
documentWorkspaceApprovedAt: {},
documentWorkspaceConfirmations: {},
documentWorkspaceCountByCategory: {},
documentWorkspaceRevisionSignatureRef: { current: null },
effectiveSelectedReviewRoundId: "",
isReadOnly: false,
isWorkflowNodeConfirmed: jest.fn(() => false),
persistEditedProduct: jest.fn(async () => true),
reviewRounds: [],
setDocumentWorkspaceApprovedAt: jest.fn(),
setDocumentWorkspaceConfirmations: jest.fn(),
setFinishedSampleShipmentRows: jest.fn(),
setReviewRounds: jest.fn(),
setSaveMessage: jest.fn(),
setSaveMessageType: jest.fn(),
uploadFiles: [],
} as unknown as Parameters<
typeof useNonIntegratedWorkflowConfirmActionController
>[0];
}
describe("useNonIntegratedWorkflowConfirmActionController", () => {
afterEach(() => {
jest.restoreAllMocks();
});
it("confirms the active batch without revalidating a completed historical batch", async () => {
const params = createControllerParams({
derivedSkuItems: [
createSkuItem({
id: "sku-batch-1",
skuCode: "XG001251",
barcode: "XG001251N160V01",
batchNo: 1,
installMethod: "",
}),
createSkuItem({ id: "sku-batch-2" }),
],
});
jest.spyOn(window, "confirm").mockReturnValue(true);
const { result } = renderHook(() =>
useNonIntegratedWorkflowConfirmActionController(params),
);
await act(async () => {
await result.current.handleConfirmWorkflowNode(
NON_INTEGRATED_BASIC_INFO_WORKSPACE_CATEGORY,
);
});
expect(params.persistEditedProduct).toHaveBeenCalledTimes(1);
expect(params.setSaveMessage).not.toHaveBeenCalledWith(
expect.stringContaining("XG001251"),
);
});
it("still blocks confirmation when the active batch itself is incomplete", async () => {
const params = createControllerParams({
derivedSkuItems: [
createSkuItem({
id: "sku-batch-1",
skuCode: "XG001251",
barcode: "XG001251N160V01",
batchNo: 1,
}),
createSkuItem({
id: "sku-batch-2",
installMethod: "",
}),
],
});
const { result } = renderHook(() =>
useNonIntegratedWorkflowConfirmActionController(params),
);
await act(async () => {
await result.current.handleConfirmWorkflowNode(
NON_INTEGRATED_BASIC_INFO_WORKSPACE_CATEGORY,
);
});
expect(params.persistEditedProduct).not.toHaveBeenCalled();
expect(params.setSaveMessage).toHaveBeenCalledWith(
"基础信息未填写完整,SKU XG001254 缺少:安装方式。请补全后再确认。",
);
});
});

View File

@ -51,6 +51,7 @@ type PersistEditedProduct = (params: {
}) => Promise<boolean>;
type UseNonIntegratedWorkflowConfirmActionControllerParams = {
activeWorkflowBatchNo: number;
basicInfoHasContent: boolean;
basicInfoWorkspaceCategory: WorkflowNodeCategory;
derivedSkuItems: NonIntegratedSkuItem[];
@ -84,6 +85,7 @@ type UseNonIntegratedWorkflowConfirmActionControllerParams = {
};
export function useNonIntegratedWorkflowConfirmActionController({
activeWorkflowBatchNo,
basicInfoHasContent,
basicInfoWorkspaceCategory,
derivedSkuItems,
@ -128,8 +130,11 @@ export function useNonIntegratedWorkflowConfirmActionController({
}
if (category === basicInfoWorkspaceCategory) {
const activeBatchSkuItems = derivedSkuItems.filter(
(item) => (item.batchNo || 1) === activeWorkflowBatchNo,
);
const validationMessage = getBasicInfoConfirmationValidationMessage(
derivedSkuItems,
activeBatchSkuItems,
);
if (validationMessage) {
setSaveMessage(validationMessage);