Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 7 additions & 3 deletions changelog.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
# Payplug module changelog
## Unreleased
## Version 5.2.0
- Feature :
- [PRE-3601](https://payplug-prod.atlassian.net/browse/PRE-3601): Let the merchant narrow the Scalapay amount range from the back office, and hide Scalapay at checkout for carts outside it

- Bugfix :
- [PRE-3557](https://payplug-prod.atlassian.net/browse/PRE-3557): Don't create an order (and send the confirmation email) until a card payment is confirmed paid, deferred or Oney; let late payment failures cancel the order instead of being silently dropped
- [PRE-3580](https://payplug-prod.atlassian.net/browse/PRE-3580): Stop answering 500 (retried in a loop by PayPlug) to a replayed IPN for a failed payment whose cart association was already replaced by a newer attempt
- [PRE-3601](https://payplug-prod.atlassian.net/browse/PRE-3601): Stop `FilesHelper::clean()` from deleting `upgrade/upgrade-5.1.0.php`, which was missing from the module file list

## Version 5.1.0
- Feature :
Expand All @@ -11,6 +13,8 @@
- Bugfix :
- [PRE-3456](https://github.com/payplug/payplug-prestashop/pull/109): Wait for Oney widget to respond before trying to show it
- [PRE-3531](https://github.com/payplug/payplug-prestashop/pull/107): Use UPC amount converter
- [PRE-3557](https://payplug-prod.atlassian.net/browse/PRE-3557): Don't create an order (and send the confirmation email) until a card payment is confirmed paid, deferred or Oney; let late payment failures cancel the order instead of being silently dropped
- [PRE-3580](https://payplug-prod.atlassian.net/browse/PRE-3580): Stop answering 500 (retried in a loop by PayPlug) to a replayed IPN for a failed payment whose cart association was already replaced by a newer attempt

- Refactoring :
- [PRE-3584](https://github.com/payplug/payplug-prestashop/pull/108): Optimize plugin size
Expand Down
2 changes: 1 addition & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"name": "payplug/payplug-prestashop",
"moduleName": "payplug",
"description": "Payplug: The online payment solution combining simplicity and first-rate support to boost your sales",
"version": "5.1.0",
"version": "5.2.0",
"require": {
"php": ">=7.4.0",
"payplug/payplug-php": "^4.0",
Expand Down
2 changes: 2 additions & 0 deletions module_files.csv
Original file line number Diff line number Diff line change
Expand Up @@ -14376,6 +14376,8 @@ upgrade/upgrade-4.4.0.php
upgrade/upgrade-4.7.1.php
upgrade/upgrade-4.8.0.php
upgrade/upgrade-4.9.0.php
upgrade/upgrade-5.1.0.php
upgrade/upgrade-5.2.0.php
vendor/autoload.php
vendor/composer/ClassLoader.php
vendor/composer/InstalledVersions.php
Expand Down
12 changes: 6 additions & 6 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "payplug",
"version": "5.1.0",
"version": "5.2.0",
"description": "======================================== Prestashop paiement module using Payplug ========================================",
"private": true,
"directories": {
Expand Down Expand Up @@ -37,7 +37,7 @@
"webpack-fix-style-only-entries": "^0.6.1"
},
"dependencies": {
"payplug-ui-plugins-bo": "^2.1.0",
"payplug-ui-plugins-bo": "^2.3.0",
"replace-in-file-webpack-plugin": "^1.0.6",
"webpack-remove-empty-scripts": "^1.0.0"
},
Expand Down
2 changes: 1 addition & 1 deletion payplug.php
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ public function __construct()
$this->module_key = '1ee28a8fb5e555e274bd8c2e1c45e31a';
$this->need_instance = 0;
$this->tab = 'payments_gateways';
$this->version = '5.1.0';
$this->version = '5.2.0';

if (version_compare(_PS_VERSION_, '8', '<')) {
$this->ps_versions_compliancy = ['min' => '1.7', 'max' => '1.7'];
Expand Down
84 changes: 83 additions & 1 deletion src/actions/ConfigurationAction.php
Original file line number Diff line number Diff line change
Expand Up @@ -811,6 +811,55 @@ public function saveAction($datas = null)
}
}

// Scalapay amounts reach us in euros from the back office. The merchant may only
// narrow the range their Payplug account authorizes (from GET /account), never
// widen it, and a minimum above the maximum would hide the method for every cart.
// This gate must stay as wide as the one guarding persistence in the switch-case
// below, which saves each amount on its own: a payload carrying a single amount
// would otherwise be persisted unvalidated.
if (isset($datas->enable_scalapay)
&& (bool) $datas->enable_scalapay
&& (isset($datas->scalapay_min_amounts) || isset($datas->scalapay_max_amounts))) {
$scalapay = $this->dependencies
->getPlugin()
->getPaymentMethodClass()
->getPaymentMethod('scalapay');
$account_limits = $scalapay->getScalapayPriceLimit(false);
// An amount the payload leaves out keeps the value in force, so the bounds
// are still compared against each other on a partial payload. A bound the
// account does not expose comes back as false, hence 0 once cast, which
// isAmount() rejects: an unusable range fails the save rather than passing it.
$limits_in_force = $scalapay->getScalapayPriceLimit();
$amount_helper = $this->dependencies
->getPlugin()
->getModule()
->getInstanceByName($this->dependencies->name)
->getService('payplug.utilities.helper.amount');
$scalapay_min = isset($datas->scalapay_min_amounts)
? (int) $amount_helper->convertAmount($datas->scalapay_min_amounts)
: (int) $limits_in_force['min'];
$scalapay_max = isset($datas->scalapay_max_amounts)
? (int) $amount_helper->convertAmount($datas->scalapay_max_amounts)
: (int) $limits_in_force['max'];
$payment_validator = $this->dependencies->getValidators()['payment'];

if ($scalapay_min > $scalapay_max
|| !$payment_validator->isAmount($scalapay_min, $account_limits)['result']
|| !$payment_validator->isAmount($scalapay_max, $account_limits)['result']) {
Comment thread
adumont-payplug marked this conversation as resolved.
$logger->addLog('ConfigurationAction::saveAction: Scalapay amounts are outside the range authorized by the account.');

return [
'success' => false,
'data' => [
'title' => null,
'msg' => $translation['scalapay']['thresholds']['text'],
'close' => $translation['scalapay']['thresholds']['submit'],
'class' => '-error',
],
];
}
}

$configuration = $this->dependencies->getPlugin()->getConfigurationClass();
$configuration_keys = [
'deferred_state' => 'payplug_deferred_state',
Expand All @@ -825,6 +874,8 @@ public function saveAction($datas = null)
'sandbox_mode' => 'payplug_sandbox',
'oney_custom_min_amounts' => 'oney_min_amounts',
'oney_custom_max_amounts' => 'oney_max_amounts',
'scalapay_custom_min_amounts' => 'scalapay_min_amounts',
'scalapay_custom_max_amounts' => 'scalapay_max_amounts',
'bancontact_country' => 'enable_bancontact_country',
'applepay_carriers' => 'applepay_carriers',
'applepay_display' => 'enable_applepay',
Expand Down Expand Up @@ -883,6 +934,8 @@ public function saveAction($datas = null)
->getInstanceByName($this->dependencies->name)
->getService('payplug.utilities.helper.amount')
->convertAmount($amount);
// isAmount() answers with ['result' => bool, 'message' => string];
// the array itself is always truthy, so the flag has to be read out.
$is_valid_amount = $this->dependencies
->getValidators()['payment']
->isAmount((int) $amount_to_cent, $limit_oney);
Expand All @@ -892,7 +945,36 @@ public function saveAction($datas = null)
->getPaymentMethod('oney')
->setCustomOneyLimit((int) $amount_to_cent);

if ($is_valid_amount && !$configuration->set($key, (string) $formated_amount)) {
if ($is_valid_amount['result'] && !$configuration->set($key, (string) $formated_amount)) {
return [
'success' => false,
'data' => [
// todo: add translation
'message' => 'An error has occurred while register ' . $config,
],
];
}
}

break;

case 'scalapay_min_amounts':
case 'scalapay_max_amounts':
// Already validated above, under a gate matching this one.
if (isset($datas->enable_scalapay) && (bool) $datas->enable_scalapay) {
$amount_to_cent = $this->dependencies
->getPlugin()
->getModule()
->getInstanceByName($this->dependencies->name)
->getService('payplug.utilities.helper.amount')
->convertAmount($value);
$formated_amount = $this->dependencies
->getPlugin()
->getPaymentMethodClass()
->getPaymentMethod('scalapay')
->setCustomScalapayLimit((int) $amount_to_cent);

if (!$configuration->set($key, (string) $formated_amount)) {
return [
'success' => false,
'data' => [
Expand Down
15 changes: 15 additions & 0 deletions src/models/classes/Configuration.php
Original file line number Diff line number Diff line change
Expand Up @@ -378,6 +378,21 @@ class Configuration
'defaultValue' => '{"amex":false,"applepay":false,"bancontact":false,"deferred":false,"installment":false,"ideal":false,"mybank":false,"one_click":false,"oney":false,"satispay":false,"standard":true,"wero":false,"bizum":false,"scalapay":false}',
'setConf' => 1,
],
'scalapay_custom_max_amounts' => [
'type' => 'string',
'name' => 'SCALAPAY_CUSTOM_MAX_AMOUNTS',
// Empty means the merchant never customised the limit: the account's own
// authorized range from GET /account applies as-is. It must NOT default to a
// concrete amount, or that amount would read as an explicit override.
'defaultValue' => '',
'setConf' => 1,
],
'scalapay_custom_min_amounts' => [
'type' => 'string',
'name' => 'SCALAPAY_CUSTOM_MIN_AMOUNTS',
'defaultValue' => '',
'setConf' => 1,
],
'sandbox_mode' => [
'type' => 'integer',
'name' => 'SANDBOX_MODE',
Expand Down
16 changes: 16 additions & 0 deletions src/models/classes/Translation.php
Original file line number Diff line number Diff line change
Expand Up @@ -285,6 +285,12 @@ public function getModalTranslations()
'submit' => $this->l('modal.applepay.carrier.submit', 'translation'),
],
],
'scalapay' => [
'thresholds' => [
'text' => $this->l('modal.scalapay.thresholds.text', 'translation'),
'submit' => $this->l('modal.scalapay.thresholds.submit', 'translation'),
],
],
'error' => [
'text' => $this->l('modal.error.text', 'translation'),
'submit' => $this->l('modal.error.submit', 'translation'),
Expand Down Expand Up @@ -674,6 +680,16 @@ public function getPaymentMethodsTranslations()
],
'link' => $this->l('paymentmethods.scalapay.link', 'translation'),
'call_to_action' => $this->l('paymentmethods.scalapay.call_to_action', 'translation'),
'thresholds' => [
'title' => $this->l('paymentmethods.scalapay.thresholds.title', 'translation'),
'description' => $this->l('paymentmethods.scalapay.thresholds.description', 'translation'),
'inter' => $this->l('paymentmethods.scalapay.thresholds.inter', 'translation'),
'error' => [
'default' => $this->l('paymentmethods.scalapay.thresholds.error.text', 'translation'),
'max' => $this->l('paymentmethods.scalapay.thresholds.error.max.text', 'translation'),
'min' => $this->l('paymentmethods.scalapay.thresholds.error.min.text', 'translation'),
],
],
],
];
}
Expand Down
23 changes: 19 additions & 4 deletions src/models/classes/paymentMethod/PaymentMethod.php
Original file line number Diff line number Diff line change
Expand Up @@ -1095,6 +1095,23 @@ public function saveResource($payment_tab = [])
return $payment;
}

/**
* @description Get the price limits authorized for the current payment method.
* Sourced from GET /account (min_amounts/max_amounts per payment method,
* in cents) and mapped in API::treatAccountResponse(). Payment methods the
* account exposes no specific range for fall back on the account default.
*
* @return array Limits as `ISO:amount` strings, e.g. `['min' => 'EUR:500', 'max' => 'EUR:400000']`
*/
public function getPriceLimit()
{
$this->setParameters();

$payplug_amounts = json_decode($this->configuration->getValue('amounts'), true);

return isset($payplug_amounts[$this->name]) ? $payplug_amounts[$this->name] : $payplug_amounts['default'];
}

/**
* @description Set object property
*
Expand Down Expand Up @@ -1394,8 +1411,7 @@ protected function getDefaultPaymentTab()
}

// Check amount
$payplug_amounts = json_decode($this->configuration->getValue('amounts'), true);
$price_limit = isset($payplug_amounts[$this->name]) ? $payplug_amounts[$this->name] : $payplug_amounts['default'];
$price_limit = $this->getPriceLimit();
$cart_amount = $this->context->cart->getOrderTotal(true);
$is_valid_amount = $this->dependencies
->getHelpers()['amount']
Expand Down Expand Up @@ -1626,8 +1642,7 @@ protected function getPaymentOption($payment_options = [])
}
}

$payplug_amounts = json_decode($this->configuration->getValue('amounts'), true);
$price_limit = isset($payplug_amounts[$this->name]) ? $payplug_amounts[$this->name] : $payplug_amounts['default'];
$price_limit = $this->getPriceLimit();
$cart_amount = $this->context->cart->getOrderTotal(true);
if (false === strpos($this->name, 'oney')) {
if (!$this->dependencies
Expand Down
Loading
Loading