import assert from 'node:assert/strict' import { readFileSync } from 'node:fs' import { dirname, resolve } from 'node:path' import { fileURLToPath } from 'node:url' const currentDir = dirname(fileURLToPath(import.meta.url)) const warehouseRoot = resolve(currentDir, '..', '..', '..') const sqlPath = resolve(warehouseRoot, 'src/main/resources/db/warehouse-public-master-data.sql') const acceptedPath = resolve(warehouseRoot, 'src/main/resources/db/master-data/fba-public-addresses.accepted.csv') const rejectedPath = resolve(warehouseRoot, 'src/main/resources/db/master-data/fba-public-addresses.rejected.csv') const fixedWarehousePath = resolve(warehouseRoot, 'src/main/resources/db/master-data/platform-fixed-warehouses.csv') function parseCsv(text) { const rows = [] let field = '' let row = [] let quoted = false for (let index = 0; index < text.length; index += 1) { const char = text[index] if (quoted) { if (char === '"' && text[index + 1] === '"') { field += '"' index += 1 } else if (char === '"') { quoted = false } else { field += char } } else if (char === '"') { quoted = true } else if (char === ',') { row.push(field) field = '' } else if (char === '\n') { row.push(field.replace(/\r$/, '')) rows.push(row) row = [] field = '' } else { field += char } } if (field.length > 0 || row.length > 0) { row.push(field) rows.push(row) } const [headers, ...data] = rows.filter((item) => item.some((value) => value !== '')) return data.map((values) => Object.fromEntries(headers.map((header, index) => [header, values[index] ?? '']))) } const sql = readFileSync(sqlPath, 'utf8') const accepted = parseCsv(readFileSync(acceptedPath, 'utf8')) const rejected = parseCsv(readFileSync(rejectedPath, 'utf8')) const fixedWarehouses = parseCsv(readFileSync(fixedWarehousePath, 'utf8')) assert.equal(accepted.length, 252) assert.equal(rejected.length, 54) assert.equal(fixedWarehouses.length, 4) const codes = new Set() const warehouseIds = new Set() const addressIds = new Set() for (const row of accepted) { assert.match(row.warehouse_code, /^[A-Z0-9]{3,5}$/) assert.equal(row.warehouse_code, row.warehouse_code.trim().toUpperCase()) assert.ok(row.city.trim()) assert.ok(row.state_province.trim()) assert.ok(row.address_line1.trim()) assert.ok(row.postal_code.trim()) assert.ok(row.timezone.trim()) assert.equal(row.country_code, 'US') assert.ok(!codes.has(row.warehouse_code), `duplicate code ${row.warehouse_code}`) assert.ok(!warehouseIds.has(row.warehouse_id_seed), `duplicate warehouse id ${row.warehouse_id_seed}`) assert.ok(!addressIds.has(row.address_id_seed), `duplicate address id ${row.address_id_seed}`) codes.add(row.warehouse_code) warehouseIds.add(row.warehouse_id_seed) addressIds.add(row.address_id_seed) } assert.ok(rejected.some((row) => row.reject_reason.includes('non_fba_business_node'))) assert.equal(rejected.filter((row) => row.reject_reason.includes('timezone_pending_confirmation')).length, 1) assert.deepEqual(fixedWarehouses.map((row) => row.warehouse_code), [ 'CN-YIWU-01', 'CN-DONGGUAN-01', 'US-LAX-01', 'US-NYC-01', ]) assert.deepEqual(fixedWarehouses.map((row) => row.timezone), [ 'UTC+8', 'UTC+8', 'UTC-8', 'UTC-5', ]) assert.ok(fixedWarehouses.every((row) => row.address_line1.includes('待维护') || row.address_line1.includes('pending maintenance'))) assert.match(sql, /CREATE TEMPORARY TABLE tmp_wh_fixed_platform_warehouse/) assert.match(sql, /'CN-YIWU-01','义乌仓','DOMESTIC','CN','UTC\+8'/) assert.match(sql, /'CN-DONGGUAN-01','东莞仓','DOMESTIC','CN','UTC\+8'/) assert.match(sql, /'US-LAX-01','洛杉矶仓','OVERSEAS','US','UTC-8'/) assert.match(sql, /'US-NYC-01','纽约仓','OVERSEAS','US','UTC-5'/) assert.match(sql, /固定平台仓地址种子ID与既有数据冲突/) assert.match(sql, /固定平台仓地址父子解析失败/) assert.match(sql, /FROM tmp_wh_fixed_platform_warehouse source[\s\S]+ON DUPLICATE KEY UPDATE\s+tenant_id = VALUES\(tenant_id\);/) assert.match(sql, /CREATE TEMPORARY TABLE tmp_wh_fba_public_master_data/) assert.match(sql, /JOIN wh_warehouse warehouse\s+ON warehouse\.tenant_id = 0\s+AND warehouse\.warehouse_code = source\.warehouse_code/s) assert.match(sql, /ON DUPLICATE KEY UPDATE\s+warehouse_type = VALUES\(warehouse_type\),\s+country_code = VALUES\(country_code\),\s+timezone = VALUES\(timezone\),\s+updated_at = CURRENT_TIMESTAMP\(3\);/s) assert.doesNotMatch(sql, /status\s*=\s*VALUES\(status\)/) assert.doesNotMatch(sql, /contact_name\s*=\s*VALUES\(contact_name\)/) assert.doesNotMatch(sql, /contact_phone\s*=\s*VALUES\(contact_phone\)/) assert.doesNotMatch(sql, /contact_email\s*=\s*VALUES\(contact_email\)/) assert.doesNotMatch(sql, /remark\s*=\s*VALUES\(remark\)/) assert.match(sql, /国内固定作业仓必须启用收货能力/) assert.match(sql, /INSERT INTO wh_service_capability[\s\S]+?'RECEIVING'/i) const fbaBlock = sql.slice(sql.indexOf('CREATE TEMPORARY TABLE tmp_wh_fba_public_master_data')) assert.doesNotMatch(fbaBlock, /INSERT INTO wh_service_capability/i) assert.match(sql, /FBA公共主数据地址种子ID与既有数据冲突/) assert.match(sql, /FBA公共地址不得创建平台作业能力/)