diff --git a/app/Domains/CostUnit/Actions/ChangeCostUnitTreasurers/ChangeCostUnitTreasurersCommand.php b/app/Domains/CostUnit/Actions/ChangeCostUnitTreasurers/ChangeCostUnitTreasurersCommand.php index b1bff4d..bacb627 100644 --- a/app/Domains/CostUnit/Actions/ChangeCostUnitTreasurers/ChangeCostUnitTreasurersCommand.php +++ b/app/Domains/CostUnit/Actions/ChangeCostUnitTreasurers/ChangeCostUnitTreasurersCommand.php @@ -18,7 +18,7 @@ class ChangeCostUnitTreasurersCommand { $this->request->costUnit->resetTreasurers(); foreach ($this->request->treasurers as $treasurer) { - $this->request->costUnit->tresurers()->attach($treasurer); + $this->request->costUnit->treasurers()->attach($treasurer); } $this->request->costUnit->save(); diff --git a/app/Domains/CostUnit/Controllers/ListController.php b/app/Domains/CostUnit/Controllers/ListController.php index 145ae00..de9ddfb 100644 --- a/app/Domains/CostUnit/Controllers/ListController.php +++ b/app/Domains/CostUnit/Controllers/ListController.php @@ -9,8 +9,6 @@ use Illuminate\Http\Request; class ListController extends CommonController { public function __invoke() { - - $inertiaProvider = new InertiaProvider('CostUnit/List', [ 'cost_unit_id' => 1 ]); diff --git a/app/Domains/CostUnit/Controllers/OpenController.php b/app/Domains/CostUnit/Controllers/OpenController.php new file mode 100644 index 0000000..a72567f --- /dev/null +++ b/app/Domains/CostUnit/Controllers/OpenController.php @@ -0,0 +1,28 @@ + $costUnitId + ]); + return $inertiaProvider->render(); + } + + public function listInvoices(int $costUnitId, string $invoiceStatus) : JsonResponse { + $costUnit = $this->costUnits->getById($costUnitId); + $invoices = $this->invoices->getByStatus($costUnit, $invoiceStatus); + + return response()->json([ + 'status' => 'success', + 'costUnit' => $costUnit, + 'invoices' => $invoices, + 'endpoint' => $invoiceStatus, + ]); + } +} diff --git a/app/Domains/CostUnit/Routes/api.php b/app/Domains/CostUnit/Routes/api.php index 38e9186..2461809 100644 --- a/app/Domains/CostUnit/Routes/api.php +++ b/app/Domains/CostUnit/Routes/api.php @@ -4,6 +4,7 @@ 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\OpenController; use App\Domains\CostUnit\Controllers\TreasurersEditController; use App\Middleware\IdentifyTenant; use Illuminate\Support\Facades\Route; @@ -21,6 +22,11 @@ Route::prefix('api/v1') Route::prefix('/{costUnitId}') ->group(function () { + Route::get('/invoice-list/{invoiceStatus}', [OpenController::class, 'listInvoices']); + + + + Route::post('/close', [ChangeStateController::class, 'close']); Route::post('/open', [ChangeStateController::class, 'open']); Route::post('/archive', [ChangeStateController::class, 'archive']); diff --git a/app/Domains/CostUnit/Routes/web.php b/app/Domains/CostUnit/Routes/web.php index 715d4c3..ed2400c 100644 --- a/app/Domains/CostUnit/Routes/web.php +++ b/app/Domains/CostUnit/Routes/web.php @@ -1,6 +1,7 @@ group(function () { Route::middleware(['auth'])->group(function () { Route::get('/create', [CreateController::class, 'showForm']); Route::get('/list', ListController::class); + Route::get('/{costUnitId}/', OpenController::class); + + }); diff --git a/app/Domains/CostUnit/Views/List.vue b/app/Domains/CostUnit/Views/List.vue index 019cf68..b842a97 100644 --- a/app/Domains/CostUnit/Views/List.vue +++ b/app/Domains/CostUnit/Views/List.vue @@ -6,10 +6,8 @@ import ShadowedBox from "../../../Views/Components/ShadowedBox.vue"; import TabbedPage from "../../../Views/Components/TabbedPage.vue"; import {toast} from "vue3-toastify"; - import ListCostUnits from "./Partials/ListCostUnits.vue"; - const props = defineProps({ message: String, diff --git a/app/Domains/CostUnit/Views/Open.vue b/app/Domains/CostUnit/Views/Open.vue new file mode 100644 index 0000000..77d4f04 --- /dev/null +++ b/app/Domains/CostUnit/Views/Open.vue @@ -0,0 +1,67 @@ + + + diff --git a/app/Domains/CostUnit/Views/Partials/ListCostUnits.vue b/app/Domains/CostUnit/Views/Partials/ListCostUnits.vue index a8a1ccd..8e88874 100644 --- a/app/Domains/CostUnit/Views/Partials/ListCostUnits.vue +++ b/app/Domains/CostUnit/Views/Partials/ListCostUnits.vue @@ -46,7 +46,7 @@ const costUnit = ref(null) const { data, loading, error, request, download } = useAjax() if (props.deep_jump_id > 0) { - open_invoice_list(props.deep_jump_id, 'new', props.deep_jump_id_sub) +// open_invoice_list(props.deep_jump_id, 'new', props.deep_jump_id_sub) } async function costUnitDetails(costUnitId) { @@ -79,17 +79,8 @@ async function editTreasurers(costUnitId) { } } - async function open_invoice_list(cost_unit_id, endpoint, invoice_id) { - const url = '' // `/wp-json/mareike/invoices/list-${endpoint}?invoice_id=${invoice_id}&cost_unit_id=${cost_unit_id} - try { - const response = await fetch(url, { method: 'GET' }) - if (!response.ok) throw new Error('Fehler beim Laden') - invoices.value = await response.json() - current_cost_unit.value = cost_unit_id - invoice_id = invoice_id - showInvoiceList.value = true - } catch (err) { - } + function loadInvoices(cost_unit_id) { + window.location.href = '/cost-unit/' + cost_unit_id; } async function denyNewRequests(costUnitId) { @@ -182,7 +173,7 @@ async function export_payouts(cost_unit_id) { Unbearbeitet {{ costUnit.countNewInvoices }} - +
diff --git a/app/Domains/CostUnit/Views/Partials/ListInvoices.vue b/app/Domains/CostUnit/Views/Partials/ListInvoices.vue new file mode 100644 index 0000000..00bc03a --- /dev/null +++ b/app/Domains/CostUnit/Views/Partials/ListInvoices.vue @@ -0,0 +1,80 @@ + + + + + diff --git a/app/Domains/Dashboard/Views/Partials/Widgets/OpenCostUnits.vue b/app/Domains/Dashboard/Views/Partials/Widgets/OpenCostUnits.vue index 5eea62f..baa7053 100644 --- a/app/Domains/Dashboard/Views/Partials/Widgets/OpenCostUnits.vue +++ b/app/Domains/Dashboard/Views/Partials/Widgets/OpenCostUnits.vue @@ -24,7 +24,7 @@ onMounted(async () => { - {{costUnit.name}} + {{costUnit.name}} {{costUnit.new_invoices_count}} {{costUnit.approved_invoices_count}} {{costUnit.totalAmount}} diff --git a/app/Domains/Invoice/Actions/ChangeStatus/ChangeStatusCommand.php b/app/Domains/Invoice/Actions/ChangeStatus/ChangeStatusCommand.php new file mode 100644 index 0000000..3657845 --- /dev/null +++ b/app/Domains/Invoice/Actions/ChangeStatus/ChangeStatusCommand.php @@ -0,0 +1,51 @@ +request = $request; + } + + public function execute() : ChangeStatusResponse { + $response = new ChangeStatusResponse(); + + switch ($this->request->status) { + case InvoiceStatus::INVOICE_STATUS_APPROVED: + $this->request->invoice->status = InvoiceStatus::INVOICE_STATUS_APPROVED; + $this->request->invoice->approved_by = auth()->user()->id; + $this->request->invoice->approved_at = now(); + break; + + case InvoiceStatus::INVOICE_STATUS_DENIED: + $this->request->invoice->status = InvoiceStatus::INVOICE_STATUS_DENIED; + $this->request->invoice->denied_by = auth()->user()->id; + $this->request->invoice->denied_at = now(); + $this->request->invoice->denied_reason = $this->request->comment; + break; + case InvoiceStatus::INVOICE_STATUS_NEW: + $this->request->invoice->status = InvoiceStatus::INVOICE_STATUS_NEW; + $this->request->invoice->approved_by = null; + $this->request->invoice->approved_at = null; + $this->request->invoice->denied_by = null; + $this->request->invoice->denied_at = null; + $this->request->invoice->comment = $this->request->invoice->denied_reason; + $this->request->invoice->denied_reason = null; + break; + + + + } + + if ($this->request->invoice->save()) { + $response->success = true; + } + + + return $response; + } +} diff --git a/app/Domains/Invoice/Actions/ChangeStatus/ChangeStatusRequest.php b/app/Domains/Invoice/Actions/ChangeStatus/ChangeStatusRequest.php new file mode 100644 index 0000000..5c2b4ae --- /dev/null +++ b/app/Domains/Invoice/Actions/ChangeStatus/ChangeStatusRequest.php @@ -0,0 +1,17 @@ +invoice = $invoice; + $this->status = $status; + $this->comment = $comment; + } +} diff --git a/app/Domains/Invoice/Actions/ChangeStatus/ChangeStatusResponse.php b/app/Domains/Invoice/Actions/ChangeStatus/ChangeStatusResponse.php new file mode 100644 index 0000000..e9c9365 --- /dev/null +++ b/app/Domains/Invoice/Actions/ChangeStatus/ChangeStatusResponse.php @@ -0,0 +1,11 @@ +success = false; + } +} diff --git a/app/Domains/Invoice/Actions/CreateInvoice/CreateInvoiceCommand.php b/app/Domains/Invoice/Actions/CreateInvoice/CreateInvoiceCommand.php index 73b4fea..fc55c6f 100644 --- a/app/Domains/Invoice/Actions/CreateInvoice/CreateInvoiceCommand.php +++ b/app/Domains/Invoice/Actions/CreateInvoice/CreateInvoiceCommand.php @@ -38,7 +38,7 @@ class CreateInvoiceCommand { 'travel_direction' => $this->request->travelRoute, 'passengers' => $this->request->passengers, 'transportation' => $this->request->transportations, - 'document_filename' => $this->request->receiptFile !== null ? $this->request->receiptFile->path : null, + 'document_filename' => $this->request->receiptFile !== null ? $this->request->receiptFile->fullPath : null, ]); if ($invoice !== null) { diff --git a/app/Domains/Invoice/Actions/CreateInvoice/CreateInvoiceRequest.php b/app/Domains/Invoice/Actions/CreateInvoice/CreateInvoiceRequest.php index 27cb211..cc88a39 100644 --- a/app/Domains/Invoice/Actions/CreateInvoice/CreateInvoiceRequest.php +++ b/app/Domains/Invoice/Actions/CreateInvoice/CreateInvoiceRequest.php @@ -59,6 +59,11 @@ class CreateInvoiceRequest { $this->totalAmount = $totalAmount; $this->isDonation = $isDonation; $this->userId = $userId; + + if ($accountIban === 'undefined') { + $this->accountIban = null; + $this->accountOwner = null; + } } } diff --git a/app/Domains/Invoice/Actions/UpdateInvoice/UpdateInvoiceCommand.php b/app/Domains/Invoice/Actions/UpdateInvoice/UpdateInvoiceCommand.php new file mode 100644 index 0000000..cb1fcec --- /dev/null +++ b/app/Domains/Invoice/Actions/UpdateInvoice/UpdateInvoiceCommand.php @@ -0,0 +1,33 @@ +request = $request; + } + + public function execute() : UpdateInvoiceResponse { + $response = new UpdateInvoiceResponse(); + + $this->request->invoice->amount = $this->request->amount->getAmount(); + $this->request->invoice->cost_unit_id = $this->request->costUnit->id; + $this->request->invoice->type = $this->request->invoiceType; + $this->request->invoice->comment = $this->request->comment; + + $this->request->invoice->save(); + + $request = new ChangeStatusRequest($this->request->invoice, InvoiceStatus::INVOICE_STATUS_APPROVED); + $changeStatusCommand = new ChangeStatusCommand($request); + $changeStatusCommand->execute(); + + return $response; + } + +} diff --git a/app/Domains/Invoice/Actions/UpdateInvoice/UpdateInvoiceRequest.php b/app/Domains/Invoice/Actions/UpdateInvoice/UpdateInvoiceRequest.php new file mode 100644 index 0000000..2086978 --- /dev/null +++ b/app/Domains/Invoice/Actions/UpdateInvoice/UpdateInvoiceRequest.php @@ -0,0 +1,24 @@ +comment = $comment; + $this->invoiceType = $invoiceType; + $this->costUnit = $costUnit; + $this->invoice = $invoice; + $this->amount = $amount; + } +} diff --git a/app/Domains/Invoice/Actions/UpdateInvoice/UpdateInvoiceResponse.php b/app/Domains/Invoice/Actions/UpdateInvoice/UpdateInvoiceResponse.php new file mode 100644 index 0000000..e05bd83 --- /dev/null +++ b/app/Domains/Invoice/Actions/UpdateInvoice/UpdateInvoiceResponse.php @@ -0,0 +1,15 @@ +success = false; + $this->invoice = null; + } +} diff --git a/app/Domains/Invoice/Controllers/ChangeStateController.php b/app/Domains/Invoice/Controllers/ChangeStateController.php new file mode 100644 index 0000000..40b7c61 --- /dev/null +++ b/app/Domains/Invoice/Controllers/ChangeStateController.php @@ -0,0 +1,27 @@ +invoices->getAsTreasurer($invoiceId); + if ($invoice === null) { + return response()->json([]); + } + + $comment = request()->get('reason') ?? null; + $changeStatusRequest = new ChangeStatusRequest($invoice, $newState, $comment); + $changeStatusCommand = new ChangeStatusCommand($changeStatusRequest); + if ($changeStatusCommand->execute()->success) { + return response()->json(['status' => 'success']); + } + + return response()->json([]); + } +} diff --git a/app/Domains/Invoice/Controllers/EditController.php b/app/Domains/Invoice/Controllers/EditController.php new file mode 100644 index 0000000..f3c5659 --- /dev/null +++ b/app/Domains/Invoice/Controllers/EditController.php @@ -0,0 +1,132 @@ +invoices->getAsTreasurer($invoiceId); + if ($invoice === null) { + return response()->json([]); + } + + $receiptfile = null; + if ($invoice->document_filename !== null) { + $receiptfile = new InvoiceFile(); + $receiptfile->filename = $invoice->document_filename; + $receiptfile->fullPath = $invoice->document_filename; + } + $createInvoiceRequest = new CreateInvoiceRequest( + $invoice->costUnit()->first(), + $invoice->contact_name, + $invoice->type, + $invoice->amount, + $receiptfile, + $invoice->donation, + $invoice->user_id, + $invoice->contact_email, + $invoice->contact_phone, + $invoice->contact_bank_owner, + $invoice->contact_bank_iban, + $invoice->type_other, + $invoice->travel_direction, + $invoice->distance, + $invoice->passengers, + $invoice->transportation + ); + + $invoiceCreationCommand = new CreateInvoiceCommand($createInvoiceRequest); + $newInvoice = $invoiceCreationCommand->execute()->invoice; + + $invoiceDenyRequest = new ChangeStatusRequest($invoice,InvoiceStatus::INVOICE_STATUS_DENIED, 'Abrechnungskorrektur in Rechnungsnummer #' . $newInvoice->invoice_number . ' erstellt.'); + $invoiceDenyCommand = new ChangeStatusCommand($invoiceDenyRequest); + $invoiceDenyCommand->execute(); + + + $runningJobs = $this->costUnits->getCostUnitsForNewInvoice(CostUnitType::COST_UNIT_TYPE_RUNNING_JOB); + $currentEvents = $this->costUnits->getCostUnitsForNewInvoice(CostUnitType::COST_UNIT_TYPE_EVENT); + + return response()->json([ + 'invoice' => new InvoiceResource($invoice)->toArray(), + 'status' => 'success', + 'costUnits' => array_merge($runningJobs, $currentEvents), + ]); + } + + public function updateInvoice(int $invoiceId, Request $request) : JsonResponse { + $invoice = $this->invoices->getAsTreasurer($invoiceId); + if ($invoice === null) { + return response()->json([]); + } + + $modifyData = $request->get('invoiceData'); + + $newAmount = Amount::fromString($modifyData['amount']); + $amountLeft = Amount::fromString($invoice->amount); + $amountLeft->subtractAmount($newAmount); + + $newCostUnit = $this->costUnits->getById($modifyData['cost_unit'],true); + $updateInvoiceRequest = new UpdateInvoiceRequest( + $invoice, + $modifyData['reason_of_correction'] ?? 'Abrechnungskorrektur', + $modifyData['type_internal'], + $newCostUnit, + $newAmount + ); + $updateInvoiceCommand = new UpdateInvoiceCommand($updateInvoiceRequest); + $updateInvoiceCommand->execute(); + + + $newInvoice = null; + if (isset($modifyData['duplicate']) && $modifyData['duplicate'] === true) { + $receiptfile = null; + if ($invoice->document_filename !== null) { + $receiptfile = new InvoiceFile(); + $receiptfile->filename = $invoice->document_filename; + $receiptfile->fullPath = $invoice->document_filename; + } + $createInvoiceRequest = new CreateInvoiceRequest( + $invoice->costUnit()->first(), + $invoice->contact_name, + $invoice->type, + $amountLeft->getAmount(), + $receiptfile, + $invoice->donation, + $invoice->user_id, + $invoice->contact_email, + $invoice->contact_phone, + $invoice->contact_bank_owner, + $invoice->contact_bank_iban, + $invoice->type_other, + $invoice->travel_direction, + $invoice->distance, + $invoice->passengers, + $invoice->transportation + ); + + $invoiceCreationCommand = new CreateInvoiceCommand($createInvoiceRequest); + $newInvoice = $invoiceCreationCommand->execute()->invoice; + } + + $useInvoice = $newInvoice ?? $invoice; + $do_copy = $newInvoice !== null ? true : false; + return response()->json([ + 'invoice' => new InvoiceResource($useInvoice)->toArray(), + 'do_copy' => $do_copy, + ]); + } +} diff --git a/app/Domains/Invoice/Controllers/ShowInvoiceController.php b/app/Domains/Invoice/Controllers/ShowInvoiceController.php new file mode 100644 index 0000000..7865118 --- /dev/null +++ b/app/Domains/Invoice/Controllers/ShowInvoiceController.php @@ -0,0 +1,55 @@ +invoices->getAsTreasurer($invoiceId); + + $runningJobs = $this->costUnits->getCostUnitsForNewInvoice(CostUnitType::COST_UNIT_TYPE_RUNNING_JOB); + $currentEvents = $this->costUnits->getCostUnitsForNewInvoice(CostUnitType::COST_UNIT_TYPE_EVENT); + + return response()->json([ + 'invoice' => new InvoiceResource($invoice)->toArray(), + 'costUnits' => array_merge($runningJobs, $currentEvents), + ]); + } + + public function showReceipt(int $invoiceId): BinaryFileResponse + { + $invoice = $this->invoices->getAsTreasurer($invoiceId); + if (null === $invoice) { + abort(404, 'Datei nicht gefunden'); + } + + if (null === $invoice->document_filename) { + abort(404, 'Datei nicht gefunden'); + } + + $path = $invoice->document_filename; + // Pfad zur Datei + $fullPath = 'private/' . $path; + + + + + if (!Storage::exists($path)) { + + + + abort(404, 'Datei nicht gefunden'); + } + + return response()->file(storage_path('app/' . $fullPath), [ + 'Content-Type' => 'application/pdf' + ]); + } +} diff --git a/app/Domains/Invoice/Routes/api.php b/app/Domains/Invoice/Routes/api.php index ea6710c..3d985d9 100644 --- a/app/Domains/Invoice/Routes/api.php +++ b/app/Domains/Invoice/Routes/api.php @@ -2,20 +2,27 @@ use App\Domains\CostUnit\Controllers\DistanceAllowanceController; use App\Domains\CostUnit\Controllers\ListController; +use App\Domains\Invoice\Controllers\ChangeStateController; +use App\Domains\Invoice\Controllers\EditController; use App\Domains\Invoice\Controllers\NewInvoiceController; +use App\Domains\Invoice\Controllers\ShowInvoiceController; 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('/details/{invoiceId}', ShowInvoiceController::class); + Route::get('/showReceipt/{invoiceId}', [ShowInvoiceController::class, 'showReceipt']); + + Route::post('/details/{invoiceId}/change-state/{newState}', ChangeStateController::class); + Route::post('/details/{invoiceId}/copy', [EditController::class, 'copyInvoice']); + Route::post('/details/{invoiceId}/update', [EditController::class, 'updateInvoice']); + + + + Route::get('/create', [CreateController::class, 'showForm']); }); diff --git a/app/Domains/Invoice/Views/Partials/invoiceDetails/DistanceAllowance.vue b/app/Domains/Invoice/Views/Partials/invoiceDetails/DistanceAllowance.vue new file mode 100644 index 0000000..34fd61f --- /dev/null +++ b/app/Domains/Invoice/Views/Partials/invoiceDetails/DistanceAllowance.vue @@ -0,0 +1,78 @@ + + + + + diff --git a/app/Domains/Invoice/Views/Partials/invoiceDetails/EditInvoice.vue b/app/Domains/Invoice/Views/Partials/invoiceDetails/EditInvoice.vue new file mode 100644 index 0000000..adba409 --- /dev/null +++ b/app/Domains/Invoice/Views/Partials/invoiceDetails/EditInvoice.vue @@ -0,0 +1,116 @@ + + + + + diff --git a/app/Domains/Invoice/Views/Partials/invoiceDetails/Header.vue b/app/Domains/Invoice/Views/Partials/invoiceDetails/Header.vue new file mode 100644 index 0000000..f98bf89 --- /dev/null +++ b/app/Domains/Invoice/Views/Partials/invoiceDetails/Header.vue @@ -0,0 +1,117 @@ + + + + + diff --git a/app/Domains/Invoice/Views/Partials/invoiceDetails/InvoiceDetails.vue b/app/Domains/Invoice/Views/Partials/invoiceDetails/InvoiceDetails.vue new file mode 100644 index 0000000..29fc008 --- /dev/null +++ b/app/Domains/Invoice/Views/Partials/invoiceDetails/InvoiceDetails.vue @@ -0,0 +1,285 @@ + + +