← Code-Übersicht

ResolveVendorUseCase.php

Pfad: src/Application/Rechnung/ResolveVendorUseCase.php

Ext: php

Größe: 3023 Bytes

Geändert: 2026-07-16 17:24:56+02

<?php
declare(strict_types=1);

namespace Demo\Application\Rechnung;

use Demo\Domain\Rechnung\ExtractedInvoiceData;
use Demo\Domain\Rechnung\InvoiceErrorCode;
use Demo\Domain\Rechnung\InvoiceLoggerPort;
use Demo\Domain\Rechnung\LexofficePort;

final class ResolveVendorUseCase
{
    public function __construct(
        private readonly LexofficePort $lexoffice,
        private readonly InvoiceLoggerPort $logger,
    ) {
    }

    public function execute(string $runId, ExtractedInvoiceData $data): string
    {
        $invoice = $data->toArray();
        $name = (string) $invoice['vendorName'];
        $signature = (string) $invoice['vendorAddressSignature'];
        $matches = [];
        foreach ($this->lexoffice->findContactByName($name) as $contact) {
            if ($this->matches($contact, $name, $signature)) {
                $matches[] = $contact;
            }
        }
        if (count($matches) > 1) {
            throw new InvoiceProcessException(
                InvoiceErrorCode::VENDOR_MATCH,
                'resolve_vendor',
                'Mehrere identische Lieferantenkontakte gefunden',
                0,
                null,
            );
        }
        if ($matches !== []) {
            $id = $matches[0]['id'] ?? null;
            if (!is_string($id) || $id === '') {
                throw new InvoiceProcessException(InvoiceErrorCode::VENDOR_MATCH, 'resolve_vendor', 'Kontakt-ID fehlt', 0, null);
            }
            $this->logger->logStep($runId, 'resolve_vendor', 'REUSED', ['contactId' => $id]);
            return $id;
        }
        $id = $this->lexoffice->createContact($name, $signature);
        $this->logger->logStep($runId, 'resolve_vendor', 'CREATED', ['contactId' => $id]);
        return $id;
    }

    /** @param array<string,mixed> $contact */
    private function matches(array $contact, string $name, string $signature): bool
    {
        $roles = $contact['roles'] ?? null;
        $company = $contact['company'] ?? null;
        if (!is_array($roles) || !array_key_exists('vendor', $roles) || !is_array($company)) {
            return false;
        }
        if ($this->normalize((string) ($company['name'] ?? '')) !== $this->normalize($name)) {
            return false;
        }
        $addresses = $contact['addresses'] ?? null;
        $billing = is_array($addresses) ? ($addresses['billing'] ?? null) : null;
        $address = is_array($billing) && isset($billing[0]) && is_array($billing[0]) ? $billing[0] : [];
        $remote = implode('|', [
            (string) ($address['street'] ?? ''),
            trim((string) ($address['zip'] ?? '') . ' ' . (string) ($address['city'] ?? '')),
            strtoupper((string) ($address['countryCode'] ?? '')),
        ]);
        return $this->normalize($remote) === $this->normalize($signature);
    }

    private function normalize(string $value): string
    {
        $value = mb_strtolower(trim($value), 'UTF-8');
        return preg_replace('/[^\pL\pN]+/u', '', $value) ?? '';
    }
}

Frühere Versionen

Version Zeitpunkt Operation
35 2026-07-16 19:55:01.886511+02 UPDATE