Inital commit
363
local/modules/Atos/Atos.php
Normal file
@@ -0,0 +1,363 @@
|
||||
<?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 Atos;
|
||||
|
||||
use Atos\Model\AtosCurrencyQuery;
|
||||
use Propel\Runtime\ActiveQuery\Criteria;
|
||||
use Propel\Runtime\Connection\ConnectionInterface;
|
||||
use Symfony\Component\Routing\Router;
|
||||
use Thelia\Core\HttpFoundation\Response;
|
||||
use Thelia\Core\Template\ParserInterface;
|
||||
use Thelia\Core\Translation\Translator;
|
||||
use Thelia\Install\Database;
|
||||
use Thelia\Log\Tlog;
|
||||
use Thelia\Model\Config;
|
||||
use Thelia\Model\ConfigQuery;
|
||||
use Thelia\Model\Message;
|
||||
use Thelia\Model\MessageQuery;
|
||||
use Thelia\Model\Order;
|
||||
use Thelia\Module\AbstractPaymentModule;
|
||||
use Thelia\Tools\URL;
|
||||
|
||||
class Atos extends AbstractPaymentModule
|
||||
{
|
||||
const MODULE_DOMAIN = 'atos';
|
||||
|
||||
/**
|
||||
* The confirmation message identifier
|
||||
*/
|
||||
const CONFIRMATION_MESSAGE_NAME = 'atos_payment_confirmation';
|
||||
|
||||
private $parameters;
|
||||
|
||||
public function postActivation(ConnectionInterface $con = null)
|
||||
{
|
||||
// Setup some default values
|
||||
if (null === Atos::getConfigValue('atos_merchantId', null)) {
|
||||
Atos::setConfigValue('atos_transactionId', 1);
|
||||
Atos::setConfigValue('minimum_amount', 0);
|
||||
Atos::setConfigValue('maximum_amount', 0);
|
||||
Atos::setConfigValue('send_payment_confirmation_message', 1);
|
||||
}
|
||||
|
||||
// Try to chmod binaries if they're not executables
|
||||
$binFile = Atos::getBinDirectory() . 'request';
|
||||
if (! is_executable($binFile)) {
|
||||
@chmod($binFile, 0755);
|
||||
}
|
||||
|
||||
$binFile = Atos::getBinDirectory() . 'response';
|
||||
if (! is_executable($binFile)) {
|
||||
@chmod($binFile, 0755);
|
||||
}
|
||||
|
||||
$database = new Database($con);
|
||||
|
||||
$database->insertSql(null, array(
|
||||
__DIR__ . DS . 'Config'.DS.'thelia.sql'
|
||||
));
|
||||
|
||||
// Create payment confirmation message from templates, if not already defined
|
||||
$email_templates_dir = __DIR__.DS.'I18n'.DS.'email-templates'.DS;
|
||||
|
||||
if (null === MessageQuery::create()->findOneByName(Atos::CONFIRMATION_MESSAGE_NAME)) {
|
||||
$message = new Message();
|
||||
|
||||
$message
|
||||
->setName(Atos::CONFIRMATION_MESSAGE_NAME)
|
||||
->setHtmlTemplateFileName('atos-payment-confirmation.html')
|
||||
->setTextTemplateFileName('atos-payment-confirmation.txt')
|
||||
->setLocale('en_US')
|
||||
->setTitle('Atos payment confirmation')
|
||||
->setSubject('Payment of order {$order_ref}')
|
||||
->setLocale('fr_FR')
|
||||
->setTitle('Confirmation de paiement par Atos')
|
||||
->setSubject('Confirmation du paiement de votre commande {$order_ref}')
|
||||
->save()
|
||||
;
|
||||
}
|
||||
|
||||
$this->replacePath();
|
||||
}
|
||||
|
||||
public function update($currentVersion, $newVersion, ConnectionInterface $con = null)
|
||||
{
|
||||
// Migrate old configuration
|
||||
if (null === Atos::getConfigValue('atos_merchantId', null)) {
|
||||
if (null !== $atosConfigs = ConfigQuery::create()->filterByName('atos_%', Criteria::LIKE)->find()) {
|
||||
/** @var Config $atosConfig */
|
||||
foreach ($atosConfigs as $atosConfig) {
|
||||
Atos::setConfigValue($atosConfig->getName(), $atosConfig->getValue());
|
||||
|
||||
$atosConfig->delete($con);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
parent::update($currentVersion, $newVersion, $con);
|
||||
}
|
||||
|
||||
public function destroy(ConnectionInterface $con = null, $deleteModuleData = false)
|
||||
{
|
||||
if ($deleteModuleData) {
|
||||
$database = new Database($con);
|
||||
|
||||
$database->execute('drop table `atos_currency`');
|
||||
|
||||
MessageQuery::create()->findOneByName(Atos::CONFIRMATION_MESSAGE_NAME)->delete();
|
||||
}
|
||||
}
|
||||
|
||||
protected function replacePath()
|
||||
{
|
||||
$pathfile = $this->getPathfilePath();
|
||||
|
||||
$pathfileContent = @file_get_contents($pathfile . '.dist');
|
||||
|
||||
if ($pathfileContent) {
|
||||
$pathfileContent = str_replace('__PATH__', __DIR__, $pathfileContent);
|
||||
|
||||
if (! file_put_contents($this->getConfigDirectory() . 'pathfile', $pathfileContent)) {
|
||||
throw new \RuntimeException(
|
||||
Translator::getInstance()->trans(
|
||||
'File %file must be writable, please check Atos/Config directory permissions.',
|
||||
[ '%file' => 'pathfile' ],
|
||||
Atos::MODULE_DOMAIN
|
||||
)
|
||||
);
|
||||
}
|
||||
} else {
|
||||
throw new \RuntimeException(
|
||||
Translator::getInstance()->trans(
|
||||
'Failed to read the %file file. Please check file and directory permissions.',
|
||||
[ '%file' => $pathfile . '.dist' ],
|
||||
Atos::MODULE_DOMAIN
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $key atos key parameter
|
||||
* @param string $value parameter value
|
||||
* @return $this
|
||||
*/
|
||||
protected function addParam($key, $value)
|
||||
{
|
||||
$this->parameters = sprintf("%s %s=%s", $this->parameters, $key, $value);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
protected function getParameters()
|
||||
{
|
||||
return trim($this->parameters);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* generate a transaction id for atos solution
|
||||
*
|
||||
* @return int|mixed
|
||||
*/
|
||||
private function generateTransactionID()
|
||||
{
|
||||
$transId = Atos::getConfigValue('atos_transactionId', 1);
|
||||
|
||||
$transId = 1 + intval($transId);
|
||||
|
||||
if (strlen($transId) > 6) {
|
||||
$transId = 1;
|
||||
}
|
||||
|
||||
Atos::setConfigValue('atos_transactionId', $transId);
|
||||
|
||||
return sprintf("%06d", $transId);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* Method used by payment gateway.
|
||||
*
|
||||
* If this method return a \Thelia\Core\HttpFoundation\Response instance, this response is send to the
|
||||
* browser.
|
||||
*
|
||||
* In many cases, it's necessary to send a form to the payment gateway.
|
||||
* On your response you can return this form already completed, ready to be sent
|
||||
*
|
||||
* @param \Thelia\Model\Order $order processed order
|
||||
* @return null|\Thelia\Core\HttpFoundation\Response
|
||||
*/
|
||||
public function pay(Order $order)
|
||||
{
|
||||
$pathBin = Atos::getBinDirectory() .'request';
|
||||
|
||||
$atosCurrency = AtosCurrencyQuery::create()->findPk(
|
||||
$order->getCurrency()->getCode()
|
||||
);
|
||||
|
||||
if (null == $atosCurrency) {
|
||||
throw new \InvalidArgumentException(
|
||||
sprintf(
|
||||
"Atos does not supprot this currency : %s",
|
||||
$order->getCurrency()->getCode()
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
$amount = $order->getTotalAmount();
|
||||
$amount = number_format($amount, $atosCurrency->getDecimals(), '', '');
|
||||
|
||||
$transactionId = $this->generateTransactionID();
|
||||
|
||||
$order->setTransactionRef($transactionId)->save();
|
||||
|
||||
/** @var Router $router */
|
||||
$router = $this->getContainer()->get('router.atos');
|
||||
|
||||
$this
|
||||
->addParam('pathfile', Atos::getPathfilePath())
|
||||
->addParam('merchant_id', Atos::getConfigValue('atos_merchantId'))
|
||||
->addParam('customer_email', $order->getCustomer()->getEmail())
|
||||
->addParam('currency_code', $atosCurrency->getAtosCode())
|
||||
->addParam('amount', $amount)
|
||||
->addParam('language', $order->getLang()->getCode())
|
||||
->addParam('transaction_id', $transactionId)
|
||||
->addParam('order_id', $order->getId())
|
||||
->addParam('automatic_response_url', URL::getInstance()->absoluteUrl($router->generate('atos.payment.confirmation')))
|
||||
->addParam('cancel_return_url', URL::getInstance()->absoluteUrl($router->generate('atos.payment.cancel', [ 'orderId' => $order->getId() ])))
|
||||
->addParam('normal_return_url', $this->getPaymentSuccessPageUrl($order->getId()))
|
||||
;
|
||||
|
||||
$encrypt = exec(sprintf("%s %s", $pathBin, $this->getParameters()));
|
||||
|
||||
if (! empty($encrypt)) {
|
||||
$datas = explode('!', $encrypt);
|
||||
|
||||
if ($datas[1] == '' && $datas[2] == '') {
|
||||
throw new \RuntimeException(
|
||||
Translator::getInstance()->trans('Request binary not found in "%path"', ['%path' => $pathBin])
|
||||
);
|
||||
} elseif ($datas[1] != 0) {
|
||||
throw new \RuntimeException($datas[2]);
|
||||
} else {
|
||||
/** @var ParserInterface $parser */
|
||||
$parser = $this->getContainer()->get('thelia.parser');
|
||||
|
||||
$parser->setTemplateDefinition(
|
||||
$parser->getTemplateHelper()->getActiveFrontTemplate(),
|
||||
true
|
||||
);
|
||||
|
||||
$content = $parser->render('atos/payment.html', [
|
||||
'site_name' => self::getConfigValue('store_name'),
|
||||
'form' => $datas[3],
|
||||
'order_id' => $order->getId()
|
||||
]);
|
||||
|
||||
return Response::create($content);
|
||||
}
|
||||
} else {
|
||||
throw new \RuntimeException(
|
||||
Translator::getInstance()->trans(
|
||||
'Empty response recevied from Atos binary "%path". Please check path and permissions.',
|
||||
['%path' => $pathBin],
|
||||
Atos::MODULE_DOMAIN
|
||||
)
|
||||
);
|
||||
// FIXME : show something to the customer
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return boolean true to allow usage of this payment module, false otherwise.
|
||||
*/
|
||||
public function isValidPayment()
|
||||
{
|
||||
$valid = false;
|
||||
|
||||
// Check config files
|
||||
$parmcomFile = Atos::getConfigDirectory() . 'parmcom.' . Atos::getConfigValue('atos_merchantId', '0');
|
||||
$certifFile = Atos::getConfigDirectory() . 'certif.fr.' . Atos::getConfigValue('atos_merchantId', '0');
|
||||
|
||||
if (is_readable($parmcomFile) && is_readable($certifFile)) {
|
||||
$mode = Atos::getConfigValue('atos_mode', false);
|
||||
|
||||
// If we're in test mode, do not display Payzen on the front office, except for allowed IP addresses.
|
||||
if ('TEST' == $mode) {
|
||||
$raw_ips = explode("\n", Atos::getConfigValue('atos_allowed_ip_list', ''));
|
||||
|
||||
$allowed_client_ips = array();
|
||||
|
||||
foreach ($raw_ips as $ip) {
|
||||
$allowed_client_ips[] = trim($ip);
|
||||
}
|
||||
|
||||
$client_ip = $this->getRequest()->getClientIp();
|
||||
|
||||
$valid = in_array($client_ip, $allowed_client_ips);
|
||||
|
||||
} elseif ('PRODUCTION' == $mode) {
|
||||
$valid = true;
|
||||
}
|
||||
|
||||
if ($valid) {
|
||||
// Check if total order amount is in the module's limits
|
||||
$valid = $this->checkMinMaxAmount();
|
||||
}
|
||||
} else {
|
||||
Tlog::getInstance()->addWarning(
|
||||
Translator::getInstance()->trans(
|
||||
"Atos payment module is nort properly configured. Please check module configuration in your back-office.",
|
||||
[],
|
||||
Atos::MODULE_DOMAIN
|
||||
)
|
||||
);
|
||||
}
|
||||
return $valid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if total order amount is in the module's limits
|
||||
*
|
||||
* @return bool true if the current order total is within the min and max limits
|
||||
*/
|
||||
protected function checkMinMaxAmount()
|
||||
{
|
||||
// Check if total order amount is in the module's limits
|
||||
$order_total = $this->getCurrentOrderTotalAmount();
|
||||
|
||||
$min_amount = Atos::getConfigValue('atos_minimum_amount', 0);
|
||||
$max_amount = Atos::getConfigValue('atos_maximum_amount', 0);
|
||||
|
||||
return
|
||||
$order_total > 0
|
||||
&&
|
||||
($min_amount <= 0 || $order_total >= $min_amount) && ($max_amount <= 0 || $order_total <= $max_amount);
|
||||
}
|
||||
|
||||
public static function getBinDirectory()
|
||||
{
|
||||
return __DIR__ . DS . 'bin' . DS;
|
||||
}
|
||||
|
||||
public static function getConfigDirectory()
|
||||
{
|
||||
return __DIR__ . DS . 'Config' . DS;
|
||||
}
|
||||
|
||||
public static function getPathfilePath()
|
||||
{
|
||||
return Atos::getConfigDirectory() . 'pathfile';
|
||||
}
|
||||
}
|
||||
44
local/modules/Atos/Config/certif.fr.031203376400035
Normal file
@@ -0,0 +1,44 @@
|
||||
GE7vlAm9WMSVdL1BBXmeD2P1ZEWn6muDOdGYOaey91vi8104USqy5IrH4EmBVpbmFA
|
||||
dY2sm0spP7rjwm2YU97L6etVXtmidboXK2uyDGKo3tq1ruDId1vNY5dUPqpT8R1y3L
|
||||
LBa3ujKfrobNukNlLmi614ZqZ95IAg4wLhoAa9eTx7tMHdECYJwaMQdUkpevoFKoQy
|
||||
S3WFBwoltAHgQd3pEjOraOiKS5ZcqCdDtXLOCta3hcRt2JgLFIEhJvcXECIzCqiVhl
|
||||
eJr7kjuACxt8p3OTe8RjOTVLTRbvJiv1VPYRsvAWXggIXEfm75tv1CcaMy2K0GAqoa
|
||||
x92iBrg6fFJlTUIP3vjil7CnjDPo0pgxEaMpOjadKDsmsmsP4eeJEsc1jlVgZ7hP6U
|
||||
EN9PGjuwegkfuvxCKHifmWVhufEunk62uclrUT1ux0XkmNWFm5VxXs6dapzFHgmHnY
|
||||
lxckSHxSRqPLabW8ll1jn0BnH8x4PItAsXQe93YDPK552FsdKuVucDduMdNU9oI2pI
|
||||
bssDMRNkKD7gds6LrBAPNCpmp84mtIyvOqthjgKjH57fLqZ17my03C92ANaOVck1un
|
||||
BwcqZyOwYhxwwmAymGvBLYHYhXc6kyafOrPBpdcnUQ8MmYaBPan8lv6lyLZtWlz7cr
|
||||
HyE9s8dx8NN4RCUrer976qfdzfCTJO4QImKiAWrzKGmQB22YZYuaCnbIAm7EvaPUMc
|
||||
Nsyt1YcUT6RyzLBS2EBkl6jn7l2RTKB6qrWSGTgOfJozF1853AoBXnZN2iZ32fp95b
|
||||
bP0pAKYMptkmXjGIEDdCjvHfoCd1TLb1onywU7H3Xl0M0RAKsKpVw2UZ59MvfzwygA
|
||||
2JZBegSHydBvAA6f7Y7eUJxeEPdR58XTaQljHBA3znO5tl4XAs3bJwvWxxH55ZUOSt
|
||||
uWWJUIxTobE82LNQTxBUiBB6jPIPZNndV0swUHxF0IalwodLYn0EVgKeevzBdectCO
|
||||
EDCxoMxNtwiEHNvEOtlG8HRltxG44jLL4k2bxyJvvs1XV5OlNgwJO4FQftt0wlTYY9
|
||||
xdM9OJ3svb9FzHL9PBDGShOv6ZhxOrMhNxTNf7vK5gtUL1tPvcjzeSbyIWxXNhou15
|
||||
q4o5ZxmqcDJWeblzefVUjtzrMs5PnA5QoMuU7siDnXmh1GbDQsEEW9CIbDXSepHxIZ
|
||||
HC48dhjbmkdlPMorjCBLbHNUJf7eSMxKPyPrOFAhZai0w68AIc9D7ptZJoPEqms64O
|
||||
9lJbdo5ZG0PopS7dmEpcSWWpDFV3jhyJTYCpVCwwaSe4JoxoqcPCMCatFnti7kq5rN
|
||||
4MDogPwrgOVSrjjf3n64uvPPoZFdBqlRJX9GEBslEE6nfPT4jKWhwji2BXifKwWwAG
|
||||
7g6skqXHXcYfJJ876oijteOXINUCUJDMZxdqahTzJMnu0C9FskoOC2lTnZw0zsJ5DF
|
||||
ElXEALjZezEWQu4LkuJXXd2IThyEKLfth1doUHcWN6HJ4UUBR5d0w02IQ6Mxdt3LjB
|
||||
5Ldqqsab7WCwPWKEY6jmFEtscM0GVLXHuQk6jqiKod90ZaQKk5FT7y36a01ES18mB4
|
||||
BycGRfNXDWoqlYGsRCc1XhD8YNMfn8kEVmxyqZyfoKwXoUVAeAAooKAC4HHK7fRKDM
|
||||
144242079835C20C45E69EB347ABBCF77F04B23BF39629A8891035423E3CC386A0
|
||||
7B3C5701C4AD69E9553B26CC0BF5EECFF5870551C600B8F730F5D254BF74A565C6
|
||||
6B4579C390A8DC6qQr1zR6dLlJOiMDbG6OGmKSYrbRLjNxgYF6O0LOphKqjcTtEjC4
|
||||
qRYApJkYmWXLLANZn46w0I65L63PlBVrpYPSvFAu25aUMaSwcELNUKcpgFq5tsI1wG
|
||||
112A59107EB88144C8A7336C5487503B02EF1E0937AB588DC4E42D35BC8567C0EA
|
||||
181F19D1F3D8D3C19626080F3D3DA7901B63475590DD907AE1eFcB1ZxNnOK4rRiC
|
||||
YhZYW3QiL6OW9eXqQr1zR6dLlJOiMDbG6OGmKSYrbRLjNxgYF6O0LOphKqjcTtEjC4
|
||||
qRYApJkYmWXLLANZn46w0I65L63PlBVrpYPSvFAu25aUMaSwcELNUKcpgFq5tsI1wG
|
||||
144242079835C20C45E69EB347ABBCF77F04B23BF39629A8891035423E3CC386A0
|
||||
7B3C5701C4AD69E9553B26CC0BF5EECFF5870551C600B8F730F5D254BF74A565C6
|
||||
6B4579C390A8DC6qQr1zR6dLlJOiMDbG6OGmKSYrbRLjNxgYF6O0LOphKqjcTtEjC4
|
||||
qRYApJkYmWXLLANZn46w0I65L63PlBVrpYPSvFAu25aUMaSwcELNUKcpgFq5tsI1wG
|
||||
1127349E4948198B92E77303D3BF9D9E7C0D37B60245BB789F425406ED1ADC2EA7
|
||||
BAED72A82D8300C138275636798737F202F376F40453FA7B01eFcB1ZxNnOK4rRiC
|
||||
YhZYW3QiL6OW9eXqQr1zR6dLlJOiMDbG6OGmKSYrbRLjNxgYF6O0LOphKqjcTtEjC4
|
||||
qRYApJkYmWXLLANZn46w0I65L63PlBVrpYPSvFAu25aUMaSwcELNUKcpgFq5tsI1wG
|
||||
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
SIPSATIS_SCLERIVEINSTERIVEIN,26/08/2014,V4,MERCANET,PROD++++++++++
|
||||
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++END
|
||||
0
local/modules/Atos/Config/certif.fr.dist
Normal file
22
local/modules/Atos/Config/config.xml
Normal file
@@ -0,0 +1,22 @@
|
||||
<?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="atos_configuration" class="Atos\Form\ConfigForm" />
|
||||
</forms>
|
||||
|
||||
<services>
|
||||
<service id="atos.confirmation.email" class="Atos\EventListeners\SendConfirmationEmail" scope="request">
|
||||
<argument type="service" id="mailer"/>
|
||||
<tag name="kernel.event_subscriber"/>
|
||||
</service>
|
||||
</services>
|
||||
|
||||
<hooks>
|
||||
<hook id="atos.configuration.hook" class="Atos\Hook\HookManager" scope="request">
|
||||
<tag name="hook.event_listener" event="module.configuration" type="back" method="onModuleConfigure" />
|
||||
</hook>
|
||||
</hooks>
|
||||
</config>
|
||||
18
local/modules/Atos/Config/module.xml
Normal file
@@ -0,0 +1,18 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module>
|
||||
<fullnamespace>Atos\Atos</fullnamespace>
|
||||
<descriptive locale="en_US">
|
||||
<title>Atos-SIPS payment module</title>
|
||||
</descriptive>
|
||||
<descriptive locale="fr_FR">
|
||||
<title>Module de paiement Atos-SIPS</title>
|
||||
</descriptive>
|
||||
<version>1.2.1</version>
|
||||
<author>
|
||||
<name>Manuel Raynaud, Franck Allimant</name>
|
||||
<email>manu@thelia.net, franck@cqfdev.fr</email>
|
||||
</author>
|
||||
<type>payment</type>
|
||||
<thelia>2.1.0</thelia>
|
||||
<stability>prod</stability>
|
||||
</module>
|
||||
16
local/modules/Atos/Config/parmcom.031203376400035
Normal file
@@ -0,0 +1,16 @@
|
||||
###############################################################################
|
||||
#
|
||||
# Fichier des parametres du commercant
|
||||
#
|
||||
# Remarque : Ce fichier parametre est sous la responsabilite du
|
||||
# commercant
|
||||
#
|
||||
###############################################################################
|
||||
|
||||
# Logo du commercant (il apparait en entete sur les pages de paiement)
|
||||
|
||||
# ADVERT!merchant.gif!
|
||||
|
||||
# END OF FILE
|
||||
|
||||
|
||||
39
local/modules/Atos/Config/parmcom.atos
Normal file
@@ -0,0 +1,39 @@
|
||||
# couleur du fond d'ecran (blanc)
|
||||
BGCOLOR!ffffff!
|
||||
|
||||
# Mode d'affichage des blocs de paiment
|
||||
BLOCK_ALIGN!center!
|
||||
|
||||
# Ordre d'affichage des blocs de paiement
|
||||
BLOCK_ORDER!1,2,3,4,5,6,7,8!
|
||||
|
||||
# Mode de securite
|
||||
CONDITION!SSL!
|
||||
|
||||
# flag d'edition des libelles des blocs de paiement
|
||||
HEADER_FLAG!yes!
|
||||
|
||||
# Code langage de l'acheteur (fr=francais)
|
||||
LANGUAGE!fr!
|
||||
|
||||
# Logo ATOS paiement
|
||||
#LOGO!logo.gif!
|
||||
|
||||
# Logo Banque Populaire
|
||||
#LOGO2!logo.gif!
|
||||
|
||||
# Code pays du commercant
|
||||
MERCHANT_COUNTRY!fr!
|
||||
|
||||
# Code langage du commercant
|
||||
MERCHANT_LANGUAGE!fr!
|
||||
|
||||
# Liste des moyens de paiement acceptes
|
||||
PAYMENT_MEANS!CB,2,VISA,2,MASTERCARD,2!
|
||||
|
||||
# Passage en une seule frame securisee au moment du paiement
|
||||
TARGET!_top!
|
||||
|
||||
# Couleur du text (noir)
|
||||
TEXTCOLOR!000000!
|
||||
# END OF FILE
|
||||
15
local/modules/Atos/Config/parmcom.dist
Normal file
@@ -0,0 +1,15 @@
|
||||
###############################################################################
|
||||
#
|
||||
# Fichier des parametres du commercant
|
||||
#
|
||||
# Remarque : Ce fichier parametre est sous la responsabilite du
|
||||
# commercant
|
||||
#
|
||||
###############################################################################
|
||||
|
||||
# Logo du commercant (il apparait en entete sur les pages de paiement)
|
||||
#ADVERT!merchant.gif!
|
||||
|
||||
# END OF FILE
|
||||
|
||||
|
||||
31
local/modules/Atos/Config/pathfile
Normal file
@@ -0,0 +1,31 @@
|
||||
#########################################################################
|
||||
#
|
||||
# Pathfile
|
||||
#
|
||||
# Liste fichiers parametres utilisés par le module de paiement
|
||||
#
|
||||
#########################################################################
|
||||
# ------------------------------------------------------------------------
|
||||
# Chemin vers le répertoire des logos depuis le web alias
|
||||
# ------------------------------------------------------------------------
|
||||
#
|
||||
D_LOGO!/atos/logo/!
|
||||
#
|
||||
#------------------------------------------------------------------------
|
||||
#------------------------------------------------------------------------
|
||||
#
|
||||
# certificat du commercant
|
||||
#
|
||||
F_CERTIFICATE!/var/www/sterivein.com/web/thelia/local/modules/Atos/Config/certif!
|
||||
#
|
||||
# fichier paramètre commercant
|
||||
#
|
||||
F_PARAM!/var/www/sterivein.com/web/thelia/local/modules/Atos/Config/parmcom!
|
||||
#
|
||||
# fichier des paramètres ATOS
|
||||
#
|
||||
F_DEFAULT!/var/www/sterivein.com/web/thelia/local/modules/Atos/Config/parmcom.atos!
|
||||
#
|
||||
# --------------------------------------------------------------------------
|
||||
# end of file
|
||||
# --------------------------------------------------------------------------
|
||||
31
local/modules/Atos/Config/pathfile.dist
Normal file
@@ -0,0 +1,31 @@
|
||||
#########################################################################
|
||||
#
|
||||
# Pathfile
|
||||
#
|
||||
# Liste fichiers parametres utilisés par le module de paiement
|
||||
#
|
||||
#########################################################################
|
||||
# ------------------------------------------------------------------------
|
||||
# Chemin vers le répertoire des logos depuis le web alias
|
||||
# ------------------------------------------------------------------------
|
||||
#
|
||||
D_LOGO!/atos/logo/!
|
||||
#
|
||||
#------------------------------------------------------------------------
|
||||
#------------------------------------------------------------------------
|
||||
#
|
||||
# certificat du commercant
|
||||
#
|
||||
F_CERTIFICATE!__PATH__/Config/certif!
|
||||
#
|
||||
# fichier paramètre commercant
|
||||
#
|
||||
F_PARAM!__PATH__/Config/parmcom!
|
||||
#
|
||||
# fichier des paramètres ATOS
|
||||
#
|
||||
F_DEFAULT!__PATH__/Config/parmcom.atos!
|
||||
#
|
||||
# --------------------------------------------------------------------------
|
||||
# end of file
|
||||
# --------------------------------------------------------------------------
|
||||
27
local/modules/Atos/Config/routing.xml
Normal file
@@ -0,0 +1,27 @@
|
||||
<?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="atos.config" path="/admin/module/atos/configure" methods="post">
|
||||
<default key="_controller">Atos\Controller\ConfigureController::configure</default>
|
||||
</route>
|
||||
|
||||
<route id="atos.download.log" path="/admin/module/atos/log">
|
||||
<default key="_controller">Atos\Controller\ConfigureController::downloadLog</default>
|
||||
</route>
|
||||
|
||||
<route id="atos.logo" path="atos/logo/{image}">
|
||||
<default key="_controller">Atos\Controller\PaymentController::displayLogo</default>
|
||||
</route>
|
||||
|
||||
<route id="atos.payment.confirmation" path="atos/callback" methods="post">
|
||||
<default key="_controller">Atos\Controller\PaymentController::processAtosRequest</default>
|
||||
</route>
|
||||
|
||||
<route id="atos.payment.cancel" path="atos/cancel/{orderId}">
|
||||
<default key="_controller">Atos\Controller\PaymentController::processUserCancel</default>
|
||||
<requirement key="orderId">\d+</requirement>
|
||||
</route>
|
||||
</routes>
|
||||
12
local/modules/Atos/Config/schema.xml
Normal file
@@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<database defaultIdMethod="native" name="thelia" namespace="Atos\Model">
|
||||
<!--
|
||||
See propel documentation on http://propelorm.org for all information about schema file
|
||||
-->
|
||||
<table name="atos_currency">
|
||||
<column name="code" required="true" size="128" type="VARCHAR" primaryKey="true"/>
|
||||
<column name="atos_code" type="INTEGER" />
|
||||
<column name="decimals" type="INTEGER" />
|
||||
</table>
|
||||
<external-schema filename="local/config/schema.xml" referenceOnly="true" />
|
||||
</database>
|
||||
44
local/modules/Atos/Config/thelia.sql
Normal file
@@ -0,0 +1,44 @@
|
||||
|
||||
# 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;
|
||||
|
||||
-- ---------------------------------------------------------------------
|
||||
-- atos_currency
|
||||
-- ---------------------------------------------------------------------
|
||||
|
||||
DROP TABLE IF EXISTS `atos_currency`;
|
||||
|
||||
CREATE TABLE `atos_currency`
|
||||
(
|
||||
`code` VARCHAR(128) NOT NULL,
|
||||
`atos_code` INTEGER,
|
||||
`decimals` INTEGER,
|
||||
PRIMARY KEY (`code`)
|
||||
) ENGINE=InnoDB;
|
||||
|
||||
INSERT INTO `atos_currency`(`code`,`atos_code`,`decimals`) VALUES
|
||||
('EUR', '978', 2),
|
||||
('USD', '840', 2),
|
||||
('CHF', '756', 2),
|
||||
('GBP', '826', 2),
|
||||
('CAD', '124', 2),
|
||||
('JPY', '392', 0),
|
||||
('MXN', '484', 2),
|
||||
('TRY', '949', 2),
|
||||
('AUD', '036', 2),
|
||||
('NZD', '554', 2),
|
||||
('NOK', '578', 2),
|
||||
('BRL', '986', 2),
|
||||
('ARS', '032', 2),
|
||||
('KHR', '116', 2),
|
||||
('TWD', '901', 2),
|
||||
('SEK', '752', 2),
|
||||
('DKK', '208', 2),
|
||||
('KRW', '410', 0),
|
||||
('SGD', '702', 2),
|
||||
('XPF', '953', 2),
|
||||
('XAF', '952', 2);
|
||||
|
||||
# This restores the fkey checks, after having unset them earlier
|
||||
SET FOREIGN_KEY_CHECKS = 1;
|
||||
166
local/modules/Atos/Controller/ConfigureController.php
Normal file
@@ -0,0 +1,166 @@
|
||||
<?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 Atos\Controller;
|
||||
|
||||
use Atos\Atos;
|
||||
use Symfony\Component\Filesystem\Filesystem;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Thelia\Controller\Admin\BaseAdminController;
|
||||
use Thelia\Core\Security\AccessManager;
|
||||
use Thelia\Core\Security\Resource\AdminResources;
|
||||
use Thelia\Core\Thelia;
|
||||
use Thelia\Exception\FileException;
|
||||
use Thelia\Form\Exception\FormValidationException;
|
||||
use Thelia\Tools\URL;
|
||||
use Thelia\Tools\Version\Version;
|
||||
|
||||
/**
|
||||
* Class ConfigureController
|
||||
* @package Atos\Controller
|
||||
* @author manuel raynaud <mraynaud@openstudio.fr>, Franck Allimant <franck@cqfdev.fr>
|
||||
*/
|
||||
class ConfigureController extends BaseAdminController
|
||||
{
|
||||
public function copyDistFile($fileName, $merchantId)
|
||||
{
|
||||
$distFile = Atos::getConfigDirectory() . $fileName . '.dist';
|
||||
$destFile = Atos::getConfigDirectory() . $fileName . '.' . $merchantId;
|
||||
|
||||
if (! is_readable($destFile)) {
|
||||
if (!is_file($distFile) && !is_readable($distFile)) {
|
||||
throw new FileException(sprintf("Can't read file '%s', please check file permissions", $distFile));
|
||||
}
|
||||
|
||||
// Copy the dist file in place
|
||||
$fs = new Filesystem();
|
||||
|
||||
$fs->copy($distFile, $destFile);
|
||||
}
|
||||
|
||||
return $destFile;
|
||||
}
|
||||
|
||||
public function checkExecutable($fileName)
|
||||
{
|
||||
$binFile = Atos::getBinDirectory() . $fileName;
|
||||
|
||||
if (! is_executable($binFile)) {
|
||||
throw new FileException(
|
||||
$this->getTranslator()->trans(
|
||||
"The '%file' should be executable. Please check file permission",
|
||||
[ '%file' => $binFile ],
|
||||
Atos::MODULE_DOMAIN
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
public function downloadLog()
|
||||
{
|
||||
if (null !== $response = $this->checkAuth(AdminResources::MODULE, 'atos', AccessManager::UPDATE)) {
|
||||
return $response;
|
||||
}
|
||||
|
||||
$logFilePath = sprintf(THELIA_ROOT."log".DS."%s.log", Atos::MODULE_DOMAIN);
|
||||
|
||||
return Response::create(
|
||||
@file_get_contents($logFilePath),
|
||||
200,
|
||||
array(
|
||||
'Content-type' => "text/plain",
|
||||
'Content-Disposition' => sprintf('Attachment;filename=atos-log.txt')
|
||||
)
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
public function configure()
|
||||
{
|
||||
if (null !== $response = $this->checkAuth(AdminResources::MODULE, 'atos', AccessManager::UPDATE)) {
|
||||
return $response;
|
||||
}
|
||||
|
||||
$configurationForm = $this->createForm('atos_configuration');
|
||||
$message = null;
|
||||
|
||||
try {
|
||||
$form = $this->validateForm($configurationForm);
|
||||
|
||||
// Get the form field values
|
||||
$data = $form->getData();
|
||||
|
||||
foreach ($data as $name => $value) {
|
||||
if (is_array($value)) {
|
||||
$value = implode(';', $value);
|
||||
}
|
||||
|
||||
Atos::setConfigValue($name, $value);
|
||||
}
|
||||
|
||||
$merchantId = $data['atos_merchantId'];
|
||||
|
||||
$this->checkExecutable('request');
|
||||
$this->checkExecutable('response');
|
||||
|
||||
$this->copyDistFile('parmcom', $merchantId);
|
||||
$certificateFile = $this->copyDistFile('certif.fr', $merchantId);
|
||||
|
||||
// Write certificate
|
||||
if (! @file_put_contents($certificateFile, $data['atos_certificate'])) {
|
||||
throw new FileException(
|
||||
$this->getTranslator()->trans(
|
||||
"Failed to write certificate data in file '%file'. Please check file permission",
|
||||
[ '%file' => $certificateFile ],
|
||||
Atos::MODULE_DOMAIN
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
// Log configuration modification
|
||||
$this->adminLogAppend(
|
||||
"atos.configuration.message",
|
||||
AccessManager::UPDATE,
|
||||
"Atos configuration updated"
|
||||
);
|
||||
|
||||
// Redirect to the success URL,
|
||||
if ($this->getRequest()->get('save_mode') == 'stay') {
|
||||
// If we have to stay on the same page, redisplay the configuration page/
|
||||
$url = '/admin/module/Atos';
|
||||
} else {
|
||||
// If we have to close the page, go back to the module back-office page.
|
||||
$url = '/admin/modules';
|
||||
}
|
||||
|
||||
return $this->generateRedirect(URL::getInstance()->absoluteUrl($url));
|
||||
} catch (FormValidationException $ex) {
|
||||
$message = $this->createStandardFormValidationErrorMessage($ex);
|
||||
} catch (\Exception $ex) {
|
||||
$message = $ex->getMessage();
|
||||
}
|
||||
|
||||
$this->setupFormErrorContext(
|
||||
$this->getTranslator()->trans("Atos configuration", [], Atos::MODULE_DOMAIN),
|
||||
$message,
|
||||
$configurationForm,
|
||||
$ex
|
||||
);
|
||||
|
||||
// Before 2.2, the errored form is not stored in session
|
||||
if (Version::test(Thelia::THELIA_VERSION, '2.2', false, "<")) {
|
||||
return $this->render('module-configure', [ 'module_code' => 'Atos' ]);
|
||||
} else {
|
||||
return $this->generateRedirect(URL::getInstance()->absoluteUrl('/admin/module/Atos'));
|
||||
}
|
||||
}
|
||||
}
|
||||
252
local/modules/Atos/Controller/PaymentController.php
Normal file
@@ -0,0 +1,252 @@
|
||||
<?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 Atos\Controller;
|
||||
|
||||
use Atos\Atos;
|
||||
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
|
||||
use Thelia\Core\Event\Order\OrderEvent;
|
||||
use Thelia\Core\Event\TheliaEvents;
|
||||
use Thelia\Core\HttpFoundation\Response;
|
||||
use Thelia\Exception\TheliaProcessException;
|
||||
use Thelia\Model\OrderQuery;
|
||||
use Thelia\Model\OrderStatusQuery;
|
||||
use Thelia\Module\BasePaymentModuleController;
|
||||
|
||||
/**
|
||||
* Class PaymentController
|
||||
* @package Atos\Controller
|
||||
* @author manuel raynaud <mraynaud@openstudio.fr>, Franck Allimant <franck@cqfdev.fr>
|
||||
*/
|
||||
class PaymentController extends BasePaymentModuleController
|
||||
{
|
||||
|
||||
public function processAtosRequest()
|
||||
{
|
||||
$this->getLog()->addInfo(
|
||||
$this->getTranslator()->trans(
|
||||
"Atos-SIPS platform request received.",
|
||||
[],
|
||||
Atos::MODULE_DOMAIN
|
||||
)
|
||||
);
|
||||
|
||||
$binResponse = Atos::getBinDirectory() . 'response';
|
||||
|
||||
if (! empty($_POST['DATA'])) {
|
||||
$data = escapeshellcmd($_POST['DATA']);
|
||||
|
||||
$pathfile = Atos::getPathfilePath();
|
||||
|
||||
$resultRaw = exec(sprintf("%s message=%s pathfile=%s", $binResponse, $data, $pathfile));
|
||||
|
||||
if (!empty($resultRaw)) {
|
||||
$result = explode('!', $resultRaw);
|
||||
|
||||
$result = $this->parseResult($result);
|
||||
|
||||
$this->getLog()->addInfo(
|
||||
$this->getTranslator()->trans(
|
||||
'Response parameters : %resp',
|
||||
['%resp' => print_r($result, true)],
|
||||
Atos::MODULE_DOMAIN
|
||||
)
|
||||
);
|
||||
|
||||
if ($result['code'] == '' && $result['error'] == '') {
|
||||
$this->getLog()->addError(
|
||||
$this->getTranslator()->trans(
|
||||
'Response request not found in %response',
|
||||
['%response' => $binResponse],
|
||||
Atos::MODULE_DOMAIN
|
||||
)
|
||||
);
|
||||
} elseif (intval($result['code']) != 0) {
|
||||
$this->getLog()->addError(
|
||||
$this->getTranslator()->trans(
|
||||
'Error %code while processing response, with message %message',
|
||||
['%code' => intval($result['code']), '%message' => $result['error']],
|
||||
Atos::MODULE_DOMAIN
|
||||
)
|
||||
);
|
||||
} elseif ($result['response_code'] == '00') {
|
||||
$atos = new Atos();
|
||||
|
||||
$order = OrderQuery::create()
|
||||
->filterByTransactionRef($result['transaction_id'])
|
||||
->filterByPaymentModuleId($atos->getModuleModel()->getId())
|
||||
->findOne();
|
||||
|
||||
if ($order) {
|
||||
$this->confirmPayment($order->getId());
|
||||
|
||||
$this->getLog()->addInfo(
|
||||
$this->getTranslator()->trans(
|
||||
"Order ID %id is confirmed.",
|
||||
['%id' => $order->getId()],
|
||||
Atos::MODULE_DOMAIN
|
||||
)
|
||||
);
|
||||
} else {
|
||||
$this->getLog()->addError(
|
||||
$this->getTranslator()->trans(
|
||||
'Cannot find an order for transaction ID "%trans"',
|
||||
['%trans' => $result['transaction_id']],
|
||||
Atos::MODULE_DOMAIN
|
||||
)
|
||||
);
|
||||
}
|
||||
} else {
|
||||
$this->getLog()->addError(
|
||||
$this->getTranslator()->trans(
|
||||
'Cannot validate order. Response code is %resp',
|
||||
['%resp' => $result['response_code']],
|
||||
Atos::MODULE_DOMAIN
|
||||
)
|
||||
);
|
||||
}
|
||||
} else {
|
||||
$this->getLog()->addError(
|
||||
$this->getTranslator()->trans(
|
||||
'Got empty response from executable %binary, check path and permissions',
|
||||
['%binary' => $binResponse],
|
||||
Atos::MODULE_DOMAIN
|
||||
)
|
||||
);
|
||||
}
|
||||
} else {
|
||||
$this->getLog()->addError(
|
||||
$this->getTranslator()->trans(
|
||||
'Request does not contains any data',
|
||||
[],
|
||||
Atos::MODULE_DOMAIN
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
$this->getLog()->info(
|
||||
$this->getTranslator()->trans(
|
||||
"Atos platform request processing terminated.",
|
||||
[],
|
||||
Atos::MODULE_DOMAIN
|
||||
)
|
||||
);
|
||||
|
||||
return Response::create();
|
||||
}
|
||||
|
||||
/*
|
||||
* @param $orderId int the order ID
|
||||
* @return \Thelia\Core\HttpFoundation\Response
|
||||
*/
|
||||
public function processUserCancel($orderId)
|
||||
{
|
||||
$this->getLog()->addInfo(
|
||||
$this->getTranslator()->trans(
|
||||
'User canceled payment of order %id',
|
||||
['%id' => $orderId],
|
||||
Atos::MODULE_DOMAIN
|
||||
)
|
||||
);
|
||||
|
||||
try {
|
||||
if (null !== $order = OrderQuery::create()->findPk($orderId)) {
|
||||
$currentCustomerId = $this->getSecurityContext()->getCustomerUser()->getId();
|
||||
$orderCustomerId = $order->getCustomerId();
|
||||
|
||||
if ($orderCustomerId != $currentCustomerId) {
|
||||
throw new TheliaProcessException(
|
||||
sprintf(
|
||||
"User ID %d is trying to cancel order ID %d ordered by user ID %d",
|
||||
$currentCustomerId,
|
||||
$orderId,
|
||||
$orderCustomerId
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
$event = new OrderEvent($order);
|
||||
$event->setStatus(OrderStatusQuery::getCancelledStatus()->getId());
|
||||
$this->dispatch(TheliaEvents::ORDER_UPDATE_STATUS, $event);
|
||||
}
|
||||
} catch (\Exception $ex) {
|
||||
$this->getLog()->addError("Error occurred while canceling order ID $orderId: " . $ex->getMessage());
|
||||
}
|
||||
|
||||
$this->redirectToFailurePage(
|
||||
$orderId,
|
||||
$this->getTranslator()->trans('you cancel the payment', [], Atos::MODULE_DOMAIN)
|
||||
);
|
||||
}
|
||||
|
||||
protected function parseResult($result)
|
||||
{
|
||||
return [
|
||||
'code' => $result[1],
|
||||
'error' => $result[2],
|
||||
'merchant_id' => $result[3],
|
||||
'merchant_country' => $result[4],
|
||||
'amount' => $result[5],
|
||||
'transaction_id' => $result[6],
|
||||
'payment_means' => $result[7],
|
||||
'transmission_date' => $result[8],
|
||||
'payment_time' => $result[9],
|
||||
'payment_date' => $result[10],
|
||||
'response_code' => $result[11],
|
||||
'payment_certificate' => $result[12],
|
||||
'authorisation_id' => $result[13],
|
||||
'currency_code' => $result[14],
|
||||
'card_number' => $result[15],
|
||||
'cvv_flag' => $result[16],
|
||||
'cvv_response_code' => $result[17],
|
||||
'bank_response_code' => $result[18],
|
||||
'complementary_code' => $result[19],
|
||||
'complementary_info' => $result[20],
|
||||
'return_context' => $result[21],
|
||||
'caddie' => $result[22],
|
||||
'receipt_complement' => $result[23],
|
||||
'merchant_language' => $result[24],
|
||||
'language' => $result[25],
|
||||
'customer_id' => $result[26],
|
||||
'order_id' => $result[27],
|
||||
'customer_email' => $result[28],
|
||||
'customer_ip_address' => $result[29],
|
||||
'capture_day' => $result[30],
|
||||
'capture_mode' => $result[31],
|
||||
'data' => $result[32]
|
||||
];
|
||||
}
|
||||
|
||||
public function displayLogo($image)
|
||||
{
|
||||
if (file_exists(__DIR__ . DS . '..' . DS . 'logo' . DS . $image)) {
|
||||
$sourceImage = file_get_contents(__DIR__ . DS . '..' . DS . 'logo' . DS . $image);
|
||||
|
||||
return Response::create($sourceImage, 200, [
|
||||
'Content-Type' => 'image/gif',
|
||||
'Content-Length' => strlen($sourceImage)
|
||||
]);
|
||||
} else {
|
||||
throw new NotFoundHttpException();
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Return a module identifier used to calculate the name of the log file,
|
||||
* and in the log messages.
|
||||
*
|
||||
* @return string the module code
|
||||
*/
|
||||
protected function getModuleCode()
|
||||
{
|
||||
return 'Atos';
|
||||
}
|
||||
}
|
||||
94
local/modules/Atos/EventListeners/SendConfirmationEmail.php
Normal file
@@ -0,0 +1,94 @@
|
||||
<?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 Atos\EventListeners;
|
||||
|
||||
use Atos\Atos;
|
||||
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 SendEmailConfirmation
|
||||
* @package Atos\EventListeners
|
||||
* @author manuel raynaud <mraynaud@openstudio.fr>
|
||||
* @author franck allimant <franck@cqfdev.fr>
|
||||
*/
|
||||
class SendConfirmationEmail 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 (Atos::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() == Atos::getModuleId()) {
|
||||
$event->stopPropagation();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* @params OrderEvent $order
|
||||
* Checks if order payment module is paypal and if order new status is paid, send an email to the customer.
|
||||
*/
|
||||
|
||||
public function updateStatus(OrderEvent $event)
|
||||
{
|
||||
$order = $event->getOrder();
|
||||
|
||||
if ($order->isPaid() && $order->getPaymentModuleId() == Atos::getModuleId()) {
|
||||
if (Atos::getConfigValue('send_payment_confirmation_message')) {
|
||||
$this->mailer->sendEmailToCustomer(
|
||||
Atos::CONFIRMATION_MESSAGE_NAME,
|
||||
$order->getCustomer(),
|
||||
[
|
||||
'order_id' => $order->getId(),
|
||||
'order_ref' => $order->getRef()
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
// Send confirmation email if required.
|
||||
if (Atos::getConfigValue('send_confirmation_message_only_if_paid')) {
|
||||
$event->getDispatcher()->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)
|
||||
);
|
||||
}
|
||||
}
|
||||
249
local/modules/Atos/Form/ConfigForm.php
Normal file
@@ -0,0 +1,249 @@
|
||||
<?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 Atos\Form;
|
||||
|
||||
use Atos\Atos;
|
||||
use Symfony\Component\Validator\Constraints\GreaterThanOrEqual;
|
||||
use Symfony\Component\Validator\Constraints\NotBlank;
|
||||
use Thelia\Core\Translation\Translator;
|
||||
use Thelia\Form\BaseForm;
|
||||
use Thelia\Model\Module;
|
||||
use Thelia\Model\ModuleQuery;
|
||||
|
||||
/**
|
||||
* Class Config
|
||||
* @author manuel raynaud <mraynaud@openstudio.fr>
|
||||
*/
|
||||
class ConfigForm extends BaseForm
|
||||
{
|
||||
protected function buildForm()
|
||||
{
|
||||
// If the Multi plugin is not enabled, all multi_fields are hidden
|
||||
/** @var Module $multiModule */
|
||||
$multiEnabled = (null !== $multiModule = ModuleQuery::create()->findOneByCode('AtosNx')) && $multiModule->getActivate() != 0;
|
||||
|
||||
$translator = Translator::getInstance();
|
||||
|
||||
$this->formBuilder
|
||||
->add(
|
||||
'atos_merchantId',
|
||||
'text',
|
||||
[
|
||||
'constraints' => [
|
||||
new NotBlank(),
|
||||
],
|
||||
'label' => $translator->trans('Shop Merchant ID', [], Atos::MODULE_DOMAIN),
|
||||
'label_attr' => [
|
||||
'for' => 'merchant_id',
|
||||
]
|
||||
]
|
||||
)
|
||||
->add(
|
||||
'atos_mode',
|
||||
'choice',
|
||||
[
|
||||
'constraints' => [
|
||||
new NotBlank()
|
||||
],
|
||||
'choices' => [
|
||||
'TEST' => $translator->trans('Test', [], Atos::MODULE_DOMAIN),
|
||||
'PRODUCTION' => $translator->trans('Production', [], Atos::MODULE_DOMAIN),
|
||||
],
|
||||
'label' => $translator->trans('Operation Mode', [], Atos::MODULE_DOMAIN),
|
||||
'label_attr' => [
|
||||
'for' => 'mode',
|
||||
'help' => $translator->trans('Test or production mode', [], Atos::MODULE_DOMAIN)
|
||||
]
|
||||
]
|
||||
)
|
||||
->add(
|
||||
'atos_allowed_ip_list',
|
||||
'textarea',
|
||||
[
|
||||
'required' => false,
|
||||
'label' => $translator->trans('Allowed IPs in test mode', [], Atos::MODULE_DOMAIN),
|
||||
'label_attr' => [
|
||||
'for' => 'platform_url',
|
||||
'help' => $translator->trans(
|
||||
'List of IP addresses allowed to use this payment on the front-office when in test mode (your current IP is %ip). One address per line',
|
||||
[ '%ip' => $this->getRequest()->getClientIp() ],
|
||||
Atos::MODULE_DOMAIN
|
||||
)
|
||||
],
|
||||
'attr' => [
|
||||
'rows' => 3
|
||||
]
|
||||
]
|
||||
)
|
||||
->add(
|
||||
'atos_minimum_amount',
|
||||
'text',
|
||||
[
|
||||
'constraints' => [
|
||||
new NotBlank(),
|
||||
new GreaterThanOrEqual(['value' => 0 ])
|
||||
],
|
||||
'label' => $translator->trans('Minimum order total', [], Atos::MODULE_DOMAIN),
|
||||
'label_attr' => [
|
||||
'for' => 'minimum_amount',
|
||||
'help' => $translator->trans(
|
||||
'Minimum order total in the default currency for which this payment method is available. Enter 0 for no minimum',
|
||||
[],
|
||||
Atos::MODULE_DOMAIN
|
||||
)
|
||||
]
|
||||
]
|
||||
)
|
||||
->add(
|
||||
'atos_maximum_amount',
|
||||
'text',
|
||||
[
|
||||
'constraints' => [
|
||||
new NotBlank(),
|
||||
new GreaterThanOrEqual([ 'value' => 0 ])
|
||||
],
|
||||
'label' => $translator->trans('Maximum order total', [], Atos::MODULE_DOMAIN),
|
||||
'label_attr' => [
|
||||
'for' => 'maximum_amount',
|
||||
'help' => $translator->trans(
|
||||
'Maximum order total in the default currency for which this payment method is available. Enter 0 for no maximum',
|
||||
[],
|
||||
Atos::MODULE_DOMAIN
|
||||
)
|
||||
]
|
||||
]
|
||||
)
|
||||
->add(
|
||||
'atos_certificate',
|
||||
'textarea',
|
||||
[
|
||||
'required' => false,
|
||||
'label' => $translator->trans('ATOS certificate content', [], Atos::MODULE_DOMAIN),
|
||||
'label_attr' => [
|
||||
'for' => 'platform_url',
|
||||
'help' => $translator->trans(
|
||||
'Please paste here the certificate downloaded from the Atos SIPS platform',
|
||||
[],
|
||||
Atos::MODULE_DOMAIN
|
||||
),
|
||||
],
|
||||
'attr' => [
|
||||
'rows' => 10
|
||||
]
|
||||
]
|
||||
)
|
||||
->add(
|
||||
'send_confirmation_message_only_if_paid',
|
||||
'checkbox',
|
||||
[
|
||||
'value' => 1,
|
||||
'required' => false,
|
||||
'label' => $this->translator->trans('Send order confirmation on payment success', [], Atos::MODULE_DOMAIN),
|
||||
'label_attr' => [
|
||||
'help' => $this->translator->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',
|
||||
[],
|
||||
Atos::MODULE_DOMAIN
|
||||
)
|
||||
]
|
||||
]
|
||||
)
|
||||
->add(
|
||||
'send_payment_confirmation_message',
|
||||
'checkbox',
|
||||
[
|
||||
'value' => 1,
|
||||
'required' => false,
|
||||
'label' => $this->translator->trans('Send a payment confirmation e-mail', [], Atos::MODULE_DOMAIN),
|
||||
'label_attr' => [
|
||||
'help' => $this->translator->trans(
|
||||
'If checked, a payment confirmation e-mail is sent to the customer.',
|
||||
[],
|
||||
Atos::MODULE_DOMAIN
|
||||
)
|
||||
]
|
||||
]
|
||||
)
|
||||
|
||||
// -- Multiple times payement parameters, hidden id the AtosNx module is not activated.
|
||||
->add(
|
||||
'nx_nb_installments',
|
||||
$multiEnabled ? 'text' : 'hidden',
|
||||
[
|
||||
'constraints' => [
|
||||
new NotBlank(),
|
||||
new GreaterThanOrEqual(['value' => 1 ])
|
||||
],
|
||||
'required' => $multiEnabled,
|
||||
'label' => $translator->trans('Number of installments', [], Atos::MODULE_DOMAIN),
|
||||
'label_attr' => [
|
||||
'for' => 'nx_nb_installments',
|
||||
'help' => $translator->trans(
|
||||
'Number of installements. Should be more than one',
|
||||
[],
|
||||
Atos::MODULE_DOMAIN
|
||||
)
|
||||
]
|
||||
]
|
||||
)
|
||||
->add(
|
||||
'nx_minimum_amount',
|
||||
$multiEnabled ? 'text' : 'hidden',
|
||||
[
|
||||
'constraints' => [
|
||||
new NotBlank(),
|
||||
new GreaterThanOrEqual(['value' => 0 ])
|
||||
],
|
||||
'required' => $multiEnabled,
|
||||
'label' => $translator->trans('Minimum order total', [], Atos::MODULE_DOMAIN),
|
||||
'label_attr' => [
|
||||
'for' => 'nx_minimum_amount',
|
||||
'help' => $translator->trans(
|
||||
'Minimum order total in the default currency for which the multiple times payment method is available. Enter 0 for no minimum',
|
||||
[],
|
||||
Atos::MODULE_DOMAIN
|
||||
)
|
||||
]
|
||||
]
|
||||
)
|
||||
->add(
|
||||
'nx_maximum_amount',
|
||||
$multiEnabled ? 'text' : 'hidden',
|
||||
[
|
||||
'constraints' => [
|
||||
new NotBlank(),
|
||||
new GreaterThanOrEqual([ 'value' => 0 ])
|
||||
],
|
||||
'required' => $multiEnabled,
|
||||
'label' => $translator->trans('Maximum order total', [], Atos::MODULE_DOMAIN),
|
||||
'label_attr' => [
|
||||
'for' => 'nx_maximum_amount',
|
||||
'help' => $translator->trans(
|
||||
'Maximum order total in the default currency for which the multiple times payment method is available. Enter 0 for no maximum',
|
||||
[],
|
||||
Atos::MODULE_DOMAIN
|
||||
)
|
||||
]
|
||||
]
|
||||
)
|
||||
;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string the name of you form. This name must be unique
|
||||
*/
|
||||
public function getName()
|
||||
{
|
||||
return 'atos_config';
|
||||
}
|
||||
}
|
||||
93
local/modules/Atos/Hook/HookManager.php
Normal file
@@ -0,0 +1,93 @@
|
||||
<?php
|
||||
/*************************************************************************************/
|
||||
/* */
|
||||
/* Thelia */
|
||||
/* */
|
||||
/* Copyright (c) OpenStudio */
|
||||
/* email : info@thelia.net */
|
||||
/* web : http://www.thelia.net */
|
||||
/* */
|
||||
/* 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/>. */
|
||||
/* */
|
||||
/*************************************************************************************/
|
||||
/**
|
||||
* Created by Franck Allimant, CQFDev <franck@cqfdev.fr>
|
||||
* Date: 11/01/2016 11:57
|
||||
*/
|
||||
namespace Atos\Hook;
|
||||
|
||||
use Atos\Atos;
|
||||
use Thelia\Core\Event\Hook\HookRenderEvent;
|
||||
use Thelia\Core\Hook\BaseHook;
|
||||
use Thelia\Model\ModuleConfig;
|
||||
use Thelia\Model\ModuleConfigQuery;
|
||||
|
||||
class HookManager extends BaseHook
|
||||
{
|
||||
const MAX_TRACE_SIZE_IN_BYTES = 40000;
|
||||
|
||||
public function onModuleConfigure(HookRenderEvent $event)
|
||||
{
|
||||
$logFilePath = sprintf(THELIA_ROOT."log".DS."%s.log", Atos::MODULE_DOMAIN);
|
||||
|
||||
if (false !== $fh = @fopen($logFilePath, "r")) {
|
||||
if (filesize($logFilePath) > self::MAX_TRACE_SIZE_IN_BYTES) {
|
||||
fseek($fh, -self::MAX_TRACE_SIZE_IN_BYTES, SEEK_END);
|
||||
$truncated = true;
|
||||
} else {
|
||||
$truncated = false;
|
||||
}
|
||||
|
||||
$traces = implode(
|
||||
'<br>',
|
||||
array_reverse(
|
||||
explode(
|
||||
"\n",
|
||||
fread($fh, self::MAX_TRACE_SIZE_IN_BYTES)
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
fclose($fh);
|
||||
|
||||
if (empty($traces)) {
|
||||
$traces = $this->translator->trans("The log file is currently empty.", [], Atos::MODULE_DOMAIN);
|
||||
} elseif ($truncated) {
|
||||
$traces = $this->translator->trans(
|
||||
"(Previous log is in %file file.)<br>",
|
||||
['%file' => sprintf("log" . DS . "%s.log", Atos::MODULE_DOMAIN)],
|
||||
Atos::MODULE_DOMAIN
|
||||
) . $traces;
|
||||
}
|
||||
} else {
|
||||
$traces = $this->translator->trans(
|
||||
"The log file '%log' does not exists yet.",
|
||||
['%log' => $logFilePath],
|
||||
Atos::MODULE_DOMAIN
|
||||
);
|
||||
}
|
||||
|
||||
$vars = [ 'trace_content' => $traces ];
|
||||
|
||||
if (null !== $params = ModuleConfigQuery::create()->findByModuleId(Atos::getModuleId())) {
|
||||
/** @var ModuleConfig $param */
|
||||
foreach ($params as $param) {
|
||||
$vars[ $param->getName() ] = $param->getValue();
|
||||
}
|
||||
}
|
||||
|
||||
$event->add(
|
||||
$this->render('atos/module-configuration.html', $vars)
|
||||
);
|
||||
}
|
||||
}
|
||||
5
local/modules/Atos/I18n/AdminIncludes/en_US.php
Normal file
@@ -0,0 +1,5 @@
|
||||
<?php
|
||||
|
||||
return array(
|
||||
'Atos Configuration' => 'Atos Configuration',
|
||||
);
|
||||
5
local/modules/Atos/I18n/AdminIncludes/fr_FR.php
Normal file
@@ -0,0 +1,5 @@
|
||||
<?php
|
||||
|
||||
return array(
|
||||
'Atos Configuration' => 'Atos Configuration',
|
||||
);
|
||||
13
local/modules/Atos/I18n/backOffice/default/en_US.php
Normal file
@@ -0,0 +1,13 @@
|
||||
<?php
|
||||
|
||||
return array(
|
||||
'Atos Configuration' => 'Atos Configuration',
|
||||
'Atos-SIPS Platform configuration' => 'Atos-SIPS Platform configuration',
|
||||
'Atos-SIPS call log to callback URL' => 'Atos-SIPS call log to callback URL',
|
||||
'Callback URL' => 'Callback URL',
|
||||
'Download full log' => 'Download full log',
|
||||
'Operation mode' => 'Operation mode',
|
||||
'Payment configuration' => 'Payment configuration',
|
||||
'This is the callback URL, that will be called by Atos SIPS after customer payment. Be sure that this URL is reachable by remote mechines' => 'This is the callback URL, that will be called by Atos SIPS after customer payment. Be sure that this URL is reachable by remote machines',
|
||||
'You can <a href="%url">edit the payment confirmation email</a> sent to the customer after a successful payment.' => 'You can <a href="%url">edit the payment confirmation email</a> sent to the customer after a successful payment.',
|
||||
);
|
||||
13
local/modules/Atos/I18n/backOffice/default/fr_FR.php
Normal file
@@ -0,0 +1,13 @@
|
||||
<?php
|
||||
|
||||
return array(
|
||||
'Atos Configuration' => 'Atos Configuration',
|
||||
'Atos-SIPS Platform configuration' => 'Configuration de la plate-forme SIPS-Atos',
|
||||
'Atos-SIPS call log to callback URL' => 'Atos-SIPS callback URL log',
|
||||
'Callback URL' => 'URL de retour',
|
||||
'Download full log' => 'Télécharger l\'historique complet',
|
||||
'Operation mode' => 'Mode de fonctionnement',
|
||||
'Payment configuration' => 'Configuration du paiement',
|
||||
'This is the callback URL, that will be called by Atos SIPS after customer payment. Be sure that this URL is reachable by remote mechines' => 'Il s\'agit de l\'URL de retour appelée par Atos SIPS après le paiement de vos clients. Assurez-vous que cette URL est joignable par des machines distantes.',
|
||||
'You can <a href="%url">edit the payment confirmation email</a> sent to the customer after a successful payment.' => 'Vous pouvez <a href="%url">modifier le mail de confirmation de paiement</a> envoyé au client.',
|
||||
);
|
||||
60
local/modules/Atos/I18n/email-templates/en.html
Normal file
@@ -0,0 +1,60 @@
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" dir="ltr" lang="en">
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
|
||||
<title>courriel de confirmation de commande de {config key="url_site"} </title>
|
||||
<style type="text/css">
|
||||
body {
|
||||
font-family: Arial, Helvetica, sans-serif;
|
||||
font-size: 100%;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
#liencompte {
|
||||
margin: 15px 0;
|
||||
text-align: center;
|
||||
font-size: 10pt;
|
||||
}
|
||||
|
||||
#wrapper {
|
||||
width: 480pt;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
#entete {
|
||||
padding-bottom: 20px;
|
||||
margin-bottom: 10px;
|
||||
border-bottom: 1px dotted #000;
|
||||
}
|
||||
|
||||
#logotexte {
|
||||
float: left;
|
||||
width: 180pt;
|
||||
height: 75pt;
|
||||
border: 1pt solid #000;
|
||||
font-size: 18pt;
|
||||
text-align: center;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="wrapper">
|
||||
<div id="entete">
|
||||
<h1 id="logotexte">{config key="store_name"}</h1>
|
||||
|
||||
<h2 id="info">The payment of your order is confirmed</h2>
|
||||
|
||||
<h3 id="commande">Reference {$order_ref} </h3>
|
||||
</div>
|
||||
|
||||
<p id="liencompte">
|
||||
Your invoice is now available in your customer account on
|
||||
<a href="{config key="url_site"}">{config key="store_name"}</a>.
|
||||
</p>
|
||||
|
||||
<p>Thank you for your order !</p>
|
||||
|
||||
<p>The {config key="store_name"} team.</p>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
9
local/modules/Atos/I18n/email-templates/en.txt
Normal file
@@ -0,0 +1,9 @@
|
||||
Dear customer,
|
||||
|
||||
This is a confirmation of the payment of your order {$order_ref} via Payzen on our shop.
|
||||
|
||||
Your invoice is now available in your customer account at {config key="url_site"}
|
||||
|
||||
Thank you again for your purchase.
|
||||
|
||||
The {config key="store_name"} team.
|
||||
62
local/modules/Atos/I18n/email-templates/fr.html
Normal file
@@ -0,0 +1,62 @@
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" dir="ltr" lang="fr">
|
||||
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
|
||||
<title>Confirmation du paiement de votre commande sur {config key="url_site"} </title>
|
||||
<style type="text/css">
|
||||
body {
|
||||
font-family: Arial, Helvetica, sans-serif;
|
||||
font-size: 100%;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
#liencompte {
|
||||
margin: 15px 0;
|
||||
text-align: center;
|
||||
font-size: 10pt;
|
||||
}
|
||||
|
||||
#wrapper {
|
||||
width: 480pt;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
#entete {
|
||||
padding-bottom: 20px;
|
||||
margin-bottom: 10px;
|
||||
border-bottom: 1px dotted #000;
|
||||
}
|
||||
|
||||
#logotexte {
|
||||
float: left;
|
||||
width: 180pt;
|
||||
height: 75pt;
|
||||
border: 1pt solid #000;
|
||||
font-size: 18pt;
|
||||
text-align: center;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div id="wrapper">
|
||||
<div id="entete">
|
||||
<h1 id="logotexte">{config key="store_name"}</h1>
|
||||
|
||||
<h2 id="info">Confirmation du paiement de votre commande</h2>
|
||||
|
||||
<h3 id="commande">N° {$order_ref}</h3>
|
||||
</div>
|
||||
|
||||
<p id="liencompte">
|
||||
Le suivi de votre commande est disponible dans la rubrique mon compte sur
|
||||
<a href="{config key="url_site"}">{config key="url_site"}</a>
|
||||
</p>
|
||||
|
||||
<p>Merci pour votre achat !</p>
|
||||
|
||||
<p>L'équipe {config key="store_name"}</p>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
9
local/modules/Atos/I18n/email-templates/fr.txt
Normal file
@@ -0,0 +1,9 @@
|
||||
Cher client,
|
||||
|
||||
Ce message confirme le paiement de votre commande numero {$order_ref} via Payzen sur notre boutique.
|
||||
|
||||
Votre facture est maintenant disponible dans votre compte client à l'adresse {config key="url_site"}
|
||||
|
||||
Merci encore pour votre achat !
|
||||
|
||||
L'équipe {config key="store_name"}
|
||||
12
local/modules/Atos/I18n/email/default/en_US.php
Normal file
@@ -0,0 +1,12 @@
|
||||
<?php
|
||||
|
||||
return array(
|
||||
'Dear customer' => 'Dear customer',
|
||||
'Payment of your order %ref' => 'Payment of your order %ref',
|
||||
'Thank you again for your purchase.' => 'Thank you again for your purchase.',
|
||||
'The %store_name team.' => 'The %store_name team.',
|
||||
'The payment of your order %ref with SIPS Atos is confirmed' => 'The payment of your order %ref with SIPS Atos is confirmed',
|
||||
'This is a confirmation of the payment of your order %ref with SIPS-Atos on our shop.' => 'This is a confirmation of the payment of your order %ref with SIPS-Atos on our shop.',
|
||||
'View this order in your account at %shop_name' => 'View this order in your account at %shop_name',
|
||||
'Your invoice is now available in your customer account at %url.' => 'Your invoice is now available in your customer account at %url.',
|
||||
);
|
||||
12
local/modules/Atos/I18n/email/default/fr_FR.php
Normal file
@@ -0,0 +1,12 @@
|
||||
<?php
|
||||
|
||||
return array(
|
||||
'Dear customer' => 'Cher client',
|
||||
'Payment of your order %ref' => 'Paiement de votre commande %ref',
|
||||
'Thank you again for your purchase.' => 'Merci encore pour votre commande.',
|
||||
'The %store_name team.' => 'L\'équipe %store_name',
|
||||
'The payment of your order %ref with SIPS Atos is confirmed' => 'Le paiement de votre commande %ref avec SIPS Atos est confirmé.',
|
||||
'This is a confirmation of the payment of your order %ref with SIPS-Atos on our shop.' => 'Ce message confirme le paiement de votre commande %ref avec SIPS Atos dans notre boutique.',
|
||||
'View this order in your account at %shop_name' => 'Les détails de cette commande sont disponibles dans votre compte client sur %shop_name',
|
||||
'Your invoice is now available in your customer account at %url.' => 'Les détails de cette commande sont disponibles dans votre compte client sur %url',
|
||||
);
|
||||
44
local/modules/Atos/I18n/en_US.php
Normal file
@@ -0,0 +1,44 @@
|
||||
<?php
|
||||
|
||||
return array(
|
||||
'(Previous log is in %file file.)\n' => '(Previous log is in %file file.)\n',
|
||||
'ATOS certificate content' => 'ATOS certificate content',
|
||||
'Allowed IPs in test mode' => 'Allowed IPs in test mode',
|
||||
'Atos configuration' => 'Atos configuration',
|
||||
'Atos payment module is nort properly configured. Please check module configuration in your back-office.' => 'Atos payment module is nort properly configured. Please check module configuration in your back-office.',
|
||||
'Atos platform request processing terminated.' => 'Atos platform request processing terminated.',
|
||||
'Atos-SIPS platform request received.' => 'Atos-SIPS platform request received.',
|
||||
'Cannot find an order for transaction ID "%trans"' => 'Cannot find an order for transaction ID "%trans"',
|
||||
'Cannot validate order. Response code is %resp' => 'Cannot validate order. Response code is %resp',
|
||||
'Empty response recevied from Atos binary "%path". Please check path and permissions.' => 'Empty response recevied from Atos binary "%path". Please check path and permissions.',
|
||||
'Error %code while processing response, with message %message' => 'Error %code while processing response, with message %message',
|
||||
'Failed to read the %file file. Please check file and directory permissions.' => 'Failed to read the %file file. Please check file and directory permissions.',
|
||||
'Failed to write certificate data in file \'%file\'. Please check file permission' => 'Failed to write certificate data in file \'%file\'. Please check file permission',
|
||||
'File %file must be writable, please check Atos/Config directory permissions.' => 'File %file must be writable, please check Atos/Config directory permissions.',
|
||||
'Got empty response from executable %binary, check path and permissions' => 'Got empty response from executable %binary, check path and permissions',
|
||||
'If checked, a payment confirmation e-mail is sent to the customer.' => 'If checked, a payment confirmation e-mail is sent to the customer.',
|
||||
'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',
|
||||
'List of IP addresses allowed to use this payment on the front-office when in test mode (your current IP is %ip). One address per line' => 'List of IP addresses allowed to use this payment on the front-office when in test mode (your current IP is %ip). One address per line',
|
||||
'Maximum order total' => 'Maximum order total',
|
||||
'Maximum order total in the default currency for which this payment method is available. Enter 0 for no maximum' => 'Maximum order total in the default currency for which this payment method is available. Enter 0 for no maximum',
|
||||
'Minimum order total' => 'Minimum order total',
|
||||
'Minimum order total in the default currency for which this payment method is available. Enter 0 for no minimum' => 'Minimum order total in the default currency for which this payment method is available. Enter 0 for no minimum',
|
||||
'Operation Mode' => 'Operation Mode',
|
||||
'Order ID %id is confirmed.' => 'Order ID %id is confirmed.',
|
||||
'Please paste here the certificate downloaded from the Atos SIPS platform' => 'Please paste here the certificate downloaded from the Atos SIPS platform',
|
||||
'Production' => 'Production',
|
||||
'Request binary not found in "%path"' => 'Request binary not found in "%path"',
|
||||
'Request does not contains any data' => 'Request does not contains any data',
|
||||
'Response parameters : %resp' => 'Response parameters : %resp',
|
||||
'Response request not found in %response' => 'Response request not found in %response',
|
||||
'Send a payment confirmation e-mail' => 'Send a payment confirmation e-mail',
|
||||
'Send order confirmation on payment success' => 'Send order confirmation on payment success',
|
||||
'Shop Merchant ID' => 'Shop Merchant ID',
|
||||
'Test' => 'Test',
|
||||
'Test or production mode' => 'Test or production mode',
|
||||
'The \'%file\' should be executable. Please check file permission' => 'The \'%file\' should be executable. Please check file permission',
|
||||
'The log file \'%log\' does not exists yet.' => 'The log file \'%log\' does not exists yet.',
|
||||
'The log file is currently empty.' => 'The log file is currently empty.',
|
||||
'User canceled payment of order %id' => 'User canceled payment of order ID %id',
|
||||
'you cancel the payment' => 'you cancel the payment',
|
||||
);
|
||||
44
local/modules/Atos/I18n/fr_FR.php
Normal file
@@ -0,0 +1,44 @@
|
||||
<?php
|
||||
|
||||
return array(
|
||||
'(Previous log is in %file file.)\n' => '(L\'historique précédent se trouve dans n %file file.)\n',
|
||||
'ATOS certificate content' => 'Certificat ATOS',
|
||||
'Allowed IPs in test mode' => 'Adresse IP autorisées en phase de test',
|
||||
'Atos configuration' => 'Configuration ATOS-SIPS',
|
||||
'Atos payment module is nort properly configured. Please check module configuration in your back-office.' => 'Le module de paiement Atos n\'est pas correctement configuré. Merci de vérifier la configuration dans votre back-office.',
|
||||
'Atos platform request processing terminated.' => 'Traitemenr de la requête ATOS terminé.',
|
||||
'Atos-SIPS platform request received.' => 'Réception d\'une requête ATOS',
|
||||
'Cannot find an order for transaction ID "%trans"' => 'Aucune commande ne correspond à l\'ID de transaction "%trans"',
|
||||
'Cannot validate order. Response code is %resp' => 'La commande ne peut être validée. Le code de réponse est %resp',
|
||||
'Empty response recevied from Atos binary "%path". Please check path and permissions.' => 'Le binaire Atos %path a retourné une réponse vide. Vérifiez que ce fichier est exécutable.',
|
||||
'Error %code while processing response, with message %message' => 'Erreur %code lors du traitement de la réponse, avec le message %message',
|
||||
'Failed to read the %file file. Please check file and directory permissions.' => 'Impossible de lire le fichier %file. Vérifier que le fichier existe et est est accessible en lecture.',
|
||||
'Failed to write certificate data in file \'%file\'. Please check file permission' => 'L\'écriture des données du certificat dans le fichier %file a échoué. Vérifier que le fichier est accessible en écriture.',
|
||||
'File %file must be writable, please check Atos/Config directory permissions.' => 'Le fichier %file doit être accessible en écriture, merci de vérifier qu\'il possède les permissions nécessaires.',
|
||||
'Got empty response from executable %binary, check path and permissions' => 'L\'executable %binary a retourné une réponse vide. Vérifier les permissions du fichier.',
|
||||
'If checked, a payment confirmation e-mail is sent to the customer.' => 'Si cette case est cochée, un mail de confirmation de paiement sera envoyé au client.',
|
||||
'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 cette case est cochée, le mail de confirmation de commande sera envoyé au client seulement si son paiement est validé.',
|
||||
'List of IP addresses allowed to use this payment on the front-office when in test mode (your current IP is %ip). One address per line' => 'Liste des adresse IP qui pourront choisir ce module de paiement en front-office pendant la phase de test (votre IP est %ip). Une adresse par ligne.',
|
||||
'Maximum order total' => 'Montant de commande maximum',
|
||||
'Maximum order total in the default currency for which this payment method is available. Enter 0 for no maximum' => 'Montant maximum dans la devise par défaut pour proposer ce moyen de paiement. Laisser 0 pour ne pas fixer de maximum.',
|
||||
'Minimum order total' => 'Montant minimum de commande',
|
||||
'Minimum order total in the default currency for which this payment method is available. Enter 0 for no minimum' => 'Montant minimum dans la devise par défaut pour proposer ce moyen de paiement. Laisser 0 pour ne pas fixer de minimum.',
|
||||
'Operation Mode' => 'Mode de fonctionnement',
|
||||
'Order ID %id is confirmed.' => 'La commande ID %id est confirmée',
|
||||
'Please paste here the certificate downloaded from the Atos SIPS platform' => 'Vous pouvez coller ici le texte du certificat téléhergé depuis la plate-forme ATOS',
|
||||
'Production' => 'Production',
|
||||
'Request binary not found in "%path"' => 'le binaire request n\'est pas trouvé dans "%path"',
|
||||
'Request does not contains any data' => 'La requête ne contient aucune donnée',
|
||||
'Response parameters : %resp' => 'Paramètres de la réponse : %resp',
|
||||
'Response request not found in %response' => 'La réponse ATOS n\'a pas été trouvée dans %response',
|
||||
'Send a payment confirmation e-mail' => 'Envoyer une confirmation de paiement',
|
||||
'Send order confirmation on payment success' => 'Confirmation de commande si le paiement réussit ',
|
||||
'Shop Merchant ID' => 'Identifiant Marchand',
|
||||
'Test' => 'Test',
|
||||
'Test or production mode' => 'Test ou production',
|
||||
'The \'%file\' should be executable. Please check file permission' => 'Le fichier %file doit être exécutable. Vérifier que ce fichier a les permission nécessaires/.',
|
||||
'The log file \'%log\' does not exists yet.' => 'Le fichier de log %log n\'existe pas encore.',
|
||||
'The log file is currently empty.' => 'Le fichier de log est vide',
|
||||
'User canceled payment of order %id' => 'Le client a annulé le paiement de la commande ID %id',
|
||||
'you cancel the payment' => 'Vous avez annulé le paiement',
|
||||
);
|
||||
165
local/modules/Atos/LICENSE.txt
Normal file
@@ -0,0 +1,165 @@
|
||||
GNU LESSER GENERAL PUBLIC LICENSE
|
||||
Version 3, 29 June 2007
|
||||
|
||||
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
|
||||
This version of the GNU Lesser General Public License incorporates
|
||||
the terms and conditions of version 3 of the GNU General Public
|
||||
License, supplemented by the additional permissions listed below.
|
||||
|
||||
0. Additional Definitions.
|
||||
|
||||
As used herein, "this License" refers to version 3 of the GNU Lesser
|
||||
General Public License, and the "GNU GPL" refers to version 3 of the GNU
|
||||
General Public License.
|
||||
|
||||
"The Library" refers to a covered work governed by this License,
|
||||
other than an Application or a Combined Work as defined below.
|
||||
|
||||
An "Application" is any work that makes use of an interface provided
|
||||
by the Library, but which is not otherwise based on the Library.
|
||||
Defining a subclass of a class defined by the Library is deemed a mode
|
||||
of using an interface provided by the Library.
|
||||
|
||||
A "Combined Work" is a work produced by combining or linking an
|
||||
Application with the Library. The particular version of the Library
|
||||
with which the Combined Work was made is also called the "Linked
|
||||
Version".
|
||||
|
||||
The "Minimal Corresponding Source" for a Combined Work means the
|
||||
Corresponding Source for the Combined Work, excluding any source code
|
||||
for portions of the Combined Work that, considered in isolation, are
|
||||
based on the Application, and not on the Linked Version.
|
||||
|
||||
The "Corresponding Application Code" for a Combined Work means the
|
||||
object code and/or source code for the Application, including any data
|
||||
and utility programs needed for reproducing the Combined Work from the
|
||||
Application, but excluding the System Libraries of the Combined Work.
|
||||
|
||||
1. Exception to Section 3 of the GNU GPL.
|
||||
|
||||
You may convey a covered work under sections 3 and 4 of this License
|
||||
without being bound by section 3 of the GNU GPL.
|
||||
|
||||
2. Conveying Modified Versions.
|
||||
|
||||
If you modify a copy of the Library, and, in your modifications, a
|
||||
facility refers to a function or data to be supplied by an Application
|
||||
that uses the facility (other than as an argument passed when the
|
||||
facility is invoked), then you may convey a copy of the modified
|
||||
version:
|
||||
|
||||
a) under this License, provided that you make a good faith effort to
|
||||
ensure that, in the event an Application does not supply the
|
||||
function or data, the facility still operates, and performs
|
||||
whatever part of its purpose remains meaningful, or
|
||||
|
||||
b) under the GNU GPL, with none of the additional permissions of
|
||||
this License applicable to that copy.
|
||||
|
||||
3. Object Code Incorporating Material from Library Header Files.
|
||||
|
||||
The object code form of an Application may incorporate material from
|
||||
a header file that is part of the Library. You may convey such object
|
||||
code under terms of your choice, provided that, if the incorporated
|
||||
material is not limited to numerical parameters, data structure
|
||||
layouts and accessors, or small macros, inline functions and templates
|
||||
(ten or fewer lines in length), you do both of the following:
|
||||
|
||||
a) Give prominent notice with each copy of the object code that the
|
||||
Library is used in it and that the Library and its use are
|
||||
covered by this License.
|
||||
|
||||
b) Accompany the object code with a copy of the GNU GPL and this license
|
||||
document.
|
||||
|
||||
4. Combined Works.
|
||||
|
||||
You may convey a Combined Work under terms of your choice that,
|
||||
taken together, effectively do not restrict modification of the
|
||||
portions of the Library contained in the Combined Work and reverse
|
||||
engineering for debugging such modifications, if you also do each of
|
||||
the following:
|
||||
|
||||
a) Give prominent notice with each copy of the Combined Work that
|
||||
the Library is used in it and that the Library and its use are
|
||||
covered by this License.
|
||||
|
||||
b) Accompany the Combined Work with a copy of the GNU GPL and this license
|
||||
document.
|
||||
|
||||
c) For a Combined Work that displays copyright notices during
|
||||
execution, include the copyright notice for the Library among
|
||||
these notices, as well as a reference directing the user to the
|
||||
copies of the GNU GPL and this license document.
|
||||
|
||||
d) Do one of the following:
|
||||
|
||||
0) Convey the Minimal Corresponding Source under the terms of this
|
||||
License, and the Corresponding Application Code in a form
|
||||
suitable for, and under terms that permit, the user to
|
||||
recombine or relink the Application with a modified version of
|
||||
the Linked Version to produce a modified Combined Work, in the
|
||||
manner specified by section 6 of the GNU GPL for conveying
|
||||
Corresponding Source.
|
||||
|
||||
1) Use a suitable shared library mechanism for linking with the
|
||||
Library. A suitable mechanism is one that (a) uses at run time
|
||||
a copy of the Library already present on the user's computer
|
||||
system, and (b) will operate properly with a modified version
|
||||
of the Library that is interface-compatible with the Linked
|
||||
Version.
|
||||
|
||||
e) Provide Installation Information, but only if you would otherwise
|
||||
be required to provide such information under section 6 of the
|
||||
GNU GPL, and only to the extent that such information is
|
||||
necessary to install and execute a modified version of the
|
||||
Combined Work produced by recombining or relinking the
|
||||
Application with a modified version of the Linked Version. (If
|
||||
you use option 4d0, the Installation Information must accompany
|
||||
the Minimal Corresponding Source and Corresponding Application
|
||||
Code. If you use option 4d1, you must provide the Installation
|
||||
Information in the manner specified by section 6 of the GNU GPL
|
||||
for conveying Corresponding Source.)
|
||||
|
||||
5. Combined Libraries.
|
||||
|
||||
You may place library facilities that are a work based on the
|
||||
Library side by side in a single library together with other library
|
||||
facilities that are not Applications and are not covered by this
|
||||
License, and convey such a combined library under terms of your
|
||||
choice, if you do both of the following:
|
||||
|
||||
a) Accompany the combined library with a copy of the same work based
|
||||
on the Library, uncombined with any other library facilities,
|
||||
conveyed under the terms of this License.
|
||||
|
||||
b) Give prominent notice with the combined library that part of it
|
||||
is a work based on the Library, and explaining where to find the
|
||||
accompanying uncombined form of the same work.
|
||||
|
||||
6. Revised Versions of the GNU Lesser General Public License.
|
||||
|
||||
The Free Software Foundation may publish revised and/or new versions
|
||||
of the GNU Lesser General Public License from time to time. Such new
|
||||
versions will be similar in spirit to the present version, but may
|
||||
differ in detail to address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the
|
||||
Library as you received it specifies that a certain numbered version
|
||||
of the GNU Lesser General Public License "or any later version"
|
||||
applies to it, you have the option of following the terms and
|
||||
conditions either of that published version or of any later version
|
||||
published by the Free Software Foundation. If the Library as you
|
||||
received it does not specify a version number of the GNU Lesser
|
||||
General Public License, you may choose any version of the GNU Lesser
|
||||
General Public License ever published by the Free Software Foundation.
|
||||
|
||||
If the Library as you received it specifies that a proxy can decide
|
||||
whether future versions of the GNU Lesser General Public License shall
|
||||
apply, that proxy's public statement of acceptance of any version is
|
||||
permanent authorization for you to choose that version for the
|
||||
Library.
|
||||
10
local/modules/Atos/Model/AtosCurrency.php
Normal file
@@ -0,0 +1,10 @@
|
||||
<?php
|
||||
|
||||
namespace Atos\Model;
|
||||
|
||||
use Atos\Model\Base\AtosCurrency as BaseAtosCurrency;
|
||||
|
||||
class AtosCurrency extends BaseAtosCurrency
|
||||
{
|
||||
|
||||
}
|
||||
20
local/modules/Atos/Model/AtosCurrencyQuery.php
Normal file
@@ -0,0 +1,20 @@
|
||||
<?php
|
||||
|
||||
namespace Atos\Model;
|
||||
|
||||
use Atos\Model\Base\AtosCurrencyQuery as BaseAtosCurrencyQuery;
|
||||
|
||||
/**
|
||||
* Skeleton subclass for performing query and update operations on the 'atos_currency' 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 AtosCurrencyQuery extends BaseAtosCurrencyQuery
|
||||
{
|
||||
|
||||
} // AtosCurrencyQuery
|
||||
1144
local/modules/Atos/Model/Base/AtosCurrency.php
Normal file
419
local/modules/Atos/Model/Base/AtosCurrencyQuery.php
Normal file
@@ -0,0 +1,419 @@
|
||||
<?php
|
||||
|
||||
namespace Atos\Model\Base;
|
||||
|
||||
use \Exception;
|
||||
use \PDO;
|
||||
use Atos\Model\AtosCurrency as ChildAtosCurrency;
|
||||
use Atos\Model\AtosCurrencyQuery as ChildAtosCurrencyQuery;
|
||||
use Atos\Model\Map\AtosCurrencyTableMap;
|
||||
use Propel\Runtime\Propel;
|
||||
use Propel\Runtime\ActiveQuery\Criteria;
|
||||
use Propel\Runtime\ActiveQuery\ModelCriteria;
|
||||
use Propel\Runtime\Connection\ConnectionInterface;
|
||||
use Propel\Runtime\Exception\PropelException;
|
||||
|
||||
/**
|
||||
* Base class that represents a query for the 'atos_currency' table.
|
||||
*
|
||||
*
|
||||
*
|
||||
* @method ChildAtosCurrencyQuery orderByCode($order = Criteria::ASC) Order by the code column
|
||||
* @method ChildAtosCurrencyQuery orderByAtosCode($order = Criteria::ASC) Order by the atos_code column
|
||||
* @method ChildAtosCurrencyQuery orderByDecimals($order = Criteria::ASC) Order by the decimals column
|
||||
*
|
||||
* @method ChildAtosCurrencyQuery groupByCode() Group by the code column
|
||||
* @method ChildAtosCurrencyQuery groupByAtosCode() Group by the atos_code column
|
||||
* @method ChildAtosCurrencyQuery groupByDecimals() Group by the decimals column
|
||||
*
|
||||
* @method ChildAtosCurrencyQuery leftJoin($relation) Adds a LEFT JOIN clause to the query
|
||||
* @method ChildAtosCurrencyQuery rightJoin($relation) Adds a RIGHT JOIN clause to the query
|
||||
* @method ChildAtosCurrencyQuery innerJoin($relation) Adds a INNER JOIN clause to the query
|
||||
*
|
||||
* @method ChildAtosCurrency findOne(ConnectionInterface $con = null) Return the first ChildAtosCurrency matching the query
|
||||
* @method ChildAtosCurrency findOneOrCreate(ConnectionInterface $con = null) Return the first ChildAtosCurrency matching the query, or a new ChildAtosCurrency object populated from the query conditions when no match is found
|
||||
*
|
||||
* @method ChildAtosCurrency findOneByCode(string $code) Return the first ChildAtosCurrency filtered by the code column
|
||||
* @method ChildAtosCurrency findOneByAtosCode(int $atos_code) Return the first ChildAtosCurrency filtered by the atos_code column
|
||||
* @method ChildAtosCurrency findOneByDecimals(int $decimals) Return the first ChildAtosCurrency filtered by the decimals column
|
||||
*
|
||||
* @method array findByCode(string $code) Return ChildAtosCurrency objects filtered by the code column
|
||||
* @method array findByAtosCode(int $atos_code) Return ChildAtosCurrency objects filtered by the atos_code column
|
||||
* @method array findByDecimals(int $decimals) Return ChildAtosCurrency objects filtered by the decimals column
|
||||
*
|
||||
*/
|
||||
abstract class AtosCurrencyQuery extends ModelCriteria
|
||||
{
|
||||
|
||||
/**
|
||||
* Initializes internal state of \Atos\Model\Base\AtosCurrencyQuery object.
|
||||
*
|
||||
* @param string $dbName The database name
|
||||
* @param string $modelName The phpName of a model, e.g. 'Book'
|
||||
* @param string $modelAlias The alias for the model in this query, e.g. 'b'
|
||||
*/
|
||||
public function __construct($dbName = 'thelia', $modelName = '\\Atos\\Model\\AtosCurrency', $modelAlias = null)
|
||||
{
|
||||
parent::__construct($dbName, $modelName, $modelAlias);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new ChildAtosCurrencyQuery object.
|
||||
*
|
||||
* @param string $modelAlias The alias of a model in the query
|
||||
* @param Criteria $criteria Optional Criteria to build the query from
|
||||
*
|
||||
* @return ChildAtosCurrencyQuery
|
||||
*/
|
||||
public static function create($modelAlias = null, $criteria = null)
|
||||
{
|
||||
if ($criteria instanceof \Atos\Model\AtosCurrencyQuery) {
|
||||
return $criteria;
|
||||
}
|
||||
$query = new \Atos\Model\AtosCurrencyQuery();
|
||||
if (null !== $modelAlias) {
|
||||
$query->setModelAlias($modelAlias);
|
||||
}
|
||||
if ($criteria instanceof Criteria) {
|
||||
$query->mergeWith($criteria);
|
||||
}
|
||||
|
||||
return $query;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find object by primary key.
|
||||
* Propel uses the instance pool to skip the database if the object exists.
|
||||
* Go fast if the query is untouched.
|
||||
*
|
||||
* <code>
|
||||
* $obj = $c->findPk(12, $con);
|
||||
* </code>
|
||||
*
|
||||
* @param mixed $key Primary key to use for the query
|
||||
* @param ConnectionInterface $con an optional connection object
|
||||
*
|
||||
* @return ChildAtosCurrency|array|mixed the result, formatted by the current formatter
|
||||
*/
|
||||
public function findPk($key, $con = null)
|
||||
{
|
||||
if ($key === null) {
|
||||
return null;
|
||||
}
|
||||
if ((null !== ($obj = AtosCurrencyTableMap::getInstanceFromPool((string) $key))) && !$this->formatter) {
|
||||
// the object is already in the instance pool
|
||||
return $obj;
|
||||
}
|
||||
if ($con === null) {
|
||||
$con = Propel::getServiceContainer()->getReadConnection(AtosCurrencyTableMap::DATABASE_NAME);
|
||||
}
|
||||
$this->basePreSelect($con);
|
||||
if ($this->formatter || $this->modelAlias || $this->with || $this->select
|
||||
|| $this->selectColumns || $this->asColumns || $this->selectModifiers
|
||||
|| $this->map || $this->having || $this->joins) {
|
||||
return $this->findPkComplex($key, $con);
|
||||
} else {
|
||||
return $this->findPkSimple($key, $con);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Find object by primary key using raw SQL to go fast.
|
||||
* Bypass doSelect() and the object formatter by using generated code.
|
||||
*
|
||||
* @param mixed $key Primary key to use for the query
|
||||
* @param ConnectionInterface $con A connection object
|
||||
*
|
||||
* @return ChildAtosCurrency A model object, or null if the key is not found
|
||||
*/
|
||||
protected function findPkSimple($key, $con)
|
||||
{
|
||||
$sql = 'SELECT CODE, ATOS_CODE, DECIMALS FROM atos_currency WHERE CODE = :p0';
|
||||
try {
|
||||
$stmt = $con->prepare($sql);
|
||||
$stmt->bindValue(':p0', $key, PDO::PARAM_STR);
|
||||
$stmt->execute();
|
||||
} catch (Exception $e) {
|
||||
Propel::log($e->getMessage(), Propel::LOG_ERR);
|
||||
throw new PropelException(sprintf('Unable to execute SELECT statement [%s]', $sql), 0, $e);
|
||||
}
|
||||
$obj = null;
|
||||
if ($row = $stmt->fetch(\PDO::FETCH_NUM)) {
|
||||
$obj = new ChildAtosCurrency();
|
||||
$obj->hydrate($row);
|
||||
AtosCurrencyTableMap::addInstanceToPool($obj, (string) $key);
|
||||
}
|
||||
$stmt->closeCursor();
|
||||
|
||||
return $obj;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find object by primary key.
|
||||
*
|
||||
* @param mixed $key Primary key to use for the query
|
||||
* @param ConnectionInterface $con A connection object
|
||||
*
|
||||
* @return ChildAtosCurrency|array|mixed the result, formatted by the current formatter
|
||||
*/
|
||||
protected function findPkComplex($key, $con)
|
||||
{
|
||||
// As the query uses a PK condition, no limit(1) is necessary.
|
||||
$criteria = $this->isKeepQuery() ? clone $this : $this;
|
||||
$dataFetcher = $criteria
|
||||
->filterByPrimaryKey($key)
|
||||
->doSelect($con);
|
||||
|
||||
return $criteria->getFormatter()->init($criteria)->formatOne($dataFetcher);
|
||||
}
|
||||
|
||||
/**
|
||||
* Find objects by primary key
|
||||
* <code>
|
||||
* $objs = $c->findPks(array(12, 56, 832), $con);
|
||||
* </code>
|
||||
* @param array $keys Primary keys to use for the query
|
||||
* @param ConnectionInterface $con an optional connection object
|
||||
*
|
||||
* @return ObjectCollection|array|mixed the list of results, formatted by the current formatter
|
||||
*/
|
||||
public function findPks($keys, $con = null)
|
||||
{
|
||||
if (null === $con) {
|
||||
$con = Propel::getServiceContainer()->getReadConnection($this->getDbName());
|
||||
}
|
||||
$this->basePreSelect($con);
|
||||
$criteria = $this->isKeepQuery() ? clone $this : $this;
|
||||
$dataFetcher = $criteria
|
||||
->filterByPrimaryKeys($keys)
|
||||
->doSelect($con);
|
||||
|
||||
return $criteria->getFormatter()->init($criteria)->format($dataFetcher);
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter the query by primary key
|
||||
*
|
||||
* @param mixed $key Primary key to use for the query
|
||||
*
|
||||
* @return ChildAtosCurrencyQuery The current query, for fluid interface
|
||||
*/
|
||||
public function filterByPrimaryKey($key)
|
||||
{
|
||||
return $this->addUsingAlias(AtosCurrencyTableMap::CODE, $key, Criteria::EQUAL);
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter the query by a list of primary keys
|
||||
*
|
||||
* @param array $keys The list of primary key to use for the query
|
||||
*
|
||||
* @return ChildAtosCurrencyQuery The current query, for fluid interface
|
||||
*/
|
||||
public function filterByPrimaryKeys($keys)
|
||||
{
|
||||
return $this->addUsingAlias(AtosCurrencyTableMap::CODE, $keys, Criteria::IN);
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter the query on the code column
|
||||
*
|
||||
* Example usage:
|
||||
* <code>
|
||||
* $query->filterByCode('fooValue'); // WHERE code = 'fooValue'
|
||||
* $query->filterByCode('%fooValue%'); // WHERE code LIKE '%fooValue%'
|
||||
* </code>
|
||||
*
|
||||
* @param string $code The value to use as filter.
|
||||
* Accepts wildcards (* and % trigger a LIKE)
|
||||
* @param string $comparison Operator to use for the column comparison, defaults to Criteria::EQUAL
|
||||
*
|
||||
* @return ChildAtosCurrencyQuery The current query, for fluid interface
|
||||
*/
|
||||
public function filterByCode($code = null, $comparison = null)
|
||||
{
|
||||
if (null === $comparison) {
|
||||
if (is_array($code)) {
|
||||
$comparison = Criteria::IN;
|
||||
} elseif (preg_match('/[\%\*]/', $code)) {
|
||||
$code = str_replace('*', '%', $code);
|
||||
$comparison = Criteria::LIKE;
|
||||
}
|
||||
}
|
||||
|
||||
return $this->addUsingAlias(AtosCurrencyTableMap::CODE, $code, $comparison);
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter the query on the atos_code column
|
||||
*
|
||||
* Example usage:
|
||||
* <code>
|
||||
* $query->filterByAtosCode(1234); // WHERE atos_code = 1234
|
||||
* $query->filterByAtosCode(array(12, 34)); // WHERE atos_code IN (12, 34)
|
||||
* $query->filterByAtosCode(array('min' => 12)); // WHERE atos_code > 12
|
||||
* </code>
|
||||
*
|
||||
* @param mixed $atosCode The value to use as filter.
|
||||
* Use scalar values for equality.
|
||||
* Use array values for in_array() equivalent.
|
||||
* Use associative array('min' => $minValue, 'max' => $maxValue) for intervals.
|
||||
* @param string $comparison Operator to use for the column comparison, defaults to Criteria::EQUAL
|
||||
*
|
||||
* @return ChildAtosCurrencyQuery The current query, for fluid interface
|
||||
*/
|
||||
public function filterByAtosCode($atosCode = null, $comparison = null)
|
||||
{
|
||||
if (is_array($atosCode)) {
|
||||
$useMinMax = false;
|
||||
if (isset($atosCode['min'])) {
|
||||
$this->addUsingAlias(AtosCurrencyTableMap::ATOS_CODE, $atosCode['min'], Criteria::GREATER_EQUAL);
|
||||
$useMinMax = true;
|
||||
}
|
||||
if (isset($atosCode['max'])) {
|
||||
$this->addUsingAlias(AtosCurrencyTableMap::ATOS_CODE, $atosCode['max'], Criteria::LESS_EQUAL);
|
||||
$useMinMax = true;
|
||||
}
|
||||
if ($useMinMax) {
|
||||
return $this;
|
||||
}
|
||||
if (null === $comparison) {
|
||||
$comparison = Criteria::IN;
|
||||
}
|
||||
}
|
||||
|
||||
return $this->addUsingAlias(AtosCurrencyTableMap::ATOS_CODE, $atosCode, $comparison);
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter the query on the decimals column
|
||||
*
|
||||
* Example usage:
|
||||
* <code>
|
||||
* $query->filterByDecimals(1234); // WHERE decimals = 1234
|
||||
* $query->filterByDecimals(array(12, 34)); // WHERE decimals IN (12, 34)
|
||||
* $query->filterByDecimals(array('min' => 12)); // WHERE decimals > 12
|
||||
* </code>
|
||||
*
|
||||
* @param mixed $decimals The value to use as filter.
|
||||
* Use scalar values for equality.
|
||||
* Use array values for in_array() equivalent.
|
||||
* Use associative array('min' => $minValue, 'max' => $maxValue) for intervals.
|
||||
* @param string $comparison Operator to use for the column comparison, defaults to Criteria::EQUAL
|
||||
*
|
||||
* @return ChildAtosCurrencyQuery The current query, for fluid interface
|
||||
*/
|
||||
public function filterByDecimals($decimals = null, $comparison = null)
|
||||
{
|
||||
if (is_array($decimals)) {
|
||||
$useMinMax = false;
|
||||
if (isset($decimals['min'])) {
|
||||
$this->addUsingAlias(AtosCurrencyTableMap::DECIMALS, $decimals['min'], Criteria::GREATER_EQUAL);
|
||||
$useMinMax = true;
|
||||
}
|
||||
if (isset($decimals['max'])) {
|
||||
$this->addUsingAlias(AtosCurrencyTableMap::DECIMALS, $decimals['max'], Criteria::LESS_EQUAL);
|
||||
$useMinMax = true;
|
||||
}
|
||||
if ($useMinMax) {
|
||||
return $this;
|
||||
}
|
||||
if (null === $comparison) {
|
||||
$comparison = Criteria::IN;
|
||||
}
|
||||
}
|
||||
|
||||
return $this->addUsingAlias(AtosCurrencyTableMap::DECIMALS, $decimals, $comparison);
|
||||
}
|
||||
|
||||
/**
|
||||
* Exclude object from result
|
||||
*
|
||||
* @param ChildAtosCurrency $atosCurrency Object to remove from the list of results
|
||||
*
|
||||
* @return ChildAtosCurrencyQuery The current query, for fluid interface
|
||||
*/
|
||||
public function prune($atosCurrency = null)
|
||||
{
|
||||
if ($atosCurrency) {
|
||||
$this->addUsingAlias(AtosCurrencyTableMap::CODE, $atosCurrency->getCode(), Criteria::NOT_EQUAL);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes all rows from the atos_currency table.
|
||||
*
|
||||
* @param ConnectionInterface $con the connection to use
|
||||
* @return int The number of affected rows (if supported by underlying database driver).
|
||||
*/
|
||||
public function doDeleteAll(ConnectionInterface $con = null)
|
||||
{
|
||||
if (null === $con) {
|
||||
$con = Propel::getServiceContainer()->getWriteConnection(AtosCurrencyTableMap::DATABASE_NAME);
|
||||
}
|
||||
$affectedRows = 0; // initialize var to track total num of affected rows
|
||||
try {
|
||||
// use transaction because $criteria could contain info
|
||||
// for more than one table or we could emulating ON DELETE CASCADE, etc.
|
||||
$con->beginTransaction();
|
||||
$affectedRows += parent::doDeleteAll($con);
|
||||
// Because this db requires some delete cascade/set null emulation, we have to
|
||||
// clear the cached instance *after* the emulation has happened (since
|
||||
// instances get re-added by the select statement contained therein).
|
||||
AtosCurrencyTableMap::clearInstancePool();
|
||||
AtosCurrencyTableMap::clearRelatedInstancePool();
|
||||
|
||||
$con->commit();
|
||||
} catch (PropelException $e) {
|
||||
$con->rollBack();
|
||||
throw $e;
|
||||
}
|
||||
|
||||
return $affectedRows;
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs a DELETE on the database, given a ChildAtosCurrency or Criteria object OR a primary key value.
|
||||
*
|
||||
* @param mixed $values Criteria or ChildAtosCurrency object or primary key or array of primary keys
|
||||
* which is used to create the DELETE statement
|
||||
* @param ConnectionInterface $con the connection to use
|
||||
* @return int The number of affected rows (if supported by underlying database driver). This includes CASCADE-related rows
|
||||
* if supported by native driver or if emulated using Propel.
|
||||
* @throws PropelException Any exceptions caught during processing will be
|
||||
* rethrown wrapped into a PropelException.
|
||||
*/
|
||||
public function delete(ConnectionInterface $con = null)
|
||||
{
|
||||
if (null === $con) {
|
||||
$con = Propel::getServiceContainer()->getWriteConnection(AtosCurrencyTableMap::DATABASE_NAME);
|
||||
}
|
||||
|
||||
$criteria = $this;
|
||||
|
||||
// Set the correct dbName
|
||||
$criteria->setDbName(AtosCurrencyTableMap::DATABASE_NAME);
|
||||
|
||||
$affectedRows = 0; // initialize var to track total num of affected rows
|
||||
|
||||
try {
|
||||
// use transaction because $criteria could contain info
|
||||
// for more than one table or we could emulating ON DELETE CASCADE, etc.
|
||||
$con->beginTransaction();
|
||||
|
||||
AtosCurrencyTableMap::removeInstanceFromPool($criteria);
|
||||
|
||||
$affectedRows += ModelCriteria::delete($con);
|
||||
AtosCurrencyTableMap::clearRelatedInstancePool();
|
||||
$con->commit();
|
||||
|
||||
return $affectedRows;
|
||||
} catch (PropelException $e) {
|
||||
$con->rollBack();
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
|
||||
} // AtosCurrencyQuery
|
||||
411
local/modules/Atos/Model/Map/AtosCurrencyTableMap.php
Normal file
@@ -0,0 +1,411 @@
|
||||
<?php
|
||||
|
||||
namespace Atos\Model\Map;
|
||||
|
||||
use Atos\Model\AtosCurrency;
|
||||
use Atos\Model\AtosCurrencyQuery;
|
||||
use Propel\Runtime\Propel;
|
||||
use Propel\Runtime\ActiveQuery\Criteria;
|
||||
use Propel\Runtime\ActiveQuery\InstancePoolTrait;
|
||||
use Propel\Runtime\Connection\ConnectionInterface;
|
||||
use Propel\Runtime\DataFetcher\DataFetcherInterface;
|
||||
use Propel\Runtime\Exception\PropelException;
|
||||
use Propel\Runtime\Map\RelationMap;
|
||||
use Propel\Runtime\Map\TableMap;
|
||||
use Propel\Runtime\Map\TableMapTrait;
|
||||
|
||||
/**
|
||||
* This class defines the structure of the 'atos_currency' table.
|
||||
*
|
||||
*
|
||||
*
|
||||
* This map class is used by Propel to do runtime db structure discovery.
|
||||
* For example, the createSelectSql() method checks the type of a given column used in an
|
||||
* ORDER BY clause to know whether it needs to apply SQL to make the ORDER BY case-insensitive
|
||||
* (i.e. if it's a text column type).
|
||||
*
|
||||
*/
|
||||
class AtosCurrencyTableMap extends TableMap
|
||||
{
|
||||
use InstancePoolTrait;
|
||||
use TableMapTrait;
|
||||
/**
|
||||
* The (dot-path) name of this class
|
||||
*/
|
||||
const CLASS_NAME = 'Atos.Model.Map.AtosCurrencyTableMap';
|
||||
|
||||
/**
|
||||
* The default database name for this class
|
||||
*/
|
||||
const DATABASE_NAME = 'thelia';
|
||||
|
||||
/**
|
||||
* The table name for this class
|
||||
*/
|
||||
const TABLE_NAME = 'atos_currency';
|
||||
|
||||
/**
|
||||
* The related Propel class for this table
|
||||
*/
|
||||
const OM_CLASS = '\\Atos\\Model\\AtosCurrency';
|
||||
|
||||
/**
|
||||
* A class that can be returned by this tableMap
|
||||
*/
|
||||
const CLASS_DEFAULT = 'Atos.Model.AtosCurrency';
|
||||
|
||||
/**
|
||||
* The total number of columns
|
||||
*/
|
||||
const NUM_COLUMNS = 3;
|
||||
|
||||
/**
|
||||
* The number of lazy-loaded columns
|
||||
*/
|
||||
const NUM_LAZY_LOAD_COLUMNS = 0;
|
||||
|
||||
/**
|
||||
* The number of columns to hydrate (NUM_COLUMNS - NUM_LAZY_LOAD_COLUMNS)
|
||||
*/
|
||||
const NUM_HYDRATE_COLUMNS = 3;
|
||||
|
||||
/**
|
||||
* the column name for the CODE field
|
||||
*/
|
||||
const CODE = 'atos_currency.CODE';
|
||||
|
||||
/**
|
||||
* the column name for the ATOS_CODE field
|
||||
*/
|
||||
const ATOS_CODE = 'atos_currency.ATOS_CODE';
|
||||
|
||||
/**
|
||||
* the column name for the DECIMALS field
|
||||
*/
|
||||
const DECIMALS = 'atos_currency.DECIMALS';
|
||||
|
||||
/**
|
||||
* The default string format for model objects of the related table
|
||||
*/
|
||||
const DEFAULT_STRING_FORMAT = 'YAML';
|
||||
|
||||
/**
|
||||
* holds an array of fieldnames
|
||||
*
|
||||
* first dimension keys are the type constants
|
||||
* e.g. self::$fieldNames[self::TYPE_PHPNAME][0] = 'Id'
|
||||
*/
|
||||
protected static $fieldNames = array (
|
||||
self::TYPE_PHPNAME => array('Code', 'AtosCode', 'Decimals', ),
|
||||
self::TYPE_STUDLYPHPNAME => array('code', 'atosCode', 'decimals', ),
|
||||
self::TYPE_COLNAME => array(AtosCurrencyTableMap::CODE, AtosCurrencyTableMap::ATOS_CODE, AtosCurrencyTableMap::DECIMALS, ),
|
||||
self::TYPE_RAW_COLNAME => array('CODE', 'ATOS_CODE', 'DECIMALS', ),
|
||||
self::TYPE_FIELDNAME => array('code', 'atos_code', 'decimals', ),
|
||||
self::TYPE_NUM => array(0, 1, 2, )
|
||||
);
|
||||
|
||||
/**
|
||||
* holds an array of keys for quick access to the fieldnames array
|
||||
*
|
||||
* first dimension keys are the type constants
|
||||
* e.g. self::$fieldKeys[self::TYPE_PHPNAME]['Id'] = 0
|
||||
*/
|
||||
protected static $fieldKeys = array (
|
||||
self::TYPE_PHPNAME => array('Code' => 0, 'AtosCode' => 1, 'Decimals' => 2, ),
|
||||
self::TYPE_STUDLYPHPNAME => array('code' => 0, 'atosCode' => 1, 'decimals' => 2, ),
|
||||
self::TYPE_COLNAME => array(AtosCurrencyTableMap::CODE => 0, AtosCurrencyTableMap::ATOS_CODE => 1, AtosCurrencyTableMap::DECIMALS => 2, ),
|
||||
self::TYPE_RAW_COLNAME => array('CODE' => 0, 'ATOS_CODE' => 1, 'DECIMALS' => 2, ),
|
||||
self::TYPE_FIELDNAME => array('code' => 0, 'atos_code' => 1, 'decimals' => 2, ),
|
||||
self::TYPE_NUM => array(0, 1, 2, )
|
||||
);
|
||||
|
||||
/**
|
||||
* Initialize the table attributes and columns
|
||||
* Relations are not initialized by this method since they are lazy loaded
|
||||
*
|
||||
* @return void
|
||||
* @throws PropelException
|
||||
*/
|
||||
public function initialize()
|
||||
{
|
||||
// attributes
|
||||
$this->setName('atos_currency');
|
||||
$this->setPhpName('AtosCurrency');
|
||||
$this->setClassName('\\Atos\\Model\\AtosCurrency');
|
||||
$this->setPackage('Atos.Model');
|
||||
$this->setUseIdGenerator(false);
|
||||
// columns
|
||||
$this->addPrimaryKey('CODE', 'Code', 'VARCHAR', true, 128, null);
|
||||
$this->addColumn('ATOS_CODE', 'AtosCode', 'INTEGER', false, null, null);
|
||||
$this->addColumn('DECIMALS', 'Decimals', 'INTEGER', false, null, null);
|
||||
} // initialize()
|
||||
|
||||
/**
|
||||
* Build the RelationMap objects for this table relationships
|
||||
*/
|
||||
public function buildRelations()
|
||||
{
|
||||
} // buildRelations()
|
||||
|
||||
/**
|
||||
* Retrieves a string version of the primary key from the DB resultset row that can be used to uniquely identify a row in this table.
|
||||
*
|
||||
* For tables with a single-column primary key, that simple pkey value will be returned. For tables with
|
||||
* a multi-column primary key, a serialize()d version of the primary key will be returned.
|
||||
*
|
||||
* @param array $row resultset row.
|
||||
* @param int $offset The 0-based offset for reading from the resultset row.
|
||||
* @param string $indexType One of the class type constants TableMap::TYPE_PHPNAME, TableMap::TYPE_STUDLYPHPNAME
|
||||
* TableMap::TYPE_COLNAME, TableMap::TYPE_FIELDNAME, TableMap::TYPE_NUM
|
||||
*/
|
||||
public static function getPrimaryKeyHashFromRow($row, $offset = 0, $indexType = TableMap::TYPE_NUM)
|
||||
{
|
||||
// If the PK cannot be derived from the row, return NULL.
|
||||
if ($row[TableMap::TYPE_NUM == $indexType ? 0 + $offset : static::translateFieldName('Code', TableMap::TYPE_PHPNAME, $indexType)] === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (string) $row[TableMap::TYPE_NUM == $indexType ? 0 + $offset : static::translateFieldName('Code', TableMap::TYPE_PHPNAME, $indexType)];
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the primary key from the DB resultset row
|
||||
* For tables with a single-column primary key, that simple pkey value will be returned. For tables with
|
||||
* a multi-column primary key, an array of the primary key columns will be returned.
|
||||
*
|
||||
* @param array $row resultset row.
|
||||
* @param int $offset The 0-based offset for reading from the resultset row.
|
||||
* @param string $indexType One of the class type constants TableMap::TYPE_PHPNAME, TableMap::TYPE_STUDLYPHPNAME
|
||||
* TableMap::TYPE_COLNAME, TableMap::TYPE_FIELDNAME, TableMap::TYPE_NUM
|
||||
*
|
||||
* @return mixed The primary key of the row
|
||||
*/
|
||||
public static function getPrimaryKeyFromRow($row, $offset = 0, $indexType = TableMap::TYPE_NUM)
|
||||
{
|
||||
return (string) $row[
|
||||
$indexType == TableMap::TYPE_NUM
|
||||
? 0 + $offset
|
||||
: self::translateFieldName('Code', TableMap::TYPE_PHPNAME, $indexType)
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* The class that the tableMap will make instances of.
|
||||
*
|
||||
* If $withPrefix is true, the returned path
|
||||
* uses a dot-path notation which is translated into a path
|
||||
* relative to a location on the PHP include_path.
|
||||
* (e.g. path.to.MyClass -> 'path/to/MyClass.php')
|
||||
*
|
||||
* @param boolean $withPrefix Whether or not to return the path with the class name
|
||||
* @return string path.to.ClassName
|
||||
*/
|
||||
public static function getOMClass($withPrefix = true)
|
||||
{
|
||||
return $withPrefix ? AtosCurrencyTableMap::CLASS_DEFAULT : AtosCurrencyTableMap::OM_CLASS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Populates an object of the default type or an object that inherit from the default.
|
||||
*
|
||||
* @param array $row row returned by DataFetcher->fetch().
|
||||
* @param int $offset The 0-based offset for reading from the resultset row.
|
||||
* @param string $indexType The index type of $row. Mostly DataFetcher->getIndexType().
|
||||
One of the class type constants TableMap::TYPE_PHPNAME, TableMap::TYPE_STUDLYPHPNAME
|
||||
* TableMap::TYPE_COLNAME, TableMap::TYPE_FIELDNAME, TableMap::TYPE_NUM.
|
||||
*
|
||||
* @throws PropelException Any exceptions caught during processing will be
|
||||
* rethrown wrapped into a PropelException.
|
||||
* @return array (AtosCurrency object, last column rank)
|
||||
*/
|
||||
public static function populateObject($row, $offset = 0, $indexType = TableMap::TYPE_NUM)
|
||||
{
|
||||
$key = AtosCurrencyTableMap::getPrimaryKeyHashFromRow($row, $offset, $indexType);
|
||||
if (null !== ($obj = AtosCurrencyTableMap::getInstanceFromPool($key))) {
|
||||
// We no longer rehydrate the object, since this can cause data loss.
|
||||
// See http://www.propelorm.org/ticket/509
|
||||
// $obj->hydrate($row, $offset, true); // rehydrate
|
||||
$col = $offset + AtosCurrencyTableMap::NUM_HYDRATE_COLUMNS;
|
||||
} else {
|
||||
$cls = AtosCurrencyTableMap::OM_CLASS;
|
||||
$obj = new $cls();
|
||||
$col = $obj->hydrate($row, $offset, false, $indexType);
|
||||
AtosCurrencyTableMap::addInstanceToPool($obj, $key);
|
||||
}
|
||||
|
||||
return array($obj, $col);
|
||||
}
|
||||
|
||||
/**
|
||||
* The returned array will contain objects of the default type or
|
||||
* objects that inherit from the default.
|
||||
*
|
||||
* @param DataFetcherInterface $dataFetcher
|
||||
* @return array
|
||||
* @throws PropelException Any exceptions caught during processing will be
|
||||
* rethrown wrapped into a PropelException.
|
||||
*/
|
||||
public static function populateObjects(DataFetcherInterface $dataFetcher)
|
||||
{
|
||||
$results = array();
|
||||
|
||||
// set the class once to avoid overhead in the loop
|
||||
$cls = static::getOMClass(false);
|
||||
// populate the object(s)
|
||||
while ($row = $dataFetcher->fetch()) {
|
||||
$key = AtosCurrencyTableMap::getPrimaryKeyHashFromRow($row, 0, $dataFetcher->getIndexType());
|
||||
if (null !== ($obj = AtosCurrencyTableMap::getInstanceFromPool($key))) {
|
||||
// We no longer rehydrate the object, since this can cause data loss.
|
||||
// See http://www.propelorm.org/ticket/509
|
||||
// $obj->hydrate($row, 0, true); // rehydrate
|
||||
$results[] = $obj;
|
||||
} else {
|
||||
$obj = new $cls();
|
||||
$obj->hydrate($row);
|
||||
$results[] = $obj;
|
||||
AtosCurrencyTableMap::addInstanceToPool($obj, $key);
|
||||
} // if key exists
|
||||
}
|
||||
|
||||
return $results;
|
||||
}
|
||||
/**
|
||||
* Add all the columns needed to create a new object.
|
||||
*
|
||||
* Note: any columns that were marked with lazyLoad="true" in the
|
||||
* XML schema will not be added to the select list and only loaded
|
||||
* on demand.
|
||||
*
|
||||
* @param Criteria $criteria object containing the columns to add.
|
||||
* @param string $alias optional table alias
|
||||
* @throws PropelException Any exceptions caught during processing will be
|
||||
* rethrown wrapped into a PropelException.
|
||||
*/
|
||||
public static function addSelectColumns(Criteria $criteria, $alias = null)
|
||||
{
|
||||
if (null === $alias) {
|
||||
$criteria->addSelectColumn(AtosCurrencyTableMap::CODE);
|
||||
$criteria->addSelectColumn(AtosCurrencyTableMap::ATOS_CODE);
|
||||
$criteria->addSelectColumn(AtosCurrencyTableMap::DECIMALS);
|
||||
} else {
|
||||
$criteria->addSelectColumn($alias . '.CODE');
|
||||
$criteria->addSelectColumn($alias . '.ATOS_CODE');
|
||||
$criteria->addSelectColumn($alias . '.DECIMALS');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the TableMap related to this object.
|
||||
* This method is not needed for general use but a specific application could have a need.
|
||||
* @return TableMap
|
||||
* @throws PropelException Any exceptions caught during processing will be
|
||||
* rethrown wrapped into a PropelException.
|
||||
*/
|
||||
public static function getTableMap()
|
||||
{
|
||||
return Propel::getServiceContainer()->getDatabaseMap(AtosCurrencyTableMap::DATABASE_NAME)->getTable(AtosCurrencyTableMap::TABLE_NAME);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a TableMap instance to the database for this tableMap class.
|
||||
*/
|
||||
public static function buildTableMap()
|
||||
{
|
||||
$dbMap = Propel::getServiceContainer()->getDatabaseMap(AtosCurrencyTableMap::DATABASE_NAME);
|
||||
if (!$dbMap->hasTable(AtosCurrencyTableMap::TABLE_NAME)) {
|
||||
$dbMap->addTableObject(new AtosCurrencyTableMap());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs a DELETE on the database, given a AtosCurrency or Criteria object OR a primary key value.
|
||||
*
|
||||
* @param mixed $values Criteria or AtosCurrency object or primary key or array of primary keys
|
||||
* which is used to create the DELETE statement
|
||||
* @param ConnectionInterface $con the connection to use
|
||||
* @return int The number of affected rows (if supported by underlying database driver). This includes CASCADE-related rows
|
||||
* if supported by native driver or if emulated using Propel.
|
||||
* @throws PropelException Any exceptions caught during processing will be
|
||||
* rethrown wrapped into a PropelException.
|
||||
*/
|
||||
public static function doDelete($values, ConnectionInterface $con = null)
|
||||
{
|
||||
if (null === $con) {
|
||||
$con = Propel::getServiceContainer()->getWriteConnection(AtosCurrencyTableMap::DATABASE_NAME);
|
||||
}
|
||||
|
||||
if ($values instanceof Criteria) {
|
||||
// rename for clarity
|
||||
$criteria = $values;
|
||||
} elseif ($values instanceof \Atos\Model\AtosCurrency) { // it's a model object
|
||||
// create criteria based on pk values
|
||||
$criteria = $values->buildPkeyCriteria();
|
||||
} else { // it's a primary key, or an array of pks
|
||||
$criteria = new Criteria(AtosCurrencyTableMap::DATABASE_NAME);
|
||||
$criteria->add(AtosCurrencyTableMap::CODE, (array) $values, Criteria::IN);
|
||||
}
|
||||
|
||||
$query = AtosCurrencyQuery::create()->mergeWith($criteria);
|
||||
|
||||
if ($values instanceof Criteria) { AtosCurrencyTableMap::clearInstancePool();
|
||||
} elseif (!is_object($values)) { // it's a primary key, or an array of pks
|
||||
foreach ((array) $values as $singleval) { AtosCurrencyTableMap::removeInstanceFromPool($singleval);
|
||||
}
|
||||
}
|
||||
|
||||
return $query->delete($con);
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes all rows from the atos_currency table.
|
||||
*
|
||||
* @param ConnectionInterface $con the connection to use
|
||||
* @return int The number of affected rows (if supported by underlying database driver).
|
||||
*/
|
||||
public static function doDeleteAll(ConnectionInterface $con = null)
|
||||
{
|
||||
return AtosCurrencyQuery::create()->doDeleteAll($con);
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs an INSERT on the database, given a AtosCurrency or Criteria object.
|
||||
*
|
||||
* @param mixed $criteria Criteria or AtosCurrency object containing data that is used to create the INSERT statement.
|
||||
* @param ConnectionInterface $con the ConnectionInterface connection to use
|
||||
* @return mixed The new primary key.
|
||||
* @throws PropelException Any exceptions caught during processing will be
|
||||
* rethrown wrapped into a PropelException.
|
||||
*/
|
||||
public static function doInsert($criteria, ConnectionInterface $con = null)
|
||||
{
|
||||
if (null === $con) {
|
||||
$con = Propel::getServiceContainer()->getWriteConnection(AtosCurrencyTableMap::DATABASE_NAME);
|
||||
}
|
||||
|
||||
if ($criteria instanceof Criteria) {
|
||||
$criteria = clone $criteria; // rename for clarity
|
||||
} else {
|
||||
$criteria = $criteria->buildCriteria(); // build Criteria from AtosCurrency object
|
||||
}
|
||||
|
||||
// Set the correct dbName
|
||||
$query = AtosCurrencyQuery::create()->mergeWith($criteria);
|
||||
|
||||
try {
|
||||
// use transaction because $criteria could contain info
|
||||
// for more than one table (I guess, conceivably)
|
||||
$con->beginTransaction();
|
||||
$pk = $query->doInsert($con);
|
||||
$con->commit();
|
||||
} catch (PropelException $e) {
|
||||
$con->rollBack();
|
||||
throw $e;
|
||||
}
|
||||
|
||||
return $pk;
|
||||
}
|
||||
|
||||
} // AtosCurrencyTableMap
|
||||
// This is the static code needed to register the TableMap for this table with the main Propel class.
|
||||
//
|
||||
AtosCurrencyTableMap::buildTableMap();
|
||||
71
local/modules/Atos/Readme.md
Normal file
@@ -0,0 +1,71 @@
|
||||
# Atos-SIPS Payment Module
|
||||
------------------------
|
||||
|
||||
## English instructions
|
||||
|
||||
This module offers to your customers the Atos SIPS payment system, which is widely used by the french banks under different names: Mercanet, E-Transactions, Citelis, and much more.
|
||||
|
||||
### Installation
|
||||
|
||||
#### Manually
|
||||
|
||||
Install the Atos module using the Module page of your back office to upload the archive.
|
||||
|
||||
You can also extract the archive in the `<thelia root>/local/modules` directory. Be sure that the name of the module's directory is `Atos` (and not `Atos-master`, for example).
|
||||
|
||||
Activate the module from the Modules page of your back-office.
|
||||
|
||||
#### composer
|
||||
|
||||
```
|
||||
$ composer require thelia/atos-module:~1.0
|
||||
```
|
||||
|
||||
### Usage
|
||||
|
||||
You have to configure the Atos module before starting to use it. To do so, go to the "Modules" tab of your Thelia back-office, and activate the Atos module.
|
||||
|
||||
Then click the "Configure" button, and enter the required information. In most case, you'll receive your merchant ID by e-mail, and you'll receive instructions to download your certificate.
|
||||
|
||||
The module performs several checks when the configuration is saved, especially the execution permissions on the Atos binaries.
|
||||
|
||||
During the test phase, you can define the IP addresses allowed to use the Atos module on the front office, so that your customers will not be able to pay with Atos during this test phase.
|
||||
|
||||
A log of Atos post-payment callbacks is displayed in the configuration page.
|
||||
|
||||
### Payment template
|
||||
|
||||
You can customize the payment page ```templates/atos/payment.html``` to provide a better integration in your template, but the payment form data cannot be modified, as it is generated and signed by the Atos binary.
|
||||
|
||||
## Instructions en français
|
||||
|
||||
Ce module permet à vos clients de payer leurs commande par carte bancaire via la plate-forme Atos SIPS, utilisée par de nombreuses banques françaises sous diverses dénominations commerciales: Mercanet, Citelis, E-Transactions, et bien d'autres.
|
||||
|
||||
## Installation
|
||||
|
||||
### Manuellement
|
||||
|
||||
Installez ce module directement depuis la page Modules de votre back-office, en envoyant le fichier zip du module.
|
||||
|
||||
Vous pouvez aussi décompresser le module, et le placer manuellement dans le dossier ```<thelia_root>/local/modules```. Assurez-vous que le nom du dossier est bien ```Atos```, et pas ```Atos-master```
|
||||
|
||||
### composer
|
||||
|
||||
```
|
||||
$ composer require thelia/atos-module:~1.0
|
||||
```
|
||||
|
||||
|
||||
## Utilisation
|
||||
|
||||
Pour utiliser le module Atos, vous devez tout d'abord le configurer. Pour ce faire, rendez-vous dans votre back-office, onglet Modules, et activez le module Atos.
|
||||
|
||||
Cliquez ensuite sur "Configurer" sur la ligne du module, et renseignez les informations requises. Dans la plupart des cas, l'ID Marchand vous a été communiqué par votre banque par e-mail, et vous devez recevoir les instructions qui vous permettront de télécharger le certificat.
|
||||
|
||||
Le module réalise plusieurs vérifications de votre configuration, et vous signalera les problèmes éventuellement rencontrés. Il contrôle notamment que les exécutables Atos possèdent bien les permissions d'exécution.
|
||||
|
||||
Lors de la phase de test, vous pouvez définir les adresses IP qui seront autorisées à utiliser le module en front-office, afin de ne pas laisser vos clients payer leur commandes avec Atos pendant cette phase.
|
||||
|
||||
## Template de paiement
|
||||
|
||||
Vous pouvez adapter la page de paiement qui se trouve dans ```templates/atos/payment.html```, et l'adapter à votre template, mais la form de paiement en elle-même ne peut pas être modifiée, elle est générée et signée par le binaire Atos, et ne doit pas être modifiée.
|
||||
BIN
local/modules/Atos/bin/request
Executable file
BIN
local/modules/Atos/bin/response
Executable file
11
local/modules/Atos/composer.json
Normal file
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"name": "thelia/atos-module",
|
||||
"license": "GPL-3.0+",
|
||||
"type": "thelia-module",
|
||||
"require": {
|
||||
"thelia/installer": "~1.1"
|
||||
},
|
||||
"extra": {
|
||||
"installer-name": "Atos"
|
||||
}
|
||||
}
|
||||
BIN
local/modules/Atos/logo/1EUROCOM.gif
Normal file
|
After Width: | Height: | Size: 1.4 KiB |
BIN
local/modules/Atos/logo/AMEX.gif
Normal file
|
After Width: | Height: | Size: 1.9 KiB |
BIN
local/modules/Atos/logo/AURORE.gif
Normal file
|
After Width: | Height: | Size: 1.5 KiB |
BIN
local/modules/Atos/logo/BANCONTACTMISTERCASH.gif
Normal file
|
After Width: | Height: | Size: 1.2 KiB |
BIN
local/modules/Atos/logo/CB.gif
Normal file
|
After Width: | Height: | Size: 1.8 KiB |
BIN
local/modules/Atos/logo/CLEF.gif
Normal file
|
After Width: | Height: | Size: 1.2 KiB |
BIN
local/modules/Atos/logo/CREDIT_CTLM.gif
Normal file
|
After Width: | Height: | Size: 1.8 KiB |
BIN
local/modules/Atos/logo/ELV.gif
Normal file
|
After Width: | Height: | Size: 682 B |
BIN
local/modules/Atos/logo/INTERVAL.gif
Normal file
|
After Width: | Height: | Size: 89 B |
BIN
local/modules/Atos/logo/JCB.gif
Normal file
|
After Width: | Height: | Size: 1.3 KiB |
BIN
local/modules/Atos/logo/MASTERCARD.gif
Normal file
|
After Width: | Height: | Size: 1.1 KiB |
BIN
local/modules/Atos/logo/NXCB.gif
Normal file
|
After Width: | Height: | Size: 3.3 KiB |
BIN
local/modules/Atos/logo/NXCB_rouge.gif
Normal file
|
After Width: | Height: | Size: 3.0 KiB |
BIN
local/modules/Atos/logo/PAYPAL.gif
Normal file
|
After Width: | Height: | Size: 956 B |
BIN
local/modules/Atos/logo/VISA.gif
Normal file
|
After Width: | Height: | Size: 1.4 KiB |
7
local/modules/Atos/templates/atos/payment.html
Normal file
@@ -0,0 +1,7 @@
|
||||
<HTML><HEAD><TITLE>BNP MERC@NET - Paiement Securise sur Internet</TITLE></HEAD>
|
||||
<BODY bgcolor=#ffffff>
|
||||
<Font color=#000000>
|
||||
<center><H1>PAIEMENT SECURISE BNP MERC@NET</H1></center>
|
||||
<center><H1>{$site_name}</H1></center><br>
|
||||
{$form nofilter}
|
||||
</BODY></HTML>
|
||||
@@ -0,0 +1,120 @@
|
||||
<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='atos.bo.default' l="Atos Configuration"}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-container">
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
{form name="atos_configuration"}
|
||||
<form action="{url path="/admin/module/atos/configure"}" method="post">
|
||||
{form_hidden_fields form=$form}
|
||||
|
||||
{include file = "includes/inner-form-toolbar.html"
|
||||
hide_flags = true
|
||||
page_url = "{url path='/admin/module/Atos'}"
|
||||
close_url = "{url path='/admin/modules'}"
|
||||
}
|
||||
|
||||
{if $form_error}
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<div class="alert alert-danger">{$form_error_message}</div>
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-4">
|
||||
<p class="title title-without-tabs">{intl d='atos.bo.default' l="Atos-SIPS Platform configuration"}</p>
|
||||
|
||||
{render_form_field form=$form field="atos_merchantId" value=$atos_merchantId}
|
||||
{render_form_field form=$form field="atos_certificate" value=$atos_certificate}
|
||||
|
||||
<div class="form-group">
|
||||
<label class="control-label">
|
||||
{intl d='atos.bo.default' l="Callback URL"}
|
||||
</label>
|
||||
|
||||
<div class="well well-sm">{url path='/atos/callback'}</div>
|
||||
|
||||
<span class="help-block">
|
||||
{intl d='atos.bo.default' l="This is the callback URL, that will be called by Atos SIPS after customer payment. Be sure that this URL is reachable by remote mechines"}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-md-4">
|
||||
<p class="title title-without-tabs">{intl d='atos.bo.default' l="Operation mode"}</p>
|
||||
|
||||
{render_form_field form=$form field="atos_mode" value=$atos_mode}
|
||||
{render_form_field form=$form field="atos_allowed_ip_list" value=$atos_allowed_ip_list}
|
||||
|
||||
<p class="title title-without-tabs">{intl d='atos.bo.default' l="Payment by N installment"}</p>
|
||||
|
||||
{loop name="multi-plugin-enabled" type="module" code="AtosNx" active="1"}{/loop}
|
||||
{elseloop rel="multi-plugin-enabled"}
|
||||
<div class="alert alert-info">
|
||||
{intl l="Install and activate Atos multiple times payment module (AtoxNx) to get configuration options." d='payzen.ai'}
|
||||
</div>
|
||||
{/elseloop}
|
||||
|
||||
{render_form_field form=$form field="nx_nb_installments" value=$nx_nb_installments|default:3}
|
||||
{render_form_field form=$form field="nx_minimum_amount" value=$nx_minimum_amount|default:0}
|
||||
{render_form_field form=$form field="nx_maximum_amount" value=$nx_maximum_amount|default:0}
|
||||
</div>
|
||||
|
||||
<div class="col-md-4">
|
||||
<p class="title title-without-tabs">{intl d='atos.bo.default' l="Payment configuration"}</p>
|
||||
|
||||
{custom_render_form_field form=$form field="send_confirmation_message_only_if_paid"}
|
||||
<input type="checkbox" {form_field_attributes form=$form field="send_confirmation_message_only_if_paid"} {if $send_confirmation_message_only_if_paid}checked{/if}>
|
||||
{$label}
|
||||
{/custom_render_form_field}
|
||||
|
||||
{custom_render_form_field form=$form field="send_payment_confirmation_message"}
|
||||
<input type="checkbox" {form_field_attributes form=$form field="send_payment_confirmation_message"} {if $send_payment_confirmation_message}checked{/if}>
|
||||
{$label}
|
||||
{/custom_render_form_field}
|
||||
|
||||
<div class="well well-sm">
|
||||
<span class="glyphicon glyphicon-info-sign"></span>
|
||||
{intl d='paypal.bo.default' l='You can <a href="%url">edit the payment confirmation email</a> sent to the customer after a successful payment.' url={url path="/admin/configuration/messages"}}
|
||||
</div>
|
||||
|
||||
{render_form_field form=$form field="atos_minimum_amount" value=$atos_minimum_amount}
|
||||
{render_form_field form=$form field="atos_maximum_amount" value=$atos_maximum_amount}
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
{/form}
|
||||
|
||||
<div class="row">
|
||||
<div class="col-xs-12">
|
||||
<div class="panel panel-primary">
|
||||
<div class="panel-heading">
|
||||
<h3 class="panel-title">
|
||||
<span class="glyphicon glyphicon-cog"></span>
|
||||
{intl d='atos.bo.default' l="Atos-SIPS call log to callback URL"}
|
||||
</h3>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<div id="log-container" style="font-family: monospace; font-size: 12px; max-height: 400px; overflow-y: scroll">
|
||||
{$trace_content nofilter}
|
||||
</div>
|
||||
</div>
|
||||
<div class="panel-footer">
|
||||
<a href="{url path='/admin/module/atos/log'}" class="btn btn-sm btn-primary">{intl d='atos.bo.default' l="Download full log"}</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,23 @@
|
||||
{extends file="email-layout.tpl"}
|
||||
|
||||
{* Do not provide a "Open in browser" link *}
|
||||
{block name="browser"}{/block}
|
||||
{* No pre-header *}
|
||||
{block name="pre-header"}{/block}
|
||||
|
||||
{* Subject *}
|
||||
{block name="email-subject"}{intl d='atos.email.default' l="Payment of your order %ref" ref=$order_ref}{/block}
|
||||
|
||||
{* Title *}
|
||||
{block name="email-title"}{intl d='atos.email.default' l="The payment of your order %ref with SIPS Atos is confirmed" ref=$order_ref}{/block}
|
||||
|
||||
{* Content *}
|
||||
{block name="email-content"}
|
||||
<p>
|
||||
<a href="{url path="/account"}">
|
||||
{intl l="View this order in your account at %shop_name" shop_name={config key="store_name"}}
|
||||
</a>
|
||||
</p>
|
||||
<p>{intl d='atos.email.default' l='Thank you again for your purchase.'}</p>
|
||||
<p>{intl d='atos.email.default' l='The %store_name team.' store_name={config key="store_name"}}</p>
|
||||
{/block}
|
||||
@@ -0,0 +1,9 @@
|
||||
{intl d='atos.email.default' l='Dear customer'},
|
||||
|
||||
{intl d='atos.email.default' l='This is a confirmation of the payment of your order %ref with SIPS-Atos on our shop.' ref=$order_ref}
|
||||
|
||||
{intl d='atos.email.default' l='Your invoice is now available in your customer account at %url.'} url={config key="url_site"}}
|
||||
|
||||
{intl d='atos.email.default' l='Thank you again for your purchase.'}
|
||||
|
||||
{intl d='atos.email.default' l='The %store_name team.' store_name={config key="store_name"}}
|
||||
@@ -0,0 +1,7 @@
|
||||
<HTML><HEAD><TITLE>ATOS - Paiement Securise sur Internet</TITLE></HEAD>
|
||||
<BODY bgcolor=#ffffff>
|
||||
<Font color=#000000>
|
||||
<center><H1>PAIEMENT SECURISE ATOS </H1></center><br><br>
|
||||
<center><H1>{$site_name}</H1></center><br><br>
|
||||
{$form nofilter}
|
||||
</BODY></HTML>
|
||||
@@ -0,0 +1,7 @@
|
||||
<HTML><HEAD><TITLE>ATOS - Paiement Securise sur Internet</TITLE></HEAD>
|
||||
<BODY bgcolor=#ffffff>
|
||||
<Font color=#000000>
|
||||
<center><H1>PAIEMENT SECURISE ATOS </H1></center><br><br>
|
||||
<center><H1>{$site_name}</H1></center><br><br>
|
||||
{$form nofilter}
|
||||
</BODY></HTML>
|
||||
26
local/modules/BestSellers/BestSellers.php
Normal file
@@ -0,0 +1,26 @@
|
||||
<?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 BestSellers;
|
||||
|
||||
use Thelia\Module\BaseModule;
|
||||
|
||||
class BestSellers extends BaseModule
|
||||
{
|
||||
/** @var string */
|
||||
const DOMAIN_NAME = 'bestsellers';
|
||||
|
||||
const GET_BEST_SELLING_PRODUCTS = "bestsellers.event.get_best_selling_products";
|
||||
|
||||
/* Data cache lifetime in minutes */
|
||||
const CACHE_LIFETIME_IN_MINUTES = 1440;
|
||||
}
|
||||
28
local/modules/BestSellers/Config/config.xml
Normal file
@@ -0,0 +1,28 @@
|
||||
<?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>
|
||||
<loop name="best_selling_products" class="BestSellers\Loop\BestSellerLoop" />
|
||||
</loops>
|
||||
|
||||
<services>
|
||||
<service id="best_sellers.event_listener" class="BestSellers\EventListeners\EventManager">
|
||||
<argument id="thelia.cache" type="service"/>
|
||||
<tag name="kernel.event_subscriber"/>
|
||||
</service>
|
||||
</services>
|
||||
|
||||
<hooks>
|
||||
<hook id="best_sellers.hook.back" class="BestSellers\Hook\HookManager">
|
||||
<tag name="hook.event_listener" event="main.top-menu-tools" type="back" method="onMainTopMenuTools" />
|
||||
<tag name="hook.event_listener" event="product.modification.form-right.bottom" type="back" templates="render:product-edit.html" />
|
||||
</hook>
|
||||
|
||||
<hook id="best_sellers.hook.front">
|
||||
<tag name="hook.event_listener" event="home.body" templates="render:home-body.html" />
|
||||
</hook>
|
||||
</hooks>
|
||||
</config>
|
||||
31
local/modules/BestSellers/Config/module.xml
Normal file
@@ -0,0 +1,31 @@
|
||||
<?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>BestSellers\BestSellers</fullnamespace>
|
||||
<descriptive locale="en_US">
|
||||
<title>Display your best sellers on your home page, and get information about products sales</title>
|
||||
</descriptive>
|
||||
|
||||
<descriptive locale="fr_FR">
|
||||
<title>Afficher vos produits les plus vendus sur votre page d'acceuil, et obtenez des détails sur les ventes de vos produits</title>
|
||||
</descriptive>
|
||||
<languages>
|
||||
<language>en_US</language>
|
||||
<language>fr_FR</language>
|
||||
</languages>
|
||||
<version>1.1.1</version>
|
||||
<authors>
|
||||
<author>
|
||||
<name>Franck Allimant</name>
|
||||
<company>CQFDev</company>
|
||||
<email>thelia@cqfdev.fr</email>
|
||||
<website>www.cqfdev.fr</website>
|
||||
</author>
|
||||
</authors>
|
||||
<type>classic</type>
|
||||
<thelia>2.3.4</thelia>
|
||||
<stability>prod</stability>
|
||||
<mandatory>0</mandatory>
|
||||
<hidden>0</hidden>
|
||||
</module>
|
||||
6
local/modules/BestSellers/Config/routing.xml
Normal file
@@ -0,0 +1,6 @@
|
||||
<?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">
|
||||
</routes>
|
||||
116
local/modules/BestSellers/EventListeners/BestSellersEvent.php
Normal file
@@ -0,0 +1,116 @@
|
||||
<?php
|
||||
/*************************************************************************************/
|
||||
/* Copyright (c) Franck Allimant, CQFDev */
|
||||
/* email : thelia@cqfdev.fr */
|
||||
/* web : http://www.cqfdev.fr */
|
||||
/* */
|
||||
/* For the full copyright and license information, please view the LICENSE */
|
||||
/* file that was distributed with this source code. */
|
||||
/*************************************************************************************/
|
||||
|
||||
/**
|
||||
* Created by Franck Allimant, CQFDev <franck@cqfdev.fr>
|
||||
* Date: 21/05/2018 16:34
|
||||
*/
|
||||
|
||||
namespace BestSellers\EventListeners;
|
||||
|
||||
use Thelia\Core\Event\ActionEvent;
|
||||
|
||||
class BestSellersEvent extends ActionEvent
|
||||
{
|
||||
/** @var \DateTime */
|
||||
protected $startDate;
|
||||
|
||||
/** @var \DateTime */
|
||||
protected $endDate;
|
||||
|
||||
/** @var array */
|
||||
protected $bestSellingProductsData = [];
|
||||
|
||||
protected $totalSales = 0;
|
||||
|
||||
/**
|
||||
* BestSellersEvent constructor.
|
||||
* @param $startDate
|
||||
* @param $endDate
|
||||
*/
|
||||
public function __construct(\DateTime $startDate = null, \DateTime $endDate = null)
|
||||
{
|
||||
$this->startDate = null === $startDate ? new \DateTime("1970-01-01") : $startDate;
|
||||
$this->endDate = null === $endDate ? new \DateTime() : $endDate;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \DateTime
|
||||
*/
|
||||
public function getStartDate()
|
||||
{
|
||||
return $this->startDate;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \DateTime $startDate
|
||||
* @return $this
|
||||
*/
|
||||
public function setStartDate($startDate)
|
||||
{
|
||||
$this->startDate = $startDate;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \DateTime
|
||||
*/
|
||||
public function getEndDate()
|
||||
{
|
||||
return $this->endDate;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \DateTime $endDate
|
||||
* @return $this
|
||||
*/
|
||||
public function setEndDate($endDate)
|
||||
{
|
||||
$this->endDate = $endDate;
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function getBestSellingProductsData()
|
||||
{
|
||||
return ! empty($this->bestSellingProductsData) ? $this->bestSellingProductsData : [];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $bestSellingProductsData
|
||||
* @return $this
|
||||
*/
|
||||
public function setBestSellingProductsData($bestSellingProductsData)
|
||||
{
|
||||
$this->bestSellingProductsData = $bestSellingProductsData;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function getTotalSales()
|
||||
{
|
||||
return $this->totalSales;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param float $totalSales
|
||||
* @return $this
|
||||
*/
|
||||
public function setTotalSales($totalSales)
|
||||
{
|
||||
$this->totalSales = floatval($totalSales);
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
129
local/modules/BestSellers/EventListeners/EventManager.php
Normal file
@@ -0,0 +1,129 @@
|
||||
<?php
|
||||
/*************************************************************************************/
|
||||
/* Copyright (c) Franck Allimant, CQFDev */
|
||||
/* email : thelia@cqfdev.fr */
|
||||
/* web : http://www.cqfdev.fr */
|
||||
/* */
|
||||
/* For the full copyright and license information, please view the LICENSE */
|
||||
/* file that was distributed with this source code. */
|
||||
/*************************************************************************************/
|
||||
|
||||
namespace BestSellers\EventListeners;
|
||||
|
||||
use BestSellers\BestSellers;
|
||||
use Propel\Runtime\Connection\PdoConnection;
|
||||
use Propel\Runtime\Propel;
|
||||
use Psr\Cache\InvalidArgumentException;
|
||||
use Symfony\Component\Cache\Adapter\AdapterInterface;
|
||||
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
|
||||
use Thelia\Action\BaseAction;
|
||||
use Thelia\Model\Map\OrderProductTableMap;
|
||||
use Thelia\Model\Map\OrderTableMap;
|
||||
use Thelia\Model\Map\ProductTableMap;
|
||||
use Thelia\Model\OrderStatusQuery;
|
||||
|
||||
class EventManager extends BaseAction implements EventSubscriberInterface
|
||||
{
|
||||
/** @var AdapterInterface $cacheAdapter */
|
||||
protected $cacheAdapter;
|
||||
|
||||
/**
|
||||
* DigressivePriceListener constructor.
|
||||
* @param AdapterInterface $cacheAdapter
|
||||
*/
|
||||
public function __construct(AdapterInterface $cacheAdapter)
|
||||
{
|
||||
$this->cacheAdapter = $cacheAdapter;
|
||||
}
|
||||
|
||||
public static function getSubscribedEvents()
|
||||
{
|
||||
return [
|
||||
BestSellers::GET_BEST_SELLING_PRODUCTS => [ "calculateBestSellers", 128 ]
|
||||
];
|
||||
}
|
||||
|
||||
public function calculateBestSellers(BestSellersEvent $event)
|
||||
{
|
||||
$cacheKey = sprintf(
|
||||
"best_sellers_%s_%s",
|
||||
$event->getStartDate()->format('Y-m-d'),
|
||||
$event->getEndDate()->format('Y-m-d')
|
||||
);
|
||||
|
||||
try {
|
||||
$cacheItem = $this->cacheAdapter->getItem($cacheKey);
|
||||
|
||||
if (! $cacheItem->isHit()) {
|
||||
/** @var PdoConnection $con */
|
||||
$con = Propel::getConnection();
|
||||
|
||||
$query = "
|
||||
SELECT
|
||||
" . ProductTableMap::ID . " as product_id,
|
||||
SUM(" . OrderProductTableMap::QUANTITY . ") as total_quantity,
|
||||
SUM(".OrderProductTableMap::QUANTITY." * IF(" . OrderProductTableMap::WAS_IN_PROMO . "," . OrderProductTableMap::PROMO_PRICE . ", ".OrderProductTableMap::PRICE.")) as total_sales
|
||||
FROM
|
||||
" . OrderProductTableMap::TABLE_NAME . "
|
||||
LEFT JOIN
|
||||
" . OrderTableMap::TABLE_NAME . " on " . OrderTableMap::ID . " = " . OrderProductTableMap::ORDER_ID . "
|
||||
LEFT JOIN
|
||||
" . ProductTableMap::TABLE_NAME . " on " . ProductTableMap::REF . " = " . OrderProductTableMap::PRODUCT_REF . "
|
||||
WHERE
|
||||
" . OrderTableMap::CREATED_AT . " >= ?
|
||||
AND
|
||||
" . OrderTableMap::CREATED_AT . " <= ?
|
||||
AND
|
||||
" . OrderTableMap::STATUS_ID . " not in (?, ?)
|
||||
GROUP BY
|
||||
" . ProductTableMap::ID . "
|
||||
ORDER BY
|
||||
total_quantity desc
|
||||
";
|
||||
|
||||
$query = preg_replace("/order([^_])/", "`order`$1", $query);
|
||||
|
||||
$stmt = $con->prepare($query);
|
||||
|
||||
$res = $stmt->execute([
|
||||
$event->getStartDate()->format("Y-m-d H:i:s"),
|
||||
$event->getEndDate()->format("Y-m-d H:i:s"),
|
||||
OrderStatusQuery::getNotPaidStatus()->getId(),
|
||||
OrderStatusQuery::getCancelledStatus()->getId()
|
||||
]);
|
||||
|
||||
$data = [];
|
||||
|
||||
$totalSales = 0;
|
||||
|
||||
while ($res && $result = $stmt->fetch(\PDO::FETCH_ASSOC)) {
|
||||
$data[] = $result;
|
||||
|
||||
$totalSales += $result['total_sales'];
|
||||
}
|
||||
|
||||
$struct = [
|
||||
'data' => $data,
|
||||
'total_sales' => $totalSales
|
||||
];
|
||||
|
||||
$cacheItem
|
||||
->set(json_encode($struct))
|
||||
->expiresAfter(60 * BestSellers::CACHE_LIFETIME_IN_MINUTES)
|
||||
;
|
||||
|
||||
$this->cacheAdapter->save($cacheItem);
|
||||
}
|
||||
|
||||
$struct = json_decode($cacheItem->get(), true);
|
||||
|
||||
$event
|
||||
->setBestSellingProductsData($struct['data'])
|
||||
->setTotalSales($struct['total_sales'])
|
||||
;
|
||||
|
||||
} catch (InvalidArgumentException $e) {
|
||||
// Nothing to do with this, return an empty result.
|
||||
}
|
||||
}
|
||||
}
|
||||
39
local/modules/BestSellers/Hook/HookManager.php
Normal file
@@ -0,0 +1,39 @@
|
||||
<?php
|
||||
/*************************************************************************************/
|
||||
/* */
|
||||
/* Copyright (c) Franck Allimant, CQFDev */
|
||||
/* email : thelia@cqfdev.fr */
|
||||
/* web : http://www.cqfdev.fr */
|
||||
/* */
|
||||
/* For the full copyright and license information, please view the LICENSE */
|
||||
/* file that was distributed with this source code. */
|
||||
/* */
|
||||
/*************************************************************************************/
|
||||
|
||||
/**
|
||||
* @author Franck Allimant <franck@cqfdev.fr>
|
||||
*
|
||||
* Creation date: 23/03/2015 12:09
|
||||
*/
|
||||
|
||||
namespace BestSellers\Hook;
|
||||
|
||||
use BestSellers\BestSellers;
|
||||
use Thelia\Core\Event\Hook\HookRenderBlockEvent;
|
||||
use Thelia\Core\Hook\BaseHook;
|
||||
use Thelia\Tools\URL;
|
||||
|
||||
class HookManager extends BaseHook
|
||||
{
|
||||
public function onMainTopMenuTools(HookRenderBlockEvent $event)
|
||||
{
|
||||
$event->add(
|
||||
[
|
||||
'id' => 'bestsellers_menu_tags',
|
||||
'class' => '',
|
||||
'url' => URL::getInstance()->absoluteUrl('/admin/best-sellers'),
|
||||
'title' => $this->trans("Best sellers", [], BestSellers::DOMAIN_NAME)
|
||||
]
|
||||
);
|
||||
}
|
||||
}
|
||||
18
local/modules/BestSellers/I18n/backOffice/default/en_US.php
Normal file
@@ -0,0 +1,18 @@
|
||||
<?php
|
||||
|
||||
return array(
|
||||
' to : ' => ' to : ',
|
||||
'% of sales: <strong>%count%</strong>' => '% of sales: <strong>%count%</strong>',
|
||||
'Best sellers' => 'Best sellers',
|
||||
'Product reference' => 'Product reference',
|
||||
'Product title' => 'Product title',
|
||||
'Sale ratio' => '% of sales',
|
||||
'Sales total' => 'Sales total',
|
||||
'Sold amount for this product: <strong>%count</strong>' => 'Sold amount for this product: <strong>%count</strong>',
|
||||
'Statistics' => 'Statistics',
|
||||
'Total amount' => 'Total amount w/o tax',
|
||||
'Total sales for this product: <strong>%count</strong>' => 'Total sales for this product: <strong>%count</strong>',
|
||||
'View' => 'View',
|
||||
'View from : ' => 'View from : ',
|
||||
'You have not sold any products yet' => 'You have not sold any products yet',
|
||||
);
|
||||
18
local/modules/BestSellers/I18n/backOffice/default/fr_FR.php
Normal file
@@ -0,0 +1,18 @@
|
||||
<?php
|
||||
|
||||
return array(
|
||||
' to : ' => ' à : ',
|
||||
'% of sales: <strong>%count%</strong>' => '% du CA : <strong>%count%</strong>',
|
||||
'Best sellers' => 'Meilleures ventes',
|
||||
'Product reference' => 'Référence produit',
|
||||
'Product title' => 'Titre du produit',
|
||||
'Sale ratio' => '% du CA',
|
||||
'Sales total' => 'Total des ventes',
|
||||
'Sold amount for this product: <strong>%count</strong>' => 'Montant total HT vendu : <strong>%count</strong>',
|
||||
'Statistics' => 'Statistiques',
|
||||
'Total amount' => 'Montant total HT',
|
||||
'Total sales for this product: <strong>%count</strong>' => 'Total des ventes de ce produit : <strong>%count</strong>',
|
||||
'View' => 'Afficher',
|
||||
'View from : ' => 'Afficher de : ',
|
||||
'You have not sold any products yet' => 'Aucun produit vendu pour le moment.',
|
||||
);
|
||||
5
local/modules/BestSellers/I18n/en_US.php
Normal file
@@ -0,0 +1,5 @@
|
||||
<?php
|
||||
|
||||
return array(
|
||||
'Best sellers' => 'Best sellers',
|
||||
);
|
||||
5
local/modules/BestSellers/I18n/fr_FR.php
Normal file
@@ -0,0 +1,5 @@
|
||||
<?php
|
||||
|
||||
return array(
|
||||
'Best sellers' => 'Meilleures ventes',
|
||||
);
|
||||
@@ -0,0 +1,5 @@
|
||||
<?php
|
||||
|
||||
return array(
|
||||
'Best sellers' => 'Our best sellers',
|
||||
);
|
||||
@@ -0,0 +1,5 @@
|
||||
<?php
|
||||
|
||||
return array(
|
||||
'Best sellers' => 'Nos meilleures ventes',
|
||||
);
|
||||
146
local/modules/BestSellers/Loop/BestSellerLoop.php
Normal file
@@ -0,0 +1,146 @@
|
||||
<?php
|
||||
/*************************************************************************************/
|
||||
/* Copyright (c) Franck Allimant, CQFDev */
|
||||
/* email : thelia@cqfdev.fr */
|
||||
/* web : http://www.cqfdev.fr */
|
||||
/* */
|
||||
/* For the full copyright and license information, please view the LICENSE */
|
||||
/* file that was distributed with this source code. */
|
||||
/*************************************************************************************/
|
||||
|
||||
namespace BestSellers\Loop;
|
||||
|
||||
use BestSellers\BestSellers;
|
||||
use BestSellers\EventListeners\BestSellersEvent;
|
||||
use Propel\Runtime\ActiveQuery\Criteria;
|
||||
use Thelia\Core\Template\Element\LoopResultRow;
|
||||
use Thelia\Core\Template\Loop\Argument\Argument;
|
||||
use Thelia\Core\Template\Loop\Product;
|
||||
use Thelia\Model\Map\ProductTableMap;
|
||||
use Thelia\Type\EnumListType;
|
||||
use Thelia\Type\TypeCollection;
|
||||
|
||||
/**
|
||||
* Class BestSellerLoop
|
||||
* @package BestSellers\Loop
|
||||
* @method string getStartDate()
|
||||
* @method string getEndDate()
|
||||
*/
|
||||
class BestSellerLoop extends Product
|
||||
{
|
||||
protected function getArgDefinitions()
|
||||
{
|
||||
$args = parent::getArgDefinitions();
|
||||
|
||||
return $args->addArguments([
|
||||
Argument::createAnyTypeArgument('start_date', null, false),
|
||||
Argument::createAnyTypeArgument('end_date', null, false),
|
||||
new Argument(
|
||||
'order',
|
||||
new TypeCollection(
|
||||
new EnumListType(
|
||||
[
|
||||
'id', 'id_reverse',
|
||||
'alpha', 'alpha_reverse',
|
||||
'min_price', 'max_price',
|
||||
'manual', 'manual_reverse',
|
||||
'created', 'created_reverse',
|
||||
'updated', 'updated_reverse',
|
||||
'ref', 'ref_reverse',
|
||||
'visible', 'visible_reverse',
|
||||
'position', 'position_reverse',
|
||||
'promo',
|
||||
'new',
|
||||
'random',
|
||||
'given_id',
|
||||
'sold_count', 'sold_count_reverse',
|
||||
'sold_amount', 'sold_amount_reverse',
|
||||
'sale_ratio', 'sale_ratio_reverse'
|
||||
]
|
||||
)
|
||||
),
|
||||
'alpha'
|
||||
),
|
||||
]);
|
||||
}
|
||||
|
||||
public function buildModelCriteria()
|
||||
{
|
||||
$query = parent::buildModelCriteria();
|
||||
|
||||
$startDate = $this->getStartDate() ? new \DateTime($this->getStartDate()) : null;
|
||||
$endDate = $this->getEndDate() ? new \DateTime($this->getEndDate()) : null;
|
||||
|
||||
$event = new BestSellersEvent($startDate, $endDate);
|
||||
|
||||
$this->dispatcher->dispatch(BestSellers::GET_BEST_SELLING_PRODUCTS, $event);
|
||||
|
||||
$caseClause = $caseSalesClause = '';
|
||||
|
||||
$productData = $event->getBestSellingProductsData();
|
||||
|
||||
array_walk($productData, function($item) use (&$caseClause, &$caseSalesClause) {
|
||||
$caseClause .= sprintf("WHEN %d THEN %f ", $item['product_id'], $item['total_quantity']);
|
||||
$caseSalesClause .= sprintf("WHEN %d THEN %f ", $item['product_id'], $item['total_sales']);
|
||||
});
|
||||
|
||||
if (! empty($caseClause)) {
|
||||
$query
|
||||
->withColumn('CASE ' . ProductTableMap::ID . ' ' . $caseClause . ' ELSE 0 END', 'sold_quantity')
|
||||
->withColumn('CASE ' . ProductTableMap::ID . ' ' . $caseSalesClause . ' ELSE 0 END', 'sold_amount')
|
||||
;
|
||||
} else {
|
||||
$query
|
||||
->withColumn('(0)', 'sold_quantity')
|
||||
->withColumn('(0)', 'sold_amount')
|
||||
;
|
||||
}
|
||||
|
||||
if ($event->getTotalSales() !== 0) {
|
||||
$query->withColumn("(select 100 * sold_amount / " . $event->getTotalSales() . ")", 'sale_ratio');
|
||||
} else {
|
||||
$query->withColumn('(0)', 'sale_ratio');
|
||||
}
|
||||
|
||||
$orders = $this->getOrder();
|
||||
|
||||
foreach ($orders as $order) {
|
||||
switch ($order) {
|
||||
case "sold_count":
|
||||
$query->orderBy('sold_quantity', Criteria::ASC);
|
||||
break;
|
||||
case "sold_count_reverse":
|
||||
$query->orderBy('sold_quantity', Criteria::DESC);
|
||||
break;
|
||||
case "sold_amount":
|
||||
$query->orderBy('sold_amount', Criteria::ASC);
|
||||
break;
|
||||
case "sold_amount_reverse":
|
||||
$query->orderBy('sold_amount', Criteria::DESC);
|
||||
break;
|
||||
case "sale_ratio":
|
||||
$query->orderBy('sale_ratio', Criteria::ASC);
|
||||
break;
|
||||
case "sale_ratio_reverse":
|
||||
$query->orderBy('sale_ratio', Criteria::DESC);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return $query;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param LoopResultRow $loopResultRow
|
||||
* @param \Thelia\Model\Product $item
|
||||
* @throws \Propel\Runtime\Exception\PropelException
|
||||
*/
|
||||
protected function addOutputFields(LoopResultRow $loopResultRow, $item)
|
||||
{
|
||||
$loopResultRow
|
||||
->set("SOLD_QUANTITY", $item->getVirtualColumn('sold_quantity'))
|
||||
->set("SOLD_AMOUNT", $item->getVirtualColumn('sold_amount'))
|
||||
->set("SALE_RATIO", $item->getVirtualColumn('sale_ratio'))
|
||||
;
|
||||
}
|
||||
}
|
||||
164
local/modules/BestSellers/Readme.md
Normal file
@@ -0,0 +1,164 @@
|
||||
# Best Sellers
|
||||
|
||||
# en_US
|
||||
|
||||
This modules provides a loop which return the best (or the worst) sales.
|
||||
|
||||
## Installation
|
||||
|
||||
Manually, or with composer :
|
||||
|
||||
```
|
||||
composer require cqfdev/best-sellers-module:~1.0
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
This module shows the 4 best sales of your shop on the front page via the `home.body` hook.
|
||||
|
||||
You can also add where you want in your template (front or back-office), a loop `best_selling_products` to show your best or your worst sales.
|
||||
|
||||
In the back-office, you can see your best sales in the "Tools" menu.
|
||||
|
||||
Finally, the total number of sales of a product appears on the product sheet.
|
||||
|
||||
## Hook
|
||||
|
||||
This module shows the 4 best sales of your shop on the front page via the `home.body` hook.
|
||||
|
||||
## Loop
|
||||
|
||||
The module provide the loop `best_selling_product`, which extend the loop `product`. All the arguments of the `product` loop are therefore available.
|
||||
|
||||
`best_selling_products` loop
|
||||
|
||||
### Input parameters
|
||||
|
||||
All the arguments of the loop `product` are available.
|
||||
|
||||
The loop offers two new values for the parameter `order` of the loop `product``
|
||||
- sold_count_reverse : sort by number of sales in decreasing order
|
||||
- sold_count : sort by number of sales in increasing order
|
||||
|
||||
|Argument |Description |
|
||||
|--- |--- |
|
||||
|**start-date** | The period start date to be consider. By default, january 1st 1970. |
|
||||
|**end-date** | The period end date to be consider. By default, today's date. |
|
||||
|
||||
### Output variables
|
||||
|
||||
All the variables of the loop `product`are available.
|
||||
|
||||
|Variable |Description |
|
||||
|--- |--- |
|
||||
|$SOLD_QUANTITY | The quantity of sold product on the considered period |
|
||||
|$SOLD_AMOUNT | The total amount untaxed of sales on the considered period |
|
||||
|$SALE_RATIO | The percentage of sales on the considered period |
|
||||
|
||||
### Example
|
||||
|
||||
To get your 10 best sales of all time:
|
||||
|
||||
<ul>
|
||||
{loop type="best_selling_products" name="best-sellers" limit=10 order='sold_count_reverse'}
|
||||
<li>{$REF} : {$TITLE} : {$SOLD_QUANTITY}</li>
|
||||
{/loop}²²
|
||||
</ul>
|
||||
|
||||
To get your 5 best sales of the month :
|
||||
|
||||
<ul>
|
||||
{loop type="best_selling_products" name="best-sellers-this-month" order='sold_count_reverse' start_date={$smarty.now|date_format:'%Y-%m-01'} limit=5}
|
||||
<li>{$REF} : {$TITLE} : {$SOLD_QUANTITY}</li>
|
||||
{/loop}
|
||||
</ul>
|
||||
|
||||
To get your 10 worst sales of all time :
|
||||
|
||||
<ul>
|
||||
{loop type="best_selling_products" name="best-sellers" limit=10 order='sold_count'}
|
||||
<li>{$REF} : {$TITLE} : {$SOLD_QUANTITY}</li>
|
||||
{/loop}
|
||||
</ul>
|
||||
|
||||
|
||||
# fr_FR
|
||||
|
||||
Ce module vous fournit une boucle qui retourne vos meilleures (ou vos pires) ventes.
|
||||
|
||||
## Installation
|
||||
|
||||
Manuellement, ou avec composer :
|
||||
|
||||
```
|
||||
composer require cqfdev/best-sellers-module:~1.0
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
Ce module affiche les 4 meilleures ventes de votre boutique sur la page d'accueil, via le hook 'home.body'
|
||||
|
||||
Vous pouvez aussi ajouter où vous voulez dans votre template front office ou back-office une boucle `best_selling_products` pour afficher vos meilleures ou pires ventes.
|
||||
|
||||
Dans le back-office, vous pouvez voir vos meilleures ventes dans le menu "Outil".
|
||||
|
||||
Enfin, le nombre de ventes total d'un produit apparaît sur la fiche produit.
|
||||
|
||||
## Hook
|
||||
|
||||
Le module affiche les 4 meilleures ventes de votre boutique sur la page d'accueil, via le hook `home.body`
|
||||
|
||||
## Loop
|
||||
|
||||
Le module vous propose la boucle `best_selling_products`, qui étend la boucle `product`. Tous les arguments de la boucle `product` sont donc disponibles.
|
||||
|
||||
`best_selling_products` loop
|
||||
|
||||
### Paramètres en entrée
|
||||
|
||||
Tous les arguments de la boucle `product` sont disponibles.
|
||||
|
||||
La boucle propose deux valeurs supplémentaires pour le paramètre `order` de la boucle `product`:
|
||||
- sold_count_reverse : trier par nombre de ventes décroissantes
|
||||
- sold_count : trier par nombre de ventes croissantes
|
||||
|
||||
|Argument |Description |
|
||||
|--- |--- |
|
||||
|**start-date** | la date de début de période à prendre en compte. Par défaut, le 1er janvier 1970. |
|
||||
|**end-date** | la date de fin de période à prendre en compte. Par défaut, la date du jour. |
|
||||
|
||||
### Variables en sortie
|
||||
|
||||
Toutes les variables de la boucle `product` sont disponibles.
|
||||
|
||||
|Variable |Description |
|
||||
|--- |--- |
|
||||
|$SOLD_QUANTITY | La quantité de produit vendue sur la période considérée |
|
||||
|$SOLD_AMOUNT | Le montant total HT des ventes sur la période considérée |
|
||||
|$SALE_RATIO | Le pourcentage du CA sur la période considérée |
|
||||
|
||||
### Exemple
|
||||
|
||||
Pour obtenir vos 10 meilleures ventes de tous les temps :
|
||||
|
||||
<ul>
|
||||
{loop type="best_selling_products" name="best-sellers" limit=10 order='sold_count_reverse'}
|
||||
<li>{$REF} : {$TITLE} : {$SOLD_QUANTITY}</li>
|
||||
{/loop}
|
||||
</ul>
|
||||
|
||||
Pour obtenir les 5 meilleures ventes du mois :
|
||||
|
||||
<ul>
|
||||
{loop type="best_selling_products" name="best-sellers-this-month" order='sold_count_reverse' start_date={$smarty.now|date_format:'%Y-%m-01'} limit=5}
|
||||
<li>{$REF} : {$TITLE} : {$SOLD_QUANTITY}</li>
|
||||
{/loop}
|
||||
</ul>
|
||||
|
||||
Pour obtenir vos 10 pires ventes de tous les temps :
|
||||
|
||||
<ul>
|
||||
{loop type="best_selling_products" name="best-sellers" limit=10 order='sold_count'}
|
||||
<li>{$REF} : {$TITLE} : {$SOLD_QUANTITY}</li>
|
||||
{/loop}
|
||||
</ul>
|
||||
11
local/modules/BestSellers/composer.json
Normal file
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"name": "cqfdev/best-sellers-module",
|
||||
"license": "LGPL-3.0-or-later",
|
||||
"type": "thelia-module",
|
||||
"require": {
|
||||
"thelia/installer": "~1.1"
|
||||
},
|
||||
"extra": {
|
||||
"installer-name": "BestSellers"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,149 @@
|
||||
{extends file="admin-layout.tpl"}
|
||||
|
||||
{block name="no-return-functions"}
|
||||
{$admin_current_location = 'tools'}
|
||||
|
||||
{$page = $smarty.get.page|default:1}
|
||||
{$order = $smarty.get.order|default:'sold_count_reverse'}
|
||||
|
||||
{$maxYear = $smarty.now|date_format:'%Y'}
|
||||
{$minYear = $maxYear}
|
||||
{loop type="order" name="first-order" customer="*" order="create-date" limit=1}
|
||||
{$minYear = {format_date date=$CREATE_DATE format="Y"}}
|
||||
{/loop}
|
||||
|
||||
{$startDate = $smarty.get.startDate|default:"$minYear-01-01"}
|
||||
{$endDate = $smarty.get.endDate|default:$smarty.now|date_format:'%Y-%m-%d'}
|
||||
{/block}
|
||||
|
||||
{block name="page-title"}{intl l='Best sellers' d='bestsellers.bo.default'}{/block}
|
||||
|
||||
{block name="check-resource"}admin.bestsellers{/block}
|
||||
{block name="check-access"}view{/block}
|
||||
|
||||
{block name="main-content"}
|
||||
<div id="wrapper" class="container">
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<div class="general-block-decorator">
|
||||
<form class="form-inline" action="{url path="/admin/best-sellers"}" method="GET" style="margin-bottom: 20px;">
|
||||
<input type="hidden" name="order" value="{$order}">
|
||||
|
||||
<div class="form-group">
|
||||
<label for="start-date">{intl l='View from : ' d='bestsellers.bo.default'}</label>
|
||||
<input id="start-date" class="form-control datecombo" data-format="YYYY-MM-DD" data-template="DD / MM / YYYY" name="startDate" value="{$startDate}" type="text">
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="end-date">{intl l=' to : ' d='bestsellers.bo.default'}</label>
|
||||
<input id="end-date" class="form-control datecombo" data-format="YYYY-MM-DD" data-template="DD / MM / YYYY" name="endDate" value="{$endDate}" type="text">
|
||||
</div>
|
||||
|
||||
<button type="submit" class="btn btn-primary">{intl l='View' d='bestsellers.bo.default'}</button>
|
||||
</form>
|
||||
|
||||
{ifloop rel="sales-count"}
|
||||
<table class="table table-bordered table-condensed table-hover">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>
|
||||
{admin_sortable_header
|
||||
current_order=$order
|
||||
order='ref'
|
||||
reverse_order='ref_reverse'
|
||||
path="/admin/best-sellers?startDate=$startDate&endDate=$endDate"
|
||||
label={intl l="Product reference" d='bestsellers.bo.default'}
|
||||
}
|
||||
</th>
|
||||
<th>
|
||||
{admin_sortable_header
|
||||
current_order=$order
|
||||
order='alpha'
|
||||
reverse_order='alpha_reverse'
|
||||
path="/admin/best-sellers?startDate=$startDate&endDate=$endDate"
|
||||
label={intl l="Product title" d='bestsellers.bo.default'}
|
||||
}
|
||||
</th>
|
||||
<th class="text-right">
|
||||
{admin_sortable_header
|
||||
current_order=$order
|
||||
order='sold_count'
|
||||
reverse_order='sold_count_reverse'
|
||||
path="/admin/best-sellers?startDate=$startDate&endDate=$endDate"
|
||||
label={intl l="Sales total" d='bestsellers.bo.default'}
|
||||
}
|
||||
</th>
|
||||
<th class="text-right">
|
||||
{admin_sortable_header
|
||||
current_order=$order
|
||||
order='sold_amount'
|
||||
reverse_order='sold_amount_reverse'
|
||||
path="/admin/best-sellers?startDate=$startDate&endDate=$endDate"
|
||||
label={intl l="Total amount" d='bestsellers.bo.default'}
|
||||
}
|
||||
</th>
|
||||
<th class="text-right">
|
||||
{admin_sortable_header
|
||||
current_order=$order
|
||||
order='sale_ratio'
|
||||
reverse_order='sale_ratio_reverse'
|
||||
path="/admin/best-sellers?startDate=$startDate&endDate=$endDate"
|
||||
label={intl l="Sale ratio" d='bestsellers.bo.default'}
|
||||
}
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{loop type="best_selling_products" name="sales-count" backend_context=true visible='*' order=$order limit=20 page=$page start_date=$startDate end_date=$endDate return_url=false}
|
||||
<tr>
|
||||
<td><a href="{url path="/admin/products/update" product_id=$ID}">{$REF}</a></td>
|
||||
<td><a href="{url path="/admin/products/update" product_id=$ID}">{$TITLE}</a></td>
|
||||
<td class="text-right">{$SOLD_QUANTITY|round}</td>
|
||||
<td class="text-right">{format_money number=$SOLD_AMOUNT}</td>
|
||||
<td class="text-right">{$SALE_RATIO|string_format:"%.2f"}%</td>
|
||||
|
||||
</tr>
|
||||
{/loop}
|
||||
<tfoot>
|
||||
<tr>
|
||||
<td colspan="100">
|
||||
{include
|
||||
file = "includes/pagination.html"
|
||||
loop_ref = "sales-count"
|
||||
max_page_count = 10
|
||||
page_url = {url path="/admin/best-sellers" order=$order startDate=$startDate endDate=$endDate}
|
||||
}
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
</tfoot>
|
||||
|
||||
</table>
|
||||
{/ifloop}
|
||||
|
||||
{elseloop rel="sales-count"}
|
||||
<div class="alert alert-info">
|
||||
{intl l="You have not sold any products yet" d='bestsellers.bo.default'}
|
||||
</div>
|
||||
{/elseloop}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{/block}
|
||||
|
||||
{block name="javascript-initialization"}
|
||||
<script src="{javascript file="/assets/js/moment-with-locales.min.js"}"></script>
|
||||
<script src="{javascript file="/assets/js/bootstrap-editable/bootstrap-editable.js"}"></script>
|
||||
<script>
|
||||
$(function(){
|
||||
$('.datecombo').combodate({
|
||||
minYear: {$minYear},
|
||||
maxYear: {$maxYear},
|
||||
firstItem: 'none'
|
||||
});
|
||||
|
||||
$('select', '.combodate').addClass('form-control');
|
||||
})
|
||||
</script>
|
||||
{/block}
|
||||
@@ -0,0 +1,14 @@
|
||||
{loop type="best_selling_products" name="sales-count" backend_context=true visible='*' id=$product_id return_url=false}
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<h3 class="panel-title">{intl d='bestsellers.bo.default' l="Statistics"}</h3>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<ul>
|
||||
<li>{intl d='bestsellers.bo.default' l="Total sales for this product: <strong>%count</strong>" count=$SOLD_QUANTITY|round}</li>
|
||||
<li>{intl d='bestsellers.bo.default' l="Sold amount for this product: <strong>%count</strong>" count={format_money number=$SOLD_AMOUNT}}</li>
|
||||
<li>{intl d='bestsellers.bo.default' l="% of sales: <strong>%count%</strong>" count=$SALE_RATIO|string_format:"%.2f"}</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
{/loop}
|
||||
@@ -0,0 +1,15 @@
|
||||
{ifloop rel="best-selling"}
|
||||
<section id="best-selling-products" class="grid">
|
||||
<div class="products-heading">
|
||||
<h2>{intl l="Best sellers" d="bestsellers.fo.default"}</h2>
|
||||
</div>
|
||||
|
||||
<div class="products-content">
|
||||
<ul class="products-grid list-unstyled row">
|
||||
{loop name="best-selling" type="best_selling_products" limit="4" order="sold_count_reverse"}
|
||||
{include file="includes/single-product.html" colClass="col-md-3 col-sm-4" product_id=$ID hasBtn=false hasDescription=false width="218" height="146"}
|
||||
{/loop}
|
||||
</ul>
|
||||
</div>
|
||||
</section>
|
||||
{/ifloop}
|
||||
6
local/modules/Carousel/CHANGELOG.md
Normal file
@@ -0,0 +1,6 @@
|
||||
# 2.3.0-alpha1
|
||||
|
||||
- Moved the images from the directory 'media' in the module to thelia/local/media/images/carousel.
|
||||
- The current images will be automatically copied in the new directory during the update of the module
|
||||
- Removed AdminIncludes directory
|
||||
- All html,js and css files are now in 'templates'
|
||||
89
local/modules/Carousel/Carousel.php
Normal file
@@ -0,0 +1,89 @@
|
||||
<?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 Carousel;
|
||||
|
||||
use Propel\Runtime\Connection\ConnectionInterface;
|
||||
use Symfony\Component\Filesystem\Filesystem;
|
||||
use Symfony\Component\Finder\Finder;
|
||||
use Symfony\Component\Finder\SplFileInfo;
|
||||
use Thelia\Install\Database;
|
||||
use Thelia\Model\ConfigQuery;
|
||||
use Thelia\Module\BaseModule;
|
||||
|
||||
/**
|
||||
* Class Carousel
|
||||
* @package Carousel
|
||||
* @author Franck Allimant <franck@cqfdev.fr>
|
||||
*/
|
||||
class Carousel extends BaseModule
|
||||
{
|
||||
const DOMAIN_NAME = 'carousel';
|
||||
|
||||
public function preActivation(ConnectionInterface $con = null)
|
||||
{
|
||||
if (! $this->getConfigValue('is_initialized', false)) {
|
||||
$database = new Database($con);
|
||||
|
||||
$database->insertSql(null, array(__DIR__ . '/Config/thelia.sql'));
|
||||
|
||||
$this->setConfigValue('is_initialized', true);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function destroy(ConnectionInterface $con = null, $deleteModuleData = false)
|
||||
{
|
||||
$database = new Database($con);
|
||||
|
||||
$database->insertSql(null, array(__DIR__ . '/Config/sql/destroy.sql'));
|
||||
}
|
||||
|
||||
public function getUploadDir()
|
||||
{
|
||||
$uploadDir = ConfigQuery::read('images_library_path');
|
||||
|
||||
if ($uploadDir === null) {
|
||||
$uploadDir = THELIA_LOCAL_DIR . 'media' . DS . 'images';
|
||||
} else {
|
||||
$uploadDir = THELIA_ROOT . $uploadDir;
|
||||
}
|
||||
|
||||
return $uploadDir . DS . Carousel::DOMAIN_NAME;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $currentVersion
|
||||
* @param string $newVersion
|
||||
* @param ConnectionInterface $con
|
||||
* @author Thomas Arnaud <tarnaud@openstudio.fr>
|
||||
*/
|
||||
public function update($currentVersion, $newVersion, ConnectionInterface $con = null)
|
||||
{
|
||||
$uploadDir = $this->getUploadDir();
|
||||
$fileSystem = new Filesystem();
|
||||
|
||||
if (!$fileSystem->exists($uploadDir) && $fileSystem->exists(__DIR__ . DS . 'media' . DS . 'carousel')) {
|
||||
$finder = new Finder();
|
||||
$finder->files()->in(__DIR__ . DS . 'media' . DS . 'carousel');
|
||||
|
||||
$fileSystem->mkdir($uploadDir);
|
||||
|
||||
/** @var SplFileInfo $file */
|
||||
foreach ($finder as $file) {
|
||||
copy($file, $uploadDir . DS . $file->getRelativePathname());
|
||||
}
|
||||
$fileSystem->remove(__DIR__ . DS . 'media');
|
||||
}
|
||||
}
|
||||
}
|
||||
25
local/modules/Carousel/Config/config.xml
Normal file
@@ -0,0 +1,25 @@
|
||||
<?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>
|
||||
<loop name="carousel" class="Carousel\Loop\CarouselLoop" />
|
||||
</loops>
|
||||
|
||||
<forms>
|
||||
<form name="carousel.image" class="Carousel\Form\CarouselImageForm" />
|
||||
<form name="carousel.update" class="Carousel\Form\CarouselUpdateForm" />
|
||||
</forms>
|
||||
|
||||
<hooks>
|
||||
<hook id="carousel.hook">
|
||||
<tag name="hook.event_listener" event="home.body" type="front" templates="render:carousel.html" />
|
||||
<tag name="hook.event_listener" event="module.configuration" type="back" templates="render:module_configuration.html" />
|
||||
<tag name="hook.event_listener" event="module.config-js" type="back" templates="js:assets/js/module-configuration.js" />
|
||||
</hook>
|
||||
<hook id="carousel.hook.back" class="Carousel\Hook\BackHook">
|
||||
<tag name="hook.event_listener" event="main.top-menu-tools" type="back" />
|
||||
</hook>
|
||||
</hooks>
|
||||
</config>
|
||||
24
local/modules/Carousel/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>Carousel\Carousel</fullnamespace>
|
||||
<descriptive locale="en_US">
|
||||
<title>An image carousel</title>
|
||||
</descriptive>
|
||||
<descriptive locale="fr_FR">
|
||||
<title>Un carrousel d'images</title>
|
||||
</descriptive>
|
||||
<languages>
|
||||
<language>en_US</language>
|
||||
<language>fr_FR</language>
|
||||
</languages>
|
||||
<version>2.3.5</version>
|
||||
<author>
|
||||
<name>Manuel Raynaud, Franck Allimant</name>
|
||||
<email>manu@raynaud.io, franck@cqfdev.fr</email>
|
||||
</author>
|
||||
<type>classic</type>
|
||||
<thelia>2.2.0</thelia>
|
||||
<stability>alpha</stability>
|
||||
</module>
|
||||
42
local/modules/Carousel/Config/routing.xml
Normal file
@@ -0,0 +1,42 @@
|
||||
<?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/carousel/ 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/carousel">
|
||||
<default key="_controller">Carousel\Full\Class\Name\Of\YourConfigurationController::methodName</default>
|
||||
</route>
|
||||
|
||||
<route id="my_route_id" path="/admin/module/carousel/route-name">
|
||||
<default key="_controller">Carousel\Full\Class\Name\Of\YourAdminController::methodName</default>
|
||||
</route>
|
||||
|
||||
<route id="my_route_id" path="/my/route/name">
|
||||
<default key="_controller">Carousel\Full\Class\Name\Of\YourOtherController::methodName</default>
|
||||
</route>
|
||||
|
||||
...add as many routes as required.
|
||||
|
||||
<route>
|
||||
...
|
||||
</route>
|
||||
-->
|
||||
<route id="carousel.upload.image" path="/admin/module/carousel/upload" methods="post">
|
||||
<default key="_controller">Carousel\Controller\ConfigurationController::uploadImage</default>
|
||||
</route>
|
||||
|
||||
<route id="carousel.update" path="/admin/module/carousel/update" methods="post">
|
||||
<default key="_controller">Carousel\Controller\ConfigurationController::updateAction</default>
|
||||
</route>
|
||||
|
||||
<route id="carousel.delete" path="/admin/module/carousel/delete" methods="post">
|
||||
<default key="_controller">Carousel\Controller\ConfigurationController::deleteAction</default>
|
||||
</route>
|
||||
|
||||
</routes>
|
||||
24
local/modules/Carousel/Config/schema.xml
Normal file
@@ -0,0 +1,24 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<database defaultIdMethod="native" name="thelia" namespace="Carousel\Model">
|
||||
<!--
|
||||
See propel documentation on http://propelorm.org for all information about schema file
|
||||
-->
|
||||
|
||||
<table name="carousel">
|
||||
<column autoIncrement="true" name="id" primaryKey="true" required="true" type="INTEGER" />
|
||||
<column name="file" type="VARCHAR" size="255" />
|
||||
<column name="position" type="INTEGER" />
|
||||
<column name="alt" size="255" type="VARCHAR" />
|
||||
<column name="url" size="255" type="VARCHAR" />
|
||||
<column name="title" size="255" type="VARCHAR" />
|
||||
<column name="description" type="CLOB" />
|
||||
<column name="chapo" type="LONGVARCHAR" />
|
||||
<column name="postscriptum" type="LONGVARCHAR" />
|
||||
<behavior name="timestampable" />
|
||||
<behavior name="i18n">
|
||||
<parameter name="i18n_columns" value="alt, title, description, chapo, postscriptum" />
|
||||
</behavior>
|
||||
</table>
|
||||
|
||||
<external-schema filename="local/config/schema.xml" referenceOnly="true" />
|
||||
</database>
|
||||
6
local/modules/Carousel/Config/sql/destroy.sql
Normal file
@@ -0,0 +1,6 @@
|
||||
SET FOREIGN_KEY_CHECKS = 0;
|
||||
|
||||
DROP TABLE IF EXISTS `carousel`;
|
||||
DROP TABLE IF EXISTS `carousel_i18n`;
|
||||
|
||||
SET FOREIGN_KEY_CHECKS = 1;
|
||||
43
local/modules/Carousel/Config/thelia.sql
Normal file
@@ -0,0 +1,43 @@
|
||||
# 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;
|
||||
|
||||
-- ---------------------------------------------------------------------
|
||||
-- carousel
|
||||
-- ---------------------------------------------------------------------
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `carousel`
|
||||
(
|
||||
`id` INTEGER NOT NULL AUTO_INCREMENT,
|
||||
`file` VARCHAR(255),
|
||||
`position` INTEGER,
|
||||
`url` VARCHAR(255),
|
||||
`created_at` DATETIME,
|
||||
`updated_at` DATETIME,
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=InnoDB;
|
||||
|
||||
-- ---------------------------------------------------------------------
|
||||
-- carousel_i18n
|
||||
-- ---------------------------------------------------------------------
|
||||
|
||||
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `carousel_i18n`
|
||||
(
|
||||
`id` INTEGER NOT NULL,
|
||||
`locale` VARCHAR(5) DEFAULT 'en_US' NOT NULL,
|
||||
`alt` VARCHAR(255),
|
||||
`title` VARCHAR(255),
|
||||
`description` LONGTEXT,
|
||||
`chapo` TEXT,
|
||||
`postscriptum` TEXT,
|
||||
PRIMARY KEY (`id`,`locale`),
|
||||
CONSTRAINT `carousel_i18n_FK_1`
|
||||
FOREIGN KEY (`id`)
|
||||
REFERENCES `carousel` (`id`)
|
||||
ON DELETE CASCADE
|
||||
) ENGINE=InnoDB;
|
||||
|
||||
# This restores the fkey checks, after having unset them earlier
|
||||
SET FOREIGN_KEY_CHECKS = 1;
|
||||
184
local/modules/Carousel/Controller/ConfigurationController.php
Normal file
@@ -0,0 +1,184 @@
|
||||
<?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 Carousel\Controller;
|
||||
|
||||
use Carousel\Model\Carousel;
|
||||
use Carousel\Model\CarouselQuery;
|
||||
use Symfony\Component\Form\Form;
|
||||
use Symfony\Component\HttpFoundation\RedirectResponse;
|
||||
use Thelia\Controller\Admin\BaseAdminController;
|
||||
use Thelia\Core\Event\File\FileCreateOrUpdateEvent;
|
||||
use Thelia\Core\Event\TheliaEvents;
|
||||
use Thelia\Core\Security\AccessManager;
|
||||
use Thelia\Core\Security\Resource\AdminResources;
|
||||
use Thelia\Form\Exception\FormValidationException;
|
||||
use Thelia\Model\Lang;
|
||||
use Thelia\Model\LangQuery;
|
||||
use Thelia\Tools\URL;
|
||||
|
||||
/**
|
||||
* Class ConfigurationController
|
||||
* @package Carousel\Controller
|
||||
* @author manuel raynaud <mraynaud@openstudio.fr>
|
||||
*/
|
||||
class ConfigurationController extends BaseAdminController
|
||||
{
|
||||
|
||||
public function uploadImage()
|
||||
{
|
||||
if (null !== $response = $this->checkAuth(AdminResources::MODULE, ['carousel'], AccessManager::CREATE)) {
|
||||
return $response;
|
||||
}
|
||||
|
||||
$request = $this->getRequest();
|
||||
$form = $this->createForm('carousel.image');
|
||||
$error_message = null;
|
||||
try {
|
||||
$this->validateForm($form);
|
||||
|
||||
/** @var \Symfony\Component\HttpFoundation\File\UploadedFile $fileBeingUploaded */
|
||||
$fileBeingUploaded = $request->files->get(sprintf('%s[file]', $form->getName()), null, true);
|
||||
|
||||
$fileModel = new Carousel();
|
||||
|
||||
$fileCreateOrUpdateEvent = new FileCreateOrUpdateEvent(1);
|
||||
$fileCreateOrUpdateEvent->setModel($fileModel);
|
||||
$fileCreateOrUpdateEvent->setUploadedFile($fileBeingUploaded);
|
||||
|
||||
$this->dispatch(
|
||||
TheliaEvents::IMAGE_SAVE,
|
||||
$fileCreateOrUpdateEvent
|
||||
);
|
||||
|
||||
// Compensate issue #1005
|
||||
$langs = LangQuery::create()->find();
|
||||
|
||||
/** @var Lang $lang */
|
||||
foreach ($langs as $lang) {
|
||||
$fileCreateOrUpdateEvent->getModel()->setLocale($lang->getLocale())->setTitle('')->save();
|
||||
}
|
||||
|
||||
$response = $this->redirectToConfigurationPage();
|
||||
|
||||
} catch (FormValidationException $e) {
|
||||
$error_message = $this->createStandardFormValidationErrorMessage($e);
|
||||
}
|
||||
|
||||
if (null !== $error_message) {
|
||||
$this->setupFormErrorContext(
|
||||
'carousel upload',
|
||||
$error_message,
|
||||
$form
|
||||
);
|
||||
|
||||
$response = $this->render(
|
||||
"module-configure",
|
||||
[
|
||||
'module_code' => 'Carousel'
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Form $form
|
||||
* @param string $fieldName
|
||||
* @param int $id
|
||||
* @return string
|
||||
*/
|
||||
protected function getFormFieldValue($form, $fieldName, $id)
|
||||
{
|
||||
$value = $form->get(sprintf('%s%d', $fieldName, $id))->getData();
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
public function updateAction()
|
||||
{
|
||||
if (null !== $response = $this->checkAuth(AdminResources::MODULE, ['carousel'], AccessManager::UPDATE)) {
|
||||
return $response;
|
||||
}
|
||||
|
||||
$form = $this->createForm('carousel.update');
|
||||
|
||||
$error_message = null;
|
||||
|
||||
try {
|
||||
$updateForm = $this->validateForm($form);
|
||||
|
||||
$carousels = CarouselQuery::create()->findAllByPosition();
|
||||
|
||||
$locale = $this->getCurrentEditionLocale();
|
||||
|
||||
/** @var Carousel $carousel */
|
||||
foreach ($carousels as $carousel) {
|
||||
$id = $carousel->getId();
|
||||
|
||||
$carousel
|
||||
->setPosition($this->getFormFieldValue($updateForm, 'position', $id))
|
||||
->setUrl($this->getFormFieldValue($updateForm, 'url', $id))
|
||||
->setLocale($locale)
|
||||
->setTitle($this->getFormFieldValue($updateForm, 'title', $id))
|
||||
->setAlt($this->getFormFieldValue($updateForm, 'alt', $id))
|
||||
->setChapo($this->getFormFieldValue($updateForm, 'chapo', $id))
|
||||
->setDescription($this->getFormFieldValue($updateForm, 'description', $id))
|
||||
->setPostscriptum($this->getFormFieldValue($updateForm, 'postscriptum', $id))
|
||||
->save();
|
||||
}
|
||||
|
||||
$response = $this->redirectToConfigurationPage();
|
||||
|
||||
} catch (FormValidationException $e) {
|
||||
$error_message = $this->createStandardFormValidationErrorMessage($e);
|
||||
}
|
||||
|
||||
if (null !== $error_message) {
|
||||
$this->setupFormErrorContext(
|
||||
'carousel upload',
|
||||
$error_message,
|
||||
$form
|
||||
);
|
||||
|
||||
$response = $this->render("module-configure", [ 'module_code' => 'Carousel' ]);
|
||||
}
|
||||
|
||||
return $response;
|
||||
|
||||
}
|
||||
|
||||
public function deleteAction()
|
||||
{
|
||||
if (null !== $response = $this->checkAuth(AdminResources::MODULE, ['carousel'], AccessManager::DELETE)) {
|
||||
return $response;
|
||||
}
|
||||
|
||||
$imageId = $this->getRequest()->request->get('image_id');
|
||||
|
||||
if ($imageId != "") {
|
||||
$carousel = CarouselQuery::create()->findPk($imageId);
|
||||
|
||||
if (null !== $carousel) {
|
||||
$carousel->delete();
|
||||
}
|
||||
}
|
||||
|
||||
return $this->redirectToConfigurationPage();
|
||||
}
|
||||
|
||||
protected function redirectToConfigurationPage()
|
||||
{
|
||||
return RedirectResponse::create(URL::getInstance()->absoluteUrl('/admin/module/Carousel'));
|
||||
}
|
||||
}
|
||||
56
local/modules/Carousel/Form/CarouselImageForm.php
Normal file
@@ -0,0 +1,56 @@
|
||||
<?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 Carousel\Form;
|
||||
|
||||
use Carousel\Carousel;
|
||||
use Symfony\Component\Validator\Constraints\Image;
|
||||
use Thelia\Core\Translation\Translator;
|
||||
use Thelia\Form\BaseForm;
|
||||
|
||||
/**
|
||||
* Class CarouselImageForm
|
||||
* @package Carousel\Form
|
||||
* @author manuel raynaud <mraynaud@openstudio.fr>
|
||||
*/
|
||||
class CarouselImageForm extends BaseForm
|
||||
{
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
protected function buildForm()
|
||||
{
|
||||
$translator = Translator::getInstance();
|
||||
$this->formBuilder
|
||||
->add(
|
||||
'file',
|
||||
'file',
|
||||
[
|
||||
'constraints' => [
|
||||
new Image()
|
||||
],
|
||||
'label' => $translator->trans('Carousel image', [], Carousel::DOMAIN_NAME),
|
||||
'label_attr' => [
|
||||
'for' => 'file'
|
||||
]
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string the name of you form. This name must be unique
|
||||
*/
|
||||
public function getName()
|
||||
{
|
||||
return 'carousel_image';
|
||||
}
|
||||
}
|
||||
166
local/modules/Carousel/Form/CarouselUpdateForm.php
Normal file
@@ -0,0 +1,166 @@
|
||||
<?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 Carousel\Form;
|
||||
|
||||
use Carousel\Carousel;
|
||||
use Carousel\Model\CarouselQuery;
|
||||
use Thelia\Form\BaseForm;
|
||||
|
||||
/**
|
||||
* Class CarouselUpdateForm
|
||||
* @package Carousel\Form
|
||||
* @author manuel raynaud <mraynaud@openstudio.fr>
|
||||
*/
|
||||
class CarouselUpdateForm extends BaseForm
|
||||
{
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
protected function buildForm()
|
||||
{
|
||||
$formBuilder = $this->formBuilder;
|
||||
|
||||
$carousels = CarouselQuery::create()->orderByPosition()->find();
|
||||
|
||||
/** @var \Carousel\Model\Carousel $carousel */
|
||||
foreach ($carousels as $carousel) {
|
||||
$id = $carousel->getId();
|
||||
|
||||
$formBuilder->add(
|
||||
'position' . $id,
|
||||
'text',
|
||||
[
|
||||
'label' => $this->translator->trans('Image position in carousel', [], Carousel::DOMAIN_NAME),
|
||||
'label_attr' => [
|
||||
'for' => 'position' . $id
|
||||
],
|
||||
'required' => false,
|
||||
'attr' => [
|
||||
'placeholder' => $this->translator->trans(
|
||||
'Image position in carousel',
|
||||
[],
|
||||
Carousel::DOMAIN_NAME
|
||||
)
|
||||
]
|
||||
]
|
||||
)->add(
|
||||
'alt' . $id,
|
||||
'text',
|
||||
[
|
||||
'label' => $this->translator->trans('Alternative image text', [], Carousel::DOMAIN_NAME),
|
||||
'label_attr' => [
|
||||
'for' => 'alt' . $id
|
||||
],
|
||||
'required' => false,
|
||||
'attr' => [
|
||||
'placeholder' => $this->translator->trans(
|
||||
'Displayed when image is not visible',
|
||||
[],
|
||||
Carousel::DOMAIN_NAME
|
||||
)
|
||||
]
|
||||
]
|
||||
)->add(
|
||||
'url' . $id,
|
||||
'url',
|
||||
[
|
||||
'label' => $this->translator->trans('Image URL', [], Carousel::DOMAIN_NAME),
|
||||
'label_attr' => [
|
||||
'for' => 'url' . $id
|
||||
],
|
||||
'required' => false,
|
||||
'attr' => [
|
||||
'placeholder' => $this->translator->trans(
|
||||
'Please enter a valid URL',
|
||||
[],
|
||||
Carousel::DOMAIN_NAME
|
||||
)
|
||||
]
|
||||
]
|
||||
)->add(
|
||||
'title' . $id,
|
||||
'text',
|
||||
[
|
||||
'constraints' => [],
|
||||
'required' => false,
|
||||
'label' => $this->translator->trans('Title'),
|
||||
'label_attr' => [
|
||||
'for' => 'title_field' . $id
|
||||
],
|
||||
'attr' => [
|
||||
'placeholder' => $this->translator->trans('A descriptive title')
|
||||
]
|
||||
]
|
||||
)->add(
|
||||
'chapo' . $id,
|
||||
'textarea',
|
||||
[
|
||||
'constraints' => [],
|
||||
'required' => false,
|
||||
'label' => $this->translator->trans('Summary'),
|
||||
'label_attr' => [
|
||||
'for' => 'summary_field' . $id,
|
||||
'help' => $this->translator->trans(
|
||||
'A short description, used when a summary or an introduction is required'
|
||||
)
|
||||
],
|
||||
'attr' => [
|
||||
'rows' => 3,
|
||||
'placeholder' => $this->translator->trans('Short description text')
|
||||
]
|
||||
]
|
||||
)->add(
|
||||
'description' . $id,
|
||||
'textarea',
|
||||
[
|
||||
'constraints' => [],
|
||||
'required' => false,
|
||||
'label' => $this->translator->trans('Detailed description'),
|
||||
'label_attr' => [
|
||||
'for' => 'detailed_description_field' . $id,
|
||||
'help' => $this->translator->trans('The detailed description.')
|
||||
],
|
||||
'attr' => [
|
||||
'rows' => 5
|
||||
]
|
||||
]
|
||||
)->add(
|
||||
'postscriptum' . $id,
|
||||
'textarea',
|
||||
[
|
||||
'constraints' => [],
|
||||
'required' => false,
|
||||
'label' => $this->translator->trans('Conclusion'),
|
||||
'label_attr' => [
|
||||
'for' => 'conclusion_field' . $id,
|
||||
'help' => $this->translator->trans(
|
||||
'A short text, used when an additional or supplemental information is required.'
|
||||
)
|
||||
],
|
||||
'attr' => [
|
||||
'placeholder' => $this->translator->trans('Short additional text'),
|
||||
'rows' => 3,
|
||||
]
|
||||
]
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function getName()
|
||||
{
|
||||
return "carousel_update";
|
||||
}
|
||||
}
|
||||
48
local/modules/Carousel/Hook/BackHook.php
Normal file
@@ -0,0 +1,48 @@
|
||||
<?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 Carousel\Hook;
|
||||
|
||||
use Carousel\Carousel;
|
||||
use Thelia\Core\Event\Hook\HookRenderBlockEvent;
|
||||
use Thelia\Core\Event\Hook\HookRenderEvent;
|
||||
use Thelia\Core\Hook\BaseHook;
|
||||
use Thelia\Tools\URL;
|
||||
|
||||
/**
|
||||
* Class BackHook
|
||||
* @package Carousel\Hook
|
||||
* @author Emmanuel Nurit <enurit@openstudio.fr>
|
||||
*/
|
||||
class BackHook extends BaseHook
|
||||
{
|
||||
|
||||
/**
|
||||
* Add a new entry in the admin tools menu
|
||||
*
|
||||
* should add to event a fragment with fields : id,class,url,title
|
||||
*
|
||||
* @param HookRenderBlockEvent $event
|
||||
*/
|
||||
public function onMainTopMenuTools(HookRenderBlockEvent $event)
|
||||
{
|
||||
$event->add(
|
||||
[
|
||||
'id' => 'tools_menu_carousel',
|
||||
'class' => '',
|
||||
'url' => URL::getInstance()->absoluteUrl('/admin/module/Carousel'),
|
||||
'title' => $this->trans('Edit your carousel', [], Carousel::DOMAIN_NAME)
|
||||
]
|
||||
);
|
||||
}
|
||||
}
|
||||
14
local/modules/Carousel/I18n/backOffice/default/de_DE.php
Normal file
@@ -0,0 +1,14 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
'Add an image to the carousel' => 'Ein Bild zu Karussell hinzufügen',
|
||||
'Add this image to the carousel' => 'Dieses Bild zu Karussell hinzufügen',
|
||||
'Carousel image' => 'Karussell-Bild',
|
||||
'Carousel images' => 'Karussell-Bilder',
|
||||
'Delete a carousel image' => 'Ein Karussell-Bild löschen',
|
||||
'Do you really want to remove this image from the carousel ?' => 'Wollen Sie dieses Bild wirklich aus dem Karussell entfernen?',
|
||||
'Edit your carousel.' => 'Karussell bearbeiten.',
|
||||
'Remove this image' => 'Dieses Bild entfernen',
|
||||
'Your carousel contains no image. Please add one using the form above.' => 'Das Karussell enthält kein Bild. Bitte fügen Sie mit dem Formular oben eines hinzu.',
|
||||
'Position' => 'Position',
|
||||
];
|
||||
14
local/modules/Carousel/I18n/backOffice/default/en_US.php
Normal file
@@ -0,0 +1,14 @@
|
||||
<?php
|
||||
|
||||
return array(
|
||||
'Add an image to the carousel' => 'Add an image to the carousel',
|
||||
'Add this image to the carousel' => 'Add this image to the carousel',
|
||||
'Carousel image' => 'Carousel image',
|
||||
'Carousel images' => 'Carousel images',
|
||||
'Delete a carousel image' => 'Delete a carousel image',
|
||||
'Do you really want to remove this image from the carousel ?' => 'Do you really want to remove this image from the carousel ?',
|
||||
'Edit your carousel.' => 'Edit your carousel.',
|
||||
'Remove this image' => 'Remove this image',
|
||||
'Your carousel contains no image. Please add one using the form above.' => 'Your carousel contains no image. Please add one using the form above.',
|
||||
'Position' => 'Position',
|
||||
);
|
||||
14
local/modules/Carousel/I18n/backOffice/default/fr_FR.php
Normal file
@@ -0,0 +1,14 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
'Add an image to the carousel' => 'Ajouter une image au carrousel',
|
||||
'Add this image to the carousel' => 'Ajouter l\'image au carrousel',
|
||||
'Carousel image' => 'Image du carrousel',
|
||||
'Carousel images' => 'Images du carrousel',
|
||||
'Delete a carousel image' => 'Supprimer une image du carrousel',
|
||||
'Do you really want to remove this image from the carousel ?' => 'Voulez-vous vraiment retirer cette image du carrousel ?',
|
||||
'Edit your carousel.' => 'Modifier votre carrousel',
|
||||
'Remove this image' => 'Supprimer cette image',
|
||||
'Your carousel contains no image. Please add one using the form above.' => 'Votre carrousel ne contient aucune image. Ajoutez votre première image avec le formulaire ci-dessus',
|
||||
'Position' => 'Position',
|
||||
];
|
||||
14
local/modules/Carousel/I18n/backOffice/default/ru_RU.php
Normal file
@@ -0,0 +1,14 @@
|
||||
<?php
|
||||
|
||||
return array(
|
||||
'Add an image to the carousel' => 'Добавить изображение в карусель',
|
||||
'Add this image to the carousel' => 'Добавить это изображение в карусель',
|
||||
'Carousel image' => 'Изображение карусели',
|
||||
'Carousel images' => 'Изображения карусели',
|
||||
'Delete a carousel image' => 'Удалить изображение карусели',
|
||||
'Do you really want to remove this image from the carousel ?' => 'Вы действительно хотите удалить это изображение из карусели ?',
|
||||
'Edit your carousel.' => 'Редактировать вашу карусель.',
|
||||
'Remove this image' => 'Удалить это изображение',
|
||||
'Your carousel contains no image. Please add one using the form above.' => 'Ваша карусель не содержит изображений. Пожалуйста, добавьте одно используя форму ниже.',
|
||||
'Position' => 'Позиция',
|
||||
);
|
||||
14
local/modules/Carousel/I18n/backOffice/default/tr_TR.php
Normal file
@@ -0,0 +1,14 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
'Add an image to the carousel' => 'Slayt için bir resim ekle',
|
||||
'Add this image to the carousel' => 'slayt için bu resim ekleme',
|
||||
'Carousel image' => 'slayt görüntü',
|
||||
'Carousel images' => 'slayt görüntüleri',
|
||||
'Delete a carousel image' => 'Bir slayt resmi silme',
|
||||
'Do you really want to remove this image from the carousel ?' => 'Bu görüntüyü slayttan kaldırmak istiyor musunuz?',
|
||||
'Edit your carousel.' => 'slayt düzenleyin.',
|
||||
'Remove this image' => 'Bu resmi kaldırma',
|
||||
'Your carousel contains no image. Please add one using the form above.' => 'Senin slayt hiçbir görüntü içermiyor . Lütfen yukarıdaki formu kullanarak ekleyin.',
|
||||
'Position' => 'Pozisyon',
|
||||
];
|
||||
20
local/modules/Carousel/I18n/de_DE.php
Normal file
@@ -0,0 +1,20 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
'A descriptive title' => 'Beschreibungstitel',
|
||||
'A short description, used when a summary or an introduction is required' => 'Eine kurze beschreibung, benutzt wenn eine Zusammenfassung order eine Einleitung ist nötig',
|
||||
'A short text, used when an additional or supplemental information is required.' => 'Ein kurzer Text, der verwendet wird, wenn eine zusätzliche oder ergänzende Information erforderlich ist.',
|
||||
'Alternative image text' => 'Alternativer Bildtext',
|
||||
'Carousel image' => 'Karussell-Bild',
|
||||
'Conclusion' => 'Abschluss',
|
||||
'Detailed description' => 'Detaillierte Beschreibung',
|
||||
'Displayed when image is not visible' => 'Angezeigt, wenn das Bild nicht sichtbar ist',
|
||||
'Image URL' => 'Bild-URL',
|
||||
'Image position in carousel' => 'Position des Bildes im Karussell',
|
||||
'Please enter a valid URL' => 'Bitte geben Sie eine gültige URL ein',
|
||||
'Short additional text' => 'Kurzer zusätzlicher Text',
|
||||
'Short description text' => 'Kurzes Beschreibungstext',
|
||||
'Summary' => 'Zusammenfassung',
|
||||
'The detailed description.' => 'Die detaillierte Beschreibung.',
|
||||
'Title' => 'Titel',
|
||||
];
|
||||
20
local/modules/Carousel/I18n/en_US.php
Normal file
@@ -0,0 +1,20 @@
|
||||
<?php
|
||||
|
||||
return array(
|
||||
'A descriptive title' => 'A descriptive title',
|
||||
'A short description, used when a summary or an introduction is required' => 'A short description, used when a summary or an introduction is required',
|
||||
'A short text, used when an additional or supplemental information is required.' => 'A short text, used when an additional or supplemental information is required.',
|
||||
'Alternative image text' => 'Alternative image text',
|
||||
'Carousel image' => 'Carousel image',
|
||||
'Conclusion' => 'Conclusion',
|
||||
'Detailed description' => 'Detailed description',
|
||||
'Displayed when image is not visible' => 'Displayed when image is not visible',
|
||||
'Image URL' => 'Image URL',
|
||||
'Image position in carousel' => 'Image position in carousel',
|
||||
'Please enter a valid URL' => 'Please enter a valid URL',
|
||||
'Short additional text' => 'Short additional text',
|
||||
'Short description text' => 'Short description text',
|
||||
'Summary' => 'Summary',
|
||||
'The detailed description.' => 'The detailed description.',
|
||||
'Title' => 'Title',
|
||||
);
|
||||
20
local/modules/Carousel/I18n/fr_FR.php
Normal file
@@ -0,0 +1,20 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
'A descriptive title' => 'Un titre descriptif',
|
||||
'A short description, used when a summary or an introduction is required' => 'Une courte description, utilisée lorsqu\'un résumé ou une introduction est requise',
|
||||
'A short text, used when an additional or supplemental information is required.' => 'Un texte court, utilisé quand une conclusion ou une information complémentaire est nécessaire.',
|
||||
'Alternative image text' => 'Texte alternatif de l\'image',
|
||||
'Carousel image' => 'Image du carrousel',
|
||||
'Conclusion' => 'Conclusion',
|
||||
'Detailed description' => 'Description détaillée',
|
||||
'Displayed when image is not visible' => 'Affiché lorsque l\'image n\'est pas visible',
|
||||
'Image URL' => 'URL de l\'image',
|
||||
'Image position in carousel' => 'Position de l\'image dans le carrousel',
|
||||
'Please enter a valid URL' => 'Merci d\'ndiquer une URL valide',
|
||||
'Short additional text' => 'Un court texte supplémentaire',
|
||||
'Short description text' => 'Un court texte de description',
|
||||
'Summary' => 'Résumé',
|
||||
'The detailed description.' => 'La description détaillée.',
|
||||
'Title' => 'Titre',
|
||||
];
|
||||