90 lines
3.0 KiB
PHP
90 lines
3.0 KiB
PHP
<?php
|
||
|
||
declare(strict_types=1);
|
||
|
||
namespace App\Model\Faktura;
|
||
|
||
/**
|
||
* Maska čísla faktury a období, po kterém se číselná řada nuluje.
|
||
*
|
||
* Značky v masce: {ROK}, {RR}, {MESIC}, {CISLO}, {CISLO4} (počet číslic 1–8).
|
||
*/
|
||
final class FakturaCislovani
|
||
{
|
||
public const MASKA_VYCHOZI = '{ROK}{CISLO4}';
|
||
public const OBDOBI_VYCHOZI = 'ROK';
|
||
public const SPLATNOST_VYCHOZI = 15;
|
||
|
||
public const OBDOBI = [
|
||
'ROK' => 'po roce',
|
||
'MESIC' => 'po měsíci',
|
||
'NEPRETRZITE' => 'nepřetržitě',
|
||
];
|
||
|
||
public static function normalizeObdobi(string $obdobi): string
|
||
{
|
||
$obdobi = strtoupper(trim($obdobi));
|
||
return isset(self::OBDOBI[$obdobi]) ? $obdobi : self::OBDOBI_VYCHOZI;
|
||
}
|
||
|
||
public static function normalizeSplatnost(int $dny): int
|
||
{
|
||
return max(0, min(365, $dny));
|
||
}
|
||
|
||
/**
|
||
* Maska musí obsahovat právě značku pořadového čísla a vejít se do čísla faktury (20 znaků).
|
||
*/
|
||
public static function validateMaska(string $maska): ?string
|
||
{
|
||
$maska = trim($maska);
|
||
if ($maska === '') {
|
||
return 'Zadejte masku čísla faktury.';
|
||
}
|
||
if (mb_strlen($maska) > 40) {
|
||
return 'Maska může mít nejvýše 40 znaků.';
|
||
}
|
||
if (!preg_match('/^(?:[^{}]|\{(?:ROK|RRRR|RR|MESIC|MM|CISLO\d?)\})+$/u', $maska)) {
|
||
return 'Maska obsahuje neznámou značku. Povolené jsou {ROK}, {RR}, {MESIC} a {CISLO} nebo {CISLO4}.';
|
||
}
|
||
if (!preg_match('/\{CISLO\d?\}/', $maska)) {
|
||
return 'Maska musí obsahovat značku pořadového čísla, například {CISLO4}.';
|
||
}
|
||
if (preg_match_all('/\{CISLO(\d)?\}/', $maska, $shody) && count($shody[0]) > 1) {
|
||
return 'Maska může obsahovat značku pořadového čísla jen jednou.';
|
||
}
|
||
if (isset($shody[1][0]) && $shody[1][0] !== '' && ((int) $shody[1][0] < 1 || (int) $shody[1][0] > 8)) {
|
||
return 'Počet číslic u {CISLO} musí být 1 až 8, například {CISLO4}.';
|
||
}
|
||
|
||
$priklad = self::format($maska, 2026, 1, 1);
|
||
if (mb_strlen($priklad) > 20) {
|
||
return 'Podle této masky by číslo faktury přesáhlo 20 znaků.';
|
||
}
|
||
|
||
return null;
|
||
}
|
||
|
||
public static function format(string $maska, int $rok, int $mesic, int $cislo): string
|
||
{
|
||
$mesicText = str_pad((string) $mesic, 2, '0', STR_PAD_LEFT);
|
||
$vysledek = strtr($maska, [
|
||
'{ROK}' => (string) $rok,
|
||
'{RRRR}' => (string) $rok,
|
||
'{RR}' => substr((string) $rok, -2),
|
||
'{MESIC}' => $mesicText,
|
||
'{MM}' => $mesicText,
|
||
]);
|
||
|
||
return (string) preg_replace_callback(
|
||
'/\{CISLO(\d)?\}/',
|
||
static function (array $shoda) use ($cislo): string {
|
||
$text = (string) $cislo;
|
||
$sirka = ($shoda[1] ?? '') !== '' ? (int) $shoda[1] : 0;
|
||
return $sirka > 0 ? str_pad($text, $sirka, '0', STR_PAD_LEFT) : $text;
|
||
},
|
||
$vysledek
|
||
);
|
||
}
|
||
}
|