Skip to content

fix(dashboard): money tiles match finance (QA-17, QA-18) - #1205

Merged
waritctd merged 5 commits into
developfrom
fix/dashboard-money-matches-finance
Oct 29, 2026
Merged

waritctd merged 5 commits into
developfrom
fix/dashboard-money-matches-finance

Conversation

@waritctd

@waritctd waritctd commented Oct 29, 2026 •

Copy link
Copy Markdown
Owner

P2 batch 2 from the sales-pipeline UI walks. The account, CEO and sales-manager dashboards each used their own money rules, and none matched /finance. Each tile now follows a definition Ploy ruled on 2026-10-29.

Rulings

Tile Before Now
Account รอรับมัดจำ Whole-deal balance (฿213,545.25) Deposit due: the latest ISSUED deposit notice's total_payable (฿85,418.10). New TicketSummaryDto.depositDue, hidden from import
ค้างรับ (account, CEO, SM) Sum of every row's outstanding, closed DEMO-TKT-05 included = /finance's คงค้างรวม: outstanding of deals with an account to-do inside account's scope (dashboardMoney.financeOutstanding)
Account รอชำระส่วนที่เหลือ Only AWAITING_FINAL_PAYMENT, so it showed "0 ดีล" while the to-do had items The deals the to-do offers รับชำระส่วนที่เหลือ for (shared offersFinalPayment)
CEO + SM CEO ยอดขายเดือนนี้ / ยอดขายปิดแล้ว / ปิดงานแล้ว / Pipeline บริษัท; SM ยอดทีมเดือนนี้ / pipeline ทีม (three different definitions) Removed. Both show เงินรับแล้ว (เดือนนี้) (receipts in the Bangkok month: deposit + balance − adjustment, new cashReceivedThisMonth for account/ceo/sales_manager only), ค้างรับ and ยอดคาดการณ์ (ACTIVE deals before ขั้น 10)
Account รับแล้ว (เดือนนี้) Guessed from updatedAt Same cashReceivedThisMonth
CEO ยอดตามทีม/ฝ่าย CEO-closed deals at amount paid This month's cash per rep (cashReceivedByRep). The rows add up to เงินรับแล้ว

No payable SQL was copied. The paid-sum sign rule is now one constant, TicketRepository.SIGNED_RECEIPT_SUM, used by paidAmountSelect and by the dashboard. depositDue is read inside the existing per-row statement, so the statement count is unchanged (TicketActionsQueryCountIntegrationTest is green).

Test coverage (written first and shown red before implementing)

  • dashboardMoney.test.js (new):
    • ค้างรับ counts deposit-pending, DEPOSIT_PAID and overdue deals.
    • It excludes the DEMO-TKT-05 shape (closed, outstanding left, commission recorded), a pre-ขั้น 10 deal the to-do would still offer (checked to be non-vacuous), a deal with no to-do, and a cancelled deal.
    • ยอดคาดการณ์ counts only ACTIVE deals before ขั้น 10.
  • AccountOverview.test.jsx:
    • The deposit tile shows ฿85,418.10.
    • The รอชำระส่วนที่เหลือ count equals the to-do rows.
    • รับแล้ว comes from the summary.
    • ค้างรับ excludes the closed deal and equals AccountFinancePage's คงค้างรวม on the same tickets (both pages rendered).
  • CeoOverview.test.jsx, ManagerOverview.test.jsx:
    • Both pages show the same three figures from one fixture, and the removed tiles are absent.
    • Rep rows add up to เงินรับแล้ว.
    • All reps are listed, with no cap.
    • The empty state shows when nothing was received.
  • DashboardServiceTest:
    • The cash figures go to account, ceo and sales_manager. They are null for hr, import, sales and employee, and the query never runs for those roles.
    • The month is the Bangkok month even while UTC is still on the previous one.
  • DashboardRepositoryIntegrationTest:
    • Bangkok month edges at both ends, deposit + balance − adjustment, and 0 for an empty month.
    • Per-rep rows group by creator id (two reps with the same name stay separate). A blank name shows as ไม่ระบุผู้ขาย. The rows add up to the total.
  • TicketDepositDueIntegrationTest (new):
    • The list row and the single-deal read both serve the newest ISSUED notice, not a DRAFT or SUPERSEDED one.
    • depositDue is null for every other payment status and for import.

Deliberately not covered:

  • What the figures show while the summary is loading (—).
  • Row order in the rep panel. The frontend sorts it, but no test pins the sort.
  • The mock mirrors (mockApi.js).
  • Exact tile placement.

Verification

  • An Opus review with a revert-check ran on both parts. With the production code reverted, the new tests go red on assertions. Restored, they go green.
  • Backend: 28 targeted tests green.
  • Frontend: 770 targeted vitest tests green.
  • I ran the backend on a copy of the walk's QA database and checked in the browser:
    • Account ค้างรับ = /finance คงค้างรวม = ฿914,905.86. The รอชำระส่วนที่เหลือ tile shows 7 ดีล and matches the to-do. DEMO-TKT-05 is gone.
    • CEO and SM both show เงินรับแล้ว ฿19,385,367.99, ค้างรับ ฿914,905.86 and ยอดคาดการณ์ ฿216,675.00.
    • That database had no deal waiting on its deposit, so the deposit tile is checked by the tests only.
  • W3-02 re-check (fix(import): dashboard = issued IRs only, direct deals get factories + IR-draft picker, legacy one-click chain removed #1194): on deal 19 (PR-2026-0014), the IR is IN_TRANSIT while the deal stays IR_ISSUED. The import dashboard shows ขนส่ง 1 and lists the deal under กำลังขนส่ง. Confirmed.

docs/api/response-fields.json was regenerated. It also picks up one unrelated existing drift line, PricingRequestSummaryDto.parentPricingRequestId, which salesActions.js already reads.

Code review (medium) — fixed before merge

  • SM leaderboard now ranks reps by this month's cash (cashReceivedByRep, the same rows as the CEO panel), not by closed deals × deal value. There is no top-5 cut, so CEO and SM agree.
  • cashReceivedThisMonth is now the sum of the per-rep rows, computed in one query. The total equals the rep rows by construction.
  • A test now pins largest-first order on the rep panel. The unused DashboardSummaryDto.of overload and two stale comments are removed.
  • Not fixed:
    • The 500-row cap is now fixed. See the section below.
    • deposit_due is a per-row lookup inside a statement that already runs for each row.
    • A deposit-pending deal with no issued notice shows ฿0. In practice it can't happen, and ฿0 would be the true amount due.
  • An Opus check reverted the fixes and confirmed the tests went red. Green after restore: backend 22, vitest 730.

ค้างรับ and ยอดคาดการณ์ as server totals (no 500-row cap)

Ploy asked for this in the same PR.

  • /api/dashboard/summary now has financeOutstanding and forecastValue, served to account, ceo and sales_manager only.
  • Both are computed in SQL over every deal, so the 500-row list cap no longer limits them. The SQL reuses payableAmountSelect, paidAmountSelect, paymentOverduePredicate, the account list scope (now accountScopePredicate(), shared with appendRoleScope) and the commission-recorded fragment.
  • The account, CEO and SM dashboards and the /finance header all show this one figure.
  • On /finance the hero now reads ค้างรับทั้งหมด. Ploy ruled one figure everywhere, so for the CEO it can include deals that the CEO's own list leaves out.
  • dashboardMoney.js is deleted. Each screen fetches the summary through one shared function, fetchDashboardSummary.
  • Anti-drift: backend/src/test/resources/dashboard/money-cases.json holds 23 deal shapes. moneyCases.test.js checks the production nextAccountAction against them, and DashboardMoneyTotalsIntegrationTest checks the SQL against the same shapes.
  • A 505-deal test proves both totals include every deal.
  • Mutation check: dropping the quotation_issued guard in the SQL turns the case-table test red.
  • Opus review: reverting the change turned 2 backend tests and 8 frontend tests red. Green runs: 112 backend tests, including TicketIaAuthzMatrixIntegrationTest and TicketScopeIntegrationTest, plus 877 vitest tests.
  • Rebased onto develop 9e815afe (fix(deals): status chips and labels follow the deal's real state (P2 batch 1) #1202 and fix(deal): skip route reads true — เสนอราคา ▾ trigger, ข้าม on never-visited stages #1206). Every commit is patch-identical after the rebase (checked with git range-diff). Re-tested after the rebase: 9 backend classes green and 883 vitest tests passing.
  • docs/api/response-fields.json was regenerated:
    • It now pins the two new fields.
    • It drops TicketSummaryDto.closedAt, which the CEO dashboard no longer reads.
    • It also picks up ImportRequestCoverageResponse.hasUncoveredFactories, which develop already reads.
  • Not fixed: the overdue predicate is evaluated twice per deal (once in the scope, once in the to-do check). That costs some speed but does not change the result.

🤖 Generated with Claude Code

@vercel

vercel Bot commented Oct 29, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
demo-glr Ready Ready Preview Oct 29, 2026 3:26pm UTC

Request Review

waritctd added a commit that referenced this pull request Oct 29, 2026
- SM leaderboard = this month's cash per rep (same rows as the CEO panel)
- cashReceivedThisMonth = sum of the per-rep rows (one query)
- pin the rep panel's largest-first order; drop unused DashboardSummaryDto.of overload; fix stale comments

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
waritctd and others added 5 commits October 29, 2026 22:05
Owner rulings 2026-10-29:
- Account รอรับมัดจำ = deposit due (latest ISSUED deposit notice total_payable,
  new TicketSummaryDto.depositDue, hidden from import).
- ค้างรับ = /finance คงค้างรวม on account, CEO and SM (shared dashboardMoney.js).
- Account รอชำระส่วนที่เหลือ counts the deals the to-do offers that step for.
- CEO + SM show เงินรับแล้ว (เดือนนี้) (receipts in the Bangkok month, new
  cashReceivedThisMonth on the dashboard summary for account/ceo/sales_manager),
  ค้างรับ and ยอดคาดการณ์ (ACTIVE deals before ขั้น 10). Old month-sales,
  closed-count and pipeline tiles removed.
- CEO ยอดตามทีม/ฝ่าย = this month's cash per rep (cashReceivedByRep).
- Paid-sum sign rule shared via TicketRepository.SIGNED_RECEIPT_SUM.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- SM leaderboard = this month's cash per rep (same rows as the CEO panel)
- cashReceivedThisMonth = sum of the per-rep rows (one query)
- pin the rep panel's largest-first order; drop unused DashboardSummaryDto.of overload; fix stale comments

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…cap)

financeOutstanding / forecastValue on /api/dashboard/summary for account/ceo/sales_manager,
one SQL reusing payableAmountSelect, paidAmountSelect, paymentOverduePredicate, the account
list scope and the commission-recorded fragment. Account, CEO, SM and the /finance header
read the same figure (CEO /finance hero relabelled ค้างรับทั้งหมด). Shared case table
money-cases.json pins the SQL against nextAccountAction.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…y cache key

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@waritctd
waritctd force-pushed the fix/dashboard-money-matches-finance branch from 2211d71 to b98d69b Compare October 29, 2026 15:26
@waritctd
waritctd merged commit 78d37bb into develop Oct 29, 2026
7 checks passed
waritctd added a commit that referenced this pull request Oct 29, 2026
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

This branch was successfully deployed

1 active deployment
Preview — b98d69be Deployed Oct 29, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant