Invoice Widgets completed
This commit is contained in:
@@ -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]);
|
||||
}
|
||||
}
|
||||
|
||||
15
app/Domains/Dashboard/Routes/api.php
Normal file
15
app/Domains/Dashboard/Routes/api.php
Normal 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']);
|
||||
});
|
||||
|
||||
});
|
||||
});
|
||||
1
app/Domains/Dashboard/Routes/web.php
Normal file
1
app/Domains/Dashboard/Routes/web.php
Normal file
@@ -0,0 +1 @@
|
||||
<?php
|
||||
@@ -1,11 +0,0 @@
|
||||
<script setup>
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
31
app/Domains/Dashboard/Views/Partials/Widgets/MyInvoices.vue
Normal file
31
app/Domains/Dashboard/Views/Partials/Widgets/MyInvoices.vue
Normal 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>
|
||||
@@ -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>
|
||||
@@ -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,
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
37
app/Repositories/InvoiceRepository.php
Normal file
37
app/Repositories/InvoiceRepository.php
Normal 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;
|
||||
}
|
||||
}
|
||||
@@ -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() {
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
|
||||
Reference in New Issue
Block a user