CluPilotCloud/app/Services/Tax/VatIdCheck.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;
}
}