Invoice Widgets completed

This commit is contained in:
2026-02-11 19:38:06 +01:00
parent 87531237c7
commit 882752472e
16 changed files with 240 additions and 18 deletions

View File

@@ -5,8 +5,10 @@ namespace App\Domains\Dashboard\Controllers;
use App\Providers\AuthCheckProvider;
use App\Providers\InertiaProvider;
use App\Scopes\CommonController;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Js;
class DashboardController extends CommonController {
public function __invoke(Request $request) {
@@ -15,10 +17,6 @@ class DashboardController extends CommonController {
}
return redirect()->intended('/login');
dd('U');
return $this->renderForGuest($request);
}
private function renderForLoggedInUser(Request $request) {
@@ -29,4 +27,14 @@ class DashboardController extends CommonController {
private function renderForGuest(Request $request) {
}
public function getMyInvoices() : JsonResponse {
$invoices = $this->invoices->getMyInvoicesWidget();
return response()->json(['myInvoices' => $invoices]);
}
public function getOpenCostUnits() : JsonResponse {
$costUnits = $this->costUnits->listForSummary(5);
return response()->json(['openCostUnits' => $costUnits]);
}
}

View File

@@ -0,0 +1,15 @@
<?php
use App\Domains\Dashboard\Controllers\DashboardController;
use App\Middleware\IdentifyTenant;
use Illuminate\Support\Facades\Route;
Route::middleware(IdentifyTenant::class)->group(function () {
Route::middleware(['auth'])->group(function () {
Route::prefix('api/v1/dashboard')->group(function () {
Route::get('/my-invoices', [DashboardController::class, 'getMyInvoices']);
Route::get('/open-cost-units', [DashboardController::class, 'getOpenCostUnits']);
});
});
});

View File

@@ -0,0 +1 @@
<?php

View File

@@ -1,11 +0,0 @@
<script setup>
</script>
<template>
</template>
<style scoped>
</style>

View File

@@ -0,0 +1,31 @@
<script setup>
import {onMounted, reactive} from "vue";
const myInvoices = reactive({
'myInvoices': '',
'approvedInvoices': '',
'deniedInvoices': '',
})
onMounted(async () => {
const response = await fetch('/api/v1/dashboard/my-invoices');
const data = await response.json();
Object.assign(myInvoices, data);
});
</script>
<template>
<p v-for="invoice in myInvoices.myInvoices" class="widget-content-item">
<a :href="'/invoices/my-invoices/' + invoice.slug" class="link">{{invoice.title}} ({{invoice.count}})</a>
<label>
{{invoice.amount}}
</label>
</p>
</template>
<style scoped>
</style>

View File

@@ -0,0 +1,40 @@
<script setup>
import {onMounted, reactive} from "vue";
const costUnits = reactive({
'openCostUnits': '',
})
onMounted(async () => {
const response = await fetch('/api/v1/dashboard/open-cost-units');
const data = await response.json();
Object.assign(costUnits, data);
});
</script>
<template>
<table class="widget-content-item" v-if="costUnits.openCostUnits.length > 0">
<tr>
<td style="font-weight: bold">Kostenstelle</td>
<td style="font-weight: bold">Neu</td>
<td style="font-weight: bold">Ang</td>
<td style="font-weight: bold">Betrag</td>
</tr>
<tr v-for="costUnit in costUnits.openCostUnits">
<td>{{costUnit.name}}</td>
<td>{{costUnit.new_invoices_count}}</td>
<td>{{costUnit.approved_invoices_count}}</td>
<td>{{costUnit.totalAmount}}</td>
</tr>
</table>
<p v-else style="padding: 10px; font-weight: bold">Es existieren im Moment keine Abrechnugnen, um die du dich kümmern musst.</p>
</template>
<style scoped>
</style>

View File

@@ -27,7 +27,7 @@ class CreateInvoiceCommand {
'type' => $this->request->invoiceType,
'type_other' => $this->request->invoiceTypeExtended,
'donation' => $this->request->isDonation,
'userId' => $this->request->userId,
'user_id' => $this->request->userId,
'contact_name' => $this->request->contactName,
'contact_email' => $this->request->contactEmail,
'contact_phone' => $this->request->contactPhone,

View File

@@ -4,6 +4,7 @@ namespace App\Models;
use App\Scopes\InstancedModel;
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
use Illuminate\Database\Eloquent\Relations\HasMany;
/**
* @property string $name
@@ -37,4 +38,8 @@ class CostUnit extends InstancedModel
$this->tresurers()->detach();
$this->save();
}
public function invoices() : hasMany {
return $this->hasMany(Invoice::class);
}
}

View File

@@ -2,7 +2,9 @@
namespace App\Models;
use App\Enumerations\InvoiceStatus;
use App\Scopes\InstancedModel;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
/**
* @property string $tenant
@@ -65,4 +67,12 @@ class Invoice extends InstancedModel
'denied_at',
'denied_reason',
];
public function costUnit() : BelongsTo{
return $this->belongsTo(CostUnit::class);
}
public function status() : BelongsTo {
return $this->belongsTo(InvoiceStatus::class, 'status')->first();
}
}

View File

@@ -3,9 +3,12 @@
namespace App\Repositories;
use App\Enumerations\CostUnitType;
use App\Enumerations\InvoiceStatus;
use App\Enumerations\UserRole;
use App\Models\CostUnit;
use App\Resources\CostUnitResource;
use App\ValueObjects\Amount;
use Illuminate\Database\Capsule\Manager as Capsule;
class CostUnitRepository {
public function getCostUnitsForNewInvoice(string $type) : array {
@@ -95,4 +98,53 @@ class CostUnitRepository {
return $visibleCostUnits;
}
public function listForSummary(int $maxCountCostUnits) : array {
$costUnits = $this->getCostUnitsByCriteria([
'archived' => false,
'tenant' => app('tenant')->slug,
],false);
foreach ($costUnits as &$cu) {
$cu->new_invoices_count = $cu->invoices()->where('status', 'new')->count();
$cu->approved_invoices_count = $cu->invoices()->where('status', 'approved')->count();
}
$costUnits = collect($costUnits)
->sortByDesc('approved_invoices_count')
->sortByDesc('new_invoices_count')
->take($maxCountCostUnits)
->values()
->all();
$returnData = [];
foreach ($costUnits as $costUnit) {
if($costUnit->approved_invoices_count === 0 && $costUnit->new_invoices_count === 0) {
continue;
}
if (strlen($costUnit->name) > 15) {
$costUnit->name = substr($costUnit->name, 8, 13) . '...';
}
$costUnit->totalAmount = $this->sumupAmounts($costUnit)->toString();
$returnData[] = $costUnit;
}
return $returnData;
}
public function sumupAmounts(CostUnit $costUnit) : Amount {
$amount = new Amount(0, '');
foreach ($costUnit->invoices()->get() as $invoice) {
if ($invoice->status === InvoiceStatus::INVOICE_STATUS_DENIED) {
continue;
}
$amount->addAmount(Amount::fromString($invoice->amount));
}
return $amount;
}
}

View File

@@ -0,0 +1,37 @@
<?php
namespace App\Repositories;
use App\Enumerations\InvoiceStatus;
use App\Models\Invoice;
use App\ValueObjects\Amount;
class InvoiceRepository {
public function getMyInvoicesWidget() : array {
$invoices = [
InvoiceStatus::INVOICE_STATUS_NEW => ['slug' => 'new', 'title' => 'Neue Abrechnungen', 'count' => 0, 'amount' => Amount::fromString('0')->toString()],
InvoiceStatus::INVOICE_STATUS_APPROVED => ['slug' => 'approved', 'title' => 'Freigegebene Abrechnungen', 'count' => 0, 'amount' => Amount::fromString('0')->toString()],
InvoiceStatus::INVOICE_STATUS_DENIED => ['slug' => 'declined', 'title' => 'Abgelehnte Abrechnungen', 'count' => 0, 'amount' => Amount::fromString('0')->toString()]
];
$user = auth()->user();
if (null === $user) {
return $invoices;
}
foreach ([InvoiceStatus::INVOICE_STATUS_NEW, InvoiceStatus::INVOICE_STATUS_APPROVED, InvoiceStatus::INVOICE_STATUS_DENIED] as $status) {
$amount = 0;
$count = 0;
foreach (Invoice::where(['user_id' => $user->id, 'status' => $status])->get() as $stack) {
$count++;
$amount += $stack->amount;
}
$invoices[$status]['count'] = $count;
$invoices[$status]['amount'] = Amount::fromString($amount)->toString();
}
return $invoices;
}
}

View File

@@ -4,6 +4,7 @@ namespace App\Scopes;
use App\Providers\AuthCheckProvider;
use App\Repositories\CostUnitRepository;
use App\Repositories\InvoiceRepository;
use App\Repositories\PageTextRepository;
use App\Repositories\UserRepository;
@@ -13,10 +14,13 @@ abstract class CommonController {
protected PageTextRepository $pageTexts;
protected InvoiceRepository $invoices;
public function __construct() {
$this->users = new UserRepository();
$this->costUnits = new CostUnitRepository();
$this->pageTexts = new PageTextRepository();
$this->invoices = new InvoiceRepository();
}
protected function checkAuth() {

View File

@@ -36,4 +36,8 @@ class Amount {
|> trim(...)
|> function (string $value) : string { return str_replace('.', ',', $value); };
}
public function addAmount(Amount $amount) : void {
$this->amount += $amount->getAmount();
}
}

View File

@@ -1,6 +1,8 @@
<script setup>
import ShadowedBox from "../../Components/ShadowedBox.vue";
import MyInvoices from "../../../Domains/Dashboard/Views/Partials/Widgets/MyInvoices.vue";
import OpenCostUnits from "../../../Domains/Dashboard/Views/Partials/Widgets/OpenCostUnits.vue";
</script>
<template>
@@ -10,13 +12,13 @@ import ShadowedBox from "../../Components/ShadowedBox.vue";
</shadowed-box>
<shadowed-box class="widget-box">
Widget 2
<MyInvoices />
</shadowed-box>
<shadowed-box class="widget-box">
Widget 3
</shadowed-box>
<shadowed-box class="widget-box">
Widget 4
<OpenCostUnits />
</shadowed-box>
</diV>
</template>