diff --git a/core/lib/Thelia/Controller/Front/BaseFrontController.php b/core/lib/Thelia/Controller/Front/BaseFrontController.php index 00ac8143d..132d02215 100644 --- a/core/lib/Thelia/Controller/Front/BaseFrontController.php +++ b/core/lib/Thelia/Controller/Front/BaseFrontController.php @@ -48,9 +48,9 @@ class BaseFrontController extends BaseController /** * Redirect to à route ID related URL * - * @param unknown $routeId the route ID, as found in Config/Resources/routing/admin.xml - * @param array|\Thelia\Controller\Front\unknown $urlParameters the URL parametrs, as a var/value pair array - * @param bool $referenceType + * @param string $routeId the route ID, as found in Config/Resources/routing/admin.xml + * @param array $urlParameters the URL parametrs, as a var/value pair array + * @param bool $referenceType */ public function redirectToRoute($routeId, $urlParameters = array(), $referenceType = Router::ABSOLUTE_PATH) { @@ -104,7 +104,7 @@ class BaseFrontController extends BaseController /** * Render the given template, and returns the result as an Http Response. * - * @param $templateName the complete template name, with extension + * @param string $templateName the complete template name, with extension * @param array $args the template arguments * @param int $status http code status * @return \Thelia\Core\HttpFoundation\Response diff --git a/core/lib/Thelia/Core/Template/ParserInterface.php b/core/lib/Thelia/Core/Template/ParserInterface.php index c9cf2eceb..3e81f49f4 100644 --- a/core/lib/Thelia/Core/Template/ParserInterface.php +++ b/core/lib/Thelia/Core/Template/ParserInterface.php @@ -38,6 +38,13 @@ interface ParserInterface public function setStatus($status); + /** + * Setup the parser with a template definition, which provides a template description. + * + * @param TemplateDefinition $templateDefinition + */ + public function setTemplateDefinition(TemplateDefinition $templateDefinition); + /** * Add a template directory to the current template list * @@ -54,7 +61,7 @@ interface ParserInterface * Return the registeted template directories for a givent template type * * @param unknown $templateType - * @throws InvalidArgumentException if the tempmateType is not defined + * @throws \InvalidArgumentException if the templateType is not defined * @return array: an array of defined templates directories for the given template type */ public function getTemplateDirectories($templateType); diff --git a/core/lib/Thelia/Core/Template/Smarty/SmartyParser.php b/core/lib/Thelia/Core/Template/Smarty/SmartyParser.php index d2450fb43..0e335c77e 100644 --- a/core/lib/Thelia/Core/Template/Smarty/SmartyParser.php +++ b/core/lib/Thelia/Core/Template/Smarty/SmartyParser.php @@ -92,11 +92,11 @@ class SmartyParser extends Smarty implements ParserInterface /** * Add a template directory to the current template list * - * @param unknown $templateType the template type (a TemplateDefinition type constant) + * @param int $templateType the template type (a TemplateDefinition type constant) * @param string $templateName the template name * @param string $templateDirectory path to the template dirtectory * @param unknown $key ??? - * @param string $unshift ??? Etienne ? + * @param boolean $unshift ??? Etienne ? */ public function addTemplateDirectory($templateType, $templateName, $templateDirectory, $key, $unshift = false) { @@ -116,9 +116,9 @@ class SmartyParser extends Smarty implements ParserInterface /** * Return the registeted template directories for a givent template type * - * @param unknown $templateType + * @param int $templateType * @throws InvalidArgumentException - * @return multitype: + * @return mixed: */ public function getTemplateDirectories($templateType) { diff --git a/core/lib/Thelia/Log/Tlog.php b/core/lib/Thelia/Log/Tlog.php index 1eaf64350..f7863eb8d 100644 --- a/core/lib/Thelia/Log/Tlog.php +++ b/core/lib/Thelia/Log/Tlog.php @@ -124,6 +124,19 @@ class Tlog Implements LoggerInterface return self::$instance; } + /** + * Create a new Tlog instance, that could be configured without interfering with the "main" instance + * + * @return Tlog a new Tlog instance. + */ + public static function getNewInstance() { + $instance = new Tlog(); + + $instance->init(); + + return $instance; + } + /** * initialize default configuration */ diff --git a/core/lib/Thelia/Module/AbstractPaymentModule.php b/core/lib/Thelia/Module/AbstractPaymentModule.php new file mode 100644 index 000000000..f80dd17f9 --- /dev/null +++ b/core/lib/Thelia/Module/AbstractPaymentModule.php @@ -0,0 +1,132 @@ +. */ +/* */ +/*************************************************************************************/ + +namespace Thelia\Module; + +use Symfony\Component\Routing\Router; +use Thelia\Core\HttpFoundation\Response; +use Thelia\Core\Template\ParserInterface; +use Thelia\Core\Template\TemplateHelper; +use Thelia\Exception\TheliaProcessException; +use Thelia\Model\Order; +use Thelia\Tools\URL; + +abstract class AbstractPaymentModule extends BaseModule implements PaymentModuleInterface +{ + /** + * This method is called when the payement gateway needs to be invoked. + * + * If this method return a Response instance, this response is sent to the browser. Return null if you don't want to + * send a response and process the payment yourself. + * + * 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, instead of redirecting. The generateGatewayFormResponse() may help you in this case :) + * + * @param Order $order processed order + * @return null|Response + */ + abstract public function pay(Order $order); + + /** + * This method is called by the Payment loop, to check if the current module has to be displayed to the customer + * + * If you return true, the payment method will de displayed to the customed + * If you return false, the payment method will not be displayed + * + * @return boolean + */ + abstract public function isValidPayment(); + + + /** + * Render the payment gateway template. The module should provide the gateway URL and the form fields names and values. + * + * @param Order $order the order + * @param string $gateway_url the payment gateway URL + * @param array $form_data an associative array of form data, that will be rendered as hiddent fields + * + * @return Response the HTTP response. + */ + public function generateGatewayFormResponse($order, $gateway_url, $form_data) + { + /** @var ParserInterface $parser */ + $parser = $this->container->get("thelia.parser"); + + $parser->setTemplateDefinition(TemplateHelper::getInstance()->getActiveFrontTemplate()); + + $renderedTemplate = $parser->render( + "order-payment-gateway.html", + array( + "order_id" => $order->getId(), + "cart_count" => $this->getRequest()->getSession()->getCart()->getCartItems()->count(), + "gateway_url" => $gateway_url, + "payment_form_data" => $form_data + ) + ); + + return Response::create($renderedTemplate); + } + + /** + * Return the order payment success page URL + * + * @param int $order_id the order ID + * @return string the order payment success page URL + */ + public function getPayementSuccessPageUrl($order_id) + { + $frontOfficeRouter = $this->container->get('router.front'); + + return URL::getInstance()->absoluteUrl( + $frontOfficeRouter->generate( + "order.placed", + array("order_id" => $order_id), + Router::ABSOLUTE_URL + ) + ); + } + + /** + * Redirect the customer to the failure payment page. if $message is null, a generic message is displayed. + * + * @param int $order_id the order ID + * @param string|null $message an error message. + * + * @return string the order payment failure page URL + */ + public function getPayementFailurePageUrl($order_id, $message) + { + $frontOfficeRouter = $this->container->get('router.front'); + + return URL::getInstance()->absoluteUrl( + $frontOfficeRouter->generate( + "order.failed", + array( + "order_id" => $order_id, + "message" => $message + ), + Router::ABSOLUTE_URL + ) + ); + } +} diff --git a/local/modules/Front/Config/front.xml b/local/modules/Front/Config/front.xml index 74b42af5a..ed5e457fa 100644 --- a/local/modules/Front/Config/front.xml +++ b/local/modules/Front/Config/front.xml @@ -158,6 +158,11 @@ Front\Controller\OrderController::orderPlaced order-placed + + + Front\Controller\OrderController::orderFailed + order-failed + diff --git a/local/modules/Front/Controller/OrderController.php b/local/modules/Front/Controller/OrderController.php index 5ac01d723..3b24a2ab4 100644 --- a/local/modules/Front/Controller/OrderController.php +++ b/local/modules/Front/Controller/OrderController.php @@ -234,6 +234,29 @@ class OrderController extends BaseFrontController $this->getParserContext()->set("placed_order_id", $placedOrder->getId()); } + public function orderFailed($order_id, $message) + { + /* check if the placed order matched the customer */ + $failedOrder = OrderQuery::create()->findPk( + $this->getRequest()->attributes->get('order_id') + ); + + if (null === $failedOrder) { + throw new TheliaProcessException("No failed order", TheliaProcessException::NO_PLACED_ORDER, $failedOrder); + } + + $customer = $this->getSecurityContext()->getCustomerUser(); + + if (null === $customer || $failedOrder->getCustomerId() !== $customer->getId()) { + throw new TheliaProcessException("Received failed order id does not belong to the current customer", TheliaProcessException::PLACED_ORDER_ID_BAD_CURRENT_CUSTOMER, $placedOrder); + } + + $this->getParserContext() + ->set("failed_order_id", $failedOrder->getId()) + ->set("failed_order_message", $message) + ; + } + protected function getOrderEvent() { $order = $this->getOrder($this->getRequest()); diff --git a/templates/backOffice/default/search.html b/templates/backOffice/default/search.html index e2f1f9211..a3af85dac 100644 --- a/templates/backOffice/default/search.html +++ b/templates/backOffice/default/search.html @@ -13,7 +13,7 @@
@@ -54,7 +54,7 @@ - {loop name="customer_list" type="customer" current="false" visible="*" backend_context="1" search_term=$smarty.get.search_term search_in="ref,firstname,lastname,email"} + {loop name="customer_list" type="customer" current="false" visible="*" backend_context="1" search_term=trim($smarty.get.search_term) search_in="ref,firstname,lastname,email"} {assign "lastOrderDate" ''} {assign "lastOrderAmount" ''} {assign "lastOrderCurrency" ''} @@ -131,7 +131,7 @@ - {loop type="order" name="order-search" backend_context=1 customer="*" search_term=$smarty.get.search_term search_in="ref,customer_ref,customer_firstname,customer_lastname,customer_email"} + {loop type="order" name="order-search" backend_context=1 customer="*" search_term=trim($smarty.get.search_term) search_in="ref,customer_ref,customer_firstname,customer_lastname,customer_email"} {loop type="order_address" name="order-invoice-address" id=$INVOICE_ADDRESS} {assign "orderInvoiceFirstName" $FIRSTNAME} {assign "orderInvoiceLastName" $LASTNAME} @@ -187,7 +187,7 @@ - {loop type="product" name="product-search" visible="*" search_mode="sentence" search_term=$smarty.get.search_term search_in="ref,title"} + {loop type="product" name="product-search" visible="*" search_mode="sentence" search_term=trim($smarty.get.search_term) search_in="ref,title"} {$ID} diff --git a/templates/frontOffice/default/order-delivery.html b/templates/frontOffice/default/order-delivery.html index c84d54592..49be8707d 100644 --- a/templates/frontOffice/default/order-delivery.html +++ b/templates/frontOffice/default/order-delivery.html @@ -23,7 +23,7 @@
-

{intl l="Your Cart"}

+

{intl l="Billing and delivery"}

{include file="misc/checkout-progress.tpl" step="delivery"} diff --git a/templates/frontOffice/default/order-invoice.html b/templates/frontOffice/default/order-invoice.html index 500b14f29..32d5408b8 100644 --- a/templates/frontOffice/default/order-invoice.html +++ b/templates/frontOffice/default/order-invoice.html @@ -23,7 +23,7 @@
-

{intl l="Your Cart"}

+

{intl l="Check my order"}

{include file="misc/checkout-progress.tpl" step="invoice"} diff --git a/templates/frontOffice/default/order-payment-gateway.html b/templates/frontOffice/default/order-payment-gateway.html new file mode 100644 index 000000000..1ac362384 --- /dev/null +++ b/templates/frontOffice/default/order-payment-gateway.html @@ -0,0 +1,76 @@ +{extends file="layout.tpl"} + +{* Security *} +{block name="no-return-functions" prepend} + {check_auth role="CUSTOMER" login_tpl="login"} +{/block} + +{* Body Class *} +{block name="body-class"}page-order-payment{/block} + +{* Breadcrumb *} +{block name='no-return-functions' append} + {$breadcrumbs = [ + ['title' => {intl l="Cart"}, 'url'=>{url path="/cart"}], + ['title' => {intl l="Secure Payment"}, 'url'=>{url path="/order/pay"}] + ]} +{/block} + + +{block name="main-content"} +
+
+ +

{intl l="Secure payment"}

+ + {include file="misc/checkout-progress.tpl" step="last"} + + {loop type="order" name="placed-order" id=$order_id} + +
+
+

{intl l="You choose to pay by"} : {loop name="payment-module" type="module" id=$PAYMENT_MODULE}{$TITLE}{/loop}

+
+ +
+ {if $cart_count > 0} +
+ {intl l="Connecting to the secure payment server, please wait a few seconds..."} +
+ +
+ +
+ {foreach from=$payment_form_data key='name' item='value'} + + {/foreach} + +

{intl l='If nothing happens within 10 seconds, please click here.'}

+
+
+ {else} + {intl l="Sorry, your cart is empty. There's nothing to pay."} + {/if} +
+
+ {/loop} +
+ +
+{/block} + +{block name="javascript-initialization"} + +{/block} + +