/**
  * Customise which actions are shown against a subscriptions order on the My Account page.
  *
  * @since 1.3
  */
 public static function filter_woocommerce_my_account_my_orders_actions($actions, $order)
 {
     if (WC_Subscriptions_Order::order_contains_subscription($order) || WC_Subscriptions_Renewal_Order::is_renewal($order)) {
         unset($actions['cancel']);
         if (is_numeric(get_post_meta($order->id, '_failed_order_replaced_by', true))) {
             unset($actions['pay']);
         }
         $original_order = WC_Subscriptions_Renewal_Order::get_parent_order($order);
         $order_items = WC_Subscriptions_Order::get_recurring_items($original_order);
         $first_order_item = reset($order_items);
         $product_id = WC_Subscriptions_Order::get_items_product_id($first_order_item);
         $subscription_key = WC_Subscriptions_Manager::get_subscription_key($original_order->id, $product_id);
         $subscription = WC_Subscriptions_Manager::get_users_subscription($original_order->customer_user, $subscription_key);
         if (empty($subscription) || !in_array($subscription['status'], array('on-hold', 'pending'))) {
             unset($actions['pay']);
         }
     }
     return $actions;
 }
 /**
  * In typical PayPal style, there are a couple of important limitations we need to work around:
  *
  * 1. PayPal does not support subscriptions with a $0 recurring total. As a result, we treat it
  * as a normal purchase and then handle the subscription renewals here.
  *
  * 2. PayPal make no guarantee about when a recurring payment will be charged. This creates issues for
  * suspending a subscription until the payment is processed. Specifically, if PayPal processed a payment
  * *before* it was due, we can't suspend the subscription when it is due because it will remain suspended
  * until the next payment. As a result, subscriptions for PayPal are not suspended. However, if there was
  * an issue with the subscription sign-up or payment that was not correctly reported to the store, then the
  * subscription would remain active. No renewal order would be generated, because no payments are completed,
  * so physical subscriptions would not be affected, however, subscriptions to digital goods would be affected.
  *
  * @since 1.4.3
  */
 public static function scheduled_subscription_payment($amount_to_charge, $order, $product_id)
 {
     if (0 == $amount_to_charge) {
         WC_Subscriptions_Manager::process_subscription_payments_on_order($order);
     } else {
         $hook_args = array('subscription_key' => WC_Subscriptions_Manager::get_subscription_key($order->id, $product_id));
         $one_day_from_now = gmdate('U') + 60 * 60 * 24;
         wp_schedule_single_event($one_day_from_now, 'paypal_check_subscription_payment', $hook_args);
     }
 }
示例#3
0
<?php

/**
 * Update Data to 7.5
 * Look for queue items for subscription emails without subscription keys in the meta
 */
