feat: add ordrestyring simulation runner

This commit is contained in:
alexpolo1
2026-04-05 20:05:07 +00:00
parent 7395d4d290
commit 4695e28088
2 changed files with 183 additions and 2 deletions

View File

@@ -0,0 +1,173 @@
const path = require('path');
const mysql = require('mysql2/promise');
const databaseService = require('../backend/src/services/databaseService');
const OrderSuggestionService = require('../backend/src/services/orderSuggestionService');
require('dotenv').config({
path: path.join(__dirname, '..', 'backend/.env')
});
const MAX_CASES = 9;
function ensureEnvVar(key) {
if (!process.env[key]) {
throw new Error(`Environment variable ${key} is required to run simulations`);
}
}
async function loadRichCases(connection, limit = MAX_CASES * 2) {
const [rows] = await connection.execute(
`
SELECT
c.case_number,
c.customer_number,
c.description,
c.remarks,
c.status,
COALESCE(c.updated_at, c.creation_date, c.created_at) AS latest_activity
FROM ordrestyring_local.cases c
WHERE c.case_number IS NOT NULL
AND c.case_number <> ''
AND EXISTS (
SELECT 1
FROM ordrestyring_local.hours h
WHERE h.new_case_number = c.case_number
AND h.new_case_number <> ''
)
AND EXISTS (
SELECT 1
FROM ordrestyring_local.case_materials m
WHERE m.case_number = c.case_number
AND m.case_number <> ''
)
ORDER BY GREATEST(
CHAR_LENGTH(COALESCE(c.description, '')),
CHAR_LENGTH(COALESCE(c.remarks, ''))
) DESC,
c.updated_at DESC
LIMIT ?
`,
[limit]
);
return rows;
}
async function createSimulationProject(databaseService, caseRow) {
const projectName = `Simulering: Ordrestyring sag ${caseRow.case_number}`;
const description = `${caseRow.description || ''} ${caseRow.remarks || ''}`.trim() || 'Simuleret beskrivelse';
const customerName = caseRow.customer_name || caseRow.customer_number || 'Ordrestyring kunde';
const [result] = await databaseService.pool.execute(
`
INSERT INTO customer_projects (
project_name,
customer_name,
customer_number,
project_description
) VALUES (?, ?, ?, ?)
`,
[
projectName,
customerName,
caseRow.customer_number || null,
description
]
);
const projectId = result.insertId;
await databaseService.pool.execute(
`
INSERT INTO roof_geometry (
project_id,
roof_type,
total_area,
roof_pitch
) VALUES (?, ?, ?, ?)
`,
[projectId, 'skraat_tag', 120, 30]
);
return projectId;
}
async function cleanupSimulationProject(databaseService, projectId) {
await databaseService.pool.execute('DELETE FROM roof_geometry WHERE project_id = ?', [projectId]);
await databaseService.pool.execute('DELETE FROM customer_projects WHERE id = ?', [projectId]);
}
function summarizeSuggestion(suggestion) {
const materialsCount = suggestion.materialsDraft.length;
const laborHours = suggestion.laborDraft
.reduce((sum, task) => sum + (Number(task.totalHours) || 0), 0);
return {
recommendation: suggestion.recommendation?.recommendedPackage?.packageId || suggestion.recommendation?.recommendedPackage?.name || 'Ingen pakke',
description: suggestion.recommendation?.descriptionDraft || suggestion.recommendation?.suggestedDescription || 'Ingen beskrivelse',
materialsCount,
laborHours: Number(laborHours.toFixed(2)),
warnings: suggestion.recommendation?.warnings || [],
clarifications: suggestion.recommendation?.clarifications || []
};
}
async function runSimulation() {
ensureEnvVar('DB_PASSWORD');
const ordrestyringConn = await mysql.createConnection({
host: process.env.DB_HOST || '127.0.0.1',
port: parseInt(process.env.DB_PORT, 10) || 3306,
user: process.env.DB_USER || 'tilbudgivern_service',
password: process.env.DB_PASSWORD,
database: 'ordrestyring_local'
});
await databaseService.initialize();
const suggestionService = new OrderSuggestionService(databaseService);
const richCases = await loadRichCases(ordrestyringConn);
const uniqueCases = [];
const seenCases = new Set();
for (const item of richCases) {
if (!item.case_number || seenCases.has(item.case_number)) {
continue;
}
seenCases.add(item.case_number);
uniqueCases.push(item);
}
const selectedCases = uniqueCases.slice(0, MAX_CASES);
console.log(`Fetched ${richCases.length} rows, simulating ${selectedCases.length} unique cases`);
const results = [];
for (const caseRow of selectedCases) {
console.log(`\n=== Simulerer case ${caseRow.case_number} (${caseRow.status || 'ukendt status'}) ===`);
const projectId = await createSimulationProject(databaseService, caseRow);
try {
const suggestion = await suggestionService.getOrderSuggestions(projectId, { limit: 5 });
const summary = summarizeSuggestion(suggestion);
console.log(JSON.stringify({
caseNumber: caseRow.case_number,
summary,
matches: suggestion.matches.map(match => ({
source: match.sourceType,
description: match.description || match.projectDescription || '',
totalHours: match.totalHours,
relevance: match.relevanceScore
}))
}, null, 2));
results.push({ caseNumber: caseRow.case_number, summary });
} catch (error) {
console.error(`Fejl ved simulering af ${caseRow.case_number}:`, error.message);
} finally {
await cleanupSimulationProject(databaseService, projectId);
}
}
console.log('\n--- Simulationsoverblik ---');
console.log(JSON.stringify(results, null, 2));
await ordrestyringConn.end();
await databaseService.pool.end();
}
runSimulation().catch(error => {
console.error('Simuleringsscript fejlede:', error.message);
process.exit(1);
});