7 Commits

Author SHA1 Message Date
Arne Weiss 22978ad714 Bump version to 0.1.8
Build / build (push) Successful in 15s
Release / release (push) Successful in 12s
2026-06-01 10:02:15 +02:00
Arne Weiss b8c0db4067 Fix DB insert: remove add_prefix=false so table prefix is applied
Db::insert() was called with add_prefix=false, causing it to target
'simple_withdrawal_request' instead of '{prefix}simple_withdrawal_request'.
Dropping the explicit false restores the default (true).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-01 10:01:47 +02:00
Arne Weiss f74bf7a73f Bump version to 0.1.7
Build / build (push) Successful in 13s
Release / release (push) Successful in 12s
2026-06-01 09:57:08 +02:00
Arne Weiss 18636c13c0 Bump version to 0.1.6 2026-06-01 09:56:25 +02:00
Arne Weiss 4597e96545 Fix layout: add Smarty template inheritance for Hummingbird theme
Hummingbird (PS8) requires module front controller templates to explicitly
extend a layout via {extends}. Without it, the template renders as a bare
HTML fragment without the theme wrapper (no header, CSS, nav, footer).

All three front templates now extend layouts/layout-full-width.tpl and
define their content inside {block name='content'}.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-01 09:56:25 +02:00
Arne Weiss 9bd62125d5 Bump version to 0.1.5
Build / build (push) Successful in 14s
Release / release (push) Successful in 12s
2026-06-01 08:52:56 +02:00
Arne Weiss 058937bd64 Add CSS hook, URL ref prefill, order prefill, and Widerrufsfrist display
- Fix CSS loading: register stylesheet via actionFrontControllerSetMedia
  hook instead of initContent() — guaranteed to fire before page render
- Upgrade script registers new hook on existing installations
- Feature 1: pre-fill order_reference from ?ref= URL parameter
- Feature 2: pre-fill customer name/email from logged-in account when
  navigating with ?ref= (already worked; now order ref is also pre-filled)
- Feature 4: compute Widerrufsfrist (order date +14 days) from DB and
  display on form (when ref in URL), confirm, and success pages
