feat(timetracking): Implement time tracking module with frontend views, HTML templates, and database migrations
- Added FastAPI router for time tracking views including dashboard, wizard, and orders.
- Created HTML templates for the time tracking wizard with responsive design and Bootstrap integration.
- Developed SQL migration script for the time tracking module, including tables for customers, cases, time entries, orders, and audit logs.
- Introduced a script to list all registered routes, focusing on time tracking routes.
- Added test script to verify route registration and specifically check for time tracking routes.
2025-12-09 22:46:30 +01:00
|
|
|
|
<!DOCTYPE html>
|
|
|
|
|
|
<html lang="da">
|
|
|
|
|
|
<head>
|
|
|
|
|
|
<meta charset="UTF-8">
|
|
|
|
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
|
|
|
|
<title>Ordrer - BMC Hub</title>
|
|
|
|
|
|
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet">
|
|
|
|
|
|
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.1/font/bootstrap-icons.css">
|
|
|
|
|
|
<style>
|
|
|
|
|
|
:root {
|
|
|
|
|
|
--bg-body: #f8f9fa;
|
|
|
|
|
|
--bg-card: #ffffff;
|
|
|
|
|
|
--text-primary: #2c3e50;
|
|
|
|
|
|
--text-secondary: #6c757d;
|
|
|
|
|
|
--accent: #0f4c75;
|
|
|
|
|
|
--accent-light: #eef2f5;
|
|
|
|
|
|
--success: #28a745;
|
|
|
|
|
|
--warning: #ffc107;
|
|
|
|
|
|
--danger: #dc3545;
|
|
|
|
|
|
--border-radius: 12px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
[data-theme="dark"] {
|
|
|
|
|
|
--bg-body: #1a1a1a;
|
|
|
|
|
|
--bg-card: #2d2d2d;
|
|
|
|
|
|
--text-primary: #e4e4e4;
|
|
|
|
|
|
--text-secondary: #a0a0a0;
|
|
|
|
|
|
--accent-light: #1e3a52;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
body {
|
|
|
|
|
|
background-color: var(--bg-body);
|
|
|
|
|
|
color: var(--text-primary);
|
|
|
|
|
|
font-family: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif;
|
|
|
|
|
|
padding-top: 80px;
|
|
|
|
|
|
transition: background-color 0.3s, color 0.3s;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.navbar {
|
|
|
|
|
|
background: var(--bg-card);
|
|
|
|
|
|
box-shadow: 0 2px 15px rgba(0,0,0,0.1);
|
|
|
|
|
|
padding: 1rem 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.navbar-brand {
|
|
|
|
|
|
font-weight: 700;
|
|
|
|
|
|
color: var(--accent);
|
|
|
|
|
|
font-size: 1.25rem;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.nav-link {
|
|
|
|
|
|
color: var(--text-secondary);
|
|
|
|
|
|
padding: 0.6rem 1.2rem !important;
|
|
|
|
|
|
border-radius: var(--border-radius);
|
|
|
|
|
|
transition: all 0.2s;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-12-10 18:29:13 +01:00
|
|
|
|
.nav-link:hover {
|
feat(timetracking): Implement time tracking module with frontend views, HTML templates, and database migrations
- Added FastAPI router for time tracking views including dashboard, wizard, and orders.
- Created HTML templates for the time tracking wizard with responsive design and Bootstrap integration.
- Developed SQL migration script for the time tracking module, including tables for customers, cases, time entries, orders, and audit logs.
- Introduced a script to list all registered routes, focusing on time tracking routes.
- Added test script to verify route registration and specifically check for time tracking routes.
2025-12-09 22:46:30 +01:00
|
|
|
|
background-color: var(--accent-light);
|
|
|
|
|
|
color: var(--accent);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-12-10 18:29:13 +01:00
|
|
|
|
.nav-link.active {
|
|
|
|
|
|
background-color: var(--accent);
|
|
|
|
|
|
color: white;
|
|
|
|
|
|
font-weight: 600;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
feat(timetracking): Implement time tracking module with frontend views, HTML templates, and database migrations
- Added FastAPI router for time tracking views including dashboard, wizard, and orders.
- Created HTML templates for the time tracking wizard with responsive design and Bootstrap integration.
- Developed SQL migration script for the time tracking module, including tables for customers, cases, time entries, orders, and audit logs.
- Introduced a script to list all registered routes, focusing on time tracking routes.
- Added test script to verify route registration and specifically check for time tracking routes.
2025-12-09 22:46:30 +01:00
|
|
|
|
.card {
|
|
|
|
|
|
border: none;
|
|
|
|
|
|
border-radius: var(--border-radius);
|
|
|
|
|
|
box-shadow: 0 2px 15px rgba(0,0,0,0.05);
|
|
|
|
|
|
background: var(--bg-card);
|
|
|
|
|
|
margin-bottom: 1.5rem;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.table {
|
|
|
|
|
|
background: var(--bg-card);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.table th {
|
|
|
|
|
|
font-weight: 600;
|
|
|
|
|
|
color: var(--text-secondary);
|
|
|
|
|
|
font-size: 0.85rem;
|
|
|
|
|
|
text-transform: uppercase;
|
|
|
|
|
|
border-bottom: 2px solid var(--accent-light);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.order-row {
|
|
|
|
|
|
cursor: pointer;
|
|
|
|
|
|
transition: background-color 0.2s;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.order-row:hover {
|
|
|
|
|
|
background-color: var(--accent-light);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.order-details {
|
|
|
|
|
|
background: var(--accent-light);
|
|
|
|
|
|
border-radius: var(--border-radius);
|
|
|
|
|
|
padding: 1.5rem;
|
|
|
|
|
|
margin-top: 1rem;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.line-item {
|
|
|
|
|
|
padding: 0.75rem;
|
|
|
|
|
|
background: var(--bg-card);
|
|
|
|
|
|
border-radius: 8px;
|
|
|
|
|
|
margin-bottom: 0.5rem;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.modal-body .info-row {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
justify-content: space-between;
|
|
|
|
|
|
padding: 0.75rem 0;
|
|
|
|
|
|
border-bottom: 1px solid var(--accent-light);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.modal-body .info-row:last-child {
|
|
|
|
|
|
border-bottom: none;
|
|
|
|
|
|
}
|
|
|
|
|
|
</style>
|
|
|
|
|
|
</head>
|
|
|
|
|
|
<body>
|
|
|
|
|
|
<!-- Navigation -->
|
|
|
|
|
|
<nav class="navbar navbar-expand-lg fixed-top">
|
|
|
|
|
|
<div class="container-fluid">
|
|
|
|
|
|
<a class="navbar-brand" href="/dashboard">
|
|
|
|
|
|
<i class="bi bi-grid-3x3-gap-fill"></i> BMC Hub
|
|
|
|
|
|
</a>
|
|
|
|
|
|
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav">
|
|
|
|
|
|
<span class="navbar-toggler-icon"></span>
|
|
|
|
|
|
</button>
|
|
|
|
|
|
<div class="collapse navbar-collapse" id="navbarNav">
|
|
|
|
|
|
<ul class="navbar-nav">
|
|
|
|
|
|
<li class="nav-item">
|
|
|
|
|
|
<a class="nav-link" href="/dashboard">Dashboard</a>
|
|
|
|
|
|
</li>
|
|
|
|
|
|
<li class="nav-item">
|
2025-12-10 18:29:13 +01:00
|
|
|
|
<a class="nav-link" href="/timetracking">
|
|
|
|
|
|
<i class="bi bi-clock-history"></i> Oversigt
|
|
|
|
|
|
</a>
|
|
|
|
|
|
</li>
|
|
|
|
|
|
<li class="nav-item">
|
|
|
|
|
|
<a class="nav-link" href="/timetracking/wizard">
|
|
|
|
|
|
<i class="bi bi-check-circle"></i> Godkend Tider
|
|
|
|
|
|
</a>
|
feat(timetracking): Implement time tracking module with frontend views, HTML templates, and database migrations
- Added FastAPI router for time tracking views including dashboard, wizard, and orders.
- Created HTML templates for the time tracking wizard with responsive design and Bootstrap integration.
- Developed SQL migration script for the time tracking module, including tables for customers, cases, time entries, orders, and audit logs.
- Introduced a script to list all registered routes, focusing on time tracking routes.
- Added test script to verify route registration and specifically check for time tracking routes.
2025-12-09 22:46:30 +01:00
|
|
|
|
</li>
|
|
|
|
|
|
<li class="nav-item">
|
2025-12-10 18:29:13 +01:00
|
|
|
|
<a class="nav-link" href="/timetracking/customers">
|
|
|
|
|
|
<i class="bi bi-building"></i> Kunder & Priser
|
|
|
|
|
|
</a>
|
|
|
|
|
|
</li>
|
|
|
|
|
|
<li class="nav-item">
|
|
|
|
|
|
<a class="nav-link active" href="/timetracking/orders">
|
|
|
|
|
|
<i class="bi bi-receipt"></i> Ordrer
|
feat(timetracking): Implement time tracking module with frontend views, HTML templates, and database migrations
- Added FastAPI router for time tracking views including dashboard, wizard, and orders.
- Created HTML templates for the time tracking wizard with responsive design and Bootstrap integration.
- Developed SQL migration script for the time tracking module, including tables for customers, cases, time entries, orders, and audit logs.
- Introduced a script to list all registered routes, focusing on time tracking routes.
- Added test script to verify route registration and specifically check for time tracking routes.
2025-12-09 22:46:30 +01:00
|
|
|
|
</a>
|
|
|
|
|
|
</li>
|
|
|
|
|
|
</ul>
|
|
|
|
|
|
<ul class="navbar-nav ms-auto">
|
|
|
|
|
|
<li class="nav-item">
|
|
|
|
|
|
<button class="btn btn-link nav-link" onclick="toggleTheme()">
|
|
|
|
|
|
<i class="bi bi-moon-fill" id="theme-icon"></i>
|
|
|
|
|
|
</button>
|
|
|
|
|
|
</li>
|
|
|
|
|
|
</ul>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</nav>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- Main Content -->
|
|
|
|
|
|
<div class="container-fluid py-4">
|
|
|
|
|
|
<!-- Header -->
|
|
|
|
|
|
<div class="row mb-4">
|
|
|
|
|
|
<div class="col-12">
|
|
|
|
|
|
<div class="d-flex justify-content-between align-items-center">
|
|
|
|
|
|
<div>
|
|
|
|
|
|
<h1 class="mb-1">
|
|
|
|
|
|
<i class="bi bi-receipt text-primary"></i> Ordrer
|
|
|
|
|
|
</h1>
|
|
|
|
|
|
<p class="text-muted mb-0">Oversigt over genererede ordrer og eksport til e-conomic</p>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<a href="/timetracking" class="btn btn-outline-secondary">
|
|
|
|
|
|
<i class="bi bi-arrow-left"></i> Tilbage
|
|
|
|
|
|
</a>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- Safety Banner -->
|
|
|
|
|
|
<div class="row mb-4">
|
|
|
|
|
|
<div class="col-12">
|
|
|
|
|
|
<div class="alert alert-warning d-flex align-items-center" role="alert">
|
|
|
|
|
|
<i class="bi bi-shield-exclamation me-2"></i>
|
|
|
|
|
|
<div>
|
|
|
|
|
|
<strong>DRY-RUN Mode Aktiv</strong> -
|
|
|
|
|
|
Eksport til e-conomic er i test-mode. Fakturaer oprettes ikke i e-conomic.
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- Orders Table -->
|
|
|
|
|
|
<div class="row">
|
|
|
|
|
|
<div class="col-12">
|
|
|
|
|
|
<div class="card">
|
|
|
|
|
|
<div class="card-header bg-white d-flex justify-content-between align-items-center">
|
|
|
|
|
|
<h5 class="mb-0">Alle Ordrer</h5>
|
|
|
|
|
|
<button class="btn btn-sm btn-outline-primary" onclick="loadOrders()">
|
|
|
|
|
|
<i class="bi bi-arrow-clockwise"></i> Opdater
|
|
|
|
|
|
</button>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="card-body">
|
|
|
|
|
|
<div id="loading" class="text-center py-4">
|
|
|
|
|
|
<div class="spinner-border text-primary" role="status">
|
|
|
|
|
|
<span class="visually-hidden">Indlæser...</span>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<div id="orders-table" class="d-none">
|
|
|
|
|
|
<table class="table table-hover">
|
|
|
|
|
|
<thead>
|
|
|
|
|
|
<tr>
|
|
|
|
|
|
<th>Ordrenr.</th>
|
|
|
|
|
|
<th>Kunde</th>
|
|
|
|
|
|
<th>Dato</th>
|
|
|
|
|
|
<th class="text-center">Linjer</th>
|
|
|
|
|
|
<th class="text-end">Total</th>
|
|
|
|
|
|
<th class="text-center">Status</th>
|
|
|
|
|
|
<th class="text-end">Handlinger</th>
|
|
|
|
|
|
</tr>
|
|
|
|
|
|
</thead>
|
|
|
|
|
|
<tbody id="orders-tbody">
|
|
|
|
|
|
</tbody>
|
|
|
|
|
|
</table>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<div id="no-orders" class="text-center py-5 d-none">
|
|
|
|
|
|
<i class="bi bi-inbox text-muted" style="font-size: 3rem;"></i>
|
|
|
|
|
|
<p class="text-muted mt-3">Ingen ordrer endnu</p>
|
|
|
|
|
|
<a href="/timetracking" class="btn btn-primary">
|
|
|
|
|
|
<i class="bi bi-arrow-left"></i> Godkend tider først
|
|
|
|
|
|
</a>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- Order Details Modal -->
|
|
|
|
|
|
<div class="modal fade" id="orderModal" tabindex="-1">
|
|
|
|
|
|
<div class="modal-dialog modal-lg">
|
|
|
|
|
|
<div class="modal-content">
|
|
|
|
|
|
<div class="modal-header">
|
|
|
|
|
|
<h5 class="modal-title">
|
|
|
|
|
|
<i class="bi bi-receipt"></i> Ordre Detaljer
|
|
|
|
|
|
</h5>
|
|
|
|
|
|
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="modal-body">
|
|
|
|
|
|
<div id="order-details-content">
|
|
|
|
|
|
<!-- Will be populated dynamically -->
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="modal-footer">
|
|
|
|
|
|
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Luk</button>
|
|
|
|
|
|
<button type="button" class="btn btn-success" id="export-order-btn" onclick="exportCurrentOrder()">
|
|
|
|
|
|
<i class="bi bi-cloud-upload"></i> Eksporter til e-conomic
|
|
|
|
|
|
</button>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.bundle.min.js"></script>
|
|
|
|
|
|
<script>
|
|
|
|
|
|
let currentOrderId = null;
|
|
|
|
|
|
let orderModal = null;
|
|
|
|
|
|
|
|
|
|
|
|
// Theme toggle
|
|
|
|
|
|
function toggleTheme() {
|
|
|
|
|
|
const html = document.documentElement;
|
|
|
|
|
|
const icon = document.getElementById('theme-icon');
|
|
|
|
|
|
if (html.getAttribute('data-theme') === 'dark') {
|
|
|
|
|
|
html.removeAttribute('data-theme');
|
|
|
|
|
|
icon.className = 'bi bi-moon-fill';
|
|
|
|
|
|
localStorage.setItem('theme', 'light');
|
|
|
|
|
|
} else {
|
|
|
|
|
|
html.setAttribute('data-theme', 'dark');
|
|
|
|
|
|
icon.className = 'bi bi-sun-fill';
|
|
|
|
|
|
localStorage.setItem('theme', 'dark');
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Load saved theme
|
|
|
|
|
|
if (localStorage.getItem('theme') === 'dark') {
|
|
|
|
|
|
document.documentElement.setAttribute('data-theme', 'dark');
|
|
|
|
|
|
document.getElementById('theme-icon').className = 'bi bi-sun-fill';
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Initialize modal
|
|
|
|
|
|
document.addEventListener('DOMContentLoaded', function() {
|
|
|
|
|
|
orderModal = new bootstrap.Modal(document.getElementById('orderModal'));
|
|
|
|
|
|
loadOrders();
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
// Load all orders
|
|
|
|
|
|
async function loadOrders() {
|
|
|
|
|
|
document.getElementById('loading').classList.remove('d-none');
|
|
|
|
|
|
document.getElementById('orders-table').classList.add('d-none');
|
|
|
|
|
|
document.getElementById('no-orders').classList.add('d-none');
|
|
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
|
const response = await fetch('/api/v1/timetracking/orders');
|
|
|
|
|
|
const orders = await response.json();
|
|
|
|
|
|
|
|
|
|
|
|
if (orders.length === 0) {
|
|
|
|
|
|
document.getElementById('loading').classList.add('d-none');
|
|
|
|
|
|
document.getElementById('no-orders').classList.remove('d-none');
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const tbody = document.getElementById('orders-tbody');
|
|
|
|
|
|
tbody.innerHTML = orders.map(order => {
|
|
|
|
|
|
const statusBadge = getStatusBadge(order);
|
|
|
|
|
|
const exportedIcon = order.exported_to_economic
|
|
|
|
|
|
? '<i class="bi bi-check-circle text-success" title="Eksporteret"></i>'
|
|
|
|
|
|
: '';
|
|
|
|
|
|
|
|
|
|
|
|
return `
|
|
|
|
|
|
<tr class="order-row" onclick="viewOrder(${order.id})">
|
|
|
|
|
|
<td>
|
|
|
|
|
|
<strong>${order.order_number}</strong>
|
|
|
|
|
|
${exportedIcon}
|
|
|
|
|
|
</td>
|
|
|
|
|
|
<td>${order.customer_name}</td>
|
|
|
|
|
|
<td>${new Date(order.order_date).toLocaleDateString('da-DK')}</td>
|
|
|
|
|
|
<td class="text-center">${order.line_count || 0}</td>
|
|
|
|
|
|
<td class="text-end"><strong>${parseFloat(order.total_amount).toFixed(2)} DKK</strong></td>
|
|
|
|
|
|
<td class="text-center">${statusBadge}</td>
|
|
|
|
|
|
<td class="text-end">
|
|
|
|
|
|
<button class="btn btn-sm btn-outline-primary"
|
|
|
|
|
|
onclick="event.stopPropagation(); viewOrder(${order.id})">
|
|
|
|
|
|
<i class="bi bi-eye"></i>
|
|
|
|
|
|
</button>
|
|
|
|
|
|
${!order.exported_to_economic ? `
|
|
|
|
|
|
<button class="btn btn-sm btn-success"
|
|
|
|
|
|
onclick="event.stopPropagation(); exportOrder(${order.id})">
|
|
|
|
|
|
<i class="bi bi-cloud-upload"></i>
|
|
|
|
|
|
</button>
|
|
|
|
|
|
` : ''}
|
|
|
|
|
|
</td>
|
|
|
|
|
|
</tr>
|
|
|
|
|
|
`;
|
|
|
|
|
|
}).join('');
|
|
|
|
|
|
|
|
|
|
|
|
document.getElementById('loading').classList.add('d-none');
|
|
|
|
|
|
document.getElementById('orders-table').classList.remove('d-none');
|
|
|
|
|
|
|
|
|
|
|
|
} catch (error) {
|
|
|
|
|
|
console.error('Error loading orders:', error);
|
|
|
|
|
|
document.getElementById('loading').innerHTML = `
|
|
|
|
|
|
<div class="alert alert-danger">
|
|
|
|
|
|
Fejl ved indlæsning: ${error.message}
|
|
|
|
|
|
</div>
|
|
|
|
|
|
`;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Get status badge
|
|
|
|
|
|
function getStatusBadge(order) {
|
|
|
|
|
|
if (order.cancelled_at) {
|
|
|
|
|
|
return '<span class="badge bg-danger">Annulleret</span>';
|
|
|
|
|
|
}
|
|
|
|
|
|
if (order.exported_to_economic) {
|
|
|
|
|
|
return '<span class="badge bg-success">Eksporteret</span>';
|
|
|
|
|
|
}
|
|
|
|
|
|
return '<span class="badge bg-warning">Pending</span>';
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// View order details
|
|
|
|
|
|
async function viewOrder(orderId) {
|
|
|
|
|
|
currentOrderId = orderId;
|
|
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
|
const response = await fetch(`/api/v1/timetracking/orders/${orderId}`);
|
|
|
|
|
|
const order = await response.json();
|
|
|
|
|
|
|
|
|
|
|
|
const content = document.getElementById('order-details-content');
|
|
|
|
|
|
content.innerHTML = `
|
|
|
|
|
|
<div class="info-row">
|
|
|
|
|
|
<span class="fw-bold">Ordrenummer:</span>
|
|
|
|
|
|
<span>${order.order_number}</span>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="info-row">
|
|
|
|
|
|
<span class="fw-bold">Kunde:</span>
|
|
|
|
|
|
<span>${order.customer_name}</span>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="info-row">
|
|
|
|
|
|
<span class="fw-bold">Dato:</span>
|
|
|
|
|
|
<span>${new Date(order.order_date).toLocaleDateString('da-DK')}</span>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="info-row">
|
|
|
|
|
|
<span class="fw-bold">Total:</span>
|
|
|
|
|
|
<span class="fs-5 fw-bold text-primary">${parseFloat(order.total_amount).toFixed(2)} DKK</span>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<hr class="my-3">
|
|
|
|
|
|
|
|
|
|
|
|
<h6 class="mb-3">Ordrelinjer:</h6>
|
2025-12-10 18:29:13 +01:00
|
|
|
|
${order.lines.map(line => {
|
|
|
|
|
|
// Parse data
|
|
|
|
|
|
const caseMatch = line.description.match(/CC(\d+)/);
|
|
|
|
|
|
const caseTitle = line.description.split(' - ').slice(1).join(' - ') || line.description;
|
|
|
|
|
|
const hours = parseFloat(line.quantity);
|
|
|
|
|
|
const unitPrice = parseFloat(line.unit_price);
|
|
|
|
|
|
const total = parseFloat(line.line_total);
|
|
|
|
|
|
const date = new Date(line.time_date).toLocaleDateString('da-DK');
|
|
|
|
|
|
|
|
|
|
|
|
// Extract contact name from case_contact if available
|
|
|
|
|
|
const contactName = line.case_contact || 'Ingen kontakt';
|
|
|
|
|
|
|
|
|
|
|
|
// Check if it's an on-site visit (udkørsel)
|
|
|
|
|
|
const isOnSite = line.description.toLowerCase().includes('udkørsel') ||
|
|
|
|
|
|
line.description.toLowerCase().includes('on-site');
|
|
|
|
|
|
|
|
|
|
|
|
return `
|
|
|
|
|
|
<div class="line-item mb-3 p-3" style="border: 1px solid #dee2e6; border-radius: 8px;">
|
|
|
|
|
|
<div class="d-flex justify-content-between align-items-start mb-2">
|
|
|
|
|
|
<div class="flex-grow-1">
|
|
|
|
|
|
<div class="d-flex align-items-center gap-2 mb-1">
|
|
|
|
|
|
${caseMatch ? `<span class="badge bg-secondary">${caseMatch[0]}</span>` : ''}
|
|
|
|
|
|
<span class="fw-bold">${hours.toFixed(1)} timer</span>
|
|
|
|
|
|
<span class="text-muted">×</span>
|
|
|
|
|
|
<span>${unitPrice.toFixed(2)} DKK</span>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="fw-bold text-uppercase mb-1" style="font-size: 0.95rem;">
|
|
|
|
|
|
${caseTitle}
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="text-muted small">
|
|
|
|
|
|
${date} - ${contactName}${isOnSite ? ' <span class="badge bg-info">Udkørsel</span>' : ''}
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="text-end">
|
|
|
|
|
|
<div class="fs-5 fw-bold text-primary">${total.toFixed(2)} DKK</div>
|
|
|
|
|
|
</div>
|
feat(timetracking): Implement time tracking module with frontend views, HTML templates, and database migrations
- Added FastAPI router for time tracking views including dashboard, wizard, and orders.
- Created HTML templates for the time tracking wizard with responsive design and Bootstrap integration.
- Developed SQL migration script for the time tracking module, including tables for customers, cases, time entries, orders, and audit logs.
- Introduced a script to list all registered routes, focusing on time tracking routes.
- Added test script to verify route registration and specifically check for time tracking routes.
2025-12-09 22:46:30 +01:00
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
2025-12-10 18:29:13 +01:00
|
|
|
|
`;
|
|
|
|
|
|
}).join('')}
|
feat(timetracking): Implement time tracking module with frontend views, HTML templates, and database migrations
- Added FastAPI router for time tracking views including dashboard, wizard, and orders.
- Created HTML templates for the time tracking wizard with responsive design and Bootstrap integration.
- Developed SQL migration script for the time tracking module, including tables for customers, cases, time entries, orders, and audit logs.
- Introduced a script to list all registered routes, focusing on time tracking routes.
- Added test script to verify route registration and specifically check for time tracking routes.
2025-12-09 22:46:30 +01:00
|
|
|
|
|
2025-12-10 18:29:13 +01:00
|
|
|
|
${order.economic_draft_id ? `
|
feat(timetracking): Implement time tracking module with frontend views, HTML templates, and database migrations
- Added FastAPI router for time tracking views including dashboard, wizard, and orders.
- Created HTML templates for the time tracking wizard with responsive design and Bootstrap integration.
- Developed SQL migration script for the time tracking module, including tables for customers, cases, time entries, orders, and audit logs.
- Introduced a script to list all registered routes, focusing on time tracking routes.
- Added test script to verify route registration and specifically check for time tracking routes.
2025-12-09 22:46:30 +01:00
|
|
|
|
<div class="alert alert-success mt-3 mb-0">
|
|
|
|
|
|
<i class="bi bi-check-circle"></i>
|
|
|
|
|
|
Eksporteret til e-conomic den ${new Date(order.exported_at).toLocaleDateString('da-DK')}
|
2025-12-10 18:29:13 +01:00
|
|
|
|
<br>Draft Order nr.: ${order.economic_draft_id}
|
|
|
|
|
|
${order.economic_order_number ? `<br>e-conomic ordre nr.: ${order.economic_order_number}` : ''}
|
feat(timetracking): Implement time tracking module with frontend views, HTML templates, and database migrations
- Added FastAPI router for time tracking views including dashboard, wizard, and orders.
- Created HTML templates for the time tracking wizard with responsive design and Bootstrap integration.
- Developed SQL migration script for the time tracking module, including tables for customers, cases, time entries, orders, and audit logs.
- Introduced a script to list all registered routes, focusing on time tracking routes.
- Added test script to verify route registration and specifically check for time tracking routes.
2025-12-09 22:46:30 +01:00
|
|
|
|
</div>
|
|
|
|
|
|
` : ''}
|
|
|
|
|
|
`;
|
|
|
|
|
|
|
|
|
|
|
|
// Update export button
|
|
|
|
|
|
const exportBtn = document.getElementById('export-order-btn');
|
2025-12-10 18:29:13 +01:00
|
|
|
|
if (order.economic_draft_id) {
|
|
|
|
|
|
exportBtn.disabled = false;
|
|
|
|
|
|
exportBtn.innerHTML = '<i class="bi bi-arrow-repeat"></i> Re-eksporter (force)';
|
|
|
|
|
|
exportBtn.onclick = () => {
|
|
|
|
|
|
if (confirm('Re-eksporter ordre til e-conomic?\n\nDette vil overskrive den eksisterende draft order.')) {
|
|
|
|
|
|
exportOrderForce(currentOrderId);
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
feat(timetracking): Implement time tracking module with frontend views, HTML templates, and database migrations
- Added FastAPI router for time tracking views including dashboard, wizard, and orders.
- Created HTML templates for the time tracking wizard with responsive design and Bootstrap integration.
- Developed SQL migration script for the time tracking module, including tables for customers, cases, time entries, orders, and audit logs.
- Introduced a script to list all registered routes, focusing on time tracking routes.
- Added test script to verify route registration and specifically check for time tracking routes.
2025-12-09 22:46:30 +01:00
|
|
|
|
} else {
|
|
|
|
|
|
exportBtn.disabled = false;
|
|
|
|
|
|
exportBtn.innerHTML = '<i class="bi bi-cloud-upload"></i> Eksporter til e-conomic';
|
2025-12-10 18:29:13 +01:00
|
|
|
|
exportBtn.onclick = exportCurrentOrder;
|
feat(timetracking): Implement time tracking module with frontend views, HTML templates, and database migrations
- Added FastAPI router for time tracking views including dashboard, wizard, and orders.
- Created HTML templates for the time tracking wizard with responsive design and Bootstrap integration.
- Developed SQL migration script for the time tracking module, including tables for customers, cases, time entries, orders, and audit logs.
- Introduced a script to list all registered routes, focusing on time tracking routes.
- Added test script to verify route registration and specifically check for time tracking routes.
2025-12-09 22:46:30 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
orderModal.show();
|
|
|
|
|
|
|
|
|
|
|
|
} catch (error) {
|
|
|
|
|
|
alert('Fejl ved indlæsning af ordre: ' + error.message);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Export order
|
|
|
|
|
|
async function exportOrder(orderId) {
|
2025-12-10 18:29:13 +01:00
|
|
|
|
if (!confirm('Eksporter ordre til e-conomic?\n\nDette opretter en kladde-ordre i e-conomic.')) {
|
feat(timetracking): Implement time tracking module with frontend views, HTML templates, and database migrations
- Added FastAPI router for time tracking views including dashboard, wizard, and orders.
- Created HTML templates for the time tracking wizard with responsive design and Bootstrap integration.
- Developed SQL migration script for the time tracking module, including tables for customers, cases, time entries, orders, and audit logs.
- Introduced a script to list all registered routes, focusing on time tracking routes.
- Added test script to verify route registration and specifically check for time tracking routes.
2025-12-09 22:46:30 +01:00
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
try {
|
2025-12-10 18:29:13 +01:00
|
|
|
|
const response = await fetch(`/api/v1/timetracking/export`, {
|
|
|
|
|
|
method: 'POST',
|
|
|
|
|
|
headers: {
|
|
|
|
|
|
'Content-Type': 'application/json'
|
|
|
|
|
|
},
|
|
|
|
|
|
body: JSON.stringify({
|
|
|
|
|
|
order_id: orderId,
|
|
|
|
|
|
force: false
|
|
|
|
|
|
})
|
feat(timetracking): Implement time tracking module with frontend views, HTML templates, and database migrations
- Added FastAPI router for time tracking views including dashboard, wizard, and orders.
- Created HTML templates for the time tracking wizard with responsive design and Bootstrap integration.
- Developed SQL migration script for the time tracking module, including tables for customers, cases, time entries, orders, and audit logs.
- Introduced a script to list all registered routes, focusing on time tracking routes.
- Added test script to verify route registration and specifically check for time tracking routes.
2025-12-09 22:46:30 +01:00
|
|
|
|
});
|
2025-12-10 18:29:13 +01:00
|
|
|
|
|
|
|
|
|
|
if (!response.ok) {
|
|
|
|
|
|
const errorData = await response.json();
|
|
|
|
|
|
throw new Error(errorData.detail || 'Export failed');
|
|
|
|
|
|
}
|
|
|
|
|
|
|
feat(timetracking): Implement time tracking module with frontend views, HTML templates, and database migrations
- Added FastAPI router for time tracking views including dashboard, wizard, and orders.
- Created HTML templates for the time tracking wizard with responsive design and Bootstrap integration.
- Developed SQL migration script for the time tracking module, including tables for customers, cases, time entries, orders, and audit logs.
- Introduced a script to list all registered routes, focusing on time tracking routes.
- Added test script to verify route registration and specifically check for time tracking routes.
2025-12-09 22:46:30 +01:00
|
|
|
|
const result = await response.json();
|
|
|
|
|
|
|
|
|
|
|
|
if (result.dry_run) {
|
2025-12-10 18:29:13 +01:00
|
|
|
|
alert(`DRY-RUN MODE:\n\n${result.message}\n\nDetails:\n- Ordre: ${result.details.order_number}\n- Kunde: ${result.details.customer_name}\n- Total: ${result.details.total_amount} DKK\n- Linjer: ${result.details.line_count}\n\n⚠️ Ingen ændringer er foretaget i e-conomic (DRY-RUN mode aktiveret).`);
|
|
|
|
|
|
} else if (result.success) {
|
|
|
|
|
|
alert(`✅ Ordre eksporteret til e-conomic!\n\n- Draft Order nr.: ${result.economic_draft_id}\n- e-conomic ordre nr.: ${result.economic_order_number}\n\n${result.message}`);
|
|
|
|
|
|
loadOrders();
|
|
|
|
|
|
if (orderModal._isShown) {
|
|
|
|
|
|
orderModal.hide();
|
|
|
|
|
|
}
|
feat(timetracking): Implement time tracking module with frontend views, HTML templates, and database migrations
- Added FastAPI router for time tracking views including dashboard, wizard, and orders.
- Created HTML templates for the time tracking wizard with responsive design and Bootstrap integration.
- Developed SQL migration script for the time tracking module, including tables for customers, cases, time entries, orders, and audit logs.
- Introduced a script to list all registered routes, focusing on time tracking routes.
- Added test script to verify route registration and specifically check for time tracking routes.
2025-12-09 22:46:30 +01:00
|
|
|
|
} else {
|
2025-12-10 18:29:13 +01:00
|
|
|
|
throw new Error(result.message || 'Export failed');
|
feat(timetracking): Implement time tracking module with frontend views, HTML templates, and database migrations
- Added FastAPI router for time tracking views including dashboard, wizard, and orders.
- Created HTML templates for the time tracking wizard with responsive design and Bootstrap integration.
- Developed SQL migration script for the time tracking module, including tables for customers, cases, time entries, orders, and audit logs.
- Introduced a script to list all registered routes, focusing on time tracking routes.
- Added test script to verify route registration and specifically check for time tracking routes.
2025-12-09 22:46:30 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
} catch (error) {
|
|
|
|
|
|
alert('Fejl ved eksport: ' + error.message);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Export current order from modal
|
|
|
|
|
|
function exportCurrentOrder() {
|
|
|
|
|
|
if (currentOrderId) {
|
|
|
|
|
|
exportOrder(currentOrderId);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-12-10 18:29:13 +01:00
|
|
|
|
|
|
|
|
|
|
// Force re-export order
|
|
|
|
|
|
async function exportOrderForce(orderId) {
|
|
|
|
|
|
try {
|
|
|
|
|
|
const response = await fetch(`/api/v1/timetracking/export`, {
|
|
|
|
|
|
method: 'POST',
|
|
|
|
|
|
headers: {
|
|
|
|
|
|
'Content-Type': 'application/json'
|
|
|
|
|
|
},
|
|
|
|
|
|
body: JSON.stringify({
|
|
|
|
|
|
order_id: orderId,
|
|
|
|
|
|
force: true
|
|
|
|
|
|
})
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
if (!response.ok) {
|
|
|
|
|
|
const errorData = await response.json();
|
|
|
|
|
|
throw new Error(errorData.detail || 'Export failed');
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const result = await response.json();
|
|
|
|
|
|
|
|
|
|
|
|
if (result.dry_run) {
|
|
|
|
|
|
alert(`DRY-RUN MODE:\n\n${result.message}\n\n⚠️ Ingen ændringer er foretaget i e-conomic (DRY-RUN mode aktiveret).`);
|
|
|
|
|
|
} else if (result.success) {
|
|
|
|
|
|
alert(`✅ Ordre re-eksporteret til e-conomic!\n\n- Draft Order nr.: ${result.economic_draft_id}\n- e-conomic ordre nr.: ${result.economic_order_number}`);
|
|
|
|
|
|
loadOrders();
|
|
|
|
|
|
if (orderModal._isShown) {
|
|
|
|
|
|
orderModal.hide();
|
|
|
|
|
|
}
|
|
|
|
|
|
} else {
|
|
|
|
|
|
throw new Error(result.message || 'Export failed');
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
} catch (error) {
|
|
|
|
|
|
alert('Fejl ved eksport: ' + error.message);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
feat(timetracking): Implement time tracking module with frontend views, HTML templates, and database migrations
- Added FastAPI router for time tracking views including dashboard, wizard, and orders.
- Created HTML templates for the time tracking wizard with responsive design and Bootstrap integration.
- Developed SQL migration script for the time tracking module, including tables for customers, cases, time entries, orders, and audit logs.
- Introduced a script to list all registered routes, focusing on time tracking routes.
- Added test script to verify route registration and specifically check for time tracking routes.
2025-12-09 22:46:30 +01:00
|
|
|
|
</script>
|
|
|
|
|
|
</body>
|
|
|
|
|
|
</html>
|