if (!defined('ABSPATH')) {
    exit;
    // Exit if accessed directly
}
global $wpdb;
if (class_exists('WC_Subscriptions_Manager')) {
    $email_ids = fue_get_emails('subscription', '', array('fields' => 'ids'));
    if (count($email_ids)) {
        $item_ids = $wpdb->get_results("SELECT id FROM {$wpdb->prefix}followup_email_orders WHERE email_id IN (" . implode(',', $email_ids) . ")");
        foreach ($item_ids as $item_id) {
            $item = new FUE_Sending_Queue_Item($item_id->id);
            if (empty($item->meta['subs_key']) && WC_Subscriptions_Order::order_contains_subscription($item->order_id)) {
                $subs_key = WC_Subscriptions_Manager::get_subscription_key($item->order_id);
                $item->meta['subs_key'] = $subs_key;
                $item->save();
            }
        }
    }
}
    /**
     * A general purpose function for grabbing an array of subscriptions in form of 'subscription_key' => 'subscription_details'.
     *
     * The $args param is based on the parameter of the same name used by the core WordPress @see get_posts() function.
     * It can be used to choose which subscriptions should be returned by the function, how many subscriptions shoudl be returned
     * and in what order those subscriptions should be returned.
     *
     * @param array $args A set of name value pairs to determine the return value.
     *		'subscriptions_per_page' The number of subscriptions to return. Set to -1 for unlimited. Default 10.
     *		'offset' An optional number of subscription to displace or pass over. Default 0.
     *		'orderby' The field which the subscriptions should be orderd by. Can be 'start_date', 'expiry_date', 'end_date', 'status', 'name' or 'order_id'. Defaults to 'start_date'.
     *		'order' The order of the values returned. Can be 'ASC' or 'DESC'. Defaults to 'DESC'
     *		'customer_id' The user ID of a customer on the site.
     *		'product_id' The post ID of a WC_Product_Subscription, WC_Product_Variable_Subscription or WC_Product_Subscription_Variation object
     *		'subscription_status' Any valid subscription status. Can be 'any', 'active', 'cancelled', 'suspended', 'expired', 'pending' or 'trash'. Defaults to 'any'.
     * @return array Subscription details in 'subscription_key' => 'subscription_details' form.
     * @since 1.4
     */
    public static function get_subscriptions($args = array())
    {
        global $wpdb;
        $args = wp_parse_args($args, array('subscriptions_per_page' => 10, 'paged' => 1, 'offset' => 0, 'orderby' => '_subscription_start_date', 'order' => 'DESC', 'customer_id' => '', 'product_id' => '', 'variation_id' => '', 'order_id' => array(), 'subscription_status' => 'any'));
        // Map human friendly order_by values to internal keys
        switch ($args['orderby']) {
            case 'status':
                $args['orderby'] = '_subscription_status';
                break;
            case 'start_date':
                $args['orderby'] = '_subscription_start_date';
                break;
            case 'expiry_date':
                $args['orderby'] = '_subscription_expiry_date';
                break;
            case 'trial_expiry_date':
                $args['orderby'] = '_subscription_trial_expiry_date';
                break;
            case 'end_date':
                $args['orderby'] = '_subscription_end_date';
                break;
        }
        $subscriptions = array();
        // First see if we're paging, so the limit can be applied to subqueries
        if (-1 !== $args['subscriptions_per_page']) {
            $per_page = absint($args['subscriptions_per_page']);
            $page_start = '';
            if (0 == $args['paged']) {
                $args['paged'] = 1;
            }
            if ($args['paged']) {
                $page_start = absint($args['paged'] - 1) * $per_page . ', ';
            } elseif ($args['offset']) {
                $page_start = absint($args['offset']) . ', ';
            }
            $limit_query = '
				LIMIT ' . $page_start . $per_page;
        } else {
            $limit_query = '';
        }
        if ('DESC' === $args['order']) {
            $order_query = ' DESC';
        } else {
            $order_query = ' ASC';
        }
        // Now start building the actual query
        $query = "\n\t\t\tSELECT meta.*, items.*, r.renewal_order_count, (CASE WHEN (r.renewal_order_count > 0) THEN l.last_payment_date ELSE o.order_date END) AS last_payment_date FROM `{$wpdb->prefix}woocommerce_order_itemmeta` AS meta\n\t\t\tLEFT JOIN `{$wpdb->prefix}woocommerce_order_items` AS items USING (order_item_id)";
        $query .= "\n\t\t\tLEFT JOIN (\n\t\t\t\tSELECT a.order_item_id FROM `{$wpdb->prefix}woocommerce_order_itemmeta` AS a";
        // To filter order items by a specific product ID, we need to do another join
        if (!empty($args['product_id']) || !empty($args['variation_id'])) {
            // Can only specify a product ID or a variation ID, no need to specify a product ID if you want a variation of that product
            $meta_key = !empty($args['variation_id']) ? '_variation_id' : '_product_id';
            $query .= sprintf("\n\t\t\t\tLEFT JOIN (\n\t\t\t\t\tSELECT `{$wpdb->prefix}woocommerce_order_itemmeta`.order_item_id FROM `{$wpdb->prefix}woocommerce_order_itemmeta`\n\t\t\t\t\tWHERE `{$wpdb->prefix}woocommerce_order_itemmeta`.meta_key = '%s'\n\t\t\t\t\tAND `{$wpdb->prefix}woocommerce_order_itemmeta`.meta_value = %s\n\t\t\t\t) AS p\n\t\t\t\tUSING (order_item_id)", $meta_key, $args['product_id']);
        }
        // To filter order items by a specific subscription status, we need to do another join (unless we're also ordering by subscription status)
        if (!empty($args['subscription_status']) && 'any' !== $args['subscription_status'] && '_subscription_status' !== $args['orderby']) {
            if ('all' == $args['subscription_status']) {
                // get all but trashed subscriptions
                $query .= "\n\t\t\t\tLEFT JOIN (\n\t\t\t\t\tSELECT `{$wpdb->prefix}woocommerce_order_itemmeta`.order_item_id FROM `{$wpdb->prefix}woocommerce_order_itemmeta`\n\t\t\t\t\tWHERE `{$wpdb->prefix}woocommerce_order_itemmeta`.meta_key = '_subscription_status'\n\t\t\t\t\tAND `{$wpdb->prefix}woocommerce_order_itemmeta`.meta_value != 'trash'\n\t\t\t\t) AS s\n\t\t\t\tUSING (order_item_id)";
            } else {
                $query .= sprintf("\n\t\t\t\tLEFT JOIN (\n\t\t\t\t\tSELECT `{$wpdb->prefix}woocommerce_order_itemmeta`.order_item_id FROM `{$wpdb->prefix}woocommerce_order_itemmeta`\n\t\t\t\t\tWHERE `{$wpdb->prefix}woocommerce_order_itemmeta`.meta_key = '_subscription_status'\n\t\t\t\t\tAND `{$wpdb->prefix}woocommerce_order_itemmeta`.meta_value = '%s'\n\t\t\t\t) AS s\n\t\t\t\tUSING (order_item_id)", $args['subscription_status']);
            }
        }
        // We need an additional join when ordering by certain attributes
        switch ($args['orderby']) {
            case '_product_id':
                // Because all products have a product ID, but not all products are subscriptions
                if (empty($args['product_id'])) {
                    $query .= "\n\t\t\t\tLEFT JOIN (\n\t\t\t\t\tSELECT `{$wpdb->prefix}woocommerce_order_itemmeta`.order_item_id FROM `{$wpdb->prefix}woocommerce_order_itemmeta`\n\t\t\t\t\tWHERE `{$wpdb->prefix}woocommerce_order_itemmeta`.meta_key LIKE '_subscription_%s'\n\t\t\t\t\tGROUP BY `{$wpdb->prefix}woocommerce_order_itemmeta`.order_item_id\n\t\t\t\t) AS a2 USING (order_item_id)";
                }
                break;
            case '_order_item_name':
                // Because the order item name is found in the order_items tables
            // Because the order item name is found in the order_items tables
            case 'name':
                if (empty($args['product_id'])) {
                    $query .= "\n\t\t\t\tLEFT JOIN (\n\t\t\t\t\tSELECT `{$wpdb->prefix}woocommerce_order_items`.order_item_id, `{$wpdb->prefix}woocommerce_order_items`.order_item_name FROM `{$wpdb->prefix}woocommerce_order_items`\n\t\t\t\t\tWHERE `{$wpdb->prefix}woocommerce_order_items`.order_item_type = 'line_item'\n\t\t\t\t) AS names USING (order_item_id)";
                }
                break;
            case 'order_id':
                // Because the order ID is found in the order_items tables
                $query .= "\n\t\t\t\tLEFT JOIN (\n\t\t\t\t\tSELECT `{$wpdb->prefix}woocommerce_order_items`.order_item_id, `{$wpdb->prefix}woocommerce_order_items`.order_id FROM `{$wpdb->prefix}woocommerce_order_items`\n\t\t\t\t\tWHERE `{$wpdb->prefix}woocommerce_order_items`.order_item_type = 'line_item'\n\t\t\t\t) AS order_ids USING (order_item_id)";
                break;
            case 'renewal_order_count':
                $query .= "\n\t\t\t\tLEFT JOIN (\n\t\t\t\t\tSELECT items2.order_item_id, items2.order_id, r2.renewal_order_count FROM `{$wpdb->prefix}woocommerce_order_items` AS items2\n\t\t\t\t\tLEFT JOIN (\n\t\t\t\t\t\tSELECT posts.post_parent, COUNT(posts.ID) as renewal_order_count FROM `{$wpdb->prefix}posts` AS posts\n\t\t\t\t\t\tWHERE posts.post_parent != 0\n\t\t\t\t\t\tAND posts.post_type = 'shop_order'\n\t\t\t\t\t\tGROUP BY posts.post_parent\n\t\t\t\t\t) AS r2 ON r2.post_parent = items2.order_id\n\t\t\t\t\tWHERE items2.order_item_type = 'line_item'\n\t\t\t\t) AS renewals USING (order_item_id)";
                break;
            case 'user_display_name':
            case 'user':
                if (empty($args['customer_id'])) {
                    $query .= "\n\t\t\t\tLEFT JOIN (\n\t\t\t\t\tSELECT items2.order_item_id, items2.order_id, users.display_name FROM `{$wpdb->prefix}woocommerce_order_items` AS items2\n\t\t\t\t\tLEFT JOIN (\n\t\t\t\t\t\tSELECT postmeta.post_id, postmeta.meta_value, u.display_name FROM `{$wpdb->prefix}postmeta` AS postmeta\n\t\t\t\t\t\tLEFT JOIN (\n\t\t\t\t\t\t\tSELECT `{$wpdb->prefix}users`.ID, `{$wpdb->prefix}users`.display_name FROM `{$wpdb->prefix}users`\n\t\t\t\t\t\t) AS u ON u.ID = postmeta.meta_value\n\t\t\t\t\t\tWHERE postmeta.meta_key = '_customer_user'\n\t\t\t\t\t) AS users ON users.post_id = items2.order_id\n\t\t\t\t\tWHERE items2.order_item_type = 'line_item'\n\t\t\t\t) AS users_items USING (order_item_id)";
                }
            case 'last_payment_date':
                // Because we need the date of the last renewal order (or maybe the original order if there are no renewal orders)
                $query .= "\n\t\t\t\tLEFT JOIN (\n\t\t\t\t\tSELECT items2.order_item_id, (CASE WHEN (r2.renewal_order_count > 0) THEN l.last_payment_date ELSE o.order_date END) AS last_payment_date FROM `{$wpdb->prefix}woocommerce_order_items` AS items2\n\t\t\t\t\tLEFT JOIN (\n\t\t\t\t\t\tSELECT posts.post_parent, COUNT(posts.ID) as renewal_order_count FROM `{$wpdb->prefix}posts` AS posts\n\t\t\t\t\t\tWHERE posts.post_parent != 0\n\t\t\t\t\t\tAND posts.post_type = 'shop_order'\n\t\t\t\t\t\tGROUP BY posts.post_parent\n\t\t\t\t\t) AS r2 ON r2.post_parent = items2.order_id\n\t\t\t\t\tLEFT JOIN (\n\t\t\t\t\t\tSELECT o.ID, o.post_date_gmt AS order_date FROM `{$wpdb->prefix}posts` AS o\n\t\t\t\t\t\tWHERE o.post_type = 'shop_order'\n\t\t\t\t\t\tAND o.post_parent = 0\n\t\t\t\t\t) AS o ON o.ID = items2.order_id\n\t\t\t\t\tLEFT JOIN (\n\t\t\t\t\t\tSELECT p.ID, p.post_parent, MAX(p.post_date_gmt) AS last_payment_date FROM `{$wpdb->prefix}posts` AS p\n\t\t\t\t\t\tWHERE p.post_type = 'shop_order'\n\t\t\t\t\t\tAND p.post_parent != 0\n\t\t\t\t\t\tGROUP BY p.post_parent\n\t\t\t\t\t) AS l ON l.post_parent = items2.order_id\n\t\t\t\t\tWHERE items2.order_item_type = 'line_item'\n\t\t\t\t) AS payment_dates USING (order_item_id)";
                break;
        }
        // Start where query
        $query .= "\n\t\t\t\tWHERE 1=1";
        // We only want subscriptions from within the product filter subclause
        if (!empty($args['product_id']) || !empty($args['variation_id'])) {
            $query .= "\n\t\t\t\tAND a.order_item_id = p.order_item_id";
        }
        // We only want subscriptions from within the status filter subclause
        if (!empty($args['subscription_status']) && 'any' !== $args['subscription_status'] && '_subscription_status' !== $args['orderby']) {
            $query .= "\n\t\t\t\tAND a.order_item_id = s.order_item_id";
        }
        // We only want items from a certain order
        if (!empty($args['order_id'])) {
            $order_ids = is_array($args['order_id']) ? implode(',', $args['order_id']) : $args['order_id'];
            $query .= sprintf("\n\t\t\t\tAND a.order_item_id IN (\n\t\t\t\t\tSELECT o.order_item_id FROM `{$wpdb->prefix}woocommerce_order_items` AS o\n\t\t\t\t\tWHERE o.order_id IN (%s)\n\t\t\t\t)", $order_ids);
        }
        // If we only want subscriptions for a certain customer ID, we need to make sure items are from the customer's orders
        if (!empty($args['customer_id'])) {
            $query .= sprintf("\n\t\t\t\tAND a.order_item_id IN (\n\t\t\t\t\tSELECT `{$wpdb->prefix}woocommerce_order_items`.order_item_id FROM `{$wpdb->prefix}woocommerce_order_items`\n\t\t\t\t\tWHERE `{$wpdb->prefix}woocommerce_order_items`.order_id IN (\n\t\t\t\t\t\tSELECT `{$wpdb->prefix}postmeta`.post_id FROM `{$wpdb->prefix}postmeta`\n\t\t\t\t\t\tWHERE `{$wpdb->prefix}postmeta`.meta_key = '_customer_user'\n\t\t\t\t\t\tAND `{$wpdb->prefix}postmeta`.meta_value = %s\n\t\t\t\t\t)\n\t\t\t\t)", $args['customer_id']);
        }
        // Now we need to sort the subscriptions, which may mean selecting a specific bit of meta data
        switch ($args['orderby']) {
            case '_subscription_start_date':
            case '_subscription_expiry_date':
            case '_subscription_trial_expiry_date':
            case '_subscription_end_date':
                $query .= sprintf("\n\t\t\t\tAND a.meta_key = '%s'\n\t\t\t\tORDER BY CASE WHEN CAST(a.meta_value AS DATETIME) IS NULL THEN 1 ELSE 0 END, CAST(a.meta_value AS DATETIME) %s", $args['orderby'], $order_query);
                break;
            case '_subscription_status':
                $query .= "\n\t\t\t\tAND a.meta_key = '_subscription_status'\n\t\t\t\tORDER BY a.meta_value" . $order_query;
                break;
            case '_product_id':
                if (empty($args['product_id'])) {
                    $query .= "\n\t\t\t\tAND a2.order_item_id = a.order_item_id\n\t\t\t\tAND a.meta_key = '_product_id'\n\t\t\t\tORDER BY a.meta_value" . $order_query;
                }
                break;
            case '_order_item_name':
            case 'name':
                if (empty($args['product_id'])) {
                    $query .= "\n\t\t\t\tAND a.meta_key = '_subscription_start_date'\n\t\t\t\tAND names.order_item_id = a.order_item_id\n\t\t\t\tORDER BY names.order_item_name" . $order_query . ", CASE WHEN CAST(a.meta_value AS DATETIME) IS NULL THEN 1 ELSE 0 END, CAST(a.meta_value AS DATETIME) DESC";
                }
                break;
            case 'order_id':
                $query .= "\n\t\t\t\tAND a.meta_key = '_subscription_start_date'\n\t\t\t\tAND order_ids.order_item_id = a.order_item_id\n\t\t\t\tORDER BY order_ids.order_id" . $order_query;
                break;
            case 'renewal_order_count':
                $query .= "\n\t\t\t\tAND a.meta_key = '_subscription_start_date'\n\t\t\t\tAND renewals.order_item_id = a.order_item_id\n\t\t\t\tORDER BY renewals.renewal_order_count" . $order_query;
                break;
            case 'user_display_name':
            case 'user':
                if (empty($args['customer_id'])) {
                    $query .= "\n\t\t\t\tAND a.meta_key = '_subscription_start_date'\n\t\t\t\tAND users_items.order_item_id = a.order_item_id\n\t\t\t\tORDER BY users_items.display_name" . $order_query . ", CASE WHEN CAST(a.meta_value AS DATETIME) IS NULL THEN 1 ELSE 0 END, CAST(a.meta_value AS DATETIME) DESC";
                }
                break;
            case 'last_payment_date':
                $query .= "\n\t\t\t\tAND a.meta_key = '_subscription_start_date'\n\t\t\t\tAND payment_dates.order_item_id = a.order_item_id\n\t\t\t\tORDER BY payment_dates.last_payment_date" . $order_query;
                break;
        }
        // Paging
        if (-1 !== $args['subscriptions_per_page']) {
            $query .= $limit_query;
        }
        $query .= "\n\t\t\t) AS a3 USING (order_item_id)";
        // Add renewal order count & last payment date (there is duplication here when ordering by renewal order count or last payment date, but it's an arbitrary performance hit)
        $query .= "\n\t\t\tLEFT JOIN (\n\t\t\t\tSELECT `{$wpdb->prefix}posts`.post_parent, COUNT(`{$wpdb->prefix}posts`.ID) as renewal_order_count FROM `{$wpdb->prefix}posts`\n\t\t\t\tWHERE `{$wpdb->prefix}posts`.post_parent != 0\n\t\t\t\tAND `{$wpdb->prefix}posts`.post_type = 'shop_order'\n\t\t\t\tGROUP BY `{$wpdb->prefix}posts`.post_parent\n\t\t\t) AS r ON r.post_parent = items.order_id\n\t\t\tLEFT JOIN (\n\t\t\t\tSELECT o.ID, o.post_date_gmt AS order_date FROM `{$wpdb->prefix}posts` AS o\n\t\t\t\tWHERE o.post_type = 'shop_order'\n\t\t\t\tAND o.post_parent = 0\n\t\t\t) AS o ON o.ID = items.order_id\n\t\t\tLEFT JOIN (\n\t\t\t\tSELECT p.ID, p.post_parent, MAX(p.post_date_gmt) AS last_payment_date FROM `{$wpdb->prefix}posts` AS p\n\t\t\t\tWHERE p.post_type = 'shop_order'\n\t\t\t\tAND p.post_parent != 0\n\t\t\t\tGROUP BY p.post_parent\n\t\t\t) AS l ON l.post_parent = items.order_id";
        $query .= "\n\t\t\tWHERE meta.meta_key REGEXP '_subscription_(.*)|_product_id|_variation_id'\n\t\t\tAND meta.order_item_id = a3.order_item_id";
        $query = apply_filters('woocommerce_get_subscriptions_query', $query, $args);
        $raw_subscriptions = $wpdb->get_results($query);
        // Create a backward compatible structure
        foreach ($raw_subscriptions as $raw_subscription) {
            if (!isset($raw_subscription->order_item_id)) {
                continue;
            }
            if (!array_key_exists($raw_subscription->order_item_id, $subscriptions)) {
                $subscriptions[$raw_subscription->order_item_id] = array('order_id' => $raw_subscription->order_id, 'name' => $raw_subscription->order_item_name, 'renewal_order_count' => empty($raw_subscription->renewal_order_count) ? 0 : $raw_subscription->renewal_order_count, 'last_payment_date' => $raw_subscription->last_payment_date);
                $subscriptions[$raw_subscription->order_item_id]['user_id'] = get_post_meta($raw_subscription->order_id, '_customer_user', true);
            }
            $meta_key = str_replace('_subscription', '', $raw_subscription->meta_key);
            $meta_key = substr($meta_key, 0, 1) == '_' ? substr($meta_key, 1) : $meta_key;
            if ('product_id' === $meta_key) {
                $subscriptions[$raw_subscription->order_item_id]['subscription_key'] = WC_Subscriptions_Manager::get_subscription_key($subscriptions[$raw_subscription->order_item_id]['order_id'], $raw_subscription->meta_value);
            }
            $subscriptions[$raw_subscription->order_item_id][$meta_key] = maybe_unserialize($raw_subscription->meta_value);
        }
        return apply_filters('woocommerce_get_subscriptions', $subscriptions, $args);
    }
 /**
  * Update the recurring payment method for a subscription after a customer has paid for a failed renewal order
  * (which usually failed because of an issue with the existing payment, like an expired card or token).
  *
  * Also trigger a hook for payment gateways to update any meta on the original order for a subscription.
  *
  * @param WC_Order $renewal_order The order which recorded the successful payment (to make up for the failed automatic payment).
  * @param WC_Order $original_order The original order in which the subscription was purchased.
  * @since 1.4
  */
 public static function change_failing_payment_method($renewal_order, $original_order)
 {
     $subscription_key = WC_Subscriptions_Manager::get_subscription_key($original_order->id);
     $new_payment_method = woocommerce_clean($_POST['payment_method']);
     self::update_recurring_payment_method($subscription_key, $original_order, $new_payment_method);
     do_action('woocommerce_subscriptions_changed_failing_payment_method', $original_order, $renewal_order, $subscription_key);
     do_action('woocommerce_subscriptions_changed_failing_payment_method_' . $new_payment_method, $original_order, $renewal_order, $subscription_key);
 }
 /**
  * Make sure anything requesting the first payment date for a synced subscription on the front-end receives
  * a date which takes into account the day on which payments should be processed.
  *
  * This is necessary as the self::calculate_first_payment_date() is not called when the subscription is active
  * (which it isn't until the first payment is completed and the subscription is activated).
  *
  * @since 1.5
  */
 public static function get_first_payment_date($first_payment_date, $order, $product_id, $type)
 {
     $subscription_key = WC_Subscriptions_Manager::get_subscription_key($order->id, $product_id);
     if (self::order_contains_synced_subscription($order->id) && 1 >= WC_Subscriptions_Manager::get_subscriptions_completed_payment_count($subscription_key)) {
         $subscription = WC_Subscriptions_Manager::get_subscription($subscription_key);
         // Don't prematurely set the first payment date when manually adding a subscription from the admin
         if (defined('WOOCOMMERCE_CHECKOUT') && true === WOOCOMMERCE_CHECKOUT || !is_admin() || 'active' == $subscription['status']) {
             $id_for_calculation = !empty($subscription['variation_id']) ? $subscription['variation_id'] : $subscription['product_id'];
             $first_payment_timestamp = self::calculate_first_payment_date($id_for_calculation, 'timestamp', $order->order_date);
             if (0 != $first_payment_timestamp) {
                 $first_payment_date = 'mysql' == $type ? date('Y-m-d H:i:s', $first_payment_timestamp) : $first_payment_timestamp;
             }
         }
     }
     return $first_payment_date;
 }
 /**
  * Save related subscription data when a membership access is granted via a purchase
  *
  * Sets the end date to match subscription end date
  *
  * @since 1.0.0
  * @param WC_Memberships_Membership_Plan $plan
  * @param array $args
  */
 public function save_subscription_data(WC_Memberships_Membership_Plan $plan, $args)
 {
     $product = wc_get_product($args['product_id']);
     // Handle access from subscriptions
     if ($this->has_membership_plan_subscription($plan->get_id()) && $product->is_type(array('subscription', 'subscription_variation', 'variable-subscription'))) {
         // note: always use the product ID (not variation ID) when looking up a subscription
         // as Subs requires it
         $subscription = $this->get_order_product_subscription($args['order_id'], $product->id);
         if (!$subscription) {
             return;
         }
         if ($this->is_subscriptions_gte_2_0()) {
             // Save related subscription ID
             update_post_meta($args['user_membership_id'], '_subscription_id', $subscription->id);
         } else {
             // Save related subscription key
             $subscription_key = WC_Subscriptions_Manager::get_subscription_key($args['order_id'], $product->id);
             update_post_meta($args['user_membership_id'], '_subscription_key', $subscription_key);
         }
         // Set membership expiry date based on subscription expiry date
         if ($this->plan_grants_access_while_subscription_active($plan->get_id())) {
             $end_date = $this->is_subscriptions_gte_2_0() ? $subscription->get_date('end') ? $subscription->get_date('end') : '' : ($subscription['expiry_date'] ? $subscription['expiry_date'] : '');
             update_post_meta($args['user_membership_id'], '_end_date', $end_date);
         }
     }
 }
 /**
  * If the payment for a renewal order has previously failed and is then paid, we need to make sure the
  * subscription payment function is called.
  *
  * @param int $user_id The id of the user who purchased the subscription
  * @param string $subscription_key A subscription key of the form created by @see WC_Subscriptions_Manager::get_subscription_key()
  * @since 1.2
  */
 public static function process_subscription_payment_on_child_order($order_id, $payment_status = 'completed')
 {
     if (self::is_renewal($order_id, array('order_role' => 'child'))) {
         $child_order = new WC_Order($order_id);
         $parent_order = self::get_parent_order($child_order);
         $subscriptions_in_order = $child_order->get_items();
         // Should only be one subscription in the renewal order, but just in case
         foreach ($subscriptions_in_order as $item) {
             $item_id = WC_Subscriptions_Order::get_items_product_id($item);
             if (WC_Subscriptions_Order::is_item_subscription($parent_order, $item_id)) {
                 if ('failed' == $payment_status) {
                     // Don't duplicate renewal order
                     remove_action('processed_subscription_payment_failure', __CLASS__ . '::generate_failed_payment_renewal_order', 10, 2);
                     WC_Subscriptions_Manager::process_subscription_payment_failure_on_order($parent_order->id, $item_id);
                     // But make sure orders are still generated for other payments in the same request
                     add_action('processed_subscription_payment_failure', __CLASS__ . '::generate_failed_payment_renewal_order', 10, 2);
                 } else {
                     // Don't duplicate renewal order
                     remove_action('processed_subscription_payment', __CLASS__ . '::generate_paid_renewal_order', 10, 2);
                     WC_Subscriptions_Manager::process_subscription_payments_on_order($parent_order->id, $item_id);
                     // But make sure orders are still generated for other payments in the same request
                     add_action('processed_subscription_payment', __CLASS__ . '::generate_paid_renewal_order', 10, 2);
                     // Reactivate the subscription - activate_subscription doesn't operate on child orders
                     $subscription_key = WC_Subscriptions_Manager::get_subscription_key($parent_order->id, $item_id);
                     WC_Subscriptions_Manager::reactivate_subscription($parent_order->customer_user, $subscription_key);
                 }
             }
         }
     }
 }
 /**
  * Update the recurring payment method for a subscription after a customer has paid for a failed renewal order
  * (which usually failed because of an issue with the existing payment, like an expired card or token).
  *
  * Also trigger a hook for payment gateways to update any meta on the original order for a subscription.
  *
  * @param WC_Order $renewal_order The order which recorded the successful payment (to make up for the failed automatic payment).
  * @param WC_Order $original_order The original order in which the subscription was purchased.
  * @since 1.4
  */
 public static function change_failing_payment_method($renewal_order, $original_order)
 {
     if (!WC_Subscriptions_Order::requires_manual_renewal($original_order->id)) {
         $subscription_key = WC_Subscriptions_Manager::get_subscription_key($original_order->id);
         if (isset($_POST['payment_method'])) {
             $new_payment_method = woocommerce_clean($_POST['payment_method']);
         } else {
             $new_payment_method = $renewal_order->payment_method;
         }
         self::update_recurring_payment_method($subscription_key, $original_order, $new_payment_method);
         do_action('woocommerce_subscriptions_changed_failing_payment_method', $original_order, $renewal_order, $subscription_key);
         do_action('woocommerce_subscriptions_changed_failing_payment_method_' . $new_payment_method, $original_order, $renewal_order, $subscription_key);
     }
 }
示例#10
0
function blendercloud_api($atts)
{
    $user_data = array('shop_id' => '0', 'cloud_access' => 0, 'expiration_date' => '1970-01-01 00:00:00');
    $last_expiration_date = new DateTime('1970-01-01 00:00:00');
    // map blenderid to userid
    $args = array('search' => $_GET['blenderid'], 'search_columns' => array('user_login'));
    $user_query = new WP_User_Query($args);
    // Get the results from the query, returning the first user
    $users = $user_query->get_results();
    if (!empty($users)) {
        $user_id = $users[0]->ID;
        $user_data['shop_id'] = $user_id;
        // process simple products (prepaid subscriptions)
        $order_ids = bo_get_all_user_orders($user_id, 'completed');
        foreach ($order_ids as $order_id) {
            $order = new WC_Order($order_id);
            $order_date = $order->order_date;
            $items = $order->get_items();
            foreach ($items as $item) {
                $tmp = bo_empty_subscription_line();
                $product_id = $item['product_id'];
                $product = get_product($product_id);
                $sku = $product->get_sku();
                $expiry_date = new DateTime($order_date);
                $tmp['sku'] = $sku;
                switch ($sku) {
                    case 'cloud-prepaid-3':
                    case 'cloud-prepaid-3-renewal':
                        $expiry_date->modify('+3 month');
                        break;
                    case 'cloud-prepaid-18':
                        $expiry_date->modify('+18 month');
                        break;
                    default:
                        continue 2;
                        // skip to next product
                }
                $tmp['expiration_date'] = $expiry_date->format('Y-m-d H:i:s');
                $tmp['subscription_status'] = 'prepaid';
                $now = new DateTime("now");
                if ($expiry_date > $now) {
                    $tmp['cloud_access'] = 1;
                }
                if ($expiry_date > $last_expiration_date) {
                    $last_expiration_date = $expiry_date;
                }
                $user_data['subscriptions'][] = $tmp;
            }
        }
        // process recurring subscriptions
        $subscriptions = WC_Subscriptions_Manager::get_users_subscriptions($user_id);
        if (!empty($subscriptions)) {
            // iterate over all subscriptions.
            foreach ($subscriptions as $subscription_details) {
                if ($subscription_details['status'] != 'trash') {
                    $order_id = $subscription_details['order_id'];
                    $product_id = $subscription_details['product_id'];
                    $order = new WC_Order($order_id);
                    // print_r($order);
                    // $next_payment_date	= WC_Subscriptions_Manager::get_next_payment_date( $subscription_key, $user_id, 'mysql' );
                    $subscription_key = WC_Subscriptions_Manager::get_subscription_key($order_id, $product_id);
                    if ($subscription_details['expiry_date'] == 0 && !in_array($subscription_details['status'], array('cancelled', 'switched'))) {
                        $end_time = WC_Subscriptions_Manager::get_next_payment_date($subscription_key, $user_id, 'mysql');
                        $end_timestamp = strtotime($end_time);
                    } else {
                        if (in_array($subscription_details['status'], array('cancelled', 'switched'))) {
                            $end_of_prepaid_term = wc_next_scheduled_action('scheduled_subscription_end_of_prepaid_term', array('user_id' => (int) $user_id, 'subscription_key' => $subscription_key));
                            if (false === $end_of_prepaid_term) {
                                $end_timestamp = strtotime($subscription_details['end_date']);
                            } else {
                                $end_timestamp = $end_of_prepaid_term;
                            }
                        } else {
                            $end_timestamp = strtotime($subscription_details['expiry_date']);
                        }
                    }
                    //					if( $users[0]->data->user_email == '*****@*****.**' ) {
                    //						print_r($subscription_details);
                    //					}
                    if ($subscription_details['status'] == 'cancelled') {
                        $end_timestamp = strtotime($subscription_details['trial_expiry_date']);
                    }
                    if ($subscription_details['status'] == 'on-hold') {
                        $end_timestamp = strtotime($subscription_details['last_payment_date']);
                    }
                    $end_time = date("Y-m-d H:i:s", $end_timestamp);
                    $product = get_product($product_id);
                    $sku = $product->get_sku();
                    $tmp = bo_empty_subscription_line();
                    $tmp['expiration_date'] = $end_time;
                    $tmp['subscription_status'] = $subscription_details['status'];
                    $expiry_date = new DateTime($end_time);
                    if ($expiry_date > $last_expiration_date) {
                        $last_expiration_date = $expiry_date;
                    }
                    $now = new DateTime("now");
                    $tmp['cloud_access'] = $expiry_date > $now ? 1 : 0;
                    $tmp['sku'] = $sku;
                    // if order is refunded, stop access
                    if ($order->status == 'refunded') {
                        $tmp['expiration_date'] = $end_time;
                        $tmp['subscription_status'] = 'refunded';
                        $tmp['cloud_access'] = 0;
                    }
                    switch ($sku) {
                        case 'cloud-subscription-1-renewal':
                        case 'cloud-subscription-3':
                            //$tmp['failed_payments'] = $subscription['failed_payments'];
                            break;
                        case 'cloud-subscription-team':
                            // purchased team size
                            $variation_id = $subscription_details['variation_id'];
                            // find variation info from order to pass on # of seats
                            $order = new WC_Order($order_id);
                            $items = $order->get_items();
                            $team_members = 0;
                            foreach ($items as $item) {
                                // does product variation id match the current subscription?
                                if ($item['item_meta']['_variation_id'][0] == $variation_id) {
                                    $team_members = $item['item_meta']['pa_team-size'][0];
                                }
                            }
                            $tmp['team_members'] = $team_members;
                            break;
                    }
                    $user_data['subscriptions'][] = $tmp;
                }
            }
        }
    }
    // add one grace day to expiration
    $last_expiration_date->add(DateInterval::createfromdatestring('+1 day'));
    $user_data['expiration_date'] = $last_expiration_date->format('Y-m-d H:i:s');
    $now = new DateTime("now");
    if ($last_expiration_date > $now) {
        $user_data['cloud_access'] = 1;
    }
    //echo "<pre>";print_r($user_data);
    echo json_encode($user_data, JSON_PRETTY_PRINT);
    die;
}
function woo_ce_get_subscription_key( $order_id = 0, $product_id = 0 ) {

	if( method_exists( 'WC_Subscriptions_Manager', 'get_subscription_key' ) ) {
		$key = WC_Subscriptions_Manager::get_subscription_key( $order_id, $product_id );
		return $key;
	}

}
 /**
  * When a PayPal IPN messaged is received for a subscription transaction, 
  * check the transaction details and 
  *
  * @since 1.0
  */
 public static function process_paypal_ipn_request($transaction_details)
 {
     global $wpdb;
     $transaction_details = stripslashes_deep($transaction_details);
     if (!in_array($transaction_details['txn_type'], array('subscr_signup', 'subscr_payment', 'subscr_cancel', 'subscr_eot', 'subscr_failed', 'subscr_modify'))) {
         return;
     }
     if (empty($transaction_details['custom']) || empty($transaction_details['invoice'])) {
         return;
     }
     // Get the $order_id & $order_key with backward compatibility
     extract(self::get_order_id_and_key($transaction_details));
     $transaction_details['txn_type'] = strtolower($transaction_details['txn_type']);
     if (self::$debug) {
         self::$log->add('paypal', 'Subscription Transaction Type: ' . $transaction_details['txn_type']);
     }
     if (self::$debug) {
         self::$log->add('paypal', 'Subscription transaction details: ' . print_r($transaction_details, true));
     }
     $order = new WC_Order($order_id);
     // We have an invalid $order_id, probably because invoice_prefix has changed since the subscription was first created, so get the order by order key
     if (!isset($order->id)) {
         $order_id = function_exists('woocommerce_get_order_id_by_order_key') ? woocommerce_get_order_id_by_order_key($order_key) : $wpdb->get_var("SELECT post_id FROM {$wpdb->prefix}postmeta WHERE meta_key = '_order_key' AND meta_value = '{$order_key}'");
         $order = new WC_Order($order_id);
     }
     if ($order->order_key !== $order_key) {
         if (self::$debug) {
             self::$log->add('paypal', 'Subscription IPN Error: Order Key does not match invoice.');
         }
         return;
     }
     if (isset($transaction_details['ipn_track_id'])) {
         // Make sure the IPN request has not already been handled
         $handled_ipn_requests = get_post_meta($order_id, '_paypal_ipn_tracking_ids', true);
         if (empty($handled_ipn_requests)) {
             $handled_ipn_requests = array();
         }
         // The 'ipn_track_id' is not a unique ID and is shared between different transaction types, so create a unique ID by prepending the transaction type
         $transaction_id = $transaction_details['txn_type'] . '_' . $transaction_details['ipn_track_id'];
         if (in_array($transaction_id, $handled_ipn_requests)) {
             if (self::$debug) {
                 self::$log->add('paypal', 'Subscription IPN Error: This IPN message has already been correctly handled.');
             }
             return;
         }
     }
     if (isset($transaction_details['subscr_id'])) {
         update_post_meta($order_id, 'PayPal Subscriber ID', $transaction_details['subscr_id']);
     }
     // Get the subscription this IPN message relates to
     $subscriptions_in_order = WC_Subscriptions_Order::get_recurring_items($order);
     $subscription_item = array_pop($subscriptions_in_order);
     $subscription_key = WC_Subscriptions_Manager::get_subscription_key($order->id, WC_Subscriptions_Order::get_items_product_id($subscription_item));
     $subscription = WC_Subscriptions_Manager::get_subscription($subscription_key, $order->customer_user);
     $is_first_payment = empty($subscription['completed_payments']) ? true : false;
     switch ($transaction_details['txn_type']) {
         case 'subscr_signup':
             // Store PayPal Details
             update_post_meta($order_id, 'Payer PayPal address', $transaction_details['payer_email']);
             update_post_meta($order_id, 'Payer PayPal first name', $transaction_details['first_name']);
             update_post_meta($order_id, 'Payer PayPal last name', $transaction_details['last_name']);
             // Payment completed
             $order->add_order_note(__('IPN subscription sign up completed.', WC_Subscriptions::$text_domain));
             if (self::$debug) {
                 self::$log->add('paypal', 'IPN subscription sign up completed for order ' . $order_id);
             }
             // When there is a free trial & no initial payment amount, we need to mark the order as paid and activate the subscription
             if (0 == WC_Subscriptions_Order::get_total_initial_payment($order) && WC_Subscriptions_Order::get_subscription_trial_length($order) > 0) {
                 $order->payment_complete();
                 WC_Subscriptions_Manager::activate_subscriptions_for_order($order);
             }
             break;
         case 'subscr_payment':
             if ('completed' == strtolower($transaction_details['payment_status'])) {
                 // Store PayPal Details
                 update_post_meta($order_id, 'PayPal Transaction ID', $transaction_details['txn_id']);
                 update_post_meta($order_id, 'Payer PayPal first name', $transaction_details['first_name']);
                 update_post_meta($order_id, 'Payer PayPal last name', $transaction_details['last_name']);
                 update_post_meta($order_id, 'PayPal Payment type', $transaction_details['payment_type']);
                 // Subscription Payment completed
                 $order->add_order_note(__('IPN subscription payment completed.', WC_Subscriptions::$text_domain));
                 if (self::$debug) {
                     self::$log->add('paypal', 'IPN subscription payment completed for order ' . $order_id);
                 }
                 // First payment on order, process payment & activate subscription
                 if ($is_first_payment) {
                     $order->payment_complete();
                     WC_Subscriptions_Manager::activate_subscriptions_for_order($order);
                 } else {
                     // We don't need to reactivate the subscription because Subs didn't suspend it
                     remove_action('reactivated_subscription_paypal', __CLASS__ . '::reactivate_subscription_with_paypal', 10, 2);
                     WC_Subscriptions_Manager::process_subscription_payments_on_order($order);
                     add_action('reactivated_subscription_paypal', __CLASS__ . '::reactivate_subscription_with_paypal', 10, 2);
                 }
             } elseif ('failed' == strtolower($transaction_details['payment_status'])) {
                 // Subscription Payment completed
                 $order->add_order_note(__('IPN subscription payment failed.', WC_Subscriptions::$text_domain));
                 if (self::$debug) {
                     self::$log->add('paypal', 'IPN subscription payment failed for order ' . $order_id);
                 }
                 // First payment on order, don't generate a renewal order
                 if ($is_first_payment) {
                     remove_action('processed_subscription_payment_failure', 'WC_Subscriptions_Renewal_Order::generate_failed_payment_renewal_order', 10, 2);
                 }
                 WC_Subscriptions_Manager::process_subscription_payment_failure_on_order($order);
             } else {
                 if (self::$debug) {
                     self::$log->add('paypal', 'IPN subscription payment notification received for order ' . $order_id . ' with status ' . $transaction_details['payment_status']);
                 }
             }
             break;
         case 'subscr_cancel':
             if (self::$debug) {
                 self::$log->add('paypal', 'IPN subscription cancelled for order ' . $order_id);
             }
             // Subscription Payment completed
             $order->add_order_note(__('IPN subscription cancelled for order.', WC_Subscriptions::$text_domain));
             WC_Subscriptions_Manager::cancel_subscriptions_for_order($order);
             break;
         case 'subscr_eot':
             // Subscription ended, either due to failed payments or expiration
             $subscription_length = WC_Subscriptions_Order::get_subscription_length($order);
             // PayPal fires the 'subscr_eot' notice immediately if a subscription is only for one billing period, so ignore the request when we only have one billing period
             if (1 != $subscription_length && $subscription_length != WC_Subscriptions_Order::get_subscription_interval($order)) {
                 if (self::$debug) {
                     self::$log->add('paypal', 'IPN subscription end-of-term for order ' . $order_id);
                 }
                 // Record subscription ended
                 $order->add_order_note(__('IPN subscription end-of-term for order.', WC_Subscriptions::$text_domain));
                 // Ended due to failed payments so cancel the subscription
                 if (gmdate('U') + 24 * 60 * 60 < strtotime(WC_Subscriptions_Manager::get_subscription_expiration_date(WC_Subscriptions_Manager::get_subscription_key($order->id), $order->customer_user))) {
                     WC_Subscriptions_Manager::cancel_subscriptions_for_order($order);
                 } else {
                     WC_Subscriptions_Manager::expire_subscriptions_for_order($order);
                 }
             }
             break;
         case 'subscr_failed':
             // Subscription sign up failed
             if (self::$debug) {
                 self::$log->add('paypal', 'IPN subscription payment failure for order ' . $order_id);
             }
             // Subscription Payment completed
             $order->add_order_note(__('IPN subscription payment failure.', WC_Subscriptions::$text_domain));
             // First payment on order, don't generate a renewal order
             if ($is_first_payment) {
                 remove_action('processed_subscription_payment_failure', 'WC_Subscriptions_Renewal_Order::generate_failed_payment_renewal_order', 10, 2);
             }
             WC_Subscriptions_Manager::process_subscription_payment_failure_on_order($order_id);
             break;
     }
     // Store the transaction ID to avoid handling requests duplicated by PayPal
     if (isset($transaction_details['ipn_track_id'])) {
         $handled_ipn_requests[] = $transaction_id;
         update_post_meta($order_id, '_paypal_ipn_tracking_ids', $handled_ipn_requests);
     }
     // Prevent default IPN handling for subscription txn_types
     exit;
 }
示例#13
0
 /**
  * Delete a stored billing method
  */
 function delete_payment_method($payment_method)
 {
     global $woocommerce;
     $user = wp_get_current_user();
     $customer_vault_ids = get_user_meta($user->ID, 'customer_vault_ids', true);
     $id = $customer_vault_ids[$payment_method];
     // If method is Single Billing, actually delete the record
     if (substr($id, 0, 1) !== '_') {
         $inspire_request = array('username' => $this->username, 'password' => $this->password, 'customer_vault' => 'delete_customer', 'customer_vault_id' => $id);
         $response = $this->post_and_get_response($inspire_request);
         if ($response['response'] != 1) {
             $woocommerce->add_error(__('Sorry, there was an error: ', 'woocommerce') . $response['responsetext']);
             $woocommerce->show_messages();
             return;
         }
     }
     $last_method = count($customer_vault_ids) - 1;
     // Update subscription references
     if (class_exists('WC_Subscriptions_Manager')) {
         foreach ((array) WC_Subscriptions_Manager::get_users_subscriptions($user->ID) as $subscription) {
             $subscription_payment_method = get_post_meta($subscription['order_id'], 'payment_method_number', true);
             // Cancel subscriptions that were purchased with the deleted method
             if ($subscription_payment_method == $payment_method) {
                 delete_post_meta($subscription['order_id'], 'payment_method_number');
                 WC_Subscriptions_Manager::cancel_subscription($user->ID, WC_Subscriptions_Manager::get_subscription_key($subscription['order_id']));
             } else {
                 if ($subscription_payment_method == $last_method && $subscription['status'] != 'cancelled') {
                     update_post_meta($subscription['order_id'], 'payment_method_number', $payment_method);
                 }
             }
         }
     }
     // Delete the reference by replacing it with the last method in the array
     if ($payment_method < $last_method) {
         $customer_vault_ids[$payment_method] = $customer_vault_ids[$last_method];
     }
     unset($customer_vault_ids[$last_method]);
     update_user_meta($user->ID, 'customer_vault_ids', $customer_vault_ids);
     $woocommerce->add_message(__('Successfully deleted your information!', 'woocommerce'));
     $woocommerce->show_messages();
 }
 /**
  * Returns an array of order IDs for valid orders that grant group
  * membership for the given group to the user related to the order.
  * 
  * @param int $user_id
  * @param int $group_id
  * @return array of int, order IDs
  */
 public static function get_valid_order_ids_granting_group_membership_from_order_items($user_id, $group_id)
 {
     $order_ids = array();
     if (!empty($user_id)) {
         $base_statuses = array('processing', 'completed');
         $statuses = array('completed');
         $options = get_option('groups-woocommerce', array());
         $order_status = isset($options[GROUPS_WS_MEMBERSHIP_ORDER_STATUS]) ? $options[GROUPS_WS_MEMBERSHIP_ORDER_STATUS] : GROUPS_WS_DEFAULT_MEMBERSHIP_ORDER_STATUS;
         if ($order_status == 'processing') {
             $statuses[] = 'processing';
         }
         // DO NOT use groups_ws_order_status( $statuses ) for $statuses or $base_statuses here,
         // $order->status doesn't provide the wc- prefix.
         $groups_product_groups = get_user_meta($user_id, '_groups_product_groups', true);
         if (empty($groups_product_groups)) {
             $groups_product_groups = array();
         }
         foreach ($groups_product_groups as $order_id => $product_ids) {
             if ($order = Groups_WS_Helper::get_order($order_id)) {
                 // If this is a completed/processing order, consider group assignments.
                 // We check the order status for non-subscription products below,
                 // for subscriptions the subscription status is checked.
                 if (in_array($order->status, $base_statuses)) {
                     // Note that for orders placed with versions up to 1.4.1, the following won't give the results we might expect if the product group-related information has changed since the order was placed.
                     // As we don't store that information (WC doesn't store the whole lot of the product when purchased, nor does GW) checking the duration based on the product is the best effort at
                     // finding out about the group membership duration we can make.
                     // Use the order items (only existing order items are taken into account).
                     if ($items = $order->get_items()) {
                         foreach ($items as $item) {
                             if ($product = $order->get_product_from_item($item)) {
                                 // Use the groups that were stored for the product when it was ordered,
                                 // this avoids hickups when the product's groups were changed since.
                                 if (isset($product_ids[$product->id]) && isset($product_ids[$product->id]['groups'])) {
                                     $product_groups = $product_ids[$product->id]['groups'];
                                     if (in_array($group_id, $product_groups)) {
                                         // non-subscriptions
                                         if (!class_exists('WC_Subscriptions_Product') || !WC_Subscriptions_Product::is_subscription($product->id)) {
                                             if (in_array($order->status, $statuses)) {
                                                 if (isset($product_ids[$product->id]) && isset($product_ids[$product->id]['version'])) {
                                                     $has_duration = isset($product_ids[$product->id]['duration']) && $product_ids[$product->id]['duration'] && isset($product_ids[$product->id]['duration_uom']);
                                                 } else {
                                                     $has_duration = Groups_WS_Product::has_duration($product);
                                                 }
                                                 // unlimited membership
                                                 if (!$has_duration) {
                                                     if (!in_array($order_id, $order_ids)) {
                                                         $order_ids[] = $order_id;
                                                     }
                                                 } else {
                                                     if (isset($product_ids[$product->id]) && isset($product_ids[$product->id]['version'])) {
                                                         $duration = Groups_WS_Product::calculate_duration($product_ids[$product->id]['duration'], $product_ids[$product->id]['duration_uom']);
                                                     } else {
                                                         // <= 1.4.1
                                                         $duration = Groups_WS_Product::get_duration($product);
                                                     }
                                                     // time-limited membership
                                                     if ($duration) {
                                                         $start_date = $order->order_date;
                                                         if ($paid_date = get_post_meta($order_id, '_paid_date', true)) {
                                                             $start_date = $paid_date;
                                                         }
                                                         $end = strtotime($start_date) + $duration;
                                                         if (time() < $end) {
                                                             if (!in_array($order_id, $order_ids)) {
                                                                 $order_ids[] = $order_id;
                                                             }
                                                         }
                                                     }
                                                 }
                                             }
                                         } else {
                                             // include active subscriptions ( subscriptions >= 2.x )
                                             if (function_exists('wcs_get_subscriptions_for_order')) {
                                                 if ($subscriptions = wcs_get_subscriptions_for_order($order_id)) {
                                                     if (is_array($subscriptions)) {
                                                         foreach ($subscriptions as $subscription) {
                                                             if ($subscription->has_product($product->id)) {
                                                                 $valid = false;
                                                                 if ($subscription->get_status() == 'active') {
                                                                     $valid = true;
                                                                 } else {
                                                                     if ($subscription->get_status() == 'cancelled') {
                                                                         $hook_args = array('subscription_id' => $subscription->id);
                                                                         $end_timestamp = wp_next_scheduled('scheduled_subscription_end_of_prepaid_term', $hook_args);
                                                                         if ($end_timestamp !== false && $end_timestamp > time()) {
                                                                             $valid = true;
                                                                         }
                                                                     }
                                                                 }
                                                                 if ($valid) {
                                                                     if (!in_array($order_id, $order_ids)) {
                                                                         $order_ids[] = $order_id;
                                                                         break;
                                                                     }
                                                                 }
                                                             }
                                                         }
                                                     }
                                                 }
                                             } else {
                                                 $subscription_key = WC_Subscriptions_Manager::get_subscription_key($order_id, $product->id);
                                                 $subscription = WC_Subscriptions_Manager::get_subscription($subscription_key);
                                                 if (isset($subscription['status'])) {
                                                     $valid = false;
                                                     if ($subscription['status'] == 'active') {
                                                         $valid = true;
                                                     } else {
                                                         if ($subscription['status'] == 'cancelled') {
                                                             $hook_args = array('user_id' => (int) $user_id, 'subscription_key' => $subscription_key);
                                                             $end_timestamp = wp_next_scheduled('scheduled_subscription_end_of_prepaid_term', $hook_args);
                                                             if ($end_timestamp !== false && $end_timestamp > time()) {
                                                                 $valid = true;
                                                             }
                                                         }
                                                     }
                                                     if ($valid) {
                                                         if (!in_array($order_id, $order_ids)) {
                                                             $order_ids[] = $order_id;
                                                         }
                                                     }
                                                 }
                                             }
                                         }
                                     }
                                 }
                             }
                         }
                     }
                 }
             }
         }
     }
     return $order_ids;
 }
 /**
  * Calculate the timestamp for the next payment
  *
  * @param WC_Order  $order
  * @param int       $product_id
  *
  * @return mixed|void
  */
 private static function calculate_next_payment_timestamp($order, $product_id)
 {
     $type = 'timestamp';
     $from_date = '';
     $from_date_arg = $from_date;
     $subscription = WC_Subscriptions_Manager::get_subscription(WC_Subscriptions_Manager::get_subscription_key($order->id, $product_id));
     $subscription_period = WC_Subscriptions_Order::get_subscription_period($order, $product_id);
     $subscription_interval = WC_Subscriptions_Order::get_subscription_interval($order, $product_id);
     $subscription_trial_length = WC_Subscriptions_Order::get_subscription_trial_length($order, $product_id);
     $subscription_trial_period = WC_Subscriptions_Order::get_subscription_trial_period($order, $product_id);
     $trial_end_time = !empty($subscription['trial_expiry_date']) ? $subscription['trial_expiry_date'] : WC_Subscriptions_Product::get_trial_expiration_date($product_id, get_gmt_from_date($order->order_date));
     $trial_end_time = strtotime($trial_end_time);
     // If the subscription has a free trial period, and we're still in the free trial period, the next payment is due at the end of the free trial
     if ($subscription_trial_length > 0 && $trial_end_time > gmdate('U') + 60 * 60 * 23 + 120) {
         // Make sure trial expiry is more than 23+ hours in the future to account for trial expiration dates incorrectly stored in non-UTC/GMT timezone (and also for any potential changes to the site's timezone)
         $next_payment_timestamp = $trial_end_time;
         // The next payment date is {interval} billing periods from the from date
     } else {
         // We have a timestamp
         if (!empty($from_date) && is_numeric($from_date)) {
             $from_date = date('Y-m-d H:i:s', $from_date);
         }
         if (empty($from_date)) {
             if (!empty($subscription['completed_payments'])) {
                 $from_date = array_pop($subscription['completed_payments']);
                 $add_failed_payments = true;
             } else {
                 if (!empty($subscription['start_date'])) {
                     $from_date = $subscription['start_date'];
                     $add_failed_payments = true;
                 } else {
                     $from_date = gmdate('Y-m-d H:i:s');
                     $add_failed_payments = false;
                 }
             }
             $failed_payment_count = WC_Subscriptions_Order::get_failed_payment_count($order, $product_id);
             // Maybe take into account any failed payments
             if (true === $add_failed_payments && $failed_payment_count > 0) {
                 $failed_payment_periods = $failed_payment_count * $subscription_interval;
                 $from_timestamp = strtotime($from_date);
                 if ('month' == $subscription_period) {
                     $from_date = date('Y-m-d H:i:s', WC_Subscriptions::add_months($from_timestamp, $failed_payment_periods));
                 } else {
                     // Safe to just add the billing periods
                     $from_date = date('Y-m-d H:i:s', strtotime("+ {$failed_payment_periods} {$subscription_period}", $from_timestamp));
                 }
             }
         }
         $from_timestamp = strtotime($from_date);
         if ('month' == $subscription_period) {
             // Workaround potential PHP issue
             $next_payment_timestamp = WC_Subscriptions::add_months($from_timestamp, $subscription_interval);
         } else {
             $next_payment_timestamp = strtotime("+ {$subscription_interval} {$subscription_period}", $from_timestamp);
         }
         // Make sure the next payment is in the future
         $i = 1;
         while ($next_payment_timestamp < gmdate('U') && $i < 30) {
             if ('month' == $subscription_period) {
                 $next_payment_timestamp = WC_Subscriptions::add_months($next_payment_timestamp, $subscription_interval);
             } else {
                 // Safe to just add the billing periods
                 $next_payment_timestamp = strtotime("+ {$subscription_interval} {$subscription_period}", $next_payment_timestamp);
             }
             $i = $i + 1;
         }
     }
     // If the subscription has an expiry date and the next billing period comes after the expiration, return 0
     if (isset($subscription['expiry_date']) && 0 != $subscription['expiry_date'] && $next_payment_timestamp + 120 > strtotime($subscription['expiry_date'])) {
         $next_payment_timestamp = 0;
     }
     $next_payment = 'mysql' == $type && 0 != $next_payment_timestamp ? date('Y-m-d H:i:s', $next_payment_timestamp) : $next_payment_timestamp;
     return apply_filters('woocommerce_subscriptions_calculated_next_payment_date', $next_payment, $order, $product_id, $type, $from_date, $from_date_arg);
 }
 /**
  * Records the initial payment against a subscription. 
  *
  * This function is called when a gateway calls @see WC_Order::payment_complete() and payment
  * is completed on an order. It is also called when an orders status is changed to completed or
  * processing for those gateways which never call @see WC_Order::payment_complete(), like the 
  * core WooCommerce Cheque and Bank Transfer gateways.
  *
  * @param $order WC_Order | int A WC_Order object or ID of a WC_Order order.
  * @since 1.1.2
  */
 public static function maybe_record_order_payment($order)
 {
     if (!is_object($order)) {
         $order = new WC_Order($order);
     }
     $subscriptions_in_order = self::get_recurring_items($order);
     foreach ($subscriptions_in_order as $subscription_item) {
         $subscription_key = WC_Subscriptions_Manager::get_subscription_key($order->id, $subscription_item['id']);
         $subscription = WC_Subscriptions_Manager::get_subscription($subscription_key, $order->customer_user);
         // No payments have been recorded yet
         if (empty($subscription['completed_payments'])) {
             // Don't duplicate orders
             remove_action('processed_subscription_payment', 'WC_Subscriptions_Renewal_Order::generate_paid_renewal_order', 10, 2);
             WC_Subscriptions_Manager::process_subscription_payments_on_order($order->id);
             WC_Subscriptions_Manager::safeguard_scheduled_payments($order->customer_user, $subscription_key);
             // Make sure orders are still generated for other payments in the same request
             add_action('processed_subscription_payment', 'WC_Subscriptions_Renewal_Order::generate_paid_renewal_order', 10, 2);
         }
     }
 }
 /**
  * Override the default PayPal standard args in WooCommerce for subscription purchases.
  *
  * Based on the HTML Variables documented here: https://developer.paypal.com/webapps/developer/docs/classic/paypal-payments-standard/integration-guide/Appx_websitestandard_htmlvariables/#id08A6HI00JQU
  *
  * @since 1.0
  */
 public static function paypal_standard_subscription_args($paypal_args)
 {
     extract(self::get_order_id_and_key($paypal_args));
     if (WC_Subscriptions_Order::order_contains_subscription($order_id) && 'yes' !== get_option(WC_Subscriptions_Admin::$option_prefix . '_turn_off_automatic_payments', 'no')) {
         $order = new WC_Order($order_id);
         $order_items = $order->get_items();
         // Only one subscription allowed in the cart when PayPal Standard is active
         $product = $order->get_product_from_item(array_pop($order_items));
         // It's a subscription
         $paypal_args['cmd'] = '_xclick-subscriptions';
         if (count($order->get_items()) > 1) {
             foreach ($order->get_items() as $item) {
                 if ($item['qty'] > 1) {
                     $item_names[] = $item['qty'] . ' x ' . $item['name'];
                 } else {
                     if ($item['qty'] > 0) {
                         $item_names[] = $item['name'];
                     }
                 }
             }
             $paypal_args['item_name'] = sprintf(__('Order %s', WC_Subscriptions::$text_domain), $order->get_order_number());
         } else {
             $paypal_args['item_name'] = $product->get_title();
         }
         $unconverted_periods = array('billing_period' => WC_Subscriptions_Order::get_subscription_period($order), 'trial_period' => WC_Subscriptions_Order::get_subscription_trial_period($order));
         $converted_periods = array();
         // Convert period strings into PayPay's format
         foreach ($unconverted_periods as $key => $period) {
             switch (strtolower($period)) {
                 case 'day':
                     $converted_periods[$key] = 'D';
                     break;
                 case 'week':
                     $converted_periods[$key] = 'W';
                     break;
                 case 'year':
                     $converted_periods[$key] = 'Y';
                     break;
                 case 'month':
                 default:
                     $converted_periods[$key] = 'M';
                     break;
             }
         }
         $price_per_period = WC_Subscriptions_Order::get_recurring_total($order);
         $subscription_interval = WC_Subscriptions_Order::get_subscription_interval($order);
         $subscription_length = WC_Subscriptions_Order::get_subscription_length($order);
         $subscription_installments = $subscription_length / $subscription_interval;
         $is_payment_change = WC_Subscriptions_Change_Payment_Gateway::$is_request_to_change_payment;
         $is_switch_order = WC_Subscriptions_Switcher::order_contains_subscription_switch($order->id);
         $sign_up_fee = $is_payment_change ? 0 : WC_Subscriptions_Order::get_sign_up_fee($order);
         $initial_payment = $is_payment_change ? 0 : WC_Subscriptions_Order::get_total_initial_payment($order);
         if ($is_payment_change) {
             // Add a nonce to the order ID to avoid "This invoice has already been paid" error when changing payment method to PayPal when it was previously PayPal
             $paypal_args['invoice'] = $paypal_args['invoice'] . '-wcscpm-' . wp_create_nonce();
             // Set a flag on the order if changing from PayPal *to* PayPal to prevent incorrectly cancelling the subscription
             if ('paypal' == $order->recurring_payment_method) {
                 add_post_meta($order_id, '_wcs_changing_payment_from_paypal_to_paypal', 'true', true);
             }
         }
         // If we're changing the payment date or switching subs, we need to set the trial period to the next payment date & installments to be the number of installments left
         if ($is_payment_change || $is_switch_order) {
             $subscription_key = WC_Subscriptions_Manager::get_subscription_key($order_id, $product->id);
             // Give a free trial until the next payment date
             $next_payment_timestamp = WC_Subscriptions_Manager::get_next_payment_date($subscription_key, $order->user_id, 'timestamp');
             // When the subscription is on hold
             if ($next_payment_timestamp != false) {
                 $trial_until = self::calculate_trial_periods_until($next_payment_timestamp);
                 $subscription_trial_length = $trial_until['first_trial_length'];
                 $converted_periods['trial_period'] = $trial_until['first_trial_period'];
                 $second_trial_length = $trial_until['second_trial_length'];
                 $second_trial_period = $trial_until['second_trial_period'];
             }
             // If is a payment change, we need to account for completed payments on the number of installments owing
             if ($is_payment_change && $subscription_length > 0) {
                 $subscription_installments -= WC_Subscriptions_Manager::get_subscriptions_completed_payment_count($subscription_key);
             }
         } else {
             $subscription_trial_length = WC_Subscriptions_Order::get_subscription_trial_length($order);
         }
         if ($subscription_trial_length > 0) {
             // Specify a free trial period
             if ($is_switch_order) {
                 $paypal_args['a1'] = $initial_payment > 0 ? $initial_payment : 0;
             } else {
                 $paypal_args['a1'] = $sign_up_fee > 0 ? $sign_up_fee : 0;
             }
             // Maybe add the sign up fee to the free trial period
             // Trial period length
             $paypal_args['p1'] = $subscription_trial_length;
             // Trial period
             $paypal_args['t1'] = $converted_periods['trial_period'];
             // We need to use a second trial period before we have more than 90 days until the next payment
             if (WC_Subscriptions_Change_Payment_Gateway::$is_request_to_change_payment && $second_trial_length > 0) {
                 $paypal_args['a2'] = 0;
                 $paypal_args['p2'] = $second_trial_length;
                 $paypal_args['t2'] = $second_trial_period;
             }
         } elseif ($sign_up_fee > 0 || $initial_payment !== $price_per_period) {
             // No trial period, so charge sign up fee and per period price for the first period
             if ($subscription_installments == 1) {
                 $param_number = 3;
             } else {
                 $param_number = 1;
             }
             $paypal_args['a' . $param_number] = $initial_payment;
             // Sign Up interval
             $paypal_args['p' . $param_number] = $subscription_interval;
             // Sign Up unit of duration
             $paypal_args['t' . $param_number] = $converted_periods['billing_period'];
         }
         // We have a recurring payment
         if (!isset($param_number) || $param_number == 1) {
             // Subscription price
             $paypal_args['a3'] = $price_per_period;
             // Subscription duration
             $paypal_args['p3'] = $subscription_interval;
             // Subscription period
             $paypal_args['t3'] = $converted_periods['billing_period'];
         }
         // Recurring payments
         if ($subscription_installments == 1 || $sign_up_fee > 0 && $subscription_trial_length == 0 && $subscription_installments == 2) {
             // Non-recurring payments
             $paypal_args['src'] = 0;
         } else {
             $paypal_args['src'] = 1;
             if ($subscription_installments > 0) {
                 if ($sign_up_fee > 0 && $subscription_trial_length == 0) {
                     // An initial period is being used to charge a sign-up fee
                     $subscription_installments--;
                 }
                 $paypal_args['srt'] = $subscription_installments;
             }
         }
         // Don't reattempt failed payments, instead let Subscriptions handle the failed payment
         $paypal_args['sra'] = 0;
         // Force return URL so that order description & instructions display
         $paypal_args['rm'] = 2;
     }
     return $paypal_args;
 }
 /**
  * Checks if a user (by email) has bought an item.
  * @access public
  * @since  1.0.0
  * @param  string $customer_email
  * @param  int $user_id
  * @param  int $product_id
  * @return bool
  */
 public static function sensei_customer_bought_product($customer_email, $user_id, $product_id)
 {
     global $wpdb;
     $emails = array();
     if ($user_id) {
         $user = get_user_by('id', intval($user_id));
         $emails[] = $user->user_email;
     }
     if (is_email($customer_email)) {
         $emails[] = $customer_email;
     }
     if (sizeof($emails) == 0) {
         return false;
     }
     $orders = get_posts(array('posts_per_page' => -1, 'meta_key' => '_customer_user', 'meta_value' => intval($user_id), 'post_type' => 'shop_order', 'post_status' => array('wc-processing', 'wc-completed')));
     foreach ($orders as $order_id) {
         $order = new WC_Order($order_id->ID);
         if ($order->post_status == 'wc-completed') {
             if (0 < sizeof($order->get_items())) {
                 foreach ($order->get_items() as $item) {
                     // Allow product ID to be filtered
                     $product_id = apply_filters('sensei_bought_product_id', $product_id, $order);
                     // Check if user has bought product
                     if ($item['product_id'] == $product_id || $item['variation_id'] == $product_id) {
                         // Check if user has an active subscription for product
                         if (class_exists('WC_Subscriptions_Manager')) {
                             $sub_key = WC_Subscriptions_Manager::get_subscription_key($order_id->ID, $product_id);
                             if ($sub_key) {
                                 $sub = WC_Subscriptions_Manager::get_subscription($sub_key);
                                 if ($sub && isset($sub['status'])) {
                                     if ('active' == $sub['status']) {
                                         return true;
                                     } else {
                                         return false;
                                     }
                                 }
                             }
                         }
                         // Customer has bought product
                         return true;
                     }
                     // End If Statement
                 }
                 // End For Loop
             }
             // End If Statement
         }
         // End If Statement
     }
     // End For Loop
 }
 /**
  * Make sure when calculating the first payment date for a switched subscription, the date takes into
  * account the switch (i.e. prepaid days and possibly a downgrade).
  *
  * @since 1.4
  * @deprecated 2.0
  */
 public static function calculate_first_payment_date($next_payment_date, $order, $product_id, $type)
 {
     _deprecated_function(__METHOD__, '2.0');
     return self::get_first_payment_date($next_payment_date, WC_Subscriptions_Manager::get_subscription_key($order->id, $product_id), $order->user_id, $type);
 }
 /**
  * Operaciones sucesivas
  * */
 function scheduled_subscription_payment($amount_to_charge, $order, $product_id)
 {
     $this->write_log('scheduled_subscription_payment: ' . $amount_to_charge . '€ ' . $order->id);
     $client = $this->get_client();
     // Obtenemos el numero de pago de la suscripcion
     $subscription_key = WC_Subscriptions_Manager::get_subscription_key($order->id, $product_id);
     $num_pago = WC_Subscriptions_Manager::get_subscriptions_completed_payment_count($subscription_key);
     $paytpv_order_ref = $order->id . "_" . $num_pago;
     $importe = number_format($amount_to_charge * 100, 0, '.', '');
     // Obtenemos el terminal para el pedido
     $arrTerminalData = $this->TerminalCurrency($order);
     $currency_iso_code = $arrTerminalData["currency_iso_code"];
     $term = $arrTerminalData["term"];
     $pass = $arrTerminalData["pass"];
     $payptv_iduser = get_post_meta((int) $order->id, 'PayTPV_IdUser', true);
     $payptv_tokenuser = get_post_meta((int) $order->id, 'PayTPV_TokenUser', true);
     $result = $client->execute_purchase($order, $payptv_iduser, $payptv_tokenuser, $term, $pass, $currency_iso_code, $importe, $paytpv_order_ref);
     if ((int) $result['DS_RESPONSE'] == 1) {
         update_post_meta($order->id, 'PayTPV_Referencia', $result['DS_MERCHANT_ORDER']);
         update_post_meta($order->id, '_transaction_id', $result['DS_MERCHANT_AUTHCODE']);
         WC_Subscriptions_Manager::process_subscription_payments_on_order($order);
     }
 }
 /**
  * Checks if an order contains an in active subscription and if it does, denies download acces
  * to files purchased on the order.
  *
  * @return bool False if the order contains a subscription that has expired or is cancelled/on-hold, otherwise, the original value of $download_permitted
  * @since 1.3
  */
 public static function is_download_permitted($download_permitted, $order)
 {
     if (self::order_contains_subscription($order)) {
         foreach (self::get_recurring_items($order) as $order_item) {
             $subscription_key = WC_Subscriptions_Manager::get_subscription_key($order->id, self::get_items_product_id($order_item));
             $subscription = WC_Subscriptions_Manager::get_subscription($subscription_key);
             if (!isset($subscription['status']) || 'active' !== $subscription['status']) {
                 $download_permitted = false;
                 break;
             }
         }
     }
     return $download_permitted;
 }
