Invoices can be uploaded

This commit is contained in:
2026-02-11 15:40:06 +01:00
parent bccfc11687
commit ee7fc637f1
47 changed files with 1751 additions and 67 deletions

View File

@@ -6,6 +6,7 @@ use App\Domains\CostUnit\Actions\CreateCostUnit\CreateCostUnitCommand;
use App\Domains\CostUnit\Actions\CreateCostUnit\CreateCostUnitRequest;
use App\Enumerations\CostUnitType;
use App\Models\CostUnit;
use App\Providers\FlashMessageProvider;
use App\Providers\InertiaProvider;
use App\Scopes\CommonController;
use App\ValueObjects\Amount;
@@ -23,12 +24,12 @@ class CreateController extends CommonController{
$request->get('cost_unit_name'),
CostUnitType::COST_UNIT_TYPE_RUNNING_JOB,
Amount::fromString($request->get('distance_allowance')),
$request->get('mail_on_new')
$request->get('mailOnNew')
);
$createCostUnitCommand = new CreateCostUnitCommand($createCostUnitRequest);
$result = $createCostUnitCommand->execute();
session()->put('message', 'Die laufende Tätigkeit wurde erfolgreich angelegt.');
new FlashMessageProvider('Die laufende Tätigkeit wurde erfolgreich angelegt.', 'success');
return response()->json([]);
}

View File

@@ -0,0 +1,20 @@
<?php
namespace App\Domains\CostUnit\Controllers;
use App\Scopes\CommonController;
use Illuminate\Http\JsonResponse;
class DistanceAllowanceController extends CommonController {
public function __invoke(int $costUnitId) : JsonResponse {
$distanceAllowance = 0.00;
$costUnit = $this->costUnits->getById($costUnitId, true);
if (null !== $costUnit) {
$distanceAllowance = $costUnit->distance_allowance;
}
return response()->json([
'distanceAllowance' => $distanceAllowance
]);
}
}

View File

@@ -1,21 +1,21 @@
<?php
use App\Domains\CostUnit\Controllers\ChangeStateController;
use App\Domains\CostUnit\Controllers\CreateController;
use App\Domains\CostUnit\Controllers\DistanceAllowanceController;
use App\Domains\CostUnit\Controllers\EditController;
use App\Domains\CostUnit\Controllers\ListController;
use App\Domains\CostUnit\Controllers\TreasurersEditController;
use App\Domains\UserManagement\Controllers\EmailVerificationController;
use App\Domains\UserManagement\Controllers\RegistrationController;
use App\Domains\UserManagement\Controllers\ResetPasswordController;
use App\Middleware\IdentifyTenant;
use Illuminate\Support\Facades\Route;
use Inertia\Inertia;
Route::prefix('api/v1')
->group(function () {
Route::middleware(IdentifyTenant::class)->group(function () {
Route::prefix('cost-unit')->group(function () {
Route::get('/get-distance-allowance/{costUnitId}', DistanceAllowanceController::class);
Route::middleware(['auth'])->group(function () {
Route::post('/create-running-job', [CreateController::class, 'createCostUnitRunningJob']);
@@ -41,8 +41,6 @@ Route::prefix('api/v1')
Route::get('/closed-cost-units', [ListController::class, 'listClosedCostUnits']);
Route::get('/archived-cost-units', [ListController::class, 'listArchivedCostUnits']);
});
});
});
});

View File

@@ -1,17 +1,13 @@
<?php
use App\Domains\CostUnit\Controllers\CreateController;
use App\Domains\CostUnit\Controllers\ListController;
use App\Domains\Dashboard\Controllers\DashboardController;
use App\Domains\UserManagement\Controllers\EmailVerificationController;
use App\Domains\UserManagement\Controllers\LoginController;
use App\Domains\UserManagement\Controllers\LogOutController;
use App\Domains\UserManagement\Controllers\RegistrationController;
use App\Domains\UserManagement\Controllers\ResetPasswordController;
use App\Http\Controllers\TestRenderInertiaProvider;
use App\Middleware\IdentifyTenant;
use Illuminate\Support\Facades\Route;
use Inertia\Inertia;
Route::middleware(IdentifyTenant::class)->group(function () {
Route::prefix('cost-unit')->group(function () {

View File

@@ -1,7 +1,8 @@
<script setup>
import AppLayout from '../../../../resources/js/layouts/AppLayout.vue'
import ShadowedBox from "../../../Views/Components/ShadowedBox.vue";
import {onMounted} from "vue";
import {toast} from "vue3-toastify";
</script>
<template>

View File

@@ -0,0 +1,63 @@
<?php
namespace App\Domains\Invoice\Actions\CreateInvoice;
use App\Enumerations\InvoiceStatus;
use App\Models\Invoice;
class CreateInvoiceCommand {
private CreateInvoiceRequest $request;
public function __construct(CreateInvoiceRequest $request) {
$this->request = $request;
}
public function execute() : CreateInvoiceResponse {
$response = new CreateInvoiceResponse();
if ($this->request->accountIban === 'undefined') {
$this->request->accountIban = null;
}
$invoice = Invoice::create([
'tenant' => app('tenant')->slug,
'cost_unit_id' => $this->request->costUnit->id,
'invoice_number' => $this->generateInvoiceNumber(),
'status' => InvoiceStatus::INVOICE_STATUS_NEW,
'type' => $this->request->invoiceType,
'type_other' => $this->request->invoiceTypeExtended,
'donation' => $this->request->isDonation,
'userId' => $this->request->userId,
'contact_name' => $this->request->contactName,
'contact_email' => $this->request->contactEmail,
'contact_phone' => $this->request->contactPhone,
'contact_bank_owner' => $this->request->accountOwner,
'contact_bank_iban' => $this->request->accountIban,
'amount' => $this->request->totalAmount,
'distance' => $this->request->distance,
'travel_direction' => $this->request->travelRoute,
'passengers' => $this->request->passengers,
'transportation' => $this->request->transportations,
'document_filename' => $this->request->receiptFile !== null ? $this->request->receiptFile->path : null,
]);
if ($invoice !== null) {
$response->success = true;
$response->invoice = $invoice;
}
return $response;
}
private function generateInvoiceNumber() : string {
$lastInvoiceNumber = Invoice::query()
->where('tenant', app('tenant')->slug)
->whereYear('created_at', date('Y'))
->count();
$invoiceNumber = $lastInvoiceNumber + 1;
$invoiceNumber = str_pad($invoiceNumber, 4, '0', STR_PAD_LEFT);
return sprintf('%1$s-%2$s', date('Y'), $invoiceNumber);
}
}

View File

@@ -0,0 +1,64 @@
<?php
namespace App\Domains\Invoice\Actions\CreateInvoice;
use App\Models\CostUnit;
use App\ValueObjects\InvoiceFile;
class CreateInvoiceRequest {
public CostUnit $costUnit;
public string $contactName;
public ?string $contactEmail;
public ?string $contactPhone;
public ?string $accountOwner;
public ?string $accountIban;
public string $invoiceType;
public ?string $invoiceTypeExtended;
public ?string $travelRoute;
public ?int $distance;
public ?int $passengers;
public ?int $transportations;
public ?InvoiceFile $receiptFile;
public float $totalAmount;
public bool $isDonation;
public ?int $userId;
public function __construct(
CostUnit $costUnit,
string $contactName,
string $invoiceType,
float $totalAmount,
?InvoiceFile $receiptFile,
bool $isDonation,
?int $userId = null,
?string $contactEmail = null,
?string $contactPhone = null,
?string $accountOwner = null,
?string $accountIban = null,
?string $invoiceTypeExtended = null,
?string $travelRoute = null,
?int $distance = null,
?int $passengers = null,
?int $transportations,
) {
$this->costUnit = $costUnit;
$this->contactName = $contactName;
$this->invoiceType = $invoiceType;
$this->invoiceTypeExtended = $invoiceTypeExtended;
$this->travelRoute = $travelRoute;
$this->distance = $distance;
$this->passengers = $passengers;
$this->transportations = $transportations;
$this->receiptFile = $receiptFile;
$this->contactEmail = $contactEmail;
$this->contactPhone = $contactPhone;
$this->accountOwner = $accountOwner;
$this->accountIban = $accountIban;
$this->totalAmount = $totalAmount;
$this->isDonation = $isDonation;
$this->userId = $userId;
}
}

View File

@@ -0,0 +1,15 @@
<?php
namespace App\Domains\Invoice\Actions\CreateInvoice;
use App\Models\Invoice;
class CreateInvoiceResponse {
public bool $success;
public ?Invoice $invoice;
public function __construct() {
$this->success = false;
$this->invoice = null;
}
}

View File

@@ -0,0 +1,138 @@
<?php
namespace App\Domains\Invoice\Controllers;
use App\Domains\Invoice\Actions\CreateInvoice\CreateInvoiceCommand;
use App\Domains\Invoice\Actions\CreateInvoice\CreateInvoiceRequest;
use App\Enumerations\CostUnitType;
use App\Enumerations\InvoiceType;
use App\Models\CostUnit;
use App\Providers\FlashMessageProvider;
use App\Providers\InertiaProvider;
use App\Providers\UploadFileProvider;
use App\Scopes\CommonController;
use App\ValueObjects\Amount;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
class NewInvoiceController extends CommonController {
public function __invoke() {
$userData = $this->users->getCurrentUserDetails();
$runningJobs = $this->costUnits->getCostUnitsForNewInvoice(CostUnitType::COST_UNIT_TYPE_RUNNING_JOB);
$currentEvents = $this->costUnits->getCostUnitsForNewInvoice(CostUnitType::COST_UNIT_TYPE_EVENT);
$inertiaProvider = new InertiaProvider('Invoice/NewInvoice', [
'userName' => $userData['userName'],
'userEmail' => $userData['userEmail'],
'userTelephone' => $userData['userTelephone'],
'userAccountOwner' => $userData['userAccountOwner'],
'userAccountIban' => $userData['userAccountIban'],
'runningJobs' => $runningJobs,
'currentEvents' => $currentEvents,
]);
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->get('amount'))->getAmount();
$distance = null;
} else {
$distance = Amount::fromString($request->get('amount'))->getRoundedAmount();
$amount = $distance * $costUnit->distance_allowance;
}
$createInvoiceRequest = new CreateInvoiceRequest(
$costUnit,
$request->get('name'),
InvoiceType::INVOICE_TYPE_TRAVELLING,
$amount,
$uploadedFile,
'donation' === $request->get('decision') ? true : false,
$this->users->getCurrentUserDetails()['userId'],
$request->get('contactEmail'),
$request->get('telephone'),
$request->get('accountOwner'),
$request->get('accountIban'),
null,
$request->get('otherText'),
$distance,
$request->get('havePassengers'),
$request->get('materialTransportation'),
);
break;
default:
$createInvoiceRequest = new CreateInvoiceRequest(
$costUnit,
$request->get('name'),
$invoiceType,
Amount::fromString($request->get('amount'))->getAmount(),
$uploadedFile,
'donation' === $request->get('decision') ? true : false,
$this->users->getCurrentUserDetails()['userId'],
$request->get('contactEmail'),
$request->get('telephone'),
$request->get('accountOwner'),
$request->get('accountIban'),
$request->get('otherText'),
null,
null,
$request->get('havePassengers'),
$request->get('materialTransportation'),
);
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'
]);
}
dd($request->all());
}
}

