Operator guideENdashboardliabilitywalletscalculated

Dashboard / Player Liability

Currency-level liability snapshot with frontend summary cards for total, positive, negative, and currency-count exposure.

Reader view

Clean portal guidance

This page keeps the operator explanation, field and action descriptions, and screenshots visible without exposing repo paths, raw sidecars, or editorial-only implementation details.

Narrative content

Page body

What this widget shows

Player Liability shows current liability grouped by currency and then summarizes that result into four cards:

  • Total Liability
  • Positive Liability
  • Negative Liability
  • Currency Count

Use it when you need a quick exposure snapshot across wallet currencies.

How to read it

The table itself is a currency list. Each row shows:

  • the currency code
  • the liability amount for that currency

The backend SQL also returns a visible Total rollup row in the table. The summary cards do not use that row.

The summary cards above the table are calculated in the frontend from the returned row set.

What the summary cards mean

  • Total Liability: sum of all displayed currency liabilities
  • Positive Liability: sum of liabilities greater than zero
  • Negative Liability: sum of liabilities below zero
  • Currency Count: number of currency rows included in the calculation

Common questions

Why is there no row named Total in the summary cards?

Because the frontend explicitly removes the backend row where currencyCode === 'Total' before calculating the summary cards.

Why do the date filters not seem to change the result?

Because the current backend implementation loads a wallet-liability SQL snapshot and only applies the isStreamerData filter. The selected date range is validated in the service layer but is not injected into the SQL query.

Why can I not change the date option on the mounted dashboard?

Because the current backoffice widget does not render a date-option selector. The hook still sends dateOptions=last7days plus default dates, but the mounted dashboard only exposes:

  • Streamer data
  • Download CSV
  • Refresh data

For practical use, treat this widget as a current liability snapshot, not a historical liability timeline.

What is being summed in the backend?

The backend SQL sums wallet amounts by currency and normalizes them by exchange rate before grouping.

What currency are the money cards in, and which rate is used?

The money values (Total Liability, Positive Liability, Negative Liability) are expressed in the reporting currency, EUR — the currency flagged as primary in the currencies table, which carries an exchange rate of 1.

Each currency row is converted in the backend SQL as wallet.amount / exchange_rate, where exchange_rate comes from the currencies reference table joined on the currency code.

Two things to keep in mind:

  • Current-rate basis, not transaction-time. The conversion uses the single, admin-maintained rate currently stored per currency. Wallets only store an amount and a currency code, so there is no rate captured at the time each balance was created. The whole liability is re-stated at today's stored rate, and the total will move whenever an operator changes a currency's exchange rate.
  • Missing or zero rate falls back to 1. If a currency's exchange_rate is 0 or empty, the conversion divides by 1 instead. That means the raw foreign amount is added into the EUR total with no conversion, which can over- or under-state that currency's contribution. This is not shown in the card label.

Known caveats

  • The date UI suggests a historical filter, but the current backend SQL does not use the selected dates.
  • The mounted dashboard does not expose a date-option selector, so the custom-date branch is currently unreachable.
  • Summary cards are frontend-derived from the returned currency rows.
  • The backend also returns a Total rollup row, but the frontend excludes it from the summary-card calculation.
Operator actions

Screen actions

action

Streamer data

Re-runs the widget using only streamer-tagged users when enabled.

action

Download CSV

Downloads the current liability dataset through the same backend route with `csvDownload=true`.

action

Refresh data

Re-runs the widget with the current mounted filter state.

Operational notes

Notes

item

A custom-date `Apply Filters` button exists in code behind an unreachable branch because the mounted widget does not expose a date-option selector.

Calculation notes

Frontend calculations

calculation

filtered_rows

Remove any row where currencyCode equals Total before calculating summary cards.

calculation

total_liability

Formula
sum(filtered_rows.liability)
calculation

positive_liability_total

Formula
sum(liability where liability > 0)
calculation

negative_liability_total

Formula
sum(liability where liability < 0)
calculation

currency_count

Formula
count(filtered_rows)
Filter dictionary

Filters

field

Streamer data

Restricts the snapshot to streamer-tagged users only.

Type
boolean
Summary cards

Summary cards

field

Total Liability

field

Positive Liability

field

Negative Liability

field

Currency Count

Metric dictionary

Metrics

metric

Total Liability

Frontend-derived sum of all displayed currency liabilities after excluding the backend `Total` row.

