# BI Dashboard A flat, server-free dashboard for the Brandize BI webhook (`Summe je Abgangsland`). It shows the gross revenue (Brutto inkl. USt) per departure country for a selected period, with KPI cards, a bar chart and a detail table. ## Run Just open `index.html` in a browser (double-click it). No server, no build step. The page calls the webhook directly: ``` https://brandize.app.n8n.cloud/webhook/bi-dashboard ``` via a **POST** request with a JSON body: ```json { "query": "Summe je Abgangsland", "month": "2026-SEP" } ``` The webhook sends CORS headers (it reflects the request `Origin`, including `null` for `file://`), so a direct browser call works. ## Navigation The left sidebar groups reports by topic: - **Amazon** → *Umsatz je Abgangsland* (Brutto inkl. USt je Abgangsland) - **Amazon** → *VAT Summary* (USt-Übersicht je Land) - **ODOO** → *Rechnungen pro Monat* (Pivot über Odoo-Rechnungen) - **ODOO** → *FIFO Lager Bewertung* (Lagerwert FIFO) - **ODOO** → *Produkt Materialkosten* (Materialkosten je Produkt) - **Gesamt** → *Alle Rechnungen pro Monat* (PivotTable.js-Experiment) - **Gesamt** → *Quartal Schweiz* (AMAZON + ODOO, Lieferung in die Schweiz) All groups start collapsed, so no submenu is visible when the page opens. Clicking a topic expands its submenu; clicking a submenu item switches the view. ## Authentication The webhooks are protected with HTTP Basic Auth. The dashboard asks for the credentials when they are needed: the first request is sent without them, and when the webhook answers `401`, a login prompt appears. The entered credentials are sent as an `Authorization: Basic ...` header on every request and kept in `sessionStorage` for the rest of the browser session (so a reload does not prompt again). If the webhook rejects them (`401`), the prompt reappears. Storage is best-effort: on `file://` it may be unavailable, in which case credentials are kept in memory only. ## CSV export The header has a **CSV** button that downloads the data of the currently displayed dashboard, as a semicolon-delimited UTF-8 file (with BOM) including a Gesamt row: - *Umsatz je Abgangsland* → `umsatz-je-abgangsland_YYYY-MMM.csv` - *VAT Summary* → `vat-summary_YYYY-MMM.csv` - *Rechnungen pro Monat* → `odoo-rechnungen_YYYY-MMM.csv` - *Alle Rechnungen pro Monat* → `gesamt-rechnungen-pivot_YYYY-MMM.csv` - *Quartal Schweiz* → `schweiz-quartal_YYYY-QN.csv` - *FIFO Lager Bewertung* → `fifo-lager_YYYY-MMM.csv` - *Produkt Materialkosten* → `materialkosten_YYYY-MMM.csv` The button is disabled while no dataset is loaded for the current dashboard. ## Filter A shared filter bar sits above every dashboard (labelled **Filter** with a funnel icon and the hint *gilt für alle Dashboards*). It holds the **Zeitraum** month + year selector (e.g. `2026-SEP`) and the reload button, and stays visible across all views. The previous month is preselected. The selected period is sent to the webhook in the POST body as `month` (e.g. `2026-SEP`), matching the `%(month)s` parameter used in `../sql/*.sql`. The invoice dashboards (*ODOO Rechnungen pro Monat*, *Alle Rechnungen pro Monat* and *Quartal Schweiz*) have an additional, dashboard-specific filter row. *ODOO Rechnungen pro Monat* filters by **Tag**, **Bestellnummer**, **Lieferland** and **Rechnungsnummer**; *Alle Rechnungen pro Monat* and *Quartal Schweiz* add a **Quelle** field. Filtering re-renders the KPIs, chart and pivot live. For *Quartal Schweiz* the shared **Zeitraum** control shows a **quarter** selector (Q1–Q4) instead of the month selector; the year selector is shared. ## Pivot (Experiment) The three invoice dashboards (*ODOO Rechnungen pro Monat*, *Alle Rechnungen pro Monat* and *Quartal Schweiz*) render their data as an interactive [PivotTable.js](https://pivottable.js.org/) pivot instead of a detail table. The pivot's rows, columns, values and aggregator are freely configurable in the pivotUI control panel; the renderer is fixed to *Table*. Each dashboard has its own filter row and **Vorlage** dropdown with presets: - *ODOO Rechnungen pro Monat*: *Standard* (**Rechnungsland** rows, no column group, **Sum(Gesamtpreis brutto)**) and *Zahlart*. - *Alle Rechnungen pro Monat* and *Quartal Schweiz*: *Standard* (**Quelle** rows, no column group, **Sum(Gesamtpreis brutto)**) and *Rechnungsland (Spalten)* (adds **Rechnungsland** as the column group). *Quartal Schweiz* is filtered to invoices with a **delivery into Switzerland**. Applying a preset also resets the filters. The chosen layout is kept while you type in the filters. It loads jQuery, jQuery UI and PivotTable.js from public CDNs, so — unlike the rest of the app — it needs an **internet connection** to render; offline it shows a short message instead. To vendor the libraries locally, download them next to `index.html` and change the ``/`