# SystemCore Integration Examples

This document provides practical, copy-paste ready examples for integrating your modules with SystemCore.

## Table of Contents
- [Quick Start Integration](#quick-start-integration)
- [FieldManager Integration (Complete Example)](#fieldmanager-integration-complete-example)
- [ProductOrder Integration (Complete Example)](#productorder-integration-complete-example)
- [New CRM Module (From Scratch)](#new-crm-module-from-scratch)
- [Testing Your Integration](#testing-your-integration)
- [Migration Scripts](#migration-scripts)

---

## Quick Start Integration

### 5-Minute Integration Checklist

1. **Update your model** - Add trait and interface
2. **Implement toSystemCore()** - Define field mapping
3. **Implement fromSystemCore()** - Reverse mapping
4. **Test** - Verify sync works

That's it! Auto-sync is now active.

---

## FieldManager Integration (Complete Example)

### Step 1: Update Client Model

File: `Modules/FieldManager/App/Models/Client.php`

```php
<?php

namespace Modules\FieldManager\App\Models;

use App\Models\User;
use App\Traits\UserActionsTrait;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
use Modules\FieldManager\App\Enums\ClientCategory;
use Modules\SystemCore\App\Contracts\SyncableCustomerInterface;
use Modules\SystemCore\App\Models\CoreCustomer;
use Modules\SystemCore\App\Traits\SyncableEntity;
use OwenIt\Auditing\Auditable;
use OwenIt\Auditing\Contracts\Auditable as AuditableContract;

class Client extends Model implements AuditableContract, SyncableCustomerInterface
{
    use Auditable, HasFactory, SoftDeletes, UserActionsTrait, SyncableEntity;

    protected $table = 'clients';

    // SystemCore Integration Configuration
    protected bool $systemCoreSyncEnabled = true;
    protected string $systemCoreEntityType = 'customer';
    protected string $syncStrategy = 'realtime'; // Options: realtime, scheduled, manual
    protected string $syncDirection = 'bidirectional'; // Options: to_core, from_core, bidirectional

    protected $fillable = [
        'name',
        'email',
        'address',
        'phone',
        'latitude',
        'longitude',
        'contact_person_name',
        'radius',
        'city',
        'state',
        'postal_code',
        'category',
        'remarks',
        'image_url',
        'status',
        'created_by_id',
        'updated_by_id',
    ];

    protected $casts = [
        'latitude' => 'float',
        'longitude' => 'float',
        'radius' => 'integer',
        'category' => ClientCategory::class,
    ];

    /**
     * Convert FieldManager Client to SystemCore Customer format
     */
    public function toSystemCore(): array
    {
        return [
            'name' => $this->name,
            'email' => $this->email,
            'phone' => $this->phone,
            'customer_type' => $this->mapCategoryToCustomerType($this->category),
            'status' => $this->status === 'active' ? 'active' : 'inactive',
            'latitude' => $this->latitude,
            'longitude' => $this->longitude,

            // Store FieldManager-specific fields in metadata
            'metadata' => [
                'source_module' => 'FieldManager',
                'source_id' => $this->id,
                'address' => $this->address,
                'city' => $this->city,
                'state' => $this->state,
                'postal_code' => $this->postal_code,
                'contact_person_name' => $this->contact_person_name,
                'radius' => $this->radius,
                'category' => $this->category->value,
                'remarks' => $this->remarks,
                'image_url' => $this->image_url,
            ],
        ];
    }

    /**
     * Import SystemCore Customer data into FieldManager Client
     */
    public function fromSystemCore(CoreCustomer $customer): self
    {
        $metadata = $customer->metadata ?? [];

        $this->fill([
            'name' => $customer->name,
            'email' => $customer->email,
            'phone' => $customer->phone,
            'latitude' => $customer->latitude,
            'longitude' => $customer->longitude,
            'status' => $customer->is_active ? 'active' : 'inactive',

            // Restore FieldManager-specific fields from metadata
            'address' => $metadata['address'] ?? null,
            'city' => $metadata['city'] ?? null,
            'state' => $metadata['state'] ?? null,
            'postal_code' => $metadata['postal_code'] ?? null,
            'contact_person_name' => $metadata['contact_person_name'] ?? null,
            'radius' => $metadata['radius'] ?? 100,
            'category' => $metadata['category'] ?? ClientCategory::Regular->value,
            'remarks' => $metadata['remarks'] ?? null,
            'image_url' => $metadata['image_url'] ?? null,
        ]);

        return $this;
    }

    /**
     * Get the synced CoreCustomer entity
     */
    public function getCoreCustomer(): ?CoreCustomer
    {
        $mapping = $this->getEntityMapping();
        return $mapping ? CoreCustomer::find($mapping->core_entity_id) : null;
    }

    /**
     * Map FieldManager category to SystemCore customer type
     */
    protected function mapCategoryToCustomerType(ClientCategory $category): string
    {
        return match($category) {
            ClientCategory::Premium => 'b2b',
            ClientCategory::Regular => 'b2c',
            ClientCategory::VIP => 'distributor',
            default => 'b2c',
        };
    }

    // Existing relationships...
    public function visits()
    {
        return $this->hasMany(Visit::class);
    }

    public function createdBy()
    {
        return $this->belongsTo(User::class, 'created_by_id');
    }

    public function updatedBy()
    {
        return $this->belongsTo(User::class, 'updated_by_id');
    }

    public function paymentCollections()
    {
        return $this->hasMany(\Modules\PaymentCollection\App\Models\PaymentCollection::class);
    }
}
```

### Step 2: Test the Integration

```php
// Create a new client - it will auto-sync to SystemCore
$client = Client::create([
    'name' => 'Test Client',
    'email' => 'test@example.com',
    'phone' => '+1234567890',
    'status' => 'active',
]);

// Verify it synced
$coreCustomer = $client->getCoreCustomer();
dd($coreCustomer); // Should show the synced customer

// Update the client - it will auto-update in SystemCore
$client->update(['email' => 'newemail@example.com']);

// Check the update synced
$coreCustomer->refresh();
dd($coreCustomer->email); // Should be 'newemail@example.com'
```

### Step 3: Manual Sync (if needed)

```php
use Modules\SystemCore\App\Services\Sync\EntitySyncService;

$syncService = app(EntitySyncService::class);

// Sync single client
$coreCustomer = $syncService->syncToCore('FieldManager', 'customer', $client);

// Sync all FieldManager clients
$results = $syncService->syncModule('FieldManager', ['customer']);
```

---

## ProductOrder Integration (Complete Example)

### Step 1: Update Product Model

File: `Modules/ProductOrder/App/Models/Product.php`

```php
<?php

namespace Modules\ProductOrder\App\Models;

use App\Traits\UserActionsTrait;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
use Modules\SystemCore\App\Contracts\SyncableProductInterface;
use Modules\SystemCore\App\Models\CoreProduct;
use Modules\SystemCore\App\Traits\SyncableEntity;
use OwenIt\Auditing\Auditable;
use OwenIt\Auditing\Contracts\Auditable as AuditableContract;

class Product extends Model implements AuditableContract, SyncableProductInterface
{
    use Auditable, SoftDeletes, UserActionsTrait, SyncableEntity;

    protected $table = 'field_products';

    // SystemCore Integration Configuration
    protected bool $systemCoreSyncEnabled = true;
    protected string $systemCoreEntityType = 'product';
    protected string $syncStrategy = 'realtime';
    protected string $syncDirection = 'bidirectional';

    protected $fillable = [
        'name',
        'description',
        'product_code',
        'status',
        'category_id',
        'base_price',
        'discount',
        'tax',
        'price',
        'stock',
        'images',
        'thumbnail',
        'created_by_id',
        'updated_by_id',
    ];

    protected $casts = [
        'images' => 'array',
        'price' => 'float',
        'base_price' => 'float',
        'discount' => 'float',
        'tax' => 'float',
        'stock' => 'integer',
    ];

    /**
     * Convert ProductOrder Product to SystemCore Product format
     */
    public function toSystemCore(): array
    {
        return [
            'name' => $this->name,
            'description' => $this->description,
            'sku' => $this->product_code ?: "SKU-{$this->id}",
            'category_id' => $this->category_id,
            'status' => $this->status === 'active' ? 'active' : 'inactive',
            'base_price' => $this->base_price,
            'selling_price' => $this->price,
            'images' => $this->images,
            'thumbnail' => $this->thumbnail,
            'unit_of_measure' => 'pcs',

            // Store ProductOrder-specific fields in metadata
            'metadata' => [
                'source_module' => 'ProductOrder',
                'source_id' => $this->id,
                'discount' => $this->discount,
                'tax' => $this->tax,
                'stock' => $this->stock,
            ],
        ];
    }

    /**
     * Import SystemCore Product data into ProductOrder Product
     */
    public function fromSystemCore(CoreProduct $product): self
    {
        $metadata = $product->metadata ?? [];

        $this->fill([
            'name' => $product->name,
            'description' => $product->description,
            'product_code' => $product->sku,
            'status' => $product->is_active ? 'active' : 'inactive',
            'category_id' => $product->category_id,
            'base_price' => $product->base_price,
            'price' => $product->selling_price,
            'images' => $product->images,
            'thumbnail' => $product->thumbnail,

            // Restore ProductOrder-specific fields
            'discount' => $metadata['discount'] ?? 0,
            'tax' => $metadata['tax'] ?? 0,
            'stock' => $metadata['stock'] ?? 0,
        ]);

        return $this;
    }

    /**
     * Get the synced CoreProduct entity
     */
    public function getCoreProduct(): ?CoreProduct
    {
        $mapping = $this->getEntityMapping();
        return $mapping ? CoreProduct::find($mapping->core_entity_id) : null;
    }

    // Existing relationships...
    public function category()
    {
        return $this->belongsTo(ProductCategory::class, 'category_id');
    }

    public function orderLines()
    {
        return $this->hasMany(OrderLine::class, 'product_id');
    }
}
```

---

## New CRM Module (From Scratch)

### Complete CRM Customer Model with SystemCore Integration

File: `Modules/CRM/App/Models/Customer.php`

```php
<?php

namespace Modules\CRM\App\Models;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
use Modules\SystemCore\App\Contracts\SyncableCustomerInterface;
use Modules\SystemCore\App\Models\CoreCustomer;
use Modules\SystemCore\App\Traits\SyncableEntity;

class Customer extends Model implements SyncableCustomerInterface
{
    use SoftDeletes, SyncableEntity;

    protected $table = 'crm_customers';

    // SystemCore Integration - Two-way sync
    protected bool $systemCoreSyncEnabled = true;
    protected string $systemCoreEntityType = 'customer';
    protected string $syncStrategy = 'realtime';
    protected string $syncDirection = 'bidirectional';

    protected $fillable = [
        'company_name',
        'type', // lead, prospect, customer
        'status',
        'primary_email',
        'primary_phone',
        'website',
        'industry',
        'annual_revenue',
        'employee_count',
        'lead_source',
        'assigned_to_id',
        'tags',
        'notes',
    ];

    protected $casts = [
        'tags' => 'array',
        'annual_revenue' => 'decimal:2',
        'employee_count' => 'integer',
    ];

    /**
     * Export CRM Customer to SystemCore
     */
    public function toSystemCore(): array
    {
        return [
            'name' => $this->company_name,
            'company_name' => $this->company_name,
            'email' => $this->primary_email,
            'phone' => $this->primary_phone,
            'website' => $this->website,
            'customer_type' => $this->type, // lead, prospect, b2b
            'status' => $this->status,
            'tags' => $this->tags,

            // CRM-specific data in metadata
            'metadata' => [
                'source_module' => 'CRM',
                'source_id' => $this->id,
                'industry' => $this->industry,
                'annual_revenue' => $this->annual_revenue,
                'employee_count' => $this->employee_count,
                'lead_source' => $this->lead_source,
                'assigned_to_id' => $this->assigned_to_id,
                'notes' => $this->notes,
            ],
        ];
    }

    /**
     * Import SystemCore Customer to CRM
     */
    public function fromSystemCore(CoreCustomer $customer): self
    {
        $metadata = $customer->metadata ?? [];

        $this->fill([
            'company_name' => $customer->company_name ?: $customer->name,
            'type' => $customer->customer_type->value,
            'status' => $customer->status->value,
            'primary_email' => $customer->email,
            'primary_phone' => $customer->phone,
            'website' => $customer->website,
            'tags' => $customer->tags,

            // Restore CRM-specific fields
            'industry' => $metadata['industry'] ?? null,
            'annual_revenue' => $metadata['annual_revenue'] ?? null,
            'employee_count' => $metadata['employee_count'] ?? null,
            'lead_source' => $metadata['lead_source'] ?? null,
            'assigned_to_id' => $metadata['assigned_to_id'] ?? null,
            'notes' => $metadata['notes'] ?? null,
        ]);

        return $this;
    }

    /**
     * Get synced core customer
     */
    public function getCoreCustomer(): ?CoreCustomer
    {
        $mapping = $this->getEntityMapping();
        return $mapping ? CoreCustomer::find($mapping->core_entity_id) : null;
    }
}
```

---

## Testing Your Integration

### Unit Test Example

File: `Modules/FieldManager/tests/Feature/ClientSyncTest.php`

```php
<?php

namespace Modules\FieldManager\Tests\Feature;

use Tests\TestCase;
use Modules\FieldManager\App\Models\Client;
use Modules\SystemCore\App\Models\CoreCustomer;
use Modules\SystemCore\App\Services\Sync\EntitySyncService;

class ClientSyncTest extends TestCase
{
    protected function setUp(): void
    {
        parent::setUp();
        // Run migrations
        $this->artisan('module:migrate SystemCore');
        $this->artisan('module:migrate FieldManager');
    }

    /** @test */
    public function client_automatically_syncs_to_system_core_on_create()
    {
        // Create a client
        $client = Client::factory()->create([
            'name' => 'Test Client',
            'email' => 'test@example.com',
        ]);

        // Check it synced to SystemCore
        $coreCustomer = $client->getCoreCustomer();

        $this->assertNotNull($coreCustomer);
        $this->assertEquals($client->name, $coreCustomer->name);
        $this->assertEquals($client->email, $coreCustomer->email);
    }

    /** @test */
    public function client_updates_sync_to_system_core()
    {
        $client = Client::factory()->create();
        $coreCustomer = $client->getCoreCustomer();

        // Update client
        $client->update(['email' => 'updated@example.com']);

        // Check core customer updated
        $coreCustomer->refresh();
        $this->assertEquals('updated@example.com', $coreCustomer->email);
    }

    /** @test */
    public function manual_sync_works()
    {
        $client = Client::factory()->make(['systemCoreSyncEnabled' => false]);
        $client->save(); // Won't auto-sync

        $this->assertNull($client->getCoreCustomer());

        // Manual sync
        $syncService = app(EntitySyncService::class);
        $coreCustomer = $syncService->syncToCore('FieldManager', 'customer', $client);

        $this->assertNotNull($coreCustomer);
        $this->assertEquals($client->email, $coreCustomer->email);
    }

    /** @test */
    public function core_customer_changes_sync_back_to_client()
    {
        $client = Client::factory()->create(['email' => 'original@example.com']);
        $coreCustomer = $client->getCoreCustomer();

        // Update core customer
        $coreCustomer->update(['email' => 'updated@core.com']);

        // Sync back to module
        $syncService = app(EntitySyncService::class);
        $syncService->syncFromCore($coreCustomer, 'FieldManager', 'customer');

        // Check client updated
        $client->refresh();
        $this->assertEquals('updated@core.com', $client->email);
    }
}
```

---

## Migration Scripts

### Migrate All Existing Clients to SystemCore

File: `scripts/migrate_fieldmanager_to_systemcore.php`

```php
<?php

use Modules\FieldManager\App\Models\Client;
use Modules\SystemCore\App\Services\Sync\EntitySyncService;

// Run this script: php artisan tinker < scripts/migrate_fieldmanager_to_systemcore.php

$syncService = app(EntitySyncService::class);

echo "Starting migration of FieldManager clients to SystemCore...\n";

$total = Client::count();
$synced = 0;
$failed = 0;

Client::chunk(100, function ($clients) use ($syncService, &$synced, &$failed, $total) {
    foreach ($clients as $client) {
        try {
            $coreCustomer = $syncService->syncToCore('FieldManager', 'customer', $client);
            $synced++;
            echo "✓ Synced client #{$client->id} → customer #{$coreCustomer->id} ({$synced}/{$total})\n";
        } catch (\Exception $e) {
            $failed++;
            echo "✗ Failed to sync client #{$client->id}: {$e->getMessage()}\n";
        }
    }
});

echo "\n=== Migration Complete ===\n";
echo "Total clients: {$total}\n";
echo "Successfully synced: {$synced}\n";
echo "Failed: {$failed}\n";
```

### Verify Sync Status

```php
use Modules\FieldManager\App\Models\Client;
use Modules\SystemCore\App\Models\EntityMapping;

// Check how many clients are synced
$totalClients = Client::count();
$syncedClients = EntityMapping::where('module_name', 'FieldManager')
    ->where('entity_type', 'customer')
    ->count();

echo "Total clients: {$totalClients}\n";
echo "Synced clients: {$syncedClients}\n";
echo "Not synced: " . ($totalClients - $syncedClients) . "\n";

// Find unsynced clients
$syncedIds = EntityMapping::where('module_name', 'FieldManager')
    ->where('entity_type', 'customer')
    ->pluck('module_entity_id');

$unsyncedClients = Client::whereNotIn('id', $syncedIds)->get();

echo "\nUnsynced clients:\n";
foreach ($unsyncedClients as $client) {
    echo "- #{$client->id}: {$client->name}\n";
}
```

---

## Common Patterns

### Pattern: Disable Auto-Sync for Specific Operations

```php
// Temporarily disable sync
$client->systemCoreSyncEnabled = false;
$client->save();

// Re-enable
$client->systemCoreSyncEnabled = true;
$client->save();
```

### Pattern: Batch Operations Without Individual Syncs

```php
// Use scheduled sync strategy
$client->syncStrategy = 'scheduled';

// Perform batch updates
foreach ($clients as $client) {
    $client->update(['status' => 'inactive']);
}

// Then sync all at once
app(EntitySyncService::class)->syncModule('FieldManager', ['customer']);
```

### Pattern: Check Sync Status

```php
$client = Client::find(1);

// Is this client synced?
$isSynced = $client->getEntityMapping() !== null;

// Is it up to date?
$mapping = $client->getEntityMapping();
$isUpToDate = $mapping && !$mapping->needsSync($client->calculateSyncHash());

// When was it last synced?
$lastSynced = $mapping?->last_synced_at;
```

---

This integration guide provides everything you need to connect your modules to SystemCore. Start with the Quick Start Integration and refer to specific examples as needed!
