/**
 * Filter the product retruned by `WC_Order::woocommerce_get_product_from_item()`
 * to re-calculate a Measurement Price Calculator product's weight based on the
 * selected measurements. This function ensures that the "Weight" calculator
 * type is handled appropriately as well.
 *
 * @param \WC_Product $product The product.
 * @param array $item The order item.
 * @param \WC_Order $order The order.
 * @return \WC_Product The filtered product
 */
function sv_wc_mpc_shipstation_get_product_from_item_weight($product, $item, $order)
{
    if (WC_Price_Calculator_Product::pricing_calculated_weight_enabled($product)) {
        $settings = new WC_Price_Calculator_Settings($product);
        if ('weight' == $settings->get_calculator_type()) {
            // Now, the weight calculator products have to be handled specially
            // since the customer is actually supplying the weight, but it will
            // be in pricing units which may not be the same as the globally
            // configured WooCommerce Weight Unit expected by other plugins and code
            if (isset($item['item_meta']['_measurement_data'][0])) {
                $measurement_data = maybe_unserialize($item['item_meta']['_measurement_data'][0]);
                if (isset($measurement_data['_measurement_needed_unit']) && isset($measurement_data['_measurement_needed'])) {
                    $supplied_weight = new WC_Price_Calculator_Measurement($measurement_data['_measurement_needed_unit'], $measurement_data['_measurement_needed']);
                    // set the product weight as supplied by the customer, in WC Weight Units
                    $product->weight = $supplied_weight->get_value(get_option('woocommerce_weight_unit'));
                }
            }
        } elseif ($product->get_weight()) {
            if (isset($item['item_meta']['_measurement_data'][0])) {
                $measurement_data = maybe_unserialize($item['item_meta']['_measurement_data'][0]);
                // record the configured weight per unit for future reference
                if (!isset($measurement_data['_weight'])) {
                    $measurement_data['_weight'] = $product->get_weight();
                }
                // calculate the product weight = unit weight * total measurement (both will be in the same pricing units so we have say lbs/sq. ft. * sq. ft. = lbs)
                $product->weight = $measurement_data['_weight'] * $measurement_data['_measurement_needed'];
            }
        }
    }
    return $product;
}
 /**
  * Returns an array of measurements for the given product
  *
  * @since 3.0
  * @param WC_Product $product the product
  * @return array of WC_Price_Calculator_Measurement objects for the product
  */
 public static function get_product_measurements($product)
 {
     if (WC_Price_Calculator_Product::pricing_calculator_enabled($product)) {
         $settings = new WC_Price_Calculator_Settings($product);
         return $settings->get_calculator_measurements();
     }
 }
 /**
  * Perform any version-related changes. Changes to custom db tables should be handled by the migrate() method
  *
  * @since 3.0
  * @see SV_WC_Plugin::upgrade()
  * @param int $installed_version the currently installed version of the plugin
  */
 protected function upgrade($installed_version)
 {
     if (version_compare($installed_version, "3.0", '<')) {
         global $wpdb;
         require_once 'classes/class-wc-price-calculator-settings.php';
         // updating 3.0: From 2.0 to 3.0, the '_wc_price_calculator'
         // product post meta calculator settings structure changed: 'calculator'
         // was added to the 'pricing' option
         $rows = $wpdb->get_results("SELECT post_id, meta_value FROM {$wpdb->postmeta} WHERE meta_key='_wc_price_calculator'");
         foreach ($rows as $row) {
             if ($row->meta_value) {
                 // calculator settings found
                 $settings = new WC_Price_Calculator_Settings();
                 $settings = $settings->set_raw_settings($row->meta_value);
                 // we want the updated underlying raw settings array
                 $updated = false;
                 foreach (WC_Price_Calculator_Settings::get_measurement_types() as $measurement_type) {
                     if (isset($settings[$measurement_type]['pricing']['enabled']) && 'yes' == $settings[$measurement_type]['pricing']['enabled']) {
                         // enable the pricing calculator in the new settings data structure
                         $settings[$measurement_type]['pricing']['calculator'] = array('enabled' => 'yes');
                         $updated = true;
                     }
                 }
                 if ($updated) {
                     update_post_meta($row->post_id, '_wc_price_calculator', $settings);
                 }
             }
         }
     }
 }
 /**
  * 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;
 }
 /**
  * Returns a pricing rules HTML table
  *
  * @since 3.0
  * @param array $rules array of pricing rules
  * @param WC_Price_Calculator_Settings $settings the calculator settings object
  * @return string pricing rules HTML table
  */
 public static function get_pricing_rules_table($rules, $settings)
 {
     $html = '<table class="wc-measurement-price-calculator-pricing-table">';
     $html .= '<thead><tr><th>' . sprintf(__('Range (%s)', WC_Measurement_Price_Calculator::TEXT_DOMAIN), '<span class="units">' . __($settings->get_pricing_label(), WC_Measurement_Price_Calculator::TEXT_DOMAIN) . '</span>') . '</th>';
     $html .= '<th>' . sprintf(__('Price (%s)', WC_Measurement_Price_Calculator::TEXT_DOMAIN), '<span class="units">' . get_woocommerce_currency_symbol() . '/' . __($settings->get_pricing_label(), WC_Measurement_Price_Calculator::TEXT_DOMAIN) . '</span>') . '</th></tr></thead>';
     $html .= '<tbody>';
     foreach ($rules as $rule) {
         // format the range as "1 ft", "1 - 3 ft" or "1+ ft"
         $range = $rule['range_start'];
         if ('' === $rule['range_end']) {
             $range .= '+';
         } elseif ($rule['range_end'] != $rule['range_start']) {
             $range .= ' - ' . $rule['range_end'];
         }
         $range .= ' ' . __($settings->get_pricing_label(), WC_Measurement_Price_Calculator::TEXT_DOMAIN);
         $html .= sprintf('<tr><td>%s</td><td>%s</td></tr>', $range, $settings->get_pricing_rule_price_html($rule));
     }
     $html .= '</tbody>';
     $html .= '</table>';
     return $html;
 }
 /**
  * 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);
 }
 /**
  * Turn the cart item data into human-readable key/value pairs for
  * display in the cart
  *
  * @since 3.0
  * @param array $item cart item
  * @param array $cart_item_data the cart item data
  * @return array human-readable cart item data
  */
 private function humanize_cart_item_data($item, $cart_item_data)
 {
     $new_cart_item_data = array();
     // always need the actual parent product, not the useless variation product
     $product = isset($item['variation_id']) && $item['variation_id'] ? wc_get_product($item['product_id']) : $item['data'];
     $settings = new WC_Price_Calculator_Settings($product);
     foreach ($settings->get_calculator_measurements() as $measurement) {
         if (isset($cart_item_data[$measurement->get_name()])) {
             // if the measurement has a set of available options, get the option label for display, if we can determine it
             //  (this way we display "1/8" rather than "0.125", etc)
             if (count($measurement->get_options()) > 0) {
                 foreach ($measurement->get_options() as $value => $label) {
                     if ($cart_item_data[$measurement->get_name()] === $value) {
                         $cart_item_data[$measurement->get_name()] = $label;
                     }
                 }
             }
             $label = $measurement->get_unit_label() ? sprintf("%s (%s)", $measurement->get_label(), __($measurement->get_unit_label(), WC_Measurement_Price_Calculator::TEXT_DOMAIN)) : __($measurement->get_label(), WC_Measurement_Price_Calculator::TEXT_DOMAIN);
             $new_cart_item_data[$label] = $cart_item_data[$measurement->get_name()];
         }
     }
     // render the total measurement if this is a derived calculator (ie "Area (sq. ft.): 10" if the calculator is Area (LxW))
     if ($settings->is_calculator_type_derived() && isset($cart_item_data['_measurement_needed'])) {
         // get the product total measurement (ie area or volume)
         $product_measurement = WC_Price_Calculator_Product::get_product_measurement($product, $settings);
         $product_measurement->set_unit($cart_item_data['_measurement_needed_unit']);
         $product_measurement->set_value($cart_item_data['_measurement_needed']);
         $total_amount_text = apply_filters('wc_measurement_price_calculator_total_amount_text', $product_measurement->get_unit_label() ? sprintf(__('Total %s (%s)', WC_Measurement_Price_Calculator::TEXT_DOMAIN), $product_measurement->get_label(), __($product_measurement->get_unit_label(), WC_Measurement_Price_Calculator::TEXT_DOMAIN)) : sprintf(__('Total %s', WC_Measurement_Price_Calculator::TEXT_DOMAIN), $product_measurement->get_label()), $item);
         $new_cart_item_data[$total_amount_text] = $product_measurement->get_value();
     }
     return $new_cart_item_data;
 }
 /**
  * Manage the order stock (whether restore or reduce) from the order admin
  * returning the true product stock change if this is for a pricing calculator
  * product/item with inventory enabled.  Ie 2 pieces of cloth at 3 ft each
  * we'd want to return 6
  *
  * @since 3.0
  * @param numeric $quantity the new quantity
  * @param string $item_id the order item identifier
  * @return numeric $quantity the measurement quantity
  */
 public function admin_manage_order_stock($quantity, $item_id)
 {
     $order_id = absint($_POST['order_id']);
     $order = wc_get_order($order_id);
     $order_items = $order->get_items();
     $product = wc_get_product($order_items[$item_id]['product_id']);
     if (WC_Price_Calculator_Product::pricing_calculator_inventory_enabled($product) && isset($order_items[$item_id]['measurement_data'])) {
         $settings = new WC_Price_Calculator_Settings($product);
         $measurement_data = maybe_unserialize($order_items[$item_id]['measurement_data']);
         $total_amount = new WC_Price_Calculator_Measurement($measurement_data['_measurement_needed_unit'], $measurement_data['_measurement_needed']);
         // this is a pricing calculator product so we want to return the
         //  quantity in terms of units, ie 2 pieces of cloth at 3 ft each = 6
         $quantity *= $total_amount->get_value($settings->get_pricing_unit());
     }
     return $quantity;
 }