Add multilingual PDF font system with Noto Sans and on-demand CJK packages
Bundle Noto Sans (Regular/Bold/Italic/BoldItalic) under resources/static/fonts/ as the default PDF face — it covers Latin, Cyrillic, Greek, Arabic, Thai and Hindi out of the box, replacing the limited DejaVu Sans fallback. Move all @font-face declarations into app.pdf.partials.fonts and include it from every invoice/estimate/payment/report template, dropping per-template font-family hardcodes and the conditional Thai locale include.
Introduce FontService + FontController to download static Noto Sans CJK packages (zh, zh_CN, ja, ko) from life888888/cjk-fonts-ttf on demand. GeneratesPdfTrait::ensureFontsForLocale primes the family before rendering and the partial emits @font-face rules for installed packages so dompdf resolves them through standard CSS — no separate registerFont() instance required. Static TTFs are mandatory because dompdf's PHP-Font-Lib does not parse variable fonts (fvar/gvar tables), which is why Google Fonts' NotoSansTC[wght].ttf rendered empty boxes.
Expose status/install via /api/v1/fonts/status and /api/v1/fonts/{package}/install with matching FONTS_STATUS / FONTS_INSTALL constants in scripts-v2/api/endpoints.ts. Flip DOMPDF_ENABLE_REMOTE default to true for remote asset loading.
This commit is contained in:
52
app/Http/Controllers/Admin/FontController.php
Normal file
52
app/Http/Controllers/Admin/FontController.php
Normal file
@@ -0,0 +1,52 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Admin;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Services\FontService;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
|
||||
class FontController extends Controller
|
||||
{
|
||||
public function __construct(
|
||||
private readonly FontService $fontService,
|
||||
) {}
|
||||
|
||||
public function status(): JsonResponse
|
||||
{
|
||||
$this->authorize('manage settings');
|
||||
|
||||
return response()->json([
|
||||
'packages' => $this->fontService->getPackageStatuses(),
|
||||
]);
|
||||
}
|
||||
|
||||
public function install(string $package): JsonResponse
|
||||
{
|
||||
$this->authorize('manage settings');
|
||||
|
||||
if (! isset(FontService::FONT_PACKAGES[$package])) {
|
||||
return response()->json(['error' => 'Unknown font package'], 404);
|
||||
}
|
||||
|
||||
$pkg = FontService::FONT_PACKAGES[$package];
|
||||
|
||||
if ($this->fontService->isInstalled($pkg)) {
|
||||
return response()->json(['success' => true, 'message' => 'Already installed']);
|
||||
}
|
||||
|
||||
try {
|
||||
$this->fontService->downloadPackage($pkg);
|
||||
|
||||
return response()->json([
|
||||
'success' => true,
|
||||
'installed' => true,
|
||||
]);
|
||||
} catch (\Exception $e) {
|
||||
return response()->json([
|
||||
'success' => false,
|
||||
'error' => $e->getMessage(),
|
||||
], 500);
|
||||
}
|
||||
}
|
||||
}
|
||||
260
app/Services/FontService.php
Normal file
260
app/Services/FontService.php
Normal file
@@ -0,0 +1,260 @@
|
||||
<?php
|
||||
|
||||
namespace App\Services;
|
||||
|
||||
use Illuminate\Support\Facades\File;
|
||||
use Illuminate\Support\Facades\Http;
|
||||
|
||||
class FontService
|
||||
{
|
||||
/**
|
||||
* Font packages available for on-demand download.
|
||||
*
|
||||
* Each package downloads STATIC TrueType fonts (not variable fonts) — dompdf's
|
||||
* PHP-Font-Lib does not support variable fonts (`fvar`/`gvar` tables), which is
|
||||
* why Google Fonts' `NotoSansTC[wght].ttf` produces empty boxes when registered.
|
||||
* Source: https://github.com/life888888/cjk-fonts-ttf — official Adobe Source Han
|
||||
* Sans / Noto Sans CJK rebuilt as static TTF in Regular + Bold weights.
|
||||
*/
|
||||
public const FONT_PACKAGES = [
|
||||
'noto-sans-sc' => [
|
||||
'name' => 'Noto Sans Simplified Chinese',
|
||||
'family' => 'NotoSansCJKsc',
|
||||
'locales' => ['zh_CN'],
|
||||
'size' => '~32MB',
|
||||
'files' => [
|
||||
[
|
||||
'file' => 'NotoSansCJKsc-Regular.ttf',
|
||||
'url' => 'https://github.com/life888888/cjk-fonts-ttf/releases/download/v0.1.0/NotoSansCJKsc-Regular.ttf',
|
||||
'weight' => 'normal',
|
||||
'style' => 'normal',
|
||||
],
|
||||
[
|
||||
'file' => 'NotoSansCJKsc-Bold.ttf',
|
||||
'url' => 'https://github.com/life888888/cjk-fonts-ttf/releases/download/v0.1.0/NotoSansCJKsc-Bold.ttf',
|
||||
'weight' => 'bold',
|
||||
'style' => 'normal',
|
||||
],
|
||||
],
|
||||
],
|
||||
'noto-sans-tc' => [
|
||||
'name' => 'Noto Sans Traditional Chinese',
|
||||
'family' => 'NotoSansCJKtc',
|
||||
'locales' => ['zh'],
|
||||
'size' => '~32MB',
|
||||
'files' => [
|
||||
[
|
||||
'file' => 'NotoSansCJKtc-Regular.ttf',
|
||||
'url' => 'https://github.com/life888888/cjk-fonts-ttf/releases/download/v0.1.0/NotoSansCJKtc-Regular.ttf',
|
||||
'weight' => 'normal',
|
||||
'style' => 'normal',
|
||||
],
|
||||
[
|
||||
'file' => 'NotoSansCJKtc-Bold.ttf',
|
||||
'url' => 'https://github.com/life888888/cjk-fonts-ttf/releases/download/v0.1.0/NotoSansCJKtc-Bold.ttf',
|
||||
'weight' => 'bold',
|
||||
'style' => 'normal',
|
||||
],
|
||||
],
|
||||
],
|
||||
'noto-sans-jp' => [
|
||||
'name' => 'Noto Sans Japanese',
|
||||
'family' => 'NotoSansCJKjp',
|
||||
'locales' => ['ja'],
|
||||
'size' => '~32MB',
|
||||
'files' => [
|
||||
[
|
||||
'file' => 'NotoSansCJKjp-Regular.ttf',
|
||||
'url' => 'https://github.com/life888888/cjk-fonts-ttf/releases/download/v0.1.0/NotoSansCJKjp-Regular.ttf',
|
||||
'weight' => 'normal',
|
||||
'style' => 'normal',
|
||||
],
|
||||
[
|
||||
'file' => 'NotoSansCJKjp-Bold.ttf',
|
||||
'url' => 'https://github.com/life888888/cjk-fonts-ttf/releases/download/v0.1.0/NotoSansCJKjp-Bold.ttf',
|
||||
'weight' => 'bold',
|
||||
'style' => 'normal',
|
||||
],
|
||||
],
|
||||
],
|
||||
'noto-sans-kr' => [
|
||||
'name' => 'Noto Sans Korean',
|
||||
'family' => 'NotoSansCJKkr',
|
||||
'locales' => ['ko'],
|
||||
'size' => '~32MB',
|
||||
'files' => [
|
||||
[
|
||||
'file' => 'NotoSansCJKkr-Regular.ttf',
|
||||
'url' => 'https://github.com/life888888/cjk-fonts-ttf/releases/download/v0.1.0/NotoSansCJKkr-Regular.ttf',
|
||||
'weight' => 'normal',
|
||||
'style' => 'normal',
|
||||
],
|
||||
[
|
||||
'file' => 'NotoSansCJKkr-Bold.ttf',
|
||||
'url' => 'https://github.com/life888888/cjk-fonts-ttf/releases/download/v0.1.0/NotoSansCJKkr-Bold.ttf',
|
||||
'weight' => 'bold',
|
||||
'style' => 'normal',
|
||||
],
|
||||
],
|
||||
],
|
||||
];
|
||||
|
||||
/**
|
||||
* Check if a locale requires an on-demand font download.
|
||||
*/
|
||||
public function needsDownload(string $locale): bool
|
||||
{
|
||||
$package = $this->getPackageForLocale($locale);
|
||||
|
||||
return $package && ! $this->isInstalled($package);
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensure fonts are available for the given locale.
|
||||
* Downloads synchronously if not already installed (blocking fallback).
|
||||
*/
|
||||
public function ensureFontsForLocale(string $locale): void
|
||||
{
|
||||
$package = $this->getPackageForLocale($locale);
|
||||
|
||||
if (! $package) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (! $this->isInstalled($package)) {
|
||||
$this->downloadPackage($package);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a font package is installed (all files present).
|
||||
*/
|
||||
public function isInstalled(array $package): bool
|
||||
{
|
||||
foreach ($package['files'] as $entry) {
|
||||
if (! File::exists(storage_path('fonts/'.$entry['file']))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Download a font package to storage/fonts/.
|
||||
*/
|
||||
public function downloadPackage(array $package): void
|
||||
{
|
||||
$fontsDir = storage_path('fonts');
|
||||
|
||||
if (! File::isDirectory($fontsDir)) {
|
||||
File::makeDirectory($fontsDir, 0755, true);
|
||||
}
|
||||
|
||||
foreach ($package['files'] as $entry) {
|
||||
$targetPath = $fontsDir.'/'.$entry['file'];
|
||||
|
||||
if (File::exists($targetPath)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$response = Http::timeout(180)->get($entry['url']);
|
||||
|
||||
if ($response->successful()) {
|
||||
File::put($targetPath, $response->body());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the status of all font packages (for the admin UI).
|
||||
*/
|
||||
public function getPackageStatuses(): array
|
||||
{
|
||||
$statuses = [];
|
||||
|
||||
foreach (self::FONT_PACKAGES as $key => $package) {
|
||||
$statuses[] = [
|
||||
'key' => $key,
|
||||
'name' => $package['name'],
|
||||
'family' => $package['family'],
|
||||
'locales' => $package['locales'],
|
||||
'size' => $package['size'],
|
||||
'installed' => $this->isInstalled($package),
|
||||
];
|
||||
}
|
||||
|
||||
return $statuses;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate @font-face CSS rules for all installed on-demand fonts.
|
||||
* Used by the PDF fonts partial so dompdf can resolve CJK families
|
||||
* via standard CSS — no separate registerFont() dance required.
|
||||
*/
|
||||
public function getInstalledFontFaces(): array
|
||||
{
|
||||
$faces = [];
|
||||
$fontsDir = storage_path('fonts');
|
||||
|
||||
foreach (self::FONT_PACKAGES as $package) {
|
||||
if (! $this->isInstalled($package)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach ($package['files'] as $entry) {
|
||||
$filePath = $fontsDir.'/'.$entry['file'];
|
||||
|
||||
$faces[] = "@font-face {
|
||||
font-family: '{$package['family']}';
|
||||
font-style: {$entry['style']};
|
||||
font-weight: {$entry['weight']};
|
||||
src: url(\"{$filePath}\") format('truetype');
|
||||
}";
|
||||
}
|
||||
}
|
||||
|
||||
return $faces;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the primary font family for the current locale.
|
||||
*
|
||||
* DomPDF doesn't support font-family fallback for missing glyphs —
|
||||
* it uses the first font for ALL characters. So CJK locales must
|
||||
* use the CJK font as the primary, not as a fallback.
|
||||
*/
|
||||
public function getFontFamilyForLocale(?string $locale = null): string
|
||||
{
|
||||
$locale = $locale ?? app()->getLocale();
|
||||
|
||||
// Check if this locale has an installed on-demand font
|
||||
$package = $this->getPackageForLocale($locale);
|
||||
if ($package && $this->isInstalled($package)) {
|
||||
return '"'.$package['family'].'"';
|
||||
}
|
||||
|
||||
return '"NotoSans"';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the full font-family CSS value for the current locale.
|
||||
*/
|
||||
public function getFontFamilyChain(?string $locale = null): string
|
||||
{
|
||||
$primary = $this->getFontFamilyForLocale($locale);
|
||||
|
||||
return $primary.', "NotoSans", "DejaVu Sans", sans-serif';
|
||||
}
|
||||
|
||||
private function getPackageForLocale(string $locale): ?array
|
||||
{
|
||||
foreach (self::FONT_PACKAGES as $package) {
|
||||
if (in_array($locale, $package['locales'])) {
|
||||
return $package;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -6,6 +6,7 @@ use App\Models\Address;
|
||||
use App\Models\CompanySetting;
|
||||
use App\Models\FileDisk;
|
||||
use App\Models\Setting;
|
||||
use App\Services\FontService;
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Support\Facades\App;
|
||||
|
||||
@@ -24,6 +25,7 @@ trait GeneratesPdfTrait
|
||||
$locale = CompanySetting::getSetting('language', $this->company_id);
|
||||
|
||||
App::setLocale($locale);
|
||||
app(FontService::class)->ensureFontsForLocale($locale);
|
||||
|
||||
$pdf = $this->getPDFData();
|
||||
|
||||
@@ -78,6 +80,7 @@ trait GeneratesPdfTrait
|
||||
$locale = CompanySetting::getSetting('language', $this->company_id);
|
||||
|
||||
App::setLocale($locale);
|
||||
app(FontService::class)->ensureFontsForLocale($locale);
|
||||
|
||||
$pdf = $this->getPDFData();
|
||||
|
||||
|
||||
@@ -227,7 +227,7 @@ return [
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
'enable_remote' => env('DOMPDF_ENABLE_REMOTE', false),
|
||||
'enable_remote' => env('DOMPDF_ENABLE_REMOTE', true),
|
||||
|
||||
/**
|
||||
* A ratio applied to the fonts height to be more like browsers' line height
|
||||
|
||||
13
lang/en.json
13
lang/en.json
@@ -889,6 +889,7 @@
|
||||
"update_app": "Update App",
|
||||
"backup": "Backup",
|
||||
"file_disk": "File Disk",
|
||||
"fonts": "Fonts",
|
||||
"custom_fields": "Custom Fields",
|
||||
"payment_modes": "Payment Modes",
|
||||
"notes": "Record Notes",
|
||||
@@ -1350,6 +1351,18 @@
|
||||
"december_november": "December - November"
|
||||
}
|
||||
},
|
||||
"fonts": {
|
||||
"title": "PDF Fonts",
|
||||
"description": "Manage fonts used for PDF generation. Noto Sans is bundled and covers most languages. Additional font packages can be installed for CJK languages.",
|
||||
"bundled_info": "Noto Sans (bundled) covers Latin, Cyrillic, Greek, Arabic, Thai, Hindi, and most other scripts. Install additional packages below for CJK language support.",
|
||||
"installed": "Installed",
|
||||
"install": "Install",
|
||||
"downloading": "Downloading...",
|
||||
"download_started": "Downloading {name}. This may take a moment.",
|
||||
"download_complete": "{name} installed successfully. PDFs will now use this font.",
|
||||
"download_failed": "Failed to download {name}. Please try again.",
|
||||
"no_packages": "No additional font packages available."
|
||||
},
|
||||
"update_app": {
|
||||
"title": "Update App",
|
||||
"description": "You can easily update InvoiceShelf by checking for a new update by clicking the button below",
|
||||
|
||||
@@ -122,6 +122,10 @@ export const API = {
|
||||
BACKUPS: '/api/v1/backups',
|
||||
DOWNLOAD_BACKUP: '/api/v1/download-backup',
|
||||
|
||||
// Fonts
|
||||
FONTS_STATUS: '/api/v1/fonts/status',
|
||||
FONTS_INSTALL: '/api/v1/fonts',
|
||||
|
||||
// Exchange Rates & Currencies
|
||||
CURRENCIES: '/api/v1/currencies',
|
||||
CURRENCIES_USED: '/api/v1/currencies/used',
|
||||
|
||||
BIN
resources/static/fonts/NotoSans-Bold.ttf
Normal file
BIN
resources/static/fonts/NotoSans-Bold.ttf
Normal file
Binary file not shown.
BIN
resources/static/fonts/NotoSans-BoldItalic.ttf
Normal file
BIN
resources/static/fonts/NotoSans-BoldItalic.ttf
Normal file
Binary file not shown.
BIN
resources/static/fonts/NotoSans-Italic.ttf
Normal file
BIN
resources/static/fonts/NotoSans-Italic.ttf
Normal file
Binary file not shown.
BIN
resources/static/fonts/NotoSans-Regular.ttf
Normal file
BIN
resources/static/fonts/NotoSans-Regular.ttf
Normal file
Binary file not shown.
@@ -5,10 +5,11 @@
|
||||
<title>@lang('pdf_estimate_label') - {{ $estimate->estimate_number }}</title>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
|
||||
@include("app.pdf.partials.fonts")
|
||||
|
||||
<style type="text/css">
|
||||
/* -- Base -- */
|
||||
body {
|
||||
font-family: "DejaVu Sans";
|
||||
}
|
||||
|
||||
html {
|
||||
@@ -387,9 +388,6 @@
|
||||
|
||||
</style>
|
||||
|
||||
@if (App::isLocale('th'))
|
||||
@include('app.pdf.locale.th')
|
||||
@endif
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
@@ -4,10 +4,11 @@
|
||||
<head>
|
||||
<title>@lang('pdf_estimate_label') - {{ $estimate->estimate_number }}</title>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
@include("app.pdf.partials.fonts")
|
||||
|
||||
<style type="text/css">
|
||||
/* -- Base -- */
|
||||
body {
|
||||
font-family: "DejaVu Sans";
|
||||
}
|
||||
|
||||
html {
|
||||
@@ -77,7 +78,6 @@
|
||||
font-size: 24px;
|
||||
line-height: 36px;
|
||||
text-align: right;
|
||||
font-family: "DejaVu Sans";
|
||||
}
|
||||
|
||||
.estimate-details-container h4 {
|
||||
@@ -409,9 +409,6 @@
|
||||
|
||||
</style>
|
||||
|
||||
@if (App::isLocale('th'))
|
||||
@include('app.pdf.locale.th')
|
||||
@endif
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
@@ -5,10 +5,11 @@
|
||||
<title>@lang('pdf_estimate_label') - {{ $estimate->estimate_number }}</title>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
|
||||
@include("app.pdf.partials.fonts")
|
||||
|
||||
<style type="text/css">
|
||||
/* -- Base -- */
|
||||
body {
|
||||
font-family: "DejaVu Sans";
|
||||
}
|
||||
|
||||
html {
|
||||
@@ -347,9 +348,6 @@
|
||||
|
||||
</style>
|
||||
|
||||
@if (App::isLocale('th'))
|
||||
@include('app.pdf.locale.th')
|
||||
@endif
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
@@ -5,10 +5,11 @@
|
||||
<title>@lang('pdf_invoice_label') - {{ $invoice->invoice_number }}</title>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
|
||||
@include("app.pdf.partials.fonts")
|
||||
|
||||
<style type="text/css">
|
||||
/* -- Base -- */
|
||||
body {
|
||||
font-family: "DejaVu Sans";
|
||||
}
|
||||
|
||||
html {
|
||||
|
||||
@@ -4,10 +4,11 @@
|
||||
<head>
|
||||
<title>@lang('pdf_invoice_label') - {{ $invoice->invoice_number }}</title>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
@include("app.pdf.partials.fonts")
|
||||
|
||||
<style type="text/css">
|
||||
/* -- Base -- */
|
||||
body {
|
||||
font-family: "DejaVu Sans";
|
||||
}
|
||||
|
||||
html {
|
||||
@@ -379,9 +380,6 @@
|
||||
|
||||
</style>
|
||||
|
||||
@if (App::isLocale('th'))
|
||||
@include('app.pdf.locale.th')
|
||||
@endif
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
@@ -5,11 +5,12 @@
|
||||
<title>@lang('pdf_invoice_label') - {{ $invoice->invoice_number }}</title>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
|
||||
@include("app.pdf.partials.fonts")
|
||||
|
||||
<style type="text/css">
|
||||
/* -- Base -- */
|
||||
|
||||
body {
|
||||
font-family: "DejaVu Sans";
|
||||
}
|
||||
|
||||
html {
|
||||
@@ -308,9 +309,6 @@
|
||||
|
||||
</style>
|
||||
|
||||
@if (App::isLocale('th'))
|
||||
@include('app.pdf.locale.th')
|
||||
@endif
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
37
resources/views/app/pdf/partials/fonts.blade.php
Normal file
37
resources/views/app/pdf/partials/fonts.blade.php
Normal file
@@ -0,0 +1,37 @@
|
||||
{{-- Bundled Noto Sans — covers Latin, Cyrillic, Greek, Arabic, Thai, Hindi, and most scripts --}}
|
||||
<style type="text/css">
|
||||
@font-face {
|
||||
font-family: 'NotoSans';
|
||||
font-style: normal;
|
||||
font-weight: normal;
|
||||
src: url("{{ resource_path('static/fonts/NotoSans-Regular.ttf') }}") format('truetype');
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'NotoSans';
|
||||
font-style: normal;
|
||||
font-weight: bold;
|
||||
src: url("{{ resource_path('static/fonts/NotoSans-Bold.ttf') }}") format('truetype');
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'NotoSans';
|
||||
font-style: italic;
|
||||
font-weight: normal;
|
||||
src: url("{{ resource_path('static/fonts/NotoSans-Italic.ttf') }}") format('truetype');
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'NotoSans';
|
||||
font-style: italic;
|
||||
font-weight: bold;
|
||||
src: url("{{ resource_path('static/fonts/NotoSans-BoldItalic.ttf') }}") format('truetype');
|
||||
}
|
||||
|
||||
{{-- On-demand CJK @font-face rules (only emitted for installed packages). --}}
|
||||
{!! implode("\n", app(\App\Services\FontService::class)->getInstalledFontFaces()) !!}
|
||||
|
||||
body {
|
||||
font-family: {!! app(\App\Services\FontService::class)->getFontFamilyChain() !!};
|
||||
}
|
||||
</style>
|
||||
@@ -5,10 +5,11 @@
|
||||
<title>@lang('pdf_payment_label') - {{ $payment->payment_number }}</title>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
|
||||
@include("app.pdf.partials.fonts")
|
||||
|
||||
<style type="text/css">
|
||||
/* -- Base -- */
|
||||
body {
|
||||
font-family: "DejaVu Sans";
|
||||
}
|
||||
|
||||
html {
|
||||
@@ -277,9 +278,6 @@
|
||||
|
||||
</style>
|
||||
|
||||
@if (App::isLocale('th'))
|
||||
@include('app.pdf.locale.th')
|
||||
@endif
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
@@ -3,9 +3,10 @@
|
||||
|
||||
<head>
|
||||
<title>@lang('pdf_expense_report_label')</title>
|
||||
@include("app.pdf.partials.fonts")
|
||||
|
||||
<style type="text/css">
|
||||
body {
|
||||
font-family: "DejaVu Sans";
|
||||
}
|
||||
|
||||
table {
|
||||
@@ -135,9 +136,6 @@
|
||||
}
|
||||
</style>
|
||||
|
||||
@if (App::isLocale('th'))
|
||||
@include('app.pdf.locale.th')
|
||||
@endif
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
@@ -3,9 +3,10 @@
|
||||
|
||||
<head>
|
||||
<title>@lang('pdf_profit_loss_label')</title>
|
||||
@include("app.pdf.partials.fonts")
|
||||
|
||||
<style type="text/css">
|
||||
body {
|
||||
font-family: "DejaVu Sans";
|
||||
}
|
||||
|
||||
table {
|
||||
@@ -160,9 +161,6 @@
|
||||
}
|
||||
</style>
|
||||
|
||||
@if (App::isLocale('th'))
|
||||
@include('app.pdf.locale.th')
|
||||
@endif
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
@@ -3,9 +3,10 @@
|
||||
|
||||
<head>
|
||||
<title>@lang('pdf_sales_customers_label')</title>
|
||||
@include("app.pdf.partials.fonts")
|
||||
|
||||
<style type="text/css">
|
||||
body {
|
||||
font-family: "DejaVu Sans";
|
||||
}
|
||||
|
||||
table {
|
||||
@@ -139,9 +140,6 @@
|
||||
}
|
||||
</style>
|
||||
|
||||
@if (App::isLocale('th'))
|
||||
@include('app.pdf.locale.th')
|
||||
@endif
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
@@ -3,9 +3,10 @@
|
||||
|
||||
<head>
|
||||
<title>@lang('pdf_sales_items_label')</title>
|
||||
@include("app.pdf.partials.fonts")
|
||||
|
||||
<style type="text/css">
|
||||
body {
|
||||
font-family: "DejaVu Sans";
|
||||
}
|
||||
|
||||
table {
|
||||
@@ -139,9 +140,6 @@
|
||||
}
|
||||
</style>
|
||||
|
||||
@if (App::isLocale('th'))
|
||||
@include('app.pdf.locale.th')
|
||||
@endif
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
@@ -3,9 +3,10 @@
|
||||
|
||||
<head>
|
||||
<title>@lang('pdf_tax_summery_label')</title>
|
||||
@include("app.pdf.partials.fonts")
|
||||
|
||||
<style type="text/css">
|
||||
body {
|
||||
font-family: "DejaVu Sans";
|
||||
}
|
||||
|
||||
table {
|
||||
@@ -136,9 +137,6 @@
|
||||
}
|
||||
</style>
|
||||
|
||||
@if (App::isLocale('th'))
|
||||
@include('app.pdf.locale.th')
|
||||
@endif
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
@@ -5,6 +5,7 @@ use App\Http\Controllers\Admin\BackupsController;
|
||||
use App\Http\Controllers\Admin\CompaniesController;
|
||||
use App\Http\Controllers\Admin\CountriesController;
|
||||
use App\Http\Controllers\Admin\CurrenciesController;
|
||||
use App\Http\Controllers\Admin\FontController;
|
||||
use App\Http\Controllers\Admin\Modules\ModuleInstallationController;
|
||||
use App\Http\Controllers\Admin\Modules\ModulesController;
|
||||
use App\Http\Controllers\Admin\Settings\DiskController;
|
||||
@@ -349,6 +350,12 @@ Route::prefix('/v1')->group(function () {
|
||||
Route::get('/disk/purposes', [DiskController::class, 'getDiskPurposes']);
|
||||
Route::put('/disk/purposes', [DiskController::class, 'updateDiskPurposes']);
|
||||
|
||||
// Fonts
|
||||
// ----------------------------------
|
||||
|
||||
Route::get('/fonts/status', [FontController::class, 'status']);
|
||||
Route::post('/fonts/{package}/install', [FontController::class, 'install']);
|
||||
|
||||
// Exchange Rate
|
||||
// ----------------------------------
|
||||
|
||||
|
||||
Reference in New Issue
Block a user