# Products & Variants Unification - Implementation Plan

**Status:** Draft
**Created:** 2026-02-14
**Reference:** [PRODUCTS_VARIANTS_UNIFICATION_PLAN.md](../PRODUCTS_VARIANTS_UNIFICATION_PLAN.md)
**Strategy:** Option A - Enhance Catalog System (Migrate Sales Products & Construction Materials → Catalog)

---

## Table of Contents

1. [Phase 1: Foundation - Schema Enhancement](#phase-1-foundation---schema-enhancement)
2. [Phase 2: Permission System Setup](#phase-2-permission-system-setup)
3. [Phase 3: Model Layer Unification](#phase-3-model-layer-unification)
4. [Phase 4: Service Layer Unification](#phase-4-service-layer-unification)
5. [Phase 5: Repository Layer Updates](#phase-5-repository-layer-updates)
6. [Phase 6: Controller & API Consolidation](#phase-6-controller--api-consolidation)
7. [Phase 7: Event System Integration](#phase-7-event-system-integration)
8. [Phase 8: Data Migration](#phase-8-data-migration)
9. [Phase 9: Financial Integration](#phase-9-financial-integration)
10. [Phase 10: Testing & Validation](#phase-10-testing--validation)
11. [Phase 11: Cleanup & Deprecation](#phase-11-cleanup--deprecation)

---

## Phase 1: Foundation - Schema Enhancement

### 1.1 Multi-Tenancy Support for Catalog Products

#### 1.1.1 Create Migration: Add company_id to catalog_products

**File:** `database/migrations/YYYY_MM_DD_XXXXXX_add_company_id_to_catalog_products_table.php`

```
Tasks:
- [ ] Add company_id foreign key column
- [ ] Add index on company_id
- [ ] Add composite unique constraint (company_id, code)
- [ ] Update existing records with default company_id
```

#### 1.1.2 Create Migration: Add sales-specific fields to catalog_products

**File:** `database/migrations/YYYY_MM_DD_XXXXXX_add_sales_fields_to_catalog_products_table.php`

```
Tasks:
- [ ] Add code string column (auto-generated, ITM prefix)
- [ ] Add section enum column (accounting, procurement)
- [ ] Add category_id foreign key (simple category reference)
- [ ] Add tax_id foreign key (nullable)
- [ ] Add purchase_tax_id foreign key (nullable)
- [ ] Add cost_center_id foreign key (nullable)
- [ ] Add user_id foreign key (creator tracking)
- [ ] Add is_simple_product boolean (default: false)
- [ ] Add type string column (for backward compatibility)
```

#### 1.1.3 Create Migration: Add accounting fields to catalog_products

**File:** `database/migrations/YYYY_MM_DD_XXXXXX_add_accounting_fields_to_catalog_products_table.php`

```
Tasks:
- [ ] Add purchase_account_id foreign key (nullable)
- [ ] Verify revenue_account_id exists
- [ ] Verify expense_account_id exists
- [ ] Verify inventory_account_id exists
- [ ] Verify cogs_account_id exists
```

---

### 1.2 Multi-Tenancy Support for Catalog Product Variants

#### 1.2.1 Create Migration: Add company_id to catalog_product_variants

**File:** `database/migrations/YYYY_MM_DD_XXXXXX_add_company_id_to_catalog_product_variants_table.php`

```
Tasks:
- [ ] Add company_id foreign key column
- [ ] Add index on company_id
- [ ] Add composite unique constraint (company_id, sku)
- [ ] Update existing records with default company_id
```

#### 1.2.2 Create Migration: Add sales-specific fields to catalog_product_variants

**File:** `database/migrations/YYYY_MM_DD_XXXXXX_add_sales_fields_to_catalog_product_variants_table.php`

```
Tasks:
- [ ] Add track_stock boolean (default: true)
- [ ] Add initial_stock_level decimal (nullable)
- [ ] Add min_qty integer (default: 0)
- [ ] Add is_returnable boolean (default: true)
- [ ] Add discount_amount decimal (nullable)
- [ ] Add discount_type string (nullable, percentage/fixed)
- [ ] Add is_taxable boolean (default: true)
- [ ] Add sale_tax decimal (nullable)
- [ ] Add purchase_tax decimal (nullable)
- [ ] Add tags string (nullable)
- [ ] Add barcode_type string (nullable)
- [ ] Add barcode_path string (nullable)
```

---

### 1.3 Multi-Tenancy Support for Catalog Materials

#### 1.3.1 Create Migration: Add company_id to catalog_materials

**File:** `database/migrations/YYYY_MM_DD_XXXXXX_add_company_id_to_catalog_materials_table.php`

```
Tasks:
- [ ] Add company_id foreign key column
- [ ] Add index on company_id
- [ ] Add composite unique constraint (company_id, code)
- [ ] Update existing records with default company_id
```

#### 1.3.2 Create Migration: Add construction-specific fields to catalog_materials

**File:** `database/migrations/YYYY_MM_DD_XXXXXX_add_construction_fields_to_catalog_materials_table.php`

```
Tasks:
- [ ] Add material_type enum column (bom, construction)
- [ ] Add length string (nullable)
- [ ] Add width string (nullable)
- [ ] Add height string (nullable)
- [ ] Add weight decimal (nullable)
- [ ] Add manufacture_material string (nullable)
- [ ] Add unit_price decimal (nullable)
- [ ] Add selling_price decimal (nullable)
- [ ] Add profit_margin_type string (nullable)
- [ ] Add profit_margin decimal (nullable)
- [ ] Add final_cost decimal (nullable)
- [ ] Add current_stock integer (default: 0)
- [ ] Add store_id foreign key (nullable)
- [ ] Add material_category_id foreign key (nullable)
- [ ] Add primary_supplier_id foreign key (nullable)
- [ ] Add currency_code string (nullable)
- [ ] Add exchange_rate decimal (nullable)
- [ ] Add tax_rate decimal (nullable)
- [ ] Add reorder_level integer (nullable)
- [ ] Add max_stock integer (nullable)
- [ ] Add lead_time integer (nullable)
- [ ] Add time_unit string (nullable)
- [ ] Add expiration_date date (nullable)
- [ ] Add custom_fields json (nullable)
- [ ] Add qr_code_value string (nullable)
```

---

### 1.4 Multi-Tenancy Support for Related Tables

#### 1.4.1 Create Migration: Add company_id to catalog_product_variant_prices

**File:** `database/migrations/YYYY_MM_DD_XXXXXX_add_company_id_to_catalog_product_variant_prices_table.php`

```
Tasks:
- [ ] Add company_id foreign key column
- [ ] Add purchasing_price decimal column
- [ ] Add selling_price decimal column
- [ ] Add min_selling_price decimal column
- [ ] Add index on company_id
```

#### 1.4.2 Create Migration: Add company_id to catalog_product_variant_units

**File:** `database/migrations/YYYY_MM_DD_XXXXXX_add_company_id_to_catalog_product_variant_units_table.php`

```
Tasks:
- [ ] Add company_id foreign key column
```

#### 1.4.3 Create Migration: Add company_id to catalog_product_variant_materials

**File:** `database/migrations/YYYY_MM_DD_XXXXXX_add_company_id_to_catalog_product_variant_materials_table.php`

```
Tasks:
- [ ] Add company_id foreign key column
```

#### 1.4.4 Create Migration: Add company_id to catalog_product_images

**File:** `database/migrations/YYYY_MM_DD_XXXXXX_add_company_id_to_catalog_product_images_table.php`

```
Tasks:
- [ ] Add company_id foreign key column
```

#### 1.4.5 Create Migration: Add company_id to catalog_product_aliases

**File:** `database/migrations/YYYY_MM_DD_XXXXXX_add_company_id_to_catalog_product_aliases_table.php`

```
Tasks:
- [ ] Add company_id foreign key column
```

#### 1.4.6 Create Migration: Add company_id to catalog_client_product_prices

**File:** `database/migrations/YYYY_MM_DD_XXXXXX_add_company_id_to_catalog_client_product_prices_table.php`

```
Tasks:
- [ ] Add company_id foreign key column
```

#### 1.4.7 Create Migration: Add company_id to catalog_supplier_product_prices

**File:** `database/migrations/YYYY_MM_DD_XXXXXX_add_company_id_to_catalog_supplier_product_prices_table.php`

```
Tasks:
- [ ] Add company_id foreign key column
```

---

## Phase 2: Permission System Setup

### 2.1 Create Unified Product Permissions

#### 2.1.1 Create Permission Seeder

**File:** `database/seeders/UnifiedProductPermissionSeeder.php`

```
Tasks:
- [ ] Create seeder class
- [ ] Define permission structure:
```

**Permission Categories:**

```php
$permissions = [
    // Product Management
    'unified-products' => [
        'products.index',
        'products.show',
        'products.store',
        'products.update',
        'products.destroy',
        'products.restore',
        'products.bulk-delete',
        'products.import',
        'products.export',
    ],

    // Variant Management
    'unified-products' => [
        'variants.index',
        'variants.show',
        'variants.store',
        'variants.update',
        'variants.destroy',
        'variants.restore',
        'variants.bulk-delete',
    ],

    // Pricing Management
    'unified-products' => [
        'prices.index',
        'prices.show',
        'prices.store',
        'prices.update',
        'prices.destroy',
        'prices.history',
    ],

    // Client Pricing
    'unified-products' => [
        'client-prices.index',
        'client-prices.show',
        'client-prices.store',
        'client-prices.update',
        'client-prices.destroy',
    ],

    // Supplier Pricing
    'unified-products' => [
        'supplier-prices.index',
        'supplier-prices.show',
        'supplier-prices.store',
        'supplier-prices.update',
        'supplier-prices.destroy',
    ],

    // Materials Management
    'unified-products' => [
        'materials.index',
        'materials.show',
        'materials.store',
        'materials.update',
        'materials.destroy',
        'materials.restore',
        'materials.bulk-delete',
        'materials.import',
        'materials.export',
    ],

    // BOM (Bill of Materials)
    'unified-products' => [
        'bom.index',
        'bom.show',
        'bom.store',
        'bom.update',
        'bom.destroy',
        'bom.calculate-cost',
    ],

    // Categories
    'unified-products' => [
        'categories.index',
        'categories.show',
        'categories.store',
        'categories.update',
        'categories.destroy',
    ],

    // Product Images
    'unified-products' => [
        'images.index',
        'images.store',
        'images.update',
        'images.destroy',
        'images.reorder',
    ],

    // Product Aliases
    'unified-products' => [
        'aliases.index',
        'aliases.store',
        'aliases.update',
        'aliases.destroy',
    ],

    // Section Access (Accounting/Procurement)
    'unified-products' => [
        'section.accounting',
        'section.procurement',
        'section.all',
    ],

    // Reports
    'unified-products' => [
        'reports.product-list',
        'reports.price-list',
        'reports.stock-value',
        'reports.price-history',
        'reports.bom-cost',
        'reports.supplier-prices',
    ],
];
```

#### 2.1.2 Create Permission Migration

**File:** `database/migrations/YYYY_MM_DD_XXXXXX_add_unified_product_permissions.php`

```
Tasks:
- [ ] Create migration to run seeder
- [ ] Assign permissions to super_admin role
```

### 2.2 Permission Mapping Table

#### 2.2.1 Create Legacy Permission Mapping

**File:** `docs/plans/PRODUCT_PERMISSION_MAPPING.md`

```
Tasks:
- [ ] Document old → new permission mappings:
```

| Old Permission (Sales) | Old Permission (Construction) | Old Permission (Catalog) | New Unified Permission |
|------------------------|------------------------------|--------------------------|------------------------|
| products.index | materials.index | catalog.products.view | unified-products.products.index |
| products.store | materials.store | catalog.products.create | unified-products.products.store |
| products.update | materials.update | catalog.products.edit | unified-products.products.update |
| products.destroy | materials.destroy | catalog.products.delete | unified-products.products.destroy |
| product-prices.* | - | catalog.variant-prices.* | unified-products.prices.* |
| client-products.* | - | catalog.client-prices.* | unified-products.client-prices.* |
| - | supplier-materials.* | catalog.supplier-prices.* | unified-products.supplier-prices.* |

---

## Phase 3: Model Layer Unification

### 3.1 Enhance Catalog Product Model

#### 3.1.1 Modify Product Model

**File:** `app/Domains/Catalog/Products/Models/Product.php`

```
Tasks:
- [ ] Add company_id relationship
- [ ] Add HasCompanyScope trait
- [ ] Add category relationship (belongsTo simple Category)
- [ ] Add tax relationship (belongsTo Tax)
- [ ] Add purchaseTax relationship (belongsTo Tax)
- [ ] Add costCenter relationship (belongsTo CostCenter)
- [ ] Add user relationship (belongsTo User)
- [ ] Add fillable fields: company_id, code, section, category_id, tax_id, purchase_tax_id, cost_center_id, user_id, is_simple_product, type
- [ ] Add code generation trait (GeneratesCode)
- [ ] Add section scope (scopeForSection)
- [ ] Add Observer for auto variant creation (simple products)
- [ ] Add name accessor for backward compatibility
```

**Code Changes:**

```php
// Add to Product.php
use App\Domains\Core\Company\Traits\HasCompanyScope;
use App\Domains\Core\Traits\GeneratesCode;

class Product extends Model
{
    use HasFactory, SoftDeletes, HasCompanyScope, GeneratesCode;

    protected static string $codePrefix = 'ITM';

    protected $fillable = [
        'company_id',
        'code',
        'canonical_name',
        'description',
        'status',
        'section',
        'type',
        'catalog_item_id',
        'category_id',
        'parent_id',
        'brand',
        'manufacturer',
        'product_type',
        'tax_id',
        'purchase_tax_id',
        'purchase_account_id',
        'revenue_account_id',
        'expense_account_id',
        'inventory_account_id',
        'cogs_account_id',
        'cost_center_id',
        'user_id',
        'is_simple_product',
    ];

    protected $casts = [
        'canonical_name' => 'array',
        'description' => 'array',
        'status' => ProductStatus::class,
        'section' => ProductSection::class,
        'product_type' => ProductType::class,
        'is_simple_product' => 'boolean',
    ];

    // Backward compatibility accessor
    public function getNameAttribute(): ?string
    {
        $locale = app()->getLocale();
        return $this->canonical_name[$locale] ?? $this->canonical_name['en'] ?? null;
    }

    // Relationships
    public function company(): BelongsTo
    {
        return $this->belongsTo(Company::class);
    }

    public function category(): BelongsTo
    {
        return $this->belongsTo(Category::class);
    }

    public function tax(): BelongsTo
    {
        return $this->belongsTo(Tax::class, 'tax_id');
    }

    public function purchaseTax(): BelongsTo
    {
        return $this->belongsTo(Tax::class, 'purchase_tax_id');
    }

    public function costCenter(): BelongsTo
    {
        return $this->belongsTo(CostCenter::class);
    }

    public function creator(): BelongsTo
    {
        return $this->belongsTo(User::class, 'user_id');
    }

    // Scopes
    public function scopeForSection(Builder $query, string $section): Builder
    {
        return $query->where('section', $section);
    }

    public function scopeSimpleProducts(Builder $query): Builder
    {
        return $query->where('is_simple_product', true);
    }

    // Get default variant for simple products
    public function getDefaultVariant(): ?ProductVariant
    {
        return $this->variants()->first();
    }
}
```

#### 3.1.2 Create Product Section Enum

**File:** `app/Domains/Catalog/Products/Enums/ProductSection.php`

```
Tasks:
- [ ] Create enum with: ACCOUNTING, PROCUREMENT
```

#### 3.1.3 Create Product Observer

**File:** `app/Domains/Catalog/Products/Observers/ProductObserver.php`

```
Tasks:
- [ ] Create observer class
- [ ] Implement creating() method for code generation
- [ ] Implement created() method for auto variant creation (simple products)
- [ ] Register observer in service provider
```

### 3.2 Enhance ProductVariant Model

#### 3.2.1 Modify ProductVariant Model

**File:** `app/Domains/Catalog/Products/Models/ProductVariant.php`

```
Tasks:
- [ ] Add company_id relationship
- [ ] Add HasCompanyScope trait
- [ ] Add fillable fields for sales-specific features
- [ ] Add sales-specific field casts
- [ ] Add incrementStock method (migrate from Sales)
- [ ] Add decrementStock method (migrate from Sales)
```

**Code Changes:**

```php
// Add to ProductVariant.php
protected $fillable = [
    'company_id',
    'product_id',
    'variant_group_id',
    'sku',
    'barcode',
    'barcode_type',
    'barcode_path',
    'origin_country',
    'quality_grade',
    'manufacturer_location',
    'certification',
    'warranty_terms',
    'is_preferred',
    'notes',
    'track_stock',
    'initial_stock_level',
    'min_qty',
    'is_returnable',
    'discount_amount',
    'discount_type',
    'is_taxable',
    'sale_tax',
    'purchase_tax',
    'tags',
];

protected $casts = [
    'track_stock' => 'boolean',
    'initial_stock_level' => 'decimal:3',
    'min_qty' => 'integer',
    'is_returnable' => 'boolean',
    'discount_amount' => 'decimal:4',
    'is_taxable' => 'boolean',
    'sale_tax' => 'decimal:4',
    'purchase_tax' => 'decimal:4',
    'is_preferred' => 'boolean',
    'quality_grade' => QualityGrade::class,
];

public function company(): BelongsTo
{
    return $this->belongsTo(Company::class);
}

// Stock management methods (migrated from Sales Product)
public function incrementStock(float $quantity, ?int $warehouseId = null): void
{
    // Implementation
}

public function decrementStock(float $quantity, ?int $warehouseId = null): void
{
    // Implementation
}
```

### 3.3 Enhance ProductVariantPrice Model

#### 3.3.1 Modify ProductVariantPrice Model

**File:** `app/Domains/Catalog/Products/Models/ProductVariantPrice.php`

```
Tasks:
- [ ] Add company_id relationship
- [ ] Add HasCompanyScope trait
- [ ] Add fillable fields: company_id, purchasing_price, selling_price, min_selling_price
- [ ] Add price history tracking
```

**Code Changes:**

```php
// Add to ProductVariantPrice.php
protected $fillable = [
    'company_id',
    'variant_id',
    'unit_id',
    'price_type_id',
    'price',
    'purchasing_price',
    'selling_price',
    'min_selling_price',
    'currency',
    'min_quantity',
    'valid_from',
    'valid_to',
    'is_main_price',
];

protected $casts = [
    'price' => 'decimal:4',
    'purchasing_price' => 'decimal:4',
    'selling_price' => 'decimal:4',
    'min_selling_price' => 'decimal:4',
    'min_quantity' => 'integer',
    'valid_from' => 'date',
    'valid_to' => 'date',
    'is_main_price' => 'boolean',
];
```

### 3.4 Enhance Material Model (Unified)

#### 3.4.1 Modify Material Model

**File:** `app/Domains/Catalog/Products/Models/Material.php`

```
Tasks:
- [ ] Add company_id relationship
- [ ] Add HasCompanyScope trait
- [ ] Add construction-specific fields
- [ ] Add material_type enum (bom/construction)
- [ ] Add supplier relationships
- [ ] Add code generation trait
```

**Code Changes:**

```php
// Add to Material.php
use App\Domains\Core\Company\Traits\HasCompanyScope;
use App\Domains\Core\Traits\GeneratesCode;

class Material extends Model
{
    use HasFactory, SoftDeletes, HasCompanyScope, GeneratesCode;

    protected static string $codePrefix = 'MAT';

    protected $fillable = [
        'company_id',
        'name',
        'code',
        'description',
        'unit_id',
        'is_active',
        'material_type',
        // Construction-specific fields
        'length',
        'width',
        'height',
        'weight',
        'manufacture_material',
        'unit_price',
        'selling_price',
        'profit_margin_type',
        'profit_margin',
        'final_cost',
        'current_stock',
        'store_id',
        'material_category_id',
        'primary_supplier_id',
        'currency_code',
        'exchange_rate',
        'tax_rate',
        'reorder_level',
        'max_stock',
        'lead_time',
        'time_unit',
        'expiration_date',
        'custom_fields',
        'qr_code_value',
    ];

    protected $casts = [
        'is_active' => 'boolean',
        'material_type' => MaterialType::class,
        'weight' => 'decimal:4',
        'unit_price' => 'decimal:4',
        'selling_price' => 'decimal:4',
        'profit_margin' => 'decimal:4',
        'final_cost' => 'decimal:4',
        'current_stock' => 'integer',
        'exchange_rate' => 'decimal:6',
        'tax_rate' => 'decimal:4',
        'reorder_level' => 'integer',
        'max_stock' => 'integer',
        'lead_time' => 'integer',
        'expiration_date' => 'date',
        'custom_fields' => 'array',
    ];

    // Relationships
    public function company(): BelongsTo
    {
        return $this->belongsTo(Company::class);
    }

    public function unit(): BelongsTo
    {
        return $this->belongsTo(Unit::class);
    }

    public function store(): BelongsTo
    {
        return $this->belongsTo(Warehouse::class, 'store_id');
    }

    public function materialCategory(): BelongsTo
    {
        return $this->belongsTo(MaterialCategory::class);
    }

    public function primarySupplier(): BelongsTo
    {
        return $this->belongsTo(Supplier::class, 'primary_supplier_id');
    }

    public function suppliers(): BelongsToMany
    {
        return $this->belongsToMany(Supplier::class, 'material_supplier')
            ->withPivot(['price', 'lead_time', 'notes'])
            ->withTimestamps();
    }

    // Scopes
    public function scopeConstruction(Builder $query): Builder
    {
        return $query->where('material_type', MaterialType::CONSTRUCTION);
    }

    public function scopeBom(Builder $query): Builder
    {
        return $query->where('material_type', MaterialType::BOM);
    }
}
```

#### 3.4.2 Create MaterialType Enum

**File:** `app/Domains/Catalog/Products/Enums/MaterialType.php`

```
Tasks:
- [ ] Create enum with: BOM, CONSTRUCTION
```

### 3.5 Create Bridge/Compatibility Models

#### 3.5.1 Create SalesProductBridge Model (Temporary)

**File:** `app/Domains/Accounting/Sales/Models/ProductBridge.php`

```
Tasks:
- [ ] Create bridge model that maps old Sales Product calls to new Catalog Product
- [ ] Implement __call magic method for backward compatibility
- [ ] Log deprecation warnings
- [ ] Map to default variant for simple products
```

#### 3.5.2 Create ConstructionMaterialBridge Model (Temporary)

**File:** `app/Domains/Construction/Material/Models/MaterialBridge.php`

```
Tasks:
- [ ] Create bridge model that maps old Construction Material calls to unified Material
- [ ] Implement __call magic method for backward compatibility
- [ ] Log deprecation warnings
```

#### 3.5.3 Create ProductPriceBridge Model (Temporary)

**File:** `app/Domains/Accounting/Sales/Models/ProductPriceBridge.php`

```
Tasks:
- [ ] Create bridge model that maps old ProductPrice calls to ProductVariantPrice
- [ ] Implement __call magic method for backward compatibility
- [ ] Log deprecation warnings
```

---

## Phase 4: Service Layer Unification

### 4.1 Create Unified Product Service

#### 4.1.1 Create Main Service Interface

**File:** `app/Domains/Catalog/Products/Contracts/UnifiedProductServiceInterface.php`

```
Tasks:
- [ ] Define contract with all product operations:
```

```php
interface UnifiedProductServiceInterface
{
    // Product Operations
    public function getProducts(array $filters = []): LengthAwarePaginator;
    public function getProduct(int $id): Product;
    public function createProduct(ProductDTO $dto): Product;
    public function updateProduct(int $id, ProductDTO $dto): Product;
    public function deleteProduct(int $id): bool;
    public function restoreProduct(int $id): Product;

    // Simple Product Operations (backward compatibility)
    public function createSimpleProduct(SimpleProductDTO $dto): Product;
    public function getProductsBySection(string $section): Collection;

    // Variant Operations
    public function getVariants(int $productId): Collection;
    public function getVariant(int $id): ProductVariant;
    public function createVariant(int $productId, VariantDTO $dto): ProductVariant;
    public function updateVariant(int $id, VariantDTO $dto): ProductVariant;
    public function deleteVariant(int $id): bool;

    // Pricing Operations
    public function getVariantPrices(int $variantId): Collection;
    public function setVariantPrice(int $variantId, PriceDTO $dto): ProductVariantPrice;
    public function updateVariantPrice(int $priceId, PriceDTO $dto): ProductVariantPrice;
    public function deleteVariantPrice(int $priceId): bool;
    public function getPriceHistory(int $variantId): Collection;

    // Client Pricing
    public function getClientPrices(int $clientId): Collection;
    public function setClientPrice(int $clientId, int $variantId, ClientPriceDTO $dto): ClientProductPrice;

    // Supplier Pricing
    public function getSupplierPrices(int $supplierId): Collection;
    public function setSupplierPrice(int $supplierId, int $variantId, SupplierPriceDTO $dto): SupplierProductPrice;

    // Import/Export
    public function importProducts(string $filePath, array $options = []): ImportResult;
    public function exportProducts(array $filters = []): string;
}
```

#### 4.1.2 Create Unified Product Service Implementation

**File:** `app/Domains/Catalog/Products/Services/UnifiedProductService.php`

```
Tasks:
- [ ] Create service class implementing interface
- [ ] Inject required repositories
- [ ] Implement all product operations
- [ ] Implement all variant operations
- [ ] Implement all pricing operations
- [ ] Implement client pricing operations
- [ ] Implement supplier pricing operations
- [ ] Implement import/export operations
- [ ] Add database transaction wrapping
- [ ] Add event dispatching
- [ ] Add section-based access control
- [ ] Add auto variant creation for simple products
```

### 4.2 Create Unified Material Service

#### 4.2.1 Create Material Service Interface

**File:** `app/Domains/Catalog/Products/Contracts/UnifiedMaterialServiceInterface.php`

```
Tasks:
- [ ] Define contract with all material operations:
```

```php
interface UnifiedMaterialServiceInterface
{
    // Material CRUD
    public function getMaterials(array $filters = []): LengthAwarePaginator;
    public function getMaterial(int $id): Material;
    public function createMaterial(MaterialDTO $dto): Material;
    public function updateMaterial(int $id, MaterialDTO $dto): Material;
    public function deleteMaterial(int $id): bool;
    public function restoreMaterial(int $id): Material;

    // Material Type Operations
    public function getConstructionMaterials(): Collection;
    public function getBomMaterials(): Collection;

    // Supplier Operations
    public function getMaterialSuppliers(int $materialId): Collection;
    public function addSupplier(int $materialId, int $supplierId, SupplierMaterialDTO $dto): void;
    public function updateSupplier(int $materialId, int $supplierId, SupplierMaterialDTO $dto): void;
    public function removeSupplier(int $materialId, int $supplierId): void;

    // Stock Operations
    public function getCurrentStock(int $materialId): float;
    public function adjustStock(int $materialId, float $quantity, string $reason): void;

    // Import/Export
    public function importMaterials(string $filePath, array $options = []): ImportResult;
    public function exportMaterials(array $filters = []): string;
}
```

#### 4.2.2 Create Unified Material Service Implementation

**File:** `app/Domains/Catalog/Products/Services/UnifiedMaterialService.php`

```
Tasks:
- [ ] Create service class implementing interface
- [ ] Inject required repositories
- [ ] Implement all material operations
- [ ] Implement supplier operations
- [ ] Implement stock operations
- [ ] Implement import/export operations
- [ ] Add database transaction wrapping
- [ ] Add event dispatching
```

### 4.3 Migrate Sales Services Logic

#### 4.3.1 Migrate ProductServices Logic

**Source:** `app/Domains/Accounting/Sales/Services/ProductServices.php`

```
Tasks:
- [ ] Move index() logic to UnifiedProductService::getProducts()
- [ ] Move store() logic to UnifiedProductService::createSimpleProduct()
- [ ] Move update() logic to UnifiedProductService::updateProduct()
- [ ] Move destroy() logic to UnifiedProductService::deleteProduct()
- [ ] Move code generation logic
- [ ] Move section-based filtering logic
```

#### 4.3.2 Migrate ProductPriceServices Logic

**Source:** `app/Domains/Accounting/Sales/Services/ProductPriceServices.php`

```
Tasks:
- [ ] Move price creation logic
- [ ] Move price update logic
- [ ] Move price history tracking logic
- [ ] Move unit-based pricing logic
```

#### 4.3.3 Migrate ClientProductServices Logic

**Source:** `app/Domains/Accounting/Sales/Services/ClientProductServices.php`

```
Tasks:
- [ ] Move client price creation logic
- [ ] Move client price retrieval logic
```

### 4.4 Migrate Construction Material Services Logic

#### 4.4.1 Migrate MaterialServices Logic

**Source:** `app/Domains/Construction/Material/Services/MaterialServices.php`

```
Tasks:
- [ ] Move material creation logic to UnifiedMaterialService
- [ ] Move supplier relationship logic
- [ ] Move stock management logic
- [ ] Move code generation logic
- [ ] Move import/export logic
```

### 4.5 Enhance Existing Catalog Services

#### 4.5.1 Update ProductService

**File:** `app/Domains/Catalog/Products/Services/ProductService.php`

```
Tasks:
- [ ] Add company scoping to all queries
- [ ] Add section-based access control
- [ ] Add simple product handling
- [ ] Add backward compatibility methods
```

#### 4.5.2 Update VariantService

**File:** `app/Domains/Catalog/Products/Services/VariantService.php`

```
Tasks:
- [ ] Add company scoping to all queries
- [ ] Add stock tracking methods
- [ ] Add pricing methods
```

#### 4.5.3 Update PriceService

**File:** `app/Domains/Catalog/Products/Services/PriceService.php`

```
Tasks:
- [ ] Add company scoping to all queries
- [ ] Add price history tracking
- [ ] Add sales-style pricing support (purchasing/selling/min_selling)
```

---

## Phase 5: Repository Layer Updates

### 5.1 Update Product Repository

#### 5.1.1 Modify ProductRepository

**File:** `app/Domains/Catalog/Products/Repositories/ProductRepository.php`

```
Tasks:
- [ ] Add company scoping to all queries
- [ ] Add getBySection() method
- [ ] Add getByCategory() method
- [ ] Add getSimpleProducts() method
- [ ] Add getWithVariants() method
- [ ] Add getByCode() method
```

#### 5.1.2 Update ProductRepositoryContract

**File:** `app/Domains/Catalog/Products/Contracts/ProductRepositoryContract.php`

```
Tasks:
- [ ] Add new method signatures
```

### 5.2 Update Variant Repository

#### 5.2.1 Modify VariantRepository

**File:** `app/Domains/Catalog/Products/Repositories/VariantRepository.php`

```
Tasks:
- [ ] Add company scoping to all queries
- [ ] Add getBySku() method
- [ ] Add getByBarcode() method
- [ ] Add getWithPrices() method
- [ ] Add getWithStock() method
```

#### 5.2.2 Update VariantRepositoryContract

**File:** `app/Domains/Catalog/Products/Contracts/VariantRepositoryContract.php`

```
Tasks:
- [ ] Add new method signatures
```

### 5.3 Create/Update Material Repository

#### 5.3.1 Create/Modify MaterialRepository

**File:** `app/Domains/Catalog/Products/Repositories/MaterialRepository.php`

```
Tasks:
- [ ] Add company scoping to all queries
- [ ] Add getByType() method (bom/construction)
- [ ] Add getByCategory() method
- [ ] Add getBySupplier() method
- [ ] Add getByCode() method
- [ ] Add getLowStock() method
```

#### 5.3.2 Create MaterialRepositoryContract

**File:** `app/Domains/Catalog/Products/Contracts/MaterialRepositoryContract.php`

```
Tasks:
- [ ] Define contract methods
```

### 5.4 Create Price Repository

#### 5.4.1 Create PriceRepository

**File:** `app/Domains/Catalog/Products/Repositories/PriceRepository.php`

```
Tasks:
- [ ] Create repository for pricing operations
- [ ] Implement getByVariant() method
- [ ] Implement getByUnit() method
- [ ] Implement getMainPrice() method
- [ ] Implement getValidPrices() method (date-based)
- [ ] Implement getPriceHistory() method
```

---

## Phase 6: Controller & API Consolidation

### 6.1 Create Unified API Controllers

#### 6.1.1 Create UnifiedProductController

**File:** `app/Domains/Catalog/Products/Controllers/V2/UnifiedProductController.php`

```
Tasks:
- [ ] Create controller with full CRUD
- [ ] Implement index() with company and section scoping
- [ ] Implement store() with auto variant creation for simple products
- [ ] Implement update() with validation
- [ ] Implement destroy() with dependency checks
- [ ] Implement restore() for soft-deleted products
- [ ] Implement bySection() for section filtering
- [ ] Implement byCategory() for category filtering
- [ ] Implement import() for bulk import
- [ ] Implement export() for bulk export
```

#### 6.1.2 Create UnifiedVariantController

**File:** `app/Domains/Catalog/Products/Controllers/V2/UnifiedVariantController.php`

```
Tasks:
- [ ] Create controller for variant operations
- [ ] Implement index() with filtering
- [ ] Implement show() with details
- [ ] Implement store() for new variants
- [ ] Implement update() for existing variants
- [ ] Implement destroy() with stock checks
- [ ] Implement restore() for soft-deleted variants
- [ ] Implement byProduct() for product filtering
```

#### 6.1.3 Create UnifiedPriceController

**File:** `app/Domains/Catalog/Products/Controllers/V2/UnifiedPriceController.php`

```
Tasks:
- [ ] Create controller for pricing operations
- [ ] Implement index() for price listing
- [ ] Implement store() for new prices
- [ ] Implement update() for price changes
- [ ] Implement destroy() for price removal
- [ ] Implement history() for price history
- [ ] Implement byVariant() for variant prices
- [ ] Implement byUnit() for unit-based prices
```

#### 6.1.4 Create UnifiedClientPriceController

**File:** `app/Domains/Catalog/Products/Controllers/V2/UnifiedClientPriceController.php`

```
Tasks:
- [ ] Create controller for client-specific pricing
- [ ] Implement full CRUD operations
- [ ] Implement byClient() method
- [ ] Implement byProduct() method
```

#### 6.1.5 Create UnifiedSupplierPriceController

**File:** `app/Domains/Catalog/Products/Controllers/V2/UnifiedSupplierPriceController.php`

```
Tasks:
- [ ] Create controller for supplier-specific pricing
- [ ] Implement full CRUD operations
- [ ] Implement bySupplier() method
- [ ] Implement byProduct() method
```

#### 6.1.6 Create UnifiedMaterialController

**File:** `app/Domains/Catalog/Products/Controllers/V2/UnifiedMaterialController.php`

```
Tasks:
- [ ] Create controller for materials
- [ ] Implement full CRUD operations
- [ ] Implement byType() (construction/bom)
- [ ] Implement bySupplier()
- [ ] Implement lowStock()
- [ ] Implement import()
- [ ] Implement export()
```

#### 6.1.7 Create UnifiedBomController

**File:** `app/Domains/Catalog/Products/Controllers/V2/UnifiedBomController.php`

```
Tasks:
- [ ] Create controller for Bill of Materials
- [ ] Implement index() for BOM listing
- [ ] Implement store() for adding materials to variants
- [ ] Implement update() for quantity changes
- [ ] Implement destroy() for removing materials
- [ ] Implement calculateCost() for BOM cost calculation
```

#### 6.1.8 Create UnifiedProductReportController

**File:** `app/Domains/Catalog/Products/Controllers/V2/UnifiedProductReportController.php`

```
Tasks:
- [ ] Create controller for reports
- [ ] Implement productList() report
- [ ] Implement priceList() report
- [ ] Implement stockValue() report
- [ ] Implement priceHistory() report
- [ ] Implement bomCost() report
- [ ] Implement supplierPrices() report
```

### 6.2 Create Request Validation Classes

#### 6.2.1 Product Requests

**Files:**
- `app/Domains/Catalog/Products/Requests/V2/StoreProductRequest.php`
- `app/Domains/Catalog/Products/Requests/V2/UpdateProductRequest.php`
- `app/Domains/Catalog/Products/Requests/V2/StoreSimpleProductRequest.php`

```
Tasks:
- [ ] Create store request with validation rules
- [ ] Create update request with validation rules
- [ ] Create simple product request with variant fields included
- [ ] Add rules for: name, code, section, category_id, tax_id, etc.
```

#### 6.2.2 Variant Requests

**Files:**
- `app/Domains/Catalog/Products/Requests/V2/StoreVariantRequest.php`
- `app/Domains/Catalog/Products/Requests/V2/UpdateVariantRequest.php`

```
Tasks:
- [ ] Create store request with validation rules
- [ ] Create update request with validation rules
- [ ] Add rules for: sku, barcode, track_stock, min_qty, etc.
```

#### 6.2.3 Price Requests

**Files:**
- `app/Domains/Catalog/Products/Requests/V2/StorePriceRequest.php`
- `app/Domains/Catalog/Products/Requests/V2/UpdatePriceRequest.php`

```
Tasks:
- [ ] Create store request with validation rules
- [ ] Create update request with validation rules
- [ ] Add rules for: unit_id, purchasing_price, selling_price, min_selling_price, etc.
```

#### 6.2.4 Material Requests

**Files:**
- `app/Domains/Catalog/Products/Requests/V2/StoreMaterialRequest.php`
- `app/Domains/Catalog/Products/Requests/V2/UpdateMaterialRequest.php`

```
Tasks:
- [ ] Create store request with validation rules
- [ ] Create update request with validation rules
- [ ] Add rules for construction and BOM materials
```

### 6.3 Create API Resources

#### 6.3.1 Unified Resources

**Files:**
- `app/Domains/Catalog/Products/Resources/V2/ProductResource.php`
- `app/Domains/Catalog/Products/Resources/V2/SimpleProductResource.php`
- `app/Domains/Catalog/Products/Resources/V2/VariantResource.php`
- `app/Domains/Catalog/Products/Resources/V2/PriceResource.php`
- `app/Domains/Catalog/Products/Resources/V2/ClientPriceResource.php`
- `app/Domains/Catalog/Products/Resources/V2/SupplierPriceResource.php`
- `app/Domains/Catalog/Products/Resources/V2/MaterialResource.php`
- `app/Domains/Catalog/Products/Resources/V2/BomResource.php`

```
Tasks:
- [ ] Create resource classes with all required fields
- [ ] Include relationships (variants, prices, units, company)
- [ ] Include computed fields (total_stock, average_price)
- [ ] Add backward compatibility for Sales Product format
```

### 6.4 Create Unified Routes

#### 6.4.1 Create V2 Route File

**File:** `routes/apis/UnifiedProducts.php`

```
Tasks:
- [ ] Create route file with all unified endpoints
- [ ] Add permission middleware
- [ ] Group routes appropriately
```

**Route Structure:**

```php
Route::prefix('v2/products')->middleware(['auth:sanctum'])->group(function () {

    // Products
    Route::middleware('permission:unified-products.products.index')
        ->get('/', [UnifiedProductController::class, 'index']);
    Route::middleware('permission:unified-products.products.store')
        ->post('/', [UnifiedProductController::class, 'store']);
    Route::middleware('permission:unified-products.products.store')
        ->post('/simple', [UnifiedProductController::class, 'storeSimple']);
    Route::middleware('permission:unified-products.products.show')
        ->get('/{id}', [UnifiedProductController::class, 'show']);
    Route::middleware('permission:unified-products.products.update')
        ->put('/{id}', [UnifiedProductController::class, 'update']);
    Route::middleware('permission:unified-products.products.destroy')
        ->delete('/{id}', [UnifiedProductController::class, 'destroy']);
    Route::middleware('permission:unified-products.products.restore')
        ->post('/{id}/restore', [UnifiedProductController::class, 'restore']);
    Route::middleware('permission:unified-products.products.import')
        ->post('/import', [UnifiedProductController::class, 'import']);
    Route::middleware('permission:unified-products.products.export')
        ->get('/export', [UnifiedProductController::class, 'export']);

    // Section filtering
    Route::middleware('permission:unified-products.section.accounting')
        ->get('/section/accounting', [UnifiedProductController::class, 'bySection']);
    Route::middleware('permission:unified-products.section.procurement')
        ->get('/section/procurement', [UnifiedProductController::class, 'bySection']);

    // Variants
    Route::prefix('variants')->group(function () {
        Route::middleware('permission:unified-products.variants.index')
            ->get('/', [UnifiedVariantController::class, 'index']);
        Route::middleware('permission:unified-products.variants.store')
            ->post('/', [UnifiedVariantController::class, 'store']);
        Route::middleware('permission:unified-products.variants.show')
            ->get('/{id}', [UnifiedVariantController::class, 'show']);
        Route::middleware('permission:unified-products.variants.update')
            ->put('/{id}', [UnifiedVariantController::class, 'update']);
        Route::middleware('permission:unified-products.variants.destroy')
            ->delete('/{id}', [UnifiedVariantController::class, 'destroy']);
    });

    // Prices
    Route::prefix('prices')->group(function () {
        Route::middleware('permission:unified-products.prices.index')
            ->get('/', [UnifiedPriceController::class, 'index']);
        Route::middleware('permission:unified-products.prices.store')
            ->post('/', [UnifiedPriceController::class, 'store']);
        Route::middleware('permission:unified-products.prices.update')
            ->put('/{id}', [UnifiedPriceController::class, 'update']);
        Route::middleware('permission:unified-products.prices.destroy')
            ->delete('/{id}', [UnifiedPriceController::class, 'destroy']);
        Route::middleware('permission:unified-products.prices.history')
            ->get('/variant/{variantId}/history', [UnifiedPriceController::class, 'history']);
    });

    // Client Prices
    Route::prefix('client-prices')->group(function () {
        Route::apiResource('/', UnifiedClientPriceController::class)
            ->middleware('permission:unified-products.client-prices.*');
    });

    // Supplier Prices
    Route::prefix('supplier-prices')->group(function () {
        Route::apiResource('/', UnifiedSupplierPriceController::class)
            ->middleware('permission:unified-products.supplier-prices.*');
    });

    // Reports
    Route::prefix('reports')->middleware('permission:unified-products.reports.*')->group(function () {
        Route::get('product-list', [UnifiedProductReportController::class, 'productList']);
        Route::get('price-list', [UnifiedProductReportController::class, 'priceList']);
        Route::get('stock-value', [UnifiedProductReportController::class, 'stockValue']);
        Route::get('price-history', [UnifiedProductReportController::class, 'priceHistory']);
    });
});

// Materials
Route::prefix('v2/materials')->middleware(['auth:sanctum'])->group(function () {
    Route::middleware('permission:unified-products.materials.index')
        ->get('/', [UnifiedMaterialController::class, 'index']);
    Route::middleware('permission:unified-products.materials.store')
        ->post('/', [UnifiedMaterialController::class, 'store']);
    Route::middleware('permission:unified-products.materials.show')
        ->get('/{id}', [UnifiedMaterialController::class, 'show']);
    Route::middleware('permission:unified-products.materials.update')
        ->put('/{id}', [UnifiedMaterialController::class, 'update']);
    Route::middleware('permission:unified-products.materials.destroy')
        ->delete('/{id}', [UnifiedMaterialController::class, 'destroy']);
    Route::middleware('permission:unified-products.materials.import')
        ->post('/import', [UnifiedMaterialController::class, 'import']);
    Route::middleware('permission:unified-products.materials.export')
        ->get('/export', [UnifiedMaterialController::class, 'export']);

    // Type filtering
    Route::get('/type/construction', [UnifiedMaterialController::class, 'construction']);
    Route::get('/type/bom', [UnifiedMaterialController::class, 'bom']);
    Route::get('/low-stock', [UnifiedMaterialController::class, 'lowStock']);
});

// BOM
Route::prefix('v2/bom')->middleware(['auth:sanctum'])->group(function () {
    Route::middleware('permission:unified-products.bom.index')
        ->get('/variant/{variantId}', [UnifiedBomController::class, 'index']);
    Route::middleware('permission:unified-products.bom.store')
        ->post('/variant/{variantId}', [UnifiedBomController::class, 'store']);
    Route::middleware('permission:unified-products.bom.update')
        ->put('/{id}', [UnifiedBomController::class, 'update']);
    Route::middleware('permission:unified-products.bom.destroy')
        ->delete('/{id}', [UnifiedBomController::class, 'destroy']);
    Route::middleware('permission:unified-products.bom.calculate-cost')
        ->get('/variant/{variantId}/cost', [UnifiedBomController::class, 'calculateCost']);
});
```

#### 6.4.2 Create Backward Compatible Routes (Deprecated)

**File:** `routes/apis/ProductsLegacy.php`

```
Tasks:
- [ ] Create deprecated routes for Sales Products that redirect to new endpoints
- [ ] Create deprecated routes for Construction Materials that redirect to new endpoints
- [ ] Add deprecation headers to responses
- [ ] Log usage of deprecated endpoints
```

---

## Phase 7: Event System Integration

### 7.1 Create Unified Events

#### 7.1.1 Create Product Events

**Files:**
- `app/Domains/Catalog/Products/Events/ProductCreated.php`
- `app/Domains/Catalog/Products/Events/ProductUpdated.php`
- `app/Domains/Catalog/Products/Events/ProductDeleted.php`
- `app/Domains/Catalog/Products/Events/VariantCreated.php`
- `app/Domains/Catalog/Products/Events/VariantUpdated.php`
- `app/Domains/Catalog/Products/Events/PriceChanged.php`
- `app/Domains/Catalog/Products/Events/MaterialCreated.php`
- `app/Domains/Catalog/Products/Events/MaterialUpdated.php`
- `app/Domains/Catalog/Products/Events/BomUpdated.php`

```
Tasks:
- [ ] Create event classes with required properties
- [ ] Include company_id in all events
- [ ] Include user_id for audit trail
- [ ] Include old/new values for price changes
```

### 7.2 Create/Update Event Listeners

#### 7.2.1 Price History Listeners

**Files:**
- `app/Domains/Catalog/Products/Listeners/RecordPriceHistoryListener.php`

```
Tasks:
- [ ] Create listener for price history recording
- [ ] Store old and new price values
- [ ] Store user who made the change
```

#### 7.2.2 Stock Integration Listeners

**Files:**
- `app/Domains/Catalog/Products/Listeners/InitializeVariantStockListener.php`

```
Tasks:
- [ ] Create listener for initializing stock when variant is created
- [ ] Use initial_stock_level from variant
```

#### 7.2.3 Accounting Integration Listeners

**Files:**
- `app/Domains/Catalog/Products/Listeners/CreateProductAccountsListener.php`

```
Tasks:
- [ ] Create listener for creating Chart of Account entries
- [ ] Create revenue account if needed
- [ ] Create expense account if needed
- [ ] Create inventory account if needed
- [ ] Create COGS account if needed
```

### 7.3 Register Events and Listeners

#### 7.3.1 Update EventServiceProvider

**File:** `app/Providers/EventServiceProvider.php` (or domain-specific provider)

```
Tasks:
- [ ] Register all new events with listeners
- [ ] Register price history listeners
- [ ] Register stock integration listeners
- [ ] Register accounting integration listeners
```

---

## Phase 8: Data Migration

### 8.1 Create Data Migration Scripts

#### 8.1.1 Create Sales Product Migration Command

**File:** `app/Console/Commands/MigrateSalesProductsCommand.php`

```
Tasks:
- [ ] Create Artisan command
- [ ] Implement product data migration logic:
  - Read from sales_products
  - Map fields to catalog_products
  - Set is_simple_product = true
  - Create default variant for each product
  - Map product code to variant SKU
  - Log migration progress
- [ ] Add dry-run option
- [ ] Add rollback capability
```

#### 8.1.2 Create Sales Price Migration Command

**File:** `app/Console/Commands/MigrateSalesPricesCommand.php`

```
Tasks:
- [ ] Create Artisan command
- [ ] Implement price data migration logic:
  - Read from sales_product_prices
  - Map to catalog_product_variant_prices
  - Link to migrated variants
  - Create default price type if needed
  - Log migration progress
- [ ] Add dry-run option
- [ ] Add rollback capability
```

#### 8.1.3 Create Sales Price History Migration Command

**File:** `app/Console/Commands/MigrateSalesPriceHistoryCommand.php`

```
Tasks:
- [ ] Create Artisan command
- [ ] Implement price history migration logic:
  - Read from product_price_histories
  - Map to catalog_product_price_audits
  - Preserve timestamps and values
  - Log migration progress
- [ ] Add dry-run option
- [ ] Add rollback capability
```

#### 8.1.4 Create Construction Material Migration Command

**File:** `app/Console/Commands/MigrateConstructionMaterialsCommand.php`

```
Tasks:
- [ ] Create Artisan command
- [ ] Implement material data migration logic:
  - Read from materials
  - Map to unified catalog_materials
  - Set material_type = 'construction'
  - Preserve supplier relationships
  - Log migration progress
- [ ] Add dry-run option
- [ ] Add rollback capability
```

#### 8.1.5 Create Catalog Material Migration Command

**File:** `app/Console/Commands/MigrateCatalogMaterialsCommand.php`

```
Tasks:
- [ ] Create Artisan command
- [ ] Implement catalog material migration logic:
  - Read from existing catalog_materials
  - Add company_id
  - Set material_type = 'bom'
  - Log migration progress
- [ ] Add dry-run option
- [ ] Add rollback capability
```

#### 8.1.6 Create Client Product Migration Command

**File:** `app/Console/Commands/MigrateClientProductsCommand.php`

```
Tasks:
- [ ] Create Artisan command
- [ ] Implement client product migration logic:
  - Read from client_products
  - Map to catalog_client_product_prices
  - Link to migrated products/variants
  - Log migration progress
- [ ] Add dry-run option
- [ ] Add rollback capability
```

### 8.2 Create Migration Mapping Tables

#### 8.2.1 Create Product Mapping Table Migration

**File:** `database/migrations/YYYY_MM_DD_XXXXXX_create_product_migration_map_table.php`

```
Tasks:
- [ ] Create table with columns:
  - id
  - entity_type (product, variant, price, material)
  - source_system (sales, construction, catalog)
  - old_table
  - old_id
  - new_table
  - new_id
  - migrated_at
  - status
```

### 8.3 Create Verification Commands

#### 8.3.1 Create Product Data Verification Command

**File:** `app/Console/Commands/VerifyProductMigrationCommand.php`

```
Tasks:
- [ ] Create Artisan command
- [ ] Implement verification logic:
  - Compare row counts
  - Compare product totals
  - Compare price totals
  - Check foreign key integrity
  - Verify variant creation
  - Report discrepancies
```

---

## Phase 9: Financial Integration

### 9.1 Tax Integration

#### 9.1.1 Create Product Tax Service

**File:** `app/Domains/Catalog/Products/Services/ProductTaxService.php`

```
Tasks:
- [ ] Create service for tax calculations
- [ ] Implement getSaleTax() method
- [ ] Implement getPurchaseTax() method
- [ ] Implement calculateTaxAmount() method
- [ ] Support variant-level and product-level tax
```

### 9.2 ChartOfAccount Integration

#### 9.2.1 Create Product Account Service

**File:** `app/Domains/Catalog/Products/Services/ProductAccountService.php`

```
Tasks:
- [ ] Create service for ChartOfAccount operations
- [ ] Implement createAccountsForProduct() method
- [ ] Implement updateAccountsForProduct() method
- [ ] Handle revenue, expense, inventory, COGS accounts
- [ ] Use proper account types and hierarchies
```

### 9.3 Invoice Integration

#### 9.3.1 Update Sales Invoice Integration

```
Tasks:
- [ ] Update SalesInvoiceProduct to work with variants
- [ ] Add variant_id to sales invoice products
- [ ] Update price lookup to use variant prices
- [ ] Update stock management to use variant stock
```

#### 9.3.2 Update Purchase Invoice Integration

```
Tasks:
- [ ] Update PurchaseProduct to work with variants
- [ ] Add variant_id to purchase products
- [ ] Update price lookup to use variant prices
- [ ] Update stock management to use variant stock
```

### 9.4 Update Financial Reports

#### 9.4.1 Modify Existing Report Queries

```
Tasks:
- [ ] Update product sales reports to use new tables
- [ ] Update purchase reports to use new tables
- [ ] Update inventory valuation reports to use new tables
- [ ] Update profit margin reports to use new tables
- [ ] Verify report accuracy with test data
```

---

## Phase 10: Testing & Validation

### 10.1 Unit Tests

#### 10.1.1 Model Tests

**Files:**
- `tests/Unit/Domains/Catalog/Products/Models/ProductTest.php`
- `tests/Unit/Domains/Catalog/Products/Models/ProductVariantTest.php`
- `tests/Unit/Domains/Catalog/Products/Models/ProductVariantPriceTest.php`
- `tests/Unit/Domains/Catalog/Products/Models/MaterialTest.php`

```
Tasks:
- [ ] Test company scoping
- [ ] Test relationships
- [ ] Test accessors/mutators
- [ ] Test code generation
- [ ] Test simple product handling
- [ ] Test section scoping
```

#### 10.1.2 Service Tests

**Files:**
- `tests/Unit/Domains/Catalog/Products/Services/UnifiedProductServiceTest.php`
- `tests/Unit/Domains/Catalog/Products/Services/UnifiedMaterialServiceTest.php`
- `tests/Unit/Domains/Catalog/Products/Services/PriceServiceTest.php`

```
Tasks:
- [ ] Test all service methods
- [ ] Test error handling
- [ ] Test transaction rollbacks
- [ ] Test event dispatching
- [ ] Test auto variant creation
```

### 10.2 Feature Tests

#### 10.2.1 API Tests

**Files:**
- `tests/Feature/Domains/Catalog/Products/ProductApiTest.php`
- `tests/Feature/Domains/Catalog/Products/VariantApiTest.php`
- `tests/Feature/Domains/Catalog/Products/PriceApiTest.php`
- `tests/Feature/Domains/Catalog/Products/MaterialApiTest.php`
- `tests/Feature/Domains/Catalog/Products/BomApiTest.php`

```
Tasks:
- [ ] Test all API endpoints
- [ ] Test permission middleware
- [ ] Test validation rules
- [ ] Test response formats
- [ ] Test section-based access
```

### 10.3 Integration Tests

#### 10.3.1 Financial Integration Tests

**File:** `tests/Integration/Products/AccountingIntegrationTest.php`

```
Tasks:
- [ ] Test ChartOfAccount creation
- [ ] Test tax calculations
- [ ] Test invoice integration
```

#### 10.3.2 Migration Tests

**File:** `tests/Integration/Products/MigrationTest.php`

```
Tasks:
- [ ] Test data migration accuracy
- [ ] Test rollback capability
- [ ] Test verification commands
- [ ] Test variant creation for simple products
```

### 10.4 Create Test Data Factories

```
Tasks:
- [ ] Update ProductFactory
- [ ] Update VariantFactory
- [ ] Update PriceFactory
- [ ] Update MaterialFactory
- [ ] Create SimpleProductFactory
- [ ] Create ClientPriceFactory
- [ ] Create SupplierPriceFactory
```

---

## Phase 11: Cleanup & Deprecation

### 11.1 Mark Deprecated Code

#### 11.1.1 Add Deprecation Notices

```
Tasks:
- [ ] Add @deprecated annotations to old models:
  - Accounting\Sales\Models\Product
  - Accounting\Sales\Models\ProductPrice
  - Accounting\Sales\Models\ProductPriceHistory
  - Construction\Material\Models\Material
- [ ] Add @deprecated annotations to old services:
  - Accounting\Sales\Services\ProductServices
  - Accounting\Sales\Services\ProductPriceServices
  - Accounting\Sales\Services\ClientProductServices
  - Construction\Material\Services\MaterialServices
- [ ] Add @deprecated annotations to old controllers:
  - Accounting\Sales\Controllers\ProductController
  - Accounting\Sales\Controllers\ProductPriceController
  - Construction\Material\Controllers\MaterialController
```

#### 11.1.2 Create Deprecation Logger

**File:** `app/Support/ProductDeprecationLogger.php`

```
Tasks:
- [ ] Create logger for deprecated code usage
- [ ] Log file/line where deprecated code is called
- [ ] Create daily report of deprecation usage
```

### 11.2 Update Documentation

#### 11.2.1 API Documentation

```
Tasks:
- [ ] Update API documentation with new endpoints
- [ ] Mark old endpoints as deprecated
- [ ] Add migration guide for API consumers
- [ ] Document simple product vs variant product patterns
```

#### 11.2.2 Internal Documentation

```
Tasks:
- [ ] Update this plan with completion status
- [ ] Create architecture decision record (ADR)
- [ ] Update system diagrams
- [ ] Document the unified product model
```

### 11.3 Final Cleanup (Post-Migration Verification)

#### 11.3.1 Remove Deprecated Code (Future Phase)

```
Tasks (to be done after 30+ days of successful operation):
- [ ] Remove Accounting\Sales\Models\Product model
- [ ] Remove Accounting\Sales\Models\ProductPrice model
- [ ] Remove Accounting\Sales\Models\ProductPriceHistory model
- [ ] Remove Construction\Material\Models\Material model
- [ ] Remove old services
- [ ] Remove old controllers
- [ ] Remove old routes
- [ ] Drop deprecated tables
```

---

## Appendix A: File Checklist

### New Files to Create

| File | Phase | Status |
|------|-------|--------|
| `database/migrations/YYYY_add_company_id_to_catalog_products.php` | 1.1.1 | [ ] |
| `database/migrations/YYYY_add_sales_fields_to_catalog_products.php` | 1.1.2 | [ ] |
| `database/migrations/YYYY_add_accounting_fields_to_catalog_products.php` | 1.1.3 | [ ] |
| `database/migrations/YYYY_add_company_id_to_catalog_product_variants.php` | 1.2.1 | [ ] |
| `database/migrations/YYYY_add_sales_fields_to_catalog_product_variants.php` | 1.2.2 | [ ] |
| `database/migrations/YYYY_add_company_id_to_catalog_materials.php` | 1.3.1 | [ ] |
| `database/migrations/YYYY_add_construction_fields_to_catalog_materials.php` | 1.3.2 | [ ] |
| `database/migrations/YYYY_add_company_id_to_catalog_product_variant_prices.php` | 1.4.1 | [ ] |
| `database/migrations/YYYY_add_company_id_to_catalog_product_variant_units.php` | 1.4.2 | [ ] |
| `database/migrations/YYYY_add_company_id_to_catalog_product_variant_materials.php` | 1.4.3 | [ ] |
| `database/migrations/YYYY_add_company_id_to_catalog_product_images.php` | 1.4.4 | [ ] |
| `database/migrations/YYYY_add_company_id_to_catalog_product_aliases.php` | 1.4.5 | [ ] |
| `database/migrations/YYYY_add_company_id_to_catalog_client_product_prices.php` | 1.4.6 | [ ] |
| `database/migrations/YYYY_add_company_id_to_catalog_supplier_product_prices.php` | 1.4.7 | [ ] |
| `database/seeders/UnifiedProductPermissionSeeder.php` | 2.1.1 | [ ] |
| `database/migrations/YYYY_add_unified_product_permissions.php` | 2.1.2 | [ ] |
| `app/Domains/Catalog/Products/Enums/ProductSection.php` | 3.1.2 | [ ] |
| `app/Domains/Catalog/Products/Observers/ProductObserver.php` | 3.1.3 | [ ] |
| `app/Domains/Catalog/Products/Enums/MaterialType.php` | 3.4.2 | [ ] |
| `app/Domains/Accounting/Sales/Models/ProductBridge.php` | 3.5.1 | [ ] |
| `app/Domains/Construction/Material/Models/MaterialBridge.php` | 3.5.2 | [ ] |
| `app/Domains/Accounting/Sales/Models/ProductPriceBridge.php` | 3.5.3 | [ ] |
| `app/Domains/Catalog/Products/Contracts/UnifiedProductServiceInterface.php` | 4.1.1 | [ ] |
| `app/Domains/Catalog/Products/Services/UnifiedProductService.php` | 4.1.2 | [ ] |
| `app/Domains/Catalog/Products/Contracts/UnifiedMaterialServiceInterface.php` | 4.2.1 | [ ] |
| `app/Domains/Catalog/Products/Services/UnifiedMaterialService.php` | 4.2.2 | [ ] |
| `app/Domains/Catalog/Products/Contracts/MaterialRepositoryContract.php` | 5.3.2 | [ ] |
| `app/Domains/Catalog/Products/Repositories/MaterialRepository.php` | 5.3.1 | [ ] |
| `app/Domains/Catalog/Products/Repositories/PriceRepository.php` | 5.4.1 | [ ] |
| `app/Domains/Catalog/Products/Controllers/V2/UnifiedProductController.php` | 6.1.1 | [ ] |
| `app/Domains/Catalog/Products/Controllers/V2/UnifiedVariantController.php` | 6.1.2 | [ ] |
| `app/Domains/Catalog/Products/Controllers/V2/UnifiedPriceController.php` | 6.1.3 | [ ] |
| `app/Domains/Catalog/Products/Controllers/V2/UnifiedClientPriceController.php` | 6.1.4 | [ ] |
| `app/Domains/Catalog/Products/Controllers/V2/UnifiedSupplierPriceController.php` | 6.1.5 | [ ] |
| `app/Domains/Catalog/Products/Controllers/V2/UnifiedMaterialController.php` | 6.1.6 | [ ] |
| `app/Domains/Catalog/Products/Controllers/V2/UnifiedBomController.php` | 6.1.7 | [ ] |
| `app/Domains/Catalog/Products/Controllers/V2/UnifiedProductReportController.php` | 6.1.8 | [ ] |
| `app/Domains/Catalog/Products/Requests/V2/*.php` | 6.2.* | [ ] |
| `app/Domains/Catalog/Products/Resources/V2/*.php` | 6.3.* | [ ] |
| `routes/apis/UnifiedProducts.php` | 6.4.1 | [ ] |
| `routes/apis/ProductsLegacy.php` | 6.4.2 | [ ] |
| `app/Domains/Catalog/Products/Events/*.php` | 7.1.* | [ ] |
| `app/Domains/Catalog/Products/Listeners/RecordPriceHistoryListener.php` | 7.2.1 | [ ] |
| `app/Domains/Catalog/Products/Listeners/InitializeVariantStockListener.php` | 7.2.2 | [ ] |
| `app/Domains/Catalog/Products/Listeners/CreateProductAccountsListener.php` | 7.2.3 | [ ] |
| `app/Console/Commands/MigrateSalesProductsCommand.php` | 8.1.1 | [ ] |
| `app/Console/Commands/MigrateSalesPricesCommand.php` | 8.1.2 | [ ] |
| `app/Console/Commands/MigrateSalesPriceHistoryCommand.php` | 8.1.3 | [ ] |
| `app/Console/Commands/MigrateConstructionMaterialsCommand.php` | 8.1.4 | [ ] |
| `app/Console/Commands/MigrateCatalogMaterialsCommand.php` | 8.1.5 | [ ] |
| `app/Console/Commands/MigrateClientProductsCommand.php` | 8.1.6 | [ ] |
| `database/migrations/YYYY_create_product_migration_map_table.php` | 8.2.1 | [ ] |
| `app/Console/Commands/VerifyProductMigrationCommand.php` | 8.3.1 | [ ] |
| `app/Domains/Catalog/Products/Services/ProductTaxService.php` | 9.1.1 | [ ] |
| `app/Domains/Catalog/Products/Services/ProductAccountService.php` | 9.2.1 | [ ] |
| `tests/Unit/Domains/Catalog/Products/Models/*.php` | 10.1.1 | [ ] |
| `tests/Unit/Domains/Catalog/Products/Services/*.php` | 10.1.2 | [ ] |
| `tests/Feature/Domains/Catalog/Products/*.php` | 10.2.* | [ ] |
| `tests/Integration/Products/*.php` | 10.3.* | [ ] |
| `app/Support/ProductDeprecationLogger.php` | 11.1.2 | [ ] |

### Files to Modify

| File | Phase | Status |
|------|-------|--------|
| `app/Domains/Catalog/Products/Models/Product.php` | 3.1.1 | [ ] |
| `app/Domains/Catalog/Products/Models/ProductVariant.php` | 3.2.1 | [ ] |
| `app/Domains/Catalog/Products/Models/ProductVariantPrice.php` | 3.3.1 | [ ] |
| `app/Domains/Catalog/Products/Models/Material.php` | 3.4.1 | [ ] |
| `app/Domains/Catalog/Products/Services/ProductService.php` | 4.5.1 | [ ] |
| `app/Domains/Catalog/Products/Services/VariantService.php` | 4.5.2 | [ ] |
| `app/Domains/Catalog/Products/Services/PriceService.php` | 4.5.3 | [ ] |
| `app/Domains/Catalog/Products/Repositories/ProductRepository.php` | 5.1.1 | [ ] |
| `app/Domains/Catalog/Products/Repositories/VariantRepository.php` | 5.2.1 | [ ] |
| `app/Domains/Catalog/Products/Contracts/ProductRepositoryContract.php` | 5.1.2 | [ ] |
| `app/Domains/Catalog/Products/Contracts/VariantRepositoryContract.php` | 5.2.2 | [ ] |
| `app/Providers/EventServiceProvider.php` | 7.3.1 | [ ] |

### Files to Deprecate (Mark, Don't Delete)

| File | Phase | Status |
|------|-------|--------|
| `app/Domains/Accounting/Sales/Models/Product.php` | 11.1.1 | [ ] |
| `app/Domains/Accounting/Sales/Models/ProductPrice.php` | 11.1.1 | [ ] |
| `app/Domains/Accounting/Sales/Models/ProductPriceHistory.php` | 11.1.1 | [ ] |
| `app/Domains/Construction/Material/Models/Material.php` | 11.1.1 | [ ] |
| `app/Domains/Accounting/Sales/Services/ProductServices.php` | 11.1.1 | [ ] |
| `app/Domains/Accounting/Sales/Services/ProductPriceServices.php` | 11.1.1 | [ ] |
| `app/Domains/Accounting/Sales/Services/ClientProductServices.php` | 11.1.1 | [ ] |
| `app/Domains/Construction/Material/Services/MaterialServices.php` | 11.1.1 | [ ] |
| `app/Domains/Accounting/Sales/Controllers/V1/ProductController.php` | 11.1.1 | [ ] |
| `app/Domains/Accounting/Sales/Controllers/V1/ProductPriceController.php` | 11.1.1 | [ ] |
| `app/Domains/Construction/Material/Controllers/V1/MaterialController.php` | 11.1.1 | [ ] |

---

## Appendix B: Database Schema Changes Summary

### Tables to Add Columns

| Table | New Columns |
|-------|------------|
| `catalog_products` | company_id, code, section, category_id, tax_id, purchase_tax_id, cost_center_id, user_id, is_simple_product, type, purchase_account_id |
| `catalog_product_variants` | company_id, track_stock, initial_stock_level, min_qty, is_returnable, discount_amount, discount_type, is_taxable, sale_tax, purchase_tax, tags, barcode_type, barcode_path |
| `catalog_materials` | company_id, material_type, length, width, height, weight, manufacture_material, unit_price, selling_price, profit_margin_type, profit_margin, final_cost, current_stock, store_id, material_category_id, primary_supplier_id, currency_code, exchange_rate, tax_rate, reorder_level, max_stock, lead_time, time_unit, expiration_date, custom_fields, qr_code_value |
| `catalog_product_variant_prices` | company_id, purchasing_price, selling_price, min_selling_price |
| `catalog_product_variant_units` | company_id |
| `catalog_product_variant_materials` | company_id |
| `catalog_product_images` | company_id |
| `catalog_product_aliases` | company_id |
| `catalog_client_product_prices` | company_id |
| `catalog_supplier_product_prices` | company_id |

### New Tables

| Table | Purpose |
|-------|---------|
| `product_migration_map` | Track migration of records from old to new tables |

---

## Appendix C: Permission Mapping Reference

| Category | Old Permission (Sales) | Old Permission (Construction) | Old Permission (Catalog) | New Unified Permission |
|----------|------------------------|------------------------------|--------------------------|------------------------|
| Products | products.index | - | catalog.products.view | unified-products.products.index |
| Products | products.show | - | catalog.products.view | unified-products.products.show |
| Products | products.store | - | catalog.products.create | unified-products.products.store |
| Products | products.update | - | catalog.products.edit | unified-products.products.update |
| Products | products.destroy | - | catalog.products.delete | unified-products.products.destroy |
| Variants | - | - | catalog.variants.* | unified-products.variants.* |
| Prices | product-prices.index | - | catalog.prices.view | unified-products.prices.index |
| Prices | product-prices.store | - | catalog.prices.create | unified-products.prices.store |
| Prices | product-prices.update | - | catalog.prices.edit | unified-products.prices.update |
| Client Prices | client-products.* | - | catalog.client-prices.* | unified-products.client-prices.* |
| Materials | - | materials.index | catalog.materials.view | unified-products.materials.index |
| Materials | - | materials.store | catalog.materials.create | unified-products.materials.store |
| Materials | - | materials.update | catalog.materials.edit | unified-products.materials.update |
| Materials | - | materials.destroy | catalog.materials.delete | unified-products.materials.destroy |
| Supplier Prices | - | supplier-materials.* | catalog.supplier-prices.* | unified-products.supplier-prices.* |

---

## Appendix D: Simple Product Migration Example

### Sales Product → Catalog Product + Variant

**Sales Product (Before):**
```php
{
  id: 1,
  company_id: 1,
  name: "Widget A",
  code: "ITM-0001-01",
  status: true,
  section: "accounting",
  track_stock: true,
  initial_stock_level: 100,
  category_id: 5,
  tax_id: 2
}
```

**Sales ProductPrice (Before):**
```php
{
  id: 1,
  company_id: 1,
  product_id: 1,
  unit_id: 3,
  purchasing_price: 10.00,
  selling_price: 15.00,
  min_selling_price: 12.00,
  is_main_price: true
}
```

**Migrated Catalog Product (After):**
```php
{
  id: 1001,
  company_id: 1,
  canonical_name: {"en": "Widget A", "ar": "Widget A"},
  code: "ITM-0001-01",
  status: "active",
  section: "accounting",
  category_id: 5,
  tax_id: 2,
  is_simple_product: true
}
```

**Migrated Catalog ProductVariant (After):**
```php
{
  id: 2001,
  company_id: 1,
  product_id: 1001,
  sku: "ITM-0001-01",
  track_stock: true,
  initial_stock_level: 100,
  is_preferred: true
}
```

**Migrated Catalog ProductVariantPrice (After):**
```php
{
  id: 3001,
  company_id: 1,
  variant_id: 2001,
  unit_id: 3,
  price_type_id: 1, // Default price type
  purchasing_price: 10.00,
  selling_price: 15.00,
  min_selling_price: 12.00,
  is_main_price: true
}
```

---

*Document Version: 1.0*
*Last Updated: 2026-02-14*
