## 1. Created BITESHIP_ADDON_SPEC.md ✅ - Complete plugin specification - Database schema, API endpoints - WooCommerce integration - React components - Implementation timeline ## 2. Merged Addon Documentation ✅ Created ADDON_DEVELOPMENT_GUIDE.md (single source of truth): - Merged ADDON_INJECTION_GUIDE.md + ADDON_HOOK_SYSTEM.md - Two addon types: Route Injection + Hook System - Clear examples for each type - Best practices and troubleshooting - Deleted old documents ## 3. Tax Settings ✅ Frontend (admin-spa/src/routes/Settings/Tax.tsx): - Enable/disable tax calculation toggle - Display standard/reduced/zero tax rates - Show tax options (prices include tax, based on, display) - Link to WooCommerce for advanced config - Clean, simple UI Backend (includes/Api/TaxController.php): - GET /settings/tax - Fetch tax settings - POST /settings/tax/toggle - Enable/disable taxes - Fetches rates from woocommerce_tax_rates table - Clears WooCommerce cache on update ## 4. Advanced Local Pickup - TODO Will be simple: Admin adds multiple pickup locations ## Key Decisions: ✅ Hook system = No hardcoding, zero coupling ✅ Tax settings = Simple toggle + view, advanced in WC ✅ Single addon guide = One source of truth Next: Advanced Local Pickup locations
261 lines
7.3 KiB
Markdown
261 lines
7.3 KiB
Markdown
# WooNooW Indonesia Shipping (Biteship Integration)
|
|
|
|
## Plugin Specification
|
|
|
|
**Plugin Name:** WooNooW Indonesia Shipping
|
|
**Description:** Simple Indonesian shipping integration using Biteship Rate API
|
|
**Version:** 1.0.0
|
|
**Requires:** WooNooW 1.0.0+, WooCommerce 8.0+
|
|
**License:** GPL v2 or later
|
|
|
|
---
|
|
|
|
## Overview
|
|
|
|
A lightweight shipping plugin that integrates Biteship's Rate API with WooNooW SPA, providing:
|
|
- ✅ Indonesian address fields (Province, City, District, Subdistrict)
|
|
- ✅ Real-time shipping rate calculation
|
|
- ✅ Multiple courier support (JNE, SiCepat, J&T, AnterAja, etc.)
|
|
- ✅ Works in both frontend checkout AND admin order form
|
|
- ✅ No subscription required (uses free Biteship Rate API)
|
|
|
|
---
|
|
|
|
## Features Roadmap
|
|
|
|
### Phase 1: Core Functionality
|
|
- [ ] WooCommerce Shipping Method integration
|
|
- [ ] Biteship Rate API integration
|
|
- [ ] Indonesian address database (Province → Subdistrict)
|
|
- [ ] Frontend checkout integration
|
|
- [ ] Admin settings page
|
|
|
|
### Phase 2: SPA Integration
|
|
- [ ] REST API endpoints for address data
|
|
- [ ] REST API for rate calculation
|
|
- [ ] React components (SubdistrictSelector, CourierSelector)
|
|
- [ ] Hook integration with WooNooW OrderForm
|
|
- [ ] Admin order form support
|
|
|
|
### Phase 3: Advanced Features
|
|
- [ ] Rate caching (reduce API calls)
|
|
- [ ] Custom rate markup
|
|
- [ ] Free shipping threshold
|
|
- [ ] Multi-origin support
|
|
- [ ] Shipping label generation (optional, requires paid Biteship plan)
|
|
|
|
---
|
|
|
|
## Plugin Structure
|
|
|
|
```
|
|
woonoow-indonesia-shipping/
|
|
├── woonoow-indonesia-shipping.php # Main plugin file
|
|
├── includes/
|
|
│ ├── class-shipping-method.php # WooCommerce shipping method
|
|
│ ├── class-biteship-api.php # Biteship API client
|
|
│ ├── class-address-database.php # Indonesian address data
|
|
│ ├── class-addon-integration.php # WooNooW addon integration
|
|
│ └── Api/
|
|
│ └── AddressController.php # REST API endpoints
|
|
├── admin/
|
|
│ ├── class-settings.php # Admin settings page
|
|
│ └── views/
|
|
│ └── settings-page.php # Settings UI
|
|
├── admin-spa/
|
|
│ ├── src/
|
|
│ │ ├── components/
|
|
│ │ │ ├── SubdistrictSelector.tsx # Address selector
|
|
│ │ │ └── CourierSelector.tsx # Courier selection
|
|
│ │ ├── hooks/
|
|
│ │ │ ├── useAddressData.ts # Fetch address data
|
|
│ │ │ └── useRateCalculation.ts # Calculate rates
|
|
│ │ └── index.ts # Addon registration
|
|
│ ├── package.json
|
|
│ └── vite.config.ts
|
|
├── data/
|
|
│ └── indonesia-areas.sql # Address database dump
|
|
└── README.md
|
|
```
|
|
|
|
---
|
|
|
|
## Database Schema
|
|
|
|
```sql
|
|
CREATE TABLE `wp_woonoow_indonesia_areas` (
|
|
`id` bigint(20) NOT NULL AUTO_INCREMENT,
|
|
`biteship_area_id` varchar(50) NOT NULL,
|
|
`name` varchar(255) NOT NULL,
|
|
`type` enum('province','city','district','subdistrict') NOT NULL,
|
|
`parent_id` bigint(20) DEFAULT NULL,
|
|
`postal_code` varchar(10) DEFAULT NULL,
|
|
PRIMARY KEY (`id`),
|
|
KEY `biteship_area_id` (`biteship_area_id`),
|
|
KEY `parent_id` (`parent_id`),
|
|
KEY `type` (`type`)
|
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
|
```
|
|
|
|
---
|
|
|
|
## WooCommerce Shipping Method
|
|
|
|
```php
|
|
<?php
|
|
// includes/class-shipping-method.php
|
|
|
|
class WooNooW_Indonesia_Shipping_Method extends WC_Shipping_Method {
|
|
|
|
public function __construct($instance_id = 0) {
|
|
$this->id = 'woonoow_indonesia_shipping';
|
|
$this->instance_id = absint($instance_id);
|
|
$this->method_title = __('Indonesia Shipping', 'woonoow-indonesia-shipping');
|
|
$this->supports = array('shipping-zones', 'instance-settings');
|
|
$this->init();
|
|
}
|
|
|
|
public function init_form_fields() {
|
|
$this->instance_form_fields = array(
|
|
'api_key' => array(
|
|
'title' => 'Biteship API Key',
|
|
'type' => 'text'
|
|
),
|
|
'origin_subdistrict_id' => array(
|
|
'title' => 'Origin Subdistrict',
|
|
'type' => 'select',
|
|
'options' => $this->get_subdistrict_options()
|
|
),
|
|
'couriers' => array(
|
|
'title' => 'Available Couriers',
|
|
'type' => 'multiselect',
|
|
'options' => array(
|
|
'jne' => 'JNE',
|
|
'sicepat' => 'SiCepat',
|
|
'jnt' => 'J&T Express'
|
|
)
|
|
)
|
|
);
|
|
}
|
|
|
|
public function calculate_shipping($package = array()) {
|
|
$origin = $this->get_option('origin_subdistrict_id');
|
|
$destination = $package['destination']['subdistrict_id'] ?? null;
|
|
|
|
if (!$origin || !$destination) return;
|
|
|
|
$api = new WooNooW_Biteship_API($this->get_option('api_key'));
|
|
$rates = $api->get_rates($origin, $destination, $package);
|
|
|
|
foreach ($rates as $rate) {
|
|
$this->add_rate(array(
|
|
'id' => $this->id . ':' . $rate['courier_code'],
|
|
'label' => $rate['courier_name'] . ' - ' . $rate['service_name'],
|
|
'cost' => $rate['price']
|
|
));
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## REST API Endpoints
|
|
|
|
```php
|
|
<?php
|
|
// includes/Api/AddressController.php
|
|
|
|
register_rest_route('woonoow/v1', '/indonesia-shipping/provinces', array(
|
|
'methods' => 'GET',
|
|
'callback' => 'get_provinces'
|
|
));
|
|
|
|
register_rest_route('woonoow/v1', '/indonesia-shipping/calculate-rates', array(
|
|
'methods' => 'POST',
|
|
'callback' => 'calculate_rates'
|
|
));
|
|
```
|
|
|
|
---
|
|
|
|
## React Components
|
|
|
|
```typescript
|
|
// admin-spa/src/components/SubdistrictSelector.tsx
|
|
|
|
export function SubdistrictSelector({ value, onChange }) {
|
|
const [provinceId, setProvinceId] = useState('');
|
|
const [cityId, setCityId] = useState('');
|
|
|
|
const { data: provinces } = useQuery({
|
|
queryKey: ['provinces'],
|
|
queryFn: () => api.get('/indonesia-shipping/provinces')
|
|
});
|
|
|
|
return (
|
|
<div className="space-y-3">
|
|
<Select label="Province" options={provinces} />
|
|
<Select label="City" options={cities} />
|
|
<Select label="Subdistrict" onChange={onChange} />
|
|
</div>
|
|
);
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## WooNooW Hook Integration
|
|
|
|
```typescript
|
|
// admin-spa/src/index.ts
|
|
|
|
import { addonLoader, addFilter } from '@woonoow/hooks';
|
|
|
|
addonLoader.register({
|
|
id: 'indonesia-shipping',
|
|
name: 'Indonesia Shipping',
|
|
version: '1.0.0',
|
|
init: () => {
|
|
// Add subdistrict selector in order form
|
|
addFilter('woonoow_order_form_after_shipping', (content, formData, setFormData) => {
|
|
return (
|
|
<>
|
|
{content}
|
|
<SubdistrictSelector
|
|
value={formData.shipping?.subdistrict_id}
|
|
onChange={(id) => setFormData({
|
|
...formData,
|
|
shipping: { ...formData.shipping, subdistrict_id: id }
|
|
})}
|
|
/>
|
|
</>
|
|
);
|
|
});
|
|
}
|
|
});
|
|
```
|
|
|
|
---
|
|
|
|
## Implementation Timeline
|
|
|
|
**Week 1: Backend**
|
|
- Day 1-2: Database schema + address data import
|
|
- Day 3-4: WooCommerce shipping method class
|
|
- Day 5: Biteship API integration
|
|
|
|
**Week 2: Frontend**
|
|
- Day 1-2: REST API endpoints
|
|
- Day 3-4: React components
|
|
- Day 5: Hook integration + testing
|
|
|
|
**Week 3: Polish**
|
|
- Day 1-2: Error handling + loading states
|
|
- Day 3: Rate caching
|
|
- Day 4-5: Documentation + testing
|
|
|
|
---
|
|
|
|
**Status:** Specification Complete - Ready for Implementation
|