Compare commits
11 Commits
1ba3d11325
...
56af6f4cbf
| Author | SHA1 | Date |
|---|---|---|
|
|
56af6f4cbf | |
|
|
ac88df2cad | |
|
|
adc78a65e7 | |
|
|
c7618b0545 | |
|
|
e5c2599846 | |
|
|
3a80e3bcee | |
|
|
4abdac75f6 | |
|
|
1e4361c709 | |
|
|
8924774ed0 | |
|
|
f0ed9185ba | |
|
|
f9deb56d22 |
|
|
@ -1,5 +1,9 @@
|
|||
# Letzte Änderungen
|
||||
|
||||
### 1.12.22
|
||||
|
||||
- Bei Mitgliedern wird nun auch die geschäftliche tel-nr aktualisiert
|
||||
|
||||
### 1.12.21
|
||||
|
||||
- Reply-To-Header bei Versand von Prävention-und-Veranstaltungs-Mails kann nun eingestellt werden
|
||||
|
|
|
|||
|
|
@ -31,25 +31,27 @@ class CreateExcelDocumentAction
|
|||
private function allSheet(Collection $participants): TableDocumentData
|
||||
{
|
||||
$document = TableDocumentData::from(['title' => 'Anmeldungen für ' . $this->form->name, 'sheets' => []]);
|
||||
$headers = $this->form->getFields()->map(fn ($field) => $field->name)->toArray();
|
||||
$headers = $this->form->getFields()->names()->push('Abgemeldet am')->prepend('ID')->toArray();
|
||||
[$activeParticipants, $cancelledParticipants] = $participants->partition(fn ($participant) => $participant->cancelled_at === null);
|
||||
|
||||
$document->addSheet(SheetData::from([
|
||||
'header' => $headers,
|
||||
'data' => $participants
|
||||
->map(fn ($participant) => $this->form->getFields()->map(fn ($field) => $participant->getFields()->find($field)->presentRaw())->toArray())
|
||||
->toArray(),
|
||||
'data' => $this->rowsFor($activeParticipants),
|
||||
'name' => 'Alle',
|
||||
]));
|
||||
$document->addSheet(SheetData::from([
|
||||
'header' => $headers,
|
||||
'data' => $this->rowsFor($cancelledParticipants),
|
||||
'name' => 'Abgemeldet',
|
||||
]));
|
||||
|
||||
if ($this->form->export->groupBy) {
|
||||
$groups = $participants->groupBy(fn ($participant) => $participant->getFields()->findByKey($this->form->export->groupBy)->presentRaw());
|
||||
$groups = $activeParticipants->groupBy(fn ($participant) => $participant->getFields()->findByKey($this->form->export->groupBy)->presentRaw());
|
||||
|
||||
foreach ($groups as $name => $participants) {
|
||||
foreach ($groups as $name => $groupedParticipants) {
|
||||
$document->addSheet(SheetData::from([
|
||||
'header' => $headers,
|
||||
'data' => $participants
|
||||
->map(fn ($participant) => $this->form->getFields()->map(fn ($field) => $participant->getFields()->find($field)->presentRaw())->toArray())
|
||||
->toArray(),
|
||||
'data' => $this->rowsFor($groupedParticipants),
|
||||
'name' => $name,
|
||||
]));
|
||||
}
|
||||
|
|
@ -64,6 +66,17 @@ class CreateExcelDocumentAction
|
|||
return $document;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Collection<int, Participant> $participants
|
||||
* @return array<int, array<string, mixed>>
|
||||
*/
|
||||
public function rowsFor(Collection $participants): array {
|
||||
return $participants->map(fn ($participant) => $participant->getFields()->presentValues()
|
||||
->put('Abgemeldet am', $participant->cancelled_at?->format('d.m.Y H:i:s') ?: '')
|
||||
->prepend((string) $participant->id, 'ID')
|
||||
)->toArray();
|
||||
}
|
||||
|
||||
private function tempPath(): string
|
||||
{
|
||||
return sys_get_temp_dir() . '/' . str()->uuid()->toString();
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ class ParticipantDestroyAction
|
|||
|
||||
public function handle(int $participantId): void
|
||||
{
|
||||
Participant::findOrFail($participantId)->delete();
|
||||
Participant::findOrFail($participantId)->update(['cancelled_at' => now()]);
|
||||
}
|
||||
|
||||
public function asController(Participant $participant): void
|
||||
|
|
|
|||
|
|
@ -18,10 +18,10 @@ class UpdateParticipantSearchIndexAction
|
|||
$form->searchableUsing()->updateIndexSettings(
|
||||
$form->participantsSearchableAs(),
|
||||
[
|
||||
'filterableAttributes' => [...$form->getFields()->filterables()->getKeys(), 'parent-id'],
|
||||
'filterableAttributes' => [...$form->getFields()->filterables()->getKeys(), 'parent-id', 'cancelled_at'],
|
||||
'searchableAttributes' => $form->getFields()->searchables()->getKeys(),
|
||||
'sortableAttributes' => [...$form->getFields()->sortables()->getKeys(), 'id', 'created_at'],
|
||||
'displayedAttributes' => [...$form->getFields()->filterables()->getKeys(), ...$form->getFields()->searchables()->getKeys(), 'id'],
|
||||
'displayedAttributes' => [...$form->getFields()->filterables()->getKeys(), ...$form->getFields()->searchables()->getKeys(), 'id', 'cancelled_at'],
|
||||
'pagination' => [
|
||||
'maxTotalHits' => 1000000,
|
||||
]
|
||||
|
|
|
|||
|
|
@ -99,19 +99,19 @@ class FieldCollection extends Collection
|
|||
}
|
||||
|
||||
/**
|
||||
* @return array<int, string>
|
||||
* @return Collection<int, string>
|
||||
*/
|
||||
public function names(): array
|
||||
public function names(): Collection
|
||||
{
|
||||
return $this->map(fn ($field) => $field->name)->toArray();
|
||||
return $this->map(fn ($field) => $field->name);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<int, string>
|
||||
* @return Collection<string, string>
|
||||
*/
|
||||
public function presentValues(): array
|
||||
public function presentValues(): Collection
|
||||
{
|
||||
return $this->map(fn ($field) => $field->presentRaw())->toArray();
|
||||
return $this->mapWithKeys(fn ($field) => [$field->name => $field->presentRaw()]);
|
||||
}
|
||||
|
||||
public function hasSpecialType(SpecialType $specialType): bool
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@ class Participant extends Model implements Preventable
|
|||
public $casts = [
|
||||
'data' => 'json',
|
||||
'last_remembered_at' => 'datetime',
|
||||
'cancelled_at' => 'datetime',
|
||||
];
|
||||
|
||||
/**
|
||||
|
|
@ -108,7 +109,12 @@ class Participant extends Model implements Preventable
|
|||
/** @return array<string, mixed> */
|
||||
public function toSearchableArray(): array
|
||||
{
|
||||
return [...$this->data, 'parent-id' => $this->parent_id, 'created_at' => $this->created_at->timestamp];
|
||||
return [
|
||||
...$this->data,
|
||||
'parent-id' => $this->parent_id,
|
||||
'created_at' => $this->created_at->timestamp,
|
||||
'cancelled_at' => $this->cancelled_at
|
||||
];
|
||||
}
|
||||
|
||||
public function matchesCondition(Condition $condition): bool {
|
||||
|
|
|
|||
|
|
@ -54,6 +54,8 @@ class ParticipantFilterScope extends ScoutFilter
|
|||
$filter->push('parent-id IS NULL');
|
||||
}
|
||||
|
||||
$filter->push('cancelled_at IS NULL');
|
||||
|
||||
if ($this->parent !== null && $this->parent !== -1) {
|
||||
$filter->push('parent-id = ' . $this->parent);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -75,6 +75,7 @@ class MemberRequest extends FormRequest
|
|||
'send_newspaper' => 'boolean',
|
||||
'main_phone' => ['nullable', new ValidPhoneRule('Telefon (Eltern)')],
|
||||
'mobile_phone' => ['nullable', new ValidPhoneRule('Handy (Eltern)')],
|
||||
'work_phone' => ['nullable', new ValidPhoneRule('Tel geschäftlich')],
|
||||
'invoice_address' => '',
|
||||
'gender_id' => 'nullable|exists:genders,id',
|
||||
'region_id' => 'nullable|exists:regions,id',
|
||||
|
|
|
|||
|
|
@ -0,0 +1,28 @@
|
|||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Schema::table('participants', function (Blueprint $table) {
|
||||
$table->datetime('cancelled_at')->nullable();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::table('participants', function (Blueprint $table) {
|
||||
$table->dropColumn('cancelled_at');
|
||||
});
|
||||
}
|
||||
};
|
||||
|
|
@ -1 +1 @@
|
|||
Subproject commit 7304963370ff64fb5accf08da4864981cc424301
|
||||
Subproject commit f7b04591830ebdeaddf76236e4cbc87a8b3eec8f
|
||||
|
|
@ -269,6 +269,15 @@ it('testItShowsPreventionState', function () {
|
|||
->assertJsonPath('data.0.prevention_items.0.tooltip', 'erweitertes Führungszeugnis nicht vorhanden');
|
||||
});
|
||||
|
||||
it('doesnt show cancelled participants', function () {
|
||||
$this->login()->loginNami()->withoutExceptionHandling();
|
||||
$participant = Participant::factory()->for(Form::factory())->create(['cancelled_at' => now()]);
|
||||
|
||||
sleep(2);
|
||||
$this->callFilter('form.participant.index', [], ['form' => $participant->form])
|
||||
->assertJsonCount(0, 'data');
|
||||
});
|
||||
|
||||
it('test it orders participants by value', function (array $values, array $sorting, array $expected) {
|
||||
list($key, $direction) = $sorting;
|
||||
$this->login()->loginNami()->withoutExceptionHandling();
|
||||
|
|
|
|||
|
|
@ -24,5 +24,9 @@ it('testItCanDestroyAParticipant', function () {
|
|||
$this->deleteJson(route('participant.destroy', ['participant' => $form->participants->first()]))
|
||||
->assertOk();
|
||||
|
||||
$this->assertDatabaseCount('participants', 0);
|
||||
$this->assertDatabaseCount('participants', 1);
|
||||
$this->assertDatabaseHas('participants', [
|
||||
'cancelled_at' => now(),
|
||||
'id' => $form->participants->first()->id,
|
||||
]);
|
||||
});
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
namespace Tests\Feature\Form;
|
||||
|
||||
use DB;
|
||||
use App\Form\Models\Form;
|
||||
use App\Form\Models\Participant;
|
||||
use Illuminate\Foundation\Testing\DatabaseTransactions;
|
||||
|
|
@ -20,15 +21,14 @@ it('testItShowsParticipantsAndColumns', function () {
|
|||
$this->login()->loginNami()->withoutExceptionHandling();
|
||||
$form = Form::factory()
|
||||
->has(Participant::factory()->data(['stufe' => 'Pfadfinder', 'vorname' => 'Max', 'select' => ['A', 'B']]))
|
||||
->sections([
|
||||
FormtemplateSectionRequest::new()->fields([
|
||||
$this->textField('vorname')->name('Vorname'),
|
||||
$this->checkboxesField('select')->name('Abcselect')->options(['A', 'B', 'C']),
|
||||
$this->dropdownField('stufe')->name('Stufe')->options(['Wölfling', 'Jungpfadfinder', 'Pfadfinder']),
|
||||
]),
|
||||
->fields([
|
||||
$this->textField('vorname')->name('Vorname'),
|
||||
$this->checkboxesField('select')->name('Abcselect')->options(['A', 'B', 'C']),
|
||||
$this->dropdownField('stufe')->name('Stufe')->options(['Wölfling', 'Jungpfadfinder', 'Pfadfinder']),
|
||||
])
|
||||
->name('ZEM 2024')
|
||||
->create();
|
||||
DB::table('participants')->where('id', $form->participants->first()->id)->update(['id' => 9909]);
|
||||
|
||||
$this->get(route('form.export', ['form' => $form]))->assertDownload('tn-zem-2024.xlsx');
|
||||
$contents = Storage::disk('temp')->get('tn-zem-2024.xlsx');
|
||||
|
|
@ -37,4 +37,17 @@ it('testItShowsParticipantsAndColumns', function () {
|
|||
$this->assertExcelContent('Pfadfinder', $contents);
|
||||
$this->assertExcelContent('Stufe', $contents);
|
||||
$this->assertExcelContent('Abcselect', $contents);
|
||||
$this->assertExcelContent('9909', $contents);
|
||||
});
|
||||
|
||||
it('shows cancelled at', function () {
|
||||
Storage::fake('temp');
|
||||
$this->login()->loginNami()->withoutExceptionHandling();
|
||||
$form = Form::factory()->name('ZEM 2024')
|
||||
->has(Participant::factory()->state(['cancelled_at' => now()->subWeek()]))
|
||||
->create();
|
||||
|
||||
$this->get(route('form.export', ['form' => $form]))->assertDownload('tn-zem-2024.xlsx');
|
||||
$contents = Storage::disk('temp')->get('tn-zem-2024.xlsx');
|
||||
$this->assertExcelContent(now()->subWeek()->format('d.m.Y'), $contents);
|
||||
});
|
||||
|
|
|
|||
|
|
@ -157,6 +157,18 @@ it('testItSetsLocationToNull', function () {
|
|||
]);
|
||||
});
|
||||
|
||||
it('updates work phone', function () {
|
||||
$this->withoutExceptionHandling()->login()->loginNami();
|
||||
$member = factory()->notInNami()->create();
|
||||
fakeRequest();
|
||||
NamiPutMemberAction::allowToRun();
|
||||
|
||||
$this->patch("/member/{$member->id}", MemberUpdateRequestFactory::new()->noNami()->create([
|
||||
'work_phone' => '+49 212 1353688',
|
||||
]));
|
||||
test()->assertDatabaseHas('members', ['work_phone' => '+49 212 1353688']);
|
||||
});
|
||||
|
||||
it('testItUpdatesContact', function () {
|
||||
$this->withoutExceptionHandling()->login()->loginNami();
|
||||
$member = factory()->notInNami()->create();
|
||||
|
|
|
|||
|
|
@ -1,7 +1,5 @@
|
|||
<?php
|
||||
|
||||
namespace Illuminate\Testing;
|
||||
|
||||
namespace Spatie\LaravelSettings;
|
||||
|
||||
/**
|
||||
|
|
|
|||
Loading…
Reference in New Issue