Objective
- Quote worklists (e.g. Manager: Quote Close Out and other custom quote lists) must show the same charge / service names and amounts staff see on Open Quotes (
/work/quotes), so managers are not misled by generic "Charge" orCharge Nrows at $0.00 when triaging aging quotes. - Remove apparent intermittency: the same quote can look correct in one place and wrong in another at the same time (FHI, RIA, and other brands).
Background
Product feedback: Pending quotes / Open Quotes show correct services (e.g. "Home/Condo Inspection" at $425.91), while some custom quote worklists show "Charge" or "Charge 1" at $0.00 in the expanded row—and sometimes after opening the quote from that worklist. Reports mention quotes that sat pending for a few days; behavior has also been described as "fixing itself," which likely reflects different list entry points or worklist configs, not data self-healing.
Open Quotes loads via
GET /quotewithaddQuotePopulationStages()inattik-backend/src/util/functions/quote/addQuotePopulationStages.ts, which fully populatescharges(including nestedservices, bundles, discount codes).Custom quote worklists load via
GET /worklist/:id/datainattik-backend/src/routes/worklist.ts. Conditions are split inseparateConditions()/requiresPopulation(): only attributes likeservice-ids,required-info-*, and event-inspection fields are treated as post-population. Typical close-out filters (status, age, address, created-by, etc.) stay pre-population only.For quote worklists without post-population conditions,
buildWorklistPopulationStages()usesgetInspectionPopulationPipeline({ includeCharges: false })(~lines 1016–1027), sochargesare returned as unpopulated refs (ObjectIds), not full charge documents.Worklists with post-population but without
service-idsmay populate charges viagetInspectionPopulationPipeline({ includeCharges: true }), which is still a different shape thanaddQuotePopulationStages()used by Open Quotes.Worklists with
service-idsuse a lightweight charge lookup for filtering, then a follow-up lookup—a third path.Two custom quote worklists can disagree at the same time for the same quote: one whose conditions trigger post-pop (e.g. includes
service-idsorrequired-info-*) may show real service names; one with only pre-pop filters (common for close-out lists) will not.On the frontend,
SingleQuoteDropdownuses fallbacks whencharge.name/charge.amountare missing (Charge Nlabels and$0.00), so missing population surfaces as generic labels and zero dollars—not as an empty state.SE region is attempting to isolate quotes that are abandoned status by using the following configuration. The only worklists that have this issue are both using this same group of conditions
Repro / examples (screenshots)
Custom worklist showing incorrect charge data:
Open Quotes list showing correct service and amount:
FHI Example 1
FHI example 2
RIA
Scope
Backend
GET /worklist/:id/data—attik-backend/src/routes/worklist.ts:requiresPopulation(),buildWorklistFilterStages(),buildWorklistPopulationStages(), and the aggregate pipeline that applies population after sort/limit.- Quote population today: default quote branch sets
includeCharges: falsewhenhasPostPopConditionsis false; alternate branches when post-pop orservice-idsare present usegetInspectionPopulationPipeline()fromattik-backend/src/util/functions/aggregation/inspectionPopulation.tsinstead ofaddQuotePopulationStages(). - Reference implementation for correct shape:
attik-backend/src/util/functions/quote/addQuotePopulationStages.ts(used byattik-backend/src/routes/quote.tsfor list/detail). - Requirement: All quote worklist responses should expose populated
chargeswithnameandamount(and nested service data if the UI depends on it), regardless of which condition branch was used for filtering. - Decision needed: Whether lightweight charge lookups used only for
service-idspost-pop$matchshould remain separate from the final response shape returned to the client. - Decision needed: Whether to add regression coverage on the worklist quote aggregate (e.g. pre-pop-only worklist returns
charges[0].name).
Frontend
- Worklist quote UI:
attik-frontend/src/components/task-check/WorklistResolver.tsx→SingleQuoteBar.tsx→SingleQuoteDropdown.tsx(expanded charges section with fallbacks). - Open Quotes comparison path:
attik-frontend/src/components/task-check/QuoteList.tsx→ sameSingleQuoteBar/SingleQuoteDropdown, fed byGET quotewith full population. - Segment filtering on Open Quotes uses
primaryCharge?._serviceId?._segmentIdinQuoteList.tsx; worklists with unpopulated charges may also affect segment-related display where that pattern is reused. - Decision needed: Whether to keep UI fallbacks (
Charge N,$0.00) when data is missing, or surface an explicit empty/error state after backend is fixed.
Out of scope (unless product asks)
- Changing quote business logic, pricing, or charge creation.
- Inspection or event worklist population (only quote worklists are in scope for this bug).
References
- Slack report (FHI / Quote Close Out)
attik-backend/src/routes/worklist.tsattik-backend/src/util/functions/quote/addQuotePopulationStages.tsattik-backend/src/util/functions/aggregation/inspectionPopulation.tsattik-backend/src/routes/quote.tsattik-frontend/src/components/task-check/SingleQuoteDropdown.tsxattik-frontend/src/components/task-check/WorklistResolver.tsx