2026-01-31 23:16:24 +01:00
{% extends "shared/frontend/base.html" %}
{% block title %}Ny Sag - BMC Hub{% endblock %}
{% block extra_css %}
< style >
2026-09-08 01:55:47 +02:00
.cc-panel { border: 1px solid var(--border-color, #dce3eb); border-radius: 10px; margin: 0 0 12px; background: var(--bg-surface, #fff); }
.cc-panel > summary { padding: 14px 16px; cursor: pointer; font-weight: 600; }
.cc-summary { display: block; color: var(--text-secondary, #65758a); font-weight: 400; margin-left: 18px; overflow-wrap: anywhere; }
.cc-panel-body { padding: 8px 16px 16px; }
.cc-panel-body > h5, .cc-panel-body > section > h5, .cc-panel-body > section > hr, #createForm > hr { display: none; }
.cc-types { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; }
.cc-types .btn { min-height: 44px; }
#cc-more > summary { padding: 10px; cursor: pointer; }
.cc-actions { position: sticky; bottom: 55px; z-index: 1020; padding: 16px; border: 1px solid var(--border-color, #dce3eb); border-radius: 10px; background: var(--bg-surface, #fff); box-shadow: 0 -4px 18px #0001; flex-wrap: wrap; }
.cc-workload { margin: 12px 0; padding: 12px; border-radius: 8px; background: var(--bg-hover, #f5f7fa); }
.cc-workload summary { cursor: pointer; }
.cc-work-item { padding: 8px 0; border-bottom: 1px solid var(--border-color, #dce3eb); }
.cc-work-item small { display: block; }
[data-bs-theme="dark"] #createForm .bg-light { background: var(--bg-surface) !important; color: var(--text-primary); }
@media(max-width: 600px) { .cc-actions { bottom: 55px; padding: 10px; gap: 8px !important; } .cc-actions #cc-save { width: 100%; } .cc-actions .btn { padding: 10px 16px !important; } .cc-panel-body { padding: 8px 12px; } }
feat(sag): Add Varekøb & Salg module with database migration and frontend template
- Created a new SQL migration for the sag_salgsvarer table to manage sales and purchase items.
- Implemented a new HTML template for the Varekøb & Salg module, including summary cards and tables for sales and purchases.
- Added JavaScript functions for loading and rendering order data dynamically.
- Introduced a new backend search module for customers, contacts, hardware, and locations with autocomplete functionality.
- Developed an email templates API for managing system and customer-specific email templates.
- Created multiple migrations for Nextcloud instances, cache, audit logs, email templates, sag comments, hardware locations, and billing methods.
- Enhanced the sag module with solutions, order lines, work types, and 2FA support for user authentication.
2026-02-02 20:23:56 +01:00
/* Gradient Header for the Card */
.card-header-custom {
background: linear-gradient(135deg, var(--bmc-blue, #0f4c75) 0%, #3282b8 100%);
color: white;
padding: 1.5rem;
border-top-left-radius: 12px;
border-top-right-radius: 12px;
2026-01-31 23:16:24 +01:00
}
feat(sag): Add Varekøb & Salg module with database migration and frontend template
- Created a new SQL migration for the sag_salgsvarer table to manage sales and purchase items.
- Implemented a new HTML template for the Varekøb & Salg module, including summary cards and tables for sales and purchases.
- Added JavaScript functions for loading and rendering order data dynamically.
- Introduced a new backend search module for customers, contacts, hardware, and locations with autocomplete functionality.
- Developed an email templates API for managing system and customer-specific email templates.
- Created multiple migrations for Nextcloud instances, cache, audit logs, email templates, sag comments, hardware locations, and billing methods.
- Enhanced the sag module with solutions, order lines, work types, and 2FA support for user authentication.
2026-02-02 20:23:56 +01:00
.card-custom {
2026-01-31 23:16:24 +01:00
border: none;
border-radius: 12px;
feat(sag): Add Varekøb & Salg module with database migration and frontend template
- Created a new SQL migration for the sag_salgsvarer table to manage sales and purchase items.
- Implemented a new HTML template for the Varekøb & Salg module, including summary cards and tables for sales and purchases.
- Added JavaScript functions for loading and rendering order data dynamically.
- Introduced a new backend search module for customers, contacts, hardware, and locations with autocomplete functionality.
- Developed an email templates API for managing system and customer-specific email templates.
- Created multiple migrations for Nextcloud instances, cache, audit logs, email templates, sag comments, hardware locations, and billing methods.
- Enhanced the sag module with solutions, order lines, work types, and 2FA support for user authentication.
2026-02-02 20:23:56 +01:00
box-shadow: 0 10px 30px rgba(0,0,0,0.08);
overflow: visible; /* Changed from hidden to visible for shadows/tooltips */
2026-01-31 23:16:24 +01:00
}
feat(sag): Add Varekøb & Salg module with database migration and frontend template
- Created a new SQL migration for the sag_salgsvarer table to manage sales and purchase items.
- Implemented a new HTML template for the Varekøb & Salg module, including summary cards and tables for sales and purchases.
- Added JavaScript functions for loading and rendering order data dynamically.
- Introduced a new backend search module for customers, contacts, hardware, and locations with autocomplete functionality.
- Developed an email templates API for managing system and customer-specific email templates.
- Created multiple migrations for Nextcloud instances, cache, audit logs, email templates, sag comments, hardware locations, and billing methods.
- Enhanced the sag module with solutions, order lines, work types, and 2FA support for user authentication.
2026-02-02 20:23:56 +01:00
.form-label {
2026-01-31 23:16:24 +01:00
font-weight: 600;
feat(sag): Add Varekøb & Salg module with database migration and frontend template
- Created a new SQL migration for the sag_salgsvarer table to manage sales and purchase items.
- Implemented a new HTML template for the Varekøb & Salg module, including summary cards and tables for sales and purchases.
- Added JavaScript functions for loading and rendering order data dynamically.
- Introduced a new backend search module for customers, contacts, hardware, and locations with autocomplete functionality.
- Developed an email templates API for managing system and customer-specific email templates.
- Created multiple migrations for Nextcloud instances, cache, audit logs, email templates, sag comments, hardware locations, and billing methods.
- Enhanced the sag module with solutions, order lines, work types, and 2FA support for user authentication.
2026-02-02 20:23:56 +01:00
color: var(--text-primary);
font-size: 0.9rem;
2026-01-31 23:16:24 +01:00
margin-bottom: 0.5rem;
}
feat(sag): Add Varekøb & Salg module with database migration and frontend template
- Created a new SQL migration for the sag_salgsvarer table to manage sales and purchase items.
- Implemented a new HTML template for the Varekøb & Salg module, including summary cards and tables for sales and purchases.
- Added JavaScript functions for loading and rendering order data dynamically.
- Introduced a new backend search module for customers, contacts, hardware, and locations with autocomplete functionality.
- Developed an email templates API for managing system and customer-specific email templates.
- Created multiple migrations for Nextcloud instances, cache, audit logs, email templates, sag comments, hardware locations, and billing methods.
- Enhanced the sag module with solutions, order lines, work types, and 2FA support for user authentication.
2026-02-02 20:23:56 +01:00
.form-control:focus, .form-select:focus {
border-color: #3282b8;
box-shadow: 0 0 0 0.25rem rgba(50, 130, 184, 0.25);
2026-01-31 23:16:24 +01:00
}
feat(sag): Add Varekøb & Salg module with database migration and frontend template
- Created a new SQL migration for the sag_salgsvarer table to manage sales and purchase items.
- Implemented a new HTML template for the Varekøb & Salg module, including summary cards and tables for sales and purchases.
- Added JavaScript functions for loading and rendering order data dynamically.
- Introduced a new backend search module for customers, contacts, hardware, and locations with autocomplete functionality.
- Developed an email templates API for managing system and customer-specific email templates.
- Created multiple migrations for Nextcloud instances, cache, audit logs, email templates, sag comments, hardware locations, and billing methods.
- Enhanced the sag module with solutions, order lines, work types, and 2FA support for user authentication.
2026-02-02 20:23:56 +01:00
/* Search Results Dropdown */
.search-position-relative {
position: relative;
2026-01-31 23:16:24 +01:00
}
.search-results {
position: absolute;
top: 100%;
left: 0;
right: 0;
feat(sag): Add Varekøb & Salg module with database migration and frontend template
- Created a new SQL migration for the sag_salgsvarer table to manage sales and purchase items.
- Implemented a new HTML template for the Varekøb & Salg module, including summary cards and tables for sales and purchases.
- Added JavaScript functions for loading and rendering order data dynamically.
- Introduced a new backend search module for customers, contacts, hardware, and locations with autocomplete functionality.
- Developed an email templates API for managing system and customer-specific email templates.
- Created multiple migrations for Nextcloud instances, cache, audit logs, email templates, sag comments, hardware locations, and billing methods.
- Enhanced the sag module with solutions, order lines, work types, and 2FA support for user authentication.
2026-02-02 20:23:56 +01:00
background: var(--bg-surface, #ffffff);
border: 1px solid var(--border-color, rgba(0,0,0,0.1));
2026-01-31 23:16:24 +01:00
border-radius: 8px;
feat(sag): Add Varekøb & Salg module with database migration and frontend template
- Created a new SQL migration for the sag_salgsvarer table to manage sales and purchase items.
- Implemented a new HTML template for the Varekøb & Salg module, including summary cards and tables for sales and purchases.
- Added JavaScript functions for loading and rendering order data dynamically.
- Introduced a new backend search module for customers, contacts, hardware, and locations with autocomplete functionality.
- Developed an email templates API for managing system and customer-specific email templates.
- Created multiple migrations for Nextcloud instances, cache, audit logs, email templates, sag comments, hardware locations, and billing methods.
- Enhanced the sag module with solutions, order lines, work types, and 2FA support for user authentication.
2026-02-02 20:23:56 +01:00
max-height: 250px;
2026-01-31 23:16:24 +01:00
overflow-y: auto;
feat(sag): Add Varekøb & Salg module with database migration and frontend template
- Created a new SQL migration for the sag_salgsvarer table to manage sales and purchase items.
- Implemented a new HTML template for the Varekøb & Salg module, including summary cards and tables for sales and purchases.
- Added JavaScript functions for loading and rendering order data dynamically.
- Introduced a new backend search module for customers, contacts, hardware, and locations with autocomplete functionality.
- Developed an email templates API for managing system and customer-specific email templates.
- Created multiple migrations for Nextcloud instances, cache, audit logs, email templates, sag comments, hardware locations, and billing methods.
- Enhanced the sag module with solutions, order lines, work types, and 2FA support for user authentication.
2026-02-02 20:23:56 +01:00
z-index: 1050;
margin-top: 5px;
box-shadow: 0 4px 15px rgba(0,0,0,0.1);
2026-01-31 23:16:24 +01:00
}
.search-result-item {
feat(sag): Add Varekøb & Salg module with database migration and frontend template
- Created a new SQL migration for the sag_salgsvarer table to manage sales and purchase items.
- Implemented a new HTML template for the Varekøb & Salg module, including summary cards and tables for sales and purchases.
- Added JavaScript functions for loading and rendering order data dynamically.
- Introduced a new backend search module for customers, contacts, hardware, and locations with autocomplete functionality.
- Developed an email templates API for managing system and customer-specific email templates.
- Created multiple migrations for Nextcloud instances, cache, audit logs, email templates, sag comments, hardware locations, and billing methods.
- Enhanced the sag module with solutions, order lines, work types, and 2FA support for user authentication.
2026-02-02 20:23:56 +01:00
padding: 10px 15px;
border-bottom: 1px solid var(--border-color, rgba(0,0,0,0.05));
2026-01-31 23:16:24 +01:00
cursor: pointer;
feat(sag): Add Varekøb & Salg module with database migration and frontend template
- Created a new SQL migration for the sag_salgsvarer table to manage sales and purchase items.
- Implemented a new HTML template for the Varekøb & Salg module, including summary cards and tables for sales and purchases.
- Added JavaScript functions for loading and rendering order data dynamically.
- Introduced a new backend search module for customers, contacts, hardware, and locations with autocomplete functionality.
- Developed an email templates API for managing system and customer-specific email templates.
- Created multiple migrations for Nextcloud instances, cache, audit logs, email templates, sag comments, hardware locations, and billing methods.
- Enhanced the sag module with solutions, order lines, work types, and 2FA support for user authentication.
2026-02-02 20:23:56 +01:00
transition: background-color 0.15s ease;
2026-01-31 23:16:24 +01:00
}
.search-result-item:hover {
feat(sag): Add Varekøb & Salg module with database migration and frontend template
- Created a new SQL migration for the sag_salgsvarer table to manage sales and purchase items.
- Implemented a new HTML template for the Varekøb & Salg module, including summary cards and tables for sales and purchases.
- Added JavaScript functions for loading and rendering order data dynamically.
- Introduced a new backend search module for customers, contacts, hardware, and locations with autocomplete functionality.
- Developed an email templates API for managing system and customer-specific email templates.
- Created multiple migrations for Nextcloud instances, cache, audit logs, email templates, sag comments, hardware locations, and billing methods.
- Enhanced the sag module with solutions, order lines, work types, and 2FA support for user authentication.
2026-02-02 20:23:56 +01:00
background-color: var(--bg-hover, #f8f9fa);
2026-01-31 23:16:24 +01:00
}
.search-result-item:last-child {
border-bottom: none;
}
.search-result-name {
font-weight: 600;
feat(sag): Add Varekøb & Salg module with database migration and frontend template
- Created a new SQL migration for the sag_salgsvarer table to manage sales and purchase items.
- Implemented a new HTML template for the Varekøb & Salg module, including summary cards and tables for sales and purchases.
- Added JavaScript functions for loading and rendering order data dynamically.
- Introduced a new backend search module for customers, contacts, hardware, and locations with autocomplete functionality.
- Developed an email templates API for managing system and customer-specific email templates.
- Created multiple migrations for Nextcloud instances, cache, audit logs, email templates, sag comments, hardware locations, and billing methods.
- Enhanced the sag module with solutions, order lines, work types, and 2FA support for user authentication.
2026-02-02 20:23:56 +01:00
color: var(--text-primary);
font-size: 0.95rem;
2026-01-31 23:16:24 +01:00
}
.search-result-meta {
feat(sag): Add Varekøb & Salg module with database migration and frontend template
- Created a new SQL migration for the sag_salgsvarer table to manage sales and purchase items.
- Implemented a new HTML template for the Varekøb & Salg module, including summary cards and tables for sales and purchases.
- Added JavaScript functions for loading and rendering order data dynamically.
- Introduced a new backend search module for customers, contacts, hardware, and locations with autocomplete functionality.
- Developed an email templates API for managing system and customer-specific email templates.
- Created multiple migrations for Nextcloud instances, cache, audit logs, email templates, sag comments, hardware locations, and billing methods.
- Enhanced the sag module with solutions, order lines, work types, and 2FA support for user authentication.
2026-02-02 20:23:56 +01:00
font-size: 0.8rem;
color: var(--text-secondary, #6c757d);
2026-01-31 23:16:24 +01:00
}
feat(sag): Add Varekøb & Salg module with database migration and frontend template
- Created a new SQL migration for the sag_salgsvarer table to manage sales and purchase items.
- Implemented a new HTML template for the Varekøb & Salg module, including summary cards and tables for sales and purchases.
- Added JavaScript functions for loading and rendering order data dynamically.
- Introduced a new backend search module for customers, contacts, hardware, and locations with autocomplete functionality.
- Developed an email templates API for managing system and customer-specific email templates.
- Created multiple migrations for Nextcloud instances, cache, audit logs, email templates, sag comments, hardware locations, and billing methods.
- Enhanced the sag module with solutions, order lines, work types, and 2FA support for user authentication.
2026-02-02 20:23:56 +01:00
/* Selected Items (Tags) */
2026-01-31 23:16:24 +01:00
.selected-item {
feat(sag): Add Varekøb & Salg module with database migration and frontend template
- Created a new SQL migration for the sag_salgsvarer table to manage sales and purchase items.
- Implemented a new HTML template for the Varekøb & Salg module, including summary cards and tables for sales and purchases.
- Added JavaScript functions for loading and rendering order data dynamically.
- Introduced a new backend search module for customers, contacts, hardware, and locations with autocomplete functionality.
- Developed an email templates API for managing system and customer-specific email templates.
- Created multiple migrations for Nextcloud instances, cache, audit logs, email templates, sag comments, hardware locations, and billing methods.
- Enhanced the sag module with solutions, order lines, work types, and 2FA support for user authentication.
2026-02-02 20:23:56 +01:00
display: inline-flex;
align-items: center;
background-color: #e3f2fd;
color: #0f4c75;
padding: 6px 12px;
2026-01-31 23:16:24 +01:00
border-radius: 20px;
font-size: 0.85rem;
font-weight: 500;
feat(sag): Add Varekøb & Salg module with database migration and frontend template
- Created a new SQL migration for the sag_salgsvarer table to manage sales and purchase items.
- Implemented a new HTML template for the Varekøb & Salg module, including summary cards and tables for sales and purchases.
- Added JavaScript functions for loading and rendering order data dynamically.
- Introduced a new backend search module for customers, contacts, hardware, and locations with autocomplete functionality.
- Developed an email templates API for managing system and customer-specific email templates.
- Created multiple migrations for Nextcloud instances, cache, audit logs, email templates, sag comments, hardware locations, and billing methods.
- Enhanced the sag module with solutions, order lines, work types, and 2FA support for user authentication.
2026-02-02 20:23:56 +01:00
margin-right: 8px;
margin-bottom: 8px;
border: 1px solid #bbdefb;
2026-01-31 23:16:24 +01:00
}
.selected-item button {
background: none;
border: none;
feat(sag): Add Varekøb & Salg module with database migration and frontend template
- Created a new SQL migration for the sag_salgsvarer table to manage sales and purchase items.
- Implemented a new HTML template for the Varekøb & Salg module, including summary cards and tables for sales and purchases.
- Added JavaScript functions for loading and rendering order data dynamically.
- Introduced a new backend search module for customers, contacts, hardware, and locations with autocomplete functionality.
- Developed an email templates API for managing system and customer-specific email templates.
- Created multiple migrations for Nextcloud instances, cache, audit logs, email templates, sag comments, hardware locations, and billing methods.
- Enhanced the sag module with solutions, order lines, work types, and 2FA support for user authentication.
2026-02-02 20:23:56 +01:00
color: #0f4c75;
margin-left: 8px;
padding: 0;
line-height: 1;
font-size: 1.1rem;
2026-01-31 23:16:24 +01:00
cursor: pointer;
feat(sag): Add Varekøb & Salg module with database migration and frontend template
- Created a new SQL migration for the sag_salgsvarer table to manage sales and purchase items.
- Implemented a new HTML template for the Varekøb & Salg module, including summary cards and tables for sales and purchases.
- Added JavaScript functions for loading and rendering order data dynamically.
- Introduced a new backend search module for customers, contacts, hardware, and locations with autocomplete functionality.
- Developed an email templates API for managing system and customer-specific email templates.
- Created multiple migrations for Nextcloud instances, cache, audit logs, email templates, sag comments, hardware locations, and billing methods.
- Enhanced the sag module with solutions, order lines, work types, and 2FA support for user authentication.
2026-02-02 20:23:56 +01:00
opacity: 0.6;
transition: opacity 0.2s;
}
.selected-item button:hover {
opacity: 1;
}
/* Dark Mode Adjustments */
[data-bs-theme="dark"] .card-custom {
background-color: var(--bg-surface);
}
[data-bs-theme="dark"] .selected-item {
background-color: rgba(50, 130, 184, 0.2);
color: #a6d5fa;
border-color: rgba(50, 130, 184, 0.4);
}
[data-bs-theme="dark"] .selected-item button {
color: #a6d5fa;
2026-01-31 23:16:24 +01:00
}
2026-04-01 21:34:58 +02:00
.case-top-alerts .alert {
border-left: 6px solid;
}
.case-top-alerts .alert-warning {
border-left-color: #f59f00;
}
.case-top-alerts .alert-danger {
border-left-color: #e03131;
}
2026-09-08 01:55:47 +02:00
.cc-page { max-width: 1440px; padding-bottom: 100px !important; }
.cc-pagebar { display:flex; justify-content:space-between; align-items:center; gap:16px; margin:0 0 20px; }
.cc-pagebar > a { color:var(--text-secondary,#63758c); text-decoration:none; font-size:.88rem; }
.cc-pagebar .btn { border-radius:12px; font-size:.85rem; padding:10px 16px; }
.cc-page .card-custom { border:1px solid var(--border-color,#dce5ed); border-radius:22px; box-shadow:0 16px 48px #143b5610; }
.cc-page .card-header-custom { display:flex; justify-content:space-between; align-items:center; gap:20px; padding:34px 36px; border-radius:21px 21px 0 0; background:linear-gradient(115deg,#122f46,#164b62); }
.cc-eyebrow { display:block; color:#9ed7de; font-size:.66rem; font-weight:700; letter-spacing:.15em; margin-bottom:10px; }
.cc-page h1 { font-size:1.9rem; font-weight:700; letter-spacing:-.04em; margin-bottom:10px; }
.cc-page .card-header-custom p { color:#c5dce6; font-size:.9rem; max-width:520px; line-height:1.6; }
.cc-hero-icon { display:grid; place-items:center; flex-shrink:0; width:72px; height:72px; border-radius:22px; background:#ffffff0d; border:1px solid #ffffff25; font-size:2rem; color:#a9e4df; }
.cc-page .card-custom > .card-body { padding:32px 42px !important; }
.cc-page .form-control,.cc-page .form-select { border-radius:10px; min-height:43px; background-color:var(--bg-surface,#fff); border-color:var(--border-color,#dbe4ec); }
.cc-page .input-group-text { border-radius:10px 0 0 10px; background:transparent !important; color:#7891a5; }
.cc-page .input-group .form-control { border-top-left-radius:0; border-bottom-left-radius:0; }
.cc-page textarea.form-control { line-height:1.7; padding:14px 16px; }
.cc-page .form-label { font-size:.82rem; }
.cc-page .form-text { font-size:.75rem; line-height:1.5; }
.cc-page .cc-type-section > label { font-size:.72rem; text-transform:uppercase; letter-spacing:.08em; color:var(--text-secondary,#63758c); }
.cc-page #cc-types { align-items:stretch; gap:10px; }
.cc-page #cc-types > button { flex:1; border:1px solid var(--border-color,#dbe4ec); color:var(--text-primary,#26465d); border-radius:13px; text-align:left; padding:14px; background:var(--bg-surface,#fff); transition:border-color .15s,background .15s; }
.cc-type-name { display:block; font-size:.9rem; font-weight:600; }
.cc-type-hint { display:block; color:var(--text-secondary,#708397); margin-top:5px; font-size:.7rem; font-weight:400; }
.cc-page #cc-types > button.active { border-color:#258783; background:var(--accent-light,#eaf6f4); box-shadow:0 0 0 1px #258783; }
.cc-page #cc-types > .cc-message-type { border-style:dashed; border-color:#86aaa8; background:color-mix(in srgb,var(--accent-light,#eaf6f4) 62%,var(--bg-surface,#fff)); }
.cc-page #cc-types > .cc-message-type:hover { border-style:solid; background:var(--accent-light,#eaf6f4); }
.cc-message-type .cc-type-name { display:flex; align-items:center; gap:7px; }
.cc-message-type .cc-type-name::after { content:'INTERN'; padding:2px 5px; border-radius:4px; background:#267b74; color:#fff; font-size:.52rem; font-weight:700; letter-spacing:.08em; }
.cc-message-fallback { display:flex; width:100%; margin-top:12px; text-align:left; padding:14px; border-radius:13px; }
.cc-page #cc-types > button:hover { border-color:#258783; }
.cc-page #cc-more { flex-basis:100%; font-size:.78rem; }
.cc-page #cc-more > summary { padding:4px 0; color:var(--text-secondary,#63758c); }
.cc-page #cc-more .cc-types { padding-top:10px; }
.cc-page .cc-panel { border-radius:13px; margin-bottom:12px; }
.cc-page .cc-panel > summary { display:flex; align-items:center; gap:12px; list-style:none; padding:15px 17px; }
.cc-page .cc-panel > summary::-webkit-details-marker { display:none; }
.cc-page .cc-panel > summary::after { content:'⌄'; margin-left:auto; color:#8196a8; transition:transform .15s; }
.cc-page .cc-panel[open] > summary::after { transform:rotate(180deg); }
.cc-panel-icon { display:grid; place-items:center; flex-shrink:0; width:35px; height:35px; border-radius:10px; color:#3e777e; background:var(--accent-light,#eef5f6); }
.cc-panel-label { min-width:0; font-size:.86rem; }
.cc-page .cc-summary { margin:3px 0 0; font-size:.72rem; }
.cc-page .cc-panel[open] { border-color:#a7c5cc; }
.cc-page .cc-panel-body { padding:8px 18px 18px; }
.cc-page .cc-actions { border-radius:14px; box-shadow:0 8px 30px #143b561c; margin-top:28px !important; }
.cc-page .cc-actions .btn { border-radius:10px; }
.cc-page #submitBtn { background:#176967; border-color:#176967; }
.cc-page #cc-save { color:var(--text-secondary,#63758c); font-size:.73rem; }
.cc-template-toolbar { display:flex; align-items:center; gap:12px; flex-wrap:wrap; padding-bottom:20px; margin-bottom:20px !important; border-bottom:1px solid var(--border-color,#e3eaf0); }
.cc-template-toolbar .form-label { margin:0; }
.cc-template-toolbar .form-select { flex:1; width:auto; max-width:320px; min-width:180px; font-size:.83rem; }
.cc-page .cc-workload { background:var(--bg-hover,#f5f8fa); border:1px solid var(--border-color,#e3eaf0); font-size:.8rem; }
.cc-contact-cases { margin-top:14px; padding:0; border:1px solid #bdd9da; border-radius:12px; background:var(--bg-surface,#fff); overflow:hidden; font-size:.8rem; box-shadow:0 4px 14px #164b620c; }
.cc-contact-cases[hidden] { display:none; }
.cc-contact-cases__header { display:flex; align-items:center; gap:10px; padding:11px 13px; background:#edf8f7; color:#195f5e; }
.cc-contact-cases__header-icon { display:grid; place-items:center; width:29px; height:29px; border-radius:8px; background:#cfeceb; font-size:.85rem; }
.cc-contact-cases__eyebrow { display:block; color:#4d8382; font-size:.62rem; font-weight:700; letter-spacing:.07em; text-transform:uppercase; }
.cc-contact-cases__title { display:block; font-weight:700; line-height:1.25; }
.cc-contact-cases__body { padding:6px 13px 10px; }
.cc-contact-cases__group { padding-top:8px; }
.cc-contact-cases__group-name { display:block; color:var(--text-secondary,#65758a); font-size:.7rem; font-weight:600; margin:0 0 4px; }
.cc-contact-cases__item { display:flex; align-items:center; justify-content:space-between; gap:12px; padding:9px 0; border-bottom:1px solid var(--border-color,#e6eff0); }
.cc-contact-cases__item:last-child { border-bottom:0; }
.cc-contact-cases__item a { color:var(--text-primary,#213547); font-weight:600; text-decoration:none; }
.cc-contact-cases__item a:hover { color:#176967; text-decoration:underline; }
.cc-contact-cases__item small { color:var(--text-secondary,#65758a); white-space:nowrap; font-size:.69rem; }
.cc-contact-cases__more { display:block; padding-top:6px; color:var(--text-secondary,#65758a); font-size:.69rem; }
.cc-contact-cases__empty { padding:11px 13px; color:var(--text-secondary,#65758a); }
.cc-tag-suggestions { margin:10px 0 4px; padding-top:10px; border-top:1px solid var(--border-color,#e3eaf0); }
.cc-tag-suggestions__label { color:var(--text-secondary,#65758a); font-size:.7rem; font-weight:600; margin-bottom:6px; }
.cc-tag-suggestions .btn { border-radius:999px; font-size:.72rem; padding:3px 8px; }
[data-bs-theme="dark"] .cc-contact-cases { background:var(--bg-surface); border-color:#326b6b; }
[data-bs-theme="dark"] .cc-contact-cases__header { background:#173e3e; color:#c9edeb; }
@media(min-width:1200px) {
.cc-page #cc-relations .row { grid-template-columns:minmax(0, 1fr) minmax(0, 1fr); display:grid; gap:28px !important; }
.cc-page #cc-relations .row > [class*="col-"] { width:auto; max-width:none; padding:0; }
.cc-page .cc-panel-body { padding:14px 24px 24px; }
.cc-contact-cases__item { display:grid; grid-template-columns:minmax(0, 1fr) auto; column-gap:14px; align-items:center; }
.cc-contact-cases__item small { text-align:right; margin:0; }
}
@media(max-width:600px) { .cc-page .card-header-custom { padding:25px 20px; } .cc-hero-icon { display:none; } .cc-page h1 { font-size:1.6rem; } .cc-page .card-custom > .card-body { padding:20px 16px !important; } .cc-page #cc-types > button { flex:1 1 40%; } .cc-pagebar { align-items:flex-start; } .cc-pagebar .btn { max-width:190px; } }
/* Calm, task-first layout: the form is the product, not the decoration. */
.cc-page { max-width:1240px; }
.cc-page .card-custom { border-radius:16px; box-shadow:0 8px 28px #143b560d; }
.cc-page .card-header-custom { min-height:auto; padding:20px 28px; border-radius:15px 15px 0 0; background:var(--bg-surface,#fff); color:var(--text-primary,#213547); border-bottom:1px solid var(--border-color,#dce5ed); }
.cc-page .card-header-custom p { display:none; }
.cc-page .card-header-custom .cc-eyebrow { color:#267b74; margin:0 0 4px; font-size:.59rem; }
.cc-page .card-header-custom h1 { margin:0; font-size:1.35rem; letter-spacing:-.02em; color:inherit; }
.cc-page .cc-hero-icon { width:42px; height:42px; border-radius:12px; font-size:1.15rem; color:#267b74; background:var(--accent-light,#eaf6f4); border:0; }
.cc-page .card-custom > .card-body { padding:24px 28px 32px !important; }
.cc-template-toolbar { padding:12px 14px; margin:0 0 16px !important; border:1px solid var(--border-color,#e3eaf0); border-radius:10px; background:var(--bg-hover,#f7fafb); }
.cc-template-toolbar .form-label { font-weight:600; font-size:.76rem; }
.cc-template-toolbar .form-select { min-height:36px; max-width:280px; font-size:.78rem; }
.cc-page .cc-type-section { padding:0 0 16px; margin-bottom:16px !important; border-bottom:1px solid var(--border-color,#e3eaf0); }
.cc-page .cc-type-section > label { display:block; margin-bottom:8px !important; text-transform:none; letter-spacing:0; color:var(--text-primary,#213547); font-weight:600; font-size:.82rem; }
.cc-page #caseTypeHelp { display:none; }
.cc-page #cc-types { gap:7px; }
.cc-page #cc-types > button { flex:0 1 auto; min-height:0; padding:8px 11px; border-radius:9px; font-size:.78rem; }
.cc-page .cc-type-name { display:inline; font-size:.78rem; }
.cc-page .cc-type-hint { display:none; }
.cc-page #cc-types > button.active { box-shadow:none; background:#176967; border-color:#176967; color:#fff; }
.cc-page #cc-types > button.active .cc-type-name::after { background:#fff3; color:#fff; }
.cc-page #cc-types > .cc-message-type { margin-left:auto; border-style:solid; background:transparent; }
.cc-page #cc-more { flex-basis:auto; }
.cc-page #cc-more > summary { padding:8px 4px; }
.cc-page .cc-panel { border-radius:10px; margin-bottom:8px; box-shadow:none; }
.cc-page .cc-panel > summary { padding:12px 14px; }
.cc-panel-icon { width:30px; height:30px; border-radius:8px; font-size:.82rem; }
.cc-page .cc-panel-label { font-size:.8rem; }
.cc-page .cc-summary { display:inline; margin-left:7px; font-size:.69rem; }
.cc-page .cc-panel-body { padding:8px 14px 16px; }
.cc-page .cc-panel-body > .row { margin-bottom:0 !important; }
.cc-page #cc-relations[open] { border-color:#9dc7c3; }
.cc-page #cc-metadata { margin-top:16px; }
.cc-page #cc-workload { margin:8px 0 16px; padding:10px 14px; }
.cc-page .cc-actions { margin-top:20px !important; padding:12px 14px; }
/* The panels have very different heights. Keep them in a single stable flow
instead of pretending they are equal dashboard cards. */
@media(min-width:992px) {
.cc-page .cc-panel:not(#cc-relations):not(#cc-metadata) { width:100%; display:block; margin-right:0; }
}
@media(max-width:700px) {
.cc-page .card-header-custom { padding:16px 18px; }
.cc-page .card-custom > .card-body { padding:18px 14px 28px !important; }
.cc-page #cc-types > .cc-message-type { margin-left:0; }
}
2026-01-31 23:16:24 +01:00
< / style >
{% endblock %}
{% block content %}
2026-09-08 01:55:47 +02:00
< div class = "container py-4 cc-page" >
< div class = "cc-pagebar" > < a href = "/sag" > < i class = "bi bi-arrow-left me-2" > < / i > Alle sager< / a > < / div >
feat(sag): Add Varekøb & Salg module with database migration and frontend template
- Created a new SQL migration for the sag_salgsvarer table to manage sales and purchase items.
- Implemented a new HTML template for the Varekøb & Salg module, including summary cards and tables for sales and purchases.
- Added JavaScript functions for loading and rendering order data dynamically.
- Introduced a new backend search module for customers, contacts, hardware, and locations with autocomplete functionality.
- Developed an email templates API for managing system and customer-specific email templates.
- Created multiple migrations for Nextcloud instances, cache, audit logs, email templates, sag comments, hardware locations, and billing methods.
- Enhanced the sag module with solutions, order lines, work types, and 2FA support for user authentication.
2026-02-02 20:23:56 +01:00
< div class = "row justify-content-center" >
2026-09-08 01:55:47 +02:00
< div class = "col-12" >
feat(sag): Add Varekøb & Salg module with database migration and frontend template
- Created a new SQL migration for the sag_salgsvarer table to manage sales and purchase items.
- Implemented a new HTML template for the Varekøb & Salg module, including summary cards and tables for sales and purchases.
- Added JavaScript functions for loading and rendering order data dynamically.
- Introduced a new backend search module for customers, contacts, hardware, and locations with autocomplete functionality.
- Developed an email templates API for managing system and customer-specific email templates.
- Created multiple migrations for Nextcloud instances, cache, audit logs, email templates, sag comments, hardware locations, and billing methods.
- Enhanced the sag module with solutions, order lines, work types, and 2FA support for user authentication.
2026-02-02 20:23:56 +01:00
<!-- Main Card -->
< div class = "card card-custom" >
< div class = "card-header-custom" >
2026-09-08 01:55:47 +02:00
< div > < span class = "cc-eyebrow" > ET GODT STED AT STARTE< / span > < h1 > Opret en ny sag< / h1 > < p class = "mb-0" > Saml opgaven, vælg de rette personer, og tilføj det, du har brug for.< / p > < / div >
< span class = "cc-hero-icon" aria-hidden = "true" > < i class = "bi bi-folder-plus" > < / i > < / span >
2026-01-31 23:16:24 +01:00
< / div >
feat(sag): Add Varekøb & Salg module with database migration and frontend template
- Created a new SQL migration for the sag_salgsvarer table to manage sales and purchase items.
- Implemented a new HTML template for the Varekøb & Salg module, including summary cards and tables for sales and purchases.
- Added JavaScript functions for loading and rendering order data dynamically.
- Introduced a new backend search module for customers, contacts, hardware, and locations with autocomplete functionality.
- Developed an email templates API for managing system and customer-specific email templates.
- Created multiple migrations for Nextcloud instances, cache, audit logs, email templates, sag comments, hardware locations, and billing methods.
- Enhanced the sag module with solutions, order lines, work types, and 2FA support for user authentication.
2026-02-02 20:23:56 +01:00
< div class = "card-body p-4" >
2026-04-01 21:34:58 +02:00
< div id = "caseTopAlerts" class = "case-top-alerts d-none mb-3" > < / div >
feat(sag): Add Varekøb & Salg module with database migration and frontend template
- Created a new SQL migration for the sag_salgsvarer table to manage sales and purchase items.
- Implemented a new HTML template for the Varekøb & Salg module, including summary cards and tables for sales and purchases.
- Added JavaScript functions for loading and rendering order data dynamically.
- Introduced a new backend search module for customers, contacts, hardware, and locations with autocomplete functionality.
- Developed an email templates API for managing system and customer-specific email templates.
- Created multiple migrations for Nextcloud instances, cache, audit logs, email templates, sag comments, hardware locations, and billing methods.
- Enhanced the sag module with solutions, order lines, work types, and 2FA support for user authentication.
2026-02-02 20:23:56 +01:00
<!-- Notifications -->
< div id = "error" class = "alert alert-danger d-none shadow-sm" role = "alert" >
< i class = "bi bi-exclamation-triangle-fill me-2" > < / i > < span id = "error-text" > < / span >
2026-01-31 23:16:24 +01:00
< / div >
feat(sag): Add Varekøb & Salg module with database migration and frontend template
- Created a new SQL migration for the sag_salgsvarer table to manage sales and purchase items.
- Implemented a new HTML template for the Varekøb & Salg module, including summary cards and tables for sales and purchases.
- Added JavaScript functions for loading and rendering order data dynamically.
- Introduced a new backend search module for customers, contacts, hardware, and locations with autocomplete functionality.
- Developed an email templates API for managing system and customer-specific email templates.
- Created multiple migrations for Nextcloud instances, cache, audit logs, email templates, sag comments, hardware locations, and billing methods.
- Enhanced the sag module with solutions, order lines, work types, and 2FA support for user authentication.
2026-02-02 20:23:56 +01:00
< div id = "success" class = "alert alert-success d-none shadow-sm" role = "alert" >
< i class = "bi bi-check-circle-fill me-2" > < / i > < span id = "success-text" > < / span >
2026-01-31 23:16:24 +01:00
< / div >
feat(sag): Add Varekøb & Salg module with database migration and frontend template
- Created a new SQL migration for the sag_salgsvarer table to manage sales and purchase items.
- Implemented a new HTML template for the Varekøb & Salg module, including summary cards and tables for sales and purchases.
- Added JavaScript functions for loading and rendering order data dynamically.
- Introduced a new backend search module for customers, contacts, hardware, and locations with autocomplete functionality.
- Developed an email templates API for managing system and customer-specific email templates.
- Created multiple migrations for Nextcloud instances, cache, audit logs, email templates, sag comments, hardware locations, and billing methods.
- Enhanced the sag module with solutions, order lines, work types, and 2FA support for user authentication.
2026-02-02 20:23:56 +01:00
< form id = "createForm" novalidate >
2026-09-08 01:55:47 +02:00
< div class = "mb-4 cc-type-section" >
2026-07-17 01:58:02 +02:00
< label for = "type" class = "form-label mb-2" > Hvilken type sag vil du oprette?< / label >
< select class = "form-select form-select-lg" id = "type" required > < / select >
< div class = "form-text" id = "caseTypeHelp" > Vælg sagstype for at vise de relevante felter.< / div >
2026-09-08 01:55:47 +02:00
< button type = "button" id = "caseMessageTypeButton" class = "btn btn-outline-primary cc-message-type cc-message-fallback" onclick = "window.caseCreateUI?.openMessage?.() || window.openInternalMessage?.()" >
< span class = "cc-type-name" > < i class = "bi bi-chat-square-text" > < / i > Besked til kollega< / span >
< small class = "cc-type-hint" > Kort besked eller telefonbesked< / small >
< / button >
2026-07-17 01:58:02 +02:00
< / div >
feat(sag): Add Varekøb & Salg module with database migration and frontend template
- Created a new SQL migration for the sag_salgsvarer table to manage sales and purchase items.
- Implemented a new HTML template for the Varekøb & Salg module, including summary cards and tables for sales and purchases.
- Added JavaScript functions for loading and rendering order data dynamically.
- Introduced a new backend search module for customers, contacts, hardware, and locations with autocomplete functionality.
- Developed an email templates API for managing system and customer-specific email templates.
- Created multiple migrations for Nextcloud instances, cache, audit logs, email templates, sag comments, hardware locations, and billing methods.
- Enhanced the sag module with solutions, order lines, work types, and 2FA support for user authentication.
2026-02-02 20:23:56 +01:00
<!-- Section: Relations -->
< h5 class = "mb-3 text-muted fw-bold small text-uppercase" > Relationer< / h5 >
< div class = "row g-4 mb-4" >
<!-- Contact Search -->
< div class = "col-md-6" >
< label class = "form-label" > Kontaktpersoner< / label >
< div class = "search-position-relative" >
< div class = "input-group" >
< span class = "input-group-text bg-light border-end-0" > < i class = "bi bi-person-plus" > < / i > < / span >
< input type = "text" id = "contactSearch" class = "form-control border-start-0 ps-0" placeholder = "Søg kontakt..." >
< / div >
< div id = "contactResults" class = "search-results shadow-sm d-none" > < / div >
< / div >
2026-08-18 20:57:49 +02:00
< div id = "contactSearchContext" class = "form-text" > Søg blandt alle kontakter.< / div >
feat(sag): Add Varekøb & Salg module with database migration and frontend template
- Created a new SQL migration for the sag_salgsvarer table to manage sales and purchase items.
- Implemented a new HTML template for the Varekøb & Salg module, including summary cards and tables for sales and purchases.
- Added JavaScript functions for loading and rendering order data dynamically.
- Introduced a new backend search module for customers, contacts, hardware, and locations with autocomplete functionality.
- Developed an email templates API for managing system and customer-specific email templates.
- Created multiple migrations for Nextcloud instances, cache, audit logs, email templates, sag comments, hardware locations, and billing methods.
- Enhanced the sag module with solutions, order lines, work types, and 2FA support for user authentication.
2026-02-02 20:23:56 +01:00
< div id = "selectedContacts" class = "mt-2 text-wrap" > < / div >
< / div >
2026-02-15 11:12:58 +01:00
<!-- Company Search -->
feat(sag): Add Varekøb & Salg module with database migration and frontend template
- Created a new SQL migration for the sag_salgsvarer table to manage sales and purchase items.
- Implemented a new HTML template for the Varekøb & Salg module, including summary cards and tables for sales and purchases.
- Added JavaScript functions for loading and rendering order data dynamically.
- Introduced a new backend search module for customers, contacts, hardware, and locations with autocomplete functionality.
- Developed an email templates API for managing system and customer-specific email templates.
- Created multiple migrations for Nextcloud instances, cache, audit logs, email templates, sag comments, hardware locations, and billing methods.
- Enhanced the sag module with solutions, order lines, work types, and 2FA support for user authentication.
2026-02-02 20:23:56 +01:00
< div class = "col-md-6" >
2026-02-15 11:12:58 +01:00
< label class = "form-label" > Firma< / label >
feat(sag): Add Varekøb & Salg module with database migration and frontend template
- Created a new SQL migration for the sag_salgsvarer table to manage sales and purchase items.
- Implemented a new HTML template for the Varekøb & Salg module, including summary cards and tables for sales and purchases.
- Added JavaScript functions for loading and rendering order data dynamically.
- Introduced a new backend search module for customers, contacts, hardware, and locations with autocomplete functionality.
- Developed an email templates API for managing system and customer-specific email templates.
- Created multiple migrations for Nextcloud instances, cache, audit logs, email templates, sag comments, hardware locations, and billing methods.
- Enhanced the sag module with solutions, order lines, work types, and 2FA support for user authentication.
2026-02-02 20:23:56 +01:00
< div class = "search-position-relative" >
< div class = "input-group" >
< span class = "input-group-text bg-light border-end-0" > < i class = "bi bi-building" > < / i > < / span >
2026-02-15 11:12:58 +01:00
< input type = "text" id = "customerSearch" class = "form-control border-start-0 ps-0" placeholder = "Søg firma (min. 2 tegn)..." >
feat(sag): Add Varekøb & Salg module with database migration and frontend template
- Created a new SQL migration for the sag_salgsvarer table to manage sales and purchase items.
- Implemented a new HTML template for the Varekøb & Salg module, including summary cards and tables for sales and purchases.
- Added JavaScript functions for loading and rendering order data dynamically.
- Introduced a new backend search module for customers, contacts, hardware, and locations with autocomplete functionality.
- Developed an email templates API for managing system and customer-specific email templates.
- Created multiple migrations for Nextcloud instances, cache, audit logs, email templates, sag comments, hardware locations, and billing methods.
- Enhanced the sag module with solutions, order lines, work types, and 2FA support for user authentication.
2026-02-02 20:23:56 +01:00
< / div >
< div id = "customerResults" class = "search-results shadow-sm d-none" > < / div >
< / div >
< div id = "selectedCustomer" class = "mt-2 min-vh-20" > < / div >
< input type = "hidden" id = "customer_id" name = "customer_id" >
< / div >
< / div >
2026-08-31 13:01:35 +02:00
< div id = "internetConnectionPrefill" class = "alert alert-info d-none mb-4" role = "status" > < / div >
feat(sag): Add Varekøb & Salg module with database migration and frontend template
- Created a new SQL migration for the sag_salgsvarer table to manage sales and purchase items.
- Implemented a new HTML template for the Varekøb & Salg module, including summary cards and tables for sales and purchases.
- Added JavaScript functions for loading and rendering order data dynamically.
- Introduced a new backend search module for customers, contacts, hardware, and locations with autocomplete functionality.
- Developed an email templates API for managing system and customer-specific email templates.
- Created multiple migrations for Nextcloud instances, cache, audit logs, email templates, sag comments, hardware locations, and billing methods.
- Enhanced the sag module with solutions, order lines, work types, and 2FA support for user authentication.
2026-02-02 20:23:56 +01:00
< hr class = "my-4 opacity-25" >
2026-02-15 11:12:58 +01:00
<!-- Section: Basic Info -->
< div class = "row g-4 mb-4" >
< div class = "col-md-12" >
< label for = "titel" class = "form-label" > Titel < span class = "text-danger" > *< / span > < / label >
< div class = "input-group" >
< span class = "input-group-text bg-light border-end-0" > < i class = "bi bi-type-h1" > < / i > < / span >
< input type = "text" class = "form-control border-start-0 ps-0" id = "titel" placeholder = "Kort og præcis titel (f.eks. 'Netværksproblemer hos X')" required >
< / div >
< / div >
< div class = "col-md-12" >
2026-07-18 10:10:31 +02:00
< div class = "d-flex justify-content-between align-items-center mb-2" >
< label for = "beskrivelse" class = "form-label mb-0" > Beskrivelse< / label >
< button type = "button" id = "caseCreateRewriteBtn" class = "btn btn-sm btn-outline-primary" title = "Renskriv kun det, du allerede har skrevet" >
< i class = "bi bi-magic me-1" > < / i > AI renskriv
< / button >
< / div >
2026-02-15 11:12:58 +01:00
< textarea class = "form-control" id = "beskrivelse" rows = "5" placeholder = "Beskriv problemstillingen detaljeret..." > < / textarea >
2026-07-18 10:10:31 +02:00
< div class = "d-flex justify-content-between form-text" >
< span > AI retter kun sprog og foreslår en titel ud fra din tekst. Den må ikke tilføje oplysninger.< / span >
< span id = "charCount" > 0 tegn< / span >
< / div >
2026-02-15 11:12:58 +01:00
< / div >
< / div >
< hr class = "my-4 opacity-25" >
2026-02-10 14:40:38 +01:00
<!-- Section: Hardware & AnyDesk -->
2026-07-17 01:58:02 +02:00
< section id = "hardwareSection" >
2026-02-10 14:40:38 +01:00
< h5 class = "mb-3 text-muted fw-bold small text-uppercase" > Hardware (AnyDesk)< / h5 >
< div class = "row g-4 mb-4" >
< div class = "col-12" >
< div id = "hardwareList" class = "border rounded-3 p-3 bg-light" >
< div class = "text-muted small" > Vælg en kontakt for at se relateret hardware.< / div >
< / div >
< / div >
< div class = "col-12" >
< div class = "card border-0 shadow-sm" >
< div class = "card-body" >
< h6 class = "fw-bold mb-3" > Quick opret hardware< / h6 >
< div class = "row g-3" >
< div class = "col-md-4" >
< label class = "form-label" > Navn *< / label >
< input type = "text" class = "form-control" id = "hardwareNameInput" placeholder = "PC, NAS, Server..." >
< / div >
< div class = "col-md-4" >
< label class = "form-label" > AnyDesk ID< / label >
< input type = "text" class = "form-control" id = "hardwareAnyDeskIdInput" placeholder = "123-456-789" >
2026-02-11 13:23:32 +01:00
< div class = "form-text small text-muted" > Link genereres automatisk.< / div >
2026-02-10 14:40:38 +01:00
< / div >
< div class = "col-12 d-flex justify-content-end" >
< button type = "button" class = "btn btn-outline-primary" onclick = "quickCreateHardware()" >
< i class = "bi bi-plus-circle me-2" > < / i > Opret hardware
< / button >
< / div >
< / div >
< / div >
< / div >
< / div >
< / div >
2026-07-17 01:58:02 +02:00
< / section >
< section id = "pipelineSection" class = "d-none" >
< hr class = "my-4 opacity-25" >
< h5 class = "mb-3 text-muted fw-bold small text-uppercase" > Pipeline< / h5 >
< div class = "row g-4 mb-4" >
< div class = "col-md-4" > < label class = "form-label" > Stage< / label > < select id = "pipeline_stage_id" class = "form-select" > < option value = "" > Ikke sat< / option > < / select > < / div >
< div class = "col-md-4" > < label class = "form-label" > Beløb< / label > < input id = "pipeline_amount" type = "number" min = "0" step = "0.01" class = "form-control" placeholder = "0,00" > < / div >
< div class = "col-md-4" > < label class = "form-label" > Sandsynlighed (%)< / label > < input id = "pipeline_probability" type = "number" min = "0" max = "100" step = "1" class = "form-control" placeholder = "0-100" > < / div >
< div class = "col-12" > < label class = "form-label" > Pipelinebeskrivelse< / label > < textarea id = "pipeline_description" class = "form-control" rows = "3" placeholder = "Næste skridt, tilbud eller forventning..." > < / textarea > < / div >
< / div >
< / section >
< section id = "orderSection" class = "d-none" >
< hr class = "my-4 opacity-25" >
< div class = "d-flex justify-content-between align-items-center mb-3" >
< h5 class = "mb-0 text-muted fw-bold small text-uppercase" > Indkøb og salg< / h5 >
< div class = "btn-group btn-group-sm" >
< button type = "button" class = "btn btn-outline-primary" onclick = "addOrderLine('sale')" > < i class = "bi bi-plus-lg me-1" > < / i > Salgslinje< / button >
< button type = "button" class = "btn btn-outline-secondary" onclick = "addOrderLine('purchase')" > < i class = "bi bi-plus-lg me-1" > < / i > Indkøbslinje< / button >
< / div >
< / div >
< div id = "orderLines" class = "vstack gap-3 mb-4" > < / div >
< div id = "orderLinesEmpty" class = "text-muted small border rounded-3 p-3" > Tilføj en indkøbs- eller salgslinje efter behov.< / div >
< / section >
2026-02-10 14:40:38 +01:00
< hr class = "my-4 opacity-25" >
feat(sag): Add Varekøb & Salg module with database migration and frontend template
- Created a new SQL migration for the sag_salgsvarer table to manage sales and purchase items.
- Implemented a new HTML template for the Varekøb & Salg module, including summary cards and tables for sales and purchases.
- Added JavaScript functions for loading and rendering order data dynamically.
- Introduced a new backend search module for customers, contacts, hardware, and locations with autocomplete functionality.
- Developed an email templates API for managing system and customer-specific email templates.
- Created multiple migrations for Nextcloud instances, cache, audit logs, email templates, sag comments, hardware locations, and billing methods.
- Enhanced the sag module with solutions, order lines, work types, and 2FA support for user authentication.
2026-02-02 20:23:56 +01:00
<!-- Section: Metadata -->
< h5 class = "mb-3 text-muted fw-bold small text-uppercase" > Type, Status & Ansvar< / h5 >
< div class = "row g-4 mb-4" >
2026-07-17 01:58:02 +02:00
< div class = "col-md-4" >
feat(sag): Add Varekøb & Salg module with database migration and frontend template
- Created a new SQL migration for the sag_salgsvarer table to manage sales and purchase items.
- Implemented a new HTML template for the Varekøb & Salg module, including summary cards and tables for sales and purchases.
- Added JavaScript functions for loading and rendering order data dynamically.
- Introduced a new backend search module for customers, contacts, hardware, and locations with autocomplete functionality.
- Developed an email templates API for managing system and customer-specific email templates.
- Created multiple migrations for Nextcloud instances, cache, audit logs, email templates, sag comments, hardware locations, and billing methods.
- Enhanced the sag module with solutions, order lines, work types, and 2FA support for user authentication.
2026-02-02 20:23:56 +01:00
< label for = "status" class = "form-label" > Status < span class = "text-danger" > *< / span > < / label >
< select class = "form-select" id = "status" required >
< option value = "åben" selected > 🟢 Åben< / option >
< option value = "afventer" > 🟡 Afventer< / option >
< option value = "lukket" > 🔴 Lukket< / option >
< / select >
< / div >
2026-07-17 01:58:02 +02:00
< div class = "col-md-4" >
2026-02-17 08:29:05 +01:00
< label for = "ansvarlig_bruger_id" class = "form-label" > Ansvarlig medarbejder< / label >
< select class = "form-select" id = "ansvarlig_bruger_id" >
< option value = "" > Ingen< / option >
{% for user in assignment_users or [] %}
< option value = "{{ user.user_id }}" > {{ user.display_name }}< / option >
{% endfor %}
< / select >
< / div >
feat(sag): Add Varekøb & Salg module with database migration and frontend template
- Created a new SQL migration for the sag_salgsvarer table to manage sales and purchase items.
- Implemented a new HTML template for the Varekøb & Salg module, including summary cards and tables for sales and purchases.
- Added JavaScript functions for loading and rendering order data dynamically.
- Introduced a new backend search module for customers, contacts, hardware, and locations with autocomplete functionality.
- Developed an email templates API for managing system and customer-specific email templates.
- Created multiple migrations for Nextcloud instances, cache, audit logs, email templates, sag comments, hardware locations, and billing methods.
- Enhanced the sag module with solutions, order lines, work types, and 2FA support for user authentication.
2026-02-02 20:23:56 +01:00
2026-07-17 01:58:02 +02:00
< div class = "col-md-4" >
2026-02-17 08:29:05 +01:00
< label for = "assigned_group_id" class = "form-label" > Ansvarlig gruppe< / label >
< select class = "form-select" id = "assigned_group_id" >
< option value = "" > Ingen< / option >
{% for group in assignment_groups or [] %}
< option value = "{{ group.id }}" > {{ group.name }}< / option >
{% endfor %}
< / select >
feat(sag): Add Varekøb & Salg module with database migration and frontend template
- Created a new SQL migration for the sag_salgsvarer table to manage sales and purchase items.
- Implemented a new HTML template for the Varekøb & Salg module, including summary cards and tables for sales and purchases.
- Added JavaScript functions for loading and rendering order data dynamically.
- Introduced a new backend search module for customers, contacts, hardware, and locations with autocomplete functionality.
- Developed an email templates API for managing system and customer-specific email templates.
- Created multiple migrations for Nextcloud instances, cache, audit logs, email templates, sag comments, hardware locations, and billing methods.
- Enhanced the sag module with solutions, order lines, work types, and 2FA support for user authentication.
2026-02-02 20:23:56 +01:00
< / div >
2026-02-17 08:29:05 +01:00
< / div >
feat(sag): Add Varekøb & Salg module with database migration and frontend template
- Created a new SQL migration for the sag_salgsvarer table to manage sales and purchase items.
- Implemented a new HTML template for the Varekøb & Salg module, including summary cards and tables for sales and purchases.
- Added JavaScript functions for loading and rendering order data dynamically.
- Introduced a new backend search module for customers, contacts, hardware, and locations with autocomplete functionality.
- Developed an email templates API for managing system and customer-specific email templates.
- Created multiple migrations for Nextcloud instances, cache, audit logs, email templates, sag comments, hardware locations, and billing methods.
- Enhanced the sag module with solutions, order lines, work types, and 2FA support for user authentication.
2026-02-02 20:23:56 +01:00
2026-02-17 08:29:05 +01:00
< div class = "row g-4 mb-4" >
feat(sag): Add Varekøb & Salg module with database migration and frontend template
- Created a new SQL migration for the sag_salgsvarer table to manage sales and purchase items.
- Implemented a new HTML template for the Varekøb & Salg module, including summary cards and tables for sales and purchases.
- Added JavaScript functions for loading and rendering order data dynamically.
- Introduced a new backend search module for customers, contacts, hardware, and locations with autocomplete functionality.
- Developed an email templates API for managing system and customer-specific email templates.
- Created multiple migrations for Nextcloud instances, cache, audit logs, email templates, sag comments, hardware locations, and billing methods.
- Enhanced the sag module with solutions, order lines, work types, and 2FA support for user authentication.
2026-02-02 20:23:56 +01:00
< div class = "col-md-4" >
< label for = "deadline" class = "form-label" > Deadline< / label >
< div class = "input-group" >
< span class = "input-group-text bg-light border-end-0" > < i class = "bi bi-calendar-event" > < / i > < / span >
< input type = "datetime-local" class = "form-control border-start-0 ps-0" id = "deadline" >
< / div >
< / div >
< / div >
<!-- Action Buttons -->
< div class = "d-flex justify-content-end gap-3 mt-5" >
< a href = "/sag" class = "btn btn-light border px-4 fw-bold" > Annuller< / a >
< button type = "submit" class = "btn btn-primary px-5 fw-bold shadow-sm" id = "submitBtn" >
< span class = "d-flex align-items-center" >
< i class = "bi bi-check-lg me-2" > < / i > Opret Sag
< / span >
< / button >
< / div >
< / form >
2026-01-31 23:16:24 +01:00
< / div >
feat(sag): Add Varekøb & Salg module with database migration and frontend template
- Created a new SQL migration for the sag_salgsvarer table to manage sales and purchase items.
- Implemented a new HTML template for the Varekøb & Salg module, including summary cards and tables for sales and purchases.
- Added JavaScript functions for loading and rendering order data dynamically.
- Introduced a new backend search module for customers, contacts, hardware, and locations with autocomplete functionality.
- Developed an email templates API for managing system and customer-specific email templates.
- Created multiple migrations for Nextcloud instances, cache, audit logs, email templates, sag comments, hardware locations, and billing methods.
- Enhanced the sag module with solutions, order lines, work types, and 2FA support for user authentication.
2026-02-02 20:23:56 +01:00
< / div >
2026-01-31 23:16:24 +01:00
< / div >
< / div >
< / div >
2026-07-18 10:10:31 +02:00
< div class = "modal fade" id = "caseCreateRewriteModal" tabindex = "-1" aria-labelledby = "caseCreateRewriteModalLabel" aria-hidden = "true" >
< div class = "modal-dialog modal-lg modal-dialog-scrollable" >
< div class = "modal-content" >
< div class = "modal-header" >
< h5 class = "modal-title" id = "caseCreateRewriteModalLabel" > < i class = "bi bi-magic me-2" > < / i > AI-forslag til sag< / h5 >
< button type = "button" class = "btn-close" data-bs-dismiss = "modal" aria-label = "Luk" > < / button >
< / div >
< div class = "modal-body" >
< div class = "alert alert-info small" >
Gennemgå forslaget før du bruger det. AI må kun have rettet formulering og foreslået en titel ud fra din egen tekst.
< / div >
< div class = "mb-3" >
< label for = "caseCreateSuggestedTitle" class = "form-label" > Foreslået titel< / label >
< input id = "caseCreateSuggestedTitle" class = "form-control" type = "text" >
< / div >
< div >
< label for = "caseCreateSuggestedDescription" class = "form-label" > Renskrevet beskrivelse< / label >
< textarea id = "caseCreateSuggestedDescription" class = "form-control" rows = "10" > < / textarea >
< / div >
< / div >
< div class = "modal-footer" >
< button type = "button" class = "btn btn-outline-secondary" data-bs-dismiss = "modal" > Annuller< / button >
< button type = "button" id = "caseCreateApplyRewriteBtn" class = "btn btn-primary" > < i class = "bi bi-check2 me-1" > < / i > Brug forslag< / button >
< / div >
< / div >
< / div >
< / div >
2026-01-31 23:16:24 +01:00
< script >
let selectedCustomer = null;
let selectedContacts = {};
2026-02-10 14:40:38 +01:00
let selectedContactsCompanies = {};
2026-01-31 23:16:24 +01:00
let customerSearchTimeout;
let contactSearchTimeout;
2026-08-18 20:57:49 +02:00
let selectedCustomerContacts = [];
let customerContactsLoadToken = 0;
2026-02-20 07:10:06 +01:00
let successAlertTimeout;
2026-07-17 01:58:02 +02:00
let orderLineCounter = 0;
2026-08-31 13:01:35 +02:00
let telefoniPrefill = { contactId: null, title: null, callId: null, customerId: null, description: null, internetConnectionId: null };
2026-04-01 21:34:58 +02:00
let topAlertLoadToken = 0;
function escapeTopAlertHtml(value) {
return String(value ?? '')
.replace(/& /g, '& ')
.replace(/< /g, '< ')
.replace(/>/g, '> ')
.replace(/"/g, '" ')
.replace(/'/g, '' ');
}
async function loadCreateTopAlertsForCustomer(customerId) {
const container = document.getElementById('caseTopAlerts');
if (!container) {
return;
}
if (!customerId) {
container.classList.add('d-none');
container.innerHTML = '';
return;
}
const loadToken = ++topAlertLoadToken;
container.classList.remove('d-none');
container.innerHTML = '< div class = "alert alert-info mb-0" > < span class = "spinner-border spinner-border-sm me-2" > < / span > Henter kunde-alerts...< / div > ';
try {
const response = await fetch(`/api/v1/alert-notes/check?entity_type=customer& entity_id=${customerId}`, {
credentials: 'include'
});
if (loadToken !== topAlertLoadToken) {
return;
}
if (!response.ok) {
throw new Error(`HTTP ${response.status}`);
}
const data = await response.json();
const alerts = (data?.alerts || []).filter((alert) => ['critical', 'warning'].includes(String(alert?.severity || '').toLowerCase()));
if (!alerts.length) {
container.classList.add('d-none');
container.innerHTML = '';
return;
}
container.innerHTML = alerts.map((alert) => {
const isCritical = String(alert.severity || '').toLowerCase() === 'critical';
const klass = isCritical ? 'alert-danger' : 'alert-warning';
const label = isCritical ? 'KRITISK' : 'ADVARSEL';
const title = escapeTopAlertHtml(alert.title || 'Vigtig kundeinformation');
const message = escapeTopAlertHtml(alert.message || '');
return `
< div class = "alert ${klass} mb-2" role = "alert" >
< strong > ${label}:< / strong > ${title}
${message ? `< div class = "small mt-1" > ${message}< / div > ` : ''}
< / div >
`;
}).join('');
container.classList.remove('d-none');
} catch (error) {
if (loadToken !== topAlertLoadToken) {
return;
}
console.error('Failed to load customer alerts on sag create:', error);
container.innerHTML = '< div class = "alert alert-warning mb-0" role = "alert" > < strong > Advarsel:< / strong > Kunde-alerts kunne ikke hentes.< / div > ';
container.classList.remove('d-none');
}
}
2026-01-31 23:16:24 +01:00
2026-02-20 07:10:06 +01:00
// Helper function to show success alert
function showSuccessAlert(message, duration = 3000) {
if (successAlertTimeout) {
clearTimeout(successAlertTimeout);
}
const successDiv = document.getElementById('success');
successDiv.classList.remove('d-none');
document.getElementById('success-text').textContent = message;
successAlertTimeout = setTimeout(() => {
successDiv.classList.add('d-none');
successAlertTimeout = null;
}, duration);
}
2026-08-30 14:34:43 +02:00
function showCreateError(message) {
const errorDiv = document.getElementById('error');
errorDiv.classList.remove('d-none');
document.getElementById('error-text').textContent = String(message || 'Ukendt fejl');
errorDiv.scrollIntoView({ behavior: 'smooth', block: 'nearest' });
}
feat(sag): Add Varekøb & Salg module with database migration and frontend template
- Created a new SQL migration for the sag_salgsvarer table to manage sales and purchase items.
- Implemented a new HTML template for the Varekøb & Salg module, including summary cards and tables for sales and purchases.
- Added JavaScript functions for loading and rendering order data dynamically.
- Introduced a new backend search module for customers, contacts, hardware, and locations with autocomplete functionality.
- Developed an email templates API for managing system and customer-specific email templates.
- Created multiple migrations for Nextcloud instances, cache, audit logs, email templates, sag comments, hardware locations, and billing methods.
- Enhanced the sag module with solutions, order lines, work types, and 2FA support for user authentication.
2026-02-02 20:23:56 +01:00
// --- Character Counter ---
const beskrInput = document.getElementById('beskrivelse');
if (beskrInput) {
beskrInput.addEventListener('input', function(e) {
document.getElementById('charCount').textContent = e.target.value.length + " tegn";
});
}
2026-01-31 23:16:24 +01:00
2026-07-18 10:10:31 +02:00
// --- AI renskrivning ved oprettelse ---
// Forslaget bliver altid vist først; formularens titel og beskrivelse ændres
// først når brugeren aktivt vælger "Brug forslag".
async function requestCaseCreateRewrite() {
const descriptionInput = document.getElementById('beskrivelse');
const titleInput = document.getElementById('titel');
const button = document.getElementById('caseCreateRewriteBtn');
const source = (descriptionInput?.value || '').trim();
if (!source) {
descriptionInput?.focus();
2026-08-30 14:34:43 +02:00
showCreateError('Skriv en beskrivelse først.');
2026-07-18 10:10:31 +02:00
return;
}
const originalButton = button?.innerHTML || '';
if (button) {
button.disabled = true;
button.innerHTML = '< span class = "spinner-border spinner-border-sm me-1" > < / span > Renskriver...';
}
try {
const response = await fetch('/api/v1/sag/rewrite-case-create', {
method: 'POST',
credentials: 'include',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ title: titleInput?.value || '', description: source })
});
const payload = await response.json().catch(() => ({}));
if (!response.ok) {
throw new Error(payload?.detail || `HTTP ${response.status}`);
}
const suggestion = {
title: String(payload?.title || '').trim(),
description: String(payload?.description || '').trim()
};
if (!suggestion.description) {
throw new Error('AI returnerede ikke en beskrivelse');
}
document.getElementById('caseCreateSuggestedTitle').value = suggestion.title || titleInput?.value || '';
document.getElementById('caseCreateSuggestedDescription').value = suggestion.description;
bootstrap.Modal.getOrCreateInstance(document.getElementById('caseCreateRewriteModal')).show();
} catch (error) {
console.error('Case create rewrite failed:', error);
2026-08-30 14:34:43 +02:00
showCreateError(`Kunne ikke renskrive beskrivelsen: ${error.message || 'Ukendt fejl'}`);
2026-07-18 10:10:31 +02:00
} finally {
if (button) {
button.disabled = false;
button.innerHTML = originalButton;
}
}
}
document.getElementById('caseCreateRewriteBtn')?.addEventListener('click', requestCaseCreateRewrite);
document.getElementById('caseCreateApplyRewriteBtn')?.addEventListener('click', () => {
const suggestedTitle = document.getElementById('caseCreateSuggestedTitle').value.trim();
const suggestedDescription = document.getElementById('caseCreateSuggestedDescription').value.trim();
const titleInput = document.getElementById('titel');
const descriptionInput = document.getElementById('beskrivelse');
2026-09-08 01:55:47 +02:00
if (suggestedTitle) {
titleInput.value = suggestedTitle;
titleInput.dispatchEvent(new Event('input', { bubbles: true }));
}
2026-07-18 10:10:31 +02:00
if (suggestedDescription) {
descriptionInput.value = suggestedDescription;
2026-09-08 01:55:47 +02:00
descriptionInput.dispatchEvent(new Event('input', { bubbles: true }));
2026-07-18 10:10:31 +02:00
}
bootstrap.Modal.getOrCreateInstance(document.getElementById('caseCreateRewriteModal')).hide();
});
feat(sag): Add Varekøb & Salg module with database migration and frontend template
- Created a new SQL migration for the sag_salgsvarer table to manage sales and purchase items.
- Implemented a new HTML template for the Varekøb & Salg module, including summary cards and tables for sales and purchases.
- Added JavaScript functions for loading and rendering order data dynamically.
- Introduced a new backend search module for customers, contacts, hardware, and locations with autocomplete functionality.
- Developed an email templates API for managing system and customer-specific email templates.
- Created multiple migrations for Nextcloud instances, cache, audit logs, email templates, sag comments, hardware locations, and billing methods.
- Enhanced the sag module with solutions, order lines, work types, and 2FA support for user authentication.
2026-02-02 20:23:56 +01:00
// --- Search Logic ---
function initializeSearch() {
// Customer Search
const customerInput = document.getElementById('customerSearch');
if (customerInput) {
customerInput.addEventListener('input', (e) => handleSearch(e, 'customer'));
// Close dropdown when clicking outside
document.addEventListener('click', (e) => {
if (!e.target.closest('.search-position-relative')) {
const cr = document.getElementById('customerResults');
if(cr) cr.classList.add('d-none');
}
});
}
// Contact Search
const contactInput = document.getElementById('contactSearch');
if (contactInput) {
contactInput.addEventListener('input', (e) => handleSearch(e, 'contact'));
2026-09-08 01:55:47 +02:00
contactInput.addEventListener('keydown', e => {
if (e.key === 'Escape') {
clearTimeout(contactSearchTimeout);
document.getElementById('contactResults').classList.add('d-none');
contactInput.blur();
}
});
2026-08-18 20:57:49 +02:00
contactInput.addEventListener('focus', () => {
2026-09-08 01:55:47 +02:00
if (selectedCustomer & & contactInput.value.trim().length >= 2) {
2026-08-18 20:57:49 +02:00
renderCustomerContactResults(contactInput.value);
}
});
feat(sag): Add Varekøb & Salg module with database migration and frontend template
- Created a new SQL migration for the sag_salgsvarer table to manage sales and purchase items.
- Implemented a new HTML template for the Varekøb & Salg module, including summary cards and tables for sales and purchases.
- Added JavaScript functions for loading and rendering order data dynamically.
- Introduced a new backend search module for customers, contacts, hardware, and locations with autocomplete functionality.
- Developed an email templates API for managing system and customer-specific email templates.
- Created multiple migrations for Nextcloud instances, cache, audit logs, email templates, sag comments, hardware locations, and billing methods.
- Enhanced the sag module with solutions, order lines, work types, and 2FA support for user authentication.
2026-02-02 20:23:56 +01:00
document.addEventListener('click', (e) => {
2026-09-08 01:55:47 +02:00
if (!contactInput.closest('.search-position-relative').contains(e.target)) {
feat(sag): Add Varekøb & Salg module with database migration and frontend template
- Created a new SQL migration for the sag_salgsvarer table to manage sales and purchase items.
- Implemented a new HTML template for the Varekøb & Salg module, including summary cards and tables for sales and purchases.
- Added JavaScript functions for loading and rendering order data dynamically.
- Introduced a new backend search module for customers, contacts, hardware, and locations with autocomplete functionality.
- Developed an email templates API for managing system and customer-specific email templates.
- Created multiple migrations for Nextcloud instances, cache, audit logs, email templates, sag comments, hardware locations, and billing methods.
- Enhanced the sag module with solutions, order lines, work types, and 2FA support for user authentication.
2026-02-02 20:23:56 +01:00
const cr = document.getElementById('contactResults');
if(cr) cr.classList.add('d-none');
2026-01-31 23:16:24 +01:00
}
});
}
feat(sag): Add Varekøb & Salg module with database migration and frontend template
- Created a new SQL migration for the sag_salgsvarer table to manage sales and purchase items.
- Implemented a new HTML template for the Varekøb & Salg module, including summary cards and tables for sales and purchases.
- Added JavaScript functions for loading and rendering order data dynamically.
- Introduced a new backend search module for customers, contacts, hardware, and locations with autocomplete functionality.
- Developed an email templates API for managing system and customer-specific email templates.
- Created multiple migrations for Nextcloud instances, cache, audit logs, email templates, sag comments, hardware locations, and billing methods.
- Enhanced the sag module with solutions, order lines, work types, and 2FA support for user authentication.
2026-02-02 20:23:56 +01:00
}
function handleSearch(event, type) {
const query = event.target.value.trim();
const resultsId = type === 'customer' ? 'customerResults' : 'contactResults';
const timeoutVar = type === 'customer' ? customerSearchTimeout : contactSearchTimeout;
const resultsDiv = document.getElementById(resultsId);
2026-05-12 08:41:13 +02:00
const token = localStorage.getItem('access_token') || sessionStorage.getItem('access_token');
const authHeaders = token ? { Authorization: `Bearer ${token}` } : {};
feat(sag): Add Varekøb & Salg module with database migration and frontend template
- Created a new SQL migration for the sag_salgsvarer table to manage sales and purchase items.
- Implemented a new HTML template for the Varekøb & Salg module, including summary cards and tables for sales and purchases.
- Added JavaScript functions for loading and rendering order data dynamically.
- Introduced a new backend search module for customers, contacts, hardware, and locations with autocomplete functionality.
- Developed an email templates API for managing system and customer-specific email templates.
- Created multiple migrations for Nextcloud instances, cache, audit logs, email templates, sag comments, hardware locations, and billing methods.
- Enhanced the sag module with solutions, order lines, work types, and 2FA support for user authentication.
2026-02-02 20:23:56 +01:00
clearTimeout(timeoutVar);
2026-08-18 20:57:49 +02:00
2026-09-08 01:55:47 +02:00
if (query.length < 2 ) {
resultsDiv.classList.add('d-none');
resultsDiv.innerHTML = '';
return;
}
2026-08-18 20:57:49 +02:00
if (type === 'contact' & & selectedCustomer) {
renderCustomerContactResults(query);
return;
}
feat(sag): Add Varekøb & Salg module with database migration and frontend template
- Created a new SQL migration for the sag_salgsvarer table to manage sales and purchase items.
- Implemented a new HTML template for the Varekøb & Salg module, including summary cards and tables for sales and purchases.
- Added JavaScript functions for loading and rendering order data dynamically.
- Introduced a new backend search module for customers, contacts, hardware, and locations with autocomplete functionality.
- Developed an email templates API for managing system and customer-specific email templates.
- Created multiple migrations for Nextcloud instances, cache, audit logs, email templates, sag comments, hardware locations, and billing methods.
- Enhanced the sag module with solutions, order lines, work types, and 2FA support for user authentication.
2026-02-02 20:23:56 +01:00
if (query.length < 2 ) {
resultsDiv.classList.add('d-none');
return;
}
2026-01-31 23:16:24 +01:00
feat(sag): Add Varekøb & Salg module with database migration and frontend template
- Created a new SQL migration for the sag_salgsvarer table to manage sales and purchase items.
- Implemented a new HTML template for the Varekøb & Salg module, including summary cards and tables for sales and purchases.
- Added JavaScript functions for loading and rendering order data dynamically.
- Introduced a new backend search module for customers, contacts, hardware, and locations with autocomplete functionality.
- Developed an email templates API for managing system and customer-specific email templates.
- Created multiple migrations for Nextcloud instances, cache, audit logs, email templates, sag comments, hardware locations, and billing methods.
- Enhanced the sag module with solutions, order lines, work types, and 2FA support for user authentication.
2026-02-02 20:23:56 +01:00
const timeout = setTimeout(async () => {
2026-09-08 01:55:47 +02:00
if (event.target.value.trim() !== query || document.activeElement !== event.target) return;
feat(sag): Add Varekøb & Salg module with database migration and frontend template
- Created a new SQL migration for the sag_salgsvarer table to manage sales and purchase items.
- Implemented a new HTML template for the Varekøb & Salg module, including summary cards and tables for sales and purchases.
- Added JavaScript functions for loading and rendering order data dynamically.
- Introduced a new backend search module for customers, contacts, hardware, and locations with autocomplete functionality.
- Developed an email templates API for managing system and customer-specific email templates.
- Created multiple migrations for Nextcloud instances, cache, audit logs, email templates, sag comments, hardware locations, and billing methods.
- Enhanced the sag module with solutions, order lines, work types, and 2FA support for user authentication.
2026-02-02 20:23:56 +01:00
try {
// Show loading state
resultsDiv.classList.remove('d-none');
resultsDiv.innerHTML = '< div class = "p-3 text-muted small" > < span class = "spinner-border spinner-border-sm me-2" > < / span > Søger...< / div > ';
2026-01-31 23:16:24 +01:00
feat(sag): Add Varekøb & Salg module with database migration and frontend template
- Created a new SQL migration for the sag_salgsvarer table to manage sales and purchase items.
- Implemented a new HTML template for the Varekøb & Salg module, including summary cards and tables for sales and purchases.
- Added JavaScript functions for loading and rendering order data dynamically.
- Introduced a new backend search module for customers, contacts, hardware, and locations with autocomplete functionality.
- Developed an email templates API for managing system and customer-specific email templates.
- Created multiple migrations for Nextcloud instances, cache, audit logs, email templates, sag comments, hardware locations, and billing methods.
- Enhanced the sag module with solutions, order lines, work types, and 2FA support for user authentication.
2026-02-02 20:23:56 +01:00
const endpoint = type === 'customer' ? '/api/v1/search/customers' : '/api/v1/search/contacts';
2026-05-12 08:41:13 +02:00
const response = await fetch(`${endpoint}?q=${encodeURIComponent(query)}`, {
headers: authHeaders,
credentials: 'include'
});
feat(sag): Add Varekøb & Salg module with database migration and frontend template
- Created a new SQL migration for the sag_salgsvarer table to manage sales and purchase items.
- Implemented a new HTML template for the Varekøb & Salg module, including summary cards and tables for sales and purchases.
- Added JavaScript functions for loading and rendering order data dynamically.
- Introduced a new backend search module for customers, contacts, hardware, and locations with autocomplete functionality.
- Developed an email templates API for managing system and customer-specific email templates.
- Created multiple migrations for Nextcloud instances, cache, audit logs, email templates, sag comments, hardware locations, and billing methods.
- Enhanced the sag module with solutions, order lines, work types, and 2FA support for user authentication.
2026-02-02 20:23:56 +01:00
if (!response.ok) {
const errorText = await response.text();
resultsDiv.innerHTML = `< div class = "p-3 text-danger small" > Fejl ved søgning: ${errorText}< / div > `;
return;
}
const data = await response.json();
2026-09-08 01:55:47 +02:00
if (event.target.value.trim() !== query || document.activeElement !== event.target) return;
feat(sag): Add Varekøb & Salg module with database migration and frontend template
- Created a new SQL migration for the sag_salgsvarer table to manage sales and purchase items.
- Implemented a new HTML template for the Varekøb & Salg module, including summary cards and tables for sales and purchases.
- Added JavaScript functions for loading and rendering order data dynamically.
- Introduced a new backend search module for customers, contacts, hardware, and locations with autocomplete functionality.
- Developed an email templates API for managing system and customer-specific email templates.
- Created multiple migrations for Nextcloud instances, cache, audit logs, email templates, sag comments, hardware locations, and billing methods.
- Enhanced the sag module with solutions, order lines, work types, and 2FA support for user authentication.
2026-02-02 20:23:56 +01:00
if (!Array.isArray(data)) {
resultsDiv.innerHTML = '< div class = "p-3 text-danger small" > Fejl ved søgning< / div > ';
2026-01-31 23:16:24 +01:00
return;
}
feat(sag): Add Varekøb & Salg module with database migration and frontend template
- Created a new SQL migration for the sag_salgsvarer table to manage sales and purchase items.
- Implemented a new HTML template for the Varekøb & Salg module, including summary cards and tables for sales and purchases.
- Added JavaScript functions for loading and rendering order data dynamically.
- Introduced a new backend search module for customers, contacts, hardware, and locations with autocomplete functionality.
- Developed an email templates API for managing system and customer-specific email templates.
- Created multiple migrations for Nextcloud instances, cache, audit logs, email templates, sag comments, hardware locations, and billing methods.
- Enhanced the sag module with solutions, order lines, work types, and 2FA support for user authentication.
2026-02-02 20:23:56 +01:00
if (data.length === 0) {
2026-02-03 15:37:16 +01:00
const quickAction = type === 'customer'
? `< button class = "btn btn-sm btn-outline-primary mt-2" onclick = "quickCreateCustomer('${query.replace(/'/g, " \ \ ' " ) } ' ) " > Opret nyt firma< / button > `
: `< button class = "btn btn-sm btn-outline-primary mt-2" onclick = "quickCreateContact('${query.replace(/'/g, " \ \ ' " ) } ' ) " > Opret ny kontakt< / button > `;
resultsDiv.innerHTML = `
< div class = "p-3 text-muted small" > Ingen fundet< / div >
< div class = "p-3 pt-0" > ${quickAction}< / div >
`;
feat(sag): Add Varekøb & Salg module with database migration and frontend template
- Created a new SQL migration for the sag_salgsvarer table to manage sales and purchase items.
- Implemented a new HTML template for the Varekøb & Salg module, including summary cards and tables for sales and purchases.
- Added JavaScript functions for loading and rendering order data dynamically.
- Introduced a new backend search module for customers, contacts, hardware, and locations with autocomplete functionality.
- Developed an email templates API for managing system and customer-specific email templates.
- Created multiple migrations for Nextcloud instances, cache, audit logs, email templates, sag comments, hardware locations, and billing methods.
- Enhanced the sag module with solutions, order lines, work types, and 2FA support for user authentication.
2026-02-02 20:23:56 +01:00
} else {
resultsDiv.innerHTML = data.map(item => {
const name = type === 'customer' ? item.name : `${item.first_name} ${item.last_name}`;
2026-05-12 08:41:13 +02:00
const meta = type === 'customer'
? (item.email || ('CVR: ' + (item.cvr_nummer || '-')))
: `${item.user_company || 'Ingen firma'} · Tlf: ${item.mobile || item.phone || item.user_company_phone || '-'}`;
2026-01-31 23:16:24 +01:00
feat(sag): Add Varekøb & Salg module with database migration and frontend template
- Created a new SQL migration for the sag_salgsvarer table to manage sales and purchase items.
- Implemented a new HTML template for the Varekøb & Salg module, including summary cards and tables for sales and purchases.
- Added JavaScript functions for loading and rendering order data dynamically.
- Introduced a new backend search module for customers, contacts, hardware, and locations with autocomplete functionality.
- Developed an email templates API for managing system and customer-specific email templates.
- Created multiple migrations for Nextcloud instances, cache, audit logs, email templates, sag comments, hardware locations, and billing methods.
- Enhanced the sag module with solutions, order lines, work types, and 2FA support for user authentication.
2026-02-02 20:23:56 +01:00
// Handle escaping for JS function call
const safeName = name.replace(/'/g, "\\'");
const fn = type === 'customer' ? `selectCustomer(${item.id}, '${safeName}')` : `selectContact(${item.id}, '${safeName}')`;
return `
< div class = "search-result-item" onclick = "${fn}" >
< div class = "search-result-name" > ${name}< / div >
< div class = "search-result-meta" > ${meta}< / div >
< / div >
`;
}).join('');
}
} catch (err) {
console.error('Search error:', err);
resultsDiv.innerHTML = '< div class = "p-3 text-danger small" > Fejl ved søgning< / div > ';
}
}, 300);
if (type === 'customer') customerSearchTimeout = timeout;
else contactSearchTimeout = timeout;
2026-01-31 23:16:24 +01:00
}
2026-08-18 20:57:49 +02:00
function contactDisplayName(contact) {
return `${contact.first_name || ''} ${contact.last_name || ''}`.trim()
|| contact.name
|| `Kontakt #${contact.id}`;
}
function contactDisplayMeta(contact) {
const details = [];
if (contact.role) details.push(contact.role);
if (contact.email) details.push(contact.email);
const phone = contact.mobile || contact.phone;
if (phone) details.push(phone);
return details.join(' · ') || 'Ingen kontaktoplysninger';
}
function renderCustomerContactResults(query = '') {
const resultsDiv = document.getElementById('contactResults');
if (!resultsDiv || !selectedCustomer) return;
const normalizedQuery = String(query || '').trim().toLocaleLowerCase('da-DK');
2026-09-08 01:55:47 +02:00
if (normalizedQuery.length < 2 | | document . activeElement ! = = document . getElementById ( ' contactSearch ' ) ) {
resultsDiv.classList.add('d-none');
return;
}
2026-08-18 20:57:49 +02:00
const contacts = selectedCustomerContacts.filter((contact) => {
if (!normalizedQuery) return true;
return [
contactDisplayName(contact),
contact.email,
contact.mobile,
contact.phone,
contact.role
].some((value) => String(value || '').toLocaleLowerCase('da-DK').includes(normalizedQuery));
});
if (!contacts.length) {
resultsDiv.innerHTML = `< div class = "p-3 text-muted small" > ${
selectedCustomerContacts.length
? 'Ingen af firmaets kontakter matcher søgningen.'
: 'Firmaet har ingen registrerede kontakter.'
}< / div > `;
} else {
resultsDiv.innerHTML = contacts.map((contact) => {
const name = contactDisplayName(contact);
return `
< div class = "search-result-item" data-contact-id = "${Number(contact.id)}" >
< div class = "search-result-name" > ${escapeTopAlertHtml(name)}< / div >
< div class = "search-result-meta" > ${escapeTopAlertHtml(contactDisplayMeta(contact))}< / div >
< / div >
`;
}).join('');
resultsDiv.querySelectorAll('[data-contact-id]').forEach((row) => {
row.addEventListener('click', () => {
const contact = contacts.find((item) => Number(item.id) === Number(row.dataset.contactId));
if (contact) selectContact(contact.id, contactDisplayName(contact));
});
});
}
resultsDiv.classList.remove('d-none');
}
async function loadSelectedCustomerContacts(customerId) {
const contactInput = document.getElementById('contactSearch');
const context = document.getElementById('contactSearchContext');
const resultsDiv = document.getElementById('contactResults');
const loadToken = ++customerContactsLoadToken;
selectedCustomerContacts = [];
contactInput.placeholder = `Søg blandt kontakter hos ${selectedCustomer.name}...`;
2026-09-08 01:55:47 +02:00
context.textContent = `Søg blandt kontakter hos ${selectedCustomer.name} (mindst 2 tegn).`;
2026-08-18 20:57:49 +02:00
resultsDiv.innerHTML = '< div class = "p-3 text-muted small" > < span class = "spinner-border spinner-border-sm me-2" > < / span > Henter firmaets kontakter...< / div > ';
2026-09-08 01:55:47 +02:00
resultsDiv.classList.toggle('d-none', document.activeElement !== contactInput || contactInput.value.trim().length < 2 ) ;
2026-08-18 20:57:49 +02:00
try {
const response = await fetch(`/api/v1/customers/${customerId}/contacts`, { credentials: 'include' });
if (loadToken !== customerContactsLoadToken) return;
if (!response.ok) throw new Error(`HTTP ${response.status}`);
const contacts = await response.json();
selectedCustomerContacts = Array.isArray(contacts) ? contacts : [];
renderCustomerContactResults(contactInput.value);
} catch (error) {
if (loadToken !== customerContactsLoadToken) return;
console.error('Failed to load customer contacts:', error);
resultsDiv.innerHTML = '< div class = "p-3 text-danger small" > Firmaets kontakter kunne ikke hentes.< / div > ';
2026-09-08 01:55:47 +02:00
resultsDiv.classList.toggle('d-none', document.activeElement !== contactInput || contactInput.value.trim().length < 2 ) ;
2026-08-18 20:57:49 +02:00
}
}
function resetCustomerContactSearch() {
customerContactsLoadToken += 1;
selectedCustomerContacts = [];
const contactInput = document.getElementById('contactSearch');
const context = document.getElementById('contactSearchContext');
const resultsDiv = document.getElementById('contactResults');
contactInput.value = '';
contactInput.placeholder = 'Søg kontakt...';
context.textContent = 'Søg blandt alle kontakter.';
resultsDiv.innerHTML = '';
resultsDiv.classList.add('d-none');
}
feat(sag): Add Varekøb & Salg module with database migration and frontend template
- Created a new SQL migration for the sag_salgsvarer table to manage sales and purchase items.
- Implemented a new HTML template for the Varekøb & Salg module, including summary cards and tables for sales and purchases.
- Added JavaScript functions for loading and rendering order data dynamically.
- Introduced a new backend search module for customers, contacts, hardware, and locations with autocomplete functionality.
- Developed an email templates API for managing system and customer-specific email templates.
- Created multiple migrations for Nextcloud instances, cache, audit logs, email templates, sag comments, hardware locations, and billing methods.
- Enhanced the sag module with solutions, order lines, work types, and 2FA support for user authentication.
2026-02-02 20:23:56 +01:00
// --- Selection Logic ---
2026-02-20 07:10:06 +01:00
function selectCustomer(id, name, skipAlert = false) {
feat(sag): Add Varekøb & Salg module with database migration and frontend template
- Created a new SQL migration for the sag_salgsvarer table to manage sales and purchase items.
- Implemented a new HTML template for the Varekøb & Salg module, including summary cards and tables for sales and purchases.
- Added JavaScript functions for loading and rendering order data dynamically.
- Introduced a new backend search module for customers, contacts, hardware, and locations with autocomplete functionality.
- Developed an email templates API for managing system and customer-specific email templates.
- Created multiple migrations for Nextcloud instances, cache, audit logs, email templates, sag comments, hardware locations, and billing methods.
- Enhanced the sag module with solutions, order lines, work types, and 2FA support for user authentication.
2026-02-02 20:23:56 +01:00
selectedCustomer = { id, name };
document.getElementById('customer_id').value = id;
2026-01-31 23:16:24 +01:00
document.getElementById('customerSearch').value = '';
feat(sag): Add Varekøb & Salg module with database migration and frontend template
- Created a new SQL migration for the sag_salgsvarer table to manage sales and purchase items.
- Implemented a new HTML template for the Varekøb & Salg module, including summary cards and tables for sales and purchases.
- Added JavaScript functions for loading and rendering order data dynamically.
- Introduced a new backend search module for customers, contacts, hardware, and locations with autocomplete functionality.
- Developed an email templates API for managing system and customer-specific email templates.
- Created multiple migrations for Nextcloud instances, cache, audit logs, email templates, sag comments, hardware locations, and billing methods.
- Enhanced the sag module with solutions, order lines, work types, and 2FA support for user authentication.
2026-02-02 20:23:56 +01:00
document.getElementById('customerResults').classList.add('d-none');
renderSelections();
2026-04-01 21:34:58 +02:00
loadCreateTopAlertsForCustomer(id);
2026-08-18 20:57:49 +02:00
loadSelectedCustomerContacts(id);
2026-02-20 07:10:06 +01:00
// Show notification
if (!skipAlert) {
showSuccessAlert(`Valgte firma: ${name}`);
}
2026-01-31 23:16:24 +01:00
}
function removeCustomer() {
selectedCustomer = null;
document.getElementById('customer_id').value = '';
2026-08-18 20:57:49 +02:00
resetCustomerContactSearch();
feat(sag): Add Varekøb & Salg module with database migration and frontend template
- Created a new SQL migration for the sag_salgsvarer table to manage sales and purchase items.
- Implemented a new HTML template for the Varekøb & Salg module, including summary cards and tables for sales and purchases.
- Added JavaScript functions for loading and rendering order data dynamically.
- Introduced a new backend search module for customers, contacts, hardware, and locations with autocomplete functionality.
- Developed an email templates API for managing system and customer-specific email templates.
- Created multiple migrations for Nextcloud instances, cache, audit logs, email templates, sag comments, hardware locations, and billing methods.
- Enhanced the sag module with solutions, order lines, work types, and 2FA support for user authentication.
2026-02-02 20:23:56 +01:00
renderSelections();
2026-04-01 21:34:58 +02:00
loadCreateTopAlertsForCustomer(null);
2026-01-31 23:16:24 +01:00
}
feat(sag): Add Varekøb & Salg module with database migration and frontend template
- Created a new SQL migration for the sag_salgsvarer table to manage sales and purchase items.
- Implemented a new HTML template for the Varekøb & Salg module, including summary cards and tables for sales and purchases.
- Added JavaScript functions for loading and rendering order data dynamically.
- Introduced a new backend search module for customers, contacts, hardware, and locations with autocomplete functionality.
- Developed an email templates API for managing system and customer-specific email templates.
- Created multiple migrations for Nextcloud instances, cache, audit logs, email templates, sag comments, hardware locations, and billing methods.
- Enhanced the sag module with solutions, order lines, work types, and 2FA support for user authentication.
2026-02-02 20:23:56 +01:00
async function selectContact(id, name) {
2026-02-20 07:10:06 +01:00
const isNewContact = !selectedContacts[id];
if (isNewContact) {
feat(sag): Add Varekøb & Salg module with database migration and frontend template
- Created a new SQL migration for the sag_salgsvarer table to manage sales and purchase items.
- Implemented a new HTML template for the Varekøb & Salg module, including summary cards and tables for sales and purchases.
- Added JavaScript functions for loading and rendering order data dynamically.
- Introduced a new backend search module for customers, contacts, hardware, and locations with autocomplete functionality.
- Developed an email templates API for managing system and customer-specific email templates.
- Created multiple migrations for Nextcloud instances, cache, audit logs, email templates, sag comments, hardware locations, and billing methods.
- Enhanced the sag module with solutions, order lines, work types, and 2FA support for user authentication.
2026-02-02 20:23:56 +01:00
selectedContacts[id] = { id, name };
2026-01-31 23:16:24 +01:00
}
document.getElementById('contactSearch').value = '';
feat(sag): Add Varekøb & Salg module with database migration and frontend template
- Created a new SQL migration for the sag_salgsvarer table to manage sales and purchase items.
- Implemented a new HTML template for the Varekøb & Salg module, including summary cards and tables for sales and purchases.
- Added JavaScript functions for loading and rendering order data dynamically.
- Introduced a new backend search module for customers, contacts, hardware, and locations with autocomplete functionality.
- Developed an email templates API for managing system and customer-specific email templates.
- Created multiple migrations for Nextcloud instances, cache, audit logs, email templates, sag comments, hardware locations, and billing methods.
- Enhanced the sag module with solutions, order lines, work types, and 2FA support for user authentication.
2026-02-02 20:23:56 +01:00
document.getElementById('contactResults').classList.add('d-none');
renderSelections();
// Check for associated company (auto-select if single match)
try {
2026-03-30 07:50:15 +02:00
const response = await fetch(`/api/v1/contacts/${id}`, { credentials: 'include' });
feat(sag): Add Varekøb & Salg module with database migration and frontend template
- Created a new SQL migration for the sag_salgsvarer table to manage sales and purchase items.
- Implemented a new HTML template for the Varekøb & Salg module, including summary cards and tables for sales and purchases.
- Added JavaScript functions for loading and rendering order data dynamically.
- Introduced a new backend search module for customers, contacts, hardware, and locations with autocomplete functionality.
- Developed an email templates API for managing system and customer-specific email templates.
- Created multiple migrations for Nextcloud instances, cache, audit logs, email templates, sag comments, hardware locations, and billing methods.
- Enhanced the sag module with solutions, order lines, work types, and 2FA support for user authentication.
2026-02-02 20:23:56 +01:00
if (response.ok) {
const data = await response.json();
2026-02-10 14:40:38 +01:00
selectedContactsCompanies[id] = data.companies || [];
feat(sag): Add Varekøb & Salg module with database migration and frontend template
- Created a new SQL migration for the sag_salgsvarer table to manage sales and purchase items.
- Implemented a new HTML template for the Varekøb & Salg module, including summary cards and tables for sales and purchases.
- Added JavaScript functions for loading and rendering order data dynamically.
- Introduced a new backend search module for customers, contacts, hardware, and locations with autocomplete functionality.
- Developed an email templates API for managing system and customer-specific email templates.
- Created multiple migrations for Nextcloud instances, cache, audit logs, email templates, sag comments, hardware locations, and billing methods.
- Enhanced the sag module with solutions, order lines, work types, and 2FA support for user authentication.
2026-02-02 20:23:56 +01:00
if (data.companies & & data.companies.length === 1) {
const company = data.companies[0];
2026-02-20 07:10:06 +01:00
if (!selectedCustomer & & isNewContact) {
// Auto-select company silently, then show combined alert
selectCustomer(company.id, company.name, true);
showSuccessAlert(`Valgte kontakt: ${name} + firma: ${company.name}`, 4000);
} else if (isNewContact) {
// Just show contact alert
showSuccessAlert(`Valgte kontakt: ${name}`);
feat(sag): Add Varekøb & Salg module with database migration and frontend template
- Created a new SQL migration for the sag_salgsvarer table to manage sales and purchase items.
- Implemented a new HTML template for the Varekøb & Salg module, including summary cards and tables for sales and purchases.
- Added JavaScript functions for loading and rendering order data dynamically.
- Introduced a new backend search module for customers, contacts, hardware, and locations with autocomplete functionality.
- Developed an email templates API for managing system and customer-specific email templates.
- Created multiple migrations for Nextcloud instances, cache, audit logs, email templates, sag comments, hardware locations, and billing methods.
- Enhanced the sag module with solutions, order lines, work types, and 2FA support for user authentication.
2026-02-02 20:23:56 +01:00
}
2026-02-20 07:10:06 +01:00
} else if (isNewContact) {
// No auto-select, just show contact alert
showSuccessAlert(`Valgte kontakt: ${name}`);
feat(sag): Add Varekøb & Salg module with database migration and frontend template
- Created a new SQL migration for the sag_salgsvarer table to manage sales and purchase items.
- Implemented a new HTML template for the Varekøb & Salg module, including summary cards and tables for sales and purchases.
- Added JavaScript functions for loading and rendering order data dynamically.
- Introduced a new backend search module for customers, contacts, hardware, and locations with autocomplete functionality.
- Developed an email templates API for managing system and customer-specific email templates.
- Created multiple migrations for Nextcloud instances, cache, audit logs, email templates, sag comments, hardware locations, and billing methods.
- Enhanced the sag module with solutions, order lines, work types, and 2FA support for user authentication.
2026-02-02 20:23:56 +01:00
}
}
} catch (e) {
console.error("Auto-select company failed", e);
2026-02-20 07:10:06 +01:00
if (isNewContact) {
showSuccessAlert(`Valgte kontakt: ${name}`);
}
feat(sag): Add Varekøb & Salg module with database migration and frontend template
- Created a new SQL migration for the sag_salgsvarer table to manage sales and purchase items.
- Implemented a new HTML template for the Varekøb & Salg module, including summary cards and tables for sales and purchases.
- Added JavaScript functions for loading and rendering order data dynamically.
- Introduced a new backend search module for customers, contacts, hardware, and locations with autocomplete functionality.
- Developed an email templates API for managing system and customer-specific email templates.
- Created multiple migrations for Nextcloud instances, cache, audit logs, email templates, sag comments, hardware locations, and billing methods.
- Enhanced the sag module with solutions, order lines, work types, and 2FA support for user authentication.
2026-02-02 20:23:56 +01:00
}
2026-02-10 14:40:38 +01:00
loadHardwareForContacts();
2026-09-08 01:55:47 +02:00
window.caseCreateUI?.contactsChanged();
feat(sag): Add Varekøb & Salg module with database migration and frontend template
- Created a new SQL migration for the sag_salgsvarer table to manage sales and purchase items.
- Implemented a new HTML template for the Varekøb & Salg module, including summary cards and tables for sales and purchases.
- Added JavaScript functions for loading and rendering order data dynamically.
- Introduced a new backend search module for customers, contacts, hardware, and locations with autocomplete functionality.
- Developed an email templates API for managing system and customer-specific email templates.
- Created multiple migrations for Nextcloud instances, cache, audit logs, email templates, sag comments, hardware locations, and billing methods.
- Enhanced the sag module with solutions, order lines, work types, and 2FA support for user authentication.
2026-02-02 20:23:56 +01:00
}
2026-02-14 02:26:29 +01:00
function readTelefoniPrefill() {
const params = new URLSearchParams(window.location.search || '');
const contactIdRaw = params.get('contact_id');
const titleRaw = params.get('title');
const callIdRaw = params.get('telefoni_opkald_id');
const customerIdRaw = params.get('customer_id');
const descriptionRaw = params.get('description');
2026-08-31 13:01:35 +02:00
const internetConnectionIdRaw = params.get('internet_connection_id');
2026-02-14 02:26:29 +01:00
const contactId = contactIdRaw ? parseInt(contactIdRaw) : null;
const customerId = customerIdRaw ? parseInt(customerIdRaw) : null;
telefoniPrefill.contactId = Number.isFinite(contactId) ? contactId : null;
telefoniPrefill.customerId = Number.isFinite(customerId) ? customerId : null;
telefoniPrefill.title = titleRaw ? String(titleRaw) : null;
telefoniPrefill.callId = callIdRaw ? String(callIdRaw) : null;
telefoniPrefill.description = descriptionRaw ? String(descriptionRaw) : null;
2026-08-31 13:01:35 +02:00
const internetConnectionId = internetConnectionIdRaw ? parseInt(internetConnectionIdRaw) : null;
telefoniPrefill.internetConnectionId = Number.isFinite(internetConnectionId) ? internetConnectionId : null;
2026-02-14 02:26:29 +01:00
}
async function applyTelefoniPrefill() {
readTelefoniPrefill();
if (telefoniPrefill.title) {
const titelInput = document.getElementById('titel');
if (titelInput & & !titelInput.value.trim()) {
titelInput.value = telefoniPrefill.title;
}
}
if (telefoniPrefill.description) {
const beskrInput = document.getElementById('beskrivelse');
if (beskrInput & & !beskrInput.value.trim()) {
beskrInput.value = telefoniPrefill.description;
const charCount = document.getElementById('charCount');
if (charCount) {
charCount.textContent = beskrInput.value.length + " tegn";
}
}
}
if (telefoniPrefill.customerId & & !selectedCustomer) {
try {
2026-03-30 07:50:15 +02:00
const customerRes = await fetch(`/api/v1/customers/${telefoniPrefill.customerId}`, { credentials: 'include' });
2026-02-14 02:26:29 +01:00
if (customerRes.ok) {
const customer = await customerRes.json();
const customerName = customer.name || `Kunde #${telefoniPrefill.customerId}`;
selectCustomer(telefoniPrefill.customerId, customerName);
}
} catch (e) {
console.error('Customer prefill failed', e);
}
}
if (telefoniPrefill.contactId) {
try {
2026-03-30 07:50:15 +02:00
const res = await fetch(`/api/v1/contacts/${telefoniPrefill.contactId}`, { credentials: 'include' });
2026-02-14 02:26:29 +01:00
if (!res.ok) return;
const c = await res.json();
const name = `${c.first_name || ''} ${c.last_name || ''}`.trim() || `Kontakt #${telefoniPrefill.contactId}`;
await selectContact(telefoniPrefill.contactId, name);
} catch (e) {
console.error('Telefoni prefill failed', e);
}
}
2026-08-31 13:01:35 +02:00
if (telefoniPrefill.internetConnectionId) {
const panel = document.getElementById('internetConnectionPrefill');
try {
const res = await fetch(`/api/v1/internet-connections/${telefoniPrefill.internetConnectionId}`, { credentials: 'include' });
if (!res.ok) throw new Error('Forbindelsen findes ikke');
const connection = await res.json();
const reference = connection.circuit_number || connection.provider_reference || `#${telefoniPrefill.internetConnectionId}`;
panel.innerHTML = `< i class = "bi bi-router me-2" > < / i > < strong > Internetforbindelse knyttes til sagen:< / strong > ${escapeTopAlertHtml(connection.name || 'Internetforbindelse')} · ${escapeTopAlertHtml(reference)}${connection.address ? ` · ${escapeTopAlertHtml(connection.address)}` : ''}. < a href = "/economy/internet-connections/${telefoniPrefill.internetConnectionId}" class = "alert-link" > Åbn forbindelse< / a > < div class = "small mt-1" > Kunden vælges stadig manuelt og ændres ikke på forbindelsen.< / div > `;
panel.classList.remove('d-none');
const titleInput = document.getElementById('titel');
if (titleInput & & !titleInput.value.trim()) titleInput.value = `Vedr. forbindelse ${reference}`;
} catch (error) {
panel.textContent = `Internetforbindelse #${telefoniPrefill.internetConnectionId} kunne ikke hentes.`;
panel.className = 'alert alert-warning mb-4';
}
}
2026-02-14 02:26:29 +01:00
}
feat(sag): Add Varekøb & Salg module with database migration and frontend template
- Created a new SQL migration for the sag_salgsvarer table to manage sales and purchase items.
- Implemented a new HTML template for the Varekøb & Salg module, including summary cards and tables for sales and purchases.
- Added JavaScript functions for loading and rendering order data dynamically.
- Introduced a new backend search module for customers, contacts, hardware, and locations with autocomplete functionality.
- Developed an email templates API for managing system and customer-specific email templates.
- Created multiple migrations for Nextcloud instances, cache, audit logs, email templates, sag comments, hardware locations, and billing methods.
- Enhanced the sag module with solutions, order lines, work types, and 2FA support for user authentication.
2026-02-02 20:23:56 +01:00
function removeContact(id) {
delete selectedContacts[id];
2026-02-10 14:40:38 +01:00
delete selectedContactsCompanies[id];
feat(sag): Add Varekøb & Salg module with database migration and frontend template
- Created a new SQL migration for the sag_salgsvarer table to manage sales and purchase items.
- Implemented a new HTML template for the Varekøb & Salg module, including summary cards and tables for sales and purchases.
- Added JavaScript functions for loading and rendering order data dynamically.
- Introduced a new backend search module for customers, contacts, hardware, and locations with autocomplete functionality.
- Developed an email templates API for managing system and customer-specific email templates.
- Created multiple migrations for Nextcloud instances, cache, audit logs, email templates, sag comments, hardware locations, and billing methods.
- Enhanced the sag module with solutions, order lines, work types, and 2FA support for user authentication.
2026-02-02 20:23:56 +01:00
renderSelections();
2026-02-10 14:40:38 +01:00
loadHardwareForContacts();
2026-09-08 01:55:47 +02:00
window.caseCreateUI?.contactsChanged();
2026-01-31 23:16:24 +01:00
}
feat(sag): Add Varekøb & Salg module with database migration and frontend template
- Created a new SQL migration for the sag_salgsvarer table to manage sales and purchase items.
- Implemented a new HTML template for the Varekøb & Salg module, including summary cards and tables for sales and purchases.
- Added JavaScript functions for loading and rendering order data dynamically.
- Introduced a new backend search module for customers, contacts, hardware, and locations with autocomplete functionality.
- Developed an email templates API for managing system and customer-specific email templates.
- Created multiple migrations for Nextcloud instances, cache, audit logs, email templates, sag comments, hardware locations, and billing methods.
- Enhanced the sag module with solutions, order lines, work types, and 2FA support for user authentication.
2026-02-02 20:23:56 +01:00
function renderSelections() {
// Customer
const custDiv = document.getElementById('selectedCustomer');
if (selectedCustomer) {
custDiv.innerHTML = `
< div class = "selected-item border-primary bg-primary bg-opacity-10 text-primary" >
< i class = "bi bi-building me-2" > < / i > ${selectedCustomer.name}
< button type = "button" onclick = "removeCustomer()" class = "text-primary hover-opacity" > < i class = "bi bi-x" > < / i > < / button >
< / div > `;
} else {
custDiv.innerHTML = '';
}
// Contacts
const contDiv = document.getElementById('selectedContacts');
contDiv.innerHTML = Object.values(selectedContacts).map(c => `
< div class = "selected-item" >
< i class = "bi bi-person me-2" > < / i > ${c.name}
< button type = "button" onclick = "removeContact(${c.id})" > < i class = "bi bi-x" > < / i > < / button >
< / div >
2026-01-31 23:16:24 +01:00
`).join('');
}
2026-02-10 14:40:38 +01:00
async function loadHardwareForContacts() {
const hardwareList = document.getElementById('hardwareList');
if (!hardwareList) return;
const contactIds = Object.keys(selectedContacts).map(id => parseInt(id));
if (contactIds.length === 0) {
hardwareList.innerHTML = '< div class = "text-muted small" > Vælg en kontakt for at se relateret hardware.< / div > ';
return;
}
hardwareList.innerHTML = '< div class = "text-muted small" > < span class = "spinner-border spinner-border-sm me-2" > < / span > Henter hardware...< / div > ';
try {
const responses = await Promise.all(
2026-03-30 07:50:15 +02:00
contactIds.map(contactId => fetch(`/api/v1/hardware/by-contact/${contactId}`, { credentials: 'include' }))
2026-02-10 14:40:38 +01:00
);
const datasets = await Promise.all(responses.map(r => r.ok ? r.json() : []));
const merged = new Map();
datasets.flat().forEach(item => {
if (!merged.has(item.id)) {
merged.set(item.id, item);
}
});
renderHardwareList(Array.from(merged.values()));
} catch (err) {
console.error('Failed to load hardware:', err);
hardwareList.innerHTML = '< div class = "text-danger small" > Kunne ikke hente hardware.< / div > ';
}
}
function renderHardwareList(items) {
const hardwareList = document.getElementById('hardwareList');
if (!hardwareList) return;
if (!items || items.length === 0) {
hardwareList.innerHTML = '< div class = "text-muted small" > Ingen hardware fundet for valgte kontakt(er).< / div > ';
return;
}
hardwareList.innerHTML = items.map(item => {
const name = item.model || item.brand || `Hardware #${item.id}`;
const anydeskId = item.anydesk_id || '-';
const anydeskLink = item.anydesk_link || '';
const linkBtn = anydeskLink
? `< button type = "button" class = "btn btn-sm btn-outline-primary" onclick = "openAnyDeskLink('${anydeskLink.replace(/'/g, " \ \ ' " ) } ' ) " > Connect< / button > `
: '';
const copyBtn = item.anydesk_id
? `< button type = "button" class = "btn btn-sm btn-outline-secondary" onclick = "copyAnyDeskId('${item.anydesk_id.replace(/'/g, " \ \ ' " ) } ' ) " > Kopiér ID< / button > `
: '';
return `
< div class = "d-flex flex-wrap align-items-center justify-content-between border-bottom py-2" >
< div >
< div class = "fw-bold" > ${name}< / div >
< div class = "text-muted small" > AnyDesk ID: ${anydeskId}< / div >
< / div >
< div class = "d-flex gap-2" >
${linkBtn}
${copyBtn}
< / div >
< / div >
`;
}).join('');
}
function openAnyDeskLink(link) {
if (!link) return;
window.open(link, '_blank');
}
async function copyAnyDeskId(anydeskId) {
if (!anydeskId) return;
try {
await navigator.clipboard.writeText(anydeskId);
2026-08-30 14:34:43 +02:00
showSuccessAlert('AnyDesk ID kopieret');
2026-02-10 14:40:38 +01:00
} catch (err) {
console.error('Copy failed', err);
}
}
2026-02-11 13:23:32 +01:00
2026-02-10 14:40:38 +01:00
async function quickCreateHardware() {
const name = document.getElementById('hardwareNameInput').value.trim();
const anydeskId = document.getElementById('hardwareAnyDeskIdInput').value.trim();
2026-02-11 13:23:32 +01:00
const anydeskLink = anydeskId ? `anydesk://${anydeskId}` : null;
2026-02-10 14:40:38 +01:00
if (!name) {
2026-08-30 14:34:43 +02:00
showCreateError('Navn er påkrævet');
2026-02-10 14:40:38 +01:00
return;
}
const customerId = selectedCustomer?.id || getSingleContactCompanyId();
if (!customerId) {
2026-08-30 14:34:43 +02:00
showCreateError('Vælg et firma før du opretter hardware');
2026-02-10 14:40:38 +01:00
return;
}
try {
const response = await fetch('/api/v1/hardware/quick', {
method: 'POST',
2026-03-30 07:50:15 +02:00
credentials: 'include',
2026-02-10 14:40:38 +01:00
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
name,
customer_id: customerId,
anydesk_id: anydeskId || null,
anydesk_link: anydeskLink || null
})
});
if (!response.ok) {
const err = await response.json();
throw new Error(err.detail || 'Kunne ikke oprette hardware');
}
document.getElementById('hardwareNameInput').value = '';
document.getElementById('hardwareAnyDeskIdInput').value = '';
await loadHardwareForContacts();
} catch (err) {
2026-08-30 14:34:43 +02:00
showCreateError('Fejl: ' + err.message);
2026-02-10 14:40:38 +01:00
}
}
function getSingleContactCompanyId() {
const contactIds = Object.keys(selectedContactsCompanies);
if (contactIds.length !== 1) return null;
const companies = selectedContactsCompanies[contactIds[0]] || [];
if (companies.length !== 1) return null;
return companies[0].id;
}
2026-02-03 15:37:16 +01:00
async function quickCreateCustomer(name) {
if (!name || name.trim().length < 2 ) return ;
const resultsDiv = document.getElementById('customerResults');
resultsDiv.innerHTML = '< div class = "p-3 text-muted small" > < span class = "spinner-border spinner-border-sm me-2" > < / span > Opretter firma...< / div > ';
try {
const response = await fetch('/api/v1/customers', {
method: 'POST',
2026-03-30 07:50:15 +02:00
credentials: 'include',
2026-02-03 15:37:16 +01:00
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ name: name.trim() })
});
if (!response.ok) {
const err = await response.json();
throw new Error(err.detail || 'Kunne ikke oprette firma');
}
const created = await response.json();
selectCustomer(created.id, created.name);
const contactIds = Object.keys(selectedContacts).map(id => parseInt(id));
if (contactIds.length) {
const linkResponses = await Promise.all(contactIds.map(contactId =>
fetch(`/api/v1/contacts/${contactId}/companies`, {
method: 'POST',
2026-03-30 07:50:15 +02:00
credentials: 'include',
2026-02-03 15:37:16 +01:00
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ customer_id: created.id, is_primary: false })
})
));
const failed = linkResponses.find(res => !res.ok);
if (failed) {
const err = await failed.json();
throw new Error(err.detail || 'Kunne ikke linke kontakt til firma');
}
}
return created;
} catch (err) {
resultsDiv.innerHTML = `< div class = "p-3 text-danger small" > ${err.message}< / div > `;
throw err;
}
}
async function quickCreateContact(fullName) {
if (!fullName || fullName.trim().length < 2 ) return ;
const resultsDiv = document.getElementById('contactResults');
resultsDiv.innerHTML = '< div class = "p-3 text-muted small" > < span class = "spinner-border spinner-border-sm me-2" > < / span > Opretter kontakt...< / div > ';
const parts = fullName.trim().split(/\s+/);
const firstName = parts.shift() || '';
const lastName = parts.join(' ');
try {
const payload = {
first_name: firstName,
last_name: lastName,
company_id: selectedCustomer ? selectedCustomer.id : null
};
const response = await fetch('/api/v1/contacts', {
method: 'POST',
2026-03-30 07:50:15 +02:00
credentials: 'include',
2026-02-03 15:37:16 +01:00
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(payload)
});
if (!response.ok) {
const err = await response.json();
throw new Error(err.detail || 'Kunne ikke oprette kontakt');
}
const created = await response.json();
await selectContact(created.id, `${created.first_name} ${created.last_name}`.trim());
return created;
} catch (err) {
resultsDiv.innerHTML = `< div class = "p-3 text-danger small" > ${err.message}< / div > `;
throw err;
}
}
2026-07-17 01:58:02 +02:00
const caseTypeLabels = {
ticket: '🎫 Ticket', pipeline: '📈 Pipeline', opgave: '🧩 Opgave',
2026-08-17 19:27:43 +02:00
ordre: '🧾 Ordre', projekt: '📁 Projekt', service: '🛠️ Service',
abonnement: '🔁 Abonnement'
2026-07-17 01:58:02 +02:00
};
function updateCaseTypeSections() {
const type = document.getElementById('type')?.value || 'ticket';
2026-09-08 01:55:47 +02:00
['hardwareSection', 'pipelineSection', 'orderSection'].forEach(id => document.getElementById(id)?.classList.remove('d-none'));
window.caseCreateUI?.typeChanged(type);
2026-07-17 01:58:02 +02:00
const help = document.getElementById('caseTypeHelp');
2026-09-08 01:55:47 +02:00
if (help) help.textContent = type === 'ticket' ? 'Tilføj eventuelt hardware og AnyDesk til din ticket. Alle ekstra funktioner er tilgængelige.'
2026-07-17 01:58:02 +02:00
: type === 'pipeline' ? 'Udfyld pipelineoplysninger for muligheden.'
: type === 'ordre' ? 'Tilføj indkøbs- og salgslinjer til ordren.'
2026-09-08 01:55:47 +02:00
: 'Tilføj hardware, pipeline, tags og køb/salg efter behov.';
2026-07-17 01:58:02 +02:00
}
function renderOrderLinesEmptyState() {
const hasLines = document.querySelectorAll('#orderLines .order-line').length > 0;
document.getElementById('orderLinesEmpty')?.classList.toggle('d-none', hasLines);
}
function addOrderLine(type = 'sale') {
const id = ++orderLineCounter;
const label = type === 'purchase' ? 'Indkøb' : 'Salg';
const purpose = type === 'purchase' ? `
< div class = "col-md-4" > < label class = "form-label" > Indkøbsformål< / label > < select class = "form-select order-purpose" > < option value = "" > Vælg formål< / option > < option value = "salg" > Salg< / option > < option value = "lager" > Lager< / option > < option value = "asset" > Asset< / option > < option value = "intern_brug" > Intern brug< / option > < option value = "retur_reklamation" > Retur/reklamation< / option > < option value = "projekt_omkostning" > Projektomkostning< / option > < / select > < / div > ` : '';
const container = document.getElementById('orderLines');
container.insertAdjacentHTML('beforeend', `
< div class = "order-line border rounded-3 p-3 bg-light" data-line-id = "${id}" >
< div class = "d-flex justify-content-between align-items-center mb-3" > < strong > ${label}< / strong > < button type = "button" class = "btn btn-sm btn-outline-danger" onclick = "removeOrderLine(${id})" > < i class = "bi bi-trash" > < / i > < / button > < / div >
< input type = "hidden" class = "order-type" value = "${type}" >
< div class = "row g-3" >
< div class = "col-md-6" > < label class = "form-label" > Beskrivelse < span class = "text-danger" > *< / span > < / label > < input class = "form-control order-description" placeholder = "F.eks. switch, licens eller montage" > < / div >
< div class = "col-md-2" > < label class = "form-label" > Antal< / label > < input type = "number" min = "0" step = "0.01" class = "form-control order-quantity" > < / div >
< div class = "col-md-2" > < label class = "form-label" > Enhed< / label > < input class = "form-control order-unit" placeholder = "stk" > < / div >
< div class = "col-md-2" > < label class = "form-label" > Enhedspris< / label > < input type = "number" min = "0" step = "0.01" class = "form-control order-unit-price" > < / div >
< div class = "col-md-3" > < label class = "form-label" > Beløb < span class = "text-danger" > *< / span > < / label > < input type = "number" min = "0" step = "0.01" class = "form-control order-amount" > < / div >
< div class = "col-md-2" > < label class = "form-label" > Valuta< / label > < input class = "form-control order-currency" value = "DKK" > < / div >
< div class = "col-md-3" > < label class = "form-label" > Status< / label > < select class = "form-select order-status" > < option value = "draft" > Kladde< / option > < option value = "confirmed" > Bekræftet< / option > < option value = "cancelled" > Annulleret< / option > < / select > < / div >
< div class = "col-md-4" > < label class = "form-label" > Reference< / label > < input class = "form-control order-reference" > < / div >
${purpose}
< / div >
< / div > `);
renderOrderLinesEmptyState();
}
function removeOrderLine(id) {
document.querySelector(`.order-line[data-line-id="${id}"]`)?.remove();
renderOrderLinesEmptyState();
}
function collectOrderItems() {
return Array.from(document.querySelectorAll('#orderLines .order-line')).map(line => ({
type: line.querySelector('.order-type').value,
description: line.querySelector('.order-description').value.trim(),
quantity: line.querySelector('.order-quantity').value || null,
unit: line.querySelector('.order-unit').value.trim() || null,
unit_price: line.querySelector('.order-unit-price').value || null,
amount: line.querySelector('.order-amount').value || null,
currency: line.querySelector('.order-currency').value.trim() || 'DKK',
status: line.querySelector('.order-status').value,
external_ref: line.querySelector('.order-reference').value.trim() || null,
purchase_purpose: line.querySelector('.order-purpose')?.value || null
}));
}
async function loadPipelineStages() {
const select = document.getElementById('pipeline_stage_id');
if (!select) return;
try {
const response = await fetch('/api/v1/pipeline/stages', { credentials: 'include' });
if (!response.ok) return;
const stages = await response.json();
select.innerHTML = '< option value = "" > Ikke sat< / option > ' + (stages || []).map(stage => `< option value = "${stage.id}" > ${stage.name}< / option > `).join('');
} catch (err) { console.error('Failed to load pipeline stages', err); }
}
feat(sag): Add Varekøb & Salg module with database migration and frontend template
- Created a new SQL migration for the sag_salgsvarer table to manage sales and purchase items.
- Implemented a new HTML template for the Varekøb & Salg module, including summary cards and tables for sales and purchases.
- Added JavaScript functions for loading and rendering order data dynamically.
- Introduced a new backend search module for customers, contacts, hardware, and locations with autocomplete functionality.
- Developed an email templates API for managing system and customer-specific email templates.
- Created multiple migrations for Nextcloud instances, cache, audit logs, email templates, sag comments, hardware locations, and billing methods.
- Enhanced the sag module with solutions, order lines, work types, and 2FA support for user authentication.
2026-02-02 20:23:56 +01:00
async function loadCaseTypesSelect() {
const select = document.getElementById('type');
if (!select) return;
try {
2026-07-17 01:58:02 +02:00
const [typesRes, profileRes] = await Promise.all([
fetch('/api/v1/settings/case_types', { credentials: 'include' }),
fetch('/api/v1/auth/me/profile', { credentials: 'include' })
]);
const setting = typesRes.ok ? await typesRes.json() : { value: '[]' };
const profile = profileRes.ok ? await profileRes.json() : {};
const configured = JSON.parse(setting.value || '[]');
2026-09-08 01:55:47 +02:00
const types = Array.isArray(configured) & & configured.length ? configured.map(type => String(type).trim().toLowerCase()).filter(Boolean) : Object.keys(caseTypeLabels);
2026-07-17 01:58:02 +02:00
if (!types.includes('pipeline')) types.splice(1, 0, 'pipeline');
2026-08-17 19:27:43 +02:00
if (!types.includes('abonnement')) types.push('abonnement');
2026-07-17 01:58:02 +02:00
const finalTypes = types.length ? [...new Set(types)] : Object.keys(caseTypeLabels);
select.innerHTML = finalTypes.map(type => `< option value = "${type}" > ${caseTypeLabels[type] || type}< / option > `).join('');
select.value = finalTypes.includes(profile.default_case_type) ? profile.default_case_type : (finalTypes.includes('ticket') ? 'ticket' : finalTypes[0]);
feat(sag): Add Varekøb & Salg module with database migration and frontend template
- Created a new SQL migration for the sag_salgsvarer table to manage sales and purchase items.
- Implemented a new HTML template for the Varekøb & Salg module, including summary cards and tables for sales and purchases.
- Added JavaScript functions for loading and rendering order data dynamically.
- Introduced a new backend search module for customers, contacts, hardware, and locations with autocomplete functionality.
- Developed an email templates API for managing system and customer-specific email templates.
- Created multiple migrations for Nextcloud instances, cache, audit logs, email templates, sag comments, hardware locations, and billing methods.
- Enhanced the sag module with solutions, order lines, work types, and 2FA support for user authentication.
2026-02-02 20:23:56 +01:00
} catch (err) {
console.error('Failed to load case types', err);
2026-07-17 01:58:02 +02:00
select.innerHTML = Object.entries(caseTypeLabels).map(([type, label]) => `< option value = "${type}" > ${label}< / option > `).join('');
feat(sag): Add Varekøb & Salg module with database migration and frontend template
- Created a new SQL migration for the sag_salgsvarer table to manage sales and purchase items.
- Implemented a new HTML template for the Varekøb & Salg module, including summary cards and tables for sales and purchases.
- Added JavaScript functions for loading and rendering order data dynamically.
- Introduced a new backend search module for customers, contacts, hardware, and locations with autocomplete functionality.
- Developed an email templates API for managing system and customer-specific email templates.
- Created multiple migrations for Nextcloud instances, cache, audit logs, email templates, sag comments, hardware locations, and billing methods.
- Enhanced the sag module with solutions, order lines, work types, and 2FA support for user authentication.
2026-02-02 20:23:56 +01:00
}
2026-07-17 01:58:02 +02:00
updateCaseTypeSections();
2026-01-31 23:16:24 +01:00
}
2026-08-28 20:49:55 +02:00
async function selectCurrentUserAsResponsible() {
const select = document.getElementById('ansvarlig_bruger_id');
if (!select || select.value) return;
try {
const response = await fetch('/api/v1/auth/me', { credentials: 'include' });
if (!response.ok) return;
const user = await response.json();
const userId = user.user_id ?? user.id;
if (userId & & Array.from(select.options).some(option => option.value === String(userId))) {
select.value = String(userId);
}
} catch (error) {
console.error('Kunne ikke forvælge ansvarlig bruger', error);
}
}
feat(sag): Add Varekøb & Salg module with database migration and frontend template
- Created a new SQL migration for the sag_salgsvarer table to manage sales and purchase items.
- Implemented a new HTML template for the Varekøb & Salg module, including summary cards and tables for sales and purchases.
- Added JavaScript functions for loading and rendering order data dynamically.
- Introduced a new backend search module for customers, contacts, hardware, and locations with autocomplete functionality.
- Developed an email templates API for managing system and customer-specific email templates.
- Created multiple migrations for Nextcloud instances, cache, audit logs, email templates, sag comments, hardware locations, and billing methods.
- Enhanced the sag module with solutions, order lines, work types, and 2FA support for user authentication.
2026-02-02 20:23:56 +01:00
// --- Initialization ---
2026-09-08 01:55:47 +02:00
document.addEventListener('DOMContentLoaded', async () => {
feat(sag): Add Varekøb & Salg module with database migration and frontend template
- Created a new SQL migration for the sag_salgsvarer table to manage sales and purchase items.
- Implemented a new HTML template for the Varekøb & Salg module, including summary cards and tables for sales and purchases.
- Added JavaScript functions for loading and rendering order data dynamically.
- Introduced a new backend search module for customers, contacts, hardware, and locations with autocomplete functionality.
- Developed an email templates API for managing system and customer-specific email templates.
- Created multiple migrations for Nextcloud instances, cache, audit logs, email templates, sag comments, hardware locations, and billing methods.
- Enhanced the sag module with solutions, order lines, work types, and 2FA support for user authentication.
2026-02-02 20:23:56 +01:00
initializeSearch();
2026-09-08 01:55:47 +02:00
await Promise.all([loadCaseTypesSelect(), loadPipelineStages(), selectCurrentUserAsResponsible()]);
2026-07-17 01:58:02 +02:00
document.getElementById('type')?.addEventListener('change', updateCaseTypeSections);
2026-09-08 01:55:47 +02:00
await applyTelefoniPrefill();
await window.caseCreateUI?.init();
feat(sag): Add Varekøb & Salg module with database migration and frontend template
- Created a new SQL migration for the sag_salgsvarer table to manage sales and purchase items.
- Implemented a new HTML template for the Varekøb & Salg module, including summary cards and tables for sales and purchases.
- Added JavaScript functions for loading and rendering order data dynamically.
- Introduced a new backend search module for customers, contacts, hardware, and locations with autocomplete functionality.
- Developed an email templates API for managing system and customer-specific email templates.
- Created multiple migrations for Nextcloud instances, cache, audit logs, email templates, sag comments, hardware locations, and billing methods.
- Enhanced the sag module with solutions, order lines, work types, and 2FA support for user authentication.
2026-02-02 20:23:56 +01:00
});
// --- Form Submission ---
2026-01-31 23:16:24 +01:00
document.getElementById('createForm').addEventListener('submit', async (e) => {
e.preventDefault();
2026-09-08 01:55:47 +02:00
if (window.caseCreateUI & & !window.caseCreateUI.validate()) return;
2026-01-31 23:16:24 +01:00
feat(sag): Add Varekøb & Salg module with database migration and frontend template
- Created a new SQL migration for the sag_salgsvarer table to manage sales and purchase items.
- Implemented a new HTML template for the Varekøb & Salg module, including summary cards and tables for sales and purchases.
- Added JavaScript functions for loading and rendering order data dynamically.
- Introduced a new backend search module for customers, contacts, hardware, and locations with autocomplete functionality.
- Developed an email templates API for managing system and customer-specific email templates.
- Created multiple migrations for Nextcloud instances, cache, audit logs, email templates, sag comments, hardware locations, and billing methods.
- Enhanced the sag module with solutions, order lines, work types, and 2FA support for user authentication.
2026-02-02 20:23:56 +01:00
// UI Reset
const errorDiv = document.getElementById('error');
const successDiv = document.getElementById('success');
const btn = document.getElementById('submitBtn');
errorDiv.classList.add('d-none');
successDiv.classList.add('d-none');
// Basic Validation
const titelInput = document.getElementById('titel');
const titel = titelInput.value;
2026-01-31 23:16:24 +01:00
const status = document.getElementById('status').value;
feat(sag): Add Varekøb & Salg module with database migration and frontend template
- Created a new SQL migration for the sag_salgsvarer table to manage sales and purchase items.
- Implemented a new HTML template for the Varekøb & Salg module, including summary cards and tables for sales and purchases.
- Added JavaScript functions for loading and rendering order data dynamically.
- Introduced a new backend search module for customers, contacts, hardware, and locations with autocomplete functionality.
- Developed an email templates API for managing system and customer-specific email templates.
- Created multiple migrations for Nextcloud instances, cache, audit logs, email templates, sag comments, hardware locations, and billing methods.
- Enhanced the sag module with solutions, order lines, work types, and 2FA support for user authentication.
2026-02-02 20:23:56 +01:00
if (!titel.trim()) {
titelInput.classList.add('is-invalid');
errorDiv.classList.remove('d-none');
document.getElementById('error-text').textContent = "Titel er påkrævet";
2026-01-31 23:16:24 +01:00
return;
feat(sag): Add Varekøb & Salg module with database migration and frontend template
- Created a new SQL migration for the sag_salgsvarer table to manage sales and purchase items.
- Implemented a new HTML template for the Varekøb & Salg module, including summary cards and tables for sales and purchases.
- Added JavaScript functions for loading and rendering order data dynamically.
- Introduced a new backend search module for customers, contacts, hardware, and locations with autocomplete functionality.
- Developed an email templates API for managing system and customer-specific email templates.
- Created multiple migrations for Nextcloud instances, cache, audit logs, email templates, sag comments, hardware locations, and billing methods.
- Enhanced the sag module with solutions, order lines, work types, and 2FA support for user authentication.
2026-02-02 20:23:56 +01:00
} else {
titelInput.classList.remove('is-invalid');
2026-01-31 23:16:24 +01:00
}
feat(sag): Add Varekøb & Salg module with database migration and frontend template
- Created a new SQL migration for the sag_salgsvarer table to manage sales and purchase items.
- Implemented a new HTML template for the Varekøb & Salg module, including summary cards and tables for sales and purchases.
- Added JavaScript functions for loading and rendering order data dynamically.
- Introduced a new backend search module for customers, contacts, hardware, and locations with autocomplete functionality.
- Developed an email templates API for managing system and customer-specific email templates.
- Created multiple migrations for Nextcloud instances, cache, audit logs, email templates, sag comments, hardware locations, and billing methods.
- Enhanced the sag module with solutions, order lines, work types, and 2FA support for user authentication.
2026-02-02 20:23:56 +01:00
// Loading State
btn.disabled = true;
const originalBtnText = btn.innerHTML;
btn.innerHTML = '< span class = "spinner-border spinner-border-sm me-2" > < / span > Opretter...';
2026-02-03 15:37:16 +01:00
try {
2026-05-12 08:41:13 +02:00
const token = localStorage.getItem('access_token') || sessionStorage.getItem('access_token');
const authHeaders = token ? { Authorization: `Bearer ${token}` } : {};
2026-02-03 15:37:16 +01:00
const customerQuery = document.getElementById('customerSearch').value.trim();
if (!selectedCustomer & & customerQuery.length >= 2) {
2026-05-12 08:41:13 +02:00
const res = await fetch(`/api/v1/search/customers?q=${encodeURIComponent(customerQuery)}`, {
headers: authHeaders,
credentials: 'include'
});
2026-02-03 15:37:16 +01:00
const matches = await res.json();
if (Array.isArray(matches) & & matches.length > 0) {
throw new Error('Firma findes allerede. Vælg det fra listen.');
}
await quickCreateCustomer(customerQuery);
}
const contactQuery = document.getElementById('contactSearch').value.trim();
if (Object.keys(selectedContacts).length === 0 & & contactQuery.length >= 2) {
2026-05-12 08:41:13 +02:00
const res = await fetch(`/api/v1/search/contacts?q=${encodeURIComponent(contactQuery)}`, {
headers: authHeaders,
credentials: 'include'
});
2026-02-03 15:37:16 +01:00
const matches = await res.json();
if (Array.isArray(matches) & & matches.length > 0) {
throw new Error('Kontakt findes allerede. Vælg den fra listen.');
}
await quickCreateContact(contactQuery);
}
} catch (err) {
errorDiv.classList.remove('d-none');
document.getElementById('error-text').textContent = err.message;
btn.disabled = false;
btn.innerHTML = originalBtnText;
return;
}
2026-01-31 23:16:24 +01:00
const data = {
titel: titel,
beskrivelse: document.getElementById('beskrivelse').value || '',
feat(sag): Add Varekøb & Salg module with database migration and frontend template
- Created a new SQL migration for the sag_salgsvarer table to manage sales and purchase items.
- Implemented a new HTML template for the Varekøb & Salg module, including summary cards and tables for sales and purchases.
- Added JavaScript functions for loading and rendering order data dynamically.
- Introduced a new backend search module for customers, contacts, hardware, and locations with autocomplete functionality.
- Developed an email templates API for managing system and customer-specific email templates.
- Created multiple migrations for Nextcloud instances, cache, audit logs, email templates, sag comments, hardware locations, and billing methods.
- Enhanced the sag module with solutions, order lines, work types, and 2FA support for user authentication.
2026-02-02 20:23:56 +01:00
type: document.getElementById('type').value,
2026-01-31 23:16:24 +01:00
status: status,
feat(sag): Add Varekøb & Salg module with database migration and frontend template
- Created a new SQL migration for the sag_salgsvarer table to manage sales and purchase items.
- Implemented a new HTML template for the Varekøb & Salg module, including summary cards and tables for sales and purchases.
- Added JavaScript functions for loading and rendering order data dynamically.
- Introduced a new backend search module for customers, contacts, hardware, and locations with autocomplete functionality.
- Developed an email templates API for managing system and customer-specific email templates.
- Created multiple migrations for Nextcloud instances, cache, audit logs, email templates, sag comments, hardware locations, and billing methods.
- Enhanced the sag module with solutions, order lines, work types, and 2FA support for user authentication.
2026-02-02 20:23:56 +01:00
customer_id: selectedCustomer ? selectedCustomer.id : null,
2026-01-31 23:16:24 +01:00
ansvarlig_bruger_id: document.getElementById('ansvarlig_bruger_id').value ? parseInt(document.getElementById('ansvarlig_bruger_id').value) : null,
2026-02-17 08:29:05 +01:00
assigned_group_id: document.getElementById('assigned_group_id').value ? parseInt(document.getElementById('assigned_group_id').value) : null,
2026-08-30 14:34:43 +02:00
deadline: document.getElementById('deadline').value || null,
contact_ids: Object.keys(selectedContacts).map(id => parseInt(id)).filter(Number.isFinite),
telefoni_opkald_id: telefoniPrefill.callId ? parseInt(telefoniPrefill.callId) : null
2026-01-31 23:16:24 +01:00
};
2026-08-31 13:01:35 +02:00
if (telefoniPrefill.internetConnectionId) {
data.internet_connection_ids = [telefoniPrefill.internetConnectionId];
}
feat(sag): Add Varekøb & Salg module with database migration and frontend template
- Created a new SQL migration for the sag_salgsvarer table to manage sales and purchase items.
- Implemented a new HTML template for the Varekøb & Salg module, including summary cards and tables for sales and purchases.
- Added JavaScript functions for loading and rendering order data dynamically.
- Introduced a new backend search module for customers, contacts, hardware, and locations with autocomplete functionality.
- Developed an email templates API for managing system and customer-specific email templates.
- Created multiple migrations for Nextcloud instances, cache, audit logs, email templates, sag comments, hardware locations, and billing methods.
- Enhanced the sag module with solutions, order lines, work types, and 2FA support for user authentication.
2026-02-02 20:23:56 +01:00
2026-09-08 01:55:47 +02:00
if (['pipeline_stage_id', 'pipeline_amount', 'pipeline_probability', 'pipeline_description'].some(id => document.getElementById(id).value !== '')) {
2026-07-17 01:58:02 +02:00
data.pipeline = {
stage_id: document.getElementById('pipeline_stage_id').value || null,
amount: document.getElementById('pipeline_amount').value || null,
probability: document.getElementById('pipeline_probability').value || null,
description: document.getElementById('pipeline_description').value || null
};
}
2026-09-08 01:55:47 +02:00
if (document.querySelector('#orderLines .order-line')) {
2026-07-17 01:58:02 +02:00
data.order_items = collectOrderItems();
}
2026-09-08 01:55:47 +02:00
Object.assign(data, window.caseCreateUI?.relations() || {});
2026-07-17 01:58:02 +02:00
2026-01-31 23:16:24 +01:00
try {
feat(sag): Add Varekøb & Salg module with database migration and frontend template
- Created a new SQL migration for the sag_salgsvarer table to manage sales and purchase items.
- Implemented a new HTML template for the Varekøb & Salg module, including summary cards and tables for sales and purchases.
- Added JavaScript functions for loading and rendering order data dynamically.
- Introduced a new backend search module for customers, contacts, hardware, and locations with autocomplete functionality.
- Developed an email templates API for managing system and customer-specific email templates.
- Created multiple migrations for Nextcloud instances, cache, audit logs, email templates, sag comments, hardware locations, and billing methods.
- Enhanced the sag module with solutions, order lines, work types, and 2FA support for user authentication.
2026-02-02 20:23:56 +01:00
const response = await fetch('/api/v1/sag', {
2026-01-31 23:16:24 +01:00
method: 'POST',
2026-03-30 07:50:15 +02:00
credentials: 'include',
feat(sag): Add Varekøb & Salg module with database migration and frontend template
- Created a new SQL migration for the sag_salgsvarer table to manage sales and purchase items.
- Implemented a new HTML template for the Varekøb & Salg module, including summary cards and tables for sales and purchases.
- Added JavaScript functions for loading and rendering order data dynamically.
- Introduced a new backend search module for customers, contacts, hardware, and locations with autocomplete functionality.
- Developed an email templates API for managing system and customer-specific email templates.
- Created multiple migrations for Nextcloud instances, cache, audit logs, email templates, sag comments, hardware locations, and billing methods.
- Enhanced the sag module with solutions, order lines, work types, and 2FA support for user authentication.
2026-02-02 20:23:56 +01:00
headers: { 'Content-Type': 'application/json' },
2026-01-31 23:16:24 +01:00
body: JSON.stringify(data)
});
if (response.ok) {
const result = await response.json();
2026-09-08 01:55:47 +02:00
window.caseCreateUI?.created(result);
2026-01-31 23:16:24 +01:00
feat(sag): Add Varekøb & Salg module with database migration and frontend template
- Created a new SQL migration for the sag_salgsvarer table to manage sales and purchase items.
- Implemented a new HTML template for the Varekøb & Salg module, including summary cards and tables for sales and purchases.
- Added JavaScript functions for loading and rendering order data dynamically.
- Introduced a new backend search module for customers, contacts, hardware, and locations with autocomplete functionality.
- Developed an email templates API for managing system and customer-specific email templates.
- Created multiple migrations for Nextcloud instances, cache, audit logs, email templates, sag comments, hardware locations, and billing methods.
- Enhanced the sag module with solutions, order lines, work types, and 2FA support for user authentication.
2026-02-02 20:23:56 +01:00
successDiv.classList.remove('d-none');
2026-08-30 14:34:43 +02:00
document.getElementById('success-text').textContent = "Sag oprettet";
window.location.href = `/sag/${result.id}/v3`;
2026-01-31 23:16:24 +01:00
} else {
const errorText = await response.text();
feat(sag): Add Varekøb & Salg module with database migration and frontend template
- Created a new SQL migration for the sag_salgsvarer table to manage sales and purchase items.
- Implemented a new HTML template for the Varekøb & Salg module, including summary cards and tables for sales and purchases.
- Added JavaScript functions for loading and rendering order data dynamically.
- Introduced a new backend search module for customers, contacts, hardware, and locations with autocomplete functionality.
- Developed an email templates API for managing system and customer-specific email templates.
- Created multiple migrations for Nextcloud instances, cache, audit logs, email templates, sag comments, hardware locations, and billing methods.
- Enhanced the sag module with solutions, order lines, work types, and 2FA support for user authentication.
2026-02-02 20:23:56 +01:00
let errMsg = "Kunne ikke oprette sag";
2026-01-31 23:16:24 +01:00
try {
feat(sag): Add Varekøb & Salg module with database migration and frontend template
- Created a new SQL migration for the sag_salgsvarer table to manage sales and purchase items.
- Implemented a new HTML template for the Varekøb & Salg module, including summary cards and tables for sales and purchases.
- Added JavaScript functions for loading and rendering order data dynamically.
- Introduced a new backend search module for customers, contacts, hardware, and locations with autocomplete functionality.
- Developed an email templates API for managing system and customer-specific email templates.
- Created multiple migrations for Nextcloud instances, cache, audit logs, email templates, sag comments, hardware locations, and billing methods.
- Enhanced the sag module with solutions, order lines, work types, and 2FA support for user authentication.
2026-02-02 20:23:56 +01:00
const json = JSON.parse(errorText);
errMsg = json.detail || errMsg;
} catch(e) {}
throw new Error(errMsg);
2026-01-31 23:16:24 +01:00
}
} catch (err) {
feat(sag): Add Varekøb & Salg module with database migration and frontend template
- Created a new SQL migration for the sag_salgsvarer table to manage sales and purchase items.
- Implemented a new HTML template for the Varekøb & Salg module, including summary cards and tables for sales and purchases.
- Added JavaScript functions for loading and rendering order data dynamically.
- Introduced a new backend search module for customers, contacts, hardware, and locations with autocomplete functionality.
- Developed an email templates API for managing system and customer-specific email templates.
- Created multiple migrations for Nextcloud instances, cache, audit logs, email templates, sag comments, hardware locations, and billing methods.
- Enhanced the sag module with solutions, order lines, work types, and 2FA support for user authentication.
2026-02-02 20:23:56 +01:00
console.error('Submit error:', err);
errorDiv.classList.remove('d-none');
document.getElementById('error-text').textContent = err.message;
btn.disabled = false;
btn.innerHTML = originalBtnText;
2026-01-31 23:16:24 +01:00
}
});
< / script >
2026-09-08 01:55:47 +02:00
< script src = "/static/js/case-create.js?v=5" > < / script >
2026-01-31 23:16:24 +01:00
{% endblock %}