354 lines
14 KiB
PHP
354 lines
14 KiB
PHP
<?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/>. */
|
|
/* */
|
|
/*************************************************************************************/
|
|
|
|
namespace Paypal;
|
|
|
|
use Paypal\Classes\API\PaypalApiCredentials;
|
|
use Paypal\Classes\API\PaypalApiLogManager;
|
|
use Paypal\Classes\API\PaypalApiManager;
|
|
use Paypal\Classes\NVP\Operations\PaypalNvpOperationsSetExpressCheckout;
|
|
use Paypal\Classes\NVP\PaypalNvpMessageSender;
|
|
use Propel\Runtime\Connection\ConnectionInterface;
|
|
use Symfony\Component\HttpFoundation\RedirectResponse;
|
|
use Symfony\Component\Routing\Router;
|
|
use Thelia\Core\Translation\Translator;
|
|
use Thelia\Install\Database;
|
|
use Thelia\Model\CountryQuery;
|
|
use Thelia\Model\Message;
|
|
use Thelia\Model\MessageQuery;
|
|
use Thelia\Model\ModuleImageQuery;
|
|
use Thelia\Model\Order;
|
|
use Thelia\Model\OrderAddressQuery;
|
|
use Thelia\Model\OrderQuery;
|
|
use Thelia\Module\AbstractPaymentModule;
|
|
use Thelia\Tools\URL;
|
|
|
|
/**
|
|
* Class Paypal
|
|
* @package Paypal
|
|
* @author Thelia <info@thelia.net>
|
|
*/
|
|
class Paypal extends AbstractPaymentModule
|
|
{
|
|
const DOMAIN = 'paypal';
|
|
|
|
/**
|
|
* The confirmation message identifier
|
|
*/
|
|
const CONFIRMATION_MESSAGE_NAME = 'paypal_payment_confirmation';
|
|
|
|
public function pay(Order $order)
|
|
{
|
|
$orderId = $order->getId();
|
|
|
|
/** @var Router $router */
|
|
$router = $this->getContainer()->get('router.paypal');
|
|
|
|
$successUrl = URL::getInstance()->absoluteUrl(
|
|
$router->generate('paypal.ok', ['order_id' => $order->getId()])
|
|
);
|
|
|
|
$cancelUrl = URL::getInstance()->absoluteUrl(
|
|
$router->generate('paypal.cancel', ['order_id' => $order->getId()])
|
|
);
|
|
|
|
$order = OrderQuery::create()->findPk($orderId);
|
|
|
|
$api = new PaypalApiCredentials();
|
|
$redirect_api = new PaypalApiManager();
|
|
$products = array(array());
|
|
$itemIndex = 0;
|
|
$logger = new PaypalApiLogManager();
|
|
|
|
$send_cart_detail = (int) Paypal::getConfigValue('send_cart_detail', 0);
|
|
|
|
if ($send_cart_detail == 1) {
|
|
|
|
/*
|
|
* Store products into 2d array $products
|
|
*/
|
|
$products_amount = 0;
|
|
|
|
foreach ($order->getOrderProducts() as $product) {
|
|
if ($product !== null) {
|
|
$amount = floatval($product->getWasInPromo() ? $product->getPromoPrice() : $product->getPrice());
|
|
foreach ($product->getOrderProductTaxes() as $tax) {
|
|
$amount += $product->getWasInPromo() ? $tax->getPromoAmount() : $tax->getAmount();
|
|
}
|
|
$rounded_amounts = round($amount, 2);
|
|
$products_amount += $rounded_amounts * $product->getQuantity();
|
|
$products[0][ "NAME" . $itemIndex ] = urlencode($product->getTitle());
|
|
$products[0][ "AMT" . $itemIndex ] = urlencode($rounded_amounts);
|
|
$products[0][ "QTY" . $itemIndex ] = urlencode($product->getQuantity());
|
|
$itemIndex ++;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Compute difference between prodcts total and cart amount
|
|
* -> get Coupons.
|
|
*/
|
|
$delta = round($products_amount - $order->getTotalAmount($useless, false), 2);
|
|
|
|
if ($delta > 0) {
|
|
$products[0][ "NAME" . $itemIndex ] = Translator::getInstance()->trans("Discount");
|
|
$products[0][ "AMT" . $itemIndex ] = - $delta;
|
|
$products[0][ "QTY" . $itemIndex ] = 1;
|
|
}
|
|
} else {
|
|
$products[0]["NAME" . $itemIndex] = urlencode(Translator::getInstance()->trans("Order").' '.$orderId);
|
|
$products[0]["AMT" . $itemIndex] = round($order->getTotalAmount($useless, false),2);
|
|
$products[0]["QTY" . $itemIndex] = 1;
|
|
}
|
|
|
|
/*
|
|
* Create setExpressCheckout request
|
|
*/
|
|
$setExpressCheckout = new PaypalNvpOperationsSetExpressCheckout(
|
|
$api,
|
|
round($order->getTotalAmount(), 2),
|
|
$order->getCurrency()->getCode(),
|
|
$successUrl,
|
|
$cancelUrl,
|
|
0,
|
|
array(
|
|
"L_PAYMENTREQUEST" => $products,
|
|
"PAYMENTREQUEST" => array(
|
|
array(
|
|
"SHIPPINGAMT" => round($order->getPostage(), 2),
|
|
"ITEMAMT" => round($order->getTotalAmount($useless, false), 2)
|
|
)
|
|
)
|
|
)
|
|
);
|
|
|
|
/*
|
|
* Try to get customer's delivery address
|
|
*/
|
|
if (null !== $address = OrderAddressQuery::create()->findPk($order->getDeliveryOrderAddressId())) {
|
|
/*
|
|
* If address is found, set address in setExpressCheckout request
|
|
*/
|
|
$setExpressCheckout->setCustomerDeliveryAddress(
|
|
$address->getLastname(),
|
|
$address->getAddress1(),
|
|
$address->getAddress2(),
|
|
$address->getCity(),
|
|
"", // State
|
|
$address->getZipcode(),
|
|
CountryQuery::create()->findPk($address->getCountryId())->getIsoalpha2()
|
|
);
|
|
|
|
/*
|
|
* $sender PaypalNvpMessageSender Instance of the class that sends requests
|
|
* $response string NVP response of paypal for setExpressCheckout request
|
|
* $req array array cast of NVP response
|
|
*/
|
|
$sender = new PaypalNvpMessageSender($setExpressCheckout, self::isSandboxMode());
|
|
|
|
$response = $sender->send();
|
|
|
|
if ($response) {
|
|
$responseData = PaypalApiManager::nvpToArray($response);
|
|
|
|
$logger->logTransaction($responseData);
|
|
/*
|
|
* if setExpressCheckout is correct, store values in the session & redirect to paypal checkout page
|
|
* else print error. ( return $this->render ... )
|
|
*/
|
|
if (isset($responseData['ACK']) && $responseData['ACK'] === "Success"
|
|
&&
|
|
isset($responseData['TOKEN']) && ! empty($responseData['TOKEN'])
|
|
) {
|
|
$sess = $this->getRequest()->getSession();
|
|
$sess->set("Paypal.token", $responseData['TOKEN']);
|
|
|
|
return new RedirectResponse(
|
|
$redirect_api->getExpressCheckoutUrl($responseData['TOKEN'])
|
|
);
|
|
}
|
|
} else {
|
|
$logger->getLogger()->error(
|
|
Translator::getInstance()->trans(
|
|
"Failed to get a valid Paypal response. Please try again",
|
|
[],
|
|
self::DOMAIN
|
|
)
|
|
);
|
|
}
|
|
} else {
|
|
$logger->getLogger()->error(
|
|
Translator::getInstance()->trans(
|
|
"Failed to get customer delivery address",
|
|
[],
|
|
self::DOMAIN
|
|
)
|
|
);
|
|
}
|
|
|
|
// Failure !
|
|
return new RedirectResponse(
|
|
$this->getPaymentFailurePageUrl(
|
|
$orderId,
|
|
// Pas de point final, sinon 404 !
|
|
Translator::getInstance()->trans(
|
|
"Sorry, something did not worked with Paypal. Please try again, or use another payment type",
|
|
[],
|
|
self::DOMAIN
|
|
)
|
|
)
|
|
);
|
|
}
|
|
|
|
public function isValidPayment()
|
|
{
|
|
$valid = false;
|
|
|
|
// Check if total order amount is within the module's limits
|
|
$order_total = $this->getCurrentOrderTotalAmount();
|
|
|
|
$min_amount = Paypal::getConfigValue('minimum_amount', 0);
|
|
$max_amount = Paypal::getConfigValue('maximum_amount', 0);
|
|
|
|
if (
|
|
($order_total > 0)
|
|
&&
|
|
($min_amount <= 0 || $order_total >= $min_amount)
|
|
&&
|
|
($max_amount <= 0 || $order_total <= $max_amount)
|
|
) {
|
|
// Check cart item count
|
|
$cartItemCount = $this->getRequest()->getSession()->getSessionCart($this->getDispatcher())->countCartItems();
|
|
|
|
if ($cartItemCount <= Paypal::getConfigValue('cart_item_count', 9)) {
|
|
$valid = true;
|
|
|
|
if (Paypal::isSandboxMode()) {
|
|
// In sandbox mode, check the current IP
|
|
$raw_ips = explode("\n", Paypal::getConfigValue('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);
|
|
}
|
|
}
|
|
}
|
|
|
|
return $valid;
|
|
}
|
|
|
|
public function postActivation(ConnectionInterface $con = null)
|
|
{
|
|
// Setup some default values at first install
|
|
if (null === self::getConfigValue('minimum_amount', null)) {
|
|
self::setConfigValue('minimum_amount', 0);
|
|
self::setConfigValue('maximum_amount', 0);
|
|
self::setConfigValue('send_payment_confirmation_message', 1);
|
|
}
|
|
|
|
if (null === MessageQuery::create()->findOneByName(self::CONFIRMATION_MESSAGE_NAME)) {
|
|
$message = new Message();
|
|
|
|
$message
|
|
->setName(self::CONFIRMATION_MESSAGE_NAME)
|
|
->setHtmlTemplateFileName('paypal-payment-confirmation.html')
|
|
->setTextTemplateFileName('paypal-payment-confirmation.txt')
|
|
->setLocale('en_US')
|
|
->setTitle('Paypal payment confirmation')
|
|
->setSubject('Payment of order {$order_ref}')
|
|
->setLocale('fr_FR')
|
|
->setTitle('Confirmation de paiement par Paypal')
|
|
->setSubject('Confirmation du paiement de votre commande {$order_ref}')
|
|
->save()
|
|
;
|
|
}
|
|
|
|
/* Deploy the module's image */
|
|
$module = $this->getModuleModel();
|
|
|
|
if (ModuleImageQuery::create()->filterByModule($module)->count() == 0) {
|
|
$this->deployImageFolder($module, sprintf('%s/images', __DIR__), $con);
|
|
}
|
|
}
|
|
|
|
public function update($currentVersion, $newVersion, ConnectionInterface $con = null)
|
|
{
|
|
if (null === self::getConfigValue('login', null)) {
|
|
$database = new Database($con);
|
|
|
|
$statement = $database->execute('select * from paypal_config');
|
|
|
|
while ($statement && $config = $statement->fetchObject()) {
|
|
switch($config->name) {
|
|
case 'login_sandbox':
|
|
Paypal::setConfigValue('sandbox_login', $config->value);
|
|
break;
|
|
|
|
case 'password_sandbox':
|
|
Paypal::setConfigValue('sandbox_password', $config->value);
|
|
break;
|
|
|
|
case 'signature_sandbox':
|
|
Paypal::setConfigValue('sandbox_signature', $config->value);
|
|
break;
|
|
|
|
default:
|
|
Paypal::setConfigValue($config->name, $config->value);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
parent::update($currentVersion, $newVersion, $con);
|
|
}
|
|
|
|
public static function isSandboxMode()
|
|
{
|
|
return 1 == intval(self::getConfigValue('sandbox'));
|
|
}
|
|
|
|
public function destroy(ConnectionInterface $con = null, $deleteModuleData = false)
|
|
{
|
|
if ($deleteModuleData) {
|
|
MessageQuery::create()->findOneByName(self::CONFIRMATION_MESSAGE_NAME)->delete();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* if you want, you can manage stock in your module instead of order process.
|
|
* Return false to decrease the stock when order status switch to pay
|
|
*
|
|
* @return bool
|
|
*/
|
|
public function manageStockOnCreation()
|
|
{
|
|
return false;
|
|
}
|
|
}
|