Dont require birthday field
continuous-integration/drone/push Build is failing Details

This commit is contained in:
philipp lang 2023-07-24 16:55:07 +02:00
parent 826cc43b92
commit f11226b0a1
13 changed files with 199 additions and 17 deletions

View File

@ -32,6 +32,8 @@ class FilterScope extends Filter
public array $groupIds = [],
public array $include = [],
public array $exclude = [],
public ?bool $hasFullAddress = null,
public ?bool $hasBirthday = null,
) {
}
@ -60,6 +62,22 @@ class FilterScope extends Filter
$query->where('bill_kind', BillKind::fromValue($this->billKind));
}
if (true === $this->hasFullAddress) {
$query->whereNotNull('address')->whereNotNull('zip')->whereNotNull('location')->where('address', '!=', '')->where('zip', '!=', '')->where('location', '!=', '');
}
if (false === $this->hasFullAddress) {
$query->where(fn ($q) => $q
->orWhere('address', '')->orWhereNull('address')
->orWhere('zip', '')->orWhereNull('zip')
->orWhere('location', '')->orWhereNull('location')
);
}
if (true === $this->hasBirthday) {
$query->whereNotNull('birthday');
}
if (count($this->groupIds)) {
$query->whereIn('group_id', $this->groupIds);
}

View File

@ -161,7 +161,7 @@ class Member extends Model implements Geolocatable
public function getEfzLink(): ?string
{
return $this->isLeader()
return $this->isLeader() && $this->address && $this->zip && $this->location && $this->birthday
? route('efz', ['member' => $this])
: null;
}
@ -436,11 +436,14 @@ class Member extends Model implements Geolocatable
'VERSION' => '3.0',
'FN' => $this->fullname,
'N' => [$this->lastname, $this->firstname, '', '', ''],
'BDAY' => $this->birthday->format('Ymd'),
'CATEGORIES' => 'Scoutrobot',
'UID' => $this->slug,
]);
if ($this->birthday) {
$card->add('BDAY', $this->birthday->format('Ymd'));
}
if ($this->main_phone) {
$card->add('TEL', $this->main_phone, ['type' => 'voice']);
}

View File

@ -12,6 +12,7 @@ use App\Subactivity;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Support\Str;
use Illuminate\Validation\Rule;
use Illuminate\Validation\Validator;
use Zoomyboy\Phone\ValidPhoneRule;
class MemberRequest extends FormRequest
@ -51,15 +52,10 @@ class MemberRequest extends FormRequest
}),
'firstname' => 'required',
'lastname' => 'required',
'address' => 'required',
'zip' => 'required|numeric',
'location' => 'required',
'birthday' => 'date|required',
'country_id' => 'required|exists:countries,id',
'email' => 'nullable|email',
'email_parents' => 'nullable|email',
'bill_kind' => ['nullable', Rule::in(BillKind::values())],
'joined_at' => 'date|required',
'confession_id' => 'nullable|exists:confessions,id',
'ps_at' => 'nullable|date_format:Y-m-d',
'more_ps_at' => 'nullable|date_format:Y-m-d',
@ -76,7 +72,6 @@ class MemberRequest extends FormRequest
'invoice_address' => '',
'gender_id' => 'nullable|exists:genders,id',
'region_id' => 'nullable|exists:regions,id',
'nationality_id' => 'required|exists:nationalities,id',
'children_phone' => ['nullable', new ValidPhoneRule('Telefon (Kind)')],
'fax' => ['nullable', new ValidPhoneRule('Fax')],
'other_country' => '',
@ -122,4 +117,23 @@ class MemberRequest extends FormRequest
}
ResyncAction::dispatch();
}
public function withValidator(Validator $validator): void
{
$this->namiIfElse($validator, 'birthday', 'date|required');
$this->namiIfElse($validator, 'nationality_id', 'required|exists:nationalities,id');
$this->namiIfElse($validator, 'address', 'required|max:255');
$this->namiIfElse($validator, 'zip', 'required|numeric');
$this->namiIfElse($validator, 'location', 'required|max:255');
$this->namiIfElse($validator, 'joined_at', 'date|required');
}
public function namiIfElse(Validator $validator, string $attribute, string $rules): void
{
$request = request();
$when = fn () => true === $request->input('has_nami');
$notWhen = fn () => true !== $request->input('has_nami');
$validator->sometimes($attribute, $rules, $when);
$validator->sometimes($attribute, 'present', $notWhen);
}
}

View File

