* @copyright 2007-2011 PrestaShop SA
* @version Release: $Revision: 7769 $
* @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0)
* International Registered Trademark & Property of PrestaShop SA
*/
if (!defined('_CAN_LOAD_FILES_'))
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.6';
$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.');
global $cookie;
$context = stream_context_create(array('http' => array('method'=>"GET", 'timeout' => 5)));
$content = @file_get_contents('https://www.prestashop.com/partner/preactivation/preactivation-warnings.php?version=1.0&partner=paypal&iso_country='.Tools::strtolower(Country::getIsoById(Configuration::get('PS_COUNTRY_DEFAULT'))).'&iso_lang='.Tools::strtolower(Language::getIsoById(intval($cookie->id_lang))).'&id_lang='.(int)$cookie->id_lang.'&email='.urlencode(Configuration::get('PS_SHOP_EMAIL')).'&security='.md5(Configuration::get('PS_SHOP_EMAIL')._COOKIE_IV_), false, $context);
$content = explode('|', $content);
if ($content[0] == 'OK')
{
if (!empty($this->warning))
$this->warning .= ', ';
$this->warning .= $content[1];
}
}
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);
}
/* For 1.4.3 and less compatibility */
$updateConfig = array('PS_OS_CHEQUE', 'PS_OS_PAYMENT', 'PS_OS_PREPARATION', 'PS_OS_SHIPPING', 'PS_OS_CANCELED', 'PS_OS_REFUND', 'PS_OS_ERROR', 'PS_OS_OUTOFSTOCK', 'PS_OS_BANKWIRE', 'PS_OS_PAYPAL', 'PS_OS_WS_PAYMENT');
foreach ($updateConfig as $u)
if (!Configuration::get($u) && defined('_'.$u.'_'))
Configuration::updateValue($u, constant('_'.$u.'_'));
/* 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 .= '
'.$this->l('PayPal').'
';
$this->_postProcess();
$this->_setPayPalSubscription();
if (file_exists(_PS_ROOT_DIR_.'/modules/paypalapi/paypalapi.php'))
$this->_html .= '
'.$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.').'
';
$this->_setConfigurationForm();
return $this->_html;
}
public function hookPayment($params)
{
global $smarty;
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())
{
$smarty->assign('integral', (Configuration::get('PAYPAL_PAYMENT_METHOD') == 0 ? 1 : 0));
$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)
{
global $cookie, $smarty;
if (!$this->active)
return ;
if (Configuration::get('PAYPAL_EXPRESS_CHECKOUT') AND !$cookie->isLogged(true) AND $this->_isPayPalAPIAvailable())
{
$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)
{
global $smarty, $cookie;
$smarty->assign('iso_code', Tools::strtolower(Language::getIsoById($cookie->id_lang ? (int)($cookie->id_lang) : 1)));
$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())
{
global $cookie;
if ($params['module'] != $this->name)
return false;
if (!$token = $cookie->paypal_token)
return false;
if (!$payerID = $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 .= '
'.$message.'
';
}
if ($this->_needValidation((int)$params['id_order']) AND $this->_isPayPalAPIAvailable())
{
$this->_html .= '
';
}
if ($this->_needCapture((int)$params['id_order']) AND $this->_isPayPalAPIAvailable())
{
$this->_html .= '
';
}
if ($this->_canRefund((int)$params['id_order']) AND $this->_isPayPalAPIAvailable())
{
$this->_html .= '
';
}
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, (float)($amt));
$message = $this->l('Cancel products result:').' ';
foreach ($response AS $k => $value)
$message .= $k.': '.$value.' ';
$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)
{
global $cookie;
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[] = ''.$ppExpress->l('Token given by PayPal is not the same as the cookie token', 'submit').'';
$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::redirectLink(__PS_BASE_URI__.'order-confirmation.php?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)
{
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)
{
global $cookie;
if ($ppExpress)
{
$iso_code = Tools::strtoupper(Language::getIsoById($cookie->id_lang ? (int)$cookie->id_lang : 1));
$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()
{
global $cookie;
$cart = new Cart((int)$cookie->id_cart);
$address = new Address((int)$cart->id_address_invoice);
$country = new Country((int)$address->id_country);
return $country->iso_code;
}
public function displayPayPalAPIError($message, $log = false)
{
global $cookie, $smarty;
$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');
$smarty->assign('message', $message);
$smarty->assign('logs', $log);
$data = array('{logs}' => implode(' ', $log));
if ($send)
Mail::Send((int)($cookie->id_lang), '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 .= '
';
}
private function _getSolutionTabHtml()
{
global $cookie;
$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 = new Language((int)$cookie->id_lang);
if (strtolower($lang->iso_code) == 'es')
$link = 'http://altfarm.mediaplex.com/ad/ck/3484-34334-12439-1';
elseif (strtolower($lang->iso_code) == 'it')
$link = 'https://www.paypal-business.it/paypalpro.asp';
return '
'.$this->l('Solution').'
'.$this->l('Choose a solution:').'
* '.$this->l('(PayPal Integral Evolution, monthly subscription)').'
'.$this->l('When opening your PayPal account by clicking on the following image, you are helping us significantly to improve the PrestaShop software:').'
'.$this->l('This module allows you to accept payments by PayPal.').'
'.$this->l('If the client chooses this payment mode, your PayPal account will be automatically credited.').'
'.$this->l('You need to configure your PayPal account before using this module.').'
';
}
private function _postProcess()
{
global $currentIndex, $cookie;
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', 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_MODE_DEBUG', (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').'');
}
else
{
$error_msg = '';
foreach ($this->_errors AS $error)
$error_msg .= $error.' ';
$this->_html = $this->displayError($error_msg);
}
}
if (Tools::isSubmit('submitPayPalValidation'))
{
if (!($response = $this->_updatePaymentStatusOfOrder((int)(Tools::getValue('id_order')))) OR !sizeof($response))
$this->_html .= '
'.$this->l('Error obtaining payment status.').'
';
else
{
if ($response['ACK'] == 'Success')
{
if ($response['PAYMENTSTATUS'] == 'Completed' OR $response['PAYMENTSTATUS'] == 'Reversed' OR ($response['PAYMENTSTATUS'] == 'Pending' AND $response['PENDINGREASON'] == 'authorization'))
Tools::redirectAdmin($currentIndex.'&id_order='.(int)(Tools::getValue('id_order')).'&vieworder&paypal=validationOk&token='.Tools::getAdminToken('AdminOrders'.(int)(Tab::getIdFromClassName('AdminOrders')).(int)($cookie->id_employee)));
else
$this->_html .= '
'.$this->l('Error from PayPal: ').$response['L_LONGMESSAGE0'].' (#'.$response['L_ERRORCODE0'].')
';
}
}
if (Tools::isSubmit('submitPayPalCapture'))
{
if (!($response = $this->_doCapture((int)(Tools::getValue('id_order')))) OR !sizeof($response))
$this->_html .= '
'.$this->l('Error when making capture request').'
';
else
{
if ($response['ACK'] == 'Success')
{
if ($response['PAYMENTSTATUS'] == 'Completed')
Tools::redirectAdmin($currentIndex.'&id_order='.(int)(Tools::getValue('id_order')).'&vieworder&paypal=captureOk&token='.Tools::getAdminToken('AdminOrders'.(int)(Tab::getIdFromClassName('AdminOrders')).(int)($cookie->id_employee)));
else
Tools::redirectAdmin($currentIndex.'&id_order='.(int)(Tools::getValue('id_order')).'&vieworder&paypal=captureError&token='.Tools::getAdminToken('AdminOrders'.(int)(Tab::getIdFromClassName('AdminOrders')).(int)($cookie->id_employee)));
}
else
$this->_html .= '
'.$this->l('Error from PayPal: ').$response['L_LONGMESSAGE0'].' (#'.$response['L_ERRORCODE0'].')
';
}
}
if (Tools::isSubmit('submitPayPalRefund'))
{
if (!($response = $this->_doTotalRefund((int)(Tools::getValue('id_order')))) OR !sizeof($response))
$this->_html .= '
'.$this->l('Error when making refund request').'
';
else
{
if ($response['ACK'] == 'Success')
{
if ($response['REFUNDTRANSACTIONID'] != '')
Tools::redirectAdmin($currentIndex.'&id_order='.(int)(Tools::getValue('id_order')).'&vieworder&paypal=refundOk&token='.Tools::getAdminToken('AdminOrders'.(int)(Tab::getIdFromClassName('AdminOrders')).(int)($cookie->id_employee)));
else
Tools::redirectAdmin($currentIndex.'&id_order='.(int)(Tools::getValue('id_order')).'&vieworder&paypal=refundError&token='.Tools::getAdminToken('AdminOrders'.(int)(Tab::getIdFromClassName('AdminOrders')).(int)($cookie->id_employee)));
}
else
$this->_html .= '
'.$this->l('Error from PayPal: ').$response['L_LONGMESSAGE0'].' (#'.$response['L_ERRORCODE0'].')
';
}
}
}
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, $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`)');
$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, ' ');
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)
{
global $cookie;
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)
if ($product['product_quantity_refunded'] == 0)
$amt += (float)($product['total_price']);
$amt += (float)($order->total_shipping);
// check if total or partial
if ($order->total_products_wt == $amt)
$response = $this->_makeRefund($id_transaction);
else
$response = $this->_makeRefund($id_transaction, (float)($amt));
$message = $this->l('Refund operation result:').' ';
foreach ($response AS $k => $value)
$message .= $k.': '.$value.' ';
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)
{
global $cookie;
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:').' ';
foreach ($response AS $k => $value)
$message .= $k.': '.$value.' ';
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)
{
global $cookie;
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:').' ';
foreach ($response AS $k => $value)
$message .= $k.': '.$value.' ';
$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');
/* For 1.4.3 and less compatibility */
$updateConfig = array('PS_OS_CHEQUE', 'PS_OS_PAYMENT', 'PS_OS_PREPARATION', 'PS_OS_SHIPPING', 'PS_OS_CANCELED', 'PS_OS_REFUND', 'PS_OS_ERROR', 'PS_OS_OUTOFSTOCK', 'PS_OS_BANKWIRE', 'PS_OS_PAYPAL', 'PS_OS_WS_PAYMENT');
foreach ($updateConfig as $u)
if (!Configuration::get($u) && defined('_'.$u.'_'))
Configuration::updateValue($u, constant('_'.$u.'_'));
/* 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).'\'');
}
}