diff --git a/app/Http/Views/MemberView.php b/app/Http/Views/MemberView.php
new file mode 100644
index 00000000..83c71567
--- /dev/null
+++ b/app/Http/Views/MemberView.php
@@ -0,0 +1,56 @@
+ MemberResource::collection(Member::select('*')->search($request->query('search', null))->with('billKind')->withIsConfirmed()->paginate(15)),
+ 'toolbar' => [ ['href' => route('member.index'), 'label' => 'Zurück', 'color' => 'primary', 'icon' => 'plus'] ]
+ ];
+ }
+
+ public function paymentCreate($member) {
+ return $this->additional($member, [
+ 'model' => [
+ 'subscription_id' => $member->subscription_id,
+ 'status_id' => Status::default(),
+ 'nr' => date('Y'),
+ ],
+ 'links' => [ ['label' => 'Zurück', 'href' => route('member.payment.index', ['member' => $member]) ] ],
+ 'mode' => 'create',
+ ]);
+ }
+
+ public function paymentEdit($member, $payment) {
+ return $this->additional($member, [
+ 'model' => new PaymentResource($payment),
+ 'links' => [ ['label' => 'Zurück', 'href' => route('member.payment.index', ['member' => $member]) ] ],
+ 'mode' => 'edit',
+ ]);
+ }
+
+ public function paymentIndex($member) {
+ return $this->additional($member, [
+ 'model' => null,
+ 'links' => [ ['label' => 'Zahlung hinzufügen', 'href' => route('member.payment.create', ['member' => $member]) ] ],
+ 'mode' => 'index',
+ ]);
+ }
+
+ private function additional($member, $overwrites = []) {
+ return (new MemberResource($member->load('payments')))
+ ->additional(array_merge([
+ 'subscriptions' => Subscription::get()->pluck('name', 'id'),
+ 'statuses' => Status::get()->pluck('name', 'id'),
+ ], $overwrites));
+ }
+
+}
diff --git a/app/Member/Member.php b/app/Member/Member.php
index a4f5707b..74edde17 100644
--- a/app/Member/Member.php
+++ b/app/Member/Member.php
@@ -13,6 +13,7 @@ use App\Activity;
use App\Subactivity;
use Zoomyboy\LaravelNami\NamiUser;
use App\Payment\Subscription;
+use App\Payment\Payment;
class Member extends Model
{
@@ -87,7 +88,7 @@ class Member extends Model
public function payments()
{
- return $this->hasMany(\App\Payment::class)->orderBy('nr');
+ return $this->hasMany(Payment::class)->orderBy('nr');
}
public function way()
diff --git a/app/Member/MemberController.php b/app/Member/MemberController.php
index 9f6a1e80..a5a312c2 100644
--- a/app/Member/MemberController.php
+++ b/app/Member/MemberController.php
@@ -13,6 +13,7 @@ use App\Bill\BillKind;
use App\Activity;
use App\Group;
use App\Payment\Subscription;
+use App\Http\Views\MemberView;
class MemberController extends Controller
{
@@ -21,10 +22,10 @@ class MemberController extends Controller
session()->put('menu', 'member');
session()->put('title', 'Mitglieder');
- return \Inertia::render('member/Index', [
- 'data' => MemberResource::collection(Member::select('*')->search($request->query('search', null))->with('billKind')->withIsConfirmed()->paginate(15)),
- 'toolbar' => [ ['href' => route('member.create'), 'label' => 'Mitglied anlegen', 'color' => 'primary', 'icon' => 'plus'] ],
- ]);
+ $payload = app(MemberView::class)->index($request);
+ $payload['toolbar'] = [ ['href' => route('member.create'), 'label' => 'Mitglied anlegen', 'color' => 'primary', 'icon' => 'plus'] ];
+
+ return \Inertia::render('member/Index', $payload);
}
public function create() {
diff --git a/app/Member/MemberResource.php b/app/Member/MemberResource.php
index 22598e03..acbfd894 100644
--- a/app/Member/MemberResource.php
+++ b/app/Member/MemberResource.php
@@ -3,6 +3,7 @@
namespace App\Member;
use Illuminate\Http\Resources\Json\JsonResource;
+use App\Payment\PaymentResource;
class MemberResource extends JsonResource
{
@@ -46,6 +47,7 @@ class MemberResource extends JsonResource
'has_nami' => $this->nami_id !== null,
'is_confirmed' => $this->is_confirmed,
'children_phone' => $this->children_phone,
+ 'payments' => PaymentResource::collection($this->whenLoaded('payments')),
];
}
}
diff --git a/app/Payment/Payment.php b/app/Payment/Payment.php
new file mode 100644
index 00000000..d58604c3
--- /dev/null
+++ b/app/Payment/Payment.php
@@ -0,0 +1,28 @@
+belongsTo(Member::class);
+ }
+
+ public function subscription() {
+ return $this->belongsTo(Subscription::class);
+ }
+
+ public function status() {
+ return $this->belongsTo(Status::class);
+ }
+}
diff --git a/app/Payment/PaymentController.php b/app/Payment/PaymentController.php
new file mode 100644
index 00000000..2a023f05
--- /dev/null
+++ b/app/Payment/PaymentController.php
@@ -0,0 +1,68 @@
+put('menu', 'member');
+ session()->put('title', "Zahlungen für Mitglied {$member->fullname}");
+
+ $payload = app(MemberView::class)->index($request);
+ $payload['single'] = app(MemberView::class)->paymentIndex($member);
+
+ return \Inertia::render('member/Index', $payload);
+ }
+
+ public function create(Member $member, Request $request) {
+ session()->put('menu', 'member');
+ session()->put('title', "Zahlungen für Mitglied {$member->fullname}");
+
+ $payload = app(MemberView::class)->index($request);
+ $payload['single'] = app(MemberView::class)->paymentCreate($member);
+
+ return \Inertia::render('member/Index', $payload);
+ }
+
+ public function store(Request $request, Member $member) {
+ $member->payments()->create($request->validate([
+ 'nr' => 'required|numeric',
+ 'subscription_id' => 'required|exists:subscriptions,id',
+ 'status_id' => 'required|exists:statuses,id',
+ ]));
+
+ return redirect()->route('member.payment.index', ['member' => $member]);
+ }
+
+ public function edit(Member $member, Request $request, Payment $payment) {
+ session()->put('menu', 'member');
+ session()->put('title', "Zahlungen für Mitglied {$member->fullname}");
+
+ $payload = app(MemberView::class)->index($request);
+ $payload['single'] = app(MemberView::class)->paymentEdit($member, $payment);
+
+ return \Inertia::render('member/Index', $payload);
+ }
+
+ public function update(Request $request, Member $member, Payment $payment) {
+ $payment->update($request->validate([
+ 'nr' => 'required|numeric',
+ 'subscription_id' => 'required|exists:subscriptions,id',
+ 'status_id' => 'required|exists:statuses,id',
+ ]));
+
+ return redirect()->route('member.payment.index', ['member' => $member]);
+ }
+
+ public function destroy(Request $request, Member $member, Payment $payment) {
+ $payment->delete();
+
+ return redirect()->route('member.payment.index', ['member' => $member]);
+ }
+}
diff --git a/app/Payment/PaymentResource.php b/app/Payment/PaymentResource.php
new file mode 100644
index 00000000..711073e8
--- /dev/null
+++ b/app/Payment/PaymentResource.php
@@ -0,0 +1,26 @@
+ $this->subscription_id,
+ 'subscription_name' => $this->subscription->name,
+ 'status_name' => $this->status->name,
+ 'status_id' => $this->status->id,
+ 'nr' => $this->nr,
+ 'id' => $this->id,
+ ];
+ }
+}
diff --git a/app/Payment/Status.php b/app/Payment/Status.php
new file mode 100644
index 00000000..d22f70f5
--- /dev/null
+++ b/app/Payment/Status.php
@@ -0,0 +1,18 @@
+where('is_remember', true)->first()->id;
+ }
+}
diff --git a/bin/copydb b/bin/copydb
new file mode 100755
index 00000000..2cbb8d93
--- /dev/null
+++ b/bin/copydb
@@ -0,0 +1,7 @@
+#/bin/bash
+
+echo "drop database scoutrobot;" | sudo mysql
+echo "create database scoutrobot;" | sudo mysql
+
+ssh -l stammsilva zoomyboy.de "mysqldump -u nami -p$SCOUTROBOT_DB_PASSWORD nami" > db.tmp && sudo mysql scoutrobot < db.tmp
+rm db.tmp
diff --git a/database/migrations/2021_07_04_101300_create_payments_table.php b/database/migrations/2021_07_04_101300_create_payments_table.php
new file mode 100644
index 00000000..750bd808
--- /dev/null
+++ b/database/migrations/2021_07_04_101300_create_payments_table.php
@@ -0,0 +1,47 @@
+id();
+ $table->string('name');
+ $table->boolean('is_bill');
+ $table->boolean('is_remember');
+ });
+
+ Status::create(['name' => 'Nicht bezahlt', 'is_bill' => true, 'is_remember' => true]);
+ Status::create(['name' => 'Rechnung gestellt', 'is_bill' => false, 'is_remember' => true]);
+ Status::create(['name' => 'Rechnung beglichen', 'is_bill' => false, 'is_remember' => false]);
+
+ Schema::create('payments', function (Blueprint $table) {
+ $table->id();
+ $table->string('nr');
+ $table->foreignId('subscription_id')->constrained();
+ $table->foreignId('status_id')->constrained();
+ $table->foreignId('member_id')->constrained();
+ $table->timestamps();
+ });
+ }
+
+ /**
+ * Reverse the migrations.
+ *
+ * @return void
+ */
+ public function down()
+ {
+ Schema::dropIfExists('payments');
+ }
+}
diff --git a/resources/css/app.css b/resources/css/app.css
index 6a848b92..3cdef5ea 100644
--- a/resources/css/app.css
+++ b/resources/css/app.css
@@ -6,3 +6,4 @@
@import "layout";
@import "buttons";
@import "table";
+@import "sidebar";
diff --git a/resources/css/buttons.css b/resources/css/buttons.css
index 911b3857..56151021 100644
--- a/resources/css/buttons.css
+++ b/resources/css/buttons.css
@@ -16,6 +16,12 @@
@apply bg-primary-500;
}
}
+ &.btn-primary-light {
+ @apply bg-primary-600 text-primary-800;
+ &:hover {
+ @apply bg-primary-500 text-primary-700;
+ }
+ }
&.btn-warning {
@apply bg-yellow-700;
&:hover {
@@ -34,5 +40,22 @@
@apply bg-red-500;
}
}
+
+ &.label {
+ @apply rounded-full leading-none transition-all normal-case;
+ &.primary {
+ @apply bg-primary-800 text-primary-500;
+ &:hover {
+ @apply text-primary-400 bg-primary-700;
+ }
+ }
+ }
+
+ &.icon {
+ @apply p-0 flex justify-center items-center w-6 h-6;
+ svg {
+ @apply w-3 h-3 text-primary-100 flex-none;
+ }
+ }
}
diff --git a/resources/css/sidebar.css b/resources/css/sidebar.css
new file mode 100644
index 00000000..1fdc0c11
--- /dev/null
+++ b/resources/css/sidebar.css
@@ -0,0 +1,3 @@
+.sidebar {
+ @apply fixed w-96 shadow-2xl bg-gray-600 right-0 top-0 h-full;
+}
diff --git a/resources/css/table.css b/resources/css/table.css
index 3b765669..d3038a9a 100644
--- a/resources/css/table.css
+++ b/resources/css/table.css
@@ -1,6 +1,39 @@
.custom-table {
display: table;
width: 100%;
+ & > header > div {
+ @apply px-6 text-gray-200 font-semibold py-3 border-gray-600 border-b;
+ }
+
+ & > div {
+ @apply text-gray-200 transition-all duration-300 rounded hover:bg-gray-800;
+ & > div {
+ @apply py-1 px-6;
+ }
+ }
+
+ &.custom-table-sm {
+ & > header > div {
+ @apply px-3 py-2;
+ }
+ & > div {
+ & > div {
+ @apply py-1 px-3;
+ }
+ }
+ }
+
+ &.custom-table-light {
+ & > header > div {
+ @apply border-gray-500;
+ }
+ & > div {
+ &:hover {
+ @apply bg-gray-700;
+ }
+ }
+ }
+
}
.custom-table > * {
display: table-row;
diff --git a/resources/img/sprite.svg b/resources/img/sprite.svg
index bcb3dea7..9f3212fb 100644
--- a/resources/img/sprite.svg
+++ b/resources/img/sprite.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/resources/img/svg/trash.svg b/resources/img/svg/trash.svg
new file mode 100644
index 00000000..4232d55a
--- /dev/null
+++ b/resources/img/svg/trash.svg
@@ -0,0 +1,19 @@
+
diff --git a/resources/js/components/SidebarHeader.vue b/resources/js/components/SidebarHeader.vue
new file mode 100644
index 00000000..ff1c15e5
--- /dev/null
+++ b/resources/js/components/SidebarHeader.vue
@@ -0,0 +1,27 @@
+
+