Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
8c0caf4
fix(opc): restore module-owned checkout templates and handle displayC…
ThbPS May 5, 2026
99d1173
Imported needed templated from hummingbird and replaced includes with…
L3RAZ May 19, 2026
bc06004
Added hook for overriding checkout template
L3RAZ May 19, 2026
525fd78
Address feedback
L3RAZ May 20, 2026
ae3d9d7
removed is_one_page_checkout_enabled checks for classes
L3RAZ May 20, 2026
3e7ebb8
Replaced template copies with import from theme
L3RAZ May 20, 2026
794575f
Added back form-fields-row and removed file param from form-field
L3RAZ May 20, 2026
7b25d8f
Merge pull request #46 from PrestaShop/SPE-129
ThbPS May 21, 2026
8a44e26
Added wrappers for payment button and conditions checkboxes so core.j…
L3RAZ May 19, 2026
9a0d13b
Added OPC submit event
L3RAZ May 20, 2026
267636c
Implemented function export instead of event emits
L3RAZ May 22, 2026
9b406c3
Apply feedback
L3RAZ May 26, 2026
a619f90
Merge pull request #47 from PrestaShop/SPE-133
L3RAZ May 26, 2026
cbfedef
Added payment_html comparison
L3RAZ May 20, 2026
b46af43
Reworked payment option loader to not overwrite payment dom
L3RAZ May 21, 2026
82ff114
Reintroduced fetchPaymentMethods because it no longer emits duplicate…
L3RAZ May 21, 2026
0112a5e
Apply feedack
L3RAZ May 22, 2026
d17513c
Added new event for refreshing button state after payment fetch
L3RAZ May 22, 2026
a66f238
Merge pull request #48 from PrestaShop/SPE-134
L3RAZ May 26, 2026
c58ff4d
fix: prefix OPC form field row classes
ThbPS May 26, 2026
ece5419
fix: port Hummingbird address modal fields fix
ThbPS May 26, 2026
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
20 changes: 17 additions & 3 deletions ps_onepagecheckout.php
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,8 @@ public function install()
&& $this->registerHook('actionCheckoutBuildProcess')
&& $this->registerHook('actionFrontControllerSetMedia')
&& $this->registerHook('actionFrontControllerSetVariables')
&& $this->registerHook('actionModuleUpgradeAfter');
&& $this->registerHook('actionModuleUpgradeAfter')
&& $this->registerHook('displayOverrideTemplate');
}

public function enable($force_all = false)
Expand Down Expand Up @@ -152,7 +153,7 @@ public function hookActionCheckoutBuildProcess(array $params = []): CheckoutProc

