$ids * @return array> */ public function run(array $ids, string $timezone, bool $apply = false, bool $all = false): array { if (! in_array($timezone, DateTimeZone::listIdentifiers(DateTimeZone::ALL_WITH_BC), true)) { throw new InvalidArgumentException('Zona horaria de origen inválida.'); } if ($all && $ids !== []) { throw new InvalidArgumentException('Usar --all o --ids, no ambos.'); } if (! $all && $ids === []) { throw new InvalidArgumentException('Indicar --all para todos los fixed_window o --ids para una selección.'); } return DB::transaction(function () use ($ids, $timezone, $apply): array { $query = DB::table('validity_times')->orderBy('id'); if ($ids === []) { $query->where('type', 'fixed_window'); } else { $query->whereIn('id', $ids); } if ($apply) { $query->lockForUpdate(); } $rows = $query->get(); if ($ids !== [] && $rows->count() !== count(array_unique($ids))) { throw new InvalidArgumentException('Uno o más IDs no existen. No se modificó ningún registro.'); } if ($rows->contains(fn ($row): bool => $row->type !== 'fixed_window')) { throw new InvalidArgumentException('Sólo se admiten IDs de fixed_window. No se modificó ningún registro.'); } $result = []; foreach ($rows as $row) { $start = $this->convert($row->fixed_starts_at, $timezone); $end = $this->convert($row->fixed_expires_at, $timezone); $result[] = [ 'id' => $row->id, 'status' => $apply ? 'convertido' : 'propuesta; verificar origen local', 'original_start' => $row->fixed_starts_at, 'original_end' => $row->fixed_expires_at, 'utc_start' => $start, 'utc_end' => $end, ]; if (! $apply) { continue; } DB::table('validity_times')->where('id', $row->id)->update([ 'fixed_starts_at' => $start, 'fixed_expires_at' => $end, ]); } return $result; }); } private function convert(?string $value, string $timezone): ?string { return $value === null ? null : CarbonImmutable::parse($value, $timezone)->utc()->format('Y-m-d H:i:s'); } }