Repository navigation
PRE-3677: PPRO display eligibility by amount and country - #337
Conversation
0c8f072 to
3261a37
Compare
3261a37 to
c409ca6
Compare
adumont-payplug
left a comment
There was a problem hiding this comment.
Review of PRE-3677. Run on head c409ca6 in a separate worktree: full PHPUnit (968 tests) OK on PHP 8.2, PHPStan on src OK, ECS OK, node tests 11/11. Not run: PHPMD, Behat, admin UI in a browser, real PayPlug calls.
No blocking finding. Verdict: approve after the Medium findings on logout (stale limits), stale enabled, refusal classification and placeholder art. The admin GET refresh and the controllers.json note are strongly recommended before release.
Not anchored inline (file not in the diff or not line-specific): GatewayConnectionRevoker needs the payment_method block cleared (see the OAuth callback comment). The PR text says 950 tests; the head has 968.
Positives: fail-open design with malformed data logged and ignored, createForPaymentMethod() used everywhere, credentials flushed before the refresh, merchant settings only clamped never overwritten, single PPRO registry, strong failure-path tests, translations consistent across en/fr/it.
jhoaraupp
left a comment
There was a problem hiding this comment.
Review sur 6b81a97, dans un worktree séparé avec un composer install du lock de la PR.
- PHPUnit : 1001 tests, 2 échecs liés à la locale (voir le commentaire sur
PproEligibilityTypeExtensionTest), verts avecLC_ALL=C - PHPStan : 0 erreur
- ECS (
ruleset/ecs.php) : 0 erreur node --test: 11/11- Clés de traduction
ppro.*identiques en en/fr/it
Non lancés : Behat, PHPMD, navigateur.
Rien de bloquant. Les correctifs de 6b81a97 répondent bien aux threads précédents ; je ne reprends pas la classification des refus, déjà ouverte. Nouveaux points : un Medium (limites de l'autre environnement LIVE/TEST au checkout) et quelques Low ci-dessous, plus une réponse dans le thread d'ilajili sur UPGRADE.md concernant le fallback live.
jhoaraupp
left a comment
There was a problem hiding this comment.
Re-review sur 2fc5264 : nos remarques précédentes sont toutes traitées (threads résolus). PHPUnit 1020 tests OK, y compris avec LANG=fr_FR.UTF-8, PHPStan 0 erreur, ECS 0 erreur, node --test 11/11. Une dernière remarque non bloquante ci-dessous. Reste ouvert avant merge, hors de nos remarques : la vérification de PproRefusalClassifier sur des réponses sandbox réelles (thread d'adumont) et le test dans un navigateur du formulaire admin.
Description
Bancontact, Wero and Scalapay (the PPRO payment methods present in the plugin) are now shown at checkout only for the cart amounts and billing countries PayPlug accepts for them, and the merchant can narrow both from the payment method page.
Scope
Gateway\PproPaymentMethods::API_KEY_BY_FACTORY, so adding Satispay, MyBank, iDEAL or Bizum later is one entry, with no new eligibility code. These four are not in the plugin today and are out of scope.SupportedMethodsProvider, which is now guarded and fails open: an account that cannot be read (expired credentials, network error) no longer breaks the checkout payment method list. The error is logged.Stored configuration (per payment method)
payment_methodblock:name,enabled,allowed_countriesanddefault_amount(PayPlug limits, in cents),configured_amountandconfigured_countries(merchant settings),live,refreshed_at.UnifiedAuthenticationController). A warning is shown if they cannot be fetched.PproConfigRefreshOnAdminDisplayListener)PostSavePaymentMethodEventListener)CapturePaymentRequestHandler+PproRefusalClassifier). The customer is sent back to the order page with a message, and the payment request response data carriesredirect_urlanderrorfor headless frontends. The flash message is only added for the Twig checkout, not for a JSON or XHR request.bin/console payplug:ppro:refreshcommand, to run once after the upgraderefreshIfStale(). Limits refreshed less than 5 minutes ago in the same environment are reused with no PayPlug call and no write, so a reloaded page, a browser prefetch or repeated refusals do not call PayPlug each time.EntityManager::refresh(), which also runs Sylius's gateway config decryption) and replaces only thepayment_methodblock.StoredPproConfigReader→PproEligibilityChecker) and makes no API call for these methods. Otherwise (right after the upgrade, after a logout, when the stored block cannot be read, or when it was fetched in the other LIVE/TEST environment because the refresh after a switch failed), the method is filtered live from the PayPlug account, then by the merchant settings already saved (PproEligibilityChecker::isAllowedByMerchantSettings()), including the former Scalapay range. If the account cannot be read either, the method is shown and PayPlug decides at payment time.enabled: falsereported by PayPlug hides the method for 24 hours after the last refresh. After that it is shown again and PayPlug decides, so a method PayPlug enables later is not hidden for good. The admin alert says so ("at the last refresh…").configured_countriesbecomes[]and the method is hidden everywhere until the merchant selects new countries (flashsettings_adjusted, a permanent alertui.ppro.no_country_lefton the page, and the form requires a selection). It is never shown more widely than the merchant chose.configured_countriesnull means every country PayPlug allows. At least one country must stay selected.GatewayConnectionRevoker) clears the stored PayPlug limits and keeps the merchant settings, so a reconnection to another account never filters with the previous account's limits.Admin
ppro-eligibility: amount outside the PayPlug limits, min > max, no country). Server-side validation (PproConfigurationValidator) also refuses the save with an explicit message in en/fr/it, including negative amounts when no PayPlug limit is known.public/assets/admin/ppro/illustration-min-max.svgandillustration-pays.svgare the final assets.BC / behaviour changes (detailed in
UPGRADE.mdandCHANGELOG.md)ScalapayGatewayConfigurationTypeExtension,IsScalapayAmountRangeValidand its validator, theamount_rangeTwig hook andscalapay_amount_range.html.twig, and theui.scalapay_gateway_config.*/payplug_scalapay.*translation keys. Replacements:PproEligibilityTypeExtension,Ppro\PproConfigurationValidator, hookppro_eligibility,ui.ppro.*/ppro.*.PproMerchantSettings): until the PayPlug limits are first stored, the oldmin_amount/max_amountkeys keep narrowing the checkout; on the first refresh they become the merchant range, clamped to the PayPlug limits if needed (the admin page then shows a notice), unless the merchant entered a range in the meantime. They are not read again afterwards.ScalapayGatewayFactory::MIN_AMOUNT/MAX_AMOUNTare deprecated (read once for the carry-over).SupportedMethodsProvider,CapturePaymentRequestHandler,UnifiedAuthenticationControllerandPostSavePaymentMethodEventListener.PproConfigurationRefresherInterfacegainsrefreshIfStale().bin/console payplug:ppro:refreshonce, and rebuild the admin assets. An application that lists the plugin's controllers in its ownassets/admin/controllers.jsonmust addppro-eligibilitythere (snippet inUPGRADE.md).UPC impact: none, no bump. PHP floor unchanged (8.2).
Motivation: Stop showing customers PPRO payment methods they cannot use for their cart amount or billing country, and let merchants control each method's exposure themselves.
Related issue(s): Closes PRE-3677 (epic PRE-3674)
Type of Change
UPGRADE.md,CHANGELOG.md,README.md,doc/ppro_display_eligibility.mdChecklist
Code Quality
develop).enabledTTL are class constants by design.Testing
LANG=fr_FR.UTF-8; includes a render test of the admin PPRO template.node --test11/11 for the admin validation logic, now also run in CI (npm teststep in the coverage job).lint:containerOK.sonarcloudCI job: green on2fc5264, with the full CI (PHPUnit matrix PHP 8.2/8.4 × Sylius 2.0/2.1, Coverage, PHP Quality)Security & Ops
payplugchannel and fail open. A failed refresh after OAuth or on the admin page shows a warning. The refresh command exits non-zero if a connected method could not be refreshed.Review
Review feedback from @adumont-payplug and @ilajili addressed in
6b81a97: stale limits after logout, staleenabledflag, throttled admin and refusal refreshes, concurrent saves, removed rollback, negative amounts, log flooding, flash wording, headless flash, CI JS tests,controllers.jsonsnippet, and the upgrade window without stored limits (live fallback + Scalapay carry-over).Review feedback from @jhoaraupp addressed in
2fc5264: limits from the other LIVE/TEST environment no longer used at checkout, merchant settings and the former Scalapay range applied in the live fallback, Scalapay range kept when the block is created before the first refresh, empty country intersection hides the method (product decision), locale-independent form tests, reworded 24 h alert. Also fixed: thedisabled_by_payplugadmin alert never showed (|default(true)turnsfalseintotruein Twig).Not run / to verify before release
details.amount/details.billing.countryin the PayPlug error body) not checked against real sandbox responses: needs a Wero payment with a billing country outside BE/DE, and a Scalapay payment below its minimum, to add as test fixtures.payplug:ppro:refreshcommand and the admin asset rebuild.Possible later point (no ticket)
payplug:ppro:refreshschedulable).🤖 Generated with Claude Code