# WooCommerce to MiniCRM Sync Module

Automatically sync WooCommerce orders to MiniCRM Projects with customer grouping, field mapping, and secure API integration.

---

## Overview

This module integrates WooCommerce with MiniCRM, automatically syncing orders as Projects. Orders are grouped by customer (registered users) or individual order (guests), with complete product data, addresses, and custom field mapping.

**Key Features:**
- ✅ **Automatic sync** on order creation/update
- ✅ **Customer grouping** - all orders from registered user go to one project
- ✅ **Product aggregation** - deduplicates identical products
- ✅ **Field mapping** - sync custom WooCommerce fields to MiniCRM
- ✅ **EPO integration** - Extra Product Options support
- ✅ **Secure feed** - IP whitelist + time-limited nonces
- ✅ **Multi-shop support** - separate product ID spaces
- ✅ **Manual sync** - batch sync projects from admin panel

---

## Quick Start

### For Administrators

**Setup your integration** (5-10 minutes):
1. Read [SETUP.md](docs/SETUP.md) for step-by-step configuration
2. Configure MiniCRM credentials and IP whitelist
3. Test with manual sync
4. Enable automatic sync

**Troubleshooting:**
- Check [TROUBLESHOOTING.md](docs/TROUBLESHOOTING.md) for common issues
- Enable debug mode to see detailed logs
- Test feed URL manually for connectivity

### For Developers

