Merge branch '543-autoassign-revisions' of gitlab.com:jankstudio/resq into 552-add-notification-number-to-hub

This commit is contained in:
Korina Cordero 2021-04-26 03:06:01 +00:00
commit 3a5d57e35c
14 changed files with 894 additions and 84 deletions

View file

@ -57,6 +57,7 @@ COUNTRY_CODE=+insert_country_code_here
# redis hash
LATEST_ACTIVE_JO=latest_active_jo
HUB_JO_KEY=hub_jo_count
# dashboard
DASHBOARD_ENABLE=set_to_true_or_false

View file

@ -266,3 +266,21 @@ services:
event: 'postPersist'
entity: 'App\Entity\CustomerVehicle'
# hub service
App\Service\HubSelector:
arguments:
$em: "@doctrine.orm.entity_manager"
$im: "@App\\Service\\InventoryManager"
$hub_distributor: "@App\\Service\\HubDistributor"
$hub_filter_logger: "@App\\Service\\HubFilterLogger"
# hub distributor
App\Service\HubDistributor:
arguments:
$redis: "@App\\Service\\RedisClientProvider"
$hub_jo_key: "%env(HUB_JO_KEY)%"
# hub filter logger
App\Service\HubFilterLogger:
arguments:
$em: "@doctrine.orm.entity_manager"

View file

@ -0,0 +1,39 @@
<?php
namespace App\Command;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use App\Service\RedisClientProvider;
class ResetHubJoCountCommand extends Command
{
protected $redis;
public function __construct(RedisClientProvider $redis)
{
$this->redis = $redis->getRedisClient();
parent::__construct();
}
protected function configure()
{
$this->setName('hub:jo:reset')
->setDescription('Reset hub\'s job order count')
->setHelp('Reset hub\'s job order count');
}
protected function execute(InputInterface $input, OutputInterface $output)
{
$key = 'hub_jo_count';
$this->redis->del($key);
return 0;
}
}

View file

