Use Laravel-Dompdf and create pdf invoices.

This commit is contained in:
2025-01-06 16:04:51 +01:00
parent fa085b7384
commit 8e0696d438
15 changed files with 872 additions and 4 deletions

View File

@@ -0,0 +1,24 @@
<?php
namespace App\Http\Controllers;
use App\Models\Invoice;
use App\Models\Option;
use Barryvdh\DomPDF\Facade\Pdf;
use Illuminate\Http\Response;
class PdfController extends Controller
{
public function downloadInvoice(int $invoice_id): Response
{
$invoice = Invoice::find($invoice_id);
$all_options = Option::all(['name', 'value']);
$options = new \stdClass();
foreach ($all_options as $option) {
$key = $option->name;
$options->$key = $option->value;
}
return Pdf::loadView('pdfs.invoice', ['invoice' => $invoice->load(['address', 'delivery']), 'options' => $options])->stream();
}
}

View File

@@ -7,6 +7,7 @@
"license": "MIT", "license": "MIT",
"require": { "require": {
"php": "^8.4", "php": "^8.4",
"barryvdh/laravel-dompdf": "^3.0",
"laravel/framework": "^11.31", "laravel/framework": "^11.31",
"laravel/sanctum": "^4.0", "laravel/sanctum": "^4.0",
"laravel/tinker": "^2.9" "laravel/tinker": "^2.9"

366
composer.lock generated
View File

@@ -4,8 +4,85 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically" "This file is @generated automatically"
], ],
"content-hash": "56fda0642f43208331e4c9898bb04606", "content-hash": "09a328fa763194a399764179c2191104",
"packages": [ "packages": [
{
"name": "barryvdh/laravel-dompdf",
"version": "v3.0.0",
"source": {
"type": "git",
"url": "https://github.com/barryvdh/laravel-dompdf.git",
"reference": "2d814cd25e299be022a4fa0fb4509d7ccd353d8a"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/barryvdh/laravel-dompdf/zipball/2d814cd25e299be022a4fa0fb4509d7ccd353d8a",
"reference": "2d814cd25e299be022a4fa0fb4509d7ccd353d8a",
"shasum": ""
},
"require": {
"dompdf/dompdf": "^3.0",
"illuminate/support": "^9|^10|^11",
"php": "^8.1"
},
"require-dev": {
"larastan/larastan": "^2.7.0",
"orchestra/testbench": "^7|^8|^9",
"phpro/grumphp": "^2.5",
"squizlabs/php_codesniffer": "^3.5"
},
"type": "library",
"extra": {
"laravel": {
"aliases": {
"PDF": "Barryvdh\\DomPDF\\Facade\\Pdf",
"Pdf": "Barryvdh\\DomPDF\\Facade\\Pdf"
},
"providers": [
"Barryvdh\\DomPDF\\ServiceProvider"
]
},
"branch-alias": {
"dev-master": "3.0-dev"
}
},
"autoload": {
"psr-4": {
"Barryvdh\\DomPDF\\": "src"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Barry vd. Heuvel",
"email": "barryvdh@gmail.com"
}
],
"description": "A DOMPDF Wrapper for Laravel",
"keywords": [
"dompdf",
"laravel",
"pdf"
],
"support": {
"issues": "https://github.com/barryvdh/laravel-dompdf/issues",
"source": "https://github.com/barryvdh/laravel-dompdf/tree/v3.0.0"
},
"funding": [
{
"url": "https://fruitcake.nl",
"type": "custom"
},
{
"url": "https://github.com/barryvdh",
"type": "github"
}
],
"time": "2024-07-31T14:45:16+00:00"
},
{ {
"name": "brick/math", "name": "brick/math",
"version": "0.12.1", "version": "0.12.1",
@@ -378,6 +455,161 @@
], ],
"time": "2024-02-05T11:56:58+00:00" "time": "2024-02-05T11:56:58+00:00"
}, },
{
"name": "dompdf/dompdf",
"version": "v3.0.2",
"source": {
"type": "git",
"url": "https://github.com/dompdf/dompdf.git",
"reference": "baf4084b27c7f4b5b7a221b19a94d11327664eb8"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/dompdf/dompdf/zipball/baf4084b27c7f4b5b7a221b19a94d11327664eb8",
"reference": "baf4084b27c7f4b5b7a221b19a94d11327664eb8",
"shasum": ""
},
"require": {
"dompdf/php-font-lib": "^1.0.0",
"dompdf/php-svg-lib": "^1.0.0",
"ext-dom": "*",
"ext-mbstring": "*",
"masterminds/html5": "^2.0",
"php": "^7.1 || ^8.0"
},
"require-dev": {
"ext-gd": "*",
"ext-json": "*",
"ext-zip": "*",
"mockery/mockery": "^1.3",
"phpunit/phpunit": "^7.5 || ^8 || ^9 || ^10 || ^11",
"squizlabs/php_codesniffer": "^3.5",
"symfony/process": "^4.4 || ^5.4 || ^6.2 || ^7.0"
},
"suggest": {
"ext-gd": "Needed to process images",
"ext-gmagick": "Improves image processing performance",
"ext-imagick": "Improves image processing performance",
"ext-zlib": "Needed for pdf stream compression"
},
"type": "library",
"autoload": {
"psr-4": {
"Dompdf\\": "src/"
},
"classmap": [
"lib/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"LGPL-2.1"
],
"authors": [
{
"name": "The Dompdf Community",
"homepage": "https://github.com/dompdf/dompdf/blob/master/AUTHORS.md"
}
],
"description": "DOMPDF is a CSS 2.1 compliant HTML to PDF converter",
"homepage": "https://github.com/dompdf/dompdf",
"support": {
"issues": "https://github.com/dompdf/dompdf/issues",
"source": "https://github.com/dompdf/dompdf/tree/v3.0.2"
},
"time": "2024-12-27T20:27:37+00:00"
},
{
"name": "dompdf/php-font-lib",
"version": "1.0.1",
"source": {
"type": "git",
"url": "https://github.com/dompdf/php-font-lib.git",
"reference": "6137b7d4232b7f16c882c75e4ca3991dbcf6fe2d"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/dompdf/php-font-lib/zipball/6137b7d4232b7f16c882c75e4ca3991dbcf6fe2d",
"reference": "6137b7d4232b7f16c882c75e4ca3991dbcf6fe2d",
"shasum": ""
},
"require": {
"ext-mbstring": "*",
"php": "^7.1 || ^8.0"
},
"require-dev": {
"symfony/phpunit-bridge": "^3 || ^4 || ^5 || ^6"
},
"type": "library",
"autoload": {
"psr-4": {
"FontLib\\": "src/FontLib"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"LGPL-2.1-or-later"
],
"authors": [
{
"name": "The FontLib Community",
"homepage": "https://github.com/dompdf/php-font-lib/blob/master/AUTHORS.md"
}
],
"description": "A library to read, parse, export and make subsets of different types of font files.",
"homepage": "https://github.com/dompdf/php-font-lib",
"support": {
"issues": "https://github.com/dompdf/php-font-lib/issues",
"source": "https://github.com/dompdf/php-font-lib/tree/1.0.1"
},
"time": "2024-12-02T14:37:59+00:00"
},
{
"name": "dompdf/php-svg-lib",
"version": "1.0.0",
"source": {
"type": "git",
"url": "https://github.com/dompdf/php-svg-lib.git",
"reference": "eb045e518185298eb6ff8d80d0d0c6b17aecd9af"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/dompdf/php-svg-lib/zipball/eb045e518185298eb6ff8d80d0d0c6b17aecd9af",
"reference": "eb045e518185298eb6ff8d80d0d0c6b17aecd9af",
"shasum": ""
},
"require": {
"ext-mbstring": "*",
"php": "^7.1 || ^8.0",
"sabberworm/php-css-parser": "^8.4"
},
"require-dev": {
"phpunit/phpunit": "^7.5 || ^8.5 || ^9.5"
},
"type": "library",
"autoload": {
"psr-4": {
"Svg\\": "src/Svg"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"LGPL-3.0-or-later"
],
"authors": [
{
"name": "The SvgLib Community",
"homepage": "https://github.com/dompdf/php-svg-lib/blob/master/AUTHORS.md"
}
],
"description": "A library to read, parse and export to PDF SVG files.",
"homepage": "https://github.com/dompdf/php-svg-lib",
"support": {
"issues": "https://github.com/dompdf/php-svg-lib/issues",
"source": "https://github.com/dompdf/php-svg-lib/tree/1.0.0"
},
"time": "2024-04-29T13:26:35+00:00"
},
{ {
"name": "dragonmantank/cron-expression", "name": "dragonmantank/cron-expression",
"version": "v3.4.0", "version": "v3.4.0",
@@ -1893,6 +2125,73 @@
], ],
"time": "2024-09-21T08:32:55+00:00" "time": "2024-09-21T08:32:55+00:00"
}, },
{
"name": "masterminds/html5",
"version": "2.9.0",
"source": {
"type": "git",
"url": "https://github.com/Masterminds/html5-php.git",
"reference": "f5ac2c0b0a2eefca70b2ce32a5809992227e75a6"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/Masterminds/html5-php/zipball/f5ac2c0b0a2eefca70b2ce32a5809992227e75a6",
"reference": "f5ac2c0b0a2eefca70b2ce32a5809992227e75a6",
"shasum": ""
},
"require": {
"ext-dom": "*",
"php": ">=5.3.0"
},
"require-dev": {
"phpunit/phpunit": "^4.8.35 || ^5.7.21 || ^6 || ^7 || ^8 || ^9"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "2.7-dev"
}
},
"autoload": {
"psr-4": {
"Masterminds\\": "src"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Matt Butcher",
"email": "technosophos@gmail.com"
},
{
"name": "Matt Farina",
"email": "matt@mattfarina.com"
},
{
"name": "Asmir Mustafic",
"email": "goetas@gmail.com"
}
],
"description": "An HTML5 parser and serializer.",
"homepage": "http://masterminds.github.io/html5-php",
"keywords": [
"HTML5",
"dom",
"html",
"parser",
"querypath",
"serializer",
"xml"
],
"support": {
"issues": "https://github.com/Masterminds/html5-php/issues",
"source": "https://github.com/Masterminds/html5-php/tree/2.9.0"
},
"time": "2024-03-31T07:05:07+00:00"
},
{ {
"name": "monolog/monolog", "name": "monolog/monolog",
"version": "3.8.0", "version": "3.8.0",
@@ -3186,6 +3485,71 @@
], ],
"time": "2024-04-27T21:32:50+00:00" "time": "2024-04-27T21:32:50+00:00"
}, },
{
"name": "sabberworm/php-css-parser",
"version": "v8.7.0",
"source": {
"type": "git",
"url": "https://github.com/MyIntervals/PHP-CSS-Parser.git",
"reference": "f414ff953002a9b18e3a116f5e462c56f21237cf"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/MyIntervals/PHP-CSS-Parser/zipball/f414ff953002a9b18e3a116f5e462c56f21237cf",
"reference": "f414ff953002a9b18e3a116f5e462c56f21237cf",
"shasum": ""
},
"require": {
"ext-iconv": "*",
"php": "^5.6.20 || ^7.0.0 || ~8.0.0 || ~8.1.0 || ~8.2.0 || ~8.3.0 || ~8.4.0"
},
"require-dev": {
"phpunit/phpunit": "5.7.27 || 6.5.14 || 7.5.20 || 8.5.40"
},
"suggest": {
"ext-mbstring": "for parsing UTF-8 CSS"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-main": "9.0.x-dev"
}
},
"autoload": {
"psr-4": {
"Sabberworm\\CSS\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Raphael Schweikert"
},
{
"name": "Oliver Klee",
"email": "github@oliverklee.de"
},
{
"name": "Jake Hotson",
"email": "jake.github@qzdesign.co.uk"
}
],
"description": "Parser for CSS Files written in PHP",
"homepage": "https://www.sabberworm.com/blog/2010/6/10/php-css-parser",
"keywords": [
"css",
"parser",
"stylesheet"
],
"support": {
"issues": "https://github.com/MyIntervals/PHP-CSS-Parser/issues",
"source": "https://github.com/MyIntervals/PHP-CSS-Parser/tree/v8.7.0"
},
"time": "2024-10-27T17:38:32+00:00"
},
{ {
"name": "symfony/clock", "name": "symfony/clock",
"version": "v7.1.6", "version": "v7.1.6",

300
config/dompdf.php Normal file
View File

@@ -0,0 +1,300 @@
<?php
return [
/*
|--------------------------------------------------------------------------
| Settings
|--------------------------------------------------------------------------
|
| Set some default values. It is possible to add all defines that can be set
| in dompdf_config.inc.php. You can also override the entire config file.
|
*/
'show_warnings' => false, // Throw an Exception on warnings from dompdf
'public_path' => null, // Override the public path if needed
/*
* Dejavu Sans font is missing glyphs for converted entities, turn it off if you need to show and £.
*/
'convert_entities' => true,
'options' => [
/**
* The location of the DOMPDF font directory
*
* The location of the directory where DOMPDF will store fonts and font metrics
* Note: This directory must exist and be writable by the webserver process.
* *Please note the trailing slash.*
*
* Notes regarding fonts:
* Additional .afm font metrics can be added by executing load_font.php from command line.
*
* Only the original "Base 14 fonts" are present on all pdf viewers. Additional fonts must
* be embedded in the pdf file or the PDF may not display correctly. This can significantly
* increase file size unless font subsetting is enabled. Before embedding a font please
* review your rights under the font license.
*
* Any font specification in the source HTML is translated to the closest font available
* in the font directory.
*
* The pdf standard "Base 14 fonts" are:
* Courier, Courier-Bold, Courier-BoldOblique, Courier-Oblique,
* Helvetica, Helvetica-Bold, Helvetica-BoldOblique, Helvetica-Oblique,
* Times-Roman, Times-Bold, Times-BoldItalic, Times-Italic,
* Symbol, ZapfDingbats.
*/
'font_dir' => storage_path('fonts'), // advised by dompdf (https://github.com/dompdf/dompdf/pull/782)
/**
* The location of the DOMPDF font cache directory
*
* This directory contains the cached font metrics for the fonts used by DOMPDF.
* This directory can be the same as DOMPDF_FONT_DIR
*
* Note: This directory must exist and be writable by the webserver process.
*/
'font_cache' => storage_path('fonts'),
/**
* The location of a temporary directory.
*
* The directory specified must be writeable by the webserver process.
* The temporary directory is required to download remote images and when
* using the PDFLib back end.
*/
'temp_dir' => sys_get_temp_dir(),
/**
* ==== IMPORTANT ====
*
* dompdf's "chroot": Prevents dompdf from accessing system files or other
* files on the webserver. All local files opened by dompdf must be in a
* subdirectory of this directory. DO NOT set it to '/' since this could
* allow an attacker to use dompdf to read any files on the server. This
* should be an absolute path.
* This is only checked on command line call by dompdf.php, but not by
* direct class use like:
* $dompdf = new DOMPDF(); $dompdf->load_html($htmldata); $dompdf->render(); $pdfdata = $dompdf->output();
*/
'chroot' => realpath(base_path()),
/**
* Protocol whitelist
*
* Protocols and PHP wrappers allowed in URIs, and the validation rules
* that determine if a resouce may be loaded. Full support is not guaranteed
* for the protocols/wrappers specified
* by this array.
*
* @var array
*/
'allowed_protocols' => [
'file://' => ['rules' => []],
'http://' => ['rules' => []],
'https://' => ['rules' => []],
],
/**
* Operational artifact (log files, temporary files) path validation
*/
'artifactPathValidation' => null,
/**
* @var string
*/
'log_output_file' => null,
/**
* Whether to enable font subsetting or not.
*/
'enable_font_subsetting' => false,
/**
* The PDF rendering backend to use
*
* Valid settings are 'PDFLib', 'CPDF' (the bundled R&OS PDF class), 'GD' and
* 'auto'. 'auto' will look for PDFLib and use it if found, or if not it will
* fall back on CPDF. 'GD' renders PDFs to graphic files.
* {@link * Canvas_Factory} ultimately determines which rendering class to
* instantiate based on this setting.
*
* Both PDFLib & CPDF rendering backends provide sufficient rendering
* capabilities for dompdf, however additional features (e.g. object,
* image and font support, etc.) differ between backends. Please see
* {@link PDFLib_Adapter} for more information on the PDFLib backend
* and {@link CPDF_Adapter} and lib/class.pdf.php for more information
* on CPDF. Also see the documentation for each backend at the links
* below.
*
* The GD rendering backend is a little different than PDFLib and
* CPDF. Several features of CPDF and PDFLib are not supported or do
* not make any sense when creating image files. For example,
* multiple pages are not supported, nor are PDF 'objects'. Have a
* look at {@link GD_Adapter} for more information. GD support is
* experimental, so use it at your own risk.
*
* @link http://www.pdflib.com
* @link http://www.ros.co.nz/pdf
* @link http://www.php.net/image
*/
'pdf_backend' => 'CPDF',
/**
* html target media view which should be rendered into pdf.
* List of types and parsing rules for future extensions:
* http://www.w3.org/TR/REC-html40/types.html
* screen, tty, tv, projection, handheld, print, braille, aural, all
* Note: aural is deprecated in CSS 2.1 because it is replaced by speech in CSS 3.
* Note, even though the generated pdf file is intended for print output,
* the desired content might be different (e.g. screen or projection view of html file).
* Therefore allow specification of content here.
*/
'default_media_type' => 'screen',
/**
* The default paper size.
*
* North America standard is "letter"; other countries generally "a4"
*
* @see CPDF_Adapter::PAPER_SIZES for valid sizes ('letter', 'legal', 'A4', etc.)
*/
'default_paper_size' => 'a4',
/**
* The default paper orientation.
*
* The orientation of the page (portrait or landscape).
*
* @var string
*/
'default_paper_orientation' => 'portrait',
/**
* The default font family
*
* Used if no suitable fonts can be found. This must exist in the font folder.
*
* @var string
*/
'default_font' => 'serif',
/**
* Image DPI setting
*
* This setting determines the default DPI setting for images and fonts. The
* DPI may be overridden for inline images by explictly setting the
* image's width & height style attributes (i.e. if the image's native
* width is 600 pixels and you specify the image's width as 72 points,
* the image will have a DPI of 600 in the rendered PDF. The DPI of
* background images can not be overridden and is controlled entirely
* via this parameter.
*
* For the purposes of DOMPDF, pixels per inch (PPI) = dots per inch (DPI).
* If a size in html is given as px (or without unit as image size),
* this tells the corresponding size in pt.
* This adjusts the relative sizes to be similar to the rendering of the
* html page in a reference browser.
*
* In pdf, always 1 pt = 1/72 inch
*
* Rendering resolution of various browsers in px per inch:
* Windows Firefox and Internet Explorer:
* SystemControl->Display properties->FontResolution: Default:96, largefonts:120, custom:?
* Linux Firefox:
* about:config *resolution: Default:96
* (xorg screen dimension in mm and Desktop font dpi settings are ignored)
*
* Take care about extra font/image zoom factor of browser.
*
* In images, <img> size in pixel attribute, img css style, are overriding
* the real image dimension in px for rendering.
*
* @var int
*/
'dpi' => 96,
/**
* Enable embedded PHP
*
* If this setting is set to true then DOMPDF will automatically evaluate embedded PHP contained
* within <script type="text/php"> ... </script> tags.
*
* ==== IMPORTANT ==== Enabling this for documents you do not trust (e.g. arbitrary remote html pages)
* is a security risk.
* Embedded scripts are run with the same level of system access available to dompdf.
* Set this option to false (recommended) if you wish to process untrusted documents.
* This setting may increase the risk of system exploit.
* Do not change this settings without understanding the consequences.
* Additional documentation is available on the dompdf wiki at:
* https://github.com/dompdf/dompdf/wiki
*
* @var bool
*/
'enable_php' => false,
/**
* Rnable inline JavaScript
*
* If this setting is set to true then DOMPDF will automatically insert JavaScript code contained
* within <script type="text/javascript"> ... </script> tags as written into the PDF.
* NOTE: This is PDF-based JavaScript to be executed by the PDF viewer,
* not browser-based JavaScript executed by Dompdf.
*
* @var bool
*/
'enable_javascript' => true,
/**
* Enable remote file access
*
* If this setting is set to true, DOMPDF will access remote sites for
* images and CSS files as required.
*
* ==== IMPORTANT ====
* This can be a security risk, in particular in combination with isPhpEnabled and
* allowing remote html code to be passed to $dompdf = new DOMPDF(); $dompdf->load_html(...);
* This allows anonymous users to download legally doubtful internet content which on
* tracing back appears to being downloaded by your server, or allows malicious php code
* in remote html pages to be executed by your server with your account privileges.
*
* This setting may increase the risk of system exploit. Do not change
* this settings without understanding the consequences. Additional
* documentation is available on the dompdf wiki at:
* https://github.com/dompdf/dompdf/wiki
*
* @var bool
*/
'enable_remote' => false,
/**
* List of allowed remote hosts
*
* Each value of the array must be a valid hostname.
*
* This will be used to filter which resources can be loaded in combination with
* isRemoteEnabled. If enable_remote is FALSE, then this will have no effect.
*
* Leave to NULL to allow any remote host.
*
* @var array|null
*/
'allowed_remote_hosts' => null,
/**
* A ratio applied to the fonts height to be more like browsers' line height
*/
'font_height_ratio' => 1.1,
/**
* Use the HTML5 Lib parser
*
* @deprecated This feature is now always on in dompdf 2.x
*
* @var bool
*/
'enable_html5_parser' => true,
],
];

View File

@@ -20,6 +20,9 @@ return [
'Email' => 'Email', 'Email' => 'Email',
'Password' => 'Passwort', 'Password' => 'Passwort',
'Phone' => 'Telefon', 'Phone' => 'Telefon',
'Phone_short' => 'Tel',
'Web_short' => 'Web',
'Email_short' => 'Email',
'Address' => 'Adresse', 'Address' => 'Adresse',
'Zip Code' => 'Postleitzahl', 'Zip Code' => 'Postleitzahl',
'City' => 'Stadt', 'City' => 'Stadt',
@@ -29,5 +32,6 @@ return [
'Confirm' => 'Bestätigen', 'Confirm' => 'Bestätigen',
'Email Password Reset Link' => 'Email Passwort-Reset Link', 'Email Password Reset Link' => 'Email Passwort-Reset Link',
'Forgot your password? No problem. Just let us know your email address and we will email you a password reset link that will allow you to choose a new one.' => 'Passwort vergessen? Kein Problem. Teilen Sie uns einfach Ihre E-Mail-Adresse mit und wir senden Ihnen per E-Mail einen Link zum Zurücksetzen Ihres Passworts, mit dem Sie ein neues Passwort auswählen können.', 'Forgot your password? No problem. Just let us know your email address and we will email you a password reset link that will allow you to choose a new one.' => 'Passwort vergessen? Kein Problem. Teilen Sie uns einfach Ihre E-Mail-Adresse mit und wir senden Ihnen per E-Mail einen Link zum Zurücksetzen Ihres Passworts, mit dem Sie ein neues Passwort auswählen können.',
'Date' => 'Datum',
]; ];

View File

@@ -43,5 +43,6 @@ return [
'Correspondence' => 'Schriftverkehr', 'Correspondence' => 'Schriftverkehr',
'Color' => 'Farbe', 'Color' => 'Farbe',
'Company logo' => 'Firmenlogo', 'Company logo' => 'Firmenlogo',
'Activity' => 'Tätigkeitsfeld',
]; ];

View File

@@ -29,9 +29,20 @@ return [
'Description' => 'Beschreibung', 'Description' => 'Beschreibung',
'State' => 'Status', 'State' => 'Status',
'Invoice Number' => 'Rechnungsnummer', 'Invoice Number' => 'Rechnungsnummer',
'Invoice Number short' => 'Rechnung-Nr.',
'Sum' => 'Summe', 'Sum' => 'Summe',
'Net' => 'Nettobetrag', 'Net' => 'Nettobetrag',
'From' => 'Von', 'From' => 'Von',
'End' => 'Bis', 'End' => 'Bis',
'Enter your invoice items. Click add for an additional invoice item.' => 'Gib Deine Rechnungspositionen ein. Klicke auf "Hinzufügen" für weitere Rechnungspositionen.', 'Enter your invoice items. Click add for an additional invoice item.' => 'Gib Deine Rechnungspositionen ein. Klicke auf "Hinzufügen" für weitere Rechnungspositionen.',
'Item position short' => 'Pos.',
'Item amount short' => 'Anz.',
'Item description' => 'Beschreibung',
'Item single price short' => 'E-Preis',
'Vat short' => 'MwSt.',
'Item total price short' => 'G-Preis',
'Net long' => 'Netto zuzüglich MwSt.',
'Gross long' => 'Gesamtpreis inkl. gesetzlicher MwSt.',
'Final sentence' => 'Bitte überweisen Sie den fälligen Rechnungsbetrag in Höhe von :sum bis spätestens :date auf das unten genannte Konto.'
]; ];

