mirror of
https://github.com/InvoiceShelf/InvoiceShelf.git
synced 2026-04-17 10:14:08 +00:00
Enhance Expense Report - Grouped itemized expenses
This commit is contained in:
@@ -19,7 +19,7 @@ class ExpensesReportController extends Controller
|
|||||||
* Handle the incoming request.
|
* Handle the incoming request.
|
||||||
*
|
*
|
||||||
* @param string $hash
|
* @param string $hash
|
||||||
* @return JsonResponse
|
* @return \Illuminate\Http\JsonResponse
|
||||||
*/
|
*/
|
||||||
public function __invoke(Request $request, $hash)
|
public function __invoke(Request $request, $hash)
|
||||||
{
|
{
|
||||||
@@ -31,14 +31,26 @@ class ExpensesReportController extends Controller
|
|||||||
|
|
||||||
App::setLocale($locale);
|
App::setLocale($locale);
|
||||||
|
|
||||||
$expenseCategories = Expense::with('category')
|
// Fetch individual expenses (filtered and ordered by date), then group by category
|
||||||
|
$expenses = Expense::with('category')
|
||||||
->whereCompanyId($company->id)
|
->whereCompanyId($company->id)
|
||||||
->applyFilters($request->only(['from_date', 'to_date']))
|
->applyFilters($request->only(['from_date', 'to_date', 'expense_category_id']))
|
||||||
->expensesAttributes()
|
->orderBy('expense_date', 'asc')
|
||||||
->get();
|
->get();
|
||||||
$totalAmount = 0;
|
|
||||||
foreach ($expenseCategories as $category) {
|
$totalAmount = $expenses->sum('base_amount');
|
||||||
$totalAmount += $category->total_amount;
|
|
||||||
|
$grouped = $expenses->groupBy(function ($item) {
|
||||||
|
return $item->category ? $item->category->name : trans('expenses.uncategorized');
|
||||||
|
});
|
||||||
|
|
||||||
|
$expenseGroups = collect();
|
||||||
|
foreach ($grouped as $categoryName => $group) {
|
||||||
|
$expenseGroups->push([
|
||||||
|
'name' => $categoryName,
|
||||||
|
'expenses' => $group,
|
||||||
|
'total' => $group->sum('base_amount'),
|
||||||
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
$dateFormat = CompanySetting::getSetting('carbon_date_format', $company->id);
|
$dateFormat = CompanySetting::getSetting('carbon_date_format', $company->id);
|
||||||
@@ -62,7 +74,7 @@ class ExpensesReportController extends Controller
|
|||||||
->get();
|
->get();
|
||||||
|
|
||||||
view()->share([
|
view()->share([
|
||||||
'expenseCategories' => $expenseCategories,
|
'expenseGroups' => $expenseGroups,
|
||||||
'colorSettings' => $colorSettings,
|
'colorSettings' => $colorSettings,
|
||||||
'totalExpense' => $totalAmount,
|
'totalExpense' => $totalAmount,
|
||||||
'company' => $company,
|
'company' => $company,
|
||||||
@@ -82,4 +94,4 @@ class ExpensesReportController extends Controller
|
|||||||
|
|
||||||
return $pdf->stream();
|
return $pdf->stream();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -33,7 +33,7 @@
|
|||||||
.heading-date-range {
|
.heading-date-range {
|
||||||
font-weight: normal;
|
font-weight: normal;
|
||||||
font-size: 15px;
|
font-size: 15px;
|
||||||
color: #A5ACC1;
|
color: #606060;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
text-align: right;
|
text-align: right;
|
||||||
padding: 0px;
|
padding: 0px;
|
||||||
@@ -41,7 +41,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.sub-heading-text {
|
.sub-heading-text {
|
||||||
font-weight: normal;
|
font-weight: bold;
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
color: #595959;
|
color: #595959;
|
||||||
padding: 0px;
|
padding: 0px;
|
||||||
@@ -50,8 +50,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.expenses-title {
|
.expenses-title {
|
||||||
margin-top: 60px;
|
margin-top: 30px;
|
||||||
padding-left: 3px;
|
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
line-height: 21px;
|
line-height: 21px;
|
||||||
color: #040405;
|
color: #040405;
|
||||||
@@ -133,6 +132,84 @@
|
|||||||
line-height: 21px;
|
line-height: 21px;
|
||||||
color: #5851D8;
|
color: #5851D8;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* -- Items Table -- */
|
||||||
|
|
||||||
|
.items-table {
|
||||||
|
margin-top: 35px;
|
||||||
|
padding: 0px 30px 10px 30px;
|
||||||
|
page-break-before: avoid;
|
||||||
|
page-break-after: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.items-table hr {
|
||||||
|
height: 0.1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.item-table-heading-left {
|
||||||
|
font-size: 13.5;
|
||||||
|
text-align: left;
|
||||||
|
color: rgba(0, 0, 0, 0.85);
|
||||||
|
padding: 5px;
|
||||||
|
padding-bottom: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.item-table-heading-right {
|
||||||
|
font-size: 13.5;
|
||||||
|
text-align: right;
|
||||||
|
color: rgba(0, 0, 0, 0.85);
|
||||||
|
padding: 5px;
|
||||||
|
padding-bottom: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
tr.item-table-heading-row th {
|
||||||
|
border-bottom: 0.620315px solid #E8E8E8;
|
||||||
|
font-size: 12px;
|
||||||
|
line-height: 18px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.item-table-heading-row {
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
tr.item-row td {
|
||||||
|
font-size: 12px;
|
||||||
|
line-height: 18px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.item-cell-left {
|
||||||
|
font-size: 13;
|
||||||
|
color: #040405;
|
||||||
|
text-align: left;
|
||||||
|
padding: 5px;
|
||||||
|
padding-top: 10px;
|
||||||
|
border-color: #d9d9d9;
|
||||||
|
}
|
||||||
|
|
||||||
|
.item-cell-right {
|
||||||
|
font-size: 13;
|
||||||
|
color: #040405;
|
||||||
|
text-align: right;
|
||||||
|
padding: 5px;
|
||||||
|
padding-top: 10px;
|
||||||
|
border-color: #d9d9d9;
|
||||||
|
}
|
||||||
|
|
||||||
|
.item-description {
|
||||||
|
color: #595959;
|
||||||
|
font-size: 9px;
|
||||||
|
line-height: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.item-table-group-total {
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: bold;
|
||||||
|
text-align: right;
|
||||||
|
color: rgba(0, 0, 0, 0.85);
|
||||||
|
padding: 5px;
|
||||||
|
padding-bottom: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
@if (App::isLocale('th'))
|
@if (App::isLocale('th'))
|
||||||
@@ -158,33 +235,28 @@
|
|||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
<p class="expenses-title">@lang('pdf_expenses_label')</p>
|
<p class="expenses-title">@lang('pdf_expenses_label')</p>
|
||||||
<div class="expenses-table-container">
|
@foreach ($expenseGroups as $group)
|
||||||
<table class="expenses-table">
|
<p class="expense-title">{{ $group['name'] }}</p>
|
||||||
@foreach ($expenseCategories as $expenseCategory)
|
<table width="100%" style="margin-bottom:18px;">
|
||||||
<tr>
|
<tr class="item-table-heading-row">
|
||||||
<td>
|
<th style="width: 15%;" class="text-left item-table-heading-left">@lang('Date')</th>
|
||||||
<p class="expense-title">
|
<th style="width: 70%;" class="text-left item-table-heading-left">@lang('Note')</th>
|
||||||
{{ $expenseCategory->category->name }}
|
<th style="width: 15%;" class="text-right item-table-heading-right">@lang('Amount')</th>
|
||||||
</p>
|
</tr>
|
||||||
</td>
|
@foreach ($group['expenses'] as $expense)
|
||||||
<td>
|
<tr class="item-row">
|
||||||
<p class="expense-amount">
|
<td style="width: 15%;" class="text-left item-cell-left">{{ $expense->formatted_expense_date }}</td>
|
||||||
{!! format_money_pdf($expenseCategory->total_amount, $currency) !!}
|
<td style="width: 70%;" class="text-left item-cell-left">{{ $expense->notes ? $expense->notes : '-' }}</td>
|
||||||
</p>
|
<td style="width: 15%;" class="text-right item-cell-right">{!! format_money_pdf($expense->base_amount, $currency) !!}</td>
|
||||||
</td>
|
|
||||||
</tr>
|
</tr>
|
||||||
@endforeach
|
@endforeach
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<table class="expense-total-table">
|
</table>
|
||||||
<tr>
|
<div class="item-table-group-total">
|
||||||
<td class="expense-total-cell">
|
<p>@lang('Group Total:') <span style="color: #5851D8;">{!! format_money_pdf($group['total'], $currency) !!}</span></p>
|
||||||
<p class="expense-total">{!! format_money_pdf($totalExpense, $currency) !!}</p>
|
</div>
|
||||||
</td>
|
@endforeach
|
||||||
</tr>
|
</div>
|
||||||
</table>
|
|
||||||
<table class="report-footer">
|
<table class="report-footer">
|
||||||
<tr>
|
<tr>
|
||||||
<td>
|
<td>
|
||||||
|
|||||||
Reference in New Issue
Block a user