/**
  * trigger function.
  *
  * @access public
  * @return void
  */
 function trigger($subscription_key)
 {
     global $woocommerce;
     $this->subscription_key = $subscription_key;
     $this->object = WC_Subscriptions_Manager::get_subscription($subscription_key);
     if (!$this->is_enabled() || !$this->get_recipient()) {
         return;
     }
     $this->send($this->get_recipient(), $this->get_subject(), $this->get_content(), $this->get_headers(), $this->get_attachments());
 }
 /**
  * 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_subscription($subscription_key);
         if (empty($subscription) || !in_array($subscription['status'], array('on-hold', 'pending'))) {
             unset($actions['pay']);
         }
     }
     return $actions;
 }
예제 #3
0
 function wc_subs_exporter_get_filtered_subscriptions($export)
 {
     global $wpdb;
     $subscriptions = $filtered_subscriptions = array();
     $sql = "SELECT DISTINCT i.order_id, m.product_id, p.meta_value\n\t\t\t\tFROM\n\t\t\t\t(\n\t\t\t\tSELECT order_item_id,\n\t\t\t\tMAX(CASE WHEN meta_key = '_product_id' THEN meta_value END) product_id\n\t\t\t\tFROM {$wpdb->prefix}woocommerce_order_itemmeta\n\t\t\t\tWHERE meta_key LIKE '_subscription%' \n\t\t\t\t\tOR meta_key LIKE '_recurring%'\n\t\t\t\t\tOR meta_key = '_product_id'\n\t\t\t\tGROUP BY order_item_id\n\t\t\t\tHAVING MAX(meta_key LIKE '_subscription%')\n\t\t\t\t\t+ MAX(meta_key LIKE '_recurring%') > 0\n\t\t\t\t) m JOIN {$wpdb->prefix}woocommerce_order_items i \n\t\t\t\tON m.order_item_id = i.order_item_id \n\t\t\t\tLEFT JOIN {$wpdb->prefix}postmeta p \n\t\t\t\tON i.order_id = p.post_id \n\t\t\t\tAND p.meta_key = '_customer_user'\n\t\t\t\tLEFT JOIN {$wpdb->prefix}posts po \n\t\t\t\tON p.post_id = po.ID\n\t\t\t\tWHERE po.post_type = 'shop_order' AND po.post_parent = 0";
     $order_ids_and_product_ids = $wpdb->get_results($sql);
     foreach ($order_ids_and_product_ids as $order_id_and_product_id) {
         if (empty($order_id_and_product_id->product_id)) {
             continue;
         }
         $subscription_key = $order_id_and_product_id->order_id . '_' . $order_id_and_product_id->product_id;
         $subscription = WC_Subscriptions_Manager::get_subscription($subscription_key);
         if (empty($subscription)) {
             continue;
         }
         // filter status
         if (!array_key_exists($subscription['status'], $export->status)) {
             continue;
         }
         // filter dates
         if ($export->dates_from && strtotime($subscription['start_date']) < strtotime($export->dates_from)) {
             continue;
         } elseif ($export->dates_to && strtotime($subscription['start_date']) > strtotime($export->dates_to)) {
             continue;
         }
         $subscriptions[$order_id_and_product_id->meta_value][$subscription_key] = $subscription;
     }
     $processed_rows = 0;
     foreach ($subscriptions as $user => $user_subscriptions) {
         if (++$processed_rows <= $export->offset) {
             continue;
         }
         foreach ($user_subscriptions as $key => $subscription) {
             $filtered_subscriptions[$user][$key] = $subscription;
         }
         if ($processed_rows == $export->limit_volume) {
             break;
         }
     }
     return $filtered_subscriptions;
 }
 /**
  * If requesting a payment method change, replace the woocommerce_pay_shortcode() with a change payment form.
  *
  * @since 1.4
  */
 public static function maybe_replace_pay_shortcode()
 {
     global $woocommerce;
     if (!self::$is_request_to_change_payment) {
         return;
     }
     ob_clean();
     do_action('before_woocommerce_pay');
     echo '<div class="woocommerce">';
     if (!empty(self::$woocommerce_errors)) {
         foreach (self::$woocommerce_errors as $error) {
             WC_Subscriptions::add_notice($error, 'error');
         }
     }
     if (!empty(self::$woocommerce_messages)) {
         foreach (self::$woocommerce_messages as $message) {
             WC_Subscriptions::add_notice($message, 'success');
         }
     }
     $subscription_key = $_GET['change_payment_method'];
     $subscription = WC_Subscriptions_Manager::get_subscription($subscription_key);
     if (wp_verify_nonce($_GET['_wpnonce'], __FILE__) === false) {
         WC_Subscriptions::add_notice(__('There was an error with your request. Please try again.', 'woocommerce-subscriptions'), 'error');
         WC_Subscriptions::print_notices();
     } elseif (!WC_Subscriptions_Manager::user_owns_subscription($subscription_key)) {
         WC_Subscriptions::add_notice(__('That doesn\'t appear to be one of your subscriptions.', 'woocommerce-subscriptions'), 'error');
         WC_Subscriptions::print_notices();
     } elseif (empty($subscription)) {
         WC_Subscriptions::add_notice(__('Invalid subscription.', 'woocommerce-subscriptions'), 'error');
         WC_Subscriptions::print_notices();
     } elseif (!WC_Subscriptions_Manager::can_subscription_be_changed_to('new-payment-method', $subscription_key, get_current_user_id())) {
         WC_Subscriptions::add_notice(__('The payment method can not be changed for that subscription.', 'woocommerce-subscriptions'), 'error');
         WC_Subscriptions::print_notices();
     } else {
         $order = new WC_Order($subscription['order_id']);
         $order_id = absint($_GET['order_id']);
         $order_key = isset($_GET['key']) ? $_GET['key'] : $_GET['order'];
         $product_id = $subscription['product_id'];
         $next_payment_timestamp = WC_Subscriptions_Order::get_next_payment_timestamp($order, $product_id);
         if (!empty($next_payment_timestamp)) {
             $next_payment_string = sprintf(__(' Next payment is due %s.', 'woocommerce-subscriptions'), date_i18n(woocommerce_date_format(), $next_payment_timestamp));
         } else {
             $next_payment_string = '';
         }
         WC_Subscriptions::add_notice(sprintf(__('Choose a new payment method.%s', 'woocommerce-subscriptions'), $next_payment_string), 'notice');
         WC_Subscriptions::print_notices();
         if ($order->order_key == $order_key) {
             // Set customer location to order location
             if ($order->billing_country) {
                 $woocommerce->customer->set_country($order->billing_country);
             }
             if ($order->billing_state) {
                 $woocommerce->customer->set_state($order->billing_state);
             }
             if ($order->billing_postcode) {
                 $woocommerce->customer->set_postcode($order->billing_postcode);
             }
             // Show form
             WC_Subscriptions_Order::$recurring_only_price_strings = true;
             woocommerce_get_template('checkout/form-change-payment-method.php', array('order' => $order, 'subscription_key' => $subscription_key), '', plugin_dir_path(WC_Subscriptions::$plugin_file) . 'templates/');
             WC_Subscriptions_Order::$recurring_only_price_strings = false;
         } else {
             WC_Subscriptions::add_notice(__('Invalid order.', 'woocommerce-subscriptions'), 'error');
             WC_Subscriptions::print_notices();
         }
     }
 }
 /**
  * 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;
 }
 /**
  * Gets all the active and inactive subscriptions for all users.
  *
  * @return array An associative array containing all users with subscriptions and the details of their subscriptions: 'user_id' => $subscriptions
  * @since 1.0
  */
 public static function get_all_users_subscriptions()
 {
     global $wpdb;
     $subscriptions = array();
     $sql = "SELECT DISTINCT i.order_id, m.product_id, p.meta_value\n\t\t\t\tFROM\n\t\t\t\t(\n\t\t\t\tSELECT order_item_id,\n\t\t\t\tMAX(CASE WHEN meta_key = '_product_id' THEN meta_value END) product_id\n\t\t\t\tFROM {$wpdb->prefix}woocommerce_order_itemmeta\n\t\t\t\tWHERE meta_key LIKE '_subscription%' \n\t\t\t\t\tOR meta_key LIKE '_recurring%'\n\t\t\t\t\tOR meta_key = '_product_id'\n\t\t\t\tGROUP BY order_item_id\n\t\t\t\tHAVING MAX(meta_key LIKE '_subscription%')\n\t\t\t\t\t+ MAX(meta_key LIKE '_recurring%') > 0\n\t\t\t\t) m JOIN {$wpdb->prefix}woocommerce_order_items i \n\t\t\t\tON m.order_item_id = i.order_item_id \n\t\t\t\tLEFT JOIN {$wpdb->prefix}postmeta p \n\t\t\t\tON i.order_id = p.post_id \n\t\t\t\tAND p.meta_key = '_customer_user'\n\t\t\t\tLEFT JOIN {$wpdb->prefix}posts po \n\t\t\t\tON p.post_id = po.ID\n\t\t\t\tWHERE po.post_type = 'shop_order' AND po.post_parent = 0";
     $order_ids_and_product_ids = $wpdb->get_results($sql);
     foreach ($order_ids_and_product_ids as $order_id_and_product_id) {
         if (empty($order_id_and_product_id->product_id)) {
             continue;
         }
         $subscription_key = $order_id_and_product_id->order_id . '_' . $order_id_and_product_id->product_id;
         $subscription = WC_Subscriptions_Manager::get_subscription($subscription_key);
         $subscriptions[$order_id_and_product_id->meta_value][$subscription_key] = $subscription;
     }
     return apply_filters('woocommerce_all_users_subscriptions', $subscriptions);
 }
 /**
  * Get the subscription for a membership
  *
  * @since 1.0.0
  * @param int $user_membership_id User Membership ID
  * @return array|null Subscription or null, if not found
  */
 public function get_user_membership_subscription($user_membership_id)
 {
     // 2.0 onwards
     if ($this->is_subscriptions_gte_2_0()) {
         $subscription_id = $this->get_user_membership_subscription_id($user_membership_id);
         if (!$subscription_id) {
             return null;
         }
         return wcs_get_subscription($subscription_id);
     } else {
         $subscription_key = $this->get_user_membership_subscription_key($user_membership_id);
         if (!$subscription_key) {
             return null;
         }
         $user_membership = wc_memberships_get_user_membership($user_membership_id);
         // It seems that the order has been deleted
         if (false === get_post_status($user_membership->get_order_id())) {
             return null;
         }
         // It seems the subscription product has been removed from the order
         if (!WC_Subscriptions_Order::get_item_id_by_subscription_key($subscription_key)) {
             return null;
         }
         return WC_Subscriptions_Manager::get_subscription($subscription_key);
     }
 }
 /**
  * Check if a given subscription can be renewed. 
  *
  * For a subscription to be renewable, it must be inactive (expired or cancelled) and its parent order
  * must not have already been superseded by a renewal order. This last part is mainly just to prevent
  * displaying "Renew" links on subscriptions that have already been renewed.
  *
  * @param $subscription_key string A subscription key of the form created by @see self::get_subscription_key()
  * @param $user_id int The ID of the user who owns the subscriptions. Although this parameter is optional, if you have the User ID you should pass it to improve performance.
  * @since 1.2
  */
 public static function can_subscription_be_renewed($subscription_key, $user_id = '')
 {
     $subscription = WC_Subscriptions_Manager::get_subscription($subscription_key, $user_id);
     if (empty($subscription)) {
         $subscription_can_be_renewed = false;
     } else {
         $renewal_orders = get_posts(array('meta_key' => '_original_order', 'meta_value' => $subscription['order_id'], 'post_type' => 'shop_order', 'post_parent' => 0));
         if (empty($renewal_orders) && in_array($subscription['status'], array('cancelled', 'expired', 'trash', 'failed'))) {
             $subscription_can_be_renewed = true;
         } else {
             $subscription_can_be_renewed = false;
         }
     }
     return apply_filters('woocommerce_can_subscription_be_renewed', $subscription_can_be_renewed, $subscription, $subscription_key, $user_id);
 }
 public function maybe_update_subscription_order_addresses($user_id, $load_address)
 {
     global $woocommerce, $wp;
     if (!WC_Subscriptions_Manager::user_has_subscription($user_id)) {
         return;
     }
     if ($load_address != 'shipping') {
         return;
     }
     $subscription_ids = array();
     if (isset($_POST['update_all_subscriptions_addresses'])) {
         $users_subscriptions = WC_Subscriptions_Manager::get_users_subscriptions($user_id);
         foreach ($users_subscriptions as $subscription) {
             array_push($subscription_ids, $subscription['order_id']);
         }
     } elseif (isset($_POST['update_subscription_address'])) {
         $subscription = WC_Subscriptions_Manager::get_subscription($_POST['update_subscription_address']);
         // Update the address only if the user actually owns the subscription
         if (!empty($subscription)) {
             array_push($subscription_ids, $subscription['order_id']);
         }
     }
     if (count($subscription_ids) > 0) {
         $base_order = $order = wc_get_order($subscription_ids[0]);
         $args = array('numberposts' => -1, 'post_type' => 'shop_order', 'post_status' => 'publish', 'tax_query' => array(array('taxonomy' => 'shop_order_status', 'field' => 'slug', 'terms' => array('processing'))), 'meta_query' => array(array('key' => '_customer_user', 'value' => $user_id), array('key' => '_original_order', 'value' => $subscription_ids)));
         $posts = get_posts($args);
         $address = array('first_name' => $base_order->shipping_first_name, 'last_name' => $base_order->shipping_last_name, 'address_1' => $base_order->shipping_address_1, 'address_2' => $base_order->shipping_address_2, 'city' => $base_order->shipping_city, 'state' => $base_order->shipping_state, 'postcode' => $base_order->shipping_postcode, 'country' => $base_order->shipping_country);
         foreach ($posts as $post) {
             $order = wc_get_order($post->ID);
             $order->set_address($address, 'shipping');
         }
     }
 }
 /**
  * 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
 }
 /**
  * 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);
         }
     }
 }
 /**
  * When a subscriber's billing or shipping address is successfully updated, check if the subscriber
  * has also requested to update the addresses on existing subscriptions and if so, go ahead and update
  * the addresses on the initial order for each subscription.
  *
  * @param int $user_id The ID of a user who own's the subscription (and address)
  * @since 1.3
  */
 public static function maybe_update_subscription_addresses($user_id)
 {
     global $woocommerce;
     if (!WC_Subscriptions_Manager::user_has_subscription($user_id) || !isset($_GET['address'])) {
         return;
     }
     $load_address = isset($_GET['address']) ? esc_attr($_GET['address']) : '';
     $load_address = $load_address == 'billing' || $load_address == 'shipping' ? $load_address : '';
     $address_fields = $woocommerce->countries->get_address_fields(esc_attr($_POST[$load_address . '_country']), $load_address . '_');
     if (isset($_POST['update_all_subscriptions_addresses'])) {
         $users_subscriptions = WC_Subscriptions_Manager::get_users_subscriptions($user_id);
         foreach ($users_subscriptions as $subscription) {
             self::maybe_update_order_address($subscription, $address_fields);
         }
     } elseif (isset($_POST['update_subscription_address'])) {
         $subscription = WC_Subscriptions_Manager::get_subscription($_POST['update_subscription_address']);
         // Update the address only if the user actually owns the subscription
         if (!empty($subscription)) {
             self::maybe_update_order_address($subscription, $address_fields);
         }
     }
 }
