Module Maintenance + création du module Recette
This commit is contained in:
31
local/modules/Maintenance/Config/config.xml
Normal file
31
local/modules/Maintenance/Config/config.xml
Normal file
@@ -0,0 +1,31 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
|
||||
<config xmlns="http://thelia.net/schema/dic/config"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://thelia.net/schema/dic/config http://thelia.net/schema/dic/config/thelia-1.0.xsd">
|
||||
|
||||
<forms>
|
||||
<form name="admin_maintenance_settings" class="Maintenance\Form\MaintenanceSettingsForm" />
|
||||
</forms>
|
||||
|
||||
<services>
|
||||
<service id="maintenance.listener" class="Maintenance\EventListener\MaintenanceListener">
|
||||
<argument>%kernel.debug%</argument>
|
||||
<tag name="kernel.event_subscriber"/>
|
||||
</service>
|
||||
</services>
|
||||
|
||||
<hooks>
|
||||
<hook id="maintenance.warning" class="Maintenance\Hook\HookManager">
|
||||
<tag name="hook.event_listener" event="main.body-top" type="front" method="onMainBodyTop" />
|
||||
</hook>
|
||||
|
||||
<hook id="maintenance.configuration.hook" class="Maintenance\Hook\HookManager">
|
||||
<tag name="hook.event_listener" event="module.configuration" type="back" method="onModuleConfigure" />
|
||||
</hook>
|
||||
|
||||
<hook id="maintenance.menutools.hook" class="Maintenance\Hook\HookManager">
|
||||
<tag name="hook.event_listener" event="main.top-menu-tools" type="back" method="onMainTopMenuTools" />
|
||||
</hook>
|
||||
</hooks>
|
||||
</config>
|
||||
24
local/modules/Maintenance/Config/module.xml
Normal file
24
local/modules/Maintenance/Config/module.xml
Normal file
@@ -0,0 +1,24 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module xmlns="http://thelia.net/schema/dic/module"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://thelia.net/schema/dic/module http://thelia.net/schema/dic/module/module-2_1.xsd">
|
||||
<fullnamespace>Maintenance\Maintenance</fullnamespace>
|
||||
<descriptive locale="en_US">
|
||||
<title>Maintenance mode</title>
|
||||
</descriptive>
|
||||
<descriptive locale="fr_FR">
|
||||
<title>Mode Maintenance</title>
|
||||
</descriptive>
|
||||
<languages>
|
||||
<language>en_US</language>
|
||||
<language>fr_FR</language>
|
||||
</languages>
|
||||
<version>0.8</version>
|
||||
<author>
|
||||
<name>Nicolas Léon, Franck Allimant</name>
|
||||
<email>nicolas@omnitic.com, thelia@cqfdev.fr</email>
|
||||
</author>
|
||||
<type>classic</type>
|
||||
<thelia>2.3.0</thelia>
|
||||
<stability>prod</stability>
|
||||
</module>
|
||||
23
local/modules/Maintenance/Config/routing.xml
Normal file
23
local/modules/Maintenance/Config/routing.xml
Normal file
@@ -0,0 +1,23 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
|
||||
<routes xmlns="http://symfony.com/schema/routing"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://symfony.com/schema/routing http://symfony.com/schema/routing/routing-1.0.xsd">
|
||||
|
||||
<route id="maintenance.front" path="/maintenance">
|
||||
<default key="_controller">Maintenance\Controller\MaintenanceController::displayMaintenance</default>
|
||||
</route>
|
||||
|
||||
<route id="maintenance.back-preview" path="/maintenance-preview">
|
||||
<default key="_controller">Maintenance\Controller\MaintenanceController::displayMaintenance</default>
|
||||
</route>
|
||||
|
||||
<route id="maintenance.home" path="/admin/module/maintenance">
|
||||
<default key="_controller">Maintenance\Controller\MaintenanceAdminController::indexAction</default>
|
||||
</route>
|
||||
|
||||
<route id="maintenance.update" path="/admin/module/maintenance/configure" methods="post">
|
||||
<default key="_controller">Maintenance\Controller\MaintenanceAdminController::configureAction</default>
|
||||
</route>
|
||||
|
||||
</routes>
|
||||
@@ -0,0 +1,67 @@
|
||||
<?php
|
||||
/*************************************************************************************/
|
||||
/* Maintenance mode plugin for Thelia 2 */
|
||||
/* */
|
||||
/* Copyright (c) Omnitic */
|
||||
/* email : nicolas@omnitic.com */
|
||||
/* web : http://www.omnitic.com */
|
||||
/* */
|
||||
/*************************************************************************************/
|
||||
|
||||
namespace Maintenance\Controller;
|
||||
|
||||
use Maintenance\Form\MaintenanceSettingsForm;
|
||||
use Thelia\Controller\Admin\BaseAdminController;
|
||||
use Thelia\Core\Security\AccessManager;
|
||||
use Thelia\Core\Security\Resource\AdminResources;
|
||||
use Thelia\Form\Exception\FormValidationException;
|
||||
use Thelia\Model\ConfigQuery;
|
||||
use Thelia\Tools\URL;
|
||||
|
||||
/**
|
||||
* Class MaintenanceAdminController
|
||||
* @package Maintenance\Controller
|
||||
* @author Nicolas Léon <nicolas@omnitic.com>
|
||||
* @author Benjamin Perche <bperche@openstudio.fr>
|
||||
*/
|
||||
class MaintenanceAdminController extends BaseAdminController
|
||||
{
|
||||
|
||||
public function configureAction()
|
||||
{
|
||||
if (null !== $response = $this->checkAuth([AdminResources::MODULE], ['Maintenance'], AccessManager::UPDATE)) {
|
||||
return $response;
|
||||
}
|
||||
|
||||
$m_form = new MaintenanceSettingsForm($this->getRequest());
|
||||
|
||||
$error_message = null;
|
||||
|
||||
try {
|
||||
$form = $this->validateForm($m_form, "post");
|
||||
|
||||
$data = $form->getData();
|
||||
|
||||
ConfigQuery::write('com.omnitic.maintenance_mode', (bool) $data['maintenance_mode']);
|
||||
ConfigQuery::write('com.omnitic.maintenance_template_name', $data['maintenance_template_name']);
|
||||
ConfigQuery::write('com.omnitic.maintenance_message', $data['maintenance_message']);
|
||||
ConfigQuery::write('com.omnitic.maintenance_allowed_ips', preg_replace("/\s/", '', $data['maintenance_allowed_ips']));
|
||||
|
||||
} catch (FormValidationException $e) {
|
||||
$error_message = $this->createStandardFormValidationErrorMessage($e);
|
||||
} catch (\Exception $e) {
|
||||
$error_message = $e->getMessage();
|
||||
}
|
||||
|
||||
if ($error_message !== null) {
|
||||
$m_form->setErrorMessage($error_message);
|
||||
|
||||
$this->getParserContext()
|
||||
->addForm($m_form)
|
||||
->setGeneralError($error_message)
|
||||
;
|
||||
}
|
||||
|
||||
return $this->generateRedirect(URL::getInstance()->absoluteUrl('/admin/module/Maintenance'));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
<?php
|
||||
|
||||
namespace Maintenance\Controller;
|
||||
use Thelia\Controller\Front\BaseFrontController;
|
||||
use Thelia\Model\ConfigQuery;
|
||||
|
||||
/**
|
||||
* Class MaintenanceController
|
||||
* @package Maintenance\Controller
|
||||
* @author Benjamin Perche <bperche@openstudio.fr>
|
||||
*/
|
||||
class MaintenanceController extends BaseFrontController
|
||||
{
|
||||
public function displayMaintenance()
|
||||
{
|
||||
$tplName = ConfigQuery::read("com.omnitic.maintenance_template_name");
|
||||
|
||||
if (empty($tplName)) {
|
||||
$tplName = "maintenance";
|
||||
}
|
||||
|
||||
return $this->render("maintenance/$tplName");
|
||||
}
|
||||
}
|
||||
109
local/modules/Maintenance/EventListener/MaintenanceListener.php
Normal file
109
local/modules/Maintenance/EventListener/MaintenanceListener.php
Normal file
@@ -0,0 +1,109 @@
|
||||
<?php
|
||||
/*************************************************************************************/
|
||||
/* This file is part of the Maintenance module. */
|
||||
/* */
|
||||
/* Copyright (c) Omnitic */
|
||||
/* email : bonjour@omnitic.com */
|
||||
/* web : http://www.omnitic.com */
|
||||
/* */
|
||||
/* This program is free software; you can redistribute it and/or modify */
|
||||
/* it under the terms of the GNU General Public License as published by */
|
||||
/* the Free Software Foundation; either version 3 of the License */
|
||||
/* */
|
||||
/* This program is distributed in the hope that it will be useful, */
|
||||
/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
|
||||
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
|
||||
/* GNU General Public License for more details. */
|
||||
/* */
|
||||
/* You should have received a copy of the GNU General Public License */
|
||||
/* along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||
/* */
|
||||
/*************************************************************************************/
|
||||
|
||||
namespace Maintenance\EventListener;
|
||||
|
||||
use BackOfficePath\BackOfficePath;
|
||||
use Maintenance\Controller\MaintenanceController;
|
||||
use Maintenance\Maintenance;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
|
||||
use Symfony\Component\HttpKernel\Event\GetResponseEvent;
|
||||
use Symfony\Component\HttpKernel\KernelEvents;
|
||||
use Symfony\Component\HttpKernel\Event\FilterResponseEvent;
|
||||
|
||||
use Thelia\Core\HttpKernel\Exception\RedirectException;
|
||||
use Thelia\Model\ConfigQuery;
|
||||
use Thelia\Model\ModuleQuery;
|
||||
use Thelia\Tools\URL;
|
||||
|
||||
/**
|
||||
* Class MaintenanceListener
|
||||
* @package Maintenance\EventListener
|
||||
* @author Benjamin Perche <bperche@openstudio.fr>
|
||||
* @author Nicolas Léon <nicolas@omnitic.com>
|
||||
*/
|
||||
class MaintenanceListener implements EventSubscriberInterface
|
||||
{
|
||||
protected $debugMode;
|
||||
|
||||
/**
|
||||
* MaintenanceListener constructor.
|
||||
*
|
||||
* @param $debugMode
|
||||
*/
|
||||
public function __construct($debugMode)
|
||||
{
|
||||
$this->debugMode = $debugMode;
|
||||
}
|
||||
|
||||
/*
|
||||
* Displays the maintenance page according to Admin settings
|
||||
*
|
||||
* @params FilterResponseEvent $event
|
||||
*
|
||||
*/
|
||||
public function setMaintenanceView(GetResponseEvent $event)
|
||||
{
|
||||
$maintenance_mode = ConfigQuery::read('com.omnitic.maintenance_mode');
|
||||
|
||||
if ($maintenance_mode) {
|
||||
/**
|
||||
* @var \Thelia\Core\HttpFoundation\Request
|
||||
*/
|
||||
$request = $event->getRequest();
|
||||
|
||||
// Check that the current request ip address is in the white list
|
||||
$allowed_ips = explode(',', ConfigQuery::read('com.omnitic.maintenance_allowed_ips'));
|
||||
$allowed_ips[] = '127.0.0.1';
|
||||
$current_ip = $request->server->get('REMOTE_ADDR');
|
||||
$path = $request->getPathInfo();
|
||||
|
||||
if ($path !== '/maintenance') {
|
||||
// Check that we're not in debug mode
|
||||
if (! $this->debugMode) {
|
||||
// Check that we're not an allowed ip address
|
||||
if (!in_array($current_ip, $allowed_ips)) {
|
||||
// Check that we're not an admin user
|
||||
if ($request->getSession()->getAdminUser() === null) {
|
||||
// Check that we're not accessing admin pages
|
||||
if (!preg_match("#^/admin#i", $path)) {
|
||||
throw new RedirectException(URL::getInstance()->absoluteUrl("/maintenance"));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of event names this subscriber wants to listen to.
|
||||
*/
|
||||
public static function getSubscribedEvents()
|
||||
{
|
||||
return array(
|
||||
KernelEvents::REQUEST => ["setMaintenanceView", 128]
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
110
local/modules/Maintenance/Form/MaintenanceSettingsForm.php
Normal file
110
local/modules/Maintenance/Form/MaintenanceSettingsForm.php
Normal file
@@ -0,0 +1,110 @@
|
||||
<?php
|
||||
/*************************************************************************************/
|
||||
/* Maintenance mode plugin for Thelia 2 */
|
||||
/* */
|
||||
/* Copyright (c) Omnitic */
|
||||
/* email : nicolas@omnitic.com */
|
||||
/* web : http://www.omnitic.com */
|
||||
/* */
|
||||
/*************************************************************************************/
|
||||
namespace Maintenance\Form;
|
||||
|
||||
use Maintenance\Maintenance;
|
||||
use Symfony\Component\Validator\Constraints\NotBlank;
|
||||
use Thelia\Core\Translation\Translator;
|
||||
use Thelia\Form\BaseForm;
|
||||
|
||||
/**
|
||||
* Class MaintenanceSettingsForm
|
||||
* @package Maintenance\Form
|
||||
* @author Nicolas Léon <nicolas@omnitic.com>
|
||||
* @author Benjamin Perche <bperche@openstudio.fr>
|
||||
*/
|
||||
class MaintenanceSettingsForm extends BaseForm
|
||||
{
|
||||
protected function buildForm()
|
||||
{
|
||||
$translator = Translator::getInstance();
|
||||
|
||||
$this->formBuilder
|
||||
->add('maintenance_mode', 'checkbox', array(
|
||||
'label' => $translator->trans(
|
||||
"Put the store in maintenance mode",
|
||||
[],
|
||||
Maintenance::MESSAGE_DOMAIN
|
||||
),
|
||||
'label_attr' => [
|
||||
'for' => 'maintenance_mode',
|
||||
'help' => $this->translator->trans(
|
||||
'Lorsque cette case est cochée, votre boutique n\'est plus accessible à vos clients.',
|
||||
[],
|
||||
Maintenance::MESSAGE_DOMAIN
|
||||
)
|
||||
],
|
||||
'required' => false,
|
||||
))
|
||||
->add('maintenance_template_name', 'text', array(
|
||||
'label' => $translator->trans(
|
||||
"Template name",
|
||||
[],
|
||||
Maintenance::MESSAGE_DOMAIN
|
||||
),
|
||||
'label_attr' => array(
|
||||
'for' => 'maintenance_template_name',
|
||||
'help' => $this->translator->trans(
|
||||
'This is the name of the HTML template displayed to your customers. The module provides the following templates : "maintenance", "light" and "simple", but feel free to make your own template, and put its name here.',
|
||||
[],
|
||||
Maintenance::MESSAGE_DOMAIN
|
||||
)
|
||||
),
|
||||
'required' => true,
|
||||
'constraints' => array(
|
||||
new NotBlank(),
|
||||
)
|
||||
))
|
||||
->add('maintenance_message', 'textarea', array(
|
||||
'label' => $translator->trans(
|
||||
"Reminder message",
|
||||
[],
|
||||
Maintenance::MESSAGE_DOMAIN
|
||||
),
|
||||
'label_attr' => array(
|
||||
'for' => 'maintenance_message',
|
||||
'help' => $this->translator->trans(
|
||||
'This message will be displayed to your customers.',
|
||||
[],
|
||||
Maintenance::MESSAGE_DOMAIN
|
||||
)
|
||||
),
|
||||
"required" => true,
|
||||
"constraints" => array(
|
||||
new NotBlank(),
|
||||
)
|
||||
))
|
||||
->add('maintenance_allowed_ips', 'text', array(
|
||||
'label' => $translator->trans(
|
||||
"Authorized IP address(es)",
|
||||
[],
|
||||
Maintenance::MESSAGE_DOMAIN
|
||||
),
|
||||
'label_attr' => array(
|
||||
'for' => 'allowed_ips',
|
||||
'help' => $this->translator->trans(
|
||||
'Enter here a comma separated list of the IP addresses that will be allowed to access the shop when maintenance mode is enabled. Your IP address is currently %ip.',
|
||||
[ "%ip" => $this->getRequest()->getClientIp()],
|
||||
Maintenance::MESSAGE_DOMAIN
|
||||
)
|
||||
),
|
||||
"required" => false,
|
||||
// "constraints" => array(
|
||||
// new NotBlank(),
|
||||
// )
|
||||
))
|
||||
;
|
||||
}
|
||||
|
||||
public function getName()
|
||||
{
|
||||
return 'admin_maintenance_settings';
|
||||
}
|
||||
}
|
||||
53
local/modules/Maintenance/Hook/HookManager.php
Normal file
53
local/modules/Maintenance/Hook/HookManager.php
Normal file
@@ -0,0 +1,53 @@
|
||||
<?php
|
||||
/*************************************************************************************/
|
||||
/* This file is part of the Thelia package. */
|
||||
/* */
|
||||
/* Copyright (c) OpenStudio */
|
||||
/* email : dev@thelia.net */
|
||||
/* web : http://www.thelia.net */
|
||||
/* */
|
||||
/* For the full copyright and license information, please view the LICENSE.txt */
|
||||
/* file that was distributed with this source code. */
|
||||
/*************************************************************************************/
|
||||
|
||||
namespace Maintenance\Hook;
|
||||
|
||||
use Maintenance\Maintenance;
|
||||
use Thelia\Core\Event\Hook\HookRenderBlockEvent;
|
||||
use Thelia\Core\Event\Hook\HookRenderEvent;
|
||||
use Thelia\Core\Hook\BaseHook;
|
||||
use Thelia\Model\ConfigQuery;
|
||||
use Thelia\Tools\URL;
|
||||
|
||||
/**
|
||||
* Class HookManager
|
||||
*
|
||||
* @package Tinymce\Hook
|
||||
* @author Franck Allimant <franck@cqfdev.fr>
|
||||
*/
|
||||
class HookManager extends BaseHook
|
||||
{
|
||||
public function onMainBodyTop(HookRenderEvent $event)
|
||||
{
|
||||
if (ConfigQuery::read('com.omnitic.maintenance_mode')) {
|
||||
$event->add($this->render("maintenance/maintenance_warning.html"));
|
||||
}
|
||||
}
|
||||
|
||||
public function onMainTopMenuTools(HookRenderBlockEvent $event)
|
||||
{
|
||||
$event->add(
|
||||
[
|
||||
'id' => 'tools_menu_tags',
|
||||
'class' => '',
|
||||
'url' => URL::getInstance()->absoluteUrl('/admin/module/Maintenance'),
|
||||
'title' => $this->translator->trans("Mode maintenance", [], Maintenance::MESSAGE_DOMAIN)
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
public function onModuleConfigure(HookRenderEvent $event)
|
||||
{
|
||||
$event->add($this->render("maintenance/module_configuration.html"));
|
||||
}
|
||||
}
|
||||
11
local/modules/Maintenance/I18n/backOffice/default/en_US.php
Normal file
11
local/modules/Maintenance/I18n/backOffice/default/en_US.php
Normal file
@@ -0,0 +1,11 @@
|
||||
<?php
|
||||
|
||||
return array(
|
||||
'Le mode maintenance permet de fermer temporairement votre boutique, en affichant un message de votre choix à vos visiteurs.' => 'When the maintenance mode is active, your store is cloded, displaying a message of your choice to your visitors.',
|
||||
'Maintenance mode' => 'Maintenance mode',
|
||||
'Preview' => 'Preview',
|
||||
'Save changes' => 'Save changes',
|
||||
'Save your changes to get proper preview !' => 'Be sure to saveyour changes to get the selected preview !',
|
||||
'Sur cette page vous pouvez activer ou désactiver le mode maintenance, configurer les accès autorisés et régler les paramètres d\'affichage.' => 'On this page you can activate or deactivate the maintenance mode, configure the allowed accesses and adjust the display parameters.',
|
||||
'Vous conservez toujours un accès à la boutique si vous etes connecté en tant qu\'administrateur, ou accédez à la boutique en mode développement. Dans ce cas, un rappel du mode maintenance est affiché sur la boutique. Vous pouvez le modifier dans le template frontOffice/default/maintenance/maintenance_warning.html.' => 'You keep an access to the store if you are logged as an administrator, or access the store in development mode. In this case, a reminder of maintenance mode is displayed on the shop. You can change it in the frontOffice/default/maintenance/maintenance_warning.html template.',
|
||||
);
|
||||
11
local/modules/Maintenance/I18n/backOffice/default/fr_FR.php
Normal file
11
local/modules/Maintenance/I18n/backOffice/default/fr_FR.php
Normal file
@@ -0,0 +1,11 @@
|
||||
<?php
|
||||
|
||||
return array(
|
||||
'Le mode maintenance permet de fermer temporairement votre boutique, en affichant un message de votre choix à vos visiteurs.' => 'Le mode maintenance permet de fermer temporairement votre boutique, en affichant un message de votre choix à vos visiteurs.',
|
||||
'Maintenance mode' => 'Mode maintenance',
|
||||
'Preview' => 'Prévisualiser',
|
||||
'Save changes' => 'Enregistrer',
|
||||
'Save your changes to get proper preview !' => 'Enregistrez les changements pour afficher la vue choisie !',
|
||||
'Sur cette page vous pouvez activer ou désactiver le mode maintenance, configurer les accès autorisés et régler les paramètres d\'affichage.' => 'Sur cette page vous pouvez activer ou désactiver le mode maintenance, configurer les accès autorisés et régler les paramètres d\'affichage.',
|
||||
'Vous conservez toujours un accès à la boutique si vous etes connecté en tant qu\'administrateur, ou accédez à la boutique en mode développement. Dans ce cas, un rappel du mode maintenance est affiché sur la boutique. Vous pouvez le modifier dans le template frontOffice/default/maintenance/maintenance_warning.html.' => 'Vous conservez toujours un accès à la boutique si vous etes connecté en tant qu\'administrateur, ou accédez à la boutique en mode développement. Dans ce cas, un rappel du mode maintenance est affiché sur la boutique. Vous pouvez le modifier dans le template frontOffice/default/maintenance/maintenance_warning.html.',
|
||||
);
|
||||
13
local/modules/Maintenance/I18n/en_US.php
Normal file
13
local/modules/Maintenance/I18n/en_US.php
Normal file
@@ -0,0 +1,13 @@
|
||||
<?php
|
||||
|
||||
return array(
|
||||
'Authorized IP address(es)' => 'Allowed IP address(es)',
|
||||
'Enter here a comma separated list of the IP addresses that will be allowed to access the shop when maintenance mode is enabled. Your IP address is currently %ip.' => 'Enter here a comma separated list of the IP addresses that will be allowed to access the shop when maintenance mode is enabled. Your IP address is currently %ip.',
|
||||
'Lorsque cette case est cochée, votre boutique n\'est plus accessible à vos clients.' => 'When this box is checked, your store is closed',
|
||||
'Mode maintenance' => 'Maintenance mode',
|
||||
'Put the store in maintenance mode' => 'Put the store in maintenance mode',
|
||||
'Reminder message' => 'Reminder message',
|
||||
'Template name' => 'Template name',
|
||||
'This is the name of the HTML template displayed to your customers. The module provides the following templates : "maintenance", "light" and "simple", but feel free to make your own template, and put its name here.' => 'This is the name of the HTML template displayed to your customers. The module provides the following templates : "maintenance", "light" and "simple", but feel free to make your own template, and put its name here.',
|
||||
'This message will be displayed to your customers.' => 'This message will be displayed to your customers.',
|
||||
);
|
||||
13
local/modules/Maintenance/I18n/fr_FR.php
Normal file
13
local/modules/Maintenance/I18n/fr_FR.php
Normal file
@@ -0,0 +1,13 @@
|
||||
<?php
|
||||
|
||||
return array(
|
||||
'Authorized IP address(es)' => 'Addresses IP autorisées',
|
||||
'Enter here a comma separated list of the IP addresses that will be allowed to access the shop when maintenance mode is enabled. Your IP address is currently %ip.' => 'Indiquez ici la liste des adresses IP (séparées par des virgules) qui seront autorisées à voir la boutique lorsque le mode maintenance est actif. Votre adresse IP est %ip',
|
||||
'Lorsque cette case est cochée, votre boutique n\'est plus accessible à vos clients.' => 'Lorsque cette case est cochée, votre boutique n\'est plus accessible à vos clients.',
|
||||
'Mode maintenance' => 'Mode maintenance',
|
||||
'Put the store in maintenance mode' => 'Afficher la page de maintenance',
|
||||
'Reminder message' => 'Message d\'attente',
|
||||
'Template name' => 'Nom du template',
|
||||
'This is the name of the HTML template displayed to your customers. The module provides the following templates : "maintenance", "light" and "simple", but feel free to make your own template, and put its name here.' => 'Il s\'agit du nom du template HTML qui sera affiché aux visiteurs de la boutique. Le modulke vous propose les templates "simple", "light" et "maintenance", mais vous pouvez tout à fait créer le votre dans Maintenance/templates/frontOffice/default/maintenance et placer son nom ici.',
|
||||
'This message will be displayed to your customers.' => 'Ce message sera présenté aux visiteurs de la boutique',
|
||||
);
|
||||
@@ -0,0 +1,5 @@
|
||||
<?php
|
||||
|
||||
return array(
|
||||
'Maintenance mode is active' => 'Le mode maintenance est activé !',
|
||||
);
|
||||
65
local/modules/Maintenance/Maintenance.php
Normal file
65
local/modules/Maintenance/Maintenance.php
Normal file
@@ -0,0 +1,65 @@
|
||||
<?php
|
||||
/*************************************************************************************/
|
||||
/* Maintenance mode plugin for Thelia 2 */
|
||||
/* */
|
||||
/* Copyright (c) Omnitic */
|
||||
/* email : nicolas@omnitic.com */
|
||||
/* web : http://www.omnitic.com */
|
||||
/* */
|
||||
/*************************************************************************************/
|
||||
|
||||
namespace Maintenance;
|
||||
|
||||
use Propel\Runtime\Connection\ConnectionInterface;
|
||||
use Thelia\Model\ConfigQuery;
|
||||
use Thelia\Module\BaseModule;
|
||||
|
||||
class Maintenance extends BaseModule
|
||||
{
|
||||
const MESSAGE_DOMAIN = "maintenance";
|
||||
|
||||
private $settings = [
|
||||
'com.omnitic.maintenance_mode' => 0,
|
||||
'com.omnitic.maintenance_template_name' => 'maintenance',
|
||||
'com.omnitic.maintenance_message' => 'Nous mettons à jour notre boutique. Revenez nous voir dans quelques minutes.',
|
||||
'com.omnitic.maintenance_allowed_ips' => '',
|
||||
];
|
||||
|
||||
/*
|
||||
* Install the default module settings
|
||||
*
|
||||
*/
|
||||
public function postActivation(ConnectionInterface $con = null)
|
||||
{
|
||||
foreach ($this->settings as $setting_name => $value) {
|
||||
$setting = ConfigQuery::read($setting_name);
|
||||
|
||||
if (empty($setting)) {
|
||||
ConfigQuery::write($setting_name, $value, null, 1);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* Delete module data on module destroy
|
||||
*
|
||||
*
|
||||
*/
|
||||
public function destroy(ConnectionInterface $con = null, $deleteModuleData = false)
|
||||
{
|
||||
foreach ($this->settings as $setting_name => $value) {
|
||||
$setting = ConfigQuery::create()->findOneByName($setting_name);
|
||||
if ($setting !== null) {
|
||||
$setting->delete();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public function getCode()
|
||||
{
|
||||
return 'Maintenance';
|
||||
}
|
||||
|
||||
}
|
||||
89
local/modules/Maintenance/Readme.md
Normal file
89
local/modules/Maintenance/Readme.md
Normal file
@@ -0,0 +1,89 @@
|
||||
# Maintenance mode module for Thelia 2 (en_US)
|
||||
|
||||
This module allow the store owner to put the store in maintenance mode while performing changes to the store.
|
||||
|
||||
## How to install
|
||||
|
||||
Download the .zip file of this module or create a git submodule into your project like this :
|
||||
|
||||
```
|
||||
cd /path-to-thelia
|
||||
git submodule add https://github.com/nicolasleon/Maintenance.git local/modules/Mainteance
|
||||
```
|
||||
|
||||
To install the module, copy the folder Maintenance into your ```modules/``` directory (install_dir/local/modules).
|
||||
|
||||
Next, go to your Thelia admin panel and activate the module.
|
||||
|
||||
|
||||
## Configuration
|
||||
|
||||
You can manage the store maintenance mode settings by clicking the "Configure" button on the modules list.
|
||||
|
||||
Under the Configure tab you can set the following options:
|
||||
|
||||
**Put the store in maintenance mode**: Check the box to put the store in maintenance mode.
|
||||
|
||||
**Maintenance page name**: the name of the template to be displayed when the maintenance mode is active (See the provided templates in /templates/fontOffice/module_maintenance folder of the module).
|
||||
|
||||
**Reminder message**: a message to display in the store front when the maintenance mode is active.
|
||||
|
||||
**Allowed ips**: Ip addresses that are allowed to see the store in maintenance mode is active (e.g.: "212.127.1.5, 192.135.0.1")
|
||||
|
||||
|
||||
## How to use
|
||||
|
||||
Click on "Configure" button and check "Put the store in maintenance mode".
|
||||
Define the message displayed to the shop visitors in Reminder message field.
|
||||
|
||||
The maintenance templates are stored in Maintenance/templates/frontOffice/default/maintenance folder. There are 3 samples maintenance templates provided (maintenance, simple and light) with the modules. Feel free to customize them to best match your store design.
|
||||
|
||||
Save you settings. The store is now in maintenance mode.
|
||||
|
||||
Any store admin can still accesss the store in maintenance mode (They will see the reminder message at the top of the page). The sotre remains visible if accessed in developement mode (you know, index_dev.php)
|
||||
|
||||
|
||||
# Module Mode Maintenance pour Thelia 2 (fr_FR)
|
||||
|
||||
Ce module permet au ecommerçant de mettre la boutique en mode maintenance pendant la mise à jour de cette dernière.
|
||||
|
||||
## Installation
|
||||
|
||||
Téléchargez le fichier zip du module ou créez un submodule Git dans votre projet comme ceci :
|
||||
|
||||
```
|
||||
cd /dossier-thelia
|
||||
git submodule add https://github.com/nicolasleon/Maintenance.git local/modules/Mainteance
|
||||
```
|
||||
|
||||
Pour installer le module, copiez le dossier Maintenance dans le répertoire /local/modules situé à la racine de votre dossier Thelia (mon-dossier-thelia/local/modules).
|
||||
|
||||
Activez le module dans l'interface d'administration Thelia.
|
||||
|
||||
|
||||
## Configuration
|
||||
|
||||
Vous pouvez régler les paramètres du mode maintenance de la boutique en cliquant sur le bouton "Configuration" du module.
|
||||
|
||||
Les paramètres disponibles sont les suivants :
|
||||
|
||||
**Afficher la page de maintenance**: cochez cette case pour passer la boutique en mode maintenance.
|
||||
|
||||
**Nom du template**: le nom du template que les visiteurs verront quand la boutique est en mode maintenance (le template fourni maintenance.html pourra êtreSee the provided maintenance.html in templates/fontOffice/default folder of the module).
|
||||
|
||||
**Message d'attente**: Un message à afficher sur la page de maintenance quand la boutique est en maintenance.
|
||||
|
||||
**Adresses ip autorisées**: Liste des adresses ip pouvant accéder à la boutique quand celle-ci est en maintenance ("212.127.1.5, 192.135.0.1").
|
||||
|
||||
## Utilisation
|
||||
|
||||
Réglez les paramètres du module, cochez la case "Afficher le mode maintenance".
|
||||
Click on "Configure" button and check "Put the store in maintenance mode".
|
||||
Define the message displayed to the shop visitors in Reminder message field.
|
||||
|
||||
Les templates du mode maintenance sont définis dans Maintenance/templates/frontOffice/default/maintenance. N'hésitez pas à personnaliser les 3 (maintenance, simple et light) exemples fournis pour mieux correspondre au design de votre boutique, ou a créer le vôtre.
|
||||
|
||||
Enregistrez vos paramètres. La boutique est en mode maintenance. Pour quittez le mode maintenance décochez la case et enregistrez votre configuration.
|
||||
|
||||
Dans le mode maintenance, les utilisateurs connectés au back office Thelia accèdent normalement à la boutique (un message est affiché en haut des pages rappelle que le mode maintenance est activé).
|
||||
Vous pouvez toujours accéder à la boutique en mode développement (vous savez, index_dev.php).
|
||||
11
local/modules/Maintenance/composer.json
Normal file
11
local/modules/Maintenance/composer.json
Normal file
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"name": "vlopes/maintenance-module",
|
||||
"license": "LGPL-3.0+",
|
||||
"type": "thelia-module",
|
||||
"require": {
|
||||
"thelia/installer": "~1.1"
|
||||
},
|
||||
"extra": {
|
||||
"installer-name": "Maintenance"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
<div class="row">
|
||||
<div class="col-md-12 general-block-decorator">
|
||||
<div class="row">
|
||||
<div class="col-md-12 title title-without-tabs">
|
||||
{intl d="maintenance.fo.default" l="Maintenance mode"}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-container">
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<div class="alert alert-info">
|
||||
<p>{intl d="maintenance.fo.default" l="Le mode maintenance permet de fermer temporairement votre boutique, en affichant un message de votre choix à vos visiteurs."}</p>
|
||||
<p>{intl d="maintenance.fo.default" l="Sur cette page vous pouvez activer ou désactiver le mode maintenance, configurer les accès autorisés et régler les paramètres d'affichage."}</p>
|
||||
<p>{intl d="maintenance.fo.default" l="Vous conservez toujours un accès à la boutique si vous etes connecté en tant qu'administrateur, ou accédez à la boutique en mode développement. Dans ce cas, un rappel du mode maintenance est affiché sur la boutique. Vous pouvez le modifier dans le template frontOffice/default/maintenance/maintenance_warning.html."}</p>
|
||||
</div>
|
||||
|
||||
{form name="admin_maintenance_settings"}
|
||||
<form action="{url path="/admin/module/maintenance/configure"}" method="post">
|
||||
{if $form_error}
|
||||
<div class="alert alert-danger">{$form_error_message}</div>
|
||||
{/if}
|
||||
|
||||
{form_hidden_fields}
|
||||
|
||||
{render_form_field field="maintenance_mode" value={config key="com.omnitic.maintenance_mode"}}
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
{custom_render_form_field field="maintenance_template_name"}
|
||||
<div class="input-group">
|
||||
<input type="text" {form_field_attributes field="maintenance_template_name" value={config key="com.omnitic.maintenance_template_name"}}>
|
||||
<span class="input-group-btn">
|
||||
<a href="{url path="/maintenance-preview"}" class="btn btn-info" target="maintenance_preview" title="{intl d="maintenance.fo.default" l="Save your changes to get proper preview !"}">{intl d="maintenance.fo.default" l="Preview"}</a>
|
||||
</span>
|
||||
</div>
|
||||
{/custom_render_form_field}
|
||||
</div>
|
||||
|
||||
<div class="col-md-6">
|
||||
{render_form_field field="maintenance_allowed_ips" value={config key="com.omnitic.maintenance_allowed_ips"}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{render_form_field field="maintenance_message" value={config key="com.omnitic.maintenance_message"} extra_class="wysiwyg"}
|
||||
|
||||
<div class="form-group">
|
||||
<button type="submit" name="save_mode" value="stay" class="form-submit-button btn btn-success" title="{intl l='Save changes'}">{intl l='Save changes'} <span class="glyphicon glyphicon-ok"></span></button>
|
||||
</div>
|
||||
</form>
|
||||
{/form}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,41 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta http-equiv="content-type" content="text/html;charset=utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
|
||||
<meta name="description" content="">
|
||||
<meta name="author" content="{config key="store_name"}">
|
||||
<meta name="viewport" content="width=device-width, minimum-scale=1.0, initial-scale=1.0">
|
||||
<title>{config key="store_name"}</title>
|
||||
<style type="text/css">
|
||||
.paper {
|
||||
font-family: "Open Sans", sans serif;
|
||||
background-color: #1D7CBE;
|
||||
}
|
||||
.message {
|
||||
margin:10% auto;
|
||||
padding:30px;
|
||||
width:50%;
|
||||
}
|
||||
.message {
|
||||
color: #fff;
|
||||
font-size:24px;
|
||||
}
|
||||
.message .store-name {
|
||||
font-size:18px;
|
||||
}
|
||||
.fa {
|
||||
font-size:80px;
|
||||
}
|
||||
</style>
|
||||
<link href='//fonts.googleapis.com/css?family=Ubuntu:600' rel='stylesheet' type='text/css'>
|
||||
<link href="//maxcdn.bootstrapcdn.com/font-awesome/4.1.0/css/font-awesome.min.css" rel="stylesheet">
|
||||
</head>
|
||||
<body class="paper">
|
||||
<div class="message">
|
||||
<p><i class="fa fa-clock-o"></i></p>
|
||||
<div class="message-text">{config key="com.omnitic.maintenance_message"}</div>
|
||||
<p class="store-name">{config key="store_name"}</p>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,3 @@
|
||||
<div style="position: fixed; top: 0; left: 0; color: #fff; background-color: #ff8000; font-size: 12px; padding: 2px 10px; opacity: 0.5; z-index: 99999">
|
||||
{intl l="Maintenance mode is active" d="maintenance.fo.default"}
|
||||
</div>
|
||||
@@ -0,0 +1,39 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta http-equiv="content-type" content="text/html;charset=utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
|
||||
<meta name="description" content="">
|
||||
<meta name="author" content="{config key="store_name"}">
|
||||
<meta name="viewport" content="width=device-width, minimum-scale=1.0, initial-scale=1.0">
|
||||
<title>{config key="store_name"}</title>
|
||||
<style type="text/css">
|
||||
.paper {
|
||||
font-family: "Open Sans", sans serif;
|
||||
background-color: #466176;
|
||||
}
|
||||
.message {
|
||||
margin:10% auto;
|
||||
padding:30px;
|
||||
width:50%;
|
||||
}
|
||||
.message {
|
||||
text-align: center;
|
||||
color: #fff;
|
||||
font-size:18px;
|
||||
}
|
||||
.message .message-text {
|
||||
font-size:24px;
|
||||
}
|
||||
</style>
|
||||
<link href='//fonts.googleapis.com/css?family=Open+Sans:600' rel='stylesheet' type='text/css'>
|
||||
<link href="//maxcdn.bootstrapcdn.com/font-awesome/4.1.0/css/font-awesome.min.css" rel="stylesheet">
|
||||
</head>
|
||||
<body class="paper">
|
||||
<div class="message">
|
||||
<p class="store-name">{config key="store_name"}</p>
|
||||
<div class="message-text">{config key="com.omnitic.maintenance_message"}</div>
|
||||
<p><i class="fa fa-cog fa-spin"></i></p>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
49
local/modules/PayPlugModule/Command/TreatOrderMultiPaymentCommand.php
Executable file
49
local/modules/PayPlugModule/Command/TreatOrderMultiPaymentCommand.php
Executable file
@@ -0,0 +1,49 @@
|
||||
<?php
|
||||
|
||||
namespace PayPlugModule\Command;
|
||||
|
||||
use PayPlugModule\Event\PayPlugPaymentEvent;
|
||||
use PayPlugModule\Model\OrderPayPlugMultiPayment;
|
||||
use PayPlugModule\Model\OrderPayPlugMultiPaymentQuery;
|
||||
use Propel\Runtime\ActiveQuery\Criteria;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Thelia\Command\ContainerAwareCommand;
|
||||
|
||||
class TreatOrderMultiPaymentCommand extends ContainerAwareCommand
|
||||
{
|
||||
protected function configure()
|
||||
{
|
||||
$this
|
||||
->setName("payplug:treat:multi_payment")
|
||||
->setDescription("Treat multi payment order");
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$this->initRequest();
|
||||
$dispatcher = $this->getDispatcher();
|
||||
$today = (new \DateTime())->setTime(0,0,0,0);
|
||||
|
||||
$todayPlannedOrderPayments = OrderPayPlugMultiPaymentQuery::create()
|
||||
->filterByPaidAt(null, Criteria::ISNULL)
|
||||
->filterByPlannedAt($today)
|
||||
->find();
|
||||
|
||||
/** @var OrderPayPlugMultiPayment $todayPlannedOrderPayment */
|
||||
foreach ($todayPlannedOrderPayments as $todayPlannedOrderPayment) {
|
||||
$output->writeln($todayPlannedOrderPayment->getId());
|
||||
|
||||
$order = $todayPlannedOrderPayment->getOrder();
|
||||
$paymentEvent = @(new PayPlugPaymentEvent())->buildFromOrder($order)
|
||||
->setAmount($todayPlannedOrderPayment->getAmount())
|
||||
->setPaymentMethod($todayPlannedOrderPayment->getPaymentMethod())
|
||||
->setInitiator("MERCHANT");
|
||||
|
||||
$dispatcher->dispatch(PayPlugPaymentEvent::CREATE_PAYMENT_EVENT, $paymentEvent);
|
||||
|
||||
$todayPlannedOrderPayment->setPaymentId($paymentEvent->getPaymentId())
|
||||
->save();
|
||||
}
|
||||
}
|
||||
}
|
||||
77
local/modules/PayPlugModule/Config/config.xml
Executable file
77
local/modules/PayPlugModule/Config/config.xml
Executable file
@@ -0,0 +1,77 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
|
||||
<config xmlns="http://thelia.net/schema/dic/config"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://thelia.net/schema/dic/config http://thelia.net/schema/dic/config/thelia-1.0.xsd">
|
||||
|
||||
<loops>
|
||||
<!-- sample definition
|
||||
<loop name="MySuperLoop" class="PayPlugModule\Loop\MySuperLoop" />
|
||||
-->
|
||||
</loops>
|
||||
|
||||
<forms>
|
||||
<form name="payplugmodule_configuration_form" class="PayPlugModule\Form\ConfigurationForm" />
|
||||
<form name="payplugmodule_order_action_form" class="PayPlugModule\Form\OrderActionForm" />
|
||||
<form name="payplugmodule_order_action_form_refund" class="PayPlugModule\Form\OrderRefundForm" />
|
||||
</forms>
|
||||
|
||||
<commands>
|
||||
<command class="PayPlugModule\Command\TreatOrderMultiPaymentCommand" />
|
||||
</commands>
|
||||
|
||||
<services>
|
||||
<service id="payplugmodule_payment_service" class="PayPlugModule\Service\PaymentService">
|
||||
<argument type="service" id="event_dispatcher"/>
|
||||
</service>
|
||||
<service id="payplugmodule_order_status_service" class="PayPlugModule\Service\OrderStatusService">
|
||||
<argument type="service" id="event_dispatcher"/>
|
||||
</service>
|
||||
<service id="payplugmodule_notification_listener" class="PayPlugModule\EventListener\NotificationListener">
|
||||
<argument type="service" id="event_dispatcher"/>
|
||||
<argument type="service" id="payplugmodule_order_status_service"/>
|
||||
<tag name="kernel.event_subscriber"/>
|
||||
</service>
|
||||
<service id="payplugmodule_payment_listener" class="PayPlugModule\EventListener\PaymentListener">
|
||||
<argument type="service" id="event_dispatcher"/>
|
||||
<argument type="service" id="payplugmodule_order_status_service"/>
|
||||
<tag name="kernel.event_subscriber"/>
|
||||
</service>
|
||||
<service id="payplugmodule_order_listener" class="PayPlugModule\EventListener\OrderListener">
|
||||
<argument type="service" id="payplugmodule_payment_service"/>
|
||||
<tag name="kernel.event_subscriber"/>
|
||||
</service>
|
||||
<service id="payplugmodule_form_extend_order_listener" class="PayPlugModule\EventListener\FormExtend\OrderFormListener">
|
||||
<argument type="service" id="request_stack"/>
|
||||
<tag name="kernel.event_subscriber"/>
|
||||
</service>
|
||||
<service id="payplugmodule_conformation_emil_listener" class="PayPlugModule\EventListener\ConfirmationEmailListener">
|
||||
<argument type="service" id="mailer"/>
|
||||
<tag name="kernel.event_subscriber"/>
|
||||
</service>
|
||||
</services>
|
||||
|
||||
<hooks>
|
||||
<hook id="payplugmodule_back_hook" class="PayPlugModule\Hook\BackHookManager">
|
||||
<tag name="hook.event_listener" event="order-edit.payment-module-bottom" type="back" method="onOrderEditPaymentModuleBottom"/>
|
||||
<tag name="hook.event_listener" event="order.edit-js " type="back" templates="js:PayPlugModule/order_pay_plug.js"/>
|
||||
</hook>
|
||||
<hook id="payplugmodule_front_hook" class="PayPlugModule\Hook\FrontHookManager">
|
||||
<argument type="service" id="thelia.taxengine"/>
|
||||
<tag name="hook.event_listener" event="order-invoice.after-javascript-include" type="front" method="onOrderInvoiceAfterJsInclude"/>
|
||||
<tag name="hook.event_listener" event="order-invoice.payment-extra" type="front" method="onOrderInvoicePaymentExtra"/>
|
||||
</hook>
|
||||
</hooks>
|
||||
|
||||
<!--
|
||||
<exports>
|
||||
|
||||
</exports>
|
||||
-->
|
||||
|
||||
<!--
|
||||
<imports>
|
||||
|
||||
</imports>
|
||||
-->
|
||||
</config>
|
||||
32
local/modules/PayPlugModule/Config/module.xml
Executable file
32
local/modules/PayPlugModule/Config/module.xml
Executable file
@@ -0,0 +1,32 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module xmlns="http://thelia.net/schema/dic/module"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://thelia.net/schema/dic/module http://thelia.net/schema/dic/module/module-2_2.xsd">
|
||||
<fullnamespace>PayPlugModule\PayPlugModule</fullnamespace>
|
||||
<descriptive locale="en_US">
|
||||
<title>PayPlug payment module</title>
|
||||
<subtitle>https://www.payplug.com</subtitle>
|
||||
</descriptive>
|
||||
<descriptive locale="fr_FR">
|
||||
<title>Module de paiement PayPlug</title>
|
||||
<subtitle>https://www.payplug.com/fr</subtitle>
|
||||
</descriptive>
|
||||
<logo>payplug.png</logo>
|
||||
<images-folder>images</images-folder>
|
||||
<languages>
|
||||
<language>en_US</language>
|
||||
<language>fr_FR</language>
|
||||
</languages>
|
||||
<version>1.0.5</version>
|
||||
<authors>
|
||||
<author>
|
||||
<name>Vincent Lopes-Vicente</name>
|
||||
<email>vlopes@openstudio.fr</email>
|
||||
</author>
|
||||
</authors>
|
||||
<type>payment</type>
|
||||
<thelia>2.4.0</thelia>
|
||||
<stability>other</stability>
|
||||
<mandatory>0</mandatory>
|
||||
<hidden>0</hidden>
|
||||
</module>
|
||||
28
local/modules/PayPlugModule/Config/routing.xml
Executable file
28
local/modules/PayPlugModule/Config/routing.xml
Executable file
@@ -0,0 +1,28 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
|
||||
<routes xmlns="http://symfony.com/schema/routing"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://symfony.com/schema/routing http://symfony.com/schema/routing/routing-1.0.xsd">
|
||||
|
||||
<route id="admin.payplugmodule.config" path="/admin/module/PayPlugModule">
|
||||
<default key="_controller">PayPlugModule\Controller\Admin\ConfigurationController::viewAction</default>
|
||||
</route>
|
||||
<route id="admin.payplugmodule.config.save" path="/admin/module/payplugmodule/configuration" methods="POST">
|
||||
<default key="_controller">PayPlugModule\Controller\Admin\ConfigurationController::saveAction</default>
|
||||
</route>
|
||||
<route id="admin.payplugmodule.order.refund" path="/admin/payplugmodule/order/refund" methods="POST">
|
||||
<default key="_controller">PayPlugModule\Controller\Admin\OrderController::refundAction</default>
|
||||
</route>
|
||||
<route id="admin.payplugmodule.order.capture" path="/admin/payplugmodule/order/capture" methods="POST">
|
||||
<default key="_controller">PayPlugModule\Controller\Admin\OrderController::captureAction</default>
|
||||
</route>
|
||||
|
||||
<route id="payplugmodule_notification" path="/payplug/notification">
|
||||
<default key="_controller">PayPlugModule\Controller\NotificationController::entryPoint</default>
|
||||
</route>
|
||||
|
||||
<route id="payplugmodule_delete_card" path="/payplug/card/delete">
|
||||
<default key="_controller">PayPlugModule\Controller\CardController::deleteCurrentCustomerCard</default>
|
||||
</route>
|
||||
|
||||
</routes>
|
||||
57
local/modules/PayPlugModule/Config/schema.xml
Executable file
57
local/modules/PayPlugModule/Config/schema.xml
Executable file
@@ -0,0 +1,57 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<database defaultIdMethod="native" name="thelia"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://thelia.net/schema/dic/config http://thelia.net/schema/dic/config/thelia-1.0.xsd">
|
||||
|
||||
<table name="order_pay_plug_data" namespace="PayPlugModule\Model">
|
||||
<column name="id" type="INTEGER" required="true" primaryKey="true"/>
|
||||
<column name="amount_refunded" scale="6" size="16" type="DECIMAL" />
|
||||
<column name="need_capture" type="TINYINT" default="0"/>
|
||||
<column name="capture_expire_at" type="TIMESTAMP" />
|
||||
<column name="captured_at" type="TIMESTAMP" />
|
||||
|
||||
<foreign-key foreignTable="order" onDelete="CASCADE" onUpdate="CASCADE">
|
||||
<reference local="id" foreign="id" />
|
||||
</foreign-key>
|
||||
</table>
|
||||
|
||||
<table name="pay_plug_card" namespace="PayPlugModule\Model">
|
||||
<column name="uuid" type="VARCHAR" size="150" primaryKey="true"/>
|
||||
<column name="customer_id" type="INTEGER"/>
|
||||
<column name="brand" type="VARCHAR" size="255" />
|
||||
<column name="last_4" type="VARCHAR" size="255" />
|
||||
<column name="expire_month" type="INTEGER" />
|
||||
<column name="expire_year" type="INTEGER" />
|
||||
|
||||
<foreign-key foreignTable="customer" onDelete="CASCADE" onUpdate="CASCADE">
|
||||
<reference local="customer_id" foreign="id" />
|
||||
</foreign-key>
|
||||
</table>
|
||||
|
||||
<table name="order_pay_plug_multi_payment" namespace="PayPlugModule\Model">
|
||||
<column autoIncrement="true" name="id" type="INTEGER" required="true" primaryKey="true"/>
|
||||
<column name="order_id" type="INTEGER" required="true" primaryKey="true"/>
|
||||
<column name="amount" scale="6" size="16" type="DECIMAL" />
|
||||
<column name="is_first_payment" type="TINYINT" default="0"/>
|
||||
<column name="planned_at" type="TIMESTAMP" />
|
||||
<column name="payment_method" type="VARCHAR" size="255" />
|
||||
<column name="payment_id" type="VARCHAR" size="255" />
|
||||
<column name="paid_at" type="TIMESTAMP" />
|
||||
<column name="amount_refunded" scale="6" size="16" type="DECIMAL" default="0"/>
|
||||
|
||||
<foreign-key foreignTable="order" onDelete="CASCADE" onUpdate="CASCADE">
|
||||
<reference local="order_id" foreign="id" />
|
||||
</foreign-key>
|
||||
</table>
|
||||
|
||||
<table name="pay_plug_module_delivery_type" namespace="PayPlugModule\Model">
|
||||
<column autoIncrement="true" name="id" primaryKey="true" required="true" type="INTEGER" />
|
||||
<column name="module_id" type="integer" />
|
||||
<column name="delivery_type" size="255" type="VARCHAR" />
|
||||
<foreign-key foreignTable="module" name="fk_pay_plug_module_delivery_type_module_id" onDelete="CASCADE" onUpdate="RESTRICT">
|
||||
<reference foreign="id" local="module_id" />
|
||||
</foreign-key>
|
||||
</table>
|
||||
|
||||
<external-schema filename="local/config/schema.xml" referenceOnly="true" />
|
||||
</database>
|
||||
2
local/modules/PayPlugModule/Config/sqldb.map
Executable file
2
local/modules/PayPlugModule/Config/sqldb.map
Executable file
@@ -0,0 +1,2 @@
|
||||
# Sqlfile -> Database map
|
||||
thelia.sql=thelia
|
||||
97
local/modules/PayPlugModule/Config/thelia.sql
Normal file
97
local/modules/PayPlugModule/Config/thelia.sql
Normal file
@@ -0,0 +1,97 @@
|
||||
|
||||
# This is a fix for InnoDB in MySQL >= 4.1.x
|
||||
# It "suspends judgement" for fkey relationships until are tables are set.
|
||||
SET FOREIGN_KEY_CHECKS = 0;
|
||||
|
||||
-- ---------------------------------------------------------------------
|
||||
-- order_pay_plug_data
|
||||
-- ---------------------------------------------------------------------
|
||||
|
||||
DROP TABLE IF EXISTS `order_pay_plug_data`;
|
||||
|
||||
CREATE TABLE `order_pay_plug_data`
|
||||
(
|
||||
`id` INTEGER NOT NULL,
|
||||
`amount_refunded` DECIMAL(16,6),
|
||||
`need_capture` TINYINT DEFAULT 0,
|
||||
`capture_expire_at` DATETIME,
|
||||
`captured_at` DATETIME,
|
||||
PRIMARY KEY (`id`),
|
||||
CONSTRAINT `order_pay_plug_data_fk_19ea48`
|
||||
FOREIGN KEY (`id`)
|
||||
REFERENCES `order` (`id`)
|
||||
ON UPDATE CASCADE
|
||||
ON DELETE CASCADE
|
||||
) ENGINE=InnoDB;
|
||||
|
||||
-- ---------------------------------------------------------------------
|
||||
-- pay_plug_card
|
||||
-- ---------------------------------------------------------------------
|
||||
|
||||
DROP TABLE IF EXISTS `pay_plug_card`;
|
||||
|
||||
CREATE TABLE `pay_plug_card`
|
||||
(
|
||||
`uuid` VARCHAR(150) NOT NULL,
|
||||
`customer_id` INTEGER,
|
||||
`brand` VARCHAR(255),
|
||||
`last_4` VARCHAR(255),
|
||||
`expire_month` INTEGER,
|
||||
`expire_year` INTEGER,
|
||||
PRIMARY KEY (`uuid`),
|
||||
INDEX `pay_plug_card_fi_7e8f3e` (`customer_id`),
|
||||
CONSTRAINT `pay_plug_card_fk_7e8f3e`
|
||||
FOREIGN KEY (`customer_id`)
|
||||
REFERENCES `customer` (`id`)
|
||||
ON UPDATE CASCADE
|
||||
ON DELETE CASCADE
|
||||
) ENGINE=InnoDB;
|
||||
|
||||
-- ---------------------------------------------------------------------
|
||||
-- order_pay_plug_multi_payment
|
||||
-- ---------------------------------------------------------------------
|
||||
|
||||
DROP TABLE IF EXISTS `order_pay_plug_multi_payment`;
|
||||
|
||||
CREATE TABLE `order_pay_plug_multi_payment`
|
||||
(
|
||||
`id` INTEGER NOT NULL AUTO_INCREMENT,
|
||||
`order_id` INTEGER NOT NULL,
|
||||
`amount` DECIMAL(16,6),
|
||||
`is_first_payment` TINYINT DEFAULT 0,
|
||||
`planned_at` DATETIME,
|
||||
`payment_method` VARCHAR(255),
|
||||
`payment_id` VARCHAR(255),
|
||||
`paid_at` DATETIME,
|
||||
`amount_refunded` DECIMAL(16,6) DEFAULT 0,
|
||||
PRIMARY KEY (`id`,`order_id`),
|
||||
INDEX `order_pay_plug_multi_payment_fi_75704f` (`order_id`),
|
||||
CONSTRAINT `order_pay_plug_multi_payment_fk_75704f`
|
||||
FOREIGN KEY (`order_id`)
|
||||
REFERENCES `order` (`id`)
|
||||
ON UPDATE CASCADE
|
||||
ON DELETE CASCADE
|
||||
) ENGINE=InnoDB;
|
||||
|
||||
-- ---------------------------------------------------------------------
|
||||
-- pay_plug_module_delivery_type
|
||||
-- ---------------------------------------------------------------------
|
||||
|
||||
DROP TABLE IF EXISTS `pay_plug_module_delivery_type`;
|
||||
|
||||
CREATE TABLE `pay_plug_module_delivery_type`
|
||||
(
|
||||
`id` INTEGER NOT NULL AUTO_INCREMENT,
|
||||
`module_id` INTEGER,
|
||||
`delivery_type` VARCHAR(255),
|
||||
PRIMARY KEY (`id`),
|
||||
INDEX `fi_pay_plug_module_delivery_type_module_id` (`module_id`),
|
||||
CONSTRAINT `fk_pay_plug_module_delivery_type_module_id`
|
||||
FOREIGN KEY (`module_id`)
|
||||
REFERENCES `module` (`id`)
|
||||
ON UPDATE RESTRICT
|
||||
ON DELETE CASCADE
|
||||
) ENGINE=InnoDB;
|
||||
|
||||
# This restores the fkey checks, after having unset them earlier
|
||||
SET FOREIGN_KEY_CHECKS = 1;
|
||||
9
local/modules/PayPlugModule/Config/update/1.0.2.sql
Normal file
9
local/modules/PayPlugModule/Config/update/1.0.2.sql
Normal file
@@ -0,0 +1,9 @@
|
||||
# This is a fix for InnoDB in MySQL >= 4.1.x
|
||||
# It "suspends judgement" for fkey relationships until are tables are set.
|
||||
SET FOREIGN_KEY_CHECKS = 0;
|
||||
|
||||
ALTER TABLE `order_pay_plug_multi_payment` ADD COLUMN `amount_refunded` DECIMAL(16,6) DEFAULT 0;
|
||||
ALTER TABLE `order_pay_plug_multi_payment` DROP COLUMN `refunded_at`;
|
||||
|
||||
# This restores the fkey checks, after having unset them earlier
|
||||
SET FOREIGN_KEY_CHECKS = 1;
|
||||
27
local/modules/PayPlugModule/Config/update/1.0.3.sql
Normal file
27
local/modules/PayPlugModule/Config/update/1.0.3.sql
Normal file
@@ -0,0 +1,27 @@
|
||||
# This is a fix for InnoDB in MySQL >= 4.1.x
|
||||
# It "suspends judgement" for fkey relationships until are tables are set.
|
||||
SET FOREIGN_KEY_CHECKS = 0;
|
||||
|
||||
|
||||
-- ---------------------------------------------------------------------
|
||||
-- pay_plug_module_delivery_type
|
||||
-- ---------------------------------------------------------------------
|
||||
|
||||
DROP TABLE IF EXISTS `pay_plug_module_delivery_type`;
|
||||
|
||||
CREATE TABLE `pay_plug_module_delivery_type`
|
||||
(
|
||||
`id` INTEGER NOT NULL AUTO_INCREMENT,
|
||||
`module_id` INTEGER,
|
||||
`delivery_type` VARCHAR(255),
|
||||
PRIMARY KEY (`id`),
|
||||
INDEX `fi_pay_plug_module_delivery_type_module_id` (`module_id`),
|
||||
CONSTRAINT `fk_pay_plug_module_delivery_type_module_id`
|
||||
FOREIGN KEY (`module_id`)
|
||||
REFERENCES `module` (`id`)
|
||||
ON UPDATE RESTRICT
|
||||
ON DELETE CASCADE
|
||||
) ENGINE=InnoDB;
|
||||
|
||||
# This restores the fkey checks, after having unset them earlier
|
||||
SET FOREIGN_KEY_CHECKS = 1;
|
||||
72
local/modules/PayPlugModule/Controller/Admin/ConfigurationController.php
Executable file
72
local/modules/PayPlugModule/Controller/Admin/ConfigurationController.php
Executable file
@@ -0,0 +1,72 @@
|
||||
<?php
|
||||
|
||||
namespace PayPlugModule\Controller\Admin;
|
||||
|
||||
use PayPlugModule\Form\ConfigurationForm;
|
||||
use PayPlugModule\Model\PayPlugConfigValue;
|
||||
use PayPlugModule\Model\PayPlugModuleDeliveryTypeQuery;
|
||||
use PayPlugModule\PayPlugModule;
|
||||
use PayPlugModule\Service\OrderStatusService;
|
||||
use Thelia\Controller\Admin\BaseAdminController;
|
||||
use Thelia\Core\Security\AccessManager;
|
||||
use Thelia\Core\Security\Resource\AdminResources;
|
||||
use Thelia\Core\Translation\Translator;
|
||||
|
||||
class ConfigurationController extends BaseAdminController
|
||||
{
|
||||
public function viewAction()
|
||||
{
|
||||
// Create default order statuses
|
||||
/** @var OrderStatusService $orderStatusesService */
|
||||
$orderStatusesService = $this->container->get('payplugmodule_order_status_service');
|
||||
$orderStatusesService->initAllStatuses();
|
||||
$deliveryModuleFormFields = ConfigurationForm::getDeliveryModuleFormFields();
|
||||
|
||||
return $this->render(
|
||||
"PayPlugModule/configuration",
|
||||
compact('deliveryModuleFormFields')
|
||||
);
|
||||
}
|
||||
|
||||
public function saveAction()
|
||||
{
|
||||
if (null !== $response = $this->checkAuth(array(AdminResources::MODULE), 'PayPlugModule', AccessManager::UPDATE)) {
|
||||
return $response;
|
||||
}
|
||||
|
||||
$form = $this->createForm('payplugmodule_configuration_form');
|
||||
|
||||
try {
|
||||
$data = $this->validateForm($form)->getData();
|
||||
|
||||
foreach ($data as $key => $value) {
|
||||
if (in_array($key, PayPlugConfigValue::getConfigKeys())) {
|
||||
PayPlugModule::setConfigValue($key, $value);
|
||||
}
|
||||
|
||||
$explodedKey = explode(':', $key);
|
||||
if ($explodedKey[0] === ConfigurationForm::DELIVERY_MODULE_TYPE_KEY_PREFIX) {
|
||||
$moduleId = $explodedKey[1];
|
||||
$payPlugModuleDeliveryType = PayPlugModuleDeliveryTypeQuery::create()->filterByModuleId($moduleId)->findOneOrCreate();
|
||||
$payPlugModuleDeliveryType->setDeliveryType($value)
|
||||
->save();
|
||||
}
|
||||
}
|
||||
|
||||
} catch (\Exception $e) {
|
||||
$this->setupFormErrorContext(
|
||||
Translator::getInstance()->trans(
|
||||
"Error",
|
||||
[],
|
||||
PayPlugModule::DOMAIN_NAME
|
||||
),
|
||||
$e->getMessage(),
|
||||
$form
|
||||
);
|
||||
return $this->viewAction();
|
||||
}
|
||||
|
||||
return $this->generateSuccessRedirect($form);
|
||||
}
|
||||
|
||||
}
|
||||
84
local/modules/PayPlugModule/Controller/Admin/OrderController.php
Executable file
84
local/modules/PayPlugModule/Controller/Admin/OrderController.php
Executable file
@@ -0,0 +1,84 @@
|
||||
<?php
|
||||
|
||||
namespace PayPlugModule\Controller\Admin;
|
||||
|
||||
use PayPlugModule\PayPlugModule;
|
||||
use PayPlugModule\Service\PaymentService;
|
||||
use Thelia\Controller\Admin\BaseAdminController;
|
||||
use Thelia\Core\Security\AccessManager;
|
||||
use Thelia\Core\Security\Resource\AdminResources;
|
||||
use Thelia\Core\Translation\Translator;
|
||||
use Thelia\Model\OrderQuery;
|
||||
|
||||
class OrderController extends BaseAdminController
|
||||
{
|
||||
public function refundAction()
|
||||
{
|
||||
if (null !== $response = $this->checkAuth(array(AdminResources::MODULE), 'PayPlugModule', AccessManager::UPDATE)) {
|
||||
return $response;
|
||||
}
|
||||
|
||||
$form = $this->createForm('payplugmodule_order_action_form_refund');
|
||||
|
||||
try {
|
||||
$data = $this->validateForm($form)->getData();
|
||||
$order = OrderQuery::create()
|
||||
->findOneById($data['order_id']);
|
||||
|
||||
$amountToRefund = (int)($data['refund_amount'] * 100);
|
||||
|
||||
/** @var PaymentService $paymentService */
|
||||
$paymentService = $this->container->get('payplugmodule_payment_service');
|
||||
$paymentService->doOrderRefund($order, $amountToRefund);
|
||||
} catch (\Exception $e) {
|
||||
$this->setupFormErrorContext(
|
||||
Translator::getInstance()->trans(
|
||||
"Error",
|
||||
[],
|
||||
PayPlugModule::DOMAIN_NAME
|
||||
),
|
||||
$e->getMessage(),
|
||||
$form
|
||||
);
|
||||
}
|
||||
|
||||
// Sleep to let time for PayPlug to send validation
|
||||
sleep(2);
|
||||
$url = $this->retrieveSuccessUrl($form);
|
||||
return $this->generateRedirect($url.'#orderPayPlug');
|
||||
}
|
||||
|
||||
public function captureAction()
|
||||
{
|
||||
if (null !== $response = $this->checkAuth(array(AdminResources::MODULE), 'PayPlugModule', AccessManager::UPDATE)) {
|
||||
return $response;
|
||||
}
|
||||
|
||||
$form = $this->createForm('payplugmodule_order_action_form');
|
||||
|
||||
try {
|
||||
$data = $this->validateForm($form)->getData();
|
||||
$order = OrderQuery::create()
|
||||
->findOneById($data['order_id']);
|
||||
|
||||
/** @var PaymentService $paymentService */
|
||||
$paymentService = $this->container->get('payplugmodule_payment_service');
|
||||
$paymentService->doOrderCapture($order);
|
||||
} catch (\Exception $e) {
|
||||
$this->setupFormErrorContext(
|
||||
Translator::getInstance()->trans(
|
||||
"Error",
|
||||
[],
|
||||
PayPlugModule::DOMAIN_NAME
|
||||
),
|
||||
$e->getMessage(),
|
||||
$form
|
||||
);
|
||||
}
|
||||
|
||||
// Sleep to let time for PayPlug to send validation
|
||||
sleep(2);
|
||||
$url = $this->retrieveSuccessUrl($form);
|
||||
return $this->generateRedirect($url.'#orderPayPlug');
|
||||
}
|
||||
}
|
||||
22
local/modules/PayPlugModule/Controller/CardController.php
Executable file
22
local/modules/PayPlugModule/Controller/CardController.php
Executable file
@@ -0,0 +1,22 @@
|
||||
<?php
|
||||
|
||||
namespace PayPlugModule\Controller;
|
||||
|
||||
use PayPlugModule\Model\PayPlugCardQuery;
|
||||
use Thelia\Controller\Front\BaseFrontController;
|
||||
use Thelia\Core\HttpFoundation\Request;
|
||||
|
||||
class CardController extends BaseFrontController
|
||||
{
|
||||
public function deleteCurrentCustomerCard(Request $request)
|
||||
{
|
||||
$customerId = $request->getSession()->getCustomerUser()->getId();
|
||||
|
||||
if (null !== $card = PayPlugCardQuery::create()->findOneByCustomerId($customerId)) {
|
||||
$card->delete();
|
||||
}
|
||||
|
||||
return $this->generateRedirect($this->getSession()->getReturnToUrl());
|
||||
}
|
||||
|
||||
}
|
||||
28
local/modules/PayPlugModule/Controller/NotificationController.php
Executable file
28
local/modules/PayPlugModule/Controller/NotificationController.php
Executable file
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
namespace PayPlugModule\Controller;
|
||||
|
||||
use PayPlugModule\Event\Notification\UnknownNotificationEvent;
|
||||
use PayPlugModule\Service\PaymentService;
|
||||
use Thelia\Controller\Front\BaseFrontController;
|
||||
use Thelia\Core\HttpFoundation\Request;
|
||||
use Thelia\Core\HttpFoundation\Response;
|
||||
use Thelia\Log\Tlog;
|
||||
|
||||
class NotificationController extends BaseFrontController
|
||||
{
|
||||
public function entryPoint(Request $request)
|
||||
{
|
||||
/** @var PaymentService $paymentService */
|
||||
$paymentService = $this->container->get('payplugmodule_payment_service');
|
||||
Tlog::getInstance()->addAlert('Notification received');
|
||||
Tlog::getInstance()->addAlert($request->getContent());
|
||||
|
||||
$notificationResource = $paymentService->getNotificationResource($request);
|
||||
|
||||
$notificationEvent = new UnknownNotificationEvent($notificationResource);
|
||||
$this->dispatch(UnknownNotificationEvent::UNKNOWN_NOTIFICATION_EVENT, $notificationEvent);
|
||||
|
||||
return new Response();
|
||||
}
|
||||
}
|
||||
37
local/modules/PayPlugModule/Event/Notification/PaymentNotificationEvent.php
Executable file
37
local/modules/PayPlugModule/Event/Notification/PaymentNotificationEvent.php
Executable file
@@ -0,0 +1,37 @@
|
||||
<?php
|
||||
|
||||
namespace PayPlugModule\Event\Notification;
|
||||
|
||||
use Payplug\Resource\Payment;
|
||||
use Thelia\Core\Event\ActionEvent;
|
||||
|
||||
class PaymentNotificationEvent extends ActionEvent
|
||||
{
|
||||
const PAYMENT_NOTIFICATION_EVENT = "payplugmodule_payment_notification_event";
|
||||
|
||||
/** @var Payment */
|
||||
protected $resource;
|
||||
|
||||
public function __construct(Payment $resource)
|
||||
{
|
||||
$this->resource = $resource;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Payment
|
||||
*/
|
||||
public function getResource(): Payment
|
||||
{
|
||||
return $this->resource;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Payment $resource
|
||||
* @return PaymentNotificationEvent
|
||||
*/
|
||||
public function setResource(Payment $resource): PaymentNotificationEvent
|
||||
{
|
||||
$this->resource = $resource;
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
37
local/modules/PayPlugModule/Event/Notification/RefundNotificationEvent.php
Executable file
37
local/modules/PayPlugModule/Event/Notification/RefundNotificationEvent.php
Executable file
@@ -0,0 +1,37 @@
|
||||
<?php
|
||||
|
||||
namespace PayPlugModule\Event\Notification;
|
||||
|
||||
use Payplug\Resource\Refund;
|
||||
use Thelia\Core\Event\ActionEvent;
|
||||
|
||||
class RefundNotificationEvent extends ActionEvent
|
||||
{
|
||||
const REFUND_NOTIFICATION_EVENT = "payplugmodule_refund_notification_event";
|
||||
|
||||
/** @var Refund */
|
||||
protected $resource;
|
||||
|
||||
public function __construct(Refund $resource)
|
||||
{
|
||||
$this->resource = $resource;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Refund
|
||||
*/
|
||||
public function getResource(): Refund
|
||||
{
|
||||
return $this->resource;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Refund $resource
|
||||
* @return RefundNotificationEvent
|
||||
*/
|
||||
public function setResource(Refund $resource): RefundNotificationEvent
|
||||
{
|
||||
$this->resource = $resource;
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
37
local/modules/PayPlugModule/Event/Notification/UnknownNotificationEvent.php
Executable file
37
local/modules/PayPlugModule/Event/Notification/UnknownNotificationEvent.php
Executable file
@@ -0,0 +1,37 @@
|
||||
<?php
|
||||
|
||||
namespace PayPlugModule\Event\Notification;
|
||||
|
||||
use Payplug\Resource\IVerifiableAPIResource;
|
||||
use Thelia\Core\Event\ActionEvent;
|
||||
|
||||
class UnknownNotificationEvent extends ActionEvent
|
||||
{
|
||||
const UNKNOWN_NOTIFICATION_EVENT = "payplugmodule_unknown_notification_event";
|
||||
|
||||
/** @var IVerifiableAPIResource */
|
||||
protected $resource;
|
||||
|
||||
public function __construct(IVerifiableAPIResource $resource)
|
||||
{
|
||||
$this->resource = $resource;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return IVerifiableAPIResource
|
||||
*/
|
||||
public function getResource(): IVerifiableAPIResource
|
||||
{
|
||||
return $this->resource;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param IVerifiableAPIResource $resource
|
||||
* @return UnknownNotificationEvent
|
||||
*/
|
||||
public function setResource(IVerifiableAPIResource $resource): UnknownNotificationEvent
|
||||
{
|
||||
$this->resource = $resource;
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
1605
local/modules/PayPlugModule/Event/PayPlugPaymentEvent.php
Executable file
1605
local/modules/PayPlugModule/Event/PayPlugPaymentEvent.php
Executable file
File diff suppressed because it is too large
Load Diff
249
local/modules/PayPlugModule/Event/PayPlugProduct.php
Normal file
249
local/modules/PayPlugModule/Event/PayPlugProduct.php
Normal file
@@ -0,0 +1,249 @@
|
||||
<?php
|
||||
|
||||
namespace PayPlugModule\Event;
|
||||
|
||||
use PayPlugModule\Model\PayPlugModuleDeliveryType;
|
||||
use PayPlugModule\PayPlugModule;
|
||||
use Thelia\Core\Translation\Translator;
|
||||
use Thelia\Model\Base\OrderProduct;
|
||||
use Thelia\Model\Base\OrderProductTax;
|
||||
use Thelia\Model\ConfigQuery;
|
||||
|
||||
class PayPlugProduct
|
||||
{
|
||||
/** @var string */
|
||||
protected $brand;
|
||||
|
||||
/** @var string */
|
||||
protected $expectedDeliveryDate;
|
||||
|
||||
/** @var string */
|
||||
protected $deliveryLabel;
|
||||
|
||||
/** @var string */
|
||||
protected $deliveryType;
|
||||
|
||||
/** @var string */
|
||||
protected $merchantItemId;
|
||||
|
||||
/** @var string */
|
||||
protected $name;
|
||||
|
||||
/** @var integer */
|
||||
protected $price;
|
||||
|
||||
/** @var integer */
|
||||
protected $quantity;
|
||||
|
||||
/** @var integer */
|
||||
protected $totalAmount;
|
||||
|
||||
public function buildFromOrderProduct(OrderProduct $orderProduct, PayPlugModuleDeliveryType $payPlugModuleDeliveryType = null)
|
||||
{
|
||||
$storeName = ConfigQuery::read(
|
||||
'store_name',
|
||||
Translator::getInstance()->trans(
|
||||
'Unknown',
|
||||
[],
|
||||
PayPlugModule::DOMAIN_NAME
|
||||
)
|
||||
);
|
||||
|
||||
$deliveryType = $payPlugModuleDeliveryType !== null ? $payPlugModuleDeliveryType->getDeliveryType() : 'carrier';
|
||||
// Brand can't be find from order product but it's required so set store name as brand or "Unknown"
|
||||
$this->setBrand($storeName);
|
||||
$this->setExpectedDeliveryDate(date('Y-m-d'));
|
||||
$this->setDeliveryLabel($storeName);
|
||||
$this->setDeliveryType($deliveryType);
|
||||
$this->setMerchantItemId($orderProduct->getId());
|
||||
$this->setName($orderProduct->getTitle());
|
||||
|
||||
$orderProductTaxes = $orderProduct->getOrderProductTaxes();
|
||||
$tax = array_reduce(
|
||||
iterator_to_array($orderProductTaxes),
|
||||
function ($accumulator, OrderProductTax $orderProductTax) {
|
||||
return $accumulator + $orderProductTax->getAmount();
|
||||
},
|
||||
0
|
||||
);
|
||||
$promoTax = array_reduce(
|
||||
iterator_to_array($orderProductTaxes),
|
||||
function ($accumulator, OrderProductTax $orderProductTax) {
|
||||
return $accumulator + $orderProductTax->getPromoAmount();
|
||||
},
|
||||
0
|
||||
);
|
||||
|
||||
$taxedPrice = round((float) $orderProduct->getPrice() + $tax, 2);
|
||||
$taxedPromoPrice = round((float) $orderProduct->getPromoPrice() + $promoTax, 2);
|
||||
|
||||
$price = $orderProduct->getWasInPromo() ? $taxedPromoPrice : $taxedPrice;
|
||||
$this->setPrice($price * 100);
|
||||
$this->setQuantity($orderProduct->getQuantity());
|
||||
$this->setTotalAmount($price * $orderProduct->getQuantity() * 100);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getBrand()
|
||||
{
|
||||
return $this->brand;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $brand
|
||||
* @return PayPlugProduct
|
||||
*/
|
||||
public function setBrand(string $brand): PayPlugProduct
|
||||
{
|
||||
$this->brand = $brand;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getExpectedDeliveryDate()
|
||||
{
|
||||
return $this->expectedDeliveryDate;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $expectedDeliveryDate
|
||||
* @return PayPlugProduct
|
||||
*/
|
||||
public function setExpectedDeliveryDate(string $expectedDeliveryDate): PayPlugProduct
|
||||
{
|
||||
$this->expectedDeliveryDate = $expectedDeliveryDate;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getDeliveryLabel()
|
||||
{
|
||||
return $this->deliveryLabel;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $deliveryLabel
|
||||
* @return PayPlugProduct
|
||||
*/
|
||||
public function setDeliveryLabel(string $deliveryLabel): PayPlugProduct
|
||||
{
|
||||
$this->deliveryLabel = $deliveryLabel;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getDeliveryType()
|
||||
{
|
||||
return $this->deliveryType;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $deliveryType
|
||||
* @return PayPlugProduct
|
||||
*/
|
||||
public function setDeliveryType(string $deliveryType): PayPlugProduct
|
||||
{
|
||||
$this->deliveryType = $deliveryType;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getMerchantItemId()
|
||||
{
|
||||
return $this->merchantItemId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $merchantItemId
|
||||
* @return PayPlugProduct
|
||||
*/
|
||||
public function setMerchantItemId(string $merchantItemId): PayPlugProduct
|
||||
{
|
||||
$this->merchantItemId = $merchantItemId;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getName()
|
||||
{
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $name
|
||||
* @return PayPlugProduct
|
||||
*/
|
||||
public function setName(string $name): PayPlugProduct
|
||||
{
|
||||
$this->name = $name;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function getPrice()
|
||||
{
|
||||
return $this->price;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $price
|
||||
* @return PayPlugProduct
|
||||
*/
|
||||
public function setPrice(int $price): PayPlugProduct
|
||||
{
|
||||
$this->price = $price;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function getQuantity()
|
||||
{
|
||||
return $this->quantity;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $quantity
|
||||
* @return PayPlugProduct
|
||||
*/
|
||||
public function setQuantity(int $quantity): PayPlugProduct
|
||||
{
|
||||
$this->quantity = $quantity;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function getTotalAmount()
|
||||
{
|
||||
return $this->totalAmount;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $totalAmount
|
||||
* @return PayPlugProduct
|
||||
*/
|
||||
public function setTotalAmount(int $totalAmount): PayPlugProduct
|
||||
{
|
||||
$this->totalAmount = $totalAmount;
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
86
local/modules/PayPlugModule/EventListener/ConfirmationEmailListener.php
Executable file
86
local/modules/PayPlugModule/EventListener/ConfirmationEmailListener.php
Executable file
@@ -0,0 +1,86 @@
|
||||
<?php
|
||||
/*************************************************************************************/
|
||||
/* This file is part of the Thelia package. */
|
||||
/* */
|
||||
/* Copyright (c) OpenStudio */
|
||||
/* email : dev@thelia.net */
|
||||
/* web : http://www.thelia.net */
|
||||
/* */
|
||||
/* For the full copyright and license information, please view the LICENSE.txt */
|
||||
/* file that was distributed with this source code. */
|
||||
/*************************************************************************************/
|
||||
|
||||
namespace PayPlugModule\EventListener;
|
||||
|
||||
use PayPlugModule\PayPlugModule;
|
||||
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
|
||||
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
|
||||
use Thelia\Core\Event\Order\OrderEvent;
|
||||
use Thelia\Core\Event\TheliaEvents;
|
||||
use Thelia\Log\Tlog;
|
||||
use Thelia\Mailer\MailerFactory;
|
||||
|
||||
/**
|
||||
* Class ConfirmationEmailListener
|
||||
* @package PayPlugModule\EventListeners
|
||||
* @author franck allimant <franck@cqfdev.fr>
|
||||
*/
|
||||
class ConfirmationEmailListener implements EventSubscriberInterface
|
||||
{
|
||||
/**
|
||||
* @var MailerFactory
|
||||
*/
|
||||
protected $mailer;
|
||||
|
||||
public function __construct(MailerFactory $mailer)
|
||||
{
|
||||
$this->mailer = $mailer;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param OrderEvent $event
|
||||
*
|
||||
* @throws \Exception if the message cannot be loaded.
|
||||
*/
|
||||
public function sendConfirmationEmail(OrderEvent $event)
|
||||
{
|
||||
if (PayPlugModule::getConfigValue('send_confirmation_message_only_if_paid')) {
|
||||
// We send the order confirmation email only if the order is paid
|
||||
$order = $event->getOrder();
|
||||
|
||||
if (! $order->isPaid() && $order->getPaymentModuleId() == PayPlugModule::getModuleId()) {
|
||||
$event->stopPropagation();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Check if we are the order payment module, and if order new status is paid, send a confirmation email to the customer.
|
||||
*
|
||||
* @param OrderEvent $event
|
||||
* @param $eventName
|
||||
* @param EventDispatcherInterface $dispatcher
|
||||
* @throws \Propel\Runtime\Exception\PropelException
|
||||
*/
|
||||
public function updateStatus(OrderEvent $event, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
$order = $event->getOrder();
|
||||
|
||||
if ($order->isPaid() && $order->getPaymentModuleId() == PayPlugModule::getModuleId()) {
|
||||
// Send confirmation email if required.
|
||||
if (PayPlugModule::getConfigValue('send_confirmation_message_only_if_paid')) {
|
||||
$dispatcher->dispatch(TheliaEvents::ORDER_SEND_CONFIRMATION_EMAIL, $event);
|
||||
}
|
||||
|
||||
Tlog::getInstance()->debug("Confirmation email sent to customer " . $order->getCustomer()->getEmail());
|
||||
}
|
||||
}
|
||||
|
||||
public static function getSubscribedEvents()
|
||||
{
|
||||
return array(
|
||||
TheliaEvents::ORDER_UPDATE_STATUS => array('updateStatus', 128),
|
||||
TheliaEvents::ORDER_SEND_CONFIRMATION_EMAIL => array('sendConfirmationEmail', 129)
|
||||
);
|
||||
}
|
||||
}
|
||||
70
local/modules/PayPlugModule/EventListener/FormExtend/OrderFormListener.php
Executable file
70
local/modules/PayPlugModule/EventListener/FormExtend/OrderFormListener.php
Executable file
@@ -0,0 +1,70 @@
|
||||
<?php
|
||||
|
||||
namespace PayPlugModule\EventListener\FormExtend;
|
||||
|
||||
use PayPlugModule\Model\PayPlugConfigValue;
|
||||
use PayPlugModule\PayPlugModule;
|
||||
use PayPlugModule\Service\PaymentService;
|
||||
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
|
||||
use Symfony\Component\Form\Extension\Core\Type\CheckboxType;
|
||||
use Symfony\Component\HttpFoundation\RequestStack;
|
||||
use Thelia\Core\Event\Order\OrderEvent;
|
||||
use Thelia\Core\Event\TheliaEvents;
|
||||
use Thelia\Core\Event\TheliaFormEvent;
|
||||
use Thelia\Core\HttpFoundation\Request;
|
||||
|
||||
class OrderFormListener implements EventSubscriberInterface
|
||||
{
|
||||
const THELIA_CUSTOMER_ORDER_PAYMENT_FROM_NAME = 'thelia_order_payment';
|
||||
|
||||
const PAY_PLUG_MULTI_PAYMENT_FIELD_NAME = 'pay_plug_multi_payment';
|
||||
|
||||
/** @var Request */
|
||||
protected $request;
|
||||
|
||||
public function __construct(RequestStack $requestStack)
|
||||
{
|
||||
$this->request = $requestStack->getCurrentRequest();
|
||||
}
|
||||
|
||||
public function addMultiPaymentField(TheliaFormEvent $event)
|
||||
{
|
||||
if (!PayPlugModule::getConfigValue(PayPlugConfigValue::MULTI_PAYMENT_ENABLED)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$event->getForm()->getFormBuilder()
|
||||
->add(
|
||||
self::PAY_PLUG_MULTI_PAYMENT_FIELD_NAME,
|
||||
CheckboxType::class
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
public function checkMultiPaymentSelected(OrderEvent $event)
|
||||
{
|
||||
$this->request->getSession()->set(self::PAY_PLUG_MULTI_PAYMENT_FIELD_NAME, 0);
|
||||
$formData = $this->request->get(self::THELIA_CUSTOMER_ORDER_PAYMENT_FROM_NAME);
|
||||
|
||||
if (!isset($formData[self::PAY_PLUG_MULTI_PAYMENT_FIELD_NAME]) || 0 == $formData[self::PAY_PLUG_MULTI_PAYMENT_FIELD_NAME]) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->request->getSession()->set(self::PAY_PLUG_MULTI_PAYMENT_FIELD_NAME, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of event names this subscriber wants to listen to.
|
||||
*
|
||||
* @return array The event names to listen to
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public static function getSubscribedEvents()
|
||||
{
|
||||
return array(
|
||||
TheliaEvents::FORM_AFTER_BUILD.'.'.self::THELIA_CUSTOMER_ORDER_PAYMENT_FROM_NAME => array('addMultiPaymentField', 64),
|
||||
TheliaEvents::ORDER_SET_PAYMENT_MODULE => array('checkMultiPaymentSelected', 64)
|
||||
);
|
||||
}
|
||||
}
|
||||
209
local/modules/PayPlugModule/EventListener/NotificationListener.php
Executable file
209
local/modules/PayPlugModule/EventListener/NotificationListener.php
Executable file
@@ -0,0 +1,209 @@
|
||||
<?php
|
||||
|
||||
namespace PayPlugModule\EventListener;
|
||||
|
||||
use Payplug\Resource\Refund;
|
||||
use Payplug\Resource\Payment;
|
||||
use PayPlugModule\Event\Notification\UnknownNotificationEvent;
|
||||
use PayPlugModule\Event\Notification\PaymentNotificationEvent;
|
||||
use PayPlugModule\Event\Notification\RefundNotificationEvent;
|
||||
use PayPlugModule\Model\OrderPayPlugData;
|
||||
use PayPlugModule\Model\OrderPayPlugDataQuery;
|
||||
use PayPlugModule\Model\OrderPayPlugMultiPayment;
|
||||
use PayPlugModule\Model\OrderPayPlugMultiPaymentQuery;
|
||||
use PayPlugModule\Model\PayPlugCard;
|
||||
use PayPlugModule\Model\PayPlugCardQuery;
|
||||
use PayPlugModule\Model\PayPlugConfigValue;
|
||||
use PayPlugModule\PayPlugModule;
|
||||
use PayPlugModule\Service\OrderStatusService;
|
||||
use Propel\Runtime\Collection\Collection;
|
||||
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
|
||||
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
|
||||
use Thelia\Core\Event\Order\OrderEvent;
|
||||
use Thelia\Core\Event\TheliaEvents;
|
||||
use Thelia\Model\Order;
|
||||
use Thelia\Model\OrderQuery;
|
||||
use Thelia\Model\OrderStatusQuery;
|
||||
|
||||
class NotificationListener implements EventSubscriberInterface
|
||||
{
|
||||
/** @var OrderStatusService */
|
||||
protected $orderStatusService;
|
||||
|
||||
/** @var EventDispatcherInterface */
|
||||
protected $dispatcher;
|
||||
|
||||
public function __construct(EventDispatcherInterface $dispatcher, OrderStatusService $orderStatusService)
|
||||
{
|
||||
$this->dispatcher = $dispatcher;
|
||||
$this->orderStatusService = $orderStatusService;
|
||||
}
|
||||
|
||||
public function handleUnknownNotification(UnknownNotificationEvent $event)
|
||||
{
|
||||
$resource = $event->getResource();
|
||||
switch(true) {
|
||||
case $resource instanceof Payment:
|
||||
$paymentNotificationEvent = new PaymentNotificationEvent($resource);
|
||||
$this->dispatcher->dispatch(PaymentNotificationEvent::PAYMENT_NOTIFICATION_EVENT, $paymentNotificationEvent);
|
||||
break;
|
||||
case $resource instanceof Refund:
|
||||
$refundNotificationEvent = new RefundNotificationEvent($resource);
|
||||
$this->dispatcher->dispatch(RefundNotificationEvent::REFUND_NOTIFICATION_EVENT, $refundNotificationEvent);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public function handlePaymentNotification(PaymentNotificationEvent $event)
|
||||
{
|
||||
$transactionRef = $event->getResource()->id;
|
||||
if (!$transactionRef) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$order = OrderQuery::create()
|
||||
->filterByPaymentModuleId(PayPlugModule::getModuleId())
|
||||
->filterByTransactionRef($transactionRef)
|
||||
->findOne();
|
||||
|
||||
if (null === $order) {
|
||||
return;
|
||||
}
|
||||
|
||||
$orderPayPlugData = OrderPayPlugDataQuery::create()
|
||||
->findOneById($order->getId());
|
||||
|
||||
if (null === $orderPayPlugData) {
|
||||
return;
|
||||
}
|
||||
|
||||
$paymentResource = $event->getResource();
|
||||
|
||||
$orderStatusId = OrderStatusQuery::getCancelledStatus()->getId();
|
||||
|
||||
$orderPayPlugMultiPayment = OrderPayPlugMultiPaymentQuery::create()
|
||||
->findByOrderId($order->getId());
|
||||
|
||||
// Multi payment is really different
|
||||
if ($orderPayPlugMultiPayment->count() > 0) {
|
||||
$this->handleMultiPaymentNotification($paymentResource, $order, $orderPayPlugData, $orderPayPlugMultiPayment);
|
||||
return;
|
||||
}
|
||||
|
||||
if ($orderPayPlugData->getNeedCapture()) {
|
||||
// Handle differed payment
|
||||
if ($paymentResource->is_paid) {
|
||||
$orderPayPlugData->setCapturedAt((new \DateTime()))
|
||||
->save();
|
||||
// Don't update status on capture
|
||||
$orderStatusId = null;
|
||||
} elseif ($paymentResource->authorization->authorized_at) {
|
||||
$orderStatusId = PayPlugModule::getConfigValue(PayPlugConfigValue::DIFFERED_PAYMENT_AUTHORIZED_CAPTURE_STATUS);
|
||||
$orderPayPlugData->setCaptureExpireAt($paymentResource->authorization->expires_at)
|
||||
->save();
|
||||
}
|
||||
} elseif ($paymentResource->is_paid) {
|
||||
// Handle classic payment
|
||||
$orderStatusId = OrderStatusQuery::getPaidStatus()->getId();
|
||||
}
|
||||
|
||||
if (null !== $orderStatusId) {
|
||||
$event = (new OrderEvent($order))
|
||||
->setStatus($orderStatusId);
|
||||
$this->dispatcher->dispatch(TheliaEvents::ORDER_UPDATE_STATUS, $event);
|
||||
}
|
||||
|
||||
if (null !== $paymentResource->card->id) {
|
||||
$cardData = $paymentResource->card;
|
||||
$cardExist = PayPlugCardQuery::create()
|
||||
->filterByCustomerId($order->getCustomerId())
|
||||
->filterByUuid($cardData->id)
|
||||
->findOne();
|
||||
|
||||
if (null === $cardExist) {
|
||||
(new PayPlugCard())
|
||||
->setUuid($cardData->id)
|
||||
->setCustomerId($order->getCustomerId())
|
||||
->setBrand($cardData->brand)
|
||||
->setLast4($cardData->last4)
|
||||
->setExpireMonth($cardData->exp_month)
|
||||
->setExpireYear($cardData->exp_year)
|
||||
->save();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected function handleMultiPaymentNotification($paymentResource, Order $order, OrderPayPlugData $orderPayPlugData, Collection $orderMultiPayments)
|
||||
{
|
||||
/** @var OrderPayPlugMultiPayment $orderMultiPayment */
|
||||
foreach ($orderMultiPayments as $orderMultiPayment) {
|
||||
$orderMultiPayment->setPaymentMethod($paymentResource->card->id);
|
||||
|
||||
if ($paymentResource->id === $orderMultiPayment->getPaymentId()) {
|
||||
$orderStatusId = OrderStatusQuery::getCancelledStatus()->getId();
|
||||
|
||||
if ($paymentResource->is_paid) {
|
||||
$orderMultiPayment->setPaidAt(new \DateTime());
|
||||
$orderStatusId = OrderStatusQuery::getPaidStatus()->getId();
|
||||
}
|
||||
|
||||
// Update order status only for first payment
|
||||
if ($orderMultiPayment->getIsFirstPayment()) {
|
||||
$event = (new OrderEvent($order))
|
||||
->setStatus($orderStatusId);
|
||||
$this->dispatcher->dispatch(TheliaEvents::ORDER_UPDATE_STATUS, $event);
|
||||
}
|
||||
}
|
||||
|
||||
$orderMultiPayment->save();
|
||||
}
|
||||
}
|
||||
|
||||
public function handleRefundNotification(RefundNotificationEvent $event)
|
||||
{
|
||||
$transactionRef = $event->getResource()->payment_id;
|
||||
if (!$transactionRef) {
|
||||
return;
|
||||
}
|
||||
|
||||
$order = OrderQuery::create()
|
||||
->filterByPaymentModuleId(PayPlugModule::getModuleId())
|
||||
->filterByTransactionRef($transactionRef)
|
||||
->findOne();
|
||||
|
||||
$multiPayment = OrderPayPlugMultiPaymentQuery::create()
|
||||
->findOneByPaymentId($transactionRef);
|
||||
|
||||
if (null !== $multiPayment) {
|
||||
$multiPayment->setAmountRefunded((int)$multiPayment->getAmountRefunded() + $event->getResource()->amount)
|
||||
->save();
|
||||
$order = $multiPayment->getOrder();
|
||||
}
|
||||
|
||||
if (null === $order) {
|
||||
return;
|
||||
}
|
||||
|
||||
$orderPayPlugData = OrderPayPlugDataQuery::create()
|
||||
->findOneById($order->getId());
|
||||
|
||||
$orderPayPlugData->setAmountRefunded((int)$orderPayPlugData->getAmountRefunded() + $event->getResource()->amount)
|
||||
->save();
|
||||
|
||||
$event = (new OrderEvent($order))
|
||||
->setStatus(OrderStatusQuery::getRefundedStatus()->getId());
|
||||
$this->dispatcher->dispatch(TheliaEvents::ORDER_UPDATE_STATUS, $event);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public static function getSubscribedEvents()
|
||||
{
|
||||
return [
|
||||
UnknownNotificationEvent::UNKNOWN_NOTIFICATION_EVENT => ['handleUnknownNotification', 128],
|
||||
PaymentNotificationEvent::PAYMENT_NOTIFICATION_EVENT => ['handlePaymentNotification', 128],
|
||||
RefundNotificationEvent::REFUND_NOTIFICATION_EVENT => ['handleRefundNotification', 128]
|
||||
];
|
||||
}
|
||||
}
|
||||
59
local/modules/PayPlugModule/EventListener/OrderListener.php
Executable file
59
local/modules/PayPlugModule/EventListener/OrderListener.php
Executable file
@@ -0,0 +1,59 @@
|
||||
<?php
|
||||
|
||||
namespace PayPlugModule\EventListener;
|
||||
|
||||
use PayPlugModule\Model\OrderPayPlugData;
|
||||
use PayPlugModule\Model\OrderPayPlugDataQuery;
|
||||
use PayPlugModule\Model\PayPlugConfigValue;
|
||||
use PayPlugModule\PayPlugModule;
|
||||
use PayPlugModule\Service\PaymentService;
|
||||
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
|
||||
use Thelia\Core\Event\Order\OrderEvent;
|
||||
use Thelia\Core\Event\TheliaEvents;
|
||||
|
||||
class OrderListener implements EventSubscriberInterface
|
||||
{
|
||||
/** @var PaymentService */
|
||||
protected $paymentService;
|
||||
|
||||
public function __construct(PaymentService $paymentService)
|
||||
{
|
||||
$this->paymentService = $paymentService;
|
||||
}
|
||||
|
||||
public function onOrderUpdateStatus(OrderEvent $event)
|
||||
{
|
||||
$order = $event->getOrder();
|
||||
|
||||
$orderPayPlugData = OrderPayPlugDataQuery::create()
|
||||
->findOneById($order->getId());
|
||||
|
||||
if (null === $orderPayPlugData || false == $orderPayPlugData->getNeedCapture()) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->handleCapture($event, $orderPayPlugData);
|
||||
}
|
||||
|
||||
protected function handleCapture(OrderEvent $event, OrderPayPlugData $orderPayPlugData)
|
||||
{
|
||||
// If already captured do nothing
|
||||
if (null !== $orderPayPlugData->getCapturedAt()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// If new status is not trigger status do nothing
|
||||
if (PayPlugModule::getConfigValue(PayPlugConfigValue::DIFFERED_PAYMENT_TRIGGER_CAPTURE_STATUS) != $event->getStatus()) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->paymentService->doOrderCapture($event->getOrder());
|
||||
}
|
||||
|
||||
public static function getSubscribedEvents()
|
||||
{
|
||||
return [
|
||||
TheliaEvents::ORDER_UPDATE_STATUS => ['onOrderUpdateStatus', 64]
|
||||
];
|
||||
}
|
||||
}
|
||||
208
local/modules/PayPlugModule/EventListener/PaymentListener.php
Executable file
208
local/modules/PayPlugModule/EventListener/PaymentListener.php
Executable file
@@ -0,0 +1,208 @@
|
||||
<?php
|
||||
|
||||
namespace PayPlugModule\EventListener;
|
||||
|
||||
use Payplug\Exception\PayplugException;
|
||||
use Payplug\Payment;
|
||||
use PayPlugModule\Event\PayPlugPaymentEvent;
|
||||
use PayPlugModule\Model\OrderPayPlugData;
|
||||
use PayPlugModule\Model\OrderPayPlugMultiPaymentQuery;
|
||||
use PayPlugModule\Service\OrderStatusService;
|
||||
use PayPlugModule\Service\PaymentService;
|
||||
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
|
||||
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
|
||||
use Thelia\Core\Event\Order\OrderEvent;
|
||||
use Thelia\Core\Event\TheliaEvents;
|
||||
|
||||
class PaymentListener extends PaymentService implements EventSubscriberInterface
|
||||
{
|
||||
/** @var OrderStatusService */
|
||||
protected $orderStatusService;
|
||||
|
||||
public function __construct(EventDispatcherInterface $dispatcher, OrderStatusService $orderStatusService)
|
||||
{
|
||||
parent::__construct($dispatcher);
|
||||
$this->orderStatusService = $orderStatusService;
|
||||
}
|
||||
|
||||
/**
|
||||
* Send refund to PayPlug, set payment url and id to event
|
||||
*
|
||||
* @param PayPlugPaymentEvent $paymentEvent
|
||||
* @throws \Payplug\Exception\ConfigurationNotSetException
|
||||
*/
|
||||
public function createPayment(PayPlugPaymentEvent $paymentEvent)
|
||||
{
|
||||
try {
|
||||
$parameters = $paymentEvent->getFormattedPaymentParameters();
|
||||
$payPlugPayment = Payment::create($parameters);
|
||||
|
||||
$paymentEvent->setPaymentId($payPlugPayment->id)
|
||||
->setIsPaid($payPlugPayment->is_paid)
|
||||
->setPaymentUrl($payPlugPayment->hosted_payment->payment_url);
|
||||
|
||||
} catch (PayplugException $exception) {
|
||||
throw new \Exception($this->formatErrorMessage($exception), 0, $exception);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Send refund to PayPlug
|
||||
*
|
||||
* @param PayPlugPaymentEvent $paymentEvent
|
||||
* @throws \Payplug\Exception\ConfigurationNotSetException
|
||||
* @throws \Payplug\Exception\InvalidPaymentException
|
||||
*/
|
||||
public function createRefund(PayPlugPaymentEvent $paymentEvent)
|
||||
{
|
||||
try {
|
||||
$payPlugPayment = Payment::retrieve($paymentEvent->getPaymentId());
|
||||
$data = null;
|
||||
if ($paymentEvent->getAmount()) {
|
||||
$data = ['amount' => $paymentEvent->getAmount()];
|
||||
}
|
||||
$payPlugPayment->refund($data);
|
||||
} catch (PayplugException $exception) {
|
||||
throw new \Exception($this->formatErrorMessage($exception), 0, $exception);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Send capture to PayPlug
|
||||
*
|
||||
* @param PayPlugPaymentEvent $paymentEvent
|
||||
* @throws \Payplug\Exception\ConfigurationNotSetException
|
||||
*/
|
||||
public function createCapture(PayPlugPaymentEvent $paymentEvent)
|
||||
{
|
||||
try {
|
||||
$payPlugPayment = Payment::retrieve($paymentEvent->getPaymentId());
|
||||
|
||||
$paymentCapture = $payPlugPayment->capture();
|
||||
} catch (PayplugException $exception) {
|
||||
throw new \Exception($this->formatErrorMessage($exception), 0, $exception);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Dispatch create payment for an order and set payment id to order transaction ref
|
||||
*
|
||||
* @param PayPlugPaymentEvent $paymentEvent
|
||||
*/
|
||||
public function orderPayment(PayPlugPaymentEvent $paymentEvent)
|
||||
{
|
||||
$this->dispatcher->dispatch(PayPlugPaymentEvent::CREATE_PAYMENT_EVENT, $paymentEvent);
|
||||
|
||||
$order = $paymentEvent->getOrder();
|
||||
|
||||
$orderPayPlugData = (new OrderPayPlugData())
|
||||
->setId($order->getId());
|
||||
|
||||
if ($paymentEvent->isCapture()) {
|
||||
$orderPayPlugData->setNeedCapture(1);
|
||||
}
|
||||
|
||||
$orderPayPlugData->save();
|
||||
|
||||
$orderEvent = new OrderEvent($paymentEvent->getOrder());
|
||||
$orderEvent->setTransactionRef($paymentEvent->getPaymentId());
|
||||
$this->dispatcher->dispatch(TheliaEvents::ORDER_UPDATE_TRANSACTION_REF, $orderEvent);
|
||||
}
|
||||
|
||||
/**
|
||||
* Dispatch refund for an order
|
||||
*
|
||||
* @param PayPlugPaymentEvent $paymentEvent
|
||||
* @throws \Payplug\Exception\ConfigurationNotSetException
|
||||
* @throws \Payplug\Exception\InvalidPaymentException
|
||||
*/
|
||||
public function orderRefund(PayPlugPaymentEvent $paymentEvent)
|
||||
{
|
||||
$multiPayments = OrderPayPlugMultiPaymentQuery::create()
|
||||
->findByOrderId($paymentEvent->getOrder()->getId());
|
||||
|
||||
if (count($multiPayments) > 0) {
|
||||
$amountToRefund = $paymentEvent->getAmount();
|
||||
foreach ($multiPayments as $multiPayment) {
|
||||
if ($amountToRefund <= 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// If already refunded => do nothing
|
||||
if ($multiPayment->getAmountRefunded() >= $multiPayment->getAmount()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// If not paid => cancel it
|
||||
if ($multiPayment->getPaidAt() === null) {
|
||||
$multiPayment->setPlannedAt(null)
|
||||
->save();
|
||||
continue;
|
||||
}
|
||||
|
||||
$currentPaymentAmountToRefund = $multiPayment->getAmount()-$multiPayment->getAmountRefunded();
|
||||
$currentPaymentAmountToRefund = $currentPaymentAmountToRefund > $amountToRefund ? $amountToRefund : $currentPaymentAmountToRefund;
|
||||
// Else refund it
|
||||
$refundPaymentEvent = clone $paymentEvent;
|
||||
$refundPaymentEvent->setPaymentId($multiPayment->getPaymentId())
|
||||
->setAmount($currentPaymentAmountToRefund);
|
||||
$this->dispatcher->dispatch(PayPlugPaymentEvent::CREATE_REFUND_EVENT, $refundPaymentEvent);
|
||||
$amountToRefund = $amountToRefund - $currentPaymentAmountToRefund;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
$this->dispatcher->dispatch(PayPlugPaymentEvent::CREATE_REFUND_EVENT, $paymentEvent);
|
||||
}
|
||||
|
||||
/**
|
||||
* Dispatch capture for an order
|
||||
*
|
||||
* @param PayPlugPaymentEvent $paymentEvent
|
||||
* @throws \Payplug\Exception\ConfigurationNotSetException
|
||||
* @throws \Payplug\Exception\InvalidPaymentException
|
||||
*/
|
||||
public function orderCapture(PayPlugPaymentEvent $paymentEvent)
|
||||
{
|
||||
$this->dispatcher->dispatch(PayPlugPaymentEvent::CREATE_CAPTURE_EVENT, $paymentEvent);
|
||||
}
|
||||
|
||||
protected function formatErrorMessage(PayplugException $exception)
|
||||
{
|
||||
$response = json_decode($exception->getHttpResponse(), true);
|
||||
|
||||
$details = "";
|
||||
|
||||
|
||||
if (isset($response['details'])) {
|
||||
$details = implode(' -', array_map(
|
||||
function ($v, $k) {
|
||||
$errors = [];
|
||||
foreach ($v as $field => $error) {
|
||||
$errors[] = "$field : $error";
|
||||
}
|
||||
return " [$k] ".implode(";", $errors)." .";
|
||||
},
|
||||
$response['details'],
|
||||
array_keys($response['details'])
|
||||
));
|
||||
}
|
||||
|
||||
return $response['message'] . $details;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public static function getSubscribedEvents()
|
||||
{
|
||||
return [
|
||||
PayPlugPaymentEvent::CREATE_PAYMENT_EVENT => ['createPayment', 128],
|
||||
PayPlugPaymentEvent::CREATE_REFUND_EVENT => ['createRefund', 128],
|
||||
PayPlugPaymentEvent::CREATE_CAPTURE_EVENT => ['createCapture', 128],
|
||||
PayPlugPaymentEvent::ORDER_PAYMENT_EVENT => ['orderPayment', 128],
|
||||
PayPlugPaymentEvent::ORDER_REFUND_EVENT => ['orderRefund', 128],
|
||||
PayPlugPaymentEvent::ORDER_CAPTURE_EVENT => ['orderCapture', 128]
|
||||
];
|
||||
}
|
||||
}
|
||||
255
local/modules/PayPlugModule/Form/ConfigurationForm.php
Executable file
255
local/modules/PayPlugModule/Form/ConfigurationForm.php
Executable file
@@ -0,0 +1,255 @@
|
||||
<?php
|
||||
|
||||
namespace PayPlugModule\Form;
|
||||
|
||||
use PayPlugModule\Model\PayPlugConfigValue;
|
||||
use PayPlugModule\PayPlugModule;
|
||||
use PayPlugModule\Service\OrderStatusService;
|
||||
use PayPlugModule\Model\PayPlugModuleDeliveryTypeQuery;
|
||||
use Symfony\Component\Form\Extension\Core\Type\CheckboxType;
|
||||
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
|
||||
use Symfony\Component\Form\Extension\Core\Type\TextType;
|
||||
use Thelia\Core\Translation\Translator;
|
||||
use Thelia\Form\BaseForm;
|
||||
use Thelia\Model\Base\ModuleQuery;
|
||||
use Thelia\Model\Module;
|
||||
use Thelia\Model\OrderStatusQuery;
|
||||
use Thelia\Module\BaseModule;
|
||||
|
||||
class ConfigurationForm extends BaseForm
|
||||
{
|
||||
const DELIVERY_MODULE_TYPE_KEY_PREFIX = "module_delivery_type";
|
||||
|
||||
protected function buildForm()
|
||||
{
|
||||
$orderStatuses = OrderStatusQuery::create()
|
||||
->find();
|
||||
|
||||
$orderStatusChoices = [];
|
||||
foreach ($orderStatuses as $orderStatus) {
|
||||
$orderStatusChoices[$orderStatus->getId()] = $orderStatus->getTitle();
|
||||
}
|
||||
|
||||
/** @var OrderStatusService $orderStatusesService */
|
||||
$orderStatusesService = $this->container->get('payplugmodule_order_status_service');
|
||||
|
||||
$this->formBuilder
|
||||
->add(
|
||||
PayPlugConfigValue::OFFER,
|
||||
ChoiceType::class,
|
||||
[
|
||||
'choices' => [
|
||||
'starter' => 'Starter',
|
||||
'pro' => 'Pro',
|
||||
'premium' => 'Premium',
|
||||
],
|
||||
"data" => PayPlugModule::getConfigValue(PayPlugConfigValue::OFFER),
|
||||
"label"=> Translator::getInstance()->trans("Select your PayPlug offer", [], PayPlugModule::DOMAIN_NAME),
|
||||
"required" => true
|
||||
]
|
||||
)
|
||||
->add(
|
||||
PayPlugConfigValue::PAYMENT_ENABLED,
|
||||
CheckboxType::class,
|
||||
[
|
||||
"data" => !!PayPlugModule::getConfigValue(PayPlugConfigValue::PAYMENT_ENABLED, false),
|
||||
"label"=> Translator::getInstance()->trans("Enable payment by PayPlug", [], PayPlugModule::DOMAIN_NAME),
|
||||
"required" => false
|
||||
]
|
||||
)
|
||||
->add(
|
||||
PayPlugConfigValue::API_MODE,
|
||||
ChoiceType::class,
|
||||
[
|
||||
'choices' => [
|
||||
'live' => 'Live',
|
||||
'test' => 'Test',
|
||||
],
|
||||
"data" => PayPlugModule::getConfigValue(PayPlugConfigValue::API_MODE),
|
||||
"label"=> Translator::getInstance()->trans("Choose API mode", [], PayPlugModule::DOMAIN_NAME),
|
||||
"required" => true
|
||||
]
|
||||
)
|
||||
->add(
|
||||
PayPlugConfigValue::LIVE_API_KEY,
|
||||
TextType::class,
|
||||
[
|
||||
"data" => PayPlugModule::getConfigValue(PayPlugConfigValue::LIVE_API_KEY),
|
||||
"label"=> Translator::getInstance()->trans("Live API secret key", [], PayPlugModule::DOMAIN_NAME),
|
||||
"label_attr" => ['help' => Translator::getInstance()->trans("Look here %link", ['%link' => "<a target='_blank' href='https://portal.payplug.com/#/configuration/api'>Api configuration</a>"], PayPlugModule::DOMAIN_NAME)],
|
||||
"required" => true
|
||||
]
|
||||
)
|
||||
->add(
|
||||
PayPlugConfigValue::TEST_API_KEY,
|
||||
TextType::class,
|
||||
[
|
||||
"data" => PayPlugModule::getConfigValue(PayPlugConfigValue::TEST_API_KEY),
|
||||
"label"=> Translator::getInstance()->trans("Test API secret key", [], PayPlugModule::DOMAIN_NAME),
|
||||
"label_attr" => ['help' => Translator::getInstance()->trans("Look here %link", ['%link' => "<a target='_blank' href='https://portal.payplug.com/#/configuration/api'>Api configuration</a>"], PayPlugModule::DOMAIN_NAME)],
|
||||
"required" => true
|
||||
]
|
||||
)
|
||||
->add(
|
||||
PayPlugConfigValue::PAYMENT_PAGE_TYPE,
|
||||
ChoiceType::class,
|
||||
[
|
||||
'choices' => [
|
||||
'hosted_page' => Translator::getInstance()->trans("Hosted page", [], PayPlugModule::DOMAIN_NAME),
|
||||
'lightbox' => Translator::getInstance()->trans("Lightbox", [], PayPlugModule::DOMAIN_NAME),
|
||||
// Todo implement payplug JS
|
||||
//'payplug_js' => Translator::getInstance()->trans("Payplug.js", [], PayPlugModule::DOMAIN_NAME)
|
||||
],
|
||||
"data" => PayPlugModule::getConfigValue(PayPlugConfigValue::PAYMENT_PAGE_TYPE),
|
||||
"label"=> Translator::getInstance()->trans("Payment page type", [], PayPlugModule::DOMAIN_NAME),
|
||||
"label_attr" => ['help' => Translator::getInstance()->trans("Hosted page will redirect your customer to a payment page / Lightbox will open a payment pop up in your website.", [], PayPlugModule::DOMAIN_NAME)],
|
||||
"required" => true
|
||||
]
|
||||
)
|
||||
->add(
|
||||
PayPlugConfigValue::ONE_CLICK_PAYMENT_ENABLED,
|
||||
CheckboxType::class,
|
||||
[
|
||||
"data" => !!PayPlugModule::getConfigValue(PayPlugConfigValue::ONE_CLICK_PAYMENT_ENABLED),
|
||||
"label"=> Translator::getInstance()->trans("Enable one click payment", [], PayPlugModule::DOMAIN_NAME),
|
||||
"label_attr" => ['help' => Translator::getInstance()->trans("This will allow your customer to save their card fo future order.", [], PayPlugModule::DOMAIN_NAME)],
|
||||
"required" => false
|
||||
]
|
||||
)
|
||||
->add(
|
||||
PayPlugConfigValue::MULTI_PAYMENT_ENABLED,
|
||||
CheckboxType::class,
|
||||
[
|
||||
"data" => !!PayPlugModule::getConfigValue(PayPlugConfigValue::MULTI_PAYMENT_ENABLED),
|
||||
"label"=> Translator::getInstance()->trans("Enabled multi-payment", [], PayPlugModule::DOMAIN_NAME),
|
||||
"label_attr" => ['help' => Translator::getInstance()->trans("Enable payment in 2,3 or 4 times", [], PayPlugModule::DOMAIN_NAME)],
|
||||
"required" => false
|
||||
]
|
||||
)
|
||||
->add(
|
||||
PayPlugConfigValue::MULTI_PAYMENT_TIMES,
|
||||
ChoiceType::class,
|
||||
[
|
||||
'choices' => [
|
||||
'2' => Translator::getInstance()->trans("2 times", [], PayPlugModule::DOMAIN_NAME),
|
||||
'3' => Translator::getInstance()->trans("3 times", [], PayPlugModule::DOMAIN_NAME),
|
||||
'4' => Translator::getInstance()->trans("4 times", [], PayPlugModule::DOMAIN_NAME)
|
||||
],
|
||||
"data" => PayPlugModule::getConfigValue(PayPlugConfigValue::MULTI_PAYMENT_TIMES),
|
||||
"label"=> Translator::getInstance()->trans("Payment in ", [], PayPlugModule::DOMAIN_NAME),
|
||||
"required" => false
|
||||
]
|
||||
)
|
||||
->add(
|
||||
PayPlugConfigValue::MULTI_PAYMENT_MINIMUM,
|
||||
TextType::class,
|
||||
[
|
||||
"data" => PayPlugModule::getConfigValue(PayPlugConfigValue::MULTI_PAYMENT_MINIMUM),
|
||||
"label"=> Translator::getInstance()->trans("Minimum amount ", [], PayPlugModule::DOMAIN_NAME),
|
||||
"required" => false
|
||||
]
|
||||
)
|
||||
->add(
|
||||
PayPlugConfigValue::MULTI_PAYMENT_MAXIMUM,
|
||||
TextType::class,
|
||||
[
|
||||
"data" => PayPlugModule::getConfigValue(PayPlugConfigValue::MULTI_PAYMENT_MAXIMUM),
|
||||
"label"=> Translator::getInstance()->trans("Maximum amount ", [], PayPlugModule::DOMAIN_NAME),
|
||||
"required" => false
|
||||
]
|
||||
)
|
||||
->add(
|
||||
PayPlugConfigValue::DIFFERED_PAYMENT_ENABLED,
|
||||
CheckboxType::class,
|
||||
[
|
||||
"data" => !!PayPlugModule::getConfigValue(PayPlugConfigValue::DIFFERED_PAYMENT_ENABLED),
|
||||
"label"=> Translator::getInstance()->trans("Enabled differed payment", [], PayPlugModule::DOMAIN_NAME),
|
||||
"label_attr" => ['help' => Translator::getInstance()->trans("Trigger the payment on order status change (max : 7 days after)", [], PayPlugModule::DOMAIN_NAME)],
|
||||
"required" => false
|
||||
]
|
||||
)
|
||||
->add(
|
||||
PayPlugConfigValue::DIFFERED_PAYMENT_AUTHORIZED_CAPTURE_STATUS,
|
||||
ChoiceType::class,
|
||||
[
|
||||
'choices' => $orderStatusChoices,
|
||||
"data" => PayPlugModule::getConfigValue(PayPlugConfigValue::DIFFERED_PAYMENT_AUTHORIZED_CAPTURE_STATUS, $orderStatusesService->findOrCreateAuthorizedCaptureOrderStatus()->getId()),
|
||||
"label"=> Translator::getInstance()->trans("Which status to set when a capture is authorized", [], PayPlugModule::DOMAIN_NAME),
|
||||
"required" => false
|
||||
]
|
||||
)
|
||||
->add(
|
||||
PayPlugConfigValue::DIFFERED_PAYMENT_TRIGGER_CAPTURE_STATUS,
|
||||
ChoiceType::class,
|
||||
[
|
||||
'choices' => $orderStatusChoices,
|
||||
"data" => PayPlugModule::getConfigValue(PayPlugConfigValue::DIFFERED_PAYMENT_TRIGGER_CAPTURE_STATUS),
|
||||
"label"=> Translator::getInstance()->trans("Capture the payment after order get the status", [], PayPlugModule::DOMAIN_NAME),
|
||||
"required" => false
|
||||
]
|
||||
)
|
||||
->add(
|
||||
PayPlugConfigValue::DIFFERED_PAYMENT_CAPTURE_EXPIRED_STATUS,
|
||||
ChoiceType::class,
|
||||
[
|
||||
'choices' => $orderStatusChoices,
|
||||
"data" => PayPlugModule::getConfigValue(PayPlugConfigValue::DIFFERED_PAYMENT_CAPTURE_EXPIRED_STATUS, $orderStatusesService->findOrCreateExpiredCaptureOrderStatus()->getId()),
|
||||
"label"=> Translator::getInstance()->trans("What status to set on expired capture ", [], PayPlugModule::DOMAIN_NAME),
|
||||
"required" => false
|
||||
]
|
||||
)
|
||||
->add(
|
||||
PayPlugConfigValue::SEND_CONFIRMATION_MESSAGE_ONLY_IF_PAID,
|
||||
CheckboxType::class,
|
||||
[
|
||||
"data" => !!PayPlugModule::getConfigValue(PayPlugConfigValue::SEND_CONFIRMATION_MESSAGE_ONLY_IF_PAID),
|
||||
"label"=> Translator::getInstance()->trans("Send order confirmation on payment success", [], PayPlugModule::DOMAIN_NAME),
|
||||
"label_attr" => ['help' => Translator::getInstance()->trans("If checked, the order confirmation message is sent to the customer only when the payment is successful. The order notification is always sent to the shop administrator", [], PayPlugModule::DOMAIN_NAME)],
|
||||
"required" => false
|
||||
]
|
||||
)
|
||||
;
|
||||
|
||||
foreach (self::getDeliveryModuleFormFields() as $deliveryModuleFormField)
|
||||
{
|
||||
$this->formBuilder
|
||||
->add(
|
||||
$deliveryModuleFormField['name'],
|
||||
ChoiceType::class,
|
||||
[
|
||||
'required' => false,
|
||||
'label' => $deliveryModuleFormField['moduleCode'],
|
||||
'choices' => [
|
||||
'carrier' => Translator::getInstance()->trans('Carrier ', [], PayPlugModule::DOMAIN_NAME),
|
||||
'storepickup' => Translator::getInstance()->trans('Store pick up ', [], PayPlugModule::DOMAIN_NAME),
|
||||
'networkpickup' => Translator::getInstance()->trans('Network pick up ', [], PayPlugModule::DOMAIN_NAME),
|
||||
'travelpickup' => Translator::getInstance()->trans('Travel pick up ', [], PayPlugModule::DOMAIN_NAME),
|
||||
'edelivery' => Translator::getInstance()->trans('E-Delivery ', [], PayPlugModule::DOMAIN_NAME)
|
||||
],
|
||||
'data' => $deliveryModuleFormField['value']
|
||||
]
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
public static function getDeliveryModuleFormFields()
|
||||
{
|
||||
$deliveryModules = ModuleQuery::create()
|
||||
->filterByType(BaseModule::DELIVERY_MODULE_TYPE)
|
||||
->find();
|
||||
|
||||
return array_map(function (Module $deliveryModule) {
|
||||
$oneyModuleDeliveryType = PayPlugModuleDeliveryTypeQuery::create()->filterByModuleId($deliveryModule->getId())->findOne();
|
||||
return [
|
||||
'name' => self::DELIVERY_MODULE_TYPE_KEY_PREFIX.':'.$deliveryModule->getId(),
|
||||
'moduleCode' => $deliveryModule->getCode(),
|
||||
'value' => $oneyModuleDeliveryType !== null ? $oneyModuleDeliveryType->getDeliveryType() : null
|
||||
];
|
||||
}, iterator_to_array($deliveryModules));
|
||||
}
|
||||
|
||||
public function getName()
|
||||
{
|
||||
return "payplugmodule_configuration_form";
|
||||
}
|
||||
}
|
||||
23
local/modules/PayPlugModule/Form/OrderActionForm.php
Executable file
23
local/modules/PayPlugModule/Form/OrderActionForm.php
Executable file
@@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
namespace PayPlugModule\Form;
|
||||
|
||||
use Symfony\Component\Form\Extension\Core\Type\TextType;
|
||||
use Thelia\Form\BaseForm;
|
||||
|
||||
class OrderActionForm extends BaseForm
|
||||
{
|
||||
protected function buildForm()
|
||||
{
|
||||
$this->formBuilder
|
||||
->add(
|
||||
'order_id',
|
||||
TextType::class
|
||||
);
|
||||
}
|
||||
|
||||
public function getName()
|
||||
{
|
||||
return "payplugmodule_order_action_form";
|
||||
}
|
||||
}
|
||||
24
local/modules/PayPlugModule/Form/OrderRefundForm.php
Normal file
24
local/modules/PayPlugModule/Form/OrderRefundForm.php
Normal file
@@ -0,0 +1,24 @@
|
||||
<?php
|
||||
|
||||
namespace PayPlugModule\Form;
|
||||
|
||||
use Symfony\Component\Form\Extension\Core\Type\TextType;
|
||||
|
||||
class OrderRefundForm extends OrderActionForm
|
||||
{
|
||||
protected function buildForm()
|
||||
{
|
||||
parent::buildForm();
|
||||
|
||||
$this->formBuilder
|
||||
->add(
|
||||
'refund_amount',
|
||||
TextType::class
|
||||
);
|
||||
}
|
||||
|
||||
public function getName()
|
||||
{
|
||||
return parent::getName().'_refund';
|
||||
}
|
||||
}
|
||||
65
local/modules/PayPlugModule/Hook/BackHookManager.php
Executable file
65
local/modules/PayPlugModule/Hook/BackHookManager.php
Executable file
@@ -0,0 +1,65 @@
|
||||
<?php
|
||||
|
||||
|
||||
namespace PayPlugModule\Hook;
|
||||
|
||||
|
||||
use PayPlugModule\Model\OrderPayPlugData;
|
||||
use PayPlugModule\Model\OrderPayPlugDataQuery;
|
||||
use PayPlugModule\Model\OrderPayPlugMultiPaymentQuery;
|
||||
use PayPlugModule\PayPlugModule;
|
||||
use Propel\Runtime\Map\TableMap;
|
||||
use Thelia\Core\Event\Hook\HookRenderEvent;
|
||||
use Thelia\Core\Hook\BaseHook;
|
||||
use Thelia\Model\OrderQuery;
|
||||
use Thelia\Model\OrderStatus;
|
||||
|
||||
class BackHookManager extends BaseHook
|
||||
{
|
||||
/**
|
||||
* @param HookRenderEvent $event
|
||||
* @throws \Propel\Runtime\Exception\PropelException
|
||||
*/
|
||||
public function onOrderEditPaymentModuleBottom(HookRenderEvent $event)
|
||||
{
|
||||
$order = OrderQuery::create()
|
||||
->filterByPaymentModuleId(PayPlugModule::getModuleId())
|
||||
->filterById($event->getArgument('order_id'))
|
||||
->findOne();
|
||||
|
||||
if (null === $order) {
|
||||
return;
|
||||
}
|
||||
|
||||
/** @var OrderPayPlugData $orderPayPlugData */
|
||||
$orderPayPlugData = OrderPayPlugDataQuery::create()
|
||||
->findOneById($order->getId());
|
||||
|
||||
if (null === $orderPayPlugData) {
|
||||
return;
|
||||
}
|
||||
|
||||
$orderPayPlugMultiPayments = OrderPayPlugMultiPaymentQuery::create()
|
||||
->filterByOrderId($order->getId())
|
||||
->find()
|
||||
->toArray(null, false,TableMap::TYPE_CAMELNAME);
|
||||
|
||||
$isPaid = !in_array($order->getOrderStatus()->getCode(), [OrderStatus::CODE_NOT_PAID, OrderStatus::CODE_CANCELED]);
|
||||
$event->add(
|
||||
$this->render(
|
||||
'PayPlugModule/order_pay_plug.html',
|
||||
array_merge(
|
||||
$event->getArguments(),
|
||||
[
|
||||
'isPaid' => $isPaid,
|
||||
'currency' => $order->getCurrency()->getSymbol()
|
||||
],
|
||||
$orderPayPlugData->toArray(TableMap::TYPE_CAMELNAME),
|
||||
[
|
||||
'multiPayments' => $orderPayPlugMultiPayments
|
||||
]
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
95
local/modules/PayPlugModule/Hook/FrontHookManager.php
Executable file
95
local/modules/PayPlugModule/Hook/FrontHookManager.php
Executable file
@@ -0,0 +1,95 @@
|
||||
<?php
|
||||
|
||||
namespace PayPlugModule\Hook;
|
||||
|
||||
use PayPlugModule\Model\PayPlugCardQuery;
|
||||
use PayPlugModule\Model\PayPlugConfigValue;
|
||||
use PayPlugModule\PayPlugModule;
|
||||
use Thelia\Core\Event\Hook\HookRenderEvent;
|
||||
use Thelia\Core\Hook\BaseHook;
|
||||
use Thelia\Model\Country;
|
||||
use Thelia\TaxEngine\TaxEngine;
|
||||
|
||||
class FrontHookManager extends BaseHook
|
||||
{
|
||||
/** @var TaxEngine */
|
||||
protected $taxEngine;
|
||||
|
||||
public function __construct(TaxEngine $taxEngine)
|
||||
{
|
||||
$this->taxEngine = $taxEngine;
|
||||
}
|
||||
|
||||
public function onOrderInvoiceAfterJsInclude(HookRenderEvent $event)
|
||||
{
|
||||
$payPlugModuleId = PayPlugModule::getModuleId();
|
||||
if (PayPlugModule::getConfigValue(PayPlugConfigValue::PAYMENT_PAGE_TYPE) === "lightbox") {
|
||||
$event->add($this->render(
|
||||
'PayPlugModule/order-invoice-after-js-include.html',
|
||||
compact('payPlugModuleId')
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
public function onOrderInvoicePaymentExtra(HookRenderEvent $event)
|
||||
{
|
||||
if ((int)$event->getArgument('module') !== PayPlugModule::getModuleId()) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->displayOneClickPayment($event);
|
||||
$this->displayMultiPayment($event);
|
||||
}
|
||||
|
||||
protected function displayMultiPayment(HookRenderEvent $event)
|
||||
{
|
||||
if (!PayPlugModule::getConfigValue(PayPlugConfigValue::MULTI_PAYMENT_ENABLED)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$nTimes = PayPlugModule::getConfigValue(PayPlugConfigValue::MULTI_PAYMENT_TIMES);
|
||||
$minimumAmount = PayPlugModule::getConfigValue(PayPlugConfigValue::MULTI_PAYMENT_MINIMUM);
|
||||
$maximumAmount = PayPlugModule::getConfigValue(PayPlugConfigValue::MULTI_PAYMENT_MAXIMUM);
|
||||
|
||||
/** @var Country $country */
|
||||
$country = $this->taxEngine->getDeliveryCountry();
|
||||
|
||||
$cart = $this->getSession()->getSessionCart();
|
||||
$cartAmount = $cart->getTaxedAmount($country);
|
||||
if ($cartAmount <= $minimumAmount || $cartAmount >= $maximumAmount) {
|
||||
return;
|
||||
}
|
||||
|
||||
$event->add(
|
||||
$this->render(
|
||||
'PayPlugModule/multi-payment.html',
|
||||
compact("nTimes")
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
protected function displayOneClickPayment(HookRenderEvent $event)
|
||||
{
|
||||
if (!PayPlugModule::getConfigValue(PayPlugConfigValue::ONE_CLICK_PAYMENT_ENABLED)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$customerId = $this->getSession()->getCustomerUser()->getId();
|
||||
|
||||
$payPlugCard = PayPlugCardQuery::create()
|
||||
->findOneByCustomerId($customerId);
|
||||
|
||||
if (null === $payPlugCard) {
|
||||
return;
|
||||
}
|
||||
|
||||
$event->add(
|
||||
$this->render(
|
||||
'PayPlugModule/one-click-payment.html',
|
||||
[
|
||||
'last4' => $payPlugCard->getLast4()
|
||||
]
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
<?php
|
||||
|
||||
return array(
|
||||
' refunded' => 'Remboursé',
|
||||
'Adjust amount' => 'Ajuster le montant',
|
||||
'Amount' => 'Montant',
|
||||
'Canceled' => 'Annulé',
|
||||
'Capture order' => 'Déclencher le paiement de cette commande',
|
||||
'Differed payment' => 'Paiement différé ',
|
||||
'Do you really want to capture this order ?' => 'Voulez vous vraiment déclencher le paiement de cette commande ?',
|
||||
'Do you really want to refund this order ?' => 'Voulez vous vraiment rembourser cette commande ?',
|
||||
'Force the capture for this order' => 'Forcer le déclenchement du paiement',
|
||||
'Multi payment' => 'Paiement en plusieurs fois',
|
||||
'Order without shipping' => 'La commande sans les frais de port',
|
||||
'Paid at' => 'Payé le ',
|
||||
'PayPlug API configuration' => 'Configuration API PayPlug',
|
||||
'PayPlug basic payment configuration' => 'Configuration de paiement basique',
|
||||
'PayPlug delivery type configuration' => 'Configuration des types de livraison PayPlug',
|
||||
'PayPlug module configuration' => 'PayPlug module configuration',
|
||||
'PayPlug offer' => 'Offre PayPlug',
|
||||
'PayPlug order data' => 'Données de commande PayPlug',
|
||||
'PayPlug premium offer configuration' => 'Configuration de paiement offre Premium',
|
||||
'PayPlug pro offer configuration' => 'Configuration de paiement offre Pro',
|
||||
'Payment capture will expire on ' => 'L\'empreinte de paiement expirera le ',
|
||||
'Payment n° ' => 'Paiement n° ',
|
||||
'Payment was captured at ' => 'Paiement déclenché le ',
|
||||
'Payments in several times are not guaranteed, a default may occur on future due dates.' => 'Les paiements en plusieurs fois ne sont pas garantis. Un défaut de paiement peut survenir lors des échéances futures.',
|
||||
'Planned at' => 'Prévu le ',
|
||||
'Please select a Pay Plug delivery type correspondance for each delivery modules' => 'Veuillez choisir un type de livraison PayPlug sur chaques modules de livraison',
|
||||
'Products' => 'Produits',
|
||||
'Refund' => 'Remboursement',
|
||||
'Refund order' => 'Rembourser la commande ',
|
||||
'Refunded at' => 'Remboursé le ',
|
||||
'Save' => 'Enregistrer',
|
||||
'The entire order' => 'La commande totale',
|
||||
'To trigger the payments on planned date please add a daily cron on this Thelia command ' => 'Pour déclencher les paiements programmés veuillez ajouter cette commande Thelia a un cron journalier ',
|
||||
'What do you want refund' => 'Que voulez-vous rembourser',
|
||||
);
|
||||
34
local/modules/PayPlugModule/I18n/en_US.php
Executable file
34
local/modules/PayPlugModule/I18n/en_US.php
Executable file
@@ -0,0 +1,34 @@
|
||||
<?php
|
||||
|
||||
return array(
|
||||
'2 times' => '2 times',
|
||||
'3 times' => '3 times',
|
||||
'4 times' => '4 times',
|
||||
'Capture the payment after order get the status' => 'Capture the payment after order get the status',
|
||||
'Choose API mode' => 'Choose API mode',
|
||||
'Enable one click payment' => 'Enable one click payment',
|
||||
'Enable payment by PayPlug' => 'Enable payment by PayPlug',
|
||||
'Enable payment in 2,3 or 4 times' => 'Enable payment in 2,3 or 4 times',
|
||||
'Enabled differed payment' => 'Enabled differed payment',
|
||||
'Enabled multi-payment' => 'Enabled multi-payment',
|
||||
'Error' => 'Error',
|
||||
'Hosted page' => 'Hosted page',
|
||||
'Hosted page will redirect your customer to a payment page / Lightbox will open a payment pop up in your website.' => 'Hosted page will redirect your customer to a payment page / Lightbox will open a payment pop up in your website.',
|
||||
'If checked, the order confirmation message is sent to the customer only when the payment is successful. The order notification is always sent to the shop administrator' => 'If checked, the order confirmation message is sent to the customer only when the payment is successful. The order notification is always sent to the shop administrator',
|
||||
'Invalid payment parameter, %parameter should not be null or empty.' => 'Invalid payment parameter, %parameter should not be null or empty.',
|
||||
'Lightbox' => 'Lightbox',
|
||||
'Live API secret key' => 'Live API secret key',
|
||||
'Look here %link' => 'Look here %link',
|
||||
'Maximum amount ' => 'Maximum amount ',
|
||||
'Minimum amount ' => 'Minimum amount ',
|
||||
'Payment in ' => 'Payment in ',
|
||||
'Payment page type' => 'Payment page type',
|
||||
'Payplug.js' => 'Payplug.js',
|
||||
'Select your PayPlug offer' => 'Select your PayPlug offer',
|
||||
'Send order confirmation on payment success' => 'Send order confirmation on payment success',
|
||||
'Test API secret key' => 'Test API secret key',
|
||||
'This will allow your customer to save their card fo future order.' => 'This will allow your customer to save their card fo future order.',
|
||||
'Trigger the payment on order status change (max : 7 days after)' => 'Trigger the payment on order status change (max : 7 days after)',
|
||||
'What status to set on expired capture ' => 'What status to set on expired capture ',
|
||||
'Which status to set when a capture is authorized' => 'Which status to set when a capture is authorized',
|
||||
);
|
||||
39
local/modules/PayPlugModule/I18n/fr_FR.php
Executable file
39
local/modules/PayPlugModule/I18n/fr_FR.php
Executable file
@@ -0,0 +1,39 @@
|
||||
<?php
|
||||
|
||||
return array(
|
||||
'2 times' => '2 fois',
|
||||
'3 times' => '3 fois',
|
||||
'4 times' => '4 fois',
|
||||
'Capture the payment after order get the status' => 'Déclenché le paiement lorsque la commande as le statut',
|
||||
'Carrier ' => 'Transporteur',
|
||||
'Choose API mode' => 'Choisissez le mode de l\'API',
|
||||
'E-Delivery ' => 'Livraison en ligne',
|
||||
'Enable one click payment' => 'Activer le paiement en un clic',
|
||||
'Enable payment by PayPlug' => 'Activer le paiement par PayPlug',
|
||||
'Enable payment in 2,3 or 4 times' => 'Activer le paiement en 2, 3 ou 4 fois.',
|
||||
'Enabled differed payment' => 'Activer le paiement différé',
|
||||
'Enabled multi-payment' => 'Activer le paiement en plusieurs fois',
|
||||
'Error' => 'Erreur',
|
||||
'Hosted page' => 'Hosted page',
|
||||
'Hosted page will redirect your customer to a payment page / Lightbox will open a payment pop up in your website.' => 'Hosted page redirige le client sur une page de paiement / Lightbox ouvre une pop-up de paiement sur votre site.',
|
||||
'If checked, the order confirmation message is sent to the customer only when the payment is successful. The order notification is always sent to the shop administrator' => 'Si la case est cochée, le message de confirmation de commande est envoyé au client seulement quand le paiment est réussi. La notification de commande est toujours envoyée à l\'administrateur du site',
|
||||
'Invalid payment parameter, %parameter should not be null or empty.' => 'Paramètre de paiement invalide, %parameter ne doit pas être nulle ou vide.',
|
||||
'Lightbox' => 'Lightbox',
|
||||
'Live API secret key' => 'Live API secret key',
|
||||
'Look here %link' => 'Regardez ici %link',
|
||||
'Maximum amount ' => 'Montant maximum',
|
||||
'Minimum amount ' => 'Montant minimum',
|
||||
'Network pick up ' => 'Point retrait',
|
||||
'Payment in ' => 'Paiement en ',
|
||||
'Payment page type' => 'Type de la page de paiement',
|
||||
'Payplug.js' => 'Payplug.js',
|
||||
'Select your PayPlug offer' => 'Séléctionner votre offre PayPlug',
|
||||
'Send order confirmation on payment success' => 'Confirmation de commande si le paiement réussit',
|
||||
'Store pick up ' => 'Retrait en magasin',
|
||||
'Test API secret key' => 'Test API secret key',
|
||||
'This will allow your customer to save their card fo future order.' => 'Cela permettra a vos clients d\'enregistrer leur carte pour leur commande futur.',
|
||||
'Trigger the payment on order status change (max : 7 days after)' => 'Déclencher le paiement au changement de statut (max : 7 jour après)',
|
||||
'Unknown' => 'Inconnue',
|
||||
'What status to set on expired capture ' => 'Quel statut pour les commandes dont l\'empreinte a expirée ',
|
||||
'Which status to set when a capture is authorized' => 'Quel staut mettre quand l\'empreinte est autorisé',
|
||||
);
|
||||
9
local/modules/PayPlugModule/I18n/frontOffice/default/fr_FR.php
Executable file
9
local/modules/PayPlugModule/I18n/frontOffice/default/fr_FR.php
Executable file
@@ -0,0 +1,9 @@
|
||||
<?php
|
||||
|
||||
return array(
|
||||
'A payment card ending by %last4 has been previously saved at your request. Payment for your order will be made immediately after clicking the "Next Step" button.' => 'Une carte de paiement finissant par %last4 as été enregitrée précédemment a votre demande. Le paiement de cette commande seras fait automatiquement après un clic sur le bouton "Etape suivante".',
|
||||
'One click payment is available !' => 'Paiement en un clic disponible !',
|
||||
'Pay in %n times without fees.' => 'Paiement en %n fois sans frais.',
|
||||
'To clear your payment card details, <a href="%url">please click here</a>' => 'Pour supprimer ces informations de paiement, <a href="%url">cliquez ici</a>',
|
||||
'You will be asked to save your payment card data.' => 'Ils vous sera demandé d\'enregistrer votre carte bancaire.',
|
||||
);
|
||||
20
local/modules/PayPlugModule/Model/OrderPayPlugData.php
Executable file
20
local/modules/PayPlugModule/Model/OrderPayPlugData.php
Executable file
@@ -0,0 +1,20 @@
|
||||
<?php
|
||||
|
||||
namespace PayPlugModule\Model;
|
||||
|
||||
use PayPlugModule\Model\Base\OrderPayPlugData as BaseOrderPayPlugData;
|
||||
|
||||
/**
|
||||
* Skeleton subclass for representing a row from the 'order_pay_plug_data' table.
|
||||
*
|
||||
*
|
||||
*
|
||||
* You should add additional methods to this class to meet the
|
||||
* application requirements. This class will only be generated as
|
||||
* long as it does not already exist in the output directory.
|
||||
*
|
||||
*/
|
||||
class OrderPayPlugData extends BaseOrderPayPlugData
|
||||
{
|
||||
|
||||
}
|
||||
20
local/modules/PayPlugModule/Model/OrderPayPlugDataQuery.php
Executable file
20
local/modules/PayPlugModule/Model/OrderPayPlugDataQuery.php
Executable file
@@ -0,0 +1,20 @@
|
||||
<?php
|
||||
|
||||
namespace PayPlugModule\Model;
|
||||
|
||||
use PayPlugModule\Model\Base\OrderPayPlugDataQuery as BaseOrderPayPlugDataQuery;
|
||||
|
||||
/**
|
||||
* Skeleton subclass for performing query and update operations on the 'order_pay_plug_data' table.
|
||||
*
|
||||
*
|
||||
*
|
||||
* You should add additional methods to this class to meet the
|
||||
* application requirements. This class will only be generated as
|
||||
* long as it does not already exist in the output directory.
|
||||
*
|
||||
*/
|
||||
class OrderPayPlugDataQuery extends BaseOrderPayPlugDataQuery
|
||||
{
|
||||
|
||||
}
|
||||
20
local/modules/PayPlugModule/Model/OrderPayPlugMultiPayment.php
Executable file
20
local/modules/PayPlugModule/Model/OrderPayPlugMultiPayment.php
Executable file
@@ -0,0 +1,20 @@
|
||||
<?php
|
||||
|
||||
namespace PayPlugModule\Model;
|
||||
|
||||
use PayPlugModule\Model\Base\OrderPayPlugMultiPayment as BaseOrderPayPlugMultiPayment;
|
||||
|
||||
/**
|
||||
* Skeleton subclass for representing a row from the 'order_pay_plug_multi_payment' table.
|
||||
*
|
||||
*
|
||||
*
|
||||
* You should add additional methods to this class to meet the
|
||||
* application requirements. This class will only be generated as
|
||||
* long as it does not already exist in the output directory.
|
||||
*
|
||||
*/
|
||||
class OrderPayPlugMultiPayment extends BaseOrderPayPlugMultiPayment
|
||||
{
|
||||
|
||||
}
|
||||
20
local/modules/PayPlugModule/Model/OrderPayPlugMultiPaymentQuery.php
Executable file
20
local/modules/PayPlugModule/Model/OrderPayPlugMultiPaymentQuery.php
Executable file
@@ -0,0 +1,20 @@
|
||||
<?php
|
||||
|
||||
namespace PayPlugModule\Model;
|
||||
|
||||
use PayPlugModule\Model\Base\OrderPayPlugMultiPaymentQuery as BaseOrderPayPlugMultiPaymentQuery;
|
||||
|
||||
/**
|
||||
* Skeleton subclass for performing query and update operations on the 'order_pay_plug_multi_payment' table.
|
||||
*
|
||||
*
|
||||
*
|
||||
* You should add additional methods to this class to meet the
|
||||
* application requirements. This class will only be generated as
|
||||
* long as it does not already exist in the output directory.
|
||||
*
|
||||
*/
|
||||
class OrderPayPlugMultiPaymentQuery extends BaseOrderPayPlugMultiPaymentQuery
|
||||
{
|
||||
|
||||
}
|
||||
20
local/modules/PayPlugModule/Model/PayPlugCard.php
Executable file
20
local/modules/PayPlugModule/Model/PayPlugCard.php
Executable file
@@ -0,0 +1,20 @@
|
||||
<?php
|
||||
|
||||
namespace PayPlugModule\Model;
|
||||
|
||||
use PayPlugModule\Model\Base\PayPlugCard as BasePayPlugCard;
|
||||
|
||||
/**
|
||||
* Skeleton subclass for representing a row from the 'pay_plug_card' table.
|
||||
*
|
||||
*
|
||||
*
|
||||
* You should add additional methods to this class to meet the
|
||||
* application requirements. This class will only be generated as
|
||||
* long as it does not already exist in the output directory.
|
||||
*
|
||||
*/
|
||||
class PayPlugCard extends BasePayPlugCard
|
||||
{
|
||||
|
||||
}
|
||||
20
local/modules/PayPlugModule/Model/PayPlugCardQuery.php
Executable file
20
local/modules/PayPlugModule/Model/PayPlugCardQuery.php
Executable file
@@ -0,0 +1,20 @@
|
||||
<?php
|
||||
|
||||
namespace PayPlugModule\Model;
|
||||
|
||||
use PayPlugModule\Model\Base\PayPlugCardQuery as BasePayPlugCardQuery;
|
||||
|
||||
/**
|
||||
* Skeleton subclass for performing query and update operations on the 'pay_plug_card' table.
|
||||
*
|
||||
*
|
||||
*
|
||||
* You should add additional methods to this class to meet the
|
||||
* application requirements. This class will only be generated as
|
||||
* long as it does not already exist in the output directory.
|
||||
*
|
||||
*/
|
||||
class PayPlugCardQuery extends BasePayPlugCardQuery
|
||||
{
|
||||
|
||||
}
|
||||
58
local/modules/PayPlugModule/Model/PayPlugConfigValue.php
Executable file
58
local/modules/PayPlugModule/Model/PayPlugConfigValue.php
Executable file
@@ -0,0 +1,58 @@
|
||||
<?php
|
||||
|
||||
|
||||
namespace PayPlugModule\Model;
|
||||
|
||||
|
||||
use PayPlugModule\PayPlugModule;
|
||||
|
||||
class PayPlugConfigValue
|
||||
{
|
||||
const OFFER = "offer";
|
||||
const PAYMENT_ENABLED = "payment_enabled";
|
||||
const API_MODE = "api_mode";
|
||||
const LIVE_API_KEY = "live_api_key";
|
||||
const TEST_API_KEY = "test_api_key";
|
||||
const PAYMENT_PAGE_TYPE = "payment_page_type";
|
||||
const ONE_CLICK_PAYMENT_ENABLED = "one_click_payment_enabled";
|
||||
const MULTI_PAYMENT_ENABLED = "multi_payment_enabled";
|
||||
const MULTI_PAYMENT_TIMES = "multi_payment_times";
|
||||
const MULTI_PAYMENT_MINIMUM = "multi_payment_minimum";
|
||||
const MULTI_PAYMENT_MAXIMUM = "multi_payment_maximum";
|
||||
const DIFFERED_PAYMENT_ENABLED = "differed_payment_enabled";
|
||||
const DIFFERED_PAYMENT_AUTHORIZED_CAPTURE_STATUS = "differed_payment_authorized_capture_status";
|
||||
const DIFFERED_PAYMENT_TRIGGER_CAPTURE_STATUS = "differed_payment_trigger_capture_status";
|
||||
const DIFFERED_PAYMENT_CAPTURE_EXPIRED_STATUS = "differed_payment_capture_expired_status";
|
||||
const SEND_CONFIRMATION_MESSAGE_ONLY_IF_PAID = "send_confirmation_message_only_if_paid";
|
||||
|
||||
public static function getConfigKeys()
|
||||
{
|
||||
return [
|
||||
self::OFFER,
|
||||
self::PAYMENT_ENABLED,
|
||||
self::API_MODE,
|
||||
self::LIVE_API_KEY,
|
||||
self::TEST_API_KEY,
|
||||
self::PAYMENT_PAGE_TYPE,
|
||||
self::ONE_CLICK_PAYMENT_ENABLED,
|
||||
self::MULTI_PAYMENT_ENABLED,
|
||||
self::MULTI_PAYMENT_TIMES,
|
||||
self::MULTI_PAYMENT_MINIMUM,
|
||||
self::MULTI_PAYMENT_MAXIMUM,
|
||||
self::DIFFERED_PAYMENT_ENABLED,
|
||||
self::DIFFERED_PAYMENT_TRIGGER_CAPTURE_STATUS,
|
||||
self::DIFFERED_PAYMENT_AUTHORIZED_CAPTURE_STATUS,
|
||||
self::DIFFERED_PAYMENT_CAPTURE_EXPIRED_STATUS,
|
||||
self::SEND_CONFIRMATION_MESSAGE_ONLY_IF_PAID
|
||||
];
|
||||
}
|
||||
|
||||
public static function getApiKey()
|
||||
{
|
||||
if (PayPlugModule::getConfigValue(self::API_MODE, 'test') === 'live') {
|
||||
return PayPlugModule::getConfigValue(self::LIVE_API_KEY);
|
||||
}
|
||||
|
||||
return PayPlugModule::getConfigValue(self::TEST_API_KEY);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
<?php
|
||||
|
||||
namespace PayPlugModule\Model;
|
||||
|
||||
use PayPlugModule\Model\Base\PayPlugModuleDeliveryType as BasePayPlugModuleDeliveryType;
|
||||
|
||||
/**
|
||||
* Skeleton subclass for representing a row from the 'pay_plug_module_delivery_type' table.
|
||||
*
|
||||
*
|
||||
*
|
||||
* You should add additional methods to this class to meet the
|
||||
* application requirements. This class will only be generated as
|
||||
* long as it does not already exist in the output directory.
|
||||
*
|
||||
*/
|
||||
class PayPlugModuleDeliveryType extends BasePayPlugModuleDeliveryType
|
||||
{
|
||||
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
<?php
|
||||
|
||||
namespace PayPlugModule\Model;
|
||||
|
||||
use PayPlugModule\Model\Base\PayPlugModuleDeliveryTypeQuery as BasePayPlugModuleDeliveryTypeQuery;
|
||||
|
||||
/**
|
||||
* Skeleton subclass for performing query and update operations on the 'pay_plug_module_delivery_type' table.
|
||||
*
|
||||
*
|
||||
*
|
||||
* You should add additional methods to this class to meet the
|
||||
* application requirements. This class will only be generated as
|
||||
* long as it does not already exist in the output directory.
|
||||
*
|
||||
*/
|
||||
class PayPlugModuleDeliveryTypeQuery extends BasePayPlugModuleDeliveryTypeQuery
|
||||
{
|
||||
|
||||
}
|
||||
137
local/modules/PayPlugModule/PayPlugModule.php
Executable file
137
local/modules/PayPlugModule/PayPlugModule.php
Executable file
@@ -0,0 +1,137 @@
|
||||
<?php
|
||||
/*************************************************************************************/
|
||||
/* This file is part of the Thelia package. */
|
||||
/* */
|
||||
/* Copyright (c) OpenStudio */
|
||||
/* email : dev@thelia.net */
|
||||
/* web : http://www.thelia.net */
|
||||
/* */
|
||||
/* For the full copyright and license information, please view the LICENSE.txt */
|
||||
/* file that was distributed with this source code. */
|
||||
/*************************************************************************************/
|
||||
|
||||
namespace PayPlugModule;
|
||||
|
||||
use PayPlugModule\EventListener\FormExtend\OrderFormListener;
|
||||
use PayPlugModule\Model\PayPlugConfigValue;
|
||||
use PayPlugModule\Service\PaymentService;
|
||||
use Propel\Runtime\Connection\ConnectionInterface;
|
||||
use Symfony\Component\Finder\Finder;
|
||||
use Symfony\Component\HttpFoundation\RedirectResponse;
|
||||
use Thelia\Core\HttpFoundation\JsonResponse;
|
||||
use Thelia\Core\Template\TemplateDefinition;
|
||||
use Thelia\Install\Database;
|
||||
use Thelia\Model\Order;
|
||||
use Thelia\Module\AbstractPaymentModule;
|
||||
use Thelia\Tools\URL;
|
||||
|
||||
class PayPlugModule extends AbstractPaymentModule
|
||||
{
|
||||
/** @var string */
|
||||
const DOMAIN_NAME = 'payplugmodule';
|
||||
|
||||
|
||||
public function postActivation(ConnectionInterface $con = null)
|
||||
{
|
||||
if (!$this->getConfigValue('is_initialized', false)) {
|
||||
$database = new Database($con);
|
||||
$database->insertSql(null, [__DIR__ . "/Config/thelia.sql"]);
|
||||
}
|
||||
}
|
||||
|
||||
public function update($currentVersion, $newVersion, ConnectionInterface $con = null)
|
||||
{
|
||||
$finder = Finder::create()
|
||||
->name('*.sql')
|
||||
->depth(0)
|
||||
->sortByName()
|
||||
->in(__DIR__ . DS . 'Config' . DS . 'update');
|
||||
|
||||
$database = new Database($con);
|
||||
|
||||
/** @var \SplFileInfo $file */
|
||||
foreach ($finder as $file) {
|
||||
if (version_compare($currentVersion, $file->getBasename('.sql'), '<')) {
|
||||
$database->insertSql(null, [$file->getPathname()]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function isValidPayment()
|
||||
{
|
||||
/** @var PaymentService $paymentService */
|
||||
$paymentService = $this->container->get('payplugmodule_payment_service');
|
||||
return $paymentService->isPayPlugAvailable();
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function pay(Order $order)
|
||||
{
|
||||
try {
|
||||
/** @var PaymentService $paymentService */
|
||||
$paymentService = $this->container->get('payplugmodule_payment_service');
|
||||
|
||||
$slice = 1;
|
||||
|
||||
$isMultiPayment = $this->getRequest()->getSession()->get(OrderFormListener::PAY_PLUG_MULTI_PAYMENT_FIELD_NAME, 0);
|
||||
if ($isMultiPayment) {
|
||||
$orderTotalAmount = $order->getTotalAmount();
|
||||
|
||||
$minAmount = PayPlugModule::getConfigValue(PayPlugConfigValue::MULTI_PAYMENT_MINIMUM);
|
||||
$maxAmount = PayPlugModule::getConfigValue(PayPlugConfigValue::MULTI_PAYMENT_MAXIMUM);
|
||||
|
||||
if ($minAmount <= $orderTotalAmount && $maxAmount >= $orderTotalAmount) {
|
||||
$slice = PayPlugModule::getConfigValue(PayPlugConfigValue::MULTI_PAYMENT_TIMES);
|
||||
}
|
||||
}
|
||||
|
||||
$payment = $paymentService->sendOrderPayment(
|
||||
$order,
|
||||
PayPlugModule::getConfigValue(PayPlugConfigValue::DIFFERED_PAYMENT_ENABLED, false),
|
||||
PayPlugModule::getConfigValue(PayPlugConfigValue::ONE_CLICK_PAYMENT_ENABLED, false),
|
||||
$slice
|
||||
);
|
||||
|
||||
$forceRedirect = false;
|
||||
if (true === $payment['isPaid']) {
|
||||
$forceRedirect = true;
|
||||
$payment['url'] = URL::getInstance()->absoluteUrl('/order/placed/'.$order->getId());
|
||||
}
|
||||
|
||||
if ($this->getRequest()->isXmlHttpRequest()) {
|
||||
return new JsonResponse(
|
||||
[
|
||||
'paymentUrl' => $payment['url'],
|
||||
'forceRedirect' => $forceRedirect
|
||||
]
|
||||
);
|
||||
}
|
||||
} catch (\Exception $exception) {
|
||||
if ($this->getRequest()->isXmlHttpRequest()) {
|
||||
return new JsonResponse(['error' => $exception->getMessage()], 400);
|
||||
}
|
||||
return RedirectResponse::create(URL::getInstance()->absoluteUrl('error'));
|
||||
}
|
||||
|
||||
return new RedirectResponse($payment['url']);
|
||||
}
|
||||
|
||||
public function getHooks()
|
||||
{
|
||||
return [
|
||||
[
|
||||
"type" => TemplateDefinition::BACK_OFFICE,
|
||||
"code" => "payplugmodule.configuration.bottom",
|
||||
"title" => [
|
||||
"en_US" => "Bottom of PayPlug configuration page",
|
||||
"fr_FR" => "Bas de la page de configuration PayPlug",
|
||||
],
|
||||
"block" => false,
|
||||
"active" => true,
|
||||
]
|
||||
];
|
||||
}
|
||||
|
||||
}
|
||||
17
local/modules/PayPlugModule/Readme.md
Executable file
17
local/modules/PayPlugModule/Readme.md
Executable file
@@ -0,0 +1,17 @@
|
||||
# Pay Plug Module
|
||||
|
||||
Thelia module for the payment solution PayPlug https://www.payplug.com
|
||||
|
||||
## Installation
|
||||
|
||||
### Composer
|
||||
|
||||
Add it in your main thelia composer.json file
|
||||
|
||||
```
|
||||
composer require thelia/pay-plug-module:~1.0.0
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
Go to module configuration page select the offer you have with PayPlug (starter, pro or premium) and you will see the options who corresponding to your offer.
|
||||
103
local/modules/PayPlugModule/Service/OrderStatusService.php
Executable file
103
local/modules/PayPlugModule/Service/OrderStatusService.php
Executable file
@@ -0,0 +1,103 @@
|
||||
<?php
|
||||
|
||||
namespace PayPlugModule\Service;
|
||||
|
||||
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
|
||||
use Thelia\Core\Event\OrderStatus\OrderStatusCreateEvent;
|
||||
use Thelia\Core\Event\TheliaEvents;
|
||||
use Thelia\Model\OrderStatusQuery;
|
||||
|
||||
class OrderStatusService
|
||||
{
|
||||
const REFUND_PENDING_ORDER_STATUS_CODE = "refund_pending";
|
||||
|
||||
const AUTHORIZED_CAPTURE_ORDER_STATUS_CODE = "authorized_capture";
|
||||
const EXPIRED_CAPTURE_ORDER_STATUS_CODE = "expired_capture";
|
||||
|
||||
public function __construct(EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
$this->dispatcher = $dispatcher;
|
||||
}
|
||||
|
||||
/**
|
||||
* @var EventDispatcherInterface
|
||||
*/
|
||||
protected $dispatcher;
|
||||
|
||||
public function initAllStatuses()
|
||||
{
|
||||
$this->findOrCreateRefundPendingOrderStatus();
|
||||
$this->findOrCreateAuthorizedCaptureOrderStatus();
|
||||
$this->findOrCreateExpiredCaptureOrderStatus();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Thelia\Model\OrderStatus
|
||||
*/
|
||||
public function findOrCreateRefundPendingOrderStatus()
|
||||
{
|
||||
$refundPendingOrderStatus = OrderStatusQuery::create()
|
||||
->findOneByCode($this::REFUND_PENDING_ORDER_STATUS_CODE);
|
||||
|
||||
if (null !== $refundPendingOrderStatus) {
|
||||
return $refundPendingOrderStatus;
|
||||
}
|
||||
|
||||
$refundPendingOrderStatusEvent = (new OrderStatusCreateEvent())
|
||||
->setCode(self::REFUND_PENDING_ORDER_STATUS_CODE)
|
||||
->setColor("#A7A7A7")
|
||||
->setLocale('en_US')
|
||||
->setTitle('Refund pending');
|
||||
|
||||
$this->dispatcher->dispatch(TheliaEvents::ORDER_STATUS_CREATE, $refundPendingOrderStatusEvent);
|
||||
|
||||
return $refundPendingOrderStatusEvent->getOrderStatus();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Thelia\Model\OrderStatus
|
||||
*/
|
||||
public function findOrCreateAuthorizedCaptureOrderStatus()
|
||||
{
|
||||
$authorizedCaptureOrderStatus = OrderStatusQuery::create()
|
||||
->findOneByCode($this::AUTHORIZED_CAPTURE_ORDER_STATUS_CODE);
|
||||
|
||||
if (null !== $authorizedCaptureOrderStatus) {
|
||||
return $authorizedCaptureOrderStatus;
|
||||
}
|
||||
|
||||
$authorizedCaptureOrderStatus = (new OrderStatusCreateEvent())
|
||||
->setCode(self::AUTHORIZED_CAPTURE_ORDER_STATUS_CODE)
|
||||
->setColor("#71ED71")
|
||||
->setLocale('en_US')
|
||||
->setTitle('Authorized capture');
|
||||
|
||||
$this->dispatcher->dispatch(TheliaEvents::ORDER_STATUS_CREATE, $authorizedCaptureOrderStatus);
|
||||
|
||||
return $authorizedCaptureOrderStatus->getOrderStatus();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Thelia\Model\OrderStatus
|
||||
*/
|
||||
public function findOrCreateExpiredCaptureOrderStatus()
|
||||
{
|
||||
$expiredCaptureOrderStatus = OrderStatusQuery::create()
|
||||
->findOneByCode($this::EXPIRED_CAPTURE_ORDER_STATUS_CODE);
|
||||
|
||||
if (null !== $expiredCaptureOrderStatus) {
|
||||
return $expiredCaptureOrderStatus;
|
||||
}
|
||||
|
||||
$expiredCaptureOrderStatus = (new OrderStatusCreateEvent())
|
||||
->setCode(self::EXPIRED_CAPTURE_ORDER_STATUS_CODE)
|
||||
->setColor("#4B4B4B")
|
||||
->setLocale('en_US')
|
||||
->setTitle('Expired capture');
|
||||
|
||||
$this->dispatcher->dispatch(TheliaEvents::ORDER_STATUS_CREATE, $expiredCaptureOrderStatus);
|
||||
|
||||
return $expiredCaptureOrderStatus->getOrderStatus();
|
||||
}
|
||||
|
||||
}
|
||||
152
local/modules/PayPlugModule/Service/PaymentService.php
Executable file
152
local/modules/PayPlugModule/Service/PaymentService.php
Executable file
@@ -0,0 +1,152 @@
|
||||
<?php
|
||||
|
||||
namespace PayPlugModule\Service;
|
||||
|
||||
use Payplug\Notification;
|
||||
use Payplug\Payment;
|
||||
use Payplug\Payplug;
|
||||
use PayPlugModule\Event\PayPlugPaymentEvent;
|
||||
use PayPlugModule\Model\OrderPayPlugMultiPayment;
|
||||
use PayPlugModule\Model\PayPlugCardQuery;
|
||||
use PayPlugModule\Model\PayPlugConfigValue;
|
||||
use PayPlugModule\PayPlugModule;
|
||||
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
|
||||
use Thelia\Core\HttpFoundation\Request;
|
||||
use Thelia\Model\Order;
|
||||
|
||||
class PaymentService
|
||||
{
|
||||
/**
|
||||
* @var EventDispatcherInterface
|
||||
*/
|
||||
protected $dispatcher;
|
||||
|
||||
public function __construct(EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
$this->dispatcher = $dispatcher;
|
||||
self::initAuth();
|
||||
}
|
||||
|
||||
public function isPayPlugAvailable()
|
||||
{
|
||||
if (!PayPlugModule::getConfigValue(PayPlugConfigValue::PAYMENT_ENABLED, false)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check API availability
|
||||
try {
|
||||
Payment::listPayments(1);
|
||||
} catch (\Exception $exception) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Order $order
|
||||
* @return array
|
||||
* @throws \Propel\Runtime\Exception\PropelException
|
||||
*/
|
||||
public function sendOrderPayment(
|
||||
Order $order,
|
||||
bool $capture = false,
|
||||
bool $allowSaveCard = false,
|
||||
int $paymentSlice = 1
|
||||
) {
|
||||
$paymentEvent = (new PayPlugPaymentEvent())
|
||||
->buildFromOrder($order)
|
||||
->setCapture($capture)
|
||||
->setAllowSaveCard($allowSaveCard);
|
||||
|
||||
if (null !== $card = PayPlugCardQuery::create()->findOneByCustomerId($order->getCustomerId())) {
|
||||
$paymentEvent->setPaymentMethod($card->getUuid())
|
||||
->setInitiator('PAYER')
|
||||
->setAllowSaveCard(false);
|
||||
}
|
||||
|
||||
$firstPayment = null;
|
||||
if ($paymentSlice > 1) {
|
||||
$totalAmount = $paymentEvent->getAmount();
|
||||
$firstAmount = round($totalAmount / $paymentSlice) + $totalAmount % $paymentSlice;
|
||||
$paymentEvent->setForceSaveCard(true)
|
||||
->setAllowSaveCard(false)
|
||||
->setPaymentMethod(null)
|
||||
->setAmount($firstAmount);
|
||||
$today = (new \DateTime())->setTime(0,0,0,0);
|
||||
|
||||
$firstPayment = (new OrderPayPlugMultiPayment())
|
||||
->setAmount($paymentEvent->getAmount())
|
||||
->setOrder($order)
|
||||
->setPlannedAt($today)
|
||||
->setPaymentId($paymentEvent->getPaymentId())
|
||||
->setIsFirstPayment(true);
|
||||
$firstPayment->save();
|
||||
|
||||
for ($paymentCount = 1; $paymentCount < $paymentSlice ; $paymentCount++) {
|
||||
$paymentDay = (clone $today)->add((new \DateInterval('P'.intval($paymentCount * 30).'D')));
|
||||
$multiPayment = (new OrderPayPlugMultiPayment())
|
||||
->setAmount(round($totalAmount / $paymentSlice))
|
||||
->setOrder($order)
|
||||
->setPlannedAt($paymentDay);
|
||||
$multiPayment->save();
|
||||
}
|
||||
}
|
||||
|
||||
$this->dispatcher->dispatch(PayPlugPaymentEvent::ORDER_PAYMENT_EVENT, $paymentEvent);
|
||||
|
||||
if (null !== $firstPayment) {
|
||||
$firstPayment->setPaymentId($paymentEvent->getPaymentId())
|
||||
->save();
|
||||
|
||||
}
|
||||
|
||||
$isPaid = $paymentEvent->isPaid();
|
||||
|
||||
// If one click payment consider it as isPaid (redirect to order/placed)
|
||||
if (!$isPaid && $paymentEvent->isCapture() && null !== $paymentEvent->getPaymentMethod()) {
|
||||
$isPaid = true;
|
||||
}
|
||||
|
||||
return [
|
||||
'id' => $paymentEvent->getPaymentId(),
|
||||
'url' => $paymentEvent->getPaymentUrl(),
|
||||
'isPaid' => $isPaid
|
||||
];
|
||||
}
|
||||
|
||||
public function doOrderCapture(Order $order)
|
||||
{
|
||||
$paymentEvent = (new PayPlugPaymentEvent())
|
||||
->buildFromOrder($order);
|
||||
|
||||
$this->dispatcher->dispatch(PayPlugPaymentEvent::ORDER_CAPTURE_EVENT, $paymentEvent);
|
||||
}
|
||||
|
||||
public function doOrderRefund(Order $order, int $amountRefund = null)
|
||||
{
|
||||
$paymentEvent = (new PayPlugPaymentEvent())
|
||||
->buildFromOrder($order);
|
||||
|
||||
if (null !== $amountRefund) {
|
||||
$paymentEvent->setAmount($amountRefund);
|
||||
}
|
||||
|
||||
$this->dispatcher->dispatch(PayPlugPaymentEvent::ORDER_REFUND_EVENT, $paymentEvent);
|
||||
}
|
||||
|
||||
public function getNotificationResource(Request $request)
|
||||
{
|
||||
return Notification::treat($request->getContent());
|
||||
}
|
||||
|
||||
public function initAuth()
|
||||
{
|
||||
return Payplug::init(
|
||||
[
|
||||
'secretKey' => PayPlugConfigValue::getApiKey(),
|
||||
'apiVersion' => '2019-08-06'
|
||||
]
|
||||
);
|
||||
}
|
||||
}
|
||||
13
local/modules/PayPlugModule/composer.json
Executable file
13
local/modules/PayPlugModule/composer.json
Executable file
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"name": "thelia/pay-plug-module",
|
||||
"license": "LGPL-3.0-or-later",
|
||||
"type": "thelia-module",
|
||||
"require": {
|
||||
"thelia/installer": "~1.1",
|
||||
"payplug/payplug-php": "^3.2",
|
||||
"giggsey/libphonenumber-for-php": "^8.12"
|
||||
},
|
||||
"extra": {
|
||||
"installer-name": "PayPlugModule"
|
||||
}
|
||||
}
|
||||
BIN
local/modules/PayPlugModule/images/payplug.png
Executable file
BIN
local/modules/PayPlugModule/images/payplug.png
Executable file
Binary file not shown.
|
After Width: | Height: | Size: 9.3 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 11 KiB |
@@ -0,0 +1,408 @@
|
||||
{extends file="admin-layout.tpl"}
|
||||
|
||||
{block name="after-bootstrap-css"}
|
||||
|
||||
{/block}
|
||||
|
||||
{block name="no-return-functions"}
|
||||
{$admin_current_location = 'module'}
|
||||
{/block}
|
||||
|
||||
{block name="page-title"}{intl l='PayPlug module configuration' d='payplugmodule.bo.default'}{/block}
|
||||
|
||||
{block name="check-resource"}admin.module{/block}
|
||||
{block name="check-access"}view{/block}
|
||||
{block name="check-module"}PayPlug{/block}
|
||||
|
||||
{block name="main-content"}
|
||||
<style>
|
||||
.block {
|
||||
padding: 20px;
|
||||
border-bottom: 2px solid #00AB7A;
|
||||
}
|
||||
.block h2 {
|
||||
color: #00AB7A;
|
||||
}
|
||||
.block .block {
|
||||
border: 2px solid rgba(0, 211, 152, 0.61);
|
||||
}
|
||||
</style>
|
||||
<div class="col-md-12">
|
||||
<div class="panel panel-default">
|
||||
{form name="payplugmodule_configuration_form"}
|
||||
<form action="{url path="/admin/module/payplugmodule/configuration"}" method="POST">
|
||||
{form_hidden_fields form=$form}
|
||||
|
||||
{if $form_error}
|
||||
<div class="alert alert-danger">{$form_error_message}</div>
|
||||
{/if}
|
||||
|
||||
{form_field form=$form field='success_url'}
|
||||
<input type="hidden" name="{$name}" value="{url path={navigate to="current"}}"/>
|
||||
{/form_field}
|
||||
|
||||
<div class="panel-body">
|
||||
<div class="row">
|
||||
<div class="block col-md-12">
|
||||
<img style="height: 34px;" src="{image file='PayPlugModule/assets/logo-payplug.png' source="PayPlugModule"}" alt="Payment configuration" class="img-responsive" />
|
||||
</div>
|
||||
<div class="block col-md-12">
|
||||
<div class="col-md-12">
|
||||
<h2>{intl l="PayPlug offer" d='payplugmodule.bo.default'}</h2>
|
||||
</div>
|
||||
<div class="col-md-12">
|
||||
{form_field form=$form field="offer"}
|
||||
<div class="form-group {if $error}has-error{/if}">
|
||||
<label class="control-label">{$label}{if $required}<span class="required">*</span>{/if}</label>
|
||||
<br>
|
||||
{$inputOfferName = {$name}}
|
||||
{foreach from=$choices item=choice}
|
||||
<input id="{$name}_{$choice->value}" name="{$name}" type="radio" value="{$choice->value}" {if $data == $choice->value}checked{/if} />
|
||||
<label class="control-label" for="{$name}_{$choice->value}">{$choice->label}</label>
|
||||
{/foreach}
|
||||
{if ! empty($label_attr.help)}
|
||||
<span class="help-block">{$label_attr.help}</span>
|
||||
{/if}
|
||||
</div>
|
||||
{/form_field}
|
||||
</div>
|
||||
</div>
|
||||
<div class="block col-md-12">
|
||||
<div class="col-md-12">
|
||||
<h2>{intl l="PayPlug API configuration" d='payplugmodule.bo.default'}</h2>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
{form_field form=$form field="api_mode"}
|
||||
<div class="form-group {if $error}has-error{/if}">
|
||||
<label class="control-label" for="{$name}">
|
||||
|
||||
{$label}{if $required}<span class="required">*</span>{/if}
|
||||
<br>
|
||||
<select class="form-control" name="{$name}" id="{$name}">
|
||||
{foreach from=$choices item=choice}
|
||||
<option value="{$choice->value}" {if $data == $choice->value}selected{/if}>{$choice->label}</option>
|
||||
{/foreach}
|
||||
</select>
|
||||
</label>
|
||||
|
||||
{if ! empty($label_attr.help)}
|
||||
<span class="help-block">{$label_attr.help}</span>
|
||||
{/if}
|
||||
</div>
|
||||
{/form_field}
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
{form_field form=$form field='live_api_key'}
|
||||
<label for="{$name}" class="control-label">{$label}</label>
|
||||
<input id="{$name}" class="form-control" type="text" name="{$name}" value="{$data}"/>
|
||||
{if ! empty($label_attr.help)}
|
||||
<span class="help-block">{$label_attr.help nofilter}</span>
|
||||
{/if}
|
||||
{/form_field}
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
{form_field form=$form field='test_api_key'}
|
||||
<label for="{$name}" class="control-label">{$label}</label>
|
||||
<input id="{$name}" class="form-control" type="text" name="{$name}" value="{$data}"/>
|
||||
{if ! empty($label_attr.help)}
|
||||
<span class="help-block">{$label_attr.help nofilter}</span>
|
||||
{/if}
|
||||
{/form_field}
|
||||
</div>
|
||||
</div>
|
||||
<div class="block col-md-12" id="basic_configuration">
|
||||
<div class="col-md-12">
|
||||
<h2>{intl l="PayPlug basic payment configuration" d='payplugmodule.bo.default'}</h2>
|
||||
</div>
|
||||
<div class="col-md-12">
|
||||
{form_field form=$form field="payment_enabled"}
|
||||
<div class="form-group {if $error}has-error{/if}">
|
||||
<label class="control-label" for="{$name}">
|
||||
<input type="checkbox" name="{$name}" id="{$name}" {if $data}checked{/if}/>
|
||||
{$label}
|
||||
{if $required}<span class="required">*</span>{/if}
|
||||
</label>
|
||||
|
||||
{if ! empty($label_attr.help)}
|
||||
<span class="help-block">{$label_attr.help}</span>
|
||||
{/if}
|
||||
</div>
|
||||
{/form_field}
|
||||
</div>
|
||||
<div class="col-md-12">
|
||||
{form_field form=$form field="payment_page_type"}
|
||||
<div class="form-group {if $error}has-error{/if}">
|
||||
<label class="control-label" for="{$name}">
|
||||
{$label}{if $required}<span class="required">*</span>{/if}
|
||||
<br>
|
||||
<select class="form-control" name="{$name}" id="{$name}">
|
||||
{foreach from=$choices item=choice}
|
||||
<option value="{$choice->value}" {if $data == $choice->value}selected{/if}>{$choice->label}</option>
|
||||
{/foreach}
|
||||
</select>
|
||||
</label>
|
||||
|
||||
{if ! empty($label_attr.help)}
|
||||
<span class="help-block">{$label_attr.help}</span>
|
||||
{/if}
|
||||
</div>
|
||||
{/form_field}
|
||||
</div>
|
||||
<div class="col-md-12">
|
||||
{render_form_field field="send_confirmation_message_only_if_paid"}
|
||||
</div>
|
||||
</div>
|
||||
<div class="block col-md-12" id="pro_configuration">
|
||||
<div class="col-md-12">
|
||||
<h2>{intl l="PayPlug pro offer configuration" d='payplugmodule.bo.default'}</h2>
|
||||
</div>
|
||||
<div class="col-md-12">
|
||||
{form_field form=$form field="one_click_payment_enabled"}
|
||||
<div class="form-group {if $error}has-error{/if}">
|
||||
<label class="control-label" for="{$name}">
|
||||
<input type="checkbox" name="{$name}" id="{$name}" {if $data}checked{/if}/>
|
||||
{$label}
|
||||
|
||||
</label>
|
||||
|
||||
{if ! empty($label_attr.help)}
|
||||
<span class="help-block">{$label_attr.help}</span>
|
||||
{/if}
|
||||
</div>
|
||||
{/form_field}
|
||||
</div>
|
||||
<div class="col-md-12">
|
||||
{form_field form=$form field="multi_payment_enabled"}
|
||||
{$inputMultiPaymentName = $name}
|
||||
<div class="form-group {if $error}has-error{/if}">
|
||||
<label class="control-label" for="{$name}">
|
||||
<input type="checkbox" name="{$name}" id="{$name}" {if $data}checked{/if}/>
|
||||
{$label}
|
||||
</label>
|
||||
|
||||
{if ! empty($label_attr.help)}
|
||||
<span class="help-block">{$label_attr.help}</span>
|
||||
{/if}
|
||||
</div>
|
||||
{/form_field}
|
||||
</div>
|
||||
<div class="block col-md-12" id="multi_payment_fields">
|
||||
<div class="alert alert-warning">
|
||||
{intl l="Payments in several times are not guaranteed, a default may occur on future due dates." d='payplugmodule.bo.default'}
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
{form_field form=$form field='multi_payment_minimum'}
|
||||
<label for="auth_key" class="control-label">{$label}</label>
|
||||
<input id="auth_key" class="form-control" type="number" min="0" name="{$name}" value="{$data}"/>
|
||||
{/form_field}
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
{form_field form=$form field='multi_payment_maximum'}
|
||||
<label for="auth_key" class="control-label">{$label}</label>
|
||||
<input id="auth_key" class="form-control" type="number" min="0" name="{$name}" value="{$data}"/>
|
||||
{/form_field}
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
{form_field form=$form field="multi_payment_times"}
|
||||
<div class="form-group {if $error}has-error{/if}">
|
||||
<label class="control-label" for="{$name}">
|
||||
{$label}{if $required}<span class="required">*</span>{/if}
|
||||
<br>
|
||||
<select class="form-control" name="{$name}" id="{$name}">
|
||||
{foreach from=$choices item=choice}
|
||||
<option value="{$choice->value}" {if $data == $choice->value}selected{/if}>{$choice->label}</option>
|
||||
{/foreach}
|
||||
</select>
|
||||
</label>
|
||||
{if ! empty($label_attr.help)}
|
||||
<span class="help-block">{$label_attr.help}</span>
|
||||
{/if}
|
||||
</div>
|
||||
{/form_field}
|
||||
</div>
|
||||
<div class="alert alert-info col-md-12">
|
||||
<p>
|
||||
{intl l="To trigger the payments on planned date please add a daily cron on this Thelia command " d='payplugmodule.bo.default'}
|
||||
<strong>php Thelia payplug:treat:multi_payment</strong>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="block col-md-12" id="premium_configuration">
|
||||
<div class="col-md-12">
|
||||
<h2>{intl l="PayPlug premium offer configuration" d='payplugmodule.bo.default'}</h2>
|
||||
</div>
|
||||
<div class="col-md-12">
|
||||
{form_field form=$form field="differed_payment_enabled"}
|
||||
{$inputDifferedPaymentName = $name}
|
||||
<div class="form-group {if $error}has-error{/if}">
|
||||
<label class="control-label" for="{$name}">
|
||||
<input type="checkbox" name="{$name}" id="{$name}" {if $data}checked{/if}/>
|
||||
{$label}
|
||||
</label>
|
||||
|
||||
{if ! empty($label_attr.help)}
|
||||
<span class="help-block">{$label_attr.help}</span>
|
||||
{/if}
|
||||
</div>
|
||||
{/form_field}
|
||||
</div>
|
||||
<div class="block col-md-12" id="differed_payment_fields">
|
||||
<div class="col-md-4">
|
||||
{form_field form=$form field="differed_payment_authorized_capture_status"}
|
||||
<div class="form-group {if $error}has-error{/if}">
|
||||
<label class="control-label" for="{$name}">
|
||||
{$label}{if $required}<span class="required">*</span>{/if}
|
||||
<br>
|
||||
<select class="form-control" name="{$name}" id="{$name}">
|
||||
{loop type="order-status" name="order-status-select" backend_context="1"}
|
||||
<option value="{$ID}" {if $data == $ID}selected{/if}>{$TITLE}</option>
|
||||
{/loop}
|
||||
</select>
|
||||
</label>
|
||||
{if ! empty($label_attr.help)}
|
||||
<span class="help-block">{$label_attr.help}</span>
|
||||
{/if}
|
||||
</div>
|
||||
{/form_field}
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
{form_field form=$form field="differed_payment_trigger_capture_status"}
|
||||
<div class="form-group {if $error}has-error{/if}">
|
||||
<label class="control-label" for="{$name}">
|
||||
{$label}{if $required}<span class="required">*</span>{/if}
|
||||
<br>
|
||||
<select class="form-control" name="{$name}" id="{$name}">
|
||||
{loop type="order-status" name="order-status-select" backend_context="1"}
|
||||
<option value="{$ID}" {if $data == $ID}selected{/if}>{$TITLE}</option>
|
||||
{/loop}
|
||||
</select>
|
||||
</label>
|
||||
{if ! empty($label_attr.help)}
|
||||
<span class="help-block">{$label_attr.help}</span>
|
||||
{/if}
|
||||
</div>
|
||||
{/form_field}
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
{form_field form=$form field="differed_payment_capture_expired_status"}
|
||||
<div class="form-group {if $error}has-error{/if}">
|
||||
<label class="control-label" for="{$name}">
|
||||
{$label}{if $required}<span class="required">*</span>{/if}
|
||||
<br>
|
||||
<select class="form-control" name="{$name}" id="{$name}">
|
||||
{loop type="order-status" name="order-status-select" backend_context="1"}
|
||||
<option value="{$ID}" {if $data == $ID}selected{/if}>{$TITLE}</option>
|
||||
{/loop}
|
||||
</select>
|
||||
</label>
|
||||
{if ! empty($label_attr.help)}
|
||||
<span class="help-block">{$label_attr.help}</span>
|
||||
{/if}
|
||||
</div>
|
||||
{/form_field}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="block col-md-12" id="delivery_type_configuration">
|
||||
<div class="col-md-12">
|
||||
<h2>{intl l="PayPlug delivery type configuration" d='payplugmodule.bo.default'}</h2>
|
||||
<p>{intl l="Please select a Pay Plug delivery type correspondance for each delivery modules" d='payplugmodule.bo.default'}</p>
|
||||
</div>
|
||||
<div class="block col-md-12" id="differed_payment_fields">
|
||||
{foreach from=$deliveryModuleFormFields item="deliveryModuleFormField"}
|
||||
<div class="col-md-3">
|
||||
{form_field form=$form field=$deliveryModuleFormField['name']}
|
||||
<label class="control-label" for="{$name}">
|
||||
{$label}{if $required}<span class="required">*</span>{/if}
|
||||
<select class="form-control" name="{$name}" id="{$name}">
|
||||
{foreach from=$choices item=choice}
|
||||
<option value="{$choice->value}" {if $data == $choice->value}selected{/if}>{$choice->label}</option>
|
||||
{/foreach}
|
||||
</select>
|
||||
</label>
|
||||
{if ! empty($label_attr.help)}
|
||||
<span class="help-block">{$label_attr.help}</span>
|
||||
{/if}
|
||||
{/form_field}
|
||||
</div>
|
||||
{/foreach}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<br>
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<input type="submit" class="btn btn-success form-control" value="{intl l="Save" d='payplugmodule.bo.default'}">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
{/form}
|
||||
</div>
|
||||
{hook name="payplugmodule.configuration.bottom"}
|
||||
</div>
|
||||
{/block}
|
||||
|
||||
{block name="javascript-initialization"}
|
||||
|
||||
{/block}
|
||||
|
||||
{block name="javascript-last-call"}
|
||||
<script type="text/javascript">
|
||||
var inputOfferName = "{$inputOfferName}";
|
||||
var inputMultiPaymentName = "{$inputMultiPaymentName}";
|
||||
var inputDifferedPaymentName = "{$inputDifferedPaymentName}";
|
||||
{literal}
|
||||
jQuery(function($) {
|
||||
displayConfigurationBlock();
|
||||
displayMultiPaymentBlock();
|
||||
displayDifferedPaymentBlock();
|
||||
|
||||
$('input[name="'+inputOfferName+'"]').click(function(){
|
||||
displayConfigurationBlock();
|
||||
});
|
||||
|
||||
$('input[name="'+inputMultiPaymentName+'"]').click(function(){
|
||||
displayMultiPaymentBlock();
|
||||
});
|
||||
|
||||
$('input[name="'+inputDifferedPaymentName+'"]').click(function(){
|
||||
displayDifferedPaymentBlock();
|
||||
});
|
||||
|
||||
function displayConfigurationBlock() {
|
||||
var inputOfferChecked = $('input[name="'+inputOfferName+'"]:checked');
|
||||
var proConfigurationBlock = $("#pro_configuration");
|
||||
var premiumConfigurationBlock = $("#premium_configuration");
|
||||
|
||||
proConfigurationBlock.hide();
|
||||
premiumConfigurationBlock.hide();
|
||||
|
||||
if (inputOfferChecked.val() === 'pro') {
|
||||
proConfigurationBlock.show();
|
||||
} else if (inputOfferChecked.val() === 'premium') {
|
||||
proConfigurationBlock.show();
|
||||
premiumConfigurationBlock.show();
|
||||
}
|
||||
}
|
||||
|
||||
function displayMultiPaymentBlock() {
|
||||
var multiPaymentBlock = $("#multi_payment_fields");
|
||||
multiPaymentBlock.hide();
|
||||
if( $('input[name="'+inputMultiPaymentName+'"]').is(':checked') ){
|
||||
multiPaymentBlock.show();
|
||||
}
|
||||
}
|
||||
|
||||
function displayDifferedPaymentBlock() {
|
||||
var differedPaymentBlock = $("#differed_payment_fields");
|
||||
differedPaymentBlock.hide();
|
||||
if( $('input[name="'+inputDifferedPaymentName+'"]').is(':checked') ){
|
||||
differedPaymentBlock.show();
|
||||
}
|
||||
}
|
||||
});
|
||||
{/literal}
|
||||
</script>
|
||||
{/block}
|
||||
@@ -0,0 +1,168 @@
|
||||
<div id="orderPayPlug" class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<h4>{intl l="PayPlug order data" d='payplugmodule.bo.default'}</h4>
|
||||
</div>
|
||||
<div>
|
||||
{form name="payplugmodule_order_action_form_refund"}
|
||||
{if $form_error}
|
||||
<div class="alert alert-danger">{$form_error_message}</div>
|
||||
{/if}
|
||||
{/form}
|
||||
{form name="payplugmodule_order_action_form"}
|
||||
{if $form_error}
|
||||
<div class="alert alert-danger">{$form_error_message}</div>
|
||||
{/if}
|
||||
{/form}
|
||||
</div>
|
||||
<table class="table table-condensed table-left-aligned">
|
||||
<tbody>
|
||||
{if $amountRefunded || $isPaid}
|
||||
<tr>
|
||||
<th>{intl l="Refund" d='payplugmodule.bo.default'}</th>
|
||||
<td></td>
|
||||
<td>
|
||||
{loop type="order" name="refund-order-amount" id=$order_id customer="*" with_prev_next_info="true" backend_context="1"}
|
||||
{$orderTotalAmount = $TOTAL_TAXED_AMOUNT}
|
||||
{$orderTotalAmountWithoutShipping = $TOTAL_TAXED_AMOUNT-$POSTAGE}
|
||||
{/loop}
|
||||
{if $amountRefunded}
|
||||
<div class="alert alert-info">{format_money number=$amountRefunded/100} {intl l=" refunded" d='payplugmodule.bo.default'}</div>
|
||||
{/if}
|
||||
{if $orderTotalAmount > ($amountRefunded/100) }
|
||||
<div class="row">
|
||||
<div class="col-md-4">
|
||||
<label for="quick_select_amount_refund">{intl l="What do you want refund" d='payplugmodule.bo.default'}</label>
|
||||
<select class="form-control" name="" id="quick_select_amount_refund" multiple="true">
|
||||
<option value="{$orderTotalAmount}" selected>{intl l="The entire order" d='payplugmodule.bo.default'} ---- {format_money number=$orderTotalAmount currency_id=$CURRENCY}</option>
|
||||
<option value="{$orderTotalAmountWithoutShipping}">{intl l="Order without shipping" d='payplugmodule.bo.default'} ----{format_money number=$orderTotalAmountWithoutShipping currency_id=$CURRENCY}</option>
|
||||
<optgroup label="{intl l="Products" d='payplugmodule.bo.default'}" >
|
||||
{loop type="order_product" name="order-products" order=$order_id}
|
||||
<option value="{$REAL_TOTAL_TAXED_PRICE}">[{$PRODUCT_SALE_ELEMENTS_REF}] {$TITLE} ---- {format_money number=$REAL_TOTAL_TAXED_PRICE currency_id=$CURRENCY} </option>
|
||||
{/loop}
|
||||
</optgroup>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<label for="input_amount_refund">{intl l="Adjust amount" d='payplugmodule.bo.default'}</label>
|
||||
<div class="input-group">
|
||||
<span class="input-group-addon glyphicon glyphicon-chevron-right"></span>
|
||||
<input id="input_amount_refund" class="form-control" type="number" max="{$orderTotalAmount - $amountRefunded/100}" value="{$orderTotalAmount - $amountRefunded/100}">
|
||||
<span class="input-group-addon">{currency attr="symbol"}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<label for=""></label>
|
||||
<a class="btn btn-block btn-success image-delete" href="#order_refund_dialog" data-toggle="modal">
|
||||
{intl l="Refund" d='payplugmodule.bo.default'}
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
</td>
|
||||
</tr>
|
||||
{/if}
|
||||
{if $needCapture}
|
||||
<tr>
|
||||
<th>{intl l="Differed payment" d='payplugmodule.bo.default'}</th>
|
||||
{if null == $capturedAt}
|
||||
<td>{intl l="Payment capture will expire on " d='payplugmodule.bo.default'}{format_date date=$captureExpireAt}</td>
|
||||
<td>
|
||||
<a class="btn btn-block btn-success image-delete" href="#order_capture_dialog" data-toggle="modal">
|
||||
{intl l="Force the capture for this order" d='payplugmodule.bo.default'}
|
||||
</a>
|
||||
</td>
|
||||
{else}
|
||||
<td></td>
|
||||
<td>
|
||||
{intl l="Payment was captured at " d='payplugmodule.bo.default'}{format_date date=$capturedAt}
|
||||
</td>
|
||||
{/if}
|
||||
</tr>
|
||||
{/if}
|
||||
{if count($multiPayments) > 0}
|
||||
<tr>
|
||||
<th>{intl l="Multi payment" d='payplugmodule.bo.default'}</th>
|
||||
<td colspan="2">
|
||||
<table class="table table-condensed table-left-aligned">
|
||||
<tr>
|
||||
<th>{intl l="Payment n° " d='payplugmodule.bo.default'}</th>
|
||||
<th>{intl l="Amount" d='payplugmodule.bo.default'}</th>
|
||||
<th>{intl l="Planned at" d='payplugmodule.bo.default'}</th>
|
||||
<th>{intl l="Paid at" d='payplugmodule.bo.default'}</th>
|
||||
<th>{intl l="Refunded at" d='payplugmodule.bo.default'}</th>
|
||||
</tr>
|
||||
{$paymentCount = 1}
|
||||
{foreach from=$multiPayments item=multiPayment}
|
||||
<tr>
|
||||
<td>{$paymentCount}</td>
|
||||
<td>{format_money number=$multiPayment['amount']/100}</td>
|
||||
<td>{if $multiPayment['plannedAt']}{format_date date=$multiPayment['plannedAt']}{else}{intl l="Canceled" d='payplugmodule.bo.default'}{/if}</td>
|
||||
<td>{if $multiPayment['paidAt']}{format_date date=$multiPayment['paidAt']}{/if}</td>
|
||||
<td>{if $multiPayment['refundedAt']}{format_date date=$multiPayment['refundedAt']}{/if}</td>
|
||||
</tr>
|
||||
{$paymentCount = $paymentCount + 1}
|
||||
{/foreach}
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
{/if}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
{capture "refund_dialog"}
|
||||
{form name="payplugmodule_order_action_form_refund"}
|
||||
{form_hidden_fields form=$form}
|
||||
{if $form_error}
|
||||
<div class="alert alert-danger">{$form_error_message}</div>
|
||||
{/if}
|
||||
{form_field form=$form field='success_url'}
|
||||
<input type="hidden" name="{$name}" value="{url path={navigate to="current"}}"/>
|
||||
{/form_field}
|
||||
{form_field form=$form field="order_id"}
|
||||
<input type="hidden" name="{$name}" value="{$order_id}">
|
||||
{/form_field}
|
||||
{form_field form=$form field="refund_amount"}
|
||||
<input id="refund_amount" type="hidden" name="{$name}" value="{$orderTotalAmount}">
|
||||
{/form_field}
|
||||
{/form}
|
||||
{/capture}
|
||||
|
||||
{include
|
||||
file = "includes/generic-confirm-dialog.html"
|
||||
|
||||
dialog_id = "order_refund_dialog"
|
||||
dialog_title = {intl l="Refund order" d="payplugmodule.bo.default"}
|
||||
dialog_message = {intl l="Do you really want to refund this order ?" d="payplugmodule.bo.default"}
|
||||
|
||||
form_method = "POST"
|
||||
form_action = {url path='/admin/payplugmodule/order/refund'}
|
||||
form_content = {$smarty.capture.refund_dialog nofilter}
|
||||
}
|
||||
|
||||
{capture "capture_dialog"}
|
||||
{form name="payplugmodule_order_action_form"}
|
||||
{form_hidden_fields form=$form}
|
||||
{if $form_error}
|
||||
<div class="alert alert-danger">{$form_error_message}</div>
|
||||
{/if}
|
||||
{form_field form=$form field='success_url'}
|
||||
<input type="hidden" name="{$name}" value="{url path={navigate to="current"}}"/>
|
||||
{/form_field}
|
||||
{form_field form=$form field="order_id"}
|
||||
<input type="hidden" name="{$name}" value="{$order_id}">
|
||||
{/form_field}
|
||||
{/form}
|
||||
{/capture}
|
||||
|
||||
{include
|
||||
file = "includes/generic-confirm-dialog.html"
|
||||
|
||||
dialog_id = "order_capture_dialog"
|
||||
dialog_title = {intl l="Capture order" d="payplugmodule.bo.default"}
|
||||
dialog_message = {intl l="Do you really want to capture this order ?" d="payplugmodule.bo.default"}
|
||||
|
||||
form_method = "POST"
|
||||
form_action = {url path='/admin/payplugmodule/order/capture'}
|
||||
form_content = {$smarty.capture.capture_dialog nofilter}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
var inputAmountRefund = $('#input_amount_refund');
|
||||
var maxAmountRefund = parseFloat(inputAmountRefund.attr('max'));
|
||||
|
||||
$("#quick_select_amount_refund").change(function (e) {
|
||||
var amountToRefund = 0;
|
||||
var selected = $(e.target).val();
|
||||
|
||||
if (null !== selected) {
|
||||
amountToRefund = selected.reduce(function (a, c) {
|
||||
return parseFloat(a) + parseFloat(c);
|
||||
});
|
||||
}
|
||||
|
||||
amountToRefund = amountToRefund > maxAmountRefund ? maxAmountRefund : amountToRefund;
|
||||
inputAmountRefund.val(amountToRefund).trigger('change');
|
||||
});
|
||||
|
||||
inputAmountRefund.change(function (e) {
|
||||
var amountToRefund = $(e.target).val() > maxAmountRefund ? maxAmountRefund : $(e.target).val();
|
||||
$("#refund_amount").val(amountToRefund);
|
||||
});
|
||||
@@ -0,0 +1,8 @@
|
||||
{form_field form=$form field='pay_plug_multi_payment'}
|
||||
<p>
|
||||
<input id="{$name}" type="checkbox" name="{$name}" value="1">
|
||||
<label for="{$name}">{intl l='Pay in %n times without fees.' n={$nTimes} d='payplugmodule.fo.default'}</label>
|
||||
<br>
|
||||
{intl l='You will be asked to save your payment card data.' n={url path='/payplug/card/delete'} d='payplugmodule.fo.default'}
|
||||
</p>
|
||||
{/form_field}
|
||||
@@ -0,0 +1,6 @@
|
||||
<p><strong>{intl l='One click payment is available !' d='payplugmodule.fo.default'}</strong></p>
|
||||
<p>
|
||||
{intl l='A payment card ending by %last4 has been previously saved at your request. Payment for your order will be made immediately after clicking the "Next Step" button.' last4=$last4 d='payplugmodule.fo.default'}
|
||||
<br>
|
||||
{intl l='To clear your payment card details, <a href="%url">please click here</a>' url={url path='/payplug/card/delete'} d='payplugmodule.fo.default'}.
|
||||
</p>
|
||||
@@ -0,0 +1,34 @@
|
||||
<script type="text/javascript" src="https://api.payplug.com/js/1/form.latest.js"></script>
|
||||
|
||||
<script>
|
||||
var payPlugModuleId = '{$payPlugModuleId}';
|
||||
|
||||
{literal}
|
||||
var form = document.getElementById('form-cart-payment');
|
||||
form.addEventListener('submit', function (event) {
|
||||
var payPlugRadio = $('#payment_'+payPlugModuleId);
|
||||
if(payPlugRadio.is(':checked')) {
|
||||
event.preventDefault();
|
||||
|
||||
var form = $(this);
|
||||
var url = form.attr('action');
|
||||
$.ajax({
|
||||
type: "POST",
|
||||
url: url,
|
||||
data: form.serialize(),
|
||||
}).success(function (data) {
|
||||
if (true === data.forceRedirect) {
|
||||
window.location.replace(data.paymentUrl);
|
||||
} else {
|
||||
Payplug.showPayment(data.paymentUrl);
|
||||
}
|
||||
}).fail(function (data) {
|
||||
var payPlugLi = payPlugRadio.parent().parent();
|
||||
console.log(payPlugLi);
|
||||
console.log(data.responseJSON.error);
|
||||
payPlugLi.prepend('<div class="alert alert-danger">Error : '+data.responseJSON.error+'</div>');
|
||||
})
|
||||
}
|
||||
});
|
||||
{/literal}
|
||||
</script>
|
||||
50
local/modules/Recettes/Config/config.xml
Normal file
50
local/modules/Recettes/Config/config.xml
Normal file
@@ -0,0 +1,50 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
|
||||
<config xmlns="http://thelia.net/schema/dic/config"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://thelia.net/schema/dic/config http://thelia.net/schema/dic/config/thelia-1.0.xsd">
|
||||
|
||||
<loops>
|
||||
<!-- sample definition
|
||||
<loop name="MySuperLoop" class="Recettes\Loop\MySuperLoop" />
|
||||
-->
|
||||
</loops>
|
||||
|
||||
<forms>
|
||||
<!--
|
||||
<form name="MyFormName" class="Recettes\Form\MySuperForm" />
|
||||
-->
|
||||
</forms>
|
||||
|
||||
<commands>
|
||||
<!--
|
||||
<command class="Recettes\Command\MySuperCommand" />
|
||||
-->
|
||||
</commands>
|
||||
|
||||
<!--
|
||||
<services>
|
||||
|
||||
</services>
|
||||
-->
|
||||
|
||||
<!--
|
||||
<hooks>
|
||||
<hook id="recettes.hook" class="Recettes\Hook\MySuperHook">
|
||||
<tag name="hook.event_listener" event="main.body.bottom" type="front|back|pdf|email" method="onMainBodyBottom" />
|
||||
</hook>
|
||||
</hooks>
|
||||
-->
|
||||
|
||||
<!--
|
||||
<exports>
|
||||
|
||||
</exports>
|
||||
-->
|
||||
|
||||
<!--
|
||||
<imports>
|
||||
|
||||
</imports>
|
||||
-->
|
||||
</config>
|
||||
50
local/modules/Recettes/Config/config_dev.xml
Normal file
50
local/modules/Recettes/Config/config_dev.xml
Normal file
@@ -0,0 +1,50 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
|
||||
<config xmlns="http://thelia.net/schema/dic/config"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://thelia.net/schema/dic/config http://thelia.net/schema/dic/config/thelia-1.0.xsd">
|
||||
|
||||
<loops>
|
||||
<!-- sample definition
|
||||
<loop name="MySuperLoop" class="Recettes\Loop\MySuperLoop" />
|
||||
-->
|
||||
</loops>
|
||||
|
||||
<forms>
|
||||
<!--
|
||||
<form name="MyFormName" class="Recettes\Form\MySuperForm" />
|
||||
-->
|
||||
</forms>
|
||||
|
||||
<commands>
|
||||
<!--
|
||||
<command class="Recettes\Command\MySuperCommand" />
|
||||
-->
|
||||
</commands>
|
||||
|
||||
<!--
|
||||
<services>
|
||||
|
||||
</services>
|
||||
-->
|
||||
|
||||
<!--
|
||||
<hooks>
|
||||
<hook id="recettes.hook" class="Recettes\Hook\MySuperHook">
|
||||
<tag name="hook.event_listener" event="main.body.bottom" type="front|back|pdf|email" method="onMainBodyBottom" />
|
||||
</hook>
|
||||
</hooks>
|
||||
-->
|
||||
|
||||
<!--
|
||||
<exports>
|
||||
|
||||
</exports>
|
||||
-->
|
||||
|
||||
<!--
|
||||
<imports>
|
||||
|
||||
</imports>
|
||||
-->
|
||||
</config>
|
||||
50
local/modules/Recettes/Config/config_prod.xml
Normal file
50
local/modules/Recettes/Config/config_prod.xml
Normal file
@@ -0,0 +1,50 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
|
||||
<config xmlns="http://thelia.net/schema/dic/config"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://thelia.net/schema/dic/config http://thelia.net/schema/dic/config/thelia-1.0.xsd">
|
||||
|
||||
<loops>
|
||||
<!-- sample definition
|
||||
<loop name="MySuperLoop" class="Recettes\Loop\MySuperLoop" />
|
||||
-->
|
||||
</loops>
|
||||
|
||||
<forms>
|
||||
<!--
|
||||
<form name="MyFormName" class="Recettes\Form\MySuperForm" />
|
||||
-->
|
||||
</forms>
|
||||
|
||||
<commands>
|
||||
<!--
|
||||
<command class="Recettes\Command\MySuperCommand" />
|
||||
-->
|
||||
</commands>
|
||||
|
||||
<!--
|
||||
<services>
|
||||
|
||||
</services>
|
||||
-->
|
||||
|
||||
<!--
|
||||
<hooks>
|
||||
<hook id="recettes.hook" class="Recettes\Hook\MySuperHook">
|
||||
<tag name="hook.event_listener" event="main.body.bottom" type="front|back|pdf|email" method="onMainBodyBottom" />
|
||||
</hook>
|
||||
</hooks>
|
||||
-->
|
||||
|
||||
<!--
|
||||
<exports>
|
||||
|
||||
</exports>
|
||||
-->
|
||||
|
||||
<!--
|
||||
<imports>
|
||||
|
||||
</imports>
|
||||
-->
|
||||
</config>
|
||||
50
local/modules/Recettes/Config/config_test.xml
Normal file
50
local/modules/Recettes/Config/config_test.xml
Normal file
@@ -0,0 +1,50 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
|
||||
<config xmlns="http://thelia.net/schema/dic/config"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://thelia.net/schema/dic/config http://thelia.net/schema/dic/config/thelia-1.0.xsd">
|
||||
|
||||
<loops>
|
||||
<!-- sample definition
|
||||
<loop name="MySuperLoop" class="Recettes\Loop\MySuperLoop" />
|
||||
-->
|
||||
</loops>
|
||||
|
||||
<forms>
|
||||
<!--
|
||||
<form name="MyFormName" class="Recettes\Form\MySuperForm" />
|
||||
-->
|
||||
</forms>
|
||||
|
||||
<commands>
|
||||
<!--
|
||||
<command class="Recettes\Command\MySuperCommand" />
|
||||
-->
|
||||
</commands>
|
||||
|
||||
<!--
|
||||
<services>
|
||||
|
||||
</services>
|
||||
-->
|
||||
|
||||
<!--
|
||||
<hooks>
|
||||
<hook id="recettes.hook" class="Recettes\Hook\MySuperHook">
|
||||
<tag name="hook.event_listener" event="main.body.bottom" type="front|back|pdf|email" method="onMainBodyBottom" />
|
||||
</hook>
|
||||
</hooks>
|
||||
-->
|
||||
|
||||
<!--
|
||||
<exports>
|
||||
|
||||
</exports>
|
||||
-->
|
||||
|
||||
<!--
|
||||
<imports>
|
||||
|
||||
</imports>
|
||||
-->
|
||||
</config>
|
||||
43
local/modules/Recettes/Config/module.xml
Normal file
43
local/modules/Recettes/Config/module.xml
Normal file
@@ -0,0 +1,43 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module xmlns="http://thelia.net/schema/dic/module"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://thelia.net/schema/dic/module http://thelia.net/schema/dic/module/module-2_2.xsd">
|
||||
<fullnamespace>Recettes\Recettes</fullnamespace>
|
||||
<descriptive locale="en_US">
|
||||
<title>Automatically generated module - please update module.xml file</title>
|
||||
<!--
|
||||
<subtitle></subtitle>
|
||||
<description></description>
|
||||
<postscriptum></postscriptum>
|
||||
-->
|
||||
</descriptive>
|
||||
<descriptive locale="fr_FR">
|
||||
<title>Module généré automatiquement - éditez le fichier module.xml</title>
|
||||
</descriptive>
|
||||
<!-- <logo></logo> -->
|
||||
<!--<images-folder>images</images-folder>-->
|
||||
<languages>
|
||||
<language>en_US</language>
|
||||
<language>fr_FR</language>
|
||||
</languages>
|
||||
<version></version>
|
||||
<authors>
|
||||
<author>
|
||||
<name></name>
|
||||
<email></email>
|
||||
</author>
|
||||
</authors>
|
||||
<type>classic</type>
|
||||
<!--
|
||||
module dependencies
|
||||
<required>
|
||||
<module version=">=0.1">Front</module>
|
||||
<module version="~1.0">HookCart</module>
|
||||
<module version=">0.2">HookSearch</module>
|
||||
</required>
|
||||
-->
|
||||
<thelia>2.4.3</thelia>
|
||||
<stability>other</stability>
|
||||
<mandatory>0</mandatory>
|
||||
<hidden>0</hidden>
|
||||
</module>
|
||||
31
local/modules/Recettes/Config/routing.xml
Normal file
31
local/modules/Recettes/Config/routing.xml
Normal file
@@ -0,0 +1,31 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
|
||||
<routes xmlns="http://symfony.com/schema/routing"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://symfony.com/schema/routing http://symfony.com/schema/routing/routing-1.0.xsd">
|
||||
|
||||
<!--
|
||||
|
||||
if a /admin/module/recettes/ route is provided, a "Configuration" button will be displayed
|
||||
for the module in the module list. Clicking this button will invoke this route.
|
||||
|
||||
<route id="my_route_id" path="/admin/module/recettes">
|
||||
<default key="_controller">Recettes\Full\Class\Name\Of\YourConfigurationController::methodName</default>
|
||||
</route>
|
||||
|
||||
<route id="my_route_id" path="/admin/module/recettes/route-name">
|
||||
<default key="_controller">Recettes\Full\Class\Name\Of\YourAdminController::methodName</default>
|
||||
</route>
|
||||
|
||||
<route id="my_route_id" path="/my/route/name">
|
||||
<default key="_controller">Recettes\Full\Class\Name\Of\YourOtherController::methodName</default>
|
||||
</route>
|
||||
|
||||
...add as many routes as required.
|
||||
|
||||
<route>
|
||||
...
|
||||
</route>
|
||||
-->
|
||||
|
||||
</routes>
|
||||
25
local/modules/Recettes/Config/schema.xml
Normal file
25
local/modules/Recettes/Config/schema.xml
Normal file
@@ -0,0 +1,25 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<database defaultIdMethod="native" name="thelia"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:noNamespaceSchemaLocation="../../../core/vendor/thelia/propel/resources/xsd/database.xsd" >
|
||||
<!--
|
||||
See propel documentation on http://propelorm.org for all information about schema file
|
||||
|
||||
<table name="product_rel" namespace="Recettes\Model">
|
||||
<column autoIncrement="true" name="id" primaryKey="true" required="true" type="INTEGER" />
|
||||
<column defaultValue="0" name="visible" required="true" type="TINYINT" />
|
||||
<column defaultValue="0" name="position" required="true" type="INTEGER" />
|
||||
<column name="title" size="255" type="VARCHAR" />
|
||||
<column name="description" type="CLOB" />
|
||||
<column name="chapo" type="LONGVARCHAR" />
|
||||
<column name="postscriptum" type="LONGVARCHAR" />
|
||||
<foreign-key foreignTable="product" name="fk_product_id" onDelete="CASCADE" onUpdate="RESTRICT">
|
||||
<reference foreign="id" local="product_id" />
|
||||
</foreign-key>
|
||||
<behavior name="timestampable" />
|
||||
<behavior name="i18n">
|
||||
<parameter name="i18n_columns" value="title, description, chapo, postscriptum" />
|
||||
</behavior>
|
||||
</table>
|
||||
-->
|
||||
</database>
|
||||
4
local/modules/Recettes/I18n/en_US.php
Normal file
4
local/modules/Recettes/I18n/en_US.php
Normal file
@@ -0,0 +1,4 @@
|
||||
<?php
|
||||
return array(
|
||||
// 'an english string' => 'The displayed english string',
|
||||
);
|
||||
4
local/modules/Recettes/I18n/fr_FR.php
Normal file
4
local/modules/Recettes/I18n/fr_FR.php
Normal file
@@ -0,0 +1,4 @@
|
||||
<?php
|
||||
return array(
|
||||
// 'an english string' => 'La traduction française de la chaine',
|
||||
);
|
||||
55
local/modules/Recettes/Readme.md
Normal file
55
local/modules/Recettes/Readme.md
Normal file
@@ -0,0 +1,55 @@
|
||||
# Recettes
|
||||
|
||||
Add a short description here. You can also add a screenshot if needed.
|
||||
|
||||
## Installation
|
||||
|
||||
### Manually
|
||||
|
||||
* Copy the module into ```<thelia_root>/local/modules/``` directory and be sure that the name of the module is Recettes.
|
||||
* Activate it in your thelia administration panel
|
||||
|
||||
### Composer
|
||||
|
||||
Add it in your main thelia composer.json file
|
||||
|
||||
```
|
||||
composer require your-vendor/recettes-module:~1.0
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
Explain here how to use your module, how to configure it, etc.
|
||||
|
||||
## Hook
|
||||
|
||||
If your module use one or more hook, fill this part. Explain which hooks are used.
|
||||
|
||||
|
||||
## Loop
|
||||
|
||||
If your module declare one or more loop, describe them here like this :
|
||||
|
||||
[loop name]
|
||||
|
||||
### Input arguments
|
||||
|
||||
|Argument |Description |
|
||||
|--- |--- |
|
||||
|**arg1** | describe arg1 with an exemple. |
|
||||
|**arg2** | describe arg2 with an exemple. |
|
||||
|
||||
### Output arguments
|
||||
|
||||
|Variable |Description |
|
||||
|--- |--- |
|
||||
|$VAR1 | describe $VAR1 variable |
|
||||
|$VAR2 | describe $VAR2 variable |
|
||||
|
||||
### Exemple
|
||||
|
||||
Add a complete exemple of your loop
|
||||
|
||||
## Other ?
|
||||
|
||||
If you have other think to put, feel free to complete your readme as you want.
|
||||
28
local/modules/Recettes/Recettes.php
Normal file
28
local/modules/Recettes/Recettes.php
Normal file
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
/*************************************************************************************/
|
||||
/* This file is part of the Thelia package. */
|
||||
/* */
|
||||
/* Copyright (c) OpenStudio */
|
||||
/* email : dev@thelia.net */
|
||||
/* web : http://www.thelia.net */
|
||||
/* */
|
||||
/* For the full copyright and license information, please view the LICENSE.txt */
|
||||
/* file that was distributed with this source code. */
|
||||
/*************************************************************************************/
|
||||
|
||||
namespace Recettes;
|
||||
|
||||
use Thelia\Module\BaseModule;
|
||||
|
||||
class Recettes extends BaseModule
|
||||
{
|
||||
/** @var string */
|
||||
const DOMAIN_NAME = 'recettes';
|
||||
|
||||
/*
|
||||
* You may now override BaseModuleInterface methods, such as:
|
||||
* install, destroy, preActivation, postActivation, preDeactivation, postDeactivation
|
||||
*
|
||||
* Have fun !
|
||||
*/
|
||||
}
|
||||
12
local/modules/Recettes/composer.json
Normal file
12
local/modules/Recettes/composer.json
Normal file
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"name": "your-vendor/recettes-module",
|
||||
"description": "Recettes module for Thelia",
|
||||
"license": "LGPL-3.0-or-later",
|
||||
"type": "thelia-module",
|
||||
"require": {
|
||||
"thelia/installer": "~1.1"
|
||||
},
|
||||
"extra": {
|
||||
"installer-name": "Recettes"
|
||||
}
|
||||
}
|
||||
10
local/modules/Recettes/templates/backOffice/recette.html
Normal file
10
local/modules/Recettes/templates/backOffice/recette.html
Normal file
@@ -0,0 +1,10 @@
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
{render_form_field field='titre'}
|
||||
{render_form_field field='difficulte'}
|
||||
{render_form_field field='temps_preparation'}
|
||||
{render_form_field field='temps_cuisson'}
|
||||
{render_form_field field='ingredients'}
|
||||
{render_form_field field="description" extra_class="wysiwyg"}
|
||||
</div>
|
||||
</div>
|
||||
Reference in New Issue
Block a user