feat(admin): per-user finance panel — balances, benefits, risk, ledger
CI / changes (pull_request) Successful in 4s
CI / unit (pull_request) Successful in 11s
CI / integration (pull_request) Successful in 28s
CI / ui (pull_request) Has been skipped
CI / conformance (pull_request) Successful in 10s
CI / gate (pull_request) Successful in 0s
CI / deploy (pull_request) Successful in 1m46s
CI / changes (pull_request) Successful in 4s
CI / unit (pull_request) Successful in 11s
CI / integration (pull_request) Successful in 28s
CI / ui (pull_request) Has been skipped
CI / conformance (pull_request) Successful in 10s
CI / gate (pull_request) Successful in 0s
CI / deploy (pull_request) Successful in 1m46s
The /_gm user card gains a Finance panel: an account's chip balances per funding segment, benefits per origin (hints, no-ads until/forever), the recorded refund risk (abuse flag + floor-0 loss), and the append-only ledger history newest-first. Backed by a new payments.AccountStatement read straight from the materialized tables + the ledger (uncached — an admin, rare view). Folds the agreed admin / reports / catalog plan into PLAN.md (the PR stack: this panel, then the catalog editor, admin grant, refund + ledger export) and moves the tournament-entry storage design to the tournament stage.
This commit is contained in:
@@ -63,6 +63,28 @@
|
||||
<div><button type="submit">{{if .Suspension.Blocked}}Re-block{{else}}Block{{end}}</button></div>
|
||||
</form>
|
||||
</section>
|
||||
<section class="panel"><h2>Finance</h2>
|
||||
{{if .Finance.Present}}
|
||||
{{if or .Finance.Segments .Finance.Benefits .Finance.Abuse .Finance.Loss}}
|
||||
<ul class="kv">
|
||||
{{range .Finance.Segments}}<li><b>Chips ({{.Source}})</b> {{.Chips}}</li>{{end}}
|
||||
{{range .Finance.Benefits}}<li><b>Benefits ({{.Origin}})</b> {{.Hints}} hints{{if .Forever}} · no-ads forever{{else if .AdsUntil}} · no-ads until {{.AdsUntil}} (UTC){{end}}</li>{{end}}
|
||||
{{if or .Finance.Abuse .Finance.Loss}}<li><b>Refund risk</b> <span class="warn">{{if .Finance.Abuse}}abuse-flagged{{end}}{{if .Finance.Loss}} · loss {{.Finance.Loss}} chips{{end}}</span></li>{{end}}
|
||||
</ul>
|
||||
{{else}}<p class="note">no balances or benefits</p>{{end}}
|
||||
<h3>Ledger</h3>
|
||||
{{if .Finance.Ledger}}
|
||||
<table class="list">
|
||||
<thead><tr><th>Time</th><th>Kind</th><th>Source</th><th>Origin</th><th>Chips</th><th>Order</th><th>Provider</th><th>Detail</th></tr></thead>
|
||||
<tbody>
|
||||
{{range .Finance.Ledger}}
|
||||
<tr><td>{{.At}}</td><td>{{.Kind}}</td><td>{{.Source}}</td><td>{{.Origin}}</td><td>{{.ChipsDelta}}</td><td>{{if .Order}}<code>{{.Order}}</code>{{end}}</td><td>{{.Provider}}</td><td>{{if .Snapshot}}<code>{{.Snapshot}}</code>{{end}}</td></tr>
|
||||
{{end}}
|
||||
</tbody>
|
||||
</table>
|
||||
{{else}}<p class="note">no ledger entries</p>{{end}}
|
||||
{{else}}<p class="note">payments not enabled</p>{{end}}
|
||||
</section>
|
||||
<section class="panel"><h2>Roles</h2>
|
||||
{{$id := .ID}}
|
||||
{{if .Roles}}
|
||||
|
||||
@@ -195,6 +195,52 @@ type UserDetailView struct {
|
||||
Blocks []RelationRow
|
||||
BlockedBy []RelationRow
|
||||
Friends []RelationRow
|
||||
// Finance is the account's payments picture (balances, benefits, refund risk, ledger). Present
|
||||
// is false when the payments domain is unwired.
|
||||
Finance FinanceView
|
||||
}
|
||||
|
||||
// FinanceView is the account's payments picture on the user card: chip balances per funding
|
||||
// segment, benefits per origin, the recorded refund risk, and the append-only ledger history
|
||||
// (newest first). Present is false when the payments domain is unwired.
|
||||
type FinanceView struct {
|
||||
Present bool
|
||||
Segments []SegmentRow
|
||||
Benefits []BenefitRow
|
||||
// Abuse is the refund abuse flag; Loss is the unrecoverable chip loss from floor-0 refunds.
|
||||
Abuse bool
|
||||
Loss int
|
||||
Ledger []LedgerRow
|
||||
}
|
||||
|
||||
// SegmentRow is one funding segment's chip balance.
|
||||
type SegmentRow struct {
|
||||
Source string
|
||||
Chips int
|
||||
}
|
||||
|
||||
// BenefitRow is one origin's benefit: the hint wallet, the ad-free expiry (pre-formatted, empty
|
||||
// when none) and the lifetime ad-free flag.
|
||||
type BenefitRow struct {
|
||||
Origin string
|
||||
Hints int
|
||||
AdsUntil string
|
||||
Forever bool
|
||||
}
|
||||
|
||||
// LedgerRow is one append-only ledger entry: its kind, funding source / benefit origin, signed chip
|
||||
// delta, the product / order / provider it references (empty when none), the raw snapshot JSON and
|
||||
// the pre-formatted time.
|
||||
type LedgerRow struct {
|
||||
Kind string
|
||||
Source string
|
||||
Origin string
|
||||
ChipsDelta int
|
||||
Product string
|
||||
Order string
|
||||
Provider string
|
||||
Snapshot string
|
||||
At string
|
||||
}
|
||||
|
||||
// RelationRow is one cross-linked account in the user card's blocks / blocked-by / friends
|
||||
|
||||
Reference in New Issue
Block a user