Changeset 2553115
- Timestamp:
- 06/24/2021 04:48:25 AM (5 years ago)
- Location:
- mobipaid
- Files:
-
- 56 added
- 5 edited
-
tags/1.0.5 (added)
-
tags/1.0.5/assets (added)
-
tags/1.0.5/assets/img (added)
-
tags/1.0.5/assets/img/mp-logo.png (added)
-
tags/1.0.5/changelog.txt (added)
-
tags/1.0.5/includes (added)
-
tags/1.0.5/includes/class-mobipaid-api.php (added)
-
tags/1.0.5/includes/class-mobipaid.php (added)
-
tags/1.0.5/index.php (added)
-
tags/1.0.5/languages (added)
-
tags/1.0.5/languages/mobipaid-ar.mo (added)
-
tags/1.0.5/languages/mobipaid-ar.po (added)
-
tags/1.0.5/languages/mobipaid-da_DK.mo (added)
-
tags/1.0.5/languages/mobipaid-da_DK.po (added)
-
tags/1.0.5/languages/mobipaid-de_DE.mo (added)
-
tags/1.0.5/languages/mobipaid-de_DE.po (added)
-
tags/1.0.5/languages/mobipaid-en_US.mo (added)
-
tags/1.0.5/languages/mobipaid-en_US.po (added)
-
tags/1.0.5/languages/mobipaid-es_ES.mo (added)
-
tags/1.0.5/languages/mobipaid-es_ES.po (added)
-
tags/1.0.5/languages/mobipaid-fi.mo (added)
-
tags/1.0.5/languages/mobipaid-fi.po (added)
-
tags/1.0.5/languages/mobipaid-fr_FR.mo (added)
-
tags/1.0.5/languages/mobipaid-fr_FR.po (added)
-
tags/1.0.5/languages/mobipaid-id_ID.mo (added)
-
tags/1.0.5/languages/mobipaid-id_ID.po (added)
-
tags/1.0.5/languages/mobipaid-it_IT.mo (added)
-
tags/1.0.5/languages/mobipaid-it_IT.po (added)
-
tags/1.0.5/languages/mobipaid-ja.mo (added)
-
tags/1.0.5/languages/mobipaid-ja.po (added)
-
tags/1.0.5/languages/mobipaid-ko_KR.mo (added)
-
tags/1.0.5/languages/mobipaid-ko_KR.po (added)
-
tags/1.0.5/languages/mobipaid-nl_NL.mo (added)
-
tags/1.0.5/languages/mobipaid-nl_NL.po (added)
-
tags/1.0.5/languages/mobipaid-pl_PL.mo (added)
-
tags/1.0.5/languages/mobipaid-pl_PL.po (added)
-
tags/1.0.5/languages/mobipaid-pt_PT.mo (added)
-
tags/1.0.5/languages/mobipaid-pt_PT.po (added)
-
tags/1.0.5/languages/mobipaid-ru_RU.mo (added)
-
tags/1.0.5/languages/mobipaid-ru_RU.po (added)
-
tags/1.0.5/languages/mobipaid-sv_SE.mo (added)
-
tags/1.0.5/languages/mobipaid-sv_SE.po (added)
-
tags/1.0.5/languages/mobipaid-tr_TR.mo (added)
-
tags/1.0.5/languages/mobipaid-tr_TR.po (added)
-
tags/1.0.5/languages/mobipaid-zh_CN.mo (added)
-
tags/1.0.5/languages/mobipaid-zh_CN.po (added)
-
tags/1.0.5/mobipaid.php (added)
-
tags/1.0.5/readme.txt (added)
-
tags/1.0.5/templates (added)
-
tags/1.0.5/templates/admin (added)
-
tags/1.0.5/templates/admin/order (added)
-
tags/1.0.5/templates/admin/order/cancel-recurring.php (added)
-
trunk/changelog.txt (modified) (1 diff)
-
trunk/includes/class-mobipaid-api.php (modified) (2 diffs)
-
trunk/includes/class-mobipaid.php (modified) (2 diffs)
-
trunk/mobipaid.php (modified) (3 diffs)
-
trunk/readme.txt (modified) (2 diffs)
-
trunk/templates (added)
-
trunk/templates/admin (added)
-
trunk/templates/admin/order (added)
-
trunk/templates/admin/order/cancel-recurring.php (added)
Legend:
- Unmodified
- Added
- Removed
-
mobipaid/trunk/changelog.txt
r2448039 r2553115 16 16 = 1.0.3 - 2020-07-03 = 17 17 * add sku and unit price to payment page. 18 19 = 1.0.4 - 2020-12-30 = 20 * support compatibility wordpress 5.6 and woocommerce 4.8.0. 21 22 = 1.0.5 - 2021-06-24 = 23 * support compatibility wordpress 5.7.2 and woocommerce 5.4.1. 24 * support with woocommerce subscription plugin -
mobipaid/trunk/includes/class-mobipaid-api.php
r2448039 r2553115 6 6 */ 7 7 8 if ( ! defined( 'ABSPATH' )) {9 exit;8 if (!defined('ABSPATH')) { 9 exit; 10 10 } 11 11 … … 15 15 * @since 1.0.0 16 16 */ 17 class Mobipaid_API { 17 class Mobipaid_API 18 { 18 19 19 /**20 * API Access Key21 *22 * @var string23 */24 public static $access_key;20 /** 21 * API Access Key 22 * 23 * @var string 24 */ 25 public static $access_key; 25 26 26 /**27 * Is use test server or not28 *29 * @var bool30 */31 public static $is_test_mode = false;27 /** 28 * Is use test server or not 29 * 30 * @var bool 31 */ 32 public static $is_test_mode = false; 32 33 33 /**34 * API live url35 *36 * @var string37 */38 public static $api_live_url = 'https://live.mobipaid.io/v2';34 /** 35 * API live url 36 * 37 * @var string 38 */ 39 public static $api_live_url = 'https://live.mobipaid.io/v2'; 39 40 40 /**41 * API test url42 *43 * @var string44 */45 public static $api_test_url = 'https://test.mobipaid.io/v2';41 /** 42 * API test url 43 * 44 * @var string 45 */ 46 public static $api_test_url = 'https://test.mobipaid.io/v2'; 46 47 47 /** 48 * Get API url 49 * 50 * @return string 51 */ 52 public static function get_api_url() { 53 if ( self::$is_test_mode ) { 54 return self::$api_test_url; 55 } 56 return self::$api_live_url; 57 } 48 /** 49 * Get API url 50 * 51 * @return string 52 */ 53 public static function get_api_url() 54 { 55 if (self::$is_test_mode) { 56 return self::$api_test_url; 57 } 58 return self::$api_live_url; 59 } 58 60 59 /** 60 * Send request to the API 61 * 62 * @param string $url Url. 63 * @param array $body Body. 64 * @param string $method Method. 65 * 66 * @return array 67 */ 68 public static function send_request( $url, $body = '', $method = 'GET' ) { 69 $api_args['headers'] = array( 'Authorization' => 'Bearer ' . self::$access_key ); 70 if ( 'POST' === $method || 'PUT' === $method ) { 71 $api_args['headers']['Content-Type'] = 'Application/json'; 72 $body = wp_json_encode( $body ); 73 } 74 $api_args['method'] = strtoupper( $method ); 75 $api_args['body'] = $body; 76 $api_args['timeout'] = 70; 61 /** 62 * Send request to the API 63 * 64 * @param string $url Url. 65 * @param array $body Body. 66 * @param string $method Method. 67 * 68 * @return array 69 */ 70 public static function send_request($url, $body = '', $method = 'GET') 71 { 72 $api_args['headers'] = array('Authorization' => 'Bearer ' . self::$access_key); 73 if ('POST' === $method || 'PUT' === $method || 'DELETE' === $method) { 74 $api_args['headers']['Content-Type'] = 'Application/json'; 75 $body = wp_json_encode($body); 76 } 77 $api_args['method'] = strtoupper($method); 78 $api_args['body'] = $body; 79 $api_args['timeout'] = 70; 77 80 78 $results = wp_remote_request( $url, $api_args);79 if ( is_string( $results['body'] )) {80 $results['body'] = json_decode( $results['body'], true);81 }81 $results = wp_remote_request($url, $api_args); 82 if (is_string($results['body'])) { 83 $results['body'] = json_decode($results['body'], true); 84 } 82 85 83 return $results;84 }86 return $results; 87 } 85 88 86 /** 87 * Get pos link url with the API. 88 * 89 * @param array $body Body. 90 * 91 * @return array 92 */ 93 public static function generate_pos_link( $body ) { 94 $url = self::get_api_url() . '/pos/generate-link'; 95 return self::send_request( $url, $body, 'POST' ); 96 } 89 /** 90 * Get pos link url with the API. 91 * 92 * @param array $body Body. 93 * 94 * @return array 95 */ 96 public static function generate_pos_link($body) 97 { 98 $url = self::get_api_url() . '/pos/generate-link'; 99 return self::send_request($url, $body, 'POST'); 100 } 97 101 98 /** 99 * Get payment detail with the API. 100 * 101 * @param string $payment_id Payment ID. 102 * 103 * @return array 104 */ 105 public static function get_payment( $payment_id ) { 106 $url = self::get_api_url() . '/payments/' . $payment_id; 107 return self::send_request( $url ); 108 } 102 /** 103 * Get payment detail with the API. 104 * 105 * @param string $payment_id Payment ID. 106 * 107 * @return array 108 */ 109 public static function get_payment($payment_id) 110 { 111 $url = self::get_api_url() . '/payments/' . $payment_id; 112 return self::send_request($url); 113 } 109 114 110 /** 111 * Do refund with the API. 112 * 113 * @param string $payment_id Payment ID. 114 * @param array $body Body. 115 * 116 * @return array 117 */ 118 public static function do_refund( $payment_id, $body ) { 119 $url = self::get_api_url() . '/refunds/' . $payment_id; 120 return self::send_request( $url, $body, 'POST' ); 121 } 115 /** 116 * create payment request for subcribtion. 117 * 118 * @param string $payment_id Payment ID. 119 * 120 * @return array 121 */ 122 public static function create_payment_request($body) 123 { 124 $url = self::get_api_url() . '/payment-requests'; 125 return self::send_request($url, $body, 'POST'); 126 } 127 128 /** 129 * create payment request for subcribtion. 130 * 131 * @param string $payment_id Payment ID. 132 * 133 * @return array 134 */ 135 public static function cancel_subscription($payment_id) 136 { 137 $url = self::get_api_url() . '/payments/subscription/' . $payment_id; 138 return self::send_request($url,'','DELETE'); 139 } 140 141 /** 142 * Do refund with the API. 143 * 144 * @param string $payment_id Payment ID. 145 * @param array $body Body. 146 * 147 * @return array 148 */ 149 public static function do_refund($payment_id, $body) 150 { 151 $url = self::get_api_url() . '/refunds/' . $payment_id; 152 return self::send_request($url, $body, 'POST'); 153 } 122 154 123 155 } -
mobipaid/trunk/includes/class-mobipaid.php
r2448039 r2553115 6 6 */ 7 7 8 if ( ! defined( 'ABSPATH' )) {9 exit; // Exit if accessed directly.8 if (!defined('ABSPATH')) { 9 exit; // Exit if accessed directly. 10 10 } 11 11 12 require_once dirname( __FILE__) . '/class-mobipaid-api.php';12 require_once dirname(__FILE__) . '/class-mobipaid-api.php'; 13 13 14 14 /** … … 17 17 * @extends WC_Payment_Gateway 18 18 */ 19 class Mobipaid extends WC_Payment_Gateway { 20 /** 21 * Constructor 22 */ 23 public function __construct() { 24 $this->id = 'mobipaid'; 25 // title for backend. 26 $this->method_title = __( 'Mobipaid', 'mobipaid' ); 27 $this->method_description = __( 'Mobipaid redirects customers to Mobipaid to enter their payment information.', 'mobipaid' ); 28 // title for frontend. 29 $this->icon = WP_PLUGIN_URL . '/' . plugin_basename( dirname( dirname( __FILE__ ) ) ) . '/assets/img/mp-logo.png'; 30 $this->supports = array( 'refunds' ); 31 32 // setup backend configuration. 33 $this->init_form_fields(); 34 $this->init_settings(); 35 36 // save woocomerce settings checkout tab section mobipaid. 37 add_action( 'woocommerce_update_options_payment_gateways_' . $this->id, array( $this, 'process_admin_options' ) ); 38 // validate form fields when saved. 39 add_action( 'woocommerce_update_options_payment_gateways_' . $this->id, array( $this, 'validate_admin_options' ) ); 40 // use hook to receive response url. 41 add_action( 'woocommerce_before_thankyou', array( $this, 'response_page' ) ); 42 // use hook to do full refund. 43 add_action( 'woocommerce_order_edit_status', array( $this, 'process_full_refund' ), 10, 2 ); 44 // use hook to add notes when payment amount greater than order amount. 45 add_action( 'woocommerce_order_status_changed', array( $this, 'add_full_refund_notes' ), 10, 3 ); 46 47 $this->title = $this->get_option( 'title' ); 48 $this->description = $this->get_option( 'description' ); 49 $this->payment_type = 'DB'; 50 $this->access_key = $this->get_option( 'access_key' ); 51 $this->enable_logging = 'yes' === $this->get_option( 'enable_logging' ); 52 $this->is_test_mode = 'mp_live' !== substr( $this->access_key, 0, 7 ); 53 $this->init_api(); 54 } 55 56 /** 57 * Override function. 58 * Initialise settings form fields for mobipaid 59 * Add an array of fields to be displayed on the mobipaid settings screen. 60 */ 61 public function init_form_fields() { 62 $this->form_fields = array( 63 'enabled' => array( 64 'title' => __( 'Enable/Disable', 'mobipaid' ), 65 'label' => __( 'Enable Mobipaid', 'mobipaid' ), 66 'type' => 'checkbox', 67 'default' => 'no', 68 ), 69 'title' => array( 70 'title' => __( 'Title', 'mobipaid' ), 71 'type' => 'text', 72 'description' => __( 'This is the title which the user sees during checkout.', 'mobipaid' ), 73 'default' => __( 'Mobipaid', 'mobipaid' ), 74 'desc_tip' => true, 75 ), 76 'description' => array( 77 'title' => __( 'Description', 'mobipaid' ), 78 'type' => 'text', 79 'description' => __( 'This is the description which the user sees during checkout.', 'mobipaid' ), 80 'default' => 'Pay with Mobipaid', 81 'desc_tip' => true, 82 ), 83 'access_key' => array( 84 'title' => __( 'Access Key', 'mobipaid' ), 85 'type' => 'password', 86 'description' => __( '* This is the access key, received from Mobipaid developer portal. ( required )', 'mobipaid' ), 87 'default' => '', 88 ), 89 'enable_logging' => array( 90 'title' => __( 'Enable Logging', 'mobipaid' ), 91 'type' => 'checkbox', 92 'label' => __( 'Enable transaction logging for mobipaid.', 'mobipaid' ), 93 'default' => 'no', 94 ), 95 ); 96 } 97 98 /** 99 * Show error notice if access key is empty. 100 */ 101 public function validate_admin_options() { 102 $post_data = $this->get_post_data(); 103 $access_key = $this->get_field_value( 'access_key', $this->form_fields, $post_data ); 104 if ( empty( $access_key ) ) { 105 WC_Admin_Settings::add_error( __( 'Please enter an access key!', 'mobipaid' ) ); 106 } 107 } 108 109 /** 110 * Override function. 111 * Disable if access key is empty. 112 * 113 * @return bool 114 */ 115 public function is_available() { 116 $is_available = parent::is_available(); 117 if ( empty( $this->access_key ) ) { 118 $is_available = false; 119 } 120 121 return $is_available; 122 } 123 124 /** 125 * Get order property with compatibility check on order getter introduced 126 * in WC 3.0. 127 * 128 * @since 1.0.0 129 * 130 * @param WC_Order $order Order object. 131 * @param string $prop Property name. 132 * 133 * @return mixed Property value 134 */ 135 public static function get_order_prop( $order, $prop ) { 136 switch ( $prop ) { 137 case 'order_total': 138 $getter = array( $order, 'get_total' ); 139 break; 140 default: 141 $getter = array( $order, 'get_' . $prop ); 142 break; 143 } 144 145 return is_callable( $getter ) ? call_user_func( $getter ) : $order->{ $prop }; 146 } 147 148 /** 149 * Log system processes. 150 * 151 * @since 1.0.0 152 * 153 * @param string $message Log message. 154 * @param string $level Log level. 155 */ 156 public function log( $message, $level = 'info' ) { 157 if ( $this->enable_logging ) { 158 if ( empty( $this->logger ) ) { 159 $this->logger = new WC_Logger(); 160 } 161 $this->logger->add( 'mobipaid-' . $level, $message ); 162 } 163 } 164 165 /** 166 * Init the API class and set the access key. 167 */ 168 protected function init_api() { 169 Mobipaid_API::$access_key = $this->access_key; 170 Mobipaid_API::$is_test_mode = $this->is_test_mode; 171 } 172 173 /** 174 * Get payment url. 175 * 176 * @param int $order_id Order ID. 177 * @param string $transaction_id Transaction ID. 178 * 179 * @return string 180 * @throws \Exception Error. 181 */ 182 protected function get_payment_url( $order_id, $transaction_id ) { 183 $order = wc_get_order( $order_id ); 184 $currency = $order->get_currency(); 185 $amount = $this->get_order_prop( $order, 'order_total' ); 186 $token = $this->generate_token( $order_id, $currency ); 187 $return_url = $this->get_return_url( $order ); 188 189 $body = array( 190 'reference' => $transaction_id, 191 'payment_type' => $this->payment_type, 192 'currency' => $currency, 193 'amount' => (float) $amount, 194 'cart_items' => $this->get_cart_items( $order_id ), 195 'cancel_url' => wc_get_checkout_url(), 196 'return_url' => $return_url, 197 'response_url' => $return_url . '&mp_token=' . $token, 198 ); 199 $log_body = $body; 200 $log_body['response_url'] = $return_url . '&mp_token=*****'; 201 $this->log( 'get_payment_url - body: ' . wp_json_encode( $log_body ) ); 202 203 $results = Mobipaid_API::generate_pos_link( $body ); 204 $this->log( 'get_payment_url - results: ' . wp_json_encode( $results ) ); 205 206 if ( 200 === $results['response']['code'] && 'success' === $results['body']['result'] ) { 207 return $results['body']['long_url']; 208 } 209 210 if ( 422 === $results['response']['code'] && 'currency' === $results['body']['error_field'] ) { 211 throw new Exception( __( 'We are sorry, currency is not supported. Please contact us.', 'mobipaid' ), 1 ); 212 } 213 214 throw new Exception( __( 'Error while Processing Request: please try again.', 'mobipaid' ), 1 ); 215 } 216 217 /** 218 * Get cart items. 219 * 220 * @param int $order_id Order ID. 221 * @return array 222 */ 223 public function get_cart_items( $order_id ) { 224 $cart_items = array(); 225 $order = wc_get_order( $order_id ); 226 227 foreach ( $order->get_items() as $item_id => $item ) { 228 $product = $item->get_product(); 229 $sku = $product->get_sku(); 230 if ( !$sku ) { 231 $sku = '-'; 232 } 233 $item_total = isset( $item['recurring_line_total'] ) ? $item['recurring_line_total'] : $order->get_item_total( $item ); 234 235 $cart_items[] = array( 236 'sku' => $sku, 237 'name' => $item->get_name(), 238 'qty' => $item->get_quantity(), 239 'unit_price' => $item_total 240 ); 241 } 242 243 return $cart_items; 244 } 245 246 /** 247 * Override function. 248 * 249 * Send data to the API to get the payment url. 250 * Redirect user to the payment url. 251 * This should return the success and redirect in an array. e.g: 252 * 253 * return array( 254 * 'result' => 'success', 255 * 'redirect' => $this->get_return_url( $order ) 256 * ); 257 * 258 * @param int $order_id Order ID. 259 * @return array 260 */ 261 public function process_payment( $order_id ) { 262 $order = wc_get_order( $order_id ); 263 $transaction_id = 'wc-' . $order->get_order_number(); 264 $secret_key = wc_rand_hash(); 265 266 // * save transaction_id and secret_key first before call get_payment_url function. 267 update_post_meta( $order->get_id(), '_mobipaid_transaction_id', $transaction_id ); 268 update_post_meta( $order->get_id(), '_mobipaid_secret_key', $secret_key ); 269 270 $payment_url = $this->get_payment_url( $order_id, $transaction_id ); 271 272 return array( 273 'result' => 'success', 274 'redirect' => $payment_url, 275 ); 276 } 277 278 /** 279 * Process partial refund. 280 * 281 * If the gateway declares 'refunds' support, this will allow it to refund. 282 * a passed in amount. 283 * 284 * @param int $order_id Order ID. 285 * @param float $amount Refund amount. 286 * @param string $reason Refund reason. 287 * @return boolean True or false based on success, or a WP_Error object. 288 */ 289 public function process_refund( $order_id, $amount = null, $reason = '' ) { 290 $order = wc_get_order( $order_id ); 291 if ( $order && 'mobipaid' === $order->get_payment_method() ) { 292 $payment_id = get_post_meta( $order->get_id(), '_mobipaid_payment_id', true ); 293 $body = array( 294 'email' => $order->get_billing_email(), 295 'amount' => (float) $amount, 296 ); 297 $this->log( 'process_refund - request body ' . wp_json_encode( $body ) ); 298 $results = Mobipaid_API::do_refund( $payment_id, $body ); 299 $this->log( 'process_refund - results: ' . wp_json_encode( $results ) ); 300 301 if ( 200 === $results['response']['code'] && 'refund' === $results['body']['status'] ) { 302 $order->add_order_note( __( 'Mobipaid partial refund successfull.' ) ); 303 $this->log( 'process_refund: Success' ); 304 return true; 305 } 306 307 $this->log( 'process_refund: Failed' ); 308 return new WP_Error( $results['response']['code'], __( 'Refund Failed', 'mobipaid' ) . ': ' . $results['body']['message'] ); 309 } 310 } 311 312 /** 313 * Process full refund when order status change from processing / completed to refunded. 314 * 315 * @param int $order_id Order ID. 316 * @param string $status_to change status to. 317 */ 318 public function process_full_refund( $order_id, $status_to ) { 319 $order = wc_get_order( $order_id ); 320 if ( $order && 'mobipaid' === $order->get_payment_method() ) { 321 $status_from = $order->get_status(); 322 323 if ( ( 'processing' === $status_from || 'completed' === $status_from ) && 'refunded' === $status_to ) { 324 $amount = (float) $this->get_order_prop( $order, 'order_total' ); 325 $payment_id = get_post_meta( $order->get_id(), '_mobipaid_payment_id', true ); 326 $body = array( 327 'email' => $order->get_billing_email(), 328 'amount' => $amount, 329 ); 330 $this->log( 'process_full_refund - request body ' . wp_json_encode( $body ) ); 331 $results = Mobipaid_API::do_refund( $payment_id, $body ); 332 $this->log( 'process_full_refund - do_refund results: ' . wp_json_encode( $results ) ); 333 334 if ( 200 === $results['response']['code'] && 'refund' === $results['body']['status'] ) { 335 $this->restock_refunded_items( $order ); 336 $order->add_order_note( __( 'Mobipaid full refund successfull.' ) ); 337 $this->log( 'process_full_refund: Success' ); 338 } else { 339 $this->log( 'process_full_refund: Failed' ); 340 $redirect = get_admin_url() . 'post.php?post=' . $order_id . '&action=edit'; 341 WC_Admin_Meta_Boxes::add_error( __( 'Refund Failed', 'mobipaid' ) . ':' . $results['body']['message'] ); 342 wp_safe_redirect( $redirect ); 343 exit; 344 } 345 } 346 } 347 } 348 349 /** 350 * Add notes if payment amount greater than order amount when order status change from processing / completed to refunded. 351 * 352 * @param int $order_id Order ID. 353 * @param string $status_from change status from. 354 * @param string $status_to change status to. 355 */ 356 public function add_full_refund_notes( $order_id, $status_from, $status_to ) { 357 $order = wc_get_order( $order_id ); 358 if ( $order && 'mobipaid' === $order->get_payment_method() ) { 359 if ( ( 'processing' === $status_from || 'completed' === $status_from ) && 'refunded' === $status_to ) { 360 $order_amount = (float) $this->get_order_prop( $order, 'order_total' ); 361 $payment_id = get_post_meta( $order->get_id(), '_mobipaid_payment_id', true ); 362 $results = Mobipaid_API::get_payment( $payment_id ); 363 $this->log( 'add_full_refund_notes - get_payment results: ' . wp_json_encode( $results ) ); 364 if ( 200 === $results['response']['code'] ) { 365 $payment_amount = (float) $results['body']['payment']['amount']; 366 if ( $payment_amount > $order_amount ) { 367 $order->add_order_note( __( 'Mobipaid notes: You still have amount to be refunded, because Merchant use tax/tip when customer paid. Please contact the merchant to refund the tax/tip amount.' ) ); 368 } 369 } 370 } 371 } 372 } 373 374 /** 375 * Increase stock for refunded items. 376 * 377 * @param obj $order Order. 378 */ 379 public function restock_refunded_items( $order ) { 380 $refunded_line_items = array(); 381 $line_items = $order->get_items(); 382 383 foreach ( $line_items as $item_id => $item ) { 384 $refunded_line_items[ $item_id ]['qty'] = $item->get_quantity(); 385 } 386 wc_restock_refunded_items( $order, $refunded_line_items ); 387 } 388 389 /** 390 * Use this generated token to secure get payment status. 391 * Before call this function make sure _mobipaid_transaction_id and _mobipaid_secret_key already saved. 392 * 393 * @param int $order_id - Order Id. 394 * @param string $currency - Currency. 395 * 396 * @return string 397 */ 398 protected function generate_token( $order_id, $currency ) { 399 $transaction_id = get_post_meta( $order_id, '_mobipaid_transaction_id', true ); 400 $secret_key = get_post_meta( $order_id, '_mobipaid_secret_key', true ); 401 402 return md5( (string) $order_id . $currency . $transaction_id . $secret_key ); 403 } 404 405 /** 406 * Page to handle response from the gateway. 407 * Get payment status and update order status. 408 * 409 * @param int $order_id - Order Id. 410 */ 411 public function response_page( $order_id ) { 412 $token = get_query_var( 'mp_token' ); 413 414 if ( ! empty( $token ) ) { 415 $this->log( 'get response from the gateway reponse url' ); 416 $response = get_query_var( 'response' ); 417 $this->log( 'response_page - original response: ' . $response ); 418 $response = json_decode( wp_unslash( $response ), true ); 419 $this->log( 'response_page - formated response: ' . wp_json_encode( $response ) ); 420 421 $payment_status = ''; 422 $payment_id = ''; 423 $currency = ''; 424 425 if ( isset( $response['status'] ) ) { 426 $payment_status = $response['status']; 427 } elseif ( isset( $response['result'] ) ) { 428 $payment_status = $response['result']; 429 } 430 431 if ( isset( $response['payment_id'] ) ) { 432 $payment_id = $response['payment_id']; 433 } elseif ( isset( $response['response'] ) && isset( $response['response']['id'] ) ) { 434 $payment_id = $response['response']['id']; 435 } 436 437 if ( isset( $response['currency'] ) ) { 438 $currency = $response['currency']; 439 } elseif ( isset( $response['response'] ) && isset( $response['response']['currency'] ) ) { 440 $currency = $response['response']['currency']; 441 } 442 443 $generated_token = $this->generate_token( $order_id, $currency ); 444 $order = wc_get_order( $order_id ); 445 446 if ( $order && 'mobipaid' === $order->get_payment_method() ) { 447 if ( $token === $generated_token ) { 448 if ( 'ACK' === $payment_status ) { 449 $this->log( 'response_page: update order status to processing' ); 450 $order_status = 'processing'; 451 $order_notes = 'Mobipaid payment successfull:'; 452 update_post_meta( $order->get_id(), '_mobipaid_payment_id', $payment_id ); 453 update_post_meta( $order->get_id(), '_mobipaid_payment_result', 'succes' ); 454 $order->update_status( $order_status, $order_notes ); 455 } else { 456 $this->log( 'response_page: update order status to failed' ); 457 $order_status = 'failed'; 458 $order_notes = 'Mobipaid payment failed:'; 459 update_post_meta( $order->get_id(), '_mobipaid_payment_result', 'failed' ); 460 $order->update_status( $order_status, $order_notes ); 461 } 462 die( 'OK' ); 463 } else { 464 $this->log( 'response_page: FRAUD detected, token is not same with the generated token' ); 465 } 466 } 467 } else { 468 $this->log( 'response_page: go to thank you page' ); 469 } 470 } 19 class Mobipaid extends WC_Payment_Gateway 20 { 21 22 /** 23 * Plugin directory 24 * 25 * @var string 26 */ 27 public $plugin_directory; 28 29 /** 30 * Plugin api url 31 * 32 * @var string 33 */ 34 public $mobipaid_api_url; 35 36 /** 37 * Updated meta boxes 38 * 39 * @var boolean 40 */ 41 private static $updated_meta_boxes = false; 42 43 /** 44 45 * Constructor 46 */ 47 public function __construct() 48 { 49 $this->id = 'mobipaid'; 50 // title for backend. 51 $this->method_title = __('Mobipaid', 'mobipaid'); 52 $this->method_description = __('Mobipaid redirects customers to Mobipaid to enter their payment information.', 'mobipaid'); 53 // title for frontend. 54 $this->icon = WP_PLUGIN_URL . '/' . plugin_basename(dirname(dirname(__FILE__))) . '/assets/img/mp-logo.png'; 55 $this->supports = array( 56 'subscriptions', 57 'subscription_cancellation', 58 'refunds', 59 ); 60 $this->plugin_directory = plugin_dir_path(__FILE__); 61 62 // setup backend configuration. 63 $this->init_form_fields(); 64 $this->init_settings(); 65 66 // save woocomerce settings checkout tab section mobipaid. 67 add_action('woocommerce_update_options_payment_gateways_' . $this->id, array($this, 'process_admin_options')); 68 // validate form fields when saved. 69 add_action('woocommerce_update_options_payment_gateways_' . $this->id, array($this, 'validate_admin_options')); 70 71 // use hook to do full refund. 72 add_action('woocommerce_order_edit_status', array($this, 'process_full_refund'), 10, 2); 73 // use hook to add notes when payment amount greater than order amount. 74 add_action('woocommerce_order_status_changed', array($this, 'add_full_refund_notes'), 10, 3); 75 // use hook to add button for stop recurring 76 add_action('woocommerce_admin_order_data_after_order_details', array(&$this, 'stop_recurring_backend')); 77 add_action('woocommerce_view_order', array(&$this, 'stop_recurring_frontend')); 78 79 $this->title = $this->get_option('title'); 80 $this->description = $this->get_option('description'); 81 $this->payment_type = 'DB'; 82 $this->access_key = $this->get_option('access_key'); 83 $this->enable_logging = 'yes' === $this->get_option('enable_logging'); 84 $this->is_test_mode = 'mp_live' !== substr($this->access_key, 0, 7); 85 $this->init_api(); 86 } 87 88 /** 89 * Override function. 90 * Initialise settings form fields for mobipaid 91 * Add an array of fields to be displayed on the mobipaid settings screen. 92 */ 93 public function init_form_fields() 94 { 95 $this->form_fields = array( 96 'enabled' => array( 97 'title' => __('Enable/Disable', 'mobipaid'), 98 'label' => __('Enable Mobipaid', 'mobipaid'), 99 'type' => 'checkbox', 100 'default' => 'no', 101 ), 102 'title' => array( 103 'title' => __('Title', 'mobipaid'), 104 'type' => 'text', 105 'description' => __('This is the title which the user sees during checkout.', 'mobipaid'), 106 'default' => __('Mobipaid', 'mobipaid'), 107 'desc_tip' => true, 108 ), 109 'description' => array( 110 'title' => __('Description', 'mobipaid'), 111 'type' => 'text', 112 'description' => __('This is the description which the user sees during checkout.', 'mobipaid'), 113 'default' => 'Pay with Mobipaid', 114 'desc_tip' => true, 115 ), 116 'access_key' => array( 117 'title' => __('Access Key', 'mobipaid'), 118 'type' => 'password', 119 'description' => __('* This is the access key, received from Mobipaid developer portal. ( required )', 'mobipaid'), 120 'default' => '', 121 ), 122 'enable_logging' => array( 123 'title' => __('Enable Logging', 'mobipaid'), 124 'type' => 'checkbox', 125 'label' => __('Enable transaction logging for mobipaid.', 'mobipaid'), 126 'default' => 'no', 127 ), 128 ); 129 } 130 131 /** 132 * Show error notice if access key is empty. 133 */ 134 public function validate_admin_options() 135 { 136 $post_data = $this->get_post_data(); 137 $access_key = $this->get_field_value('access_key', $this->form_fields, $post_data); 138 if (empty($access_key)) { 139 WC_Admin_Settings::add_error(__('Please enter an access key!', 'mobipaid')); 140 } 141 } 142 143 /** 144 * Override function. 145 * Disable if access key is empty. 146 * 147 * @return bool 148 */ 149 public function is_available() 150 { 151 $is_available = parent::is_available(); 152 if (empty($this->access_key)) { 153 $is_available = false; 154 } 155 156 return $is_available; 157 } 158 159 /** 160 * Get order property with compatibility check on order getter introduced 161 * in WC 3.0. 162 * 163 * @since 1.0.0 164 * 165 * @param WC_Order $order Order object. 166 * @param string $prop Property name. 167 * 168 * @return mixed Property value 169 */ 170 public static function get_order_prop($order, $prop) 171 { 172 switch ($prop) { 173 case 'order_total': 174 $getter = array($order, 'get_total'); 175 break; 176 default: 177 $getter = array($order, 'get_' . $prop); 178 break; 179 } 180 181 return is_callable($getter) ? call_user_func($getter) : $order->{$prop}; 182 } 183 184 /** 185 * Log system processes. 186 * 187 * @since 1.0.0 188 * 189 * @param string $message Log message. 190 * @param string $level Log level. 191 */ 192 public function log($message, $level = 'info') 193 { 194 if ($this->enable_logging) { 195 if (empty($this->logger)) { 196 $this->logger = new WC_Logger(); 197 } 198 $this->logger->add('mobipaid-' . $level, $message); 199 } 200 } 201 202 /** 203 * Init the API class and set the access key. 204 */ 205 protected function init_api() 206 { 207 Mobipaid_API::$access_key = $this->access_key; 208 Mobipaid_API::$is_test_mode = $this->is_test_mode; 209 } 210 211 /** 212 * Get payment url. 213 * 214 * @param int $order_id Order ID. 215 * @param string $transaction_id Transaction ID. 216 * 217 * @return string 218 * @throws \Exception Error. 219 */ 220 protected function get_payment_url($order_id, $transaction_id) 221 { 222 $order = wc_get_order($order_id); 223 $currency = $order->get_currency(); 224 $amount = $this->get_order_prop($order, 'order_total'); 225 $token = $this->generate_token($order_id, $currency); 226 $response_url = $this->get_mobipaid_response_url($order_id); 227 $return_url = $this->get_return_url($order); 228 229 $body = array( 230 'payment_type' => $this->payment_type, 231 'currency' => $currency, 232 'cancel_url' => wc_get_checkout_url(), 233 'response_url' => $response_url . '&mp_token=' . $token, 234 ); 235 236 if ($this->is_subscription($order_id)) { 237 $this->log('this is subcription product'); 238 239 $merge_paramters = array_merge($body, $this->get_mobipaid_subscription_parameter($order)); 240 unset($body); 241 $body = array(); 242 $body = $merge_paramters; 243 $log_body = $body; 244 $log_body['response_url'] = $response_url . '&mp_token=*****'; 245 $body['redirect_url'] = $return_url; 246 $body['reference_number'] = $transaction_id; 247 $body['request_methods'] = array("WEB"); 248 249 $this->log('get_payment_url - body: ' . wp_json_encode($log_body)); 250 251 $results = Mobipaid_API::create_payment_request($body); 252 $this->log('get_payment_url - results: ' . wp_json_encode($results)); 253 254 } else { 255 $body['return_url'] = $return_url; 256 $body['cart_items'] = $this->get_cart_items($order_id); 257 $body['reference'] = $transaction_id; 258 $body['amount'] = (float) $amount; 259 $log_body = $body; 260 $log_body['response_url'] = $return_url . '&mp_token=*****'; 261 $this->log('get_payment_url - body: ' . wp_json_encode($log_body)); 262 263 $results = Mobipaid_API::generate_pos_link($body); 264 $this->log('get_payment_url - results: ' . wp_json_encode($results)); 265 } 266 267 if (200 === $results['response']['code'] && 'success' === $results['body']['result']) { 268 return $results['body']['long_url']; 269 } 270 271 if (422 === $results['response']['code'] && 'currency' === $results['body']['error_field']) { 272 throw new Exception(__('We are sorry, currency is not supported. Please contact us.', 'mobipaid'), 1); 273 } 274 275 throw new Exception(__('Error while Processing Request: please try again.', 'mobipaid'), 1); 276 } 277 278 protected function get_mobipaid_response_url($order_id) 279 { 280 global $wp; 281 282 return home_url() . "/wp-json/woocommerce_mobipaid_api/response_url?order_id=" . $order_id; 283 } 284 285 /** 286 * Get checkout parameters for order that contain subscription product 287 * 288 * @param string $property property of class WC_Orde. 289 * @return array 290 */ 291 protected function get_mobipaid_subscription_parameter($order) 292 { 293 294 $subscription_period = WC_Subscriptions_Order::get_subscription_period($order); 295 $checkout_parameters = array(); 296 $checkout_parameters['payment_frequency'] = WC_Subscriptions_Order::get_subscription_period($order); 297 298 $date_now = date('m/d/Y'); 299 300 if ($subscription_period == 'day') { 301 throw new Exception(__('We are sorry, Mobipaid subcription Payment only support interval weekly, monthly, and yearly.', 'mobipaid'), 1); 302 } 303 304 if ($subscription_period == 'week') { 305 $checkout_parameters['payment_frequency'] = 'WEEKLY'; 306 $checkout_parameters['payment_start_date'] = date('Y-m-d\TH:i:s.000\Z', strtotime($date_now . "+1 week")); 307 } elseif ($subscription_period == 'month') { 308 $checkout_parameters['payment_frequency'] = 'MONTHLY'; 309 $checkout_parameters['payment_start_date'] = date('Y-m-d\TH:i:s.000\Z', strtotime($date_now . "+1 month")); 310 } else { 311 $checkout_parameters['payment_frequency'] = 'YEARLY'; 312 $checkout_parameters['payment_start_date'] = date('Y-m-d\TH:i:s.000\Z', strtotime($date_now . "+1 year")); 313 } 314 315 $checkout_parameters['initial_payment_amount'] = (float) $this->get_order_prop($order, 'order_total'); 316 $unconvert_date = WC_Subscriptions_Manager::get_subscription_expiration_date(WC_Subscriptions_Manager::get_subscription_key($order->id), $order->customer_user); 317 318 if (0 !== $unconvert_date) { 319 if ($subscription_period == 'week') { 320 $checkout_parameters['payment_end_date'] = date('Y-m-d\TH:i:s.000\Z', strtotime($unconvert_date . "-1 week")); 321 } elseif ($subscription_period == 'month') { 322 $checkout_parameters['payment_end_date'] = date('Y-m-d\TH:i:s.000\Z', strtotime($unconvert_date . "-1 month")); 323 } else { 324 $checkout_parameters['payment_end_date'] = date('Y-m-d\TH:i:s.000\Z', strtotime($unconvert_date . "-1 year")); 325 } 326 } 327 328 $checkout_parameters['amount'] = (float) WC_Subscriptions_Order::get_recurring_total($order); 329 return $checkout_parameters; 330 } 331 332 /** 333 * Get cart items. 334 * 335 * @param int $order_id Order ID. 336 * @return array 337 */ 338 public function get_cart_items($order_id) 339 { 340 $cart_items = array(); 341 $order = wc_get_order($order_id); 342 343 foreach ($order->get_items() as $item_id => $item) { 344 $product = $item->get_product(); 345 $sku = $product->get_sku(); 346 if (!$sku) { 347 $sku = '-'; 348 } 349 $item_total = isset($item['recurring_line_total']) ? $item['recurring_line_total'] : $order->get_item_total($item); 350 351 $cart_items[] = array( 352 'sku' => $sku, 353 'name' => $item->get_name(), 354 'qty' => $item->get_quantity(), 355 'unit_price' => $item_total, 356 ); 357 } 358 359 return $cart_items; 360 } 361 362 /** 363 * Override function. 364 * 365 * Send data to the API to get the payment url. 366 * Redirect user to the payment url. 367 * This should return the success and redirect in an array. e.g: 368 * 369 * return array( 370 * 'result' => 'success', 371 * 'redirect' => $this->get_return_url( $order ) 372 * ); 373 * 374 * @param int $order_id Order ID. 375 * @return array 376 */ 377 public function process_payment($order_id) 378 { 379 $order = wc_get_order($order_id); 380 $transaction_id = 'wc-' . $order->get_order_number(); 381 $secret_key = wc_rand_hash(); 382 383 // * save transaction_id and secret_key first before call get_payment_url function. 384 update_post_meta($order->get_id(), '_mobipaid_transaction_id', $transaction_id); 385 update_post_meta($order->get_id(), '_mobipaid_secret_key', $secret_key); 386 387 $payment_url = $this->get_payment_url($order_id, $transaction_id); 388 389 return array( 390 'result' => 'success', 391 'redirect' => $payment_url, 392 ); 393 } 394 395 /** 396 * Process partial refund. 397 * 398 * If the gateway declares 'refunds' support, this will allow it to refund. 399 * a passed in amount. 400 * 401 * @param int $order_id Order ID. 402 * @param float $amount Refund amount. 403 * @param string $reason Refund reason. 404 * @return boolean True or false based on success, or a WP_Error object. 405 */ 406 public function process_refund($order_id, $amount = null, $reason = '') 407 { 408 $order = wc_get_order($order_id); 409 if ($order && 'mobipaid' === $order->get_payment_method()) { 410 $payment_id = get_post_meta($order->get_id(), '_mobipaid_payment_id', true); 411 $body = array( 412 'email' => $order->get_billing_email(), 413 'amount' => (float) $amount, 414 ); 415 $this->log('process_refund - request body ' . wp_json_encode($body)); 416 $results = Mobipaid_API::do_refund($payment_id, $body); 417 $this->log('process_refund - results: ' . wp_json_encode($results)); 418 419 if (200 === $results['response']['code'] && 'refund' === $results['body']['status']) { 420 $order->add_order_note(__('Mobipaid partial refund successfull.')); 421 $this->log('process_refund: Success'); 422 return true; 423 } 424 425 $this->log('process_refund: Failed'); 426 return new WP_Error($results['response']['code'], __('Refund Failed', 'mobipaid') . ': ' . $results['body']['message']); 427 } 428 } 429 430 /** 431 * Process full refund when order status change from processing / completed to refunded. 432 * 433 * @param int $order_id Order ID. 434 * @param string $status_to change status to. 435 */ 436 public function process_full_refund($order_id, $status_to) 437 { 438 $order = wc_get_order($order_id); 439 if ($order && 'mobipaid' === $order->get_payment_method()) { 440 $status_from = $order->get_status(); 441 442 if (('processing' === $status_from || 'completed' === $status_from) && 'refunded' === $status_to) { 443 $amount = (float) $this->get_order_prop($order, 'order_total'); 444 $payment_id = get_post_meta($order->get_id(), '_mobipaid_payment_id', true); 445 $body = array( 446 'email' => $order->get_billing_email(), 447 'amount' => $amount, 448 ); 449 $this->log('process_full_refund - request body ' . wp_json_encode($body)); 450 $results = Mobipaid_API::do_refund($payment_id, $body); 451 $this->log('process_full_refund - do_refund results: ' . wp_json_encode($results)); 452 453 if (200 === $results['response']['code'] && 'refund' === $results['body']['status']) { 454 $this->restock_refunded_items($order); 455 $order->add_order_note(__('Mobipaid full refund successfull.')); 456 $this->log('process_full_refund: Success'); 457 } else { 458 $this->log('process_full_refund: Failed'); 459 $redirect = get_admin_url() . 'post.php?post=' . $order_id . '&action=edit'; 460 WC_Admin_Meta_Boxes::add_error(__('Refund Failed', 'mobipaid') . ':' . $results['body']['message']); 461 wp_safe_redirect($redirect); 462 exit; 463 } 464 } 465 } 466 } 467 468 /** 469 * Add notes if payment amount greater than order amount when order status change from processing / completed to refunded. 470 * 471 * @param int $order_id Order ID. 472 * @param string $status_from change status from. 473 * @param string $status_to change status to. 474 */ 475 public function add_full_refund_notes($order_id, $status_from, $status_to) 476 { 477 $order = wc_get_order($order_id); 478 if ($order && 'mobipaid' === $order->get_payment_method()) { 479 if (('processing' === $status_from || 'completed' === $status_from) && 'refunded' === $status_to) { 480 $order_amount = (float) $this->get_order_prop($order, 'order_total'); 481 $payment_id = get_post_meta($order->get_id(), '_mobipaid_payment_id', true); 482 $results = Mobipaid_API::get_payment($payment_id); 483 $this->log('add_full_refund_notes - get_payment results: ' . wp_json_encode($results)); 484 if (200 === $results['response']['code']) { 485 $payment_amount = (float) $results['body']['payment']['amount']; 486 if ($payment_amount > $order_amount) { 487 $order->add_order_note(__('Mobipaid notes: You still have amount to be refunded, because Merchant use tax/tip when customer paid. Please contact the merchant to refund the tax/tip amount.')); 488 } 489 } 490 } 491 } 492 } 493 494 /** 495 * Increase stock for refunded items. 496 * 497 * @param obj $order Order. 498 */ 499 public function restock_refunded_items($order) 500 { 501 $refunded_line_items = array(); 502 $line_items = $order->get_items(); 503 504 foreach ($line_items as $item_id => $item) { 505 $refunded_line_items[$item_id]['qty'] = $item->get_quantity(); 506 } 507 wc_restock_refunded_items($order, $refunded_line_items); 508 } 509 510 /** 511 * Use this generated token to secure get payment status. 512 * Before call this function make sure _mobipaid_transaction_id and _mobipaid_secret_key already saved. 513 * 514 * @param int $order_id - Order Id. 515 * @param string $currency - Currency. 516 * 517 * @return string 518 */ 519 protected function generate_token($order_id, $currency) 520 { 521 $transaction_id = get_post_meta($order_id, '_mobipaid_transaction_id', true); 522 $secret_key = get_post_meta($order_id, '_mobipaid_secret_key', true); 523 524 return md5((string) $order_id . $currency . $transaction_id . $secret_key); 525 } 526 527 /** 528 * Page to handle response from the gateway. 529 * Get payment status and update order status. 530 * 531 * @param int $order_id - Order Id. 532 */ 533 public function response_page() 534 { 535 $token = $this->get_request_value('mp_token'); 536 $order_id = $this->get_request_value('order_id'); 537 538 if (!empty($token)) { 539 $this->log('get response from the gateway reponse url'); 540 $response = $this->get_request_value('response'); 541 $this->log('response_page - original response: ' . $response); 542 $response = json_decode($response, true); 543 $this->log('response_page - formated response: ' . wp_json_encode($response)); 544 545 $payment_status = ''; 546 $payment_id = ''; 547 $currency = ''; 548 549 if (isset($response['status'])) { 550 $payment_status = $response['status']; 551 } elseif (isset($response['result'])) { 552 $payment_status = $response['result']; 553 } 554 555 if (isset($response['payment_id'])) { 556 $payment_id = $response['payment_id']; 557 } elseif (isset($response['response']) && isset($response['response']['id'])) { 558 $payment_id = $response['response']['id']; 559 } 560 561 if (isset($response['currency'])) { 562 $currency = $response['currency']; 563 } elseif (isset($response['response']) && isset($response['response']['currency'])) { 564 $currency = $response['response']['currency']; 565 } 566 567 $generated_token = $this->generate_token($order_id, $currency); 568 $order = wc_get_order($order_id); 569 $order->set_transaction_id($payment_id); 570 571 if ($order && 'mobipaid' === $order->get_payment_method()) { 572 573 if (isset($response['transaction_type'])) { 574 if ($response['transaction_type'] == "scheduled" && 'ACK' === $payment_status && $token === $generated_token) { 575 foreach (wcs_get_subscriptions_for_order($order_id) as $subscriptions) { 576 $subscription = $subscriptions; 577 } 578 if ($subscription->has_status('active')) { 579 $this->process_subcription_renewal_order($response, $subscription, $order); 580 } 581 } 582 $this->log('failed create renewal order'); 583 die("failed create order"); 584 } 585 586 if ($token === $generated_token) { 587 if ('ACK' === $payment_status) { 588 $this->log('response_page: update order status to processing'); 589 $order_status = 'processing'; 590 $order_notes = 'Mobipaid payment successfull:'; 591 update_post_meta($order->get_id(), '_mobipaid_payment_id', $payment_id); 592 update_post_meta($order->get_id(), '_mobipaid_payment_result', 'succes'); 593 $order->update_status($order_status, $order_notes); 594 } else { 595 $this->log('response_page: update order status to failed'); 596 $order_status = 'failed'; 597 $order_notes = 'Mobipaid payment failed:'; 598 update_post_meta($order->get_id(), '_mobipaid_payment_result', 'failed'); 599 $order->update_status($order_status, $order_notes); 600 } 601 die('OK'); 602 } else { 603 $this->log('response_page: FRAUD detected, token is not same with the generated token'); 604 } 605 } 606 } else { 607 $this->log('response_page: go to thank you page'); 608 } 609 } 610 611 /** 612 * crete renewal order using response from status_url 613 * 614 * @param array $payment_response. 615 * @param string $subscription property of class WC_Subscription. 616 * @return array 617 */ 618 protected function process_subcription_renewal_order($payment_response, $subscription, $order) 619 { 620 $this->log('process renewal order'); 621 // // Generate a renewal order to record the failed payment 622 $transaction_order = wcs_create_renewal_order($subscription); 623 $available_gateways = WC()->payment_gateways->get_available_payment_gateways(); 624 $note = __($order->get_payment_method() . " payment approved (Recurring payment ID:" . $payment_response['payment_id']); 625 $transaction_order->add_order_note($note); 626 $transaction_order->set_payment_method($order->get_payment_method()); 627 $transaction_order->update_status(get_option('skrill_completed_status', 'processing'), 'order_note'); 628 $this->log('succces create renewal order'); 629 630 exit(); 631 } 632 633 /** 634 * Checks whether order is part of subscription. 635 * 636 * @since 1.2.0 637 * 638 * @param int $order_id Order ID 639 * 640 * @return bool Returns true if order is part of subscription 641 */ 642 public function is_subscription($order_id) 643 { 644 return (function_exists('wcs_order_contains_subscription') && (wcs_order_contains_subscription($order_id) || wcs_is_subscription($order_id) || wcs_order_contains_renewal($order_id))); 645 } 646 647 /** 648 * [BACKEND] cancel recurring for backend 649 * render update order button and process update order from gateway 650 * from hook "woocommerce_admin_order_data_after_order_details" 651 */ 652 public function stop_recurring_backend() 653 { 654 $post_type = $this->get_request_value('post_type'); 655 656 if (!self::$updated_meta_boxes && 'shop_order' !== $post_type) { 657 $order_id = $this->get_request_value('post'); 658 659 $this->wc_order = wc_get_order($order_id); 660 $order_status = $this->wc_order->get_status(); 661 if ('mobipaid' === $this->wc_order->get_payment_method() && $this->is_subscription($order_id) && $order_status === "processing") { 662 $is_show_warning_message = true; 663 $is_show_update_order = false; 664 $warning_message = 'subscription-cancelled'; 665 666 if ($order_status === "processing" && $this->wc_order->get_created_via() !== "subscription-cancelled") { 667 $is_show_update_order = true; 668 $is_show_warning_message = false; 669 $request_section = $this->get_request_value('section'); 670 if ($order_id && 'cancel-recurring' === $request_section) { 671 $this->log('Start start cancel recurring'); 672 $redirect = get_admin_url() . 'post.php?post=' . $this->wc_order->get_order_number() . '&action=edit'; 673 $this->process_cancel_recurring_order(); 674 if ($this->process_cancel_recurring_order()) { 675 wp_safe_redirect($redirect); 676 exit(); 677 678 } else { 679 $error_message = __('Subscription can not be Cancelled', 'mobipaid'); 680 $this->redirect_order_detail($error_message); 681 } 682 } 683 684 $cancel_reccuring_url = get_admin_url() . 'post.php?post=' . $order_id . '&action=edit§ion=cancel-recurring'; 685 686 $is_show_warning_message = false; 687 $is_show_update_order = true; 688 $warning_message = ''; 689 } 690 691 wc_get_template( 692 'cancel-recurring.php', 693 array( 694 'update_order_url' => $cancel_reccuring_url, 695 'is_show_warning_message' => $is_show_warning_message, 696 'warning_message' => $warning_message, 697 'is_show_update_order' => $is_show_update_order, 698 'is_frontend' => false, 699 'redirect_url' => null 700 ), 701 $this->plugin_directory . '../templates/admin/order/', 702 $this->plugin_directory . '../templates/admin/order/' 703 ); 704 } // End if(). 705 self::$updated_meta_boxes = true; 706 } // End if(). 707 } // End if(). 708 709 /** 710 * [BACKEND] cancel recurring for frontend 711 * render update order button and process update order from gateway 712 * from hook "woocommerce_admin_order_data_after_order_details" 713 */ 714 public function stop_recurring_frontend($order_id) 715 { 716 if (!self::$updated_meta_boxes) { 717 $this->wc_order = wc_get_order($order_id); 718 global $wp; 719 $is_show_warning_message = true; 720 $is_show_update_order = false; 721 $redirect_url = null; 722 $warning_message = 'subscription-cancelled'; 723 if ('mobipaid' === $this->wc_order->get_payment_method() && $this->is_subscription($order_id)) { 724 725 $order_status = $this->wc_order->get_status(); 726 727 if ($order_status === "processing" && $this->wc_order->get_created_via() !== "subscription-cancelled") { 728 $request_section = $this->get_request_value('section'); 729 if ($order_id && 'cancel-recurring' === $request_section) { 730 $this->log('Start cancel recurring'); 731 if ($this->process_cancel_recurring_order()) { 732 $key = 'section'; 733 $$redirect_url = preg_replace('~(\?|&)' . $key . '=[^&]*~', '$1', home_url($wp->request)); 734 } 735 } 736 737 $cancel_reccuring_url = home_url($wp->request) . '?section=cancel-recurring'; 738 739 $is_show_warning_message = false; 740 $is_show_update_order = true; 741 $warning_message = ''; 742 } 743 744 wc_get_template( 745 'cancel-recurring.php', 746 array( 747 'update_order_url' => $cancel_reccuring_url, 748 'is_show_warning_message' => $is_show_warning_message, 749 'warning_message' => $warning_message, 750 'is_show_update_order' => $is_show_update_order, 751 'is_frontend' => true, 752 'redirect_url' => $redirect_url 753 ), 754 $this->plugin_directory . '../templates/admin/order/', 755 $this->plugin_directory . '../templates/admin/order/' 756 ); 757 } // End if(). 758 self::$updated_meta_boxes = true; 759 } 760 } // End if(). 761 762 /** 763 * [BACKEND] Process cancel recurring Order 764 * 765 * @param array $transaction - transaction. 766 * @param string $order_status - order status. 767 */ 768 protected function process_cancel_recurring_order() 769 { 770 $results = Mobipaid_API::cancel_subscription($this->wc_order->get_transaction_id()); 771 772 $this->log('cancel subscription - formated response: ' . wp_json_encode($results)); 773 774 if (200 === $results['response']['code'] && 'subscription_ended' === $results['body']['status']) { 775 $this->wc_order->add_order_note(__('Mobipaid subscription Cancelled')); 776 $this->log('cancel subscription: Success'); 777 $this->wc_order->set_created_via('subscription-cancelled'); 778 $this->wc_order->save(); 779 WC_Subscriptions_Manager::expire_subscriptions_for_order($this->wc_order); 780 781 return true; 782 } 783 return false; 784 } 785 786 /** 787 * Get request value 788 * 789 * @param string $key - key. 790 * @param boolean|string $default - default. 791 * @return boolean|string 792 */ 793 public function get_request_value($key, $default = false) 794 { 795 if (isset($_POST['save']) && isset($_POST['_wpnonce']) && isset($_GET['page'])) { // input var okay. 796 if (!wp_verify_nonce(sanitize_text_field(wp_unslash($_POST['_wpnonce'])), 'woocommerce-settings')) { // input var okay. 797 return $default; 798 } 799 } 800 if (isset($_REQUEST[$key])) { // input var okay. 801 return sanitize_text_field(wp_unslash($_REQUEST[$key])); // input var okay. 802 } 803 return $default; 804 } 805 806 /** 807 * [BACKEND] Redirect Order Detail 808 * redirect to order detail and show error message if exist 809 * 810 * @param boolean|string $error_message - error message. 811 */ 812 protected function redirect_order_detail($error_message = false) 813 { 814 $redirect = get_admin_url() . 'post.php?post=' . $this->wc_order->get_order_number() . '&action=edit'; 815 if ($error_message) { 816 WC_Admin_Meta_Boxes::add_error($error_message); 817 } 818 wp_safe_redirect($redirect); 819 exit; 820 } 471 821 472 822 } -
mobipaid/trunk/mobipaid.php
r2448039 r2553115 4 4 * Plugin URI: https://github.com/MobipaidLLC/mobipaid-woocommerce 5 5 * Description: Receive payments using Mobipaid. 6 * Version: 1.0. 46 * Version: 1.0.5 7 7 * Requires at least: 5.0 8 8 * Tested up to: 5.6 … … 24 24 } 25 25 26 define( 'MOBIPAID_PLUGIN_VERSION', '1.0. 4' );26 define( 'MOBIPAID_PLUGIN_VERSION', '1.0.5' ); 27 27 28 28 register_activation_hook( __FILE__, 'mobipaid_activate_plugin' ); … … 108 108 } 109 109 add_filter( 'query_vars', 'mobipaid_add_query_vars_filter' ); 110 111 add_action('rest_api_init', 'addResponseHandlerApi'); 112 113 function addResponseHandlerApi() 114 { 115 // use hook to receive response url. 116 register_rest_route('woocommerce_mobipaid_api', 'response_url', [ 117 'methods' => 'POST', 118 'callback' => 'handleResponseUrl', 119 ]); 120 } 121 122 function handleResponseUrl() 123 { 124 require_once 'includes/class-mobipaid.php'; 125 $mobipaid = new Mobipaid(); 126 127 return $mobipaid->response_page(); 128 } -
mobipaid/trunk/readme.txt
r2448039 r2553115 30 30 * Accept payments via Mobipaid. 31 31 * Partial / Full refund. 32 * Subscription payments. 32 33 33 34 == Localization == … … 113 114 * add sku and unit price to payment page. 114 115 115 = 1.0.4 - 2020- 30-12=116 = 1.0.4 - 2020-12-30 = 116 117 * support compatibility wordpress 5.6 and woocommerce 4.8.0. 118 119 = 1.0.5 - 2021-06-24 = 120 * support compatibility wordpress 5.7.2 and woocommerce 5.4.1. 121 * support with woocommerce subscription plugin
Note: See TracChangeset
for help on using the changeset viewer.