058937bd64
- 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>
246 lines
8.7 KiB
PHP
246 lines
8.7 KiB
PHP
<?php
|
|
|
|
if (!defined('_PS_VERSION_')) {
|
|
exit;
|
|
}
|
|
|
|
class Simple_withdrawalbuttonWithdrawModuleFrontController extends ModuleFrontController
|
|
{
|
|
public $ssl = true;
|
|
public $auth = false;
|
|
public $guestAllowed = true;
|
|
|
|
/** @var string */
|
|
private $currentView = 'form';
|
|
|
|
/** @var array */
|
|
private $formData = [];
|
|
|
|
/** @var array */
|
|
private $errorsList = [];
|
|
|
|
/** @var array */
|
|
private $successData = [];
|
|
|
|
public function initContent()
|
|
{
|
|
parent::initContent();
|
|
|
|
$this->context->smarty->assign([
|
|
'errors_list' => $this->errorsList,
|
|
'form_data' => $this->formData,
|
|
'csrf_token' => $this->module->getFrontToken(),
|
|
'action_url' => $this->context->link->getModuleLink($this->module->name, 'withdraw', [], true),
|
|
'success_data' => $this->successData,
|
|
'privacy_url' => (string) Configuration::get(Simple_withdrawalbutton::CONF_PRIVACY_URL),
|
|
'revocation_url' => (string) Configuration::get(Simple_withdrawalbutton::CONF_REVOCATION_URL),
|
|
'withdrawal_deadline' => $this->computeDeadline(),
|
|
]);
|
|
|
|
if ($this->currentView === 'confirm') {
|
|
$this->setTemplate('module:' . $this->module->name . '/views/templates/front/confirm.tpl');
|
|
return;
|
|
}
|
|
|
|
if ($this->currentView === 'success') {
|
|
$this->setTemplate('module:' . $this->module->name . '/views/templates/front/success.tpl');
|
|
return;
|
|
}
|
|
|
|
$this->setTemplate('module:' . $this->module->name . '/views/templates/front/form.tpl');
|
|
}
|
|
|
|
public function postProcess()
|
|
{
|
|
if (Tools::isSubmit('submit_withdrawal_prepare')) {
|
|
$this->handlePrepare();
|
|
return;
|
|
}
|
|
|
|
if (Tools::isSubmit('submit_withdrawal_confirm')) {
|
|
$this->handleConfirm();
|
|
return;
|
|
}
|
|
|
|
if (Tools::isSubmit('submit_withdrawal_back')) {
|
|
$this->formData = $this->collectInput();
|
|
$this->currentView = 'form';
|
|
return;
|
|
}
|
|
|
|
$this->formData = $this->getEmptyFormData();
|
|
}
|
|
|
|
private function handlePrepare()
|
|
{
|
|
$data = $this->collectInput();
|
|
$this->formData = $data;
|
|
|
|
if (!$this->module->isValidFrontToken(Tools::getValue('csrf_token'))) {
|
|
$this->errorsList[] = $this->module->l('The form could not be validated. Please reload the page and try again.', 'withdraw');
|
|
}
|
|
|
|
if ($this->isHoneypotFilled()) {
|
|
$this->errorsList[] = $this->module->l('The form could not be validated. Please reload the page and try again.', 'withdraw');
|
|
}
|
|
|
|
$this->errorsList = array_merge($this->errorsList, $this->validateData($data));
|
|
|
|
if (!empty($this->errorsList)) {
|
|
$this->currentView = 'form';
|
|
return;
|
|
}
|
|
|
|
$this->currentView = 'confirm';
|
|
}
|
|
|
|
private function handleConfirm()
|
|
{
|
|
$data = $this->collectInput();
|
|
$this->formData = $data;
|
|
|
|
if (!$this->module->isValidFrontToken(Tools::getValue('csrf_token'))) {
|
|
$this->errorsList[] = $this->module->l('The form could not be validated. Please reload the page and try again.', 'withdraw');
|
|
}
|
|
|
|
if ($this->isHoneypotFilled()) {
|
|
// Do not save obvious bot submissions. Show a generic success page to avoid feedback loops.
|
|
$this->currentView = 'success';
|
|
$this->successData = [
|
|
'mail_ok' => true,
|
|
'fake' => true,
|
|
];
|
|
return;
|
|
}
|
|
|
|
$this->errorsList = array_merge($this->errorsList, $this->validateData($data));
|
|
|
|
$ipHash = $this->module->hashForPrivacy($this->module->getClientIp());
|
|
if (empty($this->errorsList) && $this->module->isRateLimited($data['customer_email'], $ipHash)) {
|
|
$this->errorsList[] = $this->module->l('Too many withdrawal declarations were submitted in a short period. Please try again later or contact us by email.', 'withdraw');
|
|
}
|
|
|
|
if (!empty($this->errorsList)) {
|
|
$this->currentView = 'form';
|
|
return;
|
|
}
|
|
|
|
$saved = $this->module->saveWithdrawal($data);
|
|
if (!$saved) {
|
|
$this->errorsList[] = $this->module->l('Your withdrawal declaration could not be saved. Please try again or contact us by email.', 'withdraw');
|
|
$this->currentView = 'form';
|
|
return;
|
|
}
|
|
|
|
$customerMailOk = $this->module->sendCustomerConfirmation($data, $saved['created_at']);
|
|
$shopMailOk = $this->module->sendShopNotification($data, $saved['created_at'], (int) $saved['id_withdrawal_request']);
|
|
|
|
if ($customerMailOk) {
|
|
$this->module->markConfirmationSent((int) $saved['id_withdrawal_request']);
|
|
}
|
|
|
|
$this->currentView = 'success';
|
|
$this->successData = [
|
|
'id_withdrawal_request' => (int) $saved['id_withdrawal_request'],
|
|
'created_at' => $this->module->formatDateTimeForMail($saved['created_at']),
|
|
'mail_ok' => (bool) $customerMailOk,
|
|
'shop_mail_ok' => (bool) $shopMailOk,
|
|
'customer_email' => $data['customer_email'],
|
|
'order_reference' => $data['order_reference'],
|
|
'withdrawal_scope' => $data['withdrawal_scope'],
|
|
'withdrawal_items_text' => $data['withdrawal_items_text'],
|
|
'message' => $data['message'],
|
|
];
|
|
}
|
|
|
|
private function collectInput()
|
|
{
|
|
$scope = (string) Tools::getValue('withdrawal_scope');
|
|
if (!in_array($scope, ['full', 'partial'], true)) {
|
|
$scope = 'full';
|
|
}
|
|
|
|
return [
|
|
'customer_name' => $this->module->cleanText(Tools::getValue('customer_name'), 255),
|
|
'customer_email' => strtolower($this->module->cleanText(Tools::getValue('customer_email'), 255)),
|
|
'order_reference' => $this->module->cleanText(Tools::getValue('order_reference'), 64),
|
|
'withdrawal_scope' => $scope,
|
|
'withdrawal_items_text' => $this->module->cleanText(Tools::getValue('withdrawal_items_text'), 5000),
|
|
'message' => $this->module->cleanText(Tools::getValue('message'), 5000),
|
|
];
|
|
}
|
|
|
|
private function getEmptyFormData()
|
|
{
|
|
$customerName = '';
|
|
$customerEmail = '';
|
|
|
|
if (Validate::isLoadedObject($this->context->customer)) {
|
|
$customerName = trim((string) $this->context->customer->firstname . ' ' . (string) $this->context->customer->lastname);
|
|
$customerEmail = (string) $this->context->customer->email;
|
|
}
|
|
|
|
$orderRef = $this->module->cleanText(Tools::getValue('ref'), 64);
|
|
|
|
return [
|
|
'customer_name' => $customerName,
|
|
'customer_email' => $customerEmail,
|
|
'order_reference' => $orderRef,
|
|
'withdrawal_scope' => 'full',
|
|
'withdrawal_items_text' => '',
|
|
'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)
|
|
{
|
|
$errors = [];
|
|
|
|
if ($data['customer_name'] === '' || Tools::strlen($data['customer_name']) < 2) {
|
|
$errors[] = $this->module->l('Please enter your name.', 'withdraw');
|
|
}
|
|
|
|
if (!Validate::isEmail($data['customer_email'])) {
|
|
$errors[] = $this->module->l('Please enter a valid email address for the confirmation.', 'withdraw');
|
|
}
|
|
|
|
if ($data['order_reference'] === '') {
|
|
$errors[] = $this->module->l('Please enter the order number or order reference.', 'withdraw');
|
|
}
|
|
|
|
if (!in_array($data['withdrawal_scope'], ['full', 'partial'], true)) {
|
|
$errors[] = $this->module->l('Please select whether you want to withdraw the full order or part of it.', 'withdraw');
|
|
}
|
|
|
|
if ($data['withdrawal_scope'] === 'partial' && $data['withdrawal_items_text'] === '') {
|
|
$errors[] = $this->module->l('For a partial withdrawal, please enter the affected items and quantities.', 'withdraw');
|
|
}
|
|
|
|
return $errors;
|
|
}
|
|
|
|
private function isHoneypotFilled()
|
|
{
|
|
return trim((string) Tools::getValue('cyp_hp_v1')) !== '';
|
|
}
|
|
}
|