Add subscriptions

This commit is contained in:
philipp lang 2021-07-04 01:44:41 +02:00
parent 545397809b
commit 0202d29c32
13 changed files with 646 additions and 14 deletions

View File

@ -0,0 +1,18 @@
<?php
namespace App\Payment;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use App\Fee;
class Subscription extends Model
{
use HasFactory;
public $fillable = ['name', 'amount', 'fee_id'];
public function fee() {
return $this->belongsTo(Fee::class);
}
}

View File

@ -0,0 +1,62 @@
<?php
namespace App\Payment;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use App\Fee;
class SubscriptionController extends Controller
{
public function index(Request $request) {
session()->put('menu', 'subscription');
session()->put('title', 'Beiträge');
return \Inertia::render('subscription/Index', [
'data' => SubscriptionResource::collection(Subscription::get()),
'toolbar' => [ ['href' => route('subscription.create'), 'label' => 'Beitrag anlegen', 'color' => 'primary', 'icon' => 'plus'] ],
]);
}
public function create() {
session()->put('menu', 'subscription');
session()->put('title', 'Beitrag erstellen');
return \Inertia::render('subscription/Form', [
'fees' => Fee::get()->pluck('name', 'id'),
'mode' => 'create',
'data' => (object) []
]);
}
public function store(Request $request) {
Subscription::create($request->validate([
'name' => 'required|max:255',
'amount' => 'required|numeric',
'fee_id' => 'required|exists:fees,id',
]));
return redirect()->route('subscription.index');
}
public function edit(Subscription $subscription, Request $request) {
session()->put('menu', 'subscription');
session()->put('title', "Beitrag {$subscription->name} bearbeiten");
return \Inertia::render('subscription/Form', [
'fees' => Fee::get()->pluck('name', 'id'),
'mode' => 'edit',
'data' => new SubscriptionResource($subscription),
]);
}
public function update(Subscription $subscription, Request $request) {
$subscription->update($request->validate([
'name' => 'required|max:255',
'amount' => 'required|numeric',
'fee_id' => 'required|exists:fees,id',
]));
return redirect()->route('subscription.index');
}
}

View File

@ -0,0 +1,26 @@
<?php
namespace App\Payment;
use Illuminate\Http\Resources\Json\JsonResource;
class SubscriptionResource extends JsonResource
{
/**
* Transform the resource into an array.
*
* @param \Illuminate\Http\Request $request
* @return array
*/
public function toArray($request)
{
return [
'id' => $this->id,
'name' => $this->name,
'fee_id' => $this->fee_id,
'fee_name' => $this->fee->name,
'amount_human' => number_format($this->amount / 100, 2, ',', '.').' €',
'amount' => $this->amount,
];
}
}

View File

