Direct payments for invoices
Events can be moved to archive and moved back Fixed validation
This commit is contained in:
@@ -3,6 +3,7 @@
|
|||||||
import InvoiceDetails from "../../../Invoice/Views/Partials/invoiceDetails/InvoiceDetails.vue";
|
import InvoiceDetails from "../../../Invoice/Views/Partials/invoiceDetails/InvoiceDetails.vue";
|
||||||
import { useAjax } from "../../../../../resources/js/components/ajaxHandler.js";
|
import { useAjax } from "../../../../../resources/js/components/ajaxHandler.js";
|
||||||
import {ref} from "vue";
|
import {ref} from "vue";
|
||||||
|
import {toast} from "vue3-toastify";
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
data: Object
|
data: Object
|
||||||
@@ -12,7 +13,7 @@
|
|||||||
const invoice = ref(null)
|
const invoice = ref(null)
|
||||||
const show_invoice = ref(false)
|
const show_invoice = ref(false)
|
||||||
const localData = ref(props.data)
|
const localData = ref(props.data)
|
||||||
|
console.log(props.data)
|
||||||
async function openInvoiceDetails(invoiceId) {
|
async function openInvoiceDetails(invoiceId) {
|
||||||
const url = '/api/v1/invoice/details/' + invoiceId
|
const url = '/api/v1/invoice/details/' + invoiceId
|
||||||
|
|
||||||
@@ -40,6 +41,50 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function exportPayouts() {
|
||||||
|
toast.info('Der Export wird nun gestartet. Bitte verlasse diese Seite nicht, bis der Export abgeschlossen ist.')
|
||||||
|
|
||||||
|
const response = await fetch('/api/v1/core/retrieve-global-data');
|
||||||
|
const data = await response.json();
|
||||||
|
const exportUrl = '/api/v1/cost-unit/' + props.data.costUnit.id + '/export-payouts';
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (data.tenant.download_exports) {
|
||||||
|
const response = await fetch(exportUrl, {
|
||||||
|
headers: { "Content-Type": "application/json" },
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!response.ok) throw new Error('Fehler beim Export (ZIP)');
|
||||||
|
|
||||||
|
const blob = await response.blob();
|
||||||
|
const downloadUrl = window.URL.createObjectURL(blob);
|
||||||
|
const a = document.createElement("a");
|
||||||
|
a.style.display = "none";
|
||||||
|
a.href = downloadUrl;
|
||||||
|
a.download = "Abrechnungen-Sippenstunden.zip";
|
||||||
|
|
||||||
|
document.body.appendChild(a);
|
||||||
|
a.click();
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
window.URL.revokeObjectURL(downloadUrl);
|
||||||
|
document.body.removeChild(a);
|
||||||
|
}, 100);
|
||||||
|
} else {
|
||||||
|
const response = await request(exportUrl, {
|
||||||
|
method: "GET",
|
||||||
|
});
|
||||||
|
|
||||||
|
toast.success(response.message);
|
||||||
|
}
|
||||||
|
|
||||||
|
reload()
|
||||||
|
|
||||||
|
} catch (err) {
|
||||||
|
toast.error('Beim Export der Abrechnungen ist ein Fehler aufgetreten.');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
@@ -56,7 +101,7 @@
|
|||||||
</td>
|
</td>
|
||||||
<td style="width: 150px;">
|
<td style="width: 150px;">
|
||||||
<Icon v-if="invoice.donation" name="hand-holding-dollar" style="color: #ffffff; background-color: green" />
|
<Icon v-if="invoice.donation" name="hand-holding-dollar" style="color: #ffffff; background-color: green" />
|
||||||
<Icon v-if="invoice.alreadyPaid" name="comments-dollar" style="color: #ffffff; background-color: green" />
|
<Icon v-if="invoice.externalPayment" name="comments-dollar" style="color: #ffffff; background-color: green" />
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
{{invoice.contactName}}<br />
|
{{invoice.contactName}}<br />
|
||||||
@@ -68,6 +113,13 @@
|
|||||||
<input type="button" value="Abrechnung Anzeigen" @click="openInvoiceDetails(invoice.id)" />
|
<input type="button" value="Abrechnung Anzeigen" @click="openInvoiceDetails(invoice.id)" />
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|
||||||
|
<tr v-if="props.data.endpoint === 'approved'">
|
||||||
|
<td colspan="5"></td>
|
||||||
|
<td>
|
||||||
|
<a style="font-size: 10pt;" class="link" @click="exportPayouts()">Genehmigte Abrechnungen exportieren</a>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
<p v-else>Es sind keine Abrechnungen in dieser Kategorie vorhanden.</p>
|
<p v-else>Es sind keine Abrechnungen in dieser Kategorie vorhanden.</p>
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,22 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Domains\Event\Actions\ArchiveEvent;
|
||||||
|
|
||||||
|
class ArchiveEventCommand {
|
||||||
|
public ArchiveEventRequest $request;
|
||||||
|
|
||||||
|
public function __construct(ArchiveEventRequest $request) {
|
||||||
|
$this->request = $request;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function execute(): ArchiveEventResponse {
|
||||||
|
$response = new ArchiveEventResponse();
|
||||||
|
|
||||||
|
$this->request->event->archived = true;
|
||||||
|
$this->request->event->save();
|
||||||
|
|
||||||
|
$response->success = true;
|
||||||
|
|
||||||
|
return $response;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Domains\Event\Actions\ArchiveEvent;
|
||||||
|
|
||||||
|
use App\Models\Event;
|
||||||
|
|
||||||
|
class ArchiveEventRequest {
|
||||||
|
public Event $event;
|
||||||
|
|
||||||
|
public function __construct(Event $event) {
|
||||||
|
$this->event = $event;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Domains\Event\Actions\ArchiveEvent;
|
||||||
|
|
||||||
|
class ArchiveEventResponse {
|
||||||
|
public bool $success;
|
||||||
|
|
||||||
|
public function __construct() {
|
||||||
|
$this->success = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Domains\Event\Actions\UnarchiveEvent;
|
||||||
|
|
||||||
|
class UnarchiveEventCommand {
|
||||||
|
public UnarchiveEventRequest $request;
|
||||||
|
|
||||||
|
public function __construct(UnarchiveEventRequest $request) {
|
||||||
|
$this->request = $request;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function execute(): UnarchiveEventResponse {
|
||||||
|
$response = new UnarchiveEventResponse();
|
||||||
|
|
||||||
|
$this->request->event->archived = false;
|
||||||
|
$this->request->event->save();
|
||||||
|
|
||||||
|
$response->success = true;
|
||||||
|
|
||||||
|
return $response;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Domains\Event\Actions\UnarchiveEvent;
|
||||||
|
|
||||||
|
use App\Models\Event;
|
||||||
|
|
||||||
|
class UnarchiveEventRequest {
|
||||||
|
public Event $event;
|
||||||
|
|
||||||
|
public function __construct(Event $event) {
|
||||||
|
$this->event = $event;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Domains\Event\Actions\UnarchiveEvent;
|
||||||
|
|
||||||
|
class UnarchiveEventResponse {
|
||||||
|
public bool $success;
|
||||||
|
|
||||||
|
public function __construct() {
|
||||||
|
$this->success = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Domains\Event\Controllers;
|
||||||
|
|
||||||
|
use App\Providers\InertiaProvider;
|
||||||
|
use App\Scopes\CommonController;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use Inertia\Response;
|
||||||
|
|
||||||
|
class ArchivedEventsController extends CommonController
|
||||||
|
{
|
||||||
|
public function __invoke(Request $request): Response {
|
||||||
|
$events = [];
|
||||||
|
foreach ($this->events->getEventsByCriteria(['archived' => true]) as $event) {
|
||||||
|
$events[] = [
|
||||||
|
'id' => $event->id,
|
||||||
|
'name' => $event->name,
|
||||||
|
'location' => $event->location,
|
||||||
|
'postalCode' => $event->postal_code,
|
||||||
|
'eventBegin' => $event->start_date->format('d.m.Y'),
|
||||||
|
'eventEnd' => $event->end_date->format('d.m.Y'),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
return (new InertiaProvider('Event/ArchivedEvents', ['events' => $events]))->render();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Domains\Event\Controllers;
|
||||||
|
|
||||||
|
use App\Domains\Event\Actions\ArchiveEvent\ArchiveEventCommand;
|
||||||
|
use App\Domains\Event\Actions\ArchiveEvent\ArchiveEventRequest;
|
||||||
|
use App\Scopes\CommonController;
|
||||||
|
use Illuminate\Http\JsonResponse;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
|
||||||
|
class EventArchiveController extends CommonController
|
||||||
|
{
|
||||||
|
public function __invoke(string $eventId, Request $request): JsonResponse {
|
||||||
|
$event = $this->events->getByIdentifier($eventId);
|
||||||
|
|
||||||
|
$archiveEventRequest = new ArchiveEventRequest($event);
|
||||||
|
$archiveEventCommand = new ArchiveEventCommand($archiveEventRequest);
|
||||||
|
$response = $archiveEventCommand->execute();
|
||||||
|
|
||||||
|
return response()->json([
|
||||||
|
'status' => $response->success ? 'success' : 'error',
|
||||||
|
'message' => $response->success ? 'Das Event wurde erfolgreich archiviert.' : 'Beim Archivieren des Events ist ein Fehler aufgetreten.'
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Domains\Event\Controllers;
|
||||||
|
|
||||||
|
use App\Domains\Event\Actions\UnarchiveEvent\UnarchiveEventCommand;
|
||||||
|
use App\Domains\Event\Actions\UnarchiveEvent\UnarchiveEventRequest;
|
||||||
|
use App\Scopes\CommonController;
|
||||||
|
use Illuminate\Http\JsonResponse;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
|
||||||
|
class EventUnarchiveController extends CommonController
|
||||||
|
{
|
||||||
|
public function __invoke(int $eventId, Request $request): JsonResponse {
|
||||||
|
$event = $this->events->getById($eventId);
|
||||||
|
|
||||||
|
$unarchiveRequest = new UnarchiveEventRequest($event);
|
||||||
|
$unarchiveCommand = new UnarchiveEventCommand($unarchiveRequest);
|
||||||
|
$response = $unarchiveCommand->execute();
|
||||||
|
|
||||||
|
return response()->json(['status' => $response->success ? 'success' : 'error']);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,6 +2,8 @@
|
|||||||
|
|
||||||
use App\Domains\Event\Controllers\CreateController;
|
use App\Domains\Event\Controllers\CreateController;
|
||||||
use App\Domains\Event\Controllers\DetailsController;
|
use App\Domains\Event\Controllers\DetailsController;
|
||||||
|
use App\Domains\Event\Controllers\EventArchiveController;
|
||||||
|
use App\Domains\Event\Controllers\EventUnarchiveController;
|
||||||
use App\Domains\Event\Controllers\MailCompose\ByGroupController;
|
use App\Domains\Event\Controllers\MailCompose\ByGroupController;
|
||||||
use App\Domains\Event\Controllers\MailCompose\SendController;
|
use App\Domains\Event\Controllers\MailCompose\SendController;
|
||||||
use App\Domains\Event\Controllers\ParticipantController;
|
use App\Domains\Event\Controllers\ParticipantController;
|
||||||
@@ -26,6 +28,7 @@ Route::prefix('api/v1')
|
|||||||
Route::middleware(['auth'])->group(function () {
|
Route::middleware(['auth'])->group(function () {
|
||||||
Route::post('/create', [CreateController::class, 'doCreate']);
|
Route::post('/create', [CreateController::class, 'doCreate']);
|
||||||
|
|
||||||
|
|
||||||
Route::prefix('{eventIdentifier}/mailing')->group(function () {
|
Route::prefix('{eventIdentifier}/mailing')->group(function () {
|
||||||
Route::post('/compose/to-group/{groupType}', ByGroupController::class);
|
Route::post('/compose/to-group/{groupType}', ByGroupController::class);
|
||||||
Route::post('/send', SendController::class);
|
Route::post('/send', SendController::class);
|
||||||
@@ -37,8 +40,8 @@ Route::prefix('api/v1')
|
|||||||
Route::get('/summary', [DetailsController::class, 'summary']);
|
Route::get('/summary', [DetailsController::class, 'summary']);
|
||||||
|
|
||||||
Route::get('/participants/{listType}', [DetailsController::class, 'listParticipants']);
|
Route::get('/participants/{listType}', [DetailsController::class, 'listParticipants']);
|
||||||
|
Route::post('/unarchive', EventUnarchiveController::class);
|
||||||
|
Route::get('/archive', EventArchiveController::class);
|
||||||
Route::post('/event-managers', [DetailsController::class, 'updateEventManagers']);
|
Route::post('/event-managers', [DetailsController::class, 'updateEventManagers']);
|
||||||
Route::post('/participation-fees', [DetailsController::class, 'updateParticipationFees']);
|
Route::post('/participation-fees', [DetailsController::class, 'updateParticipationFees']);
|
||||||
Route::post('/common-settings', [DetailsController::class, 'updateCommonSettings']);
|
Route::post('/common-settings', [DetailsController::class, 'updateCommonSettings']);
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
use App\Domains\Event\Controllers\ArchivedEventsController;
|
||||||
use App\Domains\Event\Controllers\AvailableEventsController;
|
use App\Domains\Event\Controllers\AvailableEventsController;
|
||||||
use App\Domains\Event\Controllers\CreateController;
|
use App\Domains\Event\Controllers\CreateController;
|
||||||
use App\Domains\Event\Controllers\DetailsController;
|
use App\Domains\Event\Controllers\DetailsController;
|
||||||
@@ -24,5 +25,6 @@ Route::middleware(IdentifyTenant::class)->group(function () {
|
|||||||
|
|
||||||
Route::middleware(['auth'])->group(function () {
|
Route::middleware(['auth'])->group(function () {
|
||||||
Route::get('/create-event', CreateController::class);
|
Route::get('/create-event', CreateController::class);
|
||||||
|
Route::get('/archived-events', ArchivedEventsController::class);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -0,0 +1,76 @@
|
|||||||
|
<script setup>
|
||||||
|
import { ref } from 'vue';
|
||||||
|
import AppLayout from "../../../../resources/js/layouts/AppLayout.vue";
|
||||||
|
import ShadowedBox from "../../../Views/Components/ShadowedBox.vue";
|
||||||
|
import { toast } from 'vue3-toastify';
|
||||||
|
import axios from 'axios';
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
events: Array,
|
||||||
|
});
|
||||||
|
|
||||||
|
const events = ref([...props.events]);
|
||||||
|
|
||||||
|
async function unarchiveEvent(eventId) {
|
||||||
|
try {
|
||||||
|
const response = await axios.post(`/api/v1/event/details/${eventId}/unarchive`);
|
||||||
|
if (response.data.status === 'success') {
|
||||||
|
events.value = events.value.filter(e => e.id !== eventId);
|
||||||
|
toast.success('Veranstaltung wurde aus dem Archiv geholt.');
|
||||||
|
} else {
|
||||||
|
toast.error('Fehler beim Wiederherstellen der Veranstaltung.');
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
toast.error('Ein unerwarteter Fehler ist aufgetreten.');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<AppLayout title="Archivierte Veranstaltungen">
|
||||||
|
<div style="width: 95%; margin: 20px auto;">
|
||||||
|
<h1 style="font-size: 1.5rem; font-weight: 700; margin-bottom: 20px;">Archivierte Veranstaltungen</h1>
|
||||||
|
|
||||||
|
<div
|
||||||
|
v-if="events.length === 0"
|
||||||
|
style="text-align: center; color: #6b7280; padding: 40px 0;"
|
||||||
|
>
|
||||||
|
Es sind keine archivierten Veranstaltungen vorhanden.
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<ShadowedBox
|
||||||
|
v-for="event in events"
|
||||||
|
:key="event.id"
|
||||||
|
style="padding: 20px; margin-bottom: 16px;"
|
||||||
|
>
|
||||||
|
<div style="display: flex; justify-content: space-between; align-items: center; flex-wrap: wrap; gap: 12px;">
|
||||||
|
<div>
|
||||||
|
<h2 style="margin: 0 0 4px 0; font-size: 1.1rem; font-weight: 600;">{{ event.name }}</h2>
|
||||||
|
<span style="color: #6b7280; font-size: 0.875rem;">
|
||||||
|
{{ event.postalCode }} {{ event.location }}
|
||||||
|
·
|
||||||
|
{{ event.eventBegin }} – {{ event.eventEnd }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<button
|
||||||
|
@click="unarchiveEvent(event.id)"
|
||||||
|
style="
|
||||||
|
padding: 8px 20px;
|
||||||
|
background-color: #f59e0b;
|
||||||
|
color: white;
|
||||||
|
border: none;
|
||||||
|
border-radius: 8px;
|
||||||
|
font-weight: 600;
|
||||||
|
font-size: 0.9rem;
|
||||||
|
cursor: pointer;
|
||||||
|
white-space: nowrap;
|
||||||
|
"
|
||||||
|
>
|
||||||
|
Aus dem Archiv holen
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</ShadowedBox>
|
||||||
|
</div>
|
||||||
|
</AppLayout>
|
||||||
|
</template>
|
||||||
@@ -56,6 +56,16 @@
|
|||||||
mailCompose.value = true
|
mailCompose.value = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function archiveEvent() {
|
||||||
|
const response = await fetch("/api/v1/event/details/" + props.data.event.identifier + "/archive" );
|
||||||
|
const data = await response.json();
|
||||||
|
if (data.status === 'success') {
|
||||||
|
toast.success(data.message)
|
||||||
|
} else {
|
||||||
|
toast.error(data.message)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async function sendPaymentReminder() {
|
async function sendPaymentReminder() {
|
||||||
toast.info("Die Nachrichten werden gesendet. Bitte verlasse diese Seite nicht.");
|
toast.info("Die Nachrichten werden gesendet. Bitte verlasse diese Seite nicht.");
|
||||||
const response = await fetch("/api/v1/event/" + props.data.event.identifier + "/send-payment-reminder/" );
|
const response = await fetch("/api/v1/event/" + props.data.event.identifier + "/send-payment-reminder/" );
|
||||||
@@ -150,6 +160,7 @@
|
|||||||
<label style="font-size: 9pt;" class="link" @click="showEventManagement">Veranstaltungsleitung</label>
|
<label style="font-size: 9pt;" class="link" @click="showEventManagement">Veranstaltungsleitung</label>
|
||||||
<label style="font-size: 9pt;" class="link" @click="showParticipationFees">Teilnahmegebühren</label>
|
<label style="font-size: 9pt;" class="link" @click="showParticipationFees">Teilnahmegebühren</label>
|
||||||
<a style="font-size: 9pt;" class="link" :href="'/cost-unit/' + props.data.event.costUnit.id">Ausgabenübersicht</a>
|
<a style="font-size: 9pt;" class="link" :href="'/cost-unit/' + props.data.event.costUnit.id">Ausgabenübersicht</a>
|
||||||
|
<a v-if="!dynamicProps.event.registrationAllowed && !dynamicProps.event.archived" style="color: #ff0000; font-size: 9pt;" class="link" @click="archiveEvent">Archivieren</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -42,6 +42,7 @@ class CreateInvoiceCommand {
|
|||||||
'travel_reason' => $this->request->travelReason,
|
'travel_reason' => $this->request->travelReason,
|
||||||
'passengers' => $this->request->passengers,
|
'passengers' => $this->request->passengers,
|
||||||
'transportation' => $this->request->transportations,
|
'transportation' => $this->request->transportations,
|
||||||
|
'payment_purpose' => $this->request->paymentPurpose,
|
||||||
'document_filename' => $this->request->receiptFile !== null ? $this->request->receiptFile->fullPath : null,
|
'document_filename' => $this->request->receiptFile !== null ? $this->request->receiptFile->fullPath : null,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ class CreateInvoiceRequest {
|
|||||||
public bool $isDonation;
|
public bool $isDonation;
|
||||||
public ?int $userId;
|
public ?int $userId;
|
||||||
public ?string $travelReason;
|
public ?string $travelReason;
|
||||||
|
public ?string $paymentPurpose;
|
||||||
|
|
||||||
|
|
||||||
public function __construct(
|
public function __construct(
|
||||||
@@ -43,6 +44,7 @@ class CreateInvoiceRequest {
|
|||||||
?int $passengers = null,
|
?int $passengers = null,
|
||||||
?int $transportations,
|
?int $transportations,
|
||||||
?string $travelReason = null,
|
?string $travelReason = null,
|
||||||
|
?string $paymentPurpose = null,
|
||||||
|
|
||||||
) {
|
) {
|
||||||
$this->costUnit = $costUnit;
|
$this->costUnit = $costUnit;
|
||||||
@@ -62,6 +64,7 @@ class CreateInvoiceRequest {
|
|||||||
$this->isDonation = $isDonation;
|
$this->isDonation = $isDonation;
|
||||||
$this->userId = $userId;
|
$this->userId = $userId;
|
||||||
$this->travelReason = $travelReason;
|
$this->travelReason = $travelReason;
|
||||||
|
$this->paymentPurpose = $paymentPurpose;
|
||||||
|
|
||||||
if ($accountIban === 'undefined') {
|
if ($accountIban === 'undefined') {
|
||||||
$this->accountIban = null;
|
$this->accountIban = null;
|
||||||
|
|||||||
@@ -34,102 +34,4 @@ class NewInvoiceController extends CommonController {
|
|||||||
]);
|
]);
|
||||||
return $inertiaProvider->render();
|
return $inertiaProvider->render();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function saveInvoice(Request $request, int $costUnitId, string $invoiceType) : JsonResponse {
|
|
||||||
$costUnit = $this->costUnits->getById($costUnitId, true);
|
|
||||||
if (null === $costUnit) {
|
|
||||||
return response()->json([
|
|
||||||
'status' => 'error',
|
|
||||||
'message' => 'Beim Speichern ist ein Fehler aufgetreten. Bitte starte den Vorgang erneut.'
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
$uploadedFile = null;
|
|
||||||
if (null !== $request->file('receipt')) {
|
|
||||||
$validation = sprintf('%1$s|%2$s|max:%3$s',
|
|
||||||
'required',
|
|
||||||
'mimes:pdf',
|
|
||||||
env('MAX_INVOICE_FILE_SIZE', 16)*10
|
|
||||||
);
|
|
||||||
|
|
||||||
$request->validate([
|
|
||||||
'receipt' => $validation
|
|
||||||
]);
|
|
||||||
|
|
||||||
$uploadFileProvider = new UploadFileProvider($request->file('receipt'), $costUnit);
|
|
||||||
$uploadedFile = $uploadFileProvider->saveUploadedFile();
|
|
||||||
}
|
|
||||||
|
|
||||||
switch ($invoiceType) {
|
|
||||||
case InvoiceType::INVOICE_TYPE_TRAVELLING:
|
|
||||||
|
|
||||||
if ($uploadedFile !== null) {
|
|
||||||
$amount = Amount::fromString($request->input('amount'))->getAmount();
|
|
||||||
$distance = null;
|
|
||||||
} else {
|
|
||||||
$distance = Amount::fromString($request->input('amount'))->getRoundedAmount();
|
|
||||||
$amount = $distance * $costUnit->distance_allowance;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
$createInvoiceRequest = new CreateInvoiceRequest(
|
|
||||||
$costUnit,
|
|
||||||
$request->input('name'),
|
|
||||||
InvoiceType::INVOICE_TYPE_TRAVELLING,
|
|
||||||
$amount,
|
|
||||||
$uploadedFile,
|
|
||||||
'donation' === $request->input('decision') ? true : false,
|
|
||||||
$this->users->getCurrentUserDetails()['userId'],
|
|
||||||
$request->input('email'),
|
|
||||||
$request->input('telephone'),
|
|
||||||
$request->input('accountOwner'),
|
|
||||||
$request->input('accountIban'),
|
|
||||||
null,
|
|
||||||
$request->input('otherText'),
|
|
||||||
$distance,
|
|
||||||
$request->input('havePassengers'),
|
|
||||||
$request->input('materialTransportation'),
|
|
||||||
$request->input('travelReason'),
|
|
||||||
);
|
|
||||||
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
$createInvoiceRequest = new CreateInvoiceRequest(
|
|
||||||
$costUnit,
|
|
||||||
$request->input('name'),
|
|
||||||
$invoiceType,
|
|
||||||
Amount::fromString($request->input('amount'))->getAmount(),
|
|
||||||
$uploadedFile,
|
|
||||||
'donation' === $request->input('decision') ? true : false,
|
|
||||||
$this->users->getCurrentUserDetails()['userId'],
|
|
||||||
$request->input('email'),
|
|
||||||
$request->input('telephone'),
|
|
||||||
$request->input('accountOwner'),
|
|
||||||
$request->input('accountIban'),
|
|
||||||
$request->input('otherText'),
|
|
||||||
null,
|
|
||||||
null,
|
|
||||||
$request->input('havePassengers'),
|
|
||||||
$request->input('materialTransportation'),
|
|
||||||
null
|
|
||||||
);
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
$command = new CreateInvoiceCommand($createInvoiceRequest);
|
|
||||||
$response = $command->execute();
|
|
||||||
if ($response->success) {
|
|
||||||
new FlashMessageProvider(
|
|
||||||
'Die Abrechnung wurde erfolgreich angelegt.' . PHP_EOL . PHP_EOL . 'Sollten wir Rückfragen haben, melden wir uns bei dir',
|
|
||||||
'success'
|
|
||||||
);
|
|
||||||
|
|
||||||
return response()->json([
|
|
||||||
'status' => 'success',
|
|
||||||
'message' => 'Alright'
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,128 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Domains\Invoice\Controllers;
|
||||||
|
|
||||||
|
use App\Domains\Invoice\Actions\CreateInvoice\CreateInvoiceCommand;
|
||||||
|
use App\Domains\Invoice\Actions\CreateInvoice\CreateInvoiceRequest;
|
||||||
|
use App\Enumerations\InvoiceType;
|
||||||
|
use App\Providers\FlashMessageProvider;
|
||||||
|
use App\Providers\UploadFileProvider;
|
||||||
|
use App\Scopes\CommonController;
|
||||||
|
use App\ValueObjects\Amount;
|
||||||
|
use Illuminate\Http\JsonResponse;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use Illuminate\Support\Facades\Validator;
|
||||||
|
|
||||||
|
class SaveInvoiceController extends CommonController
|
||||||
|
{
|
||||||
|
public function __invoke(Request $request, int $costUnitId, string $invoiceType) : JsonResponse {
|
||||||
|
$costUnit = $this->costUnits->getById($costUnitId, true);
|
||||||
|
$paymentPurpose = $request->input('paymentPurpose') ?? null;
|
||||||
|
if (null === $costUnit) {
|
||||||
|
return response()->json([
|
||||||
|
'status' => 'error',
|
||||||
|
'message' => 'Beim Speichern ist ein Fehler aufgetreten. Bitte starte den Vorgang erneut.'
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
$uploadedFile = null;
|
||||||
|
if (null !== $request->file('receipt')) {
|
||||||
|
$maxFileSize = env('MAX_INVOICE_FILE_SIZE', 16);
|
||||||
|
$validation = sprintf('%1$s|%2$s|max:%3$s',
|
||||||
|
'required',
|
||||||
|
'mimes:pdf',
|
||||||
|
$maxFileSize * 1024
|
||||||
|
);
|
||||||
|
|
||||||
|
$validator = Validator::make($request->all(), [
|
||||||
|
'receipt' => $validation
|
||||||
|
]);
|
||||||
|
|
||||||
|
if ($validator->fails()) {
|
||||||
|
return response()->json([
|
||||||
|
'status' => 'error',
|
||||||
|
'message' => sprintf(
|
||||||
|
'Der Beleg konnte nicht hochgeladen werden. Bitte beachte die Maximale Dateigröße von %1$s MB sowie die Tatsache, dass ausschließlich PDF-Dateien akzeptiert werden.',
|
||||||
|
$maxFileSize
|
||||||
|
)
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
$uploadFileProvider = new UploadFileProvider($request->file('receipt'), $costUnit);
|
||||||
|
$uploadedFile = $uploadFileProvider->saveUploadedFile();
|
||||||
|
}
|
||||||
|
|
||||||
|
switch ($invoiceType) {
|
||||||
|
case InvoiceType::INVOICE_TYPE_TRAVELLING:
|
||||||
|
|
||||||
|
if ($uploadedFile !== null) {
|
||||||
|
$amount = Amount::fromString($request->input('amount'))->getAmount();
|
||||||
|
$distance = null;
|
||||||
|
} else {
|
||||||
|
$distance = Amount::fromString($request->input('amount'))->getRoundedAmount();
|
||||||
|
$amount = $distance * $costUnit->distance_allowance;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
$createInvoiceRequest = new CreateInvoiceRequest(
|
||||||
|
$costUnit,
|
||||||
|
$request->input('name'),
|
||||||
|
InvoiceType::INVOICE_TYPE_TRAVELLING,
|
||||||
|
$amount,
|
||||||
|
$uploadedFile,
|
||||||
|
'donation' === $request->input('decision') ? true : false,
|
||||||
|
$this->users->getCurrentUserDetails()['userId'],
|
||||||
|
$request->input('email'),
|
||||||
|
$request->input('telephone'),
|
||||||
|
$request->input('accountOwner'),
|
||||||
|
$request->input('accountIban'),
|
||||||
|
null,
|
||||||
|
$request->input('otherText'),
|
||||||
|
$distance,
|
||||||
|
$request->input('havePassengers'),
|
||||||
|
$request->input('materialTransportation'),
|
||||||
|
$request->input('travelReason'),
|
||||||
|
);
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
$createInvoiceRequest = new CreateInvoiceRequest(
|
||||||
|
$costUnit,
|
||||||
|
$request->input('name'),
|
||||||
|
$invoiceType,
|
||||||
|
Amount::fromString($request->input('amount'))->getAmount(),
|
||||||
|
$uploadedFile,
|
||||||
|
'donation' === $request->input('decision') ? true : false,
|
||||||
|
$this->users->getCurrentUserDetails()['userId'],
|
||||||
|
$request->input('email'),
|
||||||
|
$request->input('telephone'),
|
||||||
|
$request->input('accountOwner'),
|
||||||
|
$request->input('accountIban'),
|
||||||
|
$request->input('otherText'),
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
$request->input('havePassengers'),
|
||||||
|
$request->input('materialTransportation'),
|
||||||
|
null,
|
||||||
|
$paymentPurpose,
|
||||||
|
);
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
$command = new CreateInvoiceCommand($createInvoiceRequest);
|
||||||
|
$response = $command->execute();
|
||||||
|
if ($response->success) {
|
||||||
|
new FlashMessageProvider(
|
||||||
|
'Die Abrechnung wurde erfolgreich angelegt.' . PHP_EOL . PHP_EOL . 'Sollten wir Rückfragen haben, melden wir uns bei dir',
|
||||||
|
'success'
|
||||||
|
);
|
||||||
|
|
||||||
|
return response()->json([
|
||||||
|
'status' => 'success',
|
||||||
|
'message' => 'Alright'
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -6,13 +6,14 @@ use App\Domains\Invoice\Controllers\ChangeStateController;
|
|||||||
use App\Domains\Invoice\Controllers\EditController;
|
use App\Domains\Invoice\Controllers\EditController;
|
||||||
use App\Domains\Invoice\Controllers\ListMyInvoicesController;
|
use App\Domains\Invoice\Controllers\ListMyInvoicesController;
|
||||||
use App\Domains\Invoice\Controllers\NewInvoiceController;
|
use App\Domains\Invoice\Controllers\NewInvoiceController;
|
||||||
|
use App\Domains\Invoice\Controllers\SaveInvoiceController;
|
||||||
use App\Domains\Invoice\Controllers\ShowInvoiceController;
|
use App\Domains\Invoice\Controllers\ShowInvoiceController;
|
||||||
use App\Middleware\IdentifyTenant;
|
use App\Middleware\IdentifyTenant;
|
||||||
use Illuminate\Support\Facades\Route;
|
use Illuminate\Support\Facades\Route;
|
||||||
|
|
||||||
Route::middleware(IdentifyTenant::class)->group(function () {
|
Route::middleware(IdentifyTenant::class)->group(function () {
|
||||||
Route::prefix('api/v1/invoice')->group(function () {
|
Route::prefix('api/v1/invoice')->group(function () {
|
||||||
Route::post('/new/{costUnitId}/{invoiceType}', [NewInvoiceController::class, 'saveInvoice']);
|
Route::post('/new/{costUnitId}/{invoiceType}', SaveInvoiceController::class);
|
||||||
Route::middleware(['auth'])->group(function () {
|
Route::middleware(['auth'])->group(function () {
|
||||||
Route::get('/details/{invoiceId}', ShowInvoiceController::class);
|
Route::get('/details/{invoiceId}', ShowInvoiceController::class);
|
||||||
Route::get('/showReceipt/{invoiceId}', [ShowInvoiceController::class, 'showReceipt']);
|
Route::get('/showReceipt/{invoiceId}', [ShowInvoiceController::class, 'showReceipt']);
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import Modal from "../../../Views/Components/Modal.vue";
|
|||||||
import {onMounted, reactive, ref} from "vue";
|
import {onMounted, reactive, ref} from "vue";
|
||||||
import ExpenseAccounting from "./Partials/newInvoice/expense-accounting.vue";
|
import ExpenseAccounting from "./Partials/newInvoice/expense-accounting.vue";
|
||||||
import TravelExpenseAccounting from "./Partials/newInvoice/travel-expense-accounting.vue";
|
import TravelExpenseAccounting from "./Partials/newInvoice/travel-expense-accounting.vue";
|
||||||
|
import DirectPayment from "./Partials/newInvoice/direct-payment.vue";
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
currentEvents: Object,
|
currentEvents: Object,
|
||||||
@@ -42,6 +43,24 @@ const invoiceType = ref('');
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div
|
||||||
|
v-if="eventId === 0"
|
||||||
|
class="invoice-type-layer" style="width: calc(100% - 60px); margin: auto"
|
||||||
|
@click="isOpen = true;invoiceType='direct-payment'"
|
||||||
|
>
|
||||||
|
<TextResource textName="NEW_DIRECT_PAYMENT" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<DirectPayment v-if="invoiceType === 'direct-payment' && eventId !== 0"
|
||||||
|
:eventId="eventId"
|
||||||
|
:userName="props.userName"
|
||||||
|
:userEmail="props.userEmail"
|
||||||
|
:userTelephone="props.userTelephone"
|
||||||
|
:userAccountIban="props.userAccountIban"
|
||||||
|
:userAccountOwner="props.userAccountOwner"
|
||||||
|
:userId="props.userId"
|
||||||
|
/>
|
||||||
|
|
||||||
<ExpenseAccounting v-if="invoiceType === 'expense-accounting' && eventId !== 0"
|
<ExpenseAccounting v-if="invoiceType === 'expense-accounting' && eventId !== 0"
|
||||||
:eventId="eventId"
|
:eventId="eventId"
|
||||||
:userName="props.userName"
|
:userName="props.userName"
|
||||||
@@ -62,7 +81,7 @@ const invoiceType = ref('');
|
|||||||
:userId="props.userId"
|
:userId="props.userId"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<Modal :show="isOpen" title="Veranstaltung auswählen" @close="isOpen = false">
|
<Modal :show="isOpen" title="Veranstaltung auswählen" @close="isOpen = false" width="450px">
|
||||||
<select v-model="eventId" @change="isOpen=false" style="width: 100%">
|
<select v-model="eventId" @change="isOpen=false" style="width: 100%">
|
||||||
<option value="0" disabled>Bitte auswählen</option>
|
<option value="0" disabled>Bitte auswählen</option>
|
||||||
<optgroup label="Laufende Tätigkeiten">
|
<optgroup label="Laufende Tätigkeiten">
|
||||||
|
|||||||
@@ -97,7 +97,7 @@ const emit = defineEmits(["accept", "deny", "fix", "reopen"])
|
|||||||
<td>{{props.data.accountIban}}</td>
|
<td>{{props.data.accountIban}}</td>
|
||||||
<td>Buchungsinformationen:</td>
|
<td>Buchungsinformationen:</td>
|
||||||
<td v-if="props.data.donation">Als Spende gebucht</td>
|
<td v-if="props.data.donation">Als Spende gebucht</td>
|
||||||
<td v-else-if="props.data.alreadyPaid">Beleg ohne Auszahlung</td>
|
<td v-else-if="props.data.externalPayment">Rechnungszahlung</td>
|
||||||
<td v-else>Klassische Auszahlung</td>
|
<td v-else>Klassische Auszahlung</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
|
|||||||
@@ -81,7 +81,7 @@ const emit = defineEmits(["accept", "deny", "fix", "reopen"])
|
|||||||
<td>{{props.data.accountIban}}</td>
|
<td>{{props.data.accountIban}}</td>
|
||||||
<td>Buchungsinformationen:</td>
|
<td>Buchungsinformationen:</td>
|
||||||
<td v-if="props.data.donation">Als Spende gebucht</td>
|
<td v-if="props.data.donation">Als Spende gebucht</td>
|
||||||
<td v-else-if="props.data.alreadyPaid">Beleg ohne Auszahlung</td>
|
<td v-else-if="props.data.externalPayment">Rechnungszahlung</td>
|
||||||
<td v-else>Klassische Auszahlung</td>
|
<td v-else>Klassische Auszahlung</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
|
|||||||
@@ -56,7 +56,7 @@
|
|||||||
</td>
|
</td>
|
||||||
<td style="width: 150px;">
|
<td style="width: 150px;">
|
||||||
<Icon v-if="invoice.donation" name="hand-holding-dollar" style="color: #ffffff; background-color: green" />
|
<Icon v-if="invoice.donation" name="hand-holding-dollar" style="color: #ffffff; background-color: green" />
|
||||||
<Icon v-if="invoice.alreadyPaid" name="comments-dollar" style="color: #ffffff; background-color: green" />
|
<Icon v-if="invoice.externalPayment" name="comments-dollar" style="color: #ffffff; background-color: green" />
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
{{invoice.contactName}}<br />
|
{{invoice.contactName}}<br />
|
||||||
|
|||||||
@@ -0,0 +1,126 @@
|
|||||||
|
<script setup>
|
||||||
|
|
||||||
|
import { ref, onMounted, reactive } from 'vue'
|
||||||
|
import {checkFilesize} from "../../../../../../resources/js/components/InvoiceUploadChecks.js";
|
||||||
|
import RefundData from "./refund-data.vue";
|
||||||
|
import AmountInput from "../../../../../Views/Components/AmountInput.vue";
|
||||||
|
import {useAjax} from "../../../../../../resources/js/components/ajaxHandler.js";
|
||||||
|
import InfoIcon from '../../../../../Views/Components/InfoIcon.vue'
|
||||||
|
import {toast} from "vue3-toastify";
|
||||||
|
import PaymentData from "./payment-data.vue";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
const data = defineProps({
|
||||||
|
eventId: Number,
|
||||||
|
userName: String,
|
||||||
|
userEmail: String,
|
||||||
|
userTelephone: String,
|
||||||
|
userAccountIban: String,
|
||||||
|
userAccountOwner: String,
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
const { request } = useAjax();
|
||||||
|
const amount = ref(0.00);
|
||||||
|
const invoiceType = ref(null);
|
||||||
|
const otherText = ref('');
|
||||||
|
const receipt = ref(null)
|
||||||
|
const finalStep = ref(false)
|
||||||
|
|
||||||
|
const invoiceTypeCollection = reactive({
|
||||||
|
invoiceTypes: {}
|
||||||
|
});
|
||||||
|
|
||||||
|
onMounted(async () => {
|
||||||
|
const response = await fetch('/api/v1/core/retrieve-invoice-types');
|
||||||
|
const data = await response.json();
|
||||||
|
Object.assign(invoiceTypeCollection, data);
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
function handleFileChange(event) {
|
||||||
|
if (checkFilesize('receipt')) {
|
||||||
|
receipt.value = event.target.files[0]
|
||||||
|
finalStep.value = true
|
||||||
|
} else {
|
||||||
|
event.target.value = null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<fieldset>
|
||||||
|
<legend><span style="font-weight: bolder;">Was ist der Anlass der Rechnung</span></legend>
|
||||||
|
|
||||||
|
<p v-for="availableInvoiceType in invoiceTypeCollection.invoiceTypes">
|
||||||
|
<input
|
||||||
|
name="invpice_type"
|
||||||
|
type="radio"
|
||||||
|
:value="availableInvoiceType.slug"
|
||||||
|
:id="'invoice_type_' + availableInvoiceType.slug"
|
||||||
|
v-model="invoiceType"
|
||||||
|
>
|
||||||
|
<label :for="'invoice_type_' + availableInvoiceType.slug">{{ availableInvoiceType.name }}</label>
|
||||||
|
<InfoIcon :text="'INFO_INVOICE_TYPE_' + availableInvoiceType.slug" /><br />
|
||||||
|
</p>
|
||||||
|
|
||||||
|
|
||||||
|
<label for="invoice_type_other">
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
class="width-full"
|
||||||
|
name="kostengruppe_sonstiges"
|
||||||
|
placeholder="Sonstige"
|
||||||
|
for="invoice_type_other"
|
||||||
|
v-model="otherText"
|
||||||
|
@focus="invoiceType = 'other'"
|
||||||
|
/>
|
||||||
|
</label>
|
||||||
|
|
||||||
|
</fieldset><br /><br />
|
||||||
|
|
||||||
|
<fieldset>
|
||||||
|
<legend><span style="font-weight: bolder;">Wie hoch ist der Betrag</span></legend>
|
||||||
|
<AmountInput v-model="amount" class="width-small" id="amount" name="amount" /> Euro
|
||||||
|
<info-icon></info-icon><br /><br />
|
||||||
|
|
||||||
|
<input
|
||||||
|
v-if="amount != '' && invoiceType !== null"
|
||||||
|
class="mareike-button"
|
||||||
|
onclick="document.getElementById('receipt').click();"
|
||||||
|
type="button"
|
||||||
|
value="Beleg auswählen und fortfahren" />
|
||||||
|
<input accept="application/pdf" type="file" id="receipt" name="receipt" @change="handleFileChange"
|
||||||
|
style="display: none"/>
|
||||||
|
</fieldset><br />
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<PaymentData
|
||||||
|
v-if="finalStep"
|
||||||
|
:eventId="data.eventId"
|
||||||
|
:invoice-type="invoiceType"
|
||||||
|
:amount="amount"
|
||||||
|
:other-text="otherText"
|
||||||
|
:userName="data.userName"
|
||||||
|
:userEmail="data.userEmail"
|
||||||
|
:userTelephone="data.userTelephone"
|
||||||
|
:userAccountIban="data.userAccountIban"
|
||||||
|
:userAccountOwner="data.userAccountOwner"
|
||||||
|
:receipt="receipt"
|
||||||
|
travelReason=""
|
||||||
|
@close="finalStep = false"
|
||||||
|
/>
|
||||||
|
|
||||||
|
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
|
||||||
|
</style>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,161 @@
|
|||||||
|
<script setup>
|
||||||
|
import { ref } from 'vue'
|
||||||
|
import Modal from "../../../../../Views/Components/Modal.vue";
|
||||||
|
import IbanInput from "../../../../../Views/Components/IbanInput.vue";
|
||||||
|
import {useAjax} from "../../../../../../resources/js/components/ajaxHandler.js";
|
||||||
|
import TextResource from "../../../../../Views/Components/TextResource.vue";
|
||||||
|
import {invoiceCheckContactName} from "../../../../../../resources/js/components/InvoiceUploadChecks.js";
|
||||||
|
import {toast} from "vue3-toastify";
|
||||||
|
import ErrorText from "../../../../../Views/Components/ErrorText.vue";
|
||||||
|
|
||||||
|
const { request } = useAjax();
|
||||||
|
|
||||||
|
const emit = defineEmits(['close'])
|
||||||
|
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
eventId: Number,
|
||||||
|
invoiceType: String,
|
||||||
|
amount: [String, Number],
|
||||||
|
otherText: String,
|
||||||
|
receipt: File,
|
||||||
|
userName: String,
|
||||||
|
userEmail: String,
|
||||||
|
userTelephone: String,
|
||||||
|
userAccountOwner: String,
|
||||||
|
userAccountIban: String,
|
||||||
|
havePassengers: Number,
|
||||||
|
materialTransportation: Boolean,
|
||||||
|
travelReason: String,
|
||||||
|
})
|
||||||
|
|
||||||
|
const finalStep = ref(true)
|
||||||
|
const userName = ref(props.userName)
|
||||||
|
const userEmail = ref(props.userEmail)
|
||||||
|
const userTelephone = ref(props.userTelephone)
|
||||||
|
const userIban = ref('')
|
||||||
|
const userAccountOwner = ref('')
|
||||||
|
const paymentPurpose = ref('')
|
||||||
|
const sending = ref(false)
|
||||||
|
const success = ref(false)
|
||||||
|
const decision = ref('')
|
||||||
|
const errorMsg = ref('')
|
||||||
|
const confirmation = ref(null)
|
||||||
|
const receiptError = ref('')
|
||||||
|
|
||||||
|
async function sendData() {
|
||||||
|
if (!userName.value) return
|
||||||
|
|
||||||
|
sending.value = true
|
||||||
|
errorMsg.value = ''
|
||||||
|
success.value = false
|
||||||
|
|
||||||
|
const formData = new FormData()
|
||||||
|
|
||||||
|
formData.append('name', userName.value)
|
||||||
|
formData.append('email', userEmail.value)
|
||||||
|
formData.append('telephone', userTelephone.value)
|
||||||
|
formData.append('amount', props.amount)
|
||||||
|
formData.append('otherText', props.otherText)
|
||||||
|
formData.append('decision', decision.value)
|
||||||
|
formData.append('accountOwner', userAccountOwner.value)
|
||||||
|
formData.append('accountIban', userIban.value)
|
||||||
|
formData.append('paymentPurpose', paymentPurpose.value)
|
||||||
|
formData.append('havePassengers', props.havePassengers ? 1 : 0)
|
||||||
|
formData.append('materialTransportation', props.materialTransportation ? 1 : 0)
|
||||||
|
formData.append('travelReason', props.travelReason)
|
||||||
|
|
||||||
|
if (props.receipt) {
|
||||||
|
formData.append('receipt', props.receipt)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response = await request('/api/v1/invoice/new/' + props.eventId + '/' + props.invoiceType, {
|
||||||
|
method: 'POST',
|
||||||
|
body: formData
|
||||||
|
})
|
||||||
|
|
||||||
|
if (response.status === 'success') {
|
||||||
|
window.location.href = '/';
|
||||||
|
} else {
|
||||||
|
receiptError.value = response.message;
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
toast.error(result.message);
|
||||||
|
} finally {
|
||||||
|
sending.value = false
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<Modal :show="finalStep" title='Bitte gib deine Daten ein' @close="emit('close')" width="600px">
|
||||||
|
<label>
|
||||||
|
<strong>Dein Name Name (kein Pfadiname):</strong>
|
||||||
|
</label><br />
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
@keyup="invoiceCheckContactName();"
|
||||||
|
id="contact_name"
|
||||||
|
name="contact_name" v-model="userName"
|
||||||
|
style="font-size: 14pt; width: 550px;" /><br /><br />
|
||||||
|
|
||||||
|
<label v-if="userName !== ''">
|
||||||
|
<strong>E-Mail-Adresse (Für Rückfragen):</strong>
|
||||||
|
</label><br />
|
||||||
|
<input
|
||||||
|
v-if="userName !== ''"
|
||||||
|
type="email"
|
||||||
|
name="contact_email"
|
||||||
|
v-model="userEmail"
|
||||||
|
style="font-size: 14pt; width: 550px;" /><br /><br />
|
||||||
|
|
||||||
|
<label v-if="userName !== ''">
|
||||||
|
<strong>Telefonnummer (für Rückfragen):</strong>
|
||||||
|
</label><br />
|
||||||
|
<input
|
||||||
|
v-if="userName !== ''"
|
||||||
|
type="text"
|
||||||
|
id="contact_telephone"
|
||||||
|
name="contact_telephone" v-model="userTelephone"
|
||||||
|
style="font-size: 14pt; width: 550px;" /><br /><br />
|
||||||
|
|
||||||
|
<span id="confirm_payment" v-if="userEmail !== '' && userTelephone !== ''">
|
||||||
|
<label>
|
||||||
|
<strong>Zahlungsempfänger*in:</strong>
|
||||||
|
</label><br />
|
||||||
|
<input type="text" name="account_owner" id="account_owner" v-model="userAccountOwner" style="font-size: 14pt; width: 550px;" /><br /><br />
|
||||||
|
|
||||||
|
<label>
|
||||||
|
<strong>IBAN:</strong>
|
||||||
|
</label><br />
|
||||||
|
<IbanInput id="account_iban" name="account_iban" v-model="userIban" style="font-size: 14pt; width: 550px;" /><br /><br />
|
||||||
|
|
||||||
|
<label>
|
||||||
|
<strong>Überweisungstext (laut Rechnung):</strong>
|
||||||
|
</label><br />
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
id="payment_purpose"
|
||||||
|
name="payment_purpose"
|
||||||
|
v-model="paymentPurpose"
|
||||||
|
style="font-size: 14pt; width: 550px;"
|
||||||
|
/><br /><br />
|
||||||
|
<ErrorText :message="receiptError" />
|
||||||
|
|
||||||
|
<span v-if="paymentPurpose != '' && userAccountOwner != '' && userIban && userIban.length === 27"><br />
|
||||||
|
<input type="radio" name="confirmation_radio" value="payment" id="confirmation_radio_payment" v-model="confirmation">
|
||||||
|
<TextResource belongsTo="confirmation_radio_payment" textName="CONFIRMATION_DIRECT_PAYMENT" /><br /><br />
|
||||||
|
<input type="button" v-if="confirmation !== null && !sending" @click="sendData" value="Beleg einreichen" />
|
||||||
|
</span>
|
||||||
|
</span>
|
||||||
|
</Modal>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
/* optional styling */
|
||||||
|
</style>
|
||||||
|
|
||||||
@@ -6,6 +6,7 @@ import {useAjax} from "../../../../../../resources/js/components/ajaxHandler.js"
|
|||||||
import TextResource from "../../../../../Views/Components/TextResource.vue";
|
import TextResource from "../../../../../Views/Components/TextResource.vue";
|
||||||
import {invoiceCheckContactName} from "../../../../../../resources/js/components/InvoiceUploadChecks.js";
|
import {invoiceCheckContactName} from "../../../../../../resources/js/components/InvoiceUploadChecks.js";
|
||||||
import {toast} from "vue3-toastify";
|
import {toast} from "vue3-toastify";
|
||||||
|
import ErrorText from "../../../../../Views/Components/ErrorText.vue";
|
||||||
|
|
||||||
const { request } = useAjax();
|
const { request } = useAjax();
|
||||||
|
|
||||||
@@ -39,7 +40,7 @@ const success = ref(false)
|
|||||||
const decision = ref('')
|
const decision = ref('')
|
||||||
const errorMsg = ref('')
|
const errorMsg = ref('')
|
||||||
const confirmation = ref(null)
|
const confirmation = ref(null)
|
||||||
|
const receiptError = ref('')
|
||||||
|
|
||||||
async function sendData() {
|
async function sendData() {
|
||||||
if (!userName.value) return
|
if (!userName.value) return
|
||||||
@@ -75,6 +76,8 @@ async function sendData() {
|
|||||||
|
|
||||||
if (response.status === 'success') {
|
if (response.status === 'success') {
|
||||||
window.location.href = '/';
|
window.location.href = '/';
|
||||||
|
} else {
|
||||||
|
receiptError.value = response.message;
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
toast.error(result.message);
|
toast.error(result.message);
|
||||||
@@ -87,7 +90,7 @@ async function sendData() {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<Modal :show="finalStep" title='Bitte gib deine Daten ein' @close="emit('close')">
|
<Modal :show="finalStep" title='Bitte gib deine Daten ein' @close="emit('close')" width="600px">
|
||||||
<label>
|
<label>
|
||||||
<strong>Dein Name Name (kein Pfadiname):</strong>
|
<strong>Dein Name Name (kein Pfadiname):</strong>
|
||||||
</label><br />
|
</label><br />
|
||||||
@@ -143,7 +146,7 @@ async function sendData() {
|
|||||||
<strong>IBAN:</strong>
|
<strong>IBAN:</strong>
|
||||||
</label><br />
|
</label><br />
|
||||||
<IbanInput id="account_iban" name="account_iban" v-model="userIban" style="font-size: 14pt; width: 550px;" /><br /><br />
|
<IbanInput id="account_iban" name="account_iban" v-model="userIban" style="font-size: 14pt; width: 550px;" /><br /><br />
|
||||||
|
<ErrorText :message="receiptError" />
|
||||||
<span v-if="userAccountOwner != '' && userIban && userIban.length === 27"><br />
|
<span v-if="userAccountOwner != '' && userIban && userIban.length === 27"><br />
|
||||||
<input type="radio" name="confirmation_radio" value="payment" id="confirmation_radio_payment" v-model="confirmation">
|
<input type="radio" name="confirmation_radio" value="payment" id="confirmation_radio_payment" v-model="confirmation">
|
||||||
<TextResource belongsTo="confirmation_radio_payment" textName="CONFIRMATION_PAYMENT" /><br /><br />
|
<TextResource belongsTo="confirmation_radio_payment" textName="CONFIRMATION_PAYMENT" /><br /><br />
|
||||||
|
|||||||
@@ -15,6 +15,11 @@ class InvoiceType extends CommonModel {
|
|||||||
|
|
||||||
public const INVOICE_TYPE_CATERING = 'catering';
|
public const INVOICE_TYPE_CATERING = 'catering';
|
||||||
|
|
||||||
|
public const INVOICE_TYPE_LOGSTIC = 'logistic';
|
||||||
|
|
||||||
|
public const INVOICE_TYPE_TECHNICAL = 'technical';
|
||||||
|
|
||||||
|
public const INVOICE_TYPE_MANAGEMENT = 'management';
|
||||||
|
|
||||||
protected $fillable = [
|
protected $fillable = [
|
||||||
'slug',
|
'slug',
|
||||||
|
|||||||
@@ -52,6 +52,7 @@ class Invoice extends InstancedModel
|
|||||||
'contact_phone',
|
'contact_phone',
|
||||||
'contact_bank_owner',
|
'contact_bank_owner',
|
||||||
'contact_bank_iban',
|
'contact_bank_iban',
|
||||||
|
'payment_purpose',
|
||||||
'amount',
|
'amount',
|
||||||
'donation',
|
'donation',
|
||||||
'distance',
|
'distance',
|
||||||
|
|||||||
@@ -25,12 +25,13 @@ class GlobalDataProvider {
|
|||||||
'navbar' => $this->generateNavbar(),
|
'navbar' => $this->generateNavbar(),
|
||||||
'tenant' => app('tenant'),
|
'tenant' => app('tenant'),
|
||||||
'activeUsers' => $this->getActiveUsers(),
|
'activeUsers' => $this->getActiveUsers(),
|
||||||
|
'version' => config('app.version'),
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getAllInvoiceTypes() : JsonResponse {
|
public function getAllInvoiceTypes() : JsonResponse {
|
||||||
$invoiceTypes = [];
|
$invoiceTypes = [];
|
||||||
foreach (InvoiceType::all() as $invoiceType) {
|
foreach (InvoiceType::orderBy('sort_order')->get() as $invoiceType) {
|
||||||
if (
|
if (
|
||||||
$invoiceType->slug === InvoiceType::INVOICE_TYPE_OTHER
|
$invoiceType->slug === InvoiceType::INVOICE_TYPE_OTHER
|
||||||
) {
|
) {
|
||||||
@@ -52,10 +53,9 @@ class GlobalDataProvider {
|
|||||||
|
|
||||||
public function getInvoiceTypes() : JsonResponse {
|
public function getInvoiceTypes() : JsonResponse {
|
||||||
$invoiceTypes = [];
|
$invoiceTypes = [];
|
||||||
foreach (InvoiceType::all() as $invoiceType) {
|
foreach (InvoiceType::orderBy('sort_order')->get() as $invoiceType) {
|
||||||
if (
|
if (
|
||||||
$invoiceType->slug === InvoiceType::INVOICE_TYPE_TRAVELLING ||
|
$invoiceType->slug === InvoiceType::INVOICE_TYPE_TRAVELLING
|
||||||
$invoiceType->slug === InvoiceType::INVOICE_TYPE_OTHER
|
|
||||||
) {
|
) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -66,8 +66,6 @@ class GlobalDataProvider {
|
|||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
$invoiceTypes[] = ['slug' => InvoiceType::INVOICE_TYPE_OTHER, 'name' => 'Sonstige Kosten'];
|
|
||||||
|
|
||||||
return response()->json([
|
return response()->json([
|
||||||
'invoiceTypes' => $invoiceTypes
|
'invoiceTypes' => $invoiceTypes
|
||||||
]);
|
]);
|
||||||
@@ -110,6 +108,7 @@ class GlobalDataProvider {
|
|||||||
'common' => [],
|
'common' => [],
|
||||||
'costunits' => [],
|
'costunits' => [],
|
||||||
'events' => [],
|
'events' => [],
|
||||||
|
'eventControl' => [],
|
||||||
];
|
];
|
||||||
|
|
||||||
$navigation['personal'][] = ['url' => '/', 'display' => 'Home'];
|
$navigation['personal'][] = ['url' => '/', 'display' => 'Home'];
|
||||||
@@ -129,7 +128,8 @@ class GlobalDataProvider {
|
|||||||
$navigation['events'][] = ['url' => '/event/details/' . $event->identifier, 'display' => $event->name];
|
$navigation['events'][] = ['url' => '/event/details/' . $event->identifier, 'display' => $event->name];
|
||||||
}
|
}
|
||||||
|
|
||||||
$navigation['events'][] = ['url' => '/create-event', 'display' => 'Neue Veranstaltung'];
|
$navigation['eventControl'][] = ['url' => '/archived-events', 'display' => 'Archivierte Veranstaltungen'];
|
||||||
|
$navigation['eventControl'][] = ['url' => '/create-event', 'display' => 'Neue Veranstaltung'];
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ class InvoiceCsvFileProvider {
|
|||||||
'"Kontoinhaber*in"',
|
'"Kontoinhaber*in"',
|
||||||
'"Betrag"',
|
'"Betrag"',
|
||||||
'"Spende"',
|
'"Spende"',
|
||||||
'"Beleg ohne Auszahlung"',
|
'"Buchungstext"'
|
||||||
]);
|
]);
|
||||||
|
|
||||||
foreach ($this->invoices as $invoice) {
|
foreach ($this->invoices as $invoice) {
|
||||||
@@ -38,7 +38,7 @@ class InvoiceCsvFileProvider {
|
|||||||
'"' . $invoiceReadable['accountOwner'] . '"',
|
'"' . $invoiceReadable['accountOwner'] . '"',
|
||||||
'"' . $invoiceReadable['amountPlain'] . '"',
|
'"' . $invoiceReadable['amountPlain'] . '"',
|
||||||
'"' . $invoiceReadable['donation'] . '"',
|
'"' . $invoiceReadable['donation'] . '"',
|
||||||
'"' . $invoiceReadable['alreadyPaid'] . '"'
|
'"' . $invoiceReadable['paymentPurpose'] . '"'
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$csvArray[] = $csvLine;
|
$csvArray[] = $csvLine;
|
||||||
|
|||||||
@@ -3,8 +3,10 @@
|
|||||||
namespace App\Providers;
|
namespace App\Providers;
|
||||||
|
|
||||||
use App\Models\Invoice;
|
use App\Models\Invoice;
|
||||||
|
use App\Resources\InvoiceResource;
|
||||||
use DOMDocument;
|
use DOMDocument;
|
||||||
use Exception;
|
use Exception;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
|
||||||
class PainFileProvider {
|
class PainFileProvider {
|
||||||
public string $senderIban;
|
public string $senderIban;
|
||||||
@@ -89,6 +91,8 @@ class PainFileProvider {
|
|||||||
$pmt_inf->appendChild($dbtr_agt);
|
$pmt_inf->appendChild($dbtr_agt);
|
||||||
|
|
||||||
foreach ($this->invoices as $index => $invoice) {
|
foreach ($this->invoices as $index => $invoice) {
|
||||||
|
$invoiceResource = new InvoiceResource($invoice)->toArray(new Request());
|
||||||
|
|
||||||
$cdt_trf_tx_inf = $doc->createElement('CdtTrfTxInf');
|
$cdt_trf_tx_inf = $doc->createElement('CdtTrfTxInf');
|
||||||
|
|
||||||
$pmt_id = $doc->createElement('PmtId');
|
$pmt_id = $doc->createElement('PmtId');
|
||||||
@@ -112,7 +116,7 @@ class PainFileProvider {
|
|||||||
$cdt_trf_tx_inf->appendChild($cdtr_acct);
|
$cdt_trf_tx_inf->appendChild($cdtr_acct);
|
||||||
|
|
||||||
$rmt_inf = $doc->createElement('RmtInf');
|
$rmt_inf = $doc->createElement('RmtInf');
|
||||||
$rmt_inf->appendChild($doc->createElement('Ustrd', 'Auslagenerstattung Rechnungsnummer ' . $invoice['invoice_number']));
|
$rmt_inf->appendChild($doc->createElement('Ustrd', $invoiceResource['paymentPurpose']));
|
||||||
$cdt_trf_tx_inf->appendChild($rmt_inf);
|
$cdt_trf_tx_inf->appendChild($rmt_inf);
|
||||||
|
|
||||||
$pmt_inf->appendChild($cdt_trf_tx_inf);
|
$pmt_inf->appendChild($cdt_trf_tx_inf);
|
||||||
|
|||||||
@@ -88,7 +88,7 @@ class EventParticipantRepository {
|
|||||||
|
|
||||||
public function getParticipantsWithIntolerances(Event $event, Request $request) : array {
|
public function getParticipantsWithIntolerances(Event $event, Request $request) : array {
|
||||||
$participants = [];
|
$participants = [];
|
||||||
foreach ($event->participants()->whereNotNull('intolerances')->whereNot('intolerances' , '=', '')->get() as $participant) {
|
foreach ($event->participants()->orderBy('lastname')->orderBy('firstname')->whereNotNull('intolerances')->whereNot('intolerances' , '=', '')->get() as $participant) {
|
||||||
$participants[] = $participant->toResource()->toArray($request);
|
$participants[] = $participant->toResource()->toArray($request);
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -97,7 +97,7 @@ class EventParticipantRepository {
|
|||||||
|
|
||||||
public function getKitchenOverview(Event $event) : array {
|
public function getKitchenOverview(Event $event) : array {
|
||||||
$data = [];
|
$data = [];
|
||||||
$participants = $event->participants()->get();
|
$participants = $event->participants()->orderBy('lastname')->orderBy('firstname')->get();
|
||||||
|
|
||||||
|
|
||||||
for ($cur_date = $event->start_date; $cur_date <= $event->end_date; $cur_date->modify('+1 day')) {
|
for ($cur_date = $event->start_date; $cur_date <= $event->end_date; $cur_date->modify('+1 day')) {
|
||||||
|
|||||||
@@ -90,7 +90,7 @@ class EventRepository {
|
|||||||
|
|
||||||
$visibleEvents = [];
|
$visibleEvents = [];
|
||||||
/** @var Event $event */
|
/** @var Event $event */
|
||||||
foreach (Event::where($criteria)->get() as $event) {
|
foreach (Event::where($criteria)->orderBy('start_date')->get() as $event) {
|
||||||
|
|
||||||
if ($canSeeAll || !$accessCheck || $event->eventManagers()->where('user_id', $user->id)->exists()) {
|
if ($canSeeAll || !$accessCheck || $event->eventManagers()->where('user_id', $user->id)->exists()) {
|
||||||
$visibleEvents[] = $event;
|
$visibleEvents[] = $event;
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ class CostUnitResource {
|
|||||||
|
|
||||||
$amounts = [];
|
$amounts = [];
|
||||||
$overAllAmount = new Amount(0, 'Euro');
|
$overAllAmount = new Amount(0, 'Euro');
|
||||||
foreach (InvoiceType::all() as $invoiceType) {
|
foreach (InvoiceType::orderBy('sort_order')->get() as $invoiceType) {
|
||||||
$overAllAmount->addAmount($costUnitRepository->sumupByInvoiceType($this->costUnit, $invoiceType));
|
$overAllAmount->addAmount($costUnitRepository->sumupByInvoiceType($this->costUnit, $invoiceType));
|
||||||
$amounts[$invoiceType->slug]['string'] = $costUnitRepository->sumupByInvoiceType($this->costUnit, $invoiceType)->toString();
|
$amounts[$invoiceType->slug]['string'] = $costUnitRepository->sumupByInvoiceType($this->costUnit, $invoiceType)->toString();
|
||||||
$amounts[$invoiceType->slug]['name'] = $invoiceType->name;
|
$amounts[$invoiceType->slug]['name'] = $invoiceType->name;
|
||||||
|
|||||||
@@ -32,11 +32,10 @@ class EventResource extends JsonResource{
|
|||||||
'email' => $this->event->email,
|
'email' => $this->event->email,
|
||||||
'accountOwner' => $this->event->account_owner,
|
'accountOwner' => $this->event->account_owner,
|
||||||
'accountIban' => $this->event->account_iban,
|
'accountIban' => $this->event->account_iban,
|
||||||
'accountOwner' => $this->event->account_owner,
|
|
||||||
'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,
|
||||||
|
'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')],
|
||||||
'refundAfterEarlyBirdEnd' => 100 - $this->event->early_bird_end_amount_increase,
|
'refundAfterEarlyBirdEnd' => 100 - $this->event->early_bird_end_amount_increase,
|
||||||
|
|||||||
@@ -38,7 +38,8 @@ class InvoiceResource {
|
|||||||
$returnData['amount'] = Amount::fromString($this->invoice->amount, ' Euro')->toString();
|
$returnData['amount'] = Amount::fromString($this->invoice->amount, ' Euro')->toString();
|
||||||
$returnData['id'] = $this->invoice->id;
|
$returnData['id'] = $this->invoice->id;
|
||||||
$returnData['donation'] = $this->invoice->donation;
|
$returnData['donation'] = $this->invoice->donation;
|
||||||
$returnData['alreadyPaid'] = !$this->invoice->donation && null === $this->invoice->contact_bank_iban;
|
$returnData['externalPayment'] = null !== $this->invoice->payment_purpose;
|
||||||
|
$returnData['paymentPurpose'] = $this->invoice->payment_purpose ?? 'Auslagenerstattung Rechnungsnummer ' . $returnData['invoiceNumber'];
|
||||||
$returnData['accountOwner'] = $this->invoice->contact_bank_owner ?? '--';
|
$returnData['accountOwner'] = $this->invoice->contact_bank_owner ?? '--';
|
||||||
$returnData['accountIban'] = $this->invoice->contact_bank_iban ?? '--';
|
$returnData['accountIban'] = $this->invoice->contact_bank_iban ?? '--';
|
||||||
$returnData['status'] = $this->invoice->status;
|
$returnData['status'] = $this->invoice->status;
|
||||||
@@ -67,7 +68,7 @@ class InvoiceResource {
|
|||||||
$returnData['approvedBy'] = $this->invoice->approvedBy()->first()->username ?? '--';
|
$returnData['approvedBy'] = $this->invoice->approvedBy()->first()->username ?? '--';
|
||||||
}
|
}
|
||||||
|
|
||||||
$returnData['alreadyPaid'] = $returnData['alreadyPaid'] == '' ? 0 : 1;
|
$returnData['externalPayment'] = $returnData['externalPayment'] == '' ? 0 : 1;
|
||||||
|
|
||||||
return $returnData;
|
return $returnData;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -123,4 +123,5 @@ return [
|
|||||||
'store' => env('APP_MAINTENANCE_STORE', 'database'),
|
'store' => env('APP_MAINTENANCE_STORE', 'database'),
|
||||||
],
|
],
|
||||||
|
|
||||||
|
'version' => trim(file_get_contents(base_path('version'))),
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -0,0 +1,21 @@
|
|||||||
|
<?php
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
return new class extends Migration {
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*/
|
||||||
|
public function up(): void
|
||||||
|
{
|
||||||
|
Schema::table('invoice_types', function (Blueprint $table) {
|
||||||
|
$table->integer('sort_order')->default(1)->after('name');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public function down(): void
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
<?php
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
return new class extends Migration {
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*/
|
||||||
|
public function up(): void
|
||||||
|
{
|
||||||
|
Schema::table('invoices', function (Blueprint $table) {
|
||||||
|
$table->string('payment_purpose')->nullable()->default(null)->after('contact_bank_iban');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public function down(): void
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -4,7 +4,7 @@
|
|||||||
padding: 20px;
|
padding: 20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.invoice-main-flexbox div {
|
.invoice-type-layer {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
padding: 10px;
|
padding: 10px;
|
||||||
border: 1px solid #ccc;
|
border: 1px solid #ccc;
|
||||||
@@ -15,7 +15,7 @@
|
|||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
.invoice-main-flexbox div:hover {
|
.invoice-type-layer:hover {
|
||||||
background-color: #FAE39C;
|
background-color: #FAE39C;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -51,6 +51,8 @@ const props = defineProps({
|
|||||||
title: { type: String, default: 'App' },
|
title: { type: String, default: 'App' },
|
||||||
flash: { type: Object, default: () => ({}) }
|
flash: { type: Object, default: () => ({}) }
|
||||||
});
|
});
|
||||||
|
|
||||||
|
console.log(globalProps)
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
@@ -101,6 +103,16 @@ const props = defineProps({
|
|||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
|
<ul class="nav-links" v-if="globalProps.navbar.eventControl.length > 0">
|
||||||
|
<li v-for="navlink in globalProps.navbar.eventControl">
|
||||||
|
<a
|
||||||
|
:class="{ navlink_active: navlink.url.endsWith(currentPath) }"
|
||||||
|
:href="navlink.url"
|
||||||
|
>{{navlink.display}}</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
|
||||||
</nav>
|
</nav>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -145,7 +157,7 @@ const props = defineProps({
|
|||||||
<footer class="footer">
|
<footer class="footer">
|
||||||
<table>
|
<table>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Version 4.0.0</td>
|
<td>Version {{ globalProps.version }}</td>
|
||||||
<td>
|
<td>
|
||||||
mareike - Mdodernes Anmeldesystem und richtig einfache Kostenerfassung
|
mareike - Mdodernes Anmeldesystem und richtig einfache Kostenerfassung
|
||||||
</td>
|
</td>
|
||||||
|
|||||||
Reference in New Issue
Block a user