94 lines
3.9 KiB
JavaScript
94 lines
3.9 KiB
JavaScript
(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
|
||
};
|
||
}));
|