public function hookActionFrontControllerSetMedia(): void
{
if (!isset($this->context->controller) || $this->context->controller->php_self !== 'order') {
if (!isset($this->context->controller) || !$this->context->controller instanceof OrderController) {
return;
}

Expand Down Expand Up @@ -292,7 +293,7 @@ public function hookActionFrontControllerSetMedia(): void

public function hookActionFrontControllerSetVariables(array $params): void
{
if (!isset($this->context->controller) || $this->context->controller->php_self !== 'order') {
if (!isset($this->context->controller) || !$this->context->controller instanceof OrderController) {
return;
}

Expand All @@ -303,6 +304,19 @@ public function hookActionFrontControllerSetVariables(array $params): void
$params['templateVars']['is_one_page_checkout_enabled'] = $this->isOnePageCheckoutEnabled();
}

public function hookDisplayOverrideTemplate(array $params)
{
if (
$this->isOnePageCheckoutEnabled()
&& $params['template_file'] === 'checkout/checkout'
&& $params['controller'] instanceof OrderController
) {
return 'module:ps_onepagecheckout/views/templates/front/checkout/checkout.tpl';
}

return null;
}

public function isOnePageCheckoutEnabled(): bool
{
return (new OnePageCheckoutAvailability(self::CONFIG_ONE_PAGE_CHECKOUT_ENABLED))->isEnabled();
Expand Down
19 changes: 19 additions & 0 deletions src/Checkout/CheckoutOnePageStep.php
Original file line number Diff line number Diff line change
Expand Up @@ -277,6 +277,7 @@ public function render(array $extraParams = [])
'isGift' => $this->getCheckoutSession()->getGift()['isGift'],
'message' => $this->getCheckoutSession()->getGift()['message'],
],
'opc_urls' => $this->getOpcUrls(),
'is_virtual_cart' => $this->context->cart->isVirtualCart(),
'configuration' => $this->getTemplateConfiguration(),
] + $this->opcForm->getTemplateVariables();
Expand All @@ -302,6 +303,24 @@ private function getSelectedPaymentSelectionKey(): string
return (string) ($this->context->cookie->__get('opc_selected_payment_selection_key') ?: '');
}

/**
* @return array{authentication: string, registration: string}
*/
private function getOpcUrls(): array
{
$backParams = [];
$orderPageUrl = $this->context->link->getPageLink('order', true);

if (is_string($orderPageUrl) && \Tools::urlBelongsToShop($orderPageUrl)) {
$backParams = ['back' => $orderPageUrl];
}

return [
'authentication' => $this->context->link->getPageLink('authentication', true, null, $backParams),
'registration' => $this->context->link->getPageLink('registration', true, null, $backParams),
];
}

private function restoreLastFailedSubmitState(): void
{
$submitState = $this->submitValidationStateStorage->consume();
Expand Down
3 changes: 3 additions & 0 deletions src/Form/OnePageCheckoutForm.php
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,9 @@ class OnePageCheckoutForm extends \AbstractForm
*/
protected $formatter;

/**
* @var \Context
*/
private $context;
private $customerPersister;
private $addressPersister;
Expand Down
14 changes: 14 additions & 0 deletions tests/php/Unit/Checkout/CheckoutOnePageStepRenderTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,18 @@ public function __get(string $name)
return '';
}
};
$link = $this->createMock(\Link::class);
$link->method('getPageLink')
->willReturnCallback(static function ($controller, $ssl = null, $idLang = null, $request = null, $requestUrlEncode = false, $idShop = null, $relativeProtocol = false): string {
$url = '/' . $controller;

if (is_array($request) && $request !== []) {
$url .= '?' . http_build_query($request);
}

return $url;
});
$context->link = $link;
$context->controller = new class {
public function getTemplateVarConfiguration(): array
{
Expand Down Expand Up @@ -186,6 +198,8 @@ protected function renderTemplate($template, array $extraParams = [], array $par
self::assertArrayHasKey('deliveryFields', $step->capturedParams);
self::assertArrayHasKey('invoiceFields', $step->capturedParams);
self::assertArrayHasKey('errors', $step->capturedParams);
self::assertSame('/authentication?back=%2Forder', $step->capturedParams['opc_urls']['authentication']);
self::assertSame('/registration?back=%2Forder', $step->capturedParams['opc_urls']['registration']);
self::assertArrayHasKey('configuration', $step->capturedParams);
self::assertArrayHasKey('is_guest_checkout_enabled', $step->capturedParams['configuration']);
self::assertIsBool($step->capturedParams['configuration']['is_guest_checkout_enabled']);
Expand Down
100 changes: 0 additions & 100 deletions tests/php/Unit/Js/OpcJavascriptContractTest.php

This file was deleted.

22 changes: 19 additions & 3 deletions tests/php/Unit/Module/PsOnepagecheckoutModuleTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ public function testInstallInitializesDisabledFlagRegistersHooksAndCallsParentIn
'actionFrontControllerSetMedia',
'actionFrontControllerSetVariables',
'actionModuleUpgradeAfter',
'displayOverrideTemplate',
], $module->registerHookCalls);
}

Expand Down Expand Up @@ -122,7 +123,7 @@ public function testHookActionFrontControllerSetVariablesInjectsRuntimeFlagOnOrd
$module = $this->createModule();
$module->isEnabled = true;
$module->setModuleContext((object) [
'controller' => (object) ['php_self' => 'order'],
'controller' => new DummyOrderController(),
]);

$templateVars = [];
Expand All @@ -139,7 +140,7 @@ public function testHookActionFrontControllerSetMediaAssignsFlagAndRegistersAsse
$module->name = 'ps_onepagecheckout';
$module->isEnabled = true;
$module->setModuleContext((object) [
'controller' => (object) ['php_self' => 'order'],
'controller' => new DummyOrderController(),
'smarty' => new DummySmarty(),
'link' => new DummyLink(),
]);
Expand All @@ -151,6 +152,7 @@ public function testHookActionFrontControllerSetMediaAssignsFlagAndRegistersAsse
self::assertTrue($smarty->assigned['is_one_page_checkout_enabled']);
self::assertCount(1, $module->javascriptDefinitions);
self::assertSame(1, $module->registeredJavascriptAssetsCalls);
self::assertSame(1, $module->registeredStylesheetAssetsCalls);
self::assertArrayHasKey('ps_onepagecheckout', $module->javascriptDefinitions[0]);
self::assertNotEmpty($module->javascriptDefinitions[0]['ps_onepagecheckout']['urls']['guestInit']);
self::assertNotEmpty($module->javascriptDefinitions[0]['ps_onepagecheckout']['urls']['addressForm']);
Expand All @@ -171,7 +173,7 @@ public function testHookActionFrontControllerSetMediaAssignsFlagAndSkipsAssetsWh
$module->name = 'ps_onepagecheckout';
$module->isEnabled = false;
$module->setModuleContext((object) [
'controller' => (object) ['php_self' => 'order'],
'controller' => new DummyOrderController(),
'smarty' => new DummySmarty(),
'link' => new DummyLink(),
]);
Expand All @@ -183,6 +185,7 @@ public function testHookActionFrontControllerSetMediaAssignsFlagAndSkipsAssetsWh
self::assertFalse($smarty->assigned['is_one_page_checkout_enabled']);
self::assertCount(0, $module->javascriptDefinitions);
self::assertSame(0, $module->registeredJavascriptAssetsCalls);
self::assertSame(0, $module->registeredStylesheetAssetsCalls);
}

