1815 lines
60 KiB
PHP
1815 lines
60 KiB
PHP
<?php
|
|
|
|
namespace App\Controller\TAPI;
|
|
|
|
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
|
|
use Symfony\Component\HttpFoundation\Request;
|
|
use Symfony\Component\Dotenv\Dotenv;
|
|
|
|
use Doctrine\ORM\Query;
|
|
use Doctrine\ORM\EntityManagerInterface;
|
|
|
|
use CrEOF\Spatial\PHP\Types\Geometry\Point;
|
|
|
|
use Catalyst\APIBundle\Controller\APIController;
|
|
use Catalyst\APIBundle\Response\APIResponse;
|
|
|
|
use App\Ramcar\WarrantyClass;
|
|
use App\Ramcar\JOStatus;
|
|
use App\Ramcar\AdvanceOrderSlot;
|
|
use App\Ramcar\AutoAssignStatus;
|
|
use App\Ramcar\InvoiceCriteria;
|
|
use App\Ramcar\ServiceType;
|
|
use App\Ramcar\TransactionOrigin;
|
|
use App\Ramcar\TradeInType;
|
|
use App\Ramcar\JOEventType;
|
|
use App\Ramcar\HubCriteria;
|
|
use App\Ramcar\ModeOfPayment;
|
|
use App\Ramcar\APIRiderStatus;
|
|
use App\Ramcar\VehicleStatusCondition;
|
|
use App\Ramcar\FuelType;
|
|
use App\Ramcar\DeliveryStatus;
|
|
|
|
use App\Service\InvoiceGeneratorInterface;
|
|
use App\Service\RisingTideGateway;
|
|
use App\Service\MQTTClient;
|
|
use App\Service\GeofenceTracker;
|
|
use App\Service\InventoryManager;
|
|
use App\Service\RiderAssignmentHandlerInterface;
|
|
use App\Service\HubSelector;
|
|
use App\Service\HubDistributor;
|
|
use App\Service\HubFilterLogger;
|
|
use App\Service\HubFilteringGeoChecker;
|
|
use App\Service\RiderTracker;
|
|
use App\Service\PromoLogger;
|
|
use App\Service\MapTools;
|
|
|
|
use App\Entity\JobOrder;
|
|
use App\Entity\CustomerVehicle;
|
|
use App\Entity\Promo;
|
|
use App\Entity\Battery;
|
|
use App\Entity\JOEvent;
|
|
use App\Entity\Customer;
|
|
use App\Entity\Hub;
|
|
use App\Entity\Invoice;
|
|
use App\Entity\Vehicle;
|
|
use App\Entity\VehicleManufacturer;
|
|
use App\Entity\Warranty;
|
|
|
|
use DateTime;
|
|
use DateInterval;
|
|
|
|
use Catalyst\APIBundle\Access\Generator as ACLGenerator;
|
|
|
|
class JobOrderController extends APIController
|
|
{
|
|
protected $acl_gen;
|
|
|
|
public function __construct(ACLGenerator $acl_gen)
|
|
{
|
|
$this->acl_gen = $acl_gen;
|
|
}
|
|
|
|
// TODO: break this monolithic method down
|
|
public function requestJobOrder(Request $req, InvoiceGeneratorInterface $ic, GeofenceTracker $geo,
|
|
InventoryManager $im, MQTTClient $mclient,
|
|
RiderAssignmentHandlerInterface $rah, PromoLogger $promo_logger,
|
|
HubSelector $hub_select, HubDistributor $hub_dist, HubFilterLogger $hub_filter_logger,
|
|
HubFilteringGeoChecker $hub_geofence, EntityManagerInterface $em)
|
|
{
|
|
$this->denyAccessUnlessGranted('tapi_jo.request', null, 'No access.');
|
|
|
|
// check required parameters and api key
|
|
$required_params = [
|
|
'service_type',
|
|
'trade_in_type',
|
|
'longitude',
|
|
'latitude',
|
|
'mode_of_payment',
|
|
'first_name',
|
|
'last_name',
|
|
'mobile_number',
|
|
'vehicle_manufacturer_id',
|
|
'vehicle_model_id',
|
|
'vehicle_model_year',
|
|
'vehicle_color',
|
|
'vehicle_condition',
|
|
'vehicle_fuel_type',
|
|
'plate_number'
|
|
];
|
|
|
|
$msg = $this->checkRequiredParameters($req, $required_params);
|
|
if ($msg)
|
|
return new APIResponse(false, $msg);
|
|
|
|
// get data from request
|
|
$data = [];
|
|
$status = $this->getJobOrderRequestInfo($req, $em, $data);
|
|
if ($status != null)
|
|
return new APIResponse(false, $status);
|
|
|
|
$is_covered = false;
|
|
// geofence
|
|
$is_covered = $geo->isCovered($data['long'], $data['lat']);
|
|
|
|
if (!$is_covered)
|
|
{
|
|
// TODO: put geofence error message in config file somewhere
|
|
$msg = 'Oops! Our service is limited to some areas in Metro Manila, Laguna, and Baguio only. We will update you as soon as we are able to cover your area';
|
|
return new APIResponse(false, $msg);
|
|
}
|
|
|
|
$jo = new JobOrder();
|
|
$jo->setSource($data['source'])
|
|
->setStatus(JOStatus::PENDING)
|
|
->setServiceType($data['service_type'])
|
|
->setWarrantyClass($data['warranty_class'])
|
|
->setDeliveryInstructions($data['instructions'])
|
|
->setTier1Notes('')
|
|
->setTier2Notes('')
|
|
->setDeliveryAddress($data['address'])
|
|
->setTradeInType($data['trade_in_type'])
|
|
->setDeliveryInstructions($data['instructions'])
|
|
->setModeOfPayment($data['payment_mode'])
|
|
->setAdvanceOrder($data['is_advance_order'])
|
|
->setStatusAutoAssign(AutoAssignStatus::NOT_ASSIGNED)
|
|
->setLandmark($data['landmark']);
|
|
|
|
$jo->setCustomer($data['customer']);
|
|
$jo->setCustomerVehicle($data['customer_vehicle']);
|
|
|
|
// set coordinates
|
|
$point = new Point($data['long'], $data['lat']);
|
|
$jo->setCoordinates($point);
|
|
|
|
// make invoice criteria
|
|
$icrit = new InvoiceCriteria();
|
|
$icrit->setServiceType($data['service_type']);
|
|
|
|
// TODO add promo to criteria if any
|
|
// check promo
|
|
// put in criteria
|
|
if ($data['promo'] != null)
|
|
$icrit->addPromo($data['promo']);
|
|
|
|
$icrit->setCustomerVehicle($data['customer_vehicle']);
|
|
|
|
$icrit->addEntry($data['batt'], $data['trade_in_type'], 1);
|
|
|
|
// send to invoice generator
|
|
$invoice = $ic->generateInvoice($icrit);
|
|
$jo->setInvoice($invoice);
|
|
|
|
// assign hub and rider
|
|
// check if hub is null
|
|
$hub = $data['hub'];
|
|
if ($hub == null)
|
|
{
|
|
// TODO: need to factor out the setting of HubCriteria fields
|
|
$hub_criteria = new HubCriteria();
|
|
$hub_criteria->setPoint($jo->getCoordinates());
|
|
|
|
// get distance limit for mobile from env
|
|
// get value of hub_filter_enable from env
|
|
$dotenv = new Dotenv();
|
|
$dotenv->loadEnv(__DIR__.'/../../../.env');
|
|
$limit_distance = $_ENV['CUST_DISTANCE_LIMIT'];
|
|
$hub_filter_enabled = $_ENV['HUB_FILTER_ENABLE'];
|
|
|
|
// set distance limit
|
|
$hub_criteria->setLimitDistance($limit_distance);
|
|
|
|
// check if hub filter is enabled. If not, use default values
|
|
// for the rest of the HubCriteria fields
|
|
if ($hub_filter_enabled == 'true')
|
|
{
|
|
// error_log('hub filter is enabled');
|
|
// check if customer location is in hub filter area
|
|
if ($hub_geofence->isCovered($data['long'], $data['lat']))
|
|
{
|
|
// if true, set other values for HubCriteria
|
|
// TODO: set this properly, since the other flags
|
|
// are on default values
|
|
// error_log('Area is covered by hub filtering');
|
|
$hub_criteria->setJoType($jo->getServiceType())
|
|
->setPaymentMethod($jo->getModeOfPayment())
|
|
->setRoundRobin(true);
|
|
}
|
|
}
|
|
|
|
// check if batt is null
|
|
$batt = $data['batt'];
|
|
if ($batt != null)
|
|
{
|
|
// add battery to items
|
|
$sku = $batt->getSAPCode();
|
|
if (!empty($sku))
|
|
$hub_criteria->addItem($batt->getSAPCode(), 1);
|
|
}
|
|
|
|
// get customer id. No JO id at this point
|
|
$cust = $data['customer'];
|
|
$customer_id = $cust->getID();
|
|
|
|
$hub_criteria->setCustomerId($customer_id);
|
|
|
|
// find nearest hubs
|
|
$nearest_hubs = $hub_select->find($hub_criteria);
|
|
|
|
if (!empty($nearest_hubs))
|
|
{
|
|
// go through the hub list, find the nearest hub
|
|
// with an available rider
|
|
// error_log('found nearest hub ' . $nearest_hub->getID());
|
|
foreach ($nearest_hubs as $nearest_hub)
|
|
{
|
|
// check if hub can be auto assigned
|
|
// if not, move on to the next hub in the list
|
|
if (($nearest_hub['hub']->isHubAutoAssign()))
|
|
{
|
|
// check if hub has riders that can be auto assigned
|
|
// if not, move on to the next hub
|
|
if (($nearest_hub['hub']->isRiderAutoAssign()))
|
|
{
|
|
$available_riders = $nearest_hub['hub']->getAvailableRiders();
|
|
if (count($available_riders) >= 1)
|
|
{
|
|
$assigned_rider = null;
|
|
if (count($available_riders) == 1)
|
|
{
|
|
$assigned_rider = $available_riders[0];
|
|
}
|
|
else
|
|
{
|
|
// TODO: the setting of riders into an array
|
|
// will no longer be necessary when the contents
|
|
// of randomizeRider changes
|
|
$riders = [];
|
|
foreach ($available_riders as $rider)
|
|
{
|
|
$riders[] = $rider;
|
|
}
|
|
|
|
$assigned_rider = $this->randomizeRider($riders);
|
|
}
|
|
|
|
$jo->setHub($nearest_hub['hub']);
|
|
$jo->setRider($assigned_rider);
|
|
$jo->setStatus(JOStatus::ASSIGNED);
|
|
$jo->setStatusAutoAssign(AutoAssignStatus::HUB_AND_RIDER_ASSIGNED);
|
|
$jo->setDeliveryStatus(DeliveryStatus::RIDER_ASSIGN);
|
|
|
|
// set date_assigned for job order
|
|
$jo->setDateAssign(new DateTime());
|
|
|
|
$assigned_rider->setAvailable(false);
|
|
|
|
// set rider's current job order
|
|
$assigned_rider->setCurrentJobOrder($jo);
|
|
|
|
// update redis hub_jo_count for hub
|
|
$hub_dist->incrementJoCountForHub($nearest_hub['hub']);
|
|
|
|
// break out of loop
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
// we just create the JO and let admin panel handle the hub assignment
|
|
// log hub into hub_filter_log
|
|
$hub_filter_logger->logFilteredHub($nearest_hub['hub'], 'no_available_rider', null, $cust->getID());
|
|
// continue to go through list to find hub with an available rider
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// TODO: log hub as cannot be auto rider assigned somewhere
|
|
// assign hub
|
|
// error_log('Rider cannot be auto assigned ' . $nearest_hub['hub']->getID());
|
|
$jo->setHub($nearest_hub['hub']);
|
|
$jo->setStatus(JOStatus::RIDER_ASSIGN);
|
|
$jo->setStatusAutoAssign(AutoAssignStatus::HUB_ASSIGNED);
|
|
|
|
// update redis hub_jo_count for hub
|
|
$hub_dist->incrementJoCountForHub($nearest_hub['hub']);
|
|
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// TODO: log hub as cannot be auto assigned somewhere
|
|
// move to next hub
|
|
error_log('Hub cannot be auto-assigned ' . $nearest_hub['hub']->getID());
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
$jo->setHub($hub);
|
|
$jo->setStatus(JOStatus::RIDER_ASSIGN);
|
|
$jo->setStatusAutoAssign(AutoAssignStatus::HUB_ASSIGNED);
|
|
|
|
if ($data['date_schedule'] != null)
|
|
$jo->setDateSchedule($data['date_schedule']);
|
|
|
|
// update redis hub_jo_count for hub
|
|
$hub_dist->incrementJoCountForHub($hub);
|
|
}
|
|
|
|
$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);
|
|
|
|
$rider_assign_event = new JOEvent();
|
|
$rider_assign_event->setDateHappen(new DateTime())
|
|
->setTypeID(JOEventType::RIDER_ASSIGN)
|
|
->setJobOrder($jo);
|
|
|
|
$em->persist($rider_assign_event);
|
|
|
|
// user mqtt event
|
|
$payload = [
|
|
'event' => 'outlet_assign'
|
|
];
|
|
$mclient->sendEvent($jo, $payload);
|
|
|
|
$rah->assignJobOrder($jo, $jo->getRider());
|
|
}
|
|
|
|
if ($jo->getStatus() == JOStatus::RIDER_ASSIGN)
|
|
{
|
|
// add event logs for hub assignments
|
|
$hub_assign_event = new JOEvent();
|
|
$hub_assign_event->setDateHappen(new DateTime())
|
|
->setTypeID(JOEventType::HUB_ASSIGN)
|
|
->setJobOrder($jo);
|
|
|
|
$em->persist($hub_assign_event);
|
|
|
|
// user mqtt event
|
|
$payload = [
|
|
'event' => 'outlet_assign'
|
|
];
|
|
$mclient->sendEvent($jo, $payload);
|
|
}
|
|
|
|
$em->flush();
|
|
|
|
// make invoice json data
|
|
$invoice_data = [
|
|
'total_price' => $invoice->getTotalPrice(),
|
|
'vat_ex_price' => (float) $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
|
|
$message = 'Job order created.';
|
|
|
|
return new APIResponse(true, $message, $data);
|
|
}
|
|
|
|
public function getEstimate(Request $req, InvoiceGeneratorInterface $ic, EntityManagerInterface $em)
|
|
{
|
|
$this->denyAccessUnlessGranted('tapi_jo.get.estimate', null, 'No access.');
|
|
|
|
// check required parameters and api key
|
|
$required_params = [
|
|
'service_type',
|
|
'vehicle_model_id',
|
|
];
|
|
$msg = $this->checkRequiredParameters($req, $required_params);
|
|
if ($msg)
|
|
return new APIResponse(false, $msg);
|
|
|
|
$data = [];
|
|
$msg = $this->validateAndGetEstimateRequest($req, $em, $data);
|
|
if ($msg != null)
|
|
return new APIResponse(false, $msg);
|
|
|
|
// make invoice criteria
|
|
$icrit = new InvoiceCriteria();
|
|
$icrit->setServiceType($data['service_type']);
|
|
$icrit->setCustomerVehicle($data['customer_vehicle']);
|
|
|
|
if ($data['promo'] != null)
|
|
$icrit->addPromo($data['promo']);
|
|
|
|
$icrit->addEntry($data['battery'], $data['trade_in_type'], 1);
|
|
|
|
// send to invoice generator
|
|
$invoice = $ic->generateInvoice($icrit);
|
|
|
|
// make invoice json data
|
|
$data = [
|
|
'total_price' => (float) $invoice->getTotalPrice(),
|
|
'vat_ex_price' => (float) $invoice->getVATExclusivePrice(),
|
|
'vat' => (float) $invoice->getVAT(),
|
|
'discount' => (float) $invoice->getDiscount(),
|
|
'trade_in' => (float) $invoice->getTradeIn(),
|
|
];
|
|
$items = $invoice->getItems();
|
|
$items_data = [];
|
|
foreach ($items as $item)
|
|
{
|
|
$my_data = [
|
|
'title' => $item->getTitle(),
|
|
'qty' => (int) $item->getQuantity() + 0,
|
|
'price' => (float) $item->getPrice() + 0.0,
|
|
];
|
|
|
|
$item_batt = $item->getBattery();
|
|
if ($item_batt != null)
|
|
{
|
|
$my_data['image_url'] = $this->getBatteryImageURL($req, $item_batt);
|
|
}
|
|
|
|
$items_data[] = $my_data;
|
|
}
|
|
|
|
$data['items'] = $items_data;
|
|
|
|
$message = 'Estimate computed.';
|
|
return new APIResponse(true, $message, $data);
|
|
}
|
|
|
|
public function getJOInvoice(Request $req, $jo_id, EntityManagerInterface $em)
|
|
{
|
|
$this->denyAccessUnlessGranted('tapi_jo.get.invoice', null, 'No access.');
|
|
|
|
$required_params = [];
|
|
$msg = $this->checkRequiredParameters($req, $required_params);
|
|
if ($msg)
|
|
return new APIResponse(false, $msg);
|
|
|
|
$jo = $em->getRepository(JobOrder::class)->find($jo_id);
|
|
if ($jo == null)
|
|
{
|
|
$message = 'No job order found';
|
|
return new APIResponse(false, $message);
|
|
}
|
|
|
|
$invoice = $jo->getInvoice();
|
|
|
|
// make invoice json data
|
|
$data = [
|
|
'total_price' => (float) $invoice->getTotalPrice(),
|
|
'vat_ex_price' => (float) $invoice->getVATExclusivePrice(),
|
|
'vat' => (float) $invoice->getVAT(),
|
|
'discount' => (float) $invoice->getDiscount(),
|
|
'trade_in' => (float) $invoice->getTradeIn(),
|
|
];
|
|
$items = $invoice->getItems();
|
|
$items_data = [];
|
|
foreach ($items as $item)
|
|
{
|
|
$my_data = [
|
|
'title' => $item->getTitle(),
|
|
'qty' => (int) $item->getQuantity() + 0,
|
|
'price' => (float) $item->getPrice() + 0.0,
|
|
];
|
|
|
|
$item_batt = $item->getBattery();
|
|
if ($item_batt != null)
|
|
{
|
|
$my_data['image_url'] = $this->getBatteryImageURL($req, $item_batt);
|
|
}
|
|
|
|
$items_data[] = $my_data;
|
|
}
|
|
|
|
$data['items'] = $items_data;
|
|
|
|
$message = 'JO invoice found.';
|
|
return new APIResponse(true, $message, $data);
|
|
}
|
|
|
|
public function cancelJobOrder(Request $req, MQTTClient $mclient, EntityManagerInterface $em)
|
|
{
|
|
$this->denyAccessUnlessGranted('tapi_jo.cancel', null, 'No access.');
|
|
|
|
$required_params = [
|
|
'jo_id',
|
|
'reason'
|
|
];
|
|
$msg = $this->checkRequiredParameters($req, $required_params);
|
|
if ($msg)
|
|
return new APIResponse(false, $msg);
|
|
|
|
// get job order
|
|
$jo_id = $req->request->get('jo_id');
|
|
$jo = $em->getRepository(JobOrder::class)->find($jo_id);
|
|
if ($jo == null)
|
|
{
|
|
$message = 'No job order found';
|
|
return new APIResponse(false, $message);
|
|
}
|
|
|
|
// TODO: check job order status, if it's cancellable
|
|
$cancel_reason = $req->request->get('reason');
|
|
|
|
$jo->cancel($cancel_reason);
|
|
|
|
// add event log
|
|
$event = new JOEvent();
|
|
$event->setDateHappen(new DateTime())
|
|
->setTypeID(JOEventType::CANCEL)
|
|
->setJobOrder($jo);
|
|
$em->persist($event);
|
|
|
|
$em->flush();
|
|
|
|
// TODO: do we need this?
|
|
// send mobile app event
|
|
$payload = [
|
|
'event' => 'cancelled',
|
|
'reason' => $cancel_reason,
|
|
'jo_id' => $jo->getID(),
|
|
];
|
|
$mclient->sendRiderEvent($jo, $payload);
|
|
|
|
$data = [];
|
|
$message = 'Job order cancelled.';
|
|
|
|
return new APIResponse(true, $message, $data);
|
|
}
|
|
|
|
// we can't use param converter for now because we want to output the proper 404
|
|
public function getJobOrderInfo($id, Request $req, EntityManagerInterface $em, RiderTracker $rt)
|
|
{
|
|
$this->denyAccessUnlessGranted('tapi_jo.get.info', null, 'No access.');
|
|
|
|
// check required parameters
|
|
$required_params = [];
|
|
$msg = $this->checkRequiredParameters($req, $required_params);
|
|
if ($msg)
|
|
return new APIResponse(false, $msg);
|
|
|
|
// get job order data
|
|
$jo = $em->getRepository(JobOrder::class)->find($id);
|
|
if ($jo == null)
|
|
{
|
|
$message = 'No job order information found';
|
|
return new APIResponse(false, $message);
|
|
}
|
|
|
|
// put into job order data array
|
|
$jo_data = $this->generateJobOrderData($req, $jo, $rt, $em);
|
|
|
|
$data = [
|
|
'job_order' => $jo_data
|
|
];
|
|
|
|
$message = 'Job order information found.';
|
|
return new APIResponse(true, $message, $data);
|
|
}
|
|
|
|
public function locationSupport(Request $req, GeofenceTracker $geo, EntityManagerInterface $em)
|
|
{
|
|
$this->denyAccessUnlessGranted('tapi_jo.location.support', null, 'No access.');
|
|
|
|
$required_params = [
|
|
'longitude',
|
|
'latitude',
|
|
];
|
|
$msg = $this->checkRequiredParameters($req, $required_params);
|
|
if ($msg)
|
|
return new APIResponse(false, $msg);
|
|
|
|
$long = $req->request->get('longitude');
|
|
$lat = $req->request->get('latitude');
|
|
|
|
$is_covered = false;
|
|
// geofence
|
|
$is_covered = $geo->isCovered($long, $lat);
|
|
|
|
$data = [
|
|
'longitude' => $long,
|
|
'latitude' => $lat,
|
|
'supported' => $is_covered,
|
|
];
|
|
|
|
// check if is_covered is false. If so, we need to modify the message
|
|
$message = 'Location is supported.';
|
|
if (!$is_covered)
|
|
{
|
|
$message = 'Oops! Our service is limited to some areas in Metro Manila, Laguna, and Baguio only. We will update you as soon as we are able to cover your area';
|
|
}
|
|
|
|
return new APIResponse(true, $message, $data);
|
|
}
|
|
|
|
// TODO: should we change to the HubSelector?
|
|
public function getNearestHubAndSlots(Request $req, EntityManagerInterface $em,
|
|
MapTools $map_tools)
|
|
{
|
|
$this->denyAccessUnlessGranted('tapi_jo.nearest_hub.get', null, 'No access.');
|
|
|
|
$required_params = [
|
|
'longitude',
|
|
'latitude',
|
|
];
|
|
|
|
$msg = $this->checkRequiredParameters($req, $required_params);
|
|
if ($msg)
|
|
return new APIResponse(false, $msg);
|
|
|
|
$coordinates = new Point($req->request->get('longitude'), $req->request->get('latitude'));
|
|
|
|
$nearest_hub_slots = $this->findAdvanceNearestHubAndSlots($coordinates, $em, $map_tools);
|
|
|
|
if (empty($nearest_hub_slots['hub']))
|
|
{
|
|
$message = 'Thank you for reaching out to us. Please expect a call from us and we will assist you with your request. Thank you and stay safe!';
|
|
return new APIResponse (false, $message);
|
|
}
|
|
|
|
// make hub data
|
|
$data = [
|
|
'hub_id' => $nearest_hub_slots['hub']->getID(),
|
|
'hub_slots' => $nearest_hub_slots['slots'],
|
|
];
|
|
|
|
$message = 'Nearest hub and slots found.';
|
|
|
|
return new APIResponse(true, $message, $data);
|
|
}
|
|
|
|
// comment out for now
|
|
/*
|
|
public function scheduleOptionStatus(Request $req, EntityManagerInterface $em)
|
|
{
|
|
$this->denyAccessUnlessGranted('tapi_jo.schedule_option.status', null, 'No access.');
|
|
|
|
// check required parameters and api key
|
|
$required_params = [];
|
|
$res = $this->checkParamsAndKey($req, $em, $required_params);
|
|
if ($res->isError())
|
|
return $res->getReturnResponse();
|
|
|
|
$schedule_choice = true;
|
|
|
|
// remove the time check after ECQ. This will then always return true
|
|
// get current time
|
|
$current_datetime = new DateTime();
|
|
//$current_datetime = DateTime::createFromFormat('Y-m-d H:i', '2020-04-30 17:01');
|
|
|
|
// get the hour
|
|
$hour = $current_datetime->format('G');
|
|
|
|
// commenting out the time check since we can now book 24/7
|
|
// this will get uncommented out if and when ECQ will kick in
|
|
//if (($hour < 8) || ($hour > 16))
|
|
// $schedule_choice = false;
|
|
|
|
// add checking if customer has a pre-registered hub
|
|
// TODO: modify how we get customer
|
|
$cust = $this->session->getCustomer();
|
|
if ($cust == null)
|
|
{
|
|
$res->setError(true)
|
|
->setErrorMessage('No customer information found');
|
|
return $res->getReturnResponse();
|
|
}
|
|
// check if customer has customer tag promo
|
|
if (($cust->getCustomerTag('TAG_CAR_CLUB_OFFICER_PROMO')) ||
|
|
($cust->getCustomerTag('TAG_CAR_CLUB_MEMBER_PROMO')))
|
|
{
|
|
// if has customer tag, customer has not availed of promo, get the hub where customer is pre-registered
|
|
$car_club_hub = $cust->getCarClubCustomerHub();
|
|
if ($car_club_hub != null)
|
|
{
|
|
$schedule_choice = false;
|
|
}
|
|
}
|
|
|
|
// schedule_choice will always be true aka customer can opt to
|
|
// Book Now or Schedule Order EXCEPT if customer has customer tag promo
|
|
// or ECQ comes back
|
|
$data = [
|
|
'display_schedule_choice' => $schedule_choice,
|
|
];
|
|
$res->setData($data);
|
|
|
|
return $res->getReturnResponse();
|
|
}
|
|
*/
|
|
|
|
protected function generateJobOrderData($req, $jo, $rt, $em)
|
|
{
|
|
$status = $jo->getStatus();
|
|
|
|
$dest = $jo->getCoordinates();
|
|
|
|
$jo_data = [
|
|
'id' => $jo->getID(),
|
|
'date_create' => $jo->getDateCreate()->format('M d, Y'),
|
|
'service_type' => $jo->getServiceType(),
|
|
'destination' => [
|
|
'long' => $dest->getLongitude(),
|
|
'lat' => $dest->getLatitude(),
|
|
],
|
|
'delivery_address' => $jo->getDeliveryAddress(),
|
|
'delivery_instructions' => $jo->getDeliveryInstructions(),
|
|
'jo_status' => $status,
|
|
'status' => $this->generateAPIRiderStatus($status),
|
|
];
|
|
|
|
// customer vehicle and warranty
|
|
$cv = $jo->getCustomerVehicle();
|
|
|
|
// get latest warranty using plate number
|
|
$warranty = $this->findWarranty($cv->getPlateNumber(), $em);
|
|
|
|
$jo_data['customer_vehicle'] = [
|
|
'id' => $cv->getID(),
|
|
'plate_number' => $cv->getPlateNumber(),
|
|
'warranty' => $warranty,
|
|
];
|
|
|
|
// customer information
|
|
$customer = $jo->getCustomer();
|
|
$jo_data['customer'] = [
|
|
'first_name' => $customer->getFirstName(),
|
|
'last_name' => $customer->getLastName(),
|
|
'mobile_number' => $customer->getPhoneMobile(),
|
|
];
|
|
|
|
// rider
|
|
$rider = $jo->getRider();
|
|
if ($rider != null)
|
|
{
|
|
// default image url
|
|
$url_prefix = $req->getSchemeAndHttpHost();
|
|
$image_url = $url_prefix . '/assets/images/user.gif';
|
|
if ($rider->getImageFile() != null)
|
|
$image_url = $url_prefix . '/uploads/' . $rider->getImageFile();
|
|
|
|
$coord = $rt->getRiderLocation($rider->getID());
|
|
|
|
$jo_data['rider'] = [
|
|
'id' => $rider->getID(),
|
|
'name' => $rider->getFullName(),
|
|
'plate_num' => $rider->getPlateNumber(),
|
|
'contact_num' => $rider->getContactNumber(),
|
|
'image_url' => $image_url,
|
|
'location' => [
|
|
'long' => $coord->getLongitude(),
|
|
'lat' => $coord->getLatitude()
|
|
]
|
|
];
|
|
}
|
|
else
|
|
{
|
|
$jo_data['rider'] = null;
|
|
}
|
|
|
|
// invoice items
|
|
$items = [];
|
|
$jo_items = $jo->getInvoice()->getItems();
|
|
foreach ($jo_items as $item)
|
|
{
|
|
$items[] = [
|
|
'id' => $item->getID(),
|
|
'title' => $item->getTitle(),
|
|
'qty' => $item->getQuantity(),
|
|
'price' => $item->getPrice(),
|
|
];
|
|
}
|
|
|
|
$jo_data['items'] = $items;
|
|
|
|
|
|
// dates depending on status
|
|
switch ($status)
|
|
{
|
|
case JOStatus::FULFILLED:
|
|
if ($jo->getDateFulfill() == null)
|
|
$jo_data['date_fulfilled'] = '';
|
|
else
|
|
$jo_data['date_fulfilled'] = $jo->getDateFulfill()->format('M d, Y');
|
|
break;
|
|
case JOStatus::CANCELLED:
|
|
$date_cancel = $jo->getDateCancel();
|
|
if ($date_cancel == null)
|
|
$date_cancel = new DateTime();
|
|
$jo_data['date_cancelled'] = $date_cancel->format('M d, Y');
|
|
break;
|
|
}
|
|
|
|
return $jo_data;
|
|
}
|
|
|
|
protected function findWarranty($plate_number, EntityManagerInterface $em)
|
|
{
|
|
// NOTE: Modify the search for the latest warranty. This seems hacky.
|
|
// get latest warranty using plate number
|
|
$warranty_results = $em->getRepository(Warranty::class)->findBy(['plate_number' => $plate_number],
|
|
['date_create' => 'desc']);
|
|
|
|
$warr = [];
|
|
|
|
// check if warranty_results is empty
|
|
if (empty($warranty_results))
|
|
{
|
|
/*
|
|
$res->setError(true)
|
|
->setErrorMessage('No warranty found for plate number');
|
|
return $res->getReturnResponse();
|
|
*/
|
|
|
|
return $warr;
|
|
}
|
|
|
|
// get first entry
|
|
$warranty = current($warranty_results);
|
|
|
|
// check for null values for battery and date claim and date expire
|
|
$batt_model = '';
|
|
$batt_size = '';
|
|
$sap_batt = '';
|
|
$claim_date = '';
|
|
$expiry_date = '';
|
|
|
|
if (!(is_null($warranty->getBatteryModel()))) {
|
|
$batt_model = $warranty->getBatteryModel()->getName();
|
|
}
|
|
if (!(is_null($warranty->getBatterySize()))) {
|
|
$batt_size = $warranty->getBatterySize()->getName();
|
|
}
|
|
if (!(is_null($warranty->getSAPBattery()))) {
|
|
$sap_batt = $warranty->getSAPBattery()->getID();
|
|
}
|
|
if (!(is_null($warranty->getDateClaim()))) {
|
|
$claim_date = $warranty->getDateClaim()->format("d M Y");
|
|
}
|
|
if (!(is_null($warranty->getDateExpire()))) {
|
|
$expiry_date = $warranty->getDateExpire()->format("d M Y");
|
|
}
|
|
|
|
$warr[] = [
|
|
'id' => $warranty->getID(),
|
|
'serial' => $warranty->getSerial(),
|
|
'warranty_class' => $warranty->getWarrantyClass(),
|
|
'plate_number' => $warranty->getPlateNumber(),
|
|
'first_name' => $warranty->getFirstName(),
|
|
'last_name' => $warranty->getLastName(),
|
|
'mobile_number' => $warranty->getMobileNumber(),
|
|
'battery_model' => $batt_model,
|
|
'battery_size' => $batt_size,
|
|
'sap_battery' => $sap_batt,
|
|
'status' => $warranty->getStatus(),
|
|
'date_create' => $warranty->getDateCreate()->format("d M Y g:i A"),
|
|
'date_purchase' => $warranty->getDatePurchase()->format("d M Y"),
|
|
'date_expire' => $expiry_date,
|
|
'date_claim' => $claim_date,
|
|
'claim_from' => $warranty->getClaimedFrom(),
|
|
'is_activated' => $warranty->isActivated() ? 1 : 0,
|
|
];
|
|
|
|
return $warr;
|
|
}
|
|
|
|
protected function findAdvanceNearestHubAndSlots(Point $coordinates, EntityManagerInterface $em, MapTools $map_tools, $hub=null)
|
|
{
|
|
$hub_data = [];
|
|
|
|
if ($hub != null)
|
|
{
|
|
// get the slots of hub
|
|
$hub_slots = $this->getHubRiderSlots($hub, $em);
|
|
|
|
$slots = $hub_slots['slot_data'];
|
|
|
|
$hub_data = [
|
|
'hub' => $hub,
|
|
'slots' => $slots,
|
|
];
|
|
return $hub_data;
|
|
}
|
|
|
|
// get the nearest 10 hubs
|
|
$nearest_hubs_with_distance = [];
|
|
$hubs = $map_tools->getClosestOpenHubs($coordinates, 10);
|
|
|
|
foreach ($hubs as $hub)
|
|
{
|
|
$nearest_hubs_with_distance[] = $hub;
|
|
// TODO: insert checking for branch code here when inventory manager is up
|
|
}
|
|
|
|
$nearest = null;
|
|
$hub_slots = [];
|
|
$slot_found = false;
|
|
// find the nearest hub
|
|
if (!empty($nearest_hubs_with_distance))
|
|
{
|
|
// get slots of nearest hub right after getting nearest hub.
|
|
// then check if hub has available slots. If not, get next nearest hub.
|
|
foreach ($nearest_hubs_with_distance as $nhd)
|
|
{
|
|
if (empty($nearest))
|
|
{
|
|
// get the slots for the hub to check if hub is available for assignment
|
|
$hub_slots = $this->getHubRiderSlots($nhd['hub'], $em);
|
|
|
|
$flag_hub_available = $hub_slots['flag_hub_available'];
|
|
if ($flag_hub_available == true)
|
|
{
|
|
$nearest = $nhd;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if ($nhd['distance'] < $nearest['distance'])
|
|
{
|
|
// get the slots for nearest which is nhd right now
|
|
$hub_slots = $this->getHubRiderSlots($nhd['hub'], $em);
|
|
|
|
$flag_hub_available = $hub_slots['flag_hub_available'];
|
|
|
|
// if hub is available, set hub to nearest
|
|
if ($flag_hub_available == true)
|
|
{
|
|
$nearest = $nhd;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if ($nearest != null)
|
|
{
|
|
// set hub data to what is in nearest
|
|
$hub_data = [
|
|
'hub' => $nearest['hub'],
|
|
'slots' => $hub_slots['slot_data'],
|
|
];
|
|
}
|
|
|
|
return $hub_data;
|
|
|
|
}
|
|
|
|
protected function getHubRiderSlots(Hub $hub, EntityManagerInterface $em)
|
|
{
|
|
// 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
|
|
$request_time = time();
|
|
$midnight = strtotime('00:00');
|
|
*/
|
|
$start_date = new DateTime();
|
|
$end_date = new DateTime();
|
|
|
|
// to keep things simple, just start on next day regardless of midnight timer
|
|
$start_date->add(new DateInterval('P1D'));
|
|
$end_date->add(new DateInterval('P3D'));
|
|
|
|
/*
|
|
if ($request_time < $midnight)
|
|
{
|
|
// add +1 to start date to get the next day
|
|
// add +3 to date to end date to get the advance orders for the next three days
|
|
$start_date->add(new DateInterval('P1D'));
|
|
$end_date->add(new DateInterval('P1D'));
|
|
}
|
|
$end_date->add(new DateInterval('P2D'));
|
|
*/
|
|
|
|
// set time bounds for the start and end date
|
|
$start_date->setTime(0, 1);
|
|
$end_date->setTime(23, 59);
|
|
|
|
// NOTE: get advance orders via query
|
|
// get JOs assigned to hub that are advance orders and scheduled for the next three days 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_cancelled
|
|
and jo.status != :status_fulfilled');
|
|
$jos_advance_orders = $query->setParameters([
|
|
'hub' => $hub,
|
|
'date_start' => $start_date,
|
|
'date_end' => $end_date,
|
|
'status_cancelled' => JOStatus::CANCELLED,
|
|
'status_fulfilled' => JOStatus::FULFILLED,
|
|
])
|
|
->getResult();
|
|
// check request_time
|
|
|
|
// define slots
|
|
$slots = [
|
|
'08_09' => '8:00 AM',
|
|
'09_10' => '9:00 AM',
|
|
'10_11' => '10:00 AM',
|
|
'11_12' => '11:00 AM',
|
|
'12_13' => '12:00 PM',
|
|
'13_14' => '1:00 PM',
|
|
'14_15' => '2:00 PM',
|
|
'15_16' => '3:00 PM',
|
|
'16_17' => '4:00 PM',
|
|
];
|
|
|
|
// get the dates for the next three days
|
|
$first_date = $start_date->format('Y-m-d');
|
|
$second_date = $start_date->add(new DateInterval('P1D'));
|
|
$sec_date = $second_date->format('Y-m-d');
|
|
$third_date = $end_date->format('Y-m-d');
|
|
|
|
// define days
|
|
$days = [
|
|
$first_date => $first_date,
|
|
$sec_date => $sec_date,
|
|
$third_date => $third_date,
|
|
];
|
|
|
|
// initialize hub rider slots
|
|
$hub_rider_slots = [];
|
|
foreach ($days as $day)
|
|
{
|
|
foreach ($slots as $slot_key => $slot)
|
|
{
|
|
$hub_rider_slots[$day][$slot_key] = $hub->getRiderSlots();
|
|
}
|
|
}
|
|
|
|
// check each JO's date_schedule, decrement rider_slots if date schedule falls in that slot
|
|
foreach ($jos_advance_orders as $jo)
|
|
{
|
|
// get date key
|
|
$date_sched = $jo->getDateSchedule();
|
|
$date_string = $date_sched->format('Y-m-d');
|
|
$hour = $date_sched->format('H');
|
|
$slot_id = sprintf('%02d_%02d', $hour, $hour + 1);
|
|
|
|
// error_log("SLOT - $date_string - $slot_id");
|
|
|
|
// decrement rider slot
|
|
if (isset($hub_rider_slots[$date_string][$slot_id]))
|
|
$hub_rider_slots[$date_string][$slot_id]--;
|
|
|
|
// check if it goes through next slot (10 min allowance)
|
|
$mins = $date_sched->format('i');
|
|
if ($mins > 10)
|
|
{
|
|
$next_slot_id = sprintf('%02d_%02d', $hour + 1, $hour + 2);
|
|
// error_log("NEXT SLOT - $date_string - $next_slot_id");
|
|
// decrement rider slot
|
|
if (isset($hub_rider_slots[$date_string][$next_slot_id]))
|
|
$hub_rider_slots[$date_string][$next_slot_id]--;
|
|
|
|
}
|
|
}
|
|
|
|
// error_log(print_r($hub_rider_slots, true));
|
|
|
|
$hub_slots = $this->generateHubSlots($hub_rider_slots, $slots);
|
|
|
|
// error_log(print_r($hub_slots, true));
|
|
|
|
return $hub_slots;
|
|
}
|
|
|
|
protected function generateHubSlots($rider_slots, $slots)
|
|
{
|
|
$data = [];
|
|
$total_rslots = 0;
|
|
$total_unavailable_rslots = 0;
|
|
foreach ($rider_slots as $day_id => $rslot)
|
|
{
|
|
$data[$day_id] = [];
|
|
|
|
foreach ($rslot as $slot_id => $avail_slots)
|
|
{
|
|
// increment total rider slots
|
|
$total_rslots++;
|
|
|
|
$slot_data = [
|
|
'id' => $slot_id,
|
|
'label' => $slots[$slot_id],
|
|
'available' => true,
|
|
];
|
|
|
|
// mark unavailable ones
|
|
if ($avail_slots <= 0)
|
|
{ // increment total number of unavailable slots
|
|
$total_unavailable_rslots++;
|
|
$slot_data['available'] = false;
|
|
}
|
|
|
|
// add to day data
|
|
$data[$day_id][] = $slot_data;
|
|
}
|
|
}
|
|
|
|
// check if hub has available slots
|
|
$hub_available = true;
|
|
// error_log('total rider slots ' . $total_rslots);
|
|
// error_log('total unavailable slots ' . $total_unavailable_rslots);
|
|
if ($total_rslots == $total_unavailable_rslots)
|
|
{
|
|
// error_log('hub has no available slots');
|
|
$hub_available = false;
|
|
}
|
|
|
|
$hs_data = [
|
|
'flag_hub_available' => $hub_available,
|
|
'slot_data' => $data,
|
|
];
|
|
|
|
return $hs_data;
|
|
}
|
|
|
|
protected function getTimeFromSlot($slot_id)
|
|
{
|
|
$time_selected = '';
|
|
|
|
switch($slot_id) {
|
|
case '08_09':
|
|
$time_selected = AdvanceOrderSlot::_08_09;
|
|
break;
|
|
case '09_10':
|
|
$time_selected = AdvanceOrderSlot::_09_10;
|
|
break;
|
|
case '10_11':
|
|
$time_selected = AdvanceOrderSlot::_10_11;
|
|
break;
|
|
case '11_12':
|
|
$time_selected = AdvanceOrderSlot::_11_12;
|
|
break;
|
|
case '12_13':
|
|
$time_selected = AdvanceOrderSlot::_12_13;
|
|
break;
|
|
case '13_14':
|
|
$time_selected = AdvanceOrderSlot::_13_14;
|
|
break;
|
|
case '14_15':
|
|
$time_selected = AdvanceOrderSlot::_14_15;
|
|
break;
|
|
case '15_16':
|
|
$time_selected = AdvanceOrderSlot::_15_16;
|
|
break;
|
|
case '16_17':
|
|
$time_selected = AdvanceOrderSlot::_16_17;
|
|
break;
|
|
default:
|
|
error_log('Invalid slot id ' . $slot_id);
|
|
}
|
|
|
|
return $time_selected;
|
|
}
|
|
|
|
protected function randomizeRider($riders)
|
|
{
|
|
// TODO: get redis to track the sales per rider per day
|
|
// check the time they came in
|
|
// for now, randomize the rider
|
|
$selected_index = array_rand($riders);
|
|
|
|
$selected_rider = $riders[$selected_index];
|
|
|
|
return $selected_rider;
|
|
}
|
|
|
|
// TODO: might have to put this in a common service since BatteryController also calls this
|
|
protected function getBatteryImageURL($req, $batt)
|
|
{
|
|
// TODO: workaround for now, we get static image of battery based on model name
|
|
$filename = trim(strtolower($batt->getModel()->getName())) . '_mobile.jpg';
|
|
$file_path = $req->getSchemeAndHttpHost() . $this->generateUrl('static_battery_image') . '/' . $filename;
|
|
|
|
return $file_path;
|
|
}
|
|
|
|
protected function getJobOrderRequestInfo(Request $req, EntityManagerInterface $em, &$data)
|
|
{
|
|
$error = $this->validateJORequest($req, $em);
|
|
if ($error != null)
|
|
{
|
|
// there is a validation error
|
|
return $error;
|
|
}
|
|
|
|
$r = $req->request;
|
|
|
|
// at this point, the request data has been validated
|
|
// trade-in type
|
|
$trade_in_type = $this->cleanText($r->get('trade_in_type', ''));
|
|
switch ($trade_in_type)
|
|
{
|
|
case TradeInType::MOTOLITE:
|
|
case TradeInType::OTHER:
|
|
break;
|
|
|
|
default:
|
|
$trade_in_type = '';
|
|
break;
|
|
}
|
|
|
|
// address
|
|
$address = $r->get('delivery_address', 'Set by third party API');
|
|
|
|
// instructions
|
|
$instructions = $r->get('delivery_instructions', '');
|
|
|
|
// landmark
|
|
$landmark = $r->get('landmark', ' ');
|
|
|
|
// longitude and latitude
|
|
$long = $r->get('longitude');
|
|
$lat = $r->get('latitude');
|
|
|
|
// get service type
|
|
$stype = $this->cleanText($r->get('service_type', ''));
|
|
|
|
// get mode of payment
|
|
$payment_mode = $this->cleanText($r->get('mode_of_payment', ''));
|
|
|
|
$advance_order = $r->get('flag_advance_order', 0);
|
|
// check for 'false' text
|
|
if ($advance_order === false || $advance_order === 0 || $advance_order === '0' || $advance_order == 'false')
|
|
$flag_advance_order = false;
|
|
else
|
|
$flag_advance_order = true;
|
|
|
|
$hub = null;
|
|
$hub_id = $r->get('hub_id');
|
|
if (strlen($hub_id) > 0)
|
|
$hub = $em->getRepository(Hub::class)->find($hub_id);
|
|
|
|
$schedule_date = $r->get('date_schedule');
|
|
$slot_id = $r->get('slot_id');
|
|
|
|
// process the jo date schedule
|
|
$date_schedule = null;
|
|
if ((strlen($schedule_date) > 0) && (strlen($slot_id) > 0))
|
|
{
|
|
$time_schedule = $this->getTimeFromSlot($slot_id);
|
|
if (!empty($time_schedule))
|
|
{
|
|
$s_date = $schedule_date . ' ' . $time_schedule;
|
|
$date_schedule = DateTime::createFromFormat('Y-m-d H:i', $s_date);
|
|
// error_log($date_schedule->format('Y-m-d H:i'));
|
|
}
|
|
}
|
|
|
|
// get promo
|
|
$promo_id = $r->get('promo_id', 0);
|
|
$promo = $em->getRepository(Promo::class)->find($promo_id);
|
|
|
|
// check battery
|
|
$batt_id = $req->request->get('battery_id', 0);
|
|
$batt = $em->getRepository(Battery::class)->find($batt_id);
|
|
$warranty_class = '';
|
|
if (($batt != null) && ($stype == ServiceType::BATTERY_REPLACEMENT_NEW))
|
|
$warranty_class = WarrantyClass::WTY_PRIVATE;
|
|
|
|
// get customer and vehicle info
|
|
$fname = trim($r->get('first_name', ''));
|
|
$lname = trim($r->get('last_name', ''));
|
|
$mobile = $r->get('mobile_number', '');
|
|
|
|
// validate mobile number
|
|
$clean_mobile = $this->cleanPhoneNumber($mobile);
|
|
|
|
$vmanu_id = $r->get('vehicle_manufacturer_id', 0);
|
|
// find vehicle manufacturer
|
|
$vmanu = $em->getRepository(VehicleManufacturer::class)->find($vmanu_id);
|
|
|
|
$vmodel_id = $r->get('vehicle_model_id', 0);
|
|
// find vehicle
|
|
$vehicle = $em->getRepository(Vehicle::class)->find($vmodel_id);
|
|
|
|
$plate_number = $r->get('plate_number', '');
|
|
|
|
// clean plate number
|
|
$clean_plate = $this->cleanPlateNumber($plate_number);
|
|
|
|
$v_condition = $this->cleanText($r->get('vehicle_condition', ''));
|
|
$fuel_type = $this->cleanText($r->get('vehicle_fuel_type', ''));
|
|
$color = trim($r->get('vehicle_color', ''));
|
|
$model_year = trim($r->get('vehicle_model_year', 0));
|
|
|
|
$c_data = [
|
|
'first_name' => $fname,
|
|
'last_name' => $lname,
|
|
'mobile' => $clean_mobile,
|
|
'vmanu' => $vmanu,
|
|
'vehicle' => $vehicle,
|
|
'plate_number' => $clean_plate,
|
|
'model_year' => $model_year,
|
|
'condition' => $v_condition,
|
|
'color' => $color,
|
|
'fuel_type' => $fuel_type,
|
|
];
|
|
|
|
// process customer and vehicle information
|
|
$cust_data = $this->processCustomerAndVehicleInformation($c_data, $em);
|
|
|
|
$data = [
|
|
'trade_in_type' => $trade_in_type,
|
|
'service_type' => $stype,
|
|
'long' => $long,
|
|
'lat' => $lat,
|
|
'payment_mode' => $payment_mode,
|
|
'address' => $address,
|
|
'instructions' => $instructions,
|
|
'landmark' => $landmark,
|
|
'is_advance_order' => $flag_advance_order,
|
|
'hub' => $hub,
|
|
'date_schedule' => $date_schedule,
|
|
'promo' => $promo,
|
|
'batt' => $batt,
|
|
'customer' => $cust_data['customer'],
|
|
'customer_vehicle' => $cust_data['customer_vehicle'],
|
|
'source' => TransactionOrigin::THIRD_PARTY,
|
|
'warranty_class' => $warranty_class,
|
|
];
|
|
|
|
return null;
|
|
}
|
|
|
|
protected function validateJORequest(Request $req, EntityManagerInterface $em)
|
|
{
|
|
$r = $req->request;
|
|
|
|
// validate trade-in type
|
|
$trade_in_type = $this->cleanText($r->get('trade_in_type', ''));
|
|
if ((!empty($trade_in_type)) &&
|
|
(!TradeInType::validate($trade_in_type)))
|
|
{
|
|
$message = 'Invalid trade in type';
|
|
return $message;
|
|
}
|
|
|
|
// validate service type
|
|
$stype = $this->cleanText($r->get('service_type', ''));
|
|
if (!ServiceType::validate($stype))
|
|
{
|
|
$message = 'Invalid service type';
|
|
return $message;
|
|
}
|
|
|
|
// validate mode of payment
|
|
$payment_mode = $this->cleanText($r->get('mode_of_payment', ''));
|
|
if (!ModeOfPayment::validate($payment_mode))
|
|
{
|
|
$message = 'Invalid mode of payment';
|
|
return $message;
|
|
}
|
|
|
|
// check promo
|
|
$promo = null;
|
|
$promo_id = $r->get('promo_id', 0);
|
|
if (!empty($promo_id))
|
|
{
|
|
$promo = $em->getRepository(Promo::class)->find($promo_id);
|
|
if ($promo == null)
|
|
{
|
|
$message = 'Invalid promo id';
|
|
return $message;
|
|
}
|
|
}
|
|
|
|
// check battery
|
|
$batt = null;
|
|
$batt_id = $req->request->get('battery_id', 0);
|
|
if (!empty($batt_id))
|
|
{
|
|
$batt = $em->getRepository(Battery::class)->find($batt_id);
|
|
if ($batt == null)
|
|
{
|
|
$message = 'Invalid battery id';
|
|
return $message;
|
|
}
|
|
}
|
|
|
|
// check if service type is BATTERY_REPLACEMENT_WARRANTY or
|
|
// BATTERY_REPLACEMENT_NEW and if battery_id is empty
|
|
if (($stype == ServiceType::BATTERY_REPLACEMENT_NEW) ||
|
|
($stype == ServiceType::BATTERY_REPLACEMENT_WARRANTY))
|
|
{
|
|
if ($batt == null)
|
|
{
|
|
$message = 'battery_id cannot be empty for selected service type.';
|
|
return $message;
|
|
}
|
|
}
|
|
|
|
// validate mobile number
|
|
$mobile = $r->get('mobile_number', '');
|
|
$clean_mobile = $this->cleanPhoneNumber($mobile);
|
|
if ($clean_mobile == false)
|
|
{
|
|
$message = 'Invalid mobile number.';
|
|
return $message;
|
|
}
|
|
|
|
$vmanu = null;
|
|
$vmanu_id = $r->get('vehicle_manufacturer_id', 0);
|
|
// validate the vehicle manufacturer id
|
|
// find vehicle manufacturer
|
|
$vmanu = $em->getRepository(VehicleManufacturer::class)->find($vmanu_id);
|
|
if ($vmanu == null)
|
|
{
|
|
$message = 'Invalid vehicle manufacturer id.';
|
|
return $message;
|
|
}
|
|
|
|
$vmodel = null;
|
|
$vmodel_id = $r->get('vehicle_model_id', 0);
|
|
// validate the vehicle model id
|
|
// find vehicle
|
|
$vmodel = $em->getRepository(Vehicle::class)->find($vmodel_id);
|
|
if ($vmodel == null)
|
|
{
|
|
$message = 'Invalid vehicle model id.';
|
|
return $message;
|
|
}
|
|
|
|
// check model year
|
|
// (1) if empty
|
|
// (2) if numeric
|
|
// (2)if it falls between a range of years
|
|
$model_year = $r->get('vehicle_model_year');
|
|
if (empty($model_year))
|
|
{
|
|
$message = 'Vehicle model year is empty.';
|
|
return $message;
|
|
}
|
|
if (!is_numeric($model_year))
|
|
{
|
|
$message = 'Invalid model year. Not a number.';
|
|
return $message;
|
|
}
|
|
|
|
$year_options = $this->generateYearOptions();
|
|
// get first and last element
|
|
$first_year = $year_options[0];
|
|
$last_year = end($year_options);
|
|
if (($model_year < $first_year) ||
|
|
($model_year > $last_year))
|
|
{
|
|
$message = 'Invalid model year.';
|
|
return $message;
|
|
}
|
|
|
|
// confirm that vehicle model's manufacturer is the same as the one in vehicle
|
|
if ($vmodel->getManufacturer()->getID() != $vmanu_id)
|
|
{
|
|
$message = 'Invalid vehicle manufacturer id for vehicle model.';
|
|
return $message;
|
|
}
|
|
|
|
// validate vehicle condition
|
|
$v_condition = $this->cleanText($r->get('vehicle_condition', ''));
|
|
if (!VehicleStatusCondition::validate($v_condition))
|
|
{
|
|
$message = 'Invalid vehicle condition.';
|
|
return $message;
|
|
}
|
|
|
|
// validate fuel type
|
|
$fuel_type = $this->cleanText($r->get('vehicle_fuel_type', ''));
|
|
if (!FuelType::validate($fuel_type))
|
|
{
|
|
$message = 'Invalid vehicle fuel type.';
|
|
return $message;
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
protected function processCustomerAndVehicleInformation($data, EntityManagerInterface $em)
|
|
{
|
|
$c_data = [];
|
|
|
|
// retrieve customer info
|
|
$fname = $data['first_name'];
|
|
$lname = $data['last_name'];
|
|
$vmanu = $data['vmanu'];
|
|
$vehicle = $data['vehicle'];
|
|
$plate_number = $data['plate_number'];
|
|
$mobile = $data['mobile'];
|
|
|
|
$cust = null;
|
|
$cust_vehicle = null;
|
|
|
|
// find customer + customer vehicle combo
|
|
$cust_vehicle = $this->findCustomerAndCustomerVehicle($data, $em);
|
|
if ($cust_vehicle == null)
|
|
{
|
|
// find customer given phone number
|
|
$cust = $em->getRepository(Customer::class)->findOneBy(['phone_mobile' => $mobile]);
|
|
|
|
if ($cust == null)
|
|
{
|
|
// get the api_user that made the call so that it gets added to the source
|
|
// source becomes TAPI_USER_<insert name of api user here>
|
|
$user_id = $_SERVER['HTTP_X_CATA_API_KEY'];
|
|
$source = 'TAPI_USER';
|
|
$username = '';
|
|
|
|
if (!empty($user_id))
|
|
{
|
|
$api_user = $this->getUser();
|
|
if ($api_user != null)
|
|
{
|
|
$username = $api_user->getName();
|
|
$source = $source . '_' . $username;
|
|
}
|
|
}
|
|
|
|
// create new customer and customer vehicle
|
|
$cust = new Customer();
|
|
|
|
$cust->setFirstName($fname)
|
|
->setLastName($lname)
|
|
->setPhoneMobile($mobile)
|
|
->setCreateSource($source);
|
|
|
|
$em->persist($cust);
|
|
|
|
// add customer vehicle
|
|
$cust_vehicle = $this->createCustomerVehicle($em, $cust, $data);
|
|
|
|
}
|
|
else
|
|
{
|
|
// create customer vehicle
|
|
$cust_vehicle = $this->createCustomerVehicle($em, $cust, $data);
|
|
}
|
|
|
|
$em->flush();
|
|
}
|
|
|
|
$c_data = [
|
|
'customer' => $cust_vehicle->getCustomer(),
|
|
'customer_vehicle' => $cust_vehicle,
|
|
];
|
|
|
|
return $c_data;
|
|
}
|
|
|
|
protected function createCustomerVehicle(EntityManagerInterface $em, Customer $cust, $data)
|
|
{
|
|
// add customer vehicle
|
|
$cust_vehicle = new CustomerVehicle();
|
|
|
|
$cust_vehicle->setCustomer($cust)
|
|
->setPlateNumber($data['plate_number'])
|
|
->setVehicle($data['vehicle'])
|
|
->setModelYear($data['model_year'])
|
|
->setStatusCondition($data['condition'])
|
|
->setColor($data['color'])
|
|
->setHasMotoliteBattery(false)
|
|
->setFuelType($data['fuel_type']);
|
|
|
|
$em->persist($cust_vehicle);
|
|
|
|
return $cust_vehicle;
|
|
}
|
|
|
|
protected function findCustomerAndCustomerVehicle($data, EntityManagerInterface $em)
|
|
{
|
|
$plate_number = $data['plate_number'];
|
|
$mobile = $data['mobile'];
|
|
|
|
$query = $em->createQuery('SELECT cv, c FROM App\Entity\CustomerVehicle cv
|
|
JOIN cv.customer c
|
|
WHERE cv.plate_number = :plate_number
|
|
AND c.phone_mobile = :phone_mobile');
|
|
$query->setParameter('plate_number', $plate_number)
|
|
->setParameter('phone_mobile', $mobile);
|
|
|
|
$cust_results = $query->iterate();
|
|
|
|
$cust_vehicle = null;
|
|
foreach ($cust_results as $row)
|
|
{
|
|
$cust_vehicle = $row[0];
|
|
}
|
|
|
|
return $cust_vehicle;
|
|
}
|
|
|
|
protected function validateAndGetEstimateRequest(Request $req, EntityManagerInterface $em, &$data)
|
|
{
|
|
$r = $req->request;
|
|
|
|
// validate service type
|
|
$stype = $this->cleanText($r->get('service_type', ''));
|
|
if (!ServiceType::validate($stype))
|
|
{
|
|
$message = 'Invalid service type';
|
|
return $message;
|
|
}
|
|
|
|
$trade_in_type = $this->cleanText($r->get('trade_in_type', ''));
|
|
if ((!empty($trade_in_type)) &&
|
|
(!TradeInType::validate($trade_in_type)))
|
|
{
|
|
$message = 'Invalid trade in type';
|
|
return $message;
|
|
}
|
|
|
|
switch ($trade_in_type)
|
|
{
|
|
case TradeInType::MOTOLITE:
|
|
case TradeInType::OTHER:
|
|
break;
|
|
|
|
default:
|
|
$trade_in_type = '';
|
|
break;
|
|
}
|
|
|
|
// check battery
|
|
$batt = null;
|
|
$batt_id = $req->request->get('battery_id', 0);
|
|
if (!empty($batt_id))
|
|
{
|
|
$batt = $em->getRepository(Battery::class)->find($batt_id);
|
|
if ($batt == null)
|
|
{
|
|
$message = 'Invalid battery id';
|
|
return $message;
|
|
}
|
|
}
|
|
|
|
// check if service type is BATTERY_REPLACEMENT_WARRANTY or
|
|
// BATTERY_REPLACEMENT_NEW and if battery_id is empty
|
|
if (($stype == ServiceType::BATTERY_REPLACEMENT_NEW) ||
|
|
($stype == ServiceType::BATTERY_REPLACEMENT_WARRANTY))
|
|
{
|
|
if ($batt == null)
|
|
{
|
|
$message = 'battery_id cannot be empty for selected service type.';
|
|
return $message;
|
|
}
|
|
}
|
|
|
|
$vmodel = null;
|
|
$vmodel_id = $r->get('vehicle_model_id', 0);
|
|
// validate the vehicle model id
|
|
// find vehicle
|
|
$vmodel = $em->getRepository(Vehicle::class)->find($vmodel_id);
|
|
if ($vmodel == null)
|
|
{
|
|
$message = 'Invalid vehicle model id.';
|
|
return $message;
|
|
}
|
|
|
|
// validate fuel type
|
|
$fuel_type = $this->cleanText($r->get('vehicle_fuel_type', ''));
|
|
if ((!empty($fuel_type)) &&
|
|
(!FuelType::validate($fuel_type)))
|
|
{
|
|
$message = 'Invalid vehicle fuel type.';
|
|
return $message;
|
|
}
|
|
|
|
// validate promo
|
|
$promo = null;
|
|
$promo_id = $r->get('promo_id', 0);
|
|
if (!empty($promo_id))
|
|
{
|
|
$promo = $em->getRepository(Promo::class)->find($promo_id);
|
|
if ($promo == null)
|
|
{
|
|
$message = 'Invalid promo id';
|
|
return $message;
|
|
}
|
|
}
|
|
|
|
// invoice criteria needs a customer vehicle object
|
|
// with customer set. We create dummy customer vehicle object
|
|
// with dummy customer set
|
|
$dummy_cv = $this->createDummyCustomerVehicle($vmodel, $fuel_type);
|
|
|
|
$data = [
|
|
'service_type' => $stype,
|
|
'trade_in_type' => $trade_in_type,
|
|
'vehicle' => $vmodel,
|
|
'battery' => $batt,
|
|
'fuel_type' => $fuel_type,
|
|
'promo' => $promo,
|
|
'customer_vehicle' => $dummy_cv,
|
|
];
|
|
|
|
return null;
|
|
}
|
|
|
|
protected function createDummyCustomerVehicle($vmodel, $fuel_type)
|
|
{
|
|
$dummy_cv = new CustomerVehicle();
|
|
$dummy_cust = new Customer();
|
|
|
|
$dummy_cv->setCustomer($dummy_cust)
|
|
->setFuelType($fuel_type)
|
|
->setHasMotoliteBattery(false);
|
|
|
|
return $dummy_cv;
|
|
}
|
|
|
|
protected function generateAPIRiderStatus($status)
|
|
{
|
|
switch ($status)
|
|
{
|
|
case JOStatus::PENDING:
|
|
return APIRiderStatus::OUTLET_ASSIGN;
|
|
case JOStatus::RIDER_ASSIGN:
|
|
return APIRiderStatus::RIDER_ASSIGN;
|
|
case JOStatus::ASSIGNED:
|
|
case JOStatus::IN_TRANSIT:
|
|
case JOStatus::IN_PROGRESS:
|
|
return APIRiderStatus::RIDER_PICK_UP;
|
|
}
|
|
return 'unknown';
|
|
}
|
|
|
|
protected function cleanPhoneNumber($mobile)
|
|
{
|
|
// remove any non digit character from string
|
|
$clean_number = preg_replace('~\D~', '', $mobile);
|
|
|
|
// does it fit our 09XXXXXXXXX pattern?
|
|
if (preg_match('/^09[0-9]{9}$/', $clean_number))
|
|
{
|
|
return $clean_number;
|
|
}
|
|
// does it fit our 9XXXXXXXXX pattern?
|
|
else if (preg_match('/^9[0-9]{9}$/', $clean_number))
|
|
{
|
|
return $clean_number;
|
|
}
|
|
// does it fit our 63XXXXXXXXXX pattern?
|
|
else if (preg_match('/^63[0-9]{10}$/', $clean_number))
|
|
{
|
|
// strip the 63 since we don't save the country code
|
|
$c_number = substr($clean_number, 0, 2);
|
|
return $c_number;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
protected function cleanPlateNumber($plate)
|
|
{
|
|
// remove spaces and make upper case
|
|
return strtoupper(str_replace(' ', '', $plate));
|
|
}
|
|
|
|
protected function cleanText($name)
|
|
{
|
|
return strtolower(trim($name));
|
|
}
|
|
|
|
protected function generateYearOptions()
|
|
{
|
|
$start_year = 1950;
|
|
return range($start_year, date("Y") + 1);
|
|
}
|
|
}
|
|
|