78 lines
2.4 KiB
PHP
78 lines
2.4 KiB
PHP
<?php
|
|
|
|
namespace App\Services\Tax;
|
|
|
|
/**
|
|
* What VIES answered about one VAT number.
|
|
*
|
|
* Three outcomes, not two, and the third is the whole reason this class exists.
|
|
* VIES is a gateway onto twenty-seven national registers, and any one of them is
|
|
* regularly unreachable — a member state takes its service down for the night,
|
|
* the concurrency limit is hit, the gateway times out. None of that says anything
|
|
* about the number.
|
|
*
|
|
* So UNAVAILABLE must never be read as INVALID. Treating an outage as a failed
|
|
* check would clear a verification that has been standing for months, move that
|
|
* customer from reverse charge onto the domestic rate, and change what their next
|
|
* invoice says — because a national register was asleep. It must not be read as
|
|
* VALID either: reverse charge on an unchecked number is our liability, not the
|
|
* customer's.
|
|
*
|
|
* The name and address are what the register holds. They are kept because they
|
|
* are the evidence that the number belongs to the company we are invoicing, and
|
|
* because a mismatch there is worth an operator's attention even when the number
|
|
* itself is registered.
|
|
*/
|
|
final readonly class VatIdCheck
|
|
{
|
|
public const VALID = 'valid';
|
|
|
|
public const INVALID = 'invalid';
|
|
|
|
public const UNAVAILABLE = 'unavailable';
|
|
|
|
private function __construct(
|
|
public string $outcome,
|
|
public ?string $name = null,
|
|
public ?string $address = null,
|
|
public ?string $reason = null,
|
|
) {}
|
|
|
|
public static function valid(?string $name = null, ?string $address = null): self
|
|
{
|
|
return new self(self::VALID, $name, $address);
|
|
}
|
|
|
|
public static function invalid(): self
|
|
{
|
|
return new self(self::INVALID);
|
|
}
|
|
|
|
/** @param string|null $reason what stopped us asking — for the log, never for the customer */
|
|
public static function unavailable(?string $reason = null): self
|
|
{
|
|
return new self(self::UNAVAILABLE, reason: $reason);
|
|
}
|
|
|
|
public function isValid(): bool
|
|
{
|
|
return $this->outcome === self::VALID;
|
|
}
|
|
|
|
public function isInvalid(): bool
|
|
{
|
|
return $this->outcome === self::INVALID;
|
|
}
|
|
|
|
/**
|
|
* Nothing was learnt.
|
|
*
|
|
* Callers must leave whatever they already knew alone when this is true —
|
|
* see the class comment for why that is not merely cautious.
|
|
*/
|
|
public function isUnavailable(): bool
|
|
{
|
|
return $this->outcome === self::UNAVAILABLE;
|
|
}
|
|
}
|