5 Commits

Author SHA1 Message Date
th.guenther 12d98b4d7e Small fixes 2026-06-26 22:06:15 +02:00
th.guenther 6c7fe56579 Merge pull request 'Fixed permission management' (#10) from dev-4.5.2 into main
Reviewed-on: #10
2026-06-23 18:46:50 +02:00
th.guenther e09987f5a8 Fixed permission management 2026-06-23 18:46:01 +02:00
th.guenther 5c514e9ff5 Merge pull request 'Improvements' (#9) from dev-4.5.1 into main
Reviewed-on: #9
2026-06-22 21:08:28 +02:00
th.guenther bc60461dac Improvements 2026-06-22 21:07:53 +02:00
12 changed files with 148 additions and 58 deletions
@@ -68,6 +68,11 @@ class SignupController extends CommonController {
public function signUp(int $eventId, Request $request) { public function signUp(int $eventId, Request $request) {
$event = $this->events->getById($eventId, false); $event = $this->events->getById($eventId, false);
if (!$event->registration_allowed || new \DateTime() > $event->start_date) {
return response()->json(['status' => 'closed'], 403);
}
$eventResource = $event->toResource(); $eventResource = $event->toResource();
$registrationData = $request->input('registration_data'); $registrationData = $request->input('registration_data');
$siblingReduction = $registrationData['sibling'] === 'true'; $siblingReduction = $registrationData['sibling'] === 'true';
@@ -54,7 +54,7 @@ function eatingHabit() {
<table class="form-table" style="margin-bottom: 20px;"> <table class="form-table" style="margin-bottom: 20px;">
<tr> <tr>
<td>Dein Name:</td> <td>Dein Name:</td>
<td>{{props.formData.vorname}} {{props.formData.vorname}}</td> <td>{{props.formData.vorname}} {{props.formData.nachname}}</td>
</tr> </tr>
<tr> <tr>
+12
View File
@@ -99,10 +99,14 @@ function close() {
<div class="signup-body"> <div class="signup-body">
<SignupForm <SignupForm
v-if="props.event.registrationAllowed"
:event="props.event" :event="props.event"
:participantData="props.participantData ?? {}" :participantData="props.participantData ?? {}"
:localGroups="props.localGroups ?? []" :localGroups="props.localGroups ?? []"
/> />
<p v-else class="signup-closed-notice">
Die Anmeldung für diese Veranstaltung ist geschlossen.
</p>
</div> </div>
</shadowed-box> </shadowed-box>
@@ -220,6 +224,14 @@ function close() {
word-break: break-all; word-break: break-all;
} }
.signup-closed-notice {
text-align: center;
padding: 24px;
color: #991b1b;
font-weight: 600;
font-size: 1rem;
}
/* ─── Tablet (6401023px) ─── */ /* ─── Tablet (6401023px) ─── */
@media (max-width: 1023px) { @media (max-width: 1023px) {
.signup-box { .signup-box {
@@ -4,6 +4,7 @@ namespace App\Domains\Invoice\Actions\CreateInvoice;
use App\Enumerations\InvoiceStatus; use App\Enumerations\InvoiceStatus;
use App\Mail\InvoiceMails\InvoiceMailsNewInvoiceMail; use App\Mail\InvoiceMails\InvoiceMailsNewInvoiceMail;
use App\Mail\InvoiceMails\InvoiceMailsSubmittedConfirmationMail;
use App\Mail\ParticipantParticipationMails\EventSignUpSuccessfullMail; use App\Mail\ParticipantParticipationMails\EventSignUpSuccessfullMail;
use App\Models\Invoice; use App\Models\Invoice;
use Illuminate\Support\Facades\Mail; use Illuminate\Support\Facades\Mail;
@@ -50,6 +51,13 @@ class CreateInvoiceCommand {
if ($invoice !== null) { if ($invoice !== null) {
$response->success = true; $response->success = true;
$response->invoice = $invoice; $response->invoice = $invoice;
if ($invoice->contact_email !== null) {
Mail::to($invoice->contact_email)->send(new InvoiceMailsSubmittedConfirmationMail(
invoice: $invoice,
costUnit: $this->request->costUnit,
));
}
} }
if ($this->request->costUnit->mail_on_new) { if ($this->request->costUnit->mail_on_new) {
@@ -65,7 +65,7 @@ class EditController extends CommonController{
$currentEvents = $this->costUnits->getCostUnitsForNewInvoice(CostUnitType::COST_UNIT_TYPE_EVENT); $currentEvents = $this->costUnits->getCostUnitsForNewInvoice(CostUnitType::COST_UNIT_TYPE_EVENT);
return response()->json([ return response()->json([
'invoice' => new InvoiceResource($invoice)->toArray(), 'invoice' => new InvoiceResource($newInvoice)->toArray(),
'status' => 'success', 'status' => 'success',
'costUnits' => array_merge($runningJobs, $currentEvents), 'costUnits' => array_merge($runningJobs, $currentEvents),
]); ]);
@@ -0,0 +1,50 @@
<?php
namespace App\Mail\InvoiceMails;
use App\Models\CostUnit;
use App\Models\Invoice;
use App\ValueObjects\Amount;
use Illuminate\Mail\Mailable;
use Illuminate\Mail\Mailables\Attachment;
use Illuminate\Mail\Mailables\Content;
use Illuminate\Mail\Mailables\Envelope;
class InvoiceMailsSubmittedConfirmationMail extends Mailable {
public function __construct(
private Invoice $invoice,
private CostUnit $costUnit,
)
{
//
}
public function envelope(): Envelope
{
return new Envelope(
subject: 'Deine Abrechnung wurde erfolgreich eingereicht',
);
}
public function content(): Content
{
return new Content(
view: 'emails.invoices.submitted_confirmation',
with: [
'contactName' => $this->invoice->contact_name,
'costUnitName' => $this->costUnit->name,
'invoiceAmount' => Amount::fromString($this->invoice->amount)->toString(),
'invoiceType' => $this->invoice->invoiceType()->name,
'invoiceNumber' => $this->invoice->invoice_number,
],
);
}
/**
* @return array<int, Attachment>
*/
public function attachments(): array
{
return [];
}
}
+4 -18
View File
@@ -66,34 +66,20 @@ class CostUnitRepository {
} }
public function getCostUnitsByCriteria(array $criteria, bool $forDisplay = true, $disableAccessCheck = false) : array { public function getCostUnitsByCriteria(array $criteria, bool $forDisplay = true, $disableAccessCheck = false) : array {
$tenant = app('tenant');
$canSeeAll = false;
$user = Auth()->user(); $user = Auth()->user();
if ($disableAccessCheck) { if ($disableAccessCheck) {
$canSeeAll = true; $canSeeAll = true;
} else { } else {
if ($tenant->slug !== 'lv') { $canSeeAll = in_array(new AuthCheckProvider()->getUserRole(), [
if ( UserRole::USER_ROLE_ADMIN, UserRole::USER_ROLE_GROUP_LEADER
new AuthCheckProvider()->isAdministrator() || ]);
$user->user_role_local_group === UserRole::USER_ROLE_ADMIN
) {
$canSeeAll = true;
}
} else {
if (
in_array($user->user_role_main, [UserRole::USER_ROLE_GROUP_LEADER, UserRole::USER_ROLE_ADMIN])
) {
$canSeeAll = true;
}
}
} }
$visibleCostUnits = []; $visibleCostUnits = [];
/** @var CostUnit $costUnit */ /** @var CostUnit $costUnit */
foreach (Costunit::where($criteria)->get() as $costUnit) { foreach (Costunit::where($criteria)->get() as $costUnit) {
if ($canSeeAll || $disableAccessCheck || $costUnit->treasurers()->where('user_id', $user->id)->exists() ) { if ($canSeeAll || $costUnit->treasurers()->where('user_id', $user->id)->exists() ) {
if ($forDisplay) { if ($forDisplay) {
$visibleCostUnits[] = new CostUnitResource($costUnit)->toArray(request()); $visibleCostUnits[] = new CostUnitResource($costUnit)->toArray(request());
} else { } else {
+4 -22
View File
@@ -77,38 +77,20 @@ class EventRepository {
} }
public function getEventsByCriteria(array $criteria, $accessCheck = true) : array { public function getEventsByCriteria(array $criteria, $accessCheck = true) : array {
$tenant = app('tenant');
$canSeeAll = false;
$user = Auth()->user(); $user = Auth()->user();
if (!$accessCheck) { if (!$accessCheck) {
$canSeeAll = true; $canSeeAll = true;
} else { } else {
if ( $canSeeAll = in_array(new AuthCheckProvider()->getUserRole(), [
new AuthCheckProvider()->isAdministrator() || UserRole::USER_ROLE_ADMIN, UserRole::USER_ROLE_GROUP_LEADER
$user->user_role_local_group === UserRole::USER_ROLE_ADMIN ]);
) {
if (
$user->user_role_main === UserRole::USER_ROLE_ADMIN ||
in_array($user->user_role_local_group, [UserRole::USER_ROLE_GROUP_LEADER, UserRole::USER_ROLE_ADMIN])
) {
$canSeeAll = true;
}
} else {
if (
in_array($user->user_role_main, [UserRole::USER_ROLE_GROUP_LEADER, UserRole::USER_ROLE_ADMIN])
) {
$canSeeAll = true;
}
}
} }
$visibleEvents = []; $visibleEvents = [];
/** @var Event $event */ /** @var Event $event */
foreach (Event::where($criteria)->orderBy('start_date')->get() as $event) { foreach (Event::where($criteria)->orderBy('start_date')->get() as $event) {
if ($canSeeAll || $event->eventManagers()->where('user_id', $user->id)->exists()) {
if ($canSeeAll || !$accessCheck || $event->eventManagers()->where('user_id', $user->id)->exists()) {
$visibleEvents[] = $event; $visibleEvents[] = $event;
} }
} }
+4 -13
View File
@@ -6,6 +6,7 @@ use App\Enumerations\InvoiceStatus;
use App\Enumerations\UserRole; use App\Enumerations\UserRole;
use App\Models\CostUnit; use App\Models\CostUnit;
use App\Models\Invoice; use App\Models\Invoice;
use App\Providers\AuthCheckProvider;
use App\Resources\InvoiceResource; use App\Resources\InvoiceResource;
use App\ValueObjects\Amount; use App\ValueObjects\Amount;
use Illuminate\Database\Eloquent\Collection; use Illuminate\Database\Eloquent\Collection;
@@ -83,19 +84,9 @@ class InvoiceRepository {
return $invoice; return $invoice;
} }
$user = auth()->user(); return in_array(new AuthCheckProvider()->getUserRole(), [
if ($user->user_role_main === UserRole::USER_ROLE_ADMIN) { UserRole::USER_ROLE_ADMIN, UserRole::USER_ROLE_GROUP_LEADER
return $invoice; ]) ? $invoice : null;
}
if (app('tenant')->slug === 'lv' && $user->user_role_main === UserRole::USER_ROLE_GROUP_LEADER) {
return $invoice;
}
if (app('tenant')->slug !== 'lv' && $user->local_group === app('tenant')->slug && $user->user_role_local_group === UserRole::USER_ROLE_GROUP_LEADER) {
return $invoice;
}
return null;
} }
} }
+2 -2
View File
@@ -34,7 +34,7 @@ class EventResource extends JsonResource{
'accountIban' => $this->event->account_iban, 'accountIban' => $this->event->account_iban,
'alcoholicsAge' => $this->event->alcoholics_age, 'alcoholicsAge' => $this->event->alcoholics_age,
'sendWeeklyReports' => $this->event->send_weekly_report, 'sendWeeklyReports' => $this->event->send_weekly_report,
'registrationAllowed' => $this->event->registration_allowed, 'registrationAllowed' => $this->event->registration_allowed && new \DateTime() <= $this->event->start_date,
'archived' => $this->event->archived, 'archived' => $this->event->archived,
'earlyBirdEnd' => ['internal' => $this->event->early_bird_end->format('Y-m-d'), 'formatted' => $this->event->early_bird_end->format('d.m.Y')], 'earlyBirdEnd' => ['internal' => $this->event->early_bird_end->format('Y-m-d'), 'formatted' => $this->event->early_bird_end->format('d.m.Y')],
'registrationFinalEnd' => ['internal' => $this->event->registration_final_end->format('Y-m-d'), 'formatted' => $this->event->registration_final_end->format('d.m.Y')], 'registrationFinalEnd' => ['internal' => $this->event->registration_final_end->format('Y-m-d'), 'formatted' => $this->event->registration_final_end->format('d.m.Y')],
@@ -331,7 +331,7 @@ class EventResource extends JsonResource{
$basicFee = $basicFee->multiply($this->getMultiplier()); $basicFee = $basicFee->multiply($this->getMultiplier());
if ($this->event->pay_per_day) { if ($this->event->pay_per_day) {
$days = $arrival->diff($departure)->days; $days = $arrival->diff($departure)->days + 1;
$basicFee = $basicFee->multiply($days); $basicFee = $basicFee->multiply($days);
} }
@@ -0,0 +1,56 @@
<!DOCTYPE html>
<html>
<body>
<h1>Hallo {{$contactName}},</h1>
<p>
deine Abrechnung wurde erfolgreich eingereicht.<br />
In der nachfolgenden Übersicht findest du die Details zu deiner Abrechnung:
</p>
<table cellpadding="0" cellspacing="0" border="0"
style="width: 100%; max-width: 640px; border-collapse: collapse; font-family: Arial, sans-serif; font-size: 14px; color: #1f2937;">
<tr>
<td style="padding: 8px 12px; width: 180px; font-weight: 600; color: #4b5563; border-bottom: 1px solid #e5e7eb;">
Abrechnungsnummer:
</td>
<td style="padding: 8px 12px; border-bottom: 1px solid #e5e7eb;">
{{$invoiceNumber}}
</td>
</tr>
<tr>
<td style="padding: 8px 12px; width: 180px; font-weight: 600; color: #4b5563; border-bottom: 1px solid #e5e7eb;">
Veranstaltung / Kostenstelle:
</td>
<td style="padding: 8px 12px; border-bottom: 1px solid #e5e7eb;">
{{$costUnitName}}
</td>
</tr>
<tr>
<td style="padding: 8px 12px; width: 180px; font-weight: 600; color: #4b5563; border-bottom: 1px solid #e5e7eb;">
Betrag:
</td>
<td style="padding: 8px 12px; border-bottom: 1px solid #e5e7eb;">
{{$invoiceAmount}}
</td>
</tr>
<tr>
<td style="padding: 8px 12px; font-weight: 600; color: #4b5563; border-bottom: 1px solid #e5e7eb;">
Grund der Abrechnung:
</td>
<td style="padding: 8px 12px; border-bottom: 1px solid #e5e7eb;">
{{$invoiceType}}
</td>
</tr>
</table>
<p>
Deine Abrechnung wird nun bearbeitet. Du wirst per E-Mail benachrichtigt, sobald sich der Status deiner Abrechnung ändert.
</p>
</body>
</html>
+1 -1
View File
@@ -1 +1 @@
4.5.0 4.5.3