first commit

This commit is contained in:
Noor E Ilahi
2026-01-09 12:54:53 +05:30
commit 7ccf44f7da
1070 changed files with 113036 additions and 0 deletions

View File

@@ -0,0 +1,17 @@
<?php
namespace App\Reports;
use Carbon\CarbonInterval;
abstract class BaseExport
{
protected function formatDuration(int $seconds): string
{
if ($seconds === 0) {
return '-';
}
return CarbonInterval::seconds($seconds)->cascade()->forHumans(['short' => true]);
}
}

View File

@@ -0,0 +1,206 @@
<?php
namespace App\Reports;
use App\Contracts\AppReport;
use App\Enums\DashboardSortBy;
use App\Enums\SortDirection;
use App\Helpers\ReportHelper;
use Carbon\Carbon;
use Carbon\CarbonInterval;
use Carbon\CarbonPeriod;
use Exception;
use Illuminate\Support\Collection;
use Maatwebsite\Excel\Concerns\FromCollection;
use Maatwebsite\Excel\Concerns\Exportable;
use Maatwebsite\Excel\Concerns\WithDefaultStyles;
use Maatwebsite\Excel\Concerns\WithMapping;
use Maatwebsite\Excel\Concerns\ShouldAutoSize;
use Maatwebsite\Excel\Concerns\WithHeadings;
use Maatwebsite\Excel\Concerns\WithStyles;
use PhpOffice\PhpSpreadsheet\Style\Alignment;
use PhpOffice\PhpSpreadsheet\Style\Style;
use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet;
class DashboardExport extends AppReport implements FromCollection, WithMapping, ShouldAutoSize, WithHeadings, WithStyles, WithDefaultStyles
{
use Exportable;
private array $periodDates;
private string $colsDateFormat;
private readonly CarbonPeriod $period;
public function __construct(
private readonly ?array $users,
private readonly ?array $projects,
private readonly Carbon $startAt,
private readonly Carbon $endAt,
private readonly string $companyTimezone,
private readonly string $userTimezone,
private readonly DashboardSortBy|null $sortBy = null,
private readonly SortDirection|null $sortDirection = null,
)
{
$this->period = CarbonPeriod::create(
$this->startAt->clone()->setTimezone($this->userTimezone),
$this->endAt->clone()->setTimezone($this->userTimezone)
);
$this->periodDates = $this->getPeriodDates($this->period);
}
public function collection(array|null $where = null): Collection
{
$that = $this;
$reportCollection = $this->queryReport($where)->map(static function ($interval) use ($that) {
$start = Carbon::make($interval->start_at);
$interval->duration = Carbon::make($interval->end_at)?->diffInSeconds($start);
$interval->from_midnight = $start?->diffInSeconds($start?->copy()->startOfDay());
$interval->durationByDay = ReportHelper::getIntervalDurationByDay(
$interval,
$that->companyTimezone,
$that->userTimezone
);
$interval->durationAtSelectedPeriod = ReportHelper::getIntervalDurationInPeriod(
$that->period,
$interval->durationByDay
);
return $interval;
})->groupBy('user_id');
if ($this->sortBy && $this->sortDirection) {
$sortBy = match ($this->sortBy) {
DashboardSortBy::USER_NAME => 'full_name',
DashboardSortBy::WORKED => 'durationAtSelectedPeriod',
};
$sortDirection = match ($this->sortDirection) {
SortDirection::ASC => false,
SortDirection::DESC => true,
};
if ($this->sortBy === DashboardSortBy::USER_NAME) {
$reportCollection = $reportCollection->sortBy(
fn($interval) => $interval[0][$sortBy],
SORT_NATURAL,
$sortDirection
);
} else {
$reportCollection = $reportCollection->sortBy(
fn($interval) => $interval->sum($sortBy),
SORT_NATURAL,
$sortDirection
);
}
}
return $reportCollection;
}
/**
* @param $row
* @return array
* @throws Exception
*/
public function map($row): array
{
$that = $this;
return $row->groupBy('user_id')->map(
static function ($collection) use ($that) {
$interval = CarbonInterval::seconds($collection->sum('durationAtSelectedPeriod'));
return array_merge(
array_values($collection->first()->only(['full_name'])),
[
$interval->cascade()->forHumans(['short' => true]),
round($interval->totalHours, 3),
...$that->intervalsByDay($collection)
]
);
}
)->all();
}
private function intervalsByDay(Collection $intervals): array
{
$intervalsByDay = [];
foreach ($this->periodDates as $date) {
$workedAtDate = $intervals->sum(fn($item) => (
$item->durationByDay[$date] ?? 0
));
$intervalsByDay[] = round(CarbonInterval::seconds($workedAtDate)->totalHours, 3);
}
return $intervalsByDay;
}
private function queryReport(array|null $where = null): Collection
{
$query = ReportHelper::getBaseQuery(
$this->users,
$this->startAt,
$this->endAt,
[
'time_intervals.start_at',
'time_intervals.activity_fill',
'time_intervals.mouse_fill',
'time_intervals.keyboard_fill',
'time_intervals.end_at',
'time_intervals.is_manual',
'users.email as user_email',
]
)->whereIn('project_id', $this->projects);
if (!is_null($where)) {
$query = $query->where($where);
}
return $query->get();
}
public function headings(): array
{
return [
'User Name',
'Hours',
'Hours (decimal)',
...collect($this->periodDates)->map(fn($date) => Carbon::parse($date)->format('y-m-d'))
];
}
private function getPeriodDates($period): array
{
$dates = [];
foreach ($period as $date) {
$dates[] = $date->format(ReportHelper::$dateFormat);
}
return $dates;
}
public function styles(Worksheet $sheet): array
{
return [
1 => ['font' => ['bold' => true]],
'A' => ['alignment' => ['horizontal' => Alignment::HORIZONTAL_LEFT]]
];
}
public function getReportId(): string
{
return 'dashboard_report';
}
public function getLocalizedReportName(): string
{
return __('Dashboard_Report');
}
public function defaultStyles(Style $defaultStyle)
{
return ['alignment' => ['horizontal' => Alignment::HORIZONTAL_RIGHT]];
}
}

View File

@@ -0,0 +1,26 @@
<?php
namespace App\Reports;
use Maatwebsite\Excel\Concerns\FromArray;
class DummySheetExport implements FromArray
{
protected $title;
public function __construct($title = 'Empty Sheet')
{
$this->title = $title;
}
public function array(): array
{
return [];
}
public function title(): string
{
return $this->title;
}
}

View File

@@ -0,0 +1,158 @@
<?php
namespace App\Reports;
use App\Contracts\AppReport;
use App\Models\Project;
use App\Models\CronTaskWorkers;
use Carbon\CarbonInterval;
use Exception;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Database\Eloquent\Builder as EloquentBuilder;
use Illuminate\Support\Collection;
use Maatwebsite\Excel\Concerns\FromCollection;
use Maatwebsite\Excel\Concerns\Exportable;
use Maatwebsite\Excel\Concerns\WithMapping;
use Maatwebsite\Excel\Concerns\ShouldAutoSize;
use Maatwebsite\Excel\Concerns\WithHeadings;
use Maatwebsite\Excel\Concerns\WithStyles;
use PhpOffice\PhpSpreadsheet\Style\Alignment;
use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet;
use Settings;
class PlannedTimeReportExport extends AppReport implements FromCollection, WithMapping, ShouldAutoSize, WithHeadings, WithStyles
{
use Exportable;
public function __construct(
private readonly ?array $projects,
) {
}
public function collection(): Collection
{
return collect([
'reportData' => $this->queryReport(),
'reportDate' => Settings::scope('core.reports')->get('planned_time_report_date', null)
]);
}
/**
* @param Collection|string $row
* @return array
* @throws Exception
*/
public function map($row): array
{
if (is_string($row)) {
return [
[],
['', "Created at $row", '', '', '']
];
}
$reportArr = [];
foreach ($row->toArray() as $project) {
foreach ($project['tasks'] as $task) {
foreach ($task['workers'] as $worker) {
$reportArr[] = [
$project['name'],
$task['task_name'],
$worker['user']['full_name'],
CarbonInterval::seconds($worker['duration'])->cascade()->forHumans(),
round(CarbonInterval::seconds($worker['duration'])->totalHours, 3)
];
}
if ($task['estimate'] > 0) {
$reportArr[] = [
[],
"Estimate for {$task['task_name']}",
'',
CarbonInterval::seconds($task['estimate'])->cascade()->forHumans(),
round(CarbonInterval::seconds($task['estimate'])->totalHours, 3),
];
}
if (count($task['workers']) > 1) {
$reportArr[] = [
[],
"Subtotal for {$task['task_name']}",
'',
CarbonInterval::seconds($task['total_spent_time'])->cascade()->forHumans(),
round(CarbonInterval::seconds($task['total_spent_time'])->totalHours, 3),
];
$reportArr[] = [];
}
}
if ($project['total_spent_time'] > 0) {
$reportArr[] = [
"Subtotal for {$project['name']}",
'',
'',
CarbonInterval::seconds($project['total_spent_time'])->cascade()->forHumans(),
round(CarbonInterval::seconds($project['total_spent_time'])->totalHours, 3),
];
$reportArr[] = [];
$reportArr[] = [];
}
}
return $reportArr;
}
private function queryReport(): Collection
{
$taskWorkersTable = (new CronTaskWorkers())->table;
return Project::with(
[
'tasks' => static function (HasMany $query) use ($taskWorkersTable) {
$query->select('id', 'task_name', 'due_date', 'estimate', 'project_id')
->withSum(['workers as total_spent_time' => static function (EloquentBuilder $query) use ($taskWorkersTable) {
$query->where("$taskWorkersTable.created_by_cron", true);
}], 'duration')
->withCasts(['total_spent_time' => 'integer'])
->orderBy('total_spent_time', 'desc');
},
'tasks.workers' => static function (HasMany $query) use ($taskWorkersTable) {
$query->select('id', 'user_id', 'task_id', 'duration')
->where("$taskWorkersTable.created_by_cron", true);
},
'tasks.workers.user:id,full_name,email',
]
)
->withSum(['workers as total_spent_time' => static function (EloquentBuilder $query) use ($taskWorkersTable) {
$query->where("$taskWorkersTable.created_by_cron", true);
}], 'duration')
->withCasts(['total_spent_time' => 'integer'])
->whereIn('id', $this->projects)->get();
}
public function headings(): array
{
return [
'Project Name',
'Task Name',
'User Name',
'Hours',
'Hours (decimal)',
];
}
public function styles(Worksheet $sheet): array
{
return [
1 => ['font' => ['bold' => true], 'alignment' => ['horizontal' => Alignment::HORIZONTAL_CENTER]],
];
}
public function getReportId(): string
{
return 'planned-time_report';
}
public function getLocalizedReportName(): string
{
return __('PlannedTime_Report');
}
}

View File

@@ -0,0 +1,259 @@
<?php
namespace App\Reports;
use App\Models\Project;
use Maatwebsite\Excel\Concerns\FromArray;
use Maatwebsite\Excel\Concerns\WithCharts;
use Maatwebsite\Excel\Concerns\WithTitle;
use PhpOffice\PhpSpreadsheet\Chart\Chart;
use PhpOffice\PhpSpreadsheet\Chart\DataSeries;
use PhpOffice\PhpSpreadsheet\Chart\DataSeriesValues;
use PhpOffice\PhpSpreadsheet\Chart\Legend;
use PhpOffice\PhpSpreadsheet\Chart\PlotArea;
use PhpOffice\PhpSpreadsheet\Chart\Title;
use Carbon\Carbon;
use Maatwebsite\Excel\Concerns\WithColumnWidths;
use Maatwebsite\Excel\Concerns\WithHeadings;
use PhpOffice\PhpSpreadsheet\Cell\Coordinate;
class ProjectMultiSheetExport extends BaseExport implements FromArray, WithTitle, WithCharts, WithHeadings, WithColumnWidths
{
private $data;
private $project;
private $projectName;
private $countDate;
private $periodDates;
private $reportData;
private $showTasksChart;
private $showUsersChart;
const COLUMN_FIRST = 'B';
const OFFSET_CHART = [10, 30];
const POSITIONS_CHART = [['A8', 'D38'], ['E8', 'H38']];
const TEXT_USER = 'Worked by all users';
const TEXT_USER_INDIVIDUALLY = 'Worked by all users individually';
public function __construct(array $collection, $id, array $periodDates)
{
$this->data = $collection['reportCharts'];
$this->project = $id;
$this->periodDates = $periodDates;
$this->projectName = Project::find($id)->name;
$this->reportData = $collection['reportData'];
$this->countDate = count($this->periodDates);
}
public function columnWidths(): array
{
$columnWidths = ['A' => 45];
$currentColumn = 2;
while ($currentColumn <= $this->countDate + 1) {
$columnWidths[Coordinate::stringFromColumnIndex($currentColumn)] = 25;
$currentColumn++;
}
return $columnWidths;
}
public function array(): array
{
if (isset($this->data['total_spent_time_day']['datasets'])) {
foreach ($this->data['total_spent_time_day']['datasets'] as $projectId => $project) {
if ($projectId !== $this->project)
continue;
$resultRow = [];
$resultRow[] = $project['label'] ?? '';
$this->projectName = $project['label'] ?? '';
if (isset($project['data'])) {
foreach ($project['data'] as $date => $time) {
$resultRow[] = $this->formatDuration($time);
}
}
$result[] = $resultRow;
}
}
if (isset($this->data['total_spent_time_day_and_users_separately']['datasets'])) {
$resultRow = [];
$resultRow[] = 'user name';
$resultRow[] = ' ';
$resultRow[] = ' ';
$resultRow[] = ' ';
$resultRow[] = ' ';
$resultRow[] = ' ';
$resultRow[] = ' ';
$result[] = $resultRow;
foreach ($this->data['total_spent_time_day_and_users_separately']['datasets'] as $projectId => $userTask) {
if ($projectId !== $this->project)
continue;
foreach ($userTask as $userId => $user) {
$resultRow = [];
$resultRow[] = $user['label'] ?? '';
if (isset($user['data'])) {
foreach ($user['data'] as $date => $time) {
$resultRow[] = $this->formatDuration($time);
}
}
$result[] = $resultRow;
}
}
}
if (isset($this->reportData)) {
foreach ($this->reportData as $projectId => $project) {
if ($projectId !== $this->project)
continue;
$resultRow = [];
$resultRow[] = 'Project name';
$resultRow[] = 'Create at';
$resultRow[] = 'Description';
$resultRow[] = 'Important';
$result[] = $resultRow;
$resultRow = [];
$resultRow[] = $project['name'] ?? '';
$resultRow[] = $project['created_at'] ?? '';
$resultRow[] = $project['description'] ?? '';
$resultRow[] = $project['important'] ?? '';
$result[] = $resultRow;
$resultRow = [];
$resultRow[] = 'Task information';
$resultRow[] = 'Task name';
$resultRow[] = 'Status';
$resultRow[] = 'Due date';
$resultRow[] = 'Time estimat';
$resultRow[] = 'Descriptione';
$result[] = $resultRow;
if (isset($project['tasks'])) {
foreach ($project['tasks'] as $taskId => $task) {
$resultRow = [];
$resultRow[] = '';
$resultRow[] = $task['task_name'] ?? '';
$resultRow[] = $task['status'] ?? '';
$resultRow[] = $task['due_date'] ?? 'Отсутствует';
$resultRow[] = $task['estimate'] ?? 'Отсутствует';
$resultRow[] = $task['description'] ?? '';
$result[] = $resultRow;
}
}
if (isset($projectTasks['users'])) {
$resultRow = [];
$resultRow[] = 'User Name';
$resultRow[] = 'User Email';
$resultRow[] = 'Total time';
$result[] = $resultRow;
foreach ($projectTasks['users'] as $taskId => $user) {
$resultRow = [];
$resultRow[] = $user['full_name'] ?? '';
$resultRow[] = $user['email'] ?? '';
$resultRow[] = $user['total_spent_time_by_user'] ?? 'Отсутствует';
if (isset($user['workers_day'])) {
foreach ($user['workers_day'] as $date => $time)
$resultRow[] = 'Data ' . $date . ' time: ' . $time;
}
$result[] = $resultRow;
}
}
}
}
return $result;
}
public function charts()
{
$createDataSeries = function ($label, $categories, $values) {
return new DataSeries(
DataSeries::TYPE_LINECHART,
DataSeries::GROUPING_STANDARD,
[0],
$label,
$categories,
$values
);
};
$createChart = function ($name, $title, $position, $offset, $startColumn, $endColumn, $rowCount, $columnLast) use ($createDataSeries) {
$series = [];
if (empty($rowCount)) {
$label = [new DataSeriesValues('String', "'" . $this->title() . "'" . '!A2', null, 1)];
$categories = [new DataSeriesValues('String', "'" . $this->title() . "'" . "!{$startColumn}1:{$endColumn}1", null, $columnLast)];
$values = [new DataSeriesValues('Number', "'" . $this->title() . "'" . "!{$startColumn}2:{$endColumn}2", null, $columnLast)];
$series[] = $createDataSeries($label, $categories, $values);
} else {
for ($i = $rowCount[0]; $i < $rowCount[1]; $i++) {
$label = [new DataSeriesValues('String', "'" . $this->title() . "'" . '!A' . $i, null, $i)];
$categories = [new DataSeriesValues('String', "'" . $this->title() . "'" . "!{$startColumn}1:{$endColumn}1", null, $columnLast)];
$values = [new DataSeriesValues('Number', "'" . $this->title() . "'" . "!{$startColumn}" . $i . ":!{$endColumn}" . $i, null, $columnLast)];
$series[] = $createDataSeries($label, $categories, $values);
}
}
$plot = new PlotArea(null, $series);
$legend = new Legend();
$chart = new Chart($name, new Title($title), $legend, $plot);
$chart->setTopLeftPosition($position[0]);
$chart->setTopLeftOffset($offset[0], $offset[0]);
$chart->setBottomRightPosition($position[1]);
$chart->setBottomRightOffset($offset[1], $offset[1]);
return $chart;
};
$columnNumber = $this->countDate;
$charts = [];
$columnLast = Coordinate::stringFromColumnIndex($columnNumber + 1);
$rowCounts = $this->rowCount();
if ($this->showTasksChart)
$charts[] = $createChart(static::TEXT_USER, static::TEXT_USER, static::POSITIONS_CHART[0], static::OFFSET_CHART, static::COLUMN_FIRST, $columnLast, [], $columnNumber);
if ($this->showUsersChart)
$charts[] = $createChart(static::TEXT_USER_INDIVIDUALLY, static::TEXT_USER_INDIVIDUALLY, static::POSITIONS_CHART[1], static::OFFSET_CHART, static::COLUMN_FIRST, $columnLast, [4, $rowCounts + 4], $columnNumber);
return $charts;
}
public function headings(): array
{
return [
'Project Name',
...collect($this->periodDates)->map(fn($date) => Carbon::parse($date)->format('y-m-d'))
];
}
protected function rowCount()
{
$count = 0;
if (isset($this->data['total_spent_time_day']['datasets'])) {
$this->showTasksChart = isset($this->data['total_spent_time_day']['datasets'][$this->project]);
}
if (isset($this->data['total_spent_time_day_and_users_separately']['datasets'])) {
$this->showUsersChart = isset($this->data['total_spent_time_day_and_users_separately']['datasets'][$this->project]);
foreach ($this->data['total_spent_time_day_and_users_separately']['datasets'] as $projectId => $userTasks) {
if ($projectId !== $this->project) {
continue;
}
$count += count($userTasks);
}
}
return $count;
}
/**
* @return string
*/
public function title(): string
{
return \Str::limit("{$this->project}) $this->projectName", 8);
}
}

View File

@@ -0,0 +1,182 @@
<?php
namespace App\Reports;
use App\Contracts\AppReport;
use App\Helpers\ReportHelper;
use Carbon\Carbon;
use Carbon\CarbonInterval;
use Carbon\CarbonPeriod;
use Exception;
use Illuminate\Support\Collection;
use Maatwebsite\Excel\Concerns\FromCollection;
use Maatwebsite\Excel\Concerns\Exportable;
use Maatwebsite\Excel\Concerns\WithMapping;
use Maatwebsite\Excel\Concerns\ShouldAutoSize;
use Maatwebsite\Excel\Concerns\WithHeadings;
use Maatwebsite\Excel\Concerns\WithStyles;
use PhpOffice\PhpSpreadsheet\Style\Alignment;
use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet;
class ProjectReportExport extends AppReport implements FromCollection, WithMapping, ShouldAutoSize, WithHeadings, WithStyles
{
use Exportable;
const PICS_AMOUNT = 6;
private readonly CarbonPeriod $period;
public function __construct(
private readonly ?array $users,
private readonly ?array $projects,
private readonly Carbon $startAt,
private readonly Carbon $endAt,
private readonly string $companyTimezone,
)
{
$this->period = CarbonPeriod::create($this->startAt, $this->endAt);
}
public function collection(): Collection
{
$that = $this;
return $this->queryReport()->map(static function ($interval) use ($that) {
$date = optional(Carbon::make($interval->start_at));
$interval->hour = $date->hour;
$interval->day = $date->format('Y-m-d');
$interval->minute = round($date->minute, -1);
$interval->duration = Carbon::make($interval->end_at)?->diffInSeconds(Carbon::make($interval->start_at));
$interval->durationByDay = ReportHelper::getIntervalDurationByDay($interval, $that->companyTimezone);
$interval->durationAtSelectedPeriod = ReportHelper::getIntervalDurationInPeriod(
$that->period,
$interval->durationByDay
);
return $interval;
})->groupBy('project_id')->map(
static fn(Collection $collection, int $key) => [
'id' => $key,
'name' => $collection->first()->project_name,
'time' => $collection->sum('durationAtSelectedPeriod'),
'users' => $collection->groupBy('user_id')->map(
static fn(Collection $collection, int $key) => [
'id' => $key,
'full_name' => $collection->first()->full_name,
'email' => $collection->first()->user_email,
'time' => $collection->sum('durationAtSelectedPeriod'),
'tasks' => $collection->groupBy('task_id')->map(
static fn(Collection $collection, int $key) => [
'id' => $key,
'task_name' => $collection->first()->task_name,
'time' => $collection->sum('durationAtSelectedPeriod'),
'intervals' => $collection->groupBy('day')->map(
static fn(Collection $collection, string $key) => [
'date' => $key,
'time' => $collection->sum('durationAtSelectedPeriod'),
'items' => $collection->groupBy('hour')->map(
static fn(Collection $collection
) => $collection
->split(self::PICS_AMOUNT)
->map(fn(Collection $group, $i
) => $i < (self::PICS_AMOUNT - 1) ? $group->first() : $group->last())
->values(),
)->values(),
],
)->values(),
],
)->values(),
],
)->values(),
],
)->values();
}
/**
* @param $row
* @return array
* @throws Exception
*/
public function map($row): array
{
return array_merge(
$row['users']
->map(static fn($collection) => $collection['tasks'])->flatten(1)
->map(static fn($collection) => array_merge(
$collection['intervals']->map(
static fn($collection) => $collection['items']
)->flatten(2)->unique(static fn($item) => $item->task_id)->map(
static fn($collection) => array_values($collection->only([
'project_name',
'full_name',
'task_name'
]))
)->flatten(1)->all(),
[
CarbonInterval::seconds($collection['time'])->cascade()->forHumans(),
round(CarbonInterval::seconds($collection['time'])->totalHours, 3)
]
))
->all(),
[
[
"Subtotal for {$row['name']}",
'',
'',
CarbonInterval::seconds($row['time'])->cascade()->forHumans(),
round(CarbonInterval::seconds($row['time'])->totalHours, 3),
],
[]
]
);
}
private function queryReport(): Collection
{
return ReportHelper::getBaseQuery(
$this->users,
$this->startAt,
$this->endAt,
[
'time_intervals.start_at',
'time_intervals.activity_fill',
'time_intervals.mouse_fill',
'time_intervals.keyboard_fill',
'time_intervals.end_at',
'users.email as user_email',
]
)->whereIn('project_id', $this->projects)->get();
}
public function headings(): array
{
return [
'Project Name',
'User Name',
'Task Name',
'Hours',
'Hours (decimal)',
];
}
public function styles(Worksheet $sheet): array
{
return [
1 => ['font' => ['bold' => true], 'alignment' => ['horizontal' => Alignment::HORIZONTAL_CENTER]],
];
}
public function getReportId(): string
{
return 'project_report';
}
public function getLocalizedReportName(): string
{
return __('Project_Report');
}
}

View File

@@ -0,0 +1,235 @@
<?php
namespace App\Reports;
use Maatwebsite\Excel\Concerns\FromArray;
use Maatwebsite\Excel\Concerns\WithCharts;
use Maatwebsite\Excel\Concerns\WithTitle;
use PhpOffice\PhpSpreadsheet\Chart\Chart;
use PhpOffice\PhpSpreadsheet\Chart\DataSeries;
use PhpOffice\PhpSpreadsheet\Chart\DataSeriesValues;
use PhpOffice\PhpSpreadsheet\Chart\Legend;
use PhpOffice\PhpSpreadsheet\Chart\PlotArea;
use PhpOffice\PhpSpreadsheet\Chart\Title;
use Carbon\Carbon;
use Maatwebsite\Excel\Concerns\WithColumnWidths;
use Maatwebsite\Excel\Concerns\WithHeadings;
use PhpOffice\PhpSpreadsheet\Cell\Coordinate;
class TaskMultiSheetExport extends BaseExport implements FromArray, WithTitle, WithCharts, WithHeadings, WithColumnWidths
{
private $data;
private $task;
private $taskName;
private $periodDates;
private $countDate;
private $reportData;
const COLUMN_FIRST = 'B';
const OFFSET_CHART = [10, 30];
const POSITIONS_CHART = [['A8', 'D38'], ['E8', 'H38']];
const TEXT_USER = 'Worked by all users';
const TEXT_USER_INDIVIDUALLY = 'Worked by all users individually';
public function __construct(array $collection, $taskId, $taskName, array $periodDates)
{
$this->data = $collection['reportCharts'];
$this->reportData = $collection['reportData'];
$this->task = $taskId;
$this->taskName = $taskName;
$this->periodDates = $periodDates;
$this->countDate = count($this->periodDates);
}
public function columnWidths(): array
{
$columnWidths = ['A' => 45];
$currentColumn = 2;
while ($currentColumn <= $this->countDate + 1) {
$columnWidths[Coordinate::stringFromColumnIndex($currentColumn)] = 25;
$currentColumn++;
}
return $columnWidths;
}
public function array(): array
{
if (isset($this->data['total_spent_time_day']['datasets'])) {
foreach ($this->data['total_spent_time_day']['datasets'] as $taskId => $task) {
if ($taskId !== $this->task)
continue;
$resultRow = [];
$resultRow[] = $task['label'] ?? '';
$this->taskName = $task['label'] ?? '';
if (isset($task['data'])) {
foreach ($task['data'] as $date => $time) {
$resultRow[] = $this->formatDuration($time);
}
}
$result[] = $resultRow;
}
}
if (isset($this->data['total_spent_time_day_users_separately']['datasets'])) {
$resultRow = [];
$resultRow[] = 'User name';
$resultRow[] = ' ';
$resultRow[] = ' ';
$resultRow[] = ' ';
$resultRow[] = ' ';
$resultRow[] = ' ';
$resultRow[] = ' ';
$result[] = $resultRow;
foreach ($this->data['total_spent_time_day_users_separately']['datasets'] as $taskId => $userTask) {
if ($taskId !== $this->task)
continue;
foreach ($userTask as $userId => $user) {
$resultRow = [];
$resultRow[] = $user['label'] ?? '';
if (isset($user['data'])) {
foreach ($user['data'] as $date => $time) {
$resultRow[] = $this->formatDuration($time);
}
}
$result[] = $resultRow;
}
}
}
if (isset($this->reportData)) {
foreach ($this->reportData as $taskId => $userTasks) {
if ($taskId !== $this->task)
continue;
$resultRow = [];
if (isset($userTasks['users'])) {
foreach ($userTasks['users'] as $taskId => $taskData) {
$resultRow = [];
$resultRow[] = 'User name';
$resultRow[] = 'Email user';
$resultRow[] = 'Total time';
$resultRow[] = 'Task name';
$resultRow[] = 'Priority';
$resultRow[] = 'Status';
$resultRow[] = 'Estimate';
$resultRow[] = 'Description';
$result[] = $resultRow;
$resultRow = [];
$resultRow[] = $taskData['full_name'] ?? '';
$resultRow[] = $taskData['email'] ?? '';
$resultRow[] = $taskData['total_spent_time_by_user'] ?? '';
$resultRow[] = $userTasks['task_name'] ?? '';
$resultRow[] = $userTasks['priority'] ?? '';
$resultRow[] = $userTasks['status'] ?? '';
$resultRow[] = $userTasks['estimate'] ?? '';
$resultRow[] = $userTasks['description'] ?? '';
if (isset($taskData['workers_day'])) {
foreach ($taskData['workers_day'] as $date => $time) {
$resultRow[] = 'Data ' . $date . ' time: ' . $this->formatDuration($time);
}
}
$result[] = $resultRow;
}
}
$resultRow = [];
$resultRow[] = 'Project name';
$resultRow[] = 'created at';
$resultRow[] = 'description';
$resultRow[] = 'important';
$result[] = $resultRow;
$resultRow = [];
$resultRow[] = $userTasks['project']['name'] ?? '';
$resultRow[] = $userTasks['project']['created_at'] ?? '';
$resultRow[] = $userTasks['project']['description'] ?? '';
$resultRow[] = $userTasks['project']['important'] ?? '';
$result[] = $resultRow;
}
}
return $result;
}
public function charts()
{
$createDataSeries = function ($label, $categories, $values) {
return new DataSeries(
DataSeries::TYPE_LINECHART,
DataSeries::GROUPING_STANDARD,
[0],
$label,
$categories,
$values
);
};
$createChart = function ($name, $title, $position, $offset, $startColumn, $endColumn, $rowCount, $columnLast) use ($createDataSeries) {
$series = [];
if (empty($rowCount)) {
$label = [new DataSeriesValues('String', "'" . $this->title() . "'" . '!A2', null, 1)];
$categories = [new DataSeriesValues('String', "'" . $this->title() . "'" . "!{$startColumn}1:{$endColumn}1", null, $columnLast)];
$values = [new DataSeriesValues('Number', "'" . $this->title() . "'" . "!{$startColumn}2:{$endColumn}2", null, $columnLast)];
$series[] = $createDataSeries($label, $categories, $values);
} else {
for ($i = $rowCount[0]; $i < $rowCount[1]; $i++) {
$label = [new DataSeriesValues('String', "'" . $this->title() . "'" . '!A' . $i, null, $i)];
$categories = [new DataSeriesValues('String', "'" . $this->title() . "'" . "!{$startColumn}1:{$endColumn}1", null, $columnLast)];
$values = [new DataSeriesValues('Number', "'" . $this->title() . "'" . "!{$startColumn}" . $i . ":!{$endColumn}" . $i, null, $columnLast)];
$series[] = $createDataSeries($label, $categories, $values);
}
}
$plot = new PlotArea(null, $series);
$legend = new Legend();
$chart = new Chart($name, new Title($title), $legend, $plot);
$chart->setTopLeftPosition($position[0]);
$chart->setTopLeftOffset($offset[0], $offset[0]);
$chart->setBottomRightPosition($position[1]);
$chart->setBottomRightOffset($offset[1], $offset[1]);
return $chart;
};
$columnNumber = $this->countDate;
$charts = [];
$columnLast = Coordinate::stringFromColumnIndex($columnNumber + 1);
$charts[] = $createChart(static::TEXT_USER, static::TEXT_USER, static::POSITIONS_CHART[0], static::OFFSET_CHART, static::COLUMN_FIRST, $columnLast, [], $columnNumber);
$charts[] = $createChart(static::TEXT_USER_INDIVIDUALLY, static::TEXT_USER_INDIVIDUALLY, static::POSITIONS_CHART[1], static::OFFSET_CHART, static::COLUMN_FIRST, $columnLast, [4, $this->rowCount() + 4], $columnNumber);
return $charts;
}
public function headings(): array
{
return [
'Task Name',
...collect($this->periodDates)->map(fn($date) => Carbon::parse($date)->format('y-m-d'))
];
}
/**
* @return string
*/
public function title(): string
{
return \Str::limit("{$this->task}) $this->taskName", 8);
}
protected function rowCount()
{
$count = 0;
if (isset($this->data['total_spent_time_day_users_separately']['datasets'])) {
foreach ($this->data['total_spent_time_day_users_separately']['datasets'] as $taskId => $userTasks) {
if ($taskId !== $this->task)
continue;
$count += count($userTasks);
}
}
return $count;
}
}

View File

@@ -0,0 +1,112 @@
<?php
namespace App\Reports;
use App\Contracts\AppReport;
use App\Helpers\ReportHelper;
use Carbon\Carbon;
use Carbon\CarbonPeriod;
use Illuminate\Support\Collection;
use Maatwebsite\Excel\Concerns\Exportable;
use Maatwebsite\Excel\Concerns\FromCollection;
use Maatwebsite\Excel\Concerns\ShouldAutoSize;
use Maatwebsite\Excel\Concerns\WithHeadings;
use Maatwebsite\Excel\Concerns\WithMapping;
use Maatwebsite\Excel\Concerns\WithStyles;
use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet;
class TimeUseReportExport extends AppReport implements FromCollection, WithMapping, ShouldAutoSize, WithHeadings, WithStyles
{
use Exportable;
private readonly CarbonPeriod $period;
public function __construct(
private readonly ?array $users,
private readonly Carbon $startAt,
private readonly Carbon $endAt,
private readonly string $companyTimezone
)
{
$this->period = CarbonPeriod::create($this->startAt, $this->endAt);
}
public function collection(): Collection
{
$that = $this;
return $this->queryReport()->map(static function ($interval) use ($that) {
$interval->duration = Carbon::make($interval->end_at)?->diffInSeconds(Carbon::make($interval->start_at));
$interval->durationByDay = ReportHelper::getIntervalDurationByDay($interval, $that->companyTimezone);
$interval->durationAtSelectedPeriod = ReportHelper::getIntervalDurationInPeriod(
$that->period,
$interval->durationByDay
);
return $interval;
})->groupBy('user_id')->map(
static fn($collection) => [
'time' => $collection->sum('durationAtSelectedPeriod'),
'user' => [
'id' => $collection->first()->user_id,
'email' => $collection->first()->user_email,
'full_name' => $collection->first()->full_name,
],
'tasks' => $collection->groupBy('task_id')->map(
static fn($collection) => [
'time' => $collection->sum('durationAtSelectedPeriod'),
'task_id' => $collection->first()->task_id,
'task_name' => $collection->first()->task_name,
'project_id' => $collection->first()->project_id,
'project_name' => $collection->first()->project_name,
],
)->values(),
],
)->values();
}
public function map($row): array
{
// TODO: Implement map() method.
return [];
}
private function queryReport(): Collection
{
return ReportHelper::getBaseQuery(
$this->users,
$this->startAt,
$this->endAt,
[
'time_intervals.start_at',
'time_intervals.activity_fill',
'time_intervals.mouse_fill',
'time_intervals.keyboard_fill',
'time_intervals.end_at',
'users.email as user_email',
]
)->get();
}
public function getReportId(): string
{
return 'time_use_report';
}
public function getLocalizedReportName(): string
{
return __('Time_Use_Report');
}
public function headings(): array
{
return [];
}
public function styles(Worksheet $sheet): array
{
return [];
}
}

View File

@@ -0,0 +1,159 @@
<?php
namespace App\Reports;
use App\Contracts\AppReport;
use App\Enums\UniversalReportBase;
use App\Helpers\ReportHelper;
use App\Models\UniversalReport;
use App\Services\UniversalReportServiceProject;
use App\Services\UniversalReportServiceTask;
use App\Services\UniversalReportServiceUser;
use Carbon\Carbon;
use Carbon\CarbonPeriod;
use Illuminate\Support\Collection;
use Maatwebsite\Excel\Concerns\FromCollection;
use Maatwebsite\Excel\Concerns\Exportable;
use Maatwebsite\Excel\Concerns\WithDefaultStyles;
use Maatwebsite\Excel\Concerns\ShouldAutoSize;
use Maatwebsite\Excel\Concerns\WithMultipleSheets;
use PhpOffice\PhpSpreadsheet\Style\Alignment;
use PhpOffice\PhpSpreadsheet\Style\Style;
class UniversalReportExport extends AppReport implements FromCollection, ShouldAutoSize, WithDefaultStyles, WithMultipleSheets
{
use Exportable;
private array $periodDates;
private UniversalReport $report;
private string $colsDateFormat;
private readonly CarbonPeriod $period;
public function __construct(
private readonly int $id,
private readonly Carbon $startAt,
private readonly Carbon $endAt,
private readonly string $companyTimezone,
) {
$this->report = UniversalReport::find($id);
$this->period = CarbonPeriod::create(
$this->startAt->clone()->setTimezone($this->companyTimezone),
$this->endAt->clone()->setTimezone($this->companyTimezone)
);
$this->periodDates = $this->getPeriodDates($this->period);
}
public function collection(): Collection
{
return match ($this->report->base) {
UniversalReportBase::PROJECT => $this->collectionProject(),
UniversalReportBase::USER => $this->collectionUser(),
UniversalReportBase::TASK => $this->collectionTask()
};
}
public function sheets(): array
{
$sheets = [];
switch ($this->report->base) {
case UniversalReportBase::USER:
$collection = $this->collectionUser()->all();
$data = $collection['reportCharts'];
if (isset($data['total_spent_time_day']['datasets'])) {
foreach ($data['total_spent_time_day']['datasets'] as $userId => $user) {
$sheets[] = new UserMultiSheetExport($collection, $userId, ($user['label'] ?? ''), $this->periodDates);
}
}
break;
case UniversalReportBase::TASK:
$collection = $this->collectionTask()->all();
$data = $collection['reportCharts'];
if (isset($data['total_spent_time_day']['datasets'])) {
foreach ($data['total_spent_time_day']['datasets'] as $taskId => $task) {
$sheets[] = new TaskMultiSheetExport($collection, $taskId, ($task['label'] ?? ''), $this->periodDates);
}
}
break;
case UniversalReportBase::PROJECT:
$collection = $this->collectionProject()->all();
$charts = $collection['reportCharts'];
$projectTasksIds = [];
$projectUsersIds = [];
if (isset($charts['total_spent_time_day']['datasets'])) {
$projectTasksIds = array_keys($charts['total_spent_time_day']['datasets'] ?? []);
}
if (isset($charts['total_spent_time_day_and_users_separately']['datasets'])) {
$projectUsersIds = array_keys($charts['total_spent_time_day_and_users_separately']['datasets'] ?? []);
}
if (isset($charts['total_spent_time_day']['datasets']) || isset($charts['total_spent_time_day_and_users_separately']['datasets'])) {
$allIdsProjects = array_merge($projectTasksIds, $projectUsersIds);
$allIdsProjects = array_unique($allIdsProjects);
foreach ($allIdsProjects as $id) {
$sheets[] = new ProjectMultiSheetExport($collection, $id, $this->periodDates);
}
}
break;
}
if (empty($sheets)) {
$sheets[] = new DummySheetExport();
}
return $sheets;
}
public function collectionUser(): Collection
{
$service = new UniversalReportServiceUser($this->startAt, $this->endAt, $this->report, $this->periodDates);
return collect([
'reportData' => $service->getUserReportData(),
'reportName' => $this->report->name,
'reportCharts' => $service->getUserReportCharts(),
'periodDates' => $this->periodDates,
]);
}
public function collectionTask(): Collection
{
$service = new UniversalReportServiceTask($this->startAt, $this->endAt, $this->report, $this->periodDates);
return collect([
'reportData' => $service->getTaskReportData(),
'reportName' => $this->report->name,
'reportCharts' => $service->getTasksReportCharts(),
'periodDates' => $this->periodDates,
]);
}
public function collectionProject(): Collection
{
$service = new UniversalReportServiceProject($this->startAt, $this->endAt, $this->report, $this->periodDates);
return collect([
'reportData' => $service->getProjectReportData(),
'reportName' => $this->report->name,
'reportCharts' => $service->getProjectReportCharts(),
'periodDates' => $this->periodDates,
]);
}
private function getPeriodDates($period): array
{
$dates = [];
foreach ($period as $date) {
$dates[] = $date->format(ReportHelper::$dateFormat);
}
return $dates;
}
public function getReportId(): string
{
return 'universal_report';
}
public function getLocalizedReportName(): string
{
return __('Universal_Report');
}
public function defaultStyles(Style $defaultStyle)
{
return ['alignment' => ['horizontal' => Alignment::HORIZONTAL_RIGHT]];
}
}

View File

@@ -0,0 +1,268 @@
<?php
namespace App\Reports;
use Maatwebsite\Excel\Concerns\FromArray;
use Maatwebsite\Excel\Concerns\WithCharts;
use Maatwebsite\Excel\Concerns\WithTitle;
use PhpOffice\PhpSpreadsheet\Chart\Chart;
use PhpOffice\PhpSpreadsheet\Chart\DataSeries;
use PhpOffice\PhpSpreadsheet\Chart\DataSeriesValues;
use PhpOffice\PhpSpreadsheet\Chart\Legend;
use PhpOffice\PhpSpreadsheet\Chart\PlotArea;
use PhpOffice\PhpSpreadsheet\Chart\Title;
use Carbon\Carbon;
use Maatwebsite\Excel\Concerns\WithColumnWidths;
use Maatwebsite\Excel\Concerns\WithHeadings;
use PhpOffice\PhpSpreadsheet\Cell\Coordinate;
class UserMultiSheetExport extends BaseExport implements FromArray, WithTitle, WithCharts, WithHeadings, WithColumnWidths
{
private $data;
private $reportData;
private $user;
private $userName;
private $periodDates;
private $countDate;
const COLUMN_FIRST = 'B';
const OFFSET_CHART = [10, 30];
const POSITIONS_CHART = [['A8', 'E38'], ['F8', 'R38'], ['S8', 'Z30']];
const TEXT_USER = 'Worked by all users';
const TEXT_TASK = 'Hours by tasks';
const TEXT_PROJECT = 'Hours by projects';
public function __construct(array $collection, $userId, $userName, array $periodDates)
{
$this->data = $collection['reportCharts'];
$this->reportData = $collection['reportData'];
$this->user = $userId;
$this->userName = $userName;
$this->periodDates = $periodDates;
$this->countDate = count($this->periodDates);
}
public function columnWidths(): array
{
$columnWidths = ['A' => 45];
$currentColumn = 2;
while ($currentColumn <= $this->countDate + 1) {
$columnWidths[Coordinate::stringFromColumnIndex($currentColumn)] = 25;
$currentColumn++;
}
return $columnWidths;
}
public function array(): array
{
if (isset($this->data['total_spent_time_day']['datasets'])) {
foreach ($this->data['total_spent_time_day']['datasets'] as $userId => $user) {
if ($userId !== $this->user)
continue;
$resultRow = [];
$resultRow[] = $user['label'] ?? '';
$this->userName = $user['label'] ?? '';
if (isset($user['data'])) {
foreach ($user['data'] as $date => $time) {
$resultRow[] = $this->formatDuration($time);
}
}
$result[] = $resultRow;
}
}
if (isset($this->data['total_spent_time_day_and_tasks']['datasets'])) {
$resultRow = [];
$resultRow[] = 'task name';
$resultRow[] = ' ';
$resultRow[] = ' ';
$resultRow[] = ' ';
$resultRow[] = ' ';
$resultRow[] = ' ';
$resultRow[] = ' ';
$result[] = $resultRow;
foreach ($this->data['total_spent_time_day_and_tasks']['datasets'] as $userId => $userTasks) {
if ($userId !== $this->user)
continue;
foreach ($userTasks as $taskId => $task) {
$resultRow = [];
$resultRow[] = $task['label'] ?? '';
if (isset($task['data'])) {
foreach ($task['data'] as $date => $time) {
$resultRow[] = $this->formatDuration($time);
}
}
$result[] = $resultRow;
}
}
}
if (isset($this->data['total_spent_time_day_and_projects']['datasets'])) {
$resultRow = [];
$resultRow[] = 'task project';
$resultRow[] = ' ';
$resultRow[] = ' ';
$resultRow[] = ' ';
$resultRow[] = ' ';
$resultRow[] = ' ';
$resultRow[] = ' ';
$result[] = $resultRow;
foreach ($this->data['total_spent_time_day_and_projects']['datasets'] as $userId => $userTasks) {
if ($userId !== $this->user)
continue;
foreach ($userTasks as $taskId => $task) {
$resultRow = [];
$resultRow[] = $task['label'] ?? '';
if (isset($task['data'])) {
foreach ($task['data'] as $date => $time) {
$resultRow[] = $this->formatDuration($time);
}
}
$result[] = $resultRow;
}
}
}
if (isset($this->reportData)) {
$resultRow = [];
$resultRow[] = 'User Name';
$resultRow[] = 'User Email';
$resultRow[] = 'Project Name';
$resultRow[] = 'Project created at';
$resultRow[] = 'Task name';
$resultRow[] = 'Task priority';
$resultRow[] = 'Task status';
$resultRow[] = 'Task due date';
$resultRow[] = 'Task description';
$result[] = $resultRow;
foreach ($this->reportData as $userId => $user) {
if ($userId !== $this->user)
continue;
if (isset($user['projects'])) {
foreach ($user['projects'] as $projectId => $project) {
if (isset($project['tasks'])) {
foreach ($project['tasks'] as $taskId => $task) {
$resultRow = [];
$resultRow[] = $user['full_name'] ?? '';
$resultRow[] = $user['email'] ?? '';
$resultRow[] = $project['name'] ?? '';
$resultRow[] = $project['created_at'] ?? '';
$resultRow[] = $task['task_name'] ?? '';
$resultRow[] = $task['priority'] ?? '';
$resultRow[] = $task['status'] ?? '';
$resultRow[] = $task['due_date'] ?? '';
$resultRow[] = $task['description'] ?? '';
$result[] = $resultRow;
}
}
}
}
}
}
return $result;
}
public function charts()
{
$createDataSeries = function ($label, $categories, $values) {
return new DataSeries(
DataSeries::TYPE_LINECHART,
DataSeries::GROUPING_STANDARD,
[0],
$label,
$categories,
$values
);
};
$createChart = function ($name, $title, $position, $offset, $startColumn, $endColumn, $rowCount, $columnLast) use ($createDataSeries) {
$series = [];
if (empty($rowCount)) {
$label = [new DataSeriesValues('String', "'" . $this->title() . "'" . '!A2', null, 1)];
$categories = [new DataSeriesValues('String', "'" . $this->title() . "'" . "!{$startColumn}1:{$endColumn}1", null, $columnLast)];
$values = [new DataSeriesValues('Number', "'" . $this->title() . "'" . "!{$startColumn}2:{$endColumn}2", null, $columnLast)];
$series[] = $createDataSeries($label, $categories, $values);
} else {
for ($i = $rowCount[0]; $i < $rowCount[1]; $i++) {
$label = [new DataSeriesValues('String', "'" . $this->title() . "'" . '!A' . $i, null, $i)];
$categories = [new DataSeriesValues('String', "'" . $this->title() . "'" . "!{$startColumn}1:{$endColumn}1", null, $columnLast)];
$values = [new DataSeriesValues('Number', "'" . $this->title() . "'" . "!{$startColumn}" . $i . ":!{$endColumn}" . $i, null, $columnLast)];
$series[] = $createDataSeries($label, $categories, $values);
}
}
$plot = new PlotArea(null, $series);
$legend = new Legend();
$chart = new Chart($name, new Title($title), $legend, $plot);
$chart->setTopLeftPosition($position[0]);
$chart->setTopLeftOffset($offset[0], $offset[0]);
$chart->setBottomRightPosition($position[1]);
$chart->setBottomRightOffset($offset[1], $offset[1]);
return $chart;
};
$columnNumber = $this->countDate;
$charts = [];
$columnLast = Coordinate::stringFromColumnIndex($columnNumber + 1);
$charts[] = $createChart(static::TEXT_USER, static::TEXT_USER, static::POSITIONS_CHART[0], static::OFFSET_CHART, static::COLUMN_FIRST, $columnLast, [], $columnNumber);
$charts[] = $createChart(static::TEXT_TASK, static::TEXT_TASK, static::POSITIONS_CHART[1], static::OFFSET_CHART, static::COLUMN_FIRST, $columnLast, [4, $this->rowCount() + 4], $columnNumber);
$charts[] = $createChart(static::TEXT_PROJECT, static::TEXT_PROJECT, static::POSITIONS_CHART[2], static::OFFSET_CHART, static::COLUMN_FIRST, $columnLast, [$this->rowCount() + 5, $this->rowCountProject() + $this->rowCount() + 5], $columnNumber);
return $charts;
}
public function headings(): array
{
return [
'User Name',
...collect($this->periodDates)->map(fn($date) => Carbon::parse($date)->format('y-m-d'))
];
}
/**
* @return string
*/
public function title(): string
{
return \Str::limit("$this->userName", 10);
}
protected function rowCount()
{
$count = 0;
if (isset($this->data['total_spent_time_day_and_tasks']['datasets'])) {
foreach ($this->data['total_spent_time_day_and_tasks']['datasets'] as $userId => $userTasks) {
if ($userId !== $this->user)
continue;
$count += count($userTasks);
}
}
return $count;
}
protected function rowCountProject()
{
$count = 0;
if (isset($this->data['total_spent_time_day_and_projects']['datasets'])) {
foreach ($this->data['total_spent_time_day_and_projects']['datasets'] as $userId => $userTasks) {
if ($userId !== $this->user)
continue;
$count += count($userTasks);
}
}
return $count;
}
}