/**
* 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;
}