/classes/wc-gateway-paypal-pro-angelleye.php

  1. <?php 
  2.  
  3. /** 
  4. * WC_Gateway_PayPal_Pro class. 
  5. * 
  6. * @extends WC_Payment_Gateway 
  7. */ 
  8. class WC_Gateway_PayPal_Pro_AngellEYE extends WC_Payment_Gateway_CC { 
  9.  
  10. /** 
  11. * Store client 
  12. */ 
  13. private $centinel_client = false; 
  14. public $customer_id; 
  15. /** 
  16. * __construct function. 
  17. * 
  18. * @access public 
  19. * @return void 
  20. */ 
  21. function __construct() { 
  22. $this->id = 'paypal_pro'; 
  23. $this->method_title = __('PayPal Website Payments Pro (DoDirectPayment) ', 'paypal-for-woocommerce'); 
  24. $this->method_description = __('PayPal Website Payments Pro allows you to accept credit cards directly on your site without any redirection through PayPal. You host the checkout form on your own web server, so you will need an SSL certificate to ensure your customer data is protected.', 'paypal-for-woocommerce'); 
  25. $this->has_fields = true; 
  26. $this->liveurl = 'https://api-3t.paypal.com/nvp'; 
  27. $this->testurl = 'https://api-3t.sandbox.paypal.com/nvp'; 
  28. $this->liveurl_3ds = 'https://paypal.cardinalcommerce.com/maps/txns.asp'; 
  29. $this->testurl_3ds = 'https://centineltest.cardinalcommerce.com/maps/txns.asp'; 
  30. $this->available_card_types = apply_filters('woocommerce_paypal_pro_available_card_types', array( 
  31. 'GB' => array( 
  32. 'Visa' => 'Visa',  
  33. 'MasterCard' => 'MasterCard',  
  34. 'Maestro' => 'Maestro/Switch',  
  35. 'Solo' => 'Solo' 
  36. ),  
  37. 'US' => array( 
  38. 'Visa' => 'Visa',  
  39. 'MasterCard' => 'MasterCard',  
  40. 'Discover' => 'Discover',  
  41. 'AmEx' => 'American Express' 
  42. ),  
  43. 'CA' => array( 
  44. 'Visa' => 'Visa',  
  45. 'MasterCard' => 'MasterCard' 
  46. ),  
  47. 'AU' => array( 
  48. 'Visa' => 'Visa',  
  49. 'MasterCard' => 'MasterCard',  
  50. 'Discover' => 'Discover',  
  51. 'AmEx' => 'American Express' 
  52. )); 
  53. $this->iso4217 = apply_filters('woocommerce_paypal_pro_iso_currencies', array( 
  54. 'AUD' => '036',  
  55. 'CAD' => '124',  
  56. 'CZK' => '203',  
  57. 'DKK' => '208',  
  58. 'EUR' => '978',  
  59. 'HUF' => '348',  
  60. 'JPY' => '392',  
  61. 'NOK' => '578',  
  62. 'NZD' => '554',  
  63. 'PLN' => '985',  
  64. 'GBP' => '826',  
  65. 'SGD' => '702',  
  66. 'SEK' => '752',  
  67. 'CHF' => '756',  
  68. 'USD' => '840' 
  69. )); 
  70. // Load the form fields 
  71. $this->init_form_fields(); 
  72. // Load the settings. 
  73. $this->init_settings(); 
  74. // Get setting values 
  75. $this->title = $this->get_option('title'); 
  76. $this->description = $this->get_option('description'); 
  77. $this->enabled = $this->get_option('enabled'); 
  78. $this->api_username = $this->get_option('api_username'); 
  79. $this->api_password = $this->get_option('api_password'); 
  80. $this->api_signature = $this->get_option('api_signature'); 
  81. $this->testmode = 'yes' === $this->get_option('testmode', 'no'); 
  82. if( $this->testmode == false ) { 
  83. $this->testmode = AngellEYE_Utility::angelleye_paypal_for_woocommerce_is_set_sandbox_product(); 
  84. $this->invoice_id_prefix = $this->get_option('invoice_id_prefix'); 
  85. $this->error_email_notify = $this->get_option('error_email_notify'); 
  86. $this->error_display_type = $this->get_option('error_display_type');  
  87. //$this->enable_3dsecure = 'yes' === $this->get_option('enable_3dsecure', 'no'); 
  88. $this->enable_3dsecure = false; 
  89. $this->liability_shift = 'yes' === $this->get_option('liability_shift', 'no'); 
  90. $this->debug = 'yes' === $this->get_option('debug', 'no');  
  91. $this->payment_action = $this->get_option('payment_action', 'Sale'); 
  92. $this->send_items = 'yes' === $this->get_option('send_items', 'yes'); 
  93. $this->enable_notifyurl = $this->get_option('enable_notifyurl', 'no'); 
  94. $this->is_encrypt = $this->get_option('is_encrypt', 'no'); 
  95. $this->softdescriptor = $this->get_option('softdescriptor', ''); 
  96. $this->avs_cvv2_result_admin_email = 'yes' === $this->get_option('avs_cvv2_result_admin_email', 'no');  
  97. $this->fraud_management_filters = $this->get_option('fraud_management_filters', 'place_order_on_hold_for_further_review'); 
  98. $this->notifyurl = ''; 
  99. if ($this->enable_notifyurl == 'yes') { 
  100. $this->notifyurl = $this->get_option('notifyurl'); 
  101. if (isset($this->notifyurl) && !empty($this->notifyurl)) { 
  102. $this->notifyurl = str_replace('&', '&', $this->notifyurl); 
  103. $this->enable_cardholder_first_last_name = 'yes' === $this->get_option('enable_cardholder_first_last_name', 'no'); 
  104. // 3DS 
  105. if ($this->enable_3dsecure) { 
  106. $this->centinel_pid = $this->get_option('centinel_pid'); 
  107. $this->centinel_mid = $this->get_option('centinel_mid'); 
  108. $this->centinel_pwd = $this->get_option('centinel_pwd'); 
  109. if (empty($this->centinel_pid) || empty($this->centinel_mid) || empty($this->centinel_pwd)) 
  110. $this->enable_3dsecure = false; 
  111. $this->centinel_url = $this->testmode == false ? $this->liveurl_3ds : $this->testurl_3ds; 
  112.  
  113. //fix ssl for image icon 
  114. $this->icon = $this->get_option('card_icon', plugins_url('/assets/images/cards.png', plugin_basename(dirname(__FILE__)))); 
  115. if (is_ssl()) { 
  116. $this->icon = preg_replace("/^http:/i", "https:", $this->icon); 
  117. $this->icon = apply_filters('woocommerce_paypal_pro_icon', $this->icon); 
  118. $this->supports = array( 
  119. 'products',  
  120. 'refunds' 
  121. ); 
  122. $this->enable_tokenized_payments = $this->get_option('enable_tokenized_payments', 'no'); 
  123. if($this->enable_tokenized_payments == 'yes') { 
  124. $this->supports = array( 
  125. 'subscriptions',  
  126. 'products',  
  127. 'refunds',  
  128. 'subscription_cancellation',  
  129. 'subscription_reactivation',  
  130. 'subscription_suspension',  
  131. 'subscription_amount_changes',  
  132. 'subscription_payment_method_change', // Subs 1.n compatibility. 
  133. 'subscription_payment_method_change_customer',  
  134. 'subscription_payment_method_change_admin',  
  135. 'subscription_date_changes',  
  136. 'multiple_subscriptions',  
  137. 'add_payment_method',  
  138. 'tokenization' 
  139. ); 
  140. $this->Force_tls_one_point_two = get_option('Force_tls_one_point_two', 'no'); 
  141. $this->credit_card_month_field = $this->get_option('credit_card_month_field', 'names'); 
  142. $this->credit_card_year_field = $this->get_option('credit_card_year_field', 'four_digit'); 
  143. if ($this->testmode == true) { 
  144. $this->api_username = $this->get_option('sandbox_api_username'); 
  145. $this->api_password = $this->get_option('sandbox_api_password'); 
  146. $this->api_signature = $this->get_option('sandbox_api_signature'); 
  147. // Maestro 
  148. if (!$this->enable_3dsecure) { 
  149. unset($this->available_card_types['GB']['Maestro']); 
  150.  
  151. // Hooks 
  152. add_action('woocommerce_api_wc_gateway_paypal_pro_angelleye', array($this, 'handle_3dsecure')); 
  153. /** 2.0.0 */ 
  154. add_action('woocommerce_update_options_payment_gateways_' . $this->id, array($this, 'process_admin_options')); 
  155. add_filter('woocommerce_settings_api_sanitized_fields_' . $this->id, array($this, 'angelleye_paypal_pro_encrypt_gateway_api'), 10, 1); 
  156. if ($this->enable_cardholder_first_last_name) { 
  157. add_action('woocommerce_credit_card_form_start', array($this, 'angelleye_woocommerce_credit_card_form_start'), 10, 1); 
  158.  
  159. add_filter('woocommerce_credit_card_form_fields', array($this, 'angelleye_paypal_pro_credit_card_form_fields'), 10, 2); 
  160. if( $this->avs_cvv2_result_admin_email ) { 
  161. add_action( 'woocommerce_email_before_order_table', array( $this, 'angelleye_paypal_pro_email_instructions' ), 10, 3 ); 
  162.  
  163. $this->customer_id; 
  164.  
  165. /** 
  166. * Initialise Gateway Settings Form Fields 
  167. */ 
  168. function init_form_fields() { 
  169. $this->form_fields = array( 
  170. 'enabled' => array( 
  171. 'title' => __('Enable/Disable', 'paypal-for-woocommerce'),  
  172. 'label' => __('Enable PayPal Pro', 'paypal-for-woocommerce'),  
  173. 'type' => 'checkbox',  
  174. 'description' => '',  
  175. 'default' => 'no' 
  176. ),  
  177. 'title' => array( 
  178. 'title' => __('Title', 'paypal-for-woocommerce'),  
  179. 'type' => 'text',  
  180. 'description' => __('This controls the title which the user sees during checkout.', 'paypal-for-woocommerce'),  
  181. 'default' => __('Credit card', 'paypal-for-woocommerce') 
  182. ),  
  183. 'description' => array( 
  184. 'title' => __('Description', 'paypal-for-woocommerce'),  
  185. 'type' => 'textarea',  
  186. 'description' => __('This controls the description which the user sees during checkout.', 'paypal-for-woocommerce'),  
  187. 'default' => __('Pay with your credit card', 'paypal-for-woocommerce') 
  188. ),  
  189. 'testmode' => array( 
  190. 'title' => __('Test Mode', 'paypal-for-woocommerce'),  
  191. 'label' => __('Enable PayPal Sandbox/Test Mode', 'paypal-for-woocommerce'),  
  192. 'type' => 'checkbox',  
  193. 'description' => __('Place the payment gateway in development mode.', 'paypal-for-woocommerce'),  
  194. 'default' => 'no' 
  195. ),  
  196. 'invoice_id_prefix' => array( 
  197. 'title' => __('Invoice ID Prefix', 'paypal-for-woocommerce'),  
  198. 'type' => 'text',  
  199. 'description' => __('Add a prefix to the invoice ID sent to PayPal. This can resolve duplicate invoice problems when working with multiple websites on the same PayPal account.', 'paypal-for-woocommerce'),  
  200. ),  
  201. 'card_icon' => array( 
  202. 'title' => __('Card Icon', 'paypal-for-woocommerce'),  
  203. 'type' => 'text',  
  204. 'default' => plugins_url('/assets/images/cards.png', plugin_basename(dirname(__FILE__))),  
  205. 'class' => 'button_upload',  
  206. ),  
  207. 'error_email_notify' => array( 
  208. 'title' => __('Error Email Notifications', 'paypal-for-woocommerce'),  
  209. 'type' => 'checkbox',  
  210. 'label' => __('Enable admin email notifications for errors.', 'paypal-for-woocommerce'),  
  211. 'default' => 'yes',  
  212. 'description' => __('This will send a detailed error email to the WordPress site administrator if a PayPal API error occurs.', 'paypal-for-woocommerce') 
  213. ),  
  214. 'sandbox_api_username' => array( 
  215. 'title' => __('Sandbox API Username', 'paypal-for-woocommerce'),  
  216. 'type' => 'text',  
  217. 'description' => __('Create sandbox accounts and obtain API credentials from within your 
  218. <a href="http://developer.paypal.com">PayPal developer account</a>.', 'paypal-for-woocommerce'),  
  219. 'default' => '' 
  220. ),  
  221. 'sandbox_api_password' => array( 
  222. 'title' => __('Sandbox API Password', 'paypal-for-woocommerce'),  
  223. 'type' => 'password',  
  224. 'default' => '' 
  225. ),  
  226. 'sandbox_api_signature' => array( 
  227. 'title' => __('Sandbox API Signature', 'paypal-for-woocommerce'),  
  228. 'type' => 'password',  
  229. 'default' => '' 
  230. ),  
  231. 'api_username' => array( 
  232. 'title' => __('Live API Username', 'paypal-for-woocommerce'),  
  233. 'type' => 'text',  
  234. 'description' => __('Get your live account API credentials from your PayPal account profile under the API Access section <br />or by using 
  235. <a target="_blank" href="https://www.paypal.com/us/cgi-bin/webscr?cmd=_login-api-run">this tool</a>.', 'paypal-for-woocommerce'),  
  236. 'default' => '' 
  237. ),  
  238. 'api_password' => array( 
  239. 'title' => __('Live API Password', 'paypal-for-woocommerce'),  
  240. 'type' => 'password',  
  241. 'default' => '' 
  242. ),  
  243. 'api_signature' => array( 
  244. 'title' => __('Live API Signature', 'paypal-for-woocommerce'),  
  245. 'type' => 'password',  
  246. 'default' => '' 
  247. ),  
  248. // 'enable_3dsecure' => array( 
  249. // 'title' => __('3DSecure', 'paypal-for-woocommerce'),  
  250. // 'label' => __('Enable 3DSecure', 'paypal-for-woocommerce'),  
  251. // 'type' => 'checkbox',  
  252. // 'description' => __('Allows UK merchants to pass 3-D Secure authentication data to PayPal for debit and credit cards. Updating your site with 3-D Secure enables your participation in the Verified by Visa and MasterCard SecureCode programs. (Required to accept Maestro)', 'paypal-for-woocommerce'),  
  253. // 'default' => 'no' 
  254. // ),  
  255. // 'centinel_pid' => array( 
  256. // 'title' => __('Centinel PID', 'paypal-for-woocommerce'),  
  257. // 'type' => 'text',  
  258. // 'description' => __('If enabling 3D Secure, enter your Cardinal Centinel Processor ID.', 'paypal-for-woocommerce'),  
  259. // 'default' => '' 
  260. // ),  
  261. // 'centinel_mid' => array( 
  262. // 'title' => __('Centinel MID', 'paypal-for-woocommerce'),  
  263. // 'type' => 'text',  
  264. // 'description' => __('If enabling 3D Secure, enter your Cardinal Centinel Merchant ID.', 'paypal-for-woocommerce'),  
  265. // 'default' => '' 
  266. // ),  
  267. // 'centinel_pwd' => array( 
  268. // 'title' => __('Transaction Password', 'paypal-for-woocommerce'),  
  269. // 'type' => 'password',  
  270. // 'description' => __('If enabling 3D Secure, enter your Cardinal Centinel Transaction Password.', 'paypal-for-woocommerce'),  
  271. // 'default' => '' 
  272. // ),  
  273. // 'liability_shift' => array( 
  274. // 'title' => __('Liability Shift', 'paypal-for-woocommerce'),  
  275. // 'label' => __('Require liability shift', 'paypal-for-woocommerce'),  
  276. // 'type' => 'checkbox',  
  277. // 'description' => __('Only accept payments when liability shift has occurred.', 'paypal-for-woocommerce'),  
  278. // 'default' => 'no' 
  279. // ),  
  280. 'error_display_type' => array( 
  281. 'title' => __('Error Display Type', 'paypal-for-woocommerce'),  
  282. 'type' => 'select',  
  283. 'label' => __('Display detailed or generic errors', 'paypal-for-woocommerce'),  
  284. 'css' => 'max-width:150px;',  
  285. 'class' => 'error_display_type_option, wc-enhanced-select',  
  286. 'options' => array( 
  287. 'detailed' => __('Detailed', 'paypal-for-woocommerce'),  
  288. 'generic' => __('Generic', 'paypal-for-woocommerce') 
  289. ),  
  290. 'description' => __('Detailed displays actual errors returned from PayPal. Generic displays general errors that do not reveal details 
  291. and helps to prevent fraudulant activity on your site.', 'paypal-for-woocommerce') 
  292. ),  
  293. 'payment_action' => array( 
  294. 'title' => __('Payment Action', 'paypal-for-woocommerce'),  
  295. 'label' => __('Whether to process as a Sale or Authorization.', 'paypal-for-woocommerce'),  
  296. 'description' => __('Sale will capture the funds immediately when the order is placed. Authorization will authorize the payment but will not capture the funds. You would need to capture funds from within the WooCommerce order when you are ready to deliver.'),  
  297. 'type' => 'select',  
  298. 'css' => 'max-width:150px;',  
  299. 'class' => 'wc-enhanced-select',  
  300. 'options' => array( 
  301. 'Sale' => 'Sale',  
  302. 'Authorization' => 'Authorization',  
  303. ),  
  304. 'default' => 'Sale' 
  305. ),  
  306. 'send_items' => array( 
  307. 'title' => __('Send Item Details', 'paypal-for-woocommerce'),  
  308. 'label' => __('Send line item details to PayPal', 'paypal-for-woocommerce'),  
  309. 'type' => 'checkbox',  
  310. 'description' => __('Include all line item details in the payment request to PayPal so that they can be seen from the PayPal transaction details page.', 'paypal-for-woocommerce'),  
  311. 'default' => 'yes' 
  312. ),  
  313. 'enable_notifyurl' => array( 
  314. 'title' => __('Enable PayPal IPN', 'paypal-for-woocommerce'),  
  315. 'label' => __('Enable Instant Payment Notification.', 'paypal-for-woocommerce'),  
  316. 'type' => 'checkbox',  
  317. 'description' => __('', 'paypal-for-woocommerce'),  
  318. 'default' => 'no',  
  319. 'class' => 'angelleye_enable_notifyurl' 
  320. ),  
  321. 'enable_tokenized_payments' => array( 
  322. 'title' => __('Enable Tokenized Payments', 'paypal-for-woocommerce'),  
  323. 'label' => __('Enable Tokenized Payments', 'paypal-for-woocommerce'),  
  324. 'type' => 'checkbox',  
  325. 'description' => __('Allow buyers to securely save payment details to their account for quick checkout / auto-ship orders in the future.', 'paypal-for-woocommerce'),  
  326. 'default' => 'no',  
  327. 'class' => 'enable_tokenized_payments' 
  328. ),  
  329. 'notifyurl' => array( 
  330. 'title' => __('PayPal IPN URL', 'paypal-for-woocommerce'),  
  331. 'type' => 'text',  
  332. 'description' => __('Your URL for receiving Instant Payment Notification (IPN) about transactions.', 'paypal-for-woocommerce'),  
  333. 'class' => 'angelleye_notifyurl' 
  334. ),  
  335. 'fraud_management_filters' => array( 
  336. 'title' => __('Fraud Management Filters ', 'paypal-for-woocommerce'),  
  337. 'label' => '',  
  338. 'description' => __('Choose how you would like to handle orders when Fraud Management Filters are flagged.', 'paypal-for-woocommerce'),  
  339. 'type' => 'select',  
  340. 'class' => '',  
  341. 'options' => array( 
  342. 'ignore_warnings_and_proceed_as_usual' => __('Ignore warnings and proceed as usual.', 'paypal-for-woocommerce'),  
  343. 'place_order_on_hold_for_further_review' => __('Place order On Hold for further review.', 'paypal-for-woocommerce'),  
  344. ),  
  345. 'default' => 'place_order_on_hold_for_further_review',  
  346. 'desc_tip' => true,  
  347. ),  
  348. 'enable_cardholder_first_last_name' => array( 
  349. 'title' => __('Enable Cardholder Name', 'paypal-for-woocommerce'),  
  350. 'label' => __('Adds fields for "card holder name" to checkout in addition to the "billing name" fields.', 'paypal-for-woocommerce'),  
  351. 'type' => 'checkbox',  
  352. 'description' => __('Display card holder first and last name in credit card form.', 'paypal-for-woocommerce'),  
  353. 'default' => 'no',  
  354. 'desc_tip' => true,  
  355. ),  
  356. 'avs_cvv2_result_admin_email' => array( 
  357. 'title' => __('AVS / CVV2 Results in Admin Order Email', 'paypal-for-woocommerce'),  
  358. 'label' => __('Adds the AVS / CVV2 results to the admin order email notification.', 'paypal-for-woocommerce'),  
  359. 'type' => 'checkbox',  
  360. 'description' => __('Display Address Verification Result (AVS) and Card Security Code Result (CVV2) Results in Admin Order Email.', 'paypal-for-woocommerce'),  
  361. 'default' => 'no',  
  362. 'desc_tip' => true,  
  363. ),  
  364. 'softdescriptor' => array( 
  365. 'title' => __('Credit Card Statement Name', 'paypal-for-woocommerce'),  
  366. 'type' => 'text',  
  367. 'description' => __('The value entered here will be displayed on the buyer\'s credit card statement.', 'paypal-for-woocommerce'),  
  368. 'default' => '',  
  369. 'desc_tip' => true,  
  370. ),  
  371. 'credit_card_month_field' => array( 
  372. 'title' => __('Credit Card Month Format', 'paypal-for-woocommerce'),  
  373. 'label' => __('Credit Card Month Display Format.', 'paypal-for-woocommerce'),  
  374. 'description' => __('Choose whether you wish to display Name format or Number format of Month field in the credit card form.'),  
  375. 'type' => 'select',  
  376. 'css' => 'max-width:200px;',  
  377. 'class' => 'wc-enhanced-select',  
  378. 'options' => array( 
  379. 'numbers' => 'Numbers',  
  380. 'names' => 'Names',  
  381. ),  
  382. 'default' => 'names' 
  383. ),  
  384. 'credit_card_year_field' => array( 
  385. 'title' => __('Credit Card Year Format', 'paypal-for-woocommerce'),  
  386. 'label' => __('Credit Card Year Display Format.', 'paypal-for-woocommerce'),  
  387. 'description' => __('Choose whether you wish to display two digit format or four digit of Year field in the credit card form.'),  
  388. 'type' => 'select',  
  389. 'css' => 'max-width:200px;',  
  390. 'class' => 'wc-enhanced-select',  
  391. 'options' => array( 
  392. 'two_digit' => 'Show Two Digit Years',  
  393. 'four_digit' => 'Show Four Digit Years',  
  394. ),  
  395. 'default' => 'four_digit' 
  396. ),  
  397. 'debug' => array( 
  398. 'title' => __('Debug Log', 'paypal-for-woocommerce'),  
  399. 'type' => 'checkbox',  
  400. 'label' => __('Enable logging', 'paypal-for-woocommerce'),  
  401. 'default' => 'no',  
  402. 'description' => sprintf( __( 'Log PayPal events, inside <code>%s</code>', 'paypal-for-woocommerce' ), wc_get_log_file_path( 'paypal-pro' ) ) 
  403. ),  
  404. 'is_encrypt' => array( 
  405. 'title' => __('', 'paypal-for-woocommerce'),  
  406. 'label' => __('', 'paypal-for-woocommerce'),  
  407. 'type' => 'hidden',  
  408. 'default' => 'yes',  
  409. 'class' => '' 
  410. ); 
  411. $this->form_fields = apply_filters('angelleye_pc_form_fields', $this->form_fields); 
  412.  
  413. /** 
  414. * Check if this gateway is enabled and available in the user's country 
  415. * 
  416. * This method no is used anywhere??? put above but need a fix below 
  417. */ 
  418. function is_available() { 
  419. if ($this->enabled == "yes") : 
  420. if ($this->testmode == false && get_option('woocommerce_force_ssl_checkout') == 'no' && !class_exists('WordPressHTTPS')) return false; 
  421. // Currency check 
  422. if (!in_array(get_woocommerce_currency(), apply_filters('woocommerce_paypal_pro_supported_currencies', array('AUD', 'CAD', 'CZK', 'DKK', 'EUR', 'HUF', 'JPY', 'NOK', 'NZD', 'PLN', 'GBP', 'SGD', 'SEK', 'CHF', 'USD')))) return false; 
  423. // Required fields check 
  424. if (!$this->api_username || !$this->api_password || !$this->api_signature) return false; 
  425. return isset($this->available_card_types[WC()->countries->get_base_country()]); 
  426. endif; 
  427. return false; 
  428.  
  429. /** 
  430. * Add a log entry 
  431. */ 
  432. public function log($message) { 
  433. if ($this->debug) { 
  434. if (!isset($this->log)) { 
  435. $this->log = new WC_Logger(); 
  436. $this->log->add('paypal-pro', $message); 
  437.  
  438. /** 
  439. * Payment form on checkout page 
  440. */ 
  441. public function payment_fields() { 
  442. do_action('before_angelleye_pc_payment_fields', $this); 
  443. if ($this->description) { 
  444. echo '<p>' . wp_kses_post($this->description); 
  445. if ($this->testmode == true) { 
  446. echo '<p>'; 
  447. _e('NOTICE: SANDBOX (TEST) MODE ENABLED.', 'paypal-for-woocommerce'); 
  448. echo '<br />'; 
  449. _e('For testing purposes you can use the card number 4916311462114485 with any CVC and a valid expiration date.', 'paypal-for-woocommerce'); 
  450. echo '</p>'; 
  451. parent::payment_fields(); 
  452. do_action('payment_fields_saved_payment_methods', $this); 
  453.  
  454. public function paypal_for_woocommerce_paypal_pro_credit_card_form_expiration_date_selectbox($class) { 
  455. $form_html = ""; 
  456. $form_html .= '<p class="' . $class . '">'; 
  457. $form_html .= '<label for="cc-expire-month">' . __("Expiration Date", 'paypal-for-woocommerce') . '<span class="required">*</span></label>'; 
  458. $form_html .= '<select name="paypal_pro_card_expiration_month" id="cc-expire-month" class="woocommerce-select woocommerce-cc-month mr5">'; 
  459. $form_html .= '<option value="">' . __('Month', 'paypal-for-woocommerce') . '</option>'; 
  460. $months = array(); 
  461. for ($i = 1; $i <= 12; $i++) : 
  462. $timestamp = mktime(0, 0, 0, $i, 1); 
  463. $months[date('n', $timestamp)] = date_i18n(_x('F', 'Month Names', 'paypal-for-woocommerce'), $timestamp); 
  464. endfor; 
  465. foreach ($months as $num => $name) { 
  466. if($this->credit_card_month_field == 'names') { 
  467. $form_html .= '<option value=' . $num . '>' . $name . '</option>'; 
  468. } else { 
  469. $month_value = ($num < 10) ? '0'.$num : $num; 
  470. $form_html .= '<option value=' . $num . '>' . $month_value . '</option>'; 
  471. $form_html .= '</select>'; 
  472. $form_html .= '<select name="paypal_pro_card_expiration_year" id="cc-expire-year" class="woocommerce-select woocommerce-cc-year ml5">'; 
  473. $form_html .= '<option value="">' . __('Year', 'paypal-for-woocommerce') . '</option>'; 
  474. for ($i = date('y'); $i <= date('y') + 15; $i++) { 
  475. if($this->credit_card_year_field == 'four_digit') { 
  476. $form_html .= '<option value=' . $i . '>20' . $i . '</option>'; 
  477. } else { 
  478. $form_html .= '<option value=' . $i . '>' . $i . '</option>'; 
  479. $form_html .= '</select>'; 
  480. $form_html .= '</p>'; 
  481. return $form_html; 
  482.  
  483.  
  484. /** 
  485. * Format and get posted details 
  486. * @return object 
  487. */ 
  488. private function get_posted_card() { 
  489. $card_number = isset($_POST['paypal_pro-card-number']) ? wc_clean($_POST['paypal_pro-card-number']) : ''; 
  490. $card_cvc = isset($_POST['paypal_pro-card-cvc']) ? wc_clean($_POST['paypal_pro-card-cvc']) : ''; 
  491. $card_exp_month = isset($_POST['paypal_pro_card_expiration_month']) ? wc_clean($_POST['paypal_pro_card_expiration_month']) : ''; 
  492. $card_exp_year = isset($_POST['paypal_pro_card_expiration_year']) ? wc_clean($_POST['paypal_pro_card_expiration_year']) : ''; 
  493.  
  494. // Format values 
  495. $card_number = str_replace(array(' ', '-'), '', $card_number); 
  496.  
  497. if (isset($_POST['paypal_pro-card-startdate'])) { 
  498. $card_start = wc_clean($_POST['paypal_pro-card-startdate']); 
  499. $card_start = array_map('trim', explode('/', $card_start)); 
  500. $card_start_month = str_pad($card_start[0], 2, "0", STR_PAD_LEFT); 
  501. $card_start_year = $card_start[1]; 
  502. } else { 
  503. $card_start_month = ''; 
  504. $card_start_year = ''; 
  505.  
  506. if (strlen($card_exp_year) == 2) { 
  507. $card_exp_year += 2000; 
  508.  
  509. if (strlen($card_start_year) == 2) { 
  510. $card_start_year += 2000; 
  511.  
  512. return (object) array( 
  513. 'number' => $card_number,  
  514. 'type' => '',  
  515. 'cvc' => $card_cvc,  
  516. 'exp_month' => $card_exp_month,  
  517. 'exp_year' => $card_exp_year,  
  518. 'start_month' => $card_start_month,  
  519. 'start_year' => $card_start_year 
  520. ); 
  521.  
  522. public function validate_fields() { 
  523. try { 
  524. if (isset($_POST['wc-paypal_pro-payment-token']) && 'new' !== $_POST['wc-paypal_pro-payment-token']) { 
  525. $token_id = wc_clean($_POST['wc-paypal_pro-payment-token']); 
  526. $token = WC_Payment_Tokens::get($token_id); 
  527. if ($token->get_user_id() !== get_current_user_id()) { 
  528. throw new Exception(__('Error processing checkout. Please try again.', 'paypal-for-woocommerce')); 
  529. } else { 
  530. return true; 
  531. $card = $this->get_posted_card(); 
  532. do_action('before_angelleye_pro_checkout_validate_fields', $card->type, $card->number, $card->cvc, $card->exp_month, $card->exp_year); 
  533. if (empty($card->exp_month) || empty($card->exp_year)) { 
  534. throw new Exception(__('Card expiration date is invalid', 'paypal-for-woocommerce')); 
  535.  
  536. // Validate values 
  537. if (!ctype_digit($card->cvc)) { 
  538. throw new Exception(__('Card security code is invalid (only digits are allowed)', 'paypal-for-woocommerce')); 
  539.  
  540. if ( 
  541. !ctype_digit($card->exp_month) || 
  542. !ctype_digit($card->exp_year) || 
  543. $card->exp_month > 12 || 
  544. $card->exp_month < 1 || 
  545. $card->exp_year < date('y') 
  546. ) { 
  547. throw new Exception(__('Card expiration date is invalid', 'paypal-for-woocommerce')); 
  548.  
  549. if (empty($card->number) || !ctype_digit($card->number)) { 
  550. throw new Exception(__('Card number is invalid', 'paypal-for-woocommerce')); 
  551.  
  552. $card_type = AngellEYE_Utility::card_type_from_account_number($card->number); 
  553.  
  554. if ($card_type == 'amex' && (get_woocommerce_currency() != 'USD' && get_woocommerce_currency() != 'AUD')) { 
  555. throw new Exception(__('Your processor is unable to process the Card Type in the currency requested. Please try another card type', 'paypal-for-woocommerce')); 
  556.  
  557. do_action('after_angelleye_pro_checkout_validate_fields', $card->type, $card->number, $card->cvc, $card->exp_month, $card->exp_year); 
  558. return true; 
  559.  
  560. } catch (Exception $e) { 
  561. wc_add_notice($e->getMessage(), 'error'); 
  562. return false; 
  563.  
  564.  
  565. /** 
  566. * Process the payment 
  567. */ 
  568. function process_payment($order_id) { 
  569. $order = new WC_Order($order_id); 
  570.  
  571. $this->log('Processing order #' . $order_id); 
  572.  
  573. $card = $this->get_posted_card(); 
  574.  
  575.  
  576. /** 
  577. * 3D Secure Handling 
  578. */ 
  579. if ($this->enable_3dsecure) { 
  580. if (!class_exists('CentinelClient')) include_once('lib/CentinelClient.php'); 
  581. $this->clear_centinel_session(); 
  582. $this->centinel_client = new CentinelClient; 
  583. $this->centinel_client->add("MsgType", "cmpi_lookup"); 
  584. $this->centinel_client->add("Version", "1.7"); 
  585. $this->centinel_client->add("ProcessorId", $this->centinel_pid); 
  586. $this->centinel_client->add("MerchantId", $this->centinel_mid); 
  587. $this->centinel_client->add("TransactionPwd", $this->centinel_pwd); 
  588. $this->centinel_client->add("TransactionType", 'C'); 
  589. $this->centinel_client->add('OrderNumber', $order_id); 
  590. $this->centinel_client->add('Amount', $order->get_total() * 100); 
  591. $this->centinel_client->add('CurrencyCode', $this->iso4217[version_compare(WC_VERSION, '3.0', '<') ? $order->get_order_currency() : $order->get_currency()]); 
  592. $this->centinel_client->add('TransactionMode', 'S'); 
  593. $this->centinel_client->add('ProductCode', 'PHY'); 
  594. $this->centinel_client->add('CardNumber', $card->number); 
  595. WC()->session->set('CardNumber', $card->number); 
  596. $this->centinel_client->add('CardExpMonth', $card->exp_month); 
  597. WC()->session->set('CardExpMonth', $card->exp_month); 
  598. $this->centinel_client->add('CardExpYear', $card->exp_year); 
  599. WC()->session->set('CardExpYear', $card->exp_year); 
  600. $this->centinel_client->add('CardCode', $card->cvc); 
  601. WC()->session->set('CardCode', $card->cvc); 
  602.  
  603. $billing_first_name = version_compare( WC_VERSION, '3.0', '<' ) ? $order->billing_first_name : $order->get_billing_first_name(); 
  604. $billing_last_name = version_compare( WC_VERSION, '3.0', '<' ) ? $order->billing_last_name : $order->get_billing_last_name(); 
  605. $billing_address_1 = version_compare( WC_VERSION, '3.0', '<' ) ? $order->billing_address_1 : $order->get_billing_address_1(); 
  606. $billing_address_2 = version_compare( WC_VERSION, '3.0', '<' ) ? $order->billing_address_2 : $order->get_billing_address_2(); 
  607. $billing_city = version_compare( WC_VERSION, '3.0', '<' ) ? $order->billing_city : $order->get_billing_city(); 
  608. $billing_postcode = version_compare( WC_VERSION, '3.0', '<' ) ? $order->billing_postcode : $order->get_billing_postcode(); 
  609. $billing_country = version_compare( WC_VERSION, '3.0', '<' ) ? $order->billing_country : $order->get_billing_country(); 
  610. $billing_state = version_compare( WC_VERSION, '3.0', '<' ) ? $order->billing_state : $order->get_billing_state(); 
  611. $billing_phone = version_compare( WC_VERSION, '3.0', '<' ) ? $order->billing_phone : $order->get_billing_phone(); 
  612.  
  613. $this->centinel_client->add('BillingFirstName', $billing_first_name); 
  614. $this->centinel_client->add('BillingLastName', $billing_last_name); 
  615. $this->centinel_client->add('BillingAddress1', $billing_address_1); 
  616. $this->centinel_client->add('BillingAddress2', $billing_address_2); 
  617. $this->centinel_client->add('BillingCity', $billing_city); 
  618. $this->centinel_client->add('BillingState', $billing_state); 
  619. $this->centinel_client->add('BillingPostalCode', $billing_postcode); 
  620. $this->centinel_client->add('BillingCountryCode', $billing_country); 
  621. $this->centinel_client->add('BillingPhone', $billing_phone); 
  622. $this->centinel_client->add('ShippingFirstName', version_compare( WC_VERSION, '3.0', '<' ) ? $order->shipping_first_name : $order->get_shipping_first_name()); 
  623. $this->centinel_client->add('ShippingLastName', version_compare( WC_VERSION, '3.0', '<' ) ? $order->shipping_last_name : $order->get_shipping_last_name()); 
  624. $this->centinel_client->add('ShippingAddress1', version_compare( WC_VERSION, '3.0', '<' ) ? $order->shipping_address_1 : $order->get_shipping_address_1()); 
  625. $this->centinel_client->add('ShippingAddress2', version_compare( WC_VERSION, '3.0', '<' ) ? $order->shipping_address_2 : $order->get_shipping_address_2()); 
  626. $this->centinel_client->add('ShippingCity', version_compare( WC_VERSION, '3.0', '<' ) ? $order->shipping_city : $order->get_shipping_city()); 
  627. $this->centinel_client->add('ShippingState', version_compare( WC_VERSION, '3.0', '<' ) ? $order->shipping_state : $order->get_shipping_state()); 
  628. $this->centinel_client->add('ShippingPostalCode', version_compare( WC_VERSION, '3.0', '<' ) ? $order->shipping_postcode : $order->get_shipping_postcode()); 
  629. $this->centinel_client->add('ShippingCountryCode', version_compare( WC_VERSION, '3.0', '<' ) ? $order->shipping_country : $order->get_shipping_country()); 
  630.  
  631. // Items 
  632. $item_loop = 0; 
  633. if (sizeof($order->get_items()) > 0) { 
  634. foreach ($order->get_items() as $item) { 
  635. $item_loop++; 
  636. $this->centinel_client->add('Item_Name_' . $item_loop, $item['name']); 
  637. $this->centinel_client->add('Item_Price_' . $item_loop, number_format($order->get_item_total($item, true, true) * 100), 2, '.', ''); 
  638. $this->centinel_client->add('Item_Quantity_' . $item_loop, $item['qty']); 
  639. $this->centinel_client->add('Item_Desc_' . $item_loop, $item['name']); 
  640.  
  641. // Send request 
  642. $this->centinel_client->sendHttp($this->centinel_url, "5000", "15000"); 
  643.  
  644. $this->log('Centinal client request: ' . print_r($this->centinel_client->request, true)); 
  645. $this->log('Centinal client response: ' . print_r($this->centinel_client->response, true)); 
  646.  
  647.  
  648. // Save response in session 
  649. WC()->session->set('Centinel_ErrorNo', $this->get_centinel_value("ErrorNo")); 
  650. WC()->session->set('Centinel_ErrorDesc', $this->get_centinel_value("ErrorDesc")); 
  651. WC()->session->set('Centinel_TransactionId', $this->get_centinel_value("TransactionId")); 
  652. WC()->session->set('Centinel_OrderId', $this->get_centinel_value("OrderId")); 
  653. WC()->session->set('Centinel_Enrolled', $this->get_centinel_value("Enrolled")); 
  654. WC()->session->set('Centinel_ACSUrl', $this->get_centinel_value("ACSUrl")); 
  655. WC()->session->set('Centinel_Payload', $this->get_centinel_value("Payload")); 
  656. WC()->session->set('Centinel_EciFlag', $this->get_centinel_value("EciFlag")); 
  657. WC()->session->set('Centinel_card_start_month', $card->start_month); 
  658. WC()->session->set('Centinel_card_start_year', $card->start_year); 
  659.  
  660.  
  661. if ($this->get_centinel_value("ErrorNo")) { 
  662. wc_add_notice(apply_filters('angelleye_pc_process_payment_authentication', __('Error in 3D secure authentication: ', 'woocommerce-gateway-paypal-pro') . $this->get_centinel_value("ErrorDesc")), 'error'); 
  663. return; 
  664.  
  665. if ('Y' === $this->get_centinel_value("Enrolled")) { 
  666. $this->log('Doing 3dsecure payment authorization'); 
  667. $this->log('ASCUrl: ' . $this->get_centinel_value("ACSUrl")); 
  668. $this->log('PaReq: ' . $this->get_centinel_value("Payload")); 
  669.  
  670. return array( 
  671. 'result' => 'success',  
  672. 'redirect' => add_query_arg(array('acs' => $order_id), WC()->api_request_url('WC_Gateway_PayPal_Pro_AngellEYE', is_ssl())) 
  673. ); 
  674. } elseif ($this->liability_shift && 'N' !== $this->get_centinel_value("Enrolled")) { 
  675. wc_add_notice(apply_filters('angelleye_pc_process_payment_authentication_unavailable', __('Authentication unavailable. Please try a different payment method or card.', 'woocommerce-gateway-paypal-pro')), 'error'); 
  676. return; 
  677.  
  678. // Do payment with paypal 
  679. return $this->do_payment($order, $card->number, $card->type, $card->exp_month, $card->exp_year, $card->cvc, '', '', '', '', '', $card->start_month, $card->start_year); 
  680.  
  681.  
  682. /** 
  683. * Auth 3dsecure 
  684. */ 
  685. public function handle_3dsecure() { 
  686. if (!empty($_GET['acs'])) { 
  687. $order_id = wc_clean($_GET['acs']); 
  688. $acsurl = WC()->session->get('Centinel_ACSUrl'); 
  689. $payload = WC()->session->get('Centinel_Payload'); 
  690. ?> 
  691. <html> 
  692. <head> 
  693. <title>3DSecure Payment Authorisation</title> 
  694. </head> 
  695. <body> 
  696. <form name="frmLaunchACS" id="3ds_submit_form" method="POST" action="<?php echo esc_url($acsurl); ?>"> 
  697. <input type="hidden" name="PaReq" value="<?php echo esc_attr($payload); ?>"> 
  698. <input type="hidden" name="TermUrl" 
  699. value="<?php echo esc_attr(WC()->api_request_url('WC_Gateway_PayPal_Pro_AngellEYE', is_ssl())); ?>"> 
  700. <input type="hidden" name="MD" value="<?php echo absint($order_id); ?>"> 
  701. <noscript> 
  702. <input type="submit" class="button" id="3ds_submit" value="Submit"/> 
  703. </noscript> 
  704. </form> 
  705. <script> 
  706. document.frmLaunchACS.submit(); 
  707. </script> 
  708. </body> 
  709. </html> 
  710. <?php 
  711. exit; 
  712. } else { 
  713. $this->authorise_3dsecure(); 
  714.  
  715. function authorise_3dsecure() { 
  716.  
  717. if (!class_exists('CentinelClient')) { 
  718. include_once('lib/CentinelClient.php'); 
  719.  
  720. $pares = !empty($_POST['PaRes']) ? $_POST['PaRes'] : ''; 
  721. $order_id = absint(!empty($_POST['MD']) ? $_POST['MD'] : 0); 
  722. $order = wc_get_order($order_id); 
  723. $redirect_url = $this->get_return_url($order); 
  724.  
  725. $this->log('authorise_3dsecure() for order ' . absint($order_id)); 
  726. $this->log('authorise_3dsecure() PARes ' . print_r($pares, true)); 
  727.  
  728. /** * *************************************************************************** */ 
  729. /** */ 
  730. /** If the PaRes is Not Empty then process the cmpi_authenticate message */ 
  731. /** */ 
  732. /** * *************************************************************************** */ 
  733. try { 
  734. // If the PaRes is Not Empty then process the cmpi_authenticate message 
  735. if (!empty($pares)) { 
  736.  
  737. $this->centinel_client = new CentinelClient; 
  738. $this->centinel_client->add('MsgType', 'cmpi_authenticate'); 
  739. $this->centinel_client->add("Version", "1.7"); 
  740. $this->centinel_client->add("ProcessorId", $this->centinel_pid); 
  741. $this->centinel_client->add("MerchantId", $this->centinel_mid); 
  742. $this->centinel_client->add("TransactionPwd", $this->centinel_pwd); 
  743. $this->centinel_client->add("TransactionType", 'C'); 
  744. $this->centinel_client->add('TransactionId', WC()->session->get('Centinel_TransactionId')); 
  745. $this->centinel_client->add('PAResPayload', $pares); 
  746. $this->centinel_client->sendHttp($this->centinel_url, "5000", "15000"); 
  747.  
  748. $response_to_log = $this->centinel_client->response; 
  749. $response_to_log['CardNumber'] = 'XXX'; 
  750. $response_to_log['CardCode'] = 'XXX'; 
  751. $this->log('Centinal transaction ID ' . WC()->session->get('Centinel_TransactionId')); 
  752. $this->log('Centinal client request : ' . print_r($this->centinel_client->request, true)); 
  753. $this->log('Centinal client response: ' . print_r($response_to_log, true)); 
  754. $this->log('3dsecure pa_res_status: ' . $this->get_centinel_value("PAResStatus")); 
  755.  
  756.  
  757. if ($this->liability_shift && ($this->get_centinel_value("EciFlag") == '07' || $this->get_centinel_value("EciFlag") == '01')) { 
  758. $order->update_status('failed', __('3D Secure error: No liability shift', 'woocommerce-gateway-paypal-pro')); 
  759. throw new Exception(apply_filters('angelleye_pc_3d_authentication_unavailable', __('Authentication unavailable. Please try a different payment method or card.', 'woocommerce-gateway-paypal-pro'))); 
  760.  
  761. if (!$this->get_centinel_value("ErrorNo") && in_array($this->get_centinel_value("PAResStatus"), array('Y', 'A', 'U')) && "Y" === $this->get_centinel_value("SignatureVerification")) { 
  762.  
  763. // If we are here we can process the card 
  764.  
  765. $card = new stdClass(); 
  766. $card->number = $this->get_centinel_value("CardNumber"); 
  767. $card->type = ''; 
  768. $card->cvc = $this->get_centinel_value("CardCode"); 
  769. $card->exp_month = $this->get_centinel_value("CardExpMonth"); 
  770. $card->exp_year = $this->get_centinel_value("CardExpYear"); 
  771. $card->start_month = WC()->session->get('Centinel_card_start_month'); 
  772. $card->start_year = WC()->session->get('Centinel_card_start_year'); 
  773.  
  774. $centinel = new stdClass(); 
  775. $centinel->paresstatus = $this->get_centinel_value("PAResStatus"); 
  776. $centinel->xid = $this->get_centinel_value("Xid"); 
  777. $centinel->cavv = $this->get_centinel_value("Cavv"); 
  778. $centinel->eciflag = $this->get_centinel_value("EciFlag"); 
  779. $centinel->enrolled = WC()->session->get('Centinel_Enrolled'); 
  780.  
  781. $this->do_payment($order, $card->number, $card->type, $card->exp_month, $card->exp_year, $card->cvc, $centinel->paresstatus, "Y", $centinel->cavv, $centinel->eciflag, $centinel->xid, $card->start_month, $card->start_year); 
  782. $this->clear_centinel_session(); 
  783. wp_redirect($redirect_url); 
  784. exit; 
  785.  
  786. } else { 
  787. $order->update_status('failed', sprintf(apply_filters('angelleye_pc_3d_secure_authentication', __('3D Secure error: %s', 'woocommerce-gateway-paypal-pro')), $this->get_centinel_value("ErrorDesc"))); 
  788. throw new Exception(__('Payer Authentication failed. Please try a different payment method.', 'woocommerce-gateway-paypal-pro')); 
  789. } catch (Exception $e) { 
  790. wc_add_notice($e->getMessage(), 'error'); 
  791. wp_redirect($order->get_checkout_payment_url(true)); 
  792. exit; 
  793.  
  794. /** 
  795. * do_payment 
  796. * 
  797. * Makes the request to PayPal's DoDirectPayment API 
  798. * 
  799. * @access public 
  800. * @param mixed $order 
  801. * @param mixed $card_number 
  802. * @param mixed $card_type 
  803. * @param mixed $card_exp_month 
  804. * @param mixed $card_exp_year 
  805. * @param mixed $card_csc 
  806. * @param string $centinelPAResStatus (default: '') 
  807. * @param string $centinelEnrolled (default: '') 
  808. * @param string $centinelCavv (default: '') 
  809. * @param string $centinelEciFlag (default: '') 
  810. * @param string $centinelXid (default: '') 
  811. * @return void 
  812. */ 
  813. function do_payment($order, $card_number, $card_type, $card_exp_month, $card_exp_year, $card_csc, $centinelPAResStatus = '', $centinelEnrolled = '', $centinelCavv = '', $centinelEciFlag = '', $centinelXid = '', $start_month = '', $start_year = '') { 
  814. /** 
  815. * Display message to user if session has expired. 
  816. */ 
  817. if (sizeof(WC()->cart->get_cart()) == 0) { 
  818. $pc_session_expired_error = apply_filters('angelleye_pc_session_expired_error', sprintf(__('Sorry, your session has expired. <a href=%s>Return to homepage →</a>', 'paypal-for-woocommerce'), '"' . home_url() . '"')); 
  819. wc_add_notice($pc_session_expired_error, "error"); 
  820.  
  821. /** 
  822. * Check if the PayPal class has already been established. 
  823. */ 
  824. if (!class_exists('Angelleye_PayPal')) { 
  825. require_once('lib/angelleye/paypal-php-library/includes/paypal.class.php'); 
  826.  
  827. /** 
  828. * Create PayPal object. 
  829. */ 
  830. $PayPalConfig = array( 
  831. 'Sandbox' => $this->testmode,  
  832. 'APIUsername' => $this->api_username,  
  833. 'APIPassword' => $this->api_password,  
  834. 'APISignature' => $this->api_signature,  
  835. 'Force_tls_one_point_two' => $this->Force_tls_one_point_two 
  836. ); 
  837. $PayPal = new Angelleye_PayPal($PayPalConfig); 
  838.  
  839. if (empty($GLOBALS['wp_rewrite'])) { 
  840. $GLOBALS['wp_rewrite'] = new WP_Rewrite(); 
  841.  
  842. if(!empty($_POST['paypal_pro-card-cardholder-first'])) { 
  843. $firstname = wc_clean($_POST['paypal_pro-card-cardholder-first']); 
  844. } else { 
  845. $firstname = version_compare( WC_VERSION, '3.0', '<' ) ? $order->billing_first_name : $order->get_billing_first_name(); 
  846. }  
  847.  
  848. if(!empty($_POST['paypal_pro-card-cardholder-last'])) { 
  849. $lastname = wc_clean($_POST['paypal_pro-card-cardholder-last']); 
  850. } else { 
  851. $lastname = version_compare( WC_VERSION, '3.0', '<' ) ? $order->billing_last_name : $order->get_billing_last_name(); 
  852.  
  853. $card_exp = $card_exp_month . $card_exp_year; 
  854.  
  855. /** 
  856. * Generate PayPal request 
  857. */ 
  858. $DPFields = array( 
  859. 'paymentaction' => ($order->get_total() > 0) ? $this->payment_action : 'Authorization', // How you want to obtain payment. Authorization indidicates the payment is a basic auth subject to settlement with Auth & Capture. Sale indicates that this is a final sale for which you are requesting payment. Default is Sale. 
  860. 'ipaddress' => $this->get_user_ip(), // Required. IP address of the payer's browser. 
  861. 'returnfmfdetails' => '1' // Flag to determine whether you want the results returned by FMF. 1 or 0. Default is 0. 
  862. ); 
  863.  
  864.  
  865. $CCDetails = array( 
  866. 'creditcardtype' => $card_type, // Required. Type of credit card. Visa, MasterCard, Discover, Amex, Maestro, Solo. If Maestro or Solo, the currency code must be GBP. In addition, either start date or issue number must be specified. 
  867. 'acct' => $card_number, // Required. Credit card number. No spaces or punctuation. 
  868. 'expdate' => $card_exp, // Required. Credit card expiration date. Format is MMYYYY 
  869. 'cvv2' => $card_csc, // Requirements determined by your PayPal account settings. Security digits for credit card. 
  870. 'startdate' => $start_month . $start_year, // Month and year that Maestro or Solo card was issued. MMYYYY 
  871. 'issuenumber' => '' // Issue number of Maestro or Solo card. Two numeric digits max. 
  872. ); 
  873.  
  874.  
  875. $order_id = version_compare(WC_VERSION, '3.0', '<') ? $order->id : $order->get_id(); 
  876. $billing_address_1 = version_compare( WC_VERSION, '3.0', '<' ) ? $order->billing_address_1 : $order->get_billing_address_1(); 
  877. $billing_address_2 = version_compare( WC_VERSION, '3.0', '<' ) ? $order->billing_address_2 : $order->get_billing_address_2(); 
  878. $billing_city = version_compare( WC_VERSION, '3.0', '<' ) ? $order->billing_city : $order->get_billing_city(); 
  879. $billing_postcode = version_compare( WC_VERSION, '3.0', '<' ) ? $order->billing_postcode : $order->get_billing_postcode(); 
  880. $billing_country = version_compare( WC_VERSION, '3.0', '<' ) ? $order->billing_country : $order->get_billing_country(); 
  881. $billing_state = version_compare( WC_VERSION, '3.0', '<' ) ? $order->billing_state : $order->get_billing_state(); 
  882. $billing_email = version_compare( WC_VERSION, '3.0', '<' ) ? $order->billing_email : $order->get_billing_email(); 
  883. $billing_phone = version_compare( WC_VERSION, '3.0', '<' ) ? $order->billing_phone : $order->get_billing_phone(); 
  884.  
  885.  
  886. $PayerInfo = array( 
  887. 'email' => $billing_email, // Email address of payer. 
  888. 'firstname' => $firstname, // Required. Payer's first name. 
  889. 'lastname' => $lastname // Required. Payer's last name. 
  890. ); 
  891.  
  892. $BillingAddress = array( 
  893. 'street' => $billing_address_1, // Required. First street address. 
  894. 'street2' => $billing_address_2, // Second street address. 
  895. 'city' => $billing_city, // Required. Name of City. 
  896. 'state' => $billing_state, // Required. Name of State or Province. 
  897. 'countrycode' => $billing_country, // Required. Country code. 
  898. 'zip' => $billing_postcode, // Required. Postal code of payer. 
  899. 'phonenum' => $billing_phone // Phone Number of payer. 20 char max. 
  900. ); 
  901.  
  902. $shipping_first_name = version_compare( WC_VERSION, '3.0', '<' ) ? $order->shipping_first_name : $order->get_shipping_first_name(); 
  903. $shipping_last_name = version_compare( WC_VERSION, '3.0', '<' ) ? $order->shipping_last_name : $order->get_shipping_last_name(); 
  904. $ShippingAddress = array( 
  905. 'shiptoname' => $shipping_first_name . ' ' . $shipping_last_name, // Required if shipping is included. Person's name associated with this address. 32 char max. 
  906. 'shiptostreet' => version_compare( WC_VERSION, '3.0', '<' ) ? $order->shipping_address_1 : $order->get_shipping_address_1(), // Required if shipping is included. First street address. 100 char max. 
  907. 'shiptostreet2' => version_compare( WC_VERSION, '3.0', '<' ) ? $order->shipping_address_2 : $order->get_shipping_address_2(), // Second street address. 100 char max. 
  908. 'shiptocity' => version_compare( WC_VERSION, '3.0', '<' ) ? $order->shipping_city : $order->get_shipping_city(), // Required if shipping is included. Name of city. 40 char max. 
  909. 'shiptostate' => version_compare( WC_VERSION, '3.0', '<' ) ? $order->shipping_state : $order->get_shipping_state(), // Required if shipping is included. Name of state or province. 40 char max. 
  910. 'shiptozip' => version_compare( WC_VERSION, '3.0', '<' ) ? $order->shipping_postcode : $order->get_shipping_postcode(), // Required if shipping is included. Postal code of shipping address. 20 char max. 
  911. 'shiptocountry' => version_compare( WC_VERSION, '3.0', '<' ) ? $order->shipping_country : $order->get_shipping_country(), // Required if shipping is included. Country code of shipping address. 2 char max. 
  912. 'shiptophonenum' => version_compare( WC_VERSION, '3.0', '<' ) ? $order->billing_phone : $order->get_billing_phone() // Phone number for shipping address. 20 char max. 
  913. ); 
  914.  
  915. $customer_note_value = version_compare(WC_VERSION, '3.0', '<') ? wptexturize($order->customer_note) : wptexturize($order->get_customer_note()); 
  916. $customer_note = $customer_note_value ? substr(preg_replace("/[^A-Za-z0-9 ]/", "", $customer_note_value), 0, 256) : ''; 
  917.  
  918. $PaymentDetails = array( 
  919. 'amt' => AngellEYE_Gateway_Paypal::number_format($order->get_total()), // Required. Total amount of order, including shipping, handling, and tax. 
  920. 'currencycode' => version_compare(WC_VERSION, '3.0', '<') ? $order->get_order_currency() : $order->get_currency(), // Required. Three-letter currency code. Default is USD. 
  921. 'insuranceamt' => '', // Total shipping insurance costs for this order. 
  922. 'shipdiscamt' => '0.00', // Shipping discount for the order, specified as a negative number. 
  923. 'handlingamt' => '0.00', // Total handling costs for the order. If you specify handlingamt, you must also specify itemamt. 
  924. 'desc' => '', // Description of the order the customer is purchasing. 127 char max. 
  925. 'custom' => apply_filters( 'ae_ppddp_custom_parameter', json_encode( array( 'order_id' => version_compare(WC_VERSION, '3.0', '<') ? $order->id : $order->get_id(), 'order_key' => version_compare( WC_VERSION, '3.0', '<' ) ? $order->order_key : $order->get_order_key() ) ) , $order ), // Free-form field for your own use. 256 char max. 
  926. 'invnum' => $this->invoice_id_prefix . preg_replace("/[^a-zA-Z0-9]/", "", str_replace("#", "", $order->get_order_number())), // Your own invoice or tracking number 
  927. 'recurring' => '' // Flag to indicate a recurring transaction. Value should be Y for recurring, or anything other than Y if it's not recurring. To pass Y here, you must have an established billing agreement with the buyer. 
  928. ); 
  929.  
  930. if (isset($this->notifyurl) && !empty($this->notifyurl)) { 
  931. $PaymentDetails['notifyurl'] = $this->notifyurl; 
  932.  
  933. $PaymentData = AngellEYE_Gateway_Paypal::calculate($order, $this->send_items); 
  934. $OrderItems = array(); 
  935. if ($this->send_items) { 
  936. foreach ($PaymentData['order_items'] as $item) { 
  937. $Item = array( 
  938. 'l_name' => $item['name'], // Item Name. 127 char max. 
  939. 'l_desc' => '', // Item description. 127 char max. 
  940. 'l_amt' => $item['amt'], // Cost of individual item. 
  941. 'l_number' => $item['number'], // Item Number. 127 char max. 
  942. 'l_qty' => $item['qty'], // Item quantity. Must be any positive integer. 
  943. 'l_taxamt' => '', // Item's sales tax amount. 
  944. 'l_ebayitemnumber' => '', // eBay auction number of item. 
  945. 'l_ebayitemauctiontxnid' => '', // eBay transaction ID of purchased item. 
  946. 'l_ebayitemorderid' => '' // eBay order ID for the item. 
  947. ); 
  948. array_push($OrderItems, $Item); 
  949.  
  950. //fix: itemamt = 0, make shipping or tax as order item 
  951. if ($PaymentData['itemamt'] == 0 && $PaymentData['shippingamt'] > 0) { 
  952. $OrderItems = array(); 
  953.  
  954. $Item = array( 
  955. 'l_name' => __(apply_filters('angelleye_paypal_pro_shipping_text', 'Shipping'), 'paypal-for-woocommerce'), // Item Name. 127 char max. 
  956. 'l_desc' => '', // Item description. 127 char max. 
  957. 'l_amt' => $PaymentData['shippingamt'], // Cost of individual item. 
  958. 'l_number' => '', // Item Number. 127 char max. 
  959. 'l_qty' => 1, // Item quantity. Must be any positive integer. 
  960. 'l_taxamt' => '', // Item's sales tax amount. 
  961. 'l_ebayitemnumber' => '', // eBay auction number of item. 
  962. 'l_ebayitemauctiontxnid' => '', // eBay transaction ID of purchased item. 
  963. 'l_ebayitemorderid' => '' // eBay order ID for the item. 
  964. ); 
  965. array_push($OrderItems, $Item); 
  966.  
  967.  
  968. if ($PaymentData['taxamt'] > 0) { 
  969. $Item = array( 
  970. 'l_name' => __(apply_filters('angelleye_paypal_pro_tax_text', 'Tax'), 'paypal-for-woocommerce'), // Item Name. 127 char max. 
  971. 'l_desc' => '', // Item description. 127 char max. 
  972. 'l_amt' => $PaymentData['taxamt'], // Cost of individual item. 
  973. 'l_number' => '', // Item Number. 127 char max. 
  974. 'l_qty' => 1, // Item quantity. Must be any positive integer. 
  975. 'l_taxamt' => '', // Item's sales tax amount. 
  976. 'l_ebayitemnumber' => '', // eBay auction number of item. 
  977. 'l_ebayitemauctiontxnid' => '', // eBay transaction ID of purchased item. 
  978. 'l_ebayitemorderid' => '' // eBay order ID for the item. 
  979. ); 
  980. array_push($OrderItems, $Item); 
  981.  
  982. $PaymentDetails['itemamt'] = AngellEYE_Gateway_Paypal::number_format($order->get_total()); 
  983. } else { 
  984. /** 
  985. * Shipping/tax/item amount 
  986. */ 
  987. $PaymentDetails['taxamt'] = $PaymentData['taxamt']; 
  988. $PaymentDetails['shippingamt'] = $PaymentData['shippingamt']; 
  989. $PaymentDetails['itemamt'] = $PaymentData['itemamt']; 
  990.  
  991. /** 
  992. * 3D Secure Params 
  993. */ 
  994. if ($this->enable_3dsecure) { 
  995. $Secure3D = array( 
  996. 'authstatus3ds' => $centinelPAResStatus,  
  997. 'mpivendor3ds' => $centinelEnrolled,  
  998. 'cavv' => $centinelCavv,  
  999. 'eci3ds' => $centinelEciFlag,  
  1000. 'xid' => $centinelXid 
  1001. ); 
  1002. } else { 
  1003. $Secure3D = array(); 
  1004.  
  1005. $PayPalRequestData = array( 
  1006. 'DPFields' => $DPFields,  
  1007. 'CCDetails' => $CCDetails,  
  1008. 'PayerInfo' => $PayerInfo,  
  1009. 'BillingAddress' => $BillingAddress,  
  1010. 'ShippingAddress' => $ShippingAddress,  
  1011. 'PaymentDetails' => $PaymentDetails,  
  1012. 'OrderItems' => $OrderItems,  
  1013. 'Secure3D' => $Secure3D 
  1014. ); 
  1015.  
  1016. $log = $PayPalRequestData; 
  1017. $log['CCDetails']['acct'] = empty($log['CCDetails']['acct']) ? '****' : ''; 
  1018. $log['CCDetails']['cvv2'] = empty($log['CCDetails']['cvv2']) ? '****' : ''; 
  1019. $this->log('Do payment request ' . print_r($log, true)); 
  1020.  
  1021. if (!empty($_POST['wc-paypal_pro-payment-token']) && $_POST['wc-paypal_pro-payment-token'] != 'new') { 
  1022. $token_id = wc_clean($_POST['wc-paypal_pro-payment-token']); 
  1023. $token = WC_Payment_Tokens::get($token_id); 
  1024. unset($PayPalRequestData['DPFields']); 
  1025. $PayPalRequestData['DRTFields'] = array( 
  1026. 'referenceid' => $token->get_token(),  
  1027. 'paymentaction' => ($order->get_total() > 0) ? $this->payment_action : 'Authorization',  
  1028. 'returnfmfdetails' => '1',  
  1029. 'softdescriptor' => $this->softdescriptor 
  1030. ); 
  1031. $PayPalResult = $PayPal->DoReferenceTransaction(apply_filters('angelleye_woocommerce_paypal_pro_do_reference_transaction_request_args', $PayPalRequestData)); 
  1032. } else { 
  1033. $PayPalResult = $PayPal->DoDirectPayment(apply_filters('angelleye_woocommerce_paypal_pro_do_direct_payment_request_args', $PayPalRequestData)); 
  1034.  
  1035. // Pass data into class for processing with PayPal and load the response array into $PayPalResult 
  1036.  
  1037.  
  1038. /** 
  1039. * cURL Error Handling #146 
  1040. * @since 1.1.8 
  1041. */ 
  1042.  
  1043. AngellEYE_Gateway_Paypal::angelleye_paypal_for_woocommerce_curl_error_handler($PayPalResult, $methos_name = 'DoDirectPayment', $gateway = 'PayPal Website Payments Pro (DoDirectPayment)', $this->error_email_notify); 
  1044.  
  1045.  
  1046. $PayPalRequest = isset($PayPalResult['RAWREQUEST']) ? $PayPalResult['RAWREQUEST'] : ''; 
  1047. $PayPalResponse = isset($PayPalResult['RAWRESPONSE']) ? $PayPalResult['RAWRESPONSE'] : ''; 
  1048.  
  1049. $this->log('Request: ' . print_r($PayPal->NVPToArray($PayPal->MaskAPIResult($PayPalRequest)), true)); 
  1050. $this->log('Response: ' . print_r($PayPal->NVPToArray($PayPal->MaskAPIResult($PayPalResponse)), true)); 
  1051.  
  1052.  
  1053. if (empty($PayPalResult['RAWRESPONSE'])) { 
  1054. $pc_empty_response = apply_filters('ae_ppddp_paypal_response_empty_message', __('Empty PayPal response.', 'paypal-for-woocommerce'), $PayPalResult); 
  1055. throw new Exception($pc_empty_response); 
  1056.  
  1057. if ($PayPal->APICallSuccessful($PayPalResult['ACK'])) { 
  1058. // Add order note 
  1059. $order->add_order_note(sprintf(__('PayPal Pro payment completed (Transaction ID: %s, Correlation ID: %s)', 'paypal-for-woocommerce'), $PayPalResult['TRANSACTIONID'], $PayPalResult['CORRELATIONID'])); 
  1060. //$order->add_order_note("PayPal Results: ".print_r($PayPalResult, true)); 
  1061.  
  1062. /** Checkout Note */ 
  1063. if (isset($_POST) && !empty($_POST['order_comments'])) { 
  1064. // Update post 37 
  1065. $order_id = version_compare( WC_VERSION, '3.0', '<' ) ? $order->id : $order->get_id(); 
  1066. $checkout_note = array( 
  1067. 'ID' => $order_id,  
  1068. 'post_excerpt' => $_POST['order_comments'],  
  1069. ); 
  1070. wp_update_post($checkout_note); 
  1071.  
  1072. /** 
  1073. * Add order notes for AVS result 
  1074. */ 
  1075. $avs_response_code = isset($PayPalResult['AVSCODE']) ? $PayPalResult['AVSCODE'] : ''; 
  1076. $avs_response_message = $PayPal->GetAVSCodeMessage($avs_response_code); 
  1077. $avs_response_order_note = __('Address Verification Result', 'paypal-for-woocommerce'); 
  1078. $avs_response_order_note .= "\n"; 
  1079. $avs_response_order_note .= $avs_response_code; 
  1080. $avs_response_order_note .= $avs_response_message != '' ? ' - ' . $avs_response_message : ''; 
  1081. $order->add_order_note($avs_response_order_note); 
  1082. $order_id = version_compare(WC_VERSION, '3.0', '<') ? $order->id : $order->get_id(); 
  1083. $old_wc = version_compare(WC_VERSION, '3.0', '<'); 
  1084. if ($old_wc) { 
  1085. update_post_meta($order_id, '_AVSCODE', $avs_response_code); 
  1086. } else { 
  1087. update_post_meta($order->get_id(), '_AVSCODE', $avs_response_code); 
  1088. /** 
  1089. * Add order notes for CVV2 result 
  1090. */ 
  1091. $cvv2_response_code = isset($PayPalResult['CVV2MATCH']) ? $PayPalResult['CVV2MATCH'] : ''; 
  1092. $cvv2_response_message = $PayPal->GetCVV2CodeMessage($cvv2_response_code); 
  1093. $cvv2_response_order_note = __('Card Security Code Result', 'paypal-for-woocommerce'); 
  1094. $cvv2_response_order_note .= "\n"; 
  1095. $cvv2_response_order_note .= $cvv2_response_code; 
  1096. $cvv2_response_order_note .= $cvv2_response_message != '' ? ' - ' . $cvv2_response_message : ''; 
  1097. $order->add_order_note($cvv2_response_order_note); 
  1098. if ($old_wc) { 
  1099. update_post_meta($order_id, '_CVV2MATCH', $cvv2_response_code); 
  1100. update_post_meta($order_id, 'is_sandbox', $this->testmode); 
  1101. } else { 
  1102. update_post_meta($order->get_id(), '_CVV2MATCH', $cvv2_response_code); 
  1103. update_post_meta($order->get_id(), 'is_sandbox', $this->testmode); 
  1104. do_action('before_save_payment_token', $order_id); 
  1105. if(!empty($_POST['wc-paypal_pro-payment-token']) && $_POST['wc-paypal_pro-payment-token'] == 'new') { 
  1106. if(!empty($_POST['wc-paypal_pro-new-payment-method']) && $_POST['wc-paypal_pro-new-payment-method'] == true) { 
  1107. $TRANSACTIONID = $PayPalResult['TRANSACTIONID']; 
  1108. $token = new WC_Payment_Token_CC(); 
  1109. if ( is_user_logged_in() ) { 
  1110. $token->set_user_id( get_current_user_id() ); 
  1111. $token->set_token( $TRANSACTIONID ); 
  1112. $token->set_gateway_id( $this->id ); 
  1113. $token->set_card_type( AngellEYE_Utility::card_type_from_account_number($PayPalRequestData['CCDetails']['acct'])); 
  1114. $token->set_last4( substr( $PayPalRequestData['CCDetails']['acct'], -4 ) ); 
  1115. $token->set_expiry_month( substr( $PayPalRequestData['CCDetails']['expdate'], 0, 2 ) ); 
  1116. $token->set_expiry_year( substr( $PayPalRequestData['CCDetails']['expdate'], 2, 5 ) ); 
  1117. $this->save_payment_token($order, $TRANSACTIONID); 
  1118. $save_result = $token->save(); 
  1119. if ($save_result) { 
  1120. $order->add_payment_token($token); 
  1121.  
  1122. // Payment complete 
  1123. if($PayPalResult['ACK'] == 'SuccessWithWarning' && !empty($PayPalResult['L_ERRORCODE0'])) { 
  1124. if($this->fraud_management_filters == 'place_order_on_hold_for_further_review' && $PayPalResult['L_ERRORCODE0'] == '11610') { 
  1125. $error = !empty($PayPalResult['L_LONGMESSAGE0']) ? $PayPalResult['L_LONGMESSAGE0'] : $PayPalResult['L_SHORTMESSAGE0']; 
  1126. $order->update_status('on-hold', $error); 
  1127. } elseif ($PayPalResult['L_ERRORCODE0'] == '10574') { 
  1128. $error = !empty($PayPalResult['L_LONGMESSAGE0']) ? $PayPalResult['L_LONGMESSAGE0'] : $PayPalResult['L_SHORTMESSAGE0']; 
  1129. $order->add_order_note('ERROR MESSAGE: ' . $error); 
  1130. $order->payment_complete($PayPalResult['TRANSACTIONID']); 
  1131. } elseif (!empty($PayPalResult['L_ERRORCODE0'])) { 
  1132. $error = !empty($PayPalResult['L_LONGMESSAGE0']) ? $PayPalResult['L_LONGMESSAGE0'] : $PayPalResult['L_SHORTMESSAGE0']; 
  1133. $order->add_order_note('ERROR MESSAGE: ' . $error); 
  1134. $order->update_status('on-hold', $error); 
  1135. } else { 
  1136. $order->payment_complete($PayPalResult['TRANSACTIONID']); 
  1137. } else { 
  1138. $order->payment_complete($PayPalResult['TRANSACTIONID']); 
  1139.  
  1140. if ($this->payment_action == "Authorization") { 
  1141. if ($old_wc) { 
  1142. update_post_meta($order_id, '_first_transaction_id', $PayPalResult['TRANSACTIONID']); 
  1143. } else { 
  1144. update_post_meta($order->get_id(), '_first_transaction_id', $PayPalResult['TRANSACTIONID']); 
  1145. $payment_order_meta = array('_transaction_id' => $PayPalResult['TRANSACTIONID'], '_payment_action' => $this->payment_action); 
  1146. AngellEYE_Utility::angelleye_add_order_meta($order_id, $payment_order_meta); 
  1147. AngellEYE_Utility::angelleye_paypal_for_woocommerce_add_paypal_transaction($PayPalResult, $order, $this->payment_action); 
  1148. $angelleye_utility = new AngellEYE_Utility(null, null); 
  1149. $angelleye_utility->angelleye_get_transactionDetails($PayPalResult['TRANSACTIONID']); 
  1150. $order->payment_complete($PayPalResult['TRANSACTIONID']); 
  1151. $order->add_order_note('Payment Action: ' . $this->payment_action); 
  1152.  
  1153. // Remove cart 
  1154. WC()->cart->empty_cart(); 
  1155.  
  1156. // Return thank you page redirect 
  1157. return array( 
  1158. 'result' => 'success',  
  1159. 'redirect' => $this->get_return_url($order) 
  1160. ); 
  1161. } else { 
  1162. // Get error message 
  1163. $error_code = isset($PayPalResult['ERRORS'][0]['L_ERRORCODE']) ? $PayPalResult['ERRORS'][0]['L_ERRORCODE'] : ''; 
  1164. $long_message = isset($PayPalResult['ERRORS'][0]['L_LONGMESSAGE']) ? $PayPalResult['ERRORS'][0]['L_LONGMESSAGE'] : ''; 
  1165. $error_message = $error_code . '-' . $long_message; 
  1166.  
  1167. // Notice admin if has any issue from PayPal 
  1168. if ($this->error_email_notify) { 
  1169. $admin_email = get_option("admin_email"); 
  1170. $message = __("DoDirectPayment API call failed.", "paypal-for-woocommerce") . "\n\n"; 
  1171. $message .= __('Error Code: ', 'paypal-for-woocommerce') . $error_code . "\n"; 
  1172. $message .= __('Detailed Error Message: ', 'paypal-for-woocommerce') . $long_message . "\n"; 
  1173. $message .= __('User IP: ', 'paypal-for-woocommerce') . $this->get_user_ip() . "\n"; 
  1174. $message .= __('Order ID: ') . $order_id . "\n"; 
  1175. $message .= __('Customer Name: ') . $firstname . ' ' . $lastname . "\n"; 
  1176. $message .= __('Customer Email: ') . $billing_email . "\n"; 
  1177.  
  1178. $pc_error_email_message = apply_filters('ae_ppddp_error_email_message', $message, $error_code, $long_message); 
  1179. $pc_error_email_subject = apply_filters('ae_ppddp_error_email_subject', "PayPal Pro Error Notification", $error_code, $long_message); 
  1180.  
  1181. wp_mail($admin_email, $pc_error_email_subject, $pc_error_email_message); 
  1182.  
  1183.  
  1184. $this->log('Error ' . print_r($PayPalResult['ERRORS'], true)); 
  1185.  
  1186.  
  1187. $order->update_status('failed', sprintf(__('PayPal Pro payment failed (Correlation ID: %s). Payment was rejected due to an error: %s',  
  1188. 'paypal-for-woocommerce'), $PayPalResult['CORRELATIONID'], '(' . $PayPalResult['L_ERRORCODE0'] . ') ' . '"' . $error_message . '"')); 
  1189.  
  1190. // Generate error message based on Error Display Type setting 
  1191. if ($this->error_display_type == 'detailed') { 
  1192. $pc_display_type_error = __($error_message, 'paypal-for-woocommerce'); 
  1193. $pc_display_type_notice = __('Payment error:', 'paypal-for-woocommerce') . ' ' . $error_message; 
  1194. } else { 
  1195. $pc_display_type_error = __('There was a problem connecting to the payment gateway.', 'paypal-for-woocommerce'); 
  1196. $pc_display_type_notice = __('Payment error:', 'paypal-for-woocommerce') . ' ' . $error_message; 
  1197.  
  1198. $pc_display_type_error = apply_filters('ae_ppddp_error_exception', $pc_display_type_error, $error_code, $long_message); 
  1199. $pc_display_type_notice = apply_filters('ae_ppddp_error_user_display_message', $pc_display_type_notice, $error_code, $long_message); 
  1200. wc_add_notice($pc_display_type_notice, "error"); 
  1201. throw new Exception($pc_display_type_error); 
  1202.  
  1203. return; 
  1204.  
  1205. /** 
  1206. * Get user's IP address 
  1207. */ 
  1208. function get_user_ip() { 
  1209. return WC_Geolocation::get_ip_address(); 
  1210.  
  1211. /** 
  1212. * clear_centinel_session function. 
  1213. * 
  1214. * @access public 
  1215. * @return void 
  1216. */ 
  1217. function clear_centinel_session() { 
  1218. WC()->session->set('Centinel_ErrorNo', null); 
  1219. WC()->session->set('Centinel_ErrorDesc', null); 
  1220. WC()->session->set('Centinel_TransactionId', null); 
  1221. WC()->session->set('Centinel_OrderId', null); 
  1222. WC()->session->set('Centinel_Enrolled', null); 
  1223. WC()->session->set('Centinel_ACSUrl', null); 
  1224. WC()->session->set('Centinel_Payload', null); 
  1225. WC()->session->set('Centinel_EciFlag', null); 
  1226. WC()->session->set('Centinel_card_start_month', null); 
  1227. WC()->session->set('Centinel_card_start_year', null); 
  1228.  
  1229. /** 
  1230. * Process a refund if supported 
  1231. * @param int $order_id 
  1232. * @param float $amount 
  1233. * @param string $reason 
  1234. * @return bool|wp_error True or false based on success, or a WP_Error object 
  1235. */ 
  1236. public function process_refund($order_id, $amount = null, $reason = '') { 
  1237. $order = wc_get_order($order_id); 
  1238. $this->log('Begin Refund'); 
  1239. $this->log('Order ID: ' . print_r($order_id, true)); 
  1240. $this->log('Transaction ID: ' . print_r($order->get_transaction_id(), true)); 
  1241. if (!$order || !$order->get_transaction_id() || !$this->api_username || !$this->api_password || !$this->api_signature) { 
  1242. return false; 
  1243.  
  1244. /** 
  1245. * Check if the PayPal class has already been established. 
  1246. */ 
  1247. if (!class_exists('Angelleye_PayPal')) { 
  1248. require_once('lib/angelleye/paypal-php-library/includes/paypal.class.php'); 
  1249.  
  1250. /** 
  1251. * Create PayPal object. 
  1252. */ 
  1253. $PayPalConfig = array( 
  1254. 'Sandbox' => $this->testmode,  
  1255. 'APIUsername' => $this->api_username,  
  1256. 'APIPassword' => $this->api_password,  
  1257. 'APISignature' => $this->api_signature,  
  1258. 'Force_tls_one_point_two' => $this->Force_tls_one_point_two 
  1259. ); 
  1260. $PayPal = new Angelleye_PayPal($PayPalConfig); 
  1261. if ($reason) { 
  1262. if (255 < strlen($reason)) { 
  1263. $reason = substr($reason, 0, 252) . '...'; 
  1264.  
  1265. $reason = html_entity_decode($reason, ENT_NOQUOTES, 'UTF-8'); 
  1266.  
  1267. // Prepare request arrays 
  1268. $RTFields = array( 
  1269. 'transactionid' => $order->get_transaction_id(), // Required. PayPal transaction ID for the order you're refunding. 
  1270. 'payerid' => '', // Encrypted PayPal customer account ID number. Note: Either transaction ID or payer ID must be specified. 127 char max 
  1271. 'invoiceid' => '', // Your own invoice tracking number. 
  1272. 'refundtype' => $order->get_total() == $amount ? 'Full' : 'Partial', // Required. Type of refund. Must be Full, Partial, or Other. 
  1273. 'amt' => AngellEYE_Gateway_Paypal::number_format($amount), // Refund Amt. Required if refund type is Partial. 
  1274. 'currencycode' => version_compare(WC_VERSION, '3.0', '<') ? $order->get_order_currency() : $order->get_currency(), // Three-letter currency code. Required for Partial Refunds. Do not use for full refunds. 
  1275. 'note' => $reason, // Custom memo about the refund. 255 char max. 
  1276. 'retryuntil' => '', // Maximum time until you must retry the refund. Note: this field does not apply to point-of-sale transactions. 
  1277. 'refundsource' => '', // Type of PayPal funding source (balance or eCheck) that can be used for auto refund. Values are: any, default, instant, eCheck 
  1278. 'merchantstoredetail' => '', // Information about the merchant store. 
  1279. 'refundadvice' => '', // Flag to indicate that the buyer was already given store credit for a given transaction. Values are: 1/0 
  1280. 'refunditemdetails' => '', // Details about the individual items to be returned. 
  1281. 'msgsubid' => '', // A message ID used for idempotence to uniquely identify a message. 
  1282. 'storeid' => '', // ID of a merchant store. This field is required for point-of-sale transactions. 50 char max. 
  1283. 'terminalid' => '' // ID of the terminal. 50 char max. 
  1284. ); 
  1285.  
  1286. $PayPalRequestData = array('RTFields' => $RTFields); 
  1287.  
  1288. // Pass data into class for processing with PayPal and load the response array into $PayPalResult 
  1289. $PayPalResult = $PayPal->RefundTransaction(apply_filters('angelleye_woocommerce_paypal_pro_refund_request_args', $PayPalRequestData)); 
  1290.  
  1291. /** 
  1292. * cURL Error Handling #146 
  1293. * @since 1.1.8 
  1294. */ 
  1295.  
  1296. AngellEYE_Gateway_Paypal::angelleye_paypal_for_woocommerce_curl_error_handler($PayPalResult, $methos_name = 'RefundTransaction', $gateway = 'PayPal Website Payments Pro (DoDirectPayment)', $this->error_email_notify); 
  1297.  
  1298. $PayPalRequest = isset($PayPalResult['RAWREQUEST']) ? $PayPalResult['RAWREQUEST'] : ''; 
  1299. $PayPalResponse = isset($PayPalResult['RAWRESPONSE']) ? $PayPalResult['RAWRESPONSE'] : ''; 
  1300.  
  1301. $this->log('Refund Request: ' . print_r($PayPal->NVPToArray($PayPal->MaskAPIResult($PayPalRequest)), true)); 
  1302. $this->log('Refund Response: ' . print_r($PayPal->NVPToArray($PayPal->MaskAPIResult($PayPalResponse)), true)); 
  1303.  
  1304. if ($PayPal->APICallSuccessful($PayPalResult['ACK'])) { 
  1305. $order->add_order_note('Refund Transaction ID:' . $PayPalResult['REFUNDTRANSACTIONID']); 
  1306.  
  1307. $max_remaining_refund = wc_format_decimal($order->get_total() - $order->get_total_refunded()); 
  1308. if (!$max_remaining_refund > 0) { 
  1309. $order->update_status('refunded'); 
  1310.  
  1311. if (ob_get_length()) ob_end_clean(); 
  1312. return true; 
  1313. } else { 
  1314. $pc_message = apply_filters('ae_ppddp_refund_error_message', $PayPalResult['L_LONGMESSAGE0'], $PayPalResult['L_ERRORCODE'], $PayPalResult); 
  1315. return new WP_Error('ec_refund-error', $pc_message); 
  1316.  
  1317.  
  1318. public function angelleye_woocommerce_credit_card_form_start($current_id) { 
  1319. if ($this->enable_cardholder_first_last_name && $current_id == $this->id) { 
  1320. $fields['card-cardholder-first'] = '<p class="form-row form-row-first"> 
  1321. <label for="' . esc_attr($this->id) . '-card-cvc">' . __('Cardholder First Name', 'paypal-for-woocommerce') . '</label> 
  1322. <input id="' . esc_attr($this->id) . '-card-cvc" class="input-text wc-credit-card-form-cardholder" type="text" autocomplete="off" placeholder="' . esc_attr__('First Name', 'paypal-for-woocommerce') . '" name="' . $current_id . '-card-cardholder-first' . '" /> 
  1323. </p>'; 
  1324. $fields['card-cardholder-last'] = '<p class="form-row form-row-last"> 
  1325. <label for="' . esc_attr($this->id) . '-card-startdate">' . __('Cardholder Last Name', 'paypal-for-woocommerce') . '</label> 
  1326. <input id="' . esc_attr($this->id) . '-card-startdate" class="input-text wc-credit-card-form-cardholder" type="text" autocomplete="off" placeholder="' . __('Last Name', 'paypal-for-woocommerce') . '" name="' . $current_id . '-card-cardholder-last' . '" /> 
  1327. </p>'; 
  1328.  
  1329. foreach ($fields as $field) { 
  1330. echo $field; 
  1331.  
  1332. /** 
  1333. * Get and clean a value from $this->centinel_client because the SDK does a poor job of cleaning. 
  1334. * @return string 
  1335. */ 
  1336. public function get_centinel_value($key) { 
  1337. $value = $this->centinel_client->getValue($key); 
  1338. if (empty($value)) { 
  1339. $value = WC()->session->get($key); 
  1340. $value = wc_clean($value); 
  1341. return $value; 
  1342.  
  1343. public function field_name($name) { 
  1344. return ' name="' . esc_attr($this->id . '-' . $name) . '" '; 
  1345.  
  1346. public function angelleye_paypal_pro_credit_card_form_fields($default_fields, $current_gateway_id) { 
  1347. if ($current_gateway_id == $this->id) { 
  1348. $fields = array(); 
  1349. $class = 'form-row form-row-first'; 
  1350. if (isset($this->available_card_types[WC()->countries->get_base_country()]['Maestro'])) { 
  1351. $class = 'form-row form-row-last'; 
  1352. $fields = array( 
  1353. 'card-number-field' => '<p class="form-row form-row-wide"> 
  1354. <label for="' . esc_attr($this->id) . '-card-number">' . __('Card number', 'woocommerce') . ' <span class="required">*</span></label> 
  1355. <input id="' . esc_attr($this->id) . '-card-number" class="input-text wc-credit-card-form-card-number" inputmode="numeric" autocomplete="cc-number" autocorrect="no" autocapitalize="no" spellcheck="no" type="tel" placeholder="•••• •••• •••• ••••" ' . $this->field_name('card-number') . ' /> 
  1356. </p>',  
  1357. 'card-expiry-field' => $this->paypal_for_woocommerce_paypal_pro_credit_card_form_expiration_date_selectbox($class),  
  1358. '<p class="form-row form-row-last"> 
  1359. <label for="' . esc_attr($this->id) . '-card-cvc">' . __('Card Security Code', 'woocommerce') . ' <span class="required">*</span></label> 
  1360. <input id="' . esc_attr($this->id) . '-card-cvc" class="input-text wc-credit-card-form-card-cvc" inputmode="numeric" autocomplete="off" autocorrect="no" autocapitalize="no" spellcheck="no" type="tel" maxlength="4" placeholder="' . esc_attr__('CVC', 'woocommerce') . '" ' . $this->field_name('card-cvc') . ' style="width:100px" /> 
  1361. </p>',  
  1362. 'card-startdate-field' => '<p class="form-row form-row-last"> 
  1363. <label for="' . esc_attr($this->id) . '-card-startdate">' . __('Start Date (MM/YY)', 'paypal-for-woocommerce') . '</label> 
  1364. <input id="' . esc_attr($this->id) . '-card-startdate" class="input-text wc-credit-card-form-card-expiry" type="text" autocomplete="off" placeholder="' . __('MM / YY', 'paypal-for-woocommerce') . '" name="' . $this->id . '-card-startdate' . '" /> 
  1365. </p>' 
  1366. ); 
  1367.  
  1368. } else { 
  1369. $fields = array( 
  1370. 'card-number-field' => '<p class="form-row form-row-wide"> 
  1371. <label for="' . esc_attr($this->id) . '-card-number">' . __('Card number', 'woocommerce') . ' <span class="required">*</span></label> 
  1372. <input id="' . esc_attr($this->id) . '-card-number" class="input-text wc-credit-card-form-card-number" inputmode="numeric" autocomplete="cc-number" autocorrect="no" autocapitalize="no" spellcheck="no" type="tel" placeholder="•••• •••• •••• ••••" ' . $this->field_name('card-number') . ' /> 
  1373. </p>',  
  1374. 'card-expiry-field' => $this->paypal_for_woocommerce_paypal_pro_credit_card_form_expiration_date_selectbox($class),  
  1375. '<p class="form-row form-row-last"> 
  1376. <label for="' . esc_attr($this->id) . '-card-cvc">' . __('Card Security Code', 'woocommerce') . ' <span class="required">*</span></label> 
  1377. <input id="' . esc_attr($this->id) . '-card-cvc" class="input-text wc-credit-card-form-card-cvc" inputmode="numeric" autocomplete="off" autocorrect="no" autocapitalize="no" spellcheck="no" type="tel" maxlength="4" placeholder="' . esc_attr__('CVC', 'woocommerce') . '" ' . $this->field_name('card-cvc') . ' style="width:100px" /> 
  1378. </p>' 
  1379. ); 
  1380.  
  1381. return $fields; 
  1382. } else { 
  1383. return $default_fields; 
  1384.  
  1385. public function get_transaction_url($order) { 
  1386. $sandbox_transaction_url = 'https://www.sandbox.paypal.com/cgi-bin/webscr?cmd=_view-a-trans&id=%s'; 
  1387. $live_transaction_url = 'https://www.paypal.com/cgi-bin/webscr?cmd=_view-a-trans&id=%s'; 
  1388. $old_wc = version_compare( WC_VERSION, '3.0', '<' ); 
  1389. $is_sandbox = $old_wc ? get_post_meta( $order->id, 'is_sandbox', true ) : get_post_meta($order->get_id(), 'is_sandbox', true); 
  1390. if ($is_sandbox == true) { 
  1391. $this->view_transaction_url = $sandbox_transaction_url; 
  1392. } else { 
  1393. if (empty($is_sandbox)) { 
  1394. if ( $this->testmode == true ) { 
  1395. $this->view_transaction_url = $sandbox_transaction_url; 
  1396. } else { 
  1397. $this->view_transaction_url = $live_transaction_url; 
  1398. } else { 
  1399. $this->view_transaction_url = $live_transaction_url; 
  1400. return parent::get_transaction_url($order); 
  1401.  
  1402. public function paypal_pro_error_handler($request_name = '', $redirect_url = '', $result) { 
  1403. $ErrorCode = urldecode($result["L_ERRORCODE0"]); 
  1404. $ErrorShortMsg = urldecode($result["L_SHORTMESSAGE0"]); 
  1405. $ErrorLongMsg = urldecode($result["L_LONGMESSAGE0"]); 
  1406. $ErrorSeverityCode = urldecode($result["L_SEVERITYCODE0"]); 
  1407. $this->log(__($request_name . 'API call failed. ', 'paypal-for-woocommerce')); 
  1408. $this->log(__('Detailed Error Message: ', 'paypal-for-woocommerce') . $ErrorLongMsg); 
  1409. $this->log(__('Short Error Message: ', 'paypal-for-woocommerce') . $ErrorShortMsg); 
  1410. $this->log(__('Error Code: ', 'paypal-for-woocommerce') . $ErrorCode); 
  1411. $this->log(__('Error Severity Code: ', 'paypal-for-woocommerce') . $ErrorSeverityCode); 
  1412. $message = ''; 
  1413. if ($this->error_email_notify) { 
  1414. $admin_email = get_option("admin_email"); 
  1415. $message .= __($request_name . " API call failed.", "paypal-for-woocommerce") . "\n\n"; 
  1416. $message .= __('Error Code: ', 'paypal-for-woocommerce') . $ErrorCode . "\n"; 
  1417. $message .= __('Error Severity Code: ', 'paypal-for-woocommerce') . $ErrorSeverityCode . "\n"; 
  1418. $message .= __('Short Error Message: ', 'paypal-for-woocommerce') . $ErrorShortMsg . "\n"; 
  1419. $message .= __('Detailed Error Message: ', 'paypal-for-woocommerce') . $ErrorLongMsg . "\n"; 
  1420. $message .= __('User IP: ', 'paypal-for-woocommerce') . $this->get_user_ip() . "\n"; 
  1421. $error_email_notify_mes = apply_filters('ae_ppec_error_email_message', $message, $ErrorCode, $ErrorSeverityCode, $ErrorShortMsg, $ErrorLongMsg); 
  1422. $subject = "PayPal Express Checkout Error Notification"; 
  1423. $error_email_notify_subject = apply_filters('ae_ppec_error_email_subject', $subject); 
  1424. wp_mail($admin_email, $error_email_notify_subject, $error_email_notify_mes); 
  1425. if ($this->error_display_type == 'detailed') { 
  1426. $sec_error_notice = $ErrorCode . ' - ' . $ErrorLongMsg; 
  1427. $error_display_type_message = sprintf(__($sec_error_notice, 'paypal-for-woocommerce')); 
  1428. } else { 
  1429. $error_display_type_message = sprintf(__('There was a problem paying with PayPal. Please try another method.', 'paypal-for-woocommerce')); 
  1430. $error_display_type_message = apply_filters('ae_ppec_error_user_display_message', $error_display_type_message, $ErrorCode, $ErrorLongMsg); 
  1431. wc_add_notice($error_display_type_message, 'error'); 
  1432. if (!is_ajax()) { 
  1433. wp_redirect($redirect_url); 
  1434. exit; 
  1435. } else { 
  1436. return array( 
  1437. 'result' => 'fail',  
  1438. 'redirect' => $redirect_url 
  1439. ); 
  1440.  
  1441. public function add_payment_method() { 
  1442. if (!class_exists('Angelleye_PayPal')) { 
  1443. require_once('lib/angelleye/paypal-php-library/includes/paypal.class.php'); 
  1444. $this->validate_fields(); 
  1445. $card = $this->get_posted_card(); 
  1446. $PayPalConfig = array( 
  1447. 'Sandbox' => $this->testmode,  
  1448. 'APIUsername' => $this->api_username,  
  1449. 'APIPassword' => $this->api_password,  
  1450. 'APISignature' => $this->api_signature,  
  1451. 'Force_tls_one_point_two' => $this->Force_tls_one_point_two 
  1452. ); 
  1453. $PayPal = new Angelleye_PayPal($PayPalConfig); 
  1454. $DPFields = array( 
  1455. 'paymentaction' => 'Authorization',  
  1456. 'ipaddress' => $this->get_user_ip(),  
  1457. 'returnfmfdetails' => '1' 
  1458. ); 
  1459. $CCDetails = array( 
  1460. 'creditcardtype' => $card->type,  
  1461. 'acct' => $card->number,  
  1462. 'expdate' => $card->exp_month . $card->exp_year,  
  1463. 'cvv2' => $card->cvc 
  1464. ); 
  1465. $PaymentDetails = array( 
  1466. 'amt' => 0,  
  1467. 'currencycode' => get_woocommerce_currency(),  
  1468. ); 
  1469. $PayPalRequestData = array( 
  1470. 'DPFields' => $DPFields,  
  1471. 'CCDetails' => $CCDetails,  
  1472. 'PaymentDetails' => $PaymentDetails 
  1473. ); 
  1474. $result = $PayPal->DoDirectPayment(apply_filters('angelleye_woocommerce_do_direct_payment_request_args', $PayPalRequestData)); 
  1475. if ($result['ACK'] == 'Success' || $result['ACK'] == 'SuccessWithWarning') { 
  1476. $customer_id = get_current_user_id(); 
  1477. $TRANSACTIONID = $result['TRANSACTIONID']; 
  1478. $token = new WC_Payment_Token_CC(); 
  1479. $token->set_user_id( $customer_id ); 
  1480. $token->set_token( $TRANSACTIONID ); 
  1481. $token->set_gateway_id( $this->id ); 
  1482. $token->set_card_type( AngellEYE_Utility::card_type_from_account_number($PayPalRequestData['CCDetails']['acct'])); 
  1483. $token->set_last4( substr( $PayPalRequestData['CCDetails']['acct'], -4 ) ); 
  1484. $token->set_expiry_month( substr( $PayPalRequestData['CCDetails']['expdate'], 0, 2 ) ); 
  1485. $token->set_expiry_year( substr( $PayPalRequestData['CCDetails']['expdate'], 2, 5 ) ); 
  1486. $save_result = $token->save(); 
  1487. return array( 
  1488. 'result' => 'success',  
  1489. 'redirect' => wc_get_account_endpoint_url('payment-methods') 
  1490. ); 
  1491.  
  1492. } else { 
  1493. $redirect_url = wc_get_account_endpoint_url('payment-methods'); 
  1494. $this->paypal_pro_error_handler($request_name = 'DoDirectPayment', $redirect_url, $result); 
  1495.  
  1496. public function angelleye_paypal_pro_encrypt_gateway_api($settings) { 
  1497. if( !empty($settings['sandbox_api_password'])) { 
  1498. $api_password = $settings['sandbox_api_password']; 
  1499. } else { 
  1500. $api_password = $settings['api_password']; 
  1501. if(strlen($api_password) > 35 ) { 
  1502. return $settings; 
  1503. if( !empty($settings['is_encrypt']) ) { 
  1504. $gateway_settings_keys = array('sandbox_api_username', 'sandbox_api_password', 'sandbox_api_signature', 'api_username', 'api_password', 'api_signature'); 
  1505. foreach ($gateway_settings_keys as $gateway_settings_key => $gateway_settings_value) { 
  1506. if( !empty( $settings[$gateway_settings_value]) ) { 
  1507. $settings[$gateway_settings_value] = AngellEYE_Utility::crypting($settings[$gateway_settings_value], $action = 'e'); 
  1508. return $settings; 
  1509.  
  1510. public function angelleye_paypal_pro_email_instructions($order, $sent_to_admin, $plain_text = false) { 
  1511. $payment_method = version_compare( WC_VERSION, '3.0', '<' ) ? $order->payment_method : $order->get_payment_method(); 
  1512. if ( $sent_to_admin && 'paypal_pro' === $payment_method ) { 
  1513. if (!class_exists('Angelleye_PayPal')) { 
  1514. require_once('lib/angelleye/paypal-php-library/includes/paypal.class.php'); 
  1515. $PayPalConfig = array( 
  1516. 'Sandbox' => $this->testmode,  
  1517. 'APIUsername' => $this->api_username,  
  1518. 'APIPassword' => $this->api_password,  
  1519. 'APISignature' => $this->api_signature,  
  1520. 'Force_tls_one_point_two' => $this->Force_tls_one_point_two 
  1521. ); 
  1522. $PayPal = new Angelleye_PayPal($PayPalConfig); 
  1523. $old_wc = version_compare( WC_VERSION, '3.0', '<' ); 
  1524. $order_id = version_compare( WC_VERSION, '3.0', '<' ) ? $order->id : $order->get_id(); 
  1525. $avscode = $old_wc ? get_post_meta( $order->id, '_AVSCODE', true ) : get_post_meta($order->get_id(), '_AVSCODE', true); 
  1526. if ( ! empty( $avscode ) ) { 
  1527. $avs_response_message = $PayPal->GetAVSCodeMessage($avscode); 
  1528. echo '<h2 class="wc-avs-details-heading">' . __( 'Address Verification Details', 'paypal-for-woocommerce' ) . '</h2>' . PHP_EOL; 
  1529. echo '<ul class="wc-avs-details order_details avs_details">' . PHP_EOL; 
  1530. $avs_details_fields = apply_filters( 'angelleye_avs_details_fields', array( 
  1531. 'avs_response_code'=> array( 
  1532. 'label' => __( 'AVS Response Code', 'paypal-for-woocommerce' ),  
  1533. 'value' => $avscode 
  1534. ),  
  1535. 'avs_response_message' => array( 
  1536. 'label' => __( 'AVS Response Message', 'paypal-for-woocommerce' ),  
  1537. 'value' => $avs_response_message 
  1538. ), $order_id ); 
  1539. foreach ( $avs_details_fields as $field_key => $field ) { 
  1540. if ( ! empty( $field['value'] ) ) { 
  1541. echo '<li class="' . esc_attr( $field_key ) . '">' . esc_attr( $field['label'] ) . ': <strong>' . wptexturize( $field['value'] ) . '</strong></li>' . PHP_EOL; 
  1542. echo '</ul>'; 
  1543. $old_wc = version_compare( WC_VERSION, '3.0', '<' ); 
  1544. $cvvmatch = $old_wc ? get_post_meta( $order->id, '_CVV2MATCH', true ) : get_post_meta($order->get_id(), '_CVV2MATCH', true); 
  1545. if ( ! empty( $cvvmatch ) ) { 
  1546. $cvv2_response_message = $PayPal->GetCVV2CodeMessage($cvvmatch); 
  1547. echo '<h2 class="wc-cvv2-details-heading">' . __( 'Card Security Code Details', 'paypal-for-woocommerce' ) . '</h2>' . PHP_EOL; 
  1548. echo '<ul class="wc-cvv2-details order_details cvv2_details">' . PHP_EOL; 
  1549. $cvv_details_fields = apply_filters( 'angelleye_cvv2_details_fields', array( 
  1550. 'cvv2_response_code'=> array( 
  1551. 'label' => __( 'AVS Response Code', 'paypal-for-woocommerce' ),  
  1552. 'value' => $cvvmatch 
  1553. ),  
  1554. 'cvv2_response_message' => array( 
  1555. 'label' => __( 'AVS Response Message', 'paypal-for-woocommerce' ),  
  1556. 'value' => $cvv2_response_message 
  1557. ), $order_id ); 
  1558. foreach ( $cvv_details_fields as $field_key => $field ) { 
  1559. if ( ! empty( $field['value'] ) ) { 
  1560. echo '<li class="' . esc_attr( $field_key ) . '">' . esc_attr( $field['label'] ) . ': <strong>' . wptexturize( $field['value'] ) . '</strong></li>' . PHP_EOL; 
  1561.  
  1562. public function process_subscription_payment($order) { 
  1563. if (!class_exists('Angelleye_PayPal')) { 
  1564. require_once('lib/angelleye/paypal-php-library/includes/paypal.class.php'); 
  1565. $order_id = version_compare( WC_VERSION, '3.0', '<' ) ? $order->id : $order->get_id(); 
  1566. $PayPalConfig = array( 
  1567. 'Sandbox' => $this->testmode == 'yes' ? TRUE : FALSE,  
  1568. 'APIUsername' => $this->api_username,  
  1569. 'APIPassword' => $this->api_password,  
  1570. 'APISignature' => $this->api_signature,  
  1571. 'Force_tls_one_point_two' => $this->Force_tls_one_point_two 
  1572. ); 
  1573. $PayPal = new Angelleye_PayPal($PayPalConfig); 
  1574. if(!empty($_POST['paypal_pro-card-cardholder-first'])) { 
  1575. $firstname = wc_clean($_POST['paypal_pro-card-cardholder-first']); 
  1576. } else { 
  1577. $firstname = version_compare( WC_VERSION, '3.0', '<' ) ? $order->billing_first_name : $order->get_billing_first_name(); 
  1578. }  
  1579.  
  1580. if(!empty($_POST['paypal_pro-card-cardholder-last'])) { 
  1581. $lastname = wc_clean($_POST['paypal_pro-card-cardholder-last']); 
  1582. } else { 
  1583. $lastname = version_compare( WC_VERSION, '3.0', '<' ) ? $order->billing_last_name : $order->get_billing_last_name(); 
  1584. $card_exp = $card_exp_month . $card_exp_year; 
  1585. /** 
  1586. * Generate PayPal request 
  1587. */ 
  1588. $DPFields = array( 
  1589. 'paymentaction' => ($order->get_total() > 0) ? $this->payment_action : 'Authorization', // How you want to obtain payment. Authorization indidicates the payment is a basic auth subject to settlement with Auth & Capture. Sale indicates that this is a final sale for which you are requesting payment. Default is Sale. 
  1590. 'ipaddress' => $this->get_user_ip(), // Required. IP address of the payer's browser. 
  1591. 'returnfmfdetails' => '1' // Flag to determine whether you want the results returned by FMF. 1 or 0. Default is 0. 
  1592. ); 
  1593. $CCDetails = array( 
  1594. 'creditcardtype' => $card_type, // Required. Type of credit card. Visa, MasterCard, Discover, Amex, Maestro, Solo. If Maestro or Solo, the currency code must be GBP. In addition, either start date or issue number must be specified. 
  1595. 'acct' => $card_number, // Required. Credit card number. No spaces or punctuation. 
  1596. 'expdate' => $card_exp, // Required. Credit card expiration date. Format is MMYYYY 
  1597. 'cvv2' => $card_csc, // Requirements determined by your PayPal account settings. Security digits for credit card. 
  1598. 'startdate' => $start_month . $start_year, // Month and year that Maestro or Solo card was issued. MMYYYY 
  1599. 'issuenumber' => '' // Issue number of Maestro or Solo card. Two numeric digits max. 
  1600. ); 
  1601.  
  1602. $billing_company = version_compare( WC_VERSION, '3.0', '<' ) ? $order->billing_company : $order->get_billing_company(); 
  1603. $billing_address_1 = version_compare( WC_VERSION, '3.0', '<' ) ? $order->billing_address_1 : $order->get_billing_address_1(); 
  1604. $billing_address_2 = version_compare( WC_VERSION, '3.0', '<' ) ? $order->billing_address_2 : $order->get_billing_address_2(); 
  1605. $billing_city = version_compare( WC_VERSION, '3.0', '<' ) ? $order->billing_city : $order->get_billing_city(); 
  1606. $billing_postcode = version_compare( WC_VERSION, '3.0', '<' ) ? $order->billing_postcode : $order->get_billing_postcode(); 
  1607. $billing_country = version_compare( WC_VERSION, '3.0', '<' ) ? $order->billing_country : $order->get_billing_country(); 
  1608. $billing_state = version_compare( WC_VERSION, '3.0', '<' ) ? $order->billing_state : $order->get_billing_state(); 
  1609. $billing_email = version_compare( WC_VERSION, '3.0', '<' ) ? $order->billing_email : $order->get_billing_email(); 
  1610. $billing_phone = version_compare( WC_VERSION, '3.0', '<' ) ? $order->billing_phone : $order->get_billing_phone(); 
  1611.  
  1612.  
  1613. $PayerInfo = array( 
  1614. 'email' => $billing_email, // Email address of payer. 
  1615. 'firstname' => $firstname, // Required. Payer's first name. 
  1616. 'lastname' => $lastname // Required. Payer's last name. 
  1617. ); 
  1618.  
  1619. $BillingAddress = array( 
  1620. 'street' => $billing_address_1, // Required. First street address. 
  1621. 'street2' => $billing_address_2, // Second street address. 
  1622. 'city' => $billing_city, // Required. Name of City. 
  1623. 'state' => $billing_state, // Required. Name of State or Province. 
  1624. 'countrycode' => $billing_country, // Required. Country code. 
  1625. 'zip' => $billing_postcode, // Required. Postal code of payer. 
  1626. 'phonenum' => $billing_phone // Phone Number of payer. 20 char max. 
  1627. ); 
  1628.  
  1629. $shipping_first_name = version_compare( WC_VERSION, '3.0', '<' ) ? $order->shipping_first_name : $order->get_shipping_first_name(); 
  1630. $shipping_last_name = version_compare( WC_VERSION, '3.0', '<' ) ? $order->shipping_last_name : $order->get_shipping_last_name(); 
  1631. $ShippingAddress = array( 
  1632. 'shiptoname' => $shipping_first_name . ' ' . $shipping_last_name, // Required if shipping is included. Person's name associated with this address. 32 char max. 
  1633. 'shiptostreet' => version_compare( WC_VERSION, '3.0', '<' ) ? $order->shipping_address_1 : $order->get_shipping_address_1(), // Required if shipping is included. First street address. 100 char max. 
  1634. 'shiptostreet2' => version_compare( WC_VERSION, '3.0', '<' ) ? $order->shipping_address_2 : $order->get_shipping_address_2(), // Second street address. 100 char max. 
  1635. 'shiptocity' => version_compare( WC_VERSION, '3.0', '<' ) ? $order->shipping_city : $order->get_shipping_city(), // Required if shipping is included. Name of city. 40 char max. 
  1636. 'shiptostate' => version_compare( WC_VERSION, '3.0', '<' ) ? $order->shipping_state : $order->get_shipping_state(), // Required if shipping is included. Name of state or province. 40 char max. 
  1637. 'shiptozip' => version_compare( WC_VERSION, '3.0', '<' ) ? $order->shipping_postcode : $order->get_shipping_postcode(), // Required if shipping is included. Postal code of shipping address. 20 char max. 
  1638. 'shiptocountry' => version_compare( WC_VERSION, '3.0', '<' ) ? $order->shipping_country : $order->get_shipping_country(), // Required if shipping is included. Country code of shipping address. 2 char max. 
  1639. 'shiptophonenum' => version_compare( WC_VERSION, '3.0', '<' ) ? $order->billing_phone : $order->get_billing_phone() // Phone number for shipping address. 20 char max. 
  1640. ); 
  1641.  
  1642. $customer_note_value = version_compare(WC_VERSION, '3.0', '<') ? wptexturize($order->customer_note) : wptexturize($order->get_customer_note()); 
  1643. $customer_note = $customer_note_value ? substr(preg_replace("/[^A-Za-z0-9 ]/", "", $customer_note_value), 0, 256) : ''; 
  1644.  
  1645. $PaymentDetails = array( 
  1646. 'amt' => AngellEYE_Gateway_Paypal::number_format($order->get_total()), // Required. Total amount of order, including shipping, handling, and tax. 
  1647. 'currencycode' => get_woocommerce_currency(), // Required. Three-letter currency code. Default is USD. 
  1648. 'insuranceamt' => '', // Total shipping insurance costs for this order. 
  1649. 'shipdiscamt' => '0.00', // Shipping discount for the order, specified as a negative number. 
  1650. 'handlingamt' => '0.00', // Total handling costs for the order. If you specify handlingamt, you must also specify itemamt. 
  1651. 'desc' => '', // Description of the order the customer is purchasing. 127 char max. 
  1652. 'custom' => apply_filters('ae_ppddp_custom_parameter', $customer_note, $order), // Free-form field for your own use. 256 char max. 
  1653. 'invnum' => $this->invoice_id_prefix . preg_replace("/[^a-zA-Z0-9]/", "", $order_id), // Your own invoice or tracking number 
  1654. 'recurring' => '' // Flag to indicate a recurring transaction. Value should be Y for recurring, or anything other than Y if it's not recurring. To pass Y here, you must have an established billing agreement with the buyer. 
  1655. ); 
  1656. if (isset($this->notifyurl) && !empty($this->notifyurl)) { 
  1657. $PaymentDetails['notifyurl'] = $this->notifyurl; 
  1658. $PaymentData = AngellEYE_Gateway_Paypal::calculate($order, $this->send_items); 
  1659. $OrderItems = array(); 
  1660. if ($this->send_items) { 
  1661. foreach ($PaymentData['order_items'] as $item) { 
  1662. $Item = array( 
  1663. 'l_name' => $item['name'], // Item Name. 127 char max. 
  1664. 'l_desc' => '', // Item description. 127 char max. 
  1665. 'l_amt' => $item['amt'], // Cost of individual item. 
  1666. 'l_number' => $item['number'], // Item Number. 127 char max. 
  1667. 'l_qty' => $item['qty'], // Item quantity. Must be any positive integer. 
  1668. 'l_taxamt' => '', // Item's sales tax amount. 
  1669. 'l_ebayitemnumber' => '', // eBay auction number of item. 
  1670. 'l_ebayitemauctiontxnid' => '', // eBay transaction ID of purchased item. 
  1671. 'l_ebayitemorderid' => '' // eBay order ID for the item. 
  1672. ); 
  1673. array_push($OrderItems, $Item); 
  1674. //fix: itemamt = 0, make shipping or tax as order item 
  1675. if ($PaymentData['itemamt'] == 0 && $PaymentData['shippingamt'] > 0) { 
  1676. $OrderItems = array(); 
  1677. $Item = array( 
  1678. 'l_name' => __(apply_filters('angelleye_paypal_pro_shipping_text', 'Shipping'), 'paypal-for-woocommerce'), // Item Name. 127 char max. 
  1679. 'l_desc' => '', // Item description. 127 char max. 
  1680. 'l_amt' => $PaymentData['shippingamt'], // Cost of individual item. 
  1681. 'l_number' => '', // Item Number. 127 char max. 
  1682. 'l_qty' => 1, // Item quantity. Must be any positive integer. 
  1683. 'l_taxamt' => '', // Item's sales tax amount. 
  1684. 'l_ebayitemnumber' => '', // eBay auction number of item. 
  1685. 'l_ebayitemauctiontxnid' => '', // eBay transaction ID of purchased item. 
  1686. 'l_ebayitemorderid' => '' // eBay order ID for the item. 
  1687. ); 
  1688. array_push($OrderItems, $Item); 
  1689. if ($PaymentData['taxamt'] > 0) { 
  1690. $Item = array( 
  1691. 'l_name' => __(apply_filters('angelleye_paypal_pro_tax_text', 'Tax'), 'paypal-for-woocommerce'), // Item Name. 127 char max. 
  1692. 'l_desc' => '', // Item description. 127 char max. 
  1693. 'l_amt' => $PaymentData['taxamt'], // Cost of individual item. 
  1694. 'l_number' => '', // Item Number. 127 char max. 
  1695. 'l_qty' => 1, // Item quantity. Must be any positive integer. 
  1696. 'l_taxamt' => '', // Item's sales tax amount. 
  1697. 'l_ebayitemnumber' => '', // eBay auction number of item. 
  1698. 'l_ebayitemauctiontxnid' => '', // eBay transaction ID of purchased item. 
  1699. 'l_ebayitemorderid' => '' // eBay order ID for the item. 
  1700. ); 
  1701. array_push($OrderItems, $Item); 
  1702. $PaymentDetails['itemamt'] = AngellEYE_Gateway_Paypal::number_format($order->get_total()); 
  1703. } else { 
  1704. /** 
  1705. * Shipping/tax/item amount 
  1706. */ 
  1707. $PaymentDetails['taxamt'] = $PaymentData['taxamt']; 
  1708. $PaymentDetails['shippingamt'] = $PaymentData['shippingamt']; 
  1709. $PaymentDetails['itemamt'] = $PaymentData['itemamt']; 
  1710. /** 
  1711. * 3D Secure Params 
  1712. */ 
  1713. if ($this->enable_3dsecure) { 
  1714. $Secure3D = array( 
  1715. 'authstatus3ds' => $centinelPAResStatus,  
  1716. 'mpivendor3ds' => $centinelEnrolled,  
  1717. 'cavv' => $centinelCavv,  
  1718. 'eci3ds' => $centinelEciFlag,  
  1719. 'xid' => $centinelXid 
  1720. ); 
  1721. } else { 
  1722. $Secure3D = array(); 
  1723. $PayPalRequestData = array( 
  1724. 'DPFields' => $DPFields,  
  1725. 'CCDetails' => $CCDetails,  
  1726. 'PayerInfo' => $PayerInfo,  
  1727. 'BillingAddress' => $BillingAddress,  
  1728. 'ShippingAddress' => $ShippingAddress,  
  1729. 'PaymentDetails' => $PaymentDetails,  
  1730. 'OrderItems' => $OrderItems,  
  1731. 'Secure3D' => $Secure3D 
  1732. ); 
  1733. $log = $PayPalRequestData; 
  1734. $log['CCDetails']['acct'] = isset($log['CCDetails']['acct']) ? '****' : ''; 
  1735. $log['CCDetails']['cvv2'] = isset($log['CCDetails']['cvv2']) ? '****' : ''; 
  1736. $this->log('Do payment request ' . print_r($log, true)); 
  1737. if (!empty($_POST['wc-paypal_pro-payment-token']) && $_POST['wc-paypal_pro-payment-token'] != 'new') { 
  1738. $token_id = wc_clean($_POST['wc-paypal_pro-payment-token']); 
  1739. $token = WC_Payment_Tokens::get($token_id); 
  1740. unset($PayPalRequestData['DPFields']); 
  1741. $PayPalRequestData['DRTFields'] = array( 
  1742. 'referenceid' => $token->get_token(),  
  1743. 'paymentaction' => ($order->get_total() > 0) ? $this->payment_action : 'Authorization',  
  1744. 'returnfmfdetails' => '1',  
  1745. 'softdescriptor' => '' 
  1746. ); 
  1747. $PayPalResult = $PayPal->DoReferenceTransaction($PayPalRequestData); 
  1748. } else { 
  1749. $PayPalResult = $PayPal->DoDirectPayment($PayPalRequestData); 
  1750. // Pass data into class for processing with PayPal and load the response array into $PayPalResult 
  1751. /** 
  1752. * cURL Error Handling #146 
  1753. * @since 1.1.8 
  1754. */ 
  1755. AngellEYE_Gateway_Paypal::angelleye_paypal_for_woocommerce_curl_error_handler($PayPalResult, $methos_name = 'DoDirectPayment', $gateway = 'PayPal Website Payments Pro (DoDirectPayment)', $this->error_email_notify); 
  1756. $PayPalRequest = isset($PayPalResult['RAWREQUEST']) ? $PayPalResult['RAWREQUEST'] : ''; 
  1757. $PayPalResponse = isset($PayPalResult['RAWRESPONSE']) ? $PayPalResult['RAWRESPONSE'] : ''; 
  1758. $this->log('Request: ' . print_r($PayPal->NVPToArray($PayPal->MaskAPIResult($PayPalRequest)), true)); 
  1759. $this->log('Response: ' . print_r($PayPal->NVPToArray($PayPal->MaskAPIResult($PayPalResponse)), true)); 
  1760. if (empty($PayPalResult['RAWRESPONSE'])) { 
  1761. $pc_empty_response = apply_filters('ae_ppddp_paypal_response_empty_message', __('Empty PayPal response.', 'paypal-for-woocommerce'), $PayPalResult); 
  1762. throw new Exception($pc_empty_response); 
  1763. if ($PayPal->APICallSuccessful($PayPalResult['ACK'])) { 
  1764. // Add order note 
  1765. $order->add_order_note(sprintf(__('PayPal Pro payment completed (Transaction ID: %s, Correlation ID: %s)', 'paypal-for-woocommerce'), $PayPalResult['TRANSACTIONID'], $PayPalResult['CORRELATIONID'])); 
  1766. //$order->add_order_note("PayPal Results: ".print_r($PayPalResult, true)); 
  1767. /** Checkout Note */ 
  1768. if (isset($_POST) && !empty($_POST['order_comments'])) { 
  1769. // Update post 37 
  1770. $checkout_note = array( 
  1771. 'ID' => $order_id,  
  1772. 'post_excerpt' => $_POST['order_comments'],  
  1773. ); 
  1774. wp_update_post($checkout_note); 
  1775. /** 
  1776. * Add order notes for AVS result 
  1777. */ 
  1778. $avs_response_code = isset($PayPalResult['AVSCODE']) ? $PayPalResult['AVSCODE'] : ''; 
  1779. $avs_response_message = $PayPal->GetAVSCodeMessage($avs_response_code); 
  1780. $avs_response_order_note = __('Address Verification Result', 'paypal-for-woocommerce'); 
  1781. $avs_response_order_note .= "\n"; 
  1782. $avs_response_order_note .= $avs_response_code; 
  1783. $avs_response_order_note .= $avs_response_message != '' ? ' - ' . $avs_response_message : ''; 
  1784. $order->add_order_note($avs_response_order_note); 
  1785. /** 
  1786. * Add order notes for CVV2 result 
  1787. */ 
  1788. $cvv2_response_code = isset($PayPalResult['CVV2MATCH']) ? $PayPalResult['CVV2MATCH'] : ''; 
  1789. $cvv2_response_message = $PayPal->GetCVV2CodeMessage($cvv2_response_code); 
  1790. $cvv2_response_order_note = __('Card Security Code Result', 'paypal-for-woocommerce'); 
  1791. $cvv2_response_order_note .= "\n"; 
  1792. $cvv2_response_order_note .= $cvv2_response_code; 
  1793. $cvv2_response_order_note .= $cvv2_response_message != '' ? ' - ' . $cvv2_response_message : ''; 
  1794. $order->add_order_note($cvv2_response_order_note); 
  1795. $is_sandbox = $this->testmode == 'yes' ? true : false; 
  1796. update_post_meta($order_id, 'is_sandbox', $is_sandbox); 
  1797. if (!empty($_POST['wc-paypal_pro-payment-token']) && $_POST['wc-paypal_pro-payment-token'] == 'new') { 
  1798. if (!empty($_POST['wc-paypal_pro-new-payment-method']) && $_POST['wc-paypal_pro-new-payment-method'] == true) { 
  1799. $customer_id = $order->get_user_id(); 
  1800. $TRANSACTIONID = $PayPalResult['TRANSACTIONID']; 
  1801. $token = new WC_Payment_Token_CC(); 
  1802. $token->set_user_id($customer_id); 
  1803. $token->set_token($TRANSACTIONID); 
  1804. $token->set_gateway_id($this->id); 
  1805. $token->set_card_type(AngellEYE_Utility::card_type_from_account_number($PayPalRequestData['CCDetails']['acct'])); 
  1806. $token->set_last4(substr($PayPalRequestData['CCDetails']['acct'], -4)); 
  1807. $token->set_expiry_month(date('m')); 
  1808. $token->set_expiry_year(date('Y', strtotime('+2 years'))); 
  1809. $save_result = $token->save(); 
  1810. $this->save_payment_token($order, $TRANSACTIONID); 
  1811. if ($save_result) { 
  1812. $order->add_payment_token($token); 
  1813. // Payment complete 
  1814. if ($this->payment_action == "Sale") { 
  1815. $order->payment_complete($PayPalResult['TRANSACTIONID']); 
  1816. } else { 
  1817. update_post_meta($order_id, '_first_transaction_id', $PayPalResult['TRANSACTIONID']); 
  1818. $payment_order_meta = array('_transaction_id' => $PayPalResult['TRANSACTIONID'], '_payment_action' => $this->payment_action); 
  1819. AngellEYE_Utility::angelleye_add_order_meta($order_id, $payment_order_meta); 
  1820. AngellEYE_Utility::angelleye_paypal_for_woocommerce_add_paypal_transaction($PayPalResult, $order, $this->payment_action); 
  1821. $angelleye_utility = new AngellEYE_Utility(null, null); 
  1822. $angelleye_utility->angelleye_get_transactionDetails($PayPalResult['TRANSACTIONID']); 
  1823. $order->update_status('on-hold'); 
  1824. $order->add_order_note('Payment Action: ' . $this->payment_action); 
  1825. // Remove cart 
  1826. WC()->cart->empty_cart(); 
  1827. // Return thank you page redirect 
  1828. return array( 
  1829. 'result' => 'success',  
  1830. 'redirect' => $this->get_return_url($order) 
  1831. ); 
  1832. } else { 
  1833. // Get error message 
  1834. $error_code = isset($PayPalResult['ERRORS'][0]['L_ERRORCODE']) ? $PayPalResult['ERRORS'][0]['L_ERRORCODE'] : ''; 
  1835. $long_message = isset($PayPalResult['ERRORS'][0]['L_LONGMESSAGE']) ? $PayPalResult['ERRORS'][0]['L_LONGMESSAGE'] : ''; 
  1836. $error_message = $error_code . '-' . $long_message; 
  1837. // Notice admin if has any issue from PayPal 
  1838. if ($this->error_email_notify) { 
  1839. $admin_email = get_option("admin_email"); 
  1840. $message = __("DoDirectPayment API call failed.", "paypal-for-woocommerce") . "\n\n"; 
  1841. $message .= __('Error Code: ', 'paypal-for-woocommerce') . $error_code . "\n"; 
  1842. $message .= __('Detailed Error Message: ', 'paypal-for-woocommerce') . $long_message . "\n"; 
  1843. $message .= __('User IP: ', 'paypal-for-woocommerce') . $this->get_user_ip() . "\n"; 
  1844. $message .= __('Order ID: ') . $order_id . "\n"; 
  1845. $message .= __('Customer Name: ') . $firstname . ' ' . $lastname . "\n"; 
  1846. $message .= __('Customer Email: ') . $billing_email . "\n"; 
  1847. $pc_error_email_message = apply_filters('ae_ppddp_error_email_message', $message, $error_code, $long_message); 
  1848. $pc_error_email_subject = apply_filters('ae_ppddp_error_email_subject', "PayPal Pro Error Notification", $error_code, $long_message); 
  1849. wp_mail($admin_email, $pc_error_email_subject, $pc_error_email_message); 
  1850. $this->log('Error ' . print_r($PayPalResult['ERRORS'], true)); 
  1851. $order->update_status('failed', sprintf(__('PayPal Pro payment failed (Correlation ID: %s). Payment was rejected due to an error: %s', 'paypal-for-woocommerce'), $PayPalResult['CORRELATIONID'], '(' . $PayPalResult['L_ERRORCODE0'] . ') ' . '"' . $error_message . '"')); 
  1852. // Generate error message based on Error Display Type setting 
  1853. if ($this->error_display_type == 'detailed') { 
  1854. $pc_display_type_error = __($error_message, 'paypal-for-woocommerce'); 
  1855. $pc_display_type_notice = __('Payment error:', 'paypal-for-woocommerce') . ' ' . $error_message; 
  1856. } else { 
  1857. $pc_display_type_error = __('There was a problem connecting to the payment gateway.', 'paypal-for-woocommerce'); 
  1858. $pc_display_type_notice = __('Payment error:', 'paypal-for-woocommerce') . ' ' . $error_message; 
  1859. $pc_display_type_error = apply_filters('ae_ppddp_error_exception', $pc_display_type_error, $error_code, $long_message); 
  1860. $pc_display_type_notice = apply_filters('ae_ppddp_error_user_display_message', $pc_display_type_notice, $error_code, $long_message); 
  1861. wc_add_notice($pc_display_type_notice, "error"); 
  1862. throw new Exception($pc_display_type_error); 
  1863. return; 
  1864.  
  1865.  
  1866. public function save_payment_token($order, $payment_tokens_id) { 
  1867. // Store source in the order 
  1868. $order_id = version_compare( WC_VERSION, '3.0', '<' ) ? $order->id : $order->get_id(); 
  1869. if (!empty($payment_tokens_id)) { 
  1870. update_post_meta($order_id, '_payment_tokens_id', $payment_tokens_id); 
  1871.  
  1872. public function free_signup_order_payment($order_id) { 
  1873. $order = new WC_Order($order_id); 
  1874. $this->log('Processing order #' . $order_id); 
  1875. if (!empty($_POST['wc-paypal_pro-payment-token']) && $_POST['wc-paypal_pro-payment-token'] != 'new') { 
  1876. $token_id = wc_clean($_POST['wc-paypal_pro-payment-token']); 
  1877. $token = WC_Payment_Tokens::get($token_id); 
  1878. $order->payment_complete($token->get_token()); 
  1879. update_post_meta($order_id, '_first_transaction_id', $token->get_token()); 
  1880. $order->add_order_note('Payment Action: ' . $this->payment_action); 
  1881. WC()->cart->empty_cart(); 
  1882. return array( 
  1883. 'result' => 'success',  
  1884. 'redirect' => $this->get_return_url($order) 
  1885. ); 
.