From 13cc5d956eca90d539f13d429647da48a6db605b Mon Sep 17 00:00:00 2001 From: Viktor Barzin Date: Sun, 19 Apr 2026 13:12:57 +0000 Subject: [PATCH] =?UTF-8?q?[monitoring]=20UK=20Payslip=20dashboard=20v3.1?= =?UTF-8?q?=20=E2=80=94=20add=20YTD=20reconciliation=20panel?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds panel 6 that reconciles each payslip's reported YTD summary block (ytd_gross, ytd_taxable_pay, ytd_tax_paid) against the cumulative sum of extracted per-payslip values within the same tax year. Any Δ > £0.02 flags a parser regression, missing slip, or duplicate ingest — the algebraic companion to the existing missing-months panel. Variant A payslips (pre-mid-2022) carry no YTD block and are filtered out via WHERE ytd_gross IS NOT NULL. --- .../monitoring/dashboards/uk-payslip.json | 310 ++++++++++++++++++ 1 file changed, 310 insertions(+) diff --git a/stacks/monitoring/modules/monitoring/dashboards/uk-payslip.json b/stacks/monitoring/modules/monitoring/dashboards/uk-payslip.json index 88774daa..77e211ce 100644 --- a/stacks/monitoring/modules/monitoring/dashboards/uk-payslip.json +++ b/stacks/monitoring/modules/monitoring/dashboards/uk-payslip.json @@ -649,6 +649,316 @@ "rawSql": "SELECT pay_date, employer, tax_year, gross_pay, (gross_pay - rsu_vest) AS cash_gross, salary, bonus, rsu_vest, rsu_offset, pension_sacrifice, taxable_pay, income_tax, national_insurance, pension_employee, pension_employer, student_loan, COALESCE(other_deductions, '{}'::jsonb) AS other_deductions, net_pay, validated, paperless_doc_id FROM payslip_ingest.payslip WHERE $__timeFilter(pay_date) ORDER BY pay_date DESC" } ] + }, + { + "id": 6, + "title": "YTD reconciliation \u2014 reported vs computed", + "description": "Reconciles each payslip's reported YTD summary block against the cumulative sum of extracted per-payslip values within the same tax year. Any \u0394 > \u00a30.02 is a parser regression, a missing slip, or a duplicate ingest. Variant A payslips (pre-mid-2022) have no YTD block and are excluded.", + "type": "table", + "datasource": { + "type": "grafana-postgresql-datasource", + "uid": "payslips-pg" + }, + "gridPos": { + "h": 12, + "w": 24, + "x": 0, + "y": 39 + }, + "fieldConfig": { + "defaults": { + "custom": { + "align": "right", + "cellOptions": { + "type": "auto" + }, + "inspect": false + }, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "pay_date" + }, + "properties": [ + { + "id": "custom.width", + "value": 110 + }, + { + "id": "custom.align", + "value": "left" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "tax_year" + }, + "properties": [ + { + "id": "custom.width", + "value": 80 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "gross_pay" + }, + "properties": [ + { + "id": "unit", + "value": "currencyGBP" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "ytd_gross_reported" + }, + "properties": [ + { + "id": "unit", + "value": "currencyGBP" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "ytd_gross_computed" + }, + "properties": [ + { + "id": "unit", + "value": "currencyGBP" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "delta_gross" + }, + "properties": [ + { + "id": "unit", + "value": "currencyGBP" + }, + { + "id": "custom.cellOptions", + "value": { + "type": "color-background", + "mode": "basic" + } + }, + { + "id": "thresholds", + "value": { + "mode": "absolute", + "steps": [ + { + "color": "red", + "value": null + }, + { + "color": "green", + "value": -0.02 + }, + { + "color": "red", + "value": 0.02 + } + ] + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "taxable_pay" + }, + "properties": [ + { + "id": "unit", + "value": "currencyGBP" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "ytd_taxable_reported" + }, + "properties": [ + { + "id": "unit", + "value": "currencyGBP" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "ytd_taxable_computed" + }, + "properties": [ + { + "id": "unit", + "value": "currencyGBP" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "delta_taxable" + }, + "properties": [ + { + "id": "unit", + "value": "currencyGBP" + }, + { + "id": "custom.cellOptions", + "value": { + "type": "color-background", + "mode": "basic" + } + }, + { + "id": "thresholds", + "value": { + "mode": "absolute", + "steps": [ + { + "color": "red", + "value": null + }, + { + "color": "green", + "value": -0.02 + }, + { + "color": "red", + "value": 0.02 + } + ] + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "income_tax" + }, + "properties": [ + { + "id": "unit", + "value": "currencyGBP" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "ytd_tax_reported" + }, + "properties": [ + { + "id": "unit", + "value": "currencyGBP" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "ytd_tax_computed" + }, + "properties": [ + { + "id": "unit", + "value": "currencyGBP" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "delta_tax" + }, + "properties": [ + { + "id": "unit", + "value": "currencyGBP" + }, + { + "id": "custom.cellOptions", + "value": { + "type": "color-background", + "mode": "basic" + } + }, + { + "id": "thresholds", + "value": { + "mode": "absolute", + "steps": [ + { + "color": "red", + "value": null + }, + { + "color": "green", + "value": -0.02 + }, + { + "color": "red", + "value": 0.02 + } + ] + } + } + ] + } + ] + }, + "options": { + "cellHeight": "sm", + "footer": { + "show": false + } + }, + "targets": [ + { + "refId": "A", + "datasource": { + "type": "grafana-postgresql-datasource", + "uid": "payslips-pg" + }, + "rawQuery": true, + "editorMode": "code", + "format": "table", + "rawSql": "SELECT pay_date, tax_year, gross_pay, ytd_gross AS ytd_gross_reported, SUM(gross_pay) OVER w AS ytd_gross_computed, (ytd_gross - SUM(gross_pay) OVER w) AS delta_gross, taxable_pay, ytd_taxable_pay AS ytd_taxable_reported, SUM(taxable_pay) OVER w AS ytd_taxable_computed, (ytd_taxable_pay - SUM(taxable_pay) OVER w) AS delta_taxable, income_tax, ytd_tax_paid AS ytd_tax_reported, SUM(income_tax) OVER w AS ytd_tax_computed, (ytd_tax_paid - SUM(income_tax) OVER w) AS delta_tax FROM payslip_ingest.payslip WHERE $__timeFilter(pay_date) AND ytd_gross IS NOT NULL WINDOW w AS (PARTITION BY tax_year ORDER BY pay_date) ORDER BY pay_date DESC" + } + ] } ], "refresh": "5m",