@ -0,0 +1,41 @@
<?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('members', function (Blueprint $table) {
$table->unsignedBigInteger('nationality_id')->nullable(true)->change();
$table->date('birthday')->nullable(true)->change();
$table->string('address')->nullable(true)->change();
$table->string('zip')->nullable(true)->change();
$table->string('location')->nullable(true)->change();
$table->date('joined_at')->nullable(true)->change();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::table('members', function (Blueprint $table) {
$table->unsignedBigInteger('nationality_id')->nullable(false)->change();
$table->date('birthday')->nullable(false)->change();
$table->string('address')->nullable(false)->change();
$table->string('zip')->nullable(false)->change();
$table->string('location')->nullable(false)->change();
$table->date('joined_at')->nullable(false)->change();
});
}
};

View File

@ -86,6 +86,8 @@ export default {
var response = await this.axios.post('/api/member/search', {
filter: {
search: event,
hasBirthday: true,
hasFullAddress: true,
},
});

View File

@ -27,14 +27,14 @@
<f-select id="gender_id" name="gender_id" :options="meta.genders" v-model="inner.gender_id" label="Geschlecht" size="sm"></f-select>
<f-text id="salutation" v-model="inner.salutation" size="sm" label="Anrede"></f-text>
</div>
<f-select :options="meta.nationalities" id="nationality_id" v-model="inner.nationality_id" label="Staatsangehörigkeit" name="nationality_id" size="sm" required></f-select>
<f-select :options="meta.nationalities" id="nationality_id" v-model="inner.nationality_id" label="Staatsangehörigkeit" name="nationality_id" size="sm"></f-select>
<f-text id="firstname" v-model="inner.firstname" size="sm" label="Vorname" required></f-text>
<f-text id="lastname" v-model="inner.lastname" size="sm" label="Nachname" required></f-text>
<f-text id="address" v-model="inner.address" size="sm" label="Adresse" required></f-text>
<f-text id="address" v-model="inner.address" size="sm" label="Adresse"></f-text>
<f-text id="further_address" v-model="inner.further_address" size="sm" label="Adresszusatz"></f-text>
<f-text id="zip" v-model="inner.zip" size="sm" label="PLZ" required></f-text>
<f-text id="location" v-model="inner.location" size="sm" label="Ort" required></f-text>
<f-text type="date" id="birthday" v-model="inner.birthday" size="sm" label="Geburtsdatum" required></f-text>
<f-text id="zip" v-model="inner.zip" size="sm" label="PLZ"></f-text>
<f-text id="location" v-model="inner.location" size="sm" label="Ort"></f-text>
<f-text type="date" id="birthday" v-model="inner.birthday" size="sm" label="Geburtsdatum"></f-text>
<f-select :options="meta.regions" name="region_id" id="region_id" v-model="inner.region_id" label="Bundesland" size="sm"></f-select>
<f-select :options="meta.countries" id="country_id" v-model="inner.country_id" label="Land" name="country_id" size="sm" required></f-select>
<f-text id="other_country" v-model="inner.other_country" label="Andere Staatsangehörigkeit" size="sm"></f-text>

View File

@ -5,7 +5,7 @@
<ui-text-display label="Geburtsdatum" :value="inner.birthday_human"></ui-text-display>
<ui-text-display label="Alter" :value="inner.age"></ui-text-display>
<ui-text-display label="Bundesland" :value="inner.region.name"></ui-text-display>
<ui-text-display label="Nationalität" :value="inner.nationality.name"></ui-text-display>
<ui-text-display label="Nationalität" :value="inner.nationality?.name"></ui-text-display>
<ui-text-display v-show="inner.other_country" label="Andere Staatsangehörigkeit" :value="inner.other_country"></ui-text-display>
</div>
</template>

View File

@ -25,6 +25,33 @@ class MemberIndexTest extends TestCase
$this->assertCount(1, $this->inertia($response, 'data.data'));
}
public function testItHandlesAddress(): void
{
$this->withoutExceptionHandling()->login()->loginNami();
$group = Group::factory()->create();
Member::factory()->defaults()->for(Group::factory())->create(['address' => '']);
Member::factory()->defaults()->for(Group::factory())->create(['zip' => '']);
Member::factory()->defaults()->for(Group::factory())->create(['location' => '']);
$response = $this->callFilter('member.index', ['has_full_address' => true]);
$noResponse = $this->callFilter('member.index', ['has_full_address' => false]);
$this->assertCount(0, $this->inertia($response, 'data.data'));
$this->assertCount(3, $this->inertia($noResponse, 'data.data'));
}
public function testItHandlesBirthday(): void
{
$this->withoutExceptionHandling()->login()->loginNami();
$group = Group::factory()->create();
$member = Member::factory()->defaults()->for(Group::factory())->create(['birthday' => null]);
$response = $this->callFilter('member.index', ['has_birthday' => true]);
$this->assertCount(0, $this->inertia($response, 'data.data'));
$member->delete();
}
public function testItFiltersForSearchButNotForPayments(): void
{
$this->withoutExceptionHandling()->login()->loginNami();

View File

@ -76,6 +76,15 @@ VCARD;
$this->assertEquals('Max Muster', $card->FN->getValue());
}
public function testItDoesntNeedBirthday(): void
{
$member = Member::factory()->defaults()->create(['birthday' => null]);
$card = $member->toVcard();
$this->assertNull($card->BDAY);
}
public function testItSetsTheBirthday(): void
{
$member = Member::factory()->defaults()->create(['birthday' => '1993-05-06']);

View File

@ -80,6 +80,19 @@ class IndexTest extends TestCase
$this->assertInertiaHas(false, $response, 'data.data.2.is_leader');
}
public function testItHasNoEfzLinkWhenAddressIsMissing(): void
{
$this->withoutExceptionHandling()->login()->loginNami();
$member = Member::factory()
->defaults()
->has(Membership::factory()->in('€ LeiterIn', 455, 'Pfadfinder', 15))
->create(['address' => null]);
$response = $this->get('/member');
$this->assertInertiaHas(null, $response, 'data.data.0.efz_link');
}
public function testItShowsAgeGroupIcon(): void
{
$this->withoutExceptionHandling()->login()->loginNami();
@ -93,6 +106,17 @@ class IndexTest extends TestCase
$this->assertInertiaHas('woelfling', $response, 'data.data.0.age_group_icon');
}
public function testAgeIsNullWhenBirthdayIsNull(): void
{
$this->withoutExceptionHandling()->login()->loginNami();
$member = Member::factory()->defaults()->create(['birthday' => null]);
$response = $this->get('/member');
$this->assertInertiaHas(null, $response, 'data.data.0.age');
$this->assertInertiaHas(null, $response, 'data.data.0.birthday');
}
public function testItShowsActivitiesAndSubactivities(): void
{
$this->withoutExceptionHandling()->login()->loginNami();

View File

@ -24,5 +24,4 @@ class SearchTest extends TestCase
$this->assertEquals('::firstname:: ::lastname:: Kölner Str 3, 33333 Hilden', $member->search_text);
}
}