View File

@@ -0,0 +1,25 @@
<?php
use App\Domains\CostUnit\Controllers\DistanceAllowanceController;
use App\Domains\CostUnit\Controllers\ListController;
use App\Domains\Invoice\Controllers\NewInvoiceController;
use App\Middleware\IdentifyTenant;
use Illuminate\Support\Facades\Route;
Route::middleware(IdentifyTenant::class)->group(function () {
Route::prefix('api/v1/invoice')->group(function () {
Route::post('/new/{costUnitId}/{invoiceType}', [NewInvoiceController::class, 'saveInvoice']);
Route::middleware(['auth'])->group(function () {
Route::get('/create', [CreateController::class, 'showForm']);
});
});
});

View File

@@ -0,0 +1,22 @@
<?php
use App\Domains\CostUnit\Controllers\CreateController;
use App\Domains\CostUnit\Controllers\ListController;
use App\Domains\Invoice\Controllers\NewInvoiceController;
use App\Middleware\IdentifyTenant;
use Illuminate\Support\Facades\Route;
Route::middleware(IdentifyTenant::class)->group(function () {
Route::prefix('invoice')->group(function () {
Route::get('/new', NewInvoiceController::class);
Route::middleware(['auth'])->group(function () {
Route::get('/create', [CreateController::class, 'showForm']);
});
});
});

View File

@@ -1,29 +0,0 @@
<script setup>
import AppLayout from '../../../../resources/js/layouts/AppLayout.vue'
const props = defineProps({
navbar: Object,
tenant: String,
user: Object,
currentPath: String,
})
</script>
<template>
<AppLayout title='Neue Abrechnung' :user="props.user" :navbar="props.navbar" :tenant="props.tenant" :currentPath="props.currentPath">
<!-- Alles hier wird in den Slot von AppLayout eingefügt -->
<h2>Dashboard Content</h2>
<p>Test 1!
Hier wird mal eine Rechnung erstellt.
Wenn es geht oder auch nicht</p>
{{props.tenant}}
<button @click="$toast.success('Hallo vom Dashboard!')">Test Toaster</button>
<button @click="$toast.error('Soe sieht ein Fehler aus')">Error Toaster</button>
</AppLayout>
</template>
<style scoped>
</style>

View File

@@ -0,0 +1,79 @@
<script setup>
import AppLayout from '../../../../resources/js/layouts/AppLayout.vue'
import TextResource from "../../../Views/Components/TextResource.vue";
import Modal from "../../../Views/Components/Modal.vue";
import {onMounted, reactive, ref} from "vue";
import ExpenseAccounting from "./Partials/newInvoice/expense-accounting.vue";
import TravelExpenseAccounting from "./Partials/newInvoice/travel-expense-accounting.vue";
const props = defineProps({
currentEvents: Object,
runningJobs: Object,
userId: Number,
userName: String,
userEmail: String,
userTelephone: String,
userIban: String,
userAccountOwner: String,
})
const isOpen = ref(false)
const eventId = ref(0);
const invoiceType = ref('');
</script>
<template>
<AppLayout title='Neue Abrechnung'>
<div class="invoice-main-flexbox" v-if="eventId === 0">
<div
class="invoice-type-layer"
@click="isOpen = true;invoiceType='expense-accounting'"
>
<TextResource textName="NEW_COMMON_COST_EXPENSE_DESCRIPTION" />
</div>
<div
class="invoice-type-layer"
@click="isOpen = true;invoiceType='travel-expense-accounting'"
>
<TextResource textName="NEW_TRAVEL_COST_EXPENSE_DESCRIPTION" />
</div>
</div>
<ExpenseAccounting v-if="invoiceType === 'expense-accounting' && eventId !== 0"
:eventId="eventId"
:userName="props.userName"
:userEmail="props.userEmail"
:userTelephone="props.userTelephone"
:userIban="props.userIban"
:userAccountOwner="props.userAccountOwner"
:userId="props.userId"
/>
<TravelExpenseAccounting v-else-if="invoiceType === 'travel-expense-accounting' && eventId !== 0"
:eventId="eventId"
:userName="props.userName"
:userEmail="props.userEmail"
:userTelephone="props.userTelephone"
:userIban="props.userIban"
:userAccountOwner="props.userAccountOwner"
:userId="props.userId"
/>
<Modal :show="isOpen" title="Veranstaltung auswählen" @close="isOpen = false">
<select v-model="eventId" @change="isOpen=false" style="width: 100%">
<option value="0" disabled>Bitte auswählen</option>
<optgroup label="Laufende Tätigkeiten">
<option :value="event.id" v-for="event in props.runningJobs">{{ event.name }}</option>
</optgroup>
<optgroup label="Veranstaltungen">
<option :value="event.id" v-for="event in props.currentEvents">{{ event.name }}</option>
</optgroup>
</select>
</Modal>
</AppLayout>
</template>

