format('Y-m-d H:i:s'); } if (!is_string($value)) { throw new InvalidArgumentException('created_at must be a string'); } $trimmed = trim($value); if ($trimmed === '') { throw new InvalidArgumentException('created_at cannot be empty'); } foreach (['Y-m-d H:i:s', 'Y-m-d\TH:i:s', 'Y-m-d\TH:i'] as $format) { $parsed = DateTimeImmutable::createFromFormat($format, $trimmed); if ($parsed instanceof DateTimeImmutable && $parsed->format($format) === $trimmed) { return $parsed->format('Y-m-d H:i:s'); } } throw new InvalidArgumentException('created_at must be a valid datetime'); } public static function normalizeIncludeInInvoice(mixed $value): ?bool { if ($value === null) { return null; } if (is_bool($value)) { return $value; } if (is_int($value)) { if ($value === 1) { return true; } if ($value === 0) { return false; } } if (is_string($value)) { $normalized = strtolower(trim($value)); return match ($normalized) { '', 'null', 'use_department' => null, '1', 'true', 'include', 'included', 'yes' => true, '0', 'false', 'exclude', 'excluded', 'no' => false, default => throw new InvalidArgumentException('include_in_invoice must be use_department, include, or exclude'), }; } throw new InvalidArgumentException('include_in_invoice must be use_department, include, or exclude'); } }