feat(asset-center): make modular assets immediately available
This commit is contained in:
parent
2e42fb220f
commit
6b4dcbdd31
@ -14,6 +14,7 @@ const assetStatusSchema = z.enum([
|
||||
'AVAILABLE',
|
||||
'DISABLED',
|
||||
])
|
||||
const assetCreationStatusSchema = z.enum(['DRAFT', 'AVAILABLE'])
|
||||
const assetCadImportFamilyModeSchema = z.enum(['existing', 'create'])
|
||||
const singleSubstrateFinishIdsSchema = z
|
||||
.array(z.string().trim().min(1))
|
||||
@ -54,7 +55,7 @@ export const assetFamilyCreateSchema = z.object({
|
||||
compatibleSeriesIds: z.array(z.string().trim().min(1)).optional(),
|
||||
connectionRoles: z.array(z.string().trim().min(1)).optional(),
|
||||
metadata: z.record(z.string(), z.unknown()).optional().nullable(),
|
||||
status: z.enum(['DRAFT']).optional(),
|
||||
status: assetCreationStatusSchema.optional(),
|
||||
})
|
||||
|
||||
export const assetFamilyUpdateSchema = z.object({
|
||||
@ -113,7 +114,7 @@ export const assetVariantCreateSchema = z.object({
|
||||
skuGroupId: z.string().trim().min(1).optional().nullable(),
|
||||
code: z.string().trim().min(1).optional(),
|
||||
name: z.string().trim().min(1),
|
||||
status: z.enum(['DRAFT']).optional(),
|
||||
status: assetCreationStatusSchema.optional(),
|
||||
sizeLabel: z.string().trim().optional(),
|
||||
substrateId: z.string().trim().min(1).optional().nullable(),
|
||||
finishId: z.string().trim().min(1).optional().nullable(),
|
||||
|
||||
@ -3506,7 +3506,7 @@ export default function AssetCenterClient({
|
||||
compatibleSeriesIds: submittedCompatibleSeriesIds,
|
||||
connectionRoles: normalizedSelectedRoles,
|
||||
metadata,
|
||||
status: 'DRAFT',
|
||||
status: 'AVAILABLE',
|
||||
})
|
||||
startTransition(() => {
|
||||
setFamilies((current) => sortAssetFamiliesByCreatedTime([...current, created]))
|
||||
@ -4914,7 +4914,7 @@ export default function AssetCenterClient({
|
||||
assetFamilyId: variantForm.assetFamilyId,
|
||||
skuGroupId: variantForm.skuGroupId || null,
|
||||
name: skuPayload.name,
|
||||
status: 'DRAFT',
|
||||
status: 'AVAILABLE',
|
||||
sizeLabel: skuPayload.sizeLabel || undefined,
|
||||
substrateId: resolvedVariantSubstrateId,
|
||||
finishId: resolvedVariantFinishId,
|
||||
@ -5052,7 +5052,7 @@ export default function AssetCenterClient({
|
||||
skuGroupId: variantForm.skuGroupId || null,
|
||||
code: variantForm.code || undefined,
|
||||
name: skuPayload.name,
|
||||
status: 'DRAFT',
|
||||
status: 'AVAILABLE',
|
||||
sizeLabel: skuPayload.sizeLabel || undefined,
|
||||
substrateId: null,
|
||||
finishId: resolvedVariantFinishId,
|
||||
|
||||
@ -368,7 +368,7 @@ function instantiateLaunchSelectedFamilies(input: {
|
||||
|
||||
const inventoryItem = snapshot.inventory.find((item) => item.familyId === familyId)
|
||||
const variant =
|
||||
input.variantsByFamilyId.get(familyId)?.find((item) => item.status === 'AVAILABLE') ??
|
||||
input.variantsByFamilyId.get(familyId)?.find((item) => item.status !== 'DISABLED') ??
|
||||
input.variantsByFamilyId.get(familyId)?.[0] ??
|
||||
null
|
||||
|
||||
@ -841,7 +841,7 @@ export default function AssistedAssemblyClient({
|
||||
setMaterialFamilies(nextFamilies)
|
||||
setMaterialVariants(
|
||||
nextVariants
|
||||
.filter((variant) => variant.status === 'AVAILABLE')
|
||||
.filter((variant) => variant.status !== 'DISABLED')
|
||||
.map(toRuntimeAssistedAssemblyVariant),
|
||||
)
|
||||
} catch (error) {
|
||||
|
||||
@ -884,7 +884,7 @@ export default async function AssistedAssemblyPage({
|
||||
const sourceVariantIdSet = new Set(initialWorkspace?.nodes.map((node) => node.variantId) ?? [])
|
||||
const selectableVariants = variants.filter(
|
||||
(variant) =>
|
||||
variant.status === 'AVAILABLE' ||
|
||||
variant.status !== 'DISABLED' ||
|
||||
launchSelectedFamilyIds.has(variant.assetFamilyId) ||
|
||||
sourceVariantIdSet.has(variant.id),
|
||||
)
|
||||
|
||||
@ -1502,6 +1502,11 @@ describe("NonIntegratedDetailClient", () => {
|
||||
/>,
|
||||
);
|
||||
|
||||
expect(screen.getByText("商品标签")).toBeInTheDocument();
|
||||
expect(
|
||||
screen.getByRole("combobox", { name: "商品标签" }),
|
||||
).toHaveTextContent("模块化");
|
||||
|
||||
const detailButton = screen
|
||||
.getAllByRole("button", { name: /MKH-DNZ0384K01/ })
|
||||
.find((button) =>
|
||||
@ -1773,6 +1778,10 @@ describe("NonIntegratedDetailClient", () => {
|
||||
"family-packaging",
|
||||
]),
|
||||
);
|
||||
expect(screen.getByText("商品标签")).toBeInTheDocument();
|
||||
expect(
|
||||
screen.getByRole("combobox", { name: "商品标签" }),
|
||||
).toHaveTextContent("模块化");
|
||||
expect(await screen.findByDisplayValue("DBZ-SPJ11")).toBeInTheDocument();
|
||||
expect(screen.getAllByDisplayValue("DBZ-SPJK06").length).toBeGreaterThan(0);
|
||||
});
|
||||
|
||||
@ -42,6 +42,8 @@ export function BasicField({
|
||||
readOnly = false,
|
||||
compact = false,
|
||||
searchableSelect = false,
|
||||
includeEmptyOption = false,
|
||||
clearable = false,
|
||||
onChange,
|
||||
}: {
|
||||
label: string;
|
||||
@ -53,6 +55,8 @@ export function BasicField({
|
||||
readOnly?: boolean;
|
||||
compact?: boolean;
|
||||
searchableSelect?: boolean;
|
||||
includeEmptyOption?: boolean;
|
||||
clearable?: boolean;
|
||||
onChange: (value: string) => void;
|
||||
}) {
|
||||
if (type === "select") {
|
||||
@ -72,6 +76,7 @@ export function BasicField({
|
||||
options={options}
|
||||
placeholder={placeholder}
|
||||
readOnly={readOnly}
|
||||
includeEmptyOption={includeEmptyOption}
|
||||
onChange={onChange}
|
||||
inputClassName={`h-9 w-full rounded-apple-lg border border-apple-separator px-3 pr-9 text-sm text-apple-label-primary outline-none disabled:cursor-not-allowed ${
|
||||
readOnly
|
||||
@ -86,6 +91,8 @@ export function BasicField({
|
||||
options={options}
|
||||
placeholder={placeholder}
|
||||
readOnly={readOnly}
|
||||
includeEmptyOption={includeEmptyOption}
|
||||
clearable={clearable}
|
||||
onChange={onChange}
|
||||
buttonClassName={`h-9 w-full rounded-apple-lg border border-apple-separator px-3 text-sm text-apple-label-primary outline-none disabled:cursor-not-allowed ${
|
||||
readOnly
|
||||
|
||||
@ -10,7 +10,7 @@ import {
|
||||
useState,
|
||||
} from "react";
|
||||
import { createPortal } from "react-dom";
|
||||
import { ChevronDown } from "lucide-react";
|
||||
import { ChevronDown, X } from "lucide-react";
|
||||
|
||||
function getUniqueNonEmptyStrings(
|
||||
values: ReadonlyArray<string | null | undefined>,
|
||||
@ -313,6 +313,7 @@ export function InlineSelect({
|
||||
includeEmptyOption,
|
||||
emptyOptionDisabled = false,
|
||||
showIndicatorWhenReadOnly = false,
|
||||
clearable = false,
|
||||
onChange,
|
||||
}: {
|
||||
ariaLabel: string;
|
||||
@ -328,6 +329,7 @@ export function InlineSelect({
|
||||
includeEmptyOption?: boolean;
|
||||
emptyOptionDisabled?: boolean;
|
||||
showIndicatorWhenReadOnly?: boolean;
|
||||
clearable?: boolean;
|
||||
onChange: (value: string) => void;
|
||||
}) {
|
||||
const listId = useId();
|
||||
@ -397,7 +399,9 @@ export function InlineSelect({
|
||||
if (hasOptions) setIsOpen((current) => !current);
|
||||
}
|
||||
}}
|
||||
className={`flex items-center justify-between gap-2 text-left ${buttonClassName ?? ""}`}
|
||||
className={`flex items-center justify-between gap-2 text-left ${
|
||||
buttonClassName ?? ""
|
||||
} ${clearable && value && !readOnly ? "pr-16" : ""}`}
|
||||
>
|
||||
<span className="min-w-0 flex-1 truncate">
|
||||
{displayValue || placeholder}
|
||||
@ -409,6 +413,19 @@ export function InlineSelect({
|
||||
/>
|
||||
) : null}
|
||||
</button>
|
||||
{clearable && value && !readOnly ? (
|
||||
<button
|
||||
type="button"
|
||||
aria-label={`清空${ariaLabel}`}
|
||||
onMouseDown={(event) => {
|
||||
event.preventDefault();
|
||||
}}
|
||||
onClick={() => onChange("")}
|
||||
className="absolute right-8 top-1/2 flex h-6 w-6 -translate-y-1/2 items-center justify-center rounded-apple-md text-apple-label-secondary transition hover:bg-apple-bg-tertiary hover:text-apple-label-primary"
|
||||
>
|
||||
<X className="h-3.5 w-3.5" aria-hidden="true" />
|
||||
</button>
|
||||
) : null}
|
||||
{hasOptions && isOpen && floatingPosition
|
||||
? createPortal(
|
||||
<div
|
||||
|
||||
@ -343,6 +343,7 @@ export type NonIntegratedSkuItem = {
|
||||
image: string;
|
||||
imageName: string;
|
||||
model: string;
|
||||
productTag?: string;
|
||||
skuCode: string;
|
||||
setCount: string;
|
||||
specName: string;
|
||||
@ -401,6 +402,15 @@ export type NonIntegratedSkuHolePoint = {
|
||||
};
|
||||
|
||||
export const DRAFT_GROUP_MODULAR_SKU_SOURCE = "draft_group_modular_sku";
|
||||
export const DRAFT_GROUP_MODULAR_SERIES_SOURCE = "draft_group_modular_series";
|
||||
export const NON_INTEGRATED_ASSET_SERIES_COMPONENT_SKU_SOURCE =
|
||||
"asset_series_component";
|
||||
export const NON_INTEGRATED_ASSET_VARIANT_SOURCE_TABLE = "asset_variant";
|
||||
export const NON_INTEGRATED_ASSET_SKU_GROUP_SOURCE_TABLE = "asset_sku_group";
|
||||
|
||||
function normalizeSkuSourceMarker(value: unknown) {
|
||||
return normalizeString(value).trim().toLowerCase().replace(/-/g, "_");
|
||||
}
|
||||
|
||||
export function isDraftGroupModularFormalSkuCode(value: unknown) {
|
||||
const normalizedValue = normalizeString(value).trim().toUpperCase();
|
||||
@ -432,6 +442,39 @@ export function resolveDraftGroupModularSkuIdentity(item: {
|
||||
return "";
|
||||
}
|
||||
|
||||
export function isNonIntegratedModularSkuItem(item: {
|
||||
source?: unknown;
|
||||
sourceTable?: unknown;
|
||||
skuCode?: unknown;
|
||||
barcode?: unknown;
|
||||
}) {
|
||||
const source = normalizeSkuSourceMarker(item.source);
|
||||
const sourceTable = normalizeSkuSourceMarker(item.sourceTable);
|
||||
|
||||
return (
|
||||
source === DRAFT_GROUP_MODULAR_SKU_SOURCE ||
|
||||
source === NON_INTEGRATED_ASSET_SERIES_COMPONENT_SKU_SOURCE ||
|
||||
sourceTable === NON_INTEGRATED_ASSET_VARIANT_SOURCE_TABLE ||
|
||||
sourceTable === NON_INTEGRATED_ASSET_SKU_GROUP_SOURCE_TABLE ||
|
||||
Boolean(resolveDraftGroupModularSkuIdentity(item))
|
||||
);
|
||||
}
|
||||
|
||||
export function resolveNonIntegratedSkuProductTag(item: {
|
||||
productTag?: unknown;
|
||||
source?: unknown;
|
||||
sourceTable?: unknown;
|
||||
skuCode?: unknown;
|
||||
barcode?: unknown;
|
||||
}) {
|
||||
return (
|
||||
normalizeString(item.productTag).trim() ||
|
||||
(isNonIntegratedModularSkuItem(item)
|
||||
? NON_INTEGRATED_MODULAR_PRODUCT_TAG
|
||||
: "")
|
||||
);
|
||||
}
|
||||
|
||||
export type NonIntegratedFactoryRow = {
|
||||
skuId: string;
|
||||
confirmed: boolean;
|
||||
|
||||
@ -741,6 +741,25 @@ describe('assetCenterService', () => {
|
||||
})
|
||||
})
|
||||
|
||||
it('creates asset families as available when a creator is present', async () => {
|
||||
await assetCenterService.createFamily({
|
||||
type: 'BOARD',
|
||||
assetSeriesId: defaultAssetSeries.id,
|
||||
code: 'DBZ-SPJK009',
|
||||
name: 'Immediate available family',
|
||||
status: 'DRAFT',
|
||||
createdBy: 'user-creator',
|
||||
})
|
||||
|
||||
expect(mockedAssetFamilyRepository.createWithRelations).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
status: 'AVAILABLE',
|
||||
reviewedAt: expect.any(Date),
|
||||
reviewer: { connect: { id: 'user-creator' } },
|
||||
}),
|
||||
)
|
||||
})
|
||||
|
||||
it('new asset variants use sku groups for item numbers and model codes for model details', async () => {
|
||||
const existingGroups = [
|
||||
{
|
||||
|
||||
@ -40,6 +40,7 @@ import {
|
||||
createEmptyNonIntegratedOpeningReference,
|
||||
createEmptyNonIntegratedPatentApplication,
|
||||
createEmptyNonIntegratedProjectReview,
|
||||
resolveNonIntegratedSkuProductTag,
|
||||
type NonIntegratedProductRecord,
|
||||
type NonIntegratedSkuItem,
|
||||
} from '@/app/intake/non-integrated/nonIntegratedStorage'
|
||||
@ -591,6 +592,10 @@ function createEmptySeriesComponentSkuPayloadItem(
|
||||
image: '',
|
||||
imageName: '',
|
||||
model: '',
|
||||
productTag: resolveNonIntegratedSkuProductTag({
|
||||
source: SERIES_COMPONENT_ASSET_SKU_SOURCE,
|
||||
sourceTable: ASSET_VARIANT_SOURCE_TABLE,
|
||||
}),
|
||||
skuCode: '',
|
||||
setCount: '1',
|
||||
specName: '',
|
||||
@ -639,6 +644,10 @@ function createEmptySeriesComponentSkuGroupPayloadItem(
|
||||
image: '',
|
||||
imageName: '',
|
||||
model: '',
|
||||
productTag: resolveNonIntegratedSkuProductTag({
|
||||
source: SERIES_COMPONENT_ASSET_SKU_SOURCE,
|
||||
sourceTable: ASSET_SKU_GROUP_SOURCE_TABLE,
|
||||
}),
|
||||
skuCode: '',
|
||||
setCount: '1',
|
||||
specName: '',
|
||||
@ -1177,6 +1186,11 @@ function updateSeriesComponentSkuPayloadItemFromVariant(
|
||||
'nationalStandardCompliant',
|
||||
DEFAULT_ASSET_VARIANT_NATIONAL_STANDARD_COMPLIANT,
|
||||
),
|
||||
productTag: resolveNonIntegratedSkuProductTag({
|
||||
...item,
|
||||
source: SERIES_COMPONENT_ASSET_SKU_SOURCE,
|
||||
sourceTable: ASSET_VARIANT_SOURCE_TABLE,
|
||||
}),
|
||||
manufacturer: getVariantSkuContentField(skuContentFields, 'manufacturer', readPayloadString(item, 'manufacturer') || (variant.supplierName ?? '')),
|
||||
manufacturerCode,
|
||||
salesStatus: getVariantSkuContentFieldWithDefault(
|
||||
@ -1324,6 +1338,11 @@ function updateSeriesComponentSkuPayloadItemFromSkuGroup(
|
||||
assetFamilyCode: group.assetFamilyCode,
|
||||
fallback: readPayloadString(nextItem, 'specName') || buildSeriesComponentSkuGroupDisplayCode(group),
|
||||
}),
|
||||
productTag: resolveNonIntegratedSkuProductTag({
|
||||
...nextItem,
|
||||
source: SERIES_COMPONENT_ASSET_SKU_SOURCE,
|
||||
sourceTable: ASSET_SKU_GROUP_SOURCE_TABLE,
|
||||
}),
|
||||
componentDetails: group.variants.map((variant) => ({
|
||||
code: variant.code.trim().toUpperCase(),
|
||||
barcode: resolveSeriesComponentVariantOwnBarcode(variant),
|
||||
@ -1429,6 +1448,11 @@ function updateSeriesComponentSkuPayloadItemFromSkuGroupOnly(
|
||||
DEFAULT_ASSET_VARIANT_SALES_STATUS,
|
||||
),
|
||||
batchNo,
|
||||
productTag: resolveNonIntegratedSkuProductTag({
|
||||
...item,
|
||||
source: SERIES_COMPONENT_ASSET_SKU_SOURCE,
|
||||
sourceTable: ASSET_SKU_GROUP_SOURCE_TABLE,
|
||||
}),
|
||||
image: '',
|
||||
imageName: '',
|
||||
model3dFileName: '',
|
||||
@ -1823,6 +1847,33 @@ function ensureDraftCreationStatus(status?: AssetStatus): AssetStatus {
|
||||
return status
|
||||
}
|
||||
|
||||
function buildImmediateAvailableCreationWorkflow(
|
||||
status: AssetStatus | undefined,
|
||||
actorId: string | null | undefined,
|
||||
): {
|
||||
status: AssetStatus
|
||||
reviewedAt?: Date
|
||||
reviewer?: { connect: { id: string } }
|
||||
} {
|
||||
if (status && status !== 'DRAFT' && status !== 'AVAILABLE') {
|
||||
throw new AppError(ErrorCode.VALIDATION_FAILED, 'New assets can only be created as available.')
|
||||
}
|
||||
|
||||
if (status === 'AVAILABLE' && !actorId) {
|
||||
throw new AppError(ErrorCode.VALIDATION_FAILED, 'Creating available assets requires a creator.')
|
||||
}
|
||||
|
||||
if (!actorId) {
|
||||
return { status: ensureDraftCreationStatus(status) }
|
||||
}
|
||||
|
||||
return {
|
||||
status: 'AVAILABLE',
|
||||
reviewedAt: new Date(),
|
||||
reviewer: { connect: { id: actorId } },
|
||||
}
|
||||
}
|
||||
|
||||
function assertReviewableStatus(status: AssetStatus, action: 'SUBMIT' | 'APPROVE' | 'REJECT'): void {
|
||||
if (action === 'SUBMIT' && status !== 'DRAFT' && status !== 'REJECTED') {
|
||||
throw new AppError(ErrorCode.VALIDATION_FAILED, '当前状态不能提审')
|
||||
@ -3916,6 +3967,7 @@ class AssetCenterService {
|
||||
await ensureFamilyCodeAvailable(code)
|
||||
await ensureCategoryExists(input.productCategoryId ?? null)
|
||||
const compatibleSeriesIds = [series.id]
|
||||
const creationWorkflow = buildImmediateAvailableCreationWorkflow(input.status, input.createdBy)
|
||||
|
||||
const created = await assetFamilyRepository.createWithRelations({
|
||||
type: input.type,
|
||||
@ -3932,7 +3984,9 @@ class AssetCenterService {
|
||||
: undefined,
|
||||
connectionRoles: input.connectionRoles ?? [],
|
||||
metadata: toJsonValue(input.metadata),
|
||||
status: ensureDraftCreationStatus(input.status),
|
||||
status: creationWorkflow.status,
|
||||
reviewedAt: creationWorkflow.reviewedAt,
|
||||
reviewer: creationWorkflow.reviewer,
|
||||
productCategory: input.productCategoryId
|
||||
? { connect: { id: input.productCategoryId } }
|
||||
: undefined,
|
||||
@ -4620,6 +4674,7 @@ class AssetCenterService {
|
||||
barcode: input.barcode,
|
||||
})
|
||||
await ensureVariantBarcodeAvailable(commercialFields.barcode, undefined, skuGroup.id)
|
||||
const creationWorkflow = buildImmediateAvailableCreationWorkflow(input.status, input.createdBy)
|
||||
|
||||
const created = await assetVariantRepository.createWithRelations({
|
||||
assetFamily: { connect: { id: input.assetFamilyId } },
|
||||
@ -4627,7 +4682,9 @@ class AssetCenterService {
|
||||
name,
|
||||
identityKey,
|
||||
assetType: family.type,
|
||||
status: ensureDraftCreationStatus(input.status),
|
||||
status: creationWorkflow.status,
|
||||
reviewedAt: creationWorkflow.reviewedAt,
|
||||
reviewer: creationWorkflow.reviewer,
|
||||
sizeLabel: trimOrNull(input.sizeLabel),
|
||||
substrate: input.substrateId ? { connect: { id: input.substrateId } } : undefined,
|
||||
finish: resolvedFinishId ? { connect: { id: resolvedFinishId } } : undefined,
|
||||
|
||||
@ -4,12 +4,14 @@ import {
|
||||
NON_INTEGRATED_BASIC_INFO_WORKSPACE_CATEGORY,
|
||||
NON_INTEGRATED_DEFAULT_BRAND,
|
||||
NON_INTEGRATED_DUPLICATE_SPU_MESSAGE,
|
||||
NON_INTEGRATED_MODULAR_PRODUCT_TAG,
|
||||
NON_INTEGRATED_WORKFLOW_NODE_CATEGORIES,
|
||||
applyBrandPrefixToNonIntegratedCode,
|
||||
buildNonIntegratedProductId,
|
||||
createDefaultDocumentWorkspaceConfirmations as createSharedDocumentWorkspaceConfirmations,
|
||||
normalizeNonIntegratedBrand,
|
||||
normalizeNonIntegratedProductRecord,
|
||||
resolveNonIntegratedSkuProductTag,
|
||||
resolveDraftGroupModularSkuIdentity,
|
||||
resolveNonIntegratedPersistedSpu,
|
||||
stripNonIntegratedBrandPrefix,
|
||||
@ -284,6 +286,7 @@ const BASIC_INFO_FIELD_KEYS = [
|
||||
'purchaser',
|
||||
'previewImage',
|
||||
'previewImageName',
|
||||
'productTag',
|
||||
'productCode',
|
||||
'size',
|
||||
'color',
|
||||
@ -485,6 +488,11 @@ function assignFormalSpuToSkuItems(
|
||||
skuCode,
|
||||
barcode,
|
||||
versionNo,
|
||||
productTag: resolveNonIntegratedSkuProductTag({
|
||||
...item,
|
||||
skuCode,
|
||||
barcode,
|
||||
}),
|
||||
}
|
||||
})
|
||||
}
|
||||
@ -2179,6 +2187,13 @@ function buildStructuredSkuItemOverlay(
|
||||
image: readStructuredText(row.image) || legacy?.image || '',
|
||||
imageName: readStructuredText(row.imageName) || legacy?.imageName || '',
|
||||
model: readStructuredText(row.model),
|
||||
productTag: resolveNonIntegratedSkuProductTag({
|
||||
...legacy,
|
||||
source,
|
||||
sourceTable: readStructuredText(row.sourceTable),
|
||||
skuCode: modularSkuIdentity || skuCode,
|
||||
barcode: modularSkuIdentity || barcode,
|
||||
}),
|
||||
skuCode: modularSkuIdentity || skuCode,
|
||||
setCount: legacy?.setCount || '1',
|
||||
specName: readStructuredText(row.specName),
|
||||
@ -3445,6 +3460,15 @@ function withSeriesProductDisplayName(
|
||||
}
|
||||
}
|
||||
|
||||
function withDefaultModularProductTag(product: SharedNonIntegratedProductRecord) {
|
||||
return Object.prototype.hasOwnProperty.call(product, 'productTag')
|
||||
? product
|
||||
: {
|
||||
...product,
|
||||
productTag: NON_INTEGRATED_MODULAR_PRODUCT_TAG,
|
||||
}
|
||||
}
|
||||
|
||||
async function resolveDraftGroupSeriesName(sourceDraftGroupId: unknown) {
|
||||
const draftGroupId = normalizeSeriesDisplayPart(sourceDraftGroupId)
|
||||
if (!draftGroupId) return null
|
||||
@ -3483,12 +3507,14 @@ async function hydrateSeriesProductDisplayName(
|
||||
)
|
||||
const baseSeriesName = productName.replace(/-部件$/, '')
|
||||
|
||||
return productName
|
||||
const nextProduct = productName
|
||||
? withSeriesProductDisplayName(product, productName, {
|
||||
sourceSeriesName: baseSeriesName,
|
||||
sourceSeriesCode,
|
||||
})
|
||||
: product
|
||||
|
||||
return withDefaultModularProductTag(nextProduct)
|
||||
}
|
||||
|
||||
if (
|
||||
@ -3514,12 +3540,14 @@ async function hydrateSeriesProductDisplayName(
|
||||
const resolvedSourceSeriesCode =
|
||||
resolvedDraftGroupSeriesName?.sourceSeriesCode || sourceSeriesCode
|
||||
|
||||
return productName
|
||||
const nextProduct = productName
|
||||
? withSeriesProductDisplayName(product, productName, {
|
||||
sourceSeriesName: productName,
|
||||
sourceSeriesCode: resolvedSourceSeriesCode,
|
||||
})
|
||||
: product
|
||||
|
||||
return withDefaultModularProductTag(nextProduct)
|
||||
}
|
||||
|
||||
async function hydrateSeriesProductDisplayNames(
|
||||
@ -3779,6 +3807,10 @@ function createEmptyAssetSeriesComponentSkuItem(
|
||||
image: '',
|
||||
imageName: '',
|
||||
model: '',
|
||||
productTag: resolveNonIntegratedSkuProductTag({
|
||||
source: SERIES_COMPONENT_ASSET_SKU_SOURCE,
|
||||
sourceTable: ASSET_VARIANT_SOURCE_TABLE,
|
||||
}),
|
||||
skuCode: '',
|
||||
setCount: '1',
|
||||
specName: '',
|
||||
@ -3827,6 +3859,10 @@ function createEmptyAssetSeriesComponentSkuGroupItem(
|
||||
image: '',
|
||||
imageName: '',
|
||||
model: '',
|
||||
productTag: resolveNonIntegratedSkuProductTag({
|
||||
source: SERIES_COMPONENT_ASSET_SKU_SOURCE,
|
||||
sourceTable: ASSET_SKU_GROUP_SOURCE_TABLE,
|
||||
}),
|
||||
skuCode: '',
|
||||
setCount: '1',
|
||||
specName: '',
|
||||
@ -4084,6 +4120,11 @@ function updateAssetSeriesComponentSkuItemFromSkuGroupOnly(
|
||||
id: `asset-sku-group-${group.id}`,
|
||||
skuSequence,
|
||||
model,
|
||||
productTag: resolveNonIntegratedSkuProductTag({
|
||||
...item,
|
||||
source: SERIES_COMPONENT_ASSET_SKU_SOURCE,
|
||||
sourceTable: ASSET_SKU_GROUP_SOURCE_TABLE,
|
||||
}),
|
||||
skuCode: group.code,
|
||||
barcode,
|
||||
setCount: getVariantSkuContentField(fields, 'setCount', readPayloadString(itemRecord, 'setCount') || '1'),
|
||||
@ -4289,6 +4330,11 @@ function updateAssetSeriesComponentSkuItemFromVariant(
|
||||
'nationalStandardCompliant',
|
||||
DEFAULT_ASSET_VARIANT_NATIONAL_STANDARD_COMPLIANT,
|
||||
),
|
||||
productTag: resolveNonIntegratedSkuProductTag({
|
||||
...item,
|
||||
source: SERIES_COMPONENT_ASSET_SKU_SOURCE,
|
||||
sourceTable: ASSET_VARIANT_SOURCE_TABLE,
|
||||
}),
|
||||
manufacturer: getVariantSkuContentField(
|
||||
skuContentFields,
|
||||
'manufacturer',
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user