<?php
/**
* /api/quote_pdf.php?id=<quoteId>
* Levererar en utskriftsvänlig HTML-sida för offerten.
* Browser "Save as PDF" → färdig PDF.
*/
require_once __DIR__ . '/config.php';
$id = isset($_GET['id']) ? (int) $_GET['id'] : 0;
$inModal = !empty($_GET['modal']);
if (!$id) { http_response_code(400); echo 'id saknas'; exit; }
$db = getDB();
$stmt = $db->prepare('SELECT * FROM quotes WHERE id = ?');
$stmt->execute([$id]);
$q = $stmt->fetch();
if (!$q) { http_response_code(404); echo 'Offert ej hittad'; exit; }
$config = json_decode($q['config_data'] ?? '[]', true) ?: [];
$items = $config['items'] ?? [];
$images = json_decode($q['images'] ?? '[]', true) ?: [];
function esc($s){ return htmlspecialchars((string)$s, ENT_QUOTES, 'UTF-8'); }
function fmt($n){ return number_format((float)$n, 0, ',', ' '); }
// Summera totals + potentiella skatteavdrag per tax_type
$grandTotal = 0;
$breakdown = ['ROT' => 0.0, 'GT20' => 0.0, 'GT50' => 0.0];
$aggTaxType = 'NONE';
foreach ($items as $cat => $item) {
if ($cat === '_addonsState' || (strlen($cat) > 0 && $cat[0] === '_' && preg_match('/State$/', $cat))) continue;
$entries = isset($item['entries']) && is_array($item['entries']) ? $item['entries'] : [$item];
foreach ($entries as $e) {
$grandTotal += (float) ($e['subtotal'] ?? $e['total'] ?? 0);
$ded = (float) ($e['deduction_amount'] ?? 0);
$tt = (string) ($e['tax_type'] ?? 'NONE');
if ($ded > 0 && isset($breakdown[$tt])) $breakdown[$tt] += $ded;
if ($aggTaxType === 'NONE' && $tt !== 'NONE') $aggTaxType = $tt;
}
}
$potentialDed = $breakdown['ROT'] + $breakdown['GT20'] + $breakdown['GT50'];
// Hämta skatteinställningar från app_settings
$taxRow = $db->query("SELECT setting_key, setting_value FROM app_settings WHERE setting_key IN ('tax_rot_max_per_person','tax_rot_percent','tax_gt50_percent','tax_gt20_percent','tax_moms_percent')")->fetchAll();
$tax = ['rotMax'=>50000,'rot'=>30,'gt50'=>50,'gt20'=>20,'moms'=>25];
foreach ($taxRow as $r) {
$v = (float) $r['setting_value'];
if ($r['setting_key'] === 'tax_rot_max_per_person') $tax['rotMax'] = $v;
elseif ($r['setting_key'] === 'tax_rot_percent') $tax['rot'] = $v;
elseif ($r['setting_key'] === 'tax_gt50_percent') $tax['gt50'] = $v;
elseif ($r['setting_key'] === 'tax_gt20_percent') $tax['gt20'] = $v;
elseif ($r['setting_key'] === 'tax_moms_percent') $tax['moms'] = $v;
}
$owners = max(1, (int) ($q['owner_count'] ?? 1));
$maxPerPerson = ($aggTaxType === 'ROT') ? $tax['rotMax'] : 50000;
$ownerCap = $owners * $maxPerPerson;
$effectiveDed = min($potentialDed, $ownerCap);
$netTotal = $grandTotal - $effectiveDed;
$deductionLabel = '';
if ($aggTaxType === 'GT50') $deductionLabel = 'Grönt teknik-avdrag ('.$tax['gt50'].'%)';
elseif ($aggTaxType === 'GT20') $deductionLabel = 'Grönt teknik-avdrag ('.$tax['gt20'].'%)';
elseif ($aggTaxType === 'ROT') $deductionLabel = 'ROT-avdrag ('.$tax['rot'].'%)';
elseif ($effectiveDed > 0) $deductionLabel = 'Skattereduktion';
$catLabels = [
'solceller'=>'Solpaneler','batteri'=>'Batteri','laddbox'=>'Laddbox',
'taktvatt'=>'Taktvätt','varmepump'=>'Värmepump','tak'=>'Tak',
'fonster'=>'Fönster','isolering'=>'Isolering','_addons'=>'Övriga installationskostnader'
];
// Hämta företagsinfo från app_settings
$companyKeys = ['company_name','company_orgnr','company_address','company_phone','company_email','company_website','company_footer','company_logo'];
$placeholders = implode(',', array_fill(0, count($companyKeys), '?'));
$cstmt = $db->prepare("SELECT setting_key, setting_value FROM app_settings WHERE setting_key IN ($placeholders)");
$cstmt->execute($companyKeys);
$company = [];
while ($row = $cstmt->fetch()) { $company[$row['setting_key']] = $row['setting_value']; }
$cName = $company['company_name'] ?? 'Solar Energy Group';
$cOrgnr = $company['company_orgnr'] ?? '';
$cAddress = $company['company_address'] ?? '';
$cPhone = $company['company_phone'] ?? '';
$cEmail = $company['company_email'] ?? '';
$cWebsite = $company['company_website'] ?? '';
$cFooter = $company['company_footer'] ?? 'Offerten är giltig 30 dagar från datum ovan.';
$cLogo = $company['company_logo'] ?? '';
?><!DOCTYPE html>
<html lang="sv">
<head>
<meta charset="utf-8">
<title>Offert #<?= esc($q['id']) ?><?= $q['customer_name'] ? ' – '.esc($q['customer_name']) : '' ?></title>
<style>
@page { size: A4; margin: 20mm 15mm; }
*{ box-sizing:border-box; }
body{ font-family: -apple-system, Segoe UI, Roboto, Arial, sans-serif; color:#0f172a; margin:0; padding:24px; font-size:13px; line-height:1.5; }
.pdf-head{ display:flex; justify-content:space-between; align-items:flex-start; border-bottom:3px solid #024550; padding-bottom:14px; margin-bottom:20px; }
.pdf-head h1{ margin:0 0 4px; font-size:22px; color:#024550; }
.pdf-head .meta{ text-align:right; font-size:12px; color:#64748b; }
.pdf-customer{ display:grid; grid-template-columns:1fr 1fr; gap:6px 20px; padding:12px 16px; background:#f8fafc; border:1px solid #e5e7eb; border-radius:8px; margin-bottom:20px; font-size:12px; }
.pdf-customer .lbl{ color:#64748b; font-weight:700; text-transform:uppercase; letter-spacing:.4px; font-size:10px; }
.pdf-section{ margin-bottom:18px; }
.pdf-section h2{ font-size:13px; margin:0 0 8px; padding:6px 12px; background:#024550; color:#fff; text-transform:uppercase; letter-spacing:.5px; border-radius:6px; display:flex; justify-content:space-between; }
table.pdf-lines{ width:100%; border-collapse:collapse; }
table.pdf-lines td{ padding:8px 12px; border-bottom:1px solid #e5e7eb; vertical-align:top; font-size:12px; }
table.pdf-lines td:last-child{ text-align:right; white-space:nowrap; font-weight:700; color:#024550; }
.pdf-sub{ color:#64748b; font-size:11px; margin-top:2px; }
.pdf-totals{ margin-top:24px; margin-left:auto; width:320px; border:2px solid #024550; border-radius:10px; overflow:hidden; }
.pdf-totals-row{ display:flex; justify-content:space-between; padding:10px 14px; border-bottom:1px solid #e5e7eb; font-size:13px; }
.pdf-totals-row:last-child{ border-bottom:none; background:#024550; color:#fff; font-size:16px; font-weight:800; }
.pdf-images{ display:grid; grid-template-columns:repeat(3,1fr); gap:10px; margin-top:20px; }
.pdf-images img{ width:100%; height:120px; object-fit:cover; border-radius:6px; border:1px solid #e5e7eb; }
.pdf-footer{ margin-top:40px; padding-top:14px; border-top:1px solid #e5e7eb; text-align:center; font-size:11px; color:#64748b; line-height:1.6; }
.pdf-footer > div{ margin-bottom:4px; }
.pdf-print-btn{ position:fixed; top:20px; right:20px; padding:10px 18px; background:#024550; color:#fff; border:none; border-radius:8px; font-size:14px; font-weight:700; cursor:pointer; box-shadow:0 4px 12px rgba(0,0,0,.15); }
@media print { .pdf-print-btn{ display:none; } body{ padding:0; } }
</style>
</head>
<body>
<?php if (!$inModal): ?>
<button class="pdf-print-btn" onclick="window.print()">Skriv ut / Spara som PDF</button>
<?php endif; ?>
<div class="pdf-head">
<div style="display:flex;align-items:center;gap:14px">
<?php if ($cLogo): ?>
<img src="<?= esc($cLogo) ?>" alt="<?= esc($cName) ?>" style="max-height:64px;max-width:200px;object-fit:contain">
<?php endif; ?>
<div>
<h1>Offert</h1>
<div style="font-size:12px;color:#64748b"><?= esc($cName) ?><?= $cOrgnr ? ' · Org.nr '.esc($cOrgnr) : '' ?></div>
</div>
</div>
<div class="meta">
<div><strong>Offert-nr:</strong> <?= esc($q['quote_number'] ?: ('#'.$q['id'])) ?></div>
<div><strong>Datum:</strong> <?= esc(date('Y-m-d', strtotime($q['created_at']))) ?></div>
<div><strong>Status:</strong> <?= esc(ucfirst($q['status'] ?: 'utkast')) ?></div>
</div>
</div>
<div class="pdf-customer">
<div><div class="lbl">Kund</div><div><?= esc($q['customer_name'] ?: '—') ?></div></div>
<div><div class="lbl">Personnummer</div><div><?= esc($q['customer_personnummer'] ?: '—') ?></div></div>
<div><div class="lbl">Adress</div><div><?= esc($q['customer_address'] ?: '—') ?></div></div>
<div><div class="lbl">Email</div><div><?= esc($q['customer_email'] ?: '—') ?></div></div>
<div><div class="lbl">Telefon</div><div><?= esc($q['customer_phone'] ?: '—') ?></div></div>
</div>
<?php
// === Bulk-fetcha tillval-produkter för att veta vilka är tjänster (cat='tjanster' = ROT-relevanta arbetskostnader) ===
$tillvalIds = [];
foreach ($items as $itx) {
$entriesX = isset($itx['entries']) && is_array($itx['entries']) ? $itx['entries'] : [$itx];
foreach ($entriesX as $eX) {
if (empty($eX['tillval']) || !is_array($eX['tillval'])) continue;
foreach ($eX['tillval'] as $tvX) {
// Vi behöver ta med ALLA (även hidden) för att kunna avgöra om de är tjänster
if (!empty($tvX['id']) && empty($tvX['isInfo'])) $tillvalIds[$tvX['id']] = true;
}
}
}
$tillvalCatMap = [];
if (!empty($tillvalIds)) {
$ids = array_keys($tillvalIds);
$placeholders = implode(',', array_fill(0, count($ids), '?'));
$st = $db->prepare("SELECT id, cat FROM products WHERE id IN ($placeholders)");
$st->execute($ids);
foreach ($st->fetchAll() as $r) $tillvalCatMap[$r['id']] = $r['cat'];
}
function _isTjanst($tv, $catMap){
$id = $tv['id'] ?? '';
if (isset($catMap[$id]) && $catMap[$id] === 'tjanster') return true;
// Fallback: TJ-prefix indikerar tjänst om DB-lookup saknas
if (strpos($id, 'TJ-') === 0) return true;
return false;
}
?>
<?php foreach ($items as $cat => $item):
$entriesAll = isset($item['entries']) && is_array($item['entries']) ? $item['entries'] : [$item];
// Filtrera bort dolda addon-entries (cost-only, syns ej i offert)
$entries = array_values(array_filter($entriesAll, function($e){ return empty($e['hidden']); }));
if (!$entries) continue;
$catTotal = 0;
foreach ($entries as $e) { $catTotal += (float) ($e['subtotal'] ?? $e['total'] ?? 0); }
$catLbl = $catLabels[$cat] ?? ucfirst($cat);
// Gruppera fönster-rader: identiska produkt+variant räknas som EN rad med antal.
// Tjänst-tillval (Installation/Bortforsling etc) lyfts ut till EGNA rader med pris.
$groups = [];
$services = []; // id => {name, count, totalPrice}
foreach ($entries as $e) {
$key = ($e['product_id'] ?? '') . '|' . ($e['variant_label'] ?? '');
if (!isset($groups[$key])) {
$groups[$key] = [
'desc' => $e['description'] ?? $e['product_name'] ?? $catLbl,
'variant' => $e['variant_label'] ?? '',
'count' => 0,
];
}
$groups[$key]['count'] += max(1, (int) ($e['qty'] ?? 1));
if (!empty($e['tillval']) && is_array($e['tillval'])) {
foreach ($e['tillval'] as $tv) {
if (!empty($tv['isInfo'])) continue;
if (!_isTjanst($tv, $tillvalCatMap)) continue;
// Tjänster visas ALLTID som ROT-rad — även om dolda i kalkylator-UI
// (kunden ska se vad de betalar för i offerten)
$sid = $tv['id'] ?? $tv['name'];
if (!isset($services[$sid])) {
$services[$sid] = ['name' => $tv['name'] ?? $sid, 'count' => 0, 'total' => 0.0];
}
$services[$sid]['count'] += max(1, (float) ($tv['qty'] ?? 1));
$services[$sid]['total'] += (float) ($tv['total'] ?? $tv['price'] ?? 0);
}
}
}
?>
<div class="pdf-section">
<h2><span><?= esc($catLbl) ?></span><span><?= fmt($catTotal) ?> kr</span></h2>
<table class="pdf-lines">
<?php foreach ($groups as $g):
$showVariant = $g['variant'] && strpos($g['desc'], $g['variant']) === false;
?>
<tr>
<td style="text-align:left">
<div><strong><?= esc($g['count']) ?> st</strong> <?= esc($g['desc']) ?><?= $showVariant ? ' <span style="color:#64748b">('.esc($g['variant']).')</span>' : '' ?></div>
</td>
</tr>
<?php endforeach; ?>
<?php foreach ($services as $sv):
$cnt = $sv['count'];
$cntTxt = ($cnt == (int)$cnt) ? (int)$cnt : number_format($cnt, 1, ',', ' ');
?>
<tr>
<td style="text-align:left">
<div><strong><?= esc($cntTxt) ?> st</strong> <?= esc($sv['name']) ?> <span style="color:#64748b">(ROT-berättigad arbetskostnad)</span></div>
</td>
<td style="text-align:right;white-space:nowrap;font-weight:700;color:#024550"><?= fmt($sv['total']) ?> kr</td>
</tr>
<?php endforeach; ?>
</table>
</div>
<?php endforeach; ?>
<div class="pdf-totals">
<div class="pdf-totals-row"><span>Totalt före avdrag</span><span><?= fmt($grandTotal) ?> kr</span></div>
<?php
// Flera avdragstyper → visa en rad per typ (oskapet — cap appliceras separat mot totalen).
$dedTypesActive = ((int)($breakdown['ROT'] > 0) + (int)($breakdown['GT20'] > 0) + (int)($breakdown['GT50'] > 0));
?>
<?php if ($dedTypesActive > 1): ?>
<?php if ($breakdown['ROT'] > 0): ?>
<div class="pdf-totals-row"><span>ROT-avdrag (<?= (int)$tax['rot'] ?>%)</span><span style="color:#059669">−<?= fmt($breakdown['ROT']) ?> kr</span></div>
<?php endif; ?>
<?php if ($breakdown['GT20'] > 0): ?>
<div class="pdf-totals-row"><span>Grönt teknik-avdrag (<?= (int)$tax['gt20'] ?>%)</span><span style="color:#059669">−<?= fmt($breakdown['GT20']) ?> kr</span></div>
<?php endif; ?>
<?php if ($breakdown['GT50'] > 0): ?>
<div class="pdf-totals-row"><span>Skattereduktion (<?= (int)$tax['gt50'] ?>%)</span><span style="color:#059669">−<?= fmt($breakdown['GT50']) ?> kr</span></div>
<?php endif; ?>
<div class="pdf-totals-row"><span>Totalt avdrag<?= $owners > 1 ? ' · '.$owners.' ägare' : '' ?></span><span style="color:#059669;font-weight:700">−<?= fmt($effectiveDed) ?> kr</span></div>
<?php elseif ($effectiveDed > 0): ?>
<div class="pdf-totals-row"><span><?= esc($deductionLabel ?: 'Skattereduktion') ?><?= $owners > 1 ? ' · '.$owners.' ägare' : '' ?></span><span style="color:#059669">−<?= fmt($effectiveDed) ?> kr</span></div>
<?php endif; ?>
<?php if ($potentialDed > $effectiveDed): ?>
<div class="pdf-totals-row" style="font-size:11px;color:#94a3b8"><span>Kvarvarande potentiellt avdrag</span><span><?= fmt($potentialDed - $effectiveDed) ?> kr</span></div>
<?php endif; ?>
<div class="pdf-totals-row"><span>Att betala (inkl. moms <?= (int) $tax['moms'] ?>%)</span><span><?= fmt($netTotal) ?> kr</span></div>
</div>
<?php if (count($images)): ?>
<div class="pdf-section" style="page-break-before:always">
<h2>Prospektbilder</h2>
<div class="pdf-images">
<?php foreach ($images as $im):
$url = is_array($im) ? ($im['url'] ?? '') : $im;
if (!$url) continue;
?>
<img src="<?= esc($url) ?>" alt="">
<?php endforeach; ?>
</div>
</div>
<?php endif; ?>
<?php if (!empty($q['notes'])): ?>
<div class="pdf-section">
<h2>Anteckningar</h2>
<div style="padding:10px 14px;background:#f8fafc;border:1px solid #e5e7eb;border-radius:6px;white-space:pre-wrap"><?= esc($q['notes']) ?></div>
</div>
<?php endif; ?>
<div class="pdf-footer">
<div>
<strong><?= esc($cName) ?></strong><?= $cOrgnr ? ' · Org.nr '.esc($cOrgnr) : '' ?><br>
<?php
$addrBits = array_filter([$cAddress, $cPhone, $cEmail, $cWebsite]);
echo esc(implode(' · ', $addrBits));
?>
</div>
<div><?= esc($cFooter) ?></div>
</div>
</body>
</html>