Add enum for bill kind

This commit is contained in:
philipp lang 2022-12-06 23:11:57 +01:00
parent b0f76b0ae2
commit 74575998fa
21 changed files with 177 additions and 82 deletions

View File

@ -21,7 +21,7 @@ class MemberView
return [
'data' => MemberResource::collection(Member::select('*')
->filter($filter)->search($request->query('search', null))
->with('billKind')->with('payments.subscription')->with('memberships')->with('courses')->with('subscription')->with('leaderMemberships')->with('ageGroupMemberships')
->with('payments.subscription')->with('memberships')->with('courses')->with('subscription')->with('leaderMemberships')->with('ageGroupMemberships')
->withPendingPayment()
->orderByRaw('lastname, firstname')
->paginate(15)

View File

@ -2,6 +2,7 @@
namespace App\Letter\Actions;
use App\Letter\BillKind;
use App\Letter\DocumentFactory;
use App\Payment\PaymentMail;
use Illuminate\Console\Command;
@ -32,7 +33,7 @@ class LetterSendAction
public function handle(): int
{
foreach (app(DocumentFactory::class)->types as $type) {
$letters = app(DocumentFactory::class)->letterCollection($type, 'E-Mail');
$letters = app(DocumentFactory::class)->letterCollection($type, BillKind::EMAIL);
foreach ($letters as $letter) {
$letterPath = Storage::path(Tex::compile($letter)->storeIn('/tmp', 'local'));

View File

@ -2,13 +2,30 @@
namespace App\Letter;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class BillKind extends Model
enum BillKind: string
{
use HasFactory;
case EMAIL = 'E-Mail';
case POST = 'Post';
/**
* @return array<string, string>
*/
public static function values(): array
{
return collect(static::cases())->map(fn ($case) => $case->value)->toArray();
}
public $fillable = ['name'];
public $timestamps = false;
/**
* @return array<int, array{name: string, id: string}>
*/
public static function forSelect(): array
{
return collect(static::cases())
->map(fn ($case) => ['id' => $case->value, 'name' => $case->value])
->toArray();
}
public static function fromValue(string $value): self
{
return collect(static::cases())->firstOrFail(fn ($case) => $case->value === $value);
}
}

View File

@ -3,7 +3,6 @@
namespace App\Letter;
use App\Member\Member;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Collection as EloquentCollection;
use Illuminate\Support\Collection;
use Illuminate\Support\Str;
@ -49,7 +48,7 @@ class DocumentFactory
/**
* @param class-string<Letter> $type
*/
public function forAll(string $type, string $billKind): ?Letter
public function forAll(string $type, BillKind $billKind): ?Letter
{
$pages = $this->allMemberPages($type, $billKind);
@ -63,7 +62,7 @@ class DocumentFactory
/**
* @param class-string<Letter> $type
*/
public function afterAll(string $type, string $billKind): void
public function afterAll(string $type, BillKind $billKind): void
{
$letter = $this->forAll($type, $billKind);
$this->afterSingle($letter);
@ -74,7 +73,7 @@ class DocumentFactory
*
* @return Collection<int, Letter>
*/
public function letterCollection(string $type, string $billKind): Collection
public function letterCollection(string $type, BillKind $billKind): Collection
{
$pages = $this->allMemberPages($type, $billKind);
@ -111,9 +110,9 @@ class DocumentFactory
*
* @return Collection<int, Page>
*/
private function allMemberPages(string $type, string $billKind): Collection
private function allMemberPages(string $type, BillKind $billKind): Collection
{
$members = Member::whereHas('billKind', fn (Builder $q) => $q->where('name', $billKind))
$members = Member::where('bill_kind', $billKind)
->with([
'payments' => fn ($query) => $type::paymentsQuery($query)
->orderByRaw('nr, member_id'),

View File

@ -66,6 +66,7 @@ class Member extends Model
'multiply_pv' => 'boolean',
'multiply_more_pv' => 'boolean',
'is_leader' => 'boolean',
'bill_kind' => BillKind::class,
];
/**
@ -231,11 +232,6 @@ class Member extends Model
return $this->belongsTo(Subscription::class);
}
public function billKind(): BelongsTo
{
return $this->belongsTo(BillKind::class);
}
public function group(): BelongsTo
{
return $this->belongsTo(Group::class);
@ -307,7 +303,7 @@ class Member extends Model
public function scopePayable(Builder $q): Builder
{
return $q->where('bill_kind_id', '!=', null)->where('subscription_id', '!=', null);
return $q->where('bill_kind', '!=', null)->where('subscription_id', '!=', null);
}
public function scopeWhereNoPayment(Builder $q, int $year): Builder
@ -328,7 +324,7 @@ class Member extends Model
$q->whereAusstand();
}
if (data_get($filter, 'bill_kind', false)) {
$q->where('bill_kind_id', $filter['bill_kind']);
$q->where('bill_kind', BillKind::fromValue($filter['bill_kind']));
}
if (data_get($filter, 'subactivity_id', false) || data_get($filter, 'activity_id', false)) {
$q->whereHas('memberships', function ($q) use ($filter) {

View File

@ -47,7 +47,7 @@ class MemberController extends Controller
['href' => route('sendpayment.create'), 'label' => 'Rechnungen versenden', 'color' => 'info', 'icon' => 'envelope', 'show' => $settings->hasModule('bill')],
];
$payload['query'] = $query;
$payload['billKinds'] = BillKind::pluck('name', 'id');
$payload['billKinds'] = BillKind::forSelect();
return \Inertia::render('member/VIndex', $payload);
}
@ -64,7 +64,7 @@ class MemberController extends Controller
'subactivities' => $activities->map(function (Activity $activity) {
return ['subactivities' => $activity->subactivities()->pluck('name', 'id'), 'id' => $activity->id];
})->pluck('subactivities', 'id'),
'billKinds' => BillKind::pluck('name', 'id'),
'billKinds' => BillKind::forSelect(),
'genders' => Gender::pluck('name', 'id'),
'countries' => Country::pluck('name', 'id'),
'regions' => Region::where('is_null', false)->pluck('name', 'id'),
@ -97,7 +97,7 @@ class MemberController extends Controller
'subactivities' => $activities->map(function ($activity) {
return ['subactivities' => $activity->subactivities->pluck('name', 'id'), 'id' => $activity->id];
})->pluck('subactivities', 'id'),
'billKinds' => BillKind::pluck('name', 'id'),
'billKinds' => BillKind::forSelect(),
'genders' => Gender::pluck('name', 'id'),
'countries' => Country::pluck('name', 'id'),
'regions' => Region::where('is_null', false)->pluck('name', 'id'),

View File

@ -4,6 +4,7 @@ namespace App\Member;
use App\Activity;
use App\Group;
use App\Letter\BillKind;
use App\Member\Actions\NamiPutMemberAction;
use App\Setting\NamiSettings;
use App\Subactivity;
@ -57,7 +58,7 @@ class MemberRequest extends FormRequest
'nationality_id' => 'required|exists:nationalities,id',
'email' => 'nullable|email',
'email_parents' => 'nullable|email',
'bill_kind_id' => 'nullable|exists:bill_kinds,id',
'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',

View File

@ -54,8 +54,7 @@ class MemberResource extends JsonResource
'other_country' => $this->other_country,
'confession_id' => $this->confession_id,
'letter_address' => $this->letter_address,
'bill_kind_id' => $this->bill_kind_id,
'bill_kind_name' => optional($this->billKind)->name,
'bill_kind_name' => optional($this->bill_kind)->value,
'has_nami' => null !== $this->nami_id,
'children_phone' => $this->children_phone,
'payments' => PaymentResource::collection($this->whenLoaded('payments')),

View File

@ -3,6 +3,7 @@
namespace App\Payment;
use App\Http\Controllers\Controller;
use App\Letter\BillKind;
use App\Letter\DocumentFactory;
use Illuminate\Contracts\Support\Responsable;
use Illuminate\Http\Request;
@ -28,14 +29,14 @@ class SendpaymentController extends Controller
*/
public function send(Request $request)
{
$repo = app(DocumentFactory::class)->forAll($request->type, 'Post');
$repo = app(DocumentFactory::class)->forAll($request->type, BillKind::POST);
if (is_null($repo)) {
return response()->noContent();
}
$pdfFile = Tex::compile($repo);
app(DocumentFactory::class)->afterAll($request->type, 'Post');
app(DocumentFactory::class)->afterAll($request->type, BillKind::POST);
return $pdfFile;
}

View File

@ -1,31 +0,0 @@
<?php
namespace Database\Factories\Letter;
use App\Letter\BillKind;
use Illuminate\Database\Eloquent\Factories\Factory;
/**
* @extends \Illuminate\Database\Eloquent\Factories\Factory<BillKind>
*/
class BillKindFactory extends Factory
{
public $model = BillKind::class;
/**
* Define the model's default state.
*
* @return array<string, mixed>
*/
public function definition()
{
return [
'name' => $this->faker->words(3, true),
];
}
public function name(string $name): self
{
return $this->state(['name' => $name]);
}
}

View File

@ -64,14 +64,14 @@ class MemberFactory extends Factory
public function postBillKind(): self
{
return $this->state([
'bill_kind_id' => BillKind::firstWhere('name', 'Post')->id,
'bill_kind' => BillKind::POST,
]);
}
public function emailBillKind(): self
{
return $this->state([
'bill_kind_id' => BillKind::firstWhere('name', 'E-Mail')->id,
'bill_kind' => BillKind::EMAIL,
]);
}

View File

@ -19,9 +19,6 @@ class CreateMembersTable extends Migration
$table->string('name');
});
BillKind::create(['name' => 'E-Mail']);
BillKind::create(['name' => 'Post']);
Schema::create('members', function (Blueprint $table) {
$table->id();
$table->string('firstname');

View File

@ -0,0 +1,45 @@
<?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()
{
$billKinds = DB::table('bill_kinds')->get();
Schema::table('members', function (Blueprint $table) {
$table->dropForeign(['bill_kind_id']);
});
Schema::drop('bill_kinds');
Schema::table('members', function (Blueprint $table) {
$table->renameColumn('bill_kind_id', 'bill_kind');
});
Schema::table('members', function (Blueprint $table) {
$table->string('bill_kind')->change();
});
foreach (DB::table('members')->get() as $member) {
if (is_null($member->bill_kind)) {
continue;
}
DB::table('members')->where('id', $member->id)->update([
'bill_kind' => $billKinds->firstWhere('id', $member->bill_kind)->name,
]);
}
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
}
};

View File

@ -115,10 +115,10 @@
<div class="grid gap-3">
<f-select
:options="billKinds"
id="bill_kind_id"
v-model="inner.bill_kind_id"
id="bill_kind"
v-model="inner.bill_kind"
label="Rechnung versenden über"
name="bill_kind_id"
name="bill_kind"
size="sm"
></f-select>
<f-select

View File

@ -24,5 +24,6 @@ class CreateTest extends TestCase
$this->assertInertiaHas('Biber', $response, "subactivities.{$activity->id}.{$subactivity->id}");
$this->assertInertiaHas('€ Mitglied', $response, "activities.{$activity->id}");
$this->assertInertiaHas(['name' => 'E-Mail', 'id' => 'E-Mail'], $response, 'billKinds.0');
}
}

View File

@ -27,6 +27,7 @@ class EditTest extends TestCase
$this->assertInertiaHas('Max', $response, 'data.firstname');
$this->assertInertiaHas('edit', $response, 'mode');
$this->assertInertiaHas(false, $response, 'conflict');
$this->assertInertiaHas(['name' => 'E-Mail', 'id' => 'E-Mail'], $response, 'billKinds.0');
}
public function testItDisplaysEducation(): void

View File

@ -128,4 +128,17 @@ class IndexTest extends TestCase
'name' => $member->subscription->name,
], $response, 'data.data.0.subscription');
}
public function testItCanFilterForBillKinds(): void
{
$this->withoutExceptionHandling()->login()->loginNami();
$emailMember = Member::factory()->defaults()->emailBillKind()->create();
$postMember = Member::factory()->defaults()->postBillKind()->create();
$emailResponse = $this->call('GET', '/member', ['filter' => '{"bill_kind": "E-Mail"}']);
$postResponse = $this->call('GET', '/member', ['filter' => '{"bill_kind": "Post"}']);
$this->assertCount(1, $this->inertia($emailResponse, 'data.data'));
$this->assertCount(1, $this->inertia($postResponse, 'data.data'));
}
}

View File

@ -9,7 +9,6 @@ use App\Country;
use App\Fee;
use App\Gender;
use App\Group;
use App\Letter\BillKind;
use App\Member\Actions\NamiPutMemberAction;
use App\Member\Member;
use App\Nationality;
@ -33,7 +32,6 @@ class NamiPutMemberActionTest extends TestCase
$region = Region::factory()->create();
$nationality = Nationality::factory()->inNami(565)->create();
$subscription = Subscription::factory()->create();
$billKind = BillKind::factory()->create();
$group = Group::factory()->inNami(55)->create();
$confession = Confession::factory()->inNami(567)->create(['is_null' => true]);
app(MemberFake::class)->createsSuccessfully(55, 993);
@ -46,9 +44,9 @@ class NamiPutMemberActionTest extends TestCase
->for($subscription)
->for($region)
->for($nationality)
->for($billKind)
->for($gender)
->for($group)
->emailBillKind()
->create();
NamiPutMemberAction::run($member, $activity, $subactivity);

View File

@ -7,7 +7,6 @@ use App\Course\Models\CourseMember;
use App\Fee;
use App\Gender;
use App\Group;
use App\Letter\BillKind;
use App\Member\Member;
use App\Member\Membership;
use App\Nationality;
@ -38,7 +37,7 @@ class ShowTest extends TestCase
->has(Payment::factory()->notPaid()->nr('2019')->subscription('Free', 1050))
->for(Gender::factory()->name('Männlich'))
->for(Region::factory()->name('NRW'))
->for(BillKind::factory()->name('Post'))
->postBillKind()
->inNami(123)
->for(Subscription::factory()->name('Sub')->for(Fee::factory()))
->has(CourseMember::factory()->for(Course::factory()->name(' Baustein 2e - Gewalt gegen Kinder und Jugendliche: Vertiefung, Prävention '))->state(['organizer' => 'DPSG', 'event_name' => 'Wochenende', 'completed_at' => '2022-03-03']), 'courses')

View File

@ -6,7 +6,6 @@ use App\Activity;
use App\Country;
use App\Fee;
use App\Gender;
use App\Letter\BillKind;
use App\Member\Actions\NamiPutMemberAction;
use App\Member\Member;
use App\Nationality;
@ -33,7 +32,6 @@ class StoreTest extends TestCase
$activity = Activity::factory()->create();
$subactivity = Subactivity::factory()->create();
$subscription = Subscription::factory()->create();
$billKind = BillKind::factory()->create();
NamiPutMemberAction::allowToRun();
$response = $this
@ -46,7 +44,7 @@ class StoreTest extends TestCase
'first_activity_id' => $activity->id,
'first_subactivity_id' => $subactivity->id,
'subscription_id' => $subscription->id,
'bill_kind_id' => $billKind->id,
'bill_kind' => 'Post',
]));
$response->assertStatus(302)->assertSessionHasNoErrors();
@ -54,7 +52,7 @@ class StoreTest extends TestCase
$member = Member::firstWhere('firstname', 'Joe');
$this->assertDatabaseHas('members', [
'address' => 'Bavert 50',
'bill_kind_id' => $billKind->id,
'bill_kind' => 'Post',
'birthday' => '2013-02-19',
'children_phone' => '+49 123 44444',
'country_id' => $country->id,
@ -89,7 +87,6 @@ class StoreTest extends TestCase
$region = Region::factory()->create();
$nationality = Nationality::factory()->create();
$subscription = Subscription::factory()->create();
$billKind = BillKind::factory()->create();
$activity = Activity::factory()->create();
$subactivity = Subactivity::factory()->create();
NamiPutMemberAction::allowToRun();
@ -104,7 +101,7 @@ class StoreTest extends TestCase
'first_activity_id' => $activity->id,
'first_subactivity_id' => $subactivity->id,
'subscription_id' => $subscription->id,
'bill_kind_id' => $billKind->id,
'bill_kind' => 'E-Mail',
'has_nami' => false,
]));
@ -126,7 +123,6 @@ class StoreTest extends TestCase
$region = Region::factory()->create();
$nationality = Nationality::factory()->create();
$subscription = Subscription::factory()->create();
$billKind = BillKind::factory()->create();
$activity = Activity::factory()->create(['name' => '€ Mitglied']);
$subactivity = Subactivity::factory()->create();
@ -140,7 +136,7 @@ class StoreTest extends TestCase
'first_activity_id' => $activity->id,
'first_subactivity_id' => $subactivity->id,
'subscription_id' => null,
'bill_kind_id' => $billKind->id,
'bill_kind' => 'E-Mail',
]));
$this->assertErrors(['subscription_id' => 'Beitragsart ist erforderlich.'], $response);

