fix: checkout issues - hidden fields, coupons, shipping in order totals
1. Hidden fields now properly hidden in SPA
- Added billing_postcode and shipping_postcode to isFieldHidden checks
- Fields with type='hidden' from PHP now conditionally rendered
2. Coupons now applied to order total
- Added coupons array to order submission payload
- CartController now calls calculate_totals() before reading discounts
- Returns per-coupon discount amounts {code, discount, type}
3. Shipping now applied to order total
- Already handled in submit() via find_shipping_rate_for_order
- Frontend now sends shipping_method in payload
4. Order details now include shipping/tracking info
- checkout/order/{id} API includes shipping_lines, tracking_number, tracking_url
- account/orders/{id} API includes same shipping/tracking fields
- Tracking info read from multiple plugin meta keys
5. Thank you/OrderDetails page shows shipping method and AWB
- Shipping Method section with courier name and cost
- AWB tracking for processing/completed orders with Track Shipment button
This commit is contained in:
@@ -122,6 +122,10 @@ add_filter('woocommerce_checkout_fields', function($fields) {
|
|||||||
$fields['billing']['billing_city']['type'] = 'hidden';
|
$fields['billing']['billing_city']['type'] = 'hidden';
|
||||||
$fields['billing']['billing_city']['required'] = false;
|
$fields['billing']['billing_city']['required'] = false;
|
||||||
}
|
}
|
||||||
|
if (isset($fields['billing']['billing_postcode'])) {
|
||||||
|
$fields['billing']['billing_postcode']['type'] = 'hidden';
|
||||||
|
$fields['billing']['billing_postcode']['required'] = false;
|
||||||
|
}
|
||||||
|
|
||||||
// Hide shipping fields
|
// Hide shipping fields
|
||||||
if (isset($fields['shipping']['shipping_country'])) {
|
if (isset($fields['shipping']['shipping_country'])) {
|
||||||
@@ -137,6 +141,10 @@ add_filter('woocommerce_checkout_fields', function($fields) {
|
|||||||
$fields['shipping']['shipping_city']['type'] = 'hidden';
|
$fields['shipping']['shipping_city']['type'] = 'hidden';
|
||||||
$fields['shipping']['shipping_city']['required'] = false;
|
$fields['shipping']['shipping_city']['required'] = false;
|
||||||
}
|
}
|
||||||
|
if (isset($fields['shipping']['shipping_postcode'])) {
|
||||||
|
$fields['shipping']['shipping_postcode']['type'] = 'hidden';
|
||||||
|
$fields['shipping']['shipping_postcode']['required'] = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Destination field definition (reused for billing and shipping)
|
// Destination field definition (reused for billing and shipping)
|
||||||
|
|||||||
@@ -532,6 +532,7 @@ export default function Checkout() {
|
|||||||
},
|
},
|
||||||
payment_method: paymentMethod,
|
payment_method: paymentMethod,
|
||||||
shipping_method: selectedShippingRate || undefined, // Selected shipping rate ID
|
shipping_method: selectedShippingRate || undefined, // Selected shipping rate ID
|
||||||
|
coupons: appliedCoupons.map(c => c.code), // Send applied coupon codes
|
||||||
customer_note: orderNotes,
|
customer_note: orderNotes,
|
||||||
// Include all custom field data for backend processing
|
// Include all custom field data for backend processing
|
||||||
custom_fields: customFieldData,
|
custom_fields: customFieldData,
|
||||||
@@ -771,16 +772,19 @@ export default function Checkout() {
|
|||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
<div>
|
{/* Postcode field - hidden if PHP sets type to 'hidden' */}
|
||||||
<label className="block text-sm font-medium mb-2">Postcode / ZIP *</label>
|
{!isFieldHidden('billing_postcode') && (
|
||||||
<input
|
<div>
|
||||||
type="text"
|
<label className="block text-sm font-medium mb-2">Postcode / ZIP *</label>
|
||||||
required
|
<input
|
||||||
value={billingData.postcode}
|
type="text"
|
||||||
onChange={(e) => setBillingData({ ...billingData, postcode: e.target.value })}
|
required
|
||||||
className="w-full border rounded-lg px-4 py-2"
|
value={billingData.postcode}
|
||||||
/>
|
onChange={(e) => setBillingData({ ...billingData, postcode: e.target.value })}
|
||||||
</div>
|
className="w-full border rounded-lg px-4 py-2"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
{/* Custom billing fields from plugins */}
|
{/* Custom billing fields from plugins */}
|
||||||
{billingCustomFields.map(field => (
|
{billingCustomFields.map(field => (
|
||||||
@@ -962,16 +966,19 @@ export default function Checkout() {
|
|||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
<div>
|
{/* Postcode field - hidden if PHP sets type to 'hidden' */}
|
||||||
<label className="block text-sm font-medium mb-2">Postcode / ZIP *</label>
|
{!isFieldHidden('shipping_postcode') && (
|
||||||
<input
|
<div>
|
||||||
type="text"
|
<label className="block text-sm font-medium mb-2">Postcode / ZIP *</label>
|
||||||
required
|
<input
|
||||||
value={shippingData.postcode}
|
type="text"
|
||||||
onChange={(e) => setShippingData({ ...shippingData, postcode: e.target.value })}
|
required
|
||||||
className="w-full border rounded-lg px-4 py-2"
|
value={shippingData.postcode}
|
||||||
/>
|
onChange={(e) => setShippingData({ ...shippingData, postcode: e.target.value })}
|
||||||
</div>
|
className="w-full border rounded-lg px-4 py-2"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
{/* Custom shipping fields from plugins */}
|
{/* Custom shipping fields from plugins */}
|
||||||
{shippingCustomFields.map(field => (
|
{shippingCustomFields.map(field => (
|
||||||
|
|||||||
@@ -198,18 +198,50 @@ class CheckoutController {
|
|||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Build shipping lines
|
||||||
|
$shipping_lines = [];
|
||||||
|
foreach ($order->get_shipping_methods() as $shipping_item) {
|
||||||
|
$shipping_lines[] = [
|
||||||
|
'id' => $shipping_item->get_id(),
|
||||||
|
'method_title' => $shipping_item->get_method_title(),
|
||||||
|
'method_id' => $shipping_item->get_method_id(),
|
||||||
|
'total' => wc_price($shipping_item->get_total()),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get tracking info from order meta (various plugins use different keys)
|
||||||
|
$tracking_number = $order->get_meta('_tracking_number')
|
||||||
|
?: $order->get_meta('_wc_shipment_tracking_items')
|
||||||
|
?: $order->get_meta('_rajaongkir_awb_number')
|
||||||
|
?: '';
|
||||||
|
$tracking_url = $order->get_meta('_tracking_url')
|
||||||
|
?: $order->get_meta('_rajaongkir_tracking_url')
|
||||||
|
?: '';
|
||||||
|
|
||||||
|
// Check for shipment tracking plugin format (array of tracking items)
|
||||||
|
if (is_array($tracking_number) && !empty($tracking_number)) {
|
||||||
|
$first_tracking = reset($tracking_number);
|
||||||
|
$tracking_number = $first_tracking['tracking_number'] ?? '';
|
||||||
|
$tracking_url = $first_tracking['tracking_url'] ?? $tracking_url;
|
||||||
|
}
|
||||||
|
|
||||||
return [
|
return [
|
||||||
'ok' => true,
|
'ok' => true,
|
||||||
'id' => $order->get_id(),
|
'id' => $order->get_id(),
|
||||||
'number' => $order->get_order_number(),
|
'number' => $order->get_order_number(),
|
||||||
'status' => $order->get_status(),
|
'status' => $order->get_status(),
|
||||||
'subtotal' => (float) $order->get_subtotal(),
|
'subtotal' => (float) $order->get_subtotal(),
|
||||||
|
'discount_total' => (float) $order->get_discount_total(),
|
||||||
'shipping_total' => (float) $order->get_shipping_total(),
|
'shipping_total' => (float) $order->get_shipping_total(),
|
||||||
'tax_total' => (float) $order->get_total_tax(),
|
'tax_total' => (float) $order->get_total_tax(),
|
||||||
'total' => (float) $order->get_total(),
|
'total' => (float) $order->get_total(),
|
||||||
'currency' => $order->get_currency(),
|
'currency' => $order->get_currency(),
|
||||||
'currency_symbol' => get_woocommerce_currency_symbol($order->get_currency()),
|
'currency_symbol' => get_woocommerce_currency_symbol($order->get_currency()),
|
||||||
'payment_method' => $order->get_payment_method_title(),
|
'payment_method' => $order->get_payment_method_title(),
|
||||||
|
'needs_shipping' => count($shipping_lines) > 0 || $order->needs_shipping_address(),
|
||||||
|
'shipping_lines' => $shipping_lines,
|
||||||
|
'tracking_number' => $tracking_number,
|
||||||
|
'tracking_url' => $tracking_url,
|
||||||
'billing' => [
|
'billing' => [
|
||||||
'first_name' => $order->get_billing_first_name(),
|
'first_name' => $order->get_billing_first_name(),
|
||||||
'last_name' => $order->get_billing_last_name(),
|
'last_name' => $order->get_billing_last_name(),
|
||||||
|
|||||||
@@ -521,6 +521,37 @@ class AccountController {
|
|||||||
$data['shipping_total'] = html_entity_decode(strip_tags(wc_price($order->get_shipping_total())));
|
$data['shipping_total'] = html_entity_decode(strip_tags(wc_price($order->get_shipping_total())));
|
||||||
$data['tax_total'] = html_entity_decode(strip_tags(wc_price($order->get_total_tax())));
|
$data['tax_total'] = html_entity_decode(strip_tags(wc_price($order->get_total_tax())));
|
||||||
$data['discount_total'] = html_entity_decode(strip_tags(wc_price($order->get_discount_total())));
|
$data['discount_total'] = html_entity_decode(strip_tags(wc_price($order->get_discount_total())));
|
||||||
|
|
||||||
|
// Shipping lines with method details
|
||||||
|
$shipping_lines = [];
|
||||||
|
foreach ($order->get_shipping_methods() as $shipping_item) {
|
||||||
|
$shipping_lines[] = [
|
||||||
|
'id' => $shipping_item->get_id(),
|
||||||
|
'method_title' => $shipping_item->get_method_title(),
|
||||||
|
'method_id' => $shipping_item->get_method_id(),
|
||||||
|
'total' => html_entity_decode(strip_tags(wc_price($shipping_item->get_total()))),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
$data['shipping_lines'] = $shipping_lines;
|
||||||
|
|
||||||
|
// Tracking info (from various shipping tracking plugins)
|
||||||
|
$tracking_number = $order->get_meta('_tracking_number')
|
||||||
|
?: $order->get_meta('_wc_shipment_tracking_items')
|
||||||
|
?: $order->get_meta('_rajaongkir_awb_number')
|
||||||
|
?: '';
|
||||||
|
$tracking_url = $order->get_meta('_tracking_url')
|
||||||
|
?: $order->get_meta('_rajaongkir_tracking_url')
|
||||||
|
?: '';
|
||||||
|
|
||||||
|
// Handle WooCommerce Shipment Tracking plugin format (array)
|
||||||
|
if (is_array($tracking_number) && !empty($tracking_number)) {
|
||||||
|
$first_tracking = reset($tracking_number);
|
||||||
|
$tracking_number = $first_tracking['tracking_number'] ?? '';
|
||||||
|
$tracking_url = $first_tracking['tracking_url'] ?? $tracking_url;
|
||||||
|
}
|
||||||
|
|
||||||
|
$data['tracking_number'] = $tracking_number;
|
||||||
|
$data['tracking_url'] = $tracking_url;
|
||||||
}
|
}
|
||||||
|
|
||||||
return $data;
|
return $data;
|
||||||
|
|||||||
Reference in New Issue
Block a user