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
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
# Changelog
All notable changes to this project will be documented in this file.

## [3.18]
- Add support for CheckoutSession (MarketPay) to associate a checkout session with the payment request.
## [3.17]
- Streamline and simplify management of order lines and amounts.
- Support for the new PayPal Integration.
Expand Down
106 changes: 106 additions & 0 deletions admin/controller/altapay/templates/catalog/controller/altapay.twig.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
use Altapay\Api\Ecommerce\Callback;
use Altapay\Api\Ecommerce\PaymentRequest;
use Altapay\Api\Payments\CaptureReservation;
use Altapay\Api\Payments\CheckoutSession;
use Altapay\Api\Payments\RefundCapturedReservation;
use Altapay\Api\Payments\ReleaseReservation;
use Altapay\Exceptions\ClientException;
Expand Down Expand Up @@ -270,7 +271,40 @@ public function confirm()

$customerInfo = $this->setCustomer($order_info);

// Stable identifier across order attempts in the same checkout flow.
$checkoutFlowId = 'order_' . (int)$order_info['order_id'];

$sessionKey = 'altapay_checkout_session_id_' . $checkoutFlowId;
$sessionId = isset($this->session->data[$sessionKey]) ? $this->session->data[$sessionKey] : '';

if (empty($sessionId)) {
try {
$activeTerminals = $this->getActiveTerminalNames();
$sessionId = $this->getHashedCheckoutSessionId($checkoutFlowId);
$marketPaySession = new CheckoutSession($this->getAuth());
$marketPaySession->setTerminals($activeTerminals)
->setTerminal($this->terminal_key)
->setShopOrderId($order_info['order_id'])
->setAmount((float)$amount)
->setCurrency($currency)
->setSessionId($sessionId);

$checkoutResponse = $marketPaySession->call();
if (isset($checkoutResponse->Session->Id)) {
$sessionId = $checkoutResponse->Session->Id;
}
$this->session->data[$sessionKey] = $sessionId;
} catch (\Exception $e) {
error_log('AltaPay checkout session creation failed for order ' . $order_info['order_id'] . ': ' . $e->getMessage());
}
}

$request = new PaymentRequest($this->getAuth());

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

$request->setTerminal($this->terminal_key)
->setShopOrderId($order_info['order_id'])
->setAmount($totalOrderAmount)
Expand Down Expand Up @@ -316,6 +350,76 @@ public function confirm()
}
}

/**
* Build list of active AltaPay terminal names (current terminal first).
*
* @return array
*/
private function getActiveTerminalNames()
{
$activeTerminals = array();
$currentTerminalName = $this->terminal_key;
if (!empty(trim((string)$currentTerminalName))) {
$activeTerminals[] = $currentTerminalName;
}

$rows = $this->db->query("SELECT `key`, `value` FROM " . DB_PREFIX . "setting WHERE `key` LIKE 'payment\\_Altapay\\_%\\_status' OR `key` LIKE 'payment\\_Altapay\\_%\\_title'");

$statuses = array();
$titles = array();
if ($rows->num_rows) {
foreach ($rows->rows as $row) {
if (preg_match('/^payment_Altapay_(.+)_status$/', $row['key'], $m)) {
$statuses[$m[1]] = $row['value'];
} elseif (preg_match('/^payment_Altapay_(.+)_title$/', $row['key'], $m)) {
$titles[$m[1]] = $row['value'];
}
}
}

foreach ($statuses as $termKey => $status) {
if ((string)$status !== '1' || !isset($titles[$termKey])) {
continue;
}
$name = $titles[$termKey];
if (!empty(trim((string)$name)) && $name !== $currentTerminalName) {
$activeTerminals[] = $name;
}
}

return $activeTerminals;
}

/**
* Generate a non-predictable checkout session id for AltaPay.
*
* Uses the OpenCart checkout session id plus the OpenCart encryption secret
* so the resulting value is stable for the same checkout flow and not guessable.
*
* @param string $checkoutFlowId
*
* @return string
*/
private function getHashedCheckoutSessionId($checkoutFlowId)
{
$salt = $this->config->get('config_encryption');
$raw = $checkoutFlowId . '|' . $salt;
return substr(hash('sha256', $raw), 0, 30);
}

/**
* Clear AltaPay checkout session data from OpenCart session.
*
*/
private function clearAltaPayCheckoutSessionData()
{
foreach ($this->session->data as $key => $value) {
if (strpos($key, 'altapay_checkout_session_id_') === 0) {
unset($this->session->data[$key]);
}
}
}

/**
* @param array $order_info
*
Expand Down Expand Up @@ -476,6 +580,8 @@ public function accept()

$this->model_checkout_order->addOrderHistory($order_id, $this->config->get('payment_Altapay_{key}_order_status_id'), $comment, true);

$this->clearAltaPayCheckoutSessionData();

// Redirect to order success
$this->response->redirect($this->url->link('checkout/success', 'user_token=' . $this->session->data['user_token'], true));
}
Expand Down
2 changes: 1 addition & 1 deletion admin/controller/traits/traits.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ public function transactionInfo($transactionInfo = array())
'ecomPlatform' => 'OpenCart',
'ecomVersion' => VERSION,
'altapayPluginName' => 'AltaPay',
'altapayPluginVersion' => '3.17',
'altapayPluginVersion' => '3.18',
'otherInfo' => $otherinfo,
);

Expand Down
2 changes: 1 addition & 1 deletion catalog/traits/traits.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ public function transactionInfo($transactionInfo = array())
'ecomPlatform' => 'OpenCart',
'ecomVersion' => VERSION,
'altapayPluginName' => 'AltaPay',
'altapayPluginVersion' => '3.17',
'altapayPluginVersion' => '3.18',
'otherInfo' => $otherinfo,
);

Expand Down
2 changes: 1 addition & 1 deletion composer.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"require": {
"altapay/api-php": "^3.2"
"altapay/api-php": "^3.6"
},
"config": {
"vendor-dir": "altapay-libs"
Expand Down
28 changes: 14 additions & 14 deletions composer.lock

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

8 changes: 5 additions & 3 deletions tests/integration-tests/cypress/e2e/PageObjects/objects.cy.js
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,6 @@ class Order {
cy.get('#button-payment-method').click()
cy.get('#button-confirm').click()
cy.get('[id=creditCardNumberInput]').type('4111111111111111')
cy.get('#emonth').type('01')
cy.get('#eyear').type('2023')
cy.get('#cvcInput').type('123')
cy.get('#cardholderNameInput').type('testname')
cy.get('#pensioCreditCardPaymentSubmitButton').click().wait(2000)
Expand Down Expand Up @@ -90,7 +88,11 @@ class Order {
cy.get('#input-username').type(admin.adminUsername)
cy.get('#input-password').type(admin.adminPass)
cy.get('.btn').click()
cy.get('.close').click()
cy.get('body').then(($body) => {
if ($body.find('.close').length > 0) {
cy.get('.close').click()
}
})
cy.get('h1').should('have.text', 'Dashboard')
})
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,6 @@ class Order {
cy.get('#button-payment-method').click()
cy.get('#button-confirm').click()
cy.get('[id=creditCardNumberInput]').type('4111111111111111')
cy.get('#emonth').type('01')
cy.get('#eyear').type('2023')
cy.get('#cvcInput').type('123')
cy.get('#cardholderNameInput').type('testname')
cy.get('#pensioCreditCardPaymentSubmitButton').click().wait(2000)
Expand Down
Loading