Files
PrestaShop/modules/paypal/paypal.php
T
2011-11-21 11:06:35 +00:00

1344 lines
58 KiB
PHP

<?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.5';
$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, PayPal::BOTH));
$paymentType = Configuration::get('PAYPAL_CAPTURE') == 1 ? 'Authorization' : 'Sale';
$serverName = urlencode($_SERVER['SERVER_NAME']);
$bn = ($type == 'express' ? 'ECS' : 'ECM');
$notifyURL = urlencode(PayPal::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, PayPal::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, PayPal::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;
// Set transaction details if pcc is defiend in PaymentModule class_exists
if ($this->pcc)
{
$this->pcc->transaction_id = (isset($extraVars['transaction_id']) ?
$extraVars['transaction_id'] : '');
}
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').'</h4>
'.$this->_getSolutionTabHtml().'
</div>
<div class="tab-page" id="step2">
<h4 class="tab">'.$this->l('Settings').'</h4>
'.$this->_getSettingsTabHtml().'
</div>
<div class="tab-page" id="step3">
<h4 class="tab">'.$this->l('Logos and personalization').'</h4>
'.$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(AdminController::$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(AdminController::$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(AdminController::$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(AdminController::$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(AdminController::$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).'\'');
}
// Retrocompatibility to 1.3
const ONLY_PRODUCTS = 1;
const ONLY_DISCOUNTS = 2;
const BOTH = 3;
const BOTH_WITHOUT_SHIPPING = 4;
const ONLY_SHIPPING = 5;
const ONLY_WRAPPING = 6;
const ONLY_PRODUCTS_WITHOUT_SHIPPING = 7;
/**
* getShopDomain returns domain name according to configuration and ignoring ssl
*
* @param boolean $http if true, return domain name with protocol
* @param boolean $entities if true,
* @return string domain
*/
public static function getShopDomain($http = false, $entities = false)
{
if (!($domain = Configuration::get('PS_SHOP_DOMAIN')))
$domain = Tools::getHttpHost();
if ($entities)
$domain = htmlspecialchars($domain, ENT_COMPAT, 'UTF-8');
if ($http)
$domain = 'http://'.$domain;
return $domain;
}
/**
* getShopDomainSsl returns domain name according to configuration and depending on ssl activation
*
* @param boolean $http if true, return domain name with protocol
* @param boolean $entities if true,
* @return string domain
*/
public static function getShopDomainSsl($http = false, $entities = false)
{
if (!($domain = Configuration::get('PS_SHOP_DOMAIN_SSL')))
$domain = Tools::getHttpHost();
if ($entities)
$domain = htmlspecialchars($domain, ENT_COMPAT, 'UTF-8');
if ($http)
$domain = (Configuration::get('PS_SSL_ENABLED') ? 'https://' : 'http://').$domain;
return $domain;
}
public static function display($file, $template, $cacheId = NULL, $compileId = NULL)
{
if (substr(_PS_VERSION_, 0, 3) != '1.3')
return parent::display($file, $template);
global $smarty;
$previousTemplate = $smarty->currentTemplate;
$smarty->currentTemplate = substr(basename($template), 0, -4);
$smarty->assign('module_dir', __PS_BASE_URI__.'modules/'.basename($file, '.php').'/');
if (Tools::file_exists_cache(_PS_THEME_DIR_.'modules/'.basename($file, '.php').'/'.$template))
{
$smarty->assign('module_template_dir', _THEME_DIR_.'modules/'.basename($file, '.php').'/');
$result = $smarty->fetch(_PS_THEME_DIR_.'modules/'.basename($file, '.php').'/'.$template);
}
elseif (Tools::file_exists_cache(dirname(__FILE__).'/'.$template))
{
$smarty->assign('module_template_dir', __PS_BASE_URI__.'modules/'.basename($file, '.php').'/');
$result = $smarty->fetch(dirname(__FILE__).'/'.$template);
}
else
$result = Tools::displayError('No template found');
$smarty->currentTemplate = $previousTemplate;
return $result;
}
}