@ -28,6 +28,7 @@ use App\Ramcar\TradeInType;
use App\Ramcar\JOEventType;
use App\Ramcar\AdvanceOrderSlot;
use App\Ramcar\AutoAssignStatus;
use App\Ramcar\HubCriteria;
use App\Service\InvoiceGeneratorInterface;
use App\Service\RisingTideGateway;
@ -37,6 +38,9 @@ use App\Service\RiderTracker;
use App\Service\MapTools;
use App\Service\InventoryManager;
use App\Service\RiderAssignmentHandlerInterface;
use App\Service\HubSelector;
use App\Service\HubDistributor;
use App\Service\HubFilterLogger;
use App\Entity\MobileSession;
use App\Entity\Customer;
@ -844,7 +848,8 @@ class APIController extends Controller implements LoggedController
public function requestJobOrder(Request $req, InvoiceGeneratorInterface $ic, GeofenceTracker $geo,
MapTools $map_tools, InventoryManager $im, MQTTClient $mclient,
RiderAssignmentHandlerInterface $rah)
RiderAssignmentHandlerInterface $rah, HubSelector $hub_select,
HubDistributor $hub_dist, HubFilterLogger $hub_filter_logger)
{
// check required parameters and api key
$required_params = [
@ -1009,49 +1014,69 @@ class APIController extends Controller implements LoggedController
$invoice = $ic->generateInvoice($icrit);
$jo->setInvoice($invoice);
// assign hub and rider
if (($jo->getServiceType() == ServiceType::BATTERY_REPLACEMENT_NEW) ||
($jo->getServicetype() == ServiceType::BATTERY_REPLACEMENT_WARRANTY))
{
// get nearest hub
// $nearest_hub = $this->findNearestHubWithInventory($jo, $batt, $em, $map_tools, $im);
$nearest_hub = $this->findNearestHub($jo, $em, $map_tools);
}
else
{
$nearest_hub = $this->findNearestHub($jo, $em, $map_tools);
}
if (!empty($nearest_hub))
// TODO: set this properly, since the other flags
// are on default values
$hub_criteria = new HubCriteria();
$hub_criteria->setPoint($jo->getCoordinates())
->setJoType($jo->getServiceType());
// add battery to items
$sku = $batt->getSAPCode();
if (!empty($sku))
$hub_criteria->addItem($batt->getSAPCode(), 1);
// find nearest hubs
$nearest_hubs = $hub_select->find($hub_criteria);
if (!empty($nearest_hubs))
{
// go through the hub list, find the nearest hub
// with an available rider
//error_log('found nearest hub ' . $nearest_hub->getID());
// assign rider
$available_riders = $nearest_hub->getAvailableRiders();
if (count($available_riders) > 0)
foreach ($nearest_hubs as $nearest_hub)
{
$assigned_rider = null;
if (count($available_riders) > 1)
$available_riders = $nearest_hub['hub']->getAvailableRiders();
if (count($available_riders) >= 1)
{
// TODO: the setting of riders into an array
// will no longer be necessary when the contents
// of randomizeRider changes
$riders = [];
foreach ($available_riders as $rider)
$assigned_rider = null;
if (count($available_riders) == 1)
{
$riders[] = $rider;
$assigned_rider = $available_riders[0];
}
else
{
// TODO: the setting of riders into an array
// will no longer be necessary when the contents
// of randomizeRider changes
$riders = [];
foreach ($available_riders as $rider)
{
$riders[] = $rider;
}
$assigned_rider = $this->randomizeRider($riders);
}
$assigned_rider = $this->randomizeRider($riders);
$jo->setHub($nearest_hub['hub']);
$jo->setRider($assigned_rider);
$jo->setStatus(JOStatus::ASSIGNED);
$jo->setStatusAutoAssign(AutoAssignStatus::HUB_AND_RIDER_ASSIGNED);
$assigned_rider->setAvailable(false);
// update redis hub_jo_count for hub
$hub_dist->incrementJoCountForHub($nearest_hub['hub']);
// break out of loop
break;
}
else
$assigned_rider = $available_riders[0];
//error_log('found rider ' . $assigned_rider->getID());
$jo->setHub($nearest_hub);
$jo->setRider($assigned_rider);
$jo->setStatus(JOStatus::ASSIGNED);
$assigned_rider->setAvailable(false);
{
// log hub into hub_filter_log
$hub_filter_logger->logFilteredHub($nearest_hub['hub'], 'no_available_rider');
// continue to go through list to find hub with an available rider
}
}
}
@ -2330,7 +2355,8 @@ class APIController extends Controller implements LoggedController
public function newRequestJobOrder(Request $req, InvoiceGeneratorInterface $ic, GeofenceTracker $geo,
MapTools $map_tools, InventoryManager $im, MQTTClient $mclient,
RiderAssignmentHandlerInterface $rah)
RiderAssignmentHandlerInterface $rah, HubSelector $hub_select,
HubDistributor $hub_dist, HubFilterLogger $hub_filter_logger)
{
// check required parameters and api key
$required_params = [
@ -2515,50 +2541,68 @@ class APIController extends Controller implements LoggedController
// check if hub is null
if ($hub == null)
{
// find nearest hub
if (($jo->getServiceType() == ServiceType::BATTERY_REPLACEMENT_NEW) ||
($jo->getServicetype() == ServiceType::BATTERY_REPLACEMENT_WARRANTY))
{
// get nearest hub
// $nearest_hub = $this->findNearestHubWithInventory($jo, $batt, $em, $map_tools, $im);
$nearest_hub = $this->findNearestHub($jo, $em, $map_tools);
}
else
{
$nearest_hub = $this->findNearestHub($jo, $em, $map_tools);
}
// TODO: set this properly, since the other flags
// are on default values
$hub_criteria = new HubCriteria();
$hub_criteria->setPoint($jo->getCoordinates())
->setJoType($jo->getServiceType());
if (!empty($nearest_hub))
// add battery to items
$sku = $batt->getSAPCode();
if (!empty($sku))
$hub_criteria->addItem($batt->getSAPCode(), 1);
// find nearest hubs
$nearest_hubs = $hub_select->find($hub_criteria);
if (!empty($nearest_hubs))
{
// go through the hub list, find the nearest hub
// with an available rider
//error_log('found nearest hub ' . $nearest_hub->getID());
// assign rider
$available_riders = $nearest_hub->getAvailableRiders();
if (count($available_riders) > 0)
foreach ($nearest_hubs as $nearest_hub)
{
$assigned_rider = null;
if (count($available_riders) > 1)
$available_riders = $nearest_hub['hub']->getAvailableRiders();
if (count($available_riders) >= 1)
{
// TODO: the setting of riders into an array
// will no longer be necessary when the contents
// of randomizeRider changes
$riders = [];
foreach ($available_riders as $rider)
$assigned_rider = null;
if (count($available_riders) == 1)
{
$riders[] = $rider;
$assigned_rider = $available_riders[0];
}
else
{
// TODO: the setting of riders into an array
// will no longer be necessary when the contents
// of randomizeRider changes
$riders = [];
foreach ($available_riders as $rider)
{
$riders[] = $rider;
}
$assigned_rider = $this->randomizeRider($riders);
}
$assigned_rider = $this->randomizeRider($riders);
$jo->setHub($nearest_hub['hub']);
$jo->setRider($assigned_rider);
$jo->setStatus(JOStatus::ASSIGNED);
$jo->setStatusAutoAssign(AutoAssignStatus::HUB_AND_RIDER_ASSIGNED);
$assigned_rider->setAvailable(false);
// update redis hub_jo_count for hub
$hub_dist->incrementJoCountForHub($nearest_hub['hub']);
// break out of loop
break;
}
else
$assigned_rider = $available_riders[0];
//error_log('found rider ' . $assigned_rider->getID());
$jo->setHub($nearest_hub);
$jo->setRider($assigned_rider);
$jo->setStatus(JOStatus::ASSIGNED);
$jo->setStatusAutoAssign(AutoAssignStatus::HUB_AND_RIDER_ASSIGNED);
$assigned_rider->setAvailable(false);
{
// log hub into hub_filter_log
$hub_filter_logger->logFilteredHub($nearest_hub['hub'], 'no_available_rider');
// continue to go through list to find hub with an available rider
}
}
}
}
@ -2581,7 +2625,10 @@ class APIController extends Controller implements LoggedController
$jo->setStatusAutoAssign(AutoAssignStatus::HUB_ASSIGNED);
if ($date_schedule != null)
$jo->setDateSchedule($date_schedule);
$jo->setDateSchedule($date_schedule);
// update redis hub_jo_count for hub
$hub_dist->incrementJoCountForHub($hub);
}
$em->persist($jo);

View file

@ -17,9 +17,11 @@ use DateTime;
use Catalyst\MenuBundle\Annotation\Menu;
use App\Service\MapTools;
use App\Service\RiderTracker;
use App\Service\RisingTideGateway;
use App\Service\HubSelector;
use App\Ramcar\HubCriteria;
class HubController extends Controller
{
@ -311,7 +313,7 @@ class HubController extends Controller
$response->send();
}
public function nearest(MapTools $map_tools, Request $req)
public function nearest(HubSelector $hub_selector, Request $req)
{
// get lat / long
$lat = $req->query->get('lat');
@ -319,7 +321,12 @@ class HubController extends Controller
// get nearest hubs according to position
$point = new Point($long, $lat);
$result = $map_tools->getClosestHubs($point, 10, date("H:i:s"));
// set up hub criteria
$hub_criteria = new HubCriteria();
$hub_criteria->setPoint($point);
$hub_selector->find($hub_criteria);
//$result = $map_tools->getClosestHubs($point, 10, date("H:i:s"));
$hubs = [];
foreach ($result as $hub_res)

View file

@ -23,6 +23,7 @@ use App\Service\MapTools;
use App\Service\MQTTClient;
use App\Service\APNSClient;
use App\Service\InventoryManager;
use App\Service\HubSelector;
use App\Service\RiderTracker;
use App\Service\MotivConnector;
@ -315,13 +316,13 @@ class JobOrderController extends Controller
/**
* @Menu(selected="jo_proc")
*/
public function processingForm(MapTools $map_tools, $id, JobOrderHandlerInterface $jo_handler, GISManagerInterface $gis, MotivConnector $motiv)
public function processingForm(HubSelector $hub_selector, $id, JobOrderHandlerInterface $jo_handler, GISManagerInterface $gis, MotivConnector $motiv)
{
$this->denyAccessUnlessGranted('jo_proc.list', null, 'No access.');
try
{
$params = $jo_handler->initializeProcessingForm($id, $map_tools, $motiv);
$params = $jo_handler->initializeProcessingForm($id, $hub_selector, $motiv);
}
catch (AccessDeniedHttpException $e)
{
@ -504,14 +505,14 @@ class JobOrderController extends Controller
/**
* @Menu(selected="jo_open")
*/
public function openHubForm(MapTools $map_tools, $id, JobOrderHandlerInterface $jo_handler,
public function openHubForm(HubSelector $hub_selector, $id, JobOrderHandlerInterface $jo_handler,
GISManagerInterface $gis)
{
$this->denyAccessUnlessGranted('jo_open.list', null, 'No access.');
try
{
$params = $jo_handler->initializeHubForm($id, $map_tools);
$params = $jo_handler->initializeHubForm($id, $hub_selector);
}
catch (NotFoundHttpException $e)
{
@ -1204,6 +1205,7 @@ class JobOrderController extends Controller
]);
}
// this is uncalled or does not display in admin panel
/**
* @Menu(selected="jo_autoassign")
*/
@ -1223,6 +1225,7 @@ class JobOrderController extends Controller
return $this->render($template, $params);
}
// this is uncalled or does not display in admin panel
public function autoAssignSubmit(Request $req, JobOrderHandlerInterface $jo_handler,
EntityManagerInterface $em, MapTools $map_tools,
InventoryManager $im)

View file

@ -0,0 +1,83 @@
<?php
namespace App\Entity;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validator\Constraints as Assert;
use App\Entity\Hub;
use DateTime;
/**
* @ORM\Entity
* @ORM\Table(name="hub_filter_log")
*/
class HubFilterLog
{
// unique id
/**
* @ORM\Id
* @ORM\Column(type="integer")
* @ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
// date created
/**
* @ORM\Column(type="datetime")
*/
protected $date_create;
// hub that was not included in results
/**
* @ORM\ManyToOne(targetEntity="Hub", inversedBy="hub_filtered")
* @ORM\JoinColumn(name="hub_filtered_id", referencedColumnName="id", nullable=true)
*/
protected $hub;
// filter that eliminated hub
/**
* @ORM\Column(type="string", length=80)
* @Assert\NotBlank()
*/
protected $filter_type_id;
public function __construct()
{
$this->date_create = new DateTime();
}
public function getID()
{
return $this->id;
}
public function getDateCreate()
{
return $this->date_create;
}
public function setHub(Hub $hub)
{
$this->hub = $hub;
return $this;
}
public function getHub()
{
return $this->hub;
}
public function setFilterTypeId($filter_type_id)
{
$this->filter_type_id = $filter_type_id;
return $this;
}
public function getFilterTypeId()
{
return $this->filter_type_id;
}
}

108
src/Ramcar/HubCriteria.php Normal file
View file

@ -0,0 +1,108 @@
<?php
namespace App\Ramcar;
use CrEOF\Spatial\PHP\Types\Geometry\Point;
use DateTime;
class HubCriteria
{
protected $point; // coordinates of source
protected $limit_results; // number of results to return
protected $limit_distance; // distance limit for search in km
protected $flag_inventory_check; // flag if we need to check for inventory
protected $jo_type; // jo service needed
protected $date_time; // date and time to check if hub is open or not
protected $items; // array of items: items[sku] = quantity to check for
public function __construct()
{
// TODO: default values might still change
$this->limit_results = 10;
$this->limit_distance = 500;
$this->jo_type = '';
$this->date_time = null;
$this->has_inventory = false;
$this->items = [];
}
public function setPoint(Point $point)
{
$this->point = $point;
return $this;
}
public function getPoint()
{
return $this->point;
}
public function setLimitResults($limit_results)
{
$this->limit_results = $limit_results;
return $this;
}
public function getLimitResults()
{
return $this->limit_results;
}
public function setLimitDistance($limit_distance)
{
$this->limit_distance = $limit_distance;
return $this;
}
public function getLimitDistance()
{
return $this->limit_distance;
}
public function setInventoryCheck($flag_inventory_check = true)
{
$this->flag_inventory_check = $flag_inventory_check;
return $this;
}
public function hasInventoryCheck()
{
return $this->flag_inventory_check;
}
public function setJoType($jo_type)
{
// TODO: validate the jo type
$this->jo_type = $jo_type;
return $this;
}
public function getJoType()
{
return $this->jo_type;
}
public function setDateTime(DateTime $date_time)
{
$this->date_time = $date_time;
return $this;
}
public function getDateTime()
{
return $this->date_time;
}
public function addItem($sku, $quantity)
{
// at this point, sku is assumed to be a valid item
$this->items[$sku] = $quantity;
return $this;
}
public function getItems()
{
return $this->items;
}
}

View file

@ -0,0 +1,109 @@
<?php
namespace App\Service;
use App\Service\RedisClientProvider;
use App\Entity\Hub;
class HubDistributor
{
protected $redis;
protected $hub_jo_key;
public function __construct(RedisClientProvider $redis, $hub_jo_key)
{
$this->redis = $redis->getRedisClient();
$this->hub_jo_key = $hub_jo_key;
}
public function incrementJoCountForHub(Hub $hub)
{
$key = $hub->getID();
// get current count
$jo_count = $this->redis->hget($this->hub_jo_key, $key);
if ($jo_count == false)
{
// hub not in hash
// add hub to hash
// set to 1 since this is first jo for hub
$this->redis->hset($this->hub_jo_key, $key, 1);
}
else
{
// hub exist in hash
// add to count
$this->redis->hset($this->hub_jo_key, $key, $jo_count + 1);
}
}
public function decrementJoCountForHub(Hub $hub)
{
$key = $hub->getID();
// get current count
$jo_count = $this->redis->hget($this->hub_jo_key, $key);
if ($jo_count)
{
// hub exist in hash
// decrement count
$this->redis->hset($this->hub_jo_key, $key, $jo_count - 1);
}
}
public function arrangeHubs($hubs)
{
if (count($hubs) == 1)
return $hubs;
$arranged_hubs = [];
foreach ($hubs as $hub_data)
{
$hub = $hub_data['hub'];
// need the id of hub
$key = $hub->getID();
// get jo count of hub
$hub_jo_count = $this->redis->hget($this->hub_jo_key, $key);
// check if hub is in hash. if not, hub has no jobs
// but should still be added to results
if ($hub_jo_count != null)
{
$arranged_hubs[] = [
'hub' => $hub,
'db_distance' => $hub_data['db_distance'],
'distance' => $hub_data['distance'],
'duration' => $hub_data['duration'],
'jo_count' => $hub_jo_count,
];
}
else
{
$arranged_hubs[] = [
'hub' => $hub,
'db_distance' => $hub_data['db_distance'],
'distance' => $hub_data['distance'],
'duration' => $hub_data['duration'],
'jo_count' => 0,
];
}
}
usort($arranged_hubs, function($a, $b) {
if ($a['jo_count'] == $b['jo_count'])
return 0;
if ($a['jo_count'] < $b['jo_count'])
return -1;
else
return 1;
});
//error_log('arranged hubs ' . json_encode($arranged_hubs));
return $arranged_hubs;
}
}

View file

@ -0,0 +1,29 @@
<?php
namespace App\Service;
use Doctrine\ORM\EntityManagerInterface;
use App\Entity\Hub;
use App\Entity\HubFilterLog;
class HubFilterLogger
{
protected $em;
public function __construct(EntityManagerInterface $em)
{
$this->em = $em;
}
public function logFilteredHub(Hub $hub, $filter_type)
{
$hub_filter_log = new HubFilterLog();
$hub_filter_log->setHub($hub)
->setFilterTypeId($filter_type);
$this->em->persist($hub_filter_log);
$this->em->flush();
}
}

335
src/Service/HubSelector.php Normal file
View file

@ -0,0 +1,335 @@
<?php
namespace App\Service;
use Doctrine\ORM\EntityManagerInterface;
use CrEOF\Spatial\PHP\Types\Geometry\Point;
use App\Entity\Hub;
use App\Service\HubDistributor;
use App\Service\InventoryManager;
use App\Service\HubFilterLogger;
use App\Ramcar\HubCriteria;
use App\Ramcar\ServiceType;
class HubSelector
{
protected $em;
protected $im;
protected $hub_distributor;
protected $hub_filter_logger;
public function __construct(EntityManagerInterface $em, InventoryManager $im,
HubDistributor $hub_distributor, HubFilterLogger $hub_filter_logger)
{
$this->em = $em;
$this->im = $im;
$this->hub_distributor = $hub_distributor;
$this->hub_filter_logger = $hub_filter_logger;
}
public function find(HubCriteria $criteria)
{
$point = $criteria->getPoint();
$limit_results = $criteria->getLimitResults();
$limit_distance = $criteria->getLimitDistance();
$jo_type = $criteria->getJoType();
$flag_inventory_check = $criteria->hasInventoryCheck();
$items = $criteria->getItems();
$date_time = $criteria->getDateTime();
$results = [];
// get all the hubs within distance
$filtered_hubs = $this->getClosestHubs($point, $limit_distance);
//error_log('closest hubs ' . json_encode($filtered_hubs));
// filter the first hub results for date and opening times
$hubs_date_time = $this->filterHubsByDateAndTime($filtered_hubs, $date_time);
$filtered_hubs = $hubs_date_time;
// filter jo types
$hubs_jo_type = $this->filterHubsByJoType($filtered_hubs, $jo_type);
$filtered_hubs = $hubs_jo_type;
// inventory filter
$hubs_inventory = $this->filterHubsByInventory($filtered_hubs, $flag_inventory_check,
$jo_type, $items);
$filtered_hubs = $hubs_inventory;
// round robin filter
$hubs_round_robin = $this->filterHubsByRoundRobin($filtered_hubs);
$filtered_hubs = $hubs_round_robin;
//error_log(json_encode($filtered_hubs));
// max results filter
$hubs_max_result = $this->filterHubsByMaxResults($filtered_hubs, $limit_results);
$filtered_hubs = $hubs_max_result;
$results = $filtered_hubs;
error_log(json_encode($results));
return $results;
}
protected function filterHubsByRoundRobin($hubs)
{
if (empty($hubs))
return $hubs;
$results = [];
// call hub distributor service
$arranged_hubs = $this->hub_distributor->arrangeHubs($hubs);
$results = $arranged_hubs;
return $results;
}
protected function filterHubsByMaxResults($hubs, $limit_result)
{
if (empty($hubs))
return $hubs;
if (empty($limit_result))
return $hubs;
$results = [];
for ($i = 0; $i < count($hubs); $i++)
{
if ($i < $limit_result)
$results[] = $hubs[$i];
else
$this->hub_filter_logger->logFilteredHub($hubs[$i]['hub'], 'max_results');
}
return $results;
}
protected function filterHubsByJoType($hubs, $jo_type)
{
if (empty($hubs))
return $hubs;
if (empty($jo_type))
return $hubs;
$results = [];
foreach ($hubs as $hub_data)
{
$hub = $hub_data['hub'];
// TODO: for now, have this return true
$has_jo_type = true;
// check if hub offers the jo_type
// TODO: add service to hub
if ($has_jo_type)
$results[] = [
'hub' => $hub,
'db_distance' => $hub_data['db_distance'],
'distance' => $hub_data['distance'],
'duration' => $hub_data['duration'],
];
else
$this->hub_filter_logger->logFilteredHub($hub, 'job_order_type');
}
return $results;
}
protected function filterHubsByDateAndTime($hubs, $date_time)
{
if (empty($hubs))
return $hubs;
if ($date_time == null)
return $hubs;
$results = [];
foreach ($hubs as $hub_data)
{
// go through each hub's opening times to check if hub is open
// for the specified time
// get hub opening and closing times
// TODO: maybe in the future, might also have to check if hub
// is open/available on date/day
$hub = $hub_data['hub'];
$time_open = $hub->getTimeOpen()->format("H:i:s");
$time_close = $hub->getTimeClose()->format("H:i:s");
$filter_time = $date_time->format("H:i:s");
if (($filter_time >= $time_open) &&
($filter_time <= $time_close))
{
$results[] = [
'hub' => $hub,
'db_distance' => $hub_data['db_distance'],
'distance' => $hub_data['distance'],
'duration' => $hub_data['duration'],
];
}
else
$this->hub_filter_logger->logFilteredHub($hub, 'date_and_time');
}
return $results;
}
protected function filterHubsByInventory($hubs, $flag_inventory_check, $jo_type, $items)
{
if (empty($hubs))
return $hubs;
if (!$flag_inventory_check)
return $hubs;
$results = [];
if ($flag_inventory_check)
{
foreach ($hubs as $hub_data)
{
$hub = $hub_data['hub'];
if ($jo_type == ServiceType::BATTERY_REPLACEMENT_NEW)
{
// call inventory
$has_items = $this->checkInventory($items, $hub);
if ($has_items)
$results[] = [
'hub' => $hub,
'db_distance' => $hub_data['db_distance'],
'distance' => $hub_data['distance'],
'duration' => $hub_data['duration'],
];
else
$this->hub_filter_logger->logFilteredHub($hub, 'inventory');
}
if ($jo_type == ServiceType::BATTERY_REPLACEMENT_WARRANTY)
{
// call inventory
$has_items = $this->checkInventory($items, $hub);
if ($has_items)
$results[] = [
'hub' => $hub,
'db_distance' => $hub_data['db_distance'],
'distance' => $hub_data['distance'],
'duration' => $hub_data['duration'],
];
else
$this->hub_filter_logger->logFilteredHub($hub, 'inventory');
}
}
}
return $results;
}
protected function getClosestHubs(Point $point, $limit_distance)
{
// get closest hubs based on st_distance function from db
$query_string = 'SELECT h, st_distance(h.coordinates, point(:lng, :lat)) as dist FROM App\Entity\Hub h WHERE h.status_open = true ORDER BY dist';
$query = $this->em->createQuery($query_string)
->setParameter('lat', $point->getLatitude())
->setParameter('lng', $point->getLongitude());
// error_log($query->getSql());
$result = $query->getResult();
$hubs = [];
$hubs_data = [];
foreach ($result as $row)
{
$hubs[] = $row[0];
// get coordinates of hub
$hub_coordinates = $row[0]->getCoordinates();
$cust_lat = $point->getLatitude();
$cust_lng = $point->getLongitude();
$hub_lat = $hub_coordinates->getLatitude();
$hub_lng = $hub_coordinates->getLongitude();
// get distance in kilometers from customer point to hub point
$dist = $this->distance($cust_lat, $cust_lng, $hub_lat, $hub_lng);
if ($dist < $limit_distance)
{
$hubs_data[] = [
'hub' => $row[0],
'db_distance' => $row['dist'],
'distance' => $dist,
'duration' => 0,
];
}
else
{
$this->hub_filter_logger->logFilteredHub($row[0], 'distance');
}
}
return $hubs_data;
}
protected function checkInventory($items, $hub)
{
// check if hub has all items
$skus = [];
$branch_codes[] = $hub->getBranchCode();
$result = false;
foreach ($items as $key=> $value)
{
// add sap code of item/battery into array since
// getBranchesInventory takes in an array of hubs/branches
// and an array of skus
// $items as format: $items[sku] = quantity
$skus[] = $key;
}
// call InventoryManager's getBranchesInventory to check if hub has all items
$branches_with_items = $this->im->getBranchesInventory($branch_codes, $skus);
if (!empty($branches_with_items))
{
// check if branch has enough quantity for item
foreach ($branches_with_items as $branch)
{
// get quantity from call
$qty_available = $branch['Quantity'];
// get the quantity request
$sku_requested = $branch['SapCode'];
$qty_requested = $items[$sku_requested];
if ($qty_available >= $qty_requested)
$result = true;
}
}
// return true or false
return $result;
}
// convert db distance to kilometers
protected function distance($lat1, $lon1, $lat2, $lon2)
{
if (($lat1 == $lat2) && ($lon1 == $lon2))
return 0;
$theta = $lon1 - $lon2;
$dist = sin(deg2rad($lat1)) * sin(deg2rad($lat2)) + cos(deg2rad($lat1)) * cos(deg2rad($lat2)) * cos(deg2rad($theta));
$dist = acos($dist);
$dist = rad2deg($dist);
$miles = $dist * 60 * 1.1515;
return round(($miles * 1.609344), 1);
}
}

View file

@ -71,6 +71,7 @@ class InventoryManager
// check if the response is empty
$results = [];
//error_log($response);
if (!empty($response))
$results = json_decode($response, true);

View file

@ -40,6 +40,7 @@ use App\Ramcar\JORejectionReason;
use App\Ramcar\CustomerNotWaitReason;
use App\Ramcar\NoTradeInReason;
use App\Ramcar\WillingToWaitContent;
use App\Ramcar\HubCriteria;
use App\Service\InvoiceGeneratorInterface;
use App\Service\JobOrderHandlerInterface;
@ -49,6 +50,8 @@ use App\Service\MQTTClient;
use App\Service\APNSClient;
use App\Service\MapTools;
use App\Service\RisingTideGateway;
use App\Service\HubSelector;
use App\Service\HubDistributor;
use CrEOF\Spatial\PHP\Types\Geometry\Point;
@ -70,13 +73,15 @@ class ResqJobOrderHandler implements JobOrderHandlerInterface
protected $country_code;
protected $wh;
protected $rt;
protected $hub_dist;
protected $template_hash;
public function __construct(Security $security, EntityManagerInterface $em,
InvoiceGeneratorInterface $ic, ValidatorInterface $validator,
TranslatorInterface $translator, RiderAssignmentHandlerInterface $rah,
string $country_code, WarrantyHandler $wh, RisingTideGateway $rt)
string $country_code, WarrantyHandler $wh, RisingTideGateway $rt,
HubDistributor $hub_dist)
{
$this->em = $em;
$this->ic = $ic;
@ -87,6 +92,7 @@ class ResqJobOrderHandler implements JobOrderHandlerInterface
$this->country_code = $country_code;
$this->wh = $wh;
$this->rt = $rt;
$this->hub_dist = $hub_dist;
$this->loadTemplates();
}
@ -755,6 +761,9 @@ class ResqJobOrderHandler implements JobOrderHandlerInterface
'event' => 'outlet_assign'
];
$mclient->sendEvent($obj, $payload);
// update redis hub jo count
$this->hub_dist->incrementJoCountForHub($hub);
}
return $error_array;
@ -1124,6 +1133,9 @@ class ResqJobOrderHandler implements JobOrderHandlerInterface
$more_reason = $req->request->get('not_wait_notes');
}
// get previously assigned hub, if any
$old_hub = $obj->getHub();
if (empty($error_array))
{
// rider mqtt event
@ -1197,6 +1209,13 @@ class ResqJobOrderHandler implements JobOrderHandlerInterface
'event' => 'outlet_assign'
];
$mclient->sendEvent($obj, $payload);
// update redis hub_jo_count for hub
// decrement old hub's count and increment new hub's count
if ($old_hub != null)
$this->hub_dist->decrementJoCountForHub($old_hub);
if ($hub != null)
$this->hub_dist->incrementJoCountForHub($hub);
}
return $error_array;
@ -1632,6 +1651,7 @@ class ResqJobOrderHandler implements JobOrderHandlerInterface
return $params;
}
// CMB code
public function initializeOneStepEditForm($id, $map_tools)
{
$em = $this->em;
@ -1812,7 +1832,7 @@ class ResqJobOrderHandler implements JobOrderHandlerInterface
}
// initialize dispatch/processing job order form
public function initializeProcessingForm($id, $map_tools, $motiv)
public function initializeProcessingForm($id, HubSelector $hub_selector, $motiv)
{
$em = $this->em;
@ -1879,7 +1899,12 @@ class ResqJobOrderHandler implements JobOrderHandlerInterface
$params['rejection_reasons'] = JORejectionReason::getCollection();
// get closest hubs
$hubs = $map_tools->getClosestHubs($obj->getCoordinates(), 50, date("H:i:s"));
// set hub criteria
$hub_criteria = new HubCriteria();
$hub_criteria->setPoint($obj->getCoordinates())
->setLimitResults(50);
$hubs = $hub_selector->find($hub_criteria);
//$hubs = $map_tools->getClosestHubs($obj->getCoordinates(), 50, date("H:i:s"));
$params['hubs'] = [];
@ -2103,7 +2128,7 @@ class ResqJobOrderHandler implements JobOrderHandlerInterface
}
// initialize hub form
public function initializeHubForm($id, $map_tools)
public function initializeHubForm($id, HubSelector $hub_selector)
{
$em = $this->em;
@ -2128,7 +2153,11 @@ class ResqJobOrderHandler implements JobOrderHandlerInterface
$params['rejection_reasons'] = JORejectionReason::getCollection();
// get closest hubs
$hubs = $map_tools->getClosestHubs($obj->getCoordinates(), 50, date("H:i:s"));
$hub_criteria = new HubCriteria();
$hub_criteria->setPoint($obj->getCoordinates())
->setLimitResults(50);
$hubs = $hub_selector->find($hub_criteria);
//$hubs = $map_tools->getClosestHubs($obj->getCoordinates(), 50, date("H:i:s"));
$params['status_cancelled'] = JOStatus::CANCELLED;
$params['hubs'] = [];

View file

@ -7,6 +7,7 @@ use Symfony\Component\HttpFoundation\Request;
use App\Service\MQTTClient;
use App\Service\APNSClient;
use App\Service\MapTools;
use App\Service\HubSelector;
use App\Entity\JobOrder;
@ -67,7 +68,7 @@ interface JobOrderHandlerInterface
public function initializeAllForm(int $id);
// initialize dispatch/processing job order form
public function initializeProcessingForm(int $id, MapTools $map_tools, $motiv);
public function initializeProcessingForm(int $id, HubSelector $hub_selector, $motiv);
// initialize assign job order form
public function initializeAssignForm(int $id);
@ -76,7 +77,7 @@ interface JobOrderHandlerInterface
public function initializeFulfillmentForm(int $id);
// initialize hub form
public function initializeHubForm(int $id, MapTools $map_tools);
public function initializeHubForm(int $id, HubSelector $hub_selector);
// initialize rider form
public function initializeRiderForm(int $id);