示例#22
0
 /**
  * Checks if a user has bought a product item.
  *
  * @since  1.9.0
  *
  * @param  int $user_id
  * @param  int $product_id
  *
  * @return bool
  */
 public static function has_customer_bought_product($user_id, $product_id)
 {
     $orders = get_posts(array('posts_per_page' => -1, 'meta_key' => '_customer_user', 'meta_value' => intval($user_id), 'post_type' => 'shop_order', 'post_status' => array('wc-processing', 'wc-completed')));
     foreach ($orders as $order_id) {
         $order = new WC_Order($order_id->ID);
         if ($order->post_status != 'wc-completed' && $order->post_status != 'wc-processing') {
             continue;
         }
         if (!(0 < sizeof($order->get_items()))) {
             continue;
         }
         foreach ($order->get_items() as $item) {
             // Check if user has bought product
             if ($item['product_id'] == $product_id || $item['variation_id'] == $product_id) {
                 // Check if user has an active subscription for product
                 if (class_exists('WC_Subscriptions_Manager')) {
                     $sub_key = WC_Subscriptions_Manager::get_subscription_key($order_id->ID, $product_id);
                     if ($sub_key) {
                         $sub = WC_Subscriptions_Manager::get_subscription($sub_key);
                         if ($sub && isset($sub['status'])) {
                             if ('active' == $sub['status']) {
                                 return true;
                             } else {
                                 return false;
                             }
                         }
                     }
                 }
                 // Customer has bought product
                 return true;
             }
             // End If Statement
         }
         // End For each item
     }
     // End For each order
 }
 /**
  * Make sure when calculating the first payment date for a switched subscription, the date takes into
  * account the switch (i.e. prepaid days and possibly a downgrade).
  *
  * @since 1.4
  */
 public static function calculate_first_payment_date($next_payment_date, $order, $product_id, $type)
 {
     return self::get_first_payment_date($next_payment_date, WC_Subscriptions_Manager::get_subscription_key($order->id, $product_id), $order->user_id, $type);
 }
 /**
  * In typical PayPal style, there are a couple of important limitations we need to work around:
  *
  * 1. PayPal does not support subscriptions with a $0 recurring total. As a result, we treat it
  * as a normal purchase and then handle the subscription renewals here.
  *
  * 2. PayPal make no guarantee about when a recurring payment will be charged. This creates issues for
  * suspending a subscription until the payment is processed. Specifically, if PayPal processed a payment
  * *before* it was due, we can't suspend the subscription when it is due because it will remain suspended
  * until the next payment. As a result, subscriptions for PayPal are not suspended. However, if there was
  * an issue with the subscription sign-up or payment that was not correctly reported to the store, then the
  * subscription would remain active. No renewal order would be generated, because no payments are completed,
  * so physical subscriptions would not be affected, however, subscriptions to digital goods would be affected.
  *
  * @since 1.4.3
  */
 public static function scheduled_subscription_payment($amount_to_charge, $order, $product_id)
 {
     $hook_args = array('subscription_key' => WC_Subscriptions_Manager::get_subscription_key($order->id, $product_id));
     $one_day_from_now = gmdate('U') + 60 * 60 * 24;
     wc_schedule_single_action($one_day_from_now, 'paypal_check_subscription_payment', $hook_args);
 }
 private function processSubscriptions()
 {
     global $wpdb;
     // check wether subscriptions addon is activated
     if (class_exists('WC_Subscriptions_Order') && WC_Subscriptions_Order::order_contains_subscription($this->order)) {
         $products = $this->order->get_items();
         foreach ($products as $product) {
             if (is_array($product) && isset($product['product_id']) && intval($product['product_id']) > 0 && isset($product['subscription_period']) && $product['subscription_period'] != '') {
                 // product is a subscription?
                 $woo_sub_key = WC_Subscriptions_Manager::get_subscription_key($this->order_id, $product['product_id']);
                 // required vars
                 $amount = floatval(WC_Subscriptions_Order::get_recurring_total($this->order)) * 100;
                 $currency = get_woocommerce_currency();
                 $interval = intval($product['subscription_interval']);
                 $period = strtoupper($product['subscription_period']);
                 $length = strtoupper($product['subscription_length']);
                 if ($length > 0) {
                     $periodOfValidity = $length . ' ' . $period;
                 } else {
                     $periodOfValidity = false;
                 }
                 $trial_end = strtotime(WC_Subscriptions_Product::get_trial_expiration_date($product['product_id'], get_gmt_from_date($this->order->order_date)));
                 if ($trial_end === false) {
                     $trial_time = 0;
                 } else {
                     $datediff = $trial_end - time();
                     $trial_time = ceil($datediff / (60 * 60 * 24));
                 }
                 // md5 name
                 $woo_sub_md5 = md5($amount . $currency . $interval . $trial_time);
                 // get offer
                 $name = 'woo_' . $product['product_id'] . '_' . $woo_sub_md5;
                 $offer = $this->subscriptions->offerGetDetailByName($name);
                 // check wether offer exists in paymill
                 if ($offer === false) {
                     // offer does not exist in paymill yet, create it
                     $params = array('amount' => $amount, 'currency' => $currency, 'interval' => $interval . ' ' . $period, 'name' => $name, 'trial_period_days' => intval($trial_time));
                     $offer = $this->subscriptions->offerCreate($params);
                     if ($GLOBALS['paymill_loader']->paymill_errors->status()) {
                         $GLOBALS['paymill_loader']->paymill_errors->getErrors();
                         return false;
                     }
                 }
                 // create user subscription
                 $user_sub = $this->subscriptions->create($this->clientClass->getCurrentClientID(), $offer, $this->paymentClass->getPaymentID(), isset($_POST['paymill_delivery_date']) ? $_POST['paymill_delivery_date'] : false, $periodOfValidity);
                 if ($GLOBALS['paymill_loader']->paymill_errors->status()) {
                     //maybe offer cache is outdated, recache and try again
                     $GLOBALS['paymill_loader']->paymill_errors->reset();
                     // reset error status
                     $this->subscriptions->offerGetList(true);
                     $params = array('amount' => $amount, 'currency' => $currency, 'interval' => $interval . ' ' . $period, 'name' => $name, 'trial_period_days' => intval($trial_time));
                     $offer = $this->subscriptions->offerCreate($params);
                     if ($GLOBALS['paymill_loader']->paymill_errors->status()) {
                         $GLOBALS['paymill_loader']->paymill_errors->getErrors();
                         return false;
                     }
                     $user_sub = $this->subscriptions->create($this->clientClass->getCurrentClientID(), $offer, $this->paymentClass->getPaymentID(), isset($_POST['paymill_delivery_date']) ? $_POST['paymill_delivery_date'] : false, $periodOfValidity);
                     if ($GLOBALS['paymill_loader']->paymill_errors->status()) {
                         $GLOBALS['paymill_loader']->paymill_errors->getErrors();
                         return false;
                     }
                 }
                 $wpdb->query($wpdb->prepare('INSERT INTO ' . $wpdb->prefix . 'paymill_subscriptions (paymill_sub_id, woo_user_id, woo_offer_id) VALUES (%s, %s, %s)', array($user_sub, get_current_user_id(), $woo_sub_key)));
                 // subscription successful
                 do_action('paymill_woocommerce_subscription_created', array('product_id' => $product['product_id'], 'offer_id' => $offer));
                 return true;
             }
         }
     } else {
         return true;
     }
 }
 /**
  * @param WC_Order $order
  */
 public function payment_failed_for_order($order)
 {
     if (1 == get_option('fue_subscription_failure_notification', 0)) {
         // notification enabled
         $emails_string = get_option('fue_subscription_failure_notification_emails', '');
         if (empty($emails_string)) {
             return;
         }
         // get the product id to get the subscription string
         $order_items = WC_Subscriptions_Order::get_recurring_items($order);
         $first_order_item = reset($order_items);
         $product_id = WC_Subscriptions_Order::get_items_product_id($first_order_item);
         $subs_key = WC_Subscriptions_Manager::get_subscription_key($order->id, $product_id);
         $subject = sprintf(__('Subscription payment failed for Order %s'), $order->get_order_number());
         $message = sprintf(__('A subscription payment for the order %s has failed. The subscription has now been automatically put on hold.'), $order->get_order_number());
         $recipients = array();
         if (strpos($emails_string, ',') !== false) {
             $recipients = array_map('trim', explode(',', $emails_string));
         } else {
             $recipients = array($emails_string);
         }
         foreach ($recipients as $email) {
             FUE::mail($email, $subject, $message);
         }
     }
 }
 /**
  * Once payment is completed on an order, set a lock on payments until the next subscription payment period.
  * 
  * @param $user_id int The id of the user who purchased the subscription
  * @param $subscription_key string A subscription key of the form created by @see self::get_subscription_key()
  * @since 1.1.2
  */
 public static function safeguard_scheduled_payments($order_id)
 {
     $order = new WC_Order($order_id);
     $subscription_key = WC_Subscriptions_Manager::get_subscription_key($order_id);
     WC_Subscriptions_Manager::safeguard_scheduled_payments($order->customer_user, $subscription_key);
 }
 /**
  * When a PayPal IPN messaged is received for a subscription transaction, 
  * check the transaction details and 
  *
  * @since 1.0
  */
 public static function process_paypal_ipn_request($transaction_details)
 {
     if (!in_array($transaction_details['txn_type'], array('subscr_signup', 'subscr_payment', 'subscr_cancel', 'subscr_eot', 'subscr_failed', 'subscr_modify'))) {
         return;
     }
     if (empty($transaction_details['custom']) || empty($transaction_details['invoice'])) {
         return;
     }
     // Get the $order_id & $order_key with backward compatibility
     extract(self::get_order_id_and_key($transaction_details));
     $transaction_details['txn_type'] = strtolower($transaction_details['txn_type']);
     if (self::$debug) {
         self::$log->add('paypal', 'Subscription Transaction Type: ' . $transaction_details['txn_type']);
     }
     if (self::$debug) {
         self::$log->add('paypal', 'Subscription transaction details: ' . print_r($transaction_details, true));
     }
     $order = new WC_Order($order_id);
     // We have an invalid $order_id, probably because invoice_prefix has changed since the subscription was first created, so get the
     if (!isset($order->id)) {
         $order_id = function_exists('woocommerce_get_order_id_by_order_key') ? woocommerce_get_order_id_by_order_key($order_key) : $wpdb->get_var("SELECT post_id FROM {$wpdb->prefix}postmeta WHERE meta_key = '_order_key' AND meta_value = '{$order_key}'");
         $order = new WC_Order($order_id);
     }
     if ($order->order_key !== $order_key) {
         if (self::$debug) {
             self::$log->add('paypal', 'Subscription IPN Error: Order Key does not match invoice.');
         }
         return;
     }
     switch ($transaction_details['txn_type']) {
         case 'subscr_signup':
             // Store PayPal Details
             update_post_meta($order_id, 'Payer PayPal address', $transaction_details['payer_email']);
             update_post_meta($order_id, 'Payer PayPal first name', $transaction_details['first_name']);
             update_post_meta($order_id, 'Payer PayPal last name', $transaction_details['last_name']);
             update_post_meta($order_id, 'PayPal Subscriber ID', $transaction_details['subscr_id']);
             // Payment completed
             $order->add_order_note(__('IPN subscription sign up completed.', WC_Subscriptions::$text_domain));
             if (self::$debug) {
                 self::$log->add('paypal', 'IPN subscription sign up completed for order ' . $order_id);
             }
             // When there is a free trial & no initial payment amount, we need to mark the order as paid and activate the subscription
             if (0 == WC_Subscriptions_Order::get_total_initial_payment($order) && WC_Subscriptions_Order::get_subscription_trial_length($order) > 0) {
                 $order->payment_complete();
                 WC_Subscriptions_Manager::activate_subscriptions_for_order($order);
             }
             break;
         case 'subscr_payment':
             if ('completed' == strtolower($transaction_details['payment_status'])) {
                 // Store PayPal Details
                 update_post_meta($order_id, 'PayPal Transaction ID', $transaction_details['txn_id']);
                 update_post_meta($order_id, 'Payer PayPal first name', $transaction_details['first_name']);
                 update_post_meta($order_id, 'Payer PayPal last name', $transaction_details['last_name']);
                 update_post_meta($order_id, 'PayPal Payment type', $transaction_details['payment_type']);
                 // Subscription Payment completed
                 $order->add_order_note(__('IPN subscription payment completed.', WC_Subscriptions::$text_domain));
                 if (self::$debug) {
                     self::$log->add('paypal', 'IPN subscription payment completed for order ' . $order_id);
                 }
                 $subscriptions_in_order = WC_Subscriptions_Order::get_recurring_items($order);
                 $subscription_item = array_pop($subscriptions_in_order);
                 $subscription_key = WC_Subscriptions_Manager::get_subscription_key($order->id, $subscription_item['id']);
                 $subscription = WC_Subscriptions_Manager::get_subscription($subscription_key, $order->customer_user);
                 // First payment on order, process payment & activate subscription
                 if (empty($subscription['completed_payments'])) {
                     $order->payment_complete();
                     WC_Subscriptions_Manager::activate_subscriptions_for_order($order);
                 } else {
                     WC_Subscriptions_Manager::process_subscription_payments_on_order($order);
                 }
             } elseif ('failed' == strtolower($transaction_details['payment_status'])) {
                 // Subscription Payment completed
                 $order->add_order_note(__('IPN subscription payment failed.', WC_Subscriptions::$text_domain));
                 if (self::$debug) {
                     self::$log->add('paypal', 'IPN subscription payment failed for order ' . $order_id);
                 }
                 WC_Subscriptions_Manager::process_subscription_payment_failure_on_order($order);
             } else {
                 if (self::$debug) {
                     self::$log->add('paypal', 'IPN subscription payment notification received for order ' . $order_id . ' with status ' . $transaction_details['payment_status']);
                 }
             }
             break;
         case 'subscr_cancel':
             if (self::$debug) {
                 self::$log->add('paypal', 'IPN subscription cancelled for order ' . $order_id);
             }
             // Subscription Payment completed
             $order->add_order_note(__('IPN subscription cancelled for order.', WC_Subscriptions::$text_domain));
             WC_Subscriptions_Manager::cancel_subscriptions_for_order($order);
             break;
         case 'subscr_eot':
             // Subscription ended, either due to failed payments or expiration
             // PayPal fires the 'subscr_eot' notice immediately if a subscription is only for one billing period, so ignore the request when we only have one billing period
             if (1 != WC_Subscriptions_Order::get_subscription_length($order)) {
                 if (self::$debug) {
                     self::$log->add('paypal', 'IPN subscription end-of-term for order ' . $order_id);
                 }
                 // Record subscription ended
                 $order->add_order_note(__('IPN subscription end-of-term for order.', WC_Subscriptions::$text_domain));
                 // Ended due to failed payments so cancel the subscription
                 if (time() < strtotime(WC_Subscriptions_Manager::get_subscription_expiration_date(WC_Subscriptions_Manager::get_subscription_key($order->id), $order->customer_user))) {
                     WC_Subscriptions_Manager::cancel_subscriptions_for_order($order);
                 } else {
                     WC_Subscriptions_Manager::expire_subscriptions_for_order($order);
                 }
             }
             break;
         case 'subscr_failed':
             // Subscription sign up failed
             if (self::$debug) {
                 self::$log->add('paypal', 'IPN subscription sign up failure for order ' . $order_id);
             }
             // Subscription Payment completed
             $order->add_order_note(__('IPN subscription sign up failure.', WC_Subscriptions::$text_domain));
             WC_Subscriptions_Manager::failed_subscription_sign_ups_for_order($order);
             break;
     }
     // Prevent default IPN handling for subscription txn_types
     exit;
 }