3.1 KiB
type, cluster, universe, status, entity
| type | cluster | universe | status | entity |
|---|---|---|---|---|
| object | money | live | verified | app/models/earnings_summary.rb |
EarningsSummary
A plain Ruby object (not an Active Record model) that totals a portfolio's earnings by reason for the "where did my money come from" panel.
Verified 2026-08-16 against commit 63732df.
Why this shape
It lives in app/models/ but has no table and no superclass
(app/models/earnings_summary.rb:3). It wraps a portfolio and runs one grouped sum per
reason (:36-41) — five queries per render, deliberately simple rather than a single
grouped query, because it is only ever built for one student at a time.
Known defect — transaction_fees_cents always returns 0. sum_by_reason filters
.deposits, i.e. transaction_type: :deposit (:38), but fee rows are written with
transaction_type: :fee by TransactionFeeProcessor
(app/services/transaction_fee_processor.rb:26-29). The two never intersect, so
transaction_fees_cents (:30-32) sums an empty set. It is rendered to students as
"Transaction Fees" at app/views/portfolios/_earnings_summary_card.html.erb:22, where it
always shows $0.00. The fix is to drop .deposits for that one reason — but note that
total_earnings_cents (:26-28) deliberately excludes fees, so changing sum_by_reason
wholesale would alter the total too.
Shape
- PORO;
initialize(portfolio)(:6-8) - Readers, all in cents:
attendance_earnings_cents,reading_earnings_cents,math_earnings_cents,awards_cents,total_earnings_cents,transaction_fees_cents(:10-32) total_earnings_cents= attendance + reading + math + awards (:26-28). Fees are not subtracted.- No caching, no memoization — each reader hits the database
It covers four of the seven reason values. administrative_adjustments and
transaction_fees are not part of the total; grade_earnings is leftover.
Connected to
- owns: —
- owned-by: portfolio (by construction, not by association)
- joins: reads portfolio-transaction
- looks-like-but-is-not: not an Active Record model —
EarningsSummary.findand any scope or callback do not exist. It also is not the balance: it counts income only and ignores debits, credits, and withdrawals entirely.
If you change this
- Hits:
PortfoliosController#show(app/controllers/portfolios_controller.rb:10) andAdmin::StudentsController#show(app/controllers/admin/students_controller.rb:21); the two views that render it —app/views/portfolios/_earnings_summary_card.html.erbandapp/views/admin/students/show.html.erb:85-100. - Does not hit: portfolio
#cash_balance. This class is read-only and entirely parallel to the balance calculation — correcting the fee bug here changes a displayed figure, not anyone's spendable money.
Surfaces
| Surface | Role |
|---|---|
PortfoliosController#show |
student/teacher read |
Admin::StudentsController#show |
admin read |
See
- Source:
app/models/earnings_summary.rb