IngestInvoicesUseCase.php
Pfad: src/Application/Rechnung/IngestInvoicesUseCase.php
Ext: php
Größe: 3370 Bytes
Geändert: 2026-07-16 17:43:25+02
<?php
declare(strict_types=1);
namespace Demo\Application\Rechnung;
use Demo\Domain\Rechnung\ClockPort;
use Demo\Domain\Rechnung\InvoiceLoggerPort;
use Demo\Domain\Rechnung\InvoiceState;
use Demo\Domain\Rechnung\InvoiceStatePort;
use Demo\Domain\Rechnung\InvoiceStatus;
use Demo\Domain\Rechnung\SourceInvoice;
final class IngestInvoicesUseCase
{
private readonly ProcessInvoiceUseCase $processor;
public function __construct(
private readonly InvoiceStatePort $statePort,
private readonly DiscoverInvoicesUseCase $discover,
DownloadInvoiceUseCase $download,
ExtractInvoiceDataUseCase $extract,
ResolveVendorUseCase $resolveVendor,
PostInvoiceUseCase $post,
private readonly InvoiceLoggerPort $logger,
private readonly ClockPort $clock,
int $maxRetries,
float $amountTolerance,
) {
$this->processor = new ProcessInvoiceUseCase($statePort, $download, $extract, $resolveVendor, $post, $logger, $clock, $maxRetries, $amountTolerance);
}
public function execute(string $runId, string $username, string $password): IngestResult
{
return $this->statePort->withExclusiveLock(
fn (): IngestResult => $this->executeLocked($runId, $username, $password),
);
}
private function executeLocked(string $runId, string $username, string $password): IngestResult
{
$loaded = $this->statePort->load();
$state = new InvoiceState($loaded->schemaVersion, $this->clock->now(), $loaded->all());
$sources = $this->discover->execute($runId, $username, $password);
if ($sources === []) {
$this->statePort->save($state);
return new IngestResult($runId, InvoiceStatus::DONE_NO_WORK, 0, 0, 0, 0, ['summary' => 'leer']);
}
$processed = $skipped = $errors = 0;
foreach ($sources as $source) {
if (!$this->shouldProcess($source, $state)) {
$skipped++;
continue;
}
$outcome = $this->processor->execute($runId, $source, $state);
$state = $outcome->state;
match ($outcome->result) {
InvoiceProcessOutcome::PROCESSED => $processed++,
InvoiceProcessOutcome::SKIPPED => $skipped++,
default => $errors++,
};
}
$status = $this->runStatus(count($sources), $errors);
$this->logger->logStep($runId, 'run', $status, compact('processed', 'skipped', 'errors'));
return new IngestResult($runId, $status, count($sources), $processed, $skipped, $errors, compact('processed', 'skipped', 'errors'));
}
private function shouldProcess(SourceInvoice $source, InvoiceState $state): bool
{
$bySource = $state->findBySourceId($source->sourceId);
$byKey = $state->findByRechnungsschluessel($source->rechnungsschluessel());
return !($bySource !== null && InvoiceStatus::isSuccess($bySource->status))
&& !($byKey !== null && InvoiceStatus::isSuccess($byKey->status));
}
private function runStatus(int $discovered, int $errors): string
{
if ($errors === 0) { return InvoiceStatus::DONE; }
return ($errors / $discovered) * 100 >= 20.0
? InvoiceStatus::DONE_PARTIAL
: InvoiceStatus::DONE_WITH_WARNINGS;
}
}
Frühere Versionen
| Version | Zeitpunkt | Operation |
|---|---|---|
| 34 | 2026-07-16 19:55:01.885759+02 | UPDATE |