docs: Document Rajaongkir integration issue and add session support
## 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
This commit is contained in:
229
RAJAONGKIR_INTEGRATION.md
Normal file
229
RAJAONGKIR_INTEGRATION.md
Normal file
@@ -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
|
||||
<select id="cart-destination" name="cart_destination">
|
||||
<option>Search and select location...</option>
|
||||
</select>
|
||||
```
|
||||
|
||||
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' && (
|
||||
<div>
|
||||
<Label>Destination</Label>
|
||||
<DestinationSearch
|
||||
value={destinationId}
|
||||
onChange={(id, label) => {
|
||||
setDestinationId(id);
|
||||
setDestinationLabel(label);
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
```
|
||||
|
||||
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 (
|
||||
<Combobox value={value} onChange={onChange}>
|
||||
<ComboboxInput onChange={(e) => setQuery(e.target.value)} />
|
||||
<ComboboxOptions>
|
||||
{results?.map(r => (
|
||||
<ComboboxOption key={r.id} value={r.id}>
|
||||
{r.text}
|
||||
</ComboboxOption>
|
||||
))}
|
||||
</ComboboxOptions>
|
||||
</Combobox>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 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)
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user