398 lines
13 KiB
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()
|
|
]);
|
|
}
|
|
}
|
|
|
|
}
|