View File

@@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" {{ $attributes->merge(['class' => 'size-8 p-1']) }}>>
<path d="M64 464l48 0 0 48-48 0c-35.3 0-64-28.7-64-64L0 64C0 28.7 28.7 0 64 0L229.5 0c17 0 33.3 6.7 45.3 18.7l90.5 90.5c12 12 18.7 28.3 18.7 45.3L384 304l-48 0 0-144-80 0c-17.7 0-32-14.3-32-32l0-80L64 48c-8.8 0-16 7.2-16 16l0 384c0 8.8 7.2 16 16 16zM176 352l32 0c30.9 0 56 25.1 56 56s-25.1 56-56 56l-16 0 0 32c0 8.8-7.2 16-16 16s-16-7.2-16-16l0-48 0-80c0-8.8 7.2-16 16-16zm32 80c13.3 0 24-10.7 24-24s-10.7-24-24-24l-16 0 0 48 16 0zm96-80l32 0c26.5 0 48 21.5 48 48l0 64c0 26.5-21.5 48-48 48l-32 0c-8.8 0-16-7.2-16-16l0-128c0-8.8 7.2-16 16-16zm32 128c8.8 0 16-7.2 16-16l0-64c0-8.8-7.2-16-16-16l-16 0 0 96 16 0zm80-112c0-8.8 7.2-16 16-16l48 0c8.8 0 16 7.2 16 16s-7.2 16-16 16l-32 0 0 32 32 0c8.8 0 16 7.2 16 16s-7.2 16-16 16l-32 0 0 48c0 8.8-7.2 16-16 16s-16-7.2-16-16l0-64 0-64z"/>
</svg>

