Compare commits

..

No commits in common. "8ea566c4002f6a238afadcced524a06e962e0008" and "bfdb591baf52c1981bea7840df64e2abf2b5c2e6" have entirely different histories.

14 changed files with 221 additions and 264 deletions

View File

@ -2,11 +2,11 @@
namespace App\Contribution\Actions;
use App\Contribution\Contracts\HasContributionData;
use App\Contribution\ContributionFactory;
use App\Contribution\Requests\GenerateRequest;
use App\Contribution\Documents\ContributionDocument;
use App\Rules\JsonBase64Rule;
use Illuminate\Support\Facades\Validator;
use Lorisleiva\Actions\ActionRequest;
use Lorisleiva\Actions\Concerns\AsAction;
use Zoomyboy\Tex\BaseCompiler;
use Zoomyboy\Tex\Tex;
@ -15,18 +15,23 @@ class GenerateAction
{
use AsAction;
public function handle(HasContributionData $request): BaseCompiler
/**
* @param class-string<ContributionDocument> $document
* @param array<string, mixed> $payload
*/
public function handle(string $document, array $payload): BaseCompiler
{
return Tex::compile($request->type()::fromPayload($request));
return Tex::compile($document::fromRequest($payload));
}
public function asController(GenerateRequest $request): BaseCompiler
public function asController(ActionRequest $request): BaseCompiler
{
$type = $request->type();
$payload = $this->payload($request);
$type = data_get($payload, 'type');
ValidateAction::validateType($type);
Validator::make($request->payload(), app(ContributionFactory::class)->rules($type))->validate();
Validator::make($payload, app(ContributionFactory::class)->rules($type))->validate();
return $this->handle($request);
return $this->handle($type, $payload);
}
/**
@ -38,4 +43,12 @@ class GenerateAction
'payload' => [new JsonBase64Rule()],
];
}
/**
* @return array<string, string>
*/
private function payload(ActionRequest $request): array
{
return json_decode(rawurldecode(base64_decode($request->input('payload', ''))), true);
}
}

View File

@ -2,8 +2,8 @@
namespace App\Contribution\Actions;
use App\Contribution\Contracts\HasContributionData;
use App\Contribution\Requests\GenerateApiRequest;
use App\Contribution\Documents\ContributionDocument;
use Lorisleiva\Actions\ActionRequest;
use Lorisleiva\Actions\Concerns\AsAction;
use Zoomyboy\Tex\BaseCompiler;
use Zoomyboy\Tex\Tex;
@ -13,19 +13,19 @@ class GenerateApiAction
use AsAction;
/**
* @todo merge this with GenerateAction
* @param class-string<ContributionDocument> $document
* @param array<string, mixed> $payload
*/
public function handle(HasContributionData $request): BaseCompiler
public function handle(string $document, array $payload): BaseCompiler
{
return Tex::compile($request->type()::fromPayload($request));
return Tex::compile($document::fromApiRequest($payload));
}
public function asController(GenerateApiRequest $request): BaseCompiler
public function asController(ActionRequest $request): BaseCompiler
{
$type = $request->type();
ValidateAction::validateType($type);
ValidateAction::validateType($request->input('type'));
return $this->handle($request);
return $this->handle($request->input('type'), $request->input());
}
/**

View File

@ -1,28 +0,0 @@
<?php
namespace App\Contribution\Contracts;
use App\Contribution\Data\MemberData;
use Carbon\Carbon;
use App\Contribution\Documents\ContributionDocument;
use App\Country;
use Illuminate\Support\Collection;
interface HasContributionData {
public function dateFrom(): Carbon;
public function dateUntil(): Carbon;
public function zipLocation(): string;
public function eventName(): string;
/**
* @return class-string<ContributionDocument>
*/
public function type(): string;
/**
* @return Collection<int, MemberData>
*/
public function members(): Collection;
public function country(): ?Country;
}

View File

