function commerce_discount_shipping_service in Commerce Discount 7
Rules action: Apply shipping discount.
Parameters
EntityDrupalWrapper $order_wrapper: The wrapped order entity.
string $discount_name: The name of the discount.
2 string references to 'commerce_discount_shipping_service'
File
- ./
commerce_discount.rules.inc, line 1029 - Rules integration for the Commerce Discount module.
Code
function commerce_discount_shipping_service($order_wrapper, $discount_name) {
$order = $order_wrapper
->value();
// Shipping discount rules actions run on two occasions:
// 1. When selecting the shipping service on checkout. This time
// $order->shipping_rates is already set. The cart refresh is triggered
// manually in commerce_discount_commerce_shipping_method_collect_rates()
// and we don't save the shipping line items, since we create them only to
// display the price.
// 2. On any other cart refresh the $order->shipping_rates is initially
// empty so we set it to the shipping line item present on the order (if
// any). In this case we want to save the shipping line item.
// What is common in the two cases is that we calculate the discount only
// for the shipping services in $order->shipping_rates.
// If the order hasn't had any shipping rates calculated for it, check if
// there's already a shipping line item referenced by the order.
if (empty($order->shipping_rates)) {
foreach ($order_wrapper->commerce_line_items as $line_item_wrapper) {
if ($line_item_wrapper
->value() && $line_item_wrapper
->getBundle() === 'shipping') {
$shipping_service = $line_item_wrapper->commerce_shipping_service
->value();
$order->shipping_rates[$shipping_service] = $line_item_wrapper
->value();
}
}
if (empty($order->shipping_rates)) {
return;
}
}
// Load the discount to find the free shipping service and strategy.
$discount = entity_load_single('commerce_discount', $discount_name);
$discount_wrapper = entity_metadata_wrapper('commerce_discount', $discount);
$discount_offer_wrapper = $discount_wrapper->commerce_discount_offer;
$shipping_discount_offer_type = $discount_offer_wrapper
->getBundle();
switch ($shipping_discount_offer_type) {
case 'percent_off_shipping':
$shipping_service_to_discount = $discount_offer_wrapper->commerce_percent_off_ship_serv
->value();
// Determine the discount multiplier based on submitted value.
$discount_value = $discount_offer_wrapper->commerce_percent_off_shipping
->value();
if ($discount_value > 1 && $discount_value <= 100) {
$discount_multiplier = $discount_value / 100;
}
else {
return;
}
foreach ($order->shipping_rates as $shipping_service => $shipping_object) {
// Check if the order contains the shipping rate we want to apply a
// discount against. Not all shipping rates apply to all orders.
if (isset($shipping_service_to_discount) && $shipping_service_to_discount !== $shipping_service) {
continue;
}
// Instantiate the line item wrapper.
$shipping_line_item_wrapper = entity_metadata_wrapper('commerce_line_item', $order->shipping_rates[$shipping_service]);
// Calculate the correct value to discount the line item.
$discount_shipping_value = -$shipping_line_item_wrapper->commerce_unit_price->amount
->value() * $discount_multiplier;
_commerce_discount_add_shipping_discount_price_component($shipping_line_item_wrapper, $order_wrapper, $discount_name, $discount_shipping_value);
}
break;
case 'free_shipping':
try {
$free_service = $discount_wrapper->commerce_discount_offer->commerce_free_shipping
->raw();
$free_shipping_strategy = commerce_discount_get_free_shipping_strategy($discount);
} catch (Exception $e) {
watchdog('commerce_discount', 'Free shipping configuration issue detected on discount %name.', array(
'%name' => $discount_wrapper
->label(),
));
return;
}
// If a shipping service is specified, ensure it exists.
if (!empty($free_service)) {
if (!empty($order->shipping_rates[$free_service])) {
// Exit if the shipping service is already free.
$free_service_wrapper = entity_metadata_wrapper('commerce_line_item', $order->shipping_rates[$free_service]);
if ($free_service_wrapper->commerce_unit_price->amount
->value() <= 0) {
return;
}
// Update the free shipping service line item's rate to be free using the
// service's price.
$discount_amount = $free_service_wrapper->commerce_unit_price->amount
->value();
$order->shipping_rates[$free_service]->data['shipping_service']['description'] .= ' <span class="shipping-discount-text">' . check_plain($discount->component_title) . '</span>';
_commerce_discount_add_shipping_discount_price_component($free_service_wrapper, $order_wrapper, $discount_name, -$discount_amount);
}
// The free shipping discount strategy requires us to discount all other
// shipping services an equivalent amount.
if ($free_shipping_strategy == 'discount_all') {
foreach ($order->shipping_rates as $service_name => $line_item) {
// Skip the free shipping service.
if ($service_name == $free_service) {
continue;
}
$free_shipping_service = commerce_shipping_service_load($free_service);
$callback = commerce_shipping_service_callback($free_shipping_service, 'rate');
$price = $callback($free_shipping_service, $order);
$discount_amount = $price['amount'];
// Apply the discount, ensuring the rate does not discount below 0,
// but do not use the message again to reduce spam on the form.
$line_item_wrapper = entity_metadata_wrapper('commerce_line_item', $line_item);
$service_discount_amount = min($discount_amount, $line_item_wrapper->commerce_unit_price->amount
->value());
_commerce_discount_add_shipping_discount_price_component($line_item_wrapper, $order_wrapper, $discount_name, -$service_discount_amount);
}
}
}
break;
case 'shipping_upgrade':
try {
$target_service_id = $discount_offer_wrapper->commerce_shipping_upgrade_target
->raw();
$source_service_id = $discount_offer_wrapper->commerce_shipping_upgrade_source
->raw();
} catch (Exception $e) {
watchdog('commerce_discount', 'Shipping service upgrade configuration issue detected on discount %name.', array(
'%name' => $discount_wrapper
->label(),
));
return;
}
// Exit now if we either could not determine a target or source service or
// they were not calculated for this order.
if (empty($target_service_id) || empty($source_service_id) || empty($order->shipping_rates[$target_service_id])) {
return;
}
$target_line_item_wrapper = entity_metadata_wrapper('commerce_line_item', $order->shipping_rates[$target_service_id]);
// To calculate the source shipping rate with discounts, we need to
// remove the target service from the order and apply the source instead.
$cloned_order = clone $order;
$cloned_order_wrapper = entity_metadata_wrapper('commerce_order', $cloned_order);
if (empty($cloned_order->shipping_rates[$source_service_id])) {
foreach ($cloned_order_wrapper->commerce_line_items as $delta => $line_item_wrapper) {
// If this line item is a shipping line item...
if ($line_item_wrapper
->value() && $line_item_wrapper
->getBundle() === 'shipping') {
$original_shipping_line_item = $line_item_wrapper
->value();
$cloned_order_wrapper->commerce_line_items
->offsetUnset($delta);
unset($cloned_order->shipping_rates[$target_service_id]);
}
}
module_load_include('inc', 'commerce_shipping', 'commerce_shipping.rules');
commerce_shipping_rate_apply($cloned_order, $source_service_id);
// Get the new line item.
$line_items = field_get_items('commerce_order', $cloned_order, 'commerce_line_items');
$line_item_id = array_pop($line_items);
$source_shipping_line_item = commerce_line_item_load($line_item_id['line_item_id']);
$cloned_order->shipping_rates[$source_service_id] = $source_shipping_line_item;
// Apply discounts on source line item. This won't create an endless
// loop since we have unset the source service on the order above.
commerce_discount_commerce_cart_order_refresh($cloned_order_wrapper);
}
// Get the discounted rate for the source service.
$source_line_item_wrapper = entity_metadata_wrapper('commerce_line_item', $cloned_order->shipping_rates[$source_service_id]);
// If the prices are already the same, exit now.
if ($target_line_item_wrapper->commerce_unit_price->amount
->value() <= $source_line_item_wrapper->commerce_unit_price->amount
->value()) {
return;
}
// Otherwise, calculate the difference between the source and the target.
$difference = $source_line_item_wrapper->commerce_unit_price->amount
->value() - $target_line_item_wrapper->commerce_unit_price->amount
->value();
_commerce_discount_add_shipping_discount_price_component($target_line_item_wrapper, $order_wrapper, $discount_name, $difference);
break;
}
}