akaunting 3.0 (the last dance)

This commit is contained in:
Burak Civan
2022-06-01 10:15:55 +03:00
parent cead09f6d4
commit d9c0764572
3812 changed files with 126831 additions and 102949 deletions

View File

@ -9,9 +9,17 @@ class AccountBalance extends Widget
{
public $default_name = 'widgets.account_balance';
public $description = 'widgets.description.account_balance';
public $report_class = 'App\Reports\IncomeExpense';
public function show()
{
$accounts = Account::with('income_transactions', 'expense_transactions')->enabled()->take(5)->get();
$accounts = Account::with('income_transactions', 'expense_transactions')->enabled()->take(5)->get()->map(function($account) {
$account->balance_formatted = money($account->balance, $account->currency_code, true);
return $account;
})->all();
return $this->view('widgets.account_balance', [
'accounts' => $accounts,

24
app/Widgets/BankFeeds.php Normal file
View File

@ -0,0 +1,24 @@
<?php
namespace App\Widgets;
use App\Abstracts\Widget;
use App\Traits\Cloud;
use App\Traits\Modules;
class BankFeeds extends Widget
{
use Cloud, Modules;
public $default_name = 'widgets.bank_feeds';
public function show()
{
$module = $this->getModulesByWidget('bank-feeds');
return $this->view('widgets.bank_feeds', [
'module' => $module,
'learn_more_url' => $this->getCloudBankFeedsUrl(),
]);
}
}

View File

@ -2,12 +2,12 @@
namespace App\Widgets;
use Akaunting\Apexcharts\Charts as Apexcharts;
use App\Abstracts\Widget;
use App\Models\Banking\Transaction;
use App\Traits\Currencies;
use App\Traits\DateTime;
use App\Utilities\Chartjs;
use Date;
use App\Utilities\Date;
class CashFlow extends Widget
{
@ -16,10 +16,68 @@ class CashFlow extends Widget
public $default_name = 'widgets.cash_flow';
public $default_settings = [
'width' => 'col-md-12',
'width' => 'w-full my-8 px-12',
];
public $description = 'widgets.description.cash_flow';
public $report_class = 'Modules\CashFlowStatement\Reports\CashFlowStatement';
public $start_date;
public $end_date;
public $period;
public function show()
{
$this->setFilter();
$labels = $this->getLabels();
$income = array_values($this->calculateTotals('income'));
$expense = array_values($this->calculateTotals('expense'));
$profit = array_values($this->calculateProfit($income, $expense));
$colors = $this->getColors();
$options = [
'chart' => [
'stacked' => true,
],
'plotOptions' => [
'bar' => [
'columnWidth' => '40%',
],
],
'legend' => [
'position' => 'top',
],
];
$chart = new Apexcharts();
$chart->setType('line')
->setOptions($options)
->setLabels(array_values($labels))
->setColors($colors)
->setDataset(trans('general.incoming'), 'column', $income)
->setDataset(trans('general.outgoing'), 'column', $expense)
->setDataset(trans_choice('general.profits', 1), 'line', $profit);
$totals = [
'incoming' => money(array_sum($income), setting('default.currency'), true),
'outgoing' => money(abs(array_sum($expense)), setting('default.currency'), true),
'profit' => money(array_sum($profit), setting('default.currency'), true),
];
return $this->view('widgets.cash_flow', [
'chart' => $chart,
'totals' => $totals,
]);
}
public function setFilter(): void
{
$financial_start = $this->getFinancialStart()->format('Y-m-d');
@ -28,31 +86,35 @@ class CashFlow extends Widget
$year_start = $financial_start;
}
$start = Date::parse(request('start_date', $year_start));
$end = Date::parse(request('end_date', Date::parse($year_start)->addYear(1)->subDays(1)->format('Y-m-d')));
$period = request('period', 'month');
$this->start_date = Date::parse(request('start_date', $year_start));
$this->end_date = Date::parse(request('end_date', Date::parse($year_start)->addYear(1)->subDays(1)->format('Y-m-d')));
$this->period = request('period', 'month');
}
public function getLabels(): array
{
$range = request('range', 'custom');
$start_month = $start->month;
$end_month = $end->month;
$start_month = $this->start_date->month;
$end_month = $this->end_date->month;
// Monthly
$labels = [];
$s = clone $start;
$s = clone $this->start_date;
if ($range == 'last_12_months') {
$end_month = 12;
$start_month = 0;
} elseif ($range == 'custom') {
$end_month = $end->diffInMonths($start);
$end_month = $this->end_date->diffInMonths($this->start_date);
$start_month = 0;
}
for ($j = $end_month; $j >= $start_month; $j--) {
$labels[$end_month - $j] = $s->format('M Y');
if ($period == 'month') {
if ($this->period == 'month') {
$s->addMonth();
} else {
$s->addMonths(3);
@ -60,74 +122,43 @@ class CashFlow extends Widget
}
}
$income = $this->calculateTotals('income', $start, $end, $period);
$expense = $this->calculateTotals('expense', $start, $end, $period);
$profit = $this->calculateProfit($income, $expense);
$chart = new Chartjs();
$chart->type('line')
->width(0)
->height(300)
->options($this->getLineChartOptions())
->labels(array_values($labels));
$chart->dataset(trans_choice('general.incomes', 1), 'line', array_values($income))
->backgroundColor('#328aef')
->color('#328aef')
->options([
'borderWidth' => 4,
'pointStyle' => 'line',
])
->fill(false);
$chart->dataset(trans_choice('general.expenses', 2), 'line', array_values($expense))
->backgroundColor('#ef3232')
->color('#ef3232')
->options([
'borderWidth' => 4,
'pointStyle' => 'line',
])
->fill(false);
$chart->dataset(trans_choice('general.profits', 1), 'line', array_values($profit))
->backgroundColor('#6da252')
->color('#6da252')
->options([
'borderWidth' => 4,
'pointStyle' => 'line',
])
->fill(false);
return $this->view('widgets.line_chart', [
'chart' => $chart,
]);
return $labels;
}
private function calculateTotals($type, $start, $end, $period)
public function getColors(): array
{
return [
'#8bb475',
'#fb7185',
'#7779A2',
];
}
private function calculateTotals($type): array
{
$totals = [];
$date_format = 'Y-m';
if ($period == 'month') {
if ($this->period == 'month') {
$n = 1;
$start_date = $start->format($date_format);
$end_date = $end->format($date_format);
$start_date = $this->start_date->format($date_format);
$end_date = $this->end_date->format($date_format);
$next_date = $start_date;
} else {
$n = 3;
$start_date = $start->quarter;
$end_date = $end->quarter;
$start_date = $this->start_date->quarter;
$end_date = $this->end_date->quarter;
$next_date = $start_date;
}
$s = clone $start;
$s = clone $this->start_date;
//$totals[$start_date] = 0;
while ($next_date <= $end_date) {
$totals[$next_date] = 0;
if ($period == 'month') {
if ($this->period == 'month') {
$next_date = $s->addMonths($n)->format($date_format);
} else {
if (isset($totals[4])) {
@ -138,17 +169,21 @@ class CashFlow extends Widget
}
}
$items = $this->applyFilters(Transaction::$type()->whereBetween('paid_at', [$start, $end])->isNotTransfer())->get();
$items = $this->applyFilters(Transaction::$type()->whereBetween('paid_at', [$this->start_date, $this->end_date])->isNotTransfer())->get();
$this->setTotals($totals, $items, $date_format, $period);
$this->setTotals($totals, $items, $date_format);
return $totals;
}
private function setTotals(&$totals, $items, $date_format, $period)
private function setTotals(&$totals, $items, $date_format): void
{
$type = 'income';
foreach ($items as $item) {
if ($period == 'month') {
$type = $item->type;
if ($this->period == 'month') {
$i = Date::parse($item->paid_at)->format($date_format);
} else {
$i = Date::parse($item->paid_at)->quarter;
@ -164,20 +199,24 @@ class CashFlow extends Widget
$precision = config('money.' . setting('default.currency') . '.precision');
foreach ($totals as $key => $value) {
if ($type == 'expense') {
$value = -1 * $value;
}
$totals[$key] = round($value, $precision);
}
}
private function calculateProfit($incomes, $expenses)
private function calculateProfit($incomes, $expenses): array
{
$profit = [];
$precision = config('money.' . setting('default.currency') . '.precision');
foreach ($incomes as $key => $income) {
if ($income > 0 && $income > $expenses[$key]) {
$profit[$key] = $income - $expenses[$key];
} else {
$profit[$key] = 0;
}
$value = $income - abs($expenses[$key]);
$profit[$key] = round($value, $precision);
}
return $profit;

View File

@ -9,13 +9,13 @@ class ExpensesByCategory extends Widget
{
public $default_name = 'widgets.expenses_by_category';
public $default_settings = [
'width' => 'col-md-6',
];
public $description = 'widgets.description.expenses_by_category';
public $report_class = 'App\Reports\ExpenseSummary';
public function show()
{
Category::with('expense_transactions')->expense()->each(function ($category) {
Category::withSubCategory()->with('expense_transactions')->expense()->each(function ($category) {
$amount = 0;
$this->applyFilters($category->expense_transactions)->each(function ($transaction) use (&$amount) {
@ -25,7 +25,7 @@ class ExpensesByCategory extends Widget
$this->addMoneyToDonut($category->color, $amount, $category->name);
});
$chart = $this->getDonutChart(trans_choice('general.expenses', 2), 0, 160, 6);
$chart = $this->getDonutChart(trans_choice('general.expenses', 2), '100%', 300, 6);
return $this->view('widgets.donut_chart', [
'chart' => $chart,

View File

@ -1,34 +0,0 @@
<?php
namespace App\Widgets;
use App\Abstracts\Widget;
use App\Models\Setting\Category;
class IncomeByCategory extends Widget
{
public $default_name = 'widgets.income_by_category';
public $default_settings = [
'width' => 'col-md-6',
];
public function show()
{
Category::with('income_transactions')->income()->each(function ($category) {
$amount = 0;
$this->applyFilters($category->income_transactions)->each(function ($transaction) use (&$amount) {
$amount += $transaction->getAmountConvertedToDefault();
});
$this->addMoneyToDonut($category->color, $amount, $category->name);
});
$chart = $this->getDonutChart(trans_choice('general.incomes', 1), 0, 160, 6);
return $this->view('widgets.donut_chart', [
'chart' => $chart,
]);
}
}

View File

@ -1,20 +0,0 @@
<?php
namespace App\Widgets;
use App\Abstracts\Widget;
use App\Models\Banking\Transaction;
class LatestExpenses extends Widget
{
public $default_name = 'widgets.latest_expenses';
public function show()
{
$transactions = $this->applyFilters(Transaction::with('category')->expense()->orderBy('paid_at', 'desc')->isNotTransfer()->take(5))->get();
return $this->view('widgets.latest_expenses', [
'transactions' => $transactions,
]);
}
}

View File

@ -1,20 +0,0 @@
<?php
namespace App\Widgets;
use App\Abstracts\Widget;
use App\Models\Banking\Transaction;
class LatestIncome extends Widget
{
public $default_name = 'widgets.latest_income';
public function show()
{
$transactions = $this->applyFilters(Transaction::with('category')->income()->orderBy('paid_at', 'desc')->isNotTransfer()->take(5))->get();
return $this->view('widgets.latest_income', [
'transactions' => $transactions,
]);
}
}

79
app/Widgets/Payables.php Normal file
View File

@ -0,0 +1,79 @@
<?php
namespace App\Widgets;
use App\Abstracts\Widget;
use App\Models\Document\Document;
use App\Utilities\Date;
class Payables extends Widget
{
public $default_name = 'widgets.payables';
public $description = 'widgets.description.payables';
public $report_class = 'Modules\AgedReceivablesPayables\Reports\AgedPayables';
public function show()
{
$open = $overdue = 0;
$periods = [
'overdue_1_30' => 0,
'overdue_30_60' => 0,
'overdue_60_90' => 0,
'overdue_90_un' => 0,
];
$query = Document::bill()->with('transactions')->accrued()->notPaid();
$this->applyFilters($query, ['date_field' => 'issued_at'])->each(function ($bill) use (&$open, &$overdue, &$periods) {
list($open_tmp, $overdue_tmp) = $this->calculateDocumentTotals($bill);
$open += $open_tmp;
$overdue += $overdue_tmp;
foreach ($periods as $period_name => $period_amount) {
$arr = explode('_', $period_name);
if ($arr[2] == 'un') {
$arr[2] = '9999';
}
$start = Date::today()->subDays($arr[2])->toDateString() . ' 00:00:00';
$end = Date::today()->subDays($arr[1])->toDateString() . ' 23:59:59';
if (! Date::parse($bill->due_at)->isBetween($start, $end)) {
continue;
}
$periods[$period_name] += $overdue_tmp;
}
});
foreach ($periods as $period_name => $period_amount) {
$periods[$period_name] = money($period_amount, setting('default.currency'), true);
}
$has_progress = !empty($open) || !empty($overdue);
$progress = !empty($open) ? (int) ($open * 100) / ($open + $overdue) : 0;
$grand = $open + $overdue;
$totals = [
'grand' => money($grand, setting('default.currency'), true),
'open' => money($open, setting('default.currency'), true),
'overdue' => money($overdue, setting('default.currency'), true),
];
$grand_total_text = trans('widgets.total_unpaid_bills');
return $this->view('widgets.receivables_payables', [
'totals' => $totals,
'has_progress' => $has_progress,
'progress' => $progress,
'periods' => $periods,
'grand_total_text' => $grand_total_text,
]);
}
}

217
app/Widgets/ProfitLoss.php Normal file
View File

@ -0,0 +1,217 @@
<?php
namespace App\Widgets;
use App\Abstracts\Widget;
use App\Utilities\Recurring;
use App\Models\Document\Document;
use App\Models\Banking\Transaction;
use Akaunting\Apexcharts\Charts as Apexcharts;
use App\Traits\Currencies;
use App\Traits\DateTime;
use App\Utilities\Date;
class ProfitLoss extends Widget
{
use Currencies, DateTime;
public $default_name = 'widgets.profit_loss';
public $description = 'widgets.description.profit_loss';
public $report_class = 'App\Reports\ProfitLoss';
public $start_date;
public $end_date;
public $period;
public function show()
{
$this->setFilter();
$labels = $this->getLabels();
$income = $this->getIncome();
$expense = $this->getExpense();
$colors = $this->getColors();
$chart = new Apexcharts();
$options = [
'legend' => [
'position' => 'top',
'markers' => [
'radius' => '12',
],
],
];
$chart->setType('bar')
->setOptions($options)
->setLabels(array_values($labels))
->setColors($colors)
->setDataset(trans_choice('general.incomes', 1), 'column', array_values($income))
->setDataset(trans_choice('general.expenses', 1), 'column', array_values($expense));
return $this->view('widgets.bar_chart', [
'chart' => $chart,
]);
}
public function setFilter(): void
{
$financial_start = $this->getFinancialStart()->format('Y-m-d');
// check and assign year start
if (($year_start = Date::today()->startOfYear()->format('Y-m-d')) !== $financial_start) {
$year_start = $financial_start;
}
$this->start_date = Date::parse(request('start_date', $year_start));
$this->end_date = Date::parse(request('end_date', Date::parse($year_start)->addYear(1)->subDays(1)->format('Y-m-d')));
$this->period = request('period', 'month');
}
public function getLabels(): array
{
$range = request('range', 'custom');
$start_month = $this->start_date->month;
$end_month = $this->end_date->month;
// Monthly
$labels = [];
$s = clone $this->start_date;
if ($range == 'last_12_months') {
$end_month = 12;
$start_month = 0;
} elseif ($range == 'custom') {
$end_month = $this->end_date->diffInMonths($this->start_date);
$start_month = 0;
}
for ($j = $end_month; $j >= $start_month; $j--) {
$labels[$end_month - $j] = $s->format('M Y');
if ($this->period == 'month') {
$s->addMonth();
} else {
$s->addMonths(3);
$j -= 2;
}
}
return $labels;
}
public function getIncome(): array
{
// Invoices
$query = Document::invoice()->with('recurring', 'totals', 'transactions')->accrued();
$invoices = $this->applyFilters($query, ['date_field' => 'issued_at'])->get();
Recurring::reflect($invoices, 'issued_at');
$totals = $this->calculateTotals($invoices, 'issued_at');
// Transactions
$query = Transaction::with('recurring')->income()->isNotDocument()->isNotTransfer();
$transactions = $this->applyFilters($query, ['date_field' => 'paid_at'])->get();
Recurring::reflect($transactions, 'paid_at');
$totals = $this->calculateTotals($transactions, 'paid_at', $totals);
return $totals;
}
public function getExpense(): array
{
// Bills
$query = Document::bill()->with('recurring', 'totals', 'transactions')->accrued();
$bills = $this->applyFilters($query, ['date_field' => 'issued_at'])->get();
Recurring::reflect($bills, 'issued_at');
$totals = $this->calculateTotals($bills, 'issued_at');
// Transactions
$query = Transaction::with('recurring')->expense()->isNotDocument()->isNotTransfer();
$transactions = $this->applyFilters($query, ['date_field' => 'paid_at'])->get();
Recurring::reflect($transactions, 'paid_at');
$totals = $this->calculateTotals($transactions, 'paid_at', $totals);
return $totals;
}
public function getColors(): array
{
return [
'#8bb475',
'#fb7185',
];
}
public function calculateTotals($items, $date_field, $totals = []): array
{
$date_format = 'Y-m';
if ($this->period == 'month') {
$n = 1;
$start_date = $this->start_date->format($date_format);
$end_date = $this->end_date->format($date_format);
$next_date = $start_date;
} else {
$n = 3;
$start_date = $this->start_date->quarter;
$end_date = $this->end_date->quarter;
$next_date = $start_date;
}
$s = clone $this->start_date;
//$totals[$start_date] = 0;
while ($next_date <= $end_date) {
if (! isset($totals[$next_date])) {
$totals[$next_date] = 0;
}
if ($this->period == 'month') {
$next_date = $s->addMonths($n)->format($date_format);
} else {
if (isset($totals[4])) {
break;
}
$next_date = $s->addMonths($n)->quarter;
}
}
$this->setTotals($totals, $items, $date_field, $date_format);
return $totals;
}
public function setTotals(&$totals, $items, $date_field, $date_format): void
{
foreach ($items as $item) {
if ($this->period == 'month') {
$i = Date::parse($item->$date_field)->format($date_format);
} else {
$i = Date::parse($item->$date_field)->quarter;
}
if (! isset($totals[$i])) {
continue;
}
$totals[$i] += $item->getAmountConvertedToDefault();
}
$precision = config('money.' . setting('default.currency') . '.precision');
foreach ($totals as $key => $value) {
$totals[$key] = round($value, $precision);
}
}
}

View File

@ -0,0 +1,79 @@
<?php
namespace App\Widgets;
use App\Abstracts\Widget;
use App\Models\Document\Document;
use App\Utilities\Date;
class Receivables extends Widget
{
public $default_name = 'widgets.receivables';
public $description = 'widgets.description.receivables';
public $report_class = 'Modules\AgedReceivablesPayables\Reports\AgedReceivables';
public function show()
{
$open = $overdue = 0;
$periods = [
'overdue_1_30' => 0,
'overdue_30_60' => 0,
'overdue_60_90' => 0,
'overdue_90_un' => 0,
];
$query = Document::invoice()->with('transactions')->accrued()->notPaid();
$this->applyFilters($query, ['date_field' => 'issued_at'])->each(function ($invoice) use (&$open, &$overdue, &$periods) {
list($open_tmp, $overdue_tmp) = $this->calculateDocumentTotals($invoice);
$open += $open_tmp;
$overdue += $overdue_tmp;
foreach ($periods as $period_name => $period_amount) {
$arr = explode('_', $period_name);
if ($arr[2] == 'un') {
$arr[2] = '9999';
}
$start = Date::today()->subDays($arr[2])->toDateString() . ' 00:00:00';
$end = Date::today()->subDays($arr[1])->toDateString() . ' 23:59:59';
if (! Date::parse($invoice->due_at)->isBetween($start, $end)) {
continue;
}
$periods[$period_name] += $overdue_tmp;
}
});
foreach ($periods as $period_name => $period_amount) {
$periods[$period_name] = money($period_amount, setting('default.currency'), true);
}
$has_progress = !empty($open) || !empty($overdue);
$progress = !empty($open) ? (int) ($open * 100) / ($open + $overdue) : 0;
$grand = $open + $overdue;
$totals = [
'grand' => money($grand, setting('default.currency'), true),
'open' => money($open, setting('default.currency'), true),
'overdue' => money($overdue, setting('default.currency'), true),
];
$grand_total_text = trans('widgets.total_unpaid_invoices');
return $this->view('widgets.receivables_payables', [
'totals' => $totals,
'has_progress' => $has_progress,
'progress' => $progress,
'periods' => $periods,
'grand_total_text' => $grand_total_text,
]);
}
}

View File

@ -1,56 +0,0 @@
<?php
namespace App\Widgets;
use App\Abstracts\Widget;
use App\Models\Banking\Transaction;
use App\Models\Document\Document;
class TotalExpenses extends Widget
{
public $default_name = 'widgets.total_expenses';
public $views = [
'header' => 'partials.widgets.stats_header',
];
public function show()
{
$current = $open = $overdue = 0;
$this->applyFilters(Transaction::expense()->isNotTransfer())->each(function ($transaction) use (&$current) {
$current += $transaction->getAmountConvertedToDefault();
});
$this->applyFilters(
Document::bill()->with('transactions')->accrued()->notPaid(),
['date_field' => 'created_at']
)->each(
function ($bill) use (&$open, &$overdue) {
list($open_tmp, $overdue_tmp) = $this->calculateDocumentTotals($bill);
$open += $open_tmp;
$overdue += $overdue_tmp;
}
);
$grand = $current + $open + $overdue;
$progress = 100;
if (!empty($open) && !empty($overdue)) {
$progress = (int) ($open * 100) / ($open + $overdue);
}
$totals = [
'grand' => money($grand, setting('default.currency'), true),
'open' => money($open, setting('default.currency'), true),
'overdue' => money($overdue, setting('default.currency'), true),
'progress' => $progress,
];
return $this->view('widgets.total_expenses', [
'totals' => $totals,
]);
}
}

View File

@ -1,56 +0,0 @@
<?php
namespace App\Widgets;
use App\Abstracts\Widget;
use App\Models\Banking\Transaction;
use App\Models\Document\Document;
class TotalIncome extends Widget
{
public $default_name = 'widgets.total_income';
public $views = [
'header' => 'partials.widgets.stats_header',
];
public function show()
{
$current = $open = $overdue = 0;
$this->applyFilters(Transaction::income()->isNotTransfer())->each(function ($transaction) use (&$current) {
$current += $transaction->getAmountConvertedToDefault();
});
$this->applyFilters(
Document::invoice()->with('transactions')->accrued()->notPaid(),
['date_field' => 'created_at']
)->each(
function ($invoice) use (&$open, &$overdue) {
list($open_tmp, $overdue_tmp) = $this->calculateDocumentTotals($invoice);
$open += $open_tmp;
$overdue += $overdue_tmp;
}
);
$grand = $current + $open + $overdue;
$progress = 100;
if (!empty($open) && !empty($overdue)) {
$progress = (int) ($open * 100) / ($open + $overdue);
}
$totals = [
'grand' => money($grand, setting('default.currency'), true),
'open' => money($open, setting('default.currency'), true),
'overdue' => money($overdue, setting('default.currency'), true),
'progress' => $progress,
];
return $this->view('widgets.total_income', [
'totals' => $totals,
]);
}
}

View File

@ -1,79 +0,0 @@
<?php
namespace App\Widgets;
use App\Abstracts\Widget;
use App\Models\Banking\Transaction;
use App\Models\Document\Document;
class TotalProfit extends Widget
{
public $default_name = 'widgets.total_profit';
public $views = [
'header' => 'partials.widgets.stats_header',
];
public function show()
{
$current_income = $open_invoice = $overdue_invoice = 0;
$current_expenses = $open_bill = $overdue_bill = 0;
$this->applyFilters(Transaction::isNotTransfer())->each(function ($transaction) use (&$current_income, &$current_expenses) {
$amount = $transaction->getAmountConvertedToDefault();
if ($transaction->type == 'income') {
$current_income += $amount;
} else {
$current_expenses += $amount;
}
});
$this->applyFilters(
Document::invoice()->with('transactions')->accrued()->notPaid(),
['date_field' => 'created_at']
)->each(
function ($invoice) use (&$open_invoice, &$overdue_invoice) {
list($open_tmp, $overdue_tmp) = $this->calculateDocumentTotals($invoice);
$open_invoice += $open_tmp;
$overdue_invoice += $overdue_tmp;
}
);
$this->applyFilters(
Document::bill()->with('transactions')->accrued()->notPaid(),
['date_field' => 'created_at']
)->each(
function ($bill) use (&$open_bill, &$overdue_bill) {
list($open_tmp, $overdue_tmp) = $this->calculateDocumentTotals($bill);
$open_bill += $open_tmp;
$overdue_bill += $overdue_tmp;
}
);
$current = $current_income - $current_expenses;
$open = $open_invoice - $open_bill;
$overdue = $overdue_invoice - $overdue_bill;
$grand = $current + $open + $overdue;
$progress = 100;
if (!empty($open) && !empty($overdue)) {
$progress = (int) ($open * 100) / ($open + $overdue);
}
$totals = [
'grand' => money($grand, setting('default.currency'), true),
'open' => money($open, setting('default.currency'), true),
'overdue' => money($overdue, setting('default.currency'), true),
'progress' => $progress,
];
return $this->view('widgets.total_profit', [
'totals' => $totals,
]);
}
}