middleware('auth'); $this->_service = 'metric'; $this->_module = 'campaign_view'; $this->_viewname = 'metriccampaign'; $this->_title = 'Campaign management'; $this->_base_url = '/metriccampaign'; } protected function get_list_fields() { return [ 'actions' => ['title' => 'Actions', 'buttons' => ['edit', 'delete']], 'name' => ['title' => 'Name', 'type' => 'text'], 'roles' => ['title' => 'Roles', 'type' => 'text'], 'sort_order' => ['title' => 'Sort Order', 'type' => 'number'], 'teams_rank' => ['title' => 'Teams Rank', 'type' => 'text'], 'status' => ['title' => 'Status', 'type' => 'select'], ]; } public function list(Request $request) { $response = LambdaRequest::signedrequest('get', $this->_service, $this->_module.'/get_all'); if (isset($response->statusCode) && (int) $response->statusCode === 401) { return redirect('/unauthorised'); } $roleMap = $this->getRoleNameMap(); $items = $response->data->items ?? []; foreach ($items as &$item) { $item->roles = $this->formatAssignedRoles($item->campaign_visible_roles ?? ($item->roles ?? ''), $roleMap); } unset($item); return $this->view('list')->with([ 'title' => $this->_title, 'fields' => $this->get_list_fields(), 'base_url' => $this->_base_url, 'items' => $items, 'buttons' => $this->get_list_buttons(), ]); } protected function get_form_fields($type, $values) { $roles = $this->getlambda('get', 'ums', 'roles', 'dropdown'); $roles_dd = []; foreach ($roles->data->items as $role) { $roles_dd[$role->id] = $role->name; } $metrics = $this->getlambda('get', 'metric', 'metric', 'get_all'); $metrics_dd = []; foreach ($metrics->data->items as $metric) { $metrics_dd[$metric->id] = $metric->name; } $intervalValues = [ 'yearlycy' => 'Calender Year', 'yearlyfy' => 'Financial Year', 'monthly' => 'Monthly', 'weekly' => 'Weekly', 'daily' => 'Daily', ]; $teamsRankValues = [ 'l1' => 'L1 ', 'l2' => 'L2 ', 'l3' => 'L3 ', 'l4' => 'L4 ', ]; $userAttrs = $this->getlambda('get', 'ums', 'userattribute', 'get_all'); $attrs_dd = []; $userattr_dd = []; $attrs_meta = []; foreach (($userAttrs->data->items ?? []) as $attr) { if (($attr->status ?? 'active') === 'disabled') { continue; } $code = $attr->code ?? ''; if ($code === '') { continue; } $options = []; foreach (($attr->options ?? []) as $opt) { $opt = (array) $opt; $optValue = (string) ($opt['value'] ?? ''); if ($optValue === '') { continue; } $options[$optValue] = (string) ($opt['display'] ?? $optValue); } $attrs_dd[$code] = ($attr->attribute ?? $code) . ' (' . $code . ')'; $userattr_dd[$code] = $attr->attribute ?? $code; $attrs_meta[$code] = [ 'code' => $code, 'attribute' => $attr->attribute ?? $code, 'type' => $attr->type ?? 'text', 'options' => $options, ]; } return [ 'name' => ['title' => 'Name', 'type' => 'text', 'required' => true, 'fullwidth' => true], 'sort_order' => [ 'title' => 'Sort Order', 'type' => 'number', 'required' => false, 'placeholder' => 'Lower number shows first', ], 'validity_start' => ['title' => 'Validity Start', 'type' => 'date', 'required' => true], 'validity_end' => ['title' => 'Validity End', 'type' => 'date', 'required' => true], 'campaign_visible_roles' => ['title' => 'Campaign Visible Roles', 'type' => 'multiselect', 'values' => $roles_dd, 'required' => true], 'reporting_roles' => ['title' => 'Reporting Roles', 'type' => 'multiselect', 'values' => $roles_dd, 'required' => true], 'teams_rank' => ['title' => 'Teams Rank', 'type' => 'select', 'required' => true, 'values' => $teamsRankValues], 'intervals' => ['title' => 'Intervals', 'type' => 'multiselect', 'required' => true, 'values' => $intervalValues], 'ranking_attributes' => [ 'title' => 'User Attribute Filters', 'type' => 'ranking_attributes', 'required' => false, 'fullwidth' => true, 'attributes' => $attrs_dd, 'attributes_meta' => $attrs_meta, ], 'bg_image' => ['title' => 'Background image', 'type' => 'image', 'required' => false], 'icon' => ['title' => 'Icon', 'type' => 'image', 'required' => false], 'showOverallRank' => [ 'title' => 'Show Overall Rank', 'type' => 'select', 'required' => false, 'values' => ['yes' => 'Yes', 'no' => 'No'], ], 'overallRank_title' => [ 'title' => 'Overall Rank Title', 'type' => 'text', 'required' => false, 'placeholder' => 'My Overall Rank', ], 'showManagerOverallRank' => [ 'title' => 'Show Manager Overall Rank', 'type' => 'select', 'required' => false, 'values' => ['yes' => 'Yes', 'no' => 'No'], ], 'managerOverallRank_title' => [ 'title' => 'Manager Overall Rank Title', 'type' => 'text', 'required' => false, 'placeholder' => 'View Individual Rank', ], 'overallRank_color1' => [ 'title' => 'My Rank - Gradient color (dark)', 'type' => 'text', 'required' => false, 'placeholder' => 'R-G-B-A e.g. 255-66-33-1', ], 'overallRank_color2' => [ 'title' => 'My Rank - Gradient color (light)', 'type' => 'text', 'required' => false, 'placeholder' => 'R-G-B-A e.g. 255-66-33-1', ], 'showRankInTeam' => [ 'title' => 'Show Rank in Team', 'type' => 'select', 'required' => false, 'values' => ['yes' => 'Yes', 'no' => 'No'], ], 'rankInTeam_title' => [ 'title' => 'Rank in Team Title', 'type' => 'text', 'required' => false, 'placeholder' => 'Rank in Team', ], 'rankInTeam_color1' => [ 'title' => 'Rank in Team - Gradient color (dark)', 'type' => 'text', 'required' => false, 'placeholder' => 'R-G-B-A e.g. 255-165-0-1', ], 'rankInTeam_color2' => [ 'title' => 'Rank in Team - Gradient color (light)', 'type' => 'text', 'required' => false, 'placeholder' => 'R-G-B-A e.g. 255-165-0-1', ], 'showTeamRank' => [ 'title' => 'Show Team Rank', 'type' => 'select', 'required' => false, 'values' => ['yes' => 'Yes', 'no' => 'No'], ], 'teamRank_title' => [ 'title' => 'Team Rank Title', 'type' => 'text', 'required' => false, 'placeholder' => 'Team Rank', ], 'showManagerTeamRank' => [ 'title' => 'Show Manager Team Rank', 'type' => 'select', 'required' => false, 'values' => ['yes' => 'Yes', 'no' => 'No'], ], 'managerTeamRank_title' => [ 'title' => 'Manager Team Rank Title', 'type' => 'text', 'required' => false, 'placeholder' => 'View Team Rank', ], 'teamRank_color1' => [ 'title' => 'Team Rank - Gradient color (dark)', 'type' => 'text', 'required' => false, 'placeholder' => 'R-G-B-A e.g. 18-196-110-1', ], 'teamRank_color2' => [ 'title' => 'Team Rank - Gradient color (light)', 'type' => 'text', 'required' => false, 'placeholder' => 'R-G-B-A e.g. 18-196-110-1', ], 'status' => ['title' => 'Status', 'type' => 'select', 'required' => true, 'values' => ['active' => 'Active', 'disabled' => 'Disabled']], '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']], 'show_units_export' => ['title' => 'Show Units Export', 'type' => 'select', 'required' => true, 'values' => ['yes' => 'Yes', 'no' => 'No'], 'default' => 'yes'], 'show_user_attributes' => ['title' => 'Show User Attributes', 'type' => 'select', 'required' => true, 'values' => ['yes' => 'Yes', 'no' => 'No'], 'default' => 'no'], 'user_attributes' => ['title' => 'Include User Attributes', 'type' => 'multiselect', 'values' => $userattr_dd, 'default' => []], 'show_normal_metrics' => ['title' => 'Show Normal Metrics', 'type' => 'select', 'required' => true, 'values' => ['yes' => 'Yes', 'no' => 'No'], 'default' => 'yes'], 'show_combined_metrics' => ['title' => 'Show Combined Metrics', 'type' => 'select', 'required' => true, 'values' => ['yes' => 'Yes', 'no' => 'No'], 'default' => 'yes'], 'manager_details' => ['title' => 'Manager Details', 'type' => 'multiselect', 'values' => ['l1manager' => 'L1 Manager', 'l2manager' => 'L2 Manager', 'l3manager' => 'L3 Manager', 'l4manager' => 'L4 Manager'], 'default' => ['l1manager']], 'total_units_name' => ['title' => 'Total Units Name', 'type' => 'text', 'required' => false, 'default' => ''], 'highlight_top' => [ 'title' => 'Highlight Top', 'type' => 'text', 'required' => false, 'placeholder' => 'e.g. 10, 20, 30', ], 'highlight_color' => [ 'title' => 'Highlight Color', 'type' => 'text', 'required' => false, 'placeholder' => 'R-G-B-A or CSS color', ], 'metrics' => ['title' => 'Metrics', 'type' => 'mapping', 'required' => false, 'metrics' => $metrics_dd, 'fullwidth' => true], 'combined_metrics' => ['title' => 'Combined Metrics (if any)', 'type' => 'combined_metrics', 'fullwidth' => true], ]; } protected function _beforeform($type, $values) { if ($type === 'edit' && is_object($values)) { foreach (['campaign_visible_roles', 'reporting_roles', 'intervals'] as $k) { if (!isset($values->{$k})) { $values->{$k} = []; continue; } if (is_string($values->{$k})) { $values->{$k} = $values->{$k} === '' ? [] : explode('#', $values->{$k}); } elseif (!is_array($values->{$k})) { $values->{$k} = (array) $values->{$k}; } } if (!isset($values->metrics) || $values->metrics === null) { $values->metrics = []; } elseif (!is_array($values->metrics)) { $values->metrics = (array) $values->metrics; } $values->metrics = array_values(array_map(function ($metric) { return $this->normalizeMetricMapping($metric); }, $values->metrics)); if (!isset($values->combined_metrics) || $values->combined_metrics === '') { $values->combined_metrics = '[]'; } if (!empty($values->teams_rank) && is_string($values->teams_rank)) { $values->teams_rank = strtolower(substr($values->teams_rank, 0, 2)); } $values->ranking_attributes = $this->normalizeRankingAttributes($values->ranking_attributes ?? null); $yesNoDefaults = [ 'showOverallRank' => 'yes', 'showRankInTeam' => 'yes', 'showTeamRank' => 'yes', 'showManagerOverallRank' => 'yes', 'showManagerTeamRank' => 'yes', 'show_units_export' => 'yes', 'show_normal_metrics' => 'yes', 'show_combined_metrics' => 'yes', ]; foreach ($yesNoDefaults as $field => $default) { if (!isset($values->{$field}) || $values->{$field} === '' || $values->{$field} === null) { $values->{$field} = $default; } } $values->show_user_attributes = (($values->show_user_attributes ?? 'no') === 'yes') ? 'yes' : 'no'; $values->user_attributes = $this->normalizeAttributeCodes($values->user_attributes ?? []); if (!isset($values->highlight_top) || $values->highlight_top === null) { $values->highlight_top = ''; } if (!isset($values->highlight_color) || $values->highlight_color === null) { $values->highlight_color = ''; } if (!isset($values->manager_details) || !is_array($values->manager_details) || $values->manager_details === []) { $values->manager_details = ['l1manager']; } if (!isset($values->total_units_name) || $values->total_units_name === null) { $values->total_units_name = ''; } if (!isset($values->sort_order) || $values->sort_order === null || $values->sort_order === '') { $values->sort_order = 0; } } elseif (is_object($values)) { $values->ranking_attributes = []; $values->sort_order = 0; $values->showOverallRank = 'yes'; $values->showRankInTeam = 'yes'; $values->showTeamRank = 'yes'; $values->showManagerOverallRank = 'yes'; $values->showManagerTeamRank = 'yes'; $values->highlight_top = ''; $values->highlight_color = ''; $values->show_units_export = 'yes'; $values->show_user_attributes = 'no'; $values->user_attributes = []; $values->show_normal_metrics = 'yes'; $values->show_combined_metrics = 'yes'; $values->manager_details = ['l1manager']; $values->total_units_name = ''; } return $values; } protected function normalizeRankingAttributes($raw): array { if (is_string($raw) && $raw !== '') { $decoded = json_decode($raw, true); $raw = is_array($decoded) ? $decoded : []; } if (is_object($raw)) { $raw = json_decode(json_encode($raw), true); } if (!is_array($raw)) { return []; } $normalized = []; foreach ($raw as $row) { if (is_object($row)) { $row = (array) $row; } if (!is_array($row)) { continue; } $code = trim((string) ($row['code'] ?? '')); $value = trim((string) ($row['value'] ?? '')); if ($code === '' || $value === '') { continue; } $normalized[] = [ 'code' => $code, 'value' => $value, ]; } return $normalized; } protected function normalizeMetricRules($rules) { if (is_string($rules)) { $decoded = json_decode($rules, true); $rules = is_array($decoded) ? $decoded : []; } elseif (is_object($rules)) { $rules = json_decode(json_encode($rules), true); } if (!is_array($rules)) { return []; } $normalized = []; foreach ($rules as $rule) { if (is_object($rule)) { $rule = json_decode(json_encode($rule), true); } if (!is_array($rule) || empty($rule['rule_type'])) { continue; } $ranges = $rule['ranges'] ?? []; if (is_string($ranges)) { $decodedRanges = json_decode($ranges, true); $ranges = is_array($decodedRanges) ? $decodedRanges : []; } elseif (is_object($ranges)) { $ranges = json_decode(json_encode($ranges), true); } $normalizedRanges = []; if (is_array($ranges)) { foreach ($ranges as $range) { if (is_object($range)) { $range = json_decode(json_encode($range), true); } if (!is_array($range)) { continue; } $normalizedRanges[] = [ 'start' => isset($range['start']) ? (float) $range['start'] : 0, 'end' => isset($range['end']) ? (float) $range['end'] : 0, 'weight' => isset($range['weight']) ? (float) $range['weight'] : 0, ]; } } $normalized[] = [ 'rule_type' => $rule['rule_type'], 'ranges' => $normalizedRanges, ]; } return $normalized; } protected function normalizeRulesInterval($value) { $allowed = ['overall', 'monthly', 'weekly', 'daily', 'custom']; if (is_string($value)) { return [ 'interval' => in_array($value, $allowed, true) ? $value : 'overall', 'custom_start' => '', 'custom_end' => '', ]; } if (is_object($value)) { $value = json_decode(json_encode($value), true); } if (!is_array($value)) { return ['interval' => 'overall', 'custom_start' => '', 'custom_end' => '']; } $interval = in_array(($value['interval'] ?? 'overall'), $allowed, true) ? ($value['interval'] ?? 'overall') : 'overall'; return [ 'interval' => $interval, 'custom_start' => $value['custom_start'] ?? '', 'custom_end' => $value['custom_end'] ?? '', ]; } protected function resolveRulesIntervalFromMetric($metric, $rawRules) { if (!empty($metric['rules_interval'])) { return $this->normalizeRulesInterval([ 'interval' => $metric['rules_interval'], 'custom_start' => $metric['rules_custom_start'] ?? '', 'custom_end' => $metric['rules_custom_end'] ?? '', ]); } $first = null; if (is_array($rawRules) && !empty($rawRules)) { $first = $rawRules[0]; if (is_object($first)) { $first = json_decode(json_encode($first), true); } } if (is_array($first) && !empty($first['interval'])) { return $this->normalizeRulesInterval([ 'interval' => $first['interval'], 'custom_start' => $first['custom_start'] ?? '', 'custom_end' => $first['custom_end'] ?? '', ]); } return $this->normalizeRulesInterval('overall'); } protected function normalizeMetricMapping($metric) { if (is_object($metric)) { $metric = json_decode(json_encode($metric), true); } if (!is_array($metric)) { $metric = []; } $rawRules = $metric['rules'] ?? []; $rulesInterval = $this->resolveRulesIntervalFromMetric($metric, $rawRules); $rules = $this->normalizeMetricRules($rawRules); return (object) [ 'metric' => $metric['metric'] ?? '', 'display' => $metric['display'] ?? '', 'unit_type' => in_array(($metric['unit_type'] ?? 'sum'), ['sum', 'average'], true) ? ($metric['unit_type'] ?? 'sum') : 'sum', 'sort' => isset($metric['sort']) ? (int) $metric['sort'] : 0, 'weight' => isset($metric['weight']) && $metric['weight'] !== '' ? (float) $metric['weight'] : 1, 'label_text' => $metric['label_text'] ?? 'units', 'rules_interval' => $rulesInterval['interval'], 'rules_custom_start' => $rulesInterval['custom_start'], 'rules_custom_end' => $rulesInterval['custom_end'], 'rules' => $rules, ]; } protected function normalizeCombinedMetricMapping($metric) { if (is_object($metric)) { $metric = json_decode(json_encode($metric), true); } if (!is_array($metric)) { $metric = []; } $rawRules = $metric['rules'] ?? []; $rulesInterval = $this->resolveRulesIntervalFromMetric($metric, $rawRules); $rules = $this->normalizeMetricRules($rawRules); return [ 'type' => $metric['type'] ?? '', 'title' => $metric['title'] ?? '', 'fields' => $metric['fields'] ?? [], 'unit_type' => in_array(($metric['unit_type'] ?? 'sum'), ['sum', 'average'], true) ? ($metric['unit_type'] ?? 'sum') : 'sum', 'weight' => isset($metric['weight']) && $metric['weight'] !== '' ? (float) $metric['weight'] : 1, 'label_text' => $metric['label_text'] ?? 'units', 'rules_interval' => $rulesInterval['interval'], 'rules_custom_start' => $rulesInterval['custom_start'], 'rules_custom_end' => $rulesInterval['custom_end'], 'rules' => $rules, ]; } protected function _beforesave($type, $request) { $data = $request->except('_token'); $metricIds = $request->input('metric', []); $displayUnits = $request->input('display_unit', []); // Metric-row sort (name=metric_sort[]) — keep separate from campaign-level sort_order $sortOrders = $request->input('metric_sort', $request->input('sort_order', [])); $unitTypes = $request->input('unit_type', []); $weights = $request->input('weight', []); $labelTexts = $request->input('label_text', []); $metricRules = $request->input('metric_rules', []); $metricRulesIntervals = $request->input('metric_rules_interval', []); $metricRulesCustomStart = $request->input('metric_rules_custom_start', []); $metricRulesCustomEnd = $request->input('metric_rules_custom_end', []); $metrics = []; if (is_array($metricIds)) { foreach ($metricIds as $i => $metricId) { if ($metricId === null || $metricId === '') { continue; } $rules = []; if (isset($metricRules[$i]) && $metricRules[$i] !== '') { $rules = $this->normalizeMetricRules($metricRules[$i]); } $rulesInterval = $this->normalizeRulesInterval([ 'interval' => $metricRulesIntervals[$i] ?? 'overall', 'custom_start' => $metricRulesCustomStart[$i] ?? '', 'custom_end' => $metricRulesCustomEnd[$i] ?? '', ]); $metrics[] = [ 'metric' => $metricId, 'display' => $displayUnits[$i] ?? '', 'unit_type' => in_array($unitTypes[$i] ?? 'sum', ['sum', 'average'], true) ? ($unitTypes[$i] ?? 'sum') : 'sum', 'sort' => isset($sortOrders[$i]) && $sortOrders[$i] !== '' ? (int) $sortOrders[$i] : 0, 'weight' => isset($weights[$i]) && $weights[$i] !== '' ? (float) $weights[$i] : 1, 'label_text' => isset($labelTexts[$i]) && $labelTexts[$i] !== '' ? $labelTexts[$i] : 'units', 'rules_interval' => $rulesInterval['interval'], 'rules_custom_start' => $rulesInterval['custom_start'], 'rules_custom_end' => $rulesInterval['custom_end'], 'rules' => $rules, ]; } } $data['metrics'] = $metrics; $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 === null || $v === '') { continue; } $rules = []; if (isset($data['combined_metrics']['rules'][$i]) && $data['combined_metrics']['rules'][$i] !== '') { $rules = $this->normalizeMetricRules($data['combined_metrics']['rules'][$i]); } $combined_metrics[] = $this->normalizeCombinedMetricMapping([ 'type' => $v, 'title' => $data['combined_metrics']['title'][$i] ?? '', 'fields' => $data['combined_metrics']['fields'][$i] ?? [], 'unit_type' => $data['combined_metrics']['unit_type'][$i] ?? 'sum', 'weight' => $data['combined_metrics']['weight'][$i] ?? 1, 'label_text' => $data['combined_metrics']['label_text'][$i] ?? 'units', 'rules_interval' => $data['combined_metrics']['rules_interval'][$i] ?? 'overall', 'rules_custom_start' => $data['combined_metrics']['rules_custom_start'][$i] ?? '', 'rules_custom_end' => $data['combined_metrics']['rules_custom_end'][$i] ?? '', 'rules' => $rules, ]); } } $data['combined_metrics'] = json_encode($combined_metrics); if ($request->file('bg_image')) { $data['bg_image'] = $this->_uploadMedia($request, 'bg_image', 'metric'); } if ($request->file('icon')) { $data['icon'] = $this->_uploadMedia($request, 'icon', 'metric'); } $rankingCodes = $request->input('ranking_attribute_code', []); $rankingValues = $request->input('ranking_attribute_value', []); $rankingAttributes = []; if (is_array($rankingCodes)) { foreach ($rankingCodes as $i => $code) { $code = trim((string) $code); $value = isset($rankingValues[$i]) ? trim((string) $rankingValues[$i]) : ''; if ($code === '' || $value === '') { continue; } $rankingAttributes[] = [ 'code' => $code, 'value' => $value, ]; } } $data['ranking_attributes'] = $rankingAttributes; $data['sort_order'] = isset($data['sort_order']) && $data['sort_order'] !== '' && !is_array($data['sort_order']) ? (int) $data['sort_order'] : 0; if (!isset($data['manager_details']) || !is_array($data['manager_details']) || $data['manager_details'] === []) { $data['manager_details'] = ['l1manager']; } foreach (['show_units_export', 'show_normal_metrics', 'show_combined_metrics'] as $flag) { if (!isset($data[$flag]) || $data[$flag] === '') { $data[$flag] = 'yes'; } } $data['total_units_name'] = trim((string) ($data['total_units_name'] ?? '')); $data['show_user_attributes'] = ($data['show_user_attributes'] ?? 'no') === 'yes' ? 'yes' : 'no'; $data['user_attributes'] = $this->normalizeAttributeCodes($data['user_attributes'] ?? []); unset( $data['metric'], $data['display_unit'], $data['metric_sort'], $data['unit_type'], $data['weight'], $data['label_text'], $data['metric_rules'], $data['metric_rules_interval'], $data['metric_rules_custom_start'], $data['metric_rules_custom_end'], $data['list_view'], $data['ranking_attribute_code'], $data['ranking_attribute_value'] ); return $data; } protected function normalizeAttributeCodes($raw): array { if (is_string($raw) && $raw !== '') { $decoded = json_decode($raw, true); $raw = is_array($decoded) ? $decoded : explode('#', $raw); } if (!is_array($raw)) { return []; } $codes = []; foreach ($raw as $code) { if (is_object($code)) { $code = $code->code ?? ''; } $code = trim((string) $code); if ($code !== '') { $codes[] = $code; } } return array_values(array_unique($codes)); } }