145 lines
4.8 KiB
JavaScript
145 lines
4.8 KiB
JavaScript
'use strict';
|
||
|
||
const test = require('node:test');
|
||
const assert = require('node:assert/strict');
|
||
const fs = require('node:fs');
|
||
const path = require('node:path');
|
||
const {
|
||
_test: {
|
||
buildProductCodeRequest,
|
||
buildProductCodeRequestHash,
|
||
normalizeProductCodeConfig,
|
||
normalizeProductCodeMeta,
|
||
validateProductCodeResponse,
|
||
},
|
||
} = require('../src/services/planningSelectionFissionService');
|
||
|
||
const remoteMeta = {
|
||
operationCenters: [{ name: '运营一部' }],
|
||
categories: [{ name: '住宅家具' }],
|
||
productTagOptionGroups: [
|
||
{ key: 'taxStatus', options: ['含税'] },
|
||
{ key: 'invoiceType', options: ['专票'] },
|
||
{ key: 'installationService', options: ['不安装'] },
|
||
{ key: 'installationMode', options: ['无需安装'] },
|
||
],
|
||
};
|
||
|
||
const configInput = {
|
||
operationCenter: '运营一部',
|
||
categoryName: '住宅家具',
|
||
taxStatus: '含税',
|
||
invoiceType: '专票',
|
||
installationService: '不安装',
|
||
installationMode: '无需安装',
|
||
};
|
||
|
||
const rows = [
|
||
{
|
||
skuCode: 'SOURCE-SKU-02',
|
||
selectedSkuName: '胡桃色 120cm 茶几',
|
||
colorName: '胡桃色',
|
||
colorSpec: '胡桃色;120cm',
|
||
lengthCm: 120,
|
||
widthCm: 60,
|
||
heightCm: 45,
|
||
weight: 20,
|
||
},
|
||
{
|
||
skuCode: 'SOURCE-SKU-01',
|
||
selectedSkuName: '原木色 90cm 茶几',
|
||
colorName: '原木色',
|
||
colorSpec: '原木色;90cm',
|
||
lengthCm: 90,
|
||
widthCm: 50,
|
||
heightCm: 42,
|
||
weight: 16,
|
||
},
|
||
];
|
||
|
||
test('product-code meta and required options are normalized from the remote contract', () => {
|
||
assert.deepEqual(normalizeProductCodeMeta(remoteMeta), {
|
||
operationCenters: ['运营一部'],
|
||
categories: ['住宅家具'],
|
||
tagOptions: {
|
||
taxStatus: ['含税'],
|
||
invoiceType: ['专票'],
|
||
installationService: ['不安装'],
|
||
installationMode: ['无需安装'],
|
||
},
|
||
});
|
||
assert.deepEqual(normalizeProductCodeConfig(configInput, remoteMeta), configInput);
|
||
});
|
||
|
||
test('product-code request preserves canonical SKU order and confirmed SKU names', () => {
|
||
const request = buildProductCodeRequest(configInput, rows, { name: '测试运营' });
|
||
assert.equal(request.skuItems.length, 2);
|
||
assert.equal(request.skuItems[0].productName, '胡桃色 120cm 茶几');
|
||
assert.equal(request.skuItems[1].productName, '原木色 90cm 茶几');
|
||
assert.deepEqual(request.skuItems[0], {
|
||
productName: '胡桃色 120cm 茶几',
|
||
colorSpec: '胡桃色;120cm',
|
||
lengthCm: 120,
|
||
widthCm: 60,
|
||
heightCm: 45,
|
||
weight: 20,
|
||
});
|
||
});
|
||
|
||
test('product-code result must match SKU count, order and exact confirmed names', () => {
|
||
const response = {
|
||
styleCode: 'STYLE-001',
|
||
items: [
|
||
{ productCode: 'SKU-001-01', productName: rows[0].selectedSkuName, colorSpec: rows[0].colorSpec },
|
||
{ productCode: 'SKU-001-02', productName: rows[1].selectedSkuName, colorSpec: rows[1].colorSpec },
|
||
],
|
||
};
|
||
assert.deepEqual(validateProductCodeResponse(response, rows).map((row) => row.productCode), [
|
||
'SKU-001-01',
|
||
'SKU-001-02',
|
||
]);
|
||
assert.throws(
|
||
() => validateProductCodeResponse({
|
||
...response,
|
||
items: [response.items[1], response.items[0]],
|
||
}, rows),
|
||
(error) => error.code === 'PRODUCT_CODE_NAME_MISMATCH' && error.indeterminate === true
|
||
);
|
||
});
|
||
|
||
test('product-code request hash changes when SKU order or final name changes', () => {
|
||
const request = buildProductCodeRequest(configInput, rows, { name: '测试运营' });
|
||
const originalHash = buildProductCodeRequestHash(request, rows);
|
||
const reversedRows = [...rows].reverse();
|
||
const reversedHash = buildProductCodeRequestHash(
|
||
buildProductCodeRequest(configInput, reversedRows, { name: '测试运营' }),
|
||
reversedRows
|
||
);
|
||
const renamedRows = rows.map((row, index) => index === 0
|
||
? { ...row, selectedSkuName: `${row.selectedSkuName} 新名称` }
|
||
: row);
|
||
const renamedHash = buildProductCodeRequestHash(
|
||
buildProductCodeRequest(configInput, renamedRows, { name: '测试运营' }),
|
||
renamedRows
|
||
);
|
||
assert.notEqual(originalHash, reversedHash);
|
||
assert.notEqual(originalHash, renamedHash);
|
||
});
|
||
|
||
test('1688 pricing confirmation reuses the global registry and never requests another code set', () => {
|
||
const serviceSource = fs.readFileSync(
|
||
path.join(__dirname, '../src/services/planningSelectionFissionService.js'),
|
||
'utf8'
|
||
);
|
||
const saveStart = serviceSource.indexOf('async function saveSelectionFissionProfitPricingTable');
|
||
const saveEnd = serviceSource.indexOf('\nasync function generateSelectionFissionSkuNames', saveStart);
|
||
assert.notEqual(saveStart, -1);
|
||
assert.notEqual(saveEnd, -1);
|
||
const saveSource = serviceSource.slice(saveStart, saveEnd);
|
||
|
||
assert.match(saveSource, /loadAlibaba1688GlobalEncoding/);
|
||
assert.match(saveSource, /product_code_status = 'completed'/);
|
||
assert.doesNotMatch(saveSource, /createProductCodes|getProductCodeMeta/);
|
||
assert.doesNotMatch(saveSource, /product_code_status = 'requesting'/);
|
||
});
|