Resolve "Resq - auto-assign with advance order" #1237
9 changed files with 577 additions and 136 deletions
|
|
@ -1,9 +1,8 @@
|
||||||
class DashboardMap {
|
class DashboardMap {
|
||||||
constructor(options, rider_markers, cust_markers, mc_markers) {
|
constructor(options, rider_markers, cust_markers) {
|
||||||
this.options = options;
|
this.options = options;
|
||||||
this.rider_markers = rider_markers;
|
this.rider_markers = rider_markers;
|
||||||
this.cust_markers = cust_markers;
|
this.cust_markers = cust_markers;
|
||||||
this.mobile_cust_markers = mc_markers;
|
|
||||||
|
|
||||||
// layer groups
|
// layer groups
|
||||||
this.layer_groups = {
|
this.layer_groups = {
|
||||||
|
|
@ -81,6 +80,30 @@ class DashboardMap {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
switchJobOrderOrigin(jo_id, jo_origin) {
|
||||||
|
console.log('switching jo ' + jo_id + ' to ' + jo_origin);
|
||||||
|
|
||||||
|
// find the marker
|
||||||
|
if (this.cust_markers.hasOwnProperty(jo_id)) {
|
||||||
|
var marker = this.cust_markers[jo_id];
|
||||||
|
} else {
|
||||||
|
console.log('marker not found for customer');
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// add marker to proper layer group
|
||||||
|
console.log(jo_origin);
|
||||||
|
if (jo_origin == 'mobile') {
|
||||||
|
this.layer_groups.customer.removeLayer(marker);
|
||||||
|
this.layer_groups.mobile_customer.addLayer(marker);
|
||||||
|
marker.setIcon(this.options.icons.mobile_customer);
|
||||||
|
} else {
|
||||||
|
this.layer_groups.mobile_customer.removeLayer(marker);
|
||||||
|
this.layer_groups.customer.addLayer(marker);
|
||||||
|
marker.setIcon(this.options.icons.customer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
putMarker(id, lat, lng, markers, icon, layer_group, popup_url) {
|
putMarker(id, lat, lng, markers, icon, layer_group, popup_url) {
|
||||||
var my = this;
|
var my = this;
|
||||||
// existing marker
|
// existing marker
|
||||||
|
|
@ -106,7 +129,7 @@ class DashboardMap {
|
||||||
$.get(url).done(function(data) {
|
$.get(url).done(function(data) {
|
||||||
popup.setContent(data);
|
popup.setContent(data);
|
||||||
popup.update();
|
popup.update();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -125,7 +148,6 @@ class DashboardMap {
|
||||||
|
|
||||||
removeCustomerMarker(id) {
|
removeCustomerMarker(id) {
|
||||||
console.log('removing customer marker for ' + id);
|
console.log('removing customer marker for ' + id);
|
||||||
var layer_group = this.layer_groups.customer;
|
|
||||||
var markers = this.cust_markers;
|
var markers = this.cust_markers;
|
||||||
|
|
||||||
// no customer marker with that id
|
// no customer marker with that id
|
||||||
|
|
@ -134,7 +156,8 @@ class DashboardMap {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
layer_group.removeLayer(markers[id]);
|
this.layer_groups.customer.removeLayer(markers[id]);
|
||||||
|
this.layer_groups.mobile_customer.removeLayer(markers[id]);
|
||||||
}
|
}
|
||||||
|
|
||||||
putMobileCustomerMarker(id, lat, lng) {
|
putMobileCustomerMarker(id, lat, lng) {
|
||||||
|
|
@ -142,27 +165,13 @@ class DashboardMap {
|
||||||
id,
|
id,
|
||||||
lat,
|
lat,
|
||||||
lng,
|
lng,
|
||||||
this.mobile_cust_markers,
|
this.cust_markers,
|
||||||
this.options.icons.mobile_customer,
|
this.options.icons.mobile_customer,
|
||||||
this.layer_groups.mobile_customer,
|
this.layer_groups.mobile_customer,
|
||||||
this.options.cust_popup_url
|
this.options.cust_popup_url
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
removeMobileCustomerMarker(id) {
|
|
||||||
console.log('removing mobile customer marker for ' + id);
|
|
||||||
var layer_group = this.layer_groups.mobile_customer;
|
|
||||||
var markers = this.mobile_cust_markers;
|
|
||||||
|
|
||||||
// no customer marker with that id
|
|
||||||
if (!markers.hasOwnProperty(id)) {
|
|
||||||
console.log('no such marker to remove');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
layer_group.removeLayer(markers[id]);
|
|
||||||
}
|
|
||||||
|
|
||||||
putRiderAvailableMarker(id, lat, lng) {
|
putRiderAvailableMarker(id, lat, lng) {
|
||||||
this.putMarker(
|
this.putMarker(
|
||||||
id,
|
id,
|
||||||
|
|
@ -215,22 +224,16 @@ class DashboardMap {
|
||||||
// get riders and job orders
|
// get riders and job orders
|
||||||
var riders = response.riders;
|
var riders = response.riders;
|
||||||
var jos = response.jos;
|
var jos = response.jos;
|
||||||
var mobile_jos = response.mobile_jos;
|
|
||||||
|
|
||||||
// job orders
|
// job orders
|
||||||
$.each(jos, function(id, data) {
|
$.each(jos, function(id, data) {
|
||||||
var lat = data.latitude;
|
var lat = data.latitude;
|
||||||
var lng = data.longitude;
|
var lng = data.longitude;
|
||||||
|
|
||||||
my.putCustomerMarker(id, lat, lng);
|
if (data.is_mobile)
|
||||||
});
|
my.putMobileCustomerMarker(id, lat, lng);
|
||||||
|
else
|
||||||
// mobile app job orders
|
my.putCustomerMarker(id, lat, lng);
|
||||||
$.each(mobile_jos, function(id, data) {
|
|
||||||
var lat = data.latitude;
|
|
||||||
var lng = data.longitude;
|
|
||||||
|
|
||||||
my.putMobileCustomerMarker(id, lat, lng);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// riders
|
// riders
|
||||||
|
|
|
||||||
|
|
@ -45,6 +45,10 @@ class MapEventHandler {
|
||||||
// subscribe to jo status
|
// subscribe to jo status
|
||||||
console.log('subscribing to ' + my.options.channels.jo_status);
|
console.log('subscribing to ' + my.options.channels.jo_status);
|
||||||
my.mqtt.subscribe(my.options.channels.jo_status);
|
my.mqtt.subscribe(my.options.channels.jo_status);
|
||||||
|
|
||||||
|
// subscribe to jo origin
|
||||||
|
console.log('subscribing to ' + my.options.channels.jo_origin);
|
||||||
|
my.mqtt.subscribe(my.options.channels.jo_origin);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
@ -134,6 +138,14 @@ class MapEventHandler {
|
||||||
this.dashmap.removeCustomerMarker(id);
|
this.dashmap.removeCustomerMarker(id);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
|
case "origin":
|
||||||
|
console.log("got origin for jo " + payload);
|
||||||
|
if (payload == 'mobile_app')
|
||||||
|
{
|
||||||
|
this.dashmap.switchJobOrderOrigin(chan_split[1], 'mobile');
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -989,117 +989,209 @@ class APIController extends Controller implements LoggedController
|
||||||
$invoice = $ic->generateInvoice($icrit);
|
$invoice = $ic->generateInvoice($icrit);
|
||||||
$jo->setInvoice($invoice);
|
$jo->setInvoice($invoice);
|
||||||
|
|
||||||
// assign hub and rider
|
// check if advance order
|
||||||
if (($jo->getServiceType() == ServiceType::BATTERY_REPLACEMENT_NEW) ||
|
// check for time when request came in
|
||||||
($jo->getServicetype() == ServiceType::BATTERY_REPLACEMENT_WARRANTY))
|
$request_time_in_int = time();
|
||||||
|
$start = '17:00';
|
||||||
|
$end = '08:00';
|
||||||
|
|
||||||
|
$start_time = strtotime($start);
|
||||||
|
$end_time = strtotime($end);
|
||||||
|
|
||||||
|
if (($request_time_in_int > $start_time) ||
|
||||||
|
(($request_time_in_int < $start_time) && ($request_time_in_int < $end_time)))
|
||||||
{
|
{
|
||||||
// get nearest hub
|
// advance order
|
||||||
// $nearest_hub = $this->findNearestHubWithInventory($jo, $batt, $em, $map_tools, $im);
|
// assign hub and rider
|
||||||
$nearest_hub = $this->findNearestHub($jo, $em, $map_tools);
|
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);
|
||||||
|
// TODO: when the inventory manager kicks in, create new function that finds the
|
||||||
|
// the nearest hub with inventory and rider slot
|
||||||
|
// convert to DateTime
|
||||||
|
$nearest_hub = $this->findAdvanceNearestHub($jo, $request_time_in_int, $em, $map_tools);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
$nearest_hub = $this->findAdvanceNearestHub($jo, $request_time_in_int, $em, $map_tools);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!empty($nearest_hub))
|
||||||
|
{
|
||||||
|
$jo->setHub($nearest_hub);
|
||||||
|
$jo->setStatus(JOStatus::ASSIGNED);
|
||||||
|
}
|
||||||
|
|
||||||
|
$em->persist($jo);
|
||||||
|
$em->persist($invoice);
|
||||||
|
|
||||||
|
// add event log for JO
|
||||||
|
$event = new JOEvent();
|
||||||
|
$event->setDateHappen(new DateTime())
|
||||||
|
->setTypeID(JOEventType::CREATE)
|
||||||
|
->setJobOrder($jo);
|
||||||
|
$em->persist($event);
|
||||||
|
|
||||||
|
// check JO status
|
||||||
|
if ($jo->getStatus() == JOStatus::ASSIGNED)
|
||||||
|
{
|
||||||
|
// add event logs for hub and rider assignments
|
||||||
|
$hub_assign_event = new JOEvent();
|
||||||
|
$hub_assign_event->setDateHappen(new DateTime())
|
||||||
|
->setTypeID(JOEventType::HUB_ASSIGN)
|
||||||
|
->setJobOrder($jo);
|
||||||
|
|
||||||
|
$em->persist($hub_assign_event);
|
||||||
|
}
|
||||||
|
|
||||||
|
$em->flush();
|
||||||
|
|
||||||
|
// make invoice json data
|
||||||
|
$invoice_data = [
|
||||||
|
'total_price' => $invoice->getTotalPrice(),
|
||||||
|
'vat_ex_price' => $invoice->getVATExclusivePrice(),
|
||||||
|
'vat' => $invoice->getVAT(),
|
||||||
|
'discount' => $invoice->getDiscount(),
|
||||||
|
'trade_in' => $invoice->getTradeIn(),
|
||||||
|
];
|
||||||
|
$items = $invoice->getItems();
|
||||||
|
$items_data = [];
|
||||||
|
foreach ($items as $item)
|
||||||
|
{
|
||||||
|
$items_data[] = [
|
||||||
|
'title' => $item->getTitle(),
|
||||||
|
'qty' => $item->getQuantity() + 0,
|
||||||
|
'price' => $item->getPrice() + 0.0,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
$invoice_data['items'] = $items_data;
|
||||||
|
|
||||||
|
// make job order data
|
||||||
|
$data = [
|
||||||
|
'jo_id' => $jo->getID(),
|
||||||
|
'invoice' => $invoice_data
|
||||||
|
];
|
||||||
|
|
||||||
|
// set data
|
||||||
|
$res->setData($data);
|
||||||
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
$nearest_hub = $this->findNearestHub($jo, $em, $map_tools);
|
// assign hub and rider
|
||||||
}
|
if (($jo->getServiceType() == ServiceType::BATTERY_REPLACEMENT_NEW) ||
|
||||||
|
($jo->getServicetype() == ServiceType::BATTERY_REPLACEMENT_WARRANTY))
|
||||||
if (!empty($nearest_hub))
|
|
||||||
{
|
|
||||||
// assign rider
|
|
||||||
$available_riders = $nearest_hub->getAvailableRiders();
|
|
||||||
if (count($available_riders) > 0)
|
|
||||||
{
|
{
|
||||||
$assigned_rider = null;
|
// get nearest hub
|
||||||
if (count($available_riders) > 1)
|
// $nearest_hub = $this->findNearestHubWithInventory($jo, $batt, $em, $map_tools, $im);
|
||||||
{
|
$nearest_hub = $this->findNearestHub($jo, $em, $map_tools);
|
||||||
// TODO: the setting of riders into an array
|
}
|
||||||
// will no longer be necessary when the contents
|
else
|
||||||
// of randomizeRider changes
|
{
|
||||||
$riders = [];
|
$nearest_hub = $this->findNearestHub($jo, $em, $map_tools);
|
||||||
foreach ($available_riders as $rider)
|
|
||||||
{
|
|
||||||
$riders[] = $rider;
|
|
||||||
}
|
|
||||||
|
|
||||||
$assigned_rider = $this->randomizeRider($riders);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
$assigned_rider = $available_riders[0];
|
|
||||||
|
|
||||||
$jo->setHub($nearest_hub);
|
|
||||||
$jo->setRider($assigned_rider);
|
|
||||||
$jo->setStatus(JOStatus::ASSIGNED);
|
|
||||||
|
|
||||||
$assigned_rider->setAvailable(false);
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
$em->persist($jo);
|
if (!empty($nearest_hub))
|
||||||
$em->persist($invoice);
|
{
|
||||||
|
// assign rider
|
||||||
|
$available_riders = $nearest_hub->getAvailableRiders();
|
||||||
|
if (count($available_riders) > 0)
|
||||||
|
{
|
||||||
|
$assigned_rider = null;
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
$riders[] = $rider;
|
||||||
|
}
|
||||||
|
|
||||||
// add event log for JO
|
$assigned_rider = $this->randomizeRider($riders);
|
||||||
$event = new JOEvent();
|
}
|
||||||
$event->setDateHappen(new DateTime())
|
else
|
||||||
->setTypeID(JOEventType::CREATE)
|
$assigned_rider = $available_riders[0];
|
||||||
->setJobOrder($jo);
|
|
||||||
$em->persist($event);
|
$jo->setHub($nearest_hub);
|
||||||
|
$jo->setRider($assigned_rider);
|
||||||
|
$jo->setStatus(JOStatus::ASSIGNED);
|
||||||
|
|
||||||
// check JO status
|
$assigned_rider->setAvailable(false);
|
||||||
if ($jo->getStatus() == JOStatus::ASSIGNED)
|
}
|
||||||
{
|
}
|
||||||
// add event logs for hub and rider assignments
|
|
||||||
$hub_assign_event = new JOEvent();
|
$em->persist($jo);
|
||||||
$hub_assign_event->setDateHappen(new DateTime())
|
$em->persist($invoice);
|
||||||
->setTypeID(JOEventType::HUB_ASSIGN)
|
|
||||||
|
// add event log for JO
|
||||||
|
$event = new JOEvent();
|
||||||
|
$event->setDateHappen(new DateTime())
|
||||||
|
->setTypeID(JOEventType::CREATE)
|
||||||
->setJobOrder($jo);
|
->setJobOrder($jo);
|
||||||
|
$em->persist($event);
|
||||||
|
|
||||||
$em->persist($hub_assign_event);
|
// check JO status
|
||||||
|
if ($jo->getStatus() == JOStatus::ASSIGNED)
|
||||||
|
{
|
||||||
|
// add event logs for hub and rider assignments
|
||||||
|
$hub_assign_event = new JOEvent();
|
||||||
|
$hub_assign_event->setDateHappen(new DateTime())
|
||||||
|
->setTypeID(JOEventType::HUB_ASSIGN)
|
||||||
|
->setJobOrder($jo);
|
||||||
|
|
||||||
$rider_assign_event = new JOEvent();
|
$em->persist($hub_assign_event);
|
||||||
$rider_assign_event->setDateHappen(new DateTime())
|
|
||||||
->setTypeID(JOEventType::RIDER_ASSIGN)
|
|
||||||
->setJobOrder($jo);
|
|
||||||
|
|
||||||
$em->persist($rider_assign_event);
|
$rider_assign_event = new JOEvent();
|
||||||
|
$rider_assign_event->setDateHappen(new DateTime())
|
||||||
|
->setTypeID(JOEventType::RIDER_ASSIGN)
|
||||||
|
->setJobOrder($jo);
|
||||||
|
|
||||||
// user mqtt event
|
$em->persist($rider_assign_event);
|
||||||
$payload = [
|
|
||||||
'event' => 'outlet_assign'
|
// user mqtt event
|
||||||
|
$payload = [
|
||||||
|
'event' => 'outlet_assign'
|
||||||
|
];
|
||||||
|
$mclient->sendEvent($jo, $payload);
|
||||||
|
|
||||||
|
$rah->assignJobOrder($jo, $jo->getRider());
|
||||||
|
}
|
||||||
|
|
||||||
|
$em->flush();
|
||||||
|
|
||||||
|
// make invoice json data
|
||||||
|
$invoice_data = [
|
||||||
|
'total_price' => $invoice->getTotalPrice(),
|
||||||
|
'vat_ex_price' => $invoice->getVATExclusivePrice(),
|
||||||
|
'vat' => $invoice->getVAT(),
|
||||||
|
'discount' => $invoice->getDiscount(),
|
||||||
|
'trade_in' => $invoice->getTradeIn(),
|
||||||
];
|
];
|
||||||
$mclient->sendEvent($jo, $payload);
|
$items = $invoice->getItems();
|
||||||
|
$items_data = [];
|
||||||
|
foreach ($items as $item)
|
||||||
|
{
|
||||||
|
$items_data[] = [
|
||||||
|
'title' => $item->getTitle(),
|
||||||
|
'qty' => $item->getQuantity() + 0,
|
||||||
|
'price' => $item->getPrice() + 0.0,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
$invoice_data['items'] = $items_data;
|
||||||
|
|
||||||
$rah->assignJobOrder($jo, $jo->getRider());
|
// make job order data
|
||||||
}
|
$data = [
|
||||||
|
'jo_id' => $jo->getID(),
|
||||||
$em->flush();
|
'invoice' => $invoice_data
|
||||||
|
|
||||||
// make invoice json data
|
|
||||||
$invoice_data = [
|
|
||||||
'total_price' => $invoice->getTotalPrice(),
|
|
||||||
'vat_ex_price' => $invoice->getVATExclusivePrice(),
|
|
||||||
'vat' => $invoice->getVAT(),
|
|
||||||
'discount' => $invoice->getDiscount(),
|
|
||||||
'trade_in' => $invoice->getTradeIn(),
|
|
||||||
];
|
|
||||||
$items = $invoice->getItems();
|
|
||||||
$items_data = [];
|
|
||||||
foreach ($items as $item)
|
|
||||||
{
|
|
||||||
$items_data[] = [
|
|
||||||
'title' => $item->getTitle(),
|
|
||||||
'qty' => $item->getQuantity() + 0,
|
|
||||||
'price' => $item->getPrice() + 0.0,
|
|
||||||
];
|
];
|
||||||
|
|
||||||
|
// set data
|
||||||
|
$res->setData($data);
|
||||||
}
|
}
|
||||||
$invoice_data['items'] = $items_data;
|
|
||||||
|
|
||||||
// make job order data
|
|
||||||
$data = [
|
|
||||||
'jo_id' => $jo->getID(),
|
|
||||||
'invoice' => $invoice_data
|
|
||||||
];
|
|
||||||
|
|
||||||
// set data
|
|
||||||
$res->setData($data);
|
|
||||||
|
|
||||||
return $res->getReturnResponse();
|
return $res->getReturnResponse();
|
||||||
}
|
}
|
||||||
|
|
@ -2464,4 +2556,306 @@ class APIController extends Controller implements LoggedController
|
||||||
return $selected_rider;
|
return $selected_rider;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected function findAdvanceNearestHub($jo, $request_time, EntityManagerInterface $em, MapTools $map_tools)
|
||||||
|
{
|
||||||
|
// get the nearest 10 hubs
|
||||||
|
$selected_hub = null;
|
||||||
|
$hubs = $map_tools->getClosestOpenHubs($jo->getCoordinates(), 10);
|
||||||
|
|
||||||
|
$nearest_hubs_with_distance = [];
|
||||||
|
$nearest_branch_codes = [];
|
||||||
|
foreach ($hubs as $hub)
|
||||||
|
{
|
||||||
|
$nearest_hubs_with_distance[] = $hub;
|
||||||
|
//if (!empty($hub['hub']->getBranchCode()))
|
||||||
|
// $nearest_branch_codes[] = $hub['hub']->getBranchCode();
|
||||||
|
}
|
||||||
|
|
||||||
|
// check if nearest hubs have branch codes
|
||||||
|
//if (count($nearest_branch_codes) == 0)
|
||||||
|
// return $selected_hub;
|
||||||
|
|
||||||
|
// assume all 10 have stock
|
||||||
|
// find the nearest hub with available riders
|
||||||
|
$nearest = null;
|
||||||
|
$slot_found = false;
|
||||||
|
foreach ($nearest_hubs_with_distance as $nhd)
|
||||||
|
{
|
||||||
|
if (empty($nearest))
|
||||||
|
$nearest = $nhd;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if ($nhd['distance'] < $nearest['distance'])
|
||||||
|
$nearest = $nhd;
|
||||||
|
}
|
||||||
|
|
||||||
|
$result = $this->findRiderSlots($jo, $nearest['hub'], $request_time, $em);
|
||||||
|
|
||||||
|
if ($result != null)
|
||||||
|
$slot_found = $result['slot_found'];
|
||||||
|
else
|
||||||
|
$nearest = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($slot_found && $nearest != null)
|
||||||
|
{
|
||||||
|
$result = $this->findRiderSlots($jo, $nearest['hub'], $request_time, $em);
|
||||||
|
|
||||||
|
if ($result != null)
|
||||||
|
{
|
||||||
|
$jo_date_schedule = $result['date_schedule'];
|
||||||
|
|
||||||
|
$jo->setAdvanceOrder(true);
|
||||||
|
$jo->setDateSchedule($jo_date_schedule);
|
||||||
|
|
||||||
|
$selected_hub = $nearest['hub'];
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// uncomment this snippet when inventory check becomes active
|
||||||
|
// get battery sku
|
||||||
|
/*
|
||||||
|
if ($batt != null)
|
||||||
|
{
|
||||||
|
$skus[] = $batt->getSAPCode();
|
||||||
|
|
||||||
|
// api call to check inventory
|
||||||
|
// pass the list of branch codes of nearest hubs and the skus
|
||||||
|
// go through returned list of branch codes
|
||||||
|
// bypass inventory check for now
|
||||||
|
// $hubs_with_inventory = $im->getBranchesInventory($nearest_branch_codes, $skus);
|
||||||
|
if (!empty($hubs_with_inventory))
|
||||||
|
{
|
||||||
|
$nearest = [];
|
||||||
|
$flag_hub_found = false;
|
||||||
|
foreach ($hubs_with_inventory as $hub_with_inventory)
|
||||||
|
{
|
||||||
|
// find hub according to branch code
|
||||||
|
$found_hub = $em->getRepository(Hub::class)->findOneBy(['branch_code' => $hub_with_inventory['BranchCode']]);
|
||||||
|
if ($found_hub != null)
|
||||||
|
{
|
||||||
|
// check rider availability
|
||||||
|
if (count($found_hub->getAvailableRiders()) > 0)
|
||||||
|
{
|
||||||
|
// check against nearest hubs with distance
|
||||||
|
foreach ($nearest_hubs_with_distance as $nhd)
|
||||||
|
{
|
||||||
|
// get distance of hub from location, compare with $nearest. if less, replace nearest
|
||||||
|
if ($found_hub->getID() == $nhd['hub']->getID())
|
||||||
|
{
|
||||||
|
if (empty($nearest))
|
||||||
|
{
|
||||||
|
$nearest = $nhd;
|
||||||
|
$flag_hub_found = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if ($nhd['distance'] < $nearest['distance'])
|
||||||
|
{
|
||||||
|
$nearest = $nhd;
|
||||||
|
$flag_hub_found = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$selected_hub = $nearest['hub'];
|
||||||
|
}
|
||||||
|
} */
|
||||||
|
return $selected_hub;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function findRiderSlots($jo, Hub $hub, $request_time, EntityManagerInterface $em)
|
||||||
|
{
|
||||||
|
$flag_found_slot = false;
|
||||||
|
$results = [];
|
||||||
|
|
||||||
|
// array of # of riders that can handle JOs in a timeslot
|
||||||
|
$hub_rider_slots = [];
|
||||||
|
|
||||||
|
// populate the array with the hub's rider slots
|
||||||
|
for ($i = 0; $i <=7; $i++)
|
||||||
|
{
|
||||||
|
$hub_rider_slots[$i] = $hub->getRiderSlots();
|
||||||
|
}
|
||||||
|
|
||||||
|
// check hub's advance orders for the day
|
||||||
|
// get number of advance orders for the next day if request came in before midnight
|
||||||
|
// or for current day if request came in after midnight
|
||||||
|
// check request_time
|
||||||
|
$midnight = strtotime('00:00');
|
||||||
|
$start_date = new DateTime();
|
||||||
|
$end_date = new DateTime();
|
||||||
|
|
||||||
|
if ($request_time < $midnight)
|
||||||
|
{
|
||||||
|
// add +1 to date to start and end date
|
||||||
|
$start_date->add(new DateInterval('P1D'));
|
||||||
|
$end_date->add(new DateInterval('P1D'));
|
||||||
|
}
|
||||||
|
|
||||||
|
// set time bounds for the start and end date
|
||||||
|
$start_date->setTime(0, 1);
|
||||||
|
$end_date->setTime(23, 59);
|
||||||
|
|
||||||
|
$str_request_time = date('Y-m-d H:i:s', $request_time);
|
||||||
|
$time_of_request = DateTime::createFromFormat('Y-m-d H:i:s', $str_request_time);
|
||||||
|
|
||||||
|
// NOTE: get advance orders via query
|
||||||
|
// get JOs assigned to hub that are advance orders and scheduled for the next day(if before midnight) or current day(if after midnight) with
|
||||||
|
// for hub assignment status
|
||||||
|
$query = $em->createQuery('select jo from App\Entity\JobOrder jo where jo.hub = :hub and jo.flag_advance = true and
|
||||||
|
jo.date_schedule >= :date_start and jo.date_schedule <= :date_end and jo.status = :status');
|
||||||
|
$jos_advance_orders = $query->setParameters([
|
||||||
|
'hub' => $hub,
|
||||||
|
'date_start' => $start_date,
|
||||||
|
'date_end' => $end_date,
|
||||||
|
'status' => JOStatus::ASSIGNED,
|
||||||
|
])
|
||||||
|
->getResult();
|
||||||
|
|
||||||
|
// check each JO's date_schedule, decrement rider_slots if date schedule falls in that slot
|
||||||
|
// index - equivalent time
|
||||||
|
// 0 - 8-9
|
||||||
|
// 1 - 9-10
|
||||||
|
// 2 - 10-11
|
||||||
|
// 3 - 11-12
|
||||||
|
// 4 - 12 -13
|
||||||
|
// 5 - 13-14
|
||||||
|
// 6 - 14-15
|
||||||
|
// 7 - 15-16
|
||||||
|
foreach ($jos_advance_orders as $advance_jo)
|
||||||
|
{
|
||||||
|
// get time schedule
|
||||||
|
$date_schedule = $advance_jo->getDateSchedule();
|
||||||
|
$time_schedule = $date_schedule->format('H:i');
|
||||||
|
|
||||||
|
$hour_schedule = $date_schedule->format('H');
|
||||||
|
$minute_schedule = $date_schedule->format('i');
|
||||||
|
|
||||||
|
// check minutes. for now, if not 00, take up current slot and next one
|
||||||
|
// if hour fits in the last slot but minutes is not 00, move to the next available hub
|
||||||
|
// TODO: need to add custom minutes threshold
|
||||||
|
if ($minute_schedule != '00')
|
||||||
|
{
|
||||||
|
switch($hour_schedule) {
|
||||||
|
case '8':
|
||||||
|
$hub_rider_slots[0]--;
|
||||||
|
$hub_rider_slots[1]--;
|
||||||
|
break;
|
||||||
|
case '9':
|
||||||
|
$hub_rider_slots[1]--;
|
||||||
|
$hub_rider_slots[2]--;
|
||||||
|
break;
|
||||||
|
case '10':
|
||||||
|
$hub_rider_slots[2]--;
|
||||||
|
$hub_rider_slots[3]--;
|
||||||
|
break;
|
||||||
|
case '11':
|
||||||
|
$hub_rider_slots[3]--;
|
||||||
|
$hub_rider_slots[4]--;
|
||||||
|
break;
|
||||||
|
case '12':
|
||||||
|
$hub_rider_slots[4]--;
|
||||||
|
$hub_rider_slots[5]--;
|
||||||
|
break;
|
||||||
|
case '13':
|
||||||
|
$hub_rider_slots[5]--;
|
||||||
|
$hub_rider_slots[6]--;
|
||||||
|
break;
|
||||||
|
case '14':
|
||||||
|
$hub_rider_slots[6]--;
|
||||||
|
$hub_rider_slots[7]--;
|
||||||
|
break;
|
||||||
|
case '15':
|
||||||
|
error_log('No slots for the day');
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
error_log('Does not fit in any time slot. ' . $time_schedule);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
switch ($hour_schedule) {
|
||||||
|
case '8':
|
||||||
|
$hub_rider_slots[0]--;
|
||||||
|
break;
|
||||||
|
case '9':
|
||||||
|
$hub_rider_slots[1]--;
|
||||||
|
break;
|
||||||
|
case '10':
|
||||||
|
$hub_rider_slots[2]--;
|
||||||
|
break;
|
||||||
|
case '11':
|
||||||
|
$hub_rider_slots[3]--;
|
||||||
|
break;
|
||||||
|
case '12':
|
||||||
|
$hub_rider_slots[4]--;
|
||||||
|
break;
|
||||||
|
case '13':
|
||||||
|
$hub_rider_slots[5]--;
|
||||||
|
break;
|
||||||
|
case '14':
|
||||||
|
$hub_rider_slots[6]--;
|
||||||
|
break;
|
||||||
|
case '15':
|
||||||
|
$hub_rider_slots[7]--;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
error_log('Does not fit in any time slot.' . $time_schedule);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// find first free slot
|
||||||
|
foreach ($hub_rider_slots as $index => $rider_slot)
|
||||||
|
{
|
||||||
|
if ($rider_slot > 0)
|
||||||
|
{
|
||||||
|
$flag_found_slot = true;
|
||||||
|
|
||||||
|
$jo_date_schedule = $start_date;
|
||||||
|
switch ($index) {
|
||||||
|
case '0':
|
||||||
|
$jo_date_schedule->setTime(8,0);
|
||||||
|
break;
|
||||||
|
case '1':
|
||||||
|
$jo_date_schedule->setTime(9,0);
|
||||||
|
break;
|
||||||
|
case '2':
|
||||||
|
$jo_date_schedule->setTime(10,0);
|
||||||
|
break;
|
||||||
|
case '3':
|
||||||
|
$jo_date_schedule->setTime(11,0);
|
||||||
|
break;
|
||||||
|
case '4':
|
||||||
|
$jo_date_schedule->setTime(12,0);
|
||||||
|
break;
|
||||||
|
case '5':
|
||||||
|
$jo_date_schedule->setTime(13,0);
|
||||||
|
break;
|
||||||
|
case '6':
|
||||||
|
$jo_date_schedule->setTime(14,0);
|
||||||
|
break;
|
||||||
|
case '7':
|
||||||
|
$jo_date_schedule->setTime(15,0);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
error_log('Cannot find time slot.');
|
||||||
|
}
|
||||||
|
|
||||||
|
$results = [
|
||||||
|
'slot_found' => $flag_found_slot,
|
||||||
|
'date_schedule' => $jo_date_schedule,
|
||||||
|
];
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $results;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -65,8 +65,7 @@ class HomeController extends Controller
|
||||||
$riders[$rider_id]['has_jo'] = true;
|
$riders[$rider_id]['has_jo'] = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// get JOs with transaction origin TransactionOrigin::MOBILE_APP from list of active_jos
|
// get active JOs and check transaction origin for TransactionOrigin::MOBILE_APP
|
||||||
$mobile_jos = [];
|
|
||||||
foreach ($active_jos as $jo_id => $jo_data)
|
foreach ($active_jos as $jo_id => $jo_data)
|
||||||
{
|
{
|
||||||
$jo = $em->getRepository(JobOrder::class)->find($jo_id);
|
$jo = $em->getRepository(JobOrder::class)->find($jo_id);
|
||||||
|
|
@ -78,8 +77,11 @@ class HomeController extends Controller
|
||||||
|
|
||||||
if ($jo->getSource() == TransactionOrigin::MOBILE_APP)
|
if ($jo->getSource() == TransactionOrigin::MOBILE_APP)
|
||||||
{
|
{
|
||||||
$mobile_jos[$jo_id] = $jo_data;
|
$active_jos[$jo_id]['is_mobile'] = true;
|
||||||
unset($active_jos[$jo_id]);
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
$active_jos[$jo_id]['is_mobile'] = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -140,7 +142,6 @@ class HomeController extends Controller
|
||||||
return $this->json([
|
return $this->json([
|
||||||
'jos' => $active_jos,
|
'jos' => $active_jos,
|
||||||
'riders' => $riders,
|
'riders' => $riders,
|
||||||
'mobile_jos' => $mobile_jos,
|
|
||||||
]);
|
]);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -152,7 +152,8 @@ class HubController extends Controller
|
||||||
->setTimeClose($time_close)
|
->setTimeClose($time_close)
|
||||||
->setCoordinates($point)
|
->setCoordinates($point)
|
||||||
->setBranchCode($req->request->get('branch_code', ''))
|
->setBranchCode($req->request->get('branch_code', ''))
|
||||||
->setStatusOpen($req->request->get('status_open') ?? false);
|
->setStatusOpen($req->request->get('status_open') ?? false)
|
||||||
|
->setRiderSlots($req->request->get('rider_slots', 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function setQueryFilters($datatable, QueryBuilder $query)
|
protected function setQueryFilters($datatable, QueryBuilder $query)
|
||||||
|
|
|
||||||
|
|
@ -56,6 +56,12 @@ class Hub
|
||||||
*/
|
*/
|
||||||
protected $status_open;
|
protected $status_open;
|
||||||
|
|
||||||
|
// number of rider slots per day
|
||||||
|
/**
|
||||||
|
* @ORM\Column(type="integer")
|
||||||
|
*/
|
||||||
|
protected $rider_slots;
|
||||||
|
|
||||||
public function __construct()
|
public function __construct()
|
||||||
{
|
{
|
||||||
$this->time_open = new DateTime();
|
$this->time_open = new DateTime();
|
||||||
|
|
@ -150,4 +156,15 @@ class Hub
|
||||||
return $this->status_open;
|
return $this->status_open;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function setRiderSlots($rider_slots)
|
||||||
|
{
|
||||||
|
$this->rider_slots = $rider_slots;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getRiderSlots()
|
||||||
|
{
|
||||||
|
return $this->rider_slots;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -88,7 +88,13 @@ class JobOrderActiveCacheListener
|
||||||
// send jo location
|
// send jo location
|
||||||
$this->mqtt->publish(
|
$this->mqtt->publish(
|
||||||
'jo/' . $jo->getID() . '/location',
|
'jo/' . $jo->getID() . '/location',
|
||||||
$coords->getLatitude() . ':' . $coords->getLongitude()
|
$coords->getLatitude() . ':' . $coords->getLongitude()
|
||||||
|
);
|
||||||
|
|
||||||
|
// send transaction origin
|
||||||
|
$this->mqtt->publish(
|
||||||
|
'jo/' . $jo->getID() . '/origin',
|
||||||
|
$jo->getSource()
|
||||||
);
|
);
|
||||||
|
|
||||||
// TODO: do we still need to send jo status?
|
// TODO: do we still need to send jo status?
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,7 @@
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<script>
|
<script>
|
||||||
|
|
||||||
function initMap(r_markers, c_markers, mc_markers, icons) {
|
function initMap(r_markers, c_markers, icons) {
|
||||||
var default_lat = {% trans %}default_lat{% endtrans %};
|
var default_lat = {% trans %}default_lat{% endtrans %};
|
||||||
var default_lng = {% trans %}default_long{% endtrans %};
|
var default_lng = {% trans %}default_long{% endtrans %};
|
||||||
|
|
||||||
|
|
@ -38,7 +38,7 @@ function initMap(r_markers, c_markers, mc_markers, icons) {
|
||||||
'icons': icons
|
'icons': icons
|
||||||
};
|
};
|
||||||
|
|
||||||
var dashmap = new DashboardMap(options, r_markers, c_markers, mc_markers);
|
var dashmap = new DashboardMap(options, r_markers, c_markers);
|
||||||
dashmap.initialize();
|
dashmap.initialize();
|
||||||
dashmap.loadLocations('{{ path('rider_locations') }}');
|
dashmap.loadLocations('{{ path('rider_locations') }}');
|
||||||
|
|
||||||
|
|
@ -53,7 +53,8 @@ function initEventHandler(dashmap) {
|
||||||
'rider_location': 'rider/+/location',
|
'rider_location': 'rider/+/location',
|
||||||
'rider_status': 'rider/+/status',
|
'rider_status': 'rider/+/status',
|
||||||
'jo_location': 'jo/+/location',
|
'jo_location': 'jo/+/location',
|
||||||
'jo_status': 'jo/+/status'
|
'jo_status': 'jo/+/status',
|
||||||
|
'jo_origin': 'jo/+/origin'
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -92,9 +93,8 @@ var icons = {
|
||||||
|
|
||||||
var r_markers = {};
|
var r_markers = {};
|
||||||
var c_markers = {};
|
var c_markers = {};
|
||||||
var mc_markers = {};
|
|
||||||
|
|
||||||
var dashmap = initMap(r_markers, c_markers, mc_markers, icons);
|
var dashmap = initMap(r_markers, c_markers, icons);
|
||||||
initEventHandler(dashmap, icons);
|
initEventHandler(dashmap, icons);
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -90,7 +90,14 @@
|
||||||
<input type="text" name="branch_code" class="form-control m-input" value="{{ obj.getBranchCode() }}">
|
<input type="text" name="branch_code" class="form-control m-input" value="{{ obj.getBranchCode() }}">
|
||||||
<div class="form-control-feedback hide" data-field="branch_code"></div>
|
<div class="form-control-feedback hide" data-field="branch_code"></div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-lg-6">
|
<div class="col-lg-3">
|
||||||
|
<label for="rider_slots" data-field="rider_slots">
|
||||||
|
Number of Riders Per Slot
|
||||||
|
</label>
|
||||||
|
<input type="text" name="rider_slots" class="form-control m-input" value="{{ obj.getRiderSlots() }}">
|
||||||
|
<div class="form-control-feedback hide" data-field="rider_slots"></div>
|
||||||
|
</div>
|
||||||
|
<div class="col-lg-3">
|
||||||
<span class="m-switch m-switch--icon block-switch">
|
<span class="m-switch m-switch--icon block-switch">
|
||||||
<label>
|
<label>
|
||||||
<input type="checkbox" name="status_open" id="status-open" value="1"{{ obj.isStatusOpen ? ' checked' }}>
|
<input type="checkbox" name="status_open" id="status-open" value="1"{{ obj.isStatusOpen ? ' checked' }}>
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue