150 lines
4.0 KiB
PHP
150 lines
4.0 KiB
PHP
|
<?php
|
||
|
|
||
|
namespace App\Letter;
|
||
|
|
||
|
use App\Member\Member;
|
||
|
use Illuminate\Database\Eloquent\Builder;
|
||
|
use Illuminate\Database\Eloquent\Collection as EloquentCollection;
|
||
|
use Illuminate\Support\Collection;
|
||
|
use Illuminate\Support\Str;
|
||
|
|
||
|
class DocumentFactory
|
||
|
{
|
||
|
/**
|
||
|
* @var array<int, class-string<Letter>>
|
||
|
*/
|
||
|
public array $types = [
|
||
|
BillDocument::class,
|
||
|
RememberDocument::class,
|
||
|
];
|
||
|
|
||
|
/**
|
||
|
* @return Collection<int, Letter>
|
||
|
*/
|
||
|
public function getTypes(): Collection
|
||
|
{
|
||
|
/** @var array<int, Member> */
|
||
|
$emptyMembers = [];
|
||
|
|
||
|
return collect(array_map(fn ($classString) => new $classString(collect($emptyMembers)), $this->types));
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @param class-string<Letter> $type
|
||
|
*/
|
||
|
public function fromSingleRequest(string $type, Member $member): ?Letter
|
||
|
{
|
||
|
$members = $this->singleMemberCollection($member, $type);
|
||
|
|
||
|
if ($members->isEmpty()) {
|
||
|
return null;
|
||
|
}
|
||
|
|
||
|
$repo = $this->resolve($type, $members);
|
||
|
$repo->setFilename(Str::slug("{$repo->getSubject()} für {$members->first()->singleName}"));
|
||
|
|
||
|
return $repo;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @param class-string<Letter> $type
|
||
|
*/
|
||
|
public function forAll(string $type, string $billKind): ?Letter
|
||
|
{
|
||
|
$members = $this->toPages($this->allMemberCollection($type, $billKind));
|
||
|
|
||
|
if ($members->isEmpty()) {
|
||
|
return null;
|
||
|
}
|
||
|
|
||
|
return $this->resolve($type, $members)->setFilename('alle-rechnungen');
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @param class-string<Letter> $type
|
||
|
*
|
||
|
* @return Collection<int, Letter>
|
||
|
*/
|
||
|
public function repoCollection(string $type, string $billKind): Collection
|
||
|
{
|
||
|
$pages = $this->toPages($this->allMemberCollection($type, $billKind));
|
||
|
|
||
|
return $pages->map(fn ($page) => $this->resolve($type, collect([$page])));
|
||
|
}
|
||
|
|
||
|
public function afterSingle(Letter $repo): void
|
||
|
{
|
||
|
foreach ($repo->allPayments() as $payment) {
|
||
|
$repo->afterSingle($payment);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @param class-string<Letter> $type
|
||
|
*/
|
||
|
public function afterAll(string $type, string $billKind): void
|
||
|
{
|
||
|
$members = $this->allMemberCollection($type, $billKind);
|
||
|
$repo = $this->resolve($type, $this->toPages($members));
|
||
|
|
||
|
$this->afterSingle($repo);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @param class-string<Letter> $type
|
||
|
*
|
||
|
* @return Collection<int, Page>
|
||
|
*/
|
||
|
public function singleMemberCollection(Member $member, string $type): Collection
|
||
|
{
|
||
|
$members = Member::where($member->only(['lastname', 'address', 'zip', 'location']))
|
||
|
->with([
|
||
|
'payments' => fn ($query) => $type::paymentsQuery($query)
|
||
|
->orderByRaw('nr, member_id'),
|
||
|
])
|
||
|
->get()
|
||
|
->filter(fn (Member $member) => $member->payments->count() > 0);
|
||
|
|
||
|
return $this->toPages($members);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @param class-string<Letter> $type
|
||
|
*
|
||
|
* @return EloquentCollection<Member>
|
||
|
*/
|
||
|
private function allMemberCollection(string $type, string $billKind): Collection
|
||
|
{
|
||
|
return Member::whereHas('billKind', fn (Builder $q) => $q->where('name', $billKind))
|
||
|
->with([
|
||
|
'payments' => fn ($query) => $type::paymentsQuery($query)
|
||
|
->orderByRaw('nr, member_id'),
|
||
|
])
|
||
|
->get()
|
||
|
->filter(fn (Member $member) => $member->payments->count() > 0);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @param class-string<Letter> $type
|
||
|
* @param Collection<int, Page> $pages
|
||
|
*/
|
||
|
private function resolve(string $type, Collection $pages): Letter
|
||
|
{
|
||
|
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));
|
||
|
}
|
||
|
}
|