@ -14,6 +14,7 @@
"require": {
"php": "^7.2.5",
"aweos/agnoster-installer": "1.0",
"doctrine/dbal": "^3.1",
"fideloper/proxy": "^4.2",
"fruitcake/laravel-cors": "^1.0",
"guzzlehttp/guzzle": "^7.0.1",

420
composer.lock generated
View File

@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "d960b31f70a251387c83d7ab9803fb0e",
"content-hash": "308f33b72c09fca3d6d3153bfb3cab1e",
"packages": [
{
"name": "asm89/stack-cors",
@ -147,6 +147,424 @@
],
"time": "2021-01-20T22:51:39+00:00"
},
{
"name": "composer/package-versions-deprecated",
"version": "1.11.99.2",
"source": {
"type": "git",
"url": "https://github.com/composer/package-versions-deprecated.git",
"reference": "c6522afe5540d5fc46675043d3ed5a45a740b27c"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/composer/package-versions-deprecated/zipball/c6522afe5540d5fc46675043d3ed5a45a740b27c",
"reference": "c6522afe5540d5fc46675043d3ed5a45a740b27c",
"shasum": ""
},
"require": {
"composer-plugin-api": "^1.1.0 || ^2.0",
"php": "^7 || ^8"
},
"replace": {
"ocramius/package-versions": "1.11.99"
},
"require-dev": {
"composer/composer": "^1.9.3 || ^2.0@dev",
"ext-zip": "^1.13",
"phpunit/phpunit": "^6.5 || ^7"
},
"type": "composer-plugin",
"extra": {
"class": "PackageVersions\\Installer",
"branch-alias": {
"dev-master": "1.x-dev"
}
},
"autoload": {
"psr-4": {
"PackageVersions\\": "src/PackageVersions"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Marco Pivetta",
"email": "ocramius@gmail.com"
},
{
"name": "Jordi Boggiano",
"email": "j.boggiano@seld.be"
}
],
"description": "Composer plugin that provides efficient querying for installed package versions (no runtime IO)",
"support": {
"issues": "https://github.com/composer/package-versions-deprecated/issues",
"source": "https://github.com/composer/package-versions-deprecated/tree/1.11.99.2"
},
"funding": [
{
"url": "https://packagist.com",
"type": "custom"
},
{
"url": "https://github.com/composer",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/composer/composer",
"type": "tidelift"
}
],
"time": "2021-05-24T07:46:03+00:00"
},
{
"name": "doctrine/cache",
"version": "2.0.3",
"source": {
"type": "git",
"url": "https://github.com/doctrine/cache.git",
"reference": "c9622c6820d3ede1e2315a6a377ea1076e421d88"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/doctrine/cache/zipball/c9622c6820d3ede1e2315a6a377ea1076e421d88",
"reference": "c9622c6820d3ede1e2315a6a377ea1076e421d88",
"shasum": ""
},
"require": {
"php": "~7.1 || ^8.0"
},
"conflict": {
"doctrine/common": ">2.2,<2.4",
"psr/cache": ">=3"
},
"require-dev": {
"alcaeus/mongo-php-adapter": "^1.1",
"cache/integration-tests": "dev-master",
"doctrine/coding-standard": "^8.0",
"mongodb/mongodb": "^1.1",
"phpunit/phpunit": "^7.0 || ^8.0 || ^9.0",
"predis/predis": "~1.0",
"psr/cache": "^1.0 || ^2.0",
"symfony/cache": "^4.4 || ^5.2"
},
"suggest": {
"alcaeus/mongo-php-adapter": "Required to use legacy MongoDB driver"
},
"type": "library",
"autoload": {
"psr-4": {
"Doctrine\\Common\\Cache\\": "lib/Doctrine/Common/Cache"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Guilherme Blanco",
"email": "guilhermeblanco@gmail.com"
},
{
"name": "Roman Borschel",
"email": "roman@code-factory.org"
},
{
"name": "Benjamin Eberlei",
"email": "kontakt@beberlei.de"
},
{
"name": "Jonathan Wage",
"email": "jonwage@gmail.com"
},
{
"name": "Johannes Schmitt",
"email": "schmittjoh@gmail.com"
}
],
"description": "PHP Doctrine Cache library is a popular cache implementation that supports many different drivers such as redis, memcache, apc, mongodb and others.",
"homepage": "https://www.doctrine-project.org/projects/cache.html",
"keywords": [
"abstraction",
"apcu",
"cache",
"caching",
"couchdb",
"memcached",
"php",
"redis",
"xcache"
],
"support": {
"issues": "https://github.com/doctrine/cache/issues",
"source": "https://github.com/doctrine/cache/tree/2.0.3"
},
"funding": [
{
"url": "https://www.doctrine-project.org/sponsorship.html",
"type": "custom"
},
{
"url": "https://www.patreon.com/phpdoctrine",
"type": "patreon"
},
{
"url": "https://tidelift.com/funding/github/packagist/doctrine%2Fcache",
"type": "tidelift"
}
],
"time": "2021-05-25T09:43:04+00:00"
},
{
"name": "doctrine/dbal",
"version": "3.1.1",
"source": {
"type": "git",
"url": "https://github.com/doctrine/dbal.git",
"reference": "8e0fde2b90e3f61361013d1e928621beeea07bc0"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/doctrine/dbal/zipball/8e0fde2b90e3f61361013d1e928621beeea07bc0",
"reference": "8e0fde2b90e3f61361013d1e928621beeea07bc0",
"shasum": ""
},
"require": {
"composer/package-versions-deprecated": "^1.11.99",
"doctrine/cache": "^1.0|^2.0",
"doctrine/deprecations": "^0.5.3",
"doctrine/event-manager": "^1.0",
"php": "^7.3 || ^8.0"
},
"require-dev": {
"doctrine/coding-standard": "9.0.0",
"jetbrains/phpstorm-stubs": "2020.2",
"phpstan/phpstan": "0.12.81",
"phpstan/phpstan-strict-rules": "^0.12.2",
"phpunit/phpunit": "9.5.5",
"psalm/plugin-phpunit": "0.13.0",
"squizlabs/php_codesniffer": "3.6.0",
"symfony/cache": "^5.2|^6.0",
"symfony/console": "^2.0.5|^3.0|^4.0|^5.0|^6.0",
"vimeo/psalm": "4.6.4"
},
"suggest": {
"symfony/console": "For helpful console commands such as SQL execution and import of files."
},
"bin": [
"bin/doctrine-dbal"
],
"type": "library",
"autoload": {
"psr-4": {
"Doctrine\\DBAL\\": "src"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Guilherme Blanco",
"email": "guilhermeblanco@gmail.com"
},
{
"name": "Roman Borschel",
"email": "roman@code-factory.org"
},
{
"name": "Benjamin Eberlei",
"email": "kontakt@beberlei.de"
},
{
"name": "Jonathan Wage",
"email": "jonwage@gmail.com"
}
],
"description": "Powerful PHP database abstraction layer (DBAL) with many features for database schema introspection and management.",
"homepage": "https://www.doctrine-project.org/projects/dbal.html",
"keywords": [
"abstraction",
"database",
"db2",
"dbal",
"mariadb",
"mssql",
"mysql",
"oci8",
"oracle",
"pdo",
"pgsql",
"postgresql",
"queryobject",
"sasql",
"sql",
"sqlite",
"sqlserver",
"sqlsrv"
],
"support": {
"issues": "https://github.com/doctrine/dbal/issues",
"source": "https://github.com/doctrine/dbal/tree/3.1.1"
},
"funding": [
{
"url": "https://www.doctrine-project.org/sponsorship.html",
"type": "custom"
},
{
"url": "https://www.patreon.com/phpdoctrine",
"type": "patreon"
},
{
"url": "https://tidelift.com/funding/github/packagist/doctrine%2Fdbal",
"type": "tidelift"
}
],
"time": "2021-06-19T17:59:55+00:00"
},
{
"name": "doctrine/deprecations",
"version": "v0.5.3",
"source": {
"type": "git",
"url": "https://github.com/doctrine/deprecations.git",
"reference": "9504165960a1f83cc1480e2be1dd0a0478561314"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/doctrine/deprecations/zipball/9504165960a1f83cc1480e2be1dd0a0478561314",
"reference": "9504165960a1f83cc1480e2be1dd0a0478561314",
"shasum": ""
},
"require": {
"php": "^7.1|^8.0"
},
"require-dev": {
"doctrine/coding-standard": "^6.0|^7.0|^8.0",
"phpunit/phpunit": "^7.0|^8.0|^9.0",
"psr/log": "^1.0"
},
"suggest": {
"psr/log": "Allows logging deprecations via PSR-3 logger implementation"
},
"type": "library",
"autoload": {
"psr-4": {
"Doctrine\\Deprecations\\": "lib/Doctrine/Deprecations"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"description": "A small layer on top of trigger_error(E_USER_DEPRECATED) or PSR-3 logging with options to disable all deprecations or selectively for packages.",
"homepage": "https://www.doctrine-project.org/",
"support": {
"issues": "https://github.com/doctrine/deprecations/issues",
"source": "https://github.com/doctrine/deprecations/tree/v0.5.3"
},
"time": "2021-03-21T12:59:47+00:00"
},
{
"name": "doctrine/event-manager",
"version": "1.1.1",
"source": {
"type": "git",
"url": "https://github.com/doctrine/event-manager.git",
"reference": "41370af6a30faa9dc0368c4a6814d596e81aba7f"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/doctrine/event-manager/zipball/41370af6a30faa9dc0368c4a6814d596e81aba7f",
"reference": "41370af6a30faa9dc0368c4a6814d596e81aba7f",
"shasum": ""
},
"require": {
"php": "^7.1 || ^8.0"
},
"conflict": {
"doctrine/common": "<2.9@dev"
},
"require-dev": {
"doctrine/coding-standard": "^6.0",
"phpunit/phpunit": "^7.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.0.x-dev"
}
},
"autoload": {
"psr-4": {
"Doctrine\\Common\\": "lib/Doctrine/Common"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Guilherme Blanco",
"email": "guilhermeblanco@gmail.com"
},
{
"name": "Roman Borschel",
"email": "roman@code-factory.org"
},
{
"name": "Benjamin Eberlei",
"email": "kontakt@beberlei.de"
},
{
"name": "Jonathan Wage",
"email": "jonwage@gmail.com"
},
{
"name": "Johannes Schmitt",
"email": "schmittjoh@gmail.com"
},
{
"name": "Marco Pivetta",
"email": "ocramius@gmail.com"
}
],
"description": "The Doctrine Event Manager is a simple PHP event system that was built to be used with the various Doctrine projects.",
"homepage": "https://www.doctrine-project.org/projects/event-manager.html",
"keywords": [
"event",
"event dispatcher",
"event manager",
"event system",
"events"
],
"support": {
"issues": "https://github.com/doctrine/event-manager/issues",
"source": "https://github.com/doctrine/event-manager/tree/1.1.x"
},
"funding": [
{
"url": "https://www.doctrine-project.org/sponsorship.html",
"type": "custom"
},
{
"url": "https://www.patreon.com/phpdoctrine",
"type": "patreon"
},
{
"url": "https://tidelift.com/funding/github/packagist/doctrine%2Fevent-manager",
"type": "tidelift"
}
],
"time": "2020-05-29T18:28:51+00:00"
},
{
"name": "doctrine/inflector",
"version": "2.0.3",

View File

@ -0,0 +1,32 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateSubscriptionsRelationColumn extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::table('subscriptions', function (Blueprint $table) {
$table->id()->change();
$table->unsignedInteger('amount')->after('name');
$table->foreignId('fee_id')->after('name')->constrained();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
//
}
}

View File

@ -5,3 +5,4 @@
@import "switch";
@import "layout";
@import "buttons";
@import "table";

10
resources/css/table.css vendored Normal file
View File

@ -0,0 +1,10 @@
.custom-table {
display: table;
width: 100%;
}
.custom-table > * {
display: table-row;
}
.custom-table > * > * {
display: table-cell;
}

View File

@ -8,6 +8,7 @@
<div class="grid gap-2">
<v-link href="/" menu="dashboard" icon="loss">Dashboard</v-link>
<v-link href="/member" menu="member" icon="user">Mitglieder</v-link>
<v-link href="/subscription" menu="subscription" icon="money">Beiträge</v-link>
</div>
</div>

View File

@ -1,6 +1,6 @@
<template>
<div>
<div class="member-table">
<div class="custom-table">
<header>
<div class="px-6 text-gray-200 font-semibold py-3 border-gray-600 border-b">Nachname</div>
<div class="px-6 text-gray-200 font-semibold py-3 border-gray-600 border-b">Vorname</div>
@ -63,15 +63,3 @@ export default {
}
</script>
<style scoped>
.member-table {
display: table;
width: 100%;
}
.member-table > * {
display: table-row;
}
.member-table > * > * {
display: table-cell;
}
</style>

View File

@ -0,0 +1,38 @@
<template>
<form class="p-6 grid gap-4 justify-start" @submit.prevent="submit">
<f-text id="name" v-model="inner.name" label="Name" required></f-text>
<f-select id="fee_id" :options="fees" v-model="inner.fee_id" label="Nami-Beitrag" required></f-select>
<f-text id="amount" v-model="inner.amount" label="Interner Beitrag" required></f-text>
<button type="submit" class="btn btn-primary">Absenden</button>
</form>
</template>
<script>
export default {
data: function() {
return {
inner: {},
};
},
props: {
data: {},
fees: {},
mode: {},
},
methods: {
submit() {
this.mode === 'create'
? this.$inertia.post(`/subscription`, this.inner)
: this.$inertia.patch(`/subscription/${this.inner.id}`, this.inner);
}
},
created() {
this.inner = this.data;
}
};
</script>

View File

@ -0,0 +1,35 @@
<template>
<div>
<div class="custom-table">
<header>
<div class="px-6 text-gray-200 font-semibold py-3 border-gray-600 border-b">Name</div>
<div class="px-6 text-gray-200 font-semibold py-3 border-gray-600 border-b">Interner Beitrag</div>
<div class="px-6 text-gray-200 font-semibold py-3 border-gray-600 border-b">Nami-Beitrag</div>
<div class="px-6 py-3 border-gray-600 border-b"></div>
</header>
<div v-for="sub, index in data" class="text-gray-200 transition-all duration-300 rounded flex items-center hover:bg-gray-800">
<div class="py-1 px-6" v-text="sub.name"></div>
<div class="py-1 px-6" v-text="sub.amount_human"></div>
<div class="py-1 px-6" v-text="sub.fee_name"></div>
<div class="py-1 px-6 flex">
<inertia-link :href="`/subscription/${sub.id}/edit`" class="inline-flex btn btn-warning btn-sm"><sprite src="pencil"></sprite></inertia-link>
</div>
</div>
</div>
</div>
</template>
<script>
import App from '../../layouts/App';
export default {
layout: App,
props:{
data: {}
}
}
</script>

View File

@ -1,6 +1,7 @@
<?php
use App\Member\MemberController;
use App\Payment\SubscriptionController;
use App\Member\MemberConfirmController;
use App\Http\Controllers\HomeController;
use App\Initialize\InitializeController;
@ -13,6 +14,7 @@ Route::group(['middleware' => 'auth:web'], function () {
Route::get('/', HomeController::class)->name('home');
Route::resource('initialize', InitializeController::class);
Route::resource('member', MemberController::class);
Route::resource('subscription', SubscriptionController::class);
Route::post('/member/{member}/confirm', MemberConfirmController::class);
});