- Added a comprehensive manual testing guide for the countdown functionality in `test_countdown_manual.md`. - Developed a detailed Selenium test suite in `test_countdown_selenium.py` to verify countdown behavior, including server accessibility, login, countdown progression, and UI elements. - Created a minimal Selenium test version in `test_countdown_selenium_minimal.py` for quick checks without complex setup. - Introduced a verification script in `test_countdown_verification.py` to analyze code correctness, including server checks, build file existence, and countdown logic.
5.6 KiB
Materiale Pris Integration Fix
Dato: 2024-11-07
Status: ✅ Færdig
Problem
Når man tilføjer et materiale i SmartPackageForm via "Tilføj materiale" knappen, viste prisen altid 0.00 kr selvom materialer har priser i databasen.
Symptomer
- MaterialDialog viste "Standardpris: 0.00 kr/stk"
- Effektiv pris viste også 0.00 kr/stk
- Brugerdefineret pris skulle indtastes manuelt
Root Cause
/api/materials endpoint hentede kun data fra materials tabellen uden at JOIN'e med material_prices tabellen hvor priserne faktisk er gemt.
Løsning
Backend Ændringer
Fil: /backend/unified-server.js
Ændring 1: Tilføjet JOIN med material_prices
const materials = await databaseService.query(
`SELECT
m.*,
mp.price,
mp.unit as price_unit,
mp.valid_from,
mp.supplier_name as price_supplier
FROM materials m
LEFT JOIN material_prices mp ON m.id = mp.material_id
AND mp.is_active = 1
AND mp.id = (
SELECT id
FROM material_prices
WHERE material_id = m.id
AND is_active = 1
ORDER BY valid_from DESC, id DESC
LIMIT 1
)
${whereClause}
ORDER BY m.name ASC
LIMIT ? OFFSET ?`,
[...params, parseInt(limit), parseInt(offset)]
);
Ændring 2: Rettede ambiguous column names
// FØR:
if (search) {
whereClause += ' AND (name LIKE ? OR description LIKE ? OR sku LIKE ?)';
}
// EFTER:
if (search) {
whereClause += ' AND (m.name LIKE ? OR m.description LIKE ? OR m.sku LIKE ?)';
}
Hvordan det virker
- LEFT JOIN: Alle materialer vises, også dem uden priser
- Subquery: Finder den nyeste aktive pris for hvert materiale
- ORDER BY valid_from DESC: Bruger den senest gyldige pris
- is_active = 1: Kun aktive priser inkluderes
Database Schema
Tabeller involveret:
materials- Materiale grunddata (id, name, unit, description, etc.)material_prices- Priser for materialer (material_id, price, valid_from, etc.)
Relationer:
materials.id ← material_prices.material_id (1:N)
Test Resultater
Før Fix
curl http://localhost:4031/api/materials?limit=5
{
"id": 16,
"name": "B7 tagplader",
"unit": "m2",
"price": null // ❌ Ingen pris
}
Efter Fix
curl http://localhost:4031/api/materials?search=B7%20tag
{
"id": 16,
"name": "B7 tagplader",
"unit": "m2",
"price": "125.00" // ✅ Pris hentet fra material_prices
}
Test Case: Eternit tagsten
{
"id": 37,
"name": "Eternit tagsten B6 rød",
"unit": "m2",
"price": "145.00"
}
Frontend Integration
MaterialDialog modtager nu automatisk pris fra backend:
Før (linje 105-107 i MaterialDialog.js):
const materialPrice = value.price ? parseFloat(value.price) : 0;
// value.price var altid undefined → price = 0
Efter:
const materialPrice = value.price ? parseFloat(value.price) : 0;
// value.price = "125.00" fra database → price = 125.00 ✅
Autocomplete Visning
MaterialDialog's Autocomplete viser nu priser:
getOptionLabel={(option) => {
const priceInfo = option.price
? ` - ${parseFloat(option.price).toFixed(2)} kr/${option.unit}`
: '';
return `${option.name}${priceInfo}`;
}}
Resultat:
- "B7 tagplader - 125.00 kr/m2"
- "Eternit tagsten B6 rød - 145.00 kr/m2"
Materialer med Priser
Efter fix har følgende materialer priser:
| ID | Materiale | Pris | Enhed |
|---|---|---|---|
| 16 | B7 tagplader | 125.00 | m2 |
| 35 | Test materiale | 150.00 | stk |
| 36 | Test materiale efter fix | 200.00 | m2 |
| 37 | Eternit tagsten B6 rød | 145.00 | m2 |
| 38 | Tagpap underlag T400 | 35.50 | m2 |
| 39 | Tagplade stål 35/1035 sort | 185.00 | m2 |
| 40 | Tagrender halvrund zink 150mm | 245.00 | m |
| 41 | Nedløbsrør zink 100mm | 195.00 | m |
| 42 | Stålskotskinne galvaniseret | 45.00 | m |
| 43 | Tagisolering mineraluld 200mm | 85.00 | m2 |
| 44 | Eternit vindskeder B6 | 75.00 | stk |
| 45 | Eternit rygningsten B6 | 195.00 | m |
| 46 | Lægter 38x63mm trykimprægneret | 18.50 | m |
Deployment
# Genstart backend
pm2 restart tilbudgivern-unified
# Frontend kræver ikke rebuild - ændringen er kun i backend
Server Status
- Backend: Online (port 4031) - 11 restarts
- Frontend: Online (port 3001) - 5 restarts
Known Limitations
- Materialer uden priser: Vises stadig i listen men med
price: null - Historiske priser: Kun den nyeste pris vises (baseret på
valid_from) - Multiple leverandører: Hvis samme materiale har flere priser, vises kun den nyeste
Fremtidige Forbedringer
1. Pris Import System
Automatisk import af priser fra leverandører:
- Bygma prisliste
- CSV upload
- API integration
2. Pris Historik
Vis prisudvikling over tid:
SELECT
material_id,
price,
valid_from,
supplier_name
FROM material_prices
WHERE material_id = ?
ORDER BY valid_from DESC
3. Leverandør Valg
Lad brugeren vælge mellem forskellige leverandører:
const [selectedSupplier, setSelectedSupplier] = useState('Bygma');
// Filtrer priser baseret på supplier_name
4. Bulk Pris Opdatering
Interface til at opdatere mange priser på én gang:
- Upload CSV fil med nye priser
- Automatisk validering
- Preview før import
Konklusion
✅ Materialer trækker nu automatisk priser fra databasen
✅ MaterialDialog viser korrekt standardpris
✅ Autocomplete viser priser i dropdown
✅ Brugerdefineret pris kan stadig anvendes til at overskrive
✅ Ingen frontend ændringer nødvendige
Systemet er nu fuldt funktionelt med prisintegration!