Changeset 2790425
- Timestamp:
- 09/26/2022 05:35:24 PM (3 years ago)
- Location:
- thebunch-ke-pesapal-woocommerce/trunk
- Files:
-
- 4 edited
-
lib/OAuth.php (modified) (1 diff)
-
lib/gateway.php (modified) (1 diff)
-
readme.txt (modified) (2 diffs)
-
thebunchke_pesapal_woocommerce.php (modified) (4 diffs)
Legend:
- Unmodified
- Added
- Removed
-
thebunch-ke-pesapal-woocommerce/trunk/lib/OAuth.php
r2224659 r2790425 1 1 <?php 2 /** 3 * Gateway helpers. 4 * 5 * @package TheBunchKEPesaPal 6 */ 7 8 if ( ! defined( 'ABSPATH' ) ) { 9 exit; // Exit if accessed directly. 10 } 2 11 3 12 /* -
thebunch-ke-pesapal-woocommerce/trunk/lib/gateway.php
r2725075 r2790425 1 1 <?php 2 /** 3 * Gateway class. 4 * 5 * @package TheBunchKEPesaPal 6 */ 7 2 8 if ( ! defined( 'ABSPATH' ) ) { 3 exit; // Exit if accessed directly 9 exit; // Exit if accessed directly. 4 10 } 5 11 6 12 if ( class_exists( 'WC_Payment_Gateway' ) ) { 7 if ( !class_exists( 'WC_TheBunchKE_PesaPal_Pay_Gateway' ) ) { 8 9 class WC_TheBunchKE_PesaPal_Pay_Gateway extends WC_Payment_Gateway { 10 11 function __construct(){ 12 13 //Settings 14 $this->id = 'pesapal'; 15 $this->method_title = 'Pesapal'; 16 $this->has_fields = false; 17 $this->testmode = ( $this->get_option('testmode') === 'yes' ) ? true : false; 18 $this->debug = $this->get_option( 'debug' ); 19 $this->title = $this->get_option('title'); 20 $this->description = $this->get_option('description'); 21 $this->use_cron = ( $this->get_option('use_cron') === 'yes' ); 22 $default_prefix = substr( str_shuffle( str_repeat( "ABCDEFGHJKMNPQRSTUVWXYZ", 4 ) ), 0, 4 ); 23 $order_prefix = $this->get_option( 'order_prefix', $default_prefix ); 24 25 $this->order_prefix = strtoupper( str_replace( "-","", str_replace( " ", "", $order_prefix ) ) ); 26 27 //Set up logging 28 $this->log = wc_get_logger(); 29 30 //Set up API details 31 if( $this->testmode ) { 32 $api = 'https://demo.pesapal.com/'; 33 $this->consumer_key = $this->get_option('testconsumerkey'); 34 $this->consumer_secret = $this->get_option('testsecretkey'); 35 } else { 36 $api = 'https://www.pesapal.com/'; 37 $this->consumer_key = $this->get_option('consumerkey'); 38 $this->consumer_secret = $this->get_option('secretkey'); 39 } 40 41 //OAuth Signatures 42 $this->consumer = new PesaPalOAuthConsumer($this->consumer_key, $this->consumer_secret); 43 $this->signature_method = new PesaPalOAuthSignatureMethod_HMAC_SHA1(); 44 $this->token = $this->params = NULL; 45 46 //PesaPal End Points 47 $this->gatewayURL = $api.'api/PostPesapalDirectOrderV4'; 48 $this->QueryPaymentStatus = $api.'API/QueryPaymentStatus'; 49 $this->QueryPaymentStatusByMerchantRef = $api.'API/QueryPaymentStatusByMerchantRef'; 50 $this->querypaymentdetails = $api.'API/querypaymentdetails'; 51 52 //IPN URL 53 $this->notify_url = add_query_arg( 'wc-api', strtolower( get_class( $this ) ), home_url( '/' ) ); 54 $this->rest_ipn_url = rest_url( 'thebunchke-pespal/v1/ipn-listener' ); 55 56 $this->init_form_fields(); 57 $this->init_settings(); 58 59 if ( is_admin() ) { 60 add_action('woocommerce_update_options_payment_gateways_' . $this->id, array( $this, 'process_admin_options' ) ); 61 } 62 63 add_action('woocommerce_receipt_'.$this->id, array( $this, 'payment_page' ) ); 64 65 add_action( 'woocommerce_api_callback', array( $this, 'ipn_response' ) ); 66 13 if ( ! class_exists( 'WC_TheBunchKE_PesaPal_Pay_Gateway' ) ) { 14 15 /** 16 * Main gateway class. 17 */ 18 class WC_TheBunchKE_PesaPal_Pay_Gateway extends WC_Payment_Gateway { 19 20 /** 21 * If logging is enabled. 22 * 23 * @var bool 24 */ 25 public static bool $log_enabled = false; 26 27 /** 28 * Logger instance. 29 * 30 * @var bool|WC_Logger 31 */ 32 public static $log = false; 33 34 /** 35 * Main constructor. 36 */ 37 public function __construct() { 38 39 // Settings. 40 $this->id = 'pesapal'; 41 $this->method_title = 'Pesapal'; 42 $this->has_fields = false; 43 $this->testmode = ( $this->get_option( 'testmode' ) === 'yes' ) ? true : false; 44 $this->debug = 'yes' === $this->get_option( 'debug', 'no' ); 45 $this->title = $this->get_option( 'title' ); 46 $this->description = $this->get_option( 'description' ); 47 $this->use_cron = ( $this->get_option( 'use_cron' ) === 'yes' ); 48 $default_prefix = substr( str_shuffle( str_repeat( 'ABCDEFGHJKMNPQRSTUVWXYZ', 4 ) ), 0, 4 ); 49 $order_prefix = $this->get_option( 'order_prefix', $default_prefix ); 50 51 $this->order_prefix = strtoupper( str_replace( '-', '', str_replace( ' ', '', $order_prefix ) ) ); 52 self::$log_enabled = $this->debug; 53 54 55 // Set up API details. 56 if ( $this->testmode ) { 57 $api = 'https://demo.pesapal.com/'; 58 $this->consumer_key = $this->get_option( 'testconsumerkey' ); 59 $this->consumer_secret = $this->get_option( 'testsecretkey' ); 60 } else { 61 $api = 'https://www.pesapal.com/'; 62 $this->consumer_key = $this->get_option( 'consumerkey' ); 63 $this->consumer_secret = $this->get_option( 'secretkey' ); 64 } 65 66 // OAuth Signatures. 67 $this->consumer = new PesaPalOAuthConsumer( $this->consumer_key, $this->consumer_secret ); 68 $this->signature_method = new PesaPalOAuthSignatureMethod_HMAC_SHA1(); 69 $this->token = null; 70 $this->params = null; 71 72 // PesaPal End Points. 73 $this->gateway_url = $api . 'api/PostPesapalDirectOrderV4'; 74 $this->query_payment_status = $api . 'API/QueryPaymentStatus'; 75 $this->query_payment_status_by_merchant_ref = $api . 'API/QueryPaymentStatusByMerchantRef'; 76 $this->query_payment_details = $api . 'API/querypaymentdetails'; 77 78 // IPN URL. 79 $this->notify_url = add_query_arg( 'wc-api', strtolower( get_class( $this ) ), home_url( '/' ) ); 80 $this->rest_ipn_url = rest_url( 'thebunchke-pespal/v1/ipn-listener' ); 81 82 $this->init_form_fields(); 83 $this->init_settings(); 84 85 if ( is_admin() ) { 86 add_action( 'woocommerce_update_options_payment_gateways_' . $this->id, array( $this, 'process_admin_options' ) ); 87 } 88 89 add_action( 'woocommerce_receipt_' . $this->id, array( $this, 'payment_page' ) ); 90 91 add_action( 'woocommerce_api_callback', array( $this, 'ipn_response' ) ); 92 67 93 add_action( 'woocommerce_api_wc_gateway_' . $this->id, array( $this, 'ipn_response' ) ); 68 69 add_action('thebunchke_pesapal_woo_bckground_cron', array( $this, 'check_order_status' ) ); 70 71 } 72 73 74 /** 75 * Handle logging 76 * 77 * @since 1.0.0 78 * 79 * @param string $message 80 */ 81 function pesapal_do_log( $message ) { 82 if ( 'yes' == $this->debug ) { 83 $this->log->debug( $message, array( 'source' => $this->id ) ); 84 } 85 } 86 87 88 function init_form_fields() { 89 $this->form_fields = array( 90 'enabled' => array( 91 'title' => __( 'Enable/Disable', 'woothemes' ), 92 'type' => 'checkbox', 93 'label' => __( 'Enable Pesapal Payment', 'woothemes' ), 94 'default' => 'no' 95 ), 96 'title' => array( 97 'title' => __( 'Title', 'woothemes' ), 98 'type' => 'text', 99 'description' => __( 'This controls the title which the user sees during checkout.', 'woothemes' ), 100 'default' => __( 'Pesapal Payment', 'woothemes' ) 101 ), 102 'order_prefix' => array( 103 'title' => __( 'Order Prefix', 'woothemes' ), 104 'type' => 'text', 105 'description' => __( 'This is the prefix appended to all order to ensure you do not have duplicate pesapal merchant references generated by other systems connected to your Pesapal account.', 'woothemes' ), 106 'default' => $this->order_prefix 107 ), 108 'description' => array( 109 'title' => __( 'Description', 'woocommerce' ), 110 'type' => 'textarea', 111 'description' => __( 'This is the description which the user sees during checkout.', 'woocommerce' ), 112 'default' => __("Payment via Pesapal Gateway, you can pay by either credit/debit card or use mobile payment option such as Mpesa.", 'woocommerce') 113 ), 114 'testmode' => array( 115 'title' => __( 'Use Demo Gateway', 'woothemes' ), 116 'type' => 'checkbox', 117 'label' => __( 'Use Demo Gateway', 'woothemes' ), 118 'description' => __( 'Use demo pesapal gateway for testing from your account at <a href="https://demo.pesapal.com">https://demo.pesapal.com</a>', 'woothemes' ), 119 'default' => 'no' 120 ), 121 'consumerkey' => array( 122 'title' => __( 'Pesapal Consumer Key', 'woothemes' ), 123 'type' => 'text', 124 'description' => __( 'Your Pesapal consumer key which should have been emailed to you.', 'woothemes' ), 125 'default' => '' 126 ), 127 'secretkey' => array( 128 'title' => __( 'Pesapal Secret Key', 'woothemes' ), 129 'type' => 'text', 130 'description' => __( 'Your Pesapal secret key which should have been emailed to you.', 'woothemes' ), 131 'default' => '' 132 ), 133 134 'testconsumerkey' => array( 135 'title' => __( 'Pesapal Demo Consumer Key', 'woothemes' ), 136 'type' => 'text', 137 'description' => __( 'Your demo Pesapal consumer key which can be seen at demo.pesapal.com.', 'woothemes' ), 138 'default' => '' 139 ), 140 141 'testsecretkey' => array( 142 'title' => __( 'Pesapal Demo Secret Key', 'woothemes' ), 143 'type' => 'text', 144 'description' => __( 'Your demo Pesapal secret key which can be seen at demo.pesapal.com.', 'woothemes' ), 145 'default' => '' 146 ), 147 148 'debug' => array( 149 'title' => __( 'Debug Log', 'woocommerce' ), 150 'type' => 'checkbox', 151 'label' => __( 'Enable logging', 'woocommerce' ), 152 'default' => 'no', 153 'description' => sprintf( __( 'Log PesaPal events, such as IPN requests, inside <code>woocommerce/logs/pesapal-%s.txt</code>', 'woocommerce' ), sanitize_file_name( wp_hash( 'pesapal' ) ) ), 154 ), 155 156 'use_cron' => array( 157 'title' => __( 'Use Background Cron', 'woocommerce' ), 158 'type' => 'checkbox', 159 'label' => __( 'Use Background Cron', 'woocommerce' ), 160 'default' => 'no', 161 'description' => __( 'In case IPN has issues, you can add a cron job on your server that will be a back-up process to ensure transactions get completed. Enable this to set the cron to run every 5 mins. However, its advisable to ensure IPN is up and running', 'woocommerce' ), 162 ) 163 ); 164 } 165 166 public function admin_options() { 167 ?> 168 <h3><?php _e('Pesapal', 'woothemes'); ?></h3> 169 <p> 170 <?php _e('PesaPal requires Full names and email/phone number. To handle IPN return requests, please set the url '); ?> 171 <strong><?php echo $this->notify_url; ?></strong><br/> <?php _e( 'or' ); ?> 172 <strong><?php echo $this->rest_ipn_url; ?></strong> 173 174 <?php _e(' in your <a href="https://www.pesapal.com/merchantdashboard" target="_blank">PesaPal</a> account settings'); ?> 175 </p> 176 <table class="form-table"> 177 <?php $this->generate_settings_html(); ?> 178 </table> 179 <script type="text/javascript"> 180 jQuery(function(){ 181 var testMode = jQuery("#woocommerce_pesapal_testmode"); 182 var live_consumer = jQuery("#woocommerce_pesapal_consumerkey"); 183 var live_secrect = jQuery("#woocommerce_pesapal_secretkey"); 184 var test_consumer = jQuery("#woocommerce_pesapal_testconsumerkey"); 185 var test_secrect = jQuery("#woocommerce_pesapal_testsecretkey"); 186 if (testMode.is(":not(:checked)")){ 187 test_consumer.parents("tr").hide(); 188 test_secrect.parents("tr").hide(); 189 190 live_consumer.parents("tr").show(); 191 live_secrect.parents("tr").show(); 192 } 193 testMode.click(function(){ 194 // If checked 195 if (testMode.is(":checked")) { 196 //show the hidden div 197 test_consumer.parents("tr").show("fast"); 198 test_secrect.parents("tr").show("fast"); 199 200 live_consumer.parents("tr").hide("fast"); 201 live_secrect.parents("tr").hide("fast"); 202 } else { 203 //otherwise, hide it 204 test_consumer.parents("tr").hide("fast"); 205 test_secrect.parents("tr").hide("fast"); 206 207 live_consumer.parents("tr").show("fast"); 208 live_secrect.parents("tr").show("fast"); 209 } 210 }); 211 }); 212 </script> 213 <?php 214 } 215 216 217 function process_payment( $order_id ) { 218 global $woocommerce; 219 220 $order = wc_get_order( $order_id ); 221 222 if($order->get_status() === 'completed'){ 223 //Redirect to payment page 224 return array( 225 'result' => 'success', 226 'redirect' => $this->get_return_url( $order ) 227 ); 228 }else{ 229 return array( 230 'result' => 'success', 231 'redirect' => $order->get_checkout_payment_url(true) 232 ); 233 } 234 } 235 236 237 //Create Payment Page 238 function payment_page($order_id){ 239 if(isset($_REQUEST['pesapal_merchant_reference'])){ 240 $order = wc_get_order( $order_id ); 241 $pesapalMerchantReference = $_REQUEST['pesapal_merchant_reference']; 242 $pesapalTrackingId = $_REQUEST['pesapal_transaction_tracking_id']; 243 244 $transactionDetails = $this->getTransactionDetails($pesapalMerchantReference,$pesapalTrackingId); 245 246 add_post_meta( $order_id, '_order_pesapal_transaction_tracking_id', $transactionDetails['pesapal_transaction_tracking_id']); 247 add_post_meta( $order_id, '_order_thebunchke_pesapalment_method', $transactionDetails['payment_method']); 248 249 add_post_meta( $order_id, '_order_payment_method', $transactionDetails['payment_method']); 250 251 if($transactionDetails['status'] === 'COMPLETED'){ 252 $order->payment_complete(); 253 }else{ 254 $order->update_status('wc-processing', 'Payment accepted, awaiting confirmation'); 255 } 256 return array( 257 'result' => 'success', 258 'redirect' => $this->get_return_url( $order ) 259 ); 260 261 }else{ 262 $url = $this->create_url($order_id); 263 ?> 264 <div class="pesapal_container" style="position:relative;"> 265 <img class="pesapal_loading_preloader" src="<?php echo THEBUNCHKE_PESAPAL_WOO_PLUGIN_URL; ?>/assets/img/loader.gif" alt="loading" style="position:absolute;"/> 266 <iframe class="pesapal_loading_frame" src="<?php echo $url; ?>" width="100%" height="700px" scrolling="yes" frameBorder="0"> 267 <p><?php _e('Browser unable to load iFrame', 'woothemes'); ?></p> 268 </iframe> 269 </div> 270 <script> 271 jQuery(function(){ 272 jQuery('.pesapal_loading_frame').on('load', function () { 273 jQuery('.pesapal_loading_preloader').hide(); 274 }); 275 }); 276 </script> 277 <?php 278 } 279 } 280 281 function thankyou_page($order_id) { 282 283 if(isset($_REQUEST['pesapal_transaction_tracking_id'])){ 284 $order = wc_get_order( $order_id ); 285 $pesapalMerchantReference = $_REQUEST['pesapal_merchant_reference']; 286 $pesapalTrackingId = $_REQUEST['pesapal_transaction_tracking_id']; 287 288 $transactionDetails = $this->getTransactionDetails($pesapalMerchantReference,$pesapalTrackingId); 289 290 $order->add_order_note( __('Payment accepted, awaiting confirmation.', 'woothemes') ); 291 add_post_meta( $order_id, '_order_pesapal_transaction_tracking_id', $transactionDetails['pesapal_transaction_tracking_id']); 292 add_post_meta( $order_id, '_order_thebunchke_pesapalment_method', $transactionDetails['payment_method']); 293 294 add_post_meta( $order_id, '_order_payment_method', $transactionDetails['payment_method']); 295 296 if($transactionDetails['status'] === 'COMPLETED'){ 297 $order->payment_complete(); 298 }else{ 299 $order->update_status('wc-processing', 'Payment accepted, awaiting confirmation'); 300 } 301 } 302 WC()->cart->empty_cart(); 303 } 304 305 306 /** 307 * Create iframe URL 308 * 309 */ 310 function create_url($order_id){ 311 $order = wc_get_order( $order_id ); 312 $order_xml = $this->pesapal_xml($order,$order_id); 313 $callback_url = $this->get_return_url( $order ); //add_query_arg('key', $order->order_key, add_query_arg('order', $order_id, $this->get_return_url( $order ))); 314 //$callback_url = add_query_arg('key', $order->order_key, add_query_arg('order', $order_id, $order->get_checkout_order_received_url())); 315 316 $url = PesaPalOAuthRequest::from_consumer_and_token($this->consumer, $this->token, "GET", $this->gatewayURL, $this->params); 317 $url->set_parameter("oauth_callback", $callback_url); 318 $url->set_parameter("pesapal_request_data", $order_xml); 319 $url->sign_request($this->signature_method, $this->consumer, $this->token); 320 return $url; 321 } 322 323 /** 324 * Generate PesaPal XML 325 */ 326 function pesapal_xml($order,$order_id) { 327 $pesapal_args['total'] = $order->get_total(); 328 $pesapal_args['reference'] = $this->order_prefix . '-' .$order_id; 329 $pesapal_args['first_name'] = $order->get_billing_first_name(); 330 $pesapal_args['last_name'] = $order->get_billing_last_name(); 331 $pesapal_args['email'] = $order->get_billing_email(); 332 $pesapal_args['phone'] = preg_replace( "/[^0-9]/", "", str_replace( ' ', '', $order->get_billing_phone() ) ); 333 334 $description = sprintf( __( 'Order at %s, from %s'), bloginfo('name'), $order->billing_first_name . " " . $order->billing_email . " " . $order->billing_phone ); 335 $lineitem = ''; 94 95 add_action( 'thebunchke_pesapal_woo_bckground_cron', array( $this, 'check_order_status' ) ); 96 97 } 98 99 /** 100 * Logging method. 101 * 102 * @param string|array|object $message Log message. 103 * @param string $level Optional. Default 'info'. Possible values: 104 * emergency|alert|critical|error|warning|notice|info|debug. 105 */ 106 public static function log( $message, $level = 'info' ) { 107 if ( self::$log_enabled ) { 108 if ( empty( self::$log ) ) { 109 self::$log = wc_get_logger(); 110 } 111 if ( ! is_string( $message ) ) { 112 $message = print_r( $message, true ); 113 } 114 self::$log->log( $level, $message, array( 'source' => 'pesapal' ) ); 115 } 116 } 117 118 /** 119 * Set up form fields. 120 * 121 * @return void 122 */ 123 public function init_form_fields() { 124 $this->form_fields = array( 125 'enabled' => array( 126 'title' => __( 'Enable/Disable', 'woothemes' ), 127 'type' => 'checkbox', 128 'label' => __( 'Enable Pesapal Payment', 'woothemes' ), 129 'default' => 'no', 130 ), 131 'title' => array( 132 'title' => __( 'Title', 'woothemes' ), 133 'type' => 'text', 134 'description' => __( 'This controls the title which the user sees during checkout.', 'woothemes' ), 135 'default' => __( 'Pesapal Payment', 'woothemes' ), 136 ), 137 'order_prefix' => array( 138 'title' => __( 'Order Prefix', 'woothemes' ), 139 'type' => 'text', 140 'description' => __( 'This is the prefix appended to all order to ensure you do not have duplicate pesapal merchant references generated by other systems connected to your Pesapal account.', 'woothemes' ), 141 'default' => $this->order_prefix, 142 ), 143 'description' => array( 144 'title' => __( 'Description', 'woocommerce' ), 145 'type' => 'textarea', 146 'description' => __( 'This is the description which the user sees during checkout.', 'woocommerce' ), 147 'default' => __( 'Payment via Pesapal Gateway, you can pay by either credit/debit card or use mobile payment option such as Mpesa.', 'woocommerce' ), 148 ), 149 'testmode' => array( 150 'title' => __( 'Use Demo Gateway', 'woothemes' ), 151 'type' => 'checkbox', 152 'label' => __( 'Use Demo Gateway', 'woothemes' ), 153 'description' => __( 'Use demo pesapal gateway for testing from your account at <a href="https://demo.pesapal.com">https://demo.pesapal.com</a>', 'woothemes' ), 154 'default' => 'no', 155 ), 156 'consumerkey' => array( 157 'title' => __( 'Pesapal Consumer Key', 'woothemes' ), 158 'type' => 'text', 159 'description' => __( 'Your Pesapal consumer key which should have been emailed to you.', 'woothemes' ), 160 'default' => '', 161 ), 162 'secretkey' => array( 163 'title' => __( 'Pesapal Secret Key', 'woothemes' ), 164 'type' => 'text', 165 'description' => __( 'Your Pesapal secret key which should have been emailed to you.', 'woothemes' ), 166 'default' => '', 167 ), 168 169 'testconsumerkey' => array( 170 'title' => __( 'Pesapal Demo Consumer Key', 'woothemes' ), 171 'type' => 'text', 172 'description' => __( 'Your demo Pesapal consumer key which can be seen at demo.pesapal.com.', 'woothemes' ), 173 'default' => '', 174 ), 175 176 'testsecretkey' => array( 177 'title' => __( 'Pesapal Demo Secret Key', 'woothemes' ), 178 'type' => 'text', 179 'description' => __( 'Your demo Pesapal secret key which can be seen at demo.pesapal.com.', 'woothemes' ), 180 'default' => '', 181 ), 182 183 'debug' => array( 184 'title' => __( 'Debug Log', 'woocommerce' ), 185 'type' => 'checkbox', 186 'label' => __( 'Enable logging', 'woocommerce' ), 187 'default' => 'no', 188 'description' => sprintf( __( 'Log PesaPal events, such as IPN requests, inside <code>woocommerce/logs/pesapal-%s.txt</code>', 'woocommerce' ), sanitize_file_name( wp_hash( 'pesapal' ) ) ), 189 ), 190 191 'use_cron' => array( 192 'title' => __( 'Use Background Cron', 'woocommerce' ), 193 'type' => 'checkbox', 194 'label' => __( 'Use Background Cron', 'woocommerce' ), 195 'default' => 'no', 196 'description' => __( 'In case IPN has issues, you can add a cron job on your server that will be a back-up process to ensure transactions get completed. Enable this to set the cron to run every 5 mins. However, its advisable to ensure IPN is up and running', 'woocommerce' ), 197 ), 198 ); 199 } 200 201 /** 202 * Admin options. 203 * 204 * @return void 205 */ 206 public function admin_options() { 207 ?> 208 <h3><?php esc_html_e( 'Pesapal', 'woothemes' ); ?></h3> 209 <p> 210 <?php esc_html_e( 'PesaPal requires Full names and email/phone number. To handle IPN return requests, please set the url ' ); ?> 211 <strong><?php echo esc_url( $this->notify_url ); ?></strong><br/> <?php esc_html_e( 'or' ); ?> 212 <strong><?php echo esc_url( $this->rest_ipn_url ); ?></strong> 213 <?php esc_html_e( ' in your <a href="https://www.pesapal.com/merchantdashboard" target="_blank">PesaPal</a> account settings' ); ?> 214 </p> 215 <table class="form-table"> 216 <?php $this->generate_settings_html(); ?> 217 </table> 218 <script type="text/javascript"> 219 jQuery(function(){ 220 var testMode = jQuery("#woocommerce_pesapal_testmode"); 221 var live_consumer = jQuery("#woocommerce_pesapal_consumerkey"); 222 var live_secrect = jQuery("#woocommerce_pesapal_secretkey"); 223 var test_consumer = jQuery("#woocommerce_pesapal_testconsumerkey"); 224 var test_secrect = jQuery("#woocommerce_pesapal_testsecretkey"); 225 if (testMode.is(":not(:checked)")){ 226 test_consumer.parents("tr").hide(); 227 test_secrect.parents("tr").hide(); 228 live_consumer.parents("tr").show(); 229 live_secrect.parents("tr").show(); 230 } 231 testMode.click(function(){ 232 // If checked 233 if (testMode.is(":checked")) { 234 //show the hidden div 235 test_consumer.parents("tr").show("fast"); 236 test_secrect.parents("tr").show("fast"); 237 live_consumer.parents("tr").hide("fast"); 238 live_secrect.parents("tr").hide("fast"); 239 } else { 240 //otherwise, hide it 241 test_consumer.parents("tr").hide("fast"); 242 test_secrect.parents("tr").hide("fast"); 243 live_consumer.parents("tr").show("fast"); 244 live_secrect.parents("tr").show("fast"); 245 } 246 }); 247 }); 248 </script> 249 <?php 250 } 251 252 /** 253 * Process payment. 254 * 255 * @param int $order_id The order id. 256 * 257 * @return array 258 */ 259 public function process_payment( $order_id ) { 260 global $woocommerce; 261 262 $order = wc_get_order( $order_id ); 263 264 if ( in_array( $order->get_status(), array( 'processing', 'completed' ) ) ) { 265 // Redirect to payment page 266 return array( 267 'result' => 'success', 268 'redirect' => $this->get_return_url( $order ), 269 ); 270 } else { 271 return array( 272 'result' => 'success', 273 'redirect' => $order->get_checkout_payment_url( true ), 274 ); 275 } 276 } 277 278 279 /** 280 * Create the payment page. 281 * 282 * @param int $order_id The order id. 283 * 284 * @return array 285 */ 286 public function payment_page( $order_id ) { 287 if ( isset( $_REQUEST['pesapal_merchant_reference'] ) && isset( $_REQUEST['pesapal_transaction_tracking_id'] ) ) { 288 $order = wc_get_order( $order_id ); 289 $pesapal_merchant_reference = sanitize_text_field( wp_unslash( $_REQUEST['pesapal_merchant_reference'] ) ); 290 $pesapal_transaction_tracking_id = sanitize_text_field( wp_unslash( $_REQUEST['pesapal_transaction_tracking_id'] ) ); 291 292 $transaction_details = $this->getTransactionDetails( $pesapal_merchant_reference, $pesapal_transaction_tracking_id ); 293 294 add_post_meta( $order_id, '_order_pesapal_transaction_tracking_id', $transaction_details['pesapal_transaction_tracking_id'] ); 295 add_post_meta( $order_id, '_order_thebunchke_pesapalment_method', $transaction_details['payment_method'] ); 296 297 add_post_meta( $order_id, '_order_payment_method', $transaction_details['payment_method'] ); 298 299 if ( 'COMPLETED' === $transaction_details['status'] ) { 300 $order->payment_complete(); 301 } else { 302 $order->update_status( 'wc-processing', 'Payment accepted, awaiting confirmation' ); 303 } 304 return array( 305 'result' => 'success', 306 'redirect' => $this->get_return_url( $order ), 307 ); 308 309 } else { 310 $url = $this->create_url( $order_id ); 311 ?> 312 <div class="pesapal_container" style="position:relative;"> 313 <img class="pesapal_loading_preloader" src="<?php echo esc_url( THEBUNCHKE_PESAPAL_WOO_PLUGIN_URL ); ?>/assets/img/loader.gif" alt="loading" style="position:absolute;"/> 314 <iframe class="pesapal_loading_frame" src="<?php echo esc_url( $url ); ?>" width="100%" height="700px" scrolling="yes" frameBorder="0"> 315 <p><?php esc_html_e( 'Browser unable to load iFrame', 'woothemes' ); ?></p> 316 </iframe> 317 </div> 318 <script> 319 jQuery(function(){ 320 jQuery('.pesapal_loading_frame').on('load', function () { 321 jQuery('.pesapal_loading_preloader').hide(); 322 }); 323 }); 324 </script> 325 <?php 326 } 327 } 328 329 /** 330 * Generate the thank you page. 331 * 332 * @param int $order_id The order id. 333 * 334 * @return void 335 */ 336 public function thankyou_page( $order_id ) { 337 338 if ( isset( $_REQUEST['pesapal_merchant_reference'] ) && isset( $_REQUEST['pesapal_transaction_tracking_id'] ) ) { 339 $order = wc_get_order( $order_id ); 340 $pesapal_merchant_reference = sanitize_text_field( wp_unslash( $_REQUEST['pesapal_merchant_reference'] ) ); 341 $pesapal_transaction_tracking_id = sanitize_text_field( wp_unslash( $_REQUEST['pesapal_transaction_tracking_id'] ) ); 342 343 $transaction_details = $this->getTransactionDetails( $pesapal_merchant_reference, $pesapal_transaction_tracking_id ); 344 345 $order->add_order_note( __( 'Payment accepted, awaiting confirmation.', 'woothemes' ) ); 346 add_post_meta( $order_id, '_order_pesapal_transaction_tracking_id', $transaction_details['pesapal_transaction_tracking_id'] ); 347 add_post_meta( $order_id, '_order_thebunchke_pesapalment_method', $transaction_details['payment_method'] ); 348 349 add_post_meta( $order_id, '_order_payment_method', $transaction_details['payment_method'] ); 350 351 if ( 'COMPLETED' === $transaction_details['status'] ) { 352 $order->payment_complete(); 353 } else { 354 $order->update_status( 'wc-processing', 'Payment accepted, awaiting confirmation' ); 355 } 356 } 357 WC()->cart->empty_cart(); 358 } 359 360 361 /** 362 * Create iframe URL. 363 * 364 * @param int $order_id The order id. 365 * 366 * @return string. 367 */ 368 public function create_url( $order_id ) { 369 $order = wc_get_order( $order_id ); 370 $order_xml = $this->pesapal_xml( $order, $order_id ); 371 $callback_url = $this->get_return_url( $order ); // add_query_arg('key', $order->order_key, add_query_arg('order', $order_id, $this->get_return_url( $order ))); 372 // $callback_url = add_query_arg('key', $order->order_key, add_query_arg('order', $order_id, $order->get_checkout_order_received_url())); 373 374 $url = PesaPalOAuthRequest::from_consumer_and_token( $this->consumer, $this->token, 'GET', $this->gateway_url, $this->params ); 375 $url->set_parameter( 'oauth_callback', $callback_url ); 376 $url->set_parameter( 'pesapal_request_data', $order_xml ); 377 $url->sign_request( $this->signature_method, $this->consumer, $this->token ); 378 return $url; 379 } 380 381 /** 382 * Generate PesaPal XML. 383 * 384 * @param WC_Order $order The current order. 385 * @param int $order_id The order id. 386 * 387 * @return string 388 */ 389 public function pesapal_xml( $order, $order_id ) { 390 $pesapal_args['total'] = $order->get_total(); 391 $pesapal_args['reference'] = $this->order_prefix . '-' . $order_id; 392 $pesapal_args['first_name'] = $order->get_billing_first_name(); 393 $pesapal_args['last_name'] = $order->get_billing_last_name(); 394 $pesapal_args['email'] = $order->get_billing_email(); 395 $pesapal_args['phone'] = preg_replace( '/[^0-9]/', '', str_replace( ' ', '', $order->get_billing_phone() ) ); 396 397 $description = sprintf( __( 'Order at %1$s, from %2$s' ), bloginfo( 'name' ), $order->billing_first_name . ' ' . $order->billing_email . ' ' . $order->billing_phone ); 398 $lineitem = ''; 336 399 foreach ( $order->get_items() as $item_key => $item_values ) { 337 $item_name = $item_values->get_name(); 338 $item_name = trim( preg_replace( '/ +/', ' ', preg_replace( '/[^A-Za-z0-9 ]/', ' ', urldecode( html_entity_decode( strip_tags( $item_name ) ) ) ) ) ); 339 $item_name = str_replace( array( '(', ')' ), '', htmlentities( substr( $item_name, 0, 99 ) ) ); 340 $item_quantity = $item_values->get_quantity(); 341 $item_total = $item_values->get_total(); 342 $item_price = $item_total/ $item_quantity; 343 $lineitem .= "<lineitem uniqueid='".( $item_key + 1 )."' particulars='" . $item_name . "' quantity='" . $item_quantity . "' unitcost='" . $item_price . "' subtotal='" . $item_total . "'></lineitem>"; 344 } 345 346 $xml = "<?xml version=\"1.0\" encoding=\"utf-8\"?> 347 <PesapalDirectOrderInfo 348 xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" 349 xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" 350 Amount=\"" . $pesapal_args['total'] . "\" 351 Description=\"Order from " . $description . ".\" 352 Type=\"MERCHANT\" 353 Reference=\"" . $pesapal_args['reference'] . "\" 354 FirstName=\"" . $pesapal_args['first_name'] . "\" 355 LastName=\"" . $pesapal_args['last_name'] . "\" 356 Email=\"" . $pesapal_args['email'] . "\" 357 PhoneNumber=\"" . $pesapal_args['phone'] . "\" 358 Currency=\"" . get_woocommerce_currency() . "\" 359 xmlns=\"http://www.pesapal.com\"> 360 <lineitems>".$lineitem."</lineitems> 361 </PesapalDirectOrderInfo>"; 362 363 return htmlentities( $xml ); 364 } 365 366 367 function status_request($transaction_id, $merchant_ref){ 368 $request_status = PesaPalOAuthRequest::from_consumer_and_token($this->consumer, $this->token, "GET", $this->gatewayURL, $this->params); 369 $request_status->set_parameter("pesapal_merchant_reference", $merchant_ref); 370 $request_status->set_parameter("pesapal_transaction_tracking_id", $transaction_id); 371 $request_status->sign_request($this->signature_method, $this->consumer, $this->token); 372 373 return $this->checkTransactionStatus($merchant_ref); 374 } 375 376 377 /** 378 * Check Transaction status 379 * 380 * @return PENDING/FAILED/INVALID 381 **/ 382 function checkTransactionStatus($pesapalMerchantReference,$pesapalTrackingId = NULL){ 383 if($pesapalTrackingId) 384 $queryURL = $this->QueryPaymentStatus; 385 else 386 $queryURL = $this->QueryPaymentStatusByMerchantRef; 387 388 //get transaction status 389 $request_status = PesaPalOAuthRequest::from_consumer_and_token( 390 $this->consumer, 391 $this->token, 392 "GET", 393 $queryURL, 394 $this->params 395 ); 396 397 $request_status->set_parameter("pesapal_merchant_reference", $pesapalMerchantReference); 398 399 if($pesapalTrackingId) 400 $request_status->set_parameter("pesapal_transaction_tracking_id",$pesapalTrackingId); 401 402 $request_status->sign_request($this->signature_method, $this->consumer, $this->token); 403 404 return $this->curlRequest($request_status); 405 } 406 407 /** 408 * Check Transaction status 409 * 410 * @return PENDING/FAILED/INVALID 411 **/ 412 function getTransactionDetails($pesapalMerchantReference,$pesapalTrackingId){ 413 414 $request_status = PesaPalOAuthRequest::from_consumer_and_token( 415 $this->consumer, 416 $this->token, 417 "GET", 418 $this->querypaymentdetails, 419 $this->params 420 ); 421 422 $request_status->set_parameter("pesapal_merchant_reference", $pesapalMerchantReference); 423 $request_status->set_parameter("pesapal_transaction_tracking_id",$pesapalTrackingId); 424 $request_status->sign_request($this->signature_method, $this->consumer, $this->token); 425 426 $responseData = $this->curlRequest($request_status); 427 428 $pesapalResponse = explode(",", $responseData); 429 $pesapalResponseArray=array('pesapal_transaction_tracking_id'=>$pesapalResponse[0], 430 'payment_method'=>$pesapalResponse[1], 431 'status'=>$pesapalResponse[2], 432 'pesapal_merchant_reference'=>$pesapalResponse[3] 433 ); 434 435 return $pesapalResponseArray; 436 } 437 438 /** 439 * Check Transaction status 440 * 441 * @return ARRAY 442 **/ 443 function curlRequest($request_status){ 444 445 $response = wp_remote_get( $request_status ); 446 if ( is_wp_error( $response) ) { 447 return __( 'An Error Occurred' ); 448 } else { 449 $resp_body = wp_remote_retrieve_body( $response ); 450 return $resp_body; 451 } 452 453 } 454 455 /** 456 * IPN Response 457 * 458 * @return null 459 **/ 460 function ipn_response(){ 461 462 $this->pesapal_do_log( 'IPN Begin' ); 463 464 $this->pesapal_do_log( var_export( $_REQUEST, true ) ); 465 466 $pesapalTrackingId = ''; 467 $pesapalNotification = ''; 468 $pesapalMerchantReference = ''; 469 470 if ( isset( $_REQUEST['pesapal_merchant_reference'] ) ) { 471 $pesapalMerchantReference = $_REQUEST['pesapal_merchant_reference']; 472 } 473 474 if ( isset( $_REQUEST['pesapal_transaction_tracking_id'] ) ) { 475 $pesapalTrackingId = $_REQUEST['pesapal_transaction_tracking_id']; 476 } 477 478 if ( isset( $_REQUEST['pesapal_notification_type'] ) ) { 479 $pesapalNotification=$_REQUEST['pesapal_notification_type']; 480 } 481 482 $transactionDetails = $this->getTransactionDetails( $pesapalMerchantReference,$pesapalTrackingId ); 483 484 $this->pesapal_do_log( 'IPN Response' ); 485 486 $this->pesapal_do_log( var_export( $transactionDetails, true ) ); 487 //Get original order id 488 $order_id = str_replace( strtoupper( $this->order_prefix ).'-','', $pesapalMerchantReference ); 489 $order = wc_get_order( $order_id ); 490 if ( $order ) { 491 // We are here so lets check status and do actions 492 switch ( $transactionDetails['status'] ) { 493 case 'COMPLETED' : 494 case 'PENDING' : 495 496 // Check order not already completed 497 if ( $order->get_status() == 'completed' ) { 498 if ( 'yes' == $this->debug ) 499 $this->log->add( 'pesapal', 'Aborting, Order #' . $order->id . ' is already complete.' ); 500 exit; 501 } 502 503 if ( $transactionDetails['status'] == 'COMPLETED' ) { 504 $order->add_order_note( __( 'IPN payment completed', 'woocommerce' ) ); 505 $order->payment_complete(); 506 } else { 507 $order->update_status( 'on-hold', sprintf( __( 'Payment pending: %s', 'woocommerce' ), 'Waiting PesaPal confirmation' ) ); 508 } 509 510 if ( 'yes' == $this->debug ) 511 $this->log->add( 'pesapal', 'Payment complete.' ); 512 513 break; 514 case 'INVALID' : 515 case 'FAILED' : 516 // Order failed 517 $order->update_status( 'failed', sprintf( __( 'Payment %s via IPN.', 'woocommerce' ), strtolower( $transactionDetails['status'] ) ) ); 518 break; 519 520 default : 521 // No action 522 break; 523 } 524 } 525 526 if ( $pesapalNotification =="CHANGE" && $transactionDetails['status'] != "PENDING" ){ 527 $resp = "pesapal_notification_type=$pesapalNotification". 528 "&pesapal_transaction_tracking_id=$pesapalTrackingId". 529 "&pesapal_merchant_reference=$pesapalMerchantReference"; 530 531 ob_start(); 532 echo $resp; 533 ob_flush(); 534 535 } 536 exit(); 400 $item_name = $item_values->get_name(); 401 $item_name = trim( preg_replace( '/ +/', ' ', preg_replace( '/[^A-Za-z0-9 ]/', ' ', urldecode( html_entity_decode( strip_tags( $item_name ) ) ) ) ) ); 402 $item_name = str_replace( array( '(', ')' ), '', htmlentities( substr( $item_name, 0, 99 ) ) ); 403 $item_quantity = $item_values->get_quantity(); 404 $item_total = $item_values->get_total(); 405 $item_price = $item_total / $item_quantity; 406 $lineitem .= "<lineitem uniqueid='" . ( $item_key + 1 ) . "' particulars='" . $item_name . "' quantity='" . $item_quantity . "' unitcost='" . $item_price . "' subtotal='" . $item_total . "'></lineitem>"; 407 } 408 409 $xml = '<?xml version="1.0" encoding="utf-8"?> 410 <PesapalDirectOrderInfo 411 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 412 xmlns:xsd="http://www.w3.org/2001/XMLSchema" 413 Amount="' . $pesapal_args['total'] . '" 414 Description="Order from ' . $description . '." 415 Type="MERCHANT" 416 Reference="' . $pesapal_args['reference'] . '" 417 FirstName="' . $pesapal_args['first_name'] . '" 418 LastName="' . $pesapal_args['last_name'] . '" 419 Email="' . $pesapal_args['email'] . '" 420 PhoneNumber="' . $pesapal_args['phone'] . '" 421 Currency="' . get_woocommerce_currency() . '" 422 xmlns="http://www.pesapal.com"> 423 <lineitems>' . $lineitem . '</lineitems> 424 </PesapalDirectOrderInfo>'; 425 426 return htmlentities( $xml ); 427 } 428 429 /** 430 * Process the status request. 431 * 432 * @param string $transaction_id The transaction id. 433 * @param string $merchant_ref Te merchant ref. 434 * 435 * @return string 436 */ 437 public function status_request( $transaction_id, $merchant_ref ) { 438 $request_status = PesaPalOAuthRequest::from_consumer_and_token( $this->consumer, $this->token, 'GET', $this->gateway_url, $this->params ); 439 $request_status->set_parameter( 'pesapal_merchant_reference', $merchant_ref ); 440 $request_status->set_parameter( 'pesapal_transaction_tracking_id', $transaction_id ); 441 $request_status->sign_request( $this->signature_method, $this->consumer, $this->token ); 442 443 return $this->checkTransactionStatus( $merchant_ref ); 444 } 445 446 447 /** 448 * Check Transaction status 449 * 450 * @return PENDING/FAILED/INVALID 451 **/ 452 public function checkTransactionStatus( $pesapal_merchant_reference, $pesapal_transaction_tracking_id = null ) { 453 if ( $pesapal_transaction_tracking_id ) { 454 $query_url = $this->query_payment_status; 455 } else { 456 $query_url = $this->query_payment_status_by_merchant_ref; 457 } 458 459 // get transaction status 460 $request_status = PesaPalOAuthRequest::from_consumer_and_token( 461 $this->consumer, 462 $this->token, 463 'GET', 464 $query_url, 465 $this->params 466 ); 467 468 $request_status->set_parameter( 'pesapal_merchant_reference', $pesapal_merchant_reference ); 469 470 if ( $pesapal_transaction_tracking_id ) { 471 $request_status->set_parameter( 'pesapal_transaction_tracking_id', $pesapal_transaction_tracking_id ); 472 } 473 474 $request_status->sign_request( $this->signature_method, $this->consumer, $this->token ); 475 476 return $this->curlRequest( $request_status ); 477 } 478 479 /** 480 * Check Transaction status 481 * 482 * @return PENDING/FAILED/INVALID 483 **/ 484 public function getTransactionDetails( $pesapal_merchant_reference, $pesapal_transaction_tracking_id ) { 485 486 $request_status = PesaPalOAuthRequest::from_consumer_and_token( 487 $this->consumer, 488 $this->token, 489 'GET', 490 $this->query_payment_details, 491 $this->params 492 ); 493 494 $request_status->set_parameter( 'pesapal_merchant_reference', $pesapal_merchant_reference ); 495 $request_status->set_parameter( 'pesapal_transaction_tracking_id', $pesapal_transaction_tracking_id ); 496 $request_status->sign_request( $this->signature_method, $this->consumer, $this->token ); 497 498 $response_data = $this->curlRequest( $request_status ); 499 500 $pesapal_response = explode( ',', $response_data ); 501 return array( 502 'pesapal_transaction_tracking_id' => $pesapal_response[0], 503 'payment_method' => $pesapal_response[1], 504 'status' => $pesapal_response[2], 505 'pesapal_merchant_reference' => $pesapal_response[3], 506 ); 507 } 508 509 /** 510 * Check Transaction status. 511 * 512 * @return ARRAY 513 **/ 514 public function curlRequest( $request_status ) { 515 516 $response = wp_remote_get( $request_status ); 517 if ( is_wp_error( $response ) ) { 518 return __( 'An Error Occurred' ); 519 } else { 520 $resp_body = wp_remote_retrieve_body( $response ); 521 return $resp_body; 522 } 523 524 } 525 526 /** 527 * IPN Response 528 * 529 * @return null 530 **/ 531 public function ipn_response() { 532 533 self::log( 'IPN Begin' ); 534 535 self::log( $_REQUEST ); 536 537 $pesapal_transaction_tracking_id = ''; 538 $pesapal_notification = ''; 539 $pesapal_merchant_reference = ''; 540 541 if ( isset( $_REQUEST['pesapal_merchant_reference'] ) ) { 542 $pesapal_merchant_reference = sanitize_text_field( wp_unslash( $_REQUEST['pesapal_merchant_reference'] ) ); 543 } 544 545 if ( isset( $_REQUEST['pesapal_transaction_tracking_id'] ) ) { 546 $pesapal_transaction_tracking_id = sanitize_text_field( wp_unslash( $_REQUEST['pesapal_transaction_tracking_id'] ) ); 547 } 548 549 if ( isset( $_REQUEST['pesapal_notification_type'] ) ) { 550 $pesapal_notification = sanitize_text_field( wp_unslash( $_REQUEST['pesapal_notification_type'] ) ); 551 } 552 553 $transaction_details = $this->getTransactionDetails( $pesapal_merchant_reference, $pesapal_transaction_tracking_id ); 554 555 self::log( 'IPN Response' ); 556 557 self::log( $transaction_details ); 558 // Get original order id. 559 $order_id = str_replace( strtoupper( $this->order_prefix ) . '-', '', $pesapal_merchant_reference ); 560 $order = wc_get_order( $order_id ); 561 if ( $order ) { 562 // We are here so lets check status and do actions. 563 switch ( $transaction_details['status'] ) { 564 case 'COMPLETED': 565 case 'PENDING': 566 // Check order not already completed. 567 if ( in_array( $order->get_status(), array( 'processing', 'completed' ) ) ) { 568 if ( 'yes' == $this->debug ) { 569 $this->log->add( 'pesapal', 'Aborting, Order #' . $order->id . ' is already complete.' ); 570 } 571 exit; 572 } 573 574 if ( 'COMPLETED' === $transaction_details['status'] ) { 575 $order->add_order_note( __( 'IPN payment completed', 'woocommerce' ) ); 576 $order->payment_complete(); 577 } else { 578 $order->update_status( 'on-hold', sprintf( __( 'Payment pending: %s', 'woocommerce' ), 'Waiting PesaPal confirmation' ) ); 579 } 580 581 if ( 'yes' == $this->debug ) { 582 $this->log->add( 'pesapal', 'Payment complete.' ); 583 } 584 585 break; 586 case 'INVALID': 587 case 'FAILED': 588 // Order failed. 589 $order->update_status( 'failed', sprintf( __( 'Payment %s via IPN.', 'woocommerce' ), strtolower( $transactionDetails['status'] ) ) ); 590 break; 591 592 default: 593 // No action. 594 break; 595 } 596 } 597 598 if ( 'CHANGE' === $pesapal_notification && 'PENDING' !== $transaction_details['status'] ) { 599 $resp = "pesapal_notification_type=$pesapal_notification" . 600 "&pesapal_transaction_tracking_id=$pesapal_transaction_tracking_id" . 601 "&pesapal_merchant_reference=$pesapal_merchant_reference"; 602 603 ob_start(); 604 echo $resp; 605 ob_flush(); 606 607 } 608 exit(); 537 609 } 538 610 539 611 /** 540 612 * Cron to run and check order status 541 * 613 * 542 614 * @since 1.0.0 543 615 */ 544 function check_order_status() {616 public function check_order_status() { 545 617 if ( $this->use_cron ) { 546 $this->pesapal_do_log( 'Beginning cron' );547 $fetch = array( 'pending','on-hold','processing' );548 $args = array(549 'status' => $fetch,550 'date_created' => '>' . ( time() - DAY_IN_SECONDS ),551 'return' => 'ids',618 self::log( 'Beginning cron' ); 619 $fetch = array( 'pending', 'on-hold', 'processing' ); 620 $args = array( 621 'status' => $fetch, 622 'date_created' => '>' . ( time() - DAY_IN_SECONDS ), 623 'return' => 'ids', 552 624 ); 553 625 554 626 $orders = wc_get_orders( $args ); 555 foreach ( $orders as $order ) {627 foreach ( $orders as $order ) { 556 628 if ( is_int( $order ) ) { 557 629 $order = wc_get_order( $order ); 558 630 } 559 631 $method = $order->get_payment_method(); 560 if ( $method == $this->id ) {561 $pesapal MerchantReference = $this->order_prefix . '-'. $order->get_id();562 $status = $this->checkTransactionStatus( $pesapalMerchantReference );563 if ( $status =="COMPLETED") {632 if ( $method == $this->id ) { 633 $pesapal_merchant_reference = $this->order_prefix . '-' . $order->get_id(); 634 $status = $this->checkTransactionStatus( $pesapal_merchant_reference ); 635 if ( $status == 'COMPLETED' ) { 564 636 $order->add_order_note( __( 'Payment completed via CRON', 'woocommerce' ) ); 565 637 $order->payment_complete(); 566 } else if ( $status=="FAILED" || $status=="REVERSED") {638 } elseif ( in_array( $status, array( 'FAILED', 'REVERSED' ) ) ) { 567 639 $order->update_status( 'failed', sprintf( __( 'Payment %s via CRON.', 'woocommerce' ), strtolower( $status ) ) ); 568 640 } 569 641 } 570 642 } 571 $this->pesapal_do_log( 'Completed cron' );572 } 573 } 574 }575 }643 self::log( 'Completed cron' ); 644 } 645 } 646 } 647 } 576 648 } 577 ?> -
thebunch-ke-pesapal-woocommerce/trunk/readme.txt
r2725075 r2790425 6 6 Tested up to: 5.9.3 7 7 Requires PHP: 5.6 8 Stable tag: 1.4. 78 Stable tag: 1.4.8 9 9 License: GPLv3 or later 10 10 License URI: http://www.gnu.org/licenses/gpl-3.0.html … … 32 32 33 33 == Changelog == 34 35 = 1.4.8 = 36 * Fix: Remove currencies that are already supported in WooCommerce. 37 * Fix: Code improvements. 34 38 35 39 = 1.4.7 = -
thebunch-ke-pesapal-woocommerce/trunk/thebunchke_pesapal_woocommerce.php
r2725075 r2790425 1 1 <?php 2 /* 3 Plugin Name: TheBunch KE Pesapal Woocommerce 4 Description: Add PesaPal payment gateway to your Woocommerce plugin 5 Version: 1.4.7 6 Author: rixeo 7 Author URI: http://thebunch.co.ke/ 8 Plugin URI: http://dev.thebunch.co.ke/ 9 */ 2 /** 3 * Plugin Name: TheBunch KE Pesapal Woocommerce 4 * Plugin URI: https://www.hubloy.com 5 * Description: Add PesaPal payment gateway to your Woocommerce plugin 6 * Version: 1.4.8 7 * Author: rixeo 8 * Author URI: https://www.hubloy.com 9 * License: GPLv2 10 * License URI: https://www.gnu.org/licenses/gpl-2.0.html 11 * 12 * @package TheBunchKEPesaPal 13 */ 10 14 11 if ( ! defined( 'ABSPATH' ) ) 12 exit; // Exit if accessed directly 15 if ( ! defined( 'ABSPATH' ) ) { 16 exit; // Exit if accessed directly. 17 } 13 18 14 //Define constants 15 define( 'THEBUNCHKE_PESAPAL_WOO_PLUGIN_DIR', dirname(__FILE__).'/' ); 16 define( 'THEBUNCHKE_PESAPAL_WOO_PLUGIN_URL', plugin_dir_url(__FILE__) ); 17 18 19 // Define constants. 20 define( 'THEBUNCHKE_PESAPAL_WOO_PLUGIN_DIR', dirname( __FILE__ ) . '/' ); 21 define( 'THEBUNCHKE_PESAPAL_WOO_PLUGIN_URL', plugin_dir_url( __FILE__ ) ); 22 23 /** 24 * Functions called to initiate the plugin. 25 */ 19 26 function thebunchke_pesapal_woo_init() { 20 21 //Load required files22 27 23 require_once( THEBUNCHKE_PESAPAL_WOO_PLUGIN_DIR . 'lib/OAuth.php' ); 24 require_once( THEBUNCHKE_PESAPAL_WOO_PLUGIN_DIR . 'lib/gateway.php' ); 25 26 add_filter('woocommerce_payment_gateways', 'add_pesapal_gateway_class' ); 28 // Load required files. 29 30 require_once THEBUNCHKE_PESAPAL_WOO_PLUGIN_DIR . 'lib/OAuth.php'; 31 require_once THEBUNCHKE_PESAPAL_WOO_PLUGIN_DIR . 'lib/gateway.php'; 32 33 add_filter( 'woocommerce_payment_gateways', 'add_pesapal_gateway_class' ); 34 /** 35 * Add the gateway class. 36 * 37 * @param array $methods The current methods. 38 * 39 * @return array 40 */ 27 41 function add_pesapal_gateway_class( $methods ) { 28 $methods[] = 'WC_TheBunchKE_PesaPal_Pay_Gateway'; 42 $methods[] = 'WC_TheBunchKE_PesaPal_Pay_Gateway'; 29 43 return $methods; 30 44 } 31 32 /**33 * Add Currencies34 *35 */36 add_filter( 'woocommerce_currencies', 'thebunchke_pesapal_woo_add_shilling' );37 function thebunchke_pesapal_woo_add_shilling( $currencies ) {38 if( !isset( $currencies['KES'] ) ||!isset( $currencies['KSH'] ) ) {39 $currencies['KES'] = __( 'Kenyan Shilling', 'woocommerce' );40 $currencies['TZA'] = __( 'Tanzanian Shilling', 'woocommerce' );41 $currencies['UGX'] = __( 'Ugandan Shilling', 'woocommerce' );42 return $currencies;43 }44 }45 45 46 /** 47 * Add Currency Symbols 48 * 49 */ 50 add_filter('woocommerce_currency_symbol', 'thebunchke_pesapal_woo_add_shilling_symbol', 10, 2); 51 function thebunchke_pesapal_woo_add_shilling_symbol( $currency_symbol, $currency ) { 52 switch( $currency ) { 53 case 'KES': 54 $currency_symbol = 'KShs'; 55 break; 56 case 'TZA': 57 $currency_symbol = 'TZs'; 58 break; 59 case 'UGX': 60 $currency_symbol = 'UShs'; 61 break; 62 } 63 return $currency_symbol; 64 } 46 add_action( 'init', 'thebunchke_pesapal_woo_check_cron_status' ); 65 47 } 66 48 67 // Initialize the plugin49 // Initialize the plugin. 68 50 add_action( 'plugins_loaded', 'thebunchke_pesapal_woo_init' ); 69 51 70 52 53 54 add_filter( 'cron_schedules', 'thebunchke_pesapal_woo_cron_recurrence_interval' ); 71 55 /** 72 * Set cron schedules 56 * Add custom cron schedule. 57 * 58 * @param array $schedules The current schedules. 59 * 60 * @return array 73 61 */ 74 add_filter( 'cron_schedules', 'thebunchke_pesapal_woo_cron_recurrence_interval' );75 76 62 function thebunchke_pesapal_woo_cron_recurrence_interval( $schedules ) { 77 63 $schedules['every_five_minutes'] = array( … … 83 69 84 70 85 /** 86 * Activation hook 71 72 /** 73 * Check status of cron and set it. 74 * 75 * @return void 87 76 */ 88 register_activation_hook( __FILE__, 'thebunchke_pesapal_woo_activation_hook' ); 89 function thebunchke_pesapal_woo_activation_hook() { 77 function thebunchke_pesapal_woo_check_cron_status() { 90 78 if ( ! wp_next_scheduled( 'thebunchke_pesapal_woo_check_order_status' ) ) { 91 79 wp_schedule_event( time(), 'every_five_minutes', 'thebunchke_pesapal_woo_check_order_status' ); … … 93 81 } 94 82 83 84 add_action( 'thebunchke_pesapal_woo_check_order_status', 'thebunchke_pesapal_woo_check_order_status_function' ); 95 85 /** 96 * Check the order status 86 * Check the order status. 87 * 88 * @return void 97 89 */ 98 add_action( 'thebunchke_pesapal_woo_check_order_status', 'thebunchke_pesapal_woo_check_order_status_function' );99 90 function thebunchke_pesapal_woo_check_order_status_function() { 100 91 if ( class_exists( 'WC_TheBunchKE_PesaPal_Pay_Gateway' ) ) { … … 106 97 107 98 add_action( 'rest_api_init', 'thebunchke_pesapal_woo_rest_api' ); 99 /** 100 * Register rest route. 101 * 102 * @param object $wp_rest_server The rest server. 103 * 104 * @return void 105 */ 108 106 function thebunchke_pesapal_woo_rest_api( $wp_rest_server ) { 109 register_rest_route( 'thebunchke-pespal/v1', 'ipn-listener', array( 110 'methods' => 'GET', 111 'callback' => 'thebunchke_pesapal_woo_check_ipn_function', 112 ) ); 107 register_rest_route( 108 'thebunchke-pespal/v1', 109 'ipn-listener', 110 array( 111 'methods' => 'GET', 112 'callback' => 'thebunchke_pesapal_woo_check_ipn_function', 113 ) 114 ); 113 115 } 114 116 115 117 /** 116 * IPN 118 * IPN check function. 117 119 */ 118 120 function thebunchke_pesapal_woo_check_ipn_function() { 119 if ( class_exists( 'WC_TheBunchKE_PesaPal_Pay_Gateway' ) ) {120 $newInstance = new WC_TheBunchKE_PesaPal_Pay_Gateway();121 $ newInstance->ipn_response();122 } else {123 return "invalid";124 } 121 if ( class_exists( 'WC_TheBunchKE_PesaPal_Pay_Gateway' ) ) { 122 $wc_thebunch_pesapal_instance = new WC_TheBunchKE_PesaPal_Pay_Gateway(); 123 $wc_thebunch_pesapal_instance->ipn_response(); 124 } else { 125 return 'invalid'; 126 } 125 127 } 126 ?>
Note: See TracChangeset
for help on using the changeset viewer.