Plugin Directory

Changeset 2553115


Ignore:
Timestamp:
06/24/2021 04:48:25 AM (5 years ago)
Author:
mobipaid
Message:
  • support compatibility wordpress 5.7.2 and woocommerce 5.4.1.
  • support with woocommerce subscription plugin
Location:
mobipaid
Files:
56 added
5 edited

Legend:

Unmodified
Added
Removed
  • mobipaid/trunk/changelog.txt

    r2448039 r2553115  
    1616= 1.0.3 - 2020-07-03 =
    1717* 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  
    66 */
    77
    8 if ( ! defined( 'ABSPATH' ) ) {
    9     exit;
     8if (!defined('ABSPATH')) {
     9 exit;
    1010}
    1111
     
    1515 * @since 1.0.0
    1616 */
    17 class Mobipaid_API {
     17class Mobipaid_API
     18{
    1819
    19     /**
    20     * API Access Key
    21     *
    22     * @var string
    23     */
    24     public static $access_key;
     20 /**
     21  * API Access Key
     22  *
     23  * @var string
     24  */
     25 public static $access_key;
    2526
    26     /**
    27     * Is use test server or not
    28     *
    29     * @var bool
    30     */
    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;
    3233
    33     /**
    34     * API live url
    35     *
    36     * @var string
    37     */
    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';
    3940
    40     /**
    41     * API test url
    42     *
    43     * @var string
    44     */
    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';
    4647
    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 }
    5860
    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;
    7780
    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  }
    8285
    83         return $results;
    84     }
     86  return $results;
     87 }
    8588
    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 }
    97101
    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 }
    109114
    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 }
    122154
    123155}
  • mobipaid/trunk/includes/class-mobipaid.php

    r2448039 r2553115  
    66 */
    77
    8 if ( ! defined( 'ABSPATH' ) ) {
    9     exit; // Exit if accessed directly.
     8if (!defined('ABSPATH')) {
     9 exit; // Exit if accessed directly.
    1010}
    1111
    12 require_once dirname( __FILE__ ) . '/class-mobipaid-api.php';
     12require_once dirname(__FILE__) . '/class-mobipaid-api.php';
    1313
    1414/**
     
    1717 * @extends WC_Payment_Gateway
    1818 */
    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     }
     19class 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&section=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 }
    471821
    472822}
  • mobipaid/trunk/mobipaid.php

    r2448039 r2553115  
    44 * Plugin URI:           https://github.com/MobipaidLLC/mobipaid-woocommerce
    55 * Description:          Receive payments using Mobipaid.
    6  * Version:              1.0.4
     6 * Version:              1.0.5
    77 * Requires at least:    5.0
    88 * Tested up to:         5.6
     
    2424}
    2525
    26 define( 'MOBIPAID_PLUGIN_VERSION', '1.0.4' );
     26define( 'MOBIPAID_PLUGIN_VERSION', '1.0.5' );
    2727
    2828register_activation_hook( __FILE__, 'mobipaid_activate_plugin' );
     
    108108}
    109109add_filter( 'query_vars', 'mobipaid_add_query_vars_filter' );
     110 
     111add_action('rest_api_init', 'addResponseHandlerApi');
     112
     113function 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
     122function 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  
    3030* Accept payments via Mobipaid.
    3131* Partial / Full refund.
     32* Subscription payments.
    3233 
    3334== Localization ==
     
    113114* add sku and unit price to payment page.
    114115
    115 = 1.0.4 - 2020-30-12 =
     116= 1.0.4 - 2020-12-30 =
    116117* 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.