After

Width:  |  Height:  |  Size: 907 B

View File

@@ -1,8 +1,13 @@
<x-app-layout> <x-app-layout>
<x-slot name="header"> <x-slot name="header">
<h2 class="font-semibold text-xl text-gray-800 dark:text-gray-200 leading-tight"> <div class="flex flex-row">
{{ __('invoice.Invoice') }} {{ $invoice->number }} <h2 class="w-1/2 font-semibold text-xl text-gray-800 dark:text-gray-200 leading-tight">
</h2> {{ __('invoice.Invoice') }} {{ $invoice->number }}
</h2>
<p class="w-1/2 relative">
<x-pdf-icon class="text-gray-800 absolute right-0 cursor-pointer" onclick="window.open('/invoice/{{ $invoice->id }}/download', '_blank', 'popup=true')"/>
</p>
</div>
</x-slot> </x-slot>
<div class="py-12"> <div class="py-12">

View File

@@ -115,6 +115,14 @@
autocomplete="jurisdiction" autocomplete="jurisdiction"
x-model="options.jurisdiction"/> x-model="options.jurisdiction"/>
</div> </div>
<div class="flex flex-row items-center">
<x-input-label class="w-1/4" for="activity"
:value="__('configuration.Activity')"/>
<textarea id="activity" name="activity" rows="5"
class="border-gray-300 dark:border-gray-700 dark:bg-gray-900 dark:text-gray-300 focus:border-indigo-500 dark:focus:border-indigo-600 focus:ring-indigo-500 dark:focus:ring-indigo-600 rounded-md shadow-sm mt-1 block w-full"
autocomplete="activity"
x-model="options.activity"></textarea>
</div>
</form> </form>
</details> </details>
</section> </section>

