function pmpro_upgrade_1_8_9_3_ajax()
{
    global $wpdb;
    $debug = false;
    $run = true;
    //some vars
    $all_levels = pmpro_getAllLevels(true, true);
    //keeping track of which user we're working on
    $last_user_id = get_option('pmpro_upgrade_1_8_9_3_last_user_id', 0);
    //get all active users during the period where things may have been broken
    $user_ids = $wpdb->get_col("SELECT user_id FROM {$wpdb->pmpro_memberships_users} WHERE status = 'active' AND modified > '2016-05-19' AND user_id > {$last_user_id} ORDER BY user_id LIMIT 10");
    //track progress
    $first_load = get_transient('pmpro_updates_first_load');
    if ($first_load) {
        $total_users = $wpdb->get_var("SELECT COUNT(user_id) FROM {$wpdb->pmpro_memberships_users} WHERE status = 'active' AND modified > '2016-05-19' ORDER BY user_id");
        update_option('pmpro_upgrade_1_8_9_3_total', $total_users, 'no');
        $progress = 0;
    } else {
        $total_users = get_option('pmpro_upgrade_1_8_9_3_total', 0);
        $progress = get_option('pmpro_upgrade_1_8_9_3_progress', 0);
    }
    update_option('pmpro_upgrade_1_8_9_3_progress', $progress + count($user_ids), 'no');
    global $pmpro_updates_progress;
    if ($total_users > 0) {
        $pmpro_updates_progress = "[" . $progress . "/" . $total_users . "]";
    } else {
        $pmpro_updates_progress = "";
    }
    if (empty($user_ids)) {
        //done with this update
        pmpro_removeUpdate('pmpro_upgrade_1_8_9_3_ajax');
        delete_option('pmpro_upgrade_1_8_9_3_last_user_id');
        delete_option('pmpro_upgrade_1_8_9_3_total');
        delete_option('pmpro_upgrade_1_8_9_3_progress');
    } else {
        foreach ($user_ids as $user_id) {
            $last_user_id = $user_id;
            //keeping track of the last user we processed
            $user = get_userdata($user_id);
            //user not found for some reason
            if (empty($user)) {
                if ($debug) {
                    echo "User #" . $user_id . " not found.\n";
                }
                continue;
            }
            //get level
            $user->membership_level = pmpro_getMembershipLevelForUser($user->ID);
            //has a start and end date already
            if (!empty($user->membership_level->enddate) && !empty($user->membership_level->startdate)) {
                if ($debug) {
                    echo "User #" . $user_id . ", " . $user->user_email . " already has a start and end date.\n";
                }
                continue;
            }
            //get order
            $last_order = new MemberOrder();
            $last_order->getLastMemberOrder();
            /*
            	Figure out if this user should have been given an end date.
            	The level my have an end date.
            	They might have used a discount code.
            	They might be using the set-expiration-dates code.
            	They might have custom code setting the end date.
            
            	Let's setup some vars as if we are at checkout.
            	Then pass recreate the level with the pmpro_checkout_level filter.
            	And use the end date there if there is one.
            */
            global $pmpro_level, $discount_code, $discount_code_id;
            //level
            $level_id = $user->membership_level->id;
            $_REQUEST['level'] = $level_id;
            //gateway
            if (!empty($last_order) && !empty($last_order->gateway)) {
                $_REQUEST['gateway'] = $last_order->gateway;
            } else {
                $_REQUEST['gateway'] = pmpro_getGateway();
            }
            //discount code
            $discount_code_id = $user->membership_level->code_id;
            $discount_code = $wpdb->get_var("SELECT code FROM {$wpdb->pmpro_discount_codes} WHERE id = '" . $discount_code_id . "' LIMIT 1");
            //get level
            if (!empty($discount_code_id)) {
                $sqlQuery = "SELECT l.id, cl.*, l.name, l.description, l.allow_signups FROM {$wpdb->pmpro_discount_codes_levels} cl LEFT JOIN {$wpdb->pmpro_membership_levels} l ON cl.level_id = l.id LEFT JOIN {$wpdb->pmpro_discount_codes} dc ON dc.id = cl.code_id WHERE dc.code = '" . $discount_code . "' AND cl.level_id = '" . (int) $level_id . "' LIMIT 1";
                $pmpro_level = $wpdb->get_row($sqlQuery);
                //if the discount code doesn't adjust the level, let's just get the straight level
                if (empty($pmpro_level)) {
                    $pmpro_level = $all_levels[$level_id];
                }
                //filter adjustments to the level
                $pmpro_level->code_id = $discount_code_id;
                $pmpro_level = apply_filters("pmpro_discount_code_level", $pmpro_level, $discount_code_id);
            }
            //no level yet, use default
            if (empty($pmpro_level)) {
                $pmpro_level = $all_levels[$level_id];
            }
            //no level for some reason
            if (empty($pmpro_level) && empty($pmpro_level->id)) {
                if ($debug) {
                    echo "No level found with ID #" . $level_id . " for user #" . $user_id . ", " . $user->user_email . ".\n";
                }
                continue;
            }
            //filter level
            $pmpro_level = apply_filters("pmpro_checkout_level", $pmpro_level);
            if ($debug) {
                echo "User #" . $user_id . ", " . $user->user_email . ". Fixing.\n";
            }
            //calculate and fix start date
            if (empty($user->membership_level->startdate)) {
                $startdate = $wpdb->get_var("SELECT modified FROM {$wpdb->pmpro_memberships_users} WHERE user_id = {$user_id} AND membership_id = {$level_id} AND status = 'active' LIMIT 1");
                //filter
                $filtered_startdate = apply_filters("pmpro_checkout_start_date", $startdate, $user_id, $pmpro_level);
                //only use filtered value if it's not 0
                if (!empty($filtered_startdate) && $filtered_startdate != '0000-00-00 00:00:00' && $filtered_startdate != "'0000-00-00 00:00:00'") {
                    $startdate = $filtered_startdate;
                }
                if ($debug) {
                    echo "- Adding startdate " . $startdate . ".\n";
                }
                if ($run) {
                    $sqlQuery = "UPDATE {$wpdb->pmpro_memberships_users} SET startdate = '" . esc_sql($startdate) . "' WHERE user_id = {$user_id} AND membership_id = {$level_id} AND status = 'active' LIMIT 1";
                    $wpdb->query($sqlQuery);
                }
            } else {
                $startdate = date_i18n("Y-m-d", $user->membership_level->startdate);
            }
            //calculate and fix the end date
            if (empty($user->membership_level->enddate)) {
                if (!empty($pmpro_level->expiration_number)) {
                    $enddate = date_i18n("Y-m-d", strtotime("+ " . $pmpro_level->expiration_number . " " . $pmpro_level->expiration_period, $last_order->timestamp));
                } else {
                    $enddate = "NULL";
                }
                $enddate = apply_filters("pmpro_checkout_end_date", $enddate, $user_id, $pmpro_level, $startdate);
                if (!empty($enddate) && $enddate != "NULL") {
                    if ($debug) {
                        echo "- Adding enddate " . $enddate . ".\n";
                    }
                    if ($run) {
                        $sqlQuery = "UPDATE {$wpdb->pmpro_memberships_users} SET enddate = '" . esc_sql($enddate) . "' WHERE user_id = {$user_id} AND membership_id = {$level_id} AND status = 'active' LIMIT 1";
                        $wpdb->query($sqlQuery);
                    }
                }
            }
            //clear vars for next pass
            $user_id = NULL;
            $level_id = NULL;
            $discount_code = NULL;
            $discount_code_id = NULL;
            $pmpro_level = NULL;
            $last_order = NULL;
            $startdate = NULL;
            $filtered_startdate = NULL;
            $enddate = NULL;
            echo "\n";
        }
        update_option('pmpro_upgrade_1_8_9_3_last_user_id', $last_user_id, 'no');
    }
}
function pmpro_upgrade_1_8_6_9_ajax()
{
    global $wpdb;
    //keeping track of which order we're working on
    $last_order_id = get_option('pmpro_upgrade_1_8_6_9_last_order_id', 0);
    //get orders
    $orders = $wpdb->get_results("SELECT id, user_id, membership_id, subscription_transaction_id FROM {$wpdb->pmpro_membership_orders} WHERE id > {$last_order_id} AND gateway = 'stripe' AND subscription_transaction_id LIKE 'cus_%' ORDER BY id LIMIT 100");
    if (empty($orders)) {
        //done with this update
        pmpro_removeUpdate('pmpro_upgrade_1_8_6_9_ajax');
        delete_option('pmpro_upgrade_1_8_6_9_last_order_id');
    } else {
        $subids = array();
        //cache of subids found
        foreach ($orders as $order) {
            $last_order_id = $order->id;
            //keeping track of the last order we processed
            if (!empty($subids[$order->subscription_transaction_id])) {
                $wpdb->query("UPDATE {$wpdb->pmpro_membership_orders} SET subscription_transaction_id = '" . esc_sql($subids[$order->subscription_transaction_id]) . "' WHERE id = '" . $order->id . "' LIMIT 1");
            } elseif (isset($subids[$order->subscription_transaction_id])) {
                //no sub id found, so let it go
            } else {
                //need to look for a sub id in the database
                $subid = $wpdb->get_var("SELECT subscription_transaction_id FROM {$wpdb->pmpro_membership_orders} WHERE membership_id = '" . $order->membership_id . "' AND user_id = '" . $order->user_id . "' AND subscription_transaction_id LIKE 'sub_%' LIMIT 1");
                $subids[$order->subscription_transaction_id] = $subid;
                if (!empty($subid)) {
                    $wpdb->query("UPDATE {$wpdb->pmpro_membership_orders} SET subscription_transaction_id = '" . esc_sql($subid) . "' WHERE id = '" . $order->id . "' LIMIT 1");
                } else {
                    //no sub id found, so let it go
                }
            }
        }
        update_option('pmpro_upgrade_1_8_6_9_last_order_id', $last_order_id);
    }
}
function pmpro_upgrade_1_8_8_ajax()
{
    global $wpdb;
    //keeping track of which order we're working on
    $last_order_id = get_option('pmpro_upgrade_1_8_8_last_order_id', 0);
    //Fixing old $0 Stripe orders.
    $orders = $wpdb->get_col("SELECT id FROM {$wpdb->pmpro_membership_orders} WHERE id > {$last_order_id} AND gateway = 'stripe' AND total = 0 ORDER BY id LIMIT 2");
    //track progress
    $first_load = get_transient('pmpro_updates_first_load');
    if ($first_load) {
        $total_orders = $wpdb->get_var("SELECT COUNT(id) FROM {$wpdb->pmpro_membership_orders} WHERE id > {$last_order_id} AND gateway = 'stripe' AND total = 0");
        update_option('pmpro_upgrade_1_8_8_total', $total_orders, 'no');
        $progress = 0;
    } else {
        $total_orders = get_option('pmpro_upgrade_1_8_8_total', 0);
        $progress = get_option('pmpro_upgrade_1_8_8_progress', 0);
    }
    update_option('pmpro_upgrade_1_8_8_progress', $progress + count($orders), 'no');
    global $pmpro_updates_progress;
    if ($total_orders > 0) {
        $pmpro_updates_progress = "[" . $progress . "/" . $total_orders . "]";
    } else {
        $pmpro_updates_progress = "";
    }
    if (empty($orders)) {
        //done with this update
        pmpro_removeUpdate('pmpro_upgrade_1_8_8_ajax');
        delete_option('pmpro_upgrade_1_8_8_last_order_id');
        delete_option('pmpro_upgrade_1_8_8_total');
        delete_option('pmpro_upgrade_1_8_8_progress');
    } else {
        //need to keep working
        foreach ($orders as $order_id) {
            $last_order_id = $order_id;
            //keeping track of the last order we processed
            //get order
            $order = new MemberOrder($order_id);
            //get customer
            $order->Gateway->getCustomer($order);
            //get all invoices
            if (!empty($order->Gateway->customer)) {
                try {
                    $invoices = $order->Gateway->customer->invoices();
                } catch (Exception $e) {
                    //probably no invoices, stay quiet
                }
                //get our invoice
                if (!empty($invoices)) {
                    try {
                        $invoice = $invoices->retrieve($order->payment_transaction_id);
                    } catch (Exception $e) {
                        //probably no invoice, stay quiet
                    }
                    //get total
                    if (!empty($invoice)) {
                        if ($invoice->total > 0) {
                            //invoice we accidentally saved $0 for. update the real total.
                            $order->subtotal = !empty($invoice->subtotal) ? $invoice->subtotal / 100 : 0;
                            $order->tax = !empty($invoice->tax) ? $invoice->tax / 100 : null;
                            $order->total = !empty($invoice->total) ? $invoice->total / 100 : 0;
                            $order->saveOrder();
                        } else {
                            //we don't want to track $0 invoices. delete it.
                            $order->deleteMe();
                        }
                    }
                }
            }
        }
        update_option('pmpro_upgrade_1_8_8_last_order_id', $last_order_id, 'no');
    }
}
function pmpro_upgrade_1_8_9_1_ajax()
{
    global $wpdb;
    $debug = false;
    $run = true;
    //keeping track of which order we're working on
    $last_order_id = get_option('pmpro_upgrade_1_8_9_1_last_order_id', 0);
    //Fixing old $0 Stripe orders.
    $orders = $wpdb->get_col("SELECT id FROM {$wpdb->pmpro_membership_orders} WHERE id > {$last_order_id} AND gateway = 'stripe' AND user_id = 0 AND membership_id = 0 AND status <> 'error' ORDER BY id LIMIT 2");
    //track progress
    $first_load = get_transient('pmpro_updates_first_load');
    if ($first_load) {
        $total_orders = $wpdb->get_var("SELECT COUNT(id) FROM {$wpdb->pmpro_membership_orders} WHERE id > {$last_order_id} AND gateway = 'stripe' AND user_id = 0 AND membership_id = 0 AND status <> 'error' ");
        update_option('pmpro_upgrade_1_8_9_1_total', $total_orders, 'no');
        $progress = 0;
    } else {
        $total_orders = get_option('pmpro_upgrade_1_8_9_1_total', 0);
        $progress = get_option('pmpro_upgrade_1_8_9_1_progress', 0);
    }
    update_option('pmpro_upgrade_1_8_9_1_progress', $progress + count($orders), 'no');
    global $pmpro_updates_progress;
    if ($total_orders > 0) {
        $pmpro_updates_progress = "[" . $progress . "/" . $total_orders . "]";
    } else {
        $pmpro_updates_progress = "";
    }
    if (empty($orders)) {
        //done with this update
        pmpro_removeUpdate('pmpro_upgrade_1_8_9_1_ajax');
        delete_option('pmpro_upgrade_1_8_9_1_last_order_id');
        delete_option('pmpro_upgrade_1_8_9_1_total');
        delete_option('pmpro_upgrade_1_8_9_1_progress');
    } else {
        //need to keep working
        foreach ($orders as $order_id) {
            $last_order_id = $order_id;
            //keeping track of the last order we processed
            //get order
            $order = new MemberOrder($order_id);
            //if we have a user_id, this has the same sub id as an earlier order and was already fixed
            if (!empty($order->user_id)) {
                continue;
            }
            if ($debug) {
                echo "Order #" . $order->id . ", " . $order->code . " (" . $order->subscription_transaction_id . ")\n";
            }
            //find the subscription (via remote_get since this isn't the version of the library we use)
            $subscription = json_decode(wp_remote_retrieve_body(wp_remote_get('https://api.stripe.com/v1/subscriptions/' . $order->subscription_transaction_id, array('timeout' => 60, 'sslverify' => FALSE, 'httpversion' => '1.1', 'headers' => array('Authorization' => 'Bearer ' . pmpro_getOption("stripe_secretkey"))))));
            //no sub?
            if (empty($subscription) || empty($subscription->customer)) {
                if ($debug) {
                    echo "- Can't find the subscription.\n";
                }
                if ($run) {
                    $wpdb->query("UPDATE {$wpdb->pmpro_membership_orders} SET `status` = 'error', notes = CONCAT(notes, '\nRecurring order we couldn\\'t find the subscription.') WHERE id = {$order->id} LIMIT 1");
                }
                continue;
            }
            //get customer
            $customer = Stripe_Customer::retrieve($subscription->customer);
            //no customer? mark order as error and bail
            if (empty($customer)) {
                if ($debug) {
                    echo "- Can't find the customer.\n";
                }
                if ($run) {
                    $wpdb->query("UPDATE {$wpdb->pmpro_membership_orders} SET `status` = 'error', notes = CONCAT(notes, '\nRecurring order we couldn\\'t find the original customer for.') WHERE id = {$order->id} LIMIT 1");
                }
                continue;
            }
            //get past payments
            $invoices = $customer->invoices(array("limit" => 100));
            //find invoices for the same sub and see if we have a good order for it
            if (!empty($invoices)) {
                foreach ($invoices->data as $invoice) {
                    //echo "- " . $invoice->subscription . ", " . $invoice->charge . ", " . $invoice->id . "<br />";
                    if ($invoice->subscription == $order->subscription_transaction_id) {
                        //same sub. look for an order for this invoice or charge
                        $old_order = $wpdb->get_row("SELECT id, user_id, membership_id, subscription_transaction_id\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t FROM {$wpdb->pmpro_membership_orders} \n\t\t\t\t\t\t\t\t\t\t\t\t\t\t WHERE gateway = 'stripe' AND\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t     (payment_transaction_id = '" . $invoice->charge . "' OR payment_transaction_id = '" . $invoice->id . "') AND\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t user_id <> 0 AND\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t membership_id <> 0\n\t\t\t\t\t\t\t\t\t\t\t\t\t     LIMIT 1\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t ");
                        if (!empty($old_order)) {
                            //found it, let's fix data
                            if ($debug) {
                                echo "- Order #" . $old_order->id . ", " . $old_order->code . " found! FIXED\n";
                            }
                            if ($run) {
                                $sqlQuery = "UPDATE {$wpdb->pmpro_membership_orders} SET user_id = " . $old_order->user_id . ", membership_id = " . $old_order->membership_id . " WHERE user_id = 0 AND membership_id = 0 AND subscription_transaction_id = '" . $order->subscription_transaction_id . "' ";
                                $wpdb->query($sqlQuery);
                            }
                            continue 2;
                        }
                    }
                }
            }
            //didn't find an invoice for this sub
            if ($debug) {
                echo "- No invoice for this sub.\n";
            }
            if ($run) {
                $wpdb->query("UPDATE {$wpdb->pmpro_membership_orders} SET `status` = 'error', notes = CONCAT(notes, '\nRecurring order we couldn\\'t find the original customer for.') WHERE id = {$order->id} LIMIT 1");
            }
            continue;
        }
        update_option('pmpro_upgrade_1_8_9_1_last_order_id', $last_order_id, 'no');
    }
}