v2 first commit

This commit is contained in:
denisdulici
2019-11-16 10:21:14 +03:00
parent 5b23e9c2c4
commit 6d50fa8442
3075 changed files with 3451681 additions and 65594 deletions

View File

@@ -0,0 +1,226 @@
<?php
namespace App\Abstracts\Reports;
use App\Events\Common\ReportFilterApplying;
use App\Events\Common\ReportFilterShowing;
use App\Events\Common\ReportGroupApplying;
use App\Events\Common\ReportGroupShowing;
use App\Models\Banking\Account;
use App\Models\Common\Contact;
use App\Models\Setting\Category;
use App\Traits\Contacts;
use Date;
abstract class Listener
{
use Contacts;
protected $class = '';
protected $events = [
'App\Events\Common\ReportFilterShowing',
'App\Events\Common\ReportFilterApplying',
'App\Events\Common\ReportGroupShowing',
'App\Events\Common\ReportGroupApplying',
];
public function checkClass($event)
{
return (get_class($event->class) == $this->class);
}
public function getYears()
{
$now = Date::now();
$years = [];
$y = $now->addYears(2);
for ($i = 0; $i < 10; $i++) {
$years[$y->year] = $y->year;
$y->subYear();
}
return $years;
}
public function getAccounts()
{
return Account::enabled()->orderBy('name')->pluck('name', 'id')->toArray();
}
public function getItemCategories()
{
return $this->getCategories('item');
}
public function getIncomeCategories()
{
return $this->getCategories('income');
}
public function getExpenseCategories()
{
return $this->getCategories('expense');
}
public function getIncomeExpenseCategories()
{
return $this->getCategories(['income', 'expense']);
}
public function getCategories($types)
{
return Category::type($types)->enabled()->orderBy('name')->pluck('name', 'id')->toArray();
}
public function getCustomers()
{
return $this->getContacts($this->getCustomerTypes());
}
public function getVendors()
{
return $this->getContacts($this->getVendorTypes());
}
public function getContacts($types)
{
return Contact::type($types)->enabled()->orderBy('name')->pluck('name', 'id')->toArray();
}
public function applyDateFilter($event)
{
$event->model->monthsOfYear($event->args['date_field']);
}
public function applySearchStringFilter($event)
{
$event->model->usingSearchString(request('search'));
}
public function applyAccountGroup($event)
{
if (($event->model->getTable() != 'invoices') && ($event->model->getTable() != 'bills')) {
return;
}
$filter = request('accounts', []);
$event->model->account_id = 0;
foreach ($event->model->transactions as $transaction) {
if (!empty($filter) && !in_array($transaction->account_id, $filter)) {
continue;
}
$event->model->account_id = $transaction->account_id;
}
}
public function applyCustomerGroup($event)
{
foreach ($this->getCustomerTypes() as $type) {
$id_field = $type . '_id';
$event->model->$id_field = $event->model->contact_id;
}
}
public function applyVendorGroup($event)
{
foreach ($this->getVendorTypes() as $type) {
$id_field = $type . '_id';
$event->model->$id_field = $event->model->contact_id;
}
}
/**
* Handle filter showing event.
*
* @param $event
* @return void
*/
public function handleReportFilterShowing(ReportFilterShowing $event)
{
if (!$this->checkClass($event)) {
return;
}
$event->class->filters['years'] = $this->getYears();
}
/**
* Handle filter applying event.
*
* @param $event
* @return void
*/
public function handleReportFilterApplying(ReportFilterApplying $event)
{
if (!$this->checkClass($event)) {
return;
}
// Apply date
$this->applyDateFilter($event);
// Apply search
$this->applySearchStringFilter($event);
}
/**
* Handle group showing event.
*
* @param $event
* @return void
*/
public function handleReportGroupShowing(ReportGroupShowing $event)
{
if (!$this->checkClass($event)) {
return;
}
$event->class->groups['category'] = trans_choice('general.categories', 1);
}
/**
* Handle group applying event.
*
* @param $event
* @return void
*/
public function handleReportGroupApplying(ReportGroupApplying $event)
{
if (!$this->checkClass($event)) {
return;
}
$this->applyAccountGroup($event);
}
/**
* Register the listeners for the subscriber.
*
* @param \Illuminate\Events\Dispatcher $events
*/
public function subscribe($events)
{
$class = get_class($this);
foreach ($this->events as $event) {
$method = 'handle' . (new \ReflectionClass($event))->getShortName();
if (!method_exists($class, $method)) {
continue;
}
$events->listen(
$event,
$class . '@' . $method
);
}
}
}

