Commit du répertoire FedEx

This commit is contained in:
2020-11-13 10:50:08 +01:00
parent 898aa9df75
commit 63504d5f90
21 changed files with 1102 additions and 0 deletions

View File

@@ -0,0 +1,38 @@
<?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 class="FedEx\Loop\Price" name="fedex"/>
<loop class="FedEx\Loop\CheckRightsLoop" name="fedex.check.rights" />
<loop class="FedEx\Loop\NotSendLoop" name="fedex.notsend.loop" />
</loops>
<forms>
<form name="fedex.configuration" class="FedEx\Form\Configuration" />
</forms>
<services>
<service id="send.fedex.mail" class="FedEx\Listener\SendMail">
<argument type="service" id="thelia.parser" />
<argument type="service" id="mailer"/>
<tag name="kernel.event_subscriber"/>
</service>
</services>
<!-- <services>-->
<!-- <service id="area.deleted.listener" class="FedEx\EventListener\AreaDeletedListener" scope="request">-->
<!-- <tag name="kernel.event_subscriber"/>-->
<!-- <argument type="service" id="request" />-->
<!-- </service>-->
<!-- </services>-->
<hooks>
<hook id="fedex.hook" class="FedEx\Hook\HookManager">
<tag name="hook.event_listener" event="module.configuration" type="back" method="onModuleConfiguration" />
<tag name="hook.event_listener" event="module.config-js" type="back" templates="render:assets/js/module-configuration-js.html" />
</hook>
</hooks>
</config>

View File

@@ -0,0 +1,18 @@
<?xml version="1.0" encoding="UTF-8"?>
<module>
<fullnamespace>FedEx\FedEx</fullnamespace>
<descriptive locale="en_US">
<title>FedEx delivery</title>
</descriptive>
<descriptive locale="fr_FR">
<title>Livraison par FedEx</title>
</descriptive>
<version>1.0.0</version>
<author>
<name>Laurent LE CORRE</name>
<email>laurent@thecoredev.fr</email>
</author>
<type>delivery</type>
<thelia>1.0.0</thelia>
<stability>alpha</stability>
</module>

View File

@@ -0,0 +1,13 @@
<?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="fedex.edit.prices" path="/admin/module/fedex/prices" methods="post">
<default key="_controller">FedEx\Controller\EditPrices::editprices</default>
</route>
<route id="fedex.configuration" path="/admin/module/fedex/configuration/update" methods="post">
<default key="_controller">FedEx\Controller\Configuration::editConfiguration</default>
</route>
</routes>

View File

@@ -0,0 +1,67 @@
<?php
namespace FedEx\Controller;
use FedEx\FedEx;
use FedEx\Model\Config\FedExConfigValue;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Thelia\Controller\Admin\BaseAdminController;
use Thelia\Core\Security\AccessManager;
use Thelia\Core\Security\Resource\AdminResources;
use Thelia\Form\Exception\FormValidationException;
use Thelia\Tools\URL;
/**
* Class Configuration
* @package FedEx\Controller
* @author Laurent LE CORRE <laurent@thecoredev.fr>
*/
class Configuration extends BaseAdminController
{
public function editConfiguration()
{
if (null !== $response = $this->checkAuth(
AdminResources::MODULE,
[FedEx::DOMAIN_NAME],
AccessManager::UPDATE
)) {
return $response;
}
$form = $this->createForm('fedex.configuration');
$error_message = null;
try {
$validateForm = $this->validateForm($form);
$data = $validateForm->getData();
FedEx::setConfigValue(
FedExConfigValue::TRACKING_URL,
$data["tracking_url"]
);
return $this->redirectToConfigurationPage();
} catch (FormValidationException $e) {
$error_message = $this->createStandardFormValidationErrorMessage($e);
}
if (null !== $error_message) {
$this->setupFormErrorContext(
'configuration',
$error_message,
$form
);
$response = $this->render("module-configure", ['module_code' => 'FedEx']);
}
return $response;
}
/**
* Redirect to the configuration page
*/
protected function redirectToConfigurationPage()
{
return RedirectResponse::create(URL::getInstance()->absoluteUrl('/admin/module/fedex'));
}
}

View File

