Created
November 6, 2019 10:53
-
-
Save wpmudev-sls/10c04c432b278ad02c37f22cff3bec78 to your computer and use it in GitHub Desktop.
[Membership] - Deactivated Subscriptions
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
/** | |
* Plugin Name: [Membership] - Deactivated Subscriptions | |
* Plugin URI: https://premium.wpmudev.org/ | |
* Description: Provides an admin page to list and manage Deactivated Subscriptions | |
* Author: Panos Lyrakis @ WPMUDEV | |
* Author URI: https://premium.wpmudev.org/ | |
* License: GPLv2 or later | |
*/ | |
if ( ! defined( 'ABSPATH' ) ) { | |
exit; | |
} | |
if ( ! class_exists( 'WPMUDEV_MS_Manage_Subscriptions' ) ) { | |
class WPMUDEV_MS_Manage_Subscriptions { | |
private static $_instance = null; | |
public static function get_instance() { | |
if( is_null( self::$_instance ) ){ | |
self::$_instance = new WPMUDEV_MS_Manage_Subscriptions(); | |
} | |
return self::$_instance; | |
} | |
private function __construct() { | |
add_action( 'admin_menu', array( $this, 'admin_menu' ), 999 ); | |
add_action( 'wp_ajax_wpmudev_ms_fix_subscription', array( $this, 'fix_subscription' ) ); | |
} | |
public function fix_subscription() { | |
$subscription_id = filter_input( INPUT_POST, 'subscription_id', FILTER_VALIDATE_INT ); | |
$issue_type = filter_input( INPUT_POST, 'issue_type', FILTER_DEFAULT ); | |
$subscription = MS_Factory::load( 'MS_Model_Relationship', $subscription_id ); | |
$calculated_expire_date = $this->get_subscription_calculated_expire_date( $subscription ); | |
if ( strtotime( $calculated_expire_date ) >= strtotime( MS_Helper_Period::current_date() ) ) { | |
update_post_meta( $subscription_id, 'expire_date', $calculated_expire_date ); | |
// Maybe update the last invoice date too? | |
$invoice = $subscription->get_current_invoice(); | |
if ( $invoice->is_paid() ) { | |
update_post_meta( $invoice->id, 'due_date', $calculated_expire_date ); | |
} | |
//Should be set to active | |
$subscription_suggested_status = MS_Model_Relationship::STATUS_ACTIVE; | |
if ( $subscription->status != $subscription_suggested_status ) { | |
$this->set_status( $subscription, MS_Model_Relationship::STATUS_ACTIVE ); | |
} | |
$return = array( | |
'success' => true, | |
'subscription_id' => $subscription_id, | |
'bg_color' => 'rgba(85, 239, 196, 0.8)' | |
); | |
wp_send_json($return); | |
} | |
} | |
public function admin_menu() { | |
add_submenu_page( | |
'membership2', | |
'Manage Subscriptions', | |
'Manage Subscriptions', | |
'manage_options', | |
'ms-manage-subscriptions-list', | |
array( $this, 'admin_page_display' ) | |
); | |
} | |
protected function list_subscriptions( $echo = true ) { | |
$args = array( 'numberposts' => -1 ); | |
//$allowed_statuses = array( 'pending', 'waiting', 'active', 'trial', 'canceled', 'trial_expired', 'expired', 'deactivated' ); | |
$allowed_statuses = array( 'pending', 'expired', 'deactivated' ); | |
$args['meta_key'] = 'status'; | |
$args['meta_value'] = $allowed_statuses; | |
if ( isset( $_REQUEST['status'] ) && in_array( $_REQUEST['status'], $allowed_statuses ) ) { | |
//$args['meta_key'] = 'status'; | |
$args['meta_value'] = $_REQUEST['status']; | |
} | |
$subscriptions = $this->get_subscriptions( $args ); | |
$out = ""; | |
if ( empty( $subscriptions ) ) { | |
return "<h3>No subscriptions found in Database</h3>"; | |
} | |
$out .= "<table class=\"wp-list-table widefat fixed striped subscriptions\">"; | |
$out .= "<thead>"; | |
$out .= "<tr>"; | |
$out .= "<th>#</th>"; | |
$out .= "<th style=\"width:8%;\">ID</th>"; | |
$out .= "<th style=\"width:8%;\">User ID</th>"; | |
$out .= "<th style=\"width:8%;\">Membership ID</th>"; | |
$out .= "<th style=\"width:8%;\">Status</th>"; | |
$out .= "<th style=\"width:8%;\">Gateway</th>"; | |
$out .= "<th style=\"width:8%;\">Payment type</th>"; | |
$out .= "<th style=\"width:8%;\">Start</th>"; | |
$out .= "<th style=\"width:8%;\">Expire</th>"; | |
$out .= "<th style=\"width:8%;\">Calculated Expire</th>"; | |
$out .= "<th style=\"width:8%;\">Created</th>"; | |
$out .= "<th style=\"width:16%;\">To Fix</th>"; | |
$out .= "</tr>"; | |
$out .= "</thead>"; | |
$count = 1; | |
//$ids_array = array(); | |
foreach ( $subscriptions as $subscription ) { | |
//$ids_array[] = $subscription->ID; | |
$user = get_user_by( 'ID', $subscription->post_author ); | |
$subscriptions_link = admin_url( "admin.php?page=membership2-add-member&user_id={$user->ID}" ); | |
$tofix_msg = ''; | |
$tofix_type = ''; | |
$bg_color = "rgba(85, 239, 196, 0.8)"; | |
if ( isset( $subscription->to_fix) && isset( $subscription->to_fix[ 'type' ] ) && isset( $subscription->to_fix[ 'message' ] ) ) { | |
$tofix_msg = $subscription->to_fix[ 'message' ]; | |
$tofix_type = $subscription->to_fix[ 'type' ]; | |
$bg_color = "rgba(255, 118, 117, 0.6)"; | |
} | |
$out .= "<tr style=\"background-color: {$bg_color};\">"; | |
$out .= "<td class=\"subscription-count\">{$count}</td>"; | |
$out .= "<td class=\"subscription-id\">{$subscription->ID}</td>"; | |
$out .= "<td class=\"subscription-author\"><a href=\"{$subscriptions_link}\">{$subscription->post_author}<br / >{$user->user_login}</a></td>"; | |
$out .= "<td class=\"subscription-membership\">{$subscription->meta->membership_id}</td>"; | |
$out .= "<td class=\"subscription-status\">{$subscription->meta->status}</td>"; | |
$out .= "<td class=\"subscription-gateway\">{$subscription->meta->gateway_id}</td>"; | |
$out .= "<td class=\"subscription-payment_type\">{$subscription->meta->payment_type}</td>"; | |
$out .= "<td class=\"subscription-start\">{$subscription->meta->start_date}</td>"; | |
$out .= "<td class=\"subscription-expire\">{$subscription->meta->expire_date}</td>"; | |
$out .= "<td class=\"subscription-calculated-expire\">{$subscription->meta->calculated_expire_date}</td>"; | |
$out .= "<td class=\"subscription-date\">{$subscription->post_date}</td>"; | |
$out .= "<td class=\"subscription-to-fix\">{$tofix_msg}</td>"; | |
$out .= "</tr>"; | |
$count ++; | |
} | |
$out .= "</table>"; | |
if ( ! $echo ) { | |
return $out; | |
} | |
print( $out ); | |
} | |
public function get_subscriptions ( $args = array(), $meta_keys = array() ) { | |
$defaults = array( | |
//author | |
'numberposts' => -1, | |
//'category' => 0, | |
'orderby' => 'ID', | |
'order' => 'DESC', | |
'include' => array(), | |
'exclude' => array(), | |
'meta_key' => '', | |
'meta_value' => '', | |
'post_type' => 'ms_relationship', | |
'post_status' => 'any', | |
'suppress_filters' => true, | |
); | |
$args = wp_parse_args( $args, $defaults ); | |
$meta = array(); | |
$subscriptions = get_posts( $args ); | |
if ( ! empty( $subscriptions ) ) { | |
foreach ( $subscriptions as $s_key => $subscription ) { | |
$subscription = ( array ) $subscription; | |
if ( ! is_array( $meta_keys ) || empty( $meta_keys ) ) { | |
$_meta = get_post_meta( $subscription['ID'] ); | |
foreach( $_meta as $m_key => $m_array ) { | |
$meta[ $m_key ] = $m_array[0]; | |
} | |
} else { | |
foreach ( $meta_keys as $m_key => $meta_key ) { | |
$meta[$meta_key] = get_post_meta( $subscription['ID'], $meta_key, true ); | |
} | |
} | |
$ms_subscription = MS_Factory::load( 'MS_Model_Relationship', intval( $subscription[ 'ID' ] ) ); | |
$meta[ 'calculated_expire_date' ] = $this->get_subscription_calculated_expire_date( $ms_subscription ); | |
$subscription[ 'to_fix' ] = $this->subscription_errors( $ms_subscription, $meta ); | |
$subscription['meta'] = ( object ) $meta; | |
$subscriptions[ $s_key ] = ( object ) $subscription; | |
} | |
} | |
return $subscriptions; | |
} | |
public function subscription_errors( $subscription, $meta ) { | |
if ( is_array( $subscription ) ) { | |
$subscription = MS_Factory::load( 'MS_Model_Relationship', intval( $subscription[ 'ID' ] ) ); | |
} | |
if ( ! $subscription instanceof MS_Model_Relationship ) { | |
return false; | |
} | |
$response = array(); | |
$calculated_expire_date = isset( $meta[ 'calculated_expire_date' ] ) ? $meta[ 'calculated_expire_date' ] : $subscription->expire_date; | |
if ( strtotime( $calculated_expire_date ) >= strtotime( MS_Helper_Period::current_date() ) ) { | |
// Should be set to active | |
// TODO : Add a method to calculate suggested method per subscription | |
$subscription_suggested_status = MS_Model_Relationship::STATUS_ACTIVE; | |
if ( $subscription->status != $subscription_suggested_status ) { | |
$issue_code = 'status'; | |
$response[ 'type' ] = $issue_code; | |
$response[ 'message' ] = "Subscription status is set to <strong> | |
{$subscription->status}</strong> but it seems it should be <strong>{$subscription_suggested_status}</strong> instead<div><button class=\"button button-primary ms-fix-subscription\" data-issue-type=\"{$issue_code}\" data-subscription=\"{$subscription->id}\" id=\"ms-fix-subscription-{$subscription->id}\">Fix this</button></div>"; | |
} | |
} | |
return $response; | |
} | |
public function get_subscription_calculated_expire_date( $subscription ) { | |
if ( is_array( $subscription ) ) { | |
$subscription = MS_Factory::load( 'MS_Model_Relationship', intval( $subscription[ 'ID' ] ) ); | |
} | |
if ( ! $subscription instanceof MS_Model_Relationship ) { | |
return false; | |
} | |
if ( | |
empty( $subscription->expire_date ) || | |
( $subscription->is_trial_eligible() && strtotime( $subscription->trial_expire_date ) >= strtotime( MS_Helper_Period::current_date() ) ) | |
) | |
{ | |
return; | |
} | |
//$last_payment_date = $subscription->expire_date; | |
//if ( 'admin' != $subscription->gateway_id && 'free' != $subscription->gateway_id ) { | |
$payment = $this->get_subscription_last_payment( $subscription ); | |
$subscription_expiration_date = $subscription->expire_date; | |
if ( ! ! $payment && ! empty( $payment ) ) { | |
$last_payment_date = $payment->date; | |
$calculated_expire_date = $this->get_subscription_expiration_date( $subscription, $last_payment_date ); | |
if ( strtotime( $subscription->expire_date ) > strtotime( $calculated_expire_date ) ) { | |
$calculated_expire_date = $subscription->expire_date; | |
} | |
return $calculated_expire_date; | |
} | |
return false; | |
} | |
private function log( $message ) { | |
if ( ! defined( "WP_DEBUG_LOG" ) || ! WP_DEBUG_LOG ) { | |
return; | |
} | |
$time = date( 'd-M-Y H:i:s' ); | |
error_log( | |
"[ {$time} ] \n{$message}\n\n\n", | |
3, | |
WP_CONTENT_DIR . "/ms-subs-debug-" . date( 'd-m-Y' ) . ".log" | |
); | |
} | |
private function set_status( $subscription, $status ) { | |
update_post_meta( $subscription->id, 'status', $status ); | |
if ( MS_Model_Relationship::STATUS_EXPIRED == $status ) { | |
// Since this subscription is expired, lets check if we need to move membership: | |
$membership = $subscription->get_membership(); | |
if ( ! empty( $membership->on_end_membership_id ) ) { | |
$this->maybe_move_membership( $subscription, $membership ); | |
} | |
} | |
} | |
private function maybe_move_membership( $subscription, $membership ) { | |
// Do not continue if on_end_membership_id is empty. | |
if ( empty( $membership->on_end_membership_id ) ) { | |
return; | |
} | |
// Deactivate the current membership. | |
$subscription->deactivate_membership(); | |
// Move membership to configured membership. | |
$new_membership = MS_Factory::load( | |
'MS_Model_Membership', | |
$membership->on_end_membership_id | |
); | |
if ( $new_membership->is_valid() ) { | |
$member = MS_Factory::load( 'MS_Model_Member', $subscription->user_id ); | |
$new_subscription = $member->add_membership( | |
$membership->on_end_membership_id, | |
$subscription->gateway_id | |
); | |
MS_Model_Event::save_event( | |
MS_Model_Event::TYPE_MS_MOVED, | |
$new_subscription | |
); | |
/* | |
* If the new membership is paid we want that the user | |
* confirms the payment in his account. So we set it | |
* to "Pending" first. If its free we set it as active | |
*/ | |
if ( ! $new_membership->is_free() ) { | |
$new_subscription->status = MS_Model_Relationship::STATUS_PENDING; | |
} else { | |
$new_subscription->status = MS_Model_Relationship::STATUS_ACTIVE; | |
} | |
// Save new membership. | |
$new_subscription->save(); | |
} | |
} | |
public function get_subscription_last_payment( $subscription ) { | |
$transaction = $this->get_subscription_last_transaction( $subscription->id ); | |
if ( ! $transaction || empty( $transaction ) ) { | |
return false; | |
} | |
return $this->payment_from_transaction( $transaction ); | |
} | |
public function get_subscription_last_transaction( $subscription_id ) { | |
if ( is_object( $subscription_id ) ) { | |
if ( ! isset( $subscription_id->id ) ) { | |
return false; | |
} | |
$subscription_id = $subscription_id->id; | |
} | |
$transaction = array(); | |
$args = array( | |
'numberposts' => 1, | |
'offset' => 0, | |
'post_status' => 'any', //'private', // transaction logs have private status in posts table | |
'post_type' => 'ms_transaction_log', | |
'meta_query' => array( | |
array( | |
'key' => 'subscription_id', | |
'value' => $subscription_id, | |
'compare' => '=', | |
), | |
array( | |
'key' => 'success', | |
'value' => 'ok', | |
'compare' => '=' | |
) | |
) | |
); | |
$transactions = get_posts( $args ); | |
if ( ! empty( $transactions ) ) { | |
return $transactions[0]; | |
} | |
else { | |
return false; | |
} | |
} | |
// This returns the required fields of the transaction. | |
public function payment_from_transaction( $transaction ) { | |
$payment = array(); | |
if ( ! $transaction instanceof WP_Post || 'ms_transaction_log' != $transaction->post_type ) { | |
return $payment; | |
} | |
$payment = array( | |
'id' => $transaction->ID, | |
'date' => $transaction->post_date | |
); | |
/* | |
// Currently we don't need to use transaction meta | |
$meta = get_post_meta( $transaction->ID ); | |
foreach ( $meta as $meta_key => $meta_value ) { | |
if ( isset( $meta_value[0] ) && ! isset( $payment[ $meta_key ] ) ) { | |
$payment[ $meta_key ] = $meta_value[0]; | |
} | |
} | |
*/ | |
return (object) $payment; | |
} | |
public function get_subscription_expiration_date( $subscription, $last_payment_date ) { | |
$grace_period = apply_filters( | |
'ms_subscription_expiration_grace_period', | |
1, | |
$subscription | |
); | |
$period_duration = $this->get_subscription_duration( $subscription ); | |
//$this->log( '$period_duration: ' . print_r( $period_duration,true ) ); | |
$expiration_date = date( 'Y-m-d H:i:s', strtotime( $last_payment_date . "+{$period_duration->period_unit} {$period_duration->period_type}" ) ); | |
//$this->log( '$expiration_date: ' . $expiration_date ); | |
//return date( 'Y-m-d', strtotime( $expiration_date . "+{$grace_period} days" ) ); | |
// We must not add the grace period here. The grace period is added on top of the expiration date of the subscription | |
return date( 'Y-m-d', strtotime( $expiration_date ) ); | |
} | |
public function get_subscription_duration( $subscription ) { | |
if ( ! $subscription instanceof MS_Model_Relationship ) { | |
return false; | |
} | |
return (object) get_post_meta( $subscription->membership_id, 'period', true ); | |
return (object) MS_Factory::load( | |
'MS_Model_Membership', | |
$subscription->membership_id | |
)->pay_cycle_period; | |
} | |
public function admin_page_display() { | |
?> | |
<div class="ms-wrap wrap"> | |
<h2 class="ms-settings-title">Subscriptons list from DB</h2> | |
<div style="padding: 20px; background: #fff; color: #555; font-size: 16px;"> | |
<?php $this->list_subscriptions(); ?> | |
</div> | |
</div> | |
<script type="text/javascript"> | |
($=>{ | |
const ms_fix_subscription = { | |
run : function( subscription_id, issue_type, button ) { | |
var spinner = $( '<img/>', { | |
src: '/wp-admin/images/wpspin_light.gif', | |
'class': 'ms-sfix-spinner-image' | |
}).css( { 'width':'14px', 'margin-left':'5px' } ).appendTo( button ), | |
data = { | |
action: 'wpmudev_ms_fix_subscription', | |
security: '<?php echo wp_create_nonce( "wpmudev_ms_fix_subscription" ); ?>', | |
subscription_id: subscription_id, | |
issue_type: issue_type | |
}; | |
$.post( ajaxurl, data, function(response) { | |
$( '.ms-sfix-spinner-image' ).hide( 200, function(){ $(this).remove(); } ); | |
if( response.success ){ | |
let button = $( `#ms-fix-subscription-${response.subscription_id}` ), | |
row = button.closest( 'tr' ); | |
button.parent().html( 'Fixed!' ); | |
row.css( 'background-color', response.bg_color ) ; | |
} | |
$( '.ms-fix-subscription' ).prop('disabled', false); | |
}); | |
} | |
} | |
$( document ).ready(function(){ | |
$( '.ms-fix-subscription' ).on( 'click', function(){ | |
$( '.ms-fix-subscription' ).prop('disabled', true); | |
ms_fix_subscription.run( | |
$(this).data( 'subscription' ), | |
$(this).data( 'issue_type' ), | |
$(this) | |
); | |
} ); | |
}); | |
})(jQuery); | |
</script> | |
<?php | |
} | |
} | |
if ( ! function_exists( 'wpmudev_ms_manage_subscriptions' ) ) { | |
function wpmudev_ms_manage_subscriptions(){ | |
return WPMUDEV_MS_Manage_Subscriptions::get_instance(); | |
}; | |
add_action( 'plugins_loaded', 'wpmudev_ms_manage_subscriptions', 10 ); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment