feat(admin): Say why collection will fail, when the data already knows - #246
Merged
Merged
Conversation
Reports only what the team's state already decides: no way to pay, an on-session collection mode, an INR bill over the silent-debit threshold, a mandate ceiling below the bill or awaiting re-consent, a card expiring before the charge, a wallet that cannot cover it. Silence means the question is open, not that it will succeed. Reuses the production helpers so the simulator and the collector cannot disagree, and deliberately avoids collection_mode.evaluate, which trips the profile as a side effect. Optimistic and Assumed modes sit alongside; both branches stay on screen and the ruled-out one is dimmed rather than hidden. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The simulator could say what a team would be billed and when we would ask for it. It could not say whether the ask would work. This adds that, but only where the answer is a fact rather than a forecast.
Three modes, and the output always names which produced it:
Derived is the one that earns its keep, because every conclusion it reaches is already true in the database:
flowchart TD S["Team state"] --> A{"Anything decisive?"} A -->|no active method, no credits| F1["No way to pay"] A -->|Manual Checkout / Action Required| F2["Customer must act"] A -->|INR at or over silent threshold| F3["Lands in Action Required"] A -->|mandate ceiling below the bill| F4["Debit would be refused"] A -->|mandate awaiting re-consent| F5["Method is skipped"] A -->|card expires before the charge| F6["Expires mid-cycle"] A -->|credits-only, wallet short| F7["Shortfall"] A -->|nothing| OPEN["Open — not knowable from here"] style OPEN fill:#e4f5e9,stroke:#30a66dAn empty finding list is not a prediction of success. It means the data does not settle the question, and the page says exactly that rather than implying the charge will go through.
It reuses the collector, and avoids the one helper that writes
Every rule delegates to the production helper that governs it —
silent_threshold,effective_cap,active_mandate_ceiling,reauth_pending,settlement_sources,ordered_methods— so the simulator and the charge loop cannot drift apart on who is chargeable.collection_mode.evaluate()answers the threshold question too, and trips the profile into Action Required as a side effect. A projection asks; it does not push a team into a new collection mode. There is a test holding that.Both branches stay visible
Marking the entailed arm must not hide the other one — an operator still needs to see what settling looks like even when it is not going to happen. The ruled-out branch is dimmed, not removed.