Compare commits

..
5 Commits
11 changed files with 489 additions and 60 deletions
+50 -38
View File
@@ -24,48 +24,15 @@ class BookingsController extends Controller
*/ */
public function index($year) public function index($year)
{ {
$bookings = Booking::with('subBookings.accountType.accountClass.ioType', $cashbook = $this->getCashbook($year);
'subBookings.project')
->whereYear('date', '=', $year)
->orderBy('date')
->get()
->groupBy( function ($item) {
return Carbon::parse($item->date)->format('n');
});
$sums = array(); return view('bookings.index', $cashbook);
$startBalance = SubBooking::balanceAt($year - 1 . '-12-31');
$sums[0]['balance'] = $startBalance;
$expeditures = SubBooking::expedituresInInterval($year . '-01-01', $year . '-12-31', true);
$incomes = SubBooking::incomesInInterval($year . '-01-01', $year . '-12-31', true);
// Create an array with the following properties:
// 'balance' - The account balance at the last day of a month
// 'expeditures' - the sum of all expeditures in this month
// 'incomes' - the sum of all incomes in this month plus the account
// balance of the previous month
for ($month = 1; $month <= 12; $month++) {
$currExpeditures = $expeditures->where('month', '=', $month)->first()->expeditures;
$currIncomes = $expeditures->where('month', '<', $month)->sum('expeditures')
+ $incomes->where('month', '<=', $month)->sum('incomes')
+ $startBalance;
$currBalance = $currExpeditures + $currIncomes;
$sums[$month]['expeditures'] = $currExpeditures;
$sums[$month]['incomes'] = $currIncomes;
$sums[$month]['balance'] = $currBalance;
} }
$firstDateString = Carbon::parse(Booking::firstDate()); public function report($year) {
$firstDate['Y'] = $firstDateString->format('Y'); $cashbook = $this->getCashbook($year);
$firstDate['m'] = $firstDateString->format('m');
return view('bookings.index', compact('bookings', 'year', 'sums', 'firstDate')); return view('bookings.print', $cashbook);
} }
/** /**
@@ -346,4 +313,49 @@ class BookingsController extends Controller
return compact('openTargetsArray', 'projectsArray', 'accountTypeArray'); return compact('openTargetsArray', 'projectsArray', 'accountTypeArray');
} }
private function getCashbook($year) {
$bookings = Booking::with('subBookings.accountType.accountClass.ioType',
'subBookings.project')
->whereYear('date', '=', $year)
->orderBy('date')
->get()
->groupBy( function ($item) {
return Carbon::parse($item->date)->format('n');
});
$sums = array();
$startBalance = SubBooking::balanceAt($year - 1 . '-12-31');
$sums[0]['balance'] = $startBalance;
$expeditures = SubBooking::expedituresInInterval($year . '-01-01', $year . '-12-31', true);
$incomes = SubBooking::incomesInInterval($year . '-01-01', $year . '-12-31', true);
// Create an array with the following properties:
// 'balance' - The account balance at the last day of a month
// 'expeditures' - the sum of all expeditures in this month
// 'incomes' - the sum of all incomes in this month plus the account
// balance of the previous month
for ($month = 1; $month <= 12; $month++) {
$currExpeditures = $expeditures->where('month', '=', $month)->first()->expeditures;
$currIncomes = $expeditures->where('month', '<', $month)->sum('expeditures')
+ $incomes->where('month', '<=', $month)->sum('incomes')
+ $startBalance;
$currBalance = $currExpeditures + $currIncomes;
$sums[$month]['expeditures'] = $currExpeditures;
$sums[$month]['incomes'] = $currIncomes;
$sums[$month]['balance'] = $currBalance;
}
$firstDateString = Carbon::parse(Booking::firstDate());
$firstDate['Y'] = $firstDateString->format('Y');
$firstDate['m'] = $firstDateString->format('m');
return compact('bookings', 'year', 'sums', 'firstDate');
}
} }
+100 -1
View File
@@ -154,7 +154,106 @@ class ReportsController extends Controller
return view('reports.scopes.compact', compact('scopes', 'year', return view('reports.scopes.compact', compact('scopes', 'year',
'startBalance', 'endBalance')); 'startBalance', 'endBalance'));
} elseif ($type == 'detailed') { } elseif ($type == 'detailed') {
return view('reports.scopes.detailed'); $yearFilter = function($query) use ($year) {
$query->whereHas('booking', function($query) use ($year) {
$query->whereYear('date', $year);
});
};
$scopes = Scope::select('id', 'name')
->with([
'accountClasses:id,io_type_id,scope_id,name',
'accountClasses.ioType:id,factor',
'accountClasses.accountTypes' => function($query) use ($year, $yearFilter) {
return $query->select('id', 'account_class_id', 'name', 'number')
->whereHas('subBookings', $yearFilter)
->with(['subBookings' => $yearFilter,
'subBookings.booking:id,person_or_company,date']);
}
])->get();
foreach ($scopes as $scope) {
foreach ($scope->accountClasses as $accountClass) {
$accountClass->amount =
$accountClass->accountTypes->sum(function ($accountType) {
return $accountType->subBookings->sum('amount');
});
}
}
return view('reports.scopes.detailed', compact('scopes', 'year'));
} else {
abort(404);
}
}
public function printScopes($type, $year)
{
if ($type == 'compact') {
$yearFilter = function($query) use ($year) {
$query->whereHas('booking', function($query) use ($year) {
$query->whereYear('date', $year);
});
};
$scopes = Scope::select('id', 'name')
->with([
'accountClasses:id,io_type_id,scope_id,name',
'accountClasses.ioType:id,factor',
'accountClasses.accountTypes' => function($query) use ($year, $yearFilter) {
return $query->select('id', 'account_class_id', 'name', 'number')
->whereHas('subBookings', $yearFilter)
->with(['subBookings' => $yearFilter]);
}
])->get();
foreach ($scopes as $scope) {
foreach ($scope->accountClasses as $accountClass) {
$accountClass->amount =
$accountClass->accountTypes->sum(function ($accountType) {
return $accountType->subBookings->sum('amount');
});
}
$scope->balance = $scope->accountClasses->sum(function ($accountClass) {
return $accountClass->amount * $accountClass->ioType->factor;
});
}
$startBalance = SubBooking::balanceAt(lastDayOfYear($year - 1));
$endBalance = $startBalance + $scopes->sum('balance');
return view('reports.scopes.compact_print', compact('scopes', 'year',
'startBalance', 'endBalance'));
} elseif ($type == 'detailed') {
$yearFilter = function($query) use ($year) {
$query->whereHas('booking', function($query) use ($year) {
$query->whereYear('date', $year);
});
};
$scopes = Scope::select('id', 'name')
->with([
'accountClasses:id,io_type_id,scope_id,name',
'accountClasses.ioType:id,factor',
'accountClasses.accountTypes' => function($query) use ($year, $yearFilter) {
return $query->select('id', 'account_class_id', 'name', 'number')
->whereHas('subBookings', $yearFilter)
->with(['subBookings' => $yearFilter,
'subBookings.booking:id,person_or_company,date']);
}
])->get();
foreach ($scopes as $scope) {
foreach ($scope->accountClasses as $accountClass) {
$accountClass->amount =
$accountClass->accountTypes->sum(function ($accountType) {
return $accountType->subBookings->sum('amount');
});
}
}
return view('reports.scopes.detailed_print', compact('scopes', 'year'));
} else { } else {
abort(404); abort(404);
} }
+4
View File
@@ -2,6 +2,7 @@
namespace App\Providers; namespace App\Providers;
use Illuminate\Support\Facades\Schema;
use Illuminate\Support\ServiceProvider; use Illuminate\Support\ServiceProvider;
use App\CustomValidator; use App\CustomValidator;
use Validator; use Validator;
@@ -18,6 +19,9 @@ class AppServiceProvider extends ServiceProvider
Validator::resolver(function ($translator, $data, $rules, $messages) { Validator::resolver(function ($translator, $data, $rules, $messages) {
return new CustomValidator($translator, $data, $rules, $messages); return new CustomValidator($translator, $data, $rules, $messages);
}); });
// Set default string length in order to run on older versions of MySQL
Schema::defaultStringLength(191);
} }
/** /**
+6 -4
View File
@@ -8,6 +8,8 @@
<a href='/reports/balances/{{ $year }}' class="btn btn-outline-warning">HS-Rechnung</a> <a href='/reports/balances/{{ $year }}' class="btn btn-outline-warning">HS-Rechnung</a>
<a href='/reports/scopes/compact/{{ $year }}' class="btn <a href='/reports/scopes/compact/{{ $year }}' class="btn
btn-outline-warning">Abrechnung</a> btn-outline-warning">Abrechnung</a>
<a href='/reports/scopes/detailed/{{ $year }}' class="btn
btn-outline-warning">Konten</a>
</li> </li>
@endsection @endsection
@@ -42,7 +44,7 @@
or $firstDate['Y'] == $year or $firstDate['Y'] == $year
and $firstDate['m'] <= $month and $firstDate['m'] <= $month
)) ))
<tr class='table-danger'> <tr style='color:#ff0000'>
<th>{{ startOfMonth($year, $month) }}</th> <th>{{ startOfMonth($year, $month) }}</th>
<th>Saldo</th> <th>Saldo</th>
<th></th> <th></th>
@@ -100,7 +102,7 @@
</tr> </tr>
@if (!$booking->isSimple()) @if (!$booking->isSimple())
@foreach ($booking->subBookings as $subBooking) @foreach ($booking->subBookings as $subBooking)
<tr class='table-secondary'> <tr style='font-style:italic'>
<td></td> <td></td>
<td>{{ $subBooking->reference }}</td> <td>{{ $subBooking->reference }}</td>
<td></td> <td></td>
@@ -137,7 +139,7 @@
or $firstDate['Y'] == $year or $firstDate['Y'] == $year
and $firstDate['m'] <= $month and $firstDate['m'] <= $month
)) ))
<tr class='table-primary'> <tr style='color:#000080'>
<th> <th>
{{ endOfMonth($year, $month) }} {{ endOfMonth($year, $month) }}
</th> </th>
@@ -149,7 +151,7 @@
<th></th> <th></th>
<th></th> <th></th>
</tr> </tr>
<tr class='table-danger'> <tr style='color:#ff0000'>
<th> <th>
{{ endOfMonth($year, $month) }} {{ endOfMonth($year, $month) }}
</th> </th>
+114
View File
@@ -0,0 +1,114 @@
@extends('layout.print')
@section('title', 'Kassenbuch ' . $year)
@section('content')
@for ($month = 1; $month <= 12; $month++)
<table class='table table-sm table-bordered' style='page-break-after: always'>
<thead>
<tr>
<th>Datum</th>
<th>Positionen</th>
<th>Person / Firma</th>
<th style='width:2.6cm'>Ausgang</th>
<th style='width:2.6cm'>Eingang</th>
<th>Konto</th>
</tr>
</thead>
@if ((
date('Y') > $year
or (date('Y') == $year
and date('m') >= $month)
) and (
$firstDate['Y'] < $year
or $firstDate['Y'] == $year
and $firstDate['m'] <= $month
))
<tr style='color:#ff0000'>
<th>{{ startOfMonth($year, $month) }}</th>
<th>Saldo</th>
<th></th>
<th></th>
<th>{!! formatAmount($sums[$month - 1]['balance']) !!}</th>
<th></th>
</tr>
@endif
@if (isset($bookings[$month]))
@foreach($bookings[$month] as $booking)
<tr>
<td>{{ formatDate($booking->date) }}</td>
<td>{{ $booking->reference }}</td>
<td>{{ $booking->person_or_company }}</td>
<td align='right'>
@if ($booking->signedAmount() < 0)
{!! formatAmount($booking->signedAmount()) !!}
@endif
</td>
<td align='right'>
@if ($booking->signedAmount() >= 0)
{!! formatAmount($booking->signedAmount()) !!}
@endif
</td>
<td>
@if ($booking->isSimple())
{{ $booking->accountType()->number }}
@endif
</td>
</tr>
@if (!$booking->isSimple())
@foreach ($booking->subBookings as $subBooking)
<tr style='font-style:italic'>
<td></td>
<td>{{ $subBooking->reference }}</td>
<td></td>
<td align='right'>
@if ($subBooking->signedAmount() < 0)
{!! formatAmount($subBooking->signedAmount()) !!}
@endif
</td>
<td align='right'>
@if ($subBooking->signedAmount() >= 0)
{!! formatAmount($subBooking->signedAmount()) !!}
@endif
</td>
<td>
{{ $subBooking->accountType->number }}
</td>
</tr>
@endforeach
@endif
@endforeach
@endif
@if ((
date('Y') > $year
or (date('Y') == $year
and date('m') >= $month)
) and (
$firstDate['Y'] < $year
or $firstDate['Y'] == $year
and $firstDate['m'] <= $month
))
<tr style='color:#000080'>
<th>
{{ endOfMonth($year, $month) }}
</th>
<th>Monatsabschluss</th>
<th></th>
<th>{!! formatAmount($sums[$month]['expeditures']) !!}</th>
<th>{!! formatAmount($sums[$month]['incomes']) !!}</th>
<th></th>
</tr>
<tr style='color:#ff0000'>
<th>
{{ endOfMonth($year, $month) }}
</th>
<th>Saldo</th>
<th></th>
<th>{!! formatAmount($sums[$month]['balance']) !!}</th>
<th></th>
<th></th>
</tr>
@endif
</table>
@endfor
@endsection
-2
View File
@@ -68,7 +68,5 @@
$('[data-toggle="tooltip"]').tooltip() $('[data-toggle="tooltip"]').tooltip()
}); });
</script> </script>
</body> </body>
</html> </html>
+19
View File
@@ -0,0 +1,19 @@
<html>
<head>
<title>Twäng! e. V. - @yield('title')</title>
<link rel="stylesheet"
href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css"
integrity="sha384-MCw98/SFnGE8fJT3GXwEOngsV7Zt27NXFoaoApmYm81iuXoPkFOJwJ8ERdknLPMO"
crossorigin="anonymous">
<style>
body {
position: relative;
}
</style>
</head>
<body>
@yield('content')
</body>
</html>
@@ -0,0 +1,88 @@
@extends('layout.print')
@section('title', 'Abrechnung ' . $year)
@section('content')
<table class='table table-sm table-borderless'>
<tr>
<td>
<b>Kontostand am 1. 1. {{ $year }}</b>
</td>
<td>
<b>{!! formatAmount($startBalance) !!}</b>
</td>
</tr>
<tr><td colspan='2'></td></tr>
@foreach($scopes as $scope)
<tr>
<td colspan='2'><b>{{ $scope->name }}</b></td>
</tr>
@foreach($scope->accountClasses as $accountClass)
<tr>
<td colspan='2' style='text-indent: 2em;'>
<u>{{ $accountClass->name }}</u>
</td>
</tr>
@foreach($accountClass->accountTypes as $accountType)
<tr>
<td style='text-indent: 4em;'>
{{$accountType->number}} - {{$accountType->name}}
</td>
<td>
{!! formatAmount($accountType->subBookings->sum('amount')) !!}
</td>
</tr>
@endforeach
<tr><td colspan='2'></td></tr>
@endforeach
<tr>
<td colspan='2' style='text-indent: 2em;'>
<u>GESAMT</u>
</td>
<tr>
@foreach($scope->accountClasses as $accountClass)
<tr>
<td style='text-indent: 4em;'>
{{ $accountClass->name }}
</td>
<td>
{!! formatAmount($accountClass->amount) !!}
</td>
</tr>
@endforeach
<tr>
<td style='text-indent: 4em;'>
Saldo {{ $scope->name }}
</td>
<td>{!! formatAmount($scope->balance) !!}</td>
</tr>
<tr><td colspan='2'></td></tr>
@endforeach
<tr>
<td colspan='2'>
<b>Übersicht</b>
</td>
<tr>
@foreach($scopes as $scope)
<tr>
<td style='text-indent: 4em;'>
Saldo {{ $scope->name }}
</td>
<td>{!! formatAmount($scope->balance) !!}</td>
</tr>
@endforeach
<tr>
<td style='text-indent: 4em;'>Gesamtsaldo</td>
<td>{!! formatAmount($scopes->sum('balance')) !!}</td>
</tr>
<tr><td colspan='2'></td></tr>
<tr>
<td>
<b>Kontostand am 31. 12. {{ $year }}</b>
</td>
<td>
<b>{!! formatAmount($endBalance) !!}</b>
</td>
</tr>
</table>
@endsection
@@ -0,0 +1,48 @@
@extends('layout.master')
@section('title', 'Buchungen nach Konten ' . $year)
@section('subnav')
<a class='btn btn-outline-secondary' href='/bookings/year-{{ $year }}'>
Zurück
</a>
@endsection
@section('content')
<h2>@yield('title')</h2>
@foreach($scopes as $scope)
<h3>{{ $scope->name }}</h3>
@foreach($scope->accountClasses as $accountClass)
<h4>{{ $accountClass->name }}</h4>
<table class='table'>
<tr style='color: #000080'>
<th>Datum</th>
<th>Position</th>
<th>Person / Firma</th>
<th>Betrag</th>
</td>
@foreach($accountClass->accountTypes as $accountType)
<tr>
<th colspan='4' style='color: #000080'>
{{ $accountType->number . ' - ' . $accountType->name }}
</th>
</tr>
@foreach($accountType->subBookings as $subBooking)
<tr>
<td>{{ formatDate($subBooking->date()) }}</td>
<td>{{ $subBooking->reference }}</td>
<td>{{ $subBooking->personOrCompany() }}</td>
<td>{!! formatAmount($subBooking->amount) !!}</td>
</tr>
@endforeach
<tr>
<th colspan='4' style='text-align: right; color:#ff0000'>
{!! formatAmount($accountType->subBookings
->sum('amount')) !!}
</th>
</tr>
@endforeach
</table>
@endforeach
@endforeach
@endsection
@@ -0,0 +1,43 @@
@extends('layout.print')
@section('title', 'Buchungen nach Konten ' . $year)
@section('content')
@foreach($scopes as $scope)
@foreach($scope->accountClasses as $accountClass)
<h5>{{ $scope->name }}</h5>
<b>{{ $accountClass->name }}</b>
<table class='table table-sm table-borderless' style='page-break-after: always'>
<thead>
<tr>
<th>Datum</th>
<th>Position</th>
<th>Person / Firma</th>
<th>Betrag</th>
</td>
</thead>
@foreach($accountClass->accountTypes as $accountType)
<tr>
<th colspan='4' style='color: #000080'>
{{ $accountType->number . ' - ' . $accountType->name }}
</th>
</tr>
@foreach($accountType->subBookings as $subBooking)
<tr>
<td>{{ formatDate($subBooking->date()) }}</td>
<td>{{ $subBooking->reference }}</td>
<td>{{ $subBooking->personOrCompany() }}</td>
<td>{!! formatAmount($subBooking->amount) !!}</td>
</tr>
@endforeach
<tr>
<th colspan='4' style='text-align: right; color:#ff0000'>
{!! formatAmount($accountType->subBookings
->sum('amount')) !!}
</th>
</tr>
@endforeach
</table>
@endforeach
@endforeach
@endsection
+2
View File
@@ -33,6 +33,7 @@ Route::middleware(['auth'])->group(function() {
**************************************************************************/ **************************************************************************/
Route::redirect('/bookings', 'bookings/year-' . date('Y')); Route::redirect('/bookings', 'bookings/year-' . date('Y'));
Route::get('/bookings/year-{year}', 'BookingsController@index'); Route::get('/bookings/year-{year}', 'BookingsController@index');
Route::get('/bookings/year-{year}/print', 'BookingsController@report');
Route::post('/bookings', 'BookingsController@store'); Route::post('/bookings', 'BookingsController@store');
Route::get('/bookings/create', 'BookingsController@create'); Route::get('/bookings/create', 'BookingsController@create');
@@ -74,6 +75,7 @@ Route::middleware(['auth'])->group(function() {
Route::get('/reports/projects/{project}', 'ReportsController@project'); Route::get('/reports/projects/{project}', 'ReportsController@project');
Route::get('/reports/balances/{year}', 'ReportsController@balances'); Route::get('/reports/balances/{year}', 'ReportsController@balances');
Route::get('/reports/scopes/{type}/{year}', 'ReportsController@scopes'); Route::get('/reports/scopes/{type}/{year}', 'ReportsController@scopes');
Route::get('/reports/scopes/{type}/{year}/print', 'ReportsController@printScopes');
Route::get('/reports/targets/', 'ReportsController@targets'); Route::get('/reports/targets/', 'ReportsController@targets');
}); });