ultimatepos/Modules/IndustrialEngineering/Domain/IndustrialDomainRegistry.php

523 lines
25 KiB
PHP
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?php
namespace Modules\IndustrialEngineering\Domain;
/**
* Canonical registry of every Industrial Engineering entity, its table,
* bounded context, and cross-module integration boundaries.
*
* This is the single source of truth for the digital-thread domain model.
* Migrations in Database/Migrations must stay aligned with this registry.
*/
final class IndustrialDomainRegistry
{
/**
* @return array<string, array{
* table: string,
* model: class-string|null,
* context: string,
* aggregate_root: bool,
* description: string
* }>
*/
public static function entities(): array
{
return [
// ── Master Data ──────────────────────────────────────────────
'manufacturer' => [
'table' => 'ie_manufacturers',
'model' => \Modules\IndustrialEngineering\Models\Manufacturer::class,
'context' => BoundedContext::MASTER_DATA,
'aggregate_root' => true,
'description' => 'Approved manufacturer / OEM catalog entry.',
],
'supplier' => [
'table' => 'ie_suppliers',
'model' => \Modules\IndustrialEngineering\Models\Supplier::class,
'context' => BoundedContext::MASTER_DATA,
'aggregate_root' => true,
'description' => 'Approved vendor; may link to contacts or intercompany business.',
],
'item_master' => [
'table' => 'ie_item_masters',
'model' => \Modules\IndustrialEngineering\Models\ItemMaster::class,
'context' => BoundedContext::MASTER_DATA,
'aggregate_root' => true,
'description' => 'Canonical industrial item (part, assembly, device, etc.).',
],
'item_revision' => [
'table' => 'ie_item_revisions',
'model' => \Modules\IndustrialEngineering\Models\ItemRevision::class,
'context' => BoundedContext::MASTER_DATA,
'aggregate_root' => false,
'description' => 'Versioned engineering definition of an item master.',
],
'supplier_part_number' => [
'table' => 'ie_supplier_part_numbers',
'model' => \Modules\IndustrialEngineering\Models\SupplierPartNumber::class,
'context' => BoundedContext::MASTER_DATA,
'aggregate_root' => false,
'description' => 'AVL/AML supplier part number and commercial terms.',
],
'part_equivalent' => [
'table' => 'ie_part_equivalents',
'model' => \Modules\IndustrialEngineering\Models\PartEquivalent::class,
'context' => BoundedContext::MASTER_DATA,
'aggregate_root' => false,
'description' => 'Approved alternate items (form-fit-function, functional, upgrade).',
],
'item_classification' => [
'table' => 'ie_item_classifications',
'model' => \Modules\IndustrialEngineering\Models\ItemClassification::class,
'context' => BoundedContext::MASTER_DATA,
'aggregate_root' => false,
'description' => 'Taxonomy mapping to industrial category seeders.',
],
// ── BOM & Configuration ──────────────────────────────────────
'product_platform' => [
'table' => 'ie_product_platforms',
'model' => \Modules\IndustrialEngineering\Models\ProductPlatform::class,
'context' => BoundedContext::BOM_CONFIGURATION,
'aggregate_root' => true,
'description' => 'Product / production-line family.',
],
'line_template' => [
'table' => 'ie_line_templates',
'model' => \Modules\IndustrialEngineering\Models\LineTemplate::class,
'context' => BoundedContext::BOM_CONFIGURATION,
'aggregate_root' => false,
'description' => 'Configurable line or machine template within a platform.',
],
'line_revision' => [
'table' => 'ie_line_revisions',
'model' => \Modules\IndustrialEngineering\Models\LineRevision::class,
'context' => BoundedContext::BOM_CONFIGURATION,
'aggregate_root' => true,
'description' => 'Official approved/released version of a line template.',
],
'bom' => [
'table' => 'ie_boms',
'model' => \Modules\IndustrialEngineering\Models\Bom::class,
'context' => BoundedContext::BOM_CONFIGURATION,
'aggregate_root' => true,
'description' => 'EBOM, MBOM, or SBOM header (distinct but linked by line revision).',
],
'bom_line' => [
'table' => 'ie_bom_lines',
'model' => \Modules\IndustrialEngineering\Models\BomLine::class,
'context' => BoundedContext::BOM_CONFIGURATION,
'aggregate_root' => false,
'description' => 'Multi-level BOM line with alternates, costing, and routing refs.',
],
'bom_line_alternate' => [
'table' => 'ie_bom_line_alternates',
'model' => \Modules\IndustrialEngineering\Models\BomLineAlternate::class,
'context' => BoundedContext::BOM_CONFIGURATION,
'aggregate_root' => false,
'description' => 'Approved substitute within an alternate group.',
],
'bom_change_request' => [
'table' => 'ie_bom_change_requests',
'model' => \Modules\IndustrialEngineering\Models\BomChangeRequest::class,
'context' => BoundedContext::BOM_CONFIGURATION,
'aggregate_root' => true,
'description' => 'ECR engineering change request.',
],
'bom_change_order' => [
'table' => 'ie_bom_change_orders',
'model' => \Modules\IndustrialEngineering\Models\BomChangeOrder::class,
'context' => BoundedContext::BOM_CONFIGURATION,
'aggregate_root' => true,
'description' => 'ECO approved implementation of a change request.',
],
'bom_effectivity' => [
'table' => 'ie_bom_effectivities',
'model' => \Modules\IndustrialEngineering\Models\BomEffectivity::class,
'context' => BoundedContext::BOM_CONFIGURATION,
'aggregate_root' => false,
'description' => 'Effectivity rules (date, serial, customer, project, revision).',
],
// ── Costing & Release ────────────────────────────────────────
'work_center' => [
'table' => 'ie_work_centers',
'model' => \Modules\IndustrialEngineering\Models\WorkCenter::class,
'context' => BoundedContext::COSTING_RELEASE,
'aggregate_root' => true,
'description' => 'Machine/labor/overhead rates for routing.',
],
'routing_operation' => [
'table' => 'ie_routing_operations',
'model' => \Modules\IndustrialEngineering\Models\RoutingOperation::class,
'context' => BoundedContext::COSTING_RELEASE,
'aggregate_root' => false,
'description' => 'Sequence of operations for a line revision.',
],
'cost_scenario' => [
'table' => 'ie_cost_scenarios',
'model' => \Modules\IndustrialEngineering\Models\CostScenario::class,
'context' => BoundedContext::COSTING_RELEASE,
'aggregate_root' => true,
'description' => 'What-if or baseline cost rollup for a BOM/line revision.',
],
'cost_scenario_line' => [
'table' => 'ie_cost_scenario_lines',
'model' => \Modules\IndustrialEngineering\Models\CostScenarioLine::class,
'context' => BoundedContext::COSTING_RELEASE,
'aggregate_root' => false,
'description' => 'Per-line cost with optional alternate selection.',
],
'release_package' => [
'table' => 'ie_release_packages',
'model' => \Modules\IndustrialEngineering\Models\ReleasePackage::class,
'context' => BoundedContext::COSTING_RELEASE,
'aggregate_root' => true,
'description' => 'Locked MBOM/routing/cost snapshot approved for production.',
],
'release_signoff' => [
'table' => 'ie_release_signoffs',
'model' => \Modules\IndustrialEngineering\Models\ReleaseSignoff::class,
'context' => BoundedContext::COSTING_RELEASE,
'aggregate_root' => false,
'description' => 'Multi-discipline approval on a release package.',
],
'manufacturing_work_order' => [
'table' => 'ie_manufacturing_work_orders',
'model' => \Modules\IndustrialEngineering\Models\ManufacturingWorkOrder::class,
'context' => BoundedContext::COSTING_RELEASE,
'aggregate_root' => true,
'description' => 'Shop-floor work order with frozen BOM/routing snapshot.',
],
// ── Serialization & As-Built ─────────────────────────────────
'serial_registry' => [
'table' => 'ie_serial_registry',
'model' => \Modules\IndustrialEngineering\Models\SerialRegistry::class,
'context' => BoundedContext::SERIALIZATION,
'aggregate_root' => true,
'description' => 'Global serial/lot registry for units and components.',
],
'serialized_unit' => [
'table' => 'ie_serialized_units',
'model' => \Modules\IndustrialEngineering\Models\SerializedUnit::class,
'context' => BoundedContext::SERIALIZATION,
'aggregate_root' => true,
'description' => 'As-built unit built from a release package / work order.',
],
'serialized_unit_component' => [
'table' => 'ie_serialized_unit_components',
'model' => \Modules\IndustrialEngineering\Models\SerializedUnitComponent::class,
'context' => BoundedContext::SERIALIZATION,
'aggregate_root' => false,
'description' => 'Installed component genealogy (serial, brand, warranty).',
],
'build_genealogy_event' => [
'table' => 'ie_build_genealogy_events',
'model' => \Modules\IndustrialEngineering\Models\BuildGenealogyEvent::class,
'context' => BoundedContext::SERIALIZATION,
'aggregate_root' => false,
'description' => 'Immutable audit event during build or QC.',
],
// ── Installed Base ───────────────────────────────────────────
'customer_installed_asset' => [
'table' => 'ie_customer_installed_assets',
'model' => \Modules\IndustrialEngineering\Models\CustomerInstalledAsset::class,
'context' => BoundedContext::INSTALLED_BASE,
'aggregate_root' => true,
'description' => 'As-sold / as-installed customer line or device.',
],
'customer_asset_warranty' => [
'table' => 'ie_customer_asset_warranties',
'model' => \Modules\IndustrialEngineering\Models\CustomerAssetWarranty::class,
'context' => BoundedContext::INSTALLED_BASE,
'aggregate_root' => false,
'description' => 'Warranty coverage at asset or component level.',
],
'commissioning_record' => [
'table' => 'ie_commissioning_records',
'model' => \Modules\IndustrialEngineering\Models\CommissioningRecord::class,
'context' => BoundedContext::INSTALLED_BASE,
'aggregate_root' => true,
'description' => 'Commissioning checklist and handover documents.',
],
'installation_task' => [
'table' => 'ie_installation_tasks',
'model' => \Modules\IndustrialEngineering\Models\InstallationTask::class,
'context' => BoundedContext::INSTALLED_BASE,
'aggregate_root' => false,
'description' => 'Install/commission/training task on an installed asset.',
],
// ── Sourcing ─────────────────────────────────────────────────
'intercompany_stock_visibility' => [
'table' => 'ie_intercompany_stock_visibility',
'model' => \Modules\IndustrialEngineering\Models\IntercompanyStockVisibility::class,
'context' => BoundedContext::SOURCING,
'aggregate_root' => false,
'description' => 'Cached cross-company stock availability for an item.',
],
'intercompany_transfer_request' => [
'table' => 'ie_intercompany_transfer_requests',
'model' => \Modules\IndustrialEngineering\Models\IntercompanyTransferRequest::class,
'context' => BoundedContext::SOURCING,
'aggregate_root' => true,
'description' => 'Internal transfer request between holding companies.',
],
'supplier_sourcing_case' => [
'table' => 'ie_supplier_sourcing_cases',
'model' => \Modules\IndustrialEngineering\Models\SupplierSourcingCase::class,
'context' => BoundedContext::SOURCING,
'aggregate_root' => true,
'description' => 'Sourcing case when part not available in holding.',
],
'vendor_quote_comparison' => [
'table' => 'ie_vendor_quote_comparisons',
'model' => \Modules\IndustrialEngineering\Models\VendorQuoteComparison::class,
'context' => BoundedContext::SOURCING,
'aggregate_root' => false,
'description' => 'Vendor quotes ranked for a sourcing case.',
],
'procurement_task' => [
'table' => 'ie_procurement_tasks',
'model' => \Modules\IndustrialEngineering\Models\ProcurementTask::class,
'context' => BoundedContext::SOURCING,
'aggregate_root' => false,
'description' => 'Actionable procurement step (quote, PR, PO, transfer).',
],
// ── Competitive Research ─────────────────────────────────────
'research_project' => [
'table' => 'ie_research_projects',
'model' => \Modules\IndustrialEngineering\Models\ResearchProject::class,
'context' => BoundedContext::COMPETITIVE_RESEARCH,
'aggregate_root' => true,
'description' => 'R&D or competitive intelligence project.',
],
'competitive_product' => [
'table' => 'ie_competitive_products',
'model' => \Modules\IndustrialEngineering\Models\CompetitiveProduct::class,
'context' => BoundedContext::COMPETITIVE_RESEARCH,
'aggregate_root' => true,
'description' => 'Competitor product under study.',
],
'competitive_product_structure' => [
'table' => 'ie_competitive_product_structures',
'model' => \Modules\IndustrialEngineering\Models\CompetitiveProductStructure::class,
'context' => BoundedContext::COMPETITIVE_RESEARCH,
'aggregate_root' => false,
'description' => 'Multi-level teardown structure of a competitor product.',
],
'competitive_benchmark' => [
'table' => 'ie_competitive_benchmarks',
'model' => \Modules\IndustrialEngineering\Models\CompetitiveBenchmark::class,
'context' => BoundedContext::COMPETITIVE_RESEARCH,
'aggregate_root' => false,
'description' => 'Metric comparison (cost, quality, lead time) vs our line.',
],
'engineering_finding' => [
'table' => 'ie_engineering_findings',
'model' => \Modules\IndustrialEngineering\Models\EngineeringFinding::class,
'context' => BoundedContext::COMPETITIVE_RESEARCH,
'aggregate_root' => false,
'description' => 'Finding linked to research, ECR, or cost scenario.',
],
'lessons_learned' => [
'table' => 'ie_lessons_learned',
'model' => \Modules\IndustrialEngineering\Models\LessonsLearned::class,
'context' => BoundedContext::COMPETITIVE_RESEARCH,
'aggregate_root' => false,
'description' => 'Captured lesson from research or field installation.',
],
];
}
/**
* External tables owned by other modules; IE must not duplicate their data.
*
* @return array<string, array{
* module: string,
* table: string,
* mode: string,
* bridge: string|null,
* fk_columns: array<string, string>
* }>
*/
public static function externalBoundaries(): array
{
return [
'erp_product' => [
'module' => 'Core',
'table' => 'products',
'mode' => IntegrationMode::READ_REFERENCE,
'bridge' => null,
'fk_columns' => ['ie_item_masters.product_id' => 'products.id'],
],
'erp_variation' => [
'module' => 'Core',
'table' => 'variations',
'mode' => IntegrationMode::READ_REFERENCE,
'bridge' => null,
'fk_columns' => ['ie_item_masters.variation_id' => 'variations.id'],
],
'erp_contact' => [
'module' => 'Core',
'table' => 'contacts',
'mode' => IntegrationMode::READ_REFERENCE,
'bridge' => null,
'fk_columns' => [
'ie_suppliers.contact_id' => 'contacts.id',
'ie_customer_installed_assets.customer_id' => 'contacts.id',
'ie_bom_effectivities.customer_id' => 'contacts.id',
],
],
'erp_transaction' => [
'module' => 'Core',
'table' => 'transactions',
'mode' => IntegrationMode::READ_REFERENCE,
'bridge' => 'IntegrationBridgeService::linkSaleToInstalledAsset',
'fk_columns' => [
'ie_manufacturing_work_orders.production_transaction_id' => 'transactions.id',
'ie_serialized_units.production_transaction_id' => 'transactions.id',
'ie_customer_installed_assets.sell_transaction_id' => 'transactions.id',
'ie_procurement_tasks.purchase_requisition_id' => 'transactions.id',
],
],
'erp_sell_line' => [
'module' => 'Core',
'table' => 'transaction_sell_lines',
'mode' => IntegrationMode::READ_REFERENCE,
'bridge' => 'IntegrationBridgeService::linkSaleToInstalledAsset',
'fk_columns' => [
'ie_customer_installed_assets.sell_line_id' => 'transaction_sell_lines.id',
],
],
'erp_project' => [
'module' => 'Project',
'table' => 'pjt_projects',
'mode' => IntegrationMode::READ_REFERENCE,
'bridge' => null,
'fk_columns' => [
'ie_customer_installed_assets.project_id' => 'pjt_projects.id',
'ie_research_projects.project_id' => 'pjt_projects.id',
'ie_bom_effectivities.project_id' => 'pjt_projects.id',
],
],
'maintenance_equipment' => [
'module' => 'Maintenance',
'table' => 'maintenance_equipment',
'mode' => IntegrationMode::WRITE_THROUGH_BRIDGE,
'bridge' => 'IntegrationBridgeService::syncToMaintenanceEquipment',
'fk_columns' => [
'ie_customer_installed_assets.maintenance_equipment_id' => 'maintenance_equipment.id',
],
],
'maintenance_equipment_parts' => [
'module' => 'Maintenance',
'table' => 'maintenance_equipment_parts',
'mode' => IntegrationMode::WRITE_THROUGH_BRIDGE,
'bridge' => 'IntegrationBridgeService::syncComponentsToEquipmentParts',
'fk_columns' => [],
],
'maintenance_part_catalogs' => [
'module' => 'Maintenance',
'table' => 'maintenance_part_catalogs',
'mode' => IntegrationMode::WRITE_THROUGH_BRIDGE,
'bridge' => 'IntegrationBridgeService::syncComponentsToEquipmentParts',
'fk_columns' => [],
],
'mfg_recipe' => [
'module' => 'Manufacturing',
'table' => 'mfg_recipes',
'mode' => IntegrationMode::IMPORT_BRIDGE,
'bridge' => 'IntegrationBridgeService::importMfgRecipeToMbom',
'fk_columns' => [],
],
'asset_exchange_listing' => [
'module' => 'AssetExchange',
'table' => 'aex_listings',
'mode' => IntegrationMode::READ_REFERENCE,
'bridge' => 'AssetExchangeIeBridgeService::resolveBomForListing',
'fk_columns' => [
'aex_listings.ie_line_template_id' => 'ie_line_templates.id',
'aex_listings.ie_line_revision_id' => 'ie_line_revisions.id',
'aex_listings.ie_bom_id' => 'ie_boms.id',
'aex_listings.ie_installed_asset_id' => 'ie_customer_installed_assets.id',
'aex_listings.maintenance_equipment_id' => 'maintenance_equipment.id',
],
],
];
}
/**
* Digital-thread flow: which contexts feed the next stage.
*
* @return array<string, array<int, string>>
*/
public static function contextFlow(): array
{
return [
BoundedContext::MASTER_DATA => [BoundedContext::BOM_CONFIGURATION],
BoundedContext::BOM_CONFIGURATION => [BoundedContext::COSTING_RELEASE],
BoundedContext::COSTING_RELEASE => [BoundedContext::SERIALIZATION],
BoundedContext::SERIALIZATION => [BoundedContext::INSTALLED_BASE],
BoundedContext::INSTALLED_BASE => [BoundedContext::SOURCING],
BoundedContext::COMPETITIVE_RESEARCH => [
BoundedContext::BOM_CONFIGURATION,
BoundedContext::COSTING_RELEASE,
],
];
}
public static function tablePrefix(): string
{
return 'ie_';
}
public static function moduleName(): string
{
return 'IndustrialEngineering';
}
/**
* @return array<int, string>
*/
public static function tablesForContext(string $context): array
{
return array_values(array_map(
fn (array $entity) => $entity['table'],
array_filter(self::entities(), fn (array $e) => $e['context'] === $context)
));
}
public static function entityForTable(string $table): ?array
{
foreach (self::entities() as $key => $entity) {
if ($entity['table'] === $table) {
return array_merge(['key' => $key], $entity);
}
}
return null;
}
/**
* @return array<int, string>
*/
public static function allTables(): array
{
return array_values(array_map(fn (array $e) => $e['table'], self::entities()));
}
/**
* @return array<int, class-string>
*/
public static function allModelClasses(): array
{
return array_values(array_filter(
array_map(fn (array $e) => $e['model'], self::entities())
));
}
}