Files
CKB/app/Services/TechnicianReportService.php

398 lines
13 KiB
PHP

<?php
namespace App\Services;
use App\Models\Work;
use App\Models\User;
use App\Models\Transaction;
use App\Models\Dealer;
use Carbon\Carbon;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
class TechnicianReportService
{
/**
* Get technician report data for all works and mechanics on a specific date range
*/
public function getTechnicianReportData($dealerId = null, $startDate = null, $endDate = null)
{
try {
// Debug: Check all users and roles
$allUsers = User::with('role')->get();
Log::info('All users in database:', [
'total_users' => $allUsers->count(),
'users_with_roles' => $allUsers->map(function($user) {
$roleName = 'No role';
if ($user->role) {
$roleName = is_string($user->role) ? $user->role : $user->role->name;
}
return [
'id' => $user->id,
'name' => $user->name,
'role_id' => $user->role_id,
'role_name' => $roleName,
'dealer_id' => $user->dealer_id
];
})
]);
// Get all works with category in single query
$works = Work::with(['category'])
->orderBy('name')
->get();
// Get all mechanics (users with role name = 'mechanic')
$mechanics = User::with('role')->whereHas('role', function($query) {
$query->where('name', 'mechanic');
})
->when($dealerId, function($query) use ($dealerId) {
return $query->where('dealer_id', $dealerId);
})
->orderBy('name')
->get(['id', 'name', 'role_id', 'dealer_id']);
// Fallback: If no mechanics found, get all users with dealer_id
if ($mechanics->isEmpty()) {
Log::info('No users with role "mechanic" found, using fallback: all users with dealer_id');
$mechanics = User::with('role')->whereNotNull('dealer_id')
->whereNotNull('role_id')
->when($dealerId, function($query) use ($dealerId) {
return $query->where('dealer_id', $dealerId);
})
->orderBy('name')
->get(['id', 'name', 'role_id', 'dealer_id']);
}
Log::info('Mechanics found:', [
'count' => $mechanics->count(),
'dealer_id_filter' => $dealerId,
'mechanics' => $mechanics->map(function($mechanic) {
$roleName = 'Unknown';
if ($mechanic->role) {
$roleName = is_string($mechanic->role) ? $mechanic->role : $mechanic->role->name;
}
return [
'id' => $mechanic->id,
'name' => $mechanic->name,
'role_id' => $mechanic->role_id,
'role_name' => $roleName,
'dealer_id' => $mechanic->dealer_id
];
})
]);
// Get all transaction data in single optimized query
$transactions = $this->getOptimizedTransactionData($dealerId, $startDate, $endDate, $mechanics->pluck('id'), $works->pluck('id'));
Log::info('Transaction data:', [
'transaction_count' => count($transactions),
'sample_transactions' => array_slice($transactions, 0, 5, true)
]);
$data = [];
foreach ($works as $work) {
$row = [
'work_id' => $work->id,
'work_name' => $work->name,
'work_code' => $work->shortname,
'category_name' => $work->category ? $work->category->name : '-',
'total_tickets' => 0
];
// Calculate totals for each mechanic
foreach ($mechanics as $mechanic) {
$key = $work->id . '_' . $mechanic->id;
$mechanicData = $transactions[$key] ?? ['total' => 0, 'completed' => 0, 'pending' => 0];
$row["mechanic_{$mechanic->id}_total"] = $mechanicData['total'];
// Add to totals
$row['total_tickets'] += $mechanicData['total'];
}
$data[] = $row;
}
Log::info('Final data prepared:', [
'data_count' => count($data),
'sample_data' => array_slice($data, 0, 2)
]);
return [
'data' => $data,
'mechanics' => $mechanics,
'works' => $works
];
} catch (\Exception $e) {
Log::error('Error in getTechnicianReportData: ' . $e->getMessage(), [
'dealer_id' => $dealerId,
'start_date' => $startDate,
'end_date' => $endDate,
'trace' => $e->getTraceAsString()
]);
// Return empty data structure but with proper format
return [
'data' => [],
'mechanics' => collect(),
'works' => collect()
];
}
}
/**
* Get optimized transaction data in single query
*/
private function getOptimizedTransactionData($dealerId = null, $startDate = null, $endDate = null, $mechanicIds = null, $workIds = null)
{
$query = Transaction::select(
'work_id',
'user_id',
'status',
DB::raw('COUNT(*) as count')
)
->groupBy('work_id', 'user_id', 'status');
if ($dealerId) {
$query->where('dealer_id', $dealerId);
}
if ($startDate) {
$query->where('date', '>=', $startDate);
}
if ($endDate) {
$query->where('date', '<=', $endDate);
}
if ($mechanicIds && $mechanicIds->count() > 0) {
$query->whereIn('user_id', $mechanicIds);
}
if ($workIds && $workIds->count() > 0) {
$query->whereIn('work_id', $workIds);
}
// Remove index hint that doesn't exist
$results = $query->get();
// Organize data by work_id_user_id key
$organizedData = [];
foreach ($results as $result) {
$key = $result->work_id . '_' . $result->user_id;
if (!isset($organizedData[$key])) {
$organizedData[$key] = [
'total' => 0,
'completed' => 0,
'pending' => 0
];
}
$organizedData[$key]['total'] += $result->count;
if ($result->status == 1) {
$organizedData[$key]['completed'] += $result->count;
} else {
$organizedData[$key]['pending'] += $result->count;
}
}
return $organizedData;
}
/**
* Get total ticket count for a specific work and mechanic (legacy method for backward compatibility)
*/
private function getTicketCount($workId, $mechanicId, $dealerId = null, $startDate = null, $endDate = null)
{
$query = Transaction::where('work_id', $workId)
->where('user_id', $mechanicId);
if ($dealerId) {
$query->where('dealer_id', $dealerId);
}
if ($startDate) {
$query->where('date', '>=', $startDate);
}
if ($endDate) {
$query->where('date', '<=', $endDate);
}
return $query->count();
}
/**
* Get completed ticket count for a specific work and mechanic (legacy method for backward compatibility)
*/
private function getCompletedTicketCount($workId, $mechanicId, $dealerId = null, $startDate = null, $endDate = null)
{
$query = Transaction::where('work_id', $workId)
->where('user_id', $mechanicId)
->where('status', 1); // Assuming status 1 is completed
if ($dealerId) {
$query->where('dealer_id', $dealerId);
}
if ($startDate) {
$query->where('date', '>=', $startDate);
}
if ($endDate) {
$query->where('date', '<=', $endDate);
}
return $query->count();
}
/**
* Get pending ticket count for a specific work and mechanic (legacy method for backward compatibility)
*/
private function getPendingTicketCount($workId, $mechanicId, $dealerId = null, $startDate = null, $endDate = null)
{
$query = Transaction::where('work_id', $workId)
->where('user_id', $mechanicId)
->where('status', 0); // Assuming status 0 is pending
if ($dealerId) {
$query->where('dealer_id', $dealerId);
}
if ($startDate) {
$query->where('date', '>=', $startDate);
}
if ($endDate) {
$query->where('date', '<=', $endDate);
}
return $query->count();
}
/**
* Get all dealers for filter
*/
public function getDealers()
{
return Dealer::orderBy('name')->get(['id', 'name', 'dealer_code']);
}
/**
* Get default dealer for filter (tidak perlu berbasis user)
*/
public function getDefaultDealer()
{
// Dealer pertama saja jika ada
return Dealer::orderBy('name')->first();
}
/**
* Get mechanics for a specific dealer
*/
public function getMechanicsByDealer($dealerId = null)
{
$query = User::with('role')->whereHas('role', function($query) {
$query->where('name', 'mechanic');
});
if ($dealerId) {
$query->where('dealer_id', $dealerId);
}
return $query->orderBy('name')->get(['id', 'name', 'dealer_id']);
}
/**
* Get technician report data for Yajra DataTable
*/
public function getTechnicianReportDataForDataTable($dealerId = null, $startDate = null, $endDate = null)
{
try {
// Get all works with category
$works = Work::with(['category'])
->orderBy('name')
->get();
// Get all mechanics
$mechanics = User::with('role')->whereHas('role', function($query) {
$query->where('name', 'mechanic');
})
->when($dealerId, function($query) use ($dealerId) {
return $query->where('dealer_id', $dealerId);
})
->orderBy('name')
->get(['id', 'name', 'role_id', 'dealer_id']);
// Fallback: If no mechanics found, get all users with dealer_id
if ($mechanics->isEmpty()) {
Log::info('No users with role "mechanic" found, using fallback: all users with dealer_id');
$mechanics = User::with('role')->whereNotNull('dealer_id')
->whereNotNull('role_id')
->when($dealerId, function($query) use ($dealerId) {
return $query->where('dealer_id', $dealerId);
})
->orderBy('name')
->get(['id', 'name', 'role_id', 'dealer_id']);
}
// Get transaction data
$transactions = $this->getOptimizedTransactionData($dealerId, $startDate, $endDate, $mechanics->pluck('id'), $works->pluck('id'));
$data = [];
foreach ($works as $work) {
$row = [
'DT_RowIndex' => count($data) + 1,
'work_name' => $work->name,
'work_code' => $work->shortname,
'category_name' => $work->category ? $work->category->name : '-'
];
// Add mechanic columns
foreach ($mechanics as $mechanic) {
$key = $work->id . '_' . $mechanic->id;
$mechanicData = $transactions[$key] ?? ['total' => 0, 'completed' => 0, 'pending' => 0];
$row["mechanic_{$mechanic->id}_total"] = $mechanicData['total'];
}
$data[] = $row;
}
// Create DataTable response
return response()->json([
'draw' => request()->input('draw', 1),
'recordsTotal' => count($data),
'recordsFiltered' => count($data),
'data' => $data,
'mechanics' => $mechanics,
'works' => $works
]);
} catch (\Exception $e) {
Log::error('Error in getTechnicianReportDataForDataTable: ' . $e->getMessage(), [
'dealer_id' => $dealerId,
'start_date' => $startDate,
'end_date' => $endDate,
'trace' => $e->getTraceAsString()
]);
return response()->json([
'draw' => request()->input('draw', 1),
'recordsTotal' => 0,
'recordsFiltered' => 0,
'data' => [],
'mechanics' => collect(),
'works' => collect()
]);
}
}
}