513 lines
21 KiB
PHP
513 lines
21 KiB
PHP
<?php
|
||
|
||
namespace App\Http\Controllers;
|
||
|
||
use Illuminate\Http\Request;
|
||
use App\Http\Requests\LambdaRequest;
|
||
use Maatwebsite\Excel\Facades\Excel;
|
||
use App\Exports\InvoicesExport;
|
||
|
||
class LeaderboardController extends Controller
|
||
{
|
||
public function __construct()
|
||
{
|
||
$this->middleware('auth');
|
||
$this->_service = 'reports';
|
||
$this->_module = 'roles_leaderboard';
|
||
$this->_viewname = 'leaderboard';
|
||
$this->_title = 'Leaderboard';
|
||
$this->_base_url = '/leaderboard';
|
||
}
|
||
|
||
public function list(Request $request)
|
||
{
|
||
$response = LambdaRequest::signedrequest('get', $this->_service, $this->_module.'/get_all');
|
||
if (isset($response->statusCode) && $response->statusCode == 401) {
|
||
return redirect('/unauthorised');
|
||
}
|
||
|
||
$items = isset($response->data->items) ? $response->data->items : [];
|
||
$roleMap = $this->getRoleNameMap();
|
||
foreach ($items as &$item) {
|
||
if (!empty($item->validity_start)) {
|
||
$item->validity_start = date('m/d/Y', strtotime($item->validity_start));
|
||
}
|
||
if (!empty($item->validity_end)) {
|
||
$item->validity_end = date('m/d/Y', strtotime($item->validity_end));
|
||
}
|
||
if (!isset($item->sort_order) || $item->sort_order === null || $item->sort_order === '') {
|
||
$item->sort_order = 0;
|
||
}
|
||
$item->visible_roles_label = $this->formatAssignedRoles($item->visible_roles ?? [], $roleMap);
|
||
}
|
||
unset($item);
|
||
|
||
$fields = $this->get_list_fields();
|
||
return $this->view('list')->with([
|
||
'title' => $this->_title,
|
||
'fields' => $fields,
|
||
'base_url' => $this->_base_url,
|
||
'items' => $items,
|
||
'buttons' => $this->get_list_buttons()
|
||
]);
|
||
}
|
||
|
||
protected function get_list_fields()
|
||
{
|
||
return [
|
||
'actions' => ['title' => 'Actions', 'buttons' => ['edit', 'delete']],
|
||
'name' => ['title' => 'Name', 'type' => 'text'],
|
||
'sort_order' => ['title' => 'Sort Order', 'type' => 'number'],
|
||
'visible_roles_label' => ['title' => 'Visible Roles', 'type' => 'text'],
|
||
'validity_start' => ['title' => 'Validity start', 'type' => 'text'],
|
||
'validity_end' => ['title' => 'Validity end', 'type' => 'text'],
|
||
'status' => ['title' => 'Status', 'type' => 'select'],
|
||
];
|
||
}
|
||
|
||
protected function get_list_buttons()
|
||
{
|
||
return [
|
||
['title' => 'Add New', 'link' => $this->_base_url.'/addnew'],
|
||
];
|
||
}
|
||
|
||
protected function get_form_fields($type, $values)
|
||
{
|
||
$metrics = $this->getlambda('get', 'metric', 'metric', 'get_all');
|
||
$metrics_dd = [];
|
||
if (isset($metrics->data->items) && is_array($metrics->data->items)) {
|
||
foreach ($metrics->data->items as $metric) {
|
||
$metrics_dd[$metric->id] = $metric->name;
|
||
}
|
||
}
|
||
|
||
$roles = $this->getlambda('get', 'ums', 'roles', 'dropdown');
|
||
$roles_dd = [];
|
||
if (isset($roles->data->items) && is_array($roles->data->items)) {
|
||
foreach ($roles->data->items as $role) {
|
||
$roles_dd[$role->id] = $role->name;
|
||
}
|
||
}
|
||
|
||
return [
|
||
'id' => ['title' => '', 'type' => 'hidden'],
|
||
'name' => ['title' => 'Name', 'type' => 'text', 'required' => true],
|
||
'sort_order' => ['title' => 'Sort Order', 'type' => 'number', 'required' => true],
|
||
'validity_start' => ['title' => 'Validity start', 'type' => 'date', 'required' => true],
|
||
'validity_end' => ['title' => 'Validity end', 'type' => 'date', 'required' => true],
|
||
'visible_roles' => ['title' => 'Visible Roles', 'type' => 'multiselect', 'values' => $roles_dd, 'required' => true],
|
||
'reporting_roles' => ['title' => 'Reporting Roles', 'type' => 'multiselect', 'values' => $roles_dd, 'required' => true],
|
||
'rank_roles' => ['title' => 'Rank Roles', 'type' => 'rank_roles', 'roles' => $roles_dd, 'required' => true, 'fullwidth' => true],
|
||
'metrics' => ['title' => 'Choose Metric', 'type' => 'mapping', 'required' => true, 'metrics' => $metrics_dd, 'fullwidth' => true],
|
||
'combined_metrics' => ['title' => 'Combined Metrics (if any)', 'type' => 'combined_metrics', 'fullwidth' => true],
|
||
'intervals' => ['title' => 'Intervals', 'type' => 'multiselect', 'required' => true, 'values' => [
|
||
'yearlycy' => 'Calender Year',
|
||
'yearlyfy' => 'Financial Year',
|
||
'monthly' => 'Monthly',
|
||
'weekly' => 'Weekly',
|
||
'daily' => 'Daily',
|
||
]],
|
||
'default_interval' => ['title' => 'Default Interval', 'type' => 'select', 'values' => [
|
||
'' => 'Overall / All',
|
||
'all' => 'Overall',
|
||
'month-0' => 'This Month',
|
||
'month-1' => 'Last Month',
|
||
'month-3' => 'Last 3 Months',
|
||
'month-6' => 'Last 6 Months',
|
||
'month-12' => 'Last 12 Months',
|
||
'day-0' => 'Today',
|
||
'day-1' => 'Yesterday',
|
||
'day-7' => 'Last 7 Days',
|
||
'day-30' => 'Last 30 Days',
|
||
'week-0' => 'This week',
|
||
'week-1' => 'Last week',
|
||
'yearfy-0' => 'This Financial Year',
|
||
'yearfy-1' => 'Last Financial Year',
|
||
'yearcy-0' => 'This Calender Year',
|
||
'yearcy-1' => 'Last Calender Year',
|
||
]],
|
||
'show_positions' => ['title' => 'Show Positions', 'type' => 'select', 'required' => true, 'values' => ['yes' => 'Yes', 'no' => 'No']],
|
||
'show_positions_type' => ['title' => 'Show Positions Type', 'type' => 'select', 'required' => true, 'values' => ['all' => 'All', 'loggedin' => 'Logged In']],
|
||
'status' => ['title' => 'Status', 'type' => 'select', 'required' => true, 'values' => ['active' => 'Active', 'disabled' => 'Disabled']],
|
||
];
|
||
}
|
||
|
||
protected function _beforesave($type, $request)
|
||
{
|
||
$data = $request->except('_token');
|
||
|
||
$data['sort_order'] = isset($data['sort_order']) && $data['sort_order'] !== '' ? (int) $data['sort_order'] : 0;
|
||
|
||
$metrics = [];
|
||
if (isset($data['metric']) && is_array($data['metric'])) {
|
||
foreach ($data['metric'] as $k => $metric) {
|
||
if ($metric === '' || $metric === null) {
|
||
continue;
|
||
}
|
||
$metrics[] = [
|
||
'metric' => $metric,
|
||
'display' => $data['display_unit'][$k] ?? '',
|
||
'sort_order' => isset($data['metric_sort_order'][$k]) && $data['metric_sort_order'][$k] !== ''
|
||
? (int) $data['metric_sort_order'][$k]
|
||
: 0,
|
||
'weight' => isset($data['weight'][$k]) && $data['weight'][$k] !== '' ? (string) $data['weight'][$k] : '1',
|
||
];
|
||
}
|
||
}
|
||
$data['metrics'] = $metrics;
|
||
|
||
$rankRoles = [];
|
||
if (isset($data['rank_roles']['title']) && is_array($data['rank_roles']['title'])) {
|
||
foreach ($data['rank_roles']['title'] as $i => $title) {
|
||
$role = $data['rank_roles']['role'][$i] ?? '';
|
||
if ($title === '' && $role === '') {
|
||
continue;
|
||
}
|
||
$rankRoles[] = [
|
||
'title' => $title,
|
||
'role' => $role,
|
||
'limit' => isset($data['rank_roles']['limit'][$i]) && $data['rank_roles']['limit'][$i] !== ''
|
||
? (int) $data['rank_roles']['limit'][$i]
|
||
: 10,
|
||
'sort_order' => isset($data['rank_roles']['sort_order'][$i]) && $data['rank_roles']['sort_order'][$i] !== ''
|
||
? (int) $data['rank_roles']['sort_order'][$i]
|
||
: 0,
|
||
];
|
||
}
|
||
}
|
||
$data['rank_roles'] = $rankRoles;
|
||
|
||
$combined_metrics = [];
|
||
if (isset($data['combined_metrics']) && is_array($data['combined_metrics']) && !empty($data['combined_metrics']['type'])) {
|
||
foreach ($data['combined_metrics']['type'] as $i => $v) {
|
||
if ($v === '' || $v === null) {
|
||
continue;
|
||
}
|
||
$combined_metrics[] = [
|
||
'type' => $v,
|
||
'title' => $data['combined_metrics']['title'][$i] ?? '',
|
||
'fields' => isset($data['combined_metrics']['fields'][$i]) ? $data['combined_metrics']['fields'][$i] : [],
|
||
'list_view' => isset($data['combined_metrics']['list_view'][$i]) ? $data['combined_metrics']['list_view'][$i] : 'yes',
|
||
];
|
||
}
|
||
}
|
||
$data['combined_metrics'] = json_encode($combined_metrics);
|
||
|
||
foreach (['visible_roles', 'reporting_roles', 'intervals'] as $field) {
|
||
if (!isset($data[$field]) || !is_array($data[$field])) {
|
||
$data[$field] = [];
|
||
}
|
||
}
|
||
|
||
if (!isset($data['default_interval'])) {
|
||
$data['default_interval'] = '';
|
||
}
|
||
|
||
if (array_key_exists('id', $data) && ($data['id'] === null || $data['id'] === '')) {
|
||
unset($data['id']);
|
||
}
|
||
|
||
unset($data['metric'], $data['display_unit'], $data['metric_sort_order'], $data['weight']);
|
||
|
||
return $data;
|
||
}
|
||
|
||
protected function _beforeform($type, $values)
|
||
{
|
||
if ($type === 'new') {
|
||
return (object) [
|
||
'sort_order' => 0,
|
||
'show_positions' => 'no',
|
||
'show_positions_type' => 'all',
|
||
'status' => 'active',
|
||
'default_interval' => '',
|
||
'combined_metrics' => '[]',
|
||
'metrics' => [],
|
||
'rank_roles' => [],
|
||
'visible_roles' => [],
|
||
'reporting_roles' => [],
|
||
'intervals' => [],
|
||
];
|
||
}
|
||
|
||
if ($type == 'edit') {
|
||
foreach (['visible_roles', 'reporting_roles', 'intervals', 'metrics', 'rank_roles'] as $field) {
|
||
if (!isset($values->{$field}) || !is_array($values->{$field})) {
|
||
$values->{$field} = [];
|
||
}
|
||
}
|
||
|
||
if (!isset($values->combined_metrics) || $values->combined_metrics === '') {
|
||
$values->combined_metrics = '[]';
|
||
} elseif (is_array($values->combined_metrics)) {
|
||
$values->combined_metrics = json_encode($values->combined_metrics);
|
||
}
|
||
|
||
if (!isset($values->sort_order) || $values->sort_order === null || $values->sort_order === '') {
|
||
$values->sort_order = 0;
|
||
}
|
||
|
||
if (isset($values->show_positions)) {
|
||
$values->show_positions = strtolower((string) $values->show_positions);
|
||
}
|
||
if (!isset($values->show_positions_type) || $values->show_positions_type === '') {
|
||
$values->show_positions_type = 'all';
|
||
}
|
||
if (!isset($values->default_interval)) {
|
||
$values->default_interval = '';
|
||
}
|
||
|
||
if (!empty($values->metrics)) {
|
||
usort($values->metrics, function ($a, $b) {
|
||
$aOrder = (int) (is_object($a) ? ($a->sort_order ?? 0) : ($a['sort_order'] ?? 0));
|
||
$bOrder = (int) (is_object($b) ? ($b->sort_order ?? 0) : ($b['sort_order'] ?? 0));
|
||
return $aOrder <=> $bOrder;
|
||
});
|
||
}
|
||
if (!empty($values->rank_roles)) {
|
||
usort($values->rank_roles, function ($a, $b) {
|
||
$aOrder = (int) (is_object($a) ? ($a->sort_order ?? 0) : ($a['sort_order'] ?? 0));
|
||
$bOrder = (int) (is_object($b) ? ($b->sort_order ?? 0) : ($b['sort_order'] ?? 0));
|
||
return $aOrder <=> $bOrder;
|
||
});
|
||
}
|
||
|
||
if (!empty($values->validity_start)) {
|
||
$values->validity_start = date('m/d/Y', strtotime($values->validity_start) + 19800);
|
||
}
|
||
if (!empty($values->validity_end)) {
|
||
$values->validity_end = date('m/d/Y', strtotime($values->validity_end) + 19800);
|
||
}
|
||
}
|
||
|
||
return $values;
|
||
}
|
||
|
||
public function dashboard(Request $request)
|
||
{
|
||
$data = $this->roleLeaderboardViewData($request);
|
||
$data['exportUrl'] = url('/leaderboard/export') . '?' . http_build_query($request->query());
|
||
return view('leaderboard.dashboard', $data);
|
||
}
|
||
|
||
public function export(Request $request)
|
||
{
|
||
$data = $this->roleLeaderboardViewData($request);
|
||
if (!empty($data['error'])) {
|
||
return redirect('/leaderboard/dashboard?' . http_build_query($request->query()))
|
||
->withError($data['error']);
|
||
}
|
||
|
||
$headers = ['Rank', 'User', 'Employee Code', 'Designation', 'Position', 'Score'];
|
||
foreach ($data['metrics'] as $metric) {
|
||
$headers[] = $metric['name'];
|
||
}
|
||
|
||
$exceldata = [$headers];
|
||
foreach ($data['users'] as $index => $user) {
|
||
$row = [
|
||
$user['rank'] ?? ($index + 1),
|
||
$user['name'] ?? '',
|
||
$user['employee_code'] ?? '',
|
||
$user['designation'] ?? '',
|
||
$user['position_name'] ?? '',
|
||
$user['score'] ?? 0,
|
||
];
|
||
foreach ($data['metrics'] as $metric) {
|
||
$row[] = $user['metric_values'][$metric['id']] ?? '';
|
||
}
|
||
$exceldata[] = $row;
|
||
}
|
||
|
||
$filename = preg_replace('/[^A-Za-z0-9_\-]+/', '-', (string) ($data['title'] ?: 'leaderboard'));
|
||
$filename = trim($filename, '-') ?: 'leaderboard';
|
||
|
||
return Excel::download(new InvoicesExport($exceldata), $filename . '.xlsx');
|
||
}
|
||
|
||
protected function roleLeaderboardViewData(Request $request): array
|
||
{
|
||
$id = trim((string) $request->query('id', ''));
|
||
$roleId = trim((string) $request->query('role', ''));
|
||
$empty = [
|
||
'error' => '',
|
||
'title' => 'Leaderboard',
|
||
'subtitle' => '',
|
||
'period_label' => '',
|
||
'users' => [],
|
||
'metrics' => [],
|
||
'pills' => [],
|
||
'selected_role' => $roleId,
|
||
];
|
||
|
||
if ($id === '') {
|
||
$empty['error'] = 'Leaderboard is required.';
|
||
return $empty;
|
||
}
|
||
|
||
$params = ['id' => $id];
|
||
if ($request->query('period')) {
|
||
$params['period'] = $request->query('period');
|
||
}
|
||
|
||
$response = LambdaRequest::signedrequest('get', $this->_service, $this->_module . '/dashboard', $params, 120);
|
||
if (!is_object($response) || ($response->statusCode ?? 0) != 200 || !isset($response->data)) {
|
||
$empty['error'] = is_object($response) ? ($response->message ?? 'Unable to load leaderboard.') : 'Unable to load leaderboard.';
|
||
$empty['pills'] = $this->roleLeaderboardPills($id, $roleId, [], $request->query('period'));
|
||
return $empty;
|
||
}
|
||
|
||
$view = $response->data->view ?? (object) [];
|
||
$groups = $response->data->leaderboard ?? [];
|
||
if (is_object($groups)) {
|
||
$groups = array_values((array) $groups);
|
||
}
|
||
|
||
$selected = null;
|
||
foreach ($groups as $group) {
|
||
$group = is_object($group) ? $group : (object) $group;
|
||
$roleConfig = is_object($group->role ?? null) ? $group->role : (object) ($group->role ?? []);
|
||
$currentRoleId = (string) ($roleConfig->role ?? ($roleConfig->id ?? ''));
|
||
if ($roleId === '' || $currentRoleId === $roleId) {
|
||
$selected = $group;
|
||
$roleId = $currentRoleId;
|
||
break;
|
||
}
|
||
}
|
||
|
||
$pills = $this->roleLeaderboardPills($id, $roleId, $groups, $request->query('period'));
|
||
|
||
if (!$selected) {
|
||
return [
|
||
'error' => 'No data found for this role.',
|
||
'title' => $view->name ?? 'Leaderboard',
|
||
'subtitle' => '',
|
||
'period_label' => '',
|
||
'users' => [],
|
||
'metrics' => [],
|
||
'pills' => $pills,
|
||
'selected_role' => $roleId,
|
||
];
|
||
}
|
||
|
||
$roleConfig = is_object($selected->role ?? null) ? $selected->role : (object) [];
|
||
$limit = (int) ($roleConfig->limit ?? 0);
|
||
$roleTitle = trim((string) ($roleConfig->title ?? ''));
|
||
if ($roleTitle === '') {
|
||
$roleTitle = 'Role';
|
||
}
|
||
$subtitle = preg_match('/^\s*top\s+\d+/i', $roleTitle)
|
||
? $roleTitle
|
||
: ('Top ' . ($limit > 0 ? $limit : count((array) ($selected->users ?? []))) . ' ' . $roleTitle);
|
||
|
||
$rows = $selected->users ?? [];
|
||
if (is_object($rows)) {
|
||
$rows = array_values((array) $rows);
|
||
}
|
||
if ($limit > 0) {
|
||
$rows = array_slice($rows, 0, $limit);
|
||
}
|
||
|
||
$metrics = [];
|
||
$users = [];
|
||
foreach ($rows as $index => $row) {
|
||
$row = is_object($row) ? $row : (object) $row;
|
||
$info = is_object($row->user ?? null) ? $row->user : (object) [];
|
||
$metricValues = [];
|
||
$rowMetrics = $row->metrics ?? [];
|
||
if (is_object($rowMetrics)) {
|
||
$rowMetrics = array_values((array) $rowMetrics);
|
||
}
|
||
if (is_array($rowMetrics)) {
|
||
foreach ($rowMetrics as $metric) {
|
||
$metric = is_object($metric) ? $metric : (object) $metric;
|
||
$metricId = $metric->metric ?? ($metric->title ?? ('m' . count($metrics)));
|
||
$metricName = $metric->name ?? ($metric->display ?? ($metric->title ?? $metricId));
|
||
if ($index === 0) {
|
||
$metrics[] = ['id' => $metricId, 'name' => $metricName];
|
||
}
|
||
$metricValues[$metricId] = $metric->value ?? 0;
|
||
}
|
||
}
|
||
$users[] = [
|
||
'rank' => $row->rank ?? ($index + 1),
|
||
'name' => $info->name ?? '',
|
||
'avatar' => $info->avatar ?? '',
|
||
'employee_code' => $info->employee_code ?? '',
|
||
'designation' => $info->designation ?? '',
|
||
'position_name' => $info->position_name ?? '',
|
||
'score' => $row->score ?? 0,
|
||
'metric_values' => $metricValues,
|
||
];
|
||
}
|
||
|
||
$periodLabel = trim(($view->firstDay ?? '') . (($view->firstDay ?? '') && ($view->lastDay ?? '') ? ' – ' : '') . ($view->lastDay ?? ''));
|
||
|
||
return [
|
||
'error' => '',
|
||
'title' => $view->name ?? 'Leaderboard',
|
||
'subtitle' => $subtitle,
|
||
'period_label' => $periodLabel,
|
||
'users' => $users,
|
||
'metrics' => $metrics,
|
||
'pills' => $pills,
|
||
'selected_role' => $roleId,
|
||
];
|
||
}
|
||
|
||
protected function roleLeaderboardPills($leaderboardId, $selectedRoleId, array $groups, $period = null): array
|
||
{
|
||
$rankRoles = [];
|
||
$one = LambdaRequest::signedrequest('get', $this->_service, $this->_module . '/get_one', ['id' => $leaderboardId]);
|
||
if (is_object($one) && ($one->statusCode ?? 0) == 200) {
|
||
$item = $one->data->item ?? null;
|
||
$configured = $item->rank_roles ?? [];
|
||
if (is_object($configured)) {
|
||
$configured = array_values((array) $configured);
|
||
}
|
||
if (is_array($configured)) {
|
||
usort($configured, function ($a, $b) {
|
||
$a = is_object($a) ? $a : (object) $a;
|
||
$b = is_object($b) ? $b : (object) $b;
|
||
return ((int) ($a->sort_order ?? 0)) <=> ((int) ($b->sort_order ?? 0));
|
||
});
|
||
$rankRoles = $configured;
|
||
}
|
||
}
|
||
|
||
if (!count($rankRoles)) {
|
||
foreach ($groups as $group) {
|
||
$group = is_object($group) ? $group : (object) $group;
|
||
$rankRoles[] = is_object($group->role ?? null) ? $group->role : (object) [];
|
||
}
|
||
}
|
||
|
||
$pills = [];
|
||
foreach ($rankRoles as $index => $rankRole) {
|
||
$rankRole = is_object($rankRole) ? $rankRole : (object) $rankRole;
|
||
$roleId = (string) ($rankRole->role ?? ($rankRole->id ?? ''));
|
||
$limit = (int) ($rankRole->limit ?? 10);
|
||
if ($limit < 1) {
|
||
$limit = 10;
|
||
}
|
||
$title = trim((string) ($rankRole->title ?? ''));
|
||
if ($title === '') {
|
||
$title = 'Role';
|
||
}
|
||
$label = preg_match('/^\s*top\s+\d+/i', $title) ? $title : ('Top ' . $limit . ' ' . $title);
|
||
$query = ['id' => $leaderboardId, 'role' => $roleId];
|
||
if ($period) {
|
||
$query['period'] = $period;
|
||
}
|
||
$pills[] = [
|
||
'label' => $label,
|
||
'url' => url('/leaderboard/dashboard') . '?' . http_build_query($query),
|
||
'active' => $selectedRoleId !== '' ? $roleId === (string) $selectedRoleId : $index === 0,
|
||
];
|
||
}
|
||
|
||
return $pills;
|
||
}
|
||
}
|