Merge pull request #1190 from denisdulici/master

Refactored report listener
This commit is contained in:
Denis Duliçi 2020-01-27 22:44:36 +03:00 committed by GitHub
commit 50ea418c5d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
31 changed files with 484 additions and 200 deletions

View File

@ -6,11 +6,12 @@ use App\Models\Banking\Account;
use App\Models\Common\Contact;
use App\Models\Setting\Category;
use App\Traits\Contacts;
use App\Traits\DateTime;
use Date;
abstract class Report
{
use Contacts;
use Contacts, DateTime;
protected $classes = [];
@ -19,6 +20,7 @@ abstract class Report
'App\Events\Common\ReportFilterApplying',
'App\Events\Common\ReportGroupShowing',
'App\Events\Common\ReportGroupApplying',
'App\Events\Common\ReportRowsShowing',
];
public function skipThisClass($event)
@ -26,6 +28,13 @@ abstract class Report
return (empty($event->class) || !in_array(get_class($event->class), $this->classes));
}
public function skipRowsShowing($event, $group)
{
return $this->skipThisClass($event)
|| empty($event->class->model->settings->group)
|| ($event->class->model->settings->group != $group);
}
public function getYears()
{
$now = Date::now();
@ -68,7 +77,7 @@ abstract class Report
public function getCategories($types)
{
return Category::type($types)->enabled()->orderBy('name')->pluck('name', 'id')->toArray();
return Category::type($types)->orderBy('name')->pluck('name', 'id')->toArray();
}
public function getCustomers()
@ -83,7 +92,7 @@ abstract class Report
public function getContacts($types)
{
return Contact::type($types)->enabled()->orderBy('name')->pluck('name', 'id')->toArray();
return Contact::type($types)->orderBy('name')->pluck('name', 'id')->toArray();
}
public function applyDateFilter($event)
@ -112,6 +121,8 @@ abstract class Report
}
$event->model->account_id = $transaction->account_id;
break;
}
}
@ -133,6 +144,42 @@ abstract class Report
}
}
public function setRowNamesAndValues($event, $rows)
{
foreach ($event->class->dates as $date) {
foreach ($event->class->tables as $table) {
foreach ($rows as $id => $name) {
$event->class->row_names[$table][$id] = $name;
$event->class->row_values[$table][$id][$date] = 0;
}
}
}
}
public function getFormattedDate($event, $date)
{
if (empty($event->class->model->settings->period)) {
return $date->copy()->format('Y-m-d');
}
switch ($event->class->model->settings->period) {
case 'yearly':
$d = $date->copy()->format($this->getYearlyDateFormat());
break;
case 'quarterly':
$start = $date->copy()->startOfQuarter()->format($this->getQuarterlyDateFormat());
$end = $date->copy()->endOfQuarter()->format($this->getQuarterlyDateFormat());
$d = $start . '-' . $end;
break;
default:
$d = $date->copy()->format($this->getMonthlyDateFormat());
break;
}
return $d;
}
/**
* Register the listeners for the subscriber.
*

View File

@ -6,6 +6,7 @@ use App\Events\Common\ReportFilterShowing;
use App\Events\Common\ReportFilterApplying;
use App\Events\Common\ReportGroupApplying;
use App\Events\Common\ReportGroupShowing;
use App\Events\Common\ReportRowsShowing;
use App\Exports\Common\Reports as Export;
use App\Models\Banking\Transaction;
use App\Models\Common\Report as Model;
@ -36,12 +37,16 @@ abstract class Report
public $dates = [];
public $rows = [];
public $row_names = [];
public $totals = [];
public $row_values = [];
public $footer_totals = [];
public $filters = [];
public $loaded = false;
public $indents = [
'table_header' => '0px',
'table_rows' => '0px',
@ -62,7 +67,7 @@ abstract class Report
'datasets' => [],
];
public function __construct(Model $model = null, $get_totals = true)
public function __construct(Model $model = null, $load_data = true)
{
$this->setGroups();
@ -72,20 +77,28 @@ abstract class Report
$this->model = $model;
if (!$load_data) {
return;
}
$this->load();
}
abstract public function getTotals();
public function load()
{
$this->setYear();
$this->setViews();
$this->setTables();
$this->setDates();
$this->setFilters();
$this->setRows();
$this->getTotals();
if ($get_totals) {
$this->getTotals();
}
$this->loaded = true;
}
abstract public function getTotals();
public function getDefaultName()
{
if (!empty($this->default_name)) {
@ -107,9 +120,13 @@ abstract class Report
public function getTotal()
{
if (!$this->loaded) {
$this->load();
}
$sum = 0;
foreach ($this->totals as $total) {
foreach ($this->footer_totals as $total) {
$sum += is_array($total) ? array_sum($total) : $total;
}
@ -118,21 +135,6 @@ abstract class Report
return $total;
}
public function getTableRowList()
{
$group_prl = Str::plural($this->model->settings->group);
if ($group_filter = request($group_prl)) {
$rows = collect($this->filters[$group_prl])->filter(function ($value, $key) use ($group_filter) {
return in_array($key, $group_filter);
});
} else {
$rows = $this->filters[$group_prl];
}
return $rows;
}
public function getChart()
{
$chart = new Chartjs();
@ -158,7 +160,7 @@ abstract class Report
->fill(false);
}
} else {
foreach ($this->totals as $total) {
foreach ($this->footer_totals as $total) {
$chart->dataset($this->model->name, 'line', array_values($total))
->backgroundColor(isset($config['backgroundColor']) ? $config['backgroundColor'] : '#6da252')
->color(isset($config['color']) ? $config['color'] : '#6da252')
@ -214,12 +216,16 @@ abstract class Report
public function setTables()
{
$this->tables = [
'default' => 'default'
'default' => 'default',
];
}
public function setDates()
{
if (empty($this->model->settings->period)) {
return;
}
$function = 'sub' . ucfirst(str_replace('ly', '', $this->model->settings->period));
$start = $this->getFinancialStart()->copy()->$function();
@ -234,7 +240,7 @@ abstract class Report
$this->dates[$j] = $date;
foreach ($this->tables as $table) {
$this->totals[$table][$date] = 0;
$this->footer_totals[$table][$date] = 0;
}
$j += 11;
@ -248,7 +254,7 @@ abstract class Report
$this->dates[$j] = $date;
foreach ($this->tables as $table) {
$this->totals[$table][$date] = 0;
$this->footer_totals[$table][$date] = 0;
}
$j += 2;
@ -262,7 +268,7 @@ abstract class Report
$this->dates[$j] = $date;
foreach ($this->tables as $table) {
$this->totals[$table][$date] = 0;
$this->footer_totals[$table][$date] = 0;
}
break;
@ -284,15 +290,7 @@ abstract class Report
public function setRows()
{
$list = $this->getTableRowList();
foreach ($this->dates as $date) {
foreach ($this->tables as $table) {
foreach ($list as $id => $name) {
$this->rows[$table][$id][$date] = 0;
}
}
}
event(new ReportRowsShowing($this));
}
public function setTotals($items, $date_field, $check_type = false, $table = 'default')
@ -305,31 +303,26 @@ abstract class Report
$id_field = $this->model->settings->group . '_id';
if (!isset($this->rows[$table][$item->$id_field]) ||
!isset($this->rows[$table][$item->$id_field][$date]) ||
!isset($this->totals[$table][$date]))
if (
!isset($this->row_values[$table][$item->$id_field])
|| !isset($this->row_values[$table][$item->$id_field][$date])
|| !isset($this->footer_totals[$table][$date]))
{
continue;
}
$amount = $item->getAmountConvertedToDefault();
if (!$check_type) {
$this->rows[$table][$item->$id_field][$date] += $amount;
$type = (($item instanceof Invoice) || (($item instanceof Transaction) && ($item->type == 'income'))) ? 'income' : 'expense';
$this->totals[$table][$date] += $amount;
if (($check_type == false) || ($type == 'income')) {
$this->row_values[$table][$item->$id_field][$date] += $amount;
$this->footer_totals[$table][$date] += $amount;
} else {
$type = (($item instanceof Invoice) || (($item instanceof Transaction) && ($item->type == 'income'))) ? 'income' : 'expense';
$this->row_values[$table][$item->$id_field][$date] -= $amount;
if ($type == 'income') {
$this->rows[$table][$item->$id_field][$date] += $amount;
$this->totals[$table][$date] += $amount;
} else {
$this->rows[$table][$item->$id_field][$date] -= $amount;
$this->totals[$table][$date] -= $amount;
}
$this->footer_totals[$table][$date] -= $amount;
}
}
}

View File

@ -0,0 +1,22 @@
<?php
namespace App\Events\Common;
use Illuminate\Queue\SerializesModels;
class ReportRowsShowing
{
use SerializesModels;
public $class;
/**
* Create a new event instance.
*
* @param $class
*/
public function __construct($class)
{
$this->class = $class;
}
}

View File

@ -6,6 +6,7 @@ use App\Abstracts\Listeners\Report as Listener;
use App\Events\Common\ReportFilterShowing;
use App\Events\Common\ReportGroupApplying;
use App\Events\Common\ReportGroupShowing;
use App\Events\Common\ReportRowsShowing;
class AddAccountsToReports extends Listener
{
@ -13,8 +14,6 @@ class AddAccountsToReports extends Listener
'App\Reports\IncomeSummary',
'App\Reports\ExpenseSummary',
'App\Reports\IncomeExpenseSummary',
'App\Reports\ProfitLoss',
'App\Reports\TaxSummary',
];
/**
@ -61,4 +60,27 @@ class AddAccountsToReports extends Listener
$this->applyAccountGroup($event);
}
/**
* Handle rows showing event.
*
* @param $event
* @return void
*/
public function handleReportRowsShowing(ReportRowsShowing $event)
{
if ($this->skipRowsShowing($event, 'account')) {
return;
}
if ($accounts = request('accounts')) {
$rows = collect($event->class->filters['accounts'])->filter(function ($value, $key) use ($accounts) {
return in_array($key, $accounts);
});
} else {
$rows = $event->class->filters['accounts'];
}
$this->setRowNamesAndValues($event, $rows);
}
}

