WC_Mercadopago_API

MercadoPago Checkout API class.

Defined (1)

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

/includes/class-wc-mercadopago-api.php  
  1. class WC_Mercadopago_API { 
  2.  
  3. /** 
  4. * API URL. 
  5. * @var string 
  6. */ 
  7. protected $api_url = 'https://api.mercadopago.com/'; 
  8.  
  9. /** 
  10. * Modal JS URL. 
  11. * @var string 
  12. */ 
  13. protected $modal_js_url = 'https://www.mercadopago.com/org-img/jsapi/mptools/buttons/render.js'; 
  14.  
  15. /** 
  16. * Gateway class. 
  17. * @var WC_MercadoPago_Gateway 
  18. */ 
  19. protected $gateway; 
  20.  
  21. /** 
  22. * Constructor. 
  23. * @param WC_MercadoPago_Gateway $gateway Gateway class. 
  24. */ 
  25. public function __construct( $gateway = null ) { 
  26. $this->gateway = $gateway; 
  27.  
  28. /** 
  29. * Get API URL. 
  30. * @return string 
  31. */ 
  32. public function get_api_url() { 
  33. return $this->api_url; 
  34.  
  35. /** 
  36. * Get Checkout URL. 
  37. * @param string $credentials Access token. 
  38. * @param bool $subscription Subscription order. 
  39. * @return string 
  40. */ 
  41. public function get_checkout_url( $credentials = '', $subscription = false ) { 
  42. $endpoint = $subscription ? 'preapproval' : 'checkout/preferences'; 
  43.  
  44. return $this->get_api_url() . $endpoint . '?access_token=' . $credentials; 
  45.  
  46. /** 
  47. * Get IPN URL. 
  48. * @param string $endpoint IPN endpoint. 
  49. * @param string $id Purchase ID. 
  50. * @param string $credentials Access token. 
  51. * @return string 
  52. */ 
  53. public function get_ipn_url( $endpoint, $id, $credentials = '' ) { 
  54. $sandbox = 'yes' == $this->gateway->sandbox ? 'sandbox/' : ''; 
  55.  
  56. if ( 'preapproval' === $endpoint ) { 
  57. return $this->get_api_url() . 'preapproval/' . $id . '?access_token=' . $credentials; 
  58. } else if ( 'authorized_payment' === $endpoint ) { 
  59. return $this->get_api_url() . 'authorized_payments/' . $id . '?access_token=' . $credentials; 
  60. } else { 
  61. return $this->get_api_url() . $sandbox . 'collections/notifications/' . $id . '?access_token=' . $credentials; 
  62.  
  63. /** 
  64. * Get OAuth Token URL. 
  65. * @return string 
  66. */ 
  67. public function get_oauth_token_url() { 
  68. return $this->get_api_url() . 'oauth/token'; 
  69.  
  70. /** 
  71. * Get modal JS URL. 
  72. * @return string 
  73. */ 
  74. public function get_modal_js_url() { 
  75. return $this->modal_js_url; 
  76.  
  77. /** 
  78. * Get supported currencies. 
  79. * @return array 
  80. */ 
  81. public function get_supported_currencies() { 
  82. return apply_filters( 'woocommerce_mercadopago_supported_currencies', array( 
  83. 'ARS',  
  84. 'BOB',  
  85. 'BRL',  
  86. 'CLF',  
  87. 'CLP',  
  88. 'COP',  
  89. 'CRC',  
  90. 'CUC',  
  91. 'DOP',  
  92. 'EUR',  
  93. 'GTQ',  
  94. 'HNL',  
  95. 'MXN',  
  96. 'NIO',  
  97. 'PAB',  
  98. 'PEN',  
  99. 'PYG',  
  100. 'USD',  
  101. 'UYU',  
  102. 'VEF',  
  103. ) ); 
  104.  
  105. /** 
  106. * Format date for MercadoPago. 
  107. * @param string $date Date to convert. 
  108. * @return string 
  109. */ 
  110. protected function format_date( $date ) { 
  111. return date( 'Y-m-d\TH:i:s.ZP', strtotime( $date ) ); 
  112.  
  113. /** 
  114. * Get certificate. 
  115. * @return string 
  116. */ 
  117. protected function get_certificate() { 
  118. return plugin_dir_path( __FILE__ ) . 'certificates/cacert.pem'; 
  119.  
  120. /** 
  121. * Do requests in the MercardoPago API. 
  122. * @param string $url URL. 
  123. * @param string $method Request method (default: POST). 
  124. * @param array $data Request data (default: array()). 
  125. * @param array $headers Request headers (default: array()). 
  126. * @return array Request response. 
  127. */ 
  128. protected function do_request( $url, $method = 'POST', $data = array(), $headers = array() ) { 
  129. $params = array( 
  130. 'method' => $method,  
  131. 'timeout' => 60,  
  132. 'sslcertificates' => $this->get_certificate(),  
  133. 'headers' => array( 
  134. 'Accept' => 'application/json',  
  135. 'Content-Type' => 'application/json;charset=UTF-8',  
  136. ),  
  137. ); 
  138.  
  139. if ( ! empty( $data ) ) { 
  140. $params['body'] = $data; 
  141.  
  142. if ( ! empty( $headers ) ) { 
  143. $params['headers'] = $headers; 
  144.  
  145. return wp_safe_remote_post( $url, $params ); 
  146.  
  147. /** 
  148. * Get purchase args. 
  149. * @param WC_Order $order Order data. 
  150. * @return array 
  151. */ 
  152. protected function get_purchase_args( $order ) { 
  153. $args = array( 
  154. 'back_urls' => array( 
  155. 'success' => esc_url( $this->gateway->get_return_url( $order ) ),  
  156. 'failure' => str_replace( '&', '&', $order->get_cancel_order_url() ),  
  157. 'pending' => esc_url( $this->gateway->get_return_url( $order ) ),  
  158. ),  
  159. 'auto_return' => 'approved',  
  160. 'payer' => array( 
  161. 'name' => $order->billing_first_name,  
  162. 'surname' => $order->billing_last_name,  
  163. 'email' => $order->billing_email,  
  164. ),  
  165. 'external_reference' => $this->gateway->invoice_prefix . $order->id,  
  166. 'items' => array( 
  167. array( 
  168. 'quantity' => 1,  
  169. 'unit_price' => $order->get_total(),  
  170. 'currency_id' => $order->get_order_currency(),  
  171. 'category_id' => 'others', // Generic category ID. 
  172. ),  
  173. ),  
  174. ); 
  175.  
  176. // Cart Contents. 
  177. $item_names = array(); 
  178. if ( 0 < count( $order->get_items() ) ) { 
  179. foreach ( $order->get_items() as $item ) { 
  180. if ( $item['qty'] ) { 
  181. $item_names[] = $item['name'] . ' x ' . $item['qty']; 
  182.  
  183. $args['items'][0]['title'] = sprintf( __( 'Order %s', 'woocommerce-mercadopago' ), $order->get_order_number() ) . ' - ' . implode( ', ', $item_names ); 
  184.  
  185. // Shipping Cost item. 
  186. if ( $order->get_total_shipping() > 0 ) { 
  187. if ( defined( 'WC_VERSION' ) && version_compare( WC_VERSION, '2.2', '>=' ) ) { 
  188. $shipping_method = $order->get_shipping_method(); 
  189. } else { 
  190. $shipping_method = ucwords( $order->shipping_method_title ); 
  191.  
  192. $args['items'][0]['title'] .= ', ' . __( 'Shipping via', 'woocommerce-mercadopago' ) . ' ' . $shipping_method; 
  193.  
  194. // Deprecated since 3.0.0. 
  195. $args = apply_filters( 'woocommerce_mercadopago_args', $args, $order ); 
  196.  
  197. return apply_filters( 'woocommerce_mercadopago_purchase_args', $args, $order ); 
  198.  
  199. /** 
  200. * Get subscription payment args. 
  201. * @param WC_Order $order Order ID. 
  202. * @return array 
  203. */ 
  204. protected function get_subscription_args( $order ) { 
  205. $subscriptions = wcs_get_subscriptions_for_order( $order->id ); 
  206. $subscription = current( $subscriptions ); 
  207.  
  208. if ( ! in_array( $subscription->billing_period, array( 'day', 'month' ) ) ) { 
  209. wc_add_notice( '<strong>' . esc_html( $this->gateway->title ) . ': </strong>' . __( 'Process only daily or monthly subscriptions.', 'woocommerce-mercadopago' ), 'error' ); 
  210. return array(); 
  211.  
  212. $args = array( 
  213. 'payer_email' => $subscription->billing_email,  
  214. 'back_url' => esc_url( $this->gateway->get_return_url( $order ) ),  
  215. 'reason' => sprintf( __( '%s - Subscription for order #%s', 'woocommerce-mercadopago' ), esc_html( get_bloginfo( 'name', 'display' ) ), $order->get_order_number() ),  
  216. 'external_reference' => $this->gateway->invoice_prefix . $order->id,  
  217. 'auto_recurring' => array( 
  218. 'frequency' => (int) $subscription->billing_interval,  
  219. 'frequency_type' => $subscription->billing_period . 's',  
  220. 'transaction_amount' => (float) $subscription->get_total(),  
  221. 'currency_id' => $subscription->get_order_currency(),  
  222. ),  
  223. ); 
  224.  
  225. if ( 0 < $subscription->trial_end_date && $start_date = $subscription->calculate_date( 'trial_end' ) ) { 
  226. $args['auto_recurring']['start_date'] = $this->format_date( $start_date ); 
  227. if ( $end_date = $subscription->calculate_date( 'end' ) ) { 
  228. $args['auto_recurring']['end_date'] = $this->format_date( $end_date ); 
  229.  
  230. return apply_filters( 'woocommerce_mercadopago_subscription_args', $args, $order, $subscription ); 
  231.  
  232. /** 
  233. * Generate the payment args. 
  234. * @param WC_Order $order Order data. 
  235. * @param bool $subscription Subscription order. 
  236. * @return array 
  237. */ 
  238. protected function get_payment_args( $order, $subscription = false ) { 
  239. if ( $subscription ) { 
  240. return $this->get_subscription_args( $order ); 
  241.  
  242. return $this->get_purchase_args( $order ); 
  243.  
  244. /** 
  245. * Get cliente token. 
  246. * @return mixed Sucesse return the token and error return null. 
  247. */ 
  248. protected function get_client_credentials() { 
  249. if ( 'yes' == $this->gateway->debug ) { 
  250. $this->gateway->log->add( $this->gateway->id, 'Getting client credentials...' ); 
  251.  
  252. // Set data. 
  253. $data = build_query( array( 
  254. 'client_id' => $this->gateway->client_id,  
  255. 'client_secret' => $this->gateway->client_secret,  
  256. 'grant_type' => 'client_credentials',  
  257. ) ); 
  258. $headers = array( 
  259. 'Content-Type' => 'application/x-www-form-urlencoded',  
  260. ); 
  261.  
  262. $response = $this->do_request( $this->get_oauth_token_url(), 'POST', $data, $headers ); 
  263.  
  264. // Check if the request was valid and return the token. 
  265. if ( ! is_wp_error( $response ) && $response['response']['code'] >= 200 && $response['response']['code'] < 300 && ( strcmp( $response['response']['message'], 'OK' ) == 0 ) ) { 
  266.  
  267. $token = json_decode( $response['body'] ); 
  268.  
  269. if ( 'yes' == $this->gateway->debug ) { 
  270. $this->gateway->log->add( $this->gateway->id, 'Received valid response from MercadoPago' ); 
  271.  
  272. return $token->access_token; 
  273. } else { 
  274. if ( 'yes' == $this->gateway->debug ) { 
  275. $this->gateway->log->add( $this->gateway->id, 'Received invalid response from MercadoPago. Error response: ' . print_r( $response, true ) ); 
  276.  
  277. return null; 
  278.  
  279. /** 
  280. * Generate the MercadoPago payment url. 
  281. * @param WC_Order $order Order data. 
  282. * @param bool $subscription Subscription order. 
  283. * @return string 
  284. */ 
  285. public function get_user_payment_url( $order, $subscription = false ) { 
  286. $data = json_encode( $this->get_payment_args( $order, $subscription ) ); 
  287.  
  288. if ( empty( $data ) ) { 
  289. return ''; 
  290.  
  291. if ( 'yes' == $this->gateway->debug ) { 
  292. $this->gateway->log->add( $this->gateway->id, 'Payment arguments for order ' . $order->get_order_number() . ': ' . print_r( $data, true ) ); 
  293.  
  294. $credentials = $this->get_client_credentials(); 
  295. $url = $this->get_checkout_url( $credentials, $subscription ); 
  296. $response = $this->do_request( $url, 'POST', $data ); 
  297.  
  298. if ( ! is_wp_error( $response ) && 201 == $response['response']['code'] && ( 0 == strcmp( $response['response']['message'], 'Created' ) ) ) { 
  299. $payment_data = json_decode( $response['body'] ); 
  300.  
  301. if ( 'yes' == $this->gateway->debug ) { 
  302. $this->gateway->log->add( $this->gateway->id, 'Payment link generated from MercadoPago successfully!' ); 
  303.  
  304. add_post_meta( $order->id, '_mercadopago_payment_id', sanitize_text_field( $payment_data->id ), true ); 
  305.  
  306. if ( 'yes' == $this->gateway->sandbox ) { 
  307. return $payment_data->sandbox_init_point; 
  308. } else { 
  309. return $payment_data->init_point; 
  310. } else { 
  311. if ( 'yes' == $this->gateway->debug ) { 
  312. $this->gateway->log->add( $this->gateway->id, 'Generate payment error response: ' . print_r( $response, true ) ); 
  313.  
  314. wc_add_notice( __( 'An error has occurred while processing your order, please try again. Or contact us for assistance.', 'woocommerce-mercadopago' ), 'error' ); 
  315.  
  316. return ''; 
  317.  
  318. /** 
  319. * Get Payment data. 
  320. * @param array $data MercadoPago post data. 
  321. * @return array 
  322. */ 
  323. public function get_payment_data( $data ) { 
  324. if ( ! isset( $data['id'], $data['topic'] ) ) { 
  325. return array(); 
  326.  
  327. $data = wp_unslash( $data ); 
  328. $id = sanitize_text_field( $data['id'] ); 
  329. $topic = sanitize_text_field( $data['topic'] ); 
  330.  
  331. if ( 'yes' == $this->gateway->debug ) { 
  332. $this->gateway->log->add( $this->gateway->id, 'Checking IPN request... ID: ' . $id . ' | TOPIC: ' . $topic ); 
  333.  
  334. $credentials = $this->get_client_credentials(); 
  335. $url = $this->get_ipn_url( $topic, $id, $credentials ); 
  336. $response = $this->do_request( $url, 'GET' ); 
  337.  
  338. if ( 'yes' == $this->gateway->debug ) { 
  339. $this->gateway->log->add( $this->gateway->id, 'IPN Response: ' . print_r( $response, true ) ); 
  340.  
  341. // Check if the request was valid. 
  342. if ( ! is_wp_error( $response ) && 200 == $response['response']['code'] ) { 
  343. if ( 'yes' == $this->gateway->debug ) { 
  344. $this->gateway->log->add( $this->gateway->id, 'Received valid IPN response from MercadoPago' ); 
  345.  
  346. return json_decode( $response['body'] ); 
  347. } else { 
  348. if ( 'yes' == $this->gateway->debug ) { 
  349. $this->gateway->log->add( $this->gateway->id, 'Received invalid IPN response from MercadoPago.' ); 
  350.  
  351. return array(); 
  352.  
  353. /** 
  354. * Cancel subscription. 
  355. * @param string $id MercadoPago subscription ID. 
  356. * @return bool 
  357. */ 
  358. public function cancel_subscription( $id ) { 
  359. if ( 'yes' == $this->gateway->debug ) { 
  360. $this->gateway->log->add( $this->gateway->id, 'Cancelling subscription... MercadoPago ID: ' . $id ); 
  361.  
  362. $data = json_encode( array( 'status' => 'cancelled' ) ); 
  363. $credentials = $this->get_client_credentials(); 
  364. $url = $this->get_ipn_url( 'preapproval', $id, $credentials ); 
  365. $response = $this->do_request( $url, 'PUT', $data ); 
  366.  
  367. // Check if the request was valid. 
  368. if ( ! is_wp_error( $response ) && 200 == $response['response']['code'] ) { 
  369. $_data = json_decode( $response['body'] ); 
  370.  
  371. if ( 'cancelled' === $_data->status ) { 
  372. if ( 'yes' == $this->gateway->debug ) { 
  373. $this->gateway->log->add( $this->gateway->id, 'Subscription canceled successfully! MercadoPago ID: ' . $id ); 
  374.  
  375. return true; 
  376.  
  377. if ( 'yes' == $this->gateway->debug ) { 
  378. $this->gateway->log->add( $this->gateway->id, 'Failed to cancel subscription: ' . print_r( $response, true ) ); 
  379.  
  380. return false;