Kufrik/app/Model/Faktura/FakturaCislovani.php

90 lines
3.0 KiB
PHP
Raw Permalink Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

<?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
);
}
}