'převodem', 2 => 'hotově', ]; public function __construct( private LatteFactory $latteFactory, private string $tempDir, ) { } /** * @param array $polozky */ public function render(object $faktura, array $polozky, bool $autoPrint = false): string { $view = $this->view($faktura, $polozky); $html = $this->latteFactory->create()->renderToString($this->templateFile(), $view); $mpdf = $this->createMpdf(); $mpdf->SetHTMLFooter($this->footer((string) $view['vytisteno'])); $mpdf->SetTitle('Faktura ' . (string) ($faktura->CISLO ?? '')); $mpdf->SetAuthor('Kufřík'); if ($autoPrint) { $mpdf->SetJS('this.print();'); } $mpdf->WriteHTML($html); return $mpdf->Output('', Destination::STRING_RETURN); } public static function fileName(string $cislo): string { $safe = preg_replace('/[^\p{L}\p{N}._-]+/u', '_', trim($cislo)) ?? ''; $safe = trim($safe, '._'); return 'Faktura_' . ($safe !== '' ? $safe : 'doklad') . '.pdf'; } /** * @param array $polozky * @return array */ private function view(object $faktura, array $polozky): array { $radky = []; $celkem = 0.0; foreach ($polozky as $polozka) { $cena = (float) ($polozka->CENA ?? 0); $celkem += $cena; $radky[] = [ 'nazev' => (string) ($polozka->NAZEV ?? ''), 'pocet' => self::formatQty($polozka->POCET ?? 0), 'jednotka' => (string) ($polozka->JEDNOTKA ?? ''), 'cenaJednotka' => self::formatMoney($polozka->CENA_JEDNOTKA ?? 0), 'sleva' => self::formatQty($polozka->SLEVA ?? 0) . ' %', 'cena' => self::formatMoney($cena), ]; } $cinnosti = trim((string) ($faktura->CINNOSTI ?? '')); return [ 'cislo' => (string) ($faktura->CISLO ?? ''), 'dodavatel' => [ 'nazev' => (string) ($faktura->D_PRAJM ?? ''), 'ulice' => (string) ($faktura->D_ULICE ?? ''), 'psc' => (string) ($faktura->D_PSC ?? ''), 'mesto' => (string) ($faktura->D_MESTO ?? ''), 'telefon' => (string) ($faktura->D_TELEFON ?? ''), 'email' => (string) ($faktura->D_EMAIL ?? ''), 'web' => (string) ($faktura->D_WEB ?? ''), 'ic' => (string) ($faktura->D_IC ?? ''), 'ucet' => (string) ($faktura->D_BANKA ?? ''), ], 'odberatel' => [ 'nazev' => (string) ($faktura->O_PRAJM ?? ''), 'ulice' => (string) ($faktura->O_ULICE ?? ''), 'psc' => (string) ($faktura->O_PSC ?? ''), 'mesto' => (string) ($faktura->O_MESTO ?? ''), 'ic' => (string) ($faktura->O_IC ?? ''), 'dic' => self::formatDic($faktura->O_DIC ?? null), ], 'datumVystaveni' => self::formatDate($faktura->DATUM_VYSTAVENI ?? null), 'datumSplatnosti' => self::formatDate($faktura->DATUM_SPLATNOSTI ?? null), 'formaUhrady' => self::FORMY_UHRADY[(int) ($faktura->FORMA_UHRADY ?? 0)] ?? '', 'polozky' => $radky, 'celkem' => 'Celkem: ' . self::formatMoney($celkem), 'cinnosti' => $cinnosti === '' ? [] : (preg_split("/\R/u", $cinnosti) ?: []), 'vytisteno' => (new \DateTimeImmutable('today'))->format('d.m.Y'), ]; } private function createMpdf(): Mpdf { $tempDir = $this->tempDir . DIRECTORY_SEPARATOR . 'mpdf'; FileSystem::createDir($tempDir); $fontDir = dirname(__DIR__, 3) . DIRECTORY_SEPARATOR . 'resources' . DIRECTORY_SEPARATOR . 'fonts'; $config = (new ConfigVariables())->getDefaults(); $fontData = (new FontVariables())->getDefaults(); return new Mpdf([ 'mode' => 'utf-8', 'format' => 'A4', 'margin_left' => 18, 'margin_right' => 16, 'margin_top' => 16, 'margin_bottom' => 18, 'margin_footer' => 8, 'default_font' => 'sourcesans3', 'default_font_size' => 9, 'tempDir' => $tempDir, 'shrink_tables_to_fit' => 0, 'fontDir' => array_merge($config['fontDir'], [$fontDir]), 'fontdata' => $fontData['fontdata'] + [ 'sourcesans3' => [ 'R' => 'SourceSans3-Regular.ttf', 'B' => 'SourceSans3-Bold.ttf', 'I' => 'SourceSans3-It.ttf', 'BI' => 'SourceSans3-BoldIt.ttf', ], ], ]); } private function footer(string $vytisteno): string { $datum = htmlspecialchars($vytisteno, ENT_QUOTES, 'UTF-8'); return '
Vytvořeno aplikací Kufřík Vytištěno dne: ' . $datum . '. Strana {PAGENO}/{nbpg}
'; } private function templateFile(): string { return __DIR__ . DIRECTORY_SEPARATOR . 'faktura.latte'; } private static function formatDate(mixed $value): string { if ($value instanceof \DateTimeInterface) { return $value->format('d.m.Y'); } if (!is_string($value) || trim($value) === '') { return ''; } $timestamp = strtotime($value); return $timestamp ? date('d.m.Y', $timestamp) : $value; } private static function formatMoney(mixed $value): string { return number_format((float) $value, 2, ',', ' ') . ' Kč'; } private static function formatQty(mixed $value): string { $formatted = number_format((float) $value, 2, ',', ' '); return rtrim(rtrim($formatted, '0'), ','); } private static function formatDic(mixed $value): string { $dic = trim((string) $value); if ($dic === '' || preg_match('/^[A-Za-z]{2}/', $dic)) { return $dic; } return 'CZ' . $dic; } }