Refactor DocumentFactory
continuous-integration/drone/push Build is failing Details

This commit is contained in:
philipp lang 2022-12-07 00:40:53 +01:00
parent 3a93d1585f
commit 94b405bcf9
9 changed files with 74 additions and 132 deletions

View File

@ -4,6 +4,7 @@ namespace App\Letter\Actions;
use App\Letter\BillKind; use App\Letter\BillKind;
use App\Letter\DocumentFactory; use App\Letter\DocumentFactory;
use App\Letter\Queries\BillKindQuery;
use App\Payment\PaymentMail; use App\Payment\PaymentMail;
use Illuminate\Console\Command; use Illuminate\Console\Command;
use Illuminate\Support\Facades\Storage; use Illuminate\Support\Facades\Storage;
@ -32,8 +33,8 @@ class LetterSendAction
*/ */
public function handle(): int public function handle(): int
{ {
foreach (app(DocumentFactory::class)->types as $type) { foreach (app(DocumentFactory::class)->getTypes() as $type) {
$letters = app(DocumentFactory::class)->letterCollection($type, BillKind::EMAIL); $letters = app(DocumentFactory::class)->letterCollection($type, new BillKindQuery(BillKind::EMAIL));
foreach ($letters as $letter) { foreach ($letters as $letter) {
$letterPath = Storage::path(Tex::compile($letter)->storeIn('/tmp', 'local')); $letterPath = Storage::path(Tex::compile($letter)->storeIn('/tmp', 'local'));

View File

@ -22,24 +22,11 @@ class BillDocument extends Letter
return 'tex.bill'; return 'tex.bill';
} }
public function sendAllLabel(): string public static function sendAllLabel(): string
{ {
return 'Rechnungen versenden'; return 'Rechnungen versenden';
} }
/**
* Get Descriptions for sendpayment page.
*
* @return array<int, string>
*/
public function getDescription(): array
{
return [
'Diese Funktion erstellt ein PDF mit allen noch nicht versendenden Rechnungen bei den Mitgliedern die Post als Versandweg haben.',
'Die Rechnungen werden automatisch auf "Rechnung gestellt" aktualisiert.',
];
}
public function afterSingle(Payment $payment): void public function afterSingle(Payment $payment): void
{ {
$payment->update(['status_id' => 2]); $payment->update(['status_id' => 2]);
@ -59,4 +46,17 @@ class BillDocument extends Letter
{ {
return $query->whereNeedsBill(); return $query->whereNeedsBill();
} }
/**
* Get Descriptions for sendpayment page.
*
* @return array<int, string>
*/
public static function getDescription(): array
{
return [
'Diese Funktion erstellt ein PDF mit allen noch nicht versendenden Rechnungen bei den Mitgliedern die Post als Versandweg haben.',
'Die Rechnungen werden automatisch auf "Rechnung gestellt" aktualisiert.',
];
}
} }

View File

@ -2,72 +2,39 @@
namespace App\Letter; namespace App\Letter;
use App\Letter\Queries\BillKindQuery; use App\Letter\Queries\LetterMemberQuery;
use App\Letter\Queries\SingleMemberQuery;
use App\Member\Member;
use Illuminate\Database\Eloquent\Collection as EloquentCollection;
use Illuminate\Support\Collection; use Illuminate\Support\Collection;
use Illuminate\Support\Str;
class DocumentFactory class DocumentFactory
{ {
/** /**
* @var array<int, class-string<Letter>> * @var array<int, class-string<Letter>>
*/ */
public array $types = [ private array $types = [
BillDocument::class, BillDocument::class,
RememberDocument::class, RememberDocument::class,
]; ];
/** /**
* @return Collection<int, Letter> * @return Collection<int, class-string<Letter>>
*/ */
public function getTypes(): Collection public function getTypes(): Collection
{ {
/** @var array<int, Member> */ return collect($this->types);
$emptyMembers = [];
return collect(array_map(fn ($classString) => new $classString(collect($emptyMembers)), $this->types));
} }
/** /**
* @param class-string<Letter> $type * @param class-string<Letter> $type
*/ */
public function fromSingleRequest(string $type, Member $member): ?Letter public function singleLetter(string $type, LetterMemberQuery $query): ?Letter
{ {
$members = $this->singleMemberPages($member, $type); $pages = $query->getPages($type);
if ($members->isEmpty()) {
return null;
}
return tap(
$this->resolve($type, $members),
fn ($repo) => $repo->setFilename(Str::slug("{$repo->getSubject()} für {$members->first()->singleName}"))
);
}
/**
* @param class-string<Letter> $type
*/
public function forAll(string $type, BillKind $billKind): ?Letter
{
$pages = $this->allMemberPages($type, $billKind);
if ($pages->isEmpty()) { if ($pages->isEmpty()) {
return null; return null;
} }
return tap($this->resolve($type, $pages), fn ($repo) => $repo->setFilename('alle-rechnungen')); return $this->resolve($type, $pages);
}
/**
* @param class-string<Letter> $type
*/
public function afterAll(string $type, BillKind $billKind): void
{
$letter = $this->forAll($type, $billKind);
$this->afterSingle($letter);
} }
/** /**
@ -75,11 +42,11 @@ class DocumentFactory
* *
* @return Collection<int, Letter> * @return Collection<int, Letter>
*/ */
public function letterCollection(string $type, BillKind $billKind): Collection public function letterCollection(string $type, LetterMemberQuery $query): Collection
{ {
$pages = $this->allMemberPages($type, $billKind); return $query
->getPages($type)
return $pages->map(fn ($page) => $this->resolve($type, collect([$page]))); ->map(fn ($page) => $this->resolve($type, collect([$page])));
} }
public function afterSingle(Letter $letter): void public function afterSingle(Letter $letter): void
@ -89,26 +56,6 @@ class DocumentFactory
} }
} }
/**
* @param class-string<Letter> $type
*
* @return Collection<int, Page>
*/
private function singleMemberPages(Member $member, string $type): Collection
{
return (new SingleMemberQuery($member))->getPages($type);
}
/**
* @param class-string<Letter> $type
*
* @return Collection<int, Page>
*/
private function allMemberPages(string $type, BillKind $billKind): Collection
{
return (new BillKindQuery($billKind))->getPages($type);
}
/** /**
* @param class-string<Letter> $type * @param class-string<Letter> $type
* @param Collection<int, Page> $pages * @param Collection<int, Page> $pages
@ -117,18 +64,4 @@ class DocumentFactory
{ {
return new $type($pages); return new $type($pages);
} }
/**
* @param EloquentCollection<Member> $members
*
* @return Collection<int, Page>
*/
private function toPages(EloquentCollection $members): Collection
{
return $members->groupBy(
fn ($member) => Str::slug(
"{$member->lastname}{$member->address}{$member->zip}{$member->location}",
),
)->map(fn ($page) => new Page($page));
}
} }

