fix: enforce complete scope keyword matches (#29)

Co-authored-by: alexpolo1 <alexpolo1@users.noreply.github.com>
This commit is contained in:
Alex
2026-08-30 18:14:57 +02:00
committed by GitHub
parent 1a00fdadfe
commit adb7e8a17a
2 changed files with 20 additions and 2 deletions

View File

@@ -96,6 +96,24 @@ describe('QuoteRealismService', () => {
expect(service.getRoofHistoryRegex({ project_name: 'Nyt tagpap på fladt tag' })).toBe('tagpap|fladt tag|fladtag');
});
test('matches roof keywords as complete terms and keeps rental precedence', () => {
const service = new QuoteRealismService({ pool: {} });
expect(service.classifyScope('Forskellige specialarbejder')).toBe('other');
expect(service.classifyScope('Anden etape')).toBe('other');
expect(service.classifyScope('Stillads inkl. transport', 'Udlejning')).toBe('rental');
expect(service.classifyScope('Tape, klæb og membraner')).toBe('roof');
expect(service.classifyScope('Skel-/naboovergang')).toBe('roof');
const analysis = service.buildAnalysis({
project: { id: 392, project_name: 'Betontag' },
materials: [{ material_id: 1, total_price: 100 }],
rentals: [{ rental_name: 'Forskellige specialarbejder', quantity: 1, unit: 'sum', unit_price: 1000 }],
historyByScope: { roof: [{ caseNumber: '1', totalHours: 1, materialSalesExVat: 1 }] }
});
expect(analysis.readyForFixedPrice).toBe(false);
expect(analysis.blockers).toContain('Forskellige specialarbejder kræver manuel afklaring og historik før fast pris');
});
test('classifies roof support and logistics reference services without generic errors', () => {
const service = new QuoteRealismService({ pool: {} });
expect(service.classifyScope('Tagfod, fuglegitter, ventilation og tætninger')).toBe('roof');

View File

@@ -115,9 +115,9 @@ class QuoteRealismService {
const text = this.normalizeText(`${name} ${category}`);
if (text.includes('dør') || text.includes('doer')) return 'doors';
if (/gulv|parket|laminat|sildeben/.test(text)) return 'floor';
if (/tagfod|fuglegitter|skel|inddækning|tape|klæb|membran|småmaterial/.test(text)) return 'roof';
if (/container|sortering|bortskaffelse|levering|kranhejs|transport/.test(text)) return 'logistics';
if (/stillads|faldsikring|lift|leje|udlejning/.test(text)) return 'rental';
if (/(?:^|[^a-zæøå0-9])(?:tagfod|fuglegitter|skel|inddækninger?|tape|klæb|membraner?|småmaterialer?)(?=$|[^a-zæøå0-9])/u.test(text)) return 'roof';
if (/(?:^|[^a-zæøå0-9])(?:container|sortering|bortskaffelse|levering|kranhejs|transport)(?=$|[^a-zæøå0-9])/u.test(text)) return 'logistics';
return 'other';
}