← Code-Übersicht

DownloadInvoiceUseCase.php

Pfad: src/Application/Rechnung/DownloadInvoiceUseCase.php

Ext: php

Größe: 2904 Bytes

Geändert: 2026-07-16 17:45:07+02

<?php
declare(strict_types=1);

namespace Demo\Application\Rechnung;

use Demo\Domain\Rechnung\InvoiceFileStoragePort;
use Demo\Domain\Rechnung\InvoiceLoggerPort;
use Demo\Domain\Rechnung\InvoiceRecord;
use Demo\Domain\Rechnung\SourceInvoice;
use Demo\Domain\Rechnung\WetellSourcePort;
use Demo\Domain\Rechnung\InvoiceErrorCode;
use Demo\Domain\Rechnung\ClockPort;

/**
 * Use Case: Download des PDFs und Übergabe in die lokale Ablage.
 */
final class DownloadInvoiceUseCase
{
    /**
     * @param WetellSourcePort      $portal  Quelle.
     * @param InvoiceFileStoragePort $storage Ablageadapter.
     * @param InvoiceLoggerPort      $logger  Log.
     * @param ClockPort             $clock   Zeitquelle.
     */
    public function __construct(
        private WetellSourcePort $portal,
        private InvoiceFileStoragePort $storage,
        private InvoiceLoggerPort $logger,
        private ClockPort $clock
    ) {
    }

    /**
     * @param string       $runId    Lauf-ID.
     * @param SourceInvoice $source  Rechnungsmetadaten.
     * @param InvoiceRecord $record   Aktueller Datensatz.
     * @return InvoiceRecord Aktualisierte Datensatzversion.
     */
    public function execute(string $runId, SourceInvoice $source, InvoiceRecord $record): InvoiceRecord
    {
        $this->logger->logStep($runId, 'download', 'START', ['sourceId' => $source->sourceId]);
        try {
            $content = $this->portal->downloadInvoicePdf($source->downloadUrl);
        } catch (\Throwable $error) {
            throw new InvoiceProcessException(
                InvoiceErrorCode::DOWNLOAD,
                'download',
                'Rechnungsdownload fehlgeschlagen: ' . $error->getMessage(),
                0,
                $error
            );
        }

        if ($content === '') {
            throw new InvoiceProcessException(
                InvoiceErrorCode::DOWNLOAD,
                'download',
                'Leerer PDF-Inhalt empfangen'
            );
        }
        if (!$this->isPdf($content)) {
            throw new InvoiceProcessException(
                InvoiceErrorCode::DOWNLOAD,
                'download',
                'Download ist kein gueltiges PDF (Content-Type/Dateiinhalt pruefen)'
            );
        }

        $target = $this->storage->buildTargetPath($source->invoiceDateHint, $source->vendorName, $source->sourceId);
        $this->storage->persistDownloadedPdf($content, $target);

        $sha256 = $this->storage->sha256($target);
        $record = $record->withDownload($target, $sha256, $this->clock->now());
        $this->logger->logStep($runId, 'download', 'DONE', ['path' => $target]);

        return $record;
    }

    private function isPdf(string $content): bool
    {
        if (strncmp($content, '%PDF-', 5) !== 0) {
            return false;
        }

        return str_contains(substr($content, -4096), '%%EOF');
    }
}

Frühere Versionen

Version Zeitpunkt Operation
33 2026-07-16 19:55:01.885432+02 UPDATE
9 2026-07-16 17:21:44.383784+02 UPDATE