Add pdf generator
This commit is contained in:
parent
7c190d7bcf
commit
3406cf22f9
|
@ -16,8 +16,8 @@ npm-debug.log
|
||||||
yarn-error.log
|
yarn-error.log
|
||||||
tags
|
tags
|
||||||
/resources/js/libs
|
/resources/js/libs
|
||||||
/packages
|
|
||||||
/public/vendor
|
/public/vendor
|
||||||
|
/storage/temp
|
||||||
|
|
||||||
# Temporary files
|
# Temporary files
|
||||||
*.swp
|
*.swp
|
||||||
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
[submodule "packages/silvaletter"]
|
||||||
|
path = packages/silvaletter
|
||||||
|
url = git@zoomyboy.de:silvaletter.git
|
|
@ -2,12 +2,12 @@
|
||||||
|
|
||||||
namespace App\Http\Views;
|
namespace App\Http\Views;
|
||||||
|
|
||||||
use App\Member\MemberResource;
|
|
||||||
use App\Member\Member;
|
use App\Member\Member;
|
||||||
use Illuminate\Http\Request;
|
use App\Member\MemberResource;
|
||||||
|
use App\Payment\PaymentResource;
|
||||||
use App\Payment\Status;
|
use App\Payment\Status;
|
||||||
use App\Payment\Subscription;
|
use App\Payment\Subscription;
|
||||||
use App\Payment\PaymentResource;
|
use Illuminate\Http\Request;
|
||||||
|
|
||||||
class MemberView {
|
class MemberView {
|
||||||
public function index(Request $request) {
|
public function index(Request $request) {
|
||||||
|
|
|
@ -31,4 +31,14 @@ class BillType implements PdfRepository
|
||||||
return $this->filename;
|
return $this->filename;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getView(): string
|
||||||
|
{
|
||||||
|
return 'tex.bill';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getTemplate(): string
|
||||||
|
{
|
||||||
|
return 'default';
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,7 +15,7 @@ class MemberPdfController extends Controller
|
||||||
|
|
||||||
return $repo === null
|
return $repo === null
|
||||||
? response()->noContent()
|
? response()->noContent()
|
||||||
: app(PdfGenerator::class)->render($repo);
|
: app(PdfGenerator::class)->setRepository($repo)->render();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,29 +3,64 @@
|
||||||
namespace App\Pdf;
|
namespace App\Pdf;
|
||||||
|
|
||||||
use Illuminate\Contracts\Support\Responsable;
|
use Illuminate\Contracts\Support\Responsable;
|
||||||
|
use Illuminate\Support\Str;
|
||||||
use Storage;
|
use Storage;
|
||||||
|
|
||||||
class PdfGenerator implements Responsable
|
class PdfGenerator implements Responsable
|
||||||
{
|
{
|
||||||
|
|
||||||
private ?string $filename = null;
|
private ?string $filename = null;
|
||||||
|
private PdfRepository $repo;
|
||||||
|
private string $dir;
|
||||||
|
|
||||||
public function render(PdfRepository $repo): self
|
public function setRepository(PdfRepository $repo): self
|
||||||
{
|
{
|
||||||
$content = view()->make('pdf.pdf', [
|
$this->repo = $repo;
|
||||||
'data' => $repo,
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function render(): self
|
||||||
|
{
|
||||||
|
$this->filename = $this->repo->getFilename();
|
||||||
|
$this->dir = Str::random(32);
|
||||||
|
|
||||||
|
Storage::disk('temp')->put($this->dir.'/'.$this->repo->getFilename().'.tex', $this->compileView());
|
||||||
|
Storage::disk('temp')->makeDirectory($this->dir);
|
||||||
|
|
||||||
|
$this->copyTemplateTo(Storage::disk('temp')->path($this->dir));
|
||||||
|
|
||||||
|
$command = 'cd '.Storage::disk('temp')->path($this->dir);
|
||||||
|
$command .= ' && '.env('XELATEX').' --halt-on-error '.$this->repo->getFilename().'.tex';
|
||||||
|
exec($command, $output, $returnVar);
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function compileView(): string
|
||||||
|
{
|
||||||
|
return (string) view()->make($this->repo->getView(), [
|
||||||
|
'data' => $this->repo,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$filename = $repo->getFilename();
|
|
||||||
dd($filename);
|
|
||||||
|
|
||||||
Storage::disk('temp')->put($repo->getBasename(), $content);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function toResponse($request)
|
public function toResponse($request)
|
||||||
{
|
{
|
||||||
return response()->file($this->filename);
|
return response()->file($this->getCompiledFilename(), [
|
||||||
|
'Content-Type' => 'application/pdf',
|
||||||
|
'Content-Disposition' => "inline; filename=\"{$this->filename}.pdf\"",
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getCompiledFilename(): string
|
||||||
|
{
|
||||||
|
return Storage::disk('temp')->path($this->dir.'/'.$this->filename.'.pdf');
|
||||||
|
}
|
||||||
|
|
||||||
|
private function copyTemplateTo(string $destination): void
|
||||||
|
{
|
||||||
|
$templatePath = resource_path("views/tex/templates/{$this->repo->getTemplate()}");
|
||||||
|
exec('cp '.$templatePath.'/* '.$destination);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -13,4 +13,8 @@ interface PdfRepository
|
||||||
|
|
||||||
public function getFilename(): string;
|
public function getFilename(): string;
|
||||||
|
|
||||||
|
public function getView(): string;
|
||||||
|
|
||||||
|
public function getTemplate(): string;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -176,6 +176,7 @@ return [
|
||||||
App\Providers\HorizonServiceProvider::class,
|
App\Providers\HorizonServiceProvider::class,
|
||||||
App\Providers\RouteServiceProvider::class,
|
App\Providers\RouteServiceProvider::class,
|
||||||
App\Providers\TelescopeServiceProvider::class,
|
App\Providers\TelescopeServiceProvider::class,
|
||||||
|
App\Tex\TexServiceProvider::class,
|
||||||
|
|
||||||
],
|
],
|
||||||
|
|
||||||
|
|
|
@ -48,6 +48,11 @@ return [
|
||||||
'root' => storage_path('app'),
|
'root' => storage_path('app'),
|
||||||
],
|
],
|
||||||
|
|
||||||
|
'temp' => [
|
||||||
|
'driver' => 'local',
|
||||||
|
'root' => storage_path('temp'),
|
||||||
|
],
|
||||||
|
|
||||||
'public' => [
|
'public' => [
|
||||||
'driver' => 'local',
|
'driver' => 'local',
|
||||||
'root' => storage_path('app/public'),
|
'root' => storage_path('app/public'),
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
Subproject commit 63fb0c9daed5648bc2bf06a0361d95cd586db17f
|
|
@ -1,6 +1,6 @@
|
||||||
\documentclass[silvaletter,12pt]{scrlttr2}
|
\documentclass[silvaletter,12pt]{scrlttr2}
|
||||||
|
|
||||||
\setkomavar{subject}{<-- $subject -->}
|
\setkomavar{subject}{Rechnung}
|
||||||
|
|
||||||
\begin{document}
|
\begin{document}
|
||||||
\begin{letter}{Familie Charnay\\Junkerstr 4\\42699 Solingen}
|
\begin{letter}{Familie Charnay\\Junkerstr 4\\42699 Solingen}
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
../../../../packages/silvaletter/template
|
|
@ -21,6 +21,7 @@ Route::group(['middleware' => 'auth:web'], function () {
|
||||||
Route::resource('allpayment', AllpaymentController::class);
|
Route::resource('allpayment', AllpaymentController::class);
|
||||||
Route::resource('subscription', SubscriptionController::class);
|
Route::resource('subscription', SubscriptionController::class);
|
||||||
Route::post('/member/{member}/confirm', MemberConfirmController::class);
|
Route::post('/member/{member}/confirm', MemberConfirmController::class);
|
||||||
Route::post('/member/{member}/pdf', MemberPdfController::class)->name('member.singlepdf');
|
Route::get('/member/{member}/pdf', MemberPdfController::class)
|
||||||
|
->name('member.singlepdf');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -10,6 +10,8 @@ use App\Nationality;
|
||||||
use App\Payment\Payment;
|
use App\Payment\Payment;
|
||||||
use App\Payment\Subscription;
|
use App\Payment\Subscription;
|
||||||
use App\Pdf\BillType;
|
use App\Pdf\BillType;
|
||||||
|
use App\Pdf\PdfGenerator;
|
||||||
|
use App\Pdf\PdfRepositoryFactory;
|
||||||
use Database\Factories\Member\MemberFactory;
|
use Database\Factories\Member\MemberFactory;
|
||||||
use Database\Factories\Payment\PaymentFactory;
|
use Database\Factories\Payment\PaymentFactory;
|
||||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||||
|
@ -22,13 +24,11 @@ class GenerateTest extends TestCase
|
||||||
{
|
{
|
||||||
|
|
||||||
use RefreshDatabase;
|
use RefreshDatabase;
|
||||||
use FakesTex;
|
|
||||||
|
|
||||||
public function setUp(): void
|
public function setUp(): void
|
||||||
{
|
{
|
||||||
parent::setUp();
|
parent::setUp();
|
||||||
|
|
||||||
$this->fakeTex();
|
|
||||||
Storage::fake('temp');
|
Storage::fake('temp');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -63,7 +63,7 @@ class GenerateTest extends TestCase
|
||||||
'type' => BillType::class,
|
'type' => BillType::class,
|
||||||
'filename' => 'rechnung-fur-firstname-lastname.pdf',
|
'filename' => 'rechnung-fur-firstname-lastname.pdf',
|
||||||
'output' => [
|
'output' => [
|
||||||
'12,00 €',
|
'12.00',
|
||||||
'Familie ::lastname::',
|
'Familie ::lastname::',
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
|
@ -80,8 +80,55 @@ class GenerateTest extends TestCase
|
||||||
): void {
|
): void {
|
||||||
$this->withoutExceptionHandling();
|
$this->withoutExceptionHandling();
|
||||||
$this->login();
|
$this->login();
|
||||||
|
$members = $this->setupMembers($members);
|
||||||
|
|
||||||
$members = collect($members)->map(function (array $member): Member {
|
$urlId = call_user_func($urlCallable, $members);
|
||||||
|
$response = $this->call('GET', "/member/{$urlId}/pdf", [
|
||||||
|
'type' => $type,
|
||||||
|
]);
|
||||||
|
|
||||||
|
if ($filename === null) {
|
||||||
|
$response->assertStatus(204);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->assertEquals('application/pdf', $response->headers->get('content-type'));
|
||||||
|
$this->assertEquals('inline; filename="' . $filename . '"', $response->headers->get('content-disposition'));
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @dataProvider generatorProvider */
|
||||||
|
public function testItGeneratesTheLayout(
|
||||||
|
array $members,
|
||||||
|
callable $urlCallable,
|
||||||
|
string $type,
|
||||||
|
?string $filename = null,
|
||||||
|
?array $output = null
|
||||||
|
): void {
|
||||||
|
$this->withoutExceptionHandling();
|
||||||
|
$this->login();
|
||||||
|
$members = $this->setupMembers($members);
|
||||||
|
|
||||||
|
$urlId = call_user_func($urlCallable, $members);
|
||||||
|
$member = Member::find($urlId);
|
||||||
|
$repo = app(PdfRepositoryFactory::class)->fromSingleRequest($type, $member);
|
||||||
|
|
||||||
|
if ($filename === null) {
|
||||||
|
$this->assertNull($repo);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$content = app(PdfGenerator::class)->setRepository($repo)->compileView();
|
||||||
|
|
||||||
|
foreach ($output as $out) {
|
||||||
|
$this->assertStringContainsString($out, $content);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private function setupMembers(array $members): Collection
|
||||||
|
{
|
||||||
|
return collect($members)->map(function (array $member): Member {
|
||||||
$memberFactory = Member::factory()
|
$memberFactory = Member::factory()
|
||||||
->for(Nationality::factory())
|
->for(Nationality::factory())
|
||||||
->for(Subscription::factory()->for(Fee::factory()))
|
->for(Subscription::factory()->for(Fee::factory()))
|
||||||
|
@ -97,25 +144,6 @@ class GenerateTest extends TestCase
|
||||||
|
|
||||||
return $memberModel->load('payments');
|
return $memberModel->load('payments');
|
||||||
});
|
});
|
||||||
|
|
||||||
$urlId = call_user_func($urlCallable, $members);
|
|
||||||
$response = $this->post("/member/{$urlId}/pdf", [
|
|
||||||
'type' => $type,
|
|
||||||
]);
|
|
||||||
|
|
||||||
if ($filename === null) {
|
|
||||||
$response->assertStatus(204);
|
|
||||||
$this->assertTexCount(0);
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->assertEquals('application/pdf', $response->headers->get('content-type'));
|
|
||||||
$this->assertTrue('attachment; filename="' . $filename . '"', $response->headers->get('content-disposition'));
|
|
||||||
|
|
||||||
foreach ($output as $out) {
|
|
||||||
$this->assertTexGeneratedWith($out);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,18 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace Tests\Traits;
|
|
||||||
|
|
||||||
trait FakesTex
|
|
||||||
{
|
|
||||||
|
|
||||||
public function fakeTex(): void
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public function assertTexCount(int $count): void
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
Loading…
Reference in New Issue