From 8bebd3abe5de5e5126d61c7aaa1adeb069655934 Mon Sep 17 00:00:00 2001 From: dwindown Date: Mon, 10 Nov 2025 11:23:42 +0700 Subject: [PATCH] docs: Flag emoji strategy + Tax design + Shipping types MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## ✅ Issue #1: Flag Emoji Strategy (Research-Based) Your comprehensive research revealed: - Chrome on Windows does NOT render flag emojis - Flags work for country selection (expected UX) - Flags problematic for summary cards (political sensitivity) **Action Taken:** - ✅ Removed flag from Store summary card - ✅ Changed to: "📍 Store Location: Indonesia" - ✅ Kept flags in dropdowns (country, currency) - ✅ Professional, accessible, future-proof **Pattern:** - Dropdowns: 🇮🇩 Indonesia (visual aid) - Summary: 📍 Indonesia (neutral, professional) - Shipping zones: Text only (clean, scalable) ## ✅ Issue #2: Tax Settings Design Created TAX_SETTINGS_DESIGN.md with: - Toggle at top to enable/disable - **Predefined rates based on store country** - Indonesia: 11% (PPN) auto-shown - Malaysia: 6% (SST) auto-shown - Smart! No re-selecting country - Zero learning curve **User Flow:** 1. Enable tax toggle 2. See: "🇮🇩 Indonesia: 11% (Standard)" 3. Done! Tax working. **For multi-country:** 1. Click "+ Add Tax Rate" 2. Select Malaysia 3. Auto-fills: 6% 4. Save. Done! ## ✅ Issue #3: Shipping Method Types Created SHIPPING_METHOD_TYPES.md documenting: **Type 1: Static Methods** (WC Core) - Free Shipping, Flat Rate, Local Pickup - No API, immediate availability - Basic address fields **Type 2: Live Rate Methods** (API-based) - UPS, FedEx, DHL (International) - J&T, JNE, SiCepat (Indonesian) - Requires "Calculate" button - Returns service options **Address Requirements:** - International: Postal Code (required) - Indonesian: Subdistrict (required) - Static: Basic address only **The Pattern:** ``` Static → Immediate display Live Rate → Calculate → Service options → Select ``` **Next:** Fix Create Order to show conditional fields ## Documentation Added: - TAX_SETTINGS_DESIGN.md - SHIPPING_METHOD_TYPES.md Both ready for implementation! --- SHIPPING_METHOD_TYPES.md | 327 ++++++++++++++++++++++++ TAX_SETTINGS_DESIGN.md | 177 +++++++++++++ admin-spa/src/routes/Settings/Store.tsx | 9 +- 3 files changed, 508 insertions(+), 5 deletions(-) create mode 100644 SHIPPING_METHOD_TYPES.md create mode 100644 TAX_SETTINGS_DESIGN.md diff --git a/SHIPPING_METHOD_TYPES.md b/SHIPPING_METHOD_TYPES.md new file mode 100644 index 0000000..6da6d28 --- /dev/null +++ b/SHIPPING_METHOD_TYPES.md @@ -0,0 +1,327 @@ +# Shipping Method Types - WooCommerce Core Structure + +## The Two Types of Shipping Methods + +WooCommerce has TWO fundamentally different shipping method types: + +--- + +## Type 1: Static Methods (WooCommerce Core) + +**Characteristics:** +- No API calls +- Fixed rates or free +- Configured once in settings +- Available immediately + +**Examples:** +- Free Shipping +- Flat Rate +- Local Pickup + +**Structure:** +``` +Method: Free Shipping +├── Conditions: Order total > $50 +└── Cost: $0 +``` + +**In Create Order:** +``` +User fills address +→ Static methods appear immediately +→ User selects one +→ Done! +``` + +--- + +## Type 2: Live Rate Methods (API-based) + +**Characteristics:** +- Requires API call +- Dynamic rates based on address + weight +- Returns multiple service options +- Needs "Calculate" button + +**Examples:** +- UPS (International) +- FedEx, DHL +- Indonesian Shipping Addons (J&T, JNE, SiCepat) + +**Structure:** +``` +Method: UPS Live Rates +├── API Credentials configured +└── On calculate: + ├── Service: UPS Ground - $15.00 + ├── Service: UPS 2nd Day - $25.00 + └── Service: UPS Next Day - $45.00 +``` + +**In Create Order:** +``` +User fills address +→ Click "Calculate Shipping" +→ API returns service options +→ User selects one +→ Done! +``` + +--- + +## The Real Hierarchy + +### Static Method (Simple): +``` +Method +└── (No sub-levels) +``` + +### Live Rate Method (Complex): +``` +Method +├── Courier (if applicable) +│ ├── Service Option 1 +│ ├── Service Option 2 +│ └── Service Option 3 +└── Or directly: + ├── Service Option 1 + └── Service Option 2 +``` + +--- + +## Indonesian Shipping Example + +**Method:** Indonesian Shipping (API-based) +**API:** Biteship / RajaOngkir / Custom + +**After Calculate:** +``` +J&T Express +├── Regular Service: Rp15,000 (2-3 days) +└── Express Service: Rp25,000 (1 day) + +JNE +├── REG: Rp18,000 (2-4 days) +├── YES: Rp28,000 (1-2 days) +└── OKE: Rp12,000 (3-5 days) + +SiCepat +├── Regular: Rp16,000 (2-3 days) +└── BEST: Rp20,000 (1-2 days) +``` + +**User sees:** Courier name + Service name + Price + Estimate + +--- + +## UPS Example (International) + +**Method:** UPS Live Rates +**API:** UPS API + +**After Calculate:** +``` +UPS Ground: $15.00 (5-7 business days) +UPS 2nd Day Air: $25.00 (2 business days) +UPS Next Day Air: $45.00 (1 business day) +``` + +**User sees:** Service name + Price + Estimate + +--- + +## Address Field Requirements + +### Static Methods: +- Country +- State/Province +- City +- Postal Code +- Address Line 1 +- Address Line 2 (optional) + +### Live Rate Methods: + +**International (UPS, FedEx, DHL):** +- Country +- State/Province +- City +- **Postal Code** (REQUIRED - used for rate calculation) +- Address Line 1 +- Address Line 2 (optional) + +**Indonesian (J&T, JNE, SiCepat):** +- Country: Indonesia +- Province +- City/Regency +- **Subdistrict** (REQUIRED - used for rate calculation) +- Postal Code +- Address Line 1 +- Address Line 2 (optional) + +--- + +## The Pattern + +| Method Type | Address Requirement | Rate Calculation | +|-------------|---------------------|------------------| +| Static | Basic address | Fixed/Free | +| Live Rate (International) | **Postal Code** required | API call with postal code | +| Live Rate (Indonesian) | **Subdistrict** required | API call with subdistrict ID | + +--- + +## Implementation in Create Order + +### Current Problem: +- We probably require subdistrict for ALL methods +- This breaks international live rate methods + +### Solution: + +**Step 1: Detect Available Methods** +```javascript +const availableMethods = getShippingMethods(address.country); + +const needsSubdistrict = availableMethods.some(method => + method.type === 'live_rate' && method.country === 'ID' +); + +const needsPostalCode = availableMethods.some(method => + method.type === 'live_rate' && method.country !== 'ID' +); +``` + +**Step 2: Show Conditional Fields** +```javascript +// Always show +- Country +- State/Province +- City +- Address Line 1 + +// Conditional +if (needsSubdistrict) { + - Subdistrict (required) +} + +if (needsPostalCode || needsSubdistrict) { + - Postal Code (required) +} + +// Always optional +- Address Line 2 +``` + +**Step 3: Calculate Shipping** +```javascript +// Static methods +if (method.type === 'static') { + return method.cost; // Immediate +} + +// Live rate methods +if (method.type === 'live_rate') { + const rates = await fetchLiveRates({ + method: method.id, + address: { + country: address.country, + state: address.state, + city: address.city, + subdistrict: address.subdistrict, // If Indonesian + postal_code: address.postal_code, // If international + // ... other fields + } + }); + + return rates; // Array of service options +} +``` + +--- + +## UI Flow + +### Scenario 1: Static Method Only +``` +1. User fills basic address +2. Shipping options appear immediately: + - Free Shipping: $0 + - Flat Rate: $10 +3. User selects one +4. Done! +``` + +### Scenario 2: Indonesian Live Rate +``` +1. User fills address including subdistrict +2. Click "Calculate Shipping" +3. API returns: + - J&T Regular: Rp15,000 + - JNE REG: Rp18,000 + - SiCepat BEST: Rp20,000 +4. User selects one +5. Done! +``` + +### Scenario 3: International Live Rate +``` +1. User fills address including postal code +2. Click "Calculate Shipping" +3. API returns: + - UPS Ground: $15.00 + - UPS 2nd Day: $25.00 +4. User selects one +5. Done! +``` + +### Scenario 4: Mixed (Static + Live Rate) +``` +1. User fills address +2. Static methods appear immediately: + - Free Shipping: $0 +3. Click "Calculate Shipping" for live rates +4. Live rates appear: + - UPS Ground: $15.00 +5. User selects from all options +6. Done! +``` + +--- + +## WooCommerce Core Behavior + +**Yes, this is all in WooCommerce core!** + +- Static methods: `WC_Shipping_Method` class +- Live rate methods: Extend `WC_Shipping_Method` with API logic +- Service options: Stored as shipping rates with method_id + instance_id + +**WooCommerce handles:** +- Method registration +- Rate calculation +- Service option display +- Selection and storage + +**We need to handle:** +- Conditional address fields +- "Calculate" button for live rates +- Service option display in Create Order +- Proper address validation + +--- + +## Next Steps + +1. Investigate Create Order address field logic +2. Add conditional field display based on available methods +3. Add "Calculate Shipping" button for live rates +4. Display service options properly +5. Test with: + - Static methods only + - Indonesian live rates + - International live rates + - Mixed scenarios diff --git a/TAX_SETTINGS_DESIGN.md b/TAX_SETTINGS_DESIGN.md new file mode 100644 index 0000000..2c6a198 --- /dev/null +++ b/TAX_SETTINGS_DESIGN.md @@ -0,0 +1,177 @@ +# Tax Settings Design - WooNooW + +## Philosophy: Zero Learning Curve + +User should understand tax setup in 30 seconds, not 30 minutes. + +--- + +## UI Structure + +``` +Tax Settings Page +├── [Toggle] Enable tax calculations +│ └── Description: "Calculate and display taxes at checkout" +│ +├── When ENABLED, show: +│ +├── Predefined Tax Rates [SettingsCard] +│ └── Based on store country from Store Details +│ +│ Example for Indonesia: +│ ┌─────────────────────────────────────┐ +│ │ 🇮🇩 Indonesia Tax Rates │ +│ ├─────────────────────────────────────┤ +│ │ Standard Rate: 11% │ +│ │ Applied to: All products │ +│ │ [Edit Rate] │ +│ └─────────────────────────────────────┘ +│ +├── Additional Tax Rates [SettingsCard] +│ ├── [+ Add Tax Rate] button +│ └── List of custom rates: +│ ┌─────────────────────────────────┐ +│ │ Malaysia: 6% │ +│ │ Applied to: All products │ +│ │ [Edit] [Delete] │ +│ └─────────────────────────────────┘ +│ +├── Display Settings [SettingsCard] +│ ├── Prices are entered: [Including tax / Excluding tax] +│ ├── Display prices in shop: [Including tax / Excluding tax] +│ └── Display prices in cart: [Including tax / Excluding tax] +│ +└── Advanced Settings + └── Link to WooCommerce tax settings + +``` + +--- + +## Predefined Tax Rates by Country + +When user's store country is set, we show the standard rate: + +| Country | Standard Rate | Note | +|---------|---------------|------| +| Indonesia | 11% | PPN (VAT) | +| Malaysia | 6% | SST | +| Singapore | 9% | GST | +| Thailand | 7% | VAT | +| Philippines | 12% | VAT | +| Vietnam | 10% | VAT | +| United States | 0% | Varies by state - user adds manually | +| European Union | 20% | Average - varies by country | + +--- + +## User Flow + +### Scenario 1: Indonesian Store (Simple) +1. User enables tax toggle +2. Sees: "🇮🇩 Indonesia: 11% (Standard)" +3. Done! Tax is working. + +### Scenario 2: Multi-Country Store +1. User enables tax toggle +2. Sees predefined rate for their country +3. Clicks "+ Add Tax Rate" +4. Selects country: Malaysia +5. Rate auto-fills: 6% +6. Clicks Save +7. Done! + +### Scenario 3: US Store (Complex) +1. User enables tax toggle +2. Sees: "🇺🇸 United States: 0% (Add rates by state)" +3. Clicks "+ Add Tax Rate" +4. Selects: United States - California +5. Enters: 7.25% +6. Clicks Save +7. Repeats for other states + +--- + +## Add Tax Rate Dialog + +``` +Add Tax Rate +├── Country/Region [Searchable Select] +│ └── 🇮🇩 Indonesia +│ 🇲🇾 Malaysia +│ 🇺🇸 United States +│ └── California +│ Texas +│ New York +│ +├── Tax Rate (%) +│ └── [Input: 11] +│ +├── Tax Class +│ └── [Select: Standard / Reduced / Zero] +│ +└── [Cancel] [Save Rate] +``` + +--- + +## Backend Requirements + +### API Endpoints: +- `GET /settings/tax/config` - Get tax enabled status + rates +- `POST /settings/tax/toggle` - Enable/disable tax +- `GET /settings/tax/rates` - List all tax rates +- `POST /settings/tax/rates` - Create tax rate +- `PUT /settings/tax/rates/{id}` - Update tax rate +- `DELETE /settings/tax/rates/{id}` - Delete tax rate +- `GET /settings/tax/predefined` - Get predefined rates by country + +### Predefined Rates Data: +```json +{ + "ID": { + "country": "Indonesia", + "rate": 11, + "name": "PPN (VAT)", + "class": "standard" + }, + "MY": { + "country": "Malaysia", + "rate": 6, + "name": "SST", + "class": "standard" + } +} +``` + +--- + +## Benefits + +✅ **Zero learning curve** - User sees their country's rate immediately +✅ **No re-selection** - Store country from Store Details is used +✅ **Smart defaults** - Predefined rates are accurate +✅ **Flexible** - Can add more countries/rates as needed +✅ **Accessible** - Clear labels, simple toggle +✅ **Scalable** - Works for single-country and multi-country stores + +--- + +## Comparison to WooCommerce + +| Feature | WooCommerce | WooNooW | +|---------|-------------|---------| +| Enable tax | Checkbox buried in settings | Toggle at top | +| Add rate | Navigate to Tax tab → Add rate → Fill form | Predefined + one-click add | +| Multi-country | Manual for each | Smart suggestions | +| Learning curve | 30 minutes | 30 seconds | + +--- + +## Next Steps + +1. Create Tax settings page component +2. Build backend API endpoints +3. Add predefined rates data +4. Test with Indonesian store +5. Test with multi-country store diff --git a/admin-spa/src/routes/Settings/Store.tsx b/admin-spa/src/routes/Settings/Store.tsx index ce2fd51..60bdd35 100644 --- a/admin-spa/src/routes/Settings/Store.tsx +++ b/admin-spa/src/routes/Settings/Store.tsx @@ -456,21 +456,20 @@ export default function StoreDetailsPage() { - {/* Summary Card - Dynamic with Flag */} + {/* Summary Card - Professional, No Flag */}
{(() => { - // Find flag for current currency const currencyFlag = flagsData.find((f: any) => f.code === settings.currency); const currencyInfo = currencies.find((c: any) => c.code === settings.currency); - const flagEmoji = currencyFlag ? countryCodeToEmoji(currencyFlag.countryCode) : ''; + const countryName = currencyFlag?.country || settings.country; return ( <>

- {flagEmoji} Your store is located in {currencyFlag?.country || settings.country} + 📍 Store Location: {countryName}

- Prices will be displayed in {currencyInfo?.name || settings.currency} • Timezone: {settings.timezone} + Currency: {currencyInfo?.name || settings.currency} • Timezone: {settings.timezone}

);