View File

@ -6,6 +6,7 @@ use App\Abstracts\Listeners\Report as Listener;
use App\Events\Common\ReportFilterShowing;
use App\Events\Common\ReportGroupApplying;
use App\Events\Common\ReportGroupShowing;
use App\Events\Common\ReportRowsShowing;
class AddCustomersToReports extends Listener
{
@ -58,4 +59,27 @@ class AddCustomersToReports extends Listener
$this->applyCustomerGroup($event);
}
/**
* Handle rows showing event.
*
* @param $event
* @return void
*/
public function handleReportRowsShowing(ReportRowsShowing $event)
{
if ($this->skipRowsShowing($event, 'customer')) {
return;
}
if ($customers = request('customers')) {
$rows = collect($event->class->filters['customers'])->filter(function ($value, $key) use ($customers) {
return in_array($key, $customers);
});
} else {
$rows = $event->class->filters['customers'];
}
$this->setRowNamesAndValues($event, $rows);
}
}

View File

@ -5,9 +5,14 @@ namespace App\Listeners\Common;
use App\Abstracts\Listeners\Report as Listener;
use App\Events\Common\ReportFilterShowing;
use App\Events\Common\ReportGroupShowing;
use App\Events\Common\ReportRowsShowing;
class AddExpenseCategoriesToReports extends Listener
{
protected $classes = [
'App\Reports\ExpenseSummary',
];
/**
* Handle filter showing event.
*
@ -16,18 +21,11 @@ class AddExpenseCategoriesToReports extends Listener
*/
public function handleReportFilterShowing(ReportFilterShowing $event)
{
$classes = [
'App\Reports\ExpenseSummary',
'App\Reports\IncomeExpenseSummary',
];
if (empty($event->class) || !in_array(get_class($event->class), $classes)) {
if ($this->skipThisClass($event)) {
return;
}
$categories = !empty($event->class->filters['categories']) ? $event->class->filters['categories'] : [];
$event->class->filters['categories'] = array_merge($categories, $this->getExpenseCategories());
$event->class->filters['categories'] = $this->getExpenseCategories();
}
/**
@ -38,17 +36,33 @@ class AddExpenseCategoriesToReports extends Listener
*/
public function handleReportGroupShowing(ReportGroupShowing $event)
{
$classes = [
'App\Reports\ExpenseSummary',
'App\Reports\IncomeExpenseSummary',
'App\Reports\ProfitLoss',
'App\Reports\TaxSummary',
];
if (empty($event->class) || !in_array(get_class($event->class), $classes)) {
if ($this->skipThisClass($event)) {
return;
}
$event->class->groups['category'] = trans_choice('general.categories', 1);
}
/**
* Handle rows showing event.
*
* @param $event
* @return void
*/
public function handleReportRowsShowing(ReportRowsShowing $event)
{
if ($this->skipRowsShowing($event, 'category')) {
return;
}
if ($categories = request('categories')) {
$rows = collect($event->class->filters['categories'])->filter(function ($value, $key) use ($categories) {
return in_array($key, $categories);
});
} else {
$rows = $event->class->filters['categories'];
}
$this->setRowNamesAndValues($event, $rows);
}
}

View File

@ -5,9 +5,14 @@ namespace App\Listeners\Common;
use App\Abstracts\Listeners\Report as Listener;
use App\Events\Common\ReportFilterShowing;
use App\Events\Common\ReportGroupShowing;
use App\Events\Common\ReportRowsShowing;
class AddIncomeCategoriesToReports extends Listener
{
protected $classes = [
'App\Reports\IncomeSummary',
];
/**
* Handle filter showing event.
*
@ -16,18 +21,11 @@ class AddIncomeCategoriesToReports extends Listener
*/
public function handleReportFilterShowing(ReportFilterShowing $event)
{
$classes = [
'App\Reports\IncomeSummary',
'App\Reports\IncomeExpenseSummary',
];
if (empty($event->class) || !in_array(get_class($event->class), $classes)) {
if ($this->skipThisClass($event)) {
return;
}
$categories = !empty($event->class->filters['categories']) ? $event->class->filters['categories'] : [];
$event->class->filters['categories'] = array_merge($categories, $this->getIncomeCategories());
$event->class->filters['categories'] = $this->getIncomeCategories();
}
/**
@ -38,17 +36,33 @@ class AddIncomeCategoriesToReports extends Listener
*/
public function handleReportGroupShowing(ReportGroupShowing $event)
{
$classes = [
'App\Reports\IncomeSummary',
'App\Reports\IncomeExpenseSummary',
'App\Reports\ProfitLoss',
'App\Reports\TaxSummary',
];
if (empty($event->class) || !in_array(get_class($event->class), $classes)) {
if ($this->skipThisClass($event)) {
return;
}
$event->class->groups['category'] = trans_choice('general.categories', 1);
}
/**
* Handle rows showing event.
*
* @param $event
* @return void
*/
public function handleReportRowsShowing(ReportRowsShowing $event)
{
if ($this->skipRowsShowing($event, 'category')) {
return;
}
if ($categories = request('categories')) {
$rows = collect($event->class->filters['categories'])->filter(function ($value, $key) use ($categories) {
return in_array($key, $categories);
});
} else {
$rows = $event->class->filters['categories'];
}
$this->setRowNamesAndValues($event, $rows);
}
}

View File

@ -0,0 +1,108 @@
<?php
namespace App\Listeners\Common;
use App\Abstracts\Listeners\Report as Listener;
use App\Events\Common\ReportFilterShowing;
use App\Events\Common\ReportGroupShowing;
use App\Events\Common\ReportRowsShowing;
use App\Models\Setting\Category;
class AddIncomeExpenseCategoriesToReports extends Listener
{
/**
* Handle filter showing event.
*
* @param $event
* @return void
*/
public function handleReportFilterShowing(ReportFilterShowing $event)
{
$classes = [
'App\Reports\IncomeExpenseSummary',
];
if (empty($event->class) || !in_array(get_class($event->class), $classes)) {
return;
}
$event->class->filters['categories'] = $this->getIncomeExpenseCategories();
}
/**
* Handle group showing event.
*
* @param $event
* @return void
*/
public function handleReportGroupShowing(ReportGroupShowing $event)
{
$classes = [
'App\Reports\IncomeExpenseSummary',
'App\Reports\ProfitLoss',
];
if (empty($event->class) || !in_array(get_class($event->class), $classes)) {
return;
}
$event->class->groups['category'] = trans_choice('general.categories', 1);
}
/**
* Handle records showing event.
*
* @param $event
* @return void
*/
public function handleReportRowsShowing(ReportRowsShowing $event)
{
if (
empty($event->class)
|| empty($event->class->model->settings->group)
|| ($event->class->model->settings->group != 'category')
) {
return;
}
switch (get_class($event->class)) {
case 'App\Reports\ProfitLoss':
$categories = Category::type(['income', 'expense'])->orderBy('name')->get();
$rows = $categories->pluck('name', 'id')->toArray();
$this->setRowNamesAndValuesForProfitLoss($event, $rows, $categories);
break;
case 'App\Reports\IncomeExpenseSummary':
if ($categories = request('categories')) {
$rows = collect($event->class->filters['categories'])->filter(function ($value, $key) use ($categories) {
return in_array($key, $categories);
});
} else {
$rows = $event->class->filters['categories'];
}
$this->setRowNamesAndValues($event, $rows);
break;
}
}
public function setRowNamesAndValuesForProfitLoss($event, $rows, $categories)
{
foreach ($event->class->dates as $date) {
foreach ($event->class->tables as $type_id => $type_name) {
foreach ($rows as $id => $name) {
$category = $categories->where('id', $id)->first();
if ($category->type != $type_id) {
continue;
}
$event->class->row_names[$type_name][$id] = $name;
$event->class->row_values[$type_name][$id][$date] = 0;
}
}
}
}
}

View File

@ -0,0 +1,33 @@
<?php
namespace App\Listeners\Common;
use App\Abstracts\Listeners\Report as Listener;
use App\Events\Common\ReportRowsShowing;
class AddRowsToTaxReport extends Listener
{
protected $classes = [
'App\Reports\TaxSummary',
];
/**
* Handle rows showing event.
*
* @param $event
* @return void
*/
public function handleReportRowsShowing(ReportRowsShowing $event)
{
if ($this->skipThisClass($event)) {
return;
}
$rows = [
'income' => trans_choice('general.sales', 2),
'expense' => trans_choice('general.purchases', 2),
];
$this->setRowNamesAndValues($event, $rows);
}
}

View File

@ -6,6 +6,7 @@ use App\Abstracts\Listeners\Report as Listener;
use App\Events\Common\ReportFilterShowing;
use App\Events\Common\ReportGroupApplying;
use App\Events\Common\ReportGroupShowing;
use App\Events\Common\ReportRowsShowing;
class AddVendorsToReports extends Listener
{
@ -58,4 +59,27 @@ class AddVendorsToReports extends Listener
$this->applyVendorGroup($event);
}
/**
* Handle rows showing event.
*
* @param $event
* @return void
*/
public function handleReportRowsShowing(ReportRowsShowing $event)
{
if ($this->skipRowsShowing($event, 'vendor')) {
return;
}
if ($vendors = request('vendors')) {
$rows = collect($event->class->filters['vendors'])->filter(function ($value, $key) use ($vendors) {
return in_array($key, $vendors);
});
} else {
$rows = $event->class->filters['vendors'];
}
$this->setRowNamesAndValues($event, $rows);
}
}

View File

@ -290,7 +290,7 @@ class Version200 extends Listener
'class' => 'App\Reports\TaxSummary',
'name' => trans('reports.summary.tax'),
'description' => trans('demo.reports.tax'),
'settings' => ['group' => 'category', 'period' => 'quarterly', 'basis' => 'accrual'],
'settings' => ['period' => 'quarterly', 'basis' => 'accrual'],
],
];

View File

@ -8,7 +8,6 @@ use Bkwld\Cloner\Cloneable;
class InvoiceItem extends Model
{
use Cloneable, Currencies;
protected $table = 'invoice_items';

View File

@ -68,6 +68,8 @@ class Event extends Provider
'App\Listeners\Common\AddVendorsToReports',
'App\Listeners\Common\AddExpenseCategoriesToReports',
'App\Listeners\Common\AddIncomeCategoriesToReports',
'App\Listeners\Common\AddIncomeExpenseCategoriesToReports',
'App\Listeners\Common\AddSearchToReports',
'App\Listeners\Common\AddRowsToTaxReport',
];
}

