319 lines
9.8 KiB
PHP
319 lines
9.8 KiB
PHP
<?php
|
|
|
|
namespace Modules\ManagementTools\Utils;
|
|
|
|
use App\Utils\Util;
|
|
use Illuminate\Support\Collection;
|
|
use Illuminate\Support\Facades\DB;
|
|
use Modules\ManagementTools\Entities\MtSkill;
|
|
use Modules\ManagementTools\Entities\MtTool;
|
|
|
|
class ManagementToolsUtil
|
|
{
|
|
protected $commonUtil;
|
|
|
|
public function __construct(Util $commonUtil)
|
|
{
|
|
$this->commonUtil = $commonUtil;
|
|
}
|
|
|
|
/**
|
|
* Convert user-entered date (Jalali or Gregorian) to MySQL Y-m-d.
|
|
*/
|
|
public function parseInputDate(?string $date): ?string
|
|
{
|
|
if (empty($date)) {
|
|
return null;
|
|
}
|
|
|
|
if (function_exists('jalali_to_gregorian')) {
|
|
$converted = jalali_to_gregorian($date, session('business.date_format', 'Y/m/d'), false);
|
|
if (! empty($converted) && preg_match('/^\d{4}-\d{2}-\d{2}/', $converted)) {
|
|
return $converted;
|
|
}
|
|
}
|
|
|
|
return $this->commonUtil->uf_date($date);
|
|
}
|
|
|
|
/**
|
|
* Convert user-entered datetime to MySQL Y-m-d H:i:s.
|
|
*/
|
|
public function parseInputDateTime(?string $date): ?string
|
|
{
|
|
if (empty($date)) {
|
|
return null;
|
|
}
|
|
|
|
if (function_exists('jalali_to_gregorian')) {
|
|
$converted = jalali_to_gregorian($date, session('business.date_format', 'Y/m/d'), true);
|
|
if (! empty($converted) && preg_match('/^\d{4}-\d{2}-\d{2}/', $converted)) {
|
|
return $converted;
|
|
}
|
|
}
|
|
|
|
return $this->commonUtil->uf_date($date, true);
|
|
}
|
|
|
|
/**
|
|
* Format a stored date for display/inputs — always Jalali in this module.
|
|
*/
|
|
public function formatForInput($date): ?string
|
|
{
|
|
if (empty($date)) {
|
|
return null;
|
|
}
|
|
|
|
try {
|
|
$carbon = $date instanceof \Carbon\Carbon ? $date->copy() : \Carbon\Carbon::parse($date);
|
|
$format = session('business.date_format', 'Y/m/d');
|
|
$formatted = format_jalali_date($carbon, $format);
|
|
|
|
return function_exists('persian_number') ? persian_number($formatted) : $formatted;
|
|
} catch (\Exception $e) {
|
|
return format_date($date);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Format a stored datetime for display/inputs — always Jalali in this module.
|
|
*/
|
|
public function formatDateTimeForInput($date): ?string
|
|
{
|
|
if (empty($date)) {
|
|
return null;
|
|
}
|
|
|
|
try {
|
|
$carbon = $date instanceof \Carbon\Carbon ? $date->copy() : \Carbon\Carbon::parse($date);
|
|
$format = session('business.date_format', 'Y/m/d');
|
|
$time_format = session('business.time_format', 24) == 12 ? ' h:i A' : ' H:i';
|
|
$formatted = format_jalali_date($carbon, $format.$time_format);
|
|
|
|
return function_exists('persian_number') ? persian_number($formatted) : $formatted;
|
|
} catch (\Exception $e) {
|
|
return format_datetime($date);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Shorthand for views — format date in Jalali.
|
|
*/
|
|
public function formatDate($date): ?string
|
|
{
|
|
return $this->formatForInput($date);
|
|
}
|
|
|
|
/**
|
|
* Shorthand for views — format datetime in Jalali.
|
|
*/
|
|
public function formatDateTime($date): ?string
|
|
{
|
|
return $this->formatDateTimeForInput($date);
|
|
}
|
|
/**
|
|
* Build hierarchical tree from flat collection.
|
|
*/
|
|
public function buildTree(Collection $items, $parent_id = null, $depth = 0): array
|
|
{
|
|
$branch = [];
|
|
|
|
foreach ($items->where('parent_id', $parent_id) as $item) {
|
|
$node = $item->toArray();
|
|
$node['depth'] = $depth;
|
|
$node['children'] = $this->buildTree($items, $item->id, $depth + 1);
|
|
$branch[] = $node;
|
|
}
|
|
|
|
return $branch;
|
|
}
|
|
|
|
/**
|
|
* Flatten tree for table display with indentation.
|
|
*/
|
|
public function flattenTree(array $tree, &$flat = []): array
|
|
{
|
|
foreach ($tree as $node) {
|
|
$children = $node['children'] ?? [];
|
|
unset($node['children']);
|
|
$flat[] = $node;
|
|
if (! empty($children)) {
|
|
$this->flattenTree($children, $flat);
|
|
}
|
|
}
|
|
|
|
return $flat;
|
|
}
|
|
|
|
public function getSkillsDropdown($business_id, $exclude_id = null): array
|
|
{
|
|
$query = MtSkill::forBusiness($business_id)->orderBy('title');
|
|
if ($exclude_id) {
|
|
$query->where('id', '!=', $exclude_id);
|
|
}
|
|
|
|
return $query->pluck('title', 'id')->toArray();
|
|
}
|
|
|
|
public function getToolsDropdown($business_id, $exclude_id = null): array
|
|
{
|
|
$query = MtTool::forBusiness($business_id)->orderBy('title');
|
|
if ($exclude_id) {
|
|
$query->where('id', '!=', $exclude_id);
|
|
}
|
|
|
|
return $query->pluck('title', 'id')->toArray();
|
|
}
|
|
|
|
public function parseToolAttributes(array $names, array $values): array
|
|
{
|
|
$attributes = [];
|
|
foreach ($names as $key => $name) {
|
|
$name = trim((string) $name);
|
|
if ($name === '') {
|
|
continue;
|
|
}
|
|
$attributes[$name] = $values[$key] ?? '';
|
|
}
|
|
|
|
return $attributes;
|
|
}
|
|
|
|
/**
|
|
* Assigned skills for a user: [skill_id => skill_level].
|
|
*/
|
|
public function getUserAssignedSkills(int $business_id, int $user_id): array
|
|
{
|
|
return DB::table('mt_user_skill')
|
|
->where('business_id', $business_id)
|
|
->where('user_id', $user_id)
|
|
->pluck('skill_level', 'skill_id')
|
|
->toArray();
|
|
}
|
|
|
|
/**
|
|
* Skills with title and level for profile display.
|
|
*/
|
|
public function getUserSkillsList(int $business_id, int $user_id): Collection
|
|
{
|
|
return DB::table('mt_user_skill as us')
|
|
->join('mt_skills as s', 's.id', '=', 'us.skill_id')
|
|
->where('us.business_id', $business_id)
|
|
->where('us.user_id', $user_id)
|
|
->select('s.id', 's.title', 'us.skill_level')
|
|
->orderBy('s.title')
|
|
->get();
|
|
}
|
|
|
|
/**
|
|
* Sync employee skills (replace all).
|
|
*/
|
|
public function syncUserSkills(int $business_id, int $user_id, ?array $skill_ids, ?array $skill_levels = []): void
|
|
{
|
|
DB::table('mt_user_skill')
|
|
->where('business_id', $business_id)
|
|
->where('user_id', $user_id)
|
|
->delete();
|
|
|
|
foreach ($skill_ids ?? [] as $skill_id) {
|
|
DB::table('mt_user_skill')->insert([
|
|
'business_id' => $business_id,
|
|
'skill_id' => (int) $skill_id,
|
|
'user_id' => $user_id,
|
|
'skill_level' => (int) ($skill_levels[$skill_id] ?? 1),
|
|
'created_at' => now(),
|
|
'updated_at' => now(),
|
|
]);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Sync employee tools (replace all).
|
|
*/
|
|
public function syncUserTools(int $business_id, int $user_id, ?array $tool_ids): void
|
|
{
|
|
DB::table('mt_user_tool')
|
|
->where('business_id', $business_id)
|
|
->where('user_id', $user_id)
|
|
->delete();
|
|
|
|
foreach ($tool_ids ?? [] as $tool_id) {
|
|
DB::table('mt_user_tool')->insert([
|
|
'business_id' => $business_id,
|
|
'tool_id' => (int) $tool_id,
|
|
'user_id' => $user_id,
|
|
'created_at' => now(),
|
|
'updated_at' => now(),
|
|
]);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Report: employee count per skill.
|
|
*/
|
|
public function getSkillsEmployeeReport(int $business_id): array
|
|
{
|
|
$skills = MtSkill::forBusiness($business_id)->orderBy('title')->get();
|
|
|
|
$total_employees = DB::table('users')
|
|
->where('business_id', $business_id)
|
|
->where('user_type', 'user')
|
|
->where('allow_login', 1)
|
|
->whereNull('deleted_at')
|
|
->count();
|
|
|
|
$assigned_user_ids = DB::table('mt_user_skill')
|
|
->where('business_id', $business_id)
|
|
->distinct()
|
|
->pluck('user_id');
|
|
|
|
$rows = $skills->map(function ($skill) use ($business_id) {
|
|
$employees = DB::table('mt_user_skill as us')
|
|
->join('users as u', 'u.id', '=', 'us.user_id')
|
|
->where('us.business_id', $business_id)
|
|
->where('us.skill_id', $skill->id)
|
|
->where('u.user_type', 'user')
|
|
->where('u.allow_login', 1)
|
|
->whereNull('u.deleted_at')
|
|
->select('u.id', 'u.first_name', 'u.last_name', 'u.surname', 'us.skill_level')
|
|
->orderBy('u.first_name')
|
|
->get();
|
|
|
|
return (object) [
|
|
'skill' => $skill,
|
|
'employee_count' => $employees->count(),
|
|
'employees' => $employees,
|
|
];
|
|
});
|
|
|
|
return [
|
|
'rows' => $rows,
|
|
'total_employees' => $total_employees,
|
|
'employees_with_skills' => $assigned_user_ids->count(),
|
|
'employees_without_skills' => max(0, $total_employees - $assigned_user_ids->count()),
|
|
'unassigned_skills' => $rows->where('employee_count', 0)->count(),
|
|
];
|
|
}
|
|
|
|
public function getUserRecentScores(int $business_id, int $user_id, int $limit = 6)
|
|
{
|
|
return \Modules\ManagementTools\Entities\MtUserScore::forBusiness($business_id)
|
|
->where('user_id', $user_id)
|
|
->with('scoreCard')
|
|
->orderByDesc('created_at')
|
|
->limit($limit)
|
|
->get();
|
|
}
|
|
|
|
public function getUserTotalScorePoints(int $business_id, int $user_id): float
|
|
{
|
|
return \Modules\ManagementTools\Entities\MtUserScore::forBusiness($business_id)
|
|
->where('user_id', $user_id)
|
|
->with('scoreCard')
|
|
->get()
|
|
->sum(function ($s) {
|
|
return $s->scoreCard ? (float) $s->scoreCard->points : (float) $s->score;
|
|
});
|
|
}
|
|
}
|