Add payment for promises
continuous-integration/drone/push Build is passing
Details
continuous-integration/drone/push Build is passing
Details
This commit is contained in:
parent
9740ea2be4
commit
8af0e2a16e
|
@ -43,7 +43,7 @@ class MemberController extends Controller
|
|||
$payload = app(MemberView::class)->index($request, $query['filter']);
|
||||
$payload['toolbar'] = [
|
||||
['href' => route('member.create'), 'label' => 'Mitglied anlegen', 'color' => 'primary', 'icon' => 'plus'],
|
||||
['href' => route('allpayment.create'), 'label' => 'Rechnungen erstellen', 'color' => 'primary', 'icon' => 'invoice', 'show' => $settings->hasModule('bill')],
|
||||
['href' => route('allpayment.page'), 'label' => 'Rechnungen erstellen', 'color' => 'primary', 'icon' => 'invoice', 'show' => $settings->hasModule('bill')],
|
||||
['href' => route('sendpayment.create'), 'label' => 'Rechnungen versenden', 'color' => 'info', 'icon' => 'envelope', 'show' => $settings->hasModule('bill')],
|
||||
];
|
||||
$payload['query'] = $query;
|
||||
|
|
|
@ -18,6 +18,13 @@ class Membership extends Model
|
|||
|
||||
public $fillable = ['subactivity_id', 'activity_id', 'group_id', 'member_id', 'nami_id', 'from', 'promised_at'];
|
||||
|
||||
/**
|
||||
* @var array<string, string>
|
||||
*/
|
||||
public $casts = [
|
||||
'promised_at' => 'date',
|
||||
];
|
||||
|
||||
public function activity(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(Activity::class);
|
||||
|
|
|
@ -25,7 +25,7 @@ class MembershipResource extends JsonResource
|
|||
'subactivity_id' => $this->subactivity_id,
|
||||
'subactivity_name' => $this->subactivity?->name,
|
||||
'human_date' => $this->created_at->format('d.m.Y'),
|
||||
'promised_at' => $this->promised_at,
|
||||
'promised_at' => $this->promised_at?->format('Y-m-d'),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
<?php
|
||||
|
||||
namespace App\Payment\Actions;
|
||||
|
||||
use Inertia;
|
||||
use Inertia\Response;
|
||||
use Lorisleiva\Actions\Concerns\AsAction;
|
||||
|
||||
class AllpaymentPageAction
|
||||
{
|
||||
use AsAction;
|
||||
|
||||
/**
|
||||
* @return array<string, string>
|
||||
*/
|
||||
public function handle(): array
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
public function asController(): Response
|
||||
{
|
||||
session()->put('menu', 'member');
|
||||
session()->put('title', 'Rechnungen erstellen');
|
||||
|
||||
return Inertia::render('allpayment/VForm', $this->handle());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,83 @@
|
|||
<?php
|
||||
|
||||
namespace App\Payment\Actions;
|
||||
|
||||
use App\Member\Member;
|
||||
use App\Member\Membership;
|
||||
use App\Payment\Status;
|
||||
use App\Payment\Subscription;
|
||||
use Illuminate\Database\Eloquent\Collection;
|
||||
use Illuminate\Http\RedirectResponse;
|
||||
use Lorisleiva\Actions\ActionRequest;
|
||||
use Lorisleiva\Actions\Concerns\AsAction;
|
||||
|
||||
class AllpaymentStoreAction
|
||||
{
|
||||
use AsAction;
|
||||
|
||||
/**
|
||||
* @return array<string, string>
|
||||
*/
|
||||
public function rules(): array
|
||||
{
|
||||
return [
|
||||
'year' => 'required|numeric',
|
||||
'for_promise' => 'present|boolean',
|
||||
];
|
||||
}
|
||||
|
||||
public function handle(int $year, bool $forPromise): void
|
||||
{
|
||||
foreach (Member::payable()->whereNoPayment($year)->get() as $member) {
|
||||
$member->createPayment([
|
||||
'nr' => $year,
|
||||
'subscription_id' => $member->subscription_id,
|
||||
'status_id' => Status::default(),
|
||||
]);
|
||||
|
||||
if (!$forPromise) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$this->createPaymentsForPromise($member, $year);
|
||||
}
|
||||
}
|
||||
|
||||
private function createPaymentsForPromise(Member $member, int $year): void
|
||||
{
|
||||
$subscription = Subscription::firstWhere('for_promise', true);
|
||||
|
||||
if (is_null($subscription)) {
|
||||
return;
|
||||
}
|
||||
|
||||
foreach ($this->promisedMemberships($member, $year) as $membership) {
|
||||
$attributes = [
|
||||
'nr' => $membership->subactivity->name.' '.$membership->promised_at->year,
|
||||
'subscription_id' => $subscription->id,
|
||||
];
|
||||
|
||||
if (!$member->payments()->where($attributes)->exists()) {
|
||||
$member->createPayment([
|
||||
...$attributes,
|
||||
'status_id' => Status::default(),
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Collection<Membership>
|
||||
*/
|
||||
public function promisedMemberships(Member $member, int $year): Collection
|
||||
{
|
||||
return $member->memberships()->whereNotNull('promised_at')->whereYear('promised_at', now()->year($year)->subYear())->get();
|
||||
}
|
||||
|
||||
public function asController(ActionRequest $request): RedirectResponse
|
||||
{
|
||||
$this->handle($request->year, $request->for_promise);
|
||||
|
||||
return redirect()->back()->success('Zahlungen erstellt');
|
||||
}
|
||||
}
|
|
@ -1,37 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace App\Payment;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Member\Member;
|
||||
use Illuminate\Http\RedirectResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Inertia\Response;
|
||||
|
||||
class AllpaymentController extends Controller
|
||||
{
|
||||
public function create(): Response
|
||||
{
|
||||
session()->put('menu', 'member');
|
||||
session()->put('title', 'Rechnungen erstellen');
|
||||
|
||||
return \Inertia::render('allpayment/VForm');
|
||||
}
|
||||
|
||||
public function store(Request $request): RedirectResponse
|
||||
{
|
||||
$request->validate([
|
||||
'year' => 'required|numeric',
|
||||
]);
|
||||
|
||||
foreach (Member::payable()->whereNoPayment($request->year)->get() as $member) {
|
||||
$member->createPayment([
|
||||
'nr' => $request->year,
|
||||
'subscription_id' => $member->subscription_id,
|
||||
'status_id' => Status::default(),
|
||||
]);
|
||||
}
|
||||
|
||||
return redirect()->back()->success('Zahlungen erstellt');
|
||||
}
|
||||
}
|
|
@ -15,7 +15,7 @@ class Subscription extends Model
|
|||
/**
|
||||
* @var array<int, string>
|
||||
*/
|
||||
public $fillable = ['name', 'fee_id', 'split'];
|
||||
public $fillable = ['name', 'fee_id', 'split', 'for_promise'];
|
||||
|
||||
/**
|
||||
* @var array<string, string>
|
||||
|
|
|
@ -17,6 +17,7 @@ class SubscriptionFactory extends Factory
|
|||
return [
|
||||
'name' => $this->faker->word,
|
||||
'fee_id' => Fee::factory()->createOne()->id,
|
||||
'for_promise' => false,
|
||||
];
|
||||
}
|
||||
|
||||
|
@ -38,4 +39,9 @@ class SubscriptionFactory extends Factory
|
|||
|
||||
return $instance;
|
||||
}
|
||||
|
||||
public function forPromise(): self
|
||||
{
|
||||
return $this->state(['for_promise' => true]);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,6 +18,7 @@ return new class() extends Migration {
|
|||
Schema::table('subscriptions', function (Blueprint $table) {
|
||||
$table->dropColumn('amount');
|
||||
$table->boolean('split')->default(false);
|
||||
$table->boolean('for_promise')->default(false);
|
||||
});
|
||||
|
||||
Schema::create('subscription_children', function (Blueprint $table) {
|
||||
|
|
|
@ -13,7 +13,8 @@ use App\Member\MemberController;
|
|||
use App\Membership\Actions\MembershipDestroyAction;
|
||||
use App\Membership\Actions\MembershipStoreAction;
|
||||
use App\Membership\Actions\MembershipUpdateAction;
|
||||
use App\Payment\AllpaymentController;
|
||||
use App\Payment\Actions\AllpaymentPageAction;
|
||||
use App\Payment\Actions\AllpaymentStoreAction;
|
||||
use App\Payment\PaymentController;
|
||||
use App\Payment\SendpaymentController;
|
||||
use App\Payment\SubscriptionController;
|
||||
|
@ -30,7 +31,8 @@ Route::group(['middleware' => 'auth:web'], function (): void {
|
|||
Route::resource('member', MemberController::class)->except('show');
|
||||
Route::get('/member/{member}', MemberShowAction::class)->name('member.show');
|
||||
Route::apiResource('member.payment', PaymentController::class);
|
||||
Route::resource('allpayment', AllpaymentController::class);
|
||||
Route::get('allpayment', AllpaymentPageAction::class)->name('allpayment.page');
|
||||
Route::post('allpayment', AllpaymentStoreAction::class)->name('allpayment.store');
|
||||
Route::resource('subscription', SubscriptionController::class);
|
||||
Route::get('/member/{member}/pdf', MemberPdfController::class)
|
||||
->name('member.singlepdf');
|
||||
|
|
|
@ -3,7 +3,10 @@
|
|||
namespace Tests\Feature\Payment;
|
||||
|
||||
use App\Member\Member;
|
||||
use App\Member\Membership;
|
||||
use App\Payment\Payment;
|
||||
use App\Payment\Status;
|
||||
use App\Payment\Subscription;
|
||||
use Illuminate\Foundation\Testing\DatabaseTransactions;
|
||||
use Tests\TestCase;
|
||||
|
||||
|
@ -49,6 +52,7 @@ class AllpaymentTest extends TestCase
|
|||
|
||||
$response = $this->from('/allpayment/create')->post('allpayment', [
|
||||
'year' => now()->addYear()->year,
|
||||
'for_promise' => false,
|
||||
]);
|
||||
|
||||
$response->assertRedirect('/allpayment/create');
|
||||
|
@ -59,4 +63,83 @@ class AllpaymentTest extends TestCase
|
|||
'status_id' => Status::first()->id,
|
||||
]);
|
||||
}
|
||||
|
||||
public function testItCreatesPromisePayments(): void
|
||||
{
|
||||
$member = Member::factory()
|
||||
->defaults()
|
||||
->emailBillKind()
|
||||
->has(Membership::factory()->in('€ Mitglied', 123, 'Rover', 124)->promise(now()->subYear()->startOfYear()))
|
||||
->create();
|
||||
|
||||
$subscription = Subscription::factory()->forPromise()->create();
|
||||
|
||||
$this->from('/allpayment/create')->post('allpayment', [
|
||||
'year' => now()->year,
|
||||
'for_promise' => true,
|
||||
]);
|
||||
|
||||
$this->assertDatabaseHas('payments', [
|
||||
'member_id' => $member->id,
|
||||
'nr' => 'Rover '.now()->subYear()->year,
|
||||
'subscription_id' => $subscription->id,
|
||||
'status_id' => Status::first()->id,
|
||||
]);
|
||||
}
|
||||
|
||||
public function testItDoesntCreatePromisePaymentsWhenPromiseIsOver(): void
|
||||
{
|
||||
$member = Member::factory()
|
||||
->defaults()
|
||||
->emailBillKind()
|
||||
->has(Membership::factory()->in('€ Mitglied', 123, 'Rover', 124)->promise(now()->subYears(2)->startOfYear()))
|
||||
->create();
|
||||
|
||||
$subscription = Subscription::factory()->forPromise()->create();
|
||||
|
||||
$this->from('/allpayment/create')->post('allpayment', [
|
||||
'year' => now()->year,
|
||||
'for_promise' => true,
|
||||
]);
|
||||
|
||||
$this->assertDatabaseMissing('payments', [
|
||||
'subscription_id' => $subscription->id,
|
||||
]);
|
||||
}
|
||||
|
||||
public function testItDoesntCreatePromisePaymentsWhenUserAlreadyHasPayment(): void
|
||||
{
|
||||
$subscription = Subscription::factory()->forPromise()->create();
|
||||
|
||||
$member = Member::factory()
|
||||
->defaults()
|
||||
->emailBillKind()
|
||||
->has(Membership::factory()->in('€ Mitglied', 123, 'Rover', 124)->promise(now()->subYear()->startOfYear()))
|
||||
->has(Payment::factory()->notPaid()->nr('Rover '.now()->subYear()->year)->for($subscription))
|
||||
->create();
|
||||
|
||||
$this->from('/allpayment/create')->post('allpayment', [
|
||||
'year' => now()->year,
|
||||
'for_promise' => true,
|
||||
]);
|
||||
|
||||
$this->assertCount(2, $member->payments);
|
||||
}
|
||||
|
||||
public function testItDoesntCreatePromisePaymentsWhenNoSubscriptionFound(): void
|
||||
{
|
||||
$member = Member::factory()
|
||||
->defaults()
|
||||
->emailBillKind()
|
||||
->has(Membership::factory()->in('€ Mitglied', 123, 'Rover', 124)->promise(now()->subYear()->startOfYear()))
|
||||
->has(Payment::factory()->notPaid()->nr('Rover '.now()->subYear()->year))
|
||||
->create();
|
||||
|
||||
$this->from('/allpayment/create')->post('allpayment', [
|
||||
'year' => now()->year,
|
||||
'for_promise' => true,
|
||||
]);
|
||||
|
||||
$this->assertCount(2, $member->payments);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue