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')) !== ''; } }