View File

@ -21,7 +21,7 @@ abstract class Letter extends Document
abstract public function linkLabel(): string; abstract public function linkLabel(): string;
abstract public function sendAllLabel(): string; abstract public static function sendAllLabel(): string;
/** /**
* @param HasMany<Payment> $query * @param HasMany<Payment> $query
@ -33,7 +33,7 @@ abstract class Letter extends Document
/** /**
* @return array<int, string> * @return array<int, string>
*/ */
abstract public function getDescription(): array; abstract public static function getDescription(): array;
abstract public function afterSingle(Payment $payment): void; abstract public function afterSingle(Payment $payment): void;

View File

@ -71,24 +71,6 @@ class RememberDocument extends Letter
return $page->first()->location; return $page->first()->location;
} }
public function sendAllLabel(): string
{
return 'Erinnerungen versenden';
}
/**
* Get Descriptions for sendpayment page.
*
* @return array<int, string>
*/
public function getDescription(): array
{
return [
'Diese Funktion erstellt Erinnerungs-PDFs mit allen versendeten aber noch nich bezahlten Rechnungen bei den Mitgliedern die Post als Versandweg haben.',
'Das zuletzt erinnerte Datum wird auf heute gesetzt.',
];
}
public function afterSingle(Payment $payment): void public function afterSingle(Payment $payment): void
{ {
$payment->update(['last_remembered_at' => now()]); $payment->update(['last_remembered_at' => now()]);
@ -108,4 +90,22 @@ class RememberDocument extends Letter
{ {
return $query->whereNeedsRemember(); return $query->whereNeedsRemember();
} }
/**
* Get Descriptions for sendpayment page.
*
* @return array<int, string>
*/
public static function getDescription(): array
{
return [
'Diese Funktion erstellt Erinnerungs-PDFs mit allen versendeten aber noch nich bezahlten Rechnungen bei den Mitgliedern die Post als Versandweg haben.',
'Das zuletzt erinnerte Datum wird auf heute gesetzt.',
];
}
public static function sendAllLabel(): string
{
return 'Erinnerungen versenden';
}
} }

