format('Y-m-d'); // 견적 (quotes) $quoteStats = DB::connection('mysql') ->table('quotes') ->where('tenant_id', $tenantId) ->where('registration_date', $dateStr) ->whereNull('deleted_at') ->selectRaw(" COUNT(*) as created_count, COALESCE(SUM(total_amount), 0) as total_amount, SUM(CASE WHEN status = 'approved' THEN 1 ELSE 0 END) as approved_count, SUM(CASE WHEN status = 'rejected' THEN 1 ELSE 0 END) as rejected_count, SUM(CASE WHEN status = 'converted' THEN 1 ELSE 0 END) as conversion_count ") ->first(); $createdCount = $quoteStats->created_count ?? 0; $conversionCount = $quoteStats->conversion_count ?? 0; $conversionRate = $createdCount > 0 ? ($conversionCount / $createdCount) * 100 : 0; // 입찰 (biddings) $biddingStats = DB::connection('mysql') ->table('biddings') ->where('tenant_id', $tenantId) ->where('bidding_date', $dateStr) ->whereNull('deleted_at') ->selectRaw(" COUNT(*) as cnt, SUM(CASE WHEN status = 'won' THEN 1 ELSE 0 END) as won_count, COALESCE(SUM(bidding_amount), 0) as total_amount ") ->first(); // 상담 (sales_prospect_consultations) $consultationCount = DB::connection('mysql') ->table('sales_prospect_consultations') ->whereDate('created_at', $dateStr) ->count(); // 영업 기회 (sales_prospects - tenant_id 없음, created_at 기반) $prospectStats = DB::connection('mysql') ->table('sales_prospects') ->whereDate('created_at', $dateStr) ->whereNull('deleted_at') ->selectRaw(" COUNT(*) as created_count, SUM(CASE WHEN status = 'contracted' THEN 1 ELSE 0 END) as won_count, SUM(CASE WHEN status = 'lost' THEN 1 ELSE 0 END) as lost_count ") ->first(); StatQuotePipelineDaily::updateOrCreate( ['tenant_id' => $tenantId, 'stat_date' => $dateStr], [ 'quote_created_count' => $createdCount, 'quote_amount' => $quoteStats->total_amount ?? 0, 'quote_approved_count' => $quoteStats->approved_count ?? 0, 'quote_rejected_count' => $quoteStats->rejected_count ?? 0, 'quote_conversion_count' => $conversionCount, 'quote_conversion_rate' => $conversionRate, 'prospect_created_count' => $prospectStats->created_count ?? 0, 'prospect_won_count' => $prospectStats->won_count ?? 0, 'prospect_lost_count' => $prospectStats->lost_count ?? 0, 'prospect_amount' => 0, // sales_prospects에 금액 컬럼 없음 'bidding_count' => $biddingStats->cnt ?? 0, 'bidding_won_count' => $biddingStats->won_count ?? 0, 'bidding_amount' => $biddingStats->total_amount ?? 0, 'consultation_count' => $consultationCount, ] ); return 1; } public function aggregateMonthly(int $tenantId, int $year, int $month): int { // 견적 도메인은 일간 테이블만 운영 (월간은 Phase 4에서 필요시 추가) return 0; } }