View File

@ -47,7 +47,7 @@ class StoreTest extends TestCase
'bill_kind' => 'Post',
'salutation' => 'Doktor',
'comment' => 'Lorem bla',
]));
]))->assertSessionHasNoErrors();
$response->assertRedirect('/member')->assertSessionHasNoErrors();
$member = Member::firstWhere('firstname', 'Joe');
@ -140,6 +140,30 @@ class StoreTest extends TestCase
]);
}
public function testItDoesntRequireBirthdayWhenNotInNami(): void
{
$this->login()->loginNami();
$this
->post('/member', $this->attributes([
'nationality_id' => null,
'birthday' => null,
'has_nami' => false,
'address' => null,
'zip' => null,
'location' => null,
'joined_at' => null,
]));
$this->assertDatabaseHas('members', [
'nationality_id' => null,
'birthday' => null,
'address' => null,
'zip' => null,
'location' => null,
'joined_at' => null,
]);
}
public function testItRequiresFields(): void
{
$this->login()->loginNami();
@ -147,8 +171,13 @@ class StoreTest extends TestCase
$this
->post('/member', $this->attributes([
'nationality_id' => null,
'birthday' => '',
'address' => '',
'zip' => '',
'location' => '',
'joined_at' => '',
]))
->assertSessionHasErrors(['nationality_id']);
->assertSessionHasErrors(['nationality_id', 'birthday', 'address', 'zip', 'location', 'joined_at']);
}
public function testSubscriptionIsRequiredIfFirstActivityIsPaid(): void

View File

@ -73,6 +73,22 @@ class UpdateTest extends TestCase
]);
}
public function testItSetsLocationToNull(): void
{
$this->withoutExceptionHandling()->login()->loginNami();
$member = $this->member(['location' => 'Hilden', 'nami_id' => null]);
$this->fakeRequest();
NamiPutMemberAction::allowToRun();
$this->patch("/member/{$member->id}", array_merge($member->getAttributes(), [
'location' => null,
]));
$this->assertDatabaseHas('members', [
'location' => null,
]);
}
public function testItUpdatesContact(): void
{
$this->withoutExceptionHandling()->login()->loginNami();