fix: preserve component detail spu on stock conflicts
This commit is contained in:
parent
e4809ef843
commit
7f41d0bca5
@ -49,6 +49,7 @@ jest.mock('../../repositories', () => ({
|
||||
},
|
||||
intakeNonIntegratedProductRepository: {
|
||||
listActive: jest.fn(),
|
||||
findBySpu: jest.fn(),
|
||||
updatePayloadByUser: jest.fn(),
|
||||
updateAttachmentPayloadByUser: jest.fn(),
|
||||
},
|
||||
@ -173,6 +174,7 @@ describe('assetCenterService', () => {
|
||||
mockedAssetVariantRepository.findActiveBySeriesCode.mockResolvedValue([] as never)
|
||||
mockedAssetVariantRepository.releaseDeletedUniqueKeys.mockResolvedValue(undefined as never)
|
||||
mockedIntakeNonIntegratedProductRepository.listActive.mockResolvedValue([] as never)
|
||||
mockedIntakeNonIntegratedProductRepository.findBySpu.mockResolvedValue(null as never)
|
||||
mockedIntakeNonIntegratedProductRepository.updatePayloadByUser.mockResolvedValue({} as never)
|
||||
mockedIntakeNonIntegratedProductRepository.updateAttachmentPayloadByUser.mockResolvedValue({} as never)
|
||||
mockedSubstrateRepository.findById.mockResolvedValue({
|
||||
@ -365,6 +367,90 @@ describe('assetCenterService', () => {
|
||||
}
|
||||
})
|
||||
|
||||
it('preserves the persisted component detail SPU when the configured SPU is occupied by stock data', async () => {
|
||||
const syncSpy = jest
|
||||
.spyOn(intakeNonIntegratedProductService, 'syncSeriesComponentDetailProductForSystem')
|
||||
.mockResolvedValue(undefined)
|
||||
const configuredSeries = {
|
||||
...defaultAssetSeries,
|
||||
metadata: {
|
||||
componentSpu: 'DNZ0384',
|
||||
finishedProductSpu: 'DNZ0385',
|
||||
},
|
||||
}
|
||||
mockedAssetSeriesRepository.findById.mockResolvedValueOnce(configuredSeries as never)
|
||||
mockedIntakeNonIntegratedProductRepository.listActive.mockResolvedValueOnce([
|
||||
{
|
||||
id: 'DBZ-SPJ-1780539433902',
|
||||
spu: 'PJ0039',
|
||||
brand: '其他品牌-普通大货',
|
||||
updatedBy: 'user-1',
|
||||
payload: {
|
||||
id: 'DBZ-SPJ-1780539433902',
|
||||
spu: 'PJ0039',
|
||||
productCode: 'PJ0039',
|
||||
productDevelopmentKind: 'series',
|
||||
metadata: {
|
||||
componentDetailType: 'asset-series-components',
|
||||
sourceSeriesCode: 'DBZ',
|
||||
},
|
||||
openingReference: {
|
||||
productName: '单板桌 部件开发明细',
|
||||
temporaryCode: 'DBZ-SPJ',
|
||||
},
|
||||
skuItems: [],
|
||||
},
|
||||
},
|
||||
] as never)
|
||||
mockedIntakeNonIntegratedProductRepository.findBySpu.mockResolvedValueOnce({
|
||||
id: 'jst-stock-1c617912f7581c50',
|
||||
spu: 'DNZ0384',
|
||||
brand: '其他品牌-普通大货',
|
||||
} as never)
|
||||
mockedAssetVariantRepository.findActiveBySeriesCode.mockResolvedValueOnce([] as never)
|
||||
|
||||
try {
|
||||
const result = await assetCenterService.ensureSeriesComponentDetailProduct(
|
||||
configuredSeries.id,
|
||||
{ id: 'user-2' } as never,
|
||||
)
|
||||
|
||||
expect(result).toMatchObject({
|
||||
productId: 'DBZ-SPJ-1780539433902',
|
||||
spu: 'DNZ0384',
|
||||
componentSpu: 'DNZ0384',
|
||||
finishedProductSpu: 'DNZ0385',
|
||||
created: false,
|
||||
})
|
||||
expect(mockedIntakeNonIntegratedProductRepository.findBySpu).toHaveBeenCalledWith(
|
||||
'DNZ0384',
|
||||
'DBZ-SPJ-1780539433902',
|
||||
'其他品牌-普通大货',
|
||||
)
|
||||
expect(syncSpy).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
productId: 'DBZ-SPJ-1780539433902',
|
||||
updatedBy: 'user-2',
|
||||
productInput: expect.objectContaining({
|
||||
id: 'DBZ-SPJ-1780539433902',
|
||||
spu: 'PJ0039',
|
||||
productCode: 'DNZ0384',
|
||||
metadata: expect.objectContaining({
|
||||
componentSpu: 'DNZ0384',
|
||||
finishedProductSpu: 'DNZ0385',
|
||||
sourceSeriesCode: 'DBZ',
|
||||
}),
|
||||
openingReference: expect.objectContaining({
|
||||
temporaryCode: '',
|
||||
}),
|
||||
}),
|
||||
}),
|
||||
)
|
||||
} finally {
|
||||
syncSpy.mockRestore()
|
||||
}
|
||||
})
|
||||
|
||||
it('配置部件SPU后允许按该SPU保存部件型号和规格款', async () => {
|
||||
const customSeries = {
|
||||
...defaultAssetSeries,
|
||||
|
||||
@ -1080,8 +1080,9 @@ function buildSeriesComponentDetailProductPayload(input: {
|
||||
}
|
||||
|
||||
function buildSeriesComponentDetailProductPayloadFromExistingRecord(input: {
|
||||
record: { id: string; payload: Prisma.JsonValue }
|
||||
record: { id: string; payload: Prisma.JsonValue; spu?: string | null }
|
||||
series: AssetSeriesDTO
|
||||
preservePersistedSpu?: boolean
|
||||
}): Record<string, unknown> {
|
||||
const payload = isRecord(input.record.payload) ? input.record.payload : {}
|
||||
const metadata = isRecord(payload.metadata) ? payload.metadata : {}
|
||||
@ -1093,6 +1094,11 @@ function buildSeriesComponentDetailProductPayloadFromExistingRecord(input: {
|
||||
const productName = buildSeriesComponentProductName(input.series)
|
||||
const existingPayloadSpu =
|
||||
typeof payload.spu === 'string' ? payload.spu.trim().toUpperCase() : ''
|
||||
const existingRecordSpu =
|
||||
typeof input.record.spu === 'string' ? input.record.spu.trim().toUpperCase() : ''
|
||||
const persistedSpu = input.preservePersistedSpu
|
||||
? existingPayloadSpu || existingRecordSpu || spu
|
||||
: spu
|
||||
const existingComponentSpu =
|
||||
typeof metadata.componentSpu === 'string'
|
||||
? metadata.componentSpu.trim().toUpperCase()
|
||||
@ -1115,7 +1121,7 @@ function buildSeriesComponentDetailProductPayloadFromExistingRecord(input: {
|
||||
componentSpu: spu,
|
||||
finishedProductSpu,
|
||||
},
|
||||
spu,
|
||||
spu: persistedSpu,
|
||||
productCode: spu,
|
||||
openingReference: {
|
||||
...openingReference,
|
||||
@ -2474,6 +2480,13 @@ class AssetCenterService {
|
||||
const existingSummary = readSeriesComponentDetailSummaryFromRecord(existingRecord, false)
|
||||
const existingRecordSpu = existingRecord.spu.trim().toUpperCase()
|
||||
const existingSummarySpu = existingSummary?.spu.trim().toUpperCase() ?? existingRecordSpu
|
||||
const conflictingSpuRecord = await intakeNonIntegratedProductRepository.findBySpu(
|
||||
spu,
|
||||
existingRecord.id,
|
||||
typeof existingRecord.brand === 'string' ? existingRecord.brand : undefined,
|
||||
)
|
||||
const preservePersistedSpu = Boolean(conflictingSpuRecord)
|
||||
const expectedPersistedSpu = preservePersistedSpu ? existingRecordSpu : spu
|
||||
const existingComponentSpu = existingSummary?.componentSpu ?? null
|
||||
const existingFinishedProductSpu = existingSummary?.finishedProductSpu ?? null
|
||||
const payload = isRecord(existingRecord.payload) ? existingRecord.payload : null
|
||||
@ -2498,8 +2511,8 @@ class AssetCenterService {
|
||||
)
|
||||
|
||||
const alreadySynced =
|
||||
existingRecordSpu === spu &&
|
||||
existingSummarySpu === spu &&
|
||||
existingRecordSpu === expectedPersistedSpu &&
|
||||
existingSummarySpu === expectedPersistedSpu &&
|
||||
existingComponentSpu === spu &&
|
||||
existingFinishedProductSpu === finishedProductSpu &&
|
||||
!existingTemporaryCodeIsSpu
|
||||
@ -2510,6 +2523,7 @@ class AssetCenterService {
|
||||
productInput: buildSeriesComponentDetailProductPayloadFromExistingRecord({
|
||||
record: existingRecord,
|
||||
series: input.series,
|
||||
preservePersistedSpu,
|
||||
}),
|
||||
updatedBy: updatedById,
|
||||
})
|
||||
@ -2678,6 +2692,13 @@ class AssetCenterService {
|
||||
const existingSummary = readSeriesComponentDetailSummaryFromRecord(existingRecord, false)
|
||||
const existingRecordSpu = existingRecord.spu.trim().toUpperCase()
|
||||
const existingSummarySpu = existingSummary?.spu.trim().toUpperCase() ?? existingRecordSpu
|
||||
const conflictingSpuRecord = await intakeNonIntegratedProductRepository.findBySpu(
|
||||
spu,
|
||||
existingRecord.id,
|
||||
typeof existingRecord.brand === 'string' ? existingRecord.brand : undefined,
|
||||
)
|
||||
const preservePersistedSpu = Boolean(conflictingSpuRecord)
|
||||
const expectedPersistedSpu = preservePersistedSpu ? existingRecordSpu : spu
|
||||
const existingComponentSpu = existingSummary?.componentSpu ?? null
|
||||
const existingFinishedProductSpu = existingSummary?.finishedProductSpu ?? null
|
||||
const payload = isRecord(existingRecord.payload) ? existingRecord.payload : null
|
||||
@ -2701,8 +2722,8 @@ class AssetCenterService {
|
||||
.some((item) => item.trim().toUpperCase() === existingTemporaryCode),
|
||||
)
|
||||
if (
|
||||
existingRecordSpu !== spu ||
|
||||
existingSummarySpu !== spu ||
|
||||
existingRecordSpu !== expectedPersistedSpu ||
|
||||
existingSummarySpu !== expectedPersistedSpu ||
|
||||
existingComponentSpu !== spu ||
|
||||
existingFinishedProductSpu !== finishedProductSpu ||
|
||||
existingTemporaryCodeIsSpu
|
||||
@ -2712,6 +2733,7 @@ class AssetCenterService {
|
||||
productInput: buildSeriesComponentDetailProductPayloadFromExistingRecord({
|
||||
record: existingRecord,
|
||||
series,
|
||||
preservePersistedSpu,
|
||||
}),
|
||||
updatedBy: user.id,
|
||||
})
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user