Skip to content

Caregiver Settlement Gap Mining

Scope: add source-feature checklist evidence without touching source-feature-checklist.md. Existing map pages already identify matching, compensation, and branch/HQ settlement as partial or next-source-verified slices. This page keeps merge-ready evidence separate while Mermaid architecture docs are under edit.

Reviewed docs:

  • Original Sources records source repos as read-only evidence and names Calculate.php plus Payment_model.php as branch settlement anchors.
  • Kanboard Renewal Feature Improvements lists management requests for caregiver assignment, replacement, schedules, split pay, tax calculation, settlement download, and repeated settlement correction.
  • Sanmopia Feature Backlog already names CaregiverAssignmentOptimizerInputs, CaregiverPayoutReadModelAndAcknowledgement, BranchSettlementCalculationReader, and OtherOfficeSettlement as next source-verified slices.

Current backend progress:

  • BranchSettlementCalculationReader foundation now exists under the pricing/settlement feature slice. It reads Supabase financial lifecycle rows and branch_settlement ledger lines, excludes rows already tied to a branch settlement board, preserves source ledger IDs, and feeds opening line items to BranchSettlementCommandHandler.open_board(...). PromotionalCouponCost source parity is now captured before board opening in sanmopia_branch_promotional_coupon_cost_snapshots and enters the CQRS calculation as promotional_coupon_cost source lines. Deleted product coupon 5,000/10,000 source rows remain separate cancelled_gift_coupon_commission receivable lines, and branch completion flags now use cancelled_gift_coupon_commission_paid instead of source-era fee wording. Voucher fee source buckets are now absorbed at the Supabase adapter boundary as the ubiquitous voucher_service_commission receivable line kind, so source names such as VOUCHER_FEE_PRICE no longer leak into the domain. Branch monthly membership dues now have sanmopia_branch_membership_due_snapshots, a branch-period source fact table that freezes the legacy BRANCH_TB.MEMBERSHIP_PAY_PRICE / BRANCH_MEMBERSHIP_PAY_TB.PRICE result before board opening instead of joining mutable branch rows after request/acknowledgement. This removes another live recalculation path from branch settlement board creation. BranchSettlementOperatorDashboard now exposes settlementStatusCounts from branch-scoped board rows, covering the source status-count dashboard evidence at Payment_model.php:4382-4396 without leaking STATUS_FL integers. HQ/internal branch filtering now belongs to the branch profile model: source_branch_id is kept only as trace evidence, while branch_settlement_participation and is_active decide whether a branch appears in operator board/dashboard query models. SettlementCompletionReview now consolidates source getFlagCountFromBoard(...) evidence: membership due, delivery fee, cancelled gift coupon commission, unpaid detail rows, and unpaid coupon rows decide whether central review closes the board as settled or arrears.
  • Candidate scoring and filter evidence. Status: Partial. Evidence: source-refs/sanmopia-admin/application/models/Matching_model.php:44-177. Source behavior: candidate rows join personality and preference score views, require active preference rows, require MANAGER_SCHEDULE_CHECK_FN(...) = 1, exclude pet-allergy caregivers when reservation pet info exists, accept branch and caregiver-class filters, randomize ties by user id, then reorder candidate output by calculated distance. Modern gap: persist CaregiverCandidateEvidence with score components, exclusion reasons, branch scope, pet constraint result, distance, and source request key before any customer rerun or operator final assignment.

  • Candidate detail modal evidence. Status: Pending. Evidence: source-refs/sanmopia-admin/application/controllers/ajax/Reservation.php:32-64, source-refs/sanmopia-admin/application/models/Matching_model.php:233-284, source-refs/sanmopia-admin/application/models/Matching_model.php:661-723, source-refs/sanmopia-admin/application/models/Matching_model.php:866-910, and source-refs/sanmopia-admin/application/models/Reservation_manager_trans_info_model.php:13-87. Source behavior: operator click reads selected reservation, caregiver id, displayed score, service dates, matching info, answer/preference match, distance, and cached travel time into one response. Modern gap: CaregiverAssignmentDecision must store selected caregiver, displayed candidate evidence, service-date window, actor, override reason, and decision source. Do not rebuild candidate detail from current profile data after assignment. The next backend slice should load CaregiverCandidateSnapshot by candidateSnapshotId, verify selected caregiver and reservation/request keys, copy score components, branch scope, grade, distance, transport duration, and ranking policy version into CaregiverCandidateEvidence, then fail stale/missing snapshots with typed conflict errors.

  • Travel-time and distance evidence. Status: Pending. Evidence: source-refs/sanmopia-admin/application/models/Matching_model.php:724-910. Source behavior: recommendation list can read RESERVATION_MANAGER_TRANS_INFO_TB, calculate missing public-transit time through odsaylib, but DB replace is commented out; final sort currently uses RESULT_SCORE even inside the travel-time function. Distance uses reservation address coordinates and caregiver coordinates. Modern gap: separate CaregiverTravelEvidence from ranking policy, capture provider result, fallback reason, distance, travel duration, and ranking policy version so score-vs-travel priority is explicit.

  • Availability and unavailable-day evidence. Status: Pending. Evidence: source-refs/sanmopia-admin/application/models/Manager_model.php:2038-2088, source-refs/sanmopia-admin/application/models/Manager_model.php:2146-2180. Source behavior: caregiver unavailable days are stored in MANAGER_DENIED_TB with reason and start/end dates, while schedule overlap checks read current reservation detail rows. Modern gap: CaregiverAvailabilityWindow and CaregiverAssignmentConflict must be event-backed and auditable. Conflict checks need service-window, unavailable-window, existing-assignment, and replacement-continuity reasons, not only a boolean result. Assignment variants such as primary assign, replacement, assistant handoff, and clear must emit payout-slot invalidation facts so compensation projections do not retain stale role/handoff rows.

  • Dynamic salary calculation evidence. Status: Partial. Evidence: source-refs/sanmopia-manager/application/helpers/salary_helper.php:8-227. Source behavior: caregiver-facing pay is recalculated at read time from reservation data, main/sub caregiver role, service type, live-in/special voucher surcharge, additional services, Saturday/holiday extra days, custom balance amount, tax type, custom main pay, and custom assistant pay. Modern gap: CaregiverCompensationQuoteLine must freeze assignment key, caregiver role, service-day basis, option basis, tax/insurance choice, policy version, custom override, and effective dates before payout display. Backend slice complete: quote lines now carry frozen explainability lines for base pay, additional-service rows, gross total, withholding, calculated pay, override, and final pay; Supabase persistence stores those lines inside the quote calculation basis so pay detail reads do not recalculate from mutable reservation state.

  • Tax and memo persistence evidence. Status: Partial. Evidence: source-refs/sanmopia-admin/application/models/Reservation_manager_salary_model.php:21-52, source-refs/sanmopia-admin/application/models/Reservation_manager_salary_model.php:112-180, source-refs/sanmopia-admin/application/config/constants.php:273-274, source-refs/sanmopia-manager/application/config/constants.php:145-152. Source behavior: persisted caregiver salary rows only upsert reservation id, caregiver id, tax type, memo, and update date; missing rows default tax type to four insurance and memo to blank. Tax constants cover four insurance and 3.3% income tax, with MANAGER_SALARY_TAX_RATING = 0.033. Modern gap: CaregiverPayoutInstruction needs tax/insurance policy evidence, memo evidence, bank-account reference, tax-document reference, and recalculation audit. Tax choice cannot remain an implicit default on read.

  • Caregiver pay read and acknowledgement evidence. Status: Partial. Evidence: source-refs/sanmopia-manager/application/controllers/Other.php:223-294, source-refs/sanmopia-manager/application/models/Reservation_model.php:13-78, source-refs/sanmopia-manager/application/models/Reservation_model.php:352-410, source-refs/sanmopia-manager/application/models/Reservation_model.php:488-516. Source behavior: caregiver pay list is limited to completed or settlement-status reservations, then calcSalary(...) is run for each row; pay detail recomputes salary and loads memo. Main caregiver payment status updates mutate reservation payment rows and PAYMENT_BRANCH_MANAGER_TB; assistant caregiver payment status mutates SUB_PAYMENT_STATUS_ID_FK. Modern gap: CaregiverPayoutReadModel reads frozen payout instructions, while CaregiverPayoutAcknowledgement and CaregiverPayoutReceiptState record branch deposit, main/assistant receipt acknowledgement, exception, repair, actor, idempotency key, and expected revision separately from branch settlement totals. Supabase persistence now splits immutable sanmopia_caregiver_payout_receipt_state_events from current sanmopia_caregiver_payout_receipt_states. FastAPI now binds branch deposit acknowledgement plus caregiver receipt acknowledgement, exception, repair, and read-state routes to those stores; API commands derive actor identity from Supabase Auth and check SpiceDB reservation-booking payout permissions or caregiver self-view scope. Append-only amount/tax/memo adjustment audits and bank-account destination change audits now persist previous/adjusted snapshots, changed-field vocabulary, actor, idempotency key, expected revision, participant RLS, realtime publication, FastAPI routes, TS/OpenAPI contracts, and Supabase row types. Backend payout statement and acknowledgement matching now use a role-and-handoff payout-slot identity, so legacy SORT > 0 assistant rows do not inherit another row’s branch deposit acknowledgement even when the source payment key is shared. Backend commit 81719dc adds the admin/manager shared payout projection foundation with backend-owned operator action availability, service-balance state, branch-deposit state, receipt state, total net payable, and reservation-completion decision. Remaining gaps are persisted projection read/API binding, assignment-variant invalidation from care-team changes, SettlementCompletionGate E2E proof, and portal UX removal of PHP/JS salary recalculation.

