ResolveVendorUseCaseTest.php
Pfad: tests/Rechnung/ResolveVendorUseCaseTest.php
Ext: php
Größe: 3397 Bytes
Geändert: 2026-07-16 17:57:44+02
<?php
declare(strict_types=1);
namespace Demo\Tests\Rechnung;
use Demo\Application\Rechnung\InvoiceProcessException;
use Demo\Application\Rechnung\ResolveVendorUseCase;
use Demo\Domain\Rechnung\Amount;
use Demo\Domain\Rechnung\ExtractedInvoiceData;
use Demo\Domain\Rechnung\InvoiceLoggerPort;
use Demo\Domain\Rechnung\LexofficePort;
use Demo\Domain\Rechnung\PostingResult;
use PHPUnit\Framework\TestCase;
final class ResolveVendorUseCaseTest extends TestCase
{
public function testReusesOnlyExactVendorAndBillingAddress(): void
{
$lexware = new VendorLexwareFake([$this->contact('contact-1', 'Street 1')]);
$id = (new ResolveVendorUseCase($lexware, new VendorLoggerFake()))->execute('run', $this->invoice());
self::assertSame('contact-1', $id);
self::assertSame(0, $lexware->creates);
}
public function testCreatesContactWhenAddressDiffers(): void
{
$lexware = new VendorLexwareFake([$this->contact('other', 'Other 9')]);
$id = (new ResolveVendorUseCase($lexware, new VendorLoggerFake()))->execute('run', $this->invoice());
self::assertSame('created-1', $id);
self::assertSame(1, $lexware->creates);
self::assertSame('Street 1|79106 Freiburg|DE', $lexware->lastSignature);
}
public function testRejectsAmbiguousExactContacts(): void
{
$lexware = new VendorLexwareFake([$this->contact('one', 'Street 1'), $this->contact('two', 'Street 1')]);
$this->expectException(InvoiceProcessException::class);
$this->expectExceptionMessage('Mehrere identische');
(new ResolveVendorUseCase($lexware, new VendorLoggerFake()))->execute('run', $this->invoice());
}
/** @return array<string,mixed> */
private function contact(string $id, string $street): array
{
return [
'id' => $id,
'roles' => ['vendor' => []],
'company' => ['name' => 'WEtell GmbH'],
'addresses' => ['billing' => [[
'street' => $street,
'zip' => '79106',
'city' => 'Freiburg',
'countryCode' => 'DE',
]]],
];
}
private function invoice(): ExtractedInvoiceData
{
return new ExtractedInvoiceData(
'WEtell GmbH',
'Street 1|79106 Freiburg|DE',
'RF123',
'2026-07-04',
new Amount('26.0504', '4.9496', '31.0000', 'EUR'),
0.99,
);
}
}
final class VendorLexwareFake implements LexofficePort
{
public int $creates = 0;
public ?string $lastSignature = null;
/** @param list<array<string,mixed>> $contacts */
public function __construct(private readonly array $contacts) {}
public function findContactByName(string $vendorName): array { return $this->contacts; }
public function createContact(string $vendorName, string $vendorAddressSignature): string
{
$this->creates++;
$this->lastSignature = $vendorAddressSignature;
return 'created-1';
}
public function postInvoice(ExtractedInvoiceData $invoice, string $contactId, string $pdfPath): PostingResult
{
return new PostingResult('unused', 'OPEN', null);
}
}
final class VendorLoggerFake implements InvoiceLoggerPort
{
public function logStep(string $runId, string $step, string $status, array $context = []): void {}
}