@@ -0,0 +1,74 @@
<?php
namespace FedEx\Controller;
use FedEx\FedEx;
use FedEx\Model\Config\FedExConfigValue;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Thelia\Model\AreaQuery;
use Thelia\Controller\Admin\BaseAdminController;
use Thelia\Tools\URL;
/**
* Class EditPrices
* @package FedEx\Controller
* @author Laurent LE CORRE <laurent@thecoredev.fr>
*/
class EditPrices extends BaseAdminController
{
public function editprices()
{
// Get data & treat
$post = $this->getRequest();
$operation = $post->get('operation');
$area = $post->get('area');
$weight = $post->get('weight');
$price = $post->get('price');
if (preg_match("#^add|delete$#", $operation) &&
preg_match("#^\d+$#", $area) &&
preg_match("#^\d+\.?\d*$#", $weight)
) {
// check if area exists in db
$exists = AreaQuery::create()
->findPK($area);
if ($exists !== null) {
if (null !== $data = FedEx::getConfigValue(FedExConfigValue::PRICES, null)) {
$json_data = json_decode(
$data,
true
);
}
if ((float) $weight > 0 && $operation == "add"
&& preg_match("#\d+\.?\d*#", $price)) {
$json_data[$area]['slices'][$weight] = $price;
} elseif ($operation == "delete") {
if (isset($json_data[$area]['slices'][$weight])) {
unset($json_data[$area]['slices'][$weight]);
}
} else {
throw new \Exception("Weight must be superior to 0");
}
ksort($json_data[$area]['slices']);
FedEx::setConfigValue(FedExConfigValue::PRICES, json_encode($json_data));
} else {
throw new \Exception("Area not found");
}
} else {
throw new \ErrorException("Arguments are missing or invalid");
}
return $this->redirectToConfigurationPage();
}
/**
* Redirect to the configuration page
*/
protected function redirectToConfigurationPage()
{
return RedirectResponse::create(URL::getInstance()->absoluteUrl('/admin/module/fedex'));
}
}

163
local/modules/FedEx/FedEx.php Executable file
View File

@@ -0,0 +1,163 @@
<?php
namespace FedEx;
use FedEx\Model\Config\FedExConfigValue;
use Propel\Runtime\Connection\ConnectionInterface;
use Thelia\Core\Translation\Translator;
use Thelia\Install\Database;
use Thelia\Model\Country;
use Thelia\Model\State;
use Thelia\Module\AbstractDeliveryModule;
use Thelia\Module\Exception\DeliveryException;
class FedEx extends AbstractDeliveryModule
{
protected $request;
protected $dispatcher;
const TRACKING_URL = 'tracking_url';
private static $prices = null;
const JSON_PRICE_RESOURCE = "/Config/prices.json";
const DOMAIN_NAME = 'fedex';
public static function getPrices()
{
if (null === self::$prices) {
self::$prices = json_decode(FedEx::getConfigValue(FedExConfigValue::PRICES, null), true);
}
return self::$prices;
}
public function postActivation(ConnectionInterface $con = null)
{
self::setConfigValue(FedExConfigValue::TRACKING_URL, "https://www.fedex.com/apps/fedextrack/?action=track&trackingnumber=");
$database = new Database($con);
$database->insertSql(null, array(__DIR__ . '/Config/thelia.sql'));
}
public function isValidDelivery(Country $country, State $state = null)
{
if (0 == self::getConfigValue(FedExConfigValue::ENABLED, 1)) {
return false;
}
if (null !== $area = $this->getAreaForCountry($country, $state)) {
$areaId = $area->getId();
$prices = self::getPrices();
/* Check if FedEx delivers the area */
if (isset($prices[$areaId]) && isset($prices[$areaId]["slices"])) {
// Yes ! Check if the cart weight is below slice limit
$areaPrices = $prices[$areaId]["slices"];
ksort($areaPrices);
/* Check cart weight is below the maximum weight */
end($areaPrices);
$maxWeight = key($areaPrices);
$cartWeight = $this->getRequest()->getSession()->getSessionCart($this->getDispatcher())->getWeight();
if ($cartWeight <= $maxWeight) {
return true;
}
}
}
return false;
}
/**
* @param $areaId
* @param $weight
*
* @return mixed
* @throws \Thelia\Exception\OrderException
*/
public static function getPostageAmount($areaId, $weight)
{
$prices = self::getPrices();
/* check if FedEx delivers the asked area */
if (!isset($prices[$areaId]) || !isset($prices[$areaId]["slices"])) {
throw new DeliveryException(
Translator::getInstance()->trans(
"FedEx delivery unavailable for the delivery country",
[],
self::DOMAIN_NAME
)
);
}
$areaPrices = $prices[$areaId]["slices"];
ksort($areaPrices);
/* Check cart weight is below the maximum weight */
end($areaPrices);
$maxWeight = key($areaPrices);
if ($weight > $maxWeight) {
throw new DeliveryException(
Translator::getInstance()->trans(
"FedEx delivery unavailable for this cart weight (%weight kg)",
array("%weight" => $weight),
self::DOMAIN_NAME
)
);
}
$postage = current($areaPrices);
while (prev($areaPrices)) {
if ($weight > key($areaPrices)) {
break;
}
$postage = current($areaPrices);
}
return $postage;
}
/**
*
* calculate and return delivery price
*
* @param Country $country
* @param State $state
* @return mixed
*/
public function getPostage(Country $country, State $state = null)
{
$cartWeight = $this->getRequest()->getSession()->getSessionCart($this->getDispatcher())->getWeight();
$postage = self::getPostageAmount(
$this->getAreaForCountry($country, $state)->getId(),
$cartWeight
);
return $postage;
}
public function update($currentVersion, $newVersion, ConnectionInterface $con = null)
{
$uploadDir = __DIR__ . '/Config/prices.json';
// $database = new Database($con);
// $tableExists = $database->execute("SHOW TABLES LIKE 'FedEx_freeshipping'")->rowCount();
// if (FedEx::getConfigValue(FedExConfigValue::FREE_SHIPPING, null) == null && $tableExists) {
// $result = $database->execute('SELECT active FROM FedEx_freeshipping WHERE id=1')->fetch()["active"];
// FedEx::setConfigValue(FedExConfigValue::FREE_SHIPPING, $result);
// $database->execute("DROP TABLE `FedEx_freeshipping`");
// }
if (is_readable($uploadDir) && FedEx::getConfigValue(FedExConfigValue::PRICES, null) == null) {
FedEx::setConfigValue(FedExConfigValue::PRICES, file_get_contents($uploadDir));
}
}
}