View File

@@ -0,0 +1,35 @@
<div class="left" style="margin-left: 10mm; height: 45mm; width: 100mm;">
<div style="font-size: 10px;">{{ $options->company_name }}, {{ $options->address }}
, {{ $options->zip }} {{ $options->city }}</div>
<div style="margin-top: 5mm;">
<div>{{ $invoice->address->name }}</div>
<div>{{ $invoice->address->address }}</div>
<div>&nbsp;</div>
<div>{{ $invoice->address->zip }} {{ $invoice->address->city }}</div>
</div>
</div>
<div class="right" style="height: 45mm; width: 60mm; font-size: 13px; ">
<div class="left">{{ __('common.Phone_short') }}:</div>
<div class="right text-right">{{ $options->phone }}</div>
<br/>
<div class="left">{{ __('common.Email_short') }}:</div>
<div class="right text-right" style="color: {{ $options->color_1 }};">{{ $options->email }}</div>
<br/>
<div class="left">{{ __('common.Web_short') }}:</div>
<div class="right text-right" style="color: {{ $options->color_1 }};">{{ $options->website }}</div>
<br/>
<div class="text-right" style="margin-top: 5mm; color: {{ $options->color_2 }};">{!! nl2br($options->activity) !!}</div>
<br class="clear"/>
</div>
<div class="clear"></div>
<div class="left" style="width: 110mm; height:15mm;">
{{ __('invoice.Invoice Number short') }}: {{ $invoice->number }}
</div>
<div class="right" style=" width: 60mm; height:15mm;">
<div class="left">{{ __('common.Date') }}:</div>
<div class="right text-right">{{ $invoice->created }}</div>
</div>
<div class="clear"></div>

