From 1acab8c04988e6dfb30263a549de26ce0c86ba6f Mon Sep 17 00:00:00 2001 From: "Janus C. H. Knudsen" Date: Mon, 29 Dec 2025 15:02:10 +0100 Subject: [PATCH] Adds proof-of-concept cash reconciliation HTML page Creates a detailed HTML prototype for cash reconciliation process Includes comprehensive UI components for tracking daily cash operations Implements interactive calculations and user input validation for cash counting --- wwwroot/poc-kasseafstemning.html | 1301 ++++++++++++++++-------------- 1 file changed, 681 insertions(+), 620 deletions(-) diff --git a/wwwroot/poc-kasseafstemning.html b/wwwroot/poc-kasseafstemning.html index 11b4985..9f470dc 100644 --- a/wwwroot/poc-kasseafstemning.html +++ b/wwwroot/poc-kasseafstemning.html @@ -50,11 +50,11 @@ --color-text: #333; --color-text-secondary: #666; --color-teal: #00897b; - --color-purple: #8b5cf6; - --color-amber: #f59e0b; + --color-blue: #1976d2; --color-red: #e53935; + --color-amber: #f59e0b; + --color-purple: #8b5cf6; --color-green: #43a047; - --color-blue: #3b82f6; --font-family: 'Poppins', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; --font-mono: 'JetBrains Mono', monospace; } @@ -76,6 +76,53 @@ line-height: 1.5; } + /* ========================================== + TOPBAR + ========================================== */ + swp-topbar { + display: flex; + align-items: center; + justify-content: space-between; + padding: 12px 24px; + background: var(--color-surface); + border-bottom: 1px solid var(--color-border); + position: sticky; + top: 0; + z-index: 100; + } + + swp-topbar-left { + display: flex; + align-items: center; + gap: 16px; + } + + swp-back-link { + display: flex; + align-items: center; + gap: 6px; + color: var(--color-text-secondary); + text-decoration: none; + font-size: 13px; + cursor: pointer; + transition: color 150ms ease; + } + + swp-back-link:hover { + color: var(--color-teal); + } + + swp-page-title { + font-size: 16px; + font-weight: 600; + } + + swp-topbar-right { + display: flex; + align-items: center; + gap: 12px; + } + /* ========================================== LAYOUT ========================================== */ @@ -86,88 +133,46 @@ padding: 24px; } + .grid-2 { + display: grid; + grid-template-columns: 1fr 1fr; + gap: 24px; + } + + @media (max-width: 900px) { + .grid-2 { grid-template-columns: 1fr; } + } + /* ========================================== - HEADER + PAGE HEADER ========================================== */ swp-page-header { - display: flex; - align-items: center; - justify-content: space-between; + display: block; margin-bottom: 24px; - flex-wrap: wrap; - gap: 16px; } - swp-header-left { - display: flex; - align-items: center; - gap: 16px; - } - - swp-page-title { + swp-page-header h1 { font-size: 24px; font-weight: 600; color: var(--color-text); + margin-bottom: 6px; } - swp-header-controls { - display: flex; - align-items: center; - gap: 16px; - } - - swp-employee-filter select, - swp-date-selector input[type="date"] { - padding: 10px 14px; + swp-page-subtitle { + display: block; font-size: 14px; - font-family: var(--font-family); - border: 1px solid var(--color-border); - border-radius: 6px; - background: var(--color-surface); - cursor: pointer; - } - - swp-employee-filter select { - padding-right: 32px; - background: var(--color-surface) url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='10' viewBox='0 0 24 24' fill='none' stroke='%23666' stroke-width='2'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E") no-repeat right 10px center; - appearance: none; - min-width: 180px; - } - - swp-date-selector { - display: flex; - align-items: center; - gap: 8px; - } - - swp-date-selector button { - width: 36px; - height: 36px; - display: flex; - align-items: center; - justify-content: center; - border: 1px solid var(--color-border); - border-radius: 6px; - background: var(--color-surface); - cursor: pointer; - font-size: 16px; color: var(--color-text-secondary); - transition: all 150ms ease; - } - - swp-date-selector button:hover { - background: var(--color-background-hover); - color: var(--color-text); } /* ========================================== - CARD STYLES + CARDS ========================================== */ swp-card { display: block; background: var(--color-surface); border-radius: 8px; box-shadow: 0 1px 3px rgba(0, 0, 0, 0.08); + margin-bottom: 20px; overflow: hidden; } @@ -185,358 +190,414 @@ color: var(--color-text); } + swp-card-hint { + font-size: 12px; + color: var(--color-text-secondary); + } + swp-card-body { display: block; - padding: 16px 20px; + padding: 20px; } /* ========================================== - TWO COLUMN LAYOUT + FORM ELEMENTS ========================================== */ - swp-content-grid { + swp-form-grid { display: grid; grid-template-columns: 1fr 1fr; - gap: 24px; - margin-bottom: 24px; + gap: 16px; + } + + swp-form-field { + display: block; + } + + swp-form-field.full-width { + grid-column: 1 / -1; + } + + swp-form-label { + display: block; + font-size: 12px; + font-weight: 500; + color: var(--color-text-secondary); + margin-bottom: 6px; + text-transform: uppercase; + letter-spacing: 0.3px; + } + + swp-form-label .required { + color: var(--color-red); + } + + swp-form-input input, + swp-form-input select { + width: 100%; + padding: 10px 12px; + font-size: 14px; + font-family: var(--font-family); + border: 1px solid var(--color-border); + border-radius: 6px; + background: var(--color-surface); + transition: border-color 150ms ease; + } + + swp-form-input input:focus, + swp-form-input select:focus { + outline: none; + border-color: var(--color-teal); + } + + swp-auto-id { + display: block; + font-size: 12px; + color: var(--color-text-secondary); + margin-top: 16px; + padding-top: 16px; + border-top: 1px solid var(--color-border); } /* ========================================== - SIMPLE TABLE (for payment methods & sales) + DATA TABLE ========================================== */ - swp-simple-table { + swp-data-table { display: block; width: 100%; } - swp-simple-row { - display: flex; - justify-content: space-between; - align-items: center; - padding: 12px 0; - border-bottom: 1px solid var(--color-border); + swp-data-header { + display: grid; + grid-template-columns: 1fr 100px 140px; + gap: 12px; + padding: 10px 0; + border-bottom: 2px solid var(--color-border); } - swp-simple-row:last-child { - border-bottom: none; - } - - swp-simple-row.total { + swp-data-header span { + font-size: 11px; font-weight: 600; - border-top: 2px solid var(--color-border); - border-bottom: none; - margin-top: 8px; - padding-top: 16px; - } - - swp-simple-row.subtotal { + text-transform: uppercase; + letter-spacing: 0.5px; color: var(--color-text-secondary); - font-size: 13px; - padding: 8px 0 8px 16px; + } + + swp-data-header span:not(:first-child) { + text-align: right; + } + + swp-data-row { + display: grid; + grid-template-columns: 1fr 100px 140px; + gap: 12px; + padding: 14px 0; + border-bottom: 1px solid var(--color-border); + align-items: center; + } + + swp-data-row:last-child { border-bottom: none; } - swp-row-label { - display: flex; - align-items: center; - gap: 10px; + swp-data-label { font-size: 14px; + color: var(--color-text); } - swp-row-icon { - width: 28px; - height: 28px; - display: flex; - align-items: center; - justify-content: center; - border-radius: 6px; - font-size: 14px; - } - - swp-row-icon.card { background: color-mix(in srgb, var(--color-blue) 15%, white); } - swp-row-icon.cash { background: color-mix(in srgb, var(--color-green) 15%, white); } - swp-row-icon.mobile { background: color-mix(in srgb, var(--color-purple) 15%, white); } - swp-row-icon.credit { background: color-mix(in srgb, var(--color-red) 15%, white); } - swp-row-icon.service { background: color-mix(in srgb, var(--color-teal) 15%, white); } - swp-row-icon.product { background: color-mix(in srgb, var(--color-amber) 15%, white); } - - swp-row-value { + swp-data-system { + text-align: right; font-family: var(--font-mono); font-size: 14px; - font-weight: 500; + color: var(--color-text-secondary); } - swp-row-value.negative { - color: var(--color-red); + swp-data-input input { + width: 100%; + padding: 8px 10px; + font-size: 14px; + font-family: var(--font-mono); + text-align: right; + border: 1px solid var(--color-border); + border-radius: 6px; + background: var(--color-surface); } - /* Card details toggle */ - swp-card-details { + swp-data-input input:focus { + outline: none; + border-color: var(--color-teal); + } + + swp-data-input input::placeholder { + color: #bbb; + font-family: var(--font-family); + font-size: 12px; + } + + swp-data-value { + text-align: right; + font-family: var(--font-mono); + font-size: 14px; + color: var(--color-text); + } + + swp-data-value.muted { + color: var(--color-text-secondary); + } + + swp-table-note { display: block; - padding: 12px 16px; - margin: 8px 0; + font-size: 12px; + color: var(--color-text-secondary); + margin-top: 16px; + padding: 12px; background: var(--color-background-alt); border-radius: 6px; } - swp-card-details-header { + /* ========================================== + CASH CALCULATION + ========================================== */ + swp-calc-row { display: flex; justify-content: space-between; align-items: center; - cursor: pointer; - font-size: 13px; - color: var(--color-text-secondary); - } - - swp-card-details-header:hover { - color: var(--color-text); - } - - swp-card-details-content { - margin-top: 12px; - padding-top: 12px; - border-top: 1px solid var(--color-border); - } - - swp-card-details-content.collapsed { - display: none; - } - - swp-detail-row { - display: flex; - justify-content: space-between; - padding: 6px 0; - font-size: 13px; - } - - swp-detail-row span:last-child { - font-family: var(--font-mono); - } - - /* ========================================== - CASH COUNT SECTION - ========================================== */ - swp-cash-section { - display: block; - background: var(--color-surface); - border-radius: 8px; - box-shadow: 0 1px 3px rgba(0, 0, 0, 0.08); - margin-bottom: 24px; - overflow: hidden; - } - - swp-cash-grid { - display: grid; - grid-template-columns: 200px 1fr 200px; - gap: 1px; - background: var(--color-border); - } - - swp-cash-panel { - background: var(--color-surface); - padding: 20px; - } - - swp-cash-panel-title { - display: block; - font-size: 12px; - font-weight: 600; - text-transform: uppercase; - letter-spacing: 0.5px; - color: var(--color-text-secondary); - margin-bottom: 16px; - } - - /* Primo panel */ - swp-primo-row { - display: flex; - justify-content: space-between; - padding: 10px 0; + padding: 14px 0; border-bottom: 1px solid var(--color-border); } - swp-primo-row:last-child { + swp-calc-row:last-of-type { border-bottom: none; - font-weight: 600; - padding-top: 16px; - margin-top: 8px; - border-top: 2px solid var(--color-border); } - swp-primo-row span:last-child { - font-family: var(--font-mono); + swp-calc-row.input-row { + padding: 18px 0; + background: var(--color-background-alt); + margin: 16px -20px -20px -20px; + padding: 20px; + border-radius: 0 0 8px 8px; } - /* Denomination grid */ - swp-denomination-container { + swp-calc-label span { display: block; + font-size: 14px; + color: var(--color-text); } - swp-denomination-group { + swp-calc-label small { display: block; - margin-bottom: 16px; - } - - swp-denomination-group:last-child { - margin-bottom: 0; - } - - swp-denomination-label { - display: block; - font-size: 11px; - font-weight: 600; - text-transform: uppercase; - letter-spacing: 0.5px; + font-size: 12px; color: var(--color-text-secondary); - margin-bottom: 8px; + margin-top: 2px; } - swp-denomination-grid { - display: flex; - gap: 8px; - flex-wrap: wrap; - } - - swp-denomination-item { - display: flex; - flex-direction: column; - align-items: center; - gap: 4px; - min-width: 70px; - } - - swp-denomination-item label { - font-size: 11px; - color: var(--color-text-secondary); + swp-calc-value { font-family: var(--font-mono); + font-size: 14px; + color: var(--color-text); } - swp-denomination-item input { - width: 60px; - padding: 8px; - text-align: center; + swp-calc-value.muted { + color: var(--color-text-secondary); + } + + swp-calc-input input { + width: 140px; + padding: 12px 14px; font-size: 16px; - font-weight: 600; font-family: var(--font-mono); + text-align: right; border: 2px solid var(--color-border); border-radius: 6px; background: var(--color-surface); } - swp-denomination-item input:focus { - outline: none; - border-color: var(--color-teal); - } - - swp-denomination-item input::-webkit-inner-spin-button, - swp-denomination-item input::-webkit-outer-spin-button { - -webkit-appearance: none; - margin: 0; - } - - /* Result panel */ - swp-result-row { - display: flex; - justify-content: space-between; - padding: 10px 0; - border-bottom: 1px solid var(--color-border); - } - - swp-result-row:last-child { - border-bottom: none; - } - - swp-result-row.highlight { - font-weight: 600; - padding: 16px 0; - margin-top: 8px; - border-top: 2px solid var(--color-border); - border-bottom: none; - } - - swp-result-row.difference { - font-size: 16px; - } - - swp-result-row.difference.positive span:last-child { - color: var(--color-green); - } - - swp-result-row.difference.negative span:last-child { - color: var(--color-red); - } - - swp-result-row span:last-child { - font-family: var(--font-mono); - } - - swp-result-row input { - width: 100px; - padding: 8px; - text-align: right; - font-size: 14px; - font-family: var(--font-mono); - border: 1px solid var(--color-border); - border-radius: 4px; - } - - swp-result-row input:focus { + swp-calc-input input:focus { outline: none; border-color: var(--color-teal); } /* ========================================== - FOOTER + DIFFERENCE BOX ========================================== */ - swp-page-footer { + swp-difference-box { display: flex; align-items: center; justify-content: space-between; - padding: 20px 24px; - background: var(--color-surface); + padding: 20px; border-radius: 8px; - box-shadow: 0 1px 3px rgba(0, 0, 0, 0.08); - margin-top: 24px; + background: var(--color-background-alt); + margin-top: 16px; } - swp-footer-left { - display: flex; - flex-direction: column; - gap: 4px; + swp-difference-box.positive { + background: color-mix(in srgb, var(--color-green) 10%, white); } - swp-shop-name { - font-size: 16px; + swp-difference-box.negative { + background: color-mix(in srgb, var(--color-red) 10%, white); + } + + swp-difference-box.neutral { + background: color-mix(in srgb, var(--color-teal) 10%, white); + } + + swp-difference-label { + font-size: 14px; + font-weight: 500; + color: var(--color-text); + } + + swp-difference-label small { + display: block; + font-size: 12px; + font-weight: 400; + color: var(--color-text-secondary); + margin-top: 4px; + } + + swp-difference-value { + font-size: 24px; font-weight: 600; + font-family: var(--font-mono); } - swp-reconciled-by { + swp-difference-box.positive swp-difference-value { + color: var(--color-green); + } + + swp-difference-box.negative swp-difference-value { + color: var(--color-red); + } + + swp-difference-box.neutral swp-difference-value { + color: var(--color-teal); + } + + /* ========================================== + NOTE FIELD + ========================================== */ + swp-note-field textarea { + width: 100%; + min-height: 80px; + padding: 12px; + font-size: 14px; + font-family: var(--font-family); + border: 1px solid var(--color-border); + border-radius: 6px; + resize: vertical; + } + + swp-note-field textarea:focus { + outline: none; + border-color: var(--color-teal); + } + + swp-note-hint { + display: block; + font-size: 12px; + color: var(--color-text-secondary); + margin-top: 8px; + } + + /* ========================================== + STATUS & APPROVAL + ========================================== */ + swp-status-row { display: flex; align-items: center; - gap: 8px; + gap: 12px; + margin-bottom: 20px; + } + + swp-status-label { font-size: 13px; color: var(--color-text-secondary); } - swp-reconciled-by select { - padding: 6px 10px; - font-size: 13px; - font-family: var(--font-family); - border: 1px solid var(--color-border); - border-radius: 4px; - background: var(--color-surface); + swp-status-badge { + display: inline-flex; + align-items: center; + gap: 6px; + padding: 6px 12px; + font-size: 12px; + font-weight: 500; + border-radius: 20px; } - swp-footer-actions { + swp-status-badge.draft { + background: color-mix(in srgb, var(--color-amber) 15%, white); + color: #b45309; + } + + swp-status-badge.approved { + background: color-mix(in srgb, var(--color-green) 15%, white); + color: var(--color-green); + } + + swp-status-badge::before { + content: ''; + width: 8px; + height: 8px; + border-radius: 50%; + background: currentColor; + } + + swp-approval-grid { + display: grid; + grid-template-columns: 1fr 1fr; + gap: 16px; + margin-bottom: 20px; + } + + swp-checkbox-field { display: flex; + align-items: flex-start; gap: 12px; + padding: 16px; + background: var(--color-background-alt); + border-radius: 8px; + margin-bottom: 20px; + grid-column: 1 / -1; + } + + swp-checkbox-field input[type="checkbox"] { + width: 18px; + height: 18px; + margin-top: 2px; + accent-color: var(--color-teal); + cursor: pointer; + } + + swp-checkbox-field label { + font-size: 13px; + color: var(--color-text); + cursor: pointer; + line-height: 1.5; + } + + /* ========================================== + ACTIONS + ========================================== */ + swp-card-footer { + display: flex; + justify-content: space-between; + align-items: center; + padding: 16px 20px; + background: var(--color-background-alt); + border-top: 1px solid var(--color-border); + } + + swp-actions-right { + display: flex; + gap: 10px; } swp-btn { display: inline-flex; align-items: center; - gap: 8px; - padding: 12px 24px; - font-size: 14px; + gap: 6px; + padding: 10px 18px; + font-size: 13px; font-weight: 500; font-family: var(--font-family); border-radius: 6px; @@ -544,6 +605,16 @@ transition: all 150ms ease; } + swp-btn.ghost { + background: transparent; + border: none; + color: var(--color-text-secondary); + } + + swp-btn.ghost:hover { + color: var(--color-text); + } + swp-btn.secondary { background: var(--color-surface); border: 1px solid var(--color-border); @@ -561,355 +632,345 @@ } swp-btn.primary:hover { - background: color-mix(in srgb, var(--color-teal) 90%, black); + background: #00796b; + } + + swp-btn.primary:disabled { + background: #ccc; + border-color: #ccc; + cursor: not-allowed; + } + + swp-system-note { + display: block; + font-size: 11px; + color: var(--color-text-secondary); + text-align: center; + padding: 12px; } + + + + + + Tilbage + + Kasseafstemning + + + Kladde + + + - + - - Kasseafstemning - - - - - - - - - - - +