View File

@@ -0,0 +1,31 @@
<?php
namespace FedEx\Form;
use FedEx\FedEx;
use FedEx\Model\Config\Base\FedExConfigValue;
use Thelia\Core\Translation\Translator;
use Thelia\Form\BaseForm;
/**
* Class Configuration
* @package FedEx\Form
* @author Laurent LE CORRE <laurent@thecoredev.fr>
*/
class Configuration extends BaseForm
{
protected function buildForm()
{
$this->formBuilder
->add(
FedEx::TRACKING_URL,
'text',
[
'label' => $this->translator->trans('FedEx parcel tracking URL', [], FedEx::DOMAIN_NAME),
'label_attr' => [
'help' => $this->translator->trans('This is the parcel tracking URL for FedEx.', [], FedEx::DOMAIN_NAME)
]
]
);
}
}

View File

@@ -0,0 +1,21 @@
<?php
namespace FedEx\Hook;
use Thelia\Core\Event\Hook\HookRenderEvent;
use Thelia\Core\Hook\BaseHook;
/**
* Class HookManager
* @package FedEx\Hook
* @author Laurent LE CORRE <laurent@thecoredev.fr>
*/
class HookManager extends BaseHook
{
public function onModuleConfiguration(HookRenderEvent $event)
{
$module_id = self::getModule()->getModuleId();
$event->add($this->render("module_configuration.html", ['module_id' => $module_id]));
}
}

View File

@@ -0,0 +1,34 @@
<?php
return array(
'*If you choose this option, the exported orders would not be available on this page anymore' => '*If you choose this option, the exported orders would not be available on this page anymore',
'Actions' => 'Actions',
'An error occured' => 'An error occured',
'Area : ' => 'Area : ',
'Cancel' => 'Cancel',
'FedEx Module allows to send your products all around the world with FedEx.' => 'FedEx Module allows to send your products all around the world with FedEx.',
'Create' => 'Create',
'Create a new price slice' => 'Create a new price slice',
'Create a price slice' => 'Create a price slice',
'Date' => 'Date',
'Delete' => 'Delete',
'Delete a price slice' => 'Delete a price slice',
'Delete this price slice' => 'Delete this price slice',
'Do not change' => 'Do not change',
'Do you really want to delete this slice ?' => 'Do you really want to delete this slice ?',
'Edit' => 'Edit',
'Edit a price slice' => 'Edit a price slice',
'Edit this price slice' => 'Edit this price slice',
'FedEx parcel tracking URL' => 'FedEx URL for parcel tracking',
'Please change the access rights' => 'Please change the access rights',
'Price (€)' => 'Price (€)',
'Price slices' => 'Price slices',
'Processing' => 'Processing',
'REF' => 'REF',
'Sent' => 'Sent',
'This is the parcel tracking URL for FedEx.' => 'This is the parcel tracking URL for FedEx.',
'Total taxed amount' => 'Total taxed amount',
'Weight up to ... (kg)' => 'Weight up to ... (kg)',
'Number of packages' => 'Number of packages',
'Packages weight' => 'Packages weight'
);