View File

@@ -0,0 +1,17 @@
<footer>
<div>
<div class="left footer-left">
<div style="font-weight: bold;">{{ __('configuration.Bank details') }}</div>
<div>{{ $options->institute_1 }} - {{ __('configuration.BIC') }}: {{ $options->bic_1 }} - {{ __('configuration.IBAN') }}: {{ $options->iban_1 }}</div>
</div>
<div class="left footer-center">
<div style="font-weight: bold">{{ __('configuration.Tax number') }}</div>
<div>{{ $options->tax_number }}</div>
</div>
<div class="right footer-right text-right">
<div style="font-weight: bold">{{ __('configuration.Jurisdiction') }}</div>
<div>{{ $options->jurisdiction }}</div>
</div>
</div>
<br class="clear"/>
</footer>

View File

@@ -0,0 +1,14 @@
<header>
<div>
<div class="left header-left">
<img class="header-logo" src="{{ $options->company_logo }}" />
</div>
<div class="right header-right text-right">
<div>{{ $options->company_name }}</div>
<div>{{ $options->representative }}</div>
<div>{{ $options->address }}</div>
<div>{{ $options->zip }} {{ $options->city }}</div>
</div>
</div>
</header>

View File

@@ -0,0 +1,79 @@
<!DOCTYPE html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
<head>
<meta charset="utf-8">
<title>{{ __('invoice.Invoice') }}</title>
<style>
@page { margin: 50mm 15mm 35mm 20mm; font-family:Figtree,ui-sans-serif,system-ui,sans-serif,"Apple Color Emoji","Segoe UI Emoji",Segoe UI Symbol,"Noto Color Emoji";font-feature-settings:normal;font-variation-settings:normal; }
header { position: fixed; top: -30mm; left: 0; right: 0; height: 25mm; }
footer { position: fixed; bottom: -25mm; left: 0; right: 0; height: 10mm; font-size: 10px; border-top: 1px solid black; padding-top: 2mm;}
.invoice { font-size: 13px; }
.invoice-header { font-weight: bold; border-bottom: 1px solid black; }
.item { border-bottom: 1px solid black; }
.header-left { width: 100mm; }
.header-right { width: 70mm; font-size: 13px; }
.header-logo { height: 20mm; }
.footer-left { width: 100mm; }
.footer-center { width: 40mm; }
.footer-right {width: 40mm; }
.text-right { text-align: right; }
.left { float: left; display: inline-block; }
.right { float: right; display: inline-block; }
.clear { clear:both; height: 0; line-height: 0; }
.page-break { page-break-after: always; }
</style>
</head>
<body>
@include('pdfs.header')
@include('pdfs.footer')
<main>
@include('pdfs.address')
<div class="invoice">
<div class="invoice-header">
<div style="width: 15mm;" class="left">{{ __('invoice.Item position short') }}</div>
<div style="width: 15mm;" class="left">{{ __('invoice.Item amount short') }}</div>
<div style="width: 85mm;" class="left">{{ __('invoice.Item description') }}</div>
<div style="width: 20mm;" class="left text-right">{{ __('invoice.Item single price short') }}</div>
<div style="width: 20mm;" class="left text-right">{{ __('invoice.Vat short') }}</div>
<div style="width: 20mm;" class="left text-right">{{ __('invoice.Item total price short') }}</div>
<br class="clear"/>
</div>
@foreach ($invoice->items as $key => $item)
<div class="item">
<div style="width: 15mm;" class="left">{{ $key + 1 }}</div>
<div style="width: 15mm;" class="left">{{ \Illuminate\Support\Number::format($item->amount) }}</div>
<div style="width: 85mm;" class="left">{{ $item->name }}</div>
<div style="width: 20mm;" class="left text-right">{{ \Illuminate\Support\Number::currency($item->price) }}</div>
<div style="width: 20mm;" class="left text-right">{{ \Illuminate\Support\Number::percentage($item->tax) }}<br/></div>
<div style="width: 20mm;" class="left text-right">{{ \Illuminate\Support\Number::currency($item->total) }}</div>
<br class="clear"/>
<div style="width: 30mm;" class="left"></div>
<div style="width: 105mm;" class="left">{{ $item->description }}</div>
<div style="width: 20mm;" class="left text-right">{{ \Illuminate\Support\Number::currency($item->amount * $item->price * $item->tax / 100) }}</div>
<br class="clear"/>
</div>
@endforeach
<div class="left" style="padding-left: 30mm; width: 105mm;">{{ __('invoice.Net long') }}</div>
<div class="left text-right" style="width: 40mm;">{{ \Illuminate\Support\Number::currency($invoice->sum - $invoice->tax) }}</div>
<br class="clear"/>
<div class="left" style="padding-left: 30mm; width: 105mm;">+ {{ __('invoice.Vat short') }}</div>
<div class="left text-right" style="width: 40mm;">{{ \Illuminate\Support\Number::currency($invoice->tax) }}</div>
<br class="clear"/>
<div class="left" style="width: 30mm;"></div>
<div class="left" style="font-weight: bold; width: 105mm; border-bottom: 1px solid black;">{{ __('invoice.Gross long') }}</div>
<div class="left text-right" style="font-weight: bold; width: 40mm; border-bottom: 1px solid black;">{{ \Illuminate\Support\Number::currency($invoice->sum) }}</div>
<br class="clear"/>
<div style="margin-top: 5mm;">{{ __('invoice.Final sentence', ['sum' => \Illuminate\Support\Number::currency($invoice->sum), 'date' => \Illuminate\Support\Carbon::parse($invoice->created_at)->addDays(14)->format('d.m.Y')]) }}</div>
</div>
</main>
</body>
</html>