Kasseafstemning

+ Enkel dagsafslutning med fokus på kontanter. Kort afstemmes separat mod bank/indløser.
- - - - - - Betalingsmetoder - - - - - - 💳 - Betalingskort - - 6.401 kr - +
+ +
+ + + + Dagens tal + Systemtal vs. kontrol + + + + + Type + System + Kontrol + - - - - Vis kortdetaljer - - - - + + Kortbetalinger + 12.875,50 + + + + - - - 💵 - Kontant - - 0 kr - + + MobilePay / Online + 2.450,00 + + + + - - - 📱 - MobilePay - - 475 kr - + + Kontantsalg + 3.540,00 + .. + + - - - ↩️ - Krediteringer - - 0 kr - + Kort og MobilePay afstemmes mod bank/indløser. Kontanter tælles op nedenfor. + + - - - TOTAL - - 6.876 kr - - - - + + + + Kontanter i kassen + + + + + Startbeholdning + Overført fra sidste afstemning + + 2.000,00 + - - - - Salgsfordeling - - - - - - ✂️ - Service salg - - 5.145 kr - + + + Udbetalinger / Bilag + Sammentæl bilag betalt kontant + + + + + - - - 🧴 - Produkt salg - - 1.731 kr - + + + Udtaget til bank + Kontanter lagt til side + + + + + - - - 🎁 - Gavekort salg - - 0 kr - + + + Forventet kontantbeholdning + + 5.220,00 + - - - 🎟️ - Klippekort salg - - 0 kr - + + + Optalt kontantbeholdning * + Hvad ligger der faktisk i kassen? + + + + + + + - - - OMSÆTNING - - 6.876 kr - - - - - + + + + Kontant difference + Optalt minus forventet + + – kr + +
- - - - Kontantoptælling - - - - - Kassebeholdning - - Primo (start) - 230 kr - - - Kontant ind - 0 kr - - - Forventet - 230 kr - - + +
+ + + + Dagsoplysninger + Identificér afstemningen + + + + + Dato * + + + + - - - Optælling - - - Sedler - - - - - - - - - - - - - - - - - - - + + Medarbejder * + + + + - - Mønter - - - - - - - - - - - - - - - - - - - - - - - - - + + Kassepunkt * + + + + - - - Resultat - - Optalt - 230 kr - - - DIFFERENCE - 0 kr - - - Til bank - - - - Rest til næste dag - 230 kr - - - - + + Skift (valgfrit) + + + + + - - - - KARINA KNUDSEN® - - Hvem afstemmer? - - - - - Gem kladde - Godkend afstemning - - + Afstemnings-ID: KA-2025-12-29-01 · oprettet automatisk + + + + + + + Note til difference + Valgfrit + + + + + + Kan gøres obligatorisk ved difference over 100 kr. + + + + + + + Afslut dagen + + + + + Status + + Kladde + + + + + Godkendt af (valgfrit) + + + + + + + + + + + + + Gem som kladde + + Fortryd + Godkend & lås + + + +
+
+ + Systemet gemmer hvornår og af hvem der er godkendt – enkelt kontrolspor.