/** * 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; }
/** * Add a measurement product to the cart. This allows for the programmatic * addition of measurement pricing calculator products to the cart. * * This method expects the single total measurement needed, given by * $measurement_needed, this would be the dimension, area, volume or weight * depending on the type of calculator. * * This method also expects the full set of product measurements, given by * $measurements. For calculators with a single measurement like the dimension * calculator or simple area, this will contain the same value as * $measurement_needed. For more complex calculators, like Area (w x l) * this is how the width and length measurements are specified. For * convenience use <code>WC_Price_Calculator_Product::get_product_measurements( $product )</code> * to get the set of dimensions for your product, along with the correct * units, and set whatever values you need. * * @since 3.0 * @param string $product_id contains the id of the product to add to the cart * @param WC_Price_Calculator_Measurement $measurement_needed the total * measurement desired, ie 1 m, 3 sq. ft., etc * @param array $measurements array of WC_Price_Calculator_Measurement product * measurements, ie 1 m or 1.5 ft, 1.5 ft. Defaults to $measurement_needed * for convenience for calculators with a single measurement like dimension, * simple area, etc. * @param string $quantity contains the quantity of the item to add * @param int $variation_id optional variation id * @param array $variation optional attribute values * @param array $cart_item_data optional extra cart item data we want to pass into the item * @return bool true on success */ public function add_to_cart($product_id, $measurement_needed, $measurements = array(), $quantity = 1, $variation_id = '', $variation = '', $cart_item_data = array()) { // if measurements is empty just use the provided $measurement_needed (this is a shortcut for calculators with only one measurement, ie 'length', 'area', etc) if (empty($measurements)) { $measurements[] = $measurement_needed; } // build up the cart item data with the required values that would normally come in over the add to cart post request $cart_item_data['pricing_item_meta_data']['_measurement_needed_internal'] = $measurement_needed->get_value(); $cart_item_data['pricing_item_meta_data']['_measurement_needed_unit_internal'] = $measurement_needed->get_unit(); $cart_item_data['pricing_item_meta_data']['_quantity'] = $quantity; $product = wc_get_product($product_id); $settings = new WC_Price_Calculator_Settings($product); if (WC_Price_Calculator_Product::pricing_calculator_inventory_enabled($product)) { // pricing calculator product with inventory enabled, means we need to take the item quantity (ie 2) and determine the unit quantity (ie 2 * 3 ft = 6) $quantity *= $measurement_needed->get_value($settings->get_pricing_unit()); } foreach ($measurements as $measurement) { $cart_item_data['pricing_item_meta_data'][$measurement->get_name()] = $measurement->get_value(); } // initialize the cart_contents member if needed to avoid a warning from cart::find_product_in_cart() if (is_null(WC()->cart->cart_contents)) { WC()->cart->cart_contents = array(); } return WC()->cart->add_to_cart($product_id, $quantity, $variation_id, $variation, $cart_item_data); }
/** * Gets the price for the given $measurement, if there is a matching pricing * rule, or null * * @since 3.0 * @param WC_Price_Calculator_Measurement $measurement the product total measurement * @return float the price for the given $measurement (regular or sale) */ public function get_pricing_rules_price($measurement) { // get the value in pricing units for comparison $measurement_value = $measurement->get_value($this->get_pricing_unit()); foreach ($this->get_pricing_rules() as $rule) { // if we find a matching rule, return the price if ($measurement_value >= $rule['range_start'] && ('' === $rule['range_end'] || $measurement_value <= $rule['range_end'])) { return $rule['price']; } } return null; }
/** * 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; }