Add group bulkstore backend
This commit is contained in:
parent
6972091ad0
commit
eb14189bf0
|
@ -2,6 +2,7 @@
|
|||
|
||||
namespace App;
|
||||
|
||||
use App\Group\Enums\Level;
|
||||
use App\Nami\HasNamiField;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
@ -12,9 +13,13 @@ class Group extends Model
|
|||
use HasFactory;
|
||||
use HasNamiField;
|
||||
|
||||
public $fillable = ['nami_id', 'name', 'parent_id'];
|
||||
public $fillable = ['nami_id', 'name', 'inner_name', 'level', 'parent_id'];
|
||||
public $timestamps = false;
|
||||
|
||||
public $casts = [
|
||||
'level' => Level::class
|
||||
];
|
||||
|
||||
/**
|
||||
* @return BelongsTo<static, self>
|
||||
*/
|
||||
|
|
|
@ -0,0 +1,39 @@
|
|||
<?php
|
||||
|
||||
namespace App\Group\Actions;
|
||||
|
||||
use App\Group;
|
||||
use App\Group\Enums\Level;
|
||||
use Illuminate\Database\Eloquent\Collection;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Validation\Rule;
|
||||
use Lorisleiva\Actions\ActionRequest;
|
||||
use Lorisleiva\Actions\Concerns\AsAction;
|
||||
|
||||
class GroupBulkstoreAction
|
||||
{
|
||||
use AsAction;
|
||||
|
||||
public function rules(): array
|
||||
{
|
||||
return [
|
||||
'*.id' => 'required|integer|exists:groups,id',
|
||||
'*.inner_name' => 'required|string|max:255',
|
||||
'*.level' => ['required', 'string', Rule::in(Level::values())],
|
||||
];
|
||||
}
|
||||
|
||||
public function handle($groups): void
|
||||
{
|
||||
foreach ($groups as $payload) {
|
||||
Group::find($payload['id'])->update(['level' => $payload['level'], 'inner_name' => $payload['inner_name']]);
|
||||
}
|
||||
}
|
||||
|
||||
public function asController(ActionRequest $request): JsonResponse
|
||||
{
|
||||
$this->handle($request->validated());
|
||||
|
||||
return response()->json([]);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
<?php
|
||||
|
||||
namespace App\Group\Actions;
|
||||
|
||||
use App\Group;
|
||||
use App\Group\Resources\GroupResource;
|
||||
use Illuminate\Database\Eloquent\Collection;
|
||||
use Inertia\Inertia;
|
||||
use Inertia\Response;
|
||||
use Lorisleiva\Actions\Concerns\AsAction;
|
||||
|
||||
class GroupIndexAction
|
||||
{
|
||||
use AsAction;
|
||||
|
||||
/**
|
||||
* @return Collection<int, Group>
|
||||
*/
|
||||
public function handle(): Collection
|
||||
{
|
||||
return Group::get();
|
||||
}
|
||||
|
||||
public function asController(): Response
|
||||
{
|
||||
return Inertia::render('group/Index', [
|
||||
'data' => GroupResource::collection($this->handle()),
|
||||
]);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
<?php
|
||||
|
||||
namespace App\Group\Enums;
|
||||
|
||||
use Illuminate\Support\Collection;
|
||||
|
||||
enum Level: string
|
||||
{
|
||||
|
||||
case FEDERATION = 'Diözese';
|
||||
case REGION = 'Bezirk';
|
||||
case GROUP = 'Stamm';
|
||||
|
||||
/**
|
||||
* @return Collection<int, string>
|
||||
*/
|
||||
public static function values(): Collection
|
||||
{
|
||||
return collect(static::cases())->map(fn ($case) => $case->value);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<int, array{id: string, name: string}>
|
||||
*/
|
||||
public static function forSelect(): array
|
||||
{
|
||||
return array_map(fn ($case) => ['id' => $case->value, 'name' => $case->value], static::cases());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
<?php
|
||||
|
||||
namespace App\Group\Resources;
|
||||
|
||||
use App\Lib\HasMeta;
|
||||
use Illuminate\Http\Resources\Json\JsonResource;
|
||||
|
||||
class GroupResource extends JsonResource
|
||||
{
|
||||
|
||||
use HasMeta;
|
||||
|
||||
/**
|
||||
* Transform the resource into an array.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return array|\Illuminate\Contracts\Support\Arrayable|\JsonSerializable
|
||||
*/
|
||||
public function toArray($request)
|
||||
{
|
||||
return [
|
||||
'name' => $this->name,
|
||||
'inner_name' => $this->inner_name,
|
||||
'parent_id' => $this->parent_id,
|
||||
'id' => $this->id,
|
||||
'level' => $this->level?->value,
|
||||
];
|
||||
}
|
||||
|
||||
public static function meta(): array
|
||||
{
|
||||
return [
|
||||
'links' => [
|
||||
'bulkstore' => route('group.bulkstore'),
|
||||
]
|
||||
];
|
||||
}
|
||||
}
|
|
@ -3,6 +3,7 @@
|
|||
namespace Database\Factories;
|
||||
|
||||
use App\Group;
|
||||
use App\Group\Enums\Level;
|
||||
use Illuminate\Database\Eloquent\Factories\Factory;
|
||||
|
||||
/**
|
||||
|
@ -22,6 +23,8 @@ class GroupFactory extends Factory
|
|||
return [
|
||||
'name' => $this->faker->words(5, true),
|
||||
'nami_id' => $this->faker->randomNumber(),
|
||||
'inner_name' => $this->faker->words(5, true),
|
||||
'level' => $this->faker->randomElement(Level::cases()),
|
||||
];
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,34 @@
|
|||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::table('groups', function (Blueprint $table) {
|
||||
$table->string('inner_name');
|
||||
$table->string('level')->nullable();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::table('groups', function (Blueprint $table) {
|
||||
$table->dropColumn('inner_name');
|
||||
$table->dropColumn('level');
|
||||
});
|
||||
}
|
||||
};
|
|
@ -16,6 +16,7 @@
|
|||
<v-link v-show="hasModule('bill')" href="/invoice" menu="invoice" icon="moneypaper">Rechnungen</v-link>
|
||||
<v-link href="/contribution" menu="contribution" icon="contribution">Zuschüsse</v-link>
|
||||
<v-link href="/activity" menu="activity" icon="activity">Tätigkeiten</v-link>
|
||||
<v-link href="/group" menu="group" icon="group">Gruppierungen</v-link>
|
||||
<v-link href="/maildispatcher" menu="maildispatcher" icon="at">Mail-Verteiler</v-link>
|
||||
</div>
|
||||
<div class="grid gap-2">
|
||||
|
|
|
@ -19,7 +19,8 @@ use App\Invoice\Actions\InvoiceStoreAction;
|
|||
use App\Course\Actions\CourseUpdateAction;
|
||||
use App\Dashboard\Actions\IndexAction as DashboardIndexAction;
|
||||
use App\Efz\ShowEfzDocumentAction;
|
||||
use App\Group\Actions\ListAction;
|
||||
use App\Group\Actions\GroupBulkstoreAction;
|
||||
use App\Group\Actions\GroupIndexAction;
|
||||
use App\Initialize\Actions\InitializeAction;
|
||||
use App\Initialize\Actions\InitializeFormAction;
|
||||
use App\Initialize\Actions\NamiGetSearchLayerAction;
|
||||
|
@ -31,7 +32,7 @@ use App\Invoice\Actions\InvoiceDestroyAction;
|
|||
use App\Invoice\Actions\InvoiceIndexAction;
|
||||
use App\Invoice\Actions\InvoiceUpdateAction;
|
||||
use App\Invoice\Actions\MassPostPdfAction;
|
||||
use App\Invoice\Actions\MassStoreAction;
|
||||
use App\Invoice\Actions\MassStoreAction as InvoiceMassStoreAction;
|
||||
use App\Invoice\Actions\PaymentPositionIndexAction;
|
||||
use App\Maildispatcher\Actions\CreateAction;
|
||||
use App\Maildispatcher\Actions\DestroyAction;
|
||||
|
@ -49,10 +50,11 @@ use App\Member\Actions\SearchAction;
|
|||
use App\Member\MemberController;
|
||||
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\MembershipDestroyAction;
|
||||
use App\Membership\Actions\MembershipStoreAction;
|
||||
use App\Membership\Actions\MembershipUpdateAction;
|
||||
use App\Membership\Actions\StoreForGroupAction;
|
||||
use App\Payment\SubscriptionController;
|
||||
|
||||
Route::group(['namespace' => 'App\\Http\\Controllers'], function (): void {
|
||||
|
@ -99,11 +101,9 @@ Route::group(['middleware' => 'auth:web'], function (): void {
|
|||
Route::post('/maildispatcher', MaildispatcherStoreAction::class)->name('maildispatcher.store');
|
||||
Route::delete('/maildispatcher/{maildispatcher}', DestroyAction::class)->name('maildispatcher.destroy');
|
||||
|
||||
// ----------------------------------- group -----------------------------------
|
||||
Route::get('/group', ListAction::class)->name('group.index');
|
||||
|
||||
// -------------------------------- allpayment ---------------------------------
|
||||
Route::post('/invoice/mass-store', MassStoreAction::class)->name('invoice.mass-store');
|
||||
Route::post('/invoice/mass-store', InvoiceMassStoreAction::class)->name('invoice.mass-store');
|
||||
|
||||
// ---------------------------------- invoice ----------------------------------
|
||||
Route::get('/invoice', InvoiceIndexAction::class)->name('invoice.index');
|
||||
|
@ -124,7 +124,12 @@ Route::group(['middleware' => 'auth:web'], function (): void {
|
|||
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/sync', StoreForGroupAction::class)->name('membership.sync');
|
||||
Route::post('/api/membership/masslist', MassStoreAction::class)->name('membership.masslist.store');
|
||||
Route::get('/membership/masslist', MassListAction::class)->name('membership.masslist.index');
|
||||
|
||||
// ----------------------------------- group ----------------------------------
|
||||
Route::get('/group', GroupIndexAction::class)->name('group.index');
|
||||
Route::post('/group/bulkstore', GroupBulkstoreAction::class)->name('group.bulkstore');
|
||||
|
||||
// ----------------------------------- course ----------------------------------
|
||||
Route::get('/member/{member}/course', CourseIndexAction::class)->name('member.course.index');
|
||||
|
|
|
@ -0,0 +1,30 @@
|
|||
<?php
|
||||
|
||||
namespace Tests\Feature\Group;
|
||||
|
||||
use App\Group;
|
||||
use App\Group\Enums\Level;
|
||||
use Illuminate\Foundation\Testing\DatabaseTransactions;
|
||||
use Tests\TestCase;
|
||||
|
||||
class BulkstoreTest extends TestCase
|
||||
{
|
||||
use DatabaseTransactions;
|
||||
|
||||
public function testItSavesGroupsLevelAndParent(): void
|
||||
{
|
||||
$this->login()->loginNami()->withoutExceptionHandling();
|
||||
|
||||
$group = Group::factory()->for(Group::first(), 'parent')->create(['inner_name' => 'Gruppe', 'level' => Level::REGION]);
|
||||
|
||||
$this->postJson(route('group.bulkstore'), [
|
||||
['id' => $group->id, 'inner_name' => 'Abc', 'level' => Level::FEDERATION->value]
|
||||
])->assertOk();
|
||||
|
||||
$this->assertDatabaseHas('groups', [
|
||||
'id' => $group->id,
|
||||
'inner_name' => 'Abc',
|
||||
'level' => 'Diözese',
|
||||
]);
|
||||
}
|
||||
}
|
|
@ -2,9 +2,8 @@
|
|||
|
||||
namespace Tests\Feature\Group;
|
||||
|
||||
use App\Activity;
|
||||
use App\Group;
|
||||
use App\Subactivity;
|
||||
use App\Group\Enums\Level;
|
||||
use Illuminate\Foundation\Testing\DatabaseTransactions;
|
||||
use Tests\TestCase;
|
||||
|
||||
|
@ -14,18 +13,25 @@ class IndexTest extends TestCase
|
|||
|
||||
public function testItDisplaysAllActivitiesAndSubactivities(): void
|
||||
{
|
||||
$this->login()->loginNami();
|
||||
$this->login()->loginNami()->withoutExceptionHandling();
|
||||
|
||||
$leiter = Activity::factory()->name('Leiter*in')->hasAttached(Subactivity::factory()->name('Rover'))->create();
|
||||
$intern = Activity::factory()->name('Intern')->hasAttached(Subactivity::factory()->name('Lager'))->create();
|
||||
$group = Group::factory()->create();
|
||||
$group = Group::factory()->for(Group::first(), 'parent')->create(['name' => 'Afff', 'inner_name' => 'Gruppe', 'level' => Level::REGION]);
|
||||
|
||||
$response = $this->get('/group');
|
||||
$this->get('/group')
|
||||
->assertInertiaPath('data.data.2.name', 'Afff')
|
||||
->assertInertiaPath('data.data.2.inner_name', 'Gruppe')
|
||||
->assertInertiaPath('data.data.2.id', $group->id)
|
||||
->assertInertiaPath('data.data.2.level', 'Bezirk')
|
||||
->assertInertiaPath('data.data.2.parent_id', Group::first()->id)
|
||||
->assertInertiaPath('data.meta.links.bulkstore', route('group.bulkstore'));
|
||||
}
|
||||
|
||||
$this->assertInertiaHas('Leiter*in', $response, "activities.{$leiter->id}");
|
||||
$this->assertInertiaHas('Intern', $response, "activities.{$intern->id}");
|
||||
$this->assertInertiaHas('Rover', $response, "subactivities.{$leiter->id}.{$leiter->subactivities->first()->id}");
|
||||
$this->assertInertiaHas('Lager', $response, "subactivities.{$intern->id}.{$intern->subactivities->first()->id}");
|
||||
$this->assertInertiaHas($group->name, $response, "groups.{$group->id}");
|
||||
public function testLevelCanBeNull(): void
|
||||
{
|
||||
$this->login()->loginNami()->withoutExceptionHandling();
|
||||
|
||||
Group::factory()->create(['level' => null]);
|
||||
|
||||
$this->get('/group')->assertInertiaPath('data.data.2.level', null);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -40,7 +40,7 @@ class InitializeGroupsTest extends TestCase
|
|||
|
||||
(new InitializeGroups(app(NamiSettings::class)->login()))->handle();
|
||||
|
||||
$this->assertDatabaseHas('groups', ['nami_id' => 1000, 'name' => 'testgroup']);
|
||||
$this->assertDatabaseHas('groups', ['nami_id' => 1000, 'name' => 'testgroup', 'inner_name' => 'testgroup', 'level' => null]);
|
||||
$this->assertDatabaseHas('groups', ['nami_id' => 1001, 'name' => 'subgroup1']);
|
||||
$this->assertDatabaseHas('groups', ['nami_id' => 1002, 'name' => 'subgroup2']);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue