, * }>, * } */ public function build(Carbon $from, ?Carbon $to = null): array { $to ??= Carbon::now(); $rows = ConversionEvent::query() ->whereBetween('created_at', [$from, $to]) ->get(['type', 'source', 'company_id']); $sources = []; foreach (ConversionSource::cases() as $source) { $forSource = $rows->where('source', $source); if ($forSource->isEmpty()) { continue; } $steps = []; $previous = null; foreach (ConversionEventType::ladder() as $type) { $forType = $forSource->where('type', $type); $companies = $forType ->pluck('company_id') ->filter(static fn ($id): bool => $id !== null) ->unique() ->count(); $steps[] = [ 'step' => $type->step(), 'type' => $type->value, 'label' => $type->label(), 'diagnosis' => $type->diagnosis(), 'firmen' => $companies, // Übergang von der VORIGEN Stufe. Die erste Stufe hat // keinen Vorgänger und damit keine Quote. 'uebergang' => $previous === null || $previous === 0 ? null : round($companies / $previous * 100, 1), 'ohne_firma' => $forType->whereNull('company_id')->count(), ]; $previous = $companies; } $sources[] = [ 'source' => $source->value, 'label' => $source->label(), 'steps' => $steps, ]; } return [ 'from' => $from->toDateString(), 'to' => $to->toDateString(), 'sources' => $sources, ]; } }