View File

@ -30,11 +30,12 @@ class ExpenseSummary extends Report
public function getTotals()
{
$payments = $this->applyFilters(Transaction::type('expense')->isNotTransfer(), ['date_field' => 'paid_at'])->get();
$transactions = $this->applyFilters(Transaction::type('expense')->isNotTransfer(), ['date_field' => 'paid_at']);
switch ($this->model->settings->basis) {
case 'cash':
// Payments
$payments = $transactions->get();
$this->setTotals($payments, 'paid_at');
break;
@ -45,6 +46,7 @@ class ExpenseSummary extends Report
$this->setTotals($bills, 'billed_at');
// Payments
$payments = $transactions->isNotDocument()->get();
Recurring::reflect($payments, 'paid_at');
$this->setTotals($payments, 'paid_at');

View File

@ -16,16 +16,18 @@ class IncomeExpenseSummary extends Report
public function getTotals()
{
$income_transactions = $this->applyFilters(Transaction::type('income')->isNotTransfer(), ['date_field' => 'paid_at'])->get();
$expense_transactions = $this->applyFilters(Transaction::type('expense')->isNotTransfer(), ['date_field' => 'paid_at'])->get();
$income_transactions = $this->applyFilters(Transaction::type('income')->isNotTransfer(), ['date_field' => 'paid_at']);
$expense_transactions = $this->applyFilters(Transaction::type('expense')->isNotTransfer(), ['date_field' => 'paid_at']);
switch ($this->model->settings->basis) {
case 'cash':
// Income Transactions
$this->setTotals($income_transactions, 'paid_at', true);
// Revenues
$revenues = $income_transactions->get();
$this->setTotals($revenues, 'paid_at', true);
// Expense Transactions
$this->setTotals($expense_transactions, 'paid_at', true);
// Payments
$payments = $expense_transactions->get();
$this->setTotals($payments, 'paid_at', true);
break;
default:
@ -34,18 +36,20 @@ class IncomeExpenseSummary extends Report
Recurring::reflect($invoices, 'invoiced_at');
$this->setTotals($invoices, 'invoiced_at', true);
// Income Transactions
Recurring::reflect($income_transactions, 'paid_at');
$this->setTotals($income_transactions, 'paid_at', true);
// Revenues
$revenues = $income_transactions->isNotDocument()->get();
Recurring::reflect($revenues, 'paid_at');
$this->setTotals($revenues, 'paid_at', true);
// Bills
$bills = $this->applyFilters(Bill::accrued(), ['date_field' => 'billed_at'])->get();
Recurring::reflect($bills, 'bill', 'billed_at');
$this->setTotals($bills, 'billed_at', true);
// Expense Transactions
Recurring::reflect($expense_transactions, 'paid_at');
$this->setTotals($expense_transactions, 'paid_at', true);
// Payments
$payments = $expense_transactions->isNotDocument()->get();
Recurring::reflect($payments, 'paid_at');
$this->setTotals($payments, 'paid_at', true);
break;
}

View File

@ -30,12 +30,13 @@ class IncomeSummary extends Report
public function getTotals()
{
$transactions = $this->applyFilters(Transaction::type('income')->isNotTransfer(), ['date_field' => 'paid_at'])->get();
$transactions = $this->applyFilters(Transaction::type('income')->isNotTransfer(), ['date_field' => 'paid_at']);
switch ($this->model->settings->basis) {
case 'cash':
// Transactions
$this->setTotals($transactions, 'paid_at');
// Revenues
$revenues = $transactions->get();
$this->setTotals($revenues, 'paid_at');
break;
default:
@ -44,9 +45,10 @@ class IncomeSummary extends Report
Recurring::reflect($invoices, 'invoiced_at');
$this->setTotals($invoices, 'invoiced_at');
// Transactions
Recurring::reflect($transactions, 'paid_at');
$this->setTotals($transactions, 'paid_at');
// Revenues
$revenues = $transactions->isNotDocument()->get();
Recurring::reflect($revenues, 'paid_at');
$this->setTotals($revenues, 'paid_at');
break;
}

View File

@ -6,7 +6,6 @@ use App\Abstracts\Report;
use App\Models\Banking\Transaction;
use App\Models\Purchase\Bill;
use App\Models\Sale\Invoice;
use App\Models\Setting\Category;
use App\Utilities\Recurring;
class ProfitLoss extends Report
@ -36,44 +35,20 @@ class ProfitLoss extends Report
];
}
public function getTableRowList()
{
$this->cat_list = Category::type(['income', 'expense'])->enabled()->orderBy('name')->get();
return collect($this->cat_list)->pluck('name', 'id')->toArray();
}
public function setRows()
{
$list = $this->getTableRowList();
foreach ($this->dates as $date) {
foreach ($this->tables as $t_id => $t_name) {
foreach ($list as $id => $name) {
$cat = $this->cat_list->where('id', $id)->first();
if ($cat->type != $t_id) {
continue;
}
$this->rows[$t_name][$id][$date] = 0;
}
}
}
}
public function getTotals()
{
$income_transactions = $this->applyFilters(Transaction::type('income')->isNotTransfer(), ['date_field' => 'paid_at'])->get();
$expense_transactions = $this->applyFilters(Transaction::type('expense')->isNotTransfer(), ['date_field' => 'paid_at'])->get();
$income_transactions = $this->applyFilters(Transaction::type('income')->isNotTransfer(), ['date_field' => 'paid_at']);
$expense_transactions = $this->applyFilters(Transaction::type('expense')->isNotTransfer(), ['date_field' => 'paid_at']);
switch ($this->model->settings->basis) {
case 'cash':
// Income Transactions
$this->setTotals($income_transactions, 'paid_at', true, $this->tables['income']);
// Revenues
$revenues = $income_transactions->get();
$this->setTotals($revenues, 'paid_at', true, $this->tables['income']);
// Expense Transactions
$this->setTotals($expense_transactions, 'paid_at', true, $this->tables['expense']);
// Payments
$payments = $expense_transactions->get();
$this->setTotals($payments, 'paid_at', true, $this->tables['expense']);
break;
default:
@ -82,24 +57,26 @@ class ProfitLoss extends Report
Recurring::reflect($invoices, 'invoiced_at');
$this->setTotals($invoices, 'invoiced_at', true, $this->tables['income']);
// Income Transactions
Recurring::reflect($income_transactions, 'paid_at');
$this->setTotals($income_transactions, 'paid_at', true, $this->tables['income']);
// Revenues
$revenues = $income_transactions->isNotDocument()->get();
Recurring::reflect($revenues, 'paid_at');
$this->setTotals($revenues, 'paid_at', true, $this->tables['income']);
// Bills
$bills = $this->applyFilters(Bill::accrued(), ['date_field' => 'billed_at'])->get();
Recurring::reflect($bills, 'bill', 'billed_at');
$this->setTotals($bills, 'billed_at', true, $this->tables['expense']);
// Expense Transactions
Recurring::reflect($expense_transactions, 'paid_at');
$this->setTotals($expense_transactions, 'paid_at', true, $this->tables['expense']);
// Payments
$payments = $expense_transactions->isNotDocument()->get();
Recurring::reflect($payments, 'paid_at');
$this->setTotals($payments, 'paid_at', true, $this->tables['expense']);
break;
}
// TODO: move to views
foreach ($this->totals as $table => $dates) {
foreach ($this->footer_totals as $table => $dates) {
foreach ($dates as $date => $total) {
if (!isset($this->net_profit[$date])) {
$this->net_profit[$date] = 0;

View File

@ -38,24 +38,16 @@ class TaxSummary extends Report
$this->tables = array_combine($taxes, $taxes);
}
public function getTableRowList()
{
return [
'income' => trans_choice('general.incomes', 2),
'expense' => trans_choice('general.expenses', 2),
];
}
public function getTotals()
{
switch ($this->model->settings->basis) {
case 'cash':
// Invoice Payments
$invoices = $this->applyFilters(Transaction::type('income')->isDocument()->with(['invoice', 'invoice.totals'])->isNotTransfer(), ['date_field' => 'paid_at'])->get();
$invoices = $this->applyFilters(Transaction::with(['invoice', 'invoice.totals'])->type('income')->isDocument()->isNotTransfer(), ['date_field' => 'paid_at'])->get();
$this->setTotals($invoices, 'paid_at');
// Bill Payments
$bills = $this->applyFilters(Transaction::type('expense')->isDocument()->with(['bill', 'bill.totals'])->isNotTransfer(), ['date_field' => 'paid_at'])->get();
$bills = $this->applyFilters(Transaction::with(['bill', 'bill.totals'])->type('expense')->isDocument()->isNotTransfer(), ['date_field' => 'paid_at'])->get();
$this->setTotals($bills, 'paid_at');
break;
@ -97,8 +89,9 @@ class TaxSummary extends Report
continue;
}
if (!isset($this->rows[$item_total->name][$type][$date]) ||
!isset($this->totals[$item_total->name][$date]))
if (
!isset($this->row_values[$item_total->name][$type][$date])
|| !isset($this->footer_totals[$item_total->name][$date]))
{
continue;
}
@ -113,13 +106,13 @@ class TaxSummary extends Report
$amount = $this->convertToDefault($item_amount, $item->currency_code, $item->currency_rate);
if ($type == 'income') {
$this->rows[$item_total->name][$type][$date] += $amount;
$this->row_values[$item_total->name][$type][$date] += $amount;
$this->totals[$item_total->name][$date] += $amount;
$this->footer_totals[$item_total->name][$date] += $amount;
} else {
$this->rows[$item_total->name][$type][$date] -= $amount;
$this->row_values[$item_total->name][$type][$date] -= $amount;
$this->totals[$item_total->name][$date] -= $amount;
$this->footer_totals[$item_total->name][$date] -= $amount;
}
}
}
@ -128,7 +121,6 @@ class TaxSummary extends Report
public function getFields()
{
return [
$this->getGroupField(),
$this->getPeriodField(),
$this->getBasisField(),
];

View File

@ -59,6 +59,8 @@ trait DateTime
public function getTimezones()
{
$groups = [];
// The list of available timezone groups to use.
$use_zones = array('Africa', 'America', 'Antarctica', 'Arctic', 'Asia', 'Atlantic', 'Australia', 'Europe', 'Indian', 'Pacific');

View File

@ -11,6 +11,7 @@ class Recurring
public static function reflect(&$items, $issued_date_field)
{
foreach ($items as $key => $item) {
// @todo cache recurrings
if (!$item->recurring || !empty($item->parent_id)) {
continue;
}

View File

@ -60,7 +60,7 @@ class Reports extends Seeder
'class' => 'App\Reports\TaxSummary',
'name' => trans('reports.summary.tax'),
'description' => trans('demo.reports.tax'),
'settings' => ['group' => 'category', 'period' => 'quarterly', 'basis' => 'accrual'],
'settings' => ['period' => 'quarterly', 'basis' => 'accrual'],
],
];

View File

@ -27,7 +27,7 @@ return [
'income' => 'Monthly income summary by category.',
'expense' => 'Monthly expense summary by category.',
'income_expense' => 'Monthly income vs expense by category.',
'tax' => 'Quarterly tax summary by category.',
'tax' => 'Quarterly tax summary.',
'profit_loss' => 'Quarterly profit & loss by category.',
],

View File

@ -43,6 +43,7 @@
</div>
</div>
@endpermission
{!! Form::close() !!}
</div>
@endsection

View File

@ -60,11 +60,14 @@
</div>
</div>
<div class="card-footer">
<div class="row float-right">
{{ Form::saveButtons('common/reports') }}
@permission('update-common-reports')
<div class="card-footer">
<div class="row float-right">
{{ Form::saveButtons('common/reports') }}
</div>
</div>
</div>
@endpermission
{!! Form::close() !!}
</div>
@endsection

View File

@ -25,15 +25,13 @@
<i class="fa fa-ellipsis-v text-primary"></i>
</a>
<div class="dropdown-menu dropdown-menu-right dropdown-menu-arrow">
<a class="dropdown-item" href="{{ route('reports.edit', $report->id) }}">{{ trans('general.edit') }}</a>
@permission('create-common-reports')
<a class="dropdown-item" href="{{ route('reports.edit', $report->id) }}">{{ trans('general.edit') }}</a>
<div class="dropdown-divider"></div>
@endpermission
@permission('create-common-reports')
<a class="dropdown-item" href="{{ route('reports.duplicate', $report->id) }}">{{ trans('general.duplicate') }}</a>
<div class="dropdown-divider"></div>
@endpermission
@permission('delete-common-reports')
<div class="dropdown-divider"></div>
{!! Form::deleteLink($report, 'common/reports') !!}
@endpermission
</div>

View File

@ -6,7 +6,7 @@
{{ setting('company.name') }}
@if($class->model->settings->chart)
@if(!empty($class->model->settings->chart))
@include($class->views['chart'])
@endif

View File

@ -2,8 +2,8 @@
<table class="table align-items-center rp-border-collapse">
@include($class->views['table.header'])
<tbody>
@if (!empty($class->rows[$table]))
@foreach($class->rows[$table] as $id => $items)
@if (!empty($class->row_values[$table]))
@foreach($class->row_values[$table] as $id => $rows)
@include($class->views['table.rows'])
@endforeach
@else

View File

@ -1,11 +1,11 @@
<tfoot>
<tr class="rp-border-top-1">
<th class="report-column text-left">{{ trans_choice('general.totals', 1) }}</th>
@php $total_total = 0; @endphp
@foreach($class->totals[$table] as $total)
@php $total_total += $total; @endphp
@php $grand_total = 0; @endphp
@foreach($class->footer_totals[$table] as $total)
@php $grand_total += $total; @endphp
<th class="report-column text-right px-0">@money($total, setting('default.currency'), true)</th>
@endforeach
<th class="report-column text-right">@money($total_total, setting('default.currency'), true)</th>
<th class="report-column text-right">@money($grand_total, setting('default.currency'), true)</th>
</tr>
</tfoot>

View File

@ -1,9 +1,9 @@
@php $row_total = 0; @endphp
<tr class="rp-border-top-1">
<td class="report-column">{{ $class->getTableRowList()[$id] }}</td>
@foreach($items as $item)
@php $row_total += $item; @endphp
<td class="report-column text-right px-0">@money($item, setting('default.currency'), true)</td>
<td class="report-column">{{ $class->row_names[$table][$id] }}</td>
@foreach($rows as $row)
@php $row_total += $row; @endphp
<td class="report-column text-right px-0">@money($row, setting('default.currency'), true)</td>
@endforeach
<td class="report-column text-right">@money($row_total, setting('default.currency'), true)</td>
</tr>

View File

@ -1,11 +1,11 @@
<tfoot>
<tr class="rp-border-top-1">
<th class="report-column text-left">{{ trans_choice('general.totals', 1) }}</th>
@php $total_total = 0; @endphp
@foreach($class->totals[$table] as $date => $total)
@php $total_total += $total; @endphp
@php $grand_total = 0; @endphp
@foreach($class->footer_totals[$table] as $date => $total)
@php $grand_total += $total; @endphp
<th class="report-column text-right px-0">@money($total, setting('default.currency'), true)</th>
@endforeach
<th class="report-column text-right">@money($total_total, setting('default.currency'), true)</th>
<th class="report-column text-right">@money($grand_total, setting('default.currency'), true)</th>
</tr>
</tfoot>

View File

@ -1,11 +1,11 @@
<tfoot>
<tr class="rp-border-top-1">
<th class="report-column text-left">{{ trans('reports.net') }}</th>
@php $total_total = 0; @endphp
@foreach($class->totals[$table] as $total)
@php $total_total += $total; @endphp
@php $grand_total = 0; @endphp
@foreach($class->footer_totals[$table] as $total)
@php $grand_total += $total; @endphp
<th class="report-column text-right px-0">@money($total, setting('default.currency'), true)</th>
@endforeach
<th class="report-column text-right">@money($total_total, setting('default.currency'), true)</th>
<th class="report-column text-right">@money($grand_total, setting('default.currency'), true)</th>
</tr>
</tfoot>