- Feature 3: EN mail templates were already present

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-01 08:52:53 +02:00
7 changed files with 147 additions and 14 deletions
+23 -7
View File
@@ -26,12 +26,6 @@ class Simple_withdrawalbuttonWithdrawModuleFrontController extends ModuleFrontCo
{ {
parent::initContent(); parent::initContent();
$this->registerStylesheet(
'cyp-withdrawal',
'modules/' . $this->module->name . '/views/css/withdrawal.css',
['media' => 'all', 'priority' => 200]
);
$this->context->smarty->assign([ $this->context->smarty->assign([
'errors_list' => $this->errorsList, 'errors_list' => $this->errorsList,
'form_data' => $this->formData, 'form_data' => $this->formData,
@@ -40,6 +34,7 @@ class Simple_withdrawalbuttonWithdrawModuleFrontController extends ModuleFrontCo
'success_data' => $this->successData, 'success_data' => $this->successData,
'privacy_url' => (string) Configuration::get(Simple_withdrawalbutton::CONF_PRIVACY_URL), 'privacy_url' => (string) Configuration::get(Simple_withdrawalbutton::CONF_PRIVACY_URL),
'revocation_url' => (string) Configuration::get(Simple_withdrawalbutton::CONF_REVOCATION_URL), 'revocation_url' => (string) Configuration::get(Simple_withdrawalbutton::CONF_REVOCATION_URL),
'withdrawal_deadline' => $this->computeDeadline(),
]); ]);
if ($this->currentView === 'confirm') { if ($this->currentView === 'confirm') {
@@ -185,16 +180,37 @@ class Simple_withdrawalbuttonWithdrawModuleFrontController extends ModuleFrontCo
$customerEmail = (string) $this->context->customer->email; $customerEmail = (string) $this->context->customer->email;
} }
$orderRef = $this->module->cleanText(Tools::getValue('ref'), 64);
return [ return [
'customer_name' => $customerName, 'customer_name' => $customerName,
'customer_email' => $customerEmail, 'customer_email' => $customerEmail,
'order_reference' => '', 'order_reference' => $orderRef,
'withdrawal_scope' => 'full', 'withdrawal_scope' => 'full',
'withdrawal_items_text' => '', 'withdrawal_items_text' => '',
'message' => '', 'message' => '',
]; ];
} }
private function computeDeadline()
{
$ref = isset($this->formData['order_reference']) ? $this->formData['order_reference'] : '';
if ($ref === '') {
$ref = $this->module->cleanText(Tools::getValue('ref'), 64);
}
if ($ref === '') {
return '';
}
$orderInfo = $this->module->lookupOrderInfoByReference($ref);
if (!$orderInfo) {
return '';
}
$isoCode = Language::getIsoById((int) $this->context->language->id) ?: 'de';
return (string) $this->module->computeWithdrawalDeadline($orderInfo['date_add'], $isoCode);
}
private function validateData(array $data) private function validateData(array $data)
{ {
$errors = []; $errors = [];
+54 -2
View File
@@ -27,7 +27,7 @@ class Simple_withdrawalbutton extends Module
{ {
$this->name = 'simple_withdrawalbutton'; $this->name = 'simple_withdrawalbutton';
$this->tab = 'administration'; $this->tab = 'administration';
$this->version = '0.1.4'; $this->version = '0.1.8';
$this->author = 'Arne Weiss'; $this->author = 'Arne Weiss';
$this->need_instance = 0; $this->need_instance = 0;
$this->bootstrap = true; $this->bootstrap = true;
@@ -50,6 +50,7 @@ class Simple_withdrawalbutton extends Module
&& $this->installTab() && $this->installTab()
&& $this->registerHook('displayFooter') && $this->registerHook('displayFooter')
&& $this->registerHook('displayCustomerAccount') && $this->registerHook('displayCustomerAccount')
&& $this->registerHook('actionFrontControllerSetMedia')
&& Configuration::updateValue(self::CONF_SHOP_EMAIL, (string) Configuration::get('PS_SHOP_EMAIL')) && Configuration::updateValue(self::CONF_SHOP_EMAIL, (string) Configuration::get('PS_SHOP_EMAIL'))
&& Configuration::updateValue(self::CONF_RATE_LIMIT, '5') && Configuration::updateValue(self::CONF_RATE_LIMIT, '5')
&& Configuration::updateValue(self::CONF_PRIVACY_URL, '') && Configuration::updateValue(self::CONF_PRIVACY_URL, '')
@@ -295,6 +296,20 @@ class Simple_withdrawalbutton extends Module
return $this->display(__FILE__, 'views/templates/hook/customer_account.tpl'); return $this->display(__FILE__, 'views/templates/hook/customer_account.tpl');
} }
public function hookActionFrontControllerSetMedia()
{
if (
Tools::getValue('module') === $this->name
&& Tools::getValue('controller') === 'withdraw'
) {
$this->context->controller->registerStylesheet(
'cyp-withdrawal',
'modules/' . $this->name . '/views/css/withdrawal.css',
['media' => 'all', 'priority' => 200]
);
}
}
public function getWithdrawalLink() public function getWithdrawalLink()
{ {
return $this->context->link->getModuleLink($this->name, 'withdraw', [], true); return $this->context->link->getModuleLink($this->name, 'withdraw', [], true);
@@ -342,6 +357,43 @@ class Simple_withdrawalbutton extends Module
return $idOrder > 0 ? $idOrder : null; return $idOrder > 0 ? $idOrder : null;
} }
public function lookupOrderInfoByReference($orderReference)
{
$orderReference = $this->cleanText($orderReference, 64);
if ($orderReference === '') {
return null;
}
$sql = 'SELECT `id_order`, `date_add`, `id_customer`
FROM `' . _DB_PREFIX_ . 'orders`
WHERE `reference` = "' . pSQL($orderReference) . '"
AND `id_shop` = ' . (int) $this->context->shop->id . '
ORDER BY `id_order` DESC';
$row = Db::getInstance()->getRow($sql);
if (!$row) {
return null;
}
return [
'id_order' => (int) $row['id_order'],
'date_add' => $row['date_add'],
'id_customer' => (int) $row['id_customer'],
];
}
public function computeWithdrawalDeadline($orderDateAdd, $isoCode = 'de')
{
$timestamp = strtotime((string) $orderDateAdd);
if (!$timestamp) {
return null;
}
$deadline = strtotime('+14 days', $timestamp);
return ($isoCode === 'de') ? date('d.m.Y', $deadline) : date('d/m/Y', $deadline);
}
public function hashForPrivacy($value) public function hashForPrivacy($value)
{ {
$value = trim((string) $value); $value = trim((string) $value);
@@ -412,7 +464,7 @@ class Simple_withdrawalbutton extends Module
'user_agent_hash' => $userAgentHash ?: null, 'user_agent_hash' => $userAgentHash ?: null,
]; ];
$ok = Db::getInstance()->insert(self::TABLE_REQUEST, $insert, false, true, Db::INSERT, false); $ok = Db::getInstance()->insert(self::TABLE_REQUEST, $insert, false, true, Db::INSERT);
if (!$ok) { if (!$ok) {
return false; return false;
} }
+8
View File
@@ -0,0 +1,8 @@
<?php
header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT');
header('Cache-Control: no-store, no-cache, must-revalidate');
header('Cache-Control: post-check=0, pre-check=0', false);
header('Pragma: no-cache');
header('Location: ../');
exit;
+10
View File
@@ -0,0 +1,10 @@
<?php
if (!defined('_PS_VERSION_')) {
exit;
}
function upgrade_module_0_1_5($object)
{
return $object->registerHook('actionFrontControllerSetMedia');
}
+16 -1
View File
@@ -1,3 +1,6 @@
{extends file='layouts/layout-full-width.tpl'}
{block name='content'}
<section class="cyp-withdrawal-page"> <section class="cyp-withdrawal-page">
<header class="page-header"> <header class="page-header">
<h1>{l s='Widerruf bestätigen' mod='simple_withdrawalbutton'}</h1> <h1>{l s='Widerruf bestätigen' mod='simple_withdrawalbutton'}</h1>
@@ -5,7 +8,7 @@
<div class="cyp-steps"> <div class="cyp-steps">
<div class="cyp-step done"> <div class="cyp-step done">
<div class="cyp-step-bubble"></div> <div class="cyp-step-bubble">&#10003;</div>
<div class="cyp-step-label">{l s='Angaben' mod='simple_withdrawalbutton'}</div> <div class="cyp-step-label">{l s='Angaben' mod='simple_withdrawalbutton'}</div>
</div> </div>
<div class="cyp-step-line done"></div> <div class="cyp-step-line done"></div>
@@ -70,6 +73,17 @@
<div class="cyp-summary-val">{$form_data.message|escape:'html':'UTF-8'|nl2br nofilter}</div> <div class="cyp-summary-val">{$form_data.message|escape:'html':'UTF-8'|nl2br nofilter}</div>
</div> </div>
{/if} {/if}
{if isset($withdrawal_deadline) && $withdrawal_deadline != ''}
<div class="cyp-summary-row">
<div class="cyp-summary-key">{l s='Frist' mod='simple_withdrawalbutton'}</div>
<div class="cyp-summary-val" style="color:var(--cyw-accent);font-weight:600;">
{l s='bis' mod='simple_withdrawalbutton'} {$withdrawal_deadline|escape:'html':'UTF-8'}
<span style="font-size:12px;font-weight:400;color:var(--cyw-text-muted);">
({l s='14 Tage ab Bestelldatum' mod='simple_withdrawalbutton'})
</span>
</div>
</div>
{/if}
</div> </div>
<form method="post" action="{$action_url|escape:'html':'UTF-8'}"> <form method="post" action="{$action_url|escape:'html':'UTF-8'}">
@@ -96,3 +110,4 @@
</form> </form>
</div> </div>
</section> </section>
{/block}
+17
View File
@@ -1,3 +1,6 @@
{extends file='layouts/layout-full-width.tpl'}
{block name='content'}
<section class="cyp-withdrawal-page"> <section class="cyp-withdrawal-page">
<header class="page-header"> <header class="page-header">
<h1>{l s='Widerruf erklären' mod='simple_withdrawalbutton'}</h1> <h1>{l s='Widerruf erklären' mod='simple_withdrawalbutton'}</h1>
@@ -28,6 +31,19 @@
{/if} {/if}
</div> </div>
{if isset($withdrawal_deadline) && $withdrawal_deadline != ''}
<div class="cyp-deadline-notice" style="
display:flex; align-items:center; gap:10px; background:#eef2f8;
border:1px solid #c5d4eb; border-radius:6px; padding:11px 14px;
font-size:13px; color:var(--cyw-accent); margin-bottom:24px;">
<span style="font-size:16px;">&#128197;</span>
<span>
{l s='Widerrufsfrist (14 Tage ab Bestelldatum): bis' mod='simple_withdrawalbutton'}
<strong>{$withdrawal_deadline|escape:'html':'UTF-8'}</strong>
</span>
</div>
{/if}
{if $errors_list|@count > 0} {if $errors_list|@count > 0}
<div class="alert alert-danger" role="alert"> <div class="alert alert-danger" role="alert">
<ul> <ul>
@@ -151,3 +167,4 @@
update(); update();
})(); })();
</script> </script>
{/block}
+19 -4
View File
@@ -1,3 +1,6 @@
{extends file='layouts/layout-full-width.tpl'}
{block name='content'}
<section class="cyp-withdrawal-page"> <section class="cyp-withdrawal-page">
<header class="page-header"> <header class="page-header">
<h1>{l s='Widerruf übermittelt' mod='simple_withdrawalbutton'}</h1> <h1>{l s='Widerruf übermittelt' mod='simple_withdrawalbutton'}</h1>
@@ -5,12 +8,12 @@
<div class="cyp-steps"> <div class="cyp-steps">
<div class="cyp-step done"> <div class="cyp-step done">
<div class="cyp-step-bubble"></div> <div class="cyp-step-bubble">&#10003;</div>
<div class="cyp-step-label">{l s='Angaben' mod='simple_withdrawalbutton'}</div> <div class="cyp-step-label">{l s='Angaben' mod='simple_withdrawalbutton'}</div>
</div> </div>
<div class="cyp-step-line done"></div> <div class="cyp-step-line done"></div>
<div class="cyp-step done"> <div class="cyp-step done">
<div class="cyp-step-bubble"></div> <div class="cyp-step-bubble">&#10003;</div>
<div class="cyp-step-label">{l s='Prüfen' mod='simple_withdrawalbutton'}</div> <div class="cyp-step-label">{l s='Prüfen' mod='simple_withdrawalbutton'}</div>
</div> </div>
<div class="cyp-step-line done"></div> <div class="cyp-step-line done"></div>
@@ -22,7 +25,7 @@
<div class="card card-block"> <div class="card card-block">
<div class="cyp-success-header"> <div class="cyp-success-header">
<div class="cyp-success-icon" aria-hidden="true"></div> <div class="cyp-success-icon" aria-hidden="true">&#10003;</div>
{if isset($success_data.mail_ok) && $success_data.mail_ok} {if isset($success_data.mail_ok) && $success_data.mail_ok}
<h2>{l s='Ihr Widerruf wurde erfolgreich übermittelt.' mod='simple_withdrawalbutton'}</h2> <h2>{l s='Ihr Widerruf wurde erfolgreich übermittelt.' mod='simple_withdrawalbutton'}</h2>
<p>{l s='Eine Eingangsbestätigung wurde an Ihre E-Mail-Adresse gesendet.' mod='simple_withdrawalbutton'}</p> <p>{l s='Eine Eingangsbestätigung wurde an Ihre E-Mail-Adresse gesendet.' mod='simple_withdrawalbutton'}</p>
@@ -77,6 +80,17 @@
<div class="cyp-summary-val">{$success_data.message|escape:'html':'UTF-8'|nl2br nofilter}</div> <div class="cyp-summary-val">{$success_data.message|escape:'html':'UTF-8'|nl2br nofilter}</div>
</div> </div>
{/if} {/if}
{if isset($withdrawal_deadline) && $withdrawal_deadline != ''}
<div class="cyp-summary-row">
<div class="cyp-summary-key">{l s='Frist' mod='simple_withdrawalbutton'}</div>
<div class="cyp-summary-val" style="color:var(--cyw-accent);font-weight:600;">
{l s='bis' mod='simple_withdrawalbutton'} {$withdrawal_deadline|escape:'html':'UTF-8'}
<span style="font-size:12px;font-weight:400;color:var(--cyw-text-muted);">
({l s='14 Tage ab Bestelldatum' mod='simple_withdrawalbutton'})
</span>
</div>
</div>
{/if}
</div> </div>
<div class="cyp-legal"> <div class="cyp-legal">
@@ -84,7 +98,8 @@
</div> </div>
<button class="cyp-print-btn" onclick="window.print()" type="button"> <button class="cyp-print-btn" onclick="window.print()" type="button">
{l s='Seite drucken / als PDF speichern' mod='simple_withdrawalbutton'} &#9113; {l s='Seite drucken / als PDF speichern' mod='simple_withdrawalbutton'}
</button> </button>
</div> </div>
</section> </section>
{/block}