diff --git a/woocommerce-gateway-checkout-com/includes/api/class-wc-checkoutcom-api-request.php b/woocommerce-gateway-checkout-com/includes/api/class-wc-checkoutcom-api-request.php index d38a172b..f8e27993 100644 --- a/woocommerce-gateway-checkout-com/includes/api/class-wc-checkoutcom-api-request.php +++ b/woocommerce-gateway-checkout-com/includes/api/class-wc-checkoutcom-api-request.php @@ -35,12 +35,13 @@ class WC_Checkoutcom_Api_request * * @param WC_Order $order * @param $arg + * @param $subscription subscription renewal flag * @return array */ - public static function create_payment( WC_Order $order, $arg ) + public static function create_payment( WC_Order $order, $arg, $subscription = null ) { // Get payment request parameter - $request_param = WC_Checkoutcom_Api_request::get_request_param($order, $arg); + $request_param = WC_Checkoutcom_Api_request::get_request_param($order, $arg, $subscription); $core_settings = get_option('woocommerce_wc_checkout_com_cards_settings'); $gateway_debug = WC_Admin_Settings::get_option('cko_gateway_responses') == 'yes' ? true : false; @@ -74,6 +75,12 @@ public static function create_payment( WC_Order $order, $arg ) return $response; } } else { + + // Set payment id post meta if the payment id declined + if ($response->status == 'Declined') { + update_post_meta($order->id, '_cko_payment_id', $response->id); + } + $error_message = __("An error has occurred while processing your payment. Please check your card details and try again. ", 'wc_checkout_com'); // If the merchant enabled gateway response @@ -108,16 +115,17 @@ public static function create_payment( WC_Order $order, $arg ) * Build payment request parameter * @param $order * @param $card_token + * @param $subscription subscription renewal flag * @return Payment */ - private static function get_request_param(WC_Order $order, $arg) + private static function get_request_param(WC_Order $order, $arg, $subscription = null) { global $woocommerce, $wp_version; $auto_capture = WC_Admin_Settings::get_option('ckocom_card_autocap') == 1 ? true : false; $amount = $order->get_total(); $amount_cents = WC_Checkoutcom_Utility::valueToDecimal($amount, $order->get_currency()); - $three_d = WC_Admin_Settings::get_option('ckocom_card_threed') == 1 ? true : false; + $three_d = WC_Admin_Settings::get_option('ckocom_card_threed') == 1 && $subscription == null ? true : false; $attempt_no_threeD = WC_Admin_Settings::get_option('ckocom_card_notheed') == 1 ? true : false; $dynamic_descriptor = WC_Admin_Settings::get_option('ckocom_card_desctiptor') == 1 ? true : false; $mada_enable = WC_Admin_Settings::get_option('ckocom_card_mada') == 1 ? true : false; @@ -161,9 +169,13 @@ private static function get_request_param(WC_Order $order, $arg) $payment_option = 'Apple Pay'; $method = new TokenSource($arg); - } elseif(in_array ($arg, $apms_selected)) { + } elseif (in_array ($arg, $apms_selected)) { $method = WC_Checkoutcom_Api_request::get_apm_method($postData, $order, $arg); + $payment_option = $method->type; + } elseif ( ! is_null($subscription) ) { + + $method = new IdSource($arg['source_id']); } if ($method->type != 'klarna') { @@ -210,6 +222,18 @@ private static function get_request_param(WC_Order $order, $arg) 'name' => $name ); + // Check for the subscription flag + if (! is_null($subscription) ) { + $payment->merchant_initiated = true; + $payment->payment_type = "Recurring"; + $payment->previous_payment_id = get_post_meta( $arg['parent_order_id'], '_cko_payment_id', true ) ?? null; + $payment->capture = true; + + } elseif (wcs_order_contains_subscription( $order, 'parent' )) { + $payment->merchant_initiated = false; + $payment->payment_type = "Recurring"; + } + $three_ds = new ThreeDs($three_d); if ($three_ds) { @@ -408,6 +432,12 @@ public static function verify_session( $session_id ) if ($response->isSuccessful()) { return $response; } else { + + // Set payment id post meta if the payment id declined + if ($response->status == 'Declined') { + update_post_meta($response->metadata['order_id'], '_cko_payment_id', $response->id); + } + $error_message = __("An error has occurred while processing your payment. Please check your card details and try again.", 'wc_checkout_com'); // check if gateway response is enable from module settings diff --git a/woocommerce-gateway-checkout-com/includes/class-wc-gateway-checkout-com-cards.php b/woocommerce-gateway-checkout-com/includes/class-wc-gateway-checkout-com-cards.php index 577982d8..31b9b419 100644 --- a/woocommerce-gateway-checkout-com/includes/class-wc-gateway-checkout-com-cards.php +++ b/woocommerce-gateway-checkout-com/includes/class-wc-gateway-checkout-com-cards.php @@ -4,6 +4,7 @@ include_once('settings/admin/class-wc-checkoutcom-admin.php'); include_once('api/class-wc-checkoutcom-api-request.php'); include_once ('class-wc-gateway-checkout-com-webhook.php'); +include_once('subscription/class-wc-checkout-com-subscription.php'); use Checkout\Library\Exceptions\CheckoutHttpException; use Checkout\Library\Exceptions\CheckoutModelException; @@ -27,6 +28,16 @@ public function __construct() 'products', 'refunds', 'tokenization', + 'subscriptions', + 'subscription_cancellation', + 'subscription_suspension', + 'subscription_reactivation', + 'subscription_amount_changes', + 'subscription_date_changes', + 'subscription_payment_method_change', + 'subscription_payment_method_change_customer', + 'subscription_payment_method_change_admin', + 'multiple_subscriptions', ); $this->new_method_label = __( 'Use a new card', 'wc_checkout_com' ); @@ -356,6 +367,9 @@ public function process_payment( $order_id ) $this->save_token(get_current_user_id(), $result); } + // save source id for subscription + WC_Checkoutcom_Subscription::save_source_id($order_id, $order, $result['source']['id']); + // Set action id as woo transaction id update_post_meta($order_id, '_transaction_id', $result['action_id']); update_post_meta($order_id, '_cko_payment_id', $result['id']); @@ -413,6 +427,9 @@ public function callback_handler() $order_id = $result['metadata']['order_id']; $action = $result['actions']; + // Get object as an instance of WC_Subscription + $subscription_object = wc_get_order( $order_id ); + $order = new WC_Order( $order_id ); // Query order by order number to check if order exist @@ -486,6 +503,9 @@ public function callback_handler() unset($_SESSION['wc-wc_checkout_com_cards-new-payment-method']); } + // save source id for subscription + WC_Checkoutcom_Subscription::save_source_id($order_id, $subscription_object, $result['source']['id']); + $order_status = $order->get_status(); $order->add_order_note($message); @@ -752,6 +772,9 @@ function apache_request_headers() { $event_type = $data->type; switch ($event_type){ + case 'card_verified' : + $response = WC_Checkout_Com_Webhook::card_verified($data); + break; case 'payment_approved': $response = WC_Checkout_Com_Webhook::authorize_payment($data); break; diff --git a/woocommerce-gateway-checkout-com/includes/class-wc-gateway-checkout-com-webhook.php b/woocommerce-gateway-checkout-com/includes/class-wc-gateway-checkout-com-webhook.php index 998f6416..77abca6f 100644 --- a/woocommerce-gateway-checkout-com/includes/class-wc-gateway-checkout-com-webhook.php +++ b/woocommerce-gateway-checkout-com/includes/class-wc-gateway-checkout-com-webhook.php @@ -59,6 +59,40 @@ public static function authorize_payment($data) return true; } + /** + * Process webhook for card verification + * + * @param $data + * @return bool + */ + public static function card_verified($data) + { + $webhook_data = $data->data; + $order_id = $webhook_data->metadata->order_id; + $action_id = $webhook_data->action_id; + + // return false if no order id + if (empty($order_id)) { + return false; + } + + // Load order form order id + $order = self::get_wc_order($order_id); + $order_id = $order->get_id(); + + $order->add_order_note(__("Checkout.com Card verified webhook received", 'wc_checkout_com')); + // Set action id as woo transaction id + update_post_meta($order_id, '_transaction_id', $action_id); + + // Get cko capture status configured in admin + $status = WC_Admin_Settings::get_option('ckocom_order_captured'); + + // update status of the order + $order->update_status($status); + + return true; + } + /** * Process webhook for captured payment * diff --git a/woocommerce-gateway-checkout-com/includes/subscription/class-wc-checkout-com-subscription.php b/woocommerce-gateway-checkout-com/includes/subscription/class-wc-checkout-com-subscription.php new file mode 100644 index 00000000..4ec57ee6 --- /dev/null +++ b/woocommerce-gateway-checkout-com/includes/subscription/class-wc-checkout-com-subscription.php @@ -0,0 +1,94 @@ +get_id(); + + $args = array(); + + // Get subscription object from the order + if ( wcs_order_contains_subscription( $renewal_order, 'renewal' ) ) { + $subscriptions_arr = wcs_get_subscriptions_for_order( $renewal_order, array( 'order_type' => 'renewal' ) ); + } + + foreach ($subscriptions_arr as $subscriptions_obj) { + $args['source_id'] = get_post_meta( $subscriptions_obj->get_id(), '_cko_source_id', true ); + $args['parent_order_id'] = $subscriptions_obj->data['parent_id']; + } + + $payment_result = (array) WC_Checkoutcom_Api_request::create_payment($renewal_order, $args, 'renewal'); + + // Update renewal order status based on payment result + if (! isset($payment_result['error']) && empty($payment_result['error'])) { + self::update_order_status($payment_result, $renewal_order, $order_id); + } + } + + /** + * Update status of renewal order and add notes + * @param array $payment_result + * @param object $renewal_order + */ + public static function update_order_status($payment_result, $renewal_order, $order_id) { + + // Set action id as woo transaction id + update_post_meta($order_id, '_transaction_id', $payment_result['action_id']); + update_post_meta($order_id, '_cko_payment_id', $payment_result['id']); + + // Get cko auth status configured in admin + $status = WC_Admin_Settings::get_option('ckocom_order_authorised'); + $message = __("Checkout.com Payment Authorised " ."
". " Action ID : {$payment_result['action_id']} ", 'wc_checkout_com'); + + // check if payment was flagged + if ($payment_result['risk']['flagged']) { + // Get cko auth status configured in admin + $status = WC_Admin_Settings::get_option('ckocom_order_flagged'); + $message = __("Checkout.com Payment Flagged " ."
". " Action ID : {$payment_result['action_id']} ", 'wc_checkout_com'); + } + + // add notes for the order + $renewal_order->add_order_note($message); + + $order_status = $renewal_order->get_status(); + + if($order_status == 'pending') { + update_post_meta($order_id, 'cko_payment_authorized', true); + $renewal_order->update_status($status); + } + + // Reduce stock levels + wc_reduce_stock_levels( $order_id ); + + } + + /** + * Save source id for each order containing subscription + * @param $order_id + * @param object $order + * @param string $source_id + */ + public static function save_source_id($order_id, $order, $source_id) { + + // update source id for subscription payment method change + if($order instanceof WC_Subscription) { + update_post_meta($order->get_id(), '_cko_source_id', $source_id); + } + + // check for subscription and save source id + if ( WC_Subscriptions_Order::order_contains_subscription( $order_id )) { + $subscriptions = wcs_get_subscriptions_for_order( $order ); + + foreach($subscriptions as $subscription_obj) { + update_post_meta($subscription_obj->get_id(), '_cko_source_id', $source_id); + } + } + } +} \ No newline at end of file diff --git a/woocommerce-gateway-checkout-com/woocommerce-gateway-checkout-com.php b/woocommerce-gateway-checkout-com/woocommerce-gateway-checkout-com.php index 76dc81d7..1add390c 100644 --- a/woocommerce-gateway-checkout-com/woocommerce-gateway-checkout-com.php +++ b/woocommerce-gateway-checkout-com/woocommerce-gateway-checkout-com.php @@ -418,4 +418,15 @@ function cko_gateway_icon( $icons, $id ) { return false; } +} + +/** + * Hooked function to handle subscription renewal payment + */ +add_action( 'woocommerce_scheduled_subscription_payment_wc_checkout_com_cards', 'subscriptionPayment', 10, 2); +function subscriptionPayment($renewal_total, $renewal_order) { + include_once('includes/subscription/class-wc-checkout-com-subscription.php'); + + WC_Checkoutcom_Subscription::renewal_payment($renewal_total, $renewal_order); + } \ No newline at end of file