370 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
			
		
		
	
	
			370 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
| <?php
 | |
| 
 | |
| namespace App\Http\Controllers;
 | |
| 
 | |
| use App\Http\Controllers\Controller;
 | |
| use Illuminate\Http\Request;
 | |
| use Illuminate\Http\Response;
 | |
| use Illuminate\Support\Facades\DB;
 | |
| use Illuminate\Support\Facades\Storage;
 | |
| use Validator;
 | |
| use Auth;
 | |
| use App\Responses;
 | |
| use App\Helper;
 | |
| use Maatwebsite\Excel\Facades\Excel;
 | |
| use Maatwebsite\Excel\Concerns\FromArray;
 | |
| use Maatwebsite\Excel\Concerns\WithHeadings;
 | |
| use Maatwebsite\Excel\Concerns\WithStyles;
 | |
| use Maatwebsite\Excel\Concerns\WithCustomStartCell;
 | |
| use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet;
 | |
| use Carbon\Carbon;
 | |
| use App\Models\UserLogs;
 | |
| 
 | |
| class ReportsController extends Controller
 | |
| {
 | |
| 	public function view_report_vehicle_trips(Request $req)
 | |
| 	{
 | |
| 		$q = "SELECT id, nopol1 from t_vehicles WHERE dlt is null order by nopol1";
 | |
| 		$listNopol = DB::select($q);
 | |
| 
 | |
| 		$data = [
 | |
| 			'listNopol' => $listNopol,
 | |
| 		];
 | |
| 
 | |
| 		$log = [
 | |
| 			"module" => "Vehicle Trips Report",
 | |
| 			"action" => "View",
 | |
| 			"desc" => "Open Vehicle Trips Report menu",
 | |
| 		];
 | |
| 		UserLogs::insert(Auth::user()->id, $log);
 | |
| 		return view('menu_v1.reports.vehicle_trips', $data);
 | |
| 	}
 | |
| 	public function api_report_vehicle_trips_list(Request $req)
 | |
| 	{
 | |
| 		// $TIMEFIX = Helper::TIMEFIX;
 | |
| 		// Validate input
 | |
| 		// date in unix datetime format
 | |
| 		// dd($req->type);
 | |
| 		$rules = [
 | |
| 			// 'from_date' => 'required|date',
 | |
| 			// 'to_date' => 'required|date|after_or_equal:from_date',
 | |
| 			'type' => 'nullable|in:report,list', // enum "report", "list". nullable default "list"
 | |
| 		];
 | |
| 
 | |
| 		$isValidInput = Validator::make($req->all(), $rules);
 | |
| 		if (!$isValidInput->passes()) {
 | |
| 			$apiResp = Responses::bad_input($isValidInput->messages()->first());
 | |
| 			return new Response($apiResp, $apiResp["meta"]["code"]);
 | |
| 		}
 | |
| 
 | |
| 		// $from_date = $req->input('from_date');
 | |
| 		// $to_date = $req->input('to_date');
 | |
| 		$from_date = $req->input('from_date') - Helper::TIMEFIX;
 | |
| 		$to_date = $req->input('to_date') - Helper::TIMEFIX;
 | |
| 		$vid = $req->input('vid');
 | |
| 		// $from_date = 1756054800;
 | |
| 		// $to_date = 1756745940;
 | |
| 
 | |
| 		// get month year
 | |
| 		$date = Carbon::createFromTimestamp($from_date);
 | |
| 		$yymm = $date->format('ym');
 | |
| 
 | |
| 		try {
 | |
| 			// $list = DB::select("WITH 
 | |
| 			// 	gaps AS (
 | |
| 			// 		SELECT
 | |
| 			// 			-- previous gap since previous row > 1 hour (3600s)
 | |
| 			// 			CASE
 | |
| 			// 				WHEN (crt_d - LAG(crt_d, 1, NULL) OVER (PARTITION BY vhc_id ORDER BY crt_d)) > 3600
 | |
| 			// 				THEN 1 ELSE 0
 | |
| 			// 			END AS isStop,
 | |
| 			// 			t.*
 | |
| 			// 		FROM tracks_2509 t
 | |
| 			// 		WHERE 
 | |
| 			// 		t.latitude IS NOT NULL
 | |
| 			// 		AND t.longitude IS NOT NULL
 | |
| 			// 		AND t.action = 'location'
 | |
| 			// 		AND t.crt_d BETWEEN ? AND ?
 | |
| 			// 	)
 | |
| 			// 	, trips AS (
 | |
| 			// 		SELECT
 | |
| 			// 			-- mark the start of a trip when ignition=4 and previous ignition <> 4
 | |
| 			// 			CASE
 | |
| 			// 				WHEN ignition = 4 
 | |
| 			// 					AND LAG(ignition, 1, 0) OVER (PARTITION BY vhc_id ORDER BY crt_d) <> 4
 | |
| 			// 					or LAG(isStop, 1, 0) over (PARTITION BY vhc_id ORDER BY crt_d) = 1
 | |
| 			// 				THEN 1 ELSE 0
 | |
| 			// 			END AS trip_start,
 | |
| 			// 			g.*
 | |
| 			// 		FROM gaps g
 | |
| 			// 	)
 | |
| 			// 	, numbered AS (
 | |
| 			// 		SELECT
 | |
| 			// 			*,
 | |
| 			// 			-- assign a trip_id by cumulative sum of trip_start
 | |
| 			// 			SUM(trip_start) OVER (PARTITION BY vhc_id ORDER BY crt_d) AS trip_id
 | |
| 			// 		FROM trips
 | |
| 			// 		where 
 | |
| 			// 			ignition = 4
 | |
| 			// 			and isStop = 0
 | |
| 			// 	),
 | |
| 			// 	agg AS (
 | |
| 			// 		SELECT
 | |
| 			// 			COUNT(*) AS row_count,
 | |
| 			// 			v.name,
 | |
| 			// 			v.nopol1,
 | |
| 			// 			vhc_id,
 | |
| 			// 			-- trip_id,
 | |
| 			// 			ROW_NUMBER() OVER (PARTITION BY v.id ORDER BY MIN(a.crt_d)) AS trip_id,
 | |
| 			// 			SUM(pre_milleage) AS mileage,
 | |
| 			// 			MIN(a.crt_d) AS start,
 | |
| 			// 			MAX(a.crt_d) AS finish,
 | |
| 			// 			MIN(a.vhc_milleage) AS startMileage,
 | |
| 			// 			MAX(a.vhc_milleage) AS finishMileage,
 | |
| 			// 			(SELECT fulladdress FROM t_gps_tracks_address WHERE master_id = MIN(a.id) LIMIT 1) AS startLoc,
 | |
| 			// 			(SELECT fulladdress FROM t_gps_tracks_address WHERE master_id = MAX(a.id) LIMIT 1) AS finishLoc
 | |
| 			// 		FROM t_vehicles v
 | |
| 			// 		LEFT JOIN numbered a ON a.vhc_id = v.id
 | |
| 			// 		WHERE 
 | |
| 			// 			v.dlt is null and trip_id != 0 
 | |
| 			// 			and if(? , v.id = ? , 1=1)
 | |
| 			// 		GROUP BY v.id, a.trip_id
 | |
| 			// 		HAVING COUNT(*) > 1
 | |
| 			// 	)
 | |
| 			// 	SELECT
 | |
| 			// 		*,
 | |
| 			// 		SUM(mileage) OVER (PARTITION BY agg.id) AS total_mileage,
 | |
| 			// 		COUNT(trip_id) OVER (PARTITION BY agg.id) AS total_trip,
 | |
| 			// 		tvd.pool_code, tvd.dc_code
 | |
| 			// 	FROM agg agg
 | |
| 			// 		join t_vehicles_detail tvd on tvd.vid = agg.vhc_id
 | |
| 			// 	ORDER BY agg.id, trip_id			
 | |
| 			// ", [$from_date, $to_date, $vid, $vid]);
 | |
| 
 | |
| 			$list = DB::select("WITH TotalMileage AS (
 | |
| 					SELECT id, SUM(mileage) AS total_mileage, count(*) total_trip
 | |
| 					FROM trips
 | |
| 					WHERE start BETWEEN ? AND ?
 | |
| 					GROUP BY id
 | |
| 				)
 | |
| 				SELECT 
 | |
| 					t.*,
 | |
| 					tm.total_mileage, total_trip,
 | |
| 					ROW_NUMBER() OVER (PARTITION BY t.id ORDER BY t.start) AS trip_id
 | |
| 				FROM trips t
 | |
| 					JOIN TotalMileage tm ON t.id = tm.id
 | |
| 				WHERE
 | |
| 					t.start BETWEEN ? AND ?
 | |
| 					and if(? , t.id = ? , 1=1)
 | |
| 			", [$from_date, $to_date, $from_date, $to_date, $vid, $vid]);
 | |
| 
 | |
| 			// // RETURN 1 - LIST
 | |
| 			// if($req->type != 'report'){
 | |
| 				$apiResp = Responses::success("success list vehicles report");
 | |
| 				$apiResp["data"] = $list;
 | |
| 				return new Response($apiResp, $apiResp["meta"]["code"]);
 | |
| 			// }
 | |
| 
 | |
| 			// // RETURN 2 - REPORT
 | |
| 			// if($req->type == 'report'){
 | |
| 			// 	$headings = ['Name', 'License Plate', 'Number of Trip', 'Total Mileage'];
 | |
| 
 | |
| 			// 	$export = new class($list, $headings) implements FromArray, WithHeadings {
 | |
| 			// 		private $list;
 | |
| 			// 		private $headings;
 | |
| 
 | |
| 			// 		public function __construct($list, $headings)
 | |
| 			// 		{
 | |
| 			// 			$this->list = $list;
 | |
| 			// 			$this->headings = $headings;
 | |
| 			// 		}
 | |
| 
 | |
| 			// 		public function array(): array
 | |
| 			// 		{
 | |
| 			// 			return array_map(function ($item) {
 | |
| 			// 				return [
 | |
| 			// 					$item->name,
 | |
| 			// 					$item->nopol1,
 | |
| 			// 					$item->numOfTrip,
 | |
| 			// 					$item->total_milleage,
 | |
| 			// 				];
 | |
| 			// 			}, $this->list);
 | |
| 			// 		}
 | |
| 
 | |
| 			// 		public function headings(): array
 | |
| 			// 		{
 | |
| 			// 			return $this->headings;
 | |
| 			// 		}
 | |
| 
 | |
| 			// 		// Start table from A3
 | |
| 			// 		public function startCell(): string
 | |
| 			// 		{
 | |
| 			// 			return 'A3';
 | |
| 			// 		}
 | |
| 
 | |
| 			// 		// Add title & border styling
 | |
| 			// 		public function styles(Worksheet $sheet)
 | |
| 			// 		{
 | |
| 			// 			$tgl0 = date('d-m-Y', $GLOBALS['from_date']);
 | |
| 			// 			$tgl1 = date('d-m-Y', $GLOBALS['to_date']);
 | |
| 
 | |
| 			// 			// Title in A1
 | |
| 			// 			$sheet->setCellValue('A1', 'Vehicle Trip Report $tgl0 until $tgl1');
 | |
| 			// 			$sheet->getStyle('A1')->getFont()->setBold(true)->setSize(16);
 | |
| 			// 			$sheet->getStyle('A1')->getAlignment()->setHorizontal('center');
 | |
| 			// 			$sheet->mergeCells('A1:D1'); // Merge across 4 columns
 | |
| 
 | |
| 			// 			// Get last row
 | |
| 			// 			$lastRow = $this->list->count() + 3; // 3 = heading row
 | |
| 			// 			$range = "A3:D{$lastRow}";
 | |
| 
 | |
| 			// 			// Add borders
 | |
| 			// 			$sheet->getStyle($range)->getBorders()->getAllBorders()
 | |
| 			// 				->setBorderStyle(\PhpOffice\PhpSpreadsheet\Style\Border::BORDER_THIN);
 | |
| 
 | |
| 			// 			// Bold headings
 | |
| 			// 			$sheet->getStyle('A3:D3')->getFont()->setBold(true);
 | |
| 
 | |
| 			// 			return [];
 | |
| 			// 		}
 | |
| 			// 	};
 | |
| 
 | |
| 			// 	return Excel::download($export, 'trip_report.xlsx');
 | |
| 			// }
 | |
| 		} catch (\Exception $e) {
 | |
|             $apiResp = Responses::error($e->getMessage());
 | |
|             return new Response($apiResp, $apiResp["meta"]["code"]);
 | |
| 			// return Responses::json(Responses::SERVER_ERROR, 'An error occurred while generating the report.', (object)[]);
 | |
| 		}
 | |
| 	}
 | |
| 	public function view_report_trip_detail(Request $req)
 | |
| 	{
 | |
| 		$vid = $req->vid;
 | |
| 		$tgl0 = $req->tgl0;
 | |
| 		$tgl1 = $req->tgl1;
 | |
| 		$nopol1 = $req->nopol1;
 | |
| 
 | |
| 		$d = [$vid, $tgl0, $tgl1];
 | |
| 		$list = DB::select("SELECT
 | |
| 				t.crt_d , t.latitude, t.longitude, t.speed,
 | |
| 				tgta.fulladdress,
 | |
| 				t.pre_milleage, t.vhc_milleage 
 | |
| 			FROM 
 | |
| 				t_gps_tracks t
 | |
| 				left join t_gps_tracks_address tgta on tgta.master_id = t.id 
 | |
| 			WHERE 
 | |
| 				t.vhc_id = ?
 | |
| 				and t.latitude IS NOT NULL
 | |
| 				AND t.longitude IS NOT NULL
 | |
| 				AND t.action = 'location'
 | |
| 				AND t.crt_d BETWEEN ? AND ?
 | |
| 			ORDER BY t.crt_d asc
 | |
| 		", $d);
 | |
| 
 | |
| 		$start = [
 | |
| 			'time' => $list[0]->crt_d,
 | |
| 			'fulladdress' => urldecode($list[0]->fulladdress),
 | |
| 			'mileage' => $list[0]->vhc_milleage,
 | |
| 		];
 | |
| 		$finish = [
 | |
| 			'time' => $list[count($list) - 1]->crt_d,
 | |
| 			'fulladdress' => urldecode($list[count($list) - 1]->fulladdress),
 | |
| 			'mileage' => $list[count($list) - 1]->vhc_milleage,
 | |
| 		];
 | |
| 
 | |
| 		$t0 = Carbon::createFromTimestamp($list[0]->crt_d);
 | |
| 		$t1 = Carbon::createFromTimestamp($list[count($list) - 1]->crt_d);
 | |
| 		$diff = $t1->diff($t0);
 | |
| 		$hours = $diff->h + ($diff->days * 24); // include days converted to hours
 | |
| 		$minutes = $diff->i;
 | |
| 		$duration = "{$hours} hour" . ($hours > 1 ? 's' : '') . " {$minutes} minute" . ($minutes > 1 ? 's' : '');
 | |
| 
 | |
| 		$distance = $list[count($list) - 1]->vhc_milleage - $list[0]->vhc_milleage;
 | |
| 
 | |
| 		$data = [
 | |
| 			'nopol1' => $nopol1,
 | |
| 			'vid' => $vid,
 | |
| 			'tgl0' => $tgl0,
 | |
| 			'tgl1' => $tgl1,
 | |
| 			'list' => $list,
 | |
| 			'start' => $start,
 | |
| 			'finish' => $finish,
 | |
| 			'duration' => $duration,
 | |
| 			'distance' => $distance,
 | |
| 		];
 | |
| 		// dd($list);
 | |
| 		return view('menu_v1.reports._trip_detail', $data);
 | |
| 	}
 | |
| 
 | |
| 	public function view_report_abnormalities(Request $req)
 | |
| 	{
 | |
| 		$q = "select id, nopol1 from t_vehicles WHERE dlt is null order by nopol1";
 | |
| 		$listNopol = DB::select($q);
 | |
| 
 | |
| 		$data = [
 | |
| 			'listNopol' => $listNopol,
 | |
| 		];
 | |
| 
 | |
| 		$log = [
 | |
| 			"module" => "Abnormalities Report",
 | |
| 			"action" => "View",
 | |
| 			"desc" => "Open Abnormalities Report menu",
 | |
| 		];
 | |
| 		UserLogs::insert(Auth::user()->id, $log);
 | |
| 		return view('menu_v1.reports.abnormalities', $data);
 | |
| 	}
 | |
| 	public function api_report_abnormalities_list(Request $req)
 | |
| 	{
 | |
| 		// Validate input
 | |
| 		$rules = [
 | |
| 			// 'from_date' => 'required|date',
 | |
| 			// 'to_date' => 'required|date|after_or_equal:from_date',
 | |
| 			'type' => 'nullable|in:report,list', // enum "report", "list". nullable default "list"
 | |
| 		];
 | |
| 
 | |
| 		$isValidInput = Validator::make($req->all(), $rules);
 | |
| 		if (!$isValidInput->passes()) {
 | |
| 			$apiResp = Responses::bad_input($isValidInput->messages()->first());
 | |
| 			return new Response($apiResp, $apiResp["meta"]["code"]);
 | |
| 		}
 | |
| 
 | |
| 		$from_date = $req->input('from_date') - Helper::TIMEFIX;
 | |
| 		$to_date = $req->input('to_date') - Helper::TIMEFIX;
 | |
| 		$vid = $req->input('vid');
 | |
| 
 | |
| 		try {
 | |
| 			$list = DB::select("SELECT
 | |
| 					tv.name, tv.nopol1, 
 | |
| 					t.crt_d, t.speed, tgta.fulladdress,
 | |
| 					tvd.speed_limit, tvd.pool_code, tvd.dc_code
 | |
| 				from
 | |
| 					t_gps_tracks t
 | |
| 					left join t_vehicles tv on tv.id = t.vhc_id 
 | |
| 					left join t_vehicles_detail tvd on tvd.vid = tv.id
 | |
| 					left join t_gps_tracks_address tgta on tgta.master_id = t.id
 | |
| 				WHERE 
 | |
| 					t.action = 'location'
 | |
| 					and t.speed != 0 
 | |
| 					AND t.crt_d BETWEEN ? AND ?
 | |
| 					and if(? , tv.id = ? , 1=1)
 | |
| 					-- and t.speed > tvd.speed_limit 
 | |
| 				having t.speed >= tvd.speed_limit
 | |
| 				ORDER BY t.crt_d
 | |
| 			", [$from_date, $to_date, $vid, $vid]);
 | |
| 
 | |
| 			// // RETURN 1 - LIST
 | |
| 			// if($req->type != 'report'){
 | |
| 				$apiResp = Responses::success("success list abnormalities report");
 | |
| 				$apiResp["data"] = $list;
 | |
| 				return new Response($apiResp, $apiResp["meta"]["code"]);
 | |
| 			// }
 | |
| 
 | |
| 		} catch (\Exception $e) {
 | |
|             $apiResp = Responses::error($e->getMessage());
 | |
|             return new Response($apiResp, $apiResp["meta"]["code"]);
 | |
| 			// return Responses::json(Responses::SERVER_ERROR, 'An error occurred while generating the report.', (object)[]);
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| }
 | 
