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