Basic support for creating invoices

This commit is contained in:
2026-07-02 23:39:47 +02:00
parent 872972ea48
commit 56b603aba0
15 changed files with 2147 additions and 29 deletions
@@ -0,0 +1,94 @@
<?php
namespace App\Domains\Rechnung\Actions\GeneratePdf;
use Barryvdh\DomPDF\Facade\Pdf;
class GeneratePdfCommand
{
public function __construct(private readonly GeneratePdfRequest $request) {}
public function execute(): GeneratePdfResponse
{
$rechnungsnummer = $this->request->rechnungsnummer !== ''
? $this->request->rechnungsnummer
: date('Y') . '-' . str_pad(random_int(1, 999), 3, '0', STR_PAD_LEFT);
$positionen = array_values(array_filter(
$this->request->positionen,
fn($p) => !empty($p['bezeichnung'])
));
$netto = array_sum(array_map(
fn($p) => (float) ($p['menge'] ?? 0) * (float) ($p['einzelpreis'] ?? 0),
$positionen
));
$mwst = $netto * $this->request->mwstSatz / 100;
$brutto = $netto + $mwst;
$pdf = Pdf::loadView('pdf.rechnung', [
'rechnungsnummer' => $rechnungsnummer,
'organisation' => $this->request->organisation,
'anrede' => $this->request->anrede,
'vorname' => $this->request->vorname,
'nachname' => $this->request->nachname,
'adresse' => $this->request->adresse,
'plz' => $this->request->plz,
'ort' => $this->request->ort,
'email' => $this->request->email,
'iban' => $this->request->iban,
'bic' => $this->request->bic,
'rechnungsdatum' => $this->request->rechnungsdatum,
'zahlungsziel' => $this->request->zahlungsziel,
'rechnungsdatumFormatiert' => $this->formatDate($this->request->rechnungsdatum),
'zahlungszielFormatiert' => $this->formatDate($this->request->zahlungsziel),
'positionen' => $positionen,
'mwstSatz' => $this->request->mwstSatz,
'netto' => $netto,
'mwst' => $mwst,
'brutto' => $brutto,
'absenderEmail' => $this->request->absenderEmail,
'absenderTelefon' => $this->request->absenderTelefon,
'kohteDataUri' => $this->imageToDataUri(storage_path('app/elemente/kohte.png')),
'logoDataUri' => $this->imageToDataUri(public_path('wbm.png')),
]);
$pdf->setPaper('A4', 'portrait');
$pdf->render();
$pdfContent = $pdf->output();
return new GeneratePdfResponse(
pdfContent: $pdfContent,
filename: 'rechnung-' . $rechnungsnummer . '.pdf',
);
}
private function formatDate(string $date): string
{
if (!$date) {
return '—';
}
$ts = strtotime($date);
return $ts ? date('d.m.Y', $ts) : $date;
}
private function imageToDataUri(string $path): string
{
if (!file_exists($path)) {
return '';
}
$mime = match (strtolower(pathinfo($path, PATHINFO_EXTENSION))) {
'jpg', 'jpeg' => 'image/jpeg',
'svg' => 'image/svg+xml',
default => 'image/png',
};
return 'data:' . $mime . ';base64,' . base64_encode(file_get_contents($path));
}
}
@@ -0,0 +1,49 @@
<?php
namespace App\Domains\Rechnung\Actions\GeneratePdf;
class GeneratePdfRequest
{
public function __construct(
public readonly string $organisation,
public readonly string $anrede,
public readonly string $vorname,
public readonly string $nachname,
public readonly string $adresse,
public readonly string $plz,
public readonly string $ort,
public readonly string $email,
public readonly string $rechnungsnummer,
public readonly string $rechnungsdatum,
public readonly string $zahlungsziel,
public readonly string $bic,
public readonly string $iban,
public readonly array $positionen,
public readonly int $mwstSatz,
public readonly string $absenderEmail,
public readonly string $absenderTelefon,
) {}
public static function fromArray(array $data): self
{
return new self(
organisation: $data['organisation'] ?? '',
anrede: $data['anrede'] ?? '',
vorname: $data['vorname'] ?? '',
nachname: $data['nachname'] ?? '',
adresse: $data['adresse'] ?? '',
plz: $data['plz'] ?? '',
ort: $data['ort'] ?? '',
email: $data['email'] ?? '',
rechnungsnummer: $data['rechnungsnummer'] ?? '',
rechnungsdatum: $data['rechnungsdatum'] ?? '',
zahlungsziel: $data['zahlungsziel'] ?? '',
bic: $data['bic'] ?? '',
iban: $data['iban'] ?? '',
positionen: $data['positionen'] ?? [],
mwstSatz: (int) ($data['mwstSatz'] ?? 19),
absenderEmail: $data['absenderEmail'] ?? 'finanzen@sachsen.pfadfinden.de',
absenderTelefon: $data['absenderTelefon'] ?? '',
);
}
}
@@ -0,0 +1,11 @@
<?php
namespace App\Domains\Rechnung\Actions\GeneratePdf;
class GeneratePdfResponse
{
public function __construct(
public readonly string $pdfContent,
public readonly string $filename,
) {}
}