@ -2,7 +2,6 @@
namespace App\Contribution\Documents;
use App\Contribution\Contracts\HasContributionData;
use App\Contribution\Data\MemberData;
use App\Contribution\Traits\HasPdfBackground;
use App\Country;
@ -18,8 +17,8 @@ class BdkjHesse extends ContributionDocument
* @param Collection<int, Collection<int, MemberData>> $members
*/
public function __construct(
public Carbon $dateFrom,
public Carbon $dateUntil,
public string $dateFrom,
public string $dateUntil,
public string $zipLocation,
public ?Country $country,
public Collection $members,
@ -40,15 +39,33 @@ class BdkjHesse extends ContributionDocument
return Carbon::parse($this->dateUntil)->format('d.m.Y');
}
public static function fromPayload(HasContributionData $request): self
/**
* {@inheritdoc}
*/
public static function fromRequest(array $request): self
{
return new self(
dateFrom: $request->dateFrom(),
dateUntil: $request->dateUntil(),
zipLocation: $request->zipLocation(),
country: $request->country(),
members: $request->members()->chunk(20),
eventName: $request->eventName(),
dateFrom: $request['dateFrom'],
dateUntil: $request['dateUntil'],
zipLocation: $request['zipLocation'],
country: Country::where('id', $request['country'])->firstOrFail(),
members: MemberData::fromModels($request['members'])->chunk(20),
eventName: $request['eventName'],
);
}
/**
* {@inheritdoc}
*/
public static function fromApiRequest(array $request): self
{
return new self(
dateFrom: $request['dateFrom'],
dateUntil: $request['dateUntil'],
zipLocation: $request['zipLocation'],
country: Country::where('id', $request['country'])->firstOrFail(),
members: MemberData::fromApi($request['member_data'])->chunk(20),
eventName: $request['eventName'],
);
}

View File

