Files
boc/quixzoom-landing-fixed/dac7-reporting.html
T
Bernt 6989a98d75 feat: Passwordless cross-device authentication
- Arkitektur: docs/auth/passwordless-architecture.md
- Backend: iom/quixzoom-auth-service/ (FastAPI + Redis)
- Webb: quixzoom-market-pages/se/login/ (QR-kod + polling)
- App: iom/quixzoom-app/src/features/auth/ (push + deep links)

Flöde: QR-kod → app-godkännande → webb-inloggad
2026-07-07 07:11:50 +00:00

827 lines
26 KiB
HTML

<!DOCTYPE html>
<html lang="sv" data-theme="light">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover">
<meta name="apple-native-compliance" content="full">
<meta name="module" content="dac7-reporting">
<title>DAC7 Rapportering · quiXzoom</title>
<link rel="stylesheet" >
<link rel="stylesheet" >
<script defer></script>
<style>
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
:root {
--ios-blue: #007AFF;
--ios-green: #34C759;
--ios-red: #FF3B30;
--ios-orange: #FF9500;
--ios-yellow: #FFCC00;
--ios-purple: #AF52DE;
--ios-gray: #8E8E93;
--ios-gray2: #AEAEB2;
--ios-gray3: #C7C7CC;
--ios-gray4: #D1D1D6;
--ios-gray5: #E5E5EA;
--ios-gray6: #F2F2F7;
--label-primary: rgba(0,0,0,1);
--label-secondary: rgba(60,60,67,.6);
--label-tertiary: rgba(60,60,67,.3);
--background-primary: #FFFFFF;
--background-secondary: #F2F2F7;
--grouped-bg: #F2F2F7;
--grouped-bg2: #FFFFFF;
--separator: rgba(60,60,67,.29);
--tint: var(--ios-blue);
--glass-bg: rgba(255,255,255,.72);
--glass-blur: blur(40px) saturate(180%);
--safe-top: env(safe-area-inset-top, 0px);
--safe-bottom: env(safe-area-inset-bottom, 0px);
}
body {
font-family: -apple-system, "SF Pro Text", "Helvetica Neue", sans-serif;
background: var(--grouped-bg);
color: var(--label-primary);
min-height: 100vh;
-webkit-font-smoothing: antialiased;
padding-top: calc(var(--safe-top) + 52px);
padding-bottom: calc(var(--safe-bottom) + 20px);
}
/* Navigation Bar */
.navbar {
position: fixed;
top: 0; left: 0; right: 0;
height: calc(var(--safe-top) + 52px);
padding-top: var(--safe-top);
background: var(--glass-bg);
backdrop-filter: var(--glass-blur);
-webkit-backdrop-filter: var(--glass-blur);
border-bottom: 0.5px solid var(--separator);
display: flex;
align-items: flex-end;
padding-bottom: 8px;
padding-left: 16px;
padding-right: 16px;
z-index: 1000;
gap: 12px;
}
.navbar-icon {
width: 30px; height: 30px;
background: linear-gradient(135deg, #007AFF, #5856D6);
border-radius: var(--radius-md);
display: flex; align-items: center; justify-content: center;
font-size: 16px;
flex-shrink: 0;
}
.navbar-title {
font-size: 17px;
font-weight: 600;
letter-spacing: -0.41px;
color: var(--label-primary);
flex: 1;
}
.navbar-badge {
font-size: 11px;
font-weight: 600;
color: var(--ios-blue);
background: rgba(0,122,255,.1);
padding: 3px 8px;
border-radius: var(--radius-xl);
}
/* Content */
.content { padding: 0 16px; }
/* Alert Banner */
.deadline-alert {
margin: 20px 0 0;
background: linear-gradient(135deg, rgba(255,59,48,.08), rgba(255,149,0,.08));
border: 1px solid rgba(255,59,48,.2);
border-radius: var(--radius-lg);
padding: 16px;
display: flex;
align-items: flex-start;
gap: 12px;
}
.alert-icon {
width: 36px; height: 36px;
background: rgba(255,59,48,.12);
border-radius: var(--radius-md);
display: flex; align-items: center; justify-content: center;
font-size: 18px;
flex-shrink: 0;
}
.alert-body { flex: 1; }
.alert-title {
font-size: 15px;
font-weight: 600;
color: var(--ios-red);
letter-spacing: -0.23px;
margin-bottom: 3px;
}
.alert-desc {
font-size: 13px;
color: var(--label-secondary);
line-height: 1.4;
}
.days-left {
font-size: 22px;
font-weight: 700;
color: var(--ios-red);
text-align: center;
}
.days-label {
font-size: 10px;
font-weight: 500;
color: var(--label-tertiary);
text-align: center;
text-transform: uppercase;
letter-spacing: 0.5px;
}
/* Section Header */
.section-header {
font-size: 13px;
font-weight: 600;
color: var(--label-secondary);
text-transform: uppercase;
letter-spacing: 0.5px;
padding: 24px 4px 8px;
}
/* Cards */
.card {
background: var(--grouped-bg2);
border-radius: var(--radius-lg);
overflow: hidden;
margin-bottom: 12px;
}
.card-header {
padding: 14px 16px 0;
}
.card-title {
font-size: 15px;
font-weight: 600;
letter-spacing: -0.23px;
margin-bottom: 2px;
}
.card-subtitle {
font-size: 13px;
color: var(--label-secondary);
line-height: 1.4;
}
/* Info Row */
.info-row {
display: flex;
align-items: center;
padding: 12px 16px;
border-bottom: 0.5px solid var(--separator);
gap: 12px;
}
.info-row:last-child { border-bottom: none; }
.info-icon {
width: 32px; height: 32px;
border-radius: var(--radius-md);
display: flex; align-items: center; justify-content: center;
font-size: 15px;
flex-shrink: 0;
}
.info-content { flex: 1; min-width: 0; }
.info-label { font-size: 15px; letter-spacing: -0.23px; }
.info-value {
font-size: 13px;
color: var(--label-secondary);
margin-top: 1px;
}
.info-right {
font-size: 15px;
font-weight: 600;
color: var(--label-primary);
text-align: right;
}
/* Stats Row */
.stats-grid {
display: grid;
grid-template-columns: 1fr 1fr 1fr;
gap: 1px;
background: var(--separator);
border-radius: 0 0 16px 16px;
overflow: hidden;
}
.stat-cell {
background: var(--grouped-bg2);
padding: 14px 12px;
text-align: center;
}
.stat-value {
font-size: 20px;
font-weight: 700;
letter-spacing: -0.5px;
color: var(--label-primary);
}
.stat-label {
font-size: 11px;
color: var(--label-tertiary);
margin-top: 2px;
text-transform: uppercase;
letter-spacing: 0.3px;
}
/* Zoomer Table */
.zoomer-row {
display: flex;
align-items: center;
padding: 14px 16px;
border-bottom: 0.5px solid var(--separator);
gap: 12px;
cursor: pointer;
transition: background 0.15s;
}
.zoomer-row:last-child { border-bottom: none; }
.zoomer-row:active { background: var(--ios-gray6); }
.zoomer-avatar {
width: 40px; height: 40px;
border-radius: var(--radius-full);
display: flex; align-items: center; justify-content: center;
font-size: 16px;
font-weight: 700;
color: white;
flex-shrink: 0;
}
.zoomer-info { flex: 1; min-width: 0; }
.zoomer-name { font-size: 15px; letter-spacing: -0.23px; font-weight: 500; }
.zoomer-tin {
font-size: 12px;
color: var(--label-tertiary);
font-family: "SF Mono", Menlo, monospace;
margin-top: 2px;
}
.zoomer-right { text-align: right; }
.zoomer-amount {
font-size: 15px;
font-weight: 600;
letter-spacing: -0.23px;
color: var(--label-primary);
}
.status-badge {
display: inline-flex;
align-items: center;
gap: 4px;
font-size: 11px;
font-weight: 600;
padding: 3px 8px;
border-radius: var(--radius-xl);
margin-top: 4px;
}
.status-verified {
background: rgba(52,199,89,.12);
color: var(--ios-green);
}
.status-missing {
background: rgba(255,59,48,.1);
color: var(--ios-red);
}
.status-pending {
background: rgba(255,149,0,.12);
color: var(--ios-orange);
}
/* Info Section */
.info-card {
background: var(--grouped-bg2);
border-radius: var(--radius-lg);
padding: 16px;
margin-bottom: 12px;
}
.info-card-title {
font-size: 15px;
font-weight: 600;
letter-spacing: -0.23px;
margin-bottom: 10px;
display: flex;
align-items: center;
gap: 8px;
}
.info-card-text {
font-size: 14px;
color: var(--label-secondary);
line-height: 1.55;
}
.info-card-text strong {
color: var(--label-primary);
font-weight: 600;
}
/* Export Button */
.export-section {
margin: 8px 0 24px;
}
.btn-primary {
display: flex;
align-items: center;
justify-content: center;
gap: 8px;
width: 100%;
padding: 16px;
background: var(--ios-blue);
color: white;
border: none;
border-radius: var(--radius-lg);
font-size: 17px;
font-weight: 600;
letter-spacing: -0.41px;
cursor: pointer;
transition: opacity 0.15s;
-webkit-tap-highlight-color: transparent;
}
.btn-primary:active { opacity: 0.8; }
.btn-secondary {
display: flex;
align-items: center;
justify-content: center;
gap: 8px;
width: 100%;
padding: 14px;
background: var(--ios-gray6);
color: var(--ios-blue);
border: none;
border-radius: var(--radius-lg);
font-size: 15px;
font-weight: 600;
letter-spacing: -0.23px;
cursor: pointer;
margin-top: 10px;
transition: opacity 0.15s;
}
.btn-secondary:active { opacity: 0.7; }
/* Period Card */
.period-row {
display: flex;
align-items: center;
justify-content: space-between;
padding: 14px 16px;
border-bottom: 0.5px solid var(--separator);
}
.period-row:last-child { border-bottom: none; }
.period-label { font-size: 15px; letter-spacing: -0.23px; }
.period-value { font-size: 15px; font-weight: 500; color: var(--label-secondary); }
/* Divider Text */
.divider-text {
text-align: center;
font-size: 12px;
color: var(--label-tertiary);
padding: 8px 0 16px;
line-height: 1.4;
}
/* Toast */
.toast {
position: fixed;
bottom: calc(var(--safe-bottom) + 24px);
left: 50%; transform: translateX(-50%);
background: rgba(242,242,247,.85);
color: white;
font-size: 14px;
font-weight: 500;
padding: 12px 20px;
border-radius: 100px;
white-space: nowrap;
opacity: 0;
transition: opacity 0.25s;
pointer-events: none;
z-index: 9999;
display: flex;
align-items: center;
gap: 8px;
}
.toast.show { opacity: 1; }
/* Progress Bar */
.progress-track {
height: 4px;
background: var(--ios-gray5);
border-radius: var(--radius-sm);
margin: 12px 16px 14px;
overflow: hidden;
}
.progress-fill {
height: 100%;
border-radius: var(--radius-sm);
background: var(--ios-blue);
transition: width 0.5s ease;
}
@media (max-width: 640px) {
.hero h1 { font-size: 2rem !important; }
.hero p { font-size: 1rem !important; }
.card { padding: 1.5rem !important; }
.grid { grid-template-columns: 1fr !important; }
.btn { padding: 0.75rem 1.5rem !important; font-size: 1rem !important; }
}
</style>
<style id="wcag-contrast-enforcement">
/* AAMOS GLOBAL CONTRAST ENFORCEMENT — WCAG AA (4.5:1 minimum) */
/* Regel: Ingen text under 70% opacity. Aldrig. */
body { -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; }
/* Fix common low-contrast patterns */
[style*="rgba(60,60,67,0.4)"] { color: rgba(60,60,67,0.65) !important; }
[style*="rgba(60,60,67,0.3)"] { color: rgba(60,60,67,0.65) !important; }
[style*="rgba(255,255,255,0.4)"] { color: rgba(255,255,255,0.72) !important; }
[style*="rgba(255,255,255,0.3)"] { color: rgba(255,255,255,0.72) !important; }
[style*="opacity: 0.4"] { opacity: 0.72 !important; }
[style*="opacity: 0.3"] { opacity: 0.72 !important; }
@media (max-width: 640px) {
.hero h1 { font-size: 2rem !important; }
.hero p { font-size: 1rem !important; }
.card { padding: 1.5rem !important; }
.grid { grid-template-columns: 1fr !important; }
.btn { padding: 0.75rem 1.5rem !important; font-size: 1rem !important; }
}
</style>
</head>
<body>
<!-- Navigation Bar -->
<div class="navbar">
<div class="navbar-icon"></div>
<div class="navbar-title">DAC7 Rapportering</div>
<div class="navbar-badge">2026</div>
</div>
<div class="content">
<!-- Deadline Alert -->
<div class="deadline-alert">
<div class="alert-icon"></div>
<div class="alert-body">
<div class="alert-title">Deadline: 31 januari 2027</div>
<div class="alert-desc">DAC7-rapporten för kalenderår 2026 ska vara inlämnad till Skatteverket senast 31 jan 2027.</div>
</div>
<div>
<div class="days-left" id="daysLeft"></div>
<div class="days-label">dagar kvar</div>
</div>
</div>
<!-- What is DAC7 -->
<div class="section-header">Om DAC7</div>
<div class="info-card">
<div class="info-card-title"><svg width="16" height="16" viewBox="0 0 16 16" fill="none"><rect x="3" y="2" width="10" height="12" rx="1" stroke="#666" stroke-width="1.5"/><path d="M6 5H10M6 8H10M6 11H8" stroke="#666" stroke-width="1.5" stroke-linecap="round"/></svg> Vad är DAC7?</div>
<div class="info-card-text">
<strong>EU-direktiv 2021/514 (DAC7)</strong> kräver att digitala plattformar rapporterar säljares (zoomers) intäkter till skattemyndigheterna. quiXzoom är en <strong>rapporteringsskyldig plattformsoperatör</strong> och måste varje år lämna uppgifter om zoomers som:
<br><br>
• Genomfört <strong>≥ 30 transaktioner</strong> under kalenderåret, <em>eller</em><br>
• Tjänat in <strong>≥ 2 000 EUR</strong> under kalenderåret
<br><br>
Rapporteringen sker i <strong>XML-format</strong> enligt Skatteverkets tekniska specifikation. Första rapportering avser kalenderår 2023.
</div>
</div>
<div class="info-card">
<div class="info-card-title"> Vår skyldighet</div>
<div class="info-card-text">
quiXzoom samlar in <strong>TIN (skatteregistreringsnummer)</strong> och personuppgifter från alla aktiva zoomers. Vi verifierar uppgifterna och rapporterar automatiskt till Skatteverket via deras API-integration. Zoomers informeras om rapporteringen i tjänstevillkoren.
</div>
</div>
<!-- Period -->
<div class="section-header">Rapporteringsperiod</div>
<div class="card">
<div class="period-row">
<span class="period-label">Rapporteringsår</span>
<span class="period-value">Kalenderår 2026</span>
</div>
<div class="period-row">
<span class="period-label">Period</span>
<span class="period-value">2026-01-01 — 2026-12-31</span>
</div>
<div class="period-row">
<span class="period-label">Inlämningsfrist</span>
<span class="period-value" style="color: var(--ios-red); font-weight: 600;">31 januari 2027</span>
</div>
<div class="period-row">
<span class="period-label">Rapporteringsformat</span>
<span class="period-value">XML (DAC7 schema)</span>
</div>
<div class="period-row">
<span class="period-label">Mottagare</span>
<span class="period-value">Skatteverket</span>
</div>
<div class="period-row">
<span class="period-label">Status</span>
<span class="period-value" style="color: var(--ios-orange);">⏳ Pågående insamling</span>
</div>
</div>
<!-- Summary Stats -->
<div class="section-header">Sammanfattning</div>
<div class="card">
<div style="padding: 14px 16px 0; border-bottom: 0.5px solid var(--separator);">
<div style="font-size: 13px; color: var(--label-secondary); margin-bottom: 6px;">Total rapporterad intäkt 2026</div>
<div style="font-size: 28px; font-weight: 700; letter-spacing: -1px; color: var(--label-primary); margin-bottom: 4px;">43 850 SEK</div>
<div style="font-size: 12px; color: var(--label-tertiary); padding-bottom: 12px;">Summa för 5 rapporterade zoomers</div>
<!-- Progress bar: TIN verified -->
<div style="font-size: 12px; color: var(--label-secondary); display: flex; justify-content: space-between; margin-bottom: 4px;">
<span>TIN-verifiering</span>
<span style="font-weight: 600; color: var(--ios-green);">3 av 5 klara</span>
</div>
<div class="progress-track">
<div class="progress-fill" style="width: 60%;"></div>
</div>
</div>
<div class="stats-grid">
<div class="stat-cell">
<div class="stat-value" style="color: var(--ios-green);">3</div>
<div class="stat-label">TIN verifierad</div>
</div>
<div class="stat-cell">
<div class="stat-value" style="color: var(--ios-red);">1</div>
<div class="stat-label">TIN saknas</div>
</div>
<div class="stat-cell">
<div class="stat-value" style="color: var(--ios-orange);">1</div>
<div class="stat-label">Under utredning</div>
</div>
</div>
</div>
<!-- Zoomer List -->
<div class="section-header">Rapporterade zoomers (5)</div>
<div class="card">
<!-- Zoomer 1 - verified -->
<div class="zoomer-row" onclick="showZoomerDetail('Alicia Bergström', '198804127654', '12600', 'verified')">
<div class="zoomer-avatar" style="background: linear-gradient(135deg, #007AFF, #5856D6);">A</div>
<div class="zoomer-info">
<div class="zoomer-name">Alicia Bergström</div>
<div class="zoomer-tin">TIN: 8804127654</div>
<span class="status-badge status-verified"><svg width="16" height="16" viewBox="0 0 16 16" fill="none"><path d="M3 8L6.5 11.5L13 4.5" stroke="#22c55e" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg> TIN verifierad</span>
</div>
<div class="zoomer-right">
<div class="zoomer-amount">12 600 SEK</div>
<div style="font-size: 11px; color: var(--label-tertiary); margin-top: 2px;">47 transaktioner</div>
</div>
</div>
<!-- Zoomer 2 - verified -->
<div class="zoomer-row" onclick="showZoomerDetail('Mikael Thorsson', '199103284512', '9750', 'verified')">
<div class="zoomer-avatar" style="background: linear-gradient(135deg, #34C759, #30B0C7);">M</div>
<div class="zoomer-info">
<div class="zoomer-name">Mikael Thorsson</div>
<div class="zoomer-tin">TIN: 9103284512</div>
<span class="status-badge status-verified"><svg width="16" height="16" viewBox="0 0 16 16" fill="none"><path d="M3 8L6.5 11.5L13 4.5" stroke="#22c55e" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg> TIN verifierad</span>
</div>
<div class="zoomer-right">
<div class="zoomer-amount">9 750 SEK</div>
<div style="font-size: 11px; color: var(--label-tertiary); margin-top: 2px;">38 transaktioner</div>
</div>
</div>
<!-- Zoomer 3 - missing TIN -->
<div class="zoomer-row" onclick="showZoomerDetail('Fatima Okonkwo', 'SAKNAS', '7200', 'missing')">
<div class="zoomer-avatar" style="background: linear-gradient(135deg, #FF3B30, #FF9500);">F</div>
<div class="zoomer-info">
<div class="zoomer-name">Fatima Okonkwo</div>
<div class="zoomer-tin">TIN: EJ REGISTRERAT</div>
<span class="status-badge status-missing"><svg width="16" height="16" viewBox="0 0 16 16" fill="none"><path d="M4 4L12 12M12 4L4 12" stroke="#ef4444" stroke-width="2" stroke-linecap="round"/></svg> TIN saknas</span>
</div>
<div class="zoomer-right">
<div class="zoomer-amount">7 200 SEK</div>
<div style="font-size: 11px; color: var(--label-tertiary); margin-top: 2px;">31 transaktioner</div>
</div>
</div>
<!-- Zoomer 4 - pending -->
<div class="zoomer-row" onclick="showZoomerDetail('Johan Lindkvist', '197612053311', '11900', 'pending')">
<div class="zoomer-avatar" style="background: linear-gradient(135deg, #FF9500, #FFCC00);">J</div>
<div class="zoomer-info">
<div class="zoomer-name">Johan Lindkvist</div>
<div class="zoomer-tin">TIN: 7612053311</div>
<span class="status-badge status-pending">⏳ Under utredning</span>
</div>
<div class="zoomer-right">
<div class="zoomer-amount">11 900 SEK</div>
<div style="font-size: 11px; color: var(--label-tertiary); margin-top: 2px;">44 transaktioner</div>
</div>
</div>
<!-- Zoomer 5 - verified -->
<div class="zoomer-row" onclick="showZoomerDetail('Sofia Wennberg', '200002157890', '2400', 'verified')">
<div class="zoomer-avatar" style="background: linear-gradient(135deg, #AF52DE, #5856D6);">S</div>
<div class="zoomer-info">
<div class="zoomer-name">Sofia Wennberg</div>
<div class="zoomer-tin">TIN: 0002157890</div>
<span class="status-badge status-verified"><svg width="16" height="16" viewBox="0 0 16 16" fill="none"><path d="M3 8L6.5 11.5L13 4.5" stroke="#22c55e" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg> TIN verifierad</span>
</div>
<div class="zoomer-right">
<div class="zoomer-amount">2 400 SEK</div>
<div style="font-size: 11px; color: var(--label-tertiary); margin-top: 2px;">32 transaktioner</div>
</div>
</div>
</div>
<div class="divider-text">
Alla zoomers med ≥30 transaktioner eller ≥2 000 EUR intäkt under kalenderåret inkluderas i rapporten.
</div>
<!-- Export Section -->
<div class="section-header">Exportera rapport</div>
<div class="export-section">
<button class="btn-primary" onclick="exportXML()">
<span></span>
Exportera XML till Skatteverket
</button>
<button class="btn-secondary" onclick="downloadPreview()">
<span></span>
Förhandsgranska XML
</button>
</div>
<!-- Footer note -->
<div class="info-card" style="margin-bottom: 24px;">
<div class="info-card-title"><svg width="20" height="20" viewBox="0 0 20 20" fill="none"><path d="M10 3L17 17H3L10 3Z" stroke="#f59e0b" stroke-width="2"/><path d="M10 8V12M10 14V14.5" stroke="#f59e0b" stroke-width="2" stroke-linecap="round"/></svg> Viktigt att notera</div>
<div class="info-card-text">
Zoomers med <strong>saknat TIN</strong> måste kontaktas och komplettera sina uppgifter <strong>innan export</strong>. Rapporten kan inte inkludera saknade skattenummer.
<br><br>
Har du frågor om DAC7-rapportering? Kontakta <strong>legal@quixzoom.se</strong>
</div>
</div>
</div><!-- /content -->
<!-- Toast -->
<div class="toast" id="toast"></div>
<script>
// Days Until Deadline
(function() {
const deadline = new Date('2027-01-31T23:59:59');
const now = new Date();
const diff = Math.ceil((deadline - now) / (1000 * 60 * 60 * 24));
const el = document.getElementById('daysLeft');
if (el) el.textContent = diff > 0 ? diff : '0';
})();
// Toast Helper
function showToast(msg, duration = 2500) {
const t = document.getElementById('toast');
t.textContent = msg;
t.classList.add('show');
setTimeout(() => t.classList.remove('show'), duration);
}
// Zoomer Detail
function showZoomerDetail(name, tin, amount, status) {
const statusMap = {
verified: '<svg width="20" height="20" viewBox="0 0 20 20" fill="none"><circle cx="10" cy="10" r="9" stroke="#22c55e" stroke-width="2"/><path d="M6 10L9 13L14 7" stroke="#22c55e" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg> TIN verifierad',
missing: '<svg width="20" height="20" viewBox="0 0 20 20" fill="none"><circle cx="10" cy="10" r="9" stroke="#ef4444" stroke-width="2"/><path d="M7 7L13 13M13 7L7 13" stroke="#ef4444" stroke-width="2" stroke-linecap="round"/></svg> TIN saknas',
pending: '⏳ Under utredning'
};
showToast(`${name} · ${parseInt(amount).toLocaleString('sv-SE')} SEK · ${statusMap[status]}`);
}
// Export XML
function exportXML() {
const btn = document.querySelector('.btn-primary');
const orig = btn.innerHTML;
btn.innerHTML = '<span>⏳</span> Genererar XML...';
btn.style.opacity = '0.7';
setTimeout(() => {
const xml = generateDAC7XML();
const blob = new Blob([xml], { type: 'application/xml' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = `DAC7_quiXzoom_2026_${new Date().toISOString().slice(0,10)}.xml`;
a.click();
URL.revokeObjectURL(url);
btn.innerHTML = orig;
btn.style.opacity = '';
showToast('<svg width="20" height="20" viewBox="0 0 20 20" fill="none"><circle cx="10" cy="10" r="9" stroke="#22c55e" stroke-width="2"/><path d="M6 10L9 13L14 7" stroke="#22c55e" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg> XML-fil exporterad!', 3000);
}, 1200);
}
// Preview XML
function downloadPreview() {
showToast(' Öppnar förhandsgranskning...');
setTimeout(() => {
const xml = generateDAC7XML();
const win = window.open('', '_blank');
if (win) {
win.document.write('<pre style="font-family:monospace;font-size:12px;padding:20px;white-space:pre-wrap;">' + escapeHtml(xml) + '</pre>');
}
}, 500);
}
function escapeHtml(str) {
return str.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');
}
// DAC7 XML Generator
function generateDAC7XML() {
const now = new Date().toISOString();
const zoomers = [
{ name: 'Alicia Bergström', tin: '198804127654', amount: 12600, currency: 'SEK', transactions: 47, status: 'verified' },
{ name: 'Mikael Thorsson', tin: '199103284512', amount: 9750, currency: 'SEK', transactions: 38, status: 'verified' },
{ name: 'Sofia Wennberg', tin: '200002157890', amount: 2400, currency: 'SEK', transactions: 32, status: 'verified' },
// Excluded: Fatima (missing TIN), Johan (pending)
];
const sellerRows = zoomers.map(z => `
<Seller>
<SellerID IDType="TIN" issuedBy="SE">${z.tin}</SellerID>
<Name>${z.name}</Name>
<Address>
<CountryCode>SE</CountryCode>
</Address>
<ResCountryCode>SE</ResCountryCode>
<Consideration currCode="${z.currency}">${z.amount}.00</Consideration>
<Fees currCode="${z.currency}">0.00</Fees>
<Taxes currCode="${z.currency}">0.00</Taxes>
<NumberOfActivities>${z.transactions}</NumberOfActivities>
</Seller>`).join('');
return `<?xml version="1.0" encoding="UTF-8"?>
<!-- DAC7 Rapportering - EU-direktiv 2021/514 -->
<!-- Rapporteringsskyldig plattformsoperatör: quiXzoom AB -->
<!-- Genererad: ${now} -->
<DPI:FATCA_OECD version="2.0"
xmlns:DPI="urn:oecd:ties:dpi:v2"
xmlns:stf="urn:oecd:ties:stf:v4"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<DPI:MessageSpec>
<DPI:SendingEntityIN>5566778899</DPI:SendingEntityIN>
<DPI:TransmittingCountry>SE</DPI:TransmittingCountry>
<DPI:ReceivingCountry>SE</DPI:ReceivingCountry>
<DPI:MessageType>DPI</DPI:MessageType>
<DPI:MessageRefId>quixzoom-dac7-2026-${Date.now()}</DPI:MessageRefId>
<DPI:ReportingPeriod>2026-12-31</DPI:ReportingPeriod>
<DPI:Timestamp>${now}</DPI:Timestamp>
</DPI:MessageSpec>
<DPI:DPIBody>
<DPI:PlatformOperator>
<DPI:ResCountryCode>SE</DPI:ResCountryCode>
<DPI:TIN issuedBy="SE">5566778899</DPI:TIN>
<DPI:Name>quiXzoom AB</DPI:Name>
<DPI:PlatformBusinessName>quiXzoom</DPI:PlatformBusinessName>
<DPI:Address>
<DPI:CountryCode>SE</DPI:CountryCode>
</DPI:Address>
</DPI:PlatformOperator>
<DPI:OtherActivities>${sellerRows}
</DPI:OtherActivities>
</DPI:DPIBody>
</DPI:FATCA_OECD>`;
}
</script>
</body>
</html>