View File

@@ -0,0 +1,434 @@
<?php
namespace App\Abstracts\Reports;
use App\Exports\Common\Reports as Export;
use App\Models\Common\Report as Model;
use App\Utilities\Chartjs;
use App\Traits\DateTime;
use Date;
use Illuminate\Support\Str;
abstract class Report
{
use DateTime;
public $report;
public $year;
public $views = [];
public $tables = [];
public $dates = [];
public $rows = [];
public $totals = [];
public $groups = [];
public $filters = [];
public $category = 'income-expense';
public $icon = 'fa fa-chart-pie';
public $indents = [
'table_header' => '0px',
'table_rows' => '0px',
];
public $chart = [
'line' => [
'width' => '0',
'height' => '300',
'options' => [
'color' => '#6da252',
],
],
'dates' => [],
'datasets' => [],
];
public function __construct(Model $report = null, $get_totals = true)
{
$this->setGroups();
if (!$report) {
return;
}
$this->report = $report;
$this->setYear();
$this->setViews();
$this->setTables();
$this->setDates();
$this->setFilters();
$this->setRows();
if ($get_totals) {
$this->getTotals();
}
}
abstract public function getTotals();
public function getName()
{
return Str::title(str_replace('_', ' ', Str::snake((new \ReflectionClass($this))->getShortName())));
}
public function getCategory()
{
return $this->category;
}
public function getIcon()
{
return $this->icon;
}
public function getTotal()
{
$sum = 0;
foreach ($this->totals as $total) {
$sum += is_array($total) ? array_sum($total) : $total;
}
$total = money($sum, setting('default.currency'), true);
return $total;
}
public function getTableRowList()
{
$group_prl = Str::plural($this->report->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();
$config = $this->chart[$this->report->chart];
$default_options = [
'tooltips' => [
'backgroundColor' => '#f5f5f5',
'titleFontColor' => '#333',
'bodyFontColor' => '#666',
'bodySpacing' => 4,
'YrPadding' => 12,
'mode' => 'nearest',
'intersect' => 0,
'position' => 'nearest'
],
'responsive' => true,
'scales' => [
'yAxes' => [
[
'barPercentage' => '1.6',
'gridLines' => [
'drawBorder' => false,
'color' => 'rgba(29,140,248,0.1)',
'zeroLineColor' => 'transparent',
'borderDash' => [2],
'borderDashOffset' => [2],
],
'ticks' => [
'padding' => 10,
'fontColor' => '#9e9e9e'
]
]
],
'xAxes' => [
[
'barPercentage' => '1.6',
'gridLines' => [
'drawBorder' => false,
'color' => 'rgba(29,140,248,0.0)',
'zeroLineColor' => 'transparent'
],
'ticks' => [
'suggestedMin' => 60,
'suggestedMax' => 125,
'padding' => 20,
'fontColor' => '#9e9e9e'
]
]
]
]
];
$options = array_merge($default_options, (array) $config['options']);
$chart->type($this->report->chart)
->width((int) $config['width'])
->height((int) $config['height'])
->options($options)
->labels(!empty($config['dates']) ? array_values($config['dates']) : array_values($this->dates));
if (!empty($config['datasets'])) {
foreach ($config['datasets'] as $dataset) {
$chart->dataset($dataset['name'], 'line', array_values($dataset['totals']))
->backgroundColor(isset($dataset['backgroundColor']) ? $dataset['backgroundColor'] : '#6da252')
->color(isset($dataset['color']) ? $dataset['color'] : '#6da252')
->options((array) $dataset['options'])
->fill(false);
}
} else {
foreach ($this->totals as $total) {
$chart->dataset($this->report->name, 'line', array_values($total))
->backgroundColor(isset($config['backgroundColor']) ? $config['backgroundColor'] : '#6da252')
->color(isset($config['color']) ? $config['color'] : '#6da252')
->options([
'borderWidth' => 4,
'pointStyle' => 'line',
])
->fill(false);
}
}
return $chart;
}
public function show()
{
return view($this->views['show'])->with('class', $this);
}
public function print()
{
return view($this->views['print'])->with('class', $this);
}
public function export()
{
return \Excel::download(new Export($this->views['content'], $this), $this->report->name . '.xlsx');
}
public function setYear()
{
$this->year = request('year', Date::now()->year);
}
public function setViews()
{
$this->views = [
'chart' => 'partials.reports.chart',
'content' => 'partials.reports.content',
'content.header' => 'partials.reports.content.header',
'content.footer' => 'partials.reports.content.footer',
'show' => 'partials.reports.show',
'header' => 'partials.reports.header',
'filter' => 'partials.reports.filter',
'print' => 'partials.reports.print',
'table' => 'partials.reports.table',
'table.footer' => 'partials.reports.table.footer',
'table.header' => 'partials.reports.table.header',
'table.rows' => 'partials.reports.table.rows',
];
}
public function setTables()
{
$this->tables = [
'default' => 'default'
];
}
public function setDates()
{
$function = 'sub' . ucfirst(str_replace('ly', '', $this->report->period));
$start = $this->getFinancialStart()->copy()->$function();
for ($j = 1; $j <= 12; $j++) {
switch ($this->report->period) {
case 'yearly':
$start->addYear();
$date = $this->getFormattedDate($start);
$this->dates[$j] = $date;
foreach ($this->tables as $table) {
$this->totals[$table][$date] = 0;
}
$j += 11;
break;
case 'quarterly':
$start->addQuarter();
$date = $this->getFormattedDate($start);
$this->dates[$j] = $date;
foreach ($this->tables as $table) {
$this->totals[$table][$date] = 0;
}
$j += 2;
break;
default:
$start->addMonth();
$date = $this->getFormattedDate($start);
$this->dates[$j] = $date;
foreach ($this->tables as $table) {
$this->totals[$table][$date] = 0;
}
break;
}
}
}
public function setFilters()
{
event(new \App\Events\Common\ReportFilterShowing($this));
}
public function setGroups()
{
event(new \App\Events\Common\ReportGroupShowing($this));
}
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;
}
}
}
}
public function setTotals($items, $date_field, $check_type = false, $table = 'default')
{
foreach ($items as $item) {
// Make groups extensible
$item = $this->applyGroups($item);
$date = $this->getFormattedDate(Date::parse($item->$date_field));
$id_field = $this->report->group . '_id';
if (!isset($this->rows[$table][$item->$id_field]) ||
!isset($this->rows[$table][$item->$id_field][$date]) ||
!isset($this->totals[$table][$date]))
{
continue;
}
$amount = $item->getAmountConvertedToDefault();
if (!$check_type) {
$this->rows[$table][$item->$id_field][$date] += $amount;
$this->totals[$table][$date] += $amount;
} else {
$type = (($item->getTable() == 'invoices') || (($item->getTable() == 'transactions') && ($item->type == 'income'))) ? 'income' : 'expense';
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;
}
}
}
}
public function applyFilters($model, $args = [])
{
event(new \App\Events\Common\ReportFilterApplying($this, $model, $args));
return $model;
}
public function applyGroups($model, $args = [])
{
event(new \App\Events\Common\ReportGroupApplying($this, $model, $args));
return $model;
}
public function getFormattedDate($date)
{
switch ($this->report->period) {
case 'yearly':
$i = $date->copy()->format($this->getYearlyDateFormat());
break;
case 'quarterly':
$start = $date->copy()->startOfQuarter()->format($this->getQuarterlyDateFormat());
$end = $date->copy()->endOfQuarter()->format($this->getQuarterlyDateFormat());
$i = $start . '-' . $end;
break;
default:
$i = $date->copy()->format($this->getMonthlyDateFormat());
break;
}
return $i;
}
public function getUrl($action = 'print')
{
$print_url = 'common/reports/' . $this->report->id . '/' . $action . '?year='. $this->year;
collect(request('accounts'))->each(function($item) use(&$print_url) {
$print_url .= '&accounts[]=' . $item;
});
collect(request('customers'))->each(function($item) use(&$print_url) {
$print_url .= '&customers[]=' . $item;
});
collect(request('categories'))->each(function($item) use(&$print_url) {
$print_url .= '&categories[]=' . $item;
});
return $print_url;
}
public function getPermission()
{
$permission = 'read-reports-' . Str::kebab((new \ReflectionClass($this))->getShortName());
return $permission;
}
public function canRead()
{
return user()->can($this->getPermission());
}
}