Skip to content

Instantly share code, notes, and snippets.

@ahsanmster
Created November 2, 2022 03:53
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ahsanmster/c5e844d1aaa093baa7396aa338312764 to your computer and use it in GitHub Desktop.
Save ahsanmster/c5e844d1aaa093baa7396aa338312764 to your computer and use it in GitHub Desktop.
<?php
namespace App\Http\Controllers\Api\DrivingRoute;
use App\Http\Controllers\Controller;
use App\Http\Requests\DrivingRoute\DrivingRouteKpiRequest;
use App\Http\Requests\DrivingRoute\FilterDrivingRoutesRequest;
use App\Models\PropertyLeadStatus;
use App\Services\DrivingRoute\DrivingRouteService;
use App\Models\DrivingRoute\DrivingRoute;
use Carbon\Carbon;
class KpiRouteReportsController extends Controller
{
/**
* @OA\Post(
* path="/api/driving-route/kpi-report/dashboard",
* operationId="DrivingRouteReport",
* tags={"DrivingRouteReport"},
* summary="Driving Route Dashboard KPI",
* description="Driving Route Dashboard KPI",
* @OA\RequestBody(
* required = true,
* description = "",
* @OA\JsonContent(
* @OA\Property(
* property="from_date",
* type="date",
* example="2022-06-01",
* ),
* @OA\Property(
* property="to_date",
* type="date",
* example="2022-06-15",
* ),
* @OA\Property(
* property="team_member",
* type="boolean",
* example="1",
* ),
* @OA\Property(
* property="lead_status",
* type="integer",
* example="1",
* ),
* @OA\Property(
* property="route_type",
* type="integer",
* example="1",
* ),
* @OA\Property(
* property="driving_type",
* type="integer",
* example="1",
* ),
* ),
* ),
* @OA\Response(
* response="200",
* description="data found",
* @OA\JsonContent(
* type="json",
* format="application/json",
* example=""
* )
* ),
* security={{ "apiAuth": {} }}
* )
* @param FilterDrivingRoutesRequest $request
* @return
*/
public function kpiReports(DrivingRouteKpiRequest $request)
{
$userCompanyId = appCompanyId();
if(!empty($request->lead_status)) {
$leadStatus = self::getPropertyLeadStatus($request->lead_status);
if(empty($leadStatus) || ($leadStatus->is_system != 1 && $leadStatus->user_id != $userCompanyId)) {
return response()->errorResponse('Invalid Lead Status', []);
}
}
if(!empty($request->team_member)) {
$user = appUserById($request->team_member);
if(empty($user) || ($userCompanyId != $user->company_id)){
return response()->errorResponse('Invalid Team member', []);
}
}
$request->request->add([
'timezone' => appCompanyUser()->default_timezone
]);
/** @var DrivingRouteService $drivingRouteService */
$drivingRouteService = resolve(DrivingRouteService::class);
$response = $drivingRouteService->gateway($request)->getData();
if (!empty($response->data->data)) {
$record = collect(($response->data)->data)->values();
$dates = ($response->data)->dates;
$startDate = Carbon::parse($dates->start_date)->startOfDay();
$endDate = Carbon::parse($dates->end_date)->endOfDay();
$prevStartDate = Carbon::parse($dates->prev_start_date)->toDateString();
$prevEndDate = $dates->prev_end_date;
// Applying lead status
if (!empty($request->lead_status) && $request->lead_status != 0) {
$recordWithLeadStatus = $drivingRouteService->getRecordsLeadStatus($record, $prevStartDate, $endDate, $request->lead_status);
$drivingRouteIds = $recordWithLeadStatus->pluck('driving_route_id');
$record = $record->whereIn('driving_route_id', $drivingRouteIds);
$newRecord = collect();
// the record(total properties count) coming from pgsql is against all lead status
// so i am calculating the record from mysql and updating in pgsql count
foreach ($record as $key => $rls){
$newRecordObject = $rls;
$newRecordObject->property_count = $recordWithLeadStatus->where('driving_route_id', '=', $rls->driving_route_id)->sum('total_count');
$newRecord->push($newRecordObject);
}
$record = $newRecord;
}
$record = ($record->groupBy('name')->values()); // all record previous & current
$formattedArray = self::createArray($record);
$propertiesAddedStats = self::calculateStats($formattedArray['property_added_live'], $formattedArray['property_added_virtual'], $dates);
$milesDrivenStats = self::calculateStats($formattedArray['miles_driven_live'], $formattedArray['miles_driven_virtual'], $dates);
$timesDrivenStats = self::calculateStats($formattedArray['times_driven_live'], $formattedArray['times_driven_virtual'], $dates, 'secondsToMinutes');
$propertiesAddedGraph = self::formatObject($formattedArray['property_added_virtual'], $formattedArray['property_added_live'], $startDate, $endDate);
$milesDrivenGraph = self::formatObject($formattedArray['miles_driven_virtual'], $formattedArray['miles_driven_live'], $startDate, $endDate);
$timesDrivenGraph = self::formatObject($formattedArray['times_driven_virtual'], $formattedArray['times_driven_live'], $startDate, $endDate);
$response = collect([
'stats' => [
'start_date' => Carbon::parse($startDate)->toDateString(),
'end_date' => Carbon::parse($endDate)->toDateString(),
'prev_start_date' => Carbon::parse($prevStartDate)->toDateString(),
'prev_end_date' => Carbon::parse($prevEndDate)->toDateString(),
'total_properties_added' => $propertiesAddedStats['current_total'],
'total_miles_drive' => toFixDecimal($milesDrivenStats['current_total']),
'total_time_drive' => floor($timesDrivenStats['current_total']),
'virtual_properties_added' => $propertiesAddedStats['virtual_total'],
'live_properties_added' => $propertiesAddedStats['live_total'],
'virtual_miles_added' => toFixDecimal($milesDrivenStats['virtual_total']),
'live_miles_added' => toFixDecimal($milesDrivenStats['live_total']),
'virtual_time_added' => floor($timesDrivenStats['virtual_total']),
'live_time_added' => floor($timesDrivenStats['live_total']),
],
'properties_added' => [
'stats' => $propertiesAddedStats,
'graph' => $propertiesAddedGraph
],
'miles_driven' => [
'stats' => $milesDrivenStats,
'graph' => $milesDrivenGraph
],
'time_driven' => [
'stats' => $timesDrivenStats,
'graph' => $timesDrivenGraph
]
]);
return response()->successResponse('Data Found', $response);
} else {
return response()->successResponse('Data Not Found', []);
}
}
// all record arrays previous & current
/**
* @param $record
* @return \Illuminate\Support\Collection
*/
private function createArray($record)
{
$propertiesAddedLive = collect();
$propertiesAddedVirtual = collect();
$milesDrivenRecordLive = collect();
$milesDrivenRecordVirtual = collect();
$timesDrivenRecordLive = collect();
$timesDrivenRecordVirtual = collect();
foreach ($record as $pgsql) {
$live = $pgsql->where('route_type', '=', DrivingRouteService::ROUTE_TYPE_LIVE);
$virtual = $pgsql->where('route_type', '=', DrivingRouteService::ROUTE_TYPE_VIRTUAL);
if ($live->count() > 0) {
$propertiesAddedLive->push([
'route_type' => $live->first()->route_type,
'name' => $pgsql->first()->name,
'value' => $live->sum('property_count')
]);
$milesDrivenRecordLive->push([
'route_type' => $live->first()->route_type,
'name' => $pgsql->first()->name,
'value' => $live->sum('total_distance')
]);
$timesDrivenRecordLive->push([
'route_type' => $live->first()->route_type,
'name' => $pgsql->first()->name,
'value' => $live->sum('total_seconds')
]);
}
if ($virtual->count() > 0) {
$propertiesAddedVirtual->push([
'route_type' => $virtual->first()->route_type,
'name' => $pgsql->first()->name,
'value' => $virtual->sum('property_count')
]);
$milesDrivenRecordVirtual->push([
'route_type' => $virtual->first()->route_type,
'name' => $pgsql->first()->name,
'value' => $virtual->sum('total_distance')
]);
$timesDrivenRecordVirtual->push([
'route_type' => $virtual->first()->route_type,
'name' => $pgsql->first()->name,
'value' => $virtual->sum('total_seconds')
]);
}
}
return collect([
'property_added_live' => $propertiesAddedLive,
'property_added_virtual' => $propertiesAddedVirtual,
'miles_driven_live' => $milesDrivenRecordLive,
'miles_driven_virtual' => $milesDrivenRecordVirtual,
'times_driven_live' => $timesDrivenRecordLive,
'times_driven_virtual' => $timesDrivenRecordVirtual
]);
}
/**
* @param $virtual
* @param $live
* @param $startDate
* @param $endDate
* @return \Illuminate\Support\Collection
*/
private function formatObject($virtual, $live, $startDate, $endDate)
{
$graph = collect();
//setting up virtual data
$data = $virtual->whereBetween('name', [$startDate, $endDate])->values();
$data = self::setupDataForDates($data, $startDate, $endDate, 2);
$graph->push([
'name' => DrivingRouteService::ROUTE_TYPE_VIRTUAL_KEY,
'series' => $data
]);
//setting up live data
$data = $live->whereBetween('name', [$startDate, $endDate])->values();
$data = self::setupDataForDates($data, $startDate, $endDate, 1);
$graph->push([
'name' => DrivingRouteService::ROUTE_TYPE_LIVE_KEY,
'series' => $data
]);
return $graph;
}
/**
* The purpose of the function is to loop from start to end date
* and if there is no data against any date it will send 0 as value
* to populate graph on the client side.
*
* @param $data
* @param $startDate
* @param $endDate
* @param $routeType
* @return array
*/
public function setupDataForDates($data, $startDate, $endDate, $routeType)
{
$days = $startDate->diffInDays($endDate)+1;
$newArr = array();
for ($i=0; $i < $days; $i++){
$d1 = (Carbon::parse($startDate)->startOfDay()->addDays($i)->toDateString());
$d2 = (Carbon::parse($startDate)->endOfDay()->addDays($i)->toDateString());
$dt = $data->whereBetween('name', [$d1, $d2]);
if(count($dt) > 0) {
array_push($newArr, array(
'route_type' => $dt->first()['route_type'],
'name' => $dt->first()['name'],
'value' => $dt->first()['value'],
));
} else {
array_push($newArr, array(
'route_type' => $routeType,
'name' => $d1,
'value' => 0
));
}
}
return $newArr;
}
/**
* @param $live
* @param $virtual
* @param $dates
* @param null $convert // can pass helper function name here and it will apply that filter on final calculations
* @return mixed
*/
private function calculateStats($live, $virtual, $dates, $convert = null)
{
$startDate = Carbon::parse($dates->start_date)->startOfDay()->toDateString();
$endDate = Carbon::parse($dates->end_date)->endOfDay()->toDateString();
$prevStartDate = Carbon::parse($dates->prev_start_date)->startOfDay()->toDateString();
$prevEndDate = Carbon::parse($dates->prev_end_date)->endOfDay()->toDateString();
$allRecord = $live->merge($virtual);
$virtual_total = $virtual->whereBetween('name', [$startDate, $endDate])->sum('value');
$live_total = $live->whereBetween('name', [$startDate, $endDate])->sum('value');
$current_total = $allRecord->whereBetween('name', [$startDate, $endDate])->sum('value');
$previous_total = $allRecord->whereBetween('name', [$prevStartDate, $prevEndDate])->sum('value');
if (!empty($convert)) {
$virtual_total = call_user_func($convert, $virtual_total);
$live_total = call_user_func($convert, $live_total);
$current_total = call_user_func($convert, $current_total);
$previous_total = call_user_func($convert, $previous_total);
}
$percent_change = pct_change($previous_total, $current_total);
return [
'virtual_total' => toFixDecimal($virtual_total),
'live_total' => toFixDecimal($live_total),
'current_total' => toFixDecimal($current_total),
'previous_total' => toFixDecimal($previous_total),
'percent_change' => toFixDecimal($percent_change),
];
}
public function getPropertyLeadStatus($id)
{
return PropertyLeadStatus::query()->find($id);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment