MS_Gateway_Paypalstandard

Gateway: Paypal Standard.

Defined (1)

The class is defined in the following location(s).

/app/gateway/paypalstandard/class-ms-gateway-paypalstandard.php  
  1. class MS_Gateway_Paypalstandard extends MS_Gateway { 
  2.  
  3. const ID = 'paypalstandard'; 
  4.  
  5. /** 
  6. * Gateway singleton instance. 
  7. * @since 1.0.0 
  8. * @var string $instance 
  9. */ 
  10. public static $instance; 
  11.  
  12. /** 
  13. * Paypal merchant ID. 
  14. * @since 1.0.0 
  15. * @var bool $merchant_id 
  16. */ 
  17. protected $merchant_id; 
  18.  
  19. /** 
  20. * Paypal country site. 
  21. * @since 1.0.0 
  22. * @var bool $paypal_site 
  23. */ 
  24. protected $paypal_site; 
  25.  
  26. /** 
  27. * Hook to add custom transaction status. 
  28. * @since 1.0.0 
  29. */ 
  30. public function after_load() { 
  31. parent::after_load(); 
  32.  
  33. $this->id = self::ID; 
  34. $this->name = __( 'PayPal Standard Gateway', 'membership2' ); 
  35. $this->group = 'PayPal'; 
  36. $this->manual_payment = false; // Recurring charged automatically 
  37. $this->pro_rate = false; 
  38.  
  39. if ( $this->active && $this->is_live_mode() && strpos( $this->merchant_id, '@' ) ) { 
  40. $settings_url = MS_Controller_Plugin::get_admin_url( 
  41. 'settings',  
  42. array( 'tab' => MS_Controller_Settings::TAB_PAYMENT ) 
  43. ); 
  44. lib3()->ui->admin_message( 
  45. sprintf( 
  46. __( 'Warning: You use your email address for the PayPal Standard gateway instead of your Merchant ID. Please check %syour payment settings%s and enter the Merchant ID instead', 'membership2' ),  
  47. '<a href="' . $settings_url . '">',  
  48. '</a>' 
  49. ),  
  50. 'err' 
  51. ); 
  52.  
  53. /** 
  54. * Processes gateway IPN return. 
  55. * @since 1.0.0 
  56. * @param MS_Model_Transactionlog $log Optional. A transaction log item 
  57. * that will be updated instead of creating a new log entry. 
  58. */ 
  59. public function handle_return( $log = false ) { 
  60. $success = false; 
  61. $ignore = false; 
  62. $exit = false; 
  63. $redirect = false; 
  64. $notes = ''; 
  65. $status = null; 
  66. $notes_err = ''; 
  67. $notes_pay = ''; 
  68. $notes_txn = ''; 
  69. $external_id = null; 
  70. $invoice_id = 0; 
  71. $subscription_id = 0; 
  72. $amount = 0; 
  73. $transaction_type = ''; 
  74. $payment_status = ''; 
  75. $do_action = 'ignore'; 
  76. $ext_type = false; 
  77.  
  78. if ( ! empty( $_POST[ 'txn_type'] ) ) { 
  79. $transaction_type = strtolower( $_POST[ 'txn_type'] ); 
  80. if ( isset( $_POST['mc_gross'] ) ) { 
  81. $amount = (float) $_POST['mc_gross']; 
  82. } elseif ( isset( $_POST['mc_amount3'] ) ) { 
  83. // mc_amount1 and mc_amount2 are for trial period prices. 
  84. $amount = (float) $_POST['mc_amount3']; 
  85. } elseif ( isset( $_POST['amount'] ) ) { 
  86. // mc_amount1 and mc_amount2 are for trial period prices. 
  87. $amount = (float) $_POST['amount']; 
  88. if ( ! empty( $_POST[ 'payment_status'] ) ) { 
  89. $payment_status = strtolower( $_POST[ 'payment_status'] ); 
  90.  
  91. /** 
  92. * Sandbox fix 
  93. * @see https://github.com/woothemes/woocommerce/blob/fa30a38c58373d9c3706cc0b7ae22032de3a2985/includes/gateways/paypal/includes/class-wc-gateway-paypal-ipn-handler.php#L55 
  94. */ 
  95. if ( ! $this->is_live_mode() && 'pending' == $payment_status ) { 
  96. $payment_status = 'completed'; 
  97. if ( ! empty( $_POST['txn_id'] ) ) { 
  98. $external_id = $_POST['txn_id']; 
  99. if ( ! empty( $_POST['mc_currency'] ) ) { 
  100. $currency = $_POST['mc_currency']; 
  101. } elseif ( ! empty( $_POST['currency_code'] ) ) { 
  102. $currency = $_POST['currency_code']; 
  103.  
  104. // Step 1: Find the invoice_id and determine if payment is M2 or M1. 
  105. if ( $payment_status || $transaction_type ) { 
  106.  
  107. if ( ! empty( $_POST['invoice'] ) ) { 
  108. $invoice_id = intval( $_POST['invoice'] ); 
  109. } elseif ( ! empty( $_POST['rp_invoice'] ) ) { 
  110. $invoice_id = intval( $_POST['rp_invoice'] ); 
  111.  
  112. if ( $invoice_id ) { 
  113. // BEST CASE: 
  114. // 'invoice' is set in all regular M2 subscriptions! 
  115.  
  116. /** 
  117. * PayPal only knows the first invoice of the subscription. 
  118. * So we need to check: If the invoice is already paid then the 
  119. * payment is for a follow-up invoice. 
  120. */ 
  121. $invoice = MS_Factory::load( 'MS_Model_Invoice', $invoice_id ); 
  122. if ( $invoice->is_paid() ) { 
  123. $subscription = $invoice->get_subscription(); 
  124. $invoice_id = $subscription->first_unpaid_invoice(); 
  125. $invoice_id = $invoice->id; 
  126. } elseif ( ! empty( $_POST['custom'] ) ) { 
  127. // FALLBACK A: 
  128. // Maybe it's an imported M1 subscription. 
  129. $infos = explode( ':', $_POST['custom'] ); 
  130.  
  131. if ( count( $infos ) > 2 ) { 
  132. // $infos should contain [timestamp, user_id, sub_id, key] 
  133.  
  134. $m1_user_id = intval( $infos[1] ); 
  135. $m1_sub_id = intval( $infos[2] ); // Roughtly equals M2 membership->id. 
  136.  
  137. // M1 payments use the following type/status values. 
  138. $pay_types = array( 'subscr_signup', 'subscr_payment' ); 
  139. $pay_stati = array( 'completed', 'processed' ); 
  140.  
  141. if ( $m1_user_id > 0 && $m1_sub_id > 0 ) { 
  142. if ( in_array( $transaction_type, $pay_types ) ) { 
  143. $ext_type = 'm1'; 
  144. } elseif ( in_array( $payment_status, $pay_stati ) ) { 
  145. $ext_type = 'm1'; 
  146.  
  147. if ( 'm1' == $ext_type ) { 
  148. $is_linked = false; 
  149.  
  150. // Seems to be a valid M1 payment: 
  151. // Find the associated imported subscription! 
  152. $subscription = MS_Model_Import::find_subscription( 
  153. $m1_user_id,  
  154. $m1_sub_id,  
  155. 'm1',  
  156. self::ID 
  157. ); 
  158.  
  159. if ( $subscription ) { 
  160. $is_linked = true; 
  161. $invoice_id = $subscription->first_unpaid_invoice(); 
  162. } else { 
  163. $user = get_user_by( 'id', $m1_user_id ); 
  164.  
  165. if ( $user && $user->ID == $m1_user_id ) { 
  166. $membership = MS_Model_Import::membership_by_matching( 
  167. 'm1',  
  168. $m1_sub_id 
  169. ); 
  170.  
  171. if ( $membership ) { 
  172. $notes_err = sprintf( 
  173. 'User is not subscribed to Membership %s.',  
  174. $membership->id 
  175. ); 
  176. } else { 
  177. $notes_err = 'Could not determine a membership.'; 
  178. } else { 
  179. $notes_err = sprintf( 
  180. 'Could not find user with ID %s.',  
  181. $m1_user_id 
  182. ); 
  183. $ignore = true; // We cannot fix this, so ignore it. 
  184.  
  185. if ( ! $ignore && ! $is_linked && ! $invoice_id ) { 
  186. MS_Model_Import::need_matching( $m1_sub_id, 'm1' ); 
  187. // end if: 'm1' == $ext_type 
  188. } elseif ( ! empty( $_POST['btn_id'] ) && ! empty( $_POST['payer_email'] ) ) { 
  189. // FALLBACK B: 
  190. // Payment was made by a custom PayPal Payment button. 
  191. $user = get_user_by( 'email', $_POST['payer_email'] ); 
  192.  
  193. if ( $user && $user->ID ) { 
  194. $ext_type = 'pay_btn'; 
  195. $is_linked = false; 
  196.  
  197. $subscription = MS_Model_Import::find_subscription( 
  198. $user->ID,  
  199. $_POST['btn_id'],  
  200. 'pay_btn',  
  201. self::ID 
  202. ); 
  203.  
  204. if ( $subscription ) { 
  205. $is_linked = true; 
  206. } else { 
  207. $membership = MS_Model_Import::membership_by_matching( 
  208. 'pay_btn',  
  209. $_POST['btn_id'] 
  210. ); 
  211.  
  212. if ( $membership ) { 
  213. $notes_err = sprintf( 
  214. 'User is not subscribed to Membership %s.',  
  215. $membership->id 
  216. ); 
  217. } else { 
  218. $notes_err = 'Could not determine a membership.'; 
  219.  
  220. $invoice_id = $subscription->first_unpaid_invoice(); 
  221.  
  222. if ( ! $is_linked && ! $invoice_id ) { 
  223. MS_Model_Import::need_matching( $_POST['btn_id'], 'pay_btn' ); 
  224. } else { 
  225. $notes_err = sprintf( 
  226. 'Could not find user "%s".',  
  227. $_POST['payer_email'] 
  228. ); 
  229. // end if: 'pay_btn' == $ext_type 
  230.  
  231. // Check for subscription details 
  232. if ( $transaction_type ) { 
  233. switch ( $transaction_type ) { 
  234. /** 
  235. * Certain transaction types are sufficient to mark a free 
  236. * invoice as paid. To mark a non-free invoice as paid we need 
  237. * the correct payment_status (checked below) 
  238. */ 
  239. case 'subscr_signup': 
  240. // Payment was received 
  241. $notes_txn = __( 'Subscripton has been created', 'membership2' ); 
  242. $do_action = 'pay-free'; 
  243. break; 
  244.  
  245. case 'subscr_payment': 
  246. // Payment was received 
  247. $notes_txn = __( 'Payment successful', 'membership2' ); 
  248. $do_action = 'pay-free'; 
  249. break; 
  250.  
  251. case 'recurring_payment': 
  252. // Payment was received 
  253. $notes_txn = __( 'Recurring payment successful', 'membership2' ); 
  254. $do_action = 'pay-free'; 
  255. break; 
  256.  
  257. case 'subscr_modify': 
  258. // Payment profile was modified 
  259. $notes_txn = __( 'Subscription has been modified', 'membership2' ); 
  260. break; 
  261.  
  262. case 'subscr_failed': 
  263. // Payment profile was modified 
  264. $notes_txn = __( 'Payment failed', 'membership2' ); 
  265. $do_action = 'error'; 
  266. break; 
  267.  
  268. case 'recurring_payment_profile_canceled': 
  269. case 'subscr_cancel': 
  270. // Subscription was manually cancelled. 
  271. $notes_txn = __( 'Subscription has been canceled', 'membership2' ); 
  272. $do_action = 'cancel'; 
  273. $payment_status = false; // Skip the payment_status check. 
  274. break; 
  275.  
  276. case 'recurring_payment_suspended': 
  277. // Recurring subscription was manually suspended. 
  278. $notes_txn = __( 'Subscription has been suspended', 'membership2' ); 
  279. $do_action = 'cancel'; 
  280. $payment_status = false; // Skip the payment_status check. 
  281. break; 
  282.  
  283. case 'recurring_payment_suspended_due_to_max_failed_payment': 
  284. // Recurring subscription was automatically suspended. 
  285. $notes_txn = __( 'Subscription has failed', 'membership2' ); 
  286. $do_action = 'cancel'; 
  287. $payment_status = false; // Skip the payment_status check. 
  288. break; 
  289.  
  290. case 'new_case': 
  291. // New Dispute was filed for a payment. 
  292. if ( ! empty( $_POST['buyer_additional_information'] ) ) { 
  293. $notes_txn = sprintf( 
  294. __( 'New Dispute filed: %s', 'membership2' ),  
  295. $_POST['buyer_additional_information'] 
  296. ); 
  297. } else { 
  298. $notes_txn = __( 'New Dispute filed', 'membership2' ); 
  299. $status = MS_Model_Invoice::STATUS_DENIED; 
  300. $do_action = 'error'; 
  301. break; 
  302.  
  303. case 'subscr_eot': 
  304. /** 
  305. * Meaning: Subscription expired. 
  306. * - after a one-time payment was made 
  307. * - after last transaction in a recurring subscription 
  308. * - payment failed 
  309. * - ... 
  310. * We do not handle this event... 
  311. * One time payment sends 3 messages: 
  312. * 1. subscr_start (new subscription starts) 
  313. * 2. subscr_payment (payment confirmed) 
  314. * 3. subscr_eot (subscription ends) 
  315. */ 
  316. $notes_txn = __( 'Subscription ended', 'membership2' ); 
  317. break; 
  318.  
  319. case 'recurring_payment_profile_created': 
  320. $notes_txn = __( 'Recurring payment profile created', 'membership2' ); 
  321. break; 
  322.  
  323. case 'recurring_payment_failed': 
  324. $notes_txn = __( 'Recurring payment failed', 'membership2' ); 
  325. $do_action = 'error'; 
  326. break; 
  327.  
  328. case 'recurring_payment_profile_cancel': 
  329. $notes_txn = __( 'Recurring payment profile cancelled', 'membership2' ); 
  330. break; 
  331.  
  332. case 'recurring_payment_expired': 
  333. $notes_txn = __( 'Recurring payment profile expired', 'membership2' ); 
  334. break; 
  335.  
  336. case 'recurring_payment_skipped': 
  337. $notes_txn = __( 'Recurring payment profile skipped', 'membership2' ); 
  338. break; 
  339.  
  340. case 'recurring_payment_outstanding_payment': 
  341. $os_amount = 0; 
  342. if ( ! empty( $_POST['outstanding_balance'] ) ) { 
  343. $os_amount = $_POST['outstanding_balance']; 
  344. if ( is_numeric( $os_amount) && floatval( $os_amount ) ) { 
  345. $notes_txn = sprintf( 
  346. __( 'Outstanding payment of %s', 'membership2' ),  
  347. trim( $currency . ' ' . $os_amount ) 
  348. ); 
  349. } else { 
  350. $notes_txn = __( 'Outstanding payment', 'membership2' ); 
  351. break; 
  352.  
  353. case 'recurring_payment_outstanding_payment_failed': 
  354. $os_amount = 0; 
  355. if ( ! empty( $_POST['outstanding_balance'] ) ) { 
  356. $os_amount = $_POST['outstanding_balance']; 
  357. if ( is_numeric( $os_amount) && floatval( $os_amount ) ) { 
  358. $notes_txn = sprintf( 
  359. __( 'Collecting payment of %s failed', 'membership2' ),  
  360. trim( $currency . ' ' . $os_amount ) 
  361. ); 
  362. } else { 
  363. $notes_txn = __( 'Collecting payment failed', 'membership2' ); 
  364. $do_action = 'error'; 
  365. break; 
  366.  
  367. case 'send_money': 
  368. if ( ! empty( $_POST['memo'] ) ) { 
  369. $notes_txn = sprintf( 
  370. __( 'Money sent for: %s', 'membership2' ),  
  371. $_POST['memo'] 
  372. ); 
  373. } else { 
  374. $notes_txn = __( 'Money sent', 'membership2' ); 
  375. break; 
  376.  
  377. default: 
  378. // Other event that we do not have a case for... 
  379. $notes_txn = sprintf( 
  380. __( 'Not handling txn_type: %s', 'membership2' ),  
  381. $transaction_type 
  382. ); 
  383. break; 
  384.  
  385. // Process PayPal payment status 
  386. if ( $payment_status ) { 
  387. switch ( $payment_status ) { 
  388. // Successful payment 
  389. case 'completed': 
  390. case 'processed': 
  391. $do_action = 'pay'; 
  392. break; 
  393.  
  394. case 'reversed': 
  395. $notes_pay = __( 'Last transaction has been reversed: Payment has been reversed (charge back).', 'membership2' ); 
  396. $status = MS_Model_Invoice::STATUS_DENIED; 
  397. break; 
  398.  
  399. case 'refunded': 
  400. $notes_pay = __( 'Last transaction has been reversed: Payment has been refunded.', 'membership2' ); 
  401. $status = MS_Model_Invoice::STATUS_DENIED; 
  402. break; 
  403.  
  404. case 'denied': 
  405. $notes_pay = __( 'Last transaction has been reversed: Payment Denied.', 'membership2' ); 
  406. $status = MS_Model_Invoice::STATUS_DENIED; 
  407. $do_action = 'error'; 
  408. break; 
  409.  
  410. case 'pending': 
  411. lib3()->array->strip_slashes( $_POST, 'pending_reason' ); 
  412. $notes_pay = __( 'Last transaction is pending.', 'membership2' ) . ' '; 
  413.  
  414. switch ( $_POST['pending_reason'] ) { 
  415. case 'address': 
  416. $notes_pay .= __( 'No confirmed shipping address', 'membership2' ); 
  417. break; 
  418.  
  419. case 'authorization': 
  420. $notes_pay .= __( 'Funds not captured yet', 'membership2' ); 
  421. break; 
  422.  
  423. case 'echeck': 
  424. $notes_pay .= __( 'eCheck has not cleared yet', 'membership2' ); 
  425. break; 
  426.  
  427. case 'intl': 
  428. $notes_pay .= __( 'Pending approval by service provider', 'membership2' ); 
  429. break; 
  430.  
  431. case 'multi-currency': 
  432. $notes_pay .= __( 'Pending multi-currency process by service provider', 'membership2' ); 
  433. break; 
  434.  
  435. case 'unilateral': 
  436. $notes_pay .= __( 'No confirmed email address', 'membership2' ); 
  437. break; 
  438.  
  439. case 'upgrade': 
  440. $notes_pay .= __( 'Pending upgrade of PayPal account', 'membership2' ); 
  441. break; 
  442.  
  443. case 'verify': 
  444. $notes_pay .= __( 'Pending verification of PayPal account', 'membership2' ); 
  445. break; 
  446.  
  447. default: 
  448. $notes_pay .= __( 'Unknown reason', 'membership2' ); 
  449. break; 
  450.  
  451. $status = MS_Model_Invoice::STATUS_PENDING; 
  452. break; 
  453.  
  454. default: 
  455. case 'partially-refunded': 
  456. case 'in-progress': 
  457. $notes_pay = sprintf( 
  458. __( 'Not handling payment_status: %s', 'membership2' ),  
  459. $payment_status 
  460. ); 
  461. break; 
  462.  
  463. // Now we a good description of this IPN call. 
  464. if ( $notes_pay ) { 
  465. $notes .= ($notes ? ' | ' : '') . $notes_pay; 
  466. if ( $notes_txn ) { 
  467. $notes .= ($notes ? ' | ' : '') . $notes_txn; 
  468.  
  469. // Step 2a: Check if the txn_id was already processed by M2. 
  470. if ( MS_Model_Transactionlog::was_processed( self::ID, $external_id ) ) { 
  471. $notes = 'Duplicate: Already processed that transaction.'; 
  472. $success = false; 
  473. $ignore = true; 
  474.  
  475. // Step 2b: If we have an invoice_id then process the payment. 
  476. elseif ( $invoice_id ) { 
  477. if ( $this->is_live_mode() ) { 
  478. $domain = 'https://www.paypal.com'; 
  479. } else { 
  480. $domain = 'https://www.sandbox.paypal.com'; 
  481.  
  482. // PayPal post authenticity verification. 
  483. $ipn_data = (array) stripslashes_deep( $_POST ); 
  484. $ipn_data['cmd'] = '_notify-validate'; 
  485. $response = wp_remote_post( 
  486. $domain . '/cgi-bin/webscr',  
  487. array( 
  488. 'timeout' => 60,  
  489. 'sslverify' => false,  
  490. 'httpversion' => '1.1',  
  491. 'body' => $ipn_data,  
  492. ); 
  493.  
  494. $invoice = MS_Factory::load( 'MS_Model_Invoice', $invoice_id ); 
  495.  
  496. if ( ! is_wp_error( $response ) 
  497. && 200 == $response['response']['code'] 
  498. && ! empty( $response['body'] ) 
  499. && 'VERIFIED' == $response['body'] 
  500. && $invoice->id == $invoice_id 
  501. ) { 
  502. $subscription = $invoice->get_subscription(); 
  503. $membership = $subscription->get_membership(); 
  504. $member = $subscription->get_member(); 
  505. $subscription_id = $subscription->id; 
  506.  
  507. // Process the IPN call. Until now we just collected details. 
  508. switch ( $do_action ) { 
  509. case 'pay': 
  510. $success = true; 
  511. if ( $amount == $invoice->total ) { 
  512. $notes_pay .= __( 'Payment successful', 'membership2' ); 
  513. } else { 
  514. $notes_pay .= __( 'Payment registered, though amount differs from invoice.', 'membership2' ); 
  515. break; 
  516.  
  517. case 'pay-free': 
  518. if ( 0 == $invoice->total ) { 
  519. $success = true; 
  520. } else { 
  521. $ignore = true; 
  522. break; 
  523.  
  524. case 'cancel': 
  525. $member->cancel_membership( $membership->id ); 
  526. $member->save(); 
  527. $ignore = true; 
  528. break; 
  529.  
  530. case 'ignore': 
  531. $ignore = true; 
  532. break; 
  533.  
  534. if ( ! empty( $notes_pay ) ) { $invoice->add_notes( $notes_pay ); } 
  535. if ( ! empty( $notes_txn ) ) { $invoice->add_notes( $notes_txn ); } 
  536.  
  537. $invoice->save(); 
  538.  
  539. if ( $success ) { 
  540. $invoice->pay_it( self::ID, $external_id ); 
  541. } elseif ( ! empty( $status ) ) { 
  542. $invoice->status = $status; 
  543. $invoice->save(); 
  544. $invoice->changed(); 
  545.  
  546. do_action( 
  547. 'ms_gateway_paypalstandard_payment_processed_' . $status,  
  548. $invoice,  
  549. $subscription 
  550. ); 
  551.  
  552. } else { 
  553. $reason = 'Unexpected transaction response'; 
  554. switch ( true ) { 
  555. case is_wp_error( $response ): 
  556. $reason = 'PayPal did not verify this transaction: Unknown error'; 
  557. break; 
  558.  
  559. case 200 != $response['response']['code']: 
  560. $reason = sprintf( 
  561. 'PayPal did not verify the transaction: Code %s',  
  562. $response['response']['code'] 
  563. ); 
  564. break; 
  565.  
  566. case empty( $response['body'] ): 
  567. $reason = 'PayPal did not verify this transaction: Empty response'; 
  568. break; 
  569.  
  570. case 'VERIFIED' != $response['body']: 
  571. $reason = sprintf( 
  572. 'PayPal did not verify this transaction: "%s"',  
  573. $response['body'] 
  574. ); 
  575. break; 
  576.  
  577. case ! $invoice->id: 
  578. $reason = sprintf( 
  579. 'Specified invoice does not exist: "%s"',  
  580. $invoice_id 
  581. ); 
  582. break; 
  583.  
  584. $notes = 'Response Error: ' . $reason; 
  585. $exit = true; 
  586. } else { 
  587. // Did not find expected POST variables. Possible access attempt from a non PayPal site. 
  588.  
  589. $u_agent = $_SERVER['HTTP_USER_AGENT']; 
  590. if ( ! $log && false === strpos( $u_agent, 'PayPal' ) ) { 
  591. // Very likely someone tried to open the URL manually. Redirect to home page. 
  592. if ( ! $notes ) { 
  593. $notes = 'Ignored: Missing POST variables. Redirect to Home-URL.'; 
  594. $redirect = MS_Helper_Utility::home_url( '/' ); 
  595. $ignore = true; 
  596. $success = false; 
  597. } elseif ( 'm1' == $ext_type ) { 
  598. /** 
  599. * The payment belongs to an imported M1 subscription and could 
  600. * not be auto-matched. 
  601. * Do not return an error code, but also do not modify any 
  602. * invoice/subscription. 
  603. */ 
  604. $notes = 'M1 Payment detected. Manual matching required. ' . $notes_err; 
  605. $success = false; 
  606. } elseif ( 'pay_btn' == $ext_type ) { 
  607. /** 
  608. * The payment was made by a PayPal Payment button that was 
  609. * created in the PayPal account and not by M1/M2. 
  610. */ 
  611. $notes = 'PayPal Payment button detected. Manual matching required. ' . $notes_err; 
  612. $success = false; 
  613. } else { 
  614. // PayPal sent us a IPN notice about a non-Membership payment: 
  615. // Ignore it, but add it to the logs. 
  616.  
  617. if ( ! empty( $notes_err ) ) { 
  618. // Use the notes_err. 
  619. $notes = $notes_err; 
  620. } if ( ! empty( $notes ) ) { 
  621. // We already have an error message, do nothing. 
  622. } elseif ( ! $transaction_type ) { 
  623. $notes = 'Ignored: txn_type not specified. Cannot process.'; 
  624. } elseif ( empty( $_POST['invoice'] ) && empty( $_POST['custom'] ) ) { 
  625. $notes = 'Ignored: No invoice or custom data specified.'; 
  626. } else { 
  627. $notes = 'Ignored: Missing POST variables. Identification is not possible.'; 
  628.  
  629. $ignore = true; 
  630. $success = false; 
  631. $exit = true; 
  632.  
  633. if ( $ignore && ! $success ) { 
  634. $success = null; 
  635. $notes .= ' [Irrelevant IPN call]'; 
  636.  
  637. if ( ! $log ) { 
  638. do_action( 
  639. 'ms_gateway_transaction_log',  
  640. self::ID, // gateway ID 
  641. 'handle', // request|process|handle 
  642. $success, // success flag 
  643. $subscription_id, // subscription ID 
  644. $invoice_id, // invoice ID 
  645. $amount, // charged amount 
  646. $notes, // Descriptive text 
  647. $external_id // External ID 
  648. ); 
  649.  
  650. if ( $redirect ) { 
  651. wp_safe_redirect( $redirect ); 
  652. exit; 
  653. if ( $exit ) { 
  654. exit; 
  655. } else { 
  656. $log->invoice_id = $invoice_id; 
  657. $log->subscription_id = $subscription_id; 
  658. $log->amount = $amount; 
  659. $log->description = $notes; 
  660. $log->external_id = $external_id; 
  661. if ( $success ) { 
  662. $log->manual_state( 'ok' ); 
  663. } elseif ( $ignore ) { 
  664. $log->manual_state( 'ignore' ); 
  665. $log->save(); 
  666.  
  667. do_action( 
  668. 'ms_gateway_paypalstandard_handle_return_after',  
  669. $this 
  670. ); 
  671.  
  672. if ( $log ) { 
  673. return $log; 
  674.  
  675. /** 
  676. * Get paypal country sites list. 
  677. * @see MS_Gateway::get_country_codes() 
  678. * @since 1.0.0 
  679. * @return array 
  680. */ 
  681. public function get_paypal_sites() { 
  682. return apply_filters( 
  683. 'ms_gateway_paylpaystandard_get_paypal_sites',  
  684. self::get_country_codes() 
  685. ); 
  686.  
  687. /** 
  688. * Verify required fields. 
  689. * @since 1.0.0 
  690. * @return boolean 
  691. */ 
  692. public function is_configured() { 
  693. $is_configured = true; 
  694. $required = array( 'merchant_id', 'paypal_site' ); 
  695.  
  696. foreach ( $required as $field ) { 
  697. $value = $this->$field; 
  698. if ( empty( $value ) ) { 
  699. $is_configured = false; 
  700. break; 
  701.  
  702. return apply_filters( 
  703. 'ms_gateway_paypalstandard_is_configured',  
  704. $is_configured 
  705. ); 
  706.  
  707. /** 
  708. * Validate specific property before set. 
  709. * @since 1.0.0 
  710. * @access public 
  711. * @param string $name The name of a property to associate. 
  712. * @param mixed $value The value of a property. 
  713. */ 
  714. public function __set( $property, $value ) { 
  715. if ( property_exists( $this, $property ) ) { 
  716. switch ( $property ) { 
  717. case 'paypal_site': 
  718. if ( array_key_exists( $value, self::get_paypal_sites() ) ) { 
  719. $this->$property = $value; 
  720. break; 
  721.  
  722. default: 
  723. parent::__set( $property, $value ); 
  724. break; 
  725.  
  726. do_action( 
  727. 'ms_gateway_paypalstandard__set_after',  
  728. $property,  
  729. $value,  
  730. $this 
  731. ); 
  732.