@ -2,14 +2,12 @@
namespace App\Contribution\Documents;
use App\Contribution\Contracts\HasContributionData;
use App\Contribution\Data\MemberData;
use App\Contribution\Traits\FormatsDates;
use App\Contribution\Traits\HasPdfBackground;
use App\Country;
use App\Invoice\InvoiceSettings;
use Illuminate\Support\Collection;
use Carbon\Carbon;
class CityFrankfurtMainDocument extends ContributionDocument
{
@ -22,8 +20,8 @@ class CityFrankfurtMainDocument extends ContributionDocument
* @param Collection<int, Collection<int, MemberData>> $members
*/
public function __construct(
public Carbon $dateFrom,
public Carbon $dateUntil,
public string $dateFrom,
public string $dateUntil,
public string $zipLocation,
public ?Country $country,
public Collection $members,
@ -35,15 +33,33 @@ class CityFrankfurtMainDocument extends ContributionDocument
$this->fromName = app(InvoiceSettings::class)->from_long;
}
public static function fromPayload(HasContributionData $request): self
/**
* {@inheritdoc}
*/
public static function fromRequest(array $request): self
{
return new self(
dateFrom: $request->dateFrom(),
dateUntil: $request->dateUntil(),
zipLocation: $request->zipLocation(),
country: $request->country(),
members: $request->members()->chunk(15),
eventName: $request->eventName(),
dateFrom: $request['dateFrom'],
dateUntil: $request['dateUntil'],
zipLocation: $request['zipLocation'],
country: Country::where('id', $request['country'])->firstOrFail(),
members: MemberData::fromModels($request['members'])->chunk(15),
eventName: $request['eventName'],
);
}
/**
* {@inheritdoc}
*/
public static function fromApiRequest(array $request): self
{
return new self(
dateFrom: $request['dateFrom'],
dateUntil: $request['dateUntil'],
zipLocation: $request['zipLocation'],
country: Country::where('id', $request['country'])->firstOrFail(),
members: MemberData::fromApi($request['member_data'])->chunk(15),
eventName: $request['eventName'],
);
}

View File

@ -2,13 +2,12 @@
namespace App\Contribution\Documents;
use App\Contribution\Contracts\HasContributionData;
use App\Contribution\Data\MemberData;
use App\Contribution\Traits\FormatsDates;
use App\Contribution\Traits\HasPdfBackground;
use App\Country;
use App\Member\Member;
use Illuminate\Support\Collection;
use Carbon\Carbon;
class CityRemscheidDocument extends ContributionDocument
{
@ -20,8 +19,8 @@ class CityRemscheidDocument extends ContributionDocument
* @param Collection<int, Collection<int, Member>> $children
*/
public function __construct(
public Carbon $dateFrom,
public Carbon $dateUntil,
public string $dateFrom,
public string $dateUntil,
public string $zipLocation,
public ?Country $country,
public Collection $leaders,
@ -33,18 +32,40 @@ class CityRemscheidDocument extends ContributionDocument
$this->setEventName($eventName);
}
public static function fromPayload(HasContributionData $request): self
/**
* {@inheritdoc}
*/
public static function fromRequest(array $request): self
{
[$leaders, $children] = $request->members()->partition(fn ($member) => $member->isLeader);
[$leaders, $children] = MemberData::fromModels($request['members'])->partition(fn ($member) => $member->isLeader);
return new self(
dateFrom: $request->dateFrom(),
dateUntil: $request->dateUntil(),
zipLocation: $request->zipLocation(),
country: $request->country(),
dateFrom: $request['dateFrom'],
dateUntil: $request['dateUntil'],
zipLocation: $request['zipLocation'],
country: Country::where('id', $request['country'])->firstOrFail(),
leaders: $leaders->values()->toBase()->chunk(6),
children: $children->values()->toBase()->chunk(20),
eventName: $request->eventName(),
eventName: $request['eventName'],
);
}
/**
* {@inheritdoc}
*/
public static function fromApiRequest(array $request): self
{
$members = MemberData::fromApi($request['member_data']);
[$leaders, $children] = $members->partition(fn ($member) => $member->isLeader);
return new self(
dateFrom: $request['dateFrom'],
dateUntil: $request['dateUntil'],
zipLocation: $request['zipLocation'],
country: Country::where('id', $request['country'])->firstOrFail(),
leaders: $leaders->values()->toBase()->chunk(6),
children: $children->values()->toBase()->chunk(20),
eventName: $request['eventName'],
);
}

View File

@ -2,7 +2,6 @@
namespace App\Contribution\Documents;
use App\Contribution\Contracts\HasContributionData;
use App\Contribution\Data\MemberData;
use App\Invoice\InvoiceSettings;
use Carbon\Carbon;
@ -17,8 +16,8 @@ class CitySolingenDocument extends ContributionDocument
* @param Collection<int, MemberData> $members
*/
final private function __construct(
public Carbon $dateFrom,
public Carbon $dateUntil,
public string $dateFrom,
public string $dateUntil,
public string $zipLocation,
public Collection $members,
public string $eventName,
@ -31,14 +30,28 @@ class CitySolingenDocument extends ContributionDocument
/**
* {@inheritdoc}
*/
public static function fromPayload(HasContributionData $request): static
public static function fromRequest(array $request): static
{
return new static(
dateFrom: $request->dateFrom(),
dateUntil: $request->dateUntil(),
zipLocation: $request->zipLocation(),
members: $request->members(),
eventName: $request->eventName(),
dateFrom: $request['dateFrom'],
dateUntil: $request['dateUntil'],
zipLocation: $request['zipLocation'],
members: MemberData::fromModels($request['members']),
eventName: $request['eventName'],
);
}
/**
* {@inheritdoc}
*/
public static function fromApiRequest(array $request): static
{
return new static(
dateFrom: $request['dateFrom'],
dateUntil: $request['dateUntil'],
zipLocation: $request['zipLocation'],
members: MemberData::fromApi($request['member_data']),
eventName: $request['eventName'],
);
}
@ -62,6 +75,8 @@ class CitySolingenDocument extends ContributionDocument
public function checkboxes(): string
{
$output = '';
$firstRow = collect(['B' => 'Jugendbildungsmaßnahme', 'G' => 'Gruppenleiter/innenschulung', 'FK' => 'Ferienkolonie', 'F' => 'Freizeitnaßnahme'])->map(function ($item, $key) {
return ($this->type === $key ? '\\checkedcheckbox' : '\\checkbox') . '{' . $item . '}';
})->implode(' & ') . ' \\\\';

View File

@ -2,7 +2,6 @@
namespace App\Contribution\Documents;
use App\Contribution\Contracts\HasContributionData;
use Zoomyboy\Tex\Document;
use Zoomyboy\Tex\Template;
@ -12,7 +11,15 @@ abstract class ContributionDocument extends Document
abstract public static function getName(): string;
abstract public static function fromPayload(HasContributionData $request): self;
/**
* @param ContributionRequestArray $request
*/
abstract public static function fromRequest(array $request): self;
/**
* @param ContributionApiRequestArray $request
*/
abstract public static function fromApiRequest(array $request): self;
/**
* @return array<string, mixed>

View File

@ -2,13 +2,11 @@
namespace App\Contribution\Documents;
use App\Contribution\Contracts\HasContributionData;
use App\Contribution\Data\MemberData;
use App\Contribution\Traits\FormatsDates;
use App\Contribution\Traits\HasPdfBackground;
use App\Country;
use Illuminate\Support\Collection;
use Carbon\Carbon;
class RdpNrwDocument extends ContributionDocument
{
@ -19,8 +17,8 @@ class RdpNrwDocument extends ContributionDocument
* @param Collection<int, Collection<int, MemberData>> $members
*/
public function __construct(
public Carbon $dateFrom,
public Carbon $dateUntil,
public string $dateFrom,
public string $dateUntil,
public string $zipLocation,
public ?Country $country,
public Collection $members,
@ -31,15 +29,33 @@ class RdpNrwDocument extends ContributionDocument
$this->setEventName($eventName);
}
public static function fromPayload(HasContributionData $request): self
/**
* {@inheritdoc}
*/
public static function fromRequest(array $request): self
{
return new self(
dateFrom: $request->dateFrom(),
dateUntil: $request->dateUntil(),
zipLocation: $request->zipLocation(),
country: $request->country(),
members: $request->members()->chunk(17),
eventName: $request->eventName(),
dateFrom: $request['dateFrom'],
dateUntil: $request['dateUntil'],
zipLocation: $request['zipLocation'],
country: Country::where('id', $request['country'])->firstOrFail(),
members: MemberData::fromModels($request['members'])->chunk(17),
eventName: $request['eventName'],
);
}
/**
* {@inheritdoc}
*/
public static function fromApiRequest(array $request): self
{
return new self(
dateFrom: $request['dateFrom'],
dateUntil: $request['dateUntil'],
zipLocation: $request['zipLocation'],
country: Country::where('id', $request['country'])->firstOrFail(),
members: MemberData::fromApi($request['member_data'])->chunk(17),
eventName: $request['eventName'],
);
}

View File

@ -2,13 +2,11 @@
namespace App\Contribution\Documents;
use App\Contribution\Contracts\HasContributionData;
use App\Contribution\Data\MemberData;
use App\Contribution\Traits\FormatsDates;
use App\Contribution\Traits\HasPdfBackground;
use App\Country;
use Illuminate\Support\Collection;
use Carbon\Carbon;
class WuppertalDocument extends ContributionDocument
{
@ -20,8 +18,8 @@ class WuppertalDocument extends ContributionDocument
* @param Collection<int, Collection<int, MemberData>> $members
*/
public function __construct(
public Carbon $dateFrom,
public Carbon $dateUntil,
public string $dateFrom,
public string $dateUntil,
public string $zipLocation,
public ?Country $country,
public Collection $members,
@ -32,15 +30,33 @@ class WuppertalDocument extends ContributionDocument
$this->setEventName($eventName);
}
public static function fromPayload(HasContributionData $request): self
/**
* {@inheritdoc}
*/
public static function fromRequest(array $request): self
{
return new self(
dateFrom: $request->dateFrom(),
dateUntil: $request->dateUntil(),
zipLocation: $request->zipLocation(),
country: $request->country(),
members: $request->members()->chunk(14),
eventName: $request->eventName(),
dateFrom: $request['dateFrom'],
dateUntil: $request['dateUntil'],
zipLocation: $request['zipLocation'],
country: Country::where('id', $request['country'])->firstOrFail(),
members: MemberData::fromModels($request['members'])->chunk(14),
eventName: $request['eventName'],
);
}
/**
* {@inheritdoc}
*/
public static function fromApiRequest(array $request): self
{
return new self(
dateFrom: $request['dateFrom'],
dateUntil: $request['dateUntil'],
zipLocation: $request['zipLocation'],
country: Country::where('id', $request['country'])->firstOrFail(),
members: MemberData::fromApi($request['member_data'])->chunk(14),
eventName: $request['eventName'],
);
}

View File

@ -1,67 +0,0 @@
<?php
namespace App\Contribution\Requests;
use App\Contribution\Contracts\HasContributionData;
use App\Contribution\Data\MemberData;
use App\Contribution\Documents\ContributionDocument;
use App\Country;
use Lorisleiva\Actions\ActionRequest;
use Carbon\Carbon;
use Illuminate\Support\Arr;
use Illuminate\Support\Collection;
use RuntimeException;
class GenerateApiRequest extends ActionRequest implements HasContributionData {
/**
* @return array<string, string>
*/
public function payload(): array
{
return $this->input();
}
/**
* @return string|array<array-key, mixed>
*/
public function value(string $key): string|array
{
if (!Arr::has($this->payload(), $key)) {
throw new RuntimeException('Wert für '.$key.' nicht gefunden.');
}
return data_get($this->payload(), $key);
}
/**
* @return class-string<ContributionDocument>
*/
public function type(): string
{
return $this->value('type');
}
public function dateFrom(): Carbon {
return Carbon::parse($this->value('dateFrom'));
}
public function dateUntil(): Carbon {
return Carbon::parse($this->value('dateUntil'));
}
public function zipLocation(): string {
return $this->value('zipLocation');
}
public function eventName(): string {
return $this->value('eventName');
}
public function members(): Collection {
return MemberData::fromApi($this->value('member_data'));
}
public function country(): ?Country {
return Country::where('id', $this->value('country'))->first();
}
}

View File

@ -1,62 +0,0 @@
<?php
namespace App\Contribution\Requests;
use App\Contribution\Contracts\HasContributionData;
use App\Contribution\Data\MemberData;
use App\Contribution\Documents\ContributionDocument;
use App\Country;
use Lorisleiva\Actions\ActionRequest;
use Carbon\Carbon;
use Illuminate\Support\Collection;
class GenerateRequest extends ActionRequest implements HasContributionData {
/**
* @return array<string, string>
*/
public function payload(): array
{
return json_decode(rawurldecode(base64_decode($this->input('payload', ''))), true);
}
/**
* @return string|array<array-key, mixed>
*/
public function value(string $key): string|array
{
return data_get($this->payload(), $key);
}
/**
* @return class-string<ContributionDocument>
*/
public function type(): string
{
return $this->value('type');
}
public function dateFrom(): Carbon {
return Carbon::parse($this->value('dateFrom'));
}
public function dateUntil(): Carbon {
return Carbon::parse($this->value('dateUntil'));
}
public function zipLocation(): string {
return $this->value('zipLocation');
}
public function eventName(): string {
return $this->value('eventName');
}
public function members(): Collection {
return MemberData::fromModels($this->value('members'));
}
public function country(): ?Country {
return Country::where('id', $this->value('country'))->first();
}
}

View File

@ -415,7 +415,7 @@ it('renders setting of yearly mail', function () {
app(PreventionSettings::class)->fill([
'yearlymail' => EditorRequestFactory::new()->paragraphs(["{wanted}", "bbb"])->toData()
])->save();
createMember((['efz' => now()->subYears(5), 'ps_at' => now(), 'has_vk' => true]));
$member = createMember((['efz' => now()->subYears(5), 'ps_at' => now(), 'has_vk' => true]));
sleep(2);
YearlyRememberAction::run();

View File

@ -2,9 +2,6 @@
namespace Tests\Feature\Contribution;
use App\Contribution\Documents\BdkjHesse;
use App\Contribution\Documents\CityFrankfurtMainDocument;
use App\Contribution\Documents\CityRemscheidDocument;
use App\Contribution\Documents\RdpNrwDocument;
use App\Contribution\Documents\CitySolingenDocument;
use App\Contribution\Documents\WuppertalDocument;
@ -106,7 +103,7 @@ dataset('validation', function () {
];
});
it('compiles documents via base64 param', function (string $type, array $bodyChecks) {
it('compiles documents via api', function (string $type, array $bodyChecks) {
$this->withoutExceptionHandling();
Tex::spy();
$this->login()->loginNami();
@ -128,12 +125,12 @@ it('compiles documents via base64 param', function (string $type, array $bodyChe
$response->assertOk();
Tex::assertCompiled($type, fn ($document) => $document->hasAllContent($bodyChecks));
})->with([
[CitySolingenDocument::class, ["Super tolles Lager", "Max Muster", "Jane Muster", "15.06.1991"]],
[RdpNrwDocument::class, ["Muster, Max", "Muster, Jane", "15.06.1991", "42777 SG"]],
[CityRemscheidDocument::class, ["Max", "Muster", "Jane"]],
[CityFrankfurtMainDocument::class, ["Max", "Muster", "Jane"]],
[BdkjHesse::class, ["Max", "Muster", "Jane"]],
[WuppertalDocument::class, ["Max", "Muster", "Jane", "42777 SG", "15.06.1991", "16.06.1991"]],
["App\\Contribution\\Documents\\CitySolingenDocument", ["Super tolles Lager", "Max Muster", "Jane Muster", "15.06.1991"]],
["App\\Contribution\\Documents\\RdpNrwDocument", ["Muster, Max", "Muster, Jane", "15.06.1991", "42777 SG"]],
["App\\Contribution\\Documents\\CityRemscheidDocument", ["Max", "Muster", "Jane"]],
["App\\Contribution\\Documents\\CityFrankfurtMainDocument", ["Max", "Muster", "Jane"]],
["App\\Contribution\\Documents\\BdkjHesse", ["Max", "Muster", "Jane"]],
["App\\Contribution\\Documents\\WuppertalDocument", ["Max", "Muster", "Jane", "42777 SG", "15.06.1991", "16.06.1991"]],
]);
it('testItCompilesGroupNameInSolingenDocument', function () {
@ -148,37 +145,33 @@ it('testItCompilesGroupNameInSolingenDocument', function () {
Tex::assertCompiled(CitySolingenDocument::class, fn ($document) => $document->hasAllContent(['Stamm BiPi']));
});
it('testItCompilesContributionDocumentsViaApi', function (string $type, array $bodyChecks) {
it('testItCompilesContributionDocumentsViaApi', function () {
$this->withoutExceptionHandling();
Tex::spy();
Gender::factory()->female()->create();
Gender::factory()->male()->create();
Passport::actingAsClient(Client::factory()->create(), ['contribution-generate']);
$country = Country::factory()->create();
Member::factory()->defaults()->create(['address' => 'Maxstr 44', 'zip' => '42719', 'firstname' => 'Max', 'lastname' => 'Muster']);
Member::factory()->defaults()->create(['address' => 'Maxstr 44', 'zip' => '42719', 'firstname' => 'Jane', 'lastname' => 'Muster']);
$response = $this->postJson('/api/contribution-generate', [
'country' => Country::factory()->create()->id,
'country' => $country->id,
'dateFrom' => '1991-06-15',
'dateUntil' => '1991-06-16',
'eventName' => 'Super tolles Lager',
'type' => $type,
'type' => CitySolingenDocument::class,
'zipLocation' => '42777 SG',
'member_data' => [
ContributionMemberApiRequestFactory::new()->create(['address' => 'Maxstr 44', 'zip' => '42719', 'firstname' => 'Max', 'lastname' => 'Muster']),
ContributionMemberApiRequestFactory::new()->create(['address' => 'Maxstr 44', 'zip' => '42719', 'firstname' => 'Jane', 'lastname' => 'Muster']),
ContributionMemberApiRequestFactory::new()->create(),
ContributionMemberApiRequestFactory::new()->create(),
],
]);
$response->assertSessionDoesntHaveErrors();
$response->assertOk();
Tex::assertCompiled($type, fn ($document) => $document->hasAllContent($bodyChecks));
})->with([
[CitySolingenDocument::class, ["Super tolles Lager", "Max Muster", "Jane Muster", "15.06.1991"]],
[RdpNrwDocument::class, ["Muster, Max", "Muster, Jane", "15.06.1991", "42777 SG"]],
[CityRemscheidDocument::class, ["Max", "Muster", "Jane"]],
[CityFrankfurtMainDocument::class, ["Max", "Muster", "Jane"]],
[BdkjHesse::class, ["Max", "Muster", "Jane"]],
[WuppertalDocument::class, ["Max", "Muster", "Jane", "42777 SG", "15.06.1991", "16.06.1991"]],
]);
Tex::assertCompiled(CitySolingenDocument::class, fn ($document) => $document->hasAllContent(['Super']));
});
it('testInputShouldBeBase64EncodedJson', function (string $payload) {
$this->login()->loginNami();