PRE-3601: Let merchants narrow the Scalapay amount range at checkout - #119
Merged
adumont-payplug merged 1 commit intoSep 14, 2026
Merged
Conversation
jhoaraupp
reviewed
Sep 14, 2026
jhoaraupp
left a comment
Contributor
There was a problem hiding this comment.
Automated review (3 findings below, one thread each).
adumont-payplug
force-pushed
the
feature/PRE-3601_overload_min_max_scalapay
branch
from
September 14, 2026 09:58
9acac64 to
ce65dfb
Compare
jhoaraupp
approved these changes
Sep 14, 2026
adumont-payplug
deleted the
feature/PRE-3601_overload_min_max_scalapay
branch
September 14, 2026 12:44
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.
Description
Scalapay was offered for any cart amount within the bounds the Payplug account authorizes. Merchants can now choose their own min/max inside those bounds, and Scalapay is hidden at checkout for carts outside them — same UX and same back-office placement as the existing Oney thresholds.
Every bound is sourced from
GET /account(amounts.scalapay, falling back to the account default): there is no hardcoded range anywhere. The merchant can only narrow the authorized range, never widen it, so an out-of-range custom limit is ignored in favour of the account's own.Changes:
PaymentMethod::getPaymentTab()and::getPaymentOption(); extracted it intoPaymentMethod::getPriceLimit()(pure, behaviour-preserving) and overrode it inScalapayPaymentMethod. One override now gates both the payment-option list (hides the method) and payment-tab creation (server-side guard), with no behaviour change for any other gateway.scalapay_custom_{min,max}_amounts, stored asEUR:<cents>like the Oney equivalents. Empty means "never customised", so the account range applies as-is. Registered for existing installs byupgrade-5.2.0.php.getOption()now returns a top-leveladvanced_optionscarrying thethresholdsblock.valueis the merchant's effective limit;defaultis always the account bound, which is what the widget validates against client-side — the same ceiling as the save-time check, so display and enforcement can't drift.payplug-ui-plugins-bo^2.1.0→^2.3.0. The locked 2.2.1 does not renderadvanced_optionsfor a generic gateway, so the fields would simply not appear without this bump (UI side was done in payplug/payplug-ui-plugins#36).Also fixed in passing:
upgrade/upgrade-5.1.0.phpshipped unlisted inmodule_files.csv(PRE-3456), andFilesHelper::clean()deletes any on-disk file absent from that list. It self-skips on localhost/ngrok, so this only bites real shops. Added both it and the newupgrade-5.2.0.php.Review feedback addressed
The automated review raised three findings; all three are fixed in this branch.
src/actions/ConfigurationAction.php— a partial payload bypassed validation entirely. The upfront range check only ran whenenable_scalapay,scalapay_min_amountsandscalapay_max_amountswere all present, while the switch-case below persists each amount on its own gate. A payload carrying a single amount was therefore saved unchecked — and sincegetScalapayPriceLimit()clamps each bound independently against the account range, a minimum saved above the maximum in force was never caught, silently hiding Scalapay for every cart with no error to the merchant. The validation gate is now as wide as the persistence one, and an amount the payload omits is resolved from the limits currently in force, so the two bounds are still compared against each other. A bound the account does not expose comes back asfalse, hence0once cast, whichisAmount()rejects — an unusable range fails the save rather than passing it.src/models/classes/paymentMethod/PaymentMethod.php— docblock splice.getPriceLimit()had landed betweenset()'s docblock andset()itself, leavingset()undocumented and its docblock attached to the wrong method.getPriceLimit()now sits above, andset()keeps its own docblock.src/actions/ConfigurationAction.php— pre-existing Oney no-op, fixed here. This one is outside the original scope of this PR. The Oney branch testedisAmount()'s return array rather than its['result']flag; the array is always truthy, so out-of-range Oney custom amounts were persisted regardless of validity. The flag is now read out, so an invalid Oney amount is no longer written. The reviewer suggested deferring this to its own ticket — flagging the scope change explicitly in case you would rather it were split back out. Note there is nomodal.oney.thresholds.*translation key, so an invalid Oney amount is silently skipped rather than raising an error modal the way Scalapay does; adding that modal would mean new keys in every language file and is deliberately left out.Related Issue
Ticket: PRE-3601
Type of Change
✅ Quality Checklist
Local Environment & Hooks
(PRE|SMP)-XXXX: descriptionpattern.phpstan.neon/.php-cs-fixer.php) were generated successfully from.disttemplates.Testing & Code Quality
composer cs:fix).vendor/bin/phpstan).CI/CD Deployment Context
Screenshots (if applicable)
Notes for Reviewer
Test results: 2712 tests / 4076 assertions, 0 failures (baseline 2691, so +21 new). PHPStan
[OK] No errors.php-cs-fixer --dry-runclean. The 2 PHPUnit warnings ("No tests found in class …LinkHelper") are pre-existing — verified against a stashed baseline.New coverage:
PaymentMethod/getPriceLimitTest, andScalapayPaymentMethod/withgetScalapayPriceLimitTest,getPriceLimitTest,getOptionTest,setCustomScalapayLimitTest, plus 8 cases insaveActionTest— the 5 added for the review covering a Scalapay minimum submitted alone above the ceiling in force, a maximum submitted alone below the floor in force, a valid single-amount payload, and the Oney branch persisting (resp. not persisting) an in-range (resp. out-of-range) amount. All 5 were written first and confirmed failing against the previous code. Ascalapayentry was added to the sharedamountsfixture inBasePaymentMethod— the full suite is green with it.Two boxes left unticked deliberately:
vendor/captainhook/captainhook/src/Console/Command.phpunder the PHP 7.2 CLI on my machine (unrelated to this PR;composer test/stan/cs-fixerall run fine).Changelog: the Oney
isAmount()fix has nochangelog.mdentry yet — it is a merchant-visible behaviour change (out-of-range Oney custom amounts stop being saved), so it likely deserves its own bugfix line under 5.2.0.Worth a specific look: the
module_files.csvfix touches a file the feature also needs, so the two changes overlap there. Happy to split theupgrade-5.1.0.phpline into its own PR if you'd rather keep this one single-purpose.Reused asset: the thresholds illustration reuses
views/img/oney/payplug-thresholds.jpg. It's a generic amount-range slider with no Oney branding — flagging in case design wants a Scalapay-specific one.