"Monthly cash flow — tax impact (RSU excluded)" was already stacking group A in normal mode but rendered as 70%-opacity filled lines — the overlap made the total-per-month figure visually inaccessible. Switch drawStyle to bars (100% fill, 0-width lineWidth, no per-point markers) so each month reads as a single stacked bar whose top edge is the total cash-side deduction. Add "sum" to legend.calcs so the tax-year totals per series show in the legend table alongside last and max. Panel 11 (Tax & pension — monthly, RSU-inclusive) retains the line/ area style so the two panels remain visually distinct.
2328 lines
No EOL
66 KiB
JSON
2328 lines
No EOL
66 KiB
JSON
{
|
|
"annotations": {
|
|
"list": [
|
|
{
|
|
"builtIn": 1,
|
|
"datasource": {
|
|
"type": "datasource",
|
|
"uid": "grafana"
|
|
},
|
|
"enable": true,
|
|
"hide": true,
|
|
"iconColor": "rgba(0, 211, 255, 1)",
|
|
"name": "Annotations & Alerts",
|
|
"type": "dashboard"
|
|
}
|
|
]
|
|
},
|
|
"description": "UK payslip breakdown \u2014 tax-year YTD hero, monthly cash flow, effective-rate trend, data-integrity flags, and full payslip table.",
|
|
"editable": true,
|
|
"fiscalYearStartMonth": 0,
|
|
"graphTooltip": 1,
|
|
"id": null,
|
|
"links": [],
|
|
"panels": [
|
|
{
|
|
"id": 1,
|
|
"title": "YTD sources \u2014 income composition",
|
|
"description": "Year-to-date cumulative breakdown of gross pay by source. Stacked \u2014 top of the stack equals gross_pay. Reset at each tax-year boundary.",
|
|
"type": "timeseries",
|
|
"datasource": {
|
|
"type": "grafana-postgresql-datasource",
|
|
"uid": "payslips-pg"
|
|
},
|
|
"gridPos": {
|
|
"h": 10,
|
|
"w": 12,
|
|
"x": 0,
|
|
"y": 0
|
|
},
|
|
"fieldConfig": {
|
|
"defaults": {
|
|
"color": {
|
|
"mode": "palette-classic"
|
|
},
|
|
"unit": "currencyGBP",
|
|
"custom": {
|
|
"axisPlacement": "auto",
|
|
"drawStyle": "line",
|
|
"fillOpacity": 70,
|
|
"gradientMode": "none",
|
|
"hideFrom": {
|
|
"legend": false,
|
|
"tooltip": false,
|
|
"viz": false
|
|
},
|
|
"lineWidth": 1,
|
|
"pointSize": 4,
|
|
"scaleDistribution": {
|
|
"type": "linear"
|
|
},
|
|
"showPoints": "auto",
|
|
"spanNulls": false,
|
|
"stacking": {
|
|
"group": "A",
|
|
"mode": "normal"
|
|
},
|
|
"thresholdsStyle": {
|
|
"mode": "off"
|
|
}
|
|
}
|
|
},
|
|
"overrides": [
|
|
{
|
|
"matcher": {
|
|
"id": "byName",
|
|
"options": "ytd_salary"
|
|
},
|
|
"properties": [
|
|
{
|
|
"id": "color",
|
|
"value": {
|
|
"mode": "fixed",
|
|
"fixedColor": "green"
|
|
}
|
|
},
|
|
{
|
|
"id": "displayName",
|
|
"value": "Salary"
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"matcher": {
|
|
"id": "byName",
|
|
"options": "ytd_bonus"
|
|
},
|
|
"properties": [
|
|
{
|
|
"id": "color",
|
|
"value": {
|
|
"mode": "fixed",
|
|
"fixedColor": "yellow"
|
|
}
|
|
},
|
|
{
|
|
"id": "displayName",
|
|
"value": "Bonus"
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"matcher": {
|
|
"id": "byName",
|
|
"options": "ytd_rsu"
|
|
},
|
|
"properties": [
|
|
{
|
|
"id": "color",
|
|
"value": {
|
|
"mode": "fixed",
|
|
"fixedColor": "blue"
|
|
}
|
|
},
|
|
{
|
|
"id": "displayName",
|
|
"value": "RSU (notional)"
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"matcher": {
|
|
"id": "byName",
|
|
"options": "ytd_other"
|
|
},
|
|
"properties": [
|
|
{
|
|
"id": "color",
|
|
"value": {
|
|
"mode": "fixed",
|
|
"fixedColor": "text"
|
|
}
|
|
},
|
|
{
|
|
"id": "displayName",
|
|
"value": "Other / residual"
|
|
}
|
|
]
|
|
}
|
|
]
|
|
},
|
|
"options": {
|
|
"legend": {
|
|
"calcs": [
|
|
"last",
|
|
"max"
|
|
],
|
|
"displayMode": "table",
|
|
"placement": "bottom"
|
|
},
|
|
"tooltip": {
|
|
"mode": "multi",
|
|
"sort": "desc"
|
|
}
|
|
},
|
|
"targets": [
|
|
{
|
|
"datasource": {
|
|
"type": "grafana-postgresql-datasource",
|
|
"uid": "payslips-pg"
|
|
},
|
|
"rawSql": "SELECT pay_date AS \"time\", SUM(salary) OVER w AS ytd_salary, SUM(bonus) OVER w AS ytd_bonus, SUM(rsu_vest) OVER w AS ytd_rsu, SUM(GREATEST(gross_pay - salary - bonus - rsu_vest, 0)) OVER w AS ytd_other FROM payslip_ingest.payslip WHERE $__timeFilter(pay_date) WINDOW w AS (PARTITION BY tax_year ORDER BY pay_date) ORDER BY pay_date",
|
|
"format": "time_series",
|
|
"refId": "A",
|
|
"rawQuery": true,
|
|
"editorMode": "code"
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"id": 7,
|
|
"title": "YTD uses \u2014 where gross went",
|
|
"description": "Year-to-date cumulative breakdown of where the gross went. Stacked \u2014 top equals gross_pay minus student loan and RSU offset (both small; shown on Panel 8 Sankey). Green = take-home; red = cash income tax; orange = RSU-attributed income tax + NI; purple = pension.",
|
|
"type": "timeseries",
|
|
"datasource": {
|
|
"type": "grafana-postgresql-datasource",
|
|
"uid": "payslips-pg"
|
|
},
|
|
"gridPos": {
|
|
"h": 10,
|
|
"w": 12,
|
|
"x": 12,
|
|
"y": 0
|
|
},
|
|
"fieldConfig": {
|
|
"defaults": {
|
|
"color": {
|
|
"mode": "palette-classic"
|
|
},
|
|
"unit": "currencyGBP",
|
|
"custom": {
|
|
"axisPlacement": "auto",
|
|
"drawStyle": "line",
|
|
"fillOpacity": 70,
|
|
"gradientMode": "none",
|
|
"hideFrom": {
|
|
"legend": false,
|
|
"tooltip": false,
|
|
"viz": false
|
|
},
|
|
"lineWidth": 1,
|
|
"pointSize": 4,
|
|
"scaleDistribution": {
|
|
"type": "linear"
|
|
},
|
|
"showPoints": "auto",
|
|
"spanNulls": false,
|
|
"stacking": {
|
|
"group": "A",
|
|
"mode": "normal"
|
|
},
|
|
"thresholdsStyle": {
|
|
"mode": "off"
|
|
}
|
|
}
|
|
},
|
|
"overrides": [
|
|
{
|
|
"matcher": {
|
|
"id": "byName",
|
|
"options": "ytd_net"
|
|
},
|
|
"properties": [
|
|
{
|
|
"id": "color",
|
|
"value": {
|
|
"mode": "fixed",
|
|
"fixedColor": "green"
|
|
}
|
|
},
|
|
{
|
|
"id": "displayName",
|
|
"value": "Net (take-home)"
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"matcher": {
|
|
"id": "byName",
|
|
"options": "ytd_cash_income_tax"
|
|
},
|
|
"properties": [
|
|
{
|
|
"id": "color",
|
|
"value": {
|
|
"mode": "fixed",
|
|
"fixedColor": "#C4162A"
|
|
}
|
|
},
|
|
{
|
|
"id": "displayName",
|
|
"value": "Income Tax (cash pay)"
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"matcher": {
|
|
"id": "byName",
|
|
"options": "ytd_rsu_income_tax"
|
|
},
|
|
"properties": [
|
|
{
|
|
"id": "color",
|
|
"value": {
|
|
"mode": "fixed",
|
|
"fixedColor": "#E0652E"
|
|
}
|
|
},
|
|
{
|
|
"id": "displayName",
|
|
"value": "Income Tax (RSU-attributed)"
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"matcher": {
|
|
"id": "byName",
|
|
"options": "ytd_ni"
|
|
},
|
|
"properties": [
|
|
{
|
|
"id": "color",
|
|
"value": {
|
|
"mode": "fixed",
|
|
"fixedColor": "orange"
|
|
}
|
|
},
|
|
{
|
|
"id": "displayName",
|
|
"value": "National Insurance"
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"matcher": {
|
|
"id": "byName",
|
|
"options": "ytd_pension_employee"
|
|
},
|
|
"properties": [
|
|
{
|
|
"id": "color",
|
|
"value": {
|
|
"mode": "fixed",
|
|
"fixedColor": "purple"
|
|
}
|
|
},
|
|
{
|
|
"id": "displayName",
|
|
"value": "Pension (employee)"
|
|
}
|
|
]
|
|
}
|
|
]
|
|
},
|
|
"options": {
|
|
"legend": {
|
|
"calcs": [
|
|
"last",
|
|
"max"
|
|
],
|
|
"displayMode": "table",
|
|
"placement": "bottom"
|
|
},
|
|
"tooltip": {
|
|
"mode": "multi",
|
|
"sort": "desc"
|
|
}
|
|
},
|
|
"targets": [
|
|
{
|
|
"datasource": {
|
|
"type": "grafana-postgresql-datasource",
|
|
"uid": "payslips-pg"
|
|
},
|
|
"rawSql": "SELECT pay_date AS \"time\", SUM(net_pay) OVER w AS ytd_net, SUM(COALESCE(cash_income_tax, income_tax)) OVER w AS ytd_cash_income_tax, SUM(income_tax - COALESCE(cash_income_tax, income_tax)) OVER w AS ytd_rsu_income_tax, SUM(national_insurance) OVER w AS ytd_ni, SUM(pension_employee) OVER w AS ytd_pension_employee FROM payslip_ingest.payslip WHERE $__timeFilter(pay_date) WINDOW w AS (PARTITION BY tax_year ORDER BY pay_date) ORDER BY pay_date",
|
|
"format": "time_series",
|
|
"refId": "A",
|
|
"rawQuery": true,
|
|
"editorMode": "code"
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"id": 2,
|
|
"title": "Monthly cash flow (RSU stripped)",
|
|
"type": "timeseries",
|
|
"datasource": {
|
|
"type": "grafana-postgresql-datasource",
|
|
"uid": "payslips-pg"
|
|
},
|
|
"gridPos": {
|
|
"h": 9,
|
|
"w": 12,
|
|
"x": 0,
|
|
"y": 10
|
|
},
|
|
"fieldConfig": {
|
|
"defaults": {
|
|
"color": {
|
|
"mode": "palette-classic"
|
|
},
|
|
"unit": "currencyGBP",
|
|
"custom": {
|
|
"axisBorderShow": false,
|
|
"axisCenteredZero": false,
|
|
"axisColorMode": "text",
|
|
"axisLabel": "",
|
|
"axisPlacement": "auto",
|
|
"barAlignment": 0,
|
|
"drawStyle": "line",
|
|
"fillOpacity": 10,
|
|
"gradientMode": "none",
|
|
"hideFrom": {
|
|
"legend": false,
|
|
"tooltip": false,
|
|
"viz": false
|
|
},
|
|
"lineWidth": 2,
|
|
"pointSize": 5,
|
|
"scaleDistribution": {
|
|
"type": "linear"
|
|
},
|
|
"showPoints": "auto",
|
|
"spanNulls": false,
|
|
"stacking": {
|
|
"group": "A",
|
|
"mode": "none"
|
|
},
|
|
"thresholdsStyle": {
|
|
"mode": "off"
|
|
}
|
|
}
|
|
},
|
|
"overrides": []
|
|
},
|
|
"options": {
|
|
"legend": {
|
|
"calcs": [
|
|
"last",
|
|
"mean"
|
|
],
|
|
"displayMode": "table",
|
|
"placement": "bottom"
|
|
},
|
|
"tooltip": {
|
|
"mode": "multi",
|
|
"sort": "desc"
|
|
}
|
|
},
|
|
"targets": [
|
|
{
|
|
"datasource": {
|
|
"type": "grafana-postgresql-datasource",
|
|
"uid": "payslips-pg"
|
|
},
|
|
"rawSql": "SELECT pay_date AS \"time\", (gross_pay - rsu_vest) AS cash_gross, net_pay, COALESCE(cash_income_tax, income_tax) AS income_tax, national_insurance FROM payslip_ingest.payslip WHERE $__timeFilter(pay_date) ORDER BY pay_date",
|
|
"format": "time_series",
|
|
"refId": "A",
|
|
"rawQuery": true,
|
|
"editorMode": "code"
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"id": 3,
|
|
"title": "Effective rate & take-home % (YTD cumulative)",
|
|
"description": "YTD-cumulative rates. PAYE rate uses reported taxable_pay as the base; all-deductions rate uses gross_pay. Computed from cumulative SUM over the tax year, so vest-month RSU tax is blended proportionally with RSU value \u2014 no per-slip attribution hack, no spikes.",
|
|
"type": "timeseries",
|
|
"datasource": {
|
|
"type": "grafana-postgresql-datasource",
|
|
"uid": "payslips-pg"
|
|
},
|
|
"gridPos": {
|
|
"h": 9,
|
|
"w": 12,
|
|
"x": 12,
|
|
"y": 10
|
|
},
|
|
"fieldConfig": {
|
|
"defaults": {
|
|
"color": {
|
|
"mode": "palette-classic"
|
|
},
|
|
"unit": "percent",
|
|
"min": 0,
|
|
"max": 100,
|
|
"custom": {
|
|
"axisBorderShow": false,
|
|
"axisCenteredZero": false,
|
|
"axisColorMode": "text",
|
|
"axisLabel": "",
|
|
"axisPlacement": "auto",
|
|
"barAlignment": 0,
|
|
"drawStyle": "line",
|
|
"fillOpacity": 10,
|
|
"gradientMode": "none",
|
|
"hideFrom": {
|
|
"legend": false,
|
|
"tooltip": false,
|
|
"viz": false
|
|
},
|
|
"lineWidth": 2,
|
|
"pointSize": 5,
|
|
"scaleDistribution": {
|
|
"type": "linear"
|
|
},
|
|
"showPoints": "auto",
|
|
"spanNulls": false,
|
|
"stacking": {
|
|
"group": "A",
|
|
"mode": "none"
|
|
},
|
|
"thresholdsStyle": {
|
|
"mode": "off"
|
|
}
|
|
}
|
|
},
|
|
"overrides": []
|
|
},
|
|
"options": {
|
|
"legend": {
|
|
"calcs": [
|
|
"last",
|
|
"mean"
|
|
],
|
|
"displayMode": "table",
|
|
"placement": "bottom"
|
|
},
|
|
"tooltip": {
|
|
"mode": "multi",
|
|
"sort": "desc"
|
|
}
|
|
},
|
|
"targets": [
|
|
{
|
|
"datasource": {
|
|
"type": "grafana-postgresql-datasource",
|
|
"uid": "payslips-pg"
|
|
},
|
|
"rawSql": "SELECT pay_date AS \"time\", ROUND(((SUM(income_tax) OVER w)::numeric / NULLIF(SUM(COALESCE(taxable_pay, gross_pay)) OVER w, 0)) * 100, 2) AS \"ytd_paye_rate_pct\", ROUND((((SUM(income_tax) OVER w) + (SUM(national_insurance) OVER w) + (SUM(student_loan) OVER w))::numeric / NULLIF(SUM(gross_pay) OVER w, 0)) * 100, 2) AS \"ytd_all_deductions_pct\", ROUND(((SUM(net_pay) OVER w)::numeric / NULLIF(SUM(gross_pay) OVER w, 0)) * 100, 2) AS \"ytd_take_home_pct\" FROM payslip_ingest.payslip WHERE $__timeFilter(pay_date) WINDOW w AS (PARTITION BY tax_year ORDER BY pay_date) ORDER BY pay_date",
|
|
"format": "time_series",
|
|
"refId": "A",
|
|
"rawQuery": true,
|
|
"editorMode": "code"
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"id": 11,
|
|
"title": "Tax & pension \u2014 monthly",
|
|
"description": "Per-month deductions and pension contributions. Stacked \u2014 top equals total tax + pension (both sides). Red = cash income tax; orange = RSU-attributed income tax; amber = NI; brown = student loan; purple = employee pension; light purple = employer pension (paid on top of salary).",
|
|
"type": "timeseries",
|
|
"datasource": {
|
|
"type": "grafana-postgresql-datasource",
|
|
"uid": "payslips-pg"
|
|
},
|
|
"gridPos": {
|
|
"h": 10,
|
|
"w": 12,
|
|
"x": 0,
|
|
"y": 19
|
|
},
|
|
"fieldConfig": {
|
|
"defaults": {
|
|
"color": {
|
|
"mode": "palette-classic"
|
|
},
|
|
"unit": "currencyGBP",
|
|
"custom": {
|
|
"axisPlacement": "auto",
|
|
"drawStyle": "line",
|
|
"fillOpacity": 70,
|
|
"gradientMode": "none",
|
|
"hideFrom": {
|
|
"legend": false,
|
|
"tooltip": false,
|
|
"viz": false
|
|
},
|
|
"lineWidth": 1,
|
|
"pointSize": 4,
|
|
"scaleDistribution": {
|
|
"type": "linear"
|
|
},
|
|
"showPoints": "auto",
|
|
"spanNulls": false,
|
|
"stacking": {
|
|
"group": "A",
|
|
"mode": "normal"
|
|
},
|
|
"thresholdsStyle": {
|
|
"mode": "off"
|
|
}
|
|
}
|
|
},
|
|
"overrides": [
|
|
{
|
|
"matcher": {
|
|
"id": "byName",
|
|
"options": "cash_income_tax"
|
|
},
|
|
"properties": [
|
|
{
|
|
"id": "color",
|
|
"value": {
|
|
"mode": "fixed",
|
|
"fixedColor": "#C4162A"
|
|
}
|
|
},
|
|
{
|
|
"id": "displayName",
|
|
"value": "Income Tax (cash pay)"
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"matcher": {
|
|
"id": "byName",
|
|
"options": "rsu_income_tax"
|
|
},
|
|
"properties": [
|
|
{
|
|
"id": "color",
|
|
"value": {
|
|
"mode": "fixed",
|
|
"fixedColor": "#E0652E"
|
|
}
|
|
},
|
|
{
|
|
"id": "displayName",
|
|
"value": "Income Tax (RSU-attributed)"
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"matcher": {
|
|
"id": "byName",
|
|
"options": "ni"
|
|
},
|
|
"properties": [
|
|
{
|
|
"id": "color",
|
|
"value": {
|
|
"mode": "fixed",
|
|
"fixedColor": "orange"
|
|
}
|
|
},
|
|
{
|
|
"id": "displayName",
|
|
"value": "National Insurance"
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"matcher": {
|
|
"id": "byName",
|
|
"options": "student_loan"
|
|
},
|
|
"properties": [
|
|
{
|
|
"id": "color",
|
|
"value": {
|
|
"mode": "fixed",
|
|
"fixedColor": "#8B4513"
|
|
}
|
|
},
|
|
{
|
|
"id": "displayName",
|
|
"value": "Student Loan"
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"matcher": {
|
|
"id": "byName",
|
|
"options": "pension_employee"
|
|
},
|
|
"properties": [
|
|
{
|
|
"id": "color",
|
|
"value": {
|
|
"mode": "fixed",
|
|
"fixedColor": "purple"
|
|
}
|
|
},
|
|
{
|
|
"id": "displayName",
|
|
"value": "Pension (employee)"
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"matcher": {
|
|
"id": "byName",
|
|
"options": "pension_employer"
|
|
},
|
|
"properties": [
|
|
{
|
|
"id": "color",
|
|
"value": {
|
|
"mode": "fixed",
|
|
"fixedColor": "#CE96D8"
|
|
}
|
|
},
|
|
{
|
|
"id": "displayName",
|
|
"value": "Pension (employer)"
|
|
}
|
|
]
|
|
}
|
|
]
|
|
},
|
|
"options": {
|
|
"legend": {
|
|
"calcs": [
|
|
"last",
|
|
"max"
|
|
],
|
|
"displayMode": "table",
|
|
"placement": "bottom"
|
|
},
|
|
"tooltip": {
|
|
"mode": "multi",
|
|
"sort": "desc"
|
|
}
|
|
},
|
|
"targets": [
|
|
{
|
|
"datasource": {
|
|
"type": "grafana-postgresql-datasource",
|
|
"uid": "payslips-pg"
|
|
},
|
|
"rawSql": "SELECT pay_date AS \"time\", COALESCE(cash_income_tax, income_tax) AS cash_income_tax, income_tax - COALESCE(cash_income_tax, income_tax) AS rsu_income_tax, national_insurance AS ni, student_loan, pension_employee, pension_employer FROM payslip_ingest.payslip WHERE $__timeFilter(pay_date) ORDER BY pay_date",
|
|
"format": "time_series",
|
|
"refId": "A",
|
|
"rawQuery": true,
|
|
"editorMode": "code"
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"id": 12,
|
|
"title": "Tax & pension \u2014 YTD cumulative",
|
|
"description": "Year-to-date cumulative tax and pension. Same series and colors as the monthly panel; resets on 6-April tax year boundary.",
|
|
"type": "timeseries",
|
|
"datasource": {
|
|
"type": "grafana-postgresql-datasource",
|
|
"uid": "payslips-pg"
|
|
},
|
|
"gridPos": {
|
|
"h": 10,
|
|
"w": 12,
|
|
"x": 12,
|
|
"y": 19
|
|
},
|
|
"fieldConfig": {
|
|
"defaults": {
|
|
"color": {
|
|
"mode": "palette-classic"
|
|
},
|
|
"unit": "currencyGBP",
|
|
"custom": {
|
|
"axisPlacement": "auto",
|
|
"drawStyle": "line",
|
|
"fillOpacity": 70,
|
|
"gradientMode": "none",
|
|
"hideFrom": {
|
|
"legend": false,
|
|
"tooltip": false,
|
|
"viz": false
|
|
},
|
|
"lineWidth": 1,
|
|
"pointSize": 4,
|
|
"scaleDistribution": {
|
|
"type": "linear"
|
|
},
|
|
"showPoints": "auto",
|
|
"spanNulls": false,
|
|
"stacking": {
|
|
"group": "A",
|
|
"mode": "normal"
|
|
},
|
|
"thresholdsStyle": {
|
|
"mode": "off"
|
|
}
|
|
}
|
|
},
|
|
"overrides": [
|
|
{
|
|
"matcher": {
|
|
"id": "byName",
|
|
"options": "ytd_cash_income_tax"
|
|
},
|
|
"properties": [
|
|
{
|
|
"id": "color",
|
|
"value": {
|
|
"mode": "fixed",
|
|
"fixedColor": "#C4162A"
|
|
}
|
|
},
|
|
{
|
|
"id": "displayName",
|
|
"value": "Income Tax (cash pay)"
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"matcher": {
|
|
"id": "byName",
|
|
"options": "ytd_rsu_income_tax"
|
|
},
|
|
"properties": [
|
|
{
|
|
"id": "color",
|
|
"value": {
|
|
"mode": "fixed",
|
|
"fixedColor": "#E0652E"
|
|
}
|
|
},
|
|
{
|
|
"id": "displayName",
|
|
"value": "Income Tax (RSU-attributed)"
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"matcher": {
|
|
"id": "byName",
|
|
"options": "ytd_ni"
|
|
},
|
|
"properties": [
|
|
{
|
|
"id": "color",
|
|
"value": {
|
|
"mode": "fixed",
|
|
"fixedColor": "orange"
|
|
}
|
|
},
|
|
{
|
|
"id": "displayName",
|
|
"value": "National Insurance"
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"matcher": {
|
|
"id": "byName",
|
|
"options": "ytd_student_loan"
|
|
},
|
|
"properties": [
|
|
{
|
|
"id": "color",
|
|
"value": {
|
|
"mode": "fixed",
|
|
"fixedColor": "#8B4513"
|
|
}
|
|
},
|
|
{
|
|
"id": "displayName",
|
|
"value": "Student Loan"
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"matcher": {
|
|
"id": "byName",
|
|
"options": "ytd_pension_employee"
|
|
},
|
|
"properties": [
|
|
{
|
|
"id": "color",
|
|
"value": {
|
|
"mode": "fixed",
|
|
"fixedColor": "purple"
|
|
}
|
|
},
|
|
{
|
|
"id": "displayName",
|
|
"value": "Pension (employee)"
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"matcher": {
|
|
"id": "byName",
|
|
"options": "ytd_pension_employer"
|
|
},
|
|
"properties": [
|
|
{
|
|
"id": "color",
|
|
"value": {
|
|
"mode": "fixed",
|
|
"fixedColor": "#CE96D8"
|
|
}
|
|
},
|
|
{
|
|
"id": "displayName",
|
|
"value": "Pension (employer)"
|
|
}
|
|
]
|
|
}
|
|
]
|
|
},
|
|
"options": {
|
|
"legend": {
|
|
"calcs": [
|
|
"last",
|
|
"max"
|
|
],
|
|
"displayMode": "table",
|
|
"placement": "bottom"
|
|
},
|
|
"tooltip": {
|
|
"mode": "multi",
|
|
"sort": "desc"
|
|
}
|
|
},
|
|
"targets": [
|
|
{
|
|
"datasource": {
|
|
"type": "grafana-postgresql-datasource",
|
|
"uid": "payslips-pg"
|
|
},
|
|
"rawSql": "SELECT pay_date AS \"time\", SUM(COALESCE(cash_income_tax, income_tax)) OVER w AS ytd_cash_income_tax, SUM(income_tax - COALESCE(cash_income_tax, income_tax)) OVER w AS ytd_rsu_income_tax, SUM(national_insurance) OVER w AS ytd_ni, SUM(student_loan) OVER w AS ytd_student_loan, SUM(pension_employee) OVER w AS ytd_pension_employee, SUM(pension_employer) OVER w AS ytd_pension_employer FROM payslip_ingest.payslip WHERE $__timeFilter(pay_date) WINDOW w AS (PARTITION BY tax_year ORDER BY pay_date) ORDER BY pay_date",
|
|
"format": "time_series",
|
|
"refId": "A",
|
|
"rawQuery": true,
|
|
"editorMode": "code"
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"id": 13,
|
|
"title": "Monthly cash flow \u2014 tax impact (RSU excluded)",
|
|
"description": "Cash-only deductions. RSU PAYE excluded \u2014 it's withheld at source via sell-to-cover and never hits the bank account. See Panel 11 for the full PAYE view including RSU-attributed tax.",
|
|
"type": "timeseries",
|
|
"datasource": {
|
|
"type": "grafana-postgresql-datasource",
|
|
"uid": "payslips-pg"
|
|
},
|
|
"gridPos": {
|
|
"h": 9,
|
|
"w": 24,
|
|
"x": 0,
|
|
"y": 29
|
|
},
|
|
"fieldConfig": {
|
|
"defaults": {
|
|
"color": {
|
|
"mode": "palette-classic"
|
|
},
|
|
"unit": "currencyGBP",
|
|
"custom": {
|
|
"axisPlacement": "auto",
|
|
"drawStyle": "bars",
|
|
"fillOpacity": 100,
|
|
"gradientMode": "none",
|
|
"hideFrom": {
|
|
"legend": false,
|
|
"tooltip": false,
|
|
"viz": false
|
|
},
|
|
"lineWidth": 0,
|
|
"pointSize": 4,
|
|
"scaleDistribution": {
|
|
"type": "linear"
|
|
},
|
|
"showPoints": "never",
|
|
"spanNulls": false,
|
|
"stacking": {
|
|
"group": "A",
|
|
"mode": "normal"
|
|
},
|
|
"thresholdsStyle": {
|
|
"mode": "off"
|
|
}
|
|
}
|
|
},
|
|
"overrides": [
|
|
{
|
|
"matcher": {
|
|
"id": "byName",
|
|
"options": "cash_income_tax"
|
|
},
|
|
"properties": [
|
|
{
|
|
"id": "color",
|
|
"value": {
|
|
"mode": "fixed",
|
|
"fixedColor": "#C4162A"
|
|
}
|
|
},
|
|
{
|
|
"id": "displayName",
|
|
"value": "Income Tax (cash pay)"
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"matcher": {
|
|
"id": "byName",
|
|
"options": "ni"
|
|
},
|
|
"properties": [
|
|
{
|
|
"id": "color",
|
|
"value": {
|
|
"mode": "fixed",
|
|
"fixedColor": "orange"
|
|
}
|
|
},
|
|
{
|
|
"id": "displayName",
|
|
"value": "National Insurance"
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"matcher": {
|
|
"id": "byName",
|
|
"options": "student_loan"
|
|
},
|
|
"properties": [
|
|
{
|
|
"id": "color",
|
|
"value": {
|
|
"mode": "fixed",
|
|
"fixedColor": "#8B4513"
|
|
}
|
|
},
|
|
{
|
|
"id": "displayName",
|
|
"value": "Student Loan"
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"matcher": {
|
|
"id": "byName",
|
|
"options": "pension_employee"
|
|
},
|
|
"properties": [
|
|
{
|
|
"id": "color",
|
|
"value": {
|
|
"mode": "fixed",
|
|
"fixedColor": "purple"
|
|
}
|
|
},
|
|
{
|
|
"id": "displayName",
|
|
"value": "Pension (employee)"
|
|
}
|
|
]
|
|
}
|
|
]
|
|
},
|
|
"options": {
|
|
"legend": {
|
|
"calcs": [
|
|
"last",
|
|
"max",
|
|
"sum"
|
|
],
|
|
"displayMode": "table",
|
|
"placement": "bottom"
|
|
},
|
|
"tooltip": {
|
|
"mode": "multi",
|
|
"sort": "desc"
|
|
}
|
|
},
|
|
"targets": [
|
|
{
|
|
"datasource": {
|
|
"type": "grafana-postgresql-datasource",
|
|
"uid": "payslips-pg"
|
|
},
|
|
"rawSql": "SELECT pay_date AS \"time\", COALESCE(cash_income_tax, income_tax) AS cash_income_tax, national_insurance AS ni, student_loan, pension_employee FROM payslip_ingest.payslip WHERE $__timeFilter(pay_date) ORDER BY pay_date",
|
|
"format": "time_series",
|
|
"refId": "A",
|
|
"rawQuery": true,
|
|
"editorMode": "code"
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"id": 4,
|
|
"title": "Data integrity \u2014 missing months & parser flags",
|
|
"type": "table",
|
|
"datasource": {
|
|
"type": "grafana-postgresql-datasource",
|
|
"uid": "payslips-pg"
|
|
},
|
|
"gridPos": {
|
|
"h": 6,
|
|
"w": 24,
|
|
"x": 0,
|
|
"y": 38
|
|
},
|
|
"fieldConfig": {
|
|
"defaults": {
|
|
"custom": {
|
|
"align": "right",
|
|
"cellOptions": {
|
|
"type": "auto"
|
|
},
|
|
"inspect": false
|
|
},
|
|
"thresholds": {
|
|
"mode": "absolute",
|
|
"steps": [
|
|
{
|
|
"color": "green",
|
|
"value": null
|
|
}
|
|
]
|
|
}
|
|
},
|
|
"overrides": [
|
|
{
|
|
"matcher": {
|
|
"id": "byName",
|
|
"options": "month_start"
|
|
},
|
|
"properties": [
|
|
{
|
|
"id": "custom.width",
|
|
"value": 120
|
|
},
|
|
{
|
|
"id": "custom.align",
|
|
"value": "left"
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"matcher": {
|
|
"id": "byName",
|
|
"options": "status"
|
|
},
|
|
"properties": [
|
|
{
|
|
"id": "custom.width",
|
|
"value": 140
|
|
},
|
|
{
|
|
"id": "custom.align",
|
|
"value": "center"
|
|
},
|
|
{
|
|
"id": "custom.cellOptions",
|
|
"value": {
|
|
"type": "color-background",
|
|
"mode": "basic"
|
|
}
|
|
},
|
|
{
|
|
"id": "mappings",
|
|
"value": [
|
|
{
|
|
"type": "value",
|
|
"options": {
|
|
"MISSING": {
|
|
"color": "red",
|
|
"index": 0,
|
|
"text": "MISSING"
|
|
},
|
|
"ZERO_SALARY": {
|
|
"color": "red",
|
|
"index": 1,
|
|
"text": "ZERO_SALARY"
|
|
},
|
|
"RSU_NO_SALARY": {
|
|
"color": "red",
|
|
"index": 2,
|
|
"text": "RSU_NO_SALARY"
|
|
},
|
|
"NULL_CASH_TAX": {
|
|
"color": "orange",
|
|
"index": 3,
|
|
"text": "NULL_CASH_TAX"
|
|
},
|
|
"ok": {
|
|
"color": "green",
|
|
"index": 4,
|
|
"text": "ok"
|
|
}
|
|
}
|
|
}
|
|
]
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"matcher": {
|
|
"id": "byName",
|
|
"options": "pay_date"
|
|
},
|
|
"properties": [
|
|
{
|
|
"id": "custom.width",
|
|
"value": 120
|
|
},
|
|
{
|
|
"id": "custom.align",
|
|
"value": "left"
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"matcher": {
|
|
"id": "byType",
|
|
"options": "number"
|
|
},
|
|
"properties": [
|
|
{
|
|
"id": "unit",
|
|
"value": "currencyGBP"
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"matcher": {
|
|
"id": "byName",
|
|
"options": "paperless_doc_id"
|
|
},
|
|
"properties": [
|
|
{
|
|
"id": "unit",
|
|
"value": "none"
|
|
},
|
|
{
|
|
"id": "custom.width",
|
|
"value": 100
|
|
}
|
|
]
|
|
}
|
|
]
|
|
},
|
|
"options": {
|
|
"cellHeight": "sm",
|
|
"footer": {
|
|
"show": false
|
|
}
|
|
},
|
|
"targets": [
|
|
{
|
|
"refId": "A",
|
|
"datasource": {
|
|
"type": "grafana-postgresql-datasource",
|
|
"uid": "payslips-pg"
|
|
},
|
|
"rawQuery": true,
|
|
"editorMode": "code",
|
|
"format": "table",
|
|
"rawSql": "WITH expected AS (SELECT generate_series(DATE '2019-07-01', DATE_TRUNC('month', CURRENT_DATE), '1 month'::interval)::date AS month_start), actual AS (SELECT DATE_TRUNC('month', pay_date)::date AS month_start, pay_date, salary, gross_pay, rsu_vest, cash_income_tax, income_tax, paperless_doc_id FROM payslip_ingest.payslip) SELECT e.month_start, CASE WHEN a.pay_date IS NULL THEN 'MISSING' WHEN a.salary = 0 AND a.gross_pay > 5000 THEN 'ZERO_SALARY' WHEN a.rsu_vest > 0 AND a.salary = 0 THEN 'RSU_NO_SALARY' WHEN a.rsu_vest > 0 AND a.cash_income_tax IS NULL THEN 'NULL_CASH_TAX' ELSE 'ok' END AS status, a.pay_date, a.salary, a.gross_pay, a.rsu_vest, a.cash_income_tax, a.paperless_doc_id FROM expected e LEFT JOIN actual a ON a.month_start = e.month_start WHERE e.month_start >= DATE '2019-07-01' ORDER BY e.month_start DESC"
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"id": 5,
|
|
"title": "All payslips \u2014 detailed breakdown",
|
|
"type": "table",
|
|
"datasource": {
|
|
"type": "grafana-postgresql-datasource",
|
|
"uid": "payslips-pg"
|
|
},
|
|
"gridPos": {
|
|
"h": 14,
|
|
"w": 24,
|
|
"x": 0,
|
|
"y": 44
|
|
},
|
|
"fieldConfig": {
|
|
"defaults": {
|
|
"custom": {
|
|
"align": "right",
|
|
"cellOptions": {
|
|
"type": "auto"
|
|
},
|
|
"inspect": true
|
|
},
|
|
"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": "employer"
|
|
},
|
|
"properties": [
|
|
{
|
|
"id": "custom.width",
|
|
"value": 150
|
|
},
|
|
{
|
|
"id": "custom.align",
|
|
"value": "left"
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"matcher": {
|
|
"id": "byName",
|
|
"options": "tax_year"
|
|
},
|
|
"properties": [
|
|
{
|
|
"id": "custom.width",
|
|
"value": 80
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"matcher": {
|
|
"id": "byName",
|
|
"options": "validated"
|
|
},
|
|
"properties": [
|
|
{
|
|
"id": "custom.width",
|
|
"value": 80
|
|
},
|
|
{
|
|
"id": "custom.cellOptions",
|
|
"value": {
|
|
"type": "color-text"
|
|
}
|
|
},
|
|
{
|
|
"id": "mappings",
|
|
"value": [
|
|
{
|
|
"type": "value",
|
|
"options": {
|
|
"true": {
|
|
"color": "green",
|
|
"text": "\u2713"
|
|
},
|
|
"false": {
|
|
"color": "red",
|
|
"text": "\u26a0"
|
|
}
|
|
}
|
|
}
|
|
]
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"matcher": {
|
|
"id": "byType",
|
|
"options": "number"
|
|
},
|
|
"properties": [
|
|
{
|
|
"id": "unit",
|
|
"value": "currencyGBP"
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"matcher": {
|
|
"id": "byName",
|
|
"options": "paperless_doc_id"
|
|
},
|
|
"properties": [
|
|
{
|
|
"id": "unit",
|
|
"value": "none"
|
|
},
|
|
{
|
|
"id": "custom.width",
|
|
"value": 80
|
|
}
|
|
]
|
|
}
|
|
]
|
|
},
|
|
"options": {
|
|
"footer": {
|
|
"show": true,
|
|
"reducer": [
|
|
"sum"
|
|
],
|
|
"fields": [
|
|
"gross_pay",
|
|
"net_pay",
|
|
"income_tax",
|
|
"national_insurance",
|
|
"pension_employee",
|
|
"pension_employer",
|
|
"student_loan"
|
|
]
|
|
}
|
|
},
|
|
"targets": [
|
|
{
|
|
"refId": "A",
|
|
"datasource": {
|
|
"type": "grafana-postgresql-datasource",
|
|
"uid": "payslips-pg"
|
|
},
|
|
"rawQuery": true,
|
|
"editorMode": "code",
|
|
"format": "table",
|
|
"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": 58
|
|
},
|
|
"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"
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"id": 8,
|
|
"title": "Sankey \u2014 where the money went",
|
|
"description": "Income sources flow into gross, then out to deductions and take-home. Aggregated over the selected time range (use the time picker to scope to a single tax year).",
|
|
"type": "netsage-sankey-panel",
|
|
"datasource": {
|
|
"type": "grafana-postgresql-datasource",
|
|
"uid": "payslips-pg"
|
|
},
|
|
"gridPos": {
|
|
"h": 14,
|
|
"w": 24,
|
|
"x": 0,
|
|
"y": 70
|
|
},
|
|
"options": {
|
|
"monochrome": false,
|
|
"monochromeColor": "#7294d4",
|
|
"showHeader": true,
|
|
"displayValues": "show",
|
|
"valueFormat": "currencyGBP",
|
|
"nodeWidth": 20,
|
|
"nodePadding": 15
|
|
},
|
|
"targets": [
|
|
{
|
|
"refId": "A",
|
|
"datasource": {
|
|
"type": "grafana-postgresql-datasource",
|
|
"uid": "payslips-pg"
|
|
},
|
|
"rawQuery": true,
|
|
"editorMode": "code",
|
|
"format": "table",
|
|
"rawSql": "WITH agg AS (SELECT COALESCE(SUM(salary), 0) AS salary, COALESCE(SUM(bonus), 0) AS bonus, COALESCE(SUM(rsu_vest), 0) AS rsu_vest, COALESCE(SUM(GREATEST(gross_pay - salary - bonus - rsu_vest, 0)), 0) AS other_income, COALESCE(SUM(net_pay), 0) AS net_pay, COALESCE(SUM(COALESCE(cash_income_tax, income_tax)), 0) AS cash_income_tax, COALESCE(SUM(income_tax - COALESCE(cash_income_tax, income_tax)), 0) AS rsu_income_tax, COALESCE(SUM(national_insurance), 0) AS ni, COALESCE(SUM(pension_employee), 0) AS pension, COALESCE(SUM(student_loan), 0) AS student_loan, COALESCE(SUM(rsu_offset), 0) AS rsu_offset FROM payslip_ingest.payslip WHERE $__timeFilter(pay_date)) SELECT 'Salary' AS source, 'Gross' AS target, salary AS value FROM agg WHERE salary > 0 UNION ALL SELECT 'Bonus', 'Gross', bonus FROM agg WHERE bonus > 0 UNION ALL SELECT 'RSU', 'Gross', rsu_vest FROM agg WHERE rsu_vest > 0 UNION ALL SELECT 'Other income', 'Gross', other_income FROM agg WHERE other_income > 0 UNION ALL SELECT 'Gross', 'Net pay', net_pay FROM agg WHERE net_pay > 0 UNION ALL SELECT 'Gross', 'Income Tax (cash)', cash_income_tax FROM agg WHERE cash_income_tax > 0 UNION ALL SELECT 'Gross', 'Income Tax (RSU)', rsu_income_tax FROM agg WHERE rsu_income_tax > 0 UNION ALL SELECT 'Gross', 'National Insurance', ni FROM agg WHERE ni > 0 UNION ALL SELECT 'Gross', 'Pension', pension FROM agg WHERE pension > 0 UNION ALL SELECT 'Gross', 'Student Loan', student_loan FROM agg WHERE student_loan > 0 UNION ALL SELECT 'Gross', 'RSU Offset', rsu_offset FROM agg WHERE rsu_offset > 0"
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"id": 9,
|
|
"title": "P60 reconciliation \u2014 HMRC annual vs summed payslips",
|
|
"description": "Per-tax-year comparison of the figures HMRC printed on the P60 vs what we summed from individual payslips. Delta columns: |\u0394|<1 green (exact match), 1-50 yellow (rounding), >50 red (missing month or parser drift). Always shows all years \u2014 ignores the time picker.",
|
|
"type": "table",
|
|
"datasource": {
|
|
"type": "grafana-postgresql-datasource",
|
|
"uid": "payslips-pg"
|
|
},
|
|
"gridPos": {
|
|
"h": 10,
|
|
"w": 24,
|
|
"x": 0,
|
|
"y": 84
|
|
},
|
|
"fieldConfig": {
|
|
"defaults": {
|
|
"unit": "currencyGBP",
|
|
"custom": {
|
|
"align": "right",
|
|
"displayMode": "auto"
|
|
}
|
|
},
|
|
"overrides": [
|
|
{
|
|
"matcher": {
|
|
"id": "byRegexp",
|
|
"options": "^delta_"
|
|
},
|
|
"properties": [
|
|
{
|
|
"id": "custom.displayMode",
|
|
"value": "color-background"
|
|
},
|
|
{
|
|
"id": "custom.cellOptions",
|
|
"value": {
|
|
"type": "color-background",
|
|
"mode": "gradient"
|
|
}
|
|
},
|
|
{
|
|
"id": "thresholds",
|
|
"value": {
|
|
"mode": "absolute",
|
|
"steps": [
|
|
{
|
|
"color": "green",
|
|
"value": null
|
|
},
|
|
{
|
|
"color": "green",
|
|
"value": -1
|
|
},
|
|
{
|
|
"color": "yellow",
|
|
"value": 1
|
|
},
|
|
{
|
|
"color": "red",
|
|
"value": 50
|
|
},
|
|
{
|
|
"color": "red",
|
|
"value": -50
|
|
}
|
|
]
|
|
}
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"matcher": {
|
|
"id": "byName",
|
|
"options": "tax_year"
|
|
},
|
|
"properties": [
|
|
{
|
|
"id": "unit",
|
|
"value": "string"
|
|
},
|
|
{
|
|
"id": "custom.align",
|
|
"value": "left"
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"matcher": {
|
|
"id": "byName",
|
|
"options": "employer"
|
|
},
|
|
"properties": [
|
|
{
|
|
"id": "unit",
|
|
"value": "string"
|
|
},
|
|
{
|
|
"id": "custom.align",
|
|
"value": "left"
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"matcher": {
|
|
"id": "byName",
|
|
"options": "tax_code"
|
|
},
|
|
"properties": [
|
|
{
|
|
"id": "unit",
|
|
"value": "string"
|
|
},
|
|
{
|
|
"id": "custom.align",
|
|
"value": "left"
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"matcher": {
|
|
"id": "byName",
|
|
"options": "paperless_doc_id"
|
|
},
|
|
"properties": [
|
|
{
|
|
"id": "unit",
|
|
"value": "none"
|
|
},
|
|
{
|
|
"id": "custom.align",
|
|
"value": "left"
|
|
}
|
|
]
|
|
}
|
|
]
|
|
},
|
|
"options": {
|
|
"showHeader": true,
|
|
"cellHeight": "sm",
|
|
"footer": {
|
|
"show": false
|
|
}
|
|
},
|
|
"targets": [
|
|
{
|
|
"refId": "A",
|
|
"datasource": {
|
|
"type": "grafana-postgresql-datasource",
|
|
"uid": "payslips-pg"
|
|
},
|
|
"rawQuery": true,
|
|
"editorMode": "code",
|
|
"format": "table",
|
|
"rawSql": "SELECT p.tax_year, p.employer, p.gross_pay AS p60_gross, c.sum_gross AS computed_gross, (p.gross_pay - c.sum_gross) AS delta_gross, p.income_tax AS p60_tax, c.sum_tax AS computed_tax, (p.income_tax - c.sum_tax) AS delta_tax, p.national_insurance AS p60_ni, c.sum_ni AS computed_ni, (p.national_insurance - c.sum_ni) AS delta_ni, p.tax_code, p.paperless_doc_id FROM payslip_ingest.p60_reference p LEFT JOIN LATERAL (SELECT COALESCE(SUM(gross_pay), 0) AS sum_gross, COALESCE(SUM(income_tax), 0) AS sum_tax, COALESCE(SUM(national_insurance), 0) AS sum_ni FROM payslip_ingest.payslip WHERE tax_year = p.tax_year) c ON true ORDER BY p.tax_year DESC"
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"id": 10,
|
|
"title": "HMRC Tax Year Reconciliation \u2014 Individual Tax API",
|
|
"description": "Latest snapshot from HMRC Individual Tax API v1.1 vs SUM(payslip.income_tax) per tax year. Delta > \u00a310 turns red \u2014 that's parser drift vs HMRC's held figures, the authoritative ground truth. Shown only for years where hmrc-sync has pulled a snapshot.",
|
|
"type": "table",
|
|
"datasource": {
|
|
"type": "grafana-postgresql-datasource",
|
|
"uid": "payslips-pg"
|
|
},
|
|
"gridPos": {
|
|
"h": 10,
|
|
"w": 24,
|
|
"x": 0,
|
|
"y": 94
|
|
},
|
|
"fieldConfig": {
|
|
"defaults": {
|
|
"unit": "currencyGBP",
|
|
"custom": {
|
|
"align": "right",
|
|
"displayMode": "auto"
|
|
}
|
|
},
|
|
"overrides": [
|
|
{
|
|
"matcher": {
|
|
"id": "byRegexp",
|
|
"options": "^delta_"
|
|
},
|
|
"properties": [
|
|
{
|
|
"id": "custom.displayMode",
|
|
"value": "color-background"
|
|
},
|
|
{
|
|
"id": "thresholds",
|
|
"value": {
|
|
"mode": "absolute",
|
|
"steps": [
|
|
{
|
|
"color": "green",
|
|
"value": null
|
|
},
|
|
{
|
|
"color": "green",
|
|
"value": -10
|
|
},
|
|
{
|
|
"color": "red",
|
|
"value": 10
|
|
},
|
|
{
|
|
"color": "red",
|
|
"value": -10
|
|
}
|
|
]
|
|
}
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"matcher": {
|
|
"id": "byName",
|
|
"options": "tax_year"
|
|
},
|
|
"properties": [
|
|
{
|
|
"id": "unit",
|
|
"value": "string"
|
|
},
|
|
{
|
|
"id": "custom.align",
|
|
"value": "left"
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"matcher": {
|
|
"id": "byName",
|
|
"options": "employer_paye_ref"
|
|
},
|
|
"properties": [
|
|
{
|
|
"id": "unit",
|
|
"value": "string"
|
|
},
|
|
{
|
|
"id": "custom.align",
|
|
"value": "left"
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"matcher": {
|
|
"id": "byName",
|
|
"options": "snapshot_date"
|
|
},
|
|
"properties": [
|
|
{
|
|
"id": "unit",
|
|
"value": "dateTimeAsIso"
|
|
}
|
|
]
|
|
}
|
|
]
|
|
},
|
|
"options": {
|
|
"showHeader": true,
|
|
"cellHeight": "sm",
|
|
"footer": {
|
|
"show": false
|
|
}
|
|
},
|
|
"targets": [
|
|
{
|
|
"refId": "A",
|
|
"datasource": {
|
|
"type": "grafana-postgresql-datasource",
|
|
"uid": "payslips-pg"
|
|
},
|
|
"rawQuery": true,
|
|
"editorMode": "code",
|
|
"format": "table",
|
|
"rawSql": "WITH latest AS (SELECT DISTINCT ON (tax_year, employer_paye_ref) tax_year, employer_paye_ref, snapshot_date, gross_pay, income_tax, ni_contributions FROM hmrc_sync.tax_year_snapshot ORDER BY tax_year, employer_paye_ref, snapshot_date DESC), summed AS (SELECT tax_year, COALESCE(SUM(gross_pay), 0) AS sum_gross, COALESCE(SUM(income_tax), 0) AS sum_tax, COALESCE(SUM(national_insurance), 0) AS sum_ni FROM payslip_ingest.payslip GROUP BY tax_year) SELECT l.tax_year, l.employer_paye_ref, l.snapshot_date, l.gross_pay AS hmrc_gross, s.sum_gross AS computed_gross, (l.gross_pay - s.sum_gross) AS delta_gross, l.income_tax AS hmrc_tax, s.sum_tax AS computed_tax, (l.income_tax - s.sum_tax) AS delta_tax, l.ni_contributions AS hmrc_ni, s.sum_ni AS computed_ni, (l.ni_contributions - s.sum_ni) AS delta_ni FROM latest l LEFT JOIN summed s ON s.tax_year = l.tax_year ORDER BY l.tax_year DESC"
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"id": 14,
|
|
"title": "Meta payroll: bank deposit vs payslip net pay",
|
|
"description": "Cross-check between ActualBudget bank deposits (META/FACEBOOK payee) and payslip net_pay. |delta| > \u00a350 flags likely parser or bank-sync drift. Synced daily 02:00 UTC.",
|
|
"type": "timeseries",
|
|
"datasource": {
|
|
"type": "grafana-postgresql-datasource",
|
|
"uid": "payslips-pg"
|
|
},
|
|
"gridPos": {
|
|
"h": 9,
|
|
"w": 24,
|
|
"x": 0,
|
|
"y": 160
|
|
},
|
|
"fieldConfig": {
|
|
"defaults": {
|
|
"color": {
|
|
"mode": "palette-classic"
|
|
},
|
|
"unit": "currencyGBP",
|
|
"custom": {
|
|
"axisPlacement": "auto",
|
|
"drawStyle": "line",
|
|
"fillOpacity": 0,
|
|
"lineWidth": 2,
|
|
"pointSize": 6,
|
|
"showPoints": "always",
|
|
"spanNulls": false,
|
|
"thresholdsStyle": {
|
|
"mode": "off"
|
|
}
|
|
}
|
|
},
|
|
"overrides": [
|
|
{
|
|
"matcher": {
|
|
"id": "byName",
|
|
"options": "deposit_sum"
|
|
},
|
|
"properties": [
|
|
{
|
|
"id": "color",
|
|
"value": {
|
|
"mode": "fixed",
|
|
"fixedColor": "green"
|
|
}
|
|
},
|
|
{
|
|
"id": "displayName",
|
|
"value": "Bank deposit (ActualBudget)"
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"matcher": {
|
|
"id": "byName",
|
|
"options": "payslip_net_pay"
|
|
},
|
|
"properties": [
|
|
{
|
|
"id": "color",
|
|
"value": {
|
|
"mode": "fixed",
|
|
"fixedColor": "blue"
|
|
}
|
|
},
|
|
{
|
|
"id": "displayName",
|
|
"value": "Payslip net pay"
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"matcher": {
|
|
"id": "byName",
|
|
"options": "delta"
|
|
},
|
|
"properties": [
|
|
{
|
|
"id": "color",
|
|
"value": {
|
|
"mode": "fixed",
|
|
"fixedColor": "red"
|
|
}
|
|
},
|
|
{
|
|
"id": "displayName",
|
|
"value": "Delta (deposit \u2212 payslip)"
|
|
},
|
|
{
|
|
"id": "custom.drawStyle",
|
|
"value": "bars"
|
|
}
|
|
]
|
|
}
|
|
]
|
|
},
|
|
"options": {
|
|
"legend": {
|
|
"calcs": [
|
|
"last"
|
|
],
|
|
"displayMode": "table",
|
|
"placement": "bottom"
|
|
},
|
|
"tooltip": {
|
|
"mode": "multi",
|
|
"sort": "desc"
|
|
}
|
|
},
|
|
"targets": [
|
|
{
|
|
"datasource": {
|
|
"type": "grafana-postgresql-datasource",
|
|
"uid": "payslips-pg"
|
|
},
|
|
"rawSql": "WITH deposits AS (SELECT DATE_TRUNC('month', deposit_date)::date AS month_start, SUM(amount) AS deposit_sum FROM payslip_ingest.external_meta_deposits GROUP BY 1), payslip_net AS (SELECT DATE_TRUNC('month', pay_date)::date AS month_start, SUM(net_pay) AS payslip_net_pay FROM payslip_ingest.payslip GROUP BY 1) SELECT COALESCE(p.month_start, d.month_start) AS \"time\", d.deposit_sum, p.payslip_net_pay, COALESCE(d.deposit_sum, 0) - COALESCE(p.payslip_net_pay, 0) AS delta FROM deposits d FULL OUTER JOIN payslip_net p ON p.month_start = d.month_start WHERE $__timeFilter(COALESCE(p.month_start, d.month_start)) ORDER BY \"time\"",
|
|
"format": "time_series",
|
|
"refId": "A",
|
|
"rawQuery": true,
|
|
"editorMode": "code"
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"id": 15,
|
|
"title": "RSU vest reconciliation \u2014 payslip vs Schwab",
|
|
"description": "Per-vest-month join between payslip.rsu_vest (what HMRC reporting shows) and Schwab's vest-confirmation email data (what actually happened at the broker). Empty rows until the broker-sync IMAP ingest runs and VestEvents are persisted.",
|
|
"type": "table",
|
|
"datasource": {
|
|
"type": "grafana-postgresql-datasource",
|
|
"uid": "payslips-pg"
|
|
},
|
|
"gridPos": {
|
|
"h": 10,
|
|
"w": 24,
|
|
"x": 0,
|
|
"y": 169
|
|
},
|
|
"fieldConfig": {
|
|
"defaults": {
|
|
"custom": {
|
|
"align": "right",
|
|
"cellOptions": {
|
|
"type": "auto"
|
|
},
|
|
"inspect": false
|
|
},
|
|
"unit": "currencyGBP",
|
|
"thresholds": {
|
|
"mode": "absolute",
|
|
"steps": [
|
|
{
|
|
"color": "green",
|
|
"value": null
|
|
}
|
|
]
|
|
}
|
|
},
|
|
"overrides": [
|
|
{
|
|
"matcher": {
|
|
"id": "byName",
|
|
"options": "vest_month"
|
|
},
|
|
"properties": [
|
|
{
|
|
"id": "custom.width",
|
|
"value": 140
|
|
},
|
|
{
|
|
"id": "custom.align",
|
|
"value": "left"
|
|
},
|
|
{
|
|
"id": "unit",
|
|
"value": "none"
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"matcher": {
|
|
"id": "byName",
|
|
"options": "ticker"
|
|
},
|
|
"properties": [
|
|
{
|
|
"id": "custom.width",
|
|
"value": 80
|
|
},
|
|
{
|
|
"id": "unit",
|
|
"value": "none"
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"matcher": {
|
|
"id": "byName",
|
|
"options": "shares_vested"
|
|
},
|
|
"properties": [
|
|
{
|
|
"id": "unit",
|
|
"value": "none"
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"matcher": {
|
|
"id": "byName",
|
|
"options": "tax_delta_pct"
|
|
},
|
|
"properties": [
|
|
{
|
|
"id": "unit",
|
|
"value": "percent"
|
|
},
|
|
{
|
|
"id": "custom.cellOptions",
|
|
"value": {
|
|
"type": "color-background",
|
|
"mode": "basic"
|
|
}
|
|
},
|
|
{
|
|
"id": "thresholds",
|
|
"value": {
|
|
"mode": "absolute",
|
|
"steps": [
|
|
{
|
|
"color": "green",
|
|
"value": null
|
|
},
|
|
{
|
|
"color": "orange",
|
|
"value": 2
|
|
},
|
|
{
|
|
"color": "red",
|
|
"value": 5
|
|
}
|
|
]
|
|
}
|
|
}
|
|
]
|
|
}
|
|
]
|
|
},
|
|
"options": {
|
|
"cellHeight": "sm",
|
|
"footer": {
|
|
"show": false
|
|
}
|
|
},
|
|
"targets": [
|
|
{
|
|
"refId": "A",
|
|
"datasource": {
|
|
"type": "grafana-postgresql-datasource",
|
|
"uid": "payslips-pg"
|
|
},
|
|
"rawQuery": true,
|
|
"editorMode": "code",
|
|
"format": "table",
|
|
"rawSql": "WITH vest_by_month AS (SELECT DATE_TRUNC('month', vest_date)::date AS vest_month, ticker, SUM(shares_vested) AS shares_vested, SUM(gross_value_gbp) AS broker_gross_gbp, SUM(tax_withheld_gbp) AS broker_tax_gbp FROM payslip_ingest.rsu_vest_events GROUP BY 1, 2), payslip_by_month AS (SELECT DATE_TRUNC('month', pay_date)::date AS vest_month, SUM(rsu_vest) AS payslip_rsu_gbp, SUM(income_tax - COALESCE(cash_income_tax, income_tax)) AS payslip_rsu_tax_gbp FROM payslip_ingest.payslip WHERE rsu_vest > 0 GROUP BY 1) SELECT COALESCE(v.vest_month, p.vest_month) AS vest_month, v.ticker, v.shares_vested, v.broker_gross_gbp, p.payslip_rsu_gbp, (p.payslip_rsu_gbp - v.broker_gross_gbp) AS gross_delta_gbp, v.broker_tax_gbp, p.payslip_rsu_tax_gbp, (p.payslip_rsu_tax_gbp - v.broker_tax_gbp) AS tax_delta_gbp, CASE WHEN v.broker_tax_gbp IS NULL OR v.broker_tax_gbp = 0 THEN NULL ELSE ABS(p.payslip_rsu_tax_gbp - v.broker_tax_gbp) * 100.0 / v.broker_tax_gbp END AS tax_delta_pct FROM vest_by_month v FULL OUTER JOIN payslip_by_month p ON p.vest_month = v.vest_month ORDER BY vest_month DESC"
|
|
}
|
|
]
|
|
}
|
|
],
|
|
"refresh": "5m",
|
|
"schemaVersion": 39,
|
|
"tags": [
|
|
"finance",
|
|
"personal",
|
|
"uk-tax"
|
|
],
|
|
"templating": {
|
|
"list": []
|
|
},
|
|
"time": {
|
|
"from": "now-10y",
|
|
"to": "now"
|
|
},
|
|
"timepicker": {},
|
|
"timezone": "browser",
|
|
"title": "UK Payslip",
|
|
"uid": "uk-payslip",
|
|
"version": 1
|
|
} |