# WooNooW Shipping Bridge Pattern

This document describes a generic pattern for integrating any external shipping API with WooNooW's SPA checkout.

---

## Overview

WooNooW provides hooks and endpoints that allow any shipping plugin to:
1. **Register custom checkout fields** (searchable selects, dropdowns, etc.)
2. **Bridge data to the plugin's session/API** before shipping calculation
3. **Display live rates** from external APIs

This pattern is NOT specific to Rajaongkir - it can be used for any shipping provider.

---

## Architecture

```
┌─────────────────────────────────────────────────────────────────┐
│                     WooNooW Customer SPA                        │
├─────────────────────────────────────────────────────────────────┤
│  1. Checkout loads → calls /checkout/fields                     │
│  2. Renders custom fields (e.g., searchable destination)        │
│  3. User fills form → calls /checkout/shipping-rates            │
│  4. Hook triggers → shipping plugin calculates rates            │
│  5. Rates displayed → user selects → order submitted            │
└─────────────────────────────────────────────────────────────────┘
                              │
                              ▼
┌─────────────────────────────────────────────────────────────────┐
│                   Your Bridge Snippet                            │
├─────────────────────────────────────────────────────────────────┤
│  • woocommerce_checkout_fields → Add custom fields               │
│  • register_rest_route → API endpoint for field data             │
│  • woonoow/shipping/before_calculate → Set session/data          │
└─────────────────────────────────────────────────────────────────┘
                              │
                              ▼
┌─────────────────────────────────────────────────────────────────┐
│                   Shipping Plugin (Any)                          │
├─────────────────────────────────────────────────────────────────┤
│  • Reads from WC session or customer data                        │
│  • Calls external API (Rajaongkir, Sicepat, JNE, etc.)           │
│  • Returns rates via get_rates_for_package()                     │
└─────────────────────────────────────────────────────────────────┘
```

---

## Generic Bridge Template

```php
<?php
/**
 * [PROVIDER_NAME] Bridge for WooNooW SPA Checkout
 * 
 * Replace [PROVIDER_NAME], [PROVIDER_CLASS], and [PROVIDER_SESSION_KEY] 
 * with your shipping plugin's specifics.
 */

// ============================================================
// 1. REST API Endpoint: Search/fetch data from provider
// ============================================================
add_action('rest_api_init', function() {
    register_rest_route('woonoow/v1', '/[provider]/search', [
        'methods'             => 'GET',
        'callback'            => 'woonoow_[provider]_search',
        'permission_callback' => '__return_true', // Public for customer use
        'args'                => [
            'search' => ['type' => 'string', 'required' => false],
        ],
    ]);
});

function woonoow_[provider]_search($request) {
    $search = sanitize_text_field($request->get_param('search') ?? '');
    
    if (strlen($search) < 3) {
        return [];
    }
    
    // Check if plugin is active
    if (!class_exists('[PROVIDER_CLASS]')) {
        return new WP_Error('[provider]_missing', 'Plugin not active', ['status' => 400]);
    }
    
    // Call provider's API
    // $results = [PROVIDER_CLASS]::search($search);
    
    // Format for WooNooW's SearchableSelect
    $formatted = [];
    foreach ($results as $r) {
        $formatted[] = [
            'value' => (string) $r['id'],
            'label' => $r['name'],
        ];
    }
    
    return array_slice($formatted, 0, 50);
}

// ============================================================
// 2. Add custom field(s) to checkout
// ============================================================
add_filter('woocommerce_checkout_fields', function($fields) {
    if (!class_exists('[PROVIDER_CLASS]')) {
        return $fields;
    }
    
    $custom_field = [
        'type'            => 'searchable_select', // or 'select', 'text'
        'label'           => __('[Field Label]', 'woonoow'),
        'required'        => true,
        'priority'        => 85,
        'class'           => ['form-row-wide'],
        'placeholder'     => __('Search...', 'woonoow'),
        'search_endpoint' => '/[provider]/search', // Relative to /wp-json/woonoow/v1
        'search_param'    => 'search',
        'min_chars'       => 3,
    ];
    
    $fields['billing']['billing_[provider]_field'] = $custom_field;
    $fields['shipping']['shipping_[provider]_field'] = $custom_field;
    
    return $fields;
}, 20);

// ============================================================
// 3. Bridge data to provider before shipping calculation
// ============================================================
add_action('woonoow/shipping/before_calculate', function($shipping, $items) {
    if (!class_exists('[PROVIDER_CLASS]')) {
        return;
    }
    
    // Get custom field value from shipping data
    $field_value = $shipping['[provider]_field'] 
                ?? $shipping['shipping_[provider]_field']
                ?? $shipping['billing_[provider]_field']
                ?? null;
    
    if (empty($field_value)) {
        return;
    }
    
    // Set in WC session for the shipping plugin to use
    WC()->session->set('[PROVIDER_SESSION_KEY]', $field_value);
    
    // Clear shipping cache to force recalculation
    WC()->session->set('shipping_for_package_0', false);
    
}, 10, 2);
```

---

## Supported Field Types

| Type | Description | Use Case |
|------|-------------|----------|
| `searchable_select` | Dropdown with API search | Destinations, locations, service points |
| `select` | Static dropdown | Service types, delivery options |
| `text` | Free text input | Reference numbers, notes |
| `hidden` | Hidden field | Default values, auto-set data |

---

## WooNooW Hooks Reference

| Hook | Type | Description |
|------|------|-------------|
| `woonoow/shipping/before_calculate` | Action | Called before shipping rates are calculated |
| `woocommerce_checkout_fields` | Filter | Standard WC filter for checkout fields |

---

## Examples

### Example 1: Sicepat Integration
```php
// Endpoint
register_rest_route('woonoow/v1', '/sicepat/destinations', ...);

// Session key
WC()->session->set('sicepat_destination_code', $code);
```

### Example 2: JNE Direct API
```php
// Endpoint for origin selection
register_rest_route('woonoow/v1', '/jne/origins', ...);
register_rest_route('woonoow/v1', '/jne/destinations', ...);

// Multiple session keys
WC()->session->set('jne_origin', $origin);
WC()->session->set('jne_destination', $destination);
```

---

## Checklist for New Integration

- [ ] Identify the shipping plugin's class name
- [ ] Find what session/data it reads for API calls
- [ ] Create REST endpoint for searchable data
- [ ] Add checkout field(s) via filter
- [ ] Bridge data via `woonoow/shipping/before_calculate`
- [ ] Test shipping rate calculation
- [ ] Document in dedicated `[PROVIDER]_INTEGRATION.md`

---

## Related Documentation

- [RAJAONGKIR_INTEGRATION.md](RAJAONGKIR_INTEGRATION.md) - Rajaongkir-specific implementation
- [SHIPPING_INTEGRATION.md](SHIPPING_INTEGRATION.md) - General shipping patterns
- [HOOKS_REGISTRY.md](HOOKS_REGISTRY.md) - All WooNooW hooks