Aliases
player liability total, total liability
Currency Basis
Reporting Currency: EUR -- the currencies.is_primary currency, seeded with exchange_rate = 1 | Conversion: Backend SQL converts each currency before summing as SUM(wallet.amount / COALESCE(NULLIF(currencies.exchange_rate, 0), 1)); each foreign wallet amount is divided by that currency exchange_rate to express liability in the reporting currency. | Rate Source: currencies.exchange_rate (Sequelize model field exchangeRate), joined by wallets.currency_code = currencies.code | Rate Timing: Current snapshot. The single admin-maintained per-currency rate stored on the currencies reference table is read at query time; it is not a transaction-time or booking rate. Wallets store only amount and currency_code, so all liability is remeasured at the current stored rate. | Missing Rate Fallback: If exchange_rate is 0 or NULL, NULLIF/COALESCE makes the divisor 1, so the raw foreign amount is summed 1:1 with no conversion (can over- or under-state that currency contribution).
Verification Sources
GET /api/admin/get-players-liability
Verification Status
verified_backend
Last Verified At
2026-06-29
metric

Positive Liability

Frontend-derived sum of returned liability rows with a positive value, after excluding the backend `Total` row.

Aliases
positive liability
Currency Basis
Reporting Currency: EUR -- the currencies.is_primary currency, seeded with exchange_rate = 1 | Conversion: Operates on already-converted per-currency rows. Backend SQL converts each currency as SUM(wallet.amount / COALESCE(NULLIF(currencies.exchange_rate, 0), 1)) before the frontend filters positive rows. | Rate Source: currencies.exchange_rate (Sequelize model field exchangeRate), joined by wallets.currency_code = currencies.code | Rate Timing: Current snapshot. The single admin-maintained per-currency rate stored on the currencies reference table is read at query time; it is not a transaction-time or booking rate. | Missing Rate Fallback: If exchange_rate is 0 or NULL, NULLIF/COALESCE makes the divisor 1, so the raw foreign amount is treated 1:1 with no conversion.
Verification Sources
GET /api/admin/get-players-liability
Verification Status
verified_backend
Last Verified At
2026-06-29
metric

Negative Liability

Frontend-derived sum of returned liability rows below zero, after excluding the backend `Total` row.

Aliases
negative liability
Currency Basis
Reporting Currency: EUR -- the currencies.is_primary currency, seeded with exchange_rate = 1 | Conversion: Operates on already-converted per-currency rows. Backend SQL converts each currency as SUM(wallet.amount / COALESCE(NULLIF(currencies.exchange_rate, 0), 1)) before the frontend filters negative rows. | Rate Source: currencies.exchange_rate (Sequelize model field exchangeRate), joined by wallets.currency_code = currencies.code | Rate Timing: Current snapshot. The single admin-maintained per-currency rate stored on the currencies reference table is read at query time; it is not a transaction-time or booking rate. | Missing Rate Fallback: If exchange_rate is 0 or NULL, NULLIF/COALESCE makes the divisor 1, so the raw foreign amount is treated 1:1 with no conversion.
Verification Sources
GET /api/admin/get-players-liability
Verification Status
verified_backend
Last Verified At
2026-06-29
metric

Currency Count

Frontend-derived count of currency rows included in the card calculation, excluding the backend `Total` row.

Aliases
liability currency count, currency count
Verification Sources
GET /api/admin/get-players-liability
Verification Status
verified_backend
Last Verified At
2026-06-29
Operational notes

Notes

item

Backend uses isStreamerData in SQL replacements.

item

Backend validates date filters but does not inject them into the current SQL query.

item

The mounted dashboard does not render a date-option selector even though the hook still sends `dateOptions`, `startDate`, and `endDate`.

item

CSV is returned by the same controller path as a direct file attachment when `csvDownload=true`.

Related references

Related pages

pageDashboard / Bonus Payouts

Shared comparison widget rendered for tournament, challenge, and no-deposit bonus payout groups.

pageDashboard / Game Reports

Deep comparison widget for Games and Providers with separate backend paths, multiple grouping options, search, and a mix of backend and frontend summary logic.

pageDashboard / GGR Chart

Revenue trend chart with frontend summary cards derived from the loaded time series.

pageDashboard / KPI Reports

Sortable KPI table for games or providers, used to compare betting and GGR-style metrics by entity rather than by time bucket.

pageDashboard / KPI Summary

Comparison table for high-level KPI rows across today, yesterday, month-to-date, and the selected period, with frontend trend chips and data-source badges.

pageDashboard / Live Player Report

Card-based snapshot of today's GGR, total players, conversion rates, active players, and merchant balance.