View File

@ -3,20 +3,19 @@
namespace App\Payment; namespace App\Payment;
use App\Letter\DocumentFactory; use App\Letter\DocumentFactory;
use App\Letter\Letter;
use Illuminate\Support\Collection; use Illuminate\Support\Collection;
class ActionFactory class ActionFactory
{ {
public function allLinks(): Collection public function allLinks(): Collection
{ {
return app(DocumentFactory::class)->getTypes()->map(function (Letter $repo) { return app(DocumentFactory::class)->getTypes()->map(function ($repo) {
return [ return [
'link' => [ 'link' => [
'href' => route('sendpayment.pdf', ['type' => get_class($repo)]), 'href' => route('sendpayment.pdf', ['type' => $repo]),
'label' => $repo->sendAllLabel(), 'label' => $repo::sendAllLabel(),
], ],
'text' => $repo->getDescription(), 'text' => $repo::getDescription(),
]; ];
}); });
} }

View File

@ -5,6 +5,7 @@ namespace App\Payment;
use App\Http\Controllers\Controller; use App\Http\Controllers\Controller;
use App\Letter\BillKind; use App\Letter\BillKind;
use App\Letter\DocumentFactory; use App\Letter\DocumentFactory;
use App\Letter\Queries\BillKindQuery;
use Illuminate\Contracts\Support\Responsable; use Illuminate\Contracts\Support\Responsable;
use Illuminate\Http\Request; use Illuminate\Http\Request;
use Illuminate\Http\Response; use Illuminate\Http\Response;
@ -29,14 +30,14 @@ class SendpaymentController extends Controller
*/ */
public function send(Request $request) public function send(Request $request)
{ {
$repo = app(DocumentFactory::class)->forAll($request->type, BillKind::POST); $letter = app(DocumentFactory::class)->singleLetter($request->type, new BillKindQuery(BillKind::POST));
if (is_null($repo)) { if (is_null($letter)) {
return response()->noContent(); return response()->noContent();
} }
$pdfFile = Tex::compile($repo); $pdfFile = Tex::compile($letter);
app(DocumentFactory::class)->afterAll($request->type, BillKind::POST); app(DocumentFactory::class)->afterSingle($letter);
return $pdfFile; return $pdfFile;
} }

View File

@ -4,6 +4,7 @@ namespace App\Pdf;
use App\Http\Controllers\Controller; use App\Http\Controllers\Controller;
use App\Letter\DocumentFactory; use App\Letter\DocumentFactory;
use App\Letter\Queries\SingleMemberQuery;
use App\Member\Member; use App\Member\Member;
use Illuminate\Contracts\Support\Responsable; use Illuminate\Contracts\Support\Responsable;
use Illuminate\Http\Request; use Illuminate\Http\Request;
@ -17,10 +18,10 @@ class MemberPdfController extends Controller
*/ */
public function __invoke(Request $request, Member $member) public function __invoke(Request $request, Member $member)
{ {
$document = app(DocumentFactory::class)->fromSingleRequest($request->type, $member); $letter = app(DocumentFactory::class)->singleLetter($request->type, new SingleMemberQuery($member));
return null === $document return null === $letter
? response()->noContent() ? response()->noContent()
: Tex::compile($document); : Tex::compile($letter);
} }
} }

View File

