fix(orders): Use WooCommerce cart for shipping calculation in order creation

## Issues Fixed:
1.  Shipping cost was zero in created orders
2.  Live rates (UPS, Rajaongkir) not calculated
3.  Shipping title shows service level (e.g., "JNE - REG")

## Root Cause:
Order creation was manually looking up static shipping cost:
```php
$shipping_cost = $method->get_option( 'cost', 0 );
```

This doesn't work for:
- Live rate methods (UPS, FedEx, Rajaongkir)
- Service-level rates (JNE REG vs YES vs OKE)
- Dynamic pricing based on weight/destination

## Solution:
Use WooCommerce cart to calculate actual shipping cost:

```php
// Initialize cart
WC()->cart->empty_cart();
WC()->cart->add_to_cart( $product_id, $qty );

// Set shipping address
WC()->customer->set_shipping_address( $address );

// Set chosen method
WC()->session->set( 'chosen_shipping_methods', [ $method_id ] );

// Calculate
WC()->cart->calculate_shipping();
WC()->cart->calculate_totals();

// Get calculated rate
$packages = WC()->shipping()->get_packages();
$rate = $packages[0]['rates'][ $method_id ];
$cost = $rate->get_cost();
$label = $rate->get_label(); // "JNE - REG (1-2 days)"
$taxes = $rate->get_taxes();
```

## Benefits:
-  Live rates calculated correctly
-  Service-level labels preserved
-  Shipping taxes included
-  Works with all shipping plugins
-  Same logic as frontend preview

## Testing:
1. Create order with UPS → Shows "UPS Ground" + correct cost
2. Create order with Rajaongkir → Shows "JNE - REG" + correct cost
3. Order detail page → Shows full service name
4. Shipping cost → Matches preview calculation
This commit is contained in:
dwindown
2025-11-10 16:25:52 +07:00
parent 75133c366a
commit 857d6315e6

View File

@@ -872,8 +872,65 @@ class OrdersController {
], 'shipping' );
}
// Shipping method line (parse id:instance if provided)
// Shipping method - calculate using WooCommerce cart for accurate rates
if ( $shipping_method ) {
// Initialize cart if needed
if ( ! WC()->cart ) {
wc_load_cart();
}
if ( ! WC()->session ) {
WC()->session = new \WC_Session_Handler();
WC()->session->init();
}
// Temporarily use cart to calculate shipping
WC()->cart->empty_cart();
// Add items to cart
foreach ( $items as $row ) {
$pid = absint( $row['product_id'] ?? 0 );
$qty = max( 1, absint( $row['qty'] ?? 1 ) );
if ( $pid ) {
WC()->cart->add_to_cart( $pid, $qty );
}
}
// Set shipping address for calculation
if ( $ship_addr ) {
WC()->customer->set_shipping_country( $ship_addr['country'] ?? '' );
WC()->customer->set_shipping_state( $ship_addr['state'] ?? '' );
WC()->customer->set_shipping_postcode( $ship_addr['postcode'] ?? '' );
WC()->customer->set_shipping_city( $ship_addr['city'] ?? '' );
WC()->customer->set_shipping_address( $ship_addr['address_1'] ?? '' );
}
// Set chosen shipping method
WC()->session->set( 'chosen_shipping_methods', [ $shipping_method ] );
// Calculate shipping
WC()->cart->calculate_shipping();
WC()->cart->calculate_totals();
// Get the calculated rate
$packages = WC()->shipping()->get_packages();
$shipping_cost = 0;
$shipping_title = $shipping_method;
$shipping_taxes = [];
foreach ( $packages as $package ) {
if ( isset( $package['rates'][ $shipping_method ] ) ) {
$rate = $package['rates'][ $shipping_method ];
$shipping_cost = $rate->get_cost();
$shipping_title = $rate->get_label();
$shipping_taxes = $rate->get_taxes();
break;
}
}
// Clean up cart
WC()->cart->empty_cart();
// Parse method ID and instance ID
$method_id = $shipping_method;
$instance_id = null;
if ( strpos( $shipping_method, ':' ) !== false ) {
@@ -881,36 +938,7 @@ class OrdersController {
$instance_id = absint( $instance_str );
}
// Get shipping method cost
$shipping_cost = 0;
$shipping_title = $method_id;
if ( $instance_id ) {
// Get shipping zone and method instance
$zones = \WC_Shipping_Zones::get_zones();
foreach ( $zones as $zone ) {
foreach ( $zone['shipping_methods'] as $method ) {
if ( $method->id === $method_id && $method->instance_id == $instance_id ) {
$shipping_cost = $method->get_option( 'cost', 0 );
$shipping_title = $method->get_title();
break 2;
}
}
}
// Check zone 0 (rest of the world)
if ( $shipping_cost == 0 ) {
$zone = new \WC_Shipping_Zone( 0 );
foreach ( $zone->get_shipping_methods() as $method ) {
if ( $method->id === $method_id && $method->instance_id == $instance_id ) {
$shipping_cost = $method->get_option( 'cost', 0 );
$shipping_title = $method->get_title();
break;
}
}
}
}
// Add shipping line item
$ship_item = new \WC_Order_Item_Shipping();
$ship_item->set_method_id( $method_id );
if ( null !== $instance_id && method_exists( $ship_item, 'set_instance_id' ) ) {
@@ -918,6 +946,12 @@ class OrdersController {
}
$ship_item->set_method_title( $shipping_title );
$ship_item->set_total( $shipping_cost );
// Set shipping taxes if available
if ( ! empty( $shipping_taxes ) ) {
$ship_item->set_taxes( [ 'total' => $shipping_taxes ] );
}
$order->add_item( $ship_item );
}