diff --git a/includes/abstracts/abstract-wc-order.php b/includes/abstracts/abstract-wc-order.php new file mode 100644 index 00000000000..1be2d3b0db0 --- /dev/null +++ b/includes/abstracts/abstract-wc-order.php @@ -0,0 +1,2094 @@ +prices_include_tax = get_option('woocommerce_prices_include_tax') == 'yes' ? true : false; + $this->tax_display_cart = get_option( 'woocommerce_tax_display_cart' ); + + $this->display_totals_ex_tax = $this->tax_display_cart == 'excl' ? true : false; + $this->display_cart_ex_tax = $this->tax_display_cart == 'excl' ? true : false; + + $this->order_type = 'simple'; + + if ( is_numeric( $order ) ) { + $this->id = absint( $order ); + $this->post = get_post( $order ); + $this->get_order( $this->id ); + } elseif ( $order instanceof WC_Order ) { + $this->id = absint( $order->id ); + $this->post = $order->post; + $this->get_order( $this->id ); + } elseif ( $order instanceof WP_Post || isset( $order->ID ) ) { + $this->id = absint( $order->ID ); + $this->post = $order; + $this->get_order( $this->id ); + } + } + + /** + * Remove all line items (products, coupons, shipping, taxes) from the order. + */ + public function remove_order_items( $type = null ) { + global $wpdb; + + if ( $type ) { + $wpdb->query( $wpdb->prepare( "DELETE FROM {$wpdb->prefix}woocommerce_order_itemmeta WHERE order_item_id IN ( SELECT order_item_id FROM {$wpdb->prefix}woocommerce_order_items WHERE order_id = %d AND order_item_type = %s )", $this->id, $type ) ); + $wpdb->query( $wpdb->prepare( "DELETE FROM {$wpdb->prefix}woocommerce_order_items WHERE order_id = %d AND order_item_type = %s", $this->id, $type ) ); + } else { + $wpdb->query( $wpdb->prepare( "DELETE FROM {$wpdb->prefix}woocommerce_order_itemmeta WHERE order_item_id IN ( SELECT order_item_id FROM {$wpdb->prefix}woocommerce_order_items WHERE order_id = %d )", $this->id ) ); + $wpdb->query( $wpdb->prepare( "DELETE FROM {$wpdb->prefix}woocommerce_order_items WHERE order_id = %d", $this->id ) ); + } + } + + /** + * Set the payment method for the order + * @param WC_Payment_Gateway + */ + public function set_payment_method( $payment_method ) { + if ( is_object( $payment_method ) ) { + update_post_meta( $this->id, '_payment_method', $payment_method->id ); + update_post_meta( $this->id, '_payment_method_title', $payment_method->get_title() ); + } + } + + /** + * Set the customer address + * @param array $address Address data + * @param string $type billing or shipping + */ + public function set_address( $address, $type = 'billing' ) { + foreach( $address as $key => $value ) { + update_post_meta( $this->id, "_{$type}_" . $key, $value ); + } + } + + /** + * Add a product line item to the order + * @param WC_Product $item + * @param int $qty Line item quantity + * @param array args + * @return int|bool Item ID or false + */ + public function add_product( $product, $qty = 1, $args = array() ) { + $default_args = array( + 'variation' => array(), + 'totals' => array() + ); + + $args = wp_parse_args( $args, $default_args ); + $item_id = wc_add_order_item( $this->id, array( + 'order_item_name' => $product->get_title(), + 'order_item_type' => 'line_item' + ) ); + + if ( ! $item_id ) { + return false; + } + + wc_add_order_item_meta( $item_id, '_qty', wc_stock_amount( $qty ) ); + wc_add_order_item_meta( $item_id, '_tax_class', $product->get_tax_class() ); + wc_add_order_item_meta( $item_id, '_product_id', $product->id ); + wc_add_order_item_meta( $item_id, '_variation_id', isset( $product->variation_id ) ? $product->variation_id : 0 ); + + // Set line item totals, either passed in or from the product + wc_add_order_item_meta( $item_id, '_line_subtotal', wc_format_decimal( isset( $args['totals']['subtotal'] ) ? $args['totals']['subtotal'] : $product->get_price_excluding_tax( $qty ) ) ); + wc_add_order_item_meta( $item_id, '_line_total', wc_format_decimal( isset( $args['totals']['total'] ) ? $args['totals']['total'] : $product->get_price_excluding_tax( $qty ) ) ); + wc_add_order_item_meta( $item_id, '_line_subtotal_tax', wc_format_decimal( isset( $args['totals']['subtotal_tax'] ) ? $args['totals']['subtotal_tax'] : 0 ) ); + wc_add_order_item_meta( $item_id, '_line_tax', wc_format_decimal( isset( $args['totals']['tax'] ) ? $args['totals']['tax'] : 0 ) ); + + // Add variation meta + foreach ( $args['variation'] as $key => $value ) { + wc_add_order_item_meta( $item_id, str_replace( 'attribute_', '', $key ), $value ); + } + + // Backorders + if ( $product->backorders_require_notification() && $product->is_on_backorder( $qty ) ) { + wc_add_order_item_meta( $item_id, apply_filters( 'woocommerce_backordered_item_meta_name', __( 'Backordered', 'woocommerce' ) ), $qty - max( 0, $product->get_total_stock() ) ); + } + + do_action( 'woocommerce_order_add_product', $this->id, $item_id, $product, $qty, $args ); + + return $item_id; + } + + /** + * Add coupon code to the order + * @param string $code + * @param float $discount_amount + * @return int|bool Item ID or false + */ + public function add_coupon( $code, $discount_amount = 0 ) { + $item_id = wc_add_order_item( $this->id, array( + 'order_item_name' => $code, + 'order_item_type' => 'coupon' + ) ); + + if ( ! $item_id ) { + return false; + } + + wc_add_order_item_meta( $item_id, 'discount_amount', $discount_amount ); + + do_action( 'woocommerce_order_add_coupon', $this->id, $item_id, $code, $discount_amount ); + + return $item_id; + } + + /** + * Add a tax row to the order + * @param int tax_rate_id + * @return int|bool Item ID or false + */ + public function add_tax( $tax_rate_id, $tax_amount = 0, $shipping_tax_amount = 0 ) { + $code = WC_Tax::get_rate_code( $tax_rate_id ); + + if ( ! $code ) { + return false; + } + + $item_id = wc_add_order_item( $this->id, array( + 'order_item_name' => $code, + 'order_item_type' => 'tax' + ) ); + + if ( ! $item_id ) { + return false; + } + + wc_add_order_item_meta( $item_id, 'rate_id', $tax_rate_id ); + wc_add_order_item_meta( $item_id, 'label', WC_Tax::get_rate_label( $tax_rate_id ) ); + wc_add_order_item_meta( $item_id, 'compound', WC_Tax::is_compound( $tax_rate_id ) ? 1 : 0 ); + wc_add_order_item_meta( $item_id, 'tax_amount', wc_format_decimal( $tax_amount ) ); + wc_add_order_item_meta( $item_id, 'shipping_tax_amount', wc_format_decimal( $shipping_tax_amount ) ); + + do_action( 'woocommerce_order_add_tax', $this->id, $item_id, $tax_rate_id, $tax_amount, $shipping_tax_amount ); + + return $item_id; + } + + /** + * Add a shipping row to the order + * @param WC_Shipping_Rate shipping_rate + * @return int|bool Item ID or false + */ + public function add_shipping( $shipping_rate ) { + $item_id = wc_add_order_item( $this->id, array( + 'order_item_name' => $shipping_rate->label, + 'order_item_type' => 'shipping' + ) ); + + if ( ! $item_id ) { + return false; + } + + wc_add_order_item_meta( $item_id, 'method_id', $shipping_rate->id ); + wc_add_order_item_meta( $item_id, 'cost', wc_format_decimal( $shipping_rate->cost ) ); + + do_action( 'woocommerce_order_add_shipping', $this->id, $item_id, $shipping_rate ); + + // Update total + $this->set_total( $this->order_shipping + wc_format_decimal( $shipping_rate->cost ), 'shipping' ); + + return $item_id; + } + + /** + * Add a fee to the order + * @param object $fee + * @return int|bool Item ID or false + */ + public function add_fee( $fee ) { + $item_id = wc_add_order_item( $this->id, array( + 'order_item_name' => $fee->name, + 'order_item_type' => 'fee' + ) ); + + if ( ! $item_id ) { + return false; + } + + if ( $fee->taxable ) { + wc_add_order_item_meta( $item_id, '_tax_class', $fee->tax_class ); + } else { + wc_add_order_item_meta( $item_id, '_tax_class', '0' ); + } + + wc_add_order_item_meta( $item_id, '_line_total', wc_format_decimal( $fee->amount ) ); + wc_add_order_item_meta( $item_id, '_line_tax', wc_format_decimal( $fee->tax ) ); + + do_action( 'woocommerce_order_add_fee', $this->id, $item_id, $fee ); + + return $item_id; + } + + /** + * Set an order total + * @param float $amount + * @param string $total_type + */ + public function set_total( $amount, $total_type = 'total' ) { + if ( ! in_array( $total_type, array( 'shipping', 'order_discount', 'tax', 'shipping_tax', 'total', 'cart_discount' ) ) ) { + return false; + } + switch ( $total_type ) { + case 'total' : + $key = '_order_total'; + $amount = wc_format_decimal( $amount, get_option( 'woocommerce_price_num_decimals' ) ); + break; + case 'order_discount' : + case 'cart_discount' : + $key = '_' . $total_type; + $amount = wc_format_decimal( $amount ); + break; + default : + $key = '_order_' . $total_type; + $amount = wc_format_decimal( $amount ); + break; + } + update_post_meta( $this->id, $key, $amount ); + } + + /** + * Calculate taxes for all line items and shipping, and store the totals and tax rows. + * + * Will use the base country unless customer addresses are set. + * + * @return bool success or fail + */ + public function calculate_taxes() { + $shipping_tax_total = 0; + $tax_total = 0; + $taxes = array(); + $tax_based_on = get_option( 'woocommerce_tax_based_on' ); + + if ( 'base' === $tax_based_on ) { + $default = get_option( 'woocommerce_default_country' ); + $postcode = ''; + $city = ''; + if ( strstr( $default, ':' ) ) { + list( $country, $state ) = explode( ':', $default ); + } else { + $country = $default; + $state = ''; + } + } elseif ( 'billing' === $tax_based_on ) { + $country = $this->billing_country; + $state = $this->billing_state; + $postcode = $this->billing_postcode; + $city = $this->billing_city; + } else { + $country = $this->shipping_country; + $state = $this->shipping_state; + $postcode = $this->shipping_postcode; + $city = $this->shipping_city; + } + + // Get items + foreach ( $this->get_items( array( 'line_item', 'fee' ) ) as $item_id => $item ) { + $product = $this->get_product_from_item( $item ); + $line_total = isset( $item['line_total'] ) ? $item['line_total'] : 0; + $line_subtotal = isset( $item['line_subtotal'] ) ? $item['line_subtotal'] : 0; + $tax_class = $item['tax_class']; + $item_tax_status = $product ? $product->get_tax_status() : 'taxable'; + + if ( '0' !== $tax_class && 'taxable' === $item_tax_status ) { + $tax_rates = WC_Tax::find_rates( array( + 'country' => $country, + 'state' => $state, + 'postcode' => $postcode, + 'city' => $city, + 'tax_class' => $tax_class + ) ); + $line_subtotal_taxes = WC_Tax::calc_tax( $line_subtotal, $tax_rates, false ); + $line_taxes = WC_Tax::calc_tax( $line_total, $tax_rates, false ); + $line_subtotal_tax = max( 0, array_sum( $line_subtotal_taxes ) ); + $line_tax = max( 0, array_sum( $line_taxes ) ); + $tax_total += $line_tax; + + wc_update_order_item_meta( $item_id, '_line_subtotal_tax', wc_format_decimal( $line_subtotal_tax ) ); + wc_update_order_item_meta( $item_id, '_line_tax', wc_format_decimal( $line_tax ) ); + + // Sum the item taxes + foreach ( array_keys( $taxes + $line_taxes ) as $key ) { + $taxes[ $key ] = ( isset( $line_taxes[ $key ] ) ? $line_taxes[ $key ] : 0 ) + ( isset( $taxes[ $key ] ) ? $taxes[ $key ] : 0 ); + } + } + } + + // Now calculate shipping tax + $matched_tax_rates = array(); + $tax_rates = WC_Tax::find_rates( array( + 'country' => $country, + 'state' => $state, + 'postcode' => $postcode, + 'city' => $city, + 'tax_class' => '' + ) ); + + if ( $tax_rates ) { + foreach ( $tax_rates as $key => $rate ) { + if ( isset( $rate['shipping'] ) && 'yes' === $rate['shipping'] ) { + $matched_tax_rates[ $key ] = $rate; + } + } + } + + $shipping_taxes = WC_Tax::calc_shipping_tax( $this->order_shipping, $matched_tax_rates ); + $shipping_tax_total = WC_Tax::round( array_sum( $shipping_taxes ) ); + + // Save tax totals + $this->set_total( $shipping_tax_total, 'shipping_tax' ); + $this->set_total( $tax_total, 'tax' ); + + // Tax rows + $this->remove_order_items( 'tax' ); + + // Now merge to keep tax rows + foreach ( array_keys( $taxes + $shipping_taxes ) as $tax_rate_id ) { + $this->add_tax( $tax_rate_id, isset( $taxes[ $tax_rate_id ] ) ? $taxes[ $tax_rate_id ] : 0, isset( $shipping_taxes[ $tax_rate_id ] ) ? $shipping_taxes[ $tax_rate_id ] : 0 ); + } + + return true; + } + + /** + * Calculate totals by looking at the contents of the order. Stores the totals and returns the orders final total. + * + * @return $total calculated grand total + */ + public function calculate_totals() { + $cart_subtotal = 0; + $cart_total = 0; + $fee_total = 0; + + $this->calculate_taxes(); + + foreach ( $this->get_items() as $item ) { + $cart_subtotal += wc_format_decimal( isset( $item['line_subtotal'] ) ? $item['line_subtotal'] : 0 ); + $cart_total += wc_format_decimal( isset( $item['line_total'] ) ? $item['line_total'] : 0 ); + } + + foreach ( $this->get_fees() as $item ) { + $fee_total += $item['line_total']; + } + + $grand_total = round( $cart_total + $fee_total + $this->get_total_shipping() - $this->get_order_discount() + $this->get_cart_tax() + $this->get_shipping_tax(), absint( get_option( 'woocommerce_price_num_decimals' ) ) ); + + $this->set_total( $cart_subtotal - $cart_total, 'cart_discount' ); + $this->set_total( $grand_total, 'total' ); + + return $grand_total; + } + + /** + * Gets an order from the database. + * + * @access public + * @param int $id (default: 0) + * @return bool + */ + public function get_order( $id = 0 ) { + if ( ! $id ) { + return false; + } + if ( $result = get_post( $id ) ) { + $this->populate( $result ); + return true; + } + return false; + } + + /** + * Populates an order from the loaded post data. + * + * @access public + * @param mixed $result + * @return void + */ + public function populate( $result ) { + // Standard post data + $this->id = $result->ID; + $this->order_date = $result->post_date; + $this->modified_date = $result->post_modified; + $this->customer_message = $result->post_excerpt; + $this->customer_note = $result->post_excerpt; + $this->post_status = $result->post_status; + + // Billing email cam default to user if set + if ( empty( $this->billing_email ) && ! empty( $this->customer_user ) ) { + $user = get_user_by( 'id', $this->customer_user ); + $this->billing_email = $user->user_email; + } + } + + /** + * __isset function. + * + * @access public + * @param mixed $key + * @return bool + */ + public function __isset( $key ) { + if ( ! $this->id ) { + return false; + } + return metadata_exists( 'post', $this->id, '_' . $key ); + } + + /** + * __get function. + * + * @access public + * @param mixed $key + * @return mixed + */ + public function __get( $key ) { + // Get values or default if not set + if ( 'completed_date' === $key ) { + $value = ( $value = get_post_meta( $this->id, '_completed_date', true ) ) ? $value : $this->modified_date; + } elseif ( 'user_id' === $key ) { + $value = ( $value = get_post_meta( $this->id, '_customer_user', true ) ) ? absint( $value ) : ''; + } elseif ( 'status' === $key ) { + $value = $this->get_status(); + } else { + $value = get_post_meta( $this->id, '_' . $key, true ); + } + return $value; + } + + /** + * Return the order statuses without wc- internal prefix + * @return string + */ + public function get_status() { + return apply_filters( 'woocommerce_order_get_status', 'wc-' === substr( $this->post_status, 0, 3 ) ? substr( $this->post_status, 3 ) : $this->post_status, $this ); + } + + /** + * Checks the order status against a passed in status. + * + * @access public + * @param mixed $type Array or string of types + * @return bool + */ + public function has_status( $status ) { + return apply_filters( 'woocommerce_order_has_status', ( is_array( $status ) && in_array( $this->get_status(), $status ) ) || $this->get_status() === $status ? true : false, $this, $status ); + } + + /** + * Gets the user ID associated with the order. Guests are 0. + * @since 2.2 + * @return int|false + */ + public function get_user_id() { + return $this->customer_user ? $this->customer_user : 0; + } + + /** + * Get the user associated with the order. False for guests. + * @since 2.2 + * @return WP_User|false + */ + public function get_user() { + return $user_id = $this->get_user_id() ? get_user_by( 'id', $user_id ) : false; + } + + /** + * Check if an order key is valid. + * + * @access public + * @param mixed $key + * @return bool + */ + public function key_is_valid( $key ) { + if ( $key == $this->order_key ) { + return true; + } + return false; + } + + /** + * get_order_number function. + * + * Gets the order number for display (by default, order ID) + * + * @access public + * @return string + */ + public function get_order_number() { + return apply_filters( 'woocommerce_order_number', _x( '#', 'hash before order number', 'woocommerce' ) . $this->id, $this ); + } + + /** + * Get a formatted billing address for the order. + * + * @access public + * @return string + */ + public function get_formatted_billing_address() { + if ( ! $this->formatted_billing_address ) { + + // Formatted Addresses + $address = apply_filters( 'woocommerce_order_formatted_billing_address', array( + 'first_name' => $this->billing_first_name, + 'last_name' => $this->billing_last_name, + 'company' => $this->billing_company, + 'address_1' => $this->billing_address_1, + 'address_2' => $this->billing_address_2, + 'city' => $this->billing_city, + 'state' => $this->billing_state, + 'postcode' => $this->billing_postcode, + 'country' => $this->billing_country + ), $this ); + + $this->formatted_billing_address = WC()->countries->get_formatted_address( $address ); + } + return $this->formatted_billing_address; + } + + /** + * Get the billing address in an array. + * + * @access public + * @return string + */ + public function get_billing_address() { + if ( ! $this->billing_address ) { + // Formatted Addresses + $address = array( + 'address_1' => $this->billing_address_1, + 'address_2' => $this->billing_address_2, + 'city' => $this->billing_city, + 'state' => $this->billing_state, + 'postcode' => $this->billing_postcode, + 'country' => $this->billing_country + ); + $joined_address = array(); + foreach ( $address as $part ) { + if ( ! empty( $part ) ) { + $joined_address[] = $part; + } + } + $this->billing_address = implode( ', ', $joined_address ); + } + return $this->billing_address; + } + + /** + * Get a formatted shipping address for the order. + * + * @access public + * @return string + */ + public function get_formatted_shipping_address() { + if ( ! $this->formatted_shipping_address ) { + if ( $this->shipping_address_1 ) { + + // Formatted Addresses + $address = apply_filters( 'woocommerce_order_formatted_shipping_address', array( + 'first_name' => $this->shipping_first_name, + 'last_name' => $this->shipping_last_name, + 'company' => $this->shipping_company, + 'address_1' => $this->shipping_address_1, + 'address_2' => $this->shipping_address_2, + 'city' => $this->shipping_city, + 'state' => $this->shipping_state, + 'postcode' => $this->shipping_postcode, + 'country' => $this->shipping_country + ), $this ); + + $this->formatted_shipping_address = WC()->countries->get_formatted_address( $address ); + } + } + return $this->formatted_shipping_address; + } + + /** + * Get the shipping address in an array. + * + * @access public + * @return array + */ + public function get_shipping_address() { + if ( ! $this->shipping_address ) { + if ( $this->shipping_address_1 ) { + // Formatted Addresses + $address = array( + 'address_1' => $this->shipping_address_1, + 'address_2' => $this->shipping_address_2, + 'city' => $this->shipping_city, + 'state' => $this->shipping_state, + 'postcode' => $this->shipping_postcode, + 'country' => $this->shipping_country + ); + $joined_address = array(); + foreach ( $address as $part ) { + if ( ! empty( $part ) ) { + $joined_address[] = $part; + } + } + $this->shipping_address = implode( ', ', $joined_address ); + } + } + return $this->shipping_address; + } + + /** + * Return an array of items/products within this order. + * + * @access public + * @param string|array $type Types of line items to get (array or string) + * @return array + */ + public function get_items( $type = '' ) { + global $wpdb; + + if ( empty( $type ) ) { + $type = array( 'line_item' ); + } + + if ( ! is_array( $type ) ) { + $type = array( $type ); + } + + $type = array_map( 'esc_attr', $type ); + + $line_items = $wpdb->get_results( $wpdb->prepare( " + SELECT order_item_id, order_item_name, order_item_type + FROM {$wpdb->prefix}woocommerce_order_items + WHERE order_id = %d + AND order_item_type IN ( '" . implode( "','", $type ) . "' ) + ORDER BY order_item_id + ", $this->id ) ); + + $items = array(); + + // Reserved meta keys + $reserved_item_meta_keys = array( + 'name', + 'type', + 'item_meta', + 'qty', + 'tax_class', + 'product_id', + 'variation_id', + 'line_subtotal', + 'line_total', + 'line_tax', + 'line_subtotal_tax' + ); + + // Loop items + foreach ( $line_items as $item ) { + // Place line item into array to return + $items[ $item->order_item_id ]['name'] = $item->order_item_name; + $items[ $item->order_item_id ]['type'] = $item->order_item_type; + $items[ $item->order_item_id ]['item_meta'] = $this->get_item_meta( $item->order_item_id ); + + // Expand meta data into the array + foreach ( $items[ $item->order_item_id ]['item_meta'] as $name => $value ) { + if ( in_array( $name, $reserved_item_meta_keys ) ) { + continue; + } + if ( '_' === substr( $name, 0, 1 ) ) { + $items[ $item->order_item_id ][ substr( $name, 1 ) ] = $value[0]; + } elseif ( ! in_array( $name, $reserved_item_meta_keys ) ) { + $items[ $item->order_item_id ][ $name ] = $value[0]; + } + } + } + + return apply_filters( 'woocommerce_order_get_items', $items, $this ); + } + + /** + * Gets order total - formatted for display. + * + * @access public + * @return string + */ + public function get_item_count( $type = '' ) { + if ( empty( $type ) ) { + $type = array( 'line_item' ); + } + + if ( ! is_array( $type ) ) { + $type = array( $type ); + } + + $items = $this->get_items( $type ); + + $count = 0; + + foreach ( $items as $item ) { + if ( ! empty( $item['qty'] ) ) { + $count += $item['qty']; + } else { + $count ++; + } + } + + return apply_filters( 'woocommerce_get_item_count', $count, $type, $this ); + } + + /** + * Return an array of fees within this order. + * + * @access public + * @return array + */ + public function get_fees() { + return $this->get_items( 'fee' ); + } + + /** + * Return an array of taxes within this order. + * + * @access public + * @return array + */ + public function get_taxes() { + return $this->get_items( 'tax' ); + } + + /** + * Return an array of shipping costs within this order. + * + * @return array + */ + public function get_shipping_methods() { + return $this->get_items( 'shipping' ); + } + + /** + * Check whether this order has a specific shipping method or not + * @param string $method_id + * @return bool + */ + public function has_shipping_method( $method_id ) { + $shipping_methods = $this->get_shipping_methods(); + $has_method = false; + + if ( ! $shipping_methods ) { + return false; + } + + foreach ( $shipping_methods as $shipping_method ) { + if ( $shipping_method['method_id'] == $method_id ) { + $has_method = true; + } + } + + return $has_method; + } + + /** + * Get taxes, merged by code, formatted ready for output. + * + * @access public + * @return array + */ + public function get_tax_totals() { + $taxes = $this->get_items( 'tax' ); + $tax_totals = array(); + + foreach ( $taxes as $key => $tax ) { + + $code = $tax[ 'name' ]; + + if ( ! isset( $tax_totals[ $code ] ) ) { + $tax_totals[ $code ] = new stdClass(); + $tax_totals[ $code ]->amount = 0; + } + + $tax_totals[ $code ]->is_compound = $tax[ 'compound' ]; + $tax_totals[ $code ]->label = isset( $tax[ 'label' ] ) ? $tax[ 'label' ] : $tax[ 'name' ]; + $tax_totals[ $code ]->amount += $tax[ 'tax_amount' ] + $tax[ 'shipping_tax_amount' ]; + $tax_totals[ $code ]->formatted_amount = wc_price( wc_round_tax_total( $tax_totals[ $code ]->amount ), array('currency' => $this->get_order_currency()) ); + } + + return apply_filters( 'woocommerce_order_tax_totals', $tax_totals, $this ); + } + + /** + * has_meta function for order items. + * @access public + * @param string $order_item_id + * @return array of meta data + */ + public function has_meta( $order_item_id ) { + global $wpdb; + + return $wpdb->get_results( $wpdb->prepare( "SELECT meta_key, meta_value, meta_id, order_item_id + FROM {$wpdb->prefix}woocommerce_order_itemmeta WHERE order_item_id = %d + ORDER BY meta_id", absint( $order_item_id ) ), ARRAY_A ); + } + + /** + * Get order item meta. + * + * @access public + * @param mixed $order_item_id + * @param string $key (default: '') + * @param bool $single (default: false) + * @return array|string + */ + public function get_item_meta( $order_item_id, $key = '', $single = false ) { + return get_metadata( 'order_item', $order_item_id, $key, $single ); + } + + /** Total Getters *******************************************************/ + + /** + * Gets the total (product) discount amount - these are applied before tax. + * + * @access public + * @return float + */ + public function get_cart_discount() { + return apply_filters( 'woocommerce_order_amount_cart_discount', (double) $this->cart_discount, $this ); + } + + /** + * Gets the total (product) discount amount - these are applied before tax. + * + * @access public + * @return float + */ + public function get_order_discount() { + return apply_filters( 'woocommerce_order_amount_order_discount', (double) $this->order_discount, $this ); + } + + /** + * Gets the total discount amount - both kinds + * + * @access public + * @return float + */ + public function get_total_discount() { + return apply_filters( 'woocommerce_order_amount_total_discount', $this->get_cart_discount() + $this->get_order_discount(), $this ); + } + + /** + * Gets shipping tax amount. + * + * @access public + * @return float + */ + public function get_cart_tax() { + return apply_filters( 'woocommerce_order_amount_cart_tax', (double) $this->order_tax, $this ); + } + + /** + * Gets shipping tax amount. + * + * @access public + * @return float + */ + public function get_shipping_tax() { + return apply_filters( 'woocommerce_order_amount_shipping_tax', (double) $this->order_shipping_tax, $this ); + } + + /** + * Gets shipping and product tax. + * + * @access public + * @return float + */ + public function get_total_tax() { + return apply_filters( 'woocommerce_order_amount_total_tax', wc_round_tax_total( $this->get_cart_tax() + $this->get_shipping_tax() ), $this ); + } + + /** + * Gets shipping total. + * + * @access public + * @return float + */ + public function get_total_shipping() { + return apply_filters( 'woocommerce_order_amount_total_shipping', (double) $this->order_shipping, $this ); + } + + /** + * Gets order total. + * + * @access public + * @return float + */ + public function get_total() { + return apply_filters( 'woocommerce_order_amount_total', (double) $this->order_total, $this ); + } + + /** + * Get item subtotal - this is the cost before discount. + * + * @access public + * @param mixed $item + * @param bool $inc_tax (default: false) + * @param bool $round (default: true) + * @return float + */ + public function get_item_subtotal( $item, $inc_tax = false, $round = true ) { + if ( $inc_tax ) { + $price = ( $item['line_subtotal'] + $item['line_subtotal_tax'] ) / max( 1, $item['qty'] ); + } else { + $price = ( $item['line_subtotal'] / $item['qty'] ); + } + + $price = $round ? round( $price, 2 ) : $price; + + return apply_filters( 'woocommerce_order_amount_item_subtotal', $price, $this, $item ); + } + + /** + * Get line subtotal - this is the cost before discount. + * + * @access public + * @param mixed $item + * @param bool $inc_tax (default: false) + * @param bool $round (default: true) + * @return float + */ + public function get_line_subtotal( $item, $inc_tax = false, $round = true ) { + if ( $inc_tax ) { + $price = $item['line_subtotal'] + $item['line_subtotal_tax']; + } else { + $price = $item['line_subtotal']; + } + + $price = $round ? round( $price, 2 ) : $price; + + return apply_filters( 'woocommerce_order_amount_line_subtotal', $price, $this, $item ); + } + + /** + * Calculate item cost - useful for gateways. + * + * @access public + * @param mixed $item + * @param bool $inc_tax (default: false) + * @param bool $round (default: true) + * @return float + */ + public function get_item_total( $item, $inc_tax = false, $round = true ) { + if ( $inc_tax ) { + $price = ( $item['line_total'] + $item['line_tax'] ) / max( 1, $item['qty'] ); + } else { + $price = $item['line_total'] / $item['qty']; + } + + $price = $round ? round( $price, 2 ) : $price; + + return apply_filters( 'woocommerce_order_amount_item_total', $price, $this ); + } + + /** + * Calculate line total - useful for gateways. + * + * @access public + * @param mixed $item + * @param bool $inc_tax (default: false) + * @return float + */ + public function get_line_total( $item, $inc_tax = false ) { + $line_total = $inc_tax ? round( $item['line_total'] + $item['line_tax'], 2 ) : round( $item['line_total'], 2 ); + return apply_filters( 'woocommerce_order_amount_line_total', $line_total, $this ); + } + + /** + * Calculate item tax - useful for gateways. + * + * @access public + * @param mixed $item + * @param bool $round (default: true) + * @return float + */ + public function get_item_tax( $item, $round = true ) { + $price = $item['line_tax'] / max( 1, $item['qty'] ); + $price = $round ? wc_round_tax_total( $price ) : $price; + return apply_filters( 'woocommerce_order_amount_item_tax', $price, $item, $round, $this ); + } + + /** + * Calculate line tax - useful for gateways. + * + * @access public + * @param mixed $item + * @return float + */ + public function get_line_tax( $item ) { + return apply_filters( 'woocommerce_order_amount_line_tax', wc_round_tax_total( $item['line_tax'] ), $item, $this ); + } + + /** + * Gets shipping total. + * + * @deprecated As of 2.1, use of get_total_shipping() is preferred + * @access public + * @return float + */ + public function get_shipping() { + _deprecated_function( 'get_shipping', '2.1', 'get_total_shipping' ); + return $this->get_total_shipping(); + } + + /** + * get_order_total function. Alias for get_total() + * + * @deprecated As of 2.1, use of get_total() is preferred + * @access public + * @return float + */ + public function get_order_total() { + _deprecated_function( 'get_order_total', '2.1', 'get_total' ); + return $this->get_total(); + } + + /** End Total Getters *******************************************************/ + + /** + * Gets formatted shipping method title. + * + * @return string + */ + public function get_shipping_method() { + $labels = array(); + + // Backwards compat < 2.1 - get shipping title stored in meta + if ( $this->shipping_method_title ) { + $labels[] = $this->shipping_method_title; + } else { + // 2.1+ get line items for shipping + $shipping_methods = $this->get_shipping_methods(); + + foreach ( $shipping_methods as $shipping ) { + $labels[] = $shipping['name']; + } + } + + return apply_filters( 'woocommerce_order_shipping_method', implode( ', ', $labels ), $this ); + } + + /** + * Gets line subtotal - formatted for display. + * + * @access public + * @param array $item + * @param string $tax_display + * @return string + */ + public function get_formatted_line_subtotal( $item, $tax_display = '' ) { + if ( ! $tax_display ) { + $tax_display = $this->tax_display_cart; + } + + if ( ! isset( $item['line_subtotal'] ) || ! isset( $item['line_subtotal_tax'] ) ) { + return ''; + } + + if ( 'excl' == $tax_display ) { + $ex_tax_label = $this->prices_include_tax ? 1 : 0; + + $subtotal = wc_price( $this->get_line_subtotal( $item ), array( 'ex_tax_label' => $ex_tax_label, 'currency' => $this->get_order_currency() ) ); + } else { + $subtotal = wc_price( $this->get_line_subtotal( $item, true ), array('currency' => $this->get_order_currency()) ); + } + + return apply_filters( 'woocommerce_order_formatted_line_subtotal', $subtotal, $item, $this ); + } + + /** + * Gets order currency + * + * @access public + * @return string + */ + public function get_order_currency() { + + $currency = $this->order_currency; + + return apply_filters( 'woocommerce_get_order_currency', $currency, $this ); + } + + /** + * Gets order total - formatted for display. + * + * @access public + * @return string + */ + public function get_formatted_order_total() { + + $formatted_total = wc_price( $this->order_total , array('currency' => $this->get_order_currency())); + + return apply_filters( 'woocommerce_get_formatted_order_total', $formatted_total, $this ); + } + + + /** + * Gets subtotal - subtotal is shown before discounts, but with localised taxes. + * + * @access public + * @param bool $compound (default: false) + * @param string $tax_display (default: the tax_display_cart value) + * @return string + */ + public function get_subtotal_to_display( $compound = false, $tax_display = '' ) { + if ( ! $tax_display ) { + $tax_display = $this->tax_display_cart; + } + + $subtotal = 0; + + if ( ! $compound ) { + foreach ( $this->get_items() as $item ) { + + if ( ! isset( $item['line_subtotal'] ) || ! isset( $item['line_subtotal_tax'] ) ) { + return ''; + } + + $subtotal += $item['line_subtotal']; + + if ( 'incl' == $tax_display ) { + $subtotal += $item['line_subtotal_tax']; + } + } + + $subtotal = wc_price( $subtotal, array('currency' => $this->get_order_currency()) ); + + if ( $tax_display == 'excl' && $this->prices_include_tax ) { + $subtotal .= ' ' . WC()->countries->ex_tax_or_vat() . ''; + } + + } else { + + if ( 'incl' == $tax_display ) { + return ''; + } + + foreach ( $this->get_items() as $item ) { + + $subtotal += $item['line_subtotal']; + + } + + // Add Shipping Costs + $subtotal += $this->get_total_shipping(); + + // Remove non-compound taxes + foreach ( $this->get_taxes() as $tax ) { + + if ( ! empty( $tax['compound'] ) ) { + continue; + } + + $subtotal = $subtotal + $tax['tax_amount'] + $tax['shipping_tax_amount']; + + } + + // Remove discounts + $subtotal = $subtotal - $this->get_cart_discount(); + + $subtotal = wc_price( $subtotal, array('currency' => $this->get_order_currency()) ); + } + + return apply_filters( 'woocommerce_order_subtotal_to_display', $subtotal, $compound, $this ); + } + + + /** + * Gets shipping (formatted). + * + * @access public + * @return string + */ + public function get_shipping_to_display( $tax_display = '' ) { + if ( ! $tax_display ) { + $tax_display = $this->tax_display_cart; + } + + if ( $this->order_shipping > 0 ) { + + $tax_text = ''; + + if ( $tax_display == 'excl' ) { + + // Show shipping excluding tax + $shipping = wc_price( $this->order_shipping, array('currency' => $this->get_order_currency()) ); + + if ( $this->order_shipping_tax > 0 && $this->prices_include_tax ) { + $tax_text = WC()->countries->ex_tax_or_vat() . ' '; + } + + } else { + + // Show shipping including tax + $shipping = wc_price( $this->order_shipping + $this->order_shipping_tax, array('currency' => $this->get_order_currency()) ); + + if ( $this->order_shipping_tax > 0 && ! $this->prices_include_tax ) { + $tax_text = WC()->countries->inc_tax_or_vat() . ' '; + } + + } + + $shipping .= sprintf( __( ' %svia %s', 'woocommerce' ), $tax_text, $this->get_shipping_method() ); + + } elseif ( $this->get_shipping_method() ) { + $shipping = $this->get_shipping_method(); + } else { + $shipping = __( 'Free!', 'woocommerce' ); + } + + return apply_filters( 'woocommerce_order_shipping_to_display', $shipping, $this ); + } + + + /** + * Get cart discount (formatted). + * + * @access public + * @return string. + */ + public function get_cart_discount_to_display() { + return apply_filters( 'woocommerce_order_cart_discount_to_display', wc_price( $this->get_cart_discount(), array( 'currency' => $this->get_order_currency() ) ), $this ); + } + + + /** + * Get cart discount (formatted). + * + * @access public + * @return string + */ + public function get_order_discount_to_display() { + return apply_filters( 'woocommerce_order_discount_to_display', wc_price( $this->get_order_discount(), array( 'currency' => $this->get_order_currency() ) ), $this ); + } + + + /** + * Get a product (either product or variation). + * + * @access public + * @param mixed $item + * @return WC_Product + */ + public function get_product_from_item( $item ) { + if ( ! empty( $item['variation_id'] ) && 'product_variation' === get_post_type( $item['variation_id'] ) ) { + $_product = get_product( $item['variation_id'] ); + } else { + $_product = get_product( $item['product_id'] ); + } + return apply_filters( 'woocommerce_get_product_from_item', $_product, $item, $this ); + } + + + /** + * Get totals for display on pages and in emails. + * + * @access public + * @return array + */ + public function get_order_item_totals( $tax_display = '' ) { + if ( ! $tax_display ) { + $tax_display = $this->tax_display_cart; + } + + $total_rows = array(); + + if ( $subtotal = $this->get_subtotal_to_display() ) { + $total_rows['cart_subtotal'] = array( + 'label' => __( 'Cart Subtotal:', 'woocommerce' ), + 'value' => $subtotal + ); + } + + if ( $this->get_cart_discount() > 0 ) { + $total_rows['cart_discount'] = array( + 'label' => __( 'Cart Discount:', 'woocommerce' ), + 'value' => '-' . $this->get_cart_discount_to_display() + ); + } + + if ( $this->get_shipping_method() ) { + $total_rows['shipping'] = array( + 'label' => __( 'Shipping:', 'woocommerce' ), + 'value' => $this->get_shipping_to_display() + ); + } + + if ( $fees = $this->get_fees() ) + foreach( $fees as $id => $fee ) { + if ( apply_filters( 'woocommerce_get_order_item_totals_excl_free_fees', $fee['line_total'] + $fee['line_tax'] == 0, $id ) ) { + continue; + } + + if ( 'excl' == $tax_display ) { + + $total_rows[ 'fee_' . $id ] = array( + 'label' => $fee['name'] . ':', + 'value' => wc_price( $fee['line_total'], array('currency' => $this->get_order_currency()) ) + ); + + } else { + + $total_rows[ 'fee_' . $id ] = array( + 'label' => $fee['name'] . ':', + 'value' => wc_price( $fee['line_total'] + $fee['line_tax'], array('currency' => $this->get_order_currency()) ) + ); + + } + } + + // Tax for tax exclusive prices + if ( 'excl' == $tax_display ) { + if ( get_option( 'woocommerce_tax_total_display' ) == 'itemized' ) { + foreach ( $this->get_tax_totals() as $code => $tax ) { + $total_rows[ sanitize_title( $code ) ] = array( + 'label' => $tax->label . ':', + 'value' => $tax->formatted_amount + ); + } + } else { + $total_rows['tax'] = array( + 'label' => WC()->countries->tax_or_vat() . ':', + 'value' => wc_price( $this->get_total_tax(), array('currency' => $this->get_order_currency()) ) + ); + } + } + + if ( $this->get_order_discount() > 0 ) { + $total_rows['order_discount'] = array( + 'label' => __( 'Order Discount:', 'woocommerce' ), + 'value' => '-' . $this->get_order_discount_to_display() + ); + } + + if ( $this->get_total() > 0 ) { + $total_rows['payment_method'] = array( + 'label' => __( 'Payment Method:', 'woocommerce' ), + 'value' => $this->payment_method_title + ); + } + + $total_rows['order_total'] = array( + 'label' => __( 'Order Total:', 'woocommerce' ), + 'value' => $this->get_formatted_order_total() + ); + + // Tax for inclusive prices + if ( 'yes' == get_option( 'woocommerce_calc_taxes' ) && 'incl' == $tax_display ) { + + $tax_string_array = array(); + + if ( 'itemized' == get_option( 'woocommerce_tax_total_display' ) ) { + foreach ( $this->get_tax_totals() as $code => $tax ) { + $tax_string_array[] = sprintf( '%s %s', $tax->formatted_amount, $tax->label ); + } + } else { + $tax_string_array[] = sprintf( '%s %s', wc_price( $this->get_total_tax(), array('currency' => $this->get_order_currency()) ), WC()->countries->tax_or_vat() ); + } + + if ( ! empty( $tax_string_array ) ) { + $total_rows['order_total']['value'] .= ' ' . sprintf( __( '(Includes %s)', 'woocommerce' ), implode( ', ', $tax_string_array ) ); + } + } + + return apply_filters( 'woocommerce_get_order_item_totals', $total_rows, $this ); + } + + + /** + * Output items for display in html emails. + * + * @access public + * @param bool $show_download_links (default: false) + * @param bool $show_sku (default: false) + * @param bool $show_purchase_note (default: false) + * @param bool $show_image (default: false) + * @param array $image_size (default: array( 32, 32 ) + * @param bool plain text + * @return string + */ + public function email_order_items_table( $show_download_links = false, $show_sku = false, $show_purchase_note = false, $show_image = false, $image_size = array( 32, 32 ), $plain_text = false ) { + + ob_start(); + + $template = $plain_text ? 'emails/plain/email-order-items.php' : 'emails/email-order-items.php'; + + wc_get_template( $template, array( + 'order' => $this, + 'items' => $this->get_items(), + 'show_download_links' => $show_download_links, + 'show_sku' => $show_sku, + 'show_purchase_note' => $show_purchase_note, + 'show_image' => $show_image, + 'image_size' => $image_size + ) ); + + $return = apply_filters( 'woocommerce_email_order_items_table', ob_get_clean(), $this ); + + return $return; + } + + /** + * Checks if product download is permitted + * + * @access public + * @return bool + */ + public function is_download_permitted() { + return apply_filters( 'woocommerce_order_is_download_permitted', $this->has_status( 'completed' ) || ( get_option( 'woocommerce_downloads_grant_access_after_payment' ) == 'yes' && $this->has_status( 'processing' ) ), $this ); + } + + /** + * Returns true if the order contains a downloadable product. + * + * @access public + * @return bool + */ + public function has_downloadable_item() { + $has_downloadable_item = false; + + foreach ( $this->get_items() as $item ) { + + $_product = $this->get_product_from_item( $item ); + + if ( $_product && $_product->exists() && $_product->is_downloadable() && $_product->has_file() ) { + $has_downloadable_item = true; + } + + } + + return $has_downloadable_item; + } + + + /** + * Generates a URL so that a customer can pay for their (unpaid - pending) order. Pass 'true' for the checkout version which doesn't offer gateway choices. + * + * @access public + * @param boolean $on_checkout + * @return string + */ + public function get_checkout_payment_url( $on_checkout = false ) { + + $pay_url = wc_get_endpoint_url( 'order-pay', $this->id, get_permalink( wc_get_page_id( 'checkout' ) ) ); + + if ( 'yes' == get_option( 'woocommerce_force_ssl_checkout' ) || is_ssl() ) { + $pay_url = str_replace( 'http:', 'https:', $pay_url ); + } + + if ( $on_checkout ) { + $pay_url = add_query_arg( 'key', $this->order_key, $pay_url ); + } else { + $pay_url = add_query_arg( array( 'pay_for_order' => 'true', 'key' => $this->order_key ), $pay_url ); + } + + return apply_filters( 'woocommerce_get_checkout_payment_url', $pay_url, $this ); + } + + + /** + * Generates a URL for the thanks page (order received) + * + * @access public + * @return string + */ + public function get_checkout_order_received_url() { + + $order_received_url = wc_get_endpoint_url( 'order-received', $this->id, get_permalink( wc_get_page_id( 'checkout' ) ) ); + + if ( 'yes' == get_option( 'woocommerce_force_ssl_checkout' ) || is_ssl() ) { + $order_received_url = str_replace( 'http:', 'https:', $order_received_url ); + } + + $order_received_url = add_query_arg( 'key', $this->order_key, $order_received_url ); + + return apply_filters( 'woocommerce_get_checkout_order_received_url', $order_received_url, $this ); + } + + + /** + * Generates a URL so that a customer can cancel their (unpaid - pending) order. + * + * @access public + * @return string + */ + public function get_cancel_order_url( $redirect = '' ) { + $cancel_endpoint = get_permalink( wc_get_page_id( 'cart' ) ); + if ( ! $cancel_endpoint ) { + $cancel_endpoint = home_url(); + } + + if ( false === strpos( $cancel_endpoint, '?' ) ) { + $cancel_endpoint = trailingslashit( $cancel_endpoint ); + } + + return apply_filters('woocommerce_get_cancel_order_url', wp_nonce_url( add_query_arg( array( 'cancel_order' => 'true', 'order' => $this->order_key, 'order_id' => $this->id, 'redirect' => $redirect ), $cancel_endpoint ), 'woocommerce-cancel_order' ) ); + } + + /** + * Generates a URL to view an order from the my account page + * + * @return string + */ + public function get_view_order_url() { + $view_order_url = wc_get_endpoint_url( 'view-order', $this->id, get_permalink( wc_get_page_id( 'myaccount' ) ) ); + + return apply_filters( 'woocommerce_get_view_order_url', $view_order_url, $this ); + } + + /** + * Gets any downloadable product file urls. + * + * @deprecated as of 2.1 get_item_downloads is preferred as downloads are more than just file urls + * @param int $product_id product identifier + * @param int $variation_id variation identifier, or null + * @param array $item the item + * @return array available downloadable file urls + */ + public function get_downloadable_file_urls( $product_id, $variation_id, $item ) { + global $wpdb; + + _deprecated_function( 'get_downloadable_file_urls', '2.1', 'get_item_downloads' ); + + $download_file = $variation_id > 0 ? $variation_id : $product_id; + $_product = get_product( $download_file ); + + $user_email = $this->billing_email; + + $results = $wpdb->get_results( $wpdb->prepare(" + SELECT download_id + FROM {$wpdb->prefix}woocommerce_downloadable_product_permissions + WHERE user_email = %s + AND order_key = %s + AND product_id = %s + ", $user_email, $this->order_key, $download_file ) ); + + $file_urls = array(); + foreach ( $results as $result ) { + if ( $_product->has_file( $result->download_id ) ) { + $file_urls[ $_product->get_file_download_path( $result->download_id ) ] = $this->get_download_url( $download_file, $result->download_id ); + } + } + + return apply_filters( 'woocommerce_get_downloadable_file_urls', $file_urls, $product_id, $variation_id, $item ); + } + + /** + * Get the downloadable files for an item in this order + * @param array $item + * @return array + */ + public function get_item_downloads( $item ) { + global $wpdb; + + $product_id = $item['variation_id'] > 0 ? $item['variation_id'] : $item['product_id']; + $product = get_product( $product_id ); + $download_ids = $wpdb->get_col( $wpdb->prepare(" + SELECT download_id + FROM {$wpdb->prefix}woocommerce_downloadable_product_permissions + WHERE user_email = %s + AND order_key = %s + AND product_id = %s + ORDER BY permission_id + ", $this->billing_email, $this->order_key, $product_id ) ); + + $files = array(); + + foreach ( $download_ids as $download_id ) { + if ( $product->has_file( $download_id ) ) { + $files[ $download_id ] = $product->get_file( $download_id ); + $files[ $download_id ]['download_url'] = $this->get_download_url( $product_id, $download_id ); + } + } + + return apply_filters( 'woocommerce_get_item_downloads', $files, $item, $this ); + } + + /** + * Get the Download URL + * @param int $product_id + * @param int $download_id + * @return string + */ + public function get_download_url( $product_id, $download_id ) { + return add_query_arg( array( + 'download_file' => $product_id, + 'order' => $this->order_key, + 'email' => urlencode( $this->billing_email ), + 'key' => $download_id + ), trailingslashit( home_url() ) ); + } + + /** + * Adds a note (comment) to the order + * + * @access public + * @param string $note Note to add + * @param int $is_customer_note (default: 0) Is this a note for the customer? + * @return id Comment ID + */ + public function add_order_note( $note, $is_customer_note = 0 ) { + + $is_customer_note = intval( $is_customer_note ); + + if ( is_user_logged_in() && current_user_can( 'edit_shop_order', $this->id ) ) { + $user = get_user_by( 'id', get_current_user_id() ); + $comment_author = $user->display_name; + $comment_author_email = $user->user_email; + } else { + $comment_author = __( 'WooCommerce', 'woocommerce' ); + $comment_author_email = strtolower( __( 'WooCommerce', 'woocommerce' ) ) . '@'; + $comment_author_email .= isset( $_SERVER['HTTP_HOST'] ) ? str_replace( 'www.', '', $_SERVER['HTTP_HOST'] ) : 'noreply.com'; + $comment_author_email = sanitize_email( $comment_author_email ); + } + + $comment_post_ID = $this->id; + $comment_author_url = ''; + $comment_content = $note; + $comment_agent = 'WooCommerce'; + $comment_type = 'order_note'; + $comment_parent = 0; + $comment_approved = 1; + $commentdata = apply_filters( 'woocommerce_new_order_note_data', compact( 'comment_post_ID', 'comment_author', 'comment_author_email', 'comment_author_url', 'comment_content', 'comment_agent', 'comment_type', 'comment_parent', 'comment_approved' ), array( 'order_id' => $this->id, 'is_customer_note' => $is_customer_note ) ); + + $comment_id = wp_insert_comment( $commentdata ); + + add_comment_meta( $comment_id, 'is_customer_note', $is_customer_note ); + + if ( $is_customer_note ) { + do_action( 'woocommerce_new_customer_note', array( 'order_id' => $this->id, 'customer_note' => $note ) ); + } + + return $comment_id; + } + + /** + * Updates status of order + * + * @access public + * @param string $new_status Status to change the order to. No internal wc- prefix is required. + * @param string $note (default: '') Optional note to add + */ + public function update_status( $new_status, $note = '' ) { + $old_status = $this->get_status(); + $new_status = 'wc-' === substr( $new_status, 0, 3 ) ? substr( $new_status, 3 ) : $new_status; + + // Only update if they differ + if ( $this->id && $new_status !== $old_status ) { + + // Update the order + wp_update_post( array( 'ID' => $this->id, 'post_status' => 'wc-' . $new_status ) ); + $this->post_status = 'wc-' . $new_status; + $this->add_order_note( trim( $note . ' ' . sprintf( __( 'Order status changed from %s to %s.', 'woocommerce' ), $old_status, $new_status ) ) ); + + // Status was changed + do_action( 'woocommerce_order_status_' . $new_status, $this->id ); + do_action( 'woocommerce_order_status_' . $old_status . '_to_' . $new_status, $this->id ); + do_action( 'woocommerce_order_status_changed', $this->id, $old_status, $new_status ); + + switch ( $new_status ) { + case 'completed' : + // Record the sales + $this->record_product_sales(); + + // Increase coupon usage counts + $this->increase_coupon_usage_counts(); + + // Record the completed date of the order + update_post_meta( $this->id, '_completed_date', current_time('mysql') ); + + // Update reports + wc_delete_shop_order_transients( $this->id ); + break; + case 'processing' : + case 'on-hold' : + // Record the sales + $this->record_product_sales(); + + // Increase coupon usage counts + $this->increase_coupon_usage_counts(); + + // Update reports + wc_delete_shop_order_transients( $this->id ); + break; + case 'cancelled' : + // If the order is cancelled, restore used coupons + $this->decrease_coupon_usage_counts(); + + // Update reports + wc_delete_shop_order_transients( $this->id ); + break; + } + } + } + + + /** + * Cancel the order and restore the cart (before payment) + * + * @access public + * @param string $note (default: '') Optional note to add + * @return void + */ + public function cancel_order( $note = '' ) { + unset( WC()->session->order_awaiting_payment ); + + $this->update_status( 'cancelled', $note ); + + } + + /** + * When a payment is complete this function is called + * + * Most of the time this should mark an order as 'processing' so that admin can process/post the items + * If the cart contains only downloadable items then the order is 'completed' since the admin needs to take no action + * Stock levels are reduced at this point + * Sales are also recorded for products + * Finally, record the date of payment + * + * @access public + * @param $transaction_id string Optional transaction id to store in post meta + * @return void + */ + public function payment_complete( $transaction_id = '' ) { + + do_action( 'woocommerce_pre_payment_complete', $this->id ); + + if ( ! empty( WC()->session->order_awaiting_payment ) ) { + unset( WC()->session->order_awaiting_payment ); + } + + $valid_order_statuses = apply_filters( 'woocommerce_valid_order_statuses_for_payment_complete', array( 'on-hold', 'pending', 'failed' ), $this ); + + if ( $this->id && $this->has_status( $valid_order_statuses ) ) { + + $order_needs_processing = true; + + if ( sizeof( $this->get_items() ) > 0 ) { + + foreach( $this->get_items() as $item ) { + + if ( $item['product_id'] > 0 ) { + + $_product = $this->get_product_from_item( $item ); + + if ( false !== $_product && ( $_product->is_downloadable() && $_product->is_virtual() ) || ! apply_filters( 'woocommerce_order_item_needs_processing', true, $_product, $this->id ) ) { + $order_needs_processing = false; + continue; + } + + } + $order_needs_processing = true; + break; + } + } + + $new_order_status = $order_needs_processing ? 'processing' : 'completed'; + + $new_order_status = apply_filters( 'woocommerce_payment_complete_order_status', $new_order_status, $this->id ); + + $this->update_status( $new_order_status ); + + add_post_meta( $this->id, '_paid_date', current_time('mysql'), true ); + + if ( ! empty( $transaction_id ) ) { + add_post_meta( $this->id, '_transaction_id', $transaction_id ); + } + + $this_order = array( + 'ID' => $this->id, + 'post_date' => current_time( 'mysql', 0 ), + 'post_date_gmt' => current_time( 'mysql', 1 ) + ); + wp_update_post( $this_order ); + + if ( apply_filters( 'woocommerce_payment_complete_reduce_order_stock', true, $this->id ) ) { + $this->reduce_order_stock(); // Payment is complete so reduce stock levels + } + + do_action( 'woocommerce_payment_complete', $this->id ); + + } else { + + do_action( 'woocommerce_payment_complete_order_status_' . $this->get_status(), $this->id ); + + } + } + + + /** + * Record sales + * + * @access public + * @return void + */ + public function record_product_sales() { + + if ( 'yes' == get_post_meta( $this->id, '_recorded_sales', true ) ) { + return; + } + + if ( sizeof( $this->get_items() ) > 0 ) { + foreach ( $this->get_items() as $item ) { + if ( $item['product_id'] > 0 ) { + $sales = (int) get_post_meta( $item['product_id'], 'total_sales', true ); + $sales += (int) $item['qty']; + if ( $sales ) { + update_post_meta( $item['product_id'], 'total_sales', $sales ); + } + } + } + } + + update_post_meta( $this->id, '_recorded_sales', 'yes' ); + } + + + /** + * Get coupon codes only. + * + * @access public + * @return array + */ + public function get_used_coupons() { + + $codes = array(); + $coupons = $this->get_items( 'coupon' ); + + foreach ( $coupons as $item_id => $item ) { + $codes[] = trim( $item['name'] ); + } + + return $codes; + } + + + /** + * Increase applied coupon counts + * + * @access public + * @return void + */ + public function increase_coupon_usage_counts() { + + if ( 'yes' == get_post_meta( $this->id, '_recorded_coupon_usage_counts', true ) ) { + return; + } + + if ( sizeof( $this->get_used_coupons() ) > 0 ) { + foreach ( $this->get_used_coupons() as $code ) { + if ( ! $code ) { + continue; + } + + $coupon = new WC_Coupon( $code ); + + $used_by = $this->user_id; + if ( ! $used_by ) { + $used_by = $this->billing_email; + } + + $coupon->inc_usage_count( $used_by ); + } + } + + update_post_meta( $this->id, '_recorded_coupon_usage_counts', 'yes' ); + } + + + /** + * Decrease applied coupon counts + * + * @access public + * @return void + */ + public function decrease_coupon_usage_counts() { + + if ( 'yes' != get_post_meta( $this->id, '_recorded_coupon_usage_counts', true ) ) { + return; + } + + if ( sizeof( $this->get_used_coupons() ) > 0 ) { + foreach ( $this->get_used_coupons() as $code ) { + if ( ! $code ) { + continue; + } + + $coupon = new WC_Coupon( $code ); + + $used_by = $this->user_id; + if ( ! $used_by ) { + $used_by = $this->billing_email; + } + + $coupon->dcr_usage_count( $used_by ); + } + } + + delete_post_meta( $this->id, '_recorded_coupon_usage_counts' ); + } + + + /** + * Reduce stock levels + * + * @access public + * @return void + */ + public function reduce_order_stock() { + + if ( 'yes' == get_option('woocommerce_manage_stock') && sizeof( $this->get_items() ) > 0 ) { + + // Reduce stock levels and do any other actions with products in the cart + foreach ( $this->get_items() as $item ) { + + if ( $item['product_id'] > 0 ) { + $_product = $this->get_product_from_item( $item ); + + if ( $_product && $_product->exists() && $_product->managing_stock() ) { + $qty = apply_filters( 'woocommerce_order_item_quantity', $item['qty'], $this, $item ); + $new_stock = $_product->reduce_stock( $qty ); + + $this->add_order_note( sprintf( __( 'Item #%s stock reduced from %s to %s.', 'woocommerce' ), $item['product_id'], $new_stock + $qty, $new_stock) ); + $this->send_stock_notifications( $_product, $new_stock, $item['qty'] ); + } + + } + + } + + do_action( 'woocommerce_reduce_order_stock', $this ); + + $this->add_order_note( __( 'Order item stock reduced successfully.', 'woocommerce' ) ); + } + } + + /** + * send_stock_notifications function. + * + * @access public + * @param object $product + * @param int $new_stock + * @param int $qty_ordered + * @return void + */ + public function send_stock_notifications( $product, $new_stock, $qty_ordered ) { + + // Backorders + if ( $new_stock < 0 ) { + do_action( 'woocommerce_product_on_backorder', array( 'product' => $product, 'order_id' => $this->id, 'quantity' => $qty_ordered ) ); + } + + // stock status notifications + $notification_sent = false; + + if ( 'yes' == get_option( 'woocommerce_notify_no_stock' ) && get_option('woocommerce_notify_no_stock_amount') >= $new_stock ) { + do_action( 'woocommerce_no_stock', $product ); + $notification_sent = true; + } + if ( ! $notification_sent && 'yes' == get_option( 'woocommerce_notify_low_stock' ) && get_option('woocommerce_notify_low_stock_amount') >= $new_stock ) { + do_action( 'woocommerce_low_stock', $product ); + $notification_sent = true; + } + + } + + + /** + * List order notes (public) for the customer + * + * @access public + * @return array + */ + public function get_customer_order_notes() { + + $notes = array(); + + $args = array( + 'post_id' => $this->id, + 'approve' => 'approve', + 'type' => '' + ); + + remove_filter( 'comments_clauses', array( 'WC_Comments', 'exclude_order_comments' ) ); + + $comments = get_comments( $args ); + + foreach ( $comments as $comment ) { + $is_customer_note = get_comment_meta( $comment->comment_ID, 'is_customer_note', true ); + $comment->comment_content = make_clickable( $comment->comment_content ); + if ( $is_customer_note ) { + $notes[] = $comment; + } + } + + add_filter( 'comments_clauses', array( 'WC_Comments', 'exclude_order_comments' ) ); + + return (array) $notes; + + } + + /** + * Checks if an order needs payment, based on status and order total + * + * @access public + * @return bool + */ + public function needs_payment() { + $valid_order_statuses = apply_filters( 'woocommerce_valid_order_statuses_for_payment', array( 'pending', 'failed' ), $this ); + + if ( $this->has_status( $valid_order_statuses ) && $this->get_total() > 0 ) { + $needs_payment = true; + } else { + $needs_payment = false; + } + + return apply_filters( 'woocommerce_order_needs_payment', $needs_payment, $this, $valid_order_statuses ); + } + + /** + * Checks if an order needs display the shipping address, based on shipping method + * + * @access public + * @return bool + */ + public function needs_shipping_address() { + $hide = apply_filters( 'woocommerce_order_hide_shipping_address', array( 'local_pickup' ), $this ); + $needs = false; + + foreach ( $this->get_shipping_methods() as $shipping_method ) { + if ( ! in_array( $shipping_method['method_id'], $hide ) ) { + $needs = true; + break; + } + } + } +} \ No newline at end of file diff --git a/includes/abstracts/abstract-wc-payment-gateway.php b/includes/abstracts/abstract-wc-payment-gateway.php index 2c5f66ac4a2..14528b697bc 100644 --- a/includes/abstracts/abstract-wc-payment-gateway.php +++ b/includes/abstracts/abstract-wc-payment-gateway.php @@ -100,7 +100,7 @@ abstract class WC_Payment_Gateway extends WC_Settings_API { // Gets order total from "pay for order" page. if ( 0 < $order_id ) { - $order = new WC_Order( $order_id ); + $order = get_order( $order_id ); $total = (float) $order->get_total(); // Gets order total from cart/checkout. diff --git a/includes/admin/class-wc-admin-post-types.php b/includes/admin/class-wc-admin-post-types.php index 7710ed29acc..16300f3a56d 100644 --- a/includes/admin/class-wc-admin-post-types.php +++ b/includes/admin/class-wc-admin-post-types.php @@ -439,7 +439,7 @@ class WC_Admin_Post_Types { global $post, $woocommerce, $the_order; if ( empty( $the_order ) || $the_order->id != $post->ID ) { - $the_order = new WC_Order( $post->ID ); + $the_order = get_order( $post->ID ); } switch ( $column ) { @@ -1180,7 +1180,7 @@ class WC_Admin_Post_Types { $post_ids = array_map( 'absint', (array) $_REQUEST['post'] ); foreach ( $post_ids as $post_id ) { - $order = new WC_Order( $post_id ); + $order = get_order( $post_id ); $order->update_status( $new_status, __( 'Order status changed by bulk edit:', 'woocommerce' ) ); $changed++; } @@ -2015,7 +2015,7 @@ class WC_Admin_Post_Types { $existing_permissions = $wpdb->get_results( $wpdb->prepare( "SELECT * from {$wpdb->prefix}woocommerce_downloadable_product_permissions WHERE product_id = %d GROUP BY order_id", $product_id ) ); foreach ( $existing_permissions as $existing_permission ) { - $order = new WC_Order( $existing_permission->order_id ); + $order = get_order( $existing_permission->order_id ); if ( $order->id ) { // Remove permissions diff --git a/includes/admin/meta-boxes/class-wc-meta-box-order-actions.php b/includes/admin/meta-boxes/class-wc-meta-box-order-actions.php index 670944a9b01..28d60351479 100644 --- a/includes/admin/meta-boxes/class-wc-meta-box-order-actions.php +++ b/includes/admin/meta-boxes/class-wc-meta-box-order-actions.php @@ -21,7 +21,7 @@ class WC_Meta_Box_Order_Actions { global $theorder; if ( ! is_object( $theorder ) ) - $theorder = new WC_Order( $post->ID ); + $theorder = get_order( $post->ID ); $order = $theorder; ?> @@ -82,7 +82,7 @@ class WC_Meta_Box_Order_Actions { */ public static function save( $post_id, $post ) { // Order data saved, now get it so we can manipulate status - $order = new WC_Order( $post_id ); + $order = get_order( $post_id ); // Handle button actions if ( ! empty( $_POST['wc_order_action'] ) ) { diff --git a/includes/admin/meta-boxes/class-wc-meta-box-order-data.php b/includes/admin/meta-boxes/class-wc-meta-box-order-data.php index d10ba27e443..828722e391d 100644 --- a/includes/admin/meta-boxes/class-wc-meta-box-order-data.php +++ b/includes/admin/meta-boxes/class-wc-meta-box-order-data.php @@ -133,7 +133,7 @@ class WC_Meta_Box_Order_Data { global $theorder; if ( ! is_object( $theorder ) ) { - $theorder = new WC_Order( $post->ID ); + $theorder = get_order( $post->ID ); } $order = $theorder; @@ -441,7 +441,7 @@ class WC_Meta_Box_Order_Data { $wpdb->query( $wpdb->prepare( "UPDATE $wpdb->posts SET post_date = %s, post_date_gmt = %s WHERE ID = %s", $date, get_gmt_from_date( $date ), $post_id ) ); // Order data saved, now get it so we can manipulate status - $order = new WC_Order( $post_id ); + $order = get_order( $post_id ); // Order status $order->update_status( $_POST['order_status'] ); diff --git a/includes/admin/meta-boxes/class-wc-meta-box-order-items.php b/includes/admin/meta-boxes/class-wc-meta-box-order-items.php index 254f9762072..cc250e0e87e 100644 --- a/includes/admin/meta-boxes/class-wc-meta-box-order-items.php +++ b/includes/admin/meta-boxes/class-wc-meta-box-order-items.php @@ -21,7 +21,7 @@ class WC_Meta_Box_Order_Items { global $thepostid, $theorder; if ( ! is_object( $theorder ) ) - $theorder = new WC_Order( $thepostid ); + $theorder = get_order( $thepostid ); $order = $theorder; ?> diff --git a/includes/admin/meta-boxes/class-wc-meta-box-order-totals.php b/includes/admin/meta-boxes/class-wc-meta-box-order-totals.php index ac3f5a84de1..a5b2aacac1f 100644 --- a/includes/admin/meta-boxes/class-wc-meta-box-order-totals.php +++ b/includes/admin/meta-boxes/class-wc-meta-box-order-totals.php @@ -21,7 +21,7 @@ class WC_Meta_Box_Order_Totals { global $theorder, $wpdb, $post; if ( ! is_object( $theorder ) ) - $theorder = new WC_Order( $post->ID ); + $theorder = get_order( $post->ID ); $order = $theorder; diff --git a/includes/admin/reports/class-wc-report-customer-list.php b/includes/admin/reports/class-wc-report-customer-list.php index 595d38115fc..7636fa8ea8e 100644 --- a/includes/admin/reports/class-wc-report-customer-list.php +++ b/includes/admin/reports/class-wc-report-customer-list.php @@ -163,7 +163,7 @@ class WC_Report_Customer_List extends WP_List_Table { ) ); if ( $order_ids ) { - $order = new WC_Order( $order_ids[0] ); + $order = get_order( $order_ids[0] ); echo '' . $order->get_order_number() . ' – ' . date_i18n( get_option( 'date_format' ), strtotime( $order->order_date ) ); } else echo '-'; diff --git a/includes/api/class-wc-api-orders.php b/includes/api/class-wc-api-orders.php index 4f69648650a..d7860538a62 100644 --- a/includes/api/class-wc-api-orders.php +++ b/includes/api/class-wc-api-orders.php @@ -106,7 +106,7 @@ class WC_API_Orders extends WC_API_Resource { if ( is_wp_error( $id ) ) return $id; - $order = new WC_Order( $id ); + $order = get_order( $id ); $order_post = get_post( $id ); @@ -275,7 +275,7 @@ class WC_API_Orders extends WC_API_Resource { if ( is_wp_error( $id ) ) return $id; - $order = new WC_Order( $id ); + $order = get_order( $id ); if ( ! empty( $data['status'] ) ) { diff --git a/includes/class-wc-ajax.php b/includes/class-wc-ajax.php index bacc884e0c8..8fae68c7ad9 100644 --- a/includes/class-wc-ajax.php +++ b/includes/class-wc-ajax.php @@ -351,7 +351,7 @@ class WC_AJAX { die(); } - $order = new WC_Order( $order_id ); + $order = get_order( $order_id ); $order->update_status( 'completed' ); wp_safe_redirect( wp_get_referer() ); @@ -376,7 +376,7 @@ class WC_AJAX { die(); } - $order = new WC_Order( $order_id ); + $order = get_order( $order_id ); $order->update_status( 'processing' ); wp_safe_redirect( wp_get_referer() ); @@ -847,7 +847,7 @@ class WC_AJAX { $product_ids = $_POST['product_ids']; $loop = intval( $_POST['loop'] ); $file_counter = 0; - $order = new WC_Order( $order_id ); + $order = get_order( $order_id ); if ( ! is_array( $product_ids ) ) { $product_ids = array( $product_ids ); @@ -936,7 +936,7 @@ class WC_AJAX { } $_product = get_product( $post->ID ); - $order = new WC_Order( $order_id ); + $order = get_order( $order_id ); $class = 'new_row'; // Set values @@ -996,7 +996,7 @@ class WC_AJAX { check_ajax_referer( 'order-item', 'security' ); $order_id = absint( $_POST['order_id'] ); - $order = new WC_Order( $order_id ); + $order = get_order( $order_id ); // Add line item $item_id = wc_add_order_item( $order_id, array( @@ -1043,7 +1043,7 @@ class WC_AJAX { $order_id = absint( $_POST['order_id'] ); $order_item_ids = isset( $_POST['order_item_ids'] ) ? $_POST['order_item_ids'] : array(); $order_item_qty = isset( $_POST['order_item_qty'] ) ? $_POST['order_item_qty'] : array(); - $order = new WC_Order( $order_id ); + $order = get_order( $order_id ); $order_items = $order->get_items(); $return = array(); @@ -1089,7 +1089,7 @@ class WC_AJAX { $order_id = absint( $_POST['order_id'] ); $order_item_ids = isset( $_POST['order_item_ids'] ) ? $_POST['order_item_ids'] : array(); $order_item_qty = isset( $_POST['order_item_qty'] ) ? $_POST['order_item_qty'] : array(); - $order = new WC_Order( $order_id ); + $order = get_order( $order_id ); $order_items = $order->get_items(); $return = array(); @@ -1169,7 +1169,7 @@ class WC_AJAX { $taxes = $tax_rows = $item_taxes = $shipping_taxes = array(); $order_id = absint( $_POST['order_id'] ); - $order = new WC_Order( $order_id ); + $order = get_order( $order_id ); $country = strtoupper( esc_attr( $_POST['country'] ) ); $state = strtoupper( esc_attr( $_POST['state'] ) ); $postcode = strtoupper( esc_attr( $_POST['postcode'] ) ); @@ -1285,7 +1285,7 @@ class WC_AJAX { $is_customer_note = $note_type == 'customer' ? 1 : 0; if ( $post_id > 0 ) { - $order = new WC_Order( $post_id ); + $order = get_order( $post_id ); $comment_id = $order->add_order_note( $note, $is_customer_note ); echo '
  • ' . __( 'Go to homepage', 'woocommerce' ) . '', '', array( 'response' => 404 ) ); diff --git a/includes/class-wc-emails.php b/includes/class-wc-emails.php index da8bce26d96..01d0ba5bfc5 100644 --- a/includes/class-wc-emails.php +++ b/includes/class-wc-emails.php @@ -412,7 +412,7 @@ class WC_Emails { else $title = sprintf(__( 'Product #%s - %s', 'woocommerce' ), $product->id, get_the_title($product->id)) . $sku; - $order = new WC_Order( $order_id ); + $order = get_order( $order_id ); $message = sprintf(__( '%s units of %s have been backordered in order %s.', 'woocommerce' ), $quantity, $title, $order->get_order_number() ); // CC, BCC, additional headers diff --git a/includes/class-wc-form-handler.php b/includes/class-wc-form-handler.php index bd8b3ced679..4216b28e172 100755 --- a/includes/class-wc-form-handler.php +++ b/includes/class-wc-form-handler.php @@ -264,7 +264,7 @@ class WC_Form_Handler { // Pay for existing order $order_key = $_GET['key']; $order_id = absint( $wp->query_vars['order-pay'] ); - $order = new WC_Order( $order_id ); + $order = get_order( $order_id ); $valid_order_statuses = apply_filters( 'woocommerce_valid_order_statuses_for_payment', array( 'pending', 'failed' ), $order ); @@ -462,7 +462,7 @@ class WC_Form_Handler { WC()->cart->empty_cart(); // Load the previous order - Stop if the order does not exist - $order = new WC_Order( absint( $_GET['order_again'] ) ); + $order = get_order( absint( $_GET['order_again'] ) ); if ( empty( $order->id ) ) { return; @@ -519,7 +519,7 @@ class WC_Form_Handler { $order_key = $_GET['order']; $order_id = absint( $_GET['order_id'] ); - $order = new WC_Order( $order_id ); + $order = get_order( $order_id ); $user_can_cancel = current_user_can( 'cancel_order', $order_id ); $order_can_cancel = $order->has_status( apply_filters( 'woocommerce_valid_order_statuses_for_cancel', array( 'pending', 'failed' ) ) ); $redirect = $_GET['redirect']; diff --git a/includes/class-wc-order-factory.php b/includes/class-wc-order-factory.php new file mode 100644 index 00000000000..c4d28f74e3b --- /dev/null +++ b/includes/class-wc-order-factory.php @@ -0,0 +1,57 @@ +ID ); + $post_type = $the_order->post_type; + } + + if ( 'shop_order' == $post_type ) { + $classname = 'WC_Order'; + $order_type = 'simple'; + } else { + $classname = false; + $order_type = false; + } + + // Filter classname so that the class can be overridden if extended. + $classname = apply_filters( 'woocommerce_order_class', $classname, $order_type, $post_type, $order_id ); + + if ( ! class_exists( $classname ) ) + $classname = 'WC_Order'; + + return new $classname( $the_order, $args ); + } +} \ No newline at end of file diff --git a/includes/class-wc-order.php b/includes/class-wc-order.php index 408a214ad38..07a114430c0 100644 --- a/includes/class-wc-order.php +++ b/includes/class-wc-order.php @@ -1,2078 +1,18 @@ prices_include_tax = get_option('woocommerce_prices_include_tax') == 'yes' ? true : false; - $this->tax_display_cart = get_option( 'woocommerce_tax_display_cart' ); - - $this->display_totals_ex_tax = $this->tax_display_cart == 'excl' ? true : false; - $this->display_cart_ex_tax = $this->tax_display_cart == 'excl' ? true : false; - - if ( $id > 0 ) { - $this->get_order( $id ); - } - } - - /** - * Remove all line items (products, coupons, shipping, taxes) from the order. - */ - public function remove_order_items( $type = null ) { - global $wpdb; - - if ( $type ) { - $wpdb->query( $wpdb->prepare( "DELETE FROM {$wpdb->prefix}woocommerce_order_itemmeta WHERE order_item_id IN ( SELECT order_item_id FROM {$wpdb->prefix}woocommerce_order_items WHERE order_id = %d AND order_item_type = %s )", $this->id, $type ) ); - $wpdb->query( $wpdb->prepare( "DELETE FROM {$wpdb->prefix}woocommerce_order_items WHERE order_id = %d AND order_item_type = %s", $this->id, $type ) ); - } else { - $wpdb->query( $wpdb->prepare( "DELETE FROM {$wpdb->prefix}woocommerce_order_itemmeta WHERE order_item_id IN ( SELECT order_item_id FROM {$wpdb->prefix}woocommerce_order_items WHERE order_id = %d )", $this->id ) ); - $wpdb->query( $wpdb->prepare( "DELETE FROM {$wpdb->prefix}woocommerce_order_items WHERE order_id = %d", $this->id ) ); - } - } - - /** - * Set the payment method for the order - * @param WC_Payment_Gateway - */ - public function set_payment_method( $payment_method ) { - if ( is_object( $payment_method ) ) { - update_post_meta( $this->id, '_payment_method', $payment_method->id ); - update_post_meta( $this->id, '_payment_method_title', $payment_method->get_title() ); - } - } - - /** - * Set the customer address - * @param array $address Address data - * @param string $type billing or shipping - */ - public function set_address( $address, $type = 'billing' ) { - foreach( $address as $key => $value ) { - update_post_meta( $this->id, "_{$type}_" . $key, $value ); - } - } - - /** - * Add a product line item to the order - * @param WC_Product $item - * @param int $qty Line item quantity - * @param array args - * @return int|bool Item ID or false - */ - public function add_product( $product, $qty = 1, $args = array() ) { - $default_args = array( - 'variation' => array(), - 'totals' => array() - ); - - $args = wp_parse_args( $args, $default_args ); - $item_id = wc_add_order_item( $this->id, array( - 'order_item_name' => $product->get_title(), - 'order_item_type' => 'line_item' - ) ); - - if ( ! $item_id ) { - return false; - } - - wc_add_order_item_meta( $item_id, '_qty', wc_stock_amount( $qty ) ); - wc_add_order_item_meta( $item_id, '_tax_class', $product->get_tax_class() ); - wc_add_order_item_meta( $item_id, '_product_id', $product->id ); - wc_add_order_item_meta( $item_id, '_variation_id', isset( $product->variation_id ) ? $product->variation_id : 0 ); - - // Set line item totals, either passed in or from the product - wc_add_order_item_meta( $item_id, '_line_subtotal', wc_format_decimal( isset( $args['totals']['subtotal'] ) ? $args['totals']['subtotal'] : $product->get_price_excluding_tax( $qty ) ) ); - wc_add_order_item_meta( $item_id, '_line_total', wc_format_decimal( isset( $args['totals']['total'] ) ? $args['totals']['total'] : $product->get_price_excluding_tax( $qty ) ) ); - wc_add_order_item_meta( $item_id, '_line_subtotal_tax', wc_format_decimal( isset( $args['totals']['subtotal_tax'] ) ? $args['totals']['subtotal_tax'] : 0 ) ); - wc_add_order_item_meta( $item_id, '_line_tax', wc_format_decimal( isset( $args['totals']['tax'] ) ? $args['totals']['tax'] : 0 ) ); - - // Add variation meta - foreach ( $args['variation'] as $key => $value ) { - wc_add_order_item_meta( $item_id, str_replace( 'attribute_', '', $key ), $value ); - } - - // Backorders - if ( $product->backorders_require_notification() && $product->is_on_backorder( $qty ) ) { - wc_add_order_item_meta( $item_id, apply_filters( 'woocommerce_backordered_item_meta_name', __( 'Backordered', 'woocommerce' ) ), $qty - max( 0, $product->get_total_stock() ) ); - } - - do_action( 'woocommerce_order_add_product', $this->id, $item_id, $product, $qty, $args ); - - return $item_id; - } - - /** - * Add coupon code to the order - * @param string $code - * @param float $discount_amount - * @return int|bool Item ID or false - */ - public function add_coupon( $code, $discount_amount = 0 ) { - $item_id = wc_add_order_item( $this->id, array( - 'order_item_name' => $code, - 'order_item_type' => 'coupon' - ) ); - - if ( ! $item_id ) { - return false; - } - - wc_add_order_item_meta( $item_id, 'discount_amount', $discount_amount ); - - do_action( 'woocommerce_order_add_coupon', $this->id, $item_id, $code, $discount_amount ); - - return $item_id; - } - - /** - * Add a tax row to the order - * @param int tax_rate_id - * @return int|bool Item ID or false - */ - public function add_tax( $tax_rate_id, $tax_amount = 0, $shipping_tax_amount = 0 ) { - $code = WC_Tax::get_rate_code( $tax_rate_id ); - - if ( ! $code ) { - return false; - } - - $item_id = wc_add_order_item( $this->id, array( - 'order_item_name' => $code, - 'order_item_type' => 'tax' - ) ); - - if ( ! $item_id ) { - return false; - } - - wc_add_order_item_meta( $item_id, 'rate_id', $tax_rate_id ); - wc_add_order_item_meta( $item_id, 'label', WC_Tax::get_rate_label( $tax_rate_id ) ); - wc_add_order_item_meta( $item_id, 'compound', WC_Tax::is_compound( $tax_rate_id ) ? 1 : 0 ); - wc_add_order_item_meta( $item_id, 'tax_amount', wc_format_decimal( $tax_amount ) ); - wc_add_order_item_meta( $item_id, 'shipping_tax_amount', wc_format_decimal( $shipping_tax_amount ) ); - - do_action( 'woocommerce_order_add_tax', $this->id, $item_id, $tax_rate_id, $tax_amount, $shipping_tax_amount ); - - return $item_id; - } - - /** - * Add a shipping row to the order - * @param WC_Shipping_Rate shipping_rate - * @return int|bool Item ID or false - */ - public function add_shipping( $shipping_rate ) { - $item_id = wc_add_order_item( $this->id, array( - 'order_item_name' => $shipping_rate->label, - 'order_item_type' => 'shipping' - ) ); - - if ( ! $item_id ) { - return false; - } - - wc_add_order_item_meta( $item_id, 'method_id', $shipping_rate->id ); - wc_add_order_item_meta( $item_id, 'cost', wc_format_decimal( $shipping_rate->cost ) ); - - do_action( 'woocommerce_order_add_shipping', $this->id, $item_id, $shipping_rate ); - - // Update total - $this->set_total( $this->order_shipping + wc_format_decimal( $shipping_rate->cost ), 'shipping' ); - - return $item_id; - } - - /** - * Add a fee to the order - * @param object $fee - * @return int|bool Item ID or false - */ - public function add_fee( $fee ) { - $item_id = wc_add_order_item( $this->id, array( - 'order_item_name' => $fee->name, - 'order_item_type' => 'fee' - ) ); - - if ( ! $item_id ) { - return false; - } - - if ( $fee->taxable ) { - wc_add_order_item_meta( $item_id, '_tax_class', $fee->tax_class ); - } else { - wc_add_order_item_meta( $item_id, '_tax_class', '0' ); - } - - wc_add_order_item_meta( $item_id, '_line_total', wc_format_decimal( $fee->amount ) ); - wc_add_order_item_meta( $item_id, '_line_tax', wc_format_decimal( $fee->tax ) ); - - do_action( 'woocommerce_order_add_fee', $this->id, $item_id, $fee ); - - return $item_id; - } - - /** - * Set an order total - * @param float $amount - * @param string $total_type - */ - public function set_total( $amount, $total_type = 'total' ) { - if ( ! in_array( $total_type, array( 'shipping', 'order_discount', 'tax', 'shipping_tax', 'total', 'cart_discount' ) ) ) { - return false; - } - switch ( $total_type ) { - case 'total' : - $key = '_order_total'; - $amount = wc_format_decimal( $amount, get_option( 'woocommerce_price_num_decimals' ) ); - break; - case 'order_discount' : - case 'cart_discount' : - $key = '_' . $total_type; - $amount = wc_format_decimal( $amount ); - break; - default : - $key = '_order_' . $total_type; - $amount = wc_format_decimal( $amount ); - break; - } - update_post_meta( $this->id, $key, $amount ); - } - - /** - * Calculate taxes for all line items and shipping, and store the totals and tax rows. - * - * Will use the base country unless customer addresses are set. - * - * @return bool success or fail - */ - public function calculate_taxes() { - $shipping_tax_total = 0; - $tax_total = 0; - $taxes = array(); - $tax_based_on = get_option( 'woocommerce_tax_based_on' ); - - if ( 'base' === $tax_based_on ) { - $default = get_option( 'woocommerce_default_country' ); - $postcode = ''; - $city = ''; - if ( strstr( $default, ':' ) ) { - list( $country, $state ) = explode( ':', $default ); - } else { - $country = $default; - $state = ''; - } - } elseif ( 'billing' === $tax_based_on ) { - $country = $this->billing_country; - $state = $this->billing_state; - $postcode = $this->billing_postcode; - $city = $this->billing_city; - } else { - $country = $this->shipping_country; - $state = $this->shipping_state; - $postcode = $this->shipping_postcode; - $city = $this->shipping_city; - } - - // Get items - foreach ( $this->get_items( array( 'line_item', 'fee' ) ) as $item_id => $item ) { - $product = $this->get_product_from_item( $item ); - $line_total = isset( $item['line_total'] ) ? $item['line_total'] : 0; - $line_subtotal = isset( $item['line_subtotal'] ) ? $item['line_subtotal'] : 0; - $tax_class = $item['tax_class']; - $item_tax_status = $product ? $product->get_tax_status() : 'taxable'; - - if ( '0' !== $tax_class && 'taxable' === $item_tax_status ) { - $tax_rates = WC_Tax::find_rates( array( - 'country' => $country, - 'state' => $state, - 'postcode' => $postcode, - 'city' => $city, - 'tax_class' => $tax_class - ) ); - $line_subtotal_taxes = WC_Tax::calc_tax( $line_subtotal, $tax_rates, false ); - $line_taxes = WC_Tax::calc_tax( $line_total, $tax_rates, false ); - $line_subtotal_tax = max( 0, array_sum( $line_subtotal_taxes ) ); - $line_tax = max( 0, array_sum( $line_taxes ) ); - $tax_total += $line_tax; - - wc_update_order_item_meta( $item_id, '_line_subtotal_tax', wc_format_decimal( $line_subtotal_tax ) ); - wc_update_order_item_meta( $item_id, '_line_tax', wc_format_decimal( $line_tax ) ); - - // Sum the item taxes - foreach ( array_keys( $taxes + $line_taxes ) as $key ) { - $taxes[ $key ] = ( isset( $line_taxes[ $key ] ) ? $line_taxes[ $key ] : 0 ) + ( isset( $taxes[ $key ] ) ? $taxes[ $key ] : 0 ); - } - } - } - - // Now calculate shipping tax - $matched_tax_rates = array(); - $tax_rates = WC_Tax::find_rates( array( - 'country' => $country, - 'state' => $state, - 'postcode' => $postcode, - 'city' => $city, - 'tax_class' => '' - ) ); - - if ( $tax_rates ) { - foreach ( $tax_rates as $key => $rate ) { - if ( isset( $rate['shipping'] ) && 'yes' === $rate['shipping'] ) { - $matched_tax_rates[ $key ] = $rate; - } - } - } - - $shipping_taxes = WC_Tax::calc_shipping_tax( $this->order_shipping, $matched_tax_rates ); - $shipping_tax_total = WC_Tax::round( array_sum( $shipping_taxes ) ); - - // Save tax totals - $this->set_total( $shipping_tax_total, 'shipping_tax' ); - $this->set_total( $tax_total, 'tax' ); - - // Tax rows - $this->remove_order_items( 'tax' ); - - // Now merge to keep tax rows - foreach ( array_keys( $taxes + $shipping_taxes ) as $tax_rate_id ) { - $this->add_tax( $tax_rate_id, isset( $taxes[ $tax_rate_id ] ) ? $taxes[ $tax_rate_id ] : 0, isset( $shipping_taxes[ $tax_rate_id ] ) ? $shipping_taxes[ $tax_rate_id ] : 0 ); - } - - return true; - } - - /** - * Calculate totals by looking at the contents of the order. Stores the totals and returns the orders final total. - * - * @return $total calculated grand total - */ - public function calculate_totals() { - $cart_subtotal = 0; - $cart_total = 0; - $fee_total = 0; - - $this->calculate_taxes(); - - foreach ( $this->get_items() as $item ) { - $cart_subtotal += wc_format_decimal( isset( $item['line_subtotal'] ) ? $item['line_subtotal'] : 0 ); - $cart_total += wc_format_decimal( isset( $item['line_total'] ) ? $item['line_total'] : 0 ); - } - - foreach ( $this->get_fees() as $item ) { - $fee_total += $item['line_total']; - } - - $grand_total = round( $cart_total + $fee_total + $this->get_total_shipping() - $this->get_order_discount() + $this->get_cart_tax() + $this->get_shipping_tax(), absint( get_option( 'woocommerce_price_num_decimals' ) ) ); - - $this->set_total( $cart_subtotal - $cart_total, 'cart_discount' ); - $this->set_total( $grand_total, 'total' ); - - return $grand_total; - } - - /** - * Gets an order from the database. - * - * @access public - * @param int $id (default: 0) - * @return bool - */ - public function get_order( $id = 0 ) { - if ( ! $id ) { - return false; - } - if ( $result = get_post( $id ) ) { - $this->populate( $result ); - return true; - } - return false; - } - - /** - * Populates an order from the loaded post data. - * - * @access public - * @param mixed $result - * @return void - */ - public function populate( $result ) { - // Standard post data - $this->id = $result->ID; - $this->order_date = $result->post_date; - $this->modified_date = $result->post_modified; - $this->customer_message = $result->post_excerpt; - $this->customer_note = $result->post_excerpt; - $this->post_status = $result->post_status; - - // Billing email cam default to user if set - if ( empty( $this->billing_email ) && ! empty( $this->customer_user ) ) { - $user = get_user_by( 'id', $this->customer_user ); - $this->billing_email = $user->user_email; - } - } - - /** - * __isset function. - * - * @access public - * @param mixed $key - * @return bool - */ - public function __isset( $key ) { - if ( ! $this->id ) { - return false; - } - return metadata_exists( 'post', $this->id, '_' . $key ); - } - - /** - * __get function. - * - * @access public - * @param mixed $key - * @return mixed - */ - public function __get( $key ) { - // Get values or default if not set - if ( 'completed_date' === $key ) { - $value = ( $value = get_post_meta( $this->id, '_completed_date', true ) ) ? $value : $this->modified_date; - } elseif ( 'user_id' === $key ) { - $value = ( $value = get_post_meta( $this->id, '_customer_user', true ) ) ? absint( $value ) : ''; - } elseif ( 'status' === $key ) { - $value = $this->get_status(); - } else { - $value = get_post_meta( $this->id, '_' . $key, true ); - } - return $value; - } - - /** - * Return the order statuses without wc- internal prefix - * @return string - */ - public function get_status() { - return apply_filters( 'woocommerce_order_get_status', 'wc-' === substr( $this->post_status, 0, 3 ) ? substr( $this->post_status, 3 ) : $this->post_status, $this ); - } - - /** - * Checks the order status against a passed in status. - * - * @access public - * @param mixed $type Array or string of types - * @return bool - */ - public function has_status( $status ) { - return apply_filters( 'woocommerce_order_has_status', ( is_array( $status ) && in_array( $this->get_status(), $status ) ) || $this->get_status() === $status ? true : false, $this, $status ); - } - - /** - * Gets the user ID associated with the order. Guests are 0. - * @since 2.2 - * @return int|false - */ - public function get_user_id() { - return $this->customer_user ? $this->customer_user : 0; - } - - /** - * Get the user associated with the order. False for guests. - * @since 2.2 - * @return WP_User|false - */ - public function get_user() { - return $user_id = $this->get_user_id() ? get_user_by( 'id', $user_id ) : false; - } - - /** - * Check if an order key is valid. - * - * @access public - * @param mixed $key - * @return bool - */ - public function key_is_valid( $key ) { - if ( $key == $this->order_key ) { - return true; - } - return false; - } - - /** - * get_order_number function. - * - * Gets the order number for display (by default, order ID) - * - * @access public - * @return string - */ - public function get_order_number() { - return apply_filters( 'woocommerce_order_number', _x( '#', 'hash before order number', 'woocommerce' ) . $this->id, $this ); - } - - /** - * Get a formatted billing address for the order. - * - * @access public - * @return string - */ - public function get_formatted_billing_address() { - if ( ! $this->formatted_billing_address ) { - - // Formatted Addresses - $address = apply_filters( 'woocommerce_order_formatted_billing_address', array( - 'first_name' => $this->billing_first_name, - 'last_name' => $this->billing_last_name, - 'company' => $this->billing_company, - 'address_1' => $this->billing_address_1, - 'address_2' => $this->billing_address_2, - 'city' => $this->billing_city, - 'state' => $this->billing_state, - 'postcode' => $this->billing_postcode, - 'country' => $this->billing_country - ), $this ); - - $this->formatted_billing_address = WC()->countries->get_formatted_address( $address ); - } - return $this->formatted_billing_address; - } - - /** - * Get the billing address in an array. - * - * @access public - * @return string - */ - public function get_billing_address() { - if ( ! $this->billing_address ) { - // Formatted Addresses - $address = array( - 'address_1' => $this->billing_address_1, - 'address_2' => $this->billing_address_2, - 'city' => $this->billing_city, - 'state' => $this->billing_state, - 'postcode' => $this->billing_postcode, - 'country' => $this->billing_country - ); - $joined_address = array(); - foreach ( $address as $part ) { - if ( ! empty( $part ) ) { - $joined_address[] = $part; - } - } - $this->billing_address = implode( ', ', $joined_address ); - } - return $this->billing_address; - } - - /** - * Get a formatted shipping address for the order. - * - * @access public - * @return string - */ - public function get_formatted_shipping_address() { - if ( ! $this->formatted_shipping_address ) { - if ( $this->shipping_address_1 ) { - - // Formatted Addresses - $address = apply_filters( 'woocommerce_order_formatted_shipping_address', array( - 'first_name' => $this->shipping_first_name, - 'last_name' => $this->shipping_last_name, - 'company' => $this->shipping_company, - 'address_1' => $this->shipping_address_1, - 'address_2' => $this->shipping_address_2, - 'city' => $this->shipping_city, - 'state' => $this->shipping_state, - 'postcode' => $this->shipping_postcode, - 'country' => $this->shipping_country - ), $this ); - - $this->formatted_shipping_address = WC()->countries->get_formatted_address( $address ); - } - } - return $this->formatted_shipping_address; - } - - /** - * Get the shipping address in an array. - * - * @access public - * @return array - */ - public function get_shipping_address() { - if ( ! $this->shipping_address ) { - if ( $this->shipping_address_1 ) { - // Formatted Addresses - $address = array( - 'address_1' => $this->shipping_address_1, - 'address_2' => $this->shipping_address_2, - 'city' => $this->shipping_city, - 'state' => $this->shipping_state, - 'postcode' => $this->shipping_postcode, - 'country' => $this->shipping_country - ); - $joined_address = array(); - foreach ( $address as $part ) { - if ( ! empty( $part ) ) { - $joined_address[] = $part; - } - } - $this->shipping_address = implode( ', ', $joined_address ); - } - } - return $this->shipping_address; - } - - /** - * Return an array of items/products within this order. - * - * @access public - * @param string|array $type Types of line items to get (array or string) - * @return array - */ - public function get_items( $type = '' ) { - global $wpdb; - - if ( empty( $type ) ) { - $type = array( 'line_item' ); - } - - if ( ! is_array( $type ) ) { - $type = array( $type ); - } - - $type = array_map( 'esc_attr', $type ); - - $line_items = $wpdb->get_results( $wpdb->prepare( " - SELECT order_item_id, order_item_name, order_item_type - FROM {$wpdb->prefix}woocommerce_order_items - WHERE order_id = %d - AND order_item_type IN ( '" . implode( "','", $type ) . "' ) - ORDER BY order_item_id - ", $this->id ) ); - - $items = array(); - - // Reserved meta keys - $reserved_item_meta_keys = array( - 'name', - 'type', - 'item_meta', - 'qty', - 'tax_class', - 'product_id', - 'variation_id', - 'line_subtotal', - 'line_total', - 'line_tax', - 'line_subtotal_tax' - ); - - // Loop items - foreach ( $line_items as $item ) { - // Place line item into array to return - $items[ $item->order_item_id ]['name'] = $item->order_item_name; - $items[ $item->order_item_id ]['type'] = $item->order_item_type; - $items[ $item->order_item_id ]['item_meta'] = $this->get_item_meta( $item->order_item_id ); - - // Expand meta data into the array - foreach ( $items[ $item->order_item_id ]['item_meta'] as $name => $value ) { - if ( in_array( $name, $reserved_item_meta_keys ) ) { - continue; - } - if ( '_' === substr( $name, 0, 1 ) ) { - $items[ $item->order_item_id ][ substr( $name, 1 ) ] = $value[0]; - } elseif ( ! in_array( $name, $reserved_item_meta_keys ) ) { - $items[ $item->order_item_id ][ $name ] = $value[0]; - } - } - } - - return apply_filters( 'woocommerce_order_get_items', $items, $this ); - } - - /** - * Gets order total - formatted for display. - * - * @access public - * @return string - */ - public function get_item_count( $type = '' ) { - if ( empty( $type ) ) { - $type = array( 'line_item' ); - } - - if ( ! is_array( $type ) ) { - $type = array( $type ); - } - - $items = $this->get_items( $type ); - - $count = 0; - - foreach ( $items as $item ) { - if ( ! empty( $item['qty'] ) ) { - $count += $item['qty']; - } else { - $count ++; - } - } - - return apply_filters( 'woocommerce_get_item_count', $count, $type, $this ); - } - - /** - * Return an array of fees within this order. - * - * @access public - * @return array - */ - public function get_fees() { - return $this->get_items( 'fee' ); - } - - /** - * Return an array of taxes within this order. - * - * @access public - * @return array - */ - public function get_taxes() { - return $this->get_items( 'tax' ); - } - - /** - * Return an array of shipping costs within this order. - * - * @return array - */ - public function get_shipping_methods() { - return $this->get_items( 'shipping' ); - } - - /** - * Check whether this order has a specific shipping method or not - * @param string $method_id - * @return bool - */ - public function has_shipping_method( $method_id ) { - $shipping_methods = $this->get_shipping_methods(); - $has_method = false; - - if ( ! $shipping_methods ) { - return false; - } - - foreach ( $shipping_methods as $shipping_method ) { - if ( $shipping_method['method_id'] == $method_id ) { - $has_method = true; - } - } - - return $has_method; - } - - /** - * Get taxes, merged by code, formatted ready for output. - * - * @access public - * @return array - */ - public function get_tax_totals() { - $taxes = $this->get_items( 'tax' ); - $tax_totals = array(); - - foreach ( $taxes as $key => $tax ) { - - $code = $tax[ 'name' ]; - - if ( ! isset( $tax_totals[ $code ] ) ) { - $tax_totals[ $code ] = new stdClass(); - $tax_totals[ $code ]->amount = 0; - } - - $tax_totals[ $code ]->is_compound = $tax[ 'compound' ]; - $tax_totals[ $code ]->label = isset( $tax[ 'label' ] ) ? $tax[ 'label' ] : $tax[ 'name' ]; - $tax_totals[ $code ]->amount += $tax[ 'tax_amount' ] + $tax[ 'shipping_tax_amount' ]; - $tax_totals[ $code ]->formatted_amount = wc_price( wc_round_tax_total( $tax_totals[ $code ]->amount ), array('currency' => $this->get_order_currency()) ); - } - - return apply_filters( 'woocommerce_order_tax_totals', $tax_totals, $this ); - } - - /** - * has_meta function for order items. - * @access public - * @param string $order_item_id - * @return array of meta data - */ - public function has_meta( $order_item_id ) { - global $wpdb; - - return $wpdb->get_results( $wpdb->prepare( "SELECT meta_key, meta_value, meta_id, order_item_id - FROM {$wpdb->prefix}woocommerce_order_itemmeta WHERE order_item_id = %d - ORDER BY meta_id", absint( $order_item_id ) ), ARRAY_A ); - } - - /** - * Get order item meta. - * - * @access public - * @param mixed $order_item_id - * @param string $key (default: '') - * @param bool $single (default: false) - * @return array|string - */ - public function get_item_meta( $order_item_id, $key = '', $single = false ) { - return get_metadata( 'order_item', $order_item_id, $key, $single ); - } - - /** Total Getters *******************************************************/ - - /** - * Gets the total (product) discount amount - these are applied before tax. - * - * @access public - * @return float - */ - public function get_cart_discount() { - return apply_filters( 'woocommerce_order_amount_cart_discount', (double) $this->cart_discount, $this ); - } - - /** - * Gets the total (product) discount amount - these are applied before tax. - * - * @access public - * @return float - */ - public function get_order_discount() { - return apply_filters( 'woocommerce_order_amount_order_discount', (double) $this->order_discount, $this ); - } - - /** - * Gets the total discount amount - both kinds - * - * @access public - * @return float - */ - public function get_total_discount() { - return apply_filters( 'woocommerce_order_amount_total_discount', $this->get_cart_discount() + $this->get_order_discount(), $this ); - } - - /** - * Gets shipping tax amount. - * - * @access public - * @return float - */ - public function get_cart_tax() { - return apply_filters( 'woocommerce_order_amount_cart_tax', (double) $this->order_tax, $this ); - } - - /** - * Gets shipping tax amount. - * - * @access public - * @return float - */ - public function get_shipping_tax() { - return apply_filters( 'woocommerce_order_amount_shipping_tax', (double) $this->order_shipping_tax, $this ); - } - - /** - * Gets shipping and product tax. - * - * @access public - * @return float - */ - public function get_total_tax() { - return apply_filters( 'woocommerce_order_amount_total_tax', wc_round_tax_total( $this->get_cart_tax() + $this->get_shipping_tax() ), $this ); - } - - /** - * Gets shipping total. - * - * @access public - * @return float - */ - public function get_total_shipping() { - return apply_filters( 'woocommerce_order_amount_total_shipping', (double) $this->order_shipping, $this ); - } - - /** - * Gets order total. - * - * @access public - * @return float - */ - public function get_total() { - return apply_filters( 'woocommerce_order_amount_total', (double) $this->order_total, $this ); - } - - /** - * Get item subtotal - this is the cost before discount. - * - * @access public - * @param mixed $item - * @param bool $inc_tax (default: false) - * @param bool $round (default: true) - * @return float - */ - public function get_item_subtotal( $item, $inc_tax = false, $round = true ) { - if ( $inc_tax ) { - $price = ( $item['line_subtotal'] + $item['line_subtotal_tax'] ) / max( 1, $item['qty'] ); - } else { - $price = ( $item['line_subtotal'] / $item['qty'] ); - } - - $price = $round ? round( $price, 2 ) : $price; - - return apply_filters( 'woocommerce_order_amount_item_subtotal', $price, $this, $item ); - } - - /** - * Get line subtotal - this is the cost before discount. - * - * @access public - * @param mixed $item - * @param bool $inc_tax (default: false) - * @param bool $round (default: true) - * @return float - */ - public function get_line_subtotal( $item, $inc_tax = false, $round = true ) { - if ( $inc_tax ) { - $price = $item['line_subtotal'] + $item['line_subtotal_tax']; - } else { - $price = $item['line_subtotal']; - } - - $price = $round ? round( $price, 2 ) : $price; - - return apply_filters( 'woocommerce_order_amount_line_subtotal', $price, $this, $item ); - } - - /** - * Calculate item cost - useful for gateways. - * - * @access public - * @param mixed $item - * @param bool $inc_tax (default: false) - * @param bool $round (default: true) - * @return float - */ - public function get_item_total( $item, $inc_tax = false, $round = true ) { - if ( $inc_tax ) { - $price = ( $item['line_total'] + $item['line_tax'] ) / max( 1, $item['qty'] ); - } else { - $price = $item['line_total'] / $item['qty']; - } - - $price = $round ? round( $price, 2 ) : $price; - - return apply_filters( 'woocommerce_order_amount_item_total', $price, $this ); - } - - /** - * Calculate line total - useful for gateways. - * - * @access public - * @param mixed $item - * @param bool $inc_tax (default: false) - * @return float - */ - public function get_line_total( $item, $inc_tax = false ) { - $line_total = $inc_tax ? round( $item['line_total'] + $item['line_tax'], 2 ) : round( $item['line_total'], 2 ); - return apply_filters( 'woocommerce_order_amount_line_total', $line_total, $this ); - } - - /** - * Calculate item tax - useful for gateways. - * - * @access public - * @param mixed $item - * @param bool $round (default: true) - * @return float - */ - public function get_item_tax( $item, $round = true ) { - $price = $item['line_tax'] / max( 1, $item['qty'] ); - $price = $round ? wc_round_tax_total( $price ) : $price; - return apply_filters( 'woocommerce_order_amount_item_tax', $price, $item, $round, $this ); - } - - /** - * Calculate line tax - useful for gateways. - * - * @access public - * @param mixed $item - * @return float - */ - public function get_line_tax( $item ) { - return apply_filters( 'woocommerce_order_amount_line_tax', wc_round_tax_total( $item['line_tax'] ), $item, $this ); - } - - /** - * Gets shipping total. - * - * @deprecated As of 2.1, use of get_total_shipping() is preferred - * @access public - * @return float - */ - public function get_shipping() { - _deprecated_function( 'get_shipping', '2.1', 'get_total_shipping' ); - return $this->get_total_shipping(); - } - - /** - * get_order_total function. Alias for get_total() - * - * @deprecated As of 2.1, use of get_total() is preferred - * @access public - * @return float - */ - public function get_order_total() { - _deprecated_function( 'get_order_total', '2.1', 'get_total' ); - return $this->get_total(); - } - - /** End Total Getters *******************************************************/ - - /** - * Gets formatted shipping method title. - * - * @return string - */ - public function get_shipping_method() { - $labels = array(); - - // Backwards compat < 2.1 - get shipping title stored in meta - if ( $this->shipping_method_title ) { - $labels[] = $this->shipping_method_title; - } else { - // 2.1+ get line items for shipping - $shipping_methods = $this->get_shipping_methods(); - - foreach ( $shipping_methods as $shipping ) { - $labels[] = $shipping['name']; - } - } - - return apply_filters( 'woocommerce_order_shipping_method', implode( ', ', $labels ), $this ); - } - - /** - * Gets line subtotal - formatted for display. - * - * @access public - * @param array $item - * @param string $tax_display - * @return string - */ - public function get_formatted_line_subtotal( $item, $tax_display = '' ) { - if ( ! $tax_display ) { - $tax_display = $this->tax_display_cart; - } - - if ( ! isset( $item['line_subtotal'] ) || ! isset( $item['line_subtotal_tax'] ) ) { - return ''; - } - - if ( 'excl' == $tax_display ) { - $ex_tax_label = $this->prices_include_tax ? 1 : 0; - - $subtotal = wc_price( $this->get_line_subtotal( $item ), array( 'ex_tax_label' => $ex_tax_label, 'currency' => $this->get_order_currency() ) ); - } else { - $subtotal = wc_price( $this->get_line_subtotal( $item, true ), array('currency' => $this->get_order_currency()) ); - } - - return apply_filters( 'woocommerce_order_formatted_line_subtotal', $subtotal, $item, $this ); - } - - /** - * Gets order currency - * - * @access public - * @return string - */ - public function get_order_currency() { - - $currency = $this->order_currency; - - return apply_filters( 'woocommerce_get_order_currency', $currency, $this ); - } - - /** - * Gets order total - formatted for display. - * - * @access public - * @return string - */ - public function get_formatted_order_total() { - - $formatted_total = wc_price( $this->order_total , array('currency' => $this->get_order_currency())); - - return apply_filters( 'woocommerce_get_formatted_order_total', $formatted_total, $this ); - } - - - /** - * Gets subtotal - subtotal is shown before discounts, but with localised taxes. - * - * @access public - * @param bool $compound (default: false) - * @param string $tax_display (default: the tax_display_cart value) - * @return string - */ - public function get_subtotal_to_display( $compound = false, $tax_display = '' ) { - if ( ! $tax_display ) { - $tax_display = $this->tax_display_cart; - } - - $subtotal = 0; - - if ( ! $compound ) { - foreach ( $this->get_items() as $item ) { - - if ( ! isset( $item['line_subtotal'] ) || ! isset( $item['line_subtotal_tax'] ) ) { - return ''; - } - - $subtotal += $item['line_subtotal']; - - if ( 'incl' == $tax_display ) { - $subtotal += $item['line_subtotal_tax']; - } - } - - $subtotal = wc_price( $subtotal, array('currency' => $this->get_order_currency()) ); - - if ( $tax_display == 'excl' && $this->prices_include_tax ) { - $subtotal .= ' ' . WC()->countries->ex_tax_or_vat() . ''; - } - - } else { - - if ( 'incl' == $tax_display ) { - return ''; - } - - foreach ( $this->get_items() as $item ) { - - $subtotal += $item['line_subtotal']; - - } - - // Add Shipping Costs - $subtotal += $this->get_total_shipping(); - - // Remove non-compound taxes - foreach ( $this->get_taxes() as $tax ) { - - if ( ! empty( $tax['compound'] ) ) { - continue; - } - - $subtotal = $subtotal + $tax['tax_amount'] + $tax['shipping_tax_amount']; - - } - - // Remove discounts - $subtotal = $subtotal - $this->get_cart_discount(); - - $subtotal = wc_price( $subtotal, array('currency' => $this->get_order_currency()) ); - } - - return apply_filters( 'woocommerce_order_subtotal_to_display', $subtotal, $compound, $this ); - } - - - /** - * Gets shipping (formatted). - * - * @access public - * @return string - */ - public function get_shipping_to_display( $tax_display = '' ) { - if ( ! $tax_display ) { - $tax_display = $this->tax_display_cart; - } - - if ( $this->order_shipping > 0 ) { - - $tax_text = ''; - - if ( $tax_display == 'excl' ) { - - // Show shipping excluding tax - $shipping = wc_price( $this->order_shipping, array('currency' => $this->get_order_currency()) ); - - if ( $this->order_shipping_tax > 0 && $this->prices_include_tax ) { - $tax_text = WC()->countries->ex_tax_or_vat() . ' '; - } - - } else { - - // Show shipping including tax - $shipping = wc_price( $this->order_shipping + $this->order_shipping_tax, array('currency' => $this->get_order_currency()) ); - - if ( $this->order_shipping_tax > 0 && ! $this->prices_include_tax ) { - $tax_text = WC()->countries->inc_tax_or_vat() . ' '; - } - - } - - $shipping .= sprintf( __( ' %svia %s', 'woocommerce' ), $tax_text, $this->get_shipping_method() ); - - } elseif ( $this->get_shipping_method() ) { - $shipping = $this->get_shipping_method(); - } else { - $shipping = __( 'Free!', 'woocommerce' ); - } - - return apply_filters( 'woocommerce_order_shipping_to_display', $shipping, $this ); - } - - - /** - * Get cart discount (formatted). - * - * @access public - * @return string. - */ - public function get_cart_discount_to_display() { - return apply_filters( 'woocommerce_order_cart_discount_to_display', wc_price( $this->get_cart_discount(), array( 'currency' => $this->get_order_currency() ) ), $this ); - } - - - /** - * Get cart discount (formatted). - * - * @access public - * @return string - */ - public function get_order_discount_to_display() { - return apply_filters( 'woocommerce_order_discount_to_display', wc_price( $this->get_order_discount(), array( 'currency' => $this->get_order_currency() ) ), $this ); - } - - - /** - * Get a product (either product or variation). - * - * @access public - * @param mixed $item - * @return WC_Product - */ - public function get_product_from_item( $item ) { - if ( ! empty( $item['variation_id'] ) && 'product_variation' === get_post_type( $item['variation_id'] ) ) { - $_product = get_product( $item['variation_id'] ); - } else { - $_product = get_product( $item['product_id'] ); - } - return apply_filters( 'woocommerce_get_product_from_item', $_product, $item, $this ); - } - - - /** - * Get totals for display on pages and in emails. - * - * @access public - * @return array - */ - public function get_order_item_totals( $tax_display = '' ) { - if ( ! $tax_display ) { - $tax_display = $this->tax_display_cart; - } - - $total_rows = array(); - - if ( $subtotal = $this->get_subtotal_to_display() ) { - $total_rows['cart_subtotal'] = array( - 'label' => __( 'Cart Subtotal:', 'woocommerce' ), - 'value' => $subtotal - ); - } - - if ( $this->get_cart_discount() > 0 ) { - $total_rows['cart_discount'] = array( - 'label' => __( 'Cart Discount:', 'woocommerce' ), - 'value' => '-' . $this->get_cart_discount_to_display() - ); - } - - if ( $this->get_shipping_method() ) { - $total_rows['shipping'] = array( - 'label' => __( 'Shipping:', 'woocommerce' ), - 'value' => $this->get_shipping_to_display() - ); - } - - if ( $fees = $this->get_fees() ) - foreach( $fees as $id => $fee ) { - if ( apply_filters( 'woocommerce_get_order_item_totals_excl_free_fees', $fee['line_total'] + $fee['line_tax'] == 0, $id ) ) { - continue; - } - - if ( 'excl' == $tax_display ) { - - $total_rows[ 'fee_' . $id ] = array( - 'label' => $fee['name'] . ':', - 'value' => wc_price( $fee['line_total'], array('currency' => $this->get_order_currency()) ) - ); - - } else { - - $total_rows[ 'fee_' . $id ] = array( - 'label' => $fee['name'] . ':', - 'value' => wc_price( $fee['line_total'] + $fee['line_tax'], array('currency' => $this->get_order_currency()) ) - ); - - } - } - - // Tax for tax exclusive prices - if ( 'excl' == $tax_display ) { - if ( get_option( 'woocommerce_tax_total_display' ) == 'itemized' ) { - foreach ( $this->get_tax_totals() as $code => $tax ) { - $total_rows[ sanitize_title( $code ) ] = array( - 'label' => $tax->label . ':', - 'value' => $tax->formatted_amount - ); - } - } else { - $total_rows['tax'] = array( - 'label' => WC()->countries->tax_or_vat() . ':', - 'value' => wc_price( $this->get_total_tax(), array('currency' => $this->get_order_currency()) ) - ); - } - } - - if ( $this->get_order_discount() > 0 ) { - $total_rows['order_discount'] = array( - 'label' => __( 'Order Discount:', 'woocommerce' ), - 'value' => '-' . $this->get_order_discount_to_display() - ); - } - - if ( $this->get_total() > 0 ) { - $total_rows['payment_method'] = array( - 'label' => __( 'Payment Method:', 'woocommerce' ), - 'value' => $this->payment_method_title - ); - } - - $total_rows['order_total'] = array( - 'label' => __( 'Order Total:', 'woocommerce' ), - 'value' => $this->get_formatted_order_total() - ); - - // Tax for inclusive prices - if ( 'yes' == get_option( 'woocommerce_calc_taxes' ) && 'incl' == $tax_display ) { - - $tax_string_array = array(); - - if ( 'itemized' == get_option( 'woocommerce_tax_total_display' ) ) { - foreach ( $this->get_tax_totals() as $code => $tax ) { - $tax_string_array[] = sprintf( '%s %s', $tax->formatted_amount, $tax->label ); - } - } else { - $tax_string_array[] = sprintf( '%s %s', wc_price( $this->get_total_tax(), array('currency' => $this->get_order_currency()) ), WC()->countries->tax_or_vat() ); - } - - if ( ! empty( $tax_string_array ) ) { - $total_rows['order_total']['value'] .= ' ' . sprintf( __( '(Includes %s)', 'woocommerce' ), implode( ', ', $tax_string_array ) ); - } - } - - return apply_filters( 'woocommerce_get_order_item_totals', $total_rows, $this ); - } - - - /** - * Output items for display in html emails. - * - * @access public - * @param bool $show_download_links (default: false) - * @param bool $show_sku (default: false) - * @param bool $show_purchase_note (default: false) - * @param bool $show_image (default: false) - * @param array $image_size (default: array( 32, 32 ) - * @param bool plain text - * @return string - */ - public function email_order_items_table( $show_download_links = false, $show_sku = false, $show_purchase_note = false, $show_image = false, $image_size = array( 32, 32 ), $plain_text = false ) { - - ob_start(); - - $template = $plain_text ? 'emails/plain/email-order-items.php' : 'emails/email-order-items.php'; - - wc_get_template( $template, array( - 'order' => $this, - 'items' => $this->get_items(), - 'show_download_links' => $show_download_links, - 'show_sku' => $show_sku, - 'show_purchase_note' => $show_purchase_note, - 'show_image' => $show_image, - 'image_size' => $image_size - ) ); - - $return = apply_filters( 'woocommerce_email_order_items_table', ob_get_clean(), $this ); - - return $return; - } - - /** - * Checks if product download is permitted - * - * @access public - * @return bool - */ - public function is_download_permitted() { - return apply_filters( 'woocommerce_order_is_download_permitted', $this->has_status( 'completed' ) || ( get_option( 'woocommerce_downloads_grant_access_after_payment' ) == 'yes' && $this->has_status( 'processing' ) ), $this ); - } - - /** - * Returns true if the order contains a downloadable product. - * - * @access public - * @return bool - */ - public function has_downloadable_item() { - $has_downloadable_item = false; - - foreach ( $this->get_items() as $item ) { - - $_product = $this->get_product_from_item( $item ); - - if ( $_product && $_product->exists() && $_product->is_downloadable() && $_product->has_file() ) { - $has_downloadable_item = true; - } - - } - - return $has_downloadable_item; - } - - - /** - * Generates a URL so that a customer can pay for their (unpaid - pending) order. Pass 'true' for the checkout version which doesn't offer gateway choices. - * - * @access public - * @param boolean $on_checkout - * @return string - */ - public function get_checkout_payment_url( $on_checkout = false ) { - - $pay_url = wc_get_endpoint_url( 'order-pay', $this->id, get_permalink( wc_get_page_id( 'checkout' ) ) ); - - if ( 'yes' == get_option( 'woocommerce_force_ssl_checkout' ) || is_ssl() ) { - $pay_url = str_replace( 'http:', 'https:', $pay_url ); - } - - if ( $on_checkout ) { - $pay_url = add_query_arg( 'key', $this->order_key, $pay_url ); - } else { - $pay_url = add_query_arg( array( 'pay_for_order' => 'true', 'key' => $this->order_key ), $pay_url ); - } - - return apply_filters( 'woocommerce_get_checkout_payment_url', $pay_url, $this ); - } - - - /** - * Generates a URL for the thanks page (order received) - * - * @access public - * @return string - */ - public function get_checkout_order_received_url() { - - $order_received_url = wc_get_endpoint_url( 'order-received', $this->id, get_permalink( wc_get_page_id( 'checkout' ) ) ); - - if ( 'yes' == get_option( 'woocommerce_force_ssl_checkout' ) || is_ssl() ) { - $order_received_url = str_replace( 'http:', 'https:', $order_received_url ); - } - - $order_received_url = add_query_arg( 'key', $this->order_key, $order_received_url ); - - return apply_filters( 'woocommerce_get_checkout_order_received_url', $order_received_url, $this ); - } - - - /** - * Generates a URL so that a customer can cancel their (unpaid - pending) order. - * - * @access public - * @return string - */ - public function get_cancel_order_url( $redirect = '' ) { - $cancel_endpoint = get_permalink( wc_get_page_id( 'cart' ) ); - if ( ! $cancel_endpoint ) { - $cancel_endpoint = home_url(); - } - - if ( false === strpos( $cancel_endpoint, '?' ) ) { - $cancel_endpoint = trailingslashit( $cancel_endpoint ); - } - - return apply_filters('woocommerce_get_cancel_order_url', wp_nonce_url( add_query_arg( array( 'cancel_order' => 'true', 'order' => $this->order_key, 'order_id' => $this->id, 'redirect' => $redirect ), $cancel_endpoint ), 'woocommerce-cancel_order' ) ); - } - - /** - * Generates a URL to view an order from the my account page - * - * @return string - */ - public function get_view_order_url() { - $view_order_url = wc_get_endpoint_url( 'view-order', $this->id, get_permalink( wc_get_page_id( 'myaccount' ) ) ); - - return apply_filters( 'woocommerce_get_view_order_url', $view_order_url, $this ); - } - - /** - * Gets any downloadable product file urls. - * - * @deprecated as of 2.1 get_item_downloads is preferred as downloads are more than just file urls - * @param int $product_id product identifier - * @param int $variation_id variation identifier, or null - * @param array $item the item - * @return array available downloadable file urls - */ - public function get_downloadable_file_urls( $product_id, $variation_id, $item ) { - global $wpdb; - - _deprecated_function( 'get_downloadable_file_urls', '2.1', 'get_item_downloads' ); - - $download_file = $variation_id > 0 ? $variation_id : $product_id; - $_product = get_product( $download_file ); - - $user_email = $this->billing_email; - - $results = $wpdb->get_results( $wpdb->prepare(" - SELECT download_id - FROM {$wpdb->prefix}woocommerce_downloadable_product_permissions - WHERE user_email = %s - AND order_key = %s - AND product_id = %s - ", $user_email, $this->order_key, $download_file ) ); - - $file_urls = array(); - foreach ( $results as $result ) { - if ( $_product->has_file( $result->download_id ) ) { - $file_urls[ $_product->get_file_download_path( $result->download_id ) ] = $this->get_download_url( $download_file, $result->download_id ); - } - } - - return apply_filters( 'woocommerce_get_downloadable_file_urls', $file_urls, $product_id, $variation_id, $item ); - } - - /** - * Get the downloadable files for an item in this order - * @param array $item - * @return array - */ - public function get_item_downloads( $item ) { - global $wpdb; - - $product_id = $item['variation_id'] > 0 ? $item['variation_id'] : $item['product_id']; - $product = get_product( $product_id ); - $download_ids = $wpdb->get_col( $wpdb->prepare(" - SELECT download_id - FROM {$wpdb->prefix}woocommerce_downloadable_product_permissions - WHERE user_email = %s - AND order_key = %s - AND product_id = %s - ORDER BY permission_id - ", $this->billing_email, $this->order_key, $product_id ) ); - - $files = array(); - - foreach ( $download_ids as $download_id ) { - if ( $product->has_file( $download_id ) ) { - $files[ $download_id ] = $product->get_file( $download_id ); - $files[ $download_id ]['download_url'] = $this->get_download_url( $product_id, $download_id ); - } - } - - return apply_filters( 'woocommerce_get_item_downloads', $files, $item, $this ); - } - - /** - * Get the Download URL - * @param int $product_id - * @param int $download_id - * @return string - */ - public function get_download_url( $product_id, $download_id ) { - return add_query_arg( array( - 'download_file' => $product_id, - 'order' => $this->order_key, - 'email' => urlencode( $this->billing_email ), - 'key' => $download_id - ), trailingslashit( home_url() ) ); - } - - /** - * Adds a note (comment) to the order - * - * @access public - * @param string $note Note to add - * @param int $is_customer_note (default: 0) Is this a note for the customer? - * @return id Comment ID - */ - public function add_order_note( $note, $is_customer_note = 0 ) { - - $is_customer_note = intval( $is_customer_note ); - - if ( is_user_logged_in() && current_user_can( 'edit_shop_order', $this->id ) ) { - $user = get_user_by( 'id', get_current_user_id() ); - $comment_author = $user->display_name; - $comment_author_email = $user->user_email; - } else { - $comment_author = __( 'WooCommerce', 'woocommerce' ); - $comment_author_email = strtolower( __( 'WooCommerce', 'woocommerce' ) ) . '@'; - $comment_author_email .= isset( $_SERVER['HTTP_HOST'] ) ? str_replace( 'www.', '', $_SERVER['HTTP_HOST'] ) : 'noreply.com'; - $comment_author_email = sanitize_email( $comment_author_email ); - } - - $comment_post_ID = $this->id; - $comment_author_url = ''; - $comment_content = $note; - $comment_agent = 'WooCommerce'; - $comment_type = 'order_note'; - $comment_parent = 0; - $comment_approved = 1; - $commentdata = apply_filters( 'woocommerce_new_order_note_data', compact( 'comment_post_ID', 'comment_author', 'comment_author_email', 'comment_author_url', 'comment_content', 'comment_agent', 'comment_type', 'comment_parent', 'comment_approved' ), array( 'order_id' => $this->id, 'is_customer_note' => $is_customer_note ) ); - - $comment_id = wp_insert_comment( $commentdata ); - - add_comment_meta( $comment_id, 'is_customer_note', $is_customer_note ); - - if ( $is_customer_note ) { - do_action( 'woocommerce_new_customer_note', array( 'order_id' => $this->id, 'customer_note' => $note ) ); - } - - return $comment_id; - } - - /** - * Updates status of order - * - * @access public - * @param string $new_status Status to change the order to. No internal wc- prefix is required. - * @param string $note (default: '') Optional note to add - */ - public function update_status( $new_status, $note = '' ) { - $old_status = $this->get_status(); - $new_status = 'wc-' === substr( $new_status, 0, 3 ) ? substr( $new_status, 3 ) : $new_status; - - // Only update if they differ - if ( $this->id && $new_status !== $old_status ) { - - // Update the order - wp_update_post( array( 'ID' => $this->id, 'post_status' => 'wc-' . $new_status ) ); - $this->post_status = 'wc-' . $new_status; - $this->add_order_note( trim( $note . ' ' . sprintf( __( 'Order status changed from %s to %s.', 'woocommerce' ), $old_status, $new_status ) ) ); - - // Status was changed - do_action( 'woocommerce_order_status_' . $new_status, $this->id ); - do_action( 'woocommerce_order_status_' . $old_status . '_to_' . $new_status, $this->id ); - do_action( 'woocommerce_order_status_changed', $this->id, $old_status, $new_status ); - - switch ( $new_status ) { - case 'completed' : - // Record the sales - $this->record_product_sales(); - - // Increase coupon usage counts - $this->increase_coupon_usage_counts(); - - // Record the completed date of the order - update_post_meta( $this->id, '_completed_date', current_time('mysql') ); - - // Update reports - wc_delete_shop_order_transients( $this->id ); - break; - case 'processing' : - case 'on-hold' : - // Record the sales - $this->record_product_sales(); - - // Increase coupon usage counts - $this->increase_coupon_usage_counts(); - - // Update reports - wc_delete_shop_order_transients( $this->id ); - break; - case 'cancelled' : - // If the order is cancelled, restore used coupons - $this->decrease_coupon_usage_counts(); - - // Update reports - wc_delete_shop_order_transients( $this->id ); - break; - } - } - } - - - /** - * Cancel the order and restore the cart (before payment) - * - * @access public - * @param string $note (default: '') Optional note to add - * @return void - */ - public function cancel_order( $note = '' ) { - unset( WC()->session->order_awaiting_payment ); - - $this->update_status( 'cancelled', $note ); - - } - - /** - * When a payment is complete this function is called - * - * Most of the time this should mark an order as 'processing' so that admin can process/post the items - * If the cart contains only downloadable items then the order is 'completed' since the admin needs to take no action - * Stock levels are reduced at this point - * Sales are also recorded for products - * Finally, record the date of payment - * - * @access public - * @param $transaction_id string Optional transaction id to store in post meta - * @return void - */ - public function payment_complete( $transaction_id = '' ) { - - do_action( 'woocommerce_pre_payment_complete', $this->id ); - - if ( ! empty( WC()->session->order_awaiting_payment ) ) { - unset( WC()->session->order_awaiting_payment ); - } - - $valid_order_statuses = apply_filters( 'woocommerce_valid_order_statuses_for_payment_complete', array( 'on-hold', 'pending', 'failed' ), $this ); - - if ( $this->id && $this->has_status( $valid_order_statuses ) ) { - - $order_needs_processing = true; - - if ( sizeof( $this->get_items() ) > 0 ) { - - foreach( $this->get_items() as $item ) { - - if ( $item['product_id'] > 0 ) { - - $_product = $this->get_product_from_item( $item ); - - if ( false !== $_product && ( $_product->is_downloadable() && $_product->is_virtual() ) || ! apply_filters( 'woocommerce_order_item_needs_processing', true, $_product, $this->id ) ) { - $order_needs_processing = false; - continue; - } - - } - $order_needs_processing = true; - break; - } - } - - $new_order_status = $order_needs_processing ? 'processing' : 'completed'; - - $new_order_status = apply_filters( 'woocommerce_payment_complete_order_status', $new_order_status, $this->id ); - - $this->update_status( $new_order_status ); - - add_post_meta( $this->id, '_paid_date', current_time('mysql'), true ); - - if ( ! empty( $transaction_id ) ) { - add_post_meta( $this->id, '_transaction_id', $transaction_id ); - } - - $this_order = array( - 'ID' => $this->id, - 'post_date' => current_time( 'mysql', 0 ), - 'post_date_gmt' => current_time( 'mysql', 1 ) - ); - wp_update_post( $this_order ); - - if ( apply_filters( 'woocommerce_payment_complete_reduce_order_stock', true, $this->id ) ) { - $this->reduce_order_stock(); // Payment is complete so reduce stock levels - } - - do_action( 'woocommerce_payment_complete', $this->id ); - - } else { - - do_action( 'woocommerce_payment_complete_order_status_' . $this->get_status(), $this->id ); - - } - } - - - /** - * Record sales - * - * @access public - * @return void - */ - public function record_product_sales() { - - if ( 'yes' == get_post_meta( $this->id, '_recorded_sales', true ) ) { - return; - } - - if ( sizeof( $this->get_items() ) > 0 ) { - foreach ( $this->get_items() as $item ) { - if ( $item['product_id'] > 0 ) { - $sales = (int) get_post_meta( $item['product_id'], 'total_sales', true ); - $sales += (int) $item['qty']; - if ( $sales ) { - update_post_meta( $item['product_id'], 'total_sales', $sales ); - } - } - } - } - - update_post_meta( $this->id, '_recorded_sales', 'yes' ); - } - - - /** - * Get coupon codes only. - * - * @access public - * @return array - */ - public function get_used_coupons() { - - $codes = array(); - $coupons = $this->get_items( 'coupon' ); - - foreach ( $coupons as $item_id => $item ) { - $codes[] = trim( $item['name'] ); - } - - return $codes; - } - - - /** - * Increase applied coupon counts - * - * @access public - * @return void - */ - public function increase_coupon_usage_counts() { - - if ( 'yes' == get_post_meta( $this->id, '_recorded_coupon_usage_counts', true ) ) { - return; - } - - if ( sizeof( $this->get_used_coupons() ) > 0 ) { - foreach ( $this->get_used_coupons() as $code ) { - if ( ! $code ) { - continue; - } - - $coupon = new WC_Coupon( $code ); - - $used_by = $this->user_id; - if ( ! $used_by ) { - $used_by = $this->billing_email; - } - - $coupon->inc_usage_count( $used_by ); - } - } - - update_post_meta( $this->id, '_recorded_coupon_usage_counts', 'yes' ); - } - - - /** - * Decrease applied coupon counts - * - * @access public - * @return void - */ - public function decrease_coupon_usage_counts() { - - if ( 'yes' != get_post_meta( $this->id, '_recorded_coupon_usage_counts', true ) ) { - return; - } - - if ( sizeof( $this->get_used_coupons() ) > 0 ) { - foreach ( $this->get_used_coupons() as $code ) { - if ( ! $code ) { - continue; - } - - $coupon = new WC_Coupon( $code ); - - $used_by = $this->user_id; - if ( ! $used_by ) { - $used_by = $this->billing_email; - } - - $coupon->dcr_usage_count( $used_by ); - } - } - - delete_post_meta( $this->id, '_recorded_coupon_usage_counts' ); - } - - - /** - * Reduce stock levels - * - * @access public - * @return void - */ - public function reduce_order_stock() { - - if ( 'yes' == get_option('woocommerce_manage_stock') && sizeof( $this->get_items() ) > 0 ) { - - // Reduce stock levels and do any other actions with products in the cart - foreach ( $this->get_items() as $item ) { - - if ( $item['product_id'] > 0 ) { - $_product = $this->get_product_from_item( $item ); - - if ( $_product && $_product->exists() && $_product->managing_stock() ) { - $qty = apply_filters( 'woocommerce_order_item_quantity', $item['qty'], $this, $item ); - $new_stock = $_product->reduce_stock( $qty ); - - $this->add_order_note( sprintf( __( 'Item #%s stock reduced from %s to %s.', 'woocommerce' ), $item['product_id'], $new_stock + $qty, $new_stock) ); - $this->send_stock_notifications( $_product, $new_stock, $item['qty'] ); - } - - } - - } - - do_action( 'woocommerce_reduce_order_stock', $this ); - - $this->add_order_note( __( 'Order item stock reduced successfully.', 'woocommerce' ) ); - } - } - - /** - * send_stock_notifications function. - * - * @access public - * @param object $product - * @param int $new_stock - * @param int $qty_ordered - * @return void - */ - public function send_stock_notifications( $product, $new_stock, $qty_ordered ) { - - // Backorders - if ( $new_stock < 0 ) { - do_action( 'woocommerce_product_on_backorder', array( 'product' => $product, 'order_id' => $this->id, 'quantity' => $qty_ordered ) ); - } - - // stock status notifications - $notification_sent = false; - - if ( 'yes' == get_option( 'woocommerce_notify_no_stock' ) && get_option('woocommerce_notify_no_stock_amount') >= $new_stock ) { - do_action( 'woocommerce_no_stock', $product ); - $notification_sent = true; - } - if ( ! $notification_sent && 'yes' == get_option( 'woocommerce_notify_low_stock' ) && get_option('woocommerce_notify_low_stock_amount') >= $new_stock ) { - do_action( 'woocommerce_low_stock', $product ); - $notification_sent = true; - } - - } - - - /** - * List order notes (public) for the customer - * - * @access public - * @return array - */ - public function get_customer_order_notes() { - - $notes = array(); - - $args = array( - 'post_id' => $this->id, - 'approve' => 'approve', - 'type' => '' - ); - - remove_filter( 'comments_clauses', array( 'WC_Comments', 'exclude_order_comments' ) ); - - $comments = get_comments( $args ); - - foreach ( $comments as $comment ) { - $is_customer_note = get_comment_meta( $comment->comment_ID, 'is_customer_note', true ); - $comment->comment_content = make_clickable( $comment->comment_content ); - if ( $is_customer_note ) { - $notes[] = $comment; - } - } - - add_filter( 'comments_clauses', array( 'WC_Comments', 'exclude_order_comments' ) ); - - return (array) $notes; - - } - - /** - * Checks if an order needs payment, based on status and order total - * - * @access public - * @return bool - */ - public function needs_payment() { - $valid_order_statuses = apply_filters( 'woocommerce_valid_order_statuses_for_payment', array( 'pending', 'failed' ), $this ); - - if ( $this->has_status( $valid_order_statuses ) && $this->get_total() > 0 ) { - $needs_payment = true; - } else { - $needs_payment = false; - } - - return apply_filters( 'woocommerce_order_needs_payment', $needs_payment, $this, $valid_order_statuses ); - } - - /** - * Checks if an order needs display the shipping address, based on shipping method - * - * @access public - * @return bool - */ - public function needs_shipping_address() { - $hide = apply_filters( 'woocommerce_order_hide_shipping_address', array( 'local_pickup' ), $this ); - $needs = false; - - foreach ( $this->get_shipping_methods() as $shipping_method ) { - if ( ! in_array( $shipping_method['method_id'], $hide ) ) { - $needs = true; - break; - } - } - - return apply_filters( 'woocommerce_order_needs_shipping_address', $needs, $this, $hide ); +class WC_Order extends WC_Abstract_Order { + public function __construct( $order ) { + $this->order_type = 'simple'; + parent::__construct( $order ); } -} +} \ No newline at end of file diff --git a/includes/emails/class-wc-email-customer-completed-order.php b/includes/emails/class-wc-email-customer-completed-order.php index e8631245b7d..ed7aed2a4c1 100644 --- a/includes/emails/class-wc-email-customer-completed-order.php +++ b/includes/emails/class-wc-email-customer-completed-order.php @@ -52,7 +52,7 @@ class WC_Email_Customer_Completed_Order extends WC_Email { function trigger( $order_id ) { if ( $order_id ) { - $this->object = new WC_Order( $order_id ); + $this->object = get_order( $order_id ); $this->recipient = $this->object->billing_email; $this->find['order-date'] = '{order_date}'; diff --git a/includes/emails/class-wc-email-customer-invoice.php b/includes/emails/class-wc-email-customer-invoice.php index fbd4dd7ef41..0cecb6fc13b 100644 --- a/includes/emails/class-wc-email-customer-invoice.php +++ b/includes/emails/class-wc-email-customer-invoice.php @@ -54,7 +54,7 @@ class WC_Email_Customer_Invoice extends WC_Email { function trigger( $order ) { if ( ! is_object( $order ) ) { - $order = new WC_Order( absint( $order ) ); + $order = get_order( absint( $order ) ); } if ( $order ) { diff --git a/includes/emails/class-wc-email-customer-note.php b/includes/emails/class-wc-email-customer-note.php index f280238e9bb..03e6bc44e63 100644 --- a/includes/emails/class-wc-email-customer-note.php +++ b/includes/emails/class-wc-email-customer-note.php @@ -63,7 +63,7 @@ class WC_Email_Customer_Note extends WC_Email { extract( $args ); - $this->object = new WC_Order( $order_id ); + $this->object = get_order( $order_id ); $this->recipient = $this->object->billing_email; $this->customer_note = $customer_note; diff --git a/includes/emails/class-wc-email-customer-processing-order.php b/includes/emails/class-wc-email-customer-processing-order.php index 32836a69dd3..a648c69c27f 100644 --- a/includes/emails/class-wc-email-customer-processing-order.php +++ b/includes/emails/class-wc-email-customer-processing-order.php @@ -49,7 +49,7 @@ class WC_Email_Customer_Processing_Order extends WC_Email { function trigger( $order_id ) { if ( $order_id ) { - $this->object = new WC_Order( $order_id ); + $this->object = get_order( $order_id ); $this->recipient = $this->object->billing_email; $this->find['order-date'] = '{order_date}'; diff --git a/includes/emails/class-wc-email-new-order.php b/includes/emails/class-wc-email-new-order.php index 160ed1fdf78..3c7a62f2c4a 100644 --- a/includes/emails/class-wc-email-new-order.php +++ b/includes/emails/class-wc-email-new-order.php @@ -59,7 +59,7 @@ class WC_Email_New_Order extends WC_Email { function trigger( $order_id ) { if ( $order_id ) { - $this->object = new WC_Order( $order_id ); + $this->object = get_order( $order_id ); $this->find['order-date'] = '{order_date}'; $this->find['order-number'] = '{order_number}'; diff --git a/includes/gateways/bacs/class-wc-gateway-bacs.php b/includes/gateways/bacs/class-wc-gateway-bacs.php index cb89ce5985c..dcbe2892a1d 100644 --- a/includes/gateways/bacs/class-wc-gateway-bacs.php +++ b/includes/gateways/bacs/class-wc-gateway-bacs.php @@ -291,7 +291,7 @@ class WC_Gateway_BACS extends WC_Payment_Gateway { */ public function process_payment( $order_id ) { - $order = new WC_Order( $order_id ); + $order = get_order( $order_id ); // Mark as on-hold (we're awaiting the payment) $order->update_status( 'on-hold', __( 'Awaiting BACS payment', 'woocommerce' ) ); diff --git a/includes/gateways/cheque/class-wc-gateway-cheque.php b/includes/gateways/cheque/class-wc-gateway-cheque.php index c2928217465..09069506e6f 100755 --- a/includes/gateways/cheque/class-wc-gateway-cheque.php +++ b/includes/gateways/cheque/class-wc-gateway-cheque.php @@ -108,7 +108,7 @@ class WC_Gateway_Cheque extends WC_Payment_Gateway { */ public function process_payment( $order_id ) { - $order = new WC_Order( $order_id ); + $order = get_order( $order_id ); // Mark as on-hold (we're awaiting the cheque) $order->update_status( 'on-hold', __( 'Awaiting cheque payment', 'woocommerce' ) ); diff --git a/includes/gateways/cod/class-wc-gateway-cod.php b/includes/gateways/cod/class-wc-gateway-cod.php index dcb8b1473df..389d9f28f3e 100644 --- a/includes/gateways/cod/class-wc-gateway-cod.php +++ b/includes/gateways/cod/class-wc-gateway-cod.php @@ -120,7 +120,7 @@ class WC_Gateway_COD extends WC_Payment_Gateway { if ( is_page( wc_get_page_id( 'checkout' ) ) && 0 < get_query_var( 'order-pay' ) ) { $order_id = absint( get_query_var( 'order-pay' ) ); - $order = new WC_Order( $order_id ); + $order = get_order( $order_id ); // Test if order needs shipping. $needs_shipping = false; @@ -198,7 +198,7 @@ class WC_Gateway_COD extends WC_Payment_Gateway { */ public function process_payment( $order_id ) { - $order = new WC_Order( $order_id ); + $order = get_order( $order_id ); // Mark as processing (payment won't be taken until delivery) $order->update_status( 'processing', __( 'Payment to be made upon delivery.', 'woocommerce' ) ); diff --git a/includes/gateways/mijireh/class-wc-gateway-mijireh.php b/includes/gateways/mijireh/class-wc-gateway-mijireh.php index 9671b604bf8..f242e8dd7cf 100644 --- a/includes/gateways/mijireh/class-wc-gateway-mijireh.php +++ b/includes/gateways/mijireh/class-wc-gateway-mijireh.php @@ -88,7 +88,7 @@ class WC_Gateway_Mijireh extends WC_Payment_Gateway { try { $mj_order = new Mijireh_Order( esc_attr( $_GET['order_number'] ) ); $wc_order_id = $mj_order->get_meta_value( 'wc_order_id' ); - $wc_order = new WC_Order( absint( $wc_order_id ) ); + $wc_order = get_order( absint( $wc_order_id ) ); // Mark order complete $wc_order->payment_complete(); @@ -188,7 +188,7 @@ class WC_Gateway_Mijireh extends WC_Payment_Gateway { $this->init_mijireh(); $mj_order = new Mijireh_Order(); - $wc_order = new WC_Order( $order_id ); + $wc_order = get_order( $order_id ); // Avoid rounding issues altogether by sending the order as one lump if ( get_option( 'woocommerce_prices_include_tax' ) == 'yes' ) { diff --git a/includes/gateways/paypal/class-wc-gateway-paypal.php b/includes/gateways/paypal/class-wc-gateway-paypal.php index c4d23897c9b..3789ef3b426 100644 --- a/includes/gateways/paypal/class-wc-gateway-paypal.php +++ b/includes/gateways/paypal/class-wc-gateway-paypal.php @@ -445,7 +445,7 @@ class WC_Gateway_Paypal extends WC_Payment_Gateway { */ function generate_paypal_form( $order_id ) { - $order = new WC_Order( $order_id ); + $order = get_order( $order_id ); if ( 'yes' == $this->testmode ) { $paypal_adr = $this->testurl . '?test_ipn=1&'; @@ -506,7 +506,7 @@ class WC_Gateway_Paypal extends WC_Payment_Gateway { */ function process_payment( $order_id ) { - $order = new WC_Order( $order_id ); + $order = get_order( $order_id ); if ( ! $this->form_submission_method ) { @@ -912,12 +912,12 @@ class WC_Gateway_Paypal extends WC_Payment_Gateway { list( $order_id, $order_key ) = $custom; } - $order = new WC_Order( $order_id ); + $order = get_order( $order_id ); if ( ! isset( $order->id ) ) { // We have an invalid $order_id, probably because invoice_prefix has changed $order_id = wc_get_order_id_by_order_key( $order_key ); - $order = new WC_Order( $order_id ); + $order = get_order( $order_id ); } // Validate key diff --git a/includes/shortcodes/class-wc-shortcode-checkout.php b/includes/shortcodes/class-wc-shortcode-checkout.php index 501264ff7a4..b09185dcc52 100644 --- a/includes/shortcodes/class-wc-shortcode-checkout.php +++ b/includes/shortcodes/class-wc-shortcode-checkout.php @@ -44,7 +44,7 @@ class WC_Shortcode_Checkout { // Get the order to work out what we are showing $order_id = absint( $_GET['order'] ); - $order = new WC_Order( $order_id ); + $order = get_order( $order_id ); if ( $order->has_status( 'pending' ) ) { $wp->query_vars['order-pay'] = absint( $_GET['order'] ); @@ -85,7 +85,7 @@ class WC_Shortcode_Checkout { // Pay for existing order $order_key = $_GET[ 'key' ]; - $order = new WC_Order( $order_id ); + $order = get_order( $order_id ); $valid_order_statuses = apply_filters( 'woocommerce_valid_order_statuses_for_payment', array( 'pending', 'failed' ), $order ); if ( ! current_user_can( 'pay_for_order', $order_id ) ) { @@ -119,7 +119,7 @@ class WC_Shortcode_Checkout { // Pay for order after checkout step $order_key = isset( $_GET['key'] ) ? wc_clean( $_GET['key'] ) : ''; - $order = new WC_Order( $order_id ); + $order = get_order( $order_id ); $valid_order_statuses = apply_filters( 'woocommerce_valid_order_statuses_for_payment', array( 'pending', 'failed' ), $order ); if ( $order->id == $order_id && $order->order_key == $order_key ) { @@ -186,7 +186,7 @@ class WC_Shortcode_Checkout { $order_key = apply_filters( 'woocommerce_thankyou_order_key', empty( $_GET['key'] ) ? '' : wc_clean( $_GET['key'] ) ); if ( $order_id > 0 ) { - $order = new WC_Order( $order_id ); + $order = get_order( $order_id ); if ( $order->order_key != $order_key ) unset( $order ); } diff --git a/includes/shortcodes/class-wc-shortcode-my-account.php b/includes/shortcodes/class-wc-shortcode-my-account.php index 39eb0b028cc..074657c5473 100644 --- a/includes/shortcodes/class-wc-shortcode-my-account.php +++ b/includes/shortcodes/class-wc-shortcode-my-account.php @@ -105,7 +105,7 @@ class WC_Shortcode_My_Account { private static function view_order( $order_id ) { $user_id = get_current_user_id(); - $order = new WC_Order( $order_id ); + $order = get_order( $order_id ); if ( ! current_user_can( 'view_order', $order_id ) ) { echo '
    ' . __( 'Invalid order.', 'woocommerce' ) . ' '. __( 'My Account', 'woocommerce' ) .'' . '
    '; @@ -118,7 +118,7 @@ class WC_Shortcode_My_Account { wc_get_template( 'myaccount/view-order.php', array( 'status' => $status, // @deprecated 2.2 - 'order' => new WC_Order( $order_id ), + 'order' => get_order( $order_id ), 'order_id' => $order_id ) ); } diff --git a/includes/shortcodes/class-wc-shortcode-order-tracking.php b/includes/shortcodes/class-wc-shortcode-order-tracking.php index 3ff436710e4..ff91de416fb 100644 --- a/includes/shortcodes/class-wc-shortcode-order-tracking.php +++ b/includes/shortcodes/class-wc-shortcode-order-tracking.php @@ -59,7 +59,7 @@ class WC_Shortcode_Order_Tracking { } else { - $order = new WC_Order( apply_filters( 'woocommerce_shortcode_order_tracking_order_id', $order_id ) ); + $order = get_order( apply_filters( 'woocommerce_shortcode_order_tracking_order_id', $order_id ) ); if ( $order->id && $order_email ) { diff --git a/includes/wc-cart-functions.php b/includes/wc-cart-functions.php index 29388b0e46a..f877d6cae92 100644 --- a/includes/wc-cart-functions.php +++ b/includes/wc-cart-functions.php @@ -119,7 +119,7 @@ function wc_clear_cart_after_payment() { $order_key = ''; if ( $order_id > 0 ) { - $order = new WC_Order( $order_id ); + $order = get_order( $order_id ); if ( $order->order_key == $order_key ) { WC()->cart->empty_cart(); @@ -130,7 +130,7 @@ function wc_clear_cart_after_payment() { if ( WC()->session->order_awaiting_payment > 0 ) { - $order = new WC_Order( WC()->session->order_awaiting_payment ); + $order = get_order( WC()->session->order_awaiting_payment ); if ( $order->id > 0 ) { // If the order has not failed, or is not pending, the order must have gone through diff --git a/includes/wc-order-functions.php b/includes/wc-order-functions.php index 10d4c621e77..9f7dc522dbb 100644 --- a/includes/wc-order-functions.php +++ b/includes/wc-order-functions.php @@ -31,6 +31,17 @@ function wc_get_order_statuses() { return apply_filters( 'wc_order_statuses', $order_statuses ); } +/** + * Main function for returning orders, uses the WC_Order_Factory class. + * + * @param mixed $the_order Post object or post ID of the order. + * @param array $args (default: array()) Contains all arguments to be used to get this order. + * @return WC_Order + */ +function get_order( $the_order = false, $args = array() ) { + return WC()->order_factory->get_order( $the_order, $args ); +} + /** * Get the nice name for an orer status * @param string $status @@ -135,7 +146,7 @@ function wc_downloadable_product_permissions( $order_id ) { return; // Only do this once } - $order = new WC_Order( $order_id ); + $order = get_order( $order_id ); if ( $order->has_status( 'processing' ) && get_option( 'woocommerce_downloads_grant_access_after_payment' ) == 'no' ) { return; @@ -312,7 +323,7 @@ function wc_cancel_unpaid_orders() { if ( $unpaid_orders ) { foreach ( $unpaid_orders as $unpaid_order ) { - $order = new WC_Order( $unpaid_order ); + $order = get_order( $unpaid_order ); if ( apply_filters( 'woocommerce_cancel_unpaid_order', true, $order ) ) $order->update_status( 'cancelled', __( 'Unpaid order cancelled - time limit reached.', 'woocommerce' ) ); diff --git a/includes/wc-user-functions.php b/includes/wc-user-functions.php index 52aebcd524d..1b08dd4b2da 100644 --- a/includes/wc-user-functions.php +++ b/includes/wc-user-functions.php @@ -198,7 +198,7 @@ function wc_update_new_customer_past_orders( $customer_id ) { */ function wc_paying_customer( $order_id ) { - $order = new WC_Order( $order_id ); + $order = get_order( $order_id ); if ( $order->user_id > 0 ) { update_user_meta( $order->user_id, 'paying_customer', 1 ); @@ -278,7 +278,7 @@ function wc_customer_has_capability( $allcaps, $caps, $args ) { switch ( $caps[0] ) { case 'view_order' : $user_id = $args[1]; - $order = new WC_Order( $args[2] ); + $order = get_order( $args[2] ); if ( $user_id == $order->user_id ) { $allcaps['view_order'] = true; @@ -295,14 +295,14 @@ function wc_customer_has_capability( $allcaps, $caps, $args ) { break; } - $order = new WC_Order( $order_id ); + $order = get_order( $order_id ); if ( $user_id == $order->user_id || empty( $order->user_id ) ) { $allcaps['pay_for_order'] = true; } break; case 'order_again' : $user_id = $args[1]; - $order = new WC_Order( $args[2] ); + $order = get_order( $args[2] ); if ( $user_id == $order->user_id ) { $allcaps['order_again'] = true; @@ -310,7 +310,7 @@ function wc_customer_has_capability( $allcaps, $caps, $args ) { break; case 'cancel_order' : $user_id = $args[1]; - $order = new WC_Order( $args[2] ); + $order = get_order( $args[2] ); if ( $user_id == $order->user_id ) { $allcaps['cancel_order'] = true; @@ -418,7 +418,7 @@ function wc_get_customer_available_downloads( $customer_id ) { foreach ( $results as $result ) { if ( ! $order || $order->id != $result->order_id ) { // new order - $order = new WC_Order( $result->order_id ); + $order = get_order( $result->order_id ); $_product = null; } diff --git a/templates/myaccount/my-orders.php b/templates/myaccount/my-orders.php index d43c1990c88..43558784469 100644 --- a/templates/myaccount/my-orders.php +++ b/templates/myaccount/my-orders.php @@ -39,7 +39,7 @@ if ( $customer_orders ) : ?> populate( $customer_order ); $item_count = $order->get_item_count(); diff --git a/templates/order/order-details.php b/templates/order/order-details.php index 52e8932a987..eab3a5a60bd 100755 --- a/templates/order/order-details.php +++ b/templates/order/order-details.php @@ -11,7 +11,7 @@ if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly global $woocommerce; -$order = new WC_Order( $order_id ); +$order = get_order( $order_id ); ?>

    diff --git a/woocommerce.php b/woocommerce.php index a5b6622d003..1982f27b22d 100644 --- a/woocommerce.php +++ b/woocommerce.php @@ -76,6 +76,11 @@ final class WooCommerce { */ public $customer = null; + /** + * @var WC_Order_Factory $order_factory + */ + public $order_factory = null; + /** * Main WooCommerce Instance * @@ -279,6 +284,7 @@ final class WooCommerce { // Include abstract classes include_once( 'includes/abstracts/abstract-wc-product.php' ); // Products + include_once( 'includes/abstracts/abstract-wc-order.php' ); // Orders include_once( 'includes/abstracts/abstract-wc-settings-api.php' ); // Settings API (for gateways, shipping, and integrations) include_once( 'includes/abstracts/abstract-wc-shipping-method.php' ); // A Shipping method include_once( 'includes/abstracts/abstract-wc-payment-gateway.php' ); // A Payment gateway @@ -362,6 +368,7 @@ final class WooCommerce { // Load class instances $this->product_factory = new WC_Product_Factory(); // Product Factory to create new product instances + $this->order_factory = new WC_Order_Factory(); // Order Factory to create new order instances $this->countries = new WC_Countries(); // Countries class $this->integrations = new WC_Integrations(); // Integrations class