/**
  * Output a pricing table
  *
  * * product_id/product_sku - id or sku of product.  Defaults to current product, if any
  *
  * Usage:
  * [wc_measurement_price_calculator_pricing_table]
  *
  * @param array $atts associative array of shortcode parameters
  */
 public static function output($atts)
 {
     global $product, $wpdb;
     extract(shortcode_atts(array('product_id' => '', 'product_sku' => ''), $atts));
     // product by sku?
     if ($product_sku) {
         $product_id = $wpdb->get_var($wpdb->prepare("SELECT post_id FROM {$wpdb->postmeta} WHERE meta_key='_sku' AND meta_value=%s LIMIT 1", $product_sku));
     }
     // product by id?
     if ($product_id) {
         $product = wc_get_product($product_id);
     }
     // product ?
     if (!$product) {
         return;
     }
     // pricing rules?
     $settings = new WC_Price_Calculator_Settings($product);
     if (!$settings->pricing_rules_enabled() || !$settings->has_pricing_rules()) {
         return;
     }
     // the countdown element with a unique identifier to allow multiple countdowns on the same page, and common class for ease of styling
     echo self::get_pricing_rules_table($settings->get_pricing_rules($settings->get_pricing_unit()), $settings);
 }
 /**
  * Calculate the item price based on the given measurements
  *
  * @since 3.1.3
  * @param WC_Product $product the product
  * @param float $measurement_needed_value the total measurement needed
  * @param string $measurement_needed_value_unit the unit of $measurement_needed_value
  * @return float the calculated price
  */
 public static function calculate_price($product, $measurement_needed_value, $measurement_needed_value_unit)
 {
     $price = $product->get_price();
     // get the parent product if there is one
     $_product = 'WC_Product_Variation' == get_class($product) ? $product->parent : $product;
     if (self::pricing_calculator_enabled($_product)) {
         $settings = new WC_Price_Calculator_Settings($_product);
         $measurement_needed = new WC_Price_Calculator_Measurement($measurement_needed_value_unit, (double) $measurement_needed_value);
         // if this calculator uses pricing rules, retrieve the price based on the product measurements
         if ($settings->pricing_rules_enabled()) {
             $product->price = $settings->get_pricing_rules_price($measurement_needed);
         }
         // calculate the price
         $price = $product->get_price() * $measurement_needed->get_value($settings->get_pricing_unit());
         // is there a minimum price to use?
         if (WC_Price_Calculator_Product::get_product_meta($product, 'wc_measurement_price_calculator_min_price') > $price) {
             $price = WC_Price_Calculator_Product::get_product_meta($product, 'wc_measurement_price_calculator_min_price');
         }
     }
     // return the final price
     return $price;
 }
 /**
  * Ensure Google Product Feed includes products with the pricing rules enabled
  *
  * @since 3.8.0
  * @param object $feed_item
  * @return object
  */
 public function google_product_feed_pricing_rules_price_adjustment($feed_item)
 {
     $product = wc_get_product($feed_item->ID);
     if ($product) {
         $settings = new WC_Price_Calculator_Settings($product);
         if ($settings->pricing_rules_enabled()) {
             $price = $settings->get_pricing_rules_minimum_price();
             $regular_price = $settings->get_pricing_rules_minimum_regular_price();
             $sale_price = $price;
             if ('' !== $price) {
                 $feed_item->price_inc_tax = $product->get_price_excluding_tax(1, $price);
                 $feed_item->price_ex_tax = $product->get_price_including_tax(1, $price);
             }
             if ('' !== $regular_price) {
                 $feed_item->regular_price_ex_tax = $product->get_price_excluding_tax(1, $regular_price);
                 $feed_item->regular_price_inc_tax = $product->get_price_including_tax(1, $regular_price);
             }
             if ($settings->pricing_rules_is_on_sale()) {
                 $feed_item->sale_price_ex_tax = $product->get_price_excluding_tax(1, $sale_price);
                 $feed_item->sale_price_inc_tax = $product->get_price_including_tax(1, $sale_price);
             }
         }
     }
     return $feed_item;
 }
 /**
  * Calculate the item price based on the given measurements
  *
  * @since 3.1.3
  * @param WC_Product $product the product
  * @param float $measurement_needed_value the total measurement needed
  * @param string $measurement_needed_value_unit the unit of $measurement_needed_value
  * @param bool $round Optional. If true the returned price will be rounded to two decimal places. Default true.
  * @return float the calculated price
  */
 public static function calculate_price($product, $measurement_needed_value, $measurement_needed_value_unit, $round = true)
 {
     $price = $product->get_price();
     // get the parent product if there is one
     $_product = 'WC_Product_Variation' == get_class($product) ? $product->parent : $product;
     if (self::pricing_calculator_enabled($_product)) {
         $settings = new WC_Price_Calculator_Settings($_product);
         $measurement_needed = new WC_Price_Calculator_Measurement($measurement_needed_value_unit, (double) $measurement_needed_value);
         // if this calculator uses pricing rules, retrieve the price based on the product measurements
         if ($settings->pricing_rules_enabled()) {
             $product->price = $settings->get_pricing_rules_price($measurement_needed);
         }
         // calculate the price
         $price = $product->get_price() * $measurement_needed->get_value($settings->get_pricing_unit());
         // is there a minimum price to use?
         if ($product->wc_measurement_price_calculator_min_price > $price) {
             $price = $product->wc_measurement_price_calculator_min_price;
         }
     }
     if ($round) {
         $price = round($price, absint(get_option('woocommerce_price_num_decimals', 2)));
     }
     // return the final price
     return $price;
 }
 /**
  * Make product variations visible even if they don't have a price, as long
  * as they are priced with a pricing table
  *
  * This is one of the few times where we are altering this filter in a
  * positive manner, and so we try to hook into it first.
  *
  * @since 3.0
  * @param boolean $visible whether the product is visible
  * @param int $product_id the product id
  * @return boolean true if the product is visible, false otherwise.
  */
 public function variable_product_is_visible($visible, $product_id)
 {
     $product = SV_WC_Plugin_Compatibility::wc_get_product($product_id);
     if (!$visible && $product && $product->is_type('variable') && WC_Price_Calculator_Product::pricing_calculator_enabled($product)) {
         $settings = new WC_Price_Calculator_Settings($product);
         if ($settings->pricing_rules_enabled()) {
             $visible = true;
         }
     }
     return $visible;
 }
 /**
  * Returns the cart item data for the given item being re-ordered.  This is
  * a somewhat complex process of re-configuring the product based on the
  * original measurements, taking into account unit changes.  We do not handle
  * calculator type changes at the moment; in fact there's probably no way
  * of accounting for this.  (actually we could handle calculator changes as
  * long as the calculator type was simplified, ie Area (L x W) -> Area,
  * but aside from that there's nothing we can do)
  *
  * @since 3.0
  * @param array $cart_item_data the cart item data
  * @param array $item the item
  * @param WC_Order $order the original order
  * @return array the cart item data
  */
 public function order_again_cart_item_data($cart_item_data, $item, $order)
 {
     $product = wc_get_product($item['product_id']);
     if (WC_Price_Calculator_Product::pricing_calculator_enabled($product) && isset($item['item_meta']['_measurement_data'][0]) && $item['item_meta']['_measurement_data'][0]) {
         $measurement_data = maybe_unserialize($item['item_meta']['_measurement_data'][0]);
         $settings = new WC_Price_Calculator_Settings($product);
         $measurements = $settings->get_calculator_measurements();
         // get the old product measurements, converting to the new measurement units as needed
         foreach ($measurements as $measurement) {
             if (isset($measurement_data[$measurement->get_name()])) {
                 $current_unit = $measurement->get_unit();
                 $measurement->set_value($measurement_data[$measurement->get_name()]['value']);
                 $measurement->set_unit($measurement_data[$measurement->get_name()]['unit']);
                 $cart_item_data['pricing_item_meta_data'][$measurement->get_name()] = $measurement->get_value($current_unit);
             }
         }
         // the product total measurement
         $measurement_needed = new WC_Price_Calculator_Measurement($measurement_data['_measurement_needed_unit'], $measurement_data['_measurement_needed']);
         // if this calculator uses pricing rules, retrieve the price based on the product measurements
         if ($settings->pricing_rules_enabled()) {
             $product->price = $settings->get_pricing_rules_price($measurement_needed);
         }
         // calculate the price
         $price = $product->get_price() * $measurement_needed->get_value($settings->get_pricing_unit());
         // is there a minimum price to use?
         if ($product->wc_measurement_price_calculator_min_price > $price) {
             $price = $product->wc_measurement_price_calculator_min_price;
         }
         // set the product price based on the price per unit and the total measurement
         $cart_item_data['pricing_item_meta_data']['_price'] = $price;
         // save the total measurement (length, area, volume, etc) in pricing units
         $cart_item_data['pricing_item_meta_data']['_measurement_needed'] = $measurement_needed->get_value();
         $cart_item_data['pricing_item_meta_data']['_measurement_needed_unit'] = $measurement_needed->get_unit();
         // pick up the item quantity which we set in order_again_item_set_quantity()
         if (isset($item['item_meta']['_quantity'][0])) {
             $cart_item_data['pricing_item_meta_data']['_quantity'] = $item['item_meta']['_quantity'][0];
         }
     }
     return $cart_item_data;
 }