/**
  * 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;
 }
 /**
  * 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 = SV_WC_Plugin_Compatibility::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 (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');
         }
         // 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;
 }
 /**
  * Register/queue frontend scripts.
  *
  * @since 3.0
  */
 public function enqueue_frontend_scripts()
 {
     global $post, $wc_measurement_price_calculator;
     $product = null;
     if (is_product()) {
         $product = SV_WC_Plugin_Compatibility::wc_get_product($post->ID);
     }
     // is the calculator enabled for this product?
     if (!$product || !WC_Price_Calculator_Product::calculator_enabled($product)) {
         return;
     }
     $settings = new WC_Price_Calculator_Settings($product);
     wp_enqueue_script('wc-price-calculator', $wc_measurement_price_calculator->get_plugin_url() . '/assets/js/frontend/wc-measurement-price-calculator.min.js');
     // Variables for JS scripts
     $wc_price_calculator_params = array('woocommerce_currency_symbol' => get_woocommerce_currency_symbol(), 'woocommerce_price_num_decimals' => (int) get_option('woocommerce_price_num_decimals'), 'woocommerce_currency_pos' => get_option('woocommerce_currency_pos'), 'woocommerce_price_decimal_sep' => stripslashes(get_option('woocommerce_price_decimal_sep')), 'woocommerce_price_thousand_sep' => stripslashes(get_option('woocommerce_price_thousand_sep')), 'woocommerce_price_trim_zeros' => get_option('woocommerce_price_trim_zeros'), 'unit_normalize_table' => WC_Price_Calculator_Measurement::get_normalize_table(), 'unit_conversion_table' => WC_Price_Calculator_Measurement::get_conversion_table(), 'measurement_precision' => apply_filters('wc_measurement_price_calculator_measurement_precision', 3), 'minimum_price' => WC_Price_Calculator_Product::get_product_meta($product, 'wc_measurement_price_calculator_min_price'), 'measurement_type' => $settings->get_calculator_type());
     // information required for either pricing or quantity calculator to function
     $wc_price_calculator_params['product_price'] = $product->is_type('variable') ? '' : $product->get_price();
     // get the product total measurement (ie Area), get a measurement (ie length), and determine the product total measurement common unit based on the measurements common unit
     $product_measurement = WC_Price_Calculator_Product::get_product_measurement($product, $settings);
     $measurements = $settings->get_calculator_measurements();
     list($measurement) = $measurements;
     $product_measurement->set_common_unit($measurement->get_unit_common());
     // this is the unit that the product total measurement will be in, ie it's how we know what unit we get for the Volume (AxH) calculator after multiplying A * H
     $wc_price_calculator_params['product_total_measurement_common_unit'] = $product_measurement->get_unit_common();
     if (WC_Price_Calculator_Product::pricing_calculator_enabled($product)) {
         // product information required for the pricing calculator javascript to function
         $wc_price_calculator_params['calculator_type'] = 'pricing';
         $wc_price_calculator_params['product_price_unit'] = $settings->get_pricing_unit();
         // if there are pricing rules, include them on the page source
         if ($settings->pricing_rules_enabled()) {
             $wc_price_calculator_params['pricing_rules'] = $settings->get_pricing_rules();
             // generate the pricing html
             foreach ($wc_price_calculator_params['pricing_rules'] as $index => $rule) {
                 $price_html = $settings->get_pricing_rule_price_html($rule);
                 $wc_price_calculator_params['pricing_rules'][$index]['price_html'] = '<span class="price">' . $price_html . '</span>';
             }
         }
     } else {
         // product information required for the quantity calculator javascript to function
         $wc_price_calculator_params['calculator_type'] = 'quantity';
         $quantity_range = WC_Price_Calculator_Product::get_quantity_range($product);
         $wc_price_calculator_params['quantity_range_min_value'] = $quantity_range['min_value'];
         $wc_price_calculator_params['quantity_range_max_value'] = $quantity_range['max_value'];
         if ($product->is_type('simple')) {
             // product_measurement represents one quantity of the product, bail if missing required product physical attributes
             if (!$product_measurement->get_value()) {
                 return;
             }
             $wc_price_calculator_params['product_measurement_value'] = $product_measurement->get_value();
             $wc_price_calculator_params['product_measurement_unit'] = $product_measurement->get_unit();
         } else {
             // provided by the available_variation() method
             $wc_price_calculator_params['product_measurement_value'] = '';
             $wc_price_calculator_params['product_measurement_unit'] = '';
         }
     }
     wp_localize_script('wc-price-calculator', 'wc_price_calculator_params', $wc_price_calculator_params);
 }
 /**
  * Returns the pricing rules (if any) associated with this calculator, which are
  * avilable only if the pricing calculator is enabled.  Pricing rules ranges
  * default to pricing units.
  *
  * @since 3.0
  * @param string $to_unit optional units to return the pricing rules ranges in,
  *        defaults to pricing units.
  * @return array of pricing rules with ranges in terms of $to_unit
  */
 public function get_pricing_rules($to_unit = null)
 {
     // default if the pricing calculator is not enabled
     $pricing_rules = array();
     if ($this->is_pricing_calculator_enabled() && $this->product) {
         // load the pricing rules when needed
         if (is_null($this->pricing_rules)) {
             $this->set_pricing_rules(WC_Price_Calculator_Product::get_product_meta($this->product, 'wc_price_calculator_pricing_rules'));
         }
         // default pricing rules
         $pricing_rules = $this->pricing_rules;
         // if a conversion
         if ($to_unit && $to_unit != $this->get_pricing_unit()) {
             foreach ($pricing_rules as &$rule) {
                 $rule['range_start'] = WC_Price_Calculator_Measurement::convert($rule['range_start'], $this->get_pricing_unit(), $to_unit);
                 if ('' !== $rule['range_end']) {
                     $rule['range_end'] = WC_Price_Calculator_Measurement::convert($rule['range_end'], $this->get_pricing_unit(), $to_unit);
                 }
             }
         }
     }
     return $pricing_rules;
 }