Add prevention conditions
This commit is contained in:
parent
e6477fff2b
commit
146cbb0bef
|
@ -37,6 +37,7 @@ class FormStoreAction
|
||||||
'export' => 'nullable|array',
|
'export' => 'nullable|array',
|
||||||
'needs_prevention' => 'present|boolean',
|
'needs_prevention' => 'present|boolean',
|
||||||
'prevention_text' => 'array',
|
'prevention_text' => 'array',
|
||||||
|
'prevention_conditions' => 'array',
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
namespace App\Form\Actions;
|
namespace App\Form\Actions;
|
||||||
|
|
||||||
use App\Form\Models\Form;
|
use App\Form\Models\Form;
|
||||||
|
use App\Lib\Editor\Condition;
|
||||||
use App\Lib\Events\Succeeded;
|
use App\Lib\Events\Succeeded;
|
||||||
use Illuminate\Http\JsonResponse;
|
use Illuminate\Http\JsonResponse;
|
||||||
use Lorisleiva\Actions\Concerns\AsAction;
|
use Lorisleiva\Actions\Concerns\AsAction;
|
||||||
|
@ -36,6 +37,7 @@ class FormUpdateAction
|
||||||
'export' => 'nullable|array',
|
'export' => 'nullable|array',
|
||||||
'needs_prevention' => 'present|boolean',
|
'needs_prevention' => 'present|boolean',
|
||||||
'prevention_text' => 'array',
|
'prevention_text' => 'array',
|
||||||
|
'prevention_conditions' => 'array',
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
namespace App\Form\Actions;
|
namespace App\Form\Actions;
|
||||||
|
|
||||||
|
use App\Form\Editor\FormConditionResolver;
|
||||||
use App\Form\Models\Participant;
|
use App\Form\Models\Participant;
|
||||||
use App\Prevention\Mails\PreventionRememberMail;
|
use App\Prevention\Mails\PreventionRememberMail;
|
||||||
use App\Prevention\PreventionSettings;
|
use App\Prevention\PreventionSettings;
|
||||||
|
@ -23,6 +24,10 @@ class PreventionRememberAction
|
||||||
->orWhereNull('last_remembered_at')
|
->orWhereNull('last_remembered_at')
|
||||||
);
|
);
|
||||||
foreach ($query->get() as $participant) {
|
foreach ($query->get() as $participant) {
|
||||||
|
if (!app(FormConditionResolver::class)->forParticipant($participant)->filterCondition($participant->form->prevention_conditions)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if ($participant->getFields()->getMailRecipient() === null || count($participant->preventions()) === 0) {
|
if ($participant->getFields()->getMailRecipient() === null || count($participant->preventions()) === 0) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,6 +5,7 @@ namespace App\Form\Models;
|
||||||
use App\Form\Data\ExportData;
|
use App\Form\Data\ExportData;
|
||||||
use App\Form\Data\FieldCollection;
|
use App\Form\Data\FieldCollection;
|
||||||
use App\Form\Data\FormConfigData;
|
use App\Form\Data\FormConfigData;
|
||||||
|
use App\Lib\Editor\Condition;
|
||||||
use App\Lib\Editor\EditorData;
|
use App\Lib\Editor\EditorData;
|
||||||
use Cviebrock\EloquentSluggable\Sluggable;
|
use Cviebrock\EloquentSluggable\Sluggable;
|
||||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
|
@ -39,6 +40,7 @@ class Form extends Model implements HasMedia
|
||||||
'export' => ExportData::class,
|
'export' => ExportData::class,
|
||||||
'needs_prevention' => 'boolean',
|
'needs_prevention' => 'boolean',
|
||||||
'prevention_text' => EditorData::class,
|
'prevention_text' => EditorData::class,
|
||||||
|
'prevention_conditions' => Condition::class,
|
||||||
];
|
];
|
||||||
|
|
||||||
/** @var array<int, string> */
|
/** @var array<int, string> */
|
||||||
|
|
|
@ -52,6 +52,7 @@ class FormResource extends JsonResource
|
||||||
'export' => $this->export,
|
'export' => $this->export,
|
||||||
'needs_prevention' => $this->needs_prevention,
|
'needs_prevention' => $this->needs_prevention,
|
||||||
'prevention_text' => $this->prevention_text,
|
'prevention_text' => $this->prevention_text,
|
||||||
|
'prevention_conditions' => $this->prevention_conditions,
|
||||||
'links' => [
|
'links' => [
|
||||||
'participant_index' => route('form.participant.index', ['form' => $this->getModel(), 'parent' => null]),
|
'participant_index' => route('form.participant.index', ['form' => $this->getModel(), 'parent' => null]),
|
||||||
'participant_root_index' => route('form.participant.index', ['form' => $this->getModel(), 'parent' => -1]),
|
'participant_root_index' => route('form.participant.index', ['form' => $this->getModel(), 'parent' => -1]),
|
||||||
|
@ -99,6 +100,7 @@ class FormResource extends JsonResource
|
||||||
'prevention_text' => EditorData::default(),
|
'prevention_text' => EditorData::default(),
|
||||||
'id' => null,
|
'id' => null,
|
||||||
'export' => ExportData::from([]),
|
'export' => ExportData::from([]),
|
||||||
|
'prevention_conditions' => ['mode' => 'all', 'ifs' => []],
|
||||||
],
|
],
|
||||||
'section_default' => [
|
'section_default' => [
|
||||||
'name' => '',
|
'name' => '',
|
||||||
|
|
|
@ -20,21 +20,12 @@ class Condition extends Data
|
||||||
|
|
||||||
public static function fromMedia(Media $media): self
|
public static function fromMedia(Media $media): self
|
||||||
{
|
{
|
||||||
return static::withoutMagicalCreationFrom($media->getCustomProperty('conditions') ?: [
|
return $media->getCustomProperty('conditions') ? static::withoutMagicalCreationFrom($media->getCustomProperty('conditions')) : static::default();
|
||||||
'mode' => 'any',
|
|
||||||
'ifs' => [],
|
|
||||||
]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
public static function defaults(): self
|
||||||
* @param array<string, mixed> $block
|
|
||||||
*/
|
|
||||||
public static function fromBlock(array $block): self
|
|
||||||
{
|
{
|
||||||
return static::withoutMagicalCreationFrom([
|
return static::withoutMagicalCreationFrom(['mode' => 'any', 'ifs' => []]);
|
||||||
'mode' => data_get($block, 'tunes.condition.mode', 'any'),
|
|
||||||
'ifs' => data_get($block, 'tunes.condition.ifs', []),
|
|
||||||
]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function hasStatements(): bool
|
public function hasStatements(): bool
|
||||||
|
|
|
@ -21,6 +21,9 @@ abstract class ConditionResolver
|
||||||
*/
|
*/
|
||||||
public function filterBlock(array $block): bool
|
public function filterBlock(array $block): bool
|
||||||
{
|
{
|
||||||
return $this->filterCondition(Condition::fromBlock($block));
|
return $this->filterCondition(Condition::withoutMagicalCreationFrom([
|
||||||
|
'mode' => data_get($block, 'tunes.condition.mode', 'any'),
|
||||||
|
'ifs' => data_get($block, 'tunes.condition.ifs', []),
|
||||||
|
]));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,7 @@ namespace Database\Factories\Form\Models;
|
||||||
|
|
||||||
use App\Form\Data\ExportData;
|
use App\Form\Data\ExportData;
|
||||||
use App\Form\Models\Form;
|
use App\Form\Models\Form;
|
||||||
|
use App\Lib\Editor\Condition;
|
||||||
use Database\Factories\Traits\FakesMedia;
|
use Database\Factories\Traits\FakesMedia;
|
||||||
use Illuminate\Database\Eloquent\Factories\Factory;
|
use Illuminate\Database\Eloquent\Factories\Factory;
|
||||||
use Tests\Feature\Form\FormtemplateFieldRequest;
|
use Tests\Feature\Form\FormtemplateFieldRequest;
|
||||||
|
@ -54,6 +55,7 @@ class FormFactory extends Factory
|
||||||
'is_active' => true,
|
'is_active' => true,
|
||||||
'is_private' => false,
|
'is_private' => false,
|
||||||
'export' => ExportData::from([]),
|
'export' => ExportData::from([]),
|
||||||
|
'prevention_conditions' => Condition::defaults(),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,32 @@
|
||||||
|
<?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('forms', function (Blueprint $table) {
|
||||||
|
$table->json('prevention_conditions')->default(json_encode(['mode' => 'all', 'ifs' => []]));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function down()
|
||||||
|
{
|
||||||
|
Schema::table('forms', function (Blueprint $table) {
|
||||||
|
$table->dropColumn('prevention_conditions');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
|
@ -124,6 +124,9 @@
|
||||||
:rows="6"
|
:rows="6"
|
||||||
label="Präventions-Hinweis"
|
label="Präventions-Hinweis"
|
||||||
></f-editor>
|
></f-editor>
|
||||||
|
<ui-box heading="Bedingung für Präventions-Unterlagen">
|
||||||
|
<conditions id="prevention_conditions" v-model="single.prevention_conditions" :single="single"> </conditions>
|
||||||
|
</ui-box>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<template #actions>
|
<template #actions>
|
||||||
|
|
|
@ -61,6 +61,7 @@ class FormIndexActionTest extends FormTestCase
|
||||||
->assertInertiaPath('data.meta.templates.0.name', 'tname')
|
->assertInertiaPath('data.meta.templates.0.name', 'tname')
|
||||||
->assertInertiaPath('data.meta.templates.0.config.sections.0.name', 'sname')
|
->assertInertiaPath('data.meta.templates.0.config.sections.0.name', 'sname')
|
||||||
->assertInertiaPath('data.meta.default.name', '')
|
->assertInertiaPath('data.meta.default.name', '')
|
||||||
|
->assertInertiaPath('data.meta.default.prevention_conditions', ['mode' => 'all', 'ifs' => []])
|
||||||
->assertInertiaPath('data.meta.default.prevention_text.version', '1.0')
|
->assertInertiaPath('data.meta.default.prevention_text.version', '1.0')
|
||||||
->assertInertiaPath('data.meta.default.description', [])
|
->assertInertiaPath('data.meta.default.description', [])
|
||||||
->assertInertiaPath('data.meta.default.excerpt', '')
|
->assertInertiaPath('data.meta.default.excerpt', '')
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
namespace Tests\Feature\Form;
|
namespace Tests\Feature\Form;
|
||||||
|
|
||||||
use App\Form\Data\ExportData;
|
use App\Form\Data\ExportData;
|
||||||
|
use App\Lib\Editor\Condition;
|
||||||
use Illuminate\Http\UploadedFile;
|
use Illuminate\Http\UploadedFile;
|
||||||
use Illuminate\Support\Facades\Storage;
|
use Illuminate\Support\Facades\Storage;
|
||||||
use Tests\RequestFactories\EditorRequestFactory;
|
use Tests\RequestFactories\EditorRequestFactory;
|
||||||
|
@ -52,6 +53,7 @@ class FormRequest extends RequestFactory
|
||||||
'export' => ExportData::from([])->toArray(),
|
'export' => ExportData::from([])->toArray(),
|
||||||
'needs_prevention' => $this->faker->boolean(),
|
'needs_prevention' => $this->faker->boolean(),
|
||||||
'prevention_text' => EditorRequestFactory::new()->create(),
|
'prevention_text' => EditorRequestFactory::new()->create(),
|
||||||
|
'prevention_conditions' => Condition::defaults(),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,6 +5,7 @@ namespace Tests\Feature\Form;
|
||||||
use App\Fileshare\Data\FileshareResourceData;
|
use App\Fileshare\Data\FileshareResourceData;
|
||||||
use App\Form\Data\ExportData;
|
use App\Form\Data\ExportData;
|
||||||
use App\Form\Models\Form;
|
use App\Form\Models\Form;
|
||||||
|
use App\Lib\Editor\Condition;
|
||||||
use App\Lib\Editor\EditorData;
|
use App\Lib\Editor\EditorData;
|
||||||
use Illuminate\Foundation\Testing\DatabaseTransactions;
|
use Illuminate\Foundation\Testing\DatabaseTransactions;
|
||||||
use Tests\RequestFactories\EditorRequestFactory;
|
use Tests\RequestFactories\EditorRequestFactory;
|
||||||
|
@ -132,11 +133,12 @@ class FormUpdateActionTest extends FormTestCase
|
||||||
$form = Form::factory()->create();
|
$form = Form::factory()->create();
|
||||||
$payload = FormRequest::new()
|
$payload = FormRequest::new()
|
||||||
->preventionText(EditorRequestFactory::new()->text(10, 'lorem ipsum'))
|
->preventionText(EditorRequestFactory::new()->text(10, 'lorem ipsum'))
|
||||||
->state(['needs_prevention' => true])
|
->state(['needs_prevention' => true, 'prevention_conditions' => ['mode' => 'all', 'ifs' => [['field' => 'vorname', 'value' => 'Max', 'comparator' => 'isEqual']]]])
|
||||||
->create();
|
->create();
|
||||||
|
|
||||||
$this->patchJson(route('form.update', ['form' => $form]), $payload);
|
$this->patchJson(route('form.update', ['form' => $form]), $payload);
|
||||||
$this->assertTrue($form->fresh()->needs_prevention);
|
$this->assertTrue($form->fresh()->needs_prevention);
|
||||||
$this->assertEquals('lorem ipsum', $form->fresh()->prevention_text->blocks[0]['data']['text']);
|
$this->assertEquals('lorem ipsum', $form->fresh()->prevention_text->blocks[0]['data']['text']);
|
||||||
|
$this->assertEquals(['mode' => 'all', 'ifs' => [['field' => 'vorname', 'value' => 'Max', 'comparator' => 'isEqual']]], $form->fresh()->prevention_conditions->toArray());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,6 +9,7 @@ use App\Form\Enums\SpecialType;
|
||||||
use App\Form\Models\Form;
|
use App\Form\Models\Form;
|
||||||
use App\Form\Models\Participant;
|
use App\Form\Models\Participant;
|
||||||
use App\Invoice\InvoiceSettings;
|
use App\Invoice\InvoiceSettings;
|
||||||
|
use App\Lib\Editor\Condition;
|
||||||
use App\Prevention\Mails\PreventionRememberMail;
|
use App\Prevention\Mails\PreventionRememberMail;
|
||||||
use App\Member\Member;
|
use App\Member\Member;
|
||||||
use App\Member\Membership;
|
use App\Member\Membership;
|
||||||
|
@ -37,6 +38,19 @@ class PreventionTest extends TestCase
|
||||||
$this->assertEquals(now()->format('Y-m-d'), $participant->fresh()->last_remembered_at->format('Y-m-d'));
|
$this->assertEquals(now()->format('Y-m-d'), $participant->fresh()->last_remembered_at->format('Y-m-d'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testItDoesntRememberWhenConditionDoesntMatch(): void
|
||||||
|
{
|
||||||
|
Mail::fake();
|
||||||
|
$form = $this->createForm();
|
||||||
|
$form->update(['prevention_conditions' => Condition::from(['mode' => 'all', 'ifs' => [['field' => 'vorname', 'comparator' => 'isEqual', 'value' => 'Max']]])]);
|
||||||
|
$participant = $this->createParticipant($form);
|
||||||
|
$participant->update(['data' => [...$participant->data, 'vorname' => 'Jane']]);
|
||||||
|
|
||||||
|
PreventionRememberAction::run();
|
||||||
|
|
||||||
|
$this->assertNull($participant->fresh()->last_remembered_at);
|
||||||
|
}
|
||||||
|
|
||||||
public function testItRemembersWhenRememberIsDue(): void
|
public function testItRemembersWhenRememberIsDue(): void
|
||||||
{
|
{
|
||||||
Mail::fake();
|
Mail::fake();
|
||||||
|
|
Loading…
Reference in New Issue