Resolve "CMB - Data migration for Carfix data" #1355
24 changed files with 2333 additions and 270 deletions
9
config/routes/notification.yaml
Normal file
9
config/routes/notification.yaml
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
notification_ajax_list:
|
||||
path: /ajax/notifications
|
||||
controller: App\Controller\NotificationController::ajaxList
|
||||
methods: [GET]
|
||||
|
||||
notification_ajax_update:
|
||||
path: /ajax/notifications
|
||||
controller: App\Controller\NotificationController::ajaxUpdate
|
||||
methods: [POST]
|
||||
|
|
@ -61,3 +61,9 @@ rider_ajax_avialable:
|
|||
path: /riders/{id}/available
|
||||
controller: App\Controller\RiderController::ajaxAvailable
|
||||
methods: [GET]
|
||||
|
||||
rider_ajax_rider_name:
|
||||
path: /riders/{id}/name
|
||||
controller: App\Controller\RiderController::ajaxRiderName
|
||||
methods: [GET]
|
||||
|
||||
|
|
|
|||
|
|
@ -221,6 +221,12 @@ services:
|
|||
event: 'postPersist'
|
||||
entity: 'App\Entity\JobOrder'
|
||||
|
||||
App\Service\NotificationManager:
|
||||
arguments:
|
||||
$redis_prov: "@App\\Service\\RedisClientProvider"
|
||||
$redis_mqtt_key: "mqtt_events"
|
||||
$em: "@doctrine.orm.entity_manager"
|
||||
|
||||
App\Service\JobOrderCache:
|
||||
arguments:
|
||||
$redis_prov: "@App\\Service\\RedisClientProvider"
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ class DashboardMap {
|
|||
this.rider_markers = rider_markers;
|
||||
this.cust_markers = cust_markers;
|
||||
this.rider_availability = {};
|
||||
this.rider_names = {};
|
||||
|
||||
// layer groups
|
||||
this.layer_groups = {
|
||||
|
|
@ -230,30 +231,38 @@ class DashboardMap {
|
|||
);
|
||||
}
|
||||
|
||||
putRiderAvailableMarker(id, lat, lng, name) {
|
||||
this.putMarkerWithLabel(
|
||||
id,
|
||||
lat,
|
||||
lng,
|
||||
this.rider_markers,
|
||||
this.options.icons.rider_available,
|
||||
this.layer_groups.rider_available,
|
||||
this.options.rider_popup_url,
|
||||
name
|
||||
);
|
||||
putRiderAvailableMarker(id, lat, lng) {
|
||||
var my = this;
|
||||
|
||||
my.getRiderName(id, function(name) {
|
||||
my.putMarkerWithLabel(
|
||||
id,
|
||||
lat,
|
||||
lng,
|
||||
my.rider_markers,
|
||||
my.options.icons.rider_available,
|
||||
my.layer_groups.rider_available,
|
||||
my.options.rider_popup_url,
|
||||
name
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
putRiderActiveJOMarker(id, lat, lng, name) {
|
||||
this.putMarkerWithLabel(
|
||||
id,
|
||||
lat,
|
||||
lng,
|
||||
this.rider_markers,
|
||||
this.options.icons.rider_active_jo,
|
||||
this.layer_groups.rider_active_jo,
|
||||
this.options.rider_popup_url,
|
||||
name
|
||||
);
|
||||
putRiderActiveJOMarker(id, lat, lng) {
|
||||
var my = this;
|
||||
|
||||
my.getRiderName(id, function(name) {
|
||||
my.putMarkerWithLabel(
|
||||
id,
|
||||
lat,
|
||||
lng,
|
||||
my.rider_markers,
|
||||
my.options.icons.rider_active_jo,
|
||||
my.layer_groups.rider_active_jo,
|
||||
my.options.rider_popup_url,
|
||||
name
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
removeRiderMarker(id) {
|
||||
|
|
@ -305,12 +314,39 @@ class DashboardMap {
|
|||
var name = '';
|
||||
|
||||
if (data.has_jo)
|
||||
my.putRiderActiveJOMarker(id, lat, lng, name);
|
||||
my.putRiderActiveJOMarker(id, lat, lng);
|
||||
else
|
||||
my.putRiderAvailableMarker(id, lat, lng, name);
|
||||
my.putRiderAvailableMarker(id, lat, lng);
|
||||
});
|
||||
|
||||
// console.log(rider_markers);
|
||||
});
|
||||
}
|
||||
|
||||
getRiderName(id, callback) {
|
||||
var name = '';
|
||||
var rider_url = this.options.rider_name_url.replace('[id]', id);
|
||||
|
||||
var my = this;
|
||||
|
||||
console.log('getting rider name for rider ' + id);
|
||||
|
||||
// check if we have it in cache
|
||||
if (this.rider_names.hasOwnProperty(id)) {
|
||||
name = this.rider_names[id];
|
||||
callback(name);
|
||||
} else {
|
||||
// ajax call to get it
|
||||
$.ajax({
|
||||
method: "GET",
|
||||
url: rider_url
|
||||
}).done(function(response) {
|
||||
name = response.rider_name;
|
||||
|
||||
// set name in cache
|
||||
my.rider_names[id] = name;
|
||||
callback(name);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -78,8 +78,9 @@ class MapEventHandler {
|
|||
}
|
||||
|
||||
handleRider(chan_split, payload) {
|
||||
// console.log("rider message");
|
||||
//console.log("rider message");
|
||||
var rider_id = chan_split[1];
|
||||
//console.log('url ' + this.dashmap.options.rider_availability_url);
|
||||
switch (chan_split[2]) {
|
||||
case "availability":
|
||||
console.log("got availability for rider " + chan_split[1] + " - " + payload);
|
||||
|
|
@ -100,7 +101,10 @@ class MapEventHandler {
|
|||
// cheeck if rider is available / unavailable
|
||||
// TODO: make url not hardcoded
|
||||
var dashmap = this.dashmap;
|
||||
$.get('https://cmbdev.wildcard.cc/riders/' + chan_split[1] + '/available').done(function(data) {
|
||||
var url = dashmap.options.rider_availability_url;
|
||||
var rider_availability_url = url.replace('[id]', chan_split[1]);
|
||||
//console.log(rider_availability_url);
|
||||
$.get(rider_availability_url).done(function(data) {
|
||||
console.log('rider availability - ' + data);
|
||||
switch (data) {
|
||||
case 'available':
|
||||
|
|
@ -122,7 +126,7 @@ class MapEventHandler {
|
|||
// console.log("got location for rider " + chan_split[1] + " - " + payload
|
||||
var pl_split = payload.split(':');
|
||||
// console.log(pl_split);
|
||||
|
||||
|
||||
// check for correct format
|
||||
if (pl_split.length != 2)
|
||||
break;
|
||||
|
|
@ -138,6 +142,7 @@ class MapEventHandler {
|
|||
}
|
||||
} else {
|
||||
console.log('rider not in availability check');
|
||||
display_marker = false;
|
||||
}
|
||||
|
||||
// TODO: cache rider availability (available vs active jo) status and check before displaying icon
|
||||
|
|
|
|||
111
public/assets/js/notification.js
Normal file
111
public/assets/js/notification.js
Normal file
|
|
@ -0,0 +1,111 @@
|
|||
class NotificationHandler {
|
||||
constructor(options) {
|
||||
this.options = options;
|
||||
}
|
||||
|
||||
clearAll() {
|
||||
// clear notification count
|
||||
document.getElementById('notif-count').innerHTML = '';
|
||||
|
||||
// remove notifications
|
||||
document.getElementById('notif-body').innerHTML = '';
|
||||
}
|
||||
|
||||
loadAll() {
|
||||
console.log('loading notifications');
|
||||
// ajax load
|
||||
var self = this;
|
||||
var notif_update_url = this.options['notif_ajax_update_url'];
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.open('GET', this.options['notif_ajax_url']);
|
||||
xhr.onload = function() {
|
||||
if (xhr.status === 200) {
|
||||
var data = JSON.parse(xhr.responseText);
|
||||
var notifs = data.notifications;
|
||||
|
||||
// update notification unread count
|
||||
var count_html = data.unread_count;
|
||||
document.getElementById('notif-count').innerHTML = count_html;
|
||||
|
||||
// do we have any notifications?
|
||||
if (notifs.length <= 0)
|
||||
return;
|
||||
|
||||
// add actual notifications
|
||||
var notif_body = document.getElementById('notif-body');
|
||||
var notif_index = 0;
|
||||
notifs.forEach(function(notif) {
|
||||
var notif_date = moment(notif.date).fromNow();
|
||||
|
||||
var notif_html = '<div class="m-list-timeline__item">';
|
||||
notif_html += '<span class="m-list-timeline__badge -m-list-timeline__badge--state-success"></span>';
|
||||
notif_html += '<span class="m-list-timeline__text">';
|
||||
notif_html += '<a href="">' + notif.text + '</a>'
|
||||
notif_html += '</span>';
|
||||
notif_html += '<span class="m-list-timeline__time">';
|
||||
notif_html += notif_date;
|
||||
notif_html += '</span>';
|
||||
notif_html += '</div>';
|
||||
|
||||
notif_body.insertAdjacentHTML('beforeend', notif_html);
|
||||
|
||||
document.getElementsByClassName('m-list-timeline__item')[notif_index].addEventListener('click', function(e) {
|
||||
e.preventDefault();
|
||||
$.ajax({
|
||||
method: "POST",
|
||||
url: notif_update_url,
|
||||
data: {id: notif.id}
|
||||
}).done(function(response) {
|
||||
window.location.href = notif.link;
|
||||
});
|
||||
});
|
||||
|
||||
notif_index++;
|
||||
});
|
||||
}
|
||||
|
||||
};
|
||||
xhr.send();
|
||||
}
|
||||
|
||||
listen(user_id, host, port, use_ssl = false) {
|
||||
var d = new Date();
|
||||
var client_id = "dash-" + user_id + "-" + d.getMonth() + "-" + d.getDate() + "-" + d.getHours() + "-" + d.getMinutes() + "-" + d.getSeconds() + "-" + d.getMilliseconds();
|
||||
|
||||
this.mqtt = new Paho.MQTT.Client(host, port, client_id);
|
||||
var options = {
|
||||
useSSL: use_ssl,
|
||||
timeout: 3,
|
||||
invocationContext: this,
|
||||
onSuccess: this.onConnect.bind(this)
|
||||
}
|
||||
|
||||
this.mqtt.onMessageArrived = this.onMessage.bind(this);
|
||||
|
||||
this.mqtt.connect(options);
|
||||
}
|
||||
|
||||
onConnect(icontext) {
|
||||
console.log('notification mqtt connected');
|
||||
var my = icontext.invocationContext;
|
||||
|
||||
// subscribe to general notifications
|
||||
my.mqtt.subscribe('user/0/notification');
|
||||
}
|
||||
|
||||
onMessage(msg) {
|
||||
console.log('notification event received');
|
||||
// we don't care about messasge, we update
|
||||
this.clearAll();
|
||||
this.loadAll();
|
||||
}
|
||||
|
||||
getIcon(type_id) {
|
||||
if (type_id in this.options['icons']) {
|
||||
return this.options['icons'][type_id];
|
||||
}
|
||||
|
||||
return this.options['default_icon'];
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -148,19 +148,19 @@ class ImportCMBBatteryDataCommand extends Command
|
|||
// save battery manufacturer if not yet in system
|
||||
if (!isset($this->bmanu_hash[$normalized_manu]))
|
||||
{
|
||||
$this->addBatteryManufacturer($battery_manufacturer);
|
||||
$this->addBatteryManufacturer(strtoupper($battery_manufacturer));
|
||||
}
|
||||
|
||||
// save battery model if not yet in system
|
||||
if (!isset($this->bmodel_hash[$normalized_model]))
|
||||
{
|
||||
$this->addBatteryModel($battery_model);
|
||||
$this->addBatteryModel(strtoupper($battery_model));
|
||||
}
|
||||
|
||||
// save battery size if not yet in system
|
||||
if (!isset($this->bsize_hash[$normalized_size]))
|
||||
{
|
||||
$this->addBatterySize($clean_size);
|
||||
$this->addBatterySize(strtoupper($clean_size));
|
||||
}
|
||||
|
||||
// save battery if not yet in system
|
||||
|
|
|
|||
489
src/Command/ImportCMBCarFixDataCommand.php
Normal file
489
src/Command/ImportCMBCarFixDataCommand.php
Normal file
|
|
@ -0,0 +1,489 @@
|
|||
<?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 Doctrine\ORM\EntityManagerInterface;
|
||||
|
||||
use App\Entity\JobOrder;
|
||||
use App\Entity\VehicleManufacturer;
|
||||
use App\Entity\Vehicle;
|
||||
use App\Entity\BatteryManufacturer;
|
||||
use App\Entity\BatteryModel;
|
||||
use App\Entity\BatterySize;
|
||||
use App\Entity\Battery;
|
||||
use App\Entity\Customer;
|
||||
use App\Entity\CustomerVehicle;
|
||||
|
||||
use App\Ramcar\CMBServiceType;
|
||||
use App\Ramcar\JOStatus;
|
||||
use App\Ramcar\FuelType;
|
||||
use App\Ramcar\VehicleStatusCondition;
|
||||
|
||||
use DateTime;
|
||||
|
||||
class ImportCMBCarFixDataCommand extends Command
|
||||
{
|
||||
// field index in csv file
|
||||
const F_INDEX = 0;
|
||||
const F_CREATED_DATE = 1;
|
||||
const F_CASE_NO = 2;
|
||||
const F_INSURER = 3;
|
||||
const F_VEHICLE_NO = 4;
|
||||
const F_CAR_MODEL = 5;
|
||||
const F_NATURE_OF_CALL = 6;
|
||||
const F_SERVICE_NEEDED = 7;
|
||||
const F_LOCATION = 8;
|
||||
const F_STATE = 9;
|
||||
const F_DRIVER = 10;
|
||||
const F_TRUCK = 11;
|
||||
const F_WORKSHOP_ARRIVAL_TIME = 12;
|
||||
const F_STATUS = 13;
|
||||
const F_CUSTOMER_NAME = 14;
|
||||
const F_CUSTOMER_PHONE_NO = 15;
|
||||
const F_OUR_REFERENCE = 16;
|
||||
const F_ODOMETER = 17;
|
||||
const F_BATT_MODEL = 18;
|
||||
const F_BATT_SIZE = 19;
|
||||
const F_BATT_TRADE_IN = 20;
|
||||
const F_REPLACED_BY = 21;
|
||||
const F_REMARK = 22;
|
||||
const F_SATISFACTION = 23;
|
||||
|
||||
protected $em;
|
||||
|
||||
protected $bmanu_hash;
|
||||
protected $bmodel_hash;
|
||||
protected $bsize_hash;
|
||||
protected $batt_hash;
|
||||
|
||||
protected $vmanu_hash;
|
||||
protected $vmake_hash;
|
||||
|
||||
protected $cv_hash;
|
||||
|
||||
public function __construct(EntityManagerInterface $em)
|
||||
{
|
||||
$this->em = $em;
|
||||
|
||||
// load existing battery data
|
||||
$this->loadBatteryManufacturers();
|
||||
$this->loadBatteryModels();
|
||||
$this->loadBatterySizes();
|
||||
$this->loadBatteries();
|
||||
|
||||
// load existing vehicle data
|
||||
$this->loadVehicleManufacturers();
|
||||
$this->loadVehicleMakes();
|
||||
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
public function configure()
|
||||
{
|
||||
$this->setName('cmbcarfixdata:import')
|
||||
->setDescription('Retrieve from a CSV file CarFix data.')
|
||||
->setHelp('Creates job orders based on data from imported CSV.')
|
||||
->addArgument('file', InputArgument::REQUIRED, 'Path to the CSV file.');
|
||||
}
|
||||
|
||||
public function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$csv_file = $input->getArgument('file');
|
||||
|
||||
// attempt to open file
|
||||
try
|
||||
{
|
||||
$fh = fopen($csv_file, "r");
|
||||
}
|
||||
catch (Exception $e)
|
||||
{
|
||||
throw new Exception('The file "' . $csv_file . '" could be read.');
|
||||
}
|
||||
|
||||
// get entity manager
|
||||
$em = $this->em;
|
||||
|
||||
$row_num = 0;
|
||||
$invalid_entries = [];
|
||||
error_log('Processing CarFix data csv file...');
|
||||
while (($fields = fgetcsv($fh)) !== false)
|
||||
{
|
||||
if ($row_num < 1)
|
||||
{
|
||||
$row_num++;
|
||||
continue;
|
||||
}
|
||||
|
||||
// get the information
|
||||
$entry_num = trim($fields[self::F_INDEX]);
|
||||
$date_create = trim($fields[self::F_CREATED_DATE]);
|
||||
$case_number = trim($fields[self::F_CASE_NO]);
|
||||
$insurer = trim($fields[self::F_INSURER]);
|
||||
$vehicle_number = trim($fields[self::F_VEHICLE_NO]);
|
||||
$car_model = trim($fields[self::F_CAR_MODEL]);
|
||||
$nature_of_call = trim($fields[self::F_NATURE_OF_CALL]);
|
||||
$service_needed = trim($fields[self::F_SERVICE_NEEDED]);
|
||||
$location = trim($fields[self::F_LOCATION]);
|
||||
$state = trim($fields[self::F_STATE]);
|
||||
$driver = trim($fields[self::F_DRIVER]);
|
||||
$truck = trim($fields[self::F_TRUCK]);
|
||||
$workshop_arrival_time = trim($fields[self::F_WORKSHOP_ARRIVAL_TIME]);
|
||||
$status = trim($fields[self::F_STATUS]);
|
||||
$customer_name = trim($fields[self::F_CUSTOMER_NAME]);
|
||||
$customer_mobile = trim($fields[self::F_CUSTOMER_PHONE_NO]);
|
||||
$reference = trim($fields[self::F_OUR_REFERENCE]);
|
||||
$odometer = trim($fields[self::F_ODOMETER]);
|
||||
$batt_model = trim(strtolower($fields[self::F_BATT_MODEL]));
|
||||
$batt_size = trim(strtolower($fields[self::F_BATT_SIZE]));
|
||||
$trade_in = trim($fields[self::F_BATT_TRADE_IN]);
|
||||
$replaced_by = trim($fields[self::F_REPLACED_BY]);
|
||||
$remark = trim($fields[self::F_REMARK]);
|
||||
$satisfaction = trim($fields[self::F_SATISFACTION]);
|
||||
|
||||
//error_log($date_create . ' ' . $case_number . ' ' . $driver . ' ' . $customer_name . ' ' . $remark . ' ' . $satisfaction);
|
||||
|
||||
// get customer vehicle
|
||||
$v_status = $this->processVehicleInfo($car_model);
|
||||
if ($v_status != null)
|
||||
{
|
||||
error_log($v_status . ' ' . $car_model);
|
||||
$invalid_entries[] = $this->addInvalidEntry($entry_num, $date_create, $case_number, $insurer, $vehicle_number, $car_model,
|
||||
$nature_of_call, $service_needed, $location, $state, $driver, $truck, $workshop_arrival_time,
|
||||
$status, $customer_name, $customer_mobile, $reference, $odometer, $batt_model, $batt_size,
|
||||
$trade_in, $replaced_by, $remark, $satisfaction, $v_status);
|
||||
|
||||
// move to next entry
|
||||
continue;
|
||||
}
|
||||
|
||||
// check batteries
|
||||
$batt_status = $this->processBatteryInfo($batt_model, $batt_size);
|
||||
if ($batt_status != null)
|
||||
{
|
||||
error_log($batt_status);
|
||||
$invalid_entries[] = $this->addInvalidEntry($entry_num, $date_create, $case_number, $insurer, $vehicle_number, $car_model,
|
||||
$nature_of_call, $service_needed, $location, $state, $driver, $truck, $workshop_arrival_time,
|
||||
$status, $customer_name, $customer_mobile, $reference, $odometer, $batt_model, $batt_size,
|
||||
$trade_in, $replaced_by, $remark, $satisfaction, $batt_status);
|
||||
|
||||
// move to next entry
|
||||
continue;
|
||||
}
|
||||
|
||||
$new_jo = new JobOrder();
|
||||
|
||||
// add to metadata
|
||||
// case number, nature of call, workshop arrival time, reference, odometer, replaced by, satisfaction
|
||||
$new_jo->addMeta('case_number', $case_number);
|
||||
$new_jo->addMeta('nature_of_call', $nature_of_call);
|
||||
$new_jo->addMeta('workshop_arrival_time', $workshop_arrival_time);
|
||||
$new_jo->addMeta('reference', $reference);
|
||||
$new_jo->addMeta('odometer', $odometer);
|
||||
$new_jo->addMeta('replaced_by', $replaced_by);
|
||||
$new_jo->addMeta('satisfaction', $satisfaction);
|
||||
|
||||
// date_create
|
||||
$created_date = DateTime::createFromFormat('d-m-Y H:i', $date_create);
|
||||
$new_jo->setDateCreate($created_date);
|
||||
|
||||
// insurer == responsible_party
|
||||
$new_jo->setResponsibleParty($insurer);
|
||||
|
||||
// delivery address = location + state
|
||||
$delivery_address = $location . ', ' . $state;
|
||||
$new_jo->setDeliveryAddress($delivery_address);
|
||||
|
||||
// remarks == tier 1 notes
|
||||
$new_jo->setTier1Notes($remark);
|
||||
|
||||
// service_needed = service type
|
||||
// check service needed:
|
||||
// Battery == Battery Sales
|
||||
// Battery Warranty Claim == Warranty Claim
|
||||
// Battery Warranty Replacement == Warranty Replacement
|
||||
$service = $this->normalizeName($service_needed);
|
||||
switch ($service)
|
||||
{
|
||||
case 'battery':
|
||||
$new_jo->setServiceType(CMBServiceType::BATTERY_REPLACEMENT_NEW);
|
||||
break;
|
||||
case 'battery warranty claim':
|
||||
$new_jo->setServiceType(CMBServiceType::WARRANTY_CLAIM);
|
||||
break;
|
||||
case 'battery warranty replacement':
|
||||
$new_jo->setServiceType(CMBServiceType::BATTERY_REPLACEMENT_WARRANTY);
|
||||
break;
|
||||
}
|
||||
|
||||
// status set everything to fulfilled
|
||||
// store old status to metadata
|
||||
$new_jo->setStatus(JOStatus::FULFILLED);
|
||||
$new_jo->addMeta('status', $status);
|
||||
|
||||
// plate number == vehicle_number. Use as key to cv_hash
|
||||
$clean_plate = $this->cleanPlateNumber($vehicle_number);
|
||||
//error_log($clean_plate . ' ' . $new_jo->getServiceType());
|
||||
|
||||
// check if plate number has been added
|
||||
if (!isset($this->cv_hash[$clean_plate]))
|
||||
{
|
||||
$cust = $this->addCustomer($customer_name, $customer_mobile);
|
||||
$cv = $this->addCustomerVehicle($clean_plate, $car_model, $cust);
|
||||
}
|
||||
else
|
||||
{
|
||||
// get customer vehicle from hash
|
||||
$cv = $this->cv_hash[$clean_plate];
|
||||
$cust = $cv->getCustomer();
|
||||
}
|
||||
|
||||
$new_jo->setCustomer($cust)
|
||||
->setCustomerVehicle($cv);
|
||||
|
||||
$row_num++;
|
||||
}
|
||||
|
||||
$this->em->flush();
|
||||
$this->em->clear();
|
||||
|
||||
// check for invalid entries. if any, write to csv
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
protected function processVehicleInfo($car_model)
|
||||
{
|
||||
// vehicle manufacturer is the first entry
|
||||
// vehicle model is the 2nd entry + whatever follows
|
||||
$v_array = explode(' ', $car_model);
|
||||
|
||||
// manufacturer
|
||||
$v_manufacturer = trim($v_array[0]);
|
||||
|
||||
// get model
|
||||
$model_info = '';
|
||||
$v_model = '';
|
||||
for ($i = 1; $i < count($v_array); $i++)
|
||||
{
|
||||
$model_info = $model_info . ' ' . trim($v_array[$i]);
|
||||
}
|
||||
|
||||
$v_model = trim($model_info);
|
||||
//error_log($v_manufacturer . ' ' . $v_model);
|
||||
|
||||
// check if manufacturer is in hash
|
||||
if (!isset($this->vmanu_hash[$v_manufacturer]))
|
||||
{
|
||||
//error_log($v_manufacturer . ' invalid.');
|
||||
return 'Vehicle manufacturer not in system.';
|
||||
}
|
||||
|
||||
// check if manufacturer and make is in hash
|
||||
if (!isset($this->vmake_hash[$v_manufacturer][$v_model]))
|
||||
{
|
||||
//error_log($v_model . ' invalid.');
|
||||
return 'Vehicle model not in system.';
|
||||
}
|
||||
// car model info valid
|
||||
return null;
|
||||
}
|
||||
|
||||
protected function processBatteryInfo($batt_model, $batt_size)
|
||||
{
|
||||
// check if battery model is in hash
|
||||
if (!isset($this->bmodel_hash[$batt_model]))
|
||||
return 'Battery model not in system.';
|
||||
|
||||
// check if battery size is in hash
|
||||
if (!isset($this->bsize_hash[$batt_size]))
|
||||
return 'Battery size not in system.';
|
||||
|
||||
// battery info valid
|
||||
return null;
|
||||
}
|
||||
|
||||
protected function addCustomer($name, $mobile)
|
||||
{
|
||||
$new_cust = new Customer();
|
||||
|
||||
$new_cust->setFirstName($name)
|
||||
->setLastName('')
|
||||
->setPhoneMobile($mobile);
|
||||
|
||||
$this->em->persist($new_cust);
|
||||
|
||||
return $new_cust;
|
||||
}
|
||||
|
||||
protected function addCustomerVehicle($plate_num, $car_model, $customer)
|
||||
{
|
||||
$new_cv = new CustomerVehicle();
|
||||
|
||||
// get vehicle from hash
|
||||
$v_array = explode(' ', $car_model);
|
||||
|
||||
// manufacturer
|
||||
$v_manufacturer = trim($v_array[0]);
|
||||
|
||||
// get model
|
||||
$model_info = '';
|
||||
$v_model = '';
|
||||
for ($i = 1; $i < count($v_array); $i++)
|
||||
{
|
||||
$model_info = $model_info . ' ' . trim($v_array[$i]);
|
||||
}
|
||||
|
||||
$v_model = trim($model_info);
|
||||
|
||||
$vehicle = $this->vmake_hash[$v_manufacturer][$v_model];
|
||||
|
||||
$new_cv->setCustomer($customer)
|
||||
->setPlateNumber($plate_num)
|
||||
->setStatusCondition(VehicleStatusCondition::BRAND_NEW)
|
||||
->setModelYear('')
|
||||
->setColor('')
|
||||
->setFuelType(FuelType::GAS)
|
||||
->setHasMotoliteBattery(true)
|
||||
->setVehicle($vehicle);
|
||||
|
||||
$this->em->persist($new_cv);
|
||||
|
||||
// add customer vehicle to cv_hash
|
||||
$this->cv_hash[$plate_num] = $new_cv;
|
||||
|
||||
return $new_cv;
|
||||
}
|
||||
|
||||
protected function addInvalidEntry($entry_num, $date_create, $case_number, $insurer, $vehicle_number, $car_model,
|
||||
$nature_of_call, $service_needed, $location, $state, $driver, $truck, $workshop_arrival_time,
|
||||
$status, $customer_name, $customer_mobile, $reference, $odometer, $batt_model, $batt_size,
|
||||
$trade_in, $replaced_by, $remark, $satisfaction, $v_status)
|
||||
{
|
||||
$inv_entry = [
|
||||
'number' => $entry_num,
|
||||
'created_date' => $date_create,
|
||||
'case_number' => $case_number,
|
||||
'insurer' => $insurer,
|
||||
'vehicle_number' => $vehicle_number,
|
||||
'car_model' => $car_model,
|
||||
'nature_of_call' => $nature_of_call,
|
||||
'service_needed' => $service_needed,
|
||||
'location' => $location,
|
||||
'state' => $state,
|
||||
'driver' => $driver,
|
||||
'truck' => $truck,
|
||||
'workshop_arrival_time' => $workshop_arrival_time,
|
||||
'status' => $status,
|
||||
'customer_name' => $customer_name,
|
||||
'customer_phone_number' => $customer_mobile,
|
||||
'reference' => $reference,
|
||||
'odometer' => $odometer,
|
||||
'batt_model' => $batt_model,
|
||||
'batt_size' => $batt_size,
|
||||
'batt_trade_in' => $trade_in,
|
||||
'replaced_by' => $replaced_by,
|
||||
'remark' => $remark,
|
||||
'satisfaction' => $satisfaction,
|
||||
'reason' => $v_status,
|
||||
];
|
||||
|
||||
return $inv_entry;
|
||||
}
|
||||
|
||||
protected function loadBatteryManufacturers()
|
||||
{
|
||||
$this->bmanu_hash = [];
|
||||
|
||||
$batt_manufacturers = $this->em->getRepository(BatteryManufacturer::class)->findAll();
|
||||
foreach ($batt_manufacturers as $batt_manu)
|
||||
{
|
||||
$name = $this->normalizeName($batt_manu->getName());
|
||||
$this->bmanu_hash[$name] = $batt_manu;
|
||||
}
|
||||
}
|
||||
|
||||
protected function loadBatteryModels()
|
||||
{
|
||||
$this->bmodel_hash = [];
|
||||
|
||||
$batt_models = $this->em->getRepository(BatteryModel::class)->findAll();
|
||||
foreach ($batt_models as $batt_model)
|
||||
{
|
||||
$name = $this->normalizeName($batt_model->getName());
|
||||
$this->bmodel_hash[$name] = $batt_model;
|
||||
}
|
||||
}
|
||||
|
||||
protected function loadBatterySizes()
|
||||
{
|
||||
$this->bsize_hash = [];
|
||||
|
||||
$batt_sizes = $this->em->getRepository(BatterySize::class)->findAll();
|
||||
foreach ($batt_sizes as $batt_size)
|
||||
{
|
||||
$name = $this->normalizeName($batt_size->getName());
|
||||
$this->bsize_hash[$name] = $batt_size;
|
||||
}
|
||||
}
|
||||
|
||||
protected function loadBatteries()
|
||||
{
|
||||
$this->batt_hash = [];
|
||||
|
||||
$batts = $this->em->getRepository(Battery::class)->findAll();
|
||||
foreach ($batts as $batt)
|
||||
{
|
||||
$brand = $this->normalizeName($batt->getManufacturer()->getName());
|
||||
$model = $this->normalizeName($batt->getModel()->getName());
|
||||
$size = $this->normalizeName($batt->getSize()->getName());
|
||||
|
||||
$this->batt_hash[$brand][$model][$size] = $batt;
|
||||
}
|
||||
}
|
||||
|
||||
protected function loadVehicleManufacturers()
|
||||
{
|
||||
$this->vmanu_hash = [];
|
||||
|
||||
$vmanus = $this->em->getRepository(VehicleManufacturer::class)->findAll();
|
||||
foreach ($vmanus as $vmanu)
|
||||
{
|
||||
$name = $vmanu->getName();
|
||||
$this->vmanu_hash[$name] = $vmanu;
|
||||
}
|
||||
}
|
||||
|
||||
protected function loadVehicleMakes()
|
||||
{
|
||||
$this->vmake_hash = [];
|
||||
|
||||
$vmakes = $this->em->getRepository(Vehicle::class)->findAll();
|
||||
foreach ($vmakes as $vmake)
|
||||
{
|
||||
$manufacturer = $vmake->getManufacturer()->getName();
|
||||
$make = $vmake->getMake();
|
||||
|
||||
$this->vmake_hash[$manufacturer][$make] = $vmake;
|
||||
}
|
||||
}
|
||||
|
||||
protected function normalizeName($name)
|
||||
{
|
||||
$normalized_key = trim(strtolower($name));
|
||||
|
||||
return $normalized_key;
|
||||
}
|
||||
|
||||
protected function cleanPlateNumber($plate_number)
|
||||
{
|
||||
// remove spaces and make upper case
|
||||
$clean_plate_number = strtoupper(str_replace(' ' , '', $plate_number));
|
||||
|
||||
return $clean_plate_number;
|
||||
}
|
||||
}
|
||||
164
src/Command/ImportCMBLegacyJobOrderCommand.php
Normal file
164
src/Command/ImportCMBLegacyJobOrderCommand.php
Normal file
|
|
@ -0,0 +1,164 @@
|
|||
<?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 Doctrine\ORM\EntityManagerInterface;
|
||||
|
||||
use App\Entity\CMBLegacyJobOrderRow;
|
||||
|
||||
class ImportCMBLegacyJobOrderCommand extends Command
|
||||
{
|
||||
// field index in csv file
|
||||
const F_INDEX = 0;
|
||||
const F_CREATED_DATE = 1;
|
||||
const F_CASE_NO = 2;
|
||||
const F_INSURER = 3;
|
||||
const F_VEHICLE_NO = 4;
|
||||
const F_CAR_MODEL = 5;
|
||||
const F_NATURE_OF_CALL = 6;
|
||||
const F_SERVICE_NEEDED = 7;
|
||||
const F_LOCATION = 8;
|
||||
const F_STATE = 9;
|
||||
const F_DRIVER = 10;
|
||||
const F_TRUCK = 11;
|
||||
const F_WORKSHOP_ARRIVAL_TIME = 12;
|
||||
const F_STATUS = 13;
|
||||
const F_CUSTOMER_NAME = 14;
|
||||
const F_CUSTOMER_PHONE_NO = 15;
|
||||
const F_OUR_REFERENCE = 16;
|
||||
const F_ODOMETER = 17;
|
||||
const F_BATT_MODEL = 18;
|
||||
const F_BATT_SIZE = 19;
|
||||
const F_BATT_TRADE_IN = 20;
|
||||
const F_REPLACED_BY = 21;
|
||||
const F_REMARK = 22;
|
||||
const F_SATISFACTION = 23;
|
||||
|
||||
protected $em;
|
||||
|
||||
public function __construct(EntityManagerInterface $em)
|
||||
{
|
||||
$this->em = $em;
|
||||
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
public function configure()
|
||||
{
|
||||
$this->setName('cmblegacyjoborderdata:import')
|
||||
->setDescription('Retrieve from a CSV file CarFix data.')
|
||||
->setHelp('Creates legacy job order entries based on data from imported CSV.')
|
||||
->addArgument('file', InputArgument::REQUIRED, 'Path to the CSV file.');
|
||||
}
|
||||
|
||||
public function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$csv_file = $input->getArgument('file');
|
||||
|
||||
// attempt to open file
|
||||
try
|
||||
{
|
||||
$fh = fopen($csv_file, "r");
|
||||
}
|
||||
catch (Exception $e)
|
||||
{
|
||||
throw new Exception('The file "' . $csv_file . '" could be read.');
|
||||
}
|
||||
|
||||
// get entity manager
|
||||
$em = $this->em;
|
||||
|
||||
$row_num = 0;
|
||||
error_log('Processing CarFix data csv file...');
|
||||
while (($fields = fgetcsv($fh)) !== false)
|
||||
{
|
||||
if ($row_num < 1)
|
||||
{
|
||||
$row_num++;
|
||||
continue;
|
||||
}
|
||||
|
||||
// get the information
|
||||
$entry_num = trim($fields[self::F_INDEX]);
|
||||
$date_create = trim($fields[self::F_CREATED_DATE]);
|
||||
$case_number = trim($fields[self::F_CASE_NO]);
|
||||
$insurer = trim($fields[self::F_INSURER]);
|
||||
$vehicle_number = trim($fields[self::F_VEHICLE_NO]);
|
||||
$car_model = trim($fields[self::F_CAR_MODEL]);
|
||||
$nature_of_call = trim($fields[self::F_NATURE_OF_CALL]);
|
||||
$service_needed = trim($fields[self::F_SERVICE_NEEDED]);
|
||||
$location = trim($fields[self::F_LOCATION]);
|
||||
$state = trim($fields[self::F_STATE]);
|
||||
$driver = trim($fields[self::F_DRIVER]);
|
||||
$truck = trim($fields[self::F_TRUCK]);
|
||||
$workshop_arrival_time = trim($fields[self::F_WORKSHOP_ARRIVAL_TIME]);
|
||||
$status = trim($fields[self::F_STATUS]);
|
||||
$customer_name = trim($fields[self::F_CUSTOMER_NAME]);
|
||||
$customer_mobile = trim($fields[self::F_CUSTOMER_PHONE_NO]);
|
||||
$reference = trim($fields[self::F_OUR_REFERENCE]);
|
||||
$odometer = trim($fields[self::F_ODOMETER]);
|
||||
$batt_model = trim($fields[self::F_BATT_MODEL]);
|
||||
$batt_size = trim($fields[self::F_BATT_SIZE]);
|
||||
$trade_in = trim($fields[self::F_BATT_TRADE_IN]);
|
||||
$replaced_by = trim($fields[self::F_REPLACED_BY]);
|
||||
$remark = trim($fields[self::F_REMARK]);
|
||||
$satisfaction = trim($fields[self::F_SATISFACTION]);
|
||||
|
||||
$data_entry = $this->processEntry($entry_num, $date_create, $case_number, $insurer, $vehicle_number, $car_model,
|
||||
$nature_of_call, $service_needed, $location, $state, $driver, $truck, $workshop_arrival_time,
|
||||
$status, $customer_name, $customer_mobile, $reference, $odometer, $batt_model, $batt_size,
|
||||
$trade_in, $replaced_by, $remark, $satisfaction);
|
||||
|
||||
$legacy_data = new CMBLegacyJobOrderRow();
|
||||
$legacy_data->setData($data_entry);
|
||||
|
||||
$this->em->persist($legacy_data);
|
||||
}
|
||||
|
||||
$this->em->flush();
|
||||
$this->em->clear();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
protected function processEntry($entry_num, $date_create, $case_number, $insurer, $vehicle_number, $car_model,
|
||||
$nature_of_call, $service_needed, $location, $state, $driver, $truck, $workshop_arrival_time,
|
||||
$status, $customer_name, $customer_mobile, $reference, $odometer, $batt_model, $batt_size,
|
||||
$trade_in, $replaced_by, $remark, $satisfaction)
|
||||
{
|
||||
$data_entry = [
|
||||
'entry_num' => $entry_num,
|
||||
'created_date' => $date_create,
|
||||
'case_number' => $case_number,
|
||||
'insurer' => $insurer,
|
||||
'vehicle_number' => $vehicle_number,
|
||||
'car_model' => $car_model,
|
||||
'nature_of_call' => $nature_of_call,
|
||||
'service_needed' => $service_needed,
|
||||
'location' => $location,
|
||||
'state' => $state,
|
||||
'driver' => $driver,
|
||||
'truck' => $truck,
|
||||
'workshop_arrival_time' => $workshop_arrival_time,
|
||||
'status' => $status,
|
||||
'customer_name' => $customer_name,
|
||||
'customer_phone_number' => $customer_mobile,
|
||||
'reference' => $reference,
|
||||
'odometer' => $odometer,
|
||||
'batt_model' => $batt_model,
|
||||
'batt_size' => $batt_size,
|
||||
'batt_trade_in' => $trade_in,
|
||||
'replaced_by' => $replaced_by,
|
||||
'remark' => $remark,
|
||||
'satisfaction' => $satisfaction,
|
||||
];
|
||||
|
||||
return $data_entry;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -222,8 +222,8 @@ class ImportCMBVehicleCompatibilityCommand extends Command
|
|||
//}
|
||||
|
||||
// vehicle info
|
||||
$manufacturer = trim($fields[self::F_VEHICLE_MANUFACTURER]);
|
||||
$make = trim($fields[self::F_VEHICLE_MAKE]);
|
||||
$manufacturer = trim(strtolower($fields[self::F_VEHICLE_MANUFACTURER]));
|
||||
$make = trim(strtolower($fields[self::F_VEHICLE_MAKE]));
|
||||
$year = trim($fields[self::F_VEHICLE_YEAR]);
|
||||
|
||||
// vehicle data
|
||||
|
|
@ -298,7 +298,7 @@ class ImportCMBVehicleCompatibilityCommand extends Command
|
|||
// save to db
|
||||
$vehicle_manufacturer = new VehicleManufacturer();
|
||||
|
||||
$vehicle_manufacturer->setName($name);
|
||||
$vehicle_manufacturer->setName(strtoupper($name));
|
||||
|
||||
$this->em->persist($vehicle_manufacturer);
|
||||
$this->em->flush();
|
||||
|
|
@ -332,7 +332,7 @@ class ImportCMBVehicleCompatibilityCommand extends Command
|
|||
}
|
||||
|
||||
$vehicle->setManufacturer($vmanu)
|
||||
->setMake($make)
|
||||
->setMake(strtoupper($make))
|
||||
->setModelYearFrom($year_from)
|
||||
->setModelYearTo($year_to);
|
||||
|
||||
|
|
@ -412,7 +412,7 @@ class ImportCMBVehicleCompatibilityCommand extends Command
|
|||
$vmanus = $this->em->getRepository(VehicleManufacturer::class)->findAll();
|
||||
foreach ($vmanus as $vmanu)
|
||||
{
|
||||
$name = $vmanu->getName();
|
||||
$name = $this->normalizeName($vmanu->getName());
|
||||
$this->vmanu_hash[$name] = $vmanu;
|
||||
}
|
||||
}
|
||||
|
|
@ -425,7 +425,7 @@ class ImportCMBVehicleCompatibilityCommand extends Command
|
|||
foreach ($vmakes as $vmake)
|
||||
{
|
||||
$manufacturer = $vmake->getManufacturer()->getName();
|
||||
$make = $vmake->getMake();
|
||||
$make = $this->normalizeName($vmake->getMake());
|
||||
|
||||
$this->vmake_hash[$manufacturer][$make] = $vmake;
|
||||
}
|
||||
|
|
|
|||
545
src/Command/MigrateCMBLegacyJobOrderCommand.php
Normal file
545
src/Command/MigrateCMBLegacyJobOrderCommand.php
Normal file
|
|
@ -0,0 +1,545 @@
|
|||
<?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 Doctrine\ORM\EntityManagerInterface;
|
||||
|
||||
use App\Entity\CMBLegacyJobOrderRow;
|
||||
use App\Entity\CMBLegacyJobOrder;
|
||||
use App\Entity\VehicleManufacturer;
|
||||
use App\Entity\Vehicle;
|
||||
use App\Entity\BatteryManufacturer;
|
||||
use App\Entity\BatteryModel;
|
||||
use App\Entity\BatterySize;
|
||||
use App\Entity\Battery;
|
||||
use App\Entity\Customer;
|
||||
use App\Entity\CustomerVehicle;
|
||||
|
||||
use App\Ramcar\CMBServiceType;
|
||||
use App\Ramcar\JOStatus;
|
||||
use App\Ramcar\FuelType;
|
||||
use App\Ramcar\VehicleStatusCondition;
|
||||
|
||||
use DateTime;
|
||||
|
||||
class MigrateCMBLegacyJobOrderCommand extends Command
|
||||
{
|
||||
/*
|
||||
id = 'entry_num'
|
||||
trans_date = 'created_date'
|
||||
case_number = 'case_number'
|
||||
insurer = 'insurer'
|
||||
plate_number = 'vehicle_number'
|
||||
car_brand and car_make = split the 'car_model'
|
||||
nature_of_call = nature_of_call
|
||||
trans_type = 'service_needed'
|
||||
address = 'location'
|
||||
address = 'state'
|
||||
driver = 'driver'
|
||||
truck = 'truck'
|
||||
workshop_arrival_time => 'workshop_arrival_time'
|
||||
status = 'status'
|
||||
cust_name = 'customer_name'
|
||||
cust_mobile = 'customer_phone_number'
|
||||
reference = 'reference'
|
||||
odometer = 'odometer'
|
||||
batt_model = 'batt_model'
|
||||
batt_size = 'batt_size'
|
||||
is_trade_in = 'batt_trade_in'
|
||||
replaced_by = 'replaced_by'
|
||||
remarks = 'remark'
|
||||
satisfaction => 'satisfaction'
|
||||
*/
|
||||
protected $em;
|
||||
|
||||
protected $bmanu_hash;
|
||||
protected $bmodel_hash;
|
||||
protected $bsize_hash;
|
||||
protected $batt_hash;
|
||||
|
||||
protected $vmanu_hash;
|
||||
protected $vmake_hash;
|
||||
|
||||
protected $cv_hash;
|
||||
|
||||
public function __construct(EntityManagerInterface $em)
|
||||
{
|
||||
$this->em = $em;
|
||||
|
||||
// load existing battery data
|
||||
$this->loadBatteryManufacturers();
|
||||
$this->loadBatteryModels();
|
||||
$this->loadBatterySizes();
|
||||
$this->loadBatteries();
|
||||
|
||||
// load existing vehicle data
|
||||
$this->loadVehicleManufacturers();
|
||||
$this->loadVehicleMakes();
|
||||
|
||||
// load existing customer vehicle data
|
||||
$this->loadCustomerVehicles();
|
||||
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
public function configure()
|
||||
{
|
||||
$this->setName('cmblegacyjoborderdata:migrate')
|
||||
->setDescription('Retrieve database cmb legacy job orders and insert into job order.')
|
||||
->setHelp('Creates job orders based on data from imported CSV.')
|
||||
->addArgument('output_file', InputArgument::REQUIRED, 'Path to the output CSV file of the entries not added.');
|
||||
}
|
||||
|
||||
public function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$csv_file = $input->getArgument('output_file');
|
||||
|
||||
// attempt to open file
|
||||
try
|
||||
{
|
||||
$fh = fopen($csv_file, "w");
|
||||
}
|
||||
catch (Exception $e)
|
||||
{
|
||||
throw new Exception('The file "' . $csv_file . '" could be opened.');
|
||||
}
|
||||
|
||||
// get all legacy job orders
|
||||
$query = $this->em->createQuery('SELECT legacy_jo_row FROM App\Entity\CMBLegacyJobOrderRow legacy_jo_row');
|
||||
$result = $query->iterate();
|
||||
|
||||
$invalid_entries = [];
|
||||
$added_entries = 0;
|
||||
$total_entries = 0;
|
||||
$total_inv_entries = 0;
|
||||
foreach ($result as $row)
|
||||
{
|
||||
$entry = $row[0];
|
||||
$jo_entry = $entry->getData();
|
||||
|
||||
$total_entries++;
|
||||
|
||||
// get the entry information
|
||||
$entry_num = $jo_entry['entry_num'];
|
||||
$date_create = $jo_entry['created_date'];
|
||||
$case_number = $jo_entry['case_number'];
|
||||
$insurer = $jo_entry['insurer'];
|
||||
$plate_number = $this->cleanPlateNumber($jo_entry['vehicle_number']);
|
||||
$car_model = $this->normalizeName($jo_entry['car_model']);
|
||||
$nature_of_call = $jo_entry['nature_of_call'];
|
||||
$service_needed = $jo_entry['service_needed'];
|
||||
$location = $jo_entry['location'];
|
||||
$state = $jo_entry['state'];
|
||||
$driver = $jo_entry['driver'];
|
||||
$truck = $jo_entry['truck'];
|
||||
$workshop_arrival_time = $jo_entry['workshop_arrival_time'];
|
||||
$status = $jo_entry['status'];
|
||||
$customer_name = $jo_entry['customer_name'];
|
||||
$customer_mobile = $jo_entry['customer_phone_number'];
|
||||
$reference = $jo_entry['reference'];
|
||||
$odometer = $jo_entry['odometer'];
|
||||
$batt_model = $this->normalizeName($jo_entry['batt_model']);
|
||||
$batt_size = $this->normalizeName($jo_entry['batt_size']);
|
||||
$batt_trade_in = $jo_entry['batt_trade_in'];
|
||||
$replaced_by = $jo_entry['replaced_by'];
|
||||
$remark = $jo_entry['remark'];
|
||||
$satisfaction = $jo_entry['satisfaction'];
|
||||
|
||||
// check vehicle info if valid
|
||||
$v_status = $this->processVehicleInfo($car_model);
|
||||
if ($v_status != null)
|
||||
{
|
||||
//error_log($v_status . ' ' . $car_model);
|
||||
$invalid_entries[] = $this->addInvalidEntry($entry_num, $date_create, $case_number, $insurer, $plate_number, $car_model,
|
||||
$nature_of_call, $service_needed, $location, $state, $driver, $truck, $workshop_arrival_time,
|
||||
$status, $customer_name, $customer_mobile, $reference, $odometer, $batt_model, $batt_size,
|
||||
$batt_trade_in, $replaced_by, $remark, $satisfaction, $v_status);
|
||||
|
||||
$total_inv_entries++;
|
||||
// move to next entry
|
||||
continue;
|
||||
}
|
||||
|
||||
// check battery info if valid
|
||||
$batt_status = $this->processBatteryInfo($batt_model, $batt_size);
|
||||
if ($batt_status != null)
|
||||
{
|
||||
//error_log($batt_status . ' ' . $batt_model . ' ' . $batt_size);
|
||||
$invalid_entries[] = $this->addInvalidEntry($entry_num, $date_create, $case_number, $insurer, $plate_number, $car_model,
|
||||
$nature_of_call, $service_needed, $location, $state, $driver, $truck, $workshop_arrival_time,
|
||||
$status, $customer_name, $customer_mobile, $reference, $odometer, $batt_model, $batt_size,
|
||||
$batt_trade_in, $replaced_by, $remark, $satisfaction, $batt_status);
|
||||
|
||||
$total_inv_entries++;
|
||||
// move to next entry
|
||||
continue;
|
||||
}
|
||||
|
||||
// create job order
|
||||
$cmb_legacy_jo = new CMBLegacyJobOrder();
|
||||
|
||||
// date_create
|
||||
$created_date = DateTime::createFromFormat("d-m-Y H:i", $date_create);
|
||||
$cmb_legacy_jo->setTransDate($created_date);
|
||||
|
||||
// parse vehicle info
|
||||
// get vehicle from hash
|
||||
$v_array = explode(' ', $car_model);
|
||||
|
||||
// manufacturer
|
||||
$v_manufacturer = trim($v_array[0]);
|
||||
|
||||
// get model
|
||||
$model_info = '';
|
||||
$v_model = '';
|
||||
for ($i = 1; $i < count($v_array); $i++)
|
||||
{
|
||||
$model_info = $model_info . ' ' . trim($v_array[$i]);
|
||||
}
|
||||
|
||||
$v_model = trim($model_info);
|
||||
|
||||
// delivery address = location + state
|
||||
$delivery_address = $location . ', ' . $state;
|
||||
|
||||
// check if trade in
|
||||
$trade_in = false;
|
||||
if (strtolower($batt_trade_in) == 'yes')
|
||||
$trade_in = true;
|
||||
|
||||
$cmb_legacy_jo->setCaseNumber($case_number)
|
||||
->setInsurer($insurer)
|
||||
->setNatureOfCall($nature_of_call)
|
||||
->setTransType($service_needed)
|
||||
->setCarBrand(strtoupper($v_manufacturer))
|
||||
->setCarMake(strtoupper($v_model))
|
||||
->setCustName($customer_name)
|
||||
->setCustMobile($customer_mobile)
|
||||
->setAddress($delivery_address)
|
||||
->setDriver($driver)
|
||||
->setTruck($truck)
|
||||
->setWorkshopArrivalTime($workshop_arrival_time)
|
||||
->setPlateNumber($plate_number)
|
||||
->setStatus($status)
|
||||
->setReference($reference)
|
||||
->setOdometer($odometer)
|
||||
->setBatteryModel(strtoupper($batt_model))
|
||||
->setBatterySize(strtoupper($batt_size))
|
||||
->setIsTradeIn($trade_in)
|
||||
->setReplacedBy($replaced_by)
|
||||
->setSatisfaction($satisfaction);
|
||||
|
||||
// plate number == vehicle_number. Use as key to cv_hash
|
||||
// check if plate number has been added
|
||||
if (!isset($this->cv_hash[$plate_number]))
|
||||
{
|
||||
$cust = $this->addCustomer($customer_name, $customer_mobile);
|
||||
$cv = $this->addCustomerVehicle($plate_number, $car_model, $cust);
|
||||
}
|
||||
|
||||
$this->em->persist($cmb_legacy_jo);
|
||||
$this->em->detach($row[0]);
|
||||
|
||||
$added_entries++;
|
||||
}
|
||||
|
||||
$this->em->flush();
|
||||
$this->em->clear();
|
||||
|
||||
// output the entries that were not added
|
||||
if (count($invalid_entries) > 0)
|
||||
{
|
||||
fputcsv($fh, [
|
||||
'Entry Num',
|
||||
'Created Date',
|
||||
'Case Number',
|
||||
'Insurer',
|
||||
'Vehicle Number',
|
||||
'Car Model',
|
||||
'Nature of Call',
|
||||
'Service Needed',
|
||||
'Location',
|
||||
'State',
|
||||
'Driver',
|
||||
'Truck',
|
||||
'Workshop Arrival Time',
|
||||
'Status',
|
||||
'Customer Name',
|
||||
'Customer Phone Number',
|
||||
'Reference',
|
||||
'Odometer',
|
||||
'Batt Model',
|
||||
'Batt Size',
|
||||
'Batt Trade In',
|
||||
'Replaced By',
|
||||
'Remark',
|
||||
'Satisfaction',
|
||||
'Reason',
|
||||
|
||||
]);
|
||||
|
||||
foreach($invalid_entries as $row)
|
||||
{
|
||||
fputcsv($fh, $row);
|
||||
}
|
||||
}
|
||||
|
||||
fclose($fh);
|
||||
|
||||
error_log('Processed ' . $total_entries . ' entries.');
|
||||
error_log('Added ' . $added_entries . ' entries.');
|
||||
error_log('Did not add ' . $total_inv_entries . ' entries.');
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
protected function processVehicleInfo($car_model)
|
||||
{
|
||||
// vehicle manufacturer is the first entry
|
||||
// vehicle model is the 2nd entry + whatever follows
|
||||
$v_array = explode(' ', $car_model);
|
||||
|
||||
// manufacturer
|
||||
$v_manufacturer = trim($v_array[0]);
|
||||
|
||||
// get model
|
||||
$model_info = '';
|
||||
$v_model = '';
|
||||
for ($i = 1; $i < count($v_array); $i++)
|
||||
{
|
||||
$model_info = $model_info . ' ' . trim($v_array[$i]);
|
||||
}
|
||||
|
||||
$v_model = trim($model_info);
|
||||
//error_log($v_manufacturer . ' ' . $v_model);
|
||||
|
||||
// check if manufacturer is in hash
|
||||
if (!isset($this->vmanu_hash[$v_manufacturer]))
|
||||
{
|
||||
//error_log($v_manufacturer . ' invalid.');
|
||||
return 'Vehicle manufacturer not in system.';
|
||||
}
|
||||
|
||||
// check if manufacturer and make is in hash
|
||||
if (!isset($this->vmake_hash[$v_manufacturer][$v_model]))
|
||||
{
|
||||
//error_log($v_model . ' invalid.');
|
||||
return 'Vehicle model not in system.';
|
||||
}
|
||||
// car model info valid
|
||||
return null;
|
||||
}
|
||||
|
||||
protected function processBatteryInfo($batt_model, $batt_size)
|
||||
{
|
||||
// check if battery model is in hash
|
||||
if (!isset($this->bmodel_hash[$batt_model]))
|
||||
return 'Battery model not in system.';
|
||||
|
||||
// check if battery size is in hash
|
||||
if (!isset($this->bsize_hash[$batt_size]))
|
||||
return 'Battery size not in system.';
|
||||
|
||||
// battery info valid
|
||||
return null;
|
||||
}
|
||||
|
||||
protected function addInvalidEntry($entry_num, $date_create, $case_number, $insurer, $plate_number, $car_model,
|
||||
$nature_of_call, $service_needed, $location, $state, $driver, $truck, $workshop_arrival_time,
|
||||
$status, $customer_name, $customer_mobile, $reference, $odometer, $batt_model, $batt_size,
|
||||
$batt_trade_in, $replaced_by, $remark, $satisfaction, $v_status)
|
||||
{
|
||||
$inv_entry = [
|
||||
'number' => $entry_num,
|
||||
'created_date' => $date_create,
|
||||
'case_number' => $case_number,
|
||||
'insurer' => $insurer,
|
||||
'vehicle_number' => $plate_number,
|
||||
'car_model' => $car_model,
|
||||
'nature_of_call' => $nature_of_call,
|
||||
'service_needed' => $service_needed,
|
||||
'location' => $location,
|
||||
'state' => $state,
|
||||
'driver' => $driver,
|
||||
'truck' => $truck,
|
||||
'workshop_arrival_time' => $workshop_arrival_time,
|
||||
'status' => $status,
|
||||
'customer_name' => $customer_name,
|
||||
'customer_phone_number' => $customer_mobile,
|
||||
'reference' => $reference,
|
||||
'odometer' => $odometer,
|
||||
'batt_model' => $batt_model,
|
||||
'batt_size' => $batt_size,
|
||||
'batt_trade_in' => $batt_trade_in,
|
||||
'replaced_by' => $replaced_by,
|
||||
'remark' => $remark,
|
||||
'satisfaction' => $satisfaction,
|
||||
'reason' => $v_status,
|
||||
];
|
||||
|
||||
return $inv_entry;
|
||||
}
|
||||
|
||||
protected function addCustomer($name, $mobile)
|
||||
{
|
||||
$new_cust = new Customer();
|
||||
|
||||
$new_cust->setFirstName($name)
|
||||
->setLastName('')
|
||||
->setPhoneMobile($mobile);
|
||||
|
||||
$this->em->persist($new_cust);
|
||||
|
||||
return $new_cust;
|
||||
}
|
||||
|
||||
protected function addCustomerVehicle($plate_num, $car_model, $customer)
|
||||
{
|
||||
$new_cv = new CustomerVehicle();
|
||||
|
||||
// get vehicle from hash
|
||||
$v_array = explode(' ', $car_model);
|
||||
|
||||
// manufacturer
|
||||
$v_manufacturer = trim($v_array[0]);
|
||||
|
||||
// get model
|
||||
$model_info = '';
|
||||
$v_model = '';
|
||||
for ($i = 1; $i < count($v_array); $i++)
|
||||
{
|
||||
$model_info = $model_info . ' ' . trim($v_array[$i]);
|
||||
}
|
||||
|
||||
$v_model = trim($model_info);
|
||||
|
||||
$vehicle = $this->vmake_hash[$v_manufacturer][$v_model];
|
||||
|
||||
$new_cv->setCustomer($customer)
|
||||
->setPlateNumber($plate_num)
|
||||
->setStatusCondition(VehicleStatusCondition::BRAND_NEW)
|
||||
->setModelYear('')
|
||||
->setColor('')
|
||||
->setFuelType(FuelType::GAS)
|
||||
->setHasMotoliteBattery(true)
|
||||
->setVehicle($vehicle);
|
||||
|
||||
$this->em->persist($new_cv);
|
||||
|
||||
// add customer vehicle to cv_hash
|
||||
$this->cv_hash[$plate_num] = $new_cv;
|
||||
|
||||
return $new_cv;
|
||||
}
|
||||
|
||||
protected function loadBatteryManufacturers()
|
||||
{
|
||||
$this->bmanu_hash = [];
|
||||
|
||||
$batt_manufacturers = $this->em->getRepository(BatteryManufacturer::class)->findAll();
|
||||
foreach ($batt_manufacturers as $batt_manu)
|
||||
{
|
||||
$name = $this->normalizeName($batt_manu->getName());
|
||||
$this->bmanu_hash[$name] = $batt_manu;
|
||||
}
|
||||
}
|
||||
|
||||
protected function loadBatteryModels()
|
||||
{
|
||||
$this->bmodel_hash = [];
|
||||
|
||||
$batt_models = $this->em->getRepository(BatteryModel::class)->findAll();
|
||||
foreach ($batt_models as $batt_model)
|
||||
{
|
||||
$name = $this->normalizeName($batt_model->getName());
|
||||
$this->bmodel_hash[$name] = $batt_model;
|
||||
}
|
||||
}
|
||||
|
||||
protected function loadBatterySizes()
|
||||
{
|
||||
$this->bsize_hash = [];
|
||||
|
||||
$batt_sizes = $this->em->getRepository(BatterySize::class)->findAll();
|
||||
foreach ($batt_sizes as $batt_size)
|
||||
{
|
||||
$name = $this->normalizeName($batt_size->getName());
|
||||
$this->bsize_hash[$name] = $batt_size;
|
||||
}
|
||||
}
|
||||
|
||||
protected function loadBatteries()
|
||||
{
|
||||
$this->batt_hash = [];
|
||||
|
||||
$batts = $this->em->getRepository(Battery::class)->findAll();
|
||||
foreach ($batts as $batt)
|
||||
{
|
||||
$brand = $this->normalizeName($batt->getManufacturer()->getName());
|
||||
$model = $this->normalizeName($batt->getModel()->getName());
|
||||
$size = $this->normalizeName($batt->getSize()->getName());
|
||||
|
||||
$this->batt_hash[$brand][$model][$size] = $batt;
|
||||
}
|
||||
}
|
||||
|
||||
protected function loadVehicleManufacturers()
|
||||
{
|
||||
$this->vmanu_hash = [];
|
||||
|
||||
$vmanus = $this->em->getRepository(VehicleManufacturer::class)->findAll();
|
||||
foreach ($vmanus as $vmanu)
|
||||
{
|
||||
$name = $this->normalizeName($vmanu->getName());
|
||||
$this->vmanu_hash[$name] = $vmanu;
|
||||
}
|
||||
}
|
||||
|
||||
protected function loadVehicleMakes()
|
||||
{
|
||||
$this->vmake_hash = [];
|
||||
|
||||
$vmakes = $this->em->getRepository(Vehicle::class)->findAll();
|
||||
foreach ($vmakes as $vmake)
|
||||
{
|
||||
$manufacturer = $this->normalizeName($vmake->getManufacturer()->getName());
|
||||
$make = $this->normalizeName($vmake->getMake());
|
||||
|
||||
$this->vmake_hash[$manufacturer][$make] = $vmake;
|
||||
}
|
||||
}
|
||||
|
||||
protected function loadCustomerVehicles()
|
||||
{
|
||||
$this->cv_hash = [];
|
||||
|
||||
$cvs = $this->em->getRepository(CustomerVehicle::class)->findAll();
|
||||
foreach ($cvs as $cv)
|
||||
{
|
||||
$plate_number = $this->cleanPlateNumber($cv->getPlateNumber());
|
||||
|
||||
$this->cv_hash[$plate_number] = $cv;
|
||||
}
|
||||
}
|
||||
|
||||
protected function normalizeName($name)
|
||||
{
|
||||
$normalized_key = trim(strtolower($name));
|
||||
|
||||
return $normalized_key;
|
||||
}
|
||||
|
||||
protected function cleanPlateNumber($plate_number)
|
||||
{
|
||||
// remove spaces and make upper case
|
||||
$clean_plate_number = strtoupper(str_replace(' ' , '', $plate_number));
|
||||
|
||||
return $clean_plate_number;
|
||||
}
|
||||
|
||||
}
|
||||
111
src/Controller/NotificationController.php
Normal file
111
src/Controller/NotificationController.php
Normal file
|
|
@ -0,0 +1,111 @@
|
|||
<?php
|
||||
|
||||
namespace App\Controller;
|
||||
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\HttpFoundation\JsonResponse;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Catalyst\MenuBundle\Annotation\Menu;
|
||||
use DateTime;
|
||||
use DateInterval;
|
||||
use App\Entity\Notification;
|
||||
|
||||
class NotificationController extends AbstractController
|
||||
{
|
||||
// TODO: security
|
||||
public function ajaxList(EntityManagerInterface $em)
|
||||
{
|
||||
/*
|
||||
$date = new DateTime();
|
||||
$date->sub(new DateInterval('PT10M'));
|
||||
$notifs = [
|
||||
[
|
||||
'id' => 1,
|
||||
'type' => 'jo_new',
|
||||
'date' => $date->format('Y-m-d\TH:i:s.000P'),
|
||||
'text' => 'Sample incoming job order',
|
||||
'link' => '#',
|
||||
], [
|
||||
'id' => 2,
|
||||
'type' => 'rider_accept',
|
||||
'date' => $date->format('Y-m-d\TH:i:s.000P'),
|
||||
'text' => 'Sample rider has accepted job order',
|
||||
'link' => '#',
|
||||
], [
|
||||
'id' => 3,
|
||||
'type' => 'jo_cancel',
|
||||
'date' => $date->format('Y-m-d\TH:i:s.000P'),
|
||||
'text' => 'Customer has cancelled job order.',
|
||||
'link' => '#',
|
||||
], [
|
||||
'id' => 3,
|
||||
'type' => 'rider_reject',
|
||||
'date' => $date->format('Y-m-d\TH:i:s.000P'),
|
||||
'text' => 'Rider has rejected job order. Job order needs to be reassigned.',
|
||||
'link' => '#',
|
||||
],
|
||||
];
|
||||
$sample_data = [
|
||||
'count' => 4,
|
||||
'notifications' => $notifs,
|
||||
];
|
||||
*/
|
||||
|
||||
$notifs = $em->getRepository(Notification::class)->findBy(['user_id' => 0]);
|
||||
$notif_data = [];
|
||||
|
||||
$unread_count = 0;
|
||||
foreach ($notifs as $notif)
|
||||
{
|
||||
if (!($notif->isRead()))
|
||||
$unread_count++;
|
||||
|
||||
$notif_data[] = [
|
||||
'id' => $notif->getID(),
|
||||
'type' => 'jo_new',
|
||||
'is_read' => $notif->isRead(),
|
||||
'is_fresh' => $notif->isFresh(),
|
||||
'date' => $notif->getDateCreate()->format('Y-m-d\TH:i:s.000P'),
|
||||
'text' => $notif->getMessage(),
|
||||
'link' => $notif->getURL(),
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
$sample_data = [
|
||||
'count' => count($notif_data),
|
||||
'unread_count' => $unread_count,
|
||||
'notifications' => $notif_data,
|
||||
];
|
||||
|
||||
$res = new JsonResponse($sample_data);
|
||||
|
||||
return $res;
|
||||
}
|
||||
|
||||
// TODO: security
|
||||
public function ajaxUpdate(EntityManagerInterface $em, Request $req)
|
||||
{
|
||||
$notif_id = $req->request->get('id');
|
||||
error_log($notif_id);
|
||||
|
||||
$notif = $em->getRepository(Notification::class)->find($notif_id);
|
||||
|
||||
if ($notif != null)
|
||||
{
|
||||
// TODO: fresh is if unread and still within x hours
|
||||
// but for now fresh and unread are both the same
|
||||
$notif->setIsRead(true);
|
||||
$notif->setIsFresh(false);
|
||||
|
||||
$em->persist($notif);
|
||||
$em->flush();
|
||||
}
|
||||
|
||||
$res = new JsonResponse();
|
||||
|
||||
return $res;
|
||||
}
|
||||
}
|
||||
|
|
@ -616,11 +616,11 @@ class RiderController extends Controller
|
|||
return $response;
|
||||
}
|
||||
|
||||
public function ajaxRiderName(EntityManagerInterface $em, Request $req)
|
||||
/**
|
||||
* @ParamConverter("rider", class="App\Entity\Rider")
|
||||
*/
|
||||
public function ajaxRiderName(EntityManagerInterface $em, Rider $rider)
|
||||
{
|
||||
$rider_id = $req->query->get('id');
|
||||
|
||||
$rider = $em->getRepository(Rider::class)->find($rider_id);
|
||||
$rider_name = '';
|
||||
if ($rider != null)
|
||||
$rider_name = $rider->getFullName();
|
||||
|
|
@ -629,4 +629,5 @@ class RiderController extends Controller
|
|||
'rider_name' => $rider_name,
|
||||
]);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
395
src/Entity/CMBLegacyJobOrder.php
Normal file
395
src/Entity/CMBLegacyJobOrder.php
Normal file
|
|
@ -0,0 +1,395 @@
|
|||
<?php
|
||||
|
||||
namespace App\Entity;
|
||||
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
use DateTime;
|
||||
|
||||
/**
|
||||
* @ORM\Entity
|
||||
* @ORM\Table(name="cmb_legacy_job_order")
|
||||
*/
|
||||
class CMBLegacyJobOrder
|
||||
{
|
||||
// legacy internal id
|
||||
/**
|
||||
* @ORM\Id
|
||||
* @ORM\Column(type="integer")
|
||||
* @ORM\GeneratedValue(strategy="AUTO")
|
||||
*/
|
||||
protected $id;
|
||||
|
||||
/**
|
||||
* @ORM\Column(type="datetime")
|
||||
*/
|
||||
protected $trans_date;
|
||||
|
||||
/**
|
||||
* @ORM\Column(type="string", length=30, nullable=true)
|
||||
*/
|
||||
protected $case_number;
|
||||
|
||||
/**
|
||||
* @ORM\Column(type="string", length=30, nullable=true)
|
||||
*/
|
||||
protected $insurer;
|
||||
|
||||
/**
|
||||
* @ORM\Column(type="string", length=20, nullable=true)
|
||||
*/
|
||||
protected $plate_number;
|
||||
|
||||
/**
|
||||
* @ORM\Column(type="string", length=50, nullable=true)
|
||||
*/
|
||||
protected $trans_type;
|
||||
|
||||
/**
|
||||
* @ORM\Column(type="string", length=20, nullable=true)
|
||||
*/
|
||||
protected $car_brand;
|
||||
|
||||
/**
|
||||
* @ORM\Column(type="string", length=50, nullable=true)
|
||||
*/
|
||||
protected $car_make;
|
||||
|
||||
/**
|
||||
* @ORM\Column(type="string", length=30, nullable=true)
|
||||
*/
|
||||
protected $nature_of_call;
|
||||
|
||||
/**
|
||||
* @ORM\Column(type="string", length=400, nullable=true)
|
||||
*/
|
||||
protected $address;
|
||||
|
||||
/**
|
||||
* @ORM\Column(type="string", length=50, nullable=true)
|
||||
*/
|
||||
protected $driver;
|
||||
|
||||
/**
|
||||
* @ORM\Column(type="string", length=20, nullable=true)
|
||||
*/
|
||||
protected $truck;
|
||||
|
||||
/**
|
||||
* @ORM\Column(type="integer", nullable=true)
|
||||
*/
|
||||
protected $workshop_arrival_time;
|
||||
|
||||
/**
|
||||
* @ORM\Column(type="string", length=50, nullable=true)
|
||||
*/
|
||||
protected $status;
|
||||
|
||||
/**
|
||||
* @ORM\Column(type="string", length=100, nullable=true)
|
||||
*/
|
||||
protected $cust_name;
|
||||
|
||||
/**
|
||||
* @ORM\Column(type="string", length=50, nullable=true)
|
||||
*/
|
||||
protected $cust_mobile;
|
||||
|
||||
/**
|
||||
* @ORM\Column(type="string", length=20, nullable=true)
|
||||
*/
|
||||
protected $reference;
|
||||
|
||||
/**
|
||||
* @ORM\Column(type="integer", nullable=true)
|
||||
*/
|
||||
protected $odometer;
|
||||
|
||||
/**
|
||||
* @ORM\Column(type="string", length=50, nullable=true)
|
||||
*/
|
||||
protected $batt_model;
|
||||
|
||||
/**
|
||||
* @ORM\Column(type="string", length=50, nullable=true)
|
||||
*/
|
||||
protected $batt_size;
|
||||
|
||||
/**
|
||||
* @ORM\Column(type="boolean", options={"default":false})
|
||||
*/
|
||||
protected $flag_trade_in;
|
||||
|
||||
/**
|
||||
* @ORM\Column(type="string", length=50, nullable=true)
|
||||
*/
|
||||
protected $replaced_by;
|
||||
|
||||
/**
|
||||
* @ORM\Column(type="string", length=4000, nullable=true)
|
||||
*/
|
||||
protected $remarks;
|
||||
|
||||
/**
|
||||
* @ORM\Column(type="string", length=50, nullable=true)
|
||||
*/
|
||||
protected $satisfaction;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->trans_date = new DateTime();
|
||||
}
|
||||
|
||||
public function setID($id)
|
||||
{
|
||||
$this->id = $id;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getID()
|
||||
{
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
public function setTransDate(DateTime $trans_date)
|
||||
{
|
||||
$this->trans_date = $trans_date;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getTransDate()
|
||||
{
|
||||
return $this->trans_date;
|
||||
}
|
||||
|
||||
public function setTransType($trans_type)
|
||||
{
|
||||
$this->trans_type = $trans_type;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getTransType()
|
||||
{
|
||||
return $this->trans_type;
|
||||
}
|
||||
|
||||
public function setCaseNumber($case_number)
|
||||
{
|
||||
$this->case_number = $case_number;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getCaseNumber()
|
||||
{
|
||||
return $this->case_number;
|
||||
}
|
||||
|
||||
public function setInsurer($insurer)
|
||||
{
|
||||
$this->insurer = $insurer;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getInsurer()
|
||||
{
|
||||
return $this->insurer;
|
||||
}
|
||||
|
||||
public function setNatureOfCall($nature_of_call)
|
||||
{
|
||||
$this->nature_of_call = $nature_of_call;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getNatureOfCall()
|
||||
{
|
||||
return $this->nature_of_call;
|
||||
}
|
||||
|
||||
public function setPlateNumber($plate_number)
|
||||
{
|
||||
$this->plate_number = $plate_number;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getPlateNumber()
|
||||
{
|
||||
return $this->plate_number;
|
||||
}
|
||||
|
||||
public function setCarBrand($car_brand)
|
||||
{
|
||||
$this->car_brand = $car_brand;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getCarBrand()
|
||||
{
|
||||
return $this->car_brand;
|
||||
}
|
||||
|
||||
public function setCarMake($car_make)
|
||||
{
|
||||
$this->car_make = $car_make;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getCarMake()
|
||||
{
|
||||
return $this->car_make;
|
||||
}
|
||||
|
||||
public function setAddress($address)
|
||||
{
|
||||
$this->address = $address;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getAddress()
|
||||
{
|
||||
return $this->address;
|
||||
}
|
||||
|
||||
public function setDriver($driver)
|
||||
{
|
||||
$this->driver = $driver;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getDriver()
|
||||
{
|
||||
return $this->driver;
|
||||
}
|
||||
|
||||
public function setTruck($truck)
|
||||
{
|
||||
$this->truck = $truck;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getTruck()
|
||||
{
|
||||
return $this->truck;
|
||||
}
|
||||
|
||||
public function setWorkshopArrivalTime($workshop_arrival_time)
|
||||
{
|
||||
$this->workshop_arrival_time = $workshop_arrival_time;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getWorkshopArrivalTime()
|
||||
{
|
||||
return $this->workshop_arrival_time;
|
||||
}
|
||||
|
||||
public function setStatus($status)
|
||||
{
|
||||
$this->status = $status;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getStatus()
|
||||
{
|
||||
return $this->status;
|
||||
}
|
||||
|
||||
public function setCustName($cust_name)
|
||||
{
|
||||
$this->cust_name = $cust_name;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getCustName()
|
||||
{
|
||||
return $this->cust_name;
|
||||
}
|
||||
|
||||
public function setCustMobile($cust_mobile)
|
||||
{
|
||||
$this->cust_mobile = $cust_mobile;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getCustMobile()
|
||||
{
|
||||
return $this->cust_mobile;
|
||||
}
|
||||
|
||||
public function setReference($reference)
|
||||
{
|
||||
$this->reference = $reference;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getReference()
|
||||
{
|
||||
return $this->reference;
|
||||
}
|
||||
|
||||
public function setOdometer($odometer)
|
||||
{
|
||||
$this->odometer = $odometer;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getOdometer()
|
||||
{
|
||||
return $this->odometer;
|
||||
}
|
||||
|
||||
public function setBatteryModel($batt_model)
|
||||
{
|
||||
$this->batt_model = $batt_model;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getBatteryModel()
|
||||
{
|
||||
return $this->batt_model;
|
||||
}
|
||||
|
||||
public function setBatterySize($batt_size)
|
||||
{
|
||||
$this->batt_size = $batt_size;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getBatterySize()
|
||||
{
|
||||
return $this->batt_size;
|
||||
}
|
||||
|
||||
public function setIsTradeIn($flag_trade_in = true)
|
||||
{
|
||||
$this->flag_trade_in = $flag_trade_in;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function isTradeIn()
|
||||
{
|
||||
return $this->flag_trade_in;
|
||||
}
|
||||
|
||||
public function setReplacedBy($replaced_by)
|
||||
{
|
||||
$this->replaced_by = $replaced_by;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getReplacedBy()
|
||||
{
|
||||
return $this->replaced_by;
|
||||
}
|
||||
|
||||
public function setSatisfaction($satisfaction)
|
||||
{
|
||||
$this->satisfaction = $satisfaction;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getSatisfaction()
|
||||
{
|
||||
return $this->satisfaction;
|
||||
}
|
||||
|
||||
}
|
||||
57
src/Entity/CMBLegacyJobOrderRow.php
Normal file
57
src/Entity/CMBLegacyJobOrderRow.php
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
<?php
|
||||
|
||||
namespace App\Entity;
|
||||
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
|
||||
/**
|
||||
* @ORM\Entity
|
||||
* @ORM\Table(name="cmb_legacy_job_order_row")
|
||||
*/
|
||||
class CMBLegacyJobOrderRow
|
||||
{
|
||||
// unique id
|
||||
/**
|
||||
* @ORM\Id
|
||||
* @ORM\Column(type="integer")
|
||||
* @ORM\GeneratedValue(strategy="AUTO")
|
||||
*/
|
||||
protected $id;
|
||||
|
||||
// data from csv file
|
||||
/**
|
||||
* @ORM\Column(type="json")
|
||||
*/
|
||||
protected $data;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->data = [];
|
||||
}
|
||||
|
||||
public function addData($id, $value)
|
||||
{
|
||||
$this->data[$id] = $value;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setData(array $data_array)
|
||||
{
|
||||
$this->data = $data_array;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getDataById($id)
|
||||
{
|
||||
// return null if we don't have it
|
||||
if (!isset($this->data[$id]))
|
||||
return null;
|
||||
|
||||
return $this->data[$id];
|
||||
}
|
||||
|
||||
public function getData()
|
||||
{
|
||||
return $this->data;
|
||||
}
|
||||
}
|
||||
|
|
@ -34,7 +34,7 @@ class Customer
|
|||
|
||||
// first name
|
||||
/**
|
||||
* @ORM\Column(type="string", length=80)
|
||||
* @ORM\Column(type="string", length=100)
|
||||
* @Assert\NotBlank()
|
||||
*/
|
||||
protected $first_name;
|
||||
|
|
@ -42,7 +42,6 @@ class Customer
|
|||
// last name
|
||||
/**
|
||||
* @ORM\Column(type="string", length=80)
|
||||
* @Assert\NotBlank()
|
||||
*/
|
||||
protected $last_name;
|
||||
|
||||
|
|
@ -66,7 +65,7 @@ class Customer
|
|||
|
||||
// mobile phone
|
||||
/**
|
||||
* @ORM\Column(type="string", length=30)
|
||||
* @ORM\Column(type="string", length=50)
|
||||
*/
|
||||
protected $phone_mobile;
|
||||
|
||||
|
|
|
|||
148
src/Entity/Notification.php
Normal file
148
src/Entity/Notification.php
Normal file
|
|
@ -0,0 +1,148 @@
|
|||
<?php
|
||||
|
||||
namespace App\Entity;
|
||||
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
use Doctrine\Common\Collections\ArrayCollection;
|
||||
|
||||
use DateTime;
|
||||
|
||||
/**
|
||||
* @ORM\Entity
|
||||
* @ORM\Table(name="notification", indexes={@ORM\Index(columns={"user_id"})})
|
||||
*/
|
||||
class Notification
|
||||
{
|
||||
// unique id
|
||||
/**
|
||||
* @ORM\Id
|
||||
* @ORM\Column(type="integer")
|
||||
* @ORM\GeneratedValue(strategy="AUTO")
|
||||
*/
|
||||
protected $id;
|
||||
|
||||
// date / time created
|
||||
/**
|
||||
* @ORM\Column(type="datetime")
|
||||
*/
|
||||
protected $date_create;
|
||||
|
||||
// index by user for fast fetching
|
||||
// user id (don't link, don't need to)
|
||||
/**
|
||||
* @ORM\Column(type="integer")
|
||||
*/
|
||||
protected $user_id;
|
||||
|
||||
// icon
|
||||
/**
|
||||
* @ORM\Column(type="string", length=25)
|
||||
*/
|
||||
protected $icon;
|
||||
|
||||
// message text
|
||||
/**
|
||||
* @ORM\Column(type="string", length=300)
|
||||
*/
|
||||
protected $message;
|
||||
|
||||
/**
|
||||
* @ORM\Column(type="string", length=180)
|
||||
*/
|
||||
protected $url;
|
||||
|
||||
// has user read the notification
|
||||
/**
|
||||
* @ORM\Column(type="boolean")
|
||||
*/
|
||||
protected $flag_read;
|
||||
|
||||
// is this still a fresh notification for the user
|
||||
/**
|
||||
* @ORM\Column(type="boolean")
|
||||
*/
|
||||
protected $flag_fresh;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->date_create = new DateTime();
|
||||
$this->flag_read = false;
|
||||
$this->flag_fresh = true;
|
||||
}
|
||||
|
||||
public function getID()
|
||||
{
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
public function getDateCreate()
|
||||
{
|
||||
return $this->date_create;
|
||||
}
|
||||
|
||||
public function setUserID($user_id)
|
||||
{
|
||||
$this->user_id = $user_id;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getUserID()
|
||||
{
|
||||
return $this->user_id;
|
||||
}
|
||||
|
||||
public function setIcon($icon)
|
||||
{
|
||||
$this->icon = $icon;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getIcon()
|
||||
{
|
||||
return $this->icon;
|
||||
}
|
||||
|
||||
public function setMessage($message)
|
||||
{
|
||||
$this->message = $message;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getMessage()
|
||||
{
|
||||
return $this->message;
|
||||
}
|
||||
|
||||
public function setURL($url)
|
||||
{
|
||||
$this->url = $url;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getURL()
|
||||
{
|
||||
return $this->url;
|
||||
}
|
||||
|
||||
public function setIsRead($bool = true)
|
||||
{
|
||||
$this->flag_read = $bool;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function isRead()
|
||||
{
|
||||
return $this->flag_read;
|
||||
}
|
||||
|
||||
public function setIsFresh($bool = true)
|
||||
{
|
||||
$this->flag_fresh = $bool;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function isFresh()
|
||||
{
|
||||
return $this->flag_fresh;
|
||||
}
|
||||
}
|
||||
|
|
@ -449,6 +449,7 @@ class CMBJobOrderHandler implements JobOrderHandlerInterface
|
|||
|
||||
$jo = $em->getRepository(JobOrder::class)->find($id);
|
||||
$old_jo_status = null;
|
||||
$old_rider = null;
|
||||
if (empty($jo))
|
||||
{
|
||||
// new job order
|
||||
|
|
@ -456,7 +457,8 @@ class CMBJobOrderHandler implements JobOrderHandlerInterface
|
|||
}
|
||||
else
|
||||
{
|
||||
//$old_rider = $jo->getRider();
|
||||
// need to get old values of rider and status to see if we need to change JO status or not
|
||||
$old_rider = $jo->getRider();
|
||||
$old_jo_status = $jo->getStatus();
|
||||
}
|
||||
|
||||
|
|
@ -639,10 +641,25 @@ class CMBJobOrderHandler implements JobOrderHandlerInterface
|
|||
// and JO is already in_transit or in_progress?
|
||||
|
||||
// retain old jo status if it's an update JO
|
||||
if ($old_jo_status != null)
|
||||
$jo->setStatus($old_jo_status);
|
||||
else
|
||||
// check old rider if it is also a reassignment
|
||||
// old_rider should be null if JO has been rejected
|
||||
if (($old_rider == null) && ($old_jo_status == null))
|
||||
$jo->setStatus(JOStatus::ASSIGNED);
|
||||
else
|
||||
{
|
||||
error_log('not a new JO');
|
||||
$new_rider = $jo->getRider();
|
||||
if ($new_rider != $old_rider)
|
||||
{
|
||||
// reassignment
|
||||
$jo->setStatus(JOStatus::ASSIGNED);
|
||||
}
|
||||
else
|
||||
{
|
||||
if ($old_jo_status != null)
|
||||
$jo->setStatus($old_jo_status);
|
||||
}
|
||||
}
|
||||
|
||||
// check if user is null, meaning call to create came from API
|
||||
if ($user != null)
|
||||
|
|
@ -702,8 +719,8 @@ class CMBJobOrderHandler implements JobOrderHandlerInterface
|
|||
$em->flush();
|
||||
|
||||
// check if JO has been reassigned
|
||||
//if ($old_rider != $rider)
|
||||
if ($old_jo_status != $jo->getStatus())
|
||||
if ($old_rider != $jo->getRider())
|
||||
//if ($old_jo_status != $jo->getStatus())
|
||||
{
|
||||
error_log('JO has been reassigned');
|
||||
// TODO: refactor later
|
||||
|
|
|
|||
48
src/Service/NotificationManager.php
Normal file
48
src/Service/NotificationManager.php
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
<?php
|
||||
|
||||
namespace App\Service;
|
||||
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use App\Service\RedisClientProvider;
|
||||
use App\Entity\Notification;
|
||||
|
||||
class NotificationManager
|
||||
{
|
||||
protected $redis;
|
||||
protected $redis_mqtt_key;
|
||||
protected $em;
|
||||
|
||||
const NOTIF_KEY = 'user/{user_id}/notification';
|
||||
|
||||
public function __construct(RedisClientProvider $redis_prov, EntityManagerInterface $em, $redis_mqtt_key)
|
||||
{
|
||||
$this->redis = $redis_prov->getRedisClient();
|
||||
$this->redis_mqtt_key = $redis_mqtt_key;
|
||||
$this->em = $em;
|
||||
}
|
||||
|
||||
// set user_id to 0 for all
|
||||
public function sendNotification($user_id, $msg, $url)
|
||||
{
|
||||
// send mqtt
|
||||
$chan = $this->getChannel($user_id);
|
||||
$data = $chan . '|' . $msg;
|
||||
$this->redis->lpush($this->redis_mqtt_key, $data);
|
||||
|
||||
// create notif
|
||||
$notif = new Notification();
|
||||
$notif->setUserID($user_id)
|
||||
->setIcon('')
|
||||
->setMessage($msg)
|
||||
->setURL($url);
|
||||
|
||||
// save to db
|
||||
$this->em->persist($notif);
|
||||
$this->em->flush();
|
||||
}
|
||||
|
||||
protected function getChannel($user_id)
|
||||
{
|
||||
return str_replace('{user_id}', $user_id, self::NOTIF_KEY );
|
||||
}
|
||||
}
|
||||
|
|
@ -5,6 +5,7 @@ namespace App\Service\RiderAPIHandler;
|
|||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\Security\Core\Encoder\EncoderFactoryInterface;
|
||||
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
|
||||
|
||||
use App\Ramcar\CMBServiceType;
|
||||
use App\Ramcar\TradeInType;
|
||||
|
|
@ -23,6 +24,7 @@ use App\Service\WarrantyHandler;
|
|||
use App\Service\JobOrderHandlerInterface;
|
||||
use App\Service\InvoiceGeneratorInterface;
|
||||
use App\Service\RiderTracker;
|
||||
use App\Service\NotificationManager;
|
||||
|
||||
use App\Entity\RiderSession;
|
||||
use App\Entity\Rider;
|
||||
|
|
@ -53,13 +55,16 @@ class CMBRiderAPIHandler implements RiderAPIHandlerInterface
|
|||
protected $ic;
|
||||
protected $session;
|
||||
protected $upload_dir;
|
||||
protected $nm;
|
||||
protected $router;
|
||||
|
||||
public function __construct(EntityManagerInterface $em, RedisClientProvider $redis,
|
||||
EncoderFactoryInterface $ef, RiderCache $rcache,
|
||||
string $country_code, MQTTClient $mclient,
|
||||
WarrantyHandler $wh, JobOrderHandlerInterface $jo_handler,
|
||||
InvoiceGeneratorInterface $ic, string $upload_dir,
|
||||
RiderTracker $rider_tracker)
|
||||
RiderTracker $rider_tracker, NotificationManager $nm,
|
||||
UrlGeneratorInterface $router)
|
||||
{
|
||||
$this->em = $em;
|
||||
$this->redis = $redis;
|
||||
|
|
@ -72,6 +77,8 @@ class CMBRiderAPIHandler implements RiderAPIHandlerInterface
|
|||
$this->ic = $ic;
|
||||
$this->upload_dir = $upload_dir;
|
||||
$this->rider_tracker = $rider_tracker;
|
||||
$this->nm = $nm;
|
||||
$this->router = $router;
|
||||
|
||||
// one device = one session, since we have control over the devices
|
||||
// when a rider logs in, we just change the rider assigned to the device
|
||||
|
|
@ -208,7 +215,7 @@ class CMBRiderAPIHandler implements RiderAPIHandlerInterface
|
|||
$rider_id = $rider->getID();
|
||||
// cache rider location (default to hub)
|
||||
// TODO: figure out longitude / latitude default
|
||||
$this->rcache->addActiveRider($rider_id, 0, 0);
|
||||
// $this->rcache->addActiveRider($rider_id, 0, 0);
|
||||
|
||||
// TODO: log rider logging in
|
||||
|
||||
|
|
@ -278,7 +285,7 @@ class CMBRiderAPIHandler implements RiderAPIHandlerInterface
|
|||
$rider->setActive(false);
|
||||
|
||||
// remove from cache
|
||||
$this->rcache->removeActiveRider($rider->getID());
|
||||
// $this->rcache->removeActiveRider($rider->getID());
|
||||
|
||||
// remove rider from session
|
||||
$this->session->setRider(null);
|
||||
|
|
@ -311,6 +318,11 @@ class CMBRiderAPIHandler implements RiderAPIHandlerInterface
|
|||
|
||||
$this->em->flush();
|
||||
|
||||
// cache rider location (default to hub)
|
||||
// TODO: figure out longitude / latitude default
|
||||
$rider_id = $rider->getID();
|
||||
$this->rcache->addActiveRider($rider_id, 0, 0);
|
||||
|
||||
// send mqtt event to put rider on map
|
||||
// get rider coordinates from redis
|
||||
$coord = $this->rider_tracker->getRiderLocation($rider->getID());
|
||||
|
|
@ -360,6 +372,9 @@ class CMBRiderAPIHandler implements RiderAPIHandlerInterface
|
|||
|
||||
$this->em->flush();
|
||||
|
||||
// remove from cache
|
||||
$this->rcache->removeActiveRider($rider->getID());
|
||||
|
||||
// send mqtt event to remove rider from map
|
||||
$channel = 'rider/' . $rider->getID() . '/availability';
|
||||
$payload = [
|
||||
|
|
@ -1069,6 +1084,10 @@ class CMBRiderAPIHandler implements RiderAPIHandlerInterface
|
|||
|
||||
$this->em->flush();
|
||||
|
||||
// notification
|
||||
$notif_url = $this->router->generate('jo_onestep_edit_form', ['id' => $jo->getID()]);
|
||||
$this->nm->sendNotification(0, 'Job order has been cancelled by rider.', $notif_url);
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
|
|
@ -1154,6 +1173,9 @@ class CMBRiderAPIHandler implements RiderAPIHandlerInterface
|
|||
|
||||
$this->mclient->publish($channel, $rider_status);
|
||||
|
||||
$notif_url = $this->router->generate('jo_onestep_edit_form', ['id' => $jo->getID()]);
|
||||
$this->nm->sendNotification(0, 'Job order has been rejected by rider.', $notif_url);
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2,6 +2,8 @@
|
|||
|
||||
namespace App\Service;
|
||||
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
|
||||
use App\Service\RedisClientProvider;
|
||||
use App\Entity\Rider;
|
||||
|
||||
|
|
@ -10,12 +12,14 @@ class RiderCache
|
|||
protected $redis;
|
||||
protected $loc_key;
|
||||
protected $status_key;
|
||||
protected $em;
|
||||
|
||||
public function __construct(RedisClientProvider $redis_prov, $loc_key, $status_key)
|
||||
public function __construct(EntityManagerInterface $em, RedisClientProvider $redis_prov, $loc_key, $status_key)
|
||||
{
|
||||
$this->redis = $redis_prov->getRedisClient();
|
||||
$this->loc_key = $loc_key;
|
||||
$this->status_key = $status_key;
|
||||
$this->em = $em;
|
||||
}
|
||||
|
||||
public function addActiveRider($id, $lat, $lng)
|
||||
|
|
@ -46,10 +50,15 @@ class RiderCache
|
|||
$lng = $data[1][0];
|
||||
$lat = $data[1][1];
|
||||
|
||||
$locs[$id] = [
|
||||
'longitude' => $lng,
|
||||
'latitude' => $lat,
|
||||
];
|
||||
// get rider details so we can check for availability
|
||||
$rider = $this->getRiderDetails($id);
|
||||
if ($rider != null)
|
||||
{
|
||||
$locs[$id] = [
|
||||
'longitude' => $lng,
|
||||
'latitude' => $lat,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
// error_log(print_r($all_riders, true));
|
||||
|
|
@ -73,4 +82,17 @@ class RiderCache
|
|||
{
|
||||
$this->redis->hincrby($this->status_key, $id, -1);
|
||||
}
|
||||
|
||||
protected function getRiderDetails($id)
|
||||
{
|
||||
$rider = $this->em->getRepository(Rider::class)->find($id);
|
||||
if ($rider == null)
|
||||
return null;
|
||||
|
||||
// return only if available
|
||||
if ($rider->isAvailable())
|
||||
return $rider;
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -448,217 +448,50 @@
|
|||
<div id="m_header_topbar" class="m-topbar m-stack m-stack--ver m-stack--general">
|
||||
<div class="m-stack__item m-topbar__nav-wrapper">
|
||||
<ul class="m-topbar__nav m-nav m-nav--inline">
|
||||
<!--
|
||||
<li class="m-nav__item m-topbar__notifications m-topbar__notifications--img m-dropdown m-dropdown--large m-dropdown--header-bg-fill m-dropdown--arrow m-dropdown--align-center m-dropdown--mobile-full-width" data-dropdown-toggle="click" data-dropdown-persistent="true">
|
||||
<a href="#" class="m-nav__link m-dropdown__toggle" id="m_topbar_notification_icon">
|
||||
<span class="m-nav__link-badge m-badge m-badge--dot m-badge--dot-small m-badge--danger"></span>
|
||||
<span class="m-nav__link-icon">
|
||||
<i class="flaticon-music-2"></i>
|
||||
</span>
|
||||
</a>
|
||||
<div class="m-dropdown__wrapper">
|
||||
<span class="m-dropdown__arrow m-dropdown__arrow--center"></span>
|
||||
<div class="m-dropdown__inner">
|
||||
<div class="m-dropdown__header m--align-center" style="background: url(assets/app/media/img/misc/notification_bg.jpg); background-size: cover;">
|
||||
<span class="m-dropdown__header-title">
|
||||
9 New
|
||||
</span>
|
||||
<span class="m-dropdown__header-subtitle">
|
||||
User Notifications
|
||||
</span>
|
||||
</div>
|
||||
<div class="m-dropdown__body">
|
||||
<div class="m-dropdown__content">
|
||||
<ul class="nav nav-tabs m-tabs m-tabs-line m-tabs-line--brand" role="tablist">
|
||||
<li class="nav-item m-tabs__item">
|
||||
<a class="nav-link m-tabs__link active" data-toggle="tab" href="#topbar_notifications_notifications" role="tab">
|
||||
Alerts
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item m-tabs__item">
|
||||
<a class="nav-link m-tabs__link" data-toggle="tab" href="#topbar_notifications_events" role="tab">
|
||||
Events
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item m-tabs__item">
|
||||
<a class="nav-link m-tabs__link" data-toggle="tab" href="#topbar_notifications_logs" role="tab">
|
||||
Logs
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
<div class="tab-content">
|
||||
<div class="tab-pane active" id="topbar_notifications_notifications" role="tabpanel">
|
||||
<div class="m-scrollable" data-scrollable="true" data-max-height="250" data-mobile-max-height="200">
|
||||
<div class="m-list-timeline m-list-timeline--skin-light">
|
||||
<div class="m-list-timeline__items">
|
||||
<div class="m-list-timeline__item">
|
||||
<span class="m-list-timeline__badge -m-list-timeline__badge--state-success"></span>
|
||||
<span class="m-list-timeline__text">
|
||||
12 new users registered
|
||||
</span>
|
||||
<span class="m-list-timeline__time">
|
||||
Just now
|
||||
</span>
|
||||
</div>
|
||||
<div class="m-list-timeline__item">
|
||||
<span class="m-list-timeline__badge"></span>
|
||||
<span class="m-list-timeline__text">
|
||||
System shutdown
|
||||
<span class="m-badge m-badge--success m-badge--wide">
|
||||
pending
|
||||
</span>
|
||||
</span>
|
||||
<span class="m-list-timeline__time">
|
||||
14 mins
|
||||
</span>
|
||||
</div>
|
||||
<div class="m-list-timeline__item">
|
||||
<span class="m-list-timeline__badge"></span>
|
||||
<span class="m-list-timeline__text">
|
||||
New invoice received
|
||||
</span>
|
||||
<span class="m-list-timeline__time">
|
||||
20 mins
|
||||
</span>
|
||||
</div>
|
||||
<div class="m-list-timeline__item">
|
||||
<span class="m-list-timeline__badge"></span>
|
||||
<span class="m-list-timeline__text">
|
||||
DB overloaded 80%
|
||||
<span class="m-badge m-badge--info m-badge--wide">
|
||||
settled
|
||||
</span>
|
||||
</span>
|
||||
<span class="m-list-timeline__time">
|
||||
1 hr
|
||||
</span>
|
||||
</div>
|
||||
<div class="m-list-timeline__item">
|
||||
<span class="m-list-timeline__badge"></span>
|
||||
<span class="m-list-timeline__text">
|
||||
System error -
|
||||
<a href="#" class="m-link">
|
||||
Check
|
||||
</a>
|
||||
</span>
|
||||
<span class="m-list-timeline__time">
|
||||
2 hrs
|
||||
</span>
|
||||
</div>
|
||||
<div class="m-list-timeline__item m-list-timeline__item--read">
|
||||
<span class="m-list-timeline__badge"></span>
|
||||
<span href="" class="m-list-timeline__text">
|
||||
New order received
|
||||
<span class="m-badge m-badge--danger m-badge--wide">
|
||||
urgent
|
||||
</span>
|
||||
</span>
|
||||
<span class="m-list-timeline__time">
|
||||
7 hrs
|
||||
</span>
|
||||
</div>
|
||||
<div class="m-list-timeline__item m-list-timeline__item--read">
|
||||
<span class="m-list-timeline__badge"></span>
|
||||
<span class="m-list-timeline__text">
|
||||
Production server down
|
||||
</span>
|
||||
<span class="m-list-timeline__time">
|
||||
3 hrs
|
||||
</span>
|
||||
</div>
|
||||
<div class="m-list-timeline__item">
|
||||
<span class="m-list-timeline__badge"></span>
|
||||
<span class="m-list-timeline__text">
|
||||
Production server up
|
||||
</span>
|
||||
<span class="m-list-timeline__time">
|
||||
5 hrs
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="tab-pane" id="topbar_notifications_events" role="tabpanel">
|
||||
<div class="m-scrollable" m-scrollabledata-scrollable="true" data-max-height="250" data-mobile-max-height="200">
|
||||
<div class="m-list-timeline m-list-timeline--skin-light">
|
||||
<div class="m-list-timeline__items">
|
||||
<div class="m-list-timeline__item">
|
||||
<span class="m-list-timeline__badge m-list-timeline__badge--state1-success"></span>
|
||||
<a href="" class="m-list-timeline__text">
|
||||
New order received
|
||||
</a>
|
||||
<span class="m-list-timeline__time">
|
||||
Just now
|
||||
</span>
|
||||
</div>
|
||||
<div class="m-list-timeline__item">
|
||||
<span class="m-list-timeline__badge m-list-timeline__badge--state1-danger"></span>
|
||||
<a href="" class="m-list-timeline__text">
|
||||
New invoice received
|
||||
</a>
|
||||
<span class="m-list-timeline__time">
|
||||
20 mins
|
||||
</span>
|
||||
</div>
|
||||
<div class="m-list-timeline__item">
|
||||
<span class="m-list-timeline__badge m-list-timeline__badge--state1-success"></span>
|
||||
<a href="" class="m-list-timeline__text">
|
||||
Production server up
|
||||
</a>
|
||||
<span class="m-list-timeline__time">
|
||||
5 hrs
|
||||
</span>
|
||||
</div>
|
||||
<div class="m-list-timeline__item">
|
||||
<span class="m-list-timeline__badge m-list-timeline__badge--state1-info"></span>
|
||||
<a href="" class="m-list-timeline__text">
|
||||
New order received
|
||||
</a>
|
||||
<span class="m-list-timeline__time">
|
||||
7 hrs
|
||||
</span>
|
||||
</div>
|
||||
<div class="m-list-timeline__item">
|
||||
<span class="m-list-timeline__badge m-list-timeline__badge--state1-info"></span>
|
||||
<a href="" class="m-list-timeline__text">
|
||||
System shutdown
|
||||
</a>
|
||||
<span class="m-list-timeline__time">
|
||||
11 mins
|
||||
</span>
|
||||
</div>
|
||||
<div class="m-list-timeline__item">
|
||||
<span class="m-list-timeline__badge m-list-timeline__badge--state1-info"></span>
|
||||
<a href="" class="m-list-timeline__text">
|
||||
Production server down
|
||||
</a>
|
||||
<span class="m-list-timeline__time">
|
||||
3 hrs
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="tab-pane" id="topbar_notifications_logs" role="tabpanel">
|
||||
<div class="m-stack m-stack--ver m-stack--general" style="min-height: 180px;">
|
||||
<div class="m-stack__item m-stack__item--center m-stack__item--middle">
|
||||
<span class="">
|
||||
All caught up!
|
||||
<br>
|
||||
No new logs.
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
-->
|
||||
|
||||
<li class="m-nav__item m-topbar__notifications m-topbar__notifications--img m-dropdown m-dropdown--large m-dropdown--header-bg-fill m-dropdown--arrow m-dropdown--align-right m-dropdown--mobile-full-width" data-dropdown-toggle="click" data-dropdown-persistent="true">
|
||||
<a href="#" class="m-nav__link m-dropdown__toggle" id="m_topbar_notification_icon">
|
||||
<span class="m-nav__link-badge m-badge m-badge--dot m-badge--dot-small m-badge--danger"></span>
|
||||
<span class="m-nav__link-icon">
|
||||
<i class="flaticon-music-2"></i>
|
||||
</span>
|
||||
</a>
|
||||
<div class="m-dropdown__wrapper">
|
||||
<span class="m-dropdown__arrow m-dropdown__arrow--right m-dropdown__arrow--adjust"></span>
|
||||
<div class="m-dropdown__inner">
|
||||
<div class="m-dropdown__header m--align-center" style="background: url(/assets/app/media/img/misc/notification_bg.jpg); background-size: cover;">
|
||||
<span class="m-dropdown__header-title">
|
||||
<span id="notif-count">-</span> New
|
||||
</span>
|
||||
<span class="m-dropdown__header-subtitle">
|
||||
User Notifications
|
||||
</span>
|
||||
</div>
|
||||
<div class="m-dropdown__body">
|
||||
<div class="m-dropdown__content">
|
||||
<div class="m-scrollable" data-scrollable="true" data-max-height="250" data-mobile-max-height="200">
|
||||
<div class="m-list-timeline m-list-timeline--skin-light">
|
||||
<div id="notif-body" class="m-list-timeline__items">
|
||||
<div class="m-list-timeline__item">
|
||||
<span class="m-list-timeline__badge -m-list-timeline__badge--state-success"></span>
|
||||
<span class="m-list-timeline__text">
|
||||
<a href="#">This is a notification</a>
|
||||
</span>
|
||||
<span class="m-list-timeline__time">
|
||||
Just now
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
|
||||
|
||||
|
||||
<li class="m-nav__item m-topbar__user-profile m-topbar__user-profile--img m-dropdown m-dropdown--medium m-dropdown--arrow m-dropdown--header-bg-fill m-dropdown--align-right m-dropdown--mobile-full-width m-dropdown--skin-light" data-dropdown-toggle="click">
|
||||
<a href="#" class="m-nav__link m-dropdown__toggle">
|
||||
<span class="m-topbar__userpic">
|
||||
|
|
@ -718,6 +551,8 @@
|
|||
</div>
|
||||
</div>
|
||||
</li>
|
||||
|
||||
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -770,6 +605,26 @@
|
|||
<!--end::Page Snippets -->
|
||||
|
||||
<!--begin::Extra Scripts -->
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/paho-mqtt/1.0.1/mqttws31.min.js" type="text/javascript"></script>
|
||||
<script src="/assets/js/moment.min.js" type="text/javascript"></script>
|
||||
<script src="/assets/js/notification.js" type="text/javascript"></script>
|
||||
<script>
|
||||
// notifications
|
||||
var notif = new NotificationHandler({
|
||||
'notif_ajax_url': '{{ url('notification_ajax_list') }}',
|
||||
'notif_ajax_update_url': '{{ url('notification_ajax_update') }}',
|
||||
'icons': {
|
||||
'jo_new': 'flaticon-placeholder-3 kt-font-brand',
|
||||
'jo_cancel': 'fa fa-times-circle kt-font-danger',
|
||||
'rider_accept': 'fa fa-motorcycle kt-font-success',
|
||||
'rider_reject': 'fa fa-exclamation-triangle kt-font-danger'
|
||||
},
|
||||
'default_icon': 'fa fa-asterisk kt-font-brand',
|
||||
});
|
||||
notif.clearAll();
|
||||
notif.loadAll();
|
||||
notif.listen('{{ app.user.id }}', '{{ mqtt_host }}', {{ mqtt_port }}, {{ ssl_enable }});
|
||||
</script>
|
||||
{% block scripts %}{% endblock %}
|
||||
<!--end::Extra Scripts -->
|
||||
</body>
|
||||
|
|
|
|||
|
|
@ -35,7 +35,9 @@ function initMap(r_markers, c_markers, icons) {
|
|||
'zoom': 13,
|
||||
'rider_popup_url': '/riders/[id]/popup',
|
||||
'cust_popup_url': '/job-order/[id]/popup',
|
||||
'icons': icons
|
||||
'icons': icons,
|
||||
'rider_name_url': '/riders/[id]/name',
|
||||
'rider_availability_url': '{{ absolute_url('/riders/[id]/available')|raw }}'
|
||||
};
|
||||
|
||||
var dashmap = new DashboardMap(options, r_markers, c_markers);
|
||||
|
|
@ -55,7 +57,7 @@ function initEventHandler(dashmap, icons, ssl) {
|
|||
'jo_location': 'jo/+/location',
|
||||
'jo_status': 'jo/+/status',
|
||||
'jo_origin': 'jo/+/origin',
|
||||
'rider_availability': 'rider/+/availability'
|
||||
'rider_availability': 'rider/+/availability',
|
||||
},
|
||||
};
|
||||
|
||||
|
|
|
|||
15
utils/clear_jo_data.sql
Normal file
15
utils/clear_jo_data.sql
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
delete from jo_event;
|
||||
delete from invoice_item;
|
||||
delete from invoice;
|
||||
delete from ticket;
|
||||
|
||||
set foreign_key_checks = 0;
|
||||
delete from job_order;
|
||||
set foreign_key_checks = 1;
|
||||
|
||||
delete from mobile_session;
|
||||
delete from customer_vehicle;
|
||||
delete from customer;
|
||||
delete from warranty;
|
||||
|
||||
update rider set active_jo_id = null;
|
||||
Loading…
Reference in a new issue