PriorityStatusModern ubiquitous nameHidden source evidenceFeature gap
P0PartialCaregiverPayoutOverrideCommandsource-refs/sanmopia-admin/static/js/manager/manager_pay_detail.js:14-104, source-refs/sanmopia-admin/application/controllers/Manager.php:986-1027, source-refs/sanmopia-admin/application/controllers/Manager.php:1133-1183, source-refs/sanmopia-admin/application/controllers/Manager.php:1238-1272, source-refs/sanmopia-admin/application/models/Reservation_model.php:2627-2804, source-refs/sanmopia-admin/application/models/Reservation_model.php:2875-2943Admin/branch payout detail can save or reset custom caregiver pay and tax type through generic PUT /manager actions. The model upserts or zeroes PAYMENT_BRANCH_MANAGER_TB / PAYMENT_BRANCH_SUB_MANAGER_TB rows for main and assistant caregivers, with branch ownership checked after mutation setup and no append-only override audit. Modern command needs expected revision, payout-slot identity, before/after amount, tax policy, actor role, reason, idempotency key, and immutable adjustment audit.
P0PartialCaregiverPayoutCompletionCommandsource-refs/sanmopia-admin/static/js/manager/manager_pay_detail.js:14-43, source-refs/sanmopia-admin/application/controllers/Manager.php:1300-1335, source-refs/sanmopia-admin/application/models/Reservation_model.php:2945-3041, source-refs/sanmopia-admin/application/models/Reservation_model.php:3095-3147Salary completion stamps deposit dates, can create missing type-5 payment rows when none exist, updates assistant rows by source sort, and auto-moves a reservation from settlement to done when salary and service-balance flags all look complete. Modern settlement must separate payout deposit command, caregiver receipt acknowledgement, missing-instruction repair, and reservation-completion continuation behind one SettlementCompletionGate.
P0PartialCaregiverPayoutSlotInvalidationsource-refs/sanmopia-admin/application/models/Reservation_model.php:2627-3041, source-refs/sanmopia-manager/application/helpers/salary_helper.php:8-227Primary caregiver assignment, assistant assignment, replacement, and clear can change role/handoff payout identity after quote or statement projection. Modern care-team assignment events must invalidate payout-slot projections and request payout statement refresh before branch deposit or completion commands are accepted.
P1PendingCaregiverServiceBalanceDepositStatesource-refs/sanmopia-admin/static/js/manager/manager_pay_inquiry.js:254-289, source-refs/sanmopia-admin/static/js/manager/manager_pay_detail.js:234-260, source-refs/sanmopia-admin/application/controllers/Manager.php:1057-1105, source-refs/sanmopia-admin/application/controllers/Manager.php:1107-1130, source-refs/sanmopia-admin/application/models/Reservation_model.php:2453-2570, source-refs/sanmopia-admin/application/models/Reservation_model.php:2572-2625Service-balance status changes are a separate admin/branch UI path from salary completion, with check, complete, and unpaid states mutating main or assistant payment flags and sometimes reservation status. Modern payout acknowledgement should model branch deposit state and caregiver receipt state as distinct events, not overuse payment-status integers in settlement rows.
  • Branch/HQ settlement board evidence. Status: Partial. Evidence: source-refs/sanmopia-admin/application/controllers/Calculate.php:15-66, source-refs/sanmopia-admin/application/models/Payment_model.php:828-980. Source behavior: HQ settlement page builds monthly branch rows, filters by branch, excludes deleted/internal branches, reads monthly membership fee overrides, computes voucher fees, PromotionalCouponCost source buckets, deleted 5,000/10,000 source rows, other-area counts, and unpaid membership state from source tables. Modern gap: BranchSettlementStatement has versioned SettlementLineItem coverage for branch membership due snapshots, voucher service commission, promotional_coupon_cost, and cancelled_gift_coupon_commission. VoucherServiceCommission now supplies effective-dated rate selection and branch line-item materialization, so branch/admin screens must read the frozen line rather than recomputing VOUCHER_COUNT * rate. BranchSettlementDeliveryFee now supplies effective-dated rate selection and delivery_fee line-item materialization; this is separate from reservation quote rental-equipment delivery. Inter-office settlement now contributes inter_office_branch_share and inter_office_service_fee line items from frozen service/customer branch roles and charged-branch fee evidence instead of source RESULT_PRICE, FEE, ALL_PRICE, and other-area count formulas. It still needs command/API binding to the live board. Board display must not recalculate amounts from mutable reservation/coupon/profile rows.

  • Branch/admin/head-office authority split. Status: Partial. Evidence: source-refs/sanmopia-admin/application/controllers/Calculate.php:150-315, source-refs/sanmopia-admin/application/models/Payment_model.php:534-620, source-refs/sanmopia-admin/application/models/Payment_model.php:768-824, source-refs/sanmopia-admin/application/models/Payment_model.php:2977-3052, source-refs/sanmopia-admin/application/models/Payment_model.php:4312-4400. Source behavior: same action path handles HQ request and branch confirmation, and same mutable board/detail rows are used across actor roles. Modern migration still needs a role-discriminated command surface (RequestSettlementDeposit, AcknowledgeBranchSettlementDeposit, ApproveHeadquartersSettlement, RequestSettlementArrearsDeposit) so head office, branch admin, and related office roles cannot share settlement row semantics. Keep this binding separate from Danbi/external-counterparty settlement: use BranchHeadquartersSettlementCommandBinding for central-to-branch rows and ExternalCounterpartySettlementCommandBinding for user-to-Danbi rows.

  • HQ request and branch acknowledgement evidence. Status: Partial. Evidence: source-refs/sanmopia-admin/application/controllers/Calculate.php:150-315, source-refs/sanmopia-admin/application/models/Payment_model.php:534-620, source-refs/sanmopia-admin/application/models/Payment_model.php:768-824, source-refs/sanmopia-admin/application/models/Payment_model.php:2977-3052, source-refs/sanmopia-admin/application/models/Payment_model.php:4312-4400. Source behavior: same action handles HQ request and branch confirmation. HQ creates one board per branch/month, marks selected reservation payments as central-status paid, inserts source product/canceled-coupon rows, stores delivery price and manual extra rows, then logs status. The modern adapter maps those source rows to promotional_coupon_cost and cancelled_gift_coupon_commission instead of exposing source amount buckets to the domain. Branch confirmation updates delivery, membership, and canceled-coupon flags, marks detail/coupon rows, and derives complete/pending status from flag counts. Modern replacement: SettlementCompletionReview keeps the completion decision in one domain value object. SettlementStatement now separates RequestSettlementDeposit, AcknowledgeBranchSettlementDeposit, ApproveHeadquartersSettlement, and RequestSettlementArrearsDeposit with actor audit, expected revision, per-line acknowledgement state, and command replay by idempotency key. Remaining gap: every source board mutation path still needs binding to these commands, plus full history/export coverage.

  • Branch/HQ history and export evidence. Status: Pending. Evidence: source-refs/sanmopia-admin/application/controllers/Calculate.php:460-578, source-refs/sanmopia-admin/application/models/Payment_model.php:2370-2523, source-refs/sanmopia-admin/application/models/Spreadsheet_model.php:3741-3805. Source behavior: history filters by current branch for branch users or branch query for HQ, then derives counts, unpaid membership, delivery, coupon, voucher, manual extra, total price, and display status from board rows. Export endpoint named for branch/HQ settlement calls downloadExcelFormByPaymentCentralToBranch, but workbook data loading reads BOARD_PAYMENT_DANBEE_TB and loadPaymentUserToDanbeeDetail(...). Modern gap: BranchSettlementExportRequest must have separate branch/HQ source readers, frozen export artifacts, repair/retry controls, and column tests for every line-item bucket. HQ export cannot reuse branch-to-company settlement board data by accident.

  • Add CaregiverAssignmentDecision under caregiver matching. Evidence: Matching_model.php:44-177, Matching_model.php:724-910, ajax/Reservation.php:32-64, Manager_model.php:2038-2180. Required proof: score/preference/personality, pet constraint, branch scope, unavailable-day, distance, travel time, rerun, selected caregiver, and operator override are persisted as assignment decision evidence.
  • Add CaregiverPayoutInstruction under caregiver compensation. Evidence: salary_helper.php:8-227, Reservation_manager_salary_model.php:21-180, manager Other.php:223-294, manager Reservation_model.php:13-78, Reservation_model.php:352-410, Reservation_model.php:488-516. Required proof: pay rows freeze per caregiver and role, include tax/insurance policy, custom override, service-day basis, payout status, deposited date, memo, and acknowledgement without recalculating from mutable reservation data. 2026-07-05 backend foundation now adds CaregiverPayoutPolicyProfile, CareTeamCompensationSlot, and CaregiverPayoutPolicyDecisionSnapshot for salary_helper.php:109-214, including weekend/holiday extension, repeating option basis, voucher add-on/tax cutover, service-balance override, primary/assistant custom pay, and assignment-key/role/handoff slot identity.
  • Add BranchSettlementStatement and BranchSettlementExportRequest under branch/HQ settlement. Evidence: Calculate.php:15-66, Calculate.php:150-315, Calculate.php:460-578, Payment_model.php:534-620, Payment_model.php:768-824, Payment_model.php:828-980, Payment_model.php:2370-2523, Payment_model.php:2977-3052, Payment_model.php:4312-4400, Spreadsheet_model.php:3741-3805. Required proof: line-item ledger covers voucher fee, membership, delivery, promotional_coupon_cost, cancelled_gift_coupon_commission, bidirectional manual extra line items, inter_office_branch_share, and inter_office_service_fee; HQ request and branch acknowledgement replay through idempotent statement commands; history and export use frozen branch/HQ datasets, not branch-to-company settlement readers.