108 lines
3.1 KiB
JavaScript
108 lines
3.1 KiB
JavaScript
function normalizeCustomerKey(value) {
|
||
return String(value || '')
|
||
.replace(/[(]/g, '(')
|
||
.replace(/[)]/g, ')')
|
||
.replace(/[,,。.;;、\s]/g, '')
|
||
.toLowerCase()
|
||
.trim();
|
||
}
|
||
|
||
function customerDisplayName(value = {}, fallback = '') {
|
||
return value.erpName || value.name || fallback;
|
||
}
|
||
|
||
function candidateFor(key, value, keyword) {
|
||
return {
|
||
key,
|
||
id: String(value && value.id || ''),
|
||
name: customerDisplayName(value, key),
|
||
value,
|
||
matchedBy: keyword,
|
||
};
|
||
}
|
||
|
||
function matchesCustomer(candidateKey, customer, keyword) {
|
||
const wanted = normalizeCustomerKey(keyword);
|
||
const haystacks = [
|
||
candidateKey,
|
||
customer && customer.erpName,
|
||
customer && customer.name,
|
||
customer && customer.searchName,
|
||
].map(normalizeCustomerKey).filter(Boolean);
|
||
return haystacks.some((value) => value === wanted || value.includes(wanted) || wanted.includes(value));
|
||
}
|
||
|
||
function resolveCustomerKeyword(map, keyword, kind = 'customer') {
|
||
const source = map || {};
|
||
const rawKeyword = String(keyword || '').trim();
|
||
if (!rawKeyword) {
|
||
return {
|
||
status: 'not_found',
|
||
reason: 'customer_keyword_empty',
|
||
keyword: rawKeyword,
|
||
candidates: [],
|
||
customerMessage: `请补充${kind}关键词。`,
|
||
};
|
||
}
|
||
if (source[rawKeyword]) {
|
||
return {
|
||
status: 'matched',
|
||
reason: '',
|
||
keyword: rawKeyword,
|
||
key: rawKeyword,
|
||
value: source[rawKeyword],
|
||
candidates: [candidateFor(rawKeyword, source[rawKeyword], rawKeyword)],
|
||
};
|
||
}
|
||
|
||
const matches = Object.entries(source)
|
||
.filter(([key, value]) => matchesCustomer(key, value, rawKeyword))
|
||
.map(([key, value]) => candidateFor(key, value, rawKeyword));
|
||
|
||
if (matches.length === 1) {
|
||
return {
|
||
status: 'matched',
|
||
reason: '',
|
||
keyword: rawKeyword,
|
||
key: matches[0].key,
|
||
value: matches[0].value,
|
||
candidates: matches,
|
||
};
|
||
}
|
||
if (matches.length > 1) {
|
||
return {
|
||
status: 'ambiguous',
|
||
reason: 'customer_keyword_ambiguous',
|
||
keyword: rawKeyword,
|
||
candidates: matches,
|
||
customerMessage: `${kind}关键词“${rawKeyword}”匹配到多个客户,请确认:${matches.map((item) => item.name).join('、')}`,
|
||
};
|
||
}
|
||
return {
|
||
status: 'not_found',
|
||
reason: 'customer_keyword_not_found',
|
||
keyword: rawKeyword,
|
||
candidates: [],
|
||
customerMessage: `${kind}关键词“${rawKeyword}”没有匹配到 ERP 客户,请补充更完整名称。`,
|
||
};
|
||
}
|
||
|
||
function resolveCustomerOrThrow(map, keyword, kind = 'customer', options = {}) {
|
||
const result = resolveCustomerKeyword(map, keyword, kind);
|
||
if (result.status === 'matched') return result.value;
|
||
if (result.status === 'not_found' && options.allowPlainName) return {};
|
||
const error = new Error(result.status === 'ambiguous'
|
||
? `customer keyword ambiguous for ${kind}: ${keyword}`
|
||
: `customer keyword not found for ${kind}: ${keyword}`);
|
||
error.code = result.reason;
|
||
error.customerMessage = result.customerMessage;
|
||
error.candidates = result.candidates;
|
||
throw error;
|
||
}
|
||
|
||
module.exports = {
|
||
normalizeCustomerKey,
|
||
resolveCustomerKeyword,
|
||
resolveCustomerOrThrow,
|
||
};
|