From c093c32e1d1b56dff9ec1da315e0b66d27654c94 Mon Sep 17 00:00:00 2001 From: WuYongJie Date: Wed, 26 Aug 2026 16:46:57 +0800 Subject: [PATCH] fix(intake): preserve sku identities on delete --- .../basic-info/skuBatchStateHelpers.test.ts | 97 +++++++++++++++++++ .../basic-info/skuBatchStateHelpers.ts | 12 +-- .../basic-info/useSkuStructureController.ts | 4 +- 3 files changed, 104 insertions(+), 9 deletions(-) create mode 100644 furniture-3d-system/src/app/intake/non-integrated/workspaces/basic-info/skuBatchStateHelpers.test.ts diff --git a/furniture-3d-system/src/app/intake/non-integrated/workspaces/basic-info/skuBatchStateHelpers.test.ts b/furniture-3d-system/src/app/intake/non-integrated/workspaces/basic-info/skuBatchStateHelpers.test.ts new file mode 100644 index 00000000..9f9fc9b2 --- /dev/null +++ b/furniture-3d-system/src/app/intake/non-integrated/workspaces/basic-info/skuBatchStateHelpers.test.ts @@ -0,0 +1,97 @@ +import type { NonIntegratedSkuItem } from "../../nonIntegratedStorage"; +import { deleteSkuItemPreservingIdentities } from "./skuBatchStateHelpers"; +import { createEmptySkuItem } from "./skuBrandHelpers"; + +function createSkuItem( + id: string, + batchNo: number, + skuSequence: number, + overrides: Partial = {}, +) { + return { + ...createEmptySkuItem(), + id, + batchNo, + skuSequence, + skuCode: `XG0012${skuSequence}`, + barcode: `XG0012${skuSequence}N160V01`, + ...overrides, + }; +} + +describe("SKU deletion identity preservation", () => { + it("keeps batch 1 sequence 51 and batch 2 sequence 54 after deleting 52", () => { + const batchOne = createSkuItem("batch-1-51", 1, 51); + const batchTwo52 = createSkuItem("batch-2-52", 2, 52); + const batchTwo54 = createSkuItem("batch-2-54", 2, 54); + + const result = deleteSkuItemPreservingIdentities( + [batchOne, batchTwo52, batchTwo54], + batchTwo52.id, + ); + + expect(result).toEqual({ + nextItems: [batchOne, batchTwo54], + nextBatchCount: 2, + }); + expect(result.nextItems[0]).toBe(batchOne); + expect(result.nextItems[1]).toBe(batchTwo54); + }); + + it("keeps sequences 51 and 52 after deleting imported sequence 54", () => { + const batchOne = createSkuItem("batch-1-51", 1, 51); + const batchTwo52 = createSkuItem("batch-2-52", 2, 52); + const batchTwo54 = createSkuItem("batch-2-54", 2, 54); + + const result = deleteSkuItemPreservingIdentities( + [batchOne, batchTwo52, batchTwo54], + batchTwo54.id, + ); + + expect(result.nextItems).toEqual([batchOne, batchTwo52]); + expect(result.nextBatchCount).toBe(2); + }); + + it("does not renumber batch 1 when the last item in batch 2 is deleted", () => { + const batchOne = createSkuItem("batch-1-51", 1, 51); + const batchTwo = createSkuItem("batch-2-52", 2, 52); + + const result = deleteSkuItemPreservingIdentities( + [batchOne, batchTwo], + batchTwo.id, + ); + + expect(result.nextItems).toEqual([batchOne]); + expect(result.nextItems[0]).toMatchObject({ + id: "batch-1-51", + batchNo: 1, + skuSequence: 51, + skuCode: "XG001251", + barcode: "XG001251N160V01", + }); + expect(result.nextBatchCount).toBe(1); + }); + + it("removes a package group without changing unrelated SKU identities", () => { + const batchOne = createSkuItem("batch-1-51", 1, 51); + const packageA = createSkuItem("batch-2-54-a", 2, 54, { + packageGroupId: "package-54", + packageSuffix: "1/2", + }); + const packageB = createSkuItem("batch-2-54-b", 2, 54, { + packageGroupId: "package-54", + packageSuffix: "2/2", + }); + const batchTwo56 = createSkuItem("batch-2-56", 2, 56); + + const result = deleteSkuItemPreservingIdentities( + [batchOne, packageA, packageB, batchTwo56], + packageA.id, + ); + + expect(result.nextItems).toEqual([batchOne, batchTwo56]); + expect(result.nextItems[0]).toBe(batchOne); + expect(result.nextItems[1]).toBe(batchTwo56); + expect(result.nextBatchCount).toBe(2); + }); +}); diff --git a/furniture-3d-system/src/app/intake/non-integrated/workspaces/basic-info/skuBatchStateHelpers.ts b/furniture-3d-system/src/app/intake/non-integrated/workspaces/basic-info/skuBatchStateHelpers.ts index c60ed790..1fbc20c3 100644 --- a/furniture-3d-system/src/app/intake/non-integrated/workspaces/basic-info/skuBatchStateHelpers.ts +++ b/furniture-3d-system/src/app/intake/non-integrated/workspaces/basic-info/skuBatchStateHelpers.ts @@ -1,5 +1,4 @@ import type { NonIntegratedSkuItem } from "../../nonIntegratedStorage"; -import { resequenceSkuItems } from "./skuAutoHelpers"; import { createEmptySkuItem } from "./skuBrandHelpers"; export type SkuBatchSelection = number | "all"; @@ -56,7 +55,7 @@ export function normalizeSkuBatchSelectionAfterDelete( return current >= targetBatchNo ? nextBatchCount : current; } -export function deleteSkuItemAndResequence( +export function deleteSkuItemPreservingIdentities( skuItems: NonIntegratedSkuItem[], targetId: string, ) { @@ -76,16 +75,15 @@ export function deleteSkuItemAndResequence( ? item.packageGroupId !== targetItem.packageGroupId : item.id !== targetId, ); - const normalizedNextItems = resequenceSkuItems( - nextItems.length > 0 ? nextItems : [createEmptySkuItem()], - ); + const remainingItems = + nextItems.length > 0 ? nextItems : [createEmptySkuItem()]; const nextBatchCount = Math.max( 1, - ...normalizedNextItems.map((item) => item.batchNo || 1), + ...remainingItems.map((item) => item.batchNo || 1), ); return { - nextItems: normalizedNextItems, + nextItems: remainingItems, nextBatchCount, }; } diff --git a/furniture-3d-system/src/app/intake/non-integrated/workspaces/basic-info/useSkuStructureController.ts b/furniture-3d-system/src/app/intake/non-integrated/workspaces/basic-info/useSkuStructureController.ts index aa76add5..532a2ba8 100644 --- a/furniture-3d-system/src/app/intake/non-integrated/workspaces/basic-info/useSkuStructureController.ts +++ b/furniture-3d-system/src/app/intake/non-integrated/workspaces/basic-info/useSkuStructureController.ts @@ -5,7 +5,7 @@ import type { import type { NonIntegratedSkuItem } from "../../nonIntegratedStorage"; import { - deleteSkuItemAndResequence, + deleteSkuItemPreservingIdentities, type SkuBatchSelection, } from "./skuBatchStateHelpers"; import { buildSkuItemsAfterSetCountCommit } from "./skuSetCountCommitHelpers"; @@ -65,7 +65,7 @@ export function useSkuStructureController({ return; } - const { nextItems, nextBatchCount } = deleteSkuItemAndResequence( + const { nextItems, nextBatchCount } = deleteSkuItemPreservingIdentities( skuItems, id, );