View File

@@ -3,6 +3,7 @@
use App\Http\Controllers\CustomerController; use App\Http\Controllers\CustomerController;
use App\Http\Controllers\InvoiceController; use App\Http\Controllers\InvoiceController;
use App\Http\Controllers\OptionController; use App\Http\Controllers\OptionController;
use App\Http\Controllers\PdfController;
use App\Http\Controllers\ProfileController; use App\Http\Controllers\ProfileController;
use App\Http\Controllers\TaxrateController; use App\Http\Controllers\TaxrateController;
use Illuminate\Support\Facades\Route; use Illuminate\Support\Facades\Route;
@@ -24,6 +25,7 @@ Route::middleware('auth')->group(function () {
Route::resource('/taxrate', TaxrateController::class)->only(['index', 'create', 'edit']); Route::resource('/taxrate', TaxrateController::class)->only(['index', 'create', 'edit']);
Route::resource('/invoice', InvoiceController::class)->only(['index', 'create', 'show', 'edit']); Route::resource('/invoice', InvoiceController::class)->only(['index', 'create', 'show', 'edit']);
Route::get('/option', [OptionController::class, 'index'])->name('option.index'); Route::get('/option', [OptionController::class, 'index'])->name('option.index');
Route::get('/invoice/{id}/download', [PdfController::class, 'downloadInvoice'])->name('invoice.download');
}); });
require __DIR__.'/auth.php'; require __DIR__.'/auth.php';