- Implemented a new test suite for production API verification using curl, ensuring all critical endpoints respond correctly and return valid JSON. - Added frontend integration tests to check for critical errors in the UI and verify key UI elements are present and functional. - Created test data for quotes and project calculations to facilitate testing. - Developed a script to check offers in the Ordrestyring system, including detailed task descriptions. - Added tests for generating PDFs from quote data, ensuring the output is valid and contains expected information. - Implemented a test script for the Røsevangen project, integrating with the Ordrestyring API and verifying database entries.
340 lines
12 KiB
Python
340 lines
12 KiB
Python
#!/usr/bin/env python3
|
|
"""
|
|
Test script: Generer tilbud for Røsevangen 44 og send til Ordrestyring
|
|
"""
|
|
|
|
import mysql.connector
|
|
import requests
|
|
import json
|
|
from datetime import datetime
|
|
|
|
# Database connection
|
|
db_config = {
|
|
'host': 'localhost',
|
|
'user': 'tilbuduser',
|
|
'password': 'tilbudpass123',
|
|
'database': 'tilbudgivern'
|
|
}
|
|
|
|
# Projekt data
|
|
PROJECT_ID = 22 # Komplet tagudskiftning - Røsevangen 44
|
|
|
|
# Brug EKSISTERENDE kunde fra Ordrestyring (må IKKE oprette ny!)
|
|
CUSTOMER_ID = 5355 # Alexander Warme (eksisterende kunde)
|
|
|
|
def insert_project_data():
|
|
"""Indsætter projekt data i databasen"""
|
|
conn = mysql.connector.connect(**db_config)
|
|
cursor = conn.cursor()
|
|
|
|
try:
|
|
# Check om projekt eksisterer
|
|
cursor.execute("SELECT id FROM customer_projects WHERE id = %s", (PROJECT_ID,))
|
|
if not cursor.fetchone():
|
|
print(f"❌ Projekt ID {PROJECT_ID} findes ikke i databasen")
|
|
return False
|
|
|
|
print(f"✅ Bruger eksisterende projekt ID {PROJECT_ID}")
|
|
|
|
# Indsæt geometri
|
|
cursor.execute("""
|
|
INSERT INTO roof_geometry (project_id, total_area, roof_pitch, roof_height, roof_type)
|
|
VALUES (%s, %s, %s, %s, %s)
|
|
ON DUPLICATE KEY UPDATE
|
|
total_area = VALUES(total_area),
|
|
roof_pitch = VALUES(roof_pitch),
|
|
roof_height = VALUES(roof_height),
|
|
roof_type = VALUES(roof_type)
|
|
""", (PROJECT_ID, 105.0, 35, 6.5, 'skraat_tag'))
|
|
|
|
# Indsæt arbejdstimer
|
|
labor_cost_total = 85.5 * 580.0
|
|
cursor.execute("""
|
|
INSERT INTO project_labor (project_id, total_work_hours, carpenter_count, hourly_rate, estimated_hours_per_carpenter, total_labor_cost)
|
|
VALUES (%s, %s, %s, %s, %s, %s)
|
|
ON DUPLICATE KEY UPDATE
|
|
total_work_hours = VALUES(total_work_hours),
|
|
carpenter_count = VALUES(carpenter_count),
|
|
hourly_rate = VALUES(hourly_rate),
|
|
estimated_hours_per_carpenter = VALUES(estimated_hours_per_carpenter),
|
|
total_labor_cost = VALUES(total_labor_cost)
|
|
""", (PROJECT_ID, 85.5, 2, 580.0, 42.75, labor_cost_total))
|
|
|
|
# Beregn priser
|
|
labor_cost = 85.5 * 580.0 # 49,590.00 kr
|
|
material_cost = 66503.00 # Fra materialer
|
|
subtotal = labor_cost + material_cost
|
|
overhead = subtotal * 0.15
|
|
profit = subtotal * 0.20
|
|
total_excl_vat = subtotal + overhead + profit
|
|
vat = total_excl_vat * 0.25
|
|
total_incl_vat = total_excl_vat + vat
|
|
|
|
# Indsæt beregning
|
|
# Først slet eksisterende
|
|
cursor.execute("DELETE FROM project_calculations WHERE project_id = %s", (PROJECT_ID,))
|
|
|
|
# Derefter indsæt ny
|
|
cursor.execute("""
|
|
INSERT INTO project_calculations
|
|
(project_id, total_area, total_work_hours, carpenter_count,
|
|
total_labor_cost, total_material_cost, material_count,
|
|
subtotal, overhead_percentage, overhead_amount,
|
|
profit_percentage, profit_amount, total_excl_vat,
|
|
vat_percentage, vat_amount, total_incl_vat)
|
|
VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)
|
|
""", (PROJECT_ID, 105.0, 85.5, 2,
|
|
labor_cost, material_cost, 10,
|
|
subtotal, 15.0, overhead,
|
|
20.0, profit, total_excl_vat,
|
|
25.0, vat, total_incl_vat))
|
|
|
|
calculation_id = cursor.lastrowid
|
|
if calculation_id == 0:
|
|
# Hent existing calculation ID
|
|
cursor.execute("SELECT id FROM project_calculations WHERE project_id = %s ORDER BY created_at DESC LIMIT 1", (PROJECT_ID,))
|
|
result = cursor.fetchone()
|
|
calculation_id = result[0] if result else None
|
|
|
|
# Indsæt materialer
|
|
materials = [
|
|
('Eternit B7 tagplader 920x1320mm', 223, 'stk', 245.00),
|
|
('Lindab Rainline tagrende 125mm 3m', 14, 'stk', 245.00),
|
|
('Lindab Rainline konsoljern', 67, 'stk', 28.00),
|
|
('Lindab nedløb 3m', 4, 'stk', 185.00),
|
|
('Eternit tagskruer 400 stk', 2, 'pakke', 385.00),
|
|
('Lægte 30x50mm trykimp', 228, 'lbm', 18.50),
|
|
('Spær træ 45x200mm', 96, 'lbm', 42.00),
|
|
('EPDM tætningsbånd 30m', 8, 'rulle', 285.00),
|
|
('Eternit rygning B7', 12, 'lbm', 125.00),
|
|
('Ringsøm 2.8x65mm 2880 stk', 2, 'pakke', 145.00)
|
|
]
|
|
|
|
# Slet gamle materialer for dette projekt
|
|
cursor.execute("DELETE FROM project_materials WHERE project_id = %s", (PROJECT_ID,))
|
|
|
|
for material_name, quantity, unit, unit_price in materials:
|
|
total_price = quantity * unit_price
|
|
cursor.execute("""
|
|
INSERT INTO project_materials
|
|
(project_id, material_name, quantity, unit, unit_price, total_price, material_category)
|
|
VALUES (%s, %s, %s, %s, %s, %s, %s)
|
|
""", (PROJECT_ID, material_name, quantity, unit, unit_price, total_price, 'Tagmaterialer'))
|
|
|
|
# Opret generated_quotes entry hvis ikke eksisterer
|
|
cursor.execute("""
|
|
INSERT INTO generated_quotes (project_id, calculation_id, quote_text, created_at)
|
|
VALUES (%s, %s, %s, NOW())
|
|
ON DUPLICATE KEY UPDATE calculation_id = VALUES(calculation_id), quote_text = VALUES(quote_text)
|
|
""", (PROJECT_ID, calculation_id, 'Tilbud genereret via test script'))
|
|
|
|
conn.commit()
|
|
|
|
print("✅ Projekt data indsat i database")
|
|
print(f" Project ID: {PROJECT_ID}")
|
|
print(f" Calculation ID: {calculation_id}")
|
|
print(f" Arbejdsløn: {labor_cost:,.2f} kr")
|
|
print(f" Materialer: {material_cost:,.2f} kr")
|
|
print(f" Antal materialer: {len(materials)}")
|
|
|
|
return calculation_id
|
|
|
|
except Exception as e:
|
|
print(f"❌ Fejl ved indsættelse af data: {e}")
|
|
import traceback
|
|
traceback.print_exc()
|
|
conn.rollback()
|
|
return None
|
|
finally:
|
|
cursor.close()
|
|
conn.close()
|
|
|
|
def test_preview():
|
|
"""Test preview af tilbudsbeskrivelse"""
|
|
print("\n" + "=" * 80)
|
|
print("TEST 1: Preview tilbudsbeskrivelse")
|
|
print("=" * 80)
|
|
|
|
# Hent calculation_id fra database
|
|
conn = mysql.connector.connect(**db_config)
|
|
cursor = conn.cursor()
|
|
cursor.execute("SELECT id FROM project_calculations WHERE project_id = %s ORDER BY created_at DESC LIMIT 1", (PROJECT_ID,))
|
|
result = cursor.fetchone()
|
|
calculation_id = result[0] if result else 1
|
|
cursor.close()
|
|
conn.close()
|
|
|
|
response = requests.post(
|
|
'http://localhost:4031/api/ordrestyring/preview-description',
|
|
json={
|
|
'projectId': PROJECT_ID,
|
|
'calculationId': calculation_id
|
|
}
|
|
)
|
|
|
|
if response.status_code == 200:
|
|
data = response.json()
|
|
if data.get('success'):
|
|
print("\n✅ Beskrivelse genereret!\n")
|
|
print("KUNDE BESKRIVELSE (første 500 tegn):")
|
|
print("-" * 80)
|
|
print(data['description'][:500] + "...")
|
|
print("-" * 80)
|
|
|
|
if 'internalNotes' in data:
|
|
print("\nINTERNE NOTER (første 300 tegn):")
|
|
print("-" * 80)
|
|
print(data['internalNotes'][:300] + "...")
|
|
print("-" * 80)
|
|
|
|
print(f"\n💰 Pris eks. moms: {data['priceExVat']:,.2f} kr")
|
|
print(f"💰 Pris inkl. moms: {data['priceInclVat']:,.2f} kr")
|
|
return True
|
|
else:
|
|
print(f"❌ Fejl: {data.get('error')}")
|
|
return False
|
|
else:
|
|
print(f"❌ HTTP fejl {response.status_code}")
|
|
print(response.text)
|
|
return False
|
|
|
|
def send_to_ordrestyring():
|
|
"""Send tilbud til Ordrestyring"""
|
|
print("\n" + "=" * 80)
|
|
print("TEST 2: Send tilbud til Ordrestyring")
|
|
print("=" * 80)
|
|
|
|
confirm = input("\n📤 Vil du sende tilbuddet til Ordrestyring? (y/n): ")
|
|
if confirm.lower() != 'y':
|
|
print("⏹️ Test afbrudt")
|
|
return None
|
|
|
|
# Hent calculation_id fra database
|
|
conn = mysql.connector.connect(**db_config)
|
|
cursor = conn.cursor()
|
|
cursor.execute("SELECT id FROM project_calculations WHERE project_id = %s ORDER BY created_at DESC LIMIT 1", (PROJECT_ID,))
|
|
result = cursor.fetchone()
|
|
calculation_id = result[0] if result else 1
|
|
cursor.close()
|
|
conn.close()
|
|
|
|
response = requests.post(
|
|
'http://localhost:4031/api/ordrestyring/send-quote-graphql',
|
|
json={
|
|
'projectId': PROJECT_ID,
|
|
'calculationId': calculation_id,
|
|
'customerId': CUSTOMER_ID # Brug eksisterende kunde ID 5355
|
|
}
|
|
)
|
|
|
|
if response.status_code == 200:
|
|
data = response.json()
|
|
if data.get('success'):
|
|
offer = data['offer']
|
|
print("\n✅ Tilbud sendt til Ordrestyring!\n")
|
|
print("=" * 80)
|
|
print(f"Offer ID: {offer['id']}")
|
|
print(f"Offer Number: {offer['number']}")
|
|
print(f"Customer: {offer['customer']['name']}")
|
|
print(f"Status: {offer['status']['text']}")
|
|
print(f"Price ex VAT: {offer['totals']['salesPrice']:,.2f} kr")
|
|
print(f"Price incl VAT: {offer['totals']['salesPriceWithVat']:,.2f} kr")
|
|
print(f"Created: {offer['createdAt']}")
|
|
print("=" * 80)
|
|
return offer['id']
|
|
else:
|
|
print(f"❌ Fejl: {data.get('error')}")
|
|
return None
|
|
else:
|
|
print(f"❌ HTTP fejl {response.status_code}")
|
|
print(response.text)
|
|
return None
|
|
|
|
def verify_in_database(offer_id):
|
|
"""Verificer at tilbud er gemt i database"""
|
|
if not offer_id:
|
|
return
|
|
|
|
print("\n" + "=" * 80)
|
|
print("TEST 3: Verificer i database")
|
|
print("=" * 80)
|
|
|
|
conn = mysql.connector.connect(**db_config)
|
|
cursor = conn.cursor(dictionary=True)
|
|
|
|
try:
|
|
cursor.execute("""
|
|
SELECT
|
|
id,
|
|
project_id,
|
|
ordrestyring_offer_id,
|
|
ordrestyring_offer_number,
|
|
ordrestyring_status,
|
|
ordrestyring_sent_at
|
|
FROM generated_quotes
|
|
WHERE ordrestyring_offer_id = %s
|
|
""", (offer_id,))
|
|
|
|
result = cursor.fetchone()
|
|
if result:
|
|
print("\n✅ Tilbud fundet i database!\n")
|
|
for key, value in result.items():
|
|
print(f"{key}: {value}")
|
|
else:
|
|
print(f"❌ Tilbud med offer_id {offer_id} ikke fundet i database")
|
|
|
|
except Exception as e:
|
|
print(f"❌ Database fejl: {e}")
|
|
finally:
|
|
cursor.close()
|
|
conn.close()
|
|
|
|
def main():
|
|
print("\n" + "=" * 80)
|
|
print(" RØSEVANGEN 44 - ORDRESTYRING INTEGRATION TEST")
|
|
print("=" * 80)
|
|
print(f"\nProjekt: Komplet tagudskiftning - Røsevangen 44")
|
|
print(f"Kunde: Alexander Warme (ID: {CUSTOMER_ID})")
|
|
print(f"Projekt ID: {PROJECT_ID}")
|
|
|
|
# Step 1: Indsæt data
|
|
print("\n" + "-" * 80)
|
|
print("STEP 1: Indsæt projekt data i database")
|
|
print("-" * 80)
|
|
calculation_id = insert_project_data()
|
|
if not calculation_id:
|
|
print("❌ Kunne ikke indsætte data - afbryder")
|
|
return
|
|
|
|
# Step 2: Preview
|
|
if not test_preview():
|
|
print("❌ Preview fejlede - afbryder")
|
|
return
|
|
|
|
# Step 3: Send til Ordrestyring
|
|
offer_id = send_to_ordrestyring()
|
|
|
|
# Step 4: Verificer i database
|
|
if offer_id:
|
|
verify_in_database(offer_id)
|
|
|
|
print("\n" + "=" * 80)
|
|
print("✅ TEST FÆRDIG!")
|
|
print("=" * 80)
|
|
print("\nNæste skridt:")
|
|
print(" 1. Check tilbuddet i Ordrestyring systemet")
|
|
print(" 2. Verificer at status er 'Tilbudsgiver Oprettet Tilbud'")
|
|
print(" 3. Åbn 'Noter' og check at interne beregninger er der")
|
|
print(" 4. Verificer at kunde-beskrivelse IKKE viser overhead/fortjeneste")
|
|
print("=" * 80 + "\n")
|
|
|
|
if __name__ == '__main__':
|
|
try:
|
|
main()
|
|
except KeyboardInterrupt:
|
|
print("\n\n⏹️ Test afbrudt af bruger")
|
|
except Exception as e:
|
|
print(f"\n❌ Uventet fejl: {e}")
|
|
import traceback
|
|
traceback.print_exc()
|