Files
PrestaShop/modules/paypal/paypal.php

1257 lines
55 KiB
PHP
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?php
/*
* 2007-2011 PrestaShop
*
* NOTICE OF LICENSE
*
* This source file is subject to the Academic Free License (AFL 3.0)
* that is bundled with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://opensource.org/licenses/afl-3.0.php
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade PrestaShop to newer
* versions in the future. If you wish to customize PrestaShop for your
* needs please refer to http://www.prestashop.com for more information.
*
* @author PrestaShop SA <contact@prestashop.com>
* @copyright 2007-2011 PrestaShop SA
* @version Release: $Revision: 7091 $
* @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0)
* International Registered Trademark & Property of PrestaShop SA
*/
if (!defined('_PS_VERSION_'))
exit;
define('_PAYPAL_INTEGRAL_', 0);
define('_PAYPAL_OPTION_PLUS_', 1);
define('_PAYPAL_INTEGRAL_EVOLUTION_', 2);
class PayPal extends PaymentModule
{
private $_html = '';
public function __construct()
{
$this->name = 'paypal';
$this->tab = 'payments_gateways';
$this->version = '2.8.2';
$this->currencies = true;
$this->currencies_mode = 'radio';
parent::__construct();
$this->_errors = array();
$this->page = basename(__FILE__, '.php');
$this->displayName = $this->l('PayPal');
$this->description = $this->l('Accepts payments by credit cards (CB, Visa, MasterCard, Amex, Aurore, Cofinoga, 4 stars) with PayPal.');
$this->confirmUninstall = $this->l('Are you sure you want to delete your details?');
if (Configuration::get('PAYPAL_BUSINESS') == 'paypal@prestashop.com')
$this->warning = $this->l('You are currently using the default PayPal e-mail address, please enter your own e-mail address.');
$this->_checkAndUpdateFromOldVersion();
if (file_exists(_PS_ROOT_DIR_.'/modules/paypalapi/paypalapi.php') AND $this->active)
$this->warning = $this->l('All features of Paypal API module are be include in the new Paypal module. In order to don\'t have any conflict, please don\'t use and remove PayPalAPI module.');
/* For 1.4.3 and less compatibility */
$updateConfig = array('PS_OS_CHEQUE' => 1, 'PS_OS_PAYMENT' => 2, 'PS_OS_PREPARATION' => 3, 'PS_OS_SHIPPING' => 4, 'PS_OS_DELIVERED' => 5, 'PS_OS_CANCELED' => 6,
'PS_OS_REFUND' => 7, 'PS_OS_ERROR' => 8, 'PS_OS_OUTOFSTOCK' => 9, 'PS_OS_BANKWIRE' => 10, 'PS_OS_PAYPAL' => 11, 'PS_OS_WS_PAYMENT' => 12);
foreach ($updateConfig as $u => $v)
if (!Configuration::get($u) || (int)Configuration::get($u) < 1)
{
if (defined('_'.$u.'_') && (int)constant('_'.$u.'_') > 0)
Configuration::updateValue($u, constant('_'.$u.'_'));
else
Configuration::updateValue($u, $v);
}
/* Check preactivation warning */
if (Configuration::get('PS_PREACTIVATION_PAYPAL_WARNING'))
{
if (!empty($this->warning))
$this->warning .= ', ';
$this->warning .= Configuration::get('PS_PREACTIVATION_PAYPAL_WARNING');
}
}
public function install()
{
/* Install and register on hook */
if (!parent::install()
OR !$this->registerHook('payment')
OR !$this->registerHook('paymentReturn')
OR !$this->registerHook('shoppingCartExtra')
OR !$this->registerHook('backBeforePayment')
OR !$this->registerHook('paymentReturn')
OR !$this->registerHook('rightColumn')
OR !$this->registerHook('cancelProduct')
OR !$this->registerHook('adminOrder'))
return false;
if (file_exists(_PS_ROOT_DIR_.'/modules/paypalapi/paypalapi.php') AND !Configuration::get('PAYPAL_NEW'))
{
include_once(_PS_ROOT_DIR_.'/modules/paypalapi/paypalapi.php');
$paypalapi = new PaypalAPI();
return $this->_checkAndUpdateFromOldVersion(true);
}
/* Set database */
if (!Db::getInstance()->execute('CREATE TABLE IF NOT EXISTS `'._DB_PREFIX_.'paypal_order` (
`id_order` int(10) unsigned NOT NULL,
`id_transaction` varchar(255) NOT NULL,
`payment_method` int(10) unsigned NOT NULL,
`payment_status` varchar(255) NOT NULL,
`capture` int(10) unsigned NOT NULL,
PRIMARY KEY (`id_order`)
) ENGINE='._MYSQL_ENGINE_.' DEFAULT CHARSET=utf8'))
return false;
/* Set configuration */
Configuration::updateValue('PAYPAL_SANDBOX', 1);
Configuration::updateValue('PAYPAL_BUSINESS', 'paypal@prestashop.com');
Configuration::updateValue('PAYPAL_HEADER', '');
Configuration::updateValue('PAYPAL_API_USER', '');
Configuration::updateValue('PAYPAL_API_PASSWORD', '');
Configuration::updateValue('PAYPAL_API_SIGNATURE', '');
Configuration::updateValue('PAYPAL_EXPRESS_CHECKOUT', 0);
Configuration::updateValue('PAYPAL_CAPTURE', 0);
Configuration::updateValue('PAYPAL_PAYMENT_METHOD', _PAYPAL_INTEGRAL_);
Configuration::updateValue('PAYPAL_TEMPLATE', 'A');
Configuration::updateValue('PAYPAL_NEW', 1);
Configuration::updateValue('PAYPAL_DEBUG_MODE', 0);
if (!Configuration::get('PAYPAL_OS_AUTHORIZATION'))
{
$orderState = new OrderState();
$orderState->name = array();
foreach (Language::getLanguages() AS $language)
{
if (strtolower($language['iso_code']) == 'fr')
$orderState->name[$language['id_lang']] = 'Autorisation acceptée par PayPal';
else
$orderState->name[$language['id_lang']] = 'Authorization accepted from PayPal';
}
$orderState->send_email = false;
$orderState->color = '#DDEEFF';
$orderState->hidden = false;
$orderState->delivery = false;
$orderState->logable = true;
$orderState->invoice = true;
if ($orderState->add())
copy(dirname(__FILE__).'/../../img/os/'.Configuration::get('PS_OS_PAYPAL').'.gif', dirname(__FILE__).'/../../img/os/'.(int)$orderState->id.'.gif');
Configuration::updateValue('PAYPAL_OS_AUTHORIZATION', (int)$orderState->id);
}
return true;
}
public function uninstall()
{
/* Delete all configurations */
Configuration::deleteByName('PAYPAL_SANDBOX');
Configuration::deleteByName('PAYPAL_BUSINESS');
Configuration::deleteByName('PAYPAL_HEADER');
Configuration::deleteByName('PAYPAL_API_USER');
Configuration::deleteByName('PAYPAL_API_PASSWORD');
Configuration::deleteByName('PAYPAL_API_SIGNATURE');
Configuration::deleteByName('PAYPAL_EXPRESS_CHECKOUT');
Configuration::deleteByName('PAYPAL_PAYMENT_METHOD');
Configuration::deleteByName('PAYPAL_TEMPLATE');
Configuration::deleteByName('PAYPAL_CAPTURE');
Configuration::deleteByName('PAYPAL_DEBUG_MODE');
return parent::uninstall();
}
public function getContent()
{
$this->_html .= '<h2>'.$this->l('PayPal').'</h2>';
$this->_postProcess();
$this->_setPayPalSubscription();
if (file_exists(_PS_ROOT_DIR_.'/modules/paypalapi/paypalapi.php'))
$this->_html .= '<div class="warning warn"><h3>'.$this->l('All features of Paypal API module are be include in this new module. In order to don\'t have any conflict, please don\'t use and remove PayPalAPI module.').'</h3></div>';
$this->_setConfigurationForm();
return $this->_html;
}
public function hookPayment($params)
{
if (!$this->active)
return ;
/*
* PAYMENT METHOD:
* 0: Integral
* 1: Option +
* 2: Integral Evolution
*/
if (Configuration::get('PAYPAL_PAYMENT_METHOD') == _PAYPAL_INTEGRAL_EVOLUTION_)
return $this->display(__FILE__, 'integral_evolution/paypal.tpl');
elseif (Configuration::get('PAYPAL_PAYMENT_METHOD') == _PAYPAL_INTEGRAL_ OR Configuration::get('PAYPAL_PAYMENT_METHOD') == _PAYPAL_OPTION_PLUS_)
{
if ($this->_isPayPalAPIAvailable())
{
$this->context->smarty->assign('integral', (Configuration::get('PAYPAL_PAYMENT_METHOD') == 0 ? 1 : 0));
$this->context->smarty->assign('logo', _MODULE_DIR_.$this->name.'/paypal.gif');
return $this->display(__FILE__, 'payment/payment.tpl');
}
else
return $this->display(__FILE__, 'standard/paypal.tpl');
}
else
die($this->l('No valid payment method selected'));
}
public function hookShoppingCartExtra($params)
{
if (!$this->active)
return ;
if (Configuration::get('PAYPAL_EXPRESS_CHECKOUT') AND !$this->context->customer->isLogged(true) AND $this->_isPayPalAPIAvailable())
{
$this->context->smarty->assign('logo', $this->getLogo(true));
return $this->display(__FILE__, 'express/shopping_cart.tpl');
}
}
public function hookPaymentReturn($params)
{
if (!$this->active)
return ;
return $this->display(__FILE__, 'confirmation.tpl');
}
public function hookRightColumn($params)
{
$this->context->smarty->assign('iso_code', Tools::strtolower($this->context->language));
$this->context->smarty->assign('logo', $this->getLogo(false, true));
return $this->display(__FILE__, 'column.tpl');
}
public function hookLeftColumn($params)
{
return $this->hookRightColumn($params);
}
public function hookBackBeforePayment($params)
{
if (!$this->active)
return ;
/* Only execute if you use PayPal API for payment */
if (Configuration::get('PAYPAL_PAYMENT_METHOD') != _PAYPAL_INTEGRAL_EVOLUTION_ AND $this->_isPayPalAPIAvailable())
{
if ($params['module'] != $this->name)
return false;
if (!$token = $this->context->cookie->paypal_token)
return false;
if (!$payerID = $this->context->cookie->paypal_payer_id)
return false;
Tools::redirect('modules/paypal/express/submit.php?confirm=1&token='.$token.'&payerID='.$payerID);
}
}
public function hookAdminOrder($params)
{
if (Tools::isSubmit('paypal'))
{
switch (Tools::getValue('paypal'))
{
case 'captureOk':
$message = $this->l('Funds have been recovered.');
break;
case 'captureError':
$message = $this->l('Recovery of funds request unsuccessful. Please see log message!');
break;
case 'validationOk':
$message = $this->l('Validation successful. Please see log message!');
break;
case 'refundOk':
$message = $this->l('Refund has been made.');
break;
case 'refundError':
$message = $this->l('Refund request unsuccessful. Please see log message!');
break;
}
if (isset($message) AND $message)
$this->_html .= '
<br />
<div class="module_confirmation conf confirm" style="width: 400px;">
<img src="'._PS_IMG_.'admin/ok.gif" alt="" title="" /> '.$message.'
</div>';
}
if ($this->_needValidation((int)$params['id_order']) AND $this->_isPayPalAPIAvailable())
{
$this->_html .= '<br />
<fieldset style="width:400px;">
<legend><img src="'._MODULE_DIR_.$this->name.'/logo.gif" alt="" /> '.$this->l('PayPal Validation').'</legend>
<p><b>'.$this->l('Information:').'</b> '.(OrderHistory::getLastOrderState((int)($params['id_order']))->id == (int)(Configuration::get('PAYPAL_OS_AUTHORIZATION')) ? $this->l('Pending Capture - No shipping') : $this->l('Pending Payment - No shipping')).'</p>
<form method="post" action="'.htmlentities($_SERVER['REQUEST_URI']).'">
<input type="hidden" name="id_order" value="'.(int)$params['id_order'].'" />
<p class="center"><input type="submit" class="button" name="submitPayPalValidation" value="'.$this->l('Get payment status').'" /></p>
</form>';
$this->_postProcess();
$this->_html .= '</fieldset>';
}
if ($this->_needCapture((int)$params['id_order']) AND $this->_isPayPalAPIAvailable())
{
$this->_html .= '<br />
<fieldset style="width:400px;">
<legend><img src="'._MODULE_DIR_.$this->name.'/logo.gif" alt="" /> '.$this->l('PayPal Capture').'</legend>
<p><b>'.$this->l('Information:').'</b> '.$this->l('Funds ready to be captured before shipping.').'</p>
<form method="post" action="'.htmlentities($_SERVER['REQUEST_URI']).'">
<input type="hidden" name="id_order" value="'.(int)$params['id_order'].'" />
<p class="center"><input type="submit" class="button" name="submitPayPalCapture" value="'.$this->l('Get the money.').'" /></p>
</form>';
$this->_postProcess();
$this->_html .= '</fieldset>';
}
if ($this->_canRefund((int)$params['id_order']) AND $this->_isPayPalAPIAvailable())
{
$this->_html .= '<br />
<fieldset style="width:400px;">
<legend><img src="'._MODULE_DIR_.$this->name.'/logo.gif" alt="" /> '.$this->l('PayPal Refund').'</legend>
<p><b>'.$this->l('Information:').'</b> '.$this->l('Payment accepted').'</p>
<p><b>'.$this->l('Information:').'</b> '.$this->l('When you refund a product, a partial refund is made unless you select "Generate a voucher".').'</p>
<form method="post" action="'.htmlentities($_SERVER['REQUEST_URI']).'">
<input type="hidden" name="id_order" value="'.(int)$params['id_order'].'" />
<p class="center"><input type="submit" class="button" name="submitPayPalRefund" value="'.$this->l('Refund total transaction').'" onclick="if(!confirm(\''.$this->l('Are you sure?').'\'))return false;" /></p>
</form>';
$this->_postProcess();
$this->_html .= '</fieldset>';
}
return $this->_html;
}
public function hookCancelProduct($params)
{
if (Tools::isSubmit('generateDiscount'))
return false;
if (!$this->_isPayPalAPIAvailable())
return false;
if ($params['order']->module != $this->name)
return false;
if (!($order = $params['order']) OR !Validate::isLoadedObject($order))
return false;
if (!$order->hasBeenPaid())
return false;
if (!($order_detail = new OrderDetail((int)($params['id_order_detail']))) OR !Validate::isLoadedObject($order_detail))
return false;
$id_transaction = $this->_getTransactionId((int)($order->id));
if (!$id_transaction)
return false;
$products = $order->getProducts();
$amt = $products[(int)($order_detail->id)]['product_price_wt'] * (int)($_POST['cancelQuantity'][(int)($order_detail->id)]);
$response = $this->_makeRefund($id_transaction, $order->id, (float)($amt));
$message = $this->l('Cancel products result:').'<br>';
foreach ($response AS $k => $value)
$message .= $k.': '.$value.'<br>';
$this->_addNewPrivateMessage((int)$order->id, $message);
}
public function PayPalRound($value)
{
return (floor(round($value * 100, 2)) / 100);
}
public function makePayPalAPIValidation($cookie, $cart, $id_currency, $payerID, $type)
{
if (!$this->active)
return ;
if (!$this->_isPayPalAPIAvailable())
return ;
// Filling-in vars
$id_cart = (int)($cart->id);
$currency = new Currency((int)($id_currency));
$iso_currency = $currency->iso_code;
$token = $cookie->paypal_token;
$total = (float)($cart->getOrderTotal(true, Cart::BOTH));
$paymentType = Configuration::get('PAYPAL_CAPTURE') == 1 ? 'Authorization' : 'Sale';
$serverName = urlencode($_SERVER['SERVER_NAME']);
$bn = ($type == 'express' ? 'ECS' : 'ECM');
$notifyURL = urlencode(Tools::getShopDomainSsl(true, true).__PS_BASE_URI__.'modules/paypal/ipn.php');
// Getting address
if (isset($cookie->id_cart) AND $cookie->id_cart)
$cart = new Cart((int)($cookie->id_cart));
if (isset($cart->id_address_delivery) AND $cart->id_address_delivery)
$address = new Address((int)($cart->id_address_delivery));
$requestAddress = '';
if (Validate::isLoadedObject($address))
{
$country = new Country((int)($address->id_country));
$state = new State((int)($address->id_state));
$requestAddress = '&SHIPTONAME='.urlencode($address->company.' '.$address->firstname.' '.$address->lastname).'&SHIPTOSTREET='.urlencode($address->address1.' '.$address->address2).'&SHIPTOCITY='.urlencode($address->city).'&SHIPTOSTATE='.urlencode($address->id_state ? $state->iso_code :$country->iso_code).'&SHIPTOCOUNTRYCODE='.urlencode($country->iso_code).'&SHIPTOZIP='.urlencode($address->postcode);
}
// Making request
$request='&TOKEN='.urlencode($token).'&PAYERID='.urlencode($payerID).'&PAYMENTACTION='.$paymentType.'&AMT='.$total.'&CURRENCYCODE='.$iso_currency.'&IPADDRESS='.$serverName.'&NOTIFYURL='.$notifyURL.'&BUTTONSOURCE=PRESTASHOP_'.$bn.$requestAddress ;
$discounts = (float)$cart->getOrderTotal(true, Cart::ONLY_DISCOUNTS);
if ($discounts == 0)
{
$products = $cart->getProducts();
$amt = 0;
for ($i = 0; $i < sizeof($products); $i++)
{
$request .= '&L_NAME'.$i.'='.substr(urlencode($products[$i]['name'].(isset($products[$i]['attributes'])?' - '.$products[$i]['attributes']:'').(isset($products[$i]['instructions'])?' - '.$products[$i]['instructions']:'') ), 0, 127);
$request .= '&L_AMT'.$i.'='.urlencode($this->PayPalRound($products[$i]['price']));
$request .= '&L_QTY'.$i.'='.urlencode($products[$i]['cart_quantity']);
$amt += $this->PayPalRound($products[$i]['price'])*$products[$i]['cart_quantity'];
}
$shipping = $this->PayPalRound($cart->getOrderShippingCost($cart->id_carrier, false));
$request .= '&ITEMAMT='.urlencode($amt);
$request .= '&SHIPPINGAMT='.urlencode($shipping);
$request .= '&TAXAMT='.urlencode((float)max($this->PayPalRound($total - $amt - $shipping), 0));
}
else
{
$products = $cart->getProducts();
$description = 0;
for ($i = 0; $i < sizeof($products); $i++)
$description .= ($description == ''?'':', ').$products[$i]['cart_quantity']." x ".$products[$i]['name'].(isset($products[$i]['attributes'])?' - '.$products[$i]['attributes']:'').(isset($products[$i]['instructions'])?' - '.$products[$i]['instructions']:'') ;
$request .= '&ORDERDESCRIPTION='.urlencode(substr($description, 0, 120));
}
// Calling PayPal API
include_once(_PS_MODULE_DIR_.'paypal/api/paypallib.php');
$ppAPI = new PaypalLib();
$result = $ppAPI->makeCall($this->getAPIURL(), $this->getAPIScript(), 'DoExpressCheckoutPayment', $request);
$this->_logs = array_merge($this->_logs, $ppAPI->getLogs());
// Checking PayPal result
if (!is_array($result) OR !sizeof($result))
$this->displayPayPalAPIError($this->l('Authorization to PayPal failed.'), $this->_logs);
elseif (!isset($result['ACK']) OR strtoupper($result['ACK']) != 'SUCCESS')
$this->displayPayPalAPIError($this->l('PayPal return error.'), $this->_logs);
elseif (!isset($result['TOKEN']) OR $result['TOKEN'] != $cookie->paypal_token)
{
$logs[] = '<b>'.$ppExpress->l('Token given by PayPal is not the same as the cookie token', 'submit').'</b>';
$ppExpress->displayPayPalAPIError($ppExpress->l('PayPal return error.', 'submit'), $logs);
}
// Making log
$id_transaction = $result['TRANSACTIONID'];
if (Configuration::get('PAYPAL_CAPTURE'))
$this->_logs[] = $this->l('Authorization for deferred payment granted by PayPal.');
else
$this->_logs[] = $this->l('Order finished with PayPal!');
$message = Tools::htmlentitiesUTF8(strip_tags(implode("\n", $this->_logs)));
// Order status
switch ($result['PAYMENTSTATUS'])
{
case 'Completed':
$id_order_state = Configuration::get('PS_OS_PAYMENT');
break;
case 'Pending':
if ($result['PENDINGREASON'] != 'authorization')
$id_order_state = Configuration::get('PS_OS_PAYPAL');
else
$id_order_state = (int)(Configuration::get('PAYPAL_OS_AUTHORIZATION'));
break;
default:
$id_order_state = Configuration::get('PS_OS_ERROR');
}
// Call payment validation method
$this->validateOrder($id_cart, $id_order_state, (float)($cart->getOrderTotal(true, Cart::BOTH)), $this->displayName, $message, array('transaction_id' => $id_transaction, 'payment_status' => $result['PAYMENTSTATUS'], 'pending_reason' => $result['PENDINGREASON']), $id_currency, false, $cart->secure_key);
// Clean cookie
unset($cookie->paypal_token);
// Displaying output
$order = new Order((int)($this->currentOrder));
Tools::redirect('index.php?controller=order-confirmation&id_cart='.(int)($id_cart).'&id_module='.(int)($this->id).'&id_order='.(int)($this->currentOrder).'&key='.$order->secure_key);
}
public function validateOrder($id_cart, $id_order_state, $amountPaid, $paymentMethod = 'Unknown', $message = NULL, $extraVars = array(), $currency_special = NULL, $dont_touch_amount = false, $secure_key = false, Shop $shop = null)
{
if (!$this->active)
return;
parent::validateOrder($id_cart, $id_order_state, $amountPaid, $paymentMethod, $message, $extraVars, $currency_special, $dont_touch_amount, $secure_key);
if (array_key_exists('transaction_id', $extraVars) AND array_key_exists('payment_status', $extraVars))
$this->_saveTransaction($id_cart, $extraVars);
}
public function getPayPalURL()
{
return 'www'.(Configuration::get('PAYPAL_SANDBOX') ? '.sandbox' : '').'.paypal.com';
}
public function getPaypalIntegralEvolutionUrl()
{
if (Configuration::get('PAYPAL_SANDBOX'))
return 'https://'.$this->getPayPalURL().'/cgi-bin/acquiringweb';
return 'https://securepayments.paypal.com/acquiringweb?cmd=_hosted-payment';
}
public function getPaypalStandardUrl()
{
return 'https://'.$this->getPayPalURL().'/cgi-bin/webscr';
}
public function getAPIURL()
{
return 'api-3t'.(Configuration::get('PAYPAL_SANDBOX') ? '.sandbox' : '').'.paypal.com';
}
public function getAPIScript()
{
return '/nvp';
}
public function getL($key)
{
$translations = array(
'mc_gross' => $this->l('Paypal key \'mc_gross\' not specified, can\'t control amount paid.'),
'payment_status' => $this->l('Paypal key \'payment_status\' not specified, can\'t control payment validity'),
'payment' => $this->l('Payment: '),
'custom' => $this->l('Paypal key \'custom\' not specified, cannot relay to cart'),
'txn_id' => $this->l('Paypal key \'txn_id\' not specified, transaction unknown'),
'mc_currency' => $this->l('Paypal key \'mc_currency\' not specified, currency unknown'),
'cart' => $this->l('Cart not found'),
'order' => $this->l('Order has already been placed'),
'transaction' => $this->l('Paypal Transaction ID: '),
'verified' => $this->l('The PayPal transaction could not be VERIFIED.'),
'connect' => $this->l('Problem connecting to the PayPal server.'),
'nomethod' => $this->l('No communications transport available.'),
'socketmethod' => $this->l('Verification failure (using fsockopen). Returned: '),
'curlmethod' => $this->l('Verification failure (using cURL). Returned: '),
'curlmethodfailed' => $this->l('Connection using cURL failed'),
'Please wait, redirecting to Paypal... Thanks.' => $this->l('Please wait, redirecting to Paypal... Thanks.'),
'Cancel' => $this->l('Cancel'),
'My cart' => $this->l('My cart'),
'Return to shop' => $this->l('Return to shop'),
'Paypal error: (invalid or undefined business account email)' => $this->l('Paypal error: (invalid or undefined business account e-mail)'),
'Paypal error: (invalid address or customer)' => $this->l('Paypal error: (invalid address or customer)')
);
if (!isset($translations[$key]))
return $key;
return $translations[$key];
}
public function getLogo($ppExpress = false, $vertical = false)
{
if ($ppExpress)
{
$iso_code = Tools::strtoupper($this->context->language);
$logo = array(
'FR' => 'FR',
'DE' => 'DE',
'US' => 'US',
'GB' => 'UK',
'ES' => 'ES',
'IT' => 'IT',
'PL' => 'PL',
'NL' => 'NL',
'AU' => 'AU',
'CA' => 'CA',
'CN' => 'CN',
'JP' => 'JP'
);
if (!isset($logo[$iso_code]))
$iso_code = 'US';
return _MODULE_DIR_.$this->name.'/img/'.$logo[$iso_code].'_pp_express.gif';
}
if (Configuration::get('PAYPAL_PAYMENT_METHOD') == _PAYPAL_INTEGRAL_)
{
$country_code = $this->getCountryCode();
$logo = array(
'FR' => _MODULE_DIR_.$this->name.'/img/FR_pp_integral.gif',
'DE' => _MODULE_DIR_.$this->name.'/img/DE_pp_integral.gif',
'US' => _MODULE_DIR_.$this->name.'/img/US_pp_integral.gif',
'GB' => _MODULE_DIR_.$this->name.'/img/UK_pp_integral.gif',
'ES' => _MODULE_DIR_.$this->name.'/img/ES_pp_integral.gif',
'IT' => _MODULE_DIR_.$this->name.'/img/IT_pp_integral.gif',
'PL' => _MODULE_DIR_.$this->name.'/img/PL_pp_integral.gif',
'NL' => _MODULE_DIR_.$this->name.'/img/NL_pp_integral.gif',
'AU' => _MODULE_DIR_.$this->name.'/img/AU_pp_integral.gif',
'CA' => _MODULE_DIR_.$this->name.'/img/CA_pp_integral.gif',
'CN' => _MODULE_DIR_.$this->name.'/img/CN_pp_integral.gif',
'JP' => _MODULE_DIR_.$this->name.'/img/JP_pp_integral.gif',
'FR_vertical' => _MODULE_DIR_.$this->name.'/img/vertical_FR_large.png',
'US_vertical' => _MODULE_DIR_.$this->name.'/img/vertical_US_large.png'
);
if (isset($logo[$country_code.($vertical ? '_vertical' : '')]))
return $logo[$country_code.($vertical ? '_vertical' : '')];
return ($vertical ? $logo['US_vertical'] : $logo['US']);
}
elseif (Configuration::get('PAYPAL_PAYMENT_METHOD') == _PAYPAL_INTEGRAL_EVOLUTION_)
return _MODULE_DIR_.$this->name.'/img/integral_evolution'.($vertical ? '_vertical' : '').'.png';
return _MODULE_DIR_.$this->name.'/img/PayPal_mark_60x38.gif';
}
public function getCountryCode()
{
$address = new Address($this->context->cart->id_address_invoice);
$country = new Country($address->id_country);
return $country->iso_code;
}
public function displayPayPalAPIError($message, $log = false)
{
$send = true;
// Sanitize log
foreach ($log AS $key => $string)
if ($string == 'ACK -> Success')
$send = false;
elseif (substr($string, 0, 6) == 'METHOD')
{
$values = explode('&', $string);
foreach ($values AS $key2 => $value)
{
$values2 = explode('=', $value);
foreach ($values2 AS $key3 => $value2)
if ($value2 == 'PWD' || $value2 == 'SIGNATURE')
$values2[$key3 + 1] = '*********';
$values[$key2] = implode('=', $values2);
}
$log[$key] = implode('&', $values);
}
include(dirname(__FILE__).'/../../header.php');
$this->context->smarty->assign('message', $message);
$this->context->smarty->assign('logs', $log);
$data = array('{logs}' => implode('<br />', $log));
if ($send)
Mail::Send($this->context->language->id, 'error_reporting', Mail::l('Error reporting from your PayPal module'), $data, Configuration::get('PS_SHOP_EMAIL'), NULL, NULL, NULL, NULL, NULL, _PS_MODULE_DIR_.$this->name.'/mails/');
echo $this->display(__FILE__, 'error.tpl');
include_once(dirname(__FILE__).'/../../footer.php');
die;
}
private function _saveTransaction($id_cart, $extraVars)
{
$cart = new Cart((int)($id_cart));
if (Validate::isLoadedObject($cart) AND $cart->OrderExists())
{
$id_order = Db::getInstance()->getValue('
SELECT `id_order`
FROM `'._DB_PREFIX_.'orders`
WHERE `id_cart` = '.(int)$cart->id);
Db::getInstance()->execute('
INSERT INTO `'._DB_PREFIX_.'paypal_order` (`id_order`, `id_transaction`, `payment_method`, `payment_status`, `capture`)
VALUES ('.(int)$id_order.', \''.pSQL($extraVars['transaction_id']).'\', '.(int)Configuration::get('PAYPAL_PAYMENT_METHOD').', \''.pSQL($extraVars['payment_status']).((isset($extraVars['pending_reason']) AND $extraVars['pending_reason'] == 'authorization') ? '_authorization' : '').'\', '.(int)(Configuration::get('PAYPAL_CAPTURE')).')');
}
}
private function _canRefund($id_order)
{
if (!(int)$id_order)
return false;
$paypal_order = Db::getInstance()->getRow('
SELECT *
FROM `'._DB_PREFIX_.'paypal_order`
WHERE `id_order` = '.(int)$id_order);
if (!is_array($paypal_order) OR !sizeof($paypal_order))
return false;
if ($paypal_order['payment_status'] != 'Completed' OR $paypal_order['capture'] != 0)
return false;
return true;
}
private function _needValidation($id_order)
{
if (!(int)$id_order)
return false;
$order = Db::getInstance()->getRow('
SELECT `payment_method`, `payment_status`
FROM `'._DB_PREFIX_.'paypal_order`
WHERE `id_order` = '.(int)$id_order);
if (!$order)
return false;
return $order['payment_status'] == 'Pending' AND $order['payment_method'] == _PAYPAL_INTEGRAL_EVOLUTION_;
}
private function _needCapture($id_order)
{
if (!(int)$id_order)
return false;
$result = Db::getInstance()->getRow('
SELECT `payment_method`, `payment_status`, `capture`
FROM `'._DB_PREFIX_.'paypal_order`
WHERE `id_order` = '.(int)($id_order).' AND `capture` = 1');
if (!isset($result['payment_method']))
return false;
if ($result['payment_status'] != 'Pending_authorization' AND $result['payment_status'] != 'Completed')
return false;
return true;
}
private function _setConfigurationForm()
{
$this->_html .= '
<form method="post" action="'.htmlentities($_SERVER['REQUEST_URI']).'">
<script type="text/javascript">
var pos_select = '.(($tab = (int)Tools::getValue('tabs')) ? $tab : '0').';
</script>
<script type="text/javascript" src="'._PS_BASE_URL_._PS_JS_DIR_.'tabpane.js"></script>
<link type="text/css" rel="stylesheet" href="'._PS_BASE_URL_._PS_CSS_DIR_.'tabpane.css" />
<input type="hidden" name="tabs" id="tabs" value="0" />
<div class="tab-pane" id="tab-pane-1" style="width:100%;">
<div class="tab-page" id="step1">
<h4 class="tab">'.$this->l('Solution').'</h2>
'.$this->_getSolutionTabHtml().'
</div>
<div class="tab-page" id="step2">
<h4 class="tab">'.$this->l('Settings').'</h2>
'.$this->_getSettingsTabHtml().'
</div>
<div class="tab-page" id="step3">
<h4 class="tab">'.$this->l('Logos and personalization').'</h2>
'.$this->_getPersonalizationsTabHtml().'
</div>
</div>
<div class="clear"></div>
<script type="text/javascript">
function loadTab(id){}
setupAllTabs();
</script>
</form>';
}
private function _getSolutionTabHtml()
{
$paymentMethod = (int)(Tools::getValue('payment_method', Configuration::get('PAYPAL_PAYMENT_METHOD')));
$paypalExpress = (int)(Tools::isSubmit('paypal_express') ? 1 : Configuration::get('PAYPAL_EXPRESS_CHECKOUT'));
$paypalDebug = (int)(Tools::isSubmit('paypal_debug') ? 1 : Configuration::get('PAYPAL_DEBUG_MODE'));
$link = 'http://altfarm.mediaplex.com/ad/ck/3484-23403-8030-88?ID=PROCPRESTA';
$lang = $this->context->language;
if (strtolower($lang->iso_code) == 'es')
$link = 'http://altfarm.mediaplex.com/ad/ck/3484-34334-12439-1';
else if (strtolower($lang->iso_code) == 'it')
$link = 'https://www.paypal-business.it/paypalpro.asp';
return '
<h2>'.$this->l('Solution').'</h2>
<h3>'.$this->l('Choose a solution:').'</h3>
<ul style="list-style-type:none;">
<li><input type="radio" name="payment_method" id="payment_method_0" value="'._PAYPAL_INTEGRAL_.'" '.($paymentMethod == _PAYPAL_INTEGRAL_ ? 'checked="checked" ' : '').'/> <label for="payment_method_0" class="t" style="font-weight:normal;"><b>'.$this->l('Payments by credit cards').'</b>: '.$this->l('CB , Visa, Mastercard and PayPal account').'</label></li>
<li><input type="radio" name="payment_method" id="payment_method_2" value="'._PAYPAL_INTEGRAL_EVOLUTION_.'" '.($paymentMethod == _PAYPAL_INTEGRAL_EVOLUTION_ ? 'checked="checked" ' : '').'/> <label for="payment_method_2" class="t"><b>'.$this->l('Payments by cards + seller protection').'</b></label><sup>*</sup> '.$this->l('(PayPal Integral Evolution, monthly subscription)').'</li>
<li><input type="radio" name="payment_method" id="payment_method_1" value="'._PAYPAL_OPTION_PLUS_.'" '.($paymentMethod == _PAYPAL_OPTION_PLUS_ ? 'checked="checked" ' : '').'/> <label for="payment_method_1" class="t">'.$this->l('Payments by').' <b>'.$this->l('PayPal account').'</b> '.$this->l('(PayPal Option+)').'</label></li>
</ul>
<p style="color:red;"><sup>*</sup> '.$this->l('Activation subject to conditions').', <a style="color:red;text-decoration:underline;" href="'.$link.'" style="text-decoration:underline;" target="_blank">'.$this->l('click here to subscribe').'</a></p>
<h3>'.$this->l('Option:').'</h3>
<ul style="list-style-type:none;">
<li><input type="checkbox" name="paypal_express" id="paypal_express" value="1" '.($paypalExpress ? 'checked="checked" ' : '').'/> <label for="paypal_express" class="t"><b>'.$this->l('PayPal Express : payment in 2 clicks').'</b> '.$this->l('with PayPal account directly from cart page').'</label></li>
<li><input type="checkbox" name="paypal_debug" id="paypal_debug" value="1" '.($paypalDebug ? 'checked="checked" ' : '').'/> <label for="paypal_express" class="t"><b>'.$this->l('Debug only:').'</b> '.$this->l('Activate long log message').'</label></li>
</ul>
<p class="center"><input class="button" type="submit" name="submitPayPal" value="'.$this->l('Save settings').'" /></p>
<div style="border:1px solid red;color:red;padding:15px;">
<span style="font-weight:bold;text-decoration:underline;">'.$this->l('Important:').'</span>
'.$this->l('To use any PayPal solution, you need to set up API parameters in the « Settings » Tab').'
</div>';
}
private function _getSettingsTabHtml()
{
$lang = $this->context->language;
$sandboxMode = (int)(Tools::getValue('sandbox_mode', Configuration::get('PAYPAL_SANDBOX')));
$paypalCapture = (int)(Tools::getValue('paypal_capture', Configuration::get('PAYPAL_CAPTURE')));
$html = '
<h2>'.$this->l('Settings').'</h2>
<label>'.$this->l('Sandbox mode (tests)').':</label>
<div class="margin-form" style="padding-top:2px;">
<input type="radio" name="sandbox_mode" id="sandbox_mode_1" value="1" '.($sandboxMode ? 'checked="checked" ' : '').'/> <label for="sandbox_mode_1" class="t">'.$this->l('Active').'</label>
<input type="radio" name="sandbox_mode" id="sandbox_mode_0" value="0" style="margin-left:15px;" '.(!$sandboxMode ? 'checked="checked" ' : '').'/> <label for="sandbox_mode_0" class="t">'.$this->l('Inactive').'</label>
</div>
<div class="clear"></div>
<label>'.$this->l('Payment type').':</label>
<div class="margin-form" style="padding-top:2px;">
<input type="radio" name="paypal_capture" id="paypal_capture_0" value="0" '.(!$paypalCapture ? 'checked="checked" ' : '').'/> <label for="paypal_capture_0" class="t">'.$this->l('Direct (sales)').'</label>
<input type="radio" name="paypal_capture" id="paypal_capture_1" value="1" style="margin-left:15px;" '.($paypalCapture ? 'checked="checked" ' : '').'/> <label for="paypal_capture_1" class="t">'.$this->l('Authorization / Manual Capture').' '.$this->l('(Payment shipping)').'</label>
</div>
<label>'.$this->l('PayPal account e-mail').':</label>
<div class="margin-form">
<input type="text" name="email_paypal" value="'.htmlentities(Tools::getValue('email_paypal', Configuration::get('PAYPAL_BUSINESS')), ENT_COMPAT, 'UTF-8').'" size="30" />
</div>
<br />
<h3 style="clear:both;">'.$this->l('Activation of API calls').'</h3>
<label>'.$this->l('API Username').':</label>
<div class="margin-form">
<input type="text" name="api_username" value="'.htmlentities(Tools::getValue('api_username', Configuration::get('PAYPAL_API_USER')), ENT_COMPAT, 'UTF-8').'" size="30" />
</div>
<div class="clear"></div>
<label>'.$this->l('API Password').':</label>
<div class="margin-form">
<input type="password" name="api_password" value="'.htmlentities(Tools::getValue('api_password', Configuration::get('PAYPAL_API_PASSWORD')), ENT_COMPAT, 'UTF-8').'" />
<p>'.$this->l('Leave blank if the password has not changed').'</p>
</div>
<label>'.$this->l('API Signature').':</label>
<div class="margin-form">
<input type="text" name="api_signature" value="'.htmlentities(Tools::getValue('api_signature', Configuration::get('PAYPAL_API_SIGNATURE')), ENT_COMPAT, 'UTF-8').'" size="40" />
</div>
<p>
<a style="color:blue;text-decoration:underline" href="http://www.youtube.com/watch?v=';
if (strtolower($lang->iso_code) == 'fr')
$html .= 'P2OmzHzbpIA';
elseif (strtolower($lang->iso_code) == 'es')
$html .= '5x_BXI4equo';
else
$html .= 'ho1OefLKbM0';
$html .= '" target="_blank">'.$this->l('Click here to learn how to generate your API username, password and signature.').'</a>
</p>
<p class="center"><input class="button" type="submit" name="submitPayPal" value="'.$this->l('Save settings').'" /></p>';
return $html;
}
private function _getPersonalizationsTabHtml()
{
$lang = $this->context->language;
$template_paypal = Tools::getValue('template_paypal', Configuration::get('PAYPAL_TEMPLATE'));
return '
<h2>'.$this->l('Logos and personalizations').'</h2>
<label for="banner_url">'.$this->l('Banner image URL').':</label>
<div class="margin-form">
<input type="text" name="banner_url" value="'.htmlentities(Tools::getValue('banner_url', Configuration::get('PAYPAL_HEADER')), ENT_COMPAT, 'UTF-8').'" size="50" />
<p>'.$this->l('The image should be hosted on a secure (https) server. Max: 750x90px.').'</p>
</div>
<label>'.$this->l('Template chosen for PayPal Integral Evolution').':</label>
<div class="margin-form" style="padding-top:2px;">
<input type="radio" name="template_paypal" id="template_paypal_a" value="A" '.($template_paypal == 'A' ? 'checked="checked" ' : '').'/> <label for="template_paypal_a" class="t">A</label>
<input type="radio" name="template_paypal" id="template_paypal_b" value="B" style="margin-left:10px;" '.($template_paypal == 'B' ? 'checked="checked" ' : '').'/> <label for="template_paypal_b" class="t">B</label>
<input type="radio" name="template_paypal" id="template_paypal_c" value="C" style="margin-left:10px;" '.($template_paypal == 'C' ? 'checked="checked" ' : '').'/> <label for="template_paypal_c" class="t">C</label>
</div>
'.($lang->iso_code == 'fr' ? '<p style="clear:both;"><a style="color:blue;text-decoration:underline;" href="https://cms.paypal.com/cms_content/FR/fr_FR/files/developer/Paypal_Integral_Evolution_Personnalisation.pdf" target="_blank">'.$this->l('Click here to learn how to customize these templates').'</a></p>' : '').'
<p class="center"><input class="button" type="submit" name="submitPayPal" value="'.$this->l('Save settings').'" /></p>';
}
private function _setPayPalSubscription()
{
$this->_html .= '
<div style="float: right; width: 440px; height: 150px; border: dashed 1px #666; padding: 8px; margin-left: 12px;">
<h2>'.$this->l('Opening your PayPal account').'</h2>
<div style="clear: both;"></div>
<p>'.$this->l('When opening your PayPal account by clicking on the following image, you are helping us significantly to improve the PrestaShop software:').'</p>
<p style="text-align: center;"><a href="https://www.paypal.com/fr/mrb/pal=TWJHHUL9AEP9C"><img src="../modules/paypal/prestashop_paypal.png" alt="PrestaShop & PayPal" style="margin-top: 12px;" /></a></p>
<div style="clear: right;"></div>
</div>
<img src="../modules/paypal/paypal.gif" style="float:left; margin-right:15px;" />
<b>'.$this->l('This module allows you to accept payments by PayPal.').'</b><br /><br />
'.$this->l('If the client chooses this payment mode, your PayPal account will be automatically credited.').'<br />
'.$this->l('You need to configure your PayPal account before using this module.').'
<div style="clear:both;">&nbsp;</div>';
}
private function _postProcess()
{
if (Tools::isSubmit('submitPayPal'))
{
$template_available = array('A', 'B', 'C');
if (!Validate::isUnsignedInt(Tools::getValue('payment_method')) OR (int)(Tools::getValue('payment_method')) > 2)
$this->_errors[] = $this->l('Invalid solution');
if (Tools::getValue('email_paypal') == NULL AND Tools::getValue('api_username') == NULL AND Tools::getValue('api_signature') == NULL)
$this->_errors[] = $this->l('Indicate account information.');
if (Tools::getValue('email_paypal') != NULL AND !Validate::isEmail(Tools::getValue('email_paypal')))
$this->_errors[] = $this->l('E-mail invalid');
if (Tools::getValue('banner_url') != NULL AND !Validate::isUrl(Tools::getValue('banner_url')))
$this->_errors[] = $this->l('URL for banner is invalid');
elseif (Tools::getValue('banner_url') != NULL AND strpos(Tools::getValue('banner_url'), 'https://') === false)
$this->_errors[] = $this->l('URL for banner must use HTTPS protocol');
if (!in_array(Tools::getValue('template_paypal'), $template_available))
$this->_errors[] = $this->l('PayPal template invalid.');
if (Tools::getValue('paypal_capture') == 1 AND (Tools::getValue('api_username') == NULL OR Tools::getValue('api_signature') == NULL))
$this->_errors[] = $this->l('Cannot use Authorization / capture without API Credentials.');
if (Tools::getValue('payment_method') == _PAYPAL_INTEGRAL_EVOLUTION_ AND (Tools::getValue('api_username') == NULL OR Tools::getValue('api_signature') == NULL))
$this->_errors[] = $this->l('Cannot use this solution without API Credentials.');
if (Tools::isSubmit('paypal_express') AND (Tools::getValue('api_username') == NULL OR Tools::getValue('api_signature') == NULL))
$this->_errors[] = $this->l('Cannot use PayPal Express without API Credentials.');
if (!sizeof($this->_errors))
{
Configuration::updateValue('PAYPAL_SANDBOX', (int)(Tools::getValue('sandbox_mode')));
Configuration::updateValue('PAYPAL_BUSINESS', trim(Tools::getValue('email_paypal')));
Configuration::updateValue('PAYPAL_HEADER', Tools::getValue('banner_url'));
Configuration::updateValue('PAYPAL_API_USER', trim(Tools::getValue('api_username')));
Configuration::updateValue('PAYPAL_API_PASSWORD', trim(Tools::getValue('api_password')));
Configuration::updateValue('PAYPAL_API_SIGNATURE', trim(Tools::getValue('api_signature')));
Configuration::updateValue('PAYPAL_EXPRESS_CHECKOUT', (int)(Tools::isSubmit('paypal_express')));
Configuration::updateValue('PAYPAL_DEBUG_MODE', (int)(Tools::isSubmit('paypal_debug')));
Configuration::updateValue('PAYPAL_CAPTURE', (int)(Tools::getValue('paypal_capture')));
Configuration::updateValue('PAYPAL_PAYMENT_METHOD', (int)(Tools::getValue('payment_method')));
Configuration::updateValue('PAYPAL_TEMPLATE', Tools::getValue('template_paypal'));
if (Tools::getValue('payment_method') == _PAYPAL_INTEGRAL_EVOLUTION_)
$method = 'Paypal Integrale Evolution';
elseif (Tools::getValue('payment_method') == _PAYPAL_INTEGRAL_)
$method = 'Paypal Integrale';
elseif (Tools::getValue('payment_method') == _PAYPAL_OPTION_PLUS_)
$method = 'Paypal Integrale';
else
$method = '';
$this->_html = $this->displayConfirmation($this->l('Settings updated').'<img src="http://www.prestashop.com/modules/paypal.png?email='.urlencode(Tools::getValue('email_paypal')).'&mode='.(Tools::getValue('sandbox_mode') ? 0 : 1).'&method='.urlencode($method).'" style="float:right" />');
}
else
{
$error_msg = '';
foreach ($this->_errors AS $error)
$error_msg .= $error.'<br />';
$this->_html = $this->displayError($error_msg);
}
}
if (Tools::isSubmit('submitPayPalValidation'))
{
if (!($response = $this->_updatePaymentStatusOfOrder((int)(Tools::getValue('id_order')))) OR !sizeof($response))
$this->_html .= '<p style="color:red;">'.$this->l('Error obtaining payment status.').'</p>';
else
{
if ($response['ACK'] == 'Success')
{
if ($response['PAYMENTSTATUS'] == 'Completed' OR $response['PAYMENTSTATUS'] == 'Reversed' OR ($response['PAYMENTSTATUS'] == 'Pending' AND $response['PENDINGREASON'] == 'authorization'))
Tools::redirectAdmin(AdminTab::$currentIndex.'&id_order='.(int)(Tools::getValue('id_order')).'&vieworder&paypal=validationOk&token='.Tools::getAdminToken('AdminOrders'.(int)(Tab::getIdFromClassName('AdminOrders')).(int)$this->context->employee->id));
else
$this->_html .= '<p><b>'.$this->l('Status').':</b> '.$response['PAYMENTSTATUS'].' ('.$this->l('Reason:').' '.$response['PENDINGREASON'].')</p>';
}
else
$this->_html .= '<p style="color:red;">'.$this->l('Error from PayPal: ').$response['L_LONGMESSAGE0'].' (#'.$response['L_ERRORCODE0'].')</p>';
}
}
if (Tools::isSubmit('submitPayPalCapture'))
{
if (!($response = $this->_doCapture((int)(Tools::getValue('id_order')))) OR !sizeof($response))
$this->_html .= '<p style="color:red;">'.$this->l('Error when making capture request').'</p>';
else
{
if ($response['ACK'] == 'Success')
{
if ($response['PAYMENTSTATUS'] == 'Completed')
Tools::redirectAdmin(AdminTab::$currentIndex.'&id_order='.(int)(Tools::getValue('id_order')).'&vieworder&paypal=captureOk&token='.Tools::getAdminToken('AdminOrders'.(int)(Tab::getIdFromClassName('AdminOrders')).(int)$this->context->employee->id));
else
Tools::redirectAdmin(AdminTab::$currentIndex.'&id_order='.(int)(Tools::getValue('id_order')).'&vieworder&paypal=captureError&token='.Tools::getAdminToken('AdminOrders'.(int)(Tab::getIdFromClassName('AdminOrders')).(int)$this->context->employee->id));
}
else
$this->_html .= '<p style="color:red;">'.$this->l('Error from PayPal: ').$response['L_LONGMESSAGE0'].' (#'.$response['L_ERRORCODE0'].')</p>';
}
}
if (Tools::isSubmit('submitPayPalRefund'))
{
if (!($response = $this->_doTotalRefund((int)(Tools::getValue('id_order')))) OR !sizeof($response))
$this->_html .= '<p style="color:red;">'.$this->l('Error when making refund request').'</p>';
else
{
if ($response['ACK'] == 'Success')
{
if ($response['REFUNDTRANSACTIONID'] != '')
Tools::redirectAdmin(AdminTab::$currentIndex.'&id_order='.(int)(Tools::getValue('id_order')).'&vieworder&paypal=refundOk&token='.Tools::getAdminToken('AdminOrders'.(int)(Tab::getIdFromClassName('AdminOrders')).(int)$this->context->employee->id));
else
Tools::redirectAdmin(AdminTab::$currentIndex.'&id_order='.(int)(Tools::getValue('id_order')).'&vieworder&paypal=refundError&token='.Tools::getAdminToken('AdminOrders'.(int)(Tab::getIdFromClassName('AdminOrders')).(int)$this->context->employee->id));
}
else
$this->_html .= '<p style="color:red;">'.$this->l('Error from PayPal: ').$response['L_LONGMESSAGE0'].' (#'.$response['L_ERRORCODE0'].')</p>';
}
}
}
private function _getTransactionId($id_order)
{
if (!(int)$id_order)
return false;
return Db::getInstance()->getValue('
SELECT `id_transaction`
FROM `'._DB_PREFIX_.'paypal_order`
WHERE `id_order` = '.(int)$id_order);
}
private function _makeRefund($id_transaction, $id_order, $amt = false)
{
include_once(_PS_MODULE_DIR_.'paypal/api/paypallib.php');
if (!$this->_isPayPalAPIAvailable())
die(Tools::displayError('Fatal Error: no API Credentials are available'));
if (!$id_transaction)
die(Tools::displayError('Fatal Error: id_transaction is null'));
if (!$amt)
$request = '&TRANSACTIONID='.urlencode($id_transaction).'&REFUNDTYPE=Full';
else
{
$isoCurrency = Db::getInstance()->getValue('
SELECT `iso_code`
FROM `'._DB_PREFIX_.'orders` o
LEFT JOIN `'._DB_PREFIX_.'currency` c ON (o.`id_currency` = c.`id_currency`)
WHERE o.`id_order` = '.(int)$id_order);
$request = '&TRANSACTIONID='.urlencode($id_transaction).'&REFUNDTYPE=Partial&AMT='.(float)($amt).'&CURRENCYCODE='.urlencode(strtoupper($isoCurrency));
}
$paypalLib = new PaypalLib();
return $paypalLib->makeCall($this->getAPIURL(), $this->getAPIScript(), 'RefundTransaction', $request);
}
private function _addNewPrivateMessage($id_order, $message)
{
if (!$id_order)
return false;
$msg = new Message();
$message = strip_tags($message, '<br>');
if (!Validate::isCleanHtml($message))
$message = $this->l('Payment message is not valid, please check your module.');
$msg->message = $message;
$msg->id_order = (int)($id_order);
$msg->private = 1;
return $msg->add();
}
private function _doTotalRefund($id_order)
{
if (!$this->_isPayPalAPIAvailable())
return false;
if (!$id_order)
return false;
$id_transaction = $this->_getTransactionId((int)($id_order));
if (!$id_transaction)
return false;
$order = new Order((int)($id_order));
if (!Validate::isLoadedObject($order))
return false;
$products = $order->getProducts();
// Amount for refund
$amt = 0.00;
foreach ($products AS $product)
$amt += (float)($product['product_price_wt']) * ($product['product_quantity'] - $product['product_quantity_refunded']);
$amt += (float)($order->total_shipping) + (float)($order->total_wrapping) - (float)($order->total_discounts);
// check if total or partial
if ($this->PayPalRound($order->total_paid_real) == $this->PayPalRound($amt))
$response = $this->_makeRefund($id_transaction, $id_order);
else
$response = $this->_makeRefund($id_transaction, $id_order, (float)($amt));
$message = $this->l('Refund operation result:').'<br>';
foreach ($response AS $k => $value)
$message .= $k.': '.$value.'<br>';
if (array_key_exists('ACK', $response) AND $response['ACK'] == 'Success' AND $response['REFUNDTRANSACTIONID'] != '')
{
$message .= $this->l('PayPal refund successful!');
if (!Db::getInstance()->execute('UPDATE `'._DB_PREFIX_.'paypal_order` SET `payment_status` = \'Refunded\' WHERE `id_order` = '.(int)($id_order)))
die(Tools::displayError('Error when updating PayPal database'));
$history = new OrderHistory();
$history->id_order = (int)($id_order);
$history->changeIdOrderState(Configuration::get('PS_OS_REFUND'), (int)($id_order));
$history->addWithemail();
}
else
$message .= $this->l('Transaction error!');
$this->_addNewPrivateMessage((int)($id_order), $message);
return $response;
}
private function _doCapture($id_order)
{
include_once(_PS_MODULE_DIR_.'paypal/api/paypallib.php');
if (!$this->_isPayPalAPIAvailable())
return false;
if (!$id_order)
return false;
$id_transaction = $this->_getTransactionId((int)($id_order));
if (!$id_transaction)
return false;
$order = new Order((int)($id_order));
$currency = new Currency((int)($order->id_currency));
$request = '&AUTHORIZATIONID='.urlencode($id_transaction).'&AMT='.(float)($order->total_paid).'&CURRENCYCODE='.$currency->iso_code.'&COMPLETETYPE=Complete';
$paypalLib = new PaypalLib();
$response = $paypalLib->makeCall($this->getAPIURL(), $this->getAPIScript(), 'DoCapture', $request);
$message = $this->l('Capture operation result:').'<br>';
foreach ($response AS $k => $value)
$message .= $k.': '.$value.'<br>';
if (array_key_exists('ACK', $response) AND $response['ACK'] == 'Success' AND $response['PAYMENTSTATUS'] == 'Completed')
{
$history = new OrderHistory();
$history->id_order = (int)($id_order);
$history->changeIdOrderState(Configuration::get('PS_OS_PAYMENT'), (int)$id_order);
$history->addWithemail();
$message .= $this->l('Order finished with PayPal!');
}
elseif (isset($response['PAYMENTSTATUS']))
$message .= $this->l('Transaction error!');
if (!Db::getInstance()->execute('UPDATE `'._DB_PREFIX_.'paypal_order` SET `capture` = 0, `payment_status` = \''.pSQL($response['PAYMENTSTATUS']).'\', `id_transaction` = \''.pSQL($response['TRANSACTIONID']).'\' WHERE `id_order` = '.(int)$id_order))
die(Tools::displayError('Error when updating PayPal database'));
$this->_addNewPrivateMessage((int)($id_order), $message);
return $response;
}
private function _updatePaymentStatusOfOrder($id_order)
{
include_once(_PS_MODULE_DIR_.'paypal/api/paypallib.php');
if (!$this->_isPayPalAPIAvailable())
return false;
if (!$id_order)
return false;
$id_transaction = $this->_getTransactionId((int)($id_order));
if (!$id_transaction)
return false;
$request = '&TRANSACTIONID='.urlencode($id_transaction);
$paypalLib = new PaypalLib();
$response = $paypalLib->makeCall($this->getAPIURL(), $this->getAPIScript(), 'GetTransactionDetails', $request);
if (array_key_exists('ACK', $response))
{
if ($response['ACK'] == 'Success')
{
if (isset($response['PAYMENTSTATUS']))
{
if ($response['PAYMENTSTATUS'] == 'Completed')
{
$history = new OrderHistory();
$history->id_order = (int)($id_order);
$history->changeIdOrderState(Configuration::get('PS_OS_PAYMENT'), (int)($id_order));
$history->addWithemail();
}
elseif ($response['PAYMENTSTATUS'] == 'Pending' AND $response['PENDINGREASON'] == 'authorization')
{
$history = new OrderHistory();
$history->id_order = (int)($id_order);
$history->changeIdOrderState((int)(Configuration::get('PAYPAL_OS_AUTHORIZATION')), (int)($id_order));
$history->addWithemail();
}
elseif ($response['PAYMENTSTATUS'] == 'Reversed')
{
$history = new OrderHistory();
$history->id_order = (int)($id_order);
$history->changeIdOrderState(Configuration::get('PS_OS_ERROR'), (int)($id_order));
$history->addWithemail();
}
if (!Db::getInstance()->execute('UPDATE `'._DB_PREFIX_.'paypal_order` SET `payment_status` = \''.pSQL($response['PAYMENTSTATUS']).($response['PENDINGREASON'] == 'authorization' ? '_authorization' : '').'\' WHERE `id_order` = '.(int)$id_order))
die(Tools::displayError('Error when updating PayPal database'));
}
}
$message = $this->l('Verification status:').'<br>';
foreach ($response AS $k => $value)
$message .= $k.': '.$value.'<br>';
$this->_addNewPrivateMessage((int)$id_order, $message);
return $response;
}
return false;
}
private function _isPayPalAPIAvailable()
{
if (Configuration::get('PAYPAL_API_USER') != NULL AND Configuration::get('PAYPAL_API_PASSWORD') != NULL AND Configuration::get('PAYPAL_API_SIGNATURE') != NULL)
return true;
return false;
}
private function _checkAndUpdateFromOldVersion($install = false)
{
if (!Configuration::get('PAYPAL_NEW') AND ($this->active OR $install))
{
$ok = true;
/* Check PayPal API */
if (file_exists(_PS_ROOT_DIR_.'/modules/paypalapi/paypalapi.php'))
{
$confs = Configuration::getMultiple(array('PAYPAL_HEADER', 'PAYPAL_SANDBOX', 'PAYPAL_API_USER', 'PAYPAL_API_PASSWORD', 'PAYPAL_API_SIGNATURE', 'PAYPAL_EXPRESS_CHECKOUT'));
include_once(_PS_ROOT_DIR_.'/modules/paypalapi/paypalapi.php');
$paypalapi = new PayPalAPI();
if ($paypalapi->active)
{
if (Configuration::get('PAYPAL_INTEGRAL') == 1)
Configuration::updateValue('PAYPAL_PAYMENT_METHOD', _PAYPAL_INTEGRAL_);
elseif (Configuration::get('PAYPAL_INTEGRAL') == 0)
Configuration::updateValue('PAYPAL_PAYMENT_METHOD', _PAYPAL_OPTION_PLUS_);
$paypalapi->uninstall();
Configuration::loadConfiguration();
foreach ($confs AS $key => $value)
Configuration::updateValue($key, $value);
}
}
/* Create Table */
if (!Db::getInstance()->execute('
CREATE TABLE IF NOT EXISTS `'._DB_PREFIX_.'paypal_order` (
`id_order` int(10) unsigned NOT NULL auto_increment,
`id_transaction` varchar(255) NOT NULL,
PRIMARY KEY (`id_order`)
) ENGINE='._MYSQL_ENGINE_.' DEFAULT CHARSET=utf8'))
$ok = false;
if (!Db::getInstance()->execute('
ALTER TABLE `'._DB_PREFIX_.'paypal_order` ADD `payment_method` INT NOT NULL,
ADD `payment_status` VARCHAR(255) NOT NULL,
ADD `capture` INT NOT NULL'))
$ok = false;
/* Hook */
$this->registerHook('cancelProduct');
$this->registerHook('adminOrder');
/* Create OrderState */
if (!Configuration::get('PAYPAL_OS_AUTHORIZATION'))
{
$orderState = new OrderState();
$orderState->name = array();
foreach (Language::getLanguages() AS $language)
{
if (strtolower($language['iso_code']) == 'fr')
$orderState->name[$language['id_lang']] = 'Autorisation acceptée par PayPal';
else
$orderState->name[$language['id_lang']] = 'Authorization accepted from PayPal';
}
$orderState->send_email = false;
$orderState->color = '#DDEEFF';
$orderState->hidden = false;
$orderState->delivery = false;
$orderState->logable = true;
$orderState->invoice = true;
if ($orderState->add())
@copy(_PS_ROOT_DIR_.'/img/os/'.Configuration::get('PS_OS_PAYPAL').'.gif', _PS_ROOT_DIR_.'/img/os/'.(int)($orderState->id).'.gif');
Configuration::updateValue('PAYPAL_OS_AUTHORIZATION', (int)($orderState->id));
}
/* Delete unseless configuration */
Configuration::deleteByName('PAYPAL_INTEGRAL');
/* Add new Configurations */
if (!Configuration::get('PAYPAL_PAYMENT_METHOD'))
Configuration::updateValue('PAYPAL_PAYMENT_METHOD', _PAYPAL_INTEGRAL_);
Configuration::updateValue('PAYPAL_CAPTURE', 0);
Configuration::updateValue('PAYPAL_TEMPLATE', 'A');
if ($ok)
Configuration::updateValue('PAYPAL_NEW', 1);
return $ok;
}
return false;
}
public function getOrder($id_transaction)
{
return Db::getInstance()->getValue('
SELECT `id_order`
FROM `'._DB_PREFIX_.'paypal_order`
WHERE `id_transaction` = \''.pSQL($id_transaction).'\'');
}
}