WC_Addons_Gateway_Simplify_Commerce

Simplify Commerce Gateway for subscriptions.

Defined (1)

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

/includes/gateways/simplify-commerce/class-wc-addons-gateway-simplify-commerce.php  
  1. class WC_Addons_Gateway_Simplify_Commerce extends WC_Gateway_Simplify_Commerce { 
  2.  
  3. /** 
  4. * Constructor. 
  5. */ 
  6. public function __construct() { 
  7. parent::__construct(); 
  8.  
  9. if ( class_exists( 'WC_Subscriptions_Order' ) ) { 
  10. add_action( 'woocommerce_scheduled_subscription_payment_' . $this->id, array( $this, 'scheduled_subscription_payment' ), 10, 2 ); 
  11. add_action( 'woocommerce_subscription_failing_payment_method_updated_' . $this->id, array( $this, 'update_failing_payment_method' ), 10, 2 ); 
  12.  
  13. add_action( 'wcs_resubscribe_order_created', array( $this, 'delete_resubscribe_meta' ), 10 ); 
  14.  
  15. // Allow store managers to manually set Simplify as the payment method on a subscription 
  16. add_filter( 'woocommerce_subscription_payment_meta', array( $this, 'add_subscription_payment_meta' ), 10, 2 ); 
  17. add_filter( 'woocommerce_subscription_validate_payment_meta', array( $this, 'validate_subscription_payment_meta' ), 10, 2 ); 
  18.  
  19. if ( class_exists( 'WC_Pre_Orders_Order' ) ) { 
  20. add_action( 'wc_pre_orders_process_pre_order_completion_payment_' . $this->id, array( $this, 'process_pre_order_release_payment' ) ); 
  21.  
  22. add_filter( 'woocommerce_simplify_commerce_hosted_args', array( $this, 'hosted_payment_args' ), 10, 2 ); 
  23. add_action( 'woocommerce_api_wc_addons_gateway_simplify_commerce', array( $this, 'return_handler' ) ); 
  24.  
  25. /** 
  26. * Hosted payment args. 
  27. * @param array $args 
  28. * @param int $order_id 
  29. * @return array 
  30. */ 
  31. public function hosted_payment_args( $args, $order_id ) { 
  32. if ( ( $this->order_contains_subscription( $order_id ) ) || ( $this->order_contains_pre_order( $order_id ) && WC_Pre_Orders_Order::order_requires_payment_tokenization( $order_id ) ) ) { 
  33. $args['operation'] = 'create.token'; 
  34.  
  35. $args['redirect-url'] = WC()->api_request_url( 'WC_Addons_Gateway_Simplify_Commerce' ); 
  36.  
  37. return $args; 
  38.  
  39. /** 
  40. * Check if order contains subscriptions. 
  41. * @param int $order_id 
  42. * @return bool 
  43. */ 
  44. protected function order_contains_subscription( $order_id ) { 
  45. return function_exists( 'wcs_order_contains_subscription' ) && ( wcs_order_contains_subscription( $order_id ) || wcs_order_contains_renewal( $order_id ) ); 
  46.  
  47. /** 
  48. * Check if order contains pre-orders. 
  49. * @param int $order_id 
  50. * @return bool 
  51. */ 
  52. protected function order_contains_pre_order( $order_id ) { 
  53. return class_exists( 'WC_Pre_Orders_Order' ) && WC_Pre_Orders_Order::order_contains_pre_order( $order_id ); 
  54.  
  55. /** 
  56. * Process the subscription. 
  57. * @param WC_Order $order 
  58. * @param string $cart_token 
  59. * @uses Simplify_ApiException 
  60. * @uses Simplify_BadRequestException 
  61. * @return array 
  62. * @throws Exception 
  63. */ 
  64. protected function process_subscription( $order, $cart_token = '' ) { 
  65. try { 
  66. if ( empty( $cart_token ) ) { 
  67. $error_msg = __( 'Please make sure your card details have been entered correctly and that your browser supports JavaScript.', 'woocommerce' ); 
  68.  
  69. if ( 'yes' == $this->sandbox ) { 
  70. $error_msg .= ' ' . __( 'Developers: Please make sure that you\'re including jQuery and there are no JavaScript errors on the page.', 'woocommerce' ); 
  71.  
  72. throw new Simplify_ApiException( $error_msg ); 
  73.  
  74. // Create customer 
  75. $customer = Simplify_Customer::createCustomer( array( 
  76. 'token' => $cart_token,  
  77. 'email' => $order->billing_email,  
  78. 'name' => trim( $order->get_formatted_billing_full_name() ),  
  79. 'reference' => $order->id 
  80. ) ); 
  81.  
  82. if ( is_object( $customer ) && '' != $customer->id ) { 
  83. $this->save_subscription_meta( $order->id, $customer->id ); 
  84. } else { 
  85. $error_msg = __( 'Error creating user in Simplify Commerce.', 'woocommerce' ); 
  86.  
  87. throw new Simplify_ApiException( $error_msg ); 
  88.  
  89. $payment_response = $this->process_subscription_payment( $order, $order->get_total() ); 
  90.  
  91. if ( is_wp_error( $payment_response ) ) { 
  92. throw new Exception( $payment_response->get_error_message() ); 
  93. } else { 
  94. // Remove cart 
  95. WC()->cart->empty_cart(); 
  96.  
  97. // Return thank you page redirect 
  98. return array( 
  99. 'result' => 'success',  
  100. 'redirect' => $this->get_return_url( $order ) 
  101. ); 
  102.  
  103. } catch ( Simplify_ApiException $e ) { 
  104. if ( $e instanceof Simplify_BadRequestException && $e->hasFieldErrors() && $e->getFieldErrors() ) { 
  105. foreach ( $e->getFieldErrors() as $error ) { 
  106. wc_add_notice( $error->getFieldName() . ': "' . $error->getMessage() . '" (' . $error->getErrorCode() . ')', 'error' ); 
  107. } else { 
  108. wc_add_notice( $e->getMessage(), 'error' ); 
  109.  
  110. return array( 
  111. 'result' => 'fail',  
  112. 'redirect' => '' 
  113. ); 
  114.  
  115. /** 
  116. * Store the customer and card IDs on the order and subscriptions in the order. 
  117. * @param int $order_id 
  118. * @param string $customer_id 
  119. */ 
  120. protected function save_subscription_meta( $order_id, $customer_id ) { 
  121.  
  122. $customer_id = wc_clean( $customer_id ); 
  123.  
  124. update_post_meta( $order_id, '_simplify_customer_id', $customer_id ); 
  125.  
  126. // Also store it on the subscriptions being purchased in the order 
  127. foreach( wcs_get_subscriptions_for_order( $order_id ) as $subscription ) { 
  128. update_post_meta( $subscription->id, '_simplify_customer_id', $customer_id ); 
  129.  
  130. /** 
  131. * Process the pre-order. 
  132. * @param WC_Order $order 
  133. * @param string $cart_token 
  134. * @uses Simplify_ApiException 
  135. * @uses Simplify_BadRequestException 
  136. * @return array 
  137. */ 
  138. protected function process_pre_order( $order, $cart_token = '' ) { 
  139. if ( WC_Pre_Orders_Order::order_requires_payment_tokenization( $order->id ) ) { 
  140.  
  141. try { 
  142. if ( $order->order_total * 100 < 50 ) { 
  143. $error_msg = __( 'Sorry, the minimum allowed order total is 0.50 to use this payment method.', 'woocommerce' ); 
  144.  
  145. throw new Simplify_ApiException( $error_msg ); 
  146.  
  147. if ( empty( $cart_token ) ) { 
  148. $error_msg = __( 'Please make sure your card details have been entered correctly and that your browser supports JavaScript.', 'woocommerce' ); 
  149.  
  150. if ( 'yes' == $this->sandbox ) { 
  151. $error_msg .= ' ' . __( 'Developers: Please make sure that you\'re including jQuery and there are no JavaScript errors on the page.', 'woocommerce' ); 
  152.  
  153. throw new Simplify_ApiException( $error_msg ); 
  154.  
  155. // Create customer 
  156. $customer = Simplify_Customer::createCustomer( array( 
  157. 'token' => $cart_token,  
  158. 'email' => $order->billing_email,  
  159. 'name' => trim( $order->get_formatted_billing_full_name() ),  
  160. 'reference' => $order->id 
  161. ) ); 
  162.  
  163. if ( is_object( $customer ) && '' != $customer->id ) { 
  164. $customer_id = wc_clean( $customer->id ); 
  165.  
  166. // Store the customer ID in the order 
  167. update_post_meta( $order->id, '_simplify_customer_id', $customer_id ); 
  168. } else { 
  169. $error_msg = __( 'Error creating user in Simplify Commerce.', 'woocommerce' ); 
  170.  
  171. throw new Simplify_ApiException( $error_msg ); 
  172.  
  173. // Reduce stock levels 
  174. $order->reduce_order_stock(); 
  175.  
  176. // Remove cart 
  177. WC()->cart->empty_cart(); 
  178.  
  179. // Is pre ordered! 
  180. WC_Pre_Orders_Order::mark_order_as_pre_ordered( $order ); 
  181.  
  182. // Return thank you page redirect 
  183. return array( 
  184. 'result' => 'success',  
  185. 'redirect' => $this->get_return_url( $order ) 
  186. ); 
  187.  
  188. } catch ( Simplify_ApiException $e ) { 
  189. if ( $e instanceof Simplify_BadRequestException && $e->hasFieldErrors() && $e->getFieldErrors() ) { 
  190. foreach ( $e->getFieldErrors() as $error ) { 
  191. wc_add_notice( $error->getFieldName() . ': "' . $error->getMessage() . '" (' . $error->getErrorCode() . ')', 'error' ); 
  192. } else { 
  193. wc_add_notice( $e->getMessage(), 'error' ); 
  194.  
  195. return array( 
  196. 'result' => 'fail',  
  197. 'redirect' => '' 
  198. ); 
  199.  
  200. } else { 
  201. return parent::process_standard_payments( $order, $cart_token ); 
  202.  
  203. /** 
  204. * Process the payment. 
  205. * @param int $order_id 
  206. * @return array 
  207. */ 
  208. public function process_payment( $order_id ) { 
  209. $cart_token = isset( $_POST['simplify_token'] ) ? wc_clean( $_POST['simplify_token'] ) : ''; 
  210. $order = wc_get_order( $order_id ); 
  211.  
  212. // Processing subscription 
  213. if ( 'standard' == $this->mode && ( $this->order_contains_subscription( $order->id ) || ( function_exists( 'wcs_is_subscription' ) && wcs_is_subscription( $order_id ) ) ) ) { 
  214. return $this->process_subscription( $order, $cart_token ); 
  215.  
  216. // Processing pre-order 
  217. } elseif ( 'standard' == $this->mode && $this->order_contains_pre_order( $order->id ) ) { 
  218. return $this->process_pre_order( $order, $cart_token ); 
  219.  
  220. // Processing regular product 
  221. } else { 
  222. return parent::process_payment( $order_id ); 
  223.  
  224. /** 
  225. * process_subscription_payment function. 
  226. * @param WC_order $order 
  227. * @param int $amount (default: 0) 
  228. * @uses Simplify_BadRequestException 
  229. * @return bool|WP_Error 
  230. */ 
  231. public function process_subscription_payment( $order, $amount = 0 ) { 
  232. if ( 0 == $amount ) { 
  233. // Payment complete 
  234. $order->payment_complete(); 
  235.  
  236. return true; 
  237.  
  238. if ( $amount * 100 < 50 ) { 
  239. return new WP_Error( 'simplify_error', __( 'Sorry, the minimum allowed order total is 0.50 to use this payment method.', 'woocommerce' ) ); 
  240.  
  241. $customer_id = get_post_meta( $order->id, '_simplify_customer_id', true ); 
  242.  
  243. if ( ! $customer_id ) { 
  244. return new WP_Error( 'simplify_error', __( 'Customer not found', 'woocommerce' ) ); 
  245.  
  246. try { 
  247. // Charge the customer 
  248. $payment = Simplify_Payment::createPayment( array( 
  249. 'amount' => $amount * 100, // In cents. 
  250. 'customer' => $customer_id,  
  251. 'description' => sprintf( __( '%s - Order #%s', 'woocommerce' ), esc_html( get_bloginfo( 'name', 'display' ) ), $order->get_order_number() ),  
  252. 'currency' => strtoupper( get_woocommerce_currency() ),  
  253. 'reference' => $order->id 
  254. ) ); 
  255.  
  256. } catch ( Exception $e ) { 
  257.  
  258. $error_message = $e->getMessage(); 
  259.  
  260. if ( $e instanceof Simplify_BadRequestException && $e->hasFieldErrors() && $e->getFieldErrors() ) { 
  261. $error_message = ''; 
  262. foreach ( $e->getFieldErrors() as $error ) { 
  263. $error_message .= ' ' . $error->getFieldName() . ': "' . $error->getMessage() . '" (' . $error->getErrorCode() . ')'; 
  264.  
  265. $order->add_order_note( sprintf( __( 'Simplify payment error: %s', 'woocommerce' ), $error_message ) ); 
  266.  
  267. return new WP_Error( 'simplify_payment_declined', $e->getMessage(), array( 'status' => $e->getCode() ) ); 
  268.  
  269. if ( 'APPROVED' == $payment->paymentStatus ) { 
  270. // Payment complete 
  271. $order->payment_complete( $payment->id ); 
  272.  
  273. // Add order note 
  274. $order->add_order_note( sprintf( __( 'Simplify payment approved (ID: %s, Auth Code: %s)', 'woocommerce' ), $payment->id, $payment->authCode ) ); 
  275.  
  276. return true; 
  277. } else { 
  278. $order->add_order_note( __( 'Simplify payment declined', 'woocommerce' ) ); 
  279.  
  280. return new WP_Error( 'simplify_payment_declined', __( 'Payment was declined - please try another card.', 'woocommerce' ) ); 
  281.  
  282. /** 
  283. * scheduled_subscription_payment function. 
  284. * @param float $amount_to_charge The amount to charge. 
  285. * @param WC_Order $renewal_order A WC_Order object created to record the renewal payment. 
  286. */ 
  287. public function scheduled_subscription_payment( $amount_to_charge, $renewal_order ) { 
  288. $result = $this->process_subscription_payment( $renewal_order, $amount_to_charge ); 
  289.  
  290. if ( is_wp_error( $result ) ) { 
  291. $renewal_order->update_status( 'failed', sprintf( __( 'Simplify Transaction Failed (%s)', 'woocommerce' ), $result->get_error_message() ) ); 
  292.  
  293. /** 
  294. * Update the customer_id for a subscription after using Simplify to complete a payment to make up for. 
  295. * an automatic renewal payment which previously failed. 
  296. * @param WC_Subscription $subscription The subscription for which the failing payment method relates. 
  297. * @param WC_Order $renewal_order The order which recorded the successful payment (to make up for the failed automatic payment). 
  298. */ 
  299. public function update_failing_payment_method( $subscription, $renewal_order ) { 
  300. update_post_meta( $subscription->id, '_simplify_customer_id', get_post_meta( $renewal_order->id, '_simplify_customer_id', true ) ); 
  301.  
  302. /** 
  303. * Include the payment meta data required to process automatic recurring payments so that store managers can. 
  304. * manually set up automatic recurring payments for a customer via the Edit Subscription screen in Subscriptions v2.0+. 
  305. * @since 2.4 
  306. * @param array $payment_meta associative array of meta data required for automatic payments 
  307. * @param WC_Subscription $subscription An instance of a subscription object 
  308. * @return array 
  309. */ 
  310. public function add_subscription_payment_meta( $payment_meta, $subscription ) { 
  311.  
  312. $payment_meta[ $this->id ] = array( 
  313. 'post_meta' => array( 
  314. '_simplify_customer_id' => array( 
  315. 'value' => get_post_meta( $subscription->id, '_simplify_customer_id', true ),  
  316. 'label' => 'Simplify Customer ID',  
  317. ),  
  318. ),  
  319. ); 
  320.  
  321. return $payment_meta; 
  322.  
  323. /** 
  324. * Validate the payment meta data required to process automatic recurring payments so that store managers can. 
  325. * manually set up automatic recurring payments for a customer via the Edit Subscription screen in Subscriptions 2.0+. 
  326. * @since 2.4 
  327. * @param string $payment_method_id The ID of the payment method to validate 
  328. * @param array $payment_meta associative array of meta data required for automatic payments 
  329. * @return array 
  330. * @throws Exception 
  331. */ 
  332. public function validate_subscription_payment_meta( $payment_method_id, $payment_meta ) { 
  333. if ( $this->id === $payment_method_id ) { 
  334. if ( ! isset( $payment_meta['post_meta']['_simplify_customer_id']['value'] ) || empty( $payment_meta['post_meta']['_simplify_customer_id']['value'] ) ) { 
  335. throw new Exception( 'A "_simplify_customer_id" value is required.' ); 
  336.  
  337. /** 
  338. * Don't transfer customer meta to resubscribe orders. 
  339. * @access public 
  340. * @param int $resubscribe_order The order created for the customer to resubscribe to the old expired/cancelled subscription 
  341. * @return void 
  342. */ 
  343. public function delete_resubscribe_meta( $resubscribe_order ) { 
  344. delete_post_meta( $resubscribe_order->id, '_simplify_customer_id' ); 
  345.  
  346. /** 
  347. * Process a pre-order payment when the pre-order is released. 
  348. * @param WC_Order $order 
  349. * @return WP_Error|null 
  350. */ 
  351. public function process_pre_order_release_payment( $order ) { 
  352.  
  353. try { 
  354. $order_items = $order->get_items(); 
  355. $order_item = array_shift( $order_items ); 
  356. $pre_order_name = sprintf( __( '%s - Pre-order for "%s"', 'woocommerce' ), esc_html( get_bloginfo( 'name', 'display' ) ), $order_item['name'] ) . ' ' . sprintf( __( '(Order #%s)', 'woocommerce' ), $order->get_order_number() ); 
  357.  
  358. $customer_id = get_post_meta( $order->id, '_simplify_customer_id', true ); 
  359.  
  360. if ( ! $customer_id ) { 
  361. return new WP_Error( 'simplify_error', __( 'Customer not found', 'woocommerce' ) ); 
  362.  
  363. // Charge the customer 
  364. $payment = Simplify_Payment::createPayment( array( 
  365. 'amount' => $order->order_total * 100, // In cents. 
  366. 'customer' => $customer_id,  
  367. 'description' => trim( substr( $pre_order_name, 0, 1024 ) ),  
  368. 'currency' => strtoupper( get_woocommerce_currency() ),  
  369. 'reference' => $order->id 
  370. ) ); 
  371.  
  372. if ( 'APPROVED' == $payment->paymentStatus ) { 
  373. // Payment complete 
  374. $order->payment_complete( $payment->id ); 
  375.  
  376. // Add order note 
  377. $order->add_order_note( sprintf( __( 'Simplify payment approved (ID: %s, Auth Code: %s)', 'woocommerce' ), $payment->id, $payment->authCode ) ); 
  378. } else { 
  379. return new WP_Error( 'simplify_payment_declined', __( 'Payment was declined - the customer need to try another card.', 'woocommerce' ) ); 
  380. } catch ( Exception $e ) { 
  381. $order_note = sprintf( __( 'Simplify Transaction Failed (%s)', 'woocommerce' ), $e->getMessage() ); 
  382.  
  383. // Mark order as failed if not already set,  
  384. // otherwise, make sure we add the order note so we can detect when someone fails to check out multiple times 
  385. if ( 'failed' != $order->get_status() ) { 
  386. $order->update_status( 'failed', $order_note ); 
  387. } else { 
  388. $order->add_order_note( $order_note ); 
  389.  
  390. /** 
  391. * Return handler for Hosted Payments. 
  392. */ 
  393. public function return_handler() { 
  394. if ( ! isset( $_REQUEST['cardToken'] ) ) { 
  395. parent::return_handler(); 
  396.  
  397. @ob_clean(); 
  398. header( 'HTTP/1.1 200 OK' ); 
  399.  
  400. $redirect_url = wc_get_page_permalink( 'cart' ); 
  401.  
  402. if ( isset( $_REQUEST['reference'] ) && isset( $_REQUEST['amount'] ) ) { 
  403. $cart_token = $_REQUEST['cardToken']; 
  404. $amount = absint( $_REQUEST['amount'] ); 
  405. $order_id = absint( $_REQUEST['reference'] ); 
  406. $order = wc_get_order( $order_id ); 
  407. $order_total = absint( $order->order_total * 100 ); 
  408.  
  409. if ( $amount === $order_total ) { 
  410. if ( $this->order_contains_subscription( $order->id ) ) { 
  411. $response = $this->process_subscription( $order, $cart_token ); 
  412. } elseif ( $this->order_contains_pre_order( $order->id ) ) { 
  413. $response = $this->process_pre_order( $order, $cart_token ); 
  414. } else { 
  415. $response = parent::process_standard_payments( $order, $cart_token ); 
  416.  
  417. if ( 'success' == $response['result'] ) { 
  418. $redirect_url = $response['redirect']; 
  419. } else { 
  420. $order->update_status( 'failed', __( 'Payment was declined by Simplify Commerce.', 'woocommerce' ) ); 
  421.  
  422. wp_redirect( $redirect_url ); 
  423. exit(); 
  424.  
  425. wp_redirect( $redirect_url ); 
  426. exit();