Surface Quickpay's fraud signals - #139
Merged
Merged
Conversation
Three surfaces for the fraud data the SDK already models: - The admin operation history panel shows a "Fraud suspected" badge (translated in all 16 locales) next to the test-mode badge, read off the payment's metadata. - An opt-in fraud.block_capture config flag makes PaymentProcessor consult the new Fraud/FraudChecker before the automatic capture on the complete transition and skip it with a warning when Quickpay reports the payment as fraud suspected - the transition itself proceeds, leaving the payment for manual review. The checker fails open on every unanswerable case (no Quickpay payment, no api key, Quickpay unreachable), so it never blocks the payment flow, and it is off by default because it costs one extra API call per automatic capture. - setono:sylius-quickpay:reconcile-payments gains a --fraud-suspected report mode that queries each configured gateway's account directly for flagged payments in the period - report only, nothing is transitioned. The final SDK endpoint classes cannot be doubled, so the new tests run the real SDK client against a canned-response PSR-18 stub (tests/Quickpay/ FixedResponseHttpClient), and the report mode was verified live against the Quickpay API. Closes #132
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## 2.x #139 +/- ##
============================================
+ Coverage 93.86% 94.27% +0.41%
- Complexity 205 226 +21
============================================
Files 25 27 +2
Lines 766 839 +73
============================================
+ Hits 719 791 +72
- Misses 47 48 +1 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
loevgaard
commented
Aug 24, 2026
…ker's no-method case
loevgaard
force-pushed
the
fraud-signals
branch
from
August 24, 2026 09:45
957980f to
26d5aa9
Compare
loevgaard
commented
Aug 24, 2026
- FraudChecker reads the payment id through the gateway library's Details helper; a present but unusable id lands in the same fail-open catch as an unreachable Quickpay, since either way the fraud question cannot be answered - The api_key/apikey resolution lived in three places (FraudChecker, PaymentOperationsAction, the reconcile fraud report); it is now the Quickpay\ApiKeyResolver helper, the one place that knows about the pre-2.0 option name
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.
Closes #132.
Three surfaces for the fraud data the SDK already models (
Metadata::$fraudSuspected,PaymentsQuery'sfraudSuspectedfilter):Admin badge
The operation history panel shows a red Fraud suspected label next to the existing test-mode badge, read off the fetched payment's metadata. Translated in all 16 locales.
Opt-in capture guard
When enabled,
PaymentProcessorconsults the newFraud\FraudCheckerbefore the automatic capture on thecompletetransition and skips the capture with a warning when Quickpay reports the payment as fraud suspected — the transition itself proceeds (mirroring how a failed cancel is handled), leaving the payment for manual review in the Quickpay manager.Design choices:
infosays so.FraudCheckerInterfaceseam (with interface alias, per the repo convention), so the processor's tests stay cheap.Reconcile report mode
bin/console setono:sylius-quickpay:reconcile-payments --fraud-suspected --since="7 days"Unlike reconciliation (which walks local pending payments), this asks Quickpay directly: every configured Quickpay gateway's account is queried for payments flagged in the period, regardless of local state, and printed as a table (gateway, Quickpay id, order id, state, created, test mode). Report only — nothing is transitioned or persisted. Exit code fails only on API errors.
Tests
The SDK's endpoint classes are final and cannot be doubled, so the new tests run the real SDK client against a canned-response PSR-18 stub (
tests/Quickpay/FixedResponseHttpClient) — covering the flagged/clean/no-id/no-key/unreachable paths of the checker and the report mode end to end through the command. Processor tests pin: capture skipped on suspicion, capture proceeds when clean, and the checker is never consulted when the guard is off.The report mode was also verified live against the real Quickpay API (empty result on an account with no flagged payments).
README (Fraud signals section),
UPGRADE-2.0.md, andCLAUDE.mdupdated.