View File

@@ -0,0 +1,35 @@
<?php
return [
'*If you choose this option, the exported orders would not be available on this page anymore' => '* Si vous choisissez cette option, les commandes exportées ne seront plus affichée sur cette page.',
'Actions' => 'Actions',
'An error occured' => 'Une erreur est survenue',
'Area : ' => 'Zone de livraison : ',
'Cancel' => 'Annuler',
'FedEx Module allows to send your products all around the world with FedEx.' => 'FedEx vous permet dexpédier vos colis dans le monde entier avec FedEx',
'Create' => 'Créer',
'Create a new price slice' => 'Créer une nouvelle tranche de prix',
'Create a price slice' => 'Créer une tranche de prix',
'Customer' => 'Client',
'Date' => 'Date',
'Delete' => 'Supprimer',
'Delete a price slice' => 'Supprimer une tranche de prix',
'Delete this price slice' => 'Supprimer cette tranche de prix',
'Do not change' => 'Ne pas modifier',
'Do you really want to delete this slice ?' => 'Confirmez-vous la suppression de cette tranche de prix',
'Edit' => 'Modifier',
'Edit a price slice' => 'Modifier une tranche de prix',
'Edit this price slice' => 'Modifier cette tranche de prix',
'FedEx parcel tracking URL' => 'URL de suivi des colis FedEx',
'Number of packages' => 'Nombre de colis',
'Packages weight' => 'Poids des colis',
'Please change the access rights' => 'Merci de modifier les droits d\'accès',
'Price (€)' => 'Prix (€)',
'Price slices' => 'Prix et poids',
'Processing' => 'Traitement',
'REF' => 'REF',
'Sent' => 'Envoyée',
'This is the parcel tracking URL for FedEx.' => 'Il s\'agit de l\'URL fournie par FedEx afin de suivre les expéditions de ses colis.',
'Total taxed amount' => 'Total TTC',
'Weight up to ... (kg)' => 'Jusqu\'au poids (Kg)',
];

View File

@@ -0,0 +1,11 @@
<?php
return array(
'Can\'t read Config directory' => 'Can\'t read Config directory',
'Can\'t read file' => 'Can\'t read file',
'Can\'t write Config directory' => 'Can\'t write Config directory',
'Can\'t write file' => 'Can\'t write file',
'FedEx delivery unavailable for the delivery country' => 'FedEx delivery unavailable for the delivery country',
'FedEx delivery unavailable for this cart weight (%weight kg)' => 'FedEx delivery unavailable for this cart weight (%weight kg)',
'select a valid status' => 'Select a valid order status',
);

View File

@@ -0,0 +1,11 @@
<?php
return [
'Can\'t read Config directory' => 'Le dossier Config ne peut être lu',
'Can\'t read file' => 'Le fichier suivant ne peut être lu',
'Can\'t write Config directory' => 'Le dossier Config ne peut être écrit',
'Can\'t write file' => 'Le fichier suivant ne peut être écrit',
'FedEx delivery unavailable for the delivery country' => 'La livraison par FedEx n\'est pas disponible dans ce pays',
'FedEx delivery unavailable for this cart weight (%weight kg)' => 'La livraison par FedEx n\'est pas disponible pour un panier de %weight Kg',
'select a valid status' => 'Choisissez un statut de commande valide.',
];

View File

