PageRenderTime 65ms CodeModel.GetById 28ms RepoModel.GetById 1ms app.codeStats 1ms

/includes/modules/payment/paypalwpp.php

https://github.com/happyxlq/zencart_svn
PHP | 2848 lines | 2011 code | 254 blank | 583 comment | 774 complexity | ac449f49cbcd135a624063dd2c7e4221 MD5 | raw file
Possible License(s): BSD-3-Clause, LGPL-2.1

Large files files are truncated, but you can click here to view the full file

  1. <?php
  2. /**
  3. * paypalwpp.php payment module class for PayPal Express Checkout payment method
  4. *
  5. * @package paymentMethod
  6. * @copyright Copyright 2003-2010 Zen Cart Development Team
  7. * @copyright Portions Copyright 2003 osCommerce
  8. * @license http://www.zen-cart.com/license/2_0.txt GNU Public License V2.0
  9. * @version $Id: paypalwpp.php 16878 2010-07-08 17:03:31Z drbyte $
  10. */
  11. /**
  12. * load the communications layer code
  13. */
  14. require_once(DIR_FS_CATALOG . DIR_WS_MODULES . 'payment/paypal/paypal_curl.php');
  15. /**
  16. * the PayPal payment module with Express Checkout
  17. */
  18. class paypalwpp extends base {
  19. /**
  20. * name of this module
  21. *
  22. * @var string
  23. */
  24. var $code;
  25. /**
  26. * displayed module title
  27. *
  28. * @var string
  29. */
  30. var $title;
  31. /**
  32. * displayed module description
  33. *
  34. * @var string
  35. */
  36. var $description;
  37. /**
  38. * module status - set based on various config and zone criteria
  39. *
  40. * @var string
  41. */
  42. var $enabled;
  43. /**
  44. * the zone to which this module is restricted for use
  45. *
  46. * @var string
  47. */
  48. var $zone;
  49. /**
  50. * debugging flag
  51. *
  52. * @var boolean
  53. */
  54. var $enableDebugging = false;
  55. /**
  56. * Determines whether payment page is displayed or not
  57. *
  58. * @var boolean
  59. */
  60. var $showPaymentPage = false;
  61. var $flagDisablePaymentAddressChange = false;
  62. /**
  63. * sort order of display
  64. *
  65. * @var int
  66. */
  67. var $sort_order = 0;
  68. /**
  69. * Button Source / BN code -- enables the module to work for Zen Cart
  70. *
  71. * @var string
  72. */
  73. var $buttonSourceEC = 'zhongtuo_cart_ec_c2';
  74. /**
  75. * order status setting for pending orders
  76. *
  77. * @var int
  78. */
  79. var $order_pending_status = 1;
  80. /**
  81. * order status setting for completed orders
  82. *
  83. * @var int
  84. */
  85. var $order_status = DEFAULT_ORDERS_STATUS_ID;
  86. /**
  87. * Debug tools
  88. */
  89. var $_logDir = 'includes/modules/payment/paypal/logs/';
  90. var $_logLevel = 0;
  91. /**
  92. * FMF
  93. */
  94. var $fmfResponse = '';
  95. var $fmfErrors = array();
  96. /**
  97. * class constructor
  98. */
  99. function paypalwpp() {
  100. include_once(zen_get_file_directory(DIR_FS_CATALOG . DIR_WS_LANGUAGES . $_SESSION['language'] . '/modules/payment/', 'paypalwpp.php', 'false'));
  101. global $order;
  102. $this->code = 'paypalwpp';
  103. $this->codeTitle = MODULE_PAYMENT_PAYPALWPP_TEXT_ADMIN_TITLE_EC;
  104. $this->codeVersion = '1.3.9e';
  105. $this->enableDirectPayment = FALSE;
  106. $this->enabled = (MODULE_PAYMENT_PAYPALWPP_STATUS == 'True');
  107. // Set the title & description text based on the mode we're in ... EC vs US/UK vs admin
  108. if (IS_ADMIN_FLAG === true) {
  109. $this->description = sprintf(MODULE_PAYMENT_PAYPALWPP_TEXT_ADMIN_DESCRIPTION, ' (rev' . $this->codeVersion . ')');
  110. switch (MODULE_PAYMENT_PAYPALWPP_MODULE_MODE) {
  111. case ('PayPal'):
  112. $this->title = MODULE_PAYMENT_PAYPALWPP_TEXT_ADMIN_TITLE_EC;
  113. break;
  114. case ('Payflow-UK'):
  115. $this->title = MODULE_PAYMENT_PAYPALWPP_TEXT_ADMIN_TITLE_PRO20;
  116. break;
  117. case ('Payflow-US'):
  118. if (defined('MODULE_PAYMENT_PAYPALWPP_PAYFLOW_EC') && MODULE_PAYMENT_PAYPALWPP_PAYFLOW_EC == 'Yes') {
  119. $this->title = MODULE_PAYMENT_PAYPALWPP_TEXT_ADMIN_TITLE_PF_EC;
  120. } else {
  121. $this->title = MODULE_PAYMENT_PAYPALWPP_TEXT_ADMIN_TITLE_PF_GATEWAY;
  122. }
  123. break;
  124. default:
  125. $this->title = MODULE_PAYMENT_PAYPALWPP_TEXT_ADMIN_TITLE_EC;
  126. }
  127. if ($this->enabled) {
  128. if ( (MODULE_PAYMENT_PAYPALWPP_MODULE_MODE == 'PayPal' && (MODULE_PAYMENT_PAYPALWPP_APISIGNATURE == '' || MODULE_PAYMENT_PAYPALWPP_APIUSERNAME == '' || MODULE_PAYMENT_PAYPALWPP_APIPASSWORD == ''))
  129. || (substr(MODULE_PAYMENT_PAYPALWPP_MODULE_MODE,0,7) == 'Payflow' && (MODULE_PAYMENT_PAYPALWPP_PFPARTNER == '' || MODULE_PAYMENT_PAYPALWPP_PFVENDOR == '' || MODULE_PAYMENT_PAYPALWPP_PFUSER == '' || MODULE_PAYMENT_PAYPALWPP_PFPASSWORD == ''))
  130. ) $this->title .= '<span class="alert"><strong> NOT CONFIGURED YET</strong></span>';
  131. if (MODULE_PAYMENT_PAYPALWPP_SERVER =='sandbox') $this->title .= '<strong><span class="alert"> (sandbox active)</span></strong>';
  132. if (MODULE_PAYMENT_PAYPALWPP_DEBUGGING =='Log File' || MODULE_PAYMENT_PAYPALWPP_DEBUGGING =='Log and Email') $this->title .= '<strong> (Debug)</strong>';
  133. if (!function_exists('curl_init')) $this->title .= '<strong><span class="alert"> CURL NOT FOUND. Cannot Use.</span></strong>';
  134. }
  135. } else {
  136. $this->description = MODULE_PAYMENT_PAYPALWPP_TEXT_DESCRIPTION;
  137. $this->title = MODULE_PAYMENT_PAYPALWPP_EC_TEXT_TITLE; //pp
  138. }
  139. if ((!defined('PAYPAL_OVERRIDE_CURL_WARNING') || (defined('PAYPAL_OVERRIDE_CURL_WARNING') && PAYPAL_OVERRIDE_CURL_WARNING != 'True')) && !function_exists('curl_init')) $this->enabled = false;
  140. $this->enableDebugging = (MODULE_PAYMENT_PAYPALWPP_DEBUGGING == 'Log File' || MODULE_PAYMENT_PAYPALWPP_DEBUGGING =='Log and Email');
  141. $this->emailAlerts = (MODULE_PAYMENT_PAYPALWPP_DEBUGGING == 'Log File' || MODULE_PAYMENT_PAYPALWPP_DEBUGGING =='Log and Email' || MODULE_PAYMENT_PAYPALWPP_DEBUGGING == 'Alerts Only');
  142. $this->doDPonly = (MODULE_PAYMENT_PAYPALWPP_MODULE_MODE =='Payflow-US' && !(defined('MODULE_PAYMENT_PAYPALWPP_PAYFLOW_EC') && MODULE_PAYMENT_PAYPALWPP_PAYFLOW_EC == 'Yes'));
  143. $this->showPaymentPage = (MODULE_PAYMENT_PAYPALWPP_SKIP_PAYMENT_PAGE == 'No') ? true : false;
  144. $this->sort_order = MODULE_PAYMENT_PAYPALWPP_SORT_ORDER;
  145. $this->buttonSourceEC = 'ZenCart-EC_us';
  146. $this->buttonSourceDP = 'ZenCart-DP_us';
  147. if (MODULE_PAYMENT_PAYPALWPP_MODULE_MODE == 'Payflow-UK') {
  148. $this->buttonSourceEC = 'ZenCart-EC_uk';
  149. $this->buttonSourceDP = 'ZenCart-DP_uk';
  150. }
  151. if (MODULE_PAYMENT_PAYPALWPP_MODULE_MODE == 'Payflow-US') {
  152. $this->buttonSourceEC = 'ZenCart-ECGW_us';
  153. $this->buttonSourceDP = 'ZenCart-GW_us';
  154. }
  155. $this->order_pending_status = MODULE_PAYMENT_PAYPALWPP_ORDER_PENDING_STATUS_ID;
  156. if ((int)MODULE_PAYMENT_PAYPALWPP_ORDER_STATUS_ID > 0) {
  157. $this->order_status = MODULE_PAYMENT_PAYPALWPP_ORDER_STATUS_ID;
  158. }
  159. $this->new_acct_notify = MODULE_PAYMENT_PAYPALWPP_NEW_ACCT_NOTIFY;
  160. $this->zone = (int)MODULE_PAYMENT_PAYPALWPP_ZONE;
  161. if (is_object($order)) $this->update_status();
  162. if (PROJECT_VERSION_MAJOR != '1' && substr(PROJECT_VERSION_MINOR, 0, 3) != '3.9') $this->enabled = false;
  163. $this->cards = array();
  164. // if operating in markflow mode, start EC process when submitting order
  165. if (!$this->in_special_checkout()) {
  166. $this->form_action_url = zen_href_link('ipn_main_handler.php', 'type=ec&markflow=1&clearSess=1&stage=final', 'SSL', true, true, true);
  167. }
  168. // debug setup
  169. if (!@is_writable($this->_logDir)) $this->_logDir = DIR_FS_CATALOG . $this->_logDir;
  170. if (!@is_writable($this->_logDir)) $this->_logDir = DIR_FS_SQL_CACHE;
  171. // Regular mode:
  172. if ($this->enableDebugging) $this->_logLevel = PEAR_LOG_INFO;
  173. // DEV MODE:
  174. if (defined('PAYPAL_DEV_MODE') && PAYPAL_DEV_MODE == 'true') $this->_logLevel = PEAR_LOG_DEBUG;
  175. if (IS_ADMIN_FLAG === true) $this->tableCheckup();
  176. }
  177. /**
  178. * Sets payment module status based on zone restrictions etc
  179. */
  180. function update_status() {
  181. global $order, $db;
  182. if ($this->enabled && (int)$this->zone > 0) {
  183. $check_flag = false;
  184. $sql = "SELECT zone_id
  185. FROM " . TABLE_ZONES_TO_GEO_ZONES . "
  186. WHERE geo_zone_id = :zoneId
  187. AND zone_country_id = :countryId
  188. ORDER BY zone_id";
  189. $sql = $db->bindVars($sql, ':zoneId', $this->zone, 'integer');
  190. $sql = $db->bindVars($sql, ':countryId', $order->billing['country']['id'], 'integer');
  191. $check = $db->Execute($sql);
  192. while (!$check->EOF) {
  193. if ($check->fields['zone_id'] < 1) {
  194. $check_flag = true;
  195. break;
  196. } elseif ($check->fields['zone_id'] == $order->billing['zone_id']) {
  197. $check_flag = true;
  198. break;
  199. }
  200. $check->MoveNext();
  201. }
  202. if (!$check_flag) {
  203. $this->enabled = false;
  204. }
  205. // module cannot be used for purchase > $10,000 USD
  206. $order_amount = $this->calc_order_amount($order->info['total'], 'USD');
  207. if ($order_amount > 10000) $this->enabled = false;
  208. if ($order->info['total'] == 0) $this->enabled = false;
  209. }
  210. }
  211. /**
  212. * Validate the credit card information via javascript (Number, Owner, and CVV Lengths)
  213. */
  214. function javascript_validation() {
  215. return false;
  216. }
  217. /**
  218. * Display Credit Card Information Submission Fields on the Checkout Payment Page
  219. */
  220. function selection() {
  221. $this->cc_type_check = '';
  222. /**
  223. * since we are NOT processing via the gateway, we will only display MarkFlow payment option, and no CC fields
  224. */
  225. return array('id' => $this->code,
  226. 'module' => '<img src="' . MODULE_PAYMENT_PAYPALEC_MARK_BUTTON_IMG . '" alt="' . MODULE_PAYMENT_PAYPALWPP_TEXT_BUTTON_ALTTEXT . '" /><span style="font-size:11px; font-family: Arial, Verdana;"> ' . MODULE_PAYMENT_PAYPALWPP_MARK_BUTTON_TXT . '</span>');
  227. }
  228. function pre_confirmation_check() {
  229. // Since this is an EC checkout, do nothing.
  230. return false;
  231. }
  232. /**
  233. * Display Payment Information for review on the Checkout Confirmation Page
  234. */
  235. function confirmation() {
  236. $confirmation = array('title' => '', 'fields' => array());
  237. return $confirmation;
  238. }
  239. /**
  240. * Prepare the hidden fields comprising the parameters for the Submit button on the checkout confirmation page
  241. */
  242. function process_button() {
  243. $_SESSION['paypal_ec_markflow'] = 1;
  244. return '';
  245. }
  246. /**
  247. * Prepare and submit the final authorization to PayPal via the appropriate means as configured
  248. */
  249. function before_process() {
  250. global $order, $doPayPal, $messageStack;
  251. $options = array();
  252. $optionsShip = array();
  253. $optionsNVP = array();
  254. $options = $this->getLineItemDetails($this->selectCurrency($order->info['currency']));
  255. //$this->zcLog('before_process - 1', 'Have line-item details:' . "\n" . print_r($options, true));
  256. // Initializing DESC field: using for comments related to tax-included pricing, populated by getLineItemDetails()
  257. $options['DESC'] = '';
  258. $doPayPal = $this->paypal_init();
  259. $this->zcLog('before_process - EC-1', 'Beginning EC mode');
  260. /****************************************
  261. * Do EC checkout
  262. ****************************************/
  263. // do not allow blank address to be sent to PayPal
  264. if ($_SESSION['paypal_ec_payer_info']['ship_street_1'] != '' && strtoupper($_SESSION['paypal_ec_payer_info']['ship_address_status']) != 'NONE') {
  265. $options = array_merge($options,
  266. array('SHIPTONAME' => $_SESSION['paypal_ec_payer_info']['ship_name'],
  267. 'SHIPTOSTREET' => $_SESSION['paypal_ec_payer_info']['ship_street_1'],
  268. 'SHIPTOSTREET2'=> $_SESSION['paypal_ec_payer_info']['ship_street_2'],
  269. 'SHIPTOCITY' => $_SESSION['paypal_ec_payer_info']['ship_city'],
  270. 'SHIPTOSTATE' => $_SESSION['paypal_ec_payer_info']['ship_state'],
  271. 'SHIPTOZIP' => $_SESSION['paypal_ec_payer_info']['ship_postal_code'],
  272. 'SHIPTOCOUNTRYCODE'=> $_SESSION['paypal_ec_payer_info']['ship_country_code'],
  273. ));
  274. $this->zcLog('before_process - EC-2', 'address overrides added:' . "\n" . print_r($options, true));
  275. }
  276. $this->zcLog('before_process - EC-3', 'address info added:' . "\n" . print_r($options, true));
  277. $options['BUTTONSOURCE'] = $this->buttonSourceEC;
  278. // If the customer has changed their shipping address,
  279. // override the shipping address in PayPal with the shipping
  280. // address that is selected in Zen Cart.
  281. if ($order->delivery['street_address'] != $_SESSION['paypal_ec_payer_info']['ship_street_1'] && $_SESSION['paypal_ec_payer_info']['ship_street_1'] != '') {
  282. $_GET['markflow'] = 2;
  283. if (($address_arr = $this->getOverrideAddress()) !== false) {
  284. // set the override var
  285. $options['ADDROVERRIDE'] = 1;
  286. // set the address info
  287. $options['SHIPTONAME'] = $address_arr['entry_firstname'] . ' ' . $address_arr['entry_lastname'];
  288. $options['SHIPTOSTREET'] = $address_arr['entry_street_address'];
  289. if ($address_arr['entry_suburb'] != '') $options['SHIPTOSTREET2'] = $address_arr['entry_suburb'];
  290. $options['SHIPTOCITY'] = $address_arr['entry_city'];
  291. $options['SHIPTOZIP'] = $address_arr['entry_postcode'];
  292. $options['SHIPTOSTATE'] = $address_arr['zone_code'];
  293. $options['SHIPTOCOUNTRYCODE'] = $address_arr['countries_iso_code_2'];
  294. }
  295. }
  296. // if these optional parameters are blank, remove them from transaction
  297. if (isset($options['SHIPTOSTREET2']) && trim($options['SHIPTOSTREET2']) == '') unset($options['SHIPTOSTREET2']);
  298. if (isset($options['SHIPTOPHONE']) && trim($options['SHIPTOPHONE']) == '') unset($options['SHIPTOPHONE']);
  299. // if State is not supplied, repeat the city so that it's not blank, otherwise PayPal croaks
  300. if ((!isset($options['SHIPTOSTATE']) || trim($options['SHIPTOSTATE']) == '') && $options['SHIPTOCITY'] != '') $options['SHIPTOSTATE'] = $options['SHIPTOCITY'];
  301. // FMF support
  302. $options['RETURNFMFDETAILS'] = (MODULE_PAYMENT_PAYPALWPP_EC_RETURN_FMF_DETAILS == 'Yes') ? 1 : 0;
  303. // Add note to track that this was an EC transaction (used in properly handling update IPNs related to EC transactions):
  304. $options['CUSTOM'] = 'EC-' . (int)$_SESSION['customer_id'] . '-' . time();
  305. // send the store name as transaction identifier, to help distinguish payments between multiple stores:
  306. $options['INVNUM'] = (int)$_SESSION['customer_id'] . '-' . time() . '-[' . substr(preg_replace('/[^a-zA-Z0-9_]/', '', STORE_NAME), 0, 30) . ']'; // (cannot send actual invoice number because it's not assigned until after payment is completed)
  307. $options['CURRENCY'] = $this->selectCurrency($order->info['currency']);
  308. $order_amount = $this->calc_order_amount($order->info['total'], $options['CURRENCY'], FALSE);
  309. // debug output
  310. $this->zcLog('before_process - EC-4', 'info being submitted:' . "\n" . $_SESSION['paypal_ec_token'] . ' ' . $_SESSION['paypal_ec_payer_id'] . ' ' . number_format($order_amount, 2) . "\n" . print_r($options, true));
  311. if (isset($options['DESC']) && $options['DESC'] == '') unset($options['DESC']);
  312. if (!isset($options['AMT'])) $options['AMT'] = number_format($order_amount, 2, '.', '');
  313. $response = $doPayPal->DoExpressCheckoutPayment($_SESSION['paypal_ec_token'],
  314. $_SESSION['paypal_ec_payer_id'],
  315. $options);
  316. $this->zcLog('before_process - EC-5', 'resultset:' . "\n" . urldecode(print_r($response, true)));
  317. // CHECK RESPONSE -- if error, actions are taken in the errorHandler
  318. $errorHandlerMessage = $this->_errorHandler($response, 'DoExpressCheckoutPayment');
  319. if ($this->fmfResponse != '') {
  320. $this->order_status = $this->order_pending_status;
  321. }
  322. // SUCCESS
  323. $this->payment_type = MODULE_PAYMENT_PAYPALWPP_EC_TEXT_TYPE;
  324. $this->responsedata = $response;
  325. if ($response['PAYMENTTYPE'] != '') $this->payment_type .= ' (' . urldecode($response['PAYMENTTYPE']) . ')';
  326. $this->transaction_id = trim($response['PNREF'] . ' ' . $response['TRANSACTIONID']);
  327. if (empty($response['PENDINGREASON']) ||
  328. $response['PENDINGREASON'] == 'none' ||
  329. $response['PENDINGREASON'] == 'completed' ||
  330. $response['PAYMENTSTATUS'] == 'Completed') {
  331. $this->payment_status = 'Completed';
  332. if ($this->order_status > 0) $order->info['order_status'] = $this->order_status;
  333. } else {
  334. if ($response['PAYMENTSTATUS'] == 'Pending')
  335. {
  336. if ($response['L_ERRORCODE0'] == 11610 && $response['PENDINGREASON'] == '') $response['PENDINGREASON'] = 'Pending FMF Review by Storeowner';
  337. }
  338. $this->payment_status = 'Pending (' . $response['PENDINGREASON'] . ')';
  339. $order->info['order_status'] = $this->order_pending_status;
  340. }
  341. $this->avs = 'N/A';
  342. $this->cvv2 = 'N/A';
  343. $this->correlationid = $response['CORRELATIONID'];
  344. $this->transactiontype = $response['TRANSACTIONTYPE'];
  345. $this->payment_time = urldecode($response['ORDERTIME']);
  346. $this->feeamt = urldecode($response['FEEAMT']);
  347. $this->taxamt = urldecode($response['TAXAMT']);
  348. $this->pendingreason = $response['PENDINGREASON'];
  349. $this->reasoncode = $response['REASONCODE'];
  350. $this->numitems = sizeof($order->products);
  351. $this->amt = urldecode($response['AMT'] . ' ' . $response['CURRENCYCODE']);
  352. $this->auth_code = (isset($this->response['AUTHCODE'])) ? $this->response['AUTHCODE'] : $this->response['TOKEN'];
  353. }
  354. /**
  355. * When the order returns from the processor, this stores the results in order-status-history and logs data for subsequent use
  356. */
  357. function after_process() {
  358. global $insert_id, $db, $order;
  359. // FMF
  360. if ($this->fmfResponse != '') {
  361. $detailedMessage = $insert_id . "\n" . $this->fmfResponse . "\n" . MODULE_PAYMENT_PAYPALDP_TEXT_EMAIL_FMF_INTRO . "\n" . print_r($this->fmfErrors, TRUE);
  362. zen_mail(STORE_NAME, STORE_OWNER_EMAIL_ADDRESS, MODULE_PAYMENT_PAYPALDP_TEXT_EMAIL_FMF_SUBJECT . ' (' . $insert_id . ')', $detailedMessage, STORE_OWNER, STORE_OWNER_EMAIL_ADDRESS, array('EMAIL_MESSAGE_HTML'=>nl2br($detailedMessage)), 'paymentalert');
  363. }
  364. // add a new OSH record for this order's PP details
  365. $commentString = "Transaction ID: :transID: " .
  366. (isset($this->responsedata['PPREF']) ? "\nPPRef: " . $this->responsedata['PPREF'] : "") .
  367. (isset($this->responsedata['AUTHCODE'])? "\nAuthCode: " . $this->responsedata['AUTHCODE'] : "") .
  368. "\nPayment Type: :pmtType: " .
  369. ($this->payment_time != '' ? "\nTimestamp: :pmtTime: " : "") .
  370. "\nPayment Status: :pmtStatus: " .
  371. (isset($this->responsedata['auth_exp']) ? "\nAuth-Exp: " . $this->responsedata['auth_exp'] : "") .
  372. ($this->avs != 'N/A' ? "\nAVS Code: ".$this->avs."\nCVV2 Code: ".$this->cvv2 : '') .
  373. (trim($this->amt) != '' ? "\nAmount: :orderAmt: " : "");
  374. $commentString = $db->bindVars($commentString, ':transID:', $this->transaction_id, 'noquotestring');
  375. $commentString = $db->bindVars($commentString, ':pmtType:', $this->payment_type, 'noquotestring');
  376. $commentString = $db->bindVars($commentString, ':pmtTime:', $this->payment_time, 'noquotestring');
  377. $commentString = $db->bindVars($commentString, ':pmtStatus:', $this->payment_status, 'noquotestring');
  378. $commentString = $db->bindVars($commentString, ':orderAmt:', $this->amt, 'noquotestring');
  379. $sql_data_array= array(array('fieldName'=>'orders_id', 'value'=>$insert_id, 'type'=>'integer'),
  380. array('fieldName'=>'orders_status_id', 'value'=>$order->info['order_status'], 'type'=>'integer'),
  381. array('fieldName'=>'date_added', 'value'=>'now()', 'type'=>'noquotestring'),
  382. array('fieldName'=>'customer_notified', 'value'=>0, 'type'=>'integer'),
  383. array('fieldName'=>'comments', 'value'=>$commentString, 'type'=>'string'));
  384. $db->perform(TABLE_ORDERS_STATUS_HISTORY, $sql_data_array);
  385. // store the PayPal order meta data -- used for later matching and back-end processing activities
  386. $paypal_order = array('order_id' => $insert_id,
  387. 'txn_type' => $this->transactiontype,
  388. 'module_name' => $this->code,
  389. 'module_mode' => MODULE_PAYMENT_PAYPALWPP_MODULE_MODE,
  390. 'reason_code' => $this->reasoncode,
  391. 'payment_type' => $this->payment_type,
  392. 'payment_status' => $this->payment_status,
  393. 'pending_reason' => $this->pendingreason,
  394. 'invoice' => urldecode($_SESSION['paypal_ec_token'] . $this->responsedata['PPREF']),
  395. 'first_name' => $_SESSION['paypal_ec_payer_info']['payer_firstname'],
  396. 'last_name' => $_SESSION['paypal_ec_payer_info']['payer_lastname'],
  397. 'payer_business_name' => $_SESSION['paypal_ec_payer_info']['payer_business'],
  398. 'address_name' => $_SESSION['paypal_ec_payer_info']['ship_name'],
  399. 'address_street' => $_SESSION['paypal_ec_payer_info']['ship_street_1'],
  400. 'address_city' => $_SESSION['paypal_ec_payer_info']['ship_city'],
  401. 'address_state' => $_SESSION['paypal_ec_payer_info']['ship_state'],
  402. 'address_zip' => $_SESSION['paypal_ec_payer_info']['ship_postal_code'],
  403. 'address_country' => $_SESSION['paypal_ec_payer_info']['ship_country'],
  404. 'address_status' => $_SESSION['paypal_ec_payer_info']['ship_address_status'],
  405. 'payer_email' => $_SESSION['paypal_ec_payer_info']['payer_email'],
  406. 'payer_id' => $_SESSION['paypal_ec_payer_id'],
  407. 'payer_status' => $_SESSION['paypal_ec_payer_info']['payer_status'],
  408. 'payment_date' => trim(preg_replace('/[^0-9-:]/', ' ', $this->payment_time)),
  409. 'business' => '',
  410. 'receiver_email' => (substr(MODULE_PAYMENT_PAYPALWPP_MODULE_MODE,0,7) == 'Payflow' ? MODULE_PAYMENT_PAYPALWPP_PFVENDOR : str_replace('_api1', '', MODULE_PAYMENT_PAYPALWPP_APIUSERNAME)),
  411. 'receiver_id' => '',
  412. 'txn_id' => $this->transaction_id,
  413. 'parent_txn_id' => '',
  414. 'num_cart_items' => (float)$this->numitems,
  415. 'mc_gross' => (float)$this->amt,
  416. 'mc_fee' => (float)urldecode($this->feeamt),
  417. 'mc_currency' => $this->responsedata['CURRENCYCODE'],
  418. 'settle_amount' => (float)urldecode($this->responsedata['SETTLEAMT']),
  419. 'settle_currency' => $this->responsedata['CURRENCYCODE'],
  420. 'exchange_rate' => (urldecode($this->responsedata['EXCHANGERATE']) > 0 ? urldecode($this->responsedata['EXCHANGERATE']) : 1.0),
  421. 'notify_version' => '0',
  422. 'verify_sign' =>'',
  423. 'date_added' => 'now()',
  424. 'memo' => (sizeof($this->fmfErrors) > 0 ? 'FMF Details ' . print_r($this->fmfErrors, TRUE) : '{Record generated by payment module}'),
  425. );
  426. zen_db_perform(TABLE_PAYPAL, $paypal_order);
  427. // Unregister the paypal session variables, making it necessary to start again for another purchase
  428. unset($_SESSION['paypal_ec_temp']);
  429. unset($_SESSION['paypal_ec_token']);
  430. unset($_SESSION['paypal_ec_payer_id']);
  431. unset($_SESSION['paypal_ec_payer_info']);
  432. unset($_SESSION['paypal_ec_final']);
  433. unset($_SESSION['paypal_ec_markflow']);
  434. }
  435. /**
  436. * Build admin-page components
  437. *
  438. * @param int $zf_order_id
  439. * @return string
  440. */
  441. function admin_notification($zf_order_id) {
  442. if (!defined('MODULE_PAYMENT_PAYPALWPP_STATUS')) return '';
  443. global $db;
  444. $module = $this->code;
  445. $output = '';
  446. $response = $this->_GetTransactionDetails($zf_order_id);
  447. //$response = $this->_TransactionSearch('2006-12-01T00:00:00Z', $zf_order_id);
  448. $sql = "SELECT * from " . TABLE_PAYPAL . " WHERE order_id = :orderID
  449. AND parent_txn_id = '' AND order_id > 0
  450. ORDER BY paypal_ipn_id DESC LIMIT 1";
  451. $sql = $db->bindVars($sql, ':orderID', $zf_order_id, 'integer');
  452. $ipn = $db->Execute($sql);
  453. if ($ipn->RecordCount() == 0) $ipn->fields = array();
  454. if (file_exists(DIR_FS_CATALOG . DIR_WS_MODULES . 'payment/paypal/paypalwpp_admin_notification.php')) require(DIR_FS_CATALOG . DIR_WS_MODULES . 'payment/paypal/paypalwpp_admin_notification.php');
  455. return $output;
  456. }
  457. /**
  458. * Used to read details of an existing transaction. FOR FUTURE USE.
  459. */
  460. function _GetTransactionDetails($oID) {
  461. global $db, $messageStack, $doPayPal;
  462. $doPayPal = $this->paypal_init();
  463. // look up history on this order from PayPal table
  464. $sql = "select * from " . TABLE_PAYPAL . " where order_id = :orderID order by last_modified DESC, date_added DESC, parent_txn_id DESC, paypal_ipn_id DESC ";
  465. $sql = $db->bindVars($sql, ':orderID', $oID, 'integer');
  466. $zc_ppHist = $db->Execute($sql);
  467. if ($zc_ppHist->RecordCount() == 0) return false;
  468. $txnID = $zc_ppHist->fields['txn_id'];
  469. /**
  470. * Read data from PayPal
  471. */
  472. $response = $doPayPal->GetTransactionDetails($txnID);
  473. $error = $this->_errorHandler($response, 'GetTransactionDetails', 10007);
  474. if ($error === false) {
  475. return false;
  476. } else {
  477. return $response;
  478. }
  479. }
  480. /**
  481. * Used to read details of existing transactions. FOR FUTURE USE.
  482. */
  483. function _TransactionSearch($startDate = '', $oID = '', $criteria = '') {
  484. global $db, $messageStack, $doPayPal;
  485. $doPayPal = $this->paypal_init();
  486. // look up history on this order from PayPal table
  487. $sql = "select * from " . TABLE_PAYPAL . " where order_id = :orderID AND parent_txn_id = '' ";
  488. $sql = $db->bindVars($sql, ':orderID', $oID, 'integer');
  489. $zc_ppHist = $db->Execute($sql);
  490. if ($zc_ppHist->RecordCount() == 0) return false;
  491. $txnID = $zc_ppHist->fields['txn_id'];
  492. $startDate = $zc_ppHist->fields['payment_date'];
  493. $timeval = time();
  494. if ($startDate == '') $startDate = date('Y-m-d', $timeval) . 'T' . date('h:i:s', $timeval) . 'Z';
  495. /**
  496. * Read data from PayPal
  497. */
  498. $response = $doPayPal->TransactionSearch($startDate, $txnID, $email, $criteria);
  499. $error = $this->_errorHandler($response, 'TransactionSearch');
  500. if ($error === false) {
  501. return false;
  502. } else {
  503. return $response;
  504. }
  505. }
  506. /**
  507. * Evaluate installation status of this module. Returns true if the status key is found.
  508. */
  509. function check() {
  510. global $db;
  511. if (!isset($this->_check)) {
  512. $check_query = $db->Execute("select configuration_value from " . TABLE_CONFIGURATION . " where configuration_key = 'MODULE_PAYMENT_PAYPALWPP_STATUS'");
  513. $this->_check = !$check_query->EOF;
  514. }
  515. return $this->_check;
  516. }
  517. /**
  518. * Installs all the configuration keys for this module
  519. */
  520. function install() {
  521. global $db, $messageStack;
  522. if (defined('MODULE_PAYMENT_PAYPALWPP_STATUS')) {
  523. $messageStack->add_session('Express Checkout module already installed.', 'error');
  524. zen_redirect(zen_href_link(FILENAME_MODULES, 'set=payment&module=paypalwpp', 'NONSSL'));
  525. return 'failed';
  526. }
  527. if (defined('MODULE_PAYMENT_PAYPAL_STATUS')) {
  528. $messageStack->add_session('NOTE: You already have the PayPal Website Payments Standard module installed. You should REMOVE it if you want to install Express Checkout.', 'error');
  529. zen_redirect(zen_href_link(FILENAME_MODULES, 'set=payment&module=paypal', 'NONSSL'));
  530. return 'failed';
  531. }
  532. $db->Execute("insert into " . TABLE_CONFIGURATION . " (configuration_title, configuration_key, configuration_value, configuration_description, configuration_group_id, sort_order, set_function, date_added) values ('Enable this Payment Module', 'MODULE_PAYMENT_PAYPALWPP_STATUS', 'True', 'Do you want to enable this payment module?', '6', '25', 'zen_cfg_select_option(array(\'True\', \'False\'), ', now())");
  533. $db->Execute("insert into " . TABLE_CONFIGURATION . " (configuration_title, configuration_key, configuration_value, configuration_description, configuration_group_id, sort_order, set_function, date_added) values ('Live or Sandbox', 'MODULE_PAYMENT_PAYPALWPP_SERVER', 'live', '<strong>Live: </strong> Used to process Live transactions<br><strong>Sandbox: </strong>For developers and testing', '6', '25', 'zen_cfg_select_option(array(\'live\', \'sandbox\'), ', now())");
  534. $db->Execute("insert into " . TABLE_CONFIGURATION . " (configuration_title, configuration_key, configuration_value, configuration_description, configuration_group_id, sort_order, set_function, date_added) values ('Express Checkout: Require Confirmed Address', 'MODULE_PAYMENT_PAYPALWPP_CONFIRMED_ADDRESS', 'No', 'Do you want to require that your (not-logged-in) customers use a *confirmed* address when choosing their shipping address in PayPal?<br />(this is ignored for logged-in customers)', '6', '25', 'zen_cfg_select_option(array(\'Yes\', \'No\'), ', now())");
  535. $db->Execute("insert into " . TABLE_CONFIGURATION . " (configuration_title, configuration_key, configuration_value, configuration_description, configuration_group_id, sort_order, set_function, date_added) values ('Express Checkout: Select Cheapest Shipping Automatically', 'MODULE_PAYMENT_PAYPALWPP_AUTOSELECT_CHEAPEST_SHIPPING', 'Yes', 'When customer returns from PayPal, do we want to automatically select the Cheapest shipping method and skip the shipping page? (making it more *express*)<br />Note: enabling this means the customer does *not* have easy access to select an alternate shipping method (without going back to the Checkout-Step-1 page)', '6', '25', 'zen_cfg_select_option(array(\'Yes\', \'No\'), ', now())");
  536. $db->Execute("insert into " . TABLE_CONFIGURATION . " (configuration_title, configuration_key, configuration_value, configuration_description, configuration_group_id, sort_order, set_function, date_added) values ('Express Checkout: Skip Payment Page', 'MODULE_PAYMENT_PAYPALWPP_SKIP_PAYMENT_PAGE', 'Yes', 'If the customer is checking out with Express Checkout, do you want to skip the checkout payment page, making things more *express*? <br /><strong>(NOTE: The Payment Page will auto-display regardless of this setting if you have Coupons or Gift Certificates enabled in your store.)</strong>', '6', '25', 'zen_cfg_select_option(array(\'Yes\', \'No\'), ', now())");
  537. $db->Execute("insert into " . TABLE_CONFIGURATION . " (configuration_title, configuration_key, configuration_value, configuration_description, configuration_group_id, sort_order, set_function, date_added) values ('Express Checkout: Automatic Account Creation', 'MODULE_PAYMENT_PAYPALWPP_NEW_ACCT_NOTIFY', 'Yes', 'If a visitor is not an existing customer, a Zen Cart account is created for them. Would you like make it a permanent account and send them an email containing their login information?<br />NOTE: Permanent accounts are auto-created if the customer purchases downloads or gift certificates, regardless of this setting.', '6', '25', 'zen_cfg_select_option(array(\'Yes\', \'No\'), ', now())");
  538. $db->Execute("insert into " . TABLE_CONFIGURATION . " (configuration_title, configuration_key, configuration_value, configuration_description, configuration_group_id, sort_order, date_added) values ('Sort order of display.', 'MODULE_PAYMENT_PAYPALWPP_SORT_ORDER', '0', 'Sort order of display. Lowest is displayed first.', '6', '25', now())");
  539. $db->Execute("insert into " . TABLE_CONFIGURATION . " (configuration_title, configuration_key, configuration_value, configuration_description, configuration_group_id, sort_order, use_function, set_function, date_added) values ('Payment Zone', 'MODULE_PAYMENT_PAYPALWPP_ZONE', '0', 'If a zone is selected, only enable this payment method for that zone.', '6', '25', 'zen_get_zone_class_title', 'zen_cfg_pull_down_zone_classes(', now())");
  540. $db->Execute("insert into " . TABLE_CONFIGURATION . " (configuration_title, configuration_key, configuration_value, configuration_description, configuration_group_id, sort_order, set_function, use_function, date_added) values ('Set Order Status', 'MODULE_PAYMENT_PAYPALWPP_ORDER_STATUS_ID', '2', 'Set the status of orders paid with this payment module to this value. <br /><strong>Recommended: Processing[2]</strong>', '6', '25', 'zen_cfg_pull_down_order_statuses(', 'zen_get_order_status_name', now())");
  541. $db->Execute("insert into " . TABLE_CONFIGURATION . " (configuration_title, configuration_key, configuration_value, configuration_description, configuration_group_id, sort_order, set_function, use_function, date_added) values ('Set Unpaid Order Status', 'MODULE_PAYMENT_PAYPALWPP_ORDER_PENDING_STATUS_ID', '1', 'Set the status of unpaid orders made with this payment module to this value. <br /><strong>Recommended: Pending[1]</strong>', '6', '25', 'zen_cfg_pull_down_order_statuses(', 'zen_get_order_status_name', now())");
  542. $db->Execute("insert into " . TABLE_CONFIGURATION . " (configuration_title, configuration_key, configuration_value, configuration_description, configuration_group_id, sort_order, set_function, use_function, date_added) values ('Set Refund Order Status', 'MODULE_PAYMENT_PAYPALWPP_REFUNDED_STATUS_ID', '1', 'Set the status of refunded orders to this value. <br /><strong>Recommended: Pending[1]</strong>', '6', '25', 'zen_cfg_pull_down_order_statuses(', 'zen_get_order_status_name', now())");
  543. $db->Execute("insert into " . TABLE_CONFIGURATION . " (configuration_title, configuration_key, configuration_value, configuration_description, configuration_group_id, sort_order, date_added) values ('PayPal Page Style', 'MODULE_PAYMENT_PAYPALWPP_PAGE_STYLE', 'Primary', 'The page-layout style you want customers to see when they visit the PayPal site. You can configure your <strong>Custom Page Styles</strong> in your PayPal Profile settings. This value is case-sensitive.', '6', '25', now())");
  544. $db->Execute("insert into " . TABLE_CONFIGURATION . " (configuration_title, configuration_key, configuration_value, configuration_description, configuration_group_id, sort_order, set_function, date_added) values ('Payment Action', 'MODULE_PAYMENT_PAYPALWPP_TRANSACTION_MODE', 'Final Sale', 'How do you want to obtain payment?<br /><strong>Default: Final Sale</strong>', '6', '25', 'zen_cfg_select_option(array(\'Auth Only\', \'Final Sale\'), ', now())");
  545. $db->Execute("insert into " . TABLE_CONFIGURATION . " (configuration_title, configuration_key, configuration_value, configuration_description, configuration_group_id, sort_order, set_function, date_added) values ('Transaction Currency', 'MODULE_PAYMENT_PAYPALWPP_CURRENCY', 'Selected Currency', 'Which currency should the order be sent to PayPal as? <br />NOTE: if an unsupported currency is sent to PayPal, it will be auto-converted to USD (or GBP if using UK account)<br /><strong>Default: Selected Currency</strong>', '6', '25', 'zen_cfg_select_option(array(\'Selected Currency\', \'Only USD\', \'Only AUD\', \'Only CAD\', \'Only EUR\', \'Only GBP\', \'Only CHF\', \'Only CZK\', \'Only DKK\', \'Only HKD\', \'Only HUF\', \'Only JPY\', \'Only NOK\', \'Only NZD\', \'Only PLN\', \'Only SEK\', \'Only SGD\', \'Only THB\', \'Only MXN\', \'Only ILS\', \'Only PHP\', \'Only TWD\', \'Only BRL\', \'Only MYR\'), ', now())");
  546. $db->Execute("insert into " . TABLE_CONFIGURATION . " (configuration_title, configuration_key, configuration_value, configuration_description, configuration_group_id, sort_order, set_function, date_added) values ('Fraud Mgmt Filters - FMF', 'MODULE_PAYMENT_PAYPALWPP_EC_RETURN_FMF_DETAILS', 'No', 'If you have enabled FMF support in your PayPal account and wish to utilize it in your transactions, set this to yes. Otherwise, leave it at No.', '6', '25','zen_cfg_select_option(array(\'No\', \'Yes\'), ', now())");
  547. $db->Execute("insert into " . TABLE_CONFIGURATION . " (configuration_title, configuration_key, configuration_value, configuration_description, configuration_group_id, sort_order, date_added) values ('API Signature -- Username', 'MODULE_PAYMENT_PAYPALWPP_APIUSERNAME', '', 'The API Username from your PayPal API Signature settings under *API Access*. This value typically looks like an email address and is case-sensitive.', '6', '25', now())");
  548. $db->Execute("insert into " . TABLE_CONFIGURATION . " (configuration_title, configuration_key, configuration_value, configuration_description, configuration_group_id, sort_order, date_added, set_function, use_function) values ('API Signature -- Password', 'MODULE_PAYMENT_PAYPALWPP_APIPASSWORD', '', 'The API Password from your PayPal API Signature settings under *API Access*. This value is a 16-character code and is case-sensitive.', '6', '25', now(), 'zen_cfg_password_input(', 'zen_cfg_password_display')");
  549. $db->Execute("insert into " . TABLE_CONFIGURATION . " (configuration_title, configuration_key, configuration_value, configuration_description, configuration_group_id, sort_order, date_added, set_function, use_function) values ('API Signature -- Signature Code', 'MODULE_PAYMENT_PAYPALWPP_APISIGNATURE', '', 'The API Signature from your PayPal API Signature settings under *API Access*. This value is a 56-character code, and is case-sensitive.', '6', '25', now(), '', 'zen_cfg_password_display')");
  550. $db->Execute("insert into " . TABLE_CONFIGURATION . " (configuration_title, configuration_key, configuration_value, configuration_description, configuration_group_id, sort_order, date_added) values ('PAYFLOW: User', 'MODULE_PAYMENT_PAYPALWPP_PFUSER', '', 'If you set up one or more additional users on the account, this value is the ID of the user authorized to process transactions. Otherwise it should be the same value as VENDOR. This value is case-sensitive.', '6', '25', now())");
  551. $db->Execute("insert into " . TABLE_CONFIGURATION . " (configuration_title, configuration_key, configuration_value, configuration_description, configuration_group_id, sort_order, date_added) values ('PAYFLOW: Partner', 'MODULE_PAYMENT_PAYPALWPP_PFPARTNER', 'ZenCart', 'Your Payflow Partner name linked to your Payflow account. This value is case-sensitive.<br />Typical values: <strong>PayPal</strong> or <strong>ZenCart</strong>', '6', '25', now())");
  552. $db->Execute("insert into " . TABLE_CONFIGURATION . " (configuration_title, configuration_key, configuration_value, configuration_description, configuration_group_id, sort_order, date_added) values ('PAYFLOW: Vendor', 'MODULE_PAYMENT_PAYPALWPP_PFVENDOR', '', 'Your merchant login ID that you created when you registered for the Payflow Pro account. This value is case-sensitive.', '6', '25', now())");
  553. $db->Execute("insert into " . TABLE_CONFIGURATION . " (configuration_title, configuration_key, configuration_value, configuration_description, configuration_group_id, sort_order, date_added, set_function, use_function) values ('PAYFLOW: Password', 'MODULE_PAYMENT_PAYPALWPP_PFPASSWORD', '', 'The 6- to 32-character password that you defined while registering for the account. This value is case-sensitive.', '6', '25', now(), 'zen_cfg_password_input(', 'zen_cfg_password_display')");
  554. $db->Execute("insert into " . TABLE_CONFIGURATION . " (configuration_title, configuration_key, configuration_value, configuration_description, configuration_group_id, sort_order, set_function, date_added) values ('PayPal Mode', 'MODULE_PAYMENT_PAYPALWPP_MODULE_MODE', 'PayPal', 'Which PayPal API system should be used for processing? <br /><u>Choices:</u><br /><font color=green>For choice #1, you need to supply <strong>API Settings</strong> above.</font><br /><strong>1. PayPal</strong> = Express Checkout with a regular PayPal account<br />or<br /><font color=green>for choices 2 &amp; 3 you need to supply <strong>PAYFLOW settings</strong>, below (and have a Payflow account)</font><br /><strong>2. Payflow-UK</strong> = Website Payments Pro UK Payflow Edition<br /><strong>3. Payflow-US</strong> = Payflow Pro Gateway only<!--<br /><strong>4. PayflowUS+EC</strong> = Payflow Pro with Express Checkout-->', '6', '25', 'zen_cfg_select_option(array(\'PayPal\', \'Payflow-UK\', \'Payflow-US\'), ', now())");
  555. $db->Execute("insert into " . TABLE_CONFIGURATION . " (configuration_title, configuration_key, configuration_value, configuration_description, configuration_group_id, sort_order, set_function, date_added) values ('Debug Mode', 'MODULE_PAYMENT_PAYPALWPP_DEBUGGING', 'Off', 'Would you like to enable debug mode? A complete detailed log of failed transactions will be emailed to the store owner.', '6', '25', 'zen_cfg_select_option(array(\'Off\', \'Alerts Only\', \'Log File\', \'Log and Email\'), ', now())");
  556. $this->notify('NOTIFY_PAYMENT_PAYPALWPP_INSTALLED');
  557. }
  558. function keys() {
  559. $keys_list = array('MODULE_PAYMENT_PAYPALWPP_STATUS', 'MODULE_PAYMENT_PAYPALWPP_SORT_ORDER', 'MODULE_PAYMENT_PAYPALWPP_ZONE', 'MODULE_PAYMENT_PAYPALWPP_ORDER_STATUS_ID', 'MODULE_PAYMENT_PAYPALWPP_ORDER_PENDING_STATUS_ID', 'MODULE_PAYMENT_PAYPALWPP_REFUNDED_STATUS_ID', 'MODULE_PAYMENT_PAYPALWPP_CONFIRMED_ADDRESS', 'MODULE_PAYMENT_PAYPALWPP_AUTOSELECT_CHEAPEST_SHIPPING', 'MODULE_PAYMENT_PAYPALWPP_SKIP_PAYMENT_PAGE', 'MODULE_PAYMENT_PAYPALWPP_NEW_ACCT_NOTIFY', 'MODULE_PAYMENT_PAYPALWPP_TRANSACTION_MODE', 'MODULE_PAYMENT_PAYPALWPP_CURRENCY', 'MODULE_PAYMENT_PAYPALWPP_PAGE_STYLE', 'MODULE_PAYMENT_PAYPALWPP_APIUSERNAME', 'MODULE_PAYMENT_PAYPALWPP_APIPASSWORD', 'MODULE_PAYMENT_PAYPALWPP_APISIGNATURE', 'MODULE_PAYMENT_PAYPALWPP_MODULE_MODE', /*'MODULE_PAYMENT_PAYPALWPP_PFPARTNER', 'MODULE_PAYMENT_PAYPALWPP_PFVENDOR', 'MODULE_PAYMENT_PAYPALWPP_PFUSER', 'MODULE_PAYMENT_PAYPALWPP_PFPASSWORD', */'MODULE_PAYMENT_PAYPALWPP_SERVER', 'MODULE_PAYMENT_PAYPALWPP_DEBUGGING');
  560. if (IS_ADMIN_FLAG === true && (PAYPAL_DEV_MODE == 'true' || strstr(MODULE_PAYMENT_PAYPALWPP_MODULE_MODE, 'Payflow'))) {
  561. $keys_list = array_merge($keys_list, array('MODULE_PAYMENT_PAYPALWPP_PFPARTNER', 'MODULE_PAYMENT_PAYPALWPP_PFVENDOR', 'MODULE_PAYMENT_PAYPALWPP_PFUSER', 'MODULE_PAYMENT_PAYPALWPP_PFPASSWORD'));
  562. }
  563. return $keys_list;
  564. }
  565. /**
  566. * De-install this module
  567. */
  568. function remove() {
  569. global $messageStack;
  570. // cannot remove EC if DP installed:
  571. if (defined('MODULE_PAYMENT_PAYPALDP_STATUS')) {
  572. // this language text is hard-coded in english since Website Payments Pro is not yet available in any countries that speak any other language at this time.
  573. $messageStack->add_session('<strong>Sorry, you must remove Website Payments Pro (paypaldp) first.</strong> Website Payments Pro requires that you offer Express Checkout to your customers.<br /><a href="' . zen_href_link('modules.php?set=payment&module=paypaldp', '', 'NONSSL') . '">Click here to edit or remove your Website Payments Pro module.</a>' , 'error');
  574. zen_redirect(zen_href_link(FILENAME_MODULES, 'set=payment&module=paypalwpp', 'NONSSL'));
  575. return 'failed';
  576. }
  577. global $db;
  578. $db->Execute("delete from " . TABLE_CONFIGURATION . " where configuration_key LIKE 'MODULE\_PAYMENT\_PAYPALWPP\_%'");
  579. $this->notify('NOTIFY_PAYMENT_PAYPALWPP_UNINSTALLED');
  580. }
  581. /**
  582. * Check settings and conditions to determine whether we are in an Express Checkout phase or not
  583. */
  584. function in_special_checkout() {
  585. if ((defined('MODULE_PAYMENT_PAYPALWPP_STATUS') && MODULE_PAYMENT_PAYPALWPP_STATUS == 'True') &&
  586. !empty($_SESSION['paypal_ec_token']) &&
  587. !empty($_SESSION['paypal_ec_payer_id']) &&
  588. !empty($_SESSION['paypal_ec_payer_info'])) {
  589. $this->flagDisablePaymentAddressChange = true;
  590. return true;
  591. }
  592. }
  593. /**
  594. * Determine whether the shipping-edit button should be displayed or not
  595. */
  596. function alterShippingEditButton() {
  597. return false;
  598. if ($this->in_special_checkout() && empty($_SESSION['paypal_ec_markflow'])) {
  599. return zen_href_link('ipn_main_handler.php', 'type=ec&clearSess=1', 'SSL', true,true, true);
  600. }
  601. }
  602. /**
  603. * Debug Logging support
  604. */
  605. function zcLog($stage, $message) {
  606. static $tokenHash;
  607. if ($tokenHash == '') $tokenHash = '_' . zen_create_random_value(4);
  608. if (MODULE_PAYMENT_PAYPALWPP_DEBUGGING == 'Log and Email' || MODULE_PAYMENT_PAYPALWPP_DEBUGGING == 'Log File') {
  609. $token = (isset($_SESSION['paypal_ec_token'])) ? $_SESSION['paypal_ec_token'] : preg_replace('/[^0-9.A-Z\-]/', '', $_GET['token']);
  610. $token = ($token == '') ? date('m-d-Y-H-i') : $token; // or time()
  611. $token .= $tokenHash;
  612. $file = $this->_logDir . '/' . $this->code . '_Paypal_Action_' . $token . '.log';
  613. if (defined('PAYPAL_DEV_MODE') && PAYPAL_DEV_MODE == 'true') $file = $this->_logDir . '/' . $this->code . '_Paypal_Debug_' . $token . '.log';
  614. $fp = @fopen($file, 'a');
  615. @fwrite($fp, date('M-d-Y H:i:s') . ' (' . time() . ')' . "\n" . $stage . "\n" . $message . "\n=================================\n\n");
  616. @fclose($fp);
  617. }
  618. $this->_doDebug($stage, $message, false);
  619. }
  620. /**
  621. * Debug Emailing support
  622. */
  623. function _doDebug($subject = 'PayPal debug data', $data, $useSession = true) {
  624. if (MODULE_PAYMENT_PAYPALWPP_DEBUGGING == 'Log and Email') {
  625. $data = urldecode($data) . "\n\n";
  626. if ($useSession) $data .= "\nSession data: " . print_r($_SESSION, true);
  627. zen_mail(STORE_NAME, STORE_OWNER_EMAIL_ADDRESS, $subject, $this->code . "\n" . $data, STORE_OWNER, STORE_OWNER_EMAIL_ADDRESS, array('EMAIL_MESSAGE_HTML'=>nl2br($this->code . "\n" . $data)), 'debug');
  628. }
  629. }
  630. /**
  631. * Initialize the PayPal/PayflowPro object for communication to the processing gateways
  632. */
  633. function paypal_init() {
  634. if (!defined('MODULE_PAYMENT_PAYPALWPP_STATUS') || !defined('MODULE_PAYMENT_PAYPALWPP_SERVER')) {
  635. $doPayPal = new paypal_curl(array('mode' => 'NOTCONFIGURED'));
  636. return $doPayPal;
  637. }
  638. $ec_uses_gateway = (defined('MODULE_PAYMENT_PAYPALWPP_PRO20_EC_METHOD') && MODULE_PAYMENT_PAYPALWPP_PRO20_EC_METHOD == 'Payflow') ? true : false;
  639. if (substr(MODULE_PAYMENT_PAYPALWPP_MODULE_MODE,0,7) == 'Payflow') {
  640. $doPayPal = new paypal_curl(array('mode' => 'payflow',
  641. 'user' => trim(MODULE_PAYMENT_PAYPALWPP_PFUSER),
  642. 'vendor' => trim(MODULE_PAYMENT_PAYPALWPP_PFVENDOR),
  643. 'partner'=> trim(MODULE_PAYMENT_PAYPALWPP_PFPARTNER),
  644. 'pwd' => trim(MODULE_PAYMENT_PAYPALWPP_PFPASSWORD),
  645. 'server' => MODULE_PAYMENT_PAYPALWPP_SERVER));
  646. $doPayPal->_endpoints = array('live' => 'https://payflowpro.paypal.com/transaction',
  647. 'sandbox' => 'https://pilot-payflowpro.paypal.com/transaction');
  648. } else {
  649. $doPayPal = new paypal_curl(array('mode' => 'nvp',
  650. 'user' => trim(MODULE_PAYMENT_PAYPALWPP_APIUSERNAME),
  651. 'pwd' => trim(MODULE_PAYMENT_PAYPALWPP_APIPASSWORD),
  652. 'signature' => trim(MODULE_PAYMENT_PAYPALWPP_APISIGNATURE),
  653. 'version' => '60.0',
  654. 'server' => MODULE_PAYMENT_PAYPALWPP_SERVER));
  655. $doPayPal->_endpoints = array('live' => 'https://api-3t.paypal.com/nvp',
  656. 'sandbox' => 'https://api.sandbox.paypal.com/nvp');
  657. }
  658. // set logging options
  659. $doPayPal->_logDir = $this->_logDir;
  660. // $doPayPal->_logLevel = $this->_logLevel;
  661. // set proxy options if configured
  662. if (CURL_PROXY_REQUIRED == 'True' && CURL_PROXY_SERVER_DETAILS != '') {
  663. $proxy_tunnel_flag = (defined('CURL_PROXY_TUNNEL_FLAG') && strtoupper(CURL_PROXY_TUNNEL_FLAG) == 'FALSE') ? false : true;
  664. $doPayPal->setCurlOption(CURLOPT_HTTPPROXYTUNNEL, $proxy_tunnel_flag);
  665. $doPayPal->setCurlOption(CURLOPT_PROXYTYPE, CURLPROXY_HTTP);
  666. $doPayPal->setCurlOption(CURLOPT_PROXY, CURL_PROXY_SERVER_DETAILS);
  667. }
  668. // transaction processing mode
  669. $doPayPal->_trxtype = (in_array(MODULE_PAYMENT_PAYPALWPP_TRANSACTION_MODE, array('Auth Only', 'Order'))) ? 'A' : 'S';
  670. return $doPayPal;
  671. }
  672. /**
  673. * Determine which PayPal URL to direct the customer's browser to when needed
  674. */
  675. function getPayPalLoginServer() {
  676. if (MODULE_PAYMENT_PAYPALWPP_SERVER == 'live') {
  677. // live url
  678. $paypal_url = 'https://www.paypal.com/cgi-bin/webscr';
  679. } else {
  680. // sandbox url
  681. $paypal_url = 'https://www.sandbox.paypal.com/cgi-bin/webscr';
  682. }
  683. return $paypal_url;
  684. }
  685. /**
  686. * Used to submit a refund for a given transaction. FOR FUTURE USE.
  687. */
  688. function _doRefund($oID, $amount = 'Full', $note = '') {
  689. global $db, $doPayPal, $messageStack;
  690. $new_order_status = (int)MODULE_PAYMENT_PAYPALWPP_REFUNDED_STATUS_ID;
  691. $orig_order_amount = 0;
  692. $doPayPal = $this->paypal_init();
  693. $proceedToRefund = false;
  694. $refundNote = strip_tags(zen_db_input($_POST['refnote']));
  695. if (isset($_POST['fullrefund']) && $_POST['fullrefund'] == MODULE_PAYMENT_PAYPAL_ENTRY_REFUND_BUTTON_TEXT_FULL) {
  696. $refundAmt = 'Full';
  697. if (isset($_POST['reffullconfirm']) && $_POST['reffullconfirm'] == 'on') {
  698. $proceedToRefund = true;
  699. } else {
  700. $messageStack->add_session(MODULE_PAYMENT_PAYPALWPP_TEXT_REFUND_FULL_CONFIRM_ERROR, 'error');
  701. }
  702. }
  703. if (isset($_POST['partialrefund']) && $_POST['partialrefund'] == MODULE_PAYMENT_PAYPAL_ENTRY_REFUND_BUTTON_TEXT_PARTIAL) {
  704. $refundAmt = (float)$_POST['refamt'];
  705. $proceedToRefund = true;
  706. if ($refundAmt == 0) {
  707. $messageStack->add_session(MODULE_PAYMENT_PAYPALWPP_TEXT_INVALID_REFUND_AMOUNT, 'error');
  708. $proceedToRefund = false;
  709. }
  710. }
  711. // look up history on this order from PayPal table
  712. $sql = "select * from " . TABLE_PAYPAL . " wh…

Large files files are truncated, but you can click here to view the full file