argument('business_id') ?: Business::query()->value('id') ?: 0); if ($businessId <= 0) { $this->error('No business found.'); return self::FAILURE; } $business = Business::find($businessId); if (! $business) { $this->error("Business {$businessId} not found."); return self::FAILURE; } $user = User::where('business_id', $businessId)->orderBy('id')->first(); if (! $user) { $this->error("No user found for business {$businessId}."); return self::FAILURE; } if ($this->option('fresh')) { $this->purgeDemo($businessId); } elseif (Listing::where('business_id', $businessId)->where('title', self::DEMO_TITLE)->exists()) { $this->warn('Demo data already exists. Use --fresh to recreate.'); $this->printSummary($businessId); return self::SUCCESS; } $supplierId = Contact::where('business_id', $businessId) ->whereIn('type', ['supplier', 'both']) ->orderBy('id') ->value('id'); if (! $supplierId) { $supplierId = Contact::create([ 'business_id' => $businessId, 'type' => 'supplier', 'supplier_business_name' => 'تأمین‌کننده دمو AEX', 'name' => 'تأمین‌کننده دمو AEX', 'mobile' => '09000000000', 'created_by' => $user->id, 'contact_status' => 'active', ])->id; $this->line('Created demo supplier contact.'); } $this->info("Seeding AssetExchange demo for business #{$businessId}..."); try { DB::transaction(function () use ($business, $user, $supplierId) { $listing = $this->listingService->create($business, [ 'title' => self::DEMO_TITLE, 'description' => 'داده تستی خودکار برای smoke/E2E ماژول AssetExchange.', 'listing_type' => 'machine_used', 'scope_type' => 'whole', 'manufacturer' => 'Krones', 'model' => 'PET-Line 24K', 'serial_number' => 'DEMO-SN-'.now()->format('Ymd'), 'year_manufactured' => 2018, 'working_hours' => 12500, 'asking_price' => 8500000000, 'location_text' => 'تهران — انبار نمایشی', 'condition_grade' => 'B', 'intake_source' => 'internal_demo', ], $user); $listing = $this->listingService->submit($business, $listing, $user); $listing = $this->listingService->assignBroker($business, $listing, $user->id, $user); $appraisal = $this->appraisalService->startAppraisal($business, $listing, $user, [ 'methodology' => 'hybrid', 'field_visit_date' => now()->toDateString(), 'appraisal_fee' => 15000000, 'auto_import' => false, ]); AppraisalLine::create([ 'business_id' => $business->id, 'appraisal_id' => $appraisal->id, 'line_kind' => 'machine', 'name' => 'خط اصلی بسته‌بندی', 'manufacturer' => 'Krones', 'model' => 'PET-Line 24K', 'health_percentage' => 72, 'age_years' => 7, 'replacement_cost' => 12000000000, 'renovation_cost' => 1800000000, 'line_as_is_value' => 7200000000, 'line_post_renovation_value' => 9000000000, 'renovation_need' => 'moderate', 'keep_in_line' => true, 'sort_order' => 0, ]); AppraisalLine::create([ 'business_id' => $business->id, 'appraisal_id' => $appraisal->id, 'line_kind' => 'part', 'name' => 'درایور موتور اصلی', 'health_percentage' => 55, 'age_years' => 7, 'replacement_cost' => 450000000, 'renovation_cost' => 120000000, 'line_as_is_value' => 250000000, 'line_post_renovation_value' => 370000000, 'renovation_need' => 'high', 'keep_in_line' => true, 'sort_order' => 1, ]); $appraisal = $this->appraisalService->recalculate($appraisal); $appraisal = $this->appraisalService->approve( $business, $appraisal, $user, 'گزارش دمو: تجهیز قابل خرید با نوسازی محدود درایور و بازرسی هیدرولیک.' ); $inquiryData = [ 'title' => 'استعلام دمو — قطعات و سرویس خط', 'inquiry_type' => 'supplier_rfq', 'appraisal_id' => $appraisal->id, 'from_appraisal' => true, 'due_date' => now()->addDays(3)->format('Y-m-d'), 'internal_user_ids' => [$user->id], ]; if ($supplierId) { $inquiryData['supplier_contact_ids'] = [$supplierId]; } $inquiry = $this->inquiryService->create($business, $listing, $inquiryData, $user); $inquiry = $this->inquiryService->send($inquiry, $user); $slaInquiry = $this->inquiryService->create($business, $listing, [ 'title' => 'استعلام دمو SLA — معوق', 'inquiry_type' => 'supplier_rfq', 'due_date' => now()->subDay()->format('Y-m-d'), 'lines' => [[ 'part_name' => 'سنسور فشار', 'description' => 'نمونه SLA معوق', 'target_condition' => 'new', 'reference_price' => 35000000, ]], 'supplier_contact_ids' => [$supplierId], ], $user); $slaInquiry = $this->inquiryService->send($slaInquiry, $user); PriceInquiryRecipient::where('price_inquiry_id', $slaInquiry->id) ->where('recipient_type', 'supplier') ->where('status', 'pending') ->update(['sent_at' => Carbon::now()->subHours(60)]); $this->researchCaseService->openCase($business, $listing->fresh(), [ 'title' => 'پرونده تحقیق دمو — '.$listing->title, 'spawn_templates' => true, 'lead_researcher_id' => $user->id, ], $user); $listing = $listing->fresh(); $deal = $this->dealService->createDeal($business, $listing, 'brokerage', [ 'appraisal_id' => $appraisal->id, 'agreed_price' => $appraisal->recommended_buy_price, 'commission_percent' => 3, 'notes' => 'معامله دمو — کارگزاری', ], $user); try { $this->dealService->completeDeal($business, $deal, $user); } catch (\Throwable) { // ERP/CMMS bridges may be unavailable in demo environments. } }); } catch (\Throwable $e) { $this->error('Seed failed: '.$e->getMessage()); return self::FAILURE; } $this->info('Demo data seeded successfully.'); $this->printSummary($businessId); return self::SUCCESS; } protected function purgeDemo(int $businessId): void { $listingIds = Listing::withTrashed() ->where('business_id', $businessId) ->where('title', self::DEMO_TITLE) ->pluck('id'); if ($listingIds->isEmpty()) { return; } $caseIds = ResearchCase::where('business_id', $businessId) ->whereIn('listing_id', $listingIds) ->pluck('id'); if ($caseIds->isNotEmpty()) { ResearchTask::whereIn('research_case_id', $caseIds)->delete(); ResearchCase::whereIn('id', $caseIds)->delete(); } if (\Illuminate\Support\Facades\Schema::hasTable('aex_commissions')) { $dealIds = \Modules\AssetExchange\Models\Deal::withTrashed() ->whereIn('listing_id', $listingIds) ->pluck('id'); if ($dealIds->isNotEmpty()) { \Modules\AssetExchange\Models\Commission::whereIn('deal_id', $dealIds)->delete(); \Modules\AssetExchange\Models\Deal::withTrashed()->whereIn('id', $dealIds)->forceDelete(); } } $inquiryIds = PriceInquiry::where('business_id', $businessId) ->whereIn('listing_id', $listingIds) ->pluck('id'); if ($inquiryIds->isNotEmpty()) { PriceInquiryRecipient::whereIn('price_inquiry_id', $inquiryIds)->delete(); PriceInquiry::whereIn('id', $inquiryIds)->delete(); } foreach ($listingIds as $listingId) { $appraisalIds = \Modules\AssetExchange\Models\Appraisal::withTrashed() ->where('listing_id', $listingId) ->pluck('id'); if ($appraisalIds->isNotEmpty()) { AppraisalLine::whereIn('appraisal_id', $appraisalIds)->delete(); \Modules\AssetExchange\Models\Appraisal::withTrashed()->whereIn('id', $appraisalIds)->forceDelete(); } } Listing::withTrashed()->whereIn('id', $listingIds)->forceDelete(); $this->line('Previous demo records removed.'); } protected function printSummary(int $businessId): void { $listing = Listing::where('business_id', $businessId)->where('title', self::DEMO_TITLE)->first(); if (! $listing) { return; } $appraisal = $listing->appraisals()->latest('id')->first(); $inquiries = $listing->priceInquiries()->orderBy('id')->get(); $rfq = $inquiries->first(fn ($i) => str_contains($i->title, 'قطعات')); $sla = $inquiries->first(fn ($i) => str_contains($i->title, 'SLA')); $research = $listing->researchCases()->latest('id')->first(); $deal = $listing->deals()->latest('id')->first(); $this->table(['Entity', 'Code', 'Status'], [ ['Listing', $listing->listing_code, $listing->status], ['Appraisal', $appraisal?->appraisal_number ?? '—', $appraisal?->status ?? '—'], ['Research', $research?->case_code ?? '—', $research?->status ?? '—'], ['Deal', $deal?->deal_code ?? '—', $deal?->status ?? '—'], ['Inquiry (RFQ)', $rfq?->inquiry_code ?? '—', $rfq?->status ?? '—'], ['Inquiry (SLA)', $sla?->inquiry_code ?? '—', $sla?->status ?? '—'], ['Appraisal PDF', $appraisal?->report_pdf_path ? 'stored' : '—', ''], ]); } }