예제 #13
0
파일: functions.php 프로젝트: bulats/chef
/**
 * On the scheduled action hook, run the function.
 */
function ps_do_this_daily()
{
    global $wpdb;
    //    if(date('l') == "Saturday") {        // Cron run daily but execute only in sunday
    $allUser = $wpdb->get_results('SELECT * FROM wp_users WHERE 1;');
    //		if(date('l') != "Tuesday" || date('l') != "Wednesday")
    $nxtTues = date_i18n('Ymd', strtotime('next tuesday'));
    // Get the Next Tuesday to run cron
    /*		else 
    			$nxtTues =  date('Ymd', strtotime('next tuesday'));         // Get the Next Tuesday to run cron*/
    //$nxtTues = $nxtTues + 7;
    $wsm = new WC_Subscriptions_Manager();
    foreach ($allUser as $auK => $auV) {
        $userID = $auV->ID;
        $parmanent_cancel_delivery = get_user_meta($userID, 'permanent_pause', true);
        if (empty($parmanent_cancel_delivery)) {
            $susPendedData = get_user_meta($userID, 'suspended', false);
            $cur_user_subscription = get_user_meta($userID, 'wp_woocommerce_subscriptions', true);
            foreach ($cur_user_subscription as $suk => $suv) {
                //$subscriptionID = $suv['order_id'] . '_' . $suv['product_id'];
                $subscriptionID = $suk;
                break;
                /* use because one time subscription */
            }
            if (in_array($nxtTues, $susPendedData)) {
                $wsm->put_subscription_on_hold($userID, $subscriptionID);
            } else {
                $s = WC_Subscriptions_Manager::get_subscription($subscriptionID, $userID);
                if (!empty($s['status']) && $s['status'] == 'on-hold') {
                    $wsm->reactivate_subscription($userID, $subscriptionID);
                }
            }
            wp_mail('*****@*****.**', 'The subject', 'nxtTues=>' . $nxtTues . "susPendedData=>" . json_encode($cur_user_subscription) . "u=>" . $userID);
        }
    }
    //   }
}
 /**
  * Handles the display of builder sections.
  */
 public function get_builder_display($field, $where, $args, $form_prefix = "", $product_id = 0)
 {
     /* $form_prefix	shoud be passed with _ if not empty */
     $columns = array("w25" => array("col-3", 25), "w33" => array("col-4", 33), "w50" => array("col-6", 50), "w66" => array("col-8", 66), "w75" => array("col-9", 75), "w100" => array("col-12", 100));
     extract($args, EXTR_OVERWRITE);
     if (isset($field['sections']) && is_array($field['sections'])) {
         $args = array('field_id' => 'tm-epo-field-' . $unit_counter);
         wc_get_template('tm-builder-start.php', $args, $this->_namespace, $this->template_path);
         $_section_totals = 0;
         foreach ($field['sections'] as $section) {
             if (!isset($section['sections_placement']) || $section['sections_placement'] != $where) {
                 continue;
             }
             if (isset($section['sections_size']) && isset($columns[$section['sections_size']])) {
                 $size = $columns[$section['sections_size']][0];
             } else {
                 $size = "col-12";
             }
             $_section_totals = $_section_totals + $columns[$section['sections_size']][1];
             if ($_section_totals > 100) {
                 $_section_totals = $columns[$section['sections_size']][1];
                 echo '<div class="cpfclear"></div>';
             }
             $divider = "";
             if (isset($section['divider_type'])) {
                 switch ($section['divider_type']) {
                     case "hr":
                         $divider = '<hr>';
                         break;
                     case "divider":
                         $divider = '<div class="tm_divider"></div>';
                         break;
                     case "padding":
                         $divider = '<div class="tm_padding"></div>';
                         break;
                 }
             }
             $label_size = 'h3';
             if (!empty($section['label_size'])) {
                 switch ($section['label_size']) {
                     case "1":
                         $label_size = 'h1';
                         break;
                     case "2":
                         $label_size = 'h2';
                         break;
                     case "3":
                         $label_size = 'h3';
                         break;
                     case "4":
                         $label_size = 'h4';
                         break;
                     case "5":
                         $label_size = 'h5';
                         break;
                     case "6":
                         $label_size = 'h6';
                         break;
                     case "7":
                         $label_size = 'p';
                         break;
                     case "8":
                         $label_size = 'div';
                         break;
                     case "9":
                         $label_size = 'span';
                         break;
                 }
             }
             $args = array('column' => $size, 'style' => $section['sections_style'], 'uniqid' => $section['sections_uniqid'], 'logic' => esc_html(json_encode((array) json_decode($section['sections_clogic']))), 'haslogic' => $section['sections_logic'], 'sections_class' => $section['sections_class'], 'sections_type' => $section['sections_type'], 'title_size' => $label_size, 'title' => !empty($section['label']) ? $section['label'] : "", 'title_color' => !empty($section['label_color']) ? $section['label_color'] : "", 'description' => !empty($section['description']) ? $section['description'] : "", 'description_color' => !empty($section['description_color']) ? $section['description_color'] : "", 'description_position' => !empty($section['description_position']) ? $section['description_position'] : "", 'divider' => $divider);
             // custom variations check
             if (isset($section['elements']) && is_array($section['elements']) && isset($section['elements'][0]) && is_array($section['elements'][0]) && isset($section['elements'][0]['type']) && $section['elements'][0]['type'] == 'variations') {
                 $args['sections_class'] = $args['sections_class'] . " tm-epo-variation-section";
             }
             wc_get_template('tm-builder-section-start.php', $args, $this->_namespace, $this->template_path);
             if (isset($section['elements']) && is_array($section['elements'])) {
                 $totals = 0;
                 $slide_counter = 0;
                 $use_slides = false;
                 $doing_slides = false;
                 if ($section['sections_slides'] !== "" && $section['sections_type'] == "slider") {
                     $sections_slides = explode(",", $section['sections_slides']);
                     $use_slides = true;
                 }
                 foreach ($section['elements'] as $element) {
                     $empty_rules = "";
                     if (isset($element['rules_filtered'])) {
                         $empty_rules = esc_html(json_encode($element['rules_filtered']));
                     }
                     $empty_rules_type = "";
                     if (isset($element['rules_type'])) {
                         $empty_rules_type = esc_html(json_encode($element['rules_type']));
                     }
                     if (isset($element['size']) && isset($columns[$element['size']])) {
                         $size = $columns[$element['size']][0];
                     } else {
                         $size = "col-12";
                     }
                     $test_for_first_slide = false;
                     if ($use_slides && isset($sections_slides[$slide_counter])) {
                         $sections_slides[$slide_counter] = intval($sections_slides[$slide_counter]);
                         if ($sections_slides[$slide_counter] > 0 && !$doing_slides) {
                             echo '<div class="tm-slide">';
                             $doing_slides = true;
                             $test_for_first_slide = true;
                         }
                     }
                     $fee_name = $this->fee_name;
                     $cart_fee_name = $this->cart_fee_name;
                     $totals = $totals + $columns[$element['size']][1];
                     if ($totals > 100 && !$test_for_first_slide) {
                         $totals = $columns[$element['size']][1];
                         echo '<div class="cpfclear"></div>';
                     }
                     $divider = "";
                     if (isset($element['divider_type'])) {
                         $divider_class = "";
                         if ($element['type'] == 'divider' && !empty($element['class'])) {
                             $divider_class = " " . $element['class'];
                         }
                         switch ($element['divider_type']) {
                             case "hr":
                                 $divider = '<hr' . $divider_class . '>';
                                 break;
                             case "divider":
                                 $divider = '<div class="tm_divider' . $divider_class . '"></div>';
                                 break;
                             case "padding":
                                 $divider = '<div class="tm_padding' . $divider_class . '"></div>';
                                 break;
                         }
                     }
                     $label_size = 'h3';
                     if (!empty($element['label_size'])) {
                         switch ($element['label_size']) {
                             case "1":
                                 $label_size = 'h1';
                                 break;
                             case "2":
                                 $label_size = 'h2';
                                 break;
                             case "3":
                                 $label_size = 'h3';
                                 break;
                             case "4":
                                 $label_size = 'h4';
                                 break;
                             case "5":
                                 $label_size = 'h5';
                                 break;
                             case "6":
                                 $label_size = 'h6';
                                 break;
                             case "7":
                                 $label_size = 'p';
                                 break;
                             case "8":
                                 $label_size = 'div';
                                 break;
                             case "9":
                                 $label_size = 'span';
                                 break;
                             case "10":
                                 $label_size = 'label';
                                 break;
                         }
                     }
                     $variations_builder_element_start_args = array();
                     $tm_validation = $this->get_tm_validation_rules($element);
                     $args = array('tm_element_settings' => $element, 'column' => $size, 'class' => !empty($element['class']) ? $element['class'] : "", 'title_size' => $label_size, 'title' => !empty($element['label']) ? $element['label'] : "", 'title_position' => !empty($element['label_position']) ? $element['label_position'] : "", 'title_color' => !empty($element['label_color']) ? $element['label_color'] : "", 'description' => !empty($element['description']) ? $element['description'] : "", 'description_color' => !empty($element['description_color']) ? $element['description_color'] : "", 'description_position' => !empty($element['description_position']) ? $element['description_position'] : "", 'divider' => $divider, 'required' => $element['required'], 'type' => $element['type'], 'use_images' => $element['use_images'], 'use_url' => $element['use_url'], 'rules' => $empty_rules, 'rules_type' => $empty_rules_type, 'element' => $element['type'], 'class_id' => "tm-element-ul-" . $element['type'] . " element_" . $element_counter . $form_prefix, 'uniqid' => $element['uniqid'], 'logic' => esc_html(json_encode((array) json_decode($element['clogic']))), 'haslogic' => $element['logic'], 'clear_options' => empty($element['clear_options']) ? "" : $element['clear_options'], 'exactlimit' => empty($element['exactlimit']) ? "" : 'tm-exactlimit', 'minimumlimit' => empty($element['minimumlimit']) ? "" : 'tm-minimumlimit', 'tm_validation' => esc_html(json_encode($tm_validation)));
                     if ($element['type'] != "variations") {
                         wc_get_template('tm-builder-element-start.php', $args, $this->_namespace, $this->template_path);
                     } else {
                         $variations_builder_element_start_args = $args;
                     }
                     $field_counter = 0;
                     $init_class = "TM_EPO_FIELDS_" . $element['type'];
                     if (!class_exists($init_class) && !empty($this->tm_builder_elements[$element['type']]["_is_addon"])) {
                         $init_class = "TM_EPO_FIELDS";
                     }
                     if (isset($this->tm_builder_elements[$element['type']]) && ($this->tm_builder_elements[$element['type']]["is_post"] == "post" || $this->tm_builder_elements[$element['type']]["is_post"] == "display") && class_exists($init_class)) {
                         $field_obj = new $init_class();
                         if ($this->tm_builder_elements[$element['type']]["is_post"] == "post") {
                             if ($this->tm_builder_elements[$element['type']]["type"] == "single" || $this->tm_builder_elements[$element['type']]["type"] == "multiplesingle") {
                                 $tabindex++;
                                 $name_inc = $this->tm_builder_elements[$element['type']]["post_name_prefix"] . "_" . $element_counter . $form_prefix;
                                 if ($this->tm_builder_elements[$element['type']]["type"] == "single") {
                                     $is_fee = !empty($element['rules_type']) && $element['rules_type'][0][0] == "subscriptionfee";
                                     $is_cart_fee = !empty($element['rules_type']) && isset($element['rules_type'][0]) && isset($element['rules_type'][0][0]) && $element['rules_type'][0][0] == "fee";
                                 } elseif ($this->tm_builder_elements[$element['type']]["type"] == "multiplesingle") {
                                     $is_fee = !empty($element['selectbox_fee']) && $element['selectbox_fee'][0][0] == "subscriptionfee";
                                     $is_cart_fee = !empty($element['selectbox_cart_fee']) && $element['selectbox_cart_fee'][0][0] == "fee";
                                 }
                                 if ($is_fee) {
                                     $name_inc = $fee_name . $name_inc;
                                 } elseif ($is_cart_fee) {
                                     $name_inc = $cart_fee_name . $name_inc;
                                 }
                                 if (isset($_GET['switch-subscription']) && (function_exists('wcs_get_subscription') || class_exists('WC_Subscriptions_Manager') && class_exists('WC_Subscriptions_Order'))) {
                                     $item = false;
                                     if (function_exists('wcs_get_subscription')) {
                                         $subscription = wcs_get_subscription($_GET['switch-subscription']);
                                         if ($subscription instanceof WC_Subscription) {
                                             $original_order = new WC_Order($subscription->order->id);
                                             $item = WC_Subscriptions_Order::get_item_by_product_id($original_order, $subscription->id);
                                         }
                                     } else {
                                         $subscription = WC_Subscriptions_Manager::get_subscription($_GET['switch-subscription']);
                                         $original_order = new WC_Order($subscription['order_id']);
                                         $item = WC_Subscriptions_Order::get_item_by_product_id($original_order, $subscription['product_id']);
                                     }
                                     if ($item) {
                                         $saved_data = maybe_unserialize($item["item_meta"]["_tmcartepo_data"][0]);
                                         foreach ($saved_data as $key => $val) {
                                             if (isset($val["key"])) {
                                                 if ($element['uniqid'] == $val["section"]) {
                                                     $_GET['tmcp_' . $name_inc] = $val["key"];
                                                     if (isset($val['quantity'])) {
                                                         $_GET['tmcp_' . $name_inc . '_quantity'] = $val['quantity'];
                                                     }
                                                 }
                                             } else {
                                                 if ($element['uniqid'] == $val["section"]) {
                                                     $_GET['tmcp_' . $name_inc] = $val["value"];
                                                     if (isset($val['quantity'])) {
                                                         $_GET['tmcp_' . $name_inc . '_quantity'] = $val['quantity'];
                                                     }
                                                 }
                                             }
                                         }
                                     }
                                 } elseif (!empty($this->cart_edit_key) && isset($_GET['_wpnonce']) && wp_verify_nonce($_GET['_wpnonce'], 'tm-edit')) {
                                     $_cart = WC()->cart;
                                     if (isset($_cart->cart_contents) && isset($_cart->cart_contents[$this->cart_edit_key])) {
                                         if (!empty($_cart->cart_contents[$this->cart_edit_key]['tmcartepo'])) {
                                             $saved_epos = $_cart->cart_contents[$this->cart_edit_key]['tmcartepo'];
                                             foreach ($saved_epos as $key => $val) {
                                                 if (isset($val["key"])) {
                                                     if ($element['uniqid'] == $val["section"]) {
                                                         $_GET['tmcp_' . $name_inc] = $val["key"];
                                                         if (isset($val['quantity'])) {
                                                             $_GET['tmcp_' . $name_inc . '_quantity'] = $val['quantity'];
                                                         }
                                                     }
                                                 } else {
                                                     if ($element['uniqid'] == $val["section"]) {
                                                         $_GET['tmcp_' . $name_inc] = $val["value"];
                                                         if (isset($val['quantity'])) {
                                                             $_GET['tmcp_' . $name_inc . '_quantity'] = $val['quantity'];
                                                         }
                                                     }
                                                 }
                                             }
                                         }
                                         if (!empty($_cart->cart_contents[$this->cart_edit_key]['tmcartfee'])) {
                                             $saved_fees = $_cart->cart_contents[$this->cart_edit_key]['tmcartfee'];
                                             foreach ($saved_fees as $key => $val) {
                                                 if (isset($val["key"])) {
                                                     if ($element['uniqid'] == $val["section"]) {
                                                         $_GET['tmcp_' . $name_inc] = $val["key"];
                                                         if (isset($val['quantity'])) {
                                                             $_GET['tmcp_' . $name_inc . '_quantity'] = $val['quantity'];
                                                         }
                                                     }
                                                 } else {
                                                     if ($element['uniqid'] == $val["section"]) {
                                                         $_GET['tmcp_' . $name_inc] = $val["value"];
                                                         if (isset($val['quantity'])) {
                                                             $_GET['tmcp_' . $name_inc . '_quantity'] = $val['quantity'];
                                                         }
                                                     }
                                                 }
                                             }
                                         }
                                         if (!empty($_cart->cart_contents[$this->cart_edit_key]['tmsubscriptionfee'])) {
                                             $saved_subscriptionfees = $_cart->cart_contents[$this->cart_edit_key]['tmsubscriptionfee'];
                                             foreach ($saved_subscriptionfees as $key => $val) {
                                                 if (isset($val["key"])) {
                                                     if ($element['uniqid'] == $val["section"]) {
                                                         $_GET['tmcp_' . $name_inc] = $val["key"];
                                                         if (isset($val['quantity'])) {
                                                             $_GET['tmcp_' . $name_inc . '_quantity'] = $val['quantity'];
                                                         }
                                                     }
                                                 } else {
                                                     if ($element['uniqid'] == $val["section"]) {
                                                         $_GET['tmcp_' . $name_inc] = $val["value"];
                                                         if (isset($val['quantity'])) {
                                                             $_GET['tmcp_' . $name_inc . '_quantity'] = $val['quantity'];
                                                         }
                                                     }
                                                 }
                                             }
                                         }
                                     }
                                 }
                                 $display = $field_obj->display_field($element, array('name_inc' => $name_inc, 'element_counter' => $element_counter, 'tabindex' => $tabindex, 'form_prefix' => $form_prefix, 'field_counter' => $field_counter));
                                 if (is_array($display)) {
                                     $args = array('tm_element_settings' => $element, 'id' => 'tmcp_' . $this->tm_builder_elements[$element['type']]["post_name_prefix"] . '_' . $tabindex . $form_prefix, 'name' => 'tmcp_' . $name_inc, 'class' => !empty($element['class']) ? $element['class'] : "", 'tabindex' => $tabindex, 'rules' => isset($element['rules_filtered']) ? esc_html(json_encode($element['rules_filtered'])) : '', 'rules_type' => isset($element['rules_type']) ? esc_html(json_encode($element['rules_type'])) : '', 'amount' => '0 ' . $_currency, 'fieldtype' => $is_fee ? $this->fee_name_class : ($is_cart_fee ? $this->cart_fee_class : "tmcp-field"), 'field_counter' => $field_counter);
                                     $args = array_merge($args, $display);
                                     if ($this->tm_builder_elements[$element['type']]["_is_addon"]) {
                                         do_action("tm_epo_display_addons", $element, $args, array('name_inc' => $name_inc, 'element_counter' => $element_counter, 'tabindex' => $tabindex, 'form_prefix' => $form_prefix, 'field_counter' => $field_counter), $this->tm_builder_elements[$element['type']]["namespace"]);
                                     } elseif (is_readable($this->template_path . 'tm-' . $element['type'] . '.php')) {
                                         wc_get_template('tm-' . $element['type'] . '.php', $args, $this->_namespace, $this->template_path);
                                     }
                                 }
                             } elseif ($this->tm_builder_elements[$element['type']]["type"] == "multipleall" || $this->tm_builder_elements[$element['type']]["type"] == "multiple") {
                                 $field_obj->display_field_pre($element, array('element_counter' => $element_counter, 'tabindex' => $tabindex, 'form_prefix' => $form_prefix, 'field_counter' => $field_counter, 'product_id' => isset($product_id) ? $product_id : 0));
                                 foreach ($element['options'] as $value => $label) {
                                     $tabindex++;
                                     if ($this->tm_builder_elements[$element['type']]["type"] == "multipleall") {
                                         $name_inc = $this->tm_builder_elements[$element['type']]["post_name_prefix"] . "_" . $element_counter . "_" . $field_counter . $form_prefix;
                                     } else {
                                         $name_inc = $this->tm_builder_elements[$element['type']]["post_name_prefix"] . "_" . $element_counter . $form_prefix;
                                     }
                                     $is_fee = isset($element['rules_type'][$value]) && $element['rules_type'][$value][0] == "subscriptionfee";
                                     $is_cart_fee = isset($element['rules_type'][$value]) && $element['rules_type'][$value][0] == "fee";
                                     if ($is_fee) {
                                         $name_inc = $fee_name . $name_inc;
                                     } elseif ($is_cart_fee) {
                                         $name_inc = $cart_fee_name . $name_inc;
                                     }
                                     $display = $field_obj->display_field($element, array('name_inc' => $name_inc, 'value' => $value, 'label' => $label, 'element_counter' => $element_counter, 'tabindex' => $tabindex, 'form_prefix' => $form_prefix, 'field_counter' => $field_counter));
                                     if (is_array($display)) {
                                         $args = array('tm_element_settings' => $element, 'id' => 'tmcp_' . $this->tm_builder_elements[$element['type']]["post_name_prefix"] . '_' . $element_counter . "_" . $field_counter . "_" . $tabindex . $form_prefix, 'name' => 'tmcp_' . $name_inc, 'class' => !empty($element['class']) ? $element['class'] : "", 'tabindex' => $tabindex, 'rules' => isset($element['rules_filtered'][$value]) ? esc_html(json_encode($element['rules_filtered'][$value])) : '', 'rules_type' => isset($element['rules_type'][$value]) ? esc_html(json_encode($element['rules_type'][$value])) : '', 'amount' => '0 ' . $_currency, 'fieldtype' => $is_fee ? $this->fee_name_class : ($is_cart_fee ? $this->cart_fee_class : "tmcp-field"), 'border_type' => $this->tm_epo_css_selected_border, 'field_counter' => $field_counter);
                                         $args = array_merge($args, $display);
                                         if (isset($_GET['switch-subscription']) && (function_exists('wcs_get_subscription') || class_exists('WC_Subscriptions_Manager') && class_exists('WC_Subscriptions_Order'))) {
                                             $item = false;
                                             if (function_exists('wcs_get_subscription')) {
                                                 $subscription = wcs_get_subscription($_GET['switch-subscription']);
                                                 if ($subscription instanceof WC_Subscription) {
                                                     $original_order = new WC_Order($subscription->order->id);
                                                     $item = WC_Subscriptions_Order::get_item_by_product_id($original_order, $subscription->id);
                                                 }
                                             } else {
                                                 $subscription = WC_Subscriptions_Manager::get_subscription($_GET['switch-subscription']);
                                                 $original_order = new WC_Order($subscription['order_id']);
                                                 $item = WC_Subscriptions_Order::get_item_by_product_id($original_order, $subscription['product_id']);
                                             }
                                             if ($item) {
                                                 $saved_data = maybe_unserialize($item["item_meta"]["_tmcartepo_data"][0]);
                                                 foreach ($saved_data as $key => $val) {
                                                     if ($element['uniqid'] == $val["section"] && $args["value"] == $val["key"]) {
                                                         $_GET[$args['name']] = $val["key"];
                                                         if (isset($val['quantity'])) {
                                                             $_GET[$args['name'] . '_quantity'] = $val['quantity'];
                                                         }
                                                     }
                                                 }
                                             }
                                         } elseif (!empty($this->cart_edit_key) && isset($_GET['_wpnonce']) && wp_verify_nonce($_GET['_wpnonce'], 'tm-edit')) {
                                             //add_filter('woocommerce_product_single_add_to_cart_text',array($this,'tm_woocommerce_product_single_add_to_cart_text'),9999);
                                             $_cart = WC()->cart;
                                             if (isset($_cart->cart_contents) && isset($_cart->cart_contents[$this->cart_edit_key])) {
                                                 if (!empty($_cart->cart_contents[$this->cart_edit_key]['tmcartepo'])) {
                                                     $saved_epos = $_cart->cart_contents[$this->cart_edit_key]['tmcartepo'];
                                                     foreach ($saved_epos as $key => $val) {
                                                         if ($element['uniqid'] == $val["section"] && $args["value"] == $val["key"]) {
                                                             $_GET[$args['name']] = $val["key"];
                                                             if (isset($val['quantity'])) {
                                                                 $_GET[$args['name'] . '_quantity'] = $val['quantity'];
                                                             }
                                                         }
                                                     }
                                                 }
                                                 if (!empty($_cart->cart_contents[$this->cart_edit_key]['tmcartfee'])) {
                                                     $saved_fees = $_cart->cart_contents[$this->cart_edit_key]['tmcartfee'];
                                                     foreach ($saved_fees as $key => $val) {
                                                         if ($element['uniqid'] == $val["section"] && $args["value"] == $val["key"]) {
                                                             $_GET[$args['name']] = $val["key"];
                                                             if (isset($val['quantity'])) {
                                                                 $_GET[$args['name'] . '_quantity'] = $val['quantity'];
                                                             }
                                                         }
                                                     }
                                                 }
                                                 if (!empty($_cart->cart_contents[$this->cart_edit_key]['tmsubscriptionfee'])) {
                                                     $saved_subscriptionfees = $_cart->cart_contents[$this->cart_edit_key]['tmsubscriptionfee'];
                                                     foreach ($saved_subscriptionfees as $key => $val) {
                                                         if ($element['uniqid'] == $val["section"] && $args["value"] == $val["key"]) {
                                                             $_GET[$args['name']] = $val["key"];
                                                             if (isset($val['quantity'])) {
                                                                 $_GET[$args['name'] . '_quantity'] = $val['quantity'];
                                                             }
                                                         }
                                                     }
                                                 }
                                             }
                                         }
                                         if ($this->tm_builder_elements[$element['type']]["_is_addon"]) {
                                             do_action("tm_epo_display_addons", $element, $args, array('name_inc' => $name_inc, 'element_counter' => $element_counter, 'tabindex' => $tabindex, 'form_prefix' => $form_prefix, 'field_counter' => $field_counter, 'border_type' => $this->tm_epo_css_selected_border), $this->tm_builder_elements[$element['type']]["namespace"]);
                                         } elseif (is_readable($this->template_path . 'tm-' . $element['type'] . '.php')) {
                                             wc_get_template('tm-' . $element['type'] . '.php', $args, $this->_namespace, $this->template_path);
                                         }
                                     }
                                     $field_counter++;
                                 }
                             }
                             $element_counter++;
                         } elseif ($this->tm_builder_elements[$element['type']]["is_post"] == "display") {
                             $display = $field_obj->display_field($element, array('element_counter' => $element_counter, 'tabindex' => $tabindex, 'form_prefix' => $form_prefix, 'field_counter' => $field_counter));
                             if (is_array($display)) {
                                 $args = array('tm_element_settings' => $element, 'class' => !empty($element['class']) ? $element['class'] : "", 'form_prefix' => $form_prefix, 'field_counter' => $field_counter, 'tm_element' => $element, 'tm__namespace' => $this->_namespace, 'tm_template_path' => $this->template_path, 'tm_product_id' => $product_id);
                                 if ($element['type'] == "variations") {
                                     $args["variations_builder_element_start_args"] = $variations_builder_element_start_args;
                                     $args["variations_builder_element_end_args"] = array('tm_element_settings' => $element, 'element' => $element['type'], 'description' => !empty($element['description']) ? $element['description'] : "", 'description_color' => !empty($element['description_color']) ? $element['description_color'] : "", 'description_position' => !empty($element['description_position']) ? $element['description_position'] : "");
                                 }
                                 $args = array_merge($args, $display);
                                 if ($this->tm_builder_elements[$element['type']]["_is_addon"]) {
                                     do_action("tm_epo_display_addons", $element, $args, array('name_inc' => '', 'element_counter' => $element_counter, 'tabindex' => $tabindex, 'form_prefix' => $form_prefix, 'field_counter' => $field_counter), $this->tm_builder_elements[$element['type']]["namespace"]);
                                 } elseif (is_readable($this->template_path . 'tm-' . $element['type'] . '.php')) {
                                     wc_get_template('tm-' . $element['type'] . '.php', $args, $this->_namespace, $this->template_path);
                                 }
                             }
                         }
                         unset($field_obj);
                         // clear memory
                     }
                     if ($element['type'] != "variations") {
                         wc_get_template('tm-builder-element-end.php', array('tm_element_settings' => $element, 'element' => $element['type'], 'description' => !empty($element['description']) ? $element['description'] : "", 'description_color' => !empty($element['description_color']) ? $element['description_color'] : "", 'description_position' => !empty($element['description_position']) ? $element['description_position'] : ""), $this->_namespace, $this->template_path);
                     }
                     if ($use_slides && isset($sections_slides[$slide_counter])) {
                         $sections_slides[$slide_counter] = $sections_slides[$slide_counter] - 1;
                         if ($sections_slides[$slide_counter] <= 0) {
                             echo '</div>';
                             $slide_counter++;
                             $doing_slides = false;
                         }
                     }
                 }
             }
             $args = array('column' => $size, 'style' => $section['sections_style'], 'sections_type' => $section['sections_type']);
             wc_get_template('tm-builder-section-end.php', $args, $this->_namespace, $this->template_path);
         }
         wc_get_template('tm-builder-end.php', array(), $this->_namespace, $this->template_path);
         $unit_counter++;
     }
     return array('tabindex' => $tabindex, 'unit_counter' => $unit_counter, 'field_counter' => $field_counter, 'element_counter' => $element_counter, '_currency' => $_currency);
 }
 /**
  * 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;
 }
 /**
  * Prepopulate the address fields on a subscription item
  *
  * @param array $address A WooCommerce address array
  * @since 1.5
  */
 public static function maybe_populate_subscription_addresses($address)
 {
     global $woocommerce;
     if (isset($_GET['subscription'])) {
         $subscription = WC_Subscriptions_Manager::get_subscription($_GET['subscription']);
         $order = new WC_Order($subscription['order_id']);
         foreach (array_keys($address) as $key) {
             $address[$key]['value'] = $order->{$key};
         }
     }
     return $address;
 }
 /**
  * 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 ('paypal' != $order->recurring_payment_method) {
         if (self::$debug) {
             self::$log->add('paypal', 'IPN ignored, recurring payment method has changed.');
         }
         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);
     $is_first_payment = empty($subscription['completed_payments']) ? true : false;
     if ('switched' === $subscription['status']) {
         if (self::$debug) {
             self::$log->add('paypal', 'IPN ignored, subscription has been switched.');
         }
         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']);
             $default_invoice_string = self::$paypal_settings['invoice_prefix'] . ltrim($order->get_order_number(), '#');
             // If the invoice ID doesn't match the default invoice ID and contains the string '-wcscpm-', the IPN is for a subscription payment method change
             if ($default_invoice_string != $transaction_details['invoice'] && false !== strpos($transaction_details['invoice'], '-wcscpm-')) {
                 $is_payment_change = true;
             } else {
                 $is_payment_change = false;
             }
             $switched_subscription_key = get_post_meta($order_id, '_switched_subscription_key', true);
             $no_initial_payment = 0 == WC_Subscriptions_Order::get_total_initial_payment($order) && WC_Subscriptions_Order::get_subscription_trial_length($order) > 0 ? true : false;
             // When there is a free trial & no initial payment amount, we need to mark the order as paid and activate the subscription
             if (!$is_payment_change && (!empty($switched_subscription_key) || $no_initial_payment)) {
                 $order->payment_complete();
                 WC_Subscriptions_Manager::activate_subscriptions_for_order($order);
             }
             // Payment completed
             if ($is_payment_change) {
                 $order->add_order_note(__('IPN subscription payment method changed.', WC_Subscriptions::$text_domain));
             } else {
                 $order->add_order_note(__('IPN subscription sign up completed.', WC_Subscriptions::$text_domain));
             }
             if (self::$debug) {
                 if ($is_payment_change) {
                     self::$log->add('paypal', 'IPN subscription payment method changed for order ' . $order_id);
                 } else {
                     self::$log->add('paypal', 'IPN subscription sign up completed for order ' . $order_id);
                 }
             }
             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 ('true' == get_post_meta($order_id, '_wcs_changing_payment_from_paypal_to_paypal', true)) {
                 // The flag has served its purpose
                 delete_post_meta($order_id, '_wcs_changing_payment_from_paypal_to_paypal');
                 if (self::$debug) {
                     self::$log->add('paypal', 'IPN subscription cancellation request ignored as changing PayPal to PayPal, for order ' . $order_id);
                 }
             } else {
                 WC_Subscriptions_Manager::cancel_subscriptions_for_order($order);
                 // Subscription Cancellation Completed
                 $order->add_order_note(__('IPN subscription cancelled for order.', WC_Subscriptions::$text_domain));
                 if (self::$debug) {
                     self::$log->add('paypal', 'IPN subscription cancelled for order ' . $order_id);
                 }
             }
             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;
 }
예제 #18
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
 }
 /**
  * Trigger a hook when a subscription suspended due to a failed renewal payment is reactivated
  *
  * @since 1.3
  */
 public static function trigger_processed_failed_renewal_order_payment_hook($user_id, $subscription_key)
 {
     $subscription = WC_Subscriptions_Manager::get_subscription($subscription_key);
     $original_order = new WC_Order($subscription['order_id']);
     do_action('woocommerce_subscriptions_processed_failed_renewal_order_payment', $subscription_key, $original_order);
 }
 /**
  * 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', 'recurring_payment_suspended_due_to_max_failed_payment'))) {
         return;
     }
     if ('recurring_payment_suspended_due_to_max_failed_payment' == $transaction_details['txn_type'] && isset($transaction_details['rp_invoice_id'])) {
         self::$log->add('paypal', 'Returning as "recurring_payment_suspended_due_to_max_failed_payment" transaction is for a subscription created with Express Checkout');
         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.');
         }
         exit;
     }
     $is_renewal_sign_up_after_failure = false;
     // If the invoice ID doesn't match the default invoice ID and contains the string '-wcsfrp-', the IPN is for a subscription payment to fix up a failed payment
     if (false !== strpos($transaction_details['invoice'], '-wcsfrp-') && in_array($transaction_details['txn_type'], array('subscr_signup', 'subscr_payment'))) {
         $renewal_order = new WC_Order(substr($transaction_details['invoice'], strrpos($transaction_details['invoice'], '-') + 1));
         // check if the failed signup has been previously recorded
         if ($renewal_order->id != get_post_meta($order->id, '_paypal_failed_sign_up_recorded', true)) {
             $is_renewal_sign_up_after_failure = true;
         }
     }
     // If the invoice ID doesn't match the default invoice ID and contains the string '-wcscpm-', the IPN is for a subscription payment method change
     if (false !== strpos($transaction_details['invoice'], '-wcscpm-') && 'subscr_signup' == $transaction_details['txn_type']) {
         $is_payment_change = true;
     } else {
         $is_payment_change = false;
     }
     if ($is_renewal_sign_up_after_failure || $is_payment_change) {
         // Store the old profile ID on the order (for the first IPN message that comes through)
         $existing_profile_id = self::get_subscriptions_paypal_id($order);
         if (empty($existing_profile_id) || $existing_profile_id !== $transaction_details['subscr_id']) {
             update_post_meta($order->id, '_old_paypal_subscriber_id', $existing_profile_id);
             update_post_meta($order->id, '_old_recurring_payment_method', $order->recurring_payment_method);
         }
     }
     if ('paypal' != $order->recurring_payment_method && false === $is_renewal_sign_up_after_failure && false === $is_payment_change) {
         if (self::$debug) {
             self::$log->add('paypal', 'IPN ignored, recurring payment method has changed.');
         }
         exit;
     }
     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
         $ipn_id = $transaction_details['txn_type'] . '_' . $transaction_details['ipn_track_id'];
         if (in_array($ipn_id, $handled_ipn_requests)) {
             if (self::$debug) {
                 self::$log->add('paypal', 'Subscription IPN Error: IPN ' . $ipn_id . ' message has already been correctly handled.');
             }
             exit;
         }
     }
     if (isset($transaction_details['txn_id'])) {
         // Make sure the IPN request has not already been handled
         $handled_transactions = get_post_meta($order_id, '_paypal_transaction_ids', true);
         if (empty($handled_transactions)) {
             $handled_transactions = array();
         }
         $transaction_id = $transaction_details['txn_id'];
         if (isset($transaction_details['txn_type'])) {
             $transaction_id .= '_' . $transaction_details['txn_type'];
         }
         // The same transaction ID is used for different payment statuses, so make sure we handle it only once. See: http://stackoverflow.com/questions/9240235/paypal-ipn-unique-identifier
         if (isset($transaction_details['payment_status'])) {
             $transaction_id .= '_' . $transaction_details['payment_status'];
         }
         if (in_array($transaction_id, $handled_transactions)) {
             if (self::$debug) {
                 self::$log->add('paypal', 'Subscription IPN Error: transaction ' . $transaction_id . ' has already been correctly handled.');
             }
             exit;
         }
     }
     // Save the profile ID if it's not a cancellation/expiration request
     if (isset($transaction_details['subscr_id']) && !in_array($transaction_details['txn_type'], array('subscr_cancel', 'subscr_eot'))) {
         update_post_meta($order_id, 'PayPal Subscriber ID', $transaction_details['subscr_id']);
         if ('S-' == substr($transaction_details['subscr_id'], 0, 2) && 'disabled' != get_option('wcs_paypal_invalid_profile_id')) {
             update_option('wcs_paypal_invalid_profile_id', 'yes');
         }
     }
     // 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);
     $product_id = WC_Subscriptions_Order::get_items_product_id($subscription_item);
     $subscription_key = WC_Subscriptions_Manager::get_subscription_key($order->id, $product_id);
     $subscription = WC_Subscriptions_Manager::get_subscription($subscription_key);
     $is_first_payment = empty($subscription['completed_payments']) ? true : false;
     if ('switched' === $subscription['status']) {
         if (self::$debug) {
             self::$log->add('paypal', 'IPN ignored, subscription has been switched.');
         }
         exit;
     }
     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']);
             $switched_subscription_key = get_post_meta($order_id, '_switched_subscription_key', true);
             $no_initial_payment = 0 == WC_Subscriptions_Order::get_total_initial_payment($order) ? true : false;
             // When there is a free trial & no initial payment amount, we need to mark the order as paid and activate the subscription
             if (!$is_payment_change && !$is_renewal_sign_up_after_failure && (!empty($switched_subscription_key) || $no_initial_payment)) {
                 $order->payment_complete($transaction_details['txn_id']);
             }
             // Payment completed
             if ($is_payment_change) {
                 // Set PayPal as the new payment method
                 WC_Subscriptions_Change_Payment_Gateway::update_recurring_payment_method($subscription_key, $order, 'paypal');
                 $old_payment_method = get_post_meta($order->id, '_old_recurring_payment_method', true);
                 // We need to cancel the subscription now that the method has been changed successfully
                 if ('paypal' == $old_payment_method) {
                     $existing_profile_id = get_post_meta($order->id, '_old_paypal_subscriber_id', true);
                     self::cancel_subscription_with_paypal($order, $product_id, $existing_profile_id);
                 }
                 $order->add_order_note(__('IPN subscription payment method changed to PayPal.', 'woocommerce-subscriptions'));
             } else {
                 $order->add_order_note(__('IPN subscription sign up completed.', 'woocommerce-subscriptions'));
             }
             if (self::$debug) {
                 if ($is_payment_change) {
                     self::$log->add('paypal', 'IPN subscription payment method changed for order ' . $order_id);
                 } else {
                     self::$log->add('paypal', 'IPN subscription sign up completed for order ' . $order_id);
                 }
             }
             break;
         case 'subscr_payment':
             if ('completed' == strtolower($transaction_details['payment_status'])) {
                 // Store PayPal Details
                 update_post_meta($order_id, '_transaction_id', $transaction_details['txn_id']);
                 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.', 'woocommerce-subscriptions'));
                 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($transaction_details['txn_id']);
                     WC_Subscriptions_Manager::activate_subscriptions_for_order($order);
                     // Ignore the first IPN message if the PDT should have handled it (if it didn't handle it, it will have been dealt with as first payment), but set a flag to make sure we only ignore it once
                 } elseif (count($subscription['completed_payments']) == 1 && !empty(self::$paypal_settings['identity_token']) && 'true' != get_post_meta($order_id, '_paypal_first_ipn_ignored_for_pdt', true) && false === $is_renewal_sign_up_after_failure) {
                     if (self::$debug) {
                         self::$log->add('paypal', 'IPN subscription payment ignored for order ' . $order_id . ' due to PDT previously handling the payment.');
                     }
                     update_post_meta($order_id, '_paypal_first_ipn_ignored_for_pdt', 'true');
                     // Process the payment if the subscription is active
                 } elseif (!in_array($subscription['status'], array('cancelled', 'expired', 'switched', 'trash'))) {
                     // 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);
                     if (true === $is_renewal_sign_up_after_failure && is_object($renewal_order)) {
                         $old_payment_method = get_post_meta($order->id, '_old_recurring_payment_method', true);
                         update_post_meta($order->id, '_paypal_failed_sign_up_recorded', $renewal_order->id);
                         // We need to cancel the old subscription now that the method has been changed successfully
                         if ('paypal' == $old_payment_method) {
                             $profile_id = get_post_meta($order->id, '_old_paypal_subscriber_id', true);
                             // Make sure we don't cancel the current profile
                             if ($profile_id !== $transaction_details['subscr_id']) {
                                 self::cancel_subscription_with_paypal($order, $product_id, $profile_id);
                             }
                             $order->add_order_note(__('IPN subscription failing payment method changed.', 'woocommerce-subscriptions'));
                         }
                         $renewal_order->payment_complete($transaction_details['txn_id']);
                         // WC_Subscriptions_Manager::process_subscription_payments_on_order will be called with by WC_Subscriptions_Renewal_Order::process_subscription_payment_on_child_order()
                         update_post_meta($renewal_order->id, 'PayPal Subscriber ID', $transaction_details['subscr_id']);
                     } else {
                         WC_Subscriptions_Manager::process_subscription_payments_on_order($order);
                     }
                     // Make sure the next payment date is synchronised with when PayPal processes the payments
                     WC_Subscriptions_Manager::set_next_payment_date($subscription_key, $order->customer_user);
                     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.', 'woocommerce-subscriptions'));
                 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':
             // Make sure the subscription hasn't been linked to a new payment method
             if ($transaction_details['subscr_id'] != self::get_subscriptions_paypal_id($order)) {
                 if (self::$debug) {
                     self::$log->add('paypal', 'IPN subscription cancellation request ignored - new PayPal Profile ID linked to this subscription, for order ' . $order_id);
                 }
             } else {
                 WC_Subscriptions_Manager::cancel_subscriptions_for_order($order);
                 // Subscription Cancellation Completed
                 $order->add_order_note(__('IPN subscription cancelled for order.', 'woocommerce-subscriptions'));
                 if (self::$debug) {
                     self::$log->add('paypal', 'IPN subscription cancelled for order ' . $order_id);
                 }
             }
             break;
         case 'subscr_eot':
             // Subscription ended, either due to failed payments or expiration
             if (self::$debug) {
                 self::$log->add('paypal', 'IPN EOT request ignored for order ' . $order_id);
             }
             break;
         case 'subscr_failed':
             // Subscription sign up failed
         // Subscription sign up failed
         case 'recurring_payment_suspended_due_to_max_failed_payment':
             // 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.', 'woocommerce-subscriptions'));
             // 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);
             break;
     }
     // Store the transaction IDs to avoid handling requests duplicated by PayPal
     if (isset($transaction_details['ipn_track_id'])) {
         $handled_ipn_requests[] = $ipn_id;
         update_post_meta($order_id, '_paypal_ipn_tracking_ids', $handled_ipn_requests);
     }
     if (isset($transaction_details['txn_id'])) {
         $handled_transactions[] = $transaction_id;
         update_post_meta($order_id, '_paypal_transaction_ids', $handled_transactions);
     }
     // Prevent default IPN handling for subscription txn_types
     exit;
 }
 /**
  * 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;
 }
 public function get_email_address_to_send($email_data, $email_order, $email)
 {
     if ($email->email_type != 'subscription') {
         return $email_data;
     }
     $meta = maybe_unserialize($email_order->meta);
     if (isset($meta['subs_key'])) {
         $subscription = WC_Subscriptions_Manager::get_subscription($meta['subs_key']);
         if (!empty($subscription)) {
             $order = new WC_Order($subscription['order_id']);
             $user = new WP_User($order->user_id);
             $email_data['email_to'] = $user->user_email;
             $email_data['first_name'] = $user->first_name;
             $email_data['last_name'] = $user->last_name;
             $email_data['cname'] = $user->first_name . ' ' . $user->last_name;
         }
     }
     return $email_data;
 }
 /**
  * Fire a gateway specific hook when a subscription expires.
  *
  * @since 1.0
  */
 public static function trigger_gateway_subscription_expired_hook($user_id, $subscription_key)
 {
     $subscription = WC_Subscriptions_Manager::get_subscription($subscription_key);
     $order = new WC_Order($subscription['order_id']);
     if (!WC_Subscriptions_Order::requires_manual_renewal($order)) {
         do_action('subscription_expired_' . $order->recurring_payment_method, $order, $subscription['product_id']);
     }
 }
 /**
  * When switching a subscription we need to update old listings.
  *
  * No need to give the user a new package; thats still handled by the orders class.
  */
 public function switched_subscription($user_id, $original_subscription_key, $new_subscription_key)
 {
     global $wpdb;
     // Get subscription details
     $old_subscription = WC_Subscriptions_Manager::get_subscription($original_subscription_key);
     $old_subscription_type = get_post_meta($old_subscription['product_id'], '_package_subscription_type', true);
     $old_subscription_type = empty($old_subscription_type) ? 'package' : $old_subscription_type;
     $new_subscription = WC_Subscriptions_Manager::get_subscription($new_subscription_key);
     $new_subscription_type = get_post_meta($new_subscription['product_id'], '_package_subscription_type', true);
     $new_subscription_type = empty($new_subscription_type) ? 'package' : $new_subscription_type;
     // Get the user package
     $user_package = $wpdb->get_row($wpdb->prepare("SELECT * FROM {$wpdb->prefix}wcpl_user_packages WHERE user_id = %d AND order_id = %d AND product_id = %d;", $user_id, $old_subscription['order_id'], $old_subscription['product_id']));
     if ($user_package) {
         $switching_to_package = wc_get_product($new_subscription['product_id']);
         // If invalid, abort
         if (!$switching_to_package->is_type(array('job_package', 'resume_package', 'job_package_subscription', 'resume_package_subscription'))) {
             return false;
         }
         $switching_to_package_id = wc_paid_listings_give_user_package($user_id, $new_subscription['product_id'], $new_subscription['order_id']);
         // Ensure package is not given twice
         update_post_meta($new_subscription['order_id'], 'wc_paid_listings_packages_processed', true);
         // Upgrade?
         $upgrading = $switching_to_package->get_limit() >= $user_package->package_limit;
         // Delete the old package
         $wpdb->delete("{$wpdb->prefix}wcpl_user_packages", array('id' => $user_package->id));
         // Update old listings
         if ('listing' === $new_subscription_type && $switching_to_package_id) {
             $listing_ids = $wpdb->get_col($wpdb->prepare("\n\t\t\t\t\tSELECT post_id FROM {$wpdb->postmeta}\n\t\t\t\t\tLEFT JOIN {$wpdb->posts} ON {$wpdb->postmeta}.post_id = {$wpdb->posts}.ID\n\t\t\t\t\tWHERE meta_key = '_user_package_id'\n\t\t\t\t\tAND meta_value = %s;\n\t\t\t\t", $user_package->id));
             foreach ($listing_ids as $listing_id) {
                 // If we are not upgrading, expire the old listing
                 if (!$upgrading) {
                     $listing = array('ID' => $listing_id, 'post_status' => 'expired');
                     wp_update_post($listing);
                 } else {
                     wc_paid_listings_increase_package_count($user_id, $switching_to_package_id);
                     // Change the user package ID and package ID
                     update_post_meta($listing_id, '_user_package_id', $switching_to_package_id);
                     update_post_meta($listing_id, '_package_id', $new_subscription['product_id']);
                 }
                 // Featured or not
                 update_post_meta($listing_id, '_featured', $switching_to_package->is_featured() ? 1 : 0);
                 // Fire action
                 do_action('wc_paid_listings_switched_subscription', $listing_id, $user_package);
             }
         }
     }
 }
 /**
  * Make sure anything requesting the first payment date for a switched subscription receives a date which
  * takes into account the switch (i.e. prepaid days and possibly a downgrade).
  *
  * 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.4
  */
 public static function get_first_payment_date($next_payment_date, $subscription_key, $user_id, $type)
 {
     $subscription = WC_Subscriptions_Manager::get_subscription($subscription_key);
     if ('active' == $subscription['status'] && self::order_contains_subscription_switch($subscription['order_id']) && 1 >= WC_Subscriptions_Manager::get_subscriptions_completed_payment_count($subscription_key)) {
         $first_payment_timestamp = get_post_meta($subscription['order_id'], '_switched_subscription_first_payment_timestamp', true);
         if (0 != $first_payment_timestamp) {
             $next_payment_date = 'mysql' == $type ? date('Y-m-d H:i:s', $first_payment_timestamp) : $first_payment_timestamp;
         }
     }
     return $next_payment_date;
 }
 /**
  * If a subscription has the status of active, this function checks to make sure that a payment was completed
  * within the last couple of days. It is hooked to the 'paypal_check_subscription_payment' action triggered by
  * WP-Cron and scheduled with @see self::scheduled_subscription_payment() to run 24 hours after the payment was due.
  *
  * @since 1.4.3
  */
 public static function check_subscription_payment($subscription_key)
 {
     $subscription = WC_Subscriptions_Manager::get_subscription($subscription_key);
     $order = new WC_Order($subscription['order_id']);
     if ('active' === $subscription['status']) {
         $last_payment_plus_two_days = 60 * 60 * 24 * 2 + WC_Subscriptions_Manager::get_last_payment_date($subscription_key, $order->user_id, 'timestamp');
         // If the last payment was more than 2 days ago, then we're missing a payment because this function is called 24 hours after payment was due
         if ($last_payment_plus_two_days < gmdate('U')) {
             // @TODO process a subscription payment failure when this has been reliably tested
             //remove_action( 'subscription_put_on-hold_paypal', __CLASS__ . '::suspend_subscription_with_paypal', 10, 2 );
             //WC_Subscriptions_Manager::process_subscription_payment_failure( $order->user_id, $subscription_key );
             //$order->add_order_note( __( 'Subscription payment failure triggered as no recurring payment has been processed by PayPal.', 'woocommerce-subscriptions' ) );
             //add_action( 'subscription_put_on-hold_paypal', __CLASS__ . '::suspend_subscription_with_paypal', 10, 2 );
         }
     }
 }
