Add Backend for displaying memberships
continuous-integration/drone/push Build is failing
Details
continuous-integration/drone/push Build is failing
Details
This commit is contained in:
parent
878de3f566
commit
66b6a549c3
|
@ -0,0 +1,29 @@
|
|||
<?php
|
||||
|
||||
namespace App\Lib\Data;
|
||||
|
||||
use Spatie\LaravelData\Normalizers\Normalizer;
|
||||
use App\Lib\Normalizers\DateNormalizer;
|
||||
use Spatie\LaravelData\Data;
|
||||
use Spatie\LaravelData\Attributes\WithTransformer;
|
||||
use App\Lib\Transformers\DateTransformer;
|
||||
use Carbon\Carbon;
|
||||
|
||||
class DateData extends Data
|
||||
{
|
||||
public function __construct(
|
||||
#[WithTransformer(DateTransformer::class)]
|
||||
public Carbon $raw,
|
||||
public string $human,
|
||||
) {}
|
||||
|
||||
/**
|
||||
* @return array<int, class-string<Normalizer>>
|
||||
*/
|
||||
public static function normalizers(): array
|
||||
{
|
||||
return [
|
||||
DateNormalizer::class,
|
||||
];
|
||||
}
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
<?php
|
||||
|
||||
namespace App\Lib\Data;
|
||||
|
||||
use Spatie\LaravelData\Data;
|
||||
|
||||
class RecordData extends Data {
|
||||
|
||||
public function __construct(
|
||||
public int $id,
|
||||
public string $name,
|
||||
) {}
|
||||
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
<?php
|
||||
|
||||
namespace App\Lib\Normalizers;
|
||||
|
||||
use Spatie\LaravelData\Normalizers\Normalizer;
|
||||
use Carbon\Carbon;
|
||||
|
||||
class DateNormalizer implements Normalizer
|
||||
{
|
||||
/**
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
public function normalize(mixed $value): ?array
|
||||
{
|
||||
if (!$value instanceof Carbon) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return [
|
||||
'raw' => $value,
|
||||
'human' => $value->format('d.m.Y'),
|
||||
];
|
||||
}
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
<?php
|
||||
|
||||
namespace App\Lib\Transformers;
|
||||
|
||||
use Spatie\LaravelData\Transformers\Transformer;
|
||||
use Spatie\LaravelData\Support\DataProperty;
|
||||
use Spatie\LaravelData\Support\Transformation\TransformationContext;
|
||||
use Carbon\Carbon;
|
||||
|
||||
class DateTransformer implements Transformer
|
||||
{
|
||||
public function transform(DataProperty $property, mixed $value, TransformationContext $context): string
|
||||
{
|
||||
return Carbon::parse($value)->format('Y-m-d');
|
||||
}
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
<?php
|
||||
|
||||
namespace App\Member\Data;
|
||||
|
||||
use Spatie\LaravelData\Data;
|
||||
use App\Lib\Data\DateData;
|
||||
use App\Lib\Data\RecordData;
|
||||
use App\Member\Membership;
|
||||
|
||||
class MembershipData extends Data
|
||||
{
|
||||
|
||||
public function __construct(
|
||||
public int $id,
|
||||
public RecordData $activity,
|
||||
public ?RecordData $subactivity,
|
||||
public RecordData $group,
|
||||
public ?DateData $promisedAt,
|
||||
public DateData $from,
|
||||
public bool $isActive,
|
||||
public array $links,
|
||||
) {}
|
||||
|
||||
public static function fromModel(Membership $membership): static
|
||||
{
|
||||
return static::factory()->withoutMagicalCreation()->from([
|
||||
'id' => $membership->id,
|
||||
'activity' => $membership->activity,
|
||||
'subactivity' => $membership->subactivity,
|
||||
'isActive' => $membership->isActive(),
|
||||
'from' => $membership->from,
|
||||
'group' => $membership->group,
|
||||
'promisedAt' => $membership->promised_at,
|
||||
'links' => [
|
||||
'update' => route('membership.update', $membership),
|
||||
'destroy' => route('membership.destroy', $membership),
|
||||
]
|
||||
]);
|
||||
}
|
||||
|
||||
}
|
|
@ -9,7 +9,7 @@ use Illuminate\Database\Eloquent\Collection;
|
|||
use Illuminate\Http\Resources\Json\AnonymousResourceCollection;
|
||||
use Lorisleiva\Actions\Concerns\AsAction;
|
||||
|
||||
class IndexAction
|
||||
class MemberIndexAction
|
||||
{
|
||||
use AsAction;
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
<?php
|
||||
|
||||
namespace App\Membership\Actions;
|
||||
|
||||
use App\Member\Data\MembershipData;
|
||||
use App\Member\Membership;
|
||||
use Inertia\Inertia;
|
||||
use Inertia\Response;
|
||||
use Lorisleiva\Actions\Concerns\AsAction;
|
||||
use Spatie\LaravelData\PaginatedDataCollection;
|
||||
|
||||
class MembershipIndexAction
|
||||
{
|
||||
use AsAction;
|
||||
|
||||
public function asController(): Response
|
||||
{
|
||||
return Inertia::render(
|
||||
'membership/Index',
|
||||
MembershipData::collect(Membership::orderByRaw('member_id, activity_id, subactivity_id')->paginate(20), PaginatedDataCollection::class)->wrap('data')
|
||||
);
|
||||
}
|
||||
}
|
|
@ -73,7 +73,9 @@ use App\Membership\Actions\IndexAction as MembershipIndexAction;
|
|||
use App\Membership\Actions\ListForGroupAction;
|
||||
use App\Membership\Actions\MassListAction;
|
||||
use App\Membership\Actions\MassStoreAction;
|
||||
use App\Membership\Actions\MemberIndexAction;
|
||||
use App\Membership\Actions\MembershipDestroyAction;
|
||||
use App\Membership\Actions\MembershipIndexAction as ActionsMembershipIndexAction;
|
||||
use App\Membership\Actions\MembershipStoreAction;
|
||||
use App\Membership\Actions\MembershipUpdateAction;
|
||||
use App\Payment\SubscriptionController;
|
||||
|
@ -140,13 +142,14 @@ Route::group(['middleware' => 'auth:web'], function (): void {
|
|||
Route::get('/member/{member}/invoice-position', PaymentPositionIndexAction::class)->name('member.invoice-position.index');
|
||||
|
||||
// --------------------------------- membership --------------------------------
|
||||
Route::get('/member/{member}/membership', MembershipIndexAction::class)->name('member.membership.index');
|
||||
Route::get('/member/{member}/membership', MemberIndexAction::class)->name('member.membership.index');
|
||||
Route::post('/member/{member}/membership', MembershipStoreAction::class)->name('member.membership.store');
|
||||
Route::patch('/membership/{membership}', MembershipUpdateAction::class)->name('membership.update');
|
||||
Route::delete('/membership/{membership}', MembershipDestroyAction::class)->name('membership.destroy');
|
||||
Route::post('/api/membership/member-list', ListForGroupAction::class)->name('membership.member-list');
|
||||
Route::post('/api/membership/masslist', MassStoreAction::class)->name('membership.masslist.store');
|
||||
Route::get('/membership/masslist', MassListAction::class)->name('membership.masslist.index');
|
||||
Route::get('/membership', ActionsMembershipIndexAction::class)->name('membership.index');
|
||||
|
||||
// ----------------------------------- group ----------------------------------
|
||||
Route::get('/group', GroupIndexAction::class)->name('group.index');
|
||||
|
|
|
@ -63,7 +63,7 @@ it('cannot create membership when activity and subactivity doesnt belong togethe
|
|||
])->assertJsonValidationErrors(['activity_id' => 'Tätigkeit ist nicht vorhanden.']);
|
||||
});
|
||||
|
||||
it('testItDeletesAMembership', function() {
|
||||
it('deletes a membership', function() {
|
||||
MembershipDestroyAction::partialMock()->shouldReceive('handle')->once();
|
||||
MembershipStoreAction::partialMock()->shouldReceive('handle')->never();
|
||||
ResyncAction::partialMock()->shouldReceive('handle')->once();
|
||||
|
@ -73,7 +73,7 @@ it('testItDeletesAMembership', function() {
|
|||
MassStoreAction::run($member->memberships->first()->group, $member->memberships->first()->activity, $member->memberships->first()->subactivity, []);
|
||||
});
|
||||
|
||||
it('testItRollsbackWhenDeletionFails', function() {
|
||||
it('rolls back when deletion fails', function() {
|
||||
app(MembershipFake::class)
|
||||
->shows(3, ['id' => 55])
|
||||
->shows(3, ['id' => 56])
|
||||
|
|
|
@ -0,0 +1,49 @@
|
|||
<?php
|
||||
|
||||
namespace Tests\Feature\Membership;
|
||||
|
||||
use App\Activity;
|
||||
use App\Group;
|
||||
use App\Member\Data\MembershipData;
|
||||
use App\Member\Member;
|
||||
use App\Member\Membership;
|
||||
use App\Subactivity;
|
||||
use Illuminate\Foundation\Testing\DatabaseTransactions;
|
||||
use Inertia\Testing\AssertableInertia as Assert;
|
||||
|
||||
uses(DatabaseTransactions::class);
|
||||
|
||||
mutates(MembershipData::class);
|
||||
|
||||
it('lists memberships of users', function () {
|
||||
$this->login()->loginNami()->withoutExceptionHandling();
|
||||
$activity = Activity::factory()
|
||||
->hasAttached(Subactivity::factory()->name('SubAct'))
|
||||
->name('Act')
|
||||
->create();
|
||||
$group = Group::factory()->name('GG')->create();
|
||||
$member = Member::factory()->defaults()
|
||||
->for($group)
|
||||
->has(Membership::factory()->for($activity)->for($activity->subactivities->first())->for($group))
|
||||
->male()
|
||||
->name('Max Muster')
|
||||
->create();
|
||||
|
||||
$activity->subactivities()->first();
|
||||
$this->callFilter('membership.index', [])
|
||||
->assertInertia(fn(Assert $page) => $page
|
||||
->has('data.0', fn(Assert $page) => $page
|
||||
->where('activity.name', 'Act')
|
||||
->where('subactivity.name', 'SubAct')
|
||||
->where('group.name', 'GG')
|
||||
->where('promisedAt', null)
|
||||
->where('links.update', route('membership.update', $member->memberships->first()))
|
||||
->where('links.destroy', route('membership.destroy', $member->memberships->first()))
|
||||
->etc()
|
||||
)->has('meta', fn (Assert $page) => $page
|
||||
->where('current_page', 1)
|
||||
->etc()
|
||||
)
|
||||
);
|
||||
});
|
||||
|
Loading…
Reference in New Issue