public function testMainModuleFileDoesNotContainCustomAutoloaderRegistration(): void
Expand Down Expand Up @@ -228,6 +231,7 @@ class TestablePsOnepagecheckoutModule extends \Ps_Onepagecheckout
public array $javascriptDefinitions = [];

public int $registeredJavascriptAssetsCalls = 0;
public int $registeredStylesheetAssetsCalls = 0;
public bool $isEnabled = true;
public int $disableCurrentContextCalls = 0;
public bool $disableCurrentContextResult = true;
Expand Down Expand Up @@ -294,6 +298,11 @@ protected function registerOpcJavascriptAssets(): void
++$this->registeredJavascriptAssetsCalls;
}

protected function registerOpcStylesheets(): void
{
++$this->registeredStylesheetAssetsCalls;
}

protected function disableInParent(bool $forceAll): bool
{
$this->disableInParentCalls[] = $forceAll;
Expand Down Expand Up @@ -339,6 +348,13 @@ public function assign($key, $value = null): void
}
}

class DummyOrderController extends \OrderController
{
public function __construct()
{
}
}

class DummyLink
{
/**
Expand Down
1 change: 1 addition & 0 deletions views/js/events.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ const OPC_EVENTS = {
opcCarriersLoading: 'opcCarriersLoading',
opcPaymentMethodsLoading: 'opcPaymentMethodsLoading',
opcPaymentMethodsUpdated: 'opcPaymentMethodsUpdated',
opcPaymentMethodsRefreshed: 'opcPaymentMethodsRefreshed',
opcPaymentMethodsFailed: 'opcPaymentMethodsFailed',
opcPaymentMethodSelected: 'opcPaymentMethodSelected',
opcGuestInitSuccess: 'opcGuestInitSuccess',
Expand Down
4 changes: 2 additions & 2 deletions views/js/opc-address-modal.js
Original file line number Diff line number Diff line change
Expand Up @@ -454,7 +454,7 @@ function updateStateFieldUi($modal, response, selectedStateId) {
$wrapper.hide();
$select.prop('required', false).val('');
if ($row.length) {
$row.removeClass('form-fields-row--3').addClass('form-fields-row--2');
$row.removeClass('opc-form-fields-row--3').addClass('opc-form-fields-row--2');
}

return;
Expand All @@ -476,7 +476,7 @@ function updateStateFieldUi($modal, response, selectedStateId) {
$wrapper.show();
$select.prop('required', true);
if ($row.length) {
$row.removeClass('form-fields-row--2').addClass('form-fields-row--3');
$row.removeClass('opc-form-fields-row--2').addClass('opc-form-fields-row--3');
}
}

Expand Down
8 changes: 5 additions & 3 deletions views/js/opc-carrier-list.js
Original file line number Diff line number Diff line change
Expand Up @@ -133,10 +133,12 @@ function fetchCarriers() {

const checkedCarrier = $container.find(`${OPC_SELECTORS.inputs.deliveryOption}:checked`).get(0);
if (checkedCarrier) {
$container.attr('data-confirmed-delivery-option', String(checkedCarrier.value || ''));
const selectedDeliveryOption = String(checkedCarrier.value || '');

$container.attr('data-confirmed-delivery-option', selectedDeliveryOption);
prestashop.emit(OPC_EVENTS.opcCarrierSelected, {
carrierId: checkedCarrier.value,
resp: response,
selectedDeliveryOption,
response,
});
} else {
$container.removeAttr('data-confirmed-delivery-option');
Expand Down
13 changes: 12 additions & 1 deletion views/js/opc-carrier-select.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,9 @@ if (!$) {
const CONTAINER_SELECTOR = OPC_SELECTORS.opc.deliveryMethods;
const URL_KEY = 'selectCarrier';
const CHECKOUT_FORM_SELECTOR = OPC_SELECTORS.opc.checkout;
const OPC_FORM_SELECTOR = OPC_SELECTORS.opc.form;
const DELIVERY_ADDRESS_SECTION_SELECTOR = OPC_SELECTORS.opc.deliverySection;
const DELIVERY_OPTION_SELECTOR = '.js-delivery-option';
const CONFIRMED_DELIVERY_OPTION_ATTRIBUTE = 'data-confirmed-delivery-option';

function getDeliveryAddressSection() {
Expand Down Expand Up @@ -113,7 +115,16 @@ $(document).on('change', `${CONTAINER_SELECTOR} ${OPC_SELECTORS.inputs.deliveryO
updateCartSummary(response.preview, response.totals);
}
setConfirmedDeliveryOption($container, deliveryOption);
prestashop.emit(OPC_EVENTS.opcCarrierSelected, response);
// Keep existing themes compatible with the 4-step checkout carrier lifecycle.
prestashop.emit('updatedDeliveryForm', {
dataForm: $(OPC_FORM_SELECTOR).serializeArray(),
deliveryOption: $radio.closest(DELIVERY_OPTION_SELECTOR),
resp: response,
});
prestashop.emit(OPC_EVENTS.opcCarrierSelected, {
selectedDeliveryOption: deliveryOption,
response,
});
})
.fail((jqXHR) => {
restoreConfirmedDeliveryOption($container);
Expand Down
Loading
Loading