View File

@@ -0,0 +1,124 @@
<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";
const data = defineProps({
eventId: Number,
userName: String,
userEmail: String,
userTelephone: String,
userIban: 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;">Wofür hast du den Betrag ausgegeben</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 />
<RefundData
v-if="finalStep"
:eventId="data.eventId"
:invoice-type="invoiceType"
:amount="amount"
:other-text="otherText"
:userName="data.userName"
:userEmail="data.userEmail"
:userTelephone="data.userTelephone"
:userIban="data.userIban"
:userAccountOwner="data.userAccountOwner"
:receipt="receipt"
@close="finalStep = false"
/>
</template>
<style scoped>
</style>

View File

@@ -0,0 +1,157 @@
<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";
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,
userIban: String,
havePassengers: Number,
materialTransportation: Boolean,
})
console.log(props.receipt)
const finalStep = ref(true)
const userName = ref(props.userName)
const userEmail = ref(props.userEmail)
const userTelephone = ref(props.userTelephone)
const userIban = ref(props.userIban)
const userAccountOwner = ref(props.userAccountOwner)
const sending = ref(false)
const success = ref(false)
const decision = ref('')
const errorMsg = ref('')
const confirmation = ref(null)
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('havePassengers', props.havePassengers ? 1 : 0)
formData.append('materialTransportation', props.materialTransportation ? 1 : 0)
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 = '/';
}
} catch (err) {
toast.error(result.message);
} finally {
sending.value = false
}
}
</script>
<template>
<Modal :show="finalStep" title='Bitte gib deine Daten ein' @close="emit('close')">
<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>
<strong>E-Mail-Adresse (Für Rückfragen):</strong>
</label><br />
<input
type="email"
name="contact_email"
v-model="userEmail"
style="font-size: 14pt; width: 550px;" /><br /><br />
<label>
<strong>Telefonnummer (für Rückfragen):</strong>
</label><br />
<input
type="text"
id="contact_telephone"
name="contact_telephone" v-model="userTelephone"
style="font-size: 14pt; width: 550px;" /><br /><br />
<span id="decision" v-if="userName !== '' && decision === ''">
<label><br />
<strong>Möchtest du den Betrag spenden?</strong>
</label><br />
<input type="button" style="border-radius: 0; width: 100px;" @click="decision='donation'" value="Ja" />
<input type="button" style="border-radius: 0; width: 100px;" @click="decision='payout'" value="Nein" />
</span>
<span id="confirm_donation" v-if="decision === 'donation'">
<input type="radio" name="confirmation_radio" value="donation" id="confirmation_radio_donation" v-model="confirmation">
<TextResource belongsTo="confirmation_radio_donation" textName="CONFIRMATION_DONATE" />
<br /><br />
<input type="button" class="mareike-button" v-if="confirmation !== null && !sending" @click="sendData" value="Beleg einreichen" />
</span>
<span id="confirm_payment" v-if="decision === 'payout'">
<label>
<strong>Konto-Inhaber*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 />
<span v-if="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_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>

View File

