fix(receipt-import): harden bacon signal detection with pork category fallback chain
This commit is contained in:
@@ -45,6 +45,21 @@ function normalizeForRules(value: string): string {
|
|||||||
.trim();
|
.trim();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function hasPorkLikeSignal(normalized: string): boolean {
|
||||||
|
return (
|
||||||
|
normalized.includes('bacon') ||
|
||||||
|
normalized.includes('bacn') ||
|
||||||
|
normalized.includes('baco') ||
|
||||||
|
/\bbac[a-z0-9]{1,5}\b/.test(normalized) ||
|
||||||
|
/\bsidflask\b/.test(normalized) ||
|
||||||
|
/\bpancetta\b/.test(normalized) ||
|
||||||
|
/\bflask\b/.test(normalized) ||
|
||||||
|
/\bflaskfile\b/.test(normalized) ||
|
||||||
|
/\bkarr[eé]\b/.test(normalized) ||
|
||||||
|
/\bkotlett\b/.test(normalized)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class ReceiptImportService {
|
export class ReceiptImportService {
|
||||||
private readonly logger = new Logger(ReceiptImportService.name);
|
private readonly logger = new Logger(ReceiptImportService.name);
|
||||||
@@ -378,12 +393,24 @@ export class ReceiptImportService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const normalized = normalizeForRules(signalText);
|
const normalized = normalizeForRules(signalText);
|
||||||
|
return hasPorkLikeSignal(normalized);
|
||||||
|
}
|
||||||
|
|
||||||
|
private resolvePorkCategory(
|
||||||
|
categories: Awaited<ReturnType<CategoriesService['findFlattened']>>,
|
||||||
|
) {
|
||||||
return (
|
return (
|
||||||
/\bbacon\b/.test(normalized) ||
|
categories.find(
|
||||||
/\bbacn\b/.test(normalized) ||
|
(c) =>
|
||||||
/\bbaco\b/.test(normalized) ||
|
c.name.toLowerCase() === 'fläsk' &&
|
||||||
/\bsidflask\b/.test(normalized) ||
|
c.path.toLowerCase().startsWith('kött, chark & fågel > kött > '),
|
||||||
/\bpancetta\b/.test(normalized)
|
) ||
|
||||||
|
categories.find(
|
||||||
|
(c) =>
|
||||||
|
c.name.toLowerCase() === 'kött' &&
|
||||||
|
c.path.toLowerCase() === 'kött, chark & fågel > kött',
|
||||||
|
) ||
|
||||||
|
categories.find((c) => c.path.toLowerCase() === 'kött, chark & fågel')
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -393,22 +420,15 @@ export class ReceiptImportService {
|
|||||||
categories: Awaited<ReturnType<CategoriesService['findFlattened']>>,
|
categories: Awaited<ReturnType<CategoriesService['findFlattened']>>,
|
||||||
): CategorySuggestion {
|
): CategorySuggestion {
|
||||||
const normalized = normalizeForRules(signalText);
|
const normalized = normalizeForRules(signalText);
|
||||||
const hasBaconLikeSignal =
|
const hasBaconLikeSignal = hasPorkLikeSignal(normalized);
|
||||||
/\bbacon\b/.test(normalized) ||
|
|
||||||
/\bbacn\b/.test(normalized) ||
|
|
||||||
/\bbaco\b/.test(normalized) ||
|
|
||||||
/\bbac[a-z]{1,3}\b/.test(normalized) ||
|
|
||||||
/\bsidflask\b/.test(normalized) ||
|
|
||||||
/\bpancetta\b/.test(normalized);
|
|
||||||
|
|
||||||
if (!hasBaconLikeSignal) return suggestion;
|
if (!hasBaconLikeSignal) return suggestion;
|
||||||
|
|
||||||
const l3Pork = categories.find(
|
const l3Pork = this.resolvePorkCategory(categories);
|
||||||
(c) =>
|
if (!l3Pork) {
|
||||||
c.name.toLowerCase() === 'fläsk' &&
|
this.logger.warn(`Hard-override: pork signal hittad men ingen köttkategori kunde hittas för "${signalText}"`);
|
||||||
c.path.toLowerCase().startsWith('kött, chark & fågel > kött > '),
|
return suggestion;
|
||||||
);
|
}
|
||||||
if (!l3Pork) return suggestion;
|
|
||||||
|
|
||||||
if (suggestion.categoryId === l3Pork.id) return suggestion;
|
if (suggestion.categoryId === l3Pork.id) return suggestion;
|
||||||
|
|
||||||
@@ -458,22 +478,10 @@ export class ReceiptImportService {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// ── Regel: Kött/chark (bacon/fläsk m.m.) ────────────────────────────
|
// ── Regel: Kött/chark (bacon/fläsk m.m.) ────────────────────────────
|
||||||
const hasPorkSignal =
|
const hasPorkSignal = hasPorkLikeSignal(normalized);
|
||||||
/\bbacon\b/.test(normalized) ||
|
|
||||||
/\bbacn\b/.test(normalized) ||
|
|
||||||
/\bbaco\b/.test(normalized) ||
|
|
||||||
/\bsidflask\b/.test(normalized) ||
|
|
||||||
/\bpancetta\b/.test(normalized) ||
|
|
||||||
/\bflask\b/.test(normalized) ||
|
|
||||||
/\bflaskfile\b/.test(normalized) ||
|
|
||||||
/\bkarr[eé]\b/.test(normalized) ||
|
|
||||||
/\bkotlett\b/.test(normalized);
|
|
||||||
|
|
||||||
if (hasPorkSignal) {
|
if (hasPorkSignal) {
|
||||||
const l3Pork = findCategory({
|
const l3Pork = this.resolvePorkCategory(categories);
|
||||||
name: 'fläsk',
|
|
||||||
startsWith: 'kött, chark & fågel > kött > ',
|
|
||||||
});
|
|
||||||
const hit = toSuggestion(l3Pork, 'high');
|
const hit = toSuggestion(l3Pork, 'high');
|
||||||
if (hit) return hit;
|
if (hit) return hit;
|
||||||
}
|
}
|
||||||
@@ -797,16 +805,7 @@ export class ReceiptImportService {
|
|||||||
categories: Awaited<ReturnType<CategoriesService['findFlattened']>>,
|
categories: Awaited<ReturnType<CategoriesService['findFlattened']>>,
|
||||||
): CategorySuggestion {
|
): CategorySuggestion {
|
||||||
const normalized = normalizeForRules(rawName);
|
const normalized = normalizeForRules(rawName);
|
||||||
const hasPorkSignal =
|
const hasPorkSignal = hasPorkLikeSignal(normalized);
|
||||||
/\bbacon\b/.test(normalized) ||
|
|
||||||
/\bbacn\b/.test(normalized) ||
|
|
||||||
/\bbaco\b/.test(normalized) ||
|
|
||||||
/\bsidflask\b/.test(normalized) ||
|
|
||||||
/\bpancetta\b/.test(normalized) ||
|
|
||||||
/\bflask\b/.test(normalized) ||
|
|
||||||
/\bflaskfile\b/.test(normalized) ||
|
|
||||||
/\bkarr[eé]\b/.test(normalized) ||
|
|
||||||
/\bkotlett\b/.test(normalized);
|
|
||||||
|
|
||||||
if (hasPorkSignal) {
|
if (hasPorkSignal) {
|
||||||
const aiPath = suggestion.path.toLowerCase();
|
const aiPath = suggestion.path.toLowerCase();
|
||||||
@@ -815,11 +814,7 @@ export class ReceiptImportService {
|
|||||||
|
|
||||||
if (!isClearlyWrongBranch) return suggestion;
|
if (!isClearlyWrongBranch) return suggestion;
|
||||||
|
|
||||||
const l3Pork = categories.find(
|
const l3Pork = this.resolvePorkCategory(categories);
|
||||||
(c) =>
|
|
||||||
c.name.toLowerCase() === 'fläsk' &&
|
|
||||||
c.path.toLowerCase().startsWith('kött, chark & fågel > kött > '),
|
|
||||||
);
|
|
||||||
if (!l3Pork) return suggestion;
|
if (!l3Pork) return suggestion;
|
||||||
|
|
||||||
this.logger.log(
|
this.logger.log(
|
||||||
|
|||||||
Reference in New Issue
Block a user