From c115f1358275e6ad2f242b4796ed3cef5e96255d Mon Sep 17 00:00:00 2001 From: Jarryd Long Date: Thu, 29 Sep 2022 13:50:26 +0200 Subject: [PATCH 1/3] Added Beta Disclaimer --- classes/class.pmprogateway_ccbill.php | 90 +++++++++++++++------------ pmpro-ccbill.php | 5 +- webhook.php | 10 +++ 3 files changed, 62 insertions(+), 43 deletions(-) diff --git a/classes/class.pmprogateway_ccbill.php b/classes/class.pmprogateway_ccbill.php index 7321e8f..439c4a0 100644 --- a/classes/class.pmprogateway_ccbill.php +++ b/classes/class.pmprogateway_ccbill.php @@ -129,7 +129,14 @@ static function pmpro_payment_option_fields($values, $gateway) ?> style="display: none;"> - +

+
+

+
+
+ +

+
@@ -457,60 +464,61 @@ function sendToCCBill(&$order) function cancel(&$order) { - //no matter what happens below, we're going to cancel the order in our system - $order->updateStatus("cancelled"); - //require a payment transaction id - if(empty($order->subscription_transaction_id)) - return false; + //no matter what happens below, we're going to cancel the order in our system + $order->updateStatus("cancelled"); + //require a payment transaction id + if(empty($order->subscription_transaction_id)) + return false; - //build the URL - $sms_link = "https://datalink.ccbill.com/utils/subscriptionManagement.cgi?"; + //build the URL + $sms_link = "https://datalink.ccbill.com/utils/subscriptionManagement.cgi?"; - $qargs = array(); - $qargs["action"] = "cancelSubscription"; - $qargs["clientSubacc"] = pmpro_getOption('ccbill_subaccount_number'); - $qargs["subscriptionId"] = $order->subscription_transaction_id; - $qargs["clientAccnum"] = pmpro_getOption('ccbill_account_number'); - $qargs["username"] = pmpro_getOption('ccbill_datalink_username'); //must be provided by CCBill - $qargs["password"] = pmpro_getOption('ccbill_datalink_password'); //must be provided by CCBill + $qargs = array(); + $qargs["action"] = "cancelSubscription"; + $qargs["clientSubacc"] = pmpro_getOption('ccbill_subaccount_number'); + $qargs["subscriptionId"] = $order->subscription_transaction_id; + $qargs["clientAccnum"] = pmpro_getOption('ccbill_account_number'); + $qargs["username"] = pmpro_getOption('ccbill_datalink_username'); //must be provided by CCBill + $qargs["password"] = pmpro_getOption('ccbill_datalink_password'); //must be provided by CCBill - $cancel_link = add_query_arg($qargs, $sms_link); - $response = wp_remote_get($cancel_link); + $cancel_link = add_query_arg($qargs, $sms_link); + $response = wp_remote_get($cancel_link); - $response_code = wp_remote_retrieve_response_code( $response ); - $response_message = wp_remote_retrieve_response_message( $response ); + $response_code = wp_remote_retrieve_response_code( $response ); + $response_message = wp_remote_retrieve_response_message( $response ); - $response_body = wp_remote_retrieve_body( $response ); - $cancel_status = filter_var($response_body, FILTER_SANITIZE_NUMBER_INT); + $response_body = wp_remote_retrieve_body( $response ); + $cancel_status = filter_var($response_body, FILTER_SANITIZE_NUMBER_INT); - if (200 != $response_code && !empty($response_message)) { + if (200 != $response_code && !empty($response_message)) { - //return new WP_Error( $response_code, $response_message ); - $cancel_error = sprintf( __( 'Cancellation of subscription id: %s may have failed. Check CCBill Admin to confirm cancellation', 'pmpro-ccbill'), $order->subscription_transaction_id ); + //return new WP_Error( $response_code, $response_message ); + $cancel_error = sprintf( __( 'Cancellation of subscription id: %s may have failed. Check CCBill Admin to confirm cancellation', 'pmpro-ccbill'), $order->subscription_transaction_id ); - $email = get_option("admin_email"); - wp_mail($email, get_option("blogname") . __( ' CCBill Subscription Cancel Error', 'pmpro-ccbill' ), $cancel_error); + $email = get_option("admin_email"); + wp_mail($email, get_option("blogname") . __( ' CCBill Subscription Cancel Error', 'pmpro-ccbill' ), $cancel_error); - } elseif ( 200 != $response_code ) { - //Unknown Error Occurred - $cancel_error = sprintf( __( 'Cancellation of subscription id: %s may have failed. Check CCBill Admin to confirm cancellation', 'pmpro-ccbill'), $order->subscription_transaction_id ); + } elseif ( 200 != $response_code ) { + //Unknown Error Occurred + $cancel_error = sprintf( __( 'Cancellation of subscription id: %s may have failed. Check CCBill Admin to confirm cancellation', 'pmpro-ccbill'), $order->subscription_transaction_id ); - $email = get_option("admin_email"); - wp_mail($email, get_option("blogname") . __( ' CCBill Subscription Cancel Error', 'pmpro-ccbill' ), $cancel_error); + $email = get_option("admin_email"); + wp_mail($email, get_option("blogname") . __( ' CCBill Subscription Cancel Error', 'pmpro-ccbill' ), $cancel_error); - } elseif( $cancel_status < 1) { - $error_code = $this->pmprocb_return_api_response( $cancel_status ); + } elseif( $cancel_status < 1) { + $error_code = $this->pmprocb_return_api_response( $cancel_status ); - //A CCBill Error has occured. They need to contact CCBill - $cancel_error = sprintf( __( 'Cancellation of subscription id: %s may have failed. Check CCBill Admin to confirm cancellation. Error: %s', 'pmpro-ccbill'), $order->subscription_transaction_id, $error_code ); + //A CCBill Error has occured. They need to contact CCBill + $cancel_error = sprintf( __( 'Cancellation of subscription id: %s may have failed. Check CCBill Admin to confirm cancellation. Error: %s', 'pmpro-ccbill'), $order->subscription_transaction_id, $error_code ); - $email = get_option("admin_email"); - wp_mail($email, get_option("blogname") . __( ' CCBill Subscription Cancel Error', 'pmpro-ccbill' ), $cancel_error); - } else { - //success - } + $email = get_option("admin_email"); + wp_mail($email, get_option("blogname") . __( ' CCBill Subscription Cancel Error', 'pmpro-ccbill' ), $cancel_error); + } else { + //success + + } - return $order; + return $order; } function pmprocb_return_api_response( $code ) diff --git a/pmpro-ccbill.php b/pmpro-ccbill.php index e9b921d..e04ac02 100644 --- a/pmpro-ccbill.php +++ b/pmpro-ccbill.php @@ -52,9 +52,10 @@ function pmpro_ccbill_admin_notice_activation_hook() { */ function pmpro_ccbill_admin_notice() { // Check transient, if available display notice. - if ( get_transient( 'pmpro-ccbill-admin-notice' ) ) { ?> + if ( get_transient( 'pmpro-ccbill-admin-notice' ) ) { + ?>
-

Visit the payment settings page to configure the CCBill Gateway.', 'pmpro-ccbill' ), esc_url( get_admin_url( null, 'admin.php?page=pmpro-paymentsettings' ) ) ); ?>

+

Visit the payment settings page to configure the CCBill Payment Gateway.', 'pmpro-ccbill' ), esc_url( get_admin_url( null, 'admin.php?page=pmpro-paymentsettings' ) ) ); ?>

membership_id); + } + } + if(!empty($redirect)) wp_redirect($redirect); exit; From 6dc7f54de049ba857f67efd7136a16d7b204d4a6 Mon Sep 17 00:00:00 2001 From: Jarryd Long Date: Thu, 29 Sep 2022 13:58:54 +0200 Subject: [PATCH 2/3] Readme adjusted --- readme.txt | 29 +++++++++++++++++------------ 1 file changed, 17 insertions(+), 12 deletions(-) diff --git a/readme.txt b/readme.txt index ddd4252..e06e75a 100644 --- a/readme.txt +++ b/readme.txt @@ -1,22 +1,29 @@ -=== Paid Memberships Pro - CCBill Gateway Add On === +=== Paid Memberships Pro - CCBill Add On === Contributors: strangerstudios -Tags: paid memberships pro, pmpro, ccbill, adult, high risk, gateway, credit card -Requires at least: 4 -Tested up to: 5.4.1 -Stable tag: .1 +Tags: paid memberships pro, payment gateway, ccbill +Requires at least: 4.0 +Tested up to: 5.5.3 +Stable tag: 0.1 -Add CCBill as a payment gateway option for Paid Memberships Pro. +Adds the ability to accept payments using the CCBill Payment Gateway == Description == -IMPORTANT NOTE: This plugin is not yet complete. +Adds CCBill as a payment gateway to your list of accepted payment gateways. CCBill makes use of an off-site payment method process. This Add On is currently in Beta. + +[Read the full documentation for the CCBill Add On](https://www.paidmembershipspro.com/add-ons/ccbill-payment-gateway/) + += Official Paid Memberships Pro Add On = + +This is an official Add On for [Paid Memberships Pro](https://www.paidmembershipspro.com), the most complete member management and membership subscriptions plugin for WordPress. == Installation == 1. Make sure you have the Paid Memberships Pro plugin installed and activated. 1. Upload the `pmpro-ccbill` directory to the `/wp-content/plugins/` directory of your site. 1. Activate the plugin through the 'Plugins' menu in WordPress. -1. Go to Memberships -> Payment Settings in your WordPress dashboard to complete the CCBill settings. + +Navigate to Memberships > Settings > Payment Gateways & SSL and select the CCBill payment gateway. You will then need to fill out the required account credentials to connect your website to the payment gateway. == Frequently Asked Questions == @@ -24,13 +31,11 @@ IMPORTANT NOTE: This plugin is not yet complete. Please post it in the GitHub issue tracker here: https://github.com/strangerstudios/pmpro-ccbill/issues -For immediate help, also post to our premium support site at http://www.paidmembershipspro.com for more documentation and our support forums. - = I need help installing, configuring, or customizing the plugin. = Please visit our premium support site at http://www.paidmembershipspro.com for more documentation and our support forums. == Changelog == -= .1 = -* Original version. += 0.1 - 2022-10-05 = +* Initial Release \ No newline at end of file From 73ad9a6f1cb40efc8c493a194604d2f541c9bb11 Mon Sep 17 00:00:00 2001 From: Jarryd Long Date: Wed, 12 Oct 2022 13:07:15 +0200 Subject: [PATCH 3/3] Formatting, spacing and sanitization applied --- classes/class.pmprogateway_ccbill.php | 348 ++++++++++++++------------ pmpro-ccbill.php | 11 +- webhook.php | 175 +++++++------ 3 files changed, 290 insertions(+), 244 deletions(-) diff --git a/classes/class.pmprogateway_ccbill.php b/classes/class.pmprogateway_ccbill.php index 7321e8f..422a7c7 100644 --- a/classes/class.pmprogateway_ccbill.php +++ b/classes/class.pmprogateway_ccbill.php @@ -4,10 +4,10 @@ add_action('init', array('PMProGateway_CCBill', 'init')); add_filter('pmpro_is_ready', array( 'PMProGateway_CCBill', 'pmpro_is_ccbill_ready' ), 999, 1 ); -class PMProGateway_CCBill extends PMProGateway -{ - function __construct($gateway = NULL) - { +class PMProGateway_CCBill extends PMProGateway { + + function __construct( $gateway = NULL ) { + $this->gateway = $gateway; return $this->gateway; } @@ -17,30 +17,32 @@ function __construct($gateway = NULL) * * @since 1.8 */ - static function init() - { + static function init() { + //make sure CCBill is a gateway option - add_filter('pmpro_gateways', array('PMProGateway_CCBill', 'pmpro_gateways')); - add_filter('pmpro_gateways_with_pending_status', array('PMProGateway_CCBill', 'pmpro_gateways_with_pending_status')); + add_filter( 'pmpro_gateways', array( 'PMProGateway_CCBill', 'pmpro_gateways' )); + add_filter( 'pmpro_gateways_with_pending_status', array( 'PMProGateway_CCBill', 'pmpro_gateways_with_pending_status' ) ); //add fields to payment settings - add_filter('pmpro_payment_options', array('PMProGateway_CCBill', 'pmpro_payment_options')); - add_filter('pmpro_payment_option_fields', array('PMProGateway_CCBill', 'pmpro_payment_option_fields'), 10, 2); + add_filter( 'pmpro_payment_options', array( 'PMProGateway_CCBill', 'pmpro_payment_options' )); + add_filter( 'pmpro_payment_option_fields', array( 'PMProGateway_CCBill', 'pmpro_payment_option_fields' ), 10, 2); //code to add at checkout $gateway = pmpro_getGateway(); - if($gateway == "ccbill") - { - add_filter('pmpro_include_payment_information_fields', '__return_false'); - add_filter('pmpro_required_billing_fields', array('PMProGateway_CCBill', 'pmpro_required_billing_fields')); - add_filter('pmpro_checkout_default_submit_button', array('PMProGateway_CCBill', 'pmpro_checkout_default_submit_button')); - add_filter('pmpro_checkout_before_change_membership_level', array('PMProGateway_CCBill', 'pmpro_checkout_before_change_membership_level'), 10, 2); + + if ( $gateway == "ccbill" ) { + + add_filter( 'pmpro_include_payment_information_fields', '__return_false'); + add_filter( 'pmpro_required_billing_fields', array( 'PMProGateway_CCBill', 'pmpro_required_billing_fields' ) ); + add_filter( 'pmpro_checkout_default_submit_button', array( 'PMProGateway_CCBill', 'pmpro_checkout_default_submit_button' ) ); + add_filter( 'pmpro_checkout_before_change_membership_level', array( 'PMProGateway_CCBill', 'pmpro_checkout_before_change_membership_level' ), 10, 2); } } - static function pmpro_gateways_with_pending_status($gateways) - { + static function pmpro_gateways_with_pending_status( $gateways ) { + $gateways[] = 'ccbill'; return $gateways; + } @@ -49,10 +51,11 @@ static function pmpro_gateways_with_pending_status($gateways) * * @since 1.8 */ - static function pmpro_gateways($gateways) - { - if(empty($gateways['ccbill'])) - $gateways['ccbill'] = __('CCBill', 'pmpro-ccbill' ); + static function pmpro_gateways( $gateways ) { + + if ( empty( $gateways['ccbill'] ) ) { + $gateways['ccbill'] = __( 'CCBill', 'pmpro-ccbill' ); + } return $gateways; } @@ -62,8 +65,8 @@ static function pmpro_gateways($gateways) * * @since 1.8 */ - static function getGatewayOptions() - { + static function getGatewayOptions() { + $options = array( 'sslseal', 'nuclear_HTTPS', @@ -88,13 +91,12 @@ static function getGatewayOptions() * * @since 1.8 */ - static function pmpro_payment_options($options) - { + static function pmpro_payment_options( $options ) { //get ccbill options $ccbill_options = PMProGateway_CCBill::getGatewayOptions(); //merge with others. - $options = array_merge($ccbill_options, $options); + $options = array_merge( $ccbill_options, $options ); return $options; } @@ -104,7 +106,7 @@ static function pmpro_payment_options($options) */ static function pmpro_is_ccbill_ready( $ready ){ - if( pmpro_getOption('ccbill_account_number') == "" || + if ( pmpro_getOption('ccbill_account_number') == "" || pmpro_getOption('ccbill_subaccount_number') == "" || pmpro_getOption('ccbill_flex_form_id') == "" || pmpro_getOption('ccbill_salt') == "" || @@ -124,83 +126,82 @@ static function pmpro_is_ccbill_ready( $ready ){ * * @since 1.8 */ - static function pmpro_payment_option_fields($values, $gateway) - { + static function pmpro_payment_option_fields( $values, $gateway ) { ?> - style="display: none;"> + style="display: none;" > - + - style="display: none;"> + style="display: none;" > - + - -
+ +
- style="display: none;"> + style="display: none;" > - + - -
+ +
- style="display: none;"> + style="display: none;" > - + - -
+ +
- style="display: none;"> + style="display: none;"> - + - -
+ +
- style="display: none;"> + style="display: none;"> - + - -
+ +
- style="display: none;"> + style="display: none;"> - + - -
+ +
- style="display: none;"> + style="display: none;"> - + -

+

@@ -212,8 +213,8 @@ static function pmpro_payment_option_fields($values, $gateway) * * @since 1.8 */ - static function pmpro_required_billing_fields($fields) - { + static function pmpro_required_billing_fields( $fields ) { + unset($fields['CardType']); unset($fields['AccountNumber']); unset($fields['ExpirationMonth']); @@ -228,15 +229,15 @@ static function pmpro_required_billing_fields($fields) * * @since 1.8 */ - static function pmpro_checkout_default_submit_button($show) - { + static function pmpro_checkout_default_submit_button( $show ) { + global $gateway, $pmpro_requirebilling; //show our submit buttons ?> - + user_id = $user_id; $morder->saveOrder(); //save discount code use - if(!empty($discount_code_id)) - $wpdb->query("INSERT INTO $wpdb->pmpro_discount_codes_uses (code_id, user_id, order_id, timestamp) VALUES('" . $discount_code_id . "', '" . $user_id . "', '" . $morder->id . "', now())"); + if ( ! empty( $discount_code_id ) ) { + $wpdb->query( + $wpdb->prepare( + "INSERT INTO {$wpdb->pmpro_discount_codes_uses} + ( code_id, user_id, order_id, timestamp ) + VALUES( %d, %d, %s, %s )", + $discount_code_id + ), + $morder->user_id, + $morder->id, + current_time( 'mysql' ) + ); + } - do_action("pmpro_before_send_to_ccbill", $user_id, $morder); + do_action( "pmpro_before_send_to_ccbill", $user_id, $morder ); + + $morder->Gateway->sendToCCBill( $morder ); - $morder->Gateway->sendToCCBill($morder); } - function pmpro_get_digest($initial_price, $initial_period, $recurring_price = null, $recurring_period = null, $number_of_rebills = null, $currency_code, $salt) - { + function pmpro_get_digest($initial_price, $initial_period, $recurring_price = null, $recurring_period = null, $number_of_rebills = null, $currency_code, $salt ) { + $initial_price = number_format($initial_price , 2, ".",""); + $stringToHash = '' . $initial_price . $initial_period @@ -288,16 +303,17 @@ function pmpro_get_digest($initial_price, $initial_period, $recurring_price = nu . $salt; return md5($stringToHash); -} + } /** * Process checkout. * */ - function process(&$order) - { - if(empty($order->code)) + function process( &$order ) { + + if ( empty( $order->code ) ) { $order->code = $order->getRandomCode(); + } //clean up a couple values $order->payment_type = "CCBill"; @@ -310,17 +326,18 @@ function process(&$order) return true; } - static function get_currency_code($currency_abbr = null) - { + static function get_currency_code( $currency_abbr = null ) { + global $pmpro_currency; $currency_code = false; - if(empty($currency_abbr)) + if ( empty( $currency_abbr ) ) { $currency_abbr = $pmpro_currency; + } + + switch( $currency_abbr ) { - switch($currency_abbr) - { case 'EUR': $currency_code = '978'; break; @@ -349,12 +366,7 @@ static function get_currency_code($currency_abbr = null) return $currency_code; } - function sendToCCBill(&$order) - { - //These are CCBill username and password not ours - - //$username = pmpro_getParam('username', 'REQUEST'); - //$password = pmpro_getParam('password', 'REQUEST'); + function sendToCCBill( &$order ) { $first_name = pmpro_getParam('bfirstname', 'REQUEST'); $last_name = pmpro_getParam('blastname', 'REQUEST'); @@ -391,7 +403,8 @@ function sendToCCBill(&$order) $initial_payment = pmpro_round_price( (float)$initial_payment + (float)$initial_payment_tax ); // Recurring membership - if( pmpro_isLevelRecurring( $order->membership_level ) ) { + if ( pmpro_isLevelRecurring( $order->membership_level ) ) { + $recurring_price = number_format($order->membership_level->billing_amount, 2, ".", ""); $recurring_period = ''; @@ -400,21 +413,23 @@ function sendToCCBill(&$order) //are best set in days, so there is no confusion over off by 1 etc. //figure out days based on period - if($order->BillingPeriod == "Day") + if ( $order->BillingPeriod == "Day" ){ $recurring_period = 1*$order->membership_level->cycle_number; - elseif($order->BillingPeriod == "Week") + } else if ( $order->BillingPeriod == "Week" ) { $recurring_period = 7*$order->membership_level->cycle_number; - elseif($order->BillingPeriod == "Month") + } else if ( $order->BillingPeriod == "Month" ) { $recurring_period = 30*$order->membership_level->cycle_number; - elseif($order->BillingPeriod == "Year") + } else if ( $order->BillingPeriod == "Year" ) { $recurring_period = 365*$order->membership_level->cycle_number; + } $number_of_rebills = ''; - if(!empty($order->membership_level->billing_limit)) + if ( ! empty( $order->membership_level->billing_limit ) ) { $number_of_rebills = $order->membership_level->billing_limit; - else + } else { $number_of_rebills = 99; //means unlimited + } $ccbill_args['recurringPrice'] = $recurring_price; $ccbill_args['recurringPeriod'] = $recurring_period; @@ -426,13 +441,13 @@ function sendToCCBill(&$order) $ccbill_args['formDigest'] = $this->pmpro_get_digest($initial_payment, $recurring_period, $recurring_price, $recurring_period, $number_of_rebills, $currency_code, $ccbill_salt); $ccbill_args['pmpro_orderid'] = $order->id; $ccbill_args['email'] = $bemail; - } + + } else { - else - { // Non-recurring membership - $ccbill_args['initialPrice'] = number_format($initial_payment, 2, ".", ""); + // Non-recurring membership + $ccbill_args['initialPrice'] = number_format( $initial_payment, 2, ".", "" ); $ccbill_args['initialPeriod'] = 2; //2 is the lowest number you can set, and initialPeriod must be set for non-recurring transactions - $ccbill_args['formDigest'] = $this->pmpro_get_digest($initial_payment, 2, $recurring_price = null, $recurring_period = null, $number_of_rebills = null, $currency_code, $ccbill_salt); + $ccbill_args['formDigest'] = $this->pmpro_get_digest( $initial_payment, 2, $recurring_price = null, $recurring_period = null, $number_of_rebills = null, $currency_code, $ccbill_salt ); $ccbill_args['pmpro_orderid'] = $order->id; $ccbill_args['email'] = $bemail; } @@ -455,89 +470,98 @@ function sendToCCBill(&$order) exit; } - function cancel(&$order) { + function cancel( &$order ) { - //no matter what happens below, we're going to cancel the order in our system - $order->updateStatus("cancelled"); - //require a payment transaction id - if(empty($order->subscription_transaction_id)) - return false; + //no matter what happens below, we're going to cancel the order in our system + $order->updateStatus( "cancelled" ); + //require a payment transaction id + if ( empty( $order->subscription_transaction_id ) ) { + return false; + } - //build the URL - $sms_link = "https://datalink.ccbill.com/utils/subscriptionManagement.cgi?"; + //build the URL + $sms_link = "https://datalink.ccbill.com/utils/subscriptionManagement.cgi?"; - $qargs = array(); - $qargs["action"] = "cancelSubscription"; - $qargs["clientSubacc"] = pmpro_getOption('ccbill_subaccount_number'); - $qargs["subscriptionId"] = $order->subscription_transaction_id; - $qargs["clientAccnum"] = pmpro_getOption('ccbill_account_number'); - $qargs["username"] = pmpro_getOption('ccbill_datalink_username'); //must be provided by CCBill - $qargs["password"] = pmpro_getOption('ccbill_datalink_password'); //must be provided by CCBill + $qargs = array(); + $qargs["action"] = "cancelSubscription"; + $qargs["clientSubacc"] = pmpro_getOption('ccbill_subaccount_number'); + $qargs["subscriptionId"] = $order->subscription_transaction_id; + $qargs["clientAccnum"] = pmpro_getOption('ccbill_account_number'); + $qargs["username"] = pmpro_getOption('ccbill_datalink_username'); //must be provided by CCBill + $qargs["password"] = pmpro_getOption('ccbill_datalink_password'); //must be provided by CCBill - $cancel_link = add_query_arg($qargs, $sms_link); - $response = wp_remote_get($cancel_link); + $cancel_link = add_query_arg($qargs, $sms_link); + $response = wp_remote_get($cancel_link); - $response_code = wp_remote_retrieve_response_code( $response ); - $response_message = wp_remote_retrieve_response_message( $response ); + $response_code = wp_remote_retrieve_response_code( $response ); + $response_message = wp_remote_retrieve_response_message( $response ); - $response_body = wp_remote_retrieve_body( $response ); - $cancel_status = filter_var($response_body, FILTER_SANITIZE_NUMBER_INT); + $response_body = wp_remote_retrieve_body( $response ); + $cancel_status = filter_var($response_body, FILTER_SANITIZE_NUMBER_INT); - if (200 != $response_code && !empty($response_message)) { + if ( 200 != $response_code && !empty( $response_message ) ) { - //return new WP_Error( $response_code, $response_message ); - $cancel_error = sprintf( __( 'Cancellation of subscription id: %s may have failed. Check CCBill Admin to confirm cancellation', 'pmpro-ccbill'), $order->subscription_transaction_id ); + //return new WP_Error( $response_code, $response_message ); + $cancel_error = sprintf( __( 'Cancellation of subscription id: %s may have failed. Check CCBill Admin to confirm cancellation', 'pmpro-ccbill'), $order->subscription_transaction_id ); - $email = get_option("admin_email"); - wp_mail($email, get_option("blogname") . __( ' CCBill Subscription Cancel Error', 'pmpro-ccbill' ), $cancel_error); + $email = get_option("admin_email"); - } elseif ( 200 != $response_code ) { - //Unknown Error Occurred - $cancel_error = sprintf( __( 'Cancellation of subscription id: %s may have failed. Check CCBill Admin to confirm cancellation', 'pmpro-ccbill'), $order->subscription_transaction_id ); + wp_mail( $email, get_option("blogname") . __( ' CCBill Subscription Cancel Error', 'pmpro-ccbill' ), $cancel_error ); - $email = get_option("admin_email"); - wp_mail($email, get_option("blogname") . __( ' CCBill Subscription Cancel Error', 'pmpro-ccbill' ), $cancel_error); + } else if ( 200 != $response_code ) { + //Unknown Error Occurred + $cancel_error = sprintf( __( 'Cancellation of subscription id: %s may have failed. Check CCBill Admin to confirm cancellation', 'pmpro-ccbill'), $order->subscription_transaction_id ); - } elseif( $cancel_status < 1) { - $error_code = $this->pmprocb_return_api_response( $cancel_status ); + $email = get_option("admin_email"); + wp_mail($email, get_option("blogname") . __( ' CCBill Subscription Cancel Error', 'pmpro-ccbill' ), $cancel_error); - //A CCBill Error has occured. They need to contact CCBill - $cancel_error = sprintf( __( 'Cancellation of subscription id: %s may have failed. Check CCBill Admin to confirm cancellation. Error: %s', 'pmpro-ccbill'), $order->subscription_transaction_id, $error_code ); + } else if( $cancel_status < 1 ) { - $email = get_option("admin_email"); - wp_mail($email, get_option("blogname") . __( ' CCBill Subscription Cancel Error', 'pmpro-ccbill' ), $cancel_error); - } else { - //success - } + $error_code = $this->pmprocb_return_api_response( $cancel_status ); + + //A CCBill Error has occured. They need to contact CCBill + $cancel_error = sprintf( __( 'Cancellation of subscription id: %s may have failed. Check CCBill Admin to confirm cancellation. Error: %s', 'pmpro-ccbill'), $order->subscription_transaction_id, $error_code ); + + $email = get_option("admin_email"); + wp_mail($email, get_option("blogname") . __( ' CCBill Subscription Cancel Error', 'pmpro-ccbill' ), $cancel_error); - return $order; + } else { + //success + } + + return $order; } - function pmprocb_return_api_response( $code ) - { + function pmprocb_return_api_response( $code ) { + + /** + * Error codes and explanations obtained from CCBill documentation + */ $error_codes = array( - "0" => __("The requested action failed.", "pmpro-ccbill" ), - "-1" => __("The arguments provided to authenticate the merchant were invalid or missing.", "pmpro-ccbill"), - "-2" => __("The subscription id provided was invalid or the subscription type is not supported by the requested action.", "pmpro-ccbill"), - "-3" => __("No record was found for the given subscription.", "pmpro-ccbill"), - "-4" => __("The given subscription was not for the account the merchant was authenticated on.", "pmpro-ccbill"), - "-5" => __("The arguments provided for the requested action were invalid or missing.", "pmpro-ccbill"), - "-6" => __("The requested action was invalid", "pmpro-ccbill"), - "-7" => __("There was an internal error or a database error and the requested action could not complete.", "pmpro-ccbill"), - "-8" => __("The IP Address the merchant was attempting to authenticate on was not in the valid range.", "pmpro-ccbill"), - "-9" => __("The merchant’s account has been deactivated for use on the Datalink system or the merchant is not permitted to perform the requested action", "pmpro-ccbill"), - "-10" => __("The merchant has not been set up to use the Datalink system.", "pmpro-ccbill"), - "-11" => __("Subscription is not eligible for a discount, recurring price less than $5.00.", "pmpro-ccbill"), - "-12" => __("The merchant has unsuccessfully logged into the system 3 or more times in the last hour. The merchant should wait an hour before attempting to login again and is advised to review the login information.", "pmpro-ccbill"), - "-15" => __("Merchant over refund threshold", "pmpro-ccbill"), - "-16" => __("Merchant over void threshold", "pmpro-ccbill"), - "-23" => __("Transaction limit reached", "pmpro-ccbill"), - "-24" => __("Purchase limit reached", "pmpro-ccbill") + "0" => __( "The requested action failed.", "pmpro-ccbill" ), + "-1" => __( "The arguments provided to authenticate the merchant were invalid or missing.", "pmpro-ccbill" ), + "-2" => __( "The subscription id provided was invalid or the subscription type is not supported by the requested action.", "pmpro-ccbill" ), + "-3" => __( "No record was found for the given subscription.", "pmpro-ccbill" ), + "-4" => __( "The given subscription was not for the account the merchant was authenticated on.", "pmpro-ccbill" ), + "-5" => __( "The arguments provided for the requested action were invalid or missing.", "pmpro-ccbill" ), + "-6" => __( "The requested action was invalid", "pmpro-ccbill" ), + "-7" => __( "There was an internal error or a database error and the requested action could not complete.", "pmpro-ccbill" ), + "-8" => __( "The IP Address the merchant was attempting to authenticate on was not in the valid range.", "pmpro-ccbill" ), + "-9" => __( "The merchant’s account has been deactivated for use on the Datalink system or the merchant is not permitted to perform the requested action", "pmpro-ccbill" ), + "-10" => __( "The merchant has not been set up to use the Datalink system.", "pmpro-ccbill" ), + "-11" => __( "Subscription is not eligible for a discount, recurring price less than $5.00.", "pmpro-ccbill" ), + "-12" => __( "The merchant has unsuccessfully logged into the system 3 or more times in the last hour. The merchant should wait an hour before attempting to login again and is advised to review the login information.", "pmpro-ccbill" ), + "-15" => __( "Merchant over refund threshold", "pmpro-ccbill" ), + "-16" => __( "Merchant over void threshold", "pmpro-ccbill" ), + "-23" => __( "Transaction limit reached", "pmpro-ccbill" ), + "-24" => __( "Purchase limit reached", "pmpro-ccbill" ) ); - if( isset( $error_codes[$code] ) ){ + if ( isset( $error_codes[$code] ) ){ return $error_codes[$code]; } - return __("Error Code Unknown", "pmpro-ccbill"); + + return __( "Error Code Unknown", "pmpro-ccbill" ); } + } diff --git a/pmpro-ccbill.php b/pmpro-ccbill.php index e9b921d..4f04a7b 100644 --- a/pmpro-ccbill.php +++ b/pmpro-ccbill.php @@ -1,7 +1,7 @@ ' . __( 'Docs', 'pmpro-ccbill' ) . '', + '' . __( 'Docs', 'pmpro-ccbill' ) . '', '' . __( 'Support', 'pmpro-ccbill' ) . '', ); $links = array_merge( $links, $new_links ); diff --git a/webhook.php b/webhook.php index 038ae38..632b537 100644 --- a/webhook.php +++ b/webhook.php @@ -7,7 +7,7 @@ $logstr = ''; //will put debug info here and write to ccbill_webhook_log.txt -if( !function_exists( 'pmpro_getParam' ) ){ +if ( ! function_exists( 'pmpro_getParam' ) ){ return; } @@ -15,23 +15,22 @@ $response = array(); -foreach($_REQUEST as $key => $value) -{ - $response[$key] = sanitize_text_field($value); +foreach( $_REQUEST as $key => $value ) { + $response[$key] = sanitize_text_field( $valu ); } //Full reference of event types and responses: //https://kb.ccbill.com/Webhooks+User+Guide -switch($event_type) -{ +switch( $event_type ) { + case 'NewSaleSuccess': - - $order_id = $response['X-pmpro_orderid']; + + $order_id = sanitize_text_field( $response['X-pmpro_orderid'] ); $morder = new MemberOrder( $order_id ); $morder->getMembershipLevel(); $morder->getUser(); - if (pmpro_ccbill_ChangeMembershipLevel( $response, $morder ) ) { + if ( pmpro_ccbill_ChangeMembershipLevel( $response, $morder ) ) { //Log the event pmpro_ccbill_webhook_log( sprintf( __( "Checkout processed (%s) success!", 'pmpro_ccbill'), $morder->code ) ); } @@ -42,10 +41,10 @@ case 'Cancellation': - $subscription_id = $response['subscriptionId']; + $subscription_id = sanitize_text_field( $response['subscriptionId'] ); $morder = new MemberOrder( $order_id ); - $morder->getLastMemberOrderBySubscriptionTransactionID($subscription_id); + $morder->getLastMemberOrderBySubscriptionTransactionID( $subscription_id ); $morder->getMembershipLevel(); $morder->getUser(); @@ -55,7 +54,7 @@ case 'RenewalSuccess': - $order_id = $response['X-pmpro_orderid']; + $order_id = sanitize_text_field( $response['X-pmpro_orderid'] ); $morder = new MemberOrder( $order_id ); $morder->getMembershipLevel(); @@ -74,36 +73,34 @@ break; } -function pmpro_ccbill_ChangeMembershipLevel($response, $morder) -{ +function pmpro_ccbill_ChangeMembershipLevel( $response, $morder ) { + //filter for level - $morder->membership_level = apply_filters("pmpro_ccbill_handler_level", $morder->membership_level, $morder->user_id); + $morder->membership_level = apply_filters( "pmpro_ccbill_handler_level", $morder->membership_level, $morder->user_id ); //set the start date to current_time('mysql') but allow filters (documented in preheaders/checkout.php) - $startdate = apply_filters("pmpro_checkout_start_date", "'" . current_time('mysql') . "'", $morder->user_id, $morder->membership_level); + $startdate = apply_filters( "pmpro_checkout_start_date", "'" . current_time('mysql') . "'", $morder->user_id, $morder->membership_level ); //fix expiration date - if(!empty($morder->membership_level->expiration_number)) - { + if ( ! empty( $morder->membership_level->expiration_number ) ) { + $enddate = "'" . date_i18n("Y-m-d", strtotime("+ " . $morder->membership_level->expiration_number . " " . $morder->membership_level->expiration_period, current_time("timestamp"))) . "'"; - } - else - { + } else { $enddate = "NULL"; } + //filter the enddate (documented in preheaders/checkout.php) $enddate = apply_filters("pmpro_checkout_end_date", $enddate, $morder->user_id, $morder->membership_level, $startdate); //get discount code $morder->getDiscountCode(); - if(!empty($morder->discount_code)) - { + if ( ! empty( $morder->discount_code ) ) { //update membership level $morder->getMembershipLevel(true); $discount_code_id = $morder->discount_code->id; - } - else + } else { $discount_code_id = ""; + } //custom level to change user to $custom_level = array( @@ -122,26 +119,27 @@ function pmpro_ccbill_ChangeMembershipLevel($response, $morder) global $pmpro_error; - if(!empty($pmpro_error)) - { + if ( ! empty( $pmpro_error ) ) { echo $pmpro_error; pmpro_ccbill_webhook_log($pmpro_error); } - if( pmpro_changeMembershipLevel($custom_level, $morder->user_id) !== false ) - { - $txn_id = $response['transactionId']; - $sub_id = $response['subscriptionId']; - $card_type = $response['cardType']; - $card_num = $response['last4']; - $card_exp = $response['expDate']; + + if ( pmpro_changeMembershipLevel($custom_level, $morder->user_id) !== false ) { + + $txn_id = sanitize_text_field( $response['transactionId'] ); + $sub_id = sanitize_text_field( $response['subscriptionId'] ); + $card_type = sanitize_text_field( $response['cardType'] ); + $card_num = sanitize_text_field( $response['last4'] ); + $card_exp = sanitize_text_field( $response['expDate'] ); $card_exp_month = substr($card_exp, 0, 2); $card_exp_year = '20'.substr($card_exp, 2); //update order status and transaction ids $morder->status = "success"; + $morder->payment_transaction_id = $txn_id; - if( intval( $response['recurringPeriod'] ) !== 0 ){ + if ( intval( $response['recurringPeriod'] ) !== 0 ) { $morder->subscription_transaction_id = $sub_id; } $morder->cardtype = $card_type; @@ -152,37 +150,53 @@ function pmpro_ccbill_ChangeMembershipLevel($response, $morder) $morder->saveOrder(); //add discount code use - if(!empty($discount_code) && !empty($use_discount_code)) - { - $wpdb->query("INSERT INTO $wpdb->pmpro_discount_codes_uses (code_id, user_id, order_id, timestamp) VALUES('" . $discount_code_id . "', '" . $morder->user_id . "', '" . $morder->id . "', '" . current_time('mysql') . "')"); + if ( ! empty( $discount_code ) && !empty( $use_discount_code ) ) { + + $wpdb->prepare( + "INSERT INTO {$wpdb->pmpro_discount_codes_uses} + ( code_id, user_id, order_id, timestamp ) + VALUES( %d, %d, %s, %s )", + $discount_code_id + ), + $morder->user_id, + $morder->id, + current_time( 'mysql' ) } + //save first and last name fields - if(!empty($_POST['firstName'])) - { - $old_firstname = get_user_meta($morder->user_id, "first_name", true); - if(!empty($old_firstname)) - update_user_meta($morder->user_id, "first_name", sanitize_text_field( $_POST['firstName'] ) ); + if ( ! empty( $_POST['firstName'] ) ) { + $old_firstname = get_user_meta( $morder->user_id, "first_name", true ); + if ( ! empty( $old_firstname ) ) { + update_user_meta( $morder->user_id, "first_name", sanitize_text_field( $_POST['firstName'] ) ); + } } - if(!empty($_POST['lastName'])) - { - $old_lastname = get_user_meta($morder->user_id, "last_name", true); + + if ( ! empty( $_POST['lastName'] ) ) { + $old_lastname = get_user_meta( $morder->user_id, "last_name", true ); - if(!empty($old_lastname)) - update_user_meta($morder->user_id, "last_name", sanitize_text_field( $_POST['lastName'] ) ); + if( ! empty( $old_lastname ) ) { + update_user_meta( $morder->user_id, "last_name", sanitize_text_field( $_POST['lastName'] ) ); + } } + //hook - do_action("pmpro_after_checkout", $morder->user_id, $morder ); + do_action( "pmpro_after_checkout", $morder->user_id, $morder ); + //setup some values for the emails - if(!empty($morder)) + if ( ! empty( $morder ) ){ $invoice = new MemberOrder($morder->id); - else + } else { $invoice = NULL; + } pmpro_ccbill_webhook_log( ( __( "CHANGEMEMBERSHIPLEVEL: ORDER: ", 'pmpro-ccbill' ) . var_export($morder, true) . "\n---\n")); $user = get_userdata($morder->user_id); - if(empty($user)) + + if ( empty( $user ) ) { return false; + } + $user->membership_level = $morder->membership_level; //make sure they have the right level info //send email to member $pmproemail = new PMProEmail(); @@ -191,20 +205,19 @@ function pmpro_ccbill_ChangeMembershipLevel($response, $morder) $pmproemail = new PMProEmail(); $pmproemail->sendCheckoutAdminEmail($user, $invoice); return true; - } - - else + } else { return false; + } } -function pmpro_ccbill_RecurringCancel( $morder ) -{ +function pmpro_ccbill_RecurringCancel( $morder ) { + global $pmpro_error; - $worked = pmpro_changeMembershipLevel( false, $morder->user->ID , 'inactive'); - if( $worked === true ) - { + $worked = pmpro_changeMembershipLevel( false, $morder->user->ID , 'inactive' ); + + if ( $worked === true ) { //send an email to the member $myemail = new PMProEmail(); $myemail->sendCancelEmail(); @@ -215,9 +228,7 @@ function pmpro_ccbill_RecurringCancel( $morder ) pmpro_ccbill_webhook_log( sprintf( __( "Subscription Cancelled (%s)", 'pmpro-ccbill'), $morder->csubscription_transaction_id ) ); return true; - } - else - { + } else { return false; } } @@ -225,37 +236,45 @@ function pmpro_ccbill_RecurringCancel( $morder ) /* Add message to webhook string */ -function pmpro_ccbill_webhook_log( $s ) -{ +function pmpro_ccbill_webhook_log( $s ) { global $logstr; $logstr .= "\t" . $s . "\n"; } /* Output webhook log and exit; */ -function pmpro_ccbill_Exit($redirect = false) -{ +function pmpro_ccbill_Exit( $redirect = false ) { global $logstr; //echo $logstr; - $logstr = var_export($_REQUEST, true) . sprintf( __( 'Logged On: %s', 'pmpro-ccbill' ), date_i18n("m/d/Y H:i:s") ) . "\n" . $logstr . "\n-------------\n"; + $logstr = var_export( $_REQUEST, true ) . sprintf( __( 'Logged On: %s', 'pmpro-ccbill' ), date_i18n("m/d/Y H:i:s") ) . "\n" . $logstr . "\n-------------\n"; //log in file or email? - if(defined('PMPRO_CCBILL_DEBUG') && PMPRO_CCBILL_DEBUG === "log") - { + if ( defined( 'PMPRO_CCBILL_DEBUG' ) && PMPRO_CCBILL_DEBUG === "log" ) { //file $loghandle = fopen(PMPRO_CCBILL_DIR. "/logs/ccbill_webhook.txt", "a+"); fwrite($loghandle, $logstr); fclose($loghandle); - } - elseif(defined('PMPRO_CCBILL_DEBUG')) - { + } else if ( defined( 'PMPRO_CCBILL_DEBUG' ) ) { //email - if(strpos(PMPRO_CCBILL_DEBUG, "@")) + if ( strpos( PMPRO_CCBILL_DEBUG, "@" ) ) { $log_email = PMPRO_CCBILL_DEBUG; //constant defines a specific email address - else + } else { $log_email = get_option("admin_email"); - wp_mail($log_email, get_option("blogname") . __( " CCBill Webhook Log", 'pmpro-ccbill' ), nl2br($logstr)); + } + + wp_mail($log_email, get_option("blogname") . ' ' . __( "CCBill Webhook Log", 'pmpro-ccbill' ), nl2br($logstr)); + } + + if ( !empty( $_REQUEST['pmpro_orderid'] ) ){ + //Coming back from the gateway, lets redirect back to membership confirmation + $morder = new MemberOrder( intval( $_REQUEST['pmpro_orderid'] ) ); + + if ( !empty( $morder ) ) { + $redirect = pmpro_url( "confirmation", "?level=" . $morder->membership_id ); + } + } + + if ( ! empty( $redirect ) ) { + wp_redirect( $redirect ); } - if(!empty($redirect)) - wp_redirect($redirect); exit; } \ No newline at end of file