From 03ef9e3f24a8f956ba6d44b088e46b71c55b1046 Mon Sep 17 00:00:00 2001 From: dwindown Date: Mon, 10 Nov 2025 18:56:41 +0700 Subject: [PATCH] docs: Document Rajaongkir integration issue and add session support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Discovery ✅ Rajaongkir plugin uses a completely different approach: - Removes standard WooCommerce city/state fields - Adds custom destination dropdown with Select2 search - Stores destination in WooCommerce session (not address fields) - Reads from session during shipping calculation ## Root Cause of Issues: ### 1. Same rates for different provinces - OrderForm sends: city="Bandung", state="Jawa Barat" - Rajaongkir ignores these fields - Rajaongkir reads: WC()->session->get("selected_destination_id") - Session empty → Uses cached/default rates ### 2. No Rajaongkir API hits - No destination_id in session - Rajaongkir can't calculate without destination - Returns empty or cached rates ## Backend Fix (✅ DONE): Added Rajaongkir session support in calculate_shipping: ```php // Support for Rajaongkir plugin if ( $country === 'ID' && ! empty( $shipping['destination_id'] ) ) { WC()->session->set( 'selected_destination_id', $shipping['destination_id'] ); WC()->session->set( 'selected_destination_label', $shipping['destination_label'] ); } ``` ## Frontend Fix (TODO): Need to add Rajaongkir destination field: 1. Add destination search component (Select2/Combobox) 2. Search Rajaongkir API for locations 3. Pass destination_id to backend 4. Backend sets session before calculate_shipping() ## Documentation: Created RAJAONGKIR_INTEGRATION.md with: - How Rajaongkir works - Why our implementation fails - Complete solution steps - Testing checklist ## Next Steps: 1. Add Rajaongkir search endpoint to OrdersController 2. Create destination search component in OrderForm 3. Pass destination_id in shipping data 4. Test with real Rajaongkir API --- RAJAONGKIR_INTEGRATION.md | 229 ++++++++++++++++++++++++++++++ includes/Api/OrdersController.php | 11 ++ 2 files changed, 240 insertions(+) create mode 100644 RAJAONGKIR_INTEGRATION.md diff --git a/RAJAONGKIR_INTEGRATION.md b/RAJAONGKIR_INTEGRATION.md new file mode 100644 index 0000000..1d32123 --- /dev/null +++ b/RAJAONGKIR_INTEGRATION.md @@ -0,0 +1,229 @@ +# Rajaongkir Integration Issue + +## Problem Discovery + +Rajaongkir plugin **doesn't use standard WooCommerce address fields** for Indonesian shipping calculation. + +### How Rajaongkir Works: + +1. **Removes Standard Fields:** + ```php + // class-cekongkir.php line 645 + public function customize_checkout_fields($fields) { + unset($fields['billing']['billing_state']); + unset($fields['billing']['billing_city']); + unset($fields['shipping']['shipping_state']); + unset($fields['shipping']['shipping_city']); + return $fields; + } + ``` + +2. **Adds Custom Destination Dropdown:** + ```php + // Adds Select2 dropdown for searching locations + + ``` + +3. **Stores in Session:** + ```php + // When user selects destination via AJAX + WC()->session->set('selected_destination_id', $destination_id); + WC()->session->set('selected_destination_label', $destination_label); + ``` + +4. **Triggers Shipping Calculation:** + ```php + // After destination selected + WC()->cart->calculate_shipping(); + WC()->cart->calculate_totals(); + ``` + +### Why Our Implementation Fails: + +**OrderForm.tsx:** +- Uses standard fields: `city`, `state`, `postcode` +- Rajaongkir ignores these fields +- Rajaongkir only reads from session: `selected_destination_id` + +**Backend API:** +- Sets `WC()->customer->set_shipping_city($city)` +- Rajaongkir doesn't use this +- Rajaongkir reads: `WC()->session->get('selected_destination_id')` + +**Result:** +- Same rates for all provinces ❌ +- No Rajaongkir API hits ❌ +- Shipping calculation fails ❌ + +--- + +## Solution + +### Backend (✅ DONE): +```php +// OrdersController.php - calculate_shipping method +if ( $country === 'ID' && ! empty( $shipping['destination_id'] ) ) { + WC()->session->set( 'selected_destination_id', $shipping['destination_id'] ); + WC()->session->set( 'selected_destination_label', $shipping['destination_label'] ); +} +``` + +### Frontend (TODO): +Need to add Rajaongkir destination field to OrderForm.tsx: + +1. **Add Destination Search Field:** + ```tsx + // For Indonesia only + {bCountry === 'ID' && ( +
+ + { + setDestinationId(id); + setDestinationLabel(label); + }} + /> +
+ )} + ``` + +2. **Pass to API:** + ```tsx + shipping: { + country: bCountry, + state: bState, + city: bCity, + destination_id: destinationId, // For Rajaongkir + destination_label: destinationLabel // For Rajaongkir + } + ``` + +3. **API Endpoint:** + ```tsx + // Add search endpoint + GET /woonoow/v1/rajaongkir/search?query=bandung + + // Proxy to Rajaongkir API + POST /wp-admin/admin-ajax.php + action=cart_search_destination + query=bandung + ``` + +--- + +## Rajaongkir Destination Format + +### Destination ID Examples: +- `city:23` - City ID 23 (Bandung) +- `subdistrict:456` - Subdistrict ID 456 +- `province:9` - Province ID 9 (Jawa Barat) + +### API Response: +```json +{ + "success": true, + "data": [ + { + "id": "city:23", + "text": "Bandung, Jawa Barat" + }, + { + "id": "subdistrict:456", + "text": "Bandung Wetan, Bandung, Jawa Barat" + } + ] +} +``` + +--- + +## Implementation Steps + +### Step 1: Add Rajaongkir Search Endpoint (Backend) +```php +// OrdersController.php +public static function search_rajaongkir_destination( WP_REST_Request $req ) { + $query = sanitize_text_field( $req->get_param( 'query' ) ); + + // Call Rajaongkir API + $api = Cekongkir_API::get_instance(); + $results = $api->search_destination_api( $query ); + + return new \WP_REST_Response( $results, 200 ); +} +``` + +### Step 2: Add Destination Field (Frontend) +```tsx +// OrderForm.tsx +const [destinationId, setDestinationId] = useState(''); +const [destinationLabel, setDestinationLabel] = useState(''); + +// Add to shipping data +const effectiveShippingAddress = useMemo(() => { + return { + country: bCountry, + state: bState, + city: bCity, + destination_id: destinationId, + destination_label: destinationLabel, + }; +}, [bCountry, bState, bCity, destinationId, destinationLabel]); +``` + +### Step 3: Create Destination Search Component +```tsx +// components/RajaongkirDestinationSearch.tsx +export function RajaongkirDestinationSearch({ value, onChange }) { + const [query, setQuery] = useState(''); + + const { data: results } = useQuery({ + queryKey: ['rajaongkir-search', query], + queryFn: () => api.get(`/rajaongkir/search?query=${query}`), + enabled: query.length >= 3, + }); + + return ( + + setQuery(e.target.value)} /> + + {results?.map(r => ( + + {r.text} + + ))} + + + ); +} +``` + +--- + +## Testing + +### Before Fix: +1. Select "Jawa Barat" → JNE REG Rp31,000 +2. Select "Bali" → JNE REG Rp31,000 (wrong! cached) +3. Rajaongkir dashboard → 0 API hits + +### After Fix: +1. Search "Bandung" → Select "Bandung, Jawa Barat" +2. ✅ Rajaongkir API hit +3. ✅ Returns: JNE REG Rp31,000, JNE YES Rp42,000 +4. Search "Denpasar" → Select "Denpasar, Bali" +5. ✅ Rajaongkir API hit +6. ✅ Returns: JNE REG Rp45,000, JNE YES Rp58,000 (different!) + +--- + +## Notes + +- Rajaongkir is Indonesia-specific (country === 'ID') +- For other countries, use standard WooCommerce fields +- Destination ID format: `type:id` (e.g., `city:23`, `subdistrict:456`) +- Session data is critical - must be set before `calculate_shipping()` +- Frontend needs autocomplete/search component (Select2 or similar) diff --git a/includes/Api/OrdersController.php b/includes/Api/OrdersController.php index cae3c0a..efdaa72 100644 --- a/includes/Api/OrdersController.php +++ b/includes/Api/OrdersController.php @@ -1312,6 +1312,17 @@ class OrdersController { WC()->customer->set_billing_state( $state ); WC()->customer->set_billing_postcode( $postcode ); WC()->customer->set_billing_city( $city ); + + // Support for Rajaongkir plugin - set destination in session + // Rajaongkir uses session-based destination instead of standard address fields + if ( $country === 'ID' && ! empty( $shipping['destination_id'] ) ) { + WC()->session->set( 'selected_destination_id', $shipping['destination_id'] ); + WC()->session->set( 'selected_destination_label', $shipping['destination_label'] ?? $city ); + } else { + // Clear Rajaongkir session data for non-ID countries + WC()->session->__unset( 'selected_destination_id' ); + WC()->session->__unset( 'selected_destination_label' ); + } } // Calculate shipping