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
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,13 @@ PrestaShop 1.6.x, 1.7.x and 8.x

# Changelog

## [5.0.1]
### Fixed
- Fix: False "Payment service temporary unavailable" shown on redirect/wallet payments (MobilePay, Swish, Klarna, ApplePay) due to callback race condition, causing duplicate orders.
- Fix: Fatal error in `callbackform` when cart cannot be resolved, causing unnecessary gateway retries.
- Fix: Fatal error in `checkorderstatus` when cart cannot be resolved while polling for order status.
- Fix: `CheckoutSession` incorrectly called for Apple Pay payments; `setSessionID` now skipped when session is not applicable.

## [5.0.0]
### Added
- Add support for `checkoutSession` for reusable checkout sessions improving fraud detection and conversion.
Expand Down
111 changes: 91 additions & 20 deletions altapay.php
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ public function __construct()
{
$this->name = 'altapay';
$this->tab = 'payments_gateways';
$this->version = '5.0.0';
$this->version = '5.0.1';
$this->author = 'AltaPay A/S';
$this->is_eu_compatible = 1;
$this->ps_versions_compliancy = ['min' => '1.6.0.1', 'max' => '8.2.3'];
Expand Down Expand Up @@ -3186,21 +3186,15 @@ public function createTransaction($savecard,
$results = false;
}

$config = new API\PHP\Altapay\Request\Config();
$config->setCallbackOk($callback['callback_ok']);
$config->setCallbackFail($callback['callback_fail']);
$config->setCallbackOpen($callback['callback_open']);
$config->setCallbackNotification($callback['callback_notification']);
$config->setCallbackRedirect($callback['callback_redirect']);
$config->setCallbackForm($callback['callback_form']);

try {
$sessionRequest = new API\PHP\Altapay\Api\Payments\CheckoutSession(getAuth());
$sessionRequest->setTerminals([$cgConf['terminal']])
->setShopOrderId($requestShopOrderId)
->setAmount($requestAmount)
->setCurrency($cgConf['currency']);
$sessionResponse = $sessionRequest->call();
$sessionId = $sessionResponse->Session->Id;
$config = new API\PHP\Altapay\Request\Config();
$config->setCallbackOk($callback['callback_ok']);
$config->setCallbackFail($callback['callback_fail']);
$config->setCallbackOpen($callback['callback_open']);
$config->setCallbackNotification($callback['callback_notification']);
$config->setCallbackRedirect($callback['callback_redirect']);
$config->setCallbackForm($callback['callback_form']);
$request = new API\PHP\Altapay\Api\Ecommerce\PaymentRequest(getAuth());
if ($terminal->applepay) {
$response['apple_pay_terminal'] = true;
Expand Down Expand Up @@ -3230,11 +3224,12 @@ public function createTransaction($savecard,
$request->setAgreement(['type' => 'recurring']);
}

$this->createCheckoutSession($request, $requestShopOrderId, $requestAmount, $cgConf['currency'], $cgConf['terminal'], $cart->id);

$request->setType($type)->setTerminal($cgConf['terminal'])
->setShopOrderId($requestShopOrderId)
->setAmount($requestAmount)
->setCurrency($cgConf['currency'])
->setSessionID($sessionId)
->setCustomerInfo($customer)
->setTransactionInfo($transactionInfo)
->setCookie($cgConf['cookie'])
Expand All @@ -3244,7 +3239,7 @@ public function createTransaction($savecard,

if (!$isReservation) {
$request->setConfig($config)->setLanguage($cgConf['language']);
if (!$terminal->applepay) {
if ($request instanceof API\PHP\Altapay\Api\Ecommerce\PaymentRequest) {
$formTemplate = getFormTemplate();
if (!empty($formTemplate)) {
$request->setFormTemplate($formTemplate);
Expand All @@ -3253,9 +3248,8 @@ public function createTransaction($savecard,
}
try {
$response = $request->call();
$responseUrl = $response->Url ?? ($terminal->applepay ? 'cardwallet' : 'reservation');
$responseUrl = $response->Url ?? ($request instanceof API\PHP\Altapay\Api\Payments\CardWalletAuthorize ? 'cardwallet' : 'reservation');
$orderStatus = (int) Configuration::get('ALTAPAY_OS_PENDING');
// Handling for Apple Pay and reservation
if ($responseUrl === 'cardwallet' || $responseUrl === 'reservation') {
if (strtolower($response->Result) === 'success') {
$orderStatus = (int) Configuration::get('authorized_payments_status');
Expand Down Expand Up @@ -3292,7 +3286,7 @@ public function createTransaction($savecard,
$message = $e->getMessage();
}
} catch (API\PHP\Altapay\Exceptions\ClientException $e) {
$message = $e->getResponse()->getBody();
$message = (string) $e->getResponse()->getBody();
} catch (API\PHP\Altapay\Exceptions\ResponseHeaderException $e) {
$message = $e->getHeader()->ErrorMessage;
} catch (API\PHP\Altapay\Exceptions\ResponseMessageException $e) {
Expand All @@ -3306,6 +3300,83 @@ public function createTransaction($savecard,
return $response;
}

/**
* Builds the list of active terminal names for a CheckoutSession request.
*
* @param string $currentTerminal
* @param string $currency
* @param int $shopId
*
* @return string[]
*/
private function getActiveTerminals($currentTerminal, $currency, $shopId)
{
$activeTerminals = [];

if (!empty(trim($currentTerminal))) {
$activeTerminals[] = $currentTerminal;
}

$allActive = Altapay_Models_Terminal::getActiveTerminalsForCurrency($currency, $shopId);
foreach ($allActive as $t) {
$name = $t['remote_name'];
if (!empty(trim((string) $name)) && $name !== $currentTerminal) {
$activeTerminals[] = $name;
}
}

return $activeTerminals;
}

/**
* Calls CheckoutSession and sets the session ID on the request.
*
* @param mixed $request
* @param string $shopOrderId
* @param float $amount
* @param string $currency
* @param string $terminal
* @param int $cartId
*
* @return void
*/
private function createCheckoutSession($request, $shopOrderId, $amount, $currency, $terminal, $cartId)
{
if (!($request instanceof API\PHP\Altapay\Api\Ecommerce\PaymentRequest)) {
return;
}

$shopId = (int) Context::getContext()->shop->id ?: 1;
$activeTerminals = $this->getActiveTerminals($terminal, $currency, $shopId);

$sessionKey = 'altapay_checkout_session_id_' . $cartId;
$sessionId = Context::getContext()->cookie->{$sessionKey};

$sessionToken = rtrim(strtr(base64_encode(hex2bin(hash_hmac('sha256', (string) $cartId, _COOKIE_KEY_))), '+/', '-_'), '=');

if (empty($sessionId)) {
try {
$sessionRequest = new API\PHP\Altapay\Api\Payments\CheckoutSession(getAuth());
$sessionRequest->setTerminals($activeTerminals)
->setTerminal($terminal)
->setShopOrderId($shopOrderId)
->setAmount($amount)
->setCurrency($currency)
->setSessionId($sessionToken);
$sessionResponse = $sessionRequest->call();
$sessionId = $sessionResponse->Session->Id ?? null;
Context::getContext()->cookie->{$sessionKey} = $sessionId;
Context::getContext()->cookie->write();
} catch (Exception $e) {
PrestaShopLogger::addLog('CheckoutSession Exception: ' . $e->getMessage(), 3, null, $this->name, $this->id, true);
}
}

if ($sessionId) {
$request->setSessionID($sessionId);
}
}

/**
* @param array $arr
*
Expand Down
2 changes: 1 addition & 1 deletion composer.json
100755 → 100644
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
},
"require": {
"php": "^7.0",
"altapay/api-php": "^3.5.8",
"altapay/api-php": "^3.5.9",
"humbug/php-scoper": "0.13.9",
"nikic/php-parser": "4.x-dev",
"symfony/options-resolver": "^3.0",
Expand Down
Loading
Loading