Files
WooNooW/ORDER_CALCULATION_PLAN.md
dwindown 2b48e60637 docs: Add order calculation implementation plan
Created ORDER_CALCULATION_PLAN.md with:
- Backend endpoints documentation
- Frontend implementation steps
- Code examples for OrderForm.tsx
- Testing checklist
- Expected results

Next: Implement frontend integration
2025-11-10 15:54:49 +07:00

5.1 KiB

Order Calculation - WooCommerce Native Implementation

BACKEND COMPLETE

New Endpoints:

  1. POST /woonoow/v1/shipping/calculate

    • Input: { items: [], shipping: {} }
    • Output: { methods: [{ id, method_id, instance_id, label, cost, taxes, meta_data }] }
    • Returns live rates from UPS, FedEx, etc.
    • Returns service-level options (UPS Ground, UPS Express)
  2. POST /woonoow/v1/orders/preview

    • Input: { items: [], billing: {}, shipping: {}, shipping_method: '', coupons: [] }
    • Output: { subtotal, shipping_total, total_tax, total, ... }
    • Calculates taxes correctly
    • Applies coupons
    • Uses WooCommerce cart engine

🔄 FRONTEND TODO

1. Update OrderForm.tsx

A. Add Shipping Rate Calculation Query

// Query shipping rates when address changes
const { data: shippingRates, refetch: refetchShipping } = useQuery({
  queryKey: ['shipping-rates', items, shippingData],
  queryFn: async () => {
    if (!hasPhysicalProduct || !shippingData.country) return null;
    return api.post('/shipping/calculate', {
      items: items.map(i => ({ product_id: i.product_id, qty: i.qty })),
      shipping: shippingData,
    });
  },
  enabled: hasPhysicalProduct && !!shippingData.country,
});

B. Add Order Preview Query

// Query order preview for totals
const { data: orderPreview } = useQuery({
  queryKey: ['order-preview', items, bCountry, shippingData, shippingMethod, validatedCoupons],
  queryFn: async () => {
    if (items.length === 0) return null;
    return api.post('/orders/preview', {
      items: items.map(i => ({ product_id: i.product_id, qty: i.qty })),
      billing: { country: bCountry, state: bState, postcode: bPost, city: bCity },
      shipping: shipDiff ? shippingData : undefined,
      shipping_method: shippingMethod,
      coupons: validatedCoupons.map(c => c.code),
    });
  },
  enabled: items.length > 0,
});

C. Update Shipping Method Dropdown

Current:

<Select value={shippingMethod} onValueChange={setShippingMethod}>
  {shippings.map(s => (
    <SelectItem value={s.id}>{s.title} - {s.cost}</SelectItem>
  ))}
</Select>

New:

<Select value={shippingMethod} onValueChange={setShippingMethod}>
  {shippingRates?.methods?.map(rate => (
    <SelectItem value={rate.id}>
      {rate.label} - {money(rate.cost)}
    </SelectItem>
  ))}
</Select>

D. Update Order Summary Display

Add tax breakdown:

<div className="space-y-2">
  <div className="flex justify-between">
    <span>Items</span>
    <span>{items.length}</span>
  </div>
  <div className="flex justify-between">
    <span>Subtotal</span>
    <span>{money(orderPreview?.subtotal || 0)}</span>
  </div>
  {orderPreview?.shipping_total > 0 && (
    <div className="flex justify-between">
      <span>Shipping</span>
      <span>{money(orderPreview.shipping_total)}</span>
    </div>
  )}
  {orderPreview?.total_tax > 0 && (
    <div className="flex justify-between">
      <span>Tax</span>
      <span>{money(orderPreview.total_tax)}</span>
    </div>
  )}
  {orderPreview?.discount_total > 0 && (
    <div className="flex justify-between text-green-600">
      <span>Discount</span>
      <span>-{money(orderPreview.discount_total)}</span>
    </div>
  )}
  <div className="flex justify-between font-bold text-lg border-t pt-2">
    <span>Total</span>
    <span>{money(orderPreview?.total || 0)}</span>
  </div>
</div>

E. Trigger Recalculation

// Refetch shipping when address changes
useEffect(() => {
  if (hasPhysicalProduct && shippingData.country) {
    refetchShipping();
  }
}, [shippingData.country, shippingData.postcode, shippingData.state]);

📋 Implementation Steps

  1. Backend endpoints created
  2. Add shipping rate calculation query
  3. Add order preview query
  4. Update shipping method dropdown to show services
  5. Update order summary to show tax
  6. Add loading states
  7. Test with UPS Live Rates
  8. Test tax calculation

🎯 Expected Result

Before:

  • Shipping: "UPS Live Rates - RM0.00"
  • Total: RM97,000 (no tax)

After:

  • Shipping dropdown shows:
    • UPS Ground - RM15,000
    • UPS Express - RM25,000
    • UPS Next Day Air - RM35,000
  • Order summary shows:
    • Subtotal: RM97,000
    • Shipping: RM15,000
    • Tax (11%): RM12,320
    • Total: RM124,320

🔧 Testing Checklist

  • Select UPS Live Rates → Shows service options
  • Select UPS Ground → Updates total
  • Change address → Recalculates rates
  • Add item → Recalculates totals
  • Apply coupon → Updates discount and total
  • Tax shows 11% of subtotal + shipping
  • Digital products → No shipping, no shipping tax
  • Physical products → Shipping + tax calculated

⚠️ Important Notes

  1. Don't reinvent calculation - Use WooCommerce cart engine
  2. Clean up cart - Always WC()->cart->empty_cart() after calculation
  3. Session handling - Use WC()->session for chosen shipping method
  4. Tax context - Set both billing and shipping addresses for accurate tax
  5. Live rates - May take 1-2 seconds to calculate, show loading state