/**
  * Update fee for order
  *
  * Note this does not update order totals
  *
  * @since 2.2
  * @param int $item_id
  * @param array $args
  * @return bool
  */
 public function update_fee($item_id, $args)
 {
     if (!$item_id) {
         return false;
     }
     // name
     if (isset($args['name'])) {
         wc_update_order_item($item_id, array('order_item_name' => $args['name']));
     }
     // tax class
     if (isset($args['tax_class'])) {
         wc_update_order_item_meta($item_id, '_tax_class', $args['tax_class']);
     }
     // total
     if (isset($args['line_total'])) {
         wc_update_order_item_meta($item_id, '_line_total', wc_format_decimal($args['line_total']));
     }
     // total tax
     if (isset($args['line_tax'])) {
         wc_update_order_item_meta($item_id, '_line_tax', wc_format_decimal($args['line_tax']));
     }
     do_action('woocommerce_order_update_fee', $this->id, $item_id, $args);
     return true;
 }
 /**
  * Opportunity to change title and add line_item meta
  * @param $order_id
  * @param $item_id
  * @param $product
  * @param $qty
  * @param $args
  */
 public function order_add_product($order_id, $item_id, $product, $qty, $args)
 {
     $id = isset($product->id) ? $product->id : false;
     $id = isset($product->variation_id) ? $product->variation_id : $id;
     if ($id) {
         $data = $this->get_line_item($id);
         // update title
         if (isset($data['title'])) {
             wc_update_order_item($item_id, array('order_item_name' => sanitize_text_field($data['title'])));
         }
         // update meta
         if (isset($data['meta']) && !empty($data['meta'])) {
             $this->add_product_meta($item_id, $data['meta']);
         }
     }
 }
 /**
  * Create a scheduled order
  * @param  string $payment_date
  * @param  int $original_order_id
  */
 public static function create_order($payment_date, $original_order_id, $payment_number, $item, $status = '')
 {
     $original_order = wc_get_order($original_order_id);
     $new_order = wc_create_order(array('status' => $status, 'customer_id' => $original_order->get_user_id(), 'customer_note' => $original_order->customer_note, 'created_via' => 'wc_deposits'));
     if (is_wp_error($new_order)) {
         $original_order->add_order_note(sprintf(__('Error: Unable to create follow up payment (%s)', 'woocommerce-deposits'), $scheduled_order->get_error_message()));
     } else {
         $new_order->set_address(array('first_name' => $original_order->billing_first_name, 'last_name' => $original_order->billing_last_name, 'company' => $original_order->billing_company, 'address_1' => $original_order->billing_address_1, 'address_2' => $original_order->billing_address_2, 'city' => $original_order->billing_city, 'state' => $original_order->billing_state, 'postcode' => $original_order->billing_postcode, 'country' => $original_order->billing_country, 'email' => $original_order->billing_email, 'phone' => $original_order->billing_phone), 'billing');
         $new_order->set_address(array('first_name' => $original_order->shipping_first_name, 'last_name' => $original_order->shipping_last_name, 'company' => $original_order->shipping_company, 'address_1' => $original_order->shipping_address_1, 'address_2' => $original_order->shipping_address_2, 'city' => $original_order->shipping_city, 'state' => $original_order->shipping_state, 'postcode' => $original_order->shipping_postcode, 'country' => $original_order->shipping_country), 'shipping');
         // Handle items
         $item_id = $new_order->add_product($item['product'], $item['qty'], array('totals' => array('subtotal' => $item['amount'], 'total' => $item['amount'], 'subtotal_tax' => 0, 'tax' => 0)));
         woocommerce_add_order_item_meta($item_id, '_original_order_id', $original_order_id);
         wc_update_order_item($item_id, array('order_item_name' => sprintf(__('Payment #%d for %s'), $payment_number, $item['product']->get_title())));
         $new_order->calculate_totals(wc_tax_enabled());
         // Set future date and parent
         $new_order_post = array('ID' => $new_order->id, 'post_date' => date('Y-m-d H:i:s', $payment_date), 'post_parent' => $original_order_id);
         wp_update_post($new_order_post);
         do_action('woocommerce_deposits_create_order', $new_order->id);
         return $new_order->id;
     }
 }
 /**
  * Update shipping method on the subscription if the order changed anything
  *
  * @param  WC_Order $order The new order
  * @param  WC_Subscription $subscription The original subscription
  * @param  WC_Cart $recurring_cart A recurring cart
  */
 public static function update_shipping_methods($subscription, $recurring_cart)
 {
     // First, archive all the shipping methods
     foreach ($subscription->get_shipping_methods() as $shipping_method_id => $shipping_method) {
         wc_update_order_item($shipping_method_id, array('order_item_type' => 'shipping_switched'));
     }
     // Then zero the order_shipping total so we have a clean slate to add to
     $subscription->order_shipping = 0;
     WC_Subscriptions_Checkout::add_shipping($subscription, $recurring_cart);
     // Now update subscription object order_shipping to reflect updated values so it doesn't stay 0
     $subscription->order_shipping = get_post_meta($subscription->id, '_order_shipping', true);
 }
 protected function _import_line_items(&$order, $order_id, $index)
 {
     $is_product_founded = false;
     switch ($this->import->options['pmwi_order']['products_source']) {
         // Get data from existing products
         case 'existing':
             foreach ($this->data['pmwi_order']['products'][$index] as $productIndex => $productItem) {
                 if (empty($productItem['sku'])) {
                     continue;
                 }
                 $args = array('post_type' => 'product', 'meta_key' => '_sku', 'meta_value' => $productItem['sku'], 'meta_compare' => '=');
                 $product = false;
                 $query = new WP_Query($args);
                 while ($query->have_posts()) {
                     $query->the_post();
                     $product = WC()->product_factory->get_product($query->post->ID);
                     break;
                 }
                 wp_reset_postdata();
                 if (empty($product)) {
                     $args['post_type'] = 'product_variation';
                     $query = new WP_Query($args);
                     while ($query->have_posts()) {
                         $query->the_post();
                         $product = WC()->product_factory->get_product($query->post->ID);
                         break;
                     }
                     wp_reset_postdata();
                 }
                 if ($product) {
                     $is_product_founded = true;
                     $item_price = $product->get_price();
                     $item_qty = empty($productItem['qty']) ? 1 : $productItem['qty'];
                     $item_subtotal = $item_price * $item_qty;
                     $item_subtotal_tax = 0;
                     $line_taxes = array();
                     foreach ($productItem['tax_rates'] as $key => $tax_rate) {
                         if (empty($tax_rate['code'])) {
                             continue;
                         }
                         $tax_rate_codes = explode("|", $tax_rate['code']);
                         $percentage_value = explode("|", $tax_rate['percentage_value']);
                         $amount_per_unit = explode("|", $tax_rate['amount_per_unit']);
                         foreach ($tax_rate_codes as $rate_key => $tax_rate_code) {
                             if ($tax_rate_code == 'standard') {
                                 $tax_rate_code = '';
                             }
                             $line_tax = 0;
                             switch ($tax_rate['calculate_logic']) {
                                 case 'percentage':
                                     if (!empty($percentage_value[$rate_key]) and is_numeric($percentage_value[$rate_key])) {
                                         $line_tax = WC_Tax::round($item_subtotal / 100 * $percentage_value[$rate_key]);
                                         $item_subtotal_tax += $line_tax;
                                     }
                                     if (!empty($this->tax_rates)) {
                                         foreach ($this->tax_rates as $rate_id => $rate) {
                                             if ($rate->tax_rate_name == $tax_rate_code) {
                                                 $line_taxes[$rate->tax_rate_id] = $line_tax;
                                                 break;
                                             }
                                         }
                                     }
                                     break;
                                 case 'per_unit':
                                     if (!empty($amount_per_unit[$rate_key]) and is_numeric($amount_per_unit[$rate_key])) {
                                         $line_tax = WC_Tax::round($amount_per_unit[$rate_key] * $item_qty);
                                         $item_subtotal_tax += $line_tax;
                                     }
                                     if (!empty($this->tax_rates)) {
                                         foreach ($this->tax_rates as $rate_id => $rate) {
                                             if ($rate->tax_rate_name == $tax_rate_code) {
                                                 $line_taxes[$rate->tax_rate_id] = $line_tax;
                                                 break;
                                             }
                                         }
                                     }
                                     break;
                                     // Look up tax rate code
                                 // Look up tax rate code
                                 default:
                                     $found_rates = WC_Tax::get_rates_for_tax_class($tax_rate_code);
                                     if (!empty($found_rates)) {
                                         $found_priority = array();
                                         foreach ($found_rates as $found_rate) {
                                             $matched_tax_rates = array();
                                             if (in_array($found_rate->tax_rate_priority, $found_priority)) {
                                                 continue;
                                             }
                                             $matched_tax_rates[$found_rate->tax_rate_id] = array('rate' => $found_rate->tax_rate, 'label' => $found_rate->tax_rate_name, 'shipping' => $found_rate->tax_rate_shipping ? 'yes' : 'no', 'compound' => $found_rate->tax_rate_compound ? 'yes' : 'no');
                                             $line_tax = array_sum(WC_Tax::calc_tax($item_subtotal, $matched_tax_rates, $this->prices_include_tax));
                                             $item_subtotal_tax += $line_tax;
                                             $line_taxes[$found_rate->tax_rate_id] = $line_tax;
                                             $found_priority[] = $found_rate->tax_rate_priority;
                                         }
                                     }
                                     break;
                             }
                         }
                     }
                     $variation = array();
                     $variation_str = '';
                     if ($product instanceof WC_Product_Variation) {
                         $variation = $product->get_variation_attributes();
                         if (!empty($variation)) {
                             foreach ($variation as $key => $value) {
                                 $variation_str .= $key . '-' . $value;
                             }
                         }
                     }
                     $product_item = new PMXI_Post_Record();
                     $product_item->getBy(array('import_id' => $this->import->id, 'post_id' => $order_id, 'unique_key' => 'line-item-' . $product->id . '-' . $variation_str));
                     if ($product_item->isEmpty()) {
                         $item_id = false;
                         // in case when this is new order just add new line items
                         if (!$item_id) {
                             $item_id = $order->add_product($product, $item_qty, array('variation' => $variation, 'totals' => array('subtotal' => $item_subtotal, 'subtotal_tax' => $item_subtotal_tax, 'total' => $item_subtotal, 'tax' => $item_subtotal_tax, 'tax_data' => array('total' => $line_taxes, 'subtotal' => array()))));
                         }
                         if (!$item_id) {
                             $this->logger and call_user_func($this->logger, __('- <b>WARNING</b> Unable to create order line product.', 'wp_all_import_plugin'));
                         } else {
                             $product_item->set(array('import_id' => $this->import->id, 'post_id' => $order_id, 'unique_key' => 'line-item-' . $product->id . '-' . $variation_str, 'product_key' => 'line-item-' . $item_id, 'iteration' => $this->import->iteration))->save();
                         }
                     } else {
                         $item_id = str_replace('line-item-', '', $product_item->product_key);
                         $is_updated = $order->update_product($item_id, $product, array('qty' => $item_qty, 'tax_class' => $product->get_tax_class(), 'totals' => array('subtotal' => $item_subtotal, 'subtotal_tax' => $item_subtotal_tax, 'total' => $item_subtotal, 'tax' => $item_subtotal_tax, 'tax_data' => array('total' => $line_taxes, 'subtotal' => array())), 'variation' => $variation));
                         if ($is_updated) {
                             $product_item->set(array('iteration' => $this->import->iteration))->save();
                         }
                     }
                 }
             }
             break;
             // Manually import product order data and do not try to match to existing products
         // Manually import product order data and do not try to match to existing products
         default:
             $is_product_founded = true;
             foreach ($this->data['pmwi_order']['manual_products'][$index] as $productIndex => $productItem) {
                 $item_price = $productItem['price_per_unit'];
                 $item_qty = empty($productItem['qty']) ? 1 : $productItem['qty'];
                 $item_subtotal = $item_price * $item_qty;
                 $item_subtotal_tax = 0;
                 $line_taxes = array();
                 foreach ($productItem['tax_rates'] as $key => $tax_rate) {
                     if (empty($tax_rate['code'])) {
                         continue;
                     }
                     $line_tax = 0;
                     switch ($tax_rate['calculate_logic']) {
                         case 'percentage':
                             if (!empty($tax_rate['percentage_value']) and is_numeric($tax_rate['percentage_value'])) {
                                 $line_tax = WC_Tax::round($item_subtotal / 100 * $tax_rate['percentage_value']);
                                 $item_subtotal_tax += $line_tax;
                             }
                             break;
                         case 'per_unit':
                             if (!empty($tax_rate['amount_per_unit']) and is_numeric($tax_rate['amount_per_unit'])) {
                                 $line_tax = WC_Tax::round($tax_rate['amount_per_unit'] * $item_qty);
                                 $item_subtotal_tax += $line_tax;
                             }
                             break;
                             // Look up tax rate code
                         // Look up tax rate code
                         default:
                             $found_rates = WC_Tax::get_rates_for_tax_class($tax_rate['code']);
                             if (!empty($found_rates)) {
                                 $matched_tax_rates = array();
                                 $found_priority = array();
                                 foreach ($found_rates as $found_rate) {
                                     if (in_array($found_rate->tax_rate_priority, $found_priority)) {
                                         continue;
                                     }
                                     $matched_tax_rates[$found_rate->tax_rate_id] = array('rate' => $found_rate->tax_rate, 'label' => $found_rate->tax_rate_name, 'shipping' => $found_rate->tax_rate_shipping ? 'yes' : 'no', 'compound' => $found_rate->tax_rate_compound ? 'yes' : 'no');
                                     $found_priority[] = $found_rate->tax_rate_priority;
                                 }
                                 $line_tax = array_sum(WC_Tax::calc_tax($item_subtotal, $matched_tax_rates, true));
                                 $item_subtotal_tax += $line_tax;
                             }
                             break;
                     }
                     if (!empty($this->tax_rates)) {
                         foreach ($this->tax_rates as $rate_id => $rate) {
                             $line_taxes[$rate->tax_rate_id] = $line_tax;
                             break;
                         }
                     }
                 }
                 $variation = array();
                 $product_item = new PMXI_Post_Record();
                 $product_item->getBy(array('import_id' => $this->import->id, 'post_id' => $order_id, 'unique_key' => 'manual-line-item-' . $productIndex . '-' . $productItem['sku']));
                 if ($product_item->isEmpty()) {
                     $item_id = wc_add_order_item($order_id, array('order_item_name' => $productItem['sku'], 'order_item_type' => 'line_item'));
                     if (!$item_id) {
                         $this->logger and call_user_func($this->logger, __('- <b>WARNING</b> Unable to create order line product.', 'wp_all_import_plugin'));
                     } else {
                         wc_add_order_item_meta($item_id, '_qty', wc_stock_amount($item_qty));
                         wc_add_order_item_meta($item_id, '_tax_class', '');
                         wc_add_order_item_meta($item_id, '_line_subtotal', wc_format_decimal($item_subtotal));
                         wc_add_order_item_meta($item_id, '_line_total', wc_format_decimal($item_subtotal));
                         wc_add_order_item_meta($item_id, '_line_subtotal_tax', wc_format_decimal($item_subtotal_tax));
                         wc_add_order_item_meta($item_id, '_line_tax', wc_format_decimal($item_subtotal_tax));
                         wc_add_order_item_meta($item_id, '_line_tax_data', array('total' => $line_taxes, 'subtotal' => array()));
                         if (!empty($productItem['meta_name'])) {
                             foreach ($productItem['meta_name'] as $key => $meta_name) {
                                 wc_add_order_item_meta($item_id, $meta_name, isset($productItem['meta_value'][$key]) ? $productItem['meta_value'][$key] : '');
                             }
                         }
                         $product_item->set(array('import_id' => $this->import->id, 'post_id' => $order_id, 'unique_key' => 'manual-line-item-' . $productIndex . '-' . $productItem['sku'], 'product_key' => 'manual-line-item-' . $item_id, 'iteration' => $this->import->iteration))->save();
                     }
                 } else {
                     $item_id = str_replace('manual-line-item-', '', $product_item->product_key);
                     if (is_numeric($item_id)) {
                         wc_update_order_item($item_id, array('order_item_name' => $productItem['sku'], 'order_item_type' => 'line_item'));
                         wc_update_order_item_meta($item_id, '_qty', wc_stock_amount($item_qty));
                         wc_update_order_item_meta($item_id, '_tax_class', '');
                         wc_update_order_item_meta($item_id, '_line_subtotal', wc_format_decimal($item_subtotal));
                         wc_update_order_item_meta($item_id, '_line_total', wc_format_decimal($item_subtotal));
                         wc_update_order_item_meta($item_id, '_line_subtotal_tax', wc_format_decimal($item_subtotal_tax));
                         wc_update_order_item_meta($item_id, '_line_tax', wc_format_decimal($item_subtotal_tax));
                         wc_update_order_item_meta($item_id, '_line_tax_data', array('total' => $line_taxes, 'subtotal' => array()));
                         if (!empty($productItem['meta_name'])) {
                             foreach ($productItem['meta_name'] as $key => $meta_name) {
                                 wc_update_order_item_meta($item_id, $meta_name, isset($productItem['meta_value'][$key]) ? $productItem['meta_value'][$key] : '');
                             }
                         }
                         $product_item->set(array('iteration' => $this->import->iteration))->save();
                     }
                 }
             }
             break;
     }
     return $is_product_founded;
 }
 /**
  * Update shipping method on the subscription if the order changed anything
  *
  * @param  WC_Order $order The new order
  * @param  WC_Subscription $subscription The original subscription
  * @param  WC_Cart $recurring_cart A recurring cart
  */
 public static function update_shipping_methods($subscription, $recurring_cart)
 {
     // First, archive all the shipping methods
     foreach ($subscription->get_shipping_methods() as $shipping_method_id => $shipping_method) {
         wc_update_order_item($shipping_method_id, array('order_item_type' => 'shipping_switched'));
     }
     WC_Subscriptions_Checkout::add_shipping($subscription, $recurring_cart);
 }
 /**
  * Update an order item
  *
  * @since 3.0.0
  * @param \WC_Order $order WC_Order instance
  * @param int $order_item_id Order item ID to update
  * @param array $item Parsed item data from CSV
  * @param string $type Line item type
  * @return int|false ID of the updated order item, false on failure
  */
 private function update_order_item(WC_Order $order, $order_item_id, $item, $type)
 {
     $result = false;
     switch ($type) {
         case 'line_item':
             $product = $this->get_product_for_item($item);
             $args = $this->prepare_product_args($item);
             $result = $order->update_product($order_item_id, $product, $args);
             if (!$result) {
                 wc_csv_import_suite()->log(sprintf(__('> > Warning: cannot update order item %d.', 'woocommerce-csv-import-suite'), $order_item_id));
             }
             break;
         case 'shipping':
             $args = array('order_item_name' => $item['method_title']);
             $result = wc_update_order_item($order_item_id, $args);
             if (!$result) {
                 wc_csv_import_suite()->log(sprintf(__('> > Warning: cannot update shipping method "%s".', 'woocommerce-csv-import-suite'), esc_html($item['title'])));
             }
             break;
         case 'tax':
             $args = array('order_item_name' => $item['code']);
             $result = wc_update_order_item($order_item_id, $args);
             if (!$result) {
                 wc_csv_import_suite()->log(sprintf(__('> > Warning: cannot update tax "%s".', 'woocommerce-csv-import-suite'), esc_html($item['label'])));
             }
             break;
         case 'coupon':
             $args = array('code' => $item['code'], 'discount_amount' => $item['amount']);
             $result = $order->update_coupon($order_item_id, $args);
             if (!$result) {
                 wc_csv_import_suite()->log(sprintf(__('> > Warning: cannot merge coupon "%s".', 'woocommerce-csv-import-suite'), esc_html($item['code'])));
             }
             break;
         case 'fee':
             $args = array('name' => $item['title'], 'line_total' => $item['total'], 'line_tax' => $item['total_tax'], 'tax_class' => isset($item['tax_class']) ? $item['tax_class'] : '');
             $result = $order->update_fee($order_item_id, $args);
             if (!$result) {
                 wc_csv_import_suite()->log(sprintf(__('> > Warning: cannot merge fee "%s".', 'woocommerce-csv-import-suite'), esc_html($item['title'])));
             }
             break;
     }
     return $result;
 }
 /**
  * Process the remove or re-add a line item from a subscription request.
  *
  * @since 2.0
  */
 public static function maybe_remove_or_add_item_to_subscription()
 {
     if (isset($_GET['subscription_id']) && (isset($_GET['remove_item']) || isset($_GET['undo_remove_item'])) && isset($_GET['_wpnonce'])) {
         $subscription = wcs_is_subscription($_GET['subscription_id']) ? wcs_get_subscription($_GET['subscription_id']) : false;
         $undo_request = isset($_GET['undo_remove_item']) ? true : false;
         $item_id = $undo_request ? $_GET['undo_remove_item'] : $_GET['remove_item'];
         if (false === $subscription) {
             wc_add_notice(sprintf(_x('Subscription #%d does not exist.', 'hash before subscription ID', 'woocommerce-subscriptions'), $_GET['subscription_id']), 'error');
             wp_safe_redirect(wc_get_page_permalink('myaccount'));
             exit;
         }
         if (self::validate_remove_items_request($subscription, $item_id, $undo_request)) {
             if ($undo_request) {
                 // handle undo request
                 $removed_item = WC()->session->get('removed_subscription_items', array());
                 if (!empty($removed_item[$item_id]) && $subscription->id == $removed_item[$item_id]) {
                     // restore the item
                     wc_update_order_item($item_id, array('order_item_type' => 'line_item'));
                     unset($removed_item[$item_id]);
                     WC()->session->set('removed_subscription_items', $removed_item);
                     // restore download permissions for this item
                     $line_items = $subscription->get_items();
                     $line_item = $line_items[$item_id];
                     $_product = $subscription->get_product_from_item($line_item);
                     $product_id = wcs_get_canonical_product_id($line_item);
                     if ($_product && $_product->exists() && $_product->is_downloadable()) {
                         $downloads = $_product->get_files();
                         foreach (array_keys($downloads) as $download_id) {
                             wc_downloadable_file_permission($download_id, $product_id, $subscription, $line_item['qty']);
                         }
                     }
                     // translators: 1$: product name, 2$: product id
                     $subscription->add_order_note(sprintf(_x('Customer added "%1$s" (Product ID: #%2$d) via the My Account page.', 'used in order note', 'woocommerce-subscriptions'), wcs_get_line_item_name($line_item), $product_id));
                 } else {
                     wc_add_notice(__('Your request to undo your previous action was unsuccessful.', 'woocommerce-subscriptions'));
                 }
             } else {
                 // handle remove item requests
                 WC()->session->set('removed_subscription_items', array($item_id => $subscription->id));
                 // remove download access for the item
                 $line_items = $subscription->get_items();
                 $line_item = $line_items[$item_id];
                 $product_id = wcs_get_canonical_product_id($line_item);
                 WCS_Download_Handler::revoke_downloadable_file_permission($product_id, $subscription->id, $subscription->get_user_id());
                 // remove the line item from subscription but preserve its data in the DB
                 wc_update_order_item($item_id, array('order_item_type' => 'line_item_removed'));
                 // translators: 1$: product name, 2$: product id
                 $subscription->add_order_note(sprintf(_x('Customer removed "%1$s" (Product ID: #%2$d) via the My Account page.', 'used in order note', 'woocommerce-subscriptions'), wcs_get_line_item_name($line_item), $product_id));
                 // translators: placeholders are 1$: item name, and, 2$: opening and, 3$: closing link tags
                 wc_add_notice(sprintf(__('You have successfully removed "%1$s" from your subscription. %2$sUndo?%3$s', 'woocommerce-subscriptions'), $line_item['name'], '<a href="' . esc_url(self::get_undo_remove_url($subscription->id, $item_id, $subscription->get_view_order_url())) . '" >', '</a>'));
             }
         }
         $subscription->calculate_totals();
         wp_safe_redirect($subscription->get_view_order_url());
         exit;
     }
 }