diff --git a/assets/js/admin/admin.js b/assets/js/admin/admin.js index 3eaf716..e3b56b8 100644 --- a/assets/js/admin/admin.js +++ b/assets/js/admin/admin.js @@ -356,35 +356,6 @@ jQuery(document).ready(function($){ $( '#_subscription_one_time_shipping' ).prop( 'disabled', is_synced_or_has_trial ); }, - show_hidden_panels: function() { - // WooCommerce's show_hidden_panels() function introduced a change in WC 2.6.2 which would hide the general panel for variable subscriptions, this fixes that by running the show_hidden_panels() logic again after variable fields have been show/hidden for variable subscriptions - $( '.woocommerce_options_panel' ).each( function() { - - if ( 'none' != $( this ).css( 'display' ) ) { - return; - } - - var $children = $( this ).children( '.options_group' ); - - if ( 0 === $children.length ) { - return; - } - - var $invisble = $children.filter( function() { - return 'none' === $( this ).css( 'display' ); - }); - - // Show panel if it's been mistakenly hidden panel - if ( $invisble.length != $children.length ) { - var $id = $( this ).prop( 'id' ); - $( '.product_data_tabs' ).find( 'li a[href="#' + $id + '"]' ).parent().show(); - } - - }); - - // Now select the first panel in case it's changed - $( 'ul.wc-tabs li:visible' ).eq( 0 ).find( 'a' ).click(); - }, }); $('.options_group.pricing ._sale_price_field .description').prepend(''); @@ -392,6 +363,7 @@ jQuery(document).ready(function($){ // Move the subscription pricing section to the same location as the normal pricing section $('.options_group.subscription_pricing').not('.variable_subscription_pricing .options_group.subscription_pricing').insertBefore($('.options_group.pricing:first')); $('.show_if_subscription.clear').insertAfter($('.options_group.subscription_pricing')); + $( '.show_if_variable' ).addClass( 'show_if_variable-subscription' ); // Move the subscription variation pricing section to a better location in the DOM on load if($('#variable_product_options .variable_subscription_pricing').length > 0) { @@ -413,7 +385,6 @@ jQuery(document).ready(function($){ $.setTrialPeriods(); $.showHideSyncOptions(); $.disableEnableOneTimeShipping(); - $.show_hidden_panels(); } // Update subscription ranges when subscription period or interval is changed @@ -433,7 +404,6 @@ jQuery(document).ready(function($){ $.showHideSubscriptionMeta(); $.showHideVariableSubscriptionMeta(); $.showHideSyncOptions(); - $.show_hidden_panels(); }); $('input#_downloadable, input#_virtual').change(function(){ @@ -484,7 +454,16 @@ jQuery(document).ready(function($){ $('.order_actions .submitdelete').click(function(){ if($('[name="contains_subscription"]').val()=='true'){ - return confirm(WCSubscriptions.bulkTrashWarning); + return confirm(WCSubscriptions.trashWarning); + } + }); + + // Notify the store manager that trashing an order via the admin orders table row action also deletes the associated subscription if it exists + $( '.row-actions .submitdelete' ).click( function() { + var order = $( this ).closest( '.type-shop_order' ).attr( 'id' ); + + if ( true === $( '.contains_subscription', $( '#' + order ) ).data( 'contains_subscription' ) ) { + return confirm( WCSubscriptions.trashWarning ); } }); diff --git a/changelog.txt b/changelog.txt index 4971916..a4672a2 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,5 +1,26 @@ *** WooCommerce Subscriptions Changelog *** +2016.09.23 - version 2.0.20 + * Tweak: add new 'woocommerce_subscription_before_actions' and 'woocommerce_subscription_after_actions' hooks to the view-subscription.php template. (PR#1608) + * Tweak: use WC_Subscriptions_Product::is_subscription() when checking if a product is sync'd instead of checking the product type directly so that the 'woocommerce_is_subscription' filter is applied and additional product types can add support for synchronisation. (PR#1635) + * Tweak: warn administrators when trashing subscription parent orders from row actions that the related subscriptions will also be trashed. (PR#1647) + * Tweak: add new 'woocommerce_subscriptions_admin_related_orders_to_display' filter to make it easier to manipulate the list of related orders on the Edit Subscription and Edit Order screens. (PR#1631) + * Tweak: add new 'woocommerce_subscriptions_switch_is_identical_product ' filter provide a simple way for 3rd party extensions to determine whether a product should be considered as identical or not, for the purposes of a switch. (PR#1659) + * Tweak: add new 'wcs_paypal_ipn_note' filter to make it easier to modify the order notes logged when processing PayPal IPN requests. @props David Marín (PR#1657) + * Tweak: display a link to Paypal's subscription page in the Subscription Billing Information section of the Edit Subscription administration screen. @props David Marín (PR#1658) + * Fix: display tax correctly for carts with only sync/trials products. (PR#1599) + * Fix: calcaulte tax correctly for prorated sign-up fee during 2...n switch. (PR#1607) + * Fix: remove duplicate call to get items from a subscription on the view-subscription.php template. (PR#1615) + * Fix: guard against fatal errors when 3rd party code calls WordPress' current_user_can() function with invalid parameters. (PR#1652) + * Fix: replace show_hidden_panels Javascript function which was inadvertently displaying 3rd party panels on Edit Product screen. (PR#1637) + * Fix: add the chosen recurring shipping method variable to the parameters passed to callbacks on 'woocommerce_subscriptions_after_recurring_shipping_rates'. (PR#1643) + * Fix: make sure non-logged in users can buy limited subscriptions by avoiding the call to get_posts() in wcs_get_users_subscriptions() when no user ID is specified and no user is logged in. (PR#1649) + * Fix: recalculate free shipping availability based on recurring cart object when applicable to fix issues with free shipping being available for the initial order but not recurring order, either becuase of price requirements or coupons. (PR#1549) + * Fix: make sure 'woocommerce_scheduled_subscription_end_of_prepaid_term' hook is unscheduled when a subscription with the pending cancellation status is trashed. (PR#1589) + * Fix: only get downloadable files from directly related subscriptions, not old subscriptions for subscriptions created by resubscribing. (PR#1612) + * Fix: variable subscription "From:" price when one variation with a higher ID has a longer free trial than the lower priced variation. (PR#1602) + * Fix: remove unused "Email Subject (paid)" and "Email Heading (paid)" fields from the Customer Renewal Invoice email settings page. (PR#1601) + 2016.08.12 - version 2.0.19 * Tweak: require new manually added subscriptions to have a customer to avoid issues with subscriptions created without a customer. (PR#1486) * Tweak: set expiration on caching transients to avoid them being autoloaded on every request and unnecessarily using memory on those requests. (PR#1540) diff --git a/includes/admin/class-wc-subscriptions-admin.php b/includes/admin/class-wc-subscriptions-admin.php index b7bcdb0..9ee7158 100644 --- a/includes/admin/class-wc-subscriptions-admin.php +++ b/includes/admin/class-wc-subscriptions-admin.php @@ -688,7 +688,8 @@ class WC_Subscriptions_Admin { $dependencies = array( 'jquery' ); - $woocommerce_admin_script_handle = 'wc-admin-meta-boxes'; + $woocommerce_admin_script_handle = 'wc-admin-meta-boxes'; + $trashing_subscription_order_warning = __( 'Trashing this order will also trash the subscriptions purchased with the order.', 'woocommerce-subscriptions' ); if ( $screen->id == 'product' ) { $dependencies[] = $woocommerce_admin_script_handle; @@ -709,6 +710,7 @@ class WC_Subscriptions_Admin { } else if ( 'edit-shop_order' == $screen->id ) { $script_params = array( 'bulkTrashWarning' => __( "You are about to trash one or more orders which contain a subscription.\n\nTrashing the orders will also trash the subscriptions purchased with these orders.", 'woocommerce-subscriptions' ), + 'trashWarning' => $trashing_subscription_order_warning, ); } else if ( 'shop_order' == $screen->id ) { $dependencies[] = $woocommerce_admin_script_handle; @@ -719,7 +721,7 @@ class WC_Subscriptions_Admin { } $script_params = array( - 'bulkTrashWarning' => __( 'Trashing this order will also trash the subscription purchased with the order.', 'woocommerce-subscriptions' ), + 'trashWarning' => $trashing_subscription_order_warning, 'changeMetaWarning' => __( "WARNING: Bad things are about to happen!\n\nThe payment gateway used to purchase this subscription does not support modifying a subscription's details.\n\nChanges to the billing period, recurring discount, recurring tax or recurring total may not be reflected in the amount charged by the payment gateway.", 'woocommerce-subscriptions' ), 'removeItemWarning' => __( 'You are deleting a subscription item. You will also need to manually cancel and trash the subscription on the Manage Subscriptions screen.', 'woocommerce-subscriptions' ), 'roundAtSubtotal' => esc_attr( get_option( 'woocommerce_tax_round_at_subtotal' ) ), diff --git a/includes/admin/meta-boxes/class-wcs-meta-box-related-orders.php b/includes/admin/meta-boxes/class-wcs-meta-box-related-orders.php index 5e73c32..5973902 100644 --- a/includes/admin/meta-boxes/class-wcs-meta-box-related-orders.php +++ b/includes/admin/meta-boxes/class-wcs-meta-box-related-orders.php @@ -110,6 +110,8 @@ class WCS_Meta_Box_Related_Orders { } } + $orders = apply_filters( 'woocommerce_subscriptions_admin_related_orders_to_display', $orders, $subscriptions, $post ); + foreach ( $orders as $order ) { if ( $order->id == $post->ID ) { continue; diff --git a/includes/class-wc-product-subscription-variation.php b/includes/class-wc-product-subscription-variation.php index ebee278..9f7d4cd 100644 --- a/includes/class-wc-product-subscription-variation.php +++ b/includes/class-wc-product-subscription-variation.php @@ -96,11 +96,11 @@ class WC_Product_Subscription_Variation extends WC_Product_Variation { * * @return string */ - public function get_sign_up_fee_including_tax( $qty = 1 ) { + public function get_sign_up_fee_including_tax( $qty = 1, $price = '' ) { add_filter( 'woocommerce_get_price', array( &$this, 'get_sign_up_fee' ), 100, 0 ); - $sign_up_fee_including_tax = parent::get_price_including_tax( $qty ); + $sign_up_fee_including_tax = parent::get_price_including_tax( $qty, $price ); remove_filter( 'woocommerce_get_price', array( &$this, 'get_sign_up_fee' ), 100, 0 ); @@ -113,11 +113,11 @@ class WC_Product_Subscription_Variation extends WC_Product_Variation { * * @return string */ - public function get_sign_up_fee_excluding_tax( $qty = 1 ) { + public function get_sign_up_fee_excluding_tax( $qty = 1, $price = '' ) { add_filter( 'woocommerce_get_price', array( &$this, 'get_sign_up_fee' ), 100, 0 ); - $sign_up_fee_excluding_tax = parent::get_price_excluding_tax( $qty ); + $sign_up_fee_excluding_tax = parent::get_price_excluding_tax( $qty, $price ); remove_filter( 'woocommerce_get_price', array( &$this, 'get_sign_up_fee' ), 100, 0 ); diff --git a/includes/class-wc-product-variable-subscription.php b/includes/class-wc-product-variable-subscription.php index be1f940..ab8f740 100644 --- a/includes/class-wc-product-variable-subscription.php +++ b/includes/class-wc-product-variable-subscription.php @@ -153,6 +153,16 @@ class WC_Product_Variable_Subscription extends WC_Product_Variable { $child_price = ( '' === $child_price ) ? 0 : $child_price; $child_sign_up_fee = ( '' === $child_sign_up_fee ) ? 0 : $child_sign_up_fee; + // Take taxes into a account to avoid displaying a variation with a lower price pre-tax, but higher price post-tax, in the case of variations having different tax classes (see: https://github.com/Prospress/woocommerce-subscriptions/pull/1602#issuecomment-241330131) + if ( $variation = $this->get_child( $child ) ) { + if ( $child_price > 0 ) { + $child_price = ( 'incl' == get_option( 'woocommerce_tax_display_shop' ) ) ? $variation->get_price_including_tax( 1, $child_price ) : $variation->get_price_excluding_tax( 1, $child_price ); + } + if ( $child_sign_up_fee > 0 ) { + $child_sign_up_fee = ( 'incl' == get_option( 'woocommerce_tax_display_shop' ) ) ? $variation->get_sign_up_fee_including_tax( 1, $child_sign_up_fee ) : $variation->get_sign_up_fee_excluding_tax( 1, $child_sign_up_fee ); + } + } + $has_free_trial = ( '' !== $child_free_trial_length && $child_free_trial_length > 0 ) ? true : false; // Determine some recurring price flags @@ -219,7 +229,7 @@ class WC_Product_Variable_Subscription extends WC_Product_Variable { $longest_trial_length = $child_free_trial_length; } - // If the current cheapest variation is also free then the shortest trial period is the most expensive + // If the current cheapest variation is also free, then the shortest trial period is the most expensive if ( 0 == $lowest_price || '' === $lowest_price ) { if ( '' === $shortest_trial_period ) { @@ -413,6 +423,35 @@ class WC_Product_Variable_Subscription extends WC_Product_Variable { } + /** + * Get the min or max variation (active) price. + * + * This is a copy of WooCommerce < 2.4's get_variation_price() method, because 2.4.0 introduced a new + * transient caching system which assumes asort() on prices yields correct results for min/max prices + * (which it does for prices alone, but that's not the full story for subscription prices). Unfortunately, + * the new caching system is also hard to hook into so we'll just use the old system instead as the + * @see self::variable_product_sync() uses the old method also. + * + * @param string $min_or_max - min or max + * @param boolean $display Whether the value is going to be displayed + * @return string + */ + public function get_variation_price( $min_or_max = 'min', $display = false ) { + $variation_id = get_post_meta( $this->id, '_' . $min_or_max . '_price_variation_id', true ); + + if ( $display ) { + if ( $variation = $this->get_child( $variation_id ) ) { + $price = ( 'incl' == get_option( 'woocommerce_tax_display_shop' ) ) ? $variation->get_price_including_tax() : $variation->get_price_excluding_tax(); + } else { + $price = ''; + } + } else { + $price = get_post_meta( $variation_id, '_price', true ); + } + + return apply_filters( 'woocommerce_get_variation_price', $price, $this, $min_or_max, $display ); + } + /** * Returns the price in html format. * diff --git a/includes/class-wc-subscription.php b/includes/class-wc-subscription.php index a051e5a..634603f 100644 --- a/includes/class-wc-subscription.php +++ b/includes/class-wc-subscription.php @@ -1661,11 +1661,11 @@ class WC_Subscription extends WC_Order { * with a 10 BTC sign-up fee was purchased, a total 30 BTC was paid as the sign-up fee but this function will return 10 BTC. * * @param array|int Either an order item (in the array format returned by self::get_items()) or the ID of an order item. - * @param string $tax Whether or not to adjust sign up fee if prices inc tax - ensures that the sign up fee paid amount includes the paid tax if inc + * @param string $tax_inclusive_or_exclusive Whether or not to adjust sign up fee if prices inc tax - ensures that the sign up fee paid amount includes the paid tax if inc * @return bool * @since 2.0 */ - public function get_items_sign_up_fee( $line_item, $tax = 'exclusive_of_tax' ) { + public function get_items_sign_up_fee( $line_item, $tax_inclusive_or_exclusive = 'exclusive_of_tax' ) { if ( ! is_array( $line_item ) ) { $line_item = wcs_get_order_item( $line_item, $this ); @@ -1705,12 +1705,13 @@ class WC_Subscription extends WC_Order { } // If prices inc tax, ensure that the sign up fee amount includes the tax - if ( 'inclusive_of_tax' === $tax && ! empty( $original_order_item ) && ( 'yes' == $this->prices_include_tax || true === $this->prices_include_tax ) ) { - $sign_up_fee += $original_order_item['line_tax']; + if ( 'inclusive_of_tax' === $tax_inclusive_or_exclusive && ! empty( $original_order_item ) && 'yes' == $this->prices_include_tax ) { + $proportion = $sign_up_fee / ( $original_order_item['line_total'] / $original_order_item['qty'] ); + $sign_up_fee += round( $original_order_item['line_tax'] * $proportion, 2 ); } } - return apply_filters( 'woocommerce_subscription_items_sign_up_fee', $sign_up_fee, $line_item, $this ); + return apply_filters( 'woocommerce_subscription_items_sign_up_fee', $sign_up_fee, $line_item, $this, $tax_inclusive_or_exclusive ); } /** diff --git a/includes/class-wc-subscriptions-cart.php b/includes/class-wc-subscriptions-cart.php index 0255599..7bc54f7 100644 --- a/includes/class-wc-subscriptions-cart.php +++ b/includes/class-wc-subscriptions-cart.php @@ -47,6 +47,13 @@ class WC_Subscriptions_Cart { */ private static $shipping_rates = array(); + /** + * A cache of the current recurring cart being calculated + * + * @since 2.0.20 + */ + private static $cached_recurring_cart = null; + /** * Bootstraps the class and hooks required actions & filters. * @@ -110,6 +117,9 @@ class WC_Subscriptions_Cart { // Validate chosen recurring shipping methods add_action( 'woocommerce_after_checkout_validation', __CLASS__ . '::validate_recurring_shipping_methods' ); + + // WooCommerce determines if free shipping is available using the WC->cart total and coupons, we need to recalculate its availability when obtaining shipping methods for a recurring cart + add_filter( 'woocommerce_shipping_free_shipping_is_available', __CLASS__ . '::maybe_recalculate_shipping_method_availability', 10, 2 ); } /** @@ -256,6 +266,9 @@ class WC_Subscriptions_Cart { $recurring_cart->next_payment_date = apply_filters( 'wcs_recurring_cart_next_payment_date', WC_Subscriptions_Product::get_first_renewal_payment_date( $product, $recurring_cart->start_date ), $recurring_cart, $product ); $recurring_cart->end_date = apply_filters( 'wcs_recurring_cart_end_date', WC_Subscriptions_Product::get_expiration_date( $product, $recurring_cart->start_date ), $recurring_cart, $product ); + // Before calculating recurring cart totals, store this recurring cart object + self::$cached_recurring_cart = $recurring_cart; + // No fees recur (yet) $recurring_cart->fees = array(); $recurring_cart->fee_total = 0; @@ -484,7 +497,7 @@ class WC_Subscriptions_Cart { $default_method = $chosen_methods[ $recurring_cart_package_key ]; // Set the chosen shipping method (if available) to workaround WC_Shipping::get_default_method() setting the default shipping method whenever method count changes - } elseif ( isset( $chosen_methods[ $package_index ] ) && $default_method !== $chosen_methods[ $package_index ] ) { + } elseif ( isset( $chosen_methods[ $package_index ] ) && $default_method !== $chosen_methods[ $package_index ] && isset( $available_methods[ $chosen_methods[ $package_index ] ] ) ) { $default_method = $chosen_methods[ $package_index ]; } @@ -1148,14 +1161,47 @@ class WC_Subscriptions_Cart { } /** - * Generate a unqiue package key for a given shipping package to be used for caching package rates. + * Generate a unique package key for a given shipping package to be used for caching package rates. * * @param array $package A shipping package in the form returned by WC_Cart->get_shipping_packages(). * @return string key hash * @since 2.0.18 */ private static function get_package_shipping_rates_cache_key( $package ) { - return md5( implode( array_keys( $package['contents'] ) ) ); + return md5( json_encode( array( array_keys( $package['contents'] ), $package['contents_cost'], $package['applied_coupons'] ) ) ); + } + + /** + * When calculating the free shipping method availability, WC uses the WC->cart object. During shipping calculations for + * recurring carts we need the recurring cart's total and coupons to be the base for checking its availability + * + * @param bool $is_available + * @param array $package + * @return bool $is_available a revised version of is_available based off the recurring cart object + * + * @since 2.0.20 + */ + public static function maybe_recalculate_shipping_method_availability( $is_available, $package ) { + + if ( isset( $package['recurring_cart_key'] ) && isset( self::$cached_recurring_cart ) && $package['recurring_cart_key'] == self::$cached_recurring_cart->recurring_cart_key ) { + + // Take a copy of the WC global cart object so we can temporarily set it to base shipping method availability on the cached recurring cart + $global_cart = WC()->cart; + WC()->cart = self::$cached_recurring_cart; + + foreach ( WC()->shipping->get_shipping_methods() as $shipping_method ) { + if ( $shipping_method->id == 'free_shipping' ) { + remove_filter( 'woocommerce_shipping_free_shipping_is_available', __METHOD__ ); + $is_available = $shipping_method->is_available( $package ); + add_filter( 'woocommerce_shipping_free_shipping_is_available', __METHOD__, 10, 2 ); + break; + } + } + + WC()->cart = $global_cart; + } + + return $is_available; } /* Deprecated */ diff --git a/includes/class-wc-subscriptions-email.php b/includes/class-wc-subscriptions-email.php index 1599160..da12ba1 100644 --- a/includes/class-wc-subscriptions-email.php +++ b/includes/class-wc-subscriptions-email.php @@ -159,8 +159,11 @@ class WC_Subscriptions_Email { 'new_renewal_order', 'customer_processing_renewal_order', 'customer_completed_renewal_order', - 'customer_renewal_invoice', ); + + if ( $theorder->needs_payment() ) { + array_push( $available_emails, 'customer_renewal_invoice' ); + } } return $available_emails; diff --git a/includes/class-wc-subscriptions-manager.php b/includes/class-wc-subscriptions-manager.php index 8975abf..b4a3684 100644 --- a/includes/class-wc-subscriptions-manager.php +++ b/includes/class-wc-subscriptions-manager.php @@ -774,7 +774,7 @@ class WC_Subscriptions_Manager { $subscription = wcs_get_subscription( $post_id ); - if ( ! $subscription->has_status( wcs_get_subscription_ended_statuses() ) ) { + if ( $subscription->can_be_updated_to( 'cancelled' ) ) { $subscription->update_status( 'cancelled' ); diff --git a/includes/class-wc-subscriptions-switcher.php b/includes/class-wc-subscriptions-switcher.php index 204ab60..1f22d6e 100644 --- a/includes/class-wc-subscriptions-switcher.php +++ b/includes/class-wc-subscriptions-switcher.php @@ -93,7 +93,7 @@ class WC_Subscriptions_Switcher { add_filter( 'woocommerce_email_order_items_table', __CLASS__ . '::add_print_switch_link' ); // Make sure sign-up fees paid on switch orders are accounted for in an items sign-up fee - add_filter( 'woocommerce_subscription_items_sign_up_fee', __CLASS__ . '::subscription_items_sign_up_fee', 10, 3 ); + add_filter( 'woocommerce_subscription_items_sign_up_fee', __CLASS__ . '::subscription_items_sign_up_fee', 10, 4 ); // Make sure switch orders are included in related orders returned for a subscription add_filter( 'woocommerce_subscription_related_orders', __CLASS__ . '::add_related_orders', 10, 4 ); @@ -936,6 +936,14 @@ class WC_Subscriptions_Switcher { } if ( $product_id == $item['product_id'] && ( empty( $variation_id ) || ( $variation_id == $item['variation_id'] && true == $identical_attributes ) ) && $quantity == $item['qty'] ) { + $is_identical_product = true; + } else { + $is_identical_product = false; + } + + $is_identical_product = apply_filters( 'woocommerce_subscriptions_switch_is_identical_product', $is_identical_product, $product_id, $quantity, $variation_id, $subscription, $item ); + + if ( $is_identical_product ) { throw new Exception( __( 'You can not switch to the same subscription.', 'woocommerce-subscriptions' ) ); } @@ -1042,10 +1050,11 @@ class WC_Subscriptions_Switcher { * Make sure the sign-up fee on a subscription line item takes into account sign-up fees paid for switching. * * @param WC_Subscription $subscription + * @param string $tax_inclusive_or_exclusive Defaults to the value tax setting stored on the subscription. * @return array $cart_item Details of an item in WC_Cart for a switch * @since 2.0 */ - public static function subscription_items_sign_up_fee( $sign_up_fee, $line_item, $subscription ) { + public static function subscription_items_sign_up_fee( $sign_up_fee, $line_item, $subscription, $tax_inclusive_or_exclusive = '' ) { // This item has never been switched, no need to add anything if ( ! isset( $line_item['switched_subscription_item_id'] ) ) { @@ -1055,9 +1064,14 @@ class WC_Subscriptions_Switcher { // First add any sign-up fees for previously switched items $switched_line_items = $subscription->get_items( 'line_item_switched' ); + // Default tax inclusive or exclusive to the value set on the subscription. This is for backwards compatibility + if ( empty( $tax_inclusive_or_exclusive ) ) { + $tax_inclusive_or_exclusive = ( 'yes' == $subscription->prices_include_tax ) ? 'inclusive_of_tax' : 'exclusive_of_tax'; + } + foreach ( $switched_line_items as $switched_line_item_id => $switched_line_item ) { if ( $line_item['switched_subscription_item_id'] == $switched_line_item_id ) { - $sign_up_fee += $subscription->get_items_sign_up_fee( $switched_line_item ); // Recursion: get the sign up fee for this item's old item and the sign up fee for that item's old item and the sign up fee for that item's old item and the sign up fee for that item's old item ... + $sign_up_fee += $subscription->get_items_sign_up_fee( $switched_line_item, $tax_inclusive_or_exclusive ); // Recursion: get the sign up fee for this item's old item and the sign up fee for that item's old item and the sign up fee for that item's old item and the sign up fee for that item's old item ... break; // Each item can only be switched once } } @@ -1078,7 +1092,13 @@ class WC_Subscriptions_Switcher { $sign_up_proportion = 1; } - $sign_up_fee += round( $order_item['line_total'] * $sign_up_proportion, 2 ); + $order_total = $order_item['line_total']; + + if ( 'inclusive_of_tax' == $tax_inclusive_or_exclusive && 'yes' == $order->prices_include_tax ) { + $order_total += $order_item['line_tax']; + } + + $sign_up_fee += round( $order_total * $sign_up_proportion, 2 ); } } } diff --git a/includes/class-wc-subscriptions-synchroniser.php b/includes/class-wc-subscriptions-synchroniser.php index b56b7db..52530fa 100644 --- a/includes/class-wc-subscriptions-synchroniser.php +++ b/includes/class-wc-subscriptions-synchroniser.php @@ -407,7 +407,7 @@ class WC_Subscriptions_Synchroniser { $product = wc_get_product( $product ); } - if ( ! is_object( $product ) || ! self::is_syncing_enabled() || 'day' == $product->subscription_period || ! $product->is_type( array( 'subscription', 'variable-subscription', 'subscription_variation' ) ) ) { + if ( ! is_object( $product ) || ! self::is_syncing_enabled() || 'day' == $product->subscription_period || ! WC_Subscriptions_Product::is_subscription( $product ) ) { return false; } diff --git a/includes/class-wcs-download-handler.php b/includes/class-wcs-download-handler.php index 308fb76..017d196 100644 --- a/includes/class-wcs-download-handler.php +++ b/includes/class-wcs-download-handler.php @@ -136,8 +136,8 @@ class WCS_Download_Handler { public static function get_item_downloads( $files, $item, $order ) { global $wpdb; - if ( wcs_order_contains_subscription( $order, 'any' ) ) { - $subscriptions = wcs_get_subscriptions_for_order( $order, array( 'order_type' => array( 'any' ) ) ); + if ( wcs_order_contains_subscription( $order, array( 'parent', 'renewal', 'switch' ) ) ) { + $subscriptions = wcs_get_subscriptions_for_order( $order, array( 'order_type' => array( 'parent', 'renewal', 'switch' ) ) ); } else { return $files; } diff --git a/includes/emails/class-wcs-email-customer-renewal-invoice.php b/includes/emails/class-wcs-email-customer-renewal-invoice.php index 0857a19..4dad736 100644 --- a/includes/emails/class-wcs-email-customer-renewal-invoice.php +++ b/includes/emails/class-wcs-email-customer-renewal-invoice.php @@ -35,8 +35,8 @@ class WCS_Email_Customer_Renewal_Invoice extends WC_Email_Customer_Invoice { $this->subject = __( 'Invoice for renewal order {order_number} from {order_date}', 'woocommerce-subscriptions' ); $this->heading = __( 'Invoice for renewal order {order_number}', 'woocommerce-subscriptions' ); - $this->subject_paid = __( 'Your {blogname} renewal order from {order_date}', 'woocommerce-subscriptions' ); - $this->heading_paid = __( 'Renewal order {order_number} details', 'woocommerce-subscriptions' ); + $this->subject_paid = null; + $this->heading_paid = null; // Triggers for this email add_action( 'woocommerce_generated_manual_renewal_order_renewal_notification', array( $this, 'trigger' ) ); @@ -160,6 +160,14 @@ class WCS_Email_Customer_Renewal_Invoice extends WC_Email_Customer_Invoice { parent::init_form_fields(); + if ( isset( $this->form_fields['heading_paid'] ) ) { + unset( $this->form_fields['heading_paid'] ); + } + + if ( isset( $this->form_fields['subject_paid'] ) ) { + unset( $this->form_fields['subject_paid'] ); + } + $this->form_fields = array_merge( array( 'enabled' => array( diff --git a/includes/gateways/paypal/includes/admin/class-wcs-paypal-admin.php b/includes/gateways/paypal/includes/admin/class-wcs-paypal-admin.php index 7252ce1..02aac90 100644 --- a/includes/gateways/paypal/includes/admin/class-wcs-paypal-admin.php +++ b/includes/gateways/paypal/includes/admin/class-wcs-paypal-admin.php @@ -33,6 +33,9 @@ class WCS_PayPal_Admin { // Maybe show notice to enter PayPal API credentials add_action( 'admin_notices', __CLASS__ . '::maybe_show_admin_notices' ); + + // Add the PayPal subscription information to the billing information + add_action( 'woocommerce_admin_order_data_after_billing_address', __CLASS__ . '::profile_link' ); } /** @@ -212,4 +215,42 @@ class WCS_PayPal_Admin { do_action( 'wcs_paypal_admin_update_credentials' ); } + + /** + * Prints link to the PayPal's profile related to the provided subscription + * + * @param WC_Subscription $subscription + */ + public static function profile_link( $subscription ) { + if ( wcs_is_subscription( $subscription ) && 'paypal' == $subscription->payment_method ) { + + $paypal_profile_id = wcs_get_paypal_id( $subscription ); + + if ( ! empty( $paypal_profile_id ) ) { + + $url = ''; + + if ( false === wcs_is_paypal_profile_a( $paypal_profile_id, 'billing_agreement' ) ) { + // Standard subscription + $url = 'https://www.paypal.com/?cmd=_profile-recurring-payments&encrypted_profile_id=' . $paypal_profile_id; + } else if ( wcs_is_paypal_profile_a( $paypal_profile_id, 'billing_agreement' ) ) { + // Reference Transaction subscription + $url = 'https://www.paypal.com/?cmd=_profile-merchant-pull&encrypted_profile_id=' . $paypal_profile_id . '&mp_id=' . $paypal_profile_id . '&return_to=merchant&flag_flow=merchant'; + } + + echo '
'; + echo '

'; + echo esc_html( __( 'PayPal Subscription ID:', 'woocommerce-subscriptions' ) ); + echo ''; + if ( ! empty( $url ) ) { + echo '' . esc_html( $paypal_profile_id ) . ''; + } else { + echo esc_html( $paypal_profile_id ); + } + echo '

'; + } + } + + } + } diff --git a/includes/gateways/paypal/includes/class-wcs-paypal-standard-ipn-handler.php b/includes/gateways/paypal/includes/class-wcs-paypal-standard-ipn-handler.php index 6c61b1d..ec4f5b1 100644 --- a/includes/gateways/paypal/includes/class-wcs-paypal-standard-ipn-handler.php +++ b/includes/gateways/paypal/includes/class-wcs-paypal-standard-ipn-handler.php @@ -252,11 +252,11 @@ class WCS_PayPal_Standard_IPN_Handler extends WC_Gateway_Paypal_IPN_Handler { self::cancel_subscription( $subscription, get_post_meta( $subscription->id, '_old_paypal_subscriber_id', true ) ); } - $subscription->add_order_note( _x( 'IPN subscription payment method changed to PayPal.', 'when it is a payment change, and there is a subscr_signup message, this will be a confirmation message that PayPal accepted it being the new payment method', 'woocommerce-subscriptions' ) ); + $this->add_order_note( _x( 'IPN subscription payment method changed to PayPal.', 'when it is a payment change, and there is a subscr_signup message, this will be a confirmation message that PayPal accepted it being the new payment method', 'woocommerce-subscriptions' ), $subscription, $transaction_details ); } else { - $subscription->add_order_note( __( 'IPN subscription sign up completed.', 'woocommerce-subscriptions' ) ); + $this->add_order_note( __( 'IPN subscription sign up completed.', 'woocommerce-subscriptions' ), $subscription, $transaction_details ); } @@ -296,7 +296,7 @@ class WCS_PayPal_Standard_IPN_Handler extends WC_Gateway_Paypal_IPN_Handler { $this->save_paypal_meta_data( $subscription, $transaction_details ); // Subscription Payment completed - $subscription->add_order_note( __( 'IPN subscription payment completed.', 'woocommerce-subscriptions' ) ); + $this->add_order_note( __( 'IPN subscription payment completed.', 'woocommerce-subscriptions' ), $subscription, $transaction_details ); WC_Gateway_Paypal::log( 'IPN subscription payment completed for subscription ' . $subscription->id ); @@ -335,7 +335,7 @@ class WCS_PayPal_Standard_IPN_Handler extends WC_Gateway_Paypal_IPN_Handler { self::cancel_subscription( $subscription, $profile_id ); } - $subscription->add_order_note( __( 'IPN subscription failing payment method changed.', 'woocommerce-subscriptions' ) ); + $this->add_order_note( __( 'IPN subscription failing payment method changed.', 'woocommerce-subscriptions' ), $subscription, $transaction_details ); } } @@ -373,7 +373,7 @@ class WCS_PayPal_Standard_IPN_Handler extends WC_Gateway_Paypal_IPN_Handler { WC_Gateway_Paypal::log( sprintf( 'IPN subscription payment exception calling $renewal_order->payment_complete() for subscription %d: %s.', $subscription->id, $e->getMessage() ) ); } - $renewal_order->add_order_note( __( 'IPN subscription payment completed.', 'woocommerce-subscriptions' ) ); + $this->add_order_note( __( 'IPN subscription payment completed.', 'woocommerce-subscriptions' ), $renewal_order, $transaction_details ); add_action( 'woocommerce_subscription_activated_paypal', 'WCS_PayPal_Status_Manager::reactivate_subscription' ); @@ -383,14 +383,14 @@ class WCS_PayPal_Standard_IPN_Handler extends WC_Gateway_Paypal_IPN_Handler { // Subscription Payment completed // translators: placeholder is payment status (e.g. "completed") - $subscription->add_order_note( sprintf( _x( 'IPN subscription payment %s.', 'used in order note', 'woocommerce-subscriptions' ), $transaction_details['payment_status'] ) ); + $this->add_order_note( sprintf( _x( 'IPN subscription payment %s.', 'used in order note', 'woocommerce-subscriptions' ), $transaction_details['payment_status'] ), $subscription, $transaction_details ); if ( ! $is_first_payment ) { update_post_meta( $renewal_order->id, '_transaction_id', $transaction_details['txn_id'] ); // translators: placeholder is payment status (e.g. "completed") - $renewal_order->add_order_note( sprintf( _x( 'IPN subscription payment %s.', 'used in order note', 'woocommerce-subscriptions' ), $transaction_details['payment_status'] ) ); + $this->add_order_note( sprintf( _x( 'IPN subscription payment %s.', 'used in order note', 'woocommerce-subscriptions' ), $transaction_details['payment_status'] ), $renewal_order, $transaction_details ); $subscription->payment_failed(); } @@ -461,13 +461,13 @@ class WCS_PayPal_Standard_IPN_Handler extends WC_Gateway_Paypal_IPN_Handler { // Set PayPal as the payment method $available_gateways = WC()->payment_gateways->get_available_payment_gateways(); $renewal_order->set_payment_method( $available_gateways['paypal'] ); - $renewal_order->add_order_note( $ipn_failure_note ); + $this->add_order_note( $ipn_failure_note, $renewal_order, $transaction_details ); } WC_Gateway_Paypal::log( 'IPN subscription payment failure for subscription ' . $subscription->id ); // Subscription Payment completed - $subscription->add_order_note( $ipn_failure_note ); + $this->add_order_note( $ipn_failure_note, $subscription, $transaction_details ); try { $subscription->payment_failed(); @@ -654,4 +654,19 @@ class WCS_PayPal_Standard_IPN_Handler extends WC_Gateway_Paypal_IPN_Handler { return false; } } + + /** + * Add an note for the given order or subscription + * + * @param string $note The text note + * @param WC_Order $order An order object + * @param array $transaction_details The transaction details, as provided by PayPal + * @since 2.0.20 + */ + protected function add_order_note( $note, $order, $transaction_details ) { + $note = apply_filters( 'wcs_paypal_ipn_note', $note, $order, $transaction_details ); + if ( ! empty( $note ) ) { + $order->add_order_note( $note ); + } + } } diff --git a/includes/wcs-cart-functions.php b/includes/wcs-cart-functions.php index 63386ec..5f4880a 100644 --- a/includes/wcs-cart-functions.php +++ b/includes/wcs-cart-functions.php @@ -109,7 +109,7 @@ function wcs_cart_totals_shipping_html() { ); $show_package_name = false; } - do_action( 'woocommerce_subscriptions_after_recurring_shipping_rates', $index, $base_package, $recurring_cart ); + do_action( 'woocommerce_subscriptions_after_recurring_shipping_rates', $index, $base_package, $recurring_cart, $chosen_recurring_method ); } } } diff --git a/includes/wcs-user-functions.php b/includes/wcs-user-functions.php index 5925772..c915661 100644 --- a/includes/wcs-user-functions.php +++ b/includes/wcs-user-functions.php @@ -157,7 +157,7 @@ function wcs_get_users_subscriptions( $user_id = 0 ) { $subscriptions = apply_filters( 'wcs_pre_get_users_subscriptions', array(), $user_id ); - if ( empty( $subscriptions ) ) { + if ( empty( $subscriptions ) && 0 !== $user_id && ! empty( $user_id ) ) { $post_ids = get_posts( array( 'posts_per_page' => -1, @@ -309,7 +309,7 @@ function wcs_user_has_capability( $allcaps, $caps, $args ) { $user_id = $args[1]; $subscription = wcs_get_subscription( $args[2] ); - if ( $user_id === $subscription->get_user_id() ) { + if ( $subscription && $user_id === $subscription->get_user_id() ) { $allcaps['edit_shop_subscription_payment_method'] = true; } break; diff --git a/languages/woocommerce-subscriptions.pot b/languages/woocommerce-subscriptions.pot index 7991160..ecafd58 100644 --- a/languages/woocommerce-subscriptions.pot +++ b/languages/woocommerce-subscriptions.pot @@ -2,10 +2,10 @@ # This file is distributed under the same license as the WooCommerce Subscriptions package. msgid "" msgstr "" -"Project-Id-Version: WooCommerce Subscriptions 2.0.19\n" +"Project-Id-Version: WooCommerce Subscriptions 2.0.20\n" "Report-Msgid-Bugs-To: " "https://github.com/Prospress/woocommerce-subscriptions/issues\n" -"POT-Creation-Date: 2016-08-12 22:45:52+00:00\n" +"POT-Creation-Date: 2016-09-23 23:32:44+00:00\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=utf-8\n" "Content-Transfer-Encoding: 8bit\n" @@ -138,21 +138,27 @@ msgid "" "the subscription to activate it." msgstr "" -#: includes/admin/class-wc-subscriptions-admin.php:704 -msgid "Enter the new period, either day, week, month or year:" +#: includes/admin/class-wc-subscriptions-admin.php:692 +msgid "" +"Trashing this order will also trash the subscriptions purchased with the " +"order." msgstr "" #: includes/admin/class-wc-subscriptions-admin.php:705 -msgid "Enter a new length (e.g. 5):" +msgid "Enter the new period, either day, week, month or year:" msgstr "" #: includes/admin/class-wc-subscriptions-admin.php:706 +msgid "Enter a new length (e.g. 5):" +msgstr "" + +#: includes/admin/class-wc-subscriptions-admin.php:707 msgid "" "Enter a new interval as a single number (e.g. to charge every 2nd month, " "enter 2):" msgstr "" -#: includes/admin/class-wc-subscriptions-admin.php:711 +#: includes/admin/class-wc-subscriptions-admin.php:712 msgid "" "You are about to trash one or more orders which contain a subscription.\n" "\n" @@ -160,13 +166,7 @@ msgid "" "orders." msgstr "" -#: includes/admin/class-wc-subscriptions-admin.php:722 -msgid "" -"Trashing this order will also trash the subscription purchased with the " -"order." -msgstr "" - -#: includes/admin/class-wc-subscriptions-admin.php:723 +#: includes/admin/class-wc-subscriptions-admin.php:725 msgid "" "WARNING: Bad things are about to happen!\n" "\n" @@ -178,13 +178,13 @@ msgid "" "gateway." msgstr "" -#: includes/admin/class-wc-subscriptions-admin.php:724 +#: includes/admin/class-wc-subscriptions-admin.php:726 msgid "" "You are deleting a subscription item. You will also need to manually cancel " "and trash the subscription on the Manage Subscriptions screen." msgstr "" -#: includes/admin/class-wc-subscriptions-admin.php:731 +#: includes/admin/class-wc-subscriptions-admin.php:733 msgid "" "Warning: Deleting a user will also delete the user's subscriptions. The " "user's orders will remain but be reassigned to the 'Guest' user.\n" @@ -193,28 +193,28 @@ msgid "" "subscriptions?" msgstr "" -#: includes/admin/class-wc-subscriptions-admin.php:794 +#: includes/admin/class-wc-subscriptions-admin.php:796 msgid "Active Subscriber?" msgstr "" -#: includes/admin/class-wc-subscriptions-admin.php:837 +#: includes/admin/class-wc-subscriptions-admin.php:839 msgid "Manage Subscriptions" msgstr "" -#: includes/admin/class-wc-subscriptions-admin.php:841 +#: includes/admin/class-wc-subscriptions-admin.php:843 #: woocommerce-subscriptions.php:209 msgid "Search Subscriptions" msgstr "" -#: includes/admin/class-wc-subscriptions-admin.php:861 -#: includes/admin/class-wc-subscriptions-admin.php:957 +#: includes/admin/class-wc-subscriptions-admin.php:863 +#: includes/admin/class-wc-subscriptions-admin.php:959 #: includes/class-wcs-query.php:90 includes/class-wcs-query.php:110 #: includes/class-wcs-query.php:112 woocommerce-subscriptions.php:200 #: woocommerce-subscriptions.php:213 msgid "Subscriptions" msgstr "" -#: includes/admin/class-wc-subscriptions-admin.php:1004 +#: includes/admin/class-wc-subscriptions-admin.php:1006 #. translators: $1-2: opening and closing tags of a link that takes to PayPal #. settings, $3-4: opening and closing tags of a link that takes to Woo #. marketplace / Stripe product page @@ -224,34 +224,34 @@ msgid "" "%3$sfree Stripe extension%4$s if you want to process automatic payments." msgstr "" -#: includes/admin/class-wc-subscriptions-admin.php:1007 +#: includes/admin/class-wc-subscriptions-admin.php:1009 #. translators: placeholder is name of a gateway msgid "The %s gateway can process automatic subscription payments." msgstr "" -#: includes/admin/class-wc-subscriptions-admin.php:1010 +#: includes/admin/class-wc-subscriptions-admin.php:1012 #. translators: %1$s - a comma separated list of gateway names (e.g. "stripe, #. paypal, worldpay"), %2$s - one name of gateway (e.g. "authorize.net") msgid "The %1$s & %2$s gateways can process automatic subscription payments." msgstr "" -#: includes/admin/class-wc-subscriptions-admin.php:1016 +#: includes/admin/class-wc-subscriptions-admin.php:1018 msgid "Button Text" msgstr "" -#: includes/admin/class-wc-subscriptions-admin.php:1023 +#: includes/admin/class-wc-subscriptions-admin.php:1025 msgid "Add to Cart Button Text" msgstr "" -#: includes/admin/class-wc-subscriptions-admin.php:1024 +#: includes/admin/class-wc-subscriptions-admin.php:1026 msgid "" "A product displays a button with the text \"Add to Cart\". By default, a " "subscription changes this to \"Sign Up Now\". You can customise the button " "text for subscriptions here." msgstr "" -#: includes/admin/class-wc-subscriptions-admin.php:1028 -#: includes/admin/class-wc-subscriptions-admin.php:1039 +#: includes/admin/class-wc-subscriptions-admin.php:1030 +#: includes/admin/class-wc-subscriptions-admin.php:1041 #: includes/class-wc-product-subscription-variation.php:75 #: includes/class-wc-product-subscription.php:115 #: includes/class-wc-product-variable-subscription.php:101 @@ -260,11 +260,11 @@ msgstr "" msgid "Sign Up Now" msgstr "" -#: includes/admin/class-wc-subscriptions-admin.php:1034 +#: includes/admin/class-wc-subscriptions-admin.php:1036 msgid "Place Order Button Text" msgstr "" -#: includes/admin/class-wc-subscriptions-admin.php:1035 +#: includes/admin/class-wc-subscriptions-admin.php:1037 msgid "" "Use this field to customise the text displayed on the checkout button when " "an order contains a subscription. Normally the checkout submission button " @@ -272,11 +272,11 @@ msgid "" "changed to \"Sign Up Now\"." msgstr "" -#: includes/admin/class-wc-subscriptions-admin.php:1047 +#: includes/admin/class-wc-subscriptions-admin.php:1049 msgid "Roles" msgstr "" -#: includes/admin/class-wc-subscriptions-admin.php:1050 +#: includes/admin/class-wc-subscriptions-admin.php:1052 #. translators: placeholders are tags msgid "" "Choose the default roles to assign to active and inactive subscribers. For " @@ -285,46 +285,46 @@ msgid "" "allocated these roles to prevent locking out administrators." msgstr "" -#: includes/admin/class-wc-subscriptions-admin.php:1055 +#: includes/admin/class-wc-subscriptions-admin.php:1057 msgid "Subscriber Default Role" msgstr "" -#: includes/admin/class-wc-subscriptions-admin.php:1056 +#: includes/admin/class-wc-subscriptions-admin.php:1058 msgid "" "When a subscription is activated, either manually or after a successful " "purchase, new users will be assigned this role." msgstr "" -#: includes/admin/class-wc-subscriptions-admin.php:1067 +#: includes/admin/class-wc-subscriptions-admin.php:1069 msgid "Inactive Subscriber Role" msgstr "" -#: includes/admin/class-wc-subscriptions-admin.php:1068 +#: includes/admin/class-wc-subscriptions-admin.php:1070 msgid "" "If a subscriber's subscription is manually cancelled or expires, she will " "be assigned this role." msgstr "" -#: includes/admin/class-wc-subscriptions-admin.php:1088 +#: includes/admin/class-wc-subscriptions-admin.php:1090 msgid "Manual Renewal Payments" msgstr "" -#: includes/admin/class-wc-subscriptions-admin.php:1089 +#: includes/admin/class-wc-subscriptions-admin.php:1091 msgid "Accept Manual Renewals" msgstr "" -#: includes/admin/class-wc-subscriptions-admin.php:1094 +#: includes/admin/class-wc-subscriptions-admin.php:1096 #. translators: placeholders are opening and closing link tags msgid "" "With manual renewals, a customer's subscription is put on-hold until they " "login and pay to renew it. %sLearn more%s." msgstr "" -#: includes/admin/class-wc-subscriptions-admin.php:1100 +#: includes/admin/class-wc-subscriptions-admin.php:1102 msgid "Turn off Automatic Payments" msgstr "" -#: includes/admin/class-wc-subscriptions-admin.php:1105 +#: includes/admin/class-wc-subscriptions-admin.php:1107 #. translators: placeholders are opening and closing link tags msgid "" "If you never want a customer to be automatically charged for a subscription " @@ -332,11 +332,11 @@ msgid "" "more%s." msgstr "" -#: includes/admin/class-wc-subscriptions-admin.php:1120 +#: includes/admin/class-wc-subscriptions-admin.php:1122 msgid "Customer Suspensions" msgstr "" -#: includes/admin/class-wc-subscriptions-admin.php:1127 +#: includes/admin/class-wc-subscriptions-admin.php:1129 msgid "" "Set a maximum number of times a customer can suspend their account for each " "billing period. For example, for a value of 3 and a subscription billed " @@ -346,28 +346,28 @@ msgid "" "Set this to 0 to turn off the customer suspension feature completely." msgstr "" -#: includes/admin/class-wc-subscriptions-admin.php:1131 +#: includes/admin/class-wc-subscriptions-admin.php:1133 msgid "Mixed Checkout" msgstr "" -#: includes/admin/class-wc-subscriptions-admin.php:1132 +#: includes/admin/class-wc-subscriptions-admin.php:1134 msgid "Allow subscriptions and products to be purchased simultaneously." msgstr "" -#: includes/admin/class-wc-subscriptions-admin.php:1136 +#: includes/admin/class-wc-subscriptions-admin.php:1138 msgid "Allow subscriptions and products to be purchased in a single transaction." msgstr "" -#: includes/admin/class-wc-subscriptions-admin.php:1140 +#: includes/admin/class-wc-subscriptions-admin.php:1142 #: includes/upgrades/templates/wcs-about.php:108 msgid "Drip Downloadable Content" msgstr "" -#: includes/admin/class-wc-subscriptions-admin.php:1141 +#: includes/admin/class-wc-subscriptions-admin.php:1143 msgid "Enable dripping for downloadable content on subscription products." msgstr "" -#: includes/admin/class-wc-subscriptions-admin.php:1145 +#: includes/admin/class-wc-subscriptions-admin.php:1147 msgid "" "Enabling this grants access to new downloadable files added to a product " "only after the next renewal is processed.%sBy default, access to new " @@ -375,18 +375,18 @@ msgid "" "customer that has an active subscription with that product." msgstr "" -#: includes/admin/class-wc-subscriptions-admin.php:1151 +#: includes/admin/class-wc-subscriptions-admin.php:1153 msgid "Payment Gateways" msgstr "" -#: includes/admin/class-wc-subscriptions-admin.php:1159 +#: includes/admin/class-wc-subscriptions-admin.php:1161 #. translators: placeholders are opening and closing link tags msgid "" "Other payment gateways can be used to process %smanual subscription renewal " "payments%s only." msgstr "" -#: includes/admin/class-wc-subscriptions-admin.php:1166 +#: includes/admin/class-wc-subscriptions-admin.php:1168 #. translators: $1-$2: opening and closing tags. Link to documents->payment #. gateways, 3$-4$: opening and closing tags. Link to woothemes extensions shop #. page @@ -395,7 +395,7 @@ msgid "" "the official %3$sWooCommerce Marketplace%4$s." msgstr "" -#: includes/admin/class-wc-subscriptions-admin.php:1203 +#: includes/admin/class-wc-subscriptions-admin.php:1205 #. translators: $1-$2: opening and closing tags, $3-$4: opening and #. closing tags msgid "" @@ -403,52 +403,52 @@ msgid "" "start selling subscriptions!%4$s" msgstr "" -#: includes/admin/class-wc-subscriptions-admin.php:1208 +#: includes/admin/class-wc-subscriptions-admin.php:1210 msgid "Add a Subscription Product" msgstr "" -#: includes/admin/class-wc-subscriptions-admin.php:1209 +#: includes/admin/class-wc-subscriptions-admin.php:1211 #: includes/upgrades/templates/wcs-about.php:35 #: woocommerce-subscriptions.php:960 msgid "Settings" msgstr "" -#: includes/admin/class-wc-subscriptions-admin.php:1295 +#: includes/admin/class-wc-subscriptions-admin.php:1297 #. translators: placeholder is a number msgid "We can't find a subscription with ID #%d. Perhaps it was deleted?" msgstr "" -#: includes/admin/class-wc-subscriptions-admin.php:1328 -#: includes/admin/class-wc-subscriptions-admin.php:1333 +#: includes/admin/class-wc-subscriptions-admin.php:1330 +#: includes/admin/class-wc-subscriptions-admin.php:1335 #. translators: placeholders are opening link tag, ID of sub, and closing link #. tag msgid "Showing orders for %sSubscription %s%s" msgstr "" -#: includes/admin/class-wc-subscriptions-admin.php:1357 +#: includes/admin/class-wc-subscriptions-admin.php:1359 #. translators: number of 1$: days, 2$: weeks, 3$: months, 4$: years msgid "The trial period can not exceed: %1s, %2s, %3s or %4s." msgstr "" -#: includes/admin/class-wc-subscriptions-admin.php:1362 +#: includes/admin/class-wc-subscriptions-admin.php:1364 #. translators: placeholder is a time period (e.g. "4 weeks") msgid "The trial period can not exceed %s." msgstr "" -#: includes/admin/class-wc-subscriptions-admin.php:1418 -#: includes/admin/class-wc-subscriptions-admin.php:1471 +#: includes/admin/class-wc-subscriptions-admin.php:1420 +#: includes/admin/class-wc-subscriptions-admin.php:1473 msgid "Yes" msgstr "" -#: includes/admin/class-wc-subscriptions-admin.php:1418 +#: includes/admin/class-wc-subscriptions-admin.php:1420 msgid "No" msgstr "" -#: includes/admin/class-wc-subscriptions-admin.php:1454 +#: includes/admin/class-wc-subscriptions-admin.php:1456 msgid "Automatic Recurring Payments" msgstr "" -#: includes/admin/class-wc-subscriptions-admin.php:1471 +#: includes/admin/class-wc-subscriptions-admin.php:1473 msgid "" "Supports automatic renewal payments with the WooCommerce Subscriptions " "extension." @@ -942,21 +942,21 @@ msgstr "" msgid "Update the %1$s used for %2$sall%3$s of my active subscriptions" msgstr "" -#: includes/class-wc-subscriptions-cart.php:823 +#: includes/class-wc-subscriptions-cart.php:836 msgid "Please enter a valid postcode/ZIP." msgstr "" -#: includes/class-wc-subscriptions-cart.php:994 +#: includes/class-wc-subscriptions-cart.php:1007 msgid "" "That subscription product can not be added to your cart as it already " "contains a subscription renewal." msgstr "" -#: includes/class-wc-subscriptions-cart.php:1079 +#: includes/class-wc-subscriptions-cart.php:1092 msgid "Invalid recurring shipping method." msgstr "" -#: includes/class-wc-subscriptions-cart.php:2014 +#: includes/class-wc-subscriptions-cart.php:2060 msgid "now" msgstr "" @@ -1405,7 +1405,7 @@ msgstr "" #: includes/class-wc-subscriptions-switcher.php:398 #: includes/class-wc-subscriptions-switcher.php:424 -#: includes/class-wc-subscriptions-switcher.php:1858 +#: includes/class-wc-subscriptions-switcher.php:1878 msgid "Upgrade or Downgrade" msgstr "" @@ -1421,17 +1421,17 @@ msgstr "" msgid "We can not find your old subscription item." msgstr "" -#: includes/class-wc-subscriptions-switcher.php:939 +#: includes/class-wc-subscriptions-switcher.php:947 msgid "You can not switch to the same subscription." msgstr "" -#: includes/class-wc-subscriptions-switcher.php:986 +#: includes/class-wc-subscriptions-switcher.php:994 msgid "" "You can not switch this subscription. It appears you do not own the " "subscription." msgstr "" -#: includes/class-wc-subscriptions-switcher.php:1021 +#: includes/class-wc-subscriptions-switcher.php:1029 msgid "There was an error locating the switch details." msgstr "" @@ -1651,7 +1651,7 @@ msgid "Subscription Cancelled" msgstr "" #: includes/emails/class-wcs-email-cancelled-subscription.php:122 -#: includes/emails/class-wcs-email-customer-renewal-invoice.php:168 +#: includes/emails/class-wcs-email-customer-renewal-invoice.php:176 msgid "Enable this email notification" msgstr "" @@ -1756,14 +1756,6 @@ msgstr "" msgid "Invoice for renewal order {order_number}" msgstr "" -#: includes/emails/class-wcs-email-customer-renewal-invoice.php:38 -msgid "Your {blogname} renewal order from {order_date}" -msgstr "" - -#: includes/emails/class-wcs-email-customer-renewal-invoice.php:39 -msgid "Renewal order {order_number} details" -msgstr "" - #: includes/emails/class-wcs-email-new-renewal-order.php:22 msgid "New Renewal Order" msgstr "" @@ -1839,14 +1831,14 @@ msgid "" "This will suspend the subscription at PayPal." msgstr "" -#: includes/gateways/paypal/includes/admin/class-wcs-paypal-admin.php:53 +#: includes/gateways/paypal/includes/admin/class-wcs-paypal-admin.php:56 msgid "" "It is strongly recommended you do not change the Receiver Email " "address if you have active subscriptions with PayPal. Doing so can " "break existing subscriptions." msgstr "" -#: includes/gateways/paypal/includes/admin/class-wcs-paypal-admin.php:106 +#: includes/gateways/paypal/includes/admin/class-wcs-paypal-admin.php:109 #. translators: placeholders are opening and closing link tags. 1$-2$: to docs #. on woothemes, 3$-4$ to gateway settings on the site msgid "" @@ -1855,7 +1847,7 @@ msgid "" "Subscriptions." msgstr "" -#: includes/gateways/paypal/includes/admin/class-wcs-paypal-admin.php:119 +#: includes/gateways/paypal/includes/admin/class-wcs-paypal-admin.php:122 #. translators: placeholders are opening and closing strong and link tags. #. 1$-2$: strong tags, 3$-8$ link to docs on woothemes msgid "" @@ -1865,14 +1857,14 @@ msgid "" "%5$sCheck PayPal Account%6$s %7$sLearn more %8$s" msgstr "" -#: includes/gateways/paypal/includes/admin/class-wcs-paypal-admin.php:137 +#: includes/gateways/paypal/includes/admin/class-wcs-paypal-admin.php:140 #. translators: placeholders are opening and closing strong tags. msgid "" "%1$sPayPal Reference Transactions are enabled on your account%2$s. All " "subscription management features are now enabled. Happy selling!" msgstr "" -#: includes/gateways/paypal/includes/admin/class-wcs-paypal-admin.php:148 +#: includes/gateways/paypal/includes/admin/class-wcs-paypal-admin.php:151 #. translators: placeholders are link opening and closing tags. 1$-2$: to #. gateway settings, 3$-4$: support docs on woothemes.com msgid "" @@ -1880,7 +1872,7 @@ msgid "" "Please update your %1$sAPI credentials%2$s. %3$sLearn more%4$s." msgstr "" -#: includes/gateways/paypal/includes/admin/class-wcs-paypal-admin.php:161 +#: includes/gateways/paypal/includes/admin/class-wcs-paypal-admin.php:164 #. translators: placeholders are opening and closing link tags. 1$-2$: docs on #. woothemes, 3$-4$: dismiss link msgid "" @@ -1888,6 +1880,10 @@ msgid "" "subscription IDs. %1$sLearn more%2$s. %3$sDismiss%4$s." msgstr "" +#: includes/gateways/paypal/includes/admin/class-wcs-paypal-admin.php:243 +msgid "PayPal Subscription ID:" +msgstr "" + #: includes/gateways/paypal/includes/class-wcs-paypal-reference-transaction-api-request.php:274 msgid "Total Discount" msgstr "" @@ -2576,7 +2572,7 @@ msgstr "" #: templates/emails/admin-new-renewal-order.php:65 #: templates/emails/customer-processing-renewal-order.php:65 #: templates/emails/plain/admin-new-renewal-order.php:50 -#: templates/myaccount/view-subscription.php:241 +#: templates/myaccount/view-subscription.php:243 msgid "Customer details" msgstr "" @@ -2745,31 +2741,31 @@ msgstr "" msgid "My Account" msgstr "" -#: templates/myaccount/view-subscription.php:56 +#: templates/myaccount/view-subscription.php:57 msgid "Actions" msgstr "" -#: templates/myaccount/view-subscription.php:67 +#: templates/myaccount/view-subscription.php:69 msgid "Subscription Updates" msgstr "" -#: templates/myaccount/view-subscription.php:86 +#: templates/myaccount/view-subscription.php:88 msgid "Subscription Totals" msgstr "" -#: templates/myaccount/view-subscription.php:108 +#: templates/myaccount/view-subscription.php:110 msgid "Are you sure you want remove this item from your subscription?" msgstr "" -#: templates/myaccount/view-subscription.php:222 +#: templates/myaccount/view-subscription.php:224 msgid "Refunded:" msgstr "" -#: templates/myaccount/view-subscription.php:269 wcs-functions.php:254 +#: templates/myaccount/view-subscription.php:271 wcs-functions.php:254 msgid "Billing Address" msgstr "" -#: templates/myaccount/view-subscription.php:288 wcs-functions.php:253 +#: templates/myaccount/view-subscription.php:290 wcs-functions.php:253 msgid "Shipping Address" msgstr "" @@ -2991,7 +2987,7 @@ msgid "" "subscription. %s" msgstr "" -#: includes/admin/class-wc-subscriptions-admin.php:749 +#: includes/admin/class-wc-subscriptions-admin.php:751 #. translators: placeholders are for HTML tags. They are 1$: "

", 2$: #. "

", 3$: "

", 4$: "", 5$: "", 6$: "", 7$: "", 8$: #. "

" @@ -3002,7 +2998,7 @@ msgid "" "%6$sVariable subscription%7$s.%8$s" msgstr "" -#: includes/admin/class-wc-subscriptions-admin.php:751 +#: includes/admin/class-wc-subscriptions-admin.php:753 #. translators: placeholders are for HTML tags. They are 1$: "

", 2$: #. "

", 3$: "

", 4$: "

" msgctxt "used in admin pointer script params in javascript as price pointer content" @@ -3012,48 +3008,48 @@ msgid "" "sign-up fee and free trial.%4$s" msgstr "" -#: includes/admin/class-wc-subscriptions-admin.php:1081 +#: includes/admin/class-wc-subscriptions-admin.php:1083 msgctxt "option section heading" msgid "Renewals" msgstr "" -#: includes/admin/class-wc-subscriptions-admin.php:1113 +#: includes/admin/class-wc-subscriptions-admin.php:1115 msgctxt "options section heading" msgid "Miscellaneous" msgstr "" -#: includes/admin/class-wc-subscriptions-admin.php:1121 +#: includes/admin/class-wc-subscriptions-admin.php:1123 msgctxt "there's a number immediately in front of this text" msgid "suspensions per billing period." msgstr "" -#: includes/admin/class-wc-subscriptions-admin.php:1388 +#: includes/admin/class-wc-subscriptions-admin.php:1390 msgctxt "in [subscriptions] shortcode" msgid "No subscriptions found." msgstr "" -#: includes/admin/class-wc-subscriptions-admin.php:1397 +#: includes/admin/class-wc-subscriptions-admin.php:1399 #. translators: order number msgctxt "in [subscriptions] shortcode" msgid "Subscription %s" msgstr "" -#: includes/admin/class-wc-subscriptions-admin.php:1417 +#: includes/admin/class-wc-subscriptions-admin.php:1419 msgctxt "label that indicates whether debugging is turned on for the plugin" msgid "WCS_DEBUG" msgstr "" -#: includes/admin/class-wc-subscriptions-admin.php:1423 +#: includes/admin/class-wc-subscriptions-admin.php:1425 msgctxt "Live or Staging, Label on WooCommerce -> System Status page" msgid "Subscriptions Mode" msgstr "" -#: includes/admin/class-wc-subscriptions-admin.php:1424 +#: includes/admin/class-wc-subscriptions-admin.php:1426 msgctxt "refers to staging site" msgid "Staging" msgstr "" -#: includes/admin/class-wc-subscriptions-admin.php:1424 +#: includes/admin/class-wc-subscriptions-admin.php:1426 msgctxt "refers to live site" msgid "Live" msgstr "" @@ -3170,7 +3166,7 @@ msgstr "" #: templates/myaccount/my-subscriptions.php:28 #: templates/myaccount/related-orders.php:25 #: templates/myaccount/related-subscriptions.php:23 -#: templates/myaccount/view-subscription.php:94 +#: templates/myaccount/view-subscription.php:96 msgctxt "table heading" msgid "Total" msgstr "" @@ -3286,7 +3282,7 @@ msgctxt "Subscription status" msgid "On-hold" msgstr "" -#: includes/class-wc-subscriptions-switcher.php:1999 wcs-functions.php:208 +#: includes/class-wc-subscriptions-switcher.php:2019 wcs-functions.php:208 msgctxt "Subscription status" msgid "Switched" msgstr "" @@ -3407,22 +3403,22 @@ msgctxt "used in order notes" msgid "Customer switched from: %1$s to %2$s." msgstr "" -#: includes/class-wc-subscriptions-switcher.php:1604 +#: includes/class-wc-subscriptions-switcher.php:1624 msgctxt "a switch order" msgid "Downgrade" msgstr "" -#: includes/class-wc-subscriptions-switcher.php:1607 +#: includes/class-wc-subscriptions-switcher.php:1627 msgctxt "a switch order" msgid "Upgrade" msgstr "" -#: includes/class-wc-subscriptions-switcher.php:1610 +#: includes/class-wc-subscriptions-switcher.php:1630 msgctxt "a switch order" msgid "Crossgrade" msgstr "" -#: includes/class-wc-subscriptions-switcher.php:1615 +#: includes/class-wc-subscriptions-switcher.php:1635 #. translators: %1: product subtotal, %2: HTML span tag, %3: direction #. (upgrade, downgrade, crossgrade), %4: closing HTML span tag msgctxt "product subtotal string" @@ -3523,7 +3519,7 @@ msgid "[%s] Subscription Cancelled" msgstr "" #: includes/emails/class-wcs-email-cancelled-subscription.php:120 -#: includes/emails/class-wcs-email-customer-renewal-invoice.php:166 +#: includes/emails/class-wcs-email-customer-renewal-invoice.php:174 msgctxt "an email notification" msgid "Enable/Disable" msgstr "" @@ -3638,8 +3634,8 @@ msgstr "" #: includes/gateways/paypal/includes/class-wcs-paypal-reference-transaction-api-response.php:119 #: templates/admin/post-types/writepanels/order-shipping-html.php:14 #: templates/admin/post-types/writepanels/order-tax-html.php:9 -#: templates/myaccount/view-subscription.php:274 -#: templates/myaccount/view-subscription.php:293 +#: templates/myaccount/view-subscription.php:276 +#: templates/myaccount/view-subscription.php:295 msgctxt "no information about something" msgid "N/A" msgstr "" @@ -3735,8 +3731,8 @@ msgid "Free" msgstr "" #: includes/wcs-cart-functions.php:255 -#: templates/myaccount/view-subscription.php:199 -#: templates/myaccount/view-subscription.php:204 +#: templates/myaccount/view-subscription.php:201 +#: templates/myaccount/view-subscription.php:206 #. translators: placeholder is price string, denotes tax included in cart/order #. total msgctxt "includes tax" @@ -3904,7 +3900,7 @@ msgstr "" #: templates/emails/customer-completed-switch-order.php:75 #: templates/emails/customer-processing-renewal-order.php:31 #: templates/emails/customer-renewal-invoice.php:42 -#: templates/myaccount/view-subscription.php:93 +#: templates/myaccount/view-subscription.php:95 msgctxt "table headings in notification email" msgid "Product" msgstr "" @@ -4084,12 +4080,12 @@ msgctxt "admin subscription table header" msgid "Trial End Date" msgstr "" -#: templates/myaccount/view-subscription.php:73 +#: templates/myaccount/view-subscription.php:75 msgctxt "date on subscription updates list. Will be localized" msgid "l jS \\o\\f F Y, h:ia" msgstr "" -#: templates/myaccount/view-subscription.php:134 +#: templates/myaccount/view-subscription.php:136 #. translators: %1$s is the number of the file (only in plural!), %2$s: the #. name of the file msgctxt "Used as link text in view-subscription template" @@ -4098,29 +4094,29 @@ msgid_plural "Download file %1$s: %2$s" msgstr[0] "" msgstr[1] "" -#: templates/myaccount/view-subscription.php:231 +#: templates/myaccount/view-subscription.php:233 msgctxt "customer note" msgid "Note:" msgstr "" -#: templates/myaccount/view-subscription.php:247 +#: templates/myaccount/view-subscription.php:249 #. translators: there is markup here, hence can't use Email: %s msgctxt "heading in customer details on subscription detail page" msgid "Email" msgstr "" -#: templates/myaccount/view-subscription.php:252 +#: templates/myaccount/view-subscription.php:254 #. translators: there is markup here, hence can't use Email: %s msgctxt "heading in customer details on subscription detail page" msgid "Tel" msgstr "" -#: templates/myaccount/view-subscription.php:247 +#: templates/myaccount/view-subscription.php:249 msgctxt "Used in data attribute for a td tag, escaped." msgid "Email" msgstr "" -#: templates/myaccount/view-subscription.php:252 +#: templates/myaccount/view-subscription.php:254 msgctxt "Used in data attribute for a td tag, escaped." msgid "Telephone" msgstr "" diff --git a/templates/checkout/recurring-totals.php b/templates/checkout/recurring-totals.php index 30d0e02..50adc1e 100644 --- a/templates/checkout/recurring-totals.php +++ b/templates/checkout/recurring-totals.php @@ -57,14 +57,14 @@ $display_th = true; cart->tax_display_cart === 'excl' ) : ?> - cart->get_tax_totals() as $code => $tax ) : ?> + cart->get_taxes() as $tax_id => $tax_total ) : ?> $recurring_cart ) : ?> next_payment_date ) : ?> get_tax_totals() as $recurring_code => $recurring_tax ) : ?> - - + tax_rate_id ) || $recurring_tax->tax_rate_id !== $tax_id ) { continue; } ?> + label ); ?> diff --git a/templates/myaccount/view-subscription.php b/templates/myaccount/view-subscription.php index 0010a20..0fc772e 100644 --- a/templates/myaccount/view-subscription.php +++ b/templates/myaccount/view-subscription.php @@ -50,6 +50,7 @@ wc_print_notices(); + @@ -61,6 +62,7 @@ wc_print_notices(); + get_customer_order_notes() ) : ?> @@ -96,9 +98,9 @@ wc_print_notices(); get_items() ) > 0 ) { + if ( sizeof( $subscription_items = $subscription->get_items() ) > 0 ) { - foreach ( $subscription->get_items() as $item_id => $item ) { + foreach ( $subscription_items as $item_id => $item ) { $_product = apply_filters( 'woocommerce_subscriptions_order_item_product', $subscription->get_product_from_item( $item ), $item ); $item_meta = wcs_get_order_item_meta( $item, $_product ); if ( apply_filters( 'woocommerce_order_item_visible', true, $item ) ) { diff --git a/woocommerce-subscriptions.php b/woocommerce-subscriptions.php index 0365279..0109aa5 100644 --- a/woocommerce-subscriptions.php +++ b/woocommerce-subscriptions.php @@ -5,7 +5,7 @@ * Description: Sell products and services with recurring payments in your WooCommerce Store. * Author: Prospress Inc. * Author URI: http://prospress.com/ - * Version: 2.0.19 + * Version: 2.0.20 * * Copyright 2016 Prospress, Inc. (email : freedoms@prospress.com) * @@ -118,7 +118,7 @@ class WC_Subscriptions { public static $plugin_file = __FILE__; - public static $version = '2.0.19'; + public static $version = '2.0.20'; private static $total_subscription_count = null;