feat: CNB exchange rates, multi-currency KPI stats, invoice PDF VAT in CZK

- ČNB exchange rate service with date-specific rates and caching
- Invoice/received invoice stats convert foreign currencies to CZK
- Dashboard revenue converts all currencies to CZK
- Invoice PDF: VAT recap table always in CZK with CNB rate footer
- Inline styles replaced with utility classes (step 4 cleanup)
- Spinner animation exempt from prefers-reduced-motion

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
BOHA
2026-03-27 13:44:53 +01:00
parent a3ef37d0d2
commit 8cdf057ab3
13 changed files with 173 additions and 117 deletions

View File

@@ -814,8 +814,8 @@ export default function Offers() {
<tr>
<td
colSpan={8}
className="text-muted"
style={{ textAlign: "center", padding: "1.5rem" }}
className="text-muted text-center"
style={{ padding: "1.5rem" }}
>
Žádné nabídky odpovídající hledání.
</td>
@@ -879,8 +879,8 @@ export default function Offers() {
<div className="admin-modal-header">
<h2 className="admin-modal-title">Vytvořit objednávku</h2>
<p
className="text-secondary"
style={{ marginTop: "0.25rem", fontSize: "0.875rem" }}
className="text-secondary text-md"
style={{ marginTop: "0.25rem" }}
>
Nabídka:{" "}
<strong>{orderModal.quotation?.quotation_number}</strong>
@@ -917,7 +917,7 @@ export default function Offers() {
<path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z" />
<polyline points="14 2 14 8 20 8" />
</svg>
<span style={{ fontSize: "0.875rem" }}>
<span className="text-md">
{orderAttachment.name}{" "}
<span className="text-tertiary">
({(orderAttachment.size / 1024).toFixed(0)} KB)
@@ -944,11 +944,9 @@ export default function Offers() {
</div>
) : (
<label
className="admin-btn admin-btn-secondary admin-btn-sm"
className="admin-btn admin-btn-secondary admin-btn-sm inline-flex"
style={{
cursor: "pointer",
display: "inline-flex",
alignItems: "center",
gap: "0.4rem",
}}
>