WC_MercadoPago_Gateway

MercadoPago payment method.

Defined (1)

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

/includes/class-wc-mercadopago-gateway.php  
  1. class WC_MercadoPago_Gateway extends WC_Payment_Gateway { 
  2.  
  3. /** 
  4. * Initialize payment gateway actions. 
  5. */ 
  6. public function __construct() { 
  7. // Standards. 
  8. $this->id = 'mercadopago'; 
  9. $this->icon = apply_filters( 'woocommerce_mercadopago_icon', plugins_url( 'images/mercadopago.png', plugin_dir_path( __FILE__ ) ) ); 
  10. $this->has_fields = false; 
  11. $this->method_title = __( 'MercadoPago', 'woocommerce-mercadopago' ); 
  12. $this->supports = array( 
  13. 'products',  
  14. 'subscriptions',  
  15. 'subscription_cancellation',  
  16. 'gateway_scheduled_payments',  
  17. ); 
  18.  
  19. // Load the form fields. 
  20. $this->init_form_fields(); 
  21.  
  22. // Load the settings. 
  23. $this->init_settings(); 
  24.  
  25. // Define user set variables. 
  26. $this->title = $this->get_option( 'title' ); 
  27. $this->description = $this->get_option( 'description' ); 
  28. $this->client_id = $this->get_option( 'client_id' ); 
  29. $this->client_secret = $this->get_option( 'client_secret' ); 
  30. $this->invoice_prefix = $this->get_option( 'invoice_prefix', 'WC-' ); 
  31. $this->method = $this->get_option( 'method', 'modal' ); 
  32. $this->sandbox = $this->get_option( 'sandbox' ); 
  33. $this->debug = $this->get_option( 'debug' ); 
  34.  
  35. // Active logs. 
  36. if ( 'yes' == $this->debug ) { 
  37. $this->log = new WC_Logger(); 
  38.  
  39. $this->api = new WC_Mercadopago_API( $this ); 
  40.  
  41. // Actions. 
  42. add_action( 'woocommerce_api_wc_mercadopago_gateway', array( $this, 'ipn_handler' ) ); 
  43. add_action( 'woocommerce_mercadopago_change_order_status', array( $this, 'change_order_status' ), 10, 2 ); 
  44. add_action( 'woocommerce_receipt_' . $this->id, array( $this, 'receipt_page' ) ); 
  45. add_action( 'woocommerce_update_options_payment_gateways_' . $this->id, array( $this, 'process_admin_options' ) ); 
  46. add_action( 'woocommerce_subscription_cancelled_' . $this->id, array( $this, 'cancel_subscription' ) ); 
  47.  
  48. /** 
  49. * Returns a value indicating the the Gateway is available or not. It's called 
  50. * automatically by WooCommerce before allowing customers to use the gateway 
  51. * for payment. 
  52. * @return bool 
  53. */ 
  54. public function is_available() { 
  55. // Test if is valid for use. 
  56. $available = parent::is_available() && 
  57. ! empty( $this->client_id ) && 
  58. ! empty( $this->client_secret ) && 
  59. in_array( get_woocommerce_currency(), $this->api->get_supported_currencies() ); 
  60.  
  61. return $available; 
  62.  
  63. /** 
  64. * Initialise gateway settings. 
  65. */ 
  66. public function init_form_fields() { 
  67. $api_secret_locale = sprintf( 
  68. '<a href="https://www.mercadopago.com/mla/herramientas/aplicaciones" target="_blank">%s</a>, <a href="https://www.mercadopago.com/mlb/ferramentas/aplicacoes" target="_blank">%s</a>, <a href="https://www.mercadopago.com/mco/ferramentas/aplicacoes" target="_blank">%s</a>, <a href="https://www.mercadopago.com/mlm/herramientas/aplicaciones" target="_blank">%s</a> %s <a href="https://www.mercadopago.com/mlv/herramientas/aplicaciones" target="_blank">%s</a>',  
  69. __( 'Argentine', 'woocommerce-mercadopago' ),  
  70. __( 'Brazil', 'woocommerce-mercadopago' ),  
  71. __( 'Colombia', 'woocommerce-mercadopago' ),  
  72. __( 'Mexico', 'woocommerce-mercadopago' ),  
  73. __( 'or', 'woocommerce-mercadopago' ),  
  74. __( 'Venezuela', 'woocommerce-mercadopago' ) 
  75. ); 
  76.  
  77. $this->form_fields = array( 
  78. 'enabled' => array( 
  79. 'title' => __( 'Enable/Disable', 'woocommerce-mercadopago' ),  
  80. 'type' => 'checkbox',  
  81. 'label' => __( 'Enable MercadoPago', 'woocommerce-mercadopago' ),  
  82. 'default' => 'no',  
  83. ),  
  84. 'title' => array( 
  85. 'title' => __( 'Title', 'woocommerce-mercadopago' ),  
  86. 'type' => 'text',  
  87. 'description' => __( 'This controls the title which the user sees during checkout.', 'woocommerce-mercadopago' ),  
  88. 'desc_tip' => true,  
  89. 'default' => __( 'MercadoPago', 'woocommerce-mercadopago' ),  
  90. ),  
  91. 'description' => array( 
  92. 'title' => __( 'Description', 'woocommerce-mercadopago' ),  
  93. 'type' => 'textarea',  
  94. 'description' => __( 'This controls the description which the user sees during checkout.', 'woocommerce-mercadopago' ),  
  95. 'default' => __( 'Pay via MercadoPago', 'woocommerce-mercadopago' ),  
  96. ),  
  97. 'client_id' => array( 
  98. 'title' => __( 'MercadoPago Client_id', 'woocommerce-mercadopago' ),  
  99. 'type' => 'text',  
  100. 'description' => __( 'Please enter your MercadoPago Client_id.', 'woocommerce-mercadopago' ) . ' ' . sprintf( __( 'You can to get this information in MercadoPago from %s.', 'woocommerce-mercadopago' ), $api_secret_locale ),  
  101. 'default' => '',  
  102. 'custom_attributes' => array( 
  103. 'required' => 'required',  
  104. ),  
  105. ),  
  106. 'client_secret' => array( 
  107. 'title' => __( 'MercadoPago Client_secret', 'woocommerce-mercadopago' ),  
  108. 'type' => 'text',  
  109. 'description' => __( 'Please enter your MercadoPago Client_secret.', 'woocommerce-mercadopago' ) . ' ' . sprintf( __( 'You can to get this information in MercadoPago from %s.', 'woocommerce-mercadopago' ), $api_secret_locale ),  
  110. 'default' => '',  
  111. 'custom_attributes' => array( 
  112. 'required' => 'required',  
  113. ),  
  114. ),  
  115. 'invoice_prefix' => array( 
  116. 'title' => __( 'Invoice Prefix', 'woocommerce-mercadopago' ),  
  117. 'type' => 'text',  
  118. 'description' => __( 'Please enter a prefix for your invoice numbers. If you use your MercadoPago account for multiple stores ensure this prefix is unqiue as MercadoPago will not allow orders with the same invoice number.', 'woocommerce-mercadopago' ),  
  119. 'desc_tip' => true,  
  120. 'default' => 'WC-',  
  121. ),  
  122. 'method' => array( 
  123. 'title' => __( 'Integration method', 'woocommerce-mercadopago' ),  
  124. 'type' => 'select',  
  125. 'description' => __( 'Choose how the customer will interact with the MercadoPago. Modal Window (Inside your store) Redirect (Client goes to MercadoPago).', 'woocommerce-mercadopago' ),  
  126. 'desc_tip' => true,  
  127. 'class' => 'wc-enhanced-select',  
  128. 'default' => 'redirect',  
  129. 'options' => array( 
  130. 'modal' => __( 'Modal Window', 'woocommerce-mercadopago' ),  
  131. 'redirect' => __( 'Redirect', 'woocommerce-mercadopago' ),  
  132. ),  
  133. ),  
  134. 'testing' => array( 
  135. 'title' => __( 'Gateway Testing', 'woocommerce-mercadopago' ),  
  136. 'type' => 'title',  
  137. 'description' => '',  
  138. ),  
  139. 'sandbox' => array( 
  140. 'title' => __( 'MercadoPago Sandbox', 'woocommerce-mercadopago' ),  
  141. 'type' => 'checkbox',  
  142. 'label' => __( 'Enable MercadoPago sandbox', 'woocommerce-mercadopago' ),  
  143. 'default' => 'no',  
  144. 'description' => __( 'MercadoPago sandbox can be used to test payments.', 'woocommerce-mercadopago' ),  
  145. ),  
  146. 'debug' => array( 
  147. 'title' => __( 'Debug Log', 'woocommerce-mercadopago' ),  
  148. 'type' => 'checkbox',  
  149. 'label' => __( 'Enable logging', 'woocommerce-mercadopago' ),  
  150. 'default' => 'no',  
  151. 'description' => sprintf( __( 'Log MercadoPago events, such as API requests. You can find the log in %s', 'woocommerce-mercadopago' ), '<a href="' . esc_url( admin_url( 'admin.php?page=wc-status&tab=logs&log_file=' . esc_attr( $this->id ) . '-' . sanitize_file_name( wp_hash( $this->id ) ) . '.log' ) ) . '">' . __( 'System Status > Logs', 'woocommerce-mercadopago' ) . '</a>' ),  
  152. ),  
  153. ); 
  154.  
  155. /** 
  156. * Admin page. 
  157. */ 
  158. public function admin_options() { 
  159. include 'admin/views/html-admin-page.php'; 
  160.  
  161. /** 
  162. * Validate order for subscriptions. 
  163. * MercadoPago have a few limitations, we can just process one subscription at a time. 
  164. * @param WC_Order $order Order data. 
  165. * @return bool 
  166. */ 
  167. public function validate_subscription_order( $order ) { 
  168. $valid = true; 
  169.  
  170. foreach ( $order->get_items() as $order_item ) { 
  171. if ( $order_item['qty'] ) { 
  172. $product = $order->get_product_from_item( $order_item ); 
  173. if ( ! in_array( $product->product_type, array( 'subscription', 'variable-subscription' ) ) ) { 
  174. wc_add_notice( '<strong>' . esc_html( $this->title ) . ': </strong>' . __( 'Only can process one subscription at a time without other products in the cart. Please remove any other products before continue.', 'woocommerce-mercadopago' ), 'error' ); 
  175.  
  176. $valid = false; 
  177. break; 
  178.  
  179. if ( $valid && 0 < WC_Subscriptions_Order::get_sign_up_fee( $order ) ) { 
  180. wc_add_notice( '<strong>' . esc_html( $this->title ) . ': </strong>' . __( 'Unable to process signatures with sign-up fees.', 'woocommerce-mercadopago' ), 'error' ); 
  181. $valid = false; 
  182.  
  183. return $valid; 
  184.  
  185. /** 
  186. * Cancel subscription. 
  187. * @param WC_Subscription $subscription Subscription data. 
  188. */ 
  189. public function cancel_subscription( $subscription ) { 
  190. if ( $id = $subscription->order->mercadopago_payment_id ) { 
  191. $this->api->cancel_subscription( $id ); 
  192.  
  193. /** 
  194. * Output for the order received page. 
  195. * @param int $order_id Order ID. 
  196. */ 
  197. public function receipt_page( $order_id ) { 
  198. $order = wc_get_order( $order_id ); 
  199. $subscription = false; 
  200.  
  201. if ( function_exists( 'wcs_order_contains_subscription' ) && wcs_order_contains_subscription( $order->id ) ) { 
  202. $subscription = true; 
  203.  
  204. $url = $this->api->get_user_payment_url( $order, $subscription ); 
  205.  
  206. include 'views/html-modal-payment.php'; 
  207.  
  208. /** 
  209. * Process subscription payment. 
  210. * @param WC_Order $order Order Data. 
  211. * @return array 
  212. */ 
  213. protected function process_subscription_payment( $order ) { 
  214. $url = ''; 
  215.  
  216. if ( $this->validate_subscription_order( $order ) ) { 
  217. if ( 'redirect' == $this->method ) { 
  218. $url = $this->api->get_user_payment_url( $order, true ); 
  219. } else { 
  220. $url = $order->get_checkout_payment_url( true ); 
  221.  
  222. return array( 
  223. 'result' => '' !== $url ? 'success' : 'fail',  
  224. 'redirect' => $url,  
  225. ); 
  226.  
  227. /** 
  228. * Process regular payment. 
  229. * @param WC_Order $order Order Data. 
  230. * @return array 
  231. */ 
  232. protected function process_regular_payment( $order ) { 
  233. if ( 'redirect' == $this->method ) { 
  234. $url = $this->api->get_user_payment_url( $order ); 
  235. } else { 
  236. $url = $order->get_checkout_payment_url( true ); 
  237.  
  238. return array( 
  239. 'result' => '' !== $url ? 'success' : 'fail',  
  240. 'redirect' => $url,  
  241. ); 
  242.  
  243. /** 
  244. * Process the payment and return the result. 
  245. * @param int $order_id Order ID. 
  246. * @return array 
  247. */ 
  248. public function process_payment( $order_id ) { 
  249. $order = wc_get_order( $order_id ); 
  250.  
  251. if ( function_exists( 'wcs_order_contains_subscription' ) && wcs_order_contains_subscription( $order->id ) ) { 
  252. return $this->process_subscription_payment( $order ); 
  253. } else { 
  254. return $this->process_regular_payment( $order ); 
  255.  
  256. /** 
  257. * IPN handler. 
  258. */ 
  259. public function ipn_handler() { 
  260. @ob_clean(); 
  261.  
  262. if ( $data = $this->api->get_payment_data( $_GET ) ) { 
  263. header( 'HTTP/1.1 200 OK' ); 
  264.  
  265. $topic = isset( $_GET['topic'] ) ? sanitize_text_field( wp_unslash( $_GET['topic'] ) ) : ''; 
  266. do_action( 'woocommerce_mercadopago_change_order_status', $data, $topic ); 
  267.  
  268. // Deprecated since 3.0.0. 
  269. do_action( 'valid_mercadopago_ipn_request', $data ); 
  270. } else { 
  271. wp_die( esc_html__( 'MercadoPago Request Unauthorized', 'woocommerce-mercadopago' ), esc_html__( 'MercadoPago Request Unauthorized', 'woocommerce-mercadopago' ), array( 'response' => 401 ) ); 
  272.  
  273. /** 
  274. * Change order status 
  275. * @param array $purchase_data MercadoPago purchase data. 
  276. * @param array $topic MercadoPago notification topic. 
  277. */ 
  278. public function change_order_status( $purchase_data, $topic ) { 
  279. if ( 'payment' !== $topic ) { 
  280. return; 
  281.  
  282. $data = $purchase_data->collection; 
  283.  
  284. if ( empty( $data->external_reference ) ) { 
  285. return; 
  286.  
  287. $order_id = intval( str_replace( $this->invoice_prefix, '', $data->external_reference ) ); 
  288. $order = wc_get_order( $order_id ); 
  289.  
  290. // Checks whether the invoice number matches the order. 
  291. // If true processes the payment. 
  292. if ( $order->id !== $order_id ) { 
  293. return; 
  294.  
  295. if ( 'yes' == $this->debug ) { 
  296. $this->log->add( $this->id, 'Payment status for order ' . $order->get_order_number() . ': ' . $data->status ); 
  297.  
  298. // Check if is a subscription order. 
  299. $is_subscription = false; 
  300. if ( function_exists( 'wcs_order_contains_subscription' ) && wcs_order_contains_subscription( $order->id ) ) { 
  301. $is_subscription = true; 
  302.  
  303. switch ( $data->status ) { 
  304. case 'pending' : 
  305. $order->add_order_note( __( 'MercadoPago: The user has not completed the payment process yet.', 'woocommerce-mercadopago' ) ); 
  306.  
  307. break; 
  308. case 'approved' : 
  309. if ( ! empty( $data->payer->email ) ) { 
  310. add_post_meta( 
  311. $order->id,  
  312. __( 'Payer email', 'woocommerce-mercadopago' ),  
  313. sanitize_text_field( $data->payer->email ),  
  314. true 
  315. ); 
  316. if ( ! empty( $data->payment_type ) ) { 
  317. add_post_meta( 
  318. $order->id,  
  319. __( 'Payment type', 'woocommerce-mercadopago' ),  
  320. sanitize_text_field( $data->payment_type ),  
  321. true 
  322. ); 
  323.  
  324. add_post_meta( $this->id, '_transaction_id', sanitize_text_field( $data->id ), true ); 
  325.  
  326. // Payment completed. 
  327. if ( $is_subscription ) { 
  328. WC_Subscriptions_Manager::process_subscription_payments_on_order( $order ); 
  329. } else if ( ! in_array( $order->get_status(), array( 'processing', 'completed' ) ) ) { 
  330. $order->payment_complete(); 
  331.  
  332. $order->add_order_note( __( 'MercadoPago: Payment approved.', 'woocommerce-mercadopago' ) ); 
  333.  
  334. break; 
  335. case 'in_process' : 
  336. $order->update_status( 'on-hold', __( 'MercadoPago: Payment under review.', 'woocommerce-mercadopago' ) ); 
  337.  
  338. break; 
  339. case 'rejected' : 
  340. if ( $is_subscription ) { 
  341. WC_Subscriptions_Manager::process_subscription_payment_failure_on_order( $order ); 
  342. } else { 
  343. $order->update_status( 'failed' ); 
  344.  
  345. $order->add_order_note( __( 'MercadoPago: The payment was declined. The user can try again.', 'woocommerce-mercadopago' ) ); 
  346.  
  347. break; 
  348. case 'refunded' : 
  349. if ( $is_subscription ) { 
  350. WC_Subscriptions_Manager::cancel_subscriptions_for_order( $order ); 
  351. } else { 
  352. $order->update_status( 'refunded' ); 
  353.  
  354. $order->add_order_note( __( 'MercadoPago: The payment was refunded.', 'woocommerce-mercadopago' ) ); 
  355.  
  356. break; 
  357. case 'cancelled' : 
  358. if ( $is_subscription ) { 
  359. WC_Subscriptions_Manager::cancel_subscriptions_for_order( $order ); 
  360. } else { 
  361. $order->update_status( 'cancelled' ); 
  362.  
  363. $order->add_order_note( __( 'MercadoPago: Payment canceled.', 'woocommerce-mercadopago' ) ); 
  364.  
  365. break; 
  366. case 'in_mediation' : 
  367. $order->add_order_note( __( 'MercadoPago: It started a dispute for payment.', 'woocommerce-mercadopago' ) ); 
  368.  
  369. break; 
  370. case 'charged_back' : 
  371. if ( $is_subscription ) { 
  372. WC_Subscriptions_Manager::process_subscription_payment_failure_on_order( $order ); 
  373. } else { 
  374. $order->update_status( 'failed' ); 
  375.  
  376. $order->add_order_note( __( 'MercadoPago: Payment refused because a credit card chargeback.', 'woocommerce-mercadopago' ) ); 
  377.  
  378. break; 
  379.  
  380. default : 
  381. // No action xD. 
  382. break;