(main): Add module

This commit is contained in:
2026-06-22 09:45:20 +02:00
parent e8b381b132
commit 763745ee1b
17 changed files with 620 additions and 0 deletions
+1
View File
@@ -0,0 +1 @@
vendor/
+28
View File
@@ -0,0 +1,28 @@
{
"name": "websmid/giftdropdown",
"description": "Adds a gift paper style selector to the checkout",
"type": "prestashop-module",
"authors": [
{
"name": "Isabelle Oving-Anno - De Websmid BV",
"email": "isabelle@dewebsmid.nl"
}
],
"require": {
"php": ">=7.2.0"
},
"autoload": {
"psr-4": {
"Websmid\\GiftDropdown\\": "src/"
},
"classmap": [
"ws_giftdropdown.php"
],
"exclude-from-classmap": []
},
"config": {
"preferred-install": "dist",
"prepend-autoloader": false
},
"license": "MIT"
}
Generated
+20
View File
@@ -0,0 +1,20 @@
{
"_readme": [
"This file locks the dependencies of your project to a known state",
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "1e297fbe2fb6a5b7310b2215a227d48e",
"packages": [],
"packages-dev": [],
"aliases": [],
"minimum-stability": "stable",
"stability-flags": {},
"prefer-stable": false,
"prefer-lowest": false,
"platform": {
"php": ">=7.2.0"
},
"platform-dev": {},
"plugin-api-version": "2.9.0"
}
+11
View File
@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="UTF-8" ?>
<module>
<name>ws_giftdropdown</name>
<displayName><![CDATA[Gift Paper Selector]]></displayName>
<version><![CDATA[1.0.0]]></version>
<description><![CDATA[Adds a paper style selector to the gift wrap option at checkout]]></description>
<author><![CDATA[Isabelle Oving-Anno | De Websmid]]></author>
<tab><![CDATA[]]></tab>
<is_configurable>1</is_configurable>
<need_instance>0</need_instance>
</module>
+54
View File
@@ -0,0 +1,54 @@
<?php
use Websmid\GiftDropdown\Config\Config;
use Configuration;
use Context;
use Db;
use Tools;
if (!defined('_PS_VERSION_')) {
exit;
}
class Ws_GiftDropdownSavepaperModuleFrontController extends ModuleFrontController
{
public function initContent()
{
parent::initContent();
if (!$this->ajax) {
http_response_code(400);
exit;
}
$choice = Tools::getValue('gift_paper', '');
$saved = Configuration::get(Config::CONFIG_KEY);
$options = $saved ? json_decode($saved, true) : Config::DEFAULT_OPTIONS;
if (!in_array($choice, $options, true)) {
$this->ajaxRender(json_encode(['success' => false, 'error' => 'Invalid option']));
exit;
}
$idCart = (int) Context::getContext()->cart->id;
if (!$idCart) {
$this->ajaxRender(json_encode(['success' => false, 'error' => 'No cart']));
exit;
}
Db::getInstance()->execute(
'INSERT INTO `' . _DB_PREFIX_ . 'ws_gift_dropdown`
(`id_cart`, `id_order`, `paper_choice`, `date_add`)
VALUES
(' . (int) $idCart . ', 0, \'' . pSQL($choice) . '\', NOW())
ON DUPLICATE KEY UPDATE
`paper_choice` = \'' . pSQL($choice) . '\',
`date_add` = NOW()'
);
$this->ajaxRender(json_encode(['success' => true]));
exit;
}
}
+34
View File
@@ -0,0 +1,34 @@
<?php
/**
*
* NOTICE OF LICENSE
*
* This source file is subject to the Open Software License (OSL 3.0)
* that is bundled with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://opensource.org/licenses/osl-3.0.php
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade PrestaShop to newer
* versions in the future. If you wish to customize PrestaShop for your
* needs please refer to http://www.prestashop.com for more information.
*
* @author PrestaShop SA <contact@prestashop.com>
* @copyright PrestaShop SA
* @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
* International Registered Trademark & Property of PrestaShop SA
*/
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;
BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

+27
View File
@@ -0,0 +1,27 @@
<?php
namespace Websmid\GiftDropdown\Config;
class Config
{
const HOOKS = [
'actionGetExtraMailTemplateVars',
'actionValidateOrder',
'actionFrontControllerSetMedia',
'displayAdminOrderMainBottom',
'displayHeader',
'displayPDFInvoice',
'displayPDFDeliverySlip',
];
const TABS = [];
const CONFIG_KEY = 'WS_GIFT_OPTIONS';
const DEFAULT_OPTIONS = [
'Sterren',
'Bloemen',
'Strepen',
'Verrassing',
];
}
+90
View File
@@ -0,0 +1,90 @@
<?php
namespace Websmid\GiftDropdown\Module;
use Websmid\GiftDropdown\Config\Config;
use Configuration;
use Db;
use Media;
use Order;
use Tools;
trait AdminHooks
{
public function isUsingNewTranslationSystem()
{
return true;
}
public function getContent()
{
$confirmation = '';
if (Tools::isSubmit('submitWsGiftDropdown')) {
$raw = Tools::getValue('gift_options', '');
$lines = array_filter(array_map('trim', explode("\n", $raw)));
$options = array_values($lines);
Configuration::updateValue(Config::CONFIG_KEY, json_encode($options));
$confirmation = $this->displayConfirmation($this->trans('Settings saved.', [], 'Admin.Notifications.Success'));
}
$saved = Configuration::get(Config::CONFIG_KEY);
$options = $saved ? json_decode($saved, true) : Config::DEFAULT_OPTIONS;
$this->context->smarty->assign([
'gift_options' => implode("\n", $options),
'form_action' => $this->context->link->getAdminLink('AdminModules') . '&configure=' . $this->name,
'confirmation' => $confirmation,
]);
return $this->fetch('module:ws_giftdropdown/views/templates/admin/configuration.tpl');
}
public function hookActionFrontControllerSetMedia()
{
if (Tools::getValue('module') !== 'thecheckout' && $this->context->controller->php_self !== 'order') {
return;
}
$ajaxUrl = $this->context->link->getModuleLink($this->name, 'savepaper', [], true);
Media::addJsDef(['wsGiftDropdownAjaxUrl' => $ajaxUrl]);
$this->context->controller->registerStylesheet(
'ws-giftdropdown-css',
'modules/' . $this->name . '/views/css/giftwrap.css'
);
$this->context->controller->registerJavascript(
'ws-giftdropdown-js',
'modules/' . $this->name . '/views/js/giftwrap.js',
['position' => 'bottom', 'priority' => 200]
);
}
public function hookDisplayAdminOrderMainBottom(array $params)
{
$idOrder = (int) $params['id_order'];
$row = Db::getInstance()->getRow(
'SELECT `paper_choice` FROM `' . _DB_PREFIX_ . 'ws_gift_dropdown`
WHERE `id_order` = ' . (int) $idOrder
);
if (!$row) {
return '';
}
$order = new Order($idOrder);
if (!(bool) $order->gift) {
return '';
}
$this->context->smarty->assign([
'gift_paper_choice' => $row['paper_choice'],
]);
$this->context->controller->addJS($this->getPathUri() . 'views/js/admin_order.js');
return $this->fetch('module:ws_giftdropdown/views/templates/admin/order_detail.tpl');
}
}
+100
View File
@@ -0,0 +1,100 @@
<?php
namespace Websmid\GiftDropdown\Module;
use Websmid\GiftDropdown\Config\Config;
use Configuration;
use Db;
use Order;
use Tools;
use OrderInvoice;
trait DisplayHooks
{
public function hookDisplayHeader()
{
if (Tools::getValue('module') !== 'thecheckout' && $this->context->controller->php_self !== 'order') {
return;
}
$saved = Configuration::get(Config::CONFIG_KEY);
$options = $saved ? json_decode($saved, true) : Config::DEFAULT_OPTIONS;
$this->context->smarty->assign('gift_paper_options', $options);
return $this->display(__FILE__, 'views/templates/hook/your_template.tpl');
}
public function hookActionGetExtraMailTemplateVars(array $params): void
{
$paperChoice = $this->loadGiftPaperChoice((int) $params['template_vars']['{id_order}']);
if ($paperChoice === null) {
return;
}
$params['extra_template_vars']['{ws_gift_paper_choice}'] = $paperChoice;
}
public function hookActionValidateOrder(array $params)
{
/** @var Order $order */
$order = $params['order'];
$idCart = (int) $params['cart']->id;
if (!(bool) $order->gift) {
Db::getInstance()->execute(
'DELETE FROM `' . _DB_PREFIX_ . 'ws_gift_dropdown`
WHERE `id_cart` = ' . (int) $idCart . ' AND `id_order` = 0'
);
return;
}
Db::getInstance()->execute(
'UPDATE `' . _DB_PREFIX_ . 'ws_gift_dropdown`
SET `id_order` = ' . (int) $order->id . '
WHERE `id_cart` = ' . (int) $idCart
);
$paperChoice = Db::getInstance()->getValue(
'SELECT `paper_choice` FROM `' . _DB_PREFIX_ . 'ws_gift_dropdown`
WHERE `id_cart` = ' . (int) $idCart
);
if ($paperChoice) {
$note = 'Cadeaupapier: ' . $paperChoice;
$order->note = $order->note ? $order->note . "\n" . $note : $note;
$order->update();
}
}
public function hookDisplayPDFDeliverySlip(array $params)
{
return $this->hookDisplayPDFInvoice($params);
}
public function hookDisplayPDFInvoice(array $params)
{
/** @var OrderInvoice $orderInvoice */
$orderInvoice = $params['object'];
$idOrder = (int) $orderInvoice->id_order;
$paperChoice = Db::getInstance()->getValue(
'SELECT `paper_choice` FROM `' . _DB_PREFIX_ . 'ws_gift_dropdown`
WHERE `id_order` = ' . (int) $idOrder
);
$params['smarty']->assign('gift_paper_choice', $paperChoice ?: '');
return '';
}
private function loadGiftPaperChoice(int $idOrder): ?string
{
$value = Db::getInstance()->getValue(
'SELECT `paper_choice` FROM `' . _DB_PREFIX_ . 'ws_gift_dropdown`
WHERE `id_order` = ' . $idOrder
);
return $value !== false ? (string) $value : null;
}
}
+82
View File
@@ -0,0 +1,82 @@
<?php
namespace Websmid\GiftDropdown\Module;
use Websmid\GiftDropdown\Config\Config;
use Configuration;
use Db;
use Module;
trait Install
{
public function install()
{
if (!parent::install()) {
return false;
}
if (!$this->checkDependency()) {
return false;
}
if (!$this->createTables()) {
return false;
}
Configuration::updateValue(Config::CONFIG_KEY, json_encode(Config::DEFAULT_OPTIONS));
if (!$this->registerHooks()) {
return false;
}
return true;
}
private function checkDependency(): bool
{
$isInstalled = (bool) Db::getInstance()->getValue(
'SELECT `active` FROM `' . _DB_PREFIX_ . 'module` WHERE `name` = "thecheckout"'
);
if (!$isInstalled) {
$this->_errors[] = $this->trans(
'This module requires TheCheckout to be installed.',
[],
'Modules.Ws_GiftDropdown.Admin'
);
return false;
}
return true;
}
private function createTables()
{
$sql = '
CREATE TABLE IF NOT EXISTS `' . _DB_PREFIX_ . 'ws_gift_dropdown` (
`id_ws_gift_dropdown` INT(11) NOT NULL AUTO_INCREMENT,
`id_cart` INT(11) NOT NULL DEFAULT 0,
`id_order` INT(11) NOT NULL DEFAULT 0,
`paper_choice` VARCHAR(64) NOT NULL,
`date_add` DATETIME NOT NULL,
PRIMARY KEY (`id_ws_gift_dropdown`),
UNIQUE KEY `id_cart` (`id_cart`),
KEY `id_order` (`id_order`)
);
';
return Db::getInstance()->execute($sql);
}
public function registerHooks()
{
foreach (Config::HOOKS as $hook) {
if (!$this->registerHook($hook)) {
return false;
}
}
return true;
}
}
+32
View File
@@ -0,0 +1,32 @@
#gift-paper-choice {
margin-top: 12px;
padding: 12px 16px;
background: #f9f9f9;
border: 1px solid #e0e0e0;
border-radius: 4px;
}
#gift-paper-choice legend,
#gift-paper-choice .gift-paper-label {
font-weight: 600;
margin-bottom: 8px;
display: block;
}
#gift-paper-choice .gift-paper-options {
display: flex;
flex-wrap: wrap;
gap: 8px;
}
#gift-paper-choice .gift-paper-option {
display: flex;
align-items: center;
gap: 6px;
cursor: pointer;
}
#gift-paper-choice .gift-paper-option input[type="radio"] {
margin: 0;
cursor: pointer;
}
+6
View File
@@ -0,0 +1,6 @@
document.addEventListener("DOMContentLoaded", function () {
var panel = document.getElementById("ws-gift-panel");
var badge = document.querySelector('[data-badge="gift"]');
if (!panel || !badge) return;
badge.textContent = "Cadeauverpakking - " + panel.dataset.paperChoice;
});
+33
View File
@@ -0,0 +1,33 @@
(function () {
'use strict';
function savePaperChoice(choice) {
var ajaxUrl = window.wsGiftDropdownAjaxUrl || '';
if (!ajaxUrl || !choice) {
return;
}
var xhr = new XMLHttpRequest();
xhr.open('POST', ajaxUrl, true);
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
xhr.send('gift_paper=' + encodeURIComponent(choice) + '&ajax=1');
}
function init() {
var checked = document.querySelector('input[name="gift_paper"]:checked');
if (checked) {
savePaperChoice(checked.value);
}
document.addEventListener('change', function (e) {
if (e.target && e.target.name === 'gift_paper') {
savePaperChoice(e.target.value);
}
});
}
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', init);
} else {
init();
}
}());
+35
View File
@@ -0,0 +1,35 @@
{if $confirmation}
{$confirmation nofilter}
{/if}
<div class="panel">
<div class="panel-heading">
<i class="icon-gift"></i>
{l s='Gift Paper Options' mod='ws_giftdropdown'}
</div>
<div class="panel-body">
<p class="help-block">
{l s='Enter one paper style per line. These options will appear as radio buttons in the checkout when the customer selects gift wrapping.' mod='ws_giftdropdown'}
</p>
<form method="post" action="{$form_action|escape:'htmlall':'UTF-8'}">
<div class="form-group">
<label for="gift_options" class="control-label">
{l s='Paper styles (one per line)' mod='ws_giftdropdown'}
</label>
<textarea
id="gift_options"
name="gift_options"
class="form-control"
rows="8"
style="font-family: monospace;"
>{$gift_options|escape:'htmlall':'UTF-8'}</textarea>
</div>
<div class="panel-footer">
<button type="submit" name="submitWsGiftDropdown" class="btn btn-default pull-right">
<i class="process-icon-save"></i>
{l s='Save' mod='ws_giftdropdown'}
</button>
</div>
</form>
</div>
</div>
+12
View File
@@ -0,0 +1,12 @@
<div class="panel" id="ws-gift-panel" data-paper-choice="{$gift_paper_choice|escape:'htmlall':'UTF-8'}">
<div class="panel-heading">
<i class="icon-gift"></i>
{l s='Gift wrapping' mod='ws_giftdropdown'}
</div>
<div class="panel-body">
<dl class="list-unstyled">
<dt>{l s='Paper style' mod='ws_giftdropdown'}</dt>
<dd><strong>{$gift_paper_choice|escape:'htmlall':'UTF-8'}</strong></dd>
</dl>
</div>
</div>
+55
View File
@@ -0,0 +1,55 @@
<?php
/**
* 2007-2025 De Websmid BV
*
* NOTICE OF LICENSE
*
* This file is not open source! Each license that you purchased is only available for 1 website only.
* If you want to use this file on more websites (or projects), you need to purchase additional licenses.
* You are not allowed to redistribute, resell, lease, license, sub-license or offer our resources to any third party.
*
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade PrestaShop to newer
* versions in the future. If you wish to customize PrestaShop for your
* needs please contact us for extra customization service at an affordable price
*
* @author Isabelle Oving-Anno | De Websmid <isabelle@dewebsmid.nl>
* @copyright 2007-2025 De Websmid BV
* @license Valid for 1 website (or project) for each purchase of license
* International Registered Trademark & Property of De Websmid BV
*/
use Websmid\GiftDropdown\Module\Install;
use Websmid\GiftDropdown\Module\AdminHooks;
use Websmid\GiftDropdown\Module\DisplayHooks;
if (!defined('_PS_VERSION_')) {
exit;
}
if (file_exists(__DIR__ . '/vendor/autoload.php')) {
require_once __DIR__ . '/vendor/autoload.php';
}
class Ws_GiftDropdown extends Module
{
use Install;
use AdminHooks;
use DisplayHooks;
public function __construct()
{
$this->name = 'ws_giftdropdown';
$this->version = '1.0.0';
$this->author = 'Isabelle Oving-Anno | De Websmid BV';
$this->need_instance = 0;
$this->bootstrap = true;
parent::__construct();
$this->displayName = $this->trans('Gift Paper Selector', [], 'Modules.Ws_GiftDropdown.Admin');
$this->description = $this->trans('Adds a paper style selector to the gift wrap option at checkout', [], 'Modules.Ws_GiftDropdown.Description');
$this->ps_versions_compliancy = ['min' => '1.7.0.0', 'max' => _PS_VERSION_];
}
}