Advertisement
Guest User

Untitled

a guest
Sep 2nd, 2018
657
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 18.83 KB | None | 0 0
  1. <?php
  2. if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly
  3.  
  4. /**
  5. * Plugin Name: WooCommerce CoinPayments.net Gateway
  6. * Plugin URI: https://www.coinpayments.net/
  7. * Description: Provides a CoinPayments.net Payment Gateway.
  8. * Author: CoinPayments.net
  9. * Author URI: https://www.coinpayments.net/
  10. * Version: 1.0.10
  11. */
  12.  
  13. /**
  14. * CoinPayments.net Gateway
  15. * Based on the PayPal Standard Payment Gateway
  16. *
  17. * Provides a CoinPayments.net Payment Gateway.
  18. *
  19. * @class WC_Coinpayments
  20. * @extends WC_Gateway_Coinpayments
  21. * @version 1.0.10
  22. * @package WooCommerce/Classes/Payment
  23. * @author CoinPayments.net based on PayPal module by WooThemes
  24. */
  25.  
  26. add_action( 'plugins_loaded', 'coinpayments_gateway_load', 0 );
  27. function coinpayments_gateway_load() {
  28.  
  29. if ( ! class_exists( 'WC_Payment_Gateway' ) ) {
  30. // oops!
  31. return;
  32. }
  33.  
  34. /**
  35. * Add the gateway to WooCommerce.
  36. */
  37. add_filter( 'woocommerce_payment_gateways', 'wccoinpayments_add_gateway' );
  38.  
  39. function wccoinpayments_add_gateway( $methods ) {
  40. if (!in_array('WC_Gateway_Coinpayments', $methods)) {
  41. $methods[] = 'WC_Gateway_Coinpayments';
  42. }
  43. return $methods;
  44. }
  45.  
  46.  
  47. class WC_Gateway_Coinpayments extends WC_Payment_Gateway {
  48.  
  49. var $ipn_url;
  50.  
  51. /**
  52. * Constructor for the gateway.
  53. *
  54. * @access public
  55. * @return void
  56. */
  57. public function __construct() {
  58. global $woocommerce;
  59.  
  60. $this->id = 'coinpayments';
  61. $this->icon = apply_filters( 'woocommerce_coinpayments_icon', plugins_url().'/coinpayments-payment-gateway-for-woocommerce/assets/images/icons/coinpayments.png' );
  62. $this->has_fields = false;
  63. $this->method_title = __( 'CoinPayments.net', 'woocommerce' );
  64. $this->ipn_url = add_query_arg( 'wc-api', 'WC_Gateway_Coinpayments', home_url( '/' ) );
  65.  
  66. // Load the settings.
  67. $this->init_form_fields();
  68. $this->init_settings();
  69.  
  70. // Define user set variables
  71. $this->title = $this->get_option( 'title' );
  72. $this->description = $this->get_option( 'description' );
  73. $this->merchant_id = $this->get_option( 'merchant_id' );
  74. $this->ipn_secret = $this->get_option( 'ipn_secret' );
  75. $this->send_shipping = $this->get_option( 'send_shipping' );
  76. $this->debug_email = $this->get_option( 'debug_email' );
  77. $this->allow_zero_confirm = $this->get_option( 'allow_zero_confirm' ) == 'yes' ? true : false;
  78. $this->form_submission_method = $this->get_option( 'form_submission_method' ) == 'yes' ? true : false;
  79. $this->invoice_prefix = $this->get_option( 'invoice_prefix', 'WC-' );
  80. $this->simple_total = $this->get_option( 'simple_total' ) == 'yes' ? true : false;
  81.  
  82. // Logs
  83. $this->log = new WC_Logger();
  84.  
  85. // Actions
  86. add_action( 'woocommerce_receipt_coinpayments', array( $this, 'receipt_page' ) );
  87. add_action( 'woocommerce_update_options_payment_gateways_' . $this->id, array( $this, 'process_admin_options' ) );
  88.  
  89. // Payment listener/API hook
  90. add_action( 'woocommerce_api_wc_gateway_coinpayments', array( $this, 'check_ipn_response' ) );
  91.  
  92. if ( !$this->is_valid_for_use() ) $this->enabled = false;
  93. }
  94.  
  95.  
  96. /**
  97. * Check if this gateway is enabled and available in the user's country
  98. *
  99. * @access public
  100. * @return bool
  101. */
  102. function is_valid_for_use() {
  103. //if ( ! in_array( get_woocommerce_currency(), apply_filters( 'woocommerce_coinpayments_supported_currencies', array( 'AUD', 'CAD', 'USD', 'EUR', 'JPY', 'GBP', 'CZK', 'BTC', 'LTC' ) ) ) ) return false;
  104. // ^- instead of trying to maintain this list just let it always work
  105. return true;
  106. }
  107.  
  108. /**
  109. * Admin Panel Options
  110. * - Options for bits like 'title' and availability on a country-by-country basis
  111. *
  112. * @since 1.0.0
  113. */
  114. public function admin_options() {
  115.  
  116. ?>
  117. <h3><?php _e( 'CoinPayments.net', 'woocommerce' ); ?></h3>
  118. <p><?php _e( 'Completes checkout via CoinPayments.net', 'woocommerce' ); ?></p>
  119.  
  120. <?php if ( $this->is_valid_for_use() ) : ?>
  121.  
  122. <table class="form-table">
  123. <?php
  124. // Generate the HTML For the settings form.
  125. $this->generate_settings_html();
  126. ?>
  127. </table><!--/.form-table-->
  128.  
  129. <?php else : ?>
  130. <div class="inline error"><p><strong><?php _e( 'Gateway Disabled', 'woocommerce' ); ?></strong>: <?php _e( 'CoinPayments.net does not support your store currency.', 'woocommerce' ); ?></p></div>
  131. <?php
  132. endif;
  133. }
  134.  
  135.  
  136. /**
  137. * Initialise Gateway Settings Form Fields
  138. *
  139. * @access public
  140. * @return void
  141. */
  142. function init_form_fields() {
  143.  
  144. $this->form_fields = array(
  145. 'enabled' => array(
  146. 'title' => __( 'Enable/Disable', 'woocommerce' ),
  147. 'type' => 'checkbox',
  148. 'label' => __( 'Enable CoinPayments.net', 'woocommerce' ),
  149. 'default' => 'yes'
  150. ),
  151. 'title' => array(
  152. 'title' => __( 'Title', 'woocommerce' ),
  153. 'type' => 'text',
  154. 'description' => __( 'This controls the title which the user sees during checkout.', 'woocommerce' ),
  155. 'default' => __( 'CoinPayments.net', 'woocommerce' ),
  156. 'desc_tip' => true,
  157. ),
  158. 'description' => array(
  159. 'title' => __( 'Description', 'woocommerce' ),
  160. 'type' => 'textarea',
  161. 'description' => __( 'This controls the description which the user sees during checkout.', 'woocommerce' ),
  162. 'default' => __( 'Pay with Bitcoin, Litecoin, or other altcoins via CoinPayments.net', 'woocommerce' )
  163. ),
  164. 'merchant_id' => array(
  165. 'title' => __( 'Merchant ID', 'woocommerce' ),
  166. 'type' => 'text',
  167. 'description' => __( 'Please enter your CoinPayments.net Merchant ID.', 'woocommerce' ),
  168. 'default' => '',
  169. ),
  170. 'ipn_secret' => array(
  171. 'title' => __( 'IPN Secret', 'woocommerce' ),
  172. 'type' => 'text',
  173. 'description' => __( 'Please enter your CoinPayments.net IPN Secret.', 'woocommerce' ),
  174. 'default' => '',
  175. ),
  176. 'simple_total' => array(
  177. 'title' => __( 'Compatibility Mode', 'woocommerce' ),
  178. 'type' => 'checkbox',
  179. 'label' => __( "This may be needed for compatibility with certain addons if the order total isn't correct.", 'woocommerce' ),
  180. 'default' => ''
  181. ),
  182. 'send_shipping' => array(
  183. 'title' => __( 'Collect Shipping Info?', 'woocommerce' ),
  184. 'type' => 'checkbox',
  185. 'label' => __( 'Enable Shipping Information on Checkout page', 'woocommerce' ),
  186. 'default' => 'yes'
  187. ),
  188. 'allow_zero_confirm' => array(
  189. 'title' => __( 'Enable 1st-confirm payments?', 'woocommerce' ),
  190. 'type' => 'checkbox',
  191. 'label' => __( '* WARNING * If this is selected orders will be marked as paid as soon as your buyer\'s payment is detected, but before it is fully confirmed. This can be dangerous if the payment never confirms and is only recommended for digital downloads.', 'woocommerce' ),
  192. 'default' => ''
  193. ),
  194. 'invoice_prefix' => array(
  195. 'title' => __( 'Invoice Prefix', 'woocommerce' ),
  196. 'type' => 'text',
  197. 'description' => __( 'Please enter a prefix for your invoice numbers. If you use your CoinPayments.net account for multiple stores ensure this prefix is unique.', 'woocommerce' ),
  198. 'default' => 'WC-',
  199. 'desc_tip' => true,
  200. ),
  201. 'testing' => array(
  202. 'title' => __( 'Gateway Testing', 'woocommerce' ),
  203. 'type' => 'title',
  204. 'description' => '',
  205. ),
  206. 'debug_email' => array(
  207. 'title' => __( 'Debug Email', 'woocommerce' ),
  208. 'type' => 'email',
  209. 'default' => '',
  210. 'description' => __( 'Send copies of invalid IPNs to this email address.', 'woocommerce' ),
  211. )
  212. );
  213.  
  214. }
  215.  
  216.  
  217. /**
  218. * Get CoinPayments.net Args
  219. *
  220. * @access public
  221. * @param mixed $order
  222. * @return array
  223. */
  224. function get_coinpayments_args( $order ) {
  225. global $woocommerce;
  226.  
  227. $order_id = $order->id;
  228.  
  229. if ( in_array( $order->billing_country, array( 'US','CA' ) ) ) {
  230. $order->billing_phone = str_replace( array( '( ', '-', ' ', ' )', '.' ), '', $order->billing_phone );
  231. }
  232.  
  233. // CoinPayments.net Args
  234. $coinpayments_args = array(
  235. 'cmd' => '_pay_auto',
  236. 'merchant' => $this->merchant_id,
  237. 'allow_extra' => 0,
  238. // Get the currency from the order, not the active currency
  239. // NOTE: for backward compatibility with WC 2.6 and earlier,
  240. // $order->get_order_currency() should be used instead
  241. 'currency' => $order->get_currency(),
  242. 'reset' => 1,
  243. 'success_url' => $this->get_return_url( $order ),
  244. 'cancel_url' => $order->get_cancel_order_url(),
  245.  
  246. // Order key + ID
  247. 'invoice' => $this->invoice_prefix . $order->get_order_number(),
  248. 'custom' => serialize( array( $order->id, $order->order_key ) ),
  249.  
  250. // IPN
  251. 'ipn_url' => $this->ipn_url,
  252.  
  253. // Billing Address info
  254. 'first_name' => $order->billing_first_name,
  255. 'last_name' => $order->billing_last_name,
  256. 'email' => $order->billing_email,
  257. );
  258.  
  259. if ($this->send_shipping == 'yes') {
  260. $coinpayments_args = array_merge($coinpayments_args, array(
  261. 'want_shipping' => 1,
  262. 'address1' => $order->billing_address_1,
  263. 'address2' => $order->billing_address_2,
  264. 'city' => $order->billing_city,
  265. 'state' => $order->billing_state,
  266. 'zip' => $order->billing_postcode,
  267. 'country' => $order->billing_country,
  268. 'phone' => $order->billing_phone,
  269. ));
  270. } else {
  271. $coinpayments_args['want_shipping'] = 0;
  272. }
  273.  
  274. if ($this->simple_total) {
  275. $coinpayments_args['item_name'] = sprintf( __( 'Order %s' , 'woocommerce'), $order->get_order_number() );
  276. $coinpayments_args['quantity'] = 1;
  277. $coinpayments_args['amountf'] = number_format( $order->get_total(), 8, '.', '' );
  278. $coinpayments_args['taxf'] = 0.00;
  279. $coinpayments_args['shippingf'] = 0.00;
  280. } else if ( wc_tax_enabled() && wc_prices_include_tax() ) {
  281. $coinpayments_args['item_name'] = sprintf( __( 'Order %s' , 'woocommerce'), $order->get_order_number() );
  282. $coinpayments_args['quantity'] = 1;
  283. $coinpayments_args['amountf'] = number_format( $order->get_total() - $order->get_total_shipping() - $order->get_shipping_tax(), 8, '.', '' );
  284. $coinpayments_args['shippingf'] = number_format( $order->get_total_shipping() + $order->get_shipping_tax() , 8, '.', '' );
  285. $coinpayments_args['taxf'] = 0.00;
  286. } else {
  287. $coinpayments_args['item_name'] = sprintf( __( 'Order %s' , 'woocommerce'), $order->get_order_number() );
  288. $coinpayments_args['quantity'] = 1;
  289. $coinpayments_args['amountf'] = number_format( $order->get_total() - $order->get_total_shipping() - $order->get_total_tax(), 8, '.', '' );
  290. $coinpayments_args['shippingf'] = number_format( $order->get_total_shipping(), 8, '.', '' );
  291. $coinpayments_args['taxf'] = $order->get_total_tax();
  292. }
  293.  
  294. $coinpayments_args = apply_filters( 'woocommerce_coinpayments_args', $coinpayments_args );
  295.  
  296. return $coinpayments_args;
  297. }
  298.  
  299.  
  300. /**
  301. * Generate the coinpayments button link
  302. *
  303. * @access public
  304. * @param mixed $order_id
  305. * @return string
  306. */
  307. function generate_coinpayments_url($order) {
  308. global $woocommerce;
  309.  
  310. if ( $order->status != 'completed' && get_post_meta( $order->id, 'CoinPayments payment complete', true ) != 'Yes' ) {
  311. //$order->update_status('on-hold', 'Customer is being redirected to CoinPayments...');
  312. $order->update_status('pending', 'Customer is being redirected to CoinPayments...');
  313. }
  314.  
  315. $coinpayments_adr = "https://www.coinpayments.net/index.php?";
  316. $coinpayments_args = $this->get_coinpayments_args( $order );
  317. $coinpayments_adr .= http_build_query( $coinpayments_args, '', '&' );
  318. return $coinpayments_adr;
  319. }
  320.  
  321.  
  322. /**
  323. * Process the payment and return the result
  324. *
  325. * @access public
  326. * @param int $order_id
  327. * @return array
  328. */
  329. function process_payment( $order_id ) {
  330.  
  331. $order = wc_get_order( $order_id );
  332.  
  333. return array(
  334. 'result' => 'success',
  335. 'redirect' => $this->generate_coinpayments_url($order),
  336. );
  337.  
  338. }
  339.  
  340.  
  341. /**
  342. * Output for the order received page.
  343. *
  344. * @access public
  345. * @return void
  346. */
  347. function receipt_page( $order ) {
  348. echo '<p>'.__( 'Thank you for your order, please click the button below to pay with CoinPayments.net.', 'woocommerce' ).'</p>';
  349.  
  350. echo $this->generate_coinpayments_form( $order );
  351. }
  352.  
  353. /**
  354. * Check CoinPayments.net IPN validity
  355. **/
  356. function check_ipn_request_is_valid() {
  357. global $woocommerce;
  358.  
  359. $order = false;
  360. $error_msg = "Unknown error";
  361. $auth_ok = false;
  362.  
  363. if (isset($_POST['ipn_mode']) && $_POST['ipn_mode'] == 'hmac') {
  364. if (isset($_SERVER['HTTP_HMAC']) && !empty($_SERVER['HTTP_HMAC'])) {
  365. $request = file_get_contents('php://input');
  366. if ($request !== FALSE && !empty($request)) {
  367. if (isset($_POST['merchant']) && $_POST['merchant'] == trim($this->merchant_id)) {
  368. $hmac = hash_hmac("sha512", $request, trim($this->ipn_secret));
  369. if ($hmac == $_SERVER['HTTP_HMAC']) {
  370. $auth_ok = true;
  371. } else {
  372. $error_msg = 'HMAC signature does not match';
  373. }
  374. } else {
  375. $error_msg = 'No or incorrect Merchant ID passed';
  376. }
  377. } else {
  378. $error_msg = 'Error reading POST data';
  379. }
  380. } else {
  381. $error_msg = 'No HMAC signature sent.';
  382. }
  383. } else {
  384. $error_msg = "Unknown IPN verification method.";
  385. }
  386.  
  387. if ($auth_ok) {
  388. if (!empty($_POST['invoice']) && !empty($_POST['custom'])) {
  389. $order = $this->get_coinpayments_order( $_POST );
  390. }
  391.  
  392. if ($order !== FALSE) {
  393. if ($_POST['ipn_type'] == "button" || $_POST['ipn_type'] == "simple") {
  394. if ($_POST['merchant'] == $this->merchant_id) {
  395. // Get the currency from the order, not the active currency
  396. // NOTE: for backward compatibility with WC 2.6 and earlier,
  397. // $order->get_order_currency() should be used instead
  398. if ($_POST['currency1'] == $order->get_currency()) {
  399. if ($_POST['amount1'] >= $order->get_total()) {
  400. print "IPN check OK\n";
  401. return true;
  402. } else {
  403. $error_msg = "Amount received is less than the total!";
  404. }
  405. } else {
  406. $error_msg = "Original currency doesn't match!";
  407. }
  408. } else {
  409. $error_msg = "Merchant ID doesn't match!";
  410. }
  411. } else {
  412. $error_msg = "ipn_type != button or simple";
  413. }
  414. } else {
  415. $error_msg = "Could not find order info for order: ".$_POST['invoice'];
  416. }
  417. }
  418.  
  419. $report = "Error Message: ".$error_msg."\n\n";
  420.  
  421. $report .= "POST Fields\n\n";
  422. foreach ($_POST as $key => $value) {
  423. $report .= $key.'='.$value."\n";
  424. }
  425.  
  426. if ($order) {
  427. $order->update_status('on-hold', sprintf( __( 'CoinPayments.net IPN Error: %s', 'woocommerce' ), $error_msg ) );
  428. }
  429. if (!empty($this->debug_email)) { mail($this->debug_email, "CoinPayments.net Invalid IPN", $report); }
  430. mail(get_option( 'admin_email' ), sprintf( __( 'CoinPayments.net Invalid IPN', 'woocommerce' ), $error_msg ), $report );
  431. die('Error: '.$error_msg);
  432. return false;
  433. }
  434.  
  435. /**
  436. * Successful Payment!
  437. *
  438. * @access public
  439. * @param array $posted
  440. * @return void
  441. */
  442. function successful_request( $posted ) {
  443. global $woocommerce;
  444.  
  445. $posted = stripslashes_deep( $posted );
  446.  
  447. // Custom holds post ID
  448. if (!empty($_POST['invoice']) && !empty($_POST['custom'])) {
  449. $order = $this->get_coinpayments_order( $posted );
  450.  
  451. $this->log->add( 'coinpayments', 'Order #'.$order->id.' payment status: ' . $posted['status_text'] );
  452. $order->add_order_note('CoinPayments.net Payment Status: '.$posted['status_text']);
  453.  
  454. if ( $order->status != 'completed' && get_post_meta( $order->id, 'CoinPayments payment complete', true ) != 'Yes' ) {
  455. // no need to update status if it's already done
  456. if ( ! empty( $posted['txn_id'] ) )
  457. update_post_meta( $order->id, 'Transaction ID', $posted['txn_id'] );
  458. if ( ! empty( $posted['first_name'] ) )
  459. update_post_meta( $order->id, 'Payer first name', $posted['first_name'] );
  460. if ( ! empty( $posted['last_name'] ) )
  461. update_post_meta( $order->id, 'Payer last name', $posted['last_name'] );
  462. if ( ! empty( $posted['email'] ) )
  463. update_post_meta( $order->id, 'Payer email', $posted['email'] );
  464.  
  465. if ($posted['status'] >= 100 || $posted['status'] == 2 || ($this->allow_zero_confirm && $posted['status'] >= 0 && $posted['received_confirms'] > 0 && $posted['received_amount'] >= $posted['amount2'])) {
  466. print "Marking complete\n";
  467. update_post_meta( $order->id, 'CoinPayments payment complete', 'Yes' );
  468. $order->payment_complete();
  469. } else if ($posted['status'] < 0) {
  470. print "Marking cancelled\n";
  471. $order->update_status('cancelled', 'CoinPayments.net Payment cancelled/timed out: '.$posted['status_text']);
  472. mail( get_option( 'admin_email' ), sprintf( __( 'Payment for order %s cancelled/timed out', 'woocommerce' ), $order->get_order_number() ), $posted['status_text'] );
  473. } else {
  474. print "Marking pending\n";
  475. $order->update_status('pending', 'CoinPayments.net Payment pending: '.$posted['status_text']);
  476. }
  477. }
  478. die("IPN OK");
  479. }
  480. }
  481.  
  482. /**
  483. * Check for CoinPayments IPN Response
  484. *
  485. * @access public
  486. * @return void
  487. */
  488. function check_ipn_response() {
  489.  
  490. @ob_clean();
  491.  
  492. if ( ! empty( $_POST ) && $this->check_ipn_request_is_valid() ) {
  493. $this->successful_request($_POST);
  494. } else {
  495. wp_die( "CoinPayments.net IPN Request Failure" );
  496. }
  497. }
  498.  
  499. /**
  500. * get_coinpayments_order function.
  501. *
  502. * @access public
  503. * @param mixed $posted
  504. * @return void
  505. */
  506. function get_coinpayments_order( $posted ) {
  507. $custom = maybe_unserialize( stripslashes_deep($posted['custom']) );
  508.  
  509. // Backwards comp for IPN requests
  510. if ( is_numeric( $custom ) ) {
  511. $order_id = (int) $custom;
  512. $order_key = $posted['invoice'];
  513. } elseif( is_string( $custom ) ) {
  514. $order_id = (int) str_replace( $this->invoice_prefix, '', $custom );
  515. $order_key = $custom;
  516. } else {
  517. list( $order_id, $order_key ) = $custom;
  518. }
  519.  
  520. $order = new WC_Order( $order_id );
  521.  
  522. if ( ! isset( $order->id ) ) {
  523. // We have an invalid $order_id, probably because invoice_prefix has changed
  524. $order_id = woocommerce_get_order_id_by_order_key( $order_key );
  525. $order = new WC_Order( $order_id );
  526. }
  527.  
  528. // Validate key
  529. if ( $order->order_key !== $order_key ) {
  530. return FALSE;
  531. }
  532.  
  533. return $order;
  534. }
  535.  
  536. }
  537.  
  538. class WC_Coinpayments extends WC_Gateway_Coinpayments {
  539. public function __construct() {
  540. _deprecated_function( 'WC_Coinpayments', '1.4', 'WC_Gateway_Coinpayments' );
  541. parent::__construct();
  542. }
  543. }
  544. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement