Example #1
0
/**
 * Create a new order refund programmatically
 *
 * Returns a new refund object on success which can then be used to add additional data.
 *
 * @since 2.2
 * @param array $args
 * @return WC_Order_Refund|WP_Error
 */
function wc_create_refund($args = array())
{
    $default_args = array('amount' => '', 'reason' => null, 'order_id' => 0, 'refund_id' => 0, 'line_items' => array());
    $args = wp_parse_args($args, $default_args);
    $refund_data = array();
    if ($args['refund_id'] > 0) {
        $updating = true;
        $refund_data['ID'] = $args['refund_id'];
    } else {
        $updating = false;
        $refund_data['post_type'] = 'shop_order_refund';
        $refund_data['post_status'] = 'wc-completed';
        $refund_data['ping_status'] = 'closed';
        $refund_data['post_author'] = get_current_user_id() ? get_current_user_id() : 1;
        $refund_data['post_password'] = uniqid('refund_');
        $refund_data['post_parent'] = absint($args['order_id']);
        $refund_data['post_title'] = sprintf(__('Refund – %s', 'woocommerce'), strftime(_x('%b %d, %Y @ %I:%M %p', 'Order date parsed by strftime', 'woocommerce')));
    }
    if (!is_null($args['reason'])) {
        $refund_data['post_excerpt'] = $args['reason'];
    }
    if ($updating) {
        $refund_id = wp_update_post($refund_data);
    } else {
        $refund_id = wp_insert_post(apply_filters('woocommerce_new_refund_data', $refund_data), true);
    }
    if (is_wp_error($refund_id)) {
        return $refund_id;
    }
    if (!$updating) {
        // Default refund meta data
        update_post_meta($refund_id, '_refund_amount', wc_format_decimal($args['amount']));
        // Get refund object
        $refund = wc_get_order($refund_id);
        // Negative line items
        if (sizeof($args['line_items']) > 0) {
            $order = wc_get_order($args['order_id']);
            $order_items = $order->get_items(array('line_item', 'fee', 'shipping'));
            foreach ($args['line_items'] as $refund_item_id => $refund_item) {
                if (isset($order_items[$refund_item_id])) {
                    if (empty($refund_item['qty']) && empty($refund_item['refund_total']) && empty($refund_item['refund_tax'])) {
                        continue;
                    }
                    // Prevents errors when the order has no taxes
                    if (!isset($refund_item['refund_tax'])) {
                        $refund_item['refund_tax'] = array();
                    }
                    switch ($order_items[$refund_item_id]['type']) {
                        case 'line_item':
                            $line_item_args = array('totals' => array('subtotal' => wc_format_refund_total($refund_item['refund_total']), 'total' => wc_format_refund_total($refund_item['refund_total']), 'subtotal_tax' => wc_format_refund_total(array_sum($refund_item['refund_tax'])), 'tax' => wc_format_refund_total(array_sum($refund_item['refund_tax'])), 'tax_data' => array('total' => array_map('wc_format_refund_total', $refund_item['refund_tax']), 'subtotal' => array_map('wc_format_refund_total', $refund_item['refund_tax']))));
                            $new_item_id = $refund->add_product($order->get_product_from_item($order_items[$refund_item_id]), isset($refund_item['qty']) ? $refund_item['qty'] : 0, $line_item_args);
                            wc_add_order_item_meta($new_item_id, '_refunded_item_id', $refund_item_id);
                            break;
                        case 'shipping':
                            $shipping = new stdClass();
                            $shipping->label = $order_items[$refund_item_id]['name'];
                            $shipping->id = $order_items[$refund_item_id]['method_id'];
                            $shipping->cost = wc_format_refund_total($refund_item['refund_total']);
                            $shipping->taxes = array_map('wc_format_refund_total', $refund_item['refund_tax']);
                            $new_item_id = $refund->add_shipping($shipping);
                            wc_add_order_item_meta($new_item_id, '_refunded_item_id', $refund_item_id);
                            break;
                        case 'fee':
                            $fee = new stdClass();
                            $fee->name = $order_items[$refund_item_id]['name'];
                            $fee->tax_class = $order_items[$refund_item_id]['tax_class'];
                            $fee->taxable = $fee->tax_class !== '0';
                            $fee->amount = wc_format_refund_total($refund_item['refund_total']);
                            $fee->tax = wc_format_refund_total(array_sum($refund_item['refund_tax']));
                            $fee->tax_data = array_map('wc_format_refund_total', $refund_item['refund_tax']);
                            $new_item_id = $refund->add_fee($fee);
                            wc_add_order_item_meta($new_item_id, '_refunded_item_id', $refund_item_id);
                            break;
                    }
                }
            }
            $refund->update_taxes();
        }
        $refund->calculate_totals(false);
        // Set total to total refunded which may vary from order items
        $refund->set_total(wc_format_decimal($args['amount']) * -1, 'total');
        do_action('woocommerce_refund_created', $refund_id);
    }
    // Clear transients
    wc_delete_shop_order_transients($args['order_id']);
    return new WC_Order_Refund($refund_id);
}
 /**
  * Create or update an order fee.
  *
  * @param WC_Order $order Order data.
  * @param array $fee Item data.
  * @param string $action 'create' to add fee or 'update' to update it.
  * @throws WC_REST_Exception Invalid data, server error.
  */
 protected function set_fee($order, $fee, $action)
 {
     if ('create' === $action) {
         // Fee name is required.
         if (empty($fee['name'])) {
             throw new WC_REST_Exception('woocommerce_rest_invalid_fee_item', __('Fee name is required.', 'woocommerce'), 400);
         }
         $fee_data = new stdClass();
         $fee_data->id = sanitize_title($fee['name']);
         $fee_data->name = $fee['name'];
         $fee_data->amount = isset($fee['total']) ? floatval($fee['total']) : 0;
         $fee_data->taxable = false;
         $fee_data->tax = 0;
         $fee_data->tax_data = array();
         $fee_data->tax_class = '';
         // If taxable, tax class and total are required.
         if (isset($fee['tax_status']) && 'taxable' === $fee['tax_status']) {
             if (!isset($fee['tax_class'])) {
                 throw new WC_REST_Exception('woocommerce_rest_invalid_fee_item', __('Fee tax class is required when fee is taxable.', 'woocommerce'), 400);
             }
             $fee_data->taxable = true;
             $fee_data->tax_class = $fee['tax_class'];
             if (isset($fee['total_tax'])) {
                 $fee_data->tax = isset($fee['total_tax']) ? wc_format_refund_total($fee['total_tax']) : 0;
             }
         }
         $fee_id = $order->add_fee($fee_data);
         if (!$fee_id) {
             throw new WC_REST_Exception('woocommerce_rest_cannot_create_fee', __('Cannot create fee, try again.', 'woocommerce'), 500);
         }
     } else {
         $fee_args = array();
         if (isset($fee['name'])) {
             $fee_args['name'] = $fee['name'];
         }
         if (isset($fee['tax_class'])) {
             $fee_args['tax_class'] = $fee['tax_class'];
         }
         if (isset($fee['total'])) {
             $fee_args['line_total'] = floatval($fee['total']);
         }
         if (isset($fee['total_tax'])) {
             $fee_args['line_tax'] = floatval($fee['total_tax']);
         }
         $fee_id = $order->update_fee($fee['id'], $fee_args);
         if (!$fee_id) {
             throw new WC_REST_Exception('woocommerce_rest_cannot_update_fee', __('Cannot update fee, try again.', 'woocommerce'), 500);
         }
     }
 }
 /**
  * Create or update an order fee
  *
  * @since 2.2
  * @param \WC_Order $order
  * @param array $fee item data
  * @param string $action 'create' to add fee or 'update' to update it
  * @throws WC_API_Exception invalid data, server error
  */
 protected function set_fee($order, $fee, $action)
 {
     if ('create' === $action) {
         // fee title is required
         if (!isset($fee['title'])) {
             throw new WC_API_Exception('woocommerce_invalid_fee_item', __('Fee title is required', 'woocommerce'), 400);
         }
         $item = new WC_Order_Item_Fee();
         $item->set_name(sanitize_title($fee['title']));
         $item->set_total(isset($fee['total']) ? floatval($fee['total']) : 0);
         // if taxable, tax class and total are required
         if (!empty($fee['taxable'])) {
             if (!isset($fee['tax_class'])) {
                 throw new WC_API_Exception('woocommerce_invalid_fee_item', __('Fee tax class is required when fee is taxable', 'woocommerce'), 400);
             }
             $item->set_tax_status('taxable');
             $item->set_tax_class($fee['tax_class']);
             if (isset($fee['total_tax'])) {
                 $item->set_total_tax(isset($fee['total_tax']) ? wc_format_refund_total($fee['total_tax']) : 0);
             }
             if (isset($fee['tax_data'])) {
                 $item->set_total_tax(wc_format_refund_total(array_sum($fee['tax_data'])));
                 $item->set_taxes(array_map('wc_format_refund_total', $fee['tax_data']));
             }
         }
         $fee_id = $item->save();
         if (!$fee_id) {
             throw new WC_API_Exception('woocommerce_cannot_create_fee', __('Cannot create fee, try again', 'woocommerce'), 500);
         }
     } else {
         $item = new WC_Order_Item_Fee($fee['id']);
         if (isset($fee['title'])) {
             $item->set_name(sanitize_title($fee['title']));
         }
         if (isset($fee['tax_class'])) {
             $item->set_tax_class($fee['tax_class']);
         }
         if (isset($fee['total'])) {
             $item->set_total(floatval($fee['total']));
         }
         if (isset($fee['total_tax'])) {
             $item->set_total_tax(floatval($fee['total_tax']));
         }
         $fee_id = $item->save();
         if (!$fee_id) {
             throw new WC_API_Exception('woocommerce_cannot_update_fee', __('Cannot update fee, try again', 'woocommerce'), 500);
         }
     }
 }
 /**
  * Create or update an order fee.
  *
  * @since  2.5.0
  * @param  \WC_Order $order
  * @param  array $fee item data
  * @param  string $action 'create' to add fee or 'update' to update it
  * @throws WC_CLI_Exception invalid data, server error
  */
 protected function set_fee($order, $fee, $action)
 {
     if ('create' === $action) {
         // fee title is required
         if (!isset($fee['title'])) {
             throw new WC_CLI_Exception('woocommerce_invalid_fee_item', __('Fee title is required', 'woocommerce'));
         }
         $order_fee = new stdClass();
         $order_fee->id = sanitize_title($fee['title']);
         $order_fee->name = $fee['title'];
         $order_fee->amount = isset($fee['total']) ? floatval($fee['total']) : 0;
         $order_fee->taxable = false;
         $order_fee->tax = 0;
         $order_fee->tax_data = array();
         $order_fee->tax_class = '';
         // if taxable, tax class and total are required
         if (isset($fee['taxable']) && $fee['taxable']) {
             if (!isset($fee['tax_class'])) {
                 throw new WC_CLI_Exception('woocommerce_invalid_fee_item', __('Fee tax class is required when fee is taxable', 'woocommerce'));
             }
             $order_fee->taxable = true;
             $order_fee->tax_class = $fee['tax_class'];
             if (isset($fee['total_tax'])) {
                 $order_fee->tax = isset($fee['total_tax']) ? wc_format_refund_total($fee['total_tax']) : 0;
             }
             if (isset($fee['tax_data'])) {
                 $order_fee->tax = wc_format_refund_total(array_sum($fee['tax_data']));
                 $order_fee->tax_data = array_map('wc_format_refund_total', $fee['tax_data']);
             }
         }
         $fee_id = $order->add_fee($order_fee);
         if (!$fee_id) {
             throw new WC_CLI_Exception('woocommerce_cannot_create_fee', __('Cannot create fee, try again', 'woocommerce'));
         }
     } else {
         $fee_args = array();
         if (isset($fee['title'])) {
             $fee_args['name'] = $fee['title'];
         }
         if (isset($fee['tax_class'])) {
             $fee_args['tax_class'] = $fee['tax_class'];
         }
         if (isset($fee['total'])) {
             $fee_args['line_total'] = floatval($fee['total']);
         }
         if (isset($fee['total_tax'])) {
             $fee_args['line_tax'] = floatval($fee['total_tax']);
         }
         $fee_id = $order->update_fee($fee['id'], $fee_args);
         if (!$fee_id) {
             throw new WC_CLI_Exception('woocommerce_cannot_update_fee', __('Cannot update fee, try again', 'woocommerce'));
         }
     }
 }
Example #5
0
 /**
  * Test wc_format_refund_total().
  *
  * @since 2.2
  */
 public function test_wc_format_refund_total()
 {
     $this->assertEquals(-10, wc_format_refund_total(10));
     $this->assertEquals(10, wc_format_refund_total(-10));
 }
/**
 * Create a new order refund programmatically.
 *
 * Returns a new refund object on success which can then be used to add additional data.
 *
 * @since 2.2
 * @param array $args
 * @return WC_Order_Refund|WP_Error
 */
function wc_create_refund($args = array())
{
    $default_args = array('amount' => 0, 'reason' => null, 'order_id' => 0, 'refund_id' => 0, 'line_items' => array());
    try {
        $args = wp_parse_args($args, $default_args);
        $order = wc_get_order($args['order_id']);
        $refund = new WC_Order_Refund($args['refund_id']);
        if (!$order) {
            throw new Exception(__('Invalid order ID.', 'woocommerce'));
        }
        // prevent negative refunds
        if (0 > $args['amount']) {
            $args['amount'] = 0;
        }
        $refund->set_amount($args['amount']);
        $refund->set_parent_id(absint($args['order_id']));
        $refund->set_refunded_by(get_current_user_id() ? get_current_user_id() : 1);
        if (!is_null($args['reason'])) {
            $refund->set_reason($args['reason']);
        }
        // Negative line items
        if (sizeof($args['line_items']) > 0) {
            $items = $order->get_items(array('line_item', 'fee', 'shipping'));
            foreach ($items as $item_id => $item) {
                if (!isset($args['line_items'][$item_id])) {
                    continue;
                }
                $qty = isset($args['line_items'][$item_id]['qty']) ? $args['line_items'][$item_id]['qty'] : 0;
                $refund_total = $args['line_items'][$item_id]['refund_total'];
                $refund_tax = isset($args['line_items'][$item_id]['refund_tax']) ? array_filter((array) $args['line_items'][$item_id]['refund_tax']) : array();
                if (empty($qty) && empty($refund_total) && empty($args['line_items'][$item_id]['refund_tax'])) {
                    continue;
                }
                $class = get_class($item);
                $refunded_item = new $class($item);
                $refunded_item->set_id(0);
                $refunded_item->add_meta_data('_refunded_item_id', $item_id, true);
                $refunded_item->set_total(wc_format_refund_total($refund_total));
                $refunded_item->set_taxes(array('total' => array_map('wc_format_refund_total', $refund_tax), 'subtotal' => array_map('wc_format_refund_total', $refund_tax)));
                if (is_callable(array($refunded_item, 'set_subtotal'))) {
                    $refunded_item->set_subtotal(wc_format_refund_total($refund_total));
                }
                if (is_callable(array($refunded_item, 'set_quantity'))) {
                    $refunded_item->set_quantity($qty * -1);
                }
                $refund->add_item($refunded_item);
            }
        }
        $refund->update_taxes();
        $refund->calculate_totals(false);
        $refund->set_total($args['amount'] * -1);
        $refund->save();
    } catch (Exception $e) {
        return new WP_Error('error', $e->getMessage());
    }
    return $refund;
}
 /**
  * Add an item to the provided order
  *
  * @since 3.0.0
  * @param \WC_Order $order
  * @param array $item Parsed item data from CSV
  * @param string $type Line item type
  * @return int|false ID of the inserted order item, false on failure
  */
 private function add_order_item(WC_Order $order, $item, $type)
 {
     $result = false;
     switch ($type) {
         case 'line_item':
             $product = $this->get_product_for_item($item);
             $args = $this->prepare_product_args($item);
             $result = $order->add_product($product, $args['qty'], $args);
             if (!$result) {
                 wc_csv_import_suite()->log(sprintf(__('> > Warning: cannot add order item "%s".', 'woocommerce-csv-import-suite'), esc_html($identifier)));
             }
             break;
         case 'shipping':
             $args = array('order_item_name' => $item['method_title'], 'order_item_type' => 'shipping');
             // we're using wc_add_order_item instead of $order->add_shipping because
             // we do not want the order total to be recalculated
             $result = wc_add_order_item($order->id, $args);
             if (!$result) {
                 wc_csv_import_suite()->log(sprintf(__('> > Warning: cannot add shipping method "%s".', 'woocommerce-csv-import-suite'), esc_html($item['title'])));
             }
             break;
         case 'tax':
             $args = array('order_item_name' => $item['code'], 'order_item_type' => 'tax');
             $result = wc_add_order_item($order->id, $args);
             if (!$result) {
                 wc_csv_import_suite()->log(sprintf(__('> > Warning: cannot add tax "%s".', 'woocommerce-csv-import-suite'), esc_html($item['label'])));
             }
             break;
         case 'coupon':
             $result = $order->add_coupon($item['code'], $item['amount']);
             if (!$result) {
                 wc_csv_import_suite()->log(sprintf(__('> > Warning: cannot add coupon "%s".', 'woocommerce-csv-import-suite'), esc_html($item['code'])));
             }
             break;
         case 'fee':
             $order_fee = new stdClass();
             $order_fee->id = sanitize_title($item['title']);
             $order_fee->name = $item['title'];
             $order_fee->amount = isset($item['total']) ? floatval($item['total']) : 0;
             $order_fee->taxable = false;
             $order_fee->tax = 0;
             $order_fee->tax_data = array();
             $order_fee->tax_class = '';
             // if taxable, tax class and total are required
             if (isset($item['taxable']) && $item['taxable']) {
                 $order_fee->taxable = true;
                 $order_fee->tax_class = $item['tax_class'];
                 if (isset($item['total_tax'])) {
                     $order_fee->tax = isset($item['total_tax']) ? wc_format_refund_total($item['total_tax']) : 0;
                 }
                 if (isset($item['tax_data'])) {
                     $tax_data = isset($item['tax_data']['total']) ? $item['tax_data']['total'] : $item['tax_data'];
                     $order_fee->tax = wc_format_refund_total(array_sum($tax_data));
                     $order_fee->tax_data = array_map('wc_format_refund_total', $tax_data);
                 }
             }
             $result = $order->add_fee($order_fee);
             if (!$result) {
                 wc_csv_import_suite()->log(sprintf(__('> > Warning: cannot add fee "%s".', 'woocommerce-csv-import-suite'), esc_html($item['title'])));
             }
             break;
     }
     // store original order item ID
     if ($result && isset($item['order_item_id']) && $item['order_item_id'] > 0) {
         wc_update_order_item_meta($result, '_original_order_item_id', $item['order_item_id']);
     }
     return $result;
 }