@@ -0,0 +1,158 @@
<script setup>
import { ref, onMounted, reactive } from 'vue'
import {checkFilesize} from "../../../../../../resources/js/components/InvoiceUploadChecks.js";
import RefundData from "./refund-data.vue";
import NumericInput from "../../../../../Views/Components/NumericInput.vue";
import AmountInput from "../../../../../Views/Components/AmountInput.vue";
import {useAjax} from "../../../../../../resources/js/components/ajaxHandler.js";
const data = defineProps({
eventId: Number,
userName: String,
userEmail: String,
userTelephone: String,
userIban: String,
userAccountOwner: String,
})
const { request } = useAjax();
const distanceAllowance = ref(null);
const travelDirection = ref(null);
const have_receipt = ref('')
const havePassengers = ref(false);
const materialTransportation = ref(false);
const amount = ref(0.00);
const invoiceType = ref(null);
const otherText = ref('');
const receipt = ref(null)
const finalStep = ref(false)
async function getDistanceAllowance() {
const tempData = await request('/api/v1/cost-unit/get-distance-allowance/' + data.eventId, {
method: "GET",
});
distanceAllowance.value = tempData.distanceAllowance;
have_receipt.value = 'no';
}
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;">Gib deine Reisesetrecke an</span></legend>
<input
type="text"
name="travel-direction"
v-model="travelDirection"
/>
</fieldset><br /><br />
<fieldset v-if="travelDirection !== null">
<legend><span style="font-weight: bolder;">Bist du mit dem ÖPNV gefahren oder besitzt du einen Beleg</span></legend>
<input type="button" style="border-radius: 0; width: 100px;" @click="have_receipt='yes'" value="Ja" />
<input type="button" style="border-radius: 0; width: 100px;" @click="getDistanceAllowance" value="Nein" />
</fieldset>
<br /><br />
<fieldset v-if="have_receipt === 'yes'">
<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
<br /><br />
<input type="button"
v-if="amount !== null && have_receipt === 'yes' && amount != '0'"
value="Beleg auswählen und fortfahren"
onclick="document.getElementById('receipt').click();"
/>
<input accept="application/pdf" type="file" id="receipt" name="receipt" @change="handleFileChange"
style="display: none"/>
<RefundData
v-if="finalStep && have_receipt === 'yes'"
:eventId="data.eventId"
invoice-type="travelling"
:amount="amount"
:other-text="travelDirection"
:materialTransportation="materialTransportation"
:havePassengers="havePassengers"
:userName="data.userName"
:userEmail="data.userEmail"
:userTelephone="data.userTelephone"
:userIban="data.userIban"
:userAccountOwner="data.userAccountOwner"
:receipt="receipt"
@close="finalStep = false"
/>
</fieldset>
<fieldset v-else-if="distanceAllowance != null">
<legend><span style="font-weight: bolder;">Reiseinformationen</span></legend>
Gesamtlänge des Reisewegs:
<NumericInput
class="width-small"
name="total_distance"
v-model="amount"
/> km<br />
<span style="font-weight: normal">({{ amount }} km x {{distanceAllowance.toFixed(2).replace('.', ',')}} Euro / km = <strong>{{ (amount * distanceAllowance).toFixed(2).replace('.', ',') }} Euro</strong>)</span>
<br /><br />
<input
type="checkbox"
name="havePassengers"
v-model="havePassengers"
id="havePassengers"
/> <label style="margin-bottom: 20px;" for="havePassengers">Ich habe Personen mitgenommen</label>
<br />
<input
type="checkbox"
name="materialTransportation"
v-model="materialTransportation"
id="materialTransportation"
/> <label style="margin-bottom: 20px;" for="materialTransportation">Ich habe Material transportiert</label>
<br /><br />
<input
v-if="amount !== null && have_receipt === 'no' && amount != '0'"
@click="finalStep = true;"
type="button"
value="Pauschalbetrag abrechnen" />
<RefundData
v-if="finalStep && have_receipt === 'no'"
:eventId="data.eventId"
invoice-type="travelling"
:amount="amount"
:other-text="travelDirection"
:materialTransportation="materialTransportation"
:havePassengers="havePassengers"
:userName="data.userName"
:userEmail="data.userEmail"
:userTelephone="data.userTelephone"
:userIban="data.userIban"
:userAccountOwner="data.userAccountOwner"
@close="finalStep = false"
/>
</fieldset>
</template>
<style scoped>
</style>

View File

@@ -6,7 +6,6 @@ use App\Domains\UserManagement\Controllers\LogOutController;
use App\Domains\UserManagement\Controllers\RegistrationController;
use App\Domains\UserManagement\Controllers\ResetPasswordController;
use App\Middleware\IdentifyTenant;
use App\Providers\GlobalDataProvider;
use Illuminate\Support\Facades\Route;
Route::middleware(IdentifyTenant::class)->group(function () {
@@ -23,11 +22,6 @@ Route::middleware(IdentifyTenant::class)->group(function () {
Route::post('/logout', [LogoutController::class, 'logout']);
});
Route::prefix('api/v1/') ->group(function () {
Route::get('/retreive-global-data', GlobalDataProvider::class);
});
});