(function installLTJTSourceRegion(root, factory) { const api = factory(); if (typeof module !== 'undefined' && module.exports) module.exports = api; if (root) root.LTJTSourceRegion = api; }(typeof self !== 'undefined' ? self : globalThis, () => { 'use strict'; // These are source-market tokens, not a general-purpose address parser. // They are used only as an optional customer-keyword disambiguator. Product // and customer candidates are no longer required to share source-market // tokens before an ERP operation can continue. const SOURCE_REGION_TERMS = [ '黑龙江', '内蒙古', '宁夏', '新疆', '西藏', '广西', '广东', '云南', '贵州', '四川', '重庆', '湖南', '湖北', '江西', '福建', '浙江', '江苏', '安徽', '山东', '河南', '河北', '山西', '陕西', '甘肃', '青海', '辽宁', '吉林', '海南', '北京', '上海', '天津', '香港', '澳门', '衡阳', '长沙', '株洲', '湘潭', '郴州', '永州', '岳阳', '常德', '邵阳', '怀化', '南宁', '桂林', '柳州', '广州', '深圳', '佛山', '东莞', '惠州', '珠海', '汕头', '湛江', '茂名', '肇庆', '江门', '中山', '揭阳', '清远', '韶关', '云浮', '河源', '昆明', '大理', '丽江', '西双版纳', '成都', '绵阳', '乐山', '贵阳', '遵义', '南昌', '九江', '赣州', '福州', '厦门', '泉州', '杭州', '宁波', '温州', '南京', '苏州', '无锡', '合肥', '济南', '青岛', '郑州', '石家庄', '太原', '西安', '兰州', '海口', '三亚', '沈阳', '长春', '哈尔滨' ]; function normalizeSourceRegionText(value) { return String(value || '') .normalize('NFKC') .toLowerCase() .replace(/\s+/gu, '') .replace(/[“”‘’'"`【】\[\]()()、,,。.::;;/\\_|+]+/gu, ''); } function refText(reference) { if (reference && typeof reference === 'object') { return [reference.source_region, reference.region, reference.keyword, reference.name] .filter((value) => value !== undefined && value !== null) .join(' '); } return String(reference || ''); } function explicitSourceRegion(reference) { if (!reference || typeof reference !== 'object') return ''; return String(reference.source_region || reference.region || '').trim(); } function sourceRegionTokens(reference) { const explicit = explicitSourceRegion(reference); const text = normalizeSourceRegionText(explicit || refText(reference)); if (!text) return []; const known = SOURCE_REGION_TERMS .filter((term) => text.includes(normalizeSourceRegionText(term))) .sort((left, right) => right.length - left.length); if (known.length) return known; return explicit ? [text] : []; } function uniqueSourceRegionCandidate(candidates, reference) { const sourceTokens = sourceRegionTokens(reference); if (!sourceTokens.length) { return { ok: false, applicable: false, reason: 'customer_source_region_token_missing', source_tokens: [], match_count: 0, candidate: null }; } const matches = (Array.isArray(candidates) ? candidates : []).filter((candidate) => { const candidateText = normalizeSourceRegionText(refText(candidate)); return sourceTokens.every((token) => candidateText.includes(normalizeSourceRegionText(token))); }); return { ok: matches.length === 1, applicable: true, reason: matches.length === 1 ? 'unique_source_region_candidate' : (matches.length > 1 ? 'ambiguous_source_region_candidates' : 'source_region_candidate_not_found'), source_tokens: sourceTokens, match_count: matches.length, candidate: matches.length === 1 ? matches[0] : null }; } return { SOURCE_REGION_TERMS, normalizeSourceRegionText, sourceRegionTokens, uniqueSourceRegionCandidate }; }));