**Understand the architecture**:
- Read [Module Structure](#module-structure) below
- Review [How Sync Works](docs/SYNC-FLOW.md)
- Check [Design Patterns](#design-patterns-used)
- See test files in `/tests/` for usage examples

---

## How It Works

### High-Level Flow

```
┌─────────────────┐
│ WooCommerce     │
│ Order Created   │
└────────┬────────┘
         │
         │ 1. Hook triggers
         ↓
┌─────────────────────┐
│ Queue Project ID    │
│ (User ID or Guest)  │
└────────┬────────────┘
         │
         │ 2. On shutdown
         ↓
┌─────────────────────┐
│ Generate Feed URL   │
│ (with nonce)        │
└────────┬────────────┘
         │
         │ 3. Call MiniCRM API
         ↓
┌─────────────────────┐
│ MiniCRM Pulls Feed  │
│ (validates IP)      │
└────────┬────────────┘
         │
         │ 4. Generate XML
         ↓
┌─────────────────────┐
│ Return XML with     │
│ Projects/Orders     │
└─────────────────────┘
```

### Project ID Logic

**Registered Users**: All orders → one project (by user ID)
```
User ID 42:
  Order #100 → Project 42
  Order #101 → Project 42 ✓ Same project
```

**Guest Orders**: Each order → separate project (order ID + 1,000,000)
```
Guest:
  Order #100 → Project 1,000,100
  Order #101 → Project 1,000,101
```

**Why?** Prevents ID collisions between user IDs and guest order IDs.

---

## Module Structure

```
woocommerce/
│
├── README.md .......................... This file
├── docs/
│   ├── SETUP.md ....................... Admin setup guide
│   ├── TROUBLESHOOTING.md ............. Common issues & solutions
│   └── SYNC-FLOW.md ................... Detailed sync process
│
├── Root Level (7 files) ............... Orchestration & Settings
│   ├── class-woocommerce.php .......... Main orchestrator (singleton)
│   ├── class-feed-generator.php ....... XML feed coordinator
│   ├── class-feed-endpoint.php ........ Secure REST endpoint
│   ├── class-order-sync-manager.php ... MiniCRM API integration
│   ├── class-woocommerce-config.php ... Constants & mappings
│   ├── class-woocommerce-settings.php . Settings & validation
│   └── class-woocommerce-field-mapper.php Field mapping
│
├── dto/ (3 files) ..................... Data Transfer Objects
│   ├── class-address.php .............. Address value object
│   ├── class-product-data.php ......... Product value object
│   └── class-tax-rate.php ............. Tax rate value object
│
├── services/ (8 files) ................ Business Logic
│   ├── class-address-extractor.php .... Extract addresses from orders
│   ├── class-custom-field-mapper.php .. Map WC → MiniCRM fields
│   ├── class-epo-field-mapper.php ..... EPO plugin integration
│   ├── class-id-transformer.php ....... ID collision prevention
│   ├── class-order-grouping-service.php Group orders by customer
│   ├── class-order-query-service.php .. Query WooCommerce orders
│   ├── class-product-aggregator.php ... Deduplicate products
│   └── class-tax-calculator.php ....... Calculate tax percentages
│
├── item-handlers/ (5 files) ........... Order Item Processing
│   ├── interface-item-handler.php ..... Common interface
│   ├── class-product-item-handler.php . Standard products
│   ├── class-fee-item-handler.php ..... Fees
│   ├── class-shipping-item-handler.php  Shipping
│   └── class-coupon-item-handler.php .. Coupons/discounts
│
└── xml-builders/ (3 files) ............ XML Construction
    ├── class-project-xml-builder.php .. <Project> elements
    ├── class-order-xml-builder.php .... <Order> elements
    └── class-product-xml-builder.php .. <Product> elements
```

---

## Design Patterns Used

### Singleton Pattern
**Class**: `WooCommerce`
- Single instance manages all WooCommerce hooks
- Prevents duplicate event listeners

### Strategy Pattern
**Interface**: `Item_Handler`
- Different handlers for products, fees, shipping, coupons
- Extensible: add new item type handlers easily
- Clean: each handler responsible for one item type

### Builder Pattern
**Classes**: `Project_XML_Builder`, `Order_XML_Builder`, `Product_XML_Builder`
- Fluent interface for building complex XML structures
- Method chaining: `$project->with_address($addr)->add_order($order)->build()`
- Separates construction from representation

### Value Object Pattern
**Classes**: `Address`, `Product_Data`, `Tax_Rate`
- Immutable data containers
- No behavior, just data
- Type-safe data transfer

### Service Layer Pattern
**Namespace**: `Services\`
- Stateless business logic
- Easily testable
- Reusable across different contexts

---

## Key Classes

### WooCommerce (Main Orchestrator)
**File**: `class-woocommerce.php`
**Purpose**: Coordinate all WooCommerce sync operations

**Key Methods**:
- `queue_order_for_sync()` - Queue order when created/updated
- `sync_queued_projects()` - Batch sync on shutdown
- `get_project_id_for_order()` - Calculate project ID

**Hooks**:
- `woocommerce_new_order` → queue sync
- `woocommerce_update_order` → queue sync
- `woocommerce_order_status_changed` → queue sync
- `shutdown` → perform sync

---

### Feed_Generator (XML Builder)
**File**: `class-feed-generator.php`
**Purpose**: Orchestrate XML feed generation

**Process**:
1. Validate settings (locale, credentials)
2. Query orders for project IDs
3. Group orders by project
4. Extract addresses and custom fields
5. Process each order item (Strategy Pattern)
6. Aggregate duplicate products
7. Build XML using builders (Builder Pattern)
8. Return complete XML string

---

### Feed_Endpoint (Secure API)
**File**: `class-feed-endpoint.php`
**Purpose**: Provide secure REST endpoint for MiniCRM

**Security Layers**:
1. **Nonce validation** - 6-hour expiration
2. **IP whitelist** - CIDR notation support

**Endpoint**: `GET /wp-json/minicrm-bridge/v1/woocommerce/feed`

**Parameters**:
- `project_ids` - Comma-separated project IDs
- `nonce` - Time-limited nonce from sync manager

---

### Order_Sync_Manager (MiniCRM API)
**File**: `class-order-sync-manager.php`
**Purpose**: Trigger MiniCRM to pull feed

**Process**:
1. Generate random nonce (32 chars)
2. Store nonce in transient (6 hours)
3. Build feed URL with nonce
4. Call MiniCRM SyncFeed API
5. MiniCRM pulls feed URL
6. Log sync attempt

**MiniCRM API**:
```
POST https://r3.minicrm.hu/Api/SyncFeed/{system_id}?Source={feed_url}
Authorization: Basic {system_id}:{api_key}
```

---

### Product_Aggregator (Deduplication)
**File**: `class-product-aggregator.php`
**Purpose**: Combine duplicate products in orders

**Aggregation Rules**:
- Same product ID + same EPO fields → **aggregate** (sum quantities)
- Same product ID + different EPO fields → **separate** entries

**Example**:
```php
Order items:
  2× Product #100 (Color: Red)
  3× Product #100 (Color: Red)
  1× Product #100 (Color: Blue)

After aggregation:
  5× Product #100 (Color: Red)   ← Aggregated
  1× Product #100 (Color: Blue)  ← Separate
```

---

### ID_Transformer (Collision Prevention)
**File**: `class-id-transformer.php`
**Purpose**: Prevent ID conflicts between shops and entity types

**Transformations**:

**Project IDs:**
- Registered user: `user_id` (e.g., `42`)
- Guest order: `order_id + 1,000,000` (e.g., `1,000,123`)

**Product IDs (Multi-Shop):**
- Shop 0: `product_id` (no offset)
- Shop 1: `product_id + 100,000,000`
- Shop 2: `product_id + 200,000,000`

**Special Item IDs:**
- Fees: `50,000,000 + order_item_id`
- Shipping: `60,000,000 + order_item_id`
- Coupons: `70,000,000 + order_item_id`

---

## XML Structure

### Complete Example

```xml
<?xml version="1.0" encoding="UTF-8"?>
<Projects>
  <Project Id="42">
    <Name>John Doe</Name>

    <!-- Billing Address -->
    <BillingCountry>United States</BillingCountry>
    <BillingPostalCode>10001</BillingPostalCode>
    <BillingCity>New York</BillingCity>
    <BillingStreet>123 Main St Apt 4</BillingStreet>

    <!-- Shipping Address -->
    <ShippingCountry>United States</ShippingCountry>
    <ShippingPostalCode>11201</ShippingPostalCode>
    <ShippingCity>Brooklyn</ShippingCity>
    <ShippingStreet>456 Oak Ave</ShippingStreet>

    <!-- Custom Fields (from field mapping) -->
    <Phone>+1-555-0123</Phone>
    <CompanyName>Acme Corp</CompanyName>

    <Orders>
      <Order Id="123">
        <OrderDate>2025-11-09 10:30:00</OrderDate>
        <Status>completed</Status>
        <Total>150.00</Total>
        <Currency>USD</Currency>

        <Products>
          <Product Id="100">
            <Name>Product Name</Name>
            <Sku>SKU-123</Sku>
            <Quantity>2</Quantity>
            <NetUnitPrice>50.00</NetUnitPrice>
            <TaxPercentage>20.0</TaxPercentage>
            <Description>Product description</Description>
            <Unit>piece</Unit>

            <!-- EPO Fields (if configured) -->
            <GiftMessage>Happy Birthday!</GiftMessage>
          </Product>
        </Products>

        <Note>Customer note text</Note>
      </Order>
    </Orders>
  </Project>
</Projects>
```

---

## Configuration

### Required Settings

| Setting | Type | Description | Example |
|---------|------|-------------|---------|
| **System ID** | Numeric | MiniCRM system identifier | `1234` |
| **API Key** | String (32 chars) | MiniCRM API key | `a1b2c3...` |
| **Category ID** | Numeric | MiniCRM project category | `5678` |
| **Folder Name** | String | Project module name | `WooCommerce` |
| **Locale** | EN/HU/RO | Language for defaults | `EN` |

### Optional Settings

| Setting | Default | Description |
|---------|---------|-------------|
| **Shop ID** | `0` | Multi-shop identifier (0-99) |
| **Sync Product Desc** | `false` | Include product descriptions |
| **Debug Mode** | `false` | Enable detailed logging |
| **Max Orders** | `1000` | Max orders per project |
| **WC Mapping** | `""` | Field mapping (one per line) |
| **EPO Mapping** | `""` | EPO field mapping |

---

## Extending the Module

### Add Custom Item Handler

1. Create class implementing `Item_Handler` interface:
   ```php
   class My_Custom_Item_Handler implements Item_Handler {
       public function can_handle( WC_Order_Item $item ): bool {
           return $item instanceof WC_Order_Item_Custom;
       }

       public function extract_data( ... ): Product_Data {
           // Extract and return Product_Data
       }
   }
   ```

2. Register handler in `Feed_Generator::get_item_handlers()`

### Add Custom XML Elements

Modify builders to add custom elements:
```php
// In Project_XML_Builder or Order_XML_Builder
$this->add_element( 'CustomField', $value );
```

### Hook into Sync Events

WordPress actions available:
```php
// Before sync (no official hooks yet - enhancement opportunity)
// After sync (no official hooks yet - enhancement opportunity)
```

---

## Testing

### Test Coverage

**Unit Tests** (5 files):
- `IDTransformerTest.php` - 38 tests
- `TaxCalculatorTest.php` - 11 tests
- `ProductAggregatorTest.php` - 14 tests
- `ProductXMLBuilderTest.php` - 11 tests
- `OrderXMLBuilderTest.php` - 11 tests
- `ProjectXMLBuilderTest.php` - 14 tests

**Integration Tests** (1 file):
- `FeedGeneratorTest.php` - 6 tests

**Total**: ~105 WooCommerce-specific tests

### Run Tests

```bash
# All tests
composer test

# WooCommerce tests only
vendor/bin/phpunit --testsuite woocommerce

# Single test file
vendor/bin/phpunit tests/unit/WooCommerce/Services/ProductAggregatorTest.php
```

### Code Quality

```bash
# Linting
composer lint

# Auto-fix
composer phpcbf
```

---

## Security

### Nonce System

- **Generation**: 32-character random string
- **Storage**: WordPress transient (6-hour expiration)
- **Validation**: Required on feed endpoint
- **Single-use**: No (can be reused within 6 hours for retries)

### IP Whitelist

- **Exact match**: `203.0.113.50`
- **CIDR ranges**: `203.0.113.0/24` (256 IPs)

---

## Performance

### Optimizations

- **Product aggregation** reduces XML size
- **Batch sync** (150 projects at once)
- **Transient caching** for nonces
- **Single database query** per project
- **Stateless services** enable PHP opcache

### Limits

- **Max orders per sync**: 1000 (configurable)
- **Product description**: 1024 characters
- **Nonce lifetime**: 6 hours
- **Batch size**: 150 projects

---

## Troubleshooting

### Common Issues

| Issue | Documentation |
|-------|---------------|
| Sync not triggering | [TROUBLESHOOTING.md](docs/TROUBLESHOOTING.md#1-sync-not-triggering) |
| 403 Access Denied | [TROUBLESHOOTING.md](docs/TROUBLESHOOTING.md#2-feed-access-denied-403) |
| Missing custom fields | [TROUBLESHOOTING.md](docs/TROUBLESHOOTING.md#3-missing-custom-fields) |

### Debug Mode

Enable in settings or `wp-config.php`:
```php
define('WP_DEBUG', true);
define('WP_DEBUG_LOG', true);
```

Logs: `wp-content/debug.log`

---

## Documentation

- **[SETUP.md](docs/SETUP.md)** - Complete setup guide for administrators
- **[TROUBLESHOOTING.md](docs/TROUBLESHOOTING.md)** - Common issues and solutions
- **[SYNC-FLOW.md](docs/SYNC-FLOW.md)** - Detailed sync process explanation

---

## Support

1. Check [TROUBLESHOOTING.md](docs/TROUBLESHOOTING.md)
2. Enable debug mode and review logs
3. Test feed URL manually
4. Contact MiniCRM support for API issues
5. Contact plugin developer with debug info

---

## License

This module is part of the MiniCRM Bridge plugin and uses the same license as the parent project.

---

**Version**: 1.0.5
**Last Updated**: 2025-11-09
**Maintainer**: MiniCRM Bridge Development Team