@ -5,6 +5,8 @@ namespace Tests\Feature\Letter;
use App\Letter\BillDocument; use App\Letter\BillDocument;
use App\Letter\DocumentFactory; use App\Letter\DocumentFactory;
use App\Letter\LetterSettings; use App\Letter\LetterSettings;
use App\Letter\Queries\LetterMemberQuery;
use App\Letter\Queries\SingleMemberQuery;
use App\Letter\RememberDocument; use App\Letter\RememberDocument;
use App\Member\Member; use App\Member\Member;
use App\Payment\Payment; use App\Payment\Payment;
@ -23,7 +25,7 @@ class DocumentFactoryTest extends TestCase
public function testItDoesntReturnARepositoryWhenMemberDoesntHavePayments(): void public function testItDoesntReturnARepositoryWhenMemberDoesntHavePayments(): void
{ {
$member = Member::factory()->defaults()->create(); $member = Member::factory()->defaults()->create();
$letter = app(DocumentFactory::class)->fromSingleRequest(BillDocument::class, $member); $letter = app(DocumentFactory::class)->singleLetter(BillDocument::class, $this->query($member));
$this->assertNull($letter); $this->assertNull($letter);
} }
@ -41,7 +43,7 @@ class DocumentFactoryTest extends TestCase
->has(Payment::factory()->notPaid()->nr('1995')->subscription('::subName::', 1500)) ->has(Payment::factory()->notPaid()->nr('1995')->subscription('::subName::', 1500))
->create(); ->create();
$letter = app(DocumentFactory::class)->fromSingleRequest(BillDocument::class, $member); $letter = app(DocumentFactory::class)->singleLetter(BillDocument::class, $this->query($member));
$letter->assertHasAllContent([ $letter->assertHasAllContent([
'Rechnung', 'Rechnung',
@ -60,7 +62,7 @@ class DocumentFactoryTest extends TestCase
->has(Payment::factory()->notPaid()->nr('1995')->subscription('::subName::', 1500)) ->has(Payment::factory()->notPaid()->nr('1995')->subscription('::subName::', 1500))
->create(); ->create();
$letter = app(DocumentFactory::class)->fromSingleRequest(BillDocument::class, $member); $letter = app(DocumentFactory::class)->singleLetter(BillDocument::class, $this->query($member));
$this->assertEquals('rechnung-fur-lastname.pdf', $letter->compiledFilename()); $this->assertEquals('rechnung-fur-lastname.pdf', $letter->compiledFilename());
} }
@ -73,7 +75,7 @@ class DocumentFactoryTest extends TestCase
->has(Payment::factory()->notPaid()) ->has(Payment::factory()->notPaid())
->create(); ->create();
$letter = app(DocumentFactory::class)->fromSingleRequest(RememberDocument::class, $member); $letter = app(DocumentFactory::class)->singleLetter(RememberDocument::class, $this->query($member));
$this->assertEquals('zahlungserinnerung-fur-lastname.pdf', $letter->compiledFilename()); $this->assertEquals('zahlungserinnerung-fur-lastname.pdf', $letter->compiledFilename());
} }
@ -91,7 +93,7 @@ class DocumentFactoryTest extends TestCase
->has(Payment::factory()->notPaid()->nr('nr2')) ->has(Payment::factory()->notPaid()->nr('nr2'))
->create(); ->create();
$letter = app(DocumentFactory::class)->fromSingleRequest(BillDocument::class, $firstMember); $letter = app(DocumentFactory::class)->singleLetter(BillDocument::class, $this->query($firstMember));
$letter->assertHasAllContent(['Max1', 'Max2', 'nr1', 'nr2']); $letter->assertHasAllContent(['Max1', 'Max2', 'nr1', 'nr2']);
} }
@ -119,7 +121,7 @@ class DocumentFactoryTest extends TestCase
->has(Payment::factory()->notPaid()->nr('nr2')) ->has(Payment::factory()->notPaid()->nr('nr2'))
->create(); ->create();
$letter = app(DocumentFactory::class)->fromSingleRequest($type, $member); $letter = app(DocumentFactory::class)->singleLetter($type, $this->query($member));
$letter->assertHasAllContent([ $letter->assertHasAllContent([
'langer Stammesname', 'langer Stammesname',
@ -152,4 +154,9 @@ class DocumentFactoryTest extends TestCase
$this->assertEquals('application/pdf', $response->headers->get('content-type')); $this->assertEquals('application/pdf', $response->headers->get('content-type'));
$this->assertEquals('inline; filename="rechnung-fur-lastname.pdf"', $response->headers->get('content-disposition')); $this->assertEquals('inline; filename="rechnung-fur-lastname.pdf"', $response->headers->get('content-disposition'));
} }
private function query(Member $member): LetterMemberQuery
{
return new SingleMemberQuery($member);
}
} }