@@ -0,0 +1,92 @@
<?php
namespace FedEx\Listener;
use FedEx\FedEx;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Thelia\Core\Event\Order\OrderEvent;
use Thelia\Core\Event\TheliaEvents;
use Thelia\Core\Template\ParserInterface;
use Thelia\Log\Tlog;
use Thelia\Mailer\MailerFactory;
use Thelia\Model\ConfigQuery;
use Thelia\Model\MessageQuery;
use Thelia\Model\OrderStatus;
use Thelia\Module\PaymentModuleInterface;
/**
* Class SendMail
* @package FedEx\Listener
* @author Manuel Raynaud <manu@raynaud.io>
*/
class SendMail implements EventSubscriberInterface
{
protected $parser;
protected $mailer;
public function __construct(ParserInterface $parser, MailerFactory $mailer)
{
$this->parser = $parser;
$this->mailer = $mailer;
}
public function updateStatus(OrderEvent $event)
{
$order = $event->getOrder();
$FedEx = new FedEx();
if ($order->isSent() && $order->getDeliveryModuleId() == $FedEx->getModuleModel()->getId()) {
$contact_email = ConfigQuery::getStoreEmail();
if ($contact_email) {
$order = $event->getOrder();
$customer = $order->getCustomer();
$this->mailer->sendEmailToCustomer(
'mail_FedEx',
$customer,
[
'customer_id' => $customer->getId(),
'order_ref' => $order->getRef(),
'order_date' => $order->getCreatedAt(),
'update_date' => $order->getUpdatedAt(),
'package' => $order->getDeliveryRef()
]
);
Tlog::getInstance()->debug("FedEx shipping message sent to customer ".$customer->getEmail());
} else {
$customer = $order->getCustomer();
Tlog::getInstance()->debug("FedEx shipping message no contact email customer_id", $customer->getId());
}
}
}
/**
* Returns an array of event names this subscriber wants to listen to.
*
* The array keys are event names and the value can be:
*
* * The method name to call (priority defaults to 0)
* * An array composed of the method name to call and the priority
* * An array of arrays composed of the method names to call and respective
* priorities, or 0 if unset
*
* For instance:
*
* * array('eventName' => 'methodName')
* * array('eventName' => array('methodName', $priority))
* * array('eventName' => array(array('methodName1', $priority), array('methodName2'))
*
* @return array The event names to listen to
*
* @api
*/
public static function getSubscribedEvents()
{
return array(
TheliaEvents::ORDER_UPDATE_STATUS => array("updateStatus", 128)
);
}
}

View File

@@ -0,0 +1,91 @@
<?php
namespace FedEx\Loop;
use FedEx\FedEx;
use Thelia\Core\Template\Loop\Argument\ArgumentCollection;
use Thelia\Core\Template\Element\BaseLoop;
use Thelia\Core\Template\Element\LoopResultRow;
use Thelia\Core\Template\Element\LoopResult;
use Thelia\Core\Template\Element\ArraySearchLoopInterface;
use Thelia\Core\Translation\Translator;
/**
* Class CheckRightsLoop
* @package FedEx\Loop
* @author Laurent LE CORRE <laurent@thecoredev.fr>
*/
class CheckRightsLoop extends BaseLoop implements ArraySearchLoopInterface
{
protected function getArgDefinitions()
{
return new ArgumentCollection();
}
public function buildArray()
{
$ret = array();
$dir = __DIR__."/../Config/";
if (!is_readable($dir)) {
$ret[] = array(
"ERRMES"=>Translator::getInstance()->trans(
"Can't read Config directory",
[],
FedEx::DOMAIN_NAME
),
"ERRFILE"=>""
);
}
if (!is_writable($dir)) {
$ret[] = array(
"ERRMES"=>Translator::getInstance()->trans(
"Can't write Config directory",
[],
FedEx::DOMAIN_NAME
),
"ERRFILE"=>""
);
}
if ($handle = opendir($dir)) {
while (false !== ($file = readdir($handle))) {
if (strlen($file) > 5 && substr($file, -5) === ".json") {
if (!is_readable($dir.$file)) {
$ret[] = array(
"ERRMES"=>Translator::getInstance()->trans(
"Can't read file",
[],
FedEx::DOMAIN_NAME
),
"ERRFILE"=>"FedEx/Config/".$file
);
}
if (!is_writable($dir.$file)) {
$ret[] = array(
"ERRMES"=>Translator::getInstance()->trans(
"Can't write file",
[],
FedEx::DOMAIN_NAME
),
"ERRFILE"=>"FedEx/Config/".$file
);
}
}
}
}
return $ret;
}
public function parseResults(LoopResult $loopResult)
{
foreach ($loopResult->getResultDataCollection() as $arr) {
$loopResultRow = new LoopResultRow();
$loopResultRow->set("ERRMES", $arr["ERRMES"])
->set("ERRFILE", $arr["ERRFILE"]);
$loopResult->addRow($loopResultRow);
}
return $loopResult;
}
}

View File