View File

@ -0,0 +1,62 @@
<?php
namespace Tests\Feature\Payment;
use App\Member\Member;
use App\Payment\Status;
use Illuminate\Foundation\Testing\DatabaseTransactions;
use Tests\TestCase;
class AllpaymentTest extends TestCase
{
use DatabaseTransactions;
public function setUp(): void
{
parent::setUp();
$this->login()->loginNami();
}
public function testItDoesntCreatePaymentsWithoutSubscription(): void
{
$member = Member::factory()->defaults()->emailBillKind()->create();
$member->update(['subscription_id' => null]);
$response = $this->from('/allpayment/create')->post('allpayment', [
'year' => now()->addYear()->year,
]);
$response->assertRedirect('/allpayment/create');
$this->assertEmpty($member->payments()->get());
}
public function testItDoesntCreatePaymentWithoutBillKind(): void
{
$member = Member::factory()->defaults()->create();
$response = $this->from('/allpayment/create')->post('allpayment', [
'year' => now()->addYear()->year,
]);
$response->assertRedirect('/allpayment/create');
$this->assertEmpty($member->payments()->get());
}
public function testItCreatesPayments(): void
{
$member = Member::factory()->defaults()->emailBillKind()->create();
$response = $this->from('/allpayment/create')->post('allpayment', [
'year' => now()->addYear()->year,
]);
$response->assertRedirect('/allpayment/create');
$this->assertDatabaseHas('payments', [
'member_id' => $member->id,
'nr' => now()->addYear()->year,
'subscription_id' => $member->subscription->id,
'status_id' => Status::first()->id,
]);
}
}