maintenance_equipment_id) { return \Modules\Maintenance\Models\Equipment::find($listing->maintenance_equipment_id); } $code = 'AEX-EQ-'.$listing->listing_code; $equipment = \Modules\Maintenance\Models\Equipment::create([ 'business_id' => $business->id, 'customer_id' => $listing->seller_contact_id, 'code' => $code, 'name' => $listing->title, 'manufacturer' => null, 'model' => null, 'serial_number' => null, 'location' => $listing->location_text, 'status' => 'inactive', 'notes' => 'ایجاد از عرضه AssetExchange #'.$listing->listing_code, 'created_by' => $user?->id, ]); $listing->update(['maintenance_equipment_id' => $equipment->id]); return $equipment; } public function startRebuildFromDeal(Business $business, Deal $deal, ?User $user = null): ?object { if (! class_exists(\Modules\Maintenance\Services\RebuildProcessService::class)) { throw new \RuntimeException('سرویس بازسازی CMMS در دسترس نیست.'); } if (! Schema::hasTable('maintenance_rebuild_projects')) { throw new \RuntimeException('جدول پروژه‌های بازسازی موجود نیست.'); } $deal->loadMissing('listing', 'appraisal'); $listing = $deal->listing; if (! $listing) { throw new \RuntimeException('عرضه مرتبط با معامله یافت نشد.'); } $equipmentId = $deal->maintenance_equipment_id ?: $listing->maintenance_equipment_id; if (! $equipmentId) { $equipment = $this->createEquipmentFromListing($business, $listing, $user); $equipmentId = $equipment?->id; } if (! $equipmentId) { throw new \RuntimeException('تجهیز CMMS برای شروع بازسازی یافت نشد.'); } $rebuildService = app(\Modules\Maintenance\Services\RebuildProcessService::class); $project = $rebuildService->createProject($business, [ 'business_id' => $business->id, 'title' => 'بازسازی — '.$listing->title, 'description' => 'ایجاد از معامله AssetExchange '.$deal->deal_code, 'scope_type' => 'equipment', 'equipment_id' => $equipmentId, 'estimated_cost' => $deal->appraisal?->renovation_cost_estimate ?? 0, 'supervisor_id' => $user?->id, ], [$equipmentId], $user); $deal->update([ 'maintenance_rebuild_id' => $project->id, 'maintenance_equipment_id' => $equipmentId, 'status' => 'in_progress', ]); if ($deal->appraisal) { try { $this->populateMaterialListFromAppraisal($business, $project, $deal->appraisal, $user); } catch (\Throwable) { } } return $project; } public function populateMaterialListFromAppraisal(Business $business, object $rebuildProject, Appraisal $appraisal, ?User $user = null): int { if (! class_exists(\Modules\Maintenance\Services\MaterialListService::class)) { return 0; } $materialService = app(\Modules\Maintenance\Services\MaterialListService::class); $list = $materialService->getOrCreateList($business, 'rebuild', $rebuildProject->id, $user); $lines = AppraisalLine::where('appraisal_id', $appraisal->id) ->where('renovation_need', '!=', 'none') ->orderBy('sort_order') ->get(); $added = 0; foreach ($lines as $line) { $materialService->addLine($list, [ 'part_name' => $line->name, 'quantity' => 1, 'notes' => trim(($line->condition_notes ?? '').' [AEX renovation: '.$line->renovation_need.']'), ]); $added++; } return $added; } public function importEquipmentPartsToAppraisal(Appraisal $appraisal, ?int $equipmentId = null, bool $replaceExisting = false): int { if (! class_exists(\Modules\Maintenance\Models\EquipmentPart::class)) { throw new \RuntimeException('ماژول CMMS نصب نیست.'); } if (! Schema::hasTable('maintenance_equipment_parts')) { throw new \RuntimeException('جدول قطعات تجهیز موجود نیست.'); } $appraisal->loadMissing('listing'); $equipmentId = $equipmentId ?: $appraisal->listing?->maintenance_equipment_id; if (! $equipmentId) { throw new \RuntimeException('شناسه تجهیز CMMS برای واردسازی مشخص نشده است.'); } $parts = \Modules\Maintenance\Models\EquipmentPart::where('business_id', $appraisal->business_id) ->where('equipment_id', $equipmentId) ->orderBy('id') ->get(); if ($parts->isEmpty()) { throw new \RuntimeException('قطعه‌ای برای این تجهیز در CMMS ثبت نشده است.'); } if ($replaceExisting) { AppraisalLine::where('appraisal_id', $appraisal->id)->delete(); } return DB::transaction(function () use ($appraisal, $parts) { $partMap = []; $sort = 0; $created = 0; $roots = $parts->whereNull('parent_id'); $this->importPartTree($appraisal, $parts, $roots, null, $partMap, $sort, $created); return $created; }); } protected function importPartTree( Appraisal $appraisal, $allParts, $nodes, ?int $parentLineId, array &$partMap, int &$sort, int &$created ): void { foreach ($nodes as $part) { $line = AppraisalLine::create([ 'business_id' => $appraisal->business_id, 'appraisal_id' => $appraisal->id, 'parent_line_id' => $parentLineId, 'line_kind' => $part->is_consumable ? 'consumable' : 'part', 'name' => $part->part_name, 'maintenance_equipment_part_id' => $part->id, 'health_percentage' => $part->health_percentage ?? 100, 'condition_notes' => $part->notes, 'renovation_need' => 'none', 'replacement_cost' => 0, 'keep_in_line' => true, 'sort_order' => $sort++, ]); $partMap[$part->id] = $line->id; $created++; $children = $allParts->where('parent_id', $part->id); if ($children->isNotEmpty()) { $this->importPartTree($appraisal, $allParts, $children, $line->id, $partMap, $sort, $created); } } } }