@@ -0,0 +1,64 @@
<?php
namespace FedEx\Loop;
use FedEx\Model\FedExQuery;
use Thelia\Core\Template\Loop\Argument\Argument;
use Thelia\Core\Template\Loop\Argument\ArgumentCollection;
use Thelia\Core\Template\Loop\Order;
/**
* Class NotSendLoop
* @package FedEx\Loop
* @author Manuel Raynaud <manu@raynaud.io>
*/
class NotSendLoop extends Order
{
/**
*
* define all args used in your loop
*
*
* example :
*
* public function getArgDefinitions()
* {
* return new ArgumentCollection(
* Argument::createIntListTypeArgument('id'),
* new Argument(
* 'ref',
* new TypeCollection(
* new Type\AlphaNumStringListType()
* )
* ),
* Argument::createIntListTypeArgument('category'),
* Argument::createBooleanTypeArgument('new'),
* Argument::createBooleanTypeArgument('promo'),
* Argument::createFloatTypeArgument('min_price'),
* Argument::createFloatTypeArgument('max_price'),
* Argument::createIntTypeArgument('min_stock'),
* Argument::createFloatTypeArgument('min_weight'),
* Argument::createFloatTypeArgument('max_weight'),
* Argument::createBooleanTypeArgument('current'),
*
* );
* }
*
* @return \Thelia\Core\Template\Loop\Argument\ArgumentCollection
*/
public function getArgDefinitions()
{
return new ArgumentCollection(Argument::createBooleanTypeArgument('with_prev_next_info', false));
}
/**
* this method returns a Propel ModelCriteria
*
* @return \Propel\Runtime\ActiveQuery\ModelCriteria
*/
public function buildModelCriteria()
{
return FedExQuery::getOrders();
}
}

View File

@@ -0,0 +1,63 @@
<?php
namespace FedEx\Loop;
use FedEx\FedEx;
use Thelia\Core\Template\Element\ArraySearchLoopInterface;
use Thelia\Core\Template\Element\BaseLoop;
use Thelia\Core\Template\Element\LoopResult;
use Thelia\Core\Template\Element\LoopResultRow;
use Thelia\Core\Template\Loop\Argument\ArgumentCollection;
use Thelia\Core\Template\Loop\Argument\Argument;
/**
*
* Price loop
*
*
* Class Price
* @package FedEx\Loop
* @author Etienne Roudeix <eroudeix@openstudio.fr>
*/
class Price extends BaseLoop implements ArraySearchLoopInterface
{
/* set countable to false since we need to preserve keys */
protected $countable = false;
/**
* @return ArgumentCollection
*/
protected function getArgDefinitions()
{
return new ArgumentCollection(
Argument::createIntTypeArgument('area', null, true)
);
}
public function buildArray()
{
$area = $this->getArea();
$prices = FedEx::getPrices();
if (!isset($prices[$area]) || !isset($prices[$area]["slices"])) {
return array();
}
$areaPrices = $prices[$area]["slices"];
ksort($areaPrices);
return $areaPrices;
}
public function parseResults(LoopResult $loopResult)
{
foreach ($loopResult->getResultDataCollection() as $maxWeight => $price) {
$loopResultRow = new LoopResultRow();
$loopResultRow->set("MAX_WEIGHT", $maxWeight)
->set("PRICE", $price);
$loopResult->addRow($loopResultRow);
}
return $loopResult;
}
}

View File

@@ -0,0 +1,9 @@
<?php
namespace FedEx\Model\Config\Base;
class FedExConfigValue
{
const PRICES = "prices";
const TRACKING_URL = "https://www.fedex.com/apps/fedextrack/?action=track&trackingnumber=";
}

View File

@@ -0,0 +1,9 @@
<?php
namespace FedEx\Model\Config;
use FedEx\Model\Config\Base\FedExConfigValue as BaseFedExConfigValue;
class FedExConfigValue extends BaseFedExConfigValue
{
}

View File

@@ -0,0 +1,45 @@
<?php
namespace FedEx\Model;
use FedEx\FedEx;
use Propel\Runtime\ActiveQuery\Criteria;
use Thelia\Model\OrderQuery;
use Thelia\Model\OrderStatus;
use Thelia\Model\OrderStatusQuery;
/**
* Class FedExQuery
* @package FedEx\Model
* @author Laurent LE CORRE <laurent@thecoredev.fr>
*/
class FedExQuery
{
/**
* @return OrderQuery
*/
public static function getOrders()
{
$status = OrderStatusQuery::create()
->filterByCode(
array(
OrderStatus::CODE_PAID,
OrderStatus::CODE_PROCESSING,
),
Criteria::IN
)
->find()
->toArray("code");
$query = OrderQuery::create()
->filterByDeliveryModuleId((new FedEx())->getModuleModel()->getId())
->filterByStatusId(
array(
$status[OrderStatus::CODE_PAID]['Id'],
$status[OrderStatus::CODE_PROCESSING]['Id']),
Criteria::IN
);
return $query;
}
}

View File

