InvoiceState.php
Pfad: src/Domain/Rechnung/InvoiceState.php
Ext: php
Größe: 3274 Bytes
Geändert: 2026-07-16 16:54:17+02
<?php
declare(strict_types=1);
namespace Demo\Domain\Rechnung;
use InvalidArgumentException;
/**
* Versionierter Gesamtzustand der Rechnungsverarbeitung.
*/
final class InvoiceState
{
public const SCHEMA_VERSION = '2.0';
/** @param list<InvoiceRecord> $records Rechnungsstaende. */
public function __construct(public readonly string $schemaVersion, public readonly string $generatedAt, public readonly array $records)
{
}
/** Erzeugt einen leeren aktuellen Zustand. */
public static function empty(): self { return new self(self::SCHEMA_VERSION, date(DATE_ATOM), []); }
/** @param array<string,mixed> $data Persistierte Zustandsdaten. */
public static function fromArray(array $data): self
{
$rawRecords = $data['records'] ?? null;
if (!is_array($rawRecords)) {
throw new InvalidArgumentException('State enthaelt keine Record-Liste');
}
$records = [];
foreach ($rawRecords as $raw) {
if (!is_array($raw)) {
throw new InvalidArgumentException('Ungueltiger State-Record');
}
$records[] = InvoiceRecord::fromArray($raw);
}
return new self(self::SCHEMA_VERSION, (string) ($data['generatedAt'] ?? date(DATE_ATOM)), $records);
}
/** Ersetzt einen Record gleicher Quelle oder fuegt ihn hinzu. */
public function withRecord(InvoiceRecord $record): self
{
$records = [];
$replaced = false;
foreach ($this->records as $current) {
if ($current->quelleId === $record->quelleId) {
$records[] = $record;
$replaced = true;
} else {
$records[] = $current;
}
}
if (!$replaced) {
$records[] = $record;
}
return new self(self::SCHEMA_VERSION, date(DATE_ATOM), $records);
}
/** @return list<InvoiceRecord> Alle Records. */
public function all(): array { return $this->records; }
/** Sucht nach technischer Quell-ID. */
public function findBySourceId(string $quelleId): ?InvoiceRecord { return $this->find(static fn (InvoiceRecord $r): bool => $r->quelleId === $quelleId); }
/** Sucht nach kanonischem Rechnungsschluessel. */
public function findByRechnungsschluessel(string $key): ?InvoiceRecord { return $this->find(static fn (InvoiceRecord $r): bool => $r->rechnungsschluessel === $key); }
/** Sucht nach Payload-Hash. */
public function findByPayloadSha256(string $hash): ?InvoiceRecord { return $this->find(static fn (InvoiceRecord $r): bool => $r->payloadSha256 === $hash); }
/** @return array{schemaVersion:string,generatedAt:string,records:list<array<string,mixed>>} */
public function toArray(): array { return ['schemaVersion' => self::SCHEMA_VERSION, 'generatedAt' => $this->generatedAt, 'records' => array_map(static fn (InvoiceRecord $r): array => $r->toArray(), $this->records)]; }
/** @param callable(InvoiceRecord):bool $predicate Suchpraedikat. */
private function find(callable $predicate): ?InvoiceRecord
{
foreach ($this->records as $record) {
if ($predicate($record)) {
return $record;
}
}
return null;
}
}
Frühere Versionen
| Version | Zeitpunkt | Operation |
|---|---|---|
| 20 | 2026-07-16 19:01:40.812929+02 | UPDATE |