예제 #27
0
function paymill_webhooks()
{
    global $wpdb;
    // is there a webhook from Paymill?
    if (class_exists('WC_Subscriptions_Manager')) {
        // grab data from webhook
        $body = @file_get_contents('php://input');
        $event_json = json_decode($body, true);
        // retrieve sub ID
        if (isset($event_json['event']['event_resource']['id']) && strlen($event_json['event']['event_resource']['id']) > 0) {
            $paymill_sub_id = $event_json['event']['event_resource']['id'];
        } elseif (isset($event_json['event']['event_resource']['subscription']['id']) && strlen($event_json['event']['event_resource']['subscription']['id']) > 0) {
            $paymill_sub_id = $event_json['event']['event_resource']['subscription']['id'];
        }
        error_log("\n\n########################################################################################################################\n\n", 3, PAYMILL_DIR . 'lib/debug/PHP_errors.log');
        error_log(date(DATE_RFC822) . ' - Webhook ' . $event_json['event']['event_type'] . ' (Resource-ID: ' . $paymill_sub_id . ') triggered - start processing' . "\n\n", 3, PAYMILL_DIR . 'lib/debug/PHP_errors.log');
        /* output example:
        				array(1) {
        				  ["event"]=>
        				  array(4) {
        					["event_type"]=>
        					string(20) "subscription.deleted"
        					["event_resource"]=>
        					array(13) {
        					  ["id"]=>
        					  string(24) "sub_b71adbf5....."
        					  ["offer"]=>
        					  array(10) {
        						["id"]=>
        						string(26) "offer_8083a5b....."
        						["name"]=>
        						string(39) "woo_91_73da6....."
        						["amount"]=>
        						int(100)
        						["currency"]=>
        						string(3) "EUR"
        						["interval"]=>
        						string(5) "1 DAY"
        						["trial_period_days"]=>
        						int(0)
        						["created_at"]=>
        						int(1389547028)
        						["updated_at"]=>
        						int(1389547028)
        						["subscription_count"]=>
        						array(2) {
        						  ["active"]=>
        						  string(1) "1"
        						  ["inactive"]=>
        						  string(1) "1"
        						}
        						["app_id"]=>
        						NULL
        					  }
        					  ["livemode"]=>
        					  bool(false)
        					  ["cancel_at_period_end"]=>
        					  bool(false)
        					  ["trial_start"]=>
        					  NULL
        					  ["trial_end"]=>
        					  NULL
        					  ["next_capture_at"]=>
        					  int(1389836717)
        					  ["created_at"]=>
        					  int(1389663382)
        					  ["updated_at"]=>
        					  int(1389750317)
        					  ["canceled_at"]=>
        					  NULL
        					  ["app_id"]=>
        					  NULL
        					  ["payment"]=>
        					  array(12) {
        						["id"]=>
        						string(28) "pay_4e3759f....."
        						["type"]=>
        						string(10) "creditcard"
        						["client"]=>
        						string(27) "client_dbe164....."
        						["card_type"]=>
        						string(4) "visa"
        						["country"]=>
        						NULL
        						["expire_month"]=>
        						string(2) "12"
        						["expire_year"]=>
        						string(4) "2020"
        						["card_holder"]=>
        						string(13) "dfgdfgdfgdfgd"
        						["last4"]=>
        						string(4) "1111"
        						["created_at"]=>
        						int(1389663369)
        						["updated_at"]=>
        						int(1389663380)
        						["app_id"]=>
        						NULL
        					  }
        					  ["client"]=>
        					  array(8) {
        						["id"]=>
        						string(27) "client_dbe164....."
        						["email"]=>
        						string(22) "*****@*****.**"
        						["description"]=>
        						string(15) "Matthias Reuter"
        						["created_at"]=>
        						int(1389547027)
        						["updated_at"]=>
        						int(1389547027)
        						["app_id"]=>
        						NULL
        						["payment"]=>
        						array(2) {
        						  [0]=>
        						  array(12) {
        							["id"]=>
        							string(28) "pay_1a5ff8....."
        							["type"]=>
        							string(10) "creditcard"
        							["client"]=>
        							string(27) "client_dbe16....."
        							["card_type"]=>
        							string(4) "visa"
        							["country"]=>
        							NULL
        							["expire_month"]=>
        							string(2) "12"
        							["expire_year"]=>
        							string(4) "2020"
        							["card_holder"]=>
        							string(10) "dfgdfgdfgd"
        							["last4"]=>
        							string(4) "1111"
        							["created_at"]=>
        							int(1389547027)
        							["updated_at"]=>
        							int(1389547028)
        							["app_id"]=>
        							NULL
        						  }
        						  [1]=>
        						  array(12) {
        							["id"]=>
        							string(28) "pay_4e375....."
        							["type"]=>
        							string(10) "creditcard"
        							["client"]=>
        							string(27) "client_dbe164....."
        							["card_type"]=>
        							string(4) "visa"
        							["country"]=>
        							NULL
        							["expire_month"]=>
        							string(2) "12"
        							["expire_year"]=>
        							string(4) "2020"
        							["card_holder"]=>
        							string(13) "dfgdfgdfgdfgd"
        							["last4"]=>
        							string(4) "1111"
        							["created_at"]=>
        							int(1389663369)
        							["updated_at"]=>
        							int(1389663380)
        							["app_id"]=>
        							NULL
        						  }
        						}
        						["subscription"]=>
        						array(2) {
        						  [0]=>
        						  string(24) "sub_fcc4....."
        						  [1]=>
        						  string(24) "sub_b71a....."
        						}
        					  }
        					}
        					["created_at"]=>
        					int(1389816435)
        					["app_id"]=>
        					NULL
        				  }
        				}
        				
        			*/
        //error_log(var_export($event_json,true)."\n\n", 3, PAYMILL_DIR.'lib/debug/PHP_errors.log');
        // get subscription info, if available
        if (isset($paymill_sub_id) && strlen($paymill_sub_id) > 0) {
            $sql = $wpdb->prepare('SELECT * FROM ' . $wpdb->prefix . 'paymill_subscriptions WHERE paymill_sub_id=%s', array($paymill_sub_id));
            $sub_cache = $wpdb->get_results($sql, ARRAY_A);
            $sub_cache = $sub_cache[0];
            /* output example:
            			SELECT * FROM wp_paymill_subscriptions WHERE paymill_sub_id="sub_b71adbf5e097bbe5ba80"
            			*/
            error_log("\n\n" . $sql . "\n\n", 3, PAYMILL_DIR . 'lib/debug/PHP_errors.log');
            /* output example:
            			
            			1
            			
            			30
            			
            			*/
            //error_log($sub_cache['woo_user_id']."\n\n".$sub_cache['woo_offer_id']."\n\n", 3, PAYMILL_DIR.'lib/debug/PHP_errors.log');
            $subscription = WC_Subscriptions_Manager::get_subscription($sub_cache['woo_offer_id']);
            // update subscriptions when webhook is triggered
            if (isset($sub_cache['woo_offer_id']) && strlen($sub_cache['woo_offer_id']) > 0) {
                // subscription successfully created
                if ($event_json['event']['event_type'] == 'subscription.created') {
                }
                // tell WooCommerce when payment for subscription is successfully processed
                if ($event_json['event']['event_type'] == 'subscription.succeeded') {
                    /* example data WC_Subscriptions_Manager::get_subscription:
                    				array(15) {
                    				  ["order_id"]=>
                    				  string(3) "201"
                    				  ["product_id"]=>
                    				  string(2) "91"
                    				  ["variation_id"]=>
                    				  string(0) ""
                    				  ["status"]=>
                    				  string(6) "active"
                    				  ["period"]=>
                    				  string(3) "day"
                    				  ["interval"]=>
                    				  string(1) "1"
                    				  ["length"]=>
                    				  string(2) "12"
                    				  ["start_date"]=>
                    				  string(19) "2014-01-12 17:17:10"
                    				  ["expiry_date"]=>
                    				  string(19) "2014-01-24 17:17:10"
                    				  ["end_date"]=>
                    				  string(1) "0"
                    				  ["trial_expiry_date"]=>
                    				  string(1) "0"
                    				  ["failed_payments"]=>
                    				  string(1) "0"
                    				  ["completed_payments"]=>
                    				  array(1) {
                    					[0]=>
                    					string(19) "2014-01-12 17:17:10"
                    				  }
                    				  ["suspension_count"]=>
                    				  string(1) "0"
                    				  ["last_payment_date"]=>
                    				  string(19) "2014-01-12 17:17:10"
                    				}
                    			*/
                    error_log(var_export($subscription, true) . "\n\n", 3, PAYMILL_DIR . 'lib/debug/PHP_errors.log');
                    // prevent multiple subscription renewals because of multiple webhook attempts.
                    $whole_period = 0;
                    switch ($subscription['period']) {
                        case 'day':
                        default:
                            $whole_period = intval($subscription['interval']) * 86400;
                            break;
                        case 'week':
                            $whole_period = intval($subscription['interval']) * 604800;
                            break;
                        case 'month':
                            $whole_period = intval($subscription['interval']) * 2160000;
                            // using 25 days to prevent problems with shorter months
                            break;
                        case 'year':
                            $whole_period = intval($subscription['interval']) * 30240000;
                            // using 350 days to prevent any timezone problems whatsoever
                            break;
                    }
                    if (count($subscription['completed_payments']) >= 1) {
                        if (strtotime(date(DATE_RFC822)) > strtotime($subscription['last_payment_date']) + $whole_period - 18000) {
                            // minus 5 hours to prevent any problems with pending triggers
                            $order = new WC_Order($subscription['order_id']);
                            //WC_Subscriptions_Manager::process_subscription_payments_on_order($order, $subscription['product_id']);
                            WC_Subscriptions_Manager::process_subscription_payments_on_order($order);
                        }
                    } else {
                        $order = new WC_Order($subscription['order_id']);
                        $order->payment_complete();
                        WC_Subscriptions_Manager::activate_subscriptions_for_order($subscription['order_id']);
                    }
                    WC_Subscriptions_Manager::set_next_payment_date($sub_cache['woo_offer_id'], $order->customer_user);
                }
                // cancel subscription, as it was deleted through Paymill dashboard
                if ($event_json['event']['event_type'] == 'subscription.deleted') {
                    $sql = $wpdb->prepare('DELETE FROM ' . $wpdb->prefix . 'paymill_subscriptions WHERE woo_user_id=%s AND woo_offer_id=%s', array($sub_cache['woo_user_id'], $sub_cache['woo_offer_id']));
                    $wpdb->query($sql);
                    error_log("\n\n" . $sql . "\n\n", 3, PAYMILL_DIR . 'lib/debug/PHP_errors.log');
                    //WC_Subscriptions_Manager::cancel_subscriptions_for_order( $order );
                    WC_Subscriptions_Manager::cancel_subscription($sub_cache['woo_user_id'], $sub_cache['woo_offer_id']);
                }
                // tell WC that payment failure occured
                if ($event_json['event']['event_type'] == 'subscription.failed') {
                    WC_Subscriptions_Manager::process_subscription_payment_failure_on_order($subscription['order_id'], $subscription['product_id']);
                }
            }
        }
        error_log(date(DATE_RFC822) . ' - Webhook ' . $event_json['event']['event_type'] . ' finished - end processing' . "\n\n", 3, PAYMILL_DIR . 'lib/debug/PHP_errors.log');
        error_log("\n\n########################################################################################################################\n\n", 3, PAYMILL_DIR . 'lib/debug/PHP_errors.log');
    }
}
 /**
  * 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);
 }
예제 #29
0
 /**
  * Checks if a subscription has an unpaid renewal order.
  *
  * @param $subscription_key string A subscription key of the form created by @see self::get_subscription_key()
  * @param $user_id int The ID of the user who owns the subscriptions. Although this parameter is optional, if you have the User ID you should pass it to improve performance.
  * @return bool True if the subscription has an unpaid renewal order, false if the subscription has no unpaid renewal orders.
  * @since 1.2
  */
 public static function subscription_requires_payment($subscription_key, $user_id)
 {
     global $wpdb;
     $subscription = WC_Subscriptions_Manager::get_subscription($subscription_key, $user_id);
     if (empty($subscription)) {
         $subscription_requires_payment = true;
     } else {
         $subscription_requires_payment = false;
         $statuses_requiring_payment = array('pending', 'on-hold', 'failed');
         $order = new WC_Order($subscription['order_id']);
         if (in_array($order->status, $statuses_requiring_payment)) {
             $subscription_requires_payment = true;
         } else {
             $renewal_order_ids = $wpdb->get_col($wpdb->prepare("SELECT ID FROM {$wpdb->posts} WHERE post_parent = %s", $subscription['order_id']));
             foreach ($renewal_order_ids as $renewal_order_id) {
                 $renewal_order = new WC_Order($renewal_order_id);
                 if (in_array($renewal_order->status, $statuses_requiring_payment)) {
                     $subscription_requires_payment = true;
                     break;
                 }
             }
         }
     }
     return apply_filters('woocommerce_subscription_requires_payment', $subscription_requires_payment, $subscription, $subscription_key, $user_id);
 }
 /**
  * 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;
 }