@@ -0,0 +1,38 @@
{javascripts file="assets/js/bootstrap-switch/bootstrap-switch.js"}
<script src="{$asset_url}"></script>
{/javascripts}
<script>
$(document).ready(function() {
/*
$(".freeshipping-activation-FedEx").bootstrapSwitch();
$(".freeshipping-activation-FedEx").on("switch-change", function(e, data){
var is_checked = data.value;
var form = $("#freeshippingform");
$('body').append('<div class="modal-backdrop fade in" id="loading-event"><div class="loading"></div></div>');
$.ajax({
url: form.attr('action'),
type: form.attr('method'),
data: form.serialize()
}).done(function(){
$("#loading-event").remove();
})
.success(function() {
if (is_checked) {
$('#config-btn-0').removeClass('disabled');
$('#table-prices-FedEx').hide('slow');
} else {
$('#config-btn-0').addClass('disabled');
$('#table-prices-FedEx').show('slow');
}
})
.fail(function(jqXHR, textStatus, errorThrown){
$("#loading-event").remove();
$('#freeshipping-failed-body').html(jqXHR.responseJSON.error);
$("#freeshipping-failed").modal("show");
});
});
*/
});
</script>

View File

@@ -0,0 +1,175 @@
<div class="row">
<!-- Errors -->
{loop name="checkrights.fedex" type="fedex.check.rights"}
<div class="alert alert-danger">
<p>{$ERRMES} {$ERRFILE} | {intl d='fedex.bo.default' l="Please change the access rights"}.</p>
</div>
{/loop}
</div>
{elseloop rel="checkrights.fedex"}
<div class="alert alert-info">
<p>{intl d='fedex.bo.default' l="FedEx Module allows to send your products all around the world with FedEx."}</p>
</div>
<div class="modal fade" id="freeshipping-failed" tabindex="-1" role="dialog" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>
<h3>{intl d='fedex.bo.default' l="An error occured"}</h3>
</div>
<div class="modal-body" id="freeshipping-failed-body">
</div>
</div>
</div>
</div>
<div class="general-block-decorator">
<div class="row">
<div class="col-md-12">
{form name="fedex.configuration"}
<form method="POST" action="{url path='/admin/module/fedex/configuration/update'}">
{form_hidden_fields form=$form}
{form_field form=$form field="tracking_url"}
<div class="form-group">
<label class="control-label" for="{$label_attr.for}">
<input type="text" name="{$name}" id="{$label_attr.for}" />
{$label}
{form_error form=$form field="tracking_url" value={module_config module="FedEx" key='tracking_url' locale="en_US"}}
<br />
<span class="error">{$message}</span>
{/form_error}
</label>
{if ! empty($label_attr.help)}
<span class="help-block">{$label_attr.help}</span>
{/if}
</div>
{/form_field}
<button type="submit" name="fedex_save_configuration" value="save" class="form-submit-button btn btn-sm btn-default" title="{intl d='fedex.bo.default' l='Save'}">
{intl d='fedex.bo.default' l='Save'}
</button>
</form>
{/form}
</div>
</div>
</div>
<div class="general-block-decorator">
<div class="row">
<div class="col-md-12">
<!-- Tab menu -->
<ul id="tabbed-menu" class="nav nav-tabs">
<li class="{if $tab eq "1"}active{/if}"><a data-toggle="tab" href="#prices_slices_tab">{intl d='fedex.bo.default' l="Price slices"}</a></li>
</ul>
<div class="tab-content">
<div id="prices_slices_tab" class="tab-pane {if $tab eq 1}active{/if} form-container">
<div id="table-prices-fedex">
<!-- Prices editing -->
{* -- Add price slice confirmation dialog ----------------------------------- *}
{loop type="area" name="list area" backend_context=true module_id=$module_id}
{include
file = "includes/generic-create-dialog.html"
dialog_id = "price_slice_create_dialog_{$ID}"
dialog_title = {intl d='fedex.bo.default' l="Create a price slice"}
dialog_body = "<input type=\"hidden\" name=\"operation\" value=\"add\"/>
<input type=\"hidden\" name=\"area\" value=\"{$ID}\" />
<label for=\"weight_{$ID}\">{intl d='fedex.bo.default' l="Weight up to ... (kg)"}</label></label>
<input type=\"number\" step=\"0.01\" id=\"weight_{$ID}\" name=\"weight\" value=\"1\" class=\"form-control\" pattern=\"\d+\.?\d*\" required/>
<label for=\"price_{$ID}\">{intl d='fedex.bo.default' l="Price (€)"}</label></label>
<input type=\"number\" step=\"0.01\" id=\"price_{$ID}\" name=\"price\" value=\"1\" class=\"form-control\" pattern=\"\d+\.?\d*\" required/>"
form_action="{url path="/admin/module/fedex/prices"}"
dialog_ok_label = {intl d='fedex.bo.default' l="Create"}
dialog_cancel_label = {intl d='fedex.bo.default' l="Cancel"}
}
<div class="table-responsive">
<table class="table table-striped table-condensed table-left-aligned">
<caption class="clearfix">
{intl d='fedex.bo.default' l="Area : "}{$NAME}
{loop type="auth" name="can_create" role="ADMIN" module="fedex" access="CREATE"}
<a class="btn btn-default btn-primary pull-right" title="{intl d='fedex.bo.default' l='Create a new price slice'}" href="#price_slice_create_dialog_{$ID}" data-toggle="modal">
<span class="glyphicon glyphicon-plus"></span>
</a>
{/loop}
</caption>
<thead>
<tr>
<th class="col-md-3">{intl d='fedex.bo.default' l="Weight up to ... (kg)"}</th>
<th class="col-md-5">{intl d='fedex.bo.default' l="Price (€)"}</th>
<th class="col-md-1">{intl d='fedex.bo.default' l="Actions"}</th>
</tr>
</thead>
<tbody>
{loop type="fedex" name="fedex" area=$ID}
{* -- EDIT price slice confirmation dialog ----------------------------------- *}
{include
file = "includes/generic-confirm-dialog.html"
dialog_id = "price_slice_edit_dialog_{$ID}_{$MAX_WEIGHT|replace:'.':'-'}"
dialog_title = {intl d='fedex.bo.default' l="Edit a price slice"}
dialog_message = "<input type=\"hidden\" name=\"operation\" value=\"add\"/>
<input type=\"hidden\" name=\"area\" value=\"{$ID}\"/>
<input type=\"hidden\" name=\"weight\" value=\"{$MAX_WEIGHT}\"/>
<label for=\"price_edit_{$ID}_{$MAX_WEIGHT}\">{intl d='fedex.bo.default' l='Price (€)'}</label>
<input type=\"number\" step=\"0.01\" id=\"price_edit_{$ID}_{$MAX_WEIGHT}\" class=\"form-control\" name=\"price\" value=\"{$PRICE}\" pattern=\"\d+\.?\d*\" required/>"
form_action="{url path="/admin/module/fedex/prices"}"
dialog_ok_label = {intl d='fedex.bo.default' l="Edit"}
dialog_cancel_label = {intl d='fedex.bo.default' l="Cancel"}
}
{* -- Delete price slice confirmation dialog ----------------------------------- *}
{include
file = "includes/generic-confirm-dialog.html"
dialog_id = "price_slice_delete_dialog_{$ID}_{$MAX_WEIGHT|replace:'.':'-'}"
dialog_title = {intl d='fedex.bo.default' l="Delete a price slice"}
dialog_message = "<input type=\"hidden\" name=\"operation\" value=\"delete\"/>
<input type=\"hidden\" name=\"area\" value=\"{$ID}\"/>
<input type=\"hidden\" name=\"weight\" value=\"{$MAX_WEIGHT}\"/>
{intl d='fedex.bo.default' l="Do you really want to delete this slice ?"}"
form_action="{url path="/admin/module/fedex/prices"}"
dialog_ok_label = {intl d='fedex.bo.default' l="Delete"}
dialog_cancel_label = {intl d='fedex.bo.default' l="Cancel"}
}
<tr>
<td>{$MAX_WEIGHT}</td>
<td>{$PRICE}</td>
<td>
<div class="btn-group">
{loop type="auth" name="can_change" role="ADMIN" module="fedex" access="UPDATE"}
<a class="btn btn-default btn-xs" title="{intl d='fedex.bo.default' l='Edit this price slice'}" href="#price_slice_edit_dialog_{$ID}_{$MAX_WEIGHT|replace:'.':'-'}" data-toggle="modal">
<span class="glyphicon glyphicon-edit"></span>
</a>
<a class="btn btn-default btn-xs" title="{intl d='fedex.bo.default' l='Delete this price slice'}" href="#price_slice_delete_dialog_{$ID}_{$MAX_WEIGHT|replace:'.':'-'}" data-toggle="modal">
<span class="glyphicon glyphicon-trash"></span>
</a>
{/loop}
</div>
</td>
</tr>
{/loop}
</tbody>
</table>
</div>
{/loop}
</